PageRenderTime 128ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/components/forks/poi/src/loci/poi/hssf/model/Sheet.java

http://github.com/openmicroscopy/bioformats
Java | 3299 lines | 1613 code | 334 blank | 1352 comment | 345 complexity | 1e8d548d196dc1063c30d9430b35b9f5 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0, BSD-2-Clause, MPL-2.0-no-copyleft-exception
  1. /*
  2. * #%L
  3. * Fork of Apache Jakarta POI.
  4. * %%
  5. * Copyright (C) 2008 - 2013 Open Microscopy Environment:
  6. * - Board of Regents of the University of Wisconsin-Madison
  7. * - Glencoe Software, Inc.
  8. * - University of Dundee
  9. * %%
  10. * Licensed under the Apache License, Version 2.0 (the "License");
  11. * you may not use this file except in compliance with the License.
  12. * You may obtain a copy of the License at
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS,
  18. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. * See the License for the specific language governing permissions and
  20. * limitations under the License.
  21. * #L%
  22. */
  23. /* ====================================================================
  24. Licensed to the Apache Software Foundation (ASF) under one or more
  25. contributor license agreements. See the NOTICE file distributed with
  26. this work for additional information regarding copyright ownership.
  27. The ASF licenses this file to You under the Apache License, Version 2.0
  28. (the "License"); you may not use this file except in compliance with
  29. the License. You may obtain a copy of the License at
  30. http://www.apache.org/licenses/LICENSE-2.0
  31. Unless required by applicable law or agreed to in writing, software
  32. distributed under the License is distributed on an "AS IS" BASIS,
  33. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  34. See the License for the specific language governing permissions and
  35. limitations under the License.
  36. ==================================================================== */
  37. package loci.poi.hssf.model;
  38. import loci.poi.hssf.record.*;
  39. import loci.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
  40. import loci.poi.hssf.record.aggregates.FormulaRecordAggregate;
  41. import loci.poi.hssf.record.aggregates.RowRecordsAggregate;
  42. import loci.poi.hssf.record.aggregates.ValueRecordsAggregate;
  43. import loci.poi.hssf.record.formula.Ptg;
  44. import loci.poi.hssf.util.PaneInformation;
  45. import loci.poi.util.POILogFactory;
  46. import loci.poi.util.POILogger;
  47. import java.util.ArrayList;
  48. import java.util.Iterator;
  49. import java.util.List; // normally I don't do this, buy we literally mean ALL
  50. /**
  51. * Low level model implementation of a Sheet (one workbook contains many sheets)
  52. * This file contains the low level binary records starting at the sheets BOF and
  53. * ending with the sheets EOF. Use HSSFSheet for a high level representation.
  54. * <P>
  55. * The structures of the highlevel API use references to this to perform most of their
  56. * operations. Its probably unwise to use these low level structures directly unless you
  57. * really know what you're doing. I recommend you read the Microsoft Excel 97 Developer's
  58. * Kit (Microsoft Press) and the documentation at http://sc.openoffice.org/excelfileformat.pdf
  59. * before even attempting to use this.
  60. * <P>
  61. * @author Andrew C. Oliver (acoliver at apache dot org)
  62. * @author Glen Stampoultzis (glens at apache.org)
  63. * @author Shawn Laubach (slaubach at apache dot org) Gridlines, Headers, Footers, PrintSetup, and Setting Default Column Styles
  64. * @author Jason Height (jheight at chariot dot net dot au) Clone support. DBCell & Index Record writing support
  65. * @author Brian Sanders (kestrel at burdell dot org) Active Cell support
  66. * @author Jean-Pierre Paris (jean-pierre.paris at m4x dot org) (Just a little)
  67. *
  68. * @see loci.poi.hssf.model.Workbook
  69. * @see loci.poi.hssf.usermodel.HSSFSheet
  70. * @version 1.0-pre
  71. */
  72. public class Sheet implements Model
  73. {
  74. public static final short LeftMargin = 0;
  75. public static final short RightMargin = 1;
  76. public static final short TopMargin = 2;
  77. public static final short BottomMargin = 3;
  78. private static POILogger log = POILogFactory.getLogger(Sheet.class);
  79. protected ArrayList records = null;
  80. int preoffset = 0; // offset of the sheet in a new file
  81. int loc = 0;
  82. protected int dimsloc = 0;
  83. protected DimensionsRecord dims;
  84. protected DefaultColWidthRecord defaultcolwidth = null;
  85. protected DefaultRowHeightRecord defaultrowheight = null;
  86. protected GridsetRecord gridset = null;
  87. protected PrintSetupRecord printSetup = null;
  88. protected HeaderRecord header = null;
  89. protected FooterRecord footer = null;
  90. protected PrintGridlinesRecord printGridlines = null;
  91. protected WindowTwoRecord windowTwo = null;
  92. protected MergeCellsRecord merged = null;
  93. protected Margin[] margins = null;
  94. protected List mergedRecords = new ArrayList();
  95. protected int numMergedRegions = 0;
  96. protected SelectionRecord selection = null;
  97. protected ColumnInfoRecordsAggregate columns = null;
  98. protected ValueRecordsAggregate cells = null;
  99. protected RowRecordsAggregate rows = null;
  100. private Iterator valueRecIterator = null;
  101. private Iterator rowRecIterator = null;
  102. protected int eofLoc = 0;
  103. protected ProtectRecord protect = null;
  104. protected PageBreakRecord rowBreaks = null;
  105. protected PageBreakRecord colBreaks = null;
  106. protected ObjectProtectRecord objprotect = null;
  107. protected ScenarioProtectRecord scenprotect = null;
  108. protected PasswordRecord password = null;
  109. public static final byte PANE_LOWER_RIGHT = (byte)0;
  110. public static final byte PANE_UPPER_RIGHT = (byte)1;
  111. public static final byte PANE_LOWER_LEFT = (byte)2;
  112. public static final byte PANE_UPPER_LEFT = (byte)3;
  113. /**
  114. * Creates new Sheet with no intialization --useless at this point
  115. * @see #createSheet(List,int,int)
  116. */
  117. public Sheet()
  118. {
  119. }
  120. /**
  121. * read support (offset used as starting point for search) for low level
  122. * API. Pass in an array of Record objects, the sheet number (0 based) and
  123. * a record offset (should be the location of the sheets BOF record). A Sheet
  124. * object is constructed and passed back with all of its initialization set
  125. * to the passed in records and references to those records held. This function
  126. * is normally called via Workbook.
  127. *
  128. * @param recs array containing those records in the sheet in sequence (normally obtained from RecordFactory)
  129. * @param sheetnum integer specifying the sheet's number (0,1 or 2 in this release)
  130. * @param offset of the sheet's BOF record
  131. *
  132. * @return Sheet object with all values set to those read from the file
  133. *
  134. * @see loci.poi.hssf.model.Workbook
  135. * @see loci.poi.hssf.record.Record
  136. */
  137. public static Sheet createSheet(List recs, int sheetnum, int offset)
  138. {
  139. if (log.check( POILogger.DEBUG ))
  140. log.logFormatted(POILogger.DEBUG,
  141. "Sheet createSheet (existing file) with %",
  142. new Integer(recs.size()));
  143. Sheet retval = new Sheet();
  144. ArrayList records = new ArrayList(recs.size() / 5);
  145. boolean isfirstcell = true;
  146. boolean isfirstrow = true;
  147. int bofEofNestingLevel = 0;
  148. for (int k = offset; k < recs.size(); k++)
  149. {
  150. Record rec = ( Record ) recs.get(k);
  151. if (rec.getSid() == BOFRecord.sid)
  152. {
  153. bofEofNestingLevel++;
  154. if (log.check( POILogger.DEBUG ))
  155. log.log(POILogger.DEBUG, "Hit BOF record. Nesting increased to " + bofEofNestingLevel);
  156. }
  157. else if (rec.getSid() == EOFRecord.sid)
  158. {
  159. --bofEofNestingLevel;
  160. if (log.check( POILogger.DEBUG ))
  161. log.log(POILogger.DEBUG, "Hit EOF record. Nesting decreased to " + bofEofNestingLevel);
  162. if (bofEofNestingLevel == 0) {
  163. records.add(rec);
  164. retval.eofLoc = k;
  165. break;
  166. }
  167. }
  168. else if (rec.getSid() == DimensionsRecord.sid)
  169. {
  170. // Make a columns aggregate if one hasn't ready been created.
  171. if (retval.columns == null)
  172. {
  173. retval.columns = new ColumnInfoRecordsAggregate();
  174. records.add(retval.columns);
  175. }
  176. retval.dims = ( DimensionsRecord ) rec;
  177. retval.dimsloc = records.size();
  178. }
  179. else if (rec.getSid() == MergeCellsRecord.sid)
  180. {
  181. retval.mergedRecords.add(rec);
  182. retval.merged = ( MergeCellsRecord ) rec;
  183. retval.numMergedRegions += retval.merged.getNumAreas();
  184. }
  185. else if (rec.getSid() == ColumnInfoRecord.sid)
  186. {
  187. ColumnInfoRecord col = (ColumnInfoRecord)rec;
  188. if (retval.columns != null)
  189. {
  190. rec = null; //only add the aggregate once
  191. }
  192. else
  193. {
  194. rec = retval.columns = new ColumnInfoRecordsAggregate();
  195. }
  196. retval.columns.insertColumn(col);
  197. }
  198. else if (rec.getSid() == DefaultColWidthRecord.sid)
  199. {
  200. retval.defaultcolwidth = ( DefaultColWidthRecord ) rec;
  201. }
  202. else if (rec.getSid() == DefaultRowHeightRecord.sid)
  203. {
  204. retval.defaultrowheight = ( DefaultRowHeightRecord ) rec;
  205. }
  206. else if ( rec.isValue() && bofEofNestingLevel == 1 )
  207. {
  208. if ( isfirstcell )
  209. {
  210. retval.cells = new ValueRecordsAggregate();
  211. rec = retval.cells;
  212. retval.cells.construct( k, recs );
  213. isfirstcell = false;
  214. }
  215. else
  216. {
  217. rec = null;
  218. }
  219. }
  220. else if ( rec.getSid() == StringRecord.sid )
  221. {
  222. rec = null;
  223. }
  224. else if ( rec.getSid() == RowRecord.sid )
  225. {
  226. RowRecord row = (RowRecord)rec;
  227. if (!isfirstrow) rec = null; //only add the aggregate once
  228. if ( isfirstrow )
  229. {
  230. retval.rows = new RowRecordsAggregate();
  231. rec = retval.rows;
  232. isfirstrow = false;
  233. }
  234. retval.rows.insertRow(row);
  235. }
  236. else if ( rec.getSid() == PrintGridlinesRecord.sid )
  237. {
  238. retval.printGridlines = (PrintGridlinesRecord) rec;
  239. }
  240. else if ( rec.getSid() == GridsetRecord.sid )
  241. {
  242. retval.gridset = (GridsetRecord) rec;
  243. }
  244. else if ( rec.getSid() == HeaderRecord.sid && bofEofNestingLevel == 1)
  245. {
  246. retval.header = (HeaderRecord) rec;
  247. }
  248. else if ( rec.getSid() == FooterRecord.sid && bofEofNestingLevel == 1)
  249. {
  250. retval.footer = (FooterRecord) rec;
  251. }
  252. else if ( rec.getSid() == PrintSetupRecord.sid && bofEofNestingLevel == 1)
  253. {
  254. retval.printSetup = (PrintSetupRecord) rec;
  255. }
  256. else if ( rec.getSid() == LeftMarginRecord.sid)
  257. {
  258. retval.getMargins()[LeftMargin] = (LeftMarginRecord) rec;
  259. }
  260. else if ( rec.getSid() == RightMarginRecord.sid)
  261. {
  262. retval.getMargins()[RightMargin] = (RightMarginRecord) rec;
  263. }
  264. else if ( rec.getSid() == TopMarginRecord.sid)
  265. {
  266. retval.getMargins()[TopMargin] = (TopMarginRecord) rec;
  267. }
  268. else if ( rec.getSid() == BottomMarginRecord.sid)
  269. {
  270. retval.getMargins()[BottomMargin] = (BottomMarginRecord) rec;
  271. }
  272. else if ( rec.getSid() == SelectionRecord.sid )
  273. {
  274. retval.selection = (SelectionRecord) rec;
  275. }
  276. else if ( rec.getSid() == WindowTwoRecord.sid )
  277. {
  278. retval.windowTwo = (WindowTwoRecord) rec;
  279. }
  280. else if ( rec.getSid() == DBCellRecord.sid )
  281. {
  282. rec = null;
  283. }
  284. else if ( rec.getSid() == IndexRecord.sid )
  285. {
  286. rec = null;
  287. }
  288. else if ( rec.getSid() == ProtectRecord.sid )
  289. {
  290. retval.protect = (ProtectRecord) rec;
  291. }
  292. else if ( rec.getSid() == ObjectProtectRecord.sid )
  293. {
  294. retval.objprotect = (ObjectProtectRecord) rec;
  295. }
  296. else if ( rec.getSid() == ScenarioProtectRecord.sid )
  297. {
  298. retval.scenprotect = (ScenarioProtectRecord) rec;
  299. }
  300. else if ( rec.getSid() == PasswordRecord.sid )
  301. {
  302. retval.password = (PasswordRecord) rec;
  303. }
  304. else if (rec.getSid() == PageBreakRecord.HORIZONTAL_SID)
  305. {
  306. retval.rowBreaks = (PageBreakRecord)rec;
  307. }
  308. else if (rec.getSid() == PageBreakRecord.VERTICAL_SID)
  309. {
  310. retval.colBreaks = (PageBreakRecord)rec;
  311. }
  312. if (rec != null)
  313. {
  314. records.add(rec);
  315. }
  316. }
  317. retval.records = records;
  318. // if (retval.rows == null)
  319. // {
  320. // retval.rows = new RowRecordsAggregate();
  321. // }
  322. retval.checkCells();
  323. retval.checkRows();
  324. // if (retval.cells == null)
  325. // {
  326. // retval.cells = new ValueRecordsAggregate();
  327. // }
  328. if (log.check( POILogger.DEBUG ))
  329. log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited");
  330. return retval;
  331. }
  332. /**
  333. * Clones the low level records of this sheet and returns the new sheet instance.
  334. * This method is implemented by adding methods for deep cloning to all records that
  335. * can be added to a sheet. The <b>Record</b> object does not implement cloneable.
  336. * When adding a new record, implement a public clone method if and only if the record
  337. * belongs to a sheet.
  338. */
  339. public Sheet cloneSheet()
  340. {
  341. ArrayList clonedRecords = new ArrayList(this.records.size());
  342. for (int i=0; i<this.records.size();i++) {
  343. Record rec = (Record)((Record)this.records.get(i)).clone();
  344. //Need to pull out the Row record and the Value records from their
  345. //Aggregates.
  346. //This is probably the best way to do it since we probably dont want the createSheet
  347. //To cater for these artificial Record types
  348. if (rec instanceof RowRecordsAggregate) {
  349. RowRecordsAggregate rrAgg = (RowRecordsAggregate)rec;
  350. for (Iterator rowIter = rrAgg.getIterator();rowIter.hasNext();) {
  351. Record rowRec = (Record)rowIter.next();
  352. clonedRecords.add(rowRec);
  353. }
  354. } else if (rec instanceof ValueRecordsAggregate) {
  355. ValueRecordsAggregate vrAgg = (ValueRecordsAggregate)rec;
  356. for (Iterator cellIter = vrAgg.getIterator();cellIter.hasNext();) {
  357. Record valRec = (Record)cellIter.next();
  358. if (valRec instanceof FormulaRecordAggregate) {
  359. FormulaRecordAggregate fmAgg = (FormulaRecordAggregate)valRec;
  360. Record fmAggRec = fmAgg.getFormulaRecord();
  361. if (fmAggRec != null)
  362. clonedRecords.add(fmAggRec);
  363. fmAggRec = fmAgg.getStringRecord();
  364. if (fmAggRec != null)
  365. clonedRecords.add(fmAggRec);
  366. } else {
  367. clonedRecords.add(valRec);
  368. }
  369. }
  370. } else if (rec instanceof FormulaRecordAggregate) { //Is this required now??
  371. FormulaRecordAggregate fmAgg = (FormulaRecordAggregate)rec;
  372. Record fmAggRec = fmAgg.getFormulaRecord();
  373. if (fmAggRec != null)
  374. clonedRecords.add(fmAggRec);
  375. fmAggRec = fmAgg.getStringRecord();
  376. if (fmAggRec != null)
  377. clonedRecords.add(fmAggRec);
  378. } else {
  379. clonedRecords.add(rec);
  380. }
  381. }
  382. return createSheet(clonedRecords, 0, 0);
  383. }
  384. /**
  385. * read support (offset = 0) Same as createSheet(Record[] recs, int, int)
  386. * only the record offset is assumed to be 0.
  387. *
  388. * @param records array containing those records in the sheet in sequence (normally obtained from RecordFactory)
  389. * @param sheetnum integer specifying the sheet's number (0,1 or 2 in this release)
  390. * @return Sheet object
  391. */
  392. public static Sheet createSheet(List records, int sheetnum)
  393. {
  394. if (log.check( POILogger.DEBUG ))
  395. log.log(POILogger.DEBUG,
  396. "Sheet createSheet (exisiting file) assumed offset 0");
  397. return createSheet(records, sheetnum, 0);
  398. }
  399. /**
  400. * Creates a sheet with all the usual records minus values and the "index"
  401. * record (not required). Sets the location pointer to where the first value
  402. * records should go. Use this to create a sheet from "scratch".
  403. *
  404. * @return Sheet object with all values set to defaults
  405. */
  406. public static Sheet createSheet()
  407. {
  408. if (log.check( POILogger.DEBUG ))
  409. log.log(POILogger.DEBUG, "Sheet createsheet from scratch called");
  410. Sheet retval = new Sheet();
  411. ArrayList records = new ArrayList(30);
  412. records.add(retval.createBOF());
  413. // records.add(retval.createIndex());
  414. records.add(retval.createCalcMode());
  415. records.add(retval.createCalcCount() );
  416. records.add( retval.createRefMode() );
  417. records.add( retval.createIteration() );
  418. records.add( retval.createDelta() );
  419. records.add( retval.createSaveRecalc() );
  420. records.add( retval.createPrintHeaders() );
  421. retval.printGridlines = (PrintGridlinesRecord) retval.createPrintGridlines();
  422. records.add( retval.printGridlines );
  423. retval.gridset = (GridsetRecord) retval.createGridset();
  424. records.add( retval.gridset );
  425. records.add( retval.createGuts() );
  426. retval.defaultrowheight =
  427. (DefaultRowHeightRecord) retval.createDefaultRowHeight();
  428. records.add( retval.defaultrowheight );
  429. records.add( retval.createWSBool() );
  430. retval.rowBreaks = new PageBreakRecord(PageBreakRecord.HORIZONTAL_SID);
  431. records.add(retval.rowBreaks);
  432. retval.colBreaks = new PageBreakRecord(PageBreakRecord.VERTICAL_SID);
  433. records.add(retval.colBreaks);
  434. retval.header = (HeaderRecord) retval.createHeader();
  435. records.add( retval.header );
  436. retval.footer = (FooterRecord) retval.createFooter();
  437. records.add( retval.footer );
  438. records.add( retval.createHCenter() );
  439. records.add( retval.createVCenter() );
  440. retval.printSetup = (PrintSetupRecord) retval.createPrintSetup();
  441. records.add( retval.printSetup );
  442. retval.defaultcolwidth =
  443. (DefaultColWidthRecord) retval.createDefaultColWidth();
  444. records.add( retval.defaultcolwidth);
  445. ColumnInfoRecordsAggregate columns = new ColumnInfoRecordsAggregate();
  446. records.add( columns );
  447. retval.columns = columns;
  448. retval.dims = ( DimensionsRecord ) retval.createDimensions();
  449. records.add(retval.dims);
  450. retval.dimsloc = records.size()-1;
  451. records.add(retval.windowTwo = retval.createWindowTwo());
  452. retval.setLoc(records.size() - 1);
  453. retval.selection =
  454. (SelectionRecord) retval.createSelection();
  455. records.add(retval.selection);
  456. retval.protect = (ProtectRecord) retval.createProtect();
  457. records.add(retval.protect);
  458. records.add(retval.createEOF());
  459. retval.records = records;
  460. if (log.check( POILogger.DEBUG ))
  461. log.log(POILogger.DEBUG, "Sheet createsheet from scratch exit");
  462. return retval;
  463. }
  464. private void checkCells()
  465. {
  466. if (cells == null)
  467. {
  468. cells = new ValueRecordsAggregate();
  469. records.add(getDimsLoc() + 1, cells);
  470. }
  471. }
  472. private void checkRows()
  473. {
  474. if (rows == null)
  475. {
  476. rows = new RowRecordsAggregate();
  477. records.add(getDimsLoc() + 1, rows);
  478. }
  479. }
  480. //public int addMergedRegion(short rowFrom, short colFrom, short rowTo,
  481. public int addMergedRegion(int rowFrom, short colFrom, int rowTo,
  482. short colTo)
  483. {
  484. if (merged == null || merged.getNumAreas() == 1027)
  485. {
  486. merged = ( MergeCellsRecord ) createMergedCells();
  487. mergedRecords.add(merged);
  488. records.add(records.size() - 1, merged);
  489. }
  490. merged.addArea(rowFrom, colFrom, rowTo, colTo);
  491. return numMergedRegions++;
  492. }
  493. public void removeMergedRegion(int index)
  494. {
  495. //safety checks
  496. if (index >= numMergedRegions || mergedRecords.size() == 0)
  497. return;
  498. int pos = 0;
  499. int startNumRegions = 0;
  500. //optimisation for current record
  501. if (numMergedRegions - index < merged.getNumAreas())
  502. {
  503. pos = mergedRecords.size() - 1;
  504. startNumRegions = numMergedRegions - merged.getNumAreas();
  505. }
  506. else
  507. {
  508. for (int n = 0; n < mergedRecords.size(); n++)
  509. {
  510. MergeCellsRecord record = (MergeCellsRecord) mergedRecords.get(n);
  511. if (startNumRegions + record.getNumAreas() > index)
  512. {
  513. pos = n;
  514. break;
  515. }
  516. startNumRegions += record.getNumAreas();
  517. }
  518. }
  519. MergeCellsRecord rec = (MergeCellsRecord) mergedRecords.get(pos);
  520. rec.removeAreaAt(index - startNumRegions);
  521. numMergedRegions--;
  522. if (rec.getNumAreas() == 0)
  523. {
  524. mergedRecords.remove(pos);
  525. //get rid of the record from the sheet
  526. records.remove(merged);
  527. if (merged == rec) {
  528. //pull up the LAST record for operations when we finally
  529. //support continue records for mergedRegions
  530. if (mergedRecords.size() > 0) {
  531. merged = (MergeCellsRecord) mergedRecords.get(mergedRecords.size() - 1);
  532. } else {
  533. merged = null;
  534. }
  535. }
  536. }
  537. }
  538. public MergeCellsRecord.MergedRegion getMergedRegionAt(int index)
  539. {
  540. //safety checks
  541. if (index >= numMergedRegions || mergedRecords.size() == 0)
  542. return null;
  543. int pos = 0;
  544. int startNumRegions = 0;
  545. //optimisation for current record
  546. if (numMergedRegions - index < merged.getNumAreas())
  547. {
  548. pos = mergedRecords.size() - 1;
  549. startNumRegions = numMergedRegions - merged.getNumAreas();
  550. }
  551. else
  552. {
  553. for (int n = 0; n < mergedRecords.size(); n++)
  554. {
  555. MergeCellsRecord record = (MergeCellsRecord) mergedRecords.get(n);
  556. if (startNumRegions + record.getNumAreas() > index)
  557. {
  558. pos = n;
  559. break;
  560. }
  561. startNumRegions += record.getNumAreas();
  562. }
  563. }
  564. return ((MergeCellsRecord) mergedRecords.get(pos)).getAreaAt(index - startNumRegions);
  565. }
  566. public int getNumMergedRegions()
  567. {
  568. return numMergedRegions;
  569. }
  570. /**
  571. * Returns the number of low level binary records in this sheet. This adjusts things for the so called
  572. * AgregateRecords.
  573. *
  574. * @see loci.poi.hssf.record.Record
  575. */
  576. public int getNumRecords()
  577. {
  578. checkCells();
  579. checkRows();
  580. if (log.check( POILogger.DEBUG ))
  581. {
  582. log.log(POILogger.DEBUG, "Sheet.getNumRecords");
  583. log.logFormatted(POILogger.DEBUG, "returning % + % + % - 2 = %", new int[]
  584. {
  585. records.size(), cells.getPhysicalNumberOfCells(),
  586. rows.getPhysicalNumberOfRows(),
  587. records.size() + cells.getPhysicalNumberOfCells()
  588. + rows.getPhysicalNumberOfRows() - 2
  589. });
  590. }
  591. return records.size() + cells.getPhysicalNumberOfCells()
  592. + rows.getPhysicalNumberOfRows() - 2;
  593. }
  594. /**
  595. * Per an earlier reported bug in working with Andy Khan's excel read library. This
  596. * sets the values in the sheet's DimensionsRecord object to be correct. Excel doesn't
  597. * really care, but we want to play nice with other libraries.
  598. *
  599. * @see loci.poi.hssf.record.DimensionsRecord
  600. */
  601. //public void setDimensions(short firstrow, short firstcol, short lastrow,
  602. public void setDimensions(int firstrow, short firstcol, int lastrow,
  603. short lastcol)
  604. {
  605. if (log.check( POILogger.DEBUG ))
  606. {
  607. log.log(POILogger.DEBUG, "Sheet.setDimensions");
  608. log.log(POILogger.DEBUG,
  609. (new StringBuffer("firstrow")).append(firstrow)
  610. .append("firstcol").append(firstcol).append("lastrow")
  611. .append(lastrow).append("lastcol").append(lastcol)
  612. .toString());
  613. }
  614. dims.setFirstCol(firstcol);
  615. dims.setFirstRow(firstrow);
  616. dims.setLastCol(lastcol);
  617. dims.setLastRow(lastrow);
  618. if (log.check( POILogger.DEBUG ))
  619. log.log(POILogger.DEBUG, "Sheet.setDimensions exiting");
  620. }
  621. /**
  622. * set the locator for where we should look for the next value record. The
  623. * algorythm will actually start here and find the correct location so you
  624. * can set this to 0 and watch performance go down the tubes but it will work.
  625. * After a value is set this is automatically advanced. Its also set by the
  626. * create method. So you probably shouldn't mess with this unless you have
  627. * a compelling reason why or the help for the method you're calling says so.
  628. * Check the other methods for whether they care about
  629. * the loc pointer. Many of the "modify" and "remove" methods re-initialize this
  630. * to "dimsloc" which is the location of the Dimensions Record and presumably the
  631. * start of the value section (at or around 19 dec).
  632. *
  633. * @param loc the record number to start at
  634. *
  635. */
  636. public void setLoc(int loc)
  637. {
  638. valueRecIterator = null;
  639. if (log.check( POILogger.DEBUG ))
  640. log.log(POILogger.DEBUG, "sheet.setLoc(): " + loc);
  641. this.loc = loc;
  642. }
  643. /**
  644. * Returns the location pointer to the first record to look for when adding rows/values
  645. *
  646. */
  647. public int getLoc()
  648. {
  649. if (log.check( POILogger.DEBUG ))
  650. log.log(POILogger.DEBUG, "sheet.getLoc():" + loc);
  651. return loc;
  652. }
  653. /**
  654. * Set the preoffset when using DBCELL records (currently unused) - this is
  655. * the position of this sheet within the whole file.
  656. *
  657. * @param offset the offset of the sheet's BOF within the file.
  658. */
  659. public void setPreOffset(int offset)
  660. {
  661. this.preoffset = offset;
  662. }
  663. /**
  664. * get the preoffset when using DBCELL records (currently unused) - this is
  665. * the position of this sheet within the whole file.
  666. *
  667. * @return offset the offset of the sheet's BOF within the file.
  668. */
  669. public int getPreOffset()
  670. {
  671. return preoffset;
  672. }
  673. /**
  674. * Serializes all records in the sheet into one big byte array. Use this to write
  675. * the sheet out.
  676. *
  677. * @param offset to begin write at
  678. * @param data array containing the binary representation of the records in this sheet
  679. *
  680. */
  681. public int serialize(int offset, byte [] data)
  682. {
  683. if (log.check( POILogger.DEBUG ))
  684. log.log(POILogger.DEBUG, "Sheet.serialize using offsets");
  685. int pos = offset;
  686. boolean haveSerializedIndex = false;
  687. for (int k = 0; k < records.size(); k++)
  688. {
  689. Record record = (( Record ) records.get(k));
  690. //Once the rows have been found in the list of records, start
  691. //writing out the blocked row information. This includes the DBCell references
  692. if (record instanceof RowRecordsAggregate) {
  693. pos += ((RowRecordsAggregate)record).serialize(pos, data, cells); // rec.length;
  694. } else if (record instanceof ValueRecordsAggregate) {
  695. //Do nothing here. The records were serialized during the RowRecordAggregate block serialization
  696. } else {
  697. pos += record.serialize(pos, data ); // rec.length;
  698. }
  699. //If the BOF record was just serialized then add the IndexRecord
  700. if (record.getSid() == BOFRecord.sid) {
  701. //Can there be more than one BOF for a sheet? If not then we can
  702. //remove this guard. So be safe it is left here.
  703. if (rows != null && !haveSerializedIndex) {
  704. haveSerializedIndex = true;
  705. pos += serializeIndexRecord(k, pos, data);
  706. }
  707. }
  708. //// uncomment to test record sizes ////
  709. // System.out.println( record.getClass().getName() );
  710. // byte[] data2 = new byte[record.getRecordSize()];
  711. // record.serialize(0, data2 ); // rec.length;
  712. // if (LittleEndian.getUShort(data2, 2) != record.getRecordSize() - 4
  713. // && record instanceof RowRecordsAggregate == false
  714. // && record instanceof ValueRecordsAggregate == false
  715. // && record instanceof EscherAggregate == false)
  716. // {
  717. // throw new RuntimeException("Blah!!! Size off by " + ( LittleEndian.getUShort(data2, 2) - record.getRecordSize() - 4) + " records.");
  718. // }
  719. //asd: int len = record.serialize(pos + offset, data );
  720. ///// DEBUG BEGIN /////
  721. //asd: if (len != record.getRecordSize())
  722. //asd: throw new IllegalStateException("Record size does not match serialized bytes. Serialized size = " + len + " but getRecordSize() returns " + record.getRecordSize() + ". Record object is " + record.getClass());
  723. ///// DEBUG END /////
  724. //asd: pos += len; // rec.length;
  725. }
  726. if (log.check( POILogger.DEBUG ))
  727. log.log(POILogger.DEBUG, "Sheet.serialize returning ");
  728. return pos-offset;
  729. }
  730. private int serializeIndexRecord(final int BOFRecordIndex, final int offset, byte[] data) {
  731. IndexRecord index = new IndexRecord();
  732. index.setFirstRow(rows.getFirstRowNum());
  733. index.setLastRowAdd1(rows.getLastRowNum()+1);
  734. //Calculate the size of the records from the end of the BOF
  735. //and up to the RowRecordsAggregate...
  736. int sheetRecSize = 0;
  737. for (int j = BOFRecordIndex+1; j < records.size(); j++)
  738. {
  739. Record tmpRec = (( Record ) records.get(j));
  740. if (tmpRec instanceof RowRecordsAggregate)
  741. break;
  742. sheetRecSize+= tmpRec.getRecordSize();
  743. }
  744. //Add the references to the DBCells in the IndexRecord (one for each block)
  745. int blockCount = rows.getRowBlockCount();
  746. //Calculate the size of this IndexRecord
  747. int indexRecSize = IndexRecord.getRecordSizeForBlockCount(blockCount);
  748. int rowBlockOffset = 0;
  749. int cellBlockOffset = 0;
  750. int dbCellOffset = 0;
  751. for (int block=0;block<blockCount;block++) {
  752. rowBlockOffset += rows.getRowBlockSize(block);
  753. cellBlockOffset += null == cells ? 0 : cells.getRowCellBlockSize(rows.getStartRowNumberForBlock(block),
  754. rows.getEndRowNumberForBlock(block));
  755. //Note: The offsets are relative to the Workbook BOF. Assume that this is
  756. //0 for now.....
  757. index.addDbcell(offset + indexRecSize + sheetRecSize + dbCellOffset + rowBlockOffset + cellBlockOffset);
  758. //Add space required to write the dbcell record(s) (whose references were just added).
  759. dbCellOffset += (8 + (rows.getRowCountForBlock(block) * 2));
  760. }
  761. return index.serialize(offset, data);
  762. }
  763. /**
  764. * Create a row record. (does not add it to the records contained in this sheet)
  765. *
  766. * @param row number
  767. * @return RowRecord created for the passed in row number
  768. * @see loci.poi.hssf.record.RowRecord
  769. */
  770. public RowRecord createRow(int row)
  771. {
  772. return RowRecordsAggregate.createRow( row );
  773. }
  774. /**
  775. * Create a LABELSST Record (does not add it to the records contained in this sheet)
  776. *
  777. * @param row the row the LabelSST is a member of
  778. * @param col the column the LabelSST defines
  779. * @param index the index of the string within the SST (use workbook addSSTString method)
  780. * @return LabelSSTRecord newly created containing your SST Index, row,col.
  781. * @see loci.poi.hssf.record.SSTRecord
  782. */
  783. //public LabelSSTRecord createLabelSST(short row, short col, int index)
  784. public LabelSSTRecord createLabelSST(int row, short col, int index)
  785. {
  786. log.logFormatted(POILogger.DEBUG, "create labelsst row,col,index %,%,%",
  787. new int[]
  788. {
  789. row, col, index
  790. });
  791. LabelSSTRecord rec = new LabelSSTRecord();
  792. rec.setRow(row);
  793. rec.setColumn(col);
  794. rec.setSSTIndex(index);
  795. rec.setXFIndex(( short ) 0x0f);
  796. return rec;
  797. }
  798. /**
  799. * Create a NUMBER Record (does not add it to the records contained in this sheet)
  800. *
  801. * @param row the row the NumberRecord is a member of
  802. * @param col the column the NumberRecord defines
  803. * @param value for the number record
  804. *
  805. * @return NumberRecord for that row, col containing that value as added to the sheet
  806. */
  807. //public NumberRecord createNumber(short row, short col, double value)
  808. public NumberRecord createNumber(int row, short col, double value)
  809. {
  810. log.logFormatted(POILogger.DEBUG, "create number row,col,value %,%,%",
  811. new double[]
  812. {
  813. row, col, value
  814. });
  815. NumberRecord rec = new NumberRecord();
  816. //rec.setRow(( short ) row);
  817. rec.setRow(row);
  818. rec.setColumn(col);
  819. rec.setValue(value);
  820. rec.setXFIndex(( short ) 0x0f);
  821. return rec;
  822. }
  823. /**
  824. * create a BLANK record (does not add it to the records contained in this sheet)
  825. *
  826. * @param row - the row the BlankRecord is a member of
  827. * @param col - the column the BlankRecord is a member of
  828. */
  829. //public BlankRecord createBlank(short row, short col)
  830. public BlankRecord createBlank(int row, short col)
  831. {
  832. //log.logFormatted(POILogger.DEBUG, "create blank row,col %,%", new short[]
  833. log.logFormatted(POILogger.DEBUG, "create blank row,col %,%", new int[]
  834. {
  835. row, col
  836. });
  837. BlankRecord rec = new BlankRecord();
  838. //rec.setRow(( short ) row);
  839. rec.setRow(row);
  840. rec.setColumn(col);
  841. rec.setXFIndex(( short ) 0x0f);
  842. return rec;
  843. }
  844. /**
  845. * Attempts to parse the formula into PTGs and create a formula record
  846. * DOES NOT WORK YET
  847. *
  848. * @param row - the row for the formula record
  849. * @param col - the column of the formula record
  850. * @param formula - a String representing the formula. To be parsed to PTGs
  851. * @return bogus/useless formula record
  852. */
  853. //public FormulaRecord createFormula(short row, short col, String formula)
  854. public FormulaRecord createFormula(int row, short col, String formula)
  855. {
  856. log.logFormatted(POILogger.DEBUG, "create formula row,col,formula %,%,%",
  857. //new short[]
  858. new int[]
  859. {
  860. row, col
  861. }, formula);
  862. FormulaRecord rec = new FormulaRecord();
  863. rec.setRow(row);
  864. rec.setColumn(col);
  865. rec.setOptions(( short ) 2);
  866. rec.setValue(0);
  867. rec.setXFIndex(( short ) 0x0f);
  868. FormulaParser fp = new FormulaParser(formula,null); //fix - do we need this method?
  869. fp.parse();
  870. Ptg[] ptg = fp.getRPNPtg();
  871. int size = 0;
  872. for (int k = 0; k < ptg.length; k++)
  873. {
  874. size += ptg[ k ].getSize();
  875. rec.pushExpressionToken(ptg[ k ]);
  876. }
  877. rec.setExpressionLength(( short ) size);
  878. return rec;
  879. }
  880. /**
  881. * Adds a value record to the sheet's contained binary records
  882. * (i.e. LabelSSTRecord or NumberRecord).
  883. * <P>
  884. * This method is "loc" sensitive. Meaning you need to set LOC to where you
  885. * want it to start searching. If you don't know do this: setLoc(getDimsLoc).
  886. * When adding several rows you can just start at the last one by leaving loc
  887. * at what this sets it to.
  888. *
  889. * @param row the row to add the cell value to
  890. * @param col the cell value record itself.
  891. */
  892. //public void addValueRecord(short row, CellValueRecordInterface col)
  893. public void addValueRecord(int row, CellValueRecordInterface col)
  894. {
  895. checkCells();
  896. if(log.check(POILogger.DEBUG))
  897. {
  898. log.logFormatted(POILogger.DEBUG, "add value record row,loc %,%", new int[]
  899. {
  900. row, loc
  901. });
  902. }
  903. DimensionsRecord d = ( DimensionsRecord ) records.get(getDimsLoc());
  904. if (col.getColumn() > d.getLastCol())
  905. {
  906. d.setLastCol(( short ) (col.getColumn() + 1));
  907. }
  908. if (col.getColumn() < d.getFirstCol())
  909. {
  910. d.setFirstCol(col.getColumn());
  911. }
  912. cells.insertCell(col);
  913. /*
  914. * for (int k = loc; k < records.size(); k++)
  915. * {
  916. * Record rec = ( Record ) records.get(k);
  917. *
  918. * if (rec.getSid() == RowRecord.sid)
  919. * {
  920. * RowRecord rowrec = ( RowRecord ) rec;
  921. *
  922. * if (rowrec.getRowNumber() == col.getRow())
  923. * {
  924. * records.add(k + 1, col);
  925. * loc = k;
  926. * if (rowrec.getLastCol() <= col.getColumn())
  927. * {
  928. * rowrec.setLastCol((( short ) (col.getColumn() + 1)));
  929. * }
  930. * break;
  931. * }
  932. * }
  933. * }
  934. */
  935. }
  936. /**
  937. * remove a value record from the records array.
  938. *
  939. * This method is not loc sensitive, it resets loc to = dimsloc so no worries.
  940. *
  941. * @param row - the row of the value record you wish to remove
  942. * @param col - a record supporting the CellValueRecordInterface.
  943. * @see loci.poi.hssf.record.CellValueRecordInterface
  944. */
  945. //public void removeValueRecord(short row, CellValueRecordInterface col)
  946. public void removeValueRecord(int row, CellValueRecordInterface col)
  947. {
  948. checkCells();
  949. log.logFormatted(POILogger.DEBUG, "remove value record row,dimsloc %,%",
  950. new int[]{row, dimsloc} );
  951. loc = dimsloc;
  952. cells.removeCell(col);
  953. /*
  954. * for (int k = loc; k < records.size(); k++)
  955. * {
  956. * Record rec = ( Record ) records.get(k);
  957. *
  958. * // checkDimsLoc(rec,k);
  959. * if (rec.isValue())
  960. * {
  961. * CellValueRecordInterface cell =
  962. * ( CellValueRecordInterface ) rec;
  963. *
  964. * if ((cell.getRow() == col.getRow())
  965. * && (cell.getColumn() == col.getColumn()))
  966. * {
  967. * records.remove(k);
  968. * break;
  969. * }
  970. * }
  971. * }
  972. */
  973. }
  974. /**
  975. * replace a value record from the records array.
  976. *
  977. * This method is not loc sensitive, it resets loc to = dimsloc so no worries.
  978. *
  979. * @param newval - a record supporting the CellValueRecordInterface. this will replace
  980. * the cell value with the same row and column. If there isn't one, one will
  981. * be added.
  982. */
  983. public void replaceValueRecord(CellValueRecordInterface newval)
  984. {
  985. checkCells();
  986. setLoc(dimsloc);
  987. if (log.check( POILogger.DEBUG ))
  988. log.log(POILogger.DEBUG, "replaceValueRecord ");
  989. //The ValueRecordsAggregate use a tree map underneath.
  990. //The tree Map uses the CellValueRecordInterface as both the
  991. //key and the value, if we dont do a remove, then
  992. //the previous instance of the key is retained, effectively using
  993. //double the memory
  994. cells.removeCell(newval);
  995. cells.insertCell(newval);
  996. /*
  997. * CellValueRecordInterface oldval = getNextValueRecord();
  998. *
  999. * while (oldval != null)
  1000. * {
  1001. * if (oldval.isEqual(newval))
  1002. * {
  1003. * records.set(( short ) (getLoc() - 1), newval);
  1004. * return;
  1005. * }
  1006. * oldval = getNextValueRecord();
  1007. * }
  1008. * addValueRecord(newval.getRow(), newval);
  1009. * setLoc(dimsloc);
  1010. */
  1011. }
  1012. /**
  1013. * Adds a row record to the sheet
  1014. *
  1015. * <P>
  1016. * This method is "loc" sensitive. Meaning you need to set LOC to where you
  1017. * want it to start searching. If you don't know do this: setLoc(getDimsLoc).
  1018. * When adding several rows you can just start at the last one by leaving loc
  1019. * at what this sets it to.
  1020. *
  1021. * @param row the row record to be added
  1022. * @see #setLoc(int)
  1023. */
  1024. public void addRow(RowRecord row)
  1025. {
  1026. checkRows();
  1027. if (log.check( POILogger.DEBUG ))
  1028. log.log(POILogger.DEBUG, "addRow ");
  1029. DimensionsRecord d = ( DimensionsRecord ) records.get(getDimsLoc());
  1030. if (row.getRowNumber() >= d.getLastRow())
  1031. {
  1032. d.setLastRow(row.getRowNumber() + 1);
  1033. }
  1034. if (row.getRowNumber() < d.getFirstRow())
  1035. {
  1036. d.setFirstRow(row.getRowNumber());
  1037. }
  1038. //IndexRecord index = null;
  1039. //If the row exists remove it, so that any cells attached to the row are removed
  1040. RowRecord existingRow = rows.getRow(row.getRowNumber());
  1041. if (existingRow != null)
  1042. rows.removeRow(existingRow);
  1043. rows.insertRow(row);
  1044. /*
  1045. * for (int k = loc; k < records.size(); k++)
  1046. * {
  1047. * Record rec = ( Record ) records.get(k);
  1048. *
  1049. * if (rec.getSid() == IndexRecord.sid)
  1050. * {
  1051. * index = ( IndexRecord ) rec;
  1052. * }
  1053. * if (rec.getSid() == RowRecord.sid)
  1054. * {
  1055. * RowRecord rowrec = ( RowRecord ) rec;
  1056. *
  1057. * if (rowrec.getRowNumber() > row.getRowNumber())
  1058. * {
  1059. * records.add(k, row);
  1060. * loc = k;
  1061. * break;
  1062. * }
  1063. * }
  1064. * if (rec.getSid() == WindowTwoRecord.sid)
  1065. * {
  1066. * records.add(k, row);
  1067. * loc = k;
  1068. * break;
  1069. * }
  1070. * }
  1071. * if (index != null)
  1072. * {
  1073. * if (index.getLastRowAdd1() <= row.getRowNumber())
  1074. * {
  1075. * index.setLastRowAdd1(row.getRowNumber() + 1);
  1076. * }
  1077. * }
  1078. */
  1079. if (log.check( POILogger.DEBUG ))
  1080. log.log(POILogger.DEBUG, "exit addRow");
  1081. }
  1082. /**
  1083. * Removes a row record
  1084. *
  1085. * This method is not loc sensitive, it resets loc to = dimsloc so no worries.
  1086. *
  1087. * @param row the row record to remove
  1088. */
  1089. public void removeRow(RowRecord row)
  1090. {
  1091. checkRows();
  1092. // IndexRecord index = null;
  1093. setLoc(getDimsLoc());
  1094. rows.removeRow(row);
  1095. /*
  1096. * for (int k = loc; k < records.size(); k++)
  1097. * {
  1098. * Record rec = ( Record ) records.get(k);
  1099. *
  1100. * // checkDimsLoc(rec,k);
  1101. * if (rec.getSid() == RowRecord.sid)
  1102. * {
  1103. * RowRecord rowrec = ( RowRecord ) rec;
  1104. *
  1105. * if (rowrec.getRowNumber() == row.getRowNumber())
  1106. * {
  1107. * records.remove(k);
  1108. * break;
  1109. * }
  1110. * }
  1111. * if (rec.getSid() == WindowTwoRecord.sid)
  1112. * {
  1113. * break;
  1114. * }
  1115. * }
  1116. */
  1117. }
  1118. /**
  1119. * get the NEXT value record (from LOC). The first record that is a value record
  1120. * (starting at LOC) will be returned.
  1121. *
  1122. * <P>
  1123. * This method is "loc" sensitive. Meaning you need to set LOC to where you
  1124. * want it to start searching. If you don't know do this: setLoc(getDimsLoc).
  1125. * When adding several rows you can just start at the last one by leaving loc
  1126. * at what this sets it to. For this method, set loc to dimsloc to start with,
  1127. * subsequent calls will return values in (physical) sequence or NULL when you get to the end.
  1128. *
  1129. * @return CellValueRecordInterface representing the next value record or NULL if there are no more
  1130. * @see #setLoc(int)
  1131. */
  1132. public CellValueRecordInterface getNextValueRecord()
  1133. {
  1134. if (log.check( POILogger.DEBUG ))
  1135. log.log(POILogger.DEBUG, "getNextValue loc= " + loc);
  1136. if (valueRecIterator == null)
  1137. {
  1138. valueRecIterator = cells.getIterator();
  1139. }
  1140. if (!valueRecIterator.hasNext())
  1141. {
  1142. return null;
  1143. }
  1144. return ( CellValueRecordInterface ) valueRecIterator.next();
  1145. /*
  1146. * if (this.getLoc() < records.size())
  1147. * {
  1148. * for (int k = getLoc(); k < records.size(); k++)
  1149. * {
  1150. * Record rec = ( Record ) records.get(k);
  1151. *
  1152. * this.setLoc(k + 1);
  1153. * if (rec instanceof CellValueRecordInterface)
  1154. * {
  1155. * return ( CellValueRecordInterface ) rec;
  1156. * }
  1157. * }
  1158. * }
  1159. * return null;
  1160. */
  1161. }
  1162. /**
  1163. * get the NEXT RowRecord or CellValueRecord(from LOC). The first record that
  1164. * is a Row record or CellValueRecord(starting at LOC) will be returned.
  1165. * <P>
  1166. * This method is "loc" sensitive. Meaning you need to set LOC to where you
  1167. * want it to start searching. If you don't know do this: setLoc(getDimsLoc).
  1168. * When adding several rows you can just start at the last one by leaving loc
  1169. * at what this sets it to. For this method, set loc to dimsloc to start with.
  1170. * subsequent calls will return rows in (physical) sequence or NULL when you get to the end.
  1171. *
  1172. * @return RowRecord representing the next row record or CellValueRecordInterface
  1173. * representing the next cellvalue or NULL if there are no more
  1174. * @see #setLoc(int)
  1175. *
  1176. */
  1177. /* public Record getNextRowOrValue()
  1178. {
  1179. POILogger.DEBUG((new StringBuffer("getNextRow loc= ")).append(loc)
  1180. .toString());
  1181. if (this.getLoc() < records.size())
  1182. {
  1183. for (int k = this.getLoc(); k < records.size(); k++)
  1184. {
  1185. Record rec = ( Record ) records.get(k);
  1186. this.setLoc(k + 1);
  1187. if (rec.getSid() == RowRecord.sid)
  1188. {
  1189. return rec;
  1190. }
  1191. else if (rec.isValue())
  1192. {
  1193. return rec;
  1194. }
  1195. }
  1196. }
  1197. return null;
  1198. }
  1199. */
  1200. /**
  1201. * get the NEXT RowRecord (from LOC). The first record that is a Row record
  1202. * (starting at LOC) will be returned.
  1203. * <P>
  1204. * This method is "loc" sensitive. Meaning you need to set LOC to where you
  1205. * want it to start searching. If you don't know do this: setLoc(getDimsLoc).
  1206. * When adding several rows you can just start at the last one by leaving loc
  1207. * at what this sets it to. For this method, set loc to dimsloc to start with.
  1208. * subsequent calls will return rows in (physical) sequence or NULL when you get to the end.
  1209. *
  1210. * @return RowRecord representing the next row record or NULL if there are no more
  1211. * @see #setLoc(int)
  1212. *
  1213. */
  1214. public RowRecord getNextRow()
  1215. {
  1216. if (log.check( POILogger.DEBUG ))
  1217. log.log(POILogger.DEBUG, "getNextRow loc= " + loc);
  1218. if (rowRecIterator == null)
  1219. {
  1220. rowRecIterator = rows.getIterator();
  1221. }
  1222. if (!rowRecIterator.hasNext())
  1223. {
  1224. return null;
  1225. }
  1226. return ( RowRecord ) rowRecIterator.next();
  1227. /* if (this.getLoc() < records.size())
  1228. {
  1229. for (int k = this.getLoc(); k < records.size(); k++)
  1230. {
  1231. Record rec = ( Record ) records.get(k);
  1232. this.setLoc(k + 1);
  1233. if (rec.getSid() == RowRecord.sid)
  1234. {
  1235. return ( RowRecord ) rec;
  1236. }
  1237. }
  1238. }*/
  1239. }
  1240. /**
  1241. * get the NEXT (from LOC) RowRecord where rownumber matches the given rownum.
  1242. * The first record that is a Row record (starting at LOC) that has the
  1243. * same rownum as the given rownum will be returned.
  1244. * <P>
  1245. * This method is "loc" sensitive. Meaning you need to set LOC to where you
  1246. * want it to start searching. If you don't know do this: setLoc(getDimsLoc).
  1247. * When adding several rows you can just start at the last one by leaving loc
  1248. * at what this sets it to. For this method, set loc to dimsloc to start with.
  1249. * subsequent calls will return rows in (physical) sequence or NULL when you get to the end.
  1250. *
  1251. * @param rownum which row to return (careful with LOC)
  1252. * @return RowRecord representing the next row record or NULL if there are no more
  1253. * @see #setLoc(int)
  1254. *
  1255. */
  1256. //public RowRecord getRow(short rownum)
  1257. public RowRecord getRow(int rownum)
  1258. {
  1259. if (log.check( POILogger.DEBUG ))
  1260. log.log(POILogger.DEBUG, "getNextRow loc= " + loc);
  1261. return rows.getRow(rownum);
  1262. /*
  1263. * if (this.getLoc() < records.size())
  1264. * {
  1265. * for (int k = this.getLoc(); k < records.size(); k++)
  1266. * {
  1267. * Record rec = ( Record ) records.get(k);
  1268. *
  1269. * this.setLoc(k + 1);
  1270. * if (rec.getSid() == RowRecord.sid)
  1271. * {
  1272. * if ((( RowRecord ) rec).getRowNumber() == rownum)
  1273. * {
  1274. * return ( RowRecord ) rec;
  1275. * }
  1276. * }
  1277. * }
  1278. * }
  1279. */
  1280. // return null;
  1281. }
  1282. /**
  1283. * creates the BOF record
  1284. * @see loci.poi.hssf.record.BOFRecord
  1285. * @see loci.poi.hssf.record.Record
  1286. * @return record containing a BOFRecord
  1287. */
  1288. protected Record createBOF()
  1289. {
  1290. BOFRecord retval = new BOFRecord();
  1291. retval.setVersion(( short ) 0x600);
  1292. retval.setType(( short ) 0x010);
  1293. // retval.setBuild((short)0x10d3);
  1294. retval.setBuild(( short ) 0x0dbb);
  1295. retval.setBuildYear(( short ) 1996);
  1296. retval.setHistoryBitMask(0xc1);
  1297. retval.setRequiredVersion(0x6);
  1298. return retval;
  1299. }
  1300. /**
  1301. * creates the Index record - not currently used
  1302. * @see loci.poi.hssf.record.IndexRecord
  1303. * @see loci.poi.hssf.record.Record
  1304. * @return record containing a IndexRecord
  1305. */
  1306. protected Record createIndex()
  1307. {
  1308. IndexRecord retval = new IndexRecord();
  1309. retval.setFirstRow(0); // must be set explicitly
  1310. retval.setLastRowAdd1(0);
  1311. return retval;
  1312. }
  1313. /**
  1314. * creates the CalcMode record and sets it to 1 (automatic formula caculation)
  1315. * @see loci.poi.hssf.record.CalcModeRecord
  1316. * @see loci.poi.hssf.record.Record
  1317. * @return record containing a CalcModeRecord
  1318. */
  1319. protected Record createCalcMode()
  1320. {
  1321. CalcModeRecord retval = new CalcModeRecord();
  1322. retval.setCalcMode(( short ) 1);
  1323. return retval;
  1324. }
  1325. /**
  1326. * creates the CalcCount record and sets it to 0x64 (default number of iterations)
  1327. * @see loci.poi.hssf.record.CalcCountRecord
  1328. * @see loci.poi.hssf.record.Record
  1329. * @return record containing a CalcCountRecord
  1330. */
  1331. protected Record createCalcCount()
  1332. {
  1333. CalcCountRecord retval = new CalcCountRecord();
  1334. retval.setIterations(( short ) 0x64); // default 64 iterations
  1335. return retval;
  1336. }
  1337. /**
  1338. * creates the RefMode record and sets it to A1 Mode (default reference mode)
  1339. * @see loci.poi.hssf.record.RefModeRecord
  1340. * @see loci.poi.hssf.record.Record
  1341. * @return record containing a RefModeRecord
  1342. */
  1343. protected Record createRefMode()
  1344. {
  1345. RefModeRecord retval = new RefModeRecord();
  1346. retval.setMode(RefModeRecord.USE_A1_MODE);
  1347. return retval;
  1348. }
  1349. /**
  1350. * creates the Iteration record and sets it to false (don't iteratively calculate formulas)
  1351. * @see loci.poi.hssf.record.IterationRecord
  1352. * @see loci.poi.hssf.record.Record
  1353. * @return record containing a IterationRecord
  1354. */
  1355. protected Record createIteration()
  1356. {
  1357. IterationRecord retval = new IterationRecord();
  1358. retval.setIteration(false);
  1359. return retval;
  1360. }
  1361. /**
  1362. * creates the Delta record and sets it to 0.0010 (default accuracy)
  1363. * @see loci.poi.hssf.record.DeltaRecord
  1364. * @see loci.poi.hssf.record.Record
  1365. * @return record containing a DeltaRecord
  1366. */
  1367. protected Record createDelta()
  1368. {
  1369. DeltaRecord retval = new DeltaRecord();
  1370. retval.setMaxChange(0.0010);
  1371. return retval;
  1372. }
  1373. /**
  1374. * creates the SaveRecalc record and sets it to true (recalculate before saving)
  1375. * @see loci.poi.hssf.record.SaveRecalcRecord
  1376. * @see loci.poi.hssf.record.Record
  1377. * @return record containing a SaveRecalcRecord
  1378. */
  1379. protected Record createSaveRecalc()
  1380. {
  1381. SaveRecalcRecord retval = new SaveRecalcRecord();
  1382. retval.setRecalc(true);
  1383. return retval;
  1384. }
  1385. /**
  1386. * creates the PrintHeaders record and sets it to false (we don't create headers yet so why print them)
  1387. * @see loci.poi.hssf.record.PrintHeadersRecord
  1388. * @see loci.poi.hssf.record.Record
  1389. * @return record containing a PrintHeadersRecord
  1390. */
  1391. protected Record createPrintHeaders()
  1392. {
  1393. PrintHeadersRecord retval = new PrintHeadersRecord();
  1394. retval.setPrintHeaders(false);
  1395. return retval;
  1396. }
  1397. /**
  1398. * creates the PrintGridlines record and sets it to false (that makes for ugly sheets). As far as I can
  1399. * tell this does the same thing as the GridsetRecord
  1400. *
  1401. * @see loci.poi.hssf.record.PrintGridlinesRecord
  1402. * @see loci.poi.hssf.record.Record
  1403. * @return record containing a PrintGridlinesRecord
  1404. */
  1405. protected Record createPrintGridlines()
  1406. {
  1407. PrintGridlinesRecord retval = new PrintGridlinesRecord();
  1408. retval.setPrintGridlines(false);
  1409. return retval;
  1410. }
  1411. /**
  1412. * creates the Gridset record and sets it to true (user has mucked with the gridlines)
  1413. * @see loci.poi.hssf.record.GridsetRecord
  1414. * @see loci.poi.hssf.record.Record
  1415. * @return record containing a GridsetRecord
  1416. */
  1417. protected Record createGridset()
  1418. {
  1419. GridsetRecord retval = new GridsetRecord();
  1420. retval.setGridset(true);
  1421. return retval;
  1422. }
  1423. /**
  1424. * creates the Guts record and sets leftrow/topcol guttter and rowlevelmax/collevelmax to 0
  1425. * @see loci.poi.hssf.record.GutsRecord
  1426. * @see loci.poi.hssf.record.Record
  1427. * @return record containing a GutsRecordRecord
  1428. */
  1429. protected Record createGuts()
  1430. {
  1431. GutsRecord retval = new GutsRecord();
  1432. retval.setLeftRowGutter(( short ) 0);
  1433. retval.setTopColGutter(( short ) 0);
  1434. retval.setRowLevelMax(( short ) 0);
  1435. retval.setColLevelMax(( short ) 0);
  1436. return retval;
  1437. }
  1438. /**
  1439. * creates the DefaultRowHeight Record and sets its options to 0 and rowheight to 0xff
  1440. * @see loci.poi.hssf.record.DefaultRowHeightRecord
  1441. * @see loci.poi.hssf.record.Record
  1442. * @return record containing a DefaultRowHeightRecord
  1443. */
  1444. protected Record createDefaultRowHeight()
  1445. {
  1446. DefaultRowHeightRecord retval = new DefaultRowHeightRecord();
  1447. retval.setOptionFlags(( short ) 0);
  1448. retval.setRowHeight(( short ) 0xff);
  1449. return retval;
  1450. }
  1451. /**
  1452. * creates the WSBoolRecord and sets its values to defaults
  1453. * @see loci.poi.hssf.record.WSBoolRecord
  1454. * @see loci.poi.hssf.record.Record
  1455. * @return record containing a WSBoolRecord
  1456. */
  1457. protected Record createWSBool()
  1458. {
  1459. WSBoolRecord retval = new WSBoolRecord();
  1460. retval.setWSBool1(( byte ) 0x4);
  1461. retval.setWSBool2(( byte ) 0xffffffc1);
  1462. return retval;
  1463. }
  1464. /**
  1465. * creates the Header Record and sets it to nothing/0 length
  1466. * @see loci.poi.hssf.record.HeaderRecord
  1467. * @see loci.poi.hssf.record.Record
  1468. * @return record containing a HeaderRecord
  1469. */
  1470. protected Record createHeader()
  1471. {
  1472. HeaderRecord retval = new HeaderRecord();
  1473. retval.setHeaderLength(( byte ) 0);
  1474. retval.setHeader(null);
  1475. return retval;
  1476. }
  1477. /**
  1478. * creates the Footer Record and sets it to nothing/0 length
  1479. * @see loci.poi.hssf.record.FooterRecord
  1480. * @see loci.poi.hssf.record.Record
  1481. * @return record containing a FooterRecord
  1482. */
  1483. protected Record createFooter()
  1484. {
  1485. FooterRecord retval = new FooterRecord();
  1486. retval.setFooterLength(( byte ) 0);
  1487. retval.setFooter(null);
  1488. return retval;
  1489. }
  1490. /**
  1491. * creates the HCenter Record and sets it to false (don't horizontally center)
  1492. * @see loci.poi.hssf.record.HCenterRecord
  1493. * @see loci.poi.hssf.record.Record
  1494. * @return record containing a HCenterRecord
  1495. */
  1496. protected Record createHCenter()
  1497. {
  1498. HCenterRecord retval = new HCenterRecord();
  1499. retval.setHCenter(false);
  1500. return retval;
  1501. }
  1502. /**
  1503. * creates the VCenter Record and sets it to false (don't horizontally center)
  1504. * @see loci.poi.hssf.record.VCenterRecord
  1505. * @see loci.poi.hssf.record.Record
  1506. * @return record containing a VCenterRecord
  1507. */
  1508. protected Record createVCenter()
  1509. {
  1510. VCenterRecord retval = new VCenterRecord();
  1511. retval.setVCenter(false);
  1512. return retval;
  1513. }
  1514. /**
  1515. * creates the PrintSetup Record and sets it to defaults and marks it invalid
  1516. * @see loci.poi.hssf.record.PrintSetupRecord
  1517. * @see loci.poi.hssf.record.Record
  1518. * @return record containing a PrintSetupRecord
  1519. */
  1520. protected Record createPrintSetup()
  1521. {
  1522. PrintSetupRecord retval = new PrintSetupRecord();
  1523. retval.setPaperSize(( short ) 1);
  1524. retval.setScale(( short ) 100);
  1525. retval.setPageStart(( short ) 1);
  1526. retval.setFitWidth(( short ) 1);
  1527. retval.setFitHeight(( short ) 1);
  1528. retval.setOptions(( short ) 2);
  1529. retval.setHResolution(( short ) 300);
  1530. retval.setVResolution(( short ) 300);
  1531. retval.setHeaderMargin( 0.5);
  1532. retval.setFooterMargin( 0.5);
  1533. retval.setCopies(( short ) 0);
  1534. return retval;
  1535. }
  1536. /**
  1537. * creates the DefaultColWidth Record and sets it to 8
  1538. * @see loci.poi.hssf.record.DefaultColWidthRecord
  1539. * @see loci.poi.hssf.record.Record
  1540. * @return record containing a DefaultColWidthRecord
  1541. */
  1542. protected Record createDefaultColWidth()
  1543. {
  1544. DefaultColWidthRecord retval = new DefaultColWidthRecord();
  1545. retval.setColWidth(( short ) 8);
  1546. return retval;
  1547. }
  1548. /**
  1549. * creates the ColumnInfo Record and sets it to a default column/width
  1550. * @see loci.poi.hssf.record.ColumnInfoRecord
  1551. * @return record containing a ColumnInfoRecord
  1552. */
  1553. protected Record createColInfo()
  1554. {
  1555. return ColumnInfoRecordsAggregate.createColInfo();
  1556. }
  1557. /**
  1558. * get the default column width for the sheet (if the columns do not define their own width)
  1559. * @return default column width
  1560. */
  1561. public short getDefaultColumnWidth()
  1562. {
  1563. return defaultcolwidth.getColWidth();
  1564. }
  1565. /**
  1566. * get whether gridlines are printed.
  1567. * @return true if printed
  1568. */
  1569. public boolean isGridsPrinted()
  1570. {
  1571. if (gridset == null) {
  1572. gridset = (GridsetRecord)createGridset();
  1573. //Insert the newlycreated Gridset record at the end of the record (just before the EOF)
  1574. int loc = findFirstRecordLocBySid(EOFRecord.sid);
  1575. records.add(loc, gridset);
  1576. }
  1577. return !gridset.getGridset();
  1578. }
  1579. /**
  1580. * set whether gridlines printed or not.
  1581. * @param value True if gridlines printed.
  1582. */
  1583. public void setGridsPrinted(boolean value)
  1584. {
  1585. gridset.setGridset(!value);
  1586. }
  1587. /**
  1588. * set the default column width for the sheet (if the columns do not define their own width)
  1589. * @param dcw default column width
  1590. */
  1591. public void setDefaultColumnWidth(short dcw)
  1592. {
  1593. defaultcolwidth.setColWidth(dcw);
  1594. }
  1595. /**
  1596. * set the default row height for the sheet (if the rows do not define their own height)
  1597. */
  1598. public void setDefaultRowHeight(short dch)
  1599. {
  1600. defaultrowheight.setRowHeight(dch);
  1601. }
  1602. /**
  1603. * get the default row height for the sheet (if the rows do not define their own height)
  1604. * @return default row height
  1605. */
  1606. public short getDefaultRowHeight()
  1607. {
  1608. return defaultrowheight.getRowHeight();
  1609. }
  1610. /**
  1611. * get the width of a given column in units of 1/20th of a point width (twips?)
  1612. * @param column index
  1613. * @see loci.poi.hssf.record.DefaultColWidthRecord
  1614. * @see loci.poi.hssf.record.ColumnInfoRecord
  1615. * @see #setColumnWidth(short,short)
  1616. * @return column width in units of 1/20th of a point (twips?)
  1617. */
  1618. public short getColumnWidth(short column)
  1619. {
  1620. short retval = 0;
  1621. ColumnInfoRecord ci = null;
  1622. if (columns != null)
  1623. {
  1624. int count=columns.getNumColumns();
  1625. for ( int k=0;k<count;k++ )
  1626. {
  1627. ci = columns.getColInfo(k);
  1628. if ((ci.getFirstColumn() <= column)
  1629. && (column <= ci.getLastColumn()))
  1630. {
  1631. break;
  1632. }
  1633. ci = null;
  1634. }
  1635. }
  1636. if (ci != null)
  1637. {
  1638. retval = ci.getColumnWidth();
  1639. }
  1640. else
  1641. {
  1642. retval = defaultcolwidth.getColWidth();
  1643. }
  1644. return retval;
  1645. }
  1646. /**
  1647. * get the index to the ExtendedFormatRecord "associated" with
  1648. * the column at specified 0-based index. (In this case, an
  1649. * ExtendedFormatRecord index is actually associated with a
  1650. * ColumnInfoRecord which spans 1 or more columns)
  1651. * <br/>
  1652. * Returns the index to the default ExtendedFormatRecord (0xF)
  1653. * if no ColumnInfoRecord exists that includes the column
  1654. * index specified.
  1655. * @param column
  1656. * @return index of ExtendedFormatRecord associated with
  1657. * ColumnInfoRecord that includes the column index or the
  1658. * index of the default ExtendedFormatRecord (0xF)
  1659. */
  1660. public short getXFIndexForColAt(short column) {
  1661. short retval = 0;
  1662. ColumnInfoRecord ci = null;
  1663. if (columns != null) {
  1664. int count=columns.getNumColumns();
  1665. for ( int k=0;k<count;k++ )
  1666. {
  1667. ci = columns.getColInfo(k);
  1668. if ((ci.getFirstColumn() <= column)
  1669. && (column <= ci.getLastColumn())) {
  1670. break;
  1671. }
  1672. ci = null;
  1673. }
  1674. }
  1675. retval = (ci != null) ? ci.getXFIndex() : 0xF;
  1676. return retval;
  1677. }
  1678. /**
  1679. * set the width for a given column in 1/20th of a character width units
  1680. * @param column - the column number
  1681. * @param width (in units of 1/20th of a character width)
  1682. */
  1683. public void setColumnWidth(short column, short width)
  1684. {
  1685. setColumn( column, new Short(width), null, null, null);
  1686. }
  1687. /**
  1688. * Get the hidden property for a given column.
  1689. * @param column index
  1690. * @see loci.poi.hssf.record.DefaultColWidthRecord
  1691. * @see loci.poi.hssf.record.ColumnInfoRecord
  1692. * @see #setColumnHidden(short,boolean)
  1693. * @return whether the column is hidden or not.
  1694. */
  1695. public boolean isColumnHidden(short column)
  1696. {
  1697. boolean retval = false;
  1698. ColumnInfoRecord ci = null;
  1699. if (columns != null)
  1700. {
  1701. for ( Iterator iterator = columns.getIterator(); iterator.hasNext(); )
  1702. {
  1703. ci = ( ColumnInfoRecord ) iterator.next();
  1704. if ((ci.getFirstColumn() <= column)
  1705. && (column <= ci.getLastColumn()))
  1706. {
  1707. break;
  1708. }
  1709. ci = null;
  1710. }
  1711. }
  1712. if (ci != null)
  1713. {
  1714. retval = ci.getHidden();
  1715. }
  1716. return retval;
  1717. }
  1718. /**
  1719. * Get the hidden property for a given column.
  1720. * @param column - the column number
  1721. * @param hidden - whether the column is hidden or not
  1722. */
  1723. public void setColumnHidden(short column, boolean hidden)
  1724. {
  1725. setColumn( column, null, null, new Boolean(hidden), null);
  1726. }
  1727. public void setColumn(short column, Short width, Integer level, Boolean hidden, Boolean collapsed)
  1728. {
  1729. if (columns == null)
  1730. columns = new ColumnInfoRecordsAggregate();
  1731. columns.setColumn( column, null, width, level, hidden, collapsed );
  1732. }
  1733. public void setColumn(short column, Short xfStyle, Short width, Integer level, Boolean hidden, Boolean collapsed)
  1734. {
  1735. if (columns == null)
  1736. columns = new ColumnInfoRecordsAggregate();
  1737. columns.setColumn( column, xfStyle, width, level, hidden, collapsed );
  1738. }
  1739. /**
  1740. * Creates an outline group for the specified columns.
  1741. * @param fromColumn group from this column (inclusive)
  1742. * @param toColumn group to this column (inclusive)
  1743. * @param indent if true the group will be indented by one level,
  1744. * if false indenting will be removed by one level.
  1745. */
  1746. public void groupColumnRange(short fromColumn, short toColumn, boolean indent)
  1747. {
  1748. // Set the level for each column
  1749. columns.groupColumnRange( fromColumn, toColumn, indent);
  1750. // Determine the maximum overall level
  1751. int maxLevel = 0;
  1752. int count=columns.getNumColumns();
  1753. for ( int k=0;k<count;k++ )
  1754. {
  1755. ColumnInfoRecord columnInfoRecord = columns.getColInfo(k);
  1756. maxLevel = Math.max(columnInfoRecord.getOutlineLevel(), maxLevel);
  1757. }
  1758. GutsRecord guts = (GutsRecord) findFirstRecordBySid( GutsRecord.sid );
  1759. guts.setColLevelMax( (short) ( maxLevel+1 ) );
  1760. if (maxLevel == 0)
  1761. guts.setTopColGutter( (short)0 );
  1762. else
  1763. guts.setTopColGutter( (short) ( 29 + (12 * (maxLevel-1)) ) );
  1764. }
  1765. /**
  1766. * creates the Dimensions Record and sets it to bogus values (you should set this yourself
  1767. * or let the high level API do it for you)
  1768. * @see loci.poi.hssf.record.DimensionsRecord
  1769. * @see loci.poi.hssf.record.Record
  1770. * @return record containing a DimensionsRecord
  1771. */
  1772. protected Record createDimensions()
  1773. {
  1774. DimensionsRecord retval = new DimensionsRecord();
  1775. retval.setFirstCol(( short ) 0);
  1776. retval.setLastRow(1); // one more than it is
  1777. retval.setFirstRow(0);
  1778. retval.setLastCol(( short ) 1); // one more than it is
  1779. return retval;
  1780. }
  1781. /**
  1782. * creates the WindowTwo Record and sets it to: <P>
  1783. * options = 0x6b6 <P>
  1784. * toprow = 0 <P>
  1785. * leftcol = 0 <P>
  1786. * headercolor = 0x40 <P>
  1787. * pagebreakzoom = 0x0 <P>
  1788. * normalzoom = 0x0 <p>
  1789. * @see loci.poi.hssf.record.WindowTwoRecord
  1790. * @see loci.poi.hssf.record.Record
  1791. * @return record containing a WindowTwoRecord
  1792. */
  1793. protected WindowTwoRecord createWindowTwo()
  1794. {
  1795. WindowTwoRecord retval = new WindowTwoRecord();
  1796. retval.setOptions(( short ) 0x6b6);
  1797. retval.setTopRow(( short ) 0);
  1798. retval.setLeftCol(( short ) 0);
  1799. retval.setHeaderColor(0x40);
  1800. retval.setPageBreakZoom(( short ) 0);
  1801. retval.setNormalZoom(( short ) 0);
  1802. return retval;
  1803. }
  1804. /**
  1805. * Creates the Selection record and sets it to nothing selected
  1806. *
  1807. * @see loci.poi.hssf.record.SelectionRecord
  1808. * @see loci.poi.hssf.record.Record
  1809. * @return record containing a SelectionRecord
  1810. */
  1811. protected Record createSelection()
  1812. {
  1813. SelectionRecord retval = new SelectionRecord();
  1814. retval.setPane(( byte ) 0x3);
  1815. retval.setActiveCellCol(( short ) 0x0);
  1816. retval.setActiveCellRow(( short ) 0x0);
  1817. retval.setNumRefs(( short ) 0x0);
  1818. return retval;
  1819. }
  1820. public short getTopRow()
  1821. {
  1822. return (windowTwo==null) ? (short) 0 : windowTwo.getTopRow();
  1823. }
  1824. public void setTopRow(short topRow)
  1825. {
  1826. if (windowTwo!=null)
  1827. {
  1828. windowTwo.setTopRow(topRow);
  1829. }
  1830. }
  1831. /**
  1832. * Sets the left column to show in desktop window pane.
  1833. * @param leftCol the left column to show in desktop window pane
  1834. */
  1835. public void setLeftCol(short leftCol){
  1836. if (windowTwo!=null)
  1837. {
  1838. windowTwo.setLeftCol(leftCol);
  1839. }
  1840. }
  1841. public short getLeftCol()
  1842. {
  1843. return (windowTwo==null) ? (short) 0 : windowTwo.getLeftCol();
  1844. }
  1845. /**
  1846. * Returns the active row
  1847. *
  1848. * @see loci.poi.hssf.record.SelectionRecord
  1849. * @return row the active row index
  1850. */
  1851. public int getActiveCellRow()
  1852. {
  1853. if (selection == null)
  1854. {
  1855. return 0;
  1856. }
  1857. return selection.getActiveCellRow();
  1858. }
  1859. /**
  1860. * Sets the active row
  1861. *
  1862. * @param row the row index
  1863. * @see loci.poi.hssf.record.SelectionRecord
  1864. */
  1865. public void setActiveCellRow(int row)
  1866. {
  1867. //shouldn't have a sheet w/o a SelectionRecord, but best to guard anyway
  1868. if (selection != null)
  1869. {
  1870. selection.setActiveCellRow(row);
  1871. }
  1872. }
  1873. /**
  1874. * Returns the active column
  1875. *
  1876. * @see loci.poi.hssf.record.SelectionRecord
  1877. * @return row the active column index
  1878. */
  1879. public short getActiveCellCol()
  1880. {
  1881. if (selection == null)
  1882. {
  1883. return (short) 0;
  1884. }
  1885. return selection.getActiveCellCol();
  1886. }
  1887. /**
  1888. * Sets the active column
  1889. *
  1890. * @param col the column index
  1891. * @see loci.poi.hssf.record.SelectionRecord
  1892. */
  1893. public void setActiveCellCol(short col)
  1894. {
  1895. //shouldn't have a sheet w/o a SelectionRecord, but best to guard anyway
  1896. if (selection != null)
  1897. {
  1898. selection.setActiveCellCol(col);
  1899. }
  1900. }
  1901. protected Record createMergedCells()
  1902. {
  1903. MergeCellsRecord retval = new MergeCellsRecord();
  1904. retval.setNumAreas(( short ) 0);
  1905. return retval;
  1906. }
  1907. /**
  1908. * creates the EOF record
  1909. * @see loci.poi.hssf.record.EOFRecord
  1910. * @see loci.poi.hssf.record.Record
  1911. * @return record containing a EOFRecord
  1912. */
  1913. protected Record createEOF()
  1914. {
  1915. return new EOFRecord();
  1916. }
  1917. /**
  1918. * get the location of the DimensionsRecord (which is the last record before the value section)
  1919. * @return location in the array of records of the DimensionsRecord
  1920. */
  1921. public int getDimsLoc()
  1922. {
  1923. if (log.check( POILogger.DEBUG ))
  1924. log.log(POILogger.DEBUG, "getDimsLoc dimsloc= " + dimsloc);
  1925. return dimsloc;
  1926. }
  1927. /**
  1928. * in the event the record is a dimensions record, resets both the loc index and dimsloc index
  1929. */
  1930. public void checkDimsLoc(Record rec, int recloc)
  1931. {
  1932. if (rec.getSid() == DimensionsRecord.sid)
  1933. {
  1934. loc = recloc;
  1935. dimsloc = recloc;
  1936. }
  1937. }
  1938. public int getSize()
  1939. {
  1940. int retval = 0;
  1941. for ( int k = 0; k < records.size(); k++ )
  1942. {
  1943. retval += ( (Record) records.get( k ) ).getRecordSize();
  1944. }
  1945. //Add space for the IndexRecord
  1946. if (rows != null) {
  1947. final int blocks = rows.getRowBlockCount();
  1948. retval += IndexRecord.getRecordSizeForBlockCount(blocks);
  1949. //Add space for the DBCell records
  1950. //Once DBCell per block.
  1951. //8 bytes per DBCell (non variable section)
  1952. //2 bytes per row reference
  1953. retval += (8 * blocks);
  1954. for (Iterator itr = rows.getIterator(); itr.hasNext();) {
  1955. RowRecord row = (RowRecord)itr.next();
  1956. if (cells != null && cells.rowHasCells(row.getRowNumber()))
  1957. retval += 2;
  1958. }
  1959. }
  1960. return retval;
  1961. }
  1962. public List getRecords()
  1963. {
  1964. return records;
  1965. }
  1966. /**
  1967. * Gets the gridset record for this sheet.
  1968. */
  1969. public GridsetRecord getGridsetRecord()
  1970. {
  1971. return gridset;
  1972. }
  1973. /**
  1974. * Returns the first occurance of a record matching a particular sid.
  1975. */
  1976. public Record findFirstRecordBySid(short sid)
  1977. {
  1978. for (Iterator iterator = records.iterator(); iterator.hasNext(); )
  1979. {
  1980. Record record = ( Record ) iterator.next();
  1981. if (record.getSid() == sid)
  1982. {
  1983. return record;
  1984. }
  1985. }
  1986. return null;
  1987. }
  1988. /**
  1989. * Sets the SCL record or creates it in the correct place if it does not
  1990. * already exist.
  1991. *
  1992. * @param sclRecord The record to set.
  1993. */
  1994. public void setSCLRecord(SCLRecord sclRecord)
  1995. {
  1996. int oldRecordLoc = findFirstRecordLocBySid(SCLRecord.sid);
  1997. if (oldRecordLoc == -1)
  1998. {
  1999. // Insert it after the window record
  2000. int windowRecordLoc = findFirstRecordLocBySid(WindowTwoRecord.sid);
  2001. records.add(windowRecordLoc+1, sclRecord);
  2002. }
  2003. else
  2004. {
  2005. records.set(oldRecordLoc, sclRecord);
  2006. }
  2007. }
  2008. /**
  2009. * Finds the first occurance of a record matching a particular sid and
  2010. * returns it's position.
  2011. * @param sid the sid to search for
  2012. * @return the record position of the matching record or -1 if no match
  2013. * is made.
  2014. */
  2015. public int findFirstRecordLocBySid( short sid )
  2016. {
  2017. int index = 0;
  2018. for (Iterator iterator = records.iterator(); iterator.hasNext(); )
  2019. {
  2020. Record record = ( Record ) iterator.next();
  2021. if (record.getSid() == sid)
  2022. {
  2023. return index;
  2024. }
  2025. index++;
  2026. }
  2027. return -1;
  2028. }
  2029. /**
  2030. * Returns the HeaderRecord.
  2031. * @return HeaderRecord for the sheet.
  2032. */
  2033. public HeaderRecord getHeader ()
  2034. {
  2035. return header;
  2036. }
  2037. /**
  2038. * Sets the HeaderRecord.
  2039. * @param newHeader The new HeaderRecord for the sheet.
  2040. */
  2041. public void setHeader (HeaderRecord newHeader)
  2042. {
  2043. header = newHeader;
  2044. }
  2045. /**
  2046. * Returns the FooterRecord.
  2047. * @return FooterRecord for the sheet.
  2048. */
  2049. public FooterRecord getFooter ()
  2050. {
  2051. return footer;
  2052. }
  2053. /**
  2054. * Sets the FooterRecord.
  2055. * @param newFooter The new FooterRecord for the sheet.
  2056. */
  2057. public void setFooter (FooterRecord newFooter)
  2058. {
  2059. footer = newFooter;
  2060. }
  2061. /**
  2062. * Returns the PrintSetupRecord.
  2063. * @return PrintSetupRecord for the sheet.
  2064. */
  2065. public PrintSetupRecord getPrintSetup ()
  2066. {
  2067. return printSetup;
  2068. }
  2069. /**
  2070. * Sets the PrintSetupRecord.
  2071. * @param newPrintSetup The new PrintSetupRecord for the sheet.
  2072. */
  2073. public void setPrintSetup (PrintSetupRecord newPrintSetup)
  2074. {
  2075. printSetup = newPrintSetup;
  2076. }
  2077. /**
  2078. * Returns the PrintGridlinesRecord.
  2079. * @return PrintGridlinesRecord for the sheet.
  2080. */
  2081. public PrintGridlinesRecord getPrintGridlines ()
  2082. {
  2083. return printGridlines;
  2084. }
  2085. /**
  2086. * Sets the PrintGridlinesRecord.
  2087. * @param newPrintGridlines The new PrintGridlinesRecord for the sheet.
  2088. */
  2089. public void setPrintGridlines (PrintGridlinesRecord newPrintGridlines)
  2090. {
  2091. printGridlines = newPrintGridlines;
  2092. }
  2093. /**
  2094. * Sets whether the sheet is selected
  2095. * @param sel True to select the sheet, false otherwise.
  2096. */
  2097. public void setSelected(boolean sel) {
  2098. windowTwo.setSelected(sel);
  2099. }
  2100. /**
  2101. * Gets the size of the margin in inches.
  2102. * @param margin which margin to get
  2103. * @return the size of the margin
  2104. */
  2105. public double getMargin(short margin) {
  2106. if (getMargins()[margin] != null)
  2107. return margins[margin].getMargin();
  2108. else {
  2109. switch ( margin )
  2110. {
  2111. case LeftMargin:
  2112. return .75;
  2113. case RightMargin:
  2114. return .75;
  2115. case TopMargin:
  2116. return 1.0;
  2117. case BottomMargin:
  2118. return 1.0;
  2119. default :
  2120. throw new RuntimeException( "Unknown margin constant: " + margin );
  2121. }
  2122. }
  2123. }
  2124. /**
  2125. * Sets the size of the margin in inches.
  2126. * @param margin which margin to get
  2127. * @param size the size of the margin
  2128. */
  2129. public void setMargin(short margin, double size) {
  2130. Margin m = getMargins()[margin];
  2131. if (m == null) {
  2132. switch ( margin )
  2133. {
  2134. case LeftMargin:
  2135. m = new LeftMarginRecord();
  2136. records.add( getDimsLoc() + 1, m );
  2137. break;
  2138. case RightMargin:
  2139. m = new RightMarginRecord();
  2140. records.add( getDimsLoc() + 1, m );
  2141. break;
  2142. case TopMargin:
  2143. m = new TopMarginRecord();
  2144. records.add( getDimsLoc() + 1, m );
  2145. break;
  2146. case BottomMargin:
  2147. m = new BottomMarginRecord();
  2148. records.add( getDimsLoc() + 1, m );
  2149. break;
  2150. default :
  2151. throw new RuntimeException( "Unknown margin constant: " + margin );
  2152. }
  2153. margins[margin] = m;
  2154. }
  2155. m.setMargin( size );
  2156. }
  2157. public int getEofLoc()
  2158. {
  2159. return eofLoc;
  2160. }
  2161. /**
  2162. * Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
  2163. * @param colSplit Horizonatal position of split.
  2164. * @param rowSplit Vertical position of split.
  2165. * @param topRow Top row visible in bottom pane
  2166. * @param leftmostColumn Left column visible in right pane.
  2167. */
  2168. public void createFreezePane(int colSplit, int rowSplit, int topRow, int leftmostColumn )
  2169. {
  2170. int paneLoc = findFirstRecordLocBySid(PaneRecord.sid);
  2171. if (paneLoc != -1)
  2172. records.remove(paneLoc);
  2173. int loc = findFirstRecordLocBySid(WindowTwoRecord.sid);
  2174. PaneRecord pane = new PaneRecord();
  2175. pane.setX((short)colSplit);
  2176. pane.setY((short)rowSplit);
  2177. pane.setTopRow((short) topRow);
  2178. pane.setLeftColumn((short) leftmostColumn);
  2179. if (rowSplit == 0)
  2180. {
  2181. pane.setTopRow((short)0);
  2182. pane.setActivePane((short)1);
  2183. }
  2184. else if (colSplit == 0)
  2185. {
  2186. pane.setLeftColumn((short)64);
  2187. pane.setActivePane((short)2);
  2188. }
  2189. else
  2190. {
  2191. pane.setActivePane((short)0);
  2192. }
  2193. records.add(loc+1, pane);
  2194. windowTwo.setFreezePanes(true);
  2195. windowTwo.setFreezePanesNoSplit(true);
  2196. SelectionRecord sel = (SelectionRecord) findFirstRecordBySid(SelectionRecord.sid);
  2197. sel.setPane((byte)pane.getActivePane());
  2198. }
  2199. /**
  2200. * Creates a split pane. Any existing freezepane or split pane is overwritten.
  2201. * @param xSplitPos Horizonatal position of split (in 1/20th of a point).
  2202. * @param ySplitPos Vertical position of split (in 1/20th of a point).
  2203. * @param topRow Top row visible in bottom pane
  2204. * @param leftmostColumn Left column visible in right pane.
  2205. * @param activePane Active pane. One of: PANE_LOWER_RIGHT,
  2206. * PANE_UPPER_RIGHT, PANE_LOWER_LEFT, PANE_UPPER_LEFT
  2207. * @see #PANE_LOWER_LEFT
  2208. * @see #PANE_LOWER_RIGHT
  2209. * @see #PANE_UPPER_LEFT
  2210. * @see #PANE_UPPER_RIGHT
  2211. */
  2212. public void createSplitPane(int xSplitPos, int ySplitPos, int topRow, int leftmostColumn, int activePane )
  2213. {
  2214. int paneLoc = findFirstRecordLocBySid(PaneRecord.sid);
  2215. if (paneLoc != -1)
  2216. records.remove(paneLoc);
  2217. int loc = findFirstRecordLocBySid(WindowTwoRecord.sid);
  2218. PaneRecord r = new PaneRecord();
  2219. r.setX((short)xSplitPos);
  2220. r.setY((short)ySplitPos);
  2221. r.setTopRow((short) topRow);
  2222. r.setLeftColumn((short) leftmostColumn);
  2223. r.setActivePane((short) activePane);
  2224. records.add(loc+1, r);
  2225. windowTwo.setFreezePanes(false);
  2226. windowTwo.setFreezePanesNoSplit(false);
  2227. SelectionRecord sel = (SelectionRecord) findFirstRecordBySid(SelectionRecord.sid);
  2228. sel.setPane(PANE_LOWER_RIGHT);
  2229. }
  2230. /**
  2231. * Returns the information regarding the currently configured pane (split or freeze).
  2232. * @return null if no pane configured, or the pane information.
  2233. */
  2234. public PaneInformation getPaneInformation() {
  2235. PaneRecord rec = (PaneRecord)findFirstRecordBySid(PaneRecord.sid);
  2236. if (rec == null)
  2237. return null;
  2238. return new PaneInformation(rec.getX(), rec.getY(), rec.getTopRow(),
  2239. rec.getLeftColumn(), (byte)rec.getActivePane(), windowTwo.getFreezePanes());
  2240. }
  2241. public SelectionRecord getSelection()
  2242. {
  2243. return selection;
  2244. }
  2245. public void setSelection( SelectionRecord selection )
  2246. {
  2247. this.selection = selection;
  2248. }
  2249. /**
  2250. * creates a Protect record with protect set to false.
  2251. * @see loci.poi.hssf.record.ProtectRecord
  2252. * @see loci.poi.hssf.record.Record
  2253. * @return a ProtectRecord
  2254. */
  2255. protected Record createProtect()
  2256. {
  2257. if (log.check( POILogger.DEBUG ))
  2258. log.log(POILogger.DEBUG, "create protect record with protection disabled");
  2259. ProtectRecord retval = new ProtectRecord();
  2260. retval.setProtect(false);
  2261. return retval;
  2262. }
  2263. /**
  2264. * creates an ObjectProtect record with protect set to false.
  2265. * @see loci.poi.hssf.record.ObjectProtectRecord
  2266. * @see loci.poi.hssf.record.Record
  2267. * @return an ObjectProtectRecord
  2268. */
  2269. protected ObjectProtectRecord createObjectProtect()
  2270. {
  2271. if (log.check( POILogger.DEBUG ))
  2272. log.log(POILogger.DEBUG, "create protect record with protection disabled");
  2273. ObjectProtectRecord retval = new ObjectProtectRecord();
  2274. retval.setProtect(false);
  2275. return retval;
  2276. }
  2277. /**
  2278. * creates a ScenarioProtect record with protect set to false.
  2279. * @see loci.poi.hssf.record.ScenarioProtectRecord
  2280. * @see loci.poi.hssf.record.Record
  2281. * @return a ScenarioProtectRecord
  2282. */
  2283. protected ScenarioProtectRecord createScenarioProtect()
  2284. {
  2285. if (log.check( POILogger.DEBUG ))
  2286. log.log(POILogger.DEBUG, "create protect record with protection disabled");
  2287. ScenarioProtectRecord retval = new ScenarioProtectRecord();
  2288. retval.setProtect(false);
  2289. return retval;
  2290. }
  2291. /** Returns the ProtectRecord.
  2292. * If one is not contained in the sheet, then one is created.
  2293. */
  2294. public ProtectRecord getProtect()
  2295. {
  2296. if (protect == null) {
  2297. protect = (ProtectRecord)createProtect();
  2298. //Insert the newlycreated protect record at the end of the record (just before the EOF)
  2299. int loc = findFirstRecordLocBySid(EOFRecord.sid);
  2300. records.add(loc, protect);
  2301. }
  2302. return protect;
  2303. }
  2304. /** Returns the PasswordRecord.
  2305. * If one is not contained in the sheet, then one is created.
  2306. */
  2307. public PasswordRecord getPassword()
  2308. {
  2309. if (password == null) {
  2310. password = createPassword();
  2311. //Insert the newly created password record at the end of the record (just before the EOF)
  2312. int loc = findFirstRecordLocBySid(EOFRecord.sid);
  2313. records.add(loc, password);
  2314. }
  2315. return password;
  2316. }
  2317. /**
  2318. * creates a Password record with password set to 00.
  2319. * @see loci.poi.hssf.record.PasswordRecord
  2320. * @see loci.poi.hssf.record.Record
  2321. * @return a PasswordRecord
  2322. */
  2323. protected PasswordRecord createPassword()
  2324. {
  2325. if (log.check( POILogger.DEBUG ))
  2326. log.log(POILogger.DEBUG, "create password record with 00 password");
  2327. PasswordRecord retval = new PasswordRecord();
  2328. retval.setPassword((short)00);
  2329. return retval;
  2330. }
  2331. /**
  2332. /**
  2333. * Sets whether the gridlines are shown in a viewer.
  2334. * @param show whether to show gridlines or not
  2335. */
  2336. public void setDisplayGridlines(boolean show) {
  2337. windowTwo.setDisplayGridlines(show);
  2338. }
  2339. /**
  2340. * Returns if gridlines are displayed.
  2341. * @return whether gridlines are displayed
  2342. */
  2343. public boolean isDisplayGridlines() {
  2344. return windowTwo.getDisplayGridlines();
  2345. }
  2346. /**
  2347. * Sets whether the formulas are shown in a viewer.
  2348. * @param show whether to show formulas or not
  2349. */
  2350. public void setDisplayFormulas(boolean show) {
  2351. windowTwo.setDisplayFormulas(show);
  2352. }
  2353. /**
  2354. * Returns if formulas are displayed.
  2355. * @return whether formulas are displayed
  2356. */
  2357. public boolean isDisplayFormulas() {
  2358. return windowTwo.getDisplayFormulas();
  2359. }
  2360. /**
  2361. * Sets whether the RowColHeadings are shown in a viewer.
  2362. * @param show whether to show RowColHeadings or not
  2363. */
  2364. public void setDisplayRowColHeadings(boolean show) {
  2365. windowTwo.setDisplayRowColHeadings(show);
  2366. }
  2367. /**
  2368. * Returns if RowColHeadings are displayed.
  2369. * @return whether RowColHeadings are displayed
  2370. */
  2371. public boolean isDisplayRowColHeadings() {
  2372. return windowTwo.getDisplayRowColHeadings();
  2373. }
  2374. /**
  2375. * Returns the array of margins. If not created, will create.
  2376. *
  2377. * @return the array of marings.
  2378. */
  2379. protected Margin[] getMargins() {
  2380. if (margins == null)
  2381. margins = new Margin[4];
  2382. return margins;
  2383. }
  2384. public int aggregateDrawingRecords(DrawingManager2 drawingManager)
  2385. {
  2386. int loc = findFirstRecordLocBySid(DrawingRecord.sid);
  2387. boolean noDrawingRecordsFound = loc == -1;
  2388. if (noDrawingRecordsFound)
  2389. {
  2390. EscherAggregate aggregate = new EscherAggregate( drawingManager );
  2391. loc = findFirstRecordLocBySid(EscherAggregate.sid);
  2392. if (loc == -1)
  2393. {
  2394. loc = findFirstRecordLocBySid( WindowTwoRecord.sid );
  2395. }
  2396. else
  2397. {
  2398. getRecords().remove(loc);
  2399. }
  2400. getRecords().add( loc, aggregate );
  2401. return loc;
  2402. }
  2403. else
  2404. {
  2405. List records = getRecords();
  2406. EscherAggregate r = EscherAggregate.createAggregate( records, loc, drawingManager );
  2407. int startloc = loc;
  2408. while ( loc + 1 < records.size()
  2409. && records.get( loc ) instanceof DrawingRecord
  2410. && records.get( loc + 1 ) instanceof ObjRecord )
  2411. {
  2412. loc += 2;
  2413. }
  2414. int endloc = loc-1;
  2415. for(int i = 0; i < (endloc - startloc + 1); i++)
  2416. records.remove(startloc);
  2417. records.add(startloc, r);
  2418. return startloc;
  2419. }
  2420. }
  2421. /**
  2422. * Perform any work necessary before the sheet is about to be serialized.
  2423. * For instance the escher aggregates size needs to be calculated before
  2424. * serialization so that the dgg record (which occurs first) can be written.
  2425. */
  2426. public void preSerialize()
  2427. {
  2428. for ( Iterator iterator = getRecords().iterator(); iterator.hasNext(); )
  2429. {
  2430. Record r = (Record) iterator.next();
  2431. if (r instanceof EscherAggregate)
  2432. r.getRecordSize(); // Trigger flatterning of user model and corresponding update of dgg record.
  2433. }
  2434. }
  2435. /**
  2436. * Shifts all the page breaks in the range "count" number of rows/columns
  2437. * @param breaks The page record to be shifted
  2438. * @param start Starting "main" value to shift breaks
  2439. * @param stop Ending "main" value to shift breaks
  2440. * @param count number of units (rows/columns) to shift by
  2441. */
  2442. public void shiftBreaks(PageBreakRecord breaks, short start, short stop, int count) {
  2443. if(rowBreaks == null)
  2444. return;
  2445. Iterator iterator = breaks.getBreaksIterator();
  2446. List shiftedBreak = new ArrayList();
  2447. while(iterator.hasNext())
  2448. {
  2449. PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
  2450. short breakLocation = breakItem.main;
  2451. boolean inStart = (breakLocation >= start);
  2452. boolean inEnd = (breakLocation <= stop);
  2453. if(inStart && inEnd)
  2454. shiftedBreak.add(breakItem);
  2455. }
  2456. iterator = shiftedBreak.iterator();
  2457. while (iterator.hasNext()) {
  2458. PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
  2459. breaks.removeBreak(breakItem.main);
  2460. breaks.addBreak((short)(breakItem.main+count), breakItem.subFrom, breakItem.subTo);
  2461. }
  2462. }
  2463. /**
  2464. * Sets a page break at the indicated row
  2465. * @param row
  2466. */
  2467. public void setRowBreak(int row, short fromCol, short toCol) {
  2468. if (rowBreaks == null) {
  2469. int loc = findFirstRecordLocBySid(WindowTwoRecord.sid);
  2470. rowBreaks = new PageBreakRecord(PageBreakRecord.HORIZONTAL_SID);
  2471. records.add(loc, rowBreaks);
  2472. }
  2473. rowBreaks.addBreak((short)row, fromCol, toCol);
  2474. }
  2475. /**
  2476. * Removes a page break at the indicated row
  2477. * @param row
  2478. */
  2479. public void removeRowBreak(int row) {
  2480. if (rowBreaks == null)
  2481. throw new IllegalArgumentException("Sheet does not define any row breaks");
  2482. rowBreaks.removeBreak((short)row);
  2483. }
  2484. /**
  2485. * Queries if the specified row has a page break
  2486. * @param row
  2487. * @return true if the specified row has a page break
  2488. */
  2489. public boolean isRowBroken(int row) {
  2490. return (rowBreaks == null) ? false : rowBreaks.getBreak((short)row) != null;
  2491. }
  2492. /**
  2493. * Sets a page break at the indicated column
  2494. *
  2495. */
  2496. public void setColumnBreak(short column, short fromRow, short toRow) {
  2497. if (colBreaks == null) {
  2498. int loc = findFirstRecordLocBySid(WindowTwoRecord.sid);
  2499. colBreaks = new PageBreakRecord(PageBreakRecord.VERTICAL_SID);
  2500. records.add(loc, colBreaks);
  2501. }
  2502. colBreaks.addBreak(column, fromRow, toRow);
  2503. }
  2504. /**
  2505. * Removes a page break at the indicated column
  2506. *
  2507. */
  2508. public void removeColumnBreak(short column) {
  2509. if (colBreaks == null)
  2510. throw new IllegalArgumentException("Sheet does not define any column breaks");
  2511. colBreaks.removeBreak(column);
  2512. }
  2513. /**
  2514. * Queries if the specified column has a page break
  2515. *
  2516. * @return true if the specified column has a page break
  2517. */
  2518. public boolean isColumnBroken(short column) {
  2519. return (colBreaks == null) ? false : colBreaks.getBreak(column) != null;
  2520. }
  2521. /**
  2522. * Shifts the horizontal page breaks for the indicated count
  2523. * @param startingRow
  2524. * @param endingRow
  2525. * @param count
  2526. */
  2527. public void shiftRowBreaks(int startingRow, int endingRow, int count) {
  2528. shiftBreaks(rowBreaks, (short)startingRow, (short)endingRow, (short)count);
  2529. }
  2530. /**
  2531. * Shifts the vertical page breaks for the indicated count
  2532. * @param startingCol
  2533. * @param endingCol
  2534. * @param count
  2535. */
  2536. public void shiftColumnBreaks(short startingCol, short endingCol, short count) {
  2537. shiftBreaks(colBreaks, startingCol, endingCol, count);
  2538. }
  2539. /**
  2540. * Returns all the row page breaks
  2541. * @return all the row page breaks
  2542. */
  2543. public Iterator getRowBreaks() {
  2544. return rowBreaks.getBreaksIterator();
  2545. }
  2546. /**
  2547. * Returns the number of row page breaks
  2548. * @return the number of row page breaks
  2549. */
  2550. public int getNumRowBreaks(){
  2551. return (rowBreaks == null) ? 0 : (int)rowBreaks.getNumBreaks();
  2552. }
  2553. /**
  2554. * Returns all the column page breaks
  2555. * @return all the column page breaks
  2556. */
  2557. public Iterator getColumnBreaks(){
  2558. return colBreaks.getBreaksIterator();
  2559. }
  2560. /**
  2561. * Returns the number of column page breaks
  2562. * @return the number of column page breaks
  2563. */
  2564. public int getNumColumnBreaks(){
  2565. return (colBreaks == null) ? 0 : (int)colBreaks.getNumBreaks();
  2566. }
  2567. public void setColumnGroupCollapsed( short columnNumber, boolean collapsed )
  2568. {
  2569. if (collapsed)
  2570. {
  2571. columns.collapseColumn( columnNumber );
  2572. }
  2573. else
  2574. {
  2575. columns.expandColumn( columnNumber );
  2576. }
  2577. }
  2578. /**
  2579. * protect a spreadsheet with a password (not encypted, just sets protect
  2580. * flags and the password.
  2581. * @param password to set
  2582. * @param objects are protected
  2583. * @param scenarios are protected
  2584. */
  2585. public void protectSheet( String password, boolean objects, boolean scenarios ) {
  2586. int protIdx = -1;
  2587. ProtectRecord prec = getProtect();
  2588. PasswordRecord pass = getPassword();
  2589. prec.setProtect(true);
  2590. pass.setPassword(PasswordRecord.hashPassword(password));
  2591. if((objprotect == null && objects) || (scenprotect != null && scenarios)) {
  2592. protIdx = records.indexOf( protect );
  2593. }
  2594. if(objprotect == null && objects) {
  2595. ObjectProtectRecord rec = createObjectProtect();
  2596. rec.setProtect(true);
  2597. records.add(protIdx+1,rec);
  2598. objprotect = rec;
  2599. }
  2600. if(scenprotect == null && scenarios) {
  2601. ScenarioProtectRecord srec = createScenarioProtect();
  2602. srec.setProtect(true);
  2603. records.add(protIdx+2,srec);
  2604. scenprotect = srec;
  2605. }
  2606. }
  2607. /**
  2608. * unprotect objects in the sheet (will not protect them, but any set to false are
  2609. * unprotected.
  2610. * @param sheet is unprotected (false = unprotect)
  2611. * @param objects are unprotected (false = unprotect)
  2612. * @param scenarios are unprotected (false = unprotect)
  2613. */
  2614. public void unprotectSheet( boolean sheet, boolean objects, boolean scenarios ) {
  2615. int protIdx = -1;
  2616. if (!sheet) {
  2617. ProtectRecord prec = getProtect();
  2618. prec.setProtect(sheet);
  2619. PasswordRecord pass = getPassword();
  2620. pass.setPassword((short)00);
  2621. }
  2622. if(objprotect != null && !objects) {
  2623. objprotect.setProtect(false);
  2624. }
  2625. if(scenprotect != null && !scenarios) {
  2626. scenprotect.setProtect(false);
  2627. }
  2628. }
  2629. /**
  2630. * @return {sheet is protected, objects are proteced, scenarios are protected}
  2631. */
  2632. public boolean[] isProtected() {
  2633. return new boolean[] { (protect != null && protect.getProtect()),
  2634. (objprotect != null && objprotect.getProtect()),
  2635. (scenprotect != null && scenprotect.getProtect())};
  2636. }
  2637. // private void collapseColumn( short columnNumber )
  2638. // {
  2639. // int idx = findColumnIdx( columnNumber, 0 );
  2640. // if (idx == -1)
  2641. // return;
  2642. //
  2643. // // Find the start of the group.
  2644. // ColumnInfoRecord columnInfo = (ColumnInfoRecord) columnSizes.get( findStartOfColumnOutlineGroup( idx ) );
  2645. //
  2646. // // Hide all the columns until the end of the group
  2647. // columnInfo = writeHidden( columnInfo, idx, true );
  2648. //
  2649. // // Write collapse field
  2650. // setColumn( (short) ( columnInfo.getLastColumn() + 1 ), null, null, null, Boolean.TRUE);
  2651. // }
  2652. // private void expandColumn( short columnNumber )
  2653. // {
  2654. // int idx = findColumnIdx( columnNumber, 0 );
  2655. // if (idx == -1)
  2656. // return;
  2657. //
  2658. // // If it is already exapanded do nothing.
  2659. // if (!isColumnGroupCollapsed(idx))
  2660. // return;
  2661. //
  2662. // // Find the start of the group.
  2663. // int startIdx = findStartOfColumnOutlineGroup( idx );
  2664. // ColumnInfoRecord columnInfo = getColInfo( startIdx );
  2665. //
  2666. // // Find the end of the group.
  2667. // int endIdx = findEndOfColumnOutlineGroup( idx );
  2668. // ColumnInfoRecord endColumnInfo = getColInfo( endIdx );
  2669. //
  2670. // // expand:
  2671. // // colapsed bit must be unset
  2672. // // hidden bit gets unset _if_ surrounding groups are expanded you can determine
  2673. // // this by looking at the hidden bit of the enclosing group. You will have
  2674. // // to look at the start and the end of the current group to determine which
  2675. // // is the enclosing group
  2676. // // hidden bit only is altered for this outline level. ie. don't uncollapse contained groups
  2677. // if (!isColumnGroupHiddenByParent( idx ))
  2678. // {
  2679. // for (int i = startIdx; i <= endIdx; i++)
  2680. // {
  2681. // if (columnInfo.getOutlineLevel() == getColInfo(i).getOutlineLevel())
  2682. // getColInfo(i).setHidden( false );
  2683. // }
  2684. // }
  2685. //
  2686. // // Write collapse field
  2687. // setColumn( (short) ( columnInfo.getLastColumn() + 1 ), null, null, null, Boolean.FALSE);
  2688. // }
  2689. // private boolean isColumnGroupCollapsed( int idx )
  2690. // {
  2691. // int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx );
  2692. // if (endOfOutlineGroupIdx >= columnSizes.size())
  2693. // return false;
  2694. // if (getColInfo(endOfOutlineGroupIdx).getLastColumn() + 1 != getColInfo(endOfOutlineGroupIdx + 1).getFirstColumn())
  2695. // return false;
  2696. // else
  2697. // return getColInfo(endOfOutlineGroupIdx+1).getCollapsed();
  2698. // }
  2699. // private boolean isColumnGroupHiddenByParent( int idx )
  2700. // {
  2701. // // Look out outline details of end
  2702. // int endLevel;
  2703. // boolean endHidden;
  2704. // int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx );
  2705. // if (endOfOutlineGroupIdx >= columnSizes.size())
  2706. // {
  2707. // endLevel = 0;
  2708. // endHidden = false;
  2709. // }
  2710. // else if (getColInfo(endOfOutlineGroupIdx).getLastColumn() + 1 != getColInfo(endOfOutlineGroupIdx + 1).getFirstColumn())
  2711. // {
  2712. // endLevel = 0;
  2713. // endHidden = false;
  2714. // }
  2715. // else
  2716. // {
  2717. // endLevel = getColInfo( endOfOutlineGroupIdx + 1).getOutlineLevel();
  2718. // endHidden = getColInfo( endOfOutlineGroupIdx + 1).getHidden();
  2719. // }
  2720. //
  2721. // // Look out outline details of start
  2722. // int startLevel;
  2723. // boolean startHidden;
  2724. // int startOfOutlineGroupIdx = findStartOfColumnOutlineGroup( idx );
  2725. // if (startOfOutlineGroupIdx <= 0)
  2726. // {
  2727. // startLevel = 0;
  2728. // startHidden = false;
  2729. // }
  2730. // else if (getColInfo(startOfOutlineGroupIdx).getFirstColumn() - 1 != getColInfo(startOfOutlineGroupIdx - 1).getLastColumn())
  2731. // {
  2732. // startLevel = 0;
  2733. // startHidden = false;
  2734. // }
  2735. // else
  2736. // {
  2737. // startLevel = getColInfo( startOfOutlineGroupIdx - 1).getOutlineLevel();
  2738. // startHidden = getColInfo( startOfOutlineGroupIdx - 1 ).getHidden();
  2739. // }
  2740. //
  2741. // if (endLevel > startLevel)
  2742. // {
  2743. // return endHidden;
  2744. // }
  2745. // else
  2746. // {
  2747. // return startHidden;
  2748. // }
  2749. // }
  2750. // private ColumnInfoRecord getColInfo(int idx)
  2751. // {
  2752. // return columns.getColInfo( idx );
  2753. // }
  2754. // private int findStartOfColumnOutlineGroup(int idx)
  2755. // {
  2756. // // Find the start of the group.
  2757. // ColumnInfoRecord columnInfo = (ColumnInfoRecord) columnSizes.get( idx );
  2758. // int level = columnInfo.getOutlineLevel();
  2759. // while (idx != 0)
  2760. // {
  2761. // ColumnInfoRecord prevColumnInfo = (ColumnInfoRecord) columnSizes.get( idx - 1 );
  2762. // if (columnInfo.getFirstColumn() - 1 == prevColumnInfo.getLastColumn())
  2763. // {
  2764. // if (prevColumnInfo.getOutlineLevel() < level)
  2765. // {
  2766. // break;
  2767. // }
  2768. // idx--;
  2769. // columnInfo = prevColumnInfo;
  2770. // }
  2771. // else
  2772. // {
  2773. // break;
  2774. // }
  2775. // }
  2776. //
  2777. // return idx;
  2778. // }
  2779. // private int findEndOfColumnOutlineGroup(int idx)
  2780. // {
  2781. // // Find the end of the group.
  2782. // ColumnInfoRecord columnInfo = (ColumnInfoRecord) columnSizes.get( idx );
  2783. // int level = columnInfo.getOutlineLevel();
  2784. // while (idx < columnSizes.size() - 1)
  2785. // {
  2786. // ColumnInfoRecord nextColumnInfo = (ColumnInfoRecord) columnSizes.get( idx + 1 );
  2787. // if (columnInfo.getLastColumn() + 1 == nextColumnInfo.getFirstColumn())
  2788. // {
  2789. // if (nextColumnInfo.getOutlineLevel() < level)
  2790. // {
  2791. // break;
  2792. // }
  2793. // idx++;
  2794. // columnInfo = nextColumnInfo;
  2795. // }
  2796. // else
  2797. // {
  2798. // break;
  2799. // }
  2800. // }
  2801. //
  2802. // return idx;
  2803. // }
  2804. public void groupRowRange(int fromRow, int toRow, boolean indent)
  2805. {
  2806. checkRows();
  2807. for (int rowNum = fromRow; rowNum <= toRow; rowNum++)
  2808. {
  2809. RowRecord row = getRow( rowNum );
  2810. if (row == null)
  2811. {
  2812. row = createRow( rowNum );
  2813. addRow( row );
  2814. }
  2815. int level = row.getOutlineLevel();
  2816. if (indent) level++; else level--;
  2817. level = Math.max(0, level);
  2818. level = Math.min(7, level);
  2819. row.setOutlineLevel((short) ( level ));
  2820. }
  2821. recalcRowGutter();
  2822. }
  2823. private void recalcRowGutter()
  2824. {
  2825. int maxLevel = 0;
  2826. Iterator iterator = rows.getIterator();
  2827. while ( iterator.hasNext() )
  2828. {
  2829. RowRecord rowRecord = (RowRecord) iterator.next();
  2830. maxLevel = Math.max(rowRecord.getOutlineLevel(), maxLevel);
  2831. }
  2832. GutsRecord guts = (GutsRecord) findFirstRecordBySid( GutsRecord.sid );
  2833. guts.setRowLevelMax( (short) ( maxLevel + 1 ) );
  2834. guts.setLeftRowGutter( (short) ( 29 + (12 * (maxLevel)) ) );
  2835. }
  2836. public void setRowGroupCollapsed( int row, boolean collapse )
  2837. {
  2838. if (collapse)
  2839. {
  2840. rows.collapseRow( row );
  2841. }
  2842. else
  2843. {
  2844. rows.expandRow( row );
  2845. }
  2846. }
  2847. // private void collapseRow( int rowNumber )
  2848. // {
  2849. //
  2850. // // Find the start of the group.
  2851. // int startRow = rows.findStartOfRowOutlineGroup( rowNumber );
  2852. // RowRecord rowRecord = (RowRecord) rows.getRow( startRow );
  2853. //
  2854. // // Hide all the columns until the end of the group
  2855. // int lastRow = rows.writeHidden( rowRecord, startRow, true );
  2856. //
  2857. // // Write collapse field
  2858. // if (getRow(lastRow + 1) != null)
  2859. // {
  2860. // getRow(lastRow + 1).setColapsed( true );
  2861. // }
  2862. // else
  2863. // {
  2864. // RowRecord row = createRow( lastRow + 1);
  2865. // row.setColapsed( true );
  2866. // rows.insertRow( row );
  2867. // }
  2868. // }
  2869. // private int findStartOfRowOutlineGroup(int row)
  2870. // {
  2871. // // Find the start of the group.
  2872. // RowRecord rowRecord = rows.getRow( row );
  2873. // int level = rowRecord.getOutlineLevel();
  2874. // int currentRow = row;
  2875. // while (rows.getRow( currentRow ) != null)
  2876. // {
  2877. // rowRecord = rows.getRow( currentRow );
  2878. // if (rowRecord.getOutlineLevel() < level)
  2879. // return currentRow + 1;
  2880. // currentRow--;
  2881. // }
  2882. //
  2883. // return currentRow + 1;
  2884. // }
  2885. // private int writeHidden( RowRecord rowRecord, int row, boolean hidden )
  2886. // {
  2887. // int level = rowRecord.getOutlineLevel();
  2888. // while (rowRecord != null && rows.getRow(row).getOutlineLevel() >= level)
  2889. // {
  2890. // rowRecord.setZeroHeight( hidden );
  2891. // row++;
  2892. // rowRecord = rows.getRow( row );
  2893. // }
  2894. // return row - 1;
  2895. // }
  2896. // private int findEndOfRowOutlineGroup( int row )
  2897. // {
  2898. // int level = getRow( row ).getOutlineLevel();
  2899. // int currentRow;
  2900. // for (currentRow = row; currentRow < rows.getLastRowNum(); currentRow++)
  2901. // {
  2902. // if (getRow(currentRow) == null || getRow(currentRow).getOutlineLevel() < level)
  2903. // {
  2904. // break;
  2905. // }
  2906. // }
  2907. //
  2908. // return currentRow-1;
  2909. // }
  2910. // private boolean isRowGroupCollapsed( int row )
  2911. // {
  2912. // int collapseRow = rows.findEndOfRowOutlineGroup( row ) + 1;
  2913. //
  2914. // if (getRow(collapseRow) == null)
  2915. // return false;
  2916. // else
  2917. // return getRow( collapseRow ).getColapsed();
  2918. // }
  2919. // private boolean isRowGroupHiddenByParent( int row )
  2920. // {
  2921. // // Look out outline details of end
  2922. // int endLevel;
  2923. // boolean endHidden;
  2924. // int endOfOutlineGroupIdx = rows.findEndOfRowOutlineGroup( row );
  2925. // if (getRow( endOfOutlineGroupIdx + 1 ) == null)
  2926. // {
  2927. // endLevel = 0;
  2928. // endHidden = false;
  2929. // }
  2930. // else
  2931. // {
  2932. // endLevel = getRow( endOfOutlineGroupIdx + 1).getOutlineLevel();
  2933. // endHidden = getRow( endOfOutlineGroupIdx + 1).getZeroHeight();
  2934. // }
  2935. //
  2936. // // Look out outline details of start
  2937. // int startLevel;
  2938. // boolean startHidden;
  2939. // int startOfOutlineGroupIdx = rows.findStartOfRowOutlineGroup( row );
  2940. // if (startOfOutlineGroupIdx - 1 < 0 || getRow(startOfOutlineGroupIdx - 1) == null)
  2941. // {
  2942. // startLevel = 0;
  2943. // startHidden = false;
  2944. // }
  2945. // else
  2946. // {
  2947. // startLevel = getRow( startOfOutlineGroupIdx - 1).getOutlineLevel();
  2948. // startHidden = getRow( startOfOutlineGroupIdx - 1 ).getZeroHeight();
  2949. // }
  2950. //
  2951. // if (endLevel > startLevel)
  2952. // {
  2953. // return endHidden;
  2954. // }
  2955. // else
  2956. // {
  2957. // return startHidden;
  2958. // }
  2959. // }
  2960. }