Author: yegor
Date: Fri Dec 25 15:15:55 2009
New Revision: 893870

URL: http://svn.apache.org/viewvc?rev=893870&view=rev
Log:
added HSSF usermodel tests for array formulas, added support for array formulas 
in ss interfaces

Added:
    
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFArrayFormulas.java
    poi/trunk/src/testcases/org/apache/poi/hssf/record/TestArrayRecord.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/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/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
    
poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestFormulaRecordAggregate.java
    poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java

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=893870&r1=893869&r2=893870&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 
15:15:55 2009
@@ -17,7 +17,10 @@
 
 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;
 import org.apache.poi.util.LittleEndianOutput;
@@ -28,6 +31,7 @@
  * 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 {
 
@@ -35,7 +39,7 @@
        private static final int OPT_ALWAYS_RECALCULATE = 0x0001;
        private static final int OPT_CALCULATE_ON_OPEN  = 0x0002;
 
-       private int     _options;
+       private int _options;
        private int _field3notUsed;
        private Formula _formula;
 
@@ -48,6 +52,13 @@
                _formula = Formula.read(formulaTokenLen, in, totalFormulaLen);
        }
 
+       public ArrayRecord(Formula formula, CellRangeAddress8Bit range ) {
+               super(range);
+               _options = 0; //YK: Excel 2007 leaves this field unset
+               _field3notUsed = 0;
+               _formula = formula;
+       }
+
        public boolean isAlwaysRecalculate() {
                return (_options & OPT_ALWAYS_RECALCULATE) != 0;
        }
@@ -55,7 +66,11 @@
                return (_options & OPT_CALCULATE_ON_OPEN) != 0;
        }
 
