Consolidating ValueRecordsAggregate within RowRecordsAggregate

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@683758 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2008-08-07 23:49:10 +00:00
parent 7f985ab0aa
commit ea84181642
12 changed files with 754 additions and 1001 deletions

View File

@ -66,7 +66,6 @@ import org.apache.poi.hssf.record.SCLRecord;
import org.apache.poi.hssf.record.SaveRecalcRecord; import org.apache.poi.hssf.record.SaveRecalcRecord;
import org.apache.poi.hssf.record.ScenarioProtectRecord; import org.apache.poi.hssf.record.ScenarioProtectRecord;
import org.apache.poi.hssf.record.SelectionRecord; 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.StringRecord;
import org.apache.poi.hssf.record.TopMarginRecord; import org.apache.poi.hssf.record.TopMarginRecord;
import org.apache.poi.hssf.record.UncalcedRecord; 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.MergedCellsTable;
import org.apache.poi.hssf.record.aggregates.RecordAggregate; import org.apache.poi.hssf.record.aggregates.RecordAggregate;
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate; 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.record.aggregates.RecordAggregate.RecordVisitor;
import org.apache.poi.hssf.util.CellRangeAddress; import org.apache.poi.hssf.util.CellRangeAddress;
import org.apache.poi.hssf.util.PaneInformation; import org.apache.poi.hssf.util.PaneInformation;
@ -121,13 +119,12 @@ public final class Sheet implements Model {
protected ArrayList records = null; protected ArrayList records = null;
int preoffset = 0; // offset of the sheet in a new file 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 int dimsloc = -1; // TODO - is it legal for dims record to be missing?
protected DimensionsRecord dims; protected DimensionsRecord dims;
protected DefaultColWidthRecord defaultcolwidth = null; protected DefaultColWidthRecord defaultcolwidth = null;
protected DefaultRowHeightRecord defaultrowheight = null; protected DefaultRowHeightRecord defaultrowheight = null;
protected GridsetRecord gridset = null; protected GridsetRecord gridset = null;
private GutsRecord _gutsRecord; private GutsRecord _gutsRecord;
protected PrintSetupRecord printSetup = null; protected PrintSetupRecord printSetup = null;
protected HeaderRecord header = null; protected HeaderRecord header = null;
protected FooterRecord footer = null; protected FooterRecord footer = null;
@ -138,9 +135,7 @@ public final class Sheet implements Model {
protected SelectionRecord selection = null; protected SelectionRecord selection = null;
/** always present in this POI object, not always written to Excel file */ /** always present in this POI object, not always written to Excel file */
/*package*/ColumnInfoRecordsAggregate _columnInfos; /*package*/ColumnInfoRecordsAggregate _columnInfos;
protected ValueRecordsAggregate cells = null;
protected RowRecordsAggregate _rowsAggregate = null; protected RowRecordsAggregate _rowsAggregate = null;
private Iterator valueRecIterator = null;
private Iterator rowRecIterator = null; private Iterator rowRecIterator = null;
protected int eofLoc = 0; protected int eofLoc = 0;
protected ProtectRecord protect = null; protected ProtectRecord protect = null;
@ -196,17 +191,8 @@ public final class Sheet implements Model {
boolean isfirstcell = true; boolean isfirstcell = true;
int bofEofNestingLevel = 0; 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); Record rec = ( Record ) recs.get(k);
if (rec.isValue() != (rec instanceof CellValueRecordInterface)) {
if (rec instanceof SharedFormulaRecord) {
} else {
"".length();
}
}
if ( rec.getSid() == DBCellRecord.sid ) { if ( rec.getSid() == DBCellRecord.sid ) {
continue; continue;
} }
@ -239,18 +225,31 @@ public final class Sheet implements Model {
retval._dataValidityTable = new DataValidityTable(rs); retval._dataValidityTable = new DataValidityTable(rs);
k += rs.getCountRead() - 1; // TODO - convert this method result to be zero based k += rs.getCountRead() - 1; // TODO - convert this method result to be zero based
records.add(retval._dataValidityTable); 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; RowRecord row = (RowRecord)rec;
if (retval._rowsAggregate == null) { if (retval._rowsAggregate == null) {
retval._rowsAggregate = new RowRecordsAggregate(); retval._rowsAggregate = new RowRecordsAggregate();
records.add(retval._rowsAggregate); //only add the aggregate once records.add(retval._rowsAggregate); //only add the aggregate once
} }
retval._rowsAggregate.insertRow(row); retval._rowsAggregate.insertRow(row);
continue; 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) { if (rec.getSid() == MergeCellsRecord.sid) {
RecordStream rs = new RecordStream(recs, k); RecordStream rs = new RecordStream(recs, k);
retval._mergedCellsTable = new MergedCellsTable(rs); retval._mergedCellsTable = new MergedCellsTable(rs);
@ -290,21 +289,7 @@ public final class Sheet implements Model {
retval.dims = ( DimensionsRecord ) rec; retval.dims = ( DimensionsRecord ) rec;
retval.dimsloc = records.size(); retval.dimsloc = records.size();
} }
else if ( rec.isValue() && bofEofNestingLevel == 1 ) else if (rec.getSid() == DefaultColWidthRecord.sid)
{
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)
{ {
retval.defaultcolwidth = ( DefaultColWidthRecord ) rec; retval.defaultcolwidth = ( DefaultColWidthRecord ) rec;
} }
@ -381,17 +366,13 @@ public final class Sheet implements Model {
retval._columnBreaksRecord = (VerticalPageBreakRecord)rec; retval._columnBreaksRecord = (VerticalPageBreakRecord)rec;
} }
if (rec != null) records.add(rec);
{
records.add(rec);
}
} }
if (retval.dimsloc < 0) { if (retval.dimsloc < 0) {
throw new RuntimeException("DimensionsRecord was not found"); throw new RuntimeException("DimensionsRecord was not found");
} }
retval.records = records; retval.records = records;
retval.checkRows(); retval.checkRows();
retval.checkCells();
if (log.check( POILogger.DEBUG )) if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited"); log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited");
return retval; return retval;
@ -399,14 +380,14 @@ public final class Sheet implements Model {
private static final class RecordCloner implements RecordVisitor { private static final class RecordCloner implements RecordVisitor {
private final List _destList; private final List _destList;
public RecordCloner(List destList) { public RecordCloner(List destList) {
_destList = destList; _destList = destList;
} }
public void visitRecord(Record r) { public void visitRecord(Record r) {
_destList.add(r.clone()); _destList.add(r.clone());
} }
} }
/** /**
* Clones the low level records of this sheet and returns the new sheet instance. * 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<this.records.size();i++) { for (int i=0; i<this.records.size();i++) {
RecordBase rb = (RecordBase) this.records.get(i); RecordBase rb = (RecordBase) this.records.get(i);
if (rb instanceof RecordAggregate) { if (rb instanceof RecordAggregate) {
((RecordAggregate)rb).visitContainedRecords(new RecordCloner(clonedRecords)); ((RecordAggregate)rb).visitContainedRecords(new RecordCloner(clonedRecords));
// TODO - make sure this logic works for the other RecordAggregates // TODO - make sure this logic works for the other RecordAggregates
continue; continue;
} }
Record rec = (Record)((Record)rb).clone(); Record rec = (Record)((Record)rb).clone();
//Need to pull out the Row record and the Value records from their //Need to pull out the Row record and the Value records from their
//Aggregates. //Aggregates.
//This is probably the best way to do it since we probably dont want the createSheet //This is probably the best way to do it since we probably dont want the createSheet
//To cater for these artificial Record types //To cater for these artificial Record types
if (rec instanceof RowRecordsAggregate) { if (rec instanceof RowRecordsAggregate) {
RowRecordsAggregate rrAgg = (RowRecordsAggregate)rec; RowRecordsAggregate rrAgg = (RowRecordsAggregate)rec;
for (Iterator rowIter = rrAgg.getIterator();rowIter.hasNext();) { for (Iterator rowIter = rrAgg.getAllRecordsIterator();rowIter.hasNext();) {
Record rowRec = (Record)rowIter.next(); Record valRec = (Record)rowIter.next();
clonedRecords.add(rowRec);
}
} else if (rec instanceof ValueRecordsAggregate) {
ValueRecordsAggregate vrAgg = (ValueRecordsAggregate)rec;
for (Iterator cellIter = vrAgg.getIterator();cellIter.hasNext();) {
Record valRec = (Record)cellIter.next();
if (valRec instanceof FormulaRecordAggregate) { if (valRec instanceof FormulaRecordAggregate) {
FormulaRecordAggregate fmAgg = (FormulaRecordAggregate)valRec; FormulaRecordAggregate fmAgg = (FormulaRecordAggregate)valRec;
Record fmAggRec = fmAgg.getFormulaRecord(); Record fmAggRec = fmAgg.getFormulaRecord();
if (fmAggRec != null) if (fmAggRec != null) {
clonedRecords.add(fmAggRec); clonedRecords.add(fmAggRec);
}
fmAggRec = fmAgg.getStringRecord(); fmAggRec = fmAgg.getStringRecord();
if (fmAggRec != null) if (fmAggRec != null) {
clonedRecords.add(fmAggRec); clonedRecords.add(fmAggRec);
}
} else { } else {
clonedRecords.add(valRec); clonedRecords.add(valRec);
} }
@ -547,7 +524,6 @@ public final class Sheet implements Model {
records.add(retval.dims); records.add(retval.dims);
retval.dimsloc = records.size()-1; retval.dimsloc = records.size()-1;
records.add(retval.windowTwo = retval.createWindowTwo()); records.add(retval.windowTwo = retval.createWindowTwo());
retval.setLoc(records.size() - 1);
retval.selection = createSelection(); retval.selection = createSelection();
records.add(retval.selection); records.add(retval.selection);
records.add(EOFRecord.instance); records.add(EOFRecord.instance);
@ -559,23 +535,6 @@ public final class Sheet implements Model {
return retval; return retval;
} }
private void checkCells()
{
if (cells == null)
{
cells = new ValueRecordsAggregate();
// In the worksheet stream, the row records always occur before the cell (value)
// records. Therefore POI's aggregates (RowRecordsAggregate, ValueRecordsAggregate)
// should follow suit. Some methods in this class tolerate either order, while
// others have been found to fail (see bug 45145).
int rraIndex = getDimsLoc() + 1;
if (records.get(rraIndex).getClass() != RowRecordsAggregate.class) {
throw new IllegalStateException("Cannot create value records before row records exist");
}
records.add(rraIndex+1, cells);
}
}
private void checkRows() private void checkRows()
{ {
if (_rowsAggregate == null) if (_rowsAggregate == null)
@ -585,16 +544,16 @@ public final class Sheet implements Model {
} }
} }
private MergedCellsTable getMergedRecords() { private MergedCellsTable getMergedRecords() {
if (_mergedCellsTable == null) { if (_mergedCellsTable == null) {
MergedCellsTable mct = new MergedCellsTable(); MergedCellsTable mct = new MergedCellsTable();
RecordOrderer.addNewSheetRecord(records, mct); RecordOrderer.addNewSheetRecord(records, mct);
_mergedCellsTable = mct; _mergedCellsTable = mct;
} }
return _mergedCellsTable; return _mergedCellsTable;
} }
public int addMergedRegion(int rowFrom, int colFrom, int rowTo, int colTo) { public int addMergedRegion(int rowFrom, int colFrom, int rowTo, int colTo) {
// Validate input // Validate input
if (rowTo < rowFrom) { if (rowTo < rowFrom) {
throw new IllegalArgumentException("The 'to' row (" + rowTo throw new IllegalArgumentException("The 'to' row (" + rowTo
@ -606,7 +565,7 @@ public final class Sheet implements Model {
} }
MergedCellsTable mrt = getMergedRecords(); MergedCellsTable mrt = getMergedRecords();
mrt.addArea(rowFrom, colFrom, rowTo, colTo); mrt.addArea(rowFrom, colFrom, rowTo, colTo);
return mrt.getNumberOfMergedRegions()-1; return mrt.getNumberOfMergedRegions()-1;
} }
@ -614,76 +573,50 @@ public final class Sheet implements Model {
{ {
//safety checks //safety checks
MergedCellsTable mrt = getMergedRecords(); MergedCellsTable mrt = getMergedRecords();
if (index >= mrt.getNumberOfMergedRegions()) { if (index >= mrt.getNumberOfMergedRegions()) {
return; return;
} }
mrt.remove(index); mrt.remove(index);
} }
public CellRangeAddress getMergedRegionAt(int index) { public CellRangeAddress getMergedRegionAt(int index) {
//safety checks //safety checks
MergedCellsTable mrt = getMergedRecords(); MergedCellsTable mrt = getMergedRecords();
if (index >= mrt.getNumberOfMergedRegions()) { if (index >= mrt.getNumberOfMergedRegions()) {
return null; return null;
} }
return mrt.get(index); return mrt.get(index);
} }
public int getNumMergedRegions() { public int getNumMergedRegions() {
return getMergedRecords().getNumberOfMergedRegions(); return getMergedRecords().getNumberOfMergedRegions();
} }
private ConditionalFormattingTable getConditionalFormattingTable() { private ConditionalFormattingTable getConditionalFormattingTable() {
if (condFormatting == null) { if (condFormatting == null) {
condFormatting = new ConditionalFormattingTable(); condFormatting = new ConditionalFormattingTable();
RecordOrderer.addNewSheetRecord(records, condFormatting); RecordOrderer.addNewSheetRecord(records, condFormatting);
} }
return condFormatting; return condFormatting;
} }
public int addConditionalFormatting(CFRecordsAggregate cfAggregate) { public int addConditionalFormatting(CFRecordsAggregate cfAggregate) {
ConditionalFormattingTable cft = getConditionalFormattingTable(); ConditionalFormattingTable cft = getConditionalFormattingTable();
return cft.add(cfAggregate); return cft.add(cfAggregate);
} }
public void removeConditionalFormatting(int index) { public void removeConditionalFormatting(int index) {
getConditionalFormattingTable().remove(index); getConditionalFormattingTable().remove(index);
} }
public CFRecordsAggregate getCFRecordsAggregateAt(int index) { public CFRecordsAggregate getCFRecordsAggregateAt(int index) {
return getConditionalFormattingTable().get(index); return getConditionalFormattingTable().get(index);
} }
public int getNumConditionalFormattings() { public int getNumConditionalFormattings() {
return getConditionalFormattingTable().size(); 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 * 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 * 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"); 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 * Set the preoffset when using DBCELL records (currently unused) - this is
* the position of this sheet within the whole file. * 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++) 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 // Don't write out UncalcedRecord entries, as
// we handle those specially just below // 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 // Once the rows have been found in the list of records, start
// writing out the blocked row information. This includes the DBCell references // writing out the blocked row information. This includes the DBCell references
if (record instanceof RowRecordsAggregate) { pos += record.serialize(pos, data);
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 );
}
// If the BOF record was just serialized then add the IndexRecord // If the BOF record was just serialized then add the IndexRecord
if (record instanceof BOFRecord) { 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 * @param indexRecordOffset also happens to be the end of the BOF record
* @return the size of the serialized INDEX record * @return the size of the serialized INDEX record
*/ */
private int serializeIndexRecord(final int bofRecordIndex, final int indexRecordOffset, private int serializeIndexRecord(int bofRecordIndex, int indexRecordOffset, byte[] data) {
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...
// 'initial sheet records' are between INDEX and first ROW record. // 'initial sheet records' are between INDEX and first ROW record.
int sizeOfInitialSheetRecords = 0; int sizeOfInitialSheetRecords = 0;
@ -862,32 +747,7 @@ public final class Sheet implements Model {
if (_isUncalced) { if (_isUncalced) {
sizeOfInitialSheetRecords += UncalcedRecord.getStaticRecordSize(); sizeOfInitialSheetRecords += UncalcedRecord.getStaticRecordSize();
} }
IndexRecord index = _rowsAggregate.createIndexRecord(indexRecordOffset, sizeOfInitialSheetRecords);
// 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));
}
return index.serialize(indexRecordOffset, data); 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 row the row to add the cell value to
* @param col the cell value record itself. * @param col the cell value record itself.
*/ */
public void addValueRecord(int row, CellValueRecordInterface col) public void addValueRecord(int row, CellValueRecordInterface col) {
{
checkCells(); if(log.check(POILogger.DEBUG)) {
if(log.check(POILogger.DEBUG)) log.log(POILogger.DEBUG, "add value record row" + row);
{
log.logFormatted(POILogger.DEBUG, "add value record row,loc %,%", new int[]
{
row, loc
});
} }
DimensionsRecord d = ( DimensionsRecord ) records.get(getDimsLoc()); DimensionsRecord d = ( DimensionsRecord ) records.get(getDimsLoc());
@ -931,7 +786,7 @@ public final class Sheet implements Model {
{ {
d.setFirstCol(col.getColumn()); 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. * @param col - a record supporting the CellValueRecordInterface.
* @see org.apache.poi.hssf.record.CellValueRecordInterface * @see org.apache.poi.hssf.record.CellValueRecordInterface
*/ */
public void removeValueRecord(int row, CellValueRecordInterface col) public void removeValueRecord(int row, CellValueRecordInterface col) {
{
checkCells();
log.logFormatted(POILogger.DEBUG, "remove value record row,dimsloc %,%", log.logFormatted(POILogger.DEBUG, "remove value record row,dimsloc %,%",
new int[]{row, dimsloc} ); new int[]{row, dimsloc} );
loc = dimsloc; _rowsAggregate.removeCell(col);
cells.removeCell(col);
} }
/** /**
@ -962,10 +815,8 @@ public final class Sheet implements Model {
* be added. * be added.
*/ */
public void replaceValueRecord(CellValueRecordInterface newval) public void replaceValueRecord(CellValueRecordInterface newval) {
{
checkCells();
setLoc(dimsloc);
if (log.check( POILogger.DEBUG )) if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "replaceValueRecord "); log.log(POILogger.DEBUG, "replaceValueRecord ");
//The ValueRecordsAggregate use a tree map underneath. //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 //key and the value, if we dont do a remove, then
//the previous instance of the key is retained, effectively using //the previous instance of the key is retained, effectively using
//double the memory //double the memory
cells.removeCell(newval); _rowsAggregate.removeCell(newval);
cells.insertCell(newval); _rowsAggregate.insertCell(newval);
} }
/** /**
@ -1024,12 +875,8 @@ public final class Sheet implements Model {
* *
* @param row the row record to remove * @param row the row record to remove
*/ */
public void removeRow(RowRecord row) {
public void removeRow(RowRecord row)
{
checkRows(); checkRows();
setLoc(getDimsLoc());
_rowsAggregate.removeRow(row); _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 * @return CellValueRecordInterface representing the next value record or NULL if there are no more
* @see #setLoc(int) * @see #setLoc(int)
*/ */
public CellValueRecordInterface[] getValueRecords() {
public CellValueRecordInterface getNextValueRecord() return _rowsAggregate.getValueRecords();
{
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();
} }
/** /**
@ -1077,11 +912,7 @@ public final class Sheet implements Model {
* @see #setLoc(int) * @see #setLoc(int)
* *
*/ */
public RowRecord getNextRow() {
public RowRecord getNextRow()
{
if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "getNextRow loc= " + loc);
if (rowRecIterator == null) if (rowRecIterator == null)
{ {
rowRecIterator = _rowsAggregate.getIterator(); rowRecIterator = _rowsAggregate.getIterator();
@ -1110,8 +941,6 @@ public final class Sheet implements Model {
* *
*/ */
public RowRecord getRow(int rownum) { public RowRecord getRow(int rownum) {
if (log.check( POILogger.DEBUG ))
log.log(POILogger.DEBUG, "getNextRow loc= " + loc);
return _rowsAggregate.getRow(rownum); return _rowsAggregate.getRow(rownum);
} }
@ -1235,13 +1064,13 @@ public final class Sheet implements Model {
return retval; return retval;
} }
private GutsRecord getGutsRecord() { private GutsRecord getGutsRecord() {
if (_gutsRecord == null) { if (_gutsRecord == null) {
GutsRecord result = createGuts(); GutsRecord result = createGuts();
RecordOrderer.addNewSheetRecord(records, result); RecordOrderer.addNewSheetRecord(records, result);
_gutsRecord = result; _gutsRecord = result;
} }
return _gutsRecord; return _gutsRecord;
} }
/** /**
@ -1418,7 +1247,7 @@ public final class Sheet implements Model {
ColumnInfoRecord ci = _columnInfos.findColumnInfo(columnIndex); ColumnInfoRecord ci = _columnInfos.findColumnInfo(columnIndex);
if (ci != null) { if (ci != null) {
return ci.getColumnWidth(); return ci.getColumnWidth();
} }
//default column width is measured in characters //default column width is measured in characters
//multiply //multiply
@ -1443,18 +1272,18 @@ public final class Sheet implements Model {
ColumnInfoRecord ci = _columnInfos.findColumnInfo(columnIndex); ColumnInfoRecord ci = _columnInfos.findColumnInfo(columnIndex);
if (ci != null) { if (ci != null) {
return ci.getXFIndex(); return ci.getXFIndex();
} }
return 0xF; return 0xF;
} }
/** /**
* set the width for a given column in 1/256th of a character width units * set the width for a given column in 1/256th of a character width units
* *
* @param column - * @param column -
* the column number * the column number
* @param width * @param width
* (in units of 1/256th of a character width) * (in units of 1/256th of a character width)
*/ */
public void setColumnWidth(short column, short width) { public void setColumnWidth(short column, short width) {
setColumn( column, new Short(width), null, null, null); 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. * @return whether the column is hidden or not.
*/ */
public boolean isColumnHidden(short columnIndex) { public boolean isColumnHidden(short columnIndex) {
ColumnInfoRecord cir = _columnInfos.findColumnInfo(columnIndex); ColumnInfoRecord cir = _columnInfos.findColumnInfo(columnIndex);
if (cir == null) { if (cir == null) {
return false; return false;
} }
return cir.getHidden(); 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 * in the event the record is a dimensions record, resets both the loc index and dimsloc index
*/ */
public void checkDimsLoc(Record rec, int recloc) {
public void checkDimsLoc(Record rec, int recloc) if (rec.getSid() == DimensionsRecord.sid) {
{
if (rec.getSid() == DimensionsRecord.sid)
{
loc = recloc;
dimsloc = recloc; dimsloc = recloc;
} }
} }
@ -1672,33 +1497,17 @@ public final class Sheet implements Model {
/** /**
* @return the serialized size of this sheet * @return the serialized size of this sheet
*/ */
public int getSize() public int getSize() {
{
int retval = 0; int retval = 0;
for ( int k = 0; k < records.size(); k++) { for ( int k = 0; k < records.size(); k++) {
RecordBase record = (RecordBase) records.get(k); RecordBase record = (RecordBase) records.get(k);
if (record instanceof UncalcedRecord) { if (record instanceof UncalcedRecord) {
// skip the UncalcedRecord if present, it's only encoded if the isUncalced flag is set // skip the UncalcedRecord if present, it's only encoded if the isUncalced flag is set
continue; continue;
} }
retval += record.getRecordSize(); 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 // Add space for UncalcedRecord
if (_isUncalced) { if (_isUncalced) {
retval += UncalcedRecord.getStaticRecordSize(); retval += UncalcedRecord.getStaticRecordSize();
@ -1726,11 +1535,11 @@ public final class Sheet implements Model {
public Record findFirstRecordBySid(short sid) public Record findFirstRecordBySid(short sid)
{ {
int ix = findFirstRecordLocBySid(sid); int ix = findFirstRecordLocBySid(sid);
if (ix < 0) { if (ix < 0) {
return null; return null;
} }
return (Record) records.get(ix); return (Record) records.get(ix);
} }
/** /**
@ -1765,9 +1574,9 @@ public final class Sheet implements Model {
public int findFirstRecordLocBySid( short sid ) { // TODO - remove this method public int findFirstRecordLocBySid( short sid ) { // TODO - remove this method
int max = records.size(); int max = records.size();
for (int i=0; i< max; i++) { for (int i=0; i< max; i++) {
Object rb = records.get(i); Object rb = records.get(i);
if (!(rb instanceof Record)) { if (!(rb instanceof Record)) {
continue; continue;
} }
Record record = (Record) rb; Record record = (Record) rb;
if (record.getSid() == sid) { if (record.getSid() == sid) {
@ -2095,8 +1904,8 @@ public final class Sheet implements Model {
*/ */
private static PasswordRecord createPassword() { private static PasswordRecord createPassword() {
if (log.check( POILogger.DEBUG )) { 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(); PasswordRecord retval = new PasswordRecord();
retval.setPassword((short)00); retval.setPassword((short)00);
@ -2276,21 +2085,21 @@ public final class Sheet implements Model {
} }
private PageBreakRecord getRowBreaksRecord() { private PageBreakRecord getRowBreaksRecord() {
if (_rowBreaksRecord == null) { if (_rowBreaksRecord == null) {
_rowBreaksRecord = new HorizontalPageBreakRecord(); _rowBreaksRecord = new HorizontalPageBreakRecord();
RecordOrderer.addNewSheetRecord(records, _rowBreaksRecord); RecordOrderer.addNewSheetRecord(records, _rowBreaksRecord);
dimsloc++; dimsloc++;
} }
return _rowBreaksRecord; return _rowBreaksRecord;
} }
private PageBreakRecord getColumnBreaksRecord() { private PageBreakRecord getColumnBreaksRecord() {
if (_columnBreaksRecord == null) { if (_columnBreaksRecord == null) {
_columnBreaksRecord = new VerticalPageBreakRecord(); _columnBreaksRecord = new VerticalPageBreakRecord();
RecordOrderer.addNewSheetRecord(records, _columnBreaksRecord); RecordOrderer.addNewSheetRecord(records, _columnBreaksRecord);
dimsloc++; dimsloc++;
} }
return _columnBreaksRecord; return _columnBreaksRecord;
} }
@ -2334,7 +2143,7 @@ public final class Sheet implements Model {
* *
*/ */
public void removeColumnBreak(short column) { public void removeColumnBreak(short column) {
getColumnBreaksRecord().removeBreak(column); getColumnBreaksRecord().removeBreak(column);
} }
/** /**
@ -2520,8 +2329,8 @@ public final class Sheet implements Model {
} }
public DataValidityTable getOrCreateDataValidityTable() { public DataValidityTable getOrCreateDataValidityTable() {
if (_dataValidityTable == null) { if (_dataValidityTable == null) {
DataValidityTable result = new DataValidityTable(); DataValidityTable result = new DataValidityTable();
RecordOrderer.addNewSheetRecord(records, result); RecordOrderer.addNewSheetRecord(records, result);
_dataValidityTable = result; _dataValidityTable = result;
} }
return _dataValidityTable; return _dataValidityTable;

View File

@ -22,15 +22,17 @@ import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
/** /**
* Title: Row Record<P> * Title: Row Record (0x0208)<P/>
* Description: stores the row information for the sheet. <P> * Description: stores the row information for the sheet. <P/>
* REFERENCE: PG 379 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P> * REFERENCE: PG 379 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
* @author Andrew C. Oliver (acoliver at apache dot org) * @author Andrew C. Oliver (acoliver at apache dot org)
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
* @version 2.0-pre * @version 2.0-pre
*/ */
public final class RowRecord extends Record implements Comparable { 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 OPTION_BITS_ALWAYS_SET = 0x0100;
private static final int DEFAULT_HEIGHT_BIT = 0x8000; 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) public int serialize(int offset, byte [] data)
{ {
LittleEndian.putShort(data, 0 + offset, sid); LittleEndian.putUShort(data, 0 + offset, sid);
LittleEndian.putShort(data, 2 + offset, ( short ) 16); LittleEndian.putUShort(data, 2 + offset, ENCODED_SIZE - 4);
LittleEndian.putShort(data, 4 + offset, ( short ) getRowNumber()); LittleEndian.putUShort(data, 4 + offset, getRowNumber());
LittleEndian.putShort(data, 6 + offset, getFirstCol() == -1 ? (short)0 : getFirstCol()); LittleEndian.putUShort(data, 6 + offset, getFirstCol() == -1 ? (short)0 : getFirstCol());
LittleEndian.putShort(data, 8 + offset, getLastCol() == -1 ? (short)0 : getLastCol()); LittleEndian.putUShort(data, 8 + offset, getLastCol() == -1 ? (short)0 : getLastCol());
LittleEndian.putShort(data, 10 + offset, getHeight()); LittleEndian.putUShort(data, 10 + offset, getHeight());
LittleEndian.putShort(data, 12 + offset, getOptimize()); LittleEndian.putUShort(data, 12 + offset, getOptimize());
LittleEndian.putShort(data, 14 + offset, field_6_reserved); LittleEndian.putUShort(data, 14 + offset, field_6_reserved);
LittleEndian.putShort(data, 16 + offset, getOptionFlags()); LittleEndian.putUShort(data, 16 + offset, getOptionFlags());
LittleEndian.putShort(data, 18 + offset, getXFIndex()); LittleEndian.putUShort(data, 18 + offset, getXFIndex());
return getRecordSize(); return ENCODED_SIZE;
} }
public int getRecordSize() public int getRecordSize()
{ {
return 20; return ENCODED_SIZE;
} }
public short getSid() public short getSid()

View File

@ -1,4 +1,3 @@
/* ==================================================================== /* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
@ -16,85 +15,90 @@
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
package org.apache.poi.hssf.record.aggregates; package org.apache.poi.hssf.record.aggregates;
import org.apache.poi.hssf.record.DBCellRecord; import java.util.ArrayList;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.RowRecord;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; 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 andy
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
*/ */
public final class RowRecordsAggregate extends Record { public final class RowRecordsAggregate extends Record {
private int firstrow = -1; private int _firstrow = -1;
private int lastrow = -1; private int _lastrow = -1;
private Map records = null; // TODO - use a proper key in this map private final Map _rowRecords;
private int size = 0; private final ValueRecordsAggregate _valuesAgg;
/** Creates a new instance of ValueRecordsAggregate */ /** Creates a new instance of ValueRecordsAggregate */
public RowRecordsAggregate() public RowRecordsAggregate() {
{ this(new TreeMap(), new ValueRecordsAggregate());
records = new TreeMap(); }
private RowRecordsAggregate(TreeMap rowRecords, ValueRecordsAggregate valuesAgg) {
_rowRecords = rowRecords;
_valuesAgg = valuesAgg;
} }
public void insertRow(RowRecord row) public void insertRow(RowRecord row) {
{
size += row.getRecordSize();
// Integer integer = new Integer(row.getRowNumber()); // Integer integer = new Integer(row.getRowNumber());
records.put(row, row); _rowRecords.put(new Integer(row.getRowNumber()), row);
if ((row.getRowNumber() < firstrow) || (firstrow == -1)) 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) public void removeRow(RowRecord row) {
{ int rowIndex = row.getRowNumber();
size -= row.getRecordSize(); _valuesAgg.removeAllCellsValuesForRow(rowIndex);
Integer key = new Integer(rowIndex);
// Integer integer = new Integer(row.getRowNumber()); RowRecord rr = (RowRecord) _rowRecords.remove(key);
records.remove(row); 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) { public RowRecord getRow(int rowIndex) {
// Row must be between 0 and 65535 if (rowIndex < 0 || rowIndex > 65535) {
if(rownum < 0 || rownum > 65535) {
throw new IllegalArgumentException("The row number must be between 0 and 65535"); throw new IllegalArgumentException("The row number must be between 0 and 65535");
} }
return (RowRecord) _rowRecords.get(new Integer(rowIndex));
RowRecord row = new RowRecord(rownum);
return ( RowRecord ) records.get(row);
} }
public int getPhysicalNumberOfRows() public int getPhysicalNumberOfRows()
{ {
return records.size(); return _rowRecords.size();
} }
public int getFirstRowNum() public int getFirstRowNum()
{ {
return firstrow; return _firstrow;
} }
public int getLastRowNum() public int getLastRowNum()
{ {
return lastrow; return _lastrow;
} }
/** Returns the number of row blocks. /** Returns the number of row blocks.
@ -102,54 +106,60 @@ public final class RowRecordsAggregate extends Record {
* after them * after them
*/ */
public int getRowBlockCount() { public int getRowBlockCount() {
int size = records.size()/DBCellRecord.BLOCK_SIZE; int size = _rowRecords.size()/DBCellRecord.BLOCK_SIZE;
if ((records.size() % DBCellRecord.BLOCK_SIZE) != 0) if ((_rowRecords.size() % DBCellRecord.BLOCK_SIZE) != 0)
size++; size++;
return size; return size;
} }
public int getRowBlockSize(int block) { private int getRowBlockSize(int block) {
return 20 * getRowCountForBlock(block); return RowRecord.ENCODED_SIZE * getRowCountForBlock(block);
} }
/** Returns the number of physical rows within a block*/ /** Returns the number of physical rows within a block*/
public int getRowCountForBlock(int block) { public int getRowCountForBlock(int block) {
int startIndex = block * DBCellRecord.BLOCK_SIZE; int startIndex = block * DBCellRecord.BLOCK_SIZE;
int endIndex = startIndex + DBCellRecord.BLOCK_SIZE - 1; int endIndex = startIndex + DBCellRecord.BLOCK_SIZE - 1;
if (endIndex >= records.size()) if (endIndex >= _rowRecords.size())
endIndex = records.size()-1; endIndex = _rowRecords.size()-1;
return endIndex-startIndex+1; return endIndex-startIndex+1;
} }
/** Returns the physical row number of the first row in a block*/ /** 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, //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 //an iterator and use that instance throughout, rather than recreating one and
//having to move it to the right position. //having to move it to the right position.
int startIndex = block * DBCellRecord.BLOCK_SIZE; int startIndex = block * DBCellRecord.BLOCK_SIZE;
Iterator rowIter = records.values().iterator(); Iterator rowIter = _rowRecords.values().iterator();
RowRecord row = null; RowRecord row = null;
//Position the iterator at the start of the block //Position the iterator at the start of the block
for (int i=0; i<=startIndex;i++) { for (int i=0; i<=startIndex;i++) {
row = (RowRecord)rowIter.next(); row = (RowRecord)rowIter.next();
} }
if (row == null) {
throw new RuntimeException("Did not find start row for block " + block);
}
return row.getRowNumber(); return row.getRowNumber();
} }
/** Returns the physical row number of the end row in a block*/ /** 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; int endIndex = ((block + 1)*DBCellRecord.BLOCK_SIZE)-1;
if (endIndex >= records.size()) if (endIndex >= _rowRecords.size())
endIndex = records.size()-1; endIndex = _rowRecords.size()-1;
Iterator rowIter = records.values().iterator(); Iterator rowIter = _rowRecords.values().iterator();
RowRecord row = null; RowRecord row = null;
for (int i=0; i<=endIndex;i++) { for (int i=0; i<=endIndex;i++) {
row = (RowRecord)rowIter.next(); row = (RowRecord)rowIter.next();
} }
if (row == null) {
throw new RuntimeException("Did not find start row for block " + block);
}
return row.getRowNumber(); return row.getRowNumber();
} }
@ -159,7 +169,7 @@ public final class RowRecordsAggregate extends Record {
final int startIndex = block*DBCellRecord.BLOCK_SIZE; final int startIndex = block*DBCellRecord.BLOCK_SIZE;
final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE; final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE;
Iterator rowIterator = records.values().iterator(); Iterator rowIterator = _rowRecords.values().iterator();
int pos = offset; int pos = offset;
//Given that we basically iterate through the rows in order, //Given that we basically iterate through the rows in order,
@ -175,10 +185,6 @@ public final class RowRecordsAggregate extends Record {
} }
return pos - offset; 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 * @param data byte array containing instance data
* @return number of bytes written * @return number of bytes written
*/ */
public int serialize(int offset, byte [] data) {
public int serialize(int offset, byte [] data, ValueRecordsAggregate cells) ValueRecordsAggregate cells = _valuesAgg;
{
int pos = offset; int pos = offset;
//DBCells are serialized before row records. //DBCells are serialized before row records.
@ -209,7 +214,7 @@ public final class RowRecordsAggregate extends Record {
final int endRowNumber = getEndRowNumberForBlock(block); final int endRowNumber = getEndRowNumberForBlock(block);
DBCellRecord cellRecord = new DBCellRecord(); DBCellRecord cellRecord = new DBCellRecord();
//Note: Cell references start from the second row... //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++) { for (int row=startRowNumber;row<=endRowNumber;row++) {
if (null != cells && cells.rowHasCells(row)) { if (null != cells && cells.rowHasCells(row)) {
final int rowCellSize = cells.serializeCellRow(row, pos, data); final int rowCellSize = cells.serializeCellRow(row, pos, data);
@ -254,29 +259,59 @@ public final class RowRecordsAggregate extends Record {
return -1000; return -1000;
} }
public int getRecordSize() public int getRecordSize() {
{
return size; 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() 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 * Performs a deep clone of the record
*/ */
public Object clone() public Object clone()
{ {
RowRecordsAggregate rec = new RowRecordsAggregate(); TreeMap rows = new TreeMap();
for ( Iterator rowIter = getIterator(); rowIter.hasNext(); ) for ( Iterator rowIter = getIterator(); rowIter.hasNext(); )
{ {
//return the cloned Row Record & insert //return the cloned Row Record & insert
RowRecord row = (RowRecord) ( (RowRecord) rowIter.next() ).clone(); 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);
}
} }

View File

@ -1,4 +1,3 @@
/* ==================================================================== /* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
@ -16,14 +15,19 @@
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
package org.apache.poi.hssf.record.aggregates; package org.apache.poi.hssf.record.aggregates;
import org.apache.poi.hssf.record.*; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; 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 Glen Stampoultzis (glens at apache.org)
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
*/ */
public final class ValueRecordsAggregate {
public final class ValueRecordsAggregate private int firstcell = -1;
extends Record private int lastcell = -1;
{ private CellValueRecordInterface[][] records;
public final static short sid = -1001; // 1000 clashes with RowRecordsAggregate
int firstcell = -1;
int lastcell = -1;
CellValueRecordInterface[][] records;
/** Creates a new instance of ValueRecordsAggregate */ /** Creates a new instance of ValueRecordsAggregate */
public 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) { public void insertCell(CellValueRecordInterface cell) {
@ -85,19 +85,34 @@ public final class ValueRecordsAggregate
} }
} }
public void removeCell(CellValueRecordInterface cell) public void removeCell(CellValueRecordInterface cell) {
{ if (cell == null) {
if (cell != null) { throw new IllegalArgumentException("cell must not be null");
short column = cell.getColumn(); }
int row = cell.getRow(); int row = cell.getRow();
if(row>=records.length) return; if (row >= records.length) {
CellValueRecordInterface[] rowCells=records[row]; throw new RuntimeException("cell row is out of range");
if(rowCells==null) return; }
if(column>=rowCells.length) return; CellValueRecordInterface[] rowCells = records[row];
rowCells[column]=null; 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() public int getPhysicalNumberOfCells()
{ {
int count=0; int count=0;
@ -133,7 +148,7 @@ public final class ValueRecordsAggregate
{ {
Record rec = ( Record ) records.get(k); Record rec = ( Record ) records.get(k);
if (rec instanceof SharedFormulaRecord) { if (rec instanceof SharedFormulaRecord) {
sharedFormulas.add(rec); sharedFormulas.add(rec);
} }
if(rec instanceof EOFRecord) { if(rec instanceof EOFRecord) {
// End of current sheet. Ignore all subsequent shared formula records (Bugzilla 44449) // End of current sheet. Ignore all subsequent shared formula records (Bugzilla 44449)
@ -150,30 +165,30 @@ public final class ValueRecordsAggregate
{ {
break; break;
} else if (rec instanceof SharedFormulaRecord) { } else if (rec instanceof SharedFormulaRecord) {
// Already handled, not to worry // Already handled, not to worry
} else if (rec instanceof FormulaRecord) } else if (rec instanceof FormulaRecord)
{ {
FormulaRecord formula = (FormulaRecord)rec; FormulaRecord formula = (FormulaRecord)rec;
if (formula.isSharedFormula()) { if (formula.isSharedFormula()) {
// Traverse the list of shared formulas in // 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 // for us
boolean found = false; boolean found = false;
for (int i=sharedFormulas.size()-1;i>=0;i--) { for (int i=sharedFormulas.size()-1;i>=0;i--) {
// TODO - there is no junit test case to justify this reversed loop // TODO - there is no junit test case to justify this reversed loop
// perhaps it could just run in the normal direction? // perhaps it could just run in the normal direction?
SharedFormulaRecord shrd = (SharedFormulaRecord)sharedFormulas.get(i); SharedFormulaRecord shrd = (SharedFormulaRecord)sharedFormulas.get(i);
if (shrd.isFormulaInShared(formula)) { if (shrd.isFormulaInShared(formula)) {
shrd.convertSharedFormulaRecord(formula); shrd.convertSharedFormulaRecord(formula);
found = true; found = true;
break; break;
} }
} }
if (!found) { if (!found) {
handleMissingSharedFormulaRecord(formula); handleMissingSharedFormulaRecord(formula);
} }
} }
lastFormulaAggregate = new FormulaRecordAggregate((FormulaRecord)rec, null); lastFormulaAggregate = new FormulaRecordAggregate((FormulaRecord)rec, null);
insertCell( lastFormulaAggregate ); insertCell( lastFormulaAggregate );
} }
@ -206,21 +221,6 @@ public final class ValueRecordsAggregate
private static void handleMissingSharedFormulaRecord(FormulaRecord formula) { private static void handleMissingSharedFormulaRecord(FormulaRecord formula) {
// could log an info message here since this is a fairly unusual occurrence. // 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 /** Tallies a count of the size of the cell records
* that are attached to the rows in the range specified. * 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 */ /** Returns true if the row has cells attached to it */
public boolean rowHasCells(int row) { public boolean rowHasCells(int row) {
if (row > records.length-1) //previously this said row > records.length which means if 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 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 CellValueRecordInterface[] rowCells=records[row]; //because a 60 length array has the last index = 59
if(rowCells==null) return false; if(rowCells==null) return false;
for(int col=0;col<rowCells.length;col++) { for(int col=0;col<rowCells.length;col++) {
@ -267,46 +267,26 @@ public final class ValueRecordsAggregate
return pos - offset; return pos - offset;
} }
public CellValueRecordInterface[] getValueRecords() {
/** List temp = new ArrayList();
* You never fill an aggregate
*/
protected void fillFields(RecordInputStream in)
{
}
/**
* called by constructor, should throw runtime exception in the event of a
* record passed with a differing ID.
*
* @param id alleged id for this record
*/
protected void validateSid(short id)
{
}
/**
* return the non static version of the id for this record.
*/
public short getSid()
{
return sid;
}
public int getRecordSize() {
int size = 0;
Iterator irecs = this.getIterator();
while (irecs.hasNext()) { for (int i = 0; i < records.length; i++) {
size += (( Record ) irecs.next()).getRecordSize(); CellValueRecordInterface[] rowCells = records[i];
if (rowCells == null) {
continue;
}
for (int j = 0; j < rowCells.length; j++) {
CellValueRecordInterface cell = rowCells[j];
if (cell != null) {
temp.add(cell);
}
}
} }
return size; CellValueRecordInterface[] result = new CellValueRecordInterface[temp.size()];
temp.toArray(result);
return result;
} }
public Iterator getIterator() public Iterator getIterator()
{ {
return new MyIterator(); return new MyIterator();

View File

@ -15,13 +15,6 @@
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
/*
* Cell.java
*
* Created on September 30, 2001, 3:46 PM
*/
package org.apache.poi.hssf.usermodel; package org.apache.poi.hssf.usermodel;
import java.text.DateFormat; import java.text.DateFormat;
@ -74,9 +67,7 @@ import org.apache.poi.hssf.record.formula.Ptg;
* @author Yegor Kozlov cell comments support * @author Yegor Kozlov cell comments support
* @version 1.0-pre * @version 1.0-pre
*/ */
public final class HSSFCell {
public class HSSFCell
{
/** /**
* Numeric Cell type (0) * Numeric Cell type (0)
@ -152,8 +143,6 @@ public class HSSFCell
* *
* @see org.apache.poi.hssf.usermodel.HSSFRow#createCell(short) * @see org.apache.poi.hssf.usermodel.HSSFRow#createCell(short)
*/ */
//protected HSSFCell(Workbook book, Sheet sheet, short row, short col)
protected HSSFCell(HSSFWorkbook book, Sheet sheet, int row, short col) protected HSSFCell(HSSFWorkbook book, Sheet sheet, int row, short col)
{ {
checkBounds(col); checkBounds(col);
@ -181,8 +170,6 @@ public class HSSFCell
* Type of cell * Type of cell
* @see org.apache.poi.hssf.usermodel.HSSFRow#createCell(short,int) * @see org.apache.poi.hssf.usermodel.HSSFRow#createCell(short,int)
*/ */
//protected HSSFCell(Workbook book, Sheet sheet, short row, short col,
protected HSSFCell(HSSFWorkbook book, Sheet sheet, int row, short col, protected HSSFCell(HSSFWorkbook book, Sheet sheet, int row, short col,
int type) int type)
{ {
@ -204,8 +191,6 @@ public class HSSFCell
* @param sheet - Sheet record of the sheet containing this cell * @param sheet - Sheet record of the sheet containing this cell
* @param cval - the Cell Value Record we wish to represent * @param cval - the Cell Value Record we wish to represent
*/ */
//protected HSSFCell(Workbook book, Sheet sheet, short row,
protected HSSFCell(HSSFWorkbook book, Sheet sheet, int row, protected HSSFCell(HSSFWorkbook book, Sheet sheet, int row,
CellValueRecordInterface cval) CellValueRecordInterface cval)
{ {
@ -229,15 +214,9 @@ public class HSSFCell
} }
ExtendedFormatRecord xf = book.getWorkbook().getExFormatAt(cval.getXFIndex()); ExtendedFormatRecord xf = book.getWorkbook().getExFormatAt(cval.getXFIndex());
setCellStyle(new HSSFCellStyle(( short ) cval.getXFIndex(), xf, book)); setCellStyle(new HSSFCellStyle(cval.getXFIndex(), xf, book));
} }
/**
* private constructor to prevent blank construction
*/
private HSSFCell()
{
}
/** /**
* used internally -- given a cell value record, figure out its type * used internally -- given a cell value record, figure out its type
@ -346,11 +325,6 @@ public class HSSFCell
private void setCellType(int cellType, boolean setValue, int row,short col, short styleIndex) private void setCellType(int cellType, boolean setValue, int row,short col, short styleIndex)
{ {
// if (cellType == CELL_TYPE_FORMULA)
// {
// throw new RuntimeException(
// "Formulas have not been implemented in this release");
// }
if (cellType > CELL_TYPE_ERROR) if (cellType > CELL_TYPE_ERROR)
{ {
throw new RuntimeException("I have no idea what type that is!"); throw new RuntimeException("I have no idea what type that is!");
@ -501,10 +475,7 @@ public class HSSFCell
if (cellType != this.cellType && if (cellType != this.cellType &&
this.cellType!=-1 ) // Special Value to indicate an uninitialized Cell this.cellType!=-1 ) // Special Value to indicate an uninitialized Cell
{ {
int loc = sheet.getLoc();
sheet.replaceValueRecord(record); sheet.replaceValueRecord(record);
sheet.setLoc(loc);
} }
this.cellType = cellType; this.cellType = cellType;
} }
@ -540,7 +511,7 @@ public class HSSFCell
setCellType(CELL_TYPE_NUMERIC, false, row, col, styleIndex); setCellType(CELL_TYPE_NUMERIC, false, row, col, styleIndex);
} }
// Save into the apropriate record // Save into the appropriate record
if(record instanceof FormulaRecordAggregate) { if(record instanceof FormulaRecordAggregate) {
(( FormulaRecordAggregate ) record).getFormulaRecord().setValue(value); (( FormulaRecordAggregate ) record).getFormulaRecord().setValue(value);
} else { } else {
@ -670,9 +641,7 @@ public class HSSFCell
//only set to default if there is no extended format index already set //only set to default if there is no extended format index already set
if (rec.getXFIndex() == (short)0) rec.setXFIndex(( short ) 0x0f); if (rec.getXFIndex() == (short)0) rec.setXFIndex(( short ) 0x0f);
FormulaParser fp = new FormulaParser(formula, book); Ptg[] ptgs = FormulaParser.parse(formula, book);
fp.parse();
Ptg[] ptg = fp.getRPNPtg();
int size = 0; int size = 0;
// clear the Ptg Stack // clear the Ptg Stack
@ -681,9 +650,9 @@ public class HSSFCell
} }
// fill the Ptg Stack with Ptgs of new formula // fill the Ptg Stack with Ptgs of new formula
for (int k = 0; k < ptg.length; k++) { for (int k = 0; k < ptgs.length; k++) {
size += ptg[ k ].getSize(); size += ptgs[ k ].getSize();
frec.pushExpressionToken(ptg[ k ]); frec.pushExpressionToken(ptgs[ k ]);
} }
rec.getFormulaRecord().setExpressionLength(( short ) size); rec.getFormulaRecord().setExpressionLength(( short ) size);
//Workbook.currentBook = null; //Workbook.currentBook = null;
@ -957,38 +926,6 @@ public class HSSFCell
ExtendedFormatRecord xf = book.getWorkbook().getExFormatAt(styleIndex); ExtendedFormatRecord xf = book.getWorkbook().getExFormatAt(styleIndex);
return new HSSFCellStyle(styleIndex, xf, book); 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 * Should only be used by HSSFSheet and friends. Returns the low level CellValueRecordInterface record

View File

@ -98,7 +98,12 @@ public final class HSSFRow implements Comparable {
setRowNum(record.getRowNumber()); 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. * Use this to create new cells within the row and return it.
* <p> * <p>
@ -109,26 +114,31 @@ public final class HSSFRow implements Comparable {
* *
* @return HSSFCell a high level representation of the created cell. * @return HSSFCell a high level representation of the created cell.
*/ */
public HSSFCell createCell(int columnIndex)
public HSSFCell createCell(short column)
{ {
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. * Use this to create new cells within the row and return it.
* <p> * <p>
* The cell that is returned is a CELL_TYPE_BLANK. The type can be changed * The cell that is returned is a CELL_TYPE_BLANK. The type can be changed
* either through calling setCellValue or setCellType. * 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. * @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); addCell(cell);
sheet.addValueRecord(getRowNum(), cell.getCellValueRecord()); sheet.addValueRecord(getRowNum(), cell.getCellValueRecord());
@ -174,12 +184,12 @@ public final class HSSFRow implements Comparable {
* records too. * records too.
*/ */
protected void removeAllCells() { protected void removeAllCells() {
for(int i=0; i<cells.length; i++) { for(int i=0; i<cells.length; i++) {
if(cells[i] != null) { if(cells[i] != null) {
removeCell(cells[i], true); removeCell(cells[i], true);
} }
} }
cells=new HSSFCell[INITIAL_CAPACITY]; cells=new HSSFCell[INITIAL_CAPACITY];
} }
/** /**
@ -327,7 +337,7 @@ public final class HSSFRow implements Comparable {
* @return HSSFCell representing that column or null if undefined. * @return HSSFCell representing that column or null if undefined.
*/ */
public HSSFCell getCell(int cellnum) { public HSSFCell getCell(int cellnum) {
return getCell(cellnum, book.getMissingCellPolicy()); return getCell(cellnum, book.getMissingCellPolicy());
} }
/** /**
@ -340,24 +350,24 @@ public final class HSSFRow implements Comparable {
* @return representing that column or null if undefined + policy allows. * @return representing that column or null if undefined + policy allows.
*/ */
public HSSFCell getCell(int cellnum, MissingCellPolicy policy) { public HSSFCell getCell(int cellnum, MissingCellPolicy policy) {
HSSFCell cell = retrieveCell(cellnum); HSSFCell cell = retrieveCell(cellnum);
if(policy == RETURN_NULL_AND_BLANK) { if(policy == RETURN_NULL_AND_BLANK) {
return cell; return cell;
} }
if(policy == RETURN_BLANK_AS_NULL) { if(policy == RETURN_BLANK_AS_NULL) {
if(cell == null) return cell; if(cell == null) return cell;
if(cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) { if(cell.getCellType() == HSSFCell.CELL_TYPE_BLANK) {
return null; return null;
} }
return cell; return cell;
} }
if(policy == CREATE_NULL_AS_BLANK) { if(policy == CREATE_NULL_AS_BLANK) {
if(cell == null) { if(cell == null) {
return createCell((short)cellnum, HSSFCell.CELL_TYPE_BLANK); return createCell((short)cellnum, HSSFCell.CELL_TYPE_BLANK);
} }
return cell; return cell;
} }
throw new IllegalArgumentException("Illegal policy " + policy + " (" + policy.id + ")"); throw new IllegalArgumentException("Illegal policy " + policy + " (" + policy.id + ")");
} }
/** /**
@ -536,11 +546,11 @@ public final class HSSFRow implements Comparable {
* if for the case of null and blank cells * if for the case of null and blank cells
*/ */
public static class MissingCellPolicy { public static class MissingCellPolicy {
private static int NEXT_ID = 1; private static int NEXT_ID = 1;
private final int id; private final int id;
private MissingCellPolicy() { /* package */ MissingCellPolicy() {
this.id = NEXT_ID++; this.id = NEXT_ID++;
} }
} }
/** Missing cells are returned as null, Blank cells are returned as normal */ /** Missing cells are returned as null, Blank cells are returned as normal */

View File

@ -81,7 +81,7 @@ public final class HSSFSheet {
*/ */
private Sheet sheet; private Sheet sheet;
private TreeMap rows; private TreeMap rows; // TODO - use simple key into this map
protected Workbook book; protected Workbook book;
protected HSSFWorkbook workbook; protected HSSFWorkbook workbook;
private int firstrow; private int firstrow;
@ -130,21 +130,18 @@ public final class HSSFSheet {
/** /**
* used internally to set the properties given a Sheet object * used internally to set the properties given a Sheet object
*/ */
private void setPropertiesFromSheet(Sheet sheet) {
private void setPropertiesFromSheet(Sheet sheet)
{
int sloc = sheet.getLoc();
RowRecord row = sheet.getNextRow(); RowRecord row = sheet.getNextRow();
boolean rowRecordsAlreadyPresent = row!=null; boolean rowRecordsAlreadyPresent = row!=null;
while (row != null) while (row != null) {
{
createRowFromRecord(row); createRowFromRecord(row);
row = sheet.getNextRow(); row = sheet.getNextRow();
} }
sheet.setLoc(sloc);
CellValueRecordInterface cval = sheet.getNextValueRecord(); CellValueRecordInterface[] cvals = sheet.getValueRecords();
long timestart = System.currentTimeMillis(); long timestart = System.currentTimeMillis();
if (log.check( POILogger.DEBUG )) if (log.check( POILogger.DEBUG ))
@ -152,14 +149,16 @@ public final class HSSFSheet {
new Long(timestart)); new Long(timestart));
HSSFRow lastrow = null; HSSFRow lastrow = null;
while (cval != null) // Add every cell to its row
{ for (int i = 0; i < cvals.length; i++) {
CellValueRecordInterface cval = cvals[i];
long cellstart = System.currentTimeMillis(); long cellstart = System.currentTimeMillis();
HSSFRow hrow = lastrow; HSSFRow hrow = lastrow;
if ( ( lastrow == null ) || ( lastrow.getRowNum() != cval.getRow() ) ) if (hrow == null || hrow.getRowNum() != cval.getRow()) {
{
hrow = getRow( cval.getRow() ); hrow = getRow( cval.getRow() );
lastrow = hrow;
if (hrow == null) { if (hrow == null) {
// Some tools (like Perl module Spreadsheet::WriteExcel - bug 41187) skip the RowRecords // Some tools (like Perl module Spreadsheet::WriteExcel - bug 41187) skip the RowRecords
// Excel, OpenOffice.org and GoogleDocs are all OK with this, so POI should be too. // Excel, OpenOffice.org and GoogleDocs are all OK with this, so POI should be too.
@ -173,21 +172,13 @@ public final class HSSFSheet {
hrow = createRowFromRecord(rowRec); hrow = createRowFromRecord(rowRec);
} }
} }
if ( hrow != null ) if (log.check( POILogger.DEBUG ))
{ log.log( DEBUG, "record id = " + Integer.toHexString( ( (Record) cval ).getSid() ) );
lastrow = hrow; hrow.createCellFromRecord( cval );
if (log.check( POILogger.DEBUG )) if (log.check( POILogger.DEBUG ))
log.log( DEBUG, "record id = " + Integer.toHexString( ( (Record) cval ).getSid() ) ); log.log( DEBUG, "record took ",
hrow.createCellFromRecord( cval ); new Long( System.currentTimeMillis() - cellstart ) );
cval = sheet.getNextValueRecord();
if (log.check( POILogger.DEBUG ))
log.log( DEBUG, "record took ",
new Long( System.currentTimeMillis() - cellstart ) );
}
else
{
cval = null;
}
} }
if (log.check( POILogger.DEBUG )) if (log.check( POILogger.DEBUG ))
log.log(DEBUG, "total sheet cell creation took ", log.log(DEBUG, "total sheet cell creation took ",
@ -230,10 +221,7 @@ public final class HSSFSheet {
* *
* @param row representing a row to remove. * @param row representing a row to remove.
*/ */
public void removeRow(HSSFRow row) {
public void removeRow(HSSFRow row)
{
sheet.setLoc(sheet.getDimsLoc());
if (rows.size() > 0) if (rows.size() > 0)
{ {
rows.remove(row); rows.remove(row);
@ -245,15 +233,6 @@ public final class HSSFSheet {
{ {
firstrow = findFirstRow(firstrow); 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()); sheet.removeRow(row.getRowRecord());
} }
} }
@ -646,8 +625,8 @@ public final class HSSFSheet {
public Region getMergedRegionAt(int index) { public Region getMergedRegionAt(int index) {
CellRangeAddress cra = getMergedRegion(index); CellRangeAddress cra = getMergedRegion(index);
return new Region(cra.getFirstRow(), (short)cra.getFirstColumn(), return new Region(cra.getFirstRow(), (short)cra.getFirstColumn(),
cra.getLastRow(), (short)cra.getLastColumn()); cra.getLastRow(), (short)cra.getLastColumn());
} }
/** /**
* @return the merged region at the specified index * @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 //don't check if it's not within the shifted area
if (!inStart || !inEnd) { if (!inStart || !inEnd) {
continue; continue;
} }
//only shift if the region outside the shifted rows is not merged too //only shift if the region outside the shifted rows is not merged too
if (!containsCell(merged, startRow-1, 0) && !containsCell(merged, endRow+1, 0)){ 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 //read so it doesn't get shifted again
Iterator iterator = shiftedRegions.iterator(); Iterator iterator = shiftedRegions.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
CellRangeAddress region = (CellRangeAddress)iterator.next(); CellRangeAddress region = (CellRangeAddress)iterator.next();
this.addMergedRegion(region); this.addMergedRegion(region);
} }
@ -1161,7 +1140,7 @@ public final class HSSFSheet {
*/ */
public void shiftRows( int startRow, int endRow, int n, boolean copyRowHeight, boolean resetOriginalRowHeight) 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 // Fetch the first and last columns of the
// row now, so we still have them to hand // row now, so we still have them to hand
// once we start removing cells // once we start removing cells
short firstCol = row.getFirstCellNum(); short firstCol = row.getFirstCellNum();
short lastCol = row.getLastCellNum(); short lastCol = row.getLastCellNum();
// Fix up row heights if required // Fix up row heights if required
if (copyRowHeight) { if (copyRowHeight) {
@ -1237,7 +1216,7 @@ public final class HSSFSheet {
// Copy each cell from the source row to // Copy each cell from the source row to
// the destination row // the destination row
for(Iterator cells = row.cellIterator(); cells.hasNext(); ) { for(Iterator cells = row.cellIterator(); cells.hasNext(); ) {
cell = (HSSFCell)cells.next(); cell = (HSSFCell)cells.next();
row.removeCell( cell ); row.removeCell( cell );
CellValueRecordInterface cellRecord = cell.getCellValueRecord(); CellValueRecordInterface cellRecord = cell.getCellValueRecord();
cellRecord.setRow( rowNum + n ); cellRecord.setRow( rowNum + n );
@ -1251,12 +1230,12 @@ public final class HSSFSheet {
// destination row. Note that comments can // destination row. Note that comments can
// exist for cells which are null // exist for cells which are null
if(moveComments) { if(moveComments) {
for( short col = firstCol; col <= lastCol; col++ ) { for( short col = firstCol; col <= lastCol; col++ ) {
HSSFComment comment = getCellComment(rowNum, col); HSSFComment comment = getCellComment(rowNum, col);
if (comment != null) { if (comment != null) {
comment.setRow(rowNum + n); comment.setRow(rowNum + n);
} }
} }
} }
} }
if ( endRow == lastrow || endRow + n > lastrow ) lastrow = Math.min( endRow + n, 65535 ); if ( endRow == lastrow || endRow + n > lastrow ) lastrow = Math.min( endRow + n, 65535 );
@ -1592,9 +1571,9 @@ public final class HSSFSheet {
* start from scratch! * start from scratch!
*/ */
public HSSFPatriarch getDrawingPatriarch() { public HSSFPatriarch getDrawingPatriarch() {
EscherAggregate agg = getDrawingEscherAggregate(); EscherAggregate agg = getDrawingEscherAggregate();
if(agg == null) return null; if(agg == null) return null;
HSSFPatriarch patriarch = new HSSFPatriarch(this, agg); HSSFPatriarch patriarch = new HSSFPatriarch(this, agg);
agg.setPatriarch(patriarch); agg.setPatriarch(patriarch);
@ -1669,7 +1648,7 @@ public final class HSSFSheet {
* @param column the column index * @param column the column index
*/ */
public void autoSizeColumn(short column) { public void autoSizeColumn(short column) {
autoSizeColumn(column, false); autoSizeColumn(column, false);
} }
/** /**
@ -1718,19 +1697,19 @@ public final class HSSFSheet {
HSSFCell cell = row.getCell(column); HSSFCell cell = row.getCell(column);
if (cell == null) { if (cell == null) {
continue; continue;
} }
int colspan = 1; int colspan = 1;
for (int i = 0 ; i < getNumMergedRegions(); i++) { for (int i = 0 ; i < getNumMergedRegions(); i++) {
CellRangeAddress region = getMergedRegion(i); CellRangeAddress region = getMergedRegion(i);
if (containsCell(region, row.getRowNum(), column)) { if (containsCell(region, row.getRowNum(), column)) {
if (!useMergedCells) { if (!useMergedCells) {
// If we're not using merged cells, skip this one and move on to the next. // If we're not using merged cells, skip this one and move on to the next.
continue rows; continue rows;
} }
cell = row.getCell(region.getFirstColumn()); cell = row.getCell(region.getFirstColumn());
colspan = 1 + region.getLastColumn() - region.getFirstColumn(); colspan = 1 + region.getLastColumn() - region.getFirstColumn();
} }
} }
@ -1821,7 +1800,7 @@ public final class HSSFSheet {
} }
if (width != -1) { if (width != -1) {
if (width > Short.MAX_VALUE) { //width can be bigger that Short.MAX_VALUE! 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)); sheet.setColumnWidth(column, (short) (width * 256));
} }

View File

@ -40,7 +40,6 @@ import org.apache.poi.hssf.record.StringRecord;
import org.apache.poi.hssf.record.UncalcedRecord; import org.apache.poi.hssf.record.UncalcedRecord;
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate; import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate; import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate;
import org.apache.poi.hssf.util.CellRangeAddress; 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 ColumnInfoRecordsAggregate );
assertTrue( sheet.records.get(pos++) instanceof DimensionsRecord ); assertTrue( sheet.records.get(pos++) instanceof DimensionsRecord );
assertTrue( sheet.records.get(pos++) instanceof RowRecordsAggregate ); assertTrue( sheet.records.get(pos++) instanceof RowRecordsAggregate );
assertTrue( sheet.records.get(pos++) instanceof ValueRecordsAggregate );
assertTrue( sheet.records.get(pos++) instanceof EOFRecord ); assertTrue( sheet.records.get(pos++) instanceof EOFRecord );
} }
@ -434,12 +432,12 @@ public final class TestSheet extends TestCase {
throw new AssertionFailedError("Identified bug 45145"); throw new AssertionFailedError("Identified bug 45145");
} }
// make sure that RRA and VRA are in the right place if (false) {
int rraIx = sheet.getDimsLoc()+1; // make sure that RRA and VRA are in the right place
List recs = sheet.getRecords(); // (Aug 2008) since the VRA is now part of the RRA, there is much less chance that
assertEquals(RowRecordsAggregate.class, recs.get(rraIx).getClass()); // they could get out of order. Still, one could write serialize the sheet here,
assertEquals(ValueRecordsAggregate.class, recs.get(rraIx+1).getClass()); // and read back with EventRecordFactory to make sure...
}
assertEquals(242, dbCellRecordPos); assertEquals(242, dbCellRecordPos);
} }

View File

@ -106,9 +106,7 @@ public class TestValueRecordsAggregate extends TestCase
assertTrue( iterator.hasNext() ); assertTrue( iterator.hasNext() );
} }
public void testRemoveCell() public void testRemoveCell() {
throws Exception
{
BlankRecord blankRecord1 = newBlankRecord(); BlankRecord blankRecord1 = newBlankRecord();
valueRecord.insertCell( blankRecord1 ); valueRecord.insertCell( blankRecord1 );
BlankRecord blankRecord2 = newBlankRecord(); BlankRecord blankRecord2 = newBlankRecord();
@ -118,10 +116,6 @@ public class TestValueRecordsAggregate extends TestCase
// removing an already empty cell just falls through // removing an already empty cell just falls through
valueRecord.removeCell( blankRecord2 ); valueRecord.removeCell( blankRecord2 );
// even trying to remove null just falls through silently.
valueRecord.removeCell( null );
} }
public void testGetPhysicalNumberOfCells() throws Exception public void testGetPhysicalNumberOfCells() throws Exception
@ -204,22 +198,6 @@ public class TestValueRecordsAggregate extends TestCase
return blankRecord; 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 (<tt>FormulaRecord.isSharedFormula()</tt>) is set when * Sometimes the 'shared formula' flag (<tt>FormulaRecord.isSharedFormula()</tt>) is set when
* there is no corresponding SharedFormulaRecord available. SharedFormulaRecord definitions do * there is no corresponding SharedFormulaRecord available. SharedFormulaRecord definitions do

View File

@ -31,12 +31,10 @@ import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.model.Workbook; import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.CellValueRecordInterface; import org.apache.poi.hssf.record.CellValueRecordInterface;
import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord; 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.NameRecord;
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
import org.apache.poi.hssf.record.formula.DeletedArea3DPtg; import org.apache.poi.hssf.record.formula.DeletedArea3DPtg;
import org.apache.poi.hssf.util.CellRangeAddress; import org.apache.poi.hssf.util.CellRangeAddress;
import org.apache.poi.hssf.util.Region;
import org.apache.poi.util.TempFile; import org.apache.poi.util.TempFile;
/** /**
@ -991,8 +989,8 @@ public final class TestBugs extends TestCase {
assertEquals("Forms.CheckBox.1", obj.getOLE2ClassName()); assertEquals("Forms.CheckBox.1", obj.getOLE2ClassName());
try { try {
obj.getDirectory(); obj.getDirectory();
fail(); fail();
} catch(FileNotFoundException e) {} } catch(FileNotFoundException e) {}
} }
@ -1011,12 +1009,12 @@ public final class TestBugs extends TestCase {
// DeletedArea3DPtg // DeletedArea3DPtg
Workbook w = wb.getWorkbook(); Workbook w = wb.getWorkbook();
for(int i=0; i<w.getNumNames(); i++) { for(int i=0; i<w.getNumNames(); i++) {
NameRecord r = w.getNameRecord(i); NameRecord r = w.getNameRecord(i);
assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets()); assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
List nd = r.getNameDefinition(); List nd = r.getNameDefinition();
assertEquals(1, nd.size()); assertEquals(1, nd.size());
assertTrue(nd.get(0) instanceof DeletedArea3DPtg); assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
} }
@ -1029,12 +1027,12 @@ public final class TestBugs extends TestCase {
assertEquals(2, wb.getNumberOfSheets()); assertEquals(2, wb.getNumberOfSheets());
for(int i=0; i<w.getNumNames(); i++) { for(int i=0; i<w.getNumNames(); i++) {
NameRecord r = w.getNameRecord(i); NameRecord r = w.getNameRecord(i);
assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets()); assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
List nd = r.getNameDefinition(); List nd = r.getNameDefinition();
assertEquals(1, nd.size()); assertEquals(1, nd.size());
assertTrue(nd.get(0) instanceof DeletedArea3DPtg); assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
} }
@ -1046,12 +1044,12 @@ public final class TestBugs extends TestCase {
assertEquals(2, wb.getNumberOfSheets()); assertEquals(2, wb.getNumberOfSheets());
for(int i=0; i<w.getNumNames(); i++) { for(int i=0; i<w.getNumNames(); i++) {
NameRecord r = w.getNameRecord(i); NameRecord r = w.getNameRecord(i);
assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets()); assertTrue(r.getIndexToSheet() <= wb.getNumberOfSheets());
List nd = r.getNameDefinition(); List nd = r.getNameDefinition();
assertEquals(1, nd.size()); assertEquals(1, nd.size());
assertTrue(nd.get(0) instanceof DeletedArea3DPtg); assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
} }
} }
@ -1059,84 +1057,84 @@ public final class TestBugs extends TestCase {
* Test that fonts get added properly * Test that fonts get added properly
*/ */
public void test45338() throws Exception { public void test45338() throws Exception {
HSSFWorkbook wb = new HSSFWorkbook(); HSSFWorkbook wb = new HSSFWorkbook();
assertEquals(4, wb.getNumberOfFonts()); assertEquals(4, wb.getNumberOfFonts());
HSSFSheet s = wb.createSheet(); HSSFSheet s = wb.createSheet();
s.createRow(0); s.createRow(0);
s.createRow(1); s.createRow(1);
HSSFCell c1 = s.getRow(0).createCell((short)0); HSSFCell c1 = s.getRow(0).createCell((short)0);
HSSFCell c2 = s.getRow(1).createCell((short)0); HSSFCell c2 = s.getRow(1).createCell((short)0);
assertEquals(4, wb.getNumberOfFonts()); assertEquals(4, wb.getNumberOfFonts());
HSSFFont f1 = wb.getFontAt((short)0); HSSFFont f1 = wb.getFontAt((short)0);
assertEquals(400, f1.getBoldweight()); assertEquals(400, f1.getBoldweight());
// Check that asking for the same font // Check that asking for the same font
// multiple times gives you the same thing. // multiple times gives you the same thing.
// Otherwise, our tests wouldn't work! // Otherwise, our tests wouldn't work!
assertEquals( assertEquals(
wb.getFontAt((short)0), wb.getFontAt((short)0),
wb.getFontAt((short)0) wb.getFontAt((short)0)
); );
assertEquals( assertEquals(
wb.getFontAt((short)2), wb.getFontAt((short)2),
wb.getFontAt((short)2) wb.getFontAt((short)2)
); );
assertTrue( assertTrue(
wb.getFontAt((short)0) wb.getFontAt((short)0)
!= !=
wb.getFontAt((short)2) wb.getFontAt((short)2)
); );
// Look for a new font we have // Look for a new font we have
// yet to add // yet to add
assertNull( assertNull(
wb.findFont( wb.findFont(
(short)11, (short)123, (short)22, (short)11, (short)123, (short)22,
"Thingy", false, true, (short)2, (byte)2 "Thingy", false, true, (short)2, (byte)2
) )
); );
HSSFFont nf = wb.createFont(); HSSFFont nf = wb.createFont();
assertEquals(5, wb.getNumberOfFonts()); assertEquals(5, wb.getNumberOfFonts());
assertEquals(5, nf.getIndex()); assertEquals(5, nf.getIndex());
assertEquals(nf, wb.getFontAt((short)5)); assertEquals(nf, wb.getFontAt((short)5));
nf.setBoldweight((short)11); nf.setBoldweight((short)11);
nf.setColor((short)123); nf.setColor((short)123);
nf.setFontHeight((short)22); nf.setFontHeight((short)22);
nf.setFontName("Thingy"); nf.setFontName("Thingy");
nf.setItalic(false); nf.setItalic(false);
nf.setStrikeout(true); nf.setStrikeout(true);
nf.setTypeOffset((short)2); nf.setTypeOffset((short)2);
nf.setUnderline((byte)2); nf.setUnderline((byte)2);
assertEquals(5, wb.getNumberOfFonts()); assertEquals(5, wb.getNumberOfFonts());
assertEquals(nf, wb.getFontAt((short)5)); assertEquals(nf, wb.getFontAt((short)5));
// Find it now // Find it now
assertNotNull( assertNotNull(
wb.findFont( wb.findFont(
(short)11, (short)123, (short)22, (short)11, (short)123, (short)22,
"Thingy", false, true, (short)2, (byte)2 "Thingy", false, true, (short)2, (byte)2
) )
); );
assertEquals( assertEquals(
5, 5,
wb.findFont( wb.findFont(
(short)11, (short)123, (short)22, (short)11, (short)123, (short)22,
"Thingy", false, true, (short)2, (byte)2 "Thingy", false, true, (short)2, (byte)2
).getIndex() ).getIndex()
); );
assertEquals(nf, assertEquals(nf,
wb.findFont( wb.findFont(
(short)11, (short)123, (short)22, (short)11, (short)123, (short)22,
"Thingy", false, true, (short)2, (byte)2 "Thingy", false, true, (short)2, (byte)2
) )
); );
} }
/** /**
@ -1145,94 +1143,90 @@ public final class TestBugs extends TestCase {
* @throws Exception * @throws Exception
*/ */
public void testZipCodeFormulas() throws Exception { public void testZipCodeFormulas() throws Exception {
HSSFWorkbook wb = new HSSFWorkbook(); HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet(); HSSFSheet s = wb.createSheet();
s.createRow(0); s.createRow(0);
HSSFCell c1 = s.getRow(0).createCell((short)0); HSSFCell c1 = s.getRow(0).createCell((short)0);
HSSFCell c2 = s.getRow(0).createCell((short)1); HSSFCell c2 = s.getRow(0).createCell((short)1);
HSSFCell c3 = s.getRow(0).createCell((short)2); HSSFCell c3 = s.getRow(0).createCell((short)2);
// As number and string // As number and string
c1.setCellFormula("70164"); c1.setCellFormula("70164");
c2.setCellFormula("\"70164\""); c2.setCellFormula("\"70164\"");
c3.setCellFormula("\"90210\""); c3.setCellFormula("\"90210\"");
// Check the formulas // Check the formulas
assertEquals("70164.0", c1.getCellFormula()); assertEquals("70164.0", c1.getCellFormula());
assertEquals("\"70164\"", c2.getCellFormula()); assertEquals("\"70164\"", c2.getCellFormula());
// And check the values - blank // And check the values - blank
assertEquals(0.0, c1.getNumericCellValue(), 0.00001); assertEquals(0.0, c1.getNumericCellValue(), 0.00001);
assertEquals("", c1.getRichStringCellValue().getString()); assertEquals("", c1.getRichStringCellValue().getString());
assertEquals(0.0, c2.getNumericCellValue(), 0.00001); assertEquals(0.0, c2.getNumericCellValue(), 0.00001);
assertEquals("", c2.getRichStringCellValue().getString()); assertEquals("", c2.getRichStringCellValue().getString());
assertEquals(0.0, c3.getNumericCellValue(), 0.00001); assertEquals(0.0, c3.getNumericCellValue(), 0.00001);
assertEquals("", c3.getRichStringCellValue().getString()); assertEquals("", c3.getRichStringCellValue().getString());
// Try changing the cached value on one of the string // Try changing the cached value on one of the string
// formula cells, so we can see it updates properly // formula cells, so we can see it updates properly
c3.setCellValue(new HSSFRichTextString("test")); c3.setCellValue(new HSSFRichTextString("test"));
assertEquals(0.0, c3.getNumericCellValue(), 0.00001); assertEquals(0.0, c3.getNumericCellValue(), 0.00001);
assertEquals("test", c3.getRichStringCellValue().getString()); assertEquals("test", c3.getRichStringCellValue().getString());
// Now evaluate, they should all be changed // Now evaluate, they should all be changed
HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(s, wb); HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(s, wb);
eval.setCurrentRow(s.getRow(0)); eval.setCurrentRow(s.getRow(0));
eval.evaluateFormulaCell(c1); eval.evaluateFormulaCell(c1);
eval.evaluateFormulaCell(c2); eval.evaluateFormulaCell(c2);
eval.evaluateFormulaCell(c3); eval.evaluateFormulaCell(c3);
// Check that the cells now contain // Check that the cells now contain
// the correct values // the correct values
assertEquals(70164.0, c1.getNumericCellValue(), 0.00001); assertEquals(70164.0, c1.getNumericCellValue(), 0.00001);
assertEquals("", c1.getRichStringCellValue().getString()); assertEquals("", c1.getRichStringCellValue().getString());
assertEquals(0.0, c2.getNumericCellValue(), 0.00001); assertEquals(0.0, c2.getNumericCellValue(), 0.00001);
assertEquals("70164", c2.getRichStringCellValue().getString()); assertEquals("70164", c2.getRichStringCellValue().getString());
assertEquals(0.0, c3.getNumericCellValue(), 0.00001); assertEquals(0.0, c3.getNumericCellValue(), 0.00001);
assertEquals("90210", c3.getRichStringCellValue().getString()); assertEquals("90210", c3.getRichStringCellValue().getString());
// Write and read // Write and read
HSSFWorkbook nwb = writeOutAndReadBack(wb); HSSFWorkbook nwb = writeOutAndReadBack(wb);
HSSFSheet ns = nwb.getSheetAt(0); HSSFSheet ns = nwb.getSheetAt(0);
HSSFCell nc1 = ns.getRow(0).getCell((short)0); HSSFCell nc1 = ns.getRow(0).getCell((short)0);
HSSFCell nc2 = ns.getRow(0).getCell((short)1); HSSFCell nc2 = ns.getRow(0).getCell((short)1);
HSSFCell nc3 = ns.getRow(0).getCell((short)2); HSSFCell nc3 = ns.getRow(0).getCell((short)2);
// Re-check // Re-check
assertEquals(70164.0, nc1.getNumericCellValue(), 0.00001); assertEquals(70164.0, nc1.getNumericCellValue(), 0.00001);
assertEquals("", nc1.getRichStringCellValue().getString()); assertEquals("", nc1.getRichStringCellValue().getString());
assertEquals(0.0, nc2.getNumericCellValue(), 0.00001); assertEquals(0.0, nc2.getNumericCellValue(), 0.00001);
assertEquals("70164", nc2.getRichStringCellValue().getString()); assertEquals("70164", nc2.getRichStringCellValue().getString());
assertEquals(0.0, nc3.getNumericCellValue(), 0.00001); assertEquals(0.0, nc3.getNumericCellValue(), 0.00001);
assertEquals("90210", nc3.getRichStringCellValue().getString()); assertEquals("90210", nc3.getRichStringCellValue().getString());
// Now check record level stuff too CellValueRecordInterface[] cvrs = ns.getSheet().getValueRecords();
ns.getSheet().setLoc(0); for (int i = 0; i < cvrs.length; i++) {
int fn = 0; CellValueRecordInterface cvr = cvrs[i];
CellValueRecordInterface cvr; if(cvr instanceof FormulaRecordAggregate) {
while((cvr = ns.getSheet().getNextValueRecord()) != null) { FormulaRecordAggregate fr = (FormulaRecordAggregate)cvr;
if(cvr instanceof FormulaRecordAggregate) {
FormulaRecordAggregate fr = (FormulaRecordAggregate)cvr; if(i == 0) {
assertEquals(70164.0, fr.getFormulaRecord().getValue(), 0.0001);
if(fn == 0) { assertNull(fr.getStringRecord());
assertEquals(70164.0, fr.getFormulaRecord().getValue(), 0.0001); } else if (i == 1) {
assertNull(fr.getStringRecord()); assertEquals(0.0, fr.getFormulaRecord().getValue(), 0.0001);
} else if (fn == 1) { assertNotNull(fr.getStringRecord());
assertEquals(0.0, fr.getFormulaRecord().getValue(), 0.0001); assertEquals("70164", fr.getStringRecord().getString());
assertNotNull(fr.getStringRecord()); } else {
assertEquals("70164", fr.getStringRecord().getString()); assertEquals(0.0, fr.getFormulaRecord().getValue(), 0.0001);
} else { assertNotNull(fr.getStringRecord());
assertEquals(0.0, fr.getFormulaRecord().getValue(), 0.0001); assertEquals("90210", fr.getStringRecord().getString());
assertNotNull(fr.getStringRecord()); }
assertEquals("90210", fr.getStringRecord().getString()); }
} }
assertEquals(3, cvrs.length);
fn++;
}
}
assertEquals(3, fn);
} }
/** /**
@ -1263,8 +1257,8 @@ public final class TestBugs extends TestCase {
assertEquals("{=sin(B1:B9){9,1)[2][0]", c3.getCellFormula()); assertEquals("{=sin(B1:B9){9,1)[2][0]", c3.getCellFormula());
// Save and re-open, ensure it still works // Save and re-open, ensure it still works
HSSFWorkbook nwb = writeOutAndReadBack(wb); HSSFWorkbook nwb = writeOutAndReadBack(wb);
HSSFSheet ns1 = nwb.getSheetAt(0); HSSFSheet ns1 = nwb.getSheetAt(0);
HSSFCell nc1 = ns1.getRow(0).getCell(2); HSSFCell nc1 = ns1.getRow(0).getCell(2);
HSSFCell nc2 = ns1.getRow(1).getCell(2); HSSFCell nc2 = ns1.getRow(1).getCell(2);
HSSFCell nc3 = ns1.getRow(2).getCell(2); HSSFCell nc3 = ns1.getRow(2).getCell(2);
@ -1279,48 +1273,48 @@ public final class TestBugs extends TestCase {
* row and cell number * row and cell number
*/ */
public void test30635() throws Exception { public void test30635() throws Exception {
HSSFWorkbook wb = new HSSFWorkbook(); HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet(); HSSFSheet s = wb.createSheet();
// No rows, everything is 0 // No rows, everything is 0
assertEquals(0, s.getFirstRowNum()); assertEquals(0, s.getFirstRowNum());
assertEquals(0, s.getLastRowNum()); assertEquals(0, s.getLastRowNum());
assertEquals(0, s.getPhysicalNumberOfRows()); assertEquals(0, s.getPhysicalNumberOfRows());
// One row, most things are 0, physical is 1 // One row, most things are 0, physical is 1
s.createRow(0); s.createRow(0);
assertEquals(0, s.getFirstRowNum()); assertEquals(0, s.getFirstRowNum());
assertEquals(0, s.getLastRowNum()); assertEquals(0, s.getLastRowNum());
assertEquals(1, s.getPhysicalNumberOfRows()); assertEquals(1, s.getPhysicalNumberOfRows());
// And another, things change // And another, things change
s.createRow(4); s.createRow(4);
assertEquals(0, s.getFirstRowNum()); assertEquals(0, s.getFirstRowNum());
assertEquals(4, s.getLastRowNum()); assertEquals(4, s.getLastRowNum());
assertEquals(2, s.getPhysicalNumberOfRows()); assertEquals(2, s.getPhysicalNumberOfRows());
// Now start on cells // Now start on cells
HSSFRow r = s.getRow(0); HSSFRow r = s.getRow(0);
assertEquals(-1, r.getFirstCellNum()); assertEquals(-1, r.getFirstCellNum());
assertEquals(-1, r.getLastCellNum()); assertEquals(-1, r.getLastCellNum());
assertEquals(0, r.getPhysicalNumberOfCells()); assertEquals(0, r.getPhysicalNumberOfCells());
// Add a cell, things move off -1 // Add a cell, things move off -1
r.createCell((short)0); r.createCell((short)0);
assertEquals(0, r.getFirstCellNum()); assertEquals(0, r.getFirstCellNum());
assertEquals(1, r.getLastCellNum()); // last cell # + 1 assertEquals(1, r.getLastCellNum()); // last cell # + 1
assertEquals(1, r.getPhysicalNumberOfCells()); assertEquals(1, r.getPhysicalNumberOfCells());
r.createCell((short)1); r.createCell((short)1);
assertEquals(0, r.getFirstCellNum()); assertEquals(0, r.getFirstCellNum());
assertEquals(2, r.getLastCellNum()); // last cell # + 1 assertEquals(2, r.getLastCellNum()); // last cell # + 1
assertEquals(2, r.getPhysicalNumberOfCells()); assertEquals(2, r.getPhysicalNumberOfCells());
r.createCell((short)4); r.createCell((short)4);
assertEquals(0, r.getFirstCellNum()); assertEquals(0, r.getFirstCellNum());
assertEquals(5, r.getLastCellNum()); // last cell # + 1 assertEquals(5, r.getLastCellNum()); // last cell # + 1
assertEquals(3, r.getPhysicalNumberOfCells()); assertEquals(3, r.getPhysicalNumberOfCells());
} }
/** /**
@ -1331,7 +1325,7 @@ public final class TestBugs extends TestCase {
HSSFSheet s; HSSFSheet s;
HSSFRow r; HSSFRow r;
HSSFCell c; HSSFCell c;
// Check the contents of the formulas // Check the contents of the formulas
// E4 to G9 of sheet 4 make up the table // E4 to G9 of sheet 4 make up the table
@ -1368,18 +1362,18 @@ public final class TestBugs extends TestCase {
* with diagrams on. Don't any more * with diagrams on. Don't any more
*/ */
public void test45414() throws Exception { public void test45414() throws Exception {
HSSFWorkbook wb = openSample("WithThreeCharts.xls"); HSSFWorkbook wb = openSample("WithThreeCharts.xls");
wb.getSheetAt(0).setForceFormulaRecalculation(true); wb.getSheetAt(0).setForceFormulaRecalculation(true);
wb.getSheetAt(1).setForceFormulaRecalculation(false); wb.getSheetAt(1).setForceFormulaRecalculation(false);
wb.getSheetAt(2).setForceFormulaRecalculation(true); wb.getSheetAt(2).setForceFormulaRecalculation(true);
// Write out and back in again // Write out and back in again
// This used to break // This used to break
HSSFWorkbook nwb = writeOutAndReadBack(wb); HSSFWorkbook nwb = writeOutAndReadBack(wb);
// Check now set as it should be // Check now set as it should be
assertTrue(nwb.getSheetAt(0).getForceFormulaRecalculation()); assertTrue(nwb.getSheetAt(0).getForceFormulaRecalculation());
assertFalse(nwb.getSheetAt(1).getForceFormulaRecalculation()); assertFalse(nwb.getSheetAt(1).getForceFormulaRecalculation());
assertTrue(nwb.getSheetAt(2).getForceFormulaRecalculation()); assertTrue(nwb.getSheetAt(2).getForceFormulaRecalculation());
} }
} }

View File

@ -265,14 +265,14 @@ public final class TestFormulas extends TestCase {
HSSFCell c = null; HSSFCell c = null;
//get our minimum values //get our minimum values
r = s.createRow((short)0); r = s.createRow(0);
c = r.createCell((short)1); c = r.createCell(1);
c.setCellFormula("A2" + operator + "A3"); c.setCellFormula("A2" + operator + "A3");
for (short x = 1; x < Short.MAX_VALUE && x > 0; x=(short)(x*2)) { for (int x = 1; x < Short.MAX_VALUE && x > 0; x=(short)(x*2)) {
r = s.createRow((short) x); 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 ref=null;
String ref2=null; String ref2=null;
@ -296,13 +296,13 @@ public final class TestFormulas extends TestCase {
refy2=(short)(y-3); refy2=(short)(y-3);
} }
c = r.getCell((short) y); c = r.getCell(y);
CellReference cr= new CellReference(refx1,refy1, false, false); CellReference cr= new CellReference(refx1,refy1, false, false);
ref=cr.formatAsString(); ref=cr.formatAsString();
cr=new CellReference(refx2,refy2, false, false); cr=new CellReference(refx2,refy2, false, false);
ref2=cr.formatAsString(); ref2=cr.formatAsString();
c = r.createCell((short) y); c = r.createCell(y);
c.setCellFormula("" + ref + operator + ref2); 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 //make sure we do the maximum value of the Int operator
if (s.getLastRowNum() < Short.MAX_VALUE) { if (s.getLastRowNum() < Short.MAX_VALUE) {
r = s.createRow((short)0); r = s.getRow(0);
c = r.createCell((short)0); c = r.createCell(0);
c.setCellFormula("" + "B1" + operator + "IV255"); c.setCellFormula("" + "B1" + operator + "IV255");
} }
@ -453,16 +453,16 @@ public final class TestFormulas extends TestCase {
HSSFCell c = null; HSSFCell c = null;
//get our minimum values //get our minimum values
r = s.createRow((short)0); r = s.createRow(0);
c = r.createCell((short)1); c = r.createCell(1);
c.setCellFormula(1 + operator + 1); c.setCellFormula(1 + operator + 1);
for (short x = 1; x < Short.MAX_VALUE && x > 0; x=(short)(x*2)) { for (int x = 1; x < Short.MAX_VALUE && x > 0; x=(short)(x*2)) {
r = s.createRow((short) x); 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); 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 //make sure we do the maximum value of the Int operator
if (s.getLastRowNum() < Short.MAX_VALUE) { if (s.getLastRowNum() < Short.MAX_VALUE) {
r = s.createRow((short)0); r = s.getRow(0);
c = r.createCell((short)0); c = r.createCell(0);
c.setCellFormula("" + Short.MAX_VALUE + operator + Short.MAX_VALUE); c.setCellFormula("" + Short.MAX_VALUE + operator + Short.MAX_VALUE);
} }

View File

@ -30,7 +30,7 @@ import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.BackupRecord; import org.apache.poi.hssf.record.BackupRecord;
import org.apache.poi.hssf.record.LabelSSTRecord; import org.apache.poi.hssf.record.LabelSSTRecord;
import org.apache.poi.hssf.record.Record; 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.hssf.util.CellRangeAddress;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.TempFile; import org.apache.poi.util.TempFile;
@ -93,7 +93,7 @@ public final class TestWorkbook extends TestCase {
+ ((( double ) rownum / 1000) + ((( double ) rownum / 1000)
+ (( double ) cellnum / 10000))); + (( double ) cellnum / 10000)));
c = r.createCell(( short ) (cellnum + 1)); c = r.createCell(( short ) (cellnum + 1));
c.setCellValue("TEST"); c.setCellValue(new HSSFRichTextString("TEST"));
} }
} }
wb.write(out); wb.write(out);
@ -139,7 +139,7 @@ public final class TestWorkbook extends TestCase {
+ ((( double ) rownum / 1000) + ((( double ) rownum / 1000)
+ (( double ) cellnum / 10000))); + (( double ) cellnum / 10000)));
c = r.createCell(( short ) (cellnum + 1)); c = r.createCell(( short ) (cellnum + 1));
c.setCellValue("TEST"); c.setCellValue(new HSSFRichTextString("TEST"));
} }
} }
for (short rownum = ( short ) 0; rownum < 25; rownum++) for (short rownum = ( short ) 0; rownum < 25; rownum++)
@ -310,9 +310,9 @@ public final class TestWorkbook extends TestCase {
HSSFSheet sheet = workbook.getSheetAt(0); HSSFSheet sheet = workbook.getSheetAt(0);
HSSFCell cell = sheet.getRow(0).getCell(1); HSSFCell cell = sheet.getRow(0).getCell(1);
cell.setCellValue(REPLACED); cell.setCellValue(new HSSFRichTextString(REPLACED));
cell = sheet.getRow(1).getCell(0); cell = sheet.getRow(1).getCell(0);
cell.setCellValue(REPLACED); cell.setCellValue(new HSSFRichTextString(REPLACED));
workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
@ -380,11 +380,11 @@ public final class TestWorkbook extends TestCase {
HSSFSheet sheet = workbook.getSheetAt(0); HSSFSheet sheet = workbook.getSheetAt(0);
HSSFCell cell = sheet.getRow(3).getCell(2); 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 = sheet.getRow(4).getCell(2);
cell.setCellValue(FIRST_NAME_VALUE); cell.setCellValue(new HSSFRichTextString(FIRST_NAME_VALUE));
cell = sheet.getRow(5).getCell(2); cell = sheet.getRow(5).getCell(2);
cell.setCellValue(SSN_VALUE); cell.setCellValue(new HSSFRichTextString(SSN_VALUE));
workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook); workbook = HSSFTestDataSamples.writeOutAndReadBack(workbook);
sheet = workbook.getSheetAt(0); sheet = workbook.getSheetAt(0);
@ -494,11 +494,11 @@ public final class TestWorkbook extends TestCase {
cell = row.createCell(( short ) 2); cell = row.createCell(( short ) 2);
// workbook.write(new FileOutputStream("/a2.xls")); // workbook.write(new FileOutputStream("/a2.xls"));
ValueRecordsAggregate valueAggregate = RowRecordsAggregate rra = (RowRecordsAggregate)
( ValueRecordsAggregate ) sheet.getSheet() sheet.getSheet().findFirstRecordBySid((short)-1000);
.findFirstRecordBySid(ValueRecordsAggregate.sid);
int sstRecords = 0; int sstRecords = 0;
Iterator iterator = valueAggregate.getIterator(); Iterator iterator = rra.getAllRecordsIterator();
while (iterator.hasNext()) while (iterator.hasNext())
{ {
@ -511,16 +511,11 @@ public final class TestWorkbook extends TestCase {
} }
public void testManyRows() public void testManyRows() {
throws Exception
{
String testName = "TestManyRows";
File file = TempFile.createTempFile(testName, ".xls");
FileOutputStream out = new FileOutputStream(file);
HSSFWorkbook workbook = new HSSFWorkbook(); HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet(); HSSFSheet sheet = workbook.createSheet();
HSSFRow row = null; HSSFRow row;
HSSFCell cell = null; HSSFCell cell;
int i, j; int i, j;
for ( i = 0, j = 32771; j > 0; 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 = row.createCell((short) 0);
cell.setCellValue(i); cell.setCellValue(i);
} }
workbook.write(out);
out.close();
sanityChecker.checkHSSFWorkbook(workbook); sanityChecker.checkHSSFWorkbook(workbook);
assertEquals("LAST ROW == 32770", 32770, sheet.getLastRowNum()); assertEquals("LAST ROW == 32770", 32770, sheet.getLastRowNum());
cell = sheet.getRow(32770).getCell(0);
double lastVal = cell.getNumericCellValue(); double lastVal = cell.getNumericCellValue();
FileInputStream in = new FileInputStream(file); HSSFWorkbook wb = HSSFTestDataSamples.writeOutAndReadBack(workbook);
POIFSFileSystem fs = new POIFSFileSystem(in);
HSSFWorkbook wb = new HSSFWorkbook(fs);
HSSFSheet s = wb.getSheetAt(0); HSSFSheet s = wb.getSheetAt(0);
row = s.getRow(32770); row = s.getRow(32770);
cell = row.getCell(( short ) 0); cell = row.getCell(0);
assertEquals("Value from last row == 32770", lastVal, cell.getNumericCellValue(), 0); assertEquals("Value from last row == 32770", lastVal, cell.getNumericCellValue(), 0);
assertEquals("LAST ROW == 32770", 32770, s.getLastRowNum()); 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()); assertTrue("file exists",file.exists());
} }
public static void main(String [] ignored_args)
{
junit.textui.TestRunner.run(TestWorkbook.class);
}
} }