]> source.dussan.org Git - poi.git/commitdiff
Change how we do the control and drawing write out, so that XSSFRelation can do much...
authorNick Burch <nick@apache.org>
Wed, 30 Jul 2008 00:29:55 +0000 (00:29 +0000)
committerNick Burch <nick@apache.org>
Wed, 30 Jul 2008 00:29:55 +0000 (00:29 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@680889 13f79535-47bb-0310-9956-ffa450edef68

src/ooxml/java/org/apache/poi/xssf/model/Control.java
src/ooxml/java/org/apache/poi/xssf/model/Drawing.java
src/ooxml/java/org/apache/poi/xssf/model/XSSFChildContainingModel.java
src/ooxml/java/org/apache/poi/xssf/model/XSSFModel.java
src/ooxml/java/org/apache/poi/xssf/model/XSSFWritableModel.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFActiveXData.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPictureData.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java

index 0dc55a63fb7947f3af1ab00891eccfeca87c847b..9f2be120fd5d4c6b50560ca9288bbd4908bab12f 100644 (file)
@@ -9,11 +9,7 @@ import org.apache.poi.xssf.usermodel.XSSFActiveXData;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlOptions;
-import org.openxml4j.exceptions.InvalidFormatException;
 import org.openxml4j.opc.PackagePart;
-import org.openxml4j.opc.PackagePartName;
-import org.openxml4j.opc.PackagingURIHelper;
-import org.openxml4j.opc.TargetMode;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTControl;
 
 /**
@@ -71,6 +67,10 @@ public class Control implements XSSFChildContainingModel {
                };
        }
        
+       public int getNumberOfChildren() {
+               return activexBins.size();
+       }
+       
        /**
         * Generates and adds XSSFActiveXData children
         */
@@ -79,24 +79,16 @@ public class Control implements XSSFChildContainingModel {
                activexBins.add(actX);
        }
 
-       /**
-        * Writes back out our XSSFPictureData children
-        */
-       public void writeChildren(PackagePart modelPart) throws IOException, InvalidFormatException {
-               int binIndex = 1;
-               OutputStream out;
-               
-               for(XSSFActiveXData actX : activexBins) {
-                       PackagePartName binPartName = PackagingURIHelper.createPartName(XSSFWorkbook.ACTIVEX_BINS.getFileName(binIndex));
-                       modelPart.addRelationship(binPartName, TargetMode.INTERNAL, XSSFWorkbook.ACTIVEX_BINS.getRelation(), getOriginalId());
-                       PackagePart imagePart = modelPart.getPackage().createPart(binPartName, XSSFWorkbook.ACTIVEX_BINS.getContentType());                     
-                       out = imagePart.getOutputStream();
-                       actX.writeTo(out);
-                       out.close();
-                       binIndex++;
+       public WritableChild getChildForWriting(int index) {
+               if(index >= activexBins.size()) {
+                       throw new IllegalArgumentException("Can't get child at " + index + " when size is " + getNumberOfChildren());
                }
+               return new WritableChild(
+                               activexBins.get(index),
+                               XSSFWorkbook.ACTIVEX_BINS
+               );
        }
-
+       
        public ArrayList<XSSFActiveXData> getData()     {
                return this.activexBins;
        }
index df4ed853eec97e569d6c03bae3d386e861a30148..6db4fcd92a24b4cb3e63e48b2dc2a967923f6271 100644 (file)
@@ -9,11 +9,7 @@ import org.apache.poi.xssf.usermodel.XSSFPictureData;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlOptions;
-import org.openxml4j.exceptions.InvalidFormatException;
 import org.openxml4j.opc.PackagePart;
-import org.openxml4j.opc.PackagePartName;
-import org.openxml4j.opc.PackagingURIHelper;
-import org.openxml4j.opc.TargetMode;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDrawing;
 
 /**
@@ -73,6 +69,10 @@ public class Drawing implements XSSFChildContainingModel {
                };
        }
        
+       public int getNumberOfChildren() {
+               return pictures.size();
+       }
+       
        /**
         * Generates and adds XSSFActiveXData children
         */
@@ -81,22 +81,14 @@ public class Drawing implements XSSFChildContainingModel {
                pictures.add(pd);
        }
 
-       /**
-        * Writes back out our XSSFPictureData children
-        */
-       public void writeChildren(PackagePart modelPart) throws IOException, InvalidFormatException {
-               int pictureIndex = 1;
-               OutputStream out;
-               
-               for(XSSFPictureData picture : pictures) {
-                       PackagePartName imagePartName = PackagingURIHelper.createPartName(XSSFWorkbook.IMAGES.getFileName(pictureIndex));
-                       modelPart.addRelationship(imagePartName, TargetMode.INTERNAL, XSSFWorkbook.IMAGES.getRelation(), getOriginalId());
-                       PackagePart imagePart = modelPart.getPackage().createPart(imagePartName, XSSFWorkbook.IMAGES.getContentType());                     
-                       out = imagePart.getOutputStream();
-                       picture.writeTo(out);
-                       out.close();
-                       pictureIndex++;
+       public WritableChild getChildForWriting(int index) {
+               if(index >= pictures.size()) {
+                       throw new IllegalArgumentException("Can't get child at " + index + " when size is " + getNumberOfChildren());
                }
+               return new WritableChild(
+                               pictures.get(index),
+                               XSSFWorkbook.IMAGES
+               );
        }
        
        public ArrayList<XSSFPictureData> getPictures()
index d50a8eba05e810d9a18acfbdc8685ce1589fb7e3..888dba4a9112d63fb40818279e634e76d363b7fa 100644 (file)
@@ -18,6 +18,7 @@ package org.apache.poi.xssf.model;
 
 import java.io.IOException;
 
+import org.apache.poi.xssf.usermodel.XSSFWorkbook.XSSFRelation;
 import org.openxml4j.exceptions.InvalidFormatException;
 import org.openxml4j.opc.PackagePart;
 
@@ -41,11 +42,29 @@ public interface XSSFChildContainingModel extends XSSFModel {
         * @param childId the ID of the relationship the child comes from
         */
        public void generateChild(PackagePart childPart, String childRelId);
-       
-       /** 
-        * Writes out any children associated with the {@link XSSFModel},
-        *  along with the required relationship stuff.
-        * @param modelPart The new PackagePart of this model 
+
+       /**
+        * Returns the number of children contained, which
+        *  will need to be written out.
         */
-       public void writeChildren(PackagePart modelPart) throws IOException, InvalidFormatException;
+       public int getNumberOfChildren();
+       /**
+        * Called for each child in turn when writing out, 
+        *  which returns a WritableChild for the child in
+        *  that position. The WritableChild has enough
+        *  information to be able to write it out.  
+        * @param index A zero based index of this child
+        */
+       public WritableChild getChildForWriting(int index); 
+       
+       static class WritableChild {
+               private XSSFWritableModel model;
+               private XSSFRelation relation;
+               public WritableChild(XSSFWritableModel model, XSSFRelation rel) {
+                       this.model = model;
+                       this.relation = rel;
+               }
+               public XSSFWritableModel getModel() { return model; }
+               public XSSFRelation getRelation() { return relation; }
+       }
 }
index 03d08c030f00179ca0da093398c40944c6057881..06e97d4ca376692971681466355223840fe02e58 100644 (file)
@@ -18,7 +18,6 @@ package org.apache.poi.xssf.model;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 
 import org.apache.poi.xssf.usermodel.XSSFWorkbook.XSSFRelation;
 
@@ -29,9 +28,7 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook.XSSFRelation;
  *  (InputStream is), so they can be used with
  *  {@link XSSFRelation}
  */
-public interface XSSFModel {
+public interface XSSFModel extends XSSFWritableModel {
        /** Read from the given InputStream */
        public void readFrom(InputStream is) throws IOException;
-       /** Write to the supplied OutputStream, with default options */
-       public void writeTo(OutputStream out) throws IOException;
 }
diff --git a/src/ooxml/java/org/apache/poi/xssf/model/XSSFWritableModel.java b/src/ooxml/java/org/apache/poi/xssf/model/XSSFWritableModel.java
new file mode 100644 (file)
index 0000000..09f7cdf
--- /dev/null
@@ -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.xssf.model;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.xssf.usermodel.XSSFWorkbook.XSSFRelation;
+
+/**
+ * A very stripped down XSSF models interface,
+ *  which only allows writing out. Normally only
+ *  used with the children of a
+ *  {@link XSSFChildContainingModel}.
+ * Most proper models will go for {@link XSSFModel}
+ *  instead of this one.
+ * {@link XSSFRelation} needs classes to implement
+ *  this, so that it can write them out.
+ */
+public interface XSSFWritableModel {
+       /** Write to the supplied OutputStream, with default options */
+       public void writeTo(OutputStream out) throws IOException;
+}
index 84ef049725b0f072c9024b8695cbc70ba01c4698..5faed67e93ed8608aeb2d0aa4ee2c81e0e7f21fc 100644 (file)
@@ -5,9 +5,10 @@ import java.io.OutputStream;
 
 import org.apache.poi.ss.usermodel.PictureData;
 import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.model.XSSFWritableModel;
 import org.openxml4j.opc.PackagePart;
 
-public class XSSFActiveXData implements PictureData {
+public class XSSFActiveXData implements PictureData, XSSFWritableModel {
 
     private PackagePart packagePart;
     private String originalId;
index eb153ce09dbeb23b73a5f35c13f3356ecfd2f1a2..f7fb5b27ada02ee644c3eadbb0a15bf553ea62ea 100644 (file)
@@ -22,13 +22,14 @@ import java.io.OutputStream;
 
 import org.apache.poi.ss.usermodel.PictureData;
 import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.model.XSSFWritableModel;
 import org.openxml4j.opc.PackagePart;
 
 /**
  * Raw picture data, normally attached to a 
  *  vmlDrawing
  */
-public class XSSFPictureData implements PictureData {
+public class XSSFPictureData implements PictureData, XSSFWritableModel {
     private PackagePart packagePart;
     private String originalId;
 
index cb953dfbe1618d0212f380ee3d567cc95e211e74..9bbdd86d951ee477f54d817aaf7e74d92a43253a 100644 (file)
@@ -53,6 +53,7 @@ import org.apache.poi.xssf.model.SharedStringsTable;
 import org.apache.poi.xssf.model.StylesTable;
 import org.apache.poi.xssf.model.XSSFChildContainingModel;
 import org.apache.poi.xssf.model.XSSFModel;
+import org.apache.poi.xssf.model.XSSFWritableModel;
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlObject;
 import org.apache.xmlbeans.XmlOptions;
@@ -118,7 +119,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                        "application/vnd.openxmlformats-officedocument.vmlDrawing",
                        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",
                        "/xl/drawings/vmlDrawing#.vml",
-                       null
+                       Drawing.class
        );
     public static final XSSFRelation IMAGES = new XSSFRelation(
                "image/x-emf", // TODO
@@ -161,7 +162,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                        "application/vnd.ms-office.activeX+xml",
                        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/control",
                        "/xl/activeX/activeX#.xml",
-                       null
+                       Control.class
        );
        public static final XSSFRelation ACTIVEX_BINS = new XSSFRelation(
                        "application/vnd.ms-office.activeX",
@@ -220,7 +221,8 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
 
                /**
                 * Fetches the InputStream to read the contents, based
-                *  of the specified core part
+                *  of the specified core part, for which we are defined
+                *  as a suitable relationship
                 */
                public InputStream getContents(PackagePart corePart) throws IOException, InvalidFormatException {
             PackageRelationshipCollection prc =
@@ -238,45 +240,81 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                }
                
                /**
-                * Finds all the XSSFModels of this type which are
+                * Loads all the XSSFModels of this type which are
                 *  defined as relationships of the given parent part
                 */
-               public ArrayList<? extends XSSFModel> findAll(PackagePart parentPart) throws Exception {
+               public ArrayList<? extends XSSFModel> loadAll(PackagePart parentPart) throws Exception {
                        ArrayList<XSSFModel> found = new ArrayList<XSSFModel>();
                        for(PackageRelationship rel : parentPart.getRelationshipsByType(REL)) {
                                PackagePart part = getTargetPart(parentPart.getPackage(), rel);
-                               found.add(load(part));
+                               found.add(create(part, rel));
                        }
                        return found;
                }
                
                /**
-                * Load, off the specified core part
+                * Load a single Model, which is defined as a suitable
+                *  relationship from the specified core (parent) 
+                *  package part.
                 */
                public XSSFModel load(PackagePart corePart) throws Exception {
-                       Constructor<? extends XSSFModel> c = CLASS.getConstructor(InputStream.class);
+            PackageRelationshipCollection prc =
+               corePart.getRelationshipsByType(REL);
+            Iterator<PackageRelationship> it = prc.iterator();
+            if(it.hasNext()) {
+                PackageRelationship rel = it.next();
+                PackagePartName relName = PackagingURIHelper.createPartName(rel.getTargetURI());
+                PackagePart part = corePart.getPackage().getPart(relName);
+                return create(part, rel);
+            } else {
+               log.log(POILogger.WARN, "No part " + DEFAULT_NAME + " found");
+               return null;
+            }
+               }
+               
+               /**
+                * Does the actual Model creation
+                */
+               private XSSFModel create(PackagePart thisPart, PackageRelationship rel) throws Exception {
                        XSSFModel model = null;
                        
-                       InputStream inp = getContents(corePart);
+                       Constructor<? extends XSSFModel> c;
+                       boolean withString = false;
+                       
+                       // Find the right constructor 
+                       try {
+                               c = CLASS.getConstructor(InputStream.class, String.class);
+                               withString = true;
+                       } catch(NoSuchMethodException e) {
+                               c = CLASS.getConstructor(InputStream.class);
+                       }
+                       
+                       // Instantiate, if we can
+                       InputStream inp = thisPart.getInputStream();
                        if(inp != null) {
                 try {
-                       model = c.newInstance(inp);
+                       if(withString) {
+                               model = c.newInstance(inp, rel.getId());
+                       } else {
+                               model = c.newInstance(inp);
+                       }
                 } finally {
                        inp.close();
                 }
+                
+                       // Do children, if required
+                       if(model instanceof XSSFChildContainingModel) {
+                               XSSFChildContainingModel ccm = 
+                                       (XSSFChildContainingModel)model;
+                               for(String relType : ccm.getChildrenRelationshipTypes()) {
+                                       for(PackageRelationship cRel : thisPart.getRelationshipsByType(relType)) {
+                                               PackagePart childPart = getTargetPart(thisPart.getPackage(), cRel);
+                                               ccm.generateChild(childPart, cRel.getId());
+                                       }
+                               }
+                       }
             }
                        
-                       // Do children, if required
-                       if(model instanceof XSSFChildContainingModel) {
-                               XSSFChildContainingModel ccm = 
-                                       (XSSFChildContainingModel)model;
-                               for(String relType : ccm.getChildrenRelationshipTypes()) {
-                                       for(PackageRelationship rel : corePart.getRelationshipsByType(relType)) {
-                                               PackagePart childPart = getTargetPart(corePart.getPackage(), rel);
-                                               ccm.generateChild(childPart, rel.getId());
-                                       }
-                               }
-                       }
                        
             return model;
                }
@@ -285,19 +323,26 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                 * Save, with the default name
                 * @return The internal reference ID it was saved at, normally then used as an r:id
                 */
-               private String save(XSSFModel model, PackagePart corePart) throws IOException {
+               private String save(XSSFWritableModel model, PackagePart corePart) throws IOException {
                        return save(model, corePart, DEFAULT_NAME);
                }
+               /**
+                * Save, with the name generated by the given index
+                * @return The internal reference ID it was saved at, normally then used as an r:id
+                */
+               private String save(XSSFWritableModel model, PackagePart corePart, int index) throws IOException {
+                       return save(model, corePart, getFileName(index));
+               }
                /**
                 * Save, with the specified name
                 * @return The internal reference ID it was saved at, normally then used as an r:id
                 */
-               private String save(XSSFModel model, PackagePart corePart, String name) throws IOException {
+               private String save(XSSFWritableModel model, PackagePart corePart, String name) throws IOException {
             PackagePartName ppName = null;
             try {
                ppName = PackagingURIHelper.createPartName(name);
             } catch(InvalidFormatException e) {
-               throw new IllegalStateException(e);
+               throw new IllegalStateException("Can't create part with name " + name + " for " + model, e);
             }
             PackageRelationship rel =
                corePart.addRelationship(ppName, TargetMode.INTERNAL, REL);
@@ -307,6 +352,23 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
             model.writeTo(out);
             out.close();
             
+                       // Do children, if required
+                       if(model instanceof XSSFChildContainingModel) {
+                               XSSFChildContainingModel ccm = 
+                                       (XSSFChildContainingModel)model;
+                               // Loop over each child, writing it out
+                               int numChildren = ccm.getNumberOfChildren();
+                               for(int i=0; i<numChildren; i++) {
+                                       XSSFChildContainingModel.WritableChild child =
+                                               ccm.getChildForWriting(i);
+                                       child.getRelation().save(
+                                                       child.getModel(),
+                                                       part, 
+                                                       (i+1)
+                                       );
+                               }
+                       }
+            
             return rel.getId();
                }
        }
@@ -382,15 +444,15 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                 ArrayList<Control> controls;
                 try {
                        // Get the comments for the sheet, if there are any
-                       childModels = SHEET_COMMENTS.findAll(part);
+                       childModels = SHEET_COMMENTS.loadAll(part);
                        if(childModels.size() > 0) {
                                comments = (CommentsSource)childModels.get(0);
                        }
                        
                        // Get the drawings for the sheet, if there are any
-                       drawings = (ArrayList<Drawing>)VML_DRAWINGS.findAll(part);
+                       drawings = (ArrayList<Drawing>)VML_DRAWINGS.loadAll(part);
                        // Get the activeX controls for the sheet, if there are any
-                       controls = (ArrayList<Control>)ACTIVEX_CONTROLS.findAll(part);
+                       controls = (ArrayList<Control>)ACTIVEX_CONTROLS.loadAll(part);
                 } catch(Exception e) {
                        throw new RuntimeException("Unable to construct child part",e);
                 }
@@ -890,29 +952,18 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                 // If our sheet has comments, then write out those
                 if(sheet.hasComments()) {
                        CommentsTable ct = (CommentsTable)sheet.getCommentsSourceIfExists();
-                    PackagePartName ctName = PackagingURIHelper.createPartName(
-                               SHEET_COMMENTS.getFileName(sheetNumber));
-                    part.addRelationship(ctName, TargetMode.INTERNAL, SHEET_COMMENTS.getRelation(), "rComments");
-                    PackagePart ctPart = pkg.createPart(ctName, SHEET_COMMENTS.getContentType());
-                    
-                    out = ctPart.getOutputStream();
-                    ct.writeTo(out);
-                    out.close();
+                       SHEET_COMMENTS.save(ct, part, sheetNumber);
                 }
                 
                 // If our sheet has drawings, then write out those
                 if(sheet.getDrawings() != null) {
                        int drawingIndex = 1;
                        for(Drawing drawing : sheet.getDrawings()) {
-                        PackagePartName drName = PackagingURIHelper.createPartName(
-                                       VML_DRAWINGS.getFileName(drawingIndex));
-                        part.addRelationship(drName, TargetMode.INTERNAL, VML_DRAWINGS.getRelation(), drawing.getOriginalId());
-                        PackagePart drPart = pkg.createPart(drName, VML_DRAWINGS.getContentType());
-                        
-                        drawing.writeChildren(drPart);
-                        out = drPart.getOutputStream();
-                        drawing.writeTo(out);
-                        out.close();
+                               VML_DRAWINGS.save(
+                                               drawing,
+                                               part,
+                                               drawingIndex
+                               );
                                drawingIndex++;
                        }
                 }
@@ -921,15 +972,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                 if(sheet.getControls() != null) {
                        int controlIndex = 1;
                        for(Control control : sheet.getControls()) {
-                        PackagePartName crName = PackagingURIHelper.createPartName(
-                                       ACTIVEX_CONTROLS.getFileName(controlIndex));
-                        part.addRelationship(crName, TargetMode.INTERNAL, ACTIVEX_CONTROLS.getRelation(), control.getOriginalId());
-                        PackagePart crPart = pkg.createPart(crName, ACTIVEX_CONTROLS.getContentType());
-                        
-                        control.writeChildren(crPart);
-                        out = crPart.getOutputStream();
-                        control.writeTo(out);
-                        out.close();
+                               ACTIVEX_CONTROLS.save(
+                                               control,
+                                               part,
+                                               controlIndex
+                               );
                                controlIndex++;
                        }
                 }
index 9eb0da6b4a1274593f5665eda459edcd0a29ee6f..570cc077b4170684332653fb20e5e978d50657e8 100644 (file)
@@ -128,10 +128,6 @@ public class TestXSSFBugs extends TestCase {
                );
                assertNotNull(drw);
                
-               FileOutputStream fout = new FileOutputStream("/tmp/foo.xlsm");
-               nwb.write(fout);
-               fout.close();
-               
                // For testing with excel
 //             FileOutputStream fout = new FileOutputStream("/tmp/foo.xlsm");
 //             nwb.write(fout);