Package net.xoetrope.optional.svg.svgsalamander

Source Code of net.xoetrope.optional.svg.svgsalamander.XSvgPainter$RescaleElement

package net.xoetrope.optional.svg.svgsalamander;

import com.kitfox.svg.SVGDiagram;
import com.kitfox.svg.SVGElement;
import com.kitfox.svg.SVGRoot;
import com.kitfox.svg.SVGUniverse;
import com.kitfox.svg.animation.AnimationElement;
import com.kitfox.svg.app.PlayerThread;
import com.kitfox.svg.app.PlayerThreadListener;
import java.awt.Color;
import java.awt.Dimension;

import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Vector;
import javax.swing.JComponent;
import net.xoetrope.debug.DebugLogger;
import net.xoetrope.optional.svg.HitTester;
import net.xoetrope.optional.svg.XSvgStateHelper;
import net.xoetrope.optional.svg.XSvgStateHelperFactory;
import net.xoetrope.xml.XmlElement;
import net.xoetrope.xml.XmlSource;
import net.xoetrope.xui.build.BuildProperties;
import org.jdesktop.swingx.painter.Painter;

/**
* A painter that renders an SVG image
* <p>Copyright (c) Xoetrope 2001-2006, see license.txt for more details</p>
*/
public class XSvgPainter implements Painter, HitTester, PlayerThreadListener
{   
  protected SVGDiagram diagram;
  protected int oldWidth, oldHeight;
 
  protected Color bkColor;
  
  protected double scaleX, scaleY;
 
  private JComponent component;
//  private static HashMap painters = new HashMap();

  private boolean scaled;
  private Vector rescaleElements;
  private Rectangle2D viewBox;

  private Insets insets;
 
  private XSvgStateHelper helper;
 
  private XmlElement metadata;
 
  private PlayerThread animationThread;
 
  /**
   * Creates a new instance of XSvgPainter
   * @param comp the target component
   */
  public XSvgPainter( JComponent comp )
  {
    component = comp;
    helper = XSvgStateHelperFactory.getXSvgStateHelper( comp );
  }
 
  /**
   * Get the ID of the selected element
   * @param returns a comma separated list of ids
   */
  public String getSelectedId()
  {
    if ( helper == null )
      return "";
   
    return helper.getSelectedId();
  }

  /**
   * Flag this painter as an animation painter
   * @param state true to animate
   */
  public void setAnimate( boolean state )
  {
    if ( state ) {
      animationThread = new PlayerThread();
      animationThread.addListener( this );
    }
    else
      animationThread = null;
  }
 
  public void play()
  {
    animationThread.setPlayState( PlayerThread.PS_PLAY_FWD );
    animationThread.setTimeStep( 1.0 / 50.0 );
    animationThread.setCurTime( 0 );
  }
 
  public double getCurTime()
  {
    if ( animationThread != null )
      return animationThread.getCurTime();
   
    return 0;
  }
 
  public void updateTime( double curTime, double timeStep, int playState )
  {
    try {
      if ( playState == PlayerThread.PS_STOP )
        return;
     
      SVGUniverse universe = diagram.getUniverse();
      if ( universe != null ) {
        universe.setCurTime( curTime );
        universe.updateTime();
        component.repaint();
      }
    }
    catch ( Exception e )
    {
      e.printStackTrace();
    }
  }
   
  /**
   * Set the element id for elements like masks etc
   * @param element the element type/role
   * @param id the SVG element id to use
   */
  public void setElementIds( String[][] ids )
  {   
    helper.setElementIds( ids );
    helper.getStates( diagram );
  }
 
  /**
   * Set the metadata URL
   * @param mdURL the host component
   */
  public void setMetadata( URL mdURL )
  {
    try {
      metadata = XmlSource.read( new BufferedReader( new InputStreamReader( mdURL.openStream())));
    }
    catch ( IOException ex ) {
      ex.printStackTrace();
    }
  }
 
  /**
   * Set the image managed and rendered by this painter
   * @param imageURL the url of the svg
   */
  public void setImage( URL imageURL )
  {
    setImage( imageURL, false );
  }

  /**
   * Set the image managed and rendered by this painter
   * @param imageURL the url of the svg
   * @param clear true to clear the svg universe, if for instance the svg
   * image has changed
   */
  public void setImage( URL imageURL, boolean clear )
  {
    try {     
      SVGUniverse universe = new SVGUniverse();
      if ( clear )
        universe.clear();

      if ( BuildProperties.DEBUG )
        DebugLogger.logWarning( "Loading: " + imageURL.toExternalForm());
     
      diagram = universe.getDiagram( new URI( imageURL.toExternalForm()));
    }
    catch ( URISyntaxException ex )
    {
      ex.printStackTrace();
    }
  }
 
//  public void setImage( URL imageURL, int w, int h )
//  {
//    this.component = component;
//    if ( imageURL == null )
//      return;
//   
////    theImage = imageURL;
//    String key = imageURL.toString();// + "_" + w + "_" + h;
//    diagram = (SVGDiagram)painters.get( key );
//    if ( diagram == null ) {
//      try {
////        diagram = (SVGDiagram)painters.get( imageURL.toString() );
////        if ( diagram == null ) {
//          SVGUniverse universe = new SVGUniverse();
//          //universe.clear();
//          diagram = universe.getDiagram( new URI( imageURL.toExternalForm()));
//          setup();
//          painters.put( key, diagram );
////        }
//// else clone the existing image         
//      }
//      catch ( URISyntaxException ex )
//      {
//        ex.printStackTrace();
//      }
//    }
//  }