-       protected int getExtraDataSize() {
+    public void setOptions(int val){
+        _options = val;
+    }
+
+    protected int getExtraDataSize() {
                return 2 + 4
                        + _formula.getEncodedSize();
        }
@@ -84,4 +99,42 @@
                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=893870&r1=893869&r2=893870&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 15:15:55 2009
@@ -17,6 +17,7 @@
 
 package org.apache.poi.hssf.record.aggregates;
 
+import org.apache.poi.hssf.record.ArrayRecord;
 import org.apache.poi.hssf.record.CellValueRecordInterface;
 import org.apache.poi.hssf.record.FormulaRecord;
 import org.apache.poi.hssf.record.Record;
@@ -25,13 +26,17 @@
 import org.apache.poi.hssf.record.StringRecord;
 import org.apache.poi.hssf.record.formula.ExpPtg;
 import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.util.CellRangeAddress8Bit;
 import org.apache.poi.hssf.util.CellReference;
+import org.apache.poi.ss.formula.Formula;
+import org.apache.poi.ss.util.CellRangeAddress;
 
 /**
  * The formula record aggregate is used to join together the formula record 
and it's
  * (optional) string record and (optional) Shared Formula Record (template 
reads, excel optimization).
  *
  * @author Glen Stampoultzis (glens at apache.org)
+ * @author Vladimirs Abramovs(Vladimirs.Abramovs at exigenservices.com) - 
Array Formula support
  */
 public final class FormulaRecordAggregate extends RecordAggregate implements 
CellValueRecordInterface {
 
@@ -181,10 +186,15 @@
        }
 
        public Ptg[] getFormulaTokens() {
-               if (_sharedFormulaRecord == null) {
-                       return _formulaRecord.getParsedExpression();
+        if (_sharedFormulaRecord != null) {
+            return _sharedFormulaRecord.getFormulaTokens(_formulaRecord);
+        }
+               CellReference expRef = 
_formulaRecord.getFormula().getExpReference();
+               if (expRef != null) {
+                       ArrayRecord arec = 
_sharedValueManager.getArrayRecord(expRef.getRow(), expRef.getCol());
+                       return arec.getFormulaTokens();
                }
-               return _sharedFormulaRecord.getFormulaTokens(_formulaRecord);
+               return _formulaRecord.getParsedExpression();
        }
 
        /**
@@ -216,4 +226,41 @@
                        _sharedValueManager.unlink(_sharedFormulaRecord);
                }
        }
+
+    public boolean isPartOfArrayFormula() {
+        if (_sharedFormulaRecord != null) {
+            return false;
+        }
+        return _formulaRecord.getFormula().getExpReference() != null;
+    }
+
+    public CellRangeAddress getArrayFormulaRange() {
+               if (_sharedFormulaRecord != null) {
+                       throw new IllegalStateException("not an array formula 
cell.");
+               }
+               CellReference expRef = 
_formulaRecord.getFormula().getExpReference();
+               if (expRef == null) {
+                       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());
+        }
+               CellRangeAddress8Bit a = arec.getRange();
+               return new CellRangeAddress(a.getFirstRow(), a.getLastRow(), 
a.getFirstColumn(),a.getLastColumn());
+       }
+    
+    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);
+       }
+       /**
+        * Removes an array formula
+        * @return the range of the array formula containing the specified 
cell. Never <code>null</code>
+        */
+       public CellRangeAddress removeArrayFormula(int rowIndex, int 
columnIndex) {
+               CellRangeAddress8Bit a = 
_sharedValueManager.removeArrayFormula(rowIndex, columnIndex);
+               return new CellRangeAddress(a.getFirstRow(), a.getLastRow(), 
a.getFirstColumn(), a.getLastColumn());
+       }
 }

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=893870&r1=893869&r2=893870&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 15:15:55 2009
@@ -17,9 +17,11 @@
 
 package org.apache.poi.hssf.record.aggregates;
 
+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 org.apache.poi.hssf.record.ArrayRecord;
@@ -41,6 +43,7 @@
  * </ul>
  *
  * @author Josh Micich
+ * @author Vladimirs Abramovs(Vladimirs.Abramovs at exigenservices.com) - 
handling of ArrayRecords
  */
 public final class SharedValueManager {
 
@@ -112,12 +115,12 @@
        /**
         * @return a new empty {...@link SharedValueManager}.
         */
-       public static final SharedValueManager createEmpty() {
+       public static SharedValueManager createEmpty() {
                // Note - must create distinct instances because they are 
assumed to be mutable.
                return new SharedValueManager(
                        new SharedFormulaRecord[0], new CellReference[0], new 
ArrayRecord[0], new TableRecord[0]);
        }
-       private final ArrayRecord[] _arrayRecords;
+    private final List<ArrayRecord> _arrayRecords;
        private final TableRecord[] _tableRecords;
        private final Map<SharedFormulaRecord, SharedFormulaGroup> 
_groupsBySharedFormulaRecord;
        /** cached for optimization purposes */
@@ -129,7 +132,8 @@
                if (nShF != firstCells.length) {
                        throw new IllegalArgumentException("array sizes don't 
match: " + nShF + "!=" + firstCells.length + ".");
                }
-               _arrayRecords = arrayRecords;
+               _arrayRecords = new ArrayList<ArrayRecord>();
+        _arrayRecords.addAll(Arrays.asList(arrayRecords));
                _tableRecords = tableRecords;
                Map<SharedFormulaRecord, SharedFormulaGroup> m = new 
HashMap<SharedFormulaRecord, SharedFormulaGroup>(nShF * 3 / 2);
                for (int i = 0; i < nShF; i++) {
@@ -139,14 +143,6 @@
                _groupsBySharedFormulaRecord = m;
        }
 
-       /**
-        * @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) {
@@ -260,8 +256,7 @@
                                return tr;
                        }
                }
-               for (int i = 0; i < _arrayRecords.length; i++) {
-                       ArrayRecord ar = _arrayRecords[i];
+               for (ArrayRecord ar : _arrayRecords) {
                        if (ar.isFirstCell(row, column)) {
                                return ar;
                        }
@@ -281,4 +276,40 @@
                }
                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;
+    }
+    
 }

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=893870&r1=893869&r2=893870&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 
15:15:55 2009
@@ -43,6 +43,7 @@
 import org.apache.poi.hssf.record.TextObjectRecord;
 import org.apache.poi.hssf.record.UnicodeString;
 import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
+import org.apache.poi.hssf.record.formula.ExpPtg;
 import org.apache.poi.hssf.record.formula.Ptg;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.ss.usermodel.Cell;
@@ -50,7 +51,9 @@
 import org.apache.poi.ss.usermodel.Comment;
 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.formula.FormulaType;
 import org.apache.poi.ss.SpreadsheetVersion;
 import org.apache.poi.util.POILogger;
@@ -1160,4 +1163,31 @@
         }
         return 
((FormulaRecordAggregate)_record).getFormulaRecord().getCachedResultType();
     }
+
+    void setCellArrayFormula(CellRangeAddress range) {
+        int row = _record.getRow();
+        short col = _record.getColumn();
+        short styleIndex = _record.getXFIndex();
+        setCellType(CELL_TYPE_FORMULA, false, row, col, styleIndex);
+
+        // Billet for formula in rec
+        Ptg[] ptgsForCell = {new ExpPtg(range.getFirstRow(), 
range.getFirstColumn())};
+        FormulaRecordAggregate agg = (FormulaRecordAggregate) _record;
+        agg.setParsedExpression(ptgsForCell);
+    }
+
+    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");
+        }
+        return ((FormulaRecordAggregate)_record).getArrayFormulaRange();
+    }
+
+    public boolean isPartOfArrayFormulaGroup() {
+        if (_cellType != CELL_TYPE_FORMULA) {
+            return false;
+        }
+        return ((FormulaRecordAggregate)_record).isPartOfArrayFormula();
+    }
 }

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=893870&r1=893869&r2=893870&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 
15:15:55 2009
@@ -31,6 +31,7 @@
 import java.util.TreeMap;
 
 import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
 import org.apache.poi.hssf.model.InternalSheet;
 import org.apache.poi.hssf.model.InternalWorkbook;
 import org.apache.poi.hssf.record.CellValueRecordInterface;
@@ -44,14 +45,18 @@
 import org.apache.poi.hssf.record.WSBoolRecord;
 import org.apache.poi.hssf.record.WindowTwoRecord;
 import org.apache.poi.hssf.record.aggregates.DataValidityTable;
+import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
 import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock;
 import org.apache.poi.hssf.record.formula.FormulaShifter;
+import org.apache.poi.hssf.record.formula.Ptg;
 import org.apache.poi.hssf.util.PaneInformation;
 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.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.SpreadsheetVersion;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
@@ -1870,4 +1875,57 @@
         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);
+        int firstRow = range.getFirstRow();
+        int firstColumn = range.getFirstColumn();
+        for (int rowIn = firstRow; rowIn <= range.getLastRow(); rowIn++) {
+            for (int colIn = firstColumn; colIn <= range.getLastColumn(); 
colIn++) {
+                HSSFRow row = getRow(rowIn);
+                if (row == null) {
+                    row = createRow(rowIn);
+                }
+                HSSFCell cell = row.getCell(colIn);
+                if (cell == null) {
+                    cell = row.createCell(colIn);
+                }
+                cell.setCellArrayFormula(range);
+                cells[k++] = cell;
+            }
+        }
+        HSSFCell mainArrayFormulaCell = getRow(firstRow).getCell(firstColumn);
+        FormulaRecordAggregate agg = 
(FormulaRecordAggregate)mainArrayFormulaCell.getCellValueRecord();
+        agg.setArrayFormula(range, ptgs);
+        return cells;
+    }
+
+
+    public HSSFCell[] removeArrayFormula(Cell cell) {
+        ArrayList<HSSFCell> lst = new ArrayList<HSSFCell>();
+        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");
+        }
+        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");
+        }
+        // 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);
+             }
+        }
+        return lst.toArray(new HSSFCell[lst.size()]);
+    }
 }

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=893870&r1=893869&r2=893870&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 15:15:55 2009
@@ -72,6 +72,9 @@
                        case FormulaType.CELL:
                                rootNodeOperandClass = Ptg.CLASS_VALUE;
                                break;
+            case FormulaType.ARRAY:
+                rootNodeOperandClass = Ptg.CLASS_ARRAY;
+                break;
             case FormulaType.NAMEDRANGE:
                        case FormulaType.DATAVALIDATION_LIST:
                                rootNodeOperandClass = Ptg.CLASS_REF;

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=893870&r1=893869&r2=893870&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 
15:15:55 2009
@@ -21,6 +21,7 @@
 import java.util.Date;
 
 import org.apache.poi.ss.formula.FormulaParseException;
+import org.apache.poi.ss.util.CellRangeAddress;
 
 /**
  * High level representation of a cell in a row of a spreadsheet.
@@ -372,4 +373,18 @@
      * @param link hypelrink associated with this cell
      */
     void setHyperlink(Hyperlink link);
+
+
+    /**
+     * Only valid for array formula cells
+     *
+     * @return range of the array formula group that the cell belongs to.
+     */
+    CellRangeAddress getArrayFormulaRange();
+
+    /**
+     * @return <code>true</code> if this cell is part of group of cells having 
a common array formula.
+     */
+    boolean isPartOfArrayFormulaGroup();
+
 }

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=893870&r1=893869&r2=893870&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 
15:15:55 2009
@@ -781,4 +781,20 @@
      */
     boolean isSelected();
 
+
+    /**
+     * Sets array formula to specified region for result.
+     *
+     * @param formula Formula
+     * @param range   Region of array formula for result.
+     */
+    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
+     */
+    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=893870&r1=893869&r2=893870&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 
15:15:55 2009
@@ -77,8 +77,11 @@
         CellReference cellRefFrom = new CellReference(getFirstRow(), 
getFirstColumn());
         CellReference cellRefTo = new CellReference(getLastRow(), 
getLastColumn());
         sb.append(cellRefFrom.formatAsString());
-        sb.append(':');
-        sb.append(cellRefTo.formatAsString());
+        //for a single-cell reference return A1 instead of A1:A1
+        if(!cellRefFrom.equals(cellRefTo)){
+            sb.append(':');
+            sb.append(cellRefTo.formatAsString());
+        }
         return sb.toString();
     }
 

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=893870&r1=893869&r2=893870&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 
15:15:55 2009
@@ -22,6 +22,7 @@
 
 import org.apache.poi.hssf.record.formula.SheetNameFormatter;
 import org.apache.poi.ss.SpreadsheetVersion;
+import org.apache.poi.ss.usermodel.Cell;
 
 /**
  *
@@ -113,6 +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(int pRow, int pCol, boolean pAbsRow, boolean 
pAbsCol) {
                this(null, pRow, pCol, pAbsRow, pAbsCol);
@@ -483,4 +488,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);
+    }
 }

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=893870&r1=893869&r2=893870&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 15:15:55 2009
@@ -407,9 +407,9 @@
 
         XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
         //validate through the FormulaParser
-        FormulaParser.parse(formula, fpb, FormulaType.CELL, 
wb.getSheetIndex(getSheet()));
+        FormulaParser.parse(formula, fpb, formulaType, 
wb.getSheetIndex(getSheet()));
 
-        CTCellFormula f =  CTCellFormula.Factory.newInstance();
+        CTCellFormula f = CTCellFormula.Factory.newInstance();
         f.setStringValue(formula);
         _cell.setF(f);
         if(_cell.isSetV()) _cell.unsetV();

Added: 
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/TestXSSFArrayFormulas.java?rev=893870&view=auto
==============================================================================
--- 
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFArrayFormulas.java
 (added)
+++ 
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFArrayFormulas.java
 Fri Dec 25 15:15:55 2009
@@ -0,0 +1,98 @@
+/* ====================================================================
+   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.usermodel.BaseTestArrayFormulas;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.XSSFITestDataProvider;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType;
+
+/**
+ * Test array formulas in XSSF
+ *
+ * @author Yegor Kozlov
+ */
+public final class TestXSSFArrayFormulas extends BaseTestArrayFormulas {
+
+    @Override
+    protected XSSFITestDataProvider getTestDataProvider(){
+        return XSSFITestDataProvider.getInstance();
+    }
+
+    public void testXSSFSetArrayFormula_singleCell() {
+        XSSFWorkbook workbook = getTestDataProvider().createWorkbook();
+        XSSFSheet sheet = workbook.createSheet();
+
+        // 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);
+
+        // sheet.setArrayFormula creates rows and cells for the designated 
range
+        assertNotNull(sheet.getRow(2));
+        XSSFCell cell = sheet.getRow(2).getCell(2);
+        assertNotNull(cell);
+
+        assertTrue(cell.isPartOfArrayFormulaGroup());
+        assertSame(cells[0], sheet.getFirstCellInArrayFormula(cells[0]));
+        //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());
+
+    }
+
+    public void testXSSFSetArrayFormula_multiCell() {
+        XSSFCell[] cells;
+
+        XSSFWorkbook workbook = getTestDataProvider().createWorkbook();
+        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]));
+
+        /*
+         * 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;
+         */
+
+        //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());
+    }
+}
\ No newline at end of file

