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 2009/12/26 00:04:06 UTC

svn commit: r893897 - in /poi/trunk/src: java/org/apache/poi/hssf/dev/ java/org/apache/poi/hssf/record/ java/org/apache/poi/hssf/record/aggregates/ java/org/apache/poi/hssf/usermodel/ java/org/apache/poi/ss/formula/ java/org/apache/poi/ss/usermodel/ ja...

Author: josh
Date: Fri Dec 25 23:04:04 2009
New Revision: 893897

URL: http://svn.apache.org/viewvc?rev=893897&view=rev
Log:
Added CellRange return type for Sheet array formula methods.  Renamed new test classes to make it clear that array formula evaluation is not being tested yet.  Added extra test cases.

Added:
    poi/trunk/src/java/org/apache/poi/ss/usermodel/CellRange.java
    poi/trunk/src/java/org/apache/poi/ss/util/SSCellRange.java
    poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetUpdateArrayFormulas.java
      - copied, changed from r893896, poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFArrayFormulas.java
    poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheetUpdateArrayFormulas.java
      - copied, changed from r893896, poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFArrayFormulas.java
    poi/trunk/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetUpdateArrayFormulas.java
      - copied, changed from r893896, poi/trunk/src/testcases/org/apache/poi/ss/usermodel/BaseTestArrayFormulas.java
Removed:
    poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFArrayFormulas.java
    poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFArrayFormulas.java
    poi/trunk/src/testcases/org/apache/poi/ss/usermodel/BaseTestArrayFormulas.java
Modified:
    poi/trunk/src/java/org/apache/poi/hssf/dev/BiffViewer.java
    poi/trunk/src/java/org/apache/poi/hssf/record/ArrayRecord.java
    poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
    poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java
    poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
    poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
    poi/trunk/src/java/org/apache/poi/ss/formula/OperandClassTransformer.java
    poi/trunk/src/java/org/apache/poi/ss/usermodel/Cell.java
    poi/trunk/src/java/org/apache/poi/ss/usermodel/Sheet.java
    poi/trunk/src/java/org/apache/poi/ss/util/CellRangeAddress.java
    poi/trunk/src/java/org/apache/poi/ss/util/CellReference.java
    poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java
    poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
    poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/AllXSSFUsermodelTests.java
    poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java
    poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestSharedValueManager.java
    poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java

Modified: poi/trunk/src/java/org/apache/poi/hssf/dev/BiffViewer.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/dev/BiffViewer.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/dev/BiffViewer.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/dev/BiffViewer.java Fri Dec 25 23:04:04 2009
@@ -307,8 +307,8 @@
 						System.setProperty("poi.deserialize.escher", "true");
 					} else if ("--rawhex".equals(arg)) {
 						rawhex = true;
-                    } else if ("--noheader".equals(arg)) {
-                        noheader = true;
+					} else if ("--noheader".equals(arg)) {
+						noheader = true;
 					} else {
 						throw new CommandParseException("Unexpected option '" + arg + "'");
 					}

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/ArrayRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/ArrayRecord.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/ArrayRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/ArrayRecord.java Fri Dec 25 23:04:04 2009
@@ -17,9 +17,7 @@
 
 package org.apache.poi.hssf.record;
 
-import org.apache.poi.hssf.record.formula.AreaPtgBase;
 import org.apache.poi.hssf.record.formula.Ptg;
-import org.apache.poi.hssf.record.formula.RefPtgBase;
 import org.apache.poi.hssf.util.CellRangeAddress8Bit;
 import org.apache.poi.ss.formula.Formula;
 import org.apache.poi.util.HexDump;
@@ -31,7 +29,6 @@
  * Treated in a similar way to SharedFormulaRecord
  *
  * @author Josh Micich
- * @author Vladimirs Abramovs(Vladimirs.Abramovs at exigenservices.com) - Array Formula support
  */
 public final class ArrayRecord extends SharedValueRecordBase {
 
@@ -52,7 +49,7 @@
 		_formula = Formula.read(formulaTokenLen, in, totalFormulaLen);
 	}
 
