Update the formula evaluator to support XSSF style external named ranges too

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1612133 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2014-07-20 17:51:51 +00:00
parent d310441632
commit ecf2fe1238
14 changed files with 370 additions and 104 deletions

View File

@ -146,6 +146,10 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
return _iBook.getExternalName(externSheetIndex, externNameIndex); return _iBook.getExternalName(externSheetIndex, externNameIndex);
} }
public ExternalName getExternalName(String nameName, String sheetName, int externalWorkbookNumber) {
throw new IllegalStateException("XSSF-style external names are not supported for HSSF");
}
public String resolveNameXText(NameXPtg n) { public String resolveNameXText(NameXPtg n) {
return _iBook.resolveNameXText(n.getSheetRefIndex(), n.getNameIndex()); return _iBook.resolveNameXText(n.getSheetRefIndex(), n.getNameIndex());
} }

View File

@ -1504,8 +1504,10 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
// Update any formulas on this sheet that point to // Update any formulas on this sheet that point to
// rows which have been moved // rows which have been moved
int sheetIndex = _workbook.getSheetIndex(this); int sheetIndex = _workbook.getSheetIndex(this);
String sheetName = _workbook.getSheetName(sheetIndex);
short externSheetIndex = _book.checkExternSheet(sheetIndex); short externSheetIndex = _book.checkExternSheet(sheetIndex);
FormulaShifter shifter = FormulaShifter.createForRowShift(externSheetIndex, startRow, endRow, n); FormulaShifter shifter = FormulaShifter.createForRowShift(
externSheetIndex, sheetName, startRow, endRow, n);
_sheet.updateFormulasAfterCellShift(shifter, externSheetIndex); _sheet.updateFormulasAfterCellShift(shifter, externSheetIndex);
int nSheets = _workbook.getNumberOfSheets(); int nSheets = _workbook.getNumberOfSheets();

View File

