diff options
Diffstat (limited to 'src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFComments.java')
-rw-r--r-- | src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFComments.java | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFComments.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFComments.java new file mode 100644 index 0000000000..3cf82b680c --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFComments.java @@ -0,0 +1,280 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.xwpf.usermodel; + +import org.apache.poi.ooxml.POIXMLDocumentPart; +import org.apache.poi.ooxml.POIXMLException; +import org.apache.poi.ooxml.POIXMLRelation; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.util.IOUtils; +import org.apache.poi.util.Internal; +import org.apache.xmlbeans.XmlException; +import org.apache.xmlbeans.XmlOptions; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTComment; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTComments; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CommentsDocument; + +import javax.xml.namespace.QName; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; + +/** + * specifies all of the comments defined in the current document + */ +public class XWPFComments extends POIXMLDocumentPart { + + XWPFDocument document; + private List<XWPFComment> comments = new ArrayList<>(); + private List<XWPFPictureData> pictures = new ArrayList<>(); + private CTComments ctComments; + + /** + * Construct XWPFComments from a package part + * + * @param part the package part holding the data of the footnotes, + */ + public XWPFComments(PackagePart part) { + super(part); + } + + /** + * Construct XWPFComments from scratch for a new document. + */ + public XWPFComments() { + ctComments = CTComments.Factory.newInstance(); + } + + /** + * read comments form an existing package + */ + @Override + public void onDocumentRead() throws IOException { + try (InputStream is = getPackagePart().getInputStream()) { + CommentsDocument doc = CommentsDocument.Factory.parse(is, DEFAULT_XML_OPTIONS); + ctComments = doc.getComments(); + for (CTComment ctComment : ctComments.getCommentList()) { + comments.add(new XWPFComment(ctComment, this)); + } + } catch (XmlException e) { + throw new POIXMLException("Unable to read comments", e); + } + + for (POIXMLDocumentPart poixmlDocumentPart : getRelations()) { + if (poixmlDocumentPart instanceof XWPFPictureData) { + XWPFPictureData xwpfPicData = (XWPFPictureData) poixmlDocumentPart; + pictures.add(xwpfPicData); + document.registerPackagePictureData(xwpfPicData); + } + } + } + + /** + * Adds a picture to the comments. + * + * @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 If the format of the picture is not known. + * @throws IOException If reading the picture-data from the stream fails. + */ + public String addPictureData(InputStream is, int format) throws InvalidFormatException, IOException { + byte[] data = IOUtils.toByteArray(is); + return addPictureData(data, format); + } + + /** + * Adds a picture to the comments. + * + * @param pictureData The picture data + * @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 If the format of the picture is not known. + */ + 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 = getXWPFDocument().getNextPicNameNumber(format); + xwpfPicData = (XWPFPictureData) createRelationship(relDesc, XWPFFactory.getInstance(), idx); + /* write bytes to new part */ + PackagePart picDataPart = xwpfPicData.getPackagePart(); + try (OutputStream out = picDataPart.getOutputStream()) { + out.write(pictureData); + } catch (IOException e) { + throw new POIXMLException(e); + } + + 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. + */ + // TODO add support for TargetMode.EXTERNAL relations. + RelationPart rp = addRelation(null, XWPFRelation.IMAGES, xwpfPicData); + pictures.add(xwpfPicData); + return rp.getRelationship().getId(); + } else { + /* Part already existed, get relation id and return it */ + return getRelationId(xwpfPicData); + } + } + + /** + * save and commit comments + */ + @Override + protected void commit() throws IOException { + XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS); + xmlOptions.setSaveSyntheticDocumentElement(new QName( + CTComments.type.getName().getNamespaceURI(), "comments")); + PackagePart part = getPackagePart(); + OutputStream out = part.getOutputStream(); + ctComments.save(out, xmlOptions); + out.close(); + } + + public List<XWPFPictureData> getAllPictures() { + return Collections.unmodifiableList(pictures); + } + + /** + * Gets the underlying CTComments object for the comments. + * + * @return CTComments object + */ + public CTComments getCtComments() { + return ctComments; + } + + /** + * set a new comments + */ + @Internal + public void setCtComments(CTComments ctComments) { + this.ctComments = ctComments; + } + + /** + * Get the list of {@link XWPFComment} in the Comments part. + * + * @return + */ + public List<XWPFComment> getComments() { + return comments; + } + + /** + * Get the specified comment by position + * + * @param pos Array position of the comment + * @return + */ + public XWPFComment getComment(int pos) { + if (pos >= 0 && pos < ctComments.sizeOfCommentArray()) { + return getComments().get(pos); + } + return null; + } + + /** + * Get the specified comment by comment id + * + * @param id comment id + * @return the specified comment + */ + public XWPFComment getCommentByID(String id) { + for (XWPFComment comment : comments) { + if (comment.getId().equals(id)) { + return comment; + } + } + return null; + } + + /** + * Get the specified comment by ctComment + * + * @param ctComment + * @return + */ + public XWPFComment getComment(CTComment ctComment) { + for (int i = 0; i < comments.size(); i++) { + if (comments.get(i).getCtComment() == ctComment) { + return comments.get(i); + } + } + return null; + } + + /** + * Create a new comment and add it to the document. + * + * @param cid comment Id + * @return + */ + public XWPFComment createComment(BigInteger cid) { + CTComment ctComment = ctComments.addNewComment(); + ctComment.setId(cid); + XWPFComment comment = new XWPFComment(ctComment, this); + comments.add(comment); + return comment; + } + + /** + * Remove the specified comment if present. + * + * @param pos Array position of the comment to be removed + * @return True if the comment was removed. + */ + public boolean removeComment(int pos) { + if (pos >= 0 && pos < ctComments.sizeOfCommentArray()) { + comments.remove(pos); + ctComments.removeComment(pos); + return true; + } + return false; + } + + public XWPFDocument getXWPFDocument() { + if (null != document) { + return document; + } + return (XWPFDocument) getParent(); + } + + public void setXWPFDocument(XWPFDocument document) { + this.document = document; + } + +} |