git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1709354 13f79535-47bb-0310-9956-ffa450edef68pull/24/head
@@ -0,0 +1,50 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.exceptions; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.POIXMLException; | |||
public class XDGFException { | |||
/** | |||
* Creates an error message to be thrown | |||
*/ | |||
public static POIXMLException error(String message, Object o) { | |||
return new POIXMLException(o.toString() + ": " + message); | |||
} | |||
public static POIXMLException error(String message, Object o, Throwable t) { | |||
return new POIXMLException(o.toString() + ": " + message, t); | |||
} | |||
// | |||
// Use these to wrap error messages coming up so that we have at least | |||
// some idea where the error was located | |||
// | |||
public static POIXMLException wrap(POIXMLDocumentPart part, POIXMLException e) { | |||
return new POIXMLException(part.getPackagePart().getPartName().toString() + ": " + e.getMessage(), | |||
e.getCause() == null ? e : e.getCause()); | |||
} | |||
public static POIXMLException wrap(String where, POIXMLException e) { | |||
return new POIXMLException(where + ": " + e.getMessage(), | |||
e.getCause() == null ? e : e.getCause()); | |||
} | |||
} |
@@ -0,0 +1,73 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.geom; | |||
import java.awt.geom.Dimension2D; | |||
public class Dimension2dDouble extends Dimension2D { | |||
double width; | |||
double height; | |||
public Dimension2dDouble() { | |||
width = 0d; | |||
height = 0d; | |||
} | |||
public Dimension2dDouble(double width, double height) { | |||
this.width = width; | |||
this.height = height; | |||
} | |||
@Override | |||
public double getWidth() { | |||
return width; | |||
} | |||
@Override | |||
public double getHeight() { | |||
return height; | |||
} | |||
@Override | |||
public void setSize(double width, double height) { | |||
this.width = width; | |||
this.height = height; | |||
} | |||
@Override | |||
public boolean equals(Object obj) { | |||
if (obj instanceof Dimension2dDouble) { | |||
Dimension2dDouble other = (Dimension2dDouble)obj; | |||
return width == other.width && height == other.height; | |||
} | |||
return false; | |||
} | |||
@Override | |||
public int hashCode() { | |||
double sum = width + height; | |||
return (int)Math.ceil(sum * (sum + 1)/2 + width); | |||
} | |||
@Override | |||
public String toString() { | |||
return "Dimension2dDouble[" + width + ", " + height + "]"; | |||
} | |||
} |
@@ -0,0 +1,79 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.geom; | |||
import java.awt.geom.Point2D; | |||
import java.util.ArrayList; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import org.apache.poi.xdgf.usermodel.section.geometry.SplineKnot; | |||
import org.apache.poi.xdgf.usermodel.section.geometry.SplineStart; | |||
import com.graphbuilder.curve.ControlPath; | |||
import com.graphbuilder.curve.ShapeMultiPath; | |||
import com.graphbuilder.curve.ValueVector; | |||
import com.graphbuilder.geom.PointFactory; | |||
public class SplineCollector { | |||
SplineStart _start; | |||
ArrayList<SplineKnot> _knots = new ArrayList<>(); | |||
public SplineCollector(SplineStart start) { | |||
_start = start; | |||
} | |||
public void addKnot(SplineKnot knot) { | |||
if (!knot.getDel()) | |||
_knots.add(knot); | |||
} | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
// ok, we have the start, and all knots... do something with this | |||
Point2D last = path.getCurrentPoint(); | |||
// create a control path and knots | |||
ControlPath controlPath = new ControlPath(); | |||
ValueVector knots = new ValueVector(_knots.size() + 3); | |||
double firstKnot = _start.getB(); | |||
double lastKnot = _start.getC(); | |||
int degree = _start.getD(); | |||
// first/second knot | |||
knots.add(firstKnot); | |||
knots.add(_start.getA()); | |||
// first/second control point | |||
controlPath.addPoint(PointFactory.create(last.getX(), last.getY())); | |||
controlPath.addPoint(PointFactory.create(_start.getX(), _start.getY())); | |||
// middle knots/control points | |||
for (SplineKnot knot: _knots) { | |||
knots.add(knot.getA()); | |||
controlPath.addPoint(PointFactory.create(knot.getX(), knot.getY())); | |||
} | |||
// last knot | |||
knots.add(lastKnot); | |||
ShapeMultiPath shape = SplineRenderer.createNurbsSpline(controlPath, knots, null, degree); | |||
path.append(shape, true); | |||
} | |||
} |
@@ -0,0 +1,68 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.geom; | |||
import com.graphbuilder.curve.ControlPath; | |||
import com.graphbuilder.curve.GroupIterator; | |||
import com.graphbuilder.curve.NURBSpline; | |||
import com.graphbuilder.curve.ShapeMultiPath; | |||
import com.graphbuilder.curve.ValueVector; | |||
public class SplineRenderer { | |||
public static ShapeMultiPath createNurbsSpline(ControlPath controlPoints, | |||
ValueVector knots, | |||
ValueVector weights, | |||
int degree) { | |||
double firstKnot = knots.get(0); | |||
double lastKnot = knots.get(knots.size()-1); | |||
// scale knots to [0, 1] based on first/last knots | |||
for (int i = 0; i < knots.size(); i++) { | |||
knots.set((knots.get(i) - firstKnot)/lastKnot, i); | |||
} | |||
// if we don't have enough knots, duplicate the last knot until we do | |||
for (int i = knots.size(); i < controlPoints.numPoints() + degree + 1; i++) { | |||
knots.add(1); | |||
} | |||
GroupIterator gi = new GroupIterator("0:n-1", controlPoints.numPoints()); | |||
NURBSpline spline = new NURBSpline(controlPoints, gi); | |||
spline.setDegree(degree); | |||
spline.setKnotVectorType(NURBSpline.NON_UNIFORM); | |||
spline.setKnotVector(knots); | |||
if (weights == null) { | |||
spline.setUseWeightVector(false); | |||
} else { | |||
spline.setWeightVector(weights); | |||
} | |||
// now that this is done, add it to the path | |||
ShapeMultiPath shape = new ShapeMultiPath(); | |||
shape.setFlatness(0.01); | |||
spline.appendTo(shape); | |||
return shape; | |||
} | |||
} |
@@ -0,0 +1,159 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.awt.Graphics2D; | |||
import java.awt.geom.AffineTransform; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
import org.apache.poi.util.Internal; | |||
import org.apache.poi.xdgf.exceptions.XDGFException; | |||
import org.apache.poi.xdgf.usermodel.shape.ShapeRenderer; | |||
import org.apache.poi.xdgf.usermodel.shape.ShapeVisitor; | |||
import org.apache.poi.xdgf.usermodel.shape.exceptions.StopVisiting; | |||
import org.apache.poi.xdgf.xml.XDGFXMLDocumentPart; | |||
import com.microsoft.schemas.office.visio.x2012.main.ConnectType; | |||
import com.microsoft.schemas.office.visio.x2012.main.PageContentsType; | |||
import com.microsoft.schemas.office.visio.x2012.main.ShapeSheetType; | |||
/** | |||
* Container of shapes for a page in a visio document | |||
*/ | |||
public class XDGFBaseContents extends XDGFXMLDocumentPart { | |||
protected PageContentsType _pageContents; | |||
// shapes without parents | |||
protected List<XDGFShape> _toplevelShapes = new ArrayList<>(); | |||
protected Map<Long, XDGFShape> _shapes = new HashMap<>(); | |||
protected List<XDGFConnection> _connections = new ArrayList<>(); | |||
public XDGFBaseContents(PackagePart part, PackageRelationship rel, XDGFDocument document) { | |||
super(part, rel, document); | |||
} | |||
@Internal | |||
public PageContentsType getXmlObject() { | |||
return _pageContents; | |||
} | |||
@Override | |||
protected void onDocumentRead() { | |||
if (_pageContents.isSetShapes()) { | |||
for (ShapeSheetType shapeSheet: _pageContents.getShapes().getShapeArray()) { | |||
XDGFShape shape = new XDGFShape(shapeSheet, this, _document); | |||
_toplevelShapes.add(shape); | |||
addToShapeIndex(shape); | |||
} | |||
} | |||
if (_pageContents.isSetConnects()) { | |||
for (ConnectType connect: _pageContents.getConnects().getConnectArray()) { | |||
XDGFShape from = _shapes.get(connect.getFromSheet()); | |||
XDGFShape to = _shapes.get(connect.getToSheet()); | |||
if (from == null) | |||
throw new POIXMLException(this.toString() + "; Connect; Invalid from id: " + connect.getFromSheet()); | |||
if (to == null) | |||
throw new POIXMLException(this.toString() + "; Connect; Invalid to id: " + connect.getToSheet()); | |||
_connections.add(new XDGFConnection(connect, from, to)); | |||
} | |||
} | |||
} | |||
protected void addToShapeIndex(XDGFShape shape) { | |||
_shapes.put(shape.getID(), shape); | |||
List<XDGFShape> shapes = shape.getShapes(); | |||
if (shapes == null) | |||
return; | |||
for (XDGFShape subshape: shapes) | |||
addToShapeIndex(subshape); | |||
} | |||
// | |||
// API | |||
// | |||
/** | |||
* | |||
* @param graphics | |||
*/ | |||
public void draw(Graphics2D graphics) { | |||
visitShapes(new ShapeRenderer(graphics)); | |||
} | |||
public XDGFShape getShapeById(long id) { | |||
return _shapes.get(id); | |||
} | |||
public Map<Long, XDGFShape> getShapesMap() { | |||
return Collections.unmodifiableMap(_shapes); | |||
} | |||
public Collection<XDGFShape> getShapes() { | |||
return _shapes.values(); | |||
} | |||
public List<XDGFShape> getTopLevelShapes() { | |||
return Collections.unmodifiableList(_toplevelShapes); | |||
} | |||
// get connections | |||
public List<XDGFConnection> getConnections() { | |||
return Collections.unmodifiableList(_connections); | |||
} | |||
@Override | |||
public String toString() { | |||
return getPackagePart().getPartName().toString(); | |||
} | |||
/** | |||
* Provides iteration over the shapes using the visitor pattern, and provides | |||
* an easy way to convert shape coordinates into global coordinates | |||
*/ | |||
public void visitShapes(ShapeVisitor visitor) { | |||
try { | |||
for (XDGFShape shape: _toplevelShapes) { | |||
shape.visitShapes(visitor, new AffineTransform(), 0); | |||
} | |||
} catch (StopVisiting e) { | |||
// intentionally empty | |||
} catch (POIXMLException e) { | |||
throw XDGFException.wrap(this, e); | |||
} | |||
} | |||
} |
@@ -0,0 +1,150 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.util.Map; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.util.Internal; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
/** | |||
* There are a lot of different cell types. Cell is really just an attribute | |||
* of the thing that it's attached to. Will probably refactor this once I | |||
* figure out a better way to use them | |||
* | |||
* The various attributes of a Cell are constrained, and are better defined | |||
* in the XSD 1.1 visio schema | |||
*/ | |||
public class XDGFCell { | |||
public static Boolean maybeGetBoolean(Map<String, XDGFCell> cells, String name) { | |||
XDGFCell cell = cells.get(name); | |||
if (cell == null) | |||
return null; | |||
if (cell.getValue().equals("0")) | |||
return false; | |||
if (cell.getValue().equals("1")) | |||
return true; | |||
throw new POIXMLException("Invalid boolean value for '" + cell.getName() + "'"); | |||
} | |||
public static Double maybeGetDouble(Map<String, XDGFCell> cells, String name) { | |||
XDGFCell cell = cells.get(name); | |||
if (cell != null) | |||
return parseDoubleValue(cell._cell); | |||
return null; | |||
} | |||
public static Integer maybeGetInteger(Map<String, XDGFCell> cells, String name) { | |||
XDGFCell cell = cells.get(name); | |||
if (cell != null) | |||
return parseIntegerValue(cell._cell); | |||
return null; | |||
} | |||
public static String maybeGetString(Map<String, XDGFCell> cells, String name) { | |||
XDGFCell cell = cells.get(name); | |||
if (cell != null) { | |||
String v = cell._cell.getV(); | |||
if (v.equals("Themed")) | |||
return null; | |||
return v; | |||
} | |||
return null; | |||
} | |||
public static Double parseDoubleValue(CellType cell) { | |||
try { | |||
return Double.parseDouble(cell.getV()); | |||
} catch (NumberFormatException e) { | |||
if (cell.getV().equals("Themed")) | |||
return null; | |||
throw new POIXMLException("Invalid float value for '" + cell.getN() + "': " + e); | |||
} | |||
} | |||
public static Integer parseIntegerValue(CellType cell) { | |||
try { | |||
return Integer.parseInt(cell.getV()); | |||
} catch (NumberFormatException e) { | |||
if (cell.getV().equals("Themed")) | |||
return null; | |||
throw new POIXMLException("Invalid integer value for '" + cell.getN() + "': " + e); | |||
} | |||
} | |||
// returns a length, converts it to inches? | |||
public static Double parseVLength(CellType cell) { | |||
try { | |||
return Double.parseDouble(cell.getV()); | |||
} catch (NumberFormatException e) { | |||
if (cell.getV().equals("Themed")) | |||
return null; | |||
throw new POIXMLException("Invalid float value for '" + cell.getN() + "': " + e); | |||
} | |||
} | |||
CellType _cell; | |||
public XDGFCell(CellType cell) { | |||
_cell = cell; | |||
} | |||
@Internal | |||
CellType getXmlObject() { | |||
return _cell; | |||
} | |||
/** | |||
* Represents the name of the ShapeSheet cell. | |||
*/ | |||
public String getName() { | |||
return _cell.getN(); | |||
} | |||
/** | |||
* Represents the value of the cell. | |||
*/ | |||
public String getValue() { | |||
return _cell.getV(); | |||
} | |||
/** | |||
* Represents the element’s formula. This attribute can contain one of the following strings: | |||
* - ‘(some formula)’ if the formula exists locally | |||
* - No Formula if the formula is locally deleted or blocked | |||
* - Inh if the formula is inherited. | |||
*/ | |||
public String getFormula() { | |||
return _cell.getF(); | |||
} | |||
/* | |||
* Indicates that the formula evaluates to an error. The value of E is the | |||
* current value (an error message string); the value of the V attribute is | |||
* the last valid value. | |||
*/ | |||
public String getError() { | |||
return _cell.getE(); | |||
} | |||
} |
@@ -0,0 +1,134 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import com.microsoft.schemas.office.visio.x2012.main.ConnectType; | |||
public class XDGFConnection { | |||
// comments on frompart/topart taken from pkgVisio | |||
// https://msdn.microsoft.com/en-us/library/ms367611(v=office.12).aspx | |||
// The following constants declared by the Microsoft Office Visio type | |||
// library show return values for the FromPart property. | |||
// Constant Value | |||
// visConnectFromError -1 | |||
// visFromNone 0 | |||
// visLeftEdge 1 | |||
// visCenterEdge 2 | |||
// visRightEdge 3 | |||
// visBottomEdge 4 | |||
// visMiddleEdge 5 | |||
// visTopEdge 6 | |||
// visBeginX 7 | |||
// visBeginY 8 | |||
// visBegin 9 | |||
// visEndX 10 | |||
// visEndY 11 | |||
// visEnd 12 | |||
// visFromAngle 13 | |||
// visFromPin 14 | |||
// visControlPoint 100 + zero-based row index (for example, visControlPoint = 100 if the control point is in row 0; visControlPoint = 101 if the control point is in row 1) | |||
public static final int visConnectFromError = -1; | |||
public static final int visFromNone = 0; | |||
public static final int visLeftEdge = 1; | |||
public static final int visCenterEdge = 2; | |||
public static final int visRightEdge = 3; | |||
public static final int visBottomEdge = 4; | |||
public static final int visMiddleEdge = 5; | |||
public static final int visTopEdge = 6; | |||
public static final int visBeginX = 7; | |||
public static final int visBeginY = 8; | |||
public static final int visBegin = 9; | |||
public static final int visEndX = 10; | |||
public static final int visEndY = 11; | |||
public static final int visEnd = 12; | |||
public static final int visFromAngle = 13; | |||
public static final int visFromPin = 14; | |||
// The ToPart property identifies the part of a shape to which another | |||
// shape is glued, such as its begin point or endpoint, one of its edges, | |||
// or a connection point. The following constants declared by the Visio type library in member VisToParts show possible return values for the ToPart property. | |||
// Constant Value | |||
// visConnectToError -1 | |||
// visToNone 0 | |||
// visGuideX 1 | |||
// visGuideY 2 | |||
// visWholeShape 3 | |||
// visGuideIntersect 4 | |||
// visToAngle 7 | |||
// visConnectionPoint 100 + row index of connection point | |||
public static final int visConnectToError = -1; | |||
public static final int visToNone = 0; | |||
public static final int visGuideX = 1; | |||
public static final int visGuideY = 2; | |||
public static final int visWholeShape = 3; | |||
public static final int visGuideIntersect = 4; | |||
public static final int visToAngle = 7; | |||
private ConnectType _connect; | |||
private XDGFShape _from; | |||
private XDGFShape _to; | |||
public XDGFConnection(ConnectType connect, XDGFShape from, XDGFShape to) { | |||
_connect = connect; | |||
_from = from; | |||
_to = to; | |||
} | |||
public XDGFShape getFromShape() { | |||
return _from; | |||
} | |||
public XDGFCell getFromCell() { | |||
return _from.getCell(_connect.getFromCell()); | |||
} | |||
public String getFromCellName() { | |||
return _connect.getFromCell(); | |||
} | |||
public XDGFShape getToShape() { | |||
return _to; | |||
} | |||
public String getToCellName() { | |||
return _connect.getToCell(); | |||
} | |||
// see constants above | |||
public Integer getFromPart() { | |||
if (_connect.isSetFromPart()) | |||
return _connect.getFromPart(); | |||
else | |||
return null; | |||
} | |||
// see constants above | |||
public Integer getToPart() { | |||
if (_connect.isSetToPart()) | |||
return _connect.getToPart(); | |||
else | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,116 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.util.Internal; | |||
import com.microsoft.schemas.office.visio.x2012.main.DocumentSettingsType; | |||
import com.microsoft.schemas.office.visio.x2012.main.StyleSheetType; | |||
import com.microsoft.schemas.office.visio.x2012.main.VisioDocumentType; | |||
/** | |||
* Represents the root document: /visio/document.xml | |||
*/ | |||
public class XDGFDocument { | |||
protected VisioDocumentType _document; | |||
Map<Long, XDGFStyleSheet> _styleSheets = new HashMap<>(); | |||
// defaults | |||
long _defaultFillStyle = 0; | |||
long _defaultGuideStyle = 0; | |||
long _defaultLineStyle = 0; | |||
long _defaultTextStyle = 0; | |||
public XDGFDocument(VisioDocumentType document) { | |||
_document = document; | |||
if (!_document.isSetDocumentSettings()) | |||
throw new POIXMLException("Document settings not found"); | |||
DocumentSettingsType docSettings = _document.getDocumentSettings(); | |||
if (docSettings.isSetDefaultFillStyle()) | |||
_defaultFillStyle = docSettings.getDefaultFillStyle(); | |||
if (docSettings.isSetDefaultGuideStyle()) | |||
_defaultGuideStyle = docSettings.getDefaultGuideStyle(); | |||
if (docSettings.isSetDefaultLineStyle()) | |||
_defaultLineStyle = docSettings.getDefaultLineStyle(); | |||
if (docSettings.isSetDefaultTextStyle()) | |||
_defaultTextStyle = docSettings.getDefaultTextStyle(); | |||
if (_document.isSetStyleSheets()) { | |||
for (StyleSheetType styleSheet: _document.getStyleSheets().getStyleSheetArray()) { | |||
_styleSheets.put(styleSheet.getID(), new XDGFStyleSheet(styleSheet, this)); | |||
} | |||
} | |||
} | |||
@Internal | |||
public VisioDocumentType getXmlObject() { | |||
return _document; | |||
} | |||
public XDGFStyleSheet getStyleById(long id) { | |||
return _styleSheets.get(id); | |||
} | |||
public XDGFStyleSheet getDefaultFillStyle() { | |||
XDGFStyleSheet style = getStyleById(_defaultFillStyle); | |||
if (style == null) | |||
throw new POIXMLException("No default fill style found!"); | |||
return style; | |||
} | |||
public XDGFStyleSheet getDefaultGuideStyle() { | |||
XDGFStyleSheet style = getStyleById(_defaultGuideStyle); | |||
if (style == null) | |||
throw new POIXMLException("No default guide style found!"); | |||
return style; | |||
} | |||
public XDGFStyleSheet getDefaultLineStyle() { | |||
XDGFStyleSheet style = getStyleById(_defaultLineStyle); | |||
if (style == null) | |||
throw new POIXMLException("No default line style found!"); | |||
return style; | |||
} | |||
public XDGFStyleSheet getDefaultTextStyle() { | |||
XDGFStyleSheet style = getStyleById(_defaultTextStyle); | |||
if (style == null) | |||
throw new POIXMLException("No default text style found!"); | |||
return style; | |||
} | |||
} |
@@ -0,0 +1,75 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.lang.reflect.Constructor; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.POIXMLFactory; | |||
import org.apache.poi.POIXMLRelation; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
import org.apache.poi.util.POILogFactory; | |||
import org.apache.poi.util.POILogger; | |||
public class XDGFFactory extends POIXMLFactory { | |||
private static final POILogger logger = POILogFactory.getLogger(XDGFFactory.class); | |||
private XDGFDocument _document; | |||
public XDGFFactory(XDGFDocument document){ | |||
_document = document; | |||
} | |||
@Override | |||
public POIXMLDocumentPart createDocumentPart(POIXMLDocumentPart parent, | |||
PackageRelationship rel, PackagePart part) { | |||
POIXMLRelation descriptor = XDGFRelation.getInstance(rel.getRelationshipType()); | |||
if(descriptor == null || descriptor.getRelationClass() == null){ | |||
logger.log(POILogger.DEBUG, "using default POIXMLDocumentPart for " + rel.getRelationshipType()); | |||
return new POIXMLDocumentPart(part, rel); | |||
} | |||
try { | |||
Class<? extends POIXMLDocumentPart> cls = descriptor.getRelationClass(); | |||
try { | |||
Constructor<? extends POIXMLDocumentPart> constructor = cls.getDeclaredConstructor(POIXMLDocumentPart.class, PackagePart.class, PackageRelationship.class, XDGFDocument.class); | |||
return constructor.newInstance(parent, part, rel, _document); | |||
} catch (NoSuchMethodException e) { | |||
Constructor<? extends POIXMLDocumentPart> constructor = cls.getDeclaredConstructor(PackagePart.class, PackageRelationship.class, XDGFDocument.class); | |||
return constructor.newInstance(part, rel, _document); | |||
} | |||
} catch (Exception e){ | |||
throw new POIXMLException(e); | |||
} | |||
} | |||
@Override | |||
public POIXMLDocumentPart newDocumentPart(POIXMLRelation descriptor) { | |||
try { | |||
Class<? extends POIXMLDocumentPart> cls = descriptor.getRelationClass(); | |||
Constructor<? extends POIXMLDocumentPart> constructor = cls.getDeclaredConstructor(); | |||
return constructor.newInstance(); | |||
} catch (Exception e){ | |||
throw new POIXMLException(e); | |||
} | |||
} | |||
} |
@@ -0,0 +1,68 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import org.apache.poi.util.Internal; | |||
import com.microsoft.schemas.office.visio.x2012.main.MasterType; | |||
/** | |||
* Provides the API to work with an underlying master | |||
*/ | |||
public class XDGFMaster { | |||
private MasterType _master; | |||
private XDGFMasterContents _content; | |||
XDGFSheet _pageSheet = null; | |||
public XDGFMaster(MasterType master, XDGFMasterContents content, XDGFDocument document) { | |||
_master = master; | |||
_content = content; | |||
content.setMaster(this); | |||
if (master.isSetPageSheet()) | |||
_pageSheet = new XDGFPageSheet(master.getPageSheet(), document); | |||
} | |||
@Internal | |||
MasterType getXmlObject() { | |||
return _master; | |||
} | |||
@Override | |||
public String toString() { | |||
return "<Master ID=\"" + getID() + "\" " + _content + ">"; | |||
} | |||
public long getID() { | |||
return _master.getID(); | |||
} | |||
public String getName() { | |||
return _master.getName(); | |||
} | |||
public XDGFMasterContents getContent() { | |||
return _content; | |||
} | |||
public XDGFSheet getPageSheet() { | |||
return _pageSheet; | |||
} | |||
} |
@@ -0,0 +1,64 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.io.IOException; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
import org.apache.poi.xdgf.exceptions.XDGFException; | |||
import org.apache.xmlbeans.XmlException; | |||
import com.microsoft.schemas.office.visio.x2012.main.MasterContentsDocument; | |||
public class XDGFMasterContents extends XDGFBaseContents { | |||
private XDGFMaster _master; | |||
public XDGFMasterContents(PackagePart part, PackageRelationship rel, XDGFDocument document) { | |||
super(part, rel, document); | |||
} | |||
@Override | |||
protected void onDocumentRead() { | |||
try { | |||
try { | |||
_pageContents = MasterContentsDocument.Factory.parse(getPackagePart().getInputStream()).getMasterContents(); | |||
} catch (XmlException | IOException e) { | |||
throw new POIXMLException(e); | |||
} | |||
super.onDocumentRead(); | |||
} catch (POIXMLException e) { | |||
throw XDGFException.wrap(this, e); | |||
} | |||
} | |||
public XDGFMaster getMaster() { | |||
return _master; | |||
} | |||
protected void setMaster(XDGFMaster master) { | |||
_master = master; | |||
} | |||
} |
@@ -0,0 +1,99 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.io.IOException; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
import org.apache.poi.util.Internal; | |||
import org.apache.poi.xdgf.exceptions.XDGFException; | |||
import org.apache.poi.xdgf.xml.XDGFXMLDocumentPart; | |||
import org.apache.xmlbeans.XmlException; | |||
import com.microsoft.schemas.office.visio.x2012.main.MasterType; | |||
import com.microsoft.schemas.office.visio.x2012.main.MastersDocument; | |||
import com.microsoft.schemas.office.visio.x2012.main.MastersType; | |||
public class XDGFMasters extends XDGFXMLDocumentPart { | |||
MastersType _mastersObject; | |||
// key: id of master | |||
Map<Long, XDGFMaster> _masters = new HashMap<>(); | |||
public XDGFMasters(PackagePart part, PackageRelationship rel, XDGFDocument document) { | |||
super(part, rel, document); | |||
} | |||
@Internal | |||
MastersType getXmlObject() { | |||
return _mastersObject; | |||
} | |||
@Override | |||
protected void onDocumentRead() { | |||
try { | |||
try { | |||
_mastersObject = MastersDocument.Factory.parse(getPackagePart().getInputStream()).getMasters(); | |||
} catch (XmlException | IOException e) { | |||
throw new POIXMLException(e); | |||
} | |||
Map<String, MasterType> masterSettings = new HashMap<>(); | |||
for (MasterType master: _mastersObject.getMasterArray()) { | |||
masterSettings.put(master.getRel().getId(), master); | |||
} | |||
// create the masters | |||
for (POIXMLDocumentPart part: getRelations()) { | |||
String relId = part.getPackageRelationship().getId(); | |||
MasterType settings = masterSettings.get(relId); | |||
if (settings == null) | |||
throw new POIXMLException("Master relationship for " + relId + " not found"); | |||
if (!(part instanceof XDGFMasterContents)) | |||
throw new POIXMLException("Unexpected masters relationship for " + relId + ": " + part); | |||
XDGFMasterContents contents = (XDGFMasterContents)part; | |||
contents.onDocumentRead(); | |||
XDGFMaster master = new XDGFMaster(settings, contents, _document); | |||
_masters.put(master.getID(), master); | |||
} | |||
} catch (POIXMLException e) { | |||
throw XDGFException.wrap(this, e); | |||
} | |||
} | |||
public Collection<XDGFMaster> getMastersList() { | |||
return Collections.unmodifiableCollection(_masters.values()); | |||
} | |||
public XDGFMaster getMasterById(long masterId) { | |||
return _masters.get(masterId); | |||
} | |||
} |
@@ -0,0 +1,113 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.awt.geom.Point2D; | |||
import java.awt.geom.Rectangle2D; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.util.Internal; | |||
import org.apache.poi.xdgf.geom.Dimension2dDouble; | |||
import com.microsoft.schemas.office.visio.x2012.main.PageType; | |||
/** | |||
* Provides the API to work with an underlying page | |||
*/ | |||
public class XDGFPage { | |||
PageType _page; | |||
XDGFPageContents _content; | |||
XDGFPages _pages; | |||
XDGFSheet _pageSheet = null; | |||
public XDGFPage(PageType page, XDGFPageContents content, XDGFDocument document, XDGFPages pages) { | |||
_page = page; | |||
_content = content; | |||
_pages = pages; | |||
content.setPage(this); | |||
if (page.isSetPageSheet()) | |||
_pageSheet = new XDGFPageSheet(page.getPageSheet(), document); | |||
} | |||
@Internal | |||
PageType getXmlObject() { | |||
return _page; | |||
} | |||
public long getID() { | |||
return _page.getID(); | |||
} | |||
public String getName() { | |||
return _page.getName(); | |||
} | |||
public XDGFPageContents getContent() { | |||
return _content; | |||
} | |||
public XDGFSheet getPageSheet() { | |||
return _pageSheet; | |||
} | |||
public long getPageNumber() { | |||
return _pages.getPageList().indexOf(this) + 1; | |||
} | |||
// height/width of page | |||
public Dimension2dDouble getPageSize() { | |||
XDGFCell w = _pageSheet.getCell("PageWidth"); | |||
XDGFCell h = _pageSheet.getCell("PageHeight"); | |||
if (w == null || h == null) | |||
throw new POIXMLException("Cannot determine page size"); | |||
return new Dimension2dDouble(Double.parseDouble(w.getValue()), | |||
Double.parseDouble(h.getValue())); | |||
} | |||
// origin of coordinate system | |||
public Point2D.Double getPageOffset() { | |||
XDGFCell xoffcell = _pageSheet.getCell("XRulerOrigin"); | |||
XDGFCell yoffcell = _pageSheet.getCell("YRulerOrigin"); | |||
double xoffset = 0; | |||
double yoffset = 0; | |||
if (xoffcell != null) | |||
xoffset = Double.parseDouble(xoffcell.getValue()); | |||
if (xoffcell != null) | |||
yoffset = Double.parseDouble(yoffcell.getValue()); | |||
return new Point2D.Double(xoffset, yoffset); | |||
} | |||
// bounding box of page | |||
public Rectangle2D getBoundingBox() { | |||
Dimension2dDouble sz = getPageSize(); | |||
Point2D.Double offset = getPageOffset(); | |||
return new Rectangle2D.Double(-offset.getX(), | |||
-offset.getY(), | |||
sz.getWidth(), | |||
sz.getHeight()); | |||
} | |||
} |
@@ -0,0 +1,83 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.io.IOException; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
import org.apache.poi.xdgf.exceptions.XDGFException; | |||
import org.apache.xmlbeans.XmlException; | |||
import com.microsoft.schemas.office.visio.x2012.main.PageContentsDocument; | |||
public class XDGFPageContents extends XDGFBaseContents { | |||
Map<Long, XDGFMaster> _masters = new HashMap<>(); | |||
XDGFPage _page; | |||
public XDGFPageContents(PackagePart part, PackageRelationship rel, XDGFDocument document) { | |||
super(part, rel, document); | |||
} | |||
@Override | |||
protected void onDocumentRead() { | |||
try { | |||
try { | |||
_pageContents = PageContentsDocument.Factory.parse(getPackagePart().getInputStream()).getPageContents(); | |||
} catch (XmlException | IOException e) { | |||
throw new POIXMLException(e); | |||
} | |||
for (POIXMLDocumentPart part: getRelations()) { | |||
if (!(part instanceof XDGFMasterContents)) | |||
continue; | |||
//throw new POIXMLException("Unexpected page relation: " + part); | |||
XDGFMaster master = ((XDGFMasterContents)part).getMaster(); | |||
_masters.put(master.getID(), master); | |||
} | |||
super.onDocumentRead(); | |||
for (XDGFShape shape: _shapes.values()) { | |||
if (shape.isTopmost()) | |||
shape.setupMaster(this, null); | |||
} | |||
} catch (POIXMLException e) { | |||
throw XDGFException.wrap(this, e); | |||
} | |||
} | |||
public XDGFPage getPage() { | |||
return _page; | |||
} | |||
protected void setPage(XDGFPage page) { | |||
_page = page; | |||
} | |||
public XDGFMaster getMasterById(long id) { | |||
return _masters.get(id); | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import com.microsoft.schemas.office.visio.x2012.main.PageSheetType; | |||
public class XDGFPageSheet extends XDGFSheet { | |||
PageSheetType _pageSheet; | |||
public XDGFPageSheet(PageSheetType sheet, XDGFDocument document) { | |||
super(sheet, document); | |||
_pageSheet = sheet; | |||
} | |||
@Override | |||
PageSheetType getXmlObject() { | |||
return _pageSheet; | |||
} | |||
} |
@@ -0,0 +1,95 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
import org.apache.poi.util.Internal; | |||
import org.apache.poi.xdgf.exceptions.XDGFException; | |||
import org.apache.poi.xdgf.xml.XDGFXMLDocumentPart; | |||
import org.apache.xmlbeans.XmlException; | |||
import com.microsoft.schemas.office.visio.x2012.main.PageType; | |||
import com.microsoft.schemas.office.visio.x2012.main.PagesDocument; | |||
import com.microsoft.schemas.office.visio.x2012.main.PagesType; | |||
/** | |||
* Contains a list of Page objects (not page content!) | |||
*/ | |||
public class XDGFPages extends XDGFXMLDocumentPart { | |||
PagesType _pagesObject; | |||
// ordered by page number | |||
List<XDGFPage> _pages = new ArrayList<>(); | |||
public XDGFPages(PackagePart part, PackageRelationship rel, XDGFDocument document) { | |||
super(part, rel, document); | |||
} | |||
@Internal | |||
PagesType getXmlObject() { | |||
return _pagesObject; | |||
} | |||
@Override | |||
protected void onDocumentRead() { | |||
try { | |||
try { | |||
_pagesObject = PagesDocument.Factory.parse(getPackagePart().getInputStream()).getPages(); | |||
} catch (XmlException | IOException e) { | |||
throw new POIXMLException(e); | |||
} | |||
// this iteration is ordered by page number | |||
for (PageType pageSettings: _pagesObject.getPageArray()) { | |||
String relId = pageSettings.getRel().getId(); | |||
POIXMLDocumentPart pageContentsPart = getRelationById(relId); | |||
if (pageContentsPart == null) | |||
throw new POIXMLException("PageSettings relationship for " + relId + " not found"); | |||
if (!(pageContentsPart instanceof XDGFPageContents)) | |||
throw new POIXMLException("Unexpected pages relationship for " + relId + ": " + pageContentsPart); | |||
XDGFPageContents contents = (XDGFPageContents)pageContentsPart; | |||
XDGFPage page = new XDGFPage(pageSettings, contents, _document, this); | |||
contents.onDocumentRead(); | |||
_pages.add(page); | |||
} | |||
} catch (POIXMLException e) { | |||
throw XDGFException.wrap(this, e); | |||
} | |||
} | |||
// ordered by page number | |||
public List<XDGFPage> getPageList() { | |||
return Collections.unmodifiableList(_pages); | |||
} | |||
} |
@@ -0,0 +1,99 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.poi.POIXMLRelation; | |||
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; | |||
import org.apache.poi.xdgf.xml.XDGFXMLDocumentPart; | |||
public class XDGFRelation extends POIXMLRelation { | |||
/** | |||
* A map to lookup POIXMLRelation by its relation type | |||
*/ | |||
protected static final Map<String, XDGFRelation> _table = new HashMap<String, XDGFRelation>(); | |||
public static final XDGFRelation DOCUMENT = new XDGFRelation( | |||
"application/vnd.ms-visio.drawing.main+xml", | |||
"http://schemas.microsoft.com/visio/2010/relationships/document", | |||
"/visio/document.xml", | |||
null | |||
); | |||
public static final XDGFRelation MASTERS = new XDGFRelation( | |||
"application/vnd.ms-visio.masters+xml", | |||
"http://schemas.microsoft.com/visio/2010/relationships/masters", | |||
"/visio/masters/masters.xml", | |||
XDGFMasters.class | |||
); | |||
public static final XDGFRelation MASTER = new XDGFRelation( | |||
"application/vnd.ms-visio.master+xml", | |||
"http://schemas.microsoft.com/visio/2010/relationships/master", | |||
"/visio/masters/master#.xml", | |||
XDGFMasterContents.class | |||
); | |||
public static final XDGFRelation IMAGES = new XDGFRelation( | |||
null, | |||
PackageRelationshipTypes.IMAGE_PART, | |||
null, | |||
null // XSSFPictureData.class | |||
); | |||
public static final XDGFRelation PAGES = new XDGFRelation( | |||
"application/vnd.ms-visio.pages+xml", | |||
"http://schemas.microsoft.com/visio/2010/relationships/pages", | |||
"/visio/pages/pages.xml", | |||
XDGFPages.class | |||
); | |||
public static final XDGFRelation PAGE = new XDGFRelation( | |||
"application/vnd.ms-visio.page+xml", | |||
"http://schemas.microsoft.com/visio/2010/relationships/page", | |||
"/visio/pages/page#.xml", | |||
XDGFPageContents.class | |||
); | |||
public static final XDGFRelation WINDOW = new XDGFRelation( | |||
"application/vnd.ms-visio.windows+xml", | |||
"http://schemas.microsoft.com/visio/2010/relationships/windows", | |||
"/visio/windows.xml", | |||
null | |||
); | |||
private XDGFRelation(String type, String rel, String defaultName, Class<? extends XDGFXMLDocumentPart> cls) { | |||
super(type, rel, defaultName, cls); | |||
if (cls != null && !_table.containsKey(rel)) _table.put(rel, this); | |||
} | |||
/** | |||
* Get POIXMLRelation by relation type | |||
* | |||
* @param rel relation type, for example, | |||
* <code>http://schemas.openxmlformats.org/officeDocument/2006/relationships/image</code> | |||
* @return registered POIXMLRelation or null if not found | |||
*/ | |||
public static XDGFRelation getInstance(String rel) { | |||
return _table.get(rel); | |||
} | |||
} |
@@ -0,0 +1,943 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.awt.BasicStroke; | |||
import java.awt.Color; | |||
import java.awt.Stroke; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Path2D; | |||
import java.awt.geom.Rectangle2D; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import java.util.Map.Entry; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.util.Internal; | |||
import org.apache.poi.xdgf.exceptions.XDGFException; | |||
import org.apache.poi.xdgf.usermodel.section.CombinedIterable; | |||
import org.apache.poi.xdgf.usermodel.section.GeometrySection; | |||
import org.apache.poi.xdgf.usermodel.section.XDGFSection; | |||
import org.apache.poi.xdgf.usermodel.shape.ShapeVisitor; | |||
import org.apache.poi.xdgf.usermodel.shape.exceptions.StopVisitingThisBranch; | |||
import com.microsoft.schemas.office.visio.x2012.main.ShapeSheetType; | |||
import com.microsoft.schemas.office.visio.x2012.main.TextType; | |||
/** | |||
* A shape is a collection of Geometry Visualization, Format, Text, Images, | |||
* and Shape Data in a Drawing Page. | |||
*/ | |||
public class XDGFShape extends XDGFSheet { | |||
XDGFBaseContents _parentPage; | |||
XDGFShape _parent; // only non-null if a subshape | |||
XDGFMaster _master = null; | |||
XDGFShape _masterShape = null; | |||
XDGFText _text = null; | |||
// subshapes if they exist | |||
List<XDGFShape> _shapes = null; | |||
// properties specific to shapes | |||
// center of rotation relative to origin of parent | |||
Double _pinX = null; | |||
Double _pinY = null; | |||
Double _width = null; | |||
Double _height = null; | |||
// center of rotation relative to self | |||
Double _locPinX = null; | |||
Double _locPinY = null; | |||
// start x coordinate, relative to parent | |||
// -> one dimensional shapes only | |||
Double _beginX = null; | |||
Double _beginY = null; | |||
// end x coordinate, relative to parent | |||
// -> one dimensional shapes only | |||
Double _endX = null; | |||
Double _endY = null; | |||
Double _angle = null; | |||
Double _rotationXAngle = null; | |||
Double _rotationYAngle = null; | |||
Double _rotationZAngle = null; | |||
// end x coordinate, relative to parent | |||
Boolean _flipX = null; | |||
Boolean _flipY = null; | |||
// center of text relative to this shape | |||
Double _txtPinX = null; | |||
Double _txtPinY = null; | |||
// center of text relative to text block | |||
Double _txtLocPinX = null; | |||
Double _txtLocPinY = null; | |||
Double _txtAngle = null; | |||
Double _txtWidth = null; | |||
Double _txtHeight = null; | |||
public XDGFShape(ShapeSheetType shapeSheet, XDGFBaseContents parentPage, XDGFDocument document) { | |||
this(null, shapeSheet, parentPage, document); | |||
} | |||
public XDGFShape(XDGFShape parent, ShapeSheetType shapeSheet, XDGFBaseContents parentPage, XDGFDocument document) { | |||
super(shapeSheet, document); | |||
_parent = parent; | |||
_parentPage = parentPage; | |||
TextType text = shapeSheet.getText(); | |||
if (text != null) | |||
_text = new XDGFText(text, this); | |||
if (shapeSheet.isSetShapes()) { | |||
_shapes = new ArrayList<XDGFShape>(); | |||
for (ShapeSheetType shape: shapeSheet.getShapes().getShapeArray()) | |||
_shapes.add(new XDGFShape(this, shape, parentPage, document)); | |||
} | |||
readProperties(); | |||
} | |||
@Override | |||
public String toString() { | |||
if (_parentPage instanceof XDGFMasterContents) | |||
return _parentPage + ": <Shape ID=\"" + getID() + "\">"; | |||
else | |||
return "<Shape ID=\"" + getID() + "\">"; | |||
} | |||
protected void readProperties() { | |||
_pinX = XDGFCell.maybeGetDouble(_cells, "PinX"); | |||
_pinY = XDGFCell.maybeGetDouble(_cells, "PinY"); | |||
_width = XDGFCell.maybeGetDouble(_cells, "Width"); | |||
_height = XDGFCell.maybeGetDouble(_cells, "Height"); | |||
_locPinX = XDGFCell.maybeGetDouble(_cells, "LocPinX"); | |||
_locPinY = XDGFCell.maybeGetDouble(_cells, "LocPinY"); | |||
_beginX = XDGFCell.maybeGetDouble(_cells, "BeginX"); | |||
_beginY = XDGFCell.maybeGetDouble(_cells, "BeginY"); | |||
_endX = XDGFCell.maybeGetDouble(_cells, "EndX"); | |||
_endY = XDGFCell.maybeGetDouble(_cells, "EndY"); | |||
_angle = XDGFCell.maybeGetDouble(_cells, "Angle"); | |||
_rotationXAngle = XDGFCell.maybeGetDouble(_cells, "RotationXAngle"); | |||
_rotationYAngle = XDGFCell.maybeGetDouble(_cells, "RotationYAngle"); | |||
_rotationZAngle = XDGFCell.maybeGetDouble(_cells, "RotationZAngle"); | |||
_flipX = XDGFCell.maybeGetBoolean(_cells, "FlipX"); | |||
_flipY = XDGFCell.maybeGetBoolean(_cells, "FlipY"); | |||
_txtPinX = XDGFCell.maybeGetDouble(_cells, "TxtPinX"); | |||
_txtPinY = XDGFCell.maybeGetDouble(_cells, "TxtPinY"); | |||
_txtLocPinX = XDGFCell.maybeGetDouble(_cells, "TxtLocPinX"); | |||
_txtLocPinY = XDGFCell.maybeGetDouble(_cells, "TxtLocPinY"); | |||
_txtWidth = XDGFCell.maybeGetDouble(_cells, "TxtWidth"); | |||
_txtHeight = XDGFCell.maybeGetDouble(_cells, "TxtHeight"); | |||
_txtAngle = XDGFCell.maybeGetDouble(_cells, "TxtAngle"); | |||
} | |||
/** | |||
* Setup top level shapes | |||
* | |||
* Shapes that have a 'Master' attribute refer to a specific master in | |||
* the page, whereas shapes with a 'MasterShape' attribute refer to a | |||
* subshape of a Master. | |||
* | |||
* | |||
*/ | |||
protected void setupMaster(XDGFPageContents pageContents, XDGFMasterContents master) { | |||
ShapeSheetType obj = getXmlObject(); | |||
if (obj.isSetMaster()) { | |||
_master = pageContents.getMasterById(obj.getMaster()); | |||
if (_master == null) | |||
throw XDGFException.error("refers to non-existant master " + obj.getMaster(), | |||
this); | |||
/* | |||
* If a master has one top-level shape, a shape that inherits from | |||
* that master inherits the descendant elements of that master | |||
* shape. If a master has more than one master shape, a shape that | |||
* inherits from that master inherits those master shapes as | |||
* subshapes. | |||
*/ | |||
Collection<XDGFShape> masterShapes = _master.getContent().getTopLevelShapes(); | |||
switch (masterShapes.size()) { | |||
case 0: | |||
throw XDGFException.error("Could not retrieve master shape from " + _master, this); | |||
case 1: | |||
_masterShape = masterShapes.iterator().next(); | |||
break; | |||
default: | |||
break; | |||
} | |||
} else if (obj.isSetMasterShape()) { | |||
_masterShape = master.getShapeById(obj.getMasterShape()); | |||
if (_masterShape == null) | |||
throw XDGFException.error("refers to non-existant master shape " + obj.getMasterShape(), | |||
this); | |||
} | |||
setupSectionMasters(); | |||
if (_shapes != null) { | |||
for (XDGFShape shape: _shapes) { | |||
shape.setupMaster(pageContents, | |||
_master == null ? master : _master.getContent()); | |||
} | |||
} | |||
} | |||
protected void setupSectionMasters() { | |||
if (_masterShape == null) | |||
return; | |||
try { | |||
for (Entry<String, XDGFSection> section: _sections.entrySet()) { | |||
XDGFSection master = _masterShape.getSection(section.getKey()); | |||
if (master != null) | |||
section.getValue().setupMaster(master); | |||
} | |||
for (Entry<Long, GeometrySection> section: _geometry.entrySet()) { | |||
GeometrySection master = _masterShape.getGeometryByIdx(section.getKey()); | |||
if (master != null) | |||
section.getValue().setupMaster(master); | |||
} | |||
} catch (POIXMLException e) { | |||
throw XDGFException.wrap(this.toString(), e); | |||
} | |||
} | |||
@Internal | |||
public ShapeSheetType getXmlObject() { | |||
return (ShapeSheetType)_sheet; | |||
} | |||
public long getID() { | |||
return getXmlObject().getID(); | |||
} | |||
public String getType() { | |||
return getXmlObject().getType(); | |||
} | |||
public String getTextAsString() { | |||
XDGFText text = getText(); | |||
if (text == null) | |||
return ""; | |||
return text.getTextContent(); | |||
} | |||
public boolean hasText() { | |||
return _text != null || (_masterShape != null && _masterShape._text != null); | |||
} | |||
@Override | |||
public XDGFCell getCell(String cellName) { | |||
XDGFCell _cell = super.getCell(cellName); | |||
// if not found, ask the master | |||
if (_cell == null && _masterShape != null) { | |||
_cell = _masterShape.getCell(cellName); | |||
} | |||
return _cell; | |||
} | |||
public GeometrySection getGeometryByIdx(long idx) { | |||
return _geometry.get(idx); | |||
} | |||
// only available if this is a shape group | |||
// -> May be null | |||
public List<XDGFShape> getShapes() { | |||
return _shapes; | |||
} | |||
// unique to this shape on the page? | |||
public String getName() { | |||
String name = getXmlObject().getName(); | |||
if (name == null) | |||
return ""; | |||
return name; | |||
} | |||
// unique to this shape on the page? | |||
public String getShapeType() { | |||
String type = getXmlObject().getType(); | |||
if (type == null) | |||
return ""; | |||
return type; | |||
} | |||
// name of the symbol that this was derived from | |||
public String getSymbolName() { | |||
if (_master == null) | |||
return ""; | |||
String name = _master.getName(); | |||
if (name == null) | |||
return ""; | |||
return name; | |||
} | |||
public XDGFShape getMasterShape() { | |||
return _masterShape; | |||
} | |||
// returns the parent shape of this shape, if its in a subshape | |||
public XDGFShape getParentShape() { | |||
return _parent; | |||
} | |||
public XDGFShape getTopmostParentShape() { | |||
XDGFShape top = null; | |||
if (_parent != null) { | |||
top = _parent.getTopmostParentShape(); | |||
if (top == null) | |||
top = _parent; | |||
} | |||
return top; | |||
} | |||
public boolean hasMaster() { | |||
return _master != null; | |||
} | |||
public boolean hasMasterShape() { | |||
return _masterShape != null; | |||
} | |||
public boolean hasParent() { | |||
return _parent != null; | |||
} | |||
public boolean hasShapes() { | |||
return _shapes != null; | |||
} | |||
public boolean isTopmost() { | |||
return _parent == null; | |||
} | |||
public boolean isShape1D() { | |||
return getBeginX() != null; | |||
} | |||
public boolean isDeleted() { | |||
return getXmlObject().isSetDel() ? getXmlObject().getDel() : false; | |||
} | |||
public XDGFText getText() { | |||
if (_text == null && _masterShape != null) | |||
return _masterShape.getText(); | |||
return _text; | |||
} | |||
public Double getPinX() { | |||
if (_pinX == null && _masterShape != null) | |||
return _masterShape.getPinX(); | |||
if (_pinX == null) | |||
throw XDGFException.error("PinX not set!", this); | |||
return _pinX; | |||
} | |||
public Double getPinY() { | |||
if (_pinY == null && _masterShape != null) | |||
return _masterShape.getPinY(); | |||
if (_pinY == null) | |||
throw XDGFException.error("PinY not specified!", this); | |||
return _pinY; | |||
} | |||
public Double getWidth() { | |||
if (_width == null && _masterShape != null) | |||
return _masterShape.getWidth(); | |||
if (_width == null) | |||
throw XDGFException.error("Width not specified!", this); | |||
return _width; | |||
} | |||
public Double getHeight() { | |||
if (_height == null && _masterShape != null) | |||
return _masterShape.getHeight(); | |||
if (_height == null) | |||
throw XDGFException.error("Height not specified!", this); | |||
return _height; | |||
} | |||
public Double getLocPinX() { | |||
if (_locPinX == null && _masterShape != null) | |||
return _masterShape.getLocPinX(); | |||
if (_locPinX == null) | |||
throw XDGFException.error("LocPinX not specified!", this); | |||
return _locPinX; | |||
} | |||
public Double getLocPinY() { | |||
if (_locPinY == null && _masterShape != null) | |||
return _masterShape.getLocPinY(); | |||
if (_locPinY == null) | |||
throw XDGFException.error("LocPinY not specified!", this); | |||
return _locPinY; | |||
} | |||
public Double getBeginX() { | |||
if (_beginX == null && _masterShape != null) | |||
return _masterShape.getBeginX(); | |||
return _beginX; | |||
} | |||
public Double getBeginY() { | |||
if (_beginY == null && _masterShape != null) | |||
return _masterShape.getBeginY(); | |||
return _beginY; | |||
} | |||
public Double getEndX() { | |||
if (_endX == null && _masterShape != null) | |||
return _masterShape.getEndX(); | |||
return _endX; | |||
} | |||
public Double getEndY() { | |||
if (_endY == null && _masterShape != null) | |||
return _masterShape.getEndY(); | |||
return _endY; | |||
} | |||
public Double getAngle() { | |||
if (_angle == null && _masterShape != null) | |||
return _masterShape.getAngle(); | |||
return _angle; | |||
} | |||
public Boolean getFlipX() { | |||
if (_flipX == null && _masterShape != null) | |||
return _masterShape.getFlipX(); | |||
return _flipX; | |||
} | |||
public Boolean getFlipY() { | |||
if (_flipY == null && _masterShape != null) | |||
return _masterShape.getFlipY(); | |||
return _flipY; | |||
} | |||
public Double getTxtPinX() { | |||
if (_txtPinX == null && | |||
_masterShape != null && _masterShape._txtPinX != null) | |||
return _masterShape._txtPinX; | |||
if (_txtPinX == null) | |||
return getWidth()*0.5; | |||
return _txtPinX; | |||
} | |||
public Double getTxtPinY() { | |||
if (_txtLocPinY == null && | |||
_masterShape != null && _masterShape._txtLocPinY != null) | |||
return _masterShape._txtLocPinY; | |||
if (_txtPinY == null) | |||
return getHeight()*0.5; | |||
return _txtPinY; | |||
} | |||
public Double getTxtLocPinX() { | |||
if (_txtLocPinX == null && | |||
_masterShape != null && _masterShape._txtLocPinX != null) | |||
return _masterShape._txtLocPinX; | |||
if (_txtLocPinX == null) | |||
return getTxtWidth()*0.5; | |||
return _txtLocPinX; | |||
} | |||
public Double getTxtLocPinY() { | |||
if (_txtLocPinY == null && | |||
_masterShape != null && _masterShape._txtLocPinY != null) | |||
return _masterShape._txtLocPinY; | |||
if (_txtLocPinY == null) | |||
return getTxtHeight()*0.5; | |||
return _txtLocPinY; | |||
} | |||
public Double getTxtAngle() { | |||
if (_txtAngle == null && _masterShape != null) | |||
return _masterShape.getTxtAngle(); | |||
return _txtAngle; | |||
} | |||
public Double getTxtWidth() { | |||
if (_txtWidth == null && | |||
_masterShape != null && _masterShape._txtWidth != null) | |||
return _masterShape._txtWidth; | |||
if (_txtWidth == null) | |||
return getWidth(); | |||
return _txtWidth; | |||
} | |||
public Double getTxtHeight() { | |||
if (_txtHeight == null && | |||
_masterShape != null && _masterShape._txtHeight != null) | |||
return _masterShape._txtHeight; | |||
if (_txtHeight == null) | |||
return getHeight(); | |||
return _txtHeight; | |||
} | |||
@Override | |||
public Integer getLineCap() { | |||
Integer lineCap = super.getLineCap(); | |||
if (lineCap != null) | |||
return lineCap; | |||
// get from master | |||
if (_masterShape != null) { | |||
return _masterShape.getLineCap(); | |||
} | |||
// get default | |||
XDGFStyleSheet style = _document.getDefaultLineStyle(); | |||
if (style != null) | |||
return style.getLineCap(); | |||
return null; | |||
} | |||
@Override | |||
public Color getLineColor() { | |||
Color lineColor = super.getLineColor(); | |||
if (lineColor != null) | |||
return lineColor; | |||
// get from master | |||
if (_masterShape != null) { | |||
return _masterShape.getLineColor(); | |||
} | |||
// get default | |||
XDGFStyleSheet style = _document.getDefaultLineStyle(); | |||
if (style != null) | |||
return style.getLineColor(); | |||
return null; | |||
} | |||
@Override | |||
public Integer getLinePattern() { | |||
Integer linePattern = super.getLinePattern(); | |||
if (linePattern != null) | |||
return linePattern; | |||
// get from master | |||
if (_masterShape != null) { | |||
return _masterShape.getLinePattern(); | |||
} | |||
// get default | |||
XDGFStyleSheet style = _document.getDefaultLineStyle(); | |||
if (style != null) | |||
return style.getLinePattern(); | |||
return null; | |||
} | |||
@Override | |||
public Double getLineWeight() { | |||
Double lineWeight = super.getLineWeight(); | |||
if (lineWeight != null) | |||
return lineWeight; | |||
// get from master | |||
if (_masterShape != null) { | |||
return _masterShape.getLineWeight(); | |||
} | |||
// get default | |||
XDGFStyleSheet style = _document.getDefaultLineStyle(); | |||
if (style != null) | |||
return style.getLineWeight(); | |||
return null; | |||
} | |||
public Color getFontColor() { | |||
Color fontColor = super.getFontColor(); | |||
if (fontColor != null) | |||
return fontColor; | |||
// get from master | |||
if (_masterShape != null) { | |||
return _masterShape.getFontColor(); | |||
} | |||
// get default | |||
XDGFStyleSheet style = _document.getDefaultTextStyle(); | |||
if (style != null) | |||
return style.getFontColor(); | |||
return null; | |||
} | |||
public Double getFontSize() { | |||
Double fontSize = super.getFontSize(); | |||
if (fontSize != null) | |||
return fontSize; | |||
// get from master | |||
if (_masterShape != null) { | |||
return _masterShape.getFontSize(); | |||
} | |||
// get default | |||
XDGFStyleSheet style = _document.getDefaultTextStyle(); | |||
if (style != null) | |||
return style.getFontSize(); | |||
return null; | |||
} | |||
public Stroke getStroke() { | |||
float lineWeight = getLineWeight().floatValue(); | |||
int cap; | |||
int join = BasicStroke.JOIN_MITER; | |||
float miterlimit = 10.0f; | |||
switch (getLineCap()) { | |||
case 0: | |||
cap = BasicStroke.CAP_ROUND; | |||
break; | |||
case 1: | |||
cap = BasicStroke.CAP_SQUARE; | |||
break; | |||
case 2: | |||
cap = BasicStroke.CAP_BUTT; // TODO: what does extended mean? | |||
break; | |||
default: | |||
throw new POIXMLException("Invalid line cap specified"); | |||
} | |||
float[] dash = null; | |||
// these line patterns are just approximations | |||
switch (getLinePattern()) { | |||
case 0: // transparent | |||
break; | |||
case 1: // solid | |||
break; | |||
case 2: | |||
dash = new float[]{5,3}; | |||
break; | |||
case 3: | |||
dash = new float[]{1,4}; | |||
break; | |||
case 4: | |||
dash = new float[]{6,3,1,3}; | |||
break; | |||
case 5: | |||
dash = new float[]{6,3,1,3,1,3}; | |||
break; | |||
case 6: | |||
dash = new float[]{1,3,6,3,6,3}; | |||
break; | |||
case 7: | |||
dash = new float[]{15,3,6,3}; | |||
break; | |||
case 8: | |||
dash = new float[]{6,3,6,3}; | |||
break; | |||
case 9: | |||
dash = new float[]{3,2}; | |||
break; | |||
case 10: | |||
dash = new float[]{1,2}; | |||
break; | |||
case 11: | |||
dash = new float[]{3,2,1,2}; | |||
break; | |||
case 12: | |||
dash = new float[]{3,2,1,2,1}; | |||
break; | |||
case 13: | |||
dash = new float[]{1,2,3,2,3,2}; | |||
break; | |||
case 14: | |||
dash = new float[]{3,2,7,2}; | |||
break; | |||
case 15: | |||
dash = new float[]{7,2,3,2,3,2}; | |||
break; | |||
case 16: | |||
dash = new float[]{12,6}; | |||
break; | |||
case 17: | |||
dash = new float[]{1,6}; | |||
break; | |||
case 18: | |||
dash = new float[]{1,6,12,6}; | |||
break; | |||
case 19: | |||
dash = new float[]{1,6,1,6,12,6}; | |||
break; | |||
case 20: | |||
dash = new float[]{1,6,12,6,12,6}; | |||
break; | |||
case 21: | |||
dash = new float[]{30,6,12,6}; | |||
break; | |||
case 22: | |||
dash = new float[]{30,6,12,6,12,6}; | |||
break; | |||
case 23: | |||
dash = new float[]{1}; | |||
break; | |||
case 254: | |||
throw new POIXMLException("Unsupported line pattern value"); | |||
default: | |||
throw new POIXMLException("Invalid line pattern value"); | |||
} | |||
// dashes are in units of line width | |||
if (dash != null) { | |||
for (int i = 0; i < dash.length; i++) { | |||
dash[i] *= lineWeight; | |||
} | |||
} | |||
return new BasicStroke(lineWeight, cap, join, miterlimit, dash, 0); | |||
} | |||
// | |||
// Geometry | |||
// | |||
public Iterable<GeometrySection> getGeometrySections() { | |||
return new CombinedIterable<>(_geometry, | |||
_masterShape != null ? _masterShape._geometry : null); | |||
} | |||
// returns a rectangle in local coordinates | |||
public Rectangle2D.Double getBounds() { | |||
return new Rectangle2D.Double(0, 0, getWidth(), | |||
getHeight()); | |||
} | |||
// returns bounds as a path in local coordinates | |||
// -> useful if you need to transform to global coordinates | |||
// -> Don't use for 1d objects, fails for infinite line objects | |||
public Path2D.Double getBoundsAsPath() { | |||
Double w = getWidth(); | |||
Double h = getHeight(); | |||
Path2D.Double bounds = new Path2D.Double(); | |||
bounds.moveTo(0, 0); | |||
bounds.lineTo(w, 0); | |||
bounds.lineTo(w, h); | |||
bounds.lineTo(0, h); | |||
bounds.lineTo(0, 0); | |||
return bounds; | |||
} | |||
// returns the path in local coordinates | |||
public Path2D.Double getPath() { | |||
for (GeometrySection geoSection: getGeometrySections()) { | |||
if (geoSection.getNoShow() == true) | |||
continue; | |||
return geoSection.getPath(this); | |||
} | |||
return null; | |||
} | |||
/* | |||
* Returns true if the shape has a drawable geometry associated with it | |||
*/ | |||
public boolean hasGeometry() { | |||
for (GeometrySection geoSection: getGeometrySections()) { | |||
if (geoSection.getNoShow() == false) | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Returns a transform that can translate shape-local coordinates | |||
* to the coordinates of its parent shape | |||
*/ | |||
protected AffineTransform getParentTransform() { | |||
// TODO: There's probably a better way to do this | |||
AffineTransform tr = new AffineTransform(); | |||
Double locX = getLocPinX(); | |||
Double locY = getLocPinY(); | |||
Boolean flipX = getFlipX(); | |||
Boolean flipY = getFlipY(); | |||
Double angle = getAngle(); | |||
tr.translate(-locX, -locY); | |||
tr.translate(getPinX(), getPinY()); | |||
// rotate about the origin | |||
if (angle != null && Math.abs(angle) > 0.001) { | |||
tr.rotate(angle, locX, locY); | |||
} | |||
// flip if necessary | |||
if (flipX != null && flipX) { | |||
tr.scale(-1, 1); | |||
tr.translate(-getWidth(), 0); | |||
} | |||
if (flipY != null && flipY) { | |||
tr.scale(1, -1); | |||
tr.translate(0, -getHeight()); | |||
} | |||
return tr; | |||
} | |||
/** | |||
* The visitor will first visit this shape, then it's children | |||
* | |||
* This is useful because exceptions will be marked with the shapes as it | |||
* propagates up the shape hierarchy. | |||
*/ | |||
public void visitShapes(ShapeVisitor visitor, AffineTransform tr, int level) { | |||
tr = (AffineTransform)tr.clone(); | |||
tr.concatenate(getParentTransform()); | |||
try { | |||
if (visitor.accept(this)) | |||
visitor.visit(this, tr, level); | |||
if (_shapes != null) { | |||
for (XDGFShape shape: _shapes) { | |||
shape.visitShapes(visitor, tr, level + 1); | |||
} | |||
} | |||
} catch (StopVisitingThisBranch e) { | |||
// intentionally empty | |||
} catch (POIXMLException e) { | |||
throw XDGFException.wrap(this.toString(), e); | |||
} | |||
} | |||
/** | |||
* The visitor will first visit this shape, then it's children. No transform | |||
* is calculated for this visit | |||
* | |||
* This is useful because exceptions will be marked with the shapes as it | |||
* propagates up the shape hierarchy. | |||
*/ | |||
public void visitShapes(ShapeVisitor visitor, int level) { | |||
try { | |||
if (visitor.accept(this)) | |||
visitor.visit(this, null, level); | |||
if (_shapes != null) { | |||
for (XDGFShape shape: _shapes) { | |||
shape.visitShapes(visitor, level + 1); | |||
} | |||
} | |||
} catch (StopVisitingThisBranch e) { | |||
// intentionally empty | |||
} catch (POIXMLException e) { | |||
throw XDGFException.wrap(this.toString(), e); | |||
} | |||
} | |||
} |
@@ -0,0 +1,204 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.awt.Color; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.SortedMap; | |||
import java.util.TreeMap; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.exceptions.XDGFException; | |||
import org.apache.poi.xdgf.usermodel.section.CharacterSection; | |||
import org.apache.poi.xdgf.usermodel.section.GeometrySection; | |||
import org.apache.poi.xdgf.usermodel.section.XDGFSection; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.SectionType; | |||
import com.microsoft.schemas.office.visio.x2012.main.SheetType; | |||
/** | |||
* A sheet is a collection of properties that specify information for a shape, | |||
* master, drawing page, style, or web drawing. | |||
*/ | |||
public abstract class XDGFSheet { | |||
protected XDGFDocument _document; | |||
protected SheetType _sheet; | |||
// cells | |||
protected Map<String, XDGFCell> _cells = new HashMap<>(); | |||
// sections | |||
protected Map<String, XDGFSection> _sections = new HashMap<>(); | |||
// special: geometry sections (key: index, value: section) | |||
protected SortedMap<Long, GeometrySection> _geometry = new TreeMap<>(); | |||
// special: character section | |||
protected CharacterSection _character = null; | |||
public XDGFSheet(SheetType sheet, XDGFDocument document) { | |||
try { | |||
_sheet = sheet; | |||
_document = document; | |||
for (CellType cell: sheet.getCellArray()) { | |||
if (_cells.containsKey(cell.getN())) | |||
throw new POIXMLException("Unexpected duplicate cell " + cell.getN()); // this shouldn't happen | |||
_cells.put(cell.getN(), new XDGFCell(cell)); | |||
} | |||
// only geometry sections can have duplicate names | |||
// sections can be found in the master too, if there are no attributes here! | |||
// no idea if I have a master in this space. go figure. | |||
for (SectionType section: sheet.getSectionArray()) { | |||
String name = section.getN(); | |||
if (name.equals("Geometry")) { | |||
_geometry.put(section.getIX(), new GeometrySection(section, this)); | |||
} else if (name.equals("Character")) { | |||
_character = new CharacterSection(section, this); | |||
} else { | |||
_sections.put(name, XDGFSection.load(section, this)); | |||
} | |||
} | |||
} catch (POIXMLException e) { | |||
throw XDGFException.wrap(this.toString(), e); | |||
} | |||
} | |||
abstract SheetType getXmlObject(); | |||
public XDGFDocument getDocument() { | |||
return _document; | |||
} | |||
// A cell is really just a setting | |||
public XDGFCell getCell(String cellName) { | |||
return _cells.get(cellName); | |||
} | |||
public XDGFSection getSection(String sectionName) { | |||
return _sections.get(sectionName); | |||
} | |||
public XDGFStyleSheet getLineStyle() { | |||
if (!_sheet.isSetLineStyle()) | |||
return null; | |||
return _document.getStyleById(_sheet.getLineStyle()); | |||
} | |||
public XDGFStyleSheet getFillStyle() { | |||
if (!_sheet.isSetFillStyle()) | |||
return null; | |||
return _document.getStyleById(_sheet.getFillStyle()); | |||
} | |||
public XDGFStyleSheet getTextStyle() { | |||
if (!_sheet.isSetTextStyle()) | |||
return null; | |||
return _document.getStyleById(_sheet.getTextStyle()); | |||
} | |||
public Color getFontColor() { | |||
Color fontColor = null; | |||
if (_character != null) { | |||
fontColor = _character.getFontColor(); | |||
if (fontColor != null) | |||
return fontColor; | |||
} | |||
XDGFStyleSheet style = getTextStyle(); | |||
if (style != null) | |||
return style.getFontColor(); | |||
return null; | |||
} | |||
public Double getFontSize() { | |||
Double fontSize = null; | |||
if (_character != null) { | |||
fontSize = _character.getFontSize(); | |||
if (fontSize != null) | |||
return fontSize; | |||
} | |||
XDGFStyleSheet style = getTextStyle(); | |||
if (style != null) | |||
return style.getFontSize(); | |||
return null; | |||
} | |||
public Integer getLineCap() { | |||
Integer lineCap = XDGFCell.maybeGetInteger(_cells, "LineCap"); | |||
if (lineCap != null) | |||
return lineCap; | |||
XDGFStyleSheet style = getLineStyle(); | |||
if (style != null) | |||
return style.getLineCap(); | |||
return null; | |||
} | |||
public Color getLineColor() { | |||
String lineColor = XDGFCell.maybeGetString(_cells, "LineColor"); | |||
if (lineColor != null) | |||
return Color.decode(lineColor); | |||
XDGFStyleSheet style = getLineStyle(); | |||
if (style != null) | |||
return style.getLineColor(); | |||
return null; | |||
} | |||
public Integer getLinePattern() { | |||
Integer linePattern = XDGFCell.maybeGetInteger(_cells, "LinePattern"); | |||
if (linePattern != null) | |||
return linePattern; | |||
XDGFStyleSheet style = getLineStyle(); | |||
if (style != null) | |||
return style.getLinePattern(); | |||
return null; | |||
} | |||
public Double getLineWeight() { | |||
Double lineWeight = XDGFCell.maybeGetDouble(_cells, "LineWeight"); | |||
if (lineWeight != null) | |||
return lineWeight; | |||
XDGFStyleSheet style = getLineStyle(); | |||
if (style != null) | |||
return style.getLineWeight(); | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import org.apache.poi.util.Internal; | |||
import com.microsoft.schemas.office.visio.x2012.main.StyleSheetType; | |||
public class XDGFStyleSheet extends XDGFSheet { | |||
public XDGFStyleSheet(StyleSheetType styleSheet, XDGFDocument document) { | |||
super(styleSheet, document); | |||
} | |||
@Internal | |||
public StyleSheetType getXmlObject() { | |||
return (StyleSheetType)_sheet; | |||
} | |||
} |
@@ -0,0 +1,150 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.awt.Font; | |||
import java.awt.Graphics2D; | |||
import java.awt.font.FontRenderContext; | |||
import java.awt.font.TextLayout; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Path2D; | |||
import java.awt.geom.Point2D; | |||
import java.awt.geom.Rectangle2D; | |||
import org.apache.poi.util.Internal; | |||
import com.microsoft.schemas.office.visio.x2012.main.TextType; | |||
import com.microsoft.schemas.office.visio.x2012.main.impl.TextTypeImpl; | |||
public class XDGFText { | |||
TextType _text; | |||
XDGFShape _parent; | |||
public XDGFText(TextType text, XDGFShape parent) { | |||
_text = text; | |||
_parent = parent; | |||
} | |||
@Internal | |||
TextType getXmlObject() { | |||
return _text; | |||
} | |||
public String getTextContent() { | |||
// casting here is wrong, but there's no other way of getting the value, | |||
// as it doesn't seem to be exposed by complex types (even though this | |||
// is a mixed type) | |||
return ((TextTypeImpl)_text).getStringValue(); | |||
} | |||
// these are in the shape coordinate system | |||
// -> See https://msdn.microsoft.com/en-us/library/hh644132(v=office.12).aspx | |||
public Rectangle2D.Double getTextBounds() { | |||
double txtPinX = _parent.getTxtPinX(); | |||
double txtPinY = _parent.getTxtPinY(); | |||
double txtLocPinX = _parent.getTxtLocPinX(); | |||
double txtLocPinY = _parent.getTxtLocPinY(); | |||
double txtWidth = _parent.getTxtWidth(); | |||
double txtHeight = _parent.getTxtHeight(); | |||
double x = txtPinX - txtLocPinX; | |||
double y = txtPinY - txtLocPinY; | |||
return new Rectangle2D.Double(x, y, txtWidth, txtHeight); | |||
} | |||
// returns bounds as a path in local coordinates | |||
// -> useful if you need to transform to global coordinates | |||
public Path2D.Double getBoundsAsPath() { | |||
Rectangle2D.Double rect = getTextBounds(); | |||
Double w = rect.getWidth(); | |||
Double h = rect.getHeight(); | |||
Path2D.Double bounds = new Path2D.Double(); | |||
bounds.moveTo(0, 0); | |||
bounds.lineTo(w, 0); | |||
bounds.lineTo(w, h); | |||
bounds.lineTo(0, h); | |||
bounds.lineTo(0, 0); | |||
return bounds; | |||
} | |||
// center of text in local coordinates | |||
public Point2D.Double getTextCenter() { | |||
return new Point2D.Double(_parent.getTxtLocPinX(), _parent.getTxtLocPinY()); | |||
} | |||
// assumes graphics is set properly to draw in the right style | |||
public void draw(Graphics2D graphics) { | |||
String textContent = getTextContent(); | |||
if (textContent.length() == 0) | |||
return; | |||
Rectangle2D.Double bounds = getTextBounds(); | |||
String[] lines = textContent.trim().split("\n"); | |||
FontRenderContext frc = graphics.getFontRenderContext(); | |||
Font font = graphics.getFont(); | |||
AffineTransform oldTr = graphics.getTransform(); | |||
// visio is in flipped coordinates, so translate the text to be in the right place | |||
Boolean flipX = _parent.getFlipX(); | |||
Boolean flipY = _parent.getFlipY(); | |||
if (flipY == null || !_parent.getFlipY()) { | |||
graphics.translate(bounds.x, bounds.y); | |||
graphics.scale(1, -1); | |||
graphics.translate(0, -bounds.height + graphics.getFontMetrics().getMaxCharBounds(graphics).getHeight()); | |||
} | |||
if (flipX != null && _parent.getFlipX()) { | |||
graphics.scale(-1, 1); | |||
graphics.translate(-bounds.width, 0); | |||
} | |||
Double txtAngle = _parent.getTxtAngle(); | |||
if (txtAngle != null && Math.abs(txtAngle) > 0.01) | |||
graphics.rotate(txtAngle); | |||
float nextY = 0; | |||
for (String line: lines) { | |||
if (line.length() == 0) | |||
continue; | |||
TextLayout layout = new TextLayout(line, font, frc); | |||
if (layout.isLeftToRight()) | |||
layout.draw(graphics, 0, nextY); | |||
else | |||
layout.draw(graphics, (float)(bounds.width - layout.getAdvance()), nextY); | |||
nextY += layout.getAscent() + layout.getDescent() + layout.getLeading(); | |||
} | |||
graphics.setTransform(oldTr); | |||
} | |||
} |
@@ -0,0 +1,113 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import org.apache.poi.POIXMLDocument; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.openxml4j.exceptions.OpenXML4JException; | |||
import org.apache.poi.openxml4j.opc.OPCPackage; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.util.PackageHelper; | |||
import org.apache.xmlbeans.XmlException; | |||
import com.microsoft.schemas.office.visio.x2012.main.VisioDocumentDocument1; | |||
import com.microsoft.schemas.office.visio.x2012.main.VisioDocumentType; | |||
public class XmlVisioDocument extends POIXMLDocument { | |||
public static String CORE_DOCUMENT = "http://schemas.microsoft.com/visio/2010/relationships/document"; | |||
XDGFPages _pages; | |||
XDGFMasters _masters; | |||
XDGFDocument _document; | |||
public XmlVisioDocument(OPCPackage pkg) throws IOException { | |||
super(pkg, CORE_DOCUMENT); | |||
VisioDocumentType document; | |||
try { | |||
document = VisioDocumentDocument1.Factory.parse(getPackagePart().getInputStream()).getVisioDocument(); | |||
} catch (XmlException | IOException e) { | |||
throw new POIXMLException(e); | |||
} | |||
_document = new XDGFDocument(document); | |||
//build a tree of POIXMLDocumentParts, this document being the root | |||
load(new XDGFFactory(_document)); | |||
} | |||
public XmlVisioDocument(InputStream is) throws IOException { | |||
this(PackageHelper.open(is)); | |||
} | |||
@Override | |||
protected void onDocumentRead() throws IOException { | |||
// by the time this gets called, all other document parts should | |||
// have been loaded, so it's safe to build the document structure | |||
// note that in other onDocumentRead(), relations/etc may not have | |||
// loaded yet, so it's not quite safe | |||
for (POIXMLDocumentPart part: getRelations()) { | |||
// organize the document pieces | |||
if (part instanceof XDGFPages) | |||
_pages = (XDGFPages)part; | |||
else if (part instanceof XDGFMasters) | |||
_masters = (XDGFMasters)part; | |||
} | |||
if (_masters != null) | |||
_masters.onDocumentRead(); | |||
_pages.onDocumentRead(); | |||
} | |||
@Override | |||
public List<PackagePart> getAllEmbedds() throws OpenXML4JException { | |||
throw new UnsupportedOperationException("Not implemented"); | |||
} | |||
// | |||
// Useful public API goes here | |||
// | |||
public Collection<XDGFPage> getPages() { | |||
return _pages.getPageList(); | |||
} | |||
public XDGFStyleSheet getStyleById(long id) { | |||
return _document.getStyleById(id); | |||
} | |||
} |
@@ -0,0 +1,71 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section; | |||
import java.awt.Color; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFSheet; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
import com.microsoft.schemas.office.visio.x2012.main.SectionType; | |||
public class CharacterSection extends XDGFSection { | |||
Double _fontSize = null; | |||
Color _fontColor = null; | |||
Map<String, XDGFCell> _characterCells = new HashMap<>(); | |||
public CharacterSection(SectionType section, XDGFSheet containingSheet) { | |||
super(section, containingSheet); | |||
// there aren't cells for this, just a single row | |||
RowType row = section.getRowArray(0); | |||
for (CellType cell: row.getCellArray()) { | |||
_characterCells.put(cell.getN(), new XDGFCell(cell)); | |||
} | |||
if (row != null) { | |||
_fontSize = XDGFCell.maybeGetDouble(_characterCells, "Size"); | |||
String tmpColor = XDGFCell.maybeGetString(_characterCells, "Color"); | |||
if (tmpColor != null) | |||
_fontColor = Color.decode(tmpColor); | |||
} | |||
} | |||
public Double getFontSize() { | |||
return _fontSize; | |||
} | |||
public Color getFontColor() { | |||
return _fontColor; | |||
} | |||
@Override | |||
public void setupMaster(XDGFSection section) { | |||
} | |||
} | |||
@@ -0,0 +1,136 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section; | |||
import java.util.Collections; | |||
import java.util.Iterator; | |||
import java.util.NoSuchElementException; | |||
import java.util.SortedMap; | |||
import java.util.Map.Entry; | |||
// iterates over the base and master | |||
public class CombinedIterable<T> implements Iterable<T> { | |||
final SortedMap<Long, T> _baseItems; | |||
final SortedMap<Long, T> _masterItems; | |||
public CombinedIterable(SortedMap<Long, T> baseItems, | |||
SortedMap<Long, T> masterItems) { | |||
_baseItems = baseItems; | |||
_masterItems = masterItems; | |||
} | |||
@Override | |||
public Iterator<T> iterator() { | |||
final Iterator<Entry<Long, T>> vmasterI; | |||
if (_masterItems != null) | |||
vmasterI = _masterItems.entrySet().iterator(); | |||
else | |||
vmasterI = Collections.emptyIterator(); | |||
return new Iterator<T>() { | |||
Long lastI = Long.MIN_VALUE; | |||
Entry<Long, T> currentBase = null; | |||
Entry<Long, T> currentMaster = null; | |||
// grab the iterator for both | |||
Iterator<Entry<Long, T>> baseI = _baseItems.entrySet().iterator(); | |||
Iterator<Entry<Long, T>> masterI = vmasterI; | |||
@Override | |||
public boolean hasNext() { | |||
return currentBase != null || currentMaster != null || baseI.hasNext() || masterI.hasNext(); | |||
} | |||
@Override | |||
public T next() { | |||
// TODO: This seems far more complex than it needs to be | |||
long baseIdx = Long.MAX_VALUE; | |||
long masterIdx = Long.MAX_VALUE; | |||
if (currentBase == null) { | |||
while (baseI.hasNext()) { | |||
currentBase = baseI.next(); | |||
if (currentBase.getKey() > lastI) { | |||
baseIdx = currentBase.getKey(); | |||
break; | |||
} | |||
} | |||
} else { | |||
baseIdx = currentBase.getKey(); | |||
} | |||
if (currentMaster == null) { | |||
while (masterI.hasNext()) { | |||
currentMaster = masterI.next(); | |||
if (currentMaster.getKey() > lastI) { | |||
masterIdx = currentMaster.getKey(); | |||
break; | |||
} | |||
} | |||
} else { | |||
masterIdx = currentMaster.getKey(); | |||
} | |||
T val; | |||
if (currentBase != null) { | |||
if (baseIdx <= masterIdx) { | |||
lastI = baseIdx; | |||
val = currentBase.getValue(); | |||
// discard master if same as base | |||
if (masterIdx == baseIdx) { | |||
currentMaster = null; | |||
} | |||
currentBase = null; | |||
} else { | |||
lastI = masterIdx; | |||
val = currentMaster.getValue(); | |||
currentMaster = null; | |||
} | |||
} else if (currentMaster != null) { | |||
lastI = currentMaster.getKey(); | |||
val = currentMaster.getValue(); | |||
currentMaster = null; | |||
} else { | |||
throw new NoSuchElementException(); | |||
} | |||
return val; | |||
} | |||
@Override | |||
public void remove() { | |||
throw new UnsupportedOperationException(); | |||
} | |||
}; | |||
} | |||
} |
@@ -0,0 +1,33 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section; | |||
import org.apache.poi.xdgf.usermodel.XDGFSheet; | |||
import com.microsoft.schemas.office.visio.x2012.main.SectionType; | |||
public class GenericSection extends XDGFSection { | |||
public GenericSection(SectionType section, XDGFSheet containingSheet) { | |||
super(section, containingSheet); | |||
} | |||
@Override | |||
public void setupMaster(XDGFSection section) { | |||
} | |||
} |
@@ -0,0 +1,155 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section; | |||
import java.awt.geom.Path2D; | |||
import java.util.Iterator; | |||
import java.util.Map.Entry; | |||
import java.util.SortedMap; | |||
import java.util.TreeMap; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.geom.SplineCollector; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import org.apache.poi.xdgf.usermodel.XDGFSheet; | |||
import org.apache.poi.xdgf.usermodel.section.geometry.Ellipse; | |||
import org.apache.poi.xdgf.usermodel.section.geometry.GeometryRowFactory; | |||
import org.apache.poi.xdgf.usermodel.section.geometry.InfiniteLine; | |||
import org.apache.poi.xdgf.usermodel.section.geometry.GeometryRow; | |||
import org.apache.poi.xdgf.usermodel.section.geometry.SplineKnot; | |||
import org.apache.poi.xdgf.usermodel.section.geometry.SplineStart; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
import com.microsoft.schemas.office.visio.x2012.main.SectionType; | |||
public class GeometrySection extends XDGFSection { | |||
GeometrySection _master = null; | |||
// rows | |||
SortedMap<Long, GeometryRow> _rows = new TreeMap<>(); | |||
public GeometrySection(SectionType section, XDGFSheet containingSheet) { | |||
super(section, containingSheet); | |||
for (RowType row: section.getRowArray()) { | |||
if (_rows.containsKey(row.getIX())) | |||
throw new POIXMLException("Index element '" + row.getIX() + "' already exists"); | |||
_rows.put(row.getIX(), GeometryRowFactory.load(row)); | |||
} | |||
} | |||
@Override | |||
public void setupMaster(XDGFSection master) { | |||
_master = (GeometrySection)master; | |||
for (Entry<Long, GeometryRow> entry : _rows.entrySet()) { | |||
GeometryRow masterRow = _master._rows.get(entry.getKey()); | |||
if (masterRow != null) { | |||
try { | |||
entry.getValue().setupMaster(masterRow); | |||
} catch (ClassCastException e) { | |||
// this can happen when a dynamic connector overrides its master's geometry | |||
// .. probably can happen elsewhere too, I imagine. | |||
//throw XDGFException.error("Mismatched geometry section '" + entry.getKey() + "' in master", this, e); | |||
} | |||
} | |||
} | |||
} | |||
// returns True if this row shouldn't be displayed | |||
public Boolean getNoShow() { | |||
Boolean noShow = XDGFCell.maybeGetBoolean(_cells, "NoShow"); | |||
if (noShow == null) { | |||
if (_master != null) | |||
return _master.getNoShow(); | |||
return false; | |||
} | |||
return noShow; | |||
} | |||
public Iterable<GeometryRow> getCombinedRows() { | |||
return new CombinedIterable<>(_rows, | |||
_master == null ? null : _master._rows); | |||
} | |||
public Path2D.Double getPath(XDGFShape parent) { | |||
Iterator<GeometryRow> rows = getCombinedRows().iterator(); | |||
// special cases | |||
GeometryRow first = rows.next(); | |||
if (first instanceof Ellipse) { | |||
return ((Ellipse)first).getPath(); | |||
} else if (first instanceof InfiniteLine) { | |||
return ((InfiniteLine)first).getPath(); | |||
} else if (first instanceof SplineStart) { | |||
throw new POIXMLException("SplineStart must be preceded by another type"); | |||
} else { | |||
// everything else is a path | |||
Path2D.Double path = new Path2D.Double(); | |||
// dealing with splines makes this more complex | |||
SplineCollector renderer = null; | |||
GeometryRow row; | |||
while (true) { | |||
if (first != null) { | |||
row = first; | |||
first = null; | |||
} else { | |||
if (!rows.hasNext()) | |||
break; | |||
row = rows.next(); | |||
} | |||
if (row instanceof SplineStart) { | |||
if (renderer != null) | |||
throw new POIXMLException("SplineStart found multiple times!"); | |||
renderer = new SplineCollector((SplineStart) row); | |||
} else if (row instanceof SplineKnot) { | |||
if (renderer == null) | |||
throw new POIXMLException("SplineKnot found without SplineStart!"); | |||
renderer.addKnot((SplineKnot) row); | |||
} else { | |||
if (renderer != null) { | |||
renderer.addToPath(path, parent); | |||
renderer = null; | |||
} | |||
row.addToPath(path, parent); | |||
} | |||
} | |||
// just in case we end iteration | |||
if (renderer != null) | |||
renderer.addToPath(path, parent); | |||
return path; | |||
} | |||
} | |||
} |
@@ -0,0 +1,98 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.util.Internal; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFSheet; | |||
import org.apache.poi.xdgf.util.ObjectFactory; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.SectionType; | |||
public abstract class XDGFSection { | |||
static final ObjectFactory<XDGFSection, SectionType> _sectionTypes; | |||
static { | |||
_sectionTypes = new ObjectFactory<>(); | |||
try { | |||
_sectionTypes.put("LineGradient", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("FillGradient", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Character", CharacterSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Paragraph", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Tabs", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Scratch", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Connection", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("ConnectionABCD", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Field", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Control", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Geometry", GeometrySection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Actions", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Layer", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("User", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Property", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Hyperlink", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Reviewer", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("Annotation", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
_sectionTypes.put("ActionTag", GenericSection.class, SectionType.class, XDGFSheet.class); | |||
} catch (NoSuchMethodException | SecurityException e) { | |||
throw new POIXMLException("Internal error"); | |||
} | |||
} | |||
public static XDGFSection load(SectionType section, XDGFSheet containingSheet) { | |||
return _sectionTypes.load(section.getN(), section, containingSheet); | |||
} | |||
protected SectionType _section; | |||
protected XDGFSheet _containingSheet; | |||
protected Map<String, XDGFCell> _cells = new HashMap<>(); | |||
public XDGFSection(SectionType section, XDGFSheet containingSheet) { | |||
_section = section; | |||
_containingSheet = containingSheet; | |||
// only store cells in the base, not rows -- because rows are handled | |||
// specially for geometry sections | |||
for (CellType cell: section.getCellArray()) { | |||
_cells.put(cell.getN(), new XDGFCell(cell)); | |||
} | |||
} | |||
@Internal | |||
public SectionType getXmlObject() { | |||
return _section; | |||
} | |||
@Override | |||
public String toString() { | |||
return "<Section type=" + _section.getN() + " from " + _containingSheet + ">"; | |||
} | |||
public abstract void setupMaster(XDGFSection section); | |||
} |
@@ -0,0 +1,131 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Arc2D; | |||
import java.awt.geom.Path2D; | |||
import java.awt.geom.Point2D; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
public class ArcTo implements GeometryRow { | |||
ArcTo _master = null; | |||
// The x-coordinate of the ending vertex of an arc. | |||
Double x = null; | |||
// The y-coordinate of the ending vertex of an arc. | |||
Double y = null; | |||
// The distance from the arc's midpoint to the midpoint of its chord. | |||
Double a = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public ArcTo(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("A")) { | |||
a = XDGFCell.parseDoubleValue(cell); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in ArcTo row"); | |||
} | |||
} | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
public Double getA() { | |||
return a == null ? _master.a : a; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (ArcTo) row; | |||
} | |||
@Override | |||
public void addToPath(Path2D.Double path, XDGFShape parent) { | |||
if (getDel()) return; | |||
Point2D last = path.getCurrentPoint(); | |||
// intentionally shadowing variables here | |||
double x = getX(); | |||
double y = getY(); | |||
double a = getA(); | |||
if (a == 0) { | |||
path.lineTo(x, y); | |||
return; | |||
} | |||
double x0 = last.getX(); | |||
double y0 = last.getY(); | |||
double chordLength = Math.hypot(y - y0, x - x0); | |||
double radius = (4 * a * a + chordLength * chordLength) / (8 * Math.abs(a)); | |||
// center point | |||
double cx = x0 + (x - x0) / 2.0; | |||
double cy = y0 + (y - y0) / 2.0; | |||
double rotate = Math.atan2(y - cy, x - cx); | |||
Arc2D arc = new Arc2D.Double(x0, y0 - radius, | |||
chordLength, 2*radius, | |||
180, x0 < x ? 180 : -180, | |||
Arc2D.OPEN); | |||
path.append(AffineTransform.getRotateInstance(rotate, x0, y0).createTransformedShape(arc), true); | |||
} | |||
} |
@@ -0,0 +1,156 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Ellipse2D; | |||
import java.awt.geom.Path2D; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
public class Ellipse implements GeometryRow { | |||
Ellipse _master = null; | |||
// x coordinate of center point | |||
Double x = null; | |||
// y coordinate of center point | |||
Double y = null; | |||
// x coordinate of first point on ellipse | |||
Double a = null; | |||
// y coordinate of first point on ellipse | |||
Double b = null; | |||
// x coordinate of second point on ellipse | |||
Double c = null; | |||
// y coordinate of second point on ellipse | |||
Double d = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public Ellipse(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("A")) { | |||
a = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("B")) { | |||
b = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("C")) { | |||
c = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("D")) { | |||
d = XDGFCell.parseDoubleValue(cell); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in Ellipse row"); | |||
} | |||
} | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
public Double getA() { | |||
return a == null ? _master.a : a; | |||
} | |||
public Double getB() { | |||
return b == null ? _master.b : b; | |||
} | |||
public Double getC() { | |||
return c == null ? _master.c : c; | |||
} | |||
public Double getD() { | |||
return d == null ? _master.d : d; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (Ellipse) row; | |||
} | |||
public Path2D.Double getPath() { | |||
if (getDel()) return null; | |||
// intentionally shadowing variables here | |||
double cx = getX(); // center | |||
double cy = getY(); | |||
double a = getA(); // left | |||
double b = getB(); | |||
double c = getC(); // top | |||
double d = getD(); | |||
// compute radius | |||
double rx = Math.hypot(a - cx, b - cy); | |||
double ry = Math.hypot(c - cx, d - cy); | |||
// compute angle of ellipse | |||
double angle = (2.0*Math.PI + (cy > b ? 1.0 : -1.0) * Math.acos((cx - a) / rx)) % (2.0*Math.PI); | |||
// create ellipse | |||
Ellipse2D.Double ellipse = new Ellipse2D.Double(cx - rx, | |||
cy - ry, | |||
rx*2, ry*2); | |||
// create a path, rotate it about its center | |||
Path2D.Double path = new Path2D.Double(ellipse); | |||
AffineTransform tr = new AffineTransform(); | |||
tr.rotate(angle, cx, cy); | |||
path.transform(tr); | |||
return path; | |||
} | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
throw new POIXMLException("Ellipse elements cannot be part of a path"); | |||
} | |||
} |
@@ -0,0 +1,231 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Arc2D; | |||
import java.awt.geom.Path2D; | |||
import java.awt.geom.Point2D; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
public class EllipticalArcTo implements GeometryRow { | |||
EllipticalArcTo _master = null; | |||
// The x-coordinate of the ending vertex on an arc. | |||
Double x = null; | |||
// The y-coordinate of the ending vertex on an arc. | |||
Double y = null; | |||
// The x-coordinate of the arc's control point; a point on the arc. The | |||
// control point is best located about halfway between the beginning and | |||
// ending vertices of the arc. Otherwise, the arc may grow to an extreme | |||
// size in order to pass through the control point, with unpredictable | |||
// results. | |||
Double a = null; | |||
// The y-coordinate of an arc's control point. | |||
Double b = null; | |||
// The angle of an arc's major axis relative to the x-axis of its parent shape. | |||
Double c = null; | |||
// The ratio of an arc's major axis to its minor axis. Despite the usual | |||
// meaning of these words, the "major" axis does not have to be greater than | |||
// the "minor" axis, so this ratio does not have to be greater than 1. | |||
// Setting this cell to a value less than or equal to 0 or greater than 1000 | |||
// can lead to unpredictable results. | |||
Double d = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public EllipticalArcTo(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("A")) { | |||
a = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("B")) { | |||
b = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("C")) { | |||
c = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("D")) { | |||
d = XDGFCell.parseDoubleValue(cell); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in EllipticalArcTo row"); | |||
} | |||
} | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
public Double getA() { | |||
return a == null ? _master.a : a; | |||
} | |||
public Double getB() { | |||
return b == null ? _master.b : b; | |||
} | |||
public Double getC() { | |||
return c == null ? _master.c : c; | |||
} | |||
public Double getD() { | |||
return d == null ? _master.d : d; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (EllipticalArcTo) row; | |||
} | |||
public static int draw = 0; | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
if (getDel()) return; | |||
// intentionally shadowing variables here | |||
double x = getX(); | |||
double y = getY(); | |||
double a = getA(); | |||
double b = getB(); | |||
double c = getC(); | |||
double d = getD(); | |||
createEllipticalArc(x, y, a, b, c, d, path); | |||
} | |||
public static void createEllipticalArc(double x, double y, double a, double b, | |||
double c, double d, | |||
java.awt.geom.Path2D.Double path) { | |||
// Formula for center of ellipse by Junichi Yoda & nashwaan: | |||
// -> From http://visguy.com/vgforum/index.php?topic=2464.0 | |||
// | |||
// x1,y1 = start; x2,y2 = end; x3,y3 = control point | |||
// | |||
// x0 = ((x1-x2)*(x1+x2)*(y2-y3)-(x2-x3)*(x2+x3)*(y1-y2)+D^2*(y1-y2)*(y2-y3)*(y1-y3))/(2*((x1-x2)*(y2-y3)-(x2-x3)*(y1-y2))) | |||
// y0 = ((x1-x2)*(x2-x3)*(x1-x3)/D^2+(x2-x3)*(y1-y2)*(y1+y2)-(x1-x2)*(y2-y3)*(y2+y3))/(2*((x2-x3)*(y1-y2)-(x1-x2)*(y2-y3))) | |||
// radii along axis: a = sqrt{ (x1-x0)^2 + (y1-y0)^2 * D^2 } | |||
// | |||
Point2D last = path.getCurrentPoint(); | |||
double x0 = last.getX(); | |||
double y0 = last.getY(); | |||
// translate all of the points to the same angle as the ellipse | |||
AffineTransform at = AffineTransform.getRotateInstance(-c); | |||
double[] pts = new double[]{x0, y0, x, y, a, b}; | |||
at.transform(pts, 0, pts, 0, 3); | |||
x0 = pts[0]; y0 = pts[1]; | |||
x = pts[2]; y = pts[3]; | |||
a = pts[4]; b = pts[5]; | |||
// nasty math time | |||
double d2 = d*d; | |||
double cx = ((x0-x)*(x0+x)*(y-b)-(x-a)*(x+a)*(y0-y)+d2*(y0-y)*(y-b)*(y0-b))/(2.0*((x0-x)*(y-b)-(x-a)*(y0-y))); | |||
double cy = ((x0-x)*(x-a)*(x0-a)/d2+(x-a)*(y0-y)*(y0+y)-(x0-x)*(y-b)*(y+b))/(2.0*((x-a)*(y0-y)-(x0-x)*(y-b))); | |||
// calculate radii of ellipse | |||
double rx = Math.sqrt(Math.pow(x0-cx, 2) + Math.pow(y0-cy,2) * d2); | |||
double ry = rx / d; | |||
// Arc2D requires us to draw an arc from one point to another, so we | |||
// need to calculate the angle of the start point and end point along the ellipse | |||
// - Derived from parametric form of ellipse: x = h + a*cos(t); y = k + b*sin(t) | |||
double ctrlAngle = Math.toDegrees(Math.atan2((b-cy)/ry, (a-cx)/rx)); | |||
double startAngle = Math.toDegrees(Math.atan2((y0-cy)/ry, (x0-cx)/rx)); | |||
double endAngle = Math.toDegrees(Math.atan2((y-cy)/ry, (x-cx)/rx)); | |||
double sweep = computeSweep(startAngle, endAngle, ctrlAngle); | |||
// Now we have enough information to go on. Create the arc. | |||
Arc2D arc = new Arc2D.Double(cx-rx, cy-ry, | |||
rx*2, ry*2, -startAngle, sweep, Arc2D.OPEN); | |||
// rotate the arc back to the original coordinate system | |||
at.setToRotation(c); | |||
path.append(at.createTransformedShape(arc), false); | |||
} | |||
protected static double computeSweep(double startAngle, double endAngle, double ctrlAngle) { | |||
double sweep; | |||
startAngle = (360.0 + startAngle) % 360.0; | |||
endAngle = (360.0 + endAngle) % 360.0; | |||
ctrlAngle = (360.0 + ctrlAngle) % 360.0; | |||
// different sweeps depending on where the control point is | |||
if (startAngle < endAngle) { | |||
if (startAngle < ctrlAngle && ctrlAngle < endAngle) { | |||
sweep = startAngle - endAngle; | |||
} else { | |||
sweep = 360 + (startAngle - endAngle); | |||
} | |||
} else { | |||
if (endAngle < ctrlAngle && ctrlAngle < startAngle) { | |||
sweep = startAngle - endAngle; | |||
} else { | |||
sweep = - (360 - (startAngle - endAngle)); | |||
} | |||
} | |||
return sweep; | |||
} | |||
} |
@@ -0,0 +1,31 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import java.awt.geom.Path2D; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
public interface GeometryRow { | |||
public void setupMaster(GeometryRow row); | |||
public void addToPath(Path2D.Double path, XDGFShape parent); | |||
} |
@@ -0,0 +1,57 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.util.ObjectFactory; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
public class GeometryRowFactory { | |||
static final ObjectFactory<GeometryRow, RowType> _rowTypes; | |||
static { | |||
_rowTypes = new ObjectFactory<>(); | |||
try { | |||
_rowTypes.put("ArcTo", ArcTo.class, RowType.class); | |||
_rowTypes.put("Ellipse", Ellipse.class, RowType.class); | |||
_rowTypes.put("EllipticalArcTo", EllipticalArcTo.class, RowType.class); | |||
_rowTypes.put("InfiniteLine", InfiniteLine.class, RowType.class); | |||
_rowTypes.put("LineTo", LineTo.class, RowType.class); | |||
_rowTypes.put("MoveTo", MoveTo.class, RowType.class); | |||
_rowTypes.put("NURBSTo", NURBSTo.class, RowType.class); | |||
_rowTypes.put("PolyLineTo", PolyLineTo.class, RowType.class); | |||
_rowTypes.put("RelCubBezTo", RelCubBezTo.class, RowType.class); | |||
_rowTypes.put("RelEllipticalArcTo", RelEllipticalArcTo.class, RowType.class); | |||
_rowTypes.put("RelLineTo", RelLineTo.class, RowType.class); | |||
_rowTypes.put("RelMoveTo", RelMoveTo.class, RowType.class); | |||
_rowTypes.put("RelQuadBezTo", RelQuadBezTo.class, RowType.class); | |||
_rowTypes.put("SplineKnot", SplineKnot.class, RowType.class); | |||
_rowTypes.put("SplineStart", SplineStart.class, RowType.class); | |||
} catch (NoSuchMethodException | SecurityException e) { | |||
throw new POIXMLException("Internal error", e); | |||
} | |||
} | |||
public static GeometryRow load(RowType row) { | |||
return _rowTypes.load(row.getT(), row); | |||
} | |||
} |
@@ -0,0 +1,151 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import java.awt.geom.Path2D; | |||
import java.awt.geom.Point2D; | |||
import java.awt.geom.Rectangle2D; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.geom.Dimension2dDouble; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFDocument; | |||
import org.apache.poi.xdgf.usermodel.XDGFPage; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
/** | |||
* Contains the x- and y-coordinates of two points on an infinite line. | |||
*/ | |||
public class InfiniteLine implements GeometryRow { | |||
InfiniteLine _master = null; | |||
// An x-coordinate of a point on the infinite line; paired with y-coordinate represented by the Y cell. | |||
Double x = null; | |||
// A y-coordinate of a point on the infinite line; paired with x-coordinate represented by the X cell. | |||
Double y = null; | |||
// An x-coordinate of a point on the infinite line; paired with y-coordinate represented by the B cell. | |||
Double a = null; | |||
// A y-coordinate of a point on an infinite line; paired with x-coordinate represented by the A cell. | |||
Double b = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public InfiniteLine(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("A")) { | |||
a = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("B")) { | |||
b = XDGFCell.parseDoubleValue(cell); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in InfiniteLine row"); | |||
} | |||
} | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
public Double getA() { | |||
return a == null ? _master.a : a; | |||
} | |||
public Double getB() { | |||
return b == null ? _master.b : b; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (InfiniteLine) row; | |||
} | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
if (getDel()) return; | |||
throw new POIXMLException("InfiniteLine elements cannot be part of a path"); | |||
} | |||
// returns this object as a line that extends between the boundaries of | |||
// the document | |||
public Path2D.Double getPath() { | |||
Path2D.Double path = new Path2D.Double(); | |||
// this is a bit of a hack, but it works | |||
double max_val = 100000; | |||
// compute slope.. | |||
double x0 = getX(); | |||
double y0 = getY(); | |||
double x1 = getA(); // second x | |||
double y1 = getB(); // second y | |||
if (x0 == x1) { | |||
path.moveTo(x0, -max_val); | |||
path.lineTo(x0, max_val); | |||
} else if (y0 == y1) { | |||
path.moveTo(-max_val, y0); | |||
path.lineTo(max_val, y0); | |||
} else { | |||
// normal case: compute slope/intercept | |||
double m = (y1 - y0) / (x1 - x0); | |||
double c = y0 - m*x0; | |||
// y = mx + c | |||
path.moveTo(max_val, m*max_val + c); | |||
path.lineTo(max_val, (max_val - c)/m); | |||
} | |||
return path; | |||
} | |||
} |
@@ -0,0 +1,88 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
public class LineTo implements GeometryRow { | |||
LineTo _master = null; | |||
Double x = null; | |||
Double y = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public LineTo(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in LineTo row"); | |||
} | |||
} | |||
} | |||
@Override | |||
public String toString() { | |||
return "LineTo: x=" + getX() + "; y=" + getY(); | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (LineTo) row; | |||
} | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
if (getDel()) return; | |||
path.lineTo(getX(), getY()); | |||
} | |||
} |
@@ -0,0 +1,93 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
/** | |||
* Contains the x- and y-coordinates of the first vertex of a shape or the x- | |||
* and y-coordinates of the first vertex after a break in a path, relative to | |||
* the height and width of the shape. | |||
*/ | |||
public class MoveTo implements GeometryRow { | |||
MoveTo _master = null; | |||
Double x = null; | |||
Double y = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public MoveTo(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in MoveTo row"); | |||
} | |||
} | |||
} | |||
@Override | |||
public String toString() { | |||
return "MoveTo: x=" + getX() + "; y=" + getY(); | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (MoveTo) row; | |||
} | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
if (getDel()) return; | |||
path.moveTo(getX(), getY()); | |||
} | |||
} |
@@ -0,0 +1,205 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import java.awt.geom.Point2D; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.geom.SplineRenderer; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.graphbuilder.curve.ControlPath; | |||
import com.graphbuilder.curve.ShapeMultiPath; | |||
import com.graphbuilder.curve.ValueVector; | |||
import com.graphbuilder.geom.PointFactory; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
public class NURBSTo implements GeometryRow { | |||
NURBSTo _master = null; | |||
// The x-coordinate of the last control point of a NURBS. | |||
Double x = null; | |||
// The y-coordinate of the last control point of a NURBS. | |||
Double y = null; | |||
// The second to the last knot of the NURBS. | |||
Double a = null; | |||
// The last weight of the NURBS. | |||
Double b = null; | |||
// The first knot of the NURBS. | |||
Double c = null; | |||
// The first weight of the NURBS. | |||
Double d = null; | |||
// A NURBS formula. | |||
String e = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public NURBSTo(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("A")) { | |||
a = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("B")) { | |||
b = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("C")) { | |||
c = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("D")) { | |||
d = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("E")) { | |||
e = cell.getV(); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in NURBS row"); | |||
} | |||
} | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
public Double getA() { | |||
return a == null ? _master.a : a; | |||
} | |||
public Double getB() { | |||
return b == null ? _master.b : b; | |||
} | |||
public Double getC() { | |||
return c == null ? _master.c : c; | |||
} | |||
public Double getD() { | |||
return d == null ? _master.d : d; | |||
} | |||
public String getE() { | |||
return e == null ? _master.e : e; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (NURBSTo) row; | |||
} | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
if (getDel()) return; | |||
Point2D last = path.getCurrentPoint(); | |||
// A NURBS formula: knotLast, degree, xType, yType, x1, y1, knot1, weight1, .. | |||
String formula = getE().trim(); | |||
if (!formula.startsWith("NURBS(") || !formula.endsWith(")")) | |||
throw new POIXMLException("Invalid NURBS formula: " + formula); | |||
String [] components = formula.substring(6, formula.length()-1).split(","); | |||
if (components.length < 8) | |||
throw new POIXMLException("Invalid NURBS formula (not enough arguments)"); | |||
if ((components.length - 4) % 4 != 0) | |||
throw new POIXMLException("Invalid NURBS formula -- need 4 + n*4 arguments, got " + components.length); | |||
double lastControlX = getX(); | |||
double lastControlY = getY(); | |||
double secondToLastKnot = getA(); | |||
double lastWeight = getB(); | |||
double firstKnot = getC(); | |||
double firstWeight = getD(); | |||
double lastKnot = Double.parseDouble(components[0].trim()); | |||
int degree = Integer.parseInt(components[1].trim()); | |||
int xType = Integer.parseInt(components[2].trim()); | |||
int yType = Integer.parseInt(components[3].trim()); | |||
double xScale = 1; | |||
double yScale = 1; | |||
if (xType == 0) | |||
xScale = parent.getWidth(); | |||
if (yType == 0) | |||
yScale = parent.getHeight(); | |||
// setup first knots/weights/control point | |||
ControlPath controlPath = new ControlPath(); | |||
ValueVector knots = new ValueVector(); | |||
ValueVector weights = new ValueVector(); | |||
knots.add(firstKnot); | |||
weights.add(firstWeight); | |||
controlPath.addPoint(PointFactory.create(last.getX(), last.getY())); | |||
// iterate get knots/weights | |||
int sets = (components.length - 4) / 4; | |||
for (int i = 0; i < sets; i++) { | |||
double x1 = Double.parseDouble(components[4 + i*4 + 0].trim()); | |||
double y1 = Double.parseDouble(components[4 + i*4 + 1].trim()); | |||
double k = Double.parseDouble(components[4 + i*4 + 2].trim()); | |||
double w = Double.parseDouble(components[4 + i*4 + 3].trim()); | |||
controlPath.addPoint(PointFactory.create(x1*xScale, y1*yScale)); | |||
knots.add(k); | |||
weights.add(w); | |||
} | |||
// last knots/weights/control point | |||
knots.add(secondToLastKnot); | |||
knots.add(lastKnot); | |||
weights.add(lastWeight); | |||
controlPath.addPoint(PointFactory.create(lastControlX, lastControlY)); | |||
ShapeMultiPath shape = SplineRenderer.createNurbsSpline(controlPath, knots, weights, degree); | |||
path.append(shape, true); | |||
} | |||
} |
@@ -0,0 +1,95 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
public class PolyLineTo implements GeometryRow { | |||
PolyLineTo _master = null; | |||
// The x-coordinate of the ending vertex of a polyline. | |||
Double x = null; | |||
// The y-coordinate of the ending vertex of a polyline. | |||
Double y = null; | |||
// The polyline formula | |||
String a = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public PolyLineTo(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("A")) { | |||
a = cell.getV(); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in ArcTo row"); | |||
} | |||
} | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
public String getA() { | |||
return a == null ? _master.a : a; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (PolyLineTo) row; | |||
} | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
if (getDel()) return; | |||
throw new POIXMLException("Polyline support not implemented"); | |||
} | |||
} |
@@ -0,0 +1,127 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
public class RelCubBezTo implements GeometryRow { | |||
RelCubBezTo _master = null; | |||
// The x-coordinate of the ending vertex of a cubic Bézier curve relative to the width of the shape. | |||
Double x = null; | |||
// The y-coordinate of the ending vertex of a cubic Bézier curve relative to the height of the shape. | |||
Double y = null; | |||
// The x-coordinate of the curve’s beginning control point relative to the shape’s width; a point on the arc. The control point is best located between the beginning and ending vertices of the arc. | |||
Double a = null; | |||
// The y-coordinate of a curve’s beginning control point relative to the shape’s height. | |||
Double b = null; | |||
// The x-coordinate of the curve’s ending control point relative to the shape’s width; a point on the arc. The control point is best located between the beginning control point and ending vertices of the arc. | |||
Double c = null; | |||
// The y-coordinate of a curve's ending control point relative to the shape’s height. | |||
Double d = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public RelCubBezTo(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("A")) { | |||
a = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("B")) { | |||
b = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("C")) { | |||
c = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("D")) { | |||
d = XDGFCell.parseDoubleValue(cell); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in RelCubBezTo row"); | |||
} | |||
} | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
public Double getA() { | |||
return a == null ? _master.a : a; | |||
} | |||
public Double getB() { | |||
return b == null ? _master.b : b; | |||
} | |||
public Double getC() { | |||
return c == null ? _master.c : c; | |||
} | |||
public Double getD() { | |||
return d == null ? _master.d : d; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (RelCubBezTo) row; | |||
} | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
if (getDel()) return; | |||
double w = parent.getWidth(); | |||
double h = parent.getHeight(); | |||
path.curveTo(getA()*w, getB()*h, getC()*w, getD()*h, getX()*w, getY()*h); | |||
} | |||
} |
@@ -0,0 +1,141 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
public class RelEllipticalArcTo implements GeometryRow { | |||
RelEllipticalArcTo _master = null; | |||
// The x-coordinate of the ending vertex on an arc relative to the width of | |||
// the shape. | |||
Double x = null; | |||
// The y-coordinate of the ending vertex on an arc relative to the height of | |||
// the shape. | |||
Double y = null; | |||
// The x-coordinate of the arc's control point relative to the shape’s | |||
// width; a point on the arc. | |||
Double a = null; | |||
// The y-coordinate of an arc's control point relative to the shape’s width. | |||
Double b = null; | |||
// The angle of an arc's major axis relative to the x-axis of its parent. | |||
Double c = null; | |||
// The ratio of an arc's major axis to its minor axis. Despite the usual | |||
// meaning of these words, the "major" axis does not have to be greater than | |||
// the "minor" axis, so this ratio does not have to be greater than 1. | |||
Double d = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public RelEllipticalArcTo(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("A")) { | |||
a = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("B")) { | |||
b = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("C")) { | |||
c = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("D")) { | |||
d = XDGFCell.parseDoubleValue(cell); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in RelEllipticalArcTo row"); | |||
} | |||
} | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
public Double getA() { | |||
return a == null ? _master.a : a; | |||
} | |||
public Double getB() { | |||
return b == null ? _master.b : b; | |||
} | |||
public Double getC() { | |||
return c == null ? _master.c : c; | |||
} | |||
public Double getD() { | |||
return d == null ? _master.d : d; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (RelEllipticalArcTo) row; | |||
} | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
if (getDel()) return; | |||
double w = parent.getWidth(); | |||
double h = parent.getHeight(); | |||
// intentionally shadowing variables here | |||
double x = getX()*w; | |||
double y = getY()*h; | |||
double a = getA()*w; | |||
double b = getB()*h; | |||
double c = getC(); | |||
double d = getD(); | |||
EllipticalArcTo.createEllipticalArc(x, y, a, b, c, d, path); | |||
} | |||
} |
@@ -0,0 +1,90 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
/** | |||
* Contains x-and y-coordinates of the ending vertex of a straight line segment | |||
* relative to a shape’s width and height. | |||
*/ | |||
public class RelLineTo implements GeometryRow { | |||
RelLineTo _master = null; | |||
Double x = null; | |||
Double y = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public RelLineTo(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in RelLineTo row"); | |||
} | |||
} | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (RelLineTo) row; | |||
} | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
if (getDel()) return; | |||
path.lineTo(getX()*parent.getWidth(), | |||
getY()*parent.getHeight()); | |||
} | |||
} |
@@ -0,0 +1,86 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
public class RelMoveTo implements GeometryRow { | |||
RelMoveTo _master = null; | |||
Double x = null; | |||
Double y = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public RelMoveTo(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in RelMoveTo row"); | |||
} | |||
} | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (RelMoveTo) row; | |||
} | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
if (getDel()) return; | |||
path.moveTo(getX()*parent.getWidth(), | |||
getY()*parent.getHeight()); | |||
} | |||
} |
@@ -0,0 +1,114 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
/** | |||
* Contains the x- and y-coordinates of the endpoint of a quadratic Bézier curve | |||
* relative to the shape’s width and height and the x- and y-coordinates of the | |||
* control point of the curve relative shape’s width and height. | |||
*/ | |||
public class RelQuadBezTo implements GeometryRow { | |||
RelQuadBezTo _master = null; | |||
// The x-coordinate of the ending vertex of a quadratic Bézier curve relative to the width of the shape. | |||
Double x = null; | |||
// The y-coordinate of the ending vertex of a quadratic Bézier curve relative to the height of the shape. | |||
Double y = null; | |||
// The x-coordinate of the curve’s control point relative to the shape’s width; a point on the arc. The control point is best located about halfway between the beginning and ending vertices of the arc. | |||
Double a = null; | |||
// The y-coordinate of a curve’s control point relative to the shape’s height. | |||
Double b = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public RelQuadBezTo(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("A")) { | |||
a = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("B")) { | |||
b = XDGFCell.parseDoubleValue(cell); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in RelQuadBezTo row"); | |||
} | |||
} | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
public Double getA() { | |||
return a == null ? _master.a : a; | |||
} | |||
public Double getB() { | |||
return b == null ? _master.b : b; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (RelQuadBezTo) row; | |||
} | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
if (getDel()) return; | |||
double w = parent.getWidth(); | |||
double h = parent.getHeight(); | |||
path.quadTo(getA()*w, getB()*h, getX()*w, getY()*h); | |||
} | |||
} |
@@ -0,0 +1,102 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
/** | |||
* Contains x- and y-coordinates for a spline's control point and a spline's knot. | |||
*/ | |||
public class SplineKnot implements GeometryRow { | |||
SplineKnot _master = null; | |||
// The x-coordinate of a control point. | |||
Double x = null; | |||
// The y-coordinate of a control point. | |||
Double y = null; | |||
// One of the spline's knots (other than the last one or the first two). | |||
Double a = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public SplineKnot(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("A")) { | |||
a = XDGFCell.parseDoubleValue(cell); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in SplineKnot row"); | |||
} | |||
} | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
public Double getA() { | |||
return a == null ? _master.a : a; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (SplineKnot) row; | |||
} | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
throw new POIXMLException("Error: Use SplineRenderer!"); | |||
} | |||
@Override | |||
public String toString() { | |||
return "{SplineKnot x=" + getX() + " y=" + getY() + " a=" + getA() + "}"; | |||
} | |||
} |
@@ -0,0 +1,132 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section.geometry; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.xdgf.usermodel.XDGFCell; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import com.microsoft.schemas.office.visio.x2012.main.CellType; | |||
import com.microsoft.schemas.office.visio.x2012.main.RowType; | |||
/** | |||
* Contains x- and y-coordinates for a spline's second control point, its second | |||
* knot, its first knot, the last knot, and the degree of the spline. | |||
*/ | |||
public class SplineStart implements GeometryRow { | |||
SplineStart _master = null; | |||
// The x-coordinate of a spline's second control point. | |||
Double x = null; | |||
// The y-coordinate of a spline's second control point. | |||
Double y = null; | |||
// The second knot of the spline. | |||
Double a = null; | |||
// The first knot of a spline. | |||
Double b = null; | |||
// The last knot of a spline. | |||
Double c = null; | |||
// The degree of a spline (an integer from 1 to 25). | |||
Integer d = null; | |||
Boolean deleted = null; | |||
// TODO: support formulas | |||
public SplineStart(RowType row) { | |||
if (row.isSetDel()) deleted = row.getDel(); | |||
for (CellType cell: row.getCellArray()) { | |||
String cellName = cell.getN(); | |||
if (cellName.equals("X")) { | |||
x = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("Y")) { | |||
y = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("A")) { | |||
a = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("B")) { | |||
b = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("C")) { | |||
c = XDGFCell.parseDoubleValue(cell); | |||
} else if (cellName.equals("D")) { | |||
d = XDGFCell.parseIntegerValue(cell); | |||
} else { | |||
throw new POIXMLException("Invalid cell '" + cellName + "' in SplineStart row"); | |||
} | |||
} | |||
} | |||
public boolean getDel() { | |||
if (deleted != null) | |||
return deleted; | |||
if (_master != null) | |||
return _master.getDel(); | |||
return false; | |||
} | |||
public Double getX() { | |||
return x == null ? _master.x : x; | |||
} | |||
public Double getY() { | |||
return y == null ? _master.y : y; | |||
} | |||
public Double getA() { | |||
return a == null ? _master.a : a; | |||
} | |||
public Double getB() { | |||
return b == null ? _master.b : b; | |||
} | |||
public Double getC() { | |||
return c == null ? _master.c : c; | |||
} | |||
public Integer getD() { | |||
return d == null ? _master.d : d; | |||
} | |||
@Override | |||
public void setupMaster(GeometryRow row) { | |||
_master = (SplineStart) row; | |||
} | |||
@Override | |||
public void addToPath(java.awt.geom.Path2D.Double path, XDGFShape parent) { | |||
throw new POIXMLException("Error: Use SplineRenderer!"); | |||
} | |||
@Override | |||
public String toString() { | |||
return "{SplineStart x=" + getX() + " y=" + getY() + | |||
" a=" + getA() + " b=" + getB() + | |||
" c=" + getC() + " d=" + getD() + | |||
"}"; | |||
} | |||
} |
@@ -0,0 +1,69 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.shape; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
/** | |||
* This acceptor only allows traversal to shapes that have useful data | |||
* associated with them, and tries to elide details that aren't useful | |||
* when analyzing the content of a document. | |||
* | |||
* Useful is subjective of course, and is defined as any of: | |||
* | |||
* - Has non-empty text | |||
* - Is a 1d shape, such as a line | |||
* - User specified shapes | |||
* - The outline of stencil objects | |||
* - TODO | |||
*/ | |||
public class ShapeDataAcceptor implements ShapeVisitorAcceptor { | |||
@Override | |||
public boolean accept(XDGFShape shape) { | |||
if (shape.isDeleted()) | |||
return false; | |||
// text is interesting | |||
if (shape.hasText() && shape.getTextAsString().length() != 0) | |||
return true; | |||
// 1d shapes are interesting, they create connections | |||
if (shape.isShape1D()) | |||
return true; | |||
// User specified shapes are interesting | |||
if (!shape.hasMaster() && !shape.hasMasterShape()) | |||
return true; | |||
if (shape.hasMaster() && !shape.hasMasterShape()) | |||
return true; | |||
// include stencil content, but try to elide stencil interiors | |||
//if (shape.getXmlObject().isSetMaster()) | |||
// return true; | |||
if (shape.hasMasterShape() && shape.getMasterShape().isTopmost()) | |||
return true; | |||
return false; | |||
} | |||
} |
@@ -0,0 +1,70 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.shape; | |||
import java.awt.Font; | |||
import java.awt.Graphics2D; | |||
import java.awt.geom.Path2D; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
public class ShapeDebuggerRenderer extends ShapeRenderer { | |||
ShapeVisitorAcceptor _debugAcceptor = null; | |||
public ShapeDebuggerRenderer() { | |||
super(); | |||
} | |||
public ShapeDebuggerRenderer(Graphics2D g) { | |||
super(g); | |||
} | |||
public void setDebugAcceptor(ShapeVisitorAcceptor acceptor) { | |||
_debugAcceptor = acceptor; | |||
} | |||
@Override | |||
protected Path2D drawPath(XDGFShape shape){ | |||
Path2D path = super.drawPath(shape); | |||
if (_debugAcceptor == null || _debugAcceptor.accept(shape)) { | |||
// show numbers to associate shapes with ids.. doesn't always work | |||
Font f = _graphics.getFont(); | |||
_graphics.scale(1, -1); | |||
_graphics.setFont(f.deriveFont(0.05F)); | |||
String shapeId = "" + shape.getID(); | |||
float shapeOffset = -0.1F; | |||
if (shape.hasMasterShape()) { | |||
shapeId += " MS:" + shape.getMasterShape().getID(); | |||
shapeOffset -= 0.15F; | |||
} | |||
_graphics.drawString(shapeId, shapeOffset, 0); | |||
_graphics.setFont(f); | |||
_graphics.scale(1, -1); | |||
} | |||
return path; | |||
} | |||
} |
@@ -0,0 +1,93 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.shape; | |||
import java.awt.BasicStroke; | |||
import java.awt.Font; | |||
import java.awt.Graphics2D; | |||
import java.awt.geom.AffineTransform; | |||
import java.awt.geom.Path2D; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import org.apache.poi.xdgf.usermodel.XDGFText; | |||
/** | |||
* To use this to render only particular shapes, override it and provide an | |||
* appropriate implementation of getAcceptor() or accept() | |||
*/ | |||
public class ShapeRenderer extends ShapeVisitor { | |||
protected Graphics2D _graphics; | |||
public ShapeRenderer() { | |||
_graphics = null; | |||
} | |||
public ShapeRenderer(Graphics2D g) { | |||
_graphics = g; | |||
} | |||
public void setGraphics(Graphics2D g) { | |||
_graphics = g; | |||
} | |||
@Override | |||
public void visit(XDGFShape shape, AffineTransform globalTransform, int level) { | |||
AffineTransform savedTr = _graphics.getTransform(); | |||
_graphics.transform(globalTransform); | |||
drawPath(shape); | |||
drawText(shape); | |||
// we're done, undo the transforms | |||
_graphics.setTransform(savedTr); | |||
} | |||
protected Path2D drawPath(XDGFShape shape) { | |||
Path2D.Double path = shape.getPath(); | |||
if (path != null) { | |||
// setup the stroke for this line | |||
_graphics.setColor(shape.getLineColor()); | |||
_graphics.setStroke(shape.getStroke()); | |||
_graphics.draw(path); | |||
} | |||
return path; | |||
} | |||
protected void drawText(XDGFShape shape) { | |||
XDGFText text = shape.getText(); | |||
if (text != null) { | |||
if (text.getTextContent().equals("Header")) | |||
text.getTextBounds(); | |||
Font oldFont = _graphics.getFont(); | |||
_graphics.setFont(oldFont.deriveFont(shape.getFontSize().floatValue())); | |||
_graphics.setColor(shape.getFontColor()); | |||
text.draw(_graphics); | |||
_graphics.setFont(oldFont); | |||
} | |||
} | |||
} |
@@ -0,0 +1,68 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.shape; | |||
import java.awt.geom.AffineTransform; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
/** | |||
* Used to iterate through shapes | |||
* | |||
* To change the behavior of a particular visitor, you can override either | |||
* accept() or getAcceptor() [preferred] | |||
* | |||
* If accept() or visit() throw StopVisitingThisBranch, the iteration will | |||
* not visit subshapes of the shape. | |||
*/ | |||
public abstract class ShapeVisitor{ | |||
ShapeVisitorAcceptor _acceptor; | |||
public ShapeVisitor() { | |||
_acceptor = getAcceptor(); | |||
} | |||
// is only called on construction of the visitor, allows | |||
// mixing visitors and acceptors | |||
public ShapeVisitorAcceptor getAcceptor() { | |||
return new ShapeVisitorAcceptor() { | |||
@Override | |||
public boolean accept(XDGFShape shape) { | |||
return !shape.isDeleted(); | |||
} | |||
}; | |||
} | |||
public void setAcceptor(ShapeVisitorAcceptor acceptor) { | |||
_acceptor = acceptor; | |||
} | |||
public boolean accept(XDGFShape shape) { | |||
return _acceptor.accept(shape); | |||
} | |||
/** | |||
* @param shape Current shape | |||
* @param globalTransform A transform that can convert the shapes points to global coordinates | |||
* @param level Level in the tree (0 is topmost, 1 is next level... | |||
*/ | |||
public abstract void visit(XDGFShape shape, AffineTransform globalTransform, int level); | |||
} |
@@ -0,0 +1,26 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.shape; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
public interface ShapeVisitorAcceptor { | |||
public boolean accept(XDGFShape shape); | |||
} |
@@ -0,0 +1,24 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.shape.exceptions; | |||
public class StopVisiting extends RuntimeException { | |||
private static final long serialVersionUID = -4651207777092840750L; | |||
} |
@@ -0,0 +1,24 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.shape.exceptions; | |||
public class StopVisitingThisBranch extends RuntimeException { | |||
private static final long serialVersionUID = 5262319077534717862L; | |||
} |
@@ -0,0 +1,84 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.util; | |||
import java.awt.geom.AffineTransform; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileNotFoundException; | |||
import java.io.FileOutputStream; | |||
import java.io.OutputStream; | |||
import java.io.PrintStream; | |||
import org.apache.poi.xdgf.usermodel.XDGFPage; | |||
import org.apache.poi.xdgf.usermodel.XDGFShape; | |||
import org.apache.poi.xdgf.usermodel.XmlVisioDocument; | |||
import org.apache.poi.xdgf.usermodel.shape.ShapeVisitor; | |||
public class HierarchyPrinter { | |||
public static void printHierarchy(XDGFPage page, File outDir) throws FileNotFoundException { | |||
File pageFile = new File(outDir, "page" + page.getPageNumber() + "-" + Util.sanitizeFilename(page.getName()) + ".txt"); | |||
OutputStream os = new FileOutputStream(pageFile); | |||
PrintStream pos = new PrintStream(os); | |||
printHierarchy(page, pos); | |||
pos.close(); | |||
} | |||
public static void printHierarchy(XDGFPage page, final PrintStream os) { | |||
page.getContent().visitShapes(new ShapeVisitor() { | |||
@Override | |||
public void visit(XDGFShape shape, AffineTransform globalTransform, int level) { | |||
for (int i = 0; i < level; i++) { | |||
os.append(" "); | |||
} | |||
// TODO: write text? | |||
os.println(shape.toString() + " [" + shape.getShapeType() + ", " + shape.getSymbolName() + "] " + shape.getMasterShape() + " " + shape.getTextAsString().trim()); | |||
} | |||
}); | |||
} | |||
public static void printHierarchy(XmlVisioDocument document, String outDirname) throws FileNotFoundException { | |||
File outDir = new File(outDirname); | |||
for (XDGFPage page: document.getPages()) { | |||
printHierarchy(page, outDir); | |||
} | |||
} | |||
public static void main(String [] args) throws Exception { | |||
if (args.length != 2) { | |||
System.err.println("Usage: in.vsdx outdir"); | |||
System.exit(1); | |||
} | |||
String inFilename = args[0]; | |||
String outDir = args[1]; | |||
XmlVisioDocument doc = new XmlVisioDocument(new FileInputStream(inFilename)); | |||
printHierarchy(doc, outDir); | |||
} | |||
} |
@@ -0,0 +1,57 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.util; | |||
import java.lang.reflect.Constructor; | |||
import java.lang.reflect.InvocationTargetException; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.xmlbeans.XmlObject; | |||
public class ObjectFactory<T, X extends XmlObject> { | |||
Map<String, Constructor<? extends T>> _types = new HashMap<>(); | |||
public void put(String typeName, Class<? extends T> cls, Class<?>... varargs) throws NoSuchMethodException, SecurityException { | |||
_types.put(typeName, cls.getDeclaredConstructor(varargs)); | |||
} | |||
public T load(String name, Object... varargs) { | |||
Constructor<? extends T> constructor = _types.get(name); | |||
if (constructor == null) { | |||
@SuppressWarnings("unchecked") | |||
X xmlObject = (X) varargs[0]; | |||
String typeName = xmlObject.schemaType().getName().getLocalPart(); | |||
throw new POIXMLException("Invalid '" + typeName + "' name '" + name + "'"); | |||
} | |||
try { | |||
return constructor.newInstance(varargs); | |||
} catch (InvocationTargetException e) { | |||
throw new POIXMLException(e.getCause()); | |||
} catch (Exception e) { | |||
throw new POIXMLException(e); | |||
} | |||
} | |||
} |
@@ -0,0 +1,37 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.util; | |||
public class Util { | |||
public static int countLines(String str) { | |||
int lines = 1; | |||
int pos = 0; | |||
while ((pos = str.indexOf("\n", pos) + 1) != 0) { | |||
lines++; | |||
} | |||
return lines; | |||
} | |||
// this probably isn't 100% correct, so don't use it in security-sensitive | |||
// applications! | |||
// from: http://www.rgagnon.com/javadetails/java-0662.html | |||
public static String sanitizeFilename(String name) { | |||
return name.replaceAll("[:\\\\/*\"?|<>]", "_"); | |||
} | |||
} |
@@ -0,0 +1,118 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.util; | |||
import java.awt.Color; | |||
import java.awt.Graphics2D; | |||
import java.awt.RenderingHints; | |||
import java.awt.geom.Point2D; | |||
import java.awt.image.BufferedImage; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import javax.imageio.ImageIO; | |||
import org.apache.poi.xdgf.geom.Dimension2dDouble; | |||
import org.apache.poi.xdgf.usermodel.XDGFPage; | |||
import org.apache.poi.xdgf.usermodel.XmlVisioDocument; | |||
import org.apache.poi.xdgf.usermodel.shape.ShapeDebuggerRenderer; | |||
import org.apache.poi.xdgf.usermodel.shape.ShapeRenderer; | |||
public class VsdxToPng { | |||
public static void renderToPng(XDGFPage page, String outFilename, double scale, ShapeRenderer renderer) throws IOException { | |||
renderToPng(page, new File(outFilename), scale, renderer); | |||
} | |||
public static void renderToPngDir(XDGFPage page, File outDir, double scale, ShapeRenderer renderer) throws IOException { | |||
File pageFile = new File(outDir, "page" + page.getPageNumber() + "-" + Util.sanitizeFilename(page.getName()) + ".png"); | |||
System.out.println("** Writing image to " + pageFile); | |||
renderToPng(page, pageFile, scale, renderer); | |||
} | |||
public static void renderToPng(XDGFPage page, File outFile, double scale, ShapeRenderer renderer) throws IOException { | |||
Dimension2dDouble sz = page.getPageSize(); | |||
int width = (int)(scale * sz.getWidth()); | |||
int height = (int)(scale * sz.getHeight()); | |||
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); | |||
final Graphics2D graphics = img.createGraphics(); | |||
// default rendering options | |||
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | |||
graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); | |||
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); | |||
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); | |||
graphics.setColor(Color.black); | |||
graphics.setBackground(Color.white); | |||
graphics.clearRect(0, 0, width, height); | |||
// Visio's coordinate system is flipped, so flip the image vertically | |||
graphics.translate(0, img.getHeight()); | |||
graphics.scale(scale, -scale); | |||
// toplevel shapes only | |||
renderer.setGraphics(graphics); | |||
page.getContent().visitShapes(renderer); | |||
graphics.dispose(); | |||
FileOutputStream out = new FileOutputStream(outFile); | |||
ImageIO.write(img, "png", out); | |||
out.close(); | |||
} | |||
public static void renderToPng(XmlVisioDocument document, String outDirname, double scale, ShapeRenderer renderer) throws IOException { | |||
File outDir = new File(outDirname); | |||
for (XDGFPage page: document.getPages()) { | |||
renderToPngDir(page, outDir, scale, renderer); | |||
} | |||
} | |||
public static void main(String [] args) throws Exception { | |||
if (args.length > 2) { | |||
System.err.println("Usage: [--debug] in.vsdx outdir"); | |||
System.exit(1); | |||
} | |||
ShapeRenderer renderer = new ShapeRenderer(); | |||
String inFilename = args[0]; | |||
String pngDir = args[1]; | |||
if (args[0].equals("--debug")) { | |||
inFilename = args[1]; | |||
pngDir = args[2]; | |||
renderer = new ShapeDebuggerRenderer(); | |||
} | |||
XmlVisioDocument doc = new XmlVisioDocument(new FileInputStream(inFilename)); | |||
renderToPng(doc, pngDir, 2000/11.0, renderer); | |||
} | |||
} |
@@ -0,0 +1,33 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.xml; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
import org.apache.poi.xdgf.usermodel.XDGFDocument; | |||
public class XDGFXMLDocumentPart extends POIXMLDocumentPart { | |||
protected XDGFDocument _document; | |||
public XDGFXMLDocumentPart(PackagePart part, PackageRelationship rel, XDGFDocument document) { | |||
super(part, rel); | |||
_document = document; | |||
} | |||
} |
@@ -0,0 +1,159 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xdgf.usermodel.section; | |||
import java.util.Iterator; | |||
import java.util.SortedMap; | |||
import java.util.TreeMap; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
public class CombinedIteratorTest { | |||
void testIteration(CombinedIterable<String> iterable, String... expected) { | |||
Iterator<String> iter = iterable.iterator(); | |||
for (int i = 0; i < expected.length; i++) { | |||
Assert.assertEquals(true, iter.hasNext()); | |||
Assert.assertEquals(expected[i], iter.next()); | |||
} | |||
Assert.assertEquals(false, iter.hasNext()); | |||
} | |||
@Test | |||
public void testNullMaster() { | |||
SortedMap<Long, String> base = new TreeMap<>(); | |||
base.put(1L, "B1"); | |||
base.put(2L, "B2"); | |||
base.put(3L, "B3"); | |||
testIteration(new CombinedIterable<>(base, null), | |||
"B1", "B2", "B3"); | |||
} | |||
@Test | |||
public void testNoMatchesBaseFirst() { | |||
SortedMap<Long, String> base = new TreeMap<>(); | |||
base.put(1L, "B1"); | |||
base.put(2L, "B2"); | |||
base.put(3L, "B3"); | |||
SortedMap<Long, String> master = new TreeMap<>(); | |||
master.put(4L, "M4"); | |||
master.put(5L, "M5"); | |||
master.put(6L, "M6"); | |||
testIteration(new CombinedIterable<>(base, master), | |||
"B1", "B2", "B3", "M4", "M5", "M6"); | |||
} | |||
@Test | |||
public void testNoMatchesMasterFirst() { | |||
SortedMap<Long, String> base = new TreeMap<>(); | |||
base.put(4L, "B4"); | |||
base.put(5L, "B5"); | |||
base.put(6L, "B6"); | |||
SortedMap<Long, String> master = new TreeMap<>(); | |||
master.put(1L, "M1"); | |||
master.put(2L, "M2"); | |||
master.put(3L, "M3"); | |||
testIteration(new CombinedIterable<>(base, master), | |||
"M1", "M2", "M3", "B4", "B5", "B6"); | |||
} | |||
@Test | |||
public void testInterleaved1() { | |||
SortedMap<Long, String> base = new TreeMap<>(); | |||
base.put(1L, "B1"); | |||
base.put(3L, "B3"); | |||
base.put(5L, "B5"); | |||
SortedMap<Long, String> master = new TreeMap<>(); | |||
master.put(2L, "M2"); | |||
master.put(4L, "M4"); | |||
master.put(6L, "M6"); | |||
testIteration(new CombinedIterable<>(base, master), | |||
"B1", "M2", "B3", "M4", "B5", "M6"); | |||
} | |||
@Test | |||
public void testInterleaved2() { | |||
SortedMap<Long, String> base = new TreeMap<>(); | |||
base.put(1L, "B1"); | |||
base.put(2L, "B2"); | |||
base.put(5L, "B5"); | |||
base.put(6L, "B6"); | |||
SortedMap<Long, String> master = new TreeMap<>(); | |||
master.put(3L, "M3"); | |||
master.put(4L, "M4"); | |||
master.put(7L, "M7"); | |||
master.put(8L, "M8"); | |||
testIteration(new CombinedIterable<>(base, master), | |||
"B1", "B2", "M3", "M4", "B5", "B6", "M7", "M8"); | |||
} | |||
@Test | |||
public void testAllMatching() { | |||
SortedMap<Long, String> base = new TreeMap<>(); | |||
base.put(1L, "B1"); | |||
base.put(2L, "B2"); | |||
base.put(3L, "B3"); | |||
SortedMap<Long, String> master = new TreeMap<>(); | |||
master.put(1L, "M1"); | |||
master.put(2L, "M2"); | |||
master.put(3L, "M3"); | |||
testIteration(new CombinedIterable<>(base, master), | |||
"B1", "B2", "B3"); | |||
} | |||
@Test | |||
public void testAllMatching2() { | |||
SortedMap<Long, String> base = new TreeMap<>(); | |||
base.put(1L, "B1"); | |||
base.put(2L, "B2"); | |||
base.put(3L, "B3"); | |||
SortedMap<Long, String> master = new TreeMap<>(); | |||
master.put(1L, "M1"); | |||
master.put(2L, "M2"); | |||
master.put(3L, "M3"); | |||
master.put(4L, "M4"); | |||
testIteration(new CombinedIterable<>(base, master), | |||
"B1", "B2", "B3", "M4"); | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
#!/bin/bash -e | |||
# | |||
# Licensed to the Apache Software Foundation (ASF) under one or more | |||
# contributor license agreements. See the NOTICE file distributed with | |||
# this work for additional information regarding copyright ownership. | |||
# The ASF licenses this file to You under the Apache License, Version 2.0 | |||
# (the "License"); you may not use this file except in compliance with | |||
# the License. You may obtain a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, | |||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
# See the License for the specific language governing permissions and | |||
# limitations under the License. | |||
# basename it | |||
FILENAME="$1" | |||
BASENAME="${FILENAME##*/}" | |||
OUTDIR="${BASENAME%.*}" | |||
if [ ! -f "$FILENAME" ]; then | |||
echo "File $FILENAME does not exist" | |||
exit 1 | |||
fi | |||
# if dir exists, fail | |||
if [ -d "$OUTDIR" ]; then | |||
echo "Directory '$OUTDIR' already exists!" | |||
exit 1 | |||
fi | |||
mkdir "$OUTDIR" | |||
unzip -d "$OUTDIR" "$FILENAME" | |||
pushd "$OUTDIR" | |||
find . -type f \( -iname "*.xml" -or -iname "*.rels" \) -exec python -c "import os, sys, xml.dom.minidom | |||
with open('{}', 'r') as fp: | |||
s = fp.read() | |||
with open('{}.bak', 'w') as fp: | |||
fp.write(xml.dom.minidom.parseString(s).toprettyxml().encode('utf-8')) | |||
os.rename('{}.bak', '{}')" \; |