]> source.dussan.org Git - poi.git/commitdiff
Bugzilla 52268 - support cloning sheets with drawings in XSSF
authorYegor Kozlov <yegor@apache.org>
Wed, 7 Dec 2011 08:49:09 +0000 (08:49 +0000)
committerYegor Kozlov <yegor@apache.org>
Wed, 7 Dec 2011 08:49:09 +0000 (08:49 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1211339 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/status.xml
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFGraphicFrame.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java

index 12a3c9a4e7453afa190d42747658010ce631b1d4..f90dec6012f9df734c17d32ef64925e507bb453b 100644 (file)
@@ -34,6 +34,7 @@
 
     <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>
index 0c13db8ffcb9e264ca3fc08b42a37061cc58f8af..72794b6eff9756ea0cac8ff1563de0aae8bff8f6 100644 (file)
@@ -36,15 +36,10 @@ import org.apache.poi.ss.usermodel.Drawing;
 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;
 
 /**
@@ -57,7 +52,6 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing {
      * 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";
@@ -71,7 +65,6 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing {
     protected XSSFDrawing() {
         super();
         drawing = newDrawing();
-        isNew = true;
     }
 
     /**
@@ -84,8 +77,10 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing {
      */
     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);
     }
 
     /**
@@ -117,13 +112,9 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing {
                 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");
@@ -372,4 +363,20 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing {
     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;
+    }
 }
index 3abc774f862e9301e3f67d33135e97d2b04ddcb4..d22802ab2ab5a9cfa51ef158eb717b03063fb3b0 100644 (file)
@@ -25,14 +25,9 @@ import org.apache.poi.openxml4j.opc.PackageRelationship;
 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;
 
 /**
@@ -40,7 +35,7 @@ import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelations
  *
  * @author Roman Kashitsyn
  */
-public final class XSSFGraphicFrame {
+public final class XSSFGraphicFrame extends XSSFShape {
 
        private static CTGraphicalObjectFrame prototype = null;
 
@@ -186,4 +181,8 @@ public final class XSSFGraphicFrame {
                data.setUri(c_namespaceUri);
        }
 
+    @Override
+    protected CTShapeProperties getShapeProperties(){
+        return null;
+    }
 }
index 80112817870faa34f9b9a3d9d7354faa4168245b..896be63bd06d27ebc8a40d4003f65e3e6a7ea76f 100644 (file)
@@ -375,25 +375,56 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
             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;
     }
 
index 2ce1bf2793a6266d914cbc18c4d51b25ec8f94dc..ced478e3ea64776e7aa9dd14af956c09c6e3688b 100644 (file)
@@ -23,6 +23,7 @@ import junit.framework.TestCase;
 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;
 
 /**
@@ -45,9 +46,20 @@ public class TestXSSFDrawing extends TestCase {
         //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
@@ -66,31 +78,36 @@ public class TestXSSFDrawing extends TestCase {
         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();
@@ -98,12 +115,19 @@ public class TestXSSFDrawing extends TestCase {
         // 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(){
@@ -115,4 +139,36 @@ public class TestXSSFDrawing extends TestCase {
         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());
+        }
+    }
 }