  public void paint(Graphics2D g, Object object, int width, int height)
  {
    paint( g, (JComponent)object, width, height );
  }
 
  /**
   * <p>Paints on the given Graphics2D object some effect which may or may not
   * be related to the given component. For example, BackgroundPainter will
   * use the background property of the component and the width/height of the
   * component to perform a fill rect. Most other Painters will disregard the
   * component entirely, except to get the component width/height.</p>
   *
   * <p>The Graphics2D object must be returned to the same state it started
   * at by the end of the method. For example, if "setColor(c)" was called
   * on the graphics object, it should be reset to the original color before
   * the method returns.</p>
   *
   *
   * @param g The Graphics2D object in which to paint
   * @param component The JComponent that the Painter is delegate for. This
   *        must not be null.
   * @param width
   * @param height
   */
  public void paint( Graphics2D g, JComponent component, int width, int height )
  {
    Object oldHint = g.getRenderingHint( RenderingHints.KEY_ANTIALIASING );
    g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );

    // Force the initial resizing
    if ( !scaled )
      componentResized();
   
    try {
      if ( bkColor != null ) {
        g.setColor( bkColor );
        g.fillRect( 0, 0, width, height );
      }
     
      //setImage( theImage, width, height );
      if ( diagram != null ) {
        SVGRoot root = diagram.getRoot();
        if (( oldWidth != width ) || ( oldHeight != height )) {
          if ( root != null ) {
            root.setAttribute( "width", AnimationElement.AT_XML, Double.toString( width ));
            root.setAttribute( "height", AnimationElement.AT_XML, Double.toString( height ));
            root.build();  
          //diagram.setDeviceViewport( new Rectangle( 0,0,width, height));
            oldWidth = width;
            oldHeight = height;
          }

          try {
            double bbox[] = root.getPresAbsolute( "viewBox" ).getDoubleList();
            scaleX = bbox[ 2 ] / width;//root.getPresAbsolute( "width" ).getDoubleValue();   
            scaleY = bbox[ 3 ] / height;//root.getPresAbsolute( "height" ).getDoubleValue();       
          } catch ( Exception e ) {}
        }
       
        if ( root != null ) {
          if ( insets != null )
            diagram.setDeviceViewport( new Rectangle( insets.left, insets.top,
              width - ( insets.left + insets.right ), height - ( insets.top + insets.bottom )));
          diagram.render( g );
        }
      }
    }
    catch ( Exception ex ) {
      ex.printStackTrace();
    }
   
