You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

HSSFComment.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.hssf.usermodel;
  16. import org.apache.poi.ddf.DefaultEscherRecordFactory;
  17. import org.apache.poi.ddf.EscherBSERecord;
  18. import org.apache.poi.ddf.EscherContainerRecord;
  19. import org.apache.poi.ddf.EscherOptRecord;
  20. import org.apache.poi.ddf.EscherProperties;
  21. import org.apache.poi.ddf.EscherSimpleProperty;
  22. import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
  23. import org.apache.poi.hssf.record.EndSubRecord;
  24. import org.apache.poi.hssf.record.NoteRecord;
  25. import org.apache.poi.hssf.record.NoteStructureSubRecord;
  26. import org.apache.poi.hssf.record.ObjRecord;
  27. import org.apache.poi.hssf.record.TextObjectRecord;
  28. import org.apache.poi.ss.usermodel.Comment;
  29. /**
  30. * Represents a cell comment - a sticky note associated with a cell.
  31. */
  32. public class HSSFComment extends HSSFTextbox implements Comment {
  33. private final static int FILL_TYPE_SOLID = 0;
  34. private final static int FILL_TYPE_PICTURE = 3;
  35. private final static int GROUP_SHAPE_PROPERTY_DEFAULT_VALUE = 655362;
  36. private final static int GROUP_SHAPE_HIDDEN_MASK = 0x1000002;
  37. private final static int GROUP_SHAPE_NOT_HIDDEN_MASK = 0xFEFFFFFD;
  38. /*
  39. * TODO - make HSSFComment more consistent when created vs read from file.
  40. * Currently HSSFComment has two main forms (corresponding to the two constructors). There
  41. * are certain operations that only work on comment objects in one of the forms (e.g. deleting
  42. * comments).
  43. * POI is also deficient in its management of RowRecord fields firstCol and lastCol. Those
  44. * fields are supposed to take comments into account, but POI does not do this yet (feb 2009).
  45. * It seems like HSSFRow should manage a collection of local HSSFComments
  46. */
  47. private NoteRecord _note;
  48. public HSSFComment(EscherContainerRecord spContainer, ObjRecord objRecord, TextObjectRecord textObjectRecord, NoteRecord _note) {
  49. super(spContainer, objRecord, textObjectRecord);
  50. this._note = _note;
  51. }
  52. /**
  53. * Construct a new comment with the given parent and anchor.
  54. *
  55. * @param parent
  56. * @param anchor defines position of this anchor in the sheet
  57. */
  58. public HSSFComment(HSSFShape parent, HSSFAnchor anchor) {
  59. super(parent, anchor);
  60. _note = createNoteRecord();
  61. //default color for comments
  62. setFillColor(0x08000050);
  63. //by default comments are hidden
  64. setVisible(false);
  65. setAuthor("");
  66. CommonObjectDataSubRecord cod = (CommonObjectDataSubRecord) getObjRecord().getSubRecords().get(0);
  67. cod.setObjectType(CommonObjectDataSubRecord.OBJECT_TYPE_COMMENT);
  68. }
  69. protected HSSFComment(NoteRecord note, TextObjectRecord txo) {
  70. this(null, new HSSFClientAnchor());
  71. _note = note;
  72. }
  73. @Override
  74. void afterInsert(HSSFPatriarch patriarch) {
  75. super.afterInsert(patriarch);
  76. patriarch._getBoundAggregate().addTailRecord(getNoteRecord());
  77. }
  78. @Override
  79. protected EscherContainerRecord createSpContainer() {
  80. EscherContainerRecord spContainer = super.createSpContainer();
  81. EscherOptRecord opt = spContainer.getChildById(EscherOptRecord.RECORD_ID);
  82. opt.removeEscherProperty(EscherProperties.TEXT__TEXTLEFT);
  83. opt.removeEscherProperty(EscherProperties.TEXT__TEXTRIGHT);
  84. opt.removeEscherProperty(EscherProperties.TEXT__TEXTTOP);
  85. opt.removeEscherProperty(EscherProperties.TEXT__TEXTBOTTOM);
  86. opt.setEscherProperty(new EscherSimpleProperty(EscherProperties.GROUPSHAPE__PRINT, false, false, GROUP_SHAPE_PROPERTY_DEFAULT_VALUE));
  87. return spContainer;
  88. }
  89. @Override
  90. protected ObjRecord createObjRecord() {
  91. ObjRecord obj = new ObjRecord();
  92. CommonObjectDataSubRecord c = new CommonObjectDataSubRecord();
  93. c.setObjectType(OBJECT_TYPE_COMMENT);
  94. c.setLocked(true);
  95. c.setPrintable(true);
  96. c.setAutofill(false);
  97. c.setAutoline(true);
  98. NoteStructureSubRecord u = new NoteStructureSubRecord();
  99. EndSubRecord e = new EndSubRecord();
  100. obj.addSubRecord(c);
  101. obj.addSubRecord(u);
  102. obj.addSubRecord(e);
  103. return obj;
  104. }
  105. private NoteRecord createNoteRecord(){
  106. NoteRecord note = new NoteRecord();
  107. note.setFlags(NoteRecord.NOTE_HIDDEN);
  108. note.setAuthor("");
  109. return note;
  110. }
  111. @Override
  112. void setShapeId(int shapeId) {
  113. super.setShapeId(shapeId);
  114. CommonObjectDataSubRecord cod = (CommonObjectDataSubRecord) getObjRecord().getSubRecords().get(0);
  115. cod.setObjectId((short) (shapeId % 1024));
  116. _note.setShapeId(shapeId % 1024);
  117. }
  118. /**
  119. * Returns whether this comment is visible.
  120. *
  121. * @param visible <code>true</code> if the comment is visible, <code>false</code> otherwise
  122. */
  123. public void setVisible(boolean visible) {
  124. _note.setFlags(visible ? NoteRecord.NOTE_VISIBLE : NoteRecord.NOTE_HIDDEN);
  125. setHidden(!visible);
  126. }
  127. /**
  128. * Sets whether this comment is visible.
  129. *
  130. * @return <code>true</code> if the comment is visible, <code>false</code> otherwise
  131. */
  132. public boolean isVisible() {
  133. return _note.getFlags() == NoteRecord.NOTE_VISIBLE;
  134. }
  135. /**
  136. * Return the row of the cell that contains the comment
  137. *
  138. * @return the 0-based row of the cell that contains the comment
  139. */
  140. public int getRow() {
  141. return _note.getRow();
  142. }
  143. /**
  144. * Set the row of the cell that contains the comment
  145. *
  146. * @param row the 0-based row of the cell that contains the comment
  147. */
  148. public void setRow(int row) {
  149. _note.setRow(row);
  150. }
  151. /**
  152. * Return the column of the cell that contains the comment
  153. *
  154. * @return the 0-based column of the cell that contains the comment
  155. */
  156. public int getColumn() {
  157. return _note.getColumn();
  158. }
  159. /**
  160. * Set the column of the cell that contains the comment
  161. *
  162. * @param col the 0-based column of the cell that contains the comment
  163. */
  164. public void setColumn(int col) {
  165. _note.setColumn(col);
  166. }
  167. /**
  168. * @deprecated (Nov 2009) use {@link HSSFComment#setColumn(int)} }
  169. */
  170. @Deprecated
  171. public void setColumn(short col) {
  172. setColumn((int) col);
  173. }
  174. /**
  175. * Name of the original comment author
  176. *
  177. * @return the name of the original author of the comment
  178. */
  179. public String getAuthor() {
  180. return _note.getAuthor();
  181. }
  182. /**
  183. * Name of the original comment author
  184. *
  185. * @param author the name of the original author of the comment
  186. */
  187. public void setAuthor(String author) {
  188. if (_note != null) _note.setAuthor(author);
  189. }
  190. /**
  191. * Returns the underlying Note record
  192. */
  193. protected NoteRecord getNoteRecord() {
  194. return _note;
  195. }
  196. /**
  197. * Do we know which cell this comment belongs to?
  198. */
  199. public boolean hasPosition() {
  200. if (_note == null) return false;
  201. if (getColumn() < 0 || getRow() < 0) return false;
  202. return true;
  203. }
  204. @Override
  205. public void setShapeType(int shapeType) {
  206. throw new IllegalStateException("Shape type can not be changed in "+this.getClass().getSimpleName());
  207. }
  208. public void afterRemove(HSSFPatriarch patriarch){
  209. super.afterRemove(patriarch);
  210. patriarch._getBoundAggregate().removeTailRecord(getNoteRecord());
  211. }
  212. @Override
  213. protected HSSFShape cloneShape() {
  214. TextObjectRecord txo = (TextObjectRecord) getTextObjectRecord().cloneViaReserialise();
  215. EscherContainerRecord spContainer = new EscherContainerRecord();
  216. byte [] inSp = getEscherContainer().serialize();
  217. spContainer.fillFields(inSp, 0, new DefaultEscherRecordFactory());
  218. ObjRecord obj = (ObjRecord) getObjRecord().cloneViaReserialise();
  219. NoteRecord note = (NoteRecord) getNoteRecord().cloneViaReserialise();
  220. return new HSSFComment(spContainer, obj, txo, note);
  221. }
  222. public void setBackgroundImage(int pictureIndex){
  223. setPropertyValue(new EscherSimpleProperty( EscherProperties.FILL__PATTERNTEXTURE, false, true, pictureIndex));
  224. setPropertyValue(new EscherSimpleProperty( EscherProperties.FILL__FILLTYPE, false, false, FILL_TYPE_PICTURE));
  225. EscherBSERecord bse = getPatriarch().getSheet().getWorkbook().getWorkbook().getBSERecord(pictureIndex);
  226. bse.setRef(bse.getRef() + 1);
  227. }
  228. public void resetBackgroundImage(){
  229. EscherSimpleProperty property = getOptRecord().lookup(EscherProperties.FILL__PATTERNTEXTURE);
  230. if (null != property){
  231. EscherBSERecord bse = getPatriarch().getSheet().getWorkbook().getWorkbook().getBSERecord(property.getPropertyValue());
  232. bse.setRef(bse.getRef() - 1);
  233. getOptRecord().removeEscherProperty(EscherProperties.FILL__PATTERNTEXTURE);
  234. }
  235. setPropertyValue(new EscherSimpleProperty( EscherProperties.FILL__FILLTYPE, false, false, FILL_TYPE_SOLID));
  236. }
  237. public int getBackgroundImageId(){
  238. EscherSimpleProperty property = getOptRecord().lookup(EscherProperties.FILL__PATTERNTEXTURE);
  239. return property == null ? 0 : property.getPropertyValue();
  240. }
  241. private void setHidden(boolean value){
  242. EscherSimpleProperty property = getOptRecord().lookup(EscherProperties.GROUPSHAPE__PRINT);
  243. // see http://msdn.microsoft.com/en-us/library/dd949807(v=office.12).aspx
  244. if (value){
  245. setPropertyValue(new EscherSimpleProperty(EscherProperties.GROUPSHAPE__PRINT, false, false, property.getPropertyValue() | GROUP_SHAPE_HIDDEN_MASK));
  246. } else {
  247. setPropertyValue(new EscherSimpleProperty(EscherProperties.GROUPSHAPE__PRINT, false, false, property.getPropertyValue() & GROUP_SHAPE_NOT_HIDDEN_MASK));
  248. }
  249. }
  250. }