Package net.xoetrope.optional.svg

Source Code of net.xoetrope.optional.svg.XSvgCanvas

package net.xoetrope.optional.svg;

import com.tinyline.svg.ImageLoader;
import com.tinyline.svg.SVG;
import com.tinyline.svg.SVGAttr;
import com.tinyline.svg.SVGDocument;
import com.tinyline.svg.SVGFontElem;
import com.tinyline.svg.SVGImageElem;
import com.tinyline.svg.SVGParser;
import com.tinyline.svg.SVGRaster;
import com.tinyline.svg.SVGRect;
import com.tinyline.svg.SVGSVGElem;
import com.tinyline.tiny2d.TinyBitmap;
import com.tinyline.tiny2d.TinyPixbuf;
import com.tinyline.tiny2d.TinyString;
import com.tinyline.tiny2d.TinyUtil;
import com.tinyline.tiny2d.TinyVector;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.image.ColorModel;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.zip.GZIPInputStream;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import net.xoetrope.optional.svg.tinyline.PPSVGBitmap;
import net.xoetrope.optional.svg.tinyline.PlayerListener;
import net.xoetrope.optional.svg.tinyline.SVGEvent;
import net.xoetrope.optional.svg.tinyline.SVGEventQueue;
import net.xoetrope.optional.svg.w3c.dom.events.Event;
import net.xoetrope.optional.svg.w3c.dom.events.EventListener;
import net.xoetrope.optional.svg.w3c.dom.events.EventTarget;
import net.xoetrope.xui.XAttributedComponent;
import net.xoetrope.xui.XProject;
import net.xoetrope.xui.XProjectManager;
import net.xoetrope.xui.helper.XuiUtilities;



