Package com.mxgraph.shape

Source Code of com.mxgraph.shape.mxStencilShape

/**
* Copyright (c) 2010-2012, JGraph Ltd
*/
package com.mxgraph.shape;

import org.w3c.dom.Node;

import com.mxgraph.canvas.mxGraphics2DCanvas;
import com.mxgraph.util.mxUtils;
import com.mxgraph.util.mxXmlUtils;
import com.mxgraph.util.svg.AWTPathProducer;
import com.mxgraph.util.svg.AWTPolygonProducer;
import com.mxgraph.util.svg.AWTPolylineProducer;
import com.mxgraph.util.svg.CSSConstants;
import com.mxgraph.util.svg.ExtendedGeneralPath;
import com.mxgraph.view.mxCellState;
import java.awt.Color;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
* Stencil shape drawing that takes an XML definition of the shape and renders
* it.
*
* See http://projects.gnome.org/dia/custom-shapes for specs. See
* http://dia-installer.de/shapes_de.html for shapes.
*/
public class mxStencilShape extends mxBasicShape
{
  public mxStencilShape()
  {
    super();
  }

  protected GeneralPath shapePath;

  /**
   * Reference to the root node of the Dia shape description.
   */
  protected Node root;

  protected svgShape rootShape;

  protected Rectangle2D boundingBox;

  protected String name;

  protected String iconPath;

  /**
   * Transform cached to save instance created. Used to scale the internal
   * path of shapes where possible
   */
  protected AffineTransform cachedTransform = new AffineTransform();

  /**
   * Constructs a new stencil for the given Dia shape description.
   */
  public mxStencilShape(String shapeXml)
  {
    this(mxXmlUtils.parseXml(shapeXml));
  }

  public mxStencilShape(Document document)
  {
    if (document != null)
    {
      NodeList nameList = document.getElementsByTagName("name");

      if (nameList != null && nameList.getLength() > 0)
      {
        this.name = nameList.item(0).getTextContent();
      }

      NodeList iconList = document.getElementsByTagName("icon");

      if (iconList != null && iconList.getLength() > 0)
      {
        this.iconPath = iconList.item(0).getTextContent();
      }

      NodeList svgList = document.getElementsByTagName("svg:svg");

      if (svgList != null && svgList.getLength() > 0)
      {
        this.root = svgList.item(0);
      }
      else
      {
        svgList = document.getElementsByTagName("svg");

        if (svgList != null && svgList.getLength() > 0)
        {
          this.root = svgList.item(0);
        }
      }

      if (this.root != null)
      {
        rootShape = new svgShape(null, null);
        createShape(this.root, rootShape);
      }
    }
  }

  /**
   *
   */
  @Override
  public void paintShape(mxGraphics2DCanvas canvas, mxCellState state)
  {
    double x = state.getX();
    double y = state.getY();
    double w = state.getWidth();
    double h = state.getHeight();

    canvas.getGraphics().translate(x, y);
    double widthRatio = 1;
    double heightRatio = 1;

    if (boundingBox != null)
    {
      widthRatio = w / boundingBox.getWidth();
      heightRatio = h / boundingBox.getHeight();
    }

    this.paintNode(canvas, state, rootShape, widthRatio, heightRatio);

    canvas.getGraphics().translate(-x, -y);
  }

