git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@996265 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_7_BETA3
@@ -34,6 +34,7 @@ | |||
<changes> | |||
<release version="3.7-beta3" date="2010-??-??"> | |||
<action dev="poi-developers" type="fix">49872 - avoid exception in XSSFFormulaEvaluator.evaluateInCell when evaluating shared formulas</action> | |||
<action dev="poi-developers" type="fix">49895 - avoid corruption of XSSFWorkbook after removing all merged cells from sheet</action> | |||
<action dev="poi-developers" type="fix">49907 - fixed inconsistent behaviour between HSSF and XSSF when creating consecutive names</action> | |||
<action dev="poi-developers" type="add">Add getMimeType() method to HWPF Picture, alongside existing file extension</action> |
@@ -373,20 +373,27 @@ public final class XSSFCell implements Cell { | |||
/** | |||
* Creates a non shared formula from the shared formula counterpart | |||
* | |||
* @param si Shared Group Index | |||
* @return non shared formula created for the given shared formula and this cell | |||
*/ | |||
private String convertSharedFormula(int idx){ | |||
private String convertSharedFormula(int si){ | |||
XSSFSheet sheet = getSheet(); | |||
XSSFCell sfCell = sheet.getSharedFormulaCell(idx); | |||
if(sfCell == null){ | |||
throw new IllegalStateException("Shared Formula not found for group index " + idx); | |||
} | |||
String sharedFormula = sfCell.getCTCell().getF().getStringValue(); | |||
CTCellFormula f = sheet.getSharedFormula(si); | |||
if(f == null) throw new IllegalStateException( | |||
"Master cell of a shared formula with sid="+si+" was not found"); | |||
String sharedFormula = f.getStringValue(); | |||
//Range of cells which the shared formula applies to | |||
String sharedFormulaRange = f.getRef(); | |||
CellRangeAddress ref = CellRangeAddress.valueOf(sharedFormulaRange); | |||
int sheetIndex = sheet.getWorkbook().getSheetIndex(sheet); | |||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(sheet.getWorkbook()); | |||
Ptg[] ptgs = FormulaParser.parse(sharedFormula, fpb, FormulaType.CELL, sheetIndex); | |||
Ptg[] fmla = SharedFormulaRecord.convertSharedFormulas(ptgs, | |||
getRowIndex() - sfCell.getRowIndex(), getColumnIndex() - sfCell.getColumnIndex()); | |||
getRowIndex() - ref.getFirstRow(), getColumnIndex() - ref.getFirstColumn()); | |||
return FormulaRenderer.toFormulaString(fpb, fmla); | |||
} | |||
@@ -85,7 +85,11 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { | |||
private List<XSSFHyperlink> hyperlinks; | |||
private ColumnHelper columnHelper; | |||
private CommentsTable sheetComments; | |||
private Map<Integer, XSSFCell> sharedFormulas; | |||
/** | |||
* cache of master shared formulas in this sheet. | |||
* Master shared formula is the first formula in a group of shared formulas is saved in the f element. | |||
*/ | |||
private Map<Integer, CTCellFormula> sharedFormulas; | |||
private List<CellRangeAddress> arrayFormulas; | |||
private XSSFDataValidationHelper dataValidationHelper; | |||
@@ -168,7 +172,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { | |||
private void initRows(CTWorksheet worksheet) { | |||
_rows = new TreeMap<Integer, XSSFRow>(); | |||
sharedFormulas = new HashMap<Integer, XSSFCell>(); | |||
sharedFormulas = new HashMap<Integer, CTCellFormula>(); | |||
arrayFormulas = new ArrayList<CellRangeAddress>(); | |||
for (CTRow row : worksheet.getSheetData().getRowList()) { | |||
XSSFRow r = new XSSFRow(row, this); | |||
@@ -2401,12 +2405,12 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { | |||
} | |||
/** | |||
* Return a cell holding shared formula by shared group index | |||
* Return a master shared formula by index | |||
* | |||
* @param sid shared group index | |||
* @return a cell holding shared formula or <code>null</code> if not found | |||
* @return a CTCellFormula bean holding shared formula or <code>null</code> if not found | |||
*/ | |||
XSSFCell getSharedFormulaCell(int sid){ | |||
CTCellFormula getSharedFormula(int sid){ | |||
return sharedFormulas.get(sid); | |||
} | |||
@@ -2415,7 +2419,9 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { | |||
CTCell ct = cell.getCTCell(); | |||
CTCellFormula f = ct.getF(); | |||
if (f != null && f.getT() == STCellFormulaType.SHARED && f.isSetRef() && f.getStringValue() != null) { | |||
sharedFormulas.put((int)f.getSi(), cell); | |||
// save a detached copy to avoid XmlValueDisconnectedException, | |||
// this may happen when the master cell of a shared formula is changed | |||
sharedFormulas.put((int)f.getSi(), (CTCellFormula)f.copy()); | |||
} | |||
if (f != null && f.getT() == STCellFormulaType.ARRAY && f.getRef() != null) { | |||
arrayFormulas.add(CellRangeAddress.valueOf(f.getRef())); |
@@ -32,4 +32,29 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator { | |||
public void testSharedFormulas(){ | |||
baseTestSharedFormulas("shared_formulas.xlsx"); | |||
} | |||
public void testSharedFormulas_evaluateInCell(){ | |||
XSSFWorkbook wb = (XSSFWorkbook)_testDataProvider.openSampleWorkbook("49872.xlsx"); | |||
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator(); | |||
XSSFSheet sheet = wb.getSheetAt(0); | |||
double result = 3.0; | |||
// B3 is a master shared formula, C3 and D3 don't have the formula written in their f element. | |||
// Instead, the attribute si for a particular cell is used to figure what the formula expression | |||
// should be based on the cell's relative location to the master formula, e.g. | |||
// B3: <f t="shared" ref="B3:D3" si="0">B1+B2</f> | |||
// C3 and D3: <f t="shared" si="0"/> | |||
// get B3 and evaluate it in the cell | |||
XSSFCell b3 = sheet.getRow(2).getCell(1); | |||
assertEquals(result, evaluator.evaluateInCell(b3).getNumericCellValue()); | |||
//at this point the master formula is gone, but we are still able to evaluate dependent cells | |||
XSSFCell c3 = sheet.getRow(2).getCell(2); | |||
assertEquals(result, evaluator.evaluateInCell(c3).getNumericCellValue()); | |||
XSSFCell d3 = sheet.getRow(2).getCell(3); | |||
assertEquals(result, evaluator.evaluateInCell(d3).getNumericCellValue()); | |||
} | |||
} |