Modified: 
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java?rev=893870&r1=893869&r2=893870&view=diff
==============================================================================
--- 
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java 
(original)
+++ 
poi/trunk/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java 
Fri Dec 25 15:15:55 2009
@@ -914,139 +914,4 @@
         //existing cells are invalidated
         assertEquals(0, wsh.getSheetData().getRowArray(0).sizeOfCArray());
     }
-
-    public void testSetArrayFormula() throws Exception {
-        XSSFCell[] cells;
-
-        XSSFWorkbook workbook = new XSSFWorkbook();
-        XSSFSheet sheet = workbook.createSheet();
-        XSSFCell cell = sheet.createRow(0).createCell(0);
-        assertFalse(cell.isPartOfArrayFormulaGroup());
-        assertFalse(sheet.isCellInArrayFormulaContext(cell));
-        try {
-            CellRangeAddress range = cell.getArrayFormulaRange();
-            fail("expected exception");
-        } catch (IllegalStateException e){
-            assertEquals("Cell A1 is not part of an array formula", 
e.getMessage());
-        }
-
-        // 1. single-cell formula
-
-        // row 3 does not yet exist
-        assertNull(sheet.getRow(2));
-        CellRangeAddress range = new CellRangeAddress(2, 2, 2, 2);
-        cells = sheet.setArrayFormula("SUM(C11:C12*D11:D12)", range);
-        assertEquals(1, cells.length);
-        // sheet.setArrayFormula creates rows and cells for the designated 
range
-        assertNotNull(sheet.getRow(2));
-        cell = sheet.getRow(2).getCell(2);
-        assertNotNull(cell);
-
-        assertTrue(cell.isPartOfArrayFormulaGroup());
-        assertSame(cells[0], sheet.getFirstCellInArrayFormula(cells[0]));
-        //retrieve the range and check it is the same
-        assertEquals(range.formatAsString(), 
cell.getArrayFormulaRange().formatAsString());
-
-        // 2. multi-cell formula
-        //rows 3-5 don't exist yet
-        assertNull(sheet.getRow(3));
-        assertNull(sheet.getRow(4));
-        assertNull(sheet.getRow(5));
-
-        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]));
-
-        /*
-         * 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;
-         */
-        assertEquals("SUM(A1:A3*B1:B3)", 
cells[0].getCTCell().getF().getStringValue());
-        assertNull(cells[1].getCTCell().getF());
-        assertNull(cells[2].getCTCell().getF());
-
-        for(XSSFCell acell : cells){
-            assertTrue(acell.isPartOfArrayFormulaGroup());
-            assertEquals(Cell.CELL_TYPE_FORMULA, acell.getCellType());
-            assertEquals("SUM(A1:A3*B1:B3)", acell.getCellFormula());
-            //retrieve the range and check it is the same
-            assertEquals(range.formatAsString(), 
acell.getArrayFormulaRange().formatAsString());
-        }
-    }
-
-    public void testRemoveArrayFormula() throws Exception {
-        XSSFCell[] cells;
-
-        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);
-
-        // remove the formula cells in C4:C6
-        XSSFCell[] dcells = sheet.removeArrayFormula(cells[0]);
-        // removeArrayFormula should return the same cells as setArrayFormula
-        assertTrue(Arrays.equals(cells, dcells));
-
-        for(XSSFCell acell : cells){
-            assertFalse(acell.isPartOfArrayFormulaGroup());
-            assertEquals(Cell.CELL_TYPE_BLANK, acell.getCellType());
-        }
-
-        //invocation on a not-array-formula cell throws IllegalStateException
-        try {
-            sheet.removeArrayFormula(cells[0]);
-            fail("expected exception");
-        } catch (IllegalArgumentException e){
-            assertEquals("Cell C4 is not part of an array formula", 
e.getMessage());
-        }
-    }
-
-    public void testReadArrayFormula() throws Exception {
-        XSSFCell[] cells;
-
-        XSSFWorkbook workbook = new XSSFWorkbook();
-        XSSFSheet sheet1 = workbook.createSheet();
-        cells = sheet1.setArrayFormula("SUM(A1:A3*B1:B3)", 
CellRangeAddress.valueOf("C4:C6"));
-        assertEquals(3, cells.length);
-
-        cells = sheet1.setArrayFormula("MAX(A1:A3*B1:B3)", 
CellRangeAddress.valueOf("A4:A6"));
-        assertEquals(3, cells.length);
-
-        XSSFSheet sheet2 = workbook.createSheet();
-        cells = sheet2.setArrayFormula("MIN(A1:A3*B1:B3)", 
CellRangeAddress.valueOf("D2:D4"));
-        assertEquals(3, cells.length);
-
-        workbook = getTestDataProvider().writeOutAndReadBack(workbook);
-        sheet1 = workbook.getSheetAt(0);
-        for(int rownum=3; rownum <= 5; rownum++) {
-            XSSFCell cell1 = sheet1.getRow(rownum).getCell(2);
-            assertTrue( sheet1.isCellInArrayFormulaContext(cell1));
-            assertTrue( cell1.isPartOfArrayFormulaGroup());
-
-            XSSFCell cell2 = sheet1.getRow(rownum).getCell(0);
-            assertTrue( sheet1.isCellInArrayFormulaContext(cell2));
-            assertTrue( cell2.isPartOfArrayFormulaGroup());
-        }
-
-        sheet2 = workbook.getSheetAt(1);
-        for(int rownum=1; rownum <= 3; rownum++) {
-            XSSFCell cell1 = sheet2.getRow(rownum).getCell(3);
-            assertTrue( sheet2.isCellInArrayFormulaContext(cell1));
-            assertTrue( cell1.isPartOfArrayFormulaGroup());
-        }
-        XSSFCell acnhorCell = sheet2.getRow(1).getCell(3);
-        XSSFCell fmlaCell = sheet2.getRow(2).getCell(3);
-        assertSame(acnhorCell, sheet2.getFirstCellInArrayFormula(fmlaCell));
-        assertSame(acnhorCell, sheet2.getFirstCellInArrayFormula(acnhorCell));
-    }
 }

