From 5b5d4c6777f932c958c14b6e243a5a036f3b52af Mon Sep 17 00:00:00 2001 From: Javen O'Neal Date: Mon, 1 Aug 2016 17:36:06 +0000 Subject: [PATCH] whitespace git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1754782 13f79535-47bb-0310-9956-ffa450edef68 --- .../aggregates/RowRecordsAggregate.java | 880 +++++++++--------- 1 file changed, 440 insertions(+), 440 deletions(-) diff --git a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java index 0319af64e4..5551639b48 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java @@ -34,184 +34,184 @@ import org.apache.poi.ss.formula.FormulaShifter; * @author Jason Height (jheight at chariot dot net dot au) */ public final class RowRecordsAggregate extends RecordAggregate { - private int _firstrow = -1; - private int _lastrow = -1; - private final Map _rowRecords; - private final ValueRecordsAggregate _valuesAgg; - private final List _unknownRecords; - private final SharedValueManager _sharedValueManager; - - // Cache values to speed up performance of + private int _firstrow = -1; + private int _lastrow = -1; + private final Map _rowRecords; + private final ValueRecordsAggregate _valuesAgg; + private final List _unknownRecords; + private final SharedValueManager _sharedValueManager; + + // Cache values to speed up performance of // getStartRowNumberForBlock / getEndRowNumberForBlock, see Bugzilla 47405 private RowRecord[] _rowRecordValues = null; - /** Creates a new instance of ValueRecordsAggregate */ - public RowRecordsAggregate() { - this(SharedValueManager.createEmpty()); - } - private RowRecordsAggregate(SharedValueManager svm) { - if (svm == null) { - throw new IllegalArgumentException("SharedValueManager must be provided."); - } - _rowRecords = new TreeMap(); - _valuesAgg = new ValueRecordsAggregate(); - _unknownRecords = new ArrayList(); - _sharedValueManager = svm; - } - - /** - * @param rs record stream with all {@link SharedFormulaRecord} - * {@link ArrayRecord}, {@link TableRecord} {@link MergeCellsRecord} Records removed - * @param svm an initialised {@link SharedValueManager} (from the shared formula, array - * and table records of the current sheet). Never null. - */ - public RowRecordsAggregate(RecordStream rs, SharedValueManager svm) { - this(svm); - while(rs.hasNext()) { - Record rec = rs.getNext(); - switch (rec.getSid()) { - case RowRecord.sid: - insertRow((RowRecord) rec); - continue; + /** Creates a new instance of ValueRecordsAggregate */ + public RowRecordsAggregate() { + this(SharedValueManager.createEmpty()); + } + private RowRecordsAggregate(SharedValueManager svm) { + if (svm == null) { + throw new IllegalArgumentException("SharedValueManager must be provided."); + } + _rowRecords = new TreeMap(); + _valuesAgg = new ValueRecordsAggregate(); + _unknownRecords = new ArrayList(); + _sharedValueManager = svm; + } + + /** + * @param rs record stream with all {@link SharedFormulaRecord} + * {@link ArrayRecord}, {@link TableRecord} {@link MergeCellsRecord} Records removed + * @param svm an initialised {@link SharedValueManager} (from the shared formula, array + * and table records of the current sheet). Never null. + */ + public RowRecordsAggregate(RecordStream rs, SharedValueManager svm) { + this(svm); + while(rs.hasNext()) { + Record rec = rs.getNext(); + switch (rec.getSid()) { + case RowRecord.sid: + insertRow((RowRecord) rec); + continue; case DConRefRecord.sid: addUnknownRecord(rec); continue; case DBCellRecord.sid: - // end of 'Row Block'. Should only occur after cell records - // ignore DBCELL records because POI generates them upon re-serialization - continue; - } - if (rec instanceof UnknownRecord) { - // might need to keep track of where exactly these belong - addUnknownRecord(rec); - while (rs.peekNextSid() == ContinueRecord.sid) { - addUnknownRecord(rs.getNext()); - } - continue; - } - if (rec instanceof MulBlankRecord) { - _valuesAgg.addMultipleBlanks((MulBlankRecord) rec); - continue; - } - if (!(rec instanceof CellValueRecordInterface)) { - throw new RuntimeException("Unexpected record type (" + rec.getClass().getName() + ")"); - } - _valuesAgg.construct((CellValueRecordInterface)rec, rs, svm); - } - } - /** - * Handles UnknownRecords which appear within the row/cell records - */ - private void addUnknownRecord(Record rec) { - // ony a few distinct record IDs are encountered by the existing POI test cases: - // 0x1065 // many - // 0x01C2 // several - // 0x0034 // few - // No documentation could be found for these - - // keep the unknown records for re-serialization - _unknownRecords.add(rec); - } - public void insertRow(RowRecord row) { - // Integer integer = Integer.valueOf(row.getRowNumber()); - _rowRecords.put(Integer.valueOf(row.getRowNumber()), row); - // Clear the cached values - _rowRecordValues = null; - if ((row.getRowNumber() < _firstrow) || (_firstrow == -1)) { - _firstrow = row.getRowNumber(); - } - if ((row.getRowNumber() > _lastrow) || (_lastrow == -1)) { - _lastrow = row.getRowNumber(); - } - } - - public void removeRow(RowRecord row) { - int rowIndex = row.getRowNumber(); - _valuesAgg.removeAllCellsValuesForRow(rowIndex); - Integer key = Integer.valueOf(rowIndex); - RowRecord rr = _rowRecords.remove(key); - if (rr == null) { - throw new RuntimeException("Invalid row index (" + key.intValue() + ")"); - } - if (row != rr) { - _rowRecords.put(key, rr); - throw new RuntimeException("Attempt to remove row that does not belong to this sheet"); - } - - // Clear the cached values - _rowRecordValues = null; - } - - public RowRecord getRow(int rowIndex) { + // end of 'Row Block'. Should only occur after cell records + // ignore DBCELL records because POI generates them upon re-serialization + continue; + } + if (rec instanceof UnknownRecord) { + // might need to keep track of where exactly these belong + addUnknownRecord(rec); + while (rs.peekNextSid() == ContinueRecord.sid) { + addUnknownRecord(rs.getNext()); + } + continue; + } + if (rec instanceof MulBlankRecord) { + _valuesAgg.addMultipleBlanks((MulBlankRecord) rec); + continue; + } + if (!(rec instanceof CellValueRecordInterface)) { + throw new RuntimeException("Unexpected record type (" + rec.getClass().getName() + ")"); + } + _valuesAgg.construct((CellValueRecordInterface)rec, rs, svm); + } + } + /** + * Handles UnknownRecords which appear within the row/cell records + */ + private void addUnknownRecord(Record rec) { + // ony a few distinct record IDs are encountered by the existing POI test cases: + // 0x1065 // many + // 0x01C2 // several + // 0x0034 // few + // No documentation could be found for these + + // keep the unknown records for re-serialization + _unknownRecords.add(rec); + } + public void insertRow(RowRecord row) { + // Integer integer = Integer.valueOf(row.getRowNumber()); + _rowRecords.put(Integer.valueOf(row.getRowNumber()), row); + // Clear the cached values + _rowRecordValues = null; + if ((row.getRowNumber() < _firstrow) || (_firstrow == -1)) { + _firstrow = row.getRowNumber(); + } + if ((row.getRowNumber() > _lastrow) || (_lastrow == -1)) { + _lastrow = row.getRowNumber(); + } + } + + public void removeRow(RowRecord row) { + int rowIndex = row.getRowNumber(); + _valuesAgg.removeAllCellsValuesForRow(rowIndex); + Integer key = Integer.valueOf(rowIndex); + RowRecord rr = _rowRecords.remove(key); + if (rr == null) { + throw new RuntimeException("Invalid row index (" + key.intValue() + ")"); + } + if (row != rr) { + _rowRecords.put(key, rr); + throw new RuntimeException("Attempt to remove row that does not belong to this sheet"); + } + + // Clear the cached values + _rowRecordValues = null; + } + + public RowRecord getRow(int rowIndex) { int maxrow = SpreadsheetVersion.EXCEL97.getLastRowIndex(); if (rowIndex < 0 || rowIndex > maxrow) { - throw new IllegalArgumentException("The row number must be between 0 and " + maxrow + ", but had: " + rowIndex); - } - return _rowRecords.get(Integer.valueOf(rowIndex)); - } - - public int getPhysicalNumberOfRows() - { - return _rowRecords.size(); - } - - public int getFirstRowNum() - { - return _firstrow; - } - - public int getLastRowNum() - { - return _lastrow; - } - - /** Returns the number of row blocks. - *

