From 05c8f883e4e480a8d07b05738b383e83cf37d4bc Mon Sep 17 00:00:00 2001 From: Paolo Mottadelli Date: Tue, 18 Aug 2009 14:08:09 +0000 Subject: [PATCH] createHeader/Footer methods + tests git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@805422 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/poi/POIXMLDocumentPart.java | 6 +- .../xwpf/model/XWPFHeaderFooterPolicy.java | 181 ++++++++++++++++-- .../apache/poi/xwpf/usermodel/XWPFFooter.java | 8 + .../apache/poi/xwpf/usermodel/XWPFHeader.java | 8 + .../poi/xwpf/usermodel/XWPFHeaderFooter.java | 11 +- .../poi/xwpf/usermodel/XWPFRelation.java | 4 +- .../poi/xwpf/usermodel/TestXWPFHeader.java | 77 ++++++++ .../apache/poi/hwpf/data/headerFooter.docx | Bin 0 -> 28423 bytes 8 files changed, 270 insertions(+), 25 deletions(-) create mode 100644 src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFHeader.java create mode 100644 src/scratchpad/testcases/org/apache/poi/hwpf/data/headerFooter.docx diff --git a/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java b/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java index 6fccf1cb5..0aeba7450 100755 --- a/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java +++ b/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java @@ -190,11 +190,11 @@ public class POIXMLDocumentPart { * @param factory the factory that will create an instance of the requested relation * @return the created child POIXMLDocumentPart */ - protected final POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, POIXMLFactory factory){ + public final POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, POIXMLFactory factory){ return createRelationship(descriptor, factory, -1, false); } - protected final POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, POIXMLFactory factory, int idx){ + public final POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, POIXMLFactory factory, int idx){ return createRelationship(descriptor, factory, idx, false); } @@ -209,11 +209,9 @@ public class POIXMLDocumentPart { */ protected final POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, POIXMLFactory factory, int idx, boolean noRelation){ try { - PackagePartName ppName = PackagingURIHelper.createPartName(descriptor.getFileName(idx)); PackageRelationship rel = null; if(!noRelation) rel = packagePart.addRelationship(ppName, TargetMode.INTERNAL, descriptor.getRelation()); - PackagePart part = packagePart.getPackage().createPart(ppName, descriptor.getContentType()); POIXMLDocumentPart doc = factory.newDocumentPart(descriptor); doc.packageRel = rel; diff --git a/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java b/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java index 3657c1fa6..c73d4ed6f 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java +++ b/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java @@ -17,17 +17,31 @@ package org.apache.poi.xwpf.model; import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.apache.poi.xwpf.usermodel.XWPFFactory; import org.apache.poi.xwpf.usermodel.XWPFFooter; import org.apache.poi.xwpf.usermodel.XWPFHeader; +import org.apache.poi.xwpf.usermodel.XWPFHeaderFooter; +import org.apache.poi.xwpf.usermodel.XWPFRelation; import org.apache.xmlbeans.XmlException; -import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.xmlbeans.XmlOptions; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr; 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; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHdrFtr.Enum; /** * A .docx file can have no headers/footers, the same header/footer @@ -37,6 +51,12 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHdrFtr; * the right headers and footers for the document. */ public class XWPFHeaderFooterPolicy { + public static final Enum DEFAULT = STHdrFtr.DEFAULT; + public static final Enum EVEN = STHdrFtr.EVEN; + public static final Enum FIRST = STHdrFtr.FIRST; + + private XWPFDocument doc; + private XWPFHeader firstPageHeader; private XWPFFooter firstPageFooter; @@ -57,23 +77,19 @@ 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 + this.doc = doc; CTSectPr sectPr = doc.getDocument().getBody().getSectPr(); for(int i=0; i relations = doc.getRelations(); + int i = 1; + for (Iterator it = relations.iterator(); it.hasNext() ; ) { + POIXMLDocumentPart item = it.next(); + if (item.getPackageRelationship().getRelationshipType().equals(relation.getRelation())) { + i++; + } + } + return i; + } + + + private CTHdrFtr buildFtr(Enum type, String pStyle, XWPFHeaderFooter wrapper) { + CTHdrFtr ftr = buildHdrFtr(pStyle); + setFooterReference(type, wrapper); + return ftr; + } + + + private CTHdrFtr buildHdr(Enum type, String pStyle, XWPFHeaderFooter wrapper) { + CTHdrFtr hdr = buildHdrFtr(pStyle); + setHeaderReference(type, wrapper); + return hdr; + } + + + private CTHdrFtr buildHdrFtr(String pStyle) { + CTHdrFtr ftr = CTHdrFtr.Factory.newInstance(); + CTP p = ftr.addNewP(); + byte[] rsidr = doc.getDocument().getBody().getPArray()[0].getRsidR(); + byte[] rsidrdefault = doc.getDocument().getBody().getPArray()[0].getRsidRDefault(); + p.setRsidP(rsidr); + p.setRsidRDefault(rsidrdefault); + CTPPr pPr = p.addNewPPr(); + pPr.addNewPStyle().setVal(pStyle); + return ftr; + } + + + private void setFooterReference(Enum type, XWPFHeaderFooter wrapper) { + CTHdrFtrRef ref = doc.getDocument().getBody().getSectPr().addNewFooterReference(); + ref.setType(type); + ref.setId(wrapper.getPackageRelationship().getId()); + } + + + private void setHeaderReference(Enum type, XWPFHeaderFooter wrapper) { + CTHdrFtrRef ref = doc.getDocument().getBody().getSectPr().addNewHeaderReference(); + ref.setType(type); + ref.setId(wrapper.getPackageRelationship().getId()); + } + + + private XmlOptions commit(XWPFHeaderFooter wrapper) { + XmlOptions xmlOptions = new XmlOptions(wrapper.DEFAULT_XML_OPTIONS); + Map map = new HashMap(); + map.put("http://schemas.openxmlformats.org/officeDocument/2006/math", "m"); + map.put("urn:schemas-microsoft-com:office:office", "o"); + map.put("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r"); + map.put("urn:schemas-microsoft-com:vml", "v"); + map.put("http://schemas.openxmlformats.org/markup-compatibility/2006", "ve"); + map.put("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w"); + map.put("urn:schemas-microsoft-com:office:word", "w10"); + map.put("http://schemas.microsoft.com/office/word/2006/wordml", "wne"); + map.put("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", "wp"); + xmlOptions.setSaveSuggestedPrefixes(map); + return xmlOptions; + } public XWPFHeader getFirstPageHeader() { return firstPageHeader; diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFooter.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFooter.java index 7131cceb8..e0b4ed9a2 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFooter.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFooter.java @@ -16,6 +16,10 @@ ==================================================================== */ package org.apache.poi.xwpf.usermodel; +import java.io.IOException; + +import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.openxml4j.opc.PackageRelationship; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtr; /** @@ -28,5 +32,9 @@ public class XWPFFooter extends XWPFHeaderFooter { public XWPFFooter(CTHdrFtr hdrFtr) { super(hdrFtr); } + + public XWPFFooter(PackagePart part, PackageRelationship rel) throws IOException { + super(part, rel); + } } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeader.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeader.java index 971b403cb..69dc84dec 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeader.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeader.java @@ -16,6 +16,10 @@ ==================================================================== */ package org.apache.poi.xwpf.usermodel; +import java.io.IOException; + +import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.openxml4j.opc.PackageRelationship; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtr; /** @@ -28,5 +32,9 @@ public class XWPFHeader extends XWPFHeaderFooter { public XWPFHeader(CTHdrFtr hdrFtr) { super(hdrFtr); } + + public XWPFHeader(PackagePart part, PackageRelationship rel) throws IOException { + super(part, rel); + } } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeaderFooter.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeaderFooter.java index 3c84bf228..1481697d0 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeaderFooter.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeaderFooter.java @@ -16,12 +16,17 @@ ==================================================================== */ package org.apache.poi.xwpf.usermodel; +import java.io.IOException; + +import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.openxml4j.opc.PackageRelationship; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtr; /** * Parent of XWPF headers and footers */ -public abstract class XWPFHeaderFooter { +public abstract class XWPFHeaderFooter extends POIXMLDocumentPart{ protected CTHdrFtr headerFooter; protected XWPFHeaderFooter(CTHdrFtr hdrFtr) { @@ -30,6 +35,10 @@ public abstract class XWPFHeaderFooter { protected XWPFHeaderFooter() { headerFooter = CTHdrFtr.Factory.newInstance(); } + + public XWPFHeaderFooter(PackagePart part, PackageRelationship rel) throws IOException { + super(part, rel); + } public CTHdrFtr _getHdrFtr() { return headerFooter; diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRelation.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRelation.java index d28915e35..13c12c61b 100755 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRelation.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRelation.java @@ -86,13 +86,13 @@ public final class XWPFRelation extends POIXMLRelation { "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header", "/word/header#.xml", - null + XWPFHeader.class ); public static final XWPFRelation FOOTER = new XWPFRelation( "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer", "/word/footer#.xml", - null + XWPFFooter.class ); public static final XWPFRelation HYPERLINK = new XWPFRelation( null, diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFHeader.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFHeader.java new file mode 100644 index 000000000..61081062e --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFHeader.java @@ -0,0 +1,77 @@ +/* ==================================================================== + 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.IOException; + +import junit.framework.TestCase; + +import org.apache.poi.POIXMLDocument; +import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtr; + +public class TestXWPFHeader extends TestCase { + + public void testSimpleHeader() throws IOException { + File sampleFile = new File( + System.getProperty("HWPF.testdata.path") + + File.separator + "headerFooter.docx" + ); + assertTrue(sampleFile.exists()); + XWPFDocument sampleDoc; + sampleDoc = new XWPFDocument( + POIXMLDocument.openPackage(sampleFile.toString()) + ); + + XWPFHeaderFooterPolicy policy = sampleDoc.getHeaderFooterPolicy(); + + + XWPFHeader header = policy.getDefaultHeader(); + XWPFFooter footer = policy.getDefaultFooter(); + assertNotNull(header); + assertNotNull(footer); + + // TODO verify if the following is correct + assertNull(header.toString()); + + } + + public void testSetHeader() throws IOException { + File sampleFile = new File( + System.getProperty("HWPF.testdata.path") + + File.separator + "sampleDoc.docx" + ); + assertTrue(sampleFile.exists()); + XWPFDocument sampleDoc; + sampleDoc = new XWPFDocument( + POIXMLDocument.openPackage(sampleFile.toString()) + ); + // no header is set (yet) + XWPFHeaderFooterPolicy policy = sampleDoc.getHeaderFooterPolicy(); + assertNull(policy.getDefaultHeader()); + // set a default header and test it is not null + policy.createHeader(policy.DEFAULT); + policy.createHeader(policy.FIRST); + policy.createFooter(policy.DEFAULT); + + assertNotNull(policy.getDefaultHeader()); + assertNotNull(policy.getFirstPageHeader()); + assertNotNull(policy.getDefaultFooter()); + } + +} diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/headerFooter.docx b/src/scratchpad/testcases/org/apache/poi/hwpf/data/headerFooter.docx new file mode 100644 index 0000000000000000000000000000000000000000..87a86c302f3b9c1dc08dc9670a7135ab66491a31 GIT binary patch literal 28423 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