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! -->
|
||||
<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>
|
||||
|
@ -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>
|
||||
|
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
|
||||
*/
|
||||
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());
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
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