]> source.dussan.org Git - poi.git/commitdiff
added missing definition of the upArrow shape, moved support for line decorations...
authorYegor Kozlov <yegor@apache.org>
Mon, 21 Nov 2011 13:10:14 +0000 (13:10 +0000)
committerYegor Kozlov <yegor@apache.org>
Mon, 21 Nov 2011 13:10:14 +0000 (13:10 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1204477 13f79535-47bb-0310-9956-ffa450edef68

src/ooxml/java/org/apache/poi/xslf/model/geom/PresetGeometries.java
src/ooxml/java/org/apache/poi/xslf/usermodel/RenderableShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFConnectorShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
src/ooxml/testcases/org/apache/poi/xslf/geom/TestPresetGeometries.java
src/resources/ooxml/org/apache/poi/xslf/usermodel/presetShapeDefinitions.xml

index 433c0cbe2f1f40f2385cbc3d5c5ad71e29809260..62accc42f3723f67a2823d655a2e58d19c62e33c 100644 (file)
@@ -51,6 +51,9 @@ public class PresetGeometries extends LinkedHashMap<String, CustomGeometry> {
             String name = def.getDomNode().getLocalName();
             CTCustomGeometry2D geom = CTCustomGeometry2D.Factory.parse(def.toString());
 
+            if(containsKey(name)) {
+                System.out.println("Duplicate definoition of " + name) ;
+            }
             put(name, new CustomGeometry(geom));
         }
     }
