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