aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/org')
-rw-r--r--src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java8
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFCell.java43
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFRow.java4
-rw-r--r--src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java56
4 files changed, 109 insertions, 2 deletions
diff --git a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
index 07dd072ecb..a403d09e2d 100644
--- a/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
+++ b/src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
@@ -230,7 +230,9 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel
if (_sharedFormulaRecord != null) {
return false;
}
- return _formulaRecord.getFormula().getExpReference() != null;
+ CellReference expRef = _formulaRecord.getFormula().getExpReference();
+ ArrayRecord arec = expRef == null ? null : _sharedValueManager.getArrayRecord(expRef.getRow(), expRef.getCol());
+ return arec != null;
}
public CellRangeAddress getArrayFormulaRange() {
@@ -260,6 +262,8 @@ public final class FormulaRecordAggregate extends RecordAggregate implements Cel
*/
public CellRangeAddress removeArrayFormula(int rowIndex, int columnIndex) {
CellRangeAddress8Bit a = _sharedValueManager.removeArrayFormula(rowIndex, columnIndex);
- return new CellRangeAddress(a.getFirstRow(), a.getLastRow(), a.getFirstColumn(), a.getLastColumn());
+ // at this point FormulaRecordAggregate#isPartOfArrayFormula() should return false
+ _formulaRecord.setParsedExpression(null);
+ return new CellRangeAddress(a.getFirstRow(), a.getLastRow(), a.getFirstColumn(), a.getLastColumn());
}
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
index a543477136..071f1b4313 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
@@ -284,6 +284,9 @@ public class HSSFCell implements Cell {
*/
public void setCellType(int cellType) {
notifyFormulaChanging();
+ if(isPartOfArrayFormulaGroup()){
+ notifyArrayFormulaChanging();
+ }
int row=_record.getRow();
short col=_record.getColumn();
short styleIndex=_record.getXFIndex();
@@ -578,6 +581,10 @@ public class HSSFCell implements Cell {
}
public void setCellFormula(String formula) {
+ if(isPartOfArrayFormulaGroup()){
+ notifyArrayFormulaChanging();
+ }
+
int row=_record.getRow();
short col=_record.getColumn();
short styleIndex=_record.getXFIndex();
@@ -1191,4 +1198,40 @@ public class HSSFCell implements Cell {
}
return ((FormulaRecordAggregate)_record).isPartOfArrayFormula();
}
+
+ /**
+ * The purpose of this method is to validate the cell state prior to modification
+ *
+ * @see #notifyArrayFormulaChanging()
+ */
+ void notifyArrayFormulaChanging(String msg){
+ CellRangeAddress cra = getArrayFormulaRange();
+ if(cra.getNumberOfCells() > 1) {
+ throw new IllegalStateException(msg);
+ }
+ //un-register the single-cell array formula from the parent XSSFSheet
+ getRow().getSheet().removeArrayFormula(this);
+ }
+
+ /**
+ * Called when this cell is modified.
+ * <p>
+ * The purpose of this method is to validate the cell state prior to modification.
+ * </p>
+ *
+ * @see #setCellType(int)
+ * @see #setCellFormula(String)
+ * @see HSSFRow#removeCell(org.apache.poi.ss.usermodel.Cell)
+ * @see org.apache.poi.hssf.usermodel.HSSFSheet#removeRow(org.apache.poi.ss.usermodel.Row)
+ * @see org.apache.poi.hssf.usermodel.HSSFSheet#shiftRows(int, int, int)
+ * @see org.apache.poi.hssf.usermodel.HSSFSheet#addMergedRegion(org.apache.poi.ss.util.CellRangeAddress)
+ * @throws IllegalStateException if modification is not allowed
+ */
+ void notifyArrayFormulaChanging(){
+ CellReference ref = new CellReference(this);
+ String msg = "Cell "+ref.formatAsString()+" is part of a multi-cell array formula. " +
+ "You cannot change part of an array.";
+ notifyArrayFormulaChanging(msg);
+ }
+
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java
index 53938cf821..3d1c73497b 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFRow.java
@@ -163,6 +163,10 @@ public final class HSSFRow implements Row {
if(column >= cells.length || cell != cells[column]) {
throw new RuntimeException("Specified cell is not from this row");
}
+ if(cell.isPartOfArrayFormulaGroup()){
+ cell.notifyArrayFormulaChanging();
+ }
+
cells[column]=null;
if(alsoRemoveRecords) {
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
index 251b02c7fb..75e48cfa0f 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
@@ -238,6 +238,13 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
if (row.getSheet() != this) {
throw new IllegalArgumentException("Specified row does not belong to this sheet");
}
+ for(Cell cell : row) {
+ HSSFCell xcell = (HSSFCell)cell;
+ if(xcell.isPartOfArrayFormulaGroup()){
+ String msg = "Row[rownum="+row.getRowNum()+"] contains cell(s) included in a multi-cell array formula. You cannot change part of an array.";
+ xcell.notifyArrayFormulaChanging(msg);
+ }
+ }
if (_rows.size() > 0) {
Integer key = Integer.valueOf(row.getRowNum());
@@ -571,12 +578,45 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
public int addMergedRegion(CellRangeAddress region)
{
region.validate(SpreadsheetVersion.EXCEL97);
+
+ // throw IllegalStateException if the argument CellRangeAddress intersects with
+ // a multi-cell array formula defined in this sheet
+ validateArrayFormulas(region);
+
return _sheet.addMergedRegion( region.getFirstRow(),
region.getFirstColumn(),
region.getLastRow(),
region.getLastColumn());
}
+ private void validateArrayFormulas(CellRangeAddress region){
+ int firstRow = region.getFirstRow();
+ int firstColumn = region.getFirstColumn();
+ int lastRow = region.getLastRow();
+ int lastColumn = region.getLastColumn();
+ for (int rowIn = firstRow; rowIn <= lastRow; rowIn++) {
+ for (int colIn = firstColumn; colIn <= lastColumn; colIn++) {
+ HSSFRow row = getRow(rowIn);
+ if (row == null) continue;
+
+ HSSFCell cell = row.getCell(colIn);
+ if(cell == null) continue;
+
+ if(cell.isPartOfArrayFormulaGroup()){
+ CellRangeAddress arrayRange = cell.getArrayFormulaRange();
+ if (arrayRange.getNumberOfCells() > 1 &&
+ ( arrayRange.isInRange(region.getFirstRow(), region.getFirstColumn()) ||
+ arrayRange.isInRange(region.getFirstRow(), region.getFirstColumn())) ){
+ String msg = "The range " + region.formatAsString() + " intersects with a multi-cell array formula. " +
+ "You cannot merge cells of an array.";
+ throw new IllegalStateException(msg);
+ }
+ }
+ }
+ }
+
+ }
+
/**
* Whether a record must be inserted or not at generation to indicate that
* formula must be recalculated when workbook is opened.
@@ -1214,6 +1254,11 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
for ( int rowNum = s; rowNum >= startRow && rowNum <= endRow && rowNum >= 0 && rowNum < 65536; rowNum += inc ) {
HSSFRow row = getRow( rowNum );
+ // notify all cells in this row that we are going to shift them,
+ // it can throw IllegalStateException if the operation is not allowed, for example,
+ // if the row contains cells included in a multi-cell array formula
+ if(row != null) notifyRowShifting(row);
+
HSSFRow row2Replace = getRow( rowNum + n );
if ( row2Replace == null )
row2Replace = createRow( rowNum + n );
@@ -1301,6 +1346,17 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
_sheet.getRecords().addAll(window2Loc, records);
}
+ private void notifyRowShifting(HSSFRow row){
+ String msg = "Row[rownum="+row.getRowNum()+"] contains cell(s) included in a multi-cell array formula. " +
+ "You cannot change part of an array.";
+ for(Cell cell : row){
+ HSSFCell hcell = (HSSFCell)cell;
+ if(hcell.isPartOfArrayFormulaGroup()){
+ hcell.notifyArrayFormulaChanging(msg);
+ }
+ }
+ }
+
/**
* Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
* @param colSplit Horizonatal position of split.