git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@491629 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_0_RC1
@@ -47,6 +47,7 @@ | |||
<li><link href="#Outlining">Outlining</link></li> | |||
<li><link href="#Images">Images</link></li> | |||
<li><link href="#NamedRanges">Named Ranges and Named Cells</link></li> | |||
<li><link href="#CellComments">How to set cell comments</link></li> | |||
</ul> | |||
</section> | |||
<section><title>Features</title> | |||
@@ -1034,6 +1035,85 @@ | |||
</source> | |||
</section> | |||
<anchor id="CellComments"/> | |||
<section><title>Cell Comments</title> | |||
<p> | |||
In Excel a comment is a kind of a text shape, | |||
so inserting a comment is very similar to placing a text box in a worksheet: | |||
</p> | |||
<source> | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet sheet = wb.createSheet("Cell comments in POI HSSF"); | |||
// 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 | |||
HSSFCell cell1 = sheet.createRow(3).createCell((short)1); | |||
cell1.setCellValue(new HSSFRichTextString("Hello, World")); | |||
//anchor defines size and position of the comment in worksheet | |||
HSSFComment comment1 = patr.createComment(new HSSFClientAnchor(0, 0, 0, 0, (short)4, 2, (short) 6, 5)); | |||
// set text in the comment | |||
comment1.setString(new HSSFRichTextString("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 HSSFCell.setCellComment method | |||
cell1.setCellComment(comment1); | |||
//create another cell in row 6 | |||
HSSFCell cell2 = sheet.createRow(6).createCell((short)1); | |||
cell2.setCellValue(36.6); | |||
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 commnet is visible. | |||
*/ | |||
comment2.setRow(6); | |||
comment2.setColumn((short)1); | |||
FileOutputStream out = new FileOutputStream("poi_comment.xls"); | |||
wb.write(out); | |||
out.close(); | |||
</source> | |||
<p> | |||
Reading cell comments | |||
</p> | |||
<source> | |||
HSSFCell cell = sheet.get(3).getColumn((short)1); | |||
HSSFComment comment = cell.getCellComment(); | |||
if (comment != null) { | |||
HSSFRichTextString str = comment.getString(); | |||
String author = comment.getAuthor(); | |||
} | |||
</source> | |||
</section> | |||
</body> | |||
</document> |
@@ -0,0 +1,99 @@ | |||
/* ==================================================================== | |||
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.hssf.usermodel.examples; | |||
import org.apache.poi.hssf.usermodel.*; | |||
import org.apache.poi.hssf.util.HSSFColor; | |||
import java.io.*; | |||
/** | |||
* 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 { | |||
HSSFWorkbook wb = new HSSFWorkbook(); | |||
HSSFSheet sheet = wb.createSheet("Cell comments in POI HSSF"); | |||
// 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 | |||
HSSFCell cell1 = sheet.createRow(3).createCell((short)1); | |||
cell1.setCellValue(new HSSFRichTextString("Hello, World")); | |||
//anchor defines size and position of the comment in worksheet | |||
HSSFComment comment1 = patr.createComment(new HSSFClientAnchor(0, 0, 0, 0, (short)4, 2, (short) 6, 5)); | |||
// set text in the comment | |||
comment1.setString(new HSSFRichTextString("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 HSSFCell.setCellComment method | |||
cell1.setCellComment(comment1); | |||
//create another cell in row 6 | |||
HSSFCell cell2 = sheet.createRow(6).createCell((short)1); | |||
cell2.setCellValue(36.6); | |||
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); | |||
comment2.setVisible(true); //by default comments are hidden. This one is always visible. | |||
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 commnet is visible. | |||
*/ | |||
comment2.setRow(6); | |||
comment2.setColumn((short)1); | |||
FileOutputStream out = new FileOutputStream("poi_comment.xls"); | |||
wb.write(out); | |||
out.close(); | |||
} | |||
} |
@@ -509,6 +509,9 @@ public class BiffViewer { | |||
case FilePassRecord.sid: | |||
retval = new FilePassRecord(in); | |||
break; | |||
case NoteRecord.sid: | |||
retval = new NoteRecord( in ); | |||
break; | |||
default: | |||
retval = new UnknownRecord( in ); | |||
} |
@@ -107,6 +107,7 @@ import org.apache.poi.hssf.record.WindowTwoRecord; | |||
import org.apache.poi.hssf.record.WriteAccessRecord; | |||
import org.apache.poi.hssf.record.WriteProtectRecord; | |||
import org.apache.poi.hssf.record.FilePassRecord; | |||
import org.apache.poi.hssf.record.NoteRecord; | |||
/** | |||
@@ -158,7 +159,8 @@ public class EventRecordFactory | |||
LeftMarginRecord.class, RightMarginRecord.class, | |||
TopMarginRecord.class, BottomMarginRecord.class, | |||
PaletteRecord.class, StringRecord.class, SharedFormulaRecord.class, | |||
WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class | |||
WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class, | |||
NoteRecord.class | |||
}; | |||
} |
@@ -36,7 +36,11 @@ public abstract class AbstractShape | |||
public static AbstractShape createShape( HSSFShape hssfShape, int shapeId ) | |||
{ | |||
AbstractShape shape; | |||
if (hssfShape instanceof HSSFTextbox) | |||
if (hssfShape instanceof HSSFComment) | |||
{ | |||
shape = new CommentShape( (HSSFComment)hssfShape, shapeId ); | |||
} | |||
else if (hssfShape instanceof HSSFTextbox) | |||
{ | |||
shape = new TextboxShape( (HSSFTextbox)hssfShape, shapeId ); | |||
} |
@@ -0,0 +1,133 @@ | |||
/* ==================================================================== | |||
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.hssf.model; | |||
import org.apache.poi.hssf.record.*; | |||
import org.apache.poi.hssf.usermodel.HSSFComment; | |||
import org.apache.poi.hssf.usermodel.HSSFShape; | |||
import org.apache.poi.util.LittleEndian; | |||
import org.apache.poi.ddf.*; | |||
import java.util.List; | |||
import java.util.Iterator; | |||
/** | |||
* Represents a cell comment. | |||
* This class converts highlevel model data from <code>HSSFComment</code> | |||
* to low-level records. | |||
* | |||
* @author Yegor Kozlov | |||
*/ | |||
public class CommentShape extends TextboxShape { | |||
private NoteRecord note; | |||
/** | |||
* Creates the low-level records for a comment. | |||
* | |||
* @param hssfShape The highlevel shape. | |||
* @param shapeId The shape id to use for this shape. | |||
*/ | |||
public CommentShape( HSSFComment hssfShape, int shapeId ) | |||
{ | |||
super(hssfShape, shapeId); | |||
note = createNoteRecord(hssfShape, shapeId); | |||
ObjRecord obj = getObjRecord(); | |||
List records = obj.getSubRecords(); | |||
int cmoIdx = 0; | |||
for (int i = 0; i < records.size(); i++) { | |||
Object r = records.get(i); | |||
if (r instanceof CommonObjectDataSubRecord){ | |||
//modify autofill attribute inherited from <code>TextObjectRecord</code> | |||
CommonObjectDataSubRecord cmo = (CommonObjectDataSubRecord)r; | |||
cmo.setAutofill(false); | |||
cmoIdx = i; | |||
} | |||
} | |||
//add NoteStructure sub record | |||
//we don't know it's format, for now the record data is empty | |||
NoteStructureSubRecord u = new NoteStructureSubRecord(); | |||
obj.addSubRecord(cmoIdx+1, u); | |||
} | |||
/** | |||
* Creates the low level <code>NoteRecord</code> | |||
* which holds the comment attributes. | |||
*/ | |||
private NoteRecord createNoteRecord( HSSFComment shape, int shapeId ) | |||
{ | |||
NoteRecord note = new NoteRecord(); | |||
note.setColumn(shape.getColumn()); | |||
note.setRow((short)shape.getRow()); | |||
note.setFlags(shape.isVisible() ? NoteRecord.NOTE_VISIBLE : NoteRecord.NOTE_HIDDEN); | |||
note.setShapeId((short)shapeId); | |||
note.setAuthor(shape.getAuthor() == null ? "" : shape.getAuthor()); | |||
return note; | |||
} | |||
/** | |||
* Sets standard escher options for a comment. | |||
* This method is responsible for setting default background, | |||
* shading and other comment properties. | |||
* | |||
* @param shape The highlevel shape. | |||
* @param opt The escher records holding the proerties | |||
* @return number of escher options added | |||
*/ | |||
protected int addStandardOptions( HSSFShape shape, EscherOptRecord opt ) | |||
{ | |||
super.addStandardOptions(shape, opt); | |||
//remove unnecessary properties inherited from TextboxShape | |||
java.util.List props = opt.getEscherProperties(); | |||
for ( Iterator iterator = props.iterator(); iterator.hasNext(); ) { | |||
EscherProperty prop = (EscherProperty) iterator.next(); | |||
switch (prop.getId()){ | |||
case EscherProperties.TEXT__TEXTLEFT: | |||
case EscherProperties.TEXT__TEXTRIGHT: | |||
case EscherProperties.TEXT__TEXTTOP: | |||
case EscherProperties.TEXT__TEXTBOTTOM: | |||
case EscherProperties.GROUPSHAPE__PRINT: | |||
case EscherProperties.FILL__FILLBACKCOLOR: | |||
case EscherProperties.LINESTYLE__COLOR: | |||
iterator.remove(); | |||
break; | |||
} | |||
} | |||
HSSFComment comment = (HSSFComment)shape; | |||
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.GROUPSHAPE__PRINT, comment.isVisible() ? 0x000A0000 : 0x000A0002) ); | |||
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x00030003 ) ); | |||
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.SHADOWSTYLE__COLOR, 0x00000000 ) ); | |||
opt.sortProperties(); | |||
return opt.getEscherProperties().size(); // # options added | |||
} | |||
/** | |||
* Return the <code>NoteRecord</code> holding the comment attributes | |||
* | |||
* @return <code>NoteRecord</code> holding the comment attributes | |||
*/ | |||
public NoteRecord getNoteRecord() | |||
{ | |||
return note; | |||
} | |||
} |
@@ -23,6 +23,7 @@ import org.apache.poi.hssf.model.AbstractShape; | |||
import org.apache.poi.hssf.model.TextboxShape; | |||
import org.apache.poi.hssf.model.DrawingManager2; | |||
import org.apache.poi.hssf.model.ConvertAnchor; | |||
import org.apache.poi.hssf.model.CommentShape; | |||
import java.util.*; | |||
@@ -260,6 +261,11 @@ public class EscherAggregate extends AbstractEscherHolderRecord | |||
private DrawingManager2 drawingManager; | |||
private short drawingGroupId; | |||
/** | |||
* list of "tail" records that need to be serialized after all drawing group records | |||
*/ | |||
private List tailRec = new ArrayList(); | |||
public EscherAggregate( DrawingManager2 drawingManager ) | |||
{ | |||
this.drawingManager = drawingManager; | |||
@@ -450,6 +456,13 @@ public class EscherAggregate extends AbstractEscherHolderRecord | |||
} | |||
// write records that need to be serialized after all drawing group records | |||
for ( int i = 0; i < tailRec.size(); i++ ) | |||
{ | |||
Record rec = (Record)tailRec.get(i); | |||
pos += rec.serialize( pos, data ); | |||
} | |||
int bytesWritten = pos - offset; | |||
if ( bytesWritten != getRecordSize() ) | |||
throw new RecordFormatException( bytesWritten + " bytes written but getRecordSize() reports " + getRecordSize() ); | |||
@@ -484,7 +497,13 @@ public class EscherAggregate extends AbstractEscherHolderRecord | |||
Record r = (Record) iterator.next(); | |||
objRecordSize += r.getRecordSize(); | |||
} | |||
return drawingRecordSize + objRecordSize; | |||
int tailRecordSize = 0; | |||
for ( Iterator iterator = tailRec.iterator(); iterator.hasNext(); ) | |||
{ | |||
Record r = (Record) iterator.next(); | |||
tailRecordSize += r.getRecordSize(); | |||
} | |||
return drawingRecordSize + objRecordSize + tailRecordSize; | |||
} | |||
/** | |||
@@ -529,6 +548,7 @@ public class EscherAggregate extends AbstractEscherHolderRecord | |||
if ( patriarch != null ) | |||
{ | |||
shapeToObj.clear(); | |||
tailRec.clear(); | |||
clearEscherRecords(); | |||
if ( patriarch.getChildren().size() != 0 ) | |||
{ | |||
@@ -568,6 +588,12 @@ public class EscherAggregate extends AbstractEscherHolderRecord | |||
EscherRecord escherTextbox = ( (TextboxShape) shapeModel ).getEscherTextbox(); | |||
shapeToObj.put( escherTextbox, ( (TextboxShape) shapeModel ).getTextObjectRecord() ); | |||
// escherParent.addChildRecord(escherTextbox); | |||
if ( shapeModel instanceof CommentShape ){ | |||
CommentShape comment = (CommentShape)shapeModel; | |||
tailRec.add(comment.getNoteRecord()); | |||
} | |||
} | |||
escherParent.addChildRecord( shapeModel.getSpContainer() ); | |||
} |
@@ -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.hssf.record; | |||
import org.apache.poi.util.LittleEndian; | |||
/** | |||
* NOTE: Comment Associated with a Cell (1Ch) | |||
* | |||
* @author Yegor Kozlov | |||
*/ | |||
public class NoteRecord extends Record { | |||
public final static short sid = 0x1C; | |||
/** | |||
* Flag indicating that the comment is hidden (default) | |||
*/ | |||
public final static short NOTE_HIDDEN = 0x0; | |||
/** | |||
* Flag indicating that the comment is visible | |||
*/ | |||
public final static short NOTE_VISIBLE = 0x2; | |||
private short field_1_row; | |||
private short field_2_col; | |||
private short field_3_flags; | |||
private short field_4_shapeid; | |||
private String field_5_author; | |||
/** | |||
* Construct a new <code>NoteRecord</code> and | |||
* fill its data with the default values | |||
*/ | |||
public NoteRecord() | |||
{ | |||
field_5_author = ""; | |||
field_3_flags = 0; | |||
} | |||
/** | |||
* Constructs a <code>NoteRecord</code> and fills its fields | |||
* from the supplied <code>RecordInputStream</code>. | |||
* | |||
* @param in the stream to read from | |||
*/ | |||
public NoteRecord(RecordInputStream in) | |||
{ | |||
super(in); | |||
} | |||
/** | |||
* @return id of this record. | |||
*/ | |||
public short getSid() | |||
{ | |||
return sid; | |||
} | |||
/** | |||
* Checks the sid matches the expected side for this record | |||
* | |||
* @param id the expected sid. | |||
*/ | |||
protected void validateSid(short id) | |||
{ | |||
if (id != sid) | |||
{ | |||
throw new RecordFormatException("Not a NoteRecord record"); | |||
} | |||
} | |||
/** | |||
* Read the record data from the supplied <code>RecordInputStream</code> | |||
*/ | |||
protected void fillFields(RecordInputStream in) | |||
{ | |||
field_1_row = in.readShort(); | |||
field_2_col = in.readShort(); | |||
field_3_flags = in.readShort(); | |||
field_4_shapeid = in.readShort(); | |||
int length = in.readShort(); | |||
byte[] bytes = in.readRemainder(); | |||
field_5_author = new String(bytes, 1, length); | |||
} | |||
/** | |||
* Serialize the record data into the supplied array of bytes | |||
* | |||
* @param offset offset in the <code>data</code> | |||
* @param data the data to serialize into | |||
* | |||
* @return size of the record | |||
*/ | |||
public int serialize(int offset, byte [] data) | |||
{ | |||
LittleEndian.putShort(data, 0 + offset, sid); | |||
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4)); | |||
LittleEndian.putShort(data, 4 + offset , field_1_row); | |||
LittleEndian.putShort(data, 6 + offset , field_2_col); | |||
LittleEndian.putShort(data, 8 + offset , field_3_flags); | |||
LittleEndian.putShort(data, 10 + offset , field_4_shapeid); | |||
LittleEndian.putShort(data, 12 + offset , (short)field_5_author.length()); | |||
byte[] str = field_5_author.getBytes(); | |||
System.arraycopy(str, 0, data, 15 + offset, str.length); | |||
return getRecordSize(); | |||
} | |||
/** | |||
* Size of record | |||
*/ | |||
public int getRecordSize() | |||
{ | |||
int retval = 4 + 2 + 2 + 2 + 2 + 2 + 1 + field_5_author.length() + 1; | |||
return retval; | |||
} | |||
/** | |||
* Convert this record to string. | |||
* Used by BiffViewer and other utulities. | |||
*/ | |||
public String toString() | |||
{ | |||
StringBuffer buffer = new StringBuffer(); | |||
buffer.append("[NOTE]\n"); | |||
buffer.append(" .recordid = 0x" + Integer.toHexString( getSid() ) + ", size = " + getRecordSize() + "\n"); | |||
buffer.append(" .row = " + field_1_row + "\n"); | |||
buffer.append(" .col = " + field_2_col + "\n"); | |||
buffer.append(" .flags = " + field_3_flags + "\n"); | |||
buffer.append(" .shapeid = " + field_4_shapeid + "\n"); | |||
buffer.append(" .author = " + field_5_author + "\n"); | |||
buffer.append("[/NOTE]\n"); | |||
return buffer.toString(); | |||
} | |||
/** | |||
* Return the row that contains the comment | |||
* | |||
* @return the row that contains the comment | |||
*/ | |||
public short getRow(){ | |||
return field_1_row; | |||
} | |||
/** | |||
* Specify the row that contains the comment | |||
* | |||
* @param row the row that contains the comment | |||
*/ | |||
public void setRow(short row){ | |||
field_1_row = row; | |||
} | |||
/** | |||
* Return the column that contains the comment | |||
* | |||
* @return the column that contains the comment | |||
*/ | |||
public short getColumn(){ | |||
return field_2_col; | |||
} | |||
/** | |||
* Specify the column that contains the comment | |||
* | |||
* @param col the column that contains the comment | |||
*/ | |||
public void setColumn(short col){ | |||
field_2_col = col; | |||
} | |||
/** | |||
* Options flags. | |||
* | |||
* @return the options flag | |||
* @see NoteRecord.NOTE_VISIBLE | |||
* @see NoteRecord.NOTE_HIDDEN | |||
*/ | |||
public short getFlags(){ | |||
return field_3_flags; | |||
} | |||
/** | |||
* Options flag | |||
* | |||
* @param flags the options flag | |||
* @see #NOTE_VISIBLE | |||
* @see #NOTE_HIDDEN | |||
*/ | |||
public void setFlags(short flags){ | |||
field_3_flags = flags; | |||
} | |||
/** | |||
* Object id for OBJ record that contains the comment | |||
*/ | |||
public short getShapeId(){ | |||
return field_4_shapeid; | |||
} | |||
/** | |||
* Object id for OBJ record that contains the comment | |||
*/ | |||
public void setShapeId(short id){ | |||
field_4_shapeid = id; | |||
} | |||
/** | |||
* Name of the original comment author | |||
* | |||
* @return the name of the original author of the comment | |||
*/ | |||
public String getAuthor(){ | |||
return field_5_author; | |||
} | |||
/** | |||
* Name of the original comment author | |||
* | |||
* @param author the name of the original author of the comment | |||
*/ | |||
public void setAuthor(String author){ | |||
field_5_author = author; | |||
} | |||
} |
@@ -0,0 +1,130 @@ | |||
/* ==================================================================== | |||
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.hssf.record; | |||
import org.apache.poi.util.*; | |||
/** | |||
* Represents a NoteStructure (0xD) sub record. | |||
* | |||
* <p> | |||
* The docs say nothing about it. The length of this record is always 26 bytes. | |||
* </p> | |||
* | |||
* @author Yegor Kozlov | |||
*/ | |||
public class NoteStructureSubRecord | |||
extends SubRecord | |||
{ | |||
public final static short sid = 0x0D; | |||
private byte[] reserved; | |||
/** | |||
* Construct a new <code>NoteStructureSubRecord</code> and | |||
* fill its data with the default values | |||
*/ | |||
public NoteStructureSubRecord() | |||
{ | |||
//all we know is that the the length of <code>NoteStructureSubRecord</code> is always 22 bytes | |||
reserved = new byte[22]; | |||
} | |||
/** | |||
* Constructs a NoteStructureSubRecord and sets its fields appropriately. | |||
* | |||
*/ | |||
public NoteStructureSubRecord(RecordInputStream in) | |||
{ | |||
super(in); | |||
} | |||
/** | |||
* Checks the sid matches the expected side for this record | |||
* | |||
* @param id the expected sid. | |||
*/ | |||
protected void validateSid(short id) | |||
{ | |||
if (id != sid) | |||
{ | |||
throw new RecordFormatException("Not a Note Structure record"); | |||
} | |||
} | |||
/** | |||
* Read the record data from the supplied <code>RecordInputStream</code> | |||
*/ | |||
protected void fillFields(RecordInputStream in) | |||
{ | |||
//just grab the raw data | |||
reserved = in.readRemainder(); | |||
} | |||
/** | |||
* Convert this record to string. | |||
* Used by BiffViewer and other utulities. | |||
*/ | |||
public String toString() | |||
{ | |||
StringBuffer buffer = new StringBuffer(); | |||
String nl = System.getProperty("line.separator"); | |||
buffer.append("[ftNts ]" + nl); | |||
buffer.append(" size = ").append(getRecordSize()).append(nl); | |||
buffer.append(" reserved = ").append(HexDump.toHex(reserved)).append(nl); | |||
buffer.append("[/ftNts ]" + nl); | |||
return buffer.toString(); | |||
} | |||
/** | |||
* Serialize the record data into the supplied array of bytes | |||
* | |||
* @param offset offset in the <code>data</code> | |||
* @param data the data to serialize into | |||
* | |||
* @return size of the record | |||
*/ | |||
public int serialize(int offset, byte[] data) | |||
{ | |||
LittleEndian.putShort(data, 0 + offset, sid); | |||
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4)); | |||
System.arraycopy(reserved, 0, data, offset + 4, getRecordSize() - 4); | |||
return getRecordSize(); | |||
} | |||
/** | |||
* Size of record | |||
*/ | |||
public int getRecordSize() | |||
{ | |||
return 4 + reserved.length; | |||
} | |||
/** | |||
* @return id of this record. | |||
*/ | |||
public short getSid() | |||
{ | |||
return sid; | |||
} | |||
} | |||
@@ -73,7 +73,8 @@ public class RecordFactory | |||
ObjRecord.class, TextObjectRecord.class, | |||
PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class, | |||
HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class, | |||
WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class | |||
WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class, | |||
NoteRecord.class | |||
}; | |||
} | |||
private static Map recordsMap = recordsToMap(records); |
@@ -64,6 +64,9 @@ abstract public class SubRecord | |||
case EndSubRecord.sid: | |||
r = new EndSubRecord( in ); | |||
break; | |||
case NoteStructureSubRecord.sid: | |||
r = new NoteStructureSubRecord( in ); | |||
break; | |||
default: | |||
r = new UnknownRecord( in ); | |||
} |
@@ -33,8 +33,7 @@ import org.apache.poi.hssf.record.formula.Ptg; | |||
import java.text.DateFormat; | |||
import java.text.SimpleDateFormat; | |||
import java.util.Calendar; | |||
import java.util.Date; | |||
import java.util.*; | |||
/** | |||
* High level representation of a cell in a row of a spreadsheet. | |||
@@ -51,6 +50,7 @@ import java.util.Date; | |||
* @author Andrew C. Oliver (acoliver at apache dot org) | |||
* @author Dan Sherman (dsherman at isisph.com) | |||
* @author Brian Sanders (kestrel at burdell dot org) Active Cell support | |||
* @author Yegor Kozlov cell comments support | |||
* @version 1.0-pre | |||
*/ | |||
@@ -113,6 +113,7 @@ public class HSSFCell | |||
private Workbook book; | |||
private Sheet sheet; | |||
private CellValueRecordInterface record; | |||
private HSSFComment comment; | |||
/** | |||
* Creates new Cell - Should only be called by HSSFRow. This creates a cell | |||
@@ -959,4 +960,60 @@ public class HSSFCell | |||
return "Unknown Cell Type: " + getCellType(); | |||
} | |||
} | |||
/** | |||
* Assign a comment to this cell | |||
* | |||
* @param comment comment associated with this cell | |||
*/ | |||
public void setCellComment(HSSFComment comment){ | |||
comment.setRow((short)record.getRow()); | |||
comment.setColumn(record.getColumn()); | |||
this.comment = comment; | |||
} | |||
/** | |||
* Returns the comment associated with this cell | |||
* | |||
* @return comment associated with this cell | |||
*/ | |||
public HSSFComment getCellComment(){ | |||
if (comment == null) { | |||
HashMap txshapes = new HashMap(); //map shapeId and TextObjectRecord | |||
for (Iterator it = sheet.getRecords().iterator(); it.hasNext(); ) { | |||
Record rec = ( Record ) it.next(); | |||
if (rec instanceof NoteRecord){ | |||
NoteRecord note = (NoteRecord)rec; | |||
if (note.getRow() == record.getRow() && note.getColumn() == record.getColumn()){ | |||
TextObjectRecord txo = (TextObjectRecord)txshapes.get(new Integer(note.getShapeId())); | |||
comment = new HSSFComment(null, null); | |||
comment.setRow(note.getRow()); | |||
comment.setColumn(note.getColumn()); | |||
comment.setAuthor(note.getAuthor()); | |||
comment.setVisible(note.getFlags() == NoteRecord.NOTE_VISIBLE); | |||
comment.setString(txo.getStr()); | |||
break; | |||
} | |||
} else if (rec instanceof ObjRecord){ | |||
ObjRecord obj = (ObjRecord)rec; | |||
SubRecord sub = (SubRecord)obj.getSubRecords().get(0); | |||
if (sub instanceof CommonObjectDataSubRecord){ | |||
CommonObjectDataSubRecord cmo = (CommonObjectDataSubRecord)sub; | |||
if (cmo.getObjectType() == CommonObjectDataSubRecord.OBJECT_TYPE_COMMENT){ | |||
//find the nearest TextObjectRecord which holds comment's text and map it to its shapeId | |||
while(it.hasNext()) { | |||
rec = ( Record ) it.next(); | |||
if (rec instanceof TextObjectRecord) { | |||
txshapes.put(new Integer(cmo.getObjectId()), rec); | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
return comment; | |||
} | |||
} |
@@ -0,0 +1,143 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.hssf.usermodel; | |||
import org.apache.poi.hssf.record.EscherAggregate; | |||
import org.apache.poi.hssf.record.NoteRecord; | |||
import org.apache.poi.hssf.record.TextObjectRecord; | |||
import org.apache.poi.ddf.*; | |||
import java.util.Map; | |||
import java.util.List; | |||
import java.util.Iterator; | |||
/** | |||
* Represents a cell comment - a sticky note associated with a cell. | |||
* | |||
* @author Yegor Kolzlov | |||
*/ | |||
public class HSSFComment extends HSSFTextbox { | |||
private boolean visible; | |||
private short col, row; | |||
private String author; | |||
/** | |||
* Construct a new comment with the given parent and anchor. | |||
* | |||
* @param parent | |||
* @param anchor defines position of this anchor in the sheet | |||
*/ | |||
public HSSFComment( HSSFShape parent, HSSFAnchor anchor ) | |||
{ | |||
super( parent, anchor ); | |||
setShapeType(OBJECT_TYPE_COMMENT); | |||
//default color for comments | |||
fillColor = 0x08000050; | |||
//by default comments are hidden | |||
visible = false; | |||
author = ""; | |||
} | |||
/** | |||
* Returns whether this comment is visible. | |||
* | |||
* @param visible <code>true</code> if the comment is visible, <code>false</code> otherwise | |||
*/ | |||
public void setVisible(boolean visible){ | |||
this.visible = visible; | |||
} | |||
/** | |||
* Sets whether this comment is visible. | |||
* | |||
* @return <code>true</code> if the comment is visible, <code>false</code> otherwise | |||
*/ | |||
public boolean isVisible(){ | |||
return this.visible; | |||
} | |||
/** | |||
* Return the row of the cell that contains the comment | |||
* | |||
* @return the 0-based row of the cell that contains the comment | |||
*/ | |||
public int getRow(){ | |||
return row; | |||
} | |||
/** | |||
* 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){ | |||
this.row = (short)row; | |||
} | |||
/** | |||
* Return the column of the cell that contains the comment | |||
* | |||
* @return the 0-based column of the cell that contains the comment | |||
*/ | |||
public short getColumn(){ | |||
return col; | |||
} | |||
/** | |||
* 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(short col){ | |||
this.col = col; | |||
} | |||
/** | |||
* Name of the original comment author | |||
* | |||
* @return the name of the original author of the comment | |||
*/ | |||
public String getAuthor(){ | |||
return author; | |||
} | |||
/** | |||
* Name of the original comment author | |||
* | |||
* @param author the name of the original author of the comment | |||
*/ | |||
public void setAuthor(String author){ | |||
this.author = author; | |||
} | |||
/** | |||
* Sets the rich text string used by this comment. | |||
* | |||
* @param string Sets the rich text string used by this object. | |||
*/ | |||
public void setString( HSSFRichTextString string ) | |||
{ | |||
//if font is not set we must set the default one implicitly | |||
if (string.numFormattingRuns() == 0) string.applyFont((short)0); | |||
super.setString(string); | |||
} | |||
} |
@@ -125,6 +125,21 @@ public class HSSFPatriarch | |||
return shape; | |||
} | |||
/** | |||
* Constructs a cell comment. | |||
* | |||
* @param anchor the client anchor describes how this comment is attached | |||
* to the sheet. | |||
* @return the newly created comment. | |||
*/ | |||
public HSSFComment createComment(HSSFAnchor anchor) | |||
{ | |||
HSSFComment shape = new HSSFComment(null, anchor); | |||
shape.anchor = anchor; | |||
shapes.add(shape); | |||
return shape; | |||
} | |||
/** | |||
* Returns a list of all shapes contained by the patriarch. | |||
*/ |
@@ -47,7 +47,7 @@ public class HSSFSimpleShape | |||
// public final static short OBJECT_TYPE_LIST_BOX = 18; | |||
// public final static short OBJECT_TYPE_GROUP_BOX = 19; | |||
// public final static short OBJECT_TYPE_COMBO_BOX = 20; | |||
// public final static short OBJECT_TYPE_COMMENT = 25; | |||
public final static short OBJECT_TYPE_COMMENT = 25; | |||
// public final static short OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING = 30; | |||
int shapeType = OBJECT_TYPE_LINE; | |||
@@ -65,6 +65,7 @@ public class HSSFSimpleShape | |||
* @see #OBJECT_TYPE_OVAL | |||
* @see #OBJECT_TYPE_RECTANGLE | |||
* @see #OBJECT_TYPE_PICTURE | |||
* @see #OBJECT_TYPE_COMMENT | |||
*/ | |||
public int getShapeType() { return shapeType; } | |||
@@ -77,6 +78,7 @@ public class HSSFSimpleShape | |||
* @see #OBJECT_TYPE_OVAL | |||
* @see #OBJECT_TYPE_RECTANGLE | |||
* @see #OBJECT_TYPE_PICTURE | |||
* @see #OBJECT_TYPE_COMMENT | |||
*/ | |||
public void setShapeType( int shapeType ){ this.shapeType = shapeType; } | |||
@@ -110,6 +110,7 @@ import org.apache.poi.hssf.util.TestCellReference; | |||
import org.apache.poi.hssf.util.TestRKUtil; | |||
import org.apache.poi.hssf.util.TestRangeAddress; | |||
import org.apache.poi.hssf.util.TestSheetReferences; | |||
import org.apache.poi.hssf.usermodel.TestHSSFComment; | |||
/** | |||
* Test Suite for running just HSSF tests. Mostly | |||
@@ -227,7 +228,8 @@ public class HSSFTests | |||
suite.addTest(new TestSuite(TestModelFactory.class)); | |||
suite.addTest(new TestSuite(TestDrawingManager.class)); | |||
suite.addTest(new TestSuite(TestSheet.class)); | |||
suite.addTest(new TestSuite(TestHSSFComment.class)); | |||
//$JUnit-END$ | |||
return suite; | |||
} |
@@ -0,0 +1,82 @@ | |||
/* ==================================================================== | |||
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.hssf.record; | |||
import junit.framework.TestCase; | |||
import java.util.Arrays; | |||
/** | |||
* Tests the serialization and deserialization of the NoteRecord | |||
* class works correctly. Test data taken directly from a real | |||
* Excel file. | |||
* | |||
* @author Yegor Kozlov | |||
*/ | |||
public class TestNoteRecord | |||
extends TestCase | |||
{ | |||
private byte[] data = new byte[] { | |||
0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x04, 0x1A, 0x00, | |||
0x00, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x53, 0x6F, | |||
0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x46, 0x6F, 0x75, | |||
0x6E, 0x64, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00 | |||
}; | |||
public TestNoteRecord(String name) | |||
{ | |||
super(name); | |||
} | |||
public void testRead() | |||
throws Exception | |||
{ | |||
NoteRecord record = new NoteRecord(new TestcaseRecordInputStream(NoteRecord.sid, (short)data.length, data)); | |||
assertEquals(NoteRecord.sid, record.getSid()); | |||
record.validateSid(NoteRecord.sid); | |||
assertEquals(6, record.getRow()); | |||
assertEquals(1, record.getColumn()); | |||
assertEquals(NoteRecord.NOTE_VISIBLE, record.getFlags()); | |||
assertEquals(1026, record.getShapeId()); | |||
assertEquals("Apache Software Foundation", record.getAuthor()); | |||
} | |||
public void testWrite() | |||
{ | |||
NoteRecord record = new NoteRecord(); | |||
assertEquals(NoteRecord.sid, record.getSid()); | |||
record.validateSid(NoteRecord.sid); | |||
record.setRow((short)6); | |||
record.setColumn((short)1); | |||
record.setFlags(NoteRecord.NOTE_VISIBLE); | |||
record.setShapeId((short)1026); | |||
record.setAuthor("Apache Software Foundation"); | |||
byte [] ser = record.serialize(); | |||
assertEquals(ser.length - 4, data.length); | |||
byte[] recdata = new byte[ser.length - 4]; | |||
System.arraycopy(ser, 4, recdata, 0, recdata.length); | |||
assertTrue(Arrays.equals(data, recdata)); | |||
} | |||
} |
@@ -0,0 +1,68 @@ | |||
/* ==================================================================== | |||
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.hssf.record; | |||
import junit.framework.TestCase; | |||
import java.util.Arrays; | |||
/** | |||
* Tests the serialization and deserialization of the NoteRecord | |||
* class works correctly. Test data taken directly from a real | |||
* Excel file. | |||
* | |||
* @author Yegor Kozlov | |||
*/ | |||
public class TestNoteStructureSubRecord | |||
extends TestCase | |||
{ | |||
private byte[] data = new byte[] { | |||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte)0x80, 0x00, 0x00, 0x00, | |||
0x00, 0x00, (byte)0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, (byte)0x81, 0x01, | |||
(byte)0xCC, (byte)0xEC | |||
}; | |||
public TestNoteStructureSubRecord(String name) | |||
{ | |||
super(name); | |||
} | |||
public void testRead() | |||
throws Exception | |||
{ | |||
NoteStructureSubRecord record = new NoteStructureSubRecord(new TestcaseRecordInputStream(NoteStructureSubRecord.sid, (short)data.length, data)); | |||
assertEquals(NoteStructureSubRecord.sid, record.getSid()); | |||
record.validateSid(NoteStructureSubRecord.sid); | |||
assertEquals(data.length + 4, record.getRecordSize()); | |||
} | |||
public void testWrite() | |||
{ | |||
NoteStructureSubRecord record = new NoteStructureSubRecord(); | |||
assertEquals(NoteStructureSubRecord.sid, record.getSid()); | |||
record.validateSid(NoteStructureSubRecord.sid); | |||
assertEquals(data.length + 4, record.getRecordSize()); | |||
byte [] ser = record.serialize(); | |||
assertEquals(ser.length - 4, data.length); | |||
} | |||
} |
@@ -0,0 +1,120 @@ | |||
/* ==================================================================== | |||
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.hssf.usermodel; | |||
import junit.framework.TestCase; | |||
import java.io.*; | |||
/** | |||
* Tests TestHSSFCellComment. | |||
* | |||
* @author Yegor Kozlov | |||
*/ | |||
public 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; | |||
short 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); | |||
//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(); | |||
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()); | |||
} | |||
/** | |||
* test that we can read cell comments from an existing workbook. | |||
*/ | |||
public static void testReadComments() throws Exception { | |||
String dir = System.getProperty("HSSF.testdata.path"); | |||
FileInputStream is = new FileInputStream(new File(dir, "SimpleWithComments.xls")); | |||
HSSFWorkbook wb = new HSSFWorkbook(is); | |||
is.close(); | |||
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((short)0); | |||
comment = cell.getCellComment(); | |||
assertNull("Cells in the first column are not commented", comment); | |||
} | |||
for (int rownum = 0; rownum < 3; rownum++) { | |||
row = sheet.getRow(rownum); | |||
cell = row.getCell((short)1); | |||
comment = cell.getCellComment(); | |||
assertNotNull("Cells in the second column have comments", comment); | |||
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.getCellNum(), comment.getColumn()); | |||
} | |||
} | |||
} |