diff options
author | Josh Micich <josh@apache.org> | 2008-09-17 21:23:58 +0000 |
---|---|---|
committer | Josh Micich <josh@apache.org> | 2008-09-17 21:23:58 +0000 |
commit | fe820eed5c4aba26347a7d117ffd9f4d052552de (patch) | |
tree | a2b0e4ea093222e951842a3d89928ad3113ad42b /src/java | |
parent | 3ed09846f965e2f382f3149a1520fdc5e9b29d86 (diff) | |
download | poi-fe820eed5c4aba26347a7d117ffd9f4d052552de.tar.gz poi-fe820eed5c4aba26347a7d117ffd9f4d052552de.zip |
merged 696038 from trunk - (Fix for bug 45780 - update area refs during HSSFSheet.shiftRows())
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@696453 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java')
20 files changed, 611 insertions, 371 deletions
diff --git a/src/java/org/apache/poi/hssf/model/Sheet.java b/src/java/org/apache/poi/hssf/model/Sheet.java index 8bbc30435a..164399939a 100644 --- a/src/java/org/apache/poi/hssf/model/Sheet.java +++ b/src/java/org/apache/poi/hssf/model/Sheet.java @@ -62,7 +62,6 @@ import org.apache.poi.hssf.record.aggregates.CFRecordsAggregate; import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate; import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable; import org.apache.poi.hssf.record.aggregates.DataValidityTable; -import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; import org.apache.poi.hssf.record.aggregates.MergedCellsTable; import org.apache.poi.hssf.record.aggregates.PageSettingsBlock; import org.apache.poi.hssf.record.aggregates.RecordAggregate; @@ -127,7 +126,8 @@ public final class Sheet implements Model { /*package*/ColumnInfoRecordsAggregate _columnInfos; /** the DimensionsRecord is always present */ private DimensionsRecord _dimensions; - protected RowRecordsAggregate _rowsAggregate = null; + /** always present */ + protected RowRecordsAggregate _rowsAggregate; private DataValidityTable _dataValidityTable= null; private ConditionalFormattingTable condFormatting; @@ -329,10 +329,13 @@ public final class Sheet implements Model { if (retval.windowTwo == null) { throw new RuntimeException("WINDOW2 was not found"); } + if (retval._rowsAggregate == null) { + retval._rowsAggregate = new RowRecordsAggregate(); + records.add(retval.dimsloc + 1, retval._rowsAggregate); + } // put merged cells table in the right place (regardless of where the first MergedCellsRecord was found */ RecordOrderer.addNewSheetRecord(records, retval._mergedCellsTable); retval.records = records; - retval.checkRows(); if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited"); return retval; @@ -441,6 +444,8 @@ public final class Sheet implements Model { retval._dimensions = createDimensions(); records.add(retval._dimensions); retval.dimsloc = records.size()-1; + retval._rowsAggregate = new RowRecordsAggregate(); + records.add(retval._rowsAggregate); // 'Sheet View Settings' records.add(retval.windowTwo = retval.createWindowTwo()); retval.selection = createSelection(); @@ -456,14 +461,10 @@ public final class Sheet implements Model { return retval; } - private void checkRows() - { - if (_rowsAggregate == null) - { - _rowsAggregate = new RowRecordsAggregate(); - records.add(dimsloc + 1, _rowsAggregate); - } + public RowRecordsAggregate getRowsAggregate() { + return _rowsAggregate; } + private MergedCellsTable getMergedRecords() { // always present return _mergedCellsTable; @@ -624,13 +625,6 @@ public final class Sheet implements Model { } /** - * Create a row record. (does not add it to the records contained in this sheet) - */ - private static RowRecord createRow(int row) { - return RowRecordsAggregate.createRow( row ); - } - - /** * Adds a value record to the sheet's contained binary records * (i.e. LabelSSTRecord or NumberRecord). * <P> @@ -714,7 +708,6 @@ public final class Sheet implements Model { public void addRow(RowRecord row) { - checkRows(); if (log.check( POILogger.DEBUG )) log.log(POILogger.DEBUG, "addRow "); DimensionsRecord d = _dimensions; @@ -748,7 +741,6 @@ public final class Sheet implements Model { * @param row the row record to remove */ public void removeRow(RowRecord row) { - checkRows(); _rowsAggregate.removeRow(row); } @@ -1295,7 +1287,7 @@ public final class Sheet implements Model { } /** - * Returns the first occurance of a record matching a particular sid. + * Returns the first occurrence of a record matching a particular sid. */ public Record findFirstRecordBySid(short sid) @@ -1781,13 +1773,12 @@ public final class Sheet implements Model { public void groupRowRange(int fromRow, int toRow, boolean indent) { - checkRows(); for (int rowNum = fromRow; rowNum <= toRow; rowNum++) { RowRecord row = getRow( rowNum ); if (row == null) { - row = createRow( rowNum ); + row = RowRecordsAggregate.createRow(rowNum); addRow( row ); } int level = row.getOutlineLevel(); @@ -1817,17 +1808,6 @@ public final class Sheet implements Model { guts.setLeftRowGutter( (short) ( 29 + (12 * (maxLevel)) ) ); } - public void setRowGroupCollapsed( int row, boolean collapse ) - { - if (collapse) - { - _rowsAggregate.collapseRow( row ); - } - else - { - _rowsAggregate.expandRow( row ); - } - } public DataValidityTable getOrCreateDataValidityTable() { if (_dataValidityTable == null) { DataValidityTable result = new DataValidityTable(); @@ -1836,8 +1816,4 @@ public final class Sheet implements Model { } return _dataValidityTable; } - - public FormulaRecordAggregate createFormula(int row, int col) { - return _rowsAggregate.createFormula(row, col); - } } diff --git a/src/java/org/apache/poi/hssf/record/NameRecord.java b/src/java/org/apache/poi/hssf/record/NameRecord.java index 0716c448d8..215c20feec 100644 --- a/src/java/org/apache/poi/hssf/record/NameRecord.java +++ b/src/java/org/apache/poi/hssf/record/NameRecord.java @@ -537,9 +537,7 @@ public final class NameRecord extends Record { temp.add(ptg); } } else { - Ptg ptg = new Ref3DPtg(); - ((Ref3DPtg) ptg).setExternSheetIndex(externSheetIndex); - ((Ref3DPtg) ptg).setArea(ref); + Ref3DPtg ptg = new Ref3DPtg(ra.getFromCell(), externSheetIndex); temp.add(ptg); } Ptg[] ptgs = new Ptg[temp.size()]; 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 c5bbc31199..c7610de1ea 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java @@ -35,6 +35,7 @@ import org.apache.poi.hssf.record.RowRecord; import org.apache.poi.hssf.record.SharedFormulaRecord; import org.apache.poi.hssf.record.TableRecord; import org.apache.poi.hssf.record.UnknownRecord; +import org.apache.poi.hssf.record.formula.FormulaShifter; /** * @@ -507,4 +508,7 @@ public final class RowRecordsAggregate extends RecordAggregate { fr.setColumn((short) col); return new FormulaRecordAggregate(fr, null, _sharedValueManager); } + public void updateFormulasAfterRowShift(FormulaShifter formulaShifter, int currentExternSheetIndex) { + _valuesAgg.updateFormulasAfterRowShift(formulaShifter, currentExternSheetIndex); + } } diff --git a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java index 4552be797a..a9b1de2531 100644 --- a/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java +++ b/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java @@ -28,6 +28,8 @@ import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.RecordBase; import org.apache.poi.hssf.record.StringRecord; import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor; +import org.apache.poi.hssf.record.formula.FormulaShifter; +import org.apache.poi.hssf.record.formula.Ptg; /** * @@ -225,6 +227,25 @@ public final class ValueRecordsAggregate { } } + public void updateFormulasAfterRowShift(FormulaShifter shifter, int currentExternSheetIndex) { + for (int i = 0; i < records.length; i++) { + CellValueRecordInterface[] rowCells = records[i]; + if (rowCells == null) { + continue; + } + for (int j = 0; j < rowCells.length; j++) { + CellValueRecordInterface cell = rowCells[j]; + if (cell instanceof FormulaRecordAggregate) { + FormulaRecord fr = ((FormulaRecordAggregate)cell).getFormulaRecord(); + Ptg[] ptgs = fr.getParsedExpression(); // needs clone() inside this getter? + if (shifter.adjustFormula(ptgs, currentExternSheetIndex)) { + fr.setParsedExpression(ptgs); + } + } + } + } + } + public CellValueRecordInterface[] getValueRecords() { List temp = new ArrayList(); diff --git a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java index 2183cc2dd0..0c97d03d29 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java @@ -90,24 +90,6 @@ public final class Area3DPtg extends AreaPtgBase { * formulas. The sheet name will get properly delimited if required. */ public String toFormulaString(Workbook book) { - // First do the sheet name - StringBuffer retval = new StringBuffer(); - String sheetName = book.findSheetNameFromExternSheet(field_1_index_extern_sheet); - if(sheetName != null) { - if(sheetName.length() == 0) { - // What excel does if sheet has been deleted - sheetName = "#REF"; - retval.append(sheetName); - } else { - // Normal - SheetNameFormatter.appendFormat(retval, sheetName); - } - retval.append( '!' ); - } - - // Now the normal area bit - retval.append(formatReferenceAsString()); - - return retval.toString(); + return ExternSheetNameResolver.prependSheetName(book, field_1_index_extern_sheet, formatReferenceAsString()); } } diff --git a/src/java/org/apache/poi/hssf/record/formula/AreaErrPtg.java b/src/java/org/apache/poi/hssf/record/formula/AreaErrPtg.java index f1af9b68d1..1387e76856 100644 --- a/src/java/org/apache/poi/hssf/record/formula/AreaErrPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/AreaErrPtg.java @@ -18,6 +18,7 @@ package org.apache.poi.hssf.record.formula; import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.ss.usermodel.ErrorConstants; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.util.LittleEndian; @@ -27,23 +28,31 @@ import org.apache.poi.util.LittleEndian; * @author Daniel Noll (daniel at nuix dot com dot au) */ public final class AreaErrPtg extends OperandPtg { - public final static byte sid = 0x2b; - - public AreaErrPtg(RecordInputStream in) { - // 8 bytes unused: - in.readInt(); - in.readInt(); - } - - public void writeBytes(byte [] array, int offset) { - array[offset] = (byte) (sid + getPtgClass()); - LittleEndian.putInt(array, offset+1, 0); - LittleEndian.putInt(array, offset+5, 0); - } - - public String toFormulaString(Workbook book) { - return "#REF!"; - } + public final static byte sid = 0x2B; + private final int unused1; + private final int unused2; + + public AreaErrPtg() { + unused1 = 0; + unused2 = 0; + } + + public AreaErrPtg(RecordInputStream in) { + // 8 bytes unused: + unused1 = in.readInt(); + unused2 = in.readInt(); + } + + public void writeBytes(byte[] array, int offset) { + LittleEndian.putByte(array, offset + 0, sid + getPtgClass()); + LittleEndian.putInt(array, offset + 1, unused1); + LittleEndian.putInt(array, offset + 5, unused2); + } + + + public String toFormulaString(Workbook book) { + return ErrorConstants.getText(ErrorConstants.ERROR_REF); + } public byte getDefaultOperandClass() { return Ptg.CLASS_REF; diff --git a/src/java/org/apache/poi/hssf/record/formula/DeletedArea3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/DeletedArea3DPtg.java index a1c5b3db59..92506dfbe7 100644 --- a/src/java/org/apache/poi/hssf/record/formula/DeletedArea3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/DeletedArea3DPtg.java @@ -35,13 +35,21 @@ public final class DeletedArea3DPtg extends OperandPtg { private final int unused1; private final int unused2; - public DeletedArea3DPtg( RecordInputStream in) { + public DeletedArea3DPtg(int externSheetIndex) { + field_1_index_extern_sheet = externSheetIndex; + unused1 = 0; + unused2 = 0; + } + + public DeletedArea3DPtg(RecordInputStream in) { field_1_index_extern_sheet = in.readUShort(); unused1 = in.readInt(); unused2 = in.readInt(); } + public String toFormulaString(Workbook book) { - return ErrorConstants.getText(ErrorConstants.ERROR_REF); + return ExternSheetNameResolver.prependSheetName(book, field_1_index_extern_sheet, + ErrorConstants.getText(ErrorConstants.ERROR_REF)); } public byte getDefaultOperandClass() { return Ptg.CLASS_REF; diff --git a/src/java/org/apache/poi/hssf/record/formula/DeletedRef3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/DeletedRef3DPtg.java index 9312b2d766..900a48fe8e 100644 --- a/src/java/org/apache/poi/hssf/record/formula/DeletedRef3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/DeletedRef3DPtg.java @@ -41,8 +41,14 @@ public final class DeletedRef3DPtg extends OperandPtg { unused1 = in.readInt(); } + public DeletedRef3DPtg(int externSheetIndex) { + field_1_index_extern_sheet = externSheetIndex; + unused1 = 0; + } + public String toFormulaString(Workbook book) { - return ErrorConstants.getText(ErrorConstants.ERROR_REF); + return ExternSheetNameResolver.prependSheetName(book, field_1_index_extern_sheet, + ErrorConstants.getText(ErrorConstants.ERROR_REF)); } public byte getDefaultOperandClass() { return Ptg.CLASS_REF; diff --git a/src/java/org/apache/poi/hssf/record/formula/ExternSheetNameResolver.java b/src/java/org/apache/poi/hssf/record/formula/ExternSheetNameResolver.java new file mode 100644 index 0000000000..b928931b09 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/formula/ExternSheetNameResolver.java @@ -0,0 +1,44 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.formula; + +import org.apache.poi.ss.usermodel.Workbook; + +/** + * @author Josh Micich + */ +final class ExternSheetNameResolver { + + private ExternSheetNameResolver() { + // no instances of this class + } + + public static String prependSheetName(Workbook book, int field_1_index_extern_sheet, String cellRefText) { + String sheetName = book.findSheetNameFromExternSheet(field_1_index_extern_sheet); + StringBuffer sb = new StringBuffer(sheetName.length() + cellRefText.length() + 4); + if (sheetName.length() < 1) { + // What excel does if sheet has been deleted + sb.append("#REF"); // note - '!' added just once below + } else { + SheetNameFormatter.appendFormat(sb, sheetName); + } + sb.append('!'); + sb.append(cellRefText); + return sb.toString(); + } +} diff --git a/src/java/org/apache/poi/hssf/record/formula/FormulaShifter.java b/src/java/org/apache/poi/hssf/record/formula/FormulaShifter.java new file mode 100644 index 0000000000..87683d64ee --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/formula/FormulaShifter.java @@ -0,0 +1,294 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.formula; + + +/** + * @author Josh Micich + */ +public final class FormulaShifter { + + /** + * Extern sheet index of sheet where moving is occurring + */ + private final int _externSheetIndex; + private final int _firstMovedIndex; + private final int _lastMovedIndex; + private final int _amountToMove; + + private FormulaShifter(int externSheetIndex, int firstMovedIndex, int lastMovedIndex, int amountToMove) { + if (amountToMove == 0) { + throw new IllegalArgumentException("amountToMove must not be zero"); + } + if (firstMovedIndex > lastMovedIndex) { + throw new IllegalArgumentException("firstMovedIndex, lastMovedIndex out of order"); + } + _externSheetIndex = externSheetIndex; + _firstMovedIndex = firstMovedIndex; + _lastMovedIndex = lastMovedIndex; + _amountToMove = amountToMove; + } + + public static FormulaShifter createForRowShift(int externSheetIndex, int firstMovedRowIndex, int lastMovedRowIndex, int numberOfRowsToMove) { + return new FormulaShifter(externSheetIndex, firstMovedRowIndex, lastMovedRowIndex, numberOfRowsToMove); + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append(getClass().getName()); + sb.append(" ["); + sb.append(_firstMovedIndex); + sb.append(_lastMovedIndex); + sb.append(_amountToMove); + return sb.toString(); + } + + /** + * @param ptgs - if necessary, will get modified by this method + * @param currentExternSheetIx - the extern sheet index of the sheet that contains the formula being adjusted + * @return <code>true</code> if a change was made to the formula tokens + */ + public boolean adjustFormula(Ptg[] ptgs, int currentExternSheetIx) { + boolean refsWereChanged = false; + for(int i=0; i<ptgs.length; i++) { + Ptg newPtg = adjustPtg(ptgs[i], currentExternSheetIx); + if (newPtg != null) { + refsWereChanged = true; + ptgs[i] = newPtg; + } + } + return refsWereChanged; + } + + private Ptg adjustPtg(Ptg ptg, int currentExternSheetIx) { + return adjustPtgDueToRowMove(ptg, currentExternSheetIx); + } + /** + * @return <code>true</code> if this Ptg needed to be changed + */ + private Ptg adjustPtgDueToRowMove(Ptg ptg, int currentExternSheetIx) { + if(ptg instanceof RefPtg) { + if (currentExternSheetIx != _externSheetIndex) { + // local refs on other sheets are unaffected + return null; + } + RefPtg rptg = (RefPtg)ptg; + return rowMoveRefPtg(rptg); + } + if(ptg instanceof Ref3DPtg) { + Ref3DPtg rptg = (Ref3DPtg)ptg; + if (_externSheetIndex != rptg.getExternSheetIndex()) { + // only move 3D refs that refer to the sheet with cells being moved + // (currentExternSheetIx is irrelevant) + return null; + } + return rowMoveRefPtg(rptg); + } + if(ptg instanceof Area2DPtgBase) { + if (currentExternSheetIx != _externSheetIndex) { + // local refs on other sheets are unaffected + return ptg; + } + return rowMoveAreaPtg((Area2DPtgBase)ptg); + } + if(ptg instanceof Area3DPtg) { + Area3DPtg aptg = (Area3DPtg)ptg; + if (_externSheetIndex != aptg.getExternSheetIndex()) { + // only move 3D refs that refer to the sheet with cells being moved + // (currentExternSheetIx is irrelevant) + return null; + } + return rowMoveAreaPtg(aptg); + } + return null; + } + + private Ptg rowMoveRefPtg(RefPtgBase rptg) { + int refRow = rptg.getRow(); + if (_firstMovedIndex <= refRow && refRow <= _lastMovedIndex) { + // Rows being moved completely enclose the ref. + // - move the area ref along with the rows regardless of destination + rptg.setRow(refRow + _amountToMove); + return rptg; + } + // else rules for adjusting area may also depend on the destination of the moved rows + + int destFirstRowIndex = _firstMovedIndex + _amountToMove; + int destLastRowIndex = _lastMovedIndex + _amountToMove; + + // ref is outside source rows + // check for clashes with destination + + if (destLastRowIndex < refRow || refRow < destFirstRowIndex) { + // destination rows are completely outside ref + return null; + } + + if (destFirstRowIndex <= refRow && refRow <= destLastRowIndex) { + // destination rows enclose the area (possibly exactly) + return createDeletedRef(rptg); + } + throw new IllegalStateException("Situation not covered: (" + _firstMovedIndex + ", " + + _lastMovedIndex + ", " + _amountToMove + ", " + refRow + ", " + refRow + ")"); + } + + private Ptg rowMoveAreaPtg(AreaPtgBase aptg) { + int aFirstRow = aptg.getFirstRow(); + int aLastRow = aptg.getLastRow(); + if (_firstMovedIndex <= aFirstRow && aLastRow <= _lastMovedIndex) { + // Rows being moved completely enclose the area ref. + // - move the area ref along with the rows regardless of destination + aptg.setFirstRow(aFirstRow + _amountToMove); + aptg.setLastRow(aLastRow + _amountToMove); + return aptg; + } + // else rules for adjusting area may also depend on the destination of the moved rows + + int destFirstRowIndex = _firstMovedIndex + _amountToMove; + int destLastRowIndex = _lastMovedIndex + _amountToMove; + + if (aFirstRow < _firstMovedIndex && _lastMovedIndex < aLastRow) { + // Rows moved were originally *completely* within the area ref + + // If the destination of the rows overlaps either the top + // or bottom of the area ref there will be a change + if (destFirstRowIndex < aFirstRow && aFirstRow <= destLastRowIndex) { + // truncate the top of the area by the moved rows + aptg.setFirstRow(destLastRowIndex+1); + return aptg; + } else if (destFirstRowIndex <= aLastRow && aLastRow < destLastRowIndex) { + // truncate the bottom of the area by the moved rows + aptg.setLastRow(destFirstRowIndex-1); + return aptg; + } + // else - rows have moved completely outside the area ref, + // or still remain completely within the area ref + return null; // - no change to the area + } + if (_firstMovedIndex <= aFirstRow && aFirstRow <= _lastMovedIndex) { + // Rows moved include the first row of the area ref, but not the last row + // btw: (aLastRow > _lastMovedIndex) + if (_amountToMove < 0) { + // simple case - expand area by shifting top upward + aptg.setFirstRow(aFirstRow + _amountToMove); + return aptg; + } + if (destFirstRowIndex > aLastRow) { + // in this case, excel ignores the row move + return null; + } + int newFirstRowIx = aFirstRow + _amountToMove; + if (destLastRowIndex < aLastRow) { + // end of area is preserved (will remain exact same row) + // the top area row is moved simply + aptg.setFirstRow(newFirstRowIx); + return aptg; + } + // else - bottom area row has been replaced - both area top and bottom may move now + int areaRemainingTopRowIx = _lastMovedIndex + 1; + if (destFirstRowIndex > areaRemainingTopRowIx) { + // old top row of area has moved deep within the area, and exposed a new top row + newFirstRowIx = areaRemainingTopRowIx; + } + aptg.setFirstRow(newFirstRowIx); + aptg.setLastRow(Math.max(aLastRow, destLastRowIndex)); + return aptg; + } + if (_firstMovedIndex <= aLastRow && aLastRow <= _lastMovedIndex) { + // Rows moved include the last row of the area ref, but not the first + // btw: (aFirstRow < _firstMovedIndex) + if (_amountToMove > 0) { + // simple case - expand area by shifting bottom downward + aptg.setLastRow(aLastRow + _amountToMove); + return aptg; + } + if (destLastRowIndex < aFirstRow) { + // in this case, excel ignores the row move + return null; + } + int newLastRowIx = aLastRow + _amountToMove; + if (destFirstRowIndex > aFirstRow) { + // top of area is preserved (will remain exact same row) + // the bottom area row is moved simply + aptg.setLastRow(newLastRowIx); + return aptg; + } + // else - top area row has been replaced - both area top and bottom may move now + int areaRemainingBottomRowIx = _firstMovedIndex - 1; + if (destLastRowIndex < areaRemainingBottomRowIx) { + // old bottom row of area has moved up deep within the area, and exposed a new bottom row + newLastRowIx = areaRemainingBottomRowIx; + } + aptg.setFirstRow(Math.min(aFirstRow, destFirstRowIndex)); + aptg.setLastRow(newLastRowIx); + return aptg; + } + // else source rows include none of the rows of the area ref + // check for clashes with destination + + if (destLastRowIndex < aFirstRow || aLastRow < destFirstRowIndex) { + // destination rows are completely outside area ref + return null; + } + + if (destFirstRowIndex <= aFirstRow && aLastRow <= destLastRowIndex) { + // destination rows enclose the area (possibly exactly) + return createDeletedRef(aptg); + } + + if (aFirstRow <= destFirstRowIndex && destLastRowIndex <= aLastRow) { + // destination rows are within area ref (possibly exact on top or bottom, but not both) + return null; // - no change to area + } + + if (destFirstRowIndex < aFirstRow && aFirstRow <= destLastRowIndex) { + // dest rows overlap top of area + // - truncate the top + aptg.setFirstRow(destLastRowIndex+1); + return aptg; + } + if (destFirstRowIndex < aLastRow && aLastRow <= destLastRowIndex) { + // dest rows overlap bottom of area + // - truncate the bottom + aptg.setLastRow(destFirstRowIndex-1); + return aptg; + } + throw new IllegalStateException("Situation not covered: (" + _firstMovedIndex + ", " + + _lastMovedIndex + ", " + _amountToMove + ", " + aFirstRow + ", " + aLastRow + ")"); + } + + private static Ptg createDeletedRef(Ptg ptg) { + if (ptg instanceof RefPtg) { + return new RefErrorPtg(); + } + if (ptg instanceof Ref3DPtg) { + Ref3DPtg rptg = (Ref3DPtg) ptg; + return new DeletedRef3DPtg(rptg.getExternSheetIndex()); + } + if (ptg instanceof AreaPtg) { + return new AreaErrPtg(); + } + if (ptg instanceof Area3DPtg) { + Area3DPtg area3DPtg = (Area3DPtg) ptg; + return new DeletedArea3DPtg(area3DPtg.getExternSheetIndex()); + } + + throw new IllegalArgumentException("Unexpected ref ptg class (" + ptg.getClass().getName() + ")"); + } +} diff --git a/src/java/org/apache/poi/hssf/record/formula/Ref2DPtgBase.java b/src/java/org/apache/poi/hssf/record/formula/Ref2DPtgBase.java new file mode 100644 index 0000000000..2fff41d6b7 --- /dev/null +++ b/src/java/org/apache/poi/hssf/record/formula/Ref2DPtgBase.java @@ -0,0 +1,68 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.record.formula; + +import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.util.LittleEndian; + +/** + * @author Josh Micich + */ +abstract class Ref2DPtgBase extends RefPtgBase { + private final static int SIZE = 5; + + /** + * Takes in a String representation of a cell reference and fills out the + * numeric fields. + */ + protected Ref2DPtgBase(String cellref) { + super(cellref); + } + + protected Ref2DPtgBase(int row, int column, boolean isRowRelative, boolean isColumnRelative) { + setRow(row); + setColumn(column); + setRowRelative(isRowRelative); + setColRelative(isColumnRelative); + } + + protected Ref2DPtgBase(RecordInputStream in) { + readCoordinates(in); + } + public final void writeBytes(byte [] array, int offset) { + LittleEndian.putByte(array, offset+0, getSid() + getPtgClass()); + writeCoordinates(array, offset+1); + } + public final String toFormulaString(Workbook book) { + return formatReferenceAsString(); + } + + protected abstract byte getSid(); + public final int getSize() { + return SIZE; + } + public final String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(getClass().getName()); + sb.append(" ["); + sb.append(formatReferenceAsString()); + sb.append("]"); + return sb.toString(); + } +} diff --git a/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java b/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java index e72cbbc30a..308e9f0b53 100644 --- a/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java @@ -18,12 +18,8 @@ package org.apache.poi.hssf.record.formula; import org.apache.poi.hssf.record.RecordInputStream; -import org.apache.poi.hssf.util.RangeAddress; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellReference; -import org.apache.poi.ss.util.SheetReferences; -import org.apache.poi.util.BitField; -import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.LittleEndian; /** @@ -34,49 +30,36 @@ import org.apache.poi.util.LittleEndian; * @author Jason Height (jheight at chariot dot net dot au) * @version 1.0-pre */ -public final class Ref3DPtg extends OperandPtg { +public final class Ref3DPtg extends RefPtgBase { public final static byte sid = 0x3a; - private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000); - private static final BitField colRelative = BitFieldFactory.getInstance(0x4000); - private final static int SIZE = 7; // 6 + 1 for Ptg private int field_1_index_extern_sheet; - /** The row index - zero based unsigned 16 bit value */ - private int field_2_row; - /** Field 2 - * - lower 8 bits is the zero based unsigned byte column index - * - bit 16 - isRowRelative - * - bit 15 - isColumnRelative - */ - private int field_3_column; /** Creates new AreaPtg */ public Ref3DPtg() {} public Ref3DPtg(RecordInputStream in) { field_1_index_extern_sheet = in.readShort(); - field_2_row = in.readShort(); - field_3_column = in.readShort(); + readCoordinates(in); } public Ref3DPtg(String cellref, short externIdx ) { CellReference c= new CellReference(cellref); setRow(c.getRow()); - setColumn((short)c.getCol()); + setColumn(c.getCol()); setColRelative(!c.isColAbsolute()); setRowRelative(!c.isRowAbsolute()); setExternSheetIndex(externIdx); } public String toString() { - CellReference cr = new CellReference(getRow(), getColumn(), !isRowRelative(),!isColRelative()); StringBuffer sb = new StringBuffer(); sb.append(getClass().getName()); sb.append(" ["); sb.append("sheetIx=").append(getExternSheetIndex()); sb.append(" ! "); - sb.append(cr.formatAsString()); + sb.append(formatReferenceAsString()); sb.append("]"); return sb.toString(); } @@ -84,8 +67,7 @@ public final class Ref3DPtg extends OperandPtg { public void writeBytes(byte [] array, int offset) { array[ 0 + offset ] = (byte) (sid + getPtgClass()); LittleEndian.putShort(array, 1 + offset , getExternSheetIndex()); - LittleEndian.putShort(array, 3 + offset , (short)getRow()); - LittleEndian.putShort(array, 5 + offset , (short)getColumnRaw()); + writeCoordinates(array, offset+3); } public int getSize() { @@ -100,83 +82,11 @@ public final class Ref3DPtg extends OperandPtg { field_1_index_extern_sheet = index; } - public int getRow() { - return field_2_row; - } - - public void setRow(int row) { - field_2_row = row; - } - - public int getColumn() { - return field_3_column & 0xFF; - } - - public int getColumnRaw() { - return field_3_column; - } - - public boolean isRowRelative() - { - return rowRelative.isSet(field_3_column); - } - - public void setRowRelative(boolean rel) { - field_3_column=rowRelative.setBoolean(field_3_column,rel); - } - - public boolean isColRelative() - { - return colRelative.isSet(field_3_column); - } - - public void setColRelative(boolean rel) { - field_3_column=colRelative.setBoolean(field_3_column,rel); - } - public void setColumn(short column) { - field_3_column &= 0xFF00; - field_3_column |= column & 0xFF; - } - - public void setColumnRaw(short column) { - field_3_column = column; - } - - /* public String getArea(){ - RangeAddress ra = new RangeAddress(""); - - String result = (ra.numTo26Sys(getColumn()) + (getRow() + 1)); - - return result; - }*/ - - public void setArea(String ref){ - RangeAddress ra = new RangeAddress(ref); - - String from = ra.getFromCell(); - - setColumn((short) (ra.getXPosition(from) -1)); - setRow((short) (ra.getYPosition(from) -1)); - - } - /** * @return text representation of this cell reference that can be used in text * formulas. The sheet name will get properly delimited if required. */ - public String toFormulaString(Workbook book) - { - StringBuffer retval = new StringBuffer(); - String sheetName = book.findSheetNameFromExternSheet(field_1_index_extern_sheet); - if(sheetName != null) { - SheetNameFormatter.appendFormat(retval, sheetName); - retval.append( '!' ); - } - retval.append((new CellReference(getRow(),getColumn(),!isRowRelative(),!isColRelative())).formatAsString()); - return retval.toString(); + public String toFormulaString(Workbook book) { + return ExternSheetNameResolver.prependSheetName(book, field_1_index_extern_sheet, formatReferenceAsString()); } - - public byte getDefaultOperandClass() { - return Ptg.CLASS_REF; - } } diff --git a/src/java/org/apache/poi/hssf/record/formula/RefErrorPtg.java b/src/java/org/apache/poi/hssf/record/formula/RefErrorPtg.java index 6adbe43c51..a3030e1bd7 100755 --- a/src/java/org/apache/poi/hssf/record/formula/RefErrorPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/RefErrorPtg.java @@ -18,6 +18,7 @@ package org.apache.poi.hssf.record.formula; import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.ss.usermodel.ErrorConstants; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.util.LittleEndian; @@ -28,48 +29,32 @@ import org.apache.poi.util.LittleEndian; public final class RefErrorPtg extends OperandPtg { private final static int SIZE = 5; - public final static byte sid = 0x2a; + public final static byte sid = 0x2A; private int field_1_reserved; - public RefErrorPtg(RecordInputStream in) - { + public RefErrorPtg() { + field_1_reserved = 0; + } + public RefErrorPtg(RecordInputStream in) { field_1_reserved = in.readInt(); - } - public String toString() - { - StringBuffer buffer = new StringBuffer("[RefError]\n"); - - buffer.append("reserved = ").append(getReserved()).append("\n"); - return buffer.toString(); + public String toString() { + return getClass().getName(); } - public void writeBytes(byte [] array, int offset) - { - array[offset] = (byte) (sid + getPtgClass()); + public void writeBytes(byte [] array, int offset) { + LittleEndian.putByte(array, offset+0, sid + getPtgClass()); LittleEndian.putInt(array,offset+1,field_1_reserved); } - public void setReserved(int reserved) - { - field_1_reserved = reserved; - } - - public int getReserved() - { - return field_1_reserved; - } - public int getSize() { return SIZE; } - public String toFormulaString(Workbook book) - { - //TODO -- should we store a cellreference instance in this ptg?? but .. memory is an issue, i believe! - return "#REF!"; + public String toFormulaString(Workbook book) { + return ErrorConstants.getText(ErrorConstants.ERROR_REF); } public byte getDefaultOperandClass() { diff --git a/src/java/org/apache/poi/hssf/record/formula/RefNPtg.java b/src/java/org/apache/poi/hssf/record/formula/RefNPtg.java index 5ef4a413b3..07114265d0 100644 --- a/src/java/org/apache/poi/hssf/record/formula/RefNPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/RefNPtg.java @@ -23,16 +23,14 @@ import org.apache.poi.hssf.record.RecordInputStream; * RefNPtg * @author Jason Height (jheight at apache dot com) */ -public final class RefNPtg extends RefPtgBase { - public final static byte sid = 0x2C; +public final class RefNPtg extends Ref2DPtgBase { + public final static byte sid = 0x2C; - /** Creates new ValueReferencePtg */ + public RefNPtg(RecordInputStream in) { + super(in); + } - public RefNPtg(RecordInputStream in) { - super(in); - } - - protected byte getSid() { - return sid; - } + protected byte getSid() { + return sid; + } } diff --git a/src/java/org/apache/poi/hssf/record/formula/RefPtg.java b/src/java/org/apache/poi/hssf/record/formula/RefPtg.java index a324ce70f9..94a1b3301c 100644 --- a/src/java/org/apache/poi/hssf/record/formula/RefPtg.java +++ b/src/java/org/apache/poi/hssf/record/formula/RefPtg.java @@ -24,30 +24,26 @@ import org.apache.poi.hssf.record.RecordInputStream; * @author Andrew C. Oliver (acoliver@apache.org)
* @author Jason Height (jheight at chariot dot net dot au)
*/
-public final class RefPtg extends RefPtgBase {
- public final static byte sid = 0x24;
-
- /**
- * Takes in a String representation of a cell reference and fills out the
- * numeric fields.
- */
- public RefPtg(String cellref) {
- super(cellref);
- }
-
- public RefPtg(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
- setRow(row);
- setColumn(column);
- setRowRelative(isRowRelative);
- setColRelative(isColumnRelative);
- }
-
- public RefPtg(RecordInputStream in) {
- super(in);
- }
+public final class RefPtg extends Ref2DPtgBase {
+ public final static byte sid = 0x24;
+
+ /**
+ * Takes in a String representation of a cell reference and fills out the
+ * numeric fields.
+ */
+ public RefPtg(String cellref) {
+ super(cellref);
+ }
+
+ public RefPtg(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
+ super(row, column, isRowRelative, isColumnRelative);
+ }
+
+ public RefPtg(RecordInputStream in) {
+ super(in);
+ }
protected byte getSid() {
return sid;
}
-
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/RefPtgBase.java b/src/java/org/apache/poi/hssf/record/formula/RefPtgBase.java index 33dff9ec04..f04ec0ac8f 100644 --- a/src/java/org/apache/poi/hssf/record/formula/RefPtgBase.java +++ b/src/java/org/apache/poi/hssf/record/formula/RefPtgBase.java @@ -17,13 +17,11 @@ package org.apache.poi.hssf.record.formula; -import org.apache.poi.util.LittleEndian; +import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.hssf.util.CellReference; import org.apache.poi.util.BitField; import org.apache.poi.util.BitFieldFactory; - -import org.apache.poi.ss.util.CellReference; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.hssf.record.RecordInputStream; +import org.apache.poi.util.LittleEndian; /** * ReferencePtgBase - handles references (such as A1, A2, IA4) @@ -32,7 +30,6 @@ import org.apache.poi.hssf.record.RecordInputStream; */ public abstract class RefPtgBase extends OperandPtg { - private final static int SIZE = 5; private final static int MAX_ROW_NUMBER = 65536; /** The row index - zero based unsigned 16 bit value */ @@ -70,29 +67,14 @@ public abstract class RefPtgBase extends OperandPtg { setColRelative(isColumnRelative); } - protected RefPtgBase(RecordInputStream in) { + protected final void readCoordinates(RecordInputStream in) { field_1_row = in.readUShort(); field_2_col = in.readUShort(); } - - public final String toString() { - CellReference cr = new CellReference(getRow(), getColumn(), !isRowRelative(),!isColRelative()); - StringBuffer sb = new StringBuffer(); - sb.append(getClass().getName()); - sb.append(" ["); - sb.append(cr.formatAsString()); - sb.append("]"); - return sb.toString(); - } - - public final void writeBytes(byte [] array, int offset) { - array[offset] = (byte) (getSid() + getPtgClass()); - - LittleEndian.putShort(array, offset+1, (short)field_1_row); - LittleEndian.putShort(array, offset+3, (short)field_2_col); + protected final void writeCoordinates(byte[] array, int offset) { + LittleEndian.putUShort(array, offset + 0, field_1_row); + LittleEndian.putUShort(array, offset + 2, field_2_col); } - - protected abstract byte getSid(); public final void setRow(int row) { if(row < 0 || row >= MAX_ROW_NUMBER) { @@ -102,18 +84,11 @@ public abstract class RefPtgBase extends OperandPtg { } /** - * Returns the row number as a short, which will be - * wrapped (negative) for values between 32769 and 65535 + * @return the row number as an int, between 0 and 65535 */ public final int getRow(){ return field_1_row; } - /** - * Returns the row number as an int, between 0 and 65535 - */ - public final int getRowAsInt() { - return field_1_row; - } public final boolean isRowRelative() { return rowRelative.isSet(field_2_col); @@ -135,20 +110,16 @@ public abstract class RefPtgBase extends OperandPtg { if(col < 0 || col >= 0x100) { throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range"); } - field_2_col = column.setValue(field_2_col, col); + field_2_col = column.setValue(field_2_col, col); } public final int getColumn() { - return column.getValue(field_2_col); - } - - public final int getSize() { - return SIZE; + return column.getValue(field_2_col); } - - public final String toFormulaString(Workbook book) { - //TODO -- should we store a cellreference instance in this ptg?? but .. memory is an issue, i believe! - return (new CellReference(getRowAsInt(),getColumn(),!isRowRelative(),!isColRelative())).formatAsString(); + protected final String formatReferenceAsString() { + // Only make cell references as needed. Memory is an issue + CellReference cr = new CellReference(getRow(), getColumn(), !isRowRelative(), !isColRelative()); + return cr.formatAsString(); } public final byte getDefaultOperandClass() { diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java index 1f88cce2bd..4fbedb8745 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java @@ -300,7 +300,7 @@ public class HSSFCell implements Cell { FormulaRecordAggregate frec; if (cellType != this.cellType) { - frec = sheet.getSheet().createFormula(row, col); + frec = sheet.getSheet().getRowsAggregate().createFormula(row, col); } else { frec = (FormulaRecordAggregate) record; frec.setRow(row); @@ -600,12 +600,6 @@ public class HSSFCell implements Cell { Ptg[] ptgs = FormulaParser.parse(formula, book); frec.setParsedExpression(ptgs); } - /* package */ void setFormulaOnly(Ptg[] ptgs) { - if (ptgs == null) { - throw new IllegalArgumentException("ptgs must not be null"); - } - ((FormulaRecordAggregate)record).getFormulaRecord().setParsedExpression(ptgs); - } public String getCellFormula() { return FormulaParser.toFormulaString(book, ((FormulaRecordAggregate)record).getFormulaRecord().getParsedExpression()); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java index 4fde9e6cc3..6de2293794 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java @@ -126,8 +126,16 @@ public class HSSFName implements Name { * @return true if the name refers to a deleted cell, false otherwise */ public boolean isDeleted(){ - String ref = getReference(); - return "#REF!".endsWith(ref); + String formulaText = getReference(); + if (formulaText.startsWith("#REF!")) { + // sheet deleted + return true; + } + if (formulaText.endsWith("#REF!")) { + // cell range deleted + return true; + } + return false; } public boolean isFunctionName() { return _definedNameRec.isFunctionName(); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index 4d6a1f7253..231942f440 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -31,7 +31,6 @@ import java.util.List; import java.util.TreeMap; import org.apache.poi.ddf.EscherRecord; -import org.apache.poi.hssf.model.FormulaParser; import org.apache.poi.hssf.model.Sheet; import org.apache.poi.hssf.model.Workbook; import org.apache.poi.hssf.record.CellValueRecordInterface; @@ -43,8 +42,7 @@ import org.apache.poi.hssf.record.SCLRecord; import org.apache.poi.hssf.record.WSBoolRecord; import org.apache.poi.hssf.record.WindowTwoRecord; import org.apache.poi.hssf.record.aggregates.DataValidityTable; -import org.apache.poi.hssf.record.formula.Ptg; -import org.apache.poi.hssf.record.formula.RefPtg; +import org.apache.poi.hssf.record.formula.FormulaShifter; import org.apache.poi.hssf.util.PaneInformation; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Row; @@ -1180,33 +1178,26 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet * @param resetOriginalRowHeight whether to set the original row's height to the default * @param moveComments whether to move comments at the same time as the cells they are attached to */ - public void shiftRows( int startRow, int endRow, int n, boolean copyRowHeight, boolean resetOriginalRowHeight, boolean moveComments) - { - int s, e, inc; - if ( n < 0 ) - { + public void shiftRows(int startRow, int endRow, int n, + boolean copyRowHeight, boolean resetOriginalRowHeight, boolean moveComments) { + int s, inc; + if (n < 0) { s = startRow; - e = endRow; inc = 1; - } - else - { + } else { s = endRow; - e = startRow; inc = -1; } shiftMerged(startRow, endRow, n, true); sheet.getPageSettings().shiftRowBreaks(startRow, endRow, n); - for ( int rowNum = s; rowNum >= startRow && rowNum <= endRow && rowNum >= 0 && rowNum < 65536; rowNum += inc ) - { + for ( int rowNum = s; rowNum >= startRow && rowNum <= endRow && rowNum >= 0 && rowNum < 65536; rowNum += inc ) { HSSFRow row = getRow( rowNum ); HSSFRow row2Replace = getRow( rowNum + n ); if ( row2Replace == null ) row2Replace = createRow( rowNum + n ); - HSSFCell cell; // Remove all the old cells from the row we'll // be writing too, before we start overwriting @@ -1236,7 +1227,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet // Copy each cell from the source row to // the destination row for(Iterator cells = row.cellIterator(); cells.hasNext(); ) { - cell = (HSSFCell)cells.next(); + HSSFCell cell = (HSSFCell)cells.next(); row.removeCell( cell ); CellValueRecordInterface cellRecord = cell.getCellValueRecord(); cellRecord.setRow( rowNum + n ); @@ -1263,49 +1254,21 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet // Update any formulas on this sheet that point to // rows which have been moved - updateFormulasAfterShift(startRow, endRow, n); - } - - /** - * Called by shiftRows to update formulas on this sheet - * to point to the new location of moved rows - */ - private void updateFormulasAfterShift(int startRow, int endRow, int n) { - // Need to look at every cell on the sheet - // Not just those that were moved - Iterator ri = rowIterator(); - while(ri.hasNext()) { - HSSFRow r = (HSSFRow)ri.next(); - Iterator ci = r.cellIterator(); - while(ci.hasNext()) { - HSSFCell c = (HSSFCell)ci.next(); - if(c.getCellType() == HSSFCell.CELL_TYPE_FORMULA) { - // Since it's a formula cell, process the - // formula string, and look to see if - // it contains any references - - // Look for references, and update if needed - Ptg[] ptgs = FormulaParser.parse(c.getCellFormula(), workbook); - boolean changed = false; - for(int i=0; i<ptgs.length; i++) { - if(ptgs[i] instanceof RefPtg) { - RefPtg rptg = (RefPtg)ptgs[i]; - if(startRow <= rptg.getRowAsInt() && - rptg.getRowAsInt() <= endRow) { - // References a row that moved - rptg.setRow(rptg.getRowAsInt() + n); - changed = true; - } - } - } - // If any references were changed, then - // re-create the formula string - if(changed) { - c.setFormulaOnly(ptgs); - } - } + int sheetIndex = workbook.getSheetIndex(this); + short externSheetIndex = book.checkExternSheet(sheetIndex); + FormulaShifter shifter = FormulaShifter.createForRowShift(externSheetIndex, startRow, endRow, n); + sheet.getRowsAggregate().updateFormulasAfterRowShift(shifter, externSheetIndex); + + int nSheets = workbook.getNumberOfSheets(); + for(int i=0; i<nSheets; i++) { + Sheet otherSheet = workbook.getSheetAt(i).getSheet(); + if (otherSheet == this.sheet) { + continue; } + short otherExtSheetIx = book.checkExternSheet(i); + otherSheet.getRowsAggregate().updateFormulasAfterRowShift(shifter, otherExtSheetIx); } + // TODO - adjust formulas in named ranges } protected void insertChartRecords( List records ) @@ -1652,9 +1615,12 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet sheet.groupRowRange( fromRow, toRow, false ); } - public void setRowGroupCollapsed( int row, boolean collapse ) - { - sheet.setRowGroupCollapsed( row, collapse ); + public void setRowGroupCollapsed(int rowIndex, boolean collapse) { + if (collapse) { + sheet.getRowsAggregate().collapseRow(rowIndex); + } else { + sheet.getRowsAggregate().expandRow(rowIndex); + } } /** diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index b0da561fae..83bae3e43b 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -678,10 +678,35 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm * if needed. * Used by some of the more obscure formula and * named range things. + * @deprecated for POI internal use only (formula parsing). This method is likely to + * be removed in future versions of POI. */ public int getExternalSheetIndex(int internalSheetIndex) { return workbook.checkExternSheet(internalSheetIndex); } + /** + * @deprecated for POI internal use only (formula rendering). This method is likely to + * be removed in future versions of POI. + */ + public String findSheetNameFromExternSheet(int externSheetIndex){ + // TODO - don't expose internal ugliness like externSheet indexes to the user model API + return workbook.findSheetNameFromExternSheet(externSheetIndex); + } + /** + * @deprecated for POI internal use only (formula rendering). This method is likely to + * be removed in future versions of POI. + * + * @param refIndex Index to REF entry in EXTERNSHEET record in the Link Table + * @param definedNameIndex zero-based to DEFINEDNAME or EXTERNALNAME record + * @return the string representation of the defined or external name + */ + public String resolveNameXText(int refIndex, int definedNameIndex) { + // TODO - make this less cryptic / move elsewhere + return workbook.resolveNameXText(refIndex, definedNameIndex); + } + + + /** * create an HSSFSheet for this HSSFWorkbook, adds it to the sheets and returns @@ -866,15 +891,6 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm } /** - * @deprecated for POI internal use only (formula rendering). This method is likely to - * be removed in future versions of POI. - */ - public String findSheetNameFromExternSheet(int externSheetIndex){ - // TODO - don't expose internal ugliness like externSheet indexes to the user model API - return workbook.findSheetNameFromExternSheet(externSheetIndex); - } - - /** * Removes sheet at the given index.<p/> * * Care must be taken if the removed sheet is the currently active or only selected sheet in @@ -1385,20 +1401,6 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm } /** - * @deprecated for POI internal use only (formula rendering). This method is likely to - * be removed in future versions of POI. - * - * @param refIndex Index to REF entry in EXTERNSHEET record in the Link Table - * @param definedNameIndex zero-based to DEFINEDNAME or EXTERNALNAME record - * @return the string representation of the defined or external name - */ - public String resolveNameXText(int refIndex, int definedNameIndex) { - // TODO - make this less cryptic / move elsewhere - return workbook.resolveNameXText(refIndex, definedNameIndex); - } - - - /** * Sets the printarea for the sheet provided * <p> * i.e. Reference = $A$1:$B$2 |