index c59ea6d1dddfc8a4f4f586b2d282809d4cce1647..21ab67124f9f90dff4511081e45e35f9a1363df7 100644 (file)
@@ -120,7 +120,7 @@ class RenderableShape {
         else if (obj instanceof CTGradientFillProperties) {\r
             CTGradientFillProperties gradFill = (CTGradientFillProperties) obj;\r
             if (gradFill.isSetLin()) {\r
-                 paint = createLinearGradientPaint(gradFill, anchor, theme, phClr);\r
+                 paint = createLinearGradientPaint(graphics, gradFill, anchor, theme, phClr);\r
             } else if (gradFill.isSetPath()){\r
                 CTPathShadeProperties ps = gradFill.getPath();\r
                 if(ps.getPath() ==  STPathShadeType.CIRCLE){\r
@@ -166,6 +166,7 @@ class RenderableShape {
     }\r
 \r
     private static Paint createLinearGradientPaint(\r
+            Graphics2D graphics,\r
             CTGradientFillProperties gradFill, Rectangle2D anchor,\r
             XSLFTheme theme, CTSchemeColor phClr) {\r
         double angle = gradFill.getLin().getAng() / 60000;\r
@@ -204,13 +205,30 @@ class RenderableShape {
             fractions[i] = stop.getPos() / 100000.f;\r
         }\r
 \r
+        AffineTransform grAt;\r
+        if(gradFill.getRotWithShape()) grAt = new AffineTransform();\r
+        else {\r
+            // gradient fill is not rotated with the shape\r
+            try {\r
+                grAt = graphics.getTransform().createInverse();\r
+            } catch (Exception e){\r
+                // should not happen.\r
+                grAt = new AffineTransform();\r
+            }\r
+        }\r
+\r
         // Trick to return GradientPaint on JDK 1.5 and LinearGradientPaint on JDK 1.6+\r
         Paint paint;\r
         try {\r
             Class clz = Class.forName("java.awt.LinearGradientPaint");\r
+            Class clzCycleMethod = Class.forName("java.awt.MultipleGradientPaint$CycleMethod");\r
+            Class clzColorSpaceType = Class.forName("java.awt.MultipleGradientPaint$ColorSpaceType");\r
             Constructor c =\r
-                    clz.getConstructor(Point2D.class, Point2D.class, float[].class, Color[].class);\r
-            paint = (Paint) c.newInstance(p1, p2, fractions, colors);\r
+                    clz.getConstructor(Point2D.class, Point2D.class, float[].class, Color[].class,\r
+                            clzCycleMethod, clzColorSpaceType, AffineTransform.class);\r
+            paint = (Paint) c.newInstance(p1, p2, fractions, colors,\r
+                    Enum.valueOf(clzCycleMethod, "NO_CYCLE"),\r
+                    Enum.valueOf(clzColorSpaceType, "SRGB"), grAt);\r
         } catch (ClassNotFoundException e) {\r
             paint = new GradientPaint(p1, colors[0], p2, colors[colors.length - 1]);\r
         } catch (Exception e) {\r
@@ -504,9 +522,12 @@ class RenderableShape {
     }\r
 \r
     private Collection<Outline> computeOutlines() {\r
-        CustomGeometry geom = _shape.getGeometry();\r
 \r
         Collection<Outline> lst = new ArrayList<Outline>();\r
+        CustomGeometry geom = _shape.getGeometry();\r
+        if(geom == null) {\r
+            return lst;\r
+        }\r
 \r
         Rectangle2D anchor = _shape.getAnchor();\r
         for (Path p : geom) {\r
index 5f4e838a0ca30935780a6dccdf1098ef470db6c2..b880e5988d3192582b14760dbe49732b23d5bd79 100644 (file)
@@ -80,4 +80,9 @@ public class XSLFAutoShape extends XSLFTextShape {
         }\r
         return txBody;\r
     }\r
+\r
+    @Override\r
+    public String toString(){\r
+        return "[" + getClass().getSimpleName() + "] " + getShapeName();\r
+    }\r
 }\r
index cd3a925d544892a1dd3c8cc9e72ea896edd9baa5..3f7d88b87061372f9cd52067cae12006f8a3a774 100644 (file)
@@ -75,262 +75,6 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
         return ct;\r
     }\r
 \r
-    /**\r
-     * Specifies the line end decoration, such as a triangle or arrowhead.\r
-     */\r
-    public void setLineHeadDecoration(LineDecoration style) {\r
-        CTLineProperties ln = getSpPr().getLn();\r
-        CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();\r
-        if (style == null) {\r
-            if (lnEnd.isSetType()) lnEnd.unsetType();\r
-        } else {\r
-            lnEnd.setType(STLineEndType.Enum.forInt(style.ordinal() + 1));\r
-        }\r
-    }\r
-\r
-    public LineDecoration getLineHeadDecoration() {\r
-        CTLineProperties ln = getSpPr().getLn();\r
-        if (ln == null || !ln.isSetHeadEnd()) return LineDecoration.NONE;\r
-\r
-        STLineEndType.Enum end = ln.getHeadEnd().getType();\r
-        return end == null ? LineDecoration.NONE : LineDecoration.values()[end.intValue() - 1];\r
-    }\r
-\r
-    /**\r
-     * specifies decorations which can be added to the head of a line.\r
-     */\r
-    public void setLineHeadWidth(LineEndWidth style) {\r
-        CTLineProperties ln = getSpPr().getLn();\r
-        CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();\r
-        if (style == null) {\r
-            if (lnEnd.isSetW()) lnEnd.unsetW();\r
-        } else {\r
-            lnEnd.setW(STLineEndWidth.Enum.forInt(style.ordinal() + 1));\r
-        }\r
-    }\r
-\r
-    public LineEndWidth getLineHeadWidth() {\r
-        CTLineProperties ln = getSpPr().getLn();\r
-        if (ln == null || !ln.isSetHeadEnd()) return LineEndWidth.MEDIUM;\r
-\r
-        STLineEndWidth.Enum w = ln.getHeadEnd().getW();\r
-        return w == null ? LineEndWidth.MEDIUM : LineEndWidth.values()[w.intValue() - 1];\r
-    }\r
-\r
-    /**\r
-     * Specifies the line end width in relation to the line width.\r
-     */\r
-    public void setLineHeadLength(LineEndLength style) {\r
-        CTLineProperties ln = getSpPr().getLn();\r
-        CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();\r
-\r
-        if (style == null) {\r
-            if (lnEnd.isSetLen()) lnEnd.unsetLen();\r
-        } else {\r
-            lnEnd.setLen(STLineEndLength.Enum.forInt(style.ordinal() + 1));\r
-        }\r
-    }\r
-\r
-    public LineEndLength getLineHeadLength() {\r
-        CTLineProperties ln = getSpPr().getLn();\r
-        if (ln == null || !ln.isSetHeadEnd()) return LineEndLength.MEDIUM;\r
-\r
-        STLineEndLength.Enum len = ln.getHeadEnd().getLen();\r
-        return len == null ? LineEndLength.MEDIUM : LineEndLength.values()[len.intValue() - 1];\r
-    }\r
-\r
-    /**\r
-     * Specifies the line end decoration, such as a triangle or arrowhead.\r
-     */\r
-    public void setLineTailDecoration(LineDecoration style) {\r
-        CTLineProperties ln = getSpPr().getLn();\r
-        CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();\r
-        if (style == null) {\r
-            if (lnEnd.isSetType()) lnEnd.unsetType();\r
-        } else {\r
-            lnEnd.setType(STLineEndType.Enum.forInt(style.ordinal() + 1));\r
-        }\r
-    }\r
-\r
-    public LineDecoration getLineTailDecoration() {\r
-        CTLineProperties ln = getSpPr().getLn();\r
-        if (ln == null || !ln.isSetTailEnd()) return LineDecoration.NONE;\r
-\r
-        STLineEndType.Enum end = ln.getTailEnd().getType();\r
-        return end == null ? LineDecoration.NONE : LineDecoration.values()[end.intValue() - 1];\r
-    }\r
-\r
-    /**\r
-     * specifies decorations which can be added to the tail of a line.\r
-     */\r
-    public void setLineTailWidth(LineEndWidth style) {\r
-        CTLineProperties ln = getSpPr().getLn();\r
-        CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();\r
-        if (style == null) {\r
-            if (lnEnd.isSetW()) lnEnd.unsetW();\r
-        } else {\r
-            lnEnd.setW(STLineEndWidth.Enum.forInt(style.ordinal() + 1));\r
-        }\r
-    }\r
-\r
-    public LineEndWidth getLineTailWidth() {\r
-        CTLineProperties ln = getSpPr().getLn();\r
-        if (ln == null || !ln.isSetTailEnd()) return LineEndWidth.MEDIUM;\r
-\r
-        STLineEndWidth.Enum w = ln.getTailEnd().getW();\r
-        return w == null ? LineEndWidth.MEDIUM : LineEndWidth.values()[w.intValue() - 1];\r
-    }\r
-\r
-    /**\r
-     * Specifies the line end width in relation to the line width.\r
-     */\r
-    public void setLineTailLength(LineEndLength style) {\r
-        CTLineProperties ln = getSpPr().getLn();\r
-        CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();\r
-\r
-        if (style == null) {\r
-            if (lnEnd.isSetLen()) lnEnd.unsetLen();\r
-        } else {\r
-            lnEnd.setLen(STLineEndLength.Enum.forInt(style.ordinal() + 1));\r
-        }\r
-    }\r
-\r
-    public LineEndLength getLineTailLength() {\r
-        CTLineProperties ln = getSpPr().getLn();\r
-        if (ln == null || !ln.isSetTailEnd()) return LineEndLength.MEDIUM;\r
-\r
-        STLineEndLength.Enum len = ln.getTailEnd().getLen();\r
-        return len == null ? LineEndLength.MEDIUM : LineEndLength.values()[len.intValue() - 1];\r
-    }\r
-\r
-    Outline getTailDecoration() {\r
-        LineEndLength tailLength = getLineTailLength();\r
-        LineEndWidth tailWidth = getLineTailWidth();\r
-\r
-        double lineWidth = Math.max(2.5, getLineWidth());\r
-\r
-        Rectangle2D anchor = getAnchor();\r
-        double x2 = anchor.getX() + anchor.getWidth(),\r
-                y2 = anchor.getY() + anchor.getHeight();\r
-\r
-        double alpha = Math.atan(anchor.getHeight() / anchor.getWidth());\r
-\r
-        AffineTransform at = new AffineTransform();\r
-        Shape shape = null;\r
-        Path p = null;\r
-        Rectangle2D bounds;\r
-        double scaleY = Math.pow(2, tailWidth.ordinal());\r
-        double scaleX = Math.pow(2, tailLength.ordinal());\r
-        switch (getLineTailDecoration()) {\r
-            case OVAL:\r
-                p = new Path();\r
-                shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);\r
-                bounds = shape.getBounds2D();\r
-                at.translate(x2 - bounds.getWidth() / 2, y2 - bounds.getHeight() / 2);\r
-                at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);\r
-                break;\r
-            case ARROW:\r
-                p = new Path();\r
-                GeneralPath arrow = new GeneralPath();\r
-                arrow.moveTo((float) (-lineWidth * 3), (float) (-lineWidth * 2));\r
-                arrow.lineTo(0, 0);\r
-                arrow.lineTo((float) (-lineWidth * 3), (float) (lineWidth * 2));\r
-                shape = arrow;\r
-                at.translate(x2, y2);\r
-                at.rotate(alpha);\r
-                break;\r
-            case TRIANGLE:\r
-                p = new Path();\r
-                scaleY = tailWidth.ordinal() + 1;\r
-                scaleX = tailLength.ordinal() + 1;\r
-                GeneralPath triangle = new GeneralPath();\r
-                triangle.moveTo((float) (-lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));\r
-                triangle.lineTo(0, 0);\r
-                triangle.lineTo((float) (-lineWidth * scaleX), (float) (lineWidth * scaleY / 2));\r
-                triangle.closePath();\r
-                shape = triangle;\r
-                at.translate(x2, y2);\r
-                at.rotate(alpha);\r
-                break;\r
-            default:\r
-                break;\r
-        }\r
-\r
-        if (shape != null) {\r
-            shape = at.createTransformedShape(shape);\r
-        }\r
-        return shape == null ? null : new Outline(shape, p);\r
-    }\r
-\r
-    Outline getHeadDecoration() {\r
-        LineEndLength headLength = getLineHeadLength();\r
-        LineEndWidth headWidth = getLineHeadWidth();\r
-\r
-        double lineWidth = Math.max(2.5, getLineWidth());\r
-        Rectangle2D anchor = getAnchor();\r
-        double x1 = anchor.getX(),\r
-                y1 = anchor.getY();\r
-\r
-        double alpha = Math.atan(anchor.getHeight() / anchor.getWidth());\r
-\r
-        AffineTransform at = new AffineTransform();\r
-        Shape shape = null;\r
-        Path p = null;\r
-        Rectangle2D bounds;\r
-        double scaleY = 1;\r
-        double scaleX = 1;\r
-        switch (getLineHeadDecoration()) {\r
-            case OVAL:\r
-                p = new Path();\r
-                shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);\r
-                bounds = shape.getBounds2D();\r
-                at.translate(x1 - bounds.getWidth() / 2, y1 - bounds.getHeight() / 2);\r
-                at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);\r
-                break;\r
-            case STEALTH:\r
-            case ARROW:\r
-                p = new Path(false, true);\r
-                GeneralPath arrow = new GeneralPath();\r
-                arrow.moveTo((float) (lineWidth * 3 * scaleX), (float) (-lineWidth * scaleY * 2));\r
-                arrow.lineTo(0, 0);\r
-                arrow.lineTo((float) (lineWidth * 3 * scaleX), (float) (lineWidth * scaleY * 2));\r
-                shape = arrow;\r
-                at.translate(x1, y1);\r
-                at.rotate(alpha);\r
-                break;\r
-            case TRIANGLE:\r
-                p = new Path();\r
-                scaleY = headWidth.ordinal() + 1;\r
-                scaleX = headLength.ordinal() + 1;\r
-                GeneralPath triangle = new GeneralPath();\r
-                triangle.moveTo((float) (lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));\r
-                triangle.lineTo(0, 0);\r
-                triangle.lineTo((float) (lineWidth * scaleX), (float) (lineWidth * scaleY / 2));\r
-                triangle.closePath();\r
-                shape = triangle;\r
-                at.translate(x1, y1);\r
-                at.rotate(alpha);\r
-                break;\r
-            default:\r
-                break;\r
-        }\r
-\r
-        if (shape != null) {\r
-            shape = at.createTransformedShape(shape);\r
-        }\r
-        return shape == null ? null : new Outline(shape, p);\r
-    }\r
-\r
-    private List<Outline> getDecorationOutlines(){\r
-        List<Outline> lst = new ArrayList<Outline>();\r
-\r
-        Outline head = getHeadDecoration();\r
-        if(head != null) lst.add(head);\r
-\r
-        Outline tail = getTailDecoration();\r
-        if(tail != null) lst.add(tail);\r
-        return lst;\r
-    }\r
 \r
     /**\r
      * YK: dashing of lines is suppressed for now.\r
@@ -341,22 +85,4 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
         return null;\r
     }\r
 \r
-    @Override\r
-    public void draw(Graphics2D graphics){\r
-        super.draw(graphics);\r
-\r
-        // draw line decorations\r
-        Color lineColor = getLineColor();\r
-        if(lineColor != null) {\r
-            graphics.setPaint(lineColor);\r
-            for(Outline o : getDecorationOutlines()){\r
-                if(o.getPath().isFilled()){\r
-                    graphics.fill(o.getOutline());\r
-                }            \r
-                if(o.getPath().isStroked()){\r
-                    graphics.draw(o.getOutline());\r
-                }\r
-            }\r
-        }\r
-    }\r
 }
\ No newline at end of file
index 92adf446e06e03b85784aa7b6c37312b5e483c38..16ecef862372d8dcae76702993c791f06cae9c85 100644 (file)
@@ -35,25 +35,7 @@ import org.apache.poi.openxml4j.opc.TargetMode;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;\r
 import org.apache.poi.POIXMLException;\r
 import org.apache.xmlbeans.XmlObject;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTEffectStyleItem;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetLineDashProperties;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.*;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;\r
@@ -63,8 +45,10 @@ import java.awt.Graphics2D;
 import java.awt.Paint;\r
 import java.awt.Shape;\r
 import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Ellipse2D;\r
 import java.awt.geom.GeneralPath;\r
 import java.awt.geom.Rectangle2D;\r
+import java.util.ArrayList;\r
 import java.util.Collection;\r
 import java.util.Collections;\r
 import java.util.List;\r
@@ -555,6 +539,20 @@ public abstract class XSLFSimpleShape extends XSLFShape {
     public void draw(Graphics2D graphics) {\r
         RenderableShape rShape = new RenderableShape(this);\r
         rShape.render(graphics);\r
+\r
+        // draw line decorations\r
+        Color lineColor = getLineColor();\r
+        if(lineColor != null) {\r
+            graphics.setPaint(lineColor);\r
+            for(Outline o : getDecorationOutlines()){\r
+                if(o.getPath().isFilled()){\r
+                    graphics.fill(o.getOutline());\r
+                }\r
+                if(o.getPath().isStroked()){\r
+                    graphics.draw(o.getOutline());\r
+                }\r
+            }\r
+        }\r
     }\r
 \r
 \r
@@ -696,4 +694,262 @@ public abstract class XSLFSimpleShape extends XSLFShape {
         }\r
 \r
     }\r
+\r
+    /**\r
+     * Specifies the line end decoration, such as a triangle or arrowhead.\r
+     */\r
+    public void setLineHeadDecoration(LineDecoration style) {\r
+        CTLineProperties ln = getSpPr().getLn();\r
+        CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();\r
+        if (style == null) {\r
+            if (lnEnd.isSetType()) lnEnd.unsetType();\r
+        } else {\r
+            lnEnd.setType(STLineEndType.Enum.forInt(style.ordinal() + 1));\r
+        }\r
+    }\r
+\r
+    public LineDecoration getLineHeadDecoration() {\r
+        CTLineProperties ln = getSpPr().getLn();\r
+        if (ln == null || !ln.isSetHeadEnd()) return LineDecoration.NONE;\r
+\r
+        STLineEndType.Enum end = ln.getHeadEnd().getType();\r
+        return end == null ? LineDecoration.NONE : LineDecoration.values()[end.intValue() - 1];\r
+    }\r
+\r
+    /**\r
+     * specifies decorations which can be added to the head of a line.\r
+     */\r
+    public void setLineHeadWidth(LineEndWidth style) {\r
+        CTLineProperties ln = getSpPr().getLn();\r
+        CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();\r
+        if (style == null) {\r
+            if (lnEnd.isSetW()) lnEnd.unsetW();\r
+        } else {\r
+            lnEnd.setW(STLineEndWidth.Enum.forInt(style.ordinal() + 1));\r
+        }\r
+    }\r
+\r
+    public LineEndWidth getLineHeadWidth() {\r
+        CTLineProperties ln = getSpPr().getLn();\r
+        if (ln == null || !ln.isSetHeadEnd()) return LineEndWidth.MEDIUM;\r
+\r
+        STLineEndWidth.Enum w = ln.getHeadEnd().getW();\r
+        return w == null ? LineEndWidth.MEDIUM : LineEndWidth.values()[w.intValue() - 1];\r
+    }\r
+\r
+    /**\r
+     * Specifies the line end width in relation to the line width.\r
+     */\r
+    public void setLineHeadLength(LineEndLength style) {\r
+        CTLineProperties ln = getSpPr().getLn();\r
+        CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd();\r
+\r
+        if (style == null) {\r
+            if (lnEnd.isSetLen()) lnEnd.unsetLen();\r
+        } else {\r
+            lnEnd.setLen(STLineEndLength.Enum.forInt(style.ordinal() + 1));\r
+        }\r
+    }\r
+\r
+    public LineEndLength getLineHeadLength() {\r
+        CTLineProperties ln = getSpPr().getLn();\r
+        if (ln == null || !ln.isSetHeadEnd()) return LineEndLength.MEDIUM;\r
+\r
+        STLineEndLength.Enum len = ln.getHeadEnd().getLen();\r
+        return len == null ? LineEndLength.MEDIUM : LineEndLength.values()[len.intValue() - 1];\r
+    }\r
+\r
+    /**\r
+     * Specifies the line end decoration, such as a triangle or arrowhead.\r
+     */\r
+    public void setLineTailDecoration(LineDecoration style) {\r
+        CTLineProperties ln = getSpPr().getLn();\r
+        CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();\r
+        if (style == null) {\r
+            if (lnEnd.isSetType()) lnEnd.unsetType();\r
+        } else {\r
+            lnEnd.setType(STLineEndType.Enum.forInt(style.ordinal() + 1));\r
+        }\r
+    }\r
+\r
+    public LineDecoration getLineTailDecoration() {\r
+        CTLineProperties ln = getSpPr().getLn();\r
+        if (ln == null || !ln.isSetTailEnd()) return LineDecoration.NONE;\r
+\r
+        STLineEndType.Enum end = ln.getTailEnd().getType();\r
+        return end == null ? LineDecoration.NONE : LineDecoration.values()[end.intValue() - 1];\r
+    }\r
+\r
+    /**\r
+     * specifies decorations which can be added to the tail of a line.\r
+     */\r
+    public void setLineTailWidth(LineEndWidth style) {\r
+        CTLineProperties ln = getSpPr().getLn();\r
+        CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();\r
+        if (style == null) {\r
+            if (lnEnd.isSetW()) lnEnd.unsetW();\r
+        } else {\r
+            lnEnd.setW(STLineEndWidth.Enum.forInt(style.ordinal() + 1));\r
+        }\r
+    }\r
+\r
+    public LineEndWidth getLineTailWidth() {\r
+        CTLineProperties ln = getSpPr().getLn();\r
+        if (ln == null || !ln.isSetTailEnd()) return LineEndWidth.MEDIUM;\r
+\r
+        STLineEndWidth.Enum w = ln.getTailEnd().getW();\r
+        return w == null ? LineEndWidth.MEDIUM : LineEndWidth.values()[w.intValue() - 1];\r
+    }\r
+\r
+    /**\r
+     * Specifies the line end width in relation to the line width.\r
+     */\r
+    public void setLineTailLength(LineEndLength style) {\r
+        CTLineProperties ln = getSpPr().getLn();\r
+        CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd();\r
+\r
+        if (style == null) {\r
+            if (lnEnd.isSetLen()) lnEnd.unsetLen();\r
+        } else {\r
+            lnEnd.setLen(STLineEndLength.Enum.forInt(style.ordinal() + 1));\r
+        }\r
+    }\r
+\r
+    public LineEndLength getLineTailLength() {\r
+        CTLineProperties ln = getSpPr().getLn();\r
+        if (ln == null || !ln.isSetTailEnd()) return LineEndLength.MEDIUM;\r
+\r
+        STLineEndLength.Enum len = ln.getTailEnd().getLen();\r
+        return len == null ? LineEndLength.MEDIUM : LineEndLength.values()[len.intValue() - 1];\r
+    }\r
+\r
+    Outline getTailDecoration() {\r
+        LineEndLength tailLength = getLineTailLength();\r
+        LineEndWidth tailWidth = getLineTailWidth();\r
+\r
+        double lineWidth = Math.max(2.5, getLineWidth());\r
+\r
+        Rectangle2D anchor = getAnchor();\r
+        double x2 = anchor.getX() + anchor.getWidth(),\r
+                y2 = anchor.getY() + anchor.getHeight();\r
+\r
+        double alpha = Math.atan(anchor.getHeight() / anchor.getWidth());\r
+\r
+        AffineTransform at = new AffineTransform();\r
+        Shape shape = null;\r
+        Path p = null;\r
+        Rectangle2D bounds;\r
+        double scaleY = Math.pow(2, tailWidth.ordinal());\r
+        double scaleX = Math.pow(2, tailLength.ordinal());\r
+        switch (getLineTailDecoration()) {\r
+            case OVAL:\r
+                p = new Path();\r
+                shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);\r
+                bounds = shape.getBounds2D();\r
+                at.translate(x2 - bounds.getWidth() / 2, y2 - bounds.getHeight() / 2);\r
+                at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);\r
+                break;\r
+            case ARROW:\r
+                p = new Path();\r
+                GeneralPath arrow = new GeneralPath();\r
+                arrow.moveTo((float) (-lineWidth * 3), (float) (-lineWidth * 2));\r
+                arrow.lineTo(0, 0);\r
+                arrow.lineTo((float) (-lineWidth * 3), (float) (lineWidth * 2));\r
+                shape = arrow;\r
+                at.translate(x2, y2);\r
+                at.rotate(alpha);\r
+                break;\r
+            case TRIANGLE:\r
+                p = new Path();\r
+                scaleY = tailWidth.ordinal() + 1;\r
+                scaleX = tailLength.ordinal() + 1;\r
+                GeneralPath triangle = new GeneralPath();\r
+                triangle.moveTo((float) (-lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));\r
+                triangle.lineTo(0, 0);\r
+                triangle.lineTo((float) (-lineWidth * scaleX), (float) (lineWidth * scaleY / 2));\r
+                triangle.closePath();\r
+                shape = triangle;\r
+                at.translate(x2, y2);\r
+                at.rotate(alpha);\r
+                break;\r
+            default:\r
+                break;\r
+        }\r
+\r
+        if (shape != null) {\r
+            shape = at.createTransformedShape(shape);\r
+        }\r
+        return shape == null ? null : new Outline(shape, p);\r
+    }\r
+\r
+    Outline getHeadDecoration() {\r
+        LineEndLength headLength = getLineHeadLength();\r
+        LineEndWidth headWidth = getLineHeadWidth();\r
+\r
+        double lineWidth = Math.max(2.5, getLineWidth());\r
+        Rectangle2D anchor = getAnchor();\r
+        double x1 = anchor.getX(),\r
+                y1 = anchor.getY();\r
+\r
+        double alpha = Math.atan(anchor.getHeight() / anchor.getWidth());\r
+\r
+        AffineTransform at = new AffineTransform();\r
+        Shape shape = null;\r
+        Path p = null;\r
+        Rectangle2D bounds;\r
+        double scaleY = 1;\r
+        double scaleX = 1;\r
+        switch (getLineHeadDecoration()) {\r
+            case OVAL:\r
+                p = new Path();\r
+                shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);\r
+                bounds = shape.getBounds2D();\r
+                at.translate(x1 - bounds.getWidth() / 2, y1 - bounds.getHeight() / 2);\r
+                at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);\r
+                break;\r
+            case STEALTH:\r
+            case ARROW:\r
+                p = new Path(false, true);\r
+                GeneralPath arrow = new GeneralPath();\r
+                arrow.moveTo((float) (lineWidth * 3 * scaleX), (float) (-lineWidth * scaleY * 2));\r
+                arrow.lineTo(0, 0);\r
+                arrow.lineTo((float) (lineWidth * 3 * scaleX), (float) (lineWidth * scaleY * 2));\r
+                shape = arrow;\r
+                at.translate(x1, y1);\r
+                at.rotate(alpha);\r
+                break;\r
+            case TRIANGLE:\r
+                p = new Path();\r
+                scaleY = headWidth.ordinal() + 1;\r
+                scaleX = headLength.ordinal() + 1;\r
+                GeneralPath triangle = new GeneralPath();\r
+                triangle.moveTo((float) (lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));\r
+                triangle.lineTo(0, 0);\r
+                triangle.lineTo((float) (lineWidth * scaleX), (float) (lineWidth * scaleY / 2));\r
+                triangle.closePath();\r
+                shape = triangle;\r
+                at.translate(x1, y1);\r
+                at.rotate(alpha);\r
+                break;\r
+            default:\r
+                break;\r
+        }\r
+\r
+        if (shape != null) {\r
+            shape = at.createTransformedShape(shape);\r
+        }\r
+        return shape == null ? null : new Outline(shape, p);\r
+    }\r
+\r
+    private List<Outline> getDecorationOutlines(){\r
+        List<Outline> lst = new ArrayList<Outline>();\r
+\r
+        Outline head = getHeadDecoration();\r
+        if(head != null) lst.add(head);\r
+\r
+        Outline tail = getTailDecoration();\r
+        if(tail != null) lst.add(tail);\r
+        return lst;\r
+    }\r
+\r
 }\r
