]> source.dussan.org Git - poi.git/commitdiff
Apply, with a few tweaks, the patch from bug #48996 - initial support for External...
authorNick Burch <nick@apache.org>
Thu, 10 Jun 2010 17:07:06 +0000 (17:07 +0000)
committerNick Burch <nick@apache.org>
Thu, 10 Jun 2010 17:07:06 +0000 (17:07 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@953395 13f79535-47bb-0310-9956-ffa450edef68

16 files changed:
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/dev/BiffViewer.java
src/java/org/apache/poi/hssf/model/InternalWorkbook.java
src/java/org/apache/poi/hssf/model/LinkTable.java
src/java/org/apache/poi/hssf/record/ExternalNameRecord.java
src/java/org/apache/poi/hssf/record/formula/NameXPtg.java
src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java
src/testcases/org/apache/poi/hssf/record/formula/TestExternalNameReference.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java
test-data/spreadsheet/XRefCalc.xls [new file with mode: 0644]
test-data/spreadsheet/XRefCalcData.xls [new file with mode: 0644]

index 50e37663d6b9e92a7106b287719fc591f985838f..e0cdba7af756d01305ccff0f46bc3a8397ec2ded 100644 (file)
@@ -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>
index aed5c199e43d7a50f9fcd80e94213ae3eba3faa7..ba79aa80d234bfd42c21ce02a953853847a0ccee 100644 (file)
@@ -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);
index b1340f524b40a7cf7ca0f35bd8a786d7fc5807bc..567b986e7011c838020d8e69a56e2c64cb02f360 100644 (file)
@@ -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.
index 73b7d02da0a383fbbaef1f55d1169ad8f0ea2394..10a6b3063b2f930d8c3953582b04d2bb14c02a7d 100644 (file)
@@ -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:
index 6619da8c78ccd3f5c5db55435da86e0609dab746..0156ca067867096f76d56faa58ca0bfaf0402428 100644 (file)
@@ -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();
        }
 }
index de08763c7341a05972a0a5582073bc6d08ed2965..5b4176f485d1060b6ba6b6475ad7108959e514f0 100644 (file)
@@ -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;
        }
index 1f10a926ad12cfb8c6b07725601dc0e1fec7d1d0..2ac66d64e3a534f33ea62111ccc101f5c81bb016 100644 (file)
@@ -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());
index a3b232571945a15d7fe7d64e8fad37ecdd1d77c4..1f42aa8930c493e39270ccce482ffbabdf7c6f54 100644 (file)
@@ -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;
+               }
+       }
 }
index 147e07d7a543cb38360db01684212b508020cca3..71db36e0c65c19c8a0f76a75319f23dd8dd8fdae 100644 (file)
 
 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;
+      }
+   }
 }
index ad15b84e9c7b148f14fca999500020e1df7a20db..60d31a707d2ef9f72c642f81eaa0fc6c6ce40718 100644 (file)
@@ -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) {
index 08ed7f534606b1037dc8cf8de272a5d19a413721..c916006764c70ad851c9773e9a43c744b2baaba5 100644 (file)
@@ -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) {
index c3467fc7ed7e0af3a08aebc0113fb20a75a614f0..b2c71fee237a2e9cd5780f797a47f704fa4901a9 100644 (file)
@@ -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 (file)
index 0000000..6d2b871
--- /dev/null
@@ -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());
+       }
+}
index b75fb441fc99e32bb6e1ce4e6065b0103202e63f..d1b1a73b09637bfef78f2a38771b24623741136c 100644 (file)
@@ -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 (file)
index 0000000..7da6acf
Binary files /dev/null and b/test-data/spreadsheet/XRefCalc.xls differ
diff --git a/test-data/spreadsheet/XRefCalcData.xls b/test-data/spreadsheet/XRefCalcData.xls
new file mode 100644 (file)
index 0000000..677de98
Binary files /dev/null and b/test-data/spreadsheet/XRefCalcData.xls differ