]> source.dussan.org Git - poi.git/commitdiff
unified setCellType(null/_NONE) logic, setCellFormula(null) logic. updated javadoc...
authorVladislav Galas <gallon@apache.org>
Mon, 7 Jan 2019 19:10:19 +0000 (19:10 +0000)
committerVladislav Galas <gallon@apache.org>
Mon, 7 Jan 2019 19:10:19 +0000 (19:10 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1850676 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
src/java/org/apache/poi/hssf/usermodel/HSSFRow.java
src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
src/java/org/apache/poi/ss/usermodel/Cell.java
src/java/org/apache/poi/ss/usermodel/CellBase.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFCell.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java
src/ooxml/testcases/org/apache/poi/xssf/streaming/TestSXSSFCell.java
src/testcases/org/apache/poi/ss/usermodel/BaseTestCell.java

index 35c234a4496615d8e3e613a9f4b262928d913b1e..ee4d828d5ef2c3aafc0b3c0dfee3ecc0c9ffaef6 100644 (file)
@@ -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.
index 845b58a00949fd1c25d35aa890f6b8926936e7a5..9f5461cff397b9b560b22640d23b121b8bd59c86 100644 (file)
@@ -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;
index de3b05c1e5fde495544c8b978cafd92822bf2a9b..48a90959075d3b0051d292549b0477e3b0baa750 100644 (file)
@@ -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);
             }
         }
     }
index 13ddfd65187a4645d93e24958c120be880b1192d..b255c03abe2a7baaf1a3ad0bb1c7992a6a1ccb67 100644 (file)
@@ -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>
      *
diff --git a/src/java/org/apache/poi/ss/usermodel/CellBase.java b/src/java/org/apache/poi/ss/usermodel/CellBase.java
new file mode 100644 (file)
index 0000000..5a7e1f2
--- /dev/null
@@ -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);
+        }
+    }
+}
index 8917e60105342191e3c8812731654ca22d6b7337..29b4b2652b9c90eddadf9ad83319f2dbfaa579c5 100644 (file)
@@ -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>
      *
index 864b031729b6194ceb1ba37696841fa19bb5d99b..e336ae458b1a7860359b46892fdf28284ec9506c 100644 (file)
@@ -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();
     
index 66307c206d27fb3d038fbb89b8543cb7ab951816..363fc5bd9bb746afeb509ab90ae7ba646309c32a 100644 (file)
@@ -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);
index d5f4b243d1d9a0078ffefaa43c0b63fee044bf10..7a030defd9dcc47f4107b149eefabbc3c6a65131 100644 (file)
@@ -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() {
+    }
 }
index 8705ea5094029dc47301194a7c4408bf4506eed1..242b4abeec4cf18ff5ea25933d4292a6b64d6895 100644 (file)
@@ -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);
+    }
 }