  /**
   *
   */
  public void paintNode(mxGraphics2DCanvas canvas, mxCellState state,
      svgShape shape, double widthRatio, double heightRatio)
  {
    Shape associatedShape = shape.shape;

    boolean fill = false;
    boolean stroke = true;
    Color fillColor = null;
    Color strokeColor = null;

    Map<String, Object> style = shape.style;

    if (style != null)
    {
      String fillStyle = mxUtils.getString(style,
          CSSConstants.CSS_FILL_PROPERTY);
      String strokeStyle = mxUtils.getString(style,
          CSSConstants.CSS_STROKE_PROPERTY);

      if (strokeStyle != null
          && strokeStyle.equals(CSSConstants.CSS_NONE_VALUE))
      {
        if (strokeStyle.equals(CSSConstants.CSS_NONE_VALUE))
        {
          stroke = false;
        }
        else if (strokeStyle.trim().startsWith("#"))
        {
          int hashIndex = strokeStyle.indexOf("#");
          strokeColor = mxUtils.parseColor(strokeStyle
              .substring(hashIndex + 1));
        }
      }

      if (fillStyle != null)
      {
        if (fillStyle.equals(CSSConstants.CSS_NONE_VALUE))
        {
          fill = false;
        }
        else if (fillStyle.trim().startsWith("#"))
        {
          int hashIndex = fillStyle.indexOf("#");
          fillColor = mxUtils.parseColor(fillStyle
              .substring(hashIndex + 1));
          fill = true;
        }
        else
        {
          fill = true;
        }
      }
    }

    if (associatedShape != null)
    {
      boolean wasScaled = false;

      if (widthRatio != 1 || heightRatio != 1)
      {
        transformShape(associatedShape, 0.0, 0.0, widthRatio,
            heightRatio);
        wasScaled = true;
      }

      // Paints the background
      if (fill && configureGraphics(canvas, state, true))
      {
        if (fillColor != null)
        {
          canvas.getGraphics().setColor(fillColor);
        }

        canvas.getGraphics().fill(associatedShape);
      }

      // Paints the foreground
      if (stroke && configureGraphics(canvas, state, false))
      {
        if (strokeColor != null)
        {
          canvas.getGraphics().setColor(strokeColor);
        }

        canvas.getGraphics().draw(associatedShape);
      }

      if (wasScaled)
      {
        transformShape(associatedShape, 0.0, 0.0, 1.0 / widthRatio,
            1.0 / heightRatio);
      }
    }

    /*
     * If root is a group element, then we should add it's styles to the
     * children.
     */
    for (svgShape subShape : shape.subShapes)
    {
      paintNode(canvas, state, subShape, widthRatio, heightRatio);
    }
  }

  /**
   * Scales the points composing this shape by the x and y ratios specified
   *
   * @param shape
   *            the shape to scale
   * @param transX
   *            the x translation
   * @param transY
   *            the y translation
   * @param widthRatio
   *            the x co-ordinate scale
   * @param heightRatio
   *            the y co-ordinate scale
   */
  protected void transformShape(Shape shape, double transX, double transY,
      double widthRatio, double heightRatio)
  {
    if (shape instanceof Rectangle2D)
    {
      Rectangle2D rect = (Rectangle2D) shape;
      if (transX != 0 || transY != 0)
      {
        rect.setFrame(rect.getX() + transX, rect.getY() + transY,
            rect.getWidth(), rect.getHeight());
      }

      if (widthRatio != 1 || heightRatio != 1)
      {
        rect.setFrame(rect.getX() * widthRatio, rect.getY()
            * heightRatio, rect.getWidth() * widthRatio,
            rect.getHeight() * heightRatio);
      }
    }
    else if (shape instanceof Line2D)
    {
      Line2D line = (Line2D) shape;
      if (transX != 0 || transY != 0)
      {
        line.setLine(line.getX1() + transX, line.getY1() + transY,
            line.getX2() + transX, line.getY2() + transY);
      }
      if (widthRatio != 1 || heightRatio != 1)
      {
        line.setLine(line.getX1() * widthRatio, line.getY1()
            * heightRatio, line.getX2() * widthRatio, line.getY2()
            * heightRatio);
      }
    }
    else if (shape instanceof GeneralPath)
    {
      GeneralPath path = (GeneralPath) shape;
      cachedTransform.setToScale(widthRatio, heightRatio);
      cachedTransform.translate(transX, transY);
      path.transform(cachedTransform);
    }
    else if (shape instanceof ExtendedGeneralPath)
    {
      ExtendedGeneralPath path = (ExtendedGeneralPath) shape;
      cachedTransform.setToScale(widthRatio, heightRatio);
      cachedTransform.translate(transX, transY);
      path.transform(cachedTransform);
    }
    else if (shape instanceof Ellipse2D)
    {
      Ellipse2D ellipse = (Ellipse2D) shape;
      if (transX != 0 || transY != 0)
      {
        ellipse.setFrame(ellipse.getX() + transX, ellipse.getY()
            + transY, ellipse.getWidth(), ellipse.getHeight());
      }
      if (widthRatio != 1 || heightRatio != 1)
      {
        ellipse.setFrame(ellipse.getX() * widthRatio, ellipse.getY()
            * heightRatio, ellipse.getWidth() * widthRatio,
            ellipse.getHeight() * heightRatio);
      }
    }
  }

