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
This commit is contained in:
parent
bb3bf964bd
commit
d074c7a1eb
@ -67,6 +67,7 @@
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.2-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">45780 - Fixed HSSFSheet.shiftRows to also update Area refs</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45804 - Update HSMF to handle Outlook 3.0 msg files, which have a different string chunk type</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Expose the name of Named Cell Styles via HSSFCellStyle (normally held on the parent style though)</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45978 - Fixed IOOBE in Ref3DPtg.toFormulaString() due eager initialisation of SheetReferences</action>
|
||||
|
@ -64,6 +64,7 @@
|
||||
<action dev="POI-DEVELOPERS" type="add">Created a common interface for handling Excel files, irrespective of if they are .xls or .xlsx</action>
|
||||
</release>
|
||||
<release version="3.2-alpha1" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="fix">45780 - Fixed HSSFSheet.shiftRows to also update Area refs</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45804 - Update HSMF to handle Outlook 3.0 msg files, which have a different string chunk type</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">Expose the name of Named Cell Styles via HSSFCellStyle (normally held on the parent style though)</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45978 - Fixed IOOBE in Ref3DPtg.toFormulaString() due eager initialisation of SheetReferences</action>
|
||||
|
@ -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;
|
||||
@ -623,13 +624,6 @@ public final class Sheet implements Model {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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()];
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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 final static byte sid = 0x2B;
|
||||
private final int unused1;
|
||||
private final int unused2;
|
||||
|
||||
public AreaErrPtg(RecordInputStream in) {
|
||||
// 8 bytes unused:
|
||||
in.readInt();
|
||||
in.readInt();
|
||||
}
|
||||
public AreaErrPtg() {
|
||||
unused1 = 0;
|
||||
unused2 = 0;
|
||||
}
|
||||
|
||||
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 AreaErrPtg(RecordInputStream in) {
|
||||
// 8 bytes unused:
|
||||
unused1 = in.readInt();
|
||||
unused2 = in.readInt();
|
||||
}
|
||||
|
||||
public String toFormulaString(Workbook book) {
|
||||
return "#REF!";
|
||||
}
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
294
src/java/org/apache/poi/hssf/record/formula/FormulaShifter.java
Normal file
294
src/java/org/apache/poi/hssf/record/formula/FormulaShifter.java
Normal file
@ -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() + ")");
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
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);
|
||||
}
|
||||
/**
|
||||
* 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(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
|
||||
super(row, column, isRowRelative, isColumnRelative);
|
||||
}
|
||||
|
||||
public RefPtg(RecordInputStream in) {
|
||||
super(in);
|
||||
}
|
||||
public RefPtg(RecordInputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
protected byte getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,30 +67,15 @@ 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();
|
||||
protected final void writeCoordinates(byte[] array, int offset) {
|
||||
LittleEndian.putUShort(array, offset + 0, field_1_row);
|
||||
LittleEndian.putUShort(array, offset + 2, field_2_col);
|
||||
}
|
||||
|
||||
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 abstract byte getSid();
|
||||
|
||||
public final void setRow(int row) {
|
||||
if(row < 0 || row >= MAX_ROW_NUMBER) {
|
||||
throw new IllegalArgumentException("The row number, when specified as an integer, must be between 0 and " + 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);
|
||||
return column.getValue(field_2_col);
|
||||
}
|
||||
|
||||
public final int getSize() {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
int sheetIndex = workbook.getSheetIndex(this);
|
||||
short externSheetIndex = book.checkExternSheet(sheetIndex);
|
||||
FormulaShifter shifter = FormulaShifter.createForRowShift(externSheetIndex, startRow, endRow, n);
|
||||
sheet.getRowsAggregate().updateFormulasAfterRowShift(shifter, externSheetIndex);
|
||||
|
||||
/**
|
||||
* 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 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
@ -865,15 +890,6 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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/>
|
||||
*
|
||||
@ -1384,20 +1400,6 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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>
|
||||
|
Binary file not shown.
@ -43,6 +43,7 @@ public final class AllFormulaTests {
|
||||
result.addTestSuite(TestArrayPtg.class);
|
||||
result.addTestSuite(TestErrPtg.class);
|
||||
result.addTestSuite(TestExternalFunctionFormulas.class);
|
||||
result.addTestSuite(TestFormulaShifter.class);
|
||||
result.addTestSuite(TestFuncPtg.class);
|
||||
result.addTestSuite(TestFuncVarPtg.class);
|
||||
result.addTestSuite(TestIntersectionPtg.class);
|
||||
|
@ -0,0 +1,115 @@
|
||||
/* ====================================================================
|
||||
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 junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests for {@link FormulaShifter}.
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class TestFormulaShifter extends TestCase {
|
||||
// Note - the expected result row coordinates here were determined/verified
|
||||
// in Excel 2007 by manually testing.
|
||||
|
||||
/**
|
||||
* Tests what happens to area refs when a range of rows from inside, or overlapping are
|
||||
* moved
|
||||
*/
|
||||
public void testShiftAreasSourceRows() {
|
||||
|
||||
// all these operations are on an area ref spanning rows 10 to 20
|
||||
AreaPtg aptg = createAreaPtg(10, 20);
|
||||
|
||||
confirmAreaShift(aptg, 9, 21, 20, 30, 40);
|
||||
confirmAreaShift(aptg, 10, 21, 20, 30, 40);
|
||||
confirmAreaShift(aptg, 9, 20, 20, 30, 40);
|
||||
|
||||
confirmAreaShift(aptg, 8, 11, -3, 7, 20); // simple expansion of top
|
||||
// rows containing area top being shifted down:
|
||||
confirmAreaShift(aptg, 8, 11, 3, 13, 20);
|
||||
confirmAreaShift(aptg, 8, 11, 7, 17, 20);
|
||||
confirmAreaShift(aptg, 8, 11, 8, 18, 20);
|
||||
confirmAreaShift(aptg, 8, 11, 9, 12, 20); // note behaviour changes here
|
||||
confirmAreaShift(aptg, 8, 11, 10, 12, 21);
|
||||
confirmAreaShift(aptg, 8, 11, 12, 12, 23);
|
||||
confirmAreaShift(aptg, 8, 11, 13, 10, 20); // ignored
|
||||
|
||||
// rows from within being moved:
|
||||
confirmAreaShift(aptg, 12, 16, 3, 10, 20); // stay within - no change
|
||||
confirmAreaShift(aptg, 11, 19, 20, 10, 20); // move completely out - no change
|
||||
confirmAreaShift(aptg, 16, 17, -6, 10, 20); // moved exactly to top - no change
|
||||
confirmAreaShift(aptg, 16, 17, -7, 11, 20); // truncation at top
|
||||
confirmAreaShift(aptg, 12, 16, 4, 10, 20); // moved exactly to bottom - no change
|
||||
confirmAreaShift(aptg, 12, 16, 6, 10, 17); // truncation at bottom
|
||||
|
||||
// rows containing area bottom being shifted up:
|
||||
confirmAreaShift(aptg, 18, 22, -1, 10, 19); // simple contraction at bottom
|
||||
confirmAreaShift(aptg, 18, 22, -7, 10, 13); // simple contraction at bottom
|
||||
confirmAreaShift(aptg, 18, 22, -8, 10, 17); // top calculated differently here
|
||||
confirmAreaShift(aptg, 18, 22, -9, 9, 17);
|
||||
confirmAreaShift(aptg, 18, 22,-15, 10, 20); // no change because range would be turned inside out
|
||||
confirmAreaShift(aptg, 15, 19, -7, 13, 20); // dest truncates top (even though src is from inside range)
|
||||
confirmAreaShift(aptg, 19, 23,-12, 7, 18); // complex: src encloses bottom, dest encloses top
|
||||
|
||||
confirmAreaShift(aptg, 18, 22, 5, 10, 25); // simple expansion at bottom
|
||||
}
|
||||
/**
|
||||
* Tests what happens to an area ref when some outside rows are moved to overlap
|
||||
* that area ref
|
||||
*/
|
||||
public void testShiftAreasDestRows() {
|
||||
// all these operations are on an area ref spanning rows 20 to 25
|
||||
AreaPtg aptg = createAreaPtg(20, 25);
|
||||
|
||||
// no change because no overlap:
|
||||
confirmAreaShift(aptg, 5, 10, 9, 20, 25);
|
||||
confirmAreaShift(aptg, 5, 10, 21, 20, 25);
|
||||
|
||||
confirmAreaShift(aptg, 11, 14, 10, 20, 25);
|
||||
|
||||
confirmAreaShift(aptg, 7, 17, 10, -1, -1); // converted to DeletedAreaRef
|
||||
confirmAreaShift(aptg, 5, 15, 7, 23, 25); // truncation at top
|
||||
confirmAreaShift(aptg, 13, 16, 10, 20, 22); // truncation at bottom
|
||||
}
|
||||
|
||||
private static void confirmAreaShift(AreaPtg aptg,
|
||||
int firstRowMoved, int lastRowMoved, int numberRowsMoved,
|
||||
int expectedAreaFirstRow, int expectedAreaLastRow) {
|
||||
|
||||
FormulaShifter fs = FormulaShifter.createForRowShift(0, firstRowMoved, lastRowMoved, numberRowsMoved);
|
||||
boolean expectedChanged = aptg.getFirstRow() != expectedAreaFirstRow || aptg.getLastRow() != expectedAreaLastRow;
|
||||
|
||||
AreaPtg copyPtg = (AreaPtg) aptg.copy(); // clone so we can re-use aptg in calling method
|
||||
Ptg[] ptgs = { copyPtg, };
|
||||
boolean actualChanged = fs.adjustFormula(ptgs, 0);
|
||||
if (expectedAreaFirstRow < 0) {
|
||||
assertEquals(AreaErrPtg.class, ptgs[0].getClass());
|
||||
return;
|
||||
}
|
||||
assertEquals(expectedChanged, actualChanged);
|
||||
assertEquals(copyPtg, ptgs[0]); // expected to change in place (although this is not a strict requirement)
|
||||
assertEquals(expectedAreaFirstRow, copyPtg.getFirstRow());
|
||||
assertEquals(expectedAreaLastRow, copyPtg.getLastRow());
|
||||
|
||||
}
|
||||
private static AreaPtg createAreaPtg(int initialAreaFirstRow, int initialAreaLastRow) {
|
||||
return new AreaPtg(initialAreaFirstRow, initialAreaLastRow, 2, 5, false, false, false, false);
|
||||
}
|
||||
}
|
@ -1052,25 +1052,25 @@ public final class TestFormulas extends TestCase {
|
||||
sb.write(new FileOutputStream(file));
|
||||
}
|
||||
|
||||
/*Unknown Ptg 3C*/
|
||||
/** Unknown Ptg 3C*/
|
||||
public void test27272_1() throws Exception {
|
||||
HSSFWorkbook wb = openSample("27272_1.xls");
|
||||
wb.getSheetAt(0);
|
||||
assertEquals("Reference for named range ", "#REF!",wb.getNameAt(0).getReference());
|
||||
assertEquals("Reference for named range ", "Compliance!#REF!",wb.getNameAt(0).getReference());
|
||||
File outF = File.createTempFile("bug27272_1",".xls");
|
||||
wb.write(new FileOutputStream(outF));
|
||||
System.out.println("Open "+outF.getAbsolutePath()+" in Excel");
|
||||
}
|
||||
/*Unknown Ptg 3D*/
|
||||
/** Unknown Ptg 3D*/
|
||||
public void test27272_2() throws Exception {
|
||||
HSSFWorkbook wb = openSample("27272_2.xls");
|
||||
assertEquals("Reference for named range ", "#REF!",wb.getNameAt(0).getReference());
|
||||
assertEquals("Reference for named range ", "'LOAD.POD_HISTORIES'!#REF!",wb.getNameAt(0).getReference());
|
||||
File outF = File.createTempFile("bug27272_2",".xls");
|
||||
wb.write(new FileOutputStream(outF));
|
||||
System.out.println("Open "+outF.getAbsolutePath()+" in Excel");
|
||||
}
|
||||
|
||||
/* MissingArgPtg */
|
||||
/** MissingArgPtg */
|
||||
public void testMissingArgPtg() throws Exception {
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFCell cell = wb.createSheet("Sheet1").createRow(4).createCell(0);
|
||||
|
@ -476,7 +476,7 @@ public final class TestNamedRange extends TestCase {
|
||||
|
||||
HSSFName name2 = wb.getNameAt(1);
|
||||
assertEquals("b", name2.getNameName());
|
||||
assertEquals("#REF!", name2.getReference());
|
||||
assertEquals("Sheet1!#REF!", name2.getReference());
|
||||
assertTrue(name2.isDeleted());
|
||||
try {
|
||||
AreaReference ref2 = new AreaReference(name2.getReference());
|
||||
|
@ -19,6 +19,10 @@ package org.apache.poi.hssf.usermodel;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
@ -201,36 +205,69 @@ public final class TestSheetShiftRows extends TestCase {
|
||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ForShifting.xls");
|
||||
|
||||
HSSFSheet sheet = wb.getSheet("Sheet1");
|
||||
assertEquals(19, sheet.getLastRowNum());
|
||||
assertEquals(20, sheet.getLastRowNum());
|
||||
|
||||
assertEquals("cell B1 (ref)", sheet.getRow(0).getCell(3).getRichStringCellValue().toString());
|
||||
assertEquals("CONCATENATE(B1,\" (ref)\")", sheet.getRow(0).getCell(3).getCellFormula());
|
||||
assertEquals("cell B2 (ref)", sheet.getRow(1).getCell(3).getRichStringCellValue().toString());
|
||||
assertEquals("CONCATENATE(B2,\" (ref)\")", sheet.getRow(1).getCell(3).getCellFormula());
|
||||
assertEquals("cell B3 (ref)", sheet.getRow(2).getCell(3).getRichStringCellValue().toString());
|
||||
assertEquals("CONCATENATE(B3,\" (ref)\")", sheet.getRow(2).getCell(3).getCellFormula());
|
||||
assertEquals("cell B2 (ref)", sheet.getRow(6).getCell(1).getRichStringCellValue().toString());
|
||||
assertEquals("CONCATENATE(B2,\" (ref)\")", sheet.getRow(6).getCell(1).getCellFormula());
|
||||
confirmRow(sheet, 0, 1, 171, 1, "ROW(D1)", "100+B1", "COUNT(D1:E1)");
|
||||
confirmRow(sheet, 1, 2, 172, 1, "ROW(D2)", "100+B2", "COUNT(D2:E2)");
|
||||
confirmRow(sheet, 2, 3, 173, 1, "ROW(D3)", "100+B3", "COUNT(D3:E3)");
|
||||
|
||||
confirmCell(sheet, 6, 1, 271, "200+B1");
|
||||
confirmCell(sheet, 7, 1, 272, "200+B2");
|
||||
confirmCell(sheet, 8, 1, 273, "200+B3");
|
||||
|
||||
confirmCell(sheet, 14, 0, 0.0, "A12"); // the cell referred to by this formula will be replaced
|
||||
|
||||
// -----------
|
||||
// Row index 1 -> 11 (row "2" -> row "12")
|
||||
sheet.shiftRows(1, 1, 10);
|
||||
|
||||
// Row 1 => Row 11
|
||||
// So strings on row 11 unchanged, but reference in formula is
|
||||
assertEquals("cell B1 (ref)", sheet.getRow(0).getCell(3).getRichStringCellValue().toString());
|
||||
assertEquals("CONCATENATE(B1,\" (ref)\")", sheet.getRow(0).getCell(3).getCellFormula());
|
||||
// Now check what sheet looks like after move
|
||||
|
||||
// no changes on row "1"
|
||||
confirmRow(sheet, 0, 1, 171, 1, "ROW(D1)", "100+B1", "COUNT(D1:E1)");
|
||||
|
||||
// row "2" is now empty
|
||||
assertEquals(0, sheet.getRow(1).getPhysicalNumberOfCells());
|
||||
|
||||
// still save b2
|
||||
assertEquals("cell B2 (ref)", sheet.getRow(11).getCell(3).getRichStringCellValue().toString());
|
||||
// but points to b12
|
||||
assertEquals("CONCATENATE(B12,\" (ref)\")", sheet.getRow(11).getCell(3).getCellFormula());
|
||||
// Row "2" moved to row "12", and the formula has been updated.
|
||||
// note however that the cached formula result (2) has not been updated. (POI differs from Excel here)
|
||||
confirmRow(sheet, 11, 2, 172, 1, "ROW(D12)", "100+B12", "COUNT(D12:E12)");
|
||||
|
||||
assertEquals("cell B3 (ref)", sheet.getRow(2).getCell(3).getRichStringCellValue().toString());
|
||||
assertEquals("CONCATENATE(B3,\" (ref)\")", sheet.getRow(2).getCell(3).getCellFormula());
|
||||
// no changes on row "3"
|
||||
confirmRow(sheet, 2, 3, 173, 1, "ROW(D3)", "100+B3", "COUNT(D3:E3)");
|
||||
|
||||
// one on a non-shifted row also updated
|
||||
assertEquals("cell B2 (ref)", sheet.getRow(6).getCell(1).getRichStringCellValue().toString());
|
||||
assertEquals("CONCATENATE(B12,\" (ref)\")", sheet.getRow(6).getCell(1).getCellFormula());
|
||||
|
||||
confirmCell(sheet, 14, 0, 0.0, "#REF!");
|
||||
|
||||
|
||||
// Formulas on rows that weren't shifted:
|
||||
confirmCell(sheet, 6, 1, 271, "200+B1");
|
||||
confirmCell(sheet, 7, 1, 272, "200+B12"); // this one moved
|
||||
confirmCell(sheet, 8, 1, 273, "200+B3");
|
||||
|
||||
// check formulas on other sheets
|
||||
HSSFSheet sheet2 = wb.getSheet("Sheet2");
|
||||
confirmCell(sheet2, 0, 0, 371, "300+Sheet1!B1");
|
||||
confirmCell(sheet2, 1, 0, 372, "300+Sheet1!B12");
|
||||
confirmCell(sheet2, 2, 0, 373, "300+Sheet1!B3");
|
||||
|
||||
confirmCell(sheet2, 11, 0, 300, "300+Sheet1!#REF!");
|
||||
|
||||
|
||||
// Note - named ranges formulas have not been updated
|
||||
}
|
||||
|
||||
private static void confirmRow(HSSFSheet sheet, int rowIx, double valA, double valB, double valC,
|
||||
String formulaA, String formulaB, String formulaC) {
|
||||
confirmCell(sheet, rowIx, 4, valA, formulaA);
|
||||
confirmCell(sheet, rowIx, 5, valB, formulaB);
|
||||
confirmCell(sheet, rowIx, 6, valC, formulaC);
|
||||
}
|
||||
|
||||
private static void confirmCell(HSSFSheet sheet, int rowIx, int colIx,
|
||||
double expectedValue, String expectedFormula) {
|
||||
HSSFCell cell = sheet.getRow(rowIx).getCell(colIx);
|
||||
assertEquals(expectedValue, cell.getNumericCellValue(), 0.0);
|
||||
assertEquals(expectedFormula, cell.getCellFormula());
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user