]> source.dussan.org Git - poi.git/commitdiff
added suport for Calculation Chain in XSSF, remove reference from calculation chain...
authorYegor Kozlov <yegor@apache.org>
Sun, 8 Feb 2009 12:45:55 +0000 (12:45 +0000)
committerYegor Kozlov <yegor@apache.org>
Sun, 8 Feb 2009 12:45:55 +0000 (12:45 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@742077 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/ooxml/java/org/apache/poi/xssf/model/CalculationChain.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
src/ooxml/testcases/org/apache/poi/xssf/model/TestCalculationChain.java [new file with mode: 0755]
src/testcases/org/apache/poi/hssf/data/46535.xlsx [new file with mode: 0755]

index 292f202f803950eb312db5811dcc2b06e9e7f919..9a22b181d39c7c553c8836f4317d1e5460aa3479 100644 (file)
@@ -37,6 +37,7 @@
 
                <!-- Don't forget to update status.xml too! -->
         <release version="3.5-beta5" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">46535 - Remove reference from calculation chain when a formula is deleted</action>
            <action dev="POI-DEVELOPERS" type="fix">46654 - HSSFRow/RowRecord to properly update cell boundary indexes</action>
            <action dev="POI-DEVELOPERS" type="fix">46643 - Fixed formula parser to encode range operator with tMemFunc</action>
            <action dev="POI-DEVELOPERS" type="fix">46647 - Fixed COUNTIF NE operator and other special cases involving type conversion</action>
index d4f168efe5e36e1c2edab5f45b3fabfcb946e0c1..e44a128436d5b87a8ffb930f1ce5f547a133c499 100644 (file)
@@ -34,6 +34,7 @@
        <!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.5-beta5" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">46535 - Remove reference from calculation chain when a formula is deleted</action>
            <action dev="POI-DEVELOPERS" type="fix">46654 - HSSFRow/RowRecord to properly update cell boundary indexes</action>
            <action dev="POI-DEVELOPERS" type="fix">46643 - Fixed formula parser to encode range operator with tMemFunc</action>
            <action dev="POI-DEVELOPERS" type="fix">46647 - Fixed COUNTIF NE operator and other special cases involving type conversion</action>
diff --git a/src/ooxml/java/org/apache/poi/xssf/model/CalculationChain.java b/src/ooxml/java/org/apache/poi/xssf/model/CalculationChain.java
new file mode 100755 (executable)
index 0000000..2d6aadc
--- /dev/null
@@ -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.model;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.POIXMLDocumentPart;
+import org.apache.xmlbeans.XmlException;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackageRelationship;
+
+/**
+ * The cells in a workbook can be calculated in different orders depending on various optimizations and
+ * dependencies. The calculation chain object specifies the order in which the cells in a workbook were last calculated.
+ *
+ * @author Yegor Kozlov
+ */
+public class CalculationChain extends POIXMLDocumentPart {
+    private CTCalcChain chain;
+
+    public CalculationChain() {
+        super();
+        chain = CTCalcChain.Factory.newInstance();
+    }
+
+    public CalculationChain(PackagePart part, PackageRelationship rel) throws IOException {
+        super(part, rel);
+        readFrom(part.getInputStream());
+    }
+
+    public void readFrom(InputStream is) throws IOException {
+        try {
+            CalcChainDocument doc = CalcChainDocument.Factory.parse(is);
+            chain = doc.getCalcChain();
+        } catch (XmlException e) {
+            throw new IOException(e.getLocalizedMessage());
+        }
+    }
+    public void writeTo(OutputStream out) throws IOException {
+        CalcChainDocument doc = CalcChainDocument.Factory.newInstance();
+        doc.setCalcChain(chain);
+        doc.save(out, DEFAULT_XML_OPTIONS);
+    }
+
+    @Override
+    protected void commit() throws IOException {
+        PackagePart part = getPackagePart();
+        OutputStream out = part.getOutputStream();
+        writeTo(out);
+        out.close();
+    }
+
+
+    public CTCalcChain getCTCalcChain(){
+        return chain;
+    }
+
+    /**
+     * Remove a formula reference from the calculation chain
+     * 
+     * @param sheetId  the sheet Id of a sheet the formula belongs to.
+     * @param ref  A1 style reference to the cell containing the formula.
+     */
+    public void removeItem(int sheetId, String ref){
+        //sheet Id of a sheet the cell belongs to
+        int id = -1;
+        CTCalcCell[] c = chain.getCArray();
+        for (int i = 0; i < c.length; i++){
+            //If sheet Id  is omitted, it is assumed to be the same as the value of the previous cell.
+            if(c[i].isSetI()) id = c[i].getI();
+
+            if(id == sheetId && c[i].getR().equals(ref)){
+                if(c[i].isSetI() && i < c.length - 1 && !c[i+1].isSetI()) {
+                    c[i+1].setI(id);
+                }
+                chain.removeC(i);
+                break;
+            }
+        }
+    }
+}
\ No newline at end of file
index 0fdfa2c69ea1a43e164556861715e1c6ea8ce10a..b7d2713f58115d97c8b452e2bec13424a1f991e8 100644 (file)
@@ -369,12 +369,13 @@ public final class XSSFCell implements Cell {
      * @throws IllegalArgumentException if the formula is invalid
      */
     public void setCellFormula(String formula) {
+        XSSFWorkbook wb = row.getSheet().getWorkbook();
         if (formula == null && cell.isSetF()) {
+            wb.onDeleteFormula(this);
             cell.unsetF();
             return;
         }
 
-        XSSFWorkbook wb = row.getSheet().getWorkbook();
         XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
         try {
             Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL, wb.getSheetIndex(getSheet()));
@@ -482,9 +483,8 @@ public final class XSSFCell implements Cell {
                 return CELL_TYPE_ERROR;
             case STCellType.INT_S: // String is in shared strings
             case STCellType.INT_INLINE_STR: // String is inline in cell
-                return CELL_TYPE_STRING;
             case STCellType.INT_STR:
-                return CELL_TYPE_FORMULA;
+                 return CELL_TYPE_STRING;
             default:
                 throw new IllegalStateException("Illegal cell type: " + this.cell.getT());
         }
index b985d644068426b11cf85abe58d7326974cd3510..73fe263a263b5106e0e8f83758ea0e1d1fe73954 100644 (file)
@@ -28,6 +28,7 @@ import org.apache.poi.POIXMLDocumentPart;
 import org.apache.poi.xssf.model.StylesTable;
 import org.apache.poi.xssf.model.SharedStringsTable;
 import org.apache.poi.xssf.model.CommentsTable;
+import org.apache.poi.xssf.model.CalculationChain;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
@@ -184,7 +185,12 @@ public final class XSSFRelation extends POIXMLRelation {
             "/xl/theme/theme#.xml",
             null
     );
-       
+    public static final XSSFRelation CALC_CHAIN = new XSSFRelation(
+            "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml",
+            "http://schemas.openxmlformats.org/officeDocument/2006/relationships/calcChain",
+            "/xl/calcChain.xml",
+            CalculationChain.class
+    );
        
 
        private XSSFRelation(String type, String rel, String defaultName, Class<? extends POIXMLDocumentPart> cls) {
index 9a68eb7fb6344006adb5a6633aba93a9334f1d23..d3a6a4f605c553ed920c7fc6d7a372d63e7c0de6 100644 (file)
@@ -47,6 +47,7 @@ import org.apache.poi.util.POILogger;
 import org.apache.poi.util.PackageHelper;
 import org.apache.poi.xssf.model.SharedStringsTable;
 import org.apache.poi.xssf.model.StylesTable;
+import org.apache.poi.xssf.model.CalculationChain;
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlObject;
 import org.apache.xmlbeans.XmlOptions;
@@ -110,6 +111,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
      */
     private StylesTable stylesSource;
 
+    /**
+     * TODO
+     */
+    private CalculationChain calcChain;
+
     /**
      * Used to keep track of the data formatter so that all
      * createDataFormatter calls return the same one for a given
@@ -177,6 +183,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
             for(POIXMLDocumentPart p : getRelations()){
                 if(p instanceof SharedStringsTable) sharedStringSource = (SharedStringsTable)p;
                 else if(p instanceof StylesTable) stylesSource = (StylesTable)p;
+                else if(p instanceof CalculationChain) calcChain = (CalculationChain)p;
                 else if (p instanceof XSSFSheet) {
                     shIdMap.put(p.getPackageRelationship().getId(), (XSSFSheet)p);
                 }
@@ -1260,4 +1267,29 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
         ctSheet.setState(STSheetState.Enum.forInt(hidden));
     }
 
+    /**
+     * Fired when a formula is deleted from this workbook,
+     * for example when calling cell.setCellFormula(null)
+     *
+     * @see XSSFCell#setCellFormula(String) 
+     */
+    protected void onDeleteFormula(XSSFCell cell){
+        if(calcChain != null) {
+            int sheetId = (int)cell.getSheet().sheet.getSheetId();
+            calcChain.removeItem(sheetId, cell.getReference());
+        }
+    }
+
+    /**
+     * Return the CalculationChain object for this workbook
+     * <p>
+     *   The calculation chain object specifies the order in which the cells in a workbook were last calculated
+     * </p>
+     * 
+     * @return the <code>CalculationChain</code> object or <code>null</code> if not defined
+     */
+    public CalculationChain getCalculationChain(){
+        return calcChain;
+    }
+
 }
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/model/TestCalculationChain.java b/src/ooxml/testcases/org/apache/poi/xssf/model/TestCalculationChain.java
new file mode 100755 (executable)
index 0000000..191b328
--- /dev/null
@@ -0,0 +1,59 @@
+/* ====================================================================
+   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.model;
+
+import org.apache.poi.xssf.usermodel.*;
+import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
+
+import junit.framework.TestCase;
+
+
+public class TestCalculationChain extends TestCase {
+
+    public void test46535() throws Exception {
+        XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("46535.xlsx");
+
+        CalculationChain chain = wb.getCalculationChain();
+        //the bean holding the reference to the formula to be deleted
+        CTCalcCell c = chain.getCTCalcChain().getCArray(0);
+        int cnt = chain.getCTCalcChain().getCArray().length;
+        assertEquals(10, c.getI());
+        assertEquals("E1", c.getR());
+
+        XSSFSheet sheet = wb.getSheet("Test");
+        XSSFCell cell = sheet.getRow(0).getCell(4);
+
+        assertEquals(XSSFCell.CELL_TYPE_FORMULA, cell.getCellType());
+        cell.setCellFormula(null);
+
+        //the count of items is less by one 
+        c = chain.getCTCalcChain().getCArray(0);
+        int cnt2 =  chain.getCTCalcChain().getCArray().length;
+        assertEquals(cnt - 1, cnt2);
+        //the first item in the calculation chain is the former second one
+        assertEquals(10, c.getI());
+        assertEquals("C1", c.getR());
+
+        assertEquals(XSSFCell.CELL_TYPE_STRING, cell.getCellType());
+        cell.setCellValue("ABC");
+        assertEquals(XSSFCell.CELL_TYPE_STRING, cell.getCellType());
+    }
+
+
+}
\ No newline at end of file
diff --git a/src/testcases/org/apache/poi/hssf/data/46535.xlsx b/src/testcases/org/apache/poi/hssf/data/46535.xlsx
new file mode 100755 (executable)
index 0000000..555145b
Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/46535.xlsx differ