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-ffa450edef68tags/REL_3_16_BETA1
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
/* |
@@ -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 |