diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index e0694f240..7e22d7cf2 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -21,6 +21,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.TreeMap; import org.apache.poi.ddf.EscherRecord; @@ -61,6 +62,7 @@ import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.DataValidation; import org.apache.poi.ss.usermodel.DataValidationHelper; import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.util.CellAddress; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.ss.util.CellReference; @@ -2044,11 +2046,23 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet { * Returns cell comment for the specified row and column * * @return cell comment or null if not found + * @deprecated as of 2015-11-23 (circa POI 3.14beta1). Use {@link #getCellComment(CellReference)} instead. */ + @Override public HSSFComment getCellComment(int row, int column) { return findCellComment(row, column); } + /** + * Returns cell comment for the specified row and column + * + * @return cell comment or null if not found + */ + @Override + public HSSFComment getCellComment(CellAddress ref) { + return findCellComment(ref.getRow(), ref.getColumn()); + } + /** * Get a Hyperlink in this sheet anchored at row, column * @@ -2238,6 +2252,43 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet { return null; } + /** + * Returns all cell comments on this sheet. + * @return A map of each Comment in the sheet, keyed on the cell address where + * the comment is located. + */ + @Override + public Map getCellComments() { + HSSFPatriarch patriarch = getDrawingPatriarch(); + if (null == patriarch) { + patriarch = createDrawingPatriarch(); + } + + Map locations = new TreeMap(); + findCellCommentLocations(patriarch, locations); + return locations; + } + /** + * Finds all cell comments in this sheet and adds them to the specified locations map + * + * @param container a container that may contain HSSFComments + * @param locations the map to store the HSSFComments in + */ + private void findCellCommentLocations(HSSFShapeContainer container, Map locations) { + for (Object object : container.getChildren()) { + HSSFShape shape = (HSSFShape) object; + if (shape instanceof HSSFShapeGroup) { + findCellCommentLocations((HSSFShapeGroup) shape, locations); + continue; + } + if (shape instanceof HSSFComment) { + HSSFComment comment = (HSSFComment) shape; + if (comment.hasPosition()) { + locations.put(new CellAddress(comment.getRow(), comment.getColumn()), comment); + } + } + } + } public CellRangeAddress getRepeatingRows() { return getRepeatingRowsOrColums(true); diff --git a/src/java/org/apache/poi/ss/usermodel/Sheet.java b/src/java/org/apache/poi/ss/usermodel/Sheet.java index 034b94de4..036fc279a 100644 --- a/src/java/org/apache/poi/ss/usermodel/Sheet.java +++ b/src/java/org/apache/poi/ss/usermodel/Sheet.java @@ -19,9 +19,12 @@ package org.apache.poi.ss.usermodel; import java.util.Iterator; import java.util.List; +import java.util.Map; import org.apache.poi.hssf.util.PaneInformation; +import org.apache.poi.ss.util.CellAddress; import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellReference; /** * High level representation of a Excel worksheet. @@ -890,8 +893,23 @@ public interface Sheet extends Iterable { * Returns cell comment for the specified row and column * * @return cell comment or null if not found + * @deprecated as of 2015-11-23 (circa POI 3.14beta1). Use {@link #getCellComment(CellReference)} instead. */ Comment getCellComment(int row, int column); + + /** + * Returns cell comment for the specified location + * + * @return cell comment or null if not found + */ + Comment getCellComment(CellAddress ref); + + /** + * Returns all cell comments on this sheet. + * @return A map of each Comment in the sheet, keyed on the cell address where + * the comment is located. + */ + Map getCellComments(); /** * Creates the top-level drawing patriarch. diff --git a/src/java/org/apache/poi/ss/util/CellAddress.java b/src/java/org/apache/poi/ss/util/CellAddress.java index 10dae8c11..76c0bb493 100644 --- a/src/java/org/apache/poi/ss/util/CellAddress.java +++ b/src/java/org/apache/poi/ss/util/CellAddress.java @@ -19,6 +19,8 @@ package org.apache.poi.ss.util; import java.util.Locale; +import org.apache.poi.ss.usermodel.Cell; + /** *

This class is a container for POI usermodel row=0 column=0 cell references. * It is barely a container for these two coordinates. The implementation @@ -85,6 +87,15 @@ public class CellAddress implements Comparable { this(reference.getRow(), reference.getCol()); } + /** + * Create a new CellAddress object. + * + * @param cell the Cell to get the location of + */ + public CellAddress(Cell cell) { + this(cell.getRowIndex(), cell.getColumnIndex()); + } + /** * Get the cell address row * diff --git a/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java b/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java index 60d95a6d2..a8efe5ac7 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java @@ -29,7 +29,6 @@ import java.util.TreeMap; import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; -import org.apache.poi.ss.usermodel.Comment; import org.apache.poi.ss.util.CellAddress; import org.apache.poi.util.Internal; import org.apache.poi.xssf.usermodel.XSSFComment; @@ -188,9 +187,9 @@ public class CommentsTable extends POIXMLDocumentPart { * @return A map of each Comment in this sheet, keyed on the cell address where * the comment is located. */ - public Map getCellComments(){ + public Map getCellComments() { prepareCTCommentCache(); - final TreeMap map = new TreeMap(); + final TreeMap map = new TreeMap(); for (final Entry e: commentRefs.entrySet()) { map.put(e.getKey(), new XSSFComment(this, e.getValue(), null)); diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java index 72e782adb..64554c4aa 100644 --- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java @@ -30,7 +30,6 @@ import org.apache.poi.ss.usermodel.AutoFilter; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellRange; import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.Comment; import org.apache.poi.ss.usermodel.DataValidation; import org.apache.poi.ss.usermodel.DataValidationHelper; import org.apache.poi.ss.usermodel.Drawing; @@ -41,8 +40,11 @@ import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.SheetConditionalFormatting; import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellAddress; import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.SheetUtil; +import org.apache.poi.xssf.usermodel.XSSFComment; import org.apache.poi.xssf.usermodel.XSSFDataValidation; import org.apache.poi.xssf.usermodel.XSSFHyperlink; import org.apache.poi.xssf.usermodel.XSSFSheet; @@ -1322,10 +1324,33 @@ public class SXSSFSheet implements Sheet, Cloneable * Returns cell comment for the specified row and column * * @return cell comment or null if not found + * @deprecated as of 2015-11-23 (circa POI 3.14beta1). Use {@link #getCellComment(CellReference)} instead. */ - public Comment getCellComment(int row, int column) + @Override + public XSSFComment getCellComment(int row, int column) { - return _sh.getCellComment(row, column); + return getCellComment(new CellAddress(row, column)); + } + + /** + * Returns cell comment for the specified row and column + * + * @return cell comment or null if not found + */ + @Override + public XSSFComment getCellComment(CellAddress ref) + { + return _sh.getCellComment(ref); + } + + /** + * Returns all cell comments on this sheet. + * @return A map of each Comment in the sheet, keyed on the cell address where + * the comment is located. + */ + @Override + public Map getCellComments() { + return _sh.getCellComments(); } /** diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java index 85f283a67..23ec7f7c5 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java @@ -39,6 +39,7 @@ import org.apache.poi.ss.usermodel.FormulaError; import org.apache.poi.ss.usermodel.Hyperlink; import org.apache.poi.ss.usermodel.RichTextString; import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.util.CellAddress; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellReference; import org.apache.poi.util.Beta; @@ -585,7 +586,7 @@ public final class XSSFCell implements Cell { public String getReference() { String ref = _cell.getR(); if(ref == null) { - return new CellReference(this).formatAsString(); + return new CellAddress(this).formatAsString(); } return ref; } @@ -1029,7 +1030,7 @@ public final class XSSFCell implements Cell { public void removeCellComment() { XSSFComment comment = getCellComment(); if(comment != null){ - String ref = getReference(); + CellAddress ref = new CellAddress(getReference()); XSSFSheet sh = getSheet(); sh.getCommentsTable(false).removeComment(ref); sh.getVMLDrawing(false).removeCommentShape(getRowIndex(), getColumnIndex()); diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFComment.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFComment.java index 642aa9e0f..1876fa072 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFComment.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFComment.java @@ -23,6 +23,7 @@ import java.math.BigInteger; import org.apache.poi.ss.usermodel.ClientAnchor; import org.apache.poi.ss.usermodel.Comment; import org.apache.poi.ss.usermodel.RichTextString; +import org.apache.poi.ss.util.CellAddress; import org.apache.poi.ss.util.CellReference; import org.apache.poi.xssf.model.CommentsTable; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment; @@ -130,9 +131,9 @@ public class XSSFComment implements Comment { * @param col the 0-based column of the cell that contains the comment */ public void setColumn(int col) { - String oldRef = _comment.getRef(); + CellAddress oldRef = new CellAddress(_comment.getRef()); - CellReference ref = new CellReference(getRow(), col); + CellAddress ref = new CellAddress(getRow(), col); _comment.setRef(ref.formatAsString()); _comments.referenceUpdated(oldRef, _comment); @@ -154,12 +155,11 @@ public class XSSFComment implements Comment { * @param row the 0-based row of the cell that contains the comment */ public void setRow(int row) { - String oldRef = _comment.getRef(); + CellAddress oldRef = new CellAddress(_comment.getRef()); - String newRef = - (new CellReference(row, getColumn())).formatAsString(); - _comment.setRef(newRef); - _comments.referenceUpdated(oldRef, _comment); + CellAddress ref = new CellAddress(row, getColumn()); + _comment.setRef(ref.formatAsString()); + _comments.referenceUpdated(oldRef, _comment); if(_vmlShape != null) { _vmlShape.getClientDataArray(0).setRowArray(0, diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java index 2f3853973..ba45cfff4 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java @@ -33,6 +33,7 @@ import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.TargetMode; import org.apache.poi.ss.usermodel.ClientAnchor; import org.apache.poi.ss.usermodel.Drawing; +import org.apache.poi.ss.util.CellAddress; import org.apache.poi.ss.util.CellReference; import org.apache.poi.util.Internal; import org.apache.poi.util.Units; @@ -316,7 +317,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing { ca.getRow2() + ", " + dy2Pixels; vmlShape.getClientDataArray(0).setAnchorArray(0, position); } - String ref = new CellReference(ca.getRow1(), ca.getCol1()).formatAsString(); + CellAddress ref = new CellAddress(ca.getRow1(), ca.getCol1()); if(comments.findCellComment(ref) != null) { throw new IllegalArgumentException("Multiple cell comments in one cell are not allowed, cell: " + ref); diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java index 6a35bf7d1..b2a4d9483 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java @@ -63,6 +63,7 @@ import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.AreaReference; +import org.apache.poi.ss.util.CellAddress; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.ss.util.CellReference; @@ -681,13 +682,34 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { getPane().setActivePane(STPane.Enum.forInt(activePane)); } + /** + * Return cell comment at row, column, if one exists. Otherwise returns null. + * @row the row where the comment is located + * @column the column where the comment is located + * @return the cell comment, if one exists. Otherwise return null. + * @deprecated as of 2015-11-23 (circa POI 3.14beta1). Use {@link #getCellComment(CellReference)} instead. + */ @Override public XSSFComment getCellComment(int row, int column) { + return getCellComment(new CellAddress(row, column)); + } + + /** + * Return cell comment at row, column, if one exists. Otherwise returns null. + * + * @param address the location of the cell comment + * @return the cell comment, if one exists. Otherwise return null. + */ + @Override + public XSSFComment getCellComment(CellAddress address) { if (sheetComments == null) { return null; } - String ref = new CellReference(row, column).formatAsString(); + final int row = address.getRow(); + final int column = address.getColumn(); + + CellAddress ref = new CellAddress(row, column); CTComment ctComment = sheetComments.getCTComment(ref); if(ctComment == null) return null; @@ -696,6 +718,16 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { vml == null ? null : vml.findCommentShape(row, column)); } + /** + * Returns all cell comments on this sheet. + * @return A map of each Comment in the sheet, keyed on the cell address where + * the comment is located. + */ + @Override + public Map getCellComments() { + return sheetComments.getCellComments(); + } + /** * Get a Hyperlink in this sheet anchored at row, column * @@ -2805,12 +2837,12 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { CTCommentList lst = sheetComments.getCTComments().getCommentList(); for (CTComment comment : lst.getCommentArray()) { String strRef = comment.getRef(); - CellReference ref = new CellReference(strRef); + CellAddress ref = new CellAddress(strRef); // is this comment part of the current row? if(ref.getRow() == rownum) { - sheetComments.removeComment(strRef); - vml.removeCommentShape(ref.getRow(), ref.getCol()); + sheetComments.removeComment(ref); + vml.removeCommentShape(ref.getRow(), ref.getColumn()); } } } diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java index e4151360f..c875f03ed 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java +++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheet.java @@ -23,10 +23,13 @@ import static org.junit.Assert.*; import java.io.IOException; import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; import org.apache.poi.hssf.util.PaneInformation; import org.apache.poi.ss.ITestDataProvider; import org.apache.poi.ss.SpreadsheetVersion; +import org.apache.poi.ss.util.CellAddress; import org.apache.poi.ss.util.CellRangeAddress; import org.junit.Rule; import org.junit.Test; @@ -1018,13 +1021,54 @@ public abstract class BaseTestSheet { comment.setAuthor("test C10 author"); cell.setCellComment(comment); - assertNotNull(sheet.getCellComment(9, 2)); - assertEquals("test C10 author", sheet.getCellComment(9, 2).getAuthor()); + CellAddress ref = new CellAddress(9, 2); + assertNotNull(sheet.getCellComment(ref)); + assertEquals("test C10 author", sheet.getCellComment(ref).getAuthor()); assertNotNull(_testDataProvider.writeOutAndReadBack(workbook)); workbook.close(); } + + + @Test + public void getCellComments() throws IOException { + Workbook workbook = _testDataProvider.createWorkbook(); + Sheet sheet = workbook.createSheet("TEST"); + Drawing dg = sheet.createDrawingPatriarch(); + + int nRows = 5; + int nCols = 6; + + for (int r=0; r=0; c--) { + Comment comment = dg.createCellComment(workbook.getCreationHelper().createClientAnchor()); + Cell cell = sheet.getRow(r).createCell(c); + comment.setAuthor("Author " + r); + RichTextString text = workbook.getCreationHelper().createRichTextString("Test comment at row=" + r + ", column=" + c); + comment.setString(text); + cell.setCellComment(comment); + } + } + + Workbook wb = _testDataProvider.writeOutAndReadBack(workbook); + Sheet sh = wb.getSheet("TEST"); + Map cellComments = sh.getCellComments(); + assertEquals(nRows*nCols, cellComments.size()); + + for (Entry e : cellComments.entrySet()) { + CellAddress ref = e.getKey(); + Comment aComment = e.getValue(); + assertEquals("Author " + ref.getRow(), aComment.getAuthor()); + String text = "Test comment at row=" + ref.getRow() + ", column=" + ref.getColumn(); + assertEquals(text, aComment.getString().getString()); + } + + workbook.close(); + wb.close(); + } @Test