@ -59,7 +59,15 @@ public interface EvaluationWorkbook {
*/ */
int convertFromExternSheetIndex(int externSheetIndex); int convertFromExternSheetIndex(int externSheetIndex);
/**
* HSSF Only - fetch the external-style name details
*/
ExternalName getExternalName(int externSheetIndex, int externNameIndex); ExternalName getExternalName(int externSheetIndex, int externNameIndex);
/**
* XSSF Only - fetch the external-style name details
*/
ExternalName getExternalName(String nameName, String sheetName, int externalWorkbookNumber);
EvaluationName getName(NamePtg namePtg); EvaluationName getName(NamePtg namePtg);
EvaluationName getName(String name, int sheetIndex); EvaluationName getName(String name, int sheetIndex);
String resolveNameXText(NameXPtg ptg); String resolveNameXText(NameXPtg ptg);

View File

@ -17,11 +17,25 @@
package org.apache.poi.ss.formula; package org.apache.poi.ss.formula;
import org.apache.poi.ss.formula.ptg.*; import org.apache.poi.ss.formula.ptg.Area2DPtgBase;
import org.apache.poi.ss.formula.ptg.Area3DPtg;
import org.apache.poi.ss.formula.ptg.Area3DPxg;
import org.apache.poi.ss.formula.ptg.AreaErrPtg;
import org.apache.poi.ss.formula.ptg.AreaPtg;
import org.apache.poi.ss.formula.ptg.AreaPtgBase;
import org.apache.poi.ss.formula.ptg.Deleted3DPxg;
import org.apache.poi.ss.formula.ptg.DeletedArea3DPtg;
import org.apache.poi.ss.formula.ptg.DeletedRef3DPtg;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
import org.apache.poi.ss.formula.ptg.Ref3DPxg;
import org.apache.poi.ss.formula.ptg.RefErrorPtg;
import org.apache.poi.ss.formula.ptg.RefPtg;
import org.apache.poi.ss.formula.ptg.RefPtgBase;
/** /**
* @author Josh Micich * Updates Formulas as rows or sheets are shifted
*/ */
public final class FormulaShifter { public final class FormulaShifter {
@ -31,9 +45,16 @@ public final class FormulaShifter {
} }
/** /**
* Extern sheet index of sheet where moving is occurring * Extern sheet index of sheet where moving is occurring,
* used for updating HSSF style 3D references
*/ */
private final int _externSheetIndex; private final int _externSheetIndex;
/**
* Sheet name of the sheet where moving is occurring,
* used for updating XSSF style 3D references on row shifts.
*/
private final String _sheetName;
private final int _firstMovedIndex; private final int _firstMovedIndex;
private final int _lastMovedIndex; private final int _lastMovedIndex;
private final int _amountToMove; private final int _amountToMove;
@ -48,7 +69,7 @@ public final class FormulaShifter {
* *
* For example, this will be called on {@link org.apache.poi.hssf.usermodel.HSSFSheet#shiftRows(int, int, int)} } * For example, this will be called on {@link org.apache.poi.hssf.usermodel.HSSFSheet#shiftRows(int, int, int)} }
*/ */
private FormulaShifter(int externSheetIndex, int firstMovedIndex, int lastMovedIndex, int amountToMove) { private FormulaShifter(int externSheetIndex, String sheetName, int firstMovedIndex, int lastMovedIndex, int amountToMove) {
if (amountToMove == 0) { if (amountToMove == 0) {
throw new IllegalArgumentException("amountToMove must not be zero"); throw new IllegalArgumentException("amountToMove must not be zero");
} }
@ -56,6 +77,7 @@ public final class FormulaShifter {
throw new IllegalArgumentException("firstMovedIndex, lastMovedIndex out of order"); throw new IllegalArgumentException("firstMovedIndex, lastMovedIndex out of order");
} }
_externSheetIndex = externSheetIndex; _externSheetIndex = externSheetIndex;
_sheetName = sheetName;
_firstMovedIndex = firstMovedIndex; _firstMovedIndex = firstMovedIndex;
_lastMovedIndex = lastMovedIndex; _lastMovedIndex = lastMovedIndex;
_amountToMove = amountToMove; _amountToMove = amountToMove;
@ -71,14 +93,15 @@ public final class FormulaShifter {
*/ */
private FormulaShifter(int srcSheetIndex, int dstSheetIndex) { private FormulaShifter(int srcSheetIndex, int dstSheetIndex) {
_externSheetIndex = _firstMovedIndex = _lastMovedIndex = _amountToMove = -1; _externSheetIndex = _firstMovedIndex = _lastMovedIndex = _amountToMove = -1;
_sheetName = null;
_srcSheetIndex = srcSheetIndex; _srcSheetIndex = srcSheetIndex;
_dstSheetIndex = dstSheetIndex; _dstSheetIndex = dstSheetIndex;
_mode = ShiftMode.Sheet; _mode = ShiftMode.Sheet;
} }
public static FormulaShifter createForRowShift(int externSheetIndex, int firstMovedRowIndex, int lastMovedRowIndex, int numberOfRowsToMove) { public static FormulaShifter createForRowShift(int externSheetIndex, String sheetName, int firstMovedRowIndex, int lastMovedRowIndex, int numberOfRowsToMove) {
return new FormulaShifter(externSheetIndex, firstMovedRowIndex, lastMovedRowIndex, numberOfRowsToMove); return new FormulaShifter(externSheetIndex, sheetName, firstMovedRowIndex, lastMovedRowIndex, numberOfRowsToMove);
} }
public static FormulaShifter createForSheetShift(int srcSheetIndex, int dstSheetIndex) { public static FormulaShifter createForSheetShift(int srcSheetIndex, int dstSheetIndex) {
@ -145,6 +168,14 @@ public final class FormulaShifter {
} }
return rowMoveRefPtg(rptg); return rowMoveRefPtg(rptg);
} }
if(ptg instanceof Ref3DPxg) {
Ref3DPxg rpxg = (Ref3DPxg)ptg;
if (rpxg.getExternalWorkbookNumber() > 0 ||
! _sheetName.equals(rpxg.getSheetName())) {
// only move 3D refs that refer to the sheet with cells being moved
}
return rowMoveRefPtg(rpxg);
}
if(ptg instanceof Area2DPtgBase) { if(ptg instanceof Area2DPtgBase) {
if (currentExternSheetIx != _externSheetIndex) { if (currentExternSheetIx != _externSheetIndex) {
// local refs on other sheets are unaffected // local refs on other sheets are unaffected
@ -161,6 +192,15 @@ public final class FormulaShifter {
} }
return rowMoveAreaPtg(aptg); return rowMoveAreaPtg(aptg);
} }
if(ptg instanceof Area3DPxg) {
Area3DPxg apxg = (Area3DPxg)ptg;
if (apxg.getExternalWorkbookNumber() > 0 ||
! _sheetName.equals(apxg.getSheetName())) {
// only move 3D refs that refer to the sheet with cells being moved
return null;
}
return rowMoveAreaPtg(apxg);
}
return null; return null;
} }
@ -348,6 +388,14 @@ public final class FormulaShifter {
Area3DPtg area3DPtg = (Area3DPtg) ptg; Area3DPtg area3DPtg = (Area3DPtg) ptg;
return new DeletedArea3DPtg(area3DPtg.getExternSheetIndex()); return new DeletedArea3DPtg(area3DPtg.getExternSheetIndex());
} }
if (ptg instanceof Ref3DPxg) {
Ref3DPxg pxg = (Ref3DPxg)ptg;
return new Deleted3DPxg(pxg.getExternalWorkbookNumber(), pxg.getSheetName());
}
if (ptg instanceof Area3DPxg) {
Area3DPxg pxg = (Area3DPxg)ptg;
return new Deleted3DPxg(pxg.getExternalWorkbookNumber(), pxg.getSheetName());
}
throw new IllegalArgumentException("Unexpected ref ptg class (" + ptg.getClass().getName() + ")"); throw new IllegalArgumentException("Unexpected ref ptg class (" + ptg.getClass().getName() + ")");
} }

View File

@ -23,7 +23,8 @@ import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet; import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet;
import org.apache.poi.ss.formula.eval.AreaEval; import org.apache.poi.ss.formula.eval.AreaEval;
import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.NameXEval; import org.apache.poi.ss.formula.eval.ExternalNameEval;
import org.apache.poi.ss.formula.eval.FunctionNameEval;
import org.apache.poi.ss.formula.eval.RefEval; import org.apache.poi.ss.formula.eval.RefEval;
import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.functions.FreeRefFunction; import org.apache.poi.ss.formula.functions.FreeRefFunction;
@ -299,32 +300,82 @@ public final class OperationEvaluationContext {
} }
public ValueEval getNameXEval(NameXPtg nameXPtg) { public ValueEval getNameXEval(NameXPtg nameXPtg) {
// Is the name actually on our workbook?
ExternalSheet externSheet = _workbook.getExternalSheet(nameXPtg.getSheetRefIndex()); ExternalSheet externSheet = _workbook.getExternalSheet(nameXPtg.getSheetRefIndex());
if(externSheet == null || externSheet.getWorkbookName() == null) { if(externSheet == null || externSheet.getWorkbookName() == null) {
// External reference to our own workbook's name // External reference to our own workbook's name
return new NameXEval(nameXPtg); return getLocalNameXEval(nameXPtg);
} }
// Look it up for the external workbook
String workbookName = externSheet.getWorkbookName(); String workbookName = externSheet.getWorkbookName();
ExternalName externName = _workbook.getExternalName( ExternalName externName = _workbook.getExternalName(
nameXPtg.getSheetRefIndex(), nameXPtg.getSheetRefIndex(),
nameXPtg.getNameIndex() nameXPtg.getNameIndex()
); );
return getNameXEval(externName, workbookName); return getExternalNameXEval(externName, workbookName);
} }
public ValueEval getNameXEval(NameXPxg nameXPxg) { public ValueEval getNameXEval(NameXPxg nameXPxg) {
ExternalSheet externSheet = _workbook.getExternalSheet(nameXPxg.getSheetName(), nameXPxg.getExternalWorkbookNumber()); ExternalSheet externSheet = _workbook.getExternalSheet(nameXPxg.getSheetName(), nameXPxg.getExternalWorkbookNumber());
if(externSheet == null || externSheet.getWorkbookName() == null) { if(externSheet == null || externSheet.getWorkbookName() == null) {
// External reference to our own workbook's name // External reference to our own workbook's name
// TODO How to do this? return getLocalNameXEval(nameXPxg);
return new NameXEval(null);
} }
// TODO // Look it up for the external workbook
return null; String workbookName = externSheet.getWorkbookName();
// return getNameXEval(nameXPxg.getNameName(), externSheet.getWorkbookName()); ExternalName externName = _workbook.getExternalName(
nameXPxg.getNameName(),
nameXPxg.getSheetName(),
nameXPxg.getExternalWorkbookNumber()
);
return getExternalNameXEval(externName, workbookName);
} }
private ValueEval getNameXEval(ExternalName externName, String workbookName) {
private ValueEval getLocalNameXEval(NameXPxg nameXPxg) {
// Look up the sheet, if present
int sIdx = -1;
if (nameXPxg.getSheetName() != null) {
sIdx = _workbook.getSheetIndex(nameXPxg.getSheetName());
}
// Is it a name or a function?
String name = nameXPxg.getNameName();
EvaluationName evalName = _workbook.getName(name, sIdx);
if (evalName != null) {
// Process it as a name
return new ExternalNameEval(evalName);
} else {
// Must be an external function
return new FunctionNameEval(name);
}
}
private ValueEval getLocalNameXEval(NameXPtg nameXPtg) {
String name = _workbook.resolveNameXText(nameXPtg);
// Try to parse it as a name
int sheetNameAt = name.indexOf('!');
EvaluationName evalName = null;
if (sheetNameAt > -1) {
// Sheet based name
String sheetName = name.substring(0, sheetNameAt);
String nameName = name.substring(sheetNameAt+1);
evalName = _workbook.getName(nameName, _workbook.getSheetIndex(sheetName));
} else {
// Workbook based name
evalName = _workbook.getName(name, -1);
}
if (evalName != null) {
// Process it as a name
return new ExternalNameEval(evalName);
} else {
// Must be an external function
return new FunctionNameEval(name);
}
}
private ValueEval getExternalNameXEval(ExternalName externName, String workbookName) {
try { try {
WorkbookEvaluator refWorkbookEvaluator = _bookEvaluator.getOtherWorkbookEvaluator(workbookName); WorkbookEvaluator refWorkbookEvaluator = _bookEvaluator.getOtherWorkbookEvaluator(workbookName);
EvaluationName evaluationName = refWorkbookEvaluator.getName(externName.getName(),externName.getIx()-1); EvaluationName evaluationName = refWorkbookEvaluator.getName(externName.getName(),externName.getIx()-1);

View File

@ -17,7 +17,7 @@
package org.apache.poi.ss.formula; package org.apache.poi.ss.formula;
import org.apache.poi.ss.formula.eval.NameEval; import org.apache.poi.ss.formula.eval.FunctionNameEval;
import org.apache.poi.ss.formula.eval.NotImplementedFunctionException; import org.apache.poi.ss.formula.eval.NotImplementedFunctionException;
import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.functions.FreeRefFunction; import org.apache.poi.ss.formula.functions.FreeRefFunction;
@ -45,8 +45,8 @@ final class UserDefinedFunction implements FreeRefFunction {
ValueEval nameArg = args[0]; ValueEval nameArg = args[0];
String functionName; String functionName;
if (nameArg instanceof NameEval) { if (nameArg instanceof FunctionNameEval) {
functionName = ((NameEval) nameArg).getFunctionName(); functionName = ((FunctionNameEval) nameArg).getFunctionName();
} else { } else {
throw new RuntimeException("First argument should be a NameEval, but got (" throw new RuntimeException("First argument should be a NameEval, but got ("
+ nameArg.getClass().getName() + ")"); + nameArg.getClass().getName() + ")");

View File

@ -30,10 +30,10 @@ import org.apache.poi.ss.formula.eval.BlankEval;
import org.apache.poi.ss.formula.eval.BoolEval; import org.apache.poi.ss.formula.eval.BoolEval;
import org.apache.poi.ss.formula.eval.ErrorEval; import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.EvaluationException; import org.apache.poi.ss.formula.eval.EvaluationException;
import org.apache.poi.ss.formula.eval.ExternalNameEval;
import org.apache.poi.ss.formula.eval.FunctionEval; import org.apache.poi.ss.formula.eval.FunctionEval;
import org.apache.poi.ss.formula.eval.FunctionNameEval;
import org.apache.poi.ss.formula.eval.MissingArgEval; import org.apache.poi.ss.formula.eval.MissingArgEval;
import org.apache.poi.ss.formula.eval.NameEval;
import org.apache.poi.ss.formula.eval.NameXEval;
import org.apache.poi.ss.formula.eval.NotImplementedException; import org.apache.poi.ss.formula.eval.NotImplementedException;
import org.apache.poi.ss.formula.eval.NumberEval; import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.OperandResolver; import org.apache.poi.ss.formula.eval.OperandResolver;
@ -638,37 +638,13 @@ public final class WorkbookEvaluator {
EvaluationName nameRecord = _workbook.getName(namePtg); EvaluationName nameRecord = _workbook.getName(namePtg);
return getEvalForNameRecord(nameRecord, ec); return getEvalForNameRecord(nameRecord, ec);
} }
if (ptg instanceof NameXPtg) { // TODO Generalise for NameXPxg if (ptg instanceof NameXPtg) {
// Externally defined named ranges or macro functions // Externally defined named ranges or macro functions
NameXPtg nameXPtg = (NameXPtg)ptg; return processNameEval(ec.getNameXEval((NameXPtg)ptg), ec);
ValueEval eval = ec.getNameXEval(nameXPtg);
if (eval instanceof NameXEval) {
// Could not be directly evaluated, so process as a name
return getEvalForNameX(nameXPtg, ec);
} else {
// Use the evaluated version
return eval;
}
} }
if (ptg instanceof NameXPxg) { if (ptg instanceof NameXPxg) {
// TODO This is a temporary hack.... // Externally defined named ranges or macro functions
NameXPxg pxg = (NameXPxg)ptg; return processNameEval(ec.getNameXEval((NameXPxg)ptg), ec);
int sIdx = -1;
if (pxg.getSheetName() != null) {
sIdx = _workbook.getSheetIndex(pxg.getSheetName());
}
EvaluationName evalName = _workbook.getName(pxg.getNameName(), sIdx);
if (evalName == null) {
// We don't know about that name, sorry
// TODO What about UDFs?
logInfo("Unknown Name referenced: " + pxg.getNameName());
return ErrorEval.NAME_INVALID;
}
int nIdx = evalName.createPtg().getIndex();
NameXPtg nptg = new NameXPtg(sIdx, nIdx);
return getEvalForPtg(nptg, ec);
} }
if (ptg instanceof IntPtg) { if (ptg instanceof IntPtg) {
@ -729,9 +705,17 @@ public final class WorkbookEvaluator {
throw new RuntimeException("Unexpected ptg class (" + ptg.getClass().getName() + ")"); throw new RuntimeException("Unexpected ptg class (" + ptg.getClass().getName() + ")");
} }
private ValueEval processNameEval(ValueEval eval, OperationEvaluationContext ec) {
if (eval instanceof ExternalNameEval) {
EvaluationName name = ((ExternalNameEval)eval).getName();
return getEvalForNameRecord(name, ec);
}
return eval;
}
private ValueEval getEvalForNameRecord(EvaluationName nameRecord, OperationEvaluationContext ec) { private ValueEval getEvalForNameRecord(EvaluationName nameRecord, OperationEvaluationContext ec) {
if (nameRecord.isFunctionName()) { if (nameRecord.isFunctionName()) {
return new NameEval(nameRecord.getNameText()); return new FunctionNameEval(nameRecord.getNameText());
} }
if (nameRecord.hasFormula()) { if (nameRecord.hasFormula()) {
return evaluateNameFormula(nameRecord.getNameDefinition(), ec); return evaluateNameFormula(nameRecord.getNameDefinition(), ec);
@ -739,30 +723,6 @@ public final class WorkbookEvaluator {
throw new RuntimeException("Don't now how to evalate name '" + nameRecord.getNameText() + "'"); throw new RuntimeException("Don't now how to evalate name '" + nameRecord.getNameText() + "'");
} }
private ValueEval getEvalForNameX(NameXPtg nameXPtg, OperationEvaluationContext ec) {
String name = _workbook.resolveNameXText(nameXPtg);
// Try to parse it as a name
int sheetNameAt = name.indexOf('!');
EvaluationName nameRecord = null;
if (sheetNameAt > -1) {
// Sheet based name
String sheetName = name.substring(0, sheetNameAt);
String nameName = name.substring(sheetNameAt+1);
nameRecord = _workbook.getName(nameName, _workbook.getSheetIndex(sheetName));
} else {
// Workbook based name
nameRecord = _workbook.getName(name, -1);
}
if (nameRecord != null) {
// Process it as a name
return getEvalForNameRecord(nameRecord, ec);
} else {
// Must be an external function
return new NameEval(name);
}
}
/** /**
* YK: Used by OperationEvaluationContext to resolve indirect names. * YK: Used by OperationEvaluationContext to resolve indirect names.

View File

@ -117,6 +117,9 @@ final class ForkedEvaluationWorkbook implements EvaluationWorkbook {
public ExternalName getExternalName(int externSheetIndex, int externNameIndex) { public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
return _masterBook.getExternalName(externSheetIndex, externNameIndex); return _masterBook.getExternalName(externSheetIndex, externNameIndex);
} }
public ExternalName getExternalName(String nameName, String sheetName, int externalWorkbookNumber) {
return _masterBook.getExternalName(nameName, sheetName, externalWorkbookNumber);
}
public int getSheetIndex(EvaluationSheet sheet) { public int getSheetIndex(EvaluationSheet sheet) {
if (sheet instanceof ForkedEvaluationSheet) { if (sheet instanceof ForkedEvaluationSheet) {

View File

@ -0,0 +1,87 @@
/* ====================================================================
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.ss.formula.ptg;
import org.apache.poi.ss.usermodel.ErrorConstants;
import org.apache.poi.util.LittleEndianOutput;
/**
* An XSSF only representation of a reference to a deleted area
*/
public final class Deleted3DPxg extends OperandPtg {
private int externalWorkbookNumber = -1;
private String sheetName;
public Deleted3DPxg(int externalWorkbookNumber, String sheetName) {
this.externalWorkbookNumber = externalWorkbookNumber;
this.sheetName = sheetName;
}
public Deleted3DPxg(String sheetName) {
this(-1, sheetName);
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(getClass().getName());
sb.append(" [");
if (externalWorkbookNumber >= 0) {
sb.append(" [");
sb.append("workbook=").append(getExternalWorkbookNumber());
sb.append("] ");
}
sb.append("sheet=").append(getSheetName());
sb.append(" ! ");
sb.append(ErrorConstants.getText(ErrorConstants.ERROR_REF));
sb.append("]");
return sb.toString();
}
public int getExternalWorkbookNumber() {
return externalWorkbookNumber;
}
public String getSheetName() {
return sheetName;
}
public String toFormulaString() {
StringBuffer sb = new StringBuffer();
if (externalWorkbookNumber >= 0) {
sb.append('[');
sb.append(externalWorkbookNumber);
sb.append(']');
}
if (sheetName != null) {
sb.append(sheetName);
}
sb.append('!');
sb.append(ErrorConstants.getText(ErrorConstants.ERROR_REF));
return sb.toString();
}
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
public int getSize() {
return 1;
}
public void write(LittleEndianOutput out) {
throw new IllegalStateException("XSSF-only Ptg, should not be serialised");
}
}

View File

@ -119,7 +119,21 @@ public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
} }
public ExternalName getExternalName(int externSheetIndex, int externNameIndex) { public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
throw new RuntimeException("Not implemented yet"); throw new IllegalStateException("HSSF-style external references are not supported for XSSF");
}
public ExternalName getExternalName(String nameName, String sheetName, int externalWorkbookNumber) {
if (externalWorkbookNumber > 0) {
// External reference - reference is 1 based, link table is 0 based
int linkNumber = externalWorkbookNumber - 1;
ExternalLinksTable linkTable = _uBook.getExternalLinksTable().get(linkNumber);
return new ExternalName(nameName, -1, -1); // TODO Finish this
} else {
// Internal reference
int nameIdx = _uBook.getNameIndex(nameName);
return new ExternalName(nameName, nameIdx, -1); // TODO Is this right?
}
} }
public NameXPxg getNameXPtg(String name, SheetIdentifier sheet) { public NameXPxg getNameXPtg(String name, SheetIdentifier sheet) {
@ -131,6 +145,12 @@ public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
} }
// Otherwise, try it as a named range // Otherwise, try it as a named range
if (sheet == null) {
if (_uBook.getNameIndex(name) > -1) {
return new NameXPxg(null, name);
}
return null;
}
if (sheet._sheetIdentifier == null) { if (sheet._sheetIdentifier == null) {
// Workbook + Named Range only // Workbook + Named Range only
int bookIndex = resolveBookIndex(sheet._bookName); int bookIndex = resolveBookIndex(sheet._bookName);

View File

@ -42,7 +42,16 @@ import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.formula.FormulaShifter; import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.formula.SheetNameFormatter; import org.apache.poi.ss.formula.SheetNameFormatter;
import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellRange;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.Footer;
import org.apache.poi.ss.usermodel.Header;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference;
@ -58,7 +67,48 @@ import org.apache.poi.xssf.usermodel.helpers.XSSFRowShifter;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions; import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId; import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAutoFilter;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBreak;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCalcPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCommentList;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataValidation;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataValidations;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDrawing;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHeaderFooter;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHyperlink;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTLegacyDrawing;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCell;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCells;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOutlinePr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageBreak;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageMargins;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageSetUpPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPane;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPrintOptions;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSelection;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetCalcPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetFormatPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetProtection;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetView;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTablePart;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableParts;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPaneState;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnsignedShortHex;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument;
/** /**
* High level representation of a SpreadsheetML worksheet. * High level representation of a SpreadsheetML worksheet.
@ -2498,7 +2548,9 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
XSSFRowShifter rowShifter = new XSSFRowShifter(this); XSSFRowShifter rowShifter = new XSSFRowShifter(this);
int sheetIndex = getWorkbook().getSheetIndex(this); int sheetIndex = getWorkbook().getSheetIndex(this);
FormulaShifter shifter = FormulaShifter.createForRowShift(sheetIndex, startRow, endRow, n); String sheetName = getWorkbook().getSheetName(sheetIndex);
FormulaShifter shifter = FormulaShifter.createForRowShift(
sheetIndex, sheetName, startRow, endRow, n);
rowShifter.updateNamedRanges(shifter); rowShifter.updateNamedRanges(shifter);
rowShifter.updateFormulas(shifter); rowShifter.updateFormulas(shifter);

View File

@ -17,21 +17,30 @@
package org.apache.poi.xssf.usermodel.helpers; package org.apache.poi.xssf.usermodel.helpers;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.formula.FormulaParser;
import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.ss.formula.FormulaRenderer;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.formula.ptg.AreaPtg;
import org.apache.poi.ss.formula.ptg.AreaErrPtg;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import org.apache.poi.ss.formula.FormulaParser;
import org.apache.poi.ss.formula.FormulaRenderer;
import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.ss.formula.ptg.AreaErrPtg;
import org.apache.poi.ss.formula.ptg.AreaPtg;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook;
import org.apache.poi.xssf.usermodel.XSSFName;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCfRule;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTConditionalFormatting;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType;
/** /**
* @author Yegor Kozlov * @author Yegor Kozlov
@ -115,7 +124,6 @@ public final class XSSFRowShifter {
String shiftedFmla = FormulaRenderer.toFormulaString(fpb, ptgs); String shiftedFmla = FormulaRenderer.toFormulaString(fpb, ptgs);
name.setRefersToFormula(shiftedFmla); name.setRefersToFormula(shiftedFmla);
} }
} }
} }

View File

@ -17,11 +17,39 @@
package org.apache.poi.hssf.model; package org.apache.poi.hssf.model;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import junit.framework.AssertionFailedError; import junit.framework.AssertionFailedError;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.ddf.EscherDggRecord; import org.apache.poi.ddf.EscherDggRecord;
import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.*; import org.apache.poi.hssf.record.BOFRecord;
import org.apache.poi.hssf.record.BlankRecord;
import org.apache.poi.hssf.record.CellValueRecordInterface;
import org.apache.poi.hssf.record.ColumnInfoRecord;
import org.apache.poi.hssf.record.DimensionsRecord;
import org.apache.poi.hssf.record.DrawingRecord;
import org.apache.poi.hssf.record.EOFRecord;
import org.apache.poi.hssf.record.EscherAggregate;
import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.GutsRecord;
import org.apache.poi.hssf.record.IndexRecord;
import org.apache.poi.hssf.record.MergeCellsRecord;
import org.apache.poi.hssf.record.MulBlankRecord;
import org.apache.poi.hssf.record.NoteRecord;
import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.ObjRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordBase;
import org.apache.poi.hssf.record.RowRecord;
import org.apache.poi.hssf.record.StringRecord;
import org.apache.poi.hssf.record.TextObjectRecord;
import org.apache.poi.hssf.record.UncalcedRecord;
import org.apache.poi.hssf.record.WindowTwoRecord;
import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable; import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable;
import org.apache.poi.hssf.record.aggregates.PageSettingsBlock; import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor; import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
@ -35,11 +63,6 @@ import org.apache.poi.ss.formula.FormulaShifter;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.HexRead; import org.apache.poi.util.HexRead;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/** /**
* Unit test for the {@link InternalSheet} class. * Unit test for the {@link InternalSheet} class.
* *
@ -632,7 +655,7 @@ public final class TestSheet extends TestCase {
List<RecordBase> sheetRecs = sheet.getRecords(); List<RecordBase> sheetRecs = sheet.getRecords();
assertEquals(23, sheetRecs.size()); assertEquals(23, sheetRecs.size());
FormulaShifter shifter = FormulaShifter.createForRowShift(0, 0, 0, 1); FormulaShifter shifter = FormulaShifter.createForRowShift(0, "", 0, 0, 1);
sheet.updateFormulasAfterCellShift(shifter, 0); sheet.updateFormulasAfterCellShift(shifter, 0);
if (sheetRecs.size() == 24 && sheetRecs.get(22) instanceof ConditionalFormattingTable) { if (sheetRecs.size() == 24 && sheetRecs.get(22) instanceof ConditionalFormattingTable) {
throw new AssertionFailedError("Identified bug 46547a"); throw new AssertionFailedError("Identified bug 46547a");

View File

@ -97,7 +97,7 @@ public final class TestFormulaShifter extends TestCase {
int firstRowMoved, int lastRowMoved, int numberRowsMoved, int firstRowMoved, int lastRowMoved, int numberRowsMoved,
int expectedAreaFirstRow, int expectedAreaLastRow) { int expectedAreaFirstRow, int expectedAreaLastRow) {
FormulaShifter fs = FormulaShifter.createForRowShift(0, firstRowMoved, lastRowMoved, numberRowsMoved); FormulaShifter fs = FormulaShifter.createForRowShift(0, "", firstRowMoved, lastRowMoved, numberRowsMoved);
boolean expectedChanged = aptg.getFirstRow() != expectedAreaFirstRow || aptg.getLastRow() != expectedAreaLastRow; boolean expectedChanged = aptg.getFirstRow() != expectedAreaFirstRow || aptg.getLastRow() != expectedAreaLastRow;
AreaPtg copyPtg = (AreaPtg) aptg.copy(); // clone so we can re-use aptg in calling method AreaPtg copyPtg = (AreaPtg) aptg.copy(); // clone so we can re-use aptg in calling method