From 91f1934fcc0fbcbf3e0c015fbe92adfa8d938a8d Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Fri, 11 Jun 2010 14:37:58 +0000 Subject: [PATCH] Apply (with slight tweaks) patch from Phillip Epp from bug #48574 - further XWPF support for tables, paragraphs, including enhanced support for adding new ones git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@953704 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/status.xml | 1 + .../org/apache/poi/POIXMLDocumentPart.java | 1 - .../xwpf/model/XWPFHeaderFooterPolicy.java | 7 +- .../poi/xwpf/usermodel/BodyElementType.java | 34 + .../apache/poi/xwpf/usermodel/BodyType.java | 37 + .../apache/poi/xwpf/usermodel/Document.java | 38 + .../org/apache/poi/xwpf/usermodel/IBody.java | 131 +++ .../poi/xwpf/usermodel/IBodyElement.java | 31 + .../xwpf/usermodel/ParagraphAlignment.java | 2 +- .../xwpf/usermodel/PositionInParagraph.java | 65 ++ .../org/apache/poi/xwpf/usermodel/TOC.java | 2 +- .../poi/xwpf/usermodel/TextSegement.java | 98 +++ .../poi/xwpf/usermodel/XWPFAbstractNum.java | 59 ++ .../poi/xwpf/usermodel/XWPFDocument.java | 743 +++++++++++++++++- .../apache/poi/xwpf/usermodel/XWPFFooter.java | 117 ++- .../poi/xwpf/usermodel/XWPFFootnote.java | 8 +- .../apache/poi/xwpf/usermodel/XWPFHeader.java | 131 ++- .../poi/xwpf/usermodel/XWPFHeaderFooter.java | 478 ++++++++++- .../poi/xwpf/usermodel/XWPFLatentStyles.java | 48 ++ .../apache/poi/xwpf/usermodel/XWPFNum.java | 65 ++ .../poi/xwpf/usermodel/XWPFNumbering.java | 249 ++++++ .../poi/xwpf/usermodel/XWPFParagraph.java | 475 ++++++++--- .../poi/xwpf/usermodel/XWPFPicture.java | 74 ++ .../poi/xwpf/usermodel/XWPFPictureData.java | 128 +++ .../poi/xwpf/usermodel/XWPFRelation.java | 61 +- .../apache/poi/xwpf/usermodel/XWPFRun.java | 5 +- .../apache/poi/xwpf/usermodel/XWPFStyle.java | 143 ++++ .../apache/poi/xwpf/usermodel/XWPFStyles.java | 201 +++++ .../apache/poi/xwpf/usermodel/XWPFTable.java | 151 +++- .../poi/xwpf/usermodel/XWPFTableCell.java | 316 +++++++- .../poi/xwpf/usermodel/XWPFTableRow.java | 69 +- .../org/apache/poi/xwpf/AllXWPFTests.java | 9 +- .../org/apache/poi/xwpf/TestXWPFDocument.java | 36 + .../poi/xwpf/usermodel/TestXWPFHeader.java | 13 +- .../poi/xwpf/usermodel/TestXWPFNumbering.java | 40 + .../poi/xwpf/usermodel/TestXWPFParagraph.java | 50 +- .../xwpf/usermodel/TestXWPFPictureData.java | 89 +++ .../poi/xwpf/usermodel/TestXWPFStyles.java | 54 ++ .../poi/xwpf/usermodel/TestXWPFTable.java | 14 +- .../poi/xwpf/usermodel/TestXWPFTableRow.java | 46 ++ 40 files changed, 4069 insertions(+), 250 deletions(-) create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/BodyElementType.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/BodyType.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/Document.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/IBody.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/IBodyElement.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/PositionInParagraph.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/TextSegement.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFAbstractNum.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFLatentStyles.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNum.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPicture.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPictureData.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyle.java create mode 100644 src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java create mode 100644 src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFNumbering.java create mode 100644 src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFPictureData.java create mode 100644 src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java create mode 100644 src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFTableRow.java diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 92474f0aa5..9bf39c78e8 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 48574 - further XWPF support for tables, paragraphs, including enhanced support for adding new ones 48245 - tweak HWPF table cell detection to work across more files 48996 - initial support for External Name References in HSSF formula evaluation 46664 - fix up Tab IDs when adding new sheets, so that print areas don't end up invalid diff --git a/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java b/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java index 0aeba7450b..c129b0a793 100644 --- a/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java +++ b/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java @@ -281,5 +281,4 @@ public class POIXMLDocumentPart { protected void onDocumentRead() throws IOException{ } - } 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 11c934f99e..7c90a59baa 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java +++ b/src/ooxml/java/org/apache/poi/xwpf/model/XWPFHeaderFooterPolicy.java @@ -120,8 +120,7 @@ public class XWPFHeaderFooterPolicy { CTHdrFtrRef ref = sectPr.getFooterReferenceArray(i); PackagePart ftrPart = doc.getPartById(ref.getId()); XWPFFooter ftr = new XWPFFooter( - FtrDocument.Factory.parse(ftrPart.getInputStream()).getFtr() - ); + FtrDocument.Factory.parse(ftrPart.getInputStream()).getFtr()); // Assign it Enum type = ref.getType(); @@ -163,6 +162,7 @@ public class XWPFHeaderFooterPolicy { XWPFHeader wrapper = (XWPFHeader)doc.createRelationship(relation, XWPFFactory.getInstance(), i); CTHdrFtr hdr = buildHdr(type, pStyle, wrapper, pars); + wrapper.setHeaderFooter(hdr); OutputStream outputStream = wrapper.getPackagePart().getOutputStream(); hdrDoc.setHdr(hdr); @@ -189,6 +189,7 @@ public class XWPFHeaderFooterPolicy { XWPFFooter wrapper = (XWPFFooter)doc.createRelationship(relation, XWPFFactory.getInstance(), i); CTHdrFtr ftr = buildFtr(type, pStyle, wrapper, pars); + wrapper.setHeaderFooter(ftr); OutputStream outputStream = wrapper.getPackagePart().getOutputStream(); ftrDoc.setFtr(ftr); @@ -459,6 +460,6 @@ public class XWPFHeaderFooterPolicy { shapeTextPath.setString(text); pict.set(group); // end watermark paragraph - return new XWPFParagraph(p); + return new XWPFParagraph(p, null); } } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/BodyElementType.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/BodyElementType.java new file mode 100644 index 0000000000..3df31061a4 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/BodyElementType.java @@ -0,0 +1,34 @@ +/* ==================================================================== + 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; + +/** + *

+ * 9 Jan 2010 + *

+ *

+ * // TODO insert Javadoc here! + *