  /**
   *
   */
  public void createShape(Node root, svgShape shape)
  {
    Node child = root.getFirstChild();
    /*
     * If root is a group element, then we should add it's styles to the
     * childrens...
     */
    while (child != null)
    {
      if (isGroup(child.getNodeName()))
      {
        String style = ((Element) root).getAttribute("style");
        Map<String, Object> styleMap = mxStencilShape
            .getStylenames(style);
        svgShape subShape = new svgShape(null, styleMap);
        createShape(child, subShape);
      }

      svgShape subShape = createElement(child);

      if (subShape != null)
      {
        shape.subShapes.add(subShape);
      }
      child = child.getNextSibling();
    }

    for (svgShape subShape : shape.subShapes)
    {
      if (subShape != null && subShape.shape != null)
      {
        if (boundingBox == null)
        {
          boundingBox = subShape.shape.getBounds2D();
        }
        else
        {
          boundingBox.add(subShape.shape.getBounds2D());
        }
      }
    }

    // If the shape does not butt up against either or both axis,
    // ensure it is flush against both
    if (boundingBox != null
        && (boundingBox.getX() != 0 || boundingBox.getY() != 0))
    {
      for (svgShape subShape : shape.subShapes)
      {
        if (subShape != null && subShape.shape != null)
        {
          transformShape(subShape.shape, -boundingBox.getX(),
              -boundingBox.getY(), 1.0, 1.0);
        }
      }
    }
  }

