From 3d9e7d5bf5149a1f6dc969839e15f6b60fabe70d Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Sat, 29 Mar 2008 22:03:18 +0000 Subject: [PATCH] Shuffle the FormulaParser stuff about, and get it all working with the new interfaces, and not just with the hard coded HSSF classes git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@642624 13f79535-47bb-0310-9956-ffa450edef68 --- .../record/formula/eval/ExternalFunction.java | 8 +- .../formula/functions/FreeRefFunction.java | 6 +- .../record/formula/functions/Indirect.java | 6 +- .../hssf/record/formula/functions/Offset.java | 8 +- .../hssf/usermodel/HSSFFormulaEvaluator.java | 732 +---------------- .../poi/hssf/usermodel/HSSFWorkbook.java | 6 +- .../usermodel/EvaluationCycleDetector.java | 15 +- .../EvaluationCycleDetectorManager.java | 2 +- .../poi/ss/usermodel/FormulaEvaluator.java | 759 ++++++++++++++++++ .../usermodel/OperationEvaluatorFactory.java | 2 +- .../org/apache/poi/ss/usermodel/Workbook.java | 8 + .../poi/xssf/usermodel/XSSFWorkbook.java | 11 +- .../poi/hssf/model/TestFormulaParserEval.java | 2 +- .../formula/eval/TestCircularReferences.java | 2 +- .../formula/eval/TestExternalFunction.java | 2 +- .../record/formula/eval/TestFormulaBugs.java | 2 +- .../eval/TestFormulasFromSpreadsheet.java | 6 +- .../record/formula/eval/TestPercentEval.java | 2 +- .../record/formula/functions/TestIsBlank.java | 2 +- .../TestLookupFunctionsFromSpreadsheet.java | 4 +- .../poi/hssf/usermodel/TestBug42464.java | 2 +- 21 files changed, 839 insertions(+), 748 deletions(-) rename src/java/org/apache/poi/{hssf => ss}/usermodel/EvaluationCycleDetector.java (91%) rename src/java/org/apache/poi/{hssf => ss}/usermodel/EvaluationCycleDetectorManager.java (97%) create mode 100644 src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java rename src/java/org/apache/poi/{hssf => ss}/usermodel/OperationEvaluatorFactory.java (99%) diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java b/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java index b1d81e652..f40c83202 100755 --- a/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java +++ b/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java @@ -18,8 +18,8 @@ package org.apache.poi.hssf.record.formula.eval; import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; /** * * Common entry point for all external functions (where @@ -29,7 +29,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook; */ final class ExternalFunction implements FreeRefFunction { - public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, HSSFWorkbook workbook, HSSFSheet sheet) { + public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, Sheet sheet) { int nIncomingArgs = args.length; if(nIncomingArgs < 1) { @@ -56,7 +56,7 @@ final class ExternalFunction implements FreeRefFunction { return targetFunc.evaluate(outGoingArgs, srcCellRow, srcCellCol, workbook, sheet); } - private FreeRefFunction findTargetFunction(HSSFWorkbook workbook, NameEval functionNameEval) throws EvaluationException { + private FreeRefFunction findTargetFunction(Workbook workbook, NameEval functionNameEval) throws EvaluationException { int numberOfNames = workbook.getNumberOfNames(); diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java index 56d285543..2163d8f5e 100755 --- a/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java @@ -19,8 +19,8 @@ package org.apache.poi.hssf.record.formula.functions; import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; /** @@ -53,5 +53,5 @@ public interface FreeRefFunction { * a specified Excel error (Exceptions are never thrown to represent Excel errors). * */ - ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, HSSFWorkbook workbook, HSSFSheet sheet); + ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, Sheet sheet); } diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Indirect.java b/src/java/org/apache/poi/hssf/record/formula/functions/Indirect.java index 935e7cdbb..8d7d4463e 100644 --- a/src/java/org/apache/poi/hssf/record/formula/functions/Indirect.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/Indirect.java @@ -20,8 +20,8 @@ package org.apache.poi.hssf.record.formula.functions; import org.apache.poi.hssf.record.formula.eval.ErrorEval; import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.ValueEval; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; /** * Implementation for Excel function INDIRECT

@@ -41,7 +41,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook; */ public final class Indirect implements FreeRefFunction { - public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, HSSFWorkbook workbook, HSSFSheet sheet) { + public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, Sheet sheet) { // TODO - implement INDIRECT() return ErrorEval.FUNCTION_NOT_IMPLEMENTED; } diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Offset.java b/src/java/org/apache/poi/hssf/record/formula/functions/Offset.java index 9497a5f21..8a10e6225 100644 --- a/src/java/org/apache/poi/hssf/record/formula/functions/Offset.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/Offset.java @@ -31,8 +31,8 @@ import org.apache.poi.hssf.record.formula.eval.RefEval; import org.apache.poi.hssf.record.formula.eval.StringEval; import org.apache.poi.hssf.record.formula.eval.ValueEval; import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; /** * Implementation for Excel function OFFSET()

* @@ -201,7 +201,7 @@ public final class Offset implements FreeRefFunction { } - public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, HSSFWorkbook workbook, HSSFSheet sheet) { + public ValueEval evaluate(Eval[] args, int srcCellRow, short srcCellCol, Workbook workbook, Sheet sheet) { if(args.length < 3 || args.length > 5) { return ErrorEval.VALUE_INVALID; @@ -235,7 +235,7 @@ public final class Offset implements FreeRefFunction { private static AreaEval createOffset(BaseRef baseRef, LinearOffsetRange rowOffsetRange, LinearOffsetRange colOffsetRange, - HSSFWorkbook workbook, HSSFSheet sheet) throws EvalEx { + Workbook workbook, Sheet sheet) throws EvalEx { LinearOffsetRange rows = rowOffsetRange.normaliseAndTranslate(baseRef.getFirstRowIndex()); LinearOffsetRange cols = colOffsetRange.normaliseAndTranslate(baseRef.getFirstColumnIndex()); diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java index bb16fdfad..3da5f9688 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java @@ -17,96 +17,25 @@ package org.apache.poi.hssf.usermodel; -import java.lang.reflect.Constructor; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Stack; - import org.apache.poi.hssf.model.FormulaParser; -import org.apache.poi.hssf.model.Workbook; -import org.apache.poi.hssf.record.formula.Area3DPtg; -import org.apache.poi.hssf.record.formula.AreaPtg; -import org.apache.poi.hssf.record.formula.AttrPtg; -import org.apache.poi.hssf.record.formula.BoolPtg; -import org.apache.poi.hssf.record.formula.ControlPtg; -import org.apache.poi.hssf.record.formula.IntPtg; -import org.apache.poi.hssf.record.formula.MemErrPtg; -import org.apache.poi.hssf.record.formula.MissingArgPtg; -import org.apache.poi.hssf.record.formula.NamePtg; -import org.apache.poi.hssf.record.formula.NameXPtg; -import org.apache.poi.hssf.record.formula.NumberPtg; import org.apache.poi.hssf.record.formula.OperationPtg; -import org.apache.poi.hssf.record.formula.ParenthesisPtg; import org.apache.poi.hssf.record.formula.Ptg; -import org.apache.poi.hssf.record.formula.Ref3DPtg; -import org.apache.poi.hssf.record.formula.ReferencePtg; -import org.apache.poi.hssf.record.formula.StringPtg; -import org.apache.poi.hssf.record.formula.UnionPtg; -import org.apache.poi.hssf.record.formula.UnknownPtg; -import org.apache.poi.hssf.record.formula.eval.Area2DEval; -import org.apache.poi.hssf.record.formula.eval.Area3DEval; -import org.apache.poi.hssf.record.formula.eval.AreaEval; -import org.apache.poi.hssf.record.formula.eval.BlankEval; -import org.apache.poi.hssf.record.formula.eval.BoolEval; -import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.hssf.record.formula.eval.Eval; -import org.apache.poi.hssf.record.formula.eval.FunctionEval; -import org.apache.poi.hssf.record.formula.eval.NameEval; -import org.apache.poi.hssf.record.formula.eval.NumberEval; -import org.apache.poi.hssf.record.formula.eval.OperationEval; -import org.apache.poi.hssf.record.formula.eval.Ref2DEval; -import org.apache.poi.hssf.record.formula.eval.Ref3DEval; -import org.apache.poi.hssf.record.formula.eval.RefEval; -import org.apache.poi.hssf.record.formula.eval.StringEval; -import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CreationHelper; +import org.apache.poi.ss.usermodel.FormulaEvaluator; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue; /** * @author Amol S. Deshmukh < amolweb at ya hoo dot com > * */ -public class HSSFFormulaEvaluator { - - // params to lookup the right constructor using reflection - private static final Class[] VALUE_CONTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class }; - - private static final Class[] AREA3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval[].class }; - - private static final Class[] REFERENCE_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval.class }; - - private static final Class[] REF3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval.class }; - - // Maps for mapping *Eval to *Ptg - private static final Map VALUE_EVALS_MAP = new HashMap(); - - /* - * Following is the mapping between the Ptg tokens returned - * by the FormulaParser and the *Eval classes that are used - * by the FormulaEvaluator - */ - static { - VALUE_EVALS_MAP.put(BoolPtg.class, BoolEval.class); - VALUE_EVALS_MAP.put(IntPtg.class, NumberEval.class); - VALUE_EVALS_MAP.put(NumberPtg.class, NumberEval.class); - VALUE_EVALS_MAP.put(StringPtg.class, StringEval.class); - - } - - - protected HSSFRow row; - protected HSSFSheet sheet; - protected HSSFWorkbook workbook; - +public class HSSFFormulaEvaluator extends FormulaEvaluator { public HSSFFormulaEvaluator(HSSFSheet sheet, HSSFWorkbook workbook) { - this.sheet = sheet; - this.workbook = workbook; - } - - public void setCurrentRow(HSSFRow row) { - this.row = row; + super(sheet, workbook); } - /** * Returns an underlying FormulaParser, for the specified * Formula String and HSSFWorkbook. @@ -118,639 +47,6 @@ public class HSSFFormulaEvaluator { return new FormulaParser(formula, workbook.getWorkbook()); } - /** - * If cell contains a formula, the formula is evaluated and returned, - * else the CellValue simply copies the appropriate cell value from - * the cell and also its cell type. This method should be preferred over - * evaluateInCell() when the call should not modify the contents of the - * original cell. - * @param cell - */ - public CellValue evaluate(HSSFCell cell) { - CellValue retval = null; - if (cell != null) { - switch (cell.getCellType()) { - case HSSFCell.CELL_TYPE_BLANK: - retval = new CellValue(HSSFCell.CELL_TYPE_BLANK); - break; - case HSSFCell.CELL_TYPE_BOOLEAN: - retval = new CellValue(HSSFCell.CELL_TYPE_BOOLEAN); - retval.setBooleanValue(cell.getBooleanCellValue()); - break; - case HSSFCell.CELL_TYPE_ERROR: - retval = new CellValue(HSSFCell.CELL_TYPE_ERROR); - retval.setErrorValue(cell.getErrorCellValue()); - break; - case HSSFCell.CELL_TYPE_FORMULA: - retval = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook)); - break; - case HSSFCell.CELL_TYPE_NUMERIC: - retval = new CellValue(HSSFCell.CELL_TYPE_NUMERIC); - retval.setNumberValue(cell.getNumericCellValue()); - break; - case HSSFCell.CELL_TYPE_STRING: - retval = new CellValue(HSSFCell.CELL_TYPE_STRING); - retval.setRichTextStringValue(cell.getRichStringCellValue()); - break; - } - } - return retval; - } - - - /** - * If cell contains formula, it evaluates the formula, - * and saves the result of the formula. The cell - * remains as a formula cell. - * Else if cell does not contain formula, this method leaves - * the cell unchanged. - * Note that the type of the formula result is returned, - * so you know what kind of value is also stored with - * the formula. - *

-     * int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
-     * 
- * Be aware that your cell will hold both the formula, - * and the result. If you want the cell replaced with - * the result of the formula, use {@link #evaluateInCell(HSSFCell)} - * @param cell The cell to evaluate - * @return The type of the formula result (the cell's type remains as HSSFCell.CELL_TYPE_FORMULA however) - */ - public int evaluateFormulaCell(HSSFCell cell) { - if (cell != null) { - switch (cell.getCellType()) { - case HSSFCell.CELL_TYPE_FORMULA: - CellValue cv = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook)); - switch (cv.getCellType()) { - case HSSFCell.CELL_TYPE_BOOLEAN: - cell.setCellValue(cv.getBooleanValue()); - break; - case HSSFCell.CELL_TYPE_ERROR: - cell.setCellValue(cv.getErrorValue()); - break; - case HSSFCell.CELL_TYPE_NUMERIC: - cell.setCellValue(cv.getNumberValue()); - break; - case HSSFCell.CELL_TYPE_STRING: - cell.setCellValue(cv.getRichTextStringValue()); - break; - case HSSFCell.CELL_TYPE_BLANK: - break; - case HSSFCell.CELL_TYPE_FORMULA: // this will never happen, we have already evaluated the formula - break; - } - return cv.getCellType(); - } - } - return -1; - } - - /** - * If cell contains formula, it evaluates the formula, and - * puts the formula result back into the cell, in place - * of the old formula. - * Else if cell does not contain formula, this method leaves - * the cell unchanged. - * Note that the same instance of HSSFCell is returned to - * allow chained calls like: - *
-     * int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
-     * 
- * Be aware that your cell value will be changed to hold the - * result of the formula. If you simply want the formula - * value computed for you, use {@link #evaluateFormulaCell(HSSFCell)} - * @param cell - */ - public HSSFCell evaluateInCell(HSSFCell cell) { - if (cell != null) { - switch (cell.getCellType()) { - case HSSFCell.CELL_TYPE_FORMULA: - CellValue cv = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook)); - switch (cv.getCellType()) { - case HSSFCell.CELL_TYPE_BOOLEAN: - cell.setCellType(HSSFCell.CELL_TYPE_BOOLEAN); - cell.setCellValue(cv.getBooleanValue()); - break; - case HSSFCell.CELL_TYPE_ERROR: - cell.setCellType(HSSFCell.CELL_TYPE_ERROR); - cell.setCellValue(cv.getErrorValue()); - break; - case HSSFCell.CELL_TYPE_NUMERIC: - cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC); - cell.setCellValue(cv.getNumberValue()); - break; - case HSSFCell.CELL_TYPE_STRING: - cell.setCellType(HSSFCell.CELL_TYPE_STRING); - cell.setCellValue(cv.getRichTextStringValue()); - break; - case HSSFCell.CELL_TYPE_BLANK: - break; - case HSSFCell.CELL_TYPE_FORMULA: // this will never happen, we have already evaluated the formula - break; - } - } - } - return cell; - } - - /** - * Loops over all cells in all sheets of the supplied - * workbook. - * For cells that contain formulas, their formulas are - * evaluated, and the results are saved. These cells - * remain as formula cells. - * For cells that do not contain formulas, no changes - * are made. - * This is a helpful wrapper around looping over all - * cells, and calling evaluateFormulaCell on each one. - */ - public static void evaluateAllFormulaCells(HSSFWorkbook wb) { - for(int i=0; i= 0; j--) { - Eval p = (Eval) stack.pop(); - ops[j] = p; - } - Eval opresult = invokeOperation(operation, ops, srcRowNum, srcColNum, workbook, sheet); - stack.push(opresult); - } - else if (ptg instanceof ReferencePtg) { - ReferencePtg refPtg = (ReferencePtg) ptg; - int colIx = refPtg.getColumn(); - int rowIx = refPtg.getRow(); - HSSFRow row = sheet.getRow(rowIx); - HSSFCell cell = (row != null) ? row.getCell(colIx) : null; - stack.push(createRef2DEval(refPtg, cell, row, sheet, workbook)); - } - else if (ptg instanceof Ref3DPtg) { - Ref3DPtg refPtg = (Ref3DPtg) ptg; - int colIx = refPtg.getColumn(); - int rowIx = refPtg.getRow(); - Workbook wb = workbook.getWorkbook(); - HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex())); - HSSFRow row = xsheet.getRow(rowIx); - HSSFCell cell = (row != null) ? row.getCell(colIx) : null; - stack.push(createRef3DEval(refPtg, cell, row, xsheet, workbook)); - } - else if (ptg instanceof AreaPtg) { - AreaPtg ap = (AreaPtg) ptg; - AreaEval ae = evaluateAreaPtg(sheet, workbook, ap); - stack.push(ae); - } - else if (ptg instanceof Area3DPtg) { - Area3DPtg a3dp = (Area3DPtg) ptg; - AreaEval ae = evaluateArea3dPtg(workbook, a3dp); - stack.push(ae); - } - else { - Eval ptgEval = getEvalForPtg(ptg); - stack.push(ptgEval); - } - } - - ValueEval value = ((ValueEval) stack.pop()); - if (!stack.isEmpty()) { - throw new IllegalStateException("evaluation stack not empty"); - } - value = dereferenceValue(value, srcRowNum, srcColNum); - if (value instanceof BlankEval) { - // Note Excel behaviour here. A blank final final value is converted to zero. - return NumberEval.ZERO; - // Formulas _never_ evaluate to blank. If a formula appears to have evaluated to - // blank, the actual value is empty string. This can be verified with ISBLANK(). - } - return value; - } - - /** - * Dereferences a single value from any AreaEval or RefEval evaluation result. - * If the supplied evaluationResult is just a plain value, it is returned as-is. - * @return a NumberEval, StringEval, BoolEval, - * BlankEval or ErrorEval. Never null. - */ - private static ValueEval dereferenceValue(ValueEval evaluationResult, int srcRowNum, short srcColNum) { - if (evaluationResult instanceof RefEval) { - RefEval rv = (RefEval) evaluationResult; - return rv.getInnerValueEval(); - } - if (evaluationResult instanceof AreaEval) { - AreaEval ae = (AreaEval) evaluationResult; - if (ae.isRow()) { - if(ae.isColumn()) { - return ae.getValues()[0]; - } - return ae.getValueAt(ae.getFirstRow(), srcColNum); - } - if (ae.isColumn()) { - return ae.getValueAt(srcRowNum, ae.getFirstColumn()); - } - return ErrorEval.VALUE_INVALID; - } - return evaluationResult; - } - - private static Eval invokeOperation(OperationEval operation, Eval[] ops, int srcRowNum, short srcColNum, - HSSFWorkbook workbook, HSSFSheet sheet) { - - if(operation instanceof FunctionEval) { - FunctionEval fe = (FunctionEval) operation; - if(fe.isFreeRefFunction()) { - return fe.getFreeRefFunction().evaluate(ops, srcRowNum, srcColNum, workbook, sheet); - } - } - return operation.evaluate(ops, srcRowNum, srcColNum); - } - - public static AreaEval evaluateAreaPtg(HSSFSheet sheet, HSSFWorkbook workbook, AreaPtg ap) { - int row0 = ap.getFirstRow(); - int col0 = ap.getFirstColumn(); - int row1 = ap.getLastRow(); - int col1 = ap.getLastColumn(); - - // If the last row is -1, then the - // reference is for the rest of the column - // (eg C:C) - // TODO: Handle whole column ranges properly - if(row1 == -1 && row0 >= 0) { - row1 = (short)sheet.getLastRowNum(); - } - ValueEval[] values = evalArea(workbook, sheet, row0, col0, row1, col1); - return new Area2DEval(ap, values); - } - - public static AreaEval evaluateArea3dPtg(HSSFWorkbook workbook, Area3DPtg a3dp) { - int row0 = a3dp.getFirstRow(); - int col0 = a3dp.getFirstColumn(); - int row1 = a3dp.getLastRow(); - int col1 = a3dp.getLastColumn(); - Workbook wb = workbook.getWorkbook(); - HSSFSheet xsheet = workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex())); - - // If the last row is -1, then the - // reference is for the rest of the column - // (eg C:C) - // TODO: Handle whole column ranges properly - if(row1 == -1 && row0 >= 0) { - row1 = (short)xsheet.getLastRowNum(); - } - - ValueEval[] values = evalArea(workbook, xsheet, row0, col0, row1, col1); - return new Area3DEval(a3dp, values); - } - - private static ValueEval[] evalArea(HSSFWorkbook workbook, HSSFSheet sheet, - int row0, int col0, int row1, int col1) { - ValueEval[] values = new ValueEval[(row1 - row0 + 1) * (col1 - col0 + 1)]; - for (int x = row0; sheet != null && x < row1 + 1; x++) { - HSSFRow row = sheet.getRow(x); - for (int y = col0; y < col1 + 1; y++) { - ValueEval cellEval; - if(row == null) { - cellEval = BlankEval.INSTANCE; - } else { - cellEval = getEvalForCell(row.getCell(y), row, sheet, workbook); - } - values[(x - row0) * (col1 - col0 + 1) + (y - col0)] = cellEval; - } - } - return values; - } - - /** - * returns an appropriate Eval impl instance for the Ptg. The Ptg must be - * one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg, - * StringPtg, BoolPtg
special Note: OperationPtg subtypes cannot be - * passed here! - * - * @param ptg - */ - protected static Eval getEvalForPtg(Ptg ptg) { - Eval retval = null; - - Class clazz = (Class) VALUE_EVALS_MAP.get(ptg.getClass()); - try { - if (ptg instanceof Area3DPtg) { - Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY); - retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg }); - } - else if (ptg instanceof AreaPtg) { - Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY); - retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg }); - } - else if (ptg instanceof ReferencePtg) { - Constructor constructor = clazz.getConstructor(REFERENCE_CONSTRUCTOR_CLASS_ARRAY); - retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg }); - } - else if (ptg instanceof Ref3DPtg) { - Constructor constructor = clazz.getConstructor(REF3D_CONSTRUCTOR_CLASS_ARRAY); - retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg }); - } - else { - if (ptg instanceof IntPtg || ptg instanceof NumberPtg || ptg instanceof StringPtg - || ptg instanceof BoolPtg) { - Constructor constructor = clazz.getConstructor(VALUE_CONTRUCTOR_CLASS_ARRAY); - retval = (ValueEval) constructor.newInstance(new Ptg[] { ptg }); - } - } - } - catch (Exception e) { - throw new RuntimeException("Fatal Error: ", e); - } - return retval; - - } - - /** - * Given a cell, find its type and from that create an appropriate ValueEval - * impl instance and return that. Since the cell could be an external - * reference, we need the sheet that this belongs to. - * Non existent cells are treated as empty. - * @param cell - * @param sheet - * @param workbook - */ - protected static ValueEval getEvalForCell(HSSFCell cell, HSSFRow row, HSSFSheet sheet, HSSFWorkbook workbook) { - - if (cell == null) { - return BlankEval.INSTANCE; - } - switch (cell.getCellType()) { - case HSSFCell.CELL_TYPE_NUMERIC: - return new NumberEval(cell.getNumericCellValue()); - case HSSFCell.CELL_TYPE_STRING: - return new StringEval(cell.getRichStringCellValue().getString()); - case HSSFCell.CELL_TYPE_FORMULA: - return internalEvaluate(cell, row, sheet, workbook); - case HSSFCell.CELL_TYPE_BOOLEAN: - return BoolEval.valueOf(cell.getBooleanCellValue()); - case HSSFCell.CELL_TYPE_BLANK: - return BlankEval.INSTANCE; - case HSSFCell.CELL_TYPE_ERROR: - return ErrorEval.valueOf(cell.getErrorCellValue()); - } - throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")"); - } - - /** - * Creates a Ref2DEval for ReferencePtg. - * Non existent cells are treated as RefEvals containing BlankEval. - */ - private static Ref2DEval createRef2DEval(ReferencePtg ptg, HSSFCell cell, - HSSFRow row, HSSFSheet sheet, HSSFWorkbook workbook) { - if (cell == null) { - return new Ref2DEval(ptg, BlankEval.INSTANCE); - } - - switch (cell.getCellType()) { - case HSSFCell.CELL_TYPE_NUMERIC: - return new Ref2DEval(ptg, new NumberEval(cell.getNumericCellValue())); - case HSSFCell.CELL_TYPE_STRING: - return new Ref2DEval(ptg, new StringEval(cell.getRichStringCellValue().getString())); - case HSSFCell.CELL_TYPE_FORMULA: - return new Ref2DEval(ptg, internalEvaluate(cell, row, sheet, workbook)); - case HSSFCell.CELL_TYPE_BOOLEAN: - return new Ref2DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue())); - case HSSFCell.CELL_TYPE_BLANK: - return new Ref2DEval(ptg, BlankEval.INSTANCE); - case HSSFCell.CELL_TYPE_ERROR: - return new Ref2DEval(ptg, ErrorEval.valueOf(cell.getErrorCellValue())); - } - throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")"); - } - - /** - * create a Ref3DEval for Ref3DPtg. - */ - private static Ref3DEval createRef3DEval(Ref3DPtg ptg, HSSFCell cell, - HSSFRow row, HSSFSheet sheet, HSSFWorkbook workbook) { - if (cell == null) { - return new Ref3DEval(ptg, BlankEval.INSTANCE); - } - switch (cell.getCellType()) { - case HSSFCell.CELL_TYPE_NUMERIC: - return new Ref3DEval(ptg, new NumberEval(cell.getNumericCellValue())); - case HSSFCell.CELL_TYPE_STRING: - return new Ref3DEval(ptg, new StringEval(cell.getRichStringCellValue().getString())); - case HSSFCell.CELL_TYPE_FORMULA: - return new Ref3DEval(ptg, internalEvaluate(cell, row, sheet, workbook)); - case HSSFCell.CELL_TYPE_BOOLEAN: - return new Ref3DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue())); - case HSSFCell.CELL_TYPE_BLANK: - return new Ref3DEval(ptg, BlankEval.INSTANCE); - case HSSFCell.CELL_TYPE_ERROR: - return new Ref3DEval(ptg, ErrorEval.valueOf(cell.getErrorCellValue())); - } - throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")"); - } - - /** - * Mimics the 'data view' of a cell. This allows formula evaluator - * to return a CellValue instead of precasting the value to String - * or Number or boolean type. - * @author Amol S. Deshmukh < amolweb at ya hoo dot com > - */ - public static final class CellValue { - private int cellType; - private HSSFRichTextString richTextStringValue; - private double numberValue; - private boolean booleanValue; - private byte errorValue; - - /** - * CellType should be one of the types defined in HSSFCell - * @param cellType - */ - public CellValue(int cellType) { - super(); - this.cellType = cellType; - } - /** - * @return Returns the booleanValue. - */ - public boolean getBooleanValue() { - return booleanValue; - } - /** - * @param booleanValue The booleanValue to set. - */ - public void setBooleanValue(boolean booleanValue) { - this.booleanValue = booleanValue; - } - /** - * @return Returns the numberValue. - */ - public double getNumberValue() { - return numberValue; - } - /** - * @param numberValue The numberValue to set. - */ - public void setNumberValue(double numberValue) { - this.numberValue = numberValue; - } - /** - * @return Returns the stringValue. This method is deprecated, use - * getRichTextStringValue instead - * @deprecated - */ - public String getStringValue() { - return richTextStringValue.getString(); - } - /** - * @param stringValue The stringValue to set. This method is deprecated, use - * getRichTextStringValue instead. - * @deprecated - */ - public void setStringValue(String stringValue) { - this.richTextStringValue = new HSSFRichTextString(stringValue); - } - /** - * @return Returns the cellType. - */ - public int getCellType() { - return cellType; - } - /** - * @return Returns the errorValue. - */ - public byte getErrorValue() { - return errorValue; - } - /** - * @param errorValue The errorValue to set. - */ - public void setErrorValue(byte errorValue) { - this.errorValue = errorValue; - } - /** - * @return Returns the richTextStringValue. - */ - public HSSFRichTextString getRichTextStringValue() { - return richTextStringValue; - } - /** - * @param richTextStringValue The richTextStringValue to set. - */ - public void setRichTextStringValue(HSSFRichTextString richTextStringValue) { - this.richTextStringValue = richTextStringValue; - } - } /** * debug method @@ -760,7 +56,8 @@ public class HSSFFormulaEvaluator { * @param workbook */ void inspectPtgs(String formula) { - FormulaParser fp = new FormulaParser(formula, workbook.getWorkbook()); + HSSFWorkbook hssfWb = (HSSFWorkbook)workbook; + FormulaParser fp = new FormulaParser(formula, hssfWb.getWorkbook()); fp.parse(); Ptg[] ptgs = fp.getRPNPtg(); System.out.println(""); @@ -775,4 +72,13 @@ public class HSSFFormulaEvaluator { System.out.println(""); } + /** + * Compatibility class. + * Seems to do more harm than good though + */ +// public static class CellValue extends FormulaEvaluator.CellValue { +// public CellValue(int cellType, CreationHelper creationHelper) { +// super(cellType, creationHelper); +// } +// } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java index e70b77136..51499a99e 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java @@ -610,7 +610,11 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm return sheets.size(); } - /** + public int getSheetIndexFromExternSheetIndex(int externSheetNumber) { + return workbook.getSheetIndexFromExternSheetIndex(externSheetNumber); + } + + /** * Get the HSSFSheet object at the given index. * @param index of the sheet number (0-based physical & logical) * @return HSSFSheet at the provided index diff --git a/src/java/org/apache/poi/hssf/usermodel/EvaluationCycleDetector.java b/src/java/org/apache/poi/ss/usermodel/EvaluationCycleDetector.java similarity index 91% rename from src/java/org/apache/poi/hssf/usermodel/EvaluationCycleDetector.java rename to src/java/org/apache/poi/ss/usermodel/EvaluationCycleDetector.java index 90f5807ff..9cf3aa982 100755 --- a/src/java/org/apache/poi/hssf/usermodel/EvaluationCycleDetector.java +++ b/src/java/org/apache/poi/ss/usermodel/EvaluationCycleDetector.java @@ -15,11 +15,14 @@ limitations under the License. ==================================================================== */ -package org.apache.poi.hssf.usermodel; +package org.apache.poi.ss.usermodel; import java.util.ArrayList; import java.util.List; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; + /** * Instances of this class keep track of multiple dependent cell evaluations due * to recursive calls to HSSFFormulaEvaluator.internalEvaluate(). @@ -36,12 +39,12 @@ final class EvaluationCycleDetector { */ private static final class CellEvaluationFrame { - private final HSSFWorkbook _workbook; - private final HSSFSheet _sheet; + private final Workbook _workbook; + private final Sheet _sheet; private final int _srcRowNum; private final int _srcColNum; - public CellEvaluationFrame(HSSFWorkbook workbook, HSSFSheet sheet, int srcRowNum, int srcColNum) { + public CellEvaluationFrame(Workbook workbook, Sheet sheet, int srcRowNum, int srcColNum) { if (workbook == null) { throw new IllegalArgumentException("workbook must not be null"); } @@ -108,7 +111,7 @@ final class EvaluationCycleDetector { * @return true if the specified cell has not been visited yet in the current * evaluation. false if the specified cell is already being evaluated. */ - public boolean startEvaluate(HSSFWorkbook workbook, HSSFSheet sheet, int srcRowNum, int srcColNum) { + public boolean startEvaluate(Workbook workbook, Sheet sheet, int srcRowNum, int srcColNum) { CellEvaluationFrame cef = new CellEvaluationFrame(workbook, sheet, srcRowNum, srcColNum); if (_evaluationFrames.contains(cef)) { return false; @@ -129,7 +132,7 @@ final class EvaluationCycleDetector { * required. However, they have been included to assert correct behaviour, * and form more meaningful error messages. */ - public void endEvaluate(HSSFWorkbook workbook, HSSFSheet sheet, int srcRowNum, int srcColNum) { + public void endEvaluate(Workbook workbook, Sheet sheet, int srcRowNum, int srcColNum) { int nFrames = _evaluationFrames.size(); if (nFrames < 1) { throw new IllegalStateException("Call to endEvaluate without matching call to startEvaluate"); diff --git a/src/java/org/apache/poi/hssf/usermodel/EvaluationCycleDetectorManager.java b/src/java/org/apache/poi/ss/usermodel/EvaluationCycleDetectorManager.java similarity index 97% rename from src/java/org/apache/poi/hssf/usermodel/EvaluationCycleDetectorManager.java rename to src/java/org/apache/poi/ss/usermodel/EvaluationCycleDetectorManager.java index a06cd201e..d83d18700 100755 --- a/src/java/org/apache/poi/hssf/usermodel/EvaluationCycleDetectorManager.java +++ b/src/java/org/apache/poi/ss/usermodel/EvaluationCycleDetectorManager.java @@ -15,7 +15,7 @@ limitations under the License. ==================================================================== */ -package org.apache.poi.hssf.usermodel; +package org.apache.poi.ss.usermodel; /** * This class makes an EvaluationCycleDetector instance available to diff --git a/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java b/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java new file mode 100644 index 000000000..80287f5ec --- /dev/null +++ b/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java @@ -0,0 +1,759 @@ +/* +* 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.usermodel; + +import java.lang.reflect.Constructor; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Stack; + +import org.apache.poi.hssf.model.FormulaParser; +import org.apache.poi.hssf.record.formula.Area3DPtg; +import org.apache.poi.hssf.record.formula.AreaPtg; +import org.apache.poi.hssf.record.formula.AttrPtg; +import org.apache.poi.hssf.record.formula.BoolPtg; +import org.apache.poi.hssf.record.formula.ControlPtg; +import org.apache.poi.hssf.record.formula.IntPtg; +import org.apache.poi.hssf.record.formula.MemErrPtg; +import org.apache.poi.hssf.record.formula.MissingArgPtg; +import org.apache.poi.hssf.record.formula.NamePtg; +import org.apache.poi.hssf.record.formula.NameXPtg; +import org.apache.poi.hssf.record.formula.NumberPtg; +import org.apache.poi.hssf.record.formula.OperationPtg; +import org.apache.poi.hssf.record.formula.ParenthesisPtg; +import org.apache.poi.hssf.record.formula.Ptg; +import org.apache.poi.hssf.record.formula.Ref3DPtg; +import org.apache.poi.hssf.record.formula.ReferencePtg; +import org.apache.poi.hssf.record.formula.StringPtg; +import org.apache.poi.hssf.record.formula.UnionPtg; +import org.apache.poi.hssf.record.formula.UnknownPtg; +import org.apache.poi.hssf.record.formula.eval.Area2DEval; +import org.apache.poi.hssf.record.formula.eval.Area3DEval; +import org.apache.poi.hssf.record.formula.eval.AreaEval; +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.BoolEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.FunctionEval; +import org.apache.poi.hssf.record.formula.eval.NameEval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.OperationEval; +import org.apache.poi.hssf.record.formula.eval.Ref2DEval; +import org.apache.poi.hssf.record.formula.eval.Ref3DEval; +import org.apache.poi.hssf.record.formula.eval.RefEval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; + +/** + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + * + */ +public class FormulaEvaluator { + + // params to lookup the right constructor using reflection + private static final Class[] VALUE_CONTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class }; + + private static final Class[] AREA3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval[].class }; + + private static final Class[] REFERENCE_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval.class }; + + private static final Class[] REF3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval.class }; + + // Maps for mapping *Eval to *Ptg + private static final Map VALUE_EVALS_MAP = new HashMap(); + + /* + * Following is the mapping between the Ptg tokens returned + * by the FormulaParser and the *Eval classes that are used + * by the FormulaEvaluator + */ + static { + VALUE_EVALS_MAP.put(BoolPtg.class, BoolEval.class); + VALUE_EVALS_MAP.put(IntPtg.class, NumberEval.class); + VALUE_EVALS_MAP.put(NumberPtg.class, NumberEval.class); + VALUE_EVALS_MAP.put(StringPtg.class, StringEval.class); + + } + + + protected Row row; + protected Sheet sheet; + protected Workbook workbook; + + public FormulaEvaluator(Sheet sheet, Workbook workbook) { + this.sheet = sheet; + this.workbook = workbook; + } + + public void setCurrentRow(Row row) { + this.row = row; + } + + /** + * If cell contains a formula, the formula is evaluated and returned, + * else the CellValue simply copies the appropriate cell value from + * the cell and also its cell type. This method should be preferred over + * evaluateInCell() when the call should not modify the contents of the + * original cell. + * @param cell + */ + public CellValue evaluate(Cell cell) { + CellValue retval = null; + if (cell != null) { + switch (cell.getCellType()) { + case Cell.CELL_TYPE_BLANK: + retval = new CellValue(Cell.CELL_TYPE_BLANK, workbook.getCreationHelper()); + break; + case Cell.CELL_TYPE_BOOLEAN: + retval = new CellValue(Cell.CELL_TYPE_BOOLEAN, workbook.getCreationHelper()); + retval.setBooleanValue(cell.getBooleanCellValue()); + break; + case Cell.CELL_TYPE_ERROR: + retval = new CellValue(Cell.CELL_TYPE_ERROR, workbook.getCreationHelper()); + retval.setErrorValue(cell.getErrorCellValue()); + break; + case Cell.CELL_TYPE_FORMULA: + retval = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook), workbook.getCreationHelper()); + break; + case Cell.CELL_TYPE_NUMERIC: + retval = new CellValue(Cell.CELL_TYPE_NUMERIC, workbook.getCreationHelper()); + retval.setNumberValue(cell.getNumericCellValue()); + break; + case Cell.CELL_TYPE_STRING: + retval = new CellValue(Cell.CELL_TYPE_STRING, workbook.getCreationHelper()); + retval.setRichTextStringValue(cell.getRichStringCellValue()); + break; + } + } + return retval; + } + + + /** + * If cell contains formula, it evaluates the formula, + * and saves the result of the formula. The cell + * remains as a formula cell. + * Else if cell does not contain formula, this method leaves + * the cell unchanged. + * Note that the type of the formula result is returned, + * so you know what kind of value is also stored with + * the formula. + *
+     * int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
+     * 
+ * Be aware that your cell will hold both the formula, + * and the result. If you want the cell replaced with + * the result of the formula, use {@link #evaluateInCell(HSSFCell)} + * @param cell The cell to evaluate + * @return The type of the formula result (the cell's type remains as HSSFCell.CELL_TYPE_FORMULA however) + */ + public int evaluateFormulaCell(Cell cell) { + if (cell != null) { + switch (cell.getCellType()) { + case Cell.CELL_TYPE_FORMULA: + CellValue cv = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook), workbook.getCreationHelper()); + switch (cv.getCellType()) { + case Cell.CELL_TYPE_BOOLEAN: + cell.setCellValue(cv.getBooleanValue()); + break; + case Cell.CELL_TYPE_ERROR: + cell.setCellValue(cv.getErrorValue()); + break; + case Cell.CELL_TYPE_NUMERIC: + cell.setCellValue(cv.getNumberValue()); + break; + case Cell.CELL_TYPE_STRING: + cell.setCellValue(cv.getRichTextStringValue()); + break; + case Cell.CELL_TYPE_BLANK: + break; + case Cell.CELL_TYPE_FORMULA: // this will never happen, we have already evaluated the formula + break; + } + return cv.getCellType(); + } + } + return -1; + } + + /** + * If cell contains formula, it evaluates the formula, and + * puts the formula result back into the cell, in place + * of the old formula. + * Else if cell does not contain formula, this method leaves + * the cell unchanged. + * Note that the same instance of HSSFCell is returned to + * allow chained calls like: + *
+     * int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
+     * 
+ * Be aware that your cell value will be changed to hold the + * result of the formula. If you simply want the formula + * value computed for you, use {@link #evaluateFormulaCell(HSSFCell)} + * @param cell + */ + public Cell evaluateInCell(Cell cell) { + if (cell != null) { + switch (cell.getCellType()) { + case Cell.CELL_TYPE_FORMULA: + CellValue cv = getCellValueForEval(internalEvaluate(cell, row, sheet, workbook), workbook.getCreationHelper()); + switch (cv.getCellType()) { + case Cell.CELL_TYPE_BOOLEAN: + cell.setCellType(Cell.CELL_TYPE_BOOLEAN); + cell.setCellValue(cv.getBooleanValue()); + break; + case Cell.CELL_TYPE_ERROR: + cell.setCellType(Cell.CELL_TYPE_ERROR); + cell.setCellValue(cv.getErrorValue()); + break; + case Cell.CELL_TYPE_NUMERIC: + cell.setCellType(Cell.CELL_TYPE_NUMERIC); + cell.setCellValue(cv.getNumberValue()); + break; + case Cell.CELL_TYPE_STRING: + cell.setCellType(Cell.CELL_TYPE_STRING); + cell.setCellValue(cv.getRichTextStringValue()); + break; + case Cell.CELL_TYPE_BLANK: + break; + case Cell.CELL_TYPE_FORMULA: // this will never happen, we have already evaluated the formula + break; + } + } + } + return cell; + } + + /** + * Loops over all cells in all sheets of the supplied + * workbook. + * For cells that contain formulas, their formulas are + * evaluated, and the results are saved. These cells + * remain as formula cells. + * For cells that do not contain formulas, no changes + * are made. + * This is a helpful wrapper around looping over all + * cells, and calling evaluateFormulaCell on each one. + */ + public static void evaluateAllFormulaCells(Workbook wb) { + for(int i=0; i= 0; j--) { + Eval p = (Eval) stack.pop(); + ops[j] = p; + } + Eval opresult = invokeOperation(operation, ops, srcRowNum, srcColNum, workbook, sheet); + stack.push(opresult); + } + else if (ptg instanceof ReferencePtg) { + ReferencePtg refPtg = (ReferencePtg) ptg; + int colIx = refPtg.getColumn(); + int rowIx = refPtg.getRow(); + Row row = sheet.getRow(rowIx); + Cell cell = (row != null) ? row.getCell(colIx) : null; + stack.push(createRef2DEval(refPtg, cell, row, sheet, workbook)); + } + else if (ptg instanceof Ref3DPtg) { + Ref3DPtg refPtg = (Ref3DPtg) ptg; + int colIx = refPtg.getColumn(); + int rowIx = refPtg.getRow(); + Sheet xsheet = workbook.getSheetAt( + workbook.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex()) + ); + Row row = xsheet.getRow(rowIx); + Cell cell = (row != null) ? row.getCell(colIx) : null; + stack.push(createRef3DEval(refPtg, cell, row, xsheet, workbook)); + } + else if (ptg instanceof AreaPtg) { + AreaPtg ap = (AreaPtg) ptg; + AreaEval ae = evaluateAreaPtg(sheet, workbook, ap); + stack.push(ae); + } + else if (ptg instanceof Area3DPtg) { + Area3DPtg a3dp = (Area3DPtg) ptg; + AreaEval ae = evaluateArea3dPtg(workbook, a3dp); + stack.push(ae); + } + else { + Eval ptgEval = getEvalForPtg(ptg); + stack.push(ptgEval); + } + } + + ValueEval value = ((ValueEval) stack.pop()); + if (!stack.isEmpty()) { + throw new IllegalStateException("evaluation stack not empty"); + } + value = dereferenceValue(value, srcRowNum, srcColNum); + if (value instanceof BlankEval) { + // Note Excel behaviour here. A blank final final value is converted to zero. + return NumberEval.ZERO; + // Formulas _never_ evaluate to blank. If a formula appears to have evaluated to + // blank, the actual value is empty string. This can be verified with ISBLANK(). + } + return value; + } + + /** + * Dereferences a single value from any AreaEval or RefEval evaluation result. + * If the supplied evaluationResult is just a plain value, it is returned as-is. + * @return a NumberEval, StringEval, BoolEval, + * BlankEval or ErrorEval. Never null. + */ + private static ValueEval dereferenceValue(ValueEval evaluationResult, int srcRowNum, short srcColNum) { + if (evaluationResult instanceof RefEval) { + RefEval rv = (RefEval) evaluationResult; + return rv.getInnerValueEval(); + } + if (evaluationResult instanceof AreaEval) { + AreaEval ae = (AreaEval) evaluationResult; + if (ae.isRow()) { + if(ae.isColumn()) { + return ae.getValues()[0]; + } + return ae.getValueAt(ae.getFirstRow(), srcColNum); + } + if (ae.isColumn()) { + return ae.getValueAt(srcRowNum, ae.getFirstColumn()); + } + return ErrorEval.VALUE_INVALID; + } + return evaluationResult; + } + + private static Eval invokeOperation(OperationEval operation, Eval[] ops, int srcRowNum, short srcColNum, + Workbook workbook, Sheet sheet) { + + if(operation instanceof FunctionEval) { + FunctionEval fe = (FunctionEval) operation; + if(fe.isFreeRefFunction()) { + return fe.getFreeRefFunction().evaluate(ops, srcRowNum, srcColNum, workbook, sheet); + } + } + return operation.evaluate(ops, srcRowNum, srcColNum); + } + + public static AreaEval evaluateAreaPtg(Sheet sheet, Workbook workbook, AreaPtg ap) { + int row0 = ap.getFirstRow(); + int col0 = ap.getFirstColumn(); + int row1 = ap.getLastRow(); + int col1 = ap.getLastColumn(); + + // If the last row is -1, then the + // reference is for the rest of the column + // (eg C:C) + // TODO: Handle whole column ranges properly + if(row1 == -1 && row0 >= 0) { + row1 = (short)sheet.getLastRowNum(); + } + ValueEval[] values = evalArea(workbook, sheet, row0, col0, row1, col1); + return new Area2DEval(ap, values); + } + + public static AreaEval evaluateArea3dPtg(Workbook workbook, Area3DPtg a3dp) { + int row0 = a3dp.getFirstRow(); + int col0 = a3dp.getFirstColumn(); + int row1 = a3dp.getLastRow(); + int col1 = a3dp.getLastColumn(); + Sheet xsheet = workbook.getSheetAt( + workbook.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex()) + ); + + // If the last row is -1, then the + // reference is for the rest of the column + // (eg C:C) + // TODO: Handle whole column ranges properly + if(row1 == -1 && row0 >= 0) { + row1 = (short)xsheet.getLastRowNum(); + } + + ValueEval[] values = evalArea(workbook, xsheet, row0, col0, row1, col1); + return new Area3DEval(a3dp, values); + } + + private static ValueEval[] evalArea(Workbook workbook, Sheet sheet, + int row0, int col0, int row1, int col1) { + ValueEval[] values = new ValueEval[(row1 - row0 + 1) * (col1 - col0 + 1)]; + for (int x = row0; sheet != null && x < row1 + 1; x++) { + Row row = sheet.getRow(x); + for (int y = col0; y < col1 + 1; y++) { + ValueEval cellEval; + if(row == null) { + cellEval = BlankEval.INSTANCE; + } else { + cellEval = getEvalForCell(row.getCell(y), row, sheet, workbook); + } + values[(x - row0) * (col1 - col0 + 1) + (y - col0)] = cellEval; + } + } + return values; + } + + /** + * returns an appropriate Eval impl instance for the Ptg. The Ptg must be + * one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg, + * StringPtg, BoolPtg
special Note: OperationPtg subtypes cannot be + * passed here! + * + * @param ptg + */ + protected static Eval getEvalForPtg(Ptg ptg) { + Eval retval = null; + + Class clazz = (Class) VALUE_EVALS_MAP.get(ptg.getClass()); + try { + if (ptg instanceof Area3DPtg) { + Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY); + retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg }); + } + else if (ptg instanceof AreaPtg) { + Constructor constructor = clazz.getConstructor(AREA3D_CONSTRUCTOR_CLASS_ARRAY); + retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg }); + } + else if (ptg instanceof ReferencePtg) { + Constructor constructor = clazz.getConstructor(REFERENCE_CONSTRUCTOR_CLASS_ARRAY); + retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg }); + } + else if (ptg instanceof Ref3DPtg) { + Constructor constructor = clazz.getConstructor(REF3D_CONSTRUCTOR_CLASS_ARRAY); + retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg }); + } + else { + if (ptg instanceof IntPtg || ptg instanceof NumberPtg || ptg instanceof StringPtg + || ptg instanceof BoolPtg) { + Constructor constructor = clazz.getConstructor(VALUE_CONTRUCTOR_CLASS_ARRAY); + retval = (ValueEval) constructor.newInstance(new Ptg[] { ptg }); + } + } + } + catch (Exception e) { + throw new RuntimeException("Fatal Error: ", e); + } + return retval; + + } + + /** + * Given a cell, find its type and from that create an appropriate ValueEval + * impl instance and return that. Since the cell could be an external + * reference, we need the sheet that this belongs to. + * Non existent cells are treated as empty. + * @param cell + * @param sheet + * @param workbook + */ + protected static ValueEval getEvalForCell(Cell cell, Row row, Sheet sheet, Workbook workbook) { + + if (cell == null) { + return BlankEval.INSTANCE; + } + switch (cell.getCellType()) { + case Cell.CELL_TYPE_NUMERIC: + return new NumberEval(cell.getNumericCellValue()); + case Cell.CELL_TYPE_STRING: + return new StringEval(cell.getRichStringCellValue().getString()); + case Cell.CELL_TYPE_FORMULA: + return internalEvaluate(cell, row, sheet, workbook); + case Cell.CELL_TYPE_BOOLEAN: + return BoolEval.valueOf(cell.getBooleanCellValue()); + case Cell.CELL_TYPE_BLANK: + return BlankEval.INSTANCE; + case Cell.CELL_TYPE_ERROR: + return ErrorEval.valueOf(cell.getErrorCellValue()); + } + throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")"); + } + + /** + * Creates a Ref2DEval for ReferencePtg. + * Non existent cells are treated as RefEvals containing BlankEval. + */ + private static Ref2DEval createRef2DEval(ReferencePtg ptg, Cell cell, + Row row, Sheet sheet, Workbook workbook) { + if (cell == null) { + return new Ref2DEval(ptg, BlankEval.INSTANCE); + } + + switch (cell.getCellType()) { + case Cell.CELL_TYPE_NUMERIC: + return new Ref2DEval(ptg, new NumberEval(cell.getNumericCellValue())); + case Cell.CELL_TYPE_STRING: + return new Ref2DEval(ptg, new StringEval(cell.getRichStringCellValue().getString())); + case Cell.CELL_TYPE_FORMULA: + return new Ref2DEval(ptg, internalEvaluate(cell, row, sheet, workbook)); + case Cell.CELL_TYPE_BOOLEAN: + return new Ref2DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue())); + case Cell.CELL_TYPE_BLANK: + return new Ref2DEval(ptg, BlankEval.INSTANCE); + case Cell.CELL_TYPE_ERROR: + return new Ref2DEval(ptg, ErrorEval.valueOf(cell.getErrorCellValue())); + } + throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")"); + } + + /** + * create a Ref3DEval for Ref3DPtg. + */ + private static Ref3DEval createRef3DEval(Ref3DPtg ptg, Cell cell, + Row row, Sheet sheet, Workbook workbook) { + if (cell == null) { + return new Ref3DEval(ptg, BlankEval.INSTANCE); + } + switch (cell.getCellType()) { + case Cell.CELL_TYPE_NUMERIC: + return new Ref3DEval(ptg, new NumberEval(cell.getNumericCellValue())); + case Cell.CELL_TYPE_STRING: + return new Ref3DEval(ptg, new StringEval(cell.getRichStringCellValue().getString())); + case Cell.CELL_TYPE_FORMULA: + return new Ref3DEval(ptg, internalEvaluate(cell, row, sheet, workbook)); + case Cell.CELL_TYPE_BOOLEAN: + return new Ref3DEval(ptg, BoolEval.valueOf(cell.getBooleanCellValue())); + case Cell.CELL_TYPE_BLANK: + return new Ref3DEval(ptg, BlankEval.INSTANCE); + case Cell.CELL_TYPE_ERROR: + return new Ref3DEval(ptg, ErrorEval.valueOf(cell.getErrorCellValue())); + } + throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")"); + } + + /** + * Mimics the 'data view' of a cell. This allows formula evaluator + * to return a CellValue instead of precasting the value to String + * or Number or boolean type. + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + */ + public static class CellValue { + private CreationHelper creationHelper; + private int cellType; + private RichTextString richTextStringValue; + private double numberValue; + private boolean booleanValue; + private byte errorValue; + + /** + * CellType should be one of the types defined in HSSFCell + * @param cellType + */ + public CellValue(int cellType, CreationHelper creationHelper) { + super(); + this.creationHelper = creationHelper; + this.cellType = cellType; + } + /** + * @return Returns the booleanValue. + */ + public boolean getBooleanValue() { + return booleanValue; + } + /** + * @param booleanValue The booleanValue to set. + */ + public void setBooleanValue(boolean booleanValue) { + this.booleanValue = booleanValue; + } + /** + * @return Returns the numberValue. + */ + public double getNumberValue() { + return numberValue; + } + /** + * @param numberValue The numberValue to set. + */ + public void setNumberValue(double numberValue) { + this.numberValue = numberValue; + } + /** + * @return Returns the stringValue. This method is deprecated, use + * getRichTextStringValue instead + * @deprecated + */ + public String getStringValue() { + return richTextStringValue.getString(); + } + /** + * @param stringValue The stringValue to set. This method is deprecated, use + * getRichTextStringValue instead. + * @deprecated + */ + public void setStringValue(String stringValue) { + this.richTextStringValue = + creationHelper.createRichTextString(stringValue); + } + /** + * @return Returns the cellType. + */ + public int getCellType() { + return cellType; + } + /** + * @return Returns the errorValue. + */ + public byte getErrorValue() { + return errorValue; + } + /** + * @param errorValue The errorValue to set. + */ + public void setErrorValue(byte errorValue) { + this.errorValue = errorValue; + } + /** + * @return Returns the richTextStringValue. + */ + public RichTextString getRichTextStringValue() { + return richTextStringValue; + } + /** + * @param richTextStringValue The richTextStringValue to set. + */ + public void setRichTextStringValue(RichTextString richTextStringValue) { + this.richTextStringValue = richTextStringValue; + } + } +} diff --git a/src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java b/src/java/org/apache/poi/ss/usermodel/OperationEvaluatorFactory.java similarity index 99% rename from src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java rename to src/java/org/apache/poi/ss/usermodel/OperationEvaluatorFactory.java index 129200969..ed136e037 100755 --- a/src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java +++ b/src/java/org/apache/poi/ss/usermodel/OperationEvaluatorFactory.java @@ -15,7 +15,7 @@ limitations under the License. ==================================================================== */ -package org.apache.poi.hssf.usermodel; +package org.apache.poi.ss.usermodel; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; diff --git a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Workbook.java b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Workbook.java index e66cf0e1d..5605752d0 100644 --- a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Workbook.java +++ b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Workbook.java @@ -174,6 +174,14 @@ public interface Workbook { */ int getNumberOfSheets(); + + /** + * Finds the sheet index for a particular external sheet number. + * @param externSheetNumber The external sheet number to convert + * @return The index to the sheet found. + */ + int getSheetIndexFromExternSheetIndex(int externSheetNumber); + /** * Get the HSSFSheet object at the given index. diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java index d2f0d3608..dd6e5eb2c 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java @@ -472,8 +472,17 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook { } return -1; } + + /** + * Doesn't do anything - returns the same index + * TODO - figure out if this is a ole2 specific thing, or + * if we need to do something proper here too! + */ + public int getSheetIndexFromExternSheetIndex(int externSheetNumber) { + return externSheetNumber; + } - public Sheet getSheet(String name) { + public Sheet getSheet(String name) { CTSheet[] sheets = this.workbook.getSheets().getSheetArray(); for (int i = 0 ; i < sheets.length ; ++i) { if (name.equals(sheets[i].getName())) { diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java index 741973453..b200515ff 100644 --- a/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java +++ b/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java @@ -29,7 +29,7 @@ import org.apache.poi.hssf.usermodel.HSSFName; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue; +import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue; /** * Test the low level formula parser functionality, diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java index 72db658f7..97ddfdf22 100755 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java @@ -25,7 +25,7 @@ import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue; +import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue; /** * Tests HSSFFormulaEvaluator for its handling of cell formula circular references. * diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java index 27e333865..647b6330f 100755 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestExternalFunction.java @@ -25,7 +25,7 @@ import org.apache.poi.hssf.usermodel.HSSFName; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue; +import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue; /** * * @author Josh Micich diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java index 617f5d0d4..a833b77c0 100755 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulaBugs.java @@ -32,7 +32,7 @@ import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue; +import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue; /** * Miscellaneous tests for bugzilla entries.

The test name contains the diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java index 2d5408c76..4b079bcce 100644 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestFormulasFromSpreadsheet.java @@ -30,6 +30,8 @@ import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.FormulaEvaluator; /** * Tests formulas and operators as loaded from a test data spreadsheet.

@@ -104,7 +106,7 @@ public final class TestFormulasFromSpreadsheet extends TestCase { } - private static void confirmExpectedResult(String msg, HSSFCell expected, HSSFFormulaEvaluator.CellValue actual) { + private static void confirmExpectedResult(String msg, Cell expected, FormulaEvaluator.CellValue actual) { if (expected == null) { throw new AssertionFailedError(msg + " - Bad setup data expected value is null"); } @@ -249,7 +251,7 @@ public final class TestFormulasFromSpreadsheet extends TestCase { continue; } - HSSFFormulaEvaluator.CellValue actualValue = evaluator.evaluate(c); + FormulaEvaluator.CellValue actualValue = evaluator.evaluate(c); HSSFCell expectedValueCell = getExpectedValueCell(expectedValuesRow, colnum); try { diff --git a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java index be8cef13f..c1daa094c 100755 --- a/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java @@ -27,7 +27,7 @@ import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue; +import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue; /** * Test for percent operator evaluator. diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIsBlank.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIsBlank.java index 7ce2bd245..90389eeaa 100755 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIsBlank.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestIsBlank.java @@ -24,7 +24,7 @@ import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue; +import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue; /** * Tests for Excel function ISBLANK() * diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLookupFunctionsFromSpreadsheet.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLookupFunctionsFromSpreadsheet.java index 071ca0f7d..958654b06 100644 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLookupFunctionsFromSpreadsheet.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestLookupFunctionsFromSpreadsheet.java @@ -32,7 +32,7 @@ import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue; +import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue; import org.apache.poi.hssf.util.CellReference; /** @@ -90,7 +90,7 @@ public final class TestLookupFunctionsFromSpreadsheet extends TestCase { - private static void confirmExpectedResult(String msg, HSSFCell expected, HSSFFormulaEvaluator.CellValue actual) { + private static void confirmExpectedResult(String msg, HSSFCell expected, CellValue actual) { if (expected == null) { throw new AssertionFailedError(msg + " - Bad setup data expected value is null"); } diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java b/src/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java index c849fd436..f137ef6e9 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestBug42464.java @@ -25,7 +25,7 @@ import junit.framework.TestCase; import org.apache.poi.hssf.record.FormulaRecord; import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; -import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue; +import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue; import org.apache.poi.hssf.util.CellReference; public final class TestBug42464 extends TestCase {