You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by on...@apache.org on 2016/08/01 17:36:06 UTC

svn commit: r1754782 - /poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java

Author: onealj
Date: Mon Aug  1 17:36:06 2016
New Revision: 1754782

URL: http://svn.apache.org/viewvc?rev=1754782&view=rev
Log:
whitespace

Modified:
    poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java?rev=1754782&r1=1754781&r2=1754782&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java Mon Aug  1 17:36:06 2016
@@ -34,184 +34,184 @@ import org.apache.poi.ss.formula.Formula
  * @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<Integer, RowRecord> _rowRecords;
-	private final ValueRecordsAggregate _valuesAgg;
-	private final List<Record> _unknownRecords;
-	private final SharedValueManager _sharedValueManager;
+    private int _firstrow = -1;
+    private int _lastrow  = -1;
+    private final Map<Integer, RowRecord> _rowRecords;
+    private final ValueRecordsAggregate _valuesAgg;
+    private final List<Record> _unknownRecords;
+    private final SharedValueManager _sharedValueManager;
 
-	// Cache values to speed up performance of
+    // 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<Integer, RowRecord>();
-		_valuesAgg = new ValueRecordsAggregate();
-		_unknownRecords = new ArrayList<Record>();
-		_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 <code>null</code>.
-	 */
-	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<Integer, RowRecord>();
+        _valuesAgg = new ValueRecordsAggregate();
+        _unknownRecords = new ArrayList<Record>();
+        _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 <code>null</code>.
+     */
+    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;
-	}
+                    // 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 RowRecord getRow(int rowIndex) {
+    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.
-	 * <p/>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;
+            throw new IllegalArgumentException("The row number must be between 0 and " + maxrow + ", but had: " + rowIndex);
+        }
+        return _rowRecords.get(Integer.valueOf(rowIndex));
+    }
 
-        if(_rowRecordValues == null){
+    public int getPhysicalNumberOfRows()
+    {
+        return _rowRecords.size();
+    }
+
+    public int getFirstRowNum()
+    {
+        return _firstrow;
+    }
+
+    public int getLastRowNum()
+    {
+        return _lastrow;
+    }
+
+    /** Returns the number of row blocks.
+     * <p/>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);
-	    }
-	}
-
-	/** 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;
+            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;
 
-        if(_rowRecordValues == null){
+        if (_rowRecordValues == null){
             _rowRecordValues = _rowRecords.values().toArray(new RowRecord[_rowRecords.size()]);
         }
 
@@ -219,287 +219,287 @@ public final class RowRecordsAggregate e
             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<RowRecord> 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<startIndex;i++)
-		  rowIterator.next();
-		int result = 0;
-		while(rowIterator.hasNext() && (i++ < endIndex)) {
-		  Record rec = rowIterator.next();
-		  result += rec.getRecordSize();
-		  rv.visitRecord(rec);
-		}
-		return result;
-	}
+    private int visitRowRecordsForBlock(int blockIndex, RecordVisitor rv) {
+        final int startIndex = blockIndex*DBCellRecord.BLOCK_SIZE;
+        final int endIndex = startIndex + DBCellRecord.BLOCK_SIZE;
+
+        Iterator<RowRecord> 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<startIndex;i++)
+          rowIterator.next();
+        int result = 0;
+        while(rowIterator.hasNext() && (i++ < endIndex)) {
+          Record rec = rowIterator.next();
+          result += rec.getRecordSize();
+          rv.visitRecord(rec);
+        }
+        return result;
+    }
 
     @Override
     public void visitContainedRecords(RecordVisitor rv) {
 
-		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<RowRecord> 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 <em>next<em> 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<CellValueRecordInterface> 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<RowRecord> 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 <em>next<em> 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<CellValueRecordInterface> 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;
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org