Browse Source

improved work with cell comments in XSSF, also added support for cell comments to SS interfaces

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@884918 13f79535-47bb-0310-9956-ffa450edef68
tags/REL_3_6
Yegor Kozlov 14 years ago
parent
commit
21d7a81d3c
24 changed files with 1314 additions and 645 deletions
  1. 26
    113
      src/documentation/content/xdocs/spreadsheet/quick-guide.xml
  2. 4
    1
      src/documentation/content/xdocs/status.xml
  3. 80
    0
      src/examples/src/org/apache/poi/xssf/usermodel/examples/CellComments.java
  4. 8
    1
      src/java/org/apache/poi/hssf/usermodel/HSSFComment.java
  5. 5
    0
      src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
  6. 5
    0
      src/java/org/apache/poi/ss/usermodel/Cell.java
  7. 1
    1
      src/java/org/apache/poi/ss/usermodel/Comment.java
  8. 2
    0
      src/java/org/apache/poi/ss/usermodel/Drawing.java
  9. 30
    31
      src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java
  10. 21
    3
      src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java
  11. 4
    0
      src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFClientAnchor.java
  12. 109
    44
      src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFComment.java
  13. 30
    0
      src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java
  14. 1
    1
      src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java
  15. 66
    39
      src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
  16. 253
    0
      src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFVMLDrawing.java
  17. 50
    100
      src/ooxml/testcases/org/apache/poi/xssf/model/TestCommentsTable.java
  18. 137
    131
      src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFComment.java
  19. 39
    1
      src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
  20. 139
    0
      src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFVMLDrawing.java
  21. 16
    179
      src/testcases/org/apache/poi/hssf/usermodel/TestHSSFComment.java
  22. 246
    0
      src/testcases/org/apache/poi/ss/usermodel/BaseTestCellComment.java
  23. BIN
      test-data/spreadsheet/SimpleWithComments.xlsx
  24. 42
    0
      test-data/spreadsheet/vmlDrawing1.vml

+ 26
- 113
src/documentation/content/xdocs/spreadsheet/quick-guide.xml View File

@@ -43,7 +43,7 @@
<li><link href="#TextExtraction">Text Extraction</link></li>
<li><link href="#Alignment">Aligning cells</link></li>
<li><link href="#Borders">Working with borders</link></li>
<li><link href="#FrillsAndFills">Fills and color</link></li>
<li><link href="#FillsAndFrills">Fills and color</link></li>
<li><link href="#MergedCells">Merging cells</link></li>
<li><link href="#WorkingWithFonts">Working with fonts</link></li>
<li><link href="#CustomColors">Custom colors</link></li>
@@ -1328,123 +1328,36 @@ Examples:
</source>
</section>
<anchor id="CellComments"/>
<section><title>Cell Comments - HSSF and XSSF (slight differences though)</title>
<section><title>Cell Comments - HSSF and XSSF</title>
<p>
In HSSF Excel, cell comments were added to the file format as a bit of a
cludge. As such, comments are a kind of a text shape, so inserting a
comment is very similar to placing a text box in a worksheet.
A comment is a rich text note that is attached to &amp;
associated with a cell, separate from other cell content.
Comment content is stored separate from the cell, and is displayed in a drawing object (like a text box)
that is separate from, but associated with, a cell
</p>
<p>
In XSSF Excel, cell comments are more cleanly done. Each Sheet has a list
of its comments, and they can be added much like other cell properties.
</p>
<p>
Once you have created your comment, how you use it is very similar between
HSSF and XSSF. It is only the creation of a new comment where things
differ.
</p>
<p>
For HSSF, the process is:
</p>
<source>
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("Cell comments in POI HSSF");
CreationHelper createHelper = wb.getCreationHelper();

// Create the drawing patriarch. This is the top level container for all shapes including cell comments.
HSSFPatriarch patr = sheet.createDrawingPatriarch();

// Create a cell in row 3
Cell cell1 = sheet.createRow(3).createCell((short)1);
cell1.setCellValue(new HSSFRichTextString("Hello, World"));

// Anchor defines size and position of the comment in worksheet
Comment comment1 = patr.createComment(new HSSFClientAnchor(0, 0, 0, 0, (short)4, 2, (short) 6, 5));

// set text in the comment
comment1.setString(createHelper.createRichTextString("We can set comments in POI"));

// set comment author.
// you can see it in the status bar when moving mouse over the commented cell
comment1.setAuthor("Apache Software Foundation");

// The first way to assign comment to a cell is via Cell.setCellComment method
cell1.setCellComment(comment1);


// Create another cell in row 6
Cell cell2 = sheet.createRow(6).createCell((short)1);
cell2.setCellValue(36.6);

// And a comment for it
HSSFComment comment2 = patr.createComment(new HSSFClientAnchor(0, 0, 0, 0, (short)4, 8, (short) 6, 11));
// Modify background color of the comment
comment2.setFillColor(204, 236, 255);

HSSFRichTextString string = new HSSFRichTextString("Normal body temperature");

// Apply custom font to the text in the comment
HSSFFont font = wb.createFont();
font.setFontName("Arial");
font.setFontHeightInPoints((short)10);
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
font.setColor(HSSFColor.RED.index);
string.applyFont(font);

comment2.setString(string);
// By default comments are hidden. This one is always visible.
comment2.setVisible(true);

comment2.setAuthor("Bill Gates");


/**
* The second way to assign comment to a cell is to implicitly specify its row and column.
* Note, it is possible to set row and column of a non-existing cell.
* It works, the comment is visible.
*/
comment2.setRow(6);
comment2.setColumn((short)1);

FileOutputStream out = new FileOutputStream("poi_comment.xls");
wb.write(out);
out.close();
</source>
<p>
For XSSF, the simpler process is:
</p>
<source>
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet("Cell comments in POI XSSF");
CreationHelper createHelper = wb.getCreationHelper();

// Create a cell in row 3
Cell cell1 = sheet.createRow(3).createCell((short)1);
cell1.setCellValue(new XSSFRichTextString("Hello, World"));

// Create a comment, and set the text and author
// (You can see the author in the status bar when moving mouse
// over the commented cell)
Comment comment1 = sheet.createComment();
comment1.setString(createHelper.createRichTextString("We can set comments in POI"));
comment1.setAuthor("Apache Software Foundation");


// The first way to assign comment to a cell is via Cell.setCellComment method
cell1.setCellComment(comment1);
<source>
Workbook wb = new XSSFWorkbook(); //or new HSSFWorkbook();

CreationHelper factory = wb.getCreationHelper();

// The other way is to set the row and column
// This could point to a cell that isn't defined, and the comment will
// will still show up all the same
Comment comment2 = sheet.createComment();
comment2.setString(createHelper.createRichTextString("Comment for missing cell"));
comment2.setAuthor("Apache POI");
comment2.setRow(11);
comment2.setColumn(1);
Sheet sheet = wb.createSheet();
Cell cell = sheet.createRow(3).createCell(5);
cell.setCellValue("F4");
Drawing drawing = sheet.createDrawingPatriarch();

// Write out
FileOutputStream out = new FileOutputStream("poi_comment.xls");
ClientAnchor anchor = factory.createClientAnchor();
Comment comment = drawing.createCellComment(anchor);
RichTextString str = factory.createRichTextString("Hello, World!");
comment.setString(str);
comment.setAuthor("Apache POI");
//assign the comment to the cell
cell.setCellComment(comment);

String fname = "comment-xssf.xls";
if(wb instanceof XSSFWorkbook) fname += "x";
FileOutputStream out = new FileOutputStream(fname);
wb.write(out);
out.close();
</source>

+ 4
- 1
src/documentation/content/xdocs/status.xml View File

@@ -34,7 +34,10 @@

<changes>
<release version="3.6-beta1" date="2009-??-??">
<action dev="POI-DEVELOPERS" type="add">Add support for creating SummaryInformation and DocumentSummaryInformation properties on POIDocuments that don't have them, via POIDocument.createInformationProperties()</action>
<action dev="POI-DEVELOPERS" type="fix">47188 - avoid corruption of workbook when adding cell comments </action>
<action dev="POI-DEVELOPERS" type="fix">48106 - improved work with cell comments in XSSF</action>
<action dev="POI-DEVELOPERS" type="add">Add support for creating SummaryInformation and DocumentSummaryInformation properties
on POIDocuments that don't have them, via POIDocument.createInformationProperties()</action>
<action dev="POI-DEVELOPERS" type="fix">48180 - be more forgiving of short chart records, which skip some unused fields</action>
<action dev="POI-DEVELOPERS" type="fix">48274 - fix erronious wrapping of byte colours in HSSFPalette.findSimilarColor</action>
<action dev="POI-DEVELOPERS" type="fix">48269 - fix fetching of error codes from XSSF formula cells</action>

+ 80
- 0
src/examples/src/org/apache/poi/xssf/usermodel/examples/CellComments.java View File

@@ -0,0 +1,80 @@
/* ====================================================================
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.xssf.usermodel.examples;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.IOException;
import java.io.FileOutputStream;
/**
* Demonstrates how to work with excel cell comments.
*
* <p>
* Excel comment is a kind of a text shape,
* so inserting a comment is very similar to placing a text box in a worksheet
* </p>
*
* @author Yegor Kozlov
*/
public class CellComments {
public static void main(String[] args) throws IOException {
Workbook wb = new XSSFWorkbook();
CreationHelper factory = wb.getCreationHelper();
Sheet sheet = wb.createSheet();
Cell cell1 = sheet.createRow(3).createCell(5);
cell1.setCellValue("F4");
Drawing drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = factory.createClientAnchor();
Comment comment1 = drawing.createCellComment(anchor);
RichTextString str1 = factory.createRichTextString("Hello, World!");
comment1.setString(str1);
comment1.setAuthor("Apache POI");
cell1.setCellComment(comment1);
Cell cell2 = sheet.createRow(2).createCell(2);
cell2.setCellValue("C3");
Comment comment2 = drawing.createCellComment(anchor);
RichTextString str2 = factory.createRichTextString("XSSF can set cell comments");
//apply custom font to the text in the comment
Font font = wb.createFont();
font.setFontName("Arial");
font.setFontHeightInPoints((short)14);
font.setBoldweight(Font.BOLDWEIGHT_BOLD);
font.setColor(IndexedColors.RED.getIndex());
str2.applyFont(font);
comment2.setString(str2);
comment2.setAuthor("Apache POI");
comment2.setColumn(2);
comment2.setRow(2);
String fname = "comments.xlsx";
FileOutputStream out = new FileOutputStream(fname);
wb.write(out);
out.close();
}
}

