]> source.dussan.org Git - poi.git/commitdiff
53009: Problem creating header and footer
authorMark Murphy <jmarkmurphy@apache.org>
Thu, 13 Oct 2016 01:13:45 +0000 (01:13 +0000)
committerMark Murphy <jmarkmurphy@apache.org>
Thu, 13 Oct 2016 01:13:45 +0000 (01:13 +0000)
Task-Url: https://bz.apache.org/bugzilla/show_bug.cgi?id=53009

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

src/examples/src/org/apache/poi/xwpf/usermodel/SimpleDocumentWithHeader.java [new file with mode: 0644]
src/java/org/apache/poi/wp/usermodel/HeaderFooterType.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java
src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java

diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/SimpleDocumentWithHeader.java b/src/examples/src/org/apache/poi/xwpf/usermodel/SimpleDocumentWithHeader.java
new file mode 100644 (file)
index 0000000..7595b5b
--- /dev/null
@@ -0,0 +1,60 @@
+package org.apache.poi.xwpf.usermodel;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFRun;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;
+
+/**
+ * 
+ * @author Richard Ngo
+ *
+ */
+public class SimpleDocumentWithHeader {
+
+       private static XWPFParagraph[] pars;
+
+       public static void main(String[] args) {
+               XWPFDocument doc = new XWPFDocument();
+
+               XWPFParagraph p = doc.createParagraph();
+
+               XWPFRun r = p.createRun();
+               r.setText("Some Text");
+               r.setBold(true);
+               r = p.createRun();
+               r.setText("Goodbye");
+
+               CTP ctP = CTP.Factory.newInstance();
+               CTText t = ctP.addNewR().addNewT();
+               t.setStringValue("header");
+               pars = new XWPFParagraph[1];
+               p = new XWPFParagraph(ctP, doc);
+               pars[0] = p;
+
+               XWPFHeaderFooterPolicy hfPolicy = doc.createHeaderFooterPolicy();
+               hfPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT, pars);
+               
+               ctP = CTP.Factory.newInstance();
+               t = ctP.addNewR().addNewT();
+               t.setStringValue("My Footer");
+               pars[0] = new XWPFParagraph(ctP, doc);
+               hfPolicy.createFooter(XWPFHeaderFooterPolicy.DEFAULT, pars);
+               
+               try {
+                       OutputStream os = new FileOutputStream(new File("header.docx"));
+                       doc.write(os);
+               } catch (IOException e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               }
+               
+       }
+}
\ No newline at end of file
diff --git a/src/java/org/apache/poi/wp/usermodel/HeaderFooterType.java b/src/java/org/apache/poi/wp/usermodel/HeaderFooterType.java
new file mode 100644 (file)
index 0000000..bca6b66
--- /dev/null
@@ -0,0 +1,62 @@
+/* ====================================================================
+   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.wp.usermodel;
+
+/**
+ * @since POI v3.16 beta 1
+ */
+public enum HeaderFooterType {
+
+    /**
+     * This is the default header or Footer, It is displayed on every page where
+     * a more specific header or footer is not specified. It is always displayed
+     * on ODD pages that are not the first page of the section.
+     */
+    DEFAULT(2),
+
+    /**
+     * This is an even page header or footer, it is displayed on even pages that
+     * are not the first page of the section.
+     */
+    EVEN(1),
+
+    /**
+     * This is a first page header or footer It is displayed on the first page
+     * of the section.
+     */
+    FIRST(3);
+    
+    private final int code;
+    
+    private HeaderFooterType(int i) {
+        code = i;
+    }
+    
+    public int toInt() {
+        return code;
+    }
+    
+    public static HeaderFooterType forInt(int i) {
+        for (HeaderFooterType type : values()) {
+            if (type.code == i) {
+                return type;
+            }
+        }
+        throw new IllegalArgumentException("Invalid HeaderFooterType code: " + i);
+    }
+}
index e303fcf343c11e7a14e6f25d53e8c1167cdd862e..ac3d7d5e00e82ec1293fec0ddf7ea13aeabf1029 100644 (file)
@@ -18,9 +18,6 @@ package org.apache.poi.xwpf.model;
 
 import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
 