    g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, oldHint );
  }
 
  public void setBackground( Color c )
  {
    bkColor = c;
  }

  public boolean contains( int x, int y )
  {
    return helper.contains( scaleX * x, scaleY * y );
  }
 
  /**
   * Update the svg state to be consistent with the button's state
   * @param itemIndex the item index or -1 to update all items
   * @return true if the state has changed
   */
  public boolean updateState( int itemIndex )
  {
    return helper.updateState( itemIndex );
  }
 
 
  /**
   * Get the managed states in the svg diagram. The diagram may include two
   * types of managed elements. The first is managed by a helper class
   * implementing the XSvgStateHelper interface, and the second manages the
   * scaling of the component. The svg's metadata section may include a list of
   * elements to scale, and these are managed directly by this painter.
   */
  public void setup()
  {
    if ( diagram == null )
      return;
   
    if ( helper == null )
      helper = XSvgStateHelperFactory.getXSvgStateHelper( component );
    helper.getStates( diagram );
       
    // Prepare for rescaling
    viewBox = diagram.getViewRect();   
    rescaleElements = new Vector();
    SVGElement svgMetadata = diagram.getElement( "metadata" );
    if ( svgMetadata != null ) {
      String modlist = svgMetadata.getPresAbsolute( "modlist" ).getStringValue();
      String[] objectIds = modlist.split( ";" );
      for ( int i = 0; i < objectIds.length; i++ ) {
        RescaleElement re = new RescaleElement();
        re.element = diagram.getElement( objectIds[ i ] );

        String sid = re.element.getId();
        int pos;
        double r = 5.0;
        double s = 4.0;
        if (( pos = sid.indexOf( '_' )) > 0 ) {
          int lastIdx = sid.lastIndexOf( '_' );
          if ( lastIdx > pos ) {
            re.radius = (double)Integer.parseInt( sid.substring( pos + 1, lastIdx ));
            re.stroke = (double)Integer.parseInt( sid.substring( lastIdx + 1 ));
          }
          else
            re.radius = (double)Integer.parseInt( sid.substring( pos + 1 ));
        }
        rescaleElements.add( re );
      }
    }
   
    if ( metadata != null ) {
      Vector children = metadata.getChildren();
      int numChildren = children.size();
      for ( int i = 0; i < numChildren; i++ ) {
        XmlElement child = (XmlElement)children.elementAt( i );
        String tag = child.getName();
        String id = child.getAttribute( "id" );
       
        RescaleElement re = new RescaleElement();
        re.element = diagram.getElement( id );
        if ( re.element == null )
          continue;
       
        String attr = child.getAttribute( "x" );
        if ( attr != null )
          re.x = new Double( attr ).doubleValue();
       
        attr = child.getAttribute( "y" );
        if ( attr != null )
          re.y = new Double( attr ).doubleValue();
       
        attr = child.getAttribute( "w" );
        if ( attr != null )
          re.w = new Double( attr ).doubleValue();
       
        attr = child.getAttribute( "h" );
        if ( attr != null )
          re.h = new Double( attr ).doubleValue();
       
        attr = child.getAttribute( "radius" );
        if ( attr != null )
          re.radius = new Double( attr ).doubleValue();
       
        attr = child.getAttribute( "stroke" );
        if ( attr != null )
          re.stroke = new Double( attr ).doubleValue();

        attr = child.getAttribute( "ow" );
        if ( attr != null )
          re.origW = new Double( attr ).doubleValue();
       
        attr = child.getAttribute( "oh" );
        if ( attr != null )
          re.origH = new Double( attr ).doubleValue();

        rescaleElements.add( re );
      }
    }
  }
 
  /**
   * The component has been resize, so resize the svg
   */
  public void componentResized()
  {   
    try {
      if ( rescaleElements != null ) {       
        Dimension size = component.getSize();
        double vw = viewBox.getWidth();
        double vh = viewBox.getHeight();
        double ww = size.width;
        double wh = size.height;

        int numElements = rescaleElements.size();
        for ( int i = 0; i < numElements; i++ ) {
          RescaleElement re = (RescaleElement)rescaleElements.get( i );
          if (( component != null ) && ( diagram != null )) {
            if ( re.radius > 0.0 ) {
              double rx = re.radius * vw / ww;
              double ry = re.radius * vh / wh;
              re.element.setAttribute( "rx", AnimationElement.AT_XML, Double.toString( rx ));
              re.element.setAttribute( "ry", AnimationElement.AT_XML, Double.toString( ry ));       
              scaled = true;
            }

            if ( re.stroke > 0.0 ) {
              double vd = Math.sqrt( vh * vh + vw * vw );
              double wd = Math.sqrt( wh * wh + ww * ww );
              re.element.setAttribute( "stroke-width", AnimationElement.AT_XML, Double.toString( re.stroke * vd / wd ));       
              re.element.updateTime( 0.0 );
              scaled = true;
            }

            double dx, dy, dw, dh;
            dx = dy = 0.0;
            dw = dh = 1.0;
            if ( re.x != 0.0 ) {
              if ( re.x > 1.0 )
                dx = ( re.x / ww ) * vw;       
              else if ( re.x < 0.0 )
                dx = (( ww + re.x ) / ww ) * vw;       
              else
                dx = re.x * vw;       
            }
           
            if ( re.y != 0.0 ) {
              if ( re.y > 1.0 )
                dy = ( re.y / wh ) * vh;       
              else if ( re.y < 0.0 )
                dy = (( wh + re.y ) / wh ) * vh;       
              else
                dy = re.y * vh;       
            }
           
            if ( re.w != 0.0 ) {
              dw = vw / ww; // Preserve the original size
              if ( re.w > 1.0 )
                dw *= re.w / re.origW;       
              else
                dw *= ( re.w * ww ) / re.origW;       
            }
           
            if ( re.h != 0.0 ) {
              dh = vh / wh; // Preserve the original size
              if ( re.h > 1.0 )
                dh *= re.h / re.origH;       
              else
                dh *= ( re.h * wh ) / re.origH;       
            }
           
            String transform = "translate(" + dx + "," + dy + ") scale(" + dw + "," + dh + ")";
            re.element.setAttribute( "transform", AnimationElement.AT_XML, transform );       
            re.element.updateTime( 0.0 );
            scaled = true;
          }

          if ( scaled )
            oldWidth = oldHeight = 0;
        }
      }
    }
    catch ( Exception ex )
    {
      ex.printStackTrace();
    }
  }
 
  
  public SVGElement getElement( String id )
  {
    return diagram.getElement( id );
  }
 
  class RescaleElement
  {
    double x, y, w, h, origW, origH, radius, stroke;
    SVGElement element;
  }

  public void setInsets(Insets insets) {
    this.insets = insets;
  }
}
TOP

Related Classes of net.xoetrope.optional.svg.svgsalamander.XSvgPainter$RescaleElement

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.