You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ni...@apache.org on 2008/09/07 22:11:34 UTC
svn commit: r692932 [3/4] - in /poi/branches/ooxml: ./
src/documentation/content/xdocs/ src/java/org/apache/poi/ddf/
src/java/org/apache/poi/hssf/model/ src/java/org/apache/poi/hssf/record/
src/java/org/apache/poi/hssf/record/formula/ src/java/org/apac...
Added: poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java?rev=692932&view=auto
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java (added)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java Sun Sep 7 13:11:32 2008
@@ -0,0 +1,184 @@
+/* ====================================================================
+ 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 };
+ // TODO - use singleton instances directly instead of reflection
+ private static final Map _constructorsByPtgClass = initialiseConstructorsMap();
+ private static final Map _instancesByPtgClass = initialiseInstancesMap();
+
+ private OperationEvaluatorFactory() {
+ // no instances of this class
+ }
+
+ private static Map initialiseConstructorsMap() {
+ Map m = new HashMap(32);
+ add(m, ConcatPtg.class, ConcatEval.class);
+ add(m, FuncPtg.class, FuncVarEval.class);
+ add(m, FuncVarPtg.class, FuncVarEval.class);
+ return m;
+ }
+ private static Map initialiseInstancesMap() {
+ Map m = new HashMap(32);
+ add(m, EqualPtg.class, EqualEval.instance);
+ add(m, GreaterEqualPtg.class, GreaterEqualEval.instance);
+ add(m, GreaterThanPtg.class, GreaterThanEval.instance);
+ add(m, LessEqualPtg.class, LessEqualEval.instance);
+ add(m, LessThanPtg.class, LessThanEval.instance);
+ add(m, NotEqualPtg.class, NotEqualEval.instance);
+
+ add(m, AddPtg.class, AddEval.instance);
+ add(m, DividePtg.class, DivideEval.instance);
+ add(m, MultiplyPtg.class, MultiplyEval.instance);
+ add(m, PercentPtg.class, PercentEval.instance);
+ add(m, PowerPtg.class, PowerEval.instance);
+ add(m, SubtractPtg.class, SubtractEval.instance);
+ add(m, UnaryMinusPtg.class, UnaryMinusEval.instance);
+ add(m, UnaryPlusPtg.class, UnaryPlusEval.instance);
+ return m;
+ }
+
+ private static void add(Map m, Class ptgClass, OperationEval evalInstance) {
+ if(!Ptg.class.isAssignableFrom(ptgClass)) {
+ throw new IllegalArgumentException("Expected Ptg subclass");
+ }
+ m.put(ptgClass, evalInstance);
+ }
+
+ 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");
+ }
+ Object result;
+
+ Class ptgClass = ptg.getClass();
+
+ result = _instancesByPtgClass.get(ptgClass);
+ if (result != null) {
+ return (OperationEval) result;
+ }
+
+
+ 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[] 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;
+ }
+}
Propchange: poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java
------------------------------------------------------------------------------
svn:executable = *
Added: poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/EvaluationCache.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/EvaluationCache.java?rev=692932&view=auto
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/EvaluationCache.java (added)
+++ poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/EvaluationCache.java Sun Sep 7 13:11:32 2008
@@ -0,0 +1,95 @@
+/* ====================================================================
+ 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.HashMap;
+import java.util.Map;
+
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * Performance optimisation for {@link HSSFFormulaEvaluator}. This class stores previously
+ * calculated values of already visited cells, to avoid unnecessary re-calculation when the
+ * same cells are referenced multiple times
+ *
+ *
+ * @author Josh Micich
+ */
+final class EvaluationCache {
+ private static final class Key {
+
+ private final int _sheetIndex;
+ private final int _srcRowNum;
+ private final int _srcColNum;
+ private final int _hashCode;
+
+ public Key(int sheetIndex, int srcRowNum, int srcColNum) {
+ _sheetIndex = sheetIndex;
+ _srcRowNum = srcRowNum;
+ _srcColNum = srcColNum;
+ _hashCode = sheetIndex + srcRowNum + srcColNum;
+ }
+
+ public int hashCode() {
+ return _hashCode;
+ }
+
+ public boolean equals(Object obj) {
+ Key other = (Key) obj;
+ if (_hashCode != other._hashCode) {
+ return false;
+ }
+ if (_sheetIndex != other._sheetIndex) {
+ return false;
+ }
+ if (_srcRowNum != other._srcRowNum) {
+ return false;
+ }
+ if (_srcColNum != other._srcColNum) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ private final Map _valuesByKey;
+
+ /* package */EvaluationCache() {
+ _valuesByKey = new HashMap();
+ }
+
+ public ValueEval getValue(int sheetIndex, int srcRowNum, int srcColNum) {
+ Key key = new Key(sheetIndex, srcRowNum, srcColNum);
+ return (ValueEval) _valuesByKey.get(key);
+ }
+
+ public void setValue(int sheetIndex, int srcRowNum, int srcColNum, ValueEval value) {
+ Key key = new Key(sheetIndex, srcRowNum, srcColNum);
+ if (_valuesByKey.containsKey(key)) {
+ throw new RuntimeException("Already have cached value for this cell");
+ }
+ _valuesByKey.put(key, value);
+ }
+
+ /**
+ * Should be called whenever there are changes to input cells in the evaluated workbook.
+ */
+ public void clear() {
+ _valuesByKey.clear();
+ }
+}
Propchange: poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/EvaluationCache.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java Sun Sep 7 13:11:32 2008
@@ -20,7 +20,11 @@
import java.util.Iterator;
import java.util.Stack;
+import org.apache.poi.ss.util.AreaReference;
+import org.apache.poi.ss.util.CellReference;
+
import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.record.NameRecord;
import org.apache.poi.hssf.record.formula.Area3DPtg;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.BoolPtg;
@@ -56,17 +60,64 @@
import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
+ * Evaluates formula cells.<p/>
+ *
+ * For performance reasons, this class keeps a cache of all previously calculated intermediate
+ * cell values. Be sure to call {@link #clearCache()} if any workbook cells are changed between
+ * calls to evaluate~ methods on this class.
+ *
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
+ * @author Josh Micich
*/
public class FormulaEvaluator {
+ /**
+ * used to track the number of evaluations
+ */
+ private static final class Counter {
+ public int value;
+ public Counter() {
+ value = 0;
+ }
+ }
protected Sheet _sheet;
protected Workbook _workbook;
+ private final EvaluationCache _cache;
+
+ private Counter _evaluationCounter;
+
public FormulaEvaluator(Sheet sheet, Workbook workbook) {
+ this(sheet, workbook, new EvaluationCache(), new Counter());
+ }
+
+ private FormulaEvaluator(Sheet sheet, Workbook workbook, EvaluationCache cache, Counter evaluationCounter) {
_sheet = sheet;
_workbook = workbook;
+ _cache = cache;
+ _evaluationCounter = evaluationCounter;
+ }
+
+ /**
+ * for debug use. Used in toString methods
+ */
+ public String getSheetName(Sheet sheet) {
+ return _workbook.getSheetName(_workbook.getSheetIndex(sheet));
+ }
+ /**
+ * for debug/test use
+ */
+ public int getEvaluationCount() {
+ return _evaluationCounter.value;
+ }
+
+ private static boolean isDebugLogEnabled() {
+ return false;
+ }
+ private static void logDebug(String s) {
+ if (isDebugLogEnabled()) {
+ System.out.println(s);
+ }
}
/**
@@ -75,6 +126,18 @@
*/
public void setCurrentRow(Row row) {
// do nothing
+ if (false) {
+ row.getClass(); // suppress unused parameter compiler warning
+ }
+ }
+
+ /**
+ * Should be called whenever there are changes to input cells in the evaluated workbook.
+ * Failure to call this method after changing cell values will cause incorrect behaviour
+ * of the evaluate~ methods of this class
+ */
+ public void clearCache() {
+ _cache.clear();
}
@@ -102,7 +165,7 @@
retval.setErrorValue(cell.getErrorCellValue());
break;
case Cell.CELL_TYPE_FORMULA:
- retval = getCellValueForEval(internalEvaluate(cell, _sheet, _workbook), _workbook.getCreationHelper());
+ retval = getCellValueForEval(internalEvaluate(cell, _sheet), _workbook.getCreationHelper());
break;
case Cell.CELL_TYPE_NUMERIC:
retval = new CellValue(Cell.CELL_TYPE_NUMERIC, _workbook.getCreationHelper());
@@ -140,7 +203,7 @@
if (cell != null) {
switch (cell.getCellType()) {
case Cell.CELL_TYPE_FORMULA:
- CellValue cv = getCellValueForEval(internalEvaluate(cell, _sheet, _workbook), _workbook.getCreationHelper());
+ CellValue cv = getCellValueForEval(internalEvaluate(cell, _sheet), _workbook.getCreationHelper());
switch (cv.getCellType()) {
case Cell.CELL_TYPE_BOOLEAN:
cell.setCellValue(cv.getBooleanValue());
@@ -185,7 +248,7 @@
if (cell != null) {
switch (cell.getCellType()) {
case Cell.CELL_TYPE_FORMULA:
- CellValue cv = getCellValueForEval(internalEvaluate(cell, _sheet, _workbook), _workbook.getCreationHelper());
+ CellValue cv = getCellValueForEval(internalEvaluate(cell, _sheet), _workbook.getCreationHelper());
switch (cv.getCellType()) {
case Cell.CELL_TYPE_BOOLEAN:
cell.setCellType(Cell.CELL_TYPE_BOOLEAN);
@@ -283,26 +346,40 @@
* else a runtime exception will be thrown somewhere inside the method.
* (Hence this is a private method.)
*/
- private static ValueEval internalEvaluate(Cell srcCell, Sheet sheet, Workbook workbook) {
+ private ValueEval internalEvaluate(Cell srcCell, Sheet sheet) {
int srcRowNum = srcCell.getRowIndex();
- short srcColNum = srcCell.getCellNum();
+ int srcColNum = srcCell.getCellNum();
+ ValueEval result;
+
+ int sheetIndex = _workbook.getSheetIndex(sheet);
+ result = _cache.getValue(sheetIndex, srcRowNum, srcColNum);
+ if (result != null) {
+ return result;
+ }
+ _evaluationCounter.value++;
EvaluationCycleDetector tracker = EvaluationCycleDetectorManager.getTracker();
- if(!tracker.startEvaluate(workbook, sheet, srcRowNum, srcColNum)) {
+ if(!tracker.startEvaluate(_workbook, sheet, srcRowNum, srcColNum)) {
return ErrorEval.CIRCULAR_REF_ERROR;
}
try {
- return evaluateCell(workbook, sheet, srcRowNum, srcColNum, srcCell.getCellFormula());
+ result = evaluateCell(srcRowNum, (short)srcColNum, srcCell.getCellFormula());
} finally {
- tracker.endEvaluate(workbook, sheet, srcRowNum, srcColNum);
+ tracker.endEvaluate(_workbook, sheet, srcRowNum, srcColNum);
+ _cache.setValue(sheetIndex, srcRowNum, srcColNum, result);
}
+ if (isDebugLogEnabled()) {
+ String sheetName = _workbook.getSheetName(sheetIndex);
+ CellReference cr = new CellReference(srcRowNum, srcColNum);
+ logDebug("Evaluated " + sheetName + "!" + cr.formatAsString() + " to " + result.toString());
+ }
+ return result;
}
- private static ValueEval evaluateCell(Workbook workbook, Sheet sheet,
- int srcRowNum, short srcColNum, String cellFormulaText) {
+ private ValueEval evaluateCell(int srcRowNum, short srcColNum, String cellFormulaText) {
- Ptg[] ptgs = FormulaParser.parse(cellFormulaText, workbook);
+ Ptg[] ptgs = FormulaParser.parse(cellFormulaText, _workbook);
Stack stack = new Stack();
for (int i = 0, iSize = ptgs.length; i < iSize; i++) {
@@ -314,19 +391,10 @@
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) {
- NameXPtg nameXPtg = (NameXPtg) ptg;
- stack.push(new NameXEval(nameXPtg.getSheetRefIndex(), nameXPtg.getNameIndex()));
- continue;
+ if (ptg instanceof MissingArgPtg) {
+ // TODO - might need to push BlankEval or MissingArgEval
+ continue;
}
- if (ptg instanceof UnknownPtg) { continue; }
Eval opResult;
if (ptg instanceof OperationPtg) {
OperationPtg optg = (OperationPtg) ptg;
@@ -343,10 +411,15 @@
Eval p = (Eval) stack.pop();
ops[j] = p;
}
- opResult = invokeOperation(operation, ops, srcRowNum, srcColNum, workbook, sheet);
+ logDebug("invoke " + operation + " (nAgs=" + numops + ")");
+ opResult = invokeOperation(operation, ops, srcRowNum, srcColNum, _workbook, _sheet);
} else {
- opResult = getEvalForPtg(ptg, sheet, workbook);
+ opResult = getEvalForPtg(ptg, _sheet);
}
+ if (opResult == null) {
+ throw new RuntimeException("Evaluation result must not be null");
+ }
+ logDebug("push " + opResult);
stack.push(opResult);
}
@@ -403,28 +476,63 @@
return operation.evaluate(ops, srcRowNum, srcColNum);
}
+ private Sheet getOtherSheet(int externSheetIndex) {
+ return _workbook.getSheetAt(_workbook.getSheetIndexFromExternSheetIndex(externSheetIndex));
+ }
+ private FormulaEvaluator createEvaluatorForAnotherSheet(Sheet sheet) {
+ return new FormulaEvaluator(sheet, _workbook, _cache, _evaluationCounter);
+ }
+
/**
* 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!
*/
- private static Eval getEvalForPtg(Ptg ptg, Sheet sheet, Workbook workbook) {
+ private Eval getEvalForPtg(Ptg ptg, Sheet sheet) {
+ if (ptg instanceof NamePtg) {
+ // named ranges, macro functions
+ NamePtg namePtg = (NamePtg) ptg;
+ int numberOfNames = _workbook.getNumberOfNames();
+ int nameIndex = namePtg.getIndex();
+ if(nameIndex < 0 || nameIndex >= numberOfNames) {
+ throw new RuntimeException("Bad name index (" + nameIndex
+ + "). Allowed range is (0.." + (numberOfNames-1) + ")");
+ }
+ if(_workbook instanceof org.apache.poi.hssf.usermodel.HSSFWorkbook) {
+ org.apache.poi.hssf.usermodel.HSSFWorkbook hssfWb =
+ (org.apache.poi.hssf.usermodel.HSSFWorkbook)_workbook;
+ NameRecord nameRecord = hssfWb.getNameRecord(nameIndex);
+ if (nameRecord.isFunctionName()) {
+ return new NameEval(nameRecord.getNameText());
+ }
+ if (nameRecord.hasFormula()) {
+ return evaluateNameFormula(nameRecord.getNameDefinition(), sheet);
+ }
+ throw new RuntimeException("Don't know how to evalate name '" + nameRecord.getNameText() + "'");
+ } else {
+ throw new RuntimeException("Don't know how to evaluate name records for XSSF");
+ }
+ }
+ if (ptg instanceof NameXPtg) {
+ NameXPtg nameXPtg = (NameXPtg) ptg;
+ return new NameXEval(nameXPtg.getSheetRefIndex(), nameXPtg.getNameIndex());
+ }
if (ptg instanceof RefPtg) {
- return new LazyRefEval(((RefPtg) ptg), sheet, workbook);
+ return new LazyRefEval(((RefPtg) ptg), sheet, this);
}
if (ptg instanceof Ref3DPtg) {
Ref3DPtg refPtg = (Ref3DPtg) ptg;
- Sheet xsheet = workbook.getSheetAt(workbook.getSheetIndexFromExternSheetIndex(refPtg.getExternSheetIndex()));
- return new LazyRefEval(refPtg, xsheet, workbook);
+ Sheet xsheet = getOtherSheet(refPtg.getExternSheetIndex());
+ return new LazyRefEval(refPtg, xsheet, createEvaluatorForAnotherSheet(xsheet));
}
if (ptg instanceof AreaPtg) {
- return new LazyAreaEval(((AreaPtg) ptg), sheet, workbook);
+ return new LazyAreaEval(((AreaPtg) ptg), sheet, this);
}
if (ptg instanceof Area3DPtg) {
Area3DPtg a3dp = (Area3DPtg) ptg;
- Sheet xsheet = workbook.getSheetAt(workbook.getSheetIndexFromExternSheetIndex(a3dp.getExternSheetIndex()));
- return new LazyAreaEval(a3dp, xsheet, workbook);
+ Sheet xsheet = getOtherSheet(a3dp.getExternSheetIndex());
+ return new LazyAreaEval(a3dp, xsheet, createEvaluatorForAnotherSheet(xsheet));
}
if (ptg instanceof IntPtg) {
@@ -442,8 +550,19 @@
if (ptg instanceof ErrPtg) {
return ErrorEval.valueOf(((ErrPtg) ptg).getErrorCode());
}
+ if (ptg instanceof UnknownPtg) {
+ // TODO - remove UnknownPtg
+ throw new RuntimeException("UnknownPtg not allowed");
+ }
throw new RuntimeException("Unexpected ptg class (" + ptg.getClass().getName() + ")");
}
+ private Eval evaluateNameFormula(Ptg[] ptgs, Sheet sheet) {
+ if (ptgs.length > 1) {
+ throw new RuntimeException("Complex name formulas not supported yet");
+ }
+ return getEvalForPtg(ptgs[0], sheet);
+ }
+
/**
* 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
@@ -453,7 +572,7 @@
* @param sheet
* @param workbook
*/
- public static ValueEval getEvalForCell(Cell cell, Sheet sheet, Workbook workbook) {
+ public ValueEval getEvalForCell(Cell cell, Sheet sheet) {
if (cell == null) {
return BlankEval.INSTANCE;
@@ -464,7 +583,7 @@
case Cell.CELL_TYPE_STRING:
return new StringEval(cell.getRichStringCellValue().getString());
case Cell.CELL_TYPE_FORMULA:
- return internalEvaluate(cell, sheet, workbook);
+ return internalEvaluate(cell, sheet);
case Cell.CELL_TYPE_BOOLEAN:
return BoolEval.valueOf(cell.getBooleanCellValue());
case Cell.CELL_TYPE_BLANK:
Modified: poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/OperationEvaluatorFactory.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/OperationEvaluatorFactory.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/OperationEvaluatorFactory.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/OperationEvaluatorFactory.java Sun Sep 7 13:11:32 2008
@@ -69,8 +69,9 @@
*/
final class OperationEvaluatorFactory {
private static final Class[] OPERATION_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
-
+ // TODO - use singleton instances directly instead of reflection
private static final Map _constructorsByPtgClass = initialiseConstructorsMap();
+ private static final Map _instancesByPtgClass = initialiseInstancesMap();
private OperationEvaluatorFactory() {
// no instances of this class
@@ -78,32 +79,44 @@
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 Map initialiseInstancesMap() {
+ Map m = new HashMap(32);
+ add(m, EqualPtg.class, EqualEval.instance);
+ add(m, GreaterEqualPtg.class, GreaterEqualEval.instance);
+ add(m, GreaterThanPtg.class, GreaterThanEval.instance);
+ add(m, LessEqualPtg.class, LessEqualEval.instance);
+ add(m, LessThanPtg.class, LessThanEval.instance);
+ add(m, NotEqualPtg.class, NotEqualEval.instance);
+
+ add(m, AddPtg.class, AddEval.instance);
+ add(m, DividePtg.class, DivideEval.instance);
+ add(m, MultiplyPtg.class, MultiplyEval.instance);
+ add(m, PercentPtg.class, PercentEval.instance);
+ add(m, PowerPtg.class, PowerEval.instance);
+ add(m, SubtractPtg.class, SubtractEval.instance);
+ add(m, UnaryMinusPtg.class, UnaryMinusEval.instance);
+ add(m, UnaryPlusPtg.class, UnaryPlusEval.instance);
+ return m;
+ }
+
+ private static void add(Map m, Class ptgClass, OperationEval evalInstance) {
+ if(!Ptg.class.isAssignableFrom(ptgClass)) {
+ throw new IllegalArgumentException("Expected Ptg subclass");
+ }
+ m.put(ptgClass, evalInstance);
+ }
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");
}
@@ -125,7 +138,7 @@
}
m.put(ptgClass, constructor);
}
-
+
/**
* returns the OperationEval concrete impl instance corresponding
* to the supplied operationPtg
@@ -134,9 +147,16 @@
if(ptg == null) {
throw new IllegalArgumentException("ptg must not be null");
}
+ Object result;
Class ptgClass = ptg.getClass();
+ result = _instancesByPtgClass.get(ptgClass);
+ if (result != null) {
+ return (OperationEval) result;
+ }
+
+
Constructor constructor = (Constructor) _constructorsByPtgClass.get(ptgClass);
if(constructor == null) {
if(ptgClass == ExpPtg.class) {
@@ -147,7 +167,6 @@
throw new RuntimeException("Unexpected operation ptg class (" + ptgClass.getName() + ")");
}
- Object result;
Object[] initargs = { ptg };
try {
result = constructor.newInstance(initargs);
Modified: poi/branches/ooxml/src/java/org/apache/poi/ss/util/AreaReference.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/ss/util/AreaReference.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/ss/util/AreaReference.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/ss/util/AreaReference.java Sun Sep 7 13:11:32 2008
@@ -46,29 +46,59 @@
}
String[] parts = separateAreaRefs(reference);
+ String part0 = parts[0];
+ if (parts.length == 1) {
+ // TODO - probably shouldn't initialize area ref when text is really a cell ref
+ // Need to fix some named range stuff to get rid of this
+ _firstCell = new CellReference(part0);
+
+ _lastCell = _firstCell;
+ _isSingleCell = true;
+ return;
+ }
+ if (parts.length != 2) {
+ throw new IllegalArgumentException("Bad area ref '" + reference + "'");
+ }
- // Special handling for whole-column references
- if(parts.length == 2 && parts[0].length() == 1 &&
- parts[1].length() == 1 &&
- parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' &&
- parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') {
+ String part1 = parts[1];
+ if (isPlainColumn(part0)) {
+ if (!isPlainColumn(part1)) {
+ throw new RuntimeException("Bad area ref '" + reference + "'");
+ }
+ // Special handling for whole-column references
// Represented internally as x$1 to x$65536
// which is the maximum range of rows
- parts[0] = parts[0] + "$1";
- parts[1] = parts[1] + "$65536";
- }
-
- _firstCell = new CellReference(parts[0]);
-
- if(parts.length == 2) {
- _lastCell = new CellReference(parts[1]);
+
+ boolean firstIsAbs = CellReference.isPartAbsolute(part0);
+ boolean lastIsAbs = CellReference.isPartAbsolute(part1);
+
+ int col0 = CellReference.convertColStringToIndex(part0);
+ int col1 = CellReference.convertColStringToIndex(part1);
+
+ _firstCell = new CellReference(0, col0, true, firstIsAbs);
+ _lastCell = new CellReference(0xFFFF, col1, true, lastIsAbs);
_isSingleCell = false;
+ // TODO - whole row refs
} else {
- _lastCell = _firstCell;
- _isSingleCell = true;
+ _firstCell = new CellReference(part0);
+ _lastCell = new CellReference(part1);
+ _isSingleCell = part0.equals(part1);
+ }
+ }
+
+ private boolean isPlainColumn(String refPart) {
+ for(int i=refPart.length()-1; i>=0; i--) {
+ int ch = refPart.charAt(i);
+ if (ch == '$' && i==0) {
+ continue;
+ }
+ if (ch < 'A' || ch > 'Z') {
+ return false;
+ }
}
+ return true;
}
-
+
/**
* Creates an area ref from a pair of Cell References.
*/
Modified: poi/branches/ooxml/src/java/org/apache/poi/ss/util/CellReference.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/ss/util/CellReference.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/ss/util/CellReference.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/ss/util/CellReference.java Sun Sep 7 13:11:32 2008
@@ -80,7 +80,7 @@
if (_isColAbs) {
colRef=colRef.substring(1);
}
- _colIndex = convertColStringToNum(colRef);
+ _colIndex = convertColStringToIndex(colRef);
String rowRef=parts[2];
if (rowRef.length() < 1) {
@@ -94,7 +94,7 @@
}
public CellReference(int pRow, int pCol) {
- this(pRow, pCol, false, false);
+ this(pRow, pCol & 0xFFFF, false, false);
}
public CellReference(int pRow, short pCol) {
this(pRow, (int)pCol, false, false);
@@ -130,18 +130,31 @@
public String getSheetName(){
return _sheetName;
}
-
+
+ public static boolean isPartAbsolute(String part) {
+ return part.charAt(0) == ABSOLUTE_REFERENCE_MARKER;
+ }
+
/**
* takes in a column reference portion of a CellRef and converts it from
* ALPHA-26 number format to 0-based base 10.
+ * 'A' -> 0
+ * 'Z' -> 25
+ * 'AA' -> 26
+ * 'IV' -> 255
+ * @return zero based column index
*/
- private int convertColStringToNum(String ref) {
- int lastIx = ref.length()-1;
- int retval=0;
- int pos = 0;
-
- for (int k = lastIx; k > -1; k--) {
+ protected static int convertColStringToIndex(String ref) {
+ int pos = 0;
+ int retval=0;
+ for (int k = ref.length()-1; k >= 0; k--) {
char thechar = ref.charAt(k);
+ if (thechar == ABSOLUTE_REFERENCE_MARKER) {
+ if (k != 0) {
+ throw new IllegalArgumentException("Bad col ref format '" + ref + "'");
+ }
+ break;
+ }
// Character.getNumericValue() returns the values
// 10-35 for the letter A-Z
int shift = (int)Math.pow(26, pos);
Modified: poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/record/Document.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/record/Document.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/record/Document.java (original)
+++ poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/record/Document.java Sun Sep 7 13:11:32 2008
@@ -71,27 +71,44 @@
* This will normally return an array of size 2 or 3
*/
public SlideListWithText[] getSlideListWithTexts() { return slwts; }
- /**
+
+ /**
* Returns the SlideListWithText that deals with the
* Master Slides
*/
public SlideListWithText getMasterSlideListWithText() {
- if(slwts.length > 0) { return slwts[0]; }
- return null; }
+ for (int i = 0; i < slwts.length; i++) {
+ if(slwts[i].getInstance() == SlideListWithText.MASTER) {
+ return slwts[i];
+ }
+ }
+ return null;
+ }
+
/**
* Returns the SlideListWithText that deals with the
* Slides, or null if there isn't one
*/
- public SlideListWithText getSlideSlideListWithText() {
- if(slwts.length > 1) { return slwts[1]; }
- return null; }
+ public SlideListWithText getSlideSlideListWithText() {
+ for (int i = 0; i < slwts.length; i++) {
+ if(slwts[i].getInstance() == SlideListWithText.SLIDES) {
+ return slwts[i];
+ }
+ }
+ return null;
+ }
/**
* Returns the SlideListWithText that deals with the
* notes, or null if there isn't one
*/
public SlideListWithText getNotesSlideListWithText() {
- if(slwts.length > 2) { return slwts[2]; }
- return null; }
+ for (int i = 0; i < slwts.length; i++) {
+ if(slwts[i].getInstance() == SlideListWithText.NOTES) {
+ return slwts[i];
+ }
+ }
+ return null;
+ }
/**
Modified: poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/record/RecordContainer.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/record/RecordContainer.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/record/RecordContainer.java (original)
+++ poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/record/RecordContainer.java Sun Sep 7 13:11:32 2008
@@ -243,8 +243,16 @@
moveChildRecords(oldLoc, newLoc, number);
}
}
-
-
+
+ /**
+ * Set child records.
+ *
+ * @param records the new child records
+ */
+ public void setChildRecord(Record[] records) {
+ this._children = records;
+ }
+
/* ===============================================================
* External Serialisation Methods
* ===============================================================
Modified: poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/record/SlideListWithText.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/record/SlideListWithText.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/record/SlideListWithText.java (original)
+++ poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/record/SlideListWithText.java Sun Sep 7 13:11:32 2008
@@ -50,7 +50,24 @@
// For now, pretend to be an atom
public class SlideListWithText extends RecordContainer
{
- private byte[] _header;
+
+ /**
+ * Instance filed of the record header indicates that this SlideListWithText stores
+ * references to slides
+ */
+ public static final int SLIDES = 0;
+ /**
+ * Instance filed of the record header indicates that this SlideListWithText stores
+ * references to master slides
+ */
+ public static final int MASTER = 1;
+ /**
+ * Instance filed of the record header indicates that this SlideListWithText stores
+ * references to notes
+ */
+ public static final int NOTES = 2;
+
+ private byte[] _header;
private static long _type = 4080;
private SlideAtomsSet[] slideAtomsSets;
@@ -123,9 +140,9 @@
public void addSlidePersistAtom(SlidePersistAtom spa) {
// Add the new SlidePersistAtom at the end
appendChildRecord(spa);
-
+
SlideAtomsSet newSAS = new SlideAtomsSet(spa, new Record[0]);
-
+
// Update our SlideAtomsSets with this
SlideAtomsSet[] sas = new SlideAtomsSet[slideAtomsSets.length+1];
System.arraycopy(slideAtomsSets, 0, sas, 0, slideAtomsSets.length);
@@ -133,7 +150,15 @@
slideAtomsSets = sas;
}
- /**
+ public int getInstance(){
+ return LittleEndian.getShort(_header, 0) >> 4;
+ }
+
+ public void setInstance(int inst){
+ LittleEndian.putShort(_header, (short)((inst << 4) | 0xF));
+ }
+
+ /**
* Get access to the SlideAtomsSets of the children of this record
*/
public SlideAtomsSet[] getSlideAtomsSets() { return slideAtomsSets; }
@@ -152,35 +177,6 @@
}
/**
- * Shifts a SlideAtomsSet to a new position.
- * Works by shifting the child records about, then updating
- * the SlideAtomSets array
- * @param toMove The SlideAtomsSet to move
- * @param newPosition The new (0 based) position for the SlideAtomsSet
- */
- public void repositionSlideAtomsSet(SlideAtomsSet toMove, int newPosition) {
- // Ensure it's one of ours
- int curPos = -1;
- for(int i=0; i<slideAtomsSets.length; i++) {
- if(slideAtomsSets[i] == toMove) { curPos = i; }
- }
- if(curPos == -1) {
- throw new IllegalArgumentException("The supplied SlideAtomsSet didn't belong to this SlideListWithText");
- }
-
- // Ensure the newPosision is valid
- if(newPosition < 0 || newPosition >= slideAtomsSets.length) {
- throw new IllegalArgumentException("The new position must be between 0, and the number of SlideAtomsSets");
- }
-
- // Build the new records list
- moveChildrenBefore(toMove.getSlidePersistAtom(), toMove.slideRecords.length, slideAtomsSets[newPosition].getSlidePersistAtom());
-
- // Build the new SlideAtomsSets list
- ArrayUtil.arrayMoveWithin(slideAtomsSets, curPos, newPosition, 1);
- }
-
- /**
* Inner class to wrap up a matching set of records that hold the
* text for a given sheet. Contains the leading SlidePersistAtom,
* and all of the records until the next SlidePersistAtom. This
Modified: poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java (original)
+++ poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java Sun Sep 7 13:11:32 2008
@@ -536,32 +536,37 @@
/**
* Re-orders a slide, to a new position.
- * @param oldSlideNumer The old slide number (1 based)
+ * @param oldSlideNumber The old slide number (1 based)
* @param newSlideNumber The new slide number (1 based)
*/
- public void reorderSlide(int oldSlideNumer, int newSlideNumber) {
+ public void reorderSlide(int oldSlideNumber, int newSlideNumber) {
// Ensure these numbers are valid
- if(oldSlideNumer < 1 || newSlideNumber < 1) {
+ if(oldSlideNumber < 1 || newSlideNumber < 1) {
throw new IllegalArgumentException("Old and new slide numbers must be greater than 0");
}
- if(oldSlideNumer > _slides.length || newSlideNumber > _slides.length) {
+ if(oldSlideNumber > _slides.length || newSlideNumber > _slides.length) {
throw new IllegalArgumentException("Old and new slide numbers must not exceed the number of slides (" + _slides.length + ")");
}
-
- // Shift the SlideAtomsSet
- SlideListWithText slwt = _documentRecord.getSlideSlideListWithText();
- slwt.repositionSlideAtomsSet(
- slwt.getSlideAtomsSets()[(oldSlideNumer-1)],
- (newSlideNumber-1)
- );
-
- // Re-order the slides
- ArrayUtil.arrayMoveWithin(_slides, (oldSlideNumer-1), (newSlideNumber-1), 1);
-
- // Tell the appropriate slides their new numbers
- for(int i=0; i<_slides.length; i++) {
- _slides[i].setSlideNumber( (i+1) );
- }
+
+ // The order of slides is defined by the order of slide atom sets in the SlideListWithText container.
+ SlideListWithText slwt = _documentRecord.getSlideSlideListWithText();
+ SlideAtomsSet[] sas = slwt.getSlideAtomsSets();
+
+ SlideAtomsSet tmp = sas[oldSlideNumber-1];
+ sas[oldSlideNumber-1] = sas[newSlideNumber-1];
+ sas[newSlideNumber-1] = tmp;
+
+ ArrayList lst = new ArrayList();
+ for (int i = 0; i < sas.length; i++) {
+ lst.add(sas[i].getSlidePersistAtom());
+ Record[] r = sas[i].getSlideRecords();
+ for (int j = 0; j < r.length; j++) {
+ lst.add(r[j]);
+ }
+ _slides[i].setSlideNumber(i+1);
+ }
+ Record[] r = (Record[])lst.toArray(new Record[lst.size()]);
+ slwt.setChildRecord(r);
}
/* ===============================================================
@@ -585,7 +590,8 @@
if(slist == null) {
// Need to add a new one
slist = new SlideListWithText();
- _documentRecord.addSlideListWithText(slist);
+ slist.setInstance(SlideListWithText.SLIDES);
+ _documentRecord.addSlideListWithText(slist);
}
// Grab the SlidePersistAtom with the highest Slide Number.
@@ -678,11 +684,11 @@
ptr.addSlideLookup(sp.getRefID(), slideOffset);
logger.log(POILogger.INFO, "New slide ended up at " + slideOffset);
- // All done and added
+ slide.setMasterSheet(_masters[0]);
+ // All done and added
return slide;
}
-
/**
* Adds a picture to this presentation and returns the associated index.
*
Modified: poi/branches/ooxml/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestReOrderingSlides.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestReOrderingSlides.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestReOrderingSlides.java (original)
+++ poi/branches/ooxml/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestReOrderingSlides.java Sun Sep 7 13:11:32 2008
@@ -279,18 +279,23 @@
assertEquals(3, ss_read.getSlides().length);
// And check it's as expected
- s1 = ss_read.getSlides()[0];
- s2 = ss_read.getSlides()[1];
- s3 = ss_read.getSlides()[2];
-
- assertEquals(257, s1._getSheetNumber());
- assertEquals(4, s1._getSheetRefId());
+ Slide _s1 = ss_read.getSlides()[0];
+ Slide _s2 = ss_read.getSlides()[1];
+ Slide _s3 = ss_read.getSlides()[2];
+
+ // 1 --> 3
+ assertEquals(s1._getSheetNumber(), _s3._getSheetNumber());
+ assertEquals(s1._getSheetRefId(), _s3._getSheetRefId());
assertEquals(1, s1.getSlideNumber());
- assertEquals(256, s2._getSheetNumber());
- assertEquals(3, s2._getSheetRefId());
+
+ // 2nd slide is not updated
+ assertEquals(s2._getSheetNumber(), _s2._getSheetNumber());
+ assertEquals(s2._getSheetRefId(), _s2._getSheetRefId());
assertEquals(2, s2.getSlideNumber());
- assertEquals(258, s3._getSheetNumber());
- assertEquals(5, s3._getSheetRefId());
+
+ // 3 --> 1
+ assertEquals(s3._getSheetNumber(), _s1._getSheetNumber());
+ assertEquals(s3._getSheetRefId(), _s1._getSheetRefId());
assertEquals(3, s3.getSlideNumber());
}
}
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
Binary files - no diff available.
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/data/LookupFunctionsTestCaseData.xls
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/data/LookupFunctionsTestCaseData.xls?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
Binary files - no diff available.
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/data/externalFunctionExample.xls
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/data/externalFunctionExample.xls?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
Binary files - no diff available.
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/data/testNames.xls
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/data/testNames.xls?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
Binary files - no diff available.
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/TestExternalFunctionFormulas.java Sun Sep 7 13:11:32 2008
@@ -74,9 +74,18 @@
public void testEvaluate() {
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("externalFunctionExample.xls");
HSSFSheet sheet = wb.getSheetAt(0);
- HSSFCell cell = sheet.getRow(0).getCell(0);
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
- CellValue evalResult = fe.evaluate(cell);
- evalResult.toString();
+ confirmCellEval(sheet, 0, 0, fe, "YEARFRAC(B1,C1)", 29.0/90.0);
+ confirmCellEval(sheet, 1, 0, fe, "YEARFRAC(B2,C2)", 0.0);
+ confirmCellEval(sheet, 2, 0, fe, "IF(ISEVEN(3),1.2,1.6)", 1.6);
+ confirmCellEval(sheet, 3, 0, fe, "IF(ISODD(3),1.2,1.6)", 1.2);
+ }
+
+ private static void confirmCellEval(HSSFSheet sheet, int rowIx, int colIx,
+ HSSFFormulaEvaluator fe, String expectedFormula, double expectedResult) {
+ HSSFCell cell = sheet.getRow(rowIx).getCell(colIx);
+ assertEquals(expectedFormula, cell.getCellFormula());
+ CellValue cv = fe.evaluate(cell);
+ assertEquals(expectedResult, cv.getNumberValue(), 0.0);
}
}
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculator.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculator.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculator.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/atp/TestYearFracCalculator.java Sun Sep 7 13:11:32 2008
@@ -38,6 +38,7 @@
confirm(md(1999, 3, 31), md(1999, 4, 3), 1, 0.008219178);
confirm(md(1999, 4, 5), md(1999, 4, 8), 1, 0.008219178);
confirm(md(1999, 4, 4), md(1999, 4, 7), 1, 0.008219178);
+ confirm(md(2000, 2, 5), md(2000, 6, 1), 0, 0.322222222);
}
private void confirm(double startDate, double endDate, int basis, double expectedValue) {
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/AllFormulaEvalTests.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/AllFormulaEvalTests.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/AllFormulaEvalTests.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/AllFormulaEvalTests.java Sun Sep 7 13:11:32 2008
@@ -31,6 +31,8 @@
TestSuite result = new TestSuite(AllFormulaEvalTests.class.getName());
result.addTestSuite(TestAreaEval.class);
result.addTestSuite(TestCircularReferences.class);
+ result.addTestSuite(TestDivideEval.class);
+ result.addTestSuite(TestEqualEval.class);
result.addTestSuite(TestExternalFunction.class);
result.addTestSuite(TestFormulaBugs.class);
result.addTestSuite(TestFormulasFromSpreadsheet.class);
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/TestCircularReferences.java Sun Sep 7 13:11:32 2008
@@ -93,7 +93,6 @@
HSSFCell testCell = row.createCell(0);
testCell.setCellFormula("A1");
- HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
CellValue cellValue = evaluateWithCycles(wb, sheet, testCell);
confirmCycleErrorCode(cellValue);
@@ -114,7 +113,6 @@
HSSFCell testCell = row.createCell(3);
testCell.setCellFormula("A1");
- HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
CellValue cellValue = evaluateWithCycles(wb, sheet, testCell);
confirmCycleErrorCode(cellValue);
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/TestPercentEval.java Sun Sep 7 13:11:32 2008
@@ -20,7 +20,7 @@
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
-import org.apache.poi.hssf.record.formula.PercentPtg;
+import org.apache.poi.hssf.record.formula.functions.EvalFactory;
import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
@@ -41,8 +41,8 @@
arg,
};
- PercentEval opEval = new PercentEval(PercentPtg.instance);
- double result = NumericFunctionInvoker.invoke(opEval, args, -1, (short)-1);
+ OperationEval opEval = PercentEval.instance;
+ double result = NumericFunctionInvoker.invoke(opEval, args, 0, 0);
assertEquals(expectedResult, result, 0);
}
@@ -55,6 +55,10 @@
confirm(BoolEval.TRUE, 0.01);
}
+ public void test1x1Area() {
+ AreaEval ae = EvalFactory.createAreaEval("B2:B2", new ValueEval[] { new NumberEval(50), });
+ confirm(ae, 0.5);
+ }
public void testInSpreadSheet() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("Sheet1");
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/TestUnaryPlusEval.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/TestUnaryPlusEval.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/TestUnaryPlusEval.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/eval/TestUnaryPlusEval.java Sun Sep 7 13:11:32 2008
@@ -1,27 +1,25 @@
-/*
-* 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.
-*/
-
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
import org.apache.poi.hssf.record.formula.functions.EvalFactory;
import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker;
@@ -53,7 +51,7 @@
EvalFactory.createAreaEval(areaPtg, values),
};
- double result = NumericFunctionInvoker.invoke(new UnaryPlusEval(UnaryPlusPtg.instance), args, 10, (short)20);
+ double result = NumericFunctionInvoker.invoke(UnaryPlusEval.instance, args, 10, (short)20);
assertEquals(35, result, 0);
}
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java Sun Sep 7 13:11:32 2008
@@ -36,6 +36,7 @@
result.addTestSuite(TestIndex.class);
result.addTestSuite(TestIsBlank.class);
result.addTestSuite(TestLen.class);
+ result.addTestSuite(TestLookupFunctionsFromSpreadsheet.class);
result.addTestSuite(TestMid.class);
result.addTestSuite(TestMathX.class);
result.addTestSuite(TestMatch.class);
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDate.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDate.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDate.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/functions/TestDate.java Sun Sep 7 13:11:32 2008
@@ -28,29 +28,29 @@
* @author Pavel Krupets (pkrupets at palmtreebusiness dot com)
*/
public final class TestDate extends TestCase {
-
+
private HSSFCell cell11;
private HSSFFormulaEvaluator evaluator;
public void setUp() {
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("new sheet");
- cell11 = sheet.createRow(0).createCell(0);
+ cell11 = sheet.createRow(0).createCell(0);
cell11.setCellType(HSSFCell.CELL_TYPE_FORMULA);
evaluator = new HSSFFormulaEvaluator(sheet, wb);
}
-
- /**
- * Test disabled pending a fix in the formula evaluator
- * TODO - create MissingArgEval and modify the formula evaluator to handle this
- */
+
+ /**
+ * Test disabled pending a fix in the formula evaluator
+ * TODO - create MissingArgEval and modify the formula evaluator to handle this
+ */
public void DISABLEDtestSomeArgumentsMissing() {
confirm("DATE(, 1, 0)", 0.0);
confirm("DATE(, 1, 1)", 1.0);
}
-
+
public void testValid() {
-
+
confirm("DATE(1900, 1, 1)", 1);
confirm("DATE(1900, 1, 32)", 32);
confirm("DATE(1900, 222, 1)", 6727);
@@ -58,7 +58,7 @@
confirm("DATE(2000, 1, 222)", 36747.00);
confirm("DATE(2007, 1, 1)", 39083);
}
-
+
public void testBugDate() {
confirm("DATE(1900, 2, 29)", 60);
confirm("DATE(1900, 2, 30)", 61);
@@ -66,7 +66,7 @@
confirm("DATE(1900, 1, 2222)", 2222);
confirm("DATE(1900, 1, 22222)", 22222);
}
-
+
public void testPartYears() {
confirm("DATE(4, 1, 1)", 1462.00);
confirm("DATE(14, 1, 1)", 5115.00);
@@ -74,10 +74,11 @@
confirm("DATE(1004, 1, 1)", 366705.00);
}
- private void confirm(String formulaText, double expectedResult) {
+ private void confirm(String formulaText, double expectedResult) {
cell11.setCellFormula(formulaText);
+ evaluator.clearCache();
double actualValue = evaluator.evaluate(cell11).getNumberValue();
- assertEquals(expectedResult, actualValue, 0);
- }
+ assertEquals(expectedResult, actualValue, 0);
+ }
}
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java Sun Sep 7 13:11:32 2008
@@ -46,6 +46,7 @@
result.addTestSuite(TestHSSFConditionalFormatting.class);
result.addTestSuite(TestHSSFDataFormatter.class);
result.addTestSuite(TestHSSFDateUtil.class);
+ result.addTestSuite(TestHSSFFormulaEvaluator.class);
result.addTestSuite(TestHSSFHeaderFooter.class);
result.addTestSuite(TestHSSFHyperlink.class);
result.addTestSuite(TestHSSFOptimiser.class);
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestBugs.java Sun Sep 7 13:11:32 2008
@@ -37,6 +37,7 @@
import org.apache.poi.hssf.record.NameRecord;
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
import org.apache.poi.hssf.record.formula.DeletedArea3DPtg;
+import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.util.TempFile;
/**
@@ -1020,9 +1021,9 @@
NameRecord r = w.getNameRecord(i);
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
- List nd = r.getNameDefinition();
- assertEquals(1, nd.size());
- assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
+ Ptg[] nd = r.getNameDefinition();
+ assertEquals(1, nd.length);
+ assertTrue(nd[0] instanceof DeletedArea3DPtg);
}
@@ -1038,9 +1039,9 @@
NameRecord r = w.getNameRecord(i);
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
- List nd = r.getNameDefinition();
- assertEquals(1, nd.size());
- assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
+ Ptg[] nd = r.getNameDefinition();
+ assertEquals(1, nd.length);
+ assertTrue(nd[0] instanceof DeletedArea3DPtg);
}
@@ -1055,9 +1056,9 @@
NameRecord r = w.getNameRecord(i);
assertTrue(r.getSheetNumber() <= wb.getNumberOfSheets());
- List nd = r.getNameDefinition();
- assertEquals(1, nd.size());
- assertTrue(nd.get(0) instanceof DeletedArea3DPtg);
+ Ptg[] nd = r.getNameDefinition();
+ assertEquals(1, nd.length);
+ assertTrue(nd[0] instanceof DeletedArea3DPtg);
}
}
Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java?rev=692932&r1=692931&r2=692932&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java Sun Sep 7 13:11:32 2008
@@ -19,6 +19,8 @@
import java.io.File;
import java.io.FileOutputStream;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
import java.util.Iterator;
import junit.framework.AssertionFailedError;
@@ -35,6 +37,7 @@
*/
public final class TestFormulaEvaluatorBugs extends TestCase {
+ private static final boolean OUTPUT_TEST_FILES = false;
private String tmpDirName;
protected void setUp() {
@@ -65,13 +68,15 @@
HSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
assertEquals(4.2 * 25, row.getCell(3).getNumericCellValue(), 0.0001);
- // Save
- File existing = new File(tmpDirName, "44636-existing.xls");
- FileOutputStream out = new FileOutputStream(existing);
- wb.write(out);
- out.close();
- System.err.println("Existing file for bug #44636 written to " + existing.toString());
-
+ FileOutputStream out;
+ if (OUTPUT_TEST_FILES) {
+ // Save
+ File existing = new File(tmpDirName, "44636-existing.xls");
+ out = new FileOutputStream(existing);
+ wb.write(out);
+ out.close();
+ System.err.println("Existing file for bug #44636 written to " + existing.toString());
+ }
// Now, do a new file from scratch
wb = new HSSFWorkbook();
sheet = wb.createSheet();
@@ -86,12 +91,14 @@
HSSFFormulaEvaluator.evaluateAllFormulaCells(wb);
assertEquals(5.4, row.getCell(0).getNumericCellValue(), 0.0001);
- // Save
- File scratch = new File(tmpDirName, "44636-scratch.xls");
- out = new FileOutputStream(scratch);
- wb.write(out);
- out.close();
- System.err.println("New file for bug #44636 written to " + scratch.toString());
+ if (OUTPUT_TEST_FILES) {
+ // Save
+ File scratch = new File(tmpDirName, "44636-scratch.xls");
+ out = new FileOutputStream(scratch);
+ wb.write(out);
+ out.close();
+ System.err.println("New file for bug #44636 written to " + scratch.toString());
+ }
}
/**
@@ -281,64 +288,39 @@
}
/**
- * Apparently, each subsequent call takes longer, which is very
- * odd.
- * We think it's because the formulas are recursive and crazy
+ * The HSSFFormula evaluator performance benefits greatly from caching of intermediate cell values
*/
- public void DISABLEDtestSlowEvaluate45376() throws Exception {
- HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("45376.xls");
+ public void testSlowEvaluate45376() {
- final String SHEET_NAME = "Eingabe";
- final int row = 6;
- final HSSFSheet sheet = wb.getSheet(SHEET_NAME);
-
- int firstCol = 4;
- int lastCol = 14;
- long[] timings = new long[lastCol-firstCol+1];
- long[] rtimings = new long[lastCol-firstCol+1];
-
- long then, now;
-
- final HSSFRow excelRow = sheet.getRow(row);
- for(int i = firstCol; i <= lastCol; i++) {
- final HSSFCell excelCell = excelRow.getCell(i);
- final HSSFFormulaEvaluator evaluator = new
- HSSFFormulaEvaluator(sheet, wb);
-
- now = System.currentTimeMillis();
- evaluator.evaluate(excelCell);
- then = System.currentTimeMillis();
- timings[i-firstCol] = (then-now);
- System.err.println("Col " + i + " took " + (then-now) + "ms");
- }
- for(int i = lastCol; i >= firstCol; i--) {
- final HSSFCell excelCell = excelRow.getCell(i);
- final HSSFFormulaEvaluator evaluator = new
- HSSFFormulaEvaluator(sheet, wb);
-
- now = System.currentTimeMillis();
- evaluator.evaluate(excelCell);
- then = System.currentTimeMillis();
- rtimings[i-firstCol] = (then-now);
- System.err.println("Col " + i + " took " + (then-now) + "ms");
- }
-
- // The timings for each should be about the same
- long avg = 0;
- for(int i=0; i<timings.length; i++) {
- avg += timings[i];
- }
- avg = (long)( ((double)avg) / timings.length );
-
- // Warn if any took more then 1.5 the average
- // TODO - replace with assert or similar
- for(int i=0; i<timings.length; i++) {
- if(timings[i] > 1.5*avg) {
- System.err.println("Doing col " + (i+firstCol) +
- " took " + timings[i] + "ms, vs avg " +
- avg + "ms"
- );
- }
- }
+ // Firstly set up a sequence of formula cells where each depends on the previous multiple
+ // times. Without caching, each subsequent cell take about 4 times longer to evaluate.
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.createSheet("Sheet1");
+ HSSFRow row = sheet.createRow(0);
+ for(int i=1; i<10; i++) {
+ HSSFCell cell = row.createCell(i);
+ char prevCol = (char) ('A' + i-1);
+ String prevCell = prevCol + "1";
+ // this formula is inspired by the offending formula of the attachment for bug 45376
+ String formula = "IF(DATE(YEAR(" + prevCell + "),MONTH(" + prevCell + ")+1,1)<=$D$3," +
+ "DATE(YEAR(" + prevCell + "),MONTH(" + prevCell + ")+1,1),NA())";
+ cell.setCellFormula(formula);
+
+ }
+ Calendar cal = new GregorianCalendar(2000, 0, 1, 0, 0, 0);
+ row.createCell(0).setCellValue(cal);
+
+ // Choose cell A9, so that the failing test case doesn't take too long to execute.
+ HSSFCell cell = row.getCell(8);
+ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, wb);
+ evaluator.evaluate(cell);
+ int evalCount = evaluator.getEvaluationCount();
+ // With caching, the evaluationCount is 8 which is a big improvement
+ if (evalCount > 10) {
+ // Without caching, evaluating cell 'A9' takes 21845 evaluations which consumes
+ // much time (~3 sec on Core 2 Duo 2.2GHz)
+ System.err.println("Cell A9 took " + evalCount + " intermediate evaluations");
+ throw new AssertionFailedError("Identifed bug 45376 - Formula evaluator should cache values");
+ }
}
}
\ No newline at end of file
Copied: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java (from r692893, poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java)
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java?p2=poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java&p1=poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java&r1=692893&r2=692932&rev=692932&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java Sun Sep 7 13:11:32 2008
@@ -18,7 +18,7 @@
package org.apache.poi.hssf.usermodel;
import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue;
+import org.apache.poi.ss.usermodel.FormulaEvaluator.CellValue;
import junit.framework.TestCase;
/**
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org