You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by jo...@apache.org on 2008/10/09 09:20:47 UTC

svn commit: r703083 - in /poi/branches/ooxml: ./ src/java/org/apache/poi/hssf/usermodel/ src/java/org/apache/poi/ss/formula/ src/java/org/apache/poi/ss/usermodel/ src/ooxml/java/org/apache/poi/xssf/usermodel/ src/testcases/org/apache/poi/hssf/usermodel...

Author: josh
Date: Thu Oct  9 00:20:46 2008
New Revision: 703083

URL: http://svn.apache.org/viewvc?rev=703083&view=rev
Log:
Merged revisions 703063 via svnmerge from 
https://svn.apache.org/repos/asf/poi/trunk

........
  r703063 | josh | 2008-10-08 23:07:36 -0700 (Wed, 08 Oct 2008) | 1 line
  
  Performance optimisation for EvaluationCache.  Changed to use HSSFCell as key into cache entry map.  Reduced dependency information storage for blank cells.  Introduced EvaluationSheet and EvaluationCell interfaces.  Modified HSSFFormulaEvaluator API to have simpler notify~ methods
........

Added:
    poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationCell.java
      - copied unchanged from r703063, poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationCell.java
    poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationSheet.java
      - copied unchanged from r703063, poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationSheet.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationCell.java
      - copied unchanged from r703063, poi/trunk/src/java/org/apache/poi/ss/formula/EvaluationCell.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationSheet.java
      - copied unchanged from r703063, poi/trunk/src/java/org/apache/poi/ss/formula/EvaluationSheet.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/FormulaCellCache.java
      - copied unchanged from r703063, poi/trunk/src/java/org/apache/poi/ss/formula/FormulaCellCache.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/FormulaCellCacheEntry.java
      - copied unchanged from r703063, poi/trunk/src/java/org/apache/poi/ss/formula/FormulaCellCacheEntry.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/FormulaCellCacheEntrySet.java
      - copied unchanged from r703063, poi/trunk/src/java/org/apache/poi/ss/formula/FormulaCellCacheEntrySet.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/FormulaUsedBlankCellSet.java
      - copied unchanged from r703063, poi/trunk/src/java/org/apache/poi/ss/formula/FormulaUsedBlankCellSet.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/PlainCellCache.java
      - copied unchanged from r703063, poi/trunk/src/java/org/apache/poi/ss/formula/PlainCellCache.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/PlainValueCellCacheEntry.java
      - copied unchanged from r703063, poi/trunk/src/java/org/apache/poi/ss/formula/PlainValueCellCacheEntry.java
    poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationCell.java
    poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationSheet.java
    poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/HSSFEvaluationTestHelper.java
      - copied unchanged from r703063, poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/HSSFEvaluationTestHelper.java
Removed:
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/CellLocation.java
Modified:
    poi/branches/ooxml/   (props changed)
    poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
    poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/CellCacheEntry.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/CellEvaluationFrame.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationCache.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationTracker.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/IEvaluationListener.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/SheetRefEvaluator.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
    poi/branches/ooxml/src/java/org/apache/poi/ss/usermodel/FormulaEvaluator.java
    poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java
    poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java
    poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestFormulaEvaluatorBugs.java
    poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/EvaluationListener.java
    poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestCellCacheEntry.java
    poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java
    poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java

Propchange: poi/branches/ooxml/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Oct  9 00:20:46 2008
@@ -1 +1 @@
-/poi/trunk:693591-694881,695264-695420,695621,695649-702231
+/poi/trunk:693591-694881,695264-695420,695621,695649-703063

Propchange: poi/branches/ooxml/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Thu Oct  9 00:20:46 2008
@@ -1 +1 @@
-/poi/trunk:1-638784,638786-639486,639488-639601,639603-640056,640058-642562,642564-642566,642568-642574,642576-642736,642739-650914,650916-702231
+/poi/trunk:1-638784,638786-639486,639488-639601,639603-640056,640058-642562,642564-642566,642568-642574,642576-642736,642739-650914,650916-703063

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java Thu Oct  9 00:20:46 2008
@@ -1,3 +1,20 @@
+/* ====================================================================
+   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 org.apache.poi.hssf.model.HSSFFormulaParser;
@@ -8,12 +25,12 @@
 import org.apache.poi.hssf.record.formula.NamePtg;
 import org.apache.poi.hssf.record.formula.NameXPtg;
 import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.ss.formula.EvaluationCell;
 import org.apache.poi.ss.formula.EvaluationName;
+import org.apache.poi.ss.formula.EvaluationSheet;
 import org.apache.poi.ss.formula.EvaluationWorkbook;
 import org.apache.poi.ss.formula.FormulaParsingWorkbook;
 import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.Sheet;
 
 /**
  * Internal POI use only
@@ -45,8 +62,8 @@
 		return _iBook.getExternalSheetIndex(workbookName, sheetName);
 	}
 
-	public EvaluationName getName(int index) {
-		return new Name(_iBook.getNameRecord(index), index);
+	public NameXPtg getNameXPtg(String name) {
+		return _iBook.getNameXPtg(name);
 	}
 
 	public EvaluationName getName(String name) {
@@ -59,7 +76,8 @@
 		return null;
 	}
 
-	public int getSheetIndex(Sheet sheet) {
+	public int getSheetIndex(EvaluationSheet evalSheet) {
+		HSSFSheet sheet = ((HSSFEvaluationSheet)evalSheet).getHSSFSheet();
 		return _uBook.getSheetIndex(sheet);
 	}
 	public int getSheetIndex(String sheetName) {
@@ -70,16 +88,8 @@
 		return _uBook.getSheetName(sheetIndex);
 	}
 
-	public int getNameIndex(String name) {
-		return _uBook.getNameIndex(name);
-	}
-
-	public NameXPtg getNameXPtg(String name) {
-		return _iBook.getNameXPtg(name);
-	}
-
-	public Sheet getSheet(int sheetIndex) {
-		return _uBook.getSheetAt(sheetIndex);
+	public EvaluationSheet getSheet(int sheetIndex) {
+		return new HSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex));
 	}
 	public int convertFromExternSheetIndex(int externSheetIndex) {
 		return _iBook.getSheetIndexFromExternSheetIndex(externSheetIndex);
@@ -88,10 +98,6 @@
 	public ExternalSheet getExternalSheet(int externSheetIndex) {
 		return _iBook.getExternalSheet(externSheetIndex);
 	}
-	
-	public HSSFWorkbook getWorkbook() {
-		return _uBook;
-	}
 
 	public String resolveNameXText(NameXPtg n) {
 		return _iBook.resolveNameXText(n.getSheetRefIndex(), n.getNameIndex());
@@ -107,15 +113,15 @@
 		int ix = namePtg.getIndex();
 		return new Name(_iBook.getNameRecord(ix), ix);
 	}
-	public Ptg[] getFormulaTokens(Cell cell) {
+	public Ptg[] getFormulaTokens(EvaluationCell evalCell) {
+		HSSFCell cell = ((HSSFEvaluationCell)evalCell).getHSSFCell();
 		if (false) {
 			// re-parsing the formula text also works, but is a waste of time
 			// It is useful from time to time to run all unit tests with this code
 			// to make sure that all formulas POI can evaluate can also be parsed.
 			return HSSFFormulaParser.parse(cell.getCellFormula(), _uBook);
 		}
-		HSSFCell hCell = (HSSFCell) cell;
-		FormulaRecord fr = ((FormulaRecordAggregate) hCell.getCellValueRecord()).getFormulaRecord();
+		FormulaRecord fr = ((FormulaRecordAggregate) cell.getCellValueRecord()).getFormulaRecord();
 		return fr.getParsedExpression();
 	}
 
@@ -128,23 +134,18 @@
 			_nameRecord = nameRecord;
 			_index = index;
 		}
-
 		public Ptg[] getNameDefinition() {
 			return _nameRecord.getNameDefinition();
 		}
-
 		public String getNameText() {
 			return _nameRecord.getNameText();
 		}
-
 		public boolean hasFormula() {
 			return _nameRecord.hasFormula();
 		}
-
 		public boolean isFunctionName() {
 			return _nameRecord.isFunctionName();
 		}
-
 		public boolean isRange() {
 			return _nameRecord.hasFormula(); // TODO - is this right?
 		}

Modified: poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java Thu Oct  9 00:20:46 2008
@@ -19,7 +19,6 @@
 
 import java.util.Iterator;
 
-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.NumberEval;
@@ -29,7 +28,6 @@
 import org.apache.poi.ss.formula.WorkbookEvaluator;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellValue;
-import org.apache.poi.ss.usermodel.Sheet;
 
 /**
  * Evaluates formula cells.<p/>
@@ -86,7 +84,9 @@
 
 	/**
 	 * Should be called whenever there are major changes (e.g. moving sheets) to input cells
-	 * in the evaluated workbook.
+	 * in the evaluated workbook.  If performance is not critical, a single call to this method
+	 * may be used instead of many specific calls to the notify~ methods.
+	 *  
 	 * Failure to call this method after changing cell values will cause incorrect behaviour
 	 * of the evaluate~ methods of this class
 	 */
@@ -94,23 +94,22 @@
 		_bookEvaluator.clearAllCachedResultValues();
 	}
 	/**
-	 * Sets the cached value for a plain (non-formula) cell.
-	 * Should be called whenever there are changes to individual input cells in the evaluated workbook.
+	 * Should be called to tell the cell value cache that the specified (value or formula) cell 
+	 * has changed.
 	 * Failure to call this method after changing cell values will cause incorrect behaviour
 	 * of the evaluate~ methods of this class
-	 * @param never <code>null</code>. Use {@link BlankEval#INSTANCE} when the cell is being 
-	 * cleared. Otherwise an instance of {@link NumberEval}, {@link StringEval}, {@link BoolEval}
-	 * or {@link ErrorEval} to represent a plain cell value.
 	 */
-	public void setCachedPlainValue(Sheet sheet, int rowIndex, int columnIndex, ValueEval value) {
-		_bookEvaluator.setCachedPlainValue(sheet, rowIndex, columnIndex, value);
+	public void notifyUpdateCell(HSSFCell cell) {
+		_bookEvaluator.notifyUpdateCell(new HSSFEvaluationCell(cell));
 	}
 	/**
-	 * Should be called to tell the cell value cache that the specified cell has just become a
-	 * formula cell, or the formula text has changed 
+	 * Should be called to tell the cell value cache that the specified cell has just been
+	 * deleted. 
+	 * Failure to call this method after changing cell values will cause incorrect behaviour
+	 * of the evaluate~ methods of this class
 	 */
-	public void notifySetFormula(HSSFSheet sheet, int rowIndex, int columnIndex) {
-		_bookEvaluator.notifySetFormula(sheet, rowIndex, columnIndex);
+	public void notifyDeleteCell(HSSFCell cell) {
+		_bookEvaluator.notifyDeleteCell(new HSSFEvaluationCell(cell));
 	}
 
 	/**
@@ -273,7 +272,7 @@
 	 * @param eval
 	 */
 	private CellValue evaluateFormulaCellValue(Cell cell) {
-		ValueEval eval = _bookEvaluator.evaluate(cell);
+		ValueEval eval = _bookEvaluator.evaluate(new HSSFEvaluationCell((HSSFCell)cell));
 		if (eval instanceof NumberEval) {
 			NumberEval ne = (NumberEval) eval;
 			return new CellValue(ne.getNumberValue());

Modified: poi/branches/ooxml/src/java/org/apache/poi/ss/formula/CellCacheEntry.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/ss/formula/CellCacheEntry.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/ss/formula/CellCacheEntry.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/ss/formula/CellCacheEntry.java Thu Oct  9 00:20:46 2008
@@ -17,42 +17,44 @@
 
 package org.apache.poi.ss.formula;
 
-import java.util.HashSet;
-import java.util.Set;
-
 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.NumberEval;
 import org.apache.poi.hssf.record.formula.eval.StringEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.IEvaluationListener.ICacheEntry;
 
 /**
  * Stores the parameters that identify the evaluation of one cell.<br/>
  */
-final class CellCacheEntry {
+abstract class CellCacheEntry implements ICacheEntry {
+	public static final CellCacheEntry[] EMPTY_ARRAY = { };
+	
+	private final FormulaCellCacheEntrySet _consumingCells;
 	private ValueEval _value;
-	private final Set _consumingCells;
-	private CellLocation[] _usedCells;
-	private boolean _isPlainValueCell;
-	
-	public CellCacheEntry() {
-		_consumingCells = new HashSet();
-	}
-	public boolean updatePlainValue(ValueEval value) {
-		boolean wasChanged = false;
-		if (!_isPlainValueCell) {
-			wasChanged = true;
-		}
-		if (!areValuesEqual(_value, value)) {
-			wasChanged = true;
+	
+
+	protected CellCacheEntry() {
+		_consumingCells = new FormulaCellCacheEntrySet();
+	}
+	protected final void clearValue() {
+		_value = null;
+	}
+
+	public final boolean updateValue(ValueEval value) {
+		if (value == null) {
+			throw new IllegalArgumentException("Did not expect to update to null");
 		}
-		_isPlainValueCell = true;
+		boolean result = !areValuesEqual(_value, value);
 		_value = value;
-		_usedCells = null;
-		return wasChanged;
+		return result;
+	}
+	public final ValueEval getValue() {
+		return _value;
 	}
-	private boolean areValuesEqual(ValueEval a, ValueEval b) {
+	
+	private static boolean areValuesEqual(ValueEval a, ValueEval b) {
 		if (a == null) {
 			return false;
 		}
@@ -78,41 +80,58 @@
 		}
 		throw new IllegalStateException("Unexpected value class (" + cls.getName() + ")");
 	}
-	public void setFormulaResult(ValueEval value, CellLocation[] usedCells) {
-		_isPlainValueCell = false;
-		_value = value;
-		_usedCells = usedCells;
-	}
-	public void addConsumingCell(CellLocation cellLoc) {
+
+	public final void addConsumingCell(FormulaCellCacheEntry cellLoc) {
 		_consumingCells.add(cellLoc);
 		
 	}
-	public CellLocation[] getConsumingCells() {
-		int nItems = _consumingCells.size();
-		if (nItems < 1) {
-			return CellLocation.EMPTY_ARRAY;
-		}
-		CellLocation[] result = new CellLocation[nItems];
-		_consumingCells.toArray(result);
-		return result;
+	public final FormulaCellCacheEntry[] getConsumingCells() {
+		return _consumingCells.toArray();
 	}
-	public CellLocation[] getUsedCells() {
-		return _usedCells;
+
+	public final void clearConsumingCell(FormulaCellCacheEntry cce) {
+		if(!_consumingCells.remove(cce)) {
+			throw new IllegalStateException("Specified formula cell is not consumed by this cell");
+		}
 	}
-	public void clearConsumingCell(CellLocation fc) {
-		if(!_consumingCells.remove(fc)) {
-			throw new IllegalStateException("Cell '" + fc.formatAsString() + "' does not use this cell");
+	public final void recurseClearCachedFormulaResults(IEvaluationListener listener) {
+		if (listener == null) {
+			recurseClearCachedFormulaResults();
+		} else {
+			listener.onClearCachedValue(this);
+			recurseClearCachedFormulaResults(listener, 1);
 		}
+	}
+	
+	/**
+	 * Calls formulaCell.setFormulaResult(null, null) recursively all the way up the tree of 
+	 * dependencies. Calls usedCell.clearConsumingCell(fc) for each child of a cell that is
+	 * cleared along the way.
+	 * @param formulaCells
+	 */
+	protected final void recurseClearCachedFormulaResults() {
+		FormulaCellCacheEntry[] formulaCells = getConsumingCells();
 		
+		for (int i = 0; i < formulaCells.length; i++) {
+			FormulaCellCacheEntry fc = formulaCells[i];
+			fc.clearFormulaEntry();
+			fc.recurseClearCachedFormulaResults();
+		}
 	}
-	public ValueEval getValue() {
-		ValueEval result = _value;
-		if (result == null) {
-			if (_isPlainValueCell) {
-				throw new IllegalStateException("Plain value cell should always have a value");
-				
-			}
+	
+	/**
+	 * Identical to {@link #recurseClearCachedFormulaResults()} except for the listener call-backs
+	 */
+	protected final void recurseClearCachedFormulaResults(IEvaluationListener listener, int depth) {
+		FormulaCellCacheEntry[] formulaCells = getConsumingCells();
+
+		listener.sortDependentCachedValues(formulaCells);
+		for (int i = 0; i < formulaCells.length; i++) {
+			FormulaCellCacheEntry fc = formulaCells[i];
+			listener.onClearDependentCachedValue(fc, depth);
+			fc.clearFormulaEntry();
+			fc.recurseClearCachedFormulaResults(listener, depth+1);
 		}
-		return result;
 	}
+	
 }
\ No newline at end of file

Modified: poi/branches/ooxml/src/java/org/apache/poi/ss/formula/CellEvaluationFrame.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/ss/formula/CellEvaluationFrame.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/ss/formula/CellEvaluationFrame.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/ss/formula/CellEvaluationFrame.java Thu Oct  9 00:20:46 2008
@@ -20,44 +20,58 @@
 import java.util.HashSet;
 import java.util.Set;
 
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
 /**
  * Stores details about the current evaluation of a cell.<br/>
  */
 final class CellEvaluationFrame {
 
-	private final CellLocation _cellLocation;
-	private final Set _usedCells;
+	private final FormulaCellCacheEntry _cce;
+	private final Set _sensitiveInputCells;
+	private FormulaUsedBlankCellSet _usedBlankCellGroup;
 
-	public CellEvaluationFrame(CellLocation cellLoc) {
-		_cellLocation = cellLoc;
-		_usedCells = new HashSet();
+	public CellEvaluationFrame(FormulaCellCacheEntry cce) {
+		_cce = cce;
+		_sensitiveInputCells = new HashSet();
 	}
-	public CellLocation getCoordinates() {
-		return _cellLocation;
+	public CellCacheEntry getCCE() {
+		return _cce;
 	}
 
 	public String toString() {
 		StringBuffer sb = new StringBuffer(64);
 		sb.append(getClass().getName()).append(" [");
-		sb.append(_cellLocation.formatAsString());
 		sb.append("]");
 		return sb.toString();
 	}
-	public void addUsedCell(CellLocation coordinates) {
-		_usedCells.add(coordinates);
+	/**
+	 * @param inputCell a cell directly used by the formula of this evaluation frame
+	 */
+	public void addSensitiveInputCell(CellCacheEntry inputCell) {
+		_sensitiveInputCells.add(inputCell);
 	}
 	/**
 	 * @return never <code>null</code>, (possibly empty) array of all cells directly used while 
-	 * evaluating the formula of this frame.  For non-formula cells this will always be an empty
-	 * array;
+	 * evaluating the formula of this frame.
 	 */
-	public CellLocation[] getUsedCells() {
-		int nItems = _usedCells.size();
+	private CellCacheEntry[] getSensitiveInputCells() {
+		int nItems = _sensitiveInputCells.size();
 		if (nItems < 1) {
-			return CellLocation.EMPTY_ARRAY;
+			return CellCacheEntry.EMPTY_ARRAY;
 		}
-		CellLocation[] result = new CellLocation[nItems];
-		_usedCells.toArray(result);
+		CellCacheEntry[] result = new CellCacheEntry[nItems];
+		_sensitiveInputCells.toArray(result);
 		return result;
 	}
+	public void addUsedBlankCell(int bookIndex, int sheetIndex, int rowIndex, int columnIndex) {
+		if (_usedBlankCellGroup == null) {
+			_usedBlankCellGroup = new FormulaUsedBlankCellSet();
+		}
+		_usedBlankCellGroup.addCell(bookIndex, sheetIndex, rowIndex, columnIndex);
+	}
+	
+	public void updateFormulaResult(ValueEval result) {
+		_cce.updateFormulaResult(result, getSensitiveInputCells(), _usedBlankCellGroup);
+	}
 }
\ No newline at end of file

Modified: poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationCache.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationCache.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationCache.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationCache.java Thu Oct  9 00:20:46 2008
@@ -17,16 +17,17 @@
 
 package org.apache.poi.ss.formula;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
+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.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.usermodel.HSSFCell;
 import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.ss.formula.FormulaCellCache.IEntryOperation;
+import org.apache.poi.ss.formula.FormulaUsedBlankCellSet.BookSheetKey;
+import org.apache.poi.ss.formula.PlainCellCache.Loc;
 
 /**
  * Performance optimisation for {@link HSSFFormulaEvaluator}. This class stores previously
@@ -38,152 +39,138 @@
  */
 final class EvaluationCache {
 
-	private final Map _entriesByLocation;
-	private final Map _consumingCellsByUsedCells;
+	private final PlainCellCache _plainCellCache;
+	private final FormulaCellCache _formulaCellCache;
 	/** only used for testing. <code>null</code> otherwise */
-	private final IEvaluationListener _evaluationListener;
+	final IEvaluationListener _evaluationListener;
 
 	/* package */EvaluationCache(IEvaluationListener evaluationListener) {
 		_evaluationListener = evaluationListener;
-		_entriesByLocation = new HashMap();
-		_consumingCellsByUsedCells = new HashMap();
-	}
-
-	/**
-	 * @param cellLoc never <code>null</code>
-	 * @return only ever <code>null</code> for formula cells that have had their cached value cleared
-	 */
-	public ValueEval getValue(CellLocation cellLoc) {
-		return getEntry(cellLoc).getValue();
+		_plainCellCache = new PlainCellCache();
+		_formulaCellCache = new FormulaCellCache();
 	}
 
-	/**
-	 * @param cellLoc
-	 * @param usedCells never <code>null</code>, (possibly zero length) array of all cells actually 
-	 * directly used when evaluating the formula
-	 * @param isPlainValue pass <code>true</code> if cellLoc refers to a plain value (non-formula) 
-	 * cell, <code>false</code> for a formula cell.
-	 * @param value the value of a non-formula cell or the result of evaluating the cell formula
-	 * Pass <code>null</code> to signify clearing the cached result of a formula cell) 
-	 */
-	public void setValue(CellLocation cellLoc, boolean isPlainValue, 
-			CellLocation[] usedCells, ValueEval value) {
+	public void notifyUpdateCell(int bookIndex, int sheetIndex, EvaluationCell cell) {
+		FormulaCellCacheEntry fcce = _formulaCellCache.get(cell);
+		
+		Loc loc = new Loc(bookIndex, sheetIndex, cell.getRowIndex(), cell.getColumnIndex());
+		PlainValueCellCacheEntry pcce = _plainCellCache.get(loc);
 
-		CellCacheEntry existingEntry = (CellCacheEntry) _entriesByLocation.get(cellLoc);
-		if (existingEntry != null && existingEntry.getValue() != null) {
-			if (isPlainValue) {
-				// can set a plain cell cached value any time
-			} else if (value == null) {
-				// or clear the cached value of a formula cell at any time
-			} else {
-				// but a formula cached value would only be getting updated if the cache didn't have a value to start with
-				throw new IllegalStateException("Already have cached value for this cell: "
-						+ cellLoc.formatAsString());
-			}
-		}
-		sortCellLocationsForLogging(usedCells);
-		CellCacheEntry entry = getEntry(cellLoc);
-		CellLocation[] consumingFormulaCells = entry.getConsumingCells();
-		CellLocation[] prevUsedCells = entry.getUsedCells();
-		if (isPlainValue) {
-			
-			if(!entry.updatePlainValue(value)) {
-				return;
+		if (cell.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
+			if (fcce == null) {
+				if (pcce == null) {
+					updateAnyBlankReferencingFormulas(bookIndex, sheetIndex, cell.getRowIndex(), cell.getColumnIndex());
+				}
+				fcce = new FormulaCellCacheEntry();
+				_formulaCellCache.put(cell, fcce);
+			} else {
+				fcce.recurseClearCachedFormulaResults(_evaluationListener);
+				fcce.clearFormulaEntry();
+			}
+			if (pcce == null) {
+				// was formula cell before - no change of type
+			} else {
+				// changing from plain cell to formula cell
+				pcce.recurseClearCachedFormulaResults(_evaluationListener);
+				_plainCellCache.remove(loc);
 			}
 		} else {
-			entry.setFormulaResult(value, usedCells);
-			for (int i = 0; i < usedCells.length; i++) {
-				getEntry(usedCells[i]).addConsumingCell(cellLoc);
+			ValueEval value = WorkbookEvaluator.getValueFromNonFormulaCell(cell);
+			if (pcce == null) {
+				if (fcce == null) {
+					updateAnyBlankReferencingFormulas(bookIndex, sheetIndex, cell.getRowIndex(), cell.getColumnIndex());
+				}
+				pcce = new PlainValueCellCacheEntry(value);
+				_plainCellCache.put(loc, pcce);
+				if (_evaluationListener != null) {
+					_evaluationListener.onReadPlainValue(sheetIndex, cell.getRowIndex(), cell.getColumnIndex(), pcce);
+				}
+			} else {
+				if(pcce.updateValue(value)) {
+					pcce.recurseClearCachedFormulaResults(_evaluationListener);
+				}
+			}
+			if (fcce == null) {
+				// was plain cell before - no change of type
+			} else {
+				// was formula cell before - now a plain value
+				_formulaCellCache.remove(cell);
+				fcce.setSensitiveInputCells(null);
+				fcce.recurseClearCachedFormulaResults(_evaluationListener);
 			}
 		}
-		// need to tell all cells that were previously used, but no longer are, 
-		// that they are not consumed by this cell any more
-		unlinkConsumingCells(prevUsedCells, usedCells, cellLoc);
-		
-		// clear all cells that directly or indirectly depend on this one
-		recurseClearCachedFormulaResults(consumingFormulaCells, 0);
 	}
 
-	/**
-	 * This method sorts the supplied cellLocs so that the order of call-backs to the evaluation 
-	 * listener is more deterministic
-	 */
-	private void sortCellLocationsForLogging(CellLocation[] cellLocs) {
-		if (_evaluationListener == null) {
-			// optimisation - don't bother sorting if there is no listener.
-		} else {
-			Arrays.sort(cellLocs, CellLocationComparator);
-		}
-	}
+	private void updateAnyBlankReferencingFormulas(int bookIndex, int sheetIndex, 
+			final int rowIndex, final int columnIndex) {
+		final BookSheetKey bsk = new BookSheetKey(bookIndex, sheetIndex);
+		_formulaCellCache.applyOperation(new IEntryOperation() {
 
-	private void unlinkConsumingCells(CellLocation[] prevUsedCells, CellLocation[] usedCells,
-			CellLocation cellLoc) {
-		if (prevUsedCells == null) {
-			return;
-		}
-		int nPrevUsed = prevUsedCells.length;
-		if (nPrevUsed < 1) {
-			return;
-		}
-		int nUsed = usedCells.length;
-		Set usedSet;
-		if (nUsed < 1) {
-			usedSet = Collections.EMPTY_SET;
-		} else {
-			usedSet = new HashSet(nUsed * 3 / 2);
-			for (int i = 0; i < nUsed; i++) {
-				usedSet.add(usedCells[i]);
-			}
-		}
-		for (int i = 0; i < nPrevUsed; i++) {
-			CellLocation prevUsed = prevUsedCells[i];
-			if (!usedSet.contains(prevUsed)) {
-				// previously was used by cellLoc, but not anymore
-				getEntry(prevUsed).clearConsumingCell(cellLoc);
-				if (_evaluationListener != null) {
-					//TODO _evaluationListener.onUnconsume(prevUsed.getSheetIndex(), etc)
-				}
+			public void processEntry(FormulaCellCacheEntry entry) {
+				entry.notifyUpdatedBlankCell(bsk, rowIndex, columnIndex, _evaluationListener);
 			}
-		}
-		
+		});
 	}
 
-	/**
-	 * Calls formulaCell.setFormulaResult(null, null) recursively all the way up the tree of 
-	 * dependencies. Calls usedCell.clearConsumingCell(fc) for each child of a cell that is
-	 * cleared along the way.
-	 * @param formulaCells
-	 */
-	private void recurseClearCachedFormulaResults(CellLocation[] formulaCells, int depth) {
-		sortCellLocationsForLogging(formulaCells);
-		int nextDepth = depth+1;
-		for (int i = 0; i < formulaCells.length; i++) {
-			CellLocation fc = formulaCells[i];
-			CellCacheEntry formulaCell = getEntry(fc);
-			CellLocation[] usedCells = formulaCell.getUsedCells();
-			if (usedCells != null) {
-				for (int j = 0; j < usedCells.length; j++) {
-					CellCacheEntry usedCell = getEntry(usedCells[j]);
-					usedCell.clearConsumingCell(fc);
-				}
+	public PlainValueCellCacheEntry getPlainValueEntry(int bookIndex, int sheetIndex,
+			int rowIndex, int columnIndex, ValueEval value) {
+		
+		Loc loc = new Loc(bookIndex, sheetIndex, rowIndex, columnIndex);
+		PlainValueCellCacheEntry result = _plainCellCache.get(loc);
+		if (result == null) {
+			result = new PlainValueCellCacheEntry(value);
+			_plainCellCache.put(loc, result);
+			if (_evaluationListener != null) {
+				_evaluationListener.onReadPlainValue(sheetIndex, rowIndex, columnIndex, result);
+			}
+		} else {
+			// TODO - if we are confident that this sanity check is not required, we can remove 'value' from plain value cache entry  
+			if (!areValuesEqual(result.getValue(), value)) {
+				throw new IllegalStateException("value changed");
 			}
 			if (_evaluationListener != null) {
-				ValueEval value = formulaCell.getValue();
-				_evaluationListener.onClearDependentCachedValue(fc.getSheetIndex(), fc.getRowIndex(), fc.getColumnIndex(), value, nextDepth);
+				_evaluationListener.onCacheHit(sheetIndex, rowIndex, columnIndex, value);
 			}
-			formulaCell.setFormulaResult(null, null);
-			recurseClearCachedFormulaResults(formulaCell.getConsumingCells(), nextDepth);
 		}
+		return result;
 	}
-
-	private CellCacheEntry getEntry(CellLocation cellLoc) {
-		CellCacheEntry result = (CellCacheEntry)_entriesByLocation.get(cellLoc);
+	private boolean areValuesEqual(ValueEval a, ValueEval b) {
+		if (a == null) {
+			return false;
+		}
+		Class cls = a.getClass();
+		if (cls != b.getClass()) {
+			// value type is changing
+			return false;
+		}
+		if (a == BlankEval.INSTANCE) {
+			return b == a;
+		}
+		if (cls == NumberEval.class) {
+			return ((NumberEval)a).getNumberValue() == ((NumberEval)b).getNumberValue();
+		}
+		if (cls == StringEval.class) {
+			return ((StringEval)a).getStringValue().equals(((StringEval)b).getStringValue());
+		}
+		if (cls == BoolEval.class) {
+			return ((BoolEval)a).getBooleanValue() == ((BoolEval)b).getBooleanValue();
+		}
+		if (cls == ErrorEval.class) {
+			return ((ErrorEval)a).getErrorCode() == ((ErrorEval)b).getErrorCode();
+		}
+		throw new IllegalStateException("Unexpected value class (" + cls.getName() + ")");
+	}
+	
+	public FormulaCellCacheEntry getOrCreateFormulaCellEntry(EvaluationCell cell) {
+		FormulaCellCacheEntry result = _formulaCellCache.get(cell);
 		if (result == null) {
-			result = new CellCacheEntry();
-			_entriesByLocation.put(cellLoc, result);
+			
+			result = new FormulaCellCacheEntry();
+			_formulaCellCache.put(cell, result);
 		}
 		return result;
 	}
+
 	/**
 	 * Should be called whenever there are changes to input cells in the evaluated workbook.
 	 */
@@ -191,34 +178,28 @@
 		if(_evaluationListener != null) {
 			_evaluationListener.onClearWholeCache();
 		}
-		_entriesByLocation.clear();
-		_consumingCellsByUsedCells.clear();
+		_plainCellCache.clear();
+		_formulaCellCache.clear();
 	}
-
-
-	private static final Comparator CellLocationComparator = new Comparator() {
-
-		public int compare(Object a, Object b) {
-			CellLocation clA = (CellLocation) a;
-			CellLocation clB = (CellLocation) b;
-			
-			int cmp;
-			cmp = clA.getBookIndex() - clB.getBookIndex();
-			if (cmp != 0) {
-				return cmp;
-			}
-			cmp = clA.getSheetIndex() - clB.getSheetIndex();
-			if (cmp != 0) {
-				return cmp;
-			}
-			cmp = clA.getRowIndex() - clB.getRowIndex();
-			if (cmp != 0) {
-				return cmp;
+	public void notifyDeleteCell(int bookIndex, int sheetIndex, EvaluationCell cell) {
+		
+		if (cell.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
+			FormulaCellCacheEntry fcce = _formulaCellCache.remove(cell);
+			if (fcce == null) {
+				// formula cell has not been evaluated yet 
+			} else {
+				fcce.setSensitiveInputCells(null);
+				fcce.recurseClearCachedFormulaResults(_evaluationListener);
 			}
-			cmp = clA.getColumnIndex() - clB.getColumnIndex();
+		} else {
+			Loc loc = new Loc(bookIndex, sheetIndex, cell.getRowIndex(), cell.getColumnIndex());
+			PlainValueCellCacheEntry pcce = _plainCellCache.get(loc);
 			
-			return cmp;
+			if (pcce == null) {
+				// cache entry doesn't exist. nothing to do
+			} else {
+				pcce.recurseClearCachedFormulaResults(_evaluationListener);
+			}
 		}
-		
-	};
+	}
 }

Modified: poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationTracker.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationTracker.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationTracker.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationTracker.java Thu Oct  9 00:20:46 2008
@@ -22,7 +22,7 @@
 import java.util.List;
 import java.util.Set;
 
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
 import org.apache.poi.hssf.usermodel.HSSFCell;
 
@@ -32,11 +32,11 @@
  * 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 EvaluationTracker {
-
+	// TODO - consider deleting this class and letting CellEvaluationFrame take care of itself
 	private final List _evaluationFrames;
 	private final Set _currentlyEvaluatingCells;
 	private final EvaluationCache _cache;
@@ -50,47 +50,51 @@
 	/**
 	 * 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
+	 *
+	 * In the case of a <code>null</code> return code, the caller should
 	 * return an evaluation result of
-	 * <tt>ErrorEval.CIRCULAR_REF_ERROR<tt>, and not call <tt>endEvaluate()</tt>.  
+	 * <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.
+	 * @return <code>false</code> if the specified cell is already being evaluated
 	 */
-	public ValueEval startEvaluate(CellLocation cellLoc) {
-		if (cellLoc == null) {
+	public boolean startEvaluate(FormulaCellCacheEntry cce) {
+		if (cce == null) {
 			throw new IllegalArgumentException("cellLoc must not be null");
 		}
-		if (_currentlyEvaluatingCells.contains(cellLoc)) {
-			return ErrorEval.CIRCULAR_REF_ERROR;
+		if (_currentlyEvaluatingCells.contains(cce)) {
+			return false;
 		}
-		ValueEval result = _cache.getValue(cellLoc);
-		if (result == null) {
-			_currentlyEvaluatingCells.add(cellLoc);
-			_evaluationFrames.add(new CellEvaluationFrame(cellLoc));
+		_currentlyEvaluatingCells.add(cce);
+		_evaluationFrames.add(new CellEvaluationFrame(cce));
+		return true;
+	}
+
+	public void updateCacheResult(ValueEval result) {
+
+		int nFrames = _evaluationFrames.size();
+		if (nFrames < 1) {
+			throw new IllegalStateException("Call to endEvaluate without matching call to startEvaluate");
 		}
-		return result;
+		CellEvaluationFrame frame = (CellEvaluationFrame) _evaluationFrames.get(nFrames-1);
+
+		frame.updateFormulaResult(result);
 	}
 
 	/**
-	 * 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
+	 * 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.
-	 * @param result 
 	 */
-	public void endEvaluate(CellLocation cellLoc, ValueEval result, boolean isPlainValueCell) {
+	public void endEvaluate(CellCacheEntry cce) {
 
 		int nFrames = _evaluationFrames.size();
 		if (nFrames < 1) {
@@ -99,32 +103,40 @@
 
 		nFrames--;
 		CellEvaluationFrame frame = (CellEvaluationFrame) _evaluationFrames.get(nFrames);
-		CellLocation coordinates = frame.getCoordinates();
-		if (!coordinates.equals(cellLoc)) {
-			throw new RuntimeException("Wrong cell specified. "
-					+ "Corresponding startEvaluate() call was for cell {"
-					+ coordinates.formatAsString() + "} this endEvaluate() call is for cell {"
-					+ cellLoc.formatAsString() + "}");
+		if (cce != frame.getCCE()) {
+			throw new IllegalStateException("Wrong cell specified. ");
 		}
-		// else - no problems so pop current frame 
+		// else - no problems so pop current frame
 		_evaluationFrames.remove(nFrames);
-		_currentlyEvaluatingCells.remove(coordinates);
-
-		// TODO - don't cache results of volatile formulas 
-		_cache.setValue(coordinates, isPlainValueCell, frame.getUsedCells(), result);
+		_currentlyEvaluatingCells.remove(cce);
 	}
-	/**
-	 * Tells the currently evaluating cell frame that it has a dependency on the specified 
-	 * <tt>usedCell<tt> 
-	 * @param usedCell location of cell which is referenced (and used) by the current cell.
-	 */
-	public void acceptDependency(CellLocation usedCell) {
+
+	public void acceptFormulaDependency(CellCacheEntry cce) {
+		// Tell the currently evaluating cell frame that it has a dependency on the specified
 		int prevFrameIndex = _evaluationFrames.size()-1;
 		if (prevFrameIndex < 0) {
-			throw new IllegalStateException("Call to acceptDependency without prior call to startEvaluate");
+			// Top level frame, there is no 'cell' above this frame that is using the current cell
+		} else {
+			CellEvaluationFrame consumingFrame = (CellEvaluationFrame) _evaluationFrames.get(prevFrameIndex);
+			consumingFrame.addSensitiveInputCell(cce);
 		}
-		CellEvaluationFrame consumingFrame = (CellEvaluationFrame) _evaluationFrames.get(prevFrameIndex);
-		consumingFrame.addUsedCell(usedCell);
 	}
 
+	public void acceptPlainValueDependency(int bookIndex, int sheetIndex,
+			int rowIndex, int columnIndex, ValueEval value) {
+		// Tell the currently evaluating cell frame that it has a dependency on the specified
+		int prevFrameIndex = _evaluationFrames.size() - 1;
+		if (prevFrameIndex < 0) {
+			// Top level frame, there is no 'cell' above this frame that is using the current cell
+		} else {
+			CellEvaluationFrame consumingFrame = (CellEvaluationFrame) _evaluationFrames.get(prevFrameIndex);
+			if (value == BlankEval.INSTANCE) {
+				consumingFrame.addUsedBlankCell(bookIndex, sheetIndex, rowIndex, columnIndex);
+			} else {
+				PlainValueCellCacheEntry cce = _cache.getPlainValueEntry(bookIndex, sheetIndex,
+						rowIndex, columnIndex, value);
+				consumingFrame.addSensitiveInputCell(cce);
+			}
+		}
+	}
 }

Modified: poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java Thu Oct  9 00:20:46 2008
@@ -20,8 +20,7 @@
 import org.apache.poi.hssf.record.formula.NamePtg;
 import org.apache.poi.hssf.record.formula.NameXPtg;
 import org.apache.poi.hssf.record.formula.Ptg;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.Sheet;
+
 /**
  * Abstracts a workbook for the purpose of formula evaluation.<br/>
  * 
@@ -34,10 +33,10 @@
 	/**
 	 * @return -1 if the specified sheet is from a different book
 	 */
-	int getSheetIndex(Sheet sheet);
+	int getSheetIndex(EvaluationSheet sheet);
 	int getSheetIndex(String sheetName);
 
-	Sheet getSheet(int sheetIndex);
+	EvaluationSheet getSheet(int sheetIndex);
 
 	/**
 	 * @return <code>null</code> if externSheetIndex refers to a sheet inside the current workbook
@@ -46,7 +45,7 @@
 	int convertFromExternSheetIndex(int externSheetIndex);
 	EvaluationName getName(NamePtg namePtg);
 	String resolveNameXText(NameXPtg ptg);
-	Ptg[] getFormulaTokens(Cell cell);
+	Ptg[] getFormulaTokens(EvaluationCell cell);
 	
 	class ExternalSheet {
 		private final String _workbookName;

Modified: poi/branches/ooxml/src/java/org/apache/poi/ss/formula/IEvaluationListener.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/ss/formula/IEvaluationListener.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/ss/formula/IEvaluationListener.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/ss/formula/IEvaluationListener.java Thu Oct  9 00:20:46 2008
@@ -19,6 +19,7 @@
 
 import org.apache.poi.hssf.record.formula.Ptg;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.usermodel.HSSFCell;
 
 /**
  * Tests can implement this class to track the internal working of the {@link WorkbookEvaluator}.<br/>
@@ -28,12 +29,26 @@
  * @author Josh Micich
  */
 interface IEvaluationListener {
+	/**
+	 * A (mostly) opaque interface to allow test clients to trace cache values
+	 * Each spreadsheet cell gets one unique cache entry instance.  These objects
+	 * are safe to use as keys in {@link java.util.HashMap}s 
+	 */
+	interface ICacheEntry {
+		ValueEval getValue();
+	}
 
 	void onCacheHit(int sheetIndex, int rowIndex, int columnIndex, ValueEval result);
-	void onReadPlainValue(int sheetIndex, int srcRowNum, int srcColNum, ValueEval value);
-	void onStartEvaluate(int sheetIndex, int rowIndex, int columnIndex, Ptg[] ptgs);
-	void onEndEvaluate(int sheetIndex, int rowIndex, int columnIndex, ValueEval result);
+	void onReadPlainValue(int sheetIndex, int rowIndex, int columnIndex, ICacheEntry entry);
+	void onStartEvaluate(EvaluationCell cell, ICacheEntry entry, Ptg[] ptgs);
+	void onEndEvaluate(ICacheEntry entry, ValueEval result);
 	void onClearWholeCache();
-	void onClearCachedValue(int sheetIndex, int rowIndex, int columnIndex, ValueEval value);
-	void onClearDependentCachedValue(int sheetIndex, int rowIndex, int columnIndex, ValueEval value, int depth);
+	void onClearCachedValue(ICacheEntry entry);
+	/**
+	 * Internally, formula {@link ICacheEntry}s are stored in sets which may change ordering due 
+	 * to seemingly trivial changes.  This method is provided to make the order of call-backs to 
+	 * {@link #onClearDependentCachedValue(ICacheEntry, int)} more deterministic.
+	 */
+	void sortDependentCachedValues(ICacheEntry[] formulaCells);
+	void onClearDependentCachedValue(ICacheEntry formulaCell, int depth);
 }

Modified: poi/branches/ooxml/src/java/org/apache/poi/ss/formula/SheetRefEvaluator.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/ss/formula/SheetRefEvaluator.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/ss/formula/SheetRefEvaluator.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/ss/formula/SheetRefEvaluator.java Thu Oct  9 00:20:46 2008
@@ -18,7 +18,6 @@
 package org.apache.poi.ss.formula;
 
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.ss.usermodel.Sheet;
 /**
  * 
  * 
@@ -28,7 +27,7 @@
 
 	private final WorkbookEvaluator _bookEvaluator;
 	private final EvaluationTracker _tracker;
-	private final Sheet _sheet;
+	private final EvaluationSheet _sheet;
 	private final int _sheetIndex;
 
 	public SheetRefEvaluator(WorkbookEvaluator bookEvaluator, EvaluationTracker tracker,

Modified: poi/branches/ooxml/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java (original)
+++ poi/branches/ooxml/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java Thu Oct  9 00:20:46 2008
@@ -63,8 +63,6 @@
 import org.apache.poi.hssf.util.CellReference;
 import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet;
 import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
 
 /**
  * Evaluates formula cells.<p/>
@@ -131,7 +129,7 @@
 	/* package */ IEvaluationListener getEvaluationListener() {
 		return _evaluationListener;
 	}
-	 
+
 	/**
 	 * 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
@@ -143,29 +141,23 @@
 	}
 
 	/**
-	 * Sets the cached value for a plain (non-formula) cell.
-	 * @param never <code>null</code>. Use {@link BlankEval#INSTANCE} when the cell is being 
-	 * cleared. Otherwise an instance of {@link NumberEval}, {@link StringEval}, {@link BoolEval}
-	 * or {@link ErrorEval} to represent a plain cell value.
+	 * Should be called to tell the cell value cache that the specified (value or formula) cell 
+	 * has changed.
 	 */
-	public void setCachedPlainValue(Sheet sheet, int rowIndex, int columnIndex, ValueEval value) {
-		if (value == null) {
-			throw new IllegalArgumentException("value must not be null");
-		}
-		int sheetIndex = getSheetIndex(sheet);
-		_cache.setValue(getCellLoc(sheetIndex, rowIndex, columnIndex), true, CellLocation.EMPTY_ARRAY, value);
-
+	public void notifyUpdateCell(EvaluationCell cell) {
+		int sheetIndex = getSheetIndex(cell.getSheet());
+		_cache.notifyUpdateCell(_workbookIx, sheetIndex, cell);
 	}
 	/**
-	 * Should be called to tell the cell value cache that the specified cell has just become a
-	 * formula cell, or the formula text has changed 
+	 * Should be called to tell the cell value cache that the specified cell has just been
+	 * deleted. 
 	 */
-	public void notifySetFormula(Sheet sheet, int rowIndex, int columnIndex) {
-		int sheetIndex = getSheetIndex(sheet);
-		_cache.setValue(getCellLoc(sheetIndex, rowIndex, columnIndex), false, CellLocation.EMPTY_ARRAY, null);
-
+	public void notifyDeleteCell(EvaluationCell cell) {
+		int sheetIndex = getSheetIndex(cell.getSheet());
+		_cache.notifyDeleteCell(_workbookIx, sheetIndex, cell);
 	}
-	private int getSheetIndex(Sheet sheet) {
+
+	private int getSheetIndex(EvaluationSheet sheet) {
 		Integer result = (Integer) _sheetIndexesBySheet.get(sheet);
 		if (result == null) {
 			int sheetIndex = _workbook.getSheetIndex(sheet);
@@ -178,78 +170,76 @@
 		return result.intValue();
 	}
 
-	public ValueEval evaluate(Cell srcCell) {
+	public ValueEval evaluate(EvaluationCell srcCell) {
 		int sheetIndex = getSheetIndex(srcCell.getSheet());
-		CellLocation cellLoc = getCellLoc(sheetIndex, srcCell.getRowIndex(), srcCell.getCellNum());
-		return internalEvaluate(srcCell, cellLoc, new EvaluationTracker(_cache));
+		return evaluateAny(srcCell, sheetIndex, srcCell.getRowIndex(), srcCell.getColumnIndex(), new EvaluationTracker(_cache));
 	}
 
+
 	/**
 	 * @return never <code>null</code>, never {@link BlankEval}
 	 */
-	private ValueEval internalEvaluate(Cell srcCell, CellLocation cellLoc, EvaluationTracker tracker) {
-		int sheetIndex = cellLoc.getSheetIndex();
-		int rowIndex = cellLoc.getRowIndex();
-		int columnIndex = cellLoc.getColumnIndex();
+	private ValueEval evaluateAny(EvaluationCell srcCell, int sheetIndex,
+				int rowIndex, int columnIndex, EvaluationTracker tracker) {
 
-		ValueEval result;
+		if (srcCell == null || srcCell.getCellType() != Cell.CELL_TYPE_FORMULA) {
+			ValueEval result = getValueFromNonFormulaCell(srcCell);
+			tracker.acceptPlainValueDependency(_workbookIx, sheetIndex, rowIndex, columnIndex, result);
+			return result;
+		}
 
-		result = tracker.startEvaluate(cellLoc);
+		FormulaCellCacheEntry cce = _cache.getOrCreateFormulaCellEntry(srcCell);
+		tracker.acceptFormulaDependency(cce);
 		IEvaluationListener evalListener = _evaluationListener;
-		if (result != null) {
-			if(evalListener != null) {
-				evalListener.onCacheHit(sheetIndex, rowIndex, columnIndex, result);
+		if (cce.getValue() == null) {
+			if (!tracker.startEvaluate(cce)) {
+				return ErrorEval.CIRCULAR_REF_ERROR;
 			}
-			return result;
-		}
 
-		boolean isPlainFormulaCell = false;
-		try {
-			result = getValueFromNonFormulaCell(srcCell);
-			if (result != null) {
-				isPlainFormulaCell = true;
-				if(evalListener != null) {
-					evalListener.onReadPlainValue(sheetIndex, rowIndex, columnIndex, result);
-				}
-			} else {
-				isPlainFormulaCell = false;
+			try {
+				ValueEval result;
+
 				Ptg[] ptgs = _workbook.getFormulaTokens(srcCell);
-				if(evalListener == null) {
-					result = evaluateFormula(sheetIndex, rowIndex, (short)columnIndex, ptgs, tracker);
+				if (evalListener == null) {
+					result = evaluateFormula(sheetIndex, rowIndex, columnIndex, ptgs, tracker);
 				} else {
-					evalListener.onStartEvaluate(sheetIndex, rowIndex, columnIndex, ptgs);
-					result = evaluateFormula(sheetIndex, rowIndex, (short)columnIndex, ptgs, tracker);
-					evalListener.onEndEvaluate(sheetIndex, rowIndex, columnIndex, result);
+					evalListener.onStartEvaluate(srcCell, cce, ptgs);
+					result = evaluateFormula(sheetIndex, rowIndex, columnIndex, ptgs, tracker);
+					evalListener.onEndEvaluate(cce, result);
 				}
+
+				tracker.updateCacheResult(result);
+			} finally {
+				tracker.endEvaluate(cce);
+			}
+		} else {
+			if(evalListener != null) {
+				evalListener.onCacheHit(sheetIndex, rowIndex, columnIndex, cce.getValue());
 			}
-		} finally {
-			tracker.endEvaluate(cellLoc, result, isPlainFormulaCell);
+			return cce.getValue();
 		}
 		if (isDebugLogEnabled()) {
 			String sheetName = getSheetName(sheetIndex);
 			CellReference cr = new CellReference(rowIndex, columnIndex);
-			logDebug("Evaluated " + sheetName + "!" + cr.formatAsString() + " to " + result.toString());
+			logDebug("Evaluated " + sheetName + "!" + cr.formatAsString() + " to " + cce.getValue().toString());
 		}
-		return result;
+		return cce.getValue();
 	}
 	/**
 	 * Gets the value from a non-formula cell.
 	 * @param cell may be <code>null</code>
-	 * @return {@link BlankEval} if cell is <code>null</code> or blank, <code>null</code> if cell 
-	 * is a formula cell.
+	 * @return {@link BlankEval} if cell is <code>null</code> or blank, never <code>null</code>
 	 */
-	private static ValueEval getValueFromNonFormulaCell(Cell cell) {
+	/* package */ static ValueEval getValueFromNonFormulaCell(EvaluationCell cell) {
 		if (cell == null) {
 			return BlankEval.INSTANCE;
 		}
 		int cellType = cell.getCellType();
 		switch (cellType) {
-			case Cell.CELL_TYPE_FORMULA:
-				return null;
 			case Cell.CELL_TYPE_NUMERIC:
 				return new NumberEval(cell.getNumericCellValue());
 			case Cell.CELL_TYPE_STRING:
-				return new StringEval(cell.getRichStringCellValue().getString());
+				return new StringEval(cell.getStringCellValue());
 			case Cell.CELL_TYPE_BOOLEAN:
 				return BoolEval.valueOf(cell.getBooleanCellValue());
 			case Cell.CELL_TYPE_BLANK:
@@ -273,7 +263,7 @@
 					// Excel prefers to encode 'SUM()' as a tAttr token, but this evaluator
 					// expects the equivalent function token
 					byte nArgs = 1;  // tAttrSum always has 1 parameter
-					ptg = new FuncVarPtg("SUM", nArgs); 
+					ptg = new FuncVarPtg("SUM", nArgs);
 				}
 			}
 			if (ptg instanceof ControlPtg) {
@@ -381,7 +371,7 @@
 		}
 		int otherSheetIndex = _workbook.convertFromExternSheetIndex(externSheetIndex);
 		return new SheetRefEvaluator(this, tracker, _workbook, otherSheetIndex);
-		
+
 	}
 
 	/**
@@ -428,7 +418,7 @@
 		if (ptg instanceof MissingArgPtg) {
 			return MissingArgEval.instance;
 		}
-		if (ptg instanceof AreaErrPtg ||ptg instanceof RefErrorPtg 
+		if (ptg instanceof AreaErrPtg ||ptg instanceof RefErrorPtg
 				|| ptg instanceof DeletedArea3DPtg || ptg instanceof DeletedRef3DPtg) {
 				return ErrorEval.REF_INVALID;
 		}
@@ -465,25 +455,14 @@
 		}
 		return getEvalForPtg(ptgs[0], sheetIndex, tracker);
 	}
-	
+
 	/**
 	 * Used by the lazy ref evals whenever they need to get the value of a contained cell.
 	 */
-	/* package */ ValueEval evaluateReference(Sheet sheet, int sheetIndex, int rowIndex,
+	/* package */ ValueEval evaluateReference(EvaluationSheet sheet, int sheetIndex, int rowIndex,
 			int columnIndex, EvaluationTracker tracker) {
-		
-		Row row = sheet.getRow(rowIndex);
-		Cell cell;
-		if (row == null) {
-			cell = null;
-		} else {
-			cell = row.getCell(columnIndex);
- 		}
-		CellLocation cellLoc = getCellLoc(sheetIndex, rowIndex, columnIndex);
-		tracker.acceptDependency(cellLoc);
-		return internalEvaluate(cell, cellLoc, tracker);
-	}
-	private CellLocation getCellLoc(int sheetIndex, int rowIndex, int columnIndex) {
-		return new CellLocation(_workbookIx, sheetIndex, rowIndex, columnIndex);
+
+		EvaluationCell cell = sheet.getCell(rowIndex, columnIndex);
+		return evaluateAny(cell, sheetIndex, rowIndex, columnIndex, tracker);
 	}
 }

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=703083&r1=703082&r2=703083&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 Thu Oct  9 00:20:46 2008
@@ -45,20 +45,17 @@
      */
     void clearAllCachedResultValues();
 	/**
-	 * Sets the cached value for a plain (non-formula) cell.
-	 * Should be called whenever there are changes to individual input cells in the evaluated workbook.
+	 * Should be called to tell the cell value cache that the specified (value or formula) cell 
+	 * has changed.
 	 * Failure to call this method after changing cell values will cause incorrect behaviour
 	 * of the evaluate~ methods of this class
-	 * @param never <code>null</code>. Use {@link BlankEval#INSTANCE} when the cell is being 
-	 * cleared. Otherwise an instance of {@link NumberEval}, {@link StringEval}, {@link BoolEval}
-	 * or {@link ErrorEval} to represent a plain cell value.
 	 */
-    void setCachedPlainValue(Sheet sheet, int rowIndex, int columnIndex, ValueEval value);
+    void notifySetFormula(Cell cell);
 	/**
 	 * Should be called to tell the cell value cache that the specified cell has just become a
 	 * formula cell, or the formula text has changed 
 	 */
-	void notifySetFormula(HSSFSheet sheet, int rowIndex, int columnIndex);
+    void notifyDeleteCell(Cell cell);
     /**
      * If cell contains a formula, the formula is evaluated and returned,
      * else the CellValue simply copies the appropriate cell value from

Added: poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationCell.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationCell.java?rev=703083&view=auto
==============================================================================
--- poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationCell.java (added)
+++ poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationCell.java Thu Oct  9 00:20:46 2008
@@ -0,0 +1,78 @@
+/* ====================================================================
+   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.xssf.usermodel;
+
+import org.apache.poi.ss.formula.EvaluationCell;
+import org.apache.poi.ss.formula.EvaluationSheet;
+
+/**
+ * XSSF wrapper for a cell under evaluation
+ * 
+ * @author Josh Micich
+ */
+final class XSSFEvaluationCell implements EvaluationCell {
+
+	private final EvaluationSheet _evalSheet;
+	private final XSSFCell _cell;
+
+	public XSSFEvaluationCell(XSSFCell cell) {
+		_cell = cell;
+		_evalSheet = new XSSFEvaluationSheet((XSSFSheet)cell.getSheet());
+	}
+
+	public XSSFEvaluationCell(XSSFCell cell, XSSFEvaluationSheet evaluationSheet) {
+		_cell = cell;
+		_evalSheet = evaluationSheet;
+	}
+
+	// Note -  hashCode and equals defined according to underlying cell
+	public int hashCode() {
+		return _cell.hashCode();
+	}
+	public boolean equals(Object obj) {
+		return _cell == ((XSSFEvaluationCell)obj)._cell;
+	}
+
+	public XSSFCell getXSSFCell() {
+		return _cell;
+	}
+	public boolean getBooleanCellValue() {
+		return _cell.getBooleanCellValue();
+	}
+	public int getCellType() {
+		return _cell.getCellType();
+	}
+	public int getColumnIndex() {
+		return _cell.getCellNum();
+	}
+	public int getErrorCellValue() {
+		return _cell.getErrorCellValue();
+	}
+	public double getNumericCellValue() {
+		return _cell.getNumericCellValue();
+	}
+	public int getRowIndex() {
+		return _cell.getRowIndex();
+	}
+	public EvaluationSheet getSheet() {
+		return _evalSheet;
+	}
+	public String getStringCellValue() {
+		return _cell.getRichStringCellValue().getString();
+	}
+}

Added: poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationSheet.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationSheet.java?rev=703083&view=auto
==============================================================================
--- poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationSheet.java (added)
+++ poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationSheet.java Thu Oct  9 00:20:46 2008
@@ -0,0 +1,50 @@
+/* ====================================================================
+   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.xssf.usermodel;
+
+import org.apache.poi.ss.formula.EvaluationCell;
+import org.apache.poi.ss.formula.EvaluationSheet;
+
+/**
+ * XSSF wrapper for a sheet under evaluation
+ * 
+ * @author Josh Micich
+ */
+final class XSSFEvaluationSheet implements EvaluationSheet {
+
+	private final XSSFSheet _xs;
+
+	public XSSFEvaluationSheet(XSSFSheet sheet) {
+		_xs = sheet;
+	}
+
+	public XSSFSheet getXSSFSheet() {
+		return _xs;
+	}
+	public EvaluationCell getCell(int rowIndex, int columnIndex) {
+		XSSFRow row = _xs.getRow(rowIndex);
+		if (row == null) {
+			return null;
+		}
+		XSSFCell cell = row.getCell(columnIndex);
+		if (cell == null) {
+			return null;
+		}
+		return new XSSFEvaluationCell(cell, this);
+	}
+}

Modified: poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java (original)
+++ poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java Thu Oct  9 00:20:46 2008
@@ -1,16 +1,32 @@
+/* ====================================================================
+   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.xssf.usermodel;
 
 import org.apache.poi.hssf.record.formula.NamePtg;
 import org.apache.poi.hssf.record.formula.NameXPtg;
 import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.ss.formula.EvaluationCell;
 import org.apache.poi.ss.formula.EvaluationName;
+import org.apache.poi.ss.formula.EvaluationSheet;
 import org.apache.poi.ss.formula.EvaluationWorkbook;
 import org.apache.poi.ss.formula.FormulaParser;
 import org.apache.poi.ss.formula.FormulaParsingWorkbook;
 import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
 
 /**
@@ -67,7 +83,8 @@
 		return null;
 	}
 
-	public int getSheetIndex(Sheet sheet) {
+	public int getSheetIndex(EvaluationSheet evalSheet) {
+		XSSFSheet sheet = ((XSSFEvaluationSheet)evalSheet).getXSSFSheet();
 		return _uBook.getSheetIndex(sheet);
 	}
 
@@ -80,8 +97,8 @@
 		throw new RuntimeException("Not implemented yet");
 	}
 
-	public Sheet getSheet(int sheetIndex) {
-		return _uBook.getSheetAt(sheetIndex);
+	public EvaluationSheet getSheet(int sheetIndex) {
+		return new XSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex));
 	}
 
 	public ExternalSheet getExternalSheet(int externSheetIndex) {
@@ -95,10 +112,6 @@
 		return _uBook.getSheetIndex(sheetName);
 	}
 
-	public Workbook getWorkbook() {
-		return _uBook;
-	}
-
     /**
      * TODO - figure out what the hell this methods does in
      *  HSSF...
@@ -119,7 +132,8 @@
 		int ix = namePtg.getIndex();
 		return new Name(_uBook.getNameAt(ix), ix, this);
 	}
-	public Ptg[] getFormulaTokens(Cell cell) {
+	public Ptg[] getFormulaTokens(EvaluationCell evalCell) {
+		XSSFCell cell = ((XSSFEvaluationCell)evalCell).getXSSFCell();
 		XSSFEvaluationWorkbook frBook = XSSFEvaluationWorkbook.create(_uBook);
 		return FormulaParser.parse(cell.getCellFormula(), frBook);
 	}

Modified: poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java (original)
+++ poi/branches/ooxml/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFFormulaEvaluator.java Thu Oct  9 00:20:46 2008
@@ -19,14 +19,12 @@
 
 import java.util.Iterator;
 
-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.NumberEval;
 import org.apache.poi.hssf.record.formula.eval.StringEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
 import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.ss.formula.WorkbookEvaluator;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellValue;
@@ -61,11 +59,11 @@
 	public void clearAllCachedResultValues() {
 		_bookEvaluator.clearAllCachedResultValues();
 	}
-	public void setCachedPlainValue(Sheet sheet, int rowIndex, int columnIndex, ValueEval value) {
-		_bookEvaluator.setCachedPlainValue(sheet, rowIndex, columnIndex, value);
+	public void notifySetFormula(Cell cell) {
+		_bookEvaluator.notifyUpdateCell(new XSSFEvaluationCell((XSSFCell)cell));
 	}
-	public void notifySetFormula(HSSFSheet sheet, int rowIndex, int columnIndex) {
-		_bookEvaluator.notifySetFormula(sheet, rowIndex, columnIndex);
+	public void notifyDeleteCell(Cell cell) {
+		_bookEvaluator.notifyDeleteCell(new XSSFEvaluationCell((XSSFCell)cell));
 	}
 
 	/**
@@ -227,7 +225,7 @@
 	 * @param eval
 	 */
 	private CellValue evaluateFormulaCellValue(Cell cell) {
-		ValueEval eval = _bookEvaluator.evaluate(cell);
+		ValueEval eval = _bookEvaluator.evaluate(new XSSFEvaluationCell((XSSFCell) cell));
 		if (eval instanceof NumberEval) {
 			NumberEval ne = (NumberEval) eval;
 			return new CellValue(ne.getNumberValue());

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=703083&r1=703082&r2=703083&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 Thu Oct  9 00:20:46 2008
@@ -32,6 +32,7 @@
 import org.apache.poi.hssf.record.formula.FuncVarPtg;
 import org.apache.poi.hssf.record.formula.Ptg;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.EvaluationCell;
 import org.apache.poi.ss.formula.EvaluationListener;
 import org.apache.poi.ss.formula.WorkbookEvaluator;
 import org.apache.poi.ss.formula.WorkbookEvaluatorTestHelper;
@@ -168,6 +169,12 @@
 		assertEquals("-1000000.0-3000000.0", cell.getCellFormula());
 		assertEquals(-4000000, eva.evaluate(cell).getNumberValue(), 0);
 	}
+//	public static void main(String[] args) {
+//		new TestFormulaEvaluatorBugs().test44410();
+//		new TestFormulaEvaluatorBugs().testSlowEvaluate45376();
+//		new HSSFWorkbook();
+//		System.out.println("done");
+//	}
 
 	/**
 	 * Bug 44410: SUM(C:C) is valid in excel, and means a sum
@@ -309,7 +316,7 @@
 		public void onCacheHit(int sheetIndex, int srcRowNum, int srcColNum, ValueEval result) {
 			_countCacheHits++;
 		}
-		public void onStartEvaluate(int sheetIndex, int rowIndex, int columnIndex, Ptg[] ptgs) {
+		public void onStartEvaluate(EvaluationCell cell, ICacheEntry entry, Ptg[] ptgs) {
 			_countCacheMisses++;
 		}
 	}
@@ -341,7 +348,7 @@
 		HSSFCell cell = row.getCell(8);
 		EvalListener evalListener = new EvalListener();
 		WorkbookEvaluator evaluator = WorkbookEvaluatorTestHelper.createEvaluator(wb, evalListener);
-		evaluator.evaluate(cell);
+		evaluator.evaluate(HSSFEvaluationTestHelper.wrapCell(cell));
 		int evalCount = evalListener.getCountCacheMisses();
 		if (evalCount > 10) {
 			// Without caching, evaluating cell 'A9' takes 21845 evaluations which consumes

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/EvaluationListener.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/EvaluationListener.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/EvaluationListener.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/EvaluationListener.java Thu Oct  9 00:20:46 2008
@@ -19,6 +19,7 @@
 
 import org.apache.poi.hssf.record.formula.Ptg;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.usermodel.HSSFCell;
 
 /**
  * Tests should extend this class if they need to track the internal working of the {@link WorkbookEvaluator}.<br/>
@@ -28,26 +29,28 @@
  * @author Josh Micich
  */
 public abstract class EvaluationListener implements IEvaluationListener {
-	public void onCacheHit(int sheetIndex, int rowIndex, int srcColNum, ValueEval result) {
+	public void onCacheHit(int sheetIndex, int rowIndex, int columnIndex, ValueEval result) {
 		// do nothing 
 	}
-	public void onReadPlainValue(int sheetIndex, int srcRowNum, int srcColNum, ValueEval value) {
+	public void onReadPlainValue(int sheetIndex, int rowIndex, int columnIndex, ICacheEntry entry) {
 		// do nothing 
 	}
-	public void onStartEvaluate(int sheetIndex, int rowIndex, int columnIndex, Ptg[] ptgs) {
+	public void onStartEvaluate(EvaluationCell cell, ICacheEntry entry, Ptg[] ptgs) {
 		// do nothing 
 	}
-	public void onEndEvaluate(int sheetIndex, int rowIndex, int columnIndex, ValueEval result) {
+	public void onEndEvaluate(ICacheEntry entry, ValueEval result) {
 		// do nothing 
 	}
 	public void onClearWholeCache() {
 		// do nothing 
 	}
-	public void onClearCachedValue(int sheetIndex, int rowIndex, int columnIndex, ValueEval value) {
+	public void onClearCachedValue(ICacheEntry entry) {
 		// do nothing 
 	}
-	public void onClearDependentCachedValue(int sheetIndex, int rowIndex, int columnIndex,
-			ValueEval value,int depth) {
+	public void sortDependentCachedValues(ICacheEntry[] entries) {
+		// do nothing 
+	}
+	public void onClearDependentCachedValue(ICacheEntry entry, int depth) {
 		// do nothing 
 	}
 }

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestCellCacheEntry.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestCellCacheEntry.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestCellCacheEntry.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestCellCacheEntry.java Thu Oct  9 00:20:46 2008
@@ -17,13 +17,11 @@
 
 package org.apache.poi.ss.formula;
 
-import org.apache.poi.hssf.record.formula.eval.BlankEval;
+import junit.framework.TestCase;
+
 import org.apache.poi.hssf.record.formula.eval.NumberEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
-import junit.framework.AssertionFailedError;
-import junit.framework.TestCase;
-
 /**
  * Tests {@link CellCacheEntry}.
  *
@@ -32,22 +30,14 @@
 public class TestCellCacheEntry extends TestCase {
 
 	public void testBasic() {
-		CellCacheEntry cce = new CellCacheEntry();
-		cce.updatePlainValue(new NumberEval(42.0));
-		ValueEval ve = cce.getValue();
+		CellCacheEntry pcce = new PlainValueCellCacheEntry(new NumberEval(42.0));
+		ValueEval ve = pcce.getValue();
 		assertEquals(42, ((NumberEval)ve).getNumberValue(), 0.0);
 		
-		cce.setFormulaResult(new NumberEval(10.0), new CellLocation[] { });
-	}
-
-	public void testBlank() {
-		CellCacheEntry cce = new CellCacheEntry();
-		cce.updatePlainValue(BlankEval.INSTANCE);
-		try {
-			cce.updatePlainValue(BlankEval.INSTANCE);
-		} catch (IllegalStateException e) {
-			// bug was visible around svn r700356
-			throw new AssertionFailedError("cache entry does not handle blank values properly");
-		}
+		FormulaCellCacheEntry fcce = new FormulaCellCacheEntry();
+		fcce.updateFormulaResult(new NumberEval(10.0), CellCacheEntry.EMPTY_ARRAY, null);
+		
+		ve = fcce.getValue();
+		assertEquals(10, ((NumberEval)ve).getNumberValue(), 0.0);
 	}
 }

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestEvaluationCache.java Thu Oct  9 00:20:46 2008
@@ -19,7 +19,11 @@
 
 import java.io.PrintStream;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
@@ -33,10 +37,12 @@
 import org.apache.poi.hssf.record.formula.eval.StringEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
 import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFEvaluationTestHelper;
 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.util.CellReference;
+import org.apache.poi.ss.formula.PlainCellCache.Loc;
 
 /**
  * Tests {@link EvaluationCache}.  Makes sure that where possible (previously calculated) cached 
@@ -46,33 +52,89 @@
  * @author Josh Micich
  */
 public class TestEvaluationCache extends TestCase {
+	
+	private static final class FormulaCellCacheEntryComparer implements Comparator {
+
+		private final Map _formulaCellsByCacheEntry;
+
+		public FormulaCellCacheEntryComparer(Map formulaCellsByCacheEntry) {
+			_formulaCellsByCacheEntry = formulaCellsByCacheEntry;
+		}
+		private EvaluationCell getCell(Object a) {
+			return (EvaluationCell)_formulaCellsByCacheEntry.get(a);
+		}
+
+		public int compare(Object oa, Object ob) {
+			EvaluationCell a = getCell(oa);
+			EvaluationCell b = getCell(ob);
+			int cmp;
+			cmp = a.getRowIndex() - b.getRowIndex();
+			if (cmp != 0) {
+				return cmp;
+			}
+			cmp = a.getColumnIndex() - b.getColumnIndex();
+			if (cmp != 0) {
+				return cmp;
+			}
+			if (a.getSheet() == b.getSheet()) {
+				return 0;
+			}
+			throw new RuntimeException("Incomplete code - don't know how to order sheets");
+		}
+	}
+	
 	private static final class EvalListener extends EvaluationListener {
 
 		private final List _logList;
 		private final HSSFWorkbook _book;
+		private Map _formulaCellsByCacheEntry;
+		private Map _plainCellLocsByCacheEntry;
 
 		public EvalListener(HSSFWorkbook wb) {
 			_book = wb;
 			_logList = new ArrayList();
+			_formulaCellsByCacheEntry = new HashMap();
+			_plainCellLocsByCacheEntry = new HashMap();
 		}
 		public void onCacheHit(int sheetIndex, int rowIndex, int columnIndex, ValueEval result) {
 			log("hit", rowIndex, columnIndex, result);
 		}
-		public void onReadPlainValue(int sheetIndex, int rowIndex, int columnIndex, ValueEval value) {
-			log("value", rowIndex, columnIndex, value);
-		}
-		public void onStartEvaluate(int sheetIndex, int rowIndex, int columnIndex, Ptg[] ptgs) {
-			log("start", rowIndex, columnIndex, ptgs);
-		}
-		public void onEndEvaluate(int sheetIndex, int rowIndex, int columnIndex, ValueEval result) {
-			log("end", rowIndex, columnIndex, result);
+		public void onReadPlainValue(int sheetIndex, int rowIndex, int columnIndex, ICacheEntry entry) {
+			Loc loc = new Loc(0, sheetIndex, rowIndex, columnIndex);
+			_plainCellLocsByCacheEntry.put(entry, loc);
+			log("value", rowIndex, columnIndex, entry.getValue());
+		}
+		public void onStartEvaluate(EvaluationCell cell, ICacheEntry entry, Ptg[] ptgs) {
+			_formulaCellsByCacheEntry.put(entry, cell);
+			log("start", cell.getRowIndex(), cell.getColumnIndex(), ptgs);
+		}
+		public void onEndEvaluate(ICacheEntry entry, ValueEval result) {
+			EvaluationCell cell = (EvaluationCell) _formulaCellsByCacheEntry.get(entry);
+			log("end", cell.getRowIndex(), cell.getColumnIndex(), result);
+		}
+		public void onClearCachedValue(ICacheEntry entry) {
+			int rowIndex;
+			int columnIndex;
+			EvaluationCell cell = (EvaluationCell) _formulaCellsByCacheEntry.get(entry);
+			if (cell == null) {
+				Loc loc = (Loc)_plainCellLocsByCacheEntry.get(entry);
+				if (loc == null) {
+					throw new IllegalStateException("can't find cell or location");
+				}
+				rowIndex = loc.getRowIndex();
+				columnIndex = loc.getColumnIndex();
+			} else {
+				rowIndex = cell.getRowIndex();
+				columnIndex = cell.getColumnIndex();
+			}
+			log("clear", rowIndex, columnIndex, entry.getValue());
 		}
-		public void onClearCachedValue(int sheetIndex, int rowIndex, int columnIndex, ValueEval value) {
-			log("clear", rowIndex, columnIndex, value);
+		public void sortDependentCachedValues(ICacheEntry[] entries) {
+			Arrays.sort(entries, new FormulaCellCacheEntryComparer(_formulaCellsByCacheEntry));
 		}
-		public void onClearDependentCachedValue(int sheetIndex, int rowIndex, int columnIndex,
-				ValueEval value,int depth) {
-			log("clear" + depth, rowIndex, columnIndex, value);
+		public void onClearDependentCachedValue(ICacheEntry entry, int depth) {
+			EvaluationCell cell = (EvaluationCell) _formulaCellsByCacheEntry.get(entry);
+   			log("clear" + depth, cell.getRowIndex(), cell.getColumnIndex(),  entry.getValue());
 		}
 		private void log(String tag, int rowIndex, int columnIndex, Object value) {
 			StringBuffer sb = new StringBuffer(64);
@@ -139,19 +201,23 @@
 			_sheet = _wb.createSheet("Sheet1");
 		}
 
+		private static EvaluationCell wrapCell(HSSFCell cell) {
+			return HSSFEvaluationTestHelper.wrapCell(cell);
+		}
+
 		public void setCellValue(String cellRefText, double value) {
 			HSSFCell cell = getOrCreateCell(cellRefText);
 			// be sure to blank cell, in case it is currently a formula
 			cell.setCellType(HSSFCell.CELL_TYPE_BLANK);
 			// otherwise this line will only set the formula cached result;
 			cell.setCellValue(value);
-			_evaluator.setCachedPlainValue(_sheet, cell.getRowIndex(), cell.getCellNum(), new NumberEval(value));
+			_evaluator.notifyUpdateCell(wrapCell(cell));
 		}
 
 		public void setCellFormula(String cellRefText, String formulaText) {
 			HSSFCell cell = getOrCreateCell(cellRefText);
 			cell.setCellFormula(formulaText);
-			_evaluator.notifySetFormula(_sheet, cell.getRowIndex(), cell.getCellNum());
+			_evaluator.notifyUpdateCell(wrapCell(cell));
 		}
 
 		private HSSFCell getOrCreateCell(String cellRefText) {
@@ -170,7 +236,7 @@
 		}
 
 		public ValueEval evaluateCell(String cellRefText) {
-			return _evaluator.evaluate(getOrCreateCell(cellRefText));
+			return _evaluator.evaluate(wrapCell(getOrCreateCell(cellRefText)));
 		}
 
 		public String[] getAndClearLog() {
@@ -243,6 +309,7 @@
 		// change a low level cell
 		ms.setCellValue("D1", 10);
 		confirmLog(ms, new String[] {
+				"clear D1 10",
 				"clear1 C1 54",
 				"clear2 B1 8",
 				"clear3 A1 46",
@@ -272,6 +339,7 @@
 
 		ms.setCellValue("B3", 3); // B3 is in the middle of the dependency tree
 		confirmLog(ms, new String[] {
+				"clear B3 3",
 				"clear1 B2 46",
 				"clear2 A1 46",
 		});
@@ -296,6 +364,7 @@
 		ms.getAndClearLog();
 		ms.setCellFormula("B2", "B3*C2-C3"); // used to be "B3*C1-C2"
 		confirmLog(ms, new String[] {
+			"clear B2 46",
 			"clear1 A1 46",
 		});
 
@@ -307,7 +376,8 @@
 					"hit B3 2",
 					"hit C2 62",
 					"start C3 SUM(D3:E4)",
-						"hit D3 16", "hit E3 17", "value D4 #BLANK#", "value E4 #BLANK#",
+						"hit D3 16", "hit E3 17", 
+//						"value D4 #BLANK#", "value E4 #BLANK#",
 					"end C3 33",
 				"end B2 91",
 			"end A1 91",
@@ -320,6 +390,7 @@
 		// Now change a value that should no longer affect B2
 		ms.setCellValue("D1", 11);
 		confirmLog(ms, new String[] {
+			"clear D1 11",
 			"clear1 C1 54",
 			// note there is no "clear2 B2 91" here because B2 doesn't depend on C1 anymore
 			"clear2 B1 8",
@@ -342,7 +413,7 @@
 
 	/**
 	 * verifies that when updating a plain cell, depending (formula) cell cached values are cleared
-	 * only when the palin cell's value actually changes
+	 * only when the plain cell's value actually changes
 	 */
 	public void testRedundantUpdate() {
 		MySheet ms = new MySheet();
@@ -369,6 +440,7 @@
 
 		ms.setCellValue("B1", 11); // value changing
 		confirmLog(ms, new String[] {
+			"clear B1 11",
 			"clear1 A1 25",	// expect consuming formula cached result to get cleared
 		});
 		confirmEvaluate(ms, "A1", 24);
@@ -434,9 +506,55 @@
 			"hit D1 25",
 			"end A1 25",
 		});
-
 	}
 
+	public void testBlankCells() {
+
+
+		MySheet ms = new MySheet();
+
+		ms.setCellFormula("A1", "sum(B1:D4,B5:E6)");
+		ms.setCellValue("B1", 12);
+		ms.clearAllCachedResultValues();
+		ms.getAndClearLog();
+
+		confirmEvaluate(ms, "A1", 12);
+		confirmLog(ms, new String[] {
+			"start A1 SUM(B1:D4,B5:E6)",
+			"value B1 12",
+			"end A1 12",
+		});
+		ms.setCellValue("B6", 2);
+		ms.getAndClearLog();
+
+		confirmEvaluate(ms, "A1", 14);
+		confirmLog(ms, new String[] {
+			"start A1 SUM(B1:D4,B5:E6)",
+			"hit B1 12",
+			"hit B6 2",
+			"end A1 14",
+		});
+		ms.setCellValue("E4", 2);
+		ms.getAndClearLog();
+
+		confirmEvaluate(ms, "A1", 14);
+		confirmLog(ms, new String[] {
+			"hit A1 14",
+		});
+		
+		ms.setCellValue("D1", 1);
+		ms.getAndClearLog();
+
+		confirmEvaluate(ms, "A1", 15);
+		confirmLog(ms, new String[] {
+			"start A1 SUM(B1:D4,B5:E6)",
+			"hit B1 12",
+			"hit D1 1",
+			"hit B6 2",
+			"end A1 15",
+		});
+	}
+	
 	private static void confirmEvaluate(MySheet ms, String cellRefText, double expectedValue) {
 		ValueEval v = ms.evaluateCell(cellRefText);
 		assertEquals(NumberEval.class, v.getClass());

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java?rev=703083&r1=703082&r2=703083&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/ss/formula/TestWorkbookEvaluator.java Thu Oct  9 00:20:46 2008
@@ -127,18 +127,21 @@
 		confirmEvaluation(264, evaluatorA, cell);
 
 		// change [wbB]BSheet1!B3 (from 50 to 60)
-		bSheet1.getRow(2).getCell(1).setCellValue(60);
-		evaluatorB.setCachedPlainValue(bSheet1, 2, 1, new NumberEval(60));
+		HSSFCell cellB3 = bSheet1.getRow(2).getCell(1);
+		cellB3.setCellValue(60);
+		evaluatorB.notifyUpdateCell(cellB3);
 		confirmEvaluation(274, evaluatorA, cell);
 
 		// change [wbA]ASheet1!A3 (from 100 to 80)
-		aSheet1.getRow(2).getCell(0).setCellValue(80);
-		evaluatorA.setCachedPlainValue(aSheet1, 2, 0, new NumberEval(80));
+		HSSFCell cellA3 = aSheet1.getRow(2).getCell(0);
+		cellA3.setCellValue(80);
+		evaluatorA.notifyUpdateCell(cellA3);
 		confirmEvaluation(234, evaluatorA, cell);
 
 		// change [wbA]AnotherSheet!A1 (from 2 to 3)
-		wbA.getSheetAt(1).getRow(0).getCell(0).setCellValue(3);
-		evaluatorA.setCachedPlainValue(wbA.getSheetAt(1), 0, 0, new NumberEval(3));
+		HSSFCell cellA1 = wbA.getSheetAt(1).getRow(0).getCell(0);
+		cellA1.setCellValue(3);
+		evaluatorA.notifyUpdateCell(cellA1);
 		confirmEvaluation(235, evaluatorA, cell);
 	}
 



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org