57366: XWPFTable to Header / Footer

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
This commit is contained in:
Mark Murphy 2016-10-30 18:49:16 +00:00
parent 6e685dad95
commit 1c3d84671e
6 changed files with 237 additions and 39 deletions

View 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"));

View File

@ -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();
}
}

View 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;
}

View 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();
}
}

View File

@ -17,16 +17,22 @@
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
}

View 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());