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
*/
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) {
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();
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;
/**
* 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);
}
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<p/>
*/
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;
}
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()<p/>
*
}
- 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;
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());
+++ /dev/null
-/* ====================================================================
- 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.usermodel;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Instances of this class keep track of multiple dependent cell evaluations due
- * to recursive calls to <tt>HSSFFormulaEvaluator.internalEvaluate()</tt>.
- * The main purpose of this class is to detect an attempt to evaluate a cell
- * that is already being evaluated. In other words, it detects circular
- * references in spreadsheet formulas.
- *
- * @author Josh Micich
- */
-final class EvaluationCycleDetector {
-
- /**
- * Stores the parameters that identify the evaluation of one cell.<br/>
- */
- private static final class CellEvaluationFrame {
-
- private final HSSFWorkbook _workbook;
- private final HSSFSheet _sheet;
- private final int _srcRowNum;
- private final int _srcColNum;
-
- public CellEvaluationFrame(HSSFWorkbook workbook, HSSFSheet sheet, int srcRowNum, int srcColNum) {
- if (workbook == null) {
- throw new IllegalArgumentException("workbook must not be null");
- }
- if (sheet == null) {
- throw new IllegalArgumentException("sheet must not be null");
- }
- _workbook = workbook;
- _sheet = sheet;
- _srcRowNum = srcRowNum;
- _srcColNum = srcColNum;
- }
-
- public boolean equals(Object obj) {
- CellEvaluationFrame other = (CellEvaluationFrame) obj;
- if (_workbook != other._workbook) {
- return false;
- }
- if (_sheet != other._sheet) {
- return false;
- }
- if (_srcRowNum != other._srcRowNum) {
- return false;
- }
- if (_srcColNum != other._srcColNum) {
- return false;
- }
- return true;
- }
-
- /**
- * @return human readable string for debug purposes
- */
- public String formatAsString() {
- return "R=" + _srcRowNum + " C=" + _srcColNum + " ShIx=" + _workbook.getSheetIndex(_sheet);
- }
-
- public String toString() {
- StringBuffer sb = new StringBuffer(64);
- sb.append(getClass().getName()).append(" [");
- sb.append(formatAsString());
- sb.append("]");
- return sb.toString();
- }
- }
-
- private final List _evaluationFrames;
-
- public EvaluationCycleDetector() {
- _evaluationFrames = new ArrayList();
- }
-
- /**
- * Notifies this evaluation tracker that evaluation of the specified cell is
- * about to start.<br/>
- *
- * In the case of a <code>true</code> return code, the caller should
- * continue evaluation of the specified cell, and also be sure to call
- * <tt>endEvaluate()</tt> when complete.<br/>
- *
- * In the case of a <code>false</code> return code, the caller should
- * return an evaluation result of
- * <tt>ErrorEval.CIRCULAR_REF_ERROR<tt>, and not call <tt>endEvaluate()</tt>.
- * <br/>
- * @return <code>true</code> if the specified cell has not been visited yet in the current
- * evaluation. <code>false</code> if the specified cell is already being evaluated.
- */
- public boolean startEvaluate(HSSFWorkbook workbook, HSSFSheet sheet, int srcRowNum, int srcColNum) {
- CellEvaluationFrame cef = new CellEvaluationFrame(workbook, sheet, srcRowNum, srcColNum);
- if (_evaluationFrames.contains(cef)) {
- return false;
- }
- _evaluationFrames.add(cef);
- return true;
- }
-
- /**
- * Notifies this evaluation tracker that the evaluation of the specified
- * cell is complete. <p/>
- *
- * Every successful call to <tt>startEvaluate</tt> must be followed by a
- * call to <tt>endEvaluate</tt> (recommended in a finally block) to enable
- * proper tracking of which cells are being evaluated at any point in time.<p/>
- *
- * Assuming a well behaved client, parameters to this method would not be
- * 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) {
- int nFrames = _evaluationFrames.size();
- if (nFrames < 1) {
- throw new IllegalStateException("Call to endEvaluate without matching call to startEvaluate");
- }
-
- nFrames--;
- CellEvaluationFrame cefExpected = (CellEvaluationFrame) _evaluationFrames.get(nFrames);
- CellEvaluationFrame cefActual = new CellEvaluationFrame(workbook, sheet, srcRowNum, srcColNum);
- if (!cefActual.equals(cefExpected)) {
- throw new RuntimeException("Wrong cell specified. "
- + "Corresponding startEvaluate() call was for cell {"
- + cefExpected.formatAsString() + "} this endEvaluate() call is for cell {"
- + cefActual.formatAsString() + "}");
- }
- // else - no problems so pop current frame
- _evaluationFrames.remove(nFrames);
- }
-}
+++ /dev/null
-/* ====================================================================
- 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.usermodel;
-
-/**
- * This class makes an <tt>EvaluationCycleDetector</tt> instance available to
- * each thread via a <tt>ThreadLocal</tt> in order to avoid adding a parameter
- * to a few protected methods within <tt>HSSFFormulaEvaluator</tt>.
- *
- * @author Josh Micich
- */
-final class EvaluationCycleDetectorManager {
-
- ThreadLocal tl = null;
- private static ThreadLocal _tlEvaluationTracker = new ThreadLocal() {
- protected synchronized Object initialValue() {
- return new EvaluationCycleDetector();
- }
- };
-
- /**
- * @return
- */
- public static EvaluationCycleDetector getTracker() {
- return (EvaluationCycleDetector) _tlEvaluationTracker.get();
- }
-
- private EvaluationCycleDetectorManager() {
- // no instances of this class
- }
-}
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.
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.
- * <pre>
- * int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
- * </pre>
- * 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:
- * <pre>
- * int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
- * </pre>
- * 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<wb.getNumberOfSheets(); i++) {
- HSSFSheet sheet = wb.getSheetAt(i);
- HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
-
- for (Iterator rit = sheet.rowIterator(); rit.hasNext();) {
- HSSFRow r = (HSSFRow)rit.next();
- evaluator.setCurrentRow(r);
-
- for (Iterator cit = r.cellIterator(); cit.hasNext();) {
- HSSFCell c = (HSSFCell)cit.next();
- if (c.getCellType() == HSSFCell.CELL_TYPE_FORMULA)
- evaluator.evaluateFormulaCell(c);
- }
- }
- }
- }
-
-
- /**
- * Returns a CellValue wrapper around the supplied ValueEval instance.
- * @param eval
- */
- protected static CellValue getCellValueForEval(ValueEval eval) {
- CellValue retval = null;
- if (eval != null) {
- if (eval instanceof NumberEval) {
- NumberEval ne = (NumberEval) eval;
- retval = new CellValue(HSSFCell.CELL_TYPE_NUMERIC);
- retval.setNumberValue(ne.getNumberValue());
- }
- else if (eval instanceof BoolEval) {
- BoolEval be = (BoolEval) eval;
- retval = new CellValue(HSSFCell.CELL_TYPE_BOOLEAN);
- retval.setBooleanValue(be.getBooleanValue());
- }
- else if (eval instanceof StringEval) {
- StringEval ne = (StringEval) eval;
- retval = new CellValue(HSSFCell.CELL_TYPE_STRING);
- retval.setStringValue(ne.getStringValue());
- }
- else if (eval instanceof BlankEval) {
- retval = new CellValue(HSSFCell.CELL_TYPE_BLANK);
- }
- else if (eval instanceof ErrorEval) {
- retval = new CellValue(HSSFCell.CELL_TYPE_ERROR);
- retval.setErrorValue((byte)((ErrorEval)eval).getErrorCode());
-// retval.setRichTextStringValue(new HSSFRichTextString("#An error occurred. check cell.getErrorCode()"));
- }
- else {
- retval = new CellValue(HSSFCell.CELL_TYPE_ERROR);
- }
- }
- return retval;
- }
-
- /**
- * Dev. Note: Internal evaluate must be passed only a formula cell
- * else a runtime exception will be thrown somewhere inside the method.
- * (Hence this is a private method.)
- */
- private static ValueEval internalEvaluate(HSSFCell srcCell, HSSFRow srcRow, HSSFSheet sheet, HSSFWorkbook workbook) {
- int srcRowNum = srcRow.getRowNum();
- short srcColNum = srcCell.getCellNum();
-
-
- EvaluationCycleDetector tracker = EvaluationCycleDetectorManager.getTracker();
-
- if(!tracker.startEvaluate(workbook, sheet, srcRowNum, srcColNum)) {
- return ErrorEval.CIRCULAR_REF_ERROR;
- }
- try {
- return evaluateCell(workbook, sheet, srcRowNum, srcColNum, srcCell.getCellFormula());
- } finally {
- tracker.endEvaluate(workbook, sheet, srcRowNum, srcColNum);
- }
- }
- private static ValueEval evaluateCell(HSSFWorkbook workbook, HSSFSheet sheet,
- int srcRowNum, short srcColNum, String cellFormulaText) {
- FormulaParser parser = new FormulaParser(cellFormulaText, workbook.getWorkbook());
- parser.parse();
- Ptg[] ptgs = parser.getRPNPtg();
- // -- parsing over --
-
-
- Stack stack = new Stack();
- for (int i = 0, iSize = ptgs.length; i < iSize; i++) {
-
- // since we don't know how to handle these yet :(
- Ptg ptg = ptgs[i];
- if (ptg instanceof ControlPtg) { continue; }
- if (ptg instanceof MemErrPtg) { continue; }
- if (ptg instanceof MissingArgPtg) { continue; }
- if (ptg instanceof NamePtg) {
- // named ranges, macro functions
- NamePtg namePtg = (NamePtg) ptg;
- stack.push(new NameEval(namePtg.getIndex()));
- continue;
- }
- if (ptg instanceof NameXPtg) {
- // TODO - external functions
- continue;
- }
- if (ptg instanceof UnknownPtg) { continue; }
-
- if (ptg instanceof OperationPtg) {
- OperationPtg optg = (OperationPtg) ptg;
-
- // parens can be ignored since we have RPN tokens
- if (optg instanceof ParenthesisPtg) { continue; }
- if (optg instanceof AttrPtg) { continue; }
- if (optg instanceof UnionPtg) { continue; }
-
- OperationEval operation = OperationEvaluatorFactory.create(optg);
-
- int numops = operation.getNumberOfOperands();
- Eval[] ops = new Eval[numops];
-
- // storing the ops in reverse order since they are popping
- for (int j = numops - 1; j >= 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 <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt>,
- * <tt>BlankEval</tt> or <tt>ErrorEval</tt>. Never <code>null</code>.
- */
- 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 <br/>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
* @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("<ptg-group>");
System.out.println("</ptg-group>");
}
+ /**
+ * 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);
+// }
+// }
}
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
+++ /dev/null
-/* ====================================================================
- 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.usermodel;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.poi.hssf.record.formula.AddPtg;
-import org.apache.poi.hssf.record.formula.ConcatPtg;
-import org.apache.poi.hssf.record.formula.DividePtg;
-import org.apache.poi.hssf.record.formula.EqualPtg;
-import org.apache.poi.hssf.record.formula.ExpPtg;
-import org.apache.poi.hssf.record.formula.FuncPtg;
-import org.apache.poi.hssf.record.formula.FuncVarPtg;
-import org.apache.poi.hssf.record.formula.GreaterEqualPtg;
-import org.apache.poi.hssf.record.formula.GreaterThanPtg;
-import org.apache.poi.hssf.record.formula.LessEqualPtg;
-import org.apache.poi.hssf.record.formula.LessThanPtg;
-import org.apache.poi.hssf.record.formula.MultiplyPtg;
-import org.apache.poi.hssf.record.formula.NotEqualPtg;
-import org.apache.poi.hssf.record.formula.OperationPtg;
-import org.apache.poi.hssf.record.formula.PercentPtg;
-import org.apache.poi.hssf.record.formula.PowerPtg;
-import org.apache.poi.hssf.record.formula.Ptg;
-import org.apache.poi.hssf.record.formula.SubtractPtg;
-import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
-import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
-import org.apache.poi.hssf.record.formula.eval.AddEval;
-import org.apache.poi.hssf.record.formula.eval.ConcatEval;
-import org.apache.poi.hssf.record.formula.eval.DivideEval;
-import org.apache.poi.hssf.record.formula.eval.EqualEval;
-import org.apache.poi.hssf.record.formula.eval.FuncVarEval;
-import org.apache.poi.hssf.record.formula.eval.GreaterEqualEval;
-import org.apache.poi.hssf.record.formula.eval.GreaterThanEval;
-import org.apache.poi.hssf.record.formula.eval.LessEqualEval;
-import org.apache.poi.hssf.record.formula.eval.LessThanEval;
-import org.apache.poi.hssf.record.formula.eval.MultiplyEval;
-import org.apache.poi.hssf.record.formula.eval.NotEqualEval;
-import org.apache.poi.hssf.record.formula.eval.OperationEval;
-import org.apache.poi.hssf.record.formula.eval.PercentEval;
-import org.apache.poi.hssf.record.formula.eval.PowerEval;
-import org.apache.poi.hssf.record.formula.eval.SubtractEval;
-import org.apache.poi.hssf.record.formula.eval.UnaryMinusEval;
-import org.apache.poi.hssf.record.formula.eval.UnaryPlusEval;
-
-/**
- * This class creates <tt>OperationEval</tt> instances to help evaluate <tt>OperationPtg</tt>
- * formula tokens.
- *
- * @author Josh Micich
- */
-final class OperationEvaluatorFactory {
- private static final Class[] OPERATION_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
-
- private static final Map _constructorsByPtgClass = initialiseConstructorsMap();
-
- private OperationEvaluatorFactory() {
- // no instances of this class
- }
-
- private static Map initialiseConstructorsMap() {
- Map m = new HashMap(32);
- add(m, AddPtg.class, AddEval.class);
- add(m, ConcatPtg.class, ConcatEval.class);
- add(m, DividePtg.class, DivideEval.class);
- add(m, EqualPtg.class, EqualEval.class);
- add(m, FuncPtg.class, FuncVarEval.class);
- add(m, FuncVarPtg.class, FuncVarEval.class);
- add(m, GreaterEqualPtg.class, GreaterEqualEval.class);
- add(m, GreaterThanPtg.class, GreaterThanEval.class);
- add(m, LessEqualPtg.class, LessEqualEval.class);
- add(m, LessThanPtg.class, LessThanEval.class);
- add(m, MultiplyPtg.class, MultiplyEval.class);
- add(m, NotEqualPtg.class, NotEqualEval.class);
- add(m, PercentPtg.class, PercentEval.class);
- add(m, PowerPtg.class, PowerEval.class);
- add(m, SubtractPtg.class, SubtractEval.class);
- add(m, UnaryMinusPtg.class, UnaryMinusEval.class);
- add(m, UnaryPlusPtg.class, UnaryPlusEval.class);
- return m;
- }
-
- private static void add(Map m, Class ptgClass, Class evalClass) {
-
- // perform some validation now, to keep later exception handlers simple
- if(!Ptg.class.isAssignableFrom(ptgClass)) {
- throw new IllegalArgumentException("Expected Ptg subclass");
- }
- if(!OperationEval.class.isAssignableFrom(evalClass)) {
- throw new IllegalArgumentException("Expected OperationEval subclass");
- }
- if (!Modifier.isPublic(evalClass.getModifiers())) {
- throw new RuntimeException("Eval class must be public");
- }
- if (Modifier.isAbstract(evalClass.getModifiers())) {
- throw new RuntimeException("Eval class must not be abstract");
- }
-
- Constructor constructor;
- try {
- constructor = evalClass.getDeclaredConstructor(OPERATION_CONSTRUCTOR_CLASS_ARRAY);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("Missing constructor");
- }
- if (!Modifier.isPublic(constructor.getModifiers())) {
- throw new RuntimeException("Eval constructor must be public");
- }
- m.put(ptgClass, constructor);
- }
-
- /**
- * returns the OperationEval concrete impl instance corresponding
- * to the supplied operationPtg
- */
- public static OperationEval create(OperationPtg ptg) {
- if(ptg == null) {
- throw new IllegalArgumentException("ptg must not be null");
- }
-
- Class ptgClass = ptg.getClass();
-
- Constructor constructor = (Constructor) _constructorsByPtgClass.get(ptgClass);
- if(constructor == null) {
- if(ptgClass == ExpPtg.class) {
- // ExpPtg is used for array formulas and shared formulas.
- // it is currently unsupported, and may not even get implemented here
- throw new RuntimeException("ExpPtg currently not supported");
- }
- throw new RuntimeException("Unexpected operation ptg class (" + ptgClass.getName() + ")");
- }
-
- Object result;
- Object[] initargs = { ptg };
- try {
- result = constructor.newInstance(initargs);
- } catch (IllegalArgumentException e) {
- throw new RuntimeException(e);
- } catch (InstantiationException e) {
- throw new RuntimeException(e);
- } catch (IllegalAccessException e) {
- throw new RuntimeException(e);
- } catch (InvocationTargetException e) {
- throw new RuntimeException(e);
- }
- return (OperationEval) result;
- }
-}
--- /dev/null
+/* ====================================================================
+ 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.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 <tt>HSSFFormulaEvaluator.internalEvaluate()</tt>.
+ * The main purpose of this class is to detect an attempt to evaluate a cell
+ * that is already being evaluated. In other words, it detects circular
+ * references in spreadsheet formulas.
+ *
+ * @author Josh Micich
+ */
+final class EvaluationCycleDetector {
+
+ /**
+ * Stores the parameters that identify the evaluation of one cell.<br/>
+ */
+ private static final class CellEvaluationFrame {
+
+ private final Workbook _workbook;
+ private final Sheet _sheet;
+ private final int _srcRowNum;
+ private final int _srcColNum;
+
+ public CellEvaluationFrame(Workbook workbook, Sheet sheet, int srcRowNum, int srcColNum) {
+ if (workbook == null) {
+ throw new IllegalArgumentException("workbook must not be null");
+ }
+ if (sheet == null) {
+ throw new IllegalArgumentException("sheet must not be null");
+ }
+ _workbook = workbook;
+ _sheet = sheet;
+ _srcRowNum = srcRowNum;
+ _srcColNum = srcColNum;
+ }
+
+ public boolean equals(Object obj) {
+ CellEvaluationFrame other = (CellEvaluationFrame) obj;
+ if (_workbook != other._workbook) {
+ return false;
+ }
+ if (_sheet != other._sheet) {
+ return false;
+ }
+ if (_srcRowNum != other._srcRowNum) {
+ return false;
+ }
+ if (_srcColNum != other._srcColNum) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @return human readable string for debug purposes
+ */
+ public String formatAsString() {
+ return "R=" + _srcRowNum + " C=" + _srcColNum + " ShIx=" + _workbook.getSheetIndex(_sheet);
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(getClass().getName()).append(" [");
+ sb.append(formatAsString());
+ sb.append("]");
+ return sb.toString();
+ }
+ }
+
+ private final List _evaluationFrames;
+
+ public EvaluationCycleDetector() {
+ _evaluationFrames = new ArrayList();
+ }
+
+ /**
+ * Notifies this evaluation tracker that evaluation of the specified cell is
+ * about to start.<br/>
+ *
+ * In the case of a <code>true</code> return code, the caller should
+ * continue evaluation of the specified cell, and also be sure to call
+ * <tt>endEvaluate()</tt> when complete.<br/>
+ *
+ * In the case of a <code>false</code> return code, the caller should
+ * return an evaluation result of
+ * <tt>ErrorEval.CIRCULAR_REF_ERROR<tt>, and not call <tt>endEvaluate()</tt>.
+ * <br/>
+ * @return <code>true</code> if the specified cell has not been visited yet in the current
+ * evaluation. <code>false</code> if the specified cell is already being evaluated.
+ */
+ 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;
+ }
+ _evaluationFrames.add(cef);
+ return true;
+ }
+
+ /**
+ * Notifies this evaluation tracker that the evaluation of the specified
+ * cell is complete. <p/>
+ *
+ * Every successful call to <tt>startEvaluate</tt> must be followed by a
+ * call to <tt>endEvaluate</tt> (recommended in a finally block) to enable
+ * proper tracking of which cells are being evaluated at any point in time.<p/>
+ *
+ * Assuming a well behaved client, parameters to this method would not be
+ * required. However, they have been included to assert correct behaviour,
+ * and form more meaningful error messages.
+ */
+ 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");
+ }
+
+ nFrames--;
+ CellEvaluationFrame cefExpected = (CellEvaluationFrame) _evaluationFrames.get(nFrames);
+ CellEvaluationFrame cefActual = new CellEvaluationFrame(workbook, sheet, srcRowNum, srcColNum);
+ if (!cefActual.equals(cefExpected)) {
+ throw new RuntimeException("Wrong cell specified. "
+ + "Corresponding startEvaluate() call was for cell {"
+ + cefExpected.formatAsString() + "} this endEvaluate() call is for cell {"
+ + cefActual.formatAsString() + "}");
+ }
+ // else - no problems so pop current frame
+ _evaluationFrames.remove(nFrames);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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;
+
+/**
+ * This class makes an <tt>EvaluationCycleDetector</tt> instance available to
+ * each thread via a <tt>ThreadLocal</tt> in order to avoid adding a parameter
+ * to a few protected methods within <tt>HSSFFormulaEvaluator</tt>.
+ *
+ * @author Josh Micich
+ */
+final class EvaluationCycleDetectorManager {
+
+ ThreadLocal tl = null;
+ private static ThreadLocal _tlEvaluationTracker = new ThreadLocal() {
+ protected synchronized Object initialValue() {
+ return new EvaluationCycleDetector();
+ }
+ };
+
+ /**
+ * @return
+ */
+ public static EvaluationCycleDetector getTracker() {
+ return (EvaluationCycleDetector) _tlEvaluationTracker.get();
+ }
+
+ private EvaluationCycleDetectorManager() {
+ // no instances of this class
+ }
+}
--- /dev/null
+/*
+* 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.
+ * <pre>
+ * int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
+ * </pre>
+ * 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:
+ * <pre>
+ * int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
+ * </pre>
+ * 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<wb.getNumberOfSheets(); i++) {
+ Sheet sheet = wb.getSheetAt(i);
+ FormulaEvaluator evaluator = new FormulaEvaluator(sheet, wb);
+
+ for (Iterator rit = sheet.rowIterator(); rit.hasNext();) {
+ Row r = (Row)rit.next();
+ evaluator.setCurrentRow(r);
+
+ for (Iterator cit = r.cellIterator(); cit.hasNext();) {
+ Cell c = (Cell)cit.next();
+ if (c.getCellType() == Cell.CELL_TYPE_FORMULA)
+ evaluator.evaluateFormulaCell(c);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Returns a CellValue wrapper around the supplied ValueEval instance.
+ * @param eval
+ */
+ protected static CellValue getCellValueForEval(ValueEval eval, CreationHelper cHelper) {
+ CellValue retval = null;
+ if (eval != null) {
+ if (eval instanceof NumberEval) {
+ NumberEval ne = (NumberEval) eval;
+ retval = new CellValue(Cell.CELL_TYPE_NUMERIC, cHelper);
+ retval.setNumberValue(ne.getNumberValue());
+ }
+ else if (eval instanceof BoolEval) {
+ BoolEval be = (BoolEval) eval;
+ retval = new CellValue(Cell.CELL_TYPE_BOOLEAN, cHelper);
+ retval.setBooleanValue(be.getBooleanValue());
+ }
+ else if (eval instanceof StringEval) {
+ StringEval ne = (StringEval) eval;
+ retval = new CellValue(Cell.CELL_TYPE_STRING, cHelper);
+ retval.setStringValue(ne.getStringValue());
+ }
+ else if (eval instanceof BlankEval) {
+ retval = new CellValue(Cell.CELL_TYPE_BLANK, cHelper);
+ }
+ else if (eval instanceof ErrorEval) {
+ retval = new CellValue(Cell.CELL_TYPE_ERROR, cHelper);
+ retval.setErrorValue((byte)((ErrorEval)eval).getErrorCode());
+// retval.setRichTextStringValue(new HSSFRichTextString("#An error occurred. check cell.getErrorCode()"));
+ }
+ else {
+ retval = new CellValue(Cell.CELL_TYPE_ERROR, cHelper);
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * Dev. Note: Internal evaluate must be passed only a formula cell
+ * else a runtime exception will be thrown somewhere inside the method.
+ * (Hence this is a private method.)
+ */
+ private static ValueEval internalEvaluate(Cell srcCell, Row srcRow, Sheet sheet, Workbook workbook) {
+ int srcRowNum = srcRow.getRowNum();
+ short srcColNum = srcCell.getCellNum();
+
+
+ EvaluationCycleDetector tracker = EvaluationCycleDetectorManager.getTracker();
+
+ if(!tracker.startEvaluate(workbook, sheet, srcRowNum, srcColNum)) {
+ return ErrorEval.CIRCULAR_REF_ERROR;
+ }
+ try {
+ return evaluateCell(workbook, sheet, srcRowNum, srcColNum, srcCell.getCellFormula());
+ } finally {
+ tracker.endEvaluate(workbook, sheet, srcRowNum, srcColNum);
+ }
+ }
+ private static ValueEval evaluateCell(Workbook workbook, Sheet sheet,
+ int srcRowNum, short srcColNum, String cellFormulaText) {
+
+ FormulaParser parser;
+ if(workbook instanceof HSSFWorkbook) {
+ parser = HSSFFormulaEvaluator.getUnderlyingParser(
+ (HSSFWorkbook)workbook,
+ cellFormulaText
+ );
+ } else {
+ // Hope for the best...
+ parser = new FormulaParser(cellFormulaText, null);
+ }
+
+ parser.parse();
+ Ptg[] ptgs = parser.getRPNPtg();
+ // -- parsing over --
+
+
+ Stack stack = new Stack();
+ for (int i = 0, iSize = ptgs.length; i < iSize; i++) {
+
+ // since we don't know how to handle these yet :(
+ Ptg ptg = ptgs[i];
+ if (ptg instanceof ControlPtg) { continue; }
+ if (ptg instanceof MemErrPtg) { continue; }
+ if (ptg instanceof MissingArgPtg) { continue; }
+ if (ptg instanceof NamePtg) {
+ // named ranges, macro functions
+ NamePtg namePtg = (NamePtg) ptg;
+ stack.push(new NameEval(namePtg.getIndex()));
+ continue;
+ }
+ if (ptg instanceof NameXPtg) {
+ // TODO - external functions
+ continue;
+ }
+ if (ptg instanceof UnknownPtg) { continue; }
+
+ if (ptg instanceof OperationPtg) {
+ OperationPtg optg = (OperationPtg) ptg;
+
+ // parens can be ignored since we have RPN tokens
+ if (optg instanceof ParenthesisPtg) { continue; }
+ if (optg instanceof AttrPtg) { continue; }
+ if (optg instanceof UnionPtg) { continue; }
+
+ OperationEval operation = OperationEvaluatorFactory.create(optg);
+
+ int numops = operation.getNumberOfOperands();
+ Eval[] ops = new Eval[numops];
+
+ // storing the ops in reverse order since they are popping
+ for (int j = numops - 1; j >= 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 <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt>,
+ * <tt>BlankEval</tt> or <tt>ErrorEval</tt>. Never <code>null</code>.
+ */
+ 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 <br/>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;
+ }
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.hssf.record.formula.AddPtg;
+import org.apache.poi.hssf.record.formula.ConcatPtg;
+import org.apache.poi.hssf.record.formula.DividePtg;
+import org.apache.poi.hssf.record.formula.EqualPtg;
+import org.apache.poi.hssf.record.formula.ExpPtg;
+import org.apache.poi.hssf.record.formula.FuncPtg;
+import org.apache.poi.hssf.record.formula.FuncVarPtg;
+import org.apache.poi.hssf.record.formula.GreaterEqualPtg;
+import org.apache.poi.hssf.record.formula.GreaterThanPtg;
+import org.apache.poi.hssf.record.formula.LessEqualPtg;
+import org.apache.poi.hssf.record.formula.LessThanPtg;
+import org.apache.poi.hssf.record.formula.MultiplyPtg;
+import org.apache.poi.hssf.record.formula.NotEqualPtg;
+import org.apache.poi.hssf.record.formula.OperationPtg;
+import org.apache.poi.hssf.record.formula.PercentPtg;
+import org.apache.poi.hssf.record.formula.PowerPtg;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.formula.SubtractPtg;
+import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
+import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
+import org.apache.poi.hssf.record.formula.eval.AddEval;
+import org.apache.poi.hssf.record.formula.eval.ConcatEval;
+import org.apache.poi.hssf.record.formula.eval.DivideEval;
+import org.apache.poi.hssf.record.formula.eval.EqualEval;
+import org.apache.poi.hssf.record.formula.eval.FuncVarEval;
+import org.apache.poi.hssf.record.formula.eval.GreaterEqualEval;
+import org.apache.poi.hssf.record.formula.eval.GreaterThanEval;
+import org.apache.poi.hssf.record.formula.eval.LessEqualEval;
+import org.apache.poi.hssf.record.formula.eval.LessThanEval;
+import org.apache.poi.hssf.record.formula.eval.MultiplyEval;
+import org.apache.poi.hssf.record.formula.eval.NotEqualEval;
+import org.apache.poi.hssf.record.formula.eval.OperationEval;
+import org.apache.poi.hssf.record.formula.eval.PercentEval;
+import org.apache.poi.hssf.record.formula.eval.PowerEval;
+import org.apache.poi.hssf.record.formula.eval.SubtractEval;
+import org.apache.poi.hssf.record.formula.eval.UnaryMinusEval;
+import org.apache.poi.hssf.record.formula.eval.UnaryPlusEval;
+
+/**
+ * This class creates <tt>OperationEval</tt> instances to help evaluate <tt>OperationPtg</tt>
+ * formula tokens.
+ *
+ * @author Josh Micich
+ */
+final class OperationEvaluatorFactory {
+ private static final Class[] OPERATION_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
+
+ private static final Map _constructorsByPtgClass = initialiseConstructorsMap();
+
+ private OperationEvaluatorFactory() {
+ // no instances of this class
+ }
+
+ private static Map initialiseConstructorsMap() {
+ Map m = new HashMap(32);
+ add(m, AddPtg.class, AddEval.class);
+ add(m, ConcatPtg.class, ConcatEval.class);
+ add(m, DividePtg.class, DivideEval.class);
+ add(m, EqualPtg.class, EqualEval.class);
+ add(m, FuncPtg.class, FuncVarEval.class);
+ add(m, FuncVarPtg.class, FuncVarEval.class);
+ add(m, GreaterEqualPtg.class, GreaterEqualEval.class);
+ add(m, GreaterThanPtg.class, GreaterThanEval.class);
+ add(m, LessEqualPtg.class, LessEqualEval.class);
+ add(m, LessThanPtg.class, LessThanEval.class);
+ add(m, MultiplyPtg.class, MultiplyEval.class);
+ add(m, NotEqualPtg.class, NotEqualEval.class);
+ add(m, PercentPtg.class, PercentEval.class);
+ add(m, PowerPtg.class, PowerEval.class);
+ add(m, SubtractPtg.class, SubtractEval.class);
+ add(m, UnaryMinusPtg.class, UnaryMinusEval.class);
+ add(m, UnaryPlusPtg.class, UnaryPlusEval.class);
+ return m;
+ }
+
+ private static void add(Map m, Class ptgClass, Class evalClass) {
+
+ // perform some validation now, to keep later exception handlers simple
+ if(!Ptg.class.isAssignableFrom(ptgClass)) {
+ throw new IllegalArgumentException("Expected Ptg subclass");
+ }
+ if(!OperationEval.class.isAssignableFrom(evalClass)) {
+ throw new IllegalArgumentException("Expected OperationEval subclass");
+ }
+ if (!Modifier.isPublic(evalClass.getModifiers())) {
+ throw new RuntimeException("Eval class must be public");
+ }
+ if (Modifier.isAbstract(evalClass.getModifiers())) {
+ throw new RuntimeException("Eval class must not be abstract");
+ }
+
+ Constructor constructor;
+ try {
+ constructor = evalClass.getDeclaredConstructor(OPERATION_CONSTRUCTOR_CLASS_ARRAY);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("Missing constructor");
+ }
+ if (!Modifier.isPublic(constructor.getModifiers())) {
+ throw new RuntimeException("Eval constructor must be public");
+ }
+ m.put(ptgClass, constructor);
+ }
+
+ /**
+ * returns the OperationEval concrete impl instance corresponding
+ * to the supplied operationPtg
+ */
+ public static OperationEval create(OperationPtg ptg) {
+ if(ptg == null) {
+ throw new IllegalArgumentException("ptg must not be null");
+ }
+
+ Class ptgClass = ptg.getClass();
+
+ Constructor constructor = (Constructor) _constructorsByPtgClass.get(ptgClass);
+ if(constructor == null) {
+ if(ptgClass == ExpPtg.class) {
+ // ExpPtg is used for array formulas and shared formulas.
+ // it is currently unsupported, and may not even get implemented here
+ throw new RuntimeException("ExpPtg currently not supported");
+ }
+ throw new RuntimeException("Unexpected operation ptg class (" + ptgClass.getName() + ")");
+ }
+
+ Object result;
+ Object[] initargs = { ptg };
+ try {
+ result = constructor.newInstance(initargs);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ return (OperationEval) result;
+ }
+}
*/
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.
}
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())) {
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,
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.
*
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
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.<p/> The test name contains the
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.<p/>
}
- 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");
}
continue;
}
- HSSFFormulaEvaluator.CellValue actualValue = evaluator.evaluate(c);
+ FormulaEvaluator.CellValue actualValue = evaluator.evaluate(c);
HSSFCell expectedValueCell = getExpectedValueCell(expectedValuesRow, colnum);
try {
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.
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()
*
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;
/**
- 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");
}
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 {