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.

RowRecord.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  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.record;
  16. import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
  17. import java.util.Collections;
  18. import java.util.LinkedHashMap;
  19. import java.util.Map;
  20. import java.util.function.Supplier;
  21. import org.apache.poi.util.BitField;
  22. import org.apache.poi.util.BitFieldFactory;
  23. import org.apache.poi.util.LittleEndianOutput;
  24. /**
  25. * Stores the row information for the sheet.
  26. *
  27. * @since 2.0-pre
  28. */
  29. public final class RowRecord extends StandardRecord {
  30. public static final short sid = 0x0208;
  31. public static final int ENCODED_SIZE = 20;
  32. private static final int OPTION_BITS_ALWAYS_SET = 0x0100;
  33. //private static final int DEFAULT_HEIGHT_BIT = 0x8000;
  34. private static final BitField outlineLevel = BitFieldFactory.getInstance(0x07);
  35. // bit 3 reserved
  36. private static final BitField collapsed = BitFieldFactory.getInstance(0x10);
  37. private static final BitField zeroHeight = BitFieldFactory.getInstance(0x20);
  38. private static final BitField badFontHeight = BitFieldFactory.getInstance(0x40);
  39. private static final BitField formatted = BitFieldFactory.getInstance(0x80);
  40. private static final BitField xfIndex = BitFieldFactory.getInstance(0xFFF);
  41. private static final BitField topBorder = BitFieldFactory.getInstance(0x1000);
  42. private static final BitField bottomBorder = BitFieldFactory.getInstance(0x2000);
  43. private static final BitField phoneticGuide = BitFieldFactory.getInstance(0x4000);
  44. // bit 15 is unused
  45. private int field_1_row_number;
  46. private int field_2_first_col;
  47. private int field_3_last_col; // plus 1
  48. private short field_4_height;
  49. private short field_5_optimize; // hint field for gui, can/should be set to zero
  50. // for generated sheets.
  51. private short field_6_reserved;
  52. /** 16 bit options flags */
  53. private int field_7_option_flags;
  54. /** 16 bit options flags */
  55. private int field_8_option_flags; // only if isFormatted
  56. public RowRecord(RowRecord other) {
  57. super(other);
  58. field_1_row_number = other.field_1_row_number;
  59. field_2_first_col = other.field_2_first_col;
  60. field_3_last_col = other.field_3_last_col;
  61. field_4_height = other.field_4_height;
  62. field_5_optimize = other.field_5_optimize;
  63. field_6_reserved = other.field_6_reserved;
  64. field_7_option_flags = other.field_7_option_flags;
  65. field_8_option_flags = other.field_8_option_flags;
  66. }
  67. public RowRecord(int rowNumber) {
  68. if(rowNumber < 0) {
  69. throw new IllegalArgumentException("Invalid row number (" + rowNumber + ")");
  70. }
  71. field_1_row_number = rowNumber;
  72. field_4_height = (short)0xFF;
  73. field_5_optimize = ( short ) 0;
  74. field_6_reserved = ( short ) 0;
  75. field_7_option_flags = OPTION_BITS_ALWAYS_SET; // seems necessary for outlining
  76. field_8_option_flags = ( short ) 0xf;
  77. setEmpty();
  78. }
  79. public RowRecord(RecordInputStream in) {
  80. field_1_row_number = in.readUShort();
  81. if(field_1_row_number < 0) {
  82. throw new IllegalArgumentException("Invalid row number " + field_1_row_number + " found in InputStream");
  83. }
  84. field_2_first_col = in.readShort();
  85. field_3_last_col = in.readShort();
  86. field_4_height = in.readShort();
  87. field_5_optimize = in.readShort();
  88. field_6_reserved = in.readShort();
  89. field_7_option_flags = in.readShort();
  90. field_8_option_flags = in.readShort();
  91. }
  92. /**
  93. * Updates the firstCol and lastCol fields to the reserved value (-1)
  94. * to signify that this row is empty
  95. */
  96. public void setEmpty() {
  97. field_2_first_col = 0;
  98. field_3_last_col = 0;
  99. }
  100. public boolean isEmpty() {
  101. return (field_2_first_col | field_3_last_col) == 0;
  102. }
  103. /**
  104. * set the logical row number for this row (0 based index)
  105. * @param row - the row number
  106. */
  107. public void setRowNumber(int row) {
  108. field_1_row_number = row;
  109. }
  110. /**
  111. * set the logical col number for the first cell this row (0 based index)
  112. * @param col - the col number
  113. */
  114. public void setFirstCol(int col) {
  115. field_2_first_col = col;
  116. }
  117. /**
  118. * @param col - one past the zero-based index to the last cell in this row
  119. */
  120. public void setLastCol(int col) {
  121. field_3_last_col = col;
  122. }
  123. /**
  124. * set the height of the row
  125. * @param height of the row
  126. */
  127. public void setHeight(short height) {
  128. field_4_height = height;
  129. }
  130. /**
  131. * set whether to optimize or not (set to 0)
  132. * @param optimize (set to 0)
  133. */
  134. public void setOptimize(short optimize) {
  135. field_5_optimize = optimize;
  136. }
  137. // option bitfields
  138. /**
  139. * set the outline level of this row
  140. * @param ol - the outline level
  141. */
  142. public void setOutlineLevel(short ol) {
  143. field_7_option_flags = outlineLevel.setValue(field_7_option_flags, ol);
  144. }
  145. /**
  146. * set whether or not to collapse this row
  147. * @param c - collapse or not
  148. */
  149. public void setColapsed(boolean c) {
  150. field_7_option_flags = collapsed.setBoolean(field_7_option_flags, c);
  151. }
  152. /**
  153. * set whether or not to display this row with 0 height
  154. * @param z height is zero or not.
  155. */
  156. public void setZeroHeight(boolean z) {
  157. field_7_option_flags = zeroHeight.setBoolean(field_7_option_flags, z);
  158. }
  159. /**
  160. * set whether the font and row height are not compatible
  161. * @param f true if they aren't compatible (damn not logic)
  162. */
  163. public void setBadFontHeight(boolean f) {
  164. field_7_option_flags = badFontHeight.setBoolean(field_7_option_flags, f);
  165. }
  166. /**
  167. * set whether the row has been formatted (even if its got all blank cells)
  168. * @param f formatted or not
  169. */
  170. public void setFormatted(boolean f) {
  171. field_7_option_flags = formatted.setBoolean(field_7_option_flags, f);
  172. }
  173. // end bitfields
  174. /**
  175. * if the row is formatted then this is the index to the extended format record
  176. * @see org.apache.poi.hssf.record.ExtendedFormatRecord
  177. * @param index to the XF record
  178. */
  179. public void setXFIndex(short index) {
  180. field_8_option_flags = xfIndex.setValue(field_8_option_flags, index);
  181. }
  182. /**
  183. * bit that specifies whether any cell in the row has a thick top border, or any
  184. * cell in the row directly above the current row has a thick bottom border.
  185. * @param f has thick top border
  186. */
  187. public void setTopBorder(boolean f) {
  188. field_8_option_flags = topBorder.setBoolean(field_8_option_flags, f);
  189. }
  190. /**
  191. * A bit that specifies whether any cell in the row has a medium or thick
  192. * bottom border, or any cell in the row directly below the current row has
  193. * a medium or thick top border.
  194. * @param f has thick bottom border
  195. */
  196. public void setBottomBorder(boolean f) {
  197. field_8_option_flags = bottomBorder.setBoolean(field_8_option_flags, f);
  198. }
  199. /**
  200. * A bit that specifies whether the phonetic guide feature is enabled for
  201. * any cell in this row.
  202. * @param f use phoenetic guide
  203. */
  204. public void setPhoeneticGuide(boolean f) {
  205. field_8_option_flags = phoneticGuide.setBoolean(field_8_option_flags, f);
  206. }
  207. /**
  208. * get the logical row number for this row (0 based index)
  209. * @return row - the row number
  210. */
  211. public int getRowNumber() {
  212. return field_1_row_number;
  213. }
  214. /**
  215. * get the logical col number for the first cell this row (0 based index)
  216. * @return col - the col number
  217. */
  218. public int getFirstCol() {
  219. return field_2_first_col;
  220. }
  221. /**
  222. * get the logical col number for the last cell this row (0 based index), plus one
  223. * @return col - the last col index + 1
  224. */
  225. public int getLastCol() {
  226. return field_3_last_col;
  227. }
  228. /**
  229. * get the height of the row
  230. * @return height of the row
  231. */
  232. public short getHeight() {
  233. return field_4_height;
  234. }
  235. /**
  236. * get whether to optimize or not (set to 0)
  237. * @return optimize (set to 0)
  238. */
  239. public short getOptimize() {
  240. return field_5_optimize;
  241. }
  242. /**
  243. * gets the option bitmask. (use the individual bit setters that refer to this
  244. * method)
  245. * @return options - the bitmask
  246. */
  247. public short getOptionFlags() {
  248. return (short)field_7_option_flags;
  249. }
  250. // option bitfields
  251. /**
  252. * get the outline level of this row
  253. * @return ol - the outline level
  254. * @see #getOptionFlags()
  255. */
  256. public short getOutlineLevel() {
  257. return (short)outlineLevel.getValue(field_7_option_flags);
  258. }
  259. /**
  260. * get whether or not to colapse this row
  261. * @return c - colapse or not
  262. * @see #getOptionFlags()
  263. */
  264. public boolean getColapsed() {
  265. return (collapsed.isSet(field_7_option_flags));
  266. }
  267. /**
  268. * get whether or not to display this row with 0 height
  269. * @return - z height is zero or not.
  270. * @see #getOptionFlags()
  271. */
  272. public boolean getZeroHeight() {
  273. return zeroHeight.isSet(field_7_option_flags);
  274. }
  275. /**
  276. * get whether the font and row height are not compatible
  277. * @return - f -true if they aren't compatible (damn not logic)
  278. * @see #getOptionFlags()
  279. */
  280. public boolean getBadFontHeight() {
  281. return badFontHeight.isSet(field_7_option_flags);
  282. }
  283. /**
  284. * get whether the row has been formatted (even if its got all blank cells)
  285. * @return formatted or not
  286. * @see #getOptionFlags()
  287. */
  288. public boolean getFormatted() {
  289. return formatted.isSet(field_7_option_flags);
  290. }
  291. // end bitfields
  292. /**
  293. * gets the 2nd option bitmask. (use the individual bit setters that refer to this
  294. * method)
  295. * @return options - the bitmask
  296. */
  297. public short getOptionFlags2() {
  298. return (short)field_8_option_flags;
  299. }
  300. /**
  301. * if the row is formatted then this is the index to the extended format record
  302. * @see org.apache.poi.hssf.record.ExtendedFormatRecord
  303. * @return index to the XF record or bogus value (undefined) if isn't formatted
  304. */
  305. public short getXFIndex() {
  306. return xfIndex.getShortValue((short)field_8_option_flags);
  307. }
  308. /**
  309. * A bit that specifies whether any cell in the row has a thick top border, or any
  310. * cell in the row directly above the current row has a thick bottom border.
  311. * @return has cells with a thick top border
  312. */
  313. public boolean getTopBorder() {
  314. return topBorder.isSet(field_8_option_flags);
  315. }
  316. /**
  317. * A bit that specifies whether any cell in the row has a medium or thick bottom border,
  318. * or any cell in the row directly below the current row has a medium or thick top border.
  319. * @return has cells with a thick bottom border
  320. */
  321. public boolean getBottomBorder() {
  322. return bottomBorder.isSet(field_8_option_flags);
  323. }
  324. /**
  325. * A bit that specifies whether the phonetic guide feature is enabled for
  326. * any cell in this row.
  327. * @return has phoentic guide
  328. */
  329. public boolean getPhoeneticGuide() {
  330. return phoneticGuide.isSet(field_8_option_flags);
  331. }
  332. public void serialize(LittleEndianOutput out) {
  333. out.writeShort(getRowNumber());
  334. out.writeShort(getFirstCol() == -1 ? (short)0 : getFirstCol());
  335. out.writeShort(getLastCol() == -1 ? (short)0 : getLastCol());
  336. out.writeShort(getHeight());
  337. out.writeShort(getOptimize());
  338. out.writeShort(field_6_reserved);
  339. out.writeShort(getOptionFlags());
  340. out.writeShort(getOptionFlags2());
  341. }
  342. protected int getDataSize() {
  343. return ENCODED_SIZE - 4;
  344. }
  345. public short getSid() {
  346. return sid;
  347. }
  348. @Override
  349. public RowRecord copy() {
  350. return new RowRecord(this);
  351. }
  352. @Override
  353. public HSSFRecordTypes getGenericRecordType() {
  354. return HSSFRecordTypes.ROW;
  355. }
  356. @Override
  357. public Map<String, Supplier<?>> getGenericProperties() {
  358. final Map<String,Supplier<?>> m = new LinkedHashMap<>();
  359. m.put("rowNumber", this::getRowNumber);
  360. m.put("firstCol", this::getFirstCol);
  361. m.put("lastCol", this::getLastCol);
  362. m.put("height", this::getHeight);
  363. m.put("optimized", this::getOptimize);
  364. m.put("reserved", () -> field_6_reserved);
  365. m.put("options", getBitsAsString(this::getOptionFlags,
  366. new BitField[]{collapsed,zeroHeight,badFontHeight,formatted},
  367. new String[]{"COLAPSED","ZERO_HEIGHT","BAD_FONT_HEIGHT","FORMATTED"}));
  368. m.put("outlineLevel", this::getOutlineLevel);
  369. m.put("optionFlags2", getBitsAsString(this::getOptionFlags2,
  370. new BitField[]{topBorder, bottomBorder, phoneticGuide},
  371. new String[]{"TOP_BORDER","BOTTOM_BORDER","PHOENETIC_GUIDE"}));
  372. m.put("xfIndex", this::getXFIndex);
  373. return Collections.unmodifiableMap(m);
  374. }
  375. }