Added: poi/trunk/src/testcases/org/apache/poi/hssf/record/TestArrayRecord.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/TestArrayRecord.java?rev=893870&view=auto
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/TestArrayRecord.java 
(added)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/TestArrayRecord.java Fri 
Dec 25 15:15:55 2009
@@ -0,0 +1,68 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.record;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.ComparisonFailure;
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.hssf.util.CellRangeAddress8Bit;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.formula.RefPtg;
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ss.usermodel.CellValue;
+import org.apache.poi.ss.formula.FormulaParser;
+import org.apache.poi.ss.formula.FormulaRenderer;
+import org.apache.poi.ss.formula.FormulaType;
+import org.apache.poi.ss.formula.Formula;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.HexRead;
+import org.apache.poi.util.HexDump;
+
+import java.util.Arrays;
+
+public final class TestArrayRecord extends TestCase {
+
+    public void testRead() {
+        String hex =
+                "21 02 25 00 01 00 01 00 01 01 00 00 00 00 00 00 " +
+                "17 00 65 00 00 01 00 02 C0 02 C0 65 00 00 01 00 " +
+                "03 C0 03 C0 04 62 01 07 00";
+        byte[] data = HexRead.readFromString(hex);
+        RecordInputStream in = TestcaseRecordInputStream.create(data);
+        ArrayRecord r1 = new ArrayRecord(in);
+        CellRangeAddress8Bit range = r1.getRange();
+        assertEquals(1, range.getFirstColumn());
+        assertEquals(1, range.getLastColumn());
+        assertEquals(1, range.getFirstRow());
+        assertEquals(1, range.getLastRow());
+
+        Ptg[] ptg = r1.getFormulaTokens();
+        assertEquals("MAX(C1:C2-D1:D2)", FormulaRenderer.toFormulaString(null, 
ptg));
+
+        //construct a new ArrayRecord with the same contents as r1
+        Ptg[] fmlaPtg = FormulaParser.parse("MAX(C1:C2-D1:D2)", null, 
FormulaType.ARRAY, 0);
+        ArrayRecord r2 = new ArrayRecord(Formula.create(fmlaPtg), new 
CellRangeAddress8Bit(1, 1, 1, 1));
+        byte[] ser = r2.serialize();
+        //serialize and check that the data is the same as in r1
+        assertEquals(HexDump.toHex(data), HexDump.toHex(ser));
+
+
+    }
+}
\ 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=893870&r1=893869&r2=893870&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 15:15:55 2009
@@ -24,7 +24,13 @@
 import org.apache.poi.hssf.record.Record;
 import org.apache.poi.hssf.record.RecordFormatException;
 import org.apache.poi.hssf.record.StringRecord;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.formula.ExpPtg;
 import org.apache.poi.hssf.usermodel.RecordInspector.RecordCollector;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