index 7f5e967ccc964378ba3974770af778c0cd548272..50a66667abcd5f1cf0159e9f6db8007649ba1bc6 100644 (file)
@@ -39,7 +39,7 @@ public class TestPresetGeometries extends TestCase {
     public void testRead(){
 
         Map<String, CustomGeometry> shapes = PresetGeometries.getInstance();
-        assertEquals(186, shapes.size());
+        assertEquals(187, shapes.size());
 
 
         for(String name : shapes.keySet()) {
index f5fead717fe06e46e3de7b2bf0c1e70322fe409f..4a3a0701d3293c8b7ffd9ab3cf94a3458bc76a3c 100755 (executable)
     </pathLst>\r
 \r
   </upArrowCallout>\r
-  <upDownArrow>\r
+  <upArrow>\r
     <avLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">\r
       <gd name="adj1" fmla="val 50000" />\r
       <gd name="adj2" fmla="val 50000" />\r
           <pt x="x2" y="y2" />\r
         </lnTo>\r
         <lnTo>\r
-          <pt x="x2" y="y3" />\r
-        </lnTo>\r
-        <lnTo>\r
-          <pt x="r" y="y3" />\r
-        </lnTo>\r
-        <lnTo>\r
-          <pt x="hc" y="b" />\r
-        </lnTo>\r
-        <lnTo>\r
-          <pt x="l" y="y3" />\r
+          <pt x="x2" y="b" />\r
         </lnTo>\r
         <lnTo>\r
-          <pt x="x1" y="y3" />\r
+          <pt x="x1" y="b" />\r
         </lnTo>\r
         <lnTo>\r
           <pt x="x1" y="y2" />\r
         <close />\r
       </path>\r
     </pathLst>\r
-  </upDownArrow>\r
+  </upArrow>\r
   <upDownArrow>\r
     <avLst xmlns="http://schemas.openxmlformats.org/drawingml/2006/main">\r
       <gd name="adj1" fmla="val 50000" />\r