]> source.dussan.org Git - poi.git/commitdiff
57366: XWPFTable to Header / Footer
authorMark Murphy <jmarkmurphy@apache.org>
Sun, 30 Oct 2016 18:49:16 +0000 (18:49 +0000)
committerMark Murphy <jmarkmurphy@apache.org>
Sun, 30 Oct 2016 18:49:16 +0000 (18:49 +0000)
Task-Url: https://bz.apache.org/bugzilla/show_bug.cgi?id=57366

This update contains a breaking change

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

src/examples/src/org/apache/poi/xwpf/usermodel/BetterHeaderFooterExample.java
src/examples/src/org/apache/poi/xwpf/usermodel/HeaderFooterTable.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java
src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeaderFooter.java
src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFHeader.java
src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFPictureData.java

index bb67c5094a22e327b150dab49e6a4df2a6875a4c..99e7dd1ba59314608d8403910c7ef4d1c6760833 100644 (file)
@@ -38,14 +38,10 @@ public class BetterHeaderFooterExample {
 
         // create header/footer functions insert an empty paragraph
         XWPFHeader head = doc.createHeader(HeaderFooterType.DEFAULT);
-        p = head.getParagraphArray(0);
-        r = p.createRun();
-        r.setText("header");
+        head.createParagraph().createRun().setText("header");
         
         XWPFFooter foot = doc.createFooter(HeaderFooterType.DEFAULT);
-        p = foot.getParagraphArray(0);
-        r = p.createRun();
-        r.setText("footer");
+        foot.createParagraph().createRun().setText("footer");
         
         try {
             OutputStream os = new FileOutputStream(new File("header2.docx"));
diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/HeaderFooterTable.java b/src/examples/src/org/apache/poi/xwpf/usermodel/HeaderFooterTable.java
new file mode 100644 (file)
index 0000000..cd1d21f
--- /dev/null
@@ -0,0 +1,97 @@
+/* ====================================================================
+   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.usermodel;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+
+import org.apache.poi.wp.usermodel.HeaderFooterType;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGrid;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGridCol;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblLayoutType;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblLayoutType;
+
+public class HeaderFooterTable {
+
+    public static void main(String[] args) throws IOException {
+        XWPFDocument doc = new XWPFDocument();
+        
+        // Create a header with a 1 row, 3 column table
+        // changes made for issue 57366 allow a new header or footer
+        // to be created empty. This is a change. You will have to add
+        // either a paragraph or a table to the header or footer for
+        // the document to be considered valid.
+        XWPFHeader hdr = doc.createHeader(HeaderFooterType.DEFAULT);
+        XWPFTable tbl = hdr.createTable(1, 3);
+        
+        // Set the padding around text in the cells to 1/10th of an inch
+        int pad = (int) (.1 * 1440);
+        tbl.setCellMargins(pad, pad, pad, pad);
+
+        // Set table width to 6.5 inches in 1440ths of a point
+        tbl.setWidth((int)(6.5 * 1440));
+        // Can not yet set table or cell width properly, tables default to
+        // autofit layout, and this requires fixed layout
+        CTTbl ctTbl = tbl.getCTTbl();
+        CTTblPr ctTblPr = ctTbl.addNewTblPr();
+        CTTblLayoutType layoutType = ctTblPr.addNewTblLayout();
+        layoutType.setType(STTblLayoutType.FIXED);
+
+        // Now set up a grid for the table, cells will fit into the grid
+        // Each cell width is 3120 in 1440ths of an inch, or 1/3rd of 6.5"
+        BigInteger w = new BigInteger("3120");
+        CTTblGrid grid = ctTbl.addNewTblGrid();
+        for (int i = 0; i < 3; i++) {
+            CTTblGridCol gridCol = grid.addNewGridCol();
+            gridCol.setW(w);
+        }
+        
+        // Add paragraphs to the cells
+        XWPFTableRow row = tbl.getRow(0);
+        XWPFTableCell cell = row.getCell(0);
+        XWPFParagraph p = cell.getParagraphArray(0);
+        XWPFRun r = p.createRun();
+        r.setText("header left cell");
+
+        cell = row.getCell(1);
+        p = cell.getParagraphArray(0);
+        r = p.createRun();
+        r.setText("header center cell");
+
+        cell = row.getCell(2);
+        p = cell.getParagraphArray(0);
+        r = p.createRun();
+        r.setText("header right cell");
+
+        // Create a footer with a Paragraph
+        XWPFFooter ftr = doc.createFooter(HeaderFooterType.DEFAULT);
+        p = ftr.createParagraph();
+
+        r = p.createRun();
+        r.setText("footer text");
+
+        OutputStream os = new FileOutputStream(new File("headertable.docx"));
+        doc.write(os);
+        doc.close();
+       }
+
+}
index ac3d7d5e00e82ec1293fec0ddf7ea13aeabf1029..8ff59713af45441d0a8b3ae3ce7aace7fc8e0422 100644 (file)
@@ -271,19 +271,19 @@ public class XWPFHeaderFooterPolicy {
                 ftr.setPArray(i, paragraphs[i].getCTP());
             }
         } else {
-            CTP p = ftr.addNewP();
-            CTBody body = doc.getDocument().getBody();
-            if (body.sizeOfPArray() > 0) {
-                CTP p0 = body.getPArray(0);
-                if (p0.isSetRsidR()) {
-                    byte[] rsidr = p0.getRsidR();
-                    byte[] rsidrdefault = p0.getRsidRDefault();
-                    p.setRsidP(rsidr);
-                    p.setRsidRDefault(rsidrdefault);
-                }
-            }
-            CTPPr pPr = p.addNewPPr();
-            pPr.addNewPStyle().setVal(pStyle);
+//            CTP p = ftr.addNewP();
+//            CTBody body = doc.getDocument().getBody();
+//            if (body.sizeOfPArray() > 0) {
+//                CTP p0 = body.getPArray(0);
+//                if (p0.isSetRsidR()) {
+//                    byte[] rsidr = p0.getRsidR();
+//                    byte[] rsidrdefault = p0.getRsidRDefault();
+//                    p.setRsidP(rsidr);
+//                    p.setRsidRDefault(rsidrdefault);
+//                }
+//            }
+//            CTPPr pPr = p.addNewPPr();
+//            pPr.addNewPStyle().setVal(pStyle);
         }
         return ftr;
     }
index f4a13e454e28aa4e53769dd731b95e202d08c621..a0a6fd0b79023af9118b23dd6c143f9d4a2e3679 100644 (file)
@@ -43,10 +43,10 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
  * Parent of XWPF headers and footers
  */
 public abstract class XWPFHeaderFooter extends POIXMLDocumentPart implements IBody {
-    List<XWPFParagraph> paragraphs = new ArrayList<XWPFParagraph>(1);
-    List<XWPFTable> tables = new ArrayList<XWPFTable>(1);
+    List<XWPFParagraph> paragraphs = new ArrayList<XWPFParagraph>();
+    List<XWPFTable> tables = new ArrayList<XWPFTable>();
     List<XWPFPictureData> pictures = new ArrayList<XWPFPictureData>();
-    List<IBodyElement> bodyElements = new ArrayList<IBodyElement>(1);
+    List<IBodyElement> bodyElements = new ArrayList<IBodyElement>();
 
     CTHdrFtr headerFooter;
     XWPFDocument document;
@@ -323,13 +323,75 @@ public abstract class XWPFHeaderFooter extends POIXMLDocumentPart implements IBo
 
     /**
      * Adds a new paragraph at the end of the header or footer
+     * 
+     * @return new {@link XWPFParagraph} object
      */
     public XWPFParagraph createParagraph() {
         XWPFParagraph paragraph = new XWPFParagraph(headerFooter.addNewP(), this);
         paragraphs.add(paragraph);
+        bodyElements.add(paragraph);
         return paragraph;
     }
     
+    /**
+     * Adds a new table at the end of the header or footer
+     * 
+     * @param rows - number of rows in the table
+     * @param cols - number of columns in the table
+     * @return new {@link XWPFTable} object
+     */
+    public XWPFTable createTable(int rows, int cols) {
+        XWPFTable table = new XWPFTable(headerFooter.addNewTbl(), this, rows, cols);
+        tables.add(table);
+        bodyElements.add(table);
+        return table;
+    }
+    
+    /**
+     * Removes a specific paragraph from this header / footer
+     *
+     * @param paragraph - {@link XWPFParagraph} object to remove
+     */
+    public void removeParagraph(XWPFParagraph paragraph) {
+        if (paragraphs.contains(paragraph)) {
+            CTP ctP = paragraph.getCTP();
+            XmlCursor c = ctP.newCursor();
+            c.removeXml();
+            c.dispose();
+            paragraphs.remove(paragraph);
+            bodyElements.remove(paragraph);
+        }
+    }
+    
+    /**
+     * Removes a specific table from this header / footer
+     * 
+     * @param table - {@link XWPFTable} object to remove 
+     */
+    public void removeTable(XWPFTable table) {
+        if (tables.contains(table)) {
+            CTTbl ctTbl = table.getCTTbl();
+            XmlCursor c = ctTbl.newCursor();
+            c.removeXml();
+            c.dispose();
+            tables.remove(table);
+            bodyElements.remove(table);
+        }
+    }
+    
+    /**
+     * Clears all paragraphs and tables from this header / footer
+     */
+    public void clearHeaderFooter() {
+       XmlCursor c = headerFooter.newCursor();
+       c.removeXmlContents();
+       c.dispose();
+       paragraphs.clear();
+       tables.clear();
+       bodyElements.clear();
+       CTP ctp = CTP.Factory.newInstance();
+    }
+    
     /**
      * add a new paragraph at position of the cursor
      *
@@ -538,4 +600,25 @@ public abstract class XWPFHeaderFooter extends POIXMLDocumentPart implements IBo
     public POIXMLDocumentPart getPart() {
         return this;
     }
+    
+    @Override
+    protected void prepareForCommit() {
+        // must contain at least an empty paragraph
+        if (bodyElements.size() == 0) {
+            createParagraph();
+        }
+        
+        // Cells must contain at least an empty paragraph
+        for (XWPFTable tbl : tables) {
+            for (XWPFTableRow row : tbl.tableRows) {
+                for (XWPFTableCell cell : row.getTableCells()) {
+                    if (cell.getBodyElements().size() == 0) {
+                        cell.addParagraph();
+                    }
+                }
+            }
+        }
+        super.prepareForCommit();
+        
+    }
 }
index 0efb679facb50b2879dded3f13e9d742ace6dfff..371c9da0645da10993d85db677229822c283bae5 100644 (file)
 
 package org.apache.poi.xwpf.usermodel;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
 import java.io.IOException;
 
-import junit.framework.TestCase;
 import org.apache.poi.xwpf.XWPFTestDataSamples;
 import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
+import org.junit.Test;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTText;
 
-public final class TestXWPFHeader extends TestCase {
+public final class TestXWPFHeader {
+
+    @Test
     public void testSimpleHeader() throws IOException {
         XWPFDocument sampleDoc = XWPFTestDataSamples.openSampleDocument("headerFooter.docx");
 
@@ -38,6 +44,7 @@ public final class TestXWPFHeader extends TestCase {
         assertNotNull(footer);
     }
 
+    @Test
     public void testImageInHeader() throws IOException {
         XWPFDocument sampleDoc = XWPFTestDataSamples.openSampleDocument("headerPic.docx");
 
@@ -49,6 +56,7 @@ public final class TestXWPFHeader extends TestCase {
         assertEquals(1, header.getRelations().size());
     }
 
+    @Test
     public void testSetHeader() throws IOException {
         XWPFDocument sampleDoc = XWPFTestDataSamples.openSampleDocument("SampleDoc.docx");
         // no header is set (yet)
@@ -56,6 +64,7 @@ public final class TestXWPFHeader extends TestCase {
         assertNull(policy.getDefaultHeader());
         assertNull(policy.getFirstPageHeader());
         assertNull(policy.getDefaultFooter());
+        assertNull(policy.getFirstPageFooter());
 
         CTP ctP1 = CTP.Factory.newInstance();
         CTR ctR1 = ctP1.addNewR();
@@ -95,29 +104,31 @@ public final class TestXWPFHeader extends TestCase {
         XWPFHeader headerD = policy.createHeader(XWPFHeaderFooterPolicy.DEFAULT, pars);
         XWPFHeader headerF = policy.createHeader(XWPFHeaderFooterPolicy.FIRST);
         // Set a default footer and capture the returned XWPFFooter object.
-        XWPFFooter footer = policy.createFooter(XWPFHeaderFooterPolicy.DEFAULT, pars2);
+        XWPFFooter footerD = policy.createFooter(XWPFHeaderFooterPolicy.DEFAULT, pars2);
+        XWPFFooter footerF = policy.createFooter(XWPFHeaderFooterPolicy.FIRST);
 
         // Ensure the headers and footer were set correctly....
         assertNotNull(policy.getDefaultHeader());
         assertNotNull(policy.getFirstPageHeader());
         assertNotNull(policy.getDefaultFooter());
+        assertNotNull(policy.getFirstPageFooter());
         // ....and that the footer object captured above contains two
         // paragraphs of text.
-        assertEquals(2, footer.getParagraphs().size());
+        assertEquals(2, footerD.getParagraphs().size());
+        assertEquals(0, footerF.getParagraphs().size());
 
         // Check the header created with the paragraph got them, and the one
-        // created without got an empty one
+        // created without got none
         assertEquals(1, headerD.getParagraphs().size());
-        assertEquals(1, headerF.getParagraphs().size());
-
         assertEquals(tText, headerD.getParagraphs().get(0).getText());
-        assertEquals("", headerF.getParagraphs().get(0).getText());
+
+        assertEquals(0, headerF.getParagraphs().size());
 
         // As an additional check, recover the defauls footer and
         // make sure that it contains two paragraphs of text and that
         // both do hold what is expected.
-        footer = policy.getDefaultFooter();
-        XWPFParagraph[] paras = footer.getParagraphs().toArray(new XWPFParagraph[0]);
+        footerD = policy.getDefaultFooter();
+        XWPFParagraph[] paras = footerD.getParagraphs().toArray(new XWPFParagraph[0]);
 
         assertEquals(2, paras.length);
         assertEquals("First paragraph for the footer", paras[0].getText());
@@ -126,12 +137,15 @@ public final class TestXWPFHeader extends TestCase {
 
         // Add some text to the empty header
         String fText1 = "New Text!";
-        headerF.getParagraphs().get(0).insertNewRun(0).setText(fText1);
-        // TODO Add another paragraph and check
-
+        String fText2 = "More Text!";
+        headerF.createParagraph().insertNewRun(0).setText(fText1);
+        headerF.createParagraph().insertNewRun(0).setText(fText2);
+//        headerF.getParagraphs().get(0).insertNewRun(0).setText(fText1);
+    
         // Check it
         assertEquals(tText, headerD.getParagraphs().get(0).getText());
         assertEquals(fText1, headerF.getParagraphs().get(0).getText());
+        assertEquals(fText2, headerF.getParagraphs().get(1).getText());
 
 
         // Save, re-open, ensure it's all still there
@@ -141,7 +155,7 @@ public final class TestXWPFHeader extends TestCase {
         assertNotNull(policy.getFirstPageHeader());
         assertNull(policy.getEvenPageHeader());
         assertNotNull(policy.getDefaultFooter());
-        assertNull(policy.getFirstPageFooter());
+        assertNotNull(policy.getFirstPageFooter());
         assertNull(policy.getEvenPageFooter());
 
         // Check the new headers still have their text
@@ -149,16 +163,20 @@ public final class TestXWPFHeader extends TestCase {
         headerF = policy.getFirstPageHeader();
         assertEquals(tText, headerD.getParagraphs().get(0).getText());
         assertEquals(fText1, headerF.getParagraphs().get(0).getText());
+        assertEquals(fText2, headerF.getParagraphs().get(1).getText());
 
         // Check the new footers have their new text too
-        footer = policy.getDefaultFooter();
-        paras = footer.getParagraphs().toArray(new XWPFParagraph[0]);
+        footerD = policy.getDefaultFooter();
+        paras = footerD.getParagraphs().toArray(new XWPFParagraph[0]);
+        footerF = policy.getFirstPageFooter();
 
         assertEquals(2, paras.length);
         assertEquals("First paragraph for the footer", paras[0].getText());
         assertEquals("Second paragraph for the footer", paras[1].getText());
+        assertEquals(1, footerF.getParagraphs().size());
     }
 
+    @Test
     public void testSetWatermark() throws IOException {
         XWPFDocument sampleDoc = XWPFTestDataSamples.openSampleDocument("SampleDoc.docx");
 
@@ -183,18 +201,22 @@ public final class TestXWPFHeader extends TestCase {
         assertNotNull(policy.getEvenPageHeader());
     }
 
+    @Test
     public void testAddPictureData() {
         // TODO
     }
 
+    @Test
     public void testGetAllPictures() {
         // TODO
     }
 
+    @Test
     public void testGetAllPackagePictures() {
         // TODO
     }
 
+    @Test
     public void testGetPictureDataById() {
         // TODO
     }
index 02ab71adcfc8f89ba573ffad75a08cda1eac1158..f4c0a49c08af522abff6a578ad81e5fb09fa5657 100644 (file)
@@ -73,7 +73,7 @@ public class TestXWPFPictureData extends TestCase {
         // Add a default header
         policy = doc.createHeaderFooterPolicy();
         XWPFHeader header = policy.createHeader(XWPFHeaderFooterPolicy.DEFAULT);
-        header.getParagraphs().get(0).createRun().setText("Hello, Header World!");
+        header.createParagraph().createRun().setText("Hello, Header World!");
         header.createParagraph().createRun().setText("Paragraph 2");
         assertEquals(0, header.getAllPictures().size());
         assertEquals(2, header.getParagraphs().size());