+import org.apache.poi.ss.formula.FormulaType;
+import org.apache.poi.ss.formula.FormulaRenderer;
+import org.apache.poi.ss.util.CellRangeAddress;
 
 /**
  *
@@ -39,7 +45,8 @@
                s.setString("abc");
                FormulaRecordAggregate fagg = new FormulaRecordAggregate(f, s, 
SharedValueManager.createEmpty());
                assertEquals("abc", fagg.getStringValue());
-       }
+        assertFalse(fagg.isPartOfArrayFormula());
+    }
 
        /**
         * Sometimes a {...@link StringRecord} appears after a {...@link 
FormulaRecord} even though the
@@ -71,4 +78,27 @@
                assertEquals(1, vraRecs.length);
                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);
+    }
 }

Added: 
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/TestHSSFArrayFormulas.java?rev=893870&view=auto
==============================================================================
--- 
poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFArrayFormulas.java
 (added)
+++ 
poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFArrayFormulas.java
 Fri Dec 25 15:15:55 2009
@@ -0,0 +1,60 @@
+/* ====================================================================
+   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.ss.usermodel.BaseTestArrayFormulas;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.hssf.HSSFITestDataProvider;
+import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
+
+/**
+ * Test array formulas in HSSF
+ *
+ * @author Yegor Kozlov
+ */
+public final class TestHSSFArrayFormulas extends BaseTestArrayFormulas {
+
+    @Override
+    protected HSSFITestDataProvider getTestDataProvider(){
+        return HSSFITestDataProvider.getInstance();
+    }
+
+    public void testHSSFSetArrayFormula_singleCell() {
+        HSSFWorkbook workbook = getTestDataProvider().createWorkbook();
+        HSSFSheet sheet = workbook.createSheet();
+
+        CellRangeAddress range = new CellRangeAddress(2, 2, 2, 2);
+        HSSFCell[] cells = sheet.setArrayFormula("SUM(C11:C12*D11:D12)", 
range);
+        assertEquals(1, cells.length);
+
+        // sheet.setArrayFormula creates rows and cells for the designated 
range
+        assertNotNull(sheet.getRow(2));
+        HSSFCell cell = sheet.getRow(2).getCell(2);
+        assertNotNull(cell);
+
+        assertTrue(cell.isPartOfArrayFormulaGroup());
+        //retrieve the range and check it is the same
+        assertEquals(range.formatAsString(), 
cell.getArrayFormulaRange().formatAsString());
+
+        FormulaRecordAggregate agg = 
(FormulaRecordAggregate)cell.getCellValueRecord();
+        assertEquals(range.formatAsString(), 
agg.getArrayFormulaRange().formatAsString());
+        assertTrue(agg.isPartOfArrayFormula());
+
+    }
+
+}
\ No newline at end of file