  /**
   * Forms an internal representation of the specified SVG element and returns
   * that representation
   *
   * @param root
   *            the SVG element to represent
   * @return the internal representation of the element, or null if an error
   *         occurs
   */
  public svgShape createElement(Node root)
  {
    Element element = null;

    if (root instanceof Element)
    {
      element = (Element) root;
      String style = element.getAttribute("style");
      Map<String, Object> styleMap = mxStencilShape.getStylenames(style);

      if (isRectangle(root.getNodeName()))
      {
        svgShape rectShape = null;

        try
        {
          String xString = element.getAttribute("x");
          String yString = element.getAttribute("y");
          String widthString = element.getAttribute("width");
          String heightString = element.getAttribute("height");

          // Values default to zero if not specified
          double x = 0;
          double y = 0;
          double width = 0;
          double height = 0;

          if (xString.length() > 0)
          {
            x = Double.valueOf(xString);
          }
          if (yString.length() > 0)
          {
            y = Double.valueOf(yString);
          }
          if (widthString.length() > 0)
          {
            width = Double.valueOf(widthString);
            if (width < 0)
            {
              return null; // error in SVG spec
            }
          }
          if (heightString.length() > 0)
          {
            height = Double.valueOf(heightString);
            if (height < 0)
            {
              return null; // error in SVG spec
            }
          }

          String rxString = element.getAttribute("rx");
          String ryString = element.getAttribute("ry");
          double rx = 0;
          double ry = 0;

          if (rxString.length() > 0)
          {
            rx = Double.valueOf(rxString);
            if (rx < 0)
            {
              return null; // error in SVG spec
            }
          }
          if (ryString.length() > 0)
          {
            ry = Double.valueOf(ryString);
            if (ry < 0)
            {
              return null; // error in SVG spec
            }
          }

          if (rx > 0 || ry > 0)
          {
            // Specification rules on rx and ry
            if (rx > 0 && ryString.length() == 0)
            {
              ry = rx;
            }
            else if (ry > 0 && rxString.length() == 0)
            {
              rx = ry;
            }
            if (rx > width / 2.0)
            {
              rx = width / 2.0;
            }
            if (ry > height / 2.0)
            {
              ry = height / 2.0;
            }

            rectShape = new svgShape(new RoundRectangle2D.Double(x,
                y, width, height, rx, ry), styleMap);
          }
          else
          {
            rectShape = new svgShape(new Rectangle2D.Double(x, y,
                width, height), styleMap);
          }
        }
        catch (Exception e)
        {
          // TODO log something useful
        }

        return rectShape;
      }
      else if (isLine(root.getNodeName()))
      {
        String x1String = element.getAttribute("x1");
        String x2String = element.getAttribute("x2");
        String y1String = element.getAttribute("y1");
        String y2String = element.getAttribute("y2");

        double x1 = 0;
        double x2 = 0;
        double y1 = 0;
        double y2 = 0;

        if (x1String.length() > 0)
        {
          x1 = Double.valueOf(x1String);
        }
        if (x2String.length() > 0)
        {
          x2 = Double.valueOf(x2String);
        }
        if (y1String.length() > 0)
        {
          y1 = Double.valueOf(y1String);
        }
        if (y2String.length() > 0)
        {
          y2 = Double.valueOf(y2String);
        }

        svgShape lineShape = new svgShape(new Line2D.Double(x1, y1, x2,
            y2), styleMap);
        return lineShape;
      }
      else if (isPolyline(root.getNodeName())
          || isPolygon(root.getNodeName()))
      {
        String pointsString = element.getAttribute("points");
        Shape shape;

        if (isPolygon(root.getNodeName()))
        {
          shape = AWTPolygonProducer.createShape(pointsString,
              GeneralPath.WIND_NON_ZERO);
        }
        else
        {
          shape = AWTPolylineProducer.createShape(pointsString,
              GeneralPath.WIND_NON_ZERO);
        }

        if (shape != null)
        {
          return new svgShape(shape, styleMap);
        }

        return null;
      }
      else if (isCircle(root.getNodeName()))
      {
        double cx = 0;
        double cy = 0;
        double r = 0;

        String cxString = element.getAttribute("cx");
        String cyString = element.getAttribute("cy");
        String rString = element.getAttribute("r");

        if (cxString.length() > 0)
        {
          cx = Double.valueOf(cxString);
        }
        if (cyString.length() > 0)
        {
          cy = Double.valueOf(cyString);
        }
        if (rString.length() > 0)
        {
          r = Double.valueOf(rString);

          if (r < 0)
          {
            return null; // error in SVG spec
          }
        }

        return new svgShape(new Ellipse2D.Double(cx - r, cy - r, r * 2,
            r * 2), styleMap);
      }
      else if (isEllipse(root.getNodeName()))
      {
        double cx = 0;
        double cy = 0;
        double rx = 0;
        double ry = 0;

        String cxString = element.getAttribute("cx");
        String cyString = element.getAttribute("cy");
        String rxString = element.getAttribute("rx");
        String ryString = element.getAttribute("ry");

        if (cxString.length() > 0)
        {
          cx = Double.valueOf(cxString);
        }
        if (cyString.length() > 0)
        {
          cy = Double.valueOf(cyString);
        }
        if (rxString.length() > 0)
        {
          rx = Double.valueOf(rxString);

          if (rx < 0)
          {
            return null; // error in SVG spec
          }
        }
        if (ryString.length() > 0)
        {
          ry = Double.valueOf(ryString);

          if (ry < 0)
          {
            return null; // error in SVG spec
          }
        }

        return new svgShape(new Ellipse2D.Double(cx - rx, cy - ry,
            rx * 2, ry * 2), styleMap);
      }
      else if (isPath(root.getNodeName()))
      {
        String d = element.getAttribute("d");
        Shape pathShape = AWTPathProducer.createShape(d,
            GeneralPath.WIND_NON_ZERO);
        return new svgShape(pathShape, styleMap);
      }
    }

    return null;
  }

