Comment support from bug 41198, patch from Yegor
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@491629 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c5b9d25328
commit
e423cc45ed
@ -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 );
|
||||
}
|
||||
|
133
src/java/org/apache/poi/hssf/model/CommentShape.java
Normal file
133
src/java/org/apache/poi/hssf/model/CommentShape.java
Normal file
@ -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() );
|
||||
}
|
||||
|
246
src/java/org/apache/poi/hssf/record/NoteRecord.java
Normal file
246
src/java/org/apache/poi/hssf/record/NoteRecord.java
Normal 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.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;
|
||||
}
|
||||
}
|
130
src/java/org/apache/poi/hssf/record/NoteStructureSubRecord.java
Normal file
130
src/java/org/apache/poi/hssf/record/NoteStructureSubRecord.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
|
143
src/java/org/apache/poi/hssf/usermodel/HSSFComment.java
Normal file
143
src/java/org/apache/poi/hssf/usermodel/HSSFComment.java
Normal file
@ -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;
|
||||
}
|
||||
|
BIN
src/testcases/org/apache/poi/hssf/data/SimpleWithComments.xls
Normal file
BIN
src/testcases/org/apache/poi/hssf/data/SimpleWithComments.xls
Normal file
Binary file not shown.
82
src/testcases/org/apache/poi/hssf/record/TestNoteRecord.java
Normal file
82
src/testcases/org/apache/poi/hssf/record/TestNoteRecord.java
Normal file
@ -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);
|
||||
|
||||
}
|
||||
}
|
120
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFComment.java
Normal file
120
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFComment.java
Normal file
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user