Modified: 
poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java?rev=893870&r1=893869&r2=893870&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java 
(original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java 
Fri Dec 25 15:15:55 2009
@@ -20,6 +20,7 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.util.Arrays;
 
 import junit.framework.AssertionFailedError;
 
@@ -42,6 +43,9 @@
 import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock;
 import org.apache.poi.hssf.usermodel.RecordInspector.RecordCollector;
 import org.apache.poi.ss.usermodel.BaseTestSheet;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.ss.util.CellRangeAddressList;
 import org.apache.poi.util.TempFile;
@@ -820,5 +824,4 @@
         s.setRightToLeft(true);
         assertEquals(true, s.isRightToLeft());
     }
-
 }

Added: 
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/BaseTestArrayFormulas.java?rev=893870&view=auto
==============================================================================
--- 
poi/trunk/src/testcases/org/apache/poi/ss/usermodel/BaseTestArrayFormulas.java 
(added)
+++ 
poi/trunk/src/testcases/org/apache/poi/ss/usermodel/BaseTestArrayFormulas.java 
Fri Dec 25 15:15:55 2009
@@ -0,0 +1,210 @@
+/* ====================================================================
+   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 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
+ *
+ * @author Yegor Kozlov
+ */
+public abstract class BaseTestArrayFormulas extends TestCase {
+
+    /**
+     * @return an object that provides test data in HSSF / XSSF specific way
+     */
+    protected abstract ITestDataProvider getTestDataProvider();
+
+
+    /**
+     *  Set single-cell array formula
+     */
+    public void testSetArrayFormula_singleCell() {
+        Workbook workbook = getTestDataProvider().createWorkbook();
+        Sheet sheet = workbook.createSheet();
+
+        // 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);
+        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);
+        assertNotNull(cell);
+
+        assertTrue(cell.isPartOfArrayFormulaGroup());
+        //retrieve the range and check it is the same
+        assertEquals(range.formatAsString(), 
cell.getArrayFormulaRange().formatAsString());
+        //check the formula
+        assertEquals("SUM(C11:C12*D11:D12)", cell.getCellFormula());
+    }
+
+    /**
+     * Set multi-cell array formula
+     */
+    public void testSetArrayFormula_multiCell() {
+        Workbook workbook = getTestDataProvider().createWorkbook();
+        Sheet sheet = workbook.createSheet();
+
+        // multi-cell formula
+        // rows 3-5 don't exist yet
+        assertNull(sheet.getRow(3));
+        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);
+        assertEquals(3, cells.length);
+
+        // sheet.setArrayFormula creates rows and cells for the designated 
range
+        assertSame(cells[0], sheet.getRow(3).getCell(2));
+        assertSame(cells[1], sheet.getRow(4).getCell(2));
+        assertSame(cells[2], sheet.getRow(5).getCell(2));
+
+        for(Cell acell : cells){
+            assertTrue(acell.isPartOfArrayFormulaGroup());
+            assertEquals(Cell.CELL_TYPE_FORMULA, acell.getCellType());
+            assertEquals("SUM(A1:A3*B1:B3)", acell.getCellFormula());
+            //retrieve the range and check it is the same
+            assertEquals(range.formatAsString(), 
acell.getArrayFormulaRange().formatAsString());
+        }
+    }
+
+    /**
+     * Passing an incorrect formula to sheet.setArrayFormula
+     *  should throw FormulaParseException
+     */
+    public void testSetArrayFormula_incorrectFormula() {
+        Workbook workbook = getTestDataProvider().createWorkbook();
+        Sheet sheet = workbook.createSheet();
+
+        try {
+            sheet.setArrayFormula("incorrect-formula(C11_C12*D11_D12)",
+                    new CellRangeAddress(10, 10, 10, 10));
+            fail("expected exception");
+        } catch (FormulaParseException e){
+            //expected exception
+        }
+    }
+
+    /**
+     * Calls of cell.getArrayFormulaRange and sheet.removeArrayFormula
+     * on a not-array-formula cell throw IllegalStateException
+     */
+    public void testArrayFormulas_illegalCalls() {
+        Workbook workbook = getTestDataProvider().createWorkbook();
+        Sheet sheet = workbook.createSheet();
+
+        Cell cell = sheet.createRow(0).createCell(0);
+        assertFalse(cell.isPartOfArrayFormulaGroup());
+        try {
+            CellRangeAddress range = cell.getArrayFormulaRange();
+            fail("expected exception");
+        } catch (IllegalStateException e){
+            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());
+        }
+    }
+
+    /**
+     * create and remove array formulas
+     */
+    public void testRemoveArrayFormula() {
+        Workbook workbook = getTestDataProvider().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);
+
+        // remove the formula cells in C4:C6
+        Cell[] dcells = sheet.removeArrayFormula(cells[0]);
+        // removeArrayFormula should return the same cells as setArrayFormula
+        assertTrue(Arrays.equals(cells, dcells));
+
+        for(Cell acell : cells){
+            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){
+            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());
+            }
+        }
+    }
+
+    /**
+     * Test that when reading a workbook from input stream, array formulas are 
recognized
+     */
+    public void testReadArrayFormula() {
+        Cell[] cells;
+
+        Workbook workbook = getTestDataProvider().createWorkbook();
+        Sheet sheet1 = workbook.createSheet();
+        cells = sheet1.setArrayFormula("SUM(A1:A3*B1:B3)", 
CellRangeAddress.valueOf("C4:C6"));
+        assertEquals(3, cells.length);
+
+        cells = sheet1.setArrayFormula("MAX(A1:A3*B1:B3)", 
CellRangeAddress.valueOf("A4:A6"));
+        assertEquals(3, cells.length);
+
+        Sheet sheet2 = workbook.createSheet();
+        cells = sheet2.setArrayFormula("MIN(A1:A3*B1:B3)", 
CellRangeAddress.valueOf("D2:D4"));
+        assertEquals(3, cells.length);
+
+        workbook = getTestDataProvider().writeOutAndReadBack(workbook);
+        sheet1 = workbook.getSheetAt(0);
+        for(int rownum=3; rownum <= 5; rownum++) {
+            Cell cell1 = sheet1.getRow(rownum).getCell(2);
+            assertTrue( cell1.isPartOfArrayFormulaGroup());
+
+            Cell cell2 = sheet1.getRow(rownum).getCell(0);
+            assertTrue( cell2.isPartOfArrayFormulaGroup());
+        }
+
+        sheet2 = workbook.getSheetAt(1);
+        for(int rownum=1; rownum <= 3; rownum++) {
+            Cell cell1 = sheet2.getRow(rownum).getCell(3);
+            assertTrue( cell1.isPartOfArrayFormulaGroup());
+        }
+    }
+}
\ No newline at end of file



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to