aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Burch <nick@apache.org>2010-06-10 17:07:06 +0000
committerNick Burch <nick@apache.org>2010-06-10 17:07:06 +0000
commit034e5c4a978f646c7e62b571db56758e6df5fc14 (patch)
tree7612208e923c964cf6a4655251bc231095ec2e32
parent129cf711e1361a879e9ab92d09212107816449ee (diff)
downloadpoi-034e5c4a978f646c7e62b571db56758e6df5fc14.tar.gz
poi-034e5c4a978f646c7e62b571db56758e6df5fc14.zip
Apply, with a few tweaks, the patch from bug #48996 - initial support for External Name References in HSSF formula evaluation
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@953395 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/documentation/content/xdocs/status.xml1
-rw-r--r--src/java/org/apache/poi/hssf/dev/BiffViewer.java1
-rw-r--r--src/java/org/apache/poi/hssf/model/InternalWorkbook.java9
-rw-r--r--src/java/org/apache/poi/hssf/model/LinkTable.java14
-rw-r--r--src/java/org/apache/poi/hssf/record/ExternalNameRecord.java34
-rw-r--r--src/java/org/apache/poi/hssf/record/formula/NameXPtg.java8
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java5
-rw-r--r--src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java21
-rw-r--r--src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java41
-rw-r--r--src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java20
-rw-r--r--src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java4
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java5
-rw-r--r--src/testcases/org/apache/poi/hssf/record/formula/TestExternalNameReference.java106
-rw-r--r--src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java61
-rw-r--r--test-data/spreadsheet/XRefCalc.xlsbin0 -> 18944 bytes
-rw-r--r--test-data/spreadsheet/XRefCalcData.xlsbin0 -> 23040 bytes
16 files changed, 318 insertions, 12 deletions
diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml
index 50e37663d6..e0cdba7af7 100644
--- a/src/documentation/content/xdocs/status.xml
+++ b/src/documentation/content/xdocs/status.xml
@@ -34,6 +34,7 @@
<changes>
<release version="3.7-SNAPSHOT" date="2010-??-??">
+ <action dev="POI-DEVELOPERS" type="add">48996 - initial support for External Name References in HSSF formula evaluation</action>
<action dev="POI-DEVELOPERS" type="fix">46664 - fix up Tab IDs when adding new sheets, so that print areas don't end up invalid</action>
<action dev="POI-DEVELOPERS" type="fix">45269 - improve replaceText on HWPF ranges</action>
<action dev="POI-DEVELOPERS" type="fix">47815 - correct documentation on what happens when you request a String from a non-string Formula cell</action>
diff --git a/src/java/org/apache/poi/hssf/dev/BiffViewer.java b/src/java/org/apache/poi/hssf/dev/BiffViewer.java
index aed5c199e4..ba79aa80d2 100644
--- a/src/java/org/apache/poi/hssf/dev/BiffViewer.java
+++ b/src/java/org/apache/poi/hssf/dev/BiffViewer.java
@@ -162,6 +162,7 @@ public final class BiffViewer {
case ExtSSTRecord.sid: return new ExtSSTRecord(in);
case ExtendedFormatRecord.sid: return new ExtendedFormatRecord(in);
case ExternSheetRecord.sid: return new ExternSheetRecord(in);
+ case ExternalNameRecord.sid: return new ExternalNameRecord(in);
case FeatRecord.sid: return new FeatRecord(in);
case FeatHdrRecord.sid: return new FeatHdrRecord(in);
case FilePassRecord.sid: return new FilePassRecord(in);
diff --git a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java
index b1340f524b..567b986e70 100644
--- a/src/java/org/apache/poi/hssf/model/InternalWorkbook.java
+++ b/src/java/org/apache/poi/hssf/model/InternalWorkbook.java
@@ -81,6 +81,7 @@ import org.apache.poi.hssf.record.formula.NameXPtg;
import org.apache.poi.hssf.record.formula.FormulaShifter;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet;
import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
@@ -1771,6 +1772,14 @@ public final class InternalWorkbook {
}
return new ExternalSheet(extNames[0], extNames[1]);
}
+ public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
+ String nameName = linkTable.resolveNameXText(externSheetIndex, externNameIndex);
+ if(nameName == null) {
+ return null;
+ }
+ int ix = linkTable.resolveNameXIx(externSheetIndex, externNameIndex);
+ return new ExternalName(nameName, externNameIndex, ix);
+ }
/**
* Finds the sheet index for a particular external sheet number.
diff --git a/src/java/org/apache/poi/hssf/model/LinkTable.java b/src/java/org/apache/poi/hssf/model/LinkTable.java
index 73b7d02da0..10a6b3063b 100644
--- a/src/java/org/apache/poi/hssf/model/LinkTable.java
+++ b/src/java/org/apache/poi/hssf/model/LinkTable.java
@@ -124,6 +124,10 @@ final class LinkTable {
public String getNameText(int definedNameIndex) {
return _externalNameRecords[definedNameIndex].getText();
}
+
+ public int getNameIx(int definedNameIndex) {
+ return _externalNameRecords[definedNameIndex].getIx();
+ }
/**
* Performs case-insensitive search
@@ -316,8 +320,12 @@ final class LinkTable {
if (!ebr.isExternalReferences()) {
return null;
}
+ // Sheet name only applies if not a global reference
int shIx = _externSheetRecord.getFirstSheetIndexFromRefIndex(extRefIndex);
- String usSheetName = ebr.getSheetNames()[shIx];
+ String usSheetName = null;
+ if(shIx >= 0) {
+ usSheetName = ebr.getSheetNames()[shIx];
+ }
return new String[] {
ebr.getURL(),
usSheetName,
@@ -419,6 +427,10 @@ final class LinkTable {
int extBookIndex = _externSheetRecord.getExtbookIndexFromRefIndex(refIndex);
return _externalBookBlocks[extBookIndex].getNameText(definedNameIndex);
}
+ public int resolveNameXIx(int refIndex, int definedNameIndex) {
+ int extBookIndex = _externSheetRecord.getExtbookIndexFromRefIndex(refIndex);
+ return _externalBookBlocks[extBookIndex].getNameIx(definedNameIndex);
+ }
public NameXPtg getNameXPtg(String name) {
// first find any external book block that contains the name:
diff --git a/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java b/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java
index 6619da8c78..0156ca0678 100644
--- a/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java
+++ b/src/java/org/apache/poi/hssf/record/ExternalNameRecord.java
@@ -41,7 +41,8 @@ public final class ExternalNameRecord extends StandardRecord {
private short field_1_option_flag;
- private int field_2_not_used;
+ private short field_2_ixals;
+ private short field_3_not_used;
private String field_4_name;
private Formula field_5_name_definition;
@@ -96,6 +97,16 @@ public final class ExternalNameRecord extends StandardRecord {
public String getText() {
return field_4_name;
}
+
+ /**
+ * If this is a local name, then this is the (1 based)
+ * index of the name of the Sheet this refers to, as
+ * defined in the preceeding {@link SupBookRecord}.
+ * If it isn't a local name, then it must be zero.
+ */
+ public short getIx() {
+ return field_2_ixals;
+ }
protected int getDataSize(){
int result = 2 + 4; // short and int
@@ -114,10 +125,11 @@ public final class ExternalNameRecord extends StandardRecord {
public void serialize(LittleEndianOutput out) {
out.writeShort(field_1_option_flag);
- out.writeInt(field_2_not_used);
+ out.writeShort(field_2_ixals);
+ out.writeShort(field_3_not_used);
- out.writeByte(field_4_name.length());
- StringUtil.writeUnicodeStringFlagAndData(out, field_4_name);
+ out.writeByte(field_4_name.length());
+ StringUtil.writeUnicodeStringFlagAndData(out, field_4_name);
if(!isOLELink() && !isStdDocumentNameIdentifier()){
if(isAutomaticLink()){
@@ -133,7 +145,8 @@ public final class ExternalNameRecord extends StandardRecord {
public ExternalNameRecord(RecordInputStream in) {
field_1_option_flag = in.readShort();
- field_2_not_used = in.readInt();
+ field_2_ixals = in.readShort();
+ field_3_not_used = in.readShort();
int numChars = in.readUByte();
field_4_name = StringUtil.readUnicodeString(in, numChars);
@@ -166,10 +179,13 @@ public final class ExternalNameRecord extends StandardRecord {
public String toString() {
StringBuffer sb = new StringBuffer();
- sb.append(getClass().getName()).append(" [EXTERNALNAME ");
- sb.append(" ").append(field_4_name);
- sb.append(" ix=").append(field_2_not_used);
- sb.append("]");
+ sb.append("[EXTERNALNAME]\n");
+ sb.append(" .ix = ").append(field_2_ixals).append("\n");
+ sb.append(" .name = ").append(field_4_name).append("\n");
+ if(field_5_name_definition != null) {
+ sb.append(" .formula = ").append(field_5_name_definition).append("\n");
+ }
+ sb.append("[/EXTERNALNAME]\n");
return sb.toString();
}
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java b/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java
index de08763c73..5b4176f485 100644
--- a/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java
+++ b/src/java/org/apache/poi/hssf/record/formula/NameXPtg.java
@@ -73,7 +73,13 @@ public final class NameXPtg extends OperandPtg implements WorkbookDependentFormu
public String toFormulaString() {
throw new RuntimeException("3D references need a workbook to determine formula text");
}
-
+
+ public String toString(){
+ String retValue = "NameXPtg:[sheetRefIndex:" + _sheetRefIndex +
+ " , nameNumber:" + _nameNumber + "]" ;
+ return retValue;
+ }
+
public byte getDefaultOperandClass() {
return Ptg.CLASS_VALUE;
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
index 1f10a926ad..2ac66d64e3 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
@@ -33,6 +33,7 @@ import org.apache.poi.ss.formula.FormulaParseException;
import org.apache.poi.ss.formula.FormulaParsingWorkbook;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
import org.apache.poi.ss.formula.FormulaType;
+import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
/**
* Internal POI use only
@@ -107,6 +108,10 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
public ExternalSheet getExternalSheet(int externSheetIndex) {
return _iBook.getExternalSheet(externSheetIndex);
}
+
+ public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
+ return _iBook.getExternalName(externSheetIndex, externNameIndex);
+ }
public String resolveNameXText(NameXPtg n) {
return _iBook.resolveNameXText(n.getSheetRefIndex(), n.getNameIndex());
diff --git a/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java b/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
index a3b2325719..1f42aa8930 100644
--- a/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
+++ b/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
@@ -47,6 +47,7 @@ public interface EvaluationWorkbook {
*/
ExternalSheet getExternalSheet(int externSheetIndex);
int convertFromExternSheetIndex(int externSheetIndex);
+ ExternalName getExternalName(int externSheetIndex, int externNameIndex);
EvaluationName getName(NamePtg namePtg);
String resolveNameXText(NameXPtg ptg);
Ptg[] getFormulaTokens(EvaluationCell cell);
@@ -66,4 +67,24 @@ public interface EvaluationWorkbook {
return _sheetName;
}
}
+ class ExternalName {
+ private final String _nameName;
+ private final int _nameNumber;
+ private final int _ix;
+
+ public ExternalName(String nameName, int nameNumber, int ix) {
+ _nameName = nameName;
+ _nameNumber = nameNumber;
+ _ix = ix;
+ }
+ public String getName() {
+ return _nameName;
+ }
+ public int getNumber() {
+ return _nameNumber;
+ }
+ public int getIx() {
+ return _ix;
+ }
+ }
}
diff --git a/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java b/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
index 147e07d7a5..71db36e0c6 100644
--- a/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
+++ b/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
@@ -17,10 +17,15 @@
package org.apache.poi.ss.formula;
+import org.apache.poi.hssf.record.formula.Area3DPtg;
+import org.apache.poi.hssf.record.formula.NameXPtg;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.eval.*;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException;
+import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.CellReference.NameType;
@@ -254,4 +259,40 @@ public final class OperationEvaluationContext {
SheetRefEvaluator sre = createExternSheetRefEvaluator(extSheetIndex);
return new LazyAreaEval(firstRowIndex, firstColumnIndex, lastRowIndex, lastColumnIndex, sre);
}
+ public ValueEval getNameXEval(NameXPtg nameXPtg) {
+ ExternalSheet externSheet = _workbook.getExternalSheet(nameXPtg.getSheetRefIndex());
+ if(externSheet == null)
+ return new NameXEval(nameXPtg);
+ String workbookName = externSheet.getWorkbookName();
+ ExternalName externName = _workbook.getExternalName(
+ nameXPtg.getSheetRefIndex(),
+ nameXPtg.getNameIndex()
+ );
+ try{
+ WorkbookEvaluator refWorkbookEvaluator = _bookEvaluator.getOtherWorkbookEvaluator(workbookName);
+ EvaluationName evaluationName = refWorkbookEvaluator.getName(externName.getName(),externName.getIx()-1);
+ if(evaluationName != null && evaluationName.hasFormula()){
+ if (evaluationName.getNameDefinition().length > 1) {
+ throw new RuntimeException("Complex name formulas not supported yet");
+ }
+ Ptg ptg = evaluationName.getNameDefinition()[0];
+ if(ptg instanceof Ref3DPtg){
+ Ref3DPtg ref3D = (Ref3DPtg)ptg;
+ int sheetIndex = refWorkbookEvaluator.getSheetIndexByExternIndex(ref3D.getExternSheetIndex());
+ String sheetName = refWorkbookEvaluator.getSheetName(sheetIndex);
+ SheetRefEvaluator sre = createExternSheetRefEvaluator(workbookName, sheetName);
+ return new LazyRefEval(ref3D.getRow(), ref3D.getColumn(), sre);
+ }else if(ptg instanceof Area3DPtg){
+ Area3DPtg area3D = (Area3DPtg)ptg;
+ int sheetIndex = refWorkbookEvaluator.getSheetIndexByExternIndex(area3D.getExternSheetIndex());
+ String sheetName = refWorkbookEvaluator.getSheetName(sheetIndex);
+ SheetRefEvaluator sre = createExternSheetRefEvaluator(workbookName, sheetName);
+ return new LazyAreaEval(area3D.getFirstRow(), area3D.getFirstColumn(), area3D.getLastRow(), area3D.getLastColumn(), sre);
+ }
+ }
+ return ErrorEval.REF_INVALID;
+ }catch(WorkbookNotFoundException wnfe){
+ return ErrorEval.REF_INVALID;
+ }
+ }
}
diff --git a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
index ad15b84e9c..60d31a707d 100644
--- a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
+++ b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
@@ -65,6 +65,7 @@ import org.apache.poi.hssf.record.formula.functions.Choose;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
import org.apache.poi.hssf.record.formula.functions.IfFunc;
import org.apache.poi.hssf.record.formula.udf.UDFFinder;
+import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException;
import org.apache.poi.ss.formula.eval.NotImplementedException;
@@ -124,6 +125,19 @@ public final class WorkbookEvaluator {
/* package */ EvaluationSheet getSheet(int sheetIndex) {
return _workbook.getSheet(sheetIndex);
}
+
+ /* package */ EvaluationName getName(String name, int sheetIndex) {
+ NamePtg namePtg = null;
+ if(_workbook instanceof HSSFEvaluationWorkbook){
+ namePtg =((HSSFEvaluationWorkbook)_workbook).getName(name, sheetIndex).createPtg();
+ }
+
+ if(namePtg == null) {
+ return null;
+ } else {
+ return _workbook.getName(namePtg);
+ }
+ }
private static boolean isDebugLogEnabled() {
return false;
@@ -223,6 +237,10 @@ public final class WorkbookEvaluator {
}
return result.intValue();
}
+
+ /* package */ int getSheetIndexByExternIndex(int externSheetIndex) {
+ return _workbook.convertFromExternSheetIndex(externSheetIndex);
+ }
/**
@@ -524,7 +542,7 @@ public final class WorkbookEvaluator {
throw new RuntimeException("Don't now how to evalate name '" + nameRecord.getNameText() + "'");
}
if (ptg instanceof NameXPtg) {
- return new NameXEval(((NameXPtg) ptg));
+ return ec.getNameXEval(((NameXPtg) ptg));
}
if (ptg instanceof IntPtg) {
diff --git a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java
index 08ed7f5346..c916006764 100644
--- a/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java
+++ b/src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java
@@ -106,6 +106,10 @@ final class ForkedEvaluationWorkbook implements EvaluationWorkbook {
public EvaluationSheet getSheet(int sheetIndex) {
return getSharedSheet(getSheetName(sheetIndex));
}
+
+ public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
+ return _masterBook.getExternalName(externSheetIndex, externNameIndex);
+ }
public int getSheetIndex(EvaluationSheet sheet) {
if (sheet instanceof ForkedEvaluationSheet) {
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java
index c3467fc7ed..b2c71fee23 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java
@@ -29,6 +29,7 @@ import org.apache.poi.ss.formula.FormulaParser;
import org.apache.poi.ss.formula.FormulaParsingWorkbook;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
import org.apache.poi.ss.formula.FormulaType;
+import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalName;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
/**
@@ -94,6 +95,10 @@ public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
public String getSheetName(int sheetIndex) {
return _uBook.getSheetName(sheetIndex);
}
+
+ public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
+ throw new RuntimeException("Not implemented yet");
+ }
public NameXPtg getNameXPtg(String name) {
// may require to return null to make tests pass
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/TestExternalNameReference.java b/src/testcases/org/apache/poi/hssf/record/formula/TestExternalNameReference.java
new file mode 100644
index 0000000000..6d2b871c30
--- /dev/null
+++ b/src/testcases/org/apache/poi/hssf/record/formula/TestExternalNameReference.java
@@ -0,0 +1,106 @@
+/* ====================================================================
+ 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;
+
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.CellReference;
+/**
+ * Tests for proper calculation of named ranges from external workbooks.
+ *
+ *
+ * @author Stephen Wolke (smwolke at geistig.com)
+ */
+public final class TestExternalNameReference extends TestCase {
+ double MARKUP_COST = 1.9d;
+ double MARKUP_COST_1 = 1.8d;
+ double MARKUP_COST_2 = 1.5d;
+ double PART_COST = 12.3d;
+ double NEW_QUANT = 7.0d;
+ double NEW_PART_COST = 15.3d;
+ /**
+ * tests <tt>NameXPtg for external cell reference by name</tt> and logic in Workbook below that
+ */
+ public void testReadCalcSheet() {
+ try{
+ HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("XRefCalc.xls");
+ assertEquals("Sheet1!$A$2", wb.getName("QUANT").getRefersToFormula());
+ assertEquals("Sheet1!$B$2", wb.getName("PART").getRefersToFormula());
+ assertEquals("x123",wb.getSheet("Sheet1").getRow(1).getCell(1).getStringCellValue());
+ assertEquals("Sheet1!$C$2", wb.getName("UNITCOST").getRefersToFormula());
+ CellReference cellRef = new CellReference(wb.getName("UNITCOST").getRefersToFormula());
+ HSSFCell cell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
+ assertEquals("VLOOKUP(PART,COSTS,2,FALSE)",cell.getCellFormula());
+ assertEquals("Sheet1!$D$2", wb.getName("COST").getRefersToFormula());
+ cellRef = new CellReference(wb.getName("COST").getRefersToFormula());
+ cell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
+ assertEquals("UNITCOST*Quant",cell.getCellFormula());
+ assertEquals("Sheet1!$E$2", wb.getName("TOTALCOST").getRefersToFormula());
+ cellRef = new CellReference(wb.getName("TOTALCOST").getRefersToFormula());
+ cell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
+ assertEquals("Cost*Markup_Cost",cell.getCellFormula());
+ }catch(Exception e){
+ fail();
+ }
+ }
+
+ public void testReadReferencedSheet() {
+ try{
+ HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("XRefCalcData.xls");
+ assertEquals("CostSheet!$A$2:$B$3", wb.getName("COSTS").getRefersToFormula());
+ assertEquals("x123",wb.getSheet("CostSheet").getRow(1).getCell(0).getStringCellValue());
+ assertEquals(PART_COST,wb.getSheet("CostSheet").getRow(1).getCell(1).getNumericCellValue());
+ assertEquals("MarkupSheet!$B$1", wb.getName("Markup_Cost").getRefersToFormula());
+ assertEquals(MARKUP_COST_1,wb.getSheet("MarkupSheet").getRow(0).getCell(1).getNumericCellValue());
+ }catch(Exception e){
+ fail();
+ }
+ }
+
+ public void testEvaluate() throws Exception {
+ HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("XRefCalc.xls");
+ HSSFWorkbook wb2 = HSSFTestDataSamples.openSampleWorkbook("XRefCalcData.xls");
+ CellReference cellRef = new CellReference(wb.getName("QUANT").getRefersToFormula());
+ HSSFCell cell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
+ cell.setCellValue(NEW_QUANT);
+ cell = wb2.getSheet("CostSheet").getRow(1).getCell(1);
+ cell.setCellValue(NEW_PART_COST);
+ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb);
+ HSSFFormulaEvaluator evaluatorCost = new HSSFFormulaEvaluator(wb2);
+ String[] bookNames = { "XRefCalc.xls", "XRefCalcData.xls" };
+ HSSFFormulaEvaluator[] evaluators = { evaluator, evaluatorCost, };
+ HSSFFormulaEvaluator.setupEnvironment(bookNames, evaluators);
+ cellRef = new CellReference(wb.getName("UNITCOST").getRefersToFormula());
+ HSSFCell uccell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
+ cellRef = new CellReference(wb.getName("COST").getRefersToFormula());
+ HSSFCell ccell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
+ cellRef = new CellReference(wb.getName("TOTALCOST").getRefersToFormula());
+ HSSFCell tccell = wb.getSheet(cellRef.getSheetName()).getRow(cellRef.getRow()).getCell((int)cellRef.getCol());
+ evaluator.evaluateFormulaCell(uccell);
+ evaluator.evaluateFormulaCell(ccell);
+ evaluator.evaluateFormulaCell(tccell);
+ assertEquals(NEW_PART_COST, uccell.getNumericCellValue());
+ assertEquals(NEW_PART_COST*NEW_QUANT, ccell.getNumericCellValue());
+ assertEquals(NEW_PART_COST*NEW_QUANT*MARKUP_COST_2, tccell.getNumericCellValue());
+ }
+}
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java
index b75fb441fc..d1b1a73b09 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java
@@ -215,4 +215,65 @@ public final class TestHSSFFormulaEvaluator extends TestCase {
assertEquals(3, evalCount);
assertEquals(2.0, ((NumberEval)ve).getNumberValue(), 0D);
}
+
+ /**
+ * Ensures that we can handle NameXPtgs in the formulas
+ * we parse.
+ */
+ public void testXRefs() throws Exception {
+ HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("XRefCalc.xls");
+ HSSFWorkbook wbData = HSSFTestDataSamples.openSampleWorkbook("XRefCalcData.xls");
+ Cell cell;
+
+ // VLookup on a name in another file
+ cell = wb.getSheetAt(0).getRow(1).getCell(2);
+ assertEquals(Cell.CELL_TYPE_FORMULA, cell.getCellType());
+ assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
+ assertEquals(12.30, cell.getNumericCellValue(), 0.0001);
+ // WARNING - this is wrong!
+ // The file name should be showing, but bug #45970 is fixed
+ // we seem to loose it
+ assertEquals("VLOOKUP(PART,COSTS,2,FALSE)", cell.getCellFormula());
+
+
+ // Simple reference to a name in another file
+ cell = wb.getSheetAt(0).getRow(1).getCell(4);
+ assertEquals(Cell.CELL_TYPE_FORMULA, cell.getCellType());
+ assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
+ assertEquals(36.90, cell.getNumericCellValue(), 0.0001);
+ // WARNING - this is wrong!
+ // The file name should be showing, but bug #45970 is fixed
+ // we seem to loose it
+ assertEquals("Cost*Markup_Cost", cell.getCellFormula());
+
+
+ // Evaluate the cells
+ HSSFFormulaEvaluator eval = new HSSFFormulaEvaluator(wb);
+ HSSFFormulaEvaluator.setupEnvironment(
+ new String[] { "XRefCalc.xls", "XRefCalcData.xls" },
+ new HSSFFormulaEvaluator[] {
+ eval,
+ new HSSFFormulaEvaluator(wbData)
+ }
+ );
+ eval.evaluateFormulaCell(
+ wb.getSheetAt(0).getRow(1).getCell(2)
+ );
+ eval.evaluateFormulaCell(
+ wb.getSheetAt(0).getRow(1).getCell(4)
+ );
+
+
+ // Re-check VLOOKUP one
+ cell = wb.getSheetAt(0).getRow(1).getCell(2);
+ assertEquals(Cell.CELL_TYPE_FORMULA, cell.getCellType());
+ assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
+ assertEquals(12.30, cell.getNumericCellValue(), 0.0001);
+
+ // Re-check ref one
+ cell = wb.getSheetAt(0).getRow(1).getCell(4);
+ assertEquals(Cell.CELL_TYPE_FORMULA, cell.getCellType());
+ assertEquals(Cell.CELL_TYPE_NUMERIC, cell.getCachedFormulaResultType());
+ assertEquals(36.90, cell.getNumericCellValue(), 0.0001);
+ }
}
diff --git a/test-data/spreadsheet/XRefCalc.xls b/test-data/spreadsheet/XRefCalc.xls
new file mode 100644
index 0000000000..7da6acfe1e
--- /dev/null
+++ b/test-data/spreadsheet/XRefCalc.xls
Binary files differ
diff --git a/test-data/spreadsheet/XRefCalcData.xls b/test-data/spreadsheet/XRefCalcData.xls
new file mode 100644
index 0000000000..677de9839c
--- /dev/null
+++ b/test-data/spreadsheet/XRefCalcData.xls
Binary files differ