-import java.io.IOException;
-import java.io.OutputStream;
-
 import org.apache.poi.POIXMLDocumentPart;
 import org.apache.poi.POIXMLDocumentPart.RelationPart;
 import org.apache.poi.util.POILogFactory;
@@ -90,7 +87,7 @@ public class XWPFHeaderFooterPolicy {
      * as required.
      */
     public XWPFHeaderFooterPolicy(XWPFDocument doc) {
-        this(doc, doc.getDocument().getBody().getSectPr());
+        this(doc, null);
     }
 
     /**
@@ -103,6 +100,12 @@ public class XWPFHeaderFooterPolicy {
         // 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
+        if (sectPr == null) {
+            CTBody ctBody = doc.getDocument().getBody();
+            sectPr = ctBody.isSetSectPr()
+                    ? ctBody.getSectPr()
+                    : ctBody.addNewSectPr();
+        }
         this.doc = doc;
         for (int i = 0; i < sectPr.sizeOfHeaderReferenceArray(); i++) {
             // Get the header
@@ -154,7 +157,7 @@ public class XWPFHeaderFooterPolicy {
      * Creates an empty header of the specified type, containing a single
      * empty paragraph, to which you can then set text, add more paragraphs etc.
      */
-    public XWPFHeader createHeader(Enum type) throws IOException {
+    public XWPFHeader createHeader(Enum type) {
         return createHeader(type, null);
     }
 
@@ -163,33 +166,35 @@ public class XWPFHeaderFooterPolicy {
      * supplied (and previously unattached!) paragraphs are
      * added to.
      */
-    public XWPFHeader createHeader(Enum type, XWPFParagraph[] pars) throws IOException {
-        XWPFRelation relation = XWPFRelation.HEADER;
-        String pStyle = "Header";
-        int i = getRelationIndex(relation);
-        HdrDocument hdrDoc = HdrDocument.Factory.newInstance();
-        
-        XWPFHeader wrapper = (XWPFHeader) doc.createRelationship(relation, XWPFFactory.getInstance(), i);
-        wrapper.setXWPFDocument(doc);
-
-        CTHdrFtr hdr = buildHdr(type, pStyle, wrapper, pars);
-        wrapper.setHeaderFooter(hdr);
-
-        OutputStream outputStream = wrapper.getPackagePart().getOutputStream();
-        hdrDoc.setHdr(hdr);
-
-        assignHeader(wrapper, type);
-        hdrDoc.save(outputStream, DEFAULT_XML_OPTIONS);
-        outputStream.close();
-        
-        return wrapper;
+    public XWPFHeader createHeader(Enum type, XWPFParagraph[] pars) {
+        XWPFHeader header = getHeader(type);
+
+        if (header == null) {
+            HdrDocument hdrDoc = HdrDocument.Factory.newInstance();
+
+            XWPFRelation relation = XWPFRelation.HEADER;
+            int i = getRelationIndex(relation);
+
+            XWPFHeader wrapper = (XWPFHeader) doc.createRelationship(relation,
+                    XWPFFactory.getInstance(), i);
+            wrapper.setXWPFDocument(doc);
+
+            String pStyle = "Header";
+            CTHdrFtr hdr = buildHdr(type, pStyle, wrapper, pars);
+            wrapper.setHeaderFooter(hdr);
+            hdrDoc.setHdr(hdr);
+            assignHeader(wrapper, type);
+            header = wrapper;
+        }
+
+        return header;
     }
 
     /**
      * Creates an empty footer of the specified type, containing a single
      * empty paragraph, to which you can then set text, add more paragraphs etc.
      */
-    public XWPFFooter createFooter(Enum type) throws IOException {
+    public XWPFFooter createFooter(Enum type) {
         return createFooter(type, null);
     }
 
@@ -198,25 +203,28 @@ public class XWPFHeaderFooterPolicy {
      * supplied (and previously unattached!) paragraphs are
      * added to.
      */
-    public XWPFFooter createFooter(Enum type, XWPFParagraph[] pars) throws IOException {
-        XWPFRelation relation = XWPFRelation.FOOTER;
-        String pStyle = "Footer";
-        int i = getRelationIndex(relation);
-        FtrDocument ftrDoc = FtrDocument.Factory.newInstance();
-        
-        XWPFFooter wrapper = (XWPFFooter) doc.createRelationship(relation, XWPFFactory.getInstance(), i);
-        wrapper.setXWPFDocument(doc);
-
-        CTHdrFtr ftr = buildFtr(type, pStyle, wrapper, pars);
-        wrapper.setHeaderFooter(ftr);
-
-        OutputStream outputStream = wrapper.getPackagePart().getOutputStream();
-        ftrDoc.setFtr(ftr);
-
-        assignFooter(wrapper, type);
-        ftrDoc.save(outputStream, DEFAULT_XML_OPTIONS);
-        outputStream.close();
-        return wrapper;
+    public XWPFFooter createFooter(Enum type, XWPFParagraph[] pars) {
+        XWPFFooter footer = getFooter(type);
+
+        if (footer == null) {
+            FtrDocument ftrDoc = FtrDocument.Factory.newInstance();
+
+            XWPFRelation relation = XWPFRelation.FOOTER;
+            int i = getRelationIndex(relation);
+
+            XWPFFooter wrapper = (XWPFFooter) doc.createRelationship(relation,
+                    XWPFFactory.getInstance(), i);
+            wrapper.setXWPFDocument(doc);
+
+            String pStyle = "Footer";
+            CTHdrFtr ftr = buildFtr(type, pStyle, wrapper, pars);
+            wrapper.setHeaderFooter(ftr);
+            ftrDoc.setFtr(ftr);
+            assignFooter(wrapper, type);
+            footer = wrapper;
+        }
+
+        return footer;
     }
 
     private int getRelationIndex(XWPFRelation relation) {
@@ -349,6 +357,21 @@ public class XWPFHeaderFooterPolicy {
         }
         return defaultHeader;
     }
+    
+    /**
+     * Get this section header for the given type
+     *
+     * @param type of header to return
+     * @return {@link XWPFHeader} object
+     */
+    public XWPFHeader getHeader(Enum type) {
+        if (type == STHdrFtr.EVEN) {
+            return evenPageHeader;
+        } else if (type == STHdrFtr.FIRST) {
+            return firstPageHeader;
+        }
+        return defaultHeader;
+    }
 
     /**
      * Get the footer that applies to the given
@@ -365,19 +388,31 @@ public class XWPFHeaderFooterPolicy {
         }
         return defaultFooter;
     }
+    
+    /**
+     * Get this section footer for the given type
+     *
+     * @param type of footer to return
+     * @return {@link XWPFFooter} object
+     */
+    public XWPFFooter getFooter(Enum type) {
+        if (type == STHdrFtr.EVEN) {
+            return evenPageFooter;
+        } else if (type == STHdrFtr.FIRST) {
+            return firstPageFooter;
+        }
+        return defaultFooter;
+    }
+    
 
     public void createWatermark(String text) {
         XWPFParagraph[] pars = new XWPFParagraph[1];
-        try {
-            pars[0] = getWatermarkParagraph(text, 1);
-            createHeader(DEFAULT, pars);
-            pars[0] = getWatermarkParagraph(text, 2);
-            createHeader(FIRST, pars);
-            pars[0] = getWatermarkParagraph(text, 3);
-            createHeader(EVEN, pars);
-        } catch (IOException e) {
-            LOG.log(POILogger.ERROR, "error while creating watermark", e);
-        }
+        pars[0] = getWatermarkParagraph(text, 1);
+        createHeader(DEFAULT, pars);
+        pars[0] = getWatermarkParagraph(text, 2);
+        createHeader(FIRST, pars);
+        pars[0] = getWatermarkParagraph(text, 3);
+        createHeader(EVEN, pars);
     }
 
     /*
index 23a63d0e80f114880c2f0bd8c84c33b120bfc5e7..eb9da3c332678d64f524be8569ac85b4197e4e89 100644 (file)
@@ -1,5 +1,6 @@
 /* ====================================================================
    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
@@ -14,6 +15,7 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
+
 package org.apache.poi.xwpf.usermodel;
 
 import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
@@ -55,27 +57,13 @@ import org.apache.poi.util.Internal;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
 import org.apache.poi.util.PackageHelper;
+import org.apache.poi.wp.usermodel.HeaderFooterType;
 import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlObject;
 import org.apache.xmlbeans.XmlOptions;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTComment;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFtnEdn;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSdtBlock;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.CommentsDocument;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.DocumentDocument;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.EndnotesDocument;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.FootnotesDocument;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.NumberingDocument;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.STDocProtect;
-import org.openxmlformats.schemas.wordprocessingml.x2006.main.StylesDocument;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
 
 /**
  * <p>High(ish) level class for working with .docx files.</p>
@@ -438,13 +426,69 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody {
     }
     public XWPFHeaderFooterPolicy createHeaderFooterPolicy() {
         if (headerFooterPolicy == null) {
-            if (! ctDocument.getBody().isSetSectPr()) {
-                ctDocument.getBody().addNewSectPr();
-            }
+//            if (! ctDocument.getBody().isSetSectPr()) {
+//                ctDocument.getBody().addNewSectPr();
+//            }
             headerFooterPolicy = new XWPFHeaderFooterPolicy(this);
         }
         return headerFooterPolicy;
     }
+    
+    /**
+     * Create a header of the given type
+     *
+     * @param type {@link HeaderFooterType} enum
+     * @return object of type {@link XWPFHeader}
+     */
+    public XWPFHeader createHeader(HeaderFooterType type) {
+        XWPFHeaderFooterPolicy hfPolicy = createHeaderFooterPolicy();
+        // TODO this needs to be migrated out into section code
+        if (type == HeaderFooterType.FIRST) {
+            CTSectPr ctSectPr = getSection();
+            if (ctSectPr.isSetTitlePg() == false) {
+                CTOnOff titlePg = ctSectPr.addNewTitlePg();
+                titlePg.setVal(STOnOff.ON);
+            }
+        } else if (type == HeaderFooterType.EVEN) {
+            // TODO Add support for Even/Odd headings and footers
+        }
+        return hfPolicy.createHeader(STHdrFtr.Enum.forInt(type.toInt()));
+    }
+    
+    
+    /**
+     * Create a footer of the given type
+     *
+     * @param type {@link HeaderFooterType} enum
+     * @return object of type {@link XWPFFooter}
+     */
+    public XWPFFooter createFooter(HeaderFooterType type) {
+        XWPFHeaderFooterPolicy hfPolicy = createHeaderFooterPolicy();
+        // TODO this needs to be migrated out into section code
+        if (type == HeaderFooterType.FIRST) {
+            CTSectPr ctSectPr = getSection();
+            if (ctSectPr.isSetTitlePg() == false) {
+                CTOnOff titlePg = ctSectPr.addNewTitlePg();
+                titlePg.setVal(STOnOff.ON);
+            }
+        } else if (type == HeaderFooterType.EVEN) {
+            // TODO Add support for Even/Odd headings and footers
+        }
+        return hfPolicy.createFooter(STHdrFtr.Enum.forInt(type.toInt()));
+    }
+
+    /**
+     * Return the {@link CTSectPr} object that corresponds with the
+     * last section in this document.
+     *
+     * @return {@link CTSectPr} object
+     */
+    private CTSectPr getSection() {
+        CTBody ctBody = getDocument().getBody();
+        return (ctBody.isSetSectPr() ?
+                ctBody.getSectPr() :
+                ctBody.addNewSectPr());
+    }
 
     /**
      * Returns the styles object used