  /*
   *
   */
  private boolean isRectangle(String tag)
  {
    return tag.equals("svg:rect") || tag.equals("rect");
  }

  /*
   *
   */
  private boolean isPath(String tag)
  {
    return tag.equals("svg:path") || tag.equals("path");
  }

  /*
   *
   */
  private boolean isEllipse(String tag)
  {
    return tag.equals("svg:ellipse") || tag.equals("ellipse");
  }

  /*
   *
   */
  private boolean isLine(String tag)
  {
    return tag.equals("svg:line") || tag.equals("line");
  }

  /*
   *
   */
  private boolean isPolyline(String tag)
  {
    return tag.equals("svg:polyline") || tag.equals("polyline");
  }

  /*
   *
   */
  private boolean isCircle(String tag)
  {
    return tag.equals("svg:circle") || tag.equals("circle");
  }

  /*
   *
   */
  private boolean isPolygon(String tag)
  {
    return tag.equals("svg:polygon") || tag.equals("polygon");
  }

  private boolean isGroup(String tag)
  {
    return tag.equals("svg:g") || tag.equals("g");
  }

  protected class svgShape
  {
    public Shape shape;

    /**
     * Contains an array of key, value pairs that represent the style of the
     * cell.
     */
    protected Map<String, Object> style;

    public List<svgShape> subShapes;

    /**
     * Holds the current value to which the shape is scaled in X
     */
    protected double currentXScale;

    /**
     * Holds the current value to which the shape is scaled in Y
     */
    protected double currentYScale;

    public svgShape(Shape shape, Map<String, Object> style)
    {
      this.shape = shape;
      this.style = style;
      subShapes = new ArrayList<svgShape>();
    }

    public double getCurrentXScale()
    {
      return currentXScale;
    }

    public void setCurrentXScale(double currentXScale)
    {
      this.currentXScale = currentXScale;
    }

    public double getCurrentYScale()
    {
      return currentYScale;
    }

    public void setCurrentYScale(double currentYScale)
    {
      this.currentYScale = currentYScale;
    }
  }

  /**
   * Returns the stylenames in a style of the form stylename[;key=value] or an
   * empty array if the given style does not contain any stylenames.
   *
   * @param style
   *            String of the form stylename[;stylename][;key=value].
   * @return Returns the stylename from the given formatted string.
   */
  protected static Map<String, Object> getStylenames(String style)
  {
    if (style != null && style.length() > 0)
    {
      Map<String, Object> result = new Hashtable<String, Object>();

      if (style != null)
      {
        String[] pairs = style.split(";");

        for (int i = 0; i < pairs.length; i++)
        {
          String[] keyValue = pairs[i].split(":");

          if (keyValue.length == 2)
          {
            result.put(keyValue[0].trim(), keyValue[1].trim());
          }
        }
      }
      return result;
    }

    return null;
  }

  public String getName()
  {
    return name;
  }

  public void setName(String name)
  {
    this.name = name;
  }

  public String getIconPath()
  {
    return iconPath;
  }

  public void setIconPath(String iconPath)
  {
    this.iconPath = iconPath;
  }

  public Rectangle2D getBoundingBox()
  {
    return boundingBox;
  }

  public void setBoundingBox(Rectangle2D boundingBox)
  {
    this.boundingBox = boundingBox;
  }
}
TOP

Related Classes of com.mxgraph.shape.mxStencilShape

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.