diff options
Diffstat (limited to 'src/ooxml/java/org/apache/poi/xwpf/usermodel')
16 files changed, 1472 insertions, 1328 deletions
diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBody.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBody.java index a85ec7408a..8d15b07279 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBody.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBody.java @@ -19,6 +19,7 @@ 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; @@ -42,7 +43,7 @@ public interface IBody { * belongs. * @return the Part, to which the body belongs */ - IBody getPart(); + POIXMLDocumentPart getPart(); /** * get the PartType of the body, for example diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBodyElement.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBodyElement.java index 527eb7ae4d..70009be3b5 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBodyElement.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/IBodyElement.java @@ -17,6 +17,7 @@ package org.apache.poi.xwpf.usermodel; +import org.apache.poi.POIXMLDocumentPart; /** * 9 Jan 2010 @@ -24,7 +25,8 @@ package org.apache.poi.xwpf.usermodel; * */ public interface IBodyElement{ - IBody getPart(); + IBody getBody(); + POIXMLDocumentPart getPart(); BodyType getPartType(); BodyElementType getElementType(); } 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 7fed7b3e90..517c72358e 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java @@ -16,12 +16,12 @@ ==================================================================== */ package org.apache.poi.xwpf.usermodel; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -36,6 +36,7 @@ import org.apache.poi.POIXMLDocument; import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.POIXMLException; import org.apache.poi.POIXMLProperties; +import org.apache.poi.POIXMLRelation; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.OpenXML4JException; import org.apache.poi.openxml4j.opc.OPCPackage; @@ -46,6 +47,7 @@ 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.IOUtils; +import org.apache.poi.util.IdentifierManager; import org.apache.poi.util.Internal; import org.apache.poi.util.PackageHelper; import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy; @@ -85,16 +87,21 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { private CTDocument1 ctDocument; private XWPFSettings settings; - protected List<XWPFFooter> footers; - protected List <XWPFHeader> headers; - protected List<XWPFComment> comments; - protected List<XWPFHyperlink> hyperlinks; - protected List<XWPFParagraph> paragraphs; - protected List<XWPFTable> tables; - protected List<IBodyElement> bodyElements; - protected List<XWPFPictureData> pictures; - protected Map<Integer, XWPFFootnote> footnotes; - protected Map<Integer, XWPFFootnote> endnotes; + /** + * Keeps track on all id-values used in this document and included parts, like headers, footers, etc. + */ + private IdentifierManager drawingIdManager = new IdentifierManager(1L,4294967295L); + protected List<XWPFFooter> footers = new ArrayList<XWPFFooter>(); + protected List<XWPFHeader> headers = new ArrayList<XWPFHeader>(); + protected List<XWPFComment> comments = new ArrayList<XWPFComment>(); + protected List<XWPFHyperlink> hyperlinks = new ArrayList<XWPFHyperlink>(); + protected List<XWPFParagraph> paragraphs = new ArrayList<XWPFParagraph>(); + protected List<XWPFTable> tables = new ArrayList<XWPFTable>(); + protected List<IBodyElement> bodyElements = new ArrayList<IBodyElement>(); + protected List<XWPFPictureData> pictures = new ArrayList<XWPFPictureData>(); + protected Map<Long, List<XWPFPictureData>> packagePictures = new HashMap<Long, List<XWPFPictureData>>(); + protected Map<Integer, XWPFFootnote> footnotes = new HashMap<Integer, XWPFFootnote>(); + protected Map<Integer, XWPFFootnote> endnotes = new HashMap<Integer, XWPFFootnote>(); protected XWPFNumbering numbering; protected XWPFStyles styles; @@ -122,80 +129,78 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { @Override protected void onDocumentRead() throws IOException { - hyperlinks = new ArrayList<XWPFHyperlink>(); - comments = new ArrayList<XWPFComment>(); - paragraphs = new ArrayList<XWPFParagraph>(); - tables= new ArrayList<XWPFTable>(); - bodyElements = new ArrayList<IBodyElement>(); - footers = new ArrayList<XWPFFooter>(); - headers = new ArrayList<XWPFHeader>(); - footnotes = new HashMap<Integer, XWPFFootnote>(); - endnotes = new HashMap<Integer, XWPFFootnote>(); - try { DocumentDocument doc = DocumentDocument.Factory.parse(getPackagePart().getInputStream()); ctDocument = doc.getDocument(); initFootnotes(); - - + // parse the document with cursor and add // the XmlObject to its lists - XmlCursor cursor = ctDocument.getBody().newCursor(); + 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); + XWPFParagraph p = new XWPFParagraph((CTP) o, this); + bodyElements.add(p); + paragraphs.add(p); + } else if (o instanceof CTTbl) { + XWPFTable t = new XWPFTable((CTTbl) o, this); + bodyElements.add(t); + tables.add(t); } } cursor.dispose(); - + // 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()){ + 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.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())){ + if (relation.equals(XWPFRelation.STYLES.getRelation())) { + this.styles = (XWPFStyles) p; + this.styles.onDocumentRead(); + } else if (relation.equals(XWPFRelation.NUMBERING.getRelation())) { + this.numbering = (XWPFNumbering) p; + this.numbering.onDocumentRead(); + } else if (relation.equals(XWPFRelation.FOOTER.getRelation())) { + XWPFFooter footer = (XWPFFooter) p; + footers.add(footer); + footer.onDocumentRead(); + } else if (relation.equals(XWPFRelation.HEADER.getRelation())) { + XWPFHeader header = (XWPFHeader) p; + headers.add(header); + header.onDocumentRead(); + } else if (relation.equals(XWPFRelation.COMMENT.getRelation())) { + // TODO Create according XWPFComment class, extending POIXMLDocumentPart CommentsDocument cmntdoc = CommentsDocument.Factory.parse(p.getPackagePart().getInputStream()); - for(CTComment ctcomment : cmntdoc.getComments().getCommentList()) { + for (CTComment ctcomment : cmntdoc.getComments().getCommentList()) { comments.add(new XWPFComment(ctcomment, this)); } - } else if (relation.equals(XWPFRelation.SETTINGS.getRelation())){ - settings = (XWPFSettings)p; + } else if (relation.equals(XWPFRelation.SETTINGS.getRelation())) { + settings = (XWPFSettings) p; + settings.onDocumentRead(); + } else if (relation.equals(XWPFRelation.IMAGES.getRelation())) { + XWPFPictureData picData = (XWPFPictureData) p; + picData.onDocumentRead(); + registerPackagePictureData(picData); + pictures.add(picData); } } - initHyperlinks(); } 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 { - Iterator <PackageRelationship> relIter = + try { + Iterator<PackageRelationship> relIter = getPackagePart().getRelationshipsByType(XWPFRelation.HYPERLINK.getRelation()).iterator(); while(relIter.hasNext()) { PackageRelationship rel = relIter.next(); @@ -251,20 +256,10 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { */ @Override protected void onDocumentCreate() { - hyperlinks = new ArrayList<XWPFHyperlink>(); - comments = new ArrayList<XWPFComment>(); - paragraphs = new ArrayList<XWPFParagraph>(); - tables= new ArrayList<XWPFTable>(); - bodyElements = new ArrayList<IBodyElement>(); - footers = new ArrayList<XWPFFooter>(); - headers = new ArrayList<XWPFHeader>(); - footnotes = new HashMap<Integer, XWPFFootnote>(); - endnotes = new HashMap<Integer, XWPFFootnote>(); - ctDocument = CTDocument1.Factory.newInstance(); ctDocument.addNewBody(); - - settings = (XWPFSettings) createRelationship(XWPFRelation.SETTINGS, XWPFFactory.getInstance()); + + settings = (XWPFSettings) createRelationship(XWPFRelation.SETTINGS,XWPFFactory.getInstance()); POIXMLProperties.ExtendedProperties expProps = getProperties().getExtendedProperties(); expProps.getUnderlyingProperties().setApplication(DOCUMENT_CREATOR); @@ -277,6 +272,10 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { public CTDocument1 getDocument() { return ctDocument; } + + IdentifierManager getDrawingIdManager() { + return drawingIdManager; + } /** * returns an Iterator with paragraphs and tables @@ -340,8 +339,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { public XWPFHyperlink getHyperlinkByID(String id) { Iterator<XWPFHyperlink> iter = hyperlinks.iterator(); - while(iter.hasNext()) - { + while (iter.hasNext()) { XWPFHyperlink link = iter.next(); if(link.getId().equals(id)) return link; @@ -363,15 +361,12 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { } public XWPFHyperlink[] getHyperlinks() { - return hyperlinks.toArray( - new XWPFHyperlink[hyperlinks.size()] - ); + return hyperlinks.toArray(new XWPFHyperlink[hyperlinks.size()]); } public XWPFComment getCommentByID(String id) { Iterator<XWPFComment> iter = comments.iterator(); - while(iter.hasNext()) - { + while (iter.hasNext()) { XWPFComment comment = iter.next(); if(comment.getId().equals(id)) return comment; @@ -379,10 +374,9 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { return null; } + public XWPFComment[] getComments() { - return comments.toArray( - new XWPFComment[comments.size()] - ); + return comments.toArray(new XWPFComment[comments.size()]); } /** @@ -391,10 +385,8 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { */ public PackagePart getPartById(String id) { try { - return getTargetPart( - getCorePart().getRelationship(id) - ); - } catch(InvalidFormatException e) { + return getTargetPart(getCorePart().getRelationship(id)); + } catch (InvalidFormatException e) { throw new IllegalArgumentException(e); } } @@ -422,8 +414,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { throw new IllegalStateException("Expecting one Styles document part, but found " + parts.length); } - StylesDocument sd = - StylesDocument.Factory.parse(parts[0].getInputStream()); + StylesDocument sd = StylesDocument.Factory.parse(parts[0].getInputStream()); return sd.getStyles(); } @@ -435,15 +426,17 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { List<PackagePart> embedds = new LinkedList<PackagePart>(); // Get the embeddings for the workbook - for(PackageRelationship rel : getPackagePart().getRelationshipsByType(OLE_OBJECT_REL_TYPE)) + for (PackageRelationship rel : getPackagePart().getRelationshipsByType(OLE_OBJECT_REL_TYPE)) { embedds.add(getTargetPart(rel)); + } - for(PackageRelationship rel : getPackagePart().getRelationshipsByType(PACK_OBJECT_REL_TYPE)) + for (PackageRelationship rel : getPackagePart().getRelationshipsByType(PACK_OBJECT_REL_TYPE)) { embedds.add(getTargetPart(rel)); + } return embedds; } - + /** * Finds that for example the 2nd entry in the body list is the 1st paragraph */ @@ -452,7 +445,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { if(list.size() == 0) { return -1; } - + if(pos >= 0 && pos < bodyElements.size()) { // Ensure the type is correct IBodyElement needle = bodyElements.get(pos); @@ -460,7 +453,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { // Wrong type return -1; } - + // Work back until we find it int startPos = Math.min(pos, list.size()-1); for(int i=startPos; i>=0; i--) { @@ -475,17 +468,21 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { } /** - * 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 - * + * Look up the paragraph at the specified position in the body elemnts list + * and return this paragraphs position in the paragraphs list + * + * @param pos + * The position of the relevant paragraph in the body elements + * list + * @return the position of the paragraph in the paragraphs list, if there is + * a paragraph at the position in the bodyelements list. Else it + * will return -1 + * */ - public int getParagraphPos(int pos){ + public int getParagraphPos(int pos) { return getBodyElementSpecificPos(pos, paragraphs); } - + /** * get with the position of a table in the bodyelement array list * the position of this table in the table array list @@ -493,98 +490,135 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { * @return if there is a table at the position in the bodyelement array list, * else it will return null. */ - public int getTablePos(int pos){ + public int getTablePos(int pos) { return getBodyElementSpecificPos(pos, tables); } - + /** - * add a new paragraph at position of the cursor + * add a new paragraph at position of the cursor. The cursor must be on the + * {@link TokenType#START} tag of an subelement of the documents body. When + * this method is done, the cursor passed as parameter points to the + * {@link TokenType#END} of the newly inserted paragraph. + * * @param cursor + * @return the {@link XWPFParagraph} object representing the newly inserted + * CTP object */ - 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; - } - - 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 - */ - 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; - - } - + public XWPFParagraph insertNewParagraph(XmlCursor cursor) { + if (isCursorInBody(cursor)) { + String uri = CTP.type.getName().getNamespaceURI(); + /* + * TODO DO not use a coded constant, find the constant in the OOXML + * classes instead, as the child of type CT_Paragraph is defined in the + * OOXML schema as 'p' + */ + String localPart = "p"; + // creates a new Paragraph, cursor is positioned inside the new + // element + cursor.beginElement(localPart, uri); + // move the cursor to the START token to the paragraph just created + cursor.toParent(); + CTP p = (CTP) cursor.getObject(); + XWPFParagraph newP = new XWPFParagraph(p, this); + XmlObject o = null; + /* + * move the cursor to the previous element until a) the next + * paragraph is found or b) all elements have been passed + */ + while (!(o instanceof CTP) && (cursor.toPrevSibling())) { + o = cursor.getObject(); + } + /* + * if the object that has been found is a) not a paragraph or b) is + * the paragraph that has just been inserted, as the cursor in the + * while loop above was not moved as there were no other siblings, + * then the paragraph that was just inserted is the first paragraph + * in the body. Otherwise, take the previous paragraph and calculate + * the new index for the new paragraph. + */ + if ((!(o instanceof CTP)) || (CTP) o == p) { + paragraphs.add(0, newP); + } else { + int pos = paragraphs.indexOf(getParagraph((CTP) o)) + 1; + paragraphs.add(pos, newP); + } + + /* + * create a new cursor, that points to the START token of the just + * inserted paragraph + */ + XmlCursor newParaPos = p.newCursor(); + try { + /* + * Calculate the paragraphs index in the list of all body + * elements + */ + int i = 0; + cursor.toCursor(newParaPos); + while (cursor.toPrevSibling()) { + o = cursor.getObject(); + if (o instanceof CTP || o instanceof CTTbl) + i++; + } + bodyElements.add(i, newP); + cursor.toCursor(newParaPos); + cursor.toEndToken(); + return newP; + } finally { + newParaPos.dispose(); + } + } + return null; + } + + 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 + */ + private boolean isCursorInBody(XmlCursor cursor) { + XmlCursor verify = cursor.newCursor(); + verify.toParent(); + try { + return (verify.getObject() == this.ctDocument.getBody()); + } finally { + verify.dispose(); + } + } + private int getPosOfBodyElement(IBodyElement needle) { BodyElementType type = needle.getElementType(); IBodyElement current; @@ -608,7 +642,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { public int getPosOfParagraph(XWPFParagraph p){ return getPosOfBodyElement(p); } - + /** * Get the position of the table, within the list of * all the body elements. @@ -666,7 +700,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { * Appends a new paragraph to this document * @return a new paragraph */ - public XWPFParagraph createParagraph(){ + public XWPFParagraph createParagraph() { XWPFParagraph p = new XWPFParagraph(ctDocument.getBody().addNewP(), this); bodyElements.add(p); paragraphs.add(p); @@ -753,24 +787,28 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { * @param paragraph * @param pos */ - public void setParagraph(XWPFParagraph paragraph, int pos){ - paragraphs.set(pos, paragraph); - ctDocument.getBody().setPArray(pos, paragraph.getCTP()); + public void setParagraph(XWPFParagraph paragraph, int pos) { + paragraphs.set(pos, paragraph); + ctDocument.getBody().setPArray(pos, paragraph.getCTP()); + /* TODO update body element, update xwpf element, verify that + * incoming paragraph belongs to this document or if not, XML was + * copied properly (namespace-abbreviations, etc.) + */ } - + /** * @return the LastParagraph of the document */ - public XWPFParagraph getLastParagraph(){ - int lastPos = paragraphs.toArray().length - 1; - return paragraphs.get(lastPos); + 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(){ + public XWPFTable createTable() { XWPFTable table = new XWPFTable(ctDocument.getBody().addNewTbl(), this); bodyElements.add(table); tables.add(table); @@ -789,37 +827,35 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { tables.add(table); return table; } - - + /** * */ public void createTOC() { CTSdtBlock block = this.getDocument().getBody().addNewSdt(); TOC toc = new TOC(block); - for (XWPFParagraph par: paragraphs ) { + for (XWPFParagraph par : paragraphs) { String parStyle = par.getStyle(); if (parStyle != null && parStyle.substring(0, 7).equals("Heading")) { try { int level = Integer.valueOf(parStyle.substring("Heading".length())).intValue(); toc.addRow(level, par.getText(), 1, "112723803"); - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { e.printStackTrace(); } } } } - + /**Replace content of table in array tables at position pos with a * @param pos * @param table */ - public void setTable(int pos, XWPFTable table){ - tables.set(pos, table); - ctDocument.getBody().setTblArray(pos, table.getCTTbl()); + 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 <br/> * specifies that the protection is enforced (w:enforcement="1") <br/> @@ -900,7 +936,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { * <w:documentProtection w:edit="readOnly" w:enforcement="1"/> * </pre> */ - public void enforceReadonlyProtection() { + public void enforceReadonlyProtection() { settings.setEnforcementEditValue(STDocProtect.READ_ONLY); } @@ -918,7 +954,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { */ public void enforceFillingFormsProtection() { settings.setEnforcementEditValue(STDocProtect.FORMS); - } + } /** * Enforce the Comments protection.<br/> @@ -949,7 +985,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { * </pre> */ public void enforceTrackedChangesProtection() { - settings.setEnforcementEditValue(STDocProtect.TRACKED_CHANGES); + settings.setEnforcementEditValue(STDocProtect.TRACKED_CHANGES); } /** @@ -960,182 +996,220 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { public void removeProtectionEnforcement() { settings.removeEnforcement(); } - + /** - * Return the zoom level, as a percentage + * inserts an existing XWPFTable to the arrays bodyElements and tables + * @param pos + * @param table */ - public long getZoomPercent() { - return settings.getZoomPercent(); + public void insertTable(int pos, XWPFTable table) { + bodyElements.add(pos, table); + int i; + for (i = 0; i < ctDocument.getBody().getTblList().size(); i++) { + CTTbl tbl = ctDocument.getBody().getTblArray(i); + if (tbl == table.getCTTbl()) { + break; + } + } + tables.add(i, table); } - + /** - * Sets the zoom level, as a percentage + * Returns all Pictures, which are referenced from the document itself. + * @return a {@link List} of {@link XWPFPictureData}. The returned {@link List} is unmodifiable. Use #a */ - public void setZoomPercent(long zoomPercent) { - settings.setZoomPercent(zoomPercent); - } - - /** - * inserts an existing XWPFTable to the arrays bodyElements and tables - * @param pos - * @param table - */ - public void insertTable(int pos, XWPFTable table) { - bodyElements.add(pos, table); - int i; - for (i = 0; i < ctDocument.getBody().getTblList().size(); i++) { - CTTbl tbl = ctDocument.getBody().getTblArray(i); - if(tbl == table.getCTTbl()){ - break; - } - } - tables.add(i, table); - } - public List<XWPFPictureData> getAllPictures() { - if(pictures == null){ - pictures = new ArrayList<XWPFPictureData>(); - for (POIXMLDocumentPart poixmlDocumentPart : getRelations()){ - if(poixmlDocumentPart instanceof XWPFPictureData){ - pictures.add((XWPFPictureData)poixmlDocumentPart); - } - } - } - return pictures; + return Collections.unmodifiableList(pictures); } - + /** - * @return all Pictures in this package + * @return all Pictures in this package */ - public List<XWPFPictureData> getAllPackagePictures(){ - List<XWPFPictureData> pkgpictures = new ArrayList<XWPFPictureData>(); - pkgpictures.addAll(getAllPictures()); - for (POIXMLDocumentPart poixmlDocumentPart : getRelations()){ - if(poixmlDocumentPart instanceof XWPFHeaderFooter){ - pkgpictures.addAll(((XWPFHeaderFooter)poixmlDocumentPart).getAllPictures()); - } - } - return pkgpictures; + public List<XWPFPictureData> getAllPackagePictures() { + List<XWPFPictureData> result = new ArrayList<XWPFPictureData>(); + Collection<List<XWPFPictureData>> values = packagePictures.values(); + for (List<XWPFPictureData> list : values) { + result.addAll(list); + } + return Collections.unmodifiableList(result); } - - /** - * Adds a picture to the document. Users should normally call - * {@link XWPFRun#addPicture(InputStream, int)} - * - * - * @param is The stream to read image from - * @param format The format of the picture, eg {@link Document#PICTURE_TYPE_JPEG} - * - * @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, false); - OutputStream out = img.getPackagePart().getOutputStream(); - IOUtils.copy(is, out); - out.close(); - pictures.add(img); - return getAllPictures().size()-1; + void registerPackagePictureData(XWPFPictureData picData) { + List<XWPFPictureData> list = packagePictures.get(picData.getChecksum()); + if (list == null) { + list = new ArrayList<XWPFPictureData>(1); + packagePictures.put(picData.getChecksum(), list); + } + if (!list.contains(picData)) + { + list.add(picData); + } } - /** - * Adds a picture to the document. Users should normally call - * {@link XWPFRun#addPicture(InputStream, int)} - * - * @param pictureData The bytes to read image from - * @param format The format of the picture, eg {@link Document#PICTURE_TYPE_JPEG} - * - * @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 { + XWPFPictureData findPackagePictureData(byte[] pictureData, int format) + { + long checksum = IOUtils.calculateChecksum(pictureData); + XWPFPictureData xwpfPicData = null; + /* + * Try to find PictureData with this checksum. Create new, if none + * exists. + */ + List<XWPFPictureData> xwpfPicDataList = packagePictures.get(checksum); + if (xwpfPicDataList != null) { + Iterator<XWPFPictureData> iter = xwpfPicDataList.iterator(); + while (iter.hasNext() && xwpfPicData == null) { + XWPFPictureData curElem = iter.next(); + if (Arrays.equals(pictureData, curElem.getData())) { + xwpfPicData = curElem; + } + } + } + return xwpfPicData; + } + + public String addPictureData(byte[] pictureData,int format) throws InvalidFormatException + { + XWPFPictureData xwpfPicData = findPackagePictureData(pictureData, format); + POIXMLRelation relDesc = XWPFPictureData.RELATIONS[format]; + + if (xwpfPicData == null) + { + /* Part doesn't exist, create a new one */ + int idx = getNextPicNameNumber(format); + xwpfPicData = (XWPFPictureData) createRelationship(relDesc, XWPFFactory.getInstance(),idx); + /* write bytes to new part */ + PackagePart picDataPart = xwpfPicData.getPackagePart(); + OutputStream out = null; + try { + out = picDataPart.getOutputStream(); + out.write(pictureData); + } catch (IOException e) { + throw new POIXMLException(e); + } finally { + try { + out.close(); + } catch (IOException e) { + // ignore + } + } + + registerPackagePictureData(xwpfPicData); + pictures.add(xwpfPicData); + + return getRelationId(xwpfPicData); + } + else if (!getRelations().contains(xwpfPicData)) + { + /* + * Part already existed, but was not related so far. Create + * relationship to the already existing part and update + * POIXMLDocumentPart data. + */ + PackagePart picDataPart = xwpfPicData.getPackagePart(); + // TODO add support for TargetMode.EXTERNAL relations. + TargetMode targetMode = TargetMode.INTERNAL; + PackagePartName partName = picDataPart.getPartName(); + String relation = relDesc.getRelation(); + PackageRelationship relShip = getPackagePart().addRelationship(partName,targetMode,relation); + String id = relShip.getId(); + addRelation(id,xwpfPicData); + pictures.add(xwpfPicData); + return id; + } + else + { + /* Part already existed, get relation id and return it */ + return getRelationId(xwpfPicData); + } + } + + public String addPictureData(InputStream is,int format) throws InvalidFormatException + { try { - return addPicture(new ByteArrayInputStream(pictureData), format); - } catch (IOException e){ + byte[] data = IOUtils.toByteArray(is); + return addPictureData(data, format); + } catch (IOException e) { throw new POIXMLException(e); } } - + /** * get the next free ImageNumber * @param format * @return the next free ImageNumber * @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; + 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; + POIXMLDocumentPart relatedPart = getRelationById(blipID); + if (relatedPart instanceof XWPFPictureData) { + XWPFPictureData xwpfPicData = (XWPFPictureData) relatedPart; + return xwpfPicData; + } + return null; } - + /** - * getNumbering + * getNumbering * @return numbering */ - public XWPFNumbering getNumbering(){ - return numbering; + public XWPFNumbering getNumbering() { + return numbering; } - /** - * get Styles - * @return styles for this document - */ - public XWPFStyles getStyles(){ - return styles; - } - - /** - * get the paragraph with the CTP class p - * - * @param p - * @return the paragraph with the CTP class p - */ - public XWPFParagraph getParagraph(CTP p){ - for(int i=0; i<getParagraphs().size(); i++){ - if(getParagraphs().get(i).getCTP() == p) return getParagraphs().get(i); - } - return null; - } - - /** - * get a table by its CTTbl-Object - * @param ctTbl - * @see org.apache.poi.xwpf.usermodel.IBody#getTable(org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl) - * @return a table by its CTTbl-Object or null - */ + /** + * get Styles + * @return styles for this document + */ + public XWPFStyles getStyles() { + return styles; + } + + /** + * get the paragraph with the CTP class p + * + * @param p + * @return the paragraph with the CTP class p + */ + public XWPFParagraph getParagraph(CTP p) { + for (int i = 0; i < getParagraphs().size(); i++) { + if (getParagraphs().get(i).getCTP() == p) { + return getParagraphs().get(i); + } + } + return null; + } + + /** + * get a table by its CTTbl-Object + * @param ctTbl + * @see org.apache.poi.xwpf.usermodel.IBody#getTable(org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl) + * @return a table by its CTTbl-Object or null + */ public XWPFTable getTable(CTTbl ctTbl) { - for(int i=0; i<tables.size(); i++){ - if(getTables().get(i).getCTTbl() == ctTbl) return getTables().get(i); - } - return null; - } + for (int i = 0; i < tables.size(); i++) { + if (getTables().get(i).getCTTbl() == ctTbl) { + return getTables().get(i); + } + } + return null; + } public Iterator<XWPFTable> getTablesIterator() { @@ -1157,19 +1231,18 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { 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() + */ + public POIXMLDocumentPart getPart() { + return this; + } /** - * 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() - */ - public IBody getPart() { - return this; - } - - /** * get the PartType of the body, for example * DOCUMENT, HEADER, FOOTER, FOOTNOTE, * @@ -1212,4 +1285,4 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { public XWPFDocument getXWPFDocument() { return this; } -}//end class +} // 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 feaf9f7dd0..c6f6681626 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFooter.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFFooter.java @@ -19,17 +19,16 @@ 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.POIXMLException; 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; @@ -46,38 +45,34 @@ public class XWPFFooter extends XWPFHeaderFooter { super(); } - public XWPFFooter(XWPFDocument doc, CTHdrFtr hdrFtr) throws IOException { - super(doc, hdrFtr); - bodyElements = new ArrayList<IBodyElement>(); - paragraphs = new ArrayList<XWPFParagraph>(); - tables = new ArrayList<XWPFTable>(); - XmlCursor cursor = headerFooter.newCursor(); + public XWPFFooter(XWPFDocument doc, CTHdrFtr hdrFtr) throws IOException { + super(doc, hdrFtr); + 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); + 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); + XWPFTable t = new XWPFTable((CTTbl)o, this); + tables.add(t); + bodyElements.add(t); } } cursor.dispose(); - getAllPictures(); - } + } + + public XWPFFooter(POIXMLDocumentPart parent, PackagePart part, PackageRelationship rel) throws IOException { + super(parent, part, rel); + } - public XWPFFooter(POIXMLDocumentPart parent, PackagePart part, PackageRelationship rel) throws IOException { - super(parent, part, rel); - } - - /** - * save and commit footer - */ - @Override + /** + * 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")); @@ -97,58 +92,44 @@ public class XWPFFooter extends XWPFHeaderFooter { super._getHdrFtr().save(out, xmlOptions); out.close(); } - - @Override - protected void onDocumentRead(){ - bodyElements = new ArrayList<IBodyElement>(); - paragraphs = new ArrayList<XWPFParagraph>(); - tables= new ArrayList<XWPFTable>(); - 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); - } - } - cursor.dispose(); - 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() - */ - public IBody getPart() { - return this; - } - /** - * get the PartType of the body - * @see org.apache.poi.xwpf.usermodel.IBody#getPartType() - */ - public BodyType getPartType() { - return BodyType.FOOTER; - } + @Override + protected void onDocumentRead() throws IOException{ + super.onDocumentRead(); + 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); + } + } + cursor.dispose(); + } catch (Exception e) { + throw new POIXMLException(e); + } + } + + /** + * get the PartType of the body + * @see org.apache.poi.xwpf.usermodel.IBody#getPartType() + */ + public BodyType getPartType() { + return BodyType.FOOTER; + } } 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 6ccbf46241..f18e0c7bd2 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeader.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeader.java @@ -19,13 +19,13 @@ 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.POIXMLException; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.xmlbeans.XmlCursor; @@ -47,40 +47,31 @@ public class XWPFHeader extends XWPFHeaderFooter { } public XWPFHeader(POIXMLDocumentPart parent, PackagePart part, PackageRelationship rel) throws IOException { - super(parent, part, rel); - } - - public XWPFHeader(XWPFDocument doc, CTHdrFtr hdrFtr) throws IOException { - super(doc, hdrFtr); - paragraphs = new ArrayList<XWPFParagraph>(); - tables = new ArrayList<XWPFTable>(); - 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); - } - } + super(parent, part, rel); + } + + public XWPFHeader(XWPFDocument doc, CTHdrFtr hdrFtr) { + super(doc, hdrFtr); + 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); + } + } cursor.dispose(); - getAllPictures(); - } + } /** - public XWPFHeader(PackagePart part, PackageRelationship rel) - throws IOException { - super(part, rel); - } - - /** - * save and commit footer - */ - @Override + * 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")); @@ -101,62 +92,47 @@ public class XWPFHeader extends XWPFHeaderFooter { out.close(); } - /** - * reads the document - */ - @Override - protected void onDocumentRead(){ - bodyElements = new ArrayList<IBodyElement>(); - paragraphs = new ArrayList<XWPFParagraph>(); - tables= new ArrayList<XWPFTable>(); - 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); - } - } - cursor.dispose(); - } 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() - */ - public IBody getPart() { - return this; - } - - /** - * get the PartType of the body - * @see org.apache.poi.xwpf.usermodel.IBody#getPartType() - */ - public BodyType getPartType() { - return BodyType.HEADER; - } - + /** + * reads the document + * @throws IOException + */ + @Override + protected void onDocumentRead() throws IOException { + super.onDocumentRead(); + 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); + } + } + cursor.dispose(); + } catch (XmlException e) { + throw new POIXMLException(e); + } + } + /** + * get the PartType of the body + * @see org.apache.poi.xwpf.usermodel.IBody#getPartType() + */ + 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 96274be21a..482994b128 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeaderFooter.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFHeaderFooter.java @@ -25,11 +25,12 @@ import java.util.List; import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.POIXMLException; +import org.apache.poi.POIXMLRelation; 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.openxml4j.opc.TargetMode; import org.apache.poi.util.IOUtils; import org.apache.poi.util.Internal; import org.apache.xmlbeans.XmlCursor; @@ -43,254 +44,264 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc; /** * Parent of XWPF headers and footers */ -public abstract class XWPFHeaderFooter extends POIXMLDocumentPart implements IBody{ - protected CTHdrFtr headerFooter; - protected List<XWPFParagraph> paragraphs; - protected List<XWPFTable> tables; - protected List<XWPFPictureData> pictures; - protected XWPFDocument document; - protected List<IBodyElement> bodyElements; - - protected XWPFHeaderFooter(XWPFDocument doc, CTHdrFtr hdrFtr){ +public abstract class XWPFHeaderFooter extends POIXMLDocumentPart implements IBody { + List<XWPFParagraph> paragraphs = new ArrayList<XWPFParagraph>(1); + List<XWPFTable> tables= new ArrayList<XWPFTable>(1); + List<XWPFPictureData> pictures = new ArrayList<XWPFPictureData>(); + List<IBodyElement> bodyElements = new ArrayList<IBodyElement>(1); + + CTHdrFtr headerFooter; + XWPFDocument document; + + XWPFHeaderFooter(XWPFDocument doc, CTHdrFtr hdrFtr){ if (doc==null) { throw new NullPointerException(); } document = doc; - headerFooter = hdrFtr; - readHdrFtr(); - } + headerFooter = hdrFtr; + readHdrFtr(); + } protected XWPFHeaderFooter() { headerFooter = CTHdrFtr.Factory.newInstance(); readHdrFtr(); } - public XWPFHeaderFooter(POIXMLDocumentPart parent, PackagePart part, PackageRelationship rel) throws IOException { - super(parent, part, rel); - this.document = (XWPFDocument)getParent(); + super(parent, part, rel); + this.document = (XWPFDocument)getParent(); if (this.document==null) { throw new NullPointerException(); } + } + + @Override + protected void onDocumentRead() throws IOException { + for (POIXMLDocumentPart poixmlDocumentPart : getRelations()){ + if(poixmlDocumentPart instanceof XWPFPictureData){ + XWPFPictureData xwpfPicData = (XWPFPictureData) poixmlDocumentPart; + pictures.add(xwpfPicData); + document.registerPackagePictureData(xwpfPicData); + } + } + } - onDocumentRead(); - } - @Internal - public CTHdrFtr _getHdrFtr() { - return headerFooter; - } + public CTHdrFtr _getHdrFtr() { + return headerFooter; + } - public List<IBodyElement> getBodyElements(){ + public List<IBodyElement> getBodyElements(){ return Collections.unmodifiableList(bodyElements); - } - - /** - * Returns the paragraph(s) that holds - * the text of the header or footer. - * Normally there is only the one paragraph, but - * there could be more in certain cases, or - * a table. - */ + } + + /** + * Returns the paragraph(s) that holds + * the text of the header or footer. + * Normally there is only the one paragraph, but + * there could be more in certain cases, or + * a table. + */ public List<XWPFParagraph> getParagraphs() { return Collections.unmodifiableList(paragraphs); } - - - /** - * Return the table(s) that holds the text - * of the header or footer, for complex cases - * where a paragraph isn't used. - * Normally there's just one paragraph, but some - * complex headers/footers have a table or two - * in addition. - */ - public List<XWPFTable> getTables()throws ArrayIndexOutOfBoundsException { - return Collections.unmodifiableList(tables); + + + /** + * Return the table(s) that holds the text + * of the header or footer, for complex cases + * where a paragraph isn't used. + * Normally there's just one paragraph, but some + * complex headers/footers have a table or two + * in addition. + */ + public List<XWPFTable> getTables()throws ArrayIndexOutOfBoundsException { + return Collections.unmodifiableList(tables); + } + + + + /** + * Returns the textual content of the header/footer, + * by flattening out the text of its paragraph(s) + */ + public String getText() { + StringBuffer t = new StringBuffer(); + + for(int i=0; i<paragraphs.size(); i++) { + if(! paragraphs.get(i).isEmpty()) { + String text = paragraphs.get(i).getText(); + if(text != null && text.length() > 0) { + t.append(text); + t.append('\n'); + } + } + } + + List<XWPFTable> tables = getTables(); + for(int i=0; i<tables.size(); i++) { + String text = tables.get(i).getText(); + if(text != null && text.length() > 0) { + t.append(text); + t.append('\n'); + } + } + + 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 + */ + 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<XWPFParagraph> getListParagraph(){ + return paragraphs; } - - - - /** - * Returns the textual content of the header/footer, - * by flattening out the text of its paragraph(s) - */ - public String getText() { - StringBuffer t = new StringBuffer(); - - for(int i=0; i<paragraphs.size(); i++) { - if(! paragraphs.get(i).isEmpty()) { - String text = paragraphs.get(i).getText(); - if(text != null && text.length() > 0) { - t.append(text); - t.append('\n'); - } - } - } - - List<XWPFTable> tables = getTables(); - for(int i=0; i<tables.size(); i++) { - String text = tables.get(i).getText(); - if(text != null && text.length() > 0) { - t.append(text); - t.append('\n'); - } - } - - 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 - */ - 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<XWPFParagraph> getListParagraph(){ - return paragraphs; - } - + public List<XWPFPictureData> getAllPictures() { - if(pictures == null){ - pictures = new ArrayList<XWPFPictureData>(); - for (POIXMLDocumentPart poixmlDocumentPart : getRelations()){ - if(poixmlDocumentPart instanceof XWPFPictureData){ - pictures.add((XWPFPictureData)poixmlDocumentPart); - } - } - } - return pictures; + return Collections.unmodifiableList(pictures); } - + /** * get all Pictures in this package * @return all Pictures in this package */ public List<XWPFPictureData> getAllPackagePictures(){ - List<XWPFPictureData> pkgpictures = new ArrayList<XWPFPictureData>(); - pkgpictures.addAll(getAllPictures()); - for (POIXMLDocumentPart poixmlDocumentPart : getRelations()){ - if(poixmlDocumentPart instanceof XWPFHeaderFooter){ - pkgpictures.addAll(((XWPFHeaderFooter)poixmlDocumentPart).getAllPictures()); - } - } - return pkgpictures; + return document.getAllPackagePictures(); + } - - /** + + /** * 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 { - 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; - + public String addPictureData(byte[] pictureData,int format) throws InvalidFormatException + { + XWPFPictureData xwpfPicData = document.findPackagePictureData(pictureData, format); + POIXMLRelation relDesc = XWPFPictureData.RELATIONS[format]; + + if (xwpfPicData == null) + { + /* Part doesn't exist, create a new one */ + int idx = document.getNextPicNameNumber(format); + xwpfPicData = (XWPFPictureData) createRelationship(relDesc, XWPFFactory.getInstance(),idx); + /* write bytes to new part */ + PackagePart picDataPart = xwpfPicData.getPackagePart(); + OutputStream out = null; + try { + out = picDataPart.getOutputStream(); + out.write(pictureData); + } catch (IOException e) { + throw new POIXMLException(e); + } finally { + try { + out.close(); + } catch (IOException e) { + // ignore + } + } + + document.registerPackagePictureData(xwpfPicData); + pictures.add(xwpfPicData); + return getRelationId(xwpfPicData); + } + else if (!getRelations().contains(xwpfPicData)) + { + /* + * Part already existed, but was not related so far. Create + * relationship to the already existing part and update + * POIXMLDocumentPart data. + */ + PackagePart picDataPart = xwpfPicData.getPackagePart(); + // TODO add support for TargetMode.EXTERNAL relations. + TargetMode targetMode = TargetMode.INTERNAL; + PackagePartName partName = picDataPart.getPartName(); + String relation = relDesc.getRelation(); + PackageRelationship relShip = getPackagePart().addRelationship(partName,targetMode,relation); + String id = relShip.getId(); + addRelation(id,xwpfPicData); + pictures.add(xwpfPicData); + return id; + } + else + { + /* Part already existed, get relation id and return it */ + return getRelationId(xwpfPicData); + } } - + /** * Adds a picture to the document. * - * @param pictureData The picture bytes + * @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 + * @throws IOException */ - 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 the next free ImageNumber - */ - 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; + public String addPictureData(InputStream is, int format) throws InvalidFormatException,IOException { + byte[] data = IOUtils.toByteArray(is); + return addPictureData(data,format); } - + /** * returns the PictureData by blipID * @param blipID @@ -298,246 +309,195 @@ public abstract class XWPFHeaderFooter extends POIXMLDocumentPart implements IBo * @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; + POIXMLDocumentPart relatedPart = getRelationById(blipID); + if (relatedPart != null && relatedPart instanceof XWPFPictureData) { + return (XWPFPictureData) relatedPart; + } + return null; } - + /** - * Add the picture to drawing relations - * - * @param pictureData the picture bytes - * @param format the picture format + * add a new paragraph at position of the cursor + * @param cursor + * @return the inserted paragraph + */ + 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 the inserted table + */ + 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 */ - 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; + 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) + */ + 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 pos + * @param table + */ + public void insertTable(int pos, XWPFTable table) { + bodyElements.add(pos, table); + int i; + for (i = 0; i < headerFooter.getTblList().size(); i++) { + CTTbl tbl = headerFooter.getTblArray(i); + if(tbl == table.getCTTbl()){ + break; + } + } + tables.add(i, table); + } - - /** - * Add the picture to drawing relations - * - * @param is the stream to read picture data from - */ - 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 the inserted paragraph - */ - 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 the inserted table - */ - 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 - */ - 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) - */ - 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 pos - * @param table - */ - public void insertTable(int pos, XWPFTable table) { - bodyElements.add(pos, table); - int i; - for (i = 0; i < headerFooter.getTblList().size(); i++) { - CTTbl tbl = headerFooter.getTblArray(i); - if(tbl == table.getCTTbl()){ - break; - } - } - tables.add(i, table); - - } - - public void readHdrFtr(){ - bodyElements = new ArrayList<IBodyElement>(); + + public void readHdrFtr(){ + bodyElements = new ArrayList<IBodyElement>(); paragraphs = new ArrayList<XWPFParagraph>(); tables= new ArrayList<XWPFTable>(); // parse the document with cursor and add // the XmlObject to its lists - XmlCursor cursor = headerFooter.newCursor(); + 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); + 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); + XWPFTable t = new XWPFTable((CTTbl)o, this); + tables.add(t); + bodyElements.add(t); } } cursor.dispose(); - getAllPictures(); - } - - /** - * get the TableCell which belongs to the TableCell - * @param cell - */ - 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(); + } + + /** + * get the TableCell which belongs to the TableCell + * @param cell + */ + 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(); cursor.dispose(); - 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); - } - + 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); + } + public XWPFDocument getXWPFDocument() { if (document!=null) { return document; @@ -545,4 +505,12 @@ public abstract class XWPFHeaderFooter extends POIXMLDocumentPart implements IBo return (XWPFDocument)getParent(); } } + + /** + * 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() + */ + public POIXMLDocumentPart getPart() { + return this; + } }//end class diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java index 9e4fc7d08b..861b07409b 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFNumbering.java @@ -44,10 +44,11 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.NumberingDocument; * */ public class XWPFNumbering extends POIXMLDocumentPart { - private CTNumbering ctNumbering; - protected List<XWPFAbstractNum> abstractNums; - protected List<XWPFNum> nums; - protected boolean isNew; + protected List<XWPFAbstractNum> abstractNums = new ArrayList<XWPFAbstractNum>(); + protected List<XWPFNum> nums = new ArrayList<XWPFNum>(); + + private CTNumbering ctNumbering; + boolean isNew; /** *create a new styles object with an existing document @@ -55,7 +56,6 @@ public class XWPFNumbering extends POIXMLDocumentPart { public XWPFNumbering(PackagePart part, PackageRelationship rel) throws IOException, OpenXML4JException{ super(part, rel); isNew = true; - onDocumentRead(); } /** @@ -72,8 +72,6 @@ public class XWPFNumbering extends POIXMLDocumentPart { */ @Override protected void onDocumentRead() throws IOException{ - abstractNums = new ArrayList<XWPFAbstractNum>(); - nums = new ArrayList<XWPFNum>(); NumberingDocument numberingDoc = null; InputStream is; is = getPackagePart().getInputStream(); @@ -100,7 +98,7 @@ public class XWPFNumbering extends POIXMLDocumentPart { 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<String,String> map = new HashMap<String,String>(); 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"); diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java index c46b8da750..4cbb8223e9 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java @@ -21,6 +21,7 @@ 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.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlObject; @@ -50,17 +51,16 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.STLineSpacingRule; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTextAlignment; - /** * Sketch of XWPF paragraph class */ -public class XWPFParagraph implements IBodyElement{ +public class XWPFParagraph implements IBodyElement { private final CTP paragraph; protected IBody part; /** For access to the document's hyperlink, comments, tables etc */ protected XWPFDocument document; protected List<XWPFRun> runs; - + private StringBuffer footnoteText = new StringBuffer(); public XWPFParagraph(CTP prgrph, IBody part) { @@ -260,9 +260,9 @@ public class XWPFParagraph implements IBodyElement{ * @return a new text run */ public XWPFRun createRun() { - XWPFRun run = new XWPFRun(paragraph.addNewR(), this); - runs.add(run); - return run; + XWPFRun xwpfRun = new XWPFRun(paragraph.addNewR(), this); + runs.add(xwpfRun); + return xwpfRun; } /** @@ -1233,53 +1233,65 @@ public class XWPFParagraph implements IBodyElement{ return false; } - /** - * returns the type of the BodyElement Paragraph - * @see org.apache.poi.xwpf.usermodel.IBodyElement#getElementType() - */ - public BodyElementType getElementType() { - return BodyElementType.PARAGRAPH; - } - - /** - * returns the part of the bodyElement - * @see org.apache.poi.xwpf.usermodel.IBody#getPart() - */ - public IBody getPart() { - if(part != null){ - return part.getPart(); - } - return null; - } + /** + * returns the type of the BodyElement Paragraph + * @see org.apache.poi.xwpf.usermodel.IBodyElement#getElementType() + */ + public BodyElementType getElementType() { + return BodyElementType.PARAGRAPH; + } - /** - * returns the partType of the bodyPart which owns the bodyElement - * @see org.apache.poi.xwpf.usermodel.IBody#getPartType() - */ - public BodyType getPartType() { - return part.getPartType(); - } - - /** - * adds a new Run to the Paragraph - */ - public void addRun(XWPFRun r){ - runs.add(r); - } - - /** - * return the XWPFRun-Element which owns the CTR run-Element - */ - 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; - } - + @Override + public IBody getBody() + { + return part; + } + /** + * returns the part of the bodyElement + * @see org.apache.poi.xwpf.usermodel.IBody#getPart() + */ + public POIXMLDocumentPart getPart() { + if(part != null){ + return part.getPart(); + } + return null; + } -}//end class + /** + * returns the partType of the bodyPart which owns the bodyElement + * + * @see org.apache.poi.xwpf.usermodel.IBody#getPartType() + */ + public BodyType getPartType() { + return part.getPartType(); + } + /** + * adds a new Run to the Paragraph + * + * @param r + * @return + */ + public void addRun(XWPFRun r) { + if (!runs.contains(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
\ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPicture.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPicture.java index af207c651d..d613030f88 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPicture.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPicture.java @@ -25,28 +25,25 @@ import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture; * @author Philipp Epp */ public class XWPFPicture { - protected XWPFParagraph paragraph; - private CTPicture ctPic; + + private CTPicture ctPic; private String description; + private XWPFRun run; + + public XWPFPicture(CTPicture ctPic, XWPFRun run){ + this.run = run; + this.ctPic = ctPic; + description = ctPic.getNvPicPr().getCNvPr().getDescr(); + } + + /** + * Link Picture with PictureData + * @param rel + */ + public void setPictureReference(PackageRelationship rel){ + ctPic.getBlipFill().getBlip().setEmbed(rel.getId()); + } - public XWPFParagraph getParagraph(){ - return paragraph; - } - - public XWPFPicture(CTPicture ctPic, XWPFParagraph paragraph){ - this.paragraph = paragraph; - this.ctPic = ctPic; - description = ctPic.getNvPicPr().getCNvPr().getDescr(); - } - - /** - * 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 * @@ -55,19 +52,22 @@ public class XWPFPicture { public CTPicture getCTPicture(){ return ctPic; } - + /** * Get the PictureData of the Picture, if present. * Note - not all kinds of picture have data */ public XWPFPictureData getPictureData(){ - String blipId = ctPic.getBlipFill().getBlip().getEmbed(); - for(POIXMLDocumentPart part: ((POIXMLDocumentPart) paragraph.getPart()).getRelations()){ - if(part.getPackageRelationship().getId().equals(blipId)){ - return (XWPFPictureData)part; - } - } - return null; + String blipId = ctPic.getBlipFill().getBlip().getEmbed(); + POIXMLDocumentPart part = run.getParagraph().getPart(); + if (part != null) + { + POIXMLDocumentPart relatedPart = part.getRelationById(blipId); + if (relatedPart instanceof XWPFPictureData) { + return (XWPFPictureData) relatedPart; + } + } + return null; } public String getDescription() { diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPictureData.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPictureData.java index aee464e0e3..6671438417 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPictureData.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFPictureData.java @@ -18,9 +18,13 @@ package org.apache.poi.xwpf.usermodel; import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.POIXMLException; import org.apache.poi.POIXMLRelation; +import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.util.IOUtils; @@ -32,29 +36,31 @@ import org.apache.poi.util.IOUtils; /** * @author Philipp Epp - * */ public class XWPFPictureData extends POIXMLDocumentPart { - + /** * Relationships for each known picture type */ protected static final POIXMLRelation[] RELATIONS; static { RELATIONS = new POIXMLRelation[9]; - RELATIONS[Document.PICTURE_TYPE_EMF] = XWPFRelation.IMAGE_EMF; - RELATIONS[Document.PICTURE_TYPE_WMF] = XWPFRelation.IMAGE_WMF; + 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; - RELATIONS[Document.PICTURE_TYPE_GIF] = XWPFRelation.IMAGE_GIF; + RELATIONS[Document.PICTURE_TYPE_PNG] = XWPFRelation.IMAGE_PNG; + RELATIONS[Document.PICTURE_TYPE_DIB] = XWPFRelation.IMAGE_DIB; + RELATIONS[Document.PICTURE_TYPE_GIF] = XWPFRelation.IMAGE_GIF; } + + private Long checksum = null; + /** * Create a new XWPFGraphicData node * */ - protected XWPFPictureData() { + protected XWPFPictureData() { super(); } @@ -65,11 +71,15 @@ public class XWPFPictureData extends POIXMLDocumentPart { * @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) { + public XWPFPictureData(PackagePart part, PackageRelationship rel) { super(part, rel); } - + + @Override + protected void onDocumentRead() throws IOException { + super.onDocumentRead(); + } + /** * Gets the picture data as a byte array. * <p> @@ -80,44 +90,40 @@ public class XWPFPictureData extends POIXMLDocumentPart { * InputStream is = getPackagePart().getInputStream(); * </code> * </p> - * * @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; + try { + return IOUtils.toByteArray(getPackagePart().getInputStream()); + } catch (IOException e) { + throw new POIXMLException(e); + } } - + /** - * Returns the file name of the image, eg image7.jpg . - * The original filename isn't always available, but if it - * can be found it's likely to be in the CTDrawing + * Returns the file name of the image, eg image7.jpg . The original filename + * isn't always available, but if it can be found it's likely to be in the + * CTDrawing */ public String getFileName() { - String name = getPackagePart().getPartName().getName(); - if(name == null) - return null; - return name.substring(name.lastIndexOf('/') + 1); + String name = getPackagePart().getPartName().getName(); + if (name == null) + return null; + return name.substring(name.lastIndexOf('/') + 1); } - + /** * 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 + * + * @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 @@ -125,15 +131,103 @@ public class XWPFPictureData extends POIXMLDocumentPart { * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_PNG * @see org.apache.poi.xwpf.usermodel.Document#PICTURE_TYPE_DIB */ - public int getPictureType(){ + public int getPictureType() { String contentType = getPackagePart().getContentType(); for (int i = 0; i < RELATIONS.length; i++) { - if(RELATIONS[i] == null) continue; + if (RELATIONS[i] == null) { + continue; + } - if(RELATIONS[i].getContentType().equals(contentType)){ + if (RELATIONS[i].getContentType().equals(contentType)) { return i; } } return 0; } + + public Long getChecksum() { + if (this.checksum == null) { + InputStream is = null; + byte[] data; + try { + is = getPackagePart().getInputStream(); + data = IOUtils.toByteArray(is); + } catch (IOException e) { + throw new POIXMLException(e); + } finally { + try { + is.close(); + } catch (IOException e) { + throw new POIXMLException(e); + } + } + this.checksum = IOUtils.calculateChecksum(data); + } + return this.checksum; + } + + @Override + public boolean equals(Object obj) { + /** + * In case two objects ARE equal, but its not the same instance, this + * implementation will always run through the whole + * byte-array-comparison before returning true. If this will turn into a + * performance issue, two possible approaches are available:<br> + * a) Use the checksum only and take the risk that two images might have + * the same CRC32 sum, although they are not the same.<br> + * b) Use a second (or third) checksum algorithm to minimise the chance + * that two images have the same checksums but are not equal (e.g. + * CRC32, MD5 and SHA-1 checksums, additionally compare the + * data-byte-array lengths). + */ + if (obj == this) { + return true; + } + + if (obj == null) { + return false; + } + + if (!(obj instanceof XWPFPictureData)) { + return false; + } + + XWPFPictureData picData = (XWPFPictureData) obj; + PackagePart foreignPackagePart = picData.getPackagePart(); + PackagePart ownPackagePart = this.getPackagePart(); + + if ((foreignPackagePart != null && ownPackagePart == null) + || (foreignPackagePart == null && ownPackagePart != null)) { + return false; + } + + if (ownPackagePart != null) { + OPCPackage foreignPackage = foreignPackagePart.getPackage(); + OPCPackage ownPackage = ownPackagePart.getPackage(); + + if ((foreignPackage != null && ownPackage == null) + || (foreignPackage == null && ownPackage != null)) { + return false; + } + if (ownPackage != null) { + + if (!ownPackage.equals(foreignPackage)) { + return false; + } + } + } + + Long foreignChecksum = picData.getChecksum(); + Long localChecksum = getChecksum(); + + if (!(localChecksum.equals(foreignChecksum))) { + return false; + } + return Arrays.equals(this.getData(), picData.getData()); + } + + @Override + public int hashCode() { + return getChecksum().hashCode(); + } } 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 a08823c195..4e905ec6af 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java @@ -45,6 +45,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D; import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D; import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType; +import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor; import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing; @@ -87,56 +88,75 @@ public class XWPFRun { public XWPFRun(CTR r, XWPFParagraph p) { this.run = r; this.paragraph = p; - + + /** + * reserve already occupied drawing ids, so reserving new ids later will + * not corrupt the document + */ + List<CTDrawing> drawingList = r.getDrawingList(); + for (CTDrawing ctDrawing : drawingList) { + List<CTAnchor> anchorList = ctDrawing.getAnchorList(); + for (CTAnchor anchor : anchorList) { + if (anchor.getDocPr() != null) { + getDocument().getDrawingIdManager().reserve(anchor.getDocPr().getId()); + } + } + List<CTInline> inlineList = ctDrawing.getInlineList(); + for (CTInline inline : inlineList) { + if (inline.getDocPr() != null) { + getDocument().getDrawingIdManager().reserve(inline.getDocPr().getId()); + } + } + } + // Look for any text in any of our pictures or drawings StringBuffer text = new StringBuffer(); List<XmlObject> pictTextObjs = new ArrayList<XmlObject>(); pictTextObjs.addAll(r.getPictList()); - pictTextObjs.addAll(r.getDrawingList()); + pictTextObjs.addAll(drawingList); for(XmlObject o : pictTextObjs) { - XmlObject[] t = o - .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) { - if(text.length() > 0) - text.append("\n"); - text.append(kids.item(n).getNodeValue()); - } - } - } + XmlObject[] t = o.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) { + if(text.length() > 0) + text.append("\n"); + text.append(kids.item(n).getNodeValue()); + } + } + } } pictureText = text.toString(); - + // Do we have any embedded pictures? // (They're a different CTPicture, under the drawingml namespace) pictures = new ArrayList<XWPFPicture>(); for(XmlObject o : pictTextObjs) { - for(CTPicture pict : getCTPictures(o)) { - XWPFPicture picture = new XWPFPicture( pict, p ); - pictures.add(picture); - } + for(CTPicture pict : getCTPictures(o)) { + XWPFPicture picture = new XWPFPicture(pict, this); + pictures.add(picture); + } } } - + private List<CTPicture> getCTPictures(XmlObject o) { - List<CTPicture> pictures = new ArrayList<CTPicture>(); - XmlObject[] picts = o.selectPath("declare namespace pic='"+CTPicture.type.getName().getNamespaceURI()+"' .//pic:pic"); - for(XmlObject pict : picts) { - if(pict instanceof XmlAnyTypeImpl) { - // Pesky XmlBeans bug - see Bugzilla #49934 - try { - pict = CTPicture.Factory.parse( pict.toString() ); - } catch(XmlException e) { - throw new POIXMLException(e); - } - } - if(pict instanceof CTPicture) { - pictures.add((CTPicture)pict); - } - } - return pictures; + List<CTPicture> pictures = new ArrayList<CTPicture>(); + XmlObject[] picts = o.selectPath("declare namespace pic='"+CTPicture.type.getName().getNamespaceURI()+"' .//pic:pic"); + for(XmlObject pict : picts) { + if(pict instanceof XmlAnyTypeImpl) { + // Pesky XmlBeans bug - see Bugzilla #49934 + try { + pict = CTPicture.Factory.parse( pict.toString() ); + } catch(XmlException e) { + throw new POIXMLException(e); + } + } + if(pict instanceof CTPicture) { + pictures.add((CTPicture)pict); + } + } + return pictures; } /** @@ -155,18 +175,29 @@ public class XWPFRun { public XWPFParagraph getParagraph() { return paragraph; } - + + /** + * @return The {@link XWPFDocument} instance, this run belongs to, or + * <code>null</code> if parent structure (paragraph > document) is not properly set. + */ + public XWPFDocument getDocument() { + if (paragraph != null) { + return paragraph.getDocument(); + } + return null; + } + /** * For isBold, isItalic etc */ private boolean isCTOnOff(CTOnOff onoff) { - if(! onoff.isSetVal()) - return true; - if(onoff.getVal() == STOnOff.ON) - return true; - if(onoff.getVal() == STOnOff.TRUE) - return true; - return false; + if(! onoff.isSetVal()) + return true; + if(onoff.getVal() == STOnOff.ON) + return true; + if(onoff.getVal() == STOnOff.TRUE) + return true; + return false; } /** @@ -177,8 +208,9 @@ public class XWPFRun { */ public boolean isBold() { CTRPr pr = run.getRPr(); - if(pr == null || !pr.isSetB()) - return false; + if(pr == null || !pr.isSetB()) { + return false; + } return isCTOnOff(pr.getB()); } @@ -221,7 +253,7 @@ public class XWPFRun { return run.sizeOfTArray() == 0 ? null : run.getTArray(pos) .getStringValue(); } - + /** * Returns text embedded in pictures */ @@ -235,7 +267,7 @@ public class XWPFRun { * @param value the literal text which shall be displayed in the document */ public void setText(String value) { - setText(value,run.getTList().size()); + setText(value,run.getTList().size()); } /** @@ -245,13 +277,12 @@ public class XWPFRun { * @param pos - position in the text array (NB: 0 based) */ public void setText(String value, int pos) { - if(pos > run.sizeOfTArray()) throw new ArrayIndexOutOfBoundsException("Value too large for the parameter position in XWPFRun.setText(String value,int pos)"); + if(pos > run.sizeOfTArray()) throw new ArrayIndexOutOfBoundsException("Value too large for the parameter position in XWPFRun.setText(String value,int pos)"); CTText t = (pos < run.sizeOfTArray() && pos >= 0) ? run.getTArray(pos) : run.addNewT(); t.setStringValue(value); preserveSpaces(t); } - /** * Whether the italic property should be applied to all non-complex script * characters in the contents of this run when displayed in a document. @@ -261,7 +292,7 @@ public class XWPFRun { public boolean isItalic() { CTRPr pr = run.getRPr(); if(pr == null || !pr.isSetI()) - return false; + return false; return isCTOnOff(pr.getI()); } @@ -306,7 +337,7 @@ public class XWPFRun { public UnderlinePatterns getUnderline() { CTRPr pr = run.getRPr(); return (pr != null && pr.isSetU()) ? UnderlinePatterns.valueOf(pr - .getU().getVal().intValue()) : UnderlinePatterns.NONE; + .getU().getVal().intValue()) : UnderlinePatterns.NONE; } /** @@ -339,7 +370,7 @@ public class XWPFRun { public boolean isStrike() { CTRPr pr = run.getRPr(); if(pr == null || !pr.isSetStrike()) - return false; + return false; return isCTOnOff(pr.getStrike()); } @@ -384,8 +415,7 @@ public class XWPFRun { */ public VerticalAlign getSubscript() { CTRPr pr = run.getRPr(); - return (pr != null && pr.isSetVertAlign()) ? VerticalAlign.valueOf(pr - .getVertAlign().getVal().intValue()) : VerticalAlign.BASELINE; + return (pr != null && pr.isSetVertAlign()) ? VerticalAlign.valueOf(pr.getVertAlign().getVal().intValue()) : VerticalAlign.BASELINE; } /** @@ -460,7 +490,7 @@ public class XWPFRun { * @param size */ public void setFontSize(int size) { - BigInteger bint=new BigInteger(""+size); + BigInteger bint=new BigInteger(""+size); CTRPr pr = run.isSetRPr() ? run.getRPr() : run.addNewRPr(); CTHpsMeasure ctSize = pr.isSetSz() ? pr.getSz() : pr.addNewSz(); ctSize.setVal(bint.multiply(new BigInteger("2"))); @@ -503,7 +533,7 @@ public class XWPFRun { * @param val */ public void setTextPosition(int val) { - BigInteger bint=new BigInteger(""+val); + BigInteger bint=new BigInteger(""+val); CTRPr pr = run.isSetRPr() ? run.getRPr() : run.addNewRPr(); CTSignedHpsMeasure position = pr.isSetPosition() ? pr.getPosition() : pr.addNewPosition(); position.setVal(bint); @@ -513,7 +543,7 @@ public class XWPFRun { * */ public void removeBreak() { - // TODO + // TODO } /** @@ -525,7 +555,7 @@ public class XWPFRun { * @see #addCarriageReturn() */ public void addBreak() { - run.addNewBr(); + run.addNewBr(); } /** @@ -542,11 +572,10 @@ public class XWPFRun { * @see BreakType */ public void addBreak(BreakType type){ - CTBr br=run.addNewBr(); - br.setType(STBrType.Enum.forInt(type.getValue())); + CTBr br=run.addNewBr(); + br.setType(STBrType.Enum.forInt(type.getValue())); } - /** * Specifies that a break shall be placed at the current location in the run * content. A break is a special character which is used to override the @@ -560,9 +589,9 @@ public class XWPFRun { * @see BreakClear */ public void addBreak(BreakClear clear){ - CTBr br=run.addNewBr(); - br.setType(STBrType.Enum.forInt(BreakType.TEXT_WRAPPING.getValue())); - br.setClear(STBrClear.Enum.forInt(clear.getValue())); + CTBr br=run.addNewBr(); + br.setType(STBrType.Enum.forInt(BreakType.TEXT_WRAPPING.getValue())); + br.setClear(STBrClear.Enum.forInt(clear.getValue())); } /** @@ -578,13 +607,13 @@ public class XWPFRun { * restarted on the next available line in the document. */ public void addCarriageReturn() { - run.addNewCr(); + run.addNewCr(); } public void removeCarriageReturn() { - //TODO - } - + //TODO + } + /** * Adds a picture to the run. This method handles * attaching the picture data to the overall file. @@ -598,100 +627,104 @@ public class XWPFRun { * * @param pictureData The raw picture data * @param pictureType The type of the picture, eg {@link Document#PICTURE_TYPE_JPEG} - * @throws IOException - * @throws org.apache.poi.openxml4j.exceptions.InvalidFormatException - * @throws IOException + * @throws IOException + * @throws org.apache.poi.openxml4j.exceptions.InvalidFormatException + * @throws IOException */ public XWPFPicture addPicture(InputStream pictureData, int pictureType, String filename, int width, int height) throws InvalidFormatException, IOException { - XWPFDocument doc = paragraph.document; - - // Add the picture + relationship - int picNumber = doc.addPicture(pictureData, pictureType); - XWPFPictureData picData = doc.getAllPackagePictures().get(picNumber); - - // Create the drawing entry for it - try { - CTDrawing drawing = run.addNewDrawing(); - CTInline inline = drawing.addNewInline(); - - // Do the fiddly namespace bits on the inline - // (We need full control of what goes where and as what) - String xml = - "<a:graphic xmlns:a=\"" + CTGraphicalObject.type.getName().getNamespaceURI() + "\">" + - "<a:graphicData uri=\"" + CTGraphicalObject.type.getName().getNamespaceURI() + "\">" + - "<pic:pic xmlns:pic=\"" + CTPicture.type.getName().getNamespaceURI() + "\" />" + - "</a:graphicData>" + - "</a:graphic>"; - inline.set(XmlToken.Factory.parse(xml)); - - // Setup the inline - inline.setDistT(0); - inline.setDistR(0); - inline.setDistB(0); - inline.setDistL(0); - - CTNonVisualDrawingProps docPr = inline.addNewDocPr(); - docPr.setId(picNumber); - docPr.setName("Picture " + picNumber); - docPr.setDescr(filename); - - CTPositiveSize2D extent = inline.addNewExtent(); - extent.setCx(width); - extent.setCy(height); - - // Grab the picture object - CTGraphicalObject graphic = inline.getGraphic(); - CTGraphicalObjectData graphicData = graphic.getGraphicData(); - CTPicture pic = getCTPictures(graphicData).get(0); - - // Set it up - CTPictureNonVisual nvPicPr = pic.addNewNvPicPr(); - - CTNonVisualDrawingProps cNvPr = nvPicPr.addNewCNvPr(); - cNvPr.setId(picNumber); - cNvPr.setName("Picture " + picNumber); - cNvPr.setDescr(filename); - - CTNonVisualPictureProperties cNvPicPr = nvPicPr.addNewCNvPicPr(); - cNvPicPr.addNewPicLocks().setNoChangeAspect(true); - - CTBlipFillProperties blipFill = pic.addNewBlipFill(); - CTBlip blip = blipFill.addNewBlip(); - blip.setEmbed( picData.getPackageRelationship().getId() ); - blipFill.addNewStretch().addNewFillRect(); - - CTShapeProperties spPr = pic.addNewSpPr(); - CTTransform2D xfrm = spPr.addNewXfrm(); - - CTPoint2D off = xfrm.addNewOff(); - off.setX(0); - off.setY(0); - - CTPositiveSize2D ext = xfrm.addNewExt(); - ext.setCx(width); - ext.setCy(height); - - CTPresetGeometry2D prstGeom = spPr.addNewPrstGeom(); - prstGeom.setPrst(STShapeType.RECT); - prstGeom.addNewAvLst(); - - // Finish up - XWPFPicture xwpfPicture = new XWPFPicture(pic, paragraph); - pictures.add(xwpfPicture); - return xwpfPicture; - } catch(XmlException e) { - throw new IllegalStateException(e); - } - } - + XWPFDocument doc = paragraph.document; + + // Add the picture + relationship + String relationId = doc.addPictureData(pictureData, pictureType); + XWPFPictureData picData = (XWPFPictureData) doc.getRelationById(relationId); + + // Create the drawing entry for it + try { + CTDrawing drawing = run.addNewDrawing(); + CTInline inline = drawing.addNewInline(); + + // Do the fiddly namespace bits on the inline + // (We need full control of what goes where and as what) + String xml = + "<a:graphic xmlns:a=\"" + CTGraphicalObject.type.getName().getNamespaceURI() + "\">" + + "<a:graphicData uri=\"" + CTGraphicalObject.type.getName().getNamespaceURI() + "\">" + + "<pic:pic xmlns:pic=\"" + CTPicture.type.getName().getNamespaceURI() + "\" />" + + "</a:graphicData>" + + "</a:graphic>"; + inline.set(XmlToken.Factory.parse(xml)); + + // Setup the inline + inline.setDistT(0); + inline.setDistR(0); + inline.setDistB(0); + inline.setDistL(0); + + CTNonVisualDrawingProps docPr = inline.addNewDocPr(); + long id = getParagraph().document.getDrawingIdManager().reserveNew(); + docPr.setId(id); + /* This name is not visible in Word 2010 anywhere. */ + docPr.setName("Drawing " + id); + docPr.setDescr(filename); + + CTPositiveSize2D extent = inline.addNewExtent(); + extent.setCx(width); + extent.setCy(height); + + // Grab the picture object + CTGraphicalObject graphic = inline.getGraphic(); + CTGraphicalObjectData graphicData = graphic.getGraphicData(); + CTPicture pic = getCTPictures(graphicData).get(0); + + // Set it up + CTPictureNonVisual nvPicPr = pic.addNewNvPicPr(); + + CTNonVisualDrawingProps cNvPr = nvPicPr.addNewCNvPr(); + /* use "0" for the id. See ECM-576, 20.2.2.3 */ + cNvPr.setId(0L); + /* This name is not visible in Word 2010 anywhere */ + cNvPr.setName("Picture " + id); + cNvPr.setDescr(filename); + + CTNonVisualPictureProperties cNvPicPr = nvPicPr.addNewCNvPicPr(); + cNvPicPr.addNewPicLocks().setNoChangeAspect(true); + + CTBlipFillProperties blipFill = pic.addNewBlipFill(); + CTBlip blip = blipFill.addNewBlip(); + blip.setEmbed( picData.getPackageRelationship().getId() ); + blipFill.addNewStretch().addNewFillRect(); + + CTShapeProperties spPr = pic.addNewSpPr(); + CTTransform2D xfrm = spPr.addNewXfrm(); + + CTPoint2D off = xfrm.addNewOff(); + off.setX(0); + off.setY(0); + + CTPositiveSize2D ext = xfrm.addNewExt(); + ext.setCx(width); + ext.setCy(height); + + CTPresetGeometry2D prstGeom = spPr.addNewPrstGeom(); + prstGeom.setPrst(STShapeType.RECT); + prstGeom.addNewAvLst(); + + // Finish up + XWPFPicture xwpfPicture = new XWPFPicture(pic, this); + pictures.add(xwpfPicture); + return xwpfPicture; + } catch(XmlException e) { + throw new IllegalStateException(e); + } + } + /** * Returns the embedded pictures of the run. These * are pictures which reference an external, * embedded picture image such as a .png or .jpg */ public List<XWPFPicture> getEmbeddedPictures() { - return pictures; + return pictures; } /** @@ -714,56 +747,56 @@ public class XWPFRun { * carriage returns in place of their xml equivalents. */ public String toString() { - StringBuffer text = new StringBuffer(); - - // Grab the text and tabs of the text run - // Do so in a way that preserves the ordering - XmlCursor c = run.newCursor(); - c.selectPath("./*"); - while (c.toNextSelection()) { - XmlObject o = c.getObject(); - if (o instanceof CTText) { - String tagName = o.getDomNode().getNodeName(); - // Field Codes (w:instrText, defined in spec sec. 17.16.23) - // come up as instances of CTText, but we don't want them - // in the normal text output - if (!"w:instrText".equals(tagName)) { - text.append(((CTText) o).getStringValue()); - } - } - - if (o instanceof CTPTab) { - text.append("\t"); - } - if (o instanceof CTBr) { - text.append("\n"); - } - 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 - // This bit works around it, and replicates the above - // rules for that case - String tagName = o.getDomNode().getNodeName(); - if ("w:tab".equals(tagName)) { - text.append("\t"); - } - if ("w:br".equals(tagName)) { - text.append("\n"); - } - if ("w:cr".equals(tagName)) { - text.append("\n"); - } - } - } - - c.dispose(); - - // Any picture text? - if(pictureText != null && pictureText.length() > 0) { - text.append("\n").append(pictureText); - } - - return text.toString(); + StringBuffer text = new StringBuffer(); + + // Grab the text and tabs of the text run + // Do so in a way that preserves the ordering + XmlCursor c = run.newCursor(); + c.selectPath("./*"); + while (c.toNextSelection()) { + XmlObject o = c.getObject(); + if (o instanceof CTText) { + String tagName = o.getDomNode().getNodeName(); + // Field Codes (w:instrText, defined in spec sec. 17.16.23) + // come up as instances of CTText, but we don't want them + // in the normal text output + if (!"w:instrText".equals(tagName)) { + text.append(((CTText) o).getStringValue()); + } + } + + if (o instanceof CTPTab) { + text.append("\t"); + } + if (o instanceof CTBr) { + text.append("\n"); + } + 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 + // This bit works around it, and replicates the above + // rules for that case + String tagName = o.getDomNode().getNodeName(); + if ("w:tab".equals(tagName)) { + text.append("\t"); + } + if ("w:br".equals(tagName)) { + text.append("\n"); + } + if ("w:cr".equals(tagName)) { + text.append("\n"); + } + } + } + + c.dispose(); + + // Any picture text? + if(pictureText != null && pictureText.length() > 0) { + text.append("\n").append(pictureText); + } + + return text.toString(); } } diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFSettings.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFSettings.java index 09ec4cc6fb..18d787504a 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFSettings.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFSettings.java @@ -42,7 +42,6 @@ public class XWPFSettings extends POIXMLDocumentPart { public XWPFSettings(PackagePart part, PackageRelationship rel) throws IOException { super(part, rel); - readFrom(part.getInputStream()); } public XWPFSettings() { @@ -50,19 +49,26 @@ public class XWPFSettings extends POIXMLDocumentPart { ctSettings = CTSettings.Factory.newInstance(); } + @Override + protected void onDocumentRead() throws IOException + { + super.onDocumentRead(); + readFrom(getPackagePart().getInputStream()); + } + /** * Set zoom.<br/> * In the zoom tag inside settings.xml file <br/> * it sets the value of zoom * <br/> - * sample snippet from settings.xml + * sample snippet from settings.xml * <pre> - * <w:zoom w:percent="50" /> + * <w:zoom w:percent="50" /> * <pre> * @return percentage as an integer of zoom level */ public long getZoomPercent() { - CTZoom zoom; + CTZoom zoom; if (!ctSettings.isSetZoom()) { zoom = ctSettings.addNewZoom(); } else { diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java index 86895032eb..f45d113ca5 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFStyles.java @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.lang.String; import javax.xml.namespace.QName; @@ -49,11 +48,12 @@ import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocDefaults; * */ public class XWPFStyles extends POIXMLDocumentPart{ - private CTStyles ctStyles; - protected XWPFLatentStyles latentStyles; - protected List<XWPFStyle> listStyle; - - /** + + private List<XWPFStyle> listStyle = new ArrayList<XWPFStyle>(); + private CTStyles ctStyles; + XWPFLatentStyles latentStyles; + + /** * Construct XWPFStyles from a package part * * @param part the package part holding the data of the styles, @@ -62,14 +62,12 @@ public class XWPFStyles extends POIXMLDocumentPart{ public XWPFStyles(PackagePart part, PackageRelationship rel) throws IOException, OpenXML4JException{ super(part, rel); - onDocumentRead(); } /** * Construct XWPFStyles from scratch for a new document. */ public XWPFStyles() { - listStyle = new ArrayList<XWPFStyle>(); } /** @@ -77,7 +75,6 @@ public class XWPFStyles extends POIXMLDocumentPart{ */ @Override protected void onDocumentRead ()throws IOException{ - listStyle = new ArrayList<XWPFStyle>(); StylesDocument stylesDoc; try { InputStream is = getPackagePart().getInputStream(); @@ -98,7 +95,7 @@ public class XWPFStyles extends POIXMLDocumentPart{ 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<String,String> map = new HashMap<String,String>(); map.put("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r"); map.put("http://schemas.openxmlformats.org/wordprocessingml/2006/main", "w"); xmlOptions.setSaveSuggestedPrefixes(map); 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 d310b288ae..5c4d2cca58 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTable.java @@ -20,6 +20,7 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.List; +import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.util.Internal; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow; @@ -58,7 +59,6 @@ public class XWPFTable implements IBodyElement{ } } - public XWPFTable(CTTbl table, IBody part){ this.part = part; this.ctTbl = table; @@ -131,17 +131,17 @@ public class XWPFTable implements IBodyElement{ return text.toString(); } - public void addNewRowBetween(int start, int end) { // TODO } - /** * add a new column for each row in this table */ public void addNewCol() { - if (ctTbl.sizeOfTrArray() == 0) createRow(); + if (ctTbl.sizeOfTrArray() == 0) { + createRow(); + } for (int i = 0; i < ctTbl.sizeOfTrArray(); i++) { XWPFTableRow tabRow = new XWPFTableRow(ctTbl.getTrArray(i), this); tabRow.createCell(); @@ -268,12 +268,12 @@ public class XWPFTable implements IBodyElement{ * @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; + if (pos >= 0 && pos < tableRows.size()) { + ctTbl.removeTr(pos); + tableRows.remove(pos); + return true; + } + return false; } public List<XWPFTableRow> getRows() { @@ -289,26 +289,30 @@ public class XWPFTable implements IBodyElement{ return BodyElementType.TABLE; } + @Override + public IBody getBody() + { + return part; + } - /** - * returns the part of the bodyElement - * @see org.apache.poi.xwpf.usermodel.IBody#getPart() - */ - public IBody getPart() { - if(part != null){ - return part.getPart(); - } - return null; - } - + /** + * returns the part of the bodyElement + * @see org.apache.poi.xwpf.usermodel.IBody#getPart() + */ + public POIXMLDocumentPart 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() - */ - public BodyType getPartType() { - return ((IBody)part).getPartType(); - } + /** + * returns the partType of the bodyPart which owns the bodyElement + * @see org.apache.poi.xwpf.usermodel.IBody#getPartType() + */ + public BodyType getPartType() { + return part.getPartType(); + } /** * returns the XWPFRow which belongs to the CTRow row diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableCell.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableCell.java index 9ffb65a340..a28a963db9 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableCell.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableCell.java @@ -20,6 +20,7 @@ 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.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlObject; @@ -248,16 +249,14 @@ public class XWPFTableCell implements IBody { return null; } - - - - /** - * get the to which the TableCell belongs - * @see org.apache.poi.xwpf.usermodel.IBody#getPart() - */ - public IBody getPart() { - return tableRow.getTable().getPart(); - } + /** + * get the to which the TableCell belongs + * + * @see org.apache.poi.xwpf.usermodel.IBody#getPart() + */ + public POIXMLDocumentPart getPart() { + return tableRow.getTable().getPart(); + } /** 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 ebdbe04ba2..a717d7f374 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableRow.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFTableRow.java @@ -52,7 +52,7 @@ public class XWPFTableRow { * @return the newly created XWPFTableCell */ public XWPFTableCell createCell() { - XWPFTableCell tableCell = new XWPFTableCell(ctRow.addNewTc(), this, table.getPart()); + XWPFTableCell tableCell = new XWPFTableCell(ctRow.addNewTc(), this, table.getBody()); tableCells.add(tableCell); return tableCell; } @@ -69,7 +69,7 @@ public class XWPFTableRow { */ public XWPFTableCell addNewTableCell(){ CTTc cell = ctRow.addNewTc(); - XWPFTableCell tableCell = new XWPFTableCell(cell, this, table.getPart()); + XWPFTableCell tableCell = new XWPFTableCell(cell, this, table.getBody()); tableCells.add(tableCell); return tableCell; } @@ -123,7 +123,7 @@ public class XWPFTableRow { if(tableCells == null){ List<XWPFTableCell> cells = new ArrayList<XWPFTableCell>(); for (CTTc tableCell : ctRow.getTcList()) { - cells.add(new XWPFTableCell(tableCell, this, table.getPart())); + cells.add(new XWPFTableCell(tableCell, this, table.getBody())); } this.tableCells = cells; } |