whitespace

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1754782 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Javen O'Neal 2016-08-01 17:36:06 +00:00
parent 984683ab4b
commit 3c77adf9e8

View File

@ -34,184 +34,184 @@ import org.apache.poi.ss.formula.FormulaShifter;
* @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 RecordAggregate { public final class RowRecordsAggregate extends RecordAggregate {
private int _firstrow = -1; private int _firstrow = -1;
private int _lastrow = -1; private int _lastrow = -1;
private final Map<Integer, RowRecord> _rowRecords; private final Map<Integer, RowRecord> _rowRecords;
private final ValueRecordsAggregate _valuesAgg; private final ValueRecordsAggregate _valuesAgg;
private final List<Record> _unknownRecords; private final List<Record> _unknownRecords;
private final SharedValueManager _sharedValueManager; private final SharedValueManager _sharedValueManager;
// Cache values to speed up performance of // Cache values to speed up performance of
// getStartRowNumberForBlock / getEndRowNumberForBlock, see Bugzilla 47405 // getStartRowNumberForBlock / getEndRowNumberForBlock, see Bugzilla 47405
private RowRecord[] _rowRecordValues = null; private RowRecord[] _rowRecordValues = null;
/** Creates a new instance of ValueRecordsAggregate */ /** Creates a new instance of ValueRecordsAggregate */
public RowRecordsAggregate() { public RowRecordsAggregate() {
this(SharedValueManager.createEmpty()); this(SharedValueManager.createEmpty());
} }
private RowRecordsAggregate(SharedValueManager svm) { private RowRecordsAggregate(SharedValueManager svm) {
if (svm == null) { if (svm == null) {
throw new IllegalArgumentException("SharedValueManager must be provided."); throw new IllegalArgumentException("SharedValueManager must be provided.");
} }
_rowRecords = new TreeMap<Integer, RowRecord>(); _rowRecords = new TreeMap<Integer, RowRecord>();
_valuesAgg = new ValueRecordsAggregate(); _valuesAgg = new ValueRecordsAggregate();
_unknownRecords = new ArrayList<Record>(); _unknownRecords = new ArrayList<Record>();
_sharedValueManager = svm; _sharedValueManager = svm;
} }
/** /**
* @param rs record stream with all {@link SharedFormulaRecord} * @param rs record stream with all {@link SharedFormulaRecord}
* {@link ArrayRecord}, {@link TableRecord} {@link MergeCellsRecord} Records removed * {@link ArrayRecord}, {@link TableRecord} {@link MergeCellsRecord} Records removed
* @param svm an initialised {@link SharedValueManager} (from the shared formula, array * @param svm an initialised {@link SharedValueManager} (from the shared formula, array
* and table records of the current sheet). Never <code>null</code>. * and table records of the current sheet). Never <code>null</code>.
*/ */
public RowRecordsAggregate(RecordStream rs, SharedValueManager svm) { public RowRecordsAggregate(RecordStream rs, SharedValueManager svm) {
this(svm); this(svm);
while(rs.hasNext()) { while(rs.hasNext()) {
Record rec = rs.getNext(); Record rec = rs.getNext();
switch (rec.getSid()) { switch (rec.getSid()) {
case RowRecord.sid: case RowRecord.sid:
insertRow((RowRecord) rec); insertRow((RowRecord) rec);
continue; continue;
case DConRefRecord.sid: case DConRefRecord.sid:
addUnknownRecord(rec); addUnknownRecord(rec);
continue; continue;
case DBCellRecord.sid: case DBCellRecord.sid:
// end of 'Row Block'. Should only occur after cell records // end of 'Row Block'. Should only occur after cell records
// ignore DBCELL records because POI generates them upon re-serialization // ignore DBCELL records because POI generates them upon re-serialization
continue; continue;
} }
if (rec instanceof UnknownRecord) { if (rec instanceof UnknownRecord) {
// might need to keep track of where exactly these belong // might need to keep track of where exactly these belong
addUnknownRecord(rec); addUnknownRecord(rec);
while (rs.peekNextSid() == ContinueRecord.sid) { while (rs.peekNextSid() == ContinueRecord.sid) {
addUnknownRecord(rs.getNext()); addUnknownRecord(rs.getNext());
} }
continue; continue;
} }
if (rec instanceof MulBlankRecord) { if (rec instanceof MulBlankRecord) {
_valuesAgg.addMultipleBlanks((MulBlankRecord) rec); _valuesAgg.addMultipleBlanks((MulBlankRecord) rec);
continue; continue;
} }
if (!(rec instanceof CellValueRecordInterface)) { if (!(rec instanceof CellValueRecordInterface)) {
throw new RuntimeException("Unexpected record type (" + rec.getClass().getName() + ")"); throw new RuntimeException("Unexpected record type (" + rec.getClass().getName() + ")");
} }
_valuesAgg.construct((CellValueRecordInterface)rec, rs, svm); _valuesAgg.construct((CellValueRecordInterface)rec, rs, svm);
} }
} }
/** /**
* Handles UnknownRecords which appear within the row/cell records * Handles UnknownRecords which appear within the row/cell records
*/ */
private void addUnknownRecord(Record rec) { private void addUnknownRecord(Record rec) {
// ony a few distinct record IDs are encountered by the existing POI test cases: // ony a few distinct record IDs are encountered by the existing POI test cases:
// 0x1065 // many // 0x1065 // many
// 0x01C2 // several // 0x01C2 // several
// 0x0034 // few // 0x0034 // few
// No documentation could be found for these // No documentation could be found for these
// keep the unknown records for re-serialization // keep the unknown records for re-serialization
_unknownRecords.add(rec); _unknownRecords.add(rec);
} }
public void insertRow(RowRecord row) { public void insertRow(RowRecord row) {
// Integer integer = Integer.valueOf(row.getRowNumber()); // Integer integer = Integer.valueOf(row.getRowNumber());
_rowRecords.put(Integer.valueOf(row.getRowNumber()), row); _rowRecords.put(Integer.valueOf(row.getRowNumber()), row);
// Clear the cached values // Clear the cached values
_rowRecordValues = null; _rowRecordValues = null;
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(); int rowIndex = row.getRowNumber();
_valuesAgg.removeAllCellsValuesForRow(rowIndex); _valuesAgg.removeAllCellsValuesForRow(rowIndex);
Integer key = Integer.valueOf(rowIndex); Integer key = Integer.valueOf(rowIndex);
RowRecord rr = _rowRecords.remove(key); RowRecord rr = _rowRecords.remove(key);
if (rr == null) { if (rr == null) {
throw new RuntimeException("Invalid row index (" + key.intValue() + ")"); throw new RuntimeException("Invalid row index (" + key.intValue() + ")");
} }
if (row != rr) { if (row != rr) {
_rowRecords.put(key, rr); _rowRecords.put(key, rr);
throw new RuntimeException("Attempt to remove row that does not belong to this sheet"); throw new RuntimeException("Attempt to remove row that does not belong to this sheet");
} }
// Clear the cached values // Clear the cached values
_rowRecordValues = null; _rowRecordValues = null;
} }
public RowRecord getRow(int rowIndex) { public RowRecord getRow(int rowIndex) {
int maxrow = SpreadsheetVersion.EXCEL97.getLastRowIndex(); int maxrow = SpreadsheetVersion.EXCEL97.getLastRowIndex();
if (rowIndex < 0 || rowIndex > maxrow) { if (rowIndex < 0 || rowIndex > maxrow) {
throw new IllegalArgumentException("The row number must be between 0 and " + maxrow + ", but had: " + rowIndex); throw new IllegalArgumentException("The row number must be between 0 and " + maxrow + ", but had: " + rowIndex);
} }
return _rowRecords.get(Integer.valueOf(rowIndex)); return _rowRecords.get(Integer.valueOf(rowIndex));
} }
public int getPhysicalNumberOfRows() public int getPhysicalNumberOfRows()
{ {
return _rowRecords.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.
* <p/>The row blocks are goupings of rows that contain the DBCell record * <p/>The row blocks are goupings of rows that contain the DBCell record
* after them * after them
*/ */
public int getRowBlockCount() { public int getRowBlockCount() {
int size = _rowRecords.size()/DBCellRecord.BLOCK_SIZE; int size = _rowRecords.size()/DBCellRecord.BLOCK_SIZE;
if ((_rowRecords.size() % DBCellRecord.BLOCK_SIZE) != 0) if ((_rowRecords.size() % DBCellRecord.BLOCK_SIZE) != 0)
size++; size++;
return size; return size;
} }
private int getRowBlockSize(int block) { private int getRowBlockSize(int block) {
return RowRecord.ENCODED_SIZE * 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 >= _rowRecords.size()) if (endIndex >= _rowRecords.size())
endIndex = _rowRecords.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*/
private int getStartRowNumberForBlock(int block) { private int getStartRowNumberForBlock(int block) {
int startIndex = block * DBCellRecord.BLOCK_SIZE; int startIndex = block * DBCellRecord.BLOCK_SIZE;
if(_rowRecordValues == null){ if (_rowRecordValues == null) {
_rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]); _rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]);
} }
try { try {
return _rowRecordValues[startIndex].getRowNumber(); return _rowRecordValues[startIndex].getRowNumber();
} catch(ArrayIndexOutOfBoundsException e) { } catch(ArrayIndexOutOfBoundsException e) {
throw new RuntimeException("Did not find start row for block " + block); throw new RuntimeException("Did not find start row for block " + block);
} }
} }
/** Returns the physical row number of the end row in a block*/ /** Returns the physical row number of the end row in a block*/
private 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 >= _rowRecords.size()) if (endIndex >= _rowRecords.size())
endIndex = _rowRecords.size()-1; endIndex = _rowRecords.size()-1;
if(_rowRecordValues == null){ if (_rowRecordValues == null){
_rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]); _rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]);
} }
@ -219,287 +219,287 @@ public final class RowRecordsAggregate extends RecordAggregate {
return _rowRecordValues[endIndex].getRowNumber(); return _rowRecordValues[endIndex].getRowNumber();
} catch(ArrayIndexOutOfBoundsException e) { } catch(ArrayIndexOutOfBoundsException e) {
throw new RuntimeException("Did not find end row for block " + block); throw new RuntimeException("Did not find end row for block " + block);
} }
} }
private int visitRowRecordsForBlock(int blockIndex, RecordVisitor rv) { private int visitRowRecordsForBlock(int blockIndex, RecordVisitor rv) {
final int startIndex = blockIndex*DBCellRecord.BLOCK_SIZE; final int startIndex = blockIndex*DBCellRecord.BLOCK_SIZE;
final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE; final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE;
Iterator<RowRecord> rowIterator = _rowRecords.values().iterator(); Iterator<RowRecord> rowIterator = _rowRecords.values().iterator();
//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 //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 i=0; int i=0;
for (;i<startIndex;i++) for (;i<startIndex;i++)
rowIterator.next(); rowIterator.next();
int result = 0; int result = 0;
while(rowIterator.hasNext() && (i++ < endIndex)) { while(rowIterator.hasNext() && (i++ < endIndex)) {
Record rec = rowIterator.next(); Record rec = rowIterator.next();
result += rec.getRecordSize(); result += rec.getRecordSize();
rv.visitRecord(rec); rv.visitRecord(rec);
} }
return result; return result;
} }
@Override @Override
public void visitContainedRecords(RecordVisitor rv) { public void visitContainedRecords(RecordVisitor rv) {
PositionTrackingVisitor stv = new PositionTrackingVisitor(rv, 0); PositionTrackingVisitor stv = new PositionTrackingVisitor(rv, 0);
//DBCells are serialized before row records. //DBCells are serialized before row records.
final int blockCount = getRowBlockCount(); final int blockCount = getRowBlockCount();
for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) { for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) {
// Serialize a block of rows. // Serialize a block of rows.
// Hold onto the position of the first row in the block // Hold onto the position of the first row in the block
int pos=0; int pos=0;
// Hold onto the size of this block that was serialized // Hold onto the size of this block that was serialized
final int rowBlockSize = visitRowRecordsForBlock(blockIndex, rv); final int rowBlockSize = visitRowRecordsForBlock(blockIndex, rv);
pos += rowBlockSize; pos += rowBlockSize;
// Serialize a block of cells for those rows // Serialize a block of cells for those rows
final int startRowNumber = getStartRowNumberForBlock(blockIndex); final int startRowNumber = getStartRowNumberForBlock(blockIndex);
final int endRowNumber = getEndRowNumberForBlock(blockIndex); final int endRowNumber = getEndRowNumberForBlock(blockIndex);
DBCellRecord.Builder dbcrBuilder = new DBCellRecord.Builder(); DBCellRecord.Builder dbcrBuilder = new DBCellRecord.Builder();
// Note: Cell references start from the second row... // Note: Cell references start from the second row...
int cellRefOffset = (rowBlockSize - RowRecord.ENCODED_SIZE); int cellRefOffset = (rowBlockSize - RowRecord.ENCODED_SIZE);
for (int row = startRowNumber; row <= endRowNumber; row++) { for (int row = startRowNumber; row <= endRowNumber; row++) {
if (_valuesAgg.rowHasCells(row)) { if (_valuesAgg.rowHasCells(row)) {
stv.setPosition(0); stv.setPosition(0);
_valuesAgg.visitCellsForRow(row, stv); _valuesAgg.visitCellsForRow(row, stv);
int rowCellSize = stv.getPosition(); int rowCellSize = stv.getPosition();
pos += rowCellSize; pos += rowCellSize;
// Add the offset to the first cell for the row into the // Add the offset to the first cell for the row into the
// DBCellRecord. // DBCellRecord.
dbcrBuilder.addCellOffset(cellRefOffset); dbcrBuilder.addCellOffset(cellRefOffset);
cellRefOffset = rowCellSize; cellRefOffset = rowCellSize;
} }
} }
// Calculate Offset from the start of a DBCellRecord to the first Row // Calculate Offset from the start of a DBCellRecord to the first Row
rv.visitRecord(dbcrBuilder.build(pos)); rv.visitRecord(dbcrBuilder.build(pos));
} }
for (Record _unknownRecord : _unknownRecords) { for (Record _unknownRecord : _unknownRecords) {
// Potentially breaking the file here since we don't know exactly where to write these records // Potentially breaking the file here since we don't know exactly where to write these records
rv.visitRecord(_unknownRecord); rv.visitRecord(_unknownRecord);
} }
} }
public Iterator<RowRecord> getIterator() { public Iterator<RowRecord> getIterator() {
return _rowRecords.values().iterator(); return _rowRecords.values().iterator();
} }
public int findStartOfRowOutlineGroup(int row) { public int findStartOfRowOutlineGroup(int row) {
// Find the start of the group. // Find the start of the group.
RowRecord rowRecord = this.getRow( row ); RowRecord rowRecord = this.getRow( row );
int level = rowRecord.getOutlineLevel(); int level = rowRecord.getOutlineLevel();
int currentRow = row; int currentRow = row;
while (currentRow >= 0 && this.getRow( currentRow ) != null) { while (currentRow >= 0 && this.getRow( currentRow ) != null) {
rowRecord = this.getRow( currentRow ); rowRecord = this.getRow( currentRow );
if (rowRecord.getOutlineLevel() < level) { if (rowRecord.getOutlineLevel() < level) {
return currentRow + 1; return currentRow + 1;
} }
currentRow--; currentRow--;
} }
return currentRow + 1; return currentRow + 1;
} }
public int findEndOfRowOutlineGroup(int row) { public int findEndOfRowOutlineGroup(int row) {
int level = getRow( row ).getOutlineLevel(); int level = getRow( row ).getOutlineLevel();
int currentRow; int currentRow;
for (currentRow = row; currentRow < getLastRowNum(); currentRow++) { for (currentRow = row; currentRow < getLastRowNum(); currentRow++) {
if (getRow(currentRow) == null || getRow(currentRow).getOutlineLevel() < level) { if (getRow(currentRow) == null || getRow(currentRow).getOutlineLevel() < level) {
break; break;
} }
} }
return currentRow-1; return currentRow-1;
} }
/** /**
* Hide all rows at or below the current outline level * Hide all rows at or below the current outline level
* @return index of the <em>next<em> row after the last row that gets hidden * @return index of the <em>next<em> row after the last row that gets hidden
*/ */
private int writeHidden(RowRecord pRowRecord, int row) { private int writeHidden(RowRecord pRowRecord, int row) {
int rowIx = row; int rowIx = row;
RowRecord rowRecord = pRowRecord; RowRecord rowRecord = pRowRecord;
int level = rowRecord.getOutlineLevel(); int level = rowRecord.getOutlineLevel();
while (rowRecord != null && getRow(rowIx).getOutlineLevel() >= level) { while (rowRecord != null && getRow(rowIx).getOutlineLevel() >= level) {
rowRecord.setZeroHeight(true); rowRecord.setZeroHeight(true);
rowIx++; rowIx++;
rowRecord = getRow(rowIx); rowRecord = getRow(rowIx);
} }
return rowIx; return rowIx;
} }
public void collapseRow(int rowNumber) { public void collapseRow(int rowNumber) {
// Find the start of the group. // Find the start of the group.
int startRow = findStartOfRowOutlineGroup(rowNumber); int startRow = findStartOfRowOutlineGroup(rowNumber);
RowRecord rowRecord = getRow(startRow); RowRecord rowRecord = getRow(startRow);
// Hide all the columns until the end of the group // Hide all the columns until the end of the group
int nextRowIx = writeHidden(rowRecord, startRow); int nextRowIx = writeHidden(rowRecord, startRow);
RowRecord row = getRow(nextRowIx); RowRecord row = getRow(nextRowIx);
if (row == null) { if (row == null) {
row = createRow(nextRowIx); row = createRow(nextRowIx);
insertRow(row); insertRow(row);
} }
// Write collapse field // Write collapse field
row.setColapsed(true); row.setColapsed(true);
} }
/** /**
* Create a row record. * Create a row record.
* *
* @param rowNumber row number * @param rowNumber row number
* @return RowRecord created for the passed in row number * @return RowRecord created for the passed in row number
* @see org.apache.poi.hssf.record.RowRecord * @see org.apache.poi.hssf.record.RowRecord
*/ */
public static RowRecord createRow(int rowNumber) { public static RowRecord createRow(int rowNumber) {
return new RowRecord(rowNumber); return new RowRecord(rowNumber);
} }
public boolean isRowGroupCollapsed(int row) { public boolean isRowGroupCollapsed(int row) {
int collapseRow = findEndOfRowOutlineGroup(row) + 1; int collapseRow = findEndOfRowOutlineGroup(row) + 1;
return getRow(collapseRow) != null && getRow(collapseRow).getColapsed(); return getRow(collapseRow) != null && getRow(collapseRow).getColapsed();
} }
public void expandRow(int rowNumber) { public void expandRow(int rowNumber) {
if (rowNumber == -1) if (rowNumber == -1)
return; return;
// If it is already expanded do nothing. // If it is already expanded do nothing.
if (!isRowGroupCollapsed(rowNumber)) { if (!isRowGroupCollapsed(rowNumber)) {
return; return;
} }
// Find the start of the group. // Find the start of the group.
int startIdx = findStartOfRowOutlineGroup(rowNumber); int startIdx = findStartOfRowOutlineGroup(rowNumber);
RowRecord row = getRow(startIdx); RowRecord row = getRow(startIdx);
// Find the end of the group. // Find the end of the group.
int endIdx = findEndOfRowOutlineGroup(rowNumber); int endIdx = findEndOfRowOutlineGroup(rowNumber);
// expand: // expand:
// collapsed bit must be unset // collapsed bit must be unset
// hidden bit gets unset _if_ surrounding groups are expanded you can determine // hidden bit gets unset _if_ surrounding groups are expanded you can determine
// this by looking at the hidden bit of the enclosing group. You will have // this by looking at the hidden bit of the enclosing group. You will have
// to look at the start and the end of the current group to determine which // to look at the start and the end of the current group to determine which
// is the enclosing group // is the enclosing group
// hidden bit only is altered for this outline level. ie. don't un-collapse contained groups // hidden bit only is altered for this outline level. ie. don't un-collapse contained groups
if (!isRowGroupHiddenByParent(rowNumber)) { if (!isRowGroupHiddenByParent(rowNumber)) {
for (int i = startIdx; i <= endIdx; i++) { for (int i = startIdx; i <= endIdx; i++) {
RowRecord otherRow = getRow(i); RowRecord otherRow = getRow(i);
if (row.getOutlineLevel() == otherRow.getOutlineLevel() || !isRowGroupCollapsed(i)) { if (row.getOutlineLevel() == otherRow.getOutlineLevel() || !isRowGroupCollapsed(i)) {
otherRow.setZeroHeight(false); otherRow.setZeroHeight(false);
} }
} }
} }
// Write collapse field // Write collapse field
getRow(endIdx + 1).setColapsed(false); getRow(endIdx + 1).setColapsed(false);
} }
public boolean isRowGroupHiddenByParent(int row) { public boolean isRowGroupHiddenByParent(int row) {
// Look out outline details of end // Look out outline details of end
int endLevel; int endLevel;
boolean endHidden; boolean endHidden;
int endOfOutlineGroupIdx = findEndOfRowOutlineGroup(row); int endOfOutlineGroupIdx = findEndOfRowOutlineGroup(row);
if (getRow(endOfOutlineGroupIdx + 1) == null) { if (getRow(endOfOutlineGroupIdx + 1) == null) {
endLevel = 0; endLevel = 0;
endHidden = false; endHidden = false;
} else { } else {
endLevel = getRow(endOfOutlineGroupIdx + 1).getOutlineLevel(); endLevel = getRow(endOfOutlineGroupIdx + 1).getOutlineLevel();
endHidden = getRow(endOfOutlineGroupIdx + 1).getZeroHeight(); endHidden = getRow(endOfOutlineGroupIdx + 1).getZeroHeight();
} }
// Look out outline details of start // Look out outline details of start
int startLevel; int startLevel;
boolean startHidden; boolean startHidden;
int startOfOutlineGroupIdx = findStartOfRowOutlineGroup( row ); int startOfOutlineGroupIdx = findStartOfRowOutlineGroup( row );
if (startOfOutlineGroupIdx - 1 < 0 || getRow(startOfOutlineGroupIdx - 1) == null) { if (startOfOutlineGroupIdx - 1 < 0 || getRow(startOfOutlineGroupIdx - 1) == null) {
startLevel = 0; startLevel = 0;
startHidden = false; startHidden = false;
} else { } else {
startLevel = getRow(startOfOutlineGroupIdx - 1).getOutlineLevel(); startLevel = getRow(startOfOutlineGroupIdx - 1).getOutlineLevel();
startHidden = getRow(startOfOutlineGroupIdx - 1).getZeroHeight(); startHidden = getRow(startOfOutlineGroupIdx - 1).getZeroHeight();
} }
if (endLevel > startLevel) { if (endLevel > startLevel) {
return endHidden; return endHidden;
} }
return startHidden; return startHidden;
} }
/** /**
* Returns an iterator for the cell values * Returns an iterator for the cell values
*/ */
public Iterator<CellValueRecordInterface> getCellValueIterator() { public Iterator<CellValueRecordInterface> getCellValueIterator() {
return _valuesAgg.iterator(); return _valuesAgg.iterator();
} }
public IndexRecord createIndexRecord(int indexRecordOffset, int sizeOfInitialSheetRecords) { public IndexRecord createIndexRecord(int indexRecordOffset, int sizeOfInitialSheetRecords) {
IndexRecord result = new IndexRecord(); IndexRecord result = new IndexRecord();
result.setFirstRow(_firstrow); result.setFirstRow(_firstrow);
result.setLastRowAdd1(_lastrow + 1); result.setLastRowAdd1(_lastrow + 1);
// Calculate the size of the records from the end of the BOF // Calculate the size of the records from the end of the BOF
// and up to the RowRecordsAggregate... // and up to the RowRecordsAggregate...
// Add the references to the DBCells in the IndexRecord (one for each block) // 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 // Note: The offsets are relative to the Workbook BOF. Assume that this is
// 0 for now..... // 0 for now.....
int blockCount = getRowBlockCount(); int blockCount = getRowBlockCount();
// Calculate the size of this IndexRecord // Calculate the size of this IndexRecord
int indexRecSize = IndexRecord.getRecordSizeForBlockCount(blockCount); int indexRecSize = IndexRecord.getRecordSizeForBlockCount(blockCount);
int currentOffset = indexRecordOffset + indexRecSize + sizeOfInitialSheetRecords; int currentOffset = indexRecordOffset + indexRecSize + sizeOfInitialSheetRecords;
for (int block = 0; block < blockCount; block++) { for (int block = 0; block < blockCount; block++) {
// each row-block has a DBCELL record. // each row-block has a DBCELL record.
// The offset of each DBCELL record needs to be updated in the INDEX record // The offset of each DBCELL record needs to be updated in the INDEX record
// account for row records in this row-block // account for row records in this row-block
currentOffset += getRowBlockSize(block); currentOffset += getRowBlockSize(block);
// account for cell value records after those // account for cell value records after those
currentOffset += _valuesAgg.getRowCellBlockSize( currentOffset += _valuesAgg.getRowCellBlockSize(
getStartRowNumberForBlock(block), getEndRowNumberForBlock(block)); getStartRowNumberForBlock(block), getEndRowNumberForBlock(block));
// currentOffset is now the location of the DBCELL record for this row-block // currentOffset is now the location of the DBCELL record for this row-block
result.addDbcell(currentOffset); result.addDbcell(currentOffset);
// Add space required to write the DBCELL record (whose reference was just added). // Add space required to write the DBCELL record (whose reference was just added).
currentOffset += (8 + (getRowCountForBlock(block) * 2)); currentOffset += (8 + (getRowCountForBlock(block) * 2));
} }
return result; return result;
} }
public void insertCell(CellValueRecordInterface cvRec) { public void insertCell(CellValueRecordInterface cvRec) {
_valuesAgg.insertCell(cvRec); _valuesAgg.insertCell(cvRec);
} }
public void removeCell(CellValueRecordInterface cvRec) { public void removeCell(CellValueRecordInterface cvRec) {
if (cvRec instanceof FormulaRecordAggregate) { if (cvRec instanceof FormulaRecordAggregate) {
((FormulaRecordAggregate)cvRec).notifyFormulaChanging(); ((FormulaRecordAggregate)cvRec).notifyFormulaChanging();
} }
_valuesAgg.removeCell(cvRec); _valuesAgg.removeCell(cvRec);
} }
public FormulaRecordAggregate createFormula(int row, int col) { public FormulaRecordAggregate createFormula(int row, int col) {
FormulaRecord fr = new FormulaRecord(); FormulaRecord fr = new FormulaRecord();
fr.setRow(row); fr.setRow(row);
fr.setColumn((short) col); fr.setColumn((short) col);
return new FormulaRecordAggregate(fr, null, _sharedValueManager); return new FormulaRecordAggregate(fr, null, _sharedValueManager);
} }
public void updateFormulasAfterRowShift(FormulaShifter formulaShifter, int currentExternSheetIndex) { public void updateFormulasAfterRowShift(FormulaShifter formulaShifter, int currentExternSheetIndex) {
_valuesAgg.updateFormulasAfterRowShift(formulaShifter, currentExternSheetIndex); _valuesAgg.updateFormulasAfterRowShift(formulaShifter, currentExternSheetIndex);
} }
public DimensionsRecord createDimensions() { public DimensionsRecord createDimensions() {
DimensionsRecord result = new DimensionsRecord(); DimensionsRecord result = new DimensionsRecord();
result.setFirstRow(_firstrow); result.setFirstRow(_firstrow);
result.setLastRow(_lastrow); result.setLastRow(_lastrow);
result.setFirstCol((short) _valuesAgg.getFirstCellNum()); result.setFirstCol((short) _valuesAgg.getFirstCellNum());
result.setLastCol((short) _valuesAgg.getLastCellNum()); result.setLastCol((short) _valuesAgg.getLastCellNum());
return result; return result;
} }
} }