git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@893870 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_7_BETA1
@@ -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 @@ import org.apache.poi.util.LittleEndianOutput; | |||
* 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 @@ public final class ArrayRecord extends SharedValueRecordBase { | |||
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 @@ public final class ArrayRecord extends SharedValueRecordBase { | |||
_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 @@ public final class ArrayRecord extends SharedValueRecordBase { | |||
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 @@ public final class ArrayRecord extends SharedValueRecordBase { | |||
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); | |||
*/ | |||
} | |||
} |
@@ -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.SharedFormulaRecord; | |||
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 final class FormulaRecordAggregate extends RecordAggregate implements Cel | |||
} | |||
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 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel | |||
_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()); | |||
} | |||
} |
@@ -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 @@ import org.apache.poi.ss.util.CellReference; | |||
* </ul> | |||
* | |||
* @author Josh Micich | |||
* @author Vladimirs Abramovs(Vladimirs.Abramovs at exigenservices.com) - handling of ArrayRecords | |||
*/ | |||
public final class SharedValueManager { | |||
@@ -112,12 +115,12 @@ public final class SharedValueManager { | |||
/** | |||
* @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 @@ public final class SharedValueManager { | |||
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 @@ public final class SharedValueManager { | |||
_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 @@ public final class SharedValueManager { | |||
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 @@ public final class SharedValueManager { | |||
} | |||
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; | |||
} | |||
} |
@@ -43,6 +43,7 @@ import org.apache.poi.hssf.record.SubRecord; | |||
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.CellStyle; | |||
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 @@ public class HSSFCell implements Cell { | |||
} | |||
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(); | |||
} | |||
} |
@@ -31,6 +31,7 @@ import java.util.List; | |||
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.SCLRecord; | |||
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 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet { | |||
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()]); | |||
} | |||
} |
@@ -72,6 +72,9 @@ final class OperandClassTransformer { | |||
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; |
@@ -21,6 +21,7 @@ import java.util.Calendar; | |||
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 @@ public interface Cell { | |||
* @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(); | |||
} |
@@ -781,4 +781,20 @@ public interface Sheet extends Iterable<Row> { | |||
*/ | |||
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); | |||
} |
@@ -77,8 +77,11 @@ public class CellRangeAddress extends CellRangeAddressBase { | |||
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(); | |||
} | |||
@@ -22,6 +22,7 @@ import java.util.regex.Pattern; | |||
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 class CellReference { | |||
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 @@ public class CellReference { | |||
} | |||
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); | |||
} | |||
} |
@@ -407,9 +407,9 @@ public final class XSSFCell implements Cell { | |||
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(); |
@@ -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()); | |||
} | |||
} |
@@ -914,139 +914,4 @@ public class TestXSSFSheet extends BaseTestSheet { | |||
//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)); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -24,7 +24,13 @@ import org.apache.poi.hssf.record.FormulaRecord; | |||
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 @@ public final class TestFormulaRecordAggregate extends TestCase { | |||
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 @@ public final class TestFormulaRecordAggregate extends TestCase { | |||
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); | |||
} | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -20,6 +20,7 @@ package org.apache.poi.hssf.usermodel; | |||
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.WindowTwoRecord; | |||
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 @@ public final class TestHSSFSheet extends BaseTestSheet { | |||
s.setRightToLeft(true); | |||
assertEquals(true, s.isRightToLeft()); | |||
} | |||
} |
@@ -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()); | |||
} | |||
} | |||
} |