added HSSF usermodel tests for array formulas, added support for array formulas in ss interfaces
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@893870 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
b3093fc671
commit
aba7267376
@ -17,7 +17,10 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record;
|
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.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.ss.formula.Formula;
|
||||||
import org.apache.poi.util.HexDump;
|
import org.apache.poi.util.HexDump;
|
||||||
import org.apache.poi.util.LittleEndianOutput;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
@ -28,6 +31,7 @@ import org.apache.poi.util.LittleEndianOutput;
|
|||||||
* Treated in a similar way to SharedFormulaRecord
|
* Treated in a similar way to SharedFormulaRecord
|
||||||
*
|
*
|
||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
|
* @author Vladimirs Abramovs(Vladimirs.Abramovs at exigenservices.com) - Array Formula support
|
||||||
*/
|
*/
|
||||||
public final class ArrayRecord extends SharedValueRecordBase {
|
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_ALWAYS_RECALCULATE = 0x0001;
|
||||||
private static final int OPT_CALCULATE_ON_OPEN = 0x0002;
|
private static final int OPT_CALCULATE_ON_OPEN = 0x0002;
|
||||||
|
|
||||||
private int _options;
|
private int _options;
|
||||||
private int _field3notUsed;
|
private int _field3notUsed;
|
||||||
private Formula _formula;
|
private Formula _formula;
|
||||||
|
|
||||||
@ -48,6 +52,13 @@ public final class ArrayRecord extends SharedValueRecordBase {
|
|||||||
_formula = Formula.read(formulaTokenLen, in, totalFormulaLen);
|
_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() {
|
public boolean isAlwaysRecalculate() {
|
||||||
return (_options & OPT_ALWAYS_RECALCULATE) != 0;
|
return (_options & OPT_ALWAYS_RECALCULATE) != 0;
|
||||||
}
|
}
|
||||||
@ -55,7 +66,11 @@ public final class ArrayRecord extends SharedValueRecordBase {
|
|||||||
return (_options & OPT_CALCULATE_ON_OPEN) != 0;
|
return (_options & OPT_CALCULATE_ON_OPEN) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getExtraDataSize() {
|
public void setOptions(int val){
|
||||||
|
_options = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getExtraDataSize() {
|
||||||
return 2 + 4
|
return 2 + 4
|
||||||
+ _formula.getEncodedSize();
|
+ _formula.getEncodedSize();
|
||||||
}
|
}
|
||||||
@ -84,4 +99,42 @@ public final class ArrayRecord extends SharedValueRecordBase {
|
|||||||
sb.append("]");
|
sb.append("]");
|
||||||
return sb.toString();
|
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;
|
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.CellValueRecordInterface;
|
||||||
import org.apache.poi.hssf.record.FormulaRecord;
|
import org.apache.poi.hssf.record.FormulaRecord;
|
||||||
import org.apache.poi.hssf.record.Record;
|
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.StringRecord;
|
||||||
import org.apache.poi.hssf.record.formula.ExpPtg;
|
import org.apache.poi.hssf.record.formula.ExpPtg;
|
||||||
import org.apache.poi.hssf.record.formula.Ptg;
|
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.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
|
* 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).
|
* (optional) string record and (optional) Shared Formula Record (template reads, excel optimization).
|
||||||
*
|
*
|
||||||
* @author Glen Stampoultzis (glens at apache.org)
|
* @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 {
|
public final class FormulaRecordAggregate extends RecordAggregate implements CellValueRecordInterface {
|
||||||
|
|
||||||
@ -181,10 +186,15 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Ptg[] getFormulaTokens() {
|
public Ptg[] getFormulaTokens() {
|
||||||
if (_sharedFormulaRecord == null) {
|
if (_sharedFormulaRecord != null) {
|
||||||
return _formulaRecord.getParsedExpression();
|
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);
|
_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;
|
package org.apache.poi.hssf.record.aggregates;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.poi.hssf.record.ArrayRecord;
|
import org.apache.poi.hssf.record.ArrayRecord;
|
||||||
@ -41,6 +43,7 @@ import org.apache.poi.ss.util.CellReference;
|
|||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
|
* @author Vladimirs Abramovs(Vladimirs.Abramovs at exigenservices.com) - handling of ArrayRecords
|
||||||
*/
|
*/
|
||||||
public final class SharedValueManager {
|
public final class SharedValueManager {
|
||||||
|
|
||||||
@ -112,12 +115,12 @@ public final class SharedValueManager {
|
|||||||
/**
|
/**
|
||||||
* @return a new empty {@link 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.
|
// Note - must create distinct instances because they are assumed to be mutable.
|
||||||
return new SharedValueManager(
|
return new SharedValueManager(
|
||||||
new SharedFormulaRecord[0], new CellReference[0], new ArrayRecord[0], new TableRecord[0]);
|
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 TableRecord[] _tableRecords;
|
||||||
private final Map<SharedFormulaRecord, SharedFormulaGroup> _groupsBySharedFormulaRecord;
|
private final Map<SharedFormulaRecord, SharedFormulaGroup> _groupsBySharedFormulaRecord;
|
||||||
/** cached for optimization purposes */
|
/** cached for optimization purposes */
|
||||||
@ -129,7 +132,8 @@ public final class SharedValueManager {
|
|||||||
if (nShF != firstCells.length) {
|
if (nShF != firstCells.length) {
|
||||||
throw new IllegalArgumentException("array sizes don't match: " + 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;
|
_tableRecords = tableRecords;
|
||||||
Map<SharedFormulaRecord, SharedFormulaGroup> m = new HashMap<SharedFormulaRecord, SharedFormulaGroup>(nShF * 3 / 2);
|
Map<SharedFormulaRecord, SharedFormulaGroup> m = new HashMap<SharedFormulaRecord, SharedFormulaGroup>(nShF * 3 / 2);
|
||||||
for (int i = 0; i < nShF; i++) {
|
for (int i = 0; i < nShF; i++) {
|
||||||
@ -139,14 +143,6 @@ public final class SharedValueManager {
|
|||||||
_groupsBySharedFormulaRecord = m;
|
_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,
|
public static SharedValueManager create(SharedFormulaRecord[] sharedFormulaRecords,
|
||||||
CellReference[] firstCells, ArrayRecord[] arrayRecords, TableRecord[] tableRecords) {
|
CellReference[] firstCells, ArrayRecord[] arrayRecords, TableRecord[] tableRecords) {
|
||||||
if (sharedFormulaRecords.length + firstCells.length + arrayRecords.length + tableRecords.length < 1) {
|
if (sharedFormulaRecords.length + firstCells.length + arrayRecords.length + tableRecords.length < 1) {
|
||||||
@ -260,8 +256,7 @@ public final class SharedValueManager {
|
|||||||
return tr;
|
return tr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < _arrayRecords.length; i++) {
|
for (ArrayRecord ar : _arrayRecords) {
|
||||||
ArrayRecord ar = _arrayRecords[i];
|
|
||||||
if (ar.isFirstCell(row, column)) {
|
if (ar.isFirstCell(row, column)) {
|
||||||
return ar;
|
return ar;
|
||||||
}
|
}
|
||||||
@ -281,4 +276,40 @@ public final class SharedValueManager {
|
|||||||
}
|
}
|
||||||
svg.unlinkSharedFormulas();
|
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.TextObjectRecord;
|
||||||
import org.apache.poi.hssf.record.UnicodeString;
|
import org.apache.poi.hssf.record.UnicodeString;
|
||||||
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
|
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.Ptg;
|
||||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
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.Comment;
|
||||||
import org.apache.poi.ss.usermodel.Hyperlink;
|
import org.apache.poi.ss.usermodel.Hyperlink;
|
||||||
import org.apache.poi.ss.usermodel.RichTextString;
|
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.NumberToTextConverter;
|
||||||
|
import org.apache.poi.ss.util.CellReference;
|
||||||
import org.apache.poi.ss.formula.FormulaType;
|
import org.apache.poi.ss.formula.FormulaType;
|
||||||
import org.apache.poi.ss.SpreadsheetVersion;
|
import org.apache.poi.ss.SpreadsheetVersion;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
@ -1160,4 +1163,31 @@ public class HSSFCell implements Cell {
|
|||||||
}
|
}
|
||||||
return ((FormulaRecordAggregate)_record).getFormulaRecord().getCachedResultType();
|
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 java.util.TreeMap;
|
||||||
|
|
||||||
import org.apache.poi.ddf.EscherRecord;
|
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.InternalSheet;
|
||||||
import org.apache.poi.hssf.model.InternalWorkbook;
|
import org.apache.poi.hssf.model.InternalWorkbook;
|
||||||
import org.apache.poi.hssf.record.CellValueRecordInterface;
|
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.WSBoolRecord;
|
||||||
import org.apache.poi.hssf.record.WindowTwoRecord;
|
import org.apache.poi.hssf.record.WindowTwoRecord;
|
||||||
import org.apache.poi.hssf.record.aggregates.DataValidityTable;
|
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.aggregates.WorksheetProtectionBlock;
|
||||||
import org.apache.poi.hssf.record.formula.FormulaShifter;
|
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.PaneInformation;
|
||||||
import org.apache.poi.hssf.util.Region;
|
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.Cell;
|
||||||
import org.apache.poi.ss.usermodel.CellStyle;
|
import org.apache.poi.ss.usermodel.CellStyle;
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
import org.apache.poi.ss.util.CellRangeAddress;
|
import org.apache.poi.ss.util.CellRangeAddress;
|
||||||
|
import org.apache.poi.ss.util.CellReference;
|
||||||
import org.apache.poi.ss.SpreadsheetVersion;
|
import org.apache.poi.ss.SpreadsheetVersion;
|
||||||
import org.apache.poi.util.POILogFactory;
|
import org.apache.poi.util.POILogFactory;
|
||||||
import org.apache.poi.util.POILogger;
|
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);
|
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:
|
case FormulaType.CELL:
|
||||||
rootNodeOperandClass = Ptg.CLASS_VALUE;
|
rootNodeOperandClass = Ptg.CLASS_VALUE;
|
||||||
break;
|
break;
|
||||||
|
case FormulaType.ARRAY:
|
||||||
|
rootNodeOperandClass = Ptg.CLASS_ARRAY;
|
||||||
|
break;
|
||||||
case FormulaType.NAMEDRANGE:
|
case FormulaType.NAMEDRANGE:
|
||||||
case FormulaType.DATAVALIDATION_LIST:
|
case FormulaType.DATAVALIDATION_LIST:
|
||||||
rootNodeOperandClass = Ptg.CLASS_REF;
|
rootNodeOperandClass = Ptg.CLASS_REF;
|
||||||
|
@ -21,6 +21,7 @@ import java.util.Calendar;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.apache.poi.ss.formula.FormulaParseException;
|
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.
|
* 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
|
* @param link hypelrink associated with this cell
|
||||||
*/
|
*/
|
||||||
void setHyperlink(Hyperlink link);
|
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();
|
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 cellRefFrom = new CellReference(getFirstRow(), getFirstColumn());
|
||||||
CellReference cellRefTo = new CellReference(getLastRow(), getLastColumn());
|
CellReference cellRefTo = new CellReference(getLastRow(), getLastColumn());
|
||||||
sb.append(cellRefFrom.formatAsString());
|
sb.append(cellRefFrom.formatAsString());
|
||||||
sb.append(':');
|
//for a single-cell reference return A1 instead of A1:A1
|
||||||
sb.append(cellRefTo.formatAsString());
|
if(!cellRefFrom.equals(cellRefTo)){
|
||||||
|
sb.append(':');
|
||||||
|
sb.append(cellRefTo.formatAsString());
|
||||||
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
import org.apache.poi.hssf.record.formula.SheetNameFormatter;
|
import org.apache.poi.hssf.record.formula.SheetNameFormatter;
|
||||||
import org.apache.poi.ss.SpreadsheetVersion;
|
import org.apache.poi.ss.SpreadsheetVersion;
|
||||||
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -114,6 +115,10 @@ public class CellReference {
|
|||||||
this(pRow, pCol & 0xFFFF, false, false);
|
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) {
|
public CellReference(int pRow, int pCol, boolean pAbsRow, boolean pAbsCol) {
|
||||||
this(null, pRow, pCol, pAbsRow, pAbsCol);
|
this(null, pRow, pCol, pAbsRow, pAbsCol);
|
||||||
}
|
}
|
||||||
@ -483,4 +488,22 @@ public class CellReference {
|
|||||||
}
|
}
|
||||||
sb.append(_rowIndex+1);
|
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);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
//validate through the FormulaParser
|
//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);
|
f.setStringValue(formula);
|
||||||
_cell.setF(f);
|
_cell.setF(f);
|
||||||
if(_cell.isSetV()) _cell.unsetV();
|
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
|
//existing cells are invalidated
|
||||||
assertEquals(0, wsh.getSheetData().getRowArray(0).sizeOfCArray());
|
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.Record;
|
||||||
import org.apache.poi.hssf.record.RecordFormatException;
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
import org.apache.poi.hssf.record.StringRecord;
|
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.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");
|
s.setString("abc");
|
||||||
FormulaRecordAggregate fagg = new FormulaRecordAggregate(f, s, SharedValueManager.createEmpty());
|
FormulaRecordAggregate fagg = new FormulaRecordAggregate(f, s, SharedValueManager.createEmpty());
|
||||||
assertEquals("abc", fagg.getStringValue());
|
assertEquals("abc", fagg.getStringValue());
|
||||||
}
|
assertFalse(fagg.isPartOfArrayFormula());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sometimes a {@link StringRecord} appears after a {@link FormulaRecord} even though the
|
* 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(1, vraRecs.length);
|
||||||
assertEquals(fr, vraRecs[0]);
|
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.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import junit.framework.AssertionFailedError;
|
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.record.aggregates.WorksheetProtectionBlock;
|
||||||
import org.apache.poi.hssf.usermodel.RecordInspector.RecordCollector;
|
import org.apache.poi.hssf.usermodel.RecordInspector.RecordCollector;
|
||||||
import org.apache.poi.ss.usermodel.BaseTestSheet;
|
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.CellRangeAddress;
|
||||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||||
import org.apache.poi.util.TempFile;
|
import org.apache.poi.util.TempFile;
|
||||||
@ -820,5 +824,4 @@ public final class TestHSSFSheet extends BaseTestSheet {
|
|||||||
s.setRightToLeft(true);
|
s.setRightToLeft(true);
|
||||||
assertEquals(true, s.isRightToLeft());
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user