/**
* The <tt>PPSVGCanvas</tt> is the J2ME Personal Profile
* implementation of the SVG Canvas.
* <p>anit
* @author (C) Andrew Girow
* @version 1.5
* <p>
*/
public class XSvgCanvas extends JComponent implements Runnable, ImageLoader,
    EventTarget, XAttributedComponent
{
  /** The canvas offscreen image */
  private Image bimg;
 
  /** The canvas bounds */
  private int width,height;
 
  /** The SVG renderer */
  public SVGRaster raster;
 
  /** The SVGImageProducer implementation */
  private  XSVGImageProducer imageProducer;
 
  /** The events queue */
  public  SVGEventQueue   eventQueue;
 
  /** The events dispatching thread */
  private Thread   thread;
 
  /** The events listeners */
  private TinyVector listeners;
 
  /** The base URL */
  private URL      baseURL;
 
  /** The current URL to go */
  public String   currentURL="";
 
  /** The image cash */
  private MediaTracker tracker;
 
  private PlayerListener defaultListener;
 
  private boolean loadComplete;
 
  private XProject currentProject;
 
  /**
   * Constructs a new PPSVGCanvas instance.
   */
  public XSvgCanvas()
  {
    currentProject = XProjectManager.getCurrentProject();
    setBackground(new Color(184,200,216));
    loadComplete = false;

    // Makes the events queues
    eventQueue  =  new SVGEventQueue();
    listeners   =  new TinyVector(4);
   
    // Makes the image cash
    tracker   = new MediaTracker(this);
       
    // Adds the default events listener
    defaultListener = new PlayerListener(this);
    addEventListener("default", defaultListener, false);
  }
 
  /**
   * Has the component finished with the input file?
   * @param true if the input file is closed
   */
  public boolean hasFileLoadCompleted()
  {
    return loadComplete;
  }
   
  /**
   * Requests a repaint of the control once it has been created
   */
  public void addNotify()
  {
    super.addNotify();
    start();
  }
  public synchronized void setBounds( int x, int y, int w, int h )
  {  
    super.setBounds( x, y, w, h );
    if (( width != w ) && ( height != h )) {
      flush();
      raster = null;
      width = w;
      height = h;     
    }
    if ( width > 0 )
      init();
  }
 
  public synchronized void init()
  {
    if (( width > 0 ) && ( raster == null )) {
      // Creates the SVG raster
      TinyPixbuf  buffer = new TinyPixbuf(width, height);
      raster = new SVGRaster(buffer);
      imageProducer = new XSVGImageProducer(raster);
      raster.setSVGImageProducer(imageProducer);

      // Sets the SVG raster size and the color model
      imageProducer.setColorModel(ColorModel.getRGBdefault());

      // Sets the ImageLoader implementation needed for
      // loading bitmaps
      SVGImageElem.setImageLoader(this);
      // Uncomment the following line for full antialiasing
      raster.setAntialiased(true);

      if ( SVGDocument.defaultFont == null ) {
        SVGDocument doc = loadSVG( getClass().getResourceAsStream("/net/xoetrope/optional/svg/tinyline/helvetica_svg"));
        SVGFontElem font = SVGDocument.getFont(doc,SVG.VAL_DEFAULT_FONTFAMILY);
        SVGDocument.defaultFont = font;
      }
    }
  }
 
  /**
   * Returns a TinyBitmap for the given image URL or path.
   * @param uri The image URL or path.
   * @return a TinyBitmap object which gets its pixel data from
   *                         the specified URL or path.
   */
  public TinyBitmap createTinyBitmap(TinyString uri)
  {
    String imgRef = new String(uri.data);
    PPSVGBitmap bitmap = null;
    try
    {
      URL url = new URL(baseURL,imgRef);
      // check in the cash
      bitmap = new PPSVGBitmap(tracker,url);
    }
    catch (Exception ex)
    {
    }
    return bitmap;
  }
 
  /**
   * Creates a TinyBitmap which decodes the image stored in the specified
   * byte array, and at the specified offset and length.
   * @param     imageData   an array of bytes, representing
   *                         image data in a supported image format.
   * @param     imageOffset  the offset of the beginning
   *                         of the data in the array.
   * @param     imageLength  the length of the data in the array.
   * @return    a TinyBitmap object.
   */
  public TinyBitmap createTinyBitmap(byte[] imageData, int imageOffset, int imageLength)
  {
    return new PPSVGBitmap(tracker,imageData, imageOffset, imageLength);
  }
 
  /** Starts the events dispatching thread */
  public synchronized void start()
  {   
    init();
    if (( width > 0 ) && ( thread == null )) {
      thread = new Thread(this);
      thread.setPriority(Thread.MIN_PRIORITY);
      thread.start();
    }
  }
 
 
  /** Stops the events dispatching thread */
  public synchronized void stop()
  {
    flush();
    if ( thread != null )
      thread.interrupt();
    thread = null;
    imageProducer = null;
    tracker = null;
    eventQueue = null;
    removeEventListener( defaultListener );
    defaultListener = null;
    listeners = null;
  }
 
  /**
   * The events dispatching thread run()
   */
  public void run()
  {   
    Thread currentThread = Thread.currentThread();
    while (currentThread == thread) {
      try {
        if ( raster == null )
          init();
        else
          eventQueue.handleEvent(eventQueue.getNextEvent());

        Thread.currentThread().sleep(50);
        Thread.currentThread().yield();
      }
      catch ( InterruptedException ie )
      {
        break;
      }
      catch (Throwable thr)
      {
        thr.printStackTrace();
        alertError("Internal Error");
      }
    }
    thread = null;
  }
 
  /**
   * Loads and dispalys an SVG document from the given URL.
   * External hyperlinks handling
   */
  synchronized public void goURL(String url)
  {
    SVGEvent event = new SVGEvent(SVGEvent.EVENT_LOAD,url);
    postEvent(event);
  }
 
  /**
   *  Returns the current SVGT document to its original view.
   */
  public void origView()
  {
    SVGEvent  event = new SVGEvent(SVGEvent.EVENT_ORIGVIEW, null);
    postEvent(event);
  }
 
  /**
   * Switches the rendering quality of this <tt>SVGPlayer</tt> .
   */
  public void switchQuality()
  {
    SVGEvent event = new SVGEvent(SVGEvent.EVENT_QUALITY, null );
    postEvent(event);
  }
 
  /**
   * Suspends or unsuspends all animations that are defined
   * within the current SVGT document fragment.
   */
  public void pauseResumeAnimations()
  {
    SVGEvent event = new SVGEvent(SVGEvent.EVENT_PAUSERESUME, null );
    postEvent(event);
  }
 
  /**
   * This method is called when information about an image which was
   * previously requested using an asynchronous interface becomes
   * available.  Asynchronous interfaces are method calls such as
   * getWidth(ImageObserver) and drawImage(img, x, y, ImageObserver)
   * which take an ImageObserver object as an argument.
   *
   * @param     img   the image being observed.
   * @param     flags the image status flags.
   * @param     x   the <i>x</i> coordinate.
   * @param     y   the <i>y</i> coordinate.
   * @param     width    the width.
   * @param     height   the height.
   * @return    <code>false</code> if the infoflags indicate that the
   *            image is completely loaded; <code>true</code> otherwise.
   */
  public boolean imageUpdate(Image img, int flags, int x, int y, int width, int height)
  {
    if((flags & 0x30) != 0)
      repaint(x, y, width, height);
    return (flags & 0x60) == 0;
  }
 
 
  /**
   * Paints this canvas
   * @param      g   the specified Graphics context.
   */
  public void paintComponent(Graphics g)
  {
    if ( !SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater( new Runnable() {
        public void run()
        {
          repaint( 0 );
          return;
        }
      });
    }
   
    if (( bimg == null ) && ( width > 0 )) {
      if ( raster == null )
        start();
      raster.setCamera();
      raster.update();
      raster.sendPixels();
      bimg = createImage( imageProducer );
    }
   
    if (bimg != null ) {
      g.drawImage(bimg, 0, 0, this);
      Toolkit.getDefaultToolkit().sync();// ????
    }
  }
 
  /**
   * The minimum size of the canvas.
   *
   * @return The minimum size of the canvas.
   */
  public Dimension getMinimumSize()
  {
    return new Dimension(width, height);
  }
 
  /**
   * The preferred size of the canvas.
   *
   * @return The preferred size of the canvas.
   */
  public Dimension getPreferredSize()
  {
    return new Dimension(width, height);
  }
 
  /** Flushes the allocated resources. */
  public void flush()
  {
    if ( raster != null )
      raster.flush();
    if ( bimg != null ) {
      bimg.flush();
      bimg = null;
    }
  }
 
  /**
   * Loads an SVGT document from the given URL.
   * @param urlStr  The SVGT document URL or path.
   * @return     An SVGT document.
   */
  public SVGDocument loadSVG(String urlStr)
  {
    alertWait("Wait...");
    loadComplete = false;
    InputStream is = null;
    try {
      URL url = new URL(baseURL,urlStr);
      baseURL = url;
      is = url.openStream();
      if( url.toString().endsWith("svgz"))
        is = new GZIPInputStream(is);     
    }
    catch( Exception ex)
    {
      alertError("Not in SVGT format");
    }
    SVGDocument doc = loadSVG(is);
    try {
      if ( is != null )
        is.close();
      is = null;
    }
    catch( Exception ex)
    {
      alertError("Not in SVGT format");
    }
    loadComplete = true;
    return doc;
  }
 
  /**
   * Loads an SVGT document from the given InputStream.
   * @param   is  The InputStream.
   * @return     An SVGT document.
   */
  public SVGDocument loadSVG(InputStream is)
  {
    alertWait("Wait...");
    String str = "";
    if ( raster == null )
      start();
    SVGDocument doc = raster.createSVGDocument();
    try {
      // Read and parse the SVGT stream
      TinyPixbuf pixbuf = raster.getPixelBuffer();
      // Create the SVGT attributes parser
      SVGAttr attrParser = new SVGAttr(pixbuf.width, pixbuf.height);
      // Create the SVGT stream parser
      SVGParser parser = new SVGParser(attrParser);
      // Parse the input SVGT stream parser into the document
      parser.load(doc,is);
      str = "www.tinyline.com";
      alertInit(str);
    }
    catch(OutOfMemoryError memerror)
    {
      doc = null;
      Runtime.getRuntime().gc();
      alertError("Not enought memory");
    }
    catch(SecurityException secex)
    {
      doc = null;
      alertError("Security violation");
    }
    catch( Exception ex)
    {
      doc = null;
      alertError("Not in SVGT format");
    }
    catch( Throwable thr)
    {
      doc = null;
      alertError("Not in SVGT format");
    }
    finally
    {
      try
      {
        if (is != null) is.close();
      }
      catch( IOException ioe)
      {
        alertError(ioe.getMessage());
      }
    }
    return doc;
  }
 
  /** Sets the status bar implementation */
//  public void setStatusBar(StatusBar aStatusBar)
//  {
//    //statusBar = aStatusBar;
//  }
 
  /** StatusBar: shows an alert */
  public void alertError(String s)
  {
//       if(statusBar!=null) statusBar.alertError(s);
  }
 
  /** StatusBar: shows a wait */
  public void alertWait(String s)
  {
    //     if(statusBar!=null) statusBar.alertWait(s);
  }
 
  /** StatusBar: inits the bar */
  public void alertInit(String s)
  {
    //   if(statusBar!=null) statusBar.alertInit(s);
  }
 
  //////////////////////////////////////////////////////////////////
  /**
   * Posts an event to the event queue.
   *
   * @param theEvent an instance of Event, or a
   * subclass of it.
   */
  public synchronized void postEvent(SVGEvent theEvent)
  {
    //IMPORTANT
    theEvent.eventTarget = this;
    eventQueue.postEvent(theEvent);
  }
 
                /*
                 * Methods inherited from interface org.w3c.dom.events.EventTarget
                 */
 
  /**
   *
   * <b>uDOM:</b> This method allows the registration of event listeners on the event target.
   *
   * @param type The event type for which the user is registering
   *
   * @param listener The listener parameter takes an interface implemented by the
   * user which contains the methods to be called when the event occurs.
   *
   * @param useCapture If true, useCapture indicates that the user wishes
   * to initiate capture. After initiating capture, all events of the
   * specified type will be dispatched to the registered EventListener
   * before being dispatched to any EventTargets beneath them in the tree.
   * Events which are bubbling upward through the tree will not trigger an
   * EventListener designated to use capture.
   */
  public void addEventListener(java.lang.String type,
      EventListener listener,
      boolean useCapture)
  {
    listeners.addElement(listener);
  }
 
  /**
   *
   * <b>uDOM:</b> This method allows the removal of event listeners from the event target.
   *
   * @param listener The listener parameter indicates the EventListener to be removed.
   */
  public void removeEventListener( EventListener listener)
     
  {
    int i = listeners.indexOf(listener,0);
    if(i>0)
    {
      listeners.removeElementAt(i);
    }
  }
  /**
   * <b>uDOM:</b> This method allows the dispatch of events into the implementations event model.
   * Events dispatched in this manner will have the same behavior as events dispatched
   * directly by the implementation.
   *
   * @param evt  Specifies the event type, behavior, and contextual
   * information to be used in processing the event.
   * @return    The return value of dispatchEvent indicates whether
   * any of the listeners which handled the event called preventDefault.
   * If preventDefault was called the value is false, else the value is true.
   */
  public boolean dispatchEvent(Event evt)
  {
    if ( raster == null )
      start();
   
    EventListener h;
    for(int i=0; i < listeners.count; i++)
    {
      h = (EventListener)listeners.data[i];
      if(h!=null) h.handleEvent(evt);
    }
    return true;
  }
 
  /**
   * Set one or more attributes of the component.
   * @param attribName the name of the attribute
   * @param attribValue the value of the attribute
   * @return 0 for success, non zero for failure or to require some further action
   */
  public int setAttribute( String attribName, Object attribValue )
  {
    String attribNameLwr = attribName.toLowerCase();
    String attribValueStr = (String)attribValue;
    if ( attribNameLwr.equals( "content" )) {
      String fileName = attribValueStr + ( attribValueStr.toLowerCase().endsWith( ".svgz" ) ? "" : ".svgz" );
      URL resourceUrl = currentProject.findResource( fileName );
      try {
        InputStream is = resourceUrl.openStream();
        is.read();
        is.close();
      }
      catch ( Throwable t )
      {
        System.out.println( "File does not exist: " + attribValue );
        return 0;
      }
      if ( resourceUrl != null ) {
        String urlStr = resourceUrl.toExternalForm();

        goURL( urlStr );//"file:/C:/Xui/Tests/NB5_20/resources/tgirl.svg");
        if ( isVisible() && isShowing())
          start();
      }
    }
    else if ( attribNameLwr.equals( "tooltip" ))
      setToolTipText( XuiUtilities.translate( currentProject, (String)attribValue ));

    return 0;
  }
 
  public void setVisible( boolean state )
  {
    super.setVisible( state );
    if ( state )
      start();
  }
 
  /**
   * Pan/scroll the image to toa new location
   * @param x the number of pixels to move horizontally, moved the display viewport
   * @param y the number of pixels to move vertically, moved the display viewport
   */
  public void pan( int x, int y )
  {
    // Get the current viewport
    SVGRect view = raster.view;
    // Get the SVGT document
    SVGDocument doc = raster.getSVGDocument();
    // Get the root of the SVGT document
    SVGSVGElem root = (SVGSVGElem)doc.root;
    // Get the current scale value
    int scale = root.getCurrentScale();
    // Scale pan distances according to the current scale factor
    // Change the current viewport
    view.x += TinyUtil.div(x<<TinyUtil.FIX_BITS,scale);
    view.y += TinyUtil.div(y<<TinyUtil.FIX_BITS,scale);
   
    updateImage();
  }
 
  /**
   * Zoom in on the image
   * param scaleFactor the factor by which to adjust the scaling. Greater than 1.0
   * for zooming in and less than 1.0 for zooming out.
   */
  public void zoom( double scaleFactor )
  {
    // Get the current viewport
    SVGRect view = raster.view;
    // Get the SVGT document
//    SVGDocument doc = raster.getSVGDocument();
    // Get the root of the SVGT document
//    SVGSVGElem root = (SVGSVGElem)doc.root;
    // Get the current scale value
   
    //int scale = root.getCurrentScale();
    view.width /= scaleFactor;
    view.height /= scaleFactor;
      
    updateImage();
  }
 
  /**
   * Reset the image to its original size and position
   */
  public void reset()
  {
    SVGRect view = raster.view;
    view.x = raster.origview.x;
    view.y = raster.origview.y;
    view.width = raster.origview.width;
    view.height = raster.origview.height;
   
    updateImage();
  }

  /**
   * Update the raster image
   */
  protected void updateImage()
  {
    // Change the camera transform according to the new current
    // viewport and update the raster
    raster.setCamera();    // call recalculate the current 'camera' transform for the SVGRaster object.
    raster.update();       // call invokes the rendering pipeline.
    raster.sendPixels();   // call notifies the SVGImageProducer about new pixels.
  }
}
TOP

Related Classes of net.xoetrope.optional.svg.XSvgCanvas

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.