+ 8
- 1
src/java/org/apache/poi/hssf/usermodel/HSSFComment.java View File

@@ -127,12 +127,19 @@ public class HSSFComment extends HSSFTextbox implements Comment {
*
* @param col the 0-based column of the cell that contains the comment
*/
public void setColumn(short col) {
public void setColumn(int col) {
if(_note != null) {
_note.setColumn(col);
}
_col = col;
}
/**
* @deprecated (Nov 2009) use {@link HSSFComment#setColumn(int)} }
*/
@Deprecated
public void setColumn(short col) {
setColumn((int)col);
}

/**
* Name of the original comment author

+ 5
- 0
src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java View File

@@ -157,6 +157,11 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
return shape;
}

@Override
public HSSFComment createCellComment(ClientAnchor anchor){
return createComment((HSSFAnchor)anchor);
}

/**
* Returns a list of all shapes contained by the patriarch.
*/

+ 5
- 0
src/java/org/apache/poi/ss/usermodel/Cell.java View File

@@ -351,6 +351,11 @@ public interface Cell {
*/
Comment getCellComment();

/**
* Removes the comment for this cell, if there is one.
*/
void removeCellComment();

/**
* Returns hyperlink associated with this cell
*

+ 1
- 1
src/java/org/apache/poi/ss/usermodel/Comment.java View File

@@ -59,7 +59,7 @@ public interface Comment {
*
* @param col the 0-based column of the cell that contains the comment
*/
void setColumn(short col);
void setColumn(int col);

/**
* Name of the original comment author

+ 2
- 0
src/java/org/apache/poi/ss/usermodel/Drawing.java View File

@@ -21,4 +21,6 @@ package org.apache.poi.ss.usermodel;
*/
public interface Drawing {
Picture createPicture(ClientAnchor anchor, int pictureIndex);

Comment createCellComment(ClientAnchor anchor);
}

+ 30
- 31
src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java View File

@@ -24,7 +24,6 @@ import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.XSSFComment;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAuthors;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCommentList;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComments;
@@ -33,11 +32,13 @@ import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;

public class CommentsTable extends POIXMLDocumentPart {
protected CTComments comments;
private CTComments comments;

public CommentsTable() {
super();
comments = CTComments.Factory.newInstance();
comments.addNewCommentList();
comments.addNewAuthors().addAuthor("");
}

public CommentsTable(PackagePart part, PackageRelationship rel) throws IOException {
@@ -70,62 +71,60 @@ public class CommentsTable extends POIXMLDocumentPart {
public int getNumberOfComments() {
return comments.getCommentList().sizeOfCommentArray();
}

public int getNumberOfAuthors() {
return getCommentsAuthors().sizeOfAuthorArray();
return comments.getAuthors().sizeOfAuthorArray();
}

public String getAuthor(long authorId) {
return getCommentsAuthors().getAuthorArray((int)authorId);
return comments.getAuthors().getAuthorArray((int)authorId);
}

public int findAuthor(String author) {
for (int i = 0 ; i < getCommentsAuthors().sizeOfAuthorArray() ; i++) {
if (getCommentsAuthors().getAuthorArray(i).equals(author)) {
for (int i = 0 ; i < comments.getAuthors().sizeOfAuthorArray() ; i++) {
if (comments.getAuthors().getAuthorArray(i).equals(author)) {
return i;
}
}
return addNewAuthor(author);
}

public XSSFComment findCellComment(int row, int column) {
return findCellComment(
(new CellReference(row, column)).formatAsString() );
public XSSFComment findCellComment(String cellRef) {
CTComment ct = getCTComment(cellRef);
return ct == null ? null : new XSSFComment(this, ct, null);
}

public XSSFComment findCellComment(String cellRef) {
for (CTComment comment : getCommentsList().getCommentArray()) {
public CTComment getCTComment(String cellRef) {
for (CTComment comment : comments.getCommentList().getCommentArray()) {
if (cellRef.equals(comment.getRef())) {
return new XSSFComment(this, comment);
return comment;
}
}
return null;
}

/**
* Generates a new XSSFComment, associated with the
* current comments list.
*/
public XSSFComment addComment() {
return new XSSFComment(this, getCommentsList().addNewComment());
}

private CTCommentList getCommentsList() {
if (comments.getCommentList() == null) {
comments.addNewCommentList();
}
return comments.getCommentList();
public CTComment newComment() {
CTComment ct = comments.getCommentList().addNewComment();
ct.setRef("A1");
ct.setAuthorId(0);
return ct;
}

private CTAuthors getCommentsAuthors() {
if (comments.getAuthors() == null) {
comments.addNewAuthors();
public boolean removeComment(String cellRef) {
CTCommentList lst = comments.getCommentList();
if(lst != null) for(int i=0; i < lst.sizeOfCommentArray(); i++) {
CTComment comment = lst.getCommentArray(i);
if (cellRef.equals(comment.getRef())) {
lst.removeComment(i);
return true;
}
}
return comments.getAuthors();
return false;
}

private int addNewAuthor(String author) {
int index = getCommentsAuthors().sizeOfAuthorArray();
getCommentsAuthors().insertAuthor(index, author);
int index = comments.getAuthors().sizeOfAuthorArray();
comments.getAuthors().insertAuthor(index, author);
return index;
}


+ 21
- 3
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java View File

@@ -807,11 +807,29 @@ public final class XSSFCell implements Cell {
* Assign a comment to this cell. If the supplied comment is null,
* the comment for this cell will be removed.
*
* @param comment comment associated with this cell
* @param comment the XSSFComment associated with this cell
*/
public void setCellComment(Comment comment) {
String cellRef = new CellReference(_row.getRowNum(), getColumnIndex()).formatAsString();
getSheet().setCellComment(cellRef, (XSSFComment)comment);
if(comment == null) {
removeCellComment();
return;
}

comment.setRow(getRowIndex());
comment.setColumn(getColumnIndex());
}

/**
* Removes the comment for this cell, if there is one.
*/
public void removeCellComment() {
XSSFComment comment = getCellComment();
if(comment != null){
String ref = _cell.getR();
XSSFSheet sh = getSheet();
sh.getCommentsTable(false).removeComment(ref);
sh.getVMLDrawing(false).removeCommentShape(getRowIndex(), getColumnIndex());
}
}

/**

+ 4
- 0
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFClientAnchor.java View File

@@ -217,4 +217,8 @@ public final class XSSFClientAnchor extends XSSFAnchor implements ClientAnchor {
return anchorType;
}

public boolean isSet(){
return !(cell1.getCol() == 0 && cell2.getCol() == 0 &&
cell1.getRow() == 0 && cell2.getRow() == 0);
}
}

+ 109
- 44
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFComment.java View File

@@ -20,84 +20,149 @@ import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.model.CommentsTable;
import org.apache.poi.xssf.usermodel.helpers.RichTextStringHelper;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRst;
import schemasMicrosoftComVml.CTShape;

import java.math.BigInteger;

public class XSSFComment implements Comment {
private CTComment comment;
private CommentsTable comments;
private final CTComment _comment;
private final CommentsTable _comments;
private final CTShape _vmlShape;

/**
* cached reference to the string with the comment text
*/
private XSSFRichTextString _str;

/**
/**
* Creates a new XSSFComment, associated with a given
* low level comment object.
* If, as an end user, you want a new XSSFComment
* object, the please ask your sheet for one.
*/
public XSSFComment(CommentsTable comments, CTComment comment) {
this.comment = comment;
this.comments = comments;
public XSSFComment(CommentsTable comments, CTComment comment, CTShape vmlShape) {
_comment = comment;
_comments = comments;
_vmlShape = vmlShape;
}

public String getAuthor() {
return comments.getAuthor((int)comment.getAuthorId());
/**
*
* @return Name of the original comment author. Default value is blank.
*/
public String getAuthor() {
return _comments.getAuthor((int) _comment.getAuthorId());
}

/**
* Name of the original comment author. Default value is blank.
*
* @param author the name of the original author of the comment
*/
public void setAuthor(String author) {
_comment.setAuthorId(
_comments.findAuthor(author)
);
}

/**
* @return the 0-based column of the cell that the comment is associated with.
*/
public int getColumn() {
return (new CellReference(comment.getRef())).getCol();
return new CellReference(_comment.getRef()).getCol();
}

/**
* @return the 0-based row index of the cell that the comment is associated with.
*/
public int getRow() {
return (new CellReference(comment.getRef())).getRow();
return new CellReference(_comment.getRef()).getRow();
}

public boolean isVisible() {
// TODO Auto-generated method stub
return true;
/**
* @return whether the comment is visible
*/
public boolean isVisible() {
boolean visible = false;
if(_vmlShape != null){
String style = _vmlShape.getStyle();
visible = style != null && style.indexOf("visibility:visible") != -1;
}
return visible;
}

public void setAuthor(String author) {
comment.setAuthorId(
comments.findAuthor(author)
);
}
/**
* @param visible whether the comment is visible
*/
public void setVisible(boolean visible) {
if(_vmlShape != null){
String style;
if(visible) style = "position:absolute;visibility:visible";
else style = "position:absolute;visibility:hidden";
_vmlShape.setStyle(style);
}
}

public void setColumn(short col) {
initializeRef();
String newRef =
(new CellReference(getRow(), col)).formatAsString();
comment.setRef(newRef);
}

private void initializeRef() {
if (comment.getRef() == null) {
comment.setRef("A1");
}
/**
* Set the column of the cell that contains the comment
*
* @param col the 0-based column of the cell that contains the comment
*/
public void setColumn(int col) {
CellReference ref = new CellReference(getRow(), col);
_comment.setRef(ref.formatAsString());
if(_vmlShape != null) _vmlShape.getClientDataArray(0).setColumnArray(0, new BigInteger(String.valueOf(col)));
}

/**
* Set the row of the cell that contains the comment
*
* @param row the 0-based row of the cell that contains the comment
*/
public void setRow(int row) {
initializeRef();
String newRef =
(new CellReference(row, getColumn())).formatAsString();
comment.setRef(newRef);
}
_comment.setRef(newRef);
if(_vmlShape != null) _vmlShape.getClientDataArray(0).setRowArray(0, new BigInteger(String.valueOf(row)));
}
public RichTextString getString() {
return RichTextStringHelper.convertFromRst(comment.getText());
/**
* @return the rich text string of the comment
*/
public XSSFRichTextString getString() {
if(_str == null) {
CTRst rst = _comment.getText();
if(rst != null) _str = new XSSFRichTextString(_comment.getText());
}
return _str;
}

/**
* Sets the rich text string used by this comment.
*
* @param string the XSSFRichTextString used by this object.
*/
public void setString(RichTextString string) {
CTRst text = comment.addNewText();
RichTextStringHelper.convertToRst(string, text);
if(!(string instanceof XSSFRichTextString)){
throw new IllegalArgumentException("Only XSSFRichTextString argument is supported");
}
_str = (XSSFRichTextString)string;
_comment.setText(_str.getCTRst());
}
public void setString(String string) {
RichTextString richTextString = new XSSFRichTextString(string);
setString(richTextString);
setString(new XSSFRichTextString(string));
}

public void setVisible(boolean visible) {
// TODO Auto-generated method stub
}
/**
* @return the xml bean holding this comment's properties
*/
protected CTComment getCTComment(){
return _comment;
}

protected CTShape getCTShape(){
return _vmlShape;
}
}

+ 30
- 0
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java View File

@@ -25,6 +25,7 @@ import java.util.Map;
import javax.xml.namespace.QName;

import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.xssf.model.CommentsTable;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
@@ -233,6 +234,35 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing {
return shape;
}

/**
* Creates a cell comment.
*
* @param anchor the client anchor describes how this comment is attached
* to the sheet.
* @return the newly created comment.
*/
@Override
public XSSFComment createCellComment(ClientAnchor anchor)
{
XSSFClientAnchor ca = (XSSFClientAnchor)anchor;
XSSFSheet sheet = (XSSFSheet)getParent();

//create comments and vmlDrawing parts if they don't exist
CommentsTable comments = sheet.getCommentsTable(true);
XSSFVMLDrawing vml = sheet.getVMLDrawing(true);
schemasMicrosoftComVml.CTShape vmlShape = vml.newCommentShape();
if(ca.isSet()){
String position =
ca.getCol1() + ", 0, " + ca.getRow1() + ", 0, " +
ca.getCol2() + ", 0, " + ca.getRow2() + ", 0";
vmlShape.getClientDataArray(0).setAnchorArray(0, position);
}
XSSFComment shape = new XSSFComment(comments, comments.newComment(), vmlShape);
shape.setColumn(ca.getCol1());
shape.setRow(ca.getRow1());
return shape;
}

/**
* Create and initialize a CTTwoCellAnchor that anchors a shape against top-left and bottom-right cells.
*

+ 1
- 1
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java View File

@@ -118,7 +118,7 @@ public final class XSSFRelation extends POIXMLRelation {
"application/vnd.openxmlformats-officedocument.vmlDrawing",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",
"/xl/drawings/vmlDrawing#.vml",
null
XSSFVMLDrawing.class
);

public static final XSSFRelation CUSTOM_XML_MAPPINGS = new XSSFRelation(

+ 66
- 39
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java View File

@@ -54,38 +54,7 @@ import org.apache.poi.xssf.usermodel.helpers.XSSFRowShifter;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBreak;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCommentList;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDrawing;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHeaderFooter;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHyperlink;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCell;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCells;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOutlinePr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageBreak;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageMargins;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageSetUpPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPane;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPrintOptions;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSelection;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetData;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetFormatPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetProtection;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetView;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPaneState;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;

/**
* High level representation of a SpreadsheetML worksheet.
@@ -351,6 +320,48 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
return drawing;
}

/**
* Get VML drawing for this sheet (aka 'legacy' drawig)
*
* @param autoCreate if true, then a new VML drawing part is created
*
* @return the VML drawing of <code>null</code> if the drawing was not found and autoCreate=false
*/
protected XSSFVMLDrawing getVMLDrawing(boolean autoCreate) {
XSSFVMLDrawing drawing = null;
CTLegacyDrawing ctDrawing = worksheet.getLegacyDrawing();
if(ctDrawing == null) {
if(autoCreate) {
//drawingNumber = #drawings.size() + 1
int drawingNumber = getPackagePart().getPackage().getPartsByContentType(XSSFRelation.VML_DRAWINGS.getContentType()).size() + 1;
drawing = (XSSFVMLDrawing)createRelationship(XSSFRelation.VML_DRAWINGS, XSSFFactory.getInstance(), drawingNumber);
String relId = drawing.getPackageRelationship().getId();

//add CTLegacyDrawing element which indicates that this sheet contains drawing components built on the drawingML platform.
//The relationship Id references the part containing the drawing definitions.
ctDrawing = worksheet.addNewLegacyDrawing();
ctDrawing.setId(relId);
}
} else {
//search the referenced drawing in the list of the sheet's relations
for(POIXMLDocumentPart p : getRelations()){
if(p instanceof XSSFVMLDrawing) {
XSSFVMLDrawing dr = (XSSFVMLDrawing)p;
String drId = dr.getPackageRelationship().getId();
if(drId.equals(ctDrawing.getId())){
drawing = dr;
break;
}
break;
}
}
if(drawing == null){
logger.log(POILogger.ERROR, "Can't find VML drawing with id=" + ctDrawing.getId() + " in the list of the sheet's relationships");
}
}
return drawing;
}

/**
* Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
* @param colSplit Horizonatal position of split.
@@ -392,12 +403,14 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
/**
* Creates a new comment for this sheet. You still
* need to assign it to a cell though
*
* @deprecated since Nov 2009 this method is not compatible with the common SS interfaces,
* use {@link org.apache.poi.xssf.usermodel.XSSFDrawing#createCellComment
* (org.apache.poi.ss.usermodel.ClientAnchor)} instead
*/
@Deprecated
public XSSFComment createComment() {
if (sheetComments == null) {
sheetComments = (CommentsTable)createRelationship(XSSFRelation.SHEET_COMMENTS, XSSFFactory.getInstance(), (int)sheet.getSheetId());
}
return sheetComments.addComment();
return createDrawingPatriarch().createCellComment(new XSSFClientAnchor());
}

/**
@@ -438,7 +451,14 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
if (sheetComments == null) {
return null;
}
return sheetComments.findCellComment(row, column);

String ref = new CellReference(row, column).formatAsString();
CTComment ctComment = sheetComments.getCTComment(ref);
if(ctComment == null) return null;

XSSFVMLDrawing vml = getVMLDrawing(false);
return new XSSFComment(sheetComments, ctComment,
vml == null ? null : vml.findCommentShape(row, column));
}

public XSSFHyperlink getHyperlink(int row, int column) {
@@ -2161,8 +2181,10 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
*
* @param cellRef cell region
* @param comment the comment to assign
* @deprecated since Nov 2009 use {@link XSSFCell#setCellComment(org.apache.poi.ss.usermodel.Comment)} instead
*/
public void setCellComment(String cellRef, XSSFComment comment) {
@Deprecated
public static void setCellComment(String cellRef, XSSFComment comment) {
CellReference cellReference = new CellReference(cellRef);

comment.setRow(cellReference.getRow());
@@ -2234,8 +2256,13 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
/**
* Returns the sheet's comments object if there is one,
* or null if not
*
* @param create create a new comments table if it does not exist
*/
protected CommentsTable getCommentsTable() {
protected CommentsTable getCommentsTable(boolean create) {
if(sheetComments == null && create){
sheetComments = (CommentsTable)createRelationship(XSSFRelation.SHEET_COMMENTS, XSSFFactory.getInstance(), (int)sheet.getSheetId());
}
return sheetComments;
}


+ 253
- 0
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFVMLDrawing.java View File

@@ -0,0 +1,253 @@
/* ====================================================================
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.xssf.usermodel;

import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlCursor;
import org.w3c.dom.Node;
import schemasMicrosoftComOfficeOffice.*;

import javax.xml.namespace.QName;
import java.io.*;
import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.math.BigInteger;

import schemasMicrosoftComVml.*;
import schemasMicrosoftComVml.STTrueFalse;
import schemasMicrosoftComOfficeExcel.CTClientData;
import schemasMicrosoftComOfficeExcel.STObjectType;

/**
* Represents a SpreadsheetML VML drawing.
*
* <p>
* In Excel 2007 VML drawings are used to describe properties of cell comments,
* although the spec says that VML is deprecated:
* </p>
* <p>
* The VML format is a legacy format originally introduced with Office 2000 and is included and fully defined
* in this Standard for backwards compatibility reasons. The DrawingML format is a newer and richer format
* created with the goal of eventually replacing any uses of VML in the Office Open XML formats. VML should be
* considered a deprecated format included in Office Open XML for legacy reasons only and new applications that
* need a file format for drawings are strongly encouraged to use preferentially DrawingML
* </p>
*
* See 6.4 VML - SpreadsheetML Drawing in Office Open XML Part 4 - Markup Language Reference.pdf
*
* @author Yegor Kozlov
*/
public final class XSSFVMLDrawing extends POIXMLDocumentPart {
private static final QName QNAME_SHAPE_LAYOUT = new QName("urn:schemas-microsoft-com:office:office", "shapelayout");
private static final QName QNAME_SHAPE_TYPE = new QName("urn:schemas-microsoft-com:vml", "shapetype");
private static final QName QNAME_SHAPE = new QName("urn:schemas-microsoft-com:vml", "shape");

/**
* regexp to parse shape ids, in VML they have weird form of id="_x0000_s1026"
*/
private static final Pattern ptrn_shapeId = Pattern.compile("_x0000_s(\\d+)");

private List<QName> _qnames = new ArrayList<QName>();
private List<XmlObject> _items = new ArrayList<XmlObject>();
private String _shapeTypeId;
private int _shapeId = 1024;

/**
* Create a new SpreadsheetML drawing
*
* @see XSSFSheet#createDrawingPatriarch()
*/
protected XSSFVMLDrawing() {
super();
newDrawing();
}

/**
* Construct a SpreadsheetML drawing from a package part
*
* @param part the package part holding the drawing data,
* the content type must be <code>application/vnd.openxmlformats-officedocument.drawing+xml</code>
* @param rel the package relationship holding this drawing,
* the relationship type must be http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing
*/
protected XSSFVMLDrawing(PackagePart part, PackageRelationship rel) throws IOException, XmlException {
super(part, rel);
read(getPackagePart().getInputStream());
}


protected void read(InputStream is) throws IOException, XmlException {
XmlObject root = XmlObject.Factory.parse(is);

_qnames = new ArrayList<QName>();
_items = new ArrayList<XmlObject>();
for(XmlObject obj : root.selectPath("$this/xml/*")) {
Node nd = obj.getDomNode();
QName qname = new QName(nd.getNamespaceURI(), nd.getLocalName());
if (qname.equals(QNAME_SHAPE_LAYOUT)) {
_items.add(CTShapeLayout.Factory.parse(obj.xmlText()));
} else if (qname.equals(QNAME_SHAPE_TYPE)) {
CTShapetype st = CTShapetype.Factory.parse(obj.xmlText());
_items.add(st);
_shapeTypeId = st.getId();
} else if (qname.equals(QNAME_SHAPE)) {
CTShape shape = CTShape.Factory.parse(obj.xmlText());
String id = shape.getId();
if(id != null) {
Matcher m = ptrn_shapeId.matcher(id);
if(m.find()) _shapeId = Math.max(_shapeId, Integer.parseInt(m.group(1)));
}
_items.add(shape);
} else {
_items.add(XmlObject.Factory.parse(obj.xmlText()));
}
_qnames.add(qname);
}
}

protected List<XmlObject> getItems(){
return _items;
}

protected void write(OutputStream out) throws IOException {
XmlObject rootObject = XmlObject.Factory.newInstance();
XmlCursor rootCursor = rootObject.newCursor();
rootCursor.toNextToken();
rootCursor.beginElement("xml");

for(int i=0; i < _items.size(); i++){
XmlCursor xc = _items.get(i).newCursor();
rootCursor.beginElement(_qnames.get(i));
while(xc.toNextToken() == XmlCursor.TokenType.ATTR) {
Node anode = xc.getDomNode();
rootCursor.insertAttributeWithValue(anode.getLocalName(), anode.getNamespaceURI(), anode.getNodeValue());
}
xc.toStartDoc();
xc.copyXmlContents(rootCursor);
rootCursor.toNextToken();
xc.dispose();
}
rootCursor.dispose();

XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
xmlOptions.setSavePrettyPrint();
HashMap<String, String> map = new HashMap<String, String>();
map.put("urn:schemas-microsoft-com:vml", "v");
map.put("urn:schemas-microsoft-com:office:office", "o");
map.put("urn:schemas-microsoft-com:office:excel", "x");
xmlOptions.setSaveSuggestedPrefixes(map);

rootObject.save(out, xmlOptions);
}

@Override
protected void commit() throws IOException {
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
write(out);
out.close();
}

/**
* Initialize a new Speadsheet VML drawing
*/
private void newDrawing(){
CTShapeLayout layout = CTShapeLayout.Factory.newInstance();
layout.setExt(STExt.EDIT);
CTIdMap idmap = layout.addNewIdmap();
idmap.setExt(STExt.EDIT);
idmap.setData("1");
_items.add(layout);
_qnames.add(QNAME_SHAPE_LAYOUT);

CTShapetype shapetype = CTShapetype.Factory.newInstance();
_shapeTypeId = "_xssf_cell_comment";
shapetype.setId(_shapeTypeId);
shapetype.setCoordsize("21600,21600");
shapetype.setSpt(202);
shapetype.setPath2("m,l,21600r21600,l21600,xe");
shapetype.addNewStroke().setJoinstyle(STStrokeJoinStyle.MITER);
CTPath path = shapetype.addNewPath();
path.setGradientshapeok(STTrueFalse.T);
path.setConnecttype(STConnectType.RECT);
_items.add(shapetype);
_qnames.add(QNAME_SHAPE_TYPE);
}

protected CTShape newCommentShape(){
CTShape shape = CTShape.Factory.newInstance();
shape.setId("_x0000_s" + (++_shapeId));
shape.setType("#" + _shapeTypeId);
shape.setStyle("position:absolute; visibility:hidden");
shape.setFillcolor("#ffffe1");
shape.setInsetmode(STInsetMode.AUTO);
shape.addNewFill().setColor("#ffffe1");
CTShadow shadow = shape.addNewShadow();
shadow.setOn(STTrueFalse.T);
shadow.setColor("black");
shadow.setObscured(STTrueFalse.T);
shape.addNewPath().setConnecttype(STConnectType.NONE);
shape.addNewTextbox().setStyle("mso-direction-alt:auto");
CTClientData cldata = shape.addNewClientData();
cldata.setObjectType(STObjectType.NOTE);
cldata.addNewMoveWithCells();
cldata.addNewSizeWithCells();
cldata.addNewAnchor().setStringValue("1, 15, 0, 2, 3, 15, 3, 16");
cldata.addNewAutoFill().setStringValue("False");
cldata.addNewRow().setBigIntegerValue(new BigInteger("0"));
cldata.addNewColumn().setBigIntegerValue(new BigInteger("0"));
_items.add(shape);
_qnames.add(QNAME_SHAPE);
return shape;
}

/**
* Find a shape with ClientData of type "NOTE" and the specified row and column
*
* @return the comment shape or <code>null</code>
*/
protected CTShape findCommentShape(int row, int col){
for(XmlObject itm : _items){
if(itm instanceof CTShape){
CTShape sh = (CTShape)itm;
if(sh.sizeOfClientDataArray() > 0){
CTClientData cldata = sh.getClientDataArray(0);
if(cldata.getObjectType() == STObjectType.NOTE){
int crow = cldata.getRowArray(0).intValue();
int ccol = cldata.getColumnArray(0).intValue();
if(crow == row && ccol == col) {
return sh;
}
}
}
}
}
return null;
}

protected boolean removeCommentShape(int row, int col){
CTShape shape = findCommentShape(row, col);
return shape != null && _items.remove(shape);
}
}

+ 50
- 100
src/ooxml/testcases/org/apache/poi/xssf/model/TestCommentsTable.java View File

@@ -25,10 +25,7 @@ import junit.framework.AssertionFailedError;
import junit.framework.TestCase;

import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.XSSFTestDataSamples;
import org.apache.poi.xssf.usermodel.XSSFComment;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
@@ -47,32 +44,24 @@ public class TestCommentsTable extends TestCase {
private static final String TEST_A1_TEXT = "test A1 text";
private static final String TEST_AUTHOR = "test author";

public void testfindAuthor() throws Exception {
CommentsDocument doc = CommentsDocument.Factory.newInstance();
doc.setComments(CTComments.Factory.newInstance());
ByteArrayOutputStream out = new ByteArrayOutputStream();
doc.save(out, POIXMLDocumentPart.DEFAULT_XML_OPTIONS);
public void testFindAuthor() throws Exception {
CommentsTable sheetComments = new CommentsTable();
sheetComments.readFrom(new ByteArrayInputStream(out.toByteArray()));

assertEquals(0, sheetComments.findAuthor(TEST_AUTHOR));
assertEquals(1, sheetComments.findAuthor("another author"));
assertEquals(0, sheetComments.findAuthor(TEST_AUTHOR));
assertEquals(2, sheetComments.findAuthor("YAA"));
assertEquals(1, sheetComments.findAuthor("another author"));
assertEquals(1, sheetComments.getNumberOfAuthors());
assertEquals(0, sheetComments.findAuthor(""));
assertEquals("", sheetComments.getAuthor(0));

assertEquals(1, sheetComments.findAuthor(TEST_AUTHOR));
assertEquals(2, sheetComments.findAuthor("another author"));
assertEquals(1, sheetComments.findAuthor(TEST_AUTHOR));
assertEquals(3, sheetComments.findAuthor("YAA"));
assertEquals(2, sheetComments.findAuthor("another author"));
}

public void testGetCellComment() throws Exception {
CommentsDocument doc = CommentsDocument.Factory.newInstance();
doc.setComments(CTComments.Factory.newInstance());
ByteArrayOutputStream out = new ByteArrayOutputStream();
doc.save(out, POIXMLDocumentPart.DEFAULT_XML_OPTIONS);
CommentsTable sheetComments = new CommentsTable();
sheetComments.readFrom(new ByteArrayInputStream(out.toByteArray()));


CTComments comments = sheetComments.getCTComments();
CTCommentList commentList = comments.addNewCommentList();
CTCommentList commentList = comments.getCommentList();

// Create 2 comments for A1 and A" cells
CTComment comment0 = commentList.insertNewComment(0);
@@ -87,86 +76,14 @@ public class TestCommentsTable extends TestCase {
comment1.setText(ctrst1);

// test finding the right comment for a cell
assertEquals(TEST_A1_TEXT, sheetComments.findCellComment("A1").getString().getString());
assertEquals(TEST_A1_TEXT, sheetComments.findCellComment(0, 0).getString().getString());
assertEquals(TEST_A2_TEXT, sheetComments.findCellComment("A2").getString().getString());
assertEquals(TEST_A2_TEXT, sheetComments.findCellComment(1, 0).getString().getString());
assertNull(sheetComments.findCellComment("A3"));
assertNull(sheetComments.findCellComment(2, 0));
}

public void testAddCellComment() throws Exception {
CommentsDocument doc = CommentsDocument.Factory.newInstance();
doc.setComments(CTComments.Factory.newInstance());
ByteArrayOutputStream out = new ByteArrayOutputStream();
doc.save(out, POIXMLDocumentPart.DEFAULT_XML_OPTIONS);
CommentsTable sheetComments = new CommentsTable();
sheetComments.readFrom(new ByteArrayInputStream(out.toByteArray()));

CTCommentList commentList = sheetComments.getCTComments().addNewCommentList();
assertEquals(0, commentList.sizeOfCommentArray());

XSSFComment comment = sheetComments.addComment();
comment.setAuthor("test A1 author");
comment.setRow(0);
comment.setColumn((short)0);

assertEquals(1, commentList.sizeOfCommentArray());
assertEquals("test A1 author", sheetComments.getAuthor(commentList.getCommentArray(0).getAuthorId()));
assertEquals("test A1 author", comment.getAuthor());

// Change the author, check it updates
comment.setAuthor("Another Author");
assertEquals(1, commentList.sizeOfCommentArray());
assertEquals("Another Author", comment.getAuthor());
assertSame(comment0, sheetComments.getCTComment("A1"));
assertSame(comment1, sheetComments.getCTComment("A2"));
assertNull(sheetComments.getCTComment("A3"));
}

public void testDontLoostNewLines() {
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithVariousData.xlsx");
List<POIXMLDocumentPart> rels = wb.getSheetAt(0).getRelations();
CommentsTable ct = null;
for(POIXMLDocumentPart p : rels) {
if(p instanceof CommentsTable){
ct = (CommentsTable)p;
break;
}
}
if (ct == null) {
throw new AssertionFailedError("didn't find comments table");
}
assertEquals(2, ct.getNumberOfComments());
assertEquals(1, ct.getNumberOfAuthors());

XSSFComment comment = ct.findCellComment("C5");

assertEquals("Nick Burch", comment.getAuthor());
assertEquals("Nick Burch:\nThis is a comment", comment.getString().getString());

wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
rels = wb.getSheetAt(0).getRelations();
ct = null;
for(POIXMLDocumentPart p : rels) {
if(p instanceof CommentsTable){
ct = (CommentsTable)p;
break;
}
}
if (ct == null) {
throw new AssertionFailedError("didn't find comments table");
}

assertEquals(2, ct.getNumberOfComments());
assertEquals(1, ct.getNumberOfAuthors());

comment = ct.findCellComment("C5");

assertEquals("Nick Burch", comment.getAuthor());

assertEquals("Nick Burch:\nThis is a comment", comment.getString().getString());
}

public void testExisting() {
XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("WithVariousData.xlsx");
Workbook workbook = XSSFTestDataSamples.openSampleWorkbook("WithVariousData.xlsx");
Sheet sheet1 = workbook.getSheetAt(0);
Sheet sheet2 = workbook.getSheetAt(1);

@@ -238,7 +155,7 @@ public class TestCommentsTable extends TestCase {
assertEquals("Also POI",
sheet2.getRow(2).getCell(1).getCellComment().getAuthor());

assertEquals("Nick Burch:\nThis is a comment",
assertEquals("Hello!",
sheet1.getRow(4).getCell(2).getCellComment().getString().getString());
}

@@ -276,4 +193,37 @@ public class TestCommentsTable extends TestCase {

// Todo - check text too, once bug fixed
}

public void testRemoveComment() throws Exception {
CommentsTable sheetComments = new CommentsTable();
CTComment a1 = sheetComments.newComment();
a1.setRef("A1");
CTComment a2 = sheetComments.newComment();
a2.setRef("A2");
CTComment a3 = sheetComments.newComment();
a3.setRef("A3");

assertSame(a1, sheetComments.getCTComment("A1"));
assertSame(a2, sheetComments.getCTComment("A2"));
assertSame(a3, sheetComments.getCTComment("A3"));
assertEquals(3, sheetComments.getNumberOfComments());

assertTrue(sheetComments.removeComment("A1"));
assertEquals(2, sheetComments.getNumberOfComments());
assertNull(sheetComments.getCTComment("A1"));
assertSame(a2, sheetComments.getCTComment("A2"));
assertSame(a3, sheetComments.getCTComment("A3"));

assertTrue(sheetComments.removeComment("A2"));
assertEquals(1, sheetComments.getNumberOfComments());
assertNull(sheetComments.getCTComment("A1"));
assertNull(sheetComments.getCTComment("A2"));
assertSame(a3, sheetComments.getCTComment("A3"));

assertTrue(sheetComments.removeComment("A3"));
assertEquals(0, sheetComments.getNumberOfComments());
assertNull(sheetComments.getCTComment("A1"));
assertNull(sheetComments.getCTComment("A2"));
assertNull(sheetComments.getCTComment("A3"));
}
}

+ 137
- 131
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFComment.java View File

@@ -18,171 +18,177 @@
package org.apache.poi.xssf.usermodel;

import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.model.CommentsTable;
import org.apache.poi.xssf.XSSFTestDataSamples;
import org.apache.poi.xssf.XSSFITestDataProvider;
import org.apache.poi.POIXMLDocumentPart;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAuthors;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComments;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CommentsDocument;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;

import junit.framework.TestCase;
import junit.framework.AssertionFailedError;

import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;

import schemasMicrosoftComVml.CTShape;

public class TestXSSFComment extends TestCase {

public class TestXSSFComment extends BaseTestCellComment {

private static final String TEST_RICHTEXTSTRING = "test richtextstring";
private static final String TEST_AUTHOR = "test_author";

public void testConstructors() {
CommentsTable sheetComments = new CommentsTable();
XSSFComment comment = sheetComments.addComment();
assertNotNull(comment);
@Override
protected XSSFITestDataProvider getTestDataProvider(){
return XSSFITestDataProvider.getInstance();
}

CTComment ctComment = CTComment.Factory.newInstance();
XSSFComment comment2 = new XSSFComment(sheetComments, ctComment);
assertNotNull(comment2);
/**
* test that we can read cell comments from an existing workbook.
*/
public void testReadComments() {
readComments("SimpleWithComments.xlsx");
}

public void testGetColumn() {
CommentsTable sheetComments = new CommentsTable();
CTComment ctComment = CTComment.Factory.newInstance();
ctComment.setRef("A1");
XSSFComment comment = new XSSFComment(sheetComments, ctComment);
assertNotNull(comment);
assertEquals(0, comment.getColumn());
ctComment.setRef("C10");
assertEquals(2, comment.getColumn());
/**
* test that we can modify existing cell comments
*/
public void testModifyComments() throws IOException {
modifyComments("SimpleWithComments.xlsx");
}

public void testGetRow() {
CommentsTable sheetComments = new CommentsTable();
CTComment ctComment = CTComment.Factory.newInstance();
ctComment.setRef("A1");
XSSFComment comment = new XSSFComment(sheetComments, ctComment);
assertNotNull(comment);
assertEquals(0, comment.getRow());
ctComment.setRef("C10");
assertEquals(9, comment.getRow());
public void testDeleteComments() throws Exception {
deleteComments("SimpleWithComments.xlsx");
}

public void testGetAuthor() throws Exception {
CommentsDocument doc = CommentsDocument.Factory.newInstance();
CTComments ctComments = CTComments.Factory.newInstance();
CTComment ctComment = ctComments.addNewCommentList().addNewComment();
CTAuthors ctAuthors = ctComments.addNewAuthors();
ctAuthors.insertAuthor(0, TEST_AUTHOR);
ctComment.setAuthorId(0);
doc.setComments(ctComments);
/**
* test properties of a newly constructed comment
*/
public void testConstructor() {
CommentsTable sheetComments = new CommentsTable();
assertNotNull(sheetComments.getCTComments().getCommentList());
assertNotNull(sheetComments.getCTComments().getAuthors());
assertEquals(1, sheetComments.getCTComments().getAuthors().sizeOfAuthorArray());
assertEquals(1, sheetComments.getNumberOfAuthors());

ByteArrayOutputStream out = new ByteArrayOutputStream();
doc.save(out, POIXMLDocumentPart.DEFAULT_XML_OPTIONS);
CTComment ctComment = sheetComments.newComment();
CTShape vmlShape = CTShape.Factory.newInstance();

CommentsTable sheetComments = new CommentsTable();
sheetComments.readFrom(new ByteArrayInputStream(out.toByteArray()));
XSSFComment comment = new XSSFComment(sheetComments, ctComment);
assertEquals(TEST_AUTHOR, comment.getAuthor());
XSSFComment comment = new XSSFComment(sheetComments, ctComment, vmlShape);
assertEquals(null, comment.getString());
assertEquals(0, comment.getRow());
assertEquals(0, comment.getColumn());
assertEquals("", comment.getAuthor());
assertEquals(false, comment.isVisible());
}

public void testSetColumn() {
public void testGetSetCol() {
CommentsTable sheetComments = new CommentsTable();
CTComment ctComment = CTComment.Factory.newInstance();
XSSFComment comment = new XSSFComment(sheetComments, ctComment);
comment.setColumn((short)3);
assertEquals(3, comment.getColumn());
assertEquals(3, (new CellReference(ctComment.getRef()).getCol()));
assertEquals("D1", ctComment.getRef());

comment.setColumn((short)13);
assertEquals(13, comment.getColumn());
XSSFVMLDrawing vml = new XSSFVMLDrawing();
CTComment ctComment = sheetComments.newComment();
CTShape vmlShape = vml.newCommentShape();

XSSFComment comment = new XSSFComment(sheetComments, ctComment, vmlShape);
comment.setColumn(1);
assertEquals(1, comment.getColumn());
assertEquals(1, new CellReference(ctComment.getRef()).getCol());
assertEquals(1, vmlShape.getClientDataArray(0).getColumnArray(0).intValue());

comment.setColumn(5);
assertEquals(5, comment.getColumn());
assertEquals(5, new CellReference(ctComment.getRef()).getCol());
assertEquals(5, vmlShape.getClientDataArray(0).getColumnArray(0).intValue());
}

public void testSetRow() {
public void testGetSetRow() {
CommentsTable sheetComments = new CommentsTable();
CTComment ctComment = CTComment.Factory.newInstance();
XSSFComment comment = new XSSFComment(sheetComments, ctComment);
comment.setRow(20);
assertEquals(20, comment.getRow());
assertEquals(20, (new CellReference(ctComment.getRef()).getRow()));
assertEquals("A21", ctComment.getRef());

comment.setRow(19);
assertEquals(19, comment.getRow());
XSSFVMLDrawing vml = new XSSFVMLDrawing();
CTComment ctComment = sheetComments.newComment();
CTShape vmlShape = vml.newCommentShape();

XSSFComment comment = new XSSFComment(sheetComments, ctComment, vmlShape);
comment.setRow(1);
assertEquals(1, comment.getRow());
assertEquals(1, new CellReference(ctComment.getRef()).getRow());
assertEquals(1, vmlShape.getClientDataArray(0).getRowArray(0).intValue());

comment.setRow(5);
assertEquals(5, comment.getRow());
assertEquals(5, new CellReference(ctComment.getRef()).getRow());
assertEquals(5, vmlShape.getClientDataArray(0).getRowArray(0).intValue());
}

public void testSetAuthor() {
CommentsTable sheetComments = new CommentsTable();
CTComment ctComment = CTComment.Factory.newInstance();
XSSFComment comment = new XSSFComment(sheetComments, ctComment);
comment.setAuthor(TEST_AUTHOR);
assertEquals(TEST_AUTHOR, comment.getAuthor());
public void testSetString() {
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sh = wb.createSheet();
XSSFComment comment = sh.createDrawingPatriarch().createCellComment(new XSSFClientAnchor());

//passing HSSFRichTextString is incorrect
try {
comment.setString(new HSSFRichTextString(TEST_RICHTEXTSTRING));
fail("expected exception");
} catch (IllegalArgumentException e){
;
}

//simple string argument
comment.setString(TEST_RICHTEXTSTRING);
assertEquals(TEST_RICHTEXTSTRING, comment.getString().getString());

//if the text is already set, it should be overridden, not added twice!
comment.setString(TEST_RICHTEXTSTRING);

CTComment ctComment = comment.getCTComment();
XmlObject[] obj = ctComment.selectPath(
"declare namespace w='http://schemas.openxmlformats.org/spreadsheetml/2006/main' .//w:text");
assertEquals(1, obj.length);
assertEquals(TEST_RICHTEXTSTRING, comment.getString().getString());

//sequential call of comment.getString() should return the same XSSFRichTextString object
assertSame(comment.getString(), comment.getString());

XSSFRichTextString richText = new XSSFRichTextString(TEST_RICHTEXTSTRING);
XSSFFont font1 = wb.createFont();
font1.setFontName("Tahoma");
font1.setFontHeight(8.5);
font1.setItalic(true);
font1.setColor(IndexedColors.BLUE_GREY.getIndex());
richText.applyFont(0, 5, font1);

//check the low-level stuff
comment.setString(richText);
obj = ctComment.selectPath(
"declare namespace w='http://schemas.openxmlformats.org/spreadsheetml/2006/main' .//w:text");
assertEquals(1, obj.length);
assertSame(comment.getString(), richText);
//check that the rich text is set in the comment
CTRPrElt rPr = richText.getCTRst().getRArray(0).getRPr();
assertEquals(true, rPr.getIArray()[0].getVal());
assertEquals(8.5, rPr.getSzArray()[0].getVal());
assertEquals(IndexedColors.BLUE_GREY.getIndex(), rPr.getColorArray()[0].getIndexed());
assertEquals("Tahoma", rPr.getRFontArray()[0].getVal());
}

public void testSetString() {
public void testAuthor() {
CommentsTable sheetComments = new CommentsTable();
CTComment ctComment = CTComment.Factory.newInstance();
XSSFComment comment = new XSSFComment(sheetComments, ctComment);
RichTextString richTextString = new HSSFRichTextString(TEST_RICHTEXTSTRING);
comment.setString(richTextString);
assertEquals(TEST_RICHTEXTSTRING, ctComment.getText().getT());
CTComment ctComment = sheetComments.newComment();

assertEquals(1, sheetComments.getNumberOfAuthors());
XSSFComment comment = new XSSFComment(sheetComments, ctComment, null);
assertEquals("", comment.getAuthor());
comment.setAuthor("Apache POI");
assertEquals("Apache POI", comment.getAuthor());
assertEquals(2, sheetComments.getNumberOfAuthors());
comment.setAuthor("Apache POI");
assertEquals(2, sheetComments.getNumberOfAuthors());
comment.setAuthor("");
assertEquals("", comment.getAuthor());
assertEquals(2, sheetComments.getNumberOfAuthors());
}

/**
* Tests that we can add comments to a new
* file, save, load, and still see them
* @throws Exception
*/
public void testCreateSave() {
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet s1 = wb.createSheet();
Row r1 = s1.createRow(0);
Cell r1c1 = r1.createCell(0);
r1c1.setCellValue(2.2);

assertEquals(0, s1.getNumberOfComments());

Comment c1 = s1.createComment();
c1.setAuthor("Author 1");
c1.setString(new XSSFRichTextString("Comment 1"));
r1c1.setCellComment(c1);

assertEquals(1, s1.getNumberOfComments());

// Save and re-load
wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
s1 = wb.getSheetAt(0);

assertEquals(1, s1.getNumberOfComments());
assertNotNull(s1.getRow(0).getCell(0).getCellComment());
assertEquals("Author 1", s1.getRow(0).getCell(0).getCellComment().getAuthor());
assertEquals("Comment 1", s1.getRow(0).getCell(0).getCellComment().getString().getString());

// Now add an orphaned one
Comment c2 = s1.createComment();
c2.setAuthor("Author 2");
c2.setString(new XSSFRichTextString("Second Comment"));
c2.setRow(0);
c2.setColumn((short)1);
assertEquals(2, s1.getNumberOfComments());

// Save and re-load

wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
s1 = wb.getSheetAt(0);

assertEquals(2, s1.getNumberOfComments());
assertNotNull(s1.getCellComment(0, 0));
assertNotNull(s1.getCellComment(0, 1));

assertEquals("Author 1", s1.getCellComment(0, 0).getAuthor());
assertEquals("Author 2", s1.getCellComment(0, 1).getAuthor());
}
}

+ 39
- 1
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java View File

@@ -177,7 +177,7 @@ public class TestXSSFSheet extends BaseTestSheet {
XSSFComment comment = sheet.createComment();

Cell cell = sheet.createRow(0).createCell((short) 0);
CommentsTable comments = sheet.getCommentsTable();
CommentsTable comments = sheet.getCommentsTable(false);
CTComments ctComments = comments.getCTComments();

sheet.setCellComment("A1", comment);
@@ -843,4 +843,42 @@ public class TestXSSFSheet extends BaseTestSheet {
assertFalse(sheet.isColumnHidden(4));
assertFalse(sheet.isColumnHidden(5));
}

public void testCommentsTable() {
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet1 = workbook.createSheet();
CommentsTable comment1 = sheet1.getCommentsTable(false);
assertNull(comment1);

comment1 = sheet1.getCommentsTable(true);
assertNotNull(comment1);
assertEquals("/xl/comments1.xml", comment1.getPackageRelationship().getTargetURI().toString());

assertSame(comment1, sheet1.getCommentsTable(true));

//second sheet
XSSFSheet sheet2 = workbook.createSheet();
CommentsTable comment2 = sheet2.getCommentsTable(false);
assertNull(comment2);

comment2 = sheet2.getCommentsTable(true);
assertNotNull(comment2);

assertSame(comment2, sheet2.getCommentsTable(true));
assertEquals("/xl/comments2.xml", comment2.getPackageRelationship().getTargetURI().toString());

//comment1 and comment2 are different objects
assertNotSame(comment1, comment2);

//now test against a workbook containing cell comments
workbook = XSSFTestDataSamples.openSampleWorkbook("WithMoreVariousData.xlsx");
sheet1 = workbook.getSheetAt(0);
comment1 = sheet1.getCommentsTable(true);
assertNotNull(comment1);
assertEquals("/xl/comments1.xml", comment1.getPackageRelationship().getTargetURI().toString());
assertSame(comment1, sheet1.getCommentsTable(true));


}

}

+ 139
- 0
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFVMLDrawing.java View File

@@ -0,0 +1,139 @@
/* ====================================================================
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.xssf.usermodel;

import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.util.List;

import junit.framework.TestCase;

import org.apache.poi.POIDataSamples;
import org.apache.xmlbeans.XmlObject;
import schemasMicrosoftComVml.*;
import schemasMicrosoftComOfficeOffice.CTShapeLayout;
import schemasMicrosoftComOfficeOffice.STConnectType;
import schemasMicrosoftComOfficeOffice.STInsetMode;
import schemasMicrosoftComOfficeExcel.CTClientData;
import schemasMicrosoftComOfficeExcel.STObjectType;

/**
* @author Yegor Kozlov
*/
public class TestXSSFVMLDrawing extends TestCase {

public void testNew() throws Exception {
XSSFVMLDrawing vml = new XSSFVMLDrawing();
List<XmlObject> items = vml.getItems();
assertEquals(2, items.size());
assertTrue(items.get(0) instanceof CTShapeLayout);
CTShapeLayout layout = (CTShapeLayout)items.get(0);
assertEquals(STExt.EDIT, layout.getExt());
assertEquals(STExt.EDIT, layout.getIdmap().getExt());
assertEquals("1", layout.getIdmap().getData());
assertTrue(items.get(1) instanceof CTShapetype);
CTShapetype type = (CTShapetype)items.get(1);
assertEquals("21600,21600", type.getCoordsize());
assertEquals(202.0f, type.getSpt());
assertEquals("m,l,21600r21600,l21600,xe", type.getPath2());
assertEquals("_xssf_cell_comment", type.getId());
assertEquals(STTrueFalse.T, type.getPathArray(0).getGradientshapeok());
assertEquals(STConnectType.RECT, type.getPathArray(0).getConnecttype());

CTShape shape = vml.newCommentShape();
assertEquals(3, items.size());
assertSame(items.get(2), shape);
assertEquals("#_xssf_cell_comment", shape.getType());
assertEquals("position:absolute; visibility:hidden", shape.getStyle());
assertEquals("#ffffe1", shape.getFillcolor());
assertEquals(STInsetMode.AUTO, shape.getInsetmode());
assertEquals("#ffffe1", shape.getFillArray(0).getColor());
CTShadow shadow = shape.getShadowArray(0);
assertEquals(STTrueFalse.T, shadow.getOn());
assertEquals("black", shadow.getColor());
assertEquals(STTrueFalse.T, shadow.getObscured());
assertEquals(STConnectType.NONE, shape.getPathArray(0).getConnecttype());
assertEquals("mso-direction-alt:auto", shape.getTextboxArray(0).getStyle());
CTClientData cldata = shape.getClientDataArray(0);
assertEquals(STObjectType.NOTE, cldata.getObjectType());
assertEquals(1, cldata.sizeOfMoveWithCellsArray());
assertEquals(1, cldata.sizeOfSizeWithCellsArray());
assertEquals("1, 15, 0, 2, 3, 15, 3, 16", cldata.getAnchorArray(0));
assertEquals("False", cldata.getAutoFillArray(0).toString());
assertEquals(0, cldata.getRowArray(0).intValue());
assertEquals(0, cldata.getColumnArray(0).intValue());

//serialize and read again
ByteArrayOutputStream out = new ByteArrayOutputStream();
vml.write(out);

XSSFVMLDrawing vml2 = new XSSFVMLDrawing();
vml2.read(new ByteArrayInputStream(out.toByteArray()));
List<XmlObject> items2 = vml2.getItems();
assertEquals(3, items2.size());
assertTrue(items2.get(0) instanceof CTShapeLayout);
assertTrue(items2.get(1) instanceof CTShapetype);
assertTrue(items2.get(2) instanceof CTShape);
}

public void testFindCommentShape() throws Exception {
XSSFVMLDrawing vml = new XSSFVMLDrawing();
vml.read(POIDataSamples.getSpreadSheetInstance().openResourceAsStream("vmlDrawing1.vml"));

CTShape sh_a1 = vml.findCommentShape(0, 0);
assertNotNull(sh_a1);
assertEquals("_x0000_s1025", sh_a1.getId());

CTShape sh_b1 = vml.findCommentShape(0, 1);
assertNotNull(sh_b1);
assertEquals("_x0000_s1026", sh_b1.getId());

CTShape sh_c1 = vml.findCommentShape(0, 2);
assertNull(sh_c1);

CTShape sh_d1 = vml.newCommentShape();
assertEquals("_x0000_s1027", sh_d1.getId());
sh_d1.getClientDataArray(0).setRowArray(0, new BigInteger("0"));
sh_d1.getClientDataArray(0).setColumnArray(0, new BigInteger("3"));
assertSame(sh_d1, vml.findCommentShape(0, 3));

//newly created drawing
XSSFVMLDrawing newVml = new XSSFVMLDrawing();
assertNull(newVml.findCommentShape(0, 0));

sh_a1 = newVml.newCommentShape();
assertEquals("_x0000_s1025", sh_a1.getId());
sh_a1.getClientDataArray(0).setRowArray(0, new BigInteger("0"));
sh_a1.getClientDataArray(0).setColumnArray(0, new BigInteger("1"));
assertSame(sh_a1, newVml.findCommentShape(0, 1));
}

public void testRemoveCommentShape() throws Exception {
XSSFVMLDrawing vml = new XSSFVMLDrawing();
vml.read(POIDataSamples.getSpreadSheetInstance().openResourceAsStream("vmlDrawing1.vml"));

CTShape sh_a1 = vml.findCommentShape(0, 0);
assertNotNull(sh_a1);

assertTrue(vml.removeCommentShape(0, 0));
assertNull(vml.findCommentShape(0, 0));

}
}

+ 16
- 179
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFComment.java View File

@@ -16,208 +16,45 @@
==================================================================== */
package org.apache.poi.hssf.usermodel;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import junit.framework.TestCase;

import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.hssf.HSSFITestDataProvider;
import org.apache.poi.ss.usermodel.BaseTestCellComment;

/**
* Tests TestHSSFCellComment.
*
* @author Yegor Kozlov
*/
public final class TestHSSFComment extends TestCase {

/**
* Test that we can create cells and add comments to it.
*/
public static void testWriteComments() throws Exception {
String cellText = "Hello, World";
String commentText = "We can set comments in POI";
String commentAuthor = "Apache Software Foundation";
int cellRow = 3;
int cellColumn = 1;

HSSFWorkbook wb = new HSSFWorkbook();

HSSFSheet sheet = wb.createSheet();

HSSFCell cell = sheet.createRow(cellRow).createCell(cellColumn);
cell.setCellValue(new HSSFRichTextString(cellText));
assertNull(cell.getCellComment());

HSSFPatriarch patr = sheet.createDrawingPatriarch();
HSSFClientAnchor anchor = new HSSFClientAnchor();
anchor.setAnchor( (short)4, 2, 0, 0, (short) 6, 5, 0, 0);
HSSFComment comment = patr.createComment(anchor);
HSSFRichTextString string1 = new HSSFRichTextString(commentText);
comment.setString(string1);
comment.setAuthor(commentAuthor);
cell.setCellComment(comment);
if (false) {
// TODO - the following line should break this test, but it doesn't
cell.removeCellComment();
}

//verify our settings
assertEquals(HSSFSimpleShape.OBJECT_TYPE_COMMENT, comment.getShapeType());
assertEquals(commentAuthor, comment.getAuthor());
assertEquals(commentText, comment.getString().getString());
assertEquals(cellRow, comment.getRow());
assertEquals(cellColumn, comment.getColumn());

//serialize the workbook and read it again
ByteArrayOutputStream out = new ByteArrayOutputStream();
wb.write(out);
out.close();
public final class TestHSSFComment extends BaseTestCellComment {

wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
sheet = wb.getSheetAt(0);
cell = sheet.getRow(cellRow).getCell(cellColumn);
comment = cell.getCellComment();

assertNotNull(comment);
assertEquals(HSSFSimpleShape.OBJECT_TYPE_COMMENT, comment.getShapeType());
assertEquals(commentAuthor, comment.getAuthor());
assertEquals(commentText, comment.getString().getString());
assertEquals(cellRow, comment.getRow());
assertEquals(cellColumn, comment.getColumn());


// Change slightly, and re-test
comment.setString(new HSSFRichTextString("New Comment Text"));

out = new ByteArrayOutputStream();
wb.write(out);
out.close();

wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
sheet = wb.getSheetAt(0);
cell = sheet.getRow(cellRow).getCell(cellColumn);
comment = cell.getCellComment();
@Override
protected HSSFITestDataProvider getTestDataProvider(){
return HSSFITestDataProvider.getInstance();
}

assertNotNull(comment);
public static void testDefaultShapeType() throws Exception {
HSSFComment comment = new HSSFComment((HSSFShape)null, (HSSFAnchor)null);
assertEquals(HSSFSimpleShape.OBJECT_TYPE_COMMENT, comment.getShapeType());
assertEquals(commentAuthor, comment.getAuthor());
assertEquals("New Comment Text", comment.getString().getString());
assertEquals(cellRow, comment.getRow());
assertEquals(cellColumn, comment.getColumn());
}

/**
* test that we can read cell comments from an existing workbook.
*/
public static void testReadComments() {

HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SimpleWithComments.xls");

HSSFSheet sheet = wb.getSheetAt(0);

HSSFCell cell;
HSSFRow row;
HSSFComment comment;

for (int rownum = 0; rownum < 3; rownum++) {
row = sheet.getRow(rownum);
cell = row.getCell(0);
comment = cell.getCellComment();
assertNull("Cells in the first column are not commented", comment);
assertNull(sheet.getCellComment(rownum, 0));
}

for (int rownum = 0; rownum < 3; rownum++) {
row = sheet.getRow(rownum);
cell = row.getCell(1);
comment = cell.getCellComment();
assertNotNull("Cells in the second column have comments", comment);
assertNotNull("Cells in the second column have comments", sheet.getCellComment(rownum, 1));

assertEquals(HSSFSimpleShape.OBJECT_TYPE_COMMENT, comment.getShapeType());
assertEquals("Yegor Kozlov", comment.getAuthor());
assertFalse("cells in the second column have not empyy notes",
"".equals(comment.getString().getString()));
assertEquals(rownum, comment.getRow());
assertEquals(cell.getColumnIndex(), comment.getColumn());
}
}
public void testReadComments() {
readComments("SimpleWithComments.xls");
}

/**
* test that we can modify existing cell comments
*/
public static void testModifyComments() throws IOException {

HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SimpleWithComments.xls");

HSSFSheet sheet = wb.getSheetAt(0);

HSSFCell cell;
HSSFRow row;
HSSFComment comment;

for (int rownum = 0; rownum < 3; rownum++) {
row = sheet.getRow(rownum);
cell = row.getCell(1);
comment = cell.getCellComment();
comment.setAuthor("Mofified["+rownum+"] by Yegor");
comment.setString(new HSSFRichTextString("Modified comment at row " + rownum));
}

ByteArrayOutputStream out = new ByteArrayOutputStream();
wb.write(out);
out.close();

wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
sheet = wb.getSheetAt(0);

for (int rownum = 0; rownum < 3; rownum++) {
row = sheet.getRow(rownum);
cell = row.getCell(1);
comment = cell.getCellComment();

assertEquals("Mofified["+rownum+"] by Yegor", comment.getAuthor());
assertEquals("Modified comment at row " + rownum, comment.getString().getString());
}

}
public void testModifyComments() throws IOException {
modifyComments("SimpleWithComments.xls");
}

public void testDeleteComments() throws Exception {
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SimpleWithComments.xls");
HSSFSheet sheet = wb.getSheetAt(0);

// Zap from rows 1 and 3
assertNotNull(sheet.getRow(0).getCell(1).getCellComment());
assertNotNull(sheet.getRow(1).getCell(1).getCellComment());
assertNotNull(sheet.getRow(2).getCell(1).getCellComment());

sheet.getRow(0).getCell(1).removeCellComment();
sheet.getRow(2).getCell(1).setCellComment(null);

// Check gone so far
assertNull(sheet.getRow(0).getCell(1).getCellComment());
assertNotNull(sheet.getRow(1).getCell(1).getCellComment());
assertNull(sheet.getRow(2).getCell(1).getCellComment());

// Save and re-load
ByteArrayOutputStream out = new ByteArrayOutputStream();
wb.write(out);
out.close();
wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));

// Check
assertNull(sheet.getRow(0).getCell(1).getCellComment());
assertNotNull(sheet.getRow(1).getCell(1).getCellComment());
assertNull(sheet.getRow(2).getCell(1).getCellComment());

// FileOutputStream fout = new FileOutputStream("/tmp/c.xls");
// wb.write(fout);
// fout.close();
deleteComments("SimpleWithComments.xls");
}

/**

+ 246
- 0
src/testcases/org/apache/poi/ss/usermodel/BaseTestCellComment.java View File

@@ -0,0 +1,246 @@
/* ====================================================================
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.ss.usermodel;

import junit.framework.TestCase;

import org.apache.poi.ss.ITestDataProvider;

/**
* Common superclass for testing implementatiosn of
* {@link Comment}
*/
public abstract class BaseTestCellComment extends TestCase {

protected abstract ITestDataProvider getTestDataProvider();

public final void testFind() {
Workbook book = getTestDataProvider().createWorkbook();
Sheet sheet = book.createSheet();
assertNull(sheet.getCellComment(0, 0));

Row row = sheet.createRow(0);
Cell cell = row.createCell(0);
assertNull(sheet.getCellComment(0, 0));
assertNull(cell.getCellComment());
}

public final void testCreate() throws Exception {
String cellText = "Hello, World";
String commentText = "We can set comments in POI";
String commentAuthor = "Apache Software Foundation";
int cellRow = 3;
int cellColumn = 1;

Workbook wb = getTestDataProvider().createWorkbook();
CreationHelper factory = wb.getCreationHelper();

Sheet sheet = wb.createSheet();
assertNull(sheet.getCellComment(cellRow, cellColumn));

Cell cell = sheet.createRow(cellRow).createCell(cellColumn);
cell.setCellValue(factory.createRichTextString(cellText));
assertNull(cell.getCellComment());
assertNull(sheet.getCellComment(cellRow, cellColumn));

Drawing patr = sheet.createDrawingPatriarch();
ClientAnchor anchor = factory.createClientAnchor();
anchor.setCol1(2);
anchor.setCol2(5);
anchor.setRow1(1);
anchor.setRow2(2);
Comment comment = patr.createCellComment(anchor);
assertFalse(comment.isVisible());
comment.setVisible(true);
assertTrue(comment.isVisible());
RichTextString string1 = factory.createRichTextString(commentText);
comment.setString(string1);
comment.setAuthor(commentAuthor);
cell.setCellComment(comment);
assertNotNull(cell.getCellComment());
assertNotNull(sheet.getCellComment(cellRow, cellColumn));

//verify our settings
assertEquals(commentAuthor, comment.getAuthor());
assertEquals(commentText, comment.getString().getString());
assertEquals(cellRow, comment.getRow());
assertEquals(cellColumn, comment.getColumn());

wb = getTestDataProvider().writeOutAndReadBack(wb);
sheet = wb.getSheetAt(0);
cell = sheet.getRow(cellRow).getCell(cellColumn);
comment = cell.getCellComment();

assertNotNull(comment);
assertEquals(commentAuthor, comment.getAuthor());
assertEquals(commentText, comment.getString().getString());
assertEquals(cellRow, comment.getRow());
assertEquals(cellColumn, comment.getColumn());
assertTrue(comment.isVisible());

// Change slightly, and re-test
comment.setString(factory.createRichTextString("New Comment Text"));
comment.setVisible(false);

wb = getTestDataProvider().writeOutAndReadBack(wb);

sheet = wb.getSheetAt(0);
cell = sheet.getRow(cellRow).getCell(cellColumn);
comment = cell.getCellComment();

assertNotNull(comment);
assertEquals(commentAuthor, comment.getAuthor());
assertEquals("New Comment Text", comment.getString().getString());
assertEquals(cellRow, comment.getRow());
assertEquals(cellColumn, comment.getColumn());
assertFalse(comment.isVisible());
}

/**
* test that we can read cell comments from an existing workbook.
*/
public void readComments(String sampleFile) {

Workbook wb = getTestDataProvider().openSampleWorkbook(sampleFile);

Sheet sheet = wb.getSheetAt(0);

Cell cell;
Row row;
Comment comment;

for (int rownum = 0; rownum < 3; rownum++) {
row = sheet.getRow(rownum);
cell = row.getCell(0);
comment = cell.getCellComment();
assertNull("Cells in the first column are not commented", comment);
assertNull(sheet.getCellComment(rownum, 0));
}

for (int rownum = 0; rownum < 3; rownum++) {
row = sheet.getRow(rownum);
cell = row.getCell(1);
comment = cell.getCellComment();
assertNotNull("Cells in the second column have comments", comment);
assertNotNull("Cells in the second column have comments", sheet.getCellComment(rownum, 1));

assertEquals("Yegor Kozlov", comment.getAuthor());
assertFalse("cells in the second column have not empyy notes",
"".equals(comment.getString().getString()));
assertEquals(rownum, comment.getRow());
assertEquals(cell.getColumnIndex(), comment.getColumn());
}
}

/**
* test that we can modify existing cell comments
*/
public void modifyComments(String sampleFile) {

Workbook wb = getTestDataProvider().openSampleWorkbook(sampleFile);
CreationHelper factory = wb.getCreationHelper();

Sheet sheet = wb.getSheetAt(0);

Cell cell;
Row row;
Comment comment;

for (int rownum = 0; rownum < 3; rownum++) {
row = sheet.getRow(rownum);
cell = row.getCell(1);
comment = cell.getCellComment();
comment.setAuthor("Mofified[" + rownum + "] by Yegor");
comment.setString(factory.createRichTextString("Modified comment at row " + rownum));
}

wb = getTestDataProvider().writeOutAndReadBack(wb);
sheet = wb.getSheetAt(0);

for (int rownum = 0; rownum < 3; rownum++) {
row = sheet.getRow(rownum);
cell = row.getCell(1);
comment = cell.getCellComment();

assertEquals("Mofified[" + rownum + "] by Yegor", comment.getAuthor());
assertEquals("Modified comment at row " + rownum, comment.getString().getString());
}

}

public void deleteComments(String sampleFile) throws Exception {
Workbook wb = getTestDataProvider().openSampleWorkbook(sampleFile);
Sheet sheet = wb.getSheetAt(0);

// Zap from rows 1 and 3
assertNotNull(sheet.getRow(0).getCell(1).getCellComment());
assertNotNull(sheet.getRow(1).getCell(1).getCellComment());
assertNotNull(sheet.getRow(2).getCell(1).getCellComment());

sheet.getRow(0).getCell(1).removeCellComment();
sheet.getRow(2).getCell(1).setCellComment(null);

// Check gone so far
assertNull(sheet.getRow(0).getCell(1).getCellComment());
assertNotNull(sheet.getRow(1).getCell(1).getCellComment());
assertNull(sheet.getRow(2).getCell(1).getCellComment());

// Save and re-load
wb = getTestDataProvider().writeOutAndReadBack(wb);
sheet = wb.getSheetAt(0);
// Check
assertNull(sheet.getRow(0).getCell(1).getCellComment());
assertNotNull(sheet.getRow(1).getCell(1).getCellComment());
assertNull(sheet.getRow(2).getCell(1).getCellComment());

}

/**
* code from the quick guide
*/
public void testQuickGuide(){
Workbook wb = getTestDataProvider().createWorkbook();

CreationHelper factory = wb.getCreationHelper();

Sheet sheet = wb.createSheet();

Cell cell = sheet.createRow(3).createCell(5);
cell.setCellValue("F4");

Drawing drawing = sheet.createDrawingPatriarch();

ClientAnchor anchor = factory.createClientAnchor();
Comment comment = drawing.createCellComment(anchor);
RichTextString str = factory.createRichTextString("Hello, World!");
comment.setString(str);
comment.setAuthor("Apache POI");
//assign the comment to the cell
cell.setCellComment(comment);

wb = getTestDataProvider().writeOutAndReadBack(wb);
sheet = wb.getSheetAt(0);
cell = sheet.getRow(3).getCell(5);
comment = cell.getCellComment();
assertNotNull(comment);
assertEquals("Hello, World!", comment.getString().getString());
assertEquals("Apache POI", comment.getAuthor());
assertEquals(3, comment.getRow());
assertEquals(5, comment.getColumn());
}
}

BIN
test-data/spreadsheet/SimpleWithComments.xlsx View File


+ 42
- 0
test-data/spreadsheet/vmlDrawing1.vml View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<xml xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel">
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1"/>
</o:shapelayout>
<v:shapetype id="_x0000_t202" coordsize="21600,21600" o:spt="202" path="m,l,21600r21600,l21600,xe">
<v:stroke joinstyle="miter"/>
<v:path gradientshapeok="t" o:connecttype="rect"/>
</v:shapetype>
<v:shape id="_x0000_s1025" type="#_x0000_t202" style="position:absolute; margin-left:59.25pt;margin-top:1.5pt;width:96pt;height:55.5pt;z-index:1; visibility:hidden" fillcolor="#ffffe1" o:insetmode="auto">
<v:fill color2="#ffffe1"/>
<v:shadow on="t" color="black" obscured="t"/>
<v:path o:connecttype="none"/>
<v:textbox style="mso-direction-alt:auto">
<div style="text-align:left"/>
</v:textbox>
<x:ClientData ObjectType="Note">
<x:MoveWithCells/>
<x:SizeWithCells/>
<x:Anchor>1, 15, 0, 2, 3, 15, 3, 16</x:Anchor>
<x:AutoFill>False</x:AutoFill>
<x:Row>0</x:Row>
<x:Column>0</x:Column>
</x:ClientData>
</v:shape>
<v:shape id="_x0000_s1026" type="#_x0000_t202" style="position:absolute; visibility:hidden" fillcolor="#ffffe1" o:insetmode="auto">
<v:fill color2="#ffffe1"/>
<v:shadow on="t" color="black" obscured="t"/>
<v:path o:connecttype="none"/>
<v:textbox style="mso-direction-alt:auto">
<div style="text-align:left"/>
</v:textbox>
<x:ClientData ObjectType="Note">
<x:MoveWithCells/>
<x:SizeWithCells/>
<x:Anchor>1, 15, 0, 2, 3, 15, 3, 16</x:Anchor>
<x:AutoFill>False</x:AutoFill>
<x:Row>0</x:Row>
<x:Column>1</x:Column>
</x:ClientData>
</v:shape>
</xml>

Loading…
Cancel
Save