]> source.dussan.org Git - poi.git/commitdiff
refactored POIXMLDocument to be a composite of POIXMLDocumentPart, this way XSSFWorkb...
authorYegor Kozlov <yegor@apache.org>
Tue, 30 Sep 2008 13:57:36 +0000 (13:57 +0000)
committerYegor Kozlov <yegor@apache.org>
Tue, 30 Sep 2008 13:57:36 +0000 (13:57 +0000)
Also, performed major cleanup of core XSSF classes and test cases

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@700472 13f79535-47bb-0310-9956-ffa450edef68

26 files changed:
src/examples/src/org/apache/poi/xssf/usermodel/examples/CreateNewSpreadsheet.java
src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Workbook.java
src/ooxml/java/org/apache/poi/POIXMLDocument.java
src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/POIXMLException.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/POIXMLFactory.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/POIXMLRelation.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/util/PackageHelper.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/xssf/dev/XSSFDump.java
src/ooxml/java/org/apache/poi/xssf/dev/XSSFSave.java
src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java
src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java
src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCreationHelper.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFactory.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
src/ooxml/java/org/apache/poi/xssf/usermodel/extensions/XSSFCellBorder.java
src/ooxml/testcases/org/apache/poi/xssf/XSSFTestDataSamples.java
src/ooxml/testcases/org/apache/poi/xssf/model/TestCommentsTable.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFComment.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFHyperlink.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java

index e60c342287b6b12ecd8c9c5e853c4560aaca4404..b1b815ec6b2101624451716259e34da31d0972e1 100644 (file)
@@ -29,7 +29,7 @@ public class CreateNewSpreadsheet {
                CreationHelper createHelper = wb.getCreationHelper();
                
                XSSFSheet s1 = wb.createSheet("Sheet One");
-               XSSFSheet s2 = wb.createSheet("Sheet One");
+               XSSFSheet s2 = wb.createSheet("Sheet Two");
                
                // Create a few cells
                s1.createRow(0);
index f4defbae65347aebcbbaba20fe0b4884ebd3f855..2ed1c3c7b1b24bafc32d70003226b364bcadbe8a 100644 (file)
@@ -376,9 +376,6 @@ public interface Workbook {
 
     Palette getCustomPalette();
 
-    /** Test only. Do not use */
-    void insertChartRecord();
-
     /**
      * Adds a picture to the workbook.
      *
@@ -392,7 +389,7 @@ public interface Workbook {
     /**
      * Gets all pictures from the Workbook.
      *
-     * @return the list of pictures (a list of {@link HSSFPictureData} objects.)
+     * @return the list of pictures (a list of {@link PictureData} objects.)
      */
     List getAllPictures();
 
index c268dd4c8c1faffaf1da944daeda7c7db4cffdde..74be9909ca86f35caf6392fce86111fbe8629a5f 100644 (file)
 ==================================================================== */
 package org.apache.poi;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PushbackInputStream;
+import java.io.*;
 import java.util.LinkedList;
 import java.util.List;
 
 import org.apache.poi.poifs.common.POIFSConstants;
 import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.PackageHelper;
 import org.apache.xmlbeans.XmlException;
 import org.openxml4j.exceptions.InvalidFormatException;
 import org.openxml4j.exceptions.OpenXML4JException;
+import org.openxml4j.opc.*;
 import org.openxml4j.opc.Package;
-import org.openxml4j.opc.PackagePart;
-import org.openxml4j.opc.PackagePartName;
-import org.openxml4j.opc.PackageRelationship;
-import org.openxml4j.opc.PackageRelationshipCollection;
-import org.openxml4j.opc.PackageRelationshipTypes;
-import org.openxml4j.opc.PackagingURIHelper;
 
-public abstract class POIXMLDocument {
+public class POIXMLDocument extends POIXMLDocumentPart{
 
     public static final String CORE_PROPERTIES_REL_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
     public static final String EXTENDED_PROPERTIES_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
     public static final String CUSTOM_PROPERTIES_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties";
-    
+
     // OLE embeddings relation name
     public static final String OLE_OBJECT_REL_TYPE="http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
-    
+
     // Embedded OPC documents relation name
     public static final String PACK_OBJECT_REL_TYPE="http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
-    
+
     /** The OPC Package */
     private Package pkg;
 
     /** The OPC core Package Part */
     private PackagePart corePart;
-    
+
     /**
      * The properties of the OPC package, opened as needed
      */
     private POIXMLProperties properties;
-    
-       /**
-        * The embedded OLE2 files in the OPC package
-        */
-    protected List<PackagePart> embedds = new LinkedList<PackagePart>();
-    
-    protected POIXMLDocument() {}
-    
+
+    /**
+     * The embedded OLE2 files in the OPC package
+     */
+    protected List<PackagePart> embedds;
+
+    protected POIXMLDocument() {
+        super(null, null);
+        embedds = new LinkedList<PackagePart>();
+    }
+
     protected POIXMLDocument(Package pkg) throws IOException {
-       try {
-               this.pkg = pkg;
-               
-               PackageRelationship coreDocRelationship = this.pkg.getRelationshipsByType(
-                       PackageRelationshipTypes.CORE_DOCUMENT).getRelationship(0);
-           
-               // Get core part
-               this.corePart = this.pkg.getPart(coreDocRelationship);
-
-               // Verify it's there
-               if(corePart == null) {
-                       throw new IllegalArgumentException("No core part found for this document! Nothing with " + coreDocRelationship.getRelationshipType() + " present as a relation.");
-               }
-        } catch (OpenXML4JException e) {
-            throw new IOException(e.toString());
-       }
+        this();
+        initialize(pkg);
     }
-    
+
     protected POIXMLDocument(String path) throws IOException {
-               this(openPackage(path));
+           this(openPackage(path));
     }
-    
+
     /**
      * Wrapper to open a package, returning an IOException
      *  in the event of a problem.
@@ -100,25 +83,37 @@ public abstract class POIXMLDocument {
             throw new IOException(e.toString());
         }
     }
-    public static Package openPackage(InputStream is) throws IOException {
+
+    protected void initialize(Package pkg) throws IOException {
         try {
-            return Package.open(is);
-        } catch (InvalidFormatException e) {
+            this.pkg = pkg;
+
+            PackageRelationship coreDocRelationship = this.pkg.getRelationshipsByType(
+                    PackageRelationshipTypes.CORE_DOCUMENT).getRelationship(0);
+
+            // Get core part
+            this.corePart = super.packagePart = this.pkg.getPart(coreDocRelationship);
+
+            // Verify it's there
+            if(corePart == null) {
+                throw new IllegalArgumentException("No core part found for this document! Nothing with " + coreDocRelationship.getRelationshipType() + " present as a relation.");
+            }
+        } catch (OpenXML4JException e) {
             throw new IOException(e.toString());
         }
     }
 
-    protected Package getPackage() {
+    public Package getPackage() {
         return this.pkg;
     }
-    
+
     protected PackagePart getCorePart() {
         return this.corePart;
     }
 
     /**
      * Get the PackagePart that is the target of a relationship.
-     * 
+     *
      * @param rel The relationship
      * @return The target part
      * @throws InvalidFormatException
@@ -128,7 +123,7 @@ public abstract class POIXMLDocument {
     }
     /**
      * Get the PackagePart that is the target of a relationship.
-     * 
+     *
      * @param rel The relationship
      * @param pkg The package to fetch from
      * @return The target part
@@ -143,90 +138,90 @@ public abstract class POIXMLDocument {
         return part;
     }
 
-       /**
-        * Fetches the (single) PackagePart which is defined as
-        *  the supplied relation content type of the base
-        *  package/container, or null if none found.
-        * @param relationType The relation content type to search for
-        * @throws IllegalArgumentException If we find more than one part of that type
-        */
-       protected PackagePart getSinglePartByRelationType(String relationType) throws IllegalArgumentException, OpenXML4JException {
-               PackageRelationshipCollection rels =
-                       pkg.getRelationshipsByType(relationType);
-               if(rels.size() == 0) {
-                       return null;
-               }
-               if(rels.size() > 1) {
-                       throw new IllegalArgumentException("Found " + rels.size() + " relations for the type " + relationType + ", should only ever be one!");
-               }
-               PackageRelationship rel = rels.getRelationship(0);
-               return getTargetPart(rel);
-       }
-
-       /**
-        * Retrieves all the PackageParts which are defined as
-        *  relationships of the base document with the
-        *  specified content type.
-        */
-       protected PackagePart[] getRelatedByType(String contentType) throws InvalidFormatException {
-               PackageRelationshipCollection partsC =
-                       getCorePart().getRelationshipsByType(contentType);
-               
-               PackagePart[] parts = new PackagePart[partsC.size()];
-               int count = 0;
-               for (PackageRelationship rel : partsC) {
-                       parts[count] = getTargetPart(rel);
-                       count++;
-               }
-               return parts;
-       }
-
-       
-    
+    /**
+     * Fetches the (single) PackagePart which is defined as
+     *  the supplied relation content type of the base
+     *  package/container, or null if none found.
+     * @param relationType The relation content type to search for
+     * @throws IllegalArgumentException If we find more than one part of that type
+     */
+    protected PackagePart getSinglePartByRelationType(String relationType) throws IllegalArgumentException, OpenXML4JException {
+        PackageRelationshipCollection rels =
+            pkg.getRelationshipsByType(relationType);
+        if(rels.size() == 0) {
+            return null;
+        }
+        if(rels.size() > 1) {
+            throw new IllegalArgumentException("Found " + rels.size() + " relations for the type " + relationType + ", should only ever be one!");
+        }
+        PackageRelationship rel = rels.getRelationship(0);
+        return getTargetPart(rel);
+    }
+
+    /**
+     * Retrieves all the PackageParts which are defined as
+     *  relationships of the base document with the
+     *  specified content type.
+     */
+    protected PackagePart[] getRelatedByType(String contentType) throws InvalidFormatException {
+        PackageRelationshipCollection partsC =
+            getCorePart().getRelationshipsByType(contentType);
+
+        PackagePart[] parts = new PackagePart[partsC.size()];
+        int count = 0;
+        for (PackageRelationship rel : partsC) {
+            parts[count] = getTargetPart(rel);
+            count++;
+        }
+        return parts;
+    }
+
+
+
     /**
      * Checks that the supplied InputStream (which MUST
-     *  support mark and reset, or be a PushbackInputStream) 
+     *  support mark and reset, or be a PushbackInputStream)
      *  has a OOXML (zip) header at the start of it.
      * If your InputStream does not support mark / reset,
      *  then wrap it in a PushBackInputStream, then be
      *  sure to always use that, and not the original!
-     * @param inp An InputStream which supports either mark/reset, or is a PushbackInputStream 
+     * @param inp An InputStream which supports either mark/reset, or is a PushbackInputStream
      */
     public static boolean hasOOXMLHeader(InputStream inp) throws IOException {
-       // We want to peek at the first 4 bytes 
-       inp.mark(4);
+        // We want to peek at the first 4 bytes
+        inp.mark(4);
 
-       byte[] header = new byte[4];
-       IOUtils.readFully(inp, header);
+        byte[] header = new byte[4];
+        IOUtils.readFully(inp, header);
 
         // Wind back those 4 bytes
         if(inp instanceof PushbackInputStream) {
-               PushbackInputStream pin = (PushbackInputStream)inp;
-               pin.unread(header);
+            PushbackInputStream pin = (PushbackInputStream)inp;
+            pin.unread(header);
         } else {
-               inp.reset();
+            inp.reset();
         }
-       
-       // Did it match the ooxml zip signature?
+
+        // Did it match the ooxml zip signature?
         return (
-               header[0] == POIFSConstants.OOXML_FILE_HEADER[0] && 
-               header[1] == POIFSConstants.OOXML_FILE_HEADER[1] && 
-               header[2] == POIFSConstants.OOXML_FILE_HEADER[2] && 
-               header[3] == POIFSConstants.OOXML_FILE_HEADER[3]
-        );                                                         
+            header[0] == POIFSConstants.OOXML_FILE_HEADER[0] &&
+            header[1] == POIFSConstants.OOXML_FILE_HEADER[1] &&
+            header[2] == POIFSConstants.OOXML_FILE_HEADER[2] &&
+            header[3] == POIFSConstants.OOXML_FILE_HEADER[3]
+        );
+    }
+
+    /**
+     * Get the document properties. This gives you access to the
+     *  core ooxml properties, and the extended ooxml properties.
+     */
+    public POIXMLProperties getProperties() throws OpenXML4JException, IOException, XmlException {
+        if(properties == null) {
+            properties = new POIXMLProperties(pkg);
+        }
+        return properties;
     }
 
-       /**
-        * Get the document properties. This gives you access to the
-        *  core ooxml properties, and the extended ooxml properties.
-        */
-       public POIXMLProperties getProperties() throws OpenXML4JException, IOException, XmlException {
-               if(properties == null) {
-                       properties = new POIXMLProperties(pkg);
-               }
-               return properties;
-       }
-       
     /**
      * Get the document's embedded files.
      */
diff --git a/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java b/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java
new file mode 100755 (executable)
index 0000000..ed3e59f
--- /dev/null
@@ -0,0 +1,203 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi;\r
+\r
+import java.io.IOException;\r
+import java.util.LinkedList;\r
+import java.util.List;\r
+\r
+import org.apache.xmlbeans.XmlOptions;\r
+import org.apache.poi.util.POILogger;\r
+import org.apache.poi.util.POILogFactory;\r
+import org.openxml4j.exceptions.OpenXML4JException;\r
+import org.openxml4j.opc.*;\r
+\r
+/**\r
+ * Represents an entry of a OOXML package.\r
+ *\r
+ * <p>\r
+ * Each POIXMLDocumentPart keeps a reference to the underlying a {@link org.openxml4j.opc.PackagePart}.\r
+ * </p>\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class POIXMLDocumentPart {\r
+    private static POILogger logger = POILogFactory.getLogger(POIXMLDocumentPart.class);\r
+\r
+    public static XmlOptions DEFAULT_XML_OPTIONS;\r
+    static {\r
+        DEFAULT_XML_OPTIONS = new XmlOptions();\r
+        DEFAULT_XML_OPTIONS.setSaveOuter();\r
+        DEFAULT_XML_OPTIONS.setUseDefaultNamespace();\r
+    }\r
+\r
+    protected PackagePart packagePart;\r
+    protected PackageRelationship packageRel;\r
+    protected POIXMLDocumentPart parent;\r
+\r
+    protected List<POIXMLDocumentPart> relations;\r
+\r
+    public POIXMLDocumentPart(PackagePart part, PackageRelationship rel){\r
+        relations = new LinkedList<POIXMLDocumentPart>();\r
+        this.packagePart = part;\r
+        this.packageRel = rel;\r
+    }\r
+\r
+    /**\r
+     * Provides access to the underlying PackagePart\r
+     *\r
+     * @return the underlying PackagePart\r
+     */\r
+    public PackagePart getPackagePart(){\r
+        return packagePart;\r
+    }\r
+\r
+    /**\r
+     * Provides access to the PackageRelationship that identifies this POIXMLDocumentPart\r
+     *\r
+     * @return the PackageRelationship that identifies this POIXMLDocumentPart\r
+     */\r
+    public PackageRelationship getPackageRelationship(){\r
+        return packageRel;\r
+    }\r
+\r
+    /**\r
+     * Returns the list of child relations for this POIXMLDocumentPart\r
+     *\r
+     * @return child relations\r
+     */\r
+    public List<POIXMLDocumentPart> getRelations(){\r
+        return relations;\r
+    }\r
+\r
+    /**\r
+     * Add a new child POIXMLDocumentPart\r
+     *\r
+     * @param part the child to add\r
+     */\r
+    protected void addRelation(POIXMLDocumentPart part){\r
+        relations.add(part);\r
+    }\r
+\r
+    /**\r
+     * Returns the parent POIXMLDocumentPart. All parts except root have not-null parent.\r
+     *\r
+     * @return the parent POIXMLDocumentPart or <code>null</code> for the root element.\r
+     */\r
+    public POIXMLDocumentPart getParent(){\r
+        return parent;\r
+    }\r
+\r
+    @Override\r
+    public String toString(){\r
+        return packagePart.toString();\r
+    }\r
+\r
+    /**\r
+     * Save the content in the underlying package part.\r
+     * Default implemenation is empty meaning that the package part is left unmodified.\r
+     *\r
+     * Sub-classes should override and add logic to marshal the "model" into Ooxml4J.\r
+     *\r
+     * For example, the code saving a generic XML entry may look as follows:\r
+     * <pre><code>\r
+     * protected void commit() throws IOException {\r
+     *   PackagePart part = getPackagePart();\r
+     *   OutputStream out = part.getOutputStream();\r
+     *   XmlObject bean = getXmlBean(); //the "model" which holds changes in memory\r
+     *   bean.save(out, DEFAULT_XML_OPTIONS);\r
+     *   out.close();\r
+     *  </code></pre>\r
+     *\r
+     */\r
+    protected void commit() throws IOException {\r
+\r
+    }\r
+\r
+    /**\r
+     * Save changes in the underlying OOXML package.\r
+     */\r
+    protected void save() throws IOException{\r
+        commit();\r
+        for(POIXMLDocumentPart p : relations){\r
+            p.save();\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Create a new child POIXMLDocumentPart\r
+     *\r
+     * @param descriptor the part descriptor\r
+     * @param cls the Class object identifying the type of instance to create\r
+     * @return the created child POIXMLDocumentPart\r
+     */\r
+    protected POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, Class<? extends POIXMLDocumentPart> cls){\r
+        return createRelationship(descriptor, cls, -1);\r
+    }\r
+\r
+    /**\r
+     * Create a new child POIXMLDocumentPart\r
+     *\r
+     * @param descriptor the part descriptor\r
+     * @param cls the Class object identifying the type of instance to create\r
+     * @param idx part number\r
+     * @return the created child POIXMLDocumentPart\r
+     */\r
+    protected POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, Class<? extends POIXMLDocumentPart> cls, int idx){\r
+        try {\r
+\r
+            PackagePartName ppName = PackagingURIHelper.createPartName(descriptor.getFileName(idx));\r
+            PackageRelationship rel =\r
+                packagePart.addRelationship(ppName, TargetMode.INTERNAL, descriptor.getRelation());\r
+\r
+            PackagePart part = packagePart.getPackage().createPart(ppName, descriptor.getContentType());\r
+            POIXMLDocumentPart doc = cls.newInstance();\r
+            doc.packageRel = rel;\r
+            doc.packagePart = part;\r
+            addRelation(doc);\r
+            return doc;\r
+        } catch (Exception e){\r
+            throw new POIXMLException(e);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Iterate through the underlying PackagePart and create child POIXMLFactory instances\r
+     * using the specified factory\r
+     *\r
+     * @param factory   the factory object that creates POIXMLFactory instances\r
+     */\r
+    protected void read(POIXMLFactory factory) throws OpenXML4JException {\r
+        PackageRelationshipCollection rels = packagePart.getRelationships();\r
+        for (PackageRelationship rel : rels) {\r
+            if(rel.getTargetMode() == TargetMode.INTERNAL){\r
+                PackagePartName relName = PackagingURIHelper.createPartName(rel.getTargetURI());\r
+                PackagePart p = packagePart.getPackage().getPart(relName);\r
+                if(p == null) {\r
+                    logger.log(POILogger.ERROR, "Skipped invalid entry " + rel.getTargetURI());\r
+                    continue;\r
+                }\r
+                POIXMLDocumentPart childPart = factory.create(rel, p);\r
+                childPart.parent = this;\r
+                addRelation(childPart);\r
+\r
+                if(p.hasRelationships()) childPart.read(factory);\r
+            }\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/src/ooxml/java/org/apache/poi/POIXMLException.java b/src/ooxml/java/org/apache/poi/POIXMLException.java
new file mode 100755 (executable)
index 0000000..1a4bf7f
--- /dev/null
@@ -0,0 +1,69 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi;\r
+\r
+/**\r
+ * Indicates a generic OOXML error.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class POIXMLException extends RuntimeException{\r
+    /**\r
+     * Create a new <code>POIXMLException</code> with no\r
+     * detail mesage.\r
+     */\r
+    public POIXMLException() {\r
+           super();\r
+    }\r
+\r
+    /**\r
+     * Create a new <code>POIXMLException</code> with\r
+     * the <code>String</code> specified as an error message.\r
+     *\r
+     * @param msg The error message for the exception.\r
+     */\r
+   public POIXMLException(String msg) {\r
+           super(msg);\r
+    }\r
+\r
+    /**\r
+     * Create a new <code>POIXMLException</code> with\r
+     * the <code>String</code> specified as an error message and the cause.\r
+     *\r
+     * @param msg The error message for the exception.\r
+     * @param  cause the cause (which is saved for later retrieval by the\r
+     *         {@link #getCause()} method).  (A <tt>null</tt> value is\r
+     *         permitted, and indicates that the cause is nonexistent or\r
+     *         unknown.)\r
+     */\r
+    public POIXMLException(String msg, Throwable cause) {\r
+        super(msg, cause);\r
+    }\r
+\r
+    /**\r
+     * Create a new <code>POIXMLException</code> with\r
+     * the specified cause.\r
+     *\r
+     * @param  cause the cause (which is saved for later retrieval by the\r
+     *         {@link #getCause()} method).  (A <tt>null</tt> value is\r
+     *         permitted, and indicates that the cause is nonexistent or\r
+     *         unknown.)\r
+     */\r
+     public POIXMLException(Throwable cause) {\r
+        super(cause);\r
+    }\r
+}\r
diff --git a/src/ooxml/java/org/apache/poi/POIXMLFactory.java b/src/ooxml/java/org/apache/poi/POIXMLFactory.java
new file mode 100755 (executable)
index 0000000..6909cb9
--- /dev/null
@@ -0,0 +1,40 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi;\r
+\r
+import org.openxml4j.opc.PackageRelationship;\r
+import org.openxml4j.opc.PackagePart;\r
+\r
+\r
+/**\r
+ * Defines a factory API that enables sub-classes to create instances of <code>POIXMLDocumentPart</code>\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class POIXMLFactory {\r
+\r
+    /**\r
+     * Creates a new instance of a {@link POIXMLDocumentPart}\r
+     *\r
+     * @param rel   the package part relationship\r
+     * @param part  the PackagePart representing the created instance\r
+     * @return A new instance of a POIXMLDocumentPart.\r
+     */\r
+     public POIXMLDocumentPart create(PackageRelationship rel, PackagePart part){\r
+        return new POIXMLDocumentPart(part, rel);\r
+    }\r
+}\r
diff --git a/src/ooxml/java/org/apache/poi/POIXMLRelation.java b/src/ooxml/java/org/apache/poi/POIXMLRelation.java
new file mode 100755 (executable)
index 0000000..a786c02
--- /dev/null
@@ -0,0 +1,54 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi;\r
+\r
+/**\r
+ * Represents a descriptor of a OOXML relation.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class POIXMLRelation {\r
+\r
+    protected String _type;\r
+    protected String _relation;\r
+    protected String _defaultName;\r
+\r
+    /**\r
+     * Instantiates a POIXMLRelation.\r
+     */\r
+    protected POIXMLRelation(String type, String rel, String defaultName) {\r
+        _type = type;\r
+        _relation = rel;\r
+        _defaultName = defaultName;\r
+    }\r
+\r
+    public String getContentType() { return _type; }\r
+    public String getRelation() { return _relation; }\r
+    public String getDefaultFileName() { return _defaultName; }\r
+\r
+    /**\r
+     * Returns the filename for the nth one of these,\r
+     *  eg /xl/comments4.xml\r
+     */\r
+    public String getFileName(int index) {\r
+        if(_defaultName.indexOf("#") == -1) {\r
+            // Generic filename in all cases\r
+            return getDefaultFileName();\r
+        }\r
+        return _defaultName.replace("#", Integer.toString(index));\r
+    }\r
+}\r
diff --git a/src/ooxml/java/org/apache/poi/util/PackageHelper.java b/src/ooxml/java/org/apache/poi/util/PackageHelper.java
new file mode 100755 (executable)
index 0000000..4471a60
--- /dev/null
@@ -0,0 +1,150 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.util;\r
+\r
+import org.openxml4j.opc.*;\r
+import org.openxml4j.opc.Package;\r
+import org.openxml4j.opc.internal.PackagePropertiesPart;\r
+import org.openxml4j.opc.internal.marshallers.PackagePropertiesMarshaller;\r
+import org.openxml4j.exceptions.OpenXML4JException;\r
+import org.apache.poi.util.IOUtils;\r
+\r
+import java.io.*;\r
+import java.util.ArrayList;\r
+import java.lang.reflect.Method;\r
+\r
+/**\r
+ * Provides handy methods to work with OOXML packages\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class PackageHelper {\r
+\r
+    /**\r
+     * Clone the specified package.\r
+     *\r
+     * @param   pkg   the package to clone\r
+     * @return  the cloned package\r
+     */\r
+    public static Package clone(Package pkg) throws OpenXML4JException, IOException {\r
+        return clone(pkg, createTempFile());\r
+    }\r
+\r
+    /**\r
+     * Clone the specified package.\r
+     *\r
+     * @param   pkg   the package to clone\r
+     * @param   file  the destination file\r
+     * @return  the cloned package\r
+     */\r
+    public static Package clone(Package pkg, File file) throws OpenXML4JException, IOException {\r
+\r
+        String path = file.getAbsolutePath();\r
+\r
+        Package dest = Package.create(path);\r
+        PackageRelationshipCollection rels = pkg.getRelationships();\r
+        for (PackageRelationship rel : rels) {\r
+            PackagePart part = pkg.getPart(rel);\r
+            PackagePart part_tgt;\r
+            if (rel.getRelationshipType().equals(PackageRelationshipTypes.CORE_PROPERTIES)) {\r
+                copyProperties(pkg.getPackageProperties(), dest.getPackageProperties());\r
+                continue;\r
+            } else {\r
+                dest.addRelationship(part.getPartName(), rel.getTargetMode(), rel.getRelationshipType());\r
+                part_tgt = dest.createPart(part.getPartName(), part.getContentType());\r
+            }\r
+\r
+            OutputStream out = part_tgt.getOutputStream();\r
+            IOUtils.copy(part.getInputStream(), out);\r
+            out.close();\r
+\r
+            if(part.hasRelationships()) {\r
+                copy(pkg, part, dest, part_tgt);\r
+            }\r
+        }\r
+        dest.close();\r
+\r
+        //the temp file will be deleted when JVM terminates\r
+        new File(path).deleteOnExit();\r
+        return Package.open(path);\r
+    }\r
+\r
+    /**\r
+     *\r
+     * @return\r
+     * @throws IOException\r
+     */\r
+    public static File createTempFile() throws IOException {\r
+        File file = File.createTempFile("poi-ooxml-", ".tmp");\r
+        //there is no way to pass an existing file to Package.create(file),\r
+        //delete first, the file will be re-created in Packe.create(file)\r
+        file.delete();\r
+        file.deleteOnExit();\r
+        return file;\r
+\r
+    }\r
+\r
+    /**\r
+     * Recursively copy package parts to the destination package\r
+     */\r
+    private static void copy(Package pkg, PackagePart part, Package tgt, PackagePart part_tgt) throws OpenXML4JException, IOException {\r
+        PackageRelationshipCollection rels = part.getRelationships();\r
+        if(rels != null) for (PackageRelationship rel : rels) {\r
+            PackagePart p;\r
+            if(rel.getTargetMode() == TargetMode.EXTERNAL){\r
+                part_tgt.addExternalRelationship(rel.getTargetURI().toString(), rel.getRelationshipType(), rel.getId());\r
+                //external relations don't have associated package parts\r
+                continue;\r
+            } else {\r
+                PackagePartName relName = PackagingURIHelper.createPartName(rel.getTargetURI());\r
+                p = pkg.getPart(relName);\r
+            }\r
+\r
+            part_tgt.addRelationship(p.getPartName(), rel.getTargetMode(), rel.getRelationshipType(), rel.getId());\r
+\r
+            PackagePart dest;\r
+            if(!tgt.containPart(p.getPartName())){\r
+                dest = tgt.createPart(p.getPartName(), p.getContentType());\r
+                OutputStream out = dest.getOutputStream();\r
+                IOUtils.copy(p.getInputStream(), out);\r
+                out.close();\r
+                copy(pkg, p, tgt, dest);\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Copy core package properties\r
+     *\r
+     * @param src source properties\r
+     * @param tgt target properties\r
+     */\r
+    private static void copyProperties(PackageProperties src, PackageProperties tgt){\r
+        tgt.setCategoryProperty(src.getCategoryProperty().getValue());\r
+        tgt.setContentStatusProperty(src.getContentStatusProperty().getValue());\r
+        tgt.setContentTypeProperty(src.getContentTypeProperty().getValue());\r
+        tgt.setCreatorProperty(src.getCreatorProperty().getValue());\r
+        tgt.setDescriptionProperty(src.getDescriptionProperty().getValue());\r
+        tgt.setIdentifierProperty(src.getIdentifierProperty().getValue());\r
+        tgt.setKeywordsProperty(src.getKeywordsProperty().getValue());\r
+        tgt.setLanguageProperty(src.getLanguageProperty().getValue());\r
+        tgt.setRevisionProperty(src.getRevisionProperty().getValue());\r
+        tgt.setSubjectProperty(src.getSubjectProperty().getValue());\r
+        tgt.setTitleProperty(src.getTitleProperty().getValue());\r
+        tgt.setVersionProperty(src.getVersionProperty().getValue());\r
+    }\r
+}\r
index 6c3d2dcbdcfad4ef36f5e2d53c5e73fcab54a9e4..3bb60e90342870343d951eea38fe22b7fee60ffd 100755 (executable)
@@ -21,10 +21,7 @@ import org.w3c.dom.Document;
 \r
 import javax.xml.parsers.DocumentBuilderFactory;\r
 import javax.xml.parsers.DocumentBuilder;\r
-import java.io.FileOutputStream;\r
-import java.io.File;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
+import java.io.*;\r
 import java.util.zip.ZipFile;\r
 import java.util.zip.ZipEntry;\r
 import java.util.Enumeration;\r
@@ -70,24 +67,32 @@ public class XSSFDump {
             FileOutputStream out = new FileOutputStream(f);\r
 \r
             if(entry.getName().endsWith(".xml") || entry.getName().endsWith(".vml") || entry.getName().endsWith(".rels")){\r
-                //pass the xml through the Xerces serializer to produce nicely formatted output\r
-                Document doc = builder.parse(zip.getInputStream(entry));\r
-\r
-                OutputFormat  format  = new OutputFormat( doc );\r
-                format.setIndenting(true);\r
-\r
-                XMLSerializer serial = new  XMLSerializer( out, format );\r
-                serial.asDOMSerializer();\r
-                serial.serialize( doc.getDocumentElement() );\r
-\r
+                try {\r
+                    //pass the xml through the Xerces serializer to produce nicely formatted output\r
+                    Document doc = builder.parse(zip.getInputStream(entry));\r
+\r
+                    OutputFormat  format  = new OutputFormat( doc );\r
+                    format.setIndenting(true);\r
+\r
+                    XMLSerializer serial = new  XMLSerializer( out, format );\r
+                    serial.asDOMSerializer();\r
+                    serial.serialize( doc.getDocumentElement() );\r
+                } catch (Exception e){\r
+                    System.err.println("Failed to parse " + entry.getName() + ", dumping raw content");\r
+                    dump(zip.getInputStream(entry), out);\r
+                }\r
             } else {\r
-                int pos;\r
-                byte[] chunk = new byte[2048];\r
-                InputStream is = zip.getInputStream(entry);\r
-                while((pos = is.read(chunk)) > 0) out.write(chunk, 0, pos);\r
+                dump(zip.getInputStream(entry), out);\r
             }\r
             out.close();\r
 \r
         }\r
     }\r
+\r
+    protected static void dump(InputStream is, OutputStream out) throws IOException{\r
+        int pos;\r
+        byte[] chunk = new byte[2048];\r
+        while((pos = is.read(chunk)) > 0) out.write(chunk, 0, pos);\r
+\r
+    }\r
 }\r
index 148a02fcb200afd6f2c437ca752573a4e7ae5675..7ca4a3d691f7e33631fef30e585af7cdd17946cc 100755 (executable)
@@ -31,6 +31,7 @@ public class XSSFSave {
         for (int i = 0; i < args.length; i++) {\r
             XSSFWorkbook wb = new XSSFWorkbook(args[i]);\r
 \r
+            System.out.println("wb.getNumberOfSheets(): " + wb.getNumberOfSheets());\r
             int sep = args[i].lastIndexOf('.');\r
             String outfile = args[i].substring(0, sep) + "-save.xlsx";\r
             FileOutputStream out = new FileOutputStream(outfile);\r
index 388fda66ba60acb80aef8b2f64f6c1f1fab33a5f..15c09c80a9502b5fd91e14805088e30b45e52cb3 100644 (file)
@@ -23,6 +23,7 @@ import java.io.OutputStream;
 import org.apache.poi.ss.usermodel.CommentsSource;
 import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.xssf.usermodel.XSSFComment;
+import org.apache.poi.POIXMLDocumentPart;
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlOptions;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAuthors;
@@ -30,103 +31,121 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCommentList;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComments;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CommentsDocument;
+import org.openxml4j.opc.PackagePart;
+import org.openxml4j.opc.PackageRelationship;
 
-public class CommentsTable implements CommentsSource, XSSFModel {
-       private CTComments comments;
-
-       public CommentsTable(InputStream is) throws IOException {
-               readFrom(is);
-       }
-       public CommentsTable() {
-               comments = CTComments.Factory.newInstance();
-       }
-       /**
-        * For unit testing only!
-        */
-       public CommentsTable(CTComments comments) {
-               this.comments = comments;
-       }
-       
-       public void readFrom(InputStream is) throws IOException {
-               try {
-                       CommentsDocument doc = CommentsDocument.Factory.parse(is);
-                       comments = doc.getComments();
+public class CommentsTable extends POIXMLDocumentPart implements CommentsSource, XSSFModel {
+    private CTComments comments;
+
+    public CommentsTable(InputStream is) throws IOException {
+        super(null, null);
+        readFrom(is);
+    }
+    public CommentsTable() {
+        super(null, null);
+        comments = CTComments.Factory.newInstance();
+    }
+    /**
+     * For unit testing only!
+     */
+    public CommentsTable(CTComments comments) {
+        super(null, null);
+        this.comments = comments;
+    }
+
+    public CommentsTable(PackagePart part, PackageRelationship rel) throws IOException {
+        super(part, rel);
+        readFrom(part.getInputStream());
+    }
+
+    public void readFrom(InputStream is) throws IOException {
+        try {
+            CommentsDocument doc = CommentsDocument.Factory.parse(is);
+            comments = doc.getComments();
         } catch (XmlException e) {
             throw new IOException(e.getLocalizedMessage());
         }
-       }
-       public void writeTo(OutputStream out) throws IOException {
+    }
+    public void writeTo(OutputStream out) throws IOException {
         XmlOptions options = new XmlOptions();
         options.setSaveOuter();
         options.setUseDefaultNamespace();
-        
+
         // Requests use of whitespace for easier reading
         //options.setSavePrettyPrint();
-        
+
         CommentsDocument doc = CommentsDocument.Factory.newInstance(options);
         doc.setComments(comments);
         doc.save(out, options);
-       }
-       
-       public int getNumberOfComments() {
-               return comments.getCommentList().sizeOfCommentArray();
-       }
-       public int getNumberOfAuthors() {
-               return getCommentsAuthors().sizeOfAuthorArray();
-       }
-       
-       public String getAuthor(long authorId) {
-               return getCommentsAuthors().getAuthorArray((int)authorId);
-       }
-       
-       public int findAuthor(String author) {
-               for (int i = 0 ; i < getCommentsAuthors().sizeOfAuthorArray() ; i++) {
-                       if (getCommentsAuthors().getAuthorArray(i).equals(author)) {
-                               return i;
-                       }
-               }
-               return addNewAuthor(author);
-       }
-       
-       public XSSFComment findCellComment(int row, int column) {
-               return findCellComment(
-                               (new CellReference(row, column)).formatAsString() );
-       }
-       
-       public XSSFComment findCellComment(String cellRef) {
-               for (CTComment comment : getCommentsList().getCommentArray()) {
-                       if (cellRef.equals(comment.getRef())) {
-                               return new XSSFComment(this, comment);
-                       }
-               }
-               return null;
-       }
-
-       /**
-        * Generates a new XSSFComment, associated with the
-        *  current comments list.
-        */
-       public XSSFComment addComment() {
-               return new XSSFComment(this, getCommentsList().addNewComment());
-       }
-
-       private CTCommentList getCommentsList() {
-               if (comments.getCommentList() == null) {
-                       comments.addNewCommentList();
-               }
-               return comments.getCommentList();
-       }
-
-       private CTAuthors getCommentsAuthors() {
-               if (comments.getAuthors() == null) {
-                       comments.addNewAuthors();
-               }
-               return comments.getAuthors();
-       }
-       
-       private int addNewAuthor(String author) {
-               int index = getCommentsAuthors().sizeOfAuthorArray();
-               getCommentsAuthors().insertAuthor(index, author);
-               return index;
-       }
+    }
+
+    @Override
+    protected void commit() throws IOException {
+        PackagePart part = getPackagePart();
+        OutputStream out = part.getOutputStream();
+        writeTo(out);
+        out.close();
+    }
+
+    public int getNumberOfComments() {
+        return comments.getCommentList().sizeOfCommentArray();
+    }
+    public int getNumberOfAuthors() {
+        return getCommentsAuthors().sizeOfAuthorArray();
+    }
+
+    public String getAuthor(long authorId) {
+        return getCommentsAuthors().getAuthorArray((int)authorId);
+    }
+
+    public int findAuthor(String author) {
+        for (int i = 0 ; i < getCommentsAuthors().sizeOfAuthorArray() ; i++) {
+            if (getCommentsAuthors().getAuthorArray(i).equals(author)) {
+                return i;
+            }
+        }
+        return addNewAuthor(author);
+    }
+
+    public XSSFComment findCellComment(int row, int column) {
+        return findCellComment(
+                (new CellReference(row, column)).formatAsString() );
+    }
+
+    public XSSFComment findCellComment(String cellRef) {
+        for (CTComment comment : getCommentsList().getCommentArray()) {
+            if (cellRef.equals(comment.getRef())) {
+                return new XSSFComment(this, comment);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Generates a new XSSFComment, associated with the
+     *  current comments list.
+     */
+    public XSSFComment addComment() {
+        return new XSSFComment(this, getCommentsList().addNewComment());
+    }
+
+    private CTCommentList getCommentsList() {
+        if (comments.getCommentList() == null) {
+            comments.addNewCommentList();
+        }
+        return comments.getCommentList();
+    }
+
+    private CTAuthors getCommentsAuthors() {
+        if (comments.getAuthors() == null) {
+            comments.addNewAuthors();
+        }
+        return comments.getAuthors();
+    }
+
+    private int addNewAuthor(String author) {
+        int index = getCommentsAuthors().sizeOfAuthorArray();
+        getCommentsAuthors().insertAuthor(index, author);
+        return index;
+    }
 }
\ No newline at end of file
index b526d30828324c248df0fafbb9630c5cd4d7f91f..c004905412d04349947597b47ec47ddf49eb9a8d 100644 (file)
@@ -27,9 +27,13 @@ import java.util.Map;
 
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlOptions;
+import org.apache.poi.POIXMLDocumentPart;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRst;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSst;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.SstDocument;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
+import org.openxml4j.opc.PackagePart;
+import org.openxml4j.opc.PackageRelationship;
 
 
 /**
@@ -56,7 +60,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.SstDocument;
  * @author Nick Birch
  * @author Yegor Kozlov
  */
-public class SharedStringsTable implements SharedStringSource, XSSFModel {
+public class SharedStringsTable extends POIXMLDocumentPart implements XSSFModel, SharedStringSource {
 
     /**
      *  Array of individual string items in the Shared String table.
@@ -89,13 +93,17 @@ public class SharedStringsTable implements SharedStringSource, XSSFModel {
      * @throws IOException if an error occurs while reading.
      */
     public SharedStringsTable(InputStream is) throws IOException {
+        super(null, null);
         readFrom(is);
     }
-    /**
-     * Create a new, empty SharedStringsTable
-     */
+
     public SharedStringsTable() {
-        count = uniqueCount = 0;
+        super(null, null);
+    }
+
+    public SharedStringsTable(PackagePart part, PackageRelationship rel) throws IOException {
+        super(part, rel);
+        readFrom(part.getInputStream());
     }
 
     /**
@@ -204,4 +212,12 @@ public class SharedStringsTable implements SharedStringSource, XSSFModel {
         sst.setSiArray(ctr);
         doc.save(out, options);
     }
+
+    @Override
+    protected void commit() throws IOException {
+        PackagePart part = getPackagePart();
+        OutputStream out = part.getOutputStream();
+        writeTo(out);
+        out.close();
+    }
 }
index 79d28bf115e50a4fe59cb80dc2311ce64dafa18a..4f4c92e1778b733cbfa21758b96c27cf9356925f 100644 (file)
@@ -36,6 +36,7 @@ import org.apache.poi.xssf.usermodel.XSSFCellStyle;
 import org.apache.poi.xssf.usermodel.XSSFFont;
 import org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder;
 import org.apache.poi.xssf.usermodel.extensions.XSSFCellFill;
+import org.apache.poi.POIXMLDocumentPart;
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlOptions;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBorder;
@@ -54,13 +55,16 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTStylesheet;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPatternType;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.StyleSheetDocument;
+import org.openxml4j.opc.PackagePart;
+import org.openxml4j.opc.PackageRelationship;
+
 
 /**
  * Table of styles shared across all sheets in a workbook.
  *
  * @author ugo
  */
-public class StylesTable implements StylesSource, XSSFModel {
+public class StylesTable extends POIXMLDocumentPart implements StylesSource, XSSFModel {
        private final Hashtable<Long,String> numberFormats = new Hashtable<Long,String>();
        private final List<CTFont> fonts = new ArrayList<CTFont>();
        private final List<CTFill> fills = new LinkedList<CTFill>();
@@ -85,18 +89,25 @@ public class StylesTable implements StylesSource, XSSFModel {
         * @throws IOException if an error occurs while reading.
         */
        public StylesTable(InputStream is) throws IOException {
+        super(null, null);
                readFrom(is);
        }
        /**
         * Create a new, empty StylesTable
         */
        public StylesTable() {
+        super(null, null);
                doc = StyleSheetDocument.Factory.newInstance();
                doc.addNewStyleSheet();
                // Initialization required in order to make the document readable by MSExcel
                initialize();
        }
 
+    public StylesTable(PackagePart part, PackageRelationship rel) throws IOException {
+        super(part, rel);
+        readFrom(part.getInputStream());
+    }
+
        /**
         * Read this shared styles table from an XML file.
         *
@@ -365,6 +376,14 @@ public class StylesTable implements StylesSource, XSSFModel {
                doc.save(out, options);
        }
 
+    @Override
+    protected void commit() throws IOException {
+        PackagePart part = getPackagePart();
+        OutputStream out = part.getOutputStream();
+        writeTo(out);
+        out.close();
+    }
+
        private long putBorder(XSSFCellBorder border, List<CTBorder> borders) {
                return border.putBorder((LinkedList<CTBorder>) borders); // TODO - use List instead of LinkedList
        }
index 771f68482f220184c52d57462d4937d7b98a4841..a0bc00d5ab7d96c4bb0520d98af7baddde67d139 100644 (file)
@@ -23,26 +23,22 @@ import org.apache.poi.ss.usermodel.RichTextString;
 
 public class XSSFCreationHelper implements CreationHelper {
        private XSSFWorkbook workbook;
-       private XSSFDataFormat dataFormat;
        XSSFCreationHelper(XSSFWorkbook wb) {
                workbook = wb;
-               
-               // Create the things we only ever need one of
-               dataFormat = new XSSFDataFormat(workbook.getStylesSource());
        }
        
     /**
      * Creates a new XSSFRichTextString for you.
      */
-       public RichTextString createRichTextString(String text) {
+       public XSSFRichTextString createRichTextString(String text) {
                return new XSSFRichTextString(text);
        }
        
-       public DataFormat createDataFormat() {
-               return dataFormat;
+       public XSSFDataFormat createDataFormat() {
+               return workbook.createDataFormat();
        }
        
-       public Hyperlink createHyperlink(int type) {
+       public XSSFHyperlink createHyperlink(int type) {
                return new XSSFHyperlink(type);
        }
 }
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFactory.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFactory.java
new file mode 100755 (executable)
index 0000000..44f8054
--- /dev/null
@@ -0,0 +1,57 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+package org.apache.poi.xssf.usermodel;\r
+\r
+import org.apache.poi.POIXMLDocumentPart;\r
+import org.apache.poi.POIXMLFactory;\r
+import org.apache.poi.POIXMLException;\r
+import org.apache.poi.xssf.model.SharedStringsTable;\r
+import org.apache.poi.xssf.model.StylesTable;\r
+import org.apache.poi.xssf.model.CommentsTable;\r
+import org.openxml4j.opc.PackageRelationship;\r
+import org.openxml4j.opc.PackagePart;\r
+\r
+import java.util.Map;\r
+import java.util.HashMap;\r
+import java.lang.reflect.Constructor;\r
+\r
+/**\r
+ * Instantiates sub-classes of POIXMLDocumentPart depending on their relationship type\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public class XSSFFactory extends POIXMLFactory  {\r
+    protected static Map<String, Class> parts = new HashMap<String, Class>();\r
+    static {\r
+        parts.put(XSSFRelation.WORKSHEET.getRelation(), XSSFSheet.class);\r
+        parts.put(XSSFRelation.SHARED_STRINGS.getRelation(), SharedStringsTable.class);\r
+        parts.put(XSSFRelation.STYLES.getRelation(), StylesTable.class);\r
+        parts.put(XSSFRelation.SHEET_COMMENTS.getRelation(), CommentsTable.class);\r
+    }\r
+\r
+    public POIXMLDocumentPart create(PackageRelationship rel, PackagePart p){\r
+        Class cls = parts.get(rel.getRelationshipType());\r
+        if(cls == null) return super.create(rel, p);\r
+\r
+        try {\r
+            Constructor<? extends POIXMLDocumentPart> constructor = cls.getConstructor(PackagePart.class, PackageRelationship.class);\r
+            return constructor.newInstance(p, rel);\r
+        } catch (Exception e){\r
+            throw new POIXMLException(e);\r
+        }\r
+    }\r
+}\r
index 71f3f8ce0dda7139637198c28361236be376b21e..42781a59268de8b18591a1e902c7c04a2d88a09c 100644 (file)
@@ -26,6 +26,7 @@ import java.util.Iterator;
 import java.util.List;
 
 import org.apache.poi.POIXMLDocument;
+import org.apache.poi.POIXMLRelation;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
 import org.apache.poi.xssf.model.BinaryPart;
@@ -49,7 +50,7 @@ import org.openxml4j.opc.TargetMode;
 /**
  * 
  */
-public final class XSSFRelation<W extends XSSFModel> {
+public final class XSSFRelation<W extends XSSFModel> extends POIXMLRelation {
 
        public static final XSSFRelation WORKBOOK = new XSSFRelation(
                        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
@@ -156,16 +157,12 @@ public final class XSSFRelation<W extends XSSFModel> {
        return new XSSFRelation<R>(type, rel, defaultName, cls);
     }
    
-       private String _type;
-       private String _relation;
-       private String _defaultName;
        private Constructor<W> _constructor;
        private final boolean _constructorTakesTwoArgs;
        
        private XSSFRelation(String type, String rel, String defaultName, Class<W> cls) {
-               _type = type;
-               _relation = rel;
-               _defaultName = defaultName;
+               super(type, rel, defaultName);
+
                if (cls == null) {
                        _constructor = null;
                        _constructorTakesTwoArgs = false;
@@ -189,10 +186,7 @@ public final class XSSFRelation<W extends XSSFModel> {
                        _constructorTakesTwoArgs = twoArg;
                }
        }
-       public String getContentType() { return _type; }
-       public String getRelation() { return _relation; }
-       public String getDefaultFileName() { return _defaultName; }
-       
+
        /**
         * Does one of these exist for the given core
         *  package part?
index dbf6a45de7124ab73fd2bb1cbe58c779114cf3a3..1d356b188e8cd529b23c1d803e06a5f0134a623b 100644 (file)
@@ -24,6 +24,7 @@ import java.util.Arrays;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import javax.xml.namespace.QName;
 
 import org.apache.poi.hssf.util.PaneInformation;
 import org.apache.poi.ss.usermodel.CellStyle;
@@ -41,1531 +42,1528 @@ import org.apache.poi.xssf.model.CommentsTable;
 import org.apache.poi.xssf.model.Control;
 import org.apache.poi.xssf.model.Drawing;
 import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
+import org.apache.poi.POIXMLDocumentPart;
+import org.apache.poi.POIXMLException;
 import org.apache.xmlbeans.XmlOptions;
+import org.apache.xmlbeans.XmlException;
 import org.openxml4j.opc.PackagePart;
 import org.openxml4j.opc.PackageRelationship;
 import org.openxml4j.opc.PackageRelationshipCollection;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBreak;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDialogsheet;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHeaderFooter;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHyperlink;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCell;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCells;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOutlinePr;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageBreak;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageMargins;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageSetUpPr;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPane;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPrintOptions;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSelection;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetFormatPr;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetPr;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetProtection;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetView;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
 
 
 /**
- * High level representation of a worksheet.
+ * High level representation of a SpreadsheetML worksheet.
  *
  * <p>
  * Sheets are the central structures within a workbook, and are where a user does most of his spreadsheet work.
  * The most common type of sheet is the worksheet, which is represented as a grid of cells. Worksheet cells can
- * contain text, numbers, dates, and formulas. Cells can also be formatted.  A workbook usually contains more than one sheet.
+ * contain text, numbers, dates, and formulas. Cells can also be formatted.
  * </p>
  */
-public class XSSFSheet implements Sheet {
-       protected CTSheet sheet;
-       protected CTWorksheet worksheet;
-       protected CTDialogsheet dialogsheet;
-       protected List<Row> rows;
-       protected List<XSSFHyperlink> hyperlinks;
-       protected ColumnHelper columnHelper;
-       protected XSSFWorkbook workbook;
-       protected CommentsSource sheetComments;
-       protected CTMergeCells ctMergeCells;
-
-
-       protected List<Drawing> drawings;
-       protected List<Control> controls;
-
-
-       public static final short LeftMargin = 0;
-       public static final short RightMargin = 1;
-       public static final short TopMargin = 2;
-       public static final short BottomMargin = 3;
-       public static final short HeaderMargin = 4;
-       public static final short FooterMargin = 5;
-
-       public XSSFSheet(CTSheet sheet, CTWorksheet worksheet, XSSFWorkbook workbook, CommentsSource sheetComments, List<Drawing> drawings, List<Control> controls) {
-               this(sheet, worksheet, workbook, sheetComments);
-               this.drawings = drawings;
-               this.controls = controls;
-       }
-
-       public List<Drawing> getDrawings()
-       {
-               return drawings;
-       }
-
-       public List<Control> getControls()
-       {
-               return controls;
-       }
-
-       public XSSFSheet(CTSheet sheet, CTWorksheet worksheet, XSSFWorkbook workbook, CommentsSource sheetComments) {
-               this(sheet, worksheet, workbook);
-               this.sheetComments = sheetComments;
-       }
-
-       public XSSFSheet(CTSheet sheet, CTWorksheet worksheet, XSSFWorkbook workbook) {
-               this.workbook = workbook;
-               this.sheet = sheet;
-               this.worksheet = worksheet;
-
-               if (this.worksheet.getSheetData() == null) {
-                       this.worksheet.addNewSheetData();
-               }
-
-               initRows(this.worksheet);
-               initColumns(this.worksheet);
-
-               hyperlinks = new ArrayList<XSSFHyperlink>();
-       }
-
-       protected XSSFSheet(XSSFWorkbook workbook) {
-               this.workbook = workbook;
-
-               hyperlinks = new ArrayList<XSSFHyperlink>();
-       }
-
-       /**
-        * Returns the parent XSSFWorkbook
-        *
-        * @return the parent XSSFWorkbook
-        */
-       public XSSFWorkbook getWorkbook() {
-               return this.workbook;
-       }
-
-       /**
-        * Create a new CTWorksheet instance and setup default values
-        *
-        * @return a new instance
-        */
-       protected static CTWorksheet newInstance(){
-               CTWorksheet worksheet = CTWorksheet.Factory.newInstance();
-               CTSheetFormatPr ctFormat = worksheet.addNewSheetFormatPr();
-               ctFormat.setDefaultRowHeight(15.0);
-
-               CTSheetView ctView = worksheet.addNewSheetViews().addNewSheetView();
-               ctView.setTabSelected(true);
-               ctView.setWorkbookViewId(0);
-
-               worksheet.addNewDimension().setRef("A1");
-
-               worksheet.addNewSheetData();
-
-               CTPageMargins ctMargins = worksheet.addNewPageMargins();
-               ctMargins.setBottom(0.75);
-               ctMargins.setFooter(0.3);
-               ctMargins.setHeader(0.3);
-               ctMargins.setLeft(0.7);
-               ctMargins.setRight(0.7);
-               ctMargins.setTop(0.75);
-
-               return worksheet;
-       }
-
-       /**
-        * Tweaks the CTWorksheet to fit with what Excel
-        *  will accept without a massive huff, and write into
-        *  the OutputStream supplied.
-        */
-       protected void save(PackagePart sheetPart, XmlOptions xmlOptions) throws IOException {
-               // Excel objects to <cols/>
-               if(worksheet.getColsArray().length == 1) {
-                       CTCols col = worksheet.getColsArray(0);
-                       if(col.getColArray().length == 0) {
-                               worksheet.setColsArray(null);
-                       }
-               }
-
-               // Now re-generate our CTHyperlinks, if needed
-               if(hyperlinks.size() > 0) {
-                       if(worksheet.getHyperlinks() == null) {
-                               worksheet.addNewHyperlinks();
-                       }
-                       CTHyperlink[] ctHls = new CTHyperlink[hyperlinks.size()];
-                       for(int i=0; i<ctHls.length; i++) {
-                               // If our sheet has hyperlinks, have them add
-                               //  any relationships that they might need
-                               XSSFHyperlink hyperlink = hyperlinks.get(i);
-                               hyperlink.generateRelationIfNeeded(sheetPart);
-                               // Now grab their underling object
-                               ctHls[i] = hyperlink.getCTHyperlink();
-                       }
-                       worksheet.getHyperlinks().setHyperlinkArray(ctHls);
-               }
-
-               // Save
-               OutputStream out = sheetPart.getOutputStream();
-               worksheet.save(out, xmlOptions);
-               out.close();
-       }
-
-       /**
-        * Provide access to the underlying XML bean
-        *
-        * @return the underlying CTWorksheet bean
-        */
-       public CTWorksheet getWorksheet() {
-               return this.worksheet;
-       }
-
-       public ColumnHelper getColumnHelper() {
-               return columnHelper;
-       }
-
-       protected void initRows(CTWorksheet worksheet) {
-               this.rows = new LinkedList<Row>();
-               for (CTRow row : worksheet.getSheetData().getRowArray()) {
-                       this.rows.add(new XSSFRow(row, this));
-               }
-       }
-
-       protected void initColumns(CTWorksheet worksheet) {
-               columnHelper = new ColumnHelper(worksheet);
-       }
-
-       protected void initHyperlinks(PackageRelationshipCollection hyperRels) {
-               if(worksheet.getHyperlinks() == null) return;
-
-               // Turn each one into a XSSFHyperlink
-               for(CTHyperlink hyperlink : worksheet.getHyperlinks().getHyperlinkArray()) {
-                       PackageRelationship hyperRel = null;
-                       if(hyperlink.getId() != null) {
-                               hyperRel = hyperRels.getRelationshipByID(hyperlink.getId());
-                       }
-
-                       hyperlinks.add(
-                                       new XSSFHyperlink(hyperlink, hyperRel)
-                       );
-               }
-       }
-
-       protected CTSheet getSheet() {
-               return this.sheet;
-       }
-       public int addMergedRegion(CellRangeAddress cra) {
-               Region r = new Region(cra.getFirstRow(), (short)cra.getFirstColumn(),
-                               cra.getLastRow(), (short)cra.getLastColumn());
-               return addMergedRegion(r);
-       }
-
-
-       public int addMergedRegion(Region region) {
-               addNewMergeCell(region);
-               return ctMergeCells.sizeOfMergeCellArray();
-       }
-
-       /**
-        * Adjusts the column width to fit the contents.
-        *
-        * This process can be relatively slow on large sheets, so this should
-        *  normally only be called once per column, at the end of your
-        *  processing.
-        *
-        * @param column the column index
-        */
+public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
+    protected CTSheet sheet;
+    protected CTWorksheet worksheet;
+    protected CTDialogsheet dialogsheet;
+    protected List<Row> rows;
+    protected List<XSSFHyperlink> hyperlinks;
+    protected ColumnHelper columnHelper;
+    protected CommentsSource sheetComments;
+    protected CTMergeCells ctMergeCells;
+
+
+    protected List<Drawing> drawings;
+    protected List<Control> controls;
+
+
+    public static final short LeftMargin = 0;
+    public static final short RightMargin = 1;
+    public static final short TopMargin = 2;
+    public static final short BottomMargin = 3;
+    public static final short HeaderMargin = 4;
+    public static final short FooterMargin = 5;
+
+
+    public XSSFSheet() {
+        super(null, null);
+        this.worksheet = newSheet();
+        initialize();
+    }
+
+    public XSSFSheet(PackagePart part, PackageRelationship rel) throws IOException, XmlException {
+        super(part, rel);
+        worksheet = WorksheetDocument.Factory.parse(part.getInputStream()).getWorksheet();
+    }
+
+    public XSSFSheet(CTSheet sheet, CTWorksheet worksheet, XSSFWorkbook workbook, CommentsSource sheetComments) {
+        super(null, null);
+        this.parent = workbook;
+        this.sheet = sheet;
+        this.worksheet = worksheet;
+        this.sheetComments = sheetComments;
+
+        initialize();
+    }
+
+    public XSSFSheet(CTSheet sheet, CTWorksheet worksheet, XSSFWorkbook workbook) {
+        this(sheet, worksheet, workbook, null);
+    }
+
+    protected XSSFSheet(XSSFWorkbook workbook) {
+        super(null, null);
+        this.parent = workbook;
+
+        hyperlinks = new ArrayList<XSSFHyperlink>();
+    }
+
+    /**
+     * Returns the parent XSSFWorkbook
+     *
+     * @return the parent XSSFWorkbook
+     */
+    public XSSFWorkbook getWorkbook() {
+        return (XSSFWorkbook)getParent();
+    }
+
+    protected void initialize(){
+        if (this.worksheet.getSheetData() == null) {
+            this.worksheet.addNewSheetData();
+        }
+        initRows(this.worksheet);
+        initColumns(this.worksheet);
+
+        for(POIXMLDocumentPart p : getRelations()){
+            if(p instanceof CommentsTable) sheetComments = (CommentsTable)p;
+        }
+        hyperlinks = new ArrayList<XSSFHyperlink>();
+    }
+
+    /**
+     * Create a new CTWorksheet instance and setup default values
+     *
+     * @return a new instance
+     */
+    protected static CTWorksheet newSheet(){
+        CTWorksheet worksheet = CTWorksheet.Factory.newInstance();
+        CTSheetFormatPr ctFormat = worksheet.addNewSheetFormatPr();
+        ctFormat.setDefaultRowHeight(15.0);
+
+        CTSheetView ctView = worksheet.addNewSheetViews().addNewSheetView();
+        ctView.setTabSelected(true);
+        ctView.setWorkbookViewId(0);
+
+        worksheet.addNewDimension().setRef("A1");
+
+        worksheet.addNewSheetData();
+
+        CTPageMargins ctMargins = worksheet.addNewPageMargins();
+        ctMargins.setBottom(0.75);
+        ctMargins.setFooter(0.3);
+        ctMargins.setHeader(0.3);
+        ctMargins.setLeft(0.7);
+        ctMargins.setRight(0.7);
+        ctMargins.setTop(0.75);
+
+        return worksheet;
+    }
+
+    public List<Drawing> getDrawings()
+    {
+        return drawings;
+        }
+
+    public List<Control> getControls()
+    {
+        return controls;
+    }
+
+    /**
+     * Provide access to the underlying XML bean
+     *
+     * @return the underlying CTWorksheet bean
+     */
+    public CTWorksheet getWorksheet() {
+        return this.worksheet;
+    }
+
+    public ColumnHelper getColumnHelper() {
+        return columnHelper;
+    }
+
+    protected void initRows(CTWorksheet worksheet) {
+        this.rows = new LinkedList<Row>();
+        for (CTRow row : worksheet.getSheetData().getRowArray()) {
+            this.rows.add(new XSSFRow(row, this));
+        }
+    }
+
+    protected void initColumns(CTWorksheet worksheet) {
+        columnHelper = new ColumnHelper(worksheet);
+    }
+
+    protected void initHyperlinks(PackageRelationshipCollection hyperRels) {
+        if(worksheet.getHyperlinks() == null) return;
+
+        // Turn each one into a XSSFHyperlink
+        for(CTHyperlink hyperlink : worksheet.getHyperlinks().getHyperlinkArray()) {
+            PackageRelationship hyperRel = null;
+            if(hyperlink.getId() != null) {
+                hyperRel = hyperRels.getRelationshipByID(hyperlink.getId());
+            }
+
+            hyperlinks.add(
+                    new XSSFHyperlink(hyperlink, hyperRel)
+            );
+        }
+    }
+
+    protected CTSheet getSheet() {
+        return this.sheet;
+    }
+    public int addMergedRegion(CellRangeAddress cra) {
+        Region r = new Region(cra.getFirstRow(), (short)cra.getFirstColumn(),
+                cra.getLastRow(), (short)cra.getLastColumn());
+        return addMergedRegion(r);
+    }
+
+
+    public int addMergedRegion(Region region) {
+        addNewMergeCell(region);
+        return ctMergeCells.sizeOfMergeCellArray();
+    }
+
+    /**
+     * Adjusts the column width to fit the contents.
+     *
+     * This process can be relatively slow on large sheets, so this should
+     *  normally only be called once per column, at the end of your
+     *  processing.
+     *
+     * @param column the column index
+     */
    public void autoSizeColumn(short column) {
-               autoSizeColumn(column, false);
-       }
-
-       /**
-        * Adjusts the column width to fit the contents.
-        *
-        * This process can be relatively slow on large sheets, so this should
-        *  normally only be called once per column, at the end of your
-        *  processing.
-        *
-        * You can specify whether the content of merged cells should be considered or ignored.
-        *  Default is to ignore merged cells.
-        *
-        * @param column the column index
-        * @param useMergedCells whether to use the contents of merged cells when calculating the width of the column
-        */
-       public void autoSizeColumn(short column, boolean useMergedCells) {
-               //TODO:
-               columnHelper.setColBestFit(column, true);
-       }
-
-       public Patriarch createDrawingPatriarch() {
-               // TODO Auto-generated method stub
-               return null;
-       }
-
-       /**
-        * Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
-        * @param colSplit        Horizonatal position of split.
-        * @param rowSplit        Vertical position of split.
-        * @param topRow                Top row visible in bottom pane
-        * @param leftmostColumn   Left column visible in right pane.
-        */
-       public void createFreezePane(int colSplit, int rowSplit, int leftmostColumn, int topRow) {
-               this.createFreezePane(colSplit, rowSplit);
-               this.showInPane((short)topRow, (short)leftmostColumn);
-       }
-
-       /**
-        * Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
-        * @param colSplit        Horizonatal position of split.
-        * @param rowSplit        Vertical position of split.
-        */
-       public void createFreezePane(int colSplit, int rowSplit) {
-               getPane().setXSplit(colSplit);
-               getPane().setYSplit(rowSplit);
-               // make bottomRight default active pane
-               getPane().setActivePane(STPane.BOTTOM_RIGHT);
-       }
-
-       /**
-        * Creates a new comment for this sheet. You still
-        *  need to assign it to a cell though
-        */
-       public XSSFComment createComment() {
-               return (XSSFComment)getComments().addComment();
-       }
-
-       protected XSSFRow addRow(int index, int rownum) {
-               CTRow row = this.worksheet.getSheetData().insertNewRow(index);
-               XSSFRow xrow = new XSSFRow(row, this);
-               xrow.setRowNum(rownum);
-               return xrow;
-       }
-
-       /**
-        * Create a new row within the sheet and return the high level representation
-        *
-        * @param rownum  row number
-        * @return High level {@link XSSFRow} object representing a row in the sheet
-        * @see #removeRow(org.apache.poi.ss.usermodel.Row)
-        */
-       public XSSFRow createRow(int rownum) {
-               int index = 0;
-               for (Row r : this.rows) {
-                       if (r.getRowNum() == rownum) {
-                               // Replace r with new row
-                               XSSFRow xrow = addRow(index, rownum);
-                               rows.set(index, xrow);
-                               return xrow;
-                       }
-                       if (r.getRowNum() > rownum) {
-                               XSSFRow xrow = addRow(index, rownum);
-                               rows.add(index, xrow);
-                               return xrow;
-                       }
-                       ++index;
-               }
-               XSSFRow xrow = addRow(index, rownum);
-               rows.add(xrow);
-               return xrow;
-       }
-
-       /**
-        * Creates a split pane. Any existing freezepane or split pane is overwritten.
-        * @param xSplitPos       Horizonatal position of split (in 1/20th of a point).
-        * @param ySplitPos       Vertical position of split (in 1/20th of a point).
-        * @param topRow                Top row visible in bottom pane
-        * @param leftmostColumn   Left column visible in right pane.
-        * @param activePane    Active pane.  One of: PANE_LOWER_RIGHT,
-        *                                        PANE_UPPER_RIGHT, PANE_LOWER_LEFT, PANE_UPPER_LEFT
-        * @see #PANE_LOWER_LEFT
-        * @see #PANE_LOWER_RIGHT
-        * @see #PANE_UPPER_LEFT
-        * @see #PANE_UPPER_RIGHT
-        */
-       public void createSplitPane(int xSplitPos, int ySplitPos, int leftmostColumn, int topRow, int activePane) {
-               createFreezePane(xSplitPos, ySplitPos, leftmostColumn, topRow);
-               getPane().setActivePane(STPane.Enum.forInt(activePane));
-       }
-
-       public boolean getAlternateExpression() {
-               // TODO Auto-generated method stub
-               return false;
-       }
-
-       public boolean getAlternateFormula() {
-               // TODO Auto-generated method stub
-               return false;
-       }
-
-       public XSSFComment getCellComment(int row, int column) {
-               return (XSSFComment)getComments().findCellComment(row, column);
-       }
-
-       public XSSFHyperlink getHyperlink(int row, int column) {
-               String ref = new CellReference(row, column).formatAsString();
-               for(XSSFHyperlink hyperlink : hyperlinks) {
-                       if(hyperlink.getCellRef().equals(ref)) {
-                               return hyperlink;
-                       }
-               }
-               return null;
-       }
-
-       /**
-        * Vertical page break information used for print layout view, page layout view, drawing print breaks
-        * in normal view, and for printing the worksheet.
-        *
-        * @return column indexes of all the vertical page breaks, never <code>null</code>
-        */
-       public int[] getColumnBreaks() {
-               if (!worksheet.isSetColBreaks() || worksheet.getColBreaks().sizeOfBrkArray() == 0) {
-                       return new int[0];
-               }
-
-               CTBreak[] brkArray = worksheet.getColBreaks().getBrkArray();
-               int[] breaks = new int[brkArray.length];
-               for (int i = 0 ; i < brkArray.length ; i++) {
-                       CTBreak brk = brkArray[i];
-                       breaks[i] = (int)brk.getId();
-               }
-               return breaks;
-       }
-
-       protected CTPageBreak getSheetTypeColumnBreaks() {
-               if (worksheet.getColBreaks() == null) {
-                       worksheet.setColBreaks(CTPageBreak.Factory.newInstance());
-               }
-               return worksheet.getColBreaks();
-       }
-
-       public int getColumnWidth(int columnIndex) {
-               return (int) columnHelper.getColumn(columnIndex, false).getWidth();
-       }
-       public short getColumnWidth(short column) {
-               return (short) getColumnWidth(column & 0xFFFF);
-       }
-
-       public int getDefaultColumnWidth() {
-               return (int)getSheetTypeSheetFormatPr().getDefaultColWidth();
-       }
-
-       public short getDefaultRowHeight() {
-               return (short) (getSheetTypeSheetFormatPr().getDefaultRowHeight() * 20);
-       }
-
-       protected CTSheetFormatPr getSheetTypeSheetFormatPr() {
-               if (worksheet.getSheetFormatPr() == null) {
-                       worksheet.setSheetFormatPr(CTSheetFormatPr.Factory.newInstance());
-               }
-               return worksheet.getSheetFormatPr();
-       }
-
-       public float getDefaultRowHeightInPoints() {
-               return (short) getSheetTypeSheetFormatPr().getDefaultRowHeight();
-       }
-
-       public boolean getDialog() {
-               if (dialogsheet != null) {
-                       return true;
-               }
-               return false;
-       }
-
-       public boolean getDisplayGuts() {
-               // TODO Auto-generated method stub
-               return false;
-       }
-
-       /**
-        * Gets the first row on the sheet
-        *
-        * @return the number of the first logical row on the sheet, zero based
-        */
-       public int getFirstRowNum() {
-               for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
-                       Row row = it.next();
-                       if (row != null) {
-                               return row.getRowNum();
-                       }
-               }
-               return -1;
-       }
-
-       /**
-        * Flag indicating whether the Fit to Page print option is enabled.
-        *
-        * @return <code>true</code>
-        */
-       public boolean getFitToPage() {
-               CTSheetPr sheetPr = getSheetTypeSheetPr();
-               CTPageSetUpPr psSetup = (sheetPr == null || !sheetPr.isSetPageSetUpPr()) ?
-                               CTPageSetUpPr.Factory.newInstance() : sheetPr.getPageSetUpPr();
-               return psSetup.getFitToPage();
-       }
-
-       protected CTSheetPr getSheetTypeSheetPr() {
-               if (worksheet.getSheetPr() == null) {
-                       worksheet.setSheetPr(CTSheetPr.Factory.newInstance());
-               }
-               return worksheet.getSheetPr();
-       }
-
-       protected CTHeaderFooter getSheetTypeHeaderFooter() {
-               if (worksheet.getHeaderFooter() == null) {
-                       worksheet.setHeaderFooter(CTHeaderFooter.Factory.newInstance());
-               }
-               return worksheet.getHeaderFooter();
-       }
-
-
-
-       /**
-        * Returns the default footer for the sheet,
-        *  creating one as needed.
-        * You may also want to look at
-        *  {@link #getFirstFooter()},
-        *  {@link #getOddFooter()} and
-        *  {@link #getEvenFooter()}
-        */
-       public Footer getFooter() {
-               // The default footer is an odd footer
-               return getOddFooter();
-       }
-
-       /**
-        * Returns the default header for the sheet,
-        *  creating one as needed.
-        * You may also want to look at
-        *  {@link #getFirstHeader()},
-        *  {@link #getOddHeader()} and
-        *  {@link #getEvenHeader()}
-        */
-       public Header getHeader() {
-               // The default header is an odd header
-               return getOddHeader();
-       }
-
-       /**
-        * Returns the odd footer. Used on all pages unless
-        *  other footers also present, when used on only
-        *  odd pages.
-        */
-       public Footer getOddFooter() {
-               return new XSSFOddFooter(getSheetTypeHeaderFooter());
-       }
-       /**
-        * Returns the even footer. Not there by default, but
-        *  when set, used on even pages.
-        */
-       public Footer getEvenFooter() {
-               return new XSSFEvenFooter(getSheetTypeHeaderFooter());
-       }
-       /**
-        * Returns the first page footer. Not there by
-        *  default, but when set, used on the first page.
-        */
-       public Footer getFirstFooter() {
-               return new XSSFFirstFooter(getSheetTypeHeaderFooter());
-       }
-
-       /**
-        * Returns the odd header. Used on all pages unless
-        *  other headers also present, when used on only
-        *  odd pages.
-        */
-       public Header getOddHeader() {
-               return new XSSFOddHeader(getSheetTypeHeaderFooter());
-       }
-       /**
-        * Returns the even header. Not there by default, but
-        *  when set, used on even pages.
-        */
-       public Header getEvenHeader() {
-               return new XSSFEvenHeader(getSheetTypeHeaderFooter()
+        autoSizeColumn(column, false);
+    }
+
+    /**
+     * Adjusts the column width to fit the contents.
+     *
+     * This process can be relatively slow on large sheets, so this should
+     *  normally only be called once per column, at the end of your
+     *  processing.
+     *
+     * You can specify whether the content of merged cells should be considered or ignored.
+     *  Default is to ignore merged cells.
+     *
+     * @param column the column index
+     * @param useMergedCells whether to use the contents of merged cells when calculating the width of the column
+     */
+    public void autoSizeColumn(short column, boolean useMergedCells) {
+        //TODO:
+        columnHelper.setColBestFit(column, true);
+    }
+
+    public Patriarch createDrawingPatriarch() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    /**
+     * Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
+     * @param colSplit   Horizonatal position of split.
+     * @param rowSplit   Vertical position of split.
+     * @param topRow           Top row visible in bottom pane
+     * @param leftmostColumn   Left column visible in right pane.
+     */
+    public void createFreezePane(int colSplit, int rowSplit, int leftmostColumn, int topRow) {
+        this.createFreezePane(colSplit, rowSplit);
+        this.showInPane((short)topRow, (short)leftmostColumn);
+    }
+
+    /**
+     * Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
+     * @param colSplit   Horizonatal position of split.
+     * @param rowSplit   Vertical position of split.
+     */
+    public void createFreezePane(int colSplit, int rowSplit) {
+        getPane().setXSplit(colSplit);
+        getPane().setYSplit(rowSplit);
+        // make bottomRight default active pane
+        getPane().setActivePane(STPane.BOTTOM_RIGHT);
+    }
+
+    /**
+     * Creates a new comment for this sheet. You still
+     *  need to assign it to a cell though
+     */
+    public XSSFComment createComment() {
+        return (XSSFComment)getComments().addComment();
+    }
+
+    protected XSSFRow addRow(int index, int rownum) {
+        CTRow row = this.worksheet.getSheetData().insertNewRow(index);
+        XSSFRow xrow = new XSSFRow(row, this);
+        xrow.setRowNum(rownum);
+        return xrow;
+    }
+
+    /**
+     * Create a new row within the sheet and return the high level representation
+     *
+     * @param rownum  row number
+     * @return High level {@link XSSFRow} object representing a row in the sheet
+     * @see #removeRow(org.apache.poi.ss.usermodel.Row)
+     */
+    public XSSFRow createRow(int rownum) {
+        int index = 0;
+        for (Row r : this.rows) {
+            if (r.getRowNum() == rownum) {
+                // Replace r with new row
+                XSSFRow xrow = addRow(index, rownum);
+                rows.set(index, xrow);
+                return xrow;
+            }
+            if (r.getRowNum() > rownum) {
+                XSSFRow xrow = addRow(index, rownum);
+                rows.add(index, xrow);
+                return xrow;
+            }
+            ++index;
+        }
+        XSSFRow xrow = addRow(index, rownum);
+        rows.add(xrow);
+        return xrow;
+    }
+
+    /**
+     * Creates a split pane. Any existing freezepane or split pane is overwritten.
+     * @param xSplitPos          Horizonatal position of split (in 1/20th of a point).
+     * @param ySplitPos          Vertical position of split (in 1/20th of a point).
+     * @param topRow           Top row visible in bottom pane
+     * @param leftmostColumn   Left column visible in right pane.
+     * @param activePane       Active pane.  One of: PANE_LOWER_RIGHT,
+     *                                   PANE_UPPER_RIGHT, PANE_LOWER_LEFT, PANE_UPPER_LEFT
+     * @see #PANE_LOWER_LEFT
+     * @see #PANE_LOWER_RIGHT
+     * @see #PANE_UPPER_LEFT
+     * @see #PANE_UPPER_RIGHT
+     */
+    public void createSplitPane(int xSplitPos, int ySplitPos, int leftmostColumn, int topRow, int activePane) {
+        createFreezePane(xSplitPos, ySplitPos, leftmostColumn, topRow);
+        getPane().setActivePane(STPane.Enum.forInt(activePane));
+    }
+
+    public boolean getAlternateExpression() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public boolean getAlternateFormula() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public XSSFComment getCellComment(int row, int column) {
+        if (sheetComments == null) return null;
+        else return (XSSFComment)getComments().findCellComment(row, column);
+    }
+
+    public XSSFHyperlink getHyperlink(int row, int column) {
+        String ref = new CellReference(row, column).formatAsString();
+        for(XSSFHyperlink hyperlink : hyperlinks) {
+            if(hyperlink.getCellRef().equals(ref)) {
+                return hyperlink;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Vertical page break information used for print layout view, page layout view, drawing print breaks
+     * in normal view, and for printing the worksheet.
+     *
+     * @return column indexes of all the vertical page breaks, never <code>null</code>
+     */
+    public int[] getColumnBreaks() {
+        if (!worksheet.isSetColBreaks() || worksheet.getColBreaks().sizeOfBrkArray() == 0) {
+            return new int[0];
+        }
+
+        CTBreak[] brkArray = worksheet.getColBreaks().getBrkArray();
+        int[] breaks = new int[brkArray.length];
+        for (int i = 0 ; i < brkArray.length ; i++) {
+            CTBreak brk = brkArray[i];
+            breaks[i] = (int)brk.getId();
+        }
+        return breaks;
+    }
+
+    protected CTPageBreak getSheetTypeColumnBreaks() {
+        if (worksheet.getColBreaks() == null) {
+            worksheet.setColBreaks(CTPageBreak.Factory.newInstance());
+        }
+        return worksheet.getColBreaks();
+    }
+
+    public int getColumnWidth(int columnIndex) {
+        return (int) columnHelper.getColumn(columnIndex, false).getWidth();
+    }
+    public short getColumnWidth(short column) {
+        return (short) getColumnWidth(column & 0xFFFF);
+    }
+
+    public int getDefaultColumnWidth() {
+        return (int)getSheetTypeSheetFormatPr().getDefaultColWidth();
+    }
+
+    public short getDefaultRowHeight() {
+        return (short) (getSheetTypeSheetFormatPr().getDefaultRowHeight() * 20);
+    }
+
+    protected CTSheetFormatPr getSheetTypeSheetFormatPr() {
+        if (worksheet.getSheetFormatPr() == null) {
+            worksheet.setSheetFormatPr(CTSheetFormatPr.Factory.newInstance());
+        }
+        return worksheet.getSheetFormatPr();
+    }
+
+    public float getDefaultRowHeightInPoints() {
+        return (short) getSheetTypeSheetFormatPr().getDefaultRowHeight();
+    }
+
+    public boolean getDialog() {
+        if (dialogsheet != null) {
+            return true;
+        }
+        return false;
+    }
+
+    public boolean getDisplayGuts() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    /**
+     * Gets the first row on the sheet
+     *
+     * @return the number of the first logical row on the sheet, zero based
+     */
+    public int getFirstRowNum() {
+        for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
+            Row row = it.next();
+            if (row != null) {
+                return row.getRowNum();
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Flag indicating whether the Fit to Page print option is enabled.
+     *
+     * @return <code>true</code>
+     */
+    public boolean getFitToPage() {
+        CTSheetPr sheetPr = getSheetTypeSheetPr();
+        CTPageSetUpPr psSetup = (sheetPr == null || !sheetPr.isSetPageSetUpPr()) ?
+                CTPageSetUpPr.Factory.newInstance() : sheetPr.getPageSetUpPr();
+        return psSetup.getFitToPage();
+    }
+
+    protected CTSheetPr getSheetTypeSheetPr() {
+        if (worksheet.getSheetPr() == null) {
+            worksheet.setSheetPr(CTSheetPr.Factory.newInstance());
+        }
+        return worksheet.getSheetPr();
+    }
+
+    protected CTHeaderFooter getSheetTypeHeaderFooter() {
+        if (worksheet.getHeaderFooter() == null) {
+            worksheet.setHeaderFooter(CTHeaderFooter.Factory.newInstance());
+        }
+        return worksheet.getHeaderFooter();
+    }
+
+
+
+    /**
+     * Returns the default footer for the sheet,
+     *  creating one as needed.
+     * You may also want to look at
+     *  {@link #getFirstFooter()},
+     *  {@link #getOddFooter()} and
+     *  {@link #getEvenFooter()}
+     */
+    public Footer getFooter() {
+        // The default footer is an odd footer
+        return getOddFooter();
+    }
+
+    /**
+     * Returns the default header for the sheet,
+     *  creating one as needed.
+     * You may also want to look at
+     *  {@link #getFirstHeader()},
+     *  {@link #getOddHeader()} and
+     *  {@link #getEvenHeader()}
+     */
+    public Header getHeader() {
+        // The default header is an odd header
+        return getOddHeader();
+    }
+
+    /**
+     * Returns the odd footer. Used on all pages unless
+     *  other footers also present, when used on only
+     *  odd pages.
+     */
+    public Footer getOddFooter() {
+        return new XSSFOddFooter(getSheetTypeHeaderFooter());
+    }
+    /**
+     * Returns the even footer. Not there by default, but
+     *  when set, used on even pages.
+     */
+    public Footer getEvenFooter() {
+        return new XSSFEvenFooter(getSheetTypeHeaderFooter());
+    }
+    /**
+     * Returns the first page footer. Not there by
+     *  default, but when set, used on the first page.
+     */
+    public Footer getFirstFooter() {
+        return new XSSFFirstFooter(getSheetTypeHeaderFooter());
+    }
+
+    /**
+     * Returns the odd header. Used on all pages unless
+     *  other headers also present, when used on only
+     *  odd pages.
+     */
+    public Header getOddHeader() {
+        return new XSSFOddHeader(getSheetTypeHeaderFooter());
+    }
+    /**
+     * Returns the even header. Not there by default, but
+     *  when set, used on even pages.
+     */
+    public Header getEvenHeader() {
+        return new XSSFEvenHeader(getSheetTypeHeaderFooter()
 );
-       }
-       /**
-        * Returns the first page header. Not there by
-        *  default, but when set, used on the first page.
-        */
-       public Header getFirstHeader() {
-               return new XSSFFirstHeader(getSheetTypeHeaderFooter());
-       }
-
-
-       public boolean getHorizontallyCenter() {
-               return getSheetTypePrintOptions().getHorizontalCentered();
-       }
-
-       protected CTPrintOptions getSheetTypePrintOptions() {
-               if (worksheet.getPrintOptions() == null) {
-                       worksheet.setPrintOptions(CTPrintOptions.Factory.newInstance());
-               }
-               return worksheet.getPrintOptions();
-       }
-
-       public int getLastRowNum() {
-               int lastRowNum = -1;
-               for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
-                       Row row = it.next();
-                       if (row != null) {
-                               lastRowNum = row.getRowNum();
-                       }
-               }
-               return lastRowNum;
-       }
-
-       public short getLeftCol() {
-               String cellRef = worksheet.getSheetViews().getSheetViewArray(0).getTopLeftCell();
-               CellReference cellReference = new CellReference(cellRef);
-               return (short)cellReference.getCol();
-       }
-
-       public double getMargin(short margin) {
-               CTPageMargins pageMargins = getSheetTypePageMargins();
-               switch (margin) {
-               case LeftMargin:
-                       return pageMargins.getLeft();
-               case RightMargin:
-                       return pageMargins.getRight();
-               case TopMargin:
-                       return pageMargins.getTop();
-               case BottomMargin:
-                       return pageMargins.getBottom();
-               case HeaderMargin:
-                       return pageMargins.getHeader();
-               case FooterMargin:
-                       return pageMargins.getFooter();
-               default :
-                       throw new RuntimeException( "Unknown margin constant:  " + margin );
-               }
-       }
-
-       protected CTPageMargins getSheetTypePageMargins() {
-               if (worksheet.getPageMargins() == null) {
-                       worksheet.setPageMargins(CTPageMargins.Factory.newInstance());
-               }
-               return worksheet.getPageMargins();
-       }
-
-       public Region getMergedRegionAt(int index) {
-               CTMergeCell ctMergeCell = getMergedCells().getMergeCellArray(index);
-               return new Region(ctMergeCell.getRef());
-       }
-
-       public int getNumMergedRegions() {
-               return getMergedCells().sizeOfMergeCellArray();
-       }
-
-       public int getNumHyperlinks() {
-               return hyperlinks.size();
-       }
-
-       public boolean getObjectProtect() {
-               // TODO Auto-generated method stub
-               return false;
-       }
-
-       public PaneInformation getPaneInformation() {
-               // TODO Auto-generated method stub
-               return null;
-       }
-
-       public short getPassword() {
-               // TODO Auto-generated method stub
-               return 0;
-       }
-
-       public int getPhysicalNumberOfRows() {
-               int counter = 0;
-               for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
-                       if (it.next() != null) {
-                               counter++;
-                       }
-               }
-               return counter;
-       }
-
-       public PrintSetup getPrintSetup() {
-               // TODO Auto-generated method stub
-               return null;
-       }
-
-       public boolean getProtect() {
-               // TODO Auto-generated method stub
-               return false;
-       }
-
-       /**
-        * Returns the logical row ( 0-based).  If you ask for a row that is not
-        * defined you get a null.  This is to say row 4 represents the fifth row on a sheet.
-        *
-        * @param rownum  row to get
-        * @return <code>XSSFRow</code> representing the rownumber or <code>null</code> if its not defined on the sheet
-        */
-       public XSSFRow getRow(int rownum) {
-               //TODO current implemenation is expensive, it should take O(1), not O(N)
-               for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
-                       Row row = it.next();
-                       if (row.getRowNum() == rownum) {
-                                return (XSSFRow)row;
-                       }
-               }
-               return null;
-       }
-
-       /**
-        * Horizontal page break information used for print layout view, page layout view, drawing print breaks in normal
-        *  view, and for printing the worksheet.
-        *
-        * @return row indexes of all the horizontal page breaks, never <code>null</code>
-        */
-       public int[] getRowBreaks() {
-               if (!worksheet.isSetRowBreaks() || worksheet.getRowBreaks().sizeOfBrkArray() == 0) {
-                       return new int[0];
-               }
-
-               CTBreak[] brkArray = worksheet.getRowBreaks().getBrkArray();
-               int[] breaks = new int[brkArray.length];
-               for (int i = 0 ; i < brkArray.length ; i++) {
-                       CTBreak brk = brkArray[i];
-                       breaks[i] = (int)brk.getId();
-               }
-               return breaks;
-       }
-
-       /**
-        * Flag indicating whether summary rows appear below detail in an outline, when applying an outline.
-        *
-        * <p>
-        * When true a summary row is inserted below the detailed data being summarized and a
-        * new outline level is established on that row.
-        * </p>
-        * <p>
-        * When false a summary row is inserted above the detailed data being summarized and a new outline level
-        * is established on that row.
-        * </p>
-        * @return <code>true</code> if row summaries appear below detail in the outline
-        */
-       public boolean getRowSumsBelow() {
-               CTSheetPr sheetPr = worksheet.getSheetPr();
-               CTOutlinePr outlinePr = (sheetPr != null && sheetPr.isSetOutlinePr())
-                               ? sheetPr.getOutlinePr() : CTOutlinePr.Factory.newInstance();
-               return outlinePr.getSummaryBelow();
-       }
-
-       /**
-        * Flag indicating whether summary rows appear below detail in an outline, when applying an outline.
-        *
-        * <p>
-        * When true a summary row is inserted below the detailed data being summarized and a
-        * new outline level is established on that row.
-        * </p>
-        * <p>
-        * When false a summary row is inserted above the detailed data being summarized and a new outline level
-        * is established on that row.
-        * </p>
-        * @param value <code>true</code> if row summaries appear below detail in the outline
-        */
-       public void setRowSumsBelow(boolean value) {
-               ensureOutlinePr().setSummaryBelow(value);
-       }
-
-       /**
-        * Flag indicating whether summary columns appear to the right of detail in an outline, when applying an outline.
-        *
-        * <p>
-        * When true a summary column is inserted to the right of the detailed data being summarized
-        * and a new outline level is established on that column.
-        * </p>
-        * <p>
-        * When false a summary column is inserted to the left of the detailed data being
-        * summarized and a new outline level is established on that column.
-        * </p>
-        * @return <code>true</code> if col summaries appear right of the detail in the outline
-        */
-       public boolean getRowSumsRight() {
-               CTSheetPr sheetPr = worksheet.getSheetPr();
-               CTOutlinePr outlinePr = (sheetPr != null && sheetPr.isSetOutlinePr())
-                               ? sheetPr.getOutlinePr() : CTOutlinePr.Factory.newInstance();
-               return outlinePr.getSummaryRight();
-       }
-
-       /**
-        * Flag indicating whether summary columns appear to the right of detail in an outline, when applying an outline.
-        *
-        * <p>
-        * When true a summary column is inserted to the right of the detailed data being summarized
-        * and a new outline level is established on that column.
-        * </p>
-        * <p>
-        * When false a summary column is inserted to the left of the detailed data being
-        * summarized and a new outline level is established on that column.
-        * </p>
-        * @param value <code>true</code> if col summaries appear right of the detail in the outline
-        */
-       public void setRowSumsRight(boolean value) {
-               ensureOutlinePr().setSummaryRight(value);
-       }
-
-
-       /**
-        * Ensure CTWorksheet.CTSheetPr.CTOutlinePr
-        */
-       private CTOutlinePr ensureOutlinePr(){
-               CTSheetPr sheetPr = worksheet.isSetSheetPr() ? worksheet.getSheetPr() : worksheet.addNewSheetPr();
-               CTOutlinePr outlinePr = sheetPr.isSetOutlinePr() ? sheetPr.getOutlinePr() : sheetPr.addNewOutlinePr();
-               return outlinePr;
-       }
-
-       /**
-        * A flag indicating whether scenarios are locked when the sheet is protected.
-        *
-        * @return true => protection enabled; false => protection disabled
-        */
-       public boolean getScenarioProtect() {
-               return getSheetTypeProtection().getScenarios();
-       }
-
-       protected CTSheetProtection getSheetTypeProtection() {
-               if (worksheet.getSheetProtection() == null) {
-                       worksheet.setSheetProtection(CTSheetProtection.Factory.newInstance());
-               }
-               return worksheet.getSheetProtection();
-       }
-
-       /**
-        * The top row in the visible view when the sheet is
-        * first viewed after opening it in a viewer
-        *
-        * @return integer indicating the rownum (0 based) of the top row
-        */
-       public short getTopRow() {
-               String cellRef = getSheetTypeSheetView().getTopLeftCell();
-               CellReference cellReference = new CellReference(cellRef);
-               return (short) cellReference.getRow();
-       }
-
-       /**
-        * Determine whether printed output for this sheet will be vertically centered.
-        *
-        * @return whether printed output for this sheet will be vertically centered.
-        */
-       public boolean getVerticallyCenter() {
-               return getSheetTypePrintOptions().getVerticalCentered();
-       }
-
-       /**
-        * Group between (0 based) columns
-        */
-       public void groupColumn(short fromColumn, short toColumn) {
-               groupColumn1Based(fromColumn+1, toColumn+1);
-       }
-       private void groupColumn1Based(int fromColumn, int toColumn) {
-               CTCols ctCols=worksheet.getColsArray(0);
-               CTCol ctCol=CTCol.Factory.newInstance();
-               ctCol.setMin(fromColumn);
-               ctCol.setMax(toColumn);
-               this.columnHelper.addCleanColIntoCols(ctCols, ctCol);
-               for(int index=fromColumn;index<=toColumn;index++){
-                       CTCol col=columnHelper.getColumn1Based(index, false);
-                       //col must exist
-                       short outlineLevel=col.getOutlineLevel();
-                       col.setOutlineLevel((short)(outlineLevel+1));
-                       index=(int)col.getMax();
-               }
-               worksheet.setColsArray(0,ctCols);
-               setSheetFormatPrOutlineLevelCol();
-       }
-
-       public void groupRow(int fromRow, int toRow) {
-               for(int i=fromRow;i<=toRow;i++){
-                       XSSFRow xrow = getRow(i-1);
-                       if(xrow == null){//create a new Row
-                                xrow = createRow(i-1);
-                       }
-                       CTRow ctrow=xrow.getCTRow();
-                       short outlineLevel=ctrow.getOutlineLevel();
-                       ctrow.setOutlineLevel((short)(outlineLevel+1));
-               }
-               setSheetFormatPrOutlineLevelRow();
-       }
+    }
+    /**
+     * Returns the first page header. Not there by
+     *  default, but when set, used on the first page.
+     */
+    public Header getFirstHeader() {
+        return new XSSFFirstHeader(getSheetTypeHeaderFooter());
+    }
+
+
+    public boolean getHorizontallyCenter() {
+        return getSheetTypePrintOptions().getHorizontalCentered();
+    }
+
+    protected CTPrintOptions getSheetTypePrintOptions() {
+        if (worksheet.getPrintOptions() == null) {
+            worksheet.setPrintOptions(CTPrintOptions.Factory.newInstance());
+        }
+        return worksheet.getPrintOptions();
+    }
+
+    public int getLastRowNum() {
+        int lastRowNum = -1;
+        for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
+            Row row = it.next();
+            if (row != null) {
+                lastRowNum = row.getRowNum();
+            }
+        }
+        return lastRowNum;
+    }
+
+    public short getLeftCol() {
+        String cellRef = worksheet.getSheetViews().getSheetViewArray(0).getTopLeftCell();
+        CellReference cellReference = new CellReference(cellRef);
+        return (short)cellReference.getCol();
+    }
+
+    public double getMargin(short margin) {
+        CTPageMargins pageMargins = getSheetTypePageMargins();
+        switch (margin) {
+        case LeftMargin:
+            return pageMargins.getLeft();
+        case RightMargin:
+            return pageMargins.getRight();
+        case TopMargin:
+            return pageMargins.getTop();
+        case BottomMargin:
+            return pageMargins.getBottom();
+        case HeaderMargin:
+            return pageMargins.getHeader();
+        case FooterMargin:
+            return pageMargins.getFooter();
+        default :
+            throw new POIXMLException( "Unknown margin constant:  " + margin );
+        }
+    }
+
+    protected CTPageMargins getSheetTypePageMargins() {
+        if (worksheet.getPageMargins() == null) {
+            worksheet.setPageMargins(CTPageMargins.Factory.newInstance());
+        }
+        return worksheet.getPageMargins();
+    }
+
+    public Region getMergedRegionAt(int index) {
+        CTMergeCell ctMergeCell = getMergedCells().getMergeCellArray(index);
+        return new Region(ctMergeCell.getRef());
+    }
+
+    public int getNumMergedRegions() {
+        return getMergedCells().sizeOfMergeCellArray();
+    }
+
+    public int getNumHyperlinks() {
+        return hyperlinks.size();
+    }
+
+    public boolean getObjectProtect() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public PaneInformation getPaneInformation() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public short getPassword() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    public int getPhysicalNumberOfRows() {
+        int counter = 0;
+        for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
+            if (it.next() != null) {
+                counter++;
+            }
+        }
+        return counter;
+    }
+
+    public PrintSetup getPrintSetup() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public boolean getProtect() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    /**
+     * Returns the logical row ( 0-based).  If you ask for a row that is not
+     * defined you get a null.  This is to say row 4 represents the fifth row on a sheet.
+     *
+     * @param rownum  row to get
+     * @return <code>XSSFRow</code> representing the rownumber or <code>null</code> if its not defined on the sheet
+     */
+    public XSSFRow getRow(int rownum) {
+        //TODO current implemenation is expensive, it should take O(1), not O(N)
+        for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
+            Row row = it.next();
+            if (row.getRowNum() == rownum) {
+                 return (XSSFRow)row;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Horizontal page break information used for print layout view, page layout view, drawing print breaks in normal
+     *  view, and for printing the worksheet.
+     *
+     * @return row indexes of all the horizontal page breaks, never <code>null</code>
+     */
+    public int[] getRowBreaks() {
+        if (!worksheet.isSetRowBreaks() || worksheet.getRowBreaks().sizeOfBrkArray() == 0) {
+            return new int[0];
+        }
+
+        CTBreak[] brkArray = worksheet.getRowBreaks().getBrkArray();
+        int[] breaks = new int[brkArray.length];
+        for (int i = 0 ; i < brkArray.length ; i++) {
+            CTBreak brk = brkArray[i];
+            breaks[i] = (int)brk.getId();
+        }
+        return breaks;
+    }
+
+    /**
+     * Flag indicating whether summary rows appear below detail in an outline, when applying an outline.
+     *
+     * <p>
+     * When true a summary row is inserted below the detailed data being summarized and a
+     * new outline level is established on that row.
+     * </p>
+     * <p>
+     * When false a summary row is inserted above the detailed data being summarized and a new outline level
+     * is established on that row.
+     * </p>
+     * @return <code>true</code> if row summaries appear below detail in the outline
+     */
+    public boolean getRowSumsBelow() {
+        CTSheetPr sheetPr = worksheet.getSheetPr();
+        CTOutlinePr outlinePr = (sheetPr != null && sheetPr.isSetOutlinePr())
+                ? sheetPr.getOutlinePr() : CTOutlinePr.Factory.newInstance();
+        return outlinePr.getSummaryBelow();
+    }
+
+    /**
+     * Flag indicating whether summary rows appear below detail in an outline, when applying an outline.
+     *
+     * <p>
+     * When true a summary row is inserted below the detailed data being summarized and a
+     * new outline level is established on that row.
+     * </p>
+     * <p>
+     * When false a summary row is inserted above the detailed data being summarized and a new outline level
+     * is established on that row.
+     * </p>
+     * @param value <code>true</code> if row summaries appear below detail in the outline
+     */
+    public void setRowSumsBelow(boolean value) {
+        ensureOutlinePr().setSummaryBelow(value);
+    }
+
+    /**
+     * Flag indicating whether summary columns appear to the right of detail in an outline, when applying an outline.
+     *
+     * <p>
+     * When true a summary column is inserted to the right of the detailed data being summarized
+     * and a new outline level is established on that column.
+     * </p>
+     * <p>
+     * When false a summary column is inserted to the left of the detailed data being
+     * summarized and a new outline level is established on that column.
+     * </p>
+     * @return <code>true</code> if col summaries appear right of the detail in the outline
+     */
+    public boolean getRowSumsRight() {
+        CTSheetPr sheetPr = worksheet.getSheetPr();
+        CTOutlinePr outlinePr = (sheetPr != null && sheetPr.isSetOutlinePr())
+                ? sheetPr.getOutlinePr() : CTOutlinePr.Factory.newInstance();
+        return outlinePr.getSummaryRight();
+    }
+
+    /**
+     * Flag indicating whether summary columns appear to the right of detail in an outline, when applying an outline.
+     *
+     * <p>
+     * When true a summary column is inserted to the right of the detailed data being summarized
+     * and a new outline level is established on that column.
+     * </p>
+     * <p>
+     * When false a summary column is inserted to the left of the detailed data being
+     * summarized and a new outline level is established on that column.
+     * </p>
+     * @param value <code>true</code> if col summaries appear right of the detail in the outline
+     */
+    public void setRowSumsRight(boolean value) {
+        ensureOutlinePr().setSummaryRight(value);
+    }
+
+
+    /**
+     * Ensure CTWorksheet.CTSheetPr.CTOutlinePr
+     */
+    private CTOutlinePr ensureOutlinePr(){
+        CTSheetPr sheetPr = worksheet.isSetSheetPr() ? worksheet.getSheetPr() : worksheet.addNewSheetPr();
+        CTOutlinePr outlinePr = sheetPr.isSetOutlinePr() ? sheetPr.getOutlinePr() : sheetPr.addNewOutlinePr();
+        return outlinePr;
+    }
+
+    /**
+     * A flag indicating whether scenarios are locked when the sheet is protected.
+     *
+     * @return true => protection enabled; false => protection disabled
+     */
+    public boolean getScenarioProtect() {
+        return getSheetTypeProtection().getScenarios();
+    }
+
+    protected CTSheetProtection getSheetTypeProtection() {
+        if (worksheet.getSheetProtection() == null) {
+            worksheet.setSheetProtection(CTSheetProtection.Factory.newInstance());
+        }
+        return worksheet.getSheetProtection();
+    }
+
+    /**
+     * The top row in the visible view when the sheet is
+     * first viewed after opening it in a viewer
+     *
+     * @return integer indicating the rownum (0 based) of the top row
+     */
+    public short getTopRow() {
+        String cellRef = getSheetTypeSheetView().getTopLeftCell();
+        CellReference cellReference = new CellReference(cellRef);
+        return (short) cellReference.getRow();
+    }
+
+    /**
+     * Determine whether printed output for this sheet will be vertically centered.
+     *
+     * @return whether printed output for this sheet will be vertically centered.
+     */
+    public boolean getVerticallyCenter() {
+        return getSheetTypePrintOptions().getVerticalCentered();
+    }
+
+    /**
+     * Group between (0 based) columns
+     */
+    public void groupColumn(short fromColumn, short toColumn) {
+        groupColumn1Based(fromColumn+1, toColumn+1);
+    }
+    private void groupColumn1Based(int fromColumn, int toColumn) {
+        CTCols ctCols=worksheet.getColsArray(0);
+        CTCol ctCol=CTCol.Factory.newInstance();
+        ctCol.setMin(fromColumn);
+        ctCol.setMax(toColumn);
+        this.columnHelper.addCleanColIntoCols(ctCols, ctCol);
+        for(int index=fromColumn;index<=toColumn;index++){
+            CTCol col=columnHelper.getColumn1Based(index, false);
+            //col must exist
+            short outlineLevel=col.getOutlineLevel();
+            col.setOutlineLevel((short)(outlineLevel+1));
+            index=(int)col.getMax();
+        }
+        worksheet.setColsArray(0,ctCols);
+        setSheetFormatPrOutlineLevelCol();
+    }
+
+    public void groupRow(int fromRow, int toRow) {
+          for(int i=fromRow;i<=toRow;i++){
+            XSSFRow xrow = getRow(i-1);
+            if(xrow == null){//create a new Row
+                 xrow = createRow(i-1);
+            }
+            CTRow ctrow=xrow.getCTRow();
+            short outlineLevel=ctrow.getOutlineLevel();
+            ctrow.setOutlineLevel((short)(outlineLevel+1));
+           }
+          setSheetFormatPrOutlineLevelRow();
+    }
 
    private short getMaxOutlineLevelRows(){
-               short outlineLevel=0;
-               for(Row r:rows){
-                       XSSFRow xrow=(XSSFRow)r;
-                       outlineLevel=xrow.getCTRow().getOutlineLevel()>outlineLevel? xrow.getCTRow().getOutlineLevel(): outlineLevel;
-               }
-               return outlineLevel;
-       }
-
-
-       private short getMaxOutlineLevelCols(){
-               CTCols ctCols=worksheet.getColsArray(0);
-               CTCol[]colArray=ctCols.getColArray();
-               short outlineLevel=0;
-               for(CTCol col: colArray){
-                       outlineLevel=col.getOutlineLevel()>outlineLevel? col.getOutlineLevel(): outlineLevel;
-               }
-               return outlineLevel;
-       }
-
-       /**
-        * Determines if there is a page break at the indicated column
-        */
-       public boolean isColumnBroken(short column) {
-               int[] colBreaks = getColumnBreaks();
-               for (int i = 0 ; i < colBreaks.length ; i++) {
-                       if (colBreaks[i] == column) {
-                               return true;
-                       }
-               }
-               return false;
-       }
-
-       public boolean isColumnHidden(int columnIndex) {
-               return columnHelper.getColumn(columnIndex, false).getHidden();
-       }
-       public boolean isColumnHidden(short column) {
-               return isColumnHidden(column & 0xFFFF);
-       }
-
-       public boolean isDisplayFormulas() {
-               return getSheetTypeSheetView().getShowFormulas();
-       }
-
-       public boolean isDisplayGridlines() {
-               return getSheetTypeSheetView().getShowGridLines();
-       }
-
-       public boolean isDisplayRowColHeadings() {
-               return getSheetTypeSheetView().getShowRowColHeaders();
-       }
-
-       public boolean isGridsPrinted() {
-               return isPrintGridlines();
-       }
-
-       public boolean isPrintGridlines() {
-               return getSheetTypePrintOptions().getGridLines();
-       }
-
-       /**
-        * Tests if there is a page break at the indicated row
-        *
-        * @param row index of the row to test
-        * @return <code>true</code> if there is a page break at the indicated row
-        */
-       public boolean isRowBroken(int row) {
-               int[] rowBreaks = getRowBreaks();
-               for (int i = 0 ; i < rowBreaks.length ; i++) {
-                       if (rowBreaks[i] == row) {
-                               return true;
-                       }
-               }
-               return false;
-       }
-
-       /**
-        * Sets a page break at the indicated row
-        */
-       public void setRowBreak(int row) {
-               CTPageBreak pgBreak = worksheet.isSetRowBreaks() ? worksheet.getRowBreaks() : worksheet.addNewRowBreaks();
-               if (! isRowBroken(row)) {
-                       CTBreak brk = pgBreak.addNewBrk();
-                       brk.setId(row);
-               }
-       }
-
-       /**
-        * Removes a page break at the indicated column
-        */
-       public void removeColumnBreak(short column) {
-               CTBreak[] brkArray = getSheetTypeColumnBreaks().getBrkArray();
-               for (int i = 0 ; i < brkArray.length ; i++) {
-                       if (brkArray[i].getId() == column) {
-                               getSheetTypeColumnBreaks().removeBrk(i);
-                       }
-               }
-       }
-
-       public void protectSheet(String password) {
-               // TODO Auto-generated method stub
-
-       }
-
-       public void removeMergedRegion(int index) {
-               CTMergeCell[] mergeCellsArray = new CTMergeCell[getMergedCells().sizeOfMergeCellArray() - 1];
-               for (int i = 0 ; i < getMergedCells().sizeOfMergeCellArray() ; i++) {
-                       if (i < index) {
-                               mergeCellsArray[i] = getMergedCells().getMergeCellArray(i);
-                       }
-                       else if (i > index) {
-                               mergeCellsArray[i - 1] = getMergedCells().getMergeCellArray(i);
-                       }
-               }
-               getMergedCells().setMergeCellArray(mergeCellsArray);
-       }
-
-       public void removeRow(Row row) {
-               int counter = 0;
-               int rowNum=row.getRowNum();
-               for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
-                       Row r = it.next();
-                       if (r.getRowNum() == rowNum) {
-                               it.remove();
-                               worksheet.getSheetData().removeRow(counter);
-                       }
-                       counter++;
-               }
-       }
-
-       /**
-        * Removes the page break at the indicated row
-        */
-       public void removeRowBreak(int row) {
-               CTPageBreak pgBreak = worksheet.isSetRowBreaks() ? worksheet.getRowBreaks() : worksheet.addNewRowBreaks();
-               CTBreak[] brkArray = pgBreak.getBrkArray();
-               for (int i = 0 ; i < brkArray.length ; i++) {
-                       if (brkArray[i].getId() == row) {
-                               pgBreak.removeBrk(i);
-                       }
-               }
-       }
-
-       public Iterator<Row> rowIterator() {
-               return rows.iterator();
-       }
-
-       /**
-        * Alias for {@link #rowIterator()} to
-        *  allow foreach loops
-        */
-       public Iterator<Row> iterator() {
-               return rowIterator();
-       }
-
-       public void setAlternativeExpression(boolean b) {
-               // TODO Auto-generated method stub
-
-       }
-
-       public void setAlternativeFormula(boolean b) {
-               // TODO Auto-generated method stub
-
-       }
-
-       /**
-        * Flag indicating whether the sheet displays Automatic Page Breaks.
-        *
-        * @return <code>true</code> if the sheet displays Automatic Page Breaks.
-        */
-        public boolean getAutobreaks() {
-               CTSheetPr sheetPr = getSheetTypeSheetPr();
-               CTPageSetUpPr psSetup = (sheetPr == null || !sheetPr.isSetPageSetUpPr()) ?
-                               CTPageSetUpPr.Factory.newInstance() : sheetPr.getPageSetUpPr();
-               return psSetup.getAutoPageBreaks();
-       }
-
-       /**
-        * Flag indicating whether the sheet displays Automatic Page Breaks.
-        *
-        * @param value <code>true</code> if the sheet displays Automatic Page Breaks.
-        */
-       public void setAutobreaks(boolean value) {
-               CTSheetPr sheetPr = getSheetTypeSheetPr();
-               CTPageSetUpPr psSetup = sheetPr.isSetPageSetUpPr() ? sheetPr.getPageSetUpPr() : sheetPr.addNewPageSetUpPr();
-               psSetup.setAutoPageBreaks(value);
-       }
-
-       public void setColumnBreak(short column) {
-               if (! isColumnBroken(column)) {
-                       CTBreak brk = getSheetTypeColumnBreaks().addNewBrk();
-                       brk.setId(column);
-               }
-       }
-
-       public void setColumnGroupCollapsed(short columnNumber, boolean collapsed) {
-               // TODO Auto-generated method stub
-
-       }
-
-       public void setColumnHidden(int columnIndex, boolean hidden) {
-               columnHelper.setColHidden(columnIndex, hidden);
-       }
-       public void setColumnHidden(short column, boolean hidden) {
-               setColumnHidden(column & 0xFFFF, hidden);
-       }
-
-       public void setColumnWidth(int columnIndex, int width) {
-               columnHelper.setColWidth(columnIndex, width);
-       }
-       public void setColumnWidth(short column, short width) {
-               setColumnWidth(column & 0xFFFF, width & 0xFFFF);
-       }
-
-       public void setDefaultColumnStyle(short column, CellStyle style) {
-               columnHelper.setColDefaultStyle(column, style);
-       }
-
-       public void setDefaultColumnWidth(int width) {
-               getSheetTypeSheetFormatPr().setDefaultColWidth(width);
-       }
-       public void setDefaultColumnWidth(short width) {
-               setDefaultColumnWidth(width & 0xFFFF);
-       }
-
-       public void setDefaultRowHeight(short height) {
-               getSheetTypeSheetFormatPr().setDefaultRowHeight(height / 20);
-
-       }
-
-       public void setDefaultRowHeightInPoints(float height) {
-               getSheetTypeSheetFormatPr().setDefaultRowHeight(height);
-
-       }
-
-       public void setDialog(boolean b) {
-               if(b && dialogsheet == null){
-                       CTDialogsheet dialogSheet = CTDialogsheet.Factory.newInstance();
-                       dialogsheet = dialogSheet;
-               }else{
-                       dialogsheet = null;
-               }
-       }
-
-       public void setDisplayFormulas(boolean show) {
-               getSheetTypeSheetView().setShowFormulas(show);
-       }
-
-       protected CTSheetView getSheetTypeSheetView() {
-               if (getDefaultSheetView() == null) {
-                       getSheetTypeSheetViews().setSheetViewArray(0, CTSheetView.Factory.newInstance());
-               }
-               return getDefaultSheetView();
-       }
-
-       public void setDisplayGridlines(boolean show) {
-               getSheetTypeSheetView().setShowGridLines(show);
-       }
-
-       public void setDisplayGuts(boolean b) {
-               // TODO Auto-generated method stub
-
-       }
-
-       public void setDisplayRowColHeadings(boolean show) {
-               getSheetTypeSheetView().setShowRowColHeaders(show);
-       }
-
-       public void setFitToPage(boolean b) {
-               getSheetTypePageSetUpPr().setFitToPage(b);
-       }
-
-       public void setGridsPrinted(boolean value) {
-               setPrintGridlines(value);
-       }
-
-       public void setHorizontallyCenter(boolean value) {
-               getSheetTypePrintOptions().setHorizontalCentered(value);
-       }
-
-       public void setMargin(short margin, double size) {
-               CTPageMargins pageMargins = getSheetTypePageMargins();
-               switch (margin) {
-               case LeftMargin:
-                       pageMargins.setLeft(size);
-               case RightMargin:
-                       pageMargins.setRight(size);
-               case TopMargin:
-                       pageMargins.setTop(size);
-               case BottomMargin:
-                       pageMargins.setBottom(size);
-               case HeaderMargin:
-                       pageMargins.setHeader(size);
-               case FooterMargin:
-                       pageMargins.setFooter(size);
-               }
-       }
-
-       public void setPrintGridlines(boolean newPrintGridlines) {
-               getSheetTypePrintOptions().setGridLines(newPrintGridlines);
-       }
-
-       public void setRowGroupCollapsed(int row, boolean collapse) {
-               // TODO Auto-generated method stub
-
-       }
-
-       public void setVerticallyCenter(boolean value) {
-               getSheetTypePrintOptions().setVerticalCentered(value);
-       }
-
-       /**
-        * Sets the zoom magnication for the sheet.  The zoom is expressed as a
-        * fraction.  For example to express a zoom of 75% use 3 for the numerator
-        * and 4 for the denominator.
-        *
-        * @param numerator      The numerator for the zoom magnification.
-        * @param denominator   The denominator for the zoom magnification.
-        * @see #setZoom(int)
-        */
-       public void setZoom(int numerator, int denominator) {
-               Float result = new Float(numerator)/new Float(denominator)*100;
-               setZoom(result.intValue());
-       }
-
-       /**
-        * Window zoom magnification for current view representing percent values.
-        * Valid values range from 10 to 400. Horizontal & Vertical scale together.
-        *
-        * For example:
-        * <pre>
-        * 10 - 10%
-        * 20 - 20%
-        * \85
-        * 100 - 100%
-        * \85
-        * 400 - 400%
-        * </pre>
-        *
-        * Current view can be Normal, Page Layout, or Page Break Preview.
-        *
-        * @param scale window zoom magnification
-        */
-       public void setZoom(int scale) {
-               getSheetTypeSheetView().setZoomScale(scale);
-       }
-
-       /**
-        * Zoom magnification to use when in normal view, representing percent values.
-        * Valid values range from 10 to 400. Horizontal & Vertical scale together.
-        *
-        * For example:
-        * <pre>
-        * 10 - 10%
-        * 20 - 20%
-        * \85
-        * 100 - 100%
-        * \85
-        * 400 - 400%
-        * </pre>
-        *
-        * Applies for worksheet sheet type only; zero implies the automatic setting.
-        *
-        * @param scale window zoom magnification
-        */
-       public void setZoomNormal(int scale) {
-               getSheetTypeSheetView().setZoomScaleNormal(scale);
-       }
-
-       /**
-        * Zoom magnification to use when in page layout view, representing percent values.
-        * Valid values range from 10 to 400. Horizontal & Vertical scale together.
-        *
-        * For example:
-        * <pre>
-        * 10 - 10%
-        * 20 - 20%
-        * \85
-        * 100 - 100%
-        * \85
-        * 400 - 400%
-        * </pre>
-        *
-        * Applies for worksheet sheet type only; zero implies the automatic setting.
-        *
-        * @param scale
-        */
-       public void setZoomPageLayoutView(int scale) {
-               getSheetTypeSheetView().setZoomScalePageLayoutView(scale);
-       }
-
-       /**
-        * Zoom magnification to use when in page break preview, representing percent values.
-        * Valid values range from 10 to 400. Horizontal & Vertical scale together.
-        *
-        * For example:
-        * <pre>
-        * 10 - 10%
-        * 20 - 20%
-        * \85
-        * 100 - 100%
-        * \85
-        * 400 - 400%
-        * </pre>
-        *
-        * Applies for worksheet only; zero implies the automatic setting.
-        *
-        * @param scale
-        */
-       public void setZoomSheetLayoutView(int scale) {
-               getSheetTypeSheetView().setZoomScaleSheetLayoutView(scale);
-       }
-
-       public void shiftRows(int startRow, int endRow, int n) {
-               shiftRows(startRow, endRow, n, false, false);
-       }
-
-       public void shiftRows(int startRow, int endRow, int n, boolean copyRowHeight, boolean resetOriginalRowHeight) {
-               for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
-                       Row row = it.next();
-                       if (!copyRowHeight) {
-                               row.setHeight((short)0);
-                       }
-                       if (resetOriginalRowHeight && getDefaultRowHeight() >= 0) {
-                               row.setHeight(getDefaultRowHeight());
-                       }
-                       if (removeRow(startRow, endRow, n, row.getRowNum())) {
-                               it.remove();
-                       }
-                       else if (row.getRowNum() >= startRow && row.getRowNum() <= endRow) {
-                               row.setRowNum(row.getRowNum() + n);
-                       }
-               }
-       }
-
-       /**
-        * Location of the top left visible cell Location of the top left visible cell in the bottom right
-        * pane (when in Left-to-Right mode).
-        *
-        * @param toprow the top row to show in desktop window pane
-        * @param leftcol the left column to show in desktop window pane
-        */
-       public void showInPane(short toprow, short leftcol) {
-               CellReference cellReference = new CellReference(toprow, leftcol);
-               String cellRef = cellReference.formatAsString();
-               getSheetTypeSheetView().setTopLeftCell(cellRef);
-       }
-
-       public void ungroupColumn(short fromColumn, short toColumn) {
-               CTCols cols=worksheet.getColsArray(0);
-               for(int index=fromColumn;index<=toColumn;index++){
-                       CTCol col=columnHelper.getColumn(index, false);
-                       if(col!=null){
-                               short outlineLevel=col.getOutlineLevel();
-                               col.setOutlineLevel((short)(outlineLevel-1));
-                               index=(int)col.getMax();
-
-                               if(col.getOutlineLevel()<=0){
-                                       int colIndex=columnHelper.getIndexOfColumn(cols,col);
-                                       worksheet.getColsArray(0).removeCol(colIndex);
-                               }
-                       }
-               }
-               worksheet.setColsArray(0,cols);
-               setSheetFormatPrOutlineLevelCol();
-       }
-
-       public void ungroupRow(int fromRow, int toRow) {
-               for(int i=fromRow;i<=toRow;i++){
-                       XSSFRow xrow=(XSSFRow)getRow(i-1);
-                       if(xrow!=null){
-                               CTRow ctrow=xrow.getCTRow();
-                               short outlinelevel=ctrow.getOutlineLevel();
-                               ctrow.setOutlineLevel((short)(outlinelevel-1));
-                               //remove a row only if the row has no cell and if the outline level is 0
-                               if(ctrow.getOutlineLevel()==0 && xrow.getFirstCellNum()==-1){
-                                       removeRow(xrow);
-                               }
-                       }
-               }
-               setSheetFormatPrOutlineLevelRow();
-       }
-
-       private void setSheetFormatPrOutlineLevelRow(){
-               short maxLevelRow=getMaxOutlineLevelRows();
-               getSheetTypeSheetFormatPr().setOutlineLevelRow((short)(maxLevelRow));
-       }
-
-       private void setSheetFormatPrOutlineLevelCol(){
-               short maxLevelCol=getMaxOutlineLevelCols();
-               getSheetTypeSheetFormatPr().setOutlineLevelCol((short)(maxLevelCol));
-       }
-
-       protected CTSheetViews getSheetTypeSheetViews() {
-               if (worksheet.getSheetViews() == null) {
-                       worksheet.setSheetViews(CTSheetViews.Factory.newInstance());
-                       worksheet.getSheetViews().addNewSheetView();
-               }
-               return worksheet.getSheetViews();
-       }
-
-       /**
-        * Returns a flag indicating whether this sheet is selected.
-        * <p>
-        * When only 1 sheet is selected and active, this value should be in synch with the activeTab value.
-        * In case of a conflict, the Start Part setting wins and sets the active sheet tab.
-        * </p>
-        * Note: multiple sheets can be selected, but only one sheet can be active at one time.
-        *
-        * @return <code>true</code> if this sheet is selected
-        */
-       public boolean isSelected() {
-               CTSheetView view = getDefaultSheetView();
-               return view != null && view.getTabSelected();
-       }
-
-       /**
-        * Sets a flag indicating whether this sheet is selected.
-        *
-        * <p>
-        * When only 1 sheet is selected and active, this value should be in synch with the activeTab value.
-        * In case of a conflict, the Start Part setting wins and sets the active sheet tab.
-        * </p>
-        * Note: multiple sheets can be selected, but only one sheet can be active at one time.
-        *
-        * @param value <code>true</code> if this sheet is selected
-        */
-       public void setSelected(boolean value) {
-               CTSheetViews views = getSheetTypeSheetViews();
-               for (CTSheetView view : views.getSheetViewArray()) {
-                       view.setTabSelected(value);
-               }
-       }
-
-       /**
-        * Assign a cell comment to a cell region in this worksheet
-        *
-        * @param cellRef cell region
-        * @param comment the comment to assign
-        */
-       public void setCellComment(String cellRef, XSSFComment comment) {
-               CellReference cellReference = new CellReference(cellRef);
-
-               comment.setRow(cellReference.getRow());
-               comment.setColumn(cellReference.getCol());
-       }
-
-       protected void setCellHyperlink(XSSFHyperlink hyperlink) {
-               hyperlinks.add(hyperlink);
-       }
-
-       /**
-        * Return location of the active cell, e.g. <code>A1</code>.
-        *
-        * @return the location of the active cell.
-        */
-       public String getActiveCell() {
-               return getSheetTypeSelection().getActiveCell();
-       }
-
-       /**
-        * Sets location of the active cell
-        *
-        * @param cellRef the location of the active cell, e.g. <code>A1</code>..
-        */
-       public void setActiveCell(String cellRef) {
-               CTSelection ctsel = getSheetTypeSelection();
-               ctsel.setActiveCell(cellRef);
-               ctsel.setSqref(Arrays.asList(cellRef));
-       }
-
-       /**
-        * Does this sheet have any comments on it? We need to know,
-        *  so we can decide about writing it to disk or not
-        */
-       public boolean hasComments() {
-               if(sheetComments == null) { return false; }
-               return (sheetComments.getNumberOfComments() > 0);
-       }
-       protected int getNumberOfComments() {
-               if(sheetComments == null) { return 0; }
-               return sheetComments.getNumberOfComments();
-       }
-
-       private CTSelection getSheetTypeSelection() {
-               if (getSheetTypeSheetView().sizeOfSelectionArray() == 0) {
-                       getSheetTypeSheetView().insertNewSelection(0);
-               }
-               return getSheetTypeSheetView().getSelectionArray(0);
-       }
-
-       /**
-        * Return the default sheet view. This is the last one if the sheet's views, according to sec. 3.3.1.83
-        * of the OOXML spec: "A single sheet view definition. When more than 1 sheet view is defined in the file,
-        * it means that when opening the workbook, each sheet view corresponds to a separate window within the
-        * spreadsheet application, where each window is showing the particular sheet. containing the same
-        * workbookViewId value, the last sheetView definition is loaded, and the others are discarded.
-        * When multiple windows are viewing the same sheet, multiple sheetView elements (with corresponding
-        * workbookView entries) are saved."
-        */
-       private CTSheetView getDefaultSheetView() {
-               CTSheetViews views = getSheetTypeSheetViews();
-               if (views == null || views.getSheetViewArray() == null || views.getSheetViewArray().length <= 0) {
-                       return null;
-               }
-               return views.getSheetViewArray(views.getSheetViewArray().length - 1);
-       }
-
-       protected XSSFSheet cloneSheet() {
-               XSSFSheet newSheet = new XSSFSheet(this.workbook);
-               newSheet.setSheet((CTSheet)sheet.copy());
-               return newSheet;
-       }
-
-       private void setSheet(CTSheet sheet) {
-               this.sheet = sheet;
-       }
-
-       private CommentsSource getComments() {
-               if (sheetComments == null) {
-                       sheetComments = new CommentsTable();
-               }
-               return sheetComments;
-       }
-       /**
-        * Returns the sheet's comments object if there is one,
-        *  or null if not
-        */
-       protected CommentsSource getCommentsSourceIfExists() {
-               return sheetComments;
-       }
-
-       private void addNewMergeCell(Region region) {
-               ctMergeCells = getMergedCells();
-               CTMergeCell ctMergeCell = ctMergeCells.addNewMergeCell();
-               ctMergeCell.setRef(region.getRegionRef());
-       }
-
-       private CTMergeCells getMergedCells() {
-               if (ctMergeCells == null) {
-                       ctMergeCells = worksheet.addNewMergeCells();
-               }
-               return ctMergeCells;
-       }
-
-       private CTPageSetUpPr getSheetTypePageSetUpPr() {
-               CTSheetPr sheetPr = getSheetTypeSheetPr();
-               return sheetPr.isSetPageSetUpPr() ? sheetPr.getPageSetUpPr() : sheetPr.addNewPageSetUpPr();
-       }
-
-       private boolean removeRow(int startRow, int endRow, int n, int rownum) {
-               if (rownum >= (startRow + n) && rownum <= (endRow + n)) {
-                       if (n > 0 && rownum > endRow) {
-                               return true;
-                       }
-                       else if (n < 0 && rownum < startRow) {
-                               return true;
-                       }
-               }
-               return false;
-       }
-
-       private CTPane getPane() {
-               if (getDefaultSheetView().getPane() == null) {
-                       getDefaultSheetView().addNewPane();
-               }
-               return getDefaultSheetView().getPane();
-       }
+        short outlineLevel=0;
+        for(Row r:rows){
+            XSSFRow xrow=(XSSFRow)r;
+            outlineLevel=xrow.getCTRow().getOutlineLevel()>outlineLevel? xrow.getCTRow().getOutlineLevel(): outlineLevel;
+        }
+        return outlineLevel;
+    }
+
+
+    private short getMaxOutlineLevelCols(){
+        CTCols ctCols=worksheet.getColsArray(0);
+        CTCol[]colArray=ctCols.getColArray();
+        short outlineLevel=0;
+        for(CTCol col: colArray){
+            outlineLevel=col.getOutlineLevel()>outlineLevel? col.getOutlineLevel(): outlineLevel;
+        }
+        return outlineLevel;
+    }
+
+    /**
+     * Determines if there is a page break at the indicated column
+     */
+    public boolean isColumnBroken(short column) {
+        int[] colBreaks = getColumnBreaks();
+        for (int i = 0 ; i < colBreaks.length ; i++) {
+            if (colBreaks[i] == column) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean isColumnHidden(int columnIndex) {
+        return columnHelper.getColumn(columnIndex, false).getHidden();
+    }
+    public boolean isColumnHidden(short column) {
+        return isColumnHidden(column & 0xFFFF);
+    }
+
+    public boolean isDisplayFormulas() {
+        return getSheetTypeSheetView().getShowFormulas();
+    }
+
+    public boolean isDisplayGridlines() {
+        return getSheetTypeSheetView().getShowGridLines();
+    }
+
+    public boolean isDisplayRowColHeadings() {
+        return getSheetTypeSheetView().getShowRowColHeaders();
+    }
+
+    public boolean isGridsPrinted() {
+        return isPrintGridlines();
+    }
+
+    public boolean isPrintGridlines() {
+        return getSheetTypePrintOptions().getGridLines();
+    }
+
+    /**
+     * Tests if there is a page break at the indicated row
+     *
+     * @param row index of the row to test
+     * @return <code>true</code> if there is a page break at the indicated row
+     */
+    public boolean isRowBroken(int row) {
+        int[] rowBreaks = getRowBreaks();
+        for (int i = 0 ; i < rowBreaks.length ; i++) {
+            if (rowBreaks[i] == row) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Sets a page break at the indicated row
+     */
+    public void setRowBreak(int row) {
+        CTPageBreak pgBreak = worksheet.isSetRowBreaks() ? worksheet.getRowBreaks() : worksheet.addNewRowBreaks();
+        if (! isRowBroken(row)) {
+            CTBreak brk = pgBreak.addNewBrk();
+            brk.setId(row);
+        }
+    }
+
+    /**
+     * Removes a page break at the indicated column
+     */
+    public void removeColumnBreak(short column) {
+        CTBreak[] brkArray = getSheetTypeColumnBreaks().getBrkArray();
+        for (int i = 0 ; i < brkArray.length ; i++) {
+            if (brkArray[i].getId() == column) {
+                getSheetTypeColumnBreaks().removeBrk(i);
+            }
+        }
+    }
+
+    public void protectSheet(String password) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void removeMergedRegion(int index) {
+        CTMergeCell[] mergeCellsArray = new CTMergeCell[getMergedCells().sizeOfMergeCellArray() - 1];
+        for (int i = 0 ; i < getMergedCells().sizeOfMergeCellArray() ; i++) {
+            if (i < index) {
+                mergeCellsArray[i] = getMergedCells().getMergeCellArray(i);
+            }
+            else if (i > index) {
+                mergeCellsArray[i - 1] = getMergedCells().getMergeCellArray(i);
+            }
+        }
+        getMergedCells().setMergeCellArray(mergeCellsArray);
+    }
+
+    public void removeRow(Row row) {
+        int counter = 0;
+        int rowNum=row.getRowNum();
+        for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
+            Row r = it.next();
+            if (r.getRowNum() == rowNum) {
+                it.remove();
+                worksheet.getSheetData().removeRow(counter);
+            }
+            counter++;
+        }
+    }
+
+    /**
+     * Removes the page break at the indicated row
+     */
+    public void removeRowBreak(int row) {
+        CTPageBreak pgBreak = worksheet.isSetRowBreaks() ? worksheet.getRowBreaks() : worksheet.addNewRowBreaks();
+        CTBreak[] brkArray = pgBreak.getBrkArray();
+        for (int i = 0 ; i < brkArray.length ; i++) {
+            if (brkArray[i].getId() == row) {
+                pgBreak.removeBrk(i);
+            }
+        }
+    }
+
+    public Iterator<Row> rowIterator() {
+        return rows.iterator();
+    }
+
+    /**
+     * Alias for {@link #rowIterator()} to
+     *  allow foreach loops
+     */
+    public Iterator<Row> iterator() {
+        return rowIterator();
+    }
+
+    public void setAlternativeExpression(boolean b) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void setAlternativeFormula(boolean b) {
+        // TODO Auto-generated method stub
+
+    }
+
+    /**
+     * Flag indicating whether the sheet displays Automatic Page Breaks.
+     *
+     * @return <code>true</code> if the sheet displays Automatic Page Breaks.
+     */
+     public boolean getAutobreaks() {
+        CTSheetPr sheetPr = getSheetTypeSheetPr();
+        CTPageSetUpPr psSetup = (sheetPr == null || !sheetPr.isSetPageSetUpPr()) ?
+                CTPageSetUpPr.Factory.newInstance() : sheetPr.getPageSetUpPr();
+        return psSetup.getAutoPageBreaks();
+    }
+
+    /**
+     * Flag indicating whether the sheet displays Automatic Page Breaks.
+     *
+     * @param value <code>true</code> if the sheet displays Automatic Page Breaks.
+     */
+    public void setAutobreaks(boolean value) {
+        CTSheetPr sheetPr = getSheetTypeSheetPr();
+        CTPageSetUpPr psSetup = sheetPr.isSetPageSetUpPr() ? sheetPr.getPageSetUpPr() : sheetPr.addNewPageSetUpPr();
+        psSetup.setAutoPageBreaks(value);
+    }
+
+    public void setColumnBreak(short column) {
+        if (! isColumnBroken(column)) {
+            CTBreak brk = getSheetTypeColumnBreaks().addNewBrk();
+            brk.setId(column);
+        }
+    }
+
+    public void setColumnGroupCollapsed(short columnNumber, boolean collapsed) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void setColumnHidden(int columnIndex, boolean hidden) {
+        columnHelper.setColHidden(columnIndex, hidden);
+    }
+    public void setColumnHidden(short column, boolean hidden) {
+        setColumnHidden(column & 0xFFFF, hidden);
+    }
+
+    public void setColumnWidth(int columnIndex, int width) {
+        columnHelper.setColWidth(columnIndex, width);
+    }
+    public void setColumnWidth(short column, short width) {
+        setColumnWidth(column & 0xFFFF, width & 0xFFFF);
+    }
+
+    public void setDefaultColumnStyle(short column, CellStyle style) {
+        columnHelper.setColDefaultStyle(column, style);
+    }
+
+    public void setDefaultColumnWidth(int width) {
+        getSheetTypeSheetFormatPr().setDefaultColWidth(width);
+    }
+    public void setDefaultColumnWidth(short width) {
+        setDefaultColumnWidth(width & 0xFFFF);
+    }
+
+    public void setDefaultRowHeight(short height) {
+        getSheetTypeSheetFormatPr().setDefaultRowHeight(height / 20);
+
+    }
+
+    public void setDefaultRowHeightInPoints(float height) {
+        getSheetTypeSheetFormatPr().setDefaultRowHeight(height);
+
+    }
+
+    public void setDialog(boolean b) {
+        if(b && dialogsheet == null){
+            CTDialogsheet dialogSheet = CTDialogsheet.Factory.newInstance();
+            dialogsheet = dialogSheet;
+        }else{
+            dialogsheet = null;
+        }
+    }
+
+    public void setDisplayFormulas(boolean show) {
+        getSheetTypeSheetView().setShowFormulas(show);
+    }
+
+    protected CTSheetView getSheetTypeSheetView() {
+        if (getDefaultSheetView() == null) {
+            getSheetTypeSheetViews().setSheetViewArray(0, CTSheetView.Factory.newInstance());
+        }
+        return getDefaultSheetView();
+    }
+
+    public void setDisplayGridlines(boolean show) {
+        getSheetTypeSheetView().setShowGridLines(show);
+    }
+
+    public void setDisplayGuts(boolean b) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void setDisplayRowColHeadings(boolean show) {
+        getSheetTypeSheetView().setShowRowColHeaders(show);
+    }
+
+    public void setFitToPage(boolean b) {
+        getSheetTypePageSetUpPr().setFitToPage(b);
+    }
+
+    public void setGridsPrinted(boolean value) {
+        setPrintGridlines(value);
+    }
+
+    public void setHorizontallyCenter(boolean value) {
+        getSheetTypePrintOptions().setHorizontalCentered(value);
+    }
+
+    public void setMargin(short margin, double size) {
+        CTPageMargins pageMargins = getSheetTypePageMargins();
+        switch (margin) {
+        case LeftMargin:
+            pageMargins.setLeft(size);
+        case RightMargin:
+            pageMargins.setRight(size);
+        case TopMargin:
+            pageMargins.setTop(size);
+        case BottomMargin:
+            pageMargins.setBottom(size);
+        case HeaderMargin:
+            pageMargins.setHeader(size);
+        case FooterMargin:
+            pageMargins.setFooter(size);
+        }
+    }
+
+    public void setPrintGridlines(boolean newPrintGridlines) {
+        getSheetTypePrintOptions().setGridLines(newPrintGridlines);
+    }
+
+    public void setRowGroupCollapsed(int row, boolean collapse) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void setVerticallyCenter(boolean value) {
+        getSheetTypePrintOptions().setVerticalCentered(value);
+    }
+
+    /**
+     * Sets the zoom magnication for the sheet.  The zoom is expressed as a
+     * fraction.  For example to express a zoom of 75% use 3 for the numerator
+     * and 4 for the denominator.
+     *
+     * @param numerator         The numerator for the zoom magnification.
+     * @param denominator   The denominator for the zoom magnification.
+     * @see #setZoom(int)
+     */
+    public void setZoom(int numerator, int denominator) {
+        Float result = new Float(numerator)/new Float(denominator)*100;
+        setZoom(result.intValue());
+    }
+
+    /**
+     * Window zoom magnification for current view representing percent values.
+     * Valid values range from 10 to 400. Horizontal & Vertical scale together.
+     *
+     * For example:
+     * <pre>
+     * 10 - 10%
+     * 20 - 20%
+     * \85
+     * 100 - 100%
+     * \85
+     * 400 - 400%
+     * </pre>
+     *
+     * Current view can be Normal, Page Layout, or Page Break Preview.
+     *
+     * @param scale window zoom magnification
+     */
+    public void setZoom(int scale) {
+        getSheetTypeSheetView().setZoomScale(scale);
+    }
+
+    /**
+     * Zoom magnification to use when in normal view, representing percent values.
+     * Valid values range from 10 to 400. Horizontal & Vertical scale together.
+     *
+     * For example:
+     * <pre>
+     * 10 - 10%
+     * 20 - 20%
+     * \85
+     * 100 - 100%
+     * \85
+     * 400 - 400%
+     * </pre>
+     *
+     * Applies for worksheet sheet type only; zero implies the automatic setting.
+     *
+     * @param scale window zoom magnification
+     */
+    public void setZoomNormal(int scale) {
+        getSheetTypeSheetView().setZoomScaleNormal(scale);
+    }
+
+    /**
+     * Zoom magnification to use when in page layout view, representing percent values.
+     * Valid values range from 10 to 400. Horizontal & Vertical scale together.
+     *
+     * For example:
+     * <pre>
+     * 10 - 10%
+     * 20 - 20%
+     * \85
+     * 100 - 100%
+     * \85
+     * 400 - 400%
+     * </pre>
+     *
+     * Applies for worksheet sheet type only; zero implies the automatic setting.
+     *
+     * @param scale
+     */
+    public void setZoomPageLayoutView(int scale) {
+        getSheetTypeSheetView().setZoomScalePageLayoutView(scale);
+    }
+
+    /**
+     * Zoom magnification to use when in page break preview, representing percent values.
+     * Valid values range from 10 to 400. Horizontal & Vertical scale together.
+     *
+     * For example:
+     * <pre>
+     * 10 - 10%
+     * 20 - 20%
+     * \85
+     * 100 - 100%
+     * \85
+     * 400 - 400%
+     * </pre>
+     *
+     * Applies for worksheet only; zero implies the automatic setting.
+     *
+     * @param scale
+     */
+    public void setZoomSheetLayoutView(int scale) {
+        getSheetTypeSheetView().setZoomScaleSheetLayoutView(scale);
+    }
+
+    public void shiftRows(int startRow, int endRow, int n) {
+        shiftRows(startRow, endRow, n, false, false);
+    }
+
+    public void shiftRows(int startRow, int endRow, int n, boolean copyRowHeight, boolean resetOriginalRowHeight) {
+        for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
+            Row row = it.next();
+            if (!copyRowHeight) {
+                row.setHeight((short)0);
+            }
+            if (resetOriginalRowHeight && getDefaultRowHeight() >= 0) {
+                row.setHeight(getDefaultRowHeight());
+            }
+            if (removeRow(startRow, endRow, n, row.getRowNum())) {
+                it.remove();
+            }
+            else if (row.getRowNum() >= startRow && row.getRowNum() <= endRow) {
+                row.setRowNum(row.getRowNum() + n);
+            }
+        }
+    }
+
+    /**
+     * Location of the top left visible cell Location of the top left visible cell in the bottom right
+     * pane (when in Left-to-Right mode).
+     *
+     * @param toprow the top row to show in desktop window pane
+     * @param leftcol the left column to show in desktop window pane
+     */
+    public void showInPane(short toprow, short leftcol) {
+        CellReference cellReference = new CellReference(toprow, leftcol);
+        String cellRef = cellReference.formatAsString();
+        getSheetTypeSheetView().setTopLeftCell(cellRef);
+    }
+
+    public void ungroupColumn(short fromColumn, short toColumn) {
+        CTCols cols=worksheet.getColsArray(0);
+        for(int index=fromColumn;index<=toColumn;index++){
+            CTCol col=columnHelper.getColumn(index, false);
+            if(col!=null){
+                short outlineLevel=col.getOutlineLevel();
+                col.setOutlineLevel((short)(outlineLevel-1));
+                index=(int)col.getMax();
+
+                if(col.getOutlineLevel()<=0){
+                    int colIndex=columnHelper.getIndexOfColumn(cols,col);
+                    worksheet.getColsArray(0).removeCol(colIndex);
+                }
+            }
+        }
+        worksheet.setColsArray(0,cols);
+        setSheetFormatPrOutlineLevelCol();
+    }
+
+    public void ungroupRow(int fromRow, int toRow) {
+        for(int i=fromRow;i<=toRow;i++){
+            XSSFRow xrow=(XSSFRow)getRow(i-1);
+            if(xrow!=null){
+                CTRow ctrow=xrow.getCTRow();
+                short outlinelevel=ctrow.getOutlineLevel();
+                ctrow.setOutlineLevel((short)(outlinelevel-1));
+                //remove a row only if the row has no cell and if the outline level is 0
+                if(ctrow.getOutlineLevel()==0 && xrow.getFirstCellNum()==-1){
+                    removeRow(xrow);
+                }
+            }
+        }
+        setSheetFormatPrOutlineLevelRow();
+    }
+
+    private void setSheetFormatPrOutlineLevelRow(){
+        short maxLevelRow=getMaxOutlineLevelRows();
+        getSheetTypeSheetFormatPr().setOutlineLevelRow((short)(maxLevelRow));
+    }
+
+    private void setSheetFormatPrOutlineLevelCol(){
+        short maxLevelCol=getMaxOutlineLevelCols();
+        getSheetTypeSheetFormatPr().setOutlineLevelCol((short)(maxLevelCol));
+    }
+
+    protected CTSheetViews getSheetTypeSheetViews() {
+        if (worksheet.getSheetViews() == null) {
+            worksheet.setSheetViews(CTSheetViews.Factory.newInstance());
+            worksheet.getSheetViews().addNewSheetView();
+        }
+        return worksheet.getSheetViews();
+    }
+
+    /**
+     * Returns a flag indicating whether this sheet is selected.
+     * <p>
+     * When only 1 sheet is selected and active, this value should be in synch with the activeTab value.
+     * In case of a conflict, the Start Part setting wins and sets the active sheet tab.
+     * </p>
+     * Note: multiple sheets can be selected, but only one sheet can be active at one time.
+     *
+     * @return <code>true</code> if this sheet is selected
+     */
+    public boolean isSelected() {
+        CTSheetView view = getDefaultSheetView();
+        return view != null && view.getTabSelected();
+    }
+
+    /**
+     * Sets a flag indicating whether this sheet is selected.
+     *
+     * <p>
+     * When only 1 sheet is selected and active, this value should be in synch with the activeTab value.
+     * In case of a conflict, the Start Part setting wins and sets the active sheet tab.
+     * </p>
+     * Note: multiple sheets can be selected, but only one sheet can be active at one time.
+     *
+     * @param value <code>true</code> if this sheet is selected
+     */
+    public void setSelected(boolean value) {
+        CTSheetViews views = getSheetTypeSheetViews();
+        for (CTSheetView view : views.getSheetViewArray()) {
+            view.setTabSelected(value);
+        }
+    }
+
+    /**
+     * Assign a cell comment to a cell region in this worksheet
+     *
+     * @param cellRef cell region
+     * @param comment the comment to assign
+     */
+    public void setCellComment(String cellRef, XSSFComment comment) {
+        CellReference cellReference = new CellReference(cellRef);
+
+        comment.setRow(cellReference.getRow());
+        comment.setColumn(cellReference.getCol());
+    }
+
+    protected void setCellHyperlink(XSSFHyperlink hyperlink) {
+        hyperlinks.add(hyperlink);
+    }
+
+    /**
+     * Return location of the active cell, e.g. <code>A1</code>.
+     *
+     * @return the location of the active cell.
+     */
+    public String getActiveCell() {
+        return getSheetTypeSelection().getActiveCell();
+    }
+
+    /**
+     * Sets location of the active cell
+     *
+     * @param cellRef the location of the active cell, e.g. <code>A1</code>..
+     */
+    public void setActiveCell(String cellRef) {
+        CTSelection ctsel = getSheetTypeSelection();
+        ctsel.setActiveCell(cellRef);
+        ctsel.setSqref(Arrays.asList(cellRef));
+    }
+
+    /**
+     * Does this sheet have any comments on it? We need to know,
+     *  so we can decide about writing it to disk or not
+     */
+    public boolean hasComments() {
+        if(sheetComments == null) { return false; }
+        return (sheetComments.getNumberOfComments() > 0);
+    }
+    protected int getNumberOfComments() {
+        if(sheetComments == null) { return 0; }
+        return sheetComments.getNumberOfComments();
+    }
+
+    private CTSelection getSheetTypeSelection() {
+        if (getSheetTypeSheetView().sizeOfSelectionArray() == 0) {
+            getSheetTypeSheetView().insertNewSelection(0);
+        }
+        return getSheetTypeSheetView().getSelectionArray(0);
+    }
+
+    /**
+     * Return the default sheet view. This is the last one if the sheet's views, according to sec. 3.3.1.83
+     * of the OOXML spec: "A single sheet view definition. When more than 1 sheet view is defined in the file,
+     * it means that when opening the workbook, each sheet view corresponds to a separate window within the
+     * spreadsheet application, where each window is showing the particular sheet. containing the same
+     * workbookViewId value, the last sheetView definition is loaded, and the others are discarded.
+     * When multiple windows are viewing the same sheet, multiple sheetView elements (with corresponding
+     * workbookView entries) are saved."
+     */
+    private CTSheetView getDefaultSheetView() {
+        CTSheetViews views = getSheetTypeSheetViews();
+        if (views == null || views.getSheetViewArray() == null || views.getSheetViewArray().length <= 0) {
+            return null;
+        }
+        return views.getSheetViewArray(views.getSheetViewArray().length - 1);
+    }
+
+    protected XSSFSheet cloneSheet() {
+        XSSFSheet newSheet = new XSSFSheet(getWorkbook());
+        newSheet.setSheet((CTSheet)sheet.copy());
+        return newSheet;
+    }
+
+    private void setSheet(CTSheet sheet) {
+        this.sheet = sheet;
+    }
+
+    private CommentsSource getComments() {
+        if (sheetComments == null) {
+            sheetComments = (CommentsTable)createRelationship(XSSFRelation.SHEET_COMMENTS, CommentsTable.class, (int)sheet.getSheetId());
+        }
+        return sheetComments;
+    }
+    /**
+     * Returns the sheet's comments object if there is one,
+     *  or null if not
+     */
+    protected CommentsSource getCommentsSourceIfExists() {
+        return sheetComments;
+    }
+
+    private void addNewMergeCell(Region region) {
+        ctMergeCells = getMergedCells();
+        CTMergeCell ctMergeCell = ctMergeCells.addNewMergeCell();
+        ctMergeCell.setRef(region.getRegionRef());
+    }
+
+    private CTMergeCells getMergedCells() {
+        if (ctMergeCells == null) {
+            ctMergeCells = worksheet.addNewMergeCells();
+        }
+        return ctMergeCells;
+    }
+
+    private CTPageSetUpPr getSheetTypePageSetUpPr() {
+        CTSheetPr sheetPr = getSheetTypeSheetPr();
+        return sheetPr.isSetPageSetUpPr() ? sheetPr.getPageSetUpPr() : sheetPr.addNewPageSetUpPr();
+    }
+
+    private boolean removeRow(int startRow, int endRow, int n, int rownum) {
+        if (rownum >= (startRow + n) && rownum <= (endRow + n)) {
+            if (n > 0 && rownum > endRow) {
+                return true;
+            }
+            else if (n < 0 && rownum < startRow) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private CTPane getPane() {
+        if (getDefaultSheetView().getPane() == null) {
+            getDefaultSheetView().addNewPane();
+        }
+        return getDefaultSheetView().getPane();
+    }
+
+
+    @Override
+    protected void commit() throws IOException {
+
+        if(worksheet.getColsArray().length == 1) {
+            CTCols col = worksheet.getColsArray(0);
+            if(col.getColArray().length == 0) {
+                worksheet.setColsArray(null);
+            }
+        }
+        // Now re-generate our CTHyperlinks, if needed
+        if(hyperlinks.size() > 0) {
+            if(worksheet.getHyperlinks() == null) {
+                worksheet.addNewHyperlinks();
+            }
+            CTHyperlink[] ctHls = new CTHyperlink[hyperlinks.size()];
+            for(int i=0; i<ctHls.length; i++) {
+                // If our sheet has hyperlinks, have them add
+                //  any relationships that they might need
+                XSSFHyperlink hyperlink = hyperlinks.get(i);
+                hyperlink.generateRelationIfNeeded(getPackagePart());
+                // Now grab their underling object
+                ctHls[i] = hyperlink.getCTHyperlink();
+            }
+            worksheet.getHyperlinks().setHyperlinkArray(ctHls);
+        }
+
+        XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
+        xmlOptions.setSaveSyntheticDocumentElement(new QName(CTWorksheet.type.getName().getNamespaceURI(), "worksheet"));
+        PackagePart part = getPackagePart();
+        OutputStream out = part.getOutputStream();
+        worksheet.save(out, xmlOptions);
+        out.close();
+    }
+
+    protected void setParent(POIXMLDocumentPart p){
+        this.parent = p;
+    }
+
 }
index 10449078dbef05db1072290a752999989eb97a0e..d6b6c515dd008b92c3673a5edc3a60e9c8a03ee7 100644 (file)
 package org.apache.poi.xssf.usermodel;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.LinkedList;
 import java.util.List;
-
+import java.util.HashMap;
+import java.util.Iterator;
 import javax.xml.namespace.QName;
-
 import org.apache.poi.POIXMLDocument;
-import org.apache.poi.ss.usermodel.CommentsSource;
-import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.POIXMLDocumentPart;
+import org.apache.poi.POIXMLFactory;
 import org.apache.poi.ss.usermodel.Palette;
 import org.apache.poi.ss.usermodel.PictureData;
 import org.apache.poi.ss.usermodel.Row;
@@ -37,19 +36,15 @@ import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
+import org.apache.poi.util.PackageHelper;
 import org.apache.poi.xssf.model.*;
-import org.apache.xmlbeans.XmlException;
+import org.apache.poi.POIXMLException;
 import org.apache.xmlbeans.XmlObject;
 import org.apache.xmlbeans.XmlOptions;
 import org.openxml4j.exceptions.InvalidFormatException;
+import org.openxml4j.exceptions.OpenXML4JException;
+import org.openxml4j.opc.*;
 import org.openxml4j.opc.Package;
-import org.openxml4j.opc.PackagePart;
-import org.openxml4j.opc.PackagePartName;
-import org.openxml4j.opc.PackageRelationship;
-import org.openxml4j.opc.PackageRelationshipCollection;
-import org.openxml4j.opc.PackageRelationshipTypes;
-import org.openxml4j.opc.PackagingURIHelper;
-import org.openxml4j.opc.TargetMode;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBookView;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBookViews;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
@@ -57,137 +52,203 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedNames;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDialogsheet;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument;
-
-
-public class XSSFWorkbook extends POIXMLDocument implements Workbook {
-       /** Are we a normal workbook, or a macro enabled one? */
-       private boolean isMacroEnabled = false;
-
-       private CTWorkbook workbook;
-
-       private List<XSSFSheet> sheets = new LinkedList<XSSFSheet>();
-       private List<XSSFName> namedRanges = new LinkedList<XSSFName>();
 
-       private SharedStringSource sharedStringSource;
-       private StylesSource stylesSource;
-
-       private List<ThemeTable> themes = new LinkedList<ThemeTable>();
-
-       private MissingCellPolicy missingCellPolicy = Row.RETURN_NULL_AND_BLANK;
+/**
+ * High level representation of a SpreadsheetML workbook.  This is the first object most users
+ * will construct whether they are reading or writing a workbook.  It is also the
+ * top level object for creating new sheets/etc.
+ */
+public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<XSSFSheet> {
+
+    /**
+     * The underlying XML bean
+     */
+    private CTWorkbook workbook;
+
+    /**
+     * this holds the XSSFSheet objects attached to this workbook
+     */
+    private List<XSSFSheet> sheets;
+
+    /**
+     * this holds the XSSFName objects attached to this workbook
+     */
+    private List<XSSFName> namedRanges;
+
+    /**
+     * shared string table - a cache of strings in this workbook
+     */
+    private SharedStringsTable sharedStringSource;
+
+    /**
+     * A collection of shared objects used for styling content,
+     * e.g. fonts, cell styles, colors, etc.
+     */
+    private StylesSource stylesSource;
+
+    /**
+     * Used to keep track of the data formatter so that all
+     * createDataFormatter calls return the same one for a given
+     * book.  This ensures that updates from one places is visible
+     * someplace else.
+     */
+    private XSSFDataFormat formatter;
+
+    /**
+     * The policy to apply in the event of missing or
+     *  blank cells when fetching from a row.
+     * See {@link org.apache.poi.ss.usermodel.Row.MissingCellPolicy}
+     */
+    private MissingCellPolicy missingCellPolicy = Row.RETURN_NULL_AND_BLANK;
 
        private static POILogger log = POILogFactory.getLogger(XSSFWorkbook.class);
 
+    /**
+     * Create a new SpreadsheetML workbook.
+     */
        public XSSFWorkbook() {
-               this.workbook = CTWorkbook.Factory.newInstance();
-               CTBookViews bvs = this.workbook.addNewBookViews();
-               CTBookView bv = bvs.addNewWorkbookView();
-               bv.setActiveTab(0);
-               this.workbook.addNewSheets();
-
-               // We always require styles and shared strings
-               sharedStringSource = new SharedStringsTable();
-               stylesSource = new StylesTable();
-       }
-
+        super();
+        try {
+            newWorkbook();
+        }catch (Exception e){
+            throw new POIXMLException(e);
+        }
+       }
+
+    /**
+     * Constructs a XSSFWorkbook object given a file name.
+     *
+     * @param      path   the file name.
+     */
        public XSSFWorkbook(String path) throws IOException {
                this(openPackage(path));
        }
-       public XSSFWorkbook(InputStream  is) throws IOException {
-               this(openPackage(is));
-       }
 
-       public XSSFWorkbook(Package pkg) throws IOException {
-               super(pkg);
+    /**
+     * Constructs a XSSFWorkbook object given a OpenXML4J <code>Package</code> object,
+     * see <a href="http://openxml4j.org/">www.openxml4j.org</a>.
+     *
+     * @param pkg the OpenXML4J <code>Package</code> object.
+     */
+    public XSSFWorkbook(Package pkg) throws IOException {
+        super();
+        if(pkg.getPackageAccess() == PackageAccess.READ){
+            //current implementation of OpenXML4J is funny.
+            //Packages opened by Package.open(InputStream is) are read-only,
+            //there is no way to change or even save such an instance in a OutputStream.
+            //The workaround is to create a copy via a temp file
+            try {
+                Package tmp = PackageHelper.clone(pkg);
+                initialize(tmp);
+            } catch (OpenXML4JException e){
+                throw new POIXMLException(e);
+            }
+        } else {
+            initialize(pkg);
+        }
+    }
+
+    /**
+     * Initialize this workbook from the specified Package
+     */
+    @Override
+    protected void initialize(Package pkg) throws IOException {
+        super.initialize(pkg);
+
                try {
-                       WorkbookDocument doc = WorkbookDocument.Factory.parse(getCorePart().getInputStream());
-                       this.workbook = doc.getWorkbook();
+            //build the POIXMLDocumentPart tree, this workbook is the root
+            read(new XSSFFactory());
 
-                       // Are we macro enabled, or just normal?
-                       isMacroEnabled =
-                                       getCorePart().getContentType().equals(XSSFRelation.MACROS_WORKBOOK.getContentType());
+            PackagePart corePart = getCorePart();
 
-                       try {
-                               // Load shared strings
-                               sharedStringSource = XSSFRelation.SHARED_STRINGS.load(getCorePart());
-                       } catch(Exception e) {
-                               throw new IOException("Unable to load shared strings - " + e.toString());
-                       }
-                       try {
-                               // Load styles source
-                               stylesSource = XSSFRelation.STYLES.load(getCorePart());
-                       } catch(Exception e) {
-                               e.printStackTrace();
-                               throw new IOException("Unable to load styles - " + e.toString());
-                       }
-                       try {
-                               // Load themes
-                               themes = XSSFRelation.THEME.loadAll(getCorePart());
-                       } catch(Exception e) {
-                               throw new IOException("Unable to load shared strings - " + e.toString());
-                       }
+            WorkbookDocument doc = WorkbookDocument.Factory.parse(corePart.getInputStream());
+                       this.workbook = doc.getWorkbook();
 
+            HashMap<String, XSSFSheet> shIdMap = new HashMap<String, XSSFSheet>();
+            for(POIXMLDocumentPart p : getRelations()){
+                if(p instanceof SharedStringsTable) sharedStringSource = (SharedStringsTable)p;
+                else if(p instanceof StylesSource) stylesSource = (StylesSource)p;
+                else if (p instanceof XSSFSheet) {
+                    shIdMap.put(p.getPackageRelationship().getId(), (XSSFSheet)p);
+                           }
+                       }
                        // Load individual sheets
+            sheets = new LinkedList<XSSFSheet>();
                        for (CTSheet ctSheet : this.workbook.getSheets().getSheetArray()) {
-                               PackagePart part = getPackagePart(ctSheet);
-                               if (part == null) {
+                String id = ctSheet.getId();
+                XSSFSheet sh = shIdMap.get(id);
+                sh.sheet = ctSheet;
+                if(sh == null) {
                                        log.log(POILogger.WARN, "Sheet with name " + ctSheet.getName() + " and r:id " + ctSheet.getId()+ " was defined, but didn't exist in package, skipping");
                                        continue;
                                }
+                //initialize internal arrays of rows and columns
+                sh.initialize();
 
-                               // Load child streams of the sheet
-                               List<CommentsTable> childModels;
-                               CommentsSource comments = null;
-                               List<Drawing> drawings;
-                               List<Control> controls;
-                               try {
-                                       // Get the comments for the sheet, if there are any
-                                       childModels = XSSFRelation.SHEET_COMMENTS.loadAll(part);
-                                       if(childModels.size() > 0) {
-                                               comments = childModels.get(0);
-                                       }
-
-                                       // Get the drawings for the sheet, if there are any
-                                       drawings = XSSFRelation.VML_DRAWINGS.loadAll(part);
-                                       // Get the activeX controls for the sheet, if there are any
-                                       controls = XSSFRelation.ACTIVEX_CONTROLS.loadAll(part);
-                               } catch(Exception e) {
-                                       throw new RuntimeException("Unable to construct child part",e);
-                               }
-
-                               // Now create the sheet
-                               WorksheetDocument worksheetDoc = WorksheetDocument.Factory.parse(part.getInputStream());
-                               XSSFSheet sheet = new XSSFSheet(ctSheet, worksheetDoc.getWorksheet(), this, comments, drawings, controls);
-                               this.sheets.add(sheet);
-
+                PackagePart sheetPart = sh.getPackagePart();
                                // Process external hyperlinks for the sheet,
                                //  if there are any
                                PackageRelationshipCollection hyperlinkRels =
-                                       part.getRelationshipsByType(XSSFRelation.SHEET_HYPERLINKS.getRelation());
-                               sheet.initHyperlinks(hyperlinkRels);
+                       sheetPart.getRelationshipsByType(XSSFRelation.SHEET_HYPERLINKS.getRelation());
+                sh.initHyperlinks(hyperlinkRels);
 
                                // Get the embeddings for the workbook
-                               for(PackageRelationship rel : part.getRelationshipsByType(XSSFRelation.OLEEMBEDDINGS.getRelation()))
+                for(PackageRelationship rel : sheetPart.getRelationshipsByType(XSSFRelation.OLEEMBEDDINGS.getRelation()))
                                        embedds.add(getTargetPart(rel)); // TODO: Add this reference to each sheet as well
 
-                               for(PackageRelationship rel : part.getRelationshipsByType(XSSFRelation.PACKEMBEDDINGS.getRelation()))
+                for(PackageRelationship rel : sheetPart.getRelationshipsByType(XSSFRelation.PACKEMBEDDINGS.getRelation()))
                                        embedds.add(getTargetPart(rel));
-                       }
-               } catch (XmlException e) {
-                       throw new IOException(e.toString());
-               } catch (InvalidFormatException e) {
-                       throw new IOException(e.toString());
-               }
 
-               // Process the named ranges
-               if(workbook.getDefinedNames() != null) {
-                       for(CTDefinedName ctName : workbook.getDefinedNames().getDefinedNameArray()) {
-                               namedRanges.add(new XSSFName(ctName, this));
+                sheets.add(sh);
                        }
-               }
+
+            if(sharedStringSource == null) {
+                //Create SST if it is missing
+                sharedStringSource = (SharedStringsTable)createRelationship(XSSFRelation.SHARED_STRINGS, SharedStringsTable.class);
+                   }
+
+                   // Process the named ranges
+            namedRanges = new LinkedList<XSSFName>();
+            if(workbook.getDefinedNames() != null) {
+                for(CTDefinedName ctName : workbook.getDefinedNames().getDefinedNameArray()) {
+                    namedRanges.add(new XSSFName(ctName, this));
+                }
+                   }
+
+        } catch (Exception e) {
+            throw new POIXMLException(e);
+        }
+    }
+
+    /**
+     * Create a new SpreadsheetML OOXML package and setup the default minimal content
+     */
+    protected void newWorkbook() throws IOException, OpenXML4JException{
+        Package pkg = Package.create(PackageHelper.createTempFile());
+        // Main part
+        PackagePartName corePartName = PackagingURIHelper.createPartName(XSSFRelation.WORKBOOK.getDefaultFileName());
+        // Create main part relationship
+        pkg.addRelationship(corePartName, TargetMode.INTERNAL, PackageRelationshipTypes.CORE_DOCUMENT);
+        // Create main document part
+        pkg.createPart(corePartName, XSSFRelation.WORKBOOK.getContentType());
+
+        pkg.getPackageProperties().setCreatorProperty("Apache POI");
+
+        super.initialize(pkg);
+
+        workbook = CTWorkbook.Factory.newInstance();
+        CTBookViews bvs = workbook.addNewBookViews();
+        CTBookView bv = bvs.addNewWorkbookView();
+        bv.setActiveTab(0);
+        workbook.addNewSheets();
+
+        sharedStringSource = (SharedStringsTable)createRelationship(XSSFRelation.SHARED_STRINGS, SharedStringsTable.class);
+        stylesSource = (StylesTable)createRelationship(XSSFRelation.STYLES, StylesTable.class);
+
+        namedRanges = new LinkedList<XSSFName>();
+        sheets = new LinkedList<XSSFSheet>();
        }
 
        /**
@@ -199,22 +260,6 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                return this.workbook;
        }
 
-       /**
-        * Get the PackagePart corresponding to a given sheet.
-        *
-        * @param ctSheet The sheet
-        * @return A PackagePart, or null if no matching part found.
-        * @throws InvalidFormatException
-        */
-       private PackagePart getPackagePart(CTSheet ctSheet) throws InvalidFormatException {
-               PackageRelationship rel = this.getCorePart().getRelationship(ctSheet.getId());
-               if (rel == null) {
-                       log.log(POILogger.WARN, "No relationship found for sheet " + ctSheet.getId() + " - core part has " + this.getCorePart().getRelationships().size() + " relations defined");
-                       return null;
-               }
-               return getTargetPart(rel);
-       }
-
        public int addPicture(byte[] pictureData, int format) {
                // TODO Auto-generated method stub
                return 0;
@@ -252,6 +297,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                return null;
        }
 
+    /**
+     * Create a new XSSFCellStyle and add it to the workbook's style table
+     *
+     * @return the new XSSFCellStyle object
+     */
        public XSSFCellStyle createCellStyle() {
                CTXf xf=CTXf.Factory.newInstance();
                xf.setNumFmtId(0);
@@ -265,53 +315,93 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                return style;
        }
 
-       public XSSFDataFormat createDataFormat() {
-               return (XSSFDataFormat)getCreationHelper().createDataFormat();
-       }
-
+    /**
+     * Returns the instance of XSSFDataFormat for this workbook.
+     *
+     * @return the XSSFDataFormat object
+     * @see org.apache.poi.ss.usermodel.DataFormat
+     */
+    public XSSFDataFormat createDataFormat() {
+        if (formatter == null)
+            formatter = new XSSFDataFormat(stylesSource);
+        return formatter;
+    }
+
+    /**
+     * create a new Font and add it to the workbook's font table
+     *
+     * @return new font object
+     */
        public XSSFFont createFont() {
                XSSFFont font= new XSSFFont();
                stylesSource.putFont(font);
                return font;
        }
 
+    /**
+     * Creates a new named range and add it to the model
+     *
+     * @return named range high level
+     */
        public XSSFName createName() {
                XSSFName name = new XSSFName(this);
                namedRanges.add(name);
                return name;
        }
 
+    /**
+     * create an XSSFSheet for this workbook, adds it to the sheets and returns
+     * the high level representation.  Use this to create new sheets.
+     *
+     * @return XSSFSheet representing the new sheet.
+     */
        public XSSFSheet createSheet() {
                String sheetname = "Sheet" + (sheets.size() + 1);
                return createSheet(sheetname);
        }
 
+    /**
+     * create an XSSFSheet for this workbook, adds it to the sheets and returns
+     * the high level representation.  Use this to create new sheets.
+     *
+     * @param sheetname  sheetname to set for the sheet, can't be duplicate, greater than 31 chars or contain /\?*[]
+     * @return XSSFSheet representing the new sheet.
+     */
        public XSSFSheet createSheet(String sheetname) {
                if (doesContainsSheetName( sheetname, sheets.size() ))
                        throw new IllegalArgumentException( "The workbook already contains a sheet of this name" );
-               return createSheet(sheetname, XSSFSheet.newInstance());
-       }
 
-       public XSSFSheet createSheet(String sheetname, CTWorksheet worksheet) {
+        int sheetNumber = getNumberOfSheets() + 1;
+        XSSFSheet wrapper = (XSSFSheet)createRelationship(XSSFRelation.WORKSHEET, XSSFSheet.class, sheetNumber);
+        wrapper.setParent(this);
+
                CTSheet sheet = addSheet(sheetname);
-               XSSFSheet wrapper = new XSSFSheet(sheet, worksheet, this);
+        wrapper.sheet = sheet;
+        sheet.setId(wrapper.getPackageRelationship().getId());
+        sheet.setSheetId(sheetNumber);
+
                this.sheets.add(wrapper);
                return wrapper;
        }
 
-       public XSSFSheet createDialogsheet(String sheetname, CTDialogsheet dialogsheet) {
-       CTSheet sheet = addSheet(sheetname);
-       XSSFDialogsheet wrapper = new XSSFDialogsheet(sheet, dialogsheet, this);
-       this.sheets.add(wrapper);
-       return wrapper;
+    protected XSSFSheet createDialogsheet(String sheetname, CTDialogsheet dialogsheet) {
+        CTSheet sheet = addSheet(sheetname);
+        XSSFDialogsheet wrapper = new XSSFDialogsheet(sheet, dialogsheet, this);
+        this.sheets.add(wrapper);
+        return wrapper;
        }
 
        private CTSheet addSheet(String sheetname) {
-               CTSheet sheet = workbook.getSheets().addNewSheet();
+               validateSheetName(sheetname);
+
+        CTSheet sheet = workbook.getSheets().addNewSheet();
                sheet.setName(sheetname);
                return sheet;
        }
 
+    /**
+     * Finds a font that matches the one with the supplied attributes
+     */
        public XSSFFont findFont(short boldWeight, short color, short fontHeight, String name, boolean italic, boolean strikeout, short typeOffset, byte underline) {
                short fontNum=getNumberOfFonts();
                for (short i = 0; i < fontNum; i++) {
@@ -344,34 +434,43 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                return index.intValue();
        }
 
+    /**
+     * Gets all embedded OLE2 objects from the Workbook.
+     *
+     * @return the list of embedded objects (a list of {@link org.openxml4j.opc.PackagePart} objects.)
+     */
        public List getAllEmbeddedObjects() {
-               // TODO Auto-generated method stub
-               return null;
+        return embedds;
        }
 
+    /**
+     * Gets all pictures from the Workbook.
+     *
+     * @return the list of pictures (a list of {@link XSSFPictureData} objects.)
+     */
        public List<PictureData> getAllPictures() {
                // In OOXML pictures are referred to in sheets
                List<PictureData> pictures = new LinkedList<PictureData>();
-               for (CTSheet ctSheet : this.workbook.getSheets().getSheetArray()) {
-                       try {
-                               PackagePart sheetPart = getPackagePart(ctSheet);
-                               if (sheetPart == null) {
-                                       continue;
-                               }
-                               PackageRelationshipCollection prc = sheetPart.getRelationshipsByType(XSSFRelation.DRAWINGS.getRelation());
-                               for (PackageRelationship rel : prc) {
-                                       PackagePart drawingPart = getTargetPart(rel);
-                                       PackageRelationshipCollection prc2 = drawingPart.getRelationshipsByType(XSSFRelation.IMAGES.getRelation());
-                                       for (PackageRelationship rel2 : prc2) {
-                                               PackagePart imagePart = getTargetPart(rel2);
-                                               XSSFPictureData pd = new XSSFPictureData(imagePart);
-                                               pictures.add(pd);
-                                       }
-                               }
-                       } catch (InvalidFormatException e) {
-                               throw new RuntimeException(e.getMessage(), e);
-                       }
-               }
+        for(POIXMLDocumentPart p : getRelations()){
+            if (p instanceof XSSFSheet) {
+                PackagePart sheetPart = p.getPackagePart();
+                try {
+                    PackageRelationshipCollection prc = sheetPart.getRelationshipsByType(XSSFRelation.DRAWINGS.getRelation());
+                    for (PackageRelationship rel : prc) {
+                        PackagePart drawingPart = getTargetPart(rel);
+                        PackageRelationshipCollection prc2 = drawingPart.getRelationshipsByType(XSSFRelation.IMAGES.getRelation());
+                        for (PackageRelationship rel2 : prc2) {
+                            PackagePart imagePart = getTargetPart(rel2);
+                            XSSFPictureData pd = new XSSFPictureData(imagePart);
+                            pictures.add(pd);
+                        }
+                    }
+                } catch (InvalidFormatException e) {
+                    throw new POIXMLException(e.getMessage(), e);
+                }
+
+            }
+        }
                return pictures;
        }
 
@@ -389,39 +488,91 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                return null;
        }
 
+    /**
+     * Get the font at the given index number
+     *
+     * @param idx  index number
+     * @return XSSFFont at the index
+     */
        public XSSFFont getFontAt(short idx) {
                return (XSSFFont)stylesSource.getFontAt(idx);
        }
 
+    /**
+     * Gets the Named range at the given index number
+     *
+     * @param index position of the named range
+     * @return XSSFName at the index
+     */
        public XSSFName getNameAt(int index) {
                return namedRanges.get(index);
        }
+
+    /**
+     * Gets the Named range name at the given index number,
+     * this method is equivalent to <code>getNameAt(index).getName()</code>
+     *
+     * @param index the named range index (0 based)
+     * @return named range name
+     * @see #getNameAt(int)
+     */
        public String getNameName(int index) {
                return getNameAt(index).getNameName();
        }
-       public int getNameIndex(String name) {
-               for(int i=0; i<namedRanges.size(); i++) {
-                       if(namedRanges.get(i).getNameName().equals(name)) {
-                               return i;
-                       }
-               }
+
+    /**
+     * Gets the named range index by his name
+     * <i>Note:</i>Excel named ranges are case-insensitive and
+     * this method performs a case-insensitive search.
+     *
+     * @param name named range name
+     * @return named range index
+     */
+    public int getNameIndex(String name) {
+        int i = 0;
+        for(XSSFName nr : namedRanges) {
+            if(nr.getNameName().equals(name)) {
+                return i;
+            }
+            i++;
+        }
                return -1;
        }
 
+    /**
+     * Get the number of styles the workbook contains
+     *
+     * @return count of cell styles
+     */
        public short getNumCellStyles() {
                return (short) ((StylesTable)stylesSource).getNumCellStyles();
        }
 
+    /**
+     * Get the number of fonts in the this workbook
+     *
+     * @return number of fonts
+     */
        public short getNumberOfFonts() {
                return (short)((StylesTable)stylesSource).getNumberOfFonts();
        }
 
+    /**
+     * Get the number of named ranges in the this workbook
+     *
+     * @return number of named ranges
+     */
        public int getNumberOfNames() {
                return namedRanges.size();
        }
 
+    /**
+     * Get the number of worksheets in the this workbook
+     *
+     * @return number of worksheets
+     */
        public int getNumberOfSheets() {
-               return this.workbook.getSheets().sizeOfSheetArray();
+        return this.sheets.size();
        }
 
        public String getPrintArea(int sheetIndex) {
@@ -429,6 +580,10 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                return null;
        }
 
+    /**
+     * deprecated May 2008
+     * @deprecated - Misleading name - use getActiveSheetIndex()
+     */
        public short getSelectedTab() {
                short i = 0;
                for (XSSFSheet sheet : this.sheets) {
@@ -440,7 +595,13 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                return -1;
        }
 
-       public Sheet getSheet(String name) {
+    /**
+     * Get sheet with the given name (case insensitive match)
+     *
+     * @param name of the sheet
+     * @return XSSFSheet with the name provided or <code>null</code> if it does not exist
+     */
+       public XSSFSheet getSheet(String name) {
                CTSheet[] sheets = this.workbook.getSheets().getSheetArray();
                for (int i = 0 ; i < sheets.length ; ++i) {
                        if (name.equals(sheets[i].getName())) {
@@ -450,10 +611,22 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                return null;
        }
 
+    /**
+     * Get the XSSFSheet object at the given index.
+     *
+     * @param index of the sheet number (0-based physical & logical)
+     * @return XSSFSheet at the provided index
+     */
        public XSSFSheet getSheetAt(int index) {
                return this.sheets.get(index);
        }
 
+    /**
+     * Returns the index of the sheet by his name
+     *
+     * @param name the sheet name
+     * @return index of the sheet (0 based)
+     */
        public int getSheetIndex(String name) {
                CTSheet[] sheets = this.workbook.getSheets().getSheetArray();
                for (int i = 0 ; i < sheets.length ; ++i) {
@@ -464,25 +637,50 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                return -1;
        }
 
+    /**
+     * Returns the index of the given sheet
+     *
+     * @param sheet the sheet to look up
+     * @return index of the sheet (0 based). <tt>-1</tt> if not found
+     */
        public int getSheetIndex(Sheet sheet) {
-               return this.sheets.indexOf(sheet);
-       }
-
-       public String getSheetName(int sheet) {
-               return this.workbook.getSheets().getSheetArray(sheet).getName();
-       }
-
+        int idx = 0;
+        for(XSSFSheet sh : this){
+            if(sh == sheet) return idx;
+            idx++;
+        }
+        return -1;
+       }
+
+    /**
+     * Get the sheet name
+     *
+     * @param sheetIx Number
+     * @return Sheet name
+     */
+       public String getSheetName(int sheetIx) {
+        validateSheetIndex(sheetIx);
+               return this.workbook.getSheets().getSheetArray(sheetIx).getName();
+       }
+
+    /**
+     * Allow foreach loops:
+     * <pre><code>
+     * XSSFWorkbook wb = new XSSFWorkbook(package);
+     * for(XSSFSheet sheet : wb){
+     *
+     * }
+     * </code></pre>
+     */
+    public Iterator<XSSFSheet> iterator() {
+        return sheets.iterator();
+    }
        /**
         * Are we a normal workbook (.xlsx), or a
         *  macro enabled workbook (.xlsm)?
         */
        public boolean isMacroEnabled() {
-               return isMacroEnabled;
-       }
-
-       public void insertChartRecord() {
-               // TODO Auto-generated method stub
-
+        return getCorePart().getContentType().equals(XSSFRelation.MACROS_WORKBOOK.getContentType());
        }
 
        public void removeName(int index) {
@@ -500,6 +698,20 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
 
        }
 
+    /**
+     * Removes sheet at the given index.<p/>
+     *
+     * Care must be taken if the removed sheet is the currently active or only selected sheet in
+     * the workbook. There are a few situations when Excel must have a selection and/or active
+     * sheet. (For example when printing - see Bug 40414).<br/>
+     *
+     * This method makes sure that if the removed sheet was active, another sheet will become
+     * active in its place.  Furthermore, if the removed sheet was the only selected sheet, another
+     * sheet will become selected.  The newly active/selected sheet will have the same index, or
+     * one less if the removed sheet was the last in the workbook.
+     *
+     * @param index of the sheet  (0-based)
+     */
        public void removeSheetAt(int index) {
                this.sheets.remove(index);
                this.workbook.getSheets().removeSheet(index);
@@ -518,7 +730,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
         * Sets the policy on what to do when
         *  getting missing or blank cells from a row.
         * This will then apply to all calls to
-        *  {@link Row.getCell()}. See
+        *  {@link Row#getCell(int)}}. See
         *  {@link MissingCellPolicy}
         */
        public void setMissingCellPolicy(MissingCellPolicy missingCellPolicy) {
@@ -600,12 +812,24 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                }
        }
 
+    /**
+     * Set the sheet name.
+     * Will throw IllegalArgumentException if the name is greater than 31 chars
+     * or contains /\?*[]
+     * @param sheet number (0 based)
+     */
        public void setSheetName(int sheet, String name) {
                if (doesContainsSheetName(name, sheet ))
                        throw new IllegalArgumentException( "The workbook already contains a sheet of this name" );
                this.workbook.getSheets().getSheetArray(sheet).setName(name);
        }
 
+    /**
+     * sets the order of appearance for a given sheet.
+     *
+     * @param sheetname the name of the sheet to reorder
+     * @param pos the position that we want to insert the sheet into (0 based)
+     */
        public void setSheetOrder(String sheetname, int pos) {
                int idx = getSheetIndex(sheetname);
                sheets.add(pos, sheets.remove(idx));
@@ -621,141 +845,53 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
 
        }
 
-       public void write(OutputStream stream) throws IOException {
-               // What kind of workbook are we?
-               XSSFRelation workbookRelation = XSSFRelation.WORKBOOK;
-               if(isMacroEnabled) {
-                       workbookRelation = XSSFRelation.MACROS_WORKBOOK;
-               }
-
-               try {
-                       // Create a package referring the temp file.
-                       Package pkg = Package.create(stream);
-                       // Main part
-                       PackagePartName corePartName = PackagingURIHelper.createPartName(workbookRelation.getDefaultFileName());
-                       // Create main part relationship
-                       int rId = 1;
-                       pkg.addRelationship(corePartName, TargetMode.INTERNAL, PackageRelationshipTypes.CORE_DOCUMENT, "rId" + (rId++));
-
-                       // Create main document part
-                       PackagePart corePart = pkg.createPart(corePartName, workbookRelation.getContentType());
-                       OutputStream out;
-
-                       XmlOptions xmlOptions = new XmlOptions();
-                       // Requests use of whitespace for easier reading
-                       xmlOptions.setSavePrettyPrint();
-                       xmlOptions.setSaveOuter();
-                       xmlOptions.setUseDefaultNamespace();
-
-                       // Write out our sheets, updating the references
-                       //  to them in the main workbook as we go
-                       int drawingIndex = 1;
-                       for (int i=0 ; i < this.getNumberOfSheets(); i++) {
-                               int sheetNumber = (i+1);
-                               XSSFSheet sheet = this.getSheetAt(i);
-                               PackagePartName partName = PackagingURIHelper.createPartName(
-                                               XSSFRelation.WORKSHEET.getFileName(sheetNumber));
-                               PackageRelationship rel =
-                                        corePart.addRelationship(partName, TargetMode.INTERNAL, XSSFRelation.WORKSHEET.getRelation(), "rId" + sheetNumber);
-                               PackagePart part = pkg.createPart(partName, XSSFRelation.WORKSHEET.getContentType());
-
-                               // XXX This should not be needed, but apparently the setSaveOuter call above does not work in XMLBeans 2.2
-                               xmlOptions.setSaveSyntheticDocumentElement(new QName(CTWorksheet.type.getName().getNamespaceURI(), "worksheet"));
-                               sheet.save(part, xmlOptions);
-
-                               // Update our internal reference for the package part
-                               workbook.getSheets().getSheetArray(i).setId(rel.getId());
-                               workbook.getSheets().getSheetArray(i).setSheetId(sheetNumber);
-
-                               // If our sheet has drawings, then write out those
-                               if(sheet.getDrawings() != null) {
-                                       for(Drawing drawing : sheet.getDrawings()) {
-                                               XSSFRelation.VML_DRAWINGS.save(
-                                                               drawing,
-                                                               part,
-                                                               drawingIndex
-                                               );
-                                               drawingIndex++;
-                                       }
-                               }
-
-                               // If our sheet has comments, then write out those
-                               if(sheet.hasComments()) {
-                                       CommentsTable ct = (CommentsTable)sheet.getCommentsSourceIfExists();
-                                       XSSFRelation.SHEET_COMMENTS.save(ct, part, sheetNumber);
-                               }
-
-                               // If our sheet has controls, then write out those
-                               if(sheet.getControls() != null) {
-                                       int controlIndex = 1;
-                                       for(Control control : sheet.getControls()) {
-                                               XSSFRelation.ACTIVEX_CONTROLS.save(
-                                                               control,
-                                                               part,
-                                                               controlIndex
-                                               );
-                                               controlIndex++;
-                                       }
-                               }
-                       }
-
-                       // Write shared strings and styles
-                       if(sharedStringSource != null) {
-                                SharedStringsTable sst = (SharedStringsTable)sharedStringSource;
-                                XSSFRelation.SHARED_STRINGS.save(sst, corePart);
-                       }
-                       if(stylesSource != null) {
-                                StylesTable st = (StylesTable)stylesSource;
-                                XSSFRelation.STYLES.save(st, corePart);
-                       }
-                       if(themes.size() > 0) {
-                               for(int i=0; i< themes.size(); i++) {
-                                       XSSFRelation.THEME.save(themes.get(i), corePart, i+1);
-                               }
-                       }
-
-                       // Named ranges
-                       if(namedRanges.size() > 0) {
-                               CTDefinedNames names = CTDefinedNames.Factory.newInstance();
-                               CTDefinedName[] nr = new CTDefinedName[namedRanges.size()];
-                               for(int i=0; i<namedRanges.size(); i++) {
-                                       nr[i] = namedRanges.get(i).getCTName();
-                               }
-                               names.setDefinedNameArray(nr);
-                               workbook.setDefinedNames(names);
-                       } else {
-                               if(workbook.isSetDefinedNames()) {
-                                       workbook.setDefinedNames(null);
-                               }
-                       }
-
-                       // Macro related bits
-                       if(isMacroEnabled) {
-                               // Copy VBA Macros if present
-                               if(XSSFRelation.VBA_MACROS.exists( getCorePart() )) {
-                                       try {
-                                               BinaryPart vba = XSSFRelation.VBA_MACROS.load(getCorePart());
-                                               XSSFRelation.VBA_MACROS.save(vba, corePart);
-                                       } catch(Exception e) {
-                                               throw new RuntimeException("Unable to copy vba macros over", e);
-                                       }
-                               }
-                       }
-
-                       // Now we can write out the main Workbook, with
-                       //  the correct references to the other parts
-                       out = corePart.getOutputStream();
-                       // XXX This should not be needed, but apparently the setSaveOuter call above does not work in XMLBeans 2.2
-                       xmlOptions.setSaveSyntheticDocumentElement(new QName(CTWorkbook.type.getName().getNamespaceURI(), "workbook"));
-                       workbook.save(out, xmlOptions);
-                       out.close();
-
-                       //  All done
-                       pkg.close();
-               } catch (InvalidFormatException e) {
-                       // TODO: replace with more meaningful exception
-                       throw new RuntimeException(e);
-               }
+    /**
+     * marshal named ranges from the {@link #namedRanges} collection to the underlying CTWorkbook bean
+     */
+    private void saveNamedRanges(){
+        // Named ranges
+        if(namedRanges.size() > 0) {
+            CTDefinedNames names = CTDefinedNames.Factory.newInstance();
+            CTDefinedName[] nr = new CTDefinedName[namedRanges.size()];
+            int i = 0;
+            for(XSSFName name : namedRanges) {
+                nr[i] = name.getCTName();
+                i++;
+            }
+            names.setDefinedNameArray(nr);
+            workbook.setDefinedNames(names);
+        } else {
+            if(workbook.isSetDefinedNames()) {
+                workbook.unsetDefinedNames();
+            }
+        }
+
+    }
+
+    @Override
+    protected void commit() throws IOException {
+        saveNamedRanges();
+
+        XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
+        xmlOptions.setSaveSyntheticDocumentElement(new QName(CTWorkbook.type.getName().getNamespaceURI(), "workbook"));
+        PackagePart part = getPackagePart();
+        OutputStream out = part.getOutputStream();
+        workbook.save(out, xmlOptions);
+        out.close();
+    }
+
+    /**
+     * Method write - write out this workbook to an Outputstream.
+     *
+     * @param stream - the java OutputStream you wish to write the XLS to
+     *
+     * @exception IOException if anything can't be written.
+     */
+    public void write(OutputStream stream) throws IOException {
+        //force all children to commit their changes into the underlying OOXML Package
+        save();
+
+        getPackage().save(stream);
        }
 
        public void writeProtectWorkbook(String password, String username) {
@@ -763,24 +899,46 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
 
        }
 
-       public SharedStringSource getSharedStringSource() {
+    /**
+     * Returns SharedStringsTable - tha cache of string for this workbook
+     *
+     * @return the shared string table
+     */
+    public SharedStringsTable getSharedStringSource() {
                return this.sharedStringSource;
        }
-       protected void setSharedStringSource(SharedStringSource sharedStringSource) {
+    //TODO do we really need setSharedStringSource?
+    protected void setSharedStringSource(SharedStringsTable sharedStringSource) {
                this.sharedStringSource = sharedStringSource;
        }
 
+    /**
+     * Return a object representing a collection of shared objects used for styling content,
+     * e.g. fonts, cell styles, colors, etc.
+     */
        public StylesSource getStylesSource() {
                return this.stylesSource;
        }
+    //TODO do we really need setStylesSource?
        protected void setStylesSource(StylesSource stylesSource) {
                this.stylesSource = stylesSource;
        }
 
-       public CreationHelper getCreationHelper() {
+    /**
+     * Returns an object that handles instantiating concrete
+     *  classes of the various instances for XSSF.
+     */
+       public XSSFCreationHelper getCreationHelper() {
                return new XSSFCreationHelper(this);
        }
 
+    /**
+     * Determines whether a workbook contains the provided sheet name.
+     *
+     * @param name the name to test (case insensitive match)
+     * @param excludeSheetIdx the sheet to exclude from the check or -1 to include all sheets in the check.
+     * @return true if the sheet contains the name, false otherwise.
+     */
        private boolean doesContainsSheetName(String name, int excludeSheetIdx) {
                CTSheet[] ctSheetArray = workbook.getSheets().getSheetArray();
                for (int i = 0; i < ctSheetArray.length; i++) {
@@ -789,4 +947,32 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
                }
                return false;
        }
+
+    private static void validateSheetName(String sheetName) {
+        if (sheetName == null) {
+            throw new IllegalArgumentException("sheetName must not be null");
+        }
+        int len = sheetName.length();
+        if (len < 1 || len > 31) {
+            throw new IllegalArgumentException("sheetName '" + sheetName
+                    + "' is invalid - must be 1-30 characters long");
+        }
+        for (int i=0; i<len; i++) {
+            char ch = sheetName.charAt(i);
+            switch (ch) {
+                case '/':
+                case '\\':
+                case '?':
+                case '*':
+                case ']':
+                case '[':
+                    break;
+                default:
+                    // all other chars OK
+                    continue;
+            }
+            throw new IllegalArgumentException("Invalid char (" + ch
+                    + ") found at index (" + i + ") in sheet name '" + sheetName + "'");
+        }
+     }
 }
index d57b82446791a9834932ed5940188513347093f9..f947d7bd14e62155d7e7b3d5d319e29ca021f773 100644 (file)
@@ -75,10 +75,22 @@ public class XSSFCellBorder {
        
        private CTBorderPr getBorder(BorderSide side) {
                switch (side) {
-               case TOP: return border.getTop();
-               case RIGHT: return border.getRight();
-               case BOTTOM: return border.getBottom();
-               case LEFT: return border.getLeft();
+               case TOP: {
+                   CTBorderPr borderPr = border.isSetTop() ? border.getTop() : border.addNewTop();
+                   return borderPr;
+               }
+               case RIGHT: {
+                           CTBorderPr borderPr = border.isSetRight() ? border.getRight() : border.addNewRight();
+                           return borderPr;
+               }
+               case BOTTOM:{
+                           CTBorderPr borderPr = border.isSetBottom() ? border.getBottom() : border.addNewBottom();
+                           return borderPr;
+               }
+               case LEFT:{
+                           CTBorderPr borderPr = border.isSetLeft() ? border.getLeft() : border.addNewLeft();
+                           return borderPr;
+                       }
                default: throw new IllegalArgumentException("No suitable side specified for the border");
                }
        }
index aa1d78fe5f73662b2984767a185f89221a4ead42..1fe0b120c16660d1f90d149676ad78b7b3375bb3 100644 (file)
 \r
 package org.apache.poi.xssf;\r
 \r
-import java.io.ByteArrayInputStream;\r
-import java.io.ByteArrayOutputStream;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
+import java.io.*;\r
 \r
 import org.apache.poi.hssf.HSSFTestDataSamples;\r
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;\r
@@ -47,15 +44,20 @@ public class XSSFTestDataSamples {
                }\r
        }\r
     public static <R extends Workbook> R writeOutAndReadBack(R wb) {\r
-       ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);\r
        Workbook result;\r
                try {\r
-               wb.write(baos);\r
-               InputStream is = new ByteArrayInputStream(baos.toByteArray());\r
                if (wb instanceof HSSFWorkbook) {\r
+                ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);\r
+                wb.write(baos);\r
+                InputStream is = new ByteArrayInputStream(baos.toByteArray());\r
                        result = new HSSFWorkbook(is);\r
                } else if (wb instanceof XSSFWorkbook) {\r
-                       Package pkg = Package.open(is);\r
+                File tmp = File.createTempFile("poi-ooxml-", ".xlsx");\r
+                tmp.deleteOnExit();\r
+                FileOutputStream out = new FileOutputStream(tmp);\r
+                wb.write(out);\r
+                out.close();\r
+                       Package pkg = Package.open(tmp.getAbsolutePath());\r
                        result = new XSSFWorkbook(pkg);\r
                } else {\r
                        throw new RuntimeException("Unexpected workbook type (" \r
index 418ddec4768841e9b209e50f1f5fac87e3dbfe17..c37d1d8b50c30d3e434ea66efd76c61718be01a3 100644 (file)
@@ -30,6 +30,7 @@ import org.apache.poi.xssf.usermodel.XSSFComment;
 import org.apache.poi.xssf.usermodel.XSSFRichTextString;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.apache.poi.xssf.XSSFTestDataSamples;
 import org.openxml4j.opc.Package;
 import org.openxml4j.opc.PackagePart;
 import org.openxml4j.opc.PackagingURIHelper;
@@ -212,12 +213,8 @@ public class TestCommentsTable extends TestCase {
                
                
                // Save, and re-load the file
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               workbook.write(baos);
-               
-               ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-               workbook = new XSSFWorkbook(Package.open(bais));
-               
+        workbook = XSSFTestDataSamples.writeOutAndReadBack(workbook);
+
                // Check we still have comments where we should do
                sheet1 = workbook.getSheetAt(0);
                sheet2 = (XSSFSheet)workbook.getSheetAt(1);
@@ -259,12 +256,8 @@ public class TestCommentsTable extends TestCase {
                                sheet1.getRow(12).getCell(2).getCellComment().getAuthor());
                
                // Save, and re-load the file
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               workbook.write(baos);
-               
-               ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-               workbook = new XSSFWorkbook(Package.open(bais));
-               
+        workbook = XSSFTestDataSamples.writeOutAndReadBack(workbook);
+
                // Check we still have comments where we should do
                sheet1 = workbook.getSheetAt(0);
                assertNotNull(sheet1.getRow(4).getCell(2).getCellComment());
index 570cc077b4170684332653fb20e5e978d50657e8..b3f3e533dd79360f15c151c4c458446b9fef087f 100644 (file)
 
 package org.apache.poi.xssf.usermodel;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.FileOutputStream;
 
 import junit.framework.TestCase;
 
 import org.openxml4j.opc.Package;
 import org.openxml4j.opc.PackagePart;
 import org.openxml4j.opc.PackagingURIHelper;
+import org.apache.poi.xssf.XSSFTestDataSamples;
 
 public class TestXSSFBugs extends TestCase {
-       private String getFilePath(String file) {
-               File xml = new File(
-                               System.getProperty("HSSF.testdata.path") +
-                               File.separator + file
-               );
-               assertTrue(xml.exists());
-               
-               return xml.toString();
-       }
-       
-       private Package saveAndOpen(XSSFWorkbook wb) throws Exception {
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               wb.write(baos);
-               ByteArrayInputStream inp = new ByteArrayInputStream(
-                               baos.toByteArray()
-               );
-               Package pkg = Package.open(inp);
-               return pkg;
-       }
-       
-       /**
-        * Named ranges had the right reference, but
-        *  the wrong sheet name
-        */
-       public void test45430() throws Exception {
-               XSSFWorkbook wb = new XSSFWorkbook(getFilePath("45430.xlsx"));
-               assertFalse(wb.isMacroEnabled());
-               assertEquals(3, wb.getNumberOfNames());
-               
-               assertEquals(0, wb.getNameAt(0).getCTName().getLocalSheetId());
-               assertFalse(wb.getNameAt(0).getCTName().isSetLocalSheetId());
-               assertEquals("SheetA!$A$1", wb.getNameAt(0).getReference());
-               assertEquals("SheetA", wb.getNameAt(0).getSheetName());
-               
-               assertEquals(0, wb.getNameAt(1).getCTName().getLocalSheetId());
-               assertFalse(wb.getNameAt(1).getCTName().isSetLocalSheetId());
-               assertEquals("SheetB!$A$1", wb.getNameAt(1).getReference());
-               assertEquals("SheetB", wb.getNameAt(1).getSheetName());
-               
-               assertEquals(0, wb.getNameAt(2).getCTName().getLocalSheetId());
-               assertFalse(wb.getNameAt(2).getCTName().isSetLocalSheetId());
-               assertEquals("SheetC!$A$1", wb.getNameAt(2).getReference());
-               assertEquals("SheetC", wb.getNameAt(2).getSheetName());
-               
-               // Save and re-load, still there
-               Package nPkg = saveAndOpen(wb);
-               XSSFWorkbook nwb = new XSSFWorkbook(nPkg);
-               assertEquals(3, nwb.getNumberOfNames());
-               assertEquals("SheetA!$A$1", nwb.getNameAt(0).getReference());
-       }
-       
-       /**
-        * We should carry vba macros over after save
-        */
-       public void test45431() throws Exception {
-               Package pkg = Package.open(getFilePath("45431.xlsm"));
-               XSSFWorkbook wb = new XSSFWorkbook(pkg);
-               assertTrue(wb.isMacroEnabled());
-               
-               // Check the various macro related bits can be found
-               PackagePart vba = pkg.getPart(
-                               PackagingURIHelper.createPartName("/xl/vbaProject.bin")
-               );
-               assertNotNull(vba);
-               // And the drawing bit
-               PackagePart drw = pkg.getPart(
-                               PackagingURIHelper.createPartName("/xl/drawings/vmlDrawing1.vml")
-               );
-               assertNotNull(drw);
-               
-               
-               // Save and re-open, both still there
-               Package nPkg = saveAndOpen(wb);
-               XSSFWorkbook nwb = new XSSFWorkbook(nPkg);
-               assertTrue(nwb.isMacroEnabled());
-               
-               vba = nPkg.getPart(
-                               PackagingURIHelper.createPartName("/xl/vbaProject.bin")
-               );
-               assertNotNull(vba);
-               drw = nPkg.getPart(
-                               PackagingURIHelper.createPartName("/xl/drawings/vmlDrawing1.vml")
-               );
-               assertNotNull(drw);
-               
-               // And again, just to be sure
-               nPkg = saveAndOpen(nwb);
-               nwb = new XSSFWorkbook(nPkg);
-               assertTrue(nwb.isMacroEnabled());
-               
-               vba = nPkg.getPart(
-                               PackagingURIHelper.createPartName("/xl/vbaProject.bin")
-               );
-               assertNotNull(vba);
-               drw = nPkg.getPart(
-                               PackagingURIHelper.createPartName("/xl/drawings/vmlDrawing1.vml")
-               );
-               assertNotNull(drw);
-               
-               // For testing with excel
+    private String getFilePath(String file) {
+        File xml = new File(
+                System.getProperty("HSSF.testdata.path") +
+                File.separator + file
+        );
+        assertTrue(xml.exists());
+
+        return xml.toString();
+    }
+
+    /**
+     * Named ranges had the right reference, but
+     *  the wrong sheet name
+     */
+    public void test45430() throws Exception {
+        XSSFWorkbook wb = new XSSFWorkbook(getFilePath("45430.xlsx"));
+        assertFalse(wb.isMacroEnabled());
+        assertEquals(3, wb.getNumberOfNames());
+
+        assertEquals(0, wb.getNameAt(0).getCTName().getLocalSheetId());
+        assertFalse(wb.getNameAt(0).getCTName().isSetLocalSheetId());
+        assertEquals("SheetA!$A$1", wb.getNameAt(0).getReference());
+        assertEquals("SheetA", wb.getNameAt(0).getSheetName());
+
+        assertEquals(0, wb.getNameAt(1).getCTName().getLocalSheetId());
+        assertFalse(wb.getNameAt(1).getCTName().isSetLocalSheetId());
+        assertEquals("SheetB!$A$1", wb.getNameAt(1).getReference());
+        assertEquals("SheetB", wb.getNameAt(1).getSheetName());
+
+        assertEquals(0, wb.getNameAt(2).getCTName().getLocalSheetId());
+        assertFalse(wb.getNameAt(2).getCTName().isSetLocalSheetId());
+        assertEquals("SheetC!$A$1", wb.getNameAt(2).getReference());
+        assertEquals("SheetC", wb.getNameAt(2).getSheetName());
+
+        // Save and re-load, still there
+        XSSFWorkbook nwb = XSSFTestDataSamples.writeOutAndReadBack(wb);
+        assertEquals(3, nwb.getNumberOfNames());
+        assertEquals("SheetA!$A$1", nwb.getNameAt(0).getReference());
+    }
+
+    /**
+     * We should carry vba macros over after save
+     */
+    public void test45431() throws Exception {
+        Package pkg = Package.open(getFilePath("45431.xlsm"));
+        XSSFWorkbook wb = new XSSFWorkbook(pkg);
+        assertTrue(wb.isMacroEnabled());
+
+        // Check the various macro related bits can be found
+        PackagePart vba = pkg.getPart(
+                PackagingURIHelper.createPartName("/xl/vbaProject.bin")
+        );
+        assertNotNull(vba);
+        // And the drawing bit
+        PackagePart drw = pkg.getPart(
+                PackagingURIHelper.createPartName("/xl/drawings/vmlDrawing1.vml")
+        );
+        assertNotNull(drw);
+
+
+        // Save and re-open, both still there
+        XSSFWorkbook nwb = XSSFTestDataSamples.writeOutAndReadBack(wb);
+        Package nPkg = nwb.getPackage();
+        assertTrue(nwb.isMacroEnabled());
+
+        vba = nPkg.getPart(
+                PackagingURIHelper.createPartName("/xl/vbaProject.bin")
+        );
+        assertNotNull(vba);
+        drw = nPkg.getPart(
+                PackagingURIHelper.createPartName("/xl/drawings/vmlDrawing1.vml")
+        );
+        assertNotNull(drw);
+
+        // And again, just to be sure
+        nwb = XSSFTestDataSamples.writeOutAndReadBack(nwb);
+        nPkg = nwb.getPackage();
+        assertTrue(nwb.isMacroEnabled());
+
+        vba = nPkg.getPart(
+                PackagingURIHelper.createPartName("/xl/vbaProject.bin")
+        );
+        assertNotNull(vba);
+        drw = nPkg.getPart(
+                PackagingURIHelper.createPartName("/xl/drawings/vmlDrawing1.vml")
+        );
+        assertNotNull(drw);
+
+        // For testing with excel
 //             FileOutputStream fout = new FileOutputStream("/tmp/foo.xlsm");
 //             nwb.write(fout);
 //             fout.close();
-       }
+    }
 }
index 4a943597e6a70f1a300b3e003740f139ac179ee6..c2ddb01baed8da3561ed598d56acdbc3c6b7f2a5 100644 (file)
@@ -17,9 +17,6 @@
 
 package org.apache.poi.xssf.usermodel;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-
 import org.apache.poi.hssf.usermodel.HSSFRichTextString;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.Comment;
@@ -27,6 +24,7 @@ import org.apache.poi.ss.usermodel.RichTextString;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.xssf.model.CommentsTable;
+import org.apache.poi.xssf.XSSFTestDataSamples;
 import org.openxml4j.opc.Package;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAuthors;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
@@ -135,7 +133,7 @@ public class TestXSSFComment extends TestCase {
         */
        public void testCreateSave() throws Exception {
                XSSFWorkbook wb = new XSSFWorkbook();
-               XSSFSheet s1 = (XSSFSheet)wb.createSheet();
+               XSSFSheet s1 = wb.createSheet();
                Row r1 = s1.createRow(0);
                Cell r1c1 = r1.createCell(0);
                r1c1.setCellValue(2.2);
@@ -150,12 +148,8 @@ public class TestXSSFComment extends TestCase {
                assertEquals(1, s1.getNumberOfComments());
                
                // Save and re-load
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               wb.write(baos);
-               ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-               
-               wb = new XSSFWorkbook(Package.open(bais));
-               s1 = (XSSFSheet)wb.getSheetAt(0);
+               wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
+               s1 = wb.getSheetAt(0);
                
                assertEquals(1, s1.getNumberOfComments());
                assertNotNull(s1.getRow(0).getCell(0).getCellComment());
@@ -171,12 +165,9 @@ public class TestXSSFComment extends TestCase {
                assertEquals(2, s1.getNumberOfComments());
                
                // Save and re-load
-               baos = new ByteArrayOutputStream();
-               wb.write(baos);
-               bais = new ByteArrayInputStream(baos.toByteArray());
-               
-               wb = new XSSFWorkbook(Package.open(bais));
-               s1 = (XSSFSheet)wb.getSheetAt(0);
+
+               wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
+               s1 = wb.getSheetAt(0);
                
                assertEquals(2, s1.getNumberOfComments());
                assertNotNull(s1.getCellComment(0, 0));
index 2c469c49b377d49d8c593f48447de5500ce0e130..0e5141db78fe9fd18ab6defa2626d5aa0b1b88e6 100644 (file)
@@ -17,8 +17,6 @@
 
 package org.apache.poi.xssf.usermodel;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 
 import junit.framework.TestCase;
@@ -27,6 +25,7 @@ import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CreationHelper;
 import org.apache.poi.ss.usermodel.Hyperlink;
 import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.xssf.XSSFTestDataSamples;
 import org.openxml4j.opc.Package;
 
 public class TestXSSFHyperlink extends TestCase {
@@ -79,12 +78,9 @@ public class TestXSSFHyperlink extends TestCase {
                
                
                // Write out, and check
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               workbook.write(baos);
-               ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-               
+
                // Load up again, check all links still there
-               XSSFWorkbook wb2 = new XSSFWorkbook(Package.open(bais));
+               XSSFWorkbook wb2 = XSSFTestDataSamples.writeOutAndReadBack(workbook);
                assertEquals(3, wb2.getNumberOfSheets());
                assertNotNull(wb2.getSheetAt(0));
                assertNotNull(wb2.getSheetAt(1));
@@ -119,18 +115,14 @@ public class TestXSSFHyperlink extends TestCase {
                
                
                // Save and re-load once more
-               baos = new ByteArrayOutputStream();
-               wb2.write(baos);
-               bais = new ByteArrayInputStream(baos.toByteArray());
-               
-               
-               XSSFWorkbook wb3 = new XSSFWorkbook(Package.open(bais));
+
+        XSSFWorkbook wb3 = XSSFTestDataSamples.writeOutAndReadBack(wb2);
                assertEquals(3, wb3.getNumberOfSheets());
                assertNotNull(wb3.getSheetAt(0));
                assertNotNull(wb3.getSheetAt(1));
                assertNotNull(wb3.getSheetAt(2));
                
-               sheet = (XSSFSheet)wb3.getSheetAt(0);
+               sheet = wb3.getSheetAt(0);
                
                assertEquals(5, sheet.getNumHyperlinks());
                doTestHyperlinkContents(sheet);
index 2ccedebf8cce0a7f5a272b494f828627e899f5f5..5060125b0eee419828618534d671b553ac649a25 100644 (file)
@@ -17,8 +17,6 @@
 
 package org.apache.poi.xssf.usermodel;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.util.Iterator;
 import junit.framework.TestCase;
@@ -30,11 +28,7 @@ import org.apache.poi.ss.util.Region;
 import org.apache.poi.xssf.model.CommentsTable;
 import org.apache.poi.xssf.model.StylesTable;
 import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.usermodel.HSSFRow;
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.openxml4j.opc.Package;
+import org.apache.poi.xssf.XSSFTestDataSamples;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
@@ -349,11 +343,7 @@ public class TestXSSFSheet extends TestCase {
                
                
                // Save and reload
-               ByteArrayOutputStream baos = new ByteArrayOutputStream();
-               workbook.write(baos);
-               XSSFWorkbook wb = new XSSFWorkbook(Package.open(
-                               new ByteArrayInputStream(baos.toByteArray())
-               ));
+               XSSFWorkbook wb = XSSFTestDataSamples.writeOutAndReadBack(workbook);
                
                hdr = (XSSFOddHeader)wb.getSheetAt(0).getHeader();
                ftr = (XSSFOddFooter)wb.getSheetAt(0).getFooter(); 
index 4bfaf3ac2a44a47c9a55a75bc056d260383230e7..a8cdda1f5536f548ebcd9f9f931b8a233cc6bfb5 100644 (file)
@@ -441,7 +441,7 @@ public final class TestXSSFWorkbook extends TestCase {
                
                // Now, an existing file with named ranges
                workbook = XSSFTestDataSamples.openSampleWorkbook("WithVariousData.xlsx");
-               
+
                assertEquals(2, workbook.getNumberOfNames());
                assertEquals("Sheet1!$A$2:$A$7", workbook.getNameAt(0).getReference());
                assertEquals("AllANumbers", workbook.getNameAt(0).getNameName());