<changes>
<release version="3.8-beta5" date="2011-??-??">
+ <action dev="poi-developers" type="add">52268 - support cloning sheets with drawings in XSSF </action>
<action dev="poi-developers" type="add">52285 - Support XWPF smart tags text in Paragraphs</action>
<action dev="poi-developers" type="fix">51875 - More XSSF new-line in formula support</action>
<action dev="poi-developers" type="add">POIFS EntryUtils.copyNodes(POFS,POIFS) now uses FilteringDirectoryNode, so can exclude from copying nodes not just directly under the root</action>
import org.apache.poi.util.Internal;
import org.apache.poi.xssf.model.CommentsTable;
import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
-import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTConnector;
-import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;
-import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTGraphicalObjectFrame;
-import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTGroupShape;
-import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTPicture;
-import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;
-import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;
-import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.STEditAs;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.*;
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
/**
* Root element of the SpreadsheetML Drawing part
*/
private CTDrawing drawing;
- private boolean isNew;
private long numOfGraphicFrames = 0L;
protected static final String NAMESPACE_A = "http://schemas.openxmlformats.org/drawingml/2006/main";
protected XSSFDrawing() {
super();
drawing = newDrawing();
- isNew = true;
}
/**
*/
protected XSSFDrawing(PackagePart part, PackageRelationship rel) throws IOException, XmlException {
super(part, rel);
- drawing = CTDrawing.Factory.parse(part.getInputStream());
- isNew = false;
+ XmlOptions options = new XmlOptions(DEFAULT_XML_OPTIONS);
+ //Removing root element
+ options.setLoadReplaceDocumentElement(null);
+ drawing = CTDrawing.Factory.parse(part.getInputStream(),options);
}
/**
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing">
*/
- if(isNew) {
- // Have it wrapped in a <xdr:wsDr> tag
- xmlOptions.setSaveSyntheticDocumentElement(
- new QName(CTDrawing.type.getName().getNamespaceURI(), "wsDr", "xdr")
- );
- isNew = false;
- }
+ xmlOptions.setSaveSyntheticDocumentElement(
+ new QName(CTDrawing.type.getName().getNamespaceURI(), "wsDr", "xdr")
+ );
Map<String, String> map = new HashMap<String, String>();
map.put(NAMESPACE_A, "a");
map.put(STRelationshipId.type.getName().getNamespaceURI(), "r");
private long newShapeId(){
return drawing.sizeOfTwoCellAnchorArray() + 1;
}
+
+ /**
+ *
+ * @return list of shapes in this drawing
+ */
+ public List<XSSFShape> getShapes(){
+ List<XSSFShape> lst = new ArrayList<XSSFShape>();
+ for(XmlObject obj : drawing.selectPath("./*/*")) {
+ if(obj instanceof CTPicture) lst.add(new XSSFPicture(this, (CTPicture)obj)) ;
+ else if(obj instanceof CTConnector) lst.add(new XSSFConnector(this, (CTConnector)obj)) ;
+ else if(obj instanceof CTShape) lst.add(new XSSFSimpleShape(this, (CTShape)obj)) ;
+ else if(obj instanceof CTGraphicalObjectFrame) lst.add(new XSSFGraphicFrame(this, (CTGraphicalObjectFrame)obj)) ;
+ else if(obj instanceof CTGroupShape) lst.add(new XSSFShapeGroup(this, (CTGroupShape)obj)) ;
+ }
+ return lst;
+ }
}
import org.apache.poi.util.Internal;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlCursor;
+import org.openxmlformats.schemas.drawingml.x2006.main.*;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTGraphicalObjectFrame;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTGraphicalObjectFrameNonVisual;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
/**
*
* @author Roman Kashitsyn
*/
-public final class XSSFGraphicFrame {
+public final class XSSFGraphicFrame extends XSSFShape {
private static CTGraphicalObjectFrame prototype = null;
data.setUri(c_namespaceUri);
}
+ @Override
+ protected CTShapeProperties getShapeProperties(){
+ return null;
+ }
}
throw new POIXMLException("Failed to clone sheet", e);
}
CTWorksheet ct = clonedSheet.getCTWorksheet();
- if(ct.isSetDrawing()) {
- logger.log(POILogger.WARN, "Cloning sheets with drawings is not yet supported.");
- ct.unsetDrawing();
- }
if(ct.isSetLegacyDrawing()) {
logger.log(POILogger.WARN, "Cloning sheets with comments is not yet supported.");
ct.unsetLegacyDrawing();
}
+ if (ct.isSetPageSetup()) {
+ logger.log(POILogger.WARN, "Cloning sheets with page setup is not yet supported.");
+ ct.unsetPageSetup();
+ }
clonedSheet.setSelected(false);
// copy sheet's relations
List<POIXMLDocumentPart> rels = srcSheet.getRelations();
+ // if the sheet being cloned has a drawing then rememebr it and re-create tpoo
+ XSSFDrawing dg = null;
for(POIXMLDocumentPart r : rels) {
+ // do not copy the drawing relationship, it will be re-created
+ if(r instanceof XSSFDrawing) {
+ dg = (XSSFDrawing)r;
+ continue;
+ }
+
PackageRelationship rel = r.getPackageRelationship();
- clonedSheet.getPackagePart().addRelationship(rel.getTargetURI(), rel.getTargetMode(),rel.getRelationshipType());
+ clonedSheet.getPackagePart().addRelationship(
+ rel.getTargetURI(), rel.getTargetMode(),rel.getRelationshipType());
clonedSheet.addRelation(rel.getId(), r);
}
+ // clone the sheet drawing alongs with its relationships
+ if (dg != null) {
+ if(ct.isSetDrawing()) {
+ // unset the existing reference to the drawing,
+ // so that subsequent call of clonedSheet.createDrawingPatriarch() will create a new one
+ ct.unsetDrawing();
+ }
+ XSSFDrawing clonedDg = clonedSheet.createDrawingPatriarch();
+ // copy drawing contents
+ clonedDg.getCTDrawing().set(dg.getCTDrawing());
+
+ // Clone drawing relations
+ List<POIXMLDocumentPart> srcRels = srcSheet.createDrawingPatriarch().getRelations();
+ for (POIXMLDocumentPart rel : srcRels) {
+ PackageRelationship relation = rel.getPackageRelationship();
+ clonedSheet
+ .createDrawingPatriarch()
+ .getPackagePart()
+ .addRelationship(relation.getTargetURI(), relation.getTargetMode(),
+ relation.getRelationshipType(), relation.getId());
+ }
+ }
return clonedSheet;
}
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.apache.poi.xssf.dev.XSSFDump;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;
/**
//there should be a relation to this drawing in the worksheet
assertTrue(sheet.getCTWorksheet().isSetDrawing());
assertEquals(drawingId, sheet.getCTWorksheet().getDrawing().getId());
+
+ List<XSSFShape> shapes = drawing.getShapes();
+ assertEquals(6, shapes.size());
+
+ assertTrue(shapes.get(0) instanceof XSSFPicture);
+ assertTrue(shapes.get(1) instanceof XSSFPicture);
+ assertTrue(shapes.get(2) instanceof XSSFPicture);
+ assertTrue(shapes.get(3) instanceof XSSFPicture);
+ assertTrue(shapes.get(4) instanceof XSSFSimpleShape);
+ assertTrue(shapes.get(5) instanceof XSSFPicture);
+
}
- public void testNew(){
+ public void testNew() throws Exception {
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet();
//multiple calls of createDrawingPatriarch should return the same instance of XSSFDrawing
assertTrue(sheet.getCTWorksheet().isSetDrawing());
assertEquals(drawingId, sheet.getCTWorksheet().getDrawing().getId());
- XSSFClientAnchor anchor = new XSSFClientAnchor();
-
- XSSFConnector c1= drawing.createConnector(anchor);
+ XSSFConnector c1= drawing.createConnector(new XSSFClientAnchor(0,0,0,0,0,0,2,2));
c1.setLineWidth(2.5);
c1.setLineStyle(1);
- XSSFShapeGroup c2 = drawing.createGroup(anchor);
+ XSSFShapeGroup c2 = drawing.createGroup(new XSSFClientAnchor(0,0,0,0,0,0,5,5));
- XSSFSimpleShape c3 = drawing.createSimpleShape(anchor);
+ XSSFSimpleShape c3 = drawing.createSimpleShape(new XSSFClientAnchor(0,0,0,0,2,2,3,4));
c3.setText(new XSSFRichTextString("Test String"));
c3.setFillColor(128, 128, 128);
- XSSFTextBox c4 = drawing.createTextbox(anchor);
+ XSSFTextBox c4 = drawing.createTextbox(new XSSFClientAnchor(0,0,0,0,4,4,5,6));
XSSFRichTextString rt = new XSSFRichTextString("Test String");
rt.applyFont(0, 5, wb.createFont());
rt.applyFont(5, 6, wb.createFont());
c4.setText(rt);
c4.setNoFill(true);
-
-
+ assertEquals(4, drawing.getCTDrawing().sizeOfTwoCellAnchorArray());
+
+ List<XSSFShape> shapes = drawing.getShapes();
+ assertEquals(4, shapes.size());
+ assertTrue(shapes.get(0) instanceof XSSFConnector);
+ assertTrue(shapes.get(1) instanceof XSSFShapeGroup);
+ assertTrue(shapes.get(2) instanceof XSSFSimpleShape);
+ assertTrue(shapes.get(3) instanceof XSSFSimpleShape); //
+
// Save and re-load it
wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
sheet = wb.getSheetAt(0);
-
+
// Check
dr1 = sheet.createDrawingPatriarch();
CTDrawing ctDrawing = dr1.getCTDrawing();
// Connector, shapes and text boxes are all two cell anchors
assertEquals(0, ctDrawing.sizeOfAbsoluteAnchorArray());
assertEquals(0, ctDrawing.sizeOfOneCellAnchorArray());
- // TODO Fix this!
-// assertEquals(4, ctDrawing.sizeOfTwoCellAnchorArray());
-
+ assertEquals(4, ctDrawing.sizeOfTwoCellAnchorArray());
+
+ shapes = dr1.getShapes();
+ assertEquals(4, shapes.size());
+ assertTrue(shapes.get(0) instanceof XSSFConnector);
+ assertTrue(shapes.get(1) instanceof XSSFShapeGroup);
+ assertTrue(shapes.get(2) instanceof XSSFSimpleShape);
+ assertTrue(shapes.get(3) instanceof XSSFSimpleShape); //
+
// Ensure it got the right namespaces
String xml = ctDrawing.toString();
- assertEquals("<xdr:wsDr", xml.substring(0, 9));
+ assertTrue(xml.contains("xmlns:xdr=\"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing\""));
+ assertTrue(xml.contains("xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\""));
}
public void testMultipleDrawings(){
OPCPackage pkg = wb.getPackage();
assertEquals(3, pkg.getPartsByContentType(XSSFRelation.DRAWINGS.getContentType()).size());
}
+
+ public void testClone() throws Exception{
+ XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithDrawing.xlsx");
+ XSSFSheet sheet1 = wb.getSheetAt(0);
+
+ XSSFSheet sheet2 = wb.cloneSheet(0);
+
+ //the source sheet has one relationship and it is XSSFDrawing
+ List<POIXMLDocumentPart> rels1 = sheet1.getRelations();
+ assertEquals(1, rels1.size());
+ assertTrue(rels1.get(0) instanceof XSSFDrawing);
+
+ List<POIXMLDocumentPart> rels2 = sheet2.getRelations();
+ assertEquals(1, rels2.size());
+ assertTrue(rels2.get(0) instanceof XSSFDrawing);
+
+ XSSFDrawing drawing1 = (XSSFDrawing)rels1.get(0);
+ XSSFDrawing drawing2 = (XSSFDrawing)rels2.get(0);
+ assertNotSame(drawing1, drawing2); // drawing2 is a clone of drawing1
+
+ List<XSSFShape> shapes1 = drawing1.getShapes();
+ List<XSSFShape> shapes2 = drawing2.getShapes();
+ assertEquals(shapes1.size(), shapes2.size());
+
+ for(int i = 0; i < shapes1.size(); i++){
+ XSSFShape sh1 = (XSSFShape)shapes1.get(i);
+ XSSFShape sh2 = (XSSFShape)shapes2.get(i);
+
+ assertTrue(sh1.getClass() == sh2.getClass());
+ assertEquals(sh1.getShapeProperties().toString(), sh2.getShapeProperties().toString());
+ }
+ }
}