]> source.dussan.org Git - poi.git/commitdiff
Improve how XWPF headers and footers work
authorNick Burch <nick@apache.org>
Sat, 9 Aug 2008 14:21:21 +0000 (14:21 +0000)
committerNick Burch <nick@apache.org>
Sat, 9 Aug 2008 14:21:21 +0000 (14:21 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@684269 13f79535-47bb-0310-9956-ffa450edef68

src/ooxml/java/org/apache/poi/xwpf/XWPFDocument.java
src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xwpf/usermodel/XMLWordDocument.java
src/ooxml/testcases/org/apache/poi/xwpf/model/TestXWPFHeaderFooterPolicy.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java

index 6b25a42b9ebba502bb82501213afc14baff6878f..e5d5924df23c8e18895864e3ad6195edb7e44c47 100644 (file)
 package org.apache.poi.xwpf;
 
 import java.io.IOException;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Iterator;
 
 import org.apache.poi.POIXMLDocument;
+import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
+import org.apache.poi.xwpf.usermodel.XWPFComment;
+import org.apache.poi.xwpf.usermodel.XWPFHyperlink;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFTable;
 import org.apache.xmlbeans.XmlException;
 import org.openxml4j.exceptions.InvalidFormatException;
 import org.openxml4j.exceptions.OpenXML4JException;
@@ -30,23 +35,14 @@ import org.openxml4j.opc.PackagePart;
 import org.openxml4j.opc.PackageRelationship;
 import org.openxml4j.opc.PackageRelationshipCollection;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTComment;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTComment;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CommentsDocument;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.DocumentDocument;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.FtrDocument;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.HdrDocument;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.StylesDocument;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CommentsDocument;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
-
-import org.apache.poi.xwpf.usermodel.XWPFFooter;
-import org.apache.poi.xwpf.usermodel.XWPFHeader;
-import org.apache.poi.xwpf.usermodel.XWPFHyperlink;
-import org.apache.poi.xwpf.usermodel.XWPFParagraph;
-import org.apache.poi.xwpf.usermodel.XWPFComment;
-import org.apache.poi.xwpf.usermodel.XWPFTable;
 
 /**
  * Experimental class to do low level processing
@@ -75,10 +71,9 @@ public class XWPFDocument extends POIXMLDocument {
        protected List<XWPFHyperlink> hyperlinks;
        protected List<XWPFParagraph> paragraphs;
        protected List<XWPFTable> tables;
-       /** Should only ever be zero or one of these, we think */
-       protected XWPFHeader header;
-       /** Should only ever be zero or one of these, we think */
-       protected XWPFFooter footer;
+       
+       /** Handles the joy of different headers/footers for different pages */
+       private XWPFHeaderFooterPolicy headerFooterPolicy;
        
        public XWPFDocument(Package container) throws OpenXML4JException, IOException, XmlException {
                super(container);
@@ -133,23 +128,8 @@ public class XWPFDocument extends POIXMLDocument {
             embedds.add(getTargetPart(rel));
         }
         
-        // Fetch the header, if there's one
-        PackageRelationshipCollection headerRel = getCorePart().getRelationshipsByType(HEADER_RELATION_TYPE);
-               if(headerRel != null && headerRel.size() > 0) {
-                       PackagePart headerPart = getTargetPart(headerRel.getRelationship(0));
-                       header = new XWPFHeader(
-                                       HdrDocument.Factory.parse(headerPart.getInputStream()).getHdr()
-                       );
-               }
-        
-        // Fetch the footer, if there's one
-        PackageRelationshipCollection footerRel = getCorePart().getRelationshipsByType(FOOTER_RELATION_TYPE);
-               if(footerRel != null && footerRel.size() > 0) {
-                       PackagePart footerPart = getTargetPart(footerRel.getRelationship(0));
-                       footer = new XWPFFooter(
-                                       FtrDocument.Factory.parse(footerPart.getInputStream()).getFtr()
-                       );
-               }
+        // Sort out headers and footers
+        headerFooterPolicy = new XWPFHeaderFooterPolicy(this);
        }
        
        /**
@@ -207,11 +187,26 @@ public class XWPFDocument extends POIXMLDocument {
                );
        }
        
-       public XWPFHeader getDocumentHeader() {
-               return header;
+       /**
+        * Get the document part that's defined as the
+        *  given relationship of the core document.
+        */
+       public PackagePart getPartById(String id) {
+               try {
+                       return getTargetPart(
+                                       getCorePart().getRelationship(id)
+                       );
+               } catch(InvalidFormatException e) {
+                       throw new IllegalArgumentException(e);
+               }
        }
-       public XWPFFooter getDocumentFooter() {
-               return footer;
+
+       /**
+        * Returns the policy on headers and footers, which
+        *  also provides a way to get at them.
+        */
+       public XWPFHeaderFooterPolicy getHeaderFooterPolicy() {
+               return headerFooterPolicy;
        }
        
        /**
diff --git a/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java b/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java
new file mode 100644 (file)
index 0000000..83a67ad
--- /dev/null
@@ -0,0 +1,159 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.xwpf.model;
+
+import java.io.IOException;
+
+import org.apache.poi.xwpf.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFFooter;
+import org.apache.poi.xwpf.usermodel.XWPFHeader;
+import org.apache.xmlbeans.XmlException;
+import org.openxml4j.opc.PackagePart;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.FtrDocument;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.HdrDocument;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHdrFtr;
+
+/**
+ * A .docx file can have no headers/footers, the same header/footer
+ *  on each page, odd/even page footers, and optionally also 
+ *  a different header/footer on the first page.
+ * This class handles sorting out what there is, and giving you
+ *  the right headers and footers for the document.
+ */
+public class XWPFHeaderFooterPolicy {
+       private XWPFHeader firstPageHeader;
+       private XWPFFooter firstPageFooter;
+       
+       private XWPFHeader evenPageHeader;
+       private XWPFFooter evenPageFooter;
+       
+       private XWPFHeader defaultHeader;
+       private XWPFFooter defaultFooter;
+       
+       
+       /**
+        * Figures out the policy for the given document,
+        *  and creates any header and footer objects
+        *  as required.
+        */
+       public XWPFHeaderFooterPolicy(XWPFDocument doc) throws IOException, XmlException {
+               // Grab what headers and footers have been defined
+               // For now, we don't care about different ranges, as it
+               //  doesn't seem that .docx properly supports that
+               //  feature of the file format yet
+               CTSectPr sectPr = doc.getDocumentBody().getSectPr();
+               for(int i=0; i<sectPr.sizeOfHeaderReferenceArray(); i++) {
+                       // Get the header
+                       CTHdrFtrRef ref = sectPr.getHeaderReferenceArray(i);
+                       PackagePart hdrPart = doc.getPartById(ref.getId());
+                       XWPFHeader hdr = new XWPFHeader(
+                                       HdrDocument.Factory.parse(hdrPart.getInputStream()).getHdr()
+                       );
+
+                       // Assign it
+                       if(ref.getType() == STHdrFtr.FIRST) {
+                               firstPageHeader = hdr;
+                       } else if(ref.getType() == STHdrFtr.EVEN) {
+                               evenPageHeader = hdr;
+                       } else {
+                               defaultHeader = hdr;
+                       }
+               }
+               for(int i=0; i<sectPr.sizeOfFooterReferenceArray(); i++) {
+                       // Get the footer
+                       CTHdrFtrRef ref = sectPr.getFooterReferenceArray(i);
+                       PackagePart ftrPart = doc.getPartById(ref.getId());
+                       XWPFFooter ftr = new XWPFFooter(
+                                       FtrDocument.Factory.parse(ftrPart.getInputStream()).getFtr()
+                       );
+
+                       // Assign it
+                       if(ref.getType() == STHdrFtr.FIRST) {
+                               firstPageFooter = ftr;
+                       } else if(ref.getType() == STHdrFtr.EVEN) {
+                               evenPageFooter = ftr;
+                       } else {
+                               defaultFooter = ftr;
+                       }
+               }
+       }
+
+       
+       public XWPFHeader getFirstPageHeader() {
+               return firstPageHeader;
+       }
+       public XWPFFooter getFirstPageFooter() {
+               return firstPageFooter;
+       }
+       /**
+        * Returns the odd page header. This is
+        *  also the same as the default one...
+        */
+       public XWPFHeader getOddPageHeader() {
+               return defaultHeader;
+       }
+       /**
+        * Returns the odd page footer. This is
+        *  also the same as the default one...
+        */
+       public XWPFFooter getOddPageFooter() {
+               return defaultFooter;
+       }
+       public XWPFHeader getEvenPageHeader() {
+               return evenPageHeader;
+       }
+       public XWPFFooter getEvenPageFooter() {
+               return evenPageFooter;
+       }
+       public XWPFHeader getDefaultHeader() {
+               return defaultHeader;
+       }
+       public XWPFFooter getDefaultFooter() {
+               return defaultFooter;
+       }
+
+       /**
+        * Get the header that applies to the given
+        *  (1 based) page.
+        * @param pageNumber The one based page number
+        */
+       public XWPFHeader getHeader(int pageNumber) {
+               if(pageNumber == 1 && firstPageHeader != null) {
+                       return firstPageHeader;
+               }
+               if(pageNumber % 2 == 0 && evenPageHeader != null) {
+                       return evenPageHeader;
+               }
+               return defaultHeader;
+       }
+       /**
+        * Get the footer that applies to the given
+        *  (1 based) page.
+        * @param pageNumber The one based page number
+        */
+       public XWPFFooter getFooter(int pageNumber) {
+               if(pageNumber == 1 && firstPageFooter != null) {
+                       return firstPageFooter;
+               }
+               if(pageNumber % 2 == 0 && evenPageFooter != null) {
+                       return evenPageFooter;
+               }
+               return defaultFooter;
+       }
+}
index 5e30c28408916e161a95f926bc46949ec85d6dd5..3a79da989422b7fa9324ac8444992760ffd91ced 100644 (file)
@@ -17,6 +17,7 @@
 package org.apache.poi.xwpf.usermodel;
 
 import org.apache.poi.xwpf.XWPFDocument;
+import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
 
 /**
  * High level representation of a ooxml text document.
@@ -46,10 +47,7 @@ public class XMLWordDocument {
                return xwpfXML.getComments();
        }
        
-       public XWPFHeader getHeader() {
-               return xwpfXML.getDocumentHeader();
-       }
-       public XWPFFooter getFooter() {
-               return xwpfXML.getDocumentFooter();
+       public XWPFHeaderFooterPolicy getHeaderFooterPolicy() {
+               return xwpfXML.getHeaderFooterPolicy();
        }
 }
diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/model/TestXWPFHeaderFooterPolicy.java b/src/ooxml/testcases/org/apache/poi/xwpf/model/TestXWPFHeaderFooterPolicy.java
new file mode 100644 (file)
index 0000000..b1f6971
--- /dev/null
@@ -0,0 +1,180 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.xwpf.model;
+
+import java.io.File;
+
+import org.apache.poi.POIXMLDocument;
+import org.apache.poi.xwpf.XWPFDocument;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for XWPF Header Footer Stuff
+ */
+public class TestXWPFHeaderFooterPolicy extends TestCase {
+       private XWPFDocument noHeader;
+       private XWPFDocument header;
+       private XWPFDocument headerFooter;
+       private XWPFDocument footer;
+       private XWPFDocument oddEven;
+       private XWPFDocument diffFirst;
+       
+       protected void setUp() throws Exception {
+               super.setUp();
+               File file;
+               
+               file = new File(
+                               System.getProperty("HWPF.testdata.path") +
+                               File.separator + "NoHeadFoot.docx"
+               );
+               assertTrue(file.exists());
+               noHeader = new XWPFDocument(POIXMLDocument.openPackage(file.toString()));
+               
+               file = new File(
+                               System.getProperty("HWPF.testdata.path") +
+                               File.separator + "ThreeColHead.docx"
+               );
+               assertTrue(file.exists());
+               header = new XWPFDocument(POIXMLDocument.openPackage(file.toString()));
+               
+               file = new File(
+                               System.getProperty("HWPF.testdata.path") +
+                               File.separator + "SimpleHeadThreeColFoot.docx"
+               );
+               assertTrue(file.exists());
+               headerFooter = new XWPFDocument(POIXMLDocument.openPackage(file.toString()));
+               
+               file = new File(
+                               System.getProperty("HWPF.testdata.path") +
+                               File.separator + "FancyFoot.docx"
+               );
+               assertTrue(file.exists());
+               footer = new XWPFDocument(POIXMLDocument.openPackage(file.toString()));
+               
+               file = new File(
+                               System.getProperty("HWPF.testdata.path") +
+                               File.separator + "PageSpecificHeadFoot.docx"
+               );
+               assertTrue(file.exists());
+               oddEven = new XWPFDocument(POIXMLDocument.openPackage(file.toString()));
+               
+               file = new File(
+                               System.getProperty("HWPF.testdata.path") +
+                               File.separator + "DiffFirstPageHeadFoot.docx"
+               );
+               assertTrue(file.exists());
+               diffFirst = new XWPFDocument(POIXMLDocument.openPackage(file.toString()));
+       }
+       
+       public void testPolicy() throws Exception {
+               XWPFHeaderFooterPolicy policy;
+               
+               policy = noHeader.getHeaderFooterPolicy();
+               assertNull(policy.getDefaultHeader());
+               assertNull(policy.getDefaultFooter());
+               
+               assertNull(policy.getHeader(1));
+               assertNull(policy.getHeader(2));
+               assertNull(policy.getHeader(3));
+               assertNull(policy.getFooter(1));
+               assertNull(policy.getFooter(2));
+               assertNull(policy.getFooter(3));
+               
+               
+               policy = header.getHeaderFooterPolicy();
+               assertNotNull(policy.getDefaultHeader());
+               assertNull(policy.getDefaultFooter());
+               
+               assertEquals(policy.getDefaultHeader(), policy.getHeader(1));
+               assertEquals(policy.getDefaultHeader(), policy.getHeader(2));
+               assertEquals(policy.getDefaultHeader(), policy.getHeader(3));
+               assertNull(policy.getFooter(1));
+               assertNull(policy.getFooter(2));
+               assertNull(policy.getFooter(3));
+               
+               
+               policy = footer.getHeaderFooterPolicy();
+               assertNull(policy.getDefaultHeader());
+               assertNotNull(policy.getDefaultFooter());
+               
+               assertNull(policy.getHeader(1));
+               assertNull(policy.getHeader(2));
+               assertNull(policy.getHeader(3));
+               assertEquals(policy.getDefaultFooter(), policy.getFooter(1));
+               assertEquals(policy.getDefaultFooter(), policy.getFooter(2));
+               assertEquals(policy.getDefaultFooter(), policy.getFooter(3));
+               
+               
+               policy = headerFooter.getHeaderFooterPolicy();
+               assertNotNull(policy.getDefaultHeader());
+               assertNotNull(policy.getDefaultFooter());
+               
+               assertEquals(policy.getDefaultHeader(), policy.getHeader(1));
+               assertEquals(policy.getDefaultHeader(), policy.getHeader(2));
+               assertEquals(policy.getDefaultHeader(), policy.getHeader(3));
+               assertEquals(policy.getDefaultFooter(), policy.getFooter(1));
+               assertEquals(policy.getDefaultFooter(), policy.getFooter(2));
+               assertEquals(policy.getDefaultFooter(), policy.getFooter(3));
+               
+               
+               policy = oddEven.getHeaderFooterPolicy();
+               assertNotNull(policy.getDefaultHeader());
+               assertNotNull(policy.getDefaultFooter());
+               assertNotNull(policy.getEvenPageHeader());
+               assertNotNull(policy.getEvenPageFooter());
+               
+               assertEquals(policy.getDefaultHeader(), policy.getHeader(1));
+               assertEquals(policy.getEvenPageHeader(), policy.getHeader(2));
+               assertEquals(policy.getDefaultHeader(), policy.getHeader(3));
+               assertEquals(policy.getDefaultFooter(), policy.getFooter(1));
+               assertEquals(policy.getEvenPageFooter(), policy.getFooter(2));
+               assertEquals(policy.getDefaultFooter(), policy.getFooter(3));
+               
+               
+               policy = diffFirst.getHeaderFooterPolicy();
+               assertNotNull(policy.getDefaultHeader());
+               assertNotNull(policy.getDefaultFooter());
+               assertNotNull(policy.getFirstPageHeader());
+               assertNotNull(policy.getFirstPageFooter());
+               assertNull(policy.getEvenPageHeader());
+               assertNull(policy.getEvenPageFooter());
+               
+               assertEquals(policy.getFirstPageHeader(), policy.getHeader(1));
+               assertEquals(policy.getDefaultHeader(), policy.getHeader(2));
+               assertEquals(policy.getDefaultHeader(), policy.getHeader(3));
+               assertEquals(policy.getFirstPageFooter(), policy.getFooter(1));
+               assertEquals(policy.getDefaultFooter(), policy.getFooter(2));
+               assertEquals(policy.getDefaultFooter(), policy.getFooter(3));
+       }
+       
+       public void testContents() throws Exception {
+               XWPFHeaderFooterPolicy policy;
+               
+               // Just test a few bits
+               policy = diffFirst.getHeaderFooterPolicy();
+               
+               assertEquals(
+                       "I am the header on the first page, and I" + '\u2019' + "m nice and simple\n",
+                       policy.getFirstPageHeader().getText()
+               );
+               assertEquals(
+                               "First header column!\tMid header\tRight header!\n", 
+                               policy.getDefaultHeader().getText()
+               );
+       }
+}
index b88f937dceaa77f082a1a96d56f33a704f413099..5a775c361dad2aac53de280bbb287cace6f5507c 100644 (file)
@@ -48,7 +48,7 @@ public class TestXWPFParagraph extends TestCase {
         * Check that we get the right paragraph from the header
         */
        public void testHeaderParagraph() throws Exception {
-               XWPFHeader hdr = xml.getDocumentHeader();
+               XWPFHeader hdr = xml.getHeaderFooterPolicy().getDefaultHeader();
                assertNotNull(hdr);
                
                XWPFParagraph[] ps = hdr.getParagraphs();