return _bookEvaluator;
}
+ /**
+ * internal use
+ * @return evaluation workbook
+ */
+ protected EvaluationWorkbook getEvaluationWorkbook() {
+ return _bookEvaluator.getWorkbook();
+ }
+
/**
* Should be called whenever there are major changes (e.g. moving sheets) to input cells
* in the evaluated workbook. If performance is not critical, a single call to this method
return evaluateFormulaCell(cell);
}
- protected static void setCellType(Cell cell, CellValue cv) {
+ /**
+ * set the cell type
+ * @param cell
+ * @param cv
+ */
+ protected void setCellType(Cell cell, CellValue cv) {
CellType cellType = cv.getCellType();
switch (cellType) {
case BOOLEAN:
case ERROR:
case NUMERIC:
case STRING:
- cell.setCellType(cellType);
+ setCellType(cell, cellType);
return;
case BLANK:
// never happens - blanks eventually get translated to zero
throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
}
}
+
+ /**
+ * Override if a different variation is needed, e.g. passing the evaluator to the cell method
+ * @param cell
+ * @param cellType
+ */
+ protected void setCellType(Cell cell, CellType cellType) {
+ cell.setCellType(cellType);
+ }
protected abstract RichTextString createRichTextString(String str);
/**
* Sets array formula to specified region for result.
- *
+ * <p>
+ * Note if there are shared formulas this will invalidate any
+ * {@link FormulaEvaluator} instances based on this workbook
+ *</p>
* @param formula text representation of the formula
* @param range Region of array formula for result.
* @return the {@link CellRange} of cells affected by this change
import org.apache.poi.ss.formula.BaseFormulaEvaluator;
import org.apache.poi.ss.formula.EvaluationCell;
+import org.apache.poi.ss.formula.EvaluationWorkbook;
import org.apache.poi.ss.formula.WorkbookEvaluator;
import org.apache.poi.ss.formula.eval.BoolEval;
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.StringEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.RichTextString;
}
throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")");
}
+
+ protected void setCellType(Cell cell, CellType cellType) {
+ EvaluationWorkbook evaluationWorkbook = getEvaluationWorkbook();
+ BaseXSSFEvaluationWorkbook xewb = BaseXSSFEvaluationWorkbook.class.isAssignableFrom(evaluationWorkbook.getClass()) ? (BaseXSSFEvaluationWorkbook) evaluationWorkbook : null;
+
+ ((XSSFCell) cell).setCellType(cellType, xewb);
+ }
}
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.FormulaError;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Hyperlink;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
* @return a formula for the cell
* @throws IllegalStateException if the cell type returned by {@link #getCellType()} is not {@link CellType#FORMULA}
*/
- protected String getCellFormula(XSSFEvaluationWorkbook fpb) {
+ protected String getCellFormula(BaseXSSFEvaluationWorkbook fpb) {
CellType cellType = getCellType();
if(cellType != CellType.FORMULA) {
throw typeMismatch(CellType.FORMULA, cellType, false);
* @param si Shared Group Index
* @return non shared formula created for the given shared formula and this cell
*/
- private String convertSharedFormula(int si, XSSFEvaluationWorkbook fpb){
+ private String convertSharedFormula(int si, BaseXSSFEvaluationWorkbook fpb){
XSSFSheet sheet = getSheet();
CTCellFormula f = sheet.getSharedFormula(si);
* 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)}
* </p>
+ * <p>
+ * Note, if there are any shared formulas, his will invalidate any
+ * {@link FormulaEvaluator} instances based on this workbook.
+ * </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 (formula == null) {
wb.onDeleteFormula(this);
if (_cell.isSetF()) {
- _row.getSheet().onDeleteFormula(this);
+ _row.getSheet().onDeleteFormula(this, null);
_cell.unsetF();
}
return;
*/
@Override
public void setCellType(CellType cellType) {
+ setCellType(cellType, null);
+ }
+
+ /**
+ * Needed by bug #62834, which points out getCellFormula() expects an evaluation context or creates a new one,
+ * so if there is one in use, it needs to be carried on through.
+ * @param cellType
+ * @param evalWb BaseXSSFEvaluationWorkbook already in use, or null if a new implicit one should be used
+ */
+ protected void setCellType(CellType cellType, BaseXSSFEvaluationWorkbook evalWb) {
CellType prevType = getCellType();
if(isPartOfArrayFormulaGroup()){
}
if(prevType == CellType.FORMULA && cellType != CellType.FORMULA) {
if (_cell.isSetF()) {
- _row.getSheet().onDeleteFormula(this);
+ _row.getSheet().onDeleteFormula(this, evalWb);
}
getSheet().getWorkbook().onDeleteFormula(this);
}
/**
* when a cell with a 'master' shared formula is removed, the next cell in the range becomes the master
+ * @param cell
+ * @param evalWb BaseXSSFEvaluationWorkbook in use, if one exists
*/
- protected void onDeleteFormula(XSSFCell cell){
+ protected void onDeleteFormula(XSSFCell cell, BaseXSSFEvaluationWorkbook evalWb){
CTCellFormula f = cell.getCTCell().getF();
if (f != null && f.getT() == STCellFormulaType.SHARED && f.isSetRef() && f.getStringValue() != null) {
XSSFRow row = getRow(i);
if(row != null) for(int j = cell.getColumnIndex(); j <= ref.getLastColumn(); j++){
XSSFCell nextCell = row.getCell(j);
- if(nextCell != null && nextCell != cell){
+ if(nextCell != null && nextCell != cell && nextCell.getCellType() == CellType.FORMULA){
CTCellFormula nextF = nextCell.getCTCell().getF();
- nextF.setStringValue(nextCell.getCellFormula());
+ nextF.setStringValue(nextCell.getCellFormula(evalWb));
CellRangeAddress nextRef = new CellRangeAddress(
nextCell.getRowIndex(), ref.getLastRow(),
nextCell.getColumnIndex(), ref.getLastColumn());
package org.apache.poi.xssf.usermodel;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.usermodel.BaseTestFormulaEvaluator;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellValue;
+import org.apache.poi.ss.usermodel.CreationHelper;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.XSSFITestDataProvider;
import org.apache.poi.xssf.XSSFTestDataSamples;
assertEquals("D 0,068", evaluator.evaluate(wb.getSheetAt(0).getRow(1).getCell(1)));
}
+ /**
+ * see bug 62275
+ * @throws IOException
+ */
@Test
public void testBug62275() throws IOException {
try (Workbook wb = new XSSFWorkbook()) {
eval.evaluate(cell);
}
}
+
+ /**
+ * see bug 62834, handle when a shared formula range doesn't contain only formula cells
+ * @throws IOException
+ */
+ @Test
+ public void testBug62834() throws IOException {
+ try (Workbook wb = XSSFTestDataSamples.openSampleWorkbook("62834.xlsx")) {
+ FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
+
+ Cell a2 = wb.getSheetAt(0).getRow(1).getCell(0);
+ Cell value = evaluator.evaluateInCell(a2);
+ assertEquals("wrong value A2", "a value", value.getStringCellValue());
+
+// evaluator.clearAllCachedResultValues();
+
+ Cell a3 = wb.getSheetAt(0).getRow(2).getCell(0);
+ value = evaluator.evaluateInCell(a3);
+ assertEquals("wrong value A3", "a value", value.getStringCellValue());
+
+ Cell a5 = wb.getSheetAt(0).getRow(4).getCell(0);
+ value = evaluator.evaluateInCell(a5);
+ assertEquals("wrong value A5", "another value", value.getStringCellValue());
+ }
+ }
}