+ * @author epp + * + */ +public enum BodyElementType { + PARAGRAPH, + TABLE, + +} diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/BodyType.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/BodyType.java new file mode 100644 index 0000000000..10ba6e94a5 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/BodyType.java @@ -0,0 +1,37 @@ +/* ==================================================================== + 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; + +/** + *

+ * 9 Jan 2010 + *

+ *

+ * // TODO insert Javadoc here! + *

+ * @author epp + * + */ +public enum BodyType { + DOCUMENT, + HEADER, + FOOTER, + FOOTNOTE, + TABLECELL + +} diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/Document.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/Document.java new file mode 100644 index 0000000000..2c3d4f732a --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/Document.java @@ -0,0 +1,38 @@ +/* ==================================================================== + 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; + +public interface Document { + /** Extended windows meta file */ + public static final int PICTURE_TYPE_EMF = 2; + + /** Windows Meta File */ + public static final int PICTURE_TYPE_WMF = 3; + + /** Mac PICT format */ + public static final int PICTURE_TYPE_PICT = 4; + + /** JPEG format */ + public static final int PICTURE_TYPE_JPEG = 5; + + /** PNG format */ + public static final int PICTURE_TYPE_PNG = 6; + + /** Device independent bitmap */ + public static final int PICTURE_TYPE_DIB = 7; + +} diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBody.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBody.java new file mode 100644 index 0000000000..35ebffd91e --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBody.java @@ -0,0 +1,131 @@ +/* ==================================================================== + 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.util.List; + +import org.apache.poi.POIXMLDocumentPart; +import org.apache.xmlbeans.XmlCursor; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc; + + + +/** + *

+ * 8 Jan 2010 + *

+ *

+ * // This Interface represents an object, which is able to have a collection of paragraphs and tables + * this can be XWFPDocument, XWPFHeader, XWPFFooter, XWPFTableCell + *

+ * @author Philipp Epp + * + */ +public interface IBody { + /** + * returns the Part, to which the body belongs, which you need for adding relationship to other parts + * Actually it is needed of the class XWPFTableCell. Because you have to know to which part the tableCell + * belongs. + * @return + */ + IBody getPart(); + + /** + * get the PartType of the body, for example + * DOCUMENT, HEADER, FOOTER, FOOTNOTE, + * @return + */ + BodyType getPartType(); + /** + * Returns the paragraph(s) that holds + * the text of the header or footer. + */ + public List getParagraphs(); + + + /** + * Return the table(s) that holds the text + * of the IBodyPart, for complex cases + * where a paragraph isn't used. + */ + public List getTables(); + + /** + * if there is a corresponding {@link XWPFParagraph} of the parameter ctTable in the paragraphList of this header or footer + * the method will return this paragraph + * if there is no corresponding {@link XWPFParagraph} the method will return null + * @param p is instance of CTP and is searching for an XWPFParagraph + * @return null if there is no XWPFParagraph with an corresponding CTPparagraph in the paragraphList of this header or footer + * XWPFParagraph with the correspondig CTP p + */ + public XWPFParagraph getParagraph(CTP p); + + /** + * if there is a corresponding {@link XWPFTable} of the parameter ctTable in the tableList of this header + * the method will return this table + * if there is no corresponding {@link XWPFTable} the method will return null + * @param ctTable + * @return + */ + public XWPFTable getTable(CTTbl ctTable); + + /** + * Returns the paragraph that of position pos + */ + public XWPFParagraph getParagraphArray(int pos); + + /** + * Returns the table at position pos + */ + public XWPFTable getTableArray(int pos); + + /** + *inserts a new paragraph at position of the cursor + * @param cursor + * @return + */ + public XWPFParagraph insertNewParagraph(XmlCursor cursor); + + /** + * inserts a new Table at the cursor position. + * @param cursor + * @return + */ + public XWPFTable insertNewTbl(XmlCursor cursor); + + /** + * inserts a new Table at position pos + * @param pos + * @param table + */ + void insertTable(int pos, XWPFTable table); + + /** + * returns the TableCell to which the Table belongs + * @param cell + * @return + */ + XWPFTableCell getTableCell(CTTc cell); + + + + +} + diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBodyElement.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBodyElement.java new file mode 100644 index 0000000000..03d133b37f --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBodyElement.java @@ -0,0 +1,31 @@ +/* ==================================================================== + 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 org.apache.poi.POIXMLDocumentPart; + +/** + * 9 Jan 2010 + * @author Philipp Epp + * + */ +public interface IBodyElement{ + IBody getPart(); + BodyType getPartType(); + BodyElementType getElementType(); +} diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/ParagraphAlignment.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/ParagraphAlignment.java index 503aeca8e3..2fd6acade0 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/ParagraphAlignment.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/ParagraphAlignment.java @@ -17,8 +17,8 @@ package org.apache.poi.xwpf.usermodel; -import java.util.Map; import java.util.HashMap; +import java.util.Map; /** * Specifies all types of alignment which are available to be applied to objects in a diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/PositionInParagraph.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/PositionInParagraph.java new file mode 100644 index 0000000000..5e387e7f8c --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/PositionInParagraph.java @@ -0,0 +1,65 @@ +/* ==================================================================== + 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; + + +/** + * postion of a character in a paragrapho +* 1st RunPositon +* 2nd TextPosition +* 3rd CharacterPosition +* +* +*/ +public class PositionInParagraph { + private int posRun = 0, posText = 0, posChar = 0; + + public PositionInParagraph(){ + } + + public PositionInParagraph(int posRun, int posText, int posChar){ + this.posRun=posRun; + this.posChar=posChar; + this.posText= posText; + } + + public int getRun() { + return posRun; + } + + public void setRun(int beginRun) { + this.posRun = beginRun; + } + + public int getText() { + return posText; + } + + public void setText(int beginText) { + this.posText = beginText; + } + + public int getChar() { + return posChar; + } + + public void setChar(int beginChar) { + this.posChar = beginChar; + } + +} diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/TOC.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/TOC.java index 60c5386957..f144e624d8 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/TOC.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/TOC.java @@ -18,8 +18,8 @@ package org.apache.poi.xwpf.usermodel; import java.math.BigInteger; -import org.apache.xmlbeans.impl.xb.xmlschema.SpaceAttribute.Space; import org.apache.poi.util.Internal; +import org.apache.xmlbeans.impl.xb.xmlschema.SpaceAttribute.Space; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/TextSegement.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/TextSegement.java new file mode 100644 index 0000000000..23aa158081 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/TextSegement.java @@ -0,0 +1,98 @@ +/* ==================================================================== + 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; + + +/** + * saves the begin and end position of a text in a Paragraph +*/ +public class TextSegement { + private PositionInParagraph beginPos; + private PositionInParagraph endPos; + + public TextSegement(){ + this.beginPos = new PositionInParagraph(); + this. endPos = new PositionInParagraph(); + } + + public TextSegement(int beginRun, int endRun, int beginText, int endText, int beginChar, int endChar){ + PositionInParagraph beginPos = new PositionInParagraph(beginRun, beginText, beginChar); + PositionInParagraph endPos = new PositionInParagraph(endRun, endText, endChar); + this.beginPos = beginPos; + this.endPos = endPos; + } + + public TextSegement(PositionInParagraph beginPos, PositionInParagraph endPos){ + this.beginPos = beginPos; + this.endPos = endPos; + } + + public PositionInParagraph getBeginPos(){ + return beginPos; + } + + public PositionInParagraph getEndPos(){ + return endPos; + } + + public int getBeginRun(){ + return beginPos.getRun(); + } + + public void setBeginRun(int beginRun){ + beginPos.setRun(beginRun); + } + + public int getBeginText(){ + return beginPos.getText(); + } + + public void setBeginText(int beginText){ + beginPos.setText(beginText); + } + + public int getBeginChar(){ + return beginPos.getChar(); + } + + public void setBeginChar(int beginChar){ + beginPos.setChar(beginChar); + } + public int getEndRun(){ + return endPos.getRun(); + } + + public void setEndRun(int endRun){ + endPos.setRun(endRun); + } + + public int getEndText(){ + return endPos.getText(); + } + + public void setEndText(int endText){ + endPos.setText(endText); + } + + public int getEndChar(){ + return endPos.getChar(); + } + + public void setEndChar(int endChar){ + endPos.setChar(endChar); + } +} diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFAbstractNum.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFAbstractNum.java new file mode 100644 index 0000000000..12d2d3a02c --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFAbstractNum.java @@ -0,0 +1,59 @@ +/* ==================================================================== + 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 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum; + +/** + * @author Philipp Epp + * + */ +public class XWPFAbstractNum { + private CTAbstractNum ctAbstractNum; + protected XWPFNumbering numbering; + + protected XWPFAbstractNum() { + this.ctAbstractNum = null; + this.numbering = null; + + } + public XWPFAbstractNum(CTAbstractNum abstractNum){ + this.ctAbstractNum = abstractNum; + } + + public XWPFAbstractNum(CTAbstractNum ctAbstractNum, XWPFNumbering numbering){ + this.ctAbstractNum = ctAbstractNum; + this.numbering = numbering; + } + public CTAbstractNum getAbstractNum(){ + return ctAbstractNum; + } + + public XWPFNumbering getNumbering(){ + return numbering; + } + + public CTAbstractNum getCTAbstractNum(){ + return ctAbstractNum; + } + + public void setNumbering(XWPFNumbering numbering){ + this.numbering = numbering; + } + +} diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java index 2959317bfb..d7a7851963 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java @@ -22,6 +22,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -43,19 +44,24 @@ import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; import org.apache.poi.openxml4j.opc.PackagingURIHelper; import org.apache.poi.openxml4j.opc.TargetMode; -import org.apache.poi.util.PackageHelper; +import org.apache.poi.util.IOUtils; import org.apache.poi.util.Internal; +import org.apache.poi.util.PackageHelper; 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.CTBody; +import org.openxmlformats.schemas.drawingml.x2006.main.CTTableRow; 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; @@ -67,23 +73,29 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.StylesDocument; * Experimental class to do low level processing * of docx files. * - * If you are using these low level classes, then you + * If you're using these low level classes, then you * will almost certainly need to refer to the OOXML * specifications from * http://www.ecma-international.org/publications/standards/Ecma-376.htm * * WARNING - APIs expected to change rapidly */ -public class XWPFDocument extends POIXMLDocument { +public class XWPFDocument extends POIXMLDocument implements Document, IBody { private CTDocument1 ctDocument; private XWPFSettings settings; + protected List footers; + protected List headers; protected List comments; protected List hyperlinks; protected List paragraphs; protected List tables; + protected List bodyElements; + protected List pictures; protected Map footnotes; protected Map endnotes; + protected XWPFNumbering numbering; + protected XWPFStyles styles; /** Handles the joy of different headers/footers for different pages */ private XWPFHeaderFooterPolicy headerFooterPolicy; @@ -113,6 +125,9 @@ public class XWPFDocument extends POIXMLDocument { comments = new ArrayList(); paragraphs = new ArrayList(); tables= new ArrayList(); + bodyElements = new ArrayList(); + footers = new ArrayList(); + headers = new ArrayList(); footnotes = new HashMap(); endnotes = new HashMap(); @@ -120,27 +135,49 @@ public class XWPFDocument extends POIXMLDocument { DocumentDocument doc = DocumentDocument.Factory.parse(getPackagePart().getInputStream()); ctDocument = doc.getDocument(); - CTBody body = ctDocument.getBody(); - initFootnotes(); - - // filling paragraph list - for (CTP p : body.getPArray()) { - paragraphs.add(new XWPFParagraph(p, this)); - } - - // Get any tables - for(CTTbl table : body.getTblArray()) { - tables.add(new XWPFTable(this, table)); + + + // parse the document with cursor and add + // the XmlObject to its lists + XmlCursor cursor = ctDocument.getBody().newCursor(); + cursor.selectPath("./*"); + while (cursor.toNextSelection()) { + XmlObject o = cursor.getObject(); + if (o instanceof CTP) { + XWPFParagraph p = new XWPFParagraph((CTP)o, this); + bodyElements.add(p); + paragraphs.add(p); + } + if (o instanceof CTTbl) { + XWPFTable t = new XWPFTable((CTTbl)o, this); + bodyElements.add(t); + tables.add(t); + } } - + // Sort out headers and footers if (doc.getDocument().getBody().getSectPr() != null) headerFooterPolicy = new XWPFHeaderFooterPolicy(this); - + + // Create for each XML-part in the Package a PartClass for(POIXMLDocumentPart p : getRelations()){ String relation = p.getPackageRelationship().getRelationshipType(); - if(relation.equals(XWPFRelation.COMMENT.getRelation())){ + if(relation.equals(XWPFRelation.STYLES.getRelation())){ + this.styles = (XWPFStyles) p; + } + else if(relation.equals(XWPFRelation.NUMBERING.getRelation())){ + this.numbering = (XWPFNumbering) p; + + } + else if(relation.equals(XWPFRelation.FOOTER.getRelation())){ + footers.add((XWPFFooter)p); + } + else if(relation.equals(XWPFRelation.HEADER.getRelation())){ + headers.add((XWPFHeader)p); + } + + else if(relation.equals(XWPFRelation.COMMENT.getRelation())){ CommentsDocument cmntdoc = CommentsDocument.Factory.parse(p.getPackagePart().getInputStream()); for(CTComment ctcomment : cmntdoc.getComments().getCommentArray()) { comments.add(new XWPFComment(ctcomment)); @@ -155,12 +192,14 @@ public class XWPFDocument extends POIXMLDocument { } catch (XmlException e) { throw new POIXMLException(e); } + // create for every Graphic-Part in Package a new XWPFGraphic + getAllPictures(); } private void initHyperlinks(){ // Get the hyperlinks // TODO: make me optional/separated in private function - try { + try { Iterator relIter = getPackagePart().getRelationshipsByType(XWPFRelation.HYPERLINK.getRelation()).iterator(); while(relIter.hasNext()) { @@ -192,10 +231,10 @@ public class XWPFDocument extends POIXMLDocument { } /** - * Create a new SpreadsheetML package and setup the default minimal content + * Create a new WordProcessingML package and setup the default minimal content */ protected static OPCPackage newPackage() { - try { + try { OPCPackage pkg = OPCPackage.create(new ByteArrayOutputStream()); // Main part PackagePartName corePartName = PackagingURIHelper.createPartName(XWPFRelation.DOCUMENT.getDefaultFileName()); @@ -237,21 +276,90 @@ public class XWPFDocument extends POIXMLDocument { public CTDocument1 getDocument() { return ctDocument; } - - public Iterator getParagraphsIterator() { - return paragraphs.iterator(); + + /** + * returns an Iterator with paragraphs and tables + * @see org.apache.poi.xwpf.usermodel.IBody#getBodyElements() + * @return + */ + public List getBodyElements(){ + return Collections.unmodifiableList(bodyElements); } - public XWPFParagraph[] getParagraphs() { - return paragraphs.toArray( - new XWPFParagraph[paragraphs.size()] - ); + + /** + * @see org.apache.poi.xwpf.usermodel.IBody#getParagraphs() + */ + public List getParagraphs(){ + return Collections.unmodifiableList(paragraphs); } - - public Iterator getTablesIterator() - { - return tables.iterator(); + + /** + * @see org.apache.poi.xwpf.usermodel.IBody#getTables() + * @return + */ + public List getTables(){ + return Collections.unmodifiableList(tables); + } + + /** + * @see org.apache.poi.xwpf.usermodel.IBody#getTableArray(int) + */ + @Override + public XWPFTable getTableArray(int pos) { + if(pos > 0 && pos < tables.size()){ + return tables.get(pos); + } + return null; + } + + /** + * + * @return + */ + public List getFooterList(){ + return Collections.unmodifiableList(footers); + } + + /** + * + * @param pos + * @return + */ + public XWPFFooter getFooterArray(int pos){ + return footers.get(pos); + } + + /** + * + * @return + */ + public List getHeaderList(){ + return Collections.unmodifiableList(headers); + } + + /** + * + * @param pos + * @return + */ + public XWPFHeader getHeaderArray(int pos){ + return headers.get(pos); + } + + /** + * + * @param table + * @return + */ + public String getTblStyle(XWPFTable table){ + return table.getStyleID(); } + /** + * + * @param id + * @return + */ public XWPFHyperlink getHyperlinkByID(String id) { Iterator iter = hyperlinks.iterator(); while(iter.hasNext()) @@ -264,18 +372,36 @@ public class XWPFDocument extends POIXMLDocument { return null; } + /** + * + * @param id + * @return + */ public XWPFFootnote getFootnoteByID(int id) { return footnotes.get(id); } + /** + * + * @param id + * @return + */ public XWPFFootnote getEndnoteByID(int id) { return endnotes.get(id); } + /** + * + * @return + */ public Collection getFootnotes() { - return footnotes == null ? new ArrayList() : footnotes.values(); + return Collections.unmodifiableCollection(footnotes == null ? new ArrayList() : footnotes.values()); } + /** + * + * @return + */ public XWPFHyperlink[] getHyperlinks() { return hyperlinks.toArray( new XWPFHyperlink[hyperlinks.size()] @@ -356,7 +482,198 @@ public class XWPFDocument extends POIXMLDocument { return embedds; } + + /** + * get with the position of a Paragraph in the bodyelement array list + * the position of this paragraph in the paragraph array list + * @param pos position of the paragraph in the bodyelement array list + * @return if there is a paragraph at the position in the bodyelement array list, + * else it will return -1 + * + */ + public int getParagraphPos(int pos){ + if(pos >= 0 && pos < bodyElements.size()){ + if(bodyElements.get(pos).getElementType() == BodyElementType.PARAGRAPH){ + int startPos; + //find the startpoint for searching + if(pos < paragraphs.size()){ + startPos = pos; + } + else{ + startPos = (paragraphs.size()); + } + for(int i = startPos; i < 0; i--){ + if(paragraphs.get(i) == bodyElements.get(pos)) + return i; + } + } + } + if(paragraphs.size() == 0){ + return 0; + } + return -1; + } + + /** + * get with the position of a table in the bodyelement array list + * the position of this table in the table array list + * @param pos position of the table in the bodyelement array list + * @return if there is a table at the position in the bodyelement array list, + * else it will return null. + */ + public int getTablePos(int pos){ + if(pos >= 0 && pos < bodyElements.size()){ + if(bodyElements.get(pos).getElementType() == BodyElementType.TABLE){ + int startPos; + //find the startpoint for searching + if(pos < tables.size()){ + startPos = pos; + } + else{ + startPos = (tables.size()); + } + for(int i = startPos; i > 0; i--){ + if(tables.get(i) == bodyElements.get(pos)) + return i; + } + } + } + if(tables.size() == 0){ + return 0; + } + else + return -1; + } + + /** + * add a new paragraph at position of the cursor + * @param cursor + * @return + */ + public XWPFParagraph insertNewParagraph(XmlCursor cursor){ + if(isCursorInBody(cursor)){ + String uri = CTP.type.getName().getNamespaceURI(); + String localPart = "p"; + cursor.beginElement(localPart,uri); + cursor.toParent(); + CTP p = (CTP)cursor.getObject(); + XWPFParagraph newP = new XWPFParagraph(p, this); + XmlObject o = null; + while(!(o instanceof CTP)&&(cursor.toPrevSibling())){ + o = cursor.getObject(); + } + if((!(o instanceof CTP)) || (CTP)o == p){ + paragraphs.add(0, newP); + } + else{ + int pos = paragraphs.indexOf(getParagraph((CTP)o))+1; + paragraphs.add(pos,newP); + } + int i=0; + cursor.toCursor(p.newCursor()); + while(cursor.toPrevSibling()){ + o =cursor.getObject(); + if(o instanceof CTP || o instanceof CTTbl) + i++; + } + bodyElements.add(i, newP); + cursor.toCursor(p.newCursor()); + cursor.toEndToken(); + return newP; + } + return null; + } + + /** + * + * @param cursor + * @return + */ + public XWPFTable insertNewTbl(XmlCursor cursor) { + if(isCursorInBody(cursor)){ + String uri = CTTbl.type.getName().getNamespaceURI(); + String localPart ="tbl"; + cursor.beginElement(localPart,uri); + cursor.toParent(); + CTTbl t = (CTTbl)cursor.getObject(); + XWPFTable newT = new XWPFTable(t, this); + cursor.removeXmlContents(); + XmlObject o = null; + while(!(o instanceof CTTbl)&&(cursor.toPrevSibling())){ + o = cursor.getObject(); + } + if(!(o instanceof CTTbl)){ + tables.add(0, newT); + } + else{ + int pos = tables.indexOf(getTable((CTTbl)o))+1; + tables.add(pos,newT); + } + int i=0; + cursor = t.newCursor(); + while(cursor.toPrevSibling()){ + o =cursor.getObject(); + if(o instanceof CTP || o instanceof CTTbl) + i++; + } + bodyElements.add(i, newT); + cursor = t.newCursor(); + cursor.toEndToken(); + return newT; + } + return null; + } + + /** + * verifies that cursor is on the right position + * @param cursor + * @return + */ + private boolean isCursorInBody(XmlCursor cursor) { + XmlCursor verify = cursor.newCursor(); + verify.toParent(); + if(verify.getObject() == this.ctDocument.getBody()){ + return true; + } + XmlObject o = verify.getObject(); + return false; + + } + + /** + * get position of the paragraph + * @param p + * @return + */ + public Integer getPosOfParagraph(XWPFParagraph p){ + int i, pos = 0; + for (i = 0 ; i < bodyElements.size() ; i++) { + if (bodyElements.get(i) instanceof XWPFParagraph){ + if (bodyElements.get(i).equals(p)){ + return pos; + } + pos++; + } + } + return null; + } + + public Integer getPosOfTable(XWPFTable t){ + int i, pos = 0; + for(i = 0; i < bodyElements.size(); i++){ + if(bodyElements.get(i).getElementType() == BodyElementType.TABLE){ + if (bodyElements.get(i) == t){ + return pos; + } + pos++; + } + } + return null; + } + /** + * commit and saves the document + */ @Override protected void commit() throws IOException { @@ -382,20 +699,62 @@ public class XWPFDocument extends POIXMLDocument { /** * Appends a new paragraph to this document - * * @return a new paragraph */ public XWPFParagraph createParagraph(){ return new XWPFParagraph(ctDocument.getBody().addNewP(), this); } + + /** + * remove a BodyElement from bodyElements array list + * @param pos + * @return true if removing was successfully, else return false + */ + public boolean removeBodyElement(int pos){ + if(pos >= 0 && pos < bodyElements.size()){ + if(bodyElements.get(pos).getElementType() == BodyElementType.TABLE){ + bodyElements.remove(pos); + Integer tablePos = getTablePos(pos); + tables.remove(tablePos); + ctDocument.getBody().removeTbl(tablePos); + return true; + } + if(bodyElements.get(pos).getElementType() == BodyElementType.PARAGRAPH){ + bodyElements.remove(pos); + Integer paraPos = getParagraphPos(pos); + paragraphs.remove(paraPos); + ctDocument.getBody().removeP(paraPos); + return true; + } + } + return false; + } + + /** + * copies content of a paragraph to a existing paragraph in the list paragraphs at position pos + * @param paragraph + * @param pos + */ + public void setParagraph(XWPFParagraph paragraph, int pos){ + paragraphs.set(pos, paragraph); + ctDocument.getBody().setPArray(pos, paragraph.getCTP()); + } + + /** + * get the LastParagraph of the document + * @return + */ + public XWPFParagraph getLastParagraph(){ + int lastPos = paragraphs.toArray().length - 1; + return paragraphs.get(lastPos); + } /** * Create an empty table with one row and one column as default. - * * @return a new table */ public XWPFTable createTable(){ - return new XWPFTable(this, ctDocument.getBody().addNewTbl()); + return new XWPFTable(ctDocument.getBody().addNewTbl(), this); } /** @@ -405,15 +764,17 @@ public class XWPFDocument extends POIXMLDocument { * @return table */ public XWPFTable createTable(int rows, int cols) { - return new XWPFTable(this, ctDocument.getBody().addNewTbl(), rows, cols); + return new XWPFTable(ctDocument.getBody().addNewTbl(), this, rows, cols); } - + + + /** + * + */ public void createTOC() { CTSdtBlock block = this.getDocument().getBody().addNewSdt(); TOC toc = new TOC(block); - int i = 1; - for (Iterator iterator = getParagraphsIterator() ; iterator.hasNext() ; ) { - XWPFParagraph par = iterator.next(); + for (XWPFParagraph par: paragraphs ) { String parStyle = par.getStyle(); if (parStyle != null && parStyle.substring(0, 7).equals("Heading")) { try { @@ -426,7 +787,15 @@ public class XWPFDocument extends POIXMLDocument { } } } - + + /**Replace content of table in array tables at position pos with a + * @param pos, table + */ + public void setTable(int pos, XWPFTable table){ + tables.set(pos, table); + ctDocument.getBody().setTblArray(pos, table.getCTTbl()); + } + /** * Verifies that the documentProtection tag in settings.xml file
* specifies that the protection is enforced (w:enforcement="1")
@@ -568,4 +937,292 @@ public class XWPFDocument extends POIXMLDocument { settings.removeEnforcement(); } -} + /** + * inserts an existing XWPFTable to the arrays bodyElements and tables + * @param i + * @param table + */ + @Override + public void insertTable(int pos, XWPFTable table) { + bodyElements.add(pos, table); + int i; + for (i = 0; i < ctDocument.getBody().getTblArray().length; i++) { + CTTbl tbl = ctDocument.getBody().getTblArray(i); + if(tbl == table.getCTTbl()){ + break; + } + } + tables.add(i, table); + } + + /** + * + * @return + */ + public List getAllPictures() { + if(pictures == null){ + pictures = new ArrayList(); + for (POIXMLDocumentPart poixmlDocumentPart : getRelations()){ + if(poixmlDocumentPart instanceof XWPFPictureData){ + pictures.add((XWPFPictureData)poixmlDocumentPart); + } + } + } + return pictures; + } + + /** + * get all Pictures in this package + * @return + */ + public List getAllPackagePictures(){ + List pkgpictures = new ArrayList(); + pkgpictures.addAll(getAllPictures()); + for (POIXMLDocumentPart poixmlDocumentPart : getRelations()){ + if(poixmlDocumentPart instanceof XWPFHeaderFooter){ + pkgpictures.addAll(((XWPFHeaderFooter)poixmlDocumentPart).getAllPictures()); + } + } + return pkgpictures; + } + + /** + * Adds a picture to the document. + * + * @param is The stream to read image from + * @param format The format of the picture. + * + * @return the index to this picture (0 based), the added picture can be obtained from {@link #getAllPictures()} . + * @throws InvalidFormatException + */ + public int addPicture(InputStream is, int format) throws IOException, InvalidFormatException { + int imageNumber = getNextPicNameNumber(format); + XWPFPictureData img = (XWPFPictureData)createRelationship(XWPFPictureData.RELATIONS[format], XWPFFactory.getInstance(), imageNumber, true); + OutputStream out = img.getPackagePart().getOutputStream(); + IOUtils.copy(is, out); + out.close(); + pictures.add(img); + return getAllPictures().size()-1; + + } + + /** + * Adds a picture to the document. + * + * @param is The stream to read image from + * @param format The format of the picture. + * + * @return the index to this picture (0 based), the added picture can be obtained from {@link #getAllPictures()} . + * @throws InvalidFormatException + */ + public int addPicture(byte[] pictureData, int format) throws InvalidFormatException { + int imageNumber = getNextPicNameNumber(format); + XWPFPictureData img = (XWPFPictureData)createRelationship(XWPFPictureData.RELATIONS[format], XWPFFactory.getInstance(), imageNumber, false); + try { + OutputStream out = img.getPackagePart().getOutputStream(); + out.write(pictureData); + out.close(); + } catch (IOException e){ + throw new POIXMLException(e); + } + + pictures.add(img); + return getAllPictures().size()-1; + } + + /** + * get the next free ImageNumber + * @param format + * @return + * @throws InvalidFormatException + */ + public int getNextPicNameNumber(int format) throws InvalidFormatException{ + int img = getAllPackagePictures().size()+1; + String proposal = XWPFPictureData.RELATIONS[format].getFileName(img); + PackagePartName createPartName = PackagingURIHelper.createPartName(proposal); + while (this.getPackage().getPart(createPartName)!= null){ + img++; + proposal = XWPFPictureData.RELATIONS[format].getFileName(img); + createPartName = PackagingURIHelper.createPartName(proposal); + } + return img; + } + + /** + * returns the PictureData by blipID + * @param blipID + * @return XWPFPictureData of a specificID + * @throws Exception + */ + public XWPFPictureData getPictureDataByID(String blipID) { + for(POIXMLDocumentPart part: getRelations()){ + if(part.getPackageRelationship() != null){ + if(part.getPackageRelationship().getId() != null){ + if(part.getPackageRelationship().getId().equals(blipID)){ + return (XWPFPictureData)part; + } + } + } + } + return null; + } + + /** + * Add the picture to drawing relations + * + * @param img the PictureData of the Picture, + * @throws InvalidFormatException + */ + public PackageRelationship addPictureReference(byte[] pictureData, int format) throws InvalidFormatException{ + int imageNumber = getNextPicNameNumber(format); + XWPFPictureData img = (XWPFPictureData)createRelationship(XWPFPictureData.RELATIONS[format], XWPFFactory.getInstance(), imageNumber, false); + PackageRelationship rel = null; + try { + OutputStream out = img.getPackagePart().getOutputStream(); + out.write(pictureData); + out.close(); + rel = img.getPackageRelationship(); + pictures.add(img); + } catch (IOException e){ + throw new POIXMLException(e); + } + return rel; + } + + /** + * Add the picture to drawing relations + * + * @param img the PictureData of the Picture, + * @throws InvalidFormatException + * @throws IOException + */ + public PackageRelationship addPictureReference(InputStream is, int format) throws InvalidFormatException, IOException{ + + PackageRelationship rel = null; + int imageNumber = getNextPicNameNumber(format); + XWPFPictureData img = (XWPFPictureData)createRelationship(XWPFPictureData.RELATIONS[format], XWPFFactory.getInstance(), imageNumber, false); + OutputStream out = img.getPackagePart().getOutputStream(); + IOUtils.copy(is, out); + out.close(); + rel = img.getPackageRelationship(); + pictures.add(img); + return rel; + } + + /** + * getNumbering + * @return numbering + */ + public XWPFNumbering getNumbering(){ + return numbering; + } + + /** + * get Styles + * @return + */ + public XWPFStyles getStyles(){ + return styles; + } + + /** + * get the paragraph with the CTP class p + * @param p + * @return + */ + public XWPFParagraph getParagraph(CTP p){ + for(int i=0; i getTablesIterator() { + return tables.iterator(); + } + + public Iterator getParagraphsIterator() { + return paragraphs.iterator(); + } + + /** + * Returns the paragraph that of position pos + * @see org.apache.poi.xwpf.usermodel.IBody#getParagraphArray(int) + */ + @Override + public XWPFParagraph getParagraphArray(int pos) { + if(pos > 0 && pos < paragraphs.size()){ + return paragraphs.get(pos); + } + return null; + } + + + + /** + * returns the Part, to which the body belongs, which you need for adding relationship to other parts + * Actually it is needed of the class XWPFTableCell. Because you have to know to which part the tableCell + * belongs. + * @see org.apache.poi.xwpf.usermodel.IBody#getPart() + */ + @Override + public IBody getPart() { + return this; + } + + /** + * get the PartType of the body, for example + * DOCUMENT, HEADER, FOOTER, FOOTNOTE, + * @return + * @see org.apache.poi.xwpf.usermodel.IBody#getPartType() + */ + @Override + public BodyType getPartType() { + return BodyType.DOCUMENT; + } + + /** + * get the TableCell which belongs to the TableCell + * @param o + * @return + */ + @Override + public XWPFTableCell getTableCell(CTTc cell) { + XmlCursor cursor = cell.newCursor(); + cursor.toParent(); + XmlObject o = cursor.getObject(); + if(!(o instanceof CTRow)){ + return null; + } + CTRow row = (CTRow)o; + cursor.toParent(); + o = cursor.getObject(); + if(! (o instanceof CTTbl)){ + return null; + } + CTTbl tbl = (CTTbl) o; + XWPFTable table = getTable(tbl); + if(table == null){ + return null; + } + XWPFTableRow tableRow = table.getRow(row); + if(row == null){ + return null; + } + return tableRow.getTableCell(cell); + } +}//end class 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 e0b4ed9a22..4b95ad1c5b 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFooter.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFooter.java @@ -17,10 +17,25 @@ package org.apache.poi.xwpf.usermodel; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.namespace.QName; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; +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.CTHdrFtr; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTNumbering; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.FtrDocument; /** * Sketch of XWPF footer class @@ -29,12 +44,112 @@ public class XWPFFooter extends XWPFHeaderFooter { public XWPFFooter() { super(); } - public XWPFFooter(CTHdrFtr hdrFtr) { + + + public XWPFFooter(CTHdrFtr hdrFtr) throws IOException { super(hdrFtr); + bodyElements = new ArrayList(); + paragraphs = new ArrayList(); + tables = new ArrayList(); + XmlCursor cursor = headerFooter.newCursor(); + cursor.selectPath("./*"); + while (cursor.toNextSelection()) { + XmlObject o = cursor.getObject(); + if (o instanceof CTP) { + XWPFParagraph p = new XWPFParagraph((CTP)o, this); + paragraphs.add(p); + bodyElements.add(p); + } + if (o instanceof CTTbl) { + XWPFTable t = new XWPFTable((CTTbl)o, this); + tables.add(t); + bodyElements.add(t); + } + } + getAllPictures(); } public XWPFFooter(PackagePart part, PackageRelationship rel) throws IOException { super(part, rel); } + /** + * save and commit footer + */ + @Override + protected void commit() throws IOException { + XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS); + xmlOptions.setSaveSyntheticDocumentElement(new QName(CTNumbering.type.getName().getNamespaceURI(), "ftr")); + Map map = new HashMap(); + map.put("http://schemas.openxmlformats.org/markup-compatibility/2006", "ve"); + map.put("urn:schemas-microsoft-com:office:office", "o"); + map.put("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r"); + map.put("http://schemas.openxmlformats.org/officeDocument/2006/math", "m"); + map.put("urn:schemas-microsoft-com:vml", "v"); + map.put("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", "wp"); + map.put("urn:schemas-microsoft-com:office:word", "w10"); + map.put("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w"); + map.put("http://schemas.microsoft.com/office/word/2006/wordml", "wne"); + xmlOptions.setSaveSuggestedPrefixes(map); + PackagePart part = getPackagePart(); + OutputStream out = part.getOutputStream(); + super._getHdrFtr().save(out, xmlOptions); + out.close(); + } + + @Override + protected void onDocumentRead(){ + bodyElements = new ArrayList(); + paragraphs = new ArrayList(); + tables= new ArrayList(); + FtrDocument ftrDocument = null; + InputStream is; + try { + is = getPackagePart().getInputStream(); + ftrDocument = FtrDocument.Factory.parse(is); + headerFooter = ftrDocument.getFtr(); + // parse the document with cursor and add + // the XmlObject to its lists + XmlCursor cursor = headerFooter.newCursor(); + cursor.selectPath("./*"); + while (cursor.toNextSelection()) { + XmlObject o = cursor.getObject(); + if (o instanceof CTP) { + XWPFParagraph p = new XWPFParagraph((CTP)o, this); + paragraphs.add(p); + bodyElements.add(p); + } + if (o instanceof CTTbl) { + XWPFTable t = new XWPFTable((CTTbl)o, this); + tables.add(t); + bodyElements.add(t); + } + } + getAllPictures(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (XmlException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + /** + * returns the Part, to which the body belongs, which you need for adding relationship to other parts + * @see org.apache.poi.xwpf.usermodel.IBody#getPart() + */ + @Override + public IBody getPart() { + return this; + } + + /** + * get the PartType of the body + * @see org.apache.poi.xwpf.usermodel.IBody#getPartType() + */ + @Override + public BodyType getPartType() { + return BodyType.FOOTER; + } + } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFootnote.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFootnote.java index 8ee834d486..b3e30b8e0f 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFootnote.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFootnote.java @@ -16,12 +16,12 @@ ==================================================================== */ package org.apache.poi.xwpf.usermodel; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFtnEdn; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; - -import java.util.List; import java.util.ArrayList; import java.util.Iterator; +import java.util.List; + +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFtnEdn; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; public class XWPFFootnote implements Iterable { private List paragraphs = new ArrayList(); 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 69dc84dec8..c78dc05e5e 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeader.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeader.java @@ -17,24 +17,149 @@ package org.apache.poi.xwpf.usermodel; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import javax.xml.namespace.QName; + +import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; +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.CTHdrFtr; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTNumbering; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.HdrDocument; /** * Sketch of XWPF header class */ public class XWPFHeader extends XWPFHeaderFooter { + public XWPFHeader() { super(); } - public XWPFHeader(CTHdrFtr hdrFtr) { + + public XWPFHeader(PackagePart part, PackageRelationship rel) throws IOException { + super(part, rel); + } + + public XWPFHeader(CTHdrFtr hdrFtr) throws IOException { super(hdrFtr); + paragraphs = new ArrayList(); + tables = new ArrayList(); + XmlCursor cursor = headerFooter.newCursor(); + cursor.selectPath("./*"); + while (cursor.toNextSelection()) { + XmlObject o = cursor.getObject(); + if (o instanceof CTP) { + XWPFParagraph p = new XWPFParagraph((CTP) o, this); + paragraphs.add(p); + } + if (o instanceof CTTbl) { + XWPFTable t = new XWPFTable((CTTbl) o, this); + tables.add(t); + } + } + getAllPictures(); } - public XWPFHeader(PackagePart part, PackageRelationship rel) throws IOException { + /** + public XWPFHeader(PackagePart part, PackageRelationship rel) + throws IOException { super(part, rel); } -} + /** + * save and commit footer + */ + @Override + protected void commit() throws IOException { + XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS); + xmlOptions.setSaveSyntheticDocumentElement(new QName(CTNumbering.type.getName().getNamespaceURI(), "hdr")); + Map map = new HashMap(); + map.put("http://schemas.openxmlformats.org/markup-compatibility/2006", "ve"); + map.put("urn:schemas-microsoft-com:office:office", "o"); + map.put("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r"); + map.put("http://schemas.openxmlformats.org/officeDocument/2006/math", "m"); + map.put("urn:schemas-microsoft-com:vml", "v"); + map.put("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", "wp"); + map.put("urn:schemas-microsoft-com:office:word", "w10"); + map.put("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w"); + map.put("http://schemas.microsoft.com/office/word/2006/wordml", "wne"); + xmlOptions.setSaveSuggestedPrefixes(map); + PackagePart part = getPackagePart(); + OutputStream out = part.getOutputStream(); + super._getHdrFtr().save(out, xmlOptions); + out.close(); + } + + /** + * reads the document + * @overide onDocumentRead of class {@link POIXMLDocumentPart} + */ + @Override + protected void onDocumentRead(){ + bodyElements = new ArrayList(); + paragraphs = new ArrayList(); + tables= new ArrayList(); + HdrDocument hdrDocument = null; + InputStream is; + try { + is = getPackagePart().getInputStream(); + hdrDocument = HdrDocument.Factory.parse(is); + headerFooter = hdrDocument.getHdr(); + // parse the document with cursor and add + // the XmlObject to its lists + XmlCursor cursor = headerFooter.newCursor(); + cursor.selectPath("./*"); + while (cursor.toNextSelection()) { + XmlObject o = cursor.getObject(); + if (o instanceof CTP) { + XWPFParagraph p = new XWPFParagraph((CTP)o, this); + paragraphs.add(p); + bodyElements.add(p); + } + if (o instanceof CTTbl) { + XWPFTable t = new XWPFTable((CTTbl)o, this); + tables.add(t); + bodyElements.add(t); + } + } + getAllPictures(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (XmlException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * returns the Part, to which the body belongs, which you need for adding relationship to other parts + * @see org.apache.poi.xwpf.usermodel.IBody#getPart() + */ + @Override + public IBody getPart() { + return this; + } + + /** + * get the PartType of the body + * @see org.apache.poi.xwpf.usermodel.IBody#getPartType() + */ + @Override + public BodyType getPartType() { + return BodyType.HEADER; + } + + +}//end class 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 367242ee5c..2b11d733a7 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeaderFooter.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeaderFooter.java @@ -17,28 +17,52 @@ package org.apache.poi.xwpf.usermodel; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.apache.poi.POIXMLDocumentPart; -import org.apache.poi.util.Internal; +import org.apache.poi.POIXMLException; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.openxml4j.opc.PackagePartName; import org.apache.poi.openxml4j.opc.PackageRelationship; +import org.apache.poi.openxml4j.opc.PackagingURIHelper; +import org.apache.poi.util.IOUtils; +import org.apache.poi.util.Internal; +import org.apache.xmlbeans.XmlCursor; +import org.apache.xmlbeans.XmlObject; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtr; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc; /** * Parent of XWPF headers and footers */ -public abstract class XWPFHeaderFooter extends POIXMLDocumentPart{ +public abstract class XWPFHeaderFooter extends POIXMLDocumentPart implements IBody{ protected CTHdrFtr headerFooter; + protected List paragraphs; + protected List tables; + protected List pictures; + protected XWPFDocument document; + protected List bodyElements; - protected XWPFHeaderFooter(CTHdrFtr hdrFtr) { + protected XWPFHeaderFooter(CTHdrFtr hdrFtr){ headerFooter = hdrFtr; + readHdrFtr(); } protected XWPFHeaderFooter() { - headerFooter = CTHdrFtr.Factory.newInstance(); + this(CTHdrFtr.Factory.newInstance()); } public XWPFHeaderFooter(PackagePart part, PackageRelationship rel) throws IOException { super(part, rel); + this.document = (XWPFDocument)getParent(); + onDocumentRead(); } @Internal @@ -53,16 +77,11 @@ public abstract class XWPFHeaderFooter extends POIXMLDocumentPart{ * there could be more in certain cases, or * a table. */ - public XWPFParagraph[] getParagraphs() { - XWPFParagraph[] paras = - new XWPFParagraph[headerFooter.getPArray().length]; - for(int i=0; i getParagraphs() { + return Collections.unmodifiableList(paragraphs); + } + + /** * Return the table(s) that holds the text * of the header or footer, for complex cases @@ -71,17 +90,11 @@ public abstract class XWPFHeaderFooter extends POIXMLDocumentPart{ * complex headers/footers have a table or two * in addition. */ - public XWPFTable[] getTables() { - XWPFTable[] tables = - new XWPFTable[headerFooter.getTblArray().length]; - for(int i=0; i getTables()throws ArrayIndexOutOfBoundsException { + return Collections.unmodifiableList(tables); + } + + /** * Returns the textual content of the header/footer, @@ -90,10 +103,9 @@ public abstract class XWPFHeaderFooter extends POIXMLDocumentPart{ public String getText() { StringBuffer t = new StringBuffer(); - XWPFParagraph[] paras = getParagraphs(); - for(int i=0; i 0) { t.append(text); t.append('\n'); @@ -101,9 +113,9 @@ public abstract class XWPFHeaderFooter extends POIXMLDocumentPart{ } } - XWPFTable[] tables = getTables(); - for(int i=0; i tables = getTables(); + for(int i=0; i 0) { t.append(text); t.append('\n'); @@ -112,4 +124,404 @@ public abstract class XWPFHeaderFooter extends POIXMLDocumentPart{ return t.toString(); } -} + + /** + * set a new headerFooter + */ + public void setHeaderFooter(CTHdrFtr headerFooter){ + this.headerFooter = headerFooter; + readHdrFtr(); + } + + /** + * if there is a corresponding {@link XWPFTable} of the parameter ctTable in the tableList of this header + * the method will return this table + * if there is no corresponding {@link XWPFTable} the method will return null + * @param ctTable + * @return + */ + public XWPFTable getTable(CTTbl ctTable){ + for (XWPFTable table : tables) { + if(table==null) + return null; + if(table.getCTTbl().equals(ctTable)) + return table; + } + return null; + } + + /** + * if there is a corresponding {@link XWPFParagraph} of the parameter ctTable in the paragraphList of this header or footer + * the method will return this paragraph + * if there is no corresponding {@link XWPFParagraph} the method will return null + * @param p is instance of CTP and is searching for an XWPFParagraph + * @return null if there is no XWPFParagraph with an corresponding CTPparagraph in the paragraphList of this header or footer + * XWPFParagraph with the correspondig CTP p + */ + public XWPFParagraph getParagraph(CTP p){ + for (XWPFParagraph paragraph : paragraphs) { + if(paragraph.getCTP().equals(p)) + return paragraph; + } + return null; + + } + + /** + * Returns the paragraph that holds + * the text of the header or footer. + */ + public XWPFParagraph getParagraphArray(int pos) { + + return paragraphs.get(pos); + } + + /** + * get a List of all Paragraphs + * @return a list of {@link XWPFParagraph} + */ + public List getListParagraph(){ + return paragraphs; + } + + public List getAllPictures() { + if(pictures == null){ + pictures = new ArrayList(); + for (POIXMLDocumentPart poixmlDocumentPart : getRelations()){ + if(poixmlDocumentPart instanceof XWPFPictureData){ + pictures.add((XWPFPictureData)poixmlDocumentPart); + } + } + } + return pictures; + } + + /** + * get all Pictures in this package + * @return + */ + public List getAllPackagePictures(){ + List pkgpictures = new ArrayList(); + pkgpictures.addAll(getAllPictures()); + for (POIXMLDocumentPart poixmlDocumentPart : getRelations()){ + if(poixmlDocumentPart instanceof XWPFHeaderFooter){ + pkgpictures.addAll(((XWPFHeaderFooter)poixmlDocumentPart).getAllPictures()); + } + } + return pkgpictures; + } + + /** + * Adds a picture to the document. + * + * @param is The stream to read image from + * @param format The format of the picture. + * + * @return the index to this picture (0 based), the added picture can be obtained from {@link #getAllPictures()} . + */ + public int addPicture(InputStream is, int format) throws IOException { + int imageNumber = getNextPicNameNumber(format); + XWPFPictureData img = (XWPFPictureData)createRelationship(XWPFPictureData.RELATIONS[format], XWPFFactory.getInstance(), imageNumber, true); + OutputStream out = img.getPackagePart().getOutputStream(); + IOUtils.copy(is, out); + out.close(); + pictures.add(img); + return getAllPictures().size()-1; + + } + + /** + * Adds a picture to the document. + * + * @param is The stream to read image from + * @param format The format of the picture. + * + * @return the index to this picture (0 based), the added picture can be obtained from {@link #getAllPictures()} . + */ + public int addPicture(byte[] pictureData, int format) { + int imageNumber = getNextPicNameNumber(format); + XWPFPictureData img = (XWPFPictureData)createRelationship(XWPFPictureData.RELATIONS[format], XWPFFactory.getInstance(), imageNumber, false); + try { + OutputStream out = img.getPackagePart().getOutputStream(); + out.write(pictureData); + out.close(); + } catch (IOException e){ + throw new POIXMLException(e); + } + + pictures.add(img); + return getAllPictures().size()-1; + } + + /** + * get the next free ImageNumber + * @param format + * @return + */ + public int getNextPicNameNumber(int format){ + int img = getAllPackagePictures().size()+1; + String proposal = XWPFPictureData.RELATIONS[format].getFileName(img); + try { + PackagePartName createPartName = PackagingURIHelper.createPartName(proposal); + while (this.getPackagePart().getPackage().getPart(createPartName)!= null){ + img++; + proposal = XWPFPictureData.RELATIONS[format].getFileName(img); + createPartName = PackagingURIHelper.createPartName(proposal); + } + } catch (InvalidFormatException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return img; + } + + /** + * returns the PictureData by blipID + * @param blipID + * @return XWPFPictureData of a specificID + * @throws Exception + */ + public XWPFPictureData getPictureDataByID(String blipID) { + for(POIXMLDocumentPart part: getRelations()){ + if(part.getPackageRelationship() != null){ + if(part.getPackageRelationship().getId() != null){ + if(part.getPackageRelationship().getId().equals(blipID)){ + return (XWPFPictureData)part; + } + } + } + } + return null; + } + + /** + * Add the picture to drawing relations + * + * @param img the PictureData of the Picture, + */ + public PackageRelationship addPictureReference(byte[] pictureData, int format){ + int imageNumber = getNextPicNameNumber(format); + XWPFPictureData img = (XWPFPictureData)createRelationship(XWPFPictureData.RELATIONS[format], XWPFFactory.getInstance(), imageNumber, false); + PackageRelationship rel = null; + try { + OutputStream out = img.getPackagePart().getOutputStream(); + out.write(pictureData); + out.close(); + rel = img.getPackageRelationship(); + pictures.add(img); + } catch (IOException e){ + throw new POIXMLException(e); + } + return rel; + } + + /** + * Add the picture to drawing relations + * + * @param img the PictureData of the Picture, + */ + public PackageRelationship addPictureReference(InputStream is, int format){ + + PackageRelationship rel = null; + try { + int imageNumber = getNextPicNameNumber(format); + XWPFPictureData img = (XWPFPictureData)createRelationship(XWPFPictureData.RELATIONS[format], XWPFFactory.getInstance(), imageNumber, false); + OutputStream out = img.getPackagePart().getOutputStream(); + IOUtils.copy(is, out); + out.close(); + rel = img.getPackageRelationship(); + pictures.add(img); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return rel; + } + + /** + * add a new paragraph at position of the cursor + * @param cursor + * @return + */ + public XWPFParagraph insertNewParagraph(XmlCursor cursor){ + if(isCursorInHdrF(cursor)){ + String uri = CTP.type.getName().getNamespaceURI(); + String localPart = "p"; + cursor.beginElement(localPart,uri); + cursor.toParent(); + CTP p = (CTP)cursor.getObject(); + XWPFParagraph newP = new XWPFParagraph(p, this); + XmlObject o = null; + while(!(o instanceof CTP)&&(cursor.toPrevSibling())){ + o = cursor.getObject(); + } + if((!(o instanceof CTP)) || (CTP)o == p){ + paragraphs.add(0, newP); + } + else{ + int pos = paragraphs.indexOf(getParagraph((CTP)o))+1; + paragraphs.add(pos,newP); + } + int i=0; + cursor.toCursor(p.newCursor()); + while(cursor.toPrevSibling()){ + o =cursor.getObject(); + if(o instanceof CTP || o instanceof CTTbl) + i++; + } + bodyElements.add(i, newP); + cursor.toCursor(p.newCursor()); + cursor.toEndToken(); + return newP; + } + return null; + } + + + /** + * + * @param cursor + * @return + */ + public XWPFTable insertNewTbl(XmlCursor cursor) { + if(isCursorInHdrF(cursor)){ + String uri = CTTbl.type.getName().getNamespaceURI(); + String localPart = "tbl"; + cursor.beginElement(localPart,uri); + cursor.toParent(); + CTTbl t = (CTTbl)cursor.getObject(); + XWPFTable newT = new XWPFTable(t, this); + cursor.removeXmlContents(); + XmlObject o = null; + while(!(o instanceof CTTbl)&&(cursor.toPrevSibling())){ + o = cursor.getObject(); + } + if(!(o instanceof CTTbl)){ + tables.add(0, newT); + } + else{ + int pos = tables.indexOf(getTable((CTTbl)o))+1; + tables.add(pos,newT); + } + int i=0; + cursor = t.newCursor(); + while(cursor.toPrevSibling()){ + o =cursor.getObject(); + if(o instanceof CTP || o instanceof CTTbl) + i++; + } + bodyElements.add(i, newT); + cursor = t.newCursor(); + cursor.toEndToken(); + return newT; + } + return null; + } + + /** + * verifies that cursor is on the right position + * @param cursor + * @return + */ + private boolean isCursorInHdrF(XmlCursor cursor) { + XmlCursor verify = cursor.newCursor(); + verify.toParent(); + if(verify.getObject() == this.headerFooter){ + return true; + } + return false; + } + + + public POIXMLDocumentPart getOwner(){ + return this; + } + + /** + * Returns the table at position pos + * @see org.apache.poi.xwpf.usermodel.IBody#getTableArray(int) + */ + @Override + public XWPFTable getTableArray(int pos) { + + if(pos > 0 && pos < tables.size()){ + return tables.get(pos); + } + return null; + } + + /** + * inserts an existing XWPFTable to the arrays bodyElements and tables + * @param i + * @param table + */ + @Override + public void insertTable(int pos, XWPFTable table) { + bodyElements.add(pos, table); + int i; + for (i = 0; i < headerFooter.getTblArray().length; i++) { + CTTbl tbl = headerFooter.getTblArray(i); + if(tbl == table.getCTTbl()){ + break; + } + } + tables.add(i, table); + + } + + public void readHdrFtr(){ + bodyElements = new ArrayList(); + paragraphs = new ArrayList(); + tables= new ArrayList(); + // parse the document with cursor and add + // the XmlObject to its lists + XmlCursor cursor = headerFooter.newCursor(); + cursor.selectPath("./*"); + while (cursor.toNextSelection()) { + XmlObject o = cursor.getObject(); + if (o instanceof CTP) { + XWPFParagraph p = new XWPFParagraph((CTP)o, this); + paragraphs.add(p); + bodyElements.add(p); + } + if (o instanceof CTTbl) { + XWPFTable t = new XWPFTable((CTTbl)o, this); + tables.add(t); + bodyElements.add(t); + } + } + getAllPictures(); + } + + /** + * get the TableCell which belongs to the TableCell + * @param o + * @return + */ + public XWPFTableCell getTableCell(CTTc cell) { + XmlCursor cursor = cell.newCursor(); + cursor.toParent(); + XmlObject o = cursor.getObject(); + if(!(o instanceof CTRow)){ + return null; + } + CTRow row = (CTRow)o; + cursor.toParent(); + o = cursor.getObject(); + if(! (o instanceof CTTbl)){ + return null; + } + CTTbl tbl = (CTTbl) o; + XWPFTable table = getTable(tbl); + if(table == null){ + return null; + } + XWPFTableRow tableRow = table.getRow(row); + if(row == null){ + return null; + } + return tableRow.getTableCell(cell); + } + + +}//end class diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFLatentStyles.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFLatentStyles.java new file mode 100644 index 0000000000..e04dc914f4 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFLatentStyles.java @@ -0,0 +1,48 @@ +/* ==================================================================== + 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 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLatentStyles; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLsdException; + +public class XWPFLatentStyles { + private CTLatentStyles latentStyles; + protected XWPFStyles styles; //LatentStyle shall know styles + + protected XWPFLatentStyles(){ + } + + protected XWPFLatentStyles(CTLatentStyles latentStyles){ + this(latentStyles,null); + } + + protected XWPFLatentStyles(CTLatentStyles latentStyles, XWPFStyles styles) { + this.latentStyles=latentStyles; + this.styles=styles; + } + + /** + * checks wheter specific LatentStyleID is a latentStyle + */ + protected boolean isLatentStyle(String latentStyleID){ + for ( CTLsdException lsd: latentStyles.getLsdExceptionArray()) { + if(lsd.getName().equals(latentStyleID)); + return true; + } + return false; + } +} diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNum.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNum.java new file mode 100644 index 0000000000..300936d2a0 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNum.java @@ -0,0 +1,65 @@ +/* ==================================================================== + 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 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTNum; + +/** + * @author Philipp Epp + * + */ +public class XWPFNum { + private CTNum ctNum; + protected XWPFNumbering numbering; + + public XWPFNum(){ + this.ctNum = null; + this.numbering = null; + } + + public XWPFNum(CTNum ctNum){ + this.ctNum = ctNum; + this.numbering = null; + } + + public XWPFNum(XWPFNumbering numbering){ + this.ctNum = null; + this.numbering = numbering; + } + + public XWPFNum(CTNum ctNum, XWPFNumbering numbering){ + this.ctNum = ctNum; + this.numbering = numbering; + } + + public XWPFNumbering getNumbering(){ + return numbering; + } + + public CTNum getCTNum(){ + return ctNum; + } + + public void setNumbering(XWPFNumbering numbering){ + this.numbering = numbering; + } + + public void setCTNum(CTNum ctNum){ + this.ctNum = ctNum; + } +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java new file mode 100644 index 0000000000..267491ff9e --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java @@ -0,0 +1,249 @@ +/* ==================================================================== + 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.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.namespace.QName; + +import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.POIXMLException; +import org.apache.poi.openxml4j.exceptions.OpenXML4JException; +import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.openxml4j.opc.PackageRelationship; +import org.apache.xmlbeans.XmlException; +import org.apache.xmlbeans.XmlOptions; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTNum; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTNumbering; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.NumberingDocument; + +/** + * @author Philipp Epp + * + */ +public class XWPFNumbering extends POIXMLDocumentPart { + private CTNumbering ctNumbering; + protected List abstractNums; + protected List nums; + protected boolean isNew; + + /** + *create a new styles object with an existing document + */ + public XWPFNumbering(PackagePart part, PackageRelationship rel) throws IOException, OpenXML4JException{ + super(part, rel); + isNew = true; + onDocumentRead(); + } + + /** + * read numbering form an existing package + */ + @Override + protected void onDocumentRead() throws IOException{ + abstractNums = new ArrayList(); + nums = new ArrayList(); + NumberingDocument numberingDoc = null; + InputStream is; + is = getPackagePart().getInputStream(); + try { + numberingDoc = NumberingDocument.Factory.parse(is); + ctNumbering = numberingDoc.getNumbering(); + //get any Nums + for(CTNum ctNum : ctNumbering.getNumArray()) { + nums.add(new XWPFNum(ctNum, this)); + } + for(CTAbstractNum ctAbstractNum : ctNumbering.getAbstractNumArray()){ + abstractNums.add(new XWPFAbstractNum(ctAbstractNum, this)); + } + isNew = false; + } catch (XmlException e) { + throw new POIXMLException(); + } + } + + /** + * save and commit numbering + */ + @Override + protected void commit() throws IOException { + XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS); + xmlOptions.setSaveSyntheticDocumentElement(new QName(CTNumbering.type.getName().getNamespaceURI(), "numbering")); + Map map = new HashMap(); + map.put("http://schemas.openxmlformats.org/markup-compatibility/2006", "ve"); + map.put("urn:schemas-microsoft-com:office:office", "o"); + map.put("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r"); + map.put("http://schemas.openxmlformats.org/officeDocument/2006/math", "m"); + map.put("urn:schemas-microsoft-com:vml", "v"); + map.put("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", "wp"); + map.put("urn:schemas-microsoft-com:office:word", "w10"); + map.put("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w"); + map.put("http://schemas.microsoft.com/office/word/2006/wordml", "wne"); + xmlOptions.setSaveSuggestedPrefixes(map); + PackagePart part = getPackagePart(); + OutputStream out = part.getOutputStream(); + ctNumbering.save(out, xmlOptions); + out.close(); + } + + + + /** + * Checks whether number with numID exists + * @param numID + * @return boolean true if num exist, false if num not exist + */ + public boolean numExist(BigInteger numID){ + for (XWPFNum num : nums) { + if (num.getCTNum().getNumId().equals(numID)) + return true; + } + return false; + } + + /** + * add a new number to the numbering document + * @param num + */ + public BigInteger addNum(XWPFNum num){ + ctNumbering.addNewNum(); + int pos = (ctNumbering.getNumArray().length) - 1; + ctNumbering.setNumArray(pos, num.getCTNum()); + nums.add(num); + return num.getCTNum().getNumId(); + } + + /** + * Add a new num with an abstractNumID + * @return return NumId of the added num + */ + public BigInteger addNum(BigInteger abstractNumID){ + CTNum ctNum = this.ctNumbering.addNewNum(); + ctNum.addNewAbstractNumId(); + ctNum.getAbstractNumId().setVal(abstractNumID); + ctNum.setNumId(BigInteger.valueOf(nums.size()+1)); + XWPFNum num = new XWPFNum(ctNum, this); + nums.add(num); + return ctNum.getNumId(); + } + + + /** + * get Num by NumID + * @param numID + * @return abstractNum with NumId if no Num exists with that NumID + * null will be returned + */ + public XWPFNum getNum(BigInteger numID){ + for(XWPFNum num: nums){ + if(num.getCTNum().getNumId().equals(numID)) + return num; + } + return null; + } + /** + * get AbstractNum by abstractNumID + * @param abstractNumID + * @return abstractNum with abstractNumId if no abstractNum exists with that abstractNumID + * null will be returned + */ + public XWPFAbstractNum getAbstractNum(BigInteger abstractNumID){ + for(XWPFAbstractNum abstractNum: abstractNums){ + if(abstractNum.getAbstractNum().getAbstractNumId().equals(abstractNumID)){ + return abstractNum; + } + } + return null; + } + /** + * Compare AbstractNum with abstractNums of this numbering document. + * If the content of abstractNum equals with an abstractNum of the List in numbering + * the BigInteger Value of it will be returned. + * If no equal abstractNum is existing null will be returned + * + * @param abstractNum + * @return BigInteger + */ + public BigInteger getIdOfAbstractNum(XWPFAbstractNum abstractNum){ + CTAbstractNum copy = (CTAbstractNum) abstractNum.getCTAbstractNum().copy(); + XWPFAbstractNum newAbstractNum = new XWPFAbstractNum(copy, this); + int i; + for (i = 0; i < abstractNums.size(); i++) { + newAbstractNum.getCTAbstractNum().setAbstractNumId(BigInteger.valueOf(i)); + newAbstractNum.setNumbering(this); + if(newAbstractNum.getCTAbstractNum().valueEquals(abstractNums.get(i).getCTAbstractNum())){ + return newAbstractNum.getCTAbstractNum().getAbstractNumId(); + } + } + return null; + } + + + /** + * add a new AbstractNum and return its AbstractNumID + * @param abstractNum + */ + public BigInteger addAbstractNum(XWPFAbstractNum abstractNum){ + int pos = abstractNums.size(); + ctNumbering.addNewAbstractNum(); + abstractNum.getAbstractNum().setAbstractNumId(BigInteger.valueOf(pos)); + ctNumbering.setAbstractNumArray(pos, abstractNum.getAbstractNum()); + abstractNums.add(abstractNum); + return abstractNum.getCTAbstractNum().getAbstractNumId(); + } + + /** + * remove an existing abstractNum + * @param abstractNumID + * @return true if abstractNum with abstractNumID exists in NumberingArray, + * false if abstractNum with abstractNumID not exists + */ + public boolean removeAbstractNum(BigInteger abstractNumID){ + if(abstractNumID.byteValue() runs; + /** * TODO - replace with RichText String */ @@ -72,107 +81,137 @@ public class XWPFParagraph { } - protected XWPFParagraph(CTP prgrph, XWPFDocument docRef) { + public XWPFParagraph(CTP prgrph, IBody part) { this.paragraph = prgrph; - this.document = docRef; + this.part = part; + + // We only care about the document (for comments, + // hyperlinks etc) if we're attached to the + // core document + if(part instanceof XWPFDocument) { + this.document = (XWPFDocument)part; + } + + runs = new ArrayList(); + if (prgrph.getRList().size() > 0) { + for(CTR ctRun : prgrph.getRList()) { + runs.add(new XWPFRun(ctRun, this)); + } + } if (!isEmpty()) { - // All the runs to loop over - // TODO - replace this with some sort of XPath expression - // to directly find all the CTRs, in the right order - ArrayList rs = new ArrayList(); - rs.addAll(Arrays.asList(paragraph.getRArray())); - - for (CTSdtRun sdt : paragraph.getSdtArray()) { - CTSdtContentRun run = sdt.getSdtContent(); - rs.addAll(Arrays.asList(run.getRArray())); - } - for (CTRunTrackChange c : paragraph.getDelArray()) { - rs.addAll(Arrays.asList(c.getRArray())); - } - - for (CTRunTrackChange c : paragraph.getInsArray()) { - rs.addAll(Arrays.asList(c.getRArray())); - } - - // Get text of the paragraph - for (int j = 0; j < rs.size(); j++) { - // Grab the text and tabs of the paragraph - // Do so in a way that preserves the ordering - XmlCursor c = rs.get(j).newCursor(); - c.selectPath("./*"); - while (c.toNextSelection()) { - XmlObject o = c.getObject(); - if (o instanceof CTText) { - text.append(((CTText) o).getStringValue()); - } - if (o instanceof CTPTab) { - text.append("\t"); - } - if (o instanceof CTEmpty) { - // Some inline text elements get returned not as - // themselves, but as CTEmpty, owing to some odd - // definitions around line 5642 of the XSDs - String tagName = o.getDomNode().getNodeName(); - if ("w:tab".equals(tagName)) { - text.append("\t"); - } - if ("w:cr".equals(tagName)) { - text.append("\n"); - } - } - //got a reference to a footnote - if (o instanceof CTFtnEdnRef) { - CTFtnEdnRef ftn = (CTFtnEdnRef) o; - footnoteText.append("[").append(ftn.getId()).append(": "); - XWPFFootnote footnote = - ftn.getDomNode().getLocalName().equals("footnoteReference") ? - document.getFootnoteByID(ftn.getId().intValue()) : - document.getEndnoteByID(ftn.getId().intValue()); - - boolean first = true; - for (XWPFParagraph p : footnote.getParagraphs()) { - if (!first) { - footnoteText.append("\n"); - first = false; - } - footnoteText.append(p.getText()); - } - - footnoteText.append("]"); - } - } - - // Loop over pictures inside our - // paragraph, looking for text in them - CTPicture[] picts = rs.get(j).getPictArray(); - for (int k = 0; k < picts.length; k++) { - XmlObject[] t = picts[k] - .selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:t"); - for (int m = 0; m < t.length; m++) { - NodeList kids = t[m].getDomNode().getChildNodes(); - for (int n = 0; n < kids.getLength(); n++) { - if (kids.item(n) instanceof Text) { - pictureText.append("\n"); - pictureText.append(kids.item(n).getNodeValue()); - } - } - } - } - } + readNewText(); } } + + protected String readNewText() { + StringBuffer text = new StringBuffer(); + + // All the runs to loop over + // TODO - replace this with some sort of XPath expression + // to directly find all the CTRs, in the right order + ArrayList rs = new ArrayList(); + rs.addAll( paragraph.getRList() ); + + for (CTSdtRun sdt : paragraph.getSdtList()) { + CTSdtContentRun run = sdt.getSdtContent(); + rs.addAll( run.getRList() ); + } + for (CTRunTrackChange c : paragraph.getDelList()) { + rs.addAll( c.getRList() ); + } + for (CTRunTrackChange c : paragraph.getInsList()) { + rs.addAll( c.getRList() ); + } + + // Get text of the paragraph + for (int j = 0; j < rs.size(); j++) { + // Grab the text and tabs of the paragraph + // Do so in a way that preserves the ordering + XmlCursor c = rs.get(j).newCursor(); + c.selectPath("./*"); + while (c.toNextSelection()) { + XmlObject o = c.getObject(); + if (o instanceof CTText) { + text.append(((CTText) o).getStringValue()); + } + if (o instanceof CTPTab) { + text.append("\t"); + } + if (o instanceof CTEmpty) { + // Some inline text elements get returned not as + // themselves, but as CTEmpty, owing to some odd + // definitions around line 5642 of the XSDs + String tagName = o.getDomNode().getNodeName(); + if ("w:tab".equals(tagName)) { + text.append("\t"); + } + if ("w:cr".equals(tagName)) { + text.append("\n"); + } + } + + // Check for bits that only apply when + // attached to a core document + if(document != null) { + //got a reference to a footnote + if (o instanceof CTFtnEdnRef) { + CTFtnEdnRef ftn = (CTFtnEdnRef) o; + footnoteText.append("[").append(ftn.getId()).append(": "); + XWPFFootnote footnote = + ftn.getDomNode().getLocalName().equals("footnoteReference") ? + document.getFootnoteByID(ftn.getId().intValue()) : + document.getEndnoteByID(ftn.getId().intValue()); + + boolean first = true; + for (XWPFParagraph p : footnote.getParagraphs()) { + if (!first) { + footnoteText.append("\n"); + first = false; + } + footnoteText.append(p.getText()); + } + + footnoteText.append("]"); + } + } + } + + // Loop over pictures inside our + // paragraph, looking for text in them + for(CTPicture pict : rs.get(j).getPictList()) { + XmlObject[] t = pict + .selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:t"); + for (int m = 0; m < t.length; m++) { + NodeList kids = t[m].getDomNode().getChildNodes(); + for (int n = 0; n < kids.getLength(); n++) { + if (kids.item(n) instanceof Text) { + pictureText.append("\n"); + pictureText.append(kids.item(n).getNodeValue()); + } + } + } + } + } + + this.text = text; + return text.toString(); + } @Internal public CTP getCTP() { return paragraph; } - public boolean isEmpty() { + public List getRuns(){ + return Collections.unmodifiableList(runs); + } + + public boolean isEmpty(){ return !paragraph.getDomNode().hasChildNodes(); } - public XWPFDocument getDocument() { + public XWPFDocument getDocument(){ return document; } @@ -185,6 +224,51 @@ public class XWPFParagraph { out.append(text).append(footnoteText).append(pictureText); return out.toString(); } + + /** + * Return styleID of the paragraph if style exist for this paragraph + * if not, null will be returned + * @return styleID as String + */ + public String getStyleID(){ + if (paragraph.getPPr() != null){ + if(paragraph.getPPr().getPStyle()!= null){ + if (paragraph.getPPr().getPStyle().getVal()!= null) + return paragraph.getPPr().getPStyle().getVal(); + } + } + return null; + } + /** + * If style exist for this paragraph + * NumId of the paragraph will be returned. + * If style not exist null will be returned + * @return NumID as BigInteger + */ + public BigInteger getNumID(){ + if(paragraph.getPPr()!=null){ + if(paragraph.getPPr().getNumPr()!=null){ + if(paragraph.getPPr().getNumPr().getNumId()!=null) + return paragraph.getPPr().getNumPr().getNumId().getVal(); + } + } + return null; + } + + /** + * setNumID of Paragraph + * @param numPos + */ + public void setNumID(BigInteger numPos) { + if(paragraph.getPPr()==null) + paragraph.addNewPPr(); + if(paragraph.getPPr().getNumPr()==null) + paragraph.getPPr().addNewNumPr(); + if(paragraph.getPPr().getNumPr().getNumId()==null){ + paragraph.getPPr().getNumPr().addNewNumId(); + } + paragraph.getPPr().getNumPr().getNumId().setVal(numPos); + } /** * Returns the text of the paragraph, but not of any objects in the @@ -1040,5 +1124,210 @@ public class XWPFParagraph { : paragraph.getPPr(); return pr; } + + + /** + * add a new run at the end of the position of + * the content of parameter run + * @param run + */ + protected void addRun(CTR run){ + int pos; + pos = paragraph.getRArray().length; + paragraph.addNewR(); + paragraph.setRArray(pos, run); + for (CTText ctText: paragraph.getRArray(pos).getTArray()) { + this.text.append(ctText.getStringValue()); + } + } + + /** + * this methods parse the paragraph and search for the string searched. + * If it finds the string, it will return true and the position of the String + * will be saved in the parameter startPos. + * @param searched + * @param pos + * @return + */ + public TextSegement searchText(String searched,PositionInParagraph startPos){ + + int startRun = startPos.getRun(), + startText = startPos.getText(), + startChar = startPos.getChar(); + int beginRunPos = 0, candCharPos = 0; + boolean newList = false; + for (int runPos=startRun; runPos=startText){ + String candidate = ((CTText)o).getStringValue(); + if(runPos==startRun) + charPos= startChar; + else + charPos = 0; + for(; charPos= 0 && pos <= paragraph.sizeOfRArray()) { + CTR ctRun = paragraph.insertNewR(pos); + XWPFRun newRun = new XWPFRun(ctRun, this); + runs.add(newRun); + return newRun; + } + return null; + } + + + + /** + * get a Text + * @param posList + * @return + */ + public String getText(TextSegement segment){ + int runBegin = segment.getBeginRun(); + int textBegin = segment.getBeginText(); + int charBegin = segment.getBeginChar(); + int runEnd = segment.getEndRun(); + int textEnd = segment.getEndText(); + int charEnd = segment.getEndChar(); + StringBuffer out = new StringBuffer(); + for(int i=runBegin; i<=runEnd;i++){ + int startText=0, endText = paragraph.getRArray(i).getTArray().length-1; + if(i==runBegin) + startText=textBegin; + if(i==runEnd) + endText = textEnd; + for(int j=startText;j<=endText;j++){ + String tmpText = paragraph.getRArray(i).getTArray(j).getStringValue(); + int startChar=0, endChar = tmpText.length()-1; + if((j==textBegin)&&(i==runBegin)) + startChar=charBegin; + if((j==textEnd)&&(i==runEnd)){ + endChar = charEnd; + } + out.append(tmpText.substring(startChar, endChar+1)); + + } + } + return out.toString(); + } + + /** + * removes a Run at the position pos in the paragraph + * @param pos + * @return + */ + public boolean removeRun(int pos){ + if (pos >= 0 && pos < paragraph.sizeOfRArray()){ + getCTP().removeR(pos); + runs.remove(pos); + return true; + } + return false; + } + + /** + * returns the type of the BodyElement Paragraph + * @see org.apache.poi.xwpf.usermodel.IBodyElement#getElementType() + */ + @Override + public BodyElementType getElementType() { + return BodyElementType.PARAGRAPH; + } + + /** + * returns the part of the bodyElement + * @see org.apache.poi.xwpf.usermodel.IBody#getPart() + */ + @Override + public IBody getPart() { + if(part != null){ + return part.getPart(); + } + return null; + } + + /** + * returns the partType of the bodyPart which owns the bodyElement + * @see org.apache.poi.xwpf.usermodel.IBody#getPartType() + */ + @Override + public BodyType getPartType() { + return part.getPartType(); + } + + /** + * adds a new Run to the Paragraph + * @param r + * @return + */ + public void addRun(XWPFRun r){ + runs.add(r); + } + + /** + * return the XWPFRun-Element which owns the CTR run-Element + * @param r + * @return + */ + public XWPFRun getRun(CTR r){ + for(int i=0; i < getRuns().size(); i++){ + if(getRuns().get(i).getCTR() == r) return getRuns().get(i); + } + return null; + } + + + +}//end class + + -} diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPicture.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPicture.java new file mode 100644 index 0000000000..4b1cea3fc3 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPicture.java @@ -0,0 +1,74 @@ +/* ==================================================================== + 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 org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.openxml4j.opc.PackageRelationship; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; +import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture; + + +/** + * @author Philipp Epp + * + */ +public class XWPFPicture { + private static final POILogger logger = POILogFactory.getLogger(XWPFPicture.class); + protected XWPFParagraph paragraph; + private CTPicture ctPic; + + + public XWPFParagraph getParagraph(){ + return paragraph; + } + + public XWPFPicture(CTPicture ctPic, XWPFParagraph paragraph){ + this.paragraph = paragraph; + this.ctPic = ctPic; + } + /** + * Link Picture with PictureData + * @param rel + */ + public void setPictureReference(PackageRelationship rel){ + ctPic.getBlipFill().getBlip().setEmbed(rel.getId()); + } + + /** + * Return the underlying CTPicture bean that holds all properties for this picture + * + * @return the underlying CTPicture bean + */ + public CTPicture getCTPicture(){ + return ctPic; + } + /** + * Get the PictureData of the Picture + * @return + */ + public XWPFPictureData getPictureData(){ + String blipId = ctPic.getBlipFill().getBlip().getEmbed(); + for(POIXMLDocumentPart part: paragraph.getDocument().getRelations()){ + if(part.getPackageRelationship().getId().equals(blipId)){ + return (XWPFPictureData)part; + } + } + return null; + } + +}//end class diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPictureData.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPictureData.java new file mode 100644 index 0000000000..5094763f73 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPictureData.java @@ -0,0 +1,128 @@ +/* ==================================================================== + 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.IOException; + +import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.POIXMLRelation; +import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.openxml4j.opc.PackageRelationship; +import org.apache.poi.util.IOUtils; + +/** + * Raw picture data, normally attached to a WordprocessingML Drawing. + * As a rule, pictures are stored in the /word/media/ part of a WordprocessingML package. + */ + +/** + * @author Philipp Epp + * + */ +public class XWPFPictureData extends POIXMLDocumentPart { + + /** + * Relationships for each known picture type + */ + protected static final POIXMLRelation[] RELATIONS; + static { + RELATIONS = new POIXMLRelation[8]; + RELATIONS[Document.PICTURE_TYPE_EMF] = XWPFRelation.IMAGE_EMF; + RELATIONS[Document.PICTURE_TYPE_WMF] = XWPFRelation.IMAGE_WMF; + RELATIONS[Document.PICTURE_TYPE_PICT] = XWPFRelation.IMAGE_PICT; + RELATIONS[Document.PICTURE_TYPE_JPEG] = XWPFRelation.IMAGE_JPEG; + RELATIONS[Document.PICTURE_TYPE_PNG] = XWPFRelation.IMAGE_PNG; + RELATIONS[Document.PICTURE_TYPE_DIB] = XWPFRelation.IMAGE_DIB; + } + /** + * Create a new XWPFGraphicData node + * + */ + protected XWPFPictureData() { + super(); + } + + /** + * Construct XWPFPictureData from a package part + * + * @param part the package part holding the drawing data, + * @param rel the package relationship holding this drawing, + * the relationship type must be http://schemas.openxmlformats.org/officeDocument/2006/relationships/image + */ + + public XWPFPictureData(PackagePart part, PackageRelationship rel) { + super(part, rel); + } + + /** + * Gets the picture data as a byte array. + *

+ * Note, that this call might be expensive since all the picture data is copied into a temporary byte array. + * You can grab the picture data directly from the underlying package part as follows: + *
+ * + * InputStream is = getPackagePart().getInputStream(); + * + *

+ * + * @return the Picture data. + */ + public byte[] getData() { + try { + return IOUtils.toByteArray(getPackagePart().getInputStream()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + /** + * Suggests a file extension for this image. + * + * @return the file extension. + */ + public String suggestFileExtension() { + return getPackagePart().getPartName().getExtension(); + } + + /** + * Return an integer constant that specifies type of this picture + * + * @return an integer constant that specifies type of this picture + * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_EMF + * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_WMF + * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_PICT + * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_JPEG + * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_PNG + * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_DIB + */ + public int getPictureType(){ + String contentType = getPackagePart().getContentType(); + for (int i = 0; i < RELATIONS.length; i++) { + if(RELATIONS[i] == null) continue; + + if(RELATIONS[i].getContentType().equals(contentType)){ + return i; + } + } + return 0; + } + + +} 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 c5accb89f9..83d2282099 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRelation.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRelation.java @@ -17,11 +17,11 @@ package org.apache.poi.xwpf.usermodel; -import org.apache.poi.POIXMLRelation; -import org.apache.poi.POIXMLDocumentPart; - -import java.util.Map; import java.util.HashMap; +import java.util.Map; + +import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.POIXMLRelation; /** * @author Yegor Kozlov @@ -58,6 +58,13 @@ public final class XWPFRelation extends POIXMLRelation { "/word/document.xml", null ); + + public static final XWPFRelation NUMBERING = new XWPFRelation( + "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering", + "/word/numbering.xml", + XWPFNumbering.class + ); public static final XWPFRelation FONT_TABLE = new XWPFRelation( "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable", @@ -74,7 +81,7 @@ public final class XWPFRelation extends POIXMLRelation { "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", "/word/styles.xml", - null + XWPFStyles.class ); public static final XWPFRelation WEB_SETTINGS = new XWPFRelation( "application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml", @@ -118,6 +125,50 @@ public final class XWPFRelation extends POIXMLRelation { null, null ); + + public static final XWPFRelation IMAGE_EMF = new XWPFRelation( + "image/x-emf", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + "/word/media/image#.emf", + XWPFPictureData.class + ); + public static final XWPFRelation IMAGE_WMF = new XWPFRelation( + "image/x-wmf", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + "/word/media/image#.wmf", + XWPFPictureData.class + ); + public static final XWPFRelation IMAGE_PICT = new XWPFRelation( + "image/pict", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + "/word/media/image#.pict", + XWPFPictureData.class + ); + public static final XWPFRelation IMAGE_JPEG = new XWPFRelation( + "image/jpeg", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + "/word/media/image#.jpeg", + XWPFPictureData.class + ); + public static final XWPFRelation IMAGE_PNG = new XWPFRelation( + "image/png", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + "/word/media/image#.png", + XWPFPictureData.class + ); + public static final XWPFRelation IMAGE_DIB = new XWPFRelation( + "image/dib", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + "/word/media/image#.dib", + XWPFPictureData.class + ); + + public static final XWPFRelation IMAGES = new XWPFRelation( + null, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + null, + null + ); private XWPFRelation(String type, String rel, String defaultName, Class cls) { diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java index 93dd9c8f16..c041030e8d 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java @@ -18,6 +18,7 @@ package org.apache.poi.xwpf.usermodel; import java.math.BigInteger; +import org.apache.poi.util.Internal; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHpsMeasure; @@ -33,7 +34,6 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBrType; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STUnderline; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalAlignRun; -import org.apache.poi.util.Internal; /** * XWPFRun object defines a region of text with a common set of properties @@ -48,7 +48,7 @@ public class XWPFRun { * @param r the CTR bean which holds the run attributes * @param p the parent paragraph */ - protected XWPFRun(CTR r, XWPFParagraph p) { + public XWPFRun(CTR r, XWPFParagraph p) { this.run = r; this.paragraph = p; } @@ -471,5 +471,6 @@ public class XWPFRun { public void removeCarriageReturn() { //TODO } + } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyle.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyle.java new file mode 100644 index 0000000000..9de4eecdad --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyle.java @@ -0,0 +1,143 @@ +/* ==================================================================== + 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 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.STStyleType; + +/** + * @author Philipp Epp + * + */ +public class XWPFStyle { + + private CTStyle ctStyle; + protected XWPFStyles styles; + + /** + * constructor + * @param style + */ + public XWPFStyle(CTStyle style){ + this(style,null); + } + /** + * constructor + * @param style + * @param styles + */ + public XWPFStyle(CTStyle style, XWPFStyles styles){ + this.ctStyle = style; + this.styles = styles; + } + + /** + * get StyleID of the style + * @return styleID StyleID of the style + */ + public String getStyleId(){ + return ctStyle.getStyleId(); + } + + /** + * get Type of the Style + * @return ctType + */ + public STStyleType.Enum getType(){ + return ctStyle.getType(); + } + + /** + * set style + * @param style + */ + public void setStyle(CTStyle style){ + this.ctStyle = style; + } + /** + * get ctStyle + * @return ctStyle + */ + public CTStyle getCTStyle(){ + return this.ctStyle; + } + /** + * set styleID + * @param styleId + */ + public void setStyleId(String styleId){ + ctStyle.setStyleId(styleId); + } + + /** + * set styleType + * @param type + */ + public void setType(STStyleType.Enum type){ + ctStyle.setType(type); + } + /** + * get styles + * @return styles the styles to which this style belongs + */ + public XWPFStyles getStyles(){ + return styles; + } + + public String getBasisStyleID(){ + if(ctStyle.getBasedOn()!=null) + return ctStyle.getBasedOn().getVal(); + else + return null; + } + + + /** + * get StyleID of the linked Style + * @return + */ + public String getLinkStyleID(){ + if (ctStyle.getLink()!=null) + return ctStyle.getLink().getVal(); + else + return null; + } + + /** + * get StyleID of the next style + * @return + */ + public String getNextStyleID(){ + if(ctStyle.getNext()!=null) + return ctStyle.getNext().getVal(); + else + return null; + } + + /** + * compares the names of the Styles + * @param compStyle + * @return + */ + public boolean hasSameName(XWPFStyle compStyle){ + CTStyle ctCompStyle = compStyle.getCTStyle(); + String name = ctCompStyle.getName().getVal(); + return name.equals(ctStyle.getName().getVal()); + } + +}//end class diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java new file mode 100644 index 0000000000..f2328824c9 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java @@ -0,0 +1,201 @@ +/* ==================================================================== + 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.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.namespace.QName; + +import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.POIXMLException; +import org.apache.poi.openxml4j.exceptions.OpenXML4JException; +import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.openxml4j.opc.PackageRelationship; +import org.apache.xmlbeans.XmlException; +import org.apache.xmlbeans.XmlOptions; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.StylesDocument; + +/** + * @author Philipp Epp + * + */ +public class XWPFStyles extends POIXMLDocumentPart{ + private CTStyles ctStyles; + protected XWPFLatentStyles latentStyles; + protected List listStyle; + + /** + * Construct XWPFStyles from a package part + * + * @param part the package part holding the data of the styles, + * @param rel the package relationship of type "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" + */ + + public XWPFStyles(PackagePart part, PackageRelationship rel) throws IOException, OpenXML4JException{ + super(part, rel); + onDocumentRead(); + } + /** + * Read document + */ + @Override + protected void onDocumentRead ()throws IOException{ + listStyle = new ArrayList(); + StylesDocument stylesDoc; + try { + InputStream is = getPackagePart().getInputStream(); + stylesDoc = StylesDocument.Factory.parse(is); + ctStyles = stylesDoc.getStyles(); + latentStyles = new XWPFLatentStyles(ctStyles.getLatentStyles(), this); + + } catch (XmlException e) { + throw new POIXMLException(); + } + //get any Style + for(CTStyle style : ctStyles.getStyleArray()) { + listStyle.add(new XWPFStyle(style, this)); + } + } + + @Override + protected void commit() throws IOException { + XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS); + xmlOptions.setSaveSyntheticDocumentElement(new QName(CTStyles.type.getName().getNamespaceURI(), "styles")); + Map map = new HashMap(); + map.put("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r"); + map.put("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w"); + xmlOptions.setSaveSuggestedPrefixes(map); + PackagePart part = getPackagePart(); + OutputStream out = part.getOutputStream(); + ctStyles.save(out, xmlOptions); + out.close(); + } + + + + + /** + * checks whether style with styleID exist + * @param styleID styleID of the Style in the style-Document + * @return true if style exist, false if style not exist + */ + public boolean styleExist(String styleID){ + for (XWPFStyle style : listStyle) { + if (style.getStyleId().equals(styleID)) + return true; + } + return false; + } + /** + * add a style to the document + * @param style + * @throws IOException + */ + public void addStyle(XWPFStyle style){ + listStyle.add(style); + ctStyles.addNewStyle(); + int pos = (ctStyles.getStyleArray().length) - 1; + ctStyles.setStyleArray(pos, style.getCTStyle()); + } + /** + *get style by a styleID + * @param styleID styleID of the searched style + * @return style + */ + public XWPFStyle getStyle(String styleID){ + for (XWPFStyle style : listStyle) { + if(style.getStyleId().equals(styleID)) + return style; + } + return null; + } + + /** + * get the styles which are related to the parameter style and their relatives + * this method can be used to copy all styles from one document to another document + * @param style + * @return a list of all styles which were used by this method + */ + public List getUsedStyleList(XWPFStyle style){ + List usedStyleList = new ArrayList(); + usedStyleList.add(style); + return getUsedStyleList(style, usedStyleList); + } + + /** + * get the styles which are related to parameter style + * @param style + * @return all Styles of the parameterList + */ + private List getUsedStyleList(XWPFStyle style, List usedStyleList){ + String basisStyleID = style.getBasisStyleID(); + XWPFStyle basisStyle = getStyle(basisStyleID); + if((basisStyle!=null)&&(!usedStyleList.contains(basisStyle))){ + usedStyleList.add(basisStyle); + getUsedStyleList(basisStyle, usedStyleList); + } + String linkStyleID = style.getLinkStyleID(); + XWPFStyle linkStyle = getStyle(linkStyleID); + if((linkStyle!=null)&&(!usedStyleList.contains(linkStyle))){ + usedStyleList.add(linkStyle); + getUsedStyleList(linkStyle, usedStyleList); + } + + String nextStyleID = style.getNextStyleID(); + XWPFStyle nextStyle = getStyle(nextStyleID); + if((nextStyle!=null)&&(!usedStyleList.contains(nextStyle))){ + usedStyleList.add(linkStyle); + getUsedStyleList(linkStyle, usedStyleList); + } + return usedStyleList; + } + + + + /** + * get latentstyles + * @return + */ + public XWPFLatentStyles getLatentStyles() { + return latentStyles; + } + + /** + * get the style with the same name + * if this style is not existing, return null + * @param style + * @return + */ + public XWPFStyle getStyleWithSameName(XWPFStyle style){ + for (XWPFStyle ownStyle : listStyle) { + if(ownStyle.hasSameName(style)){ + return ownStyle; + } + } + return null; + + } +}//end class diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java index 61a1f11fd0..b12cce2c12 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java @@ -17,7 +17,10 @@ package org.apache.poi.xwpf.usermodel; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import org.apache.poi.util.Internal; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; @@ -27,7 +30,6 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth; -import org.apache.poi.util.Internal; /** * Sketch of XWPFTable class. Only table's text is being hold. @@ -37,16 +39,20 @@ import org.apache.poi.util.Internal; * * @author Yury Batrakov (batrakov at gmail.com) */ -public class XWPFTable { +public class XWPFTable implements IBodyElement{ protected StringBuffer text = new StringBuffer(); private CTTbl ctTbl; + protected List tableRows; + protected List styleIDs; + protected IBody part; + private XWPFDocument document; - - public XWPFTable(XWPFDocument doc, CTTbl table, int row, int col) { - this(doc, table); + public XWPFTable(CTTbl table, IBody part, int row, int col) { + this(table, part); for (int i = 0; i < row; i++) { XWPFTableRow tabRow = (getRow(i) == null) ? createRow() : getRow(i); + tableRows.add(tabRow); for (int k = 0; k < col; k++) { XWPFTableCell tabCell = (tabRow.getCell(k) == null) ? tabRow .createCell() : null; @@ -55,8 +61,11 @@ public class XWPFTable { } - public XWPFTable(XWPFDocument doc, CTTbl table) { + public XWPFTable(CTTbl table, IBody part){ + this.part = part; this.ctTbl = table; + + tableRows = new ArrayList(); // is an empty table: I add one row and one column as default if (table.sizeOfTrArray() == 0) @@ -64,9 +73,11 @@ public class XWPFTable { for (CTRow row : table.getTrArray()) { StringBuffer rowText = new StringBuffer(); + XWPFTableRow tabRow = new XWPFTableRow(row, this); + tableRows.add(tabRow); for (CTTc cell : row.getTcArray()) { for (CTP ctp : cell.getPArray()) { - XWPFParagraph p = new XWPFParagraph(ctp, doc); + XWPFParagraph p = new XWPFParagraph(ctp, part); if (rowText.length() > 0) { rowText.append('\t'); } @@ -104,7 +115,7 @@ public class XWPFTable { * CTTblGrid tblgrid=table.addNewTblGrid(); * tblgrid.addNewGridCol().setW(new BigInteger("2000")); */ - + getRows(); } /** @@ -134,7 +145,7 @@ public class XWPFTable { public void addNewCol() { if (ctTbl.sizeOfTrArray() == 0) createRow(); for (int i = 0; i < ctTbl.sizeOfTrArray(); i++) { - XWPFTableRow tabRow = new XWPFTableRow(ctTbl.getTrArray(i)); + XWPFTableRow tabRow = new XWPFTableRow(ctTbl.getTrArray(i), this); tabRow.createCell(); } } @@ -147,7 +158,7 @@ public class XWPFTable { public XWPFTableRow createRow() { int sizeCol = ctTbl.sizeOfTrArray() > 0 ? ctTbl.getTrArray(0) .sizeOfTcArray() : 0; - XWPFTableRow tabRow = new XWPFTableRow(ctTbl.addNewTr()); + XWPFTableRow tabRow = new XWPFTableRow(ctTbl.addNewTr(), this); addColumn(tabRow, sizeCol); return tabRow; } @@ -158,7 +169,8 @@ public class XWPFTable { */ public XWPFTableRow getRow(int pos) { if (pos >= 0 && pos < ctTbl.sizeOfTrArray()) { - return new XWPFTableRow(ctTbl.getTrArray(pos)); + //return new XWPFTableRow(ctTbl.getTrArray(pos)); + return getRows().get(pos); } return null; } @@ -201,5 +213,122 @@ public class XWPFTable { } } } + + /** + * get the StyleID of the table + * @return style-ID of the table + */ + public String getStyleID(){ + return ctTbl.getTblPr().getTblStyle().getVal(); + } + + /** + * add a new Row to the table + * + * @param row the row which should be added + */ + public void addRow(XWPFTableRow row){ + ctTbl.addNewTr(); + ctTbl.setTrArray(getNumberOfRows()-1, row.getCtRow()); + tableRows.add(row); + } + + /** + * add a new Row to the table + * at position pos + * @param row the row which should be added + */ + public boolean addRow(XWPFTableRow row, int pos){ + if(pos >= 0 && pos <= tableRows.size()){ + ctTbl.insertNewTr(pos); + ctTbl.setTrArray(pos,row.getCtRow()); + tableRows.add(pos, row); + return true; + } + return false; + } + + /** + * inserts a new tablerow + * @param pos + * @return + */ + public XWPFTableRow insertNewTableRow(int pos){ + if(pos >= 0 && pos <= tableRows.size()){ + CTRow row = ctTbl.insertNewTr(pos); + XWPFTableRow tableRow = new XWPFTableRow(row, this); + tableRows.add(pos, tableRow); + return tableRow; + } + return null; + } + + + /** + * Remove a row at position pos from the table + * @param pos position the Row in the Table + */ + public boolean removeRow(int pos) throws IndexOutOfBoundsException { + if(pos > 0 && pos < tableRows.size()){ + ctTbl.removeTr(pos); + tableRows.remove(pos); + return true; + } + return false; + } + + /** + * + * @param pos + * @return + */ + public List getRows() { + return tableRows; + } + + /** + * returns the type of the BodyElement Table + * @see org.apache.poi.xwpf.usermodel.IBodyElement#getElementType() + */ + @Override + public BodyElementType getElementType() { + return BodyElementType.TABLE; + } + + + /** + * returns the part of the bodyElement + * @see org.apache.poi.xwpf.usermodel.IBody#getPart() + */ + @Override + public IBody getPart() { + if(part != null){ + return part.getPart(); + } + return null; + } + + + /** + * returns the partType of the bodyPart which owns the bodyElement + * @see org.apache.poi.xwpf.usermodel.IBody#getPartType() + */ + @Override + public BodyType getPartType() { + return ((IBody)part).getPartType(); + } + + /** + * returns the XWPFRow which belongs to the CTRow row + * if this row is not existing in the table null will be returned + * @param row + * @return + */ + public XWPFTableRow getRow(CTRow row) { + for(int i=0; i paragraphs = null; + protected List tables = null; + protected List bodyElements = null; + protected IBody part; + private XWPFTableRow tableRow = null; /** * If a table cell does not include at least one block-level element, then this document shall be considered corrupt */ - public XWPFTableCell(CTTc cell) { + public XWPFTableCell(CTTc cell, XWPFTableRow tableRow, IBody part) { this.ctTc = cell; + this.part = part; + this.tableRow = tableRow; // NB: If a table cell does not include at least one block-level element, then this document shall be considered corrupt. - cell.addNewP(); + if(cell.getPArray().length<1) + cell.addNewP(); + bodyElements = new ArrayList(); + paragraphs = new ArrayList(); + tables = new ArrayList(); + + XmlCursor cursor = ctTc.newCursor(); + cursor.selectPath("./*"); + while (cursor.toNextSelection()) { + XmlObject o = cursor.getObject(); + if (o instanceof CTP) { + XWPFParagraph p = new XWPFParagraph((CTP)o, this); + paragraphs.add(p); + bodyElements.add(p); + } + if (o instanceof CTTbl) { + XWPFTable t = new XWPFTable((CTTbl)o, this); + tables.add(t); + bodyElements.add(t); + } + } } @@ -47,21 +81,275 @@ public class XWPFTableCell { ctTc.setPArray(0, p.getCTP()); } - public XWPFParagraph getParagraph() { - return ctTc.sizeOfPArray() == 0 ? null : new XWPFParagraph(ctTc.getPArray(0)); + /** + * returns a list of paragraphs + * @return + */ + public List getParagraphs(){ + return paragraphs; } - - + + /** + * add a Paragraph to this TableCell + * @param p the paragaph which has to be added + */ + public void addParagraph(XWPFParagraph p){ + paragraphs.add(p); + } + + /** + * removes a paragraph of this tablecell + * @param pos + */ + public void removeParagraph(int pos){ + paragraphs.remove(pos); + ctTc.removeP(pos); + } + + /** + * if there is a corresponding {@link XWPFParagraph} of the parameter ctTable in the paragraphList of this table + * the method will return this paragraph + * if there is no corresponding {@link XWPFParagraph} the method will return null + * @param p is instance of CTP and is searching for an XWPFParagraph + * @return null if there is no XWPFParagraph with an corresponding CTPparagraph in the paragraphList of this table + * XWPFParagraph with the correspondig CTP p + */ + @Override + public XWPFParagraph getParagraph(CTP p){ + for (XWPFParagraph paragraph : paragraphs) { + if(p.equals(paragraph.getCTP())){ + return paragraph; + } + } + return null; + } + public void setText(String text) { CTP ctP = (ctTc.sizeOfPArray() == 0) ? ctTc.addNewP() : ctTc.getPArray(0); - XWPFParagraph par = new XWPFParagraph(ctP); + XWPFParagraph par = new XWPFParagraph(ctP, this); par.createRun().setText(text); } - - public String getText() { - //TODO - return null; + + public XWPFTableRow getTableRow(){ + return tableRow; + } + + /** + * add a new paragraph at position of the cursor + * @param cursor + * @return + */ + public XWPFParagraph insertNewParagraph(XmlCursor cursor){ + if(!isCursorInTableCell(cursor)) + return null; + + String uri = CTP.type.getName().getNamespaceURI(); + String localPart = "p"; + cursor.beginElement(localPart,uri); + cursor.toParent(); + CTP p = (CTP)cursor.getObject(); + XWPFParagraph newP = new XWPFParagraph(p, this); + XmlObject o = null; + while(!(o instanceof CTP)&&(cursor.toPrevSibling())){ + o = cursor.getObject(); + } + if((!(o instanceof CTP)) || (CTP)o == p){ + paragraphs.add(0, newP); + } + else{ + int pos = paragraphs.indexOf(getParagraph((CTP)o))+1; + paragraphs.add(pos,newP); + } + int i=0; + cursor.toCursor(p.newCursor()); + while(cursor.toPrevSibling()){ + o =cursor.getObject(); + if(o instanceof CTP || o instanceof CTTbl) + i++; + } + bodyElements.add(i, newP); + cursor.toCursor(p.newCursor()); + cursor.toEndToken(); + return newP; } + /** + * + * @param cursor + * @return + */ + public XWPFTable insertNewTbl(XmlCursor cursor) { + if(isCursorInTableCell(cursor)){ + String uri = CTTbl.type.getName().getNamespaceURI(); + String localPart = "tbl"; + cursor.beginElement(localPart,uri); + cursor.toParent(); + CTTbl t = (CTTbl)cursor.getObject(); + XWPFTable newT = new XWPFTable(t, this); + cursor.removeXmlContents(); + XmlObject o = null; + while(!(o instanceof CTTbl)&&(cursor.toPrevSibling())){ + o = cursor.getObject(); + } + if(!(o instanceof CTTbl)){ + tables.add(0, newT); + } + else{ + int pos = tables.indexOf(getTable((CTTbl)o))+1; + tables.add(pos,newT); + } + int i=0; + cursor = t.newCursor(); + while(cursor.toPrevSibling()){ + o =cursor.getObject(); + if(o instanceof CTP || o instanceof CTTbl) + i++; + } + bodyElements.add(i, newT); + cursor = t.newCursor(); + cursor.toEndToken(); + return newT; + } + return null; + } + + /** + * verifies that cursor is on the right position + * @param cursor + * @return + */ + private boolean isCursorInTableCell(XmlCursor cursor) { + XmlCursor verify = cursor.newCursor(); + verify.toParent(); + if(verify.getObject() == this.ctTc){ + return true; + } + return false; + } + + + + /** + * @see org.apache.poi.xwpf.usermodel.IBody#getParagraphArray(int) + */ + @Override + public XWPFParagraph getParagraphArray(int pos) { + if(pos > 0 && pos < paragraphs.size()){ + return paragraphs.get(pos); + } + return null; + } + + + + + /** + * get the to which the TableCell belongs + * @see org.apache.poi.xwpf.usermodel.IBody#getPart() + */ + @Override + public IBody getPart() { + return (IBody) tableRow.getTable().getPart(); + } + + + /** + * @see org.apache.poi.xwpf.usermodel.IBody#getPartType() + */ + @Override + public BodyType getPartType() { + return BodyType.TABLECELL; + } + + + /** + * get a table by its CTTbl-Object + * @see org.apache.poi.xwpf.usermodel.IBody#getTable(org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl) + */ + @Override + public XWPFTable getTable(CTTbl ctTable) { + for(int i=0; i 0 && pos < tables.size()){ + return tables.get(pos); + } + return null; + } + + + /** + * @see org.apache.poi.xwpf.usermodel.IBodyPart#getTables() + */ + @Override + public List getTables() { + return Collections.unmodifiableList(tables); + } + + + /** + * inserts an existing XWPFTable to the arrays bodyElements and tables + * @see org.apache.poi.xwpf.usermodel.IBody#insertTable(int, org.apache.poi.xwpf.usermodel.XWPFTable) + */ + @Override + public void insertTable(int pos, XWPFTable table) { + bodyElements.add(pos, table); + int i; + for (i = 0; i < ctTc.getTblArray().length; i++) { + CTTbl tbl = ctTc.getTblArray(i); + if(tbl == table.getCTTbl()){ + break; + } + } + tables.add(i, table); + } + + public String getText(){ + StringBuffer text = new StringBuffer(); + for (XWPFParagraph p : paragraphs) { + text.append(p.readNewText()); + } + return text.toString(); + } + + /** + * get the TableCell which belongs to the TableCell + * @param o + * @return + */ + @Override + public XWPFTableCell getTableCell(CTTc cell) { + XmlCursor cursor = cell.newCursor(); + cursor.toParent(); + XmlObject o = cursor.getObject(); + if(!(o instanceof CTRow)){ + return null; + } + CTRow row = (CTRow)o; + cursor.toParent(); + o = cursor.getObject(); + if(! (o instanceof CTTbl)){ + return null; + } + CTTbl tbl = (CTTbl) o; + XWPFTable table = getTable(tbl); + if(table == null){ + return null; + } + XWPFTableRow tableRow = table.getRow(row); + if(row == null){ + return null; + } + return tableRow.getTableCell(cell); + } }// end class diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableRow.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableRow.java index 6794808efd..4ac301476f 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableRow.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableRow.java @@ -17,11 +17,14 @@ package org.apache.poi.xwpf.usermodel; import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import org.apache.poi.util.Internal; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHeight; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTrPr; -import org.apache.poi.util.Internal; /** @@ -30,9 +33,13 @@ import org.apache.poi.util.Internal; public class XWPFTableRow { private CTRow ctRow; + private XWPFTable table; + private List tableCells; - public XWPFTableRow(CTRow row) { + public XWPFTableRow(CTRow row, XWPFTable table) { + this.table = table; this.ctRow = row; + getTableCells(); } @Internal @@ -40,17 +47,37 @@ public class XWPFTableRow { return ctRow; } - + /** + * create a new XWPFTableCell and add it to the tableCell-list of this tableRow + * @return the newly created XWPFTableCell + */ public XWPFTableCell createCell() { - return new XWPFTableCell(ctRow.addNewTc()); + XWPFTableCell tableCell = new XWPFTableCell(ctRow.addNewTc(), this, table.getPart()); + tableCells.add(tableCell); + return tableCell; } + /** + * @param pos + * @return + */ public XWPFTableCell getCell(int pos) { if (pos >= 0 && pos < ctRow.sizeOfTcArray()) { - return new XWPFTableCell(ctRow.getTcArray(pos)); + return getTableCells().get(pos); } return null; } + + /** + * adds a new TableCell at the end of this tableRow + * @return + */ + public XWPFTableCell addNewTableCell(){ + CTTc cell = ctRow.addNewTc(); + XWPFTableCell tableCell = new XWPFTableCell(cell, this, table.getPart()); + tableCells.add(tableCell); + return tableCell; + } /** * This element specifies the height of the current table row within the @@ -87,6 +114,38 @@ public class XWPFTableRow { private CTTrPr getTrPr() { return (ctRow.isSetTrPr()) ? ctRow.getTrPr() : ctRow.addNewTrPr(); } + + public XWPFTable getTable(){ + return table; + } + + /** + * create and return a list of all XWPFTableCell + * who belongs to this row + * @return a list of {@link XWPFTableCell} + */ + public List getTableCells(){ + if(tableCells == null){ + List cells = new ArrayList(); + for (CTTc tableCell : ctRow.getTcArray()) { + cells.add(new XWPFTableCell(tableCell, this, table.getPart())); + } + this.tableCells = cells; + } + return tableCells; + } + /** + * returns the XWPFTableCell which belongs to the CTTC cell + * if there is no XWPFTableCell which belongs to the parameter CTTc cell null will be returned + * @param cell + * @return + */ + public XWPFTableCell getTableCell(CTTc cell) { + for(int i=0; iorg.apache.poi.xwpf and sub-packages. @@ -45,8 +49,11 @@ public final class AllXWPFTests { result.addTestSuite(TestXWPFParagraph.class); result.addTestSuite(TestXWPFRun.class); result.addTestSuite(TestXWPFTable.class); + result.addTestSuite(TestXWPFStyles.class); + result.addTestSuite(TestXWPFPictureData.class); + result.addTestSuite(TestXWPFNumbering.class); result.addTestSuite(TestAllExtendedProperties.class); result.addTestSuite(TestPackageCorePropertiesGetKeywords.class); - return result; + return result; } } diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/TestXWPFDocument.java b/src/ooxml/testcases/org/apache/poi/xwpf/TestXWPFDocument.java index 1a7be43790..88d0823741 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/TestXWPFDocument.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/TestXWPFDocument.java @@ -20,10 +20,15 @@ package org.apache.poi.xwpf; import junit.framework.TestCase; import org.apache.poi.POIXMLProperties; +import org.apache.poi.hssf.record.formula.AddPtg; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRelation; +import org.apache.xmlbeans.XmlCursor; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; public final class TestXWPFDocument extends TestCase { @@ -93,4 +98,35 @@ public final class TestXWPFDocument extends TestCase { assertNotNull(props); assertEquals("Apache POI", props.getExtendedProperties().getUnderlyingProperties().getApplication()); } + +// public void testAddParagraph(){ +// XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("sample.docx"); +// int pLength = doc.getParagraphs().length; +// XWPFParagraph p = doc.insertNewParagraph(3); +// assertTrue(p == doc.getParagraphs()[3]); +// assertTrue(++pLength == doc.getParagraphs().length); +// CTP ctp = p.getCTP(); +// XWPFParagraph newP = doc.getParagraph(ctp); +// assertSame(p, newP); +// XmlCursor cursor = doc.getDocument().getBody().getPArray(0).newCursor(); +// XWPFParagraph cP = doc.insertNewParagraph(cursor); +// assertSame(cP, doc.getParagraphs()[0]); +// assertTrue(++pLength == doc.getParagraphs().length); +// } + + public void testAddPicture(){ + XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("sample.docx"); + byte[] jpeg = "This is a jpeg".getBytes(); + try { + int jpegNum = doc.addPicture(jpeg, XWPFDocument.PICTURE_TYPE_JPEG); + byte[] newJpeg = doc.getAllPictures().get(jpegNum).getData(); + assertEquals(newJpeg.length, jpeg.length); + for(int i = 0 ; i < jpeg.length; i++){ + assertEquals(newJpeg[i], jpeg[i]); + } + } catch (InvalidFormatException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } } diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFHeader.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFHeader.java index 4ee379f992..4747910c7a 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFHeader.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFHeader.java @@ -18,6 +18,7 @@ package org.apache.poi.xwpf.usermodel; import java.io.IOException; +import java.util.Arrays; import junit.framework.TestCase; @@ -81,7 +82,7 @@ public final class TestXWPFHeader extends TestCase { pars[0] = p1; XWPFParagraph p2 = new XWPFParagraph(ctP2); - XWPFParagraph p3 = new XWPFParagraph(ctP3); + XWPFParagraph p3 = new XWPFParagraph(ctP3, null); XWPFParagraph[] pars2 = new XWPFParagraph[2]; pars2[0] = p2; pars2[1] = p3; @@ -96,16 +97,20 @@ public final class TestXWPFHeader extends TestCase { assertNotNull(policy.getDefaultHeader()); assertNotNull(policy.getFirstPageHeader()); assertNotNull(policy.getDefaultFooter()); - // ....and that the footer object captrued above contains two + // ....and that the footer object captured above contains two // paragraphs of text. - assertEquals(footer.getParagraphs().length, 2); + assertEquals(footer.getParagraphs().size(), 2); // 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(); + XWPFParagraph[] paras = new XWPFParagraph[footer.getParagraphs().size()]; + int i=0; + for(XWPFParagraph p : footer.getParagraphs()) { + paras[i++] = p; + } assertEquals(paras.length, 2); assertEquals(paras[0].getText(), "First paragraph for the footer"); diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFNumbering.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFNumbering.java new file mode 100644 index 0000000000..7990cd70d6 --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFNumbering.java @@ -0,0 +1,40 @@ +/* ==================================================================== + 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.math.BigInteger; + +import junit.framework.TestCase; + +import org.apache.poi.xwpf.XWPFTestDataSamples; + +public class TestXWPFNumbering extends TestCase { + + public void testCompareAbstractNum(){ + XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("Numbering.docx"); + XWPFNumbering numbering = doc.getNumbering(); + BigInteger numId = BigInteger.valueOf(1); + assertTrue(numbering.numExist(numId)); + XWPFNum num = numbering.getNum(numId); + BigInteger abstrNumId = num.getCTNum().getAbstractNumId().getVal(); + XWPFAbstractNum abstractNum = numbering.getAbstractNum(abstrNumId); + BigInteger compareAbstractNum = numbering.getIdOfAbstractNum(abstractNum); + assertEquals(abstrNumId, compareAbstractNum); + } + +} diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java index 73f66927fd..3444c246e4 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java @@ -18,12 +18,26 @@ package org.apache.poi.xwpf.usermodel; import java.math.BigInteger; -import java.io.File; +import java.util.List; import junit.framework.TestCase; import org.apache.poi.xwpf.XWPFTestDataSamples; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBookmark; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTInd; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTJc; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPBdr; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSpacing; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTextAlignment; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.STLineSpacingRule; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTextAlignment; /** * Tests for XWPF Paragraphs @@ -39,9 +53,9 @@ public final class TestXWPFParagraph extends TestCase { XWPFHeader hdr = xml.getHeaderFooterPolicy().getDefaultHeader(); assertNotNull(hdr); - XWPFParagraph[] ps = hdr.getParagraphs(); - assertEquals(1, ps.length); - XWPFParagraph p = ps[0]; + List ps = hdr.getParagraphs(); + assertEquals(1, ps.size()); + XWPFParagraph p = ps.get(0); assertEquals(5, p.getCTP().getRArray().length); assertEquals("First header column!\tMid header\tRight header!", p @@ -53,25 +67,25 @@ public final class TestXWPFParagraph extends TestCase { */ public void disabled_testDocumentParagraph() { XWPFDocument xml = XWPFTestDataSamples.openSampleDocument("ThreeColHead.docx"); - XWPFParagraph[] ps = xml.getParagraphs(); - assertEquals(10, ps.length); + List ps = xml.getParagraphs(); + assertEquals(10, ps.size()); - assertFalse(ps[0].isEmpty()); + assertFalse(ps.get(0).isEmpty()); assertEquals( "This is a sample word document. It has two pages. It has a three column heading, but no footer.", - ps[0].getText()); + ps.get(0).getText()); - assertTrue(ps[1].isEmpty()); - assertEquals("", ps[1].getText()); + assertTrue(ps.get(1).isEmpty()); + assertEquals("", ps.get(1).getText()); - assertFalse(ps[2].isEmpty()); - assertEquals("HEADING TEXT", ps[2].getText()); + assertFalse(ps.get(2).isEmpty()); + assertEquals("HEADING TEXT", ps.get(2).getText()); - assertTrue(ps[3].isEmpty()); - assertEquals("", ps[3].getText()); + assertTrue(ps.get(3).isEmpty()); + assertEquals("", ps.get(3).getText()); - assertFalse(ps[4].isEmpty()); - assertEquals("More on page one", ps[4].getText()); + assertFalse(ps.get(4).isEmpty()); + assertEquals("More on page one", ps.get(4).getText()); } public void testSetGetBorderTop() { @@ -216,7 +230,7 @@ public final class TestXWPFParagraph extends TestCase { public void testBookmarks() { XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("bookmarks.docx"); - XWPFParagraph paragraph = doc.getParagraphs()[0]; + XWPFParagraph paragraph = doc.getParagraphs().get(0); assertEquals("Sample Word Document", paragraph.getText()); assertEquals(1, paragraph.getCTP().sizeOfBookmarkStartArray()); assertEquals(0, paragraph.getCTP().sizeOfBookmarkEndArray()); diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFPictureData.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFPictureData.java new file mode 100644 index 0000000000..87be3b2c8d --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFPictureData.java @@ -0,0 +1,89 @@ +/* ==================================================================== + 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.util.Arrays; +import java.util.List; + +import org.apache.poi.hslf.usermodel.PictureData; +import org.apache.poi.hssf.record.formula.AddPtg; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.openxml4j.opc.PackageRelationship; +import org.apache.poi.xwpf.XWPFTestDataSamples; + + +import junit.framework.TestCase; + +public class TestXWPFPictureData extends TestCase { + public void testRead(){ + XWPFDocument sampleDoc = XWPFTestDataSamples.openSampleDocument("VariousPictures.docx"); + List pictures = sampleDoc.getAllPictures(); + assertSame(pictures, sampleDoc.getAllPictures()); + + assertEquals(5, pictures.size()); + String[] ext = {"wmf", "png", "emf", "emf", "jpeg"}; + for (int i = 0; i < pictures.size(); i++) { + assertEquals(ext[i], pictures.get(i).suggestFileExtension()); + } + + int num = pictures.size(); + + byte[] pictureData = {0xA, 0xB, 0XC, 0xD, 0xE, 0xF}; + + int idx; + try { + idx = sampleDoc.addPicture(pictureData, XWPFDocument.PICTURE_TYPE_JPEG); + assertEquals(num + 1, pictures.size()); + //idx is 0-based index in the #pictures array + assertEquals(pictures.size() - 1, idx); + XWPFPictureData pict = pictures.get(idx); + assertEquals("jpeg", pict.suggestFileExtension()); + assertTrue(Arrays.equals(pictureData, pict.getData())); + } catch (InvalidFormatException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void testNew(){ + XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("EmptyDocumentWithHeaderFooter.docx"); + byte[] jpegData = "test jpeg data".getBytes(); + byte[] wmfData = "test wmf data".getBytes(); + byte[] pngData = "test png data".getBytes(); + List pictures = doc.getAllPictures(); + assertEquals(0, pictures.size()); + int jpegIdx; + try { + jpegIdx = doc.addPicture(jpegData, XWPFDocument.PICTURE_TYPE_JPEG); + assertEquals(1, pictures.size()); + assertEquals("jpeg", pictures.get(jpegIdx).suggestFileExtension()); + assertTrue(Arrays.equals(jpegData, pictures.get(jpegIdx).getData())); + + PackageRelationship addPictureReference = doc.addPictureReference(jpegData, Document.PICTURE_TYPE_JPEG ); + XWPFPictureData pictureDataByID = doc.getPictureDataByID(addPictureReference.getId()); + byte [] newJPEGData = pictureDataByID.getData(); + assertEquals(newJPEGData.length, jpegData.length); + for(int i = 0; i < newJPEGData.length; i++){ + assertEquals(newJPEGData[i], jpegData[i]); + } + } catch (InvalidFormatException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java new file mode 100644 index 0000000000..6c4a722035 --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFStyles.java @@ -0,0 +1,54 @@ +/* ==================================================================== + 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.util.ArrayList; +import java.util.List; + +import org.apache.poi.xwpf.XWPFTestDataSamples; + +import junit.framework.TestCase; + +public class TestXWPFStyles extends TestCase { + +// protected void setUp() throws Exception { +// super.setUp(); +// } + + public void testGetUsedStyles(){ + XWPFDocument sampleDoc = XWPFTestDataSamples.openSampleDocument("Styles.docx"); + List testUsedStyleList = new ArrayList(); + XWPFStyles styles = sampleDoc.getStyles(); + XWPFStyle style = styles.getStyle("berschrift1"); + testUsedStyleList.add(style); + testUsedStyleList.add(styles.getStyle("Standard")); + testUsedStyleList.add(styles.getStyle("berschrift1Zchn")); + testUsedStyleList.add(styles.getStyle("Absatz-Standardschriftart")); + style.hasSameName(style); + + List usedStyleList = styles.getUsedStyleList(style); + assertEquals(usedStyleList, testUsedStyleList); + + + } + +// protected void tearDown() throws Exception { +// super.tearDown(); +// } + +} diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFTable.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFTable.java index d7a831757e..6e8fe1e8ea 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFTable.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFTable.java @@ -43,14 +43,14 @@ public class TestXWPFTable extends TestCase { public void testConstructor() { CTTbl ctTable = CTTbl.Factory.newInstance(); - XWPFTable xtab = new XWPFTable(null, ctTable); + XWPFTable xtab = new XWPFTable(ctTable, null); assertNotNull(xtab); assertEquals(1, ctTable.sizeOfTrArray()); assertEquals(1, ctTable.getTrArray(0).sizeOfTcArray()); assertNotNull(ctTable.getTrArray(0).getTcArray(0).getPArray(0)); ctTable = CTTbl.Factory.newInstance(); - xtab = new XWPFTable(null, ctTable, 3, 2); + xtab = new XWPFTable(ctTable, null, 3, 2); assertNotNull(xtab); assertEquals(3, ctTable.sizeOfTrArray()); assertEquals(2, ctTable.getTrArray(0).sizeOfTcArray()); @@ -67,7 +67,7 @@ public class TestXWPFTable extends TestCase { CTText text = run.addNewT(); text.setStringValue("finally I can write!"); - XWPFTable xtab = new XWPFTable(null, table); + XWPFTable xtab = new XWPFTable(table, null); assertEquals("finally I can write!\n", xtab.getText()); } @@ -84,7 +84,7 @@ public class TestXWPFTable extends TestCase { r3.addNewTc().addNewP(); r3.addNewTc().addNewP(); - XWPFTable xtab = new XWPFTable(null, table); + XWPFTable xtab = new XWPFTable(table, null); assertEquals(3, xtab.getNumberOfRows()); assertNotNull(xtab.getRow(2)); @@ -95,7 +95,7 @@ public class TestXWPFTable extends TestCase { assertEquals(2, table.getTrArray(0).sizeOfTcArray()); //check creation of first row - xtab = new XWPFTable(null, CTTbl.Factory.newInstance()); + xtab = new XWPFTable(CTTbl.Factory.newInstance(), null); assertEquals(1, xtab.getCTTbl().getTrArray(0).sizeOfTcArray()); } @@ -104,7 +104,7 @@ public class TestXWPFTable extends TestCase { CTTbl table = CTTbl.Factory.newInstance(); table.addNewTblPr().addNewTblW().setW(new BigInteger("1000")); - XWPFTable xtab = new XWPFTable(null, table); + XWPFTable xtab = new XWPFTable(table, null); assertEquals(1000, xtab.getWidth()); @@ -115,7 +115,7 @@ public class TestXWPFTable extends TestCase { public void testSetGetHeight() { CTTbl table = CTTbl.Factory.newInstance(); - XWPFTable xtab = new XWPFTable(null, table); + XWPFTable xtab = new XWPFTable(table, null); XWPFTableRow row = xtab.createRow(); row.setHeight(20); assertEquals(20, row.getHeight()); diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFTableRow.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFTableRow.java new file mode 100644 index 0000000000..0844b507ba --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFTableRow.java @@ -0,0 +1,46 @@ +/* ==================================================================== + 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 org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow; + +import junit.framework.TestCase; + +public class TestXWPFTableRow extends TestCase { + + + + @Override + protected void setUp() throws Exception { + // TODO Auto-generated method stub + super.setUp(); + } + + public void testSomething() throws Exception { + + CTRow ctRow = CTRow.Factory.newInstance(); + + } + + @Override + protected void tearDown() throws Exception { + // TODO Auto-generated method stub + super.tearDown(); + } + +} -- 2.39.5