git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1850676 13f79535-47bb-0310-9956-ffa450edef68pull/141/head
@@ -43,6 +43,7 @@ import org.apache.poi.ss.formula.eval.ErrorEval; | |||
import org.apache.poi.ss.formula.ptg.ExpPtg; | |||
import org.apache.poi.ss.formula.ptg.Ptg; | |||
import org.apache.poi.ss.usermodel.Cell; | |||
import org.apache.poi.ss.usermodel.CellBase; | |||
import org.apache.poi.ss.usermodel.CellStyle; | |||
import org.apache.poi.ss.usermodel.CellType; | |||
import org.apache.poi.ss.usermodel.Comment; | |||
@@ -68,7 +69,7 @@ import org.apache.poi.util.Removal; | |||
* cells that have values should be added. | |||
* <p> | |||
*/ | |||
public class HSSFCell implements Cell { | |||
public class HSSFCell extends CellBase { | |||
private static final String FILE_FORMAT_NAME = "BIFF8"; | |||
/** | |||
* The maximum number of columns in BIFF8 | |||
@@ -255,17 +256,10 @@ public class HSSFCell implements Cell { | |||
return new CellAddress(this); | |||
} | |||
/** | |||
* Set the cells type (numeric, formula or string). | |||
* If the cell currently contains a value, the value will | |||
* be converted to match the new type, if possible. | |||
*/ | |||
@Override | |||
public void setCellType(CellType cellType) { | |||
protected void setCellTypeImpl(CellType cellType) { | |||
notifyFormulaChanging(); | |||
if(isPartOfArrayFormulaGroup()){ | |||
notifyArrayFormulaChanging(); | |||
} | |||
int row=_record.getRow(); | |||
short col=_record.getColumn(); | |||
short styleIndex=_record.getXFIndex(); | |||
@@ -594,26 +588,21 @@ public class HSSFCell implements Cell { | |||
_stringValue.setUnicodeString(_book.getWorkbook().getSSTString(index)); | |||
} | |||
public void setCellFormula(String formula) { | |||
if(isPartOfArrayFormulaGroup()){ | |||
notifyArrayFormulaChanging(); | |||
} | |||
@Override | |||
protected void setCellFormulaImpl(String formula) { | |||
assert formula != null; | |||
int row=_record.getRow(); | |||
short col=_record.getColumn(); | |||
short styleIndex=_record.getXFIndex(); | |||
if (formula==null) { | |||
notifyFormulaChanging(); | |||
setCellType(CellType.BLANK, false, row, col, styleIndex); | |||
return; | |||
} | |||
int sheetIndex = _book.getSheetIndex(_sheet); | |||
Ptg[] ptgs = HSSFFormulaParser.parse(formula, _book, FormulaType.CELL, sheetIndex); | |||
setCellType(CellType.FORMULA, false, row, col, styleIndex); | |||
FormulaRecordAggregate agg = (FormulaRecordAggregate) _record; | |||
FormulaRecord frec = agg.getFormulaRecord(); | |||
frec.setOptions((short) 2); | |||
frec.setValue(0); | |||
//only set to default if there is no extended format index already set | |||
@@ -622,6 +611,42 @@ public class HSSFCell implements Cell { | |||
} | |||
agg.setParsedExpression(ptgs); | |||
} | |||
@Override | |||
protected void removeFormulaImpl() { | |||
assert getCellType() == CellType.FORMULA; | |||
notifyFormulaChanging(); | |||
switch (getCachedFormulaResultType()) { | |||
case NUMERIC: | |||
double numericValue = ((FormulaRecordAggregate)_record).getFormulaRecord().getValue(); | |||
_record = new NumberRecord(); | |||
((NumberRecord)_record).setValue(numericValue); | |||
_cellType = CellType.NUMERIC; | |||
break; | |||
case STRING: | |||
_record = new NumberRecord(); | |||
((NumberRecord)_record).setValue(0); | |||
_cellType = CellType.STRING; | |||
break; | |||
case BOOLEAN: | |||
boolean booleanValue = ((FormulaRecordAggregate)_record).getFormulaRecord().getCachedBooleanValue(); | |||
_record = new BoolErrRecord(); | |||
((BoolErrRecord)_record).setValue(booleanValue); | |||
_cellType = CellType.BOOLEAN; | |||
break; | |||
case ERROR: | |||
byte errorValue = (byte) ((FormulaRecordAggregate)_record).getFormulaRecord().getCachedErrorValue(); | |||
_record = new BoolErrRecord(); | |||
((BoolErrRecord)_record).setValue(errorValue); | |||
_cellType = CellType.ERROR; | |||
break; | |||
default: | |||
throw new AssertionError(); | |||
} | |||
} | |||
/** | |||
* Should be called any time that a formula could potentially be deleted. | |||
* Does nothing if this cell currently does not hold a formula | |||
@@ -1192,40 +1217,6 @@ public class HSSFCell implements Cell { | |||
return _cellType == CellType.FORMULA && ((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 #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); | |||
} | |||
/** | |||
* Applying a user-defined style (UDS) is special. Excel does not directly reference user-defined styles, but | |||
* instead create a 'proxy' ExtendedFormatRecord referencing the UDS as parent. |
@@ -164,7 +164,7 @@ public final class HSSFRow implements Row, Comparable<HSSFRow> { | |||
throw new RuntimeException("Specified cell is not from this row"); | |||
} | |||
if(cell.isPartOfArrayFormulaGroup()){ | |||
cell.notifyArrayFormulaChanging(); | |||
cell.tryToDeleteArrayFormula(null); | |||
} | |||
cells[column]=null; |
@@ -299,7 +299,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet { | |||
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); | |||
xcell.tryToDeleteArrayFormula(msg); | |||
} | |||
} | |||
@@ -1779,7 +1779,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet { | |||
for (Cell cell : row) { | |||
HSSFCell hcell = (HSSFCell) cell; | |||
if (hcell.isPartOfArrayFormulaGroup()) { | |||
hcell.notifyArrayFormulaChanging(msg); | |||
hcell.tryToDeleteArrayFormula(msg); | |||
} | |||
} | |||
} |
@@ -70,17 +70,22 @@ public interface Cell { | |||
Row getRow(); | |||
/** | |||
* Set the cells type (numeric, formula or string). | |||
* Set the cells type (blank, numeric, boolean, error or string). | |||
* <p>If the cell currently contains a value, the value will | |||
* be converted to match the new type, if possible. Formatting | |||
* is generally lost in the process however.</p> | |||
* <p>Conversion rules:</p> | |||
* <p>to NUMERIC: numeric value is left as is. True converts to 1.0, false converts to 0. otherwise, the | |||
* value is set to 0. Formula is removed.</p> | |||
* <p>If what you want to do is get a String value for your | |||
* numeric cell, <i>stop!</i>. This is not the way to do it. | |||
* Instead, for fetching the string value of a numeric or boolean | |||
* or date cell, use {@link DataFormatter} instead.</p> | |||
* | |||
* @throws IllegalArgumentException if the specified cell type is invalid | |||
* @throws IllegalStateException if the current value cannot be converted to the new type | |||
* or date cell, use {@link DataFormatter} instead.</p> | |||
* <p>If cell is a member of an array formula group containing more than 1 cell, an {@link IllegalStateException} | |||
* is thrown. If the array formula group contains only this cell, it is removed</p> | |||
* @throws IllegalArgumentException if the specified cell type is invalid (null or _NONE) | |||
* @throws IllegalStateException if the current value cannot be converted to the new type or | |||
* if the cell is a part of an array formula group containing other cells | |||
*/ | |||
void setCellType(CellType cellType); | |||
@@ -90,7 +95,7 @@ public interface Cell { | |||
* @return the cell type | |||
*/ | |||
CellType getCellType(); | |||
/** | |||
* Return the cell type. | |||
* | |||
@@ -101,13 +106,13 @@ public interface Cell { | |||
@Deprecated | |||
@Removal(version="4.2") | |||
CellType getCellTypeEnum(); | |||
/** | |||
* Only valid for formula cells | |||
* | |||
* | |||
* Will return {@link CellType} in a future version of POI. | |||
* For forwards compatibility, do not hard-code cell type literals in your code. | |||
* | |||
* | |||
* @return one of ({@link CellType#NUMERIC}, {@link CellType#STRING}, | |||
* {@link CellType#BOOLEAN}, {@link CellType#ERROR}) depending | |||
* on the cached value of the formula | |||
@@ -138,7 +143,7 @@ public interface Cell { | |||
/** | |||
* <p>Converts the supplied date to its equivalent Excel numeric value and sets | |||
* that into the cell.</p> | |||
* | |||
* | |||
* <p><b>Note</b> - There is actually no 'DATE' cell type in Excel. In many | |||
* cases (when entering date values), Excel automatically adjusts the | |||
* <i>cell style</i> to some date format, creating the illusion that the cell | |||
@@ -193,16 +198,33 @@ public interface Cell { | |||
/** | |||
* Sets formula for this cell. | |||
* | |||
* <p> | |||
* Note, this method only sets the formula string and does not calculate the formula value. | |||
* To set the precalculated value use {@link #setCellValue(double)} or {@link #setCellValue(String)} | |||
* To set the precalculated value use {@link #setCellValue} | |||
* </p> | |||
* | |||
* <p> | |||
* If the cell was blank, sets value to 0. Otherwise, preserves the value as precalculated. | |||
* </p> | |||
* | |||
* @param formula the formula to set, e.g. <code>"SUM(C4:E4)"</code>. | |||
* If the argument is <code>null</code> then the current formula is removed. | |||
* If the argument is <code>null</code> then the current formula is removed. | |||
* | |||
* @throws IllegalStateException if this cell is a part of an array formula group containing other cells | |||
* @throws FormulaParseException if the formula has incorrect syntax or is otherwise invalid | |||
*/ | |||
void setCellFormula(String formula) throws FormulaParseException; | |||
void setCellFormula(String formula) throws FormulaParseException, IllegalStateException; | |||
/** | |||
* Removes formula, if any. | |||
* | |||
* If cell was blank, leaves it as is. | |||
* If it is a part of an array formula group, blanks the cell. | |||
* If has a regular formula, removes the formula preserving the "cached" value. | |||
* @throws IllegalStateException if cell is a part of an array formula group containing other cells | |||
*/ | |||
void removeFormula() throws IllegalStateException; | |||
/** | |||
* Return a formula for the cell, for example, <code>SUM(C4:E4)</code> | |||
@@ -304,7 +326,7 @@ public interface Cell { | |||
/** | |||
* <p>Set the style for the cell. The style should be an CellStyle created/retrieved from | |||
* the Workbook.</p> | |||
* | |||
* | |||
* <p>To change the style of a cell without affecting other cells that use the same style, | |||
* use {@link org.apache.poi.ss.util.CellUtil#setCellStyleProperties(Cell, Map)}</p> | |||
* |
@@ -0,0 +1,137 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.ss.usermodel; | |||
import org.apache.poi.ss.formula.FormulaParseException; | |||
import org.apache.poi.ss.util.CellRangeAddress; | |||
import org.apache.poi.ss.util.CellReference; | |||
/** | |||
* Common implementation-independent logic shared by all implementations of {@link Cell}. | |||
* @author Vladislav "gallon" Galas gallon at apache dot org | |||
*/ | |||
public abstract class CellBase implements Cell { | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
public final void setCellType(CellType cellType) { | |||
if (cellType == null || cellType == CellType._NONE) { | |||
throw new IllegalArgumentException("cellType shall not be null nor _NONE"); | |||
} | |||
tryToDeleteArrayFormulaIfSet(); | |||
setCellTypeImpl(cellType); | |||
} | |||
/** | |||
* Implementation-specific logic | |||
* @param cellType new cell type. Guaranteed non-null, not _NONE. | |||
*/ | |||
protected abstract void setCellTypeImpl(CellType cellType); | |||
/** | |||
* Called when this an array formula in this cell is deleted. | |||
* <p>The purpose of this method is to validate the cell state prior to modification.</p> | |||
* | |||
* @param message a customized exception message for the case if deletion of the cell is impossible. If null, a | |||
* default message will be generated | |||
* @see #setCellType(CellType) | |||
* @see #setCellFormula(String) | |||
* @see Row#removeCell(org.apache.poi.ss.usermodel.Cell) | |||
* @see org.apache.poi.ss.usermodel.Sheet#removeRow(org.apache.poi.ss.usermodel.Row) | |||
* @see org.apache.poi.ss.usermodel.Sheet#shiftRows(int, int, int) | |||
* @see org.apache.poi.ss.usermodel.Sheet#addMergedRegion(org.apache.poi.ss.util.CellRangeAddress) | |||
* @throws IllegalStateException if modification is not allowed | |||
* | |||
* Note. Exposing this to public is ugly. Needed for methods like Sheet#shiftRows. | |||
*/ | |||
public final void tryToDeleteArrayFormula(String message) { | |||
assert isPartOfArrayFormulaGroup(); | |||
CellRangeAddress arrayFormulaRange = getArrayFormulaRange(); | |||
if(arrayFormulaRange.getNumberOfCells() > 1) { | |||
if (message == null) { | |||
message = "Cell " + new CellReference(this).formatAsString() + " is part of a multi-cell array formula. " + | |||
"You cannot change part of an array."; | |||
} | |||
throw new IllegalStateException(message); | |||
} | |||
//un-register the single-cell array formula from the parent sheet through public interface | |||
getRow().getSheet().removeArrayFormula(this); | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
public final void setCellFormula(String formula) throws FormulaParseException, IllegalStateException { | |||
if (formula == null) { | |||
removeFormula(); | |||
return; | |||
} | |||
CellType previousValueType = getCellType() == CellType.FORMULA ? getCachedFormulaResultType() : getCellType(); | |||
tryToDeleteArrayFormulaIfSet(); | |||
setCellFormulaImpl(formula); | |||
if (previousValueType == CellType.BLANK) { | |||
setCellValue(0); | |||
} | |||
} | |||
/** | |||
* Implementation-specific setting the formula. | |||
* Shall not change the value. | |||
* @param formula | |||
*/ | |||
protected abstract void setCellFormulaImpl(String formula); | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@Override | |||
public final void removeFormula() { | |||
if (getCellType() == CellType.BLANK) { | |||
return; | |||
} | |||
if (isPartOfArrayFormulaGroup()) { | |||
tryToDeleteArrayFormula(null); | |||
return; | |||
} | |||
removeFormulaImpl(); | |||
} | |||
/** | |||
* Implementation-specific removal of the formula. | |||
* The cell is guaranteed to have a regular formula set. | |||
* Shall preserve the "cached" value. | |||
*/ | |||
protected abstract void removeFormulaImpl(); | |||
private void tryToDeleteArrayFormulaIfSet() { | |||
if (isPartOfArrayFormulaGroup()) { | |||
tryToDeleteArrayFormula(null); | |||
} | |||
} | |||
} |
@@ -27,6 +27,7 @@ import org.apache.poi.ss.SpreadsheetVersion; | |||
import org.apache.poi.ss.formula.FormulaParseException; | |||
import org.apache.poi.ss.formula.eval.ErrorEval; | |||
import org.apache.poi.ss.usermodel.Cell; | |||
import org.apache.poi.ss.usermodel.CellBase; | |||
import org.apache.poi.ss.usermodel.CellStyle; | |||
import org.apache.poi.ss.usermodel.CellType; | |||
import org.apache.poi.ss.usermodel.Comment; | |||
@@ -45,7 +46,7 @@ import org.apache.poi.xssf.usermodel.XSSFRichTextString; | |||
/** | |||
* Streaming version of XSSFCell implementing the "BigGridDemo" strategy. | |||
*/ | |||
public class SXSSFCell implements Cell { | |||
public class SXSSFCell extends CellBase { | |||
private final SXSSFRow _row; | |||
private Value _value; | |||
private CellStyle _style; | |||
@@ -111,14 +112,8 @@ public class SXSSFCell implements Cell { | |||
return _row; | |||
} | |||
/** | |||
* Set the cells type (numeric, formula or string) | |||
* | |||
* @throws IllegalArgumentException if the specified cell type is invalid | |||
*/ | |||
@Override | |||
public void setCellType(CellType cellType) | |||
{ | |||
protected void setCellTypeImpl(CellType cellType) { | |||
ensureType(cellType); | |||
} | |||
@@ -331,7 +326,7 @@ public class SXSSFCell implements Cell { | |||
* @throws FormulaParseException if the formula has incorrect syntax or is otherwise invalid | |||
*/ | |||
@Override | |||
public void setCellFormula(String formula) throws FormulaParseException | |||
public void setCellFormulaImpl(String formula) throws FormulaParseException | |||
{ | |||
if(formula == null) { | |||
setType(CellType.BLANK); | |||
@@ -341,6 +336,36 @@ public class SXSSFCell implements Cell { | |||
ensureFormulaType(computeTypeFromFormula(formula)); | |||
((FormulaValue)_value).setValue(formula); | |||
} | |||
@Override | |||
protected void removeFormulaImpl() { | |||
assert getCellType() == CellType.FORMULA; | |||
switch (getCachedFormulaResultType()) { | |||
case NUMERIC: | |||
double numericValue = ((NumericFormulaValue)_value).getPreEvaluatedValue(); | |||
_value = new NumericValue(); | |||
((NumericValue) _value).setValue(numericValue); | |||
break; | |||
case STRING: | |||
String stringValue = ((StringFormulaValue)_value).getPreEvaluatedValue(); | |||
_value = new PlainStringValue(); | |||
((PlainStringValue) _value).setValue(stringValue); | |||
break; | |||
case BOOLEAN: | |||
boolean booleanValue = ((BooleanFormulaValue)_value).getPreEvaluatedValue(); | |||
_value = new BooleanValue(); | |||
((BooleanValue) _value).setValue(booleanValue); | |||
break; | |||
case ERROR: | |||
byte errorValue = ((ErrorFormulaValue)_value).getPreEvaluatedValue(); | |||
_value = new ErrorValue(); | |||
((ErrorValue) _value).setValue(errorValue); | |||
break; | |||
default: | |||
throw new AssertionError(); | |||
} | |||
} | |||
/** | |||
* Return a formula for the cell, for example, <code>SUM(C4:E4)</code> | |||
* |
@@ -30,6 +30,7 @@ import org.apache.poi.ss.formula.SharedFormula; | |||
import org.apache.poi.ss.formula.eval.ErrorEval; | |||
import org.apache.poi.ss.formula.ptg.Ptg; | |||
import org.apache.poi.ss.usermodel.Cell; | |||
import org.apache.poi.ss.usermodel.CellBase; | |||
import org.apache.poi.ss.usermodel.CellCopyPolicy; | |||
import org.apache.poi.ss.usermodel.CellStyle; | |||
import org.apache.poi.ss.usermodel.CellType; | |||
@@ -70,7 +71,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellType; | |||
* cells that have values should be added. | |||
* </p> | |||
*/ | |||
public final class XSSFCell implements Cell { | |||
public final class XSSFCell extends CellBase { | |||
private static final String FALSE_AS_STRING = "0"; | |||
private static final String TRUE_AS_STRING = "1"; | |||
@@ -549,10 +550,7 @@ public final class XSSFCell implements Cell { | |||
* when the cell is a part of a multi-cell array formula | |||
*/ | |||
@Override | |||
public void setCellFormula(String formula) { | |||
if(isPartOfArrayFormulaGroup()){ | |||
notifyArrayFormulaChanging(); | |||
} | |||
protected void setCellFormulaImpl(String formula) { | |||
setFormula(formula, FormulaType.CELL); | |||
} | |||
@@ -565,7 +563,7 @@ public final class XSSFCell implements Cell { | |||
private void setFormula(String formula, FormulaType formulaType) { | |||
XSSFWorkbook wb = _row.getSheet().getWorkbook(); | |||
if (formula == null) { | |||
if (formulaType == FormulaType.ARRAY && formula == null) { | |||
wb.onDeleteFormula(this); | |||
if (_cell.isSetF()) { | |||
_row.getSheet().onDeleteFormula(this, null); | |||
@@ -597,6 +595,15 @@ public final class XSSFCell implements Cell { | |||
} | |||
} | |||
@Override | |||
protected void removeFormulaImpl() { | |||
_row.getSheet().getWorkbook().onDeleteFormula(this); | |||
if (_cell.isSetF()) { | |||
_row.getSheet().onDeleteFormula(this, null); | |||
_cell.unsetF(); | |||
} | |||
} | |||
/** | |||
* Returns column index of this cell | |||
* | |||
@@ -960,13 +967,8 @@ public final class XSSFCell implements Cell { | |||
_cell.setR(ref); | |||
} | |||
/** | |||
* Set the cells type (numeric, formula or string) | |||
* | |||
* @throws IllegalArgumentException if the specified cell type is invalid | |||
*/ | |||
@Override | |||
public void setCellType(CellType cellType) { | |||
protected void setCellTypeImpl(CellType cellType) { | |||
setCellType(cellType, null); | |||
} | |||
@@ -978,10 +980,6 @@ public final class XSSFCell implements Cell { | |||
*/ | |||
protected void setCellType(CellType cellType, BaseXSSFEvaluationWorkbook evalWb) { | |||
CellType prevType = getCellType(); | |||
if(isPartOfArrayFormulaGroup()){ | |||
notifyArrayFormulaChanging(); | |||
} | |||
if(prevType == CellType.FORMULA && cellType != CellType.FORMULA) { | |||
if (_cell.isSetF()) { | |||
_row.getSheet().onDeleteFormula(this, evalWb); | |||
@@ -1307,48 +1305,12 @@ public final class XSSFCell implements Cell { | |||
return getSheet().isCellInArrayFormulaContext(this); | |||
} | |||
/** | |||
* The purpose of this method is to validate the cell state prior to modification | |||
* | |||
* @see #notifyArrayFormulaChanging() | |||
*/ | |||
void notifyArrayFormulaChanging(String msg){ | |||
if(isPartOfArrayFormulaGroup()){ | |||
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); | |||
//Moved from XSSFRow.shift(). Not sure what is purpose. | |||
public void updateCellReferencesForShifting(String msg){ | |||
if(isPartOfArrayFormulaGroup()) { | |||
tryToDeleteArrayFormula(msg); | |||
} | |||
} | |||
/** | |||
* Called when this cell is modified. | |||
* <p> | |||
* The purpose of this method is to validate the cell state prior to modification. | |||
* </p> | |||
* | |||
* @see #setCellType(CellType) | |||
* @see #setCellFormula(String) | |||
* @see XSSFRow#removeCell(org.apache.poi.ss.usermodel.Cell) | |||
* @see org.apache.poi.xssf.usermodel.XSSFSheet#removeRow(org.apache.poi.ss.usermodel.Row) | |||
* @see org.apache.poi.xssf.usermodel.XSSFSheet#shiftRows(int, int, int) | |||
* @see org.apache.poi.xssf.usermodel.XSSFSheet#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); | |||
} | |||
//Moved from XSSFRow.shift(). Not sure what is purpose. | |||
public void updateCellReferencesForShifting(String msg){ | |||
if(isPartOfArrayFormulaGroup()) | |||
notifyArrayFormulaChanging(msg); | |||
CalculationChain calcChain = getSheet().getWorkbook().getCalculationChain(); | |||
int sheetId = (int)getSheet().sheet.getSheetId(); | |||
@@ -480,7 +480,7 @@ public class XSSFRow implements Row, Comparable<XSSFRow> { | |||
XSSFCell xcell = (XSSFCell)cell; | |||
if(xcell.isPartOfArrayFormulaGroup()) { | |||
xcell.notifyArrayFormulaChanging(); | |||
xcell.setCellFormula(null); // to remove the array formula | |||
} | |||
if(cell.getCellType() == CellType.FORMULA) { | |||
_sheet.getWorkbook().onDeleteFormula(xcell); |
@@ -41,6 +41,7 @@ import org.apache.poi.xssf.usermodel.XSSFRichTextString; | |||
import org.apache.poi.xssf.usermodel.XSSFWorkbook; | |||
import org.apache.xmlbeans.XmlCursor; | |||
import org.junit.AfterClass; | |||
import org.junit.Ignore; | |||
import org.junit.Test; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRst; | |||
@@ -146,4 +147,35 @@ public class TestSXSSFCell extends BaseTestXCell { | |||
byte result = cell.getErrorCellValue(); | |||
assertEquals(0, result); | |||
} | |||
/** | |||
* For now, {@link SXSSFCell} doesn't support array formulas. | |||
* However, this test should be enabled if array formulas are implemented for SXSSF. | |||
*/ | |||
@Override | |||
@Ignore | |||
public void setCellType_BLANK_removesArrayFormula_ifCellIsPartOfAnArrayFormulaGroupContainingOnlyThisCell() { | |||
} | |||
/** | |||
* For now, {@link SXSSFCell} doesn't support array formulas. | |||
* However, this test should be enabled if array formulas are implemented for SXSSF. | |||
*/ | |||
@Override | |||
@Ignore | |||
@Test // <- annotation is necessary to override expected exception | |||
public void setCellType_BLANK_throwsISE_ifCellIsPartOfAnArrayFormulaGroupContainingOtherCells() { | |||
} | |||
@Override | |||
@Ignore | |||
@Test | |||
public void setCellFormula_throwsISE_ifCellIsPartOfAnArrayFormulaGroupContainingOtherCells() { | |||
} | |||
@Override | |||
@Ignore | |||
@Test | |||
public void removeFormula_turnsCellToBlank_whenFormulaWasASingleCellArrayFormula() { | |||
} | |||
} |
@@ -37,6 +37,7 @@ import org.apache.poi.common.usermodel.HyperlinkType; | |||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
import org.apache.poi.ss.ITestDataProvider; | |||
import org.apache.poi.ss.SpreadsheetVersion; | |||
import org.apache.poi.ss.util.CellRangeAddress; | |||
import org.apache.poi.util.LocaleUtil; | |||
import org.junit.Test; | |||
@@ -1200,4 +1201,109 @@ public abstract class BaseTestCell { | |||
assertEquals(CellType.NUMERIC, cell.getCellType()); | |||
assertEquals(value, cell.getNumericCellValue(), 0); | |||
} | |||
@Test(expected = IllegalArgumentException.class) | |||
public void setCellType_null_throwsIAE() { | |||
Cell cell = getInstance(); | |||
cell.setCellType(null); | |||
} | |||
@Test(expected = IllegalArgumentException.class) | |||
public void setCellType_NONE_throwsIAE() { | |||
Cell cell = getInstance(); | |||
cell.setCellType(CellType._NONE); | |||
} | |||
@Test | |||
public void setCellType_BLANK_removesArrayFormula_ifCellIsPartOfAnArrayFormulaGroupContainingOnlyThisCell() { | |||
Cell cell = getInstance(); | |||
cell.getSheet().setArrayFormula("1", CellRangeAddress.valueOf("A1")); | |||
cell.setCellValue("foo"); | |||
assertTrue(cell.isPartOfArrayFormulaGroup()); | |||
assertEquals("1", cell.getCellFormula()); | |||
cell.setCellType(CellType.BLANK); | |||
assertEquals(CellType.BLANK, cell.getCellType()); | |||
assertFalse(cell.isPartOfArrayFormulaGroup()); | |||
} | |||
@Test(expected = IllegalStateException.class) | |||
public void setCellType_BLANK_throwsISE_ifCellIsPartOfAnArrayFormulaGroupContainingOtherCells() { | |||
Cell cell = getInstance(); | |||
cell.getSheet().setArrayFormula("1", CellRangeAddress.valueOf("A1:B1")); | |||
cell.setCellValue("foo"); | |||
cell.setCellType(CellType.BLANK); | |||
} | |||
@Test(expected = IllegalStateException.class) | |||
public void setCellFormula_throwsISE_ifCellIsPartOfAnArrayFormulaGroupContainingOtherCells() { | |||
Cell cell = getInstance(); | |||
cell.getSheet().setArrayFormula("1", CellRangeAddress.valueOf("A1:B1")); | |||
assertTrue(cell.isPartOfArrayFormulaGroup()); | |||
assertEquals(CellType.FORMULA, cell.getCellType()); | |||
cell.setCellFormula("1"); | |||
} | |||
@Test | |||
public void removeFormula_preservesValue() { | |||
Cell cell = getInstance(); | |||
cell.setCellFormula("#DIV/0!"); | |||
cell.setCellValue(true); | |||
cell.removeFormula(); | |||
assertEquals(CellType.BOOLEAN, cell.getCellType()); | |||
assertTrue(cell.getBooleanCellValue()); | |||
cell.setCellFormula("#DIV/0!"); | |||
cell.setCellValue(2); | |||
cell.removeFormula(); | |||
assertEquals(CellType.NUMERIC, cell.getCellType()); | |||
assertEquals(2, cell.getNumericCellValue(), 0); | |||
cell.setCellFormula("#DIV/0!"); | |||
cell.setCellValue("foo"); | |||
cell.removeFormula(); | |||
assertEquals(CellType.STRING, cell.getCellType()); | |||
assertEquals("foo", cell.getStringCellValue()); | |||
cell.setCellFormula("#DIV/0!"); | |||
cell.setCellErrorValue(FormulaError.NUM.getCode()); | |||
cell.removeFormula(); | |||
assertEquals(CellType.ERROR, cell.getCellType()); | |||
assertEquals(FormulaError.NUM.getCode(), cell.getErrorCellValue()); | |||
} | |||
@Test | |||
public void removeFormula_turnsCellToBlank_whenFormulaWasASingleCellArrayFormula() { | |||
Cell cell = getInstance(); | |||
cell.getSheet().setArrayFormula("#DIV/0!", CellRangeAddress.valueOf("A1")); | |||
cell.setCellValue(true); | |||
cell.removeFormula(); | |||
assertEquals(CellType.BLANK, cell.getCellType()); | |||
cell.getSheet().setArrayFormula("#DIV/0!", CellRangeAddress.valueOf("A1")); | |||
cell.setCellValue(2); | |||
cell.removeFormula(); | |||
assertEquals(CellType.BLANK, cell.getCellType()); | |||
cell.getSheet().setArrayFormula("#DIV/0!", CellRangeAddress.valueOf("A1")); | |||
cell.setCellValue(true); | |||
cell.removeFormula(); | |||
assertEquals(CellType.BLANK, cell.getCellType()); | |||
cell.getSheet().setArrayFormula("#DIV/0!", CellRangeAddress.valueOf("A1")); | |||
cell.setCellErrorValue(FormulaError.NUM.getCode()); | |||
cell.removeFormula(); | |||
assertEquals(CellType.BLANK, cell.getCellType()); | |||
} | |||
private Cell getInstance() { | |||
return _testDataProvider.createWorkbook().createSheet().createRow(0).createCell(0); | |||
} | |||
} |