The row blocks are goupings of rows that contain the DBCell record - * after them - */ - public int getRowBlockCount() { - int size = _rowRecords.size()/DBCellRecord.BLOCK_SIZE; - if ((_rowRecords.size() % DBCellRecord.BLOCK_SIZE) != 0) - size++; - return size; - } - - private int getRowBlockSize(int block) { - return RowRecord.ENCODED_SIZE * getRowCountForBlock(block); - } - - /** Returns the number of physical rows within a block*/ - public int getRowCountForBlock(int block) { - int startIndex = block * DBCellRecord.BLOCK_SIZE; - int endIndex = startIndex + DBCellRecord.BLOCK_SIZE - 1; - if (endIndex >= _rowRecords.size()) - endIndex = _rowRecords.size()-1; - - return endIndex-startIndex+1; - } - - /** Returns the physical row number of the first row in a block*/ - private int getStartRowNumberForBlock(int block) { - int startIndex = block * DBCellRecord.BLOCK_SIZE; - - if(_rowRecordValues == null){ + throw new IllegalArgumentException("The row number must be between 0 and " + maxrow + ", but had: " + rowIndex); + } + return _rowRecords.get(Integer.valueOf(rowIndex)); + } + + public int getPhysicalNumberOfRows() + { + return _rowRecords.size(); + } + + public int getFirstRowNum() + { + return _firstrow; + } + + public int getLastRowNum() + { + return _lastrow; + } + + /** Returns the number of row blocks. + *

The row blocks are goupings of rows that contain the DBCell record + * after them + */ + public int getRowBlockCount() { + int size = _rowRecords.size()/DBCellRecord.BLOCK_SIZE; + if ((_rowRecords.size() % DBCellRecord.BLOCK_SIZE) != 0) + size++; + return size; + } + + private int getRowBlockSize(int block) { + return RowRecord.ENCODED_SIZE * getRowCountForBlock(block); + } + + /** Returns the number of physical rows within a block*/ + public int getRowCountForBlock(int block) { + int startIndex = block * DBCellRecord.BLOCK_SIZE; + int endIndex = startIndex + DBCellRecord.BLOCK_SIZE - 1; + if (endIndex >= _rowRecords.size()) + endIndex = _rowRecords.size()-1; + + return endIndex-startIndex+1; + } + + /** Returns the physical row number of the first row in a block*/ + private int getStartRowNumberForBlock(int block) { + int startIndex = block * DBCellRecord.BLOCK_SIZE; + + if (_rowRecordValues == null) { _rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]); } try { return _rowRecordValues[startIndex].getRowNumber(); } 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*/ - private int getEndRowNumberForBlock(int block) { - int endIndex = ((block + 1)*DBCellRecord.BLOCK_SIZE)-1; - if (endIndex >= _rowRecords.size()) - endIndex = _rowRecords.size()-1; + /** Returns the physical row number of the end row in a block*/ + private int getEndRowNumberForBlock(int block) { + int endIndex = ((block + 1)*DBCellRecord.BLOCK_SIZE)-1; + if (endIndex >= _rowRecords.size()) + endIndex = _rowRecords.size()-1; - if(_rowRecordValues == null){ + if (_rowRecordValues == null){ _rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]); } @@ -219,287 +219,287 @@ public final class RowRecordsAggregate extends RecordAggregate { return _rowRecordValues[endIndex].getRowNumber(); } catch(ArrayIndexOutOfBoundsException e) { throw new RuntimeException("Did not find end row for block " + block); - } - } - - private int visitRowRecordsForBlock(int blockIndex, RecordVisitor rv) { - final int startIndex = blockIndex*DBCellRecord.BLOCK_SIZE; - final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE; - - Iterator rowIterator = _rowRecords.values().iterator(); - - //Given that we basically iterate through the rows in order, - //For a performance improvement, it would be better to return an instance of - //an iterator and use that instance throughout, rather than recreating one and - //having to move it to the right position. - int i=0; - for (;i rowIterator = _rowRecords.values().iterator(); + + //Given that we basically iterate through the rows in order, + //For a performance improvement, it would be better to return an instance of + //an iterator and use that instance throughout, rather than recreating one and + //having to move it to the right position. + int i=0; + for (;i getIterator() { - return _rowRecords.values().iterator(); - } - - public int findStartOfRowOutlineGroup(int row) { - // Find the start of the group. - RowRecord rowRecord = this.getRow( row ); - int level = rowRecord.getOutlineLevel(); - int currentRow = row; - while (currentRow >= 0 && this.getRow( currentRow ) != null) { - rowRecord = this.getRow( currentRow ); - if (rowRecord.getOutlineLevel() < level) { - return currentRow + 1; - } - currentRow--; - } - - return currentRow + 1; - } - - public int findEndOfRowOutlineGroup(int row) { - int level = getRow( row ).getOutlineLevel(); - int currentRow; - for (currentRow = row; currentRow < getLastRowNum(); currentRow++) { - if (getRow(currentRow) == null || getRow(currentRow).getOutlineLevel() < level) { - break; - } - } - - return currentRow-1; - } - - /** - * Hide all rows at or below the current outline level - * @return index of the next row after the last row that gets hidden - */ - private int writeHidden(RowRecord pRowRecord, int row) { - int rowIx = row; - RowRecord rowRecord = pRowRecord; - int level = rowRecord.getOutlineLevel(); - while (rowRecord != null && getRow(rowIx).getOutlineLevel() >= level) { - rowRecord.setZeroHeight(true); - rowIx++; - rowRecord = getRow(rowIx); - } - return rowIx; - } - - public void collapseRow(int rowNumber) { - - // Find the start of the group. - int startRow = findStartOfRowOutlineGroup(rowNumber); - RowRecord rowRecord = getRow(startRow); - - // Hide all the columns until the end of the group - int nextRowIx = writeHidden(rowRecord, startRow); - - RowRecord row = getRow(nextRowIx); - if (row == null) { - row = createRow(nextRowIx); - insertRow(row); - } - // Write collapse field - row.setColapsed(true); - } - - /** - * Create a row record. - * - * @param rowNumber row number - * @return RowRecord created for the passed in row number - * @see org.apache.poi.hssf.record.RowRecord - */ - public static RowRecord createRow(int rowNumber) { - return new RowRecord(rowNumber); - } - - public boolean isRowGroupCollapsed(int row) { - int collapseRow = findEndOfRowOutlineGroup(row) + 1; - - return getRow(collapseRow) != null && getRow(collapseRow).getColapsed(); - } - - public void expandRow(int rowNumber) { - if (rowNumber == -1) - return; - - // If it is already expanded do nothing. - if (!isRowGroupCollapsed(rowNumber)) { - return; - } - - // Find the start of the group. - int startIdx = findStartOfRowOutlineGroup(rowNumber); - RowRecord row = getRow(startIdx); - - // Find the end of the group. - int endIdx = findEndOfRowOutlineGroup(rowNumber); - - // expand: - // collapsed bit must be unset - // 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 - // to look at the start and the end of the current group to determine which - // is the enclosing group - // hidden bit only is altered for this outline level. ie. don't un-collapse contained groups - if (!isRowGroupHiddenByParent(rowNumber)) { - for (int i = startIdx; i <= endIdx; i++) { - RowRecord otherRow = getRow(i); - if (row.getOutlineLevel() == otherRow.getOutlineLevel() || !isRowGroupCollapsed(i)) { - otherRow.setZeroHeight(false); - } - } - } - - // Write collapse field - getRow(endIdx + 1).setColapsed(false); - } - - public boolean isRowGroupHiddenByParent(int row) { - // Look out outline details of end - int endLevel; - boolean endHidden; - int endOfOutlineGroupIdx = findEndOfRowOutlineGroup(row); - if (getRow(endOfOutlineGroupIdx + 1) == null) { - endLevel = 0; - endHidden = false; - } else { - endLevel = getRow(endOfOutlineGroupIdx + 1).getOutlineLevel(); - endHidden = getRow(endOfOutlineGroupIdx + 1).getZeroHeight(); - } - - // Look out outline details of start - int startLevel; - boolean startHidden; - int startOfOutlineGroupIdx = findStartOfRowOutlineGroup( row ); - if (startOfOutlineGroupIdx - 1 < 0 || getRow(startOfOutlineGroupIdx - 1) == null) { - startLevel = 0; - startHidden = false; - } else { - startLevel = getRow(startOfOutlineGroupIdx - 1).getOutlineLevel(); - startHidden = getRow(startOfOutlineGroupIdx - 1).getZeroHeight(); - } - - if (endLevel > startLevel) { - return endHidden; - } - - return startHidden; - } - - /** - * Returns an iterator for the cell values - */ - public Iterator getCellValueIterator() { - return _valuesAgg.iterator(); - } - - 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 insertCell(CellValueRecordInterface cvRec) { - _valuesAgg.insertCell(cvRec); - } - public void removeCell(CellValueRecordInterface cvRec) { - if (cvRec instanceof FormulaRecordAggregate) { - ((FormulaRecordAggregate)cvRec).notifyFormulaChanging(); - } - _valuesAgg.removeCell(cvRec); - } - public FormulaRecordAggregate createFormula(int row, int col) { - FormulaRecord fr = new FormulaRecord(); - fr.setRow(row); - fr.setColumn((short) col); - return new FormulaRecordAggregate(fr, null, _sharedValueManager); - } - public void updateFormulasAfterRowShift(FormulaShifter formulaShifter, int currentExternSheetIndex) { - _valuesAgg.updateFormulasAfterRowShift(formulaShifter, currentExternSheetIndex); - } - public DimensionsRecord createDimensions() { - DimensionsRecord result = new DimensionsRecord(); - result.setFirstRow(_firstrow); - result.setLastRow(_lastrow); - result.setFirstCol((short) _valuesAgg.getFirstCellNum()); - result.setLastCol((short) _valuesAgg.getLastCellNum()); - return result; - } + PositionTrackingVisitor stv = new PositionTrackingVisitor(rv, 0); + //DBCells are serialized before row records. + final int blockCount = getRowBlockCount(); + for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) { + // Serialize a block of rows. + // Hold onto the position of the first row in the block + int pos=0; + // Hold onto the size of this block that was serialized + final int rowBlockSize = visitRowRecordsForBlock(blockIndex, rv); + pos += rowBlockSize; + // Serialize a block of cells for those rows + final int startRowNumber = getStartRowNumberForBlock(blockIndex); + final int endRowNumber = getEndRowNumberForBlock(blockIndex); + DBCellRecord.Builder dbcrBuilder = new DBCellRecord.Builder(); + // Note: Cell references start from the second row... + int cellRefOffset = (rowBlockSize - RowRecord.ENCODED_SIZE); + for (int row = startRowNumber; row <= endRowNumber; row++) { + if (_valuesAgg.rowHasCells(row)) { + stv.setPosition(0); + _valuesAgg.visitCellsForRow(row, stv); + int rowCellSize = stv.getPosition(); + pos += rowCellSize; + // Add the offset to the first cell for the row into the + // DBCellRecord. + dbcrBuilder.addCellOffset(cellRefOffset); + cellRefOffset = rowCellSize; + } + } + // Calculate Offset from the start of a DBCellRecord to the first Row + rv.visitRecord(dbcrBuilder.build(pos)); + } + for (Record _unknownRecord : _unknownRecords) { + // Potentially breaking the file here since we don't know exactly where to write these records + rv.visitRecord(_unknownRecord); + } + } + + public Iterator getIterator() { + return _rowRecords.values().iterator(); + } + + public int findStartOfRowOutlineGroup(int row) { + // Find the start of the group. + RowRecord rowRecord = this.getRow( row ); + int level = rowRecord.getOutlineLevel(); + int currentRow = row; + while (currentRow >= 0 && this.getRow( currentRow ) != null) { + rowRecord = this.getRow( currentRow ); + if (rowRecord.getOutlineLevel() < level) { + return currentRow + 1; + } + currentRow--; + } + + return currentRow + 1; + } + + public int findEndOfRowOutlineGroup(int row) { + int level = getRow( row ).getOutlineLevel(); + int currentRow; + for (currentRow = row; currentRow < getLastRowNum(); currentRow++) { + if (getRow(currentRow) == null || getRow(currentRow).getOutlineLevel() < level) { + break; + } + } + + return currentRow-1; + } + + /** + * Hide all rows at or below the current outline level + * @return index of the next row after the last row that gets hidden + */ + private int writeHidden(RowRecord pRowRecord, int row) { + int rowIx = row; + RowRecord rowRecord = pRowRecord; + int level = rowRecord.getOutlineLevel(); + while (rowRecord != null && getRow(rowIx).getOutlineLevel() >= level) { + rowRecord.setZeroHeight(true); + rowIx++; + rowRecord = getRow(rowIx); + } + return rowIx; + } + + public void collapseRow(int rowNumber) { + + // Find the start of the group. + int startRow = findStartOfRowOutlineGroup(rowNumber); + RowRecord rowRecord = getRow(startRow); + + // Hide all the columns until the end of the group + int nextRowIx = writeHidden(rowRecord, startRow); + + RowRecord row = getRow(nextRowIx); + if (row == null) { + row = createRow(nextRowIx); + insertRow(row); + } + // Write collapse field + row.setColapsed(true); + } + + /** + * Create a row record. + * + * @param rowNumber row number + * @return RowRecord created for the passed in row number + * @see org.apache.poi.hssf.record.RowRecord + */ + public static RowRecord createRow(int rowNumber) { + return new RowRecord(rowNumber); + } + + public boolean isRowGroupCollapsed(int row) { + int collapseRow = findEndOfRowOutlineGroup(row) + 1; + + return getRow(collapseRow) != null && getRow(collapseRow).getColapsed(); + } + + public void expandRow(int rowNumber) { + if (rowNumber == -1) + return; + + // If it is already expanded do nothing. + if (!isRowGroupCollapsed(rowNumber)) { + return; + } + + // Find the start of the group. + int startIdx = findStartOfRowOutlineGroup(rowNumber); + RowRecord row = getRow(startIdx); + + // Find the end of the group. + int endIdx = findEndOfRowOutlineGroup(rowNumber); + + // expand: + // collapsed bit must be unset + // 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 + // to look at the start and the end of the current group to determine which + // is the enclosing group + // hidden bit only is altered for this outline level. ie. don't un-collapse contained groups + if (!isRowGroupHiddenByParent(rowNumber)) { + for (int i = startIdx; i <= endIdx; i++) { + RowRecord otherRow = getRow(i); + if (row.getOutlineLevel() == otherRow.getOutlineLevel() || !isRowGroupCollapsed(i)) { + otherRow.setZeroHeight(false); + } + } + } + + // Write collapse field + getRow(endIdx + 1).setColapsed(false); + } + + public boolean isRowGroupHiddenByParent(int row) { + // Look out outline details of end + int endLevel; + boolean endHidden; + int endOfOutlineGroupIdx = findEndOfRowOutlineGroup(row); + if (getRow(endOfOutlineGroupIdx + 1) == null) { + endLevel = 0; + endHidden = false; + } else { + endLevel = getRow(endOfOutlineGroupIdx + 1).getOutlineLevel(); + endHidden = getRow(endOfOutlineGroupIdx + 1).getZeroHeight(); + } + + // Look out outline details of start + int startLevel; + boolean startHidden; + int startOfOutlineGroupIdx = findStartOfRowOutlineGroup( row ); + if (startOfOutlineGroupIdx - 1 < 0 || getRow(startOfOutlineGroupIdx - 1) == null) { + startLevel = 0; + startHidden = false; + } else { + startLevel = getRow(startOfOutlineGroupIdx - 1).getOutlineLevel(); + startHidden = getRow(startOfOutlineGroupIdx - 1).getZeroHeight(); + } + + if (endLevel > startLevel) { + return endHidden; + } + + return startHidden; + } + + /** + * Returns an iterator for the cell values + */ + public Iterator getCellValueIterator() { + return _valuesAgg.iterator(); + } + + 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 insertCell(CellValueRecordInterface cvRec) { + _valuesAgg.insertCell(cvRec); + } + public void removeCell(CellValueRecordInterface cvRec) { + if (cvRec instanceof FormulaRecordAggregate) { + ((FormulaRecordAggregate)cvRec).notifyFormulaChanging(); + } + _valuesAgg.removeCell(cvRec); + } + public FormulaRecordAggregate createFormula(int row, int col) { + FormulaRecord fr = new FormulaRecord(); + fr.setRow(row); + fr.setColumn((short) col); + return new FormulaRecordAggregate(fr, null, _sharedValueManager); + } + public void updateFormulasAfterRowShift(FormulaShifter formulaShifter, int currentExternSheetIndex) { + _valuesAgg.updateFormulasAfterRowShift(formulaShifter, currentExternSheetIndex); + } + public DimensionsRecord createDimensions() { + DimensionsRecord result = new DimensionsRecord(); + result.setFirstRow(_firstrow); + result.setLastRow(_lastrow); + result.setFirstCol((short) _valuesAgg.getFirstCellNum()); + result.setLastCol((short) _valuesAgg.getLastCellNum()); + return result; + } } -- 2.39.5