From ea84181642a33957be2a2d3e2923bc1a3bddfe8f Mon Sep 17 00:00:00 2001 From: Josh Micich Date: Thu, 7 Aug 2008 23:49:10 +0000 Subject: [PATCH] Consolidating ValueRecordsAggregate within RowRecordsAggregate git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@683758 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/poi/hssf/model/Sheet.java | 463 +++++------------ .../org/apache/poi/hssf/record/RowRecord.java | 32 +- .../aggregates/RowRecordsAggregate.java | 220 +++++--- .../aggregates/ValueRecordsAggregate.java | 156 +++--- .../apache/poi/hssf/usermodel/HSSFCell.java | 77 +-- .../apache/poi/hssf/usermodel/HSSFRow.java | 84 +-- .../apache/poi/hssf/usermodel/HSSFSheet.java | 117 ++--- .../org/apache/poi/hssf/model/TestSheet.java | 14 +- .../aggregates/TestValueRecordsAggregate.java | 24 +- .../apache/poi/hssf/usermodel/TestBugs.java | 482 +++++++++--------- .../poi/hssf/usermodel/TestFormulas.java | 34 +- .../poi/hssf/usermodel/TestWorkbook.java | 52 +- 12 files changed, 754 insertions(+), 1001 deletions(-) diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java index fe14e550f..aad645049 100644 --- a/src/java/org/apache/poi/hssf/model/Sheet.java +++ b/src/java/org/apache/poi/hssf/model/Sheet.java @@ -66,7 +66,6 @@ import org.apache.poi.hssf.record.SCLRecord; import org.apache.poi.hssf.record.SaveRecalcRecord; import org.apache.poi.hssf.record.ScenarioProtectRecord; import org.apache.poi.hssf.record.SelectionRecord; -import org.apache.poi.hssf.record.SharedFormulaRecord; import org.apache.poi.hssf.record.StringRecord; import org.apache.poi.hssf.record.TopMarginRecord; import org.apache.poi.hssf.record.UncalcedRecord; @@ -82,7 +81,6 @@ import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; import org.apache.poi.hssf.record.aggregates.MergedCellsTable; import org.apache.poi.hssf.record.aggregates.RecordAggregate; import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate; -import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate; import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor; import org.apache.poi.hssf.util.CellRangeAddress; import org.apache.poi.hssf.util.PaneInformation; @@ -121,13 +119,12 @@ public final class Sheet implements Model { protected ArrayList records = null; int preoffset = 0; // offset of the sheet in a new file - int loc = 0; protected int dimsloc = -1; // TODO - is it legal for dims record to be missing? protected DimensionsRecord dims; protected DefaultColWidthRecord defaultcolwidth = null; protected DefaultRowHeightRecord defaultrowheight = null; protected GridsetRecord gridset = null; - private GutsRecord _gutsRecord; + private GutsRecord _gutsRecord; protected PrintSetupRecord printSetup = null; protected HeaderRecord header = null; protected FooterRecord footer = null; @@ -138,9 +135,7 @@ public final class Sheet implements Model { protected SelectionRecord selection = null; /** always present in this POI object, not always written to Excel file */ /*package*/ColumnInfoRecordsAggregate _columnInfos; - protected ValueRecordsAggregate cells = null; protected RowRecordsAggregate _rowsAggregate = null; - private Iterator valueRecIterator = null; private Iterator rowRecIterator = null; protected int eofLoc = 0; protected ProtectRecord protect = null; @@ -196,17 +191,8 @@ public final class Sheet implements Model { boolean isfirstcell = true; int bofEofNestingLevel = 0; - for (int k = offset; k < recs.size(); k++) - { + for (int k = offset; k < recs.size(); k++) { Record rec = ( Record ) recs.get(k); - if (rec.isValue() != (rec instanceof CellValueRecordInterface)) { - if (rec instanceof SharedFormulaRecord) { - - } else { - "".length(); - } - } - if ( rec.getSid() == DBCellRecord.sid ) { continue; } @@ -239,18 +225,31 @@ public final class Sheet implements Model { retval._dataValidityTable = new DataValidityTable(rs); k += rs.getCountRead() - 1; // TODO - convert this method result to be zero based records.add(retval._dataValidityTable); - continue; // TODO + continue; } - if ( rec.getSid() == RowRecord.sid ) - { + // TODO construct RowRecordsAggregate from RecordStream + if ( rec.getSid() == RowRecord.sid ) { RowRecord row = (RowRecord)rec; if (retval._rowsAggregate == null) { retval._rowsAggregate = new RowRecordsAggregate(); records.add(retval._rowsAggregate); //only add the aggregate once - } + } retval._rowsAggregate.insertRow(row); continue; } + if ( rec.isValue() && bofEofNestingLevel == 1 ) { + if (isfirstcell) { + isfirstcell = false; + if (retval._rowsAggregate == null) { + retval._rowsAggregate = new RowRecordsAggregate(); + records.add(retval._rowsAggregate); //only add the aggregate once + } + retval._rowsAggregate.constructCellValues( k, recs ); + } + continue; + } + + if (rec.getSid() == MergeCellsRecord.sid) { RecordStream rs = new RecordStream(recs, k); retval._mergedCellsTable = new MergedCellsTable(rs); @@ -290,21 +289,7 @@ public final class Sheet implements Model { retval.dims = ( DimensionsRecord ) rec; retval.dimsloc = records.size(); } - else if ( rec.isValue() && bofEofNestingLevel == 1 ) - { - if ( isfirstcell ) - { - retval.cells = new ValueRecordsAggregate(); - rec = retval.cells; - retval.cells.construct( k, recs ); - isfirstcell = false; - } - else - { - rec = null; - } - } - else if (rec.getSid() == DefaultColWidthRecord.sid) + else if (rec.getSid() == DefaultColWidthRecord.sid) { retval.defaultcolwidth = ( DefaultColWidthRecord ) rec; } @@ -381,17 +366,13 @@ public final class Sheet implements Model { retval._columnBreaksRecord = (VerticalPageBreakRecord)rec; } - if (rec != null) - { - records.add(rec); - } + records.add(rec); } if (retval.dimsloc < 0) { - throw new RuntimeException("DimensionsRecord was not found"); + throw new RuntimeException("DimensionsRecord was not found"); } retval.records = records; retval.checkRows(); - retval.checkCells(); if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited"); return retval; @@ -399,14 +380,14 @@ public final class Sheet implements Model { private static final class RecordCloner implements RecordVisitor { - private final List _destList; + private final List _destList; - public RecordCloner(List destList) { - _destList = destList; - } - public void visitRecord(Record r) { - _destList.add(r.clone()); - } + public RecordCloner(List destList) { + _destList = destList; + } + public void visitRecord(Record r) { + _destList.add(r.clone()); + } } /** * Clones the low level records of this sheet and returns the new sheet instance. @@ -421,34 +402,30 @@ public final class Sheet implements Model { for (int i=0; i= mrt.getNumberOfMergedRegions()) { - return; - } - mrt.remove(index); + if (index >= mrt.getNumberOfMergedRegions()) { + return; + } + mrt.remove(index); } public CellRangeAddress getMergedRegionAt(int index) { //safety checks MergedCellsTable mrt = getMergedRecords(); - if (index >= mrt.getNumberOfMergedRegions()) { - return null; - } - return mrt.get(index); + if (index >= mrt.getNumberOfMergedRegions()) { + return null; + } + return mrt.get(index); } public int getNumMergedRegions() { return getMergedRecords().getNumberOfMergedRegions(); } private ConditionalFormattingTable getConditionalFormattingTable() { - if (condFormatting == null) { - condFormatting = new ConditionalFormattingTable(); - RecordOrderer.addNewSheetRecord(records, condFormatting); - } - return condFormatting; + if (condFormatting == null) { + condFormatting = new ConditionalFormattingTable(); + RecordOrderer.addNewSheetRecord(records, condFormatting); + } + return condFormatting; } - public int addConditionalFormatting(CFRecordsAggregate cfAggregate) { - ConditionalFormattingTable cft = getConditionalFormattingTable(); + public int addConditionalFormatting(CFRecordsAggregate cfAggregate) { + ConditionalFormattingTable cft = getConditionalFormattingTable(); return cft.add(cfAggregate); } public void removeConditionalFormatting(int index) { - getConditionalFormattingTable().remove(index); + getConditionalFormattingTable().remove(index); } public CFRecordsAggregate getCFRecordsAggregateAt(int index) { - return getConditionalFormattingTable().get(index); + return getConditionalFormattingTable().get(index); } public int getNumConditionalFormattings() { return getConditionalFormattingTable().size(); } - /** - * Returns the number of low level binary records in this sheet. This adjusts things for the so called - * AgregateRecords. - * - * @see org.apache.poi.hssf.record.Record - */ - - public int getNumRecords() - { - checkCells(); - checkRows(); - if (log.check( POILogger.DEBUG )) - { - log.log(POILogger.DEBUG, "Sheet.getNumRecords"); - log.logFormatted(POILogger.DEBUG, "returning % + % + % - 2 = %", new int[] - { - records.size(), cells.getPhysicalNumberOfCells(), - _rowsAggregate.getPhysicalNumberOfRows(), - records.size() + cells.getPhysicalNumberOfCells() - + _rowsAggregate.getPhysicalNumberOfRows() - 2 - }); - } - return records.size() + cells.getPhysicalNumberOfCells() - + _rowsAggregate.getPhysicalNumberOfRows() - 2; - } - /** * Per an earlier reported bug in working with Andy Khan's excel read library. This * sets the values in the sheet's DimensionsRecord object to be correct. Excel doesn't @@ -711,42 +644,6 @@ public final class Sheet implements Model { log.log(POILogger.DEBUG, "Sheet.setDimensions exiting"); } - /** - * set the locator for where we should look for the next value record. The - * algorithm will actually start here and find the correct location so you - * can set this to 0 and watch performance go down the tubes but it will work. - * After a value is set this is automatically advanced. Its also set by the - * create method. So you probably shouldn't mess with this unless you have - * a compelling reason why or the help for the method you're calling says so. - * Check the other methods for whether they care about - * the loc pointer. Many of the "modify" and "remove" methods re-initialize this - * to "dimsloc" which is the location of the Dimensions Record and presumably the - * start of the value section (at or around 19 dec). - * - * @param loc the record number to start at - * - */ - - public void setLoc(int loc) - { - valueRecIterator = null; - if (log.check( POILogger.DEBUG )) - log.log(POILogger.DEBUG, "sheet.setLoc(): " + loc); - this.loc = loc; - } - - /** - * Returns the location pointer to the first record to look for when adding rows/values - * - */ - - public int getLoc() - { - if (log.check( POILogger.DEBUG )) - log.log(POILogger.DEBUG, "sheet.getLoc():" + loc); - return loc; - } - /** * Set the preoffset when using DBCELL records (currently unused) - this is * the position of this sheet within the whole file. @@ -790,7 +687,7 @@ public final class Sheet implements Model { for (int k = 0; k < records.size(); k++) { - RecordBase record = (RecordBase) records.get(k); + RecordBase record = (RecordBase) records.get(k); // Don't write out UncalcedRecord entries, as // we handle those specially just below @@ -800,13 +697,7 @@ public final class Sheet implements Model { // Once the rows have been found in the list of records, start // writing out the blocked row information. This includes the DBCell references - if (record instanceof RowRecordsAggregate) { - pos += ((RowRecordsAggregate)record).serialize(pos, data, cells); - } else if (record instanceof ValueRecordsAggregate) { - //Do nothing here. The records were serialized during the RowRecordAggregate block serialization - } else { - pos += record.serialize(pos, data ); - } + pos += record.serialize(pos, data); // If the BOF record was just serialized then add the IndexRecord if (record instanceof BOFRecord) { @@ -838,13 +729,7 @@ public final class Sheet implements Model { * @param indexRecordOffset also happens to be the end of the BOF record * @return the size of the serialized INDEX record */ - private int serializeIndexRecord(final int bofRecordIndex, final int indexRecordOffset, - byte[] data) { - IndexRecord index = new IndexRecord(); - index.setFirstRow(_rowsAggregate.getFirstRowNum()); - index.setLastRowAdd1(_rowsAggregate.getLastRowNum() + 1); - // Calculate the size of the records from the end of the BOF - // and up to the RowRecordsAggregate... + private int serializeIndexRecord(int bofRecordIndex, int indexRecordOffset, byte[] data) { // 'initial sheet records' are between INDEX and first ROW record. int sizeOfInitialSheetRecords = 0; @@ -862,32 +747,7 @@ public final class Sheet implements Model { if (_isUncalced) { sizeOfInitialSheetRecords += UncalcedRecord.getStaticRecordSize(); } - - // Add the references to the DBCells in the IndexRecord (one for each block) - // Note: The offsets are relative to the Workbook BOF. Assume that this is - // 0 for now..... - - int blockCount = _rowsAggregate.getRowBlockCount(); - // Calculate the size of this IndexRecord - int indexRecSize = IndexRecord.getRecordSizeForBlockCount(blockCount); - - int currentOffset = indexRecordOffset + indexRecSize + sizeOfInitialSheetRecords; - - for (int block = 0; block < blockCount; block++) { - // each row-block has a DBCELL record. - // The offset of each DBCELL record needs to be updated in the INDEX record - - // account for row records in this row-block - currentOffset += _rowsAggregate.getRowBlockSize(block); - // account for cell value records after those - currentOffset += null == cells ? 0 : cells.getRowCellBlockSize(_rowsAggregate - .getStartRowNumberForBlock(block), _rowsAggregate.getEndRowNumberForBlock(block)); - - // currentOffset is now the location of the DBCELL record for this row-block - index.addDbcell(currentOffset); - // Add space required to write the DBCELL record (whose reference was just added). - currentOffset += (8 + (_rowsAggregate.getRowCountForBlock(block) * 2)); - } + IndexRecord index = _rowsAggregate.createIndexRecord(indexRecordOffset, sizeOfInitialSheetRecords); return index.serialize(indexRecordOffset, data); } @@ -911,15 +771,10 @@ public final class Sheet implements Model { * @param row the row to add the cell value to * @param col the cell value record itself. */ - public void addValueRecord(int row, CellValueRecordInterface col) - { - checkCells(); - if(log.check(POILogger.DEBUG)) - { - log.logFormatted(POILogger.DEBUG, "add value record row,loc %,%", new int[] - { - row, loc - }); + public void addValueRecord(int row, CellValueRecordInterface col) { + + if(log.check(POILogger.DEBUG)) { + log.log(POILogger.DEBUG, "add value record row" + row); } DimensionsRecord d = ( DimensionsRecord ) records.get(getDimsLoc()); @@ -931,7 +786,7 @@ public final class Sheet implements Model { { d.setFirstCol(col.getColumn()); } - cells.insertCell(col); + _rowsAggregate.insertCell(col); } /** @@ -943,13 +798,11 @@ public final class Sheet implements Model { * @param col - a record supporting the CellValueRecordInterface. * @see org.apache.poi.hssf.record.CellValueRecordInterface */ - public void removeValueRecord(int row, CellValueRecordInterface col) - { - checkCells(); + public void removeValueRecord(int row, CellValueRecordInterface col) { + log.logFormatted(POILogger.DEBUG, "remove value record row,dimsloc %,%", new int[]{row, dimsloc} ); - loc = dimsloc; - cells.removeCell(col); + _rowsAggregate.removeCell(col); } /** @@ -962,10 +815,8 @@ public final class Sheet implements Model { * be added. */ - public void replaceValueRecord(CellValueRecordInterface newval) - { - checkCells(); - setLoc(dimsloc); + public void replaceValueRecord(CellValueRecordInterface newval) { + if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "replaceValueRecord "); //The ValueRecordsAggregate use a tree map underneath. @@ -973,8 +824,8 @@ public final class Sheet implements Model { //key and the value, if we dont do a remove, then //the previous instance of the key is retained, effectively using //double the memory - cells.removeCell(newval); - cells.insertCell(newval); + _rowsAggregate.removeCell(newval); + _rowsAggregate.insertCell(newval); } /** @@ -1024,12 +875,8 @@ public final class Sheet implements Model { * * @param row the row record to remove */ - - public void removeRow(RowRecord row) - { + public void removeRow(RowRecord row) { checkRows(); - - setLoc(getDimsLoc()); _rowsAggregate.removeRow(row); } @@ -1047,20 +894,8 @@ public final class Sheet implements Model { * @return CellValueRecordInterface representing the next value record or NULL if there are no more * @see #setLoc(int) */ - - public CellValueRecordInterface getNextValueRecord() - { - if (log.check( POILogger.DEBUG )) - log.log(POILogger.DEBUG, "getNextValue loc= " + loc); - if (valueRecIterator == null) - { - valueRecIterator = cells.getIterator(); - } - if (!valueRecIterator.hasNext()) - { - return null; - } - return ( CellValueRecordInterface ) valueRecIterator.next(); + public CellValueRecordInterface[] getValueRecords() { + return _rowsAggregate.getValueRecords(); } /** @@ -1077,11 +912,7 @@ public final class Sheet implements Model { * @see #setLoc(int) * */ - - public RowRecord getNextRow() - { - if (log.check( POILogger.DEBUG )) - log.log(POILogger.DEBUG, "getNextRow loc= " + loc); + public RowRecord getNextRow() { if (rowRecIterator == null) { rowRecIterator = _rowsAggregate.getIterator(); @@ -1110,8 +941,6 @@ public final class Sheet implements Model { * */ public RowRecord getRow(int rownum) { - if (log.check( POILogger.DEBUG )) - log.log(POILogger.DEBUG, "getNextRow loc= " + loc); return _rowsAggregate.getRow(rownum); } @@ -1235,13 +1064,13 @@ public final class Sheet implements Model { return retval; } private GutsRecord getGutsRecord() { - if (_gutsRecord == null) { - GutsRecord result = createGuts(); - RecordOrderer.addNewSheetRecord(records, result); - _gutsRecord = result; - } + if (_gutsRecord == null) { + GutsRecord result = createGuts(); + RecordOrderer.addNewSheetRecord(records, result); + _gutsRecord = result; + } - return _gutsRecord; + return _gutsRecord; } /** @@ -1418,7 +1247,7 @@ public final class Sheet implements Model { ColumnInfoRecord ci = _columnInfos.findColumnInfo(columnIndex); if (ci != null) { - return ci.getColumnWidth(); + return ci.getColumnWidth(); } //default column width is measured in characters //multiply @@ -1443,18 +1272,18 @@ public final class Sheet implements Model { ColumnInfoRecord ci = _columnInfos.findColumnInfo(columnIndex); if (ci != null) { return ci.getXFIndex(); - } - return 0xF; - } + } + return 0xF; + } /** - * set the width for a given column in 1/256th of a character width units - * - * @param column - - * the column number - * @param width - * (in units of 1/256th of a character width) - */ + * set the width for a given column in 1/256th of a character width units + * + * @param column - + * the column number + * @param width + * (in units of 1/256th of a character width) + */ public void setColumnWidth(short column, short width) { setColumn( column, new Short(width), null, null, null); } @@ -1468,11 +1297,11 @@ public final class Sheet implements Model { * @return whether the column is hidden or not. */ public boolean isColumnHidden(short columnIndex) { - ColumnInfoRecord cir = _columnInfos.findColumnInfo(columnIndex); - if (cir == null) { - return false; - } - return cir.getHidden(); + ColumnInfoRecord cir = _columnInfos.findColumnInfo(columnIndex); + if (cir == null) { + return false; + } + return cir.getHidden(); } /** @@ -1659,12 +1488,8 @@ public final class Sheet implements Model { /** * in the event the record is a dimensions record, resets both the loc index and dimsloc index */ - - public void checkDimsLoc(Record rec, int recloc) - { - if (rec.getSid() == DimensionsRecord.sid) - { - loc = recloc; + public void checkDimsLoc(Record rec, int recloc) { + if (rec.getSid() == DimensionsRecord.sid) { dimsloc = recloc; } } @@ -1672,33 +1497,17 @@ public final class Sheet implements Model { /** * @return the serialized size of this sheet */ - public int getSize() - { + public int getSize() { int retval = 0; for ( int k = 0; k < records.size(); k++) { - RecordBase record = (RecordBase) records.get(k); + RecordBase record = (RecordBase) records.get(k); if (record instanceof UncalcedRecord) { // skip the UncalcedRecord if present, it's only encoded if the isUncalced flag is set continue; } retval += record.getRecordSize(); } - if (_rowsAggregate != null) { - // Add space for the IndexRecord and DBCell records - final int nBlocks = _rowsAggregate.getRowBlockCount(); - int nRows = 0; - if (cells != null) { - for (Iterator itr = _rowsAggregate.getIterator(); itr.hasNext();) { - RowRecord row = (RowRecord)itr.next(); - if (cells.rowHasCells(row.getRowNumber())) { - nRows++; - } - } - } - retval += IndexRecord.getRecordSizeForBlockCount(nBlocks); - retval += DBCellRecord.calculateSizeOfRecords(nBlocks, nRows); - } // Add space for UncalcedRecord if (_isUncalced) { retval += UncalcedRecord.getStaticRecordSize(); @@ -1726,11 +1535,11 @@ public final class Sheet implements Model { public Record findFirstRecordBySid(short sid) { - int ix = findFirstRecordLocBySid(sid); - if (ix < 0) { - return null; - } - return (Record) records.get(ix); + int ix = findFirstRecordLocBySid(sid); + if (ix < 0) { + return null; + } + return (Record) records.get(ix); } /** @@ -1765,9 +1574,9 @@ public final class Sheet implements Model { public int findFirstRecordLocBySid( short sid ) { // TODO - remove this method int max = records.size(); for (int i=0; i< max; i++) { - Object rb = records.get(i); + Object rb = records.get(i); if (!(rb instanceof Record)) { - continue; + continue; } Record record = (Record) rb; if (record.getSid() == sid) { @@ -2095,8 +1904,8 @@ public final class Sheet implements Model { */ private static PasswordRecord createPassword() { if (log.check( POILogger.DEBUG )) { - log.log(POILogger.DEBUG, "create password record with 00 password"); - } + log.log(POILogger.DEBUG, "create password record with 00 password"); + } PasswordRecord retval = new PasswordRecord(); retval.setPassword((short)00); @@ -2276,21 +2085,21 @@ public final class Sheet implements Model { } private PageBreakRecord getRowBreaksRecord() { - if (_rowBreaksRecord == null) { - _rowBreaksRecord = new HorizontalPageBreakRecord(); - RecordOrderer.addNewSheetRecord(records, _rowBreaksRecord); - dimsloc++; - } - return _rowBreaksRecord; + if (_rowBreaksRecord == null) { + _rowBreaksRecord = new HorizontalPageBreakRecord(); + RecordOrderer.addNewSheetRecord(records, _rowBreaksRecord); + dimsloc++; + } + return _rowBreaksRecord; } private PageBreakRecord getColumnBreaksRecord() { - if (_columnBreaksRecord == null) { - _columnBreaksRecord = new VerticalPageBreakRecord(); - RecordOrderer.addNewSheetRecord(records, _columnBreaksRecord); - dimsloc++; - } - return _columnBreaksRecord; + if (_columnBreaksRecord == null) { + _columnBreaksRecord = new VerticalPageBreakRecord(); + RecordOrderer.addNewSheetRecord(records, _columnBreaksRecord); + dimsloc++; + } + return _columnBreaksRecord; } @@ -2334,7 +2143,7 @@ public final class Sheet implements Model { * */ public void removeColumnBreak(short column) { - getColumnBreaksRecord().removeBreak(column); + getColumnBreaksRecord().removeBreak(column); } /** @@ -2520,8 +2329,8 @@ public final class Sheet implements Model { } public DataValidityTable getOrCreateDataValidityTable() { if (_dataValidityTable == null) { - DataValidityTable result = new DataValidityTable(); - RecordOrderer.addNewSheetRecord(records, result); + DataValidityTable result = new DataValidityTable(); + RecordOrderer.addNewSheetRecord(records, result); _dataValidityTable = result; } return _dataValidityTable; diff --git a/src/java/org/apache/poi/hssf/record/RowRecord.java b/src/java/org/apache/poi/hssf/record/RowRecord.java index 46d4a1efe..2ef876398 100644 --- a/src/java/org/apache/poi/hssf/record/RowRecord.java +++ b/src/java/org/apache/poi/hssf/record/RowRecord.java @@ -22,15 +22,17 @@ import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.LittleEndian; /** - * Title: Row Record

- * Description: stores the row information for the sheet.

+ * Title: Row Record (0x0208)

+ * Description: stores the row information for the sheet.

* REFERENCE: PG 379 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)

* @author Andrew C. Oliver (acoliver at apache dot org) * @author Jason Height (jheight at chariot dot net dot au) * @version 2.0-pre */ public final class RowRecord extends Record implements Comparable { - public final static short sid = 0x208; + public final static short sid = 0x0208; + + public static final int ENCODED_SIZE = 20; private static final int OPTION_BITS_ALWAYS_SET = 0x0100; private static final int DEFAULT_HEIGHT_BIT = 0x8000; @@ -407,23 +409,23 @@ public final class RowRecord extends Record implements Comparable { public int serialize(int offset, byte [] data) { - LittleEndian.putShort(data, 0 + offset, sid); - LittleEndian.putShort(data, 2 + offset, ( short ) 16); - LittleEndian.putShort(data, 4 + offset, ( short ) getRowNumber()); - LittleEndian.putShort(data, 6 + offset, getFirstCol() == -1 ? (short)0 : getFirstCol()); - LittleEndian.putShort(data, 8 + offset, getLastCol() == -1 ? (short)0 : getLastCol()); - LittleEndian.putShort(data, 10 + offset, getHeight()); - LittleEndian.putShort(data, 12 + offset, getOptimize()); - LittleEndian.putShort(data, 14 + offset, field_6_reserved); - LittleEndian.putShort(data, 16 + offset, getOptionFlags()); + LittleEndian.putUShort(data, 0 + offset, sid); + LittleEndian.putUShort(data, 2 + offset, ENCODED_SIZE - 4); + LittleEndian.putUShort(data, 4 + offset, getRowNumber()); + LittleEndian.putUShort(data, 6 + offset, getFirstCol() == -1 ? (short)0 : getFirstCol()); + LittleEndian.putUShort(data, 8 + offset, getLastCol() == -1 ? (short)0 : getLastCol()); + LittleEndian.putUShort(data, 10 + offset, getHeight()); + LittleEndian.putUShort(data, 12 + offset, getOptimize()); + LittleEndian.putUShort(data, 14 + offset, field_6_reserved); + LittleEndian.putUShort(data, 16 + offset, getOptionFlags()); - LittleEndian.putShort(data, 18 + offset, getXFIndex()); - return getRecordSize(); + LittleEndian.putUShort(data, 18 + offset, getXFIndex()); + return ENCODED_SIZE; } public int getRecordSize() { - return 20; + return ENCODED_SIZE; } public short getSid() diff --git a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java index 65af632d3..91028e360 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -16,85 +15,90 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record.aggregates; -import org.apache.poi.hssf.record.DBCellRecord; -import org.apache.poi.hssf.record.Record; -import org.apache.poi.hssf.record.RecordInputStream; -import org.apache.poi.hssf.record.RowRecord; - - +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.TreeMap; +import org.apache.poi.hssf.record.CellValueRecordInterface; +import org.apache.poi.hssf.record.DBCellRecord; +import org.apache.poi.hssf.record.IndexRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.RecordBase; +import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.hssf.record.RowRecord; + /** * * @author andy * @author Jason Height (jheight at chariot dot net dot au) */ - public final class RowRecordsAggregate extends Record { - private int firstrow = -1; - private int lastrow = -1; - private Map records = null; // TODO - use a proper key in this map - private int size = 0; + private int _firstrow = -1; + private int _lastrow = -1; + private final Map _rowRecords; + private final ValueRecordsAggregate _valuesAgg; /** Creates a new instance of ValueRecordsAggregate */ - public RowRecordsAggregate() - { - records = new TreeMap(); + public RowRecordsAggregate() { + this(new TreeMap(), new ValueRecordsAggregate()); + } + private RowRecordsAggregate(TreeMap rowRecords, ValueRecordsAggregate valuesAgg) { + _rowRecords = rowRecords; + _valuesAgg = valuesAgg; } - public void insertRow(RowRecord row) - { - size += row.getRecordSize(); - + public void insertRow(RowRecord row) { // Integer integer = new Integer(row.getRowNumber()); - records.put(row, row); - if ((row.getRowNumber() < firstrow) || (firstrow == -1)) + _rowRecords.put(new Integer(row.getRowNumber()), row); + if ((row.getRowNumber() < _firstrow) || (_firstrow == -1)) { - firstrow = row.getRowNumber(); + _firstrow = row.getRowNumber(); } - if ((row.getRowNumber() > lastrow) || (lastrow == -1)) + if ((row.getRowNumber() > _lastrow) || (_lastrow == -1)) { - lastrow = row.getRowNumber(); + _lastrow = row.getRowNumber(); } } - public void removeRow(RowRecord row) - { - size -= row.getRecordSize(); - - // Integer integer = new Integer(row.getRowNumber()); - records.remove(row); + public void removeRow(RowRecord row) { + int rowIndex = row.getRowNumber(); + _valuesAgg.removeAllCellsValuesForRow(rowIndex); + Integer key = new Integer(rowIndex); + RowRecord rr = (RowRecord) _rowRecords.remove(key); + if (rr == null) { + throw new RuntimeException("Invalid row index (" + key.intValue() + ")"); + } + if (row != rr) { + _rowRecords.put(key, rr); + throw new RuntimeException("Attempt to remove row that does not belong to this sheet"); + } } - public RowRecord getRow(int rownum) { - // Row must be between 0 and 65535 - if(rownum < 0 || rownum > 65535) { + public RowRecord getRow(int rowIndex) { + if (rowIndex < 0 || rowIndex > 65535) { throw new IllegalArgumentException("The row number must be between 0 and 65535"); } - - RowRecord row = new RowRecord(rownum); - return ( RowRecord ) records.get(row); + return (RowRecord) _rowRecords.get(new Integer(rowIndex)); } public int getPhysicalNumberOfRows() { - return records.size(); + return _rowRecords.size(); } public int getFirstRowNum() { - return firstrow; + return _firstrow; } public int getLastRowNum() { - return lastrow; + return _lastrow; } /** Returns the number of row blocks. @@ -102,54 +106,60 @@ public final class RowRecordsAggregate extends Record { * after them */ public int getRowBlockCount() { - int size = records.size()/DBCellRecord.BLOCK_SIZE; - if ((records.size() % DBCellRecord.BLOCK_SIZE) != 0) + int size = _rowRecords.size()/DBCellRecord.BLOCK_SIZE; + if ((_rowRecords.size() % DBCellRecord.BLOCK_SIZE) != 0) size++; return size; } - public int getRowBlockSize(int block) { - return 20 * getRowCountForBlock(block); + private int getRowBlockSize(int block) { + return RowRecord.ENCODED_SIZE * getRowCountForBlock(block); } /** Returns the number of physical rows within a block*/ public int getRowCountForBlock(int block) { int startIndex = block * DBCellRecord.BLOCK_SIZE; int endIndex = startIndex + DBCellRecord.BLOCK_SIZE - 1; - if (endIndex >= records.size()) - endIndex = records.size()-1; + if (endIndex >= _rowRecords.size()) + endIndex = _rowRecords.size()-1; return endIndex-startIndex+1; } /** Returns the physical row number of the first row in a block*/ - public int getStartRowNumberForBlock(int block) { + private int getStartRowNumberForBlock(int block) { //Given that we basically iterate through the rows in order, - //For a performance improvement, it would be better to return an instance of + // TODO - For a performance improvement, it would be better to return an instance of //an iterator and use that instance throughout, rather than recreating one and //having to move it to the right position. int startIndex = block * DBCellRecord.BLOCK_SIZE; - Iterator rowIter = records.values().iterator(); + Iterator rowIter = _rowRecords.values().iterator(); RowRecord row = null; //Position the iterator at the start of the block for (int i=0; i<=startIndex;i++) { row = (RowRecord)rowIter.next(); } + if (row == null) { + throw new RuntimeException("Did not find start row for block " + block); + } return row.getRowNumber(); } /** Returns the physical row number of the end row in a block*/ - public int getEndRowNumberForBlock(int block) { + private int getEndRowNumberForBlock(int block) { int endIndex = ((block + 1)*DBCellRecord.BLOCK_SIZE)-1; - if (endIndex >= records.size()) - endIndex = records.size()-1; + if (endIndex >= _rowRecords.size()) + endIndex = _rowRecords.size()-1; - Iterator rowIter = records.values().iterator(); + Iterator rowIter = _rowRecords.values().iterator(); RowRecord row = null; for (int i=0; i<=endIndex;i++) { row = (RowRecord)rowIter.next(); } + if (row == null) { + throw new RuntimeException("Did not find start row for block " + block); + } return row.getRowNumber(); } @@ -159,7 +169,7 @@ public final class RowRecordsAggregate extends Record { final int startIndex = block*DBCellRecord.BLOCK_SIZE; final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE; - Iterator rowIterator = records.values().iterator(); + Iterator rowIterator = _rowRecords.values().iterator(); int pos = offset; //Given that we basically iterate through the rows in order, @@ -175,10 +185,6 @@ public final class RowRecordsAggregate extends Record { } return pos - offset; } - - public int serialize(int offset, byte [] data) { - throw new RuntimeException("The serialize method that passes in cells should be used"); - } /** @@ -190,9 +196,8 @@ public final class RowRecordsAggregate extends Record { * @param data byte array containing instance data * @return number of bytes written */ - - public int serialize(int offset, byte [] data, ValueRecordsAggregate cells) - { + public int serialize(int offset, byte [] data) { + ValueRecordsAggregate cells = _valuesAgg; int pos = offset; //DBCells are serialized before row records. @@ -209,7 +214,7 @@ public final class RowRecordsAggregate extends Record { final int endRowNumber = getEndRowNumberForBlock(block); DBCellRecord cellRecord = new DBCellRecord(); //Note: Cell references start from the second row... - int cellRefOffset = (rowBlockSize-20); + int cellRefOffset = (rowBlockSize-RowRecord.ENCODED_SIZE); for (int row=startRowNumber;row<=endRowNumber;row++) { if (null != cells && cells.rowHasCells(row)) { final int rowCellSize = cells.serializeCellRow(row, pos, data); @@ -254,29 +259,59 @@ public final class RowRecordsAggregate extends Record { return -1000; } - public int getRecordSize() - { - return size; + public int getRecordSize() { + + int retval = this._rowRecords.size() * RowRecord.ENCODED_SIZE; + + for (Iterator itr = _valuesAgg.getIterator(); itr.hasNext();) { + RecordBase record = (RecordBase) itr.next(); + retval += record.getRecordSize(); + } + + // Add space for the IndexRecord and DBCell records + final int nBlocks = getRowBlockCount(); + int nRows = 0; + for (Iterator itr = getIterator(); itr.hasNext();) { + RowRecord row = (RowRecord)itr.next(); + if (_valuesAgg.rowHasCells(row.getRowNumber())) { + nRows++; + } + } + retval += IndexRecord.getRecordSizeForBlockCount(nBlocks); + retval += DBCellRecord.calculateSizeOfRecords(nBlocks, nRows); + return retval; } public Iterator getIterator() { - return records.values().iterator(); + return _rowRecords.values().iterator(); } + + public Iterator getAllRecordsIterator() { + List result = new ArrayList(_rowRecords.size() * 2); + result.addAll(_rowRecords.values()); + Iterator vi = _valuesAgg.getIterator(); + while (vi.hasNext()) { + result.add(vi.next()); + } + return result.iterator(); + } /** * Performs a deep clone of the record */ public Object clone() { - RowRecordsAggregate rec = new RowRecordsAggregate(); + TreeMap rows = new TreeMap(); + for ( Iterator rowIter = getIterator(); rowIter.hasNext(); ) { //return the cloned Row Record & insert RowRecord row = (RowRecord) ( (RowRecord) rowIter.next() ).clone(); - rec.insertRow( row ); + rows.put(row, row); } - return rec; + ValueRecordsAggregate valuesAgg = (ValueRecordsAggregate) _valuesAgg.clone(); + return new RowRecordsAggregate(rows, valuesAgg); } @@ -449,5 +484,52 @@ public final class RowRecordsAggregate extends Record { } } + public CellValueRecordInterface[] getValueRecords() { + return _valuesAgg.getValueRecords(); + } + + public IndexRecord createIndexRecord(int indexRecordOffset, int sizeOfInitialSheetRecords) { + IndexRecord result = new IndexRecord(); + result.setFirstRow(_firstrow); + result.setLastRowAdd1(_lastrow + 1); + // Calculate the size of the records from the end of the BOF + // and up to the RowRecordsAggregate... + + // Add the references to the DBCells in the IndexRecord (one for each block) + // Note: The offsets are relative to the Workbook BOF. Assume that this is + // 0 for now..... + + int blockCount = getRowBlockCount(); + // Calculate the size of this IndexRecord + int indexRecSize = IndexRecord.getRecordSizeForBlockCount(blockCount); + + int currentOffset = indexRecordOffset + indexRecSize + sizeOfInitialSheetRecords; + + for (int block = 0; block < blockCount; block++) { + // each row-block has a DBCELL record. + // The offset of each DBCELL record needs to be updated in the INDEX record + + // account for row records in this row-block + currentOffset += getRowBlockSize(block); + // account for cell value records after those + currentOffset += _valuesAgg.getRowCellBlockSize( + getStartRowNumberForBlock(block), getEndRowNumberForBlock(block)); + + // currentOffset is now the location of the DBCELL record for this row-block + result.addDbcell(currentOffset); + // Add space required to write the DBCELL record (whose reference was just added). + currentOffset += (8 + (getRowCountForBlock(block) * 2)); + } + return result; + } + public void constructCellValues(int offset, List records) { + _valuesAgg.construct(offset, records); + } + public void insertCell(CellValueRecordInterface cvRec) { + _valuesAgg.insertCell(cvRec); + } + public void removeCell(CellValueRecordInterface cvRec) { + _valuesAgg.removeCell(cvRec); + } } diff --git a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java index fb4bfd59a..8ba786a38 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java @@ -1,4 +1,3 @@ - /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -16,14 +15,19 @@ limitations under the License. ==================================================================== */ - package org.apache.poi.hssf.record.aggregates; -import org.apache.poi.hssf.record.*; - +import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import org.apache.poi.hssf.record.CellValueRecordInterface; +import org.apache.poi.hssf.record.EOFRecord; +import org.apache.poi.hssf.record.FormulaRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.SharedFormulaRecord; +import org.apache.poi.hssf.record.StringRecord; +import org.apache.poi.hssf.record.UnknownRecord; /** * @@ -33,20 +37,16 @@ import java.util.List; * @author Glen Stampoultzis (glens at apache.org) * @author Jason Height (jheight at chariot dot net dot au) */ - -public final class ValueRecordsAggregate - extends Record -{ - public final static short sid = -1001; // 1000 clashes with RowRecordsAggregate - int firstcell = -1; - int lastcell = -1; - CellValueRecordInterface[][] records; +public final class ValueRecordsAggregate { + private int firstcell = -1; + private int lastcell = -1; + private CellValueRecordInterface[][] records; /** Creates a new instance of ValueRecordsAggregate */ public ValueRecordsAggregate() { - records = new CellValueRecordInterface[30][]; // We start with 30 Rows. + records = new CellValueRecordInterface[30][]; // We start with 30 Rows. } public void insertCell(CellValueRecordInterface cell) { @@ -85,19 +85,34 @@ public final class ValueRecordsAggregate } } - public void removeCell(CellValueRecordInterface cell) - { - if (cell != null) { - short column = cell.getColumn(); - int row = cell.getRow(); - if(row>=records.length) return; - CellValueRecordInterface[] rowCells=records[row]; - if(rowCells==null) return; - if(column>=rowCells.length) return; - rowCells[column]=null; - } + public void removeCell(CellValueRecordInterface cell) { + if (cell == null) { + throw new IllegalArgumentException("cell must not be null"); + } + int row = cell.getRow(); + if (row >= records.length) { + throw new RuntimeException("cell row is out of range"); + } + CellValueRecordInterface[] rowCells = records[row]; + if (rowCells == null) { + throw new RuntimeException("cell row is already empty"); + } + short column = cell.getColumn(); + if (column >= rowCells.length) { + throw new RuntimeException("cell column is out of range"); + } + rowCells[column] = null; } + public void removeAllCellsValuesForRow(int rowIndex) { + if (rowIndex >= records.length) { + throw new IllegalArgumentException("Specified rowIndex " + rowIndex + + " is outside the allowable range (0.." +records.length + ")"); + } + records[rowIndex] = null; + } + + public int getPhysicalNumberOfCells() { int count=0; @@ -133,7 +148,7 @@ public final class ValueRecordsAggregate { Record rec = ( Record ) records.get(k); if (rec instanceof SharedFormulaRecord) { - sharedFormulas.add(rec); + sharedFormulas.add(rec); } if(rec instanceof EOFRecord) { // End of current sheet. Ignore all subsequent shared formula records (Bugzilla 44449) @@ -150,30 +165,30 @@ public final class ValueRecordsAggregate { break; } else if (rec instanceof SharedFormulaRecord) { - // Already handled, not to worry + // Already handled, not to worry } else if (rec instanceof FormulaRecord) { FormulaRecord formula = (FormulaRecord)rec; if (formula.isSharedFormula()) { // Traverse the list of shared formulas in - // reverse order, and try to find the correct one + // reverse order, and try to find the correct one // for us boolean found = false; for (int i=sharedFormulas.size()-1;i>=0;i--) { // TODO - there is no junit test case to justify this reversed loop // perhaps it could just run in the normal direction? - SharedFormulaRecord shrd = (SharedFormulaRecord)sharedFormulas.get(i); - if (shrd.isFormulaInShared(formula)) { - shrd.convertSharedFormulaRecord(formula); - found = true; - break; - } + SharedFormulaRecord shrd = (SharedFormulaRecord)sharedFormulas.get(i); + if (shrd.isFormulaInShared(formula)) { + shrd.convertSharedFormulaRecord(formula); + found = true; + break; + } } if (!found) { handleMissingSharedFormulaRecord(formula); } } - + lastFormulaAggregate = new FormulaRecordAggregate((FormulaRecord)rec, null); insertCell( lastFormulaAggregate ); } @@ -206,21 +221,6 @@ public final class ValueRecordsAggregate private static void handleMissingSharedFormulaRecord(FormulaRecord formula) { // could log an info message here since this is a fairly unusual occurrence. } - - /** - * called by the class that is responsible for writing this sucker. - * Subclasses should implement this so that their data is passed back in a - * byte array. - * - * @param offset to begin writing at - * @param data byte array containing instance data - * @return number of bytes written - */ - - public int serialize(int offset, byte [] data) - { - throw new RuntimeException("This method shouldnt be called. ValueRecordsAggregate.serializeCellRow() should be called from RowRecordsAggregate."); - } /** Tallies a count of the size of the cell records * that are attached to the rows in the range specified. @@ -241,8 +241,8 @@ public final class ValueRecordsAggregate /** Returns true if the row has cells attached to it */ public boolean rowHasCells(int row) { - if (row > records.length-1) //previously this said row > records.length which means if - return false; // if records.length == 60 and I pass "60" here I get array out of bounds + if (row > records.length-1) //previously this said row > records.length which means if + return false; // if records.length == 60 and I pass "60" here I get array out of bounds CellValueRecordInterface[] rowCells=records[row]; //because a 60 length array has the last index = 59 if(rowCells==null) return false; for(int col=0;col CELL_TYPE_ERROR) { throw new RuntimeException("I have no idea what type that is!"); @@ -501,10 +475,7 @@ public class HSSFCell if (cellType != this.cellType && this.cellType!=-1 ) // Special Value to indicate an uninitialized Cell { - int loc = sheet.getLoc(); - sheet.replaceValueRecord(record); - sheet.setLoc(loc); } this.cellType = cellType; } @@ -540,7 +511,7 @@ public class HSSFCell setCellType(CELL_TYPE_NUMERIC, false, row, col, styleIndex); } - // Save into the apropriate record + // Save into the appropriate record if(record instanceof FormulaRecordAggregate) { (( FormulaRecordAggregate ) record).getFormulaRecord().setValue(value); } else { @@ -670,9 +641,7 @@ public class HSSFCell //only set to default if there is no extended format index already set if (rec.getXFIndex() == (short)0) rec.setXFIndex(( short ) 0x0f); - FormulaParser fp = new FormulaParser(formula, book); - fp.parse(); - Ptg[] ptg = fp.getRPNPtg(); + Ptg[] ptgs = FormulaParser.parse(formula, book); int size = 0; // clear the Ptg Stack @@ -681,9 +650,9 @@ public class HSSFCell } // fill the Ptg Stack with Ptgs of new formula - for (int k = 0; k < ptg.length; k++) { - size += ptg[ k ].getSize(); - frec.pushExpressionToken(ptg[ k ]); + for (int k = 0; k < ptgs.length; k++) { + size += ptgs[ k ].getSize(); + frec.pushExpressionToken(ptgs[ k ]); } rec.getFormulaRecord().setExpressionLength(( short ) size); //Workbook.currentBook = null; @@ -957,38 +926,6 @@ public class HSSFCell ExtendedFormatRecord xf = book.getWorkbook().getExFormatAt(styleIndex); return new HSSFCellStyle(styleIndex, xf, book); } - - /** - * used for internationalization, currently -1 for unchanged, 0 for compressed unicode or 1 for 16-bit - * - * @see #ENCODING_UNCHANGED - * @see #ENCODING_COMPRESSED_UNICODE - * @see #ENCODING_UTF_16 - * - * @return -1, 1 or 0 for unchanged, compressed or uncompressed (used only with String type) - * - * @deprecated As of 3-Jan-06 POI now automatically handles Unicode without forcing the encoding. - */ - public short getEncoding() - { - return encoding; - } - - /** - * set the encoding to either 8 or 16 bit. (US/UK use 8-bit, rest of the western world use 16bit) - * - * @see #ENCODING_UNCHANGED - * @see #ENCODING_COMPRESSED_UNICODE - * @see #ENCODING_UTF_16 - * - * @param encoding either ENCODING_COMPRESSED_UNICODE (0) or ENCODING_UTF_16 (1) - * @deprecated As of 3-Jan-06 POI now automatically handles Unicode without forcing the encoding. - */ - - public void setEncoding(short encoding) - { - this.encoding = encoding; - } /** * Should only be used by HSSFSheet and friends. Returns the low level CellValueRecordInterface record diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java index 2a2d3635c..a893bdd69 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java @@ -98,7 +98,12 @@ public final class HSSFRow implements Comparable { setRowNum(record.getRowNumber()); } - + /** + * @deprecated (Aug 2008) use {@link HSSFRow#createCell(int) } + */ + public HSSFCell createCell(short columnIndex) { + return createCell((int)columnIndex); + } /** * Use this to create new cells within the row and return it. *

@@ -109,26 +114,31 @@ public final class HSSFRow implements Comparable { * * @return HSSFCell a high level representation of the created cell. */ - - public HSSFCell createCell(short column) + public HSSFCell createCell(int columnIndex) { - return this.createCell(column,HSSFCell.CELL_TYPE_BLANK); + return this.createCell(columnIndex,HSSFCell.CELL_TYPE_BLANK); } + /** + * @deprecated (Aug 2008) use {@link HSSFRow#createCell(int, int) } + */ + public HSSFCell createCell(short columnIndex, int type) { + return createCell((int)columnIndex, type); + } /** * Use this to create new cells within the row and return it. *

* The cell that is returned is a CELL_TYPE_BLANK. The type can be changed * either through calling setCellValue or setCellType. * - * @param column - the column number this cell represents + * @param columnIndex - the column number this cell represents * * @return HSSFCell a high level representation of the created cell. */ - public HSSFCell createCell(short column, int type) + public HSSFCell createCell(int columnIndex, int type) { - HSSFCell cell = new HSSFCell(book, sheet, getRowNum(), column, type); + HSSFCell cell = new HSSFCell(book, sheet, getRowNum(), (short)columnIndex, type); addCell(cell); sheet.addValueRecord(getRowNum(), cell.getCellValueRecord()); @@ -174,12 +184,12 @@ public final class HSSFRow implements Comparable { * records too. */ protected void removeAllCells() { - for(int i=0; i 0) { rows.remove(row); @@ -245,15 +233,6 @@ public final class HSSFSheet { { firstrow = findFirstRow(firstrow); } - Iterator iter = row.cellIterator(); - - while (iter.hasNext()) - { - HSSFCell cell = (HSSFCell) iter.next(); - - sheet.removeValueRecord(row.getRowNum(), - cell.getCellValueRecord()); - } sheet.removeRow(row.getRowRecord()); } } @@ -646,8 +625,8 @@ public final class HSSFSheet { public Region getMergedRegionAt(int index) { CellRangeAddress cra = getMergedRegion(index); - return new Region(cra.getFirstRow(), (short)cra.getFirstColumn(), - cra.getLastRow(), (short)cra.getLastColumn()); + return new Region(cra.getFirstRow(), (short)cra.getFirstColumn(), + cra.getLastRow(), (short)cra.getLastColumn()); } /** * @return the merged region at the specified index @@ -1094,8 +1073,8 @@ public final class HSSFSheet { //don't check if it's not within the shifted area if (!inStart || !inEnd) { - continue; - } + continue; + } //only shift if the region outside the shifted rows is not merged too if (!containsCell(merged, startRow-1, 0) && !containsCell(merged, endRow+1, 0)){ @@ -1111,7 +1090,7 @@ public final class HSSFSheet { //read so it doesn't get shifted again Iterator iterator = shiftedRegions.iterator(); while (iterator.hasNext()) { - CellRangeAddress region = (CellRangeAddress)iterator.next(); + CellRangeAddress region = (CellRangeAddress)iterator.next(); this.addMergedRegion(region); } @@ -1161,7 +1140,7 @@ public final class HSSFSheet { */ public void shiftRows( int startRow, int endRow, int n, boolean copyRowHeight, boolean resetOriginalRowHeight) { - shiftRows(startRow, endRow, n, copyRowHeight, resetOriginalRowHeight, true); + shiftRows(startRow, endRow, n, copyRowHeight, resetOriginalRowHeight, true); } /** @@ -1223,8 +1202,8 @@ public final class HSSFSheet { // Fetch the first and last columns of the // row now, so we still have them to hand // once we start removing cells - short firstCol = row.getFirstCellNum(); - short lastCol = row.getLastCellNum(); + short firstCol = row.getFirstCellNum(); + short lastCol = row.getLastCellNum(); // Fix up row heights if required if (copyRowHeight) { @@ -1237,7 +1216,7 @@ public final class HSSFSheet { // Copy each cell from the source row to // the destination row for(Iterator cells = row.cellIterator(); cells.hasNext(); ) { - cell = (HSSFCell)cells.next(); + cell = (HSSFCell)cells.next(); row.removeCell( cell ); CellValueRecordInterface cellRecord = cell.getCellValueRecord(); cellRecord.setRow( rowNum + n ); @@ -1251,12 +1230,12 @@ public final class HSSFSheet { // destination row. Note that comments can // exist for cells which are null if(moveComments) { - for( short col = firstCol; col <= lastCol; col++ ) { - HSSFComment comment = getCellComment(rowNum, col); - if (comment != null) { - comment.setRow(rowNum + n); - } - } + for( short col = firstCol; col <= lastCol; col++ ) { + HSSFComment comment = getCellComment(rowNum, col); + if (comment != null) { + comment.setRow(rowNum + n); + } + } } } if ( endRow == lastrow || endRow + n > lastrow ) lastrow = Math.min( endRow + n, 65535 ); @@ -1592,9 +1571,9 @@ public final class HSSFSheet { * start from scratch! */ public HSSFPatriarch getDrawingPatriarch() { - EscherAggregate agg = getDrawingEscherAggregate(); - if(agg == null) return null; - + EscherAggregate agg = getDrawingEscherAggregate(); + if(agg == null) return null; + HSSFPatriarch patriarch = new HSSFPatriarch(this, agg); agg.setPatriarch(patriarch); @@ -1669,7 +1648,7 @@ public final class HSSFSheet { * @param column the column index */ public void autoSizeColumn(short column) { - autoSizeColumn(column, false); + autoSizeColumn(column, false); } /** @@ -1718,19 +1697,19 @@ public final class HSSFSheet { HSSFCell cell = row.getCell(column); if (cell == null) { - continue; - } + continue; + } int colspan = 1; for (int i = 0 ; i < getNumMergedRegions(); i++) { CellRangeAddress region = getMergedRegion(i); - if (containsCell(region, row.getRowNum(), column)) { - if (!useMergedCells) { - // If we're not using merged cells, skip this one and move on to the next. - continue rows; - } - cell = row.getCell(region.getFirstColumn()); - colspan = 1 + region.getLastColumn() - region.getFirstColumn(); + if (containsCell(region, row.getRowNum(), column)) { + if (!useMergedCells) { + // If we're not using merged cells, skip this one and move on to the next. + continue rows; + } + cell = row.getCell(region.getFirstColumn()); + colspan = 1 + region.getLastColumn() - region.getFirstColumn(); } } @@ -1821,7 +1800,7 @@ public final class HSSFSheet { } if (width != -1) { if (width > Short.MAX_VALUE) { //width can be bigger that Short.MAX_VALUE! - width = Short.MAX_VALUE; + width = Short.MAX_VALUE; } sheet.setColumnWidth(column, (short) (width * 256)); } diff --git a/src/testcases/org/apache/poi/hssf/model/TestSheet.java b/src/testcases/org/apache/poi/hssf/model/TestSheet.java index 40b349a54..08dff3966 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestSheet.java +++ b/src/testcases/org/apache/poi/hssf/model/TestSheet.java @@ -40,7 +40,6 @@ import org.apache.poi.hssf.record.StringRecord; import org.apache.poi.hssf.record.UncalcedRecord; import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate; import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate; -import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate; import org.apache.poi.hssf.util.CellRangeAddress; /** @@ -62,7 +61,6 @@ public final class TestSheet extends TestCase { assertTrue( sheet.records.get(pos++) instanceof ColumnInfoRecordsAggregate ); assertTrue( sheet.records.get(pos++) instanceof DimensionsRecord ); assertTrue( sheet.records.get(pos++) instanceof RowRecordsAggregate ); - assertTrue( sheet.records.get(pos++) instanceof ValueRecordsAggregate ); assertTrue( sheet.records.get(pos++) instanceof EOFRecord ); } @@ -434,12 +432,12 @@ public final class TestSheet extends TestCase { throw new AssertionFailedError("Identified bug 45145"); } - // make sure that RRA and VRA are in the right place - int rraIx = sheet.getDimsLoc()+1; - List recs = sheet.getRecords(); - assertEquals(RowRecordsAggregate.class, recs.get(rraIx).getClass()); - assertEquals(ValueRecordsAggregate.class, recs.get(rraIx+1).getClass()); - + if (false) { + // make sure that RRA and VRA are in the right place + // (Aug 2008) since the VRA is now part of the RRA, there is much less chance that + // they could get out of order. Still, one could write serialize the sheet here, + // and read back with EventRecordFactory to make sure... + } assertEquals(242, dbCellRecordPos); } diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java index 5c14b70e1..2ae2eebc4 100755 --- a/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java +++ b/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java @@ -106,9 +106,7 @@ public class TestValueRecordsAggregate extends TestCase assertTrue( iterator.hasNext() ); } - public void testRemoveCell() - throws Exception - { + public void testRemoveCell() { BlankRecord blankRecord1 = newBlankRecord(); valueRecord.insertCell( blankRecord1 ); BlankRecord blankRecord2 = newBlankRecord(); @@ -118,10 +116,6 @@ public class TestValueRecordsAggregate extends TestCase // removing an already empty cell just falls through valueRecord.removeCell( blankRecord2 ); - - // even trying to remove null just falls through silently. - valueRecord.removeCell( null ); - } public void testGetPhysicalNumberOfCells() throws Exception @@ -204,22 +198,6 @@ public class TestValueRecordsAggregate extends TestCase return blankRecord; } - public void testGetRecordSize() throws Exception - { - List records = testData(); - valueRecord.construct( 0, records ); - assertEquals( 36, valueRecord.getRecordSize() ); - } - - public void testClone() throws Exception - { - List records = testData(); - valueRecord.construct( 0, records ); - valueRecord = (ValueRecordsAggregate) valueRecord.clone(); - assertEquals( 36, valueRecord.getRecordSize() ); - } - - /** * Sometimes the 'shared formula' flag (FormulaRecord.isSharedFormula()) is set when * there is no corresponding SharedFormulaRecord available. SharedFormulaRecord definitions do diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java index cc5784c50..6904e6e87 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java @@ -31,12 +31,10 @@ import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.model.Workbook; import org.apache.poi.hssf.record.CellValueRecordInterface; import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord; -import org.apache.poi.hssf.record.FormulaRecord; import org.apache.poi.hssf.record.NameRecord; import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; import org.apache.poi.hssf.record.formula.DeletedArea3DPtg; import org.apache.poi.hssf.util.CellRangeAddress; -import org.apache.poi.hssf.util.Region; import org.apache.poi.util.TempFile; /** @@ -991,8 +989,8 @@ public final class TestBugs extends TestCase { assertEquals("Forms.CheckBox.1", obj.getOLE2ClassName()); try { - obj.getDirectory(); - fail(); + obj.getDirectory(); + fail(); } catch(FileNotFoundException e) {} } @@ -1011,12 +1009,12 @@ public final class TestBugs extends TestCase { // DeletedArea3DPtg Workbook w = wb.getWorkbook(); for(int i=0; i 0; x=(short)(x*2)) { - r = s.createRow((short) x); + for (int x = 1; x < Short.MAX_VALUE && x > 0; x=(short)(x*2)) { + r = s.createRow(x); - for (short y = 1; y < 256 && y > 0; y++) { + for (int y = 1; y < 256 && y > 0; y++) { String ref=null; String ref2=null; @@ -296,13 +296,13 @@ public final class TestFormulas extends TestCase { refy2=(short)(y-3); } - c = r.getCell((short) y); + c = r.getCell(y); CellReference cr= new CellReference(refx1,refy1, false, false); ref=cr.formatAsString(); cr=new CellReference(refx2,refy2, false, false); ref2=cr.formatAsString(); - c = r.createCell((short) y); + c = r.createCell(y); c.setCellFormula("" + ref + operator + ref2); @@ -312,8 +312,8 @@ public final class TestFormulas extends TestCase { //make sure we do the maximum value of the Int operator if (s.getLastRowNum() < Short.MAX_VALUE) { - r = s.createRow((short)0); - c = r.createCell((short)0); + r = s.getRow(0); + c = r.createCell(0); c.setCellFormula("" + "B1" + operator + "IV255"); } @@ -453,16 +453,16 @@ public final class TestFormulas extends TestCase { HSSFCell c = null; //get our minimum values - r = s.createRow((short)0); - c = r.createCell((short)1); + r = s.createRow(0); + c = r.createCell(1); c.setCellFormula(1 + operator + 1); - for (short x = 1; x < Short.MAX_VALUE && x > 0; x=(short)(x*2)) { - r = s.createRow((short) x); + for (int x = 1; x < Short.MAX_VALUE && x > 0; x=(short)(x*2)) { + r = s.createRow(x); - for (short y = 1; y < 256 && y > 0; y++) { + for (int y = 1; y < 256 && y > 0; y++) { - c = r.createCell((short) y); + c = r.createCell(y); c.setCellFormula("" + x + operator + y); } @@ -470,8 +470,8 @@ public final class TestFormulas extends TestCase { //make sure we do the maximum value of the Int operator if (s.getLastRowNum() < Short.MAX_VALUE) { - r = s.createRow((short)0); - c = r.createCell((short)0); + r = s.getRow(0); + c = r.createCell(0); c.setCellFormula("" + Short.MAX_VALUE + operator + Short.MAX_VALUE); } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestWorkbook.java b/src/testcases/org/apache/poi/hssf/usermodel/TestWorkbook.java index 3851cab56..09b93cf87 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestWorkbook.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestWorkbook.java @@ -30,7 +30,7 @@ import org.apache.poi.hssf.model.Workbook; import org.apache.poi.hssf.record.BackupRecord; import org.apache.poi.hssf.record.LabelSSTRecord; import org.apache.poi.hssf.record.Record; -import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate; +import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate; import org.apache.poi.hssf.util.CellRangeAddress; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.util.TempFile; @@ -93,7 +93,7 @@ public final class TestWorkbook extends TestCase { + ((( double ) rownum / 1000) + (( double ) cellnum / 10000))); c = r.createCell(( short ) (cellnum + 1)); - c.setCellValue("TEST"); + c.setCellValue(new HSSFRichTextString("TEST")); } } wb.write(out); @@ -139,7 +139,7 @@ public final class TestWorkbook extends TestCase { + ((( double ) rownum / 1000) + (( double ) cellnum / 10000))); c = r.createCell(( short ) (cellnum + 1)); - c.setCellValue("TEST"); + c.setCellValue(new HSSFRichTextString("TEST")); } } for (short rownum = ( short ) 0; rownum < 25; rownum++) @@ -310,9 +310,9 @@ public final class TestWorkbook extends TestCase { HSSFSheet sheet = workbook.getSheetAt(0); HSSFCell cell = sheet.getRow(0).getCell(1); - cell.setCellValue(REPLACED); + cell.setCellValue(new HSSFRichTextString(REPLACED)); cell = sheet.getRow(1).getCell(0); - cell.setCellValue(REPLACED); + cell.setCellValue(new HSSFRichTextString(REPLACED)); workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); @@ -380,11 +380,11 @@ public final class TestWorkbook extends TestCase { HSSFSheet sheet = workbook.getSheetAt(0); HSSFCell cell = sheet.getRow(3).getCell(2); - cell.setCellValue(LAST_NAME_VALUE); + cell.setCellValue(new HSSFRichTextString(LAST_NAME_VALUE)); cell = sheet.getRow(4).getCell(2); - cell.setCellValue(FIRST_NAME_VALUE); + cell.setCellValue(new HSSFRichTextString(FIRST_NAME_VALUE)); cell = sheet.getRow(5).getCell(2); - cell.setCellValue(SSN_VALUE); + cell.setCellValue(new HSSFRichTextString(SSN_VALUE)); workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); sheet = workbook.getSheetAt(0); @@ -494,11 +494,11 @@ public final class TestWorkbook extends TestCase { cell = row.createCell(( short ) 2); // workbook.write(new FileOutputStream("/a2.xls")); - ValueRecordsAggregate valueAggregate = - ( ValueRecordsAggregate ) sheet.getSheet() - .findFirstRecordBySid(ValueRecordsAggregate.sid); + RowRecordsAggregate rra = (RowRecordsAggregate) + sheet.getSheet().findFirstRecordBySid((short)-1000); + int sstRecords = 0; - Iterator iterator = valueAggregate.getIterator(); + Iterator iterator = rra.getAllRecordsIterator(); while (iterator.hasNext()) { @@ -511,16 +511,11 @@ public final class TestWorkbook extends TestCase { } - public void testManyRows() - throws Exception - { - String testName = "TestManyRows"; - File file = TempFile.createTempFile(testName, ".xls"); - FileOutputStream out = new FileOutputStream(file); + public void testManyRows() { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet(); - HSSFRow row = null; - HSSFCell cell = null; + HSSFRow row; + HSSFCell cell; int i, j; for ( i = 0, j = 32771; j > 0; i++, j-- ) { @@ -528,22 +523,17 @@ public final class TestWorkbook extends TestCase { cell = row.createCell((short) 0); cell.setCellValue(i); } - workbook.write(out); - out.close(); sanityChecker.checkHSSFWorkbook(workbook); assertEquals("LAST ROW == 32770", 32770, sheet.getLastRowNum()); + cell = sheet.getRow(32770).getCell(0); double lastVal = cell.getNumericCellValue(); - FileInputStream in = new FileInputStream(file); - POIFSFileSystem fs = new POIFSFileSystem(in); - HSSFWorkbook wb = new HSSFWorkbook(fs); + HSSFWorkbook wb = HSSFTestDataSamples.writeOutAndReadBack(workbook); HSSFSheet s = wb.getSheetAt(0); row = s.getRow(32770); - cell = row.getCell(( short ) 0); + cell = row.getCell(0); assertEquals("Value from last row == 32770", lastVal, cell.getNumericCellValue(), 0); assertEquals("LAST ROW == 32770", 32770, s.getLastRowNum()); - in.close(); - file.deleteOnExit(); } /** @@ -570,10 +560,4 @@ public final class TestWorkbook extends TestCase { assertTrue("file exists",file.exists()); } - - - public static void main(String [] ignored_args) - { - junit.textui.TestRunner.run(TestWorkbook.class); - } }