-	public ArrayRecord(Formula formula, CellRangeAddress8Bit range ) {
+	public ArrayRecord(Formula formula, CellRangeAddress8Bit range) {
 		super(range);
 		_options = 0; //YK: Excel 2007 leaves this field unset
 		_field3notUsed = 0;
@@ -66,13 +63,12 @@
 		return (_options & OPT_CALCULATE_ON_OPEN) != 0;
 	}
 
-    public void setOptions(int val){
-        _options = val;
-    }
-
-    protected int getExtraDataSize() {
-		return 2 + 4
-			+ _formula.getEncodedSize();
+	public Ptg[] getFormulaTokens() {
+		return _formula.getTokens();
+	}
+
+	protected int getExtraDataSize() {
+		return 2 + 4 + _formula.getEncodedSize();
 	}
 	protected void serializeExtraData(LittleEndianOutput out) {
 		out.writeShort(_options);
@@ -99,42 +95,4 @@
 		sb.append("]");
 		return sb.toString();
 	}
-
-	/**
-	 * @return the equivalent {@link Ptg} array that the formula would have,
-	 *         were it not shared.
-	 */
-    public Ptg[] getFormulaTokens() {
-        return _formula.getTokens();
-        /*
-        YK: I don't understand all t
-
-        int formulaRow = this.getFirstRow();
-        int formulaColumn = this.getLastColumn();
-
-        // Use SharedFormulaRecord static method to convert formula
-
-        Ptg[] ptgs = _formula.getTokens();
-
-        // Convert from relative addressing to absolute
-        // because all formulas in array need to be referenced to the same
-        // ref/range
-        for (int i = 0; i < ptgs.length; i++) {
-            Ptg ptg = ptgs[i];
-            if (ptg instanceof AreaPtgBase) {
-                AreaPtgBase aptg = (AreaPtgBase) ptg;
-                aptg.setFirstRowRelative(false);
-                aptg.setLastRowRelative(false);
-                aptg.setFirstColRelative(false);
-                aptg.setLastColRelative(false);
-
-            } else if (ptg instanceof RefPtgBase) {
-                RefPtgBase rptg = (RefPtgBase) ptg;
-                rptg.setRowRelative(false);
-                rptg.setColRelative(false);
-            }
-        }
-        return SharedFormulaRecord.convertSharedFormulas(ptgs, formulaRow, formulaColumn);
-        */
-    }
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java Fri Dec 25 23:04:04 2009
@@ -186,9 +186,9 @@
 	}
 
 	public Ptg[] getFormulaTokens() {
-        if (_sharedFormulaRecord != null) {
-            return _sharedFormulaRecord.getFormulaTokens(_formulaRecord);
-        }
+		if (_sharedFormulaRecord != null) {
+			return _sharedFormulaRecord.getFormulaTokens(_formulaRecord);
+		}
 		CellReference expRef = _formulaRecord.getFormula().getExpReference();
 		if (expRef != null) {
 			ArrayRecord arec = _sharedValueManager.getArrayRecord(expRef.getRow(), expRef.getCol());
@@ -226,15 +226,14 @@
 			_sharedValueManager.unlink(_sharedFormulaRecord);
 		}
 	}
+	public boolean isPartOfArrayFormula() {
+		if (_sharedFormulaRecord != null) {
+			return false;
+		}
+		return _formulaRecord.getFormula().getExpReference() != null;
+	}
 
-    public boolean isPartOfArrayFormula() {
-        if (_sharedFormulaRecord != null) {
-            return false;
-        }
-        return _formulaRecord.getFormula().getExpReference() != null;
-    }
-
-    public CellRangeAddress getArrayFormulaRange() {
+	public CellRangeAddress getArrayFormulaRange() {
 		if (_sharedFormulaRecord != null) {
 			throw new IllegalStateException("not an array formula cell.");
 		}
@@ -243,14 +242,14 @@
 			throw new IllegalStateException("not an array formula cell.");
 		}
 		ArrayRecord arec = _sharedValueManager.getArrayRecord(expRef.getRow(), expRef.getCol());
-        if (arec == null) {
-            throw new IllegalStateException("ArrayRecord was not found for the locator " + expRef.formatAsString());
-        }
+		if (arec == null) {
+			throw new IllegalStateException("ArrayRecord was not found for the locator " + expRef.formatAsString());
+		}
 		CellRangeAddress8Bit a = arec.getRange();
 		return new CellRangeAddress(a.getFirstRow(), a.getLastRow(), a.getFirstColumn(),a.getLastColumn());
 	}
-    
-    public void setArrayFormula(CellRangeAddress r, Ptg[] ptgs) {
+
+	public void setArrayFormula(CellRangeAddress r, Ptg[] ptgs) {
 
 		ArrayRecord arr = new ArrayRecord(Formula.create(ptgs), new CellRangeAddress8Bit(r.getFirstRow(), r.getLastRow(), r.getFirstColumn(), r.getLastColumn()));
 		_sharedValueManager.addArrayRecord(arr);

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/SharedValueManager.java Fri Dec 25 23:04:04 2009
@@ -120,7 +120,7 @@
 		return new SharedValueManager(
 			new SharedFormulaRecord[0], new CellReference[0], new ArrayRecord[0], new TableRecord[0]);
 	}
-    private final List<ArrayRecord> _arrayRecords;
+	private final List<ArrayRecord> _arrayRecords;
 	private final TableRecord[] _tableRecords;
 	private final Map<SharedFormulaRecord, SharedFormulaGroup> _groupsBySharedFormulaRecord;
 	/** cached for optimization purposes */
@@ -132,8 +132,7 @@
 		if (nShF != firstCells.length) {
 			throw new IllegalArgumentException("array sizes don't match: " + nShF + "!=" + firstCells.length + ".");
 		}
-		_arrayRecords = new ArrayList<ArrayRecord>();
-        _arrayRecords.addAll(Arrays.asList(arrayRecords));
+		_arrayRecords = toList(arrayRecords);
 		_tableRecords = tableRecords;
 		Map<SharedFormulaRecord, SharedFormulaGroup> m = new HashMap<SharedFormulaRecord, SharedFormulaGroup>(nShF * 3 / 2);
 		for (int i = 0; i < nShF; i++) {
@@ -143,6 +142,25 @@
 		_groupsBySharedFormulaRecord = m;
 	}
 
+	/**
+	 * @return a modifiable list, independent of the supplied array
+	 */
+	private static <Z> List<Z> toList(Z[] zz) {
+		List<Z> result = new ArrayList<Z>(zz.length);
+		for (int i = 0; i < zz.length; i++) {
+			result.add(zz[i]);
+		}
+		return result;
+	}
+
+	/**
+	 * @param firstCells
+	 * @param recs list of sheet records (possibly contains records for other parts of the Excel file)
+	 * @param startIx index of first row/cell record for current sheet
+	 * @param endIx one past index of last row/cell record for current sheet.  It is important
+	 * that this code does not inadvertently collect <tt>SharedFormulaRecord</tt>s from any other
+	 * sheet (which could happen if endIx is chosen poorly).  (see bug 44449)
+	 */
 	public static SharedValueManager create(SharedFormulaRecord[] sharedFormulaRecords,
 			CellReference[] firstCells, ArrayRecord[] arrayRecords, TableRecord[] tableRecords) {
 		if (sharedFormulaRecords.length + firstCells.length + arrayRecords.length + tableRecords.length < 1) {
@@ -250,8 +268,7 @@
 		// The first cell will be the top left in the range.  So we can match the
 		// ARRAY/TABLE record directly.
 
-		for (int i = 0; i < _tableRecords.length; i++) {
-			TableRecord tr = _tableRecords[i];
+		for (TableRecord tr : _tableRecords) {
 			if (tr.isFirstCell(row, column)) {
 				return tr;
 			}
@@ -270,46 +287,47 @@
 	 */
 	public void unlink(SharedFormulaRecord sharedFormulaRecord) {
 		SharedFormulaGroup svg = _groupsBySharedFormulaRecord.remove(sharedFormulaRecord);
-		_groups = null; // be sure to reset cached value
 		if (svg == null) {
 			throw new IllegalStateException("Failed to find formulas for shared formula");
 		}
+		_groups = null; // be sure to reset cached value
 		svg.unlinkSharedFormulas();
 	}
 
-    /**
-     * Add specified Array Record.
-     */
-    public void addArrayRecord(ArrayRecord ar) {
-        // could do a check here to make sure none of the ranges overlap
-        _arrayRecords.add(ar);
-    }
-
-    /**
-     * Removes the {@link ArrayRecord} for the cell group containing the specified cell.
-     * The caller should clear (set blank) all cells in the returned range.
-     * @return the range of the array formula which was just removed. Never <code>null</code>.
-     */
-    public CellRangeAddress8Bit removeArrayFormula(int rowIndex, int columnIndex) {
-        for (ArrayRecord ar : _arrayRecords) {
-            if (ar.isInRange(rowIndex, columnIndex)) {
-                _arrayRecords.remove(ar);
-                return ar.getRange();
-            }
-        }
-        throw new IllegalArgumentException("Specified cell is not part of an array formula.");
-    }
-
-    /**
-     * @return the shared ArrayRecord identified by (firstRow, firstColumn). never <code>null</code>.
-     */
-    public ArrayRecord getArrayRecord(int firstRow, int firstColumn) {
-        for(ArrayRecord ar : _arrayRecords) {
-            if(ar.isFirstCell(firstRow, firstColumn)) {
-                return ar;
-            }
-        }
-        return null;
-    }
-    
+	/**
+	 * Add specified Array Record.
+	 */
+	public void addArrayRecord(ArrayRecord ar) {
+		// could do a check here to make sure none of the ranges overlap
+		_arrayRecords.add(ar);
+	}
+
+	/**
+	 * Removes the {@link ArrayRecord} for the cell group containing the specified cell.
+	 * The caller should clear (set blank) all cells in the returned range.
+	 * @return the range of the array formula which was just removed. Never <code>null</code>.
+	 */
+	public CellRangeAddress8Bit removeArrayFormula(int rowIndex, int columnIndex) {
+		for (ArrayRecord ar : _arrayRecords) {
+			if (ar.isInRange(rowIndex, columnIndex)) {
+				_arrayRecords.remove(ar);
+				return ar.getRange();
+			}
+		}
+		String ref = new CellReference(rowIndex, columnIndex, false, false).formatAsString();
+		throw new IllegalArgumentException("Specified cell " + ref
+				+ " is not part of an array formula.");
+	}
+
+	/**
+	 * @return the shared ArrayRecord identified by (firstRow, firstColumn). never <code>null</code>.
+	 */
+	public ArrayRecord getArrayRecord(int firstRow, int firstColumn) {
+		for(ArrayRecord ar : _arrayRecords) {
+			if(ar.isFirstCell(firstRow, firstColumn)) {
+				return ar;
+			}
+		}
+		return null;
+	}
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java Fri Dec 25 23:04:04 2009
@@ -52,8 +52,8 @@
 import org.apache.poi.ss.usermodel.Hyperlink;
 import org.apache.poi.ss.usermodel.RichTextString;
 import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.NumberToTextConverter;
 import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.ss.util.NumberToTextConverter;
 import org.apache.poi.ss.formula.FormulaType;
 import org.apache.poi.ss.SpreadsheetVersion;
 import org.apache.poi.util.POILogger;
@@ -1179,7 +1179,8 @@
     public CellRangeAddress getArrayFormulaRange() {
         if (_cellType != CELL_TYPE_FORMULA) {
             String ref = new CellReference(this).formatAsString();
-            throw new IllegalStateException("Cell "+ref+" is not part of an array formula");
+            throw new IllegalStateException("Cell " + ref
+                    + " is not part of an array formula.");
         }
         return ((FormulaRecordAggregate)_record).getArrayFormulaRange();
     }

Modified: poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java Fri Dec 25 23:04:04 2009
@@ -53,10 +53,12 @@
 import org.apache.poi.hssf.util.Region;
 import org.apache.poi.ss.formula.FormulaType;
 import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellRange;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.ss.util.SSCellRange;
 import org.apache.poi.ss.SpreadsheetVersion;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
@@ -69,6 +71,8 @@
  * @author  Shawn Laubach (slaubach at apache dot org) (Just a little)
  * @author  Jean-Pierre Paris (jean-pierre.paris at m4x dot org) (Just a little, too)
  * @author  Yegor Kozlov (yegor at apache.org) (Autosizing columns)
+ * @author  Josh Micich
+ * @author  Petr Udalau(Petr.Udalau at exigenservices.com) - set/remove array formulas
  */
 public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
     private static final POILogger log = POILogFactory.getLogger(HSSFSheet.class);
@@ -646,7 +650,7 @@
      */
     public void setRightToLeft(boolean value)
     {
-	    _sheet.getWindowTwo().setArabic(value);
+        _sheet.getWindowTwo().setArabic(value);
     }
 
     /**
@@ -656,7 +660,7 @@
      */
     public boolean isRightToLeft()
     {
-	    return _sheet.getWindowTwo().getArabic();
+        return _sheet.getWindowTwo().getArabic();
     }
 
     /**
@@ -1875,17 +1879,19 @@
         return wb.getSheetName(idx);
     }
 
-    public HSSFCell[] setArrayFormula(String formula, CellRangeAddress range) {
-        HSSFCell[] cells = new HSSFCell[range.getNumberOfCells()];
-        int k = 0;
-
-        // make sure the formula parses OK first
-        int sheetIndex = _workbook.getSheetIndex(this);
-        Ptg[] ptgs = HSSFFormulaParser.parse(formula, _workbook, FormulaType.ARRAY, sheetIndex);
+    /**
+     * Also creates cells if they don't exist
+     */
+    private CellRange<HSSFCell> getCellRange(CellRangeAddress range) {
         int firstRow = range.getFirstRow();
         int firstColumn = range.getFirstColumn();
-        for (int rowIn = firstRow; rowIn <= range.getLastRow(); rowIn++) {
-            for (int colIn = firstColumn; colIn <= range.getLastColumn(); colIn++) {
+        int lastRow = range.getLastRow();
+        int lastColumn = range.getLastColumn();
+        int height = lastRow - firstRow + 1;
+        int width = lastColumn - firstColumn + 1;
+        List<HSSFCell> temp = new ArrayList<HSSFCell>(height*width);
+        for (int rowIn = firstRow; rowIn <= lastRow; rowIn++) {
+            for (int colIn = firstColumn; colIn <= lastColumn; colIn++) {
                 HSSFRow row = getRow(rowIn);
                 if (row == null) {
                     row = createRow(rowIn);
@@ -1894,38 +1900,45 @@
                 if (cell == null) {
                     cell = row.createCell(colIn);
                 }
-                cell.setCellArrayFormula(range);
-                cells[k++] = cell;
+                temp.add(cell);
             }
         }
-        HSSFCell mainArrayFormulaCell = getRow(firstRow).getCell(firstColumn);
+        return SSCellRange.create(firstRow, firstColumn, height, width, temp, HSSFCell.class);
+    }
+
+    public CellRange<HSSFCell> setArrayFormula(String formula, CellRangeAddress range) {
+        // make sure the formula parses OK first
+        int sheetIndex = _workbook.getSheetIndex(this);
+        Ptg[] ptgs = HSSFFormulaParser.parse(formula, _workbook, FormulaType.ARRAY, sheetIndex);
+        CellRange<HSSFCell> cells = getCellRange(range);
+
+        for (HSSFCell c : cells) {
+            c.setCellArrayFormula(range);
+        }
+        HSSFCell mainArrayFormulaCell = cells.getTopLeftCell();
         FormulaRecordAggregate agg = (FormulaRecordAggregate)mainArrayFormulaCell.getCellValueRecord();
         agg.setArrayFormula(range, ptgs);
         return cells;
     }
 
 
-    public HSSFCell[] removeArrayFormula(Cell cell) {
-        ArrayList<HSSFCell> lst = new ArrayList<HSSFCell>();
+    public CellRange<HSSFCell> removeArrayFormula(Cell cell) {
+        if (cell.getSheet() != this) {
+            throw new IllegalArgumentException("Specified cell does not belong to this sheet.");
+        }
         CellValueRecordInterface rec = ((HSSFCell) cell).getCellValueRecord();
         if (!(rec instanceof FormulaRecordAggregate)) {
             String ref = new CellReference(cell).formatAsString();
-            throw new IllegalArgumentException("Cell " + ref + " is not part of an array formula");
+            throw new IllegalArgumentException("Cell " + ref + " is not part of an array formula.");
         }
         FormulaRecordAggregate fra = (FormulaRecordAggregate) rec;
         CellRangeAddress range = fra.removeArrayFormula(cell.getRowIndex(), cell.getColumnIndex());
-        if (range == null) {
-            String ref = new CellReference(cell).formatAsString();
-            throw new IllegalArgumentException("Cell " + ref + " is not part of an array formula");
-        }
+
+        CellRange<HSSFCell> result = getCellRange(range);
         // clear all cells in the range
-        for (int rowIn = range.getFirstRow(); rowIn <= range.getLastRow(); rowIn++) {
-            for (int colIn = range.getFirstColumn(); colIn <= range.getLastColumn(); colIn++) {
-                HSSFCell rCell = getRow(rowIn).getCell(colIn);
-                rCell.setCellType(Cell.CELL_TYPE_BLANK);
-                lst.add(rCell);
-             }
+        for (Cell c : result) {
+            c.setCellType(Cell.CELL_TYPE_BLANK);
         }
-        return lst.toArray(new HSSFCell[lst.size()]);
+        return result;
     }
 }

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/OperandClassTransformer.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/OperandClassTransformer.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/OperandClassTransformer.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/OperandClassTransformer.java Fri Dec 25 23:04:04 2009
@@ -72,10 +72,10 @@
 			case FormulaType.CELL:
 				rootNodeOperandClass = Ptg.CLASS_VALUE;
 				break;
-            case FormulaType.ARRAY:
-                rootNodeOperandClass = Ptg.CLASS_ARRAY;
-                break;
-            case FormulaType.NAMEDRANGE:
+			case FormulaType.ARRAY:
+				rootNodeOperandClass = Ptg.CLASS_ARRAY;
+				break;
+			case FormulaType.NAMEDRANGE:
 			case FormulaType.DATAVALIDATION_LIST:
 				rootNodeOperandClass = Ptg.CLASS_REF;
 				break;

Modified: poi/trunk/src/java/org/apache/poi/ss/usermodel/Cell.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/usermodel/Cell.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/usermodel/Cell.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/usermodel/Cell.java Fri Dec 25 23:04:04 2009
@@ -361,20 +361,17 @@
     void removeCellComment();
 
     /**
-     * Returns hyperlink associated with this cell
-     *
      * @return hyperlink associated with this cell or <code>null</code> if not found
      */
     Hyperlink getHyperlink();
 
     /**
-     * Assign a hypelrink to this cell
+     * Assign a hyperlink to this cell
      *
-     * @param link hypelrink associated with this cell
+     * @param link hyperlink associated with this cell
      */
     void setHyperlink(Hyperlink link);
 
-
     /**
      * Only valid for array formula cells
      *
@@ -386,5 +383,4 @@
      * @return <code>true</code> if this cell is part of group of cells having a common array formula.
      */
     boolean isPartOfArrayFormulaGroup();
-
 }

Added: poi/trunk/src/java/org/apache/poi/ss/usermodel/CellRange.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/usermodel/CellRange.java?rev=893897&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/usermodel/CellRange.java (added)
+++ poi/trunk/src/java/org/apache/poi/ss/usermodel/CellRange.java Fri Dec 25 23:04:04 2009
@@ -0,0 +1,66 @@
+/* ====================================================================
+   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.Iterator;
+
+
+/**
+ * Represents a rectangular region of a {@link Sheet}
+ *
+ * @author Josh Micich
+ */
+public interface CellRange<C extends Cell> extends Iterable<C> {
+
+	int getWidth();
+	int getHeight();
+	/**
+	 * Gets the number of cells in this range.
+	 * @return <tt>height * width </tt>
+	 */
+	int size();
+	String getReferenceText();
+
+	/**
+	 * @return the cell at relative coordinates (0,0).  Never <code>null</code>.
+	 */
+	C getTopLeftCell();
+
+	/**
+	 * @param relativeRowIndex must be between <tt>0</tt> and <tt>height-1</tt>
+	 * @param relativeColumnIndex must be between <tt>0</tt> and <tt>width-1</tt>
+	 * @return the cell at the specified coordinates.  Never <code>null</code>.
+	 */
+	C getCell(int relativeRowIndex, int relativeColumnIndex);
+	/**
+	 * @return a flattened array of all the cells in this {@link CellRange}
+	 */
+	C[] getFlattenedCells();
+	/**
+	 * @return a 2-D array of all the cells in this {@link CellRange}.  The first
+	 * array dimension is the row index (values <tt>0...height-1</tt>)
+	 * and the second dimension is the column index (values <tt>0...width-1</tt>)
+	 */
+	C[][] getCells();
+
+	/**
+	 * @return an {@link Iterator} over all cells in this range.  Iteration starts
+	 * with all cells in the first row followed by all cells in the next row, etc.
+	 */
+	Iterator<C> iterator();
+}

Modified: poi/trunk/src/java/org/apache/poi/ss/usermodel/Sheet.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/usermodel/Sheet.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/usermodel/Sheet.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/usermodel/Sheet.java Fri Dec 25 23:04:04 2009
@@ -785,16 +785,17 @@
     /**
      * Sets array formula to specified region for result.
      *
-     * @param formula Formula
-     * @param range   Region of array formula for result.
+     * @param formula text representation of the formula
+     * @param range Region of array formula for result.
+     * @return the {@link CellRange} of cells affected by this change
      */
-    Cell[] setArrayFormula(String formula, CellRangeAddress range);
+    CellRange<? extends Cell> setArrayFormula(String formula, CellRangeAddress range);
 
     /**
      * Remove a Array Formula from this sheet.  All cells contained in the Array Formula range are removed as well
      *
-     * @param cell any cell within Array Formula range
+     * @param cell   any cell within Array Formula range
+     * @return the {@link CellRange} of cells affected by this change
      */
-    Cell[] removeArrayFormula(Cell cell);
-
+    CellRange<? extends Cell> removeArrayFormula(Cell cell);
 }

Modified: poi/trunk/src/java/org/apache/poi/ss/util/CellRangeAddress.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/util/CellRangeAddress.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/util/CellRangeAddress.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/util/CellRangeAddress.java Fri Dec 25 23:04:04 2009
@@ -24,7 +24,7 @@
 
 /**
  * See OOO documentation: excelfileformat.pdf sec 2.5.14 - 'Cell Range Address'<p/>
- * 
+ *
  * Note - {@link SelectionRecord} uses the BIFF5 version of this structure
  * @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
  */
@@ -51,7 +51,7 @@
 		out.writeShort(getFirstColumn());
 		out.writeShort(getLastColumn());
 	}
-	
+
 	public CellRangeAddress(RecordInputStream in) {
 		super(readUShortAndCheck(in), in.readUShort(), in.readUShort(), in.readUShort());
 	}
@@ -72,6 +72,10 @@
 		return numberOfItems * ENCODED_SIZE;
 	}
 
+    /**
+     * @return the text format of this range.  Single cell ranges are formatted
+     *         like single cell references (e.g. 'A1' instead of 'A1:A1').
+     */
     public String formatAsString() {
         StringBuffer sb = new StringBuffer();
         CellReference cellRefFrom = new CellReference(getFirstRow(), getFirstColumn());

Modified: poi/trunk/src/java/org/apache/poi/ss/util/CellReference.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/util/CellReference.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/util/CellReference.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/util/CellReference.java Fri Dec 25 23:04:04 2009
@@ -114,10 +114,10 @@
 	public CellReference(int pRow, short pCol) {
 		this(pRow, pCol & 0xFFFF, false, false);
 	}
-    
-    public CellReference(Cell cell) {
-        this(cell.getRowIndex(), cell.getColumnIndex(), false, false);
-    }
+
+	public CellReference(Cell cell) {
+		this(cell.getRowIndex(), cell.getColumnIndex(), false, false);
+	}
 
 	public CellReference(int pRow, int pCol, boolean pAbsRow, boolean pAbsCol) {
 		this(null, pRow, pCol, pAbsRow, pAbsCol);
@@ -489,21 +489,22 @@
 		sb.append(_rowIndex+1);
 	}
 
-    /**
-     * Checks whether this cell reference is equal to another object.
-     * <p>
-     *  Two cells references are assumed to be equal if their string representations
-     *  ({@link #formatAsString()}  are equal.
-     * </p>
-     */
-    @Override
-    public boolean equals(Object o){
-        if(o == null || !(o instanceof CellReference)) {
-            return false;
-        }
-
-        String me = formatAsString();
-        String anotherRef = ((CellReference)o).formatAsString();
-        return me.equals(anotherRef);
-    }
+	/**
+	 * Checks whether this cell reference is equal to another object.
+	 * <p>
+	 *  Two cells references are assumed to be equal if their string representations
+	 *  ({@link #formatAsString()}  are equal.
+	 * </p>
+	 */
+	@Override
+	public boolean equals(Object o){
+		if(!(o instanceof CellReference)) {
+			return false;
+		}
+		CellReference cr = (CellReference) o;
+		return _rowIndex == cr._rowIndex
+			&& _colIndex == cr._colIndex
+			&& _isRowAbs == cr._isColAbs
+			&& _isColAbs == cr._isColAbs;
+	}
 }

Added: poi/trunk/src/java/org/apache/poi/ss/util/SSCellRange.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/util/SSCellRange.java?rev=893897&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/util/SSCellRange.java (added)
+++ poi/trunk/src/java/org/apache/poi/ss/util/SSCellRange.java Fri Dec 25 23:04:04 2009
@@ -0,0 +1,137 @@
+/* ====================================================================
+   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.util;
+
+import java.lang.reflect.Array;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellRange;
+import org.apache.poi.util.Internal;
+
+/**
+ * For POI internal use only
+ *
+ * @author Josh Micich
+ */
+@Internal
+public final class SSCellRange<K extends Cell> implements CellRange<K> {
+
+	private final int _height;
+	private final int _width;
+	private final K[] _flattenedArray;
+	private final int _firstRow;
+	private final int _firstColumn;
+
+	private SSCellRange(int firstRow, int firstColumn, int height, int width, K[] flattenedArray) {
+		_firstRow = firstRow;
+		_firstColumn = firstColumn;
+		_height = height;
+		_width = width;
+		_flattenedArray = flattenedArray;
+	}
+
+	public static <B extends Cell> SSCellRange<B> create(int firstRow, int firstColumn, int height, int width, List<B> flattenedList, Class<B> cellClass) {
+		int nItems = flattenedList.size();
+		if (height * width != nItems) {
+			throw new IllegalArgumentException("Array size mismatch.");
+		}
+
+		@SuppressWarnings("unchecked")
+		B[] flattenedArray = (B[]) Array.newInstance(cellClass, nItems);
+		flattenedList.toArray(flattenedArray);
+		return new SSCellRange<B>(firstRow, firstColumn, height, width, flattenedArray);
+	}
+
+	public int getHeight() {
+		return _height;
+	}
+	public int getWidth() {
+		return _width;
+	}
+	public int size() {
+		return _height*_width;
+	}
+
+	public String getReferenceText() {
+		CellRangeAddress cra = new CellRangeAddress(_firstRow, _firstRow+_height-1, _firstColumn, _firstColumn+_width-1);
+		return cra.formatAsString();
+	}
+
+	public K getTopLeftCell() {
+		return _flattenedArray[0];
+	}
+
+	public K getCell(int relativeRowIndex, int relativeColumnIndex) {
+		if (relativeRowIndex < 0 || relativeRowIndex >= _height) {
+			throw new ArrayIndexOutOfBoundsException("Specified row " + relativeRowIndex
+					+ " is outside the allowable range (0.." + (_height-1) + ").");
+		}
+		if (relativeColumnIndex < 0 || relativeColumnIndex >= _width) {
+			throw new ArrayIndexOutOfBoundsException("Specified colummn " + relativeColumnIndex
+					+ " is outside the allowable range (0.." + (_width-1) + ").");
+		}
+		int flatIndex = _width * relativeRowIndex + relativeColumnIndex;
+		return _flattenedArray[flatIndex];
+	}
+	public K[] getFlattenedCells() {
+		return _flattenedArray.clone();
+	}
+
+	public K[][] getCells() {
+		Class<?> itemCls = _flattenedArray.getClass();
+		@SuppressWarnings("unchecked")
+		K[][] result = (K[][]) Array.newInstance(itemCls, _height);
+		itemCls = itemCls.getComponentType();
+		for (int r=_height-1; r>=0; r--) {
+			@SuppressWarnings("unchecked")
+			K[] row = (K[]) Array.newInstance(itemCls, _width);
+			int flatIndex = _width * r;
+			System.arraycopy(_flattenedArray, flatIndex, row, 0, _width);
+		}
+		return result;
+	}
+	public Iterator<K> iterator() {
+		return new ArrayIterator<K>(_flattenedArray);
+	}
+	private static final class ArrayIterator<D> implements Iterator<D> {
+
+		private final D[] _array;
+		private int _index;
+
+		public ArrayIterator(D[] array) {
+			_array = array;
+			_index = 0;
+		}
+		public boolean hasNext() {
+			return _index < _array.length;
+		}
+		public D next() {
+			if (_index >= _array.length) {
+				throw new NoSuchElementException(String.valueOf(_index));
+			}
+			return _array[_index++];
+		}
+
+		public void remove() {
+			throw new UnsupportedOperationException("Cannot remove cells from this CellRange.");
+		}
+	}
+}

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java Fri Dec 25 23:04:04 2009
@@ -969,29 +969,16 @@
         throw new IllegalStateException("Unexpected formula result type (" + cellType + ")");
     }
 
-    /**
-     * If this cell is part of an array formula, returns a CellRangeAddress object
-     * that represents the entire array. 
-     *
-     * @return the range of the array formula group that this cell belongs to.
-     * @throws IllegalStateException if this cell is not part of an array formula
-     * @see #isPartOfArrayFormulaGroup()
-     */
     public CellRangeAddress getArrayFormulaRange() {
         XSSFCell cell = getSheet().getFirstCellInArrayFormula(this);
         if (cell == null) {
-            throw new IllegalStateException("Cell " + _cell.getR() + " is not part of an array formula");
+            throw new IllegalStateException("Cell " + _cell.getR()
+                    + " is not part of an array formula.");
         }
         String formulaRef = cell._cell.getF().getRef();
         return CellRangeAddress.valueOf(formulaRef);
     }
 
-    /**
-     * Test if this cell is included in an array formula
-     *
-     * @return true if this cell is part of an array formula
-     * @see #getArrayFormulaRange()
-     */
     public boolean isPartOfArrayFormulaGroup() {
         return getSheet().isCellInArrayFormulaContext(this);
     }

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java Fri Dec 25 23:04:04 2009
@@ -40,6 +40,7 @@
 import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
 import org.apache.poi.ss.SpreadsheetVersion;
 import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellRange;
 import org.apache.poi.ss.usermodel.CellStyle;
 import org.apache.poi.ss.usermodel.Footer;
 import org.apache.poi.ss.usermodel.Header;
@@ -47,9 +48,10 @@
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.ss.util.SSCellRange;
+import org.apache.poi.util.Internal;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
-import org.apache.poi.util.Internal;
 import org.apache.poi.xssf.model.CommentsTable;
 import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
 import org.apache.poi.xssf.usermodel.helpers.XSSFRowShifter;
@@ -2323,7 +2325,7 @@
         }
         if (f != null && f.getT() == STCellFormulaType.ARRAY && f.getRef() != null) {
             arrayFormulas.add(CellRangeAddress.valueOf(f.getRef()));
-    }
+        }
     }
 
     @Override
@@ -2701,85 +2703,57 @@
     }
 
     /**
-     * Sets array formula to the specified range of cells.
-     * <p>
-     *  Note, that this method silently creates cells in the
-     *  specified range if they don't exist.
-     * </p>
-     * Example:
-     * <blockquote><pre>
-     *  Workbook workbook = new XSSFWorkbook();
-     *  Sheet sheet = workbook.createSheet();
-     *  CellRangeAddress range = CellRangeAddress.valueOf("C1:C3");
-     *  Cell[] cells = sheet.setArrayFormula("A1:A3*B1:B3", range);
-     * </pre></blockquote>
-     *  Three cells in the C1:C3 range are created and returned.
-     *
-     * @param formula the formula to set
-     * @param range Region of array formula for result.
-     * @return the array of cells that represent the entire formula array
-     * @throws org.apache.poi.ss.formula.FormulaParseException if
-     *   the formula has incorrect syntax or is otherwise invalid
-     */
-     public XSSFCell[] setArrayFormula(String formula, CellRangeAddress range) {
-        XSSFRow row = getRow(range.getFirstRow());
-        if (row == null) {
-            row = createRow(range.getFirstRow());
-        }
-        XSSFCell mainArrayFormulaCell = row.getCell(range.getFirstColumn());
-        if (mainArrayFormulaCell == null) {
-            mainArrayFormulaCell = row.createCell(range.getFirstColumn());
-        }
-        mainArrayFormulaCell.setCellArrayFormula(formula, range);
-        arrayFormulas.add(range);
-
-        XSSFCell[] cells = new XSSFCell[range.getNumberOfCells()];
-        int k = 0;
-        for (int rowIndex = range.getFirstRow(); rowIndex <= range.getLastRow(); rowIndex++) {
-            row = getRow(rowIndex);
-            if (row == null) {
-                row = createRow(rowIndex);
-            }
-            for (int columnIndex = range.getFirstColumn(); columnIndex <= range.getLastColumn(); columnIndex++) {
-                XSSFCell arrayFormulaCell = row.getCell(columnIndex);
-                if (arrayFormulaCell == null) {
-                    arrayFormulaCell = row.createCell(columnIndex);
+     * Also creates cells if they don't exist
+     */
+    private CellRange<XSSFCell> getCellRange(CellRangeAddress range) {
+        int firstRow = range.getFirstRow();
+        int firstColumn = range.getFirstColumn();
+        int lastRow = range.getLastRow();
+        int lastColumn = range.getLastColumn();
+        int height = lastRow - firstRow + 1;
+        int width = lastColumn - firstColumn + 1;
+        List<XSSFCell> temp = new ArrayList<XSSFCell>(height*width);
+        for (int rowIn = firstRow; rowIn <= lastRow; rowIn++) {
+            for (int colIn = firstColumn; colIn <= lastColumn; colIn++) {
+                XSSFRow row = getRow(rowIn);
+                if (row == null) {
+                    row = createRow(rowIn);
+                }
+                XSSFCell cell = row.getCell(colIn);
+                if (cell == null) {
+                    cell = row.createCell(colIn);
                 }
-                cells[k++] = arrayFormulaCell;
+                temp.add(cell);
             }
         }
-        return cells;
+        return SSCellRange.create(firstRow, firstColumn, height, width, temp, XSSFCell.class);
     }
 
-    /**
-     * Remove an Array Formula from this sheet.
-     * <p>
-     * All cells contained in the Array Formula range are removed as well
-     * </p>
-     *
-     * @param cell   any cell within Array Formula range
-     * @return the array of affected cells.
-     * @throws IllegalArgumentException if the specified cell is not part of an array formula
-     */
-    public XSSFCell[] removeArrayFormula(Cell cell) {
-        ArrayList<XSSFCell> lst = new ArrayList<XSSFCell>();
+    public CellRange<XSSFCell> setArrayFormula(String formula, CellRangeAddress range) {
+
+        CellRange<XSSFCell> cr = getCellRange(range);
+
+        XSSFCell mainArrayFormulaCell = cr.getTopLeftCell();
+        mainArrayFormulaCell.setCellArrayFormula(formula, range);
+        arrayFormulas.add(range);
+        return cr;
+    }
+
+    public CellRange<XSSFCell> removeArrayFormula(Cell cell) {
+        if (cell.getSheet() != this) {
+            throw new IllegalArgumentException("Specified cell does not belong to this sheet.");
+        }
         for (CellRangeAddress range : arrayFormulas) {
             if (range.isInRange(cell.getRowIndex(), cell.getColumnIndex())) {
                 arrayFormulas.remove(range);
-                for (int rowIndex = range.getFirstRow(); rowIndex <= range.getLastRow(); rowIndex++) {
-                    XSSFRow row = getRow(rowIndex);
-                    for (int columnIndex = range.getFirstColumn(); columnIndex <= range.getLastColumn(); columnIndex++) {
-                        XSSFCell arrayFormulaCell = row.getCell(columnIndex);
-                        if (arrayFormulaCell != null) {
-                            arrayFormulaCell.setCellType(Cell.CELL_TYPE_BLANK);
-                            lst.add(arrayFormulaCell);
-                        }
-                    }
+                CellRange<XSSFCell> cr = getCellRange(range);
+                for (XSSFCell c : cr) {
+                    c.setCellType(Cell.CELL_TYPE_BLANK);
                 }
-                return lst.toArray(new XSSFCell[lst.size()]);
+                return cr;
             }
         }
         String ref = ((XSSFCell)cell).getCTCell().getR();
-        throw new IllegalArgumentException("Cell " + ref + " is not part of an array formula");
+        throw new IllegalArgumentException("Cell " + ref + " is not part of an array formula.");
     }
 }

Modified: poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/AllXSSFUsermodelTests.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/AllXSSFUsermodelTests.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/AllXSSFUsermodelTests.java (original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/AllXSSFUsermodelTests.java Fri Dec 25 23:04:04 2009
@@ -28,7 +28,7 @@
 
 /**
  * Collects all tests for <tt>org.apache.poi.xssf.usermodel</tt> and sub-packages.
- * 
+ *
  * @author Josh Micich
  */
 public final class AllXSSFUsermodelTests {
@@ -54,12 +54,13 @@
 		result.addTestSuite(TestXSSFRichTextString.class);
 		result.addTestSuite(TestXSSFRow.class);
 		result.addTestSuite(TestXSSFSheet.class);
+		result.addTestSuite(TestXSSFSheetUpdateArrayFormulas.class);
 		result.addTestSuite(TestXSSFWorkbook.class);
 
 		result.addTestSuite(TestXSSFBorder.class);
 		result.addTestSuite(TestXSSFCellFill.class);
 		result.addTestSuite(TestXSSFSheetComments.class);
-		
+
 		result.addTestSuite(TestColumnHelper.class);
 		result.addTestSuite(TestHeaderFooterHelper.class);
 

Copied: poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetUpdateArrayFormulas.java (from r893896, poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFArrayFormulas.java)
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetUpdateArrayFormulas.java?p2=poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetUpdateArrayFormulas.java&p1=poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFArrayFormulas.java&r1=893896&r2=893897&rev=893897&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFArrayFormulas.java (original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetUpdateArrayFormulas.java Fri Dec 25 23:04:04 2009
@@ -17,82 +17,93 @@
 
 package org.apache.poi.xssf.usermodel;
 
-import org.apache.poi.ss.usermodel.BaseTestArrayFormulas;
+import junit.framework.AssertionFailedError;
+
+import org.apache.poi.ss.usermodel.BaseTestSheetUpdateArrayFormulas;
+import org.apache.poi.ss.usermodel.CellRange;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.xssf.XSSFITestDataProvider;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType;
-
 /**
  * Test array formulas in XSSF
  *
  * @author Yegor Kozlov
+ * @author Josh Micich
  */
-public final class TestXSSFArrayFormulas extends BaseTestArrayFormulas {
+public final class TestXSSFSheetUpdateArrayFormulas extends BaseTestSheetUpdateArrayFormulas {
 
-    @Override
-    protected XSSFITestDataProvider getTestDataProvider(){
-        return XSSFITestDataProvider.getInstance();
+    public TestXSSFSheetUpdateArrayFormulas() {
+        super(XSSFITestDataProvider.getInstance());
     }
 
-    public void testXSSFSetArrayFormula_singleCell() {
-        XSSFWorkbook workbook = getTestDataProvider().createWorkbook();
-        XSSFSheet sheet = workbook.createSheet();
+    // Test methods common with HSSF are in superclass
+    // Local methods here test XSSF-specific details of updating array formulas
 
-        // row 3 does not yet exist
-        assertNull(sheet.getRow(2));
-        CellRangeAddress range = new CellRangeAddress(2, 2, 2, 2);
-        XSSFCell[] cells = sheet.setArrayFormula("SUM(C11:C12*D11:D12)", range);
-        assertEquals(1, cells.length);
+    public void testXSSFSetArrayFormula_singleCell() {
+        CellRange<XSSFCell> cells;
 
-        // sheet.setArrayFormula creates rows and cells for the designated range
-        assertNotNull(sheet.getRow(2));
-        XSSFCell cell = sheet.getRow(2).getCell(2);
-        assertNotNull(cell);
+        XSSFWorkbook workbook = new XSSFWorkbook();
+        XSSFSheet sheet = workbook.createSheet();
 
-        assertTrue(cell.isPartOfArrayFormulaGroup());
-        assertSame(cells[0], sheet.getFirstCellInArrayFormula(cells[0]));
+        // 1. single-cell array formula
+        String formula1 = "123";
+        CellRangeAddress range = CellRangeAddress.valueOf("C3:C3");
+        cells = sheet.setArrayFormula(formula1, range);
+        assertEquals(1, cells.size());
+
+        // check getFirstCell...
+        XSSFCell firstCell = cells.getTopLeftCell();
+        assertSame(firstCell, sheet.getFirstCellInArrayFormula(firstCell));
         //retrieve the range and check it is the same
-        assertEquals(range.formatAsString(), cell.getArrayFormulaRange().formatAsString());
-
-        //check the CTCellFormula bean
-        CTCellFormula f = cell.getCTCell().getF();
-        assertEquals("SUM(C11:C12*D11:D12)", f.getStringValue());
-        assertEquals("C3", f.getRef());
-        assertEquals(STCellFormulaType.ARRAY, f.getT());
-
+        assertEquals(range.formatAsString(), firstCell.getArrayFormulaRange().formatAsString());
+        confirmArrayFormulaCell(firstCell, "C3", formula1, "C3");
     }
 
     public void testXSSFSetArrayFormula_multiCell() {
-        XSSFCell[] cells;
+        CellRange<XSSFCell> cells;
 
-        XSSFWorkbook workbook = getTestDataProvider().createWorkbook();
+        String formula2 = "456";
+        XSSFWorkbook workbook = new XSSFWorkbook();
         XSSFSheet sheet = workbook.createSheet();
-        
-        CellRangeAddress range = new CellRangeAddress(3, 5, 2, 2);
-        assertEquals("C4:C6", range.formatAsString());
-        cells = sheet.setArrayFormula("SUM(A1:A3*B1:B3)", range);
-        assertEquals(3, cells.length);
 
-        // sheet.setArrayFormula creates rows and cells for the designated range
-        assertEquals("C4", cells[0].getCTCell().getR());
-        assertEquals("C5", cells[1].getCTCell().getR());
-        assertEquals("C6", cells[2].getCTCell().getR());
-        assertSame(cells[0], sheet.getFirstCellInArrayFormula(cells[0]));
+        CellRangeAddress range = CellRangeAddress.valueOf("C4:C6");
+        cells = sheet.setArrayFormula(formula2, range);
+        assertEquals(3, cells.size());
 
+        // sheet.setArrayFormula creates rows and cells for the designated range
         /*
          * From the spec:
          * For a multi-cell formula, the c elements for all cells except the top-left
          * cell in that range shall not have an f element;
          */
+        // Check that each cell exists and that the formula text is set correctly on the first cell
+        XSSFCell firstCell = cells.getTopLeftCell();
+        confirmArrayFormulaCell(firstCell, "C4", formula2, "C4:C6");
+        confirmArrayFormulaCell(cells.getCell(1, 0), "C5");
+        confirmArrayFormulaCell(cells.getCell(2, 0), "C6");
 
-        //the first cell has an f element
-        CTCellFormula f = cells[0].getCTCell().getF();
-        assertEquals("SUM(A1:A3*B1:B3)", f.getStringValue());
-        assertEquals("C4:C6", f.getRef());
-        assertEquals(STCellFormulaType.ARRAY, f.getT());
-        //the other two cells don't have an f element
-        assertNull(cells[1].getCTCell().getF());
-        assertNull(cells[2].getCTCell().getF());
+        assertSame(firstCell, sheet.getFirstCellInArrayFormula(firstCell));
+    }
+
+    private static void confirmArrayFormulaCell(XSSFCell c, String cellRef) {
+        confirmArrayFormulaCell(c, cellRef, null, null);
+    }
+    private static void confirmArrayFormulaCell(XSSFCell c, String cellRef, String formulaText, String arrayRangeRef) {
+        if (c == null) {
+            throw new AssertionFailedError("Cell should not be null.");
+        }
+        CTCell ctCell = c.getCTCell();
+        assertEquals(cellRef, ctCell.getR());
+        if (formulaText == null) {
+            assertFalse(ctCell.isSetF());
+            assertNull(ctCell.getF());
+        } else {
+            CTCellFormula f = ctCell.getF();
+            assertEquals(arrayRangeRef, f.getRef());
+            assertEquals(formulaText, f.getStringValue());
+            assertEquals(STCellFormulaType.ARRAY, f.getT());
+        }
     }
-}
\ No newline at end of file
+}

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java Fri Dec 25 23:04:04 2009
@@ -45,8 +45,8 @@
 		s.setString("abc");
 		FormulaRecordAggregate fagg = new FormulaRecordAggregate(f, s, SharedValueManager.createEmpty());
 		assertEquals("abc", fagg.getStringValue());
-        assertFalse(fagg.isPartOfArrayFormula());
-    }
+		assertFalse(fagg.isPartOfArrayFormula());
+	}
 
 	/**
 	 * Sometimes a {@link StringRecord} appears after a {@link FormulaRecord} even though the
@@ -79,26 +79,26 @@
 		assertEquals(fr, vraRecs[0]);
 	}
 
-    public void testArrayFormulas() {
-        int rownum = 4;
-        int colnum = 4;
-
-        FormulaRecord fr = new FormulaRecord();
-        fr.setRow(rownum);
-        fr.setColumn((short)colnum);
-
-        FormulaRecordAggregate agg = new FormulaRecordAggregate(fr, null, SharedValueManager.createEmpty());
-        Ptg[] ptgsForCell = {new ExpPtg(rownum, colnum)};
-        agg.setParsedExpression(ptgsForCell);
-
-        String formula = "SUM(A1:A3*B1:B3)";
-        Ptg[] ptgs = HSSFFormulaParser.parse(formula, null, FormulaType.ARRAY, 0);
-        agg.setArrayFormula(new CellRangeAddress(rownum, rownum, colnum, colnum), ptgs);
-
-        assertTrue(agg.isPartOfArrayFormula());
-        assertEquals("E5", agg.getArrayFormulaRange().formatAsString());
-        Ptg[] ptg = agg.getFormulaTokens();
-        String fmlaSer = FormulaRenderer.toFormulaString(null, ptg);
-        assertEquals(formula, fmlaSer);
-    }
+	public void testArrayFormulas() {
+		int rownum = 4;
+		int colnum = 4;
+
+		FormulaRecord fr = new FormulaRecord();
+		fr.setRow(rownum);
+		fr.setColumn((short)colnum);
+
+		FormulaRecordAggregate agg = new FormulaRecordAggregate(fr, null, SharedValueManager.createEmpty());
+		Ptg[] ptgsForCell = {new ExpPtg(rownum, colnum)};
+		agg.setParsedExpression(ptgsForCell);
+
+		String formula = "SUM(A1:A3*B1:B3)";
+		Ptg[] ptgs = HSSFFormulaParser.parse(formula, null, FormulaType.ARRAY, 0);
+		agg.setArrayFormula(new CellRangeAddress(rownum, rownum, colnum, colnum), ptgs);
+
+		assertTrue(agg.isPartOfArrayFormula());
+		assertEquals("E5", agg.getArrayFormulaRange().formatAsString());
+		Ptg[] ptg = agg.getFormulaTokens();
+		String fmlaSer = FormulaRenderer.toFormulaString(null, ptg);
+		assertEquals(formula, fmlaSer);
+	}
 }

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestSharedValueManager.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestSharedValueManager.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestSharedValueManager.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestSharedValueManager.java Fri Dec 25 23:04:04 2009
@@ -17,6 +17,7 @@
 
 package org.apache.poi.hssf.record.aggregates;
 
+import java.lang.reflect.Field;
 import java.util.Collection;
 import java.util.HashMap;
 
@@ -169,4 +170,26 @@
 		}
 		assertEquals("$AF24*A$7", formulaText);
 	}
+
+	/**
+	 * Convenience test method for digging the {@link SharedValueManager} out of a
+	 * {@link RowRecordsAggregate}.
+	 */
+	public static SharedValueManager extractFromRRA(RowRecordsAggregate rra) {
+		Field f;
+		try {
+			f = RowRecordsAggregate.class.getDeclaredField("_sharedValueManager");
+		} catch (NoSuchFieldException e) {
+			throw new RuntimeException(e);
+		}
+
+		f.setAccessible(true);
+		try {
+			return (SharedValueManager) f.get(rra);
+		} catch (IllegalArgumentException e) {
+			throw new RuntimeException(e);
+		} catch (IllegalAccessException e) {
+			throw new RuntimeException(e);
+		}
+	}
 }

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java?rev=893897&r1=893896&r2=893897&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java Fri Dec 25 23:04:04 2009
@@ -22,14 +22,14 @@
 
 /**
  * Collects all tests for the <tt>org.apache.poi.hssf.usermodel</tt> package.
- * 
+ *
  * @author Josh Micich
  */
 public class AllUserModelTests {
-	
+
 	public static Test suite() {
 		TestSuite result = new TestSuite(AllUserModelTests.class.getName());
-		
+
 		result.addTestSuite(TestBugs.class);
 		result.addTestSuite(TestCellStyle.class);
 		result.addTestSuite(TestCloneSheet.class);
@@ -57,6 +57,7 @@
 		result.addTestSuite(TestHSSFRichTextString.class);
 		result.addTestSuite(TestHSSFRow.class);
 		result.addTestSuite(TestHSSFSheet.class);
+		result.addTestSuite(TestHSSFSheetUpdateArrayFormulas.class);
 		result.addTestSuite(TestHSSFTextbox.class);
 		result.addTestSuite(TestHSSFWorkbook.class);
 		result.addTestSuite(TestHSSFName.class);
@@ -71,8 +72,8 @@
 		}
 		result.addTestSuite(TestUnicodeWorkbook.class);
 		result.addTestSuite(TestUppercaseWorkbook.class);
-		result.addTestSuite(TestWorkbook.class);		
-		
+		result.addTestSuite(TestWorkbook.class);
+
 		return result;
 	}
 }

Copied: poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheetUpdateArrayFormulas.java (from r893896, poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFArrayFormulas.java)
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheetUpdateArrayFormulas.java?p2=poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheetUpdateArrayFormulas.java&p1=poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFArrayFormulas.java&r1=893896&r2=893897&rev=893897&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFArrayFormulas.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheetUpdateArrayFormulas.java Fri Dec 25 23:04:04 2009
@@ -17,29 +17,41 @@
 
 package org.apache.poi.hssf.usermodel;
 
-import org.apache.poi.ss.usermodel.BaseTestArrayFormulas;
-import org.apache.poi.ss.util.CellRangeAddress;
+import junit.framework.AssertionFailedError;
+
 import org.apache.poi.hssf.HSSFITestDataProvider;
+import org.apache.poi.hssf.record.ArrayRecord;
+import org.apache.poi.hssf.record.FormulaRecord;
+import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
+import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
+import org.apache.poi.hssf.record.aggregates.SharedValueManager;
+import org.apache.poi.hssf.record.aggregates.TestSharedValueManager;
+import org.apache.poi.ss.usermodel.BaseTestSheetUpdateArrayFormulas;
+import org.apache.poi.ss.usermodel.CellRange;
+import org.apache.poi.ss.util.CellRangeAddress;
 
 /**
  * Test array formulas in HSSF
  *
  * @author Yegor Kozlov
+ * @author Josh Micich
  */
-public final class TestHSSFArrayFormulas extends BaseTestArrayFormulas {
+public final class TestHSSFSheetUpdateArrayFormulas extends BaseTestSheetUpdateArrayFormulas {
 
-    @Override
-    protected HSSFITestDataProvider getTestDataProvider(){
-        return HSSFITestDataProvider.getInstance();
+    public TestHSSFSheetUpdateArrayFormulas() {
+        super(HSSFITestDataProvider.getInstance());
     }
 
+    // Test methods common with XSSF are in superclass
+    // Local methods here test HSSF-specific details of updating array formulas
+
     public void testHSSFSetArrayFormula_singleCell() {
-        HSSFWorkbook workbook = getTestDataProvider().createWorkbook();
-        HSSFSheet sheet = workbook.createSheet();
+        HSSFWorkbook workbook = new HSSFWorkbook();
+        HSSFSheet sheet = workbook.createSheet("Sheet1");
 
         CellRangeAddress range = new CellRangeAddress(2, 2, 2, 2);
-        HSSFCell[] cells = sheet.setArrayFormula("SUM(C11:C12*D11:D12)", range);
+        HSSFCell[] cells = sheet.setArrayFormula("SUM(C11:C12*D11:D12)", range).getFlattenedCells();
         assertEquals(1, cells.length);
 
         // sheet.setArrayFormula creates rows and cells for the designated range
@@ -54,7 +66,57 @@
         FormulaRecordAggregate agg = (FormulaRecordAggregate)cell.getCellValueRecord();
         assertEquals(range.formatAsString(), agg.getArrayFormulaRange().formatAsString());
         assertTrue(agg.isPartOfArrayFormula());
+    }
 
+    /**
+     * Makes sure the internal state of HSSFSheet is consistent after removing array formulas
+     */
+    public void testAddRemoveArrayFormulas_recordUpdates() {
+        HSSFWorkbook wb = new HSSFWorkbook();
+        HSSFSheet s = wb.createSheet("Sheet1");
+
+        CellRange<HSSFCell> cr = s.setArrayFormula("123", CellRangeAddress.valueOf("B5:C6"));
+        Record[] recs;
+        int ix;
+        recs = RecordInspector.getRecords(s, 0);
+        ix = findRecordOfType(recs, ArrayRecord.class, 0);
+        confirmRecordClass(recs, ix-1, FormulaRecord.class);
+        confirmRecordClass(recs, ix+1, FormulaRecord.class);
+        confirmRecordClass(recs, ix+2, FormulaRecord.class);
+        confirmRecordClass(recs, ix+3, FormulaRecord.class);
+        // just one array record
+        assertTrue(findRecordOfType(recs, ArrayRecord.class, ix+1) < 0);
+
+        s.removeArrayFormula(cr.getTopLeftCell());
+
+        // Make sure the array formula has been removed properly
+
+        recs = RecordInspector.getRecords(s, 0);
+        assertTrue(findRecordOfType(recs, ArrayRecord.class, 0) < 0);
+        assertTrue(findRecordOfType(recs, FormulaRecord.class, 0) < 0);
+        RowRecordsAggregate rra = s.getSheet().getRowsAggregate();
+        SharedValueManager svm = TestSharedValueManager.extractFromRRA(rra);
+        if (svm.getArrayRecord(4, 1) != null) {
+            throw new AssertionFailedError("Array record was not cleaned up properly.");
+        }
     }
 
-}
\ No newline at end of file
+    private static void confirmRecordClass(Record[] recs, int index, Class<? extends Record> cls) {
+        if (recs.length <= index) {
+            throw new AssertionFailedError("Expected (" + cls.getName() + ") at index "
+                    + index + " but array length is " + recs.length + ".");
+        }
+        assertEquals(cls, recs[index].getClass());
+    }
+    /**
+     * @return <tt>-1<tt> if not found
+     */
+    private static int findRecordOfType(Record[] recs, Class<?> type, int fromIndex) {
+        for (int i=fromIndex; i<recs.length; i++) {
+            if (type.isInstance(recs[i])) {
+                return i;
+            }
+        }
+        return -1;
+    }
+}

Copied: poi/trunk/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetUpdateArrayFormulas.java (from r893896, poi/trunk/src/testcases/org/apache/poi/ss/usermodel/BaseTestArrayFormulas.java)
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetUpdateArrayFormulas.java?p2=poi/trunk/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetUpdateArrayFormulas.java&p1=poi/trunk/src/testcases/org/apache/poi/ss/usermodel/BaseTestArrayFormulas.java&r1=893896&r2=893897&rev=893897&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/ss/usermodel/BaseTestArrayFormulas.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/ss/usermodel/BaseTestSheetUpdateArrayFormulas.java Fri Dec 25 23:04:04 2009
@@ -17,44 +17,71 @@
 
 package org.apache.poi.ss.usermodel;
 
+import java.util.Arrays;
+
 import junit.framework.TestCase;
+
 import org.apache.poi.ss.ITestDataProvider;
-import org.apache.poi.ss.SpreadsheetVersion;
 import org.apache.poi.ss.formula.FormulaParseException;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.ss.util.CellReference;
 
-import java.util.Iterator;
-import java.util.Arrays;
-
 /**
- * Common superclass for testing usermodel API for array formulas
+ * Common superclass for testing usermodel API for array formulas.<br/>
+ * Formula evaluation is not tested here.
  *
  * @author Yegor Kozlov
+ * @author Josh Micich
  */
-public abstract class BaseTestArrayFormulas extends TestCase {
-
-    /**
-     * @return an object that provides test data in HSSF / XSSF specific way
-     */
-    protected abstract ITestDataProvider getTestDataProvider();
+public abstract class BaseTestSheetUpdateArrayFormulas extends TestCase {
+    protected final ITestDataProvider _testDataProvider;
 
+    protected BaseTestSheetUpdateArrayFormulas(ITestDataProvider testDataProvider) {
+        _testDataProvider = testDataProvider;
+    }
 
+    public final void testAutoCreateOtherCells() {
+        Workbook workbook = _testDataProvider.createWorkbook();
+        Sheet sheet = workbook.createSheet("Sheet1");
+
+        Row row1 = sheet.createRow(0);
+        Cell cellA1 = row1.createCell(0);
+        Cell cellB1 = row1.createCell(1);
+        String formula = "42";
+        sheet.setArrayFormula(formula, CellRangeAddress.valueOf("A1:B2"));
+
+        assertEquals(formula, cellA1.getCellFormula());
+        assertEquals(formula, cellB1.getCellFormula());
+        Row row2 = sheet.getRow(1);
+        assertNotNull(row2);
+        assertEquals(formula, row2.getCell(0).getCellFormula());
+        assertEquals(formula, row2.getCell(1).getCellFormula());
+    }
     /**
      *  Set single-cell array formula
      */
-    public void testSetArrayFormula_singleCell() {
-        Workbook workbook = getTestDataProvider().createWorkbook();
+    public final void testSetArrayFormula_singleCell() {
+        Cell[] cells;
+
+        Workbook workbook = _testDataProvider.createWorkbook();
         Sheet sheet = workbook.createSheet();
+        Cell cell = sheet.createRow(0).createCell(0);
+        assertFalse(cell.isPartOfArrayFormulaGroup());
+        try {
+            cell.getArrayFormulaRange();
+            fail("expected exception");
+        } catch (IllegalStateException e){
+            assertEquals("Cell A1 is not part of an array formula.", e.getMessage());
+        }
 
         // row 3 does not yet exist
         assertNull(sheet.getRow(2));
         CellRangeAddress range = new CellRangeAddress(2, 2, 2, 2);
-        Cell[] cells = sheet.setArrayFormula("SUM(C11:C12*D11:D12)", range);
+        cells = sheet.setArrayFormula("SUM(C11:C12*D11:D12)", range).getFlattenedCells();
         assertEquals(1, cells.length);
         // sheet.setArrayFormula creates rows and cells for the designated range
         assertNotNull(sheet.getRow(2));
-        Cell cell = sheet.getRow(2).getCell(2);
+        cell = sheet.getRow(2).getCell(2);
         assertNotNull(cell);
 
         assertTrue(cell.isPartOfArrayFormulaGroup());
@@ -67,8 +94,8 @@
     /**
      * Set multi-cell array formula
      */
-    public void testSetArrayFormula_multiCell() {
-        Workbook workbook = getTestDataProvider().createWorkbook();
+    public final void testSetArrayFormula_multiCell() {
+        Workbook workbook = _testDataProvider.createWorkbook();
         Sheet sheet = workbook.createSheet();
 
         // multi-cell formula
@@ -77,9 +104,8 @@
         assertNull(sheet.getRow(4));
         assertNull(sheet.getRow(5));
 
-        CellRangeAddress range = new CellRangeAddress(3, 5, 2, 2);
-        assertEquals("C4:C6", range.formatAsString());
-        Cell[] cells = sheet.setArrayFormula("SUM(A1:A3*B1:B3)", range);
+        CellRangeAddress range = CellRangeAddress.valueOf("C4:C6");
+        Cell[] cells = sheet.setArrayFormula("SUM(A1:A3*B1:B3)", range).getFlattenedCells();
         assertEquals(3, cells.length);
 
         // sheet.setArrayFormula creates rows and cells for the designated range
@@ -100,8 +126,8 @@
      * Passing an incorrect formula to sheet.setArrayFormula
      *  should throw FormulaParseException
      */
-    public void testSetArrayFormula_incorrectFormula() {
-        Workbook workbook = getTestDataProvider().createWorkbook();
+    public final void testSetArrayFormula_incorrectFormula() {
+        Workbook workbook = _testDataProvider.createWorkbook();
         Sheet sheet = workbook.createSheet();
 
         try {
@@ -117,58 +143,58 @@
      * Calls of cell.getArrayFormulaRange and sheet.removeArrayFormula
      * on a not-array-formula cell throw IllegalStateException
      */
-    public void testArrayFormulas_illegalCalls() {
-        Workbook workbook = getTestDataProvider().createWorkbook();
+    public final void testArrayFormulas_illegalCalls() {
+        Workbook workbook = _testDataProvider.createWorkbook();
         Sheet sheet = workbook.createSheet();
 
         Cell cell = sheet.createRow(0).createCell(0);
         assertFalse(cell.isPartOfArrayFormulaGroup());
         try {
-            CellRangeAddress range = cell.getArrayFormulaRange();
+            cell.getArrayFormulaRange();
             fail("expected exception");
         } catch (IllegalStateException e){
-            assertEquals("Cell A1 is not part of an array formula", e.getMessage());
+            assertEquals("Cell A1 is not part of an array formula.", e.getMessage());
         }
 
         try {
             sheet.removeArrayFormula(cell);
             fail("expected exception");
         } catch (IllegalArgumentException e){
-            assertEquals("Cell A1 is not part of an array formula", e.getMessage());
+            assertEquals("Cell A1 is not part of an array formula.", e.getMessage());
         }
     }
 
     /**
      * create and remove array formulas
      */
-    public void testRemoveArrayFormula() {
-        Workbook workbook = getTestDataProvider().createWorkbook();
+    public final void testRemoveArrayFormula() {
+        Workbook workbook = _testDataProvider.createWorkbook();
         Sheet sheet = workbook.createSheet();
 
         CellRangeAddress range = new CellRangeAddress(3, 5, 2, 2);
         assertEquals("C4:C6", range.formatAsString());
-        Cell[] cells = sheet.setArrayFormula("SUM(A1:A3*B1:B3)", range);
-        assertEquals(3, cells.length);
+        CellRange<?> cr = sheet.setArrayFormula("SUM(A1:A3*B1:B3)", range);
+        assertEquals(3, cr.size());
 
         // remove the formula cells in C4:C6
-        Cell[] dcells = sheet.removeArrayFormula(cells[0]);
+        CellRange<?> dcells = sheet.removeArrayFormula(cr.getTopLeftCell());
         // removeArrayFormula should return the same cells as setArrayFormula
-        assertTrue(Arrays.equals(cells, dcells));
+        assertTrue(Arrays.equals(cr.getFlattenedCells(), dcells.getFlattenedCells()));
 
-        for(Cell acell : cells){
+        for(Cell acell : cr){
             assertFalse(acell.isPartOfArrayFormulaGroup());
             assertEquals(Cell.CELL_TYPE_BLANK, acell.getCellType());
         }
 
         // cells C4:C6 are not included in array formula,
         // invocation of sheet.removeArrayFormula on any of them throws IllegalArgumentException
-        for(Cell acell : cells){
+        for(Cell acell : cr){
             try {
                 sheet.removeArrayFormula(acell);
                 fail("expected exception");
             } catch (IllegalArgumentException e){
                 String ref = new CellReference(acell).formatAsString();
-                assertEquals("Cell "+ref+" is not part of an array formula", e.getMessage());
+                assertEquals("Cell "+ref+" is not part of an array formula.", e.getMessage());
             }
         }
     }
@@ -176,22 +202,22 @@
     /**
      * Test that when reading a workbook from input stream, array formulas are recognized
      */
-    public void testReadArrayFormula() {
+    public final void testReadArrayFormula() {
         Cell[] cells;
 
-        Workbook workbook = getTestDataProvider().createWorkbook();
+        Workbook workbook = _testDataProvider.createWorkbook();
         Sheet sheet1 = workbook.createSheet();
-        cells = sheet1.setArrayFormula("SUM(A1:A3*B1:B3)", CellRangeAddress.valueOf("C4:C6"));
+        cells = sheet1.setArrayFormula("SUM(A1:A3*B1:B3)", CellRangeAddress.valueOf("C4:C6")).getFlattenedCells();
         assertEquals(3, cells.length);
 
-        cells = sheet1.setArrayFormula("MAX(A1:A3*B1:B3)", CellRangeAddress.valueOf("A4:A6"));
+        cells = sheet1.setArrayFormula("MAX(A1:A3*B1:B3)", CellRangeAddress.valueOf("A4:A6")).getFlattenedCells();
         assertEquals(3, cells.length);
 
         Sheet sheet2 = workbook.createSheet();
-        cells = sheet2.setArrayFormula("MIN(A1:A3*B1:B3)", CellRangeAddress.valueOf("D2:D4"));
+        cells = sheet2.setArrayFormula("MIN(A1:A3*B1:B3)", CellRangeAddress.valueOf("D2:D4")).getFlattenedCells();
         assertEquals(3, cells.length);
 
-        workbook = getTestDataProvider().writeOutAndReadBack(workbook);
+        workbook = _testDataProvider.writeOutAndReadBack(workbook);
         sheet1 = workbook.getSheetAt(0);
         for(int rownum=3; rownum <= 5; rownum++) {
             Cell cell1 = sheet1.getRow(rownum).getCell(2);
@@ -207,4 +233,4 @@
             assertTrue( cell1.isPartOfArrayFormulaGroup());
         }
     }
-}
\ No newline at end of file
+}



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