added suport for Calculation Chain in XSSF, remove reference from calculation chain when a formula is deleted (see bugzilla 46535)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@742077 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
771369c409
commit
1273d8e270
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
<!-- Don't forget to update status.xml too! -->
|
<!-- Don't forget to update status.xml too! -->
|
||||||
<release version="3.5-beta5" date="2008-??-??">
|
<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">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">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>
|
<action dev="POI-DEVELOPERS" type="fix">46647 - Fixed COUNTIF NE operator and other special cases involving type conversion</action>
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
<!-- Don't forget to update changes.xml too! -->
|
<!-- Don't forget to update changes.xml too! -->
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.5-beta5" date="2008-??-??">
|
<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">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">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>
|
<action dev="POI-DEVELOPERS" type="fix">46647 - Fixed COUNTIF NE operator and other special cases involving type conversion</action>
|
||||||
|
98
src/ooxml/java/org/apache/poi/xssf/model/CalculationChain.java
Executable file
98
src/ooxml/java/org/apache/poi/xssf/model/CalculationChain.java
Executable file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -369,12 +369,13 @@ public final class XSSFCell implements Cell {
|
|||||||
* @throws IllegalArgumentException if the formula is invalid
|
* @throws IllegalArgumentException if the formula is invalid
|
||||||
*/
|
*/
|
||||||
public void setCellFormula(String formula) {
|
public void setCellFormula(String formula) {
|
||||||
|
XSSFWorkbook wb = row.getSheet().getWorkbook();
|
||||||
if (formula == null && cell.isSetF()) {
|
if (formula == null && cell.isSetF()) {
|
||||||
|
wb.onDeleteFormula(this);
|
||||||
cell.unsetF();
|
cell.unsetF();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
XSSFWorkbook wb = row.getSheet().getWorkbook();
|
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
try {
|
try {
|
||||||
Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL, wb.getSheetIndex(getSheet()));
|
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;
|
return CELL_TYPE_ERROR;
|
||||||
case STCellType.INT_S: // String is in shared strings
|
case STCellType.INT_S: // String is in shared strings
|
||||||
case STCellType.INT_INLINE_STR: // String is inline in cell
|
case STCellType.INT_INLINE_STR: // String is inline in cell
|
||||||
return CELL_TYPE_STRING;
|
|
||||||
case STCellType.INT_STR:
|
case STCellType.INT_STR:
|
||||||
return CELL_TYPE_FORMULA;
|
return CELL_TYPE_STRING;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Illegal cell type: " + this.cell.getT());
|
throw new IllegalStateException("Illegal cell type: " + this.cell.getT());
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import org.apache.poi.POIXMLDocumentPart;
|
|||||||
import org.apache.poi.xssf.model.StylesTable;
|
import org.apache.poi.xssf.model.StylesTable;
|
||||||
import org.apache.poi.xssf.model.SharedStringsTable;
|
import org.apache.poi.xssf.model.SharedStringsTable;
|
||||||
import org.apache.poi.xssf.model.CommentsTable;
|
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.POILogFactory;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||||
@ -184,7 +185,12 @@ public final class XSSFRelation extends POIXMLRelation {
|
|||||||
"/xl/theme/theme#.xml",
|
"/xl/theme/theme#.xml",
|
||||||
null
|
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) {
|
private XSSFRelation(String type, String rel, String defaultName, Class<? extends POIXMLDocumentPart> cls) {
|
||||||
|
@ -47,6 +47,7 @@ import org.apache.poi.util.POILogger;
|
|||||||
import org.apache.poi.util.PackageHelper;
|
import org.apache.poi.util.PackageHelper;
|
||||||
import org.apache.poi.xssf.model.SharedStringsTable;
|
import org.apache.poi.xssf.model.SharedStringsTable;
|
||||||
import org.apache.poi.xssf.model.StylesTable;
|
import org.apache.poi.xssf.model.StylesTable;
|
||||||
|
import org.apache.poi.xssf.model.CalculationChain;
|
||||||
import org.apache.xmlbeans.XmlException;
|
import org.apache.xmlbeans.XmlException;
|
||||||
import org.apache.xmlbeans.XmlObject;
|
import org.apache.xmlbeans.XmlObject;
|
||||||
import org.apache.xmlbeans.XmlOptions;
|
import org.apache.xmlbeans.XmlOptions;
|
||||||
@ -110,6 +111,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
|
|||||||
*/
|
*/
|
||||||
private StylesTable stylesSource;
|
private StylesTable stylesSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
|
private CalculationChain calcChain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to keep track of the data formatter so that all
|
* Used to keep track of the data formatter so that all
|
||||||
* createDataFormatter calls return the same one for a given
|
* 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()){
|
for(POIXMLDocumentPart p : getRelations()){
|
||||||
if(p instanceof SharedStringsTable) sharedStringSource = (SharedStringsTable)p;
|
if(p instanceof SharedStringsTable) sharedStringSource = (SharedStringsTable)p;
|
||||||
else if(p instanceof StylesTable) stylesSource = (StylesTable)p;
|
else if(p instanceof StylesTable) stylesSource = (StylesTable)p;
|
||||||
|
else if(p instanceof CalculationChain) calcChain = (CalculationChain)p;
|
||||||
else if (p instanceof XSSFSheet) {
|
else if (p instanceof XSSFSheet) {
|
||||||
shIdMap.put(p.getPackageRelationship().getId(), (XSSFSheet)p);
|
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));
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
59
src/ooxml/testcases/org/apache/poi/xssf/model/TestCalculationChain.java
Executable file
59
src/ooxml/testcases/org/apache/poi/xssf/model/TestCalculationChain.java
Executable file
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
BIN
src/testcases/org/apache/poi/hssf/data/46535.xlsx
Executable file
BIN
src/testcases/org/apache/poi/hssf/data/46535.xlsx
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user