<!-- Don't forget to update status.xml too! -->
<release version="3.5-beta5" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="fix">46433 - support for shared formulas in XSSF</action>
<action dev="POI-DEVELOPERS" type="add">46299 - support for carriage return and line break in XWPFRun</action>
<action dev="POI-DEVELOPERS" type="add">46300 - support for line spacing in XWPFParagraph</action>
<action dev="POI-DEVELOPERS" type="add">46308 - initial support for creation of XWPFTable</action>
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.5-beta5" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="fix">46433 - support for shared formulas in XSSF</action>
<action dev="POI-DEVELOPERS" type="add">46299 - support for carriage return and line break in XWPFRun</action>
<action dev="POI-DEVELOPERS" type="add">46300 - support for line spacing in XWPFParagraph</action>
<action dev="POI-DEVELOPERS" type="add">46308 - initial support for creation of XWPFTable</action>
package org.apache.poi.hssf.record;
-import org.apache.poi.hssf.record.formula.AreaNPtg;
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.Ptg;
-import org.apache.poi.hssf.record.formula.RefNPtg;
-import org.apache.poi.hssf.record.formula.RefPtg;
+import org.apache.poi.hssf.record.formula.*;
import org.apache.poi.hssf.util.CellRangeAddress8Bit;
import org.apache.poi.ss.formula.Formula;
import org.apache.poi.util.HexDump;
* Perhaps this functionality could be implemented in terms of the raw
* byte array inside {@link Formula}.
*/
- static Ptg[] convertSharedFormulas(Ptg[] ptgs, int formulaRow, int formulaColumn) {
+ public static Ptg[] convertSharedFormulas(Ptg[] ptgs, int formulaRow, int formulaColumn) {
Ptg[] newPtgStack = new Ptg[ptgs.length];
if (!ptg.isBaseToken()) {
originalOperandClass = ptg.getPtgClass();
}
- if (ptg instanceof RefNPtg) {
- RefNPtg refNPtg = (RefNPtg)ptg;
+ if (ptg instanceof RefPtgBase) {
+ RefPtgBase refNPtg = (RefPtgBase)ptg;
ptg = new RefPtg(fixupRelativeRow(formulaRow,refNPtg.getRow(),refNPtg.isRowRelative()),
fixupRelativeColumn(formulaColumn,refNPtg.getColumn(),refNPtg.isColRelative()),
refNPtg.isRowRelative(),
refNPtg.isColRelative());
- } else if (ptg instanceof AreaNPtg) {
- AreaNPtg areaNPtg = (AreaNPtg)ptg;
+ } else if (ptg instanceof AreaPtgBase) {
+ AreaPtgBase areaNPtg = (AreaPtgBase)ptg;
ptg = new AreaPtg(fixupRelativeRow(formulaRow,areaNPtg.getFirstRow(),areaNPtg.isFirstRowRelative()),
fixupRelativeRow(formulaRow,areaNPtg.getLastRow(),areaNPtg.isLastRowRelative()),
fixupRelativeColumn(formulaColumn,areaNPtg.getFirstColumn(),areaNPtg.isFirstColRelative()),
* Names can contain uppercase and lowercase letters.
* </li>
* </ul>
+ *
+ * <p>
+ * A name must always be unique within its scope. POI prevents you from defining a name that is not unique
+ * within its scope. However you can use the same name in different scopes. Example:
+ * <pre><blockquote>
+ * //by default names are workbook-global
+ * HSSFName name;
+ * name = workbook.createName();
+ * name.setNameName("sales_08");
+ *
+ * name = workbook.createName();
+ * name.setNameName("sales_08"); //will throw an exception: "The workbook already contains this name (case-insensitive)"
+ *
+ * //create sheet-level name
+ * name = workbook.createName();
+ * name.setSheetIndex(0); //the scope of the name is the first sheet
+ * name.setNameName("sales_08"); //ok
+ *
+ * name = workbook.createName();
+ * name.setSheetIndex(0);
+ * name.setNameName("sales_08"); //will throw an exception: "The sheet already contains this name (case-insensitive)"
+ *
+ * </blockquote></pre>
+ * </p>
+ *
* @param nameName named range name to set
- * @throws IllegalArgumentException if the name is invalid or the workbook already contains this name (case-insensitive)
+ * @throws IllegalArgumentException if the name is invalid or the name already exists (case-insensitive)
*/
public void setNameName(String nameName){
- _definedNameRec.setNameText(nameName);
Workbook wb = _book.getWorkbook();
+ _definedNameRec.setNameText(nameName);
+
+ int sheetNumber = _definedNameRec.getSheetNumber();
//Check to ensure no other names have the same case-insensitive name
for ( int i = wb.getNumNames()-1; i >=0; i-- )
{
NameRecord rec = wb.getNameRecord(i);
if (rec != _definedNameRec) {
- if (rec.getNameText().equalsIgnoreCase(getNameName()))
- throw new IllegalArgumentException("The workbook already contains this name (case-insensitive)");
+ if (rec.getNameText().equalsIgnoreCase(nameName) && sheetNumber == rec.getSheetNumber()){
+ String msg = "The "+(sheetNumber == 0 ? "workbook" : "sheet")+" already contains this name: " + nameName;
+ throw new IllegalArgumentException(msg);
+ }
}
}
}
* Names can contain uppercase and lowercase letters.
* </li>
* </ul>
+ * <p>
+ * A name must always be unique within its scope. POI prevents you from defining a name that is not unique
+ * within its scope. However you can use the same name in different scopes. Example:
+ * <pre><blockquote>
+ * //by default names are workbook-global
+ * Name name;
+ * name = workbook.createName();
+ * name.setNameName("sales_08");
+ *
+ * name = workbook.createName();
+ * name.setNameName("sales_08"); //will throw an exception: "The workbook already contains this name (case-insensitive)"
+ *
+ * //create sheet-level name
+ * name = workbook.createName();
+ * name.setSheetIndex(0); //the scope of the name is the first sheet
+ * name.setNameName("sales_08"); //ok
+ *
+ * name = workbook.createName();
+ * name.setSheetIndex(0);
+ * name.setNameName("sales_08"); //will throw an exception: "The sheet already contains this name (case-insensitive)"
+ *
+ * </blockquote></pre>
+ * </p>
* @param name named range name to set
- * @throws IllegalArgumentException if the name is invalid or the workbook already contains this name (case-insensitive)
+ * @throws IllegalArgumentException if the name is invalid or the already exists within its scope (case-insensitive)
*/
void setNameName(String name);
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.SharedFormulaRecord;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.formula.FormulaParser;
import org.apache.poi.ss.formula.FormulaType;
+import org.apache.poi.ss.formula.FormulaRenderer;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.POIXMLException;
+import org.apache.poi.util.POILogger;
+import org.apache.poi.util.POILogFactory;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellType;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType;
/**
* High level representation of a cell in a row of a spreadsheet.
* </p>
*/
public final class XSSFCell implements Cell {
+ private static POILogger logger = POILogFactory.getLogger(XSSFCell.class);
/**
* The maximum number of columns in SpreadsheetML
protected SharedStringsTable getSharedStringSource() {
return sharedStringSource;
}
-
+
/**
* @return table of cell styles shared across this workbook
*/
* @return the sheet this cell belongs to
*/
public XSSFSheet getSheet() {
- return getRow().getSheet();
- }
+ return getRow().getSheet();
+ }
/**
* Returns the row this cell belongs to
* @return the row this cell belongs to
*/
public XSSFRow getRow() {
- return row;
- }
+ return row;
+ }
/**
* Get the value of the cell as a boolean.
int cellType = getCellType();
if(cellType != CELL_TYPE_FORMULA) throw typeMismatch(CELL_TYPE_FORMULA, cellType, false);
- return this.cell.getF().getStringValue();
+ CTCellFormula f = cell.getF();
+ if(f.getT() == STCellFormulaType.SHARED){
+ return convertSharedFormula((int)f.getSi());
+ } else {
+ return f.getStringValue();
+ }
+ }
+
+ /**
+ * Creates a non shared formula from the shared formula counterpart
+ *
+ * @return non shared formula created for the given shared formula and this cell
+ */
+ private String convertSharedFormula(int idx){
+ 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();
+ XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(sheet.getWorkbook());
+ Ptg[] ptgs = FormulaParser.parse(sharedFormula, fpb);
+ Ptg[] fmla = SharedFormulaRecord.convertSharedFormulas(ptgs,
+ getRowIndex() - sfCell.getRowIndex(), getColumnIndex() - sfCell.getColumnIndex());
+ return FormulaRenderer.toFormulaString(fpb, fmla);
}
/**
* @return zero-based column index of a column in a sheet.
*/
public int getColumnIndex() {
- return this.cellNum;
+ return this.cellNum;
}
/**
* @return zero-based row index of a row in the sheet that contains this cell
*/
public int getRowIndex() {
- return row.getRowNum();
- }
+ return row.getRowNum();
+ }
/**
* Returns an A1 style reference to the location of this cell
* @return A1 style reference to the location of this cell
*/
public String getReference() {
- return cell.getR();
- }
+ return cell.getR();
+ }
/**
* Return the cell's style.
if(style == null) {
if(cell.isSetS()) cell.unsetS();
} else {
- XSSFCellStyle xStyle = (XSSFCellStyle)style;
- xStyle.verifyBelongsToStylesSource(stylesSource);
+ XSSFCellStyle xStyle = (XSSFCellStyle)style;
+ xStyle.verifyBelongsToStylesSource(stylesSource);
long idx = stylesSource.putStyle(xStyle);
cell.setS(idx);
* will change the cell to a numeric cell and set its value.
*/
public void setCellValue(Date value) {
- boolean date1904 = getSheet().getWorkbook().isDate1904();
+ boolean date1904 = getSheet().getWorkbook().isDate1904();
setCellValue(DateUtil.getExcelDate(value, date1904));
}
* will change the cell to a numeric cell and set its value.
*/
public void setCellValue(Calendar value) {
- boolean date1904 = getSheet().getWorkbook().isDate1904();
+ boolean date1904 = getSheet().getWorkbook().isDate1904();
setCellValue( DateUtil.getExcelDate(value, date1904 ));
}
* @return hyperlink associated with this cell or <code>null</code> if not found
*/
public XSSFHyperlink getHyperlink() {
- return getSheet().getHyperlink(row.getRowNum(), cellNum);
- }
+ return getSheet().getHyperlink(row.getRowNum(), cellNum);
+ }
/**
* Assign a hypelrink to this cell
* @param hyperlink the hypelrink to associate with this cell
*/
public void setHyperlink(Hyperlink hyperlink) {
- XSSFHyperlink link = (XSSFHyperlink)hyperlink;
-
- // Assign to us
- link.setCellReference( new CellReference(row.getRowNum(), cellNum).formatAsString() );
-
- // Add to the lists
- getSheet().setCellHyperlink(link);
- }
+ XSSFHyperlink link = (XSSFHyperlink)hyperlink;
+
+ // Assign to us
+ link.setCellReference( new CellReference(row.getRowNum(), cellNum).formatAsString() );
+
+ // Add to the lists
+ getSheet().setCellHyperlink(link);
+ }
/**
* Returns the xml bean containing information about the cell's location (reference), value,
* Sets the name that will appear in the user interface for the defined name.
* Names must begin with a letter or underscore, not contain spaces and be unique across the workbook.
*
+ * <p>
+ * A name must always be unique within its scope. POI prevents you from defining a name that is not unique
+ * within its scope. However you can use the same name in different scopes. Example:
+ * <pre><blockquote>
+ * //by default names are workbook-global
+ * XSSFName name;
+ * name = workbook.createName();
+ * name.setNameName("sales_08");
+ *
+ * name = workbook.createName();
+ * name.setNameName("sales_08"); //will throw an exception: "The workbook already contains this name (case-insensitive)"
+ *
+ * //create sheet-level name
+ * name = workbook.createName();
+ * name.setSheetIndex(0); //the scope of the name is the first sheet
+ * name.setNameName("sales_08"); //ok
+ *
+ * name = workbook.createName();
+ * name.setSheetIndex(0);
+ * name.setNameName("sales_08"); //will throw an exception: "The sheet already contains this name (case-insensitive)"
+ *
+ * </blockquote></pre>
+ * </p>
* @param name name of this defined name
* @throws IllegalArgumentException if the name is invalid or the workbook already contains this name (case-insensitive)
*/
public void setNameName(String name) {
validateName(name);
+ int sheetIndex = getSheetIndex();
+
//Check to ensure no other names have the same case-insensitive name
for (int i = 0; i < workbook.getNumberOfNames(); i++) {
XSSFName nm = workbook.getNameAt(i);
- if (nm != this && nm.getNameName().equalsIgnoreCase(name)) {
- throw new IllegalArgumentException("The workbook already contains this name: " + name);
+ if (nm != this) {
+ if(name.equalsIgnoreCase(nm.getNameName()) && sheetIndex == nm.getSheetIndex()){
+ String msg = "The "+(sheetIndex == -1 ? "workbook" : "sheet")+" already contains this name: " + name;
+ throw new IllegalArgumentException(msg);
+ }
}
}
ctName.setName(name);
this.cells = new TreeMap<Integer, Cell>();
for (CTCell c : row.getCArray()) {
XSSFCell cell = new XSSFCell(this, c);
- this.cells.put(cell.getColumnIndex(), cell);
+ cells.put(cell.getColumnIndex(), cell);
+ sheet.onReadCell(cell);
}
}
private List<XSSFHyperlink> hyperlinks;
private ColumnHelper columnHelper;
private CommentsTable sheetComments;
+ private Map<Integer, XSSFCell> sharedFormulas;
/**
* Creates new XSSFSheet - called by XSSFWorkbook to create a sheet from scratch.
private void initRows(CTWorksheet worksheet) {
rows = new TreeMap<Integer, Row>();
+ sharedFormulas = new HashMap<Integer, XSSFCell>();
for (CTRow row : worksheet.getSheetData().getRowArray()) {
XSSFRow r = new XSSFRow(row, this);
rows.put(r.getRowNum(), r);
return getDefaultSheetView().getPane();
}
+ /**
+ * Return a cell holding shared formula by shared group index
+ *
+ * @param sid shared group index
+ * @return a cell holding shared formula or <code>null</code> if not found
+ */
+ XSSFCell getSharedFormulaCell(int sid){
+ return sharedFormulas.get(sid);
+ }
+
+ void onReadCell(XSSFCell cell){
+ //collect cells holding shared formulas
+ 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);
+ }
+ }
@Override
protected void commit() throws IOException {
import junit.framework.TestCase;
-import org.apache.poi.ss.usermodel.Cell;
-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.*;
+import org.apache.poi.xssf.XSSFTestDataSamples;
public final class TestXSSFFormulaEvaluation extends TestCase {
- public TestXSSFFormulaEvaluation(String name) {
- super(name);
-
- // Use system out logger
- System.setProperty(
- "org.apache.poi.util.POILogger",
- "org.apache.poi.util.SystemOutLogger"
- );
- }
-
- public void testSimpleArithmatic() {
- XSSFWorkbook wb = new XSSFWorkbook();
- Sheet s = wb.createSheet();
- Row r = s.createRow(0);
-
- Cell c1 = r.createCell(0);
- c1.setCellFormula("1+5");
- assertEquals(0.0, c1.getNumericCellValue() );
-
- Cell c2 = r.createCell(1);
- c2.setCellFormula("10/2");
+ public TestXSSFFormulaEvaluation(String name) {
+ super(name);
+
+ // Use system out logger
+ System.setProperty(
+ "org.apache.poi.util.POILogger",
+ "org.apache.poi.util.SystemOutLogger"
+ );
+ }
+
+ public void testSimpleArithmatic() {
+ XSSFWorkbook wb = new XSSFWorkbook();
+ Sheet s = wb.createSheet();
+ Row r = s.createRow(0);
+
+ Cell c1 = r.createCell(0);
+ c1.setCellFormula("1+5");
+ assertEquals(0.0, c1.getNumericCellValue() );
+
+ Cell c2 = r.createCell(1);
+ c2.setCellFormula("10/2");
assertEquals(0.0, c2.getNumericCellValue() );
- FormulaEvaluator fe = new XSSFFormulaEvaluator(wb);
-
- fe.evaluateFormulaCell(c1);
- fe.evaluateFormulaCell(c2);
-
- assertEquals(6.0, c1.getNumericCellValue(), 0.0001);
- assertEquals(5.0, c2.getNumericCellValue(), 0.0001);
- }
-
- public void testSumCount() {
- XSSFWorkbook wb = new XSSFWorkbook();
- Sheet s = wb.createSheet();
- Row r = s.createRow(0);
- r.createCell(0).setCellValue(2.5);
- r.createCell(1).setCellValue(1.1);
- r.createCell(2).setCellValue(3.2);
- r.createCell(4).setCellValue(10.7);
-
- r = s.createRow(1);
-
- Cell c1 = r.createCell(0);
- c1.setCellFormula("SUM(A1:B1)");
+ FormulaEvaluator fe = new XSSFFormulaEvaluator(wb);
+
+ fe.evaluateFormulaCell(c1);
+ fe.evaluateFormulaCell(c2);
+
+ assertEquals(6.0, c1.getNumericCellValue(), 0.0001);
+ assertEquals(5.0, c2.getNumericCellValue(), 0.0001);
+ }
+
+ public void testSumCount() {
+ XSSFWorkbook wb = new XSSFWorkbook();
+ Sheet s = wb.createSheet();
+ Row r = s.createRow(0);
+ r.createCell(0).setCellValue(2.5);
+ r.createCell(1).setCellValue(1.1);
+ r.createCell(2).setCellValue(3.2);
+ r.createCell(4).setCellValue(10.7);
+
+ r = s.createRow(1);
+
+ Cell c1 = r.createCell(0);
+ c1.setCellFormula("SUM(A1:B1)");
assertEquals(0.0, c1.getNumericCellValue() );
- Cell c2 = r.createCell(1);
- c2.setCellFormula("SUM(A1:E1)");
+ Cell c2 = r.createCell(1);
+ c2.setCellFormula("SUM(A1:E1)");
assertEquals(0.0, c2.getNumericCellValue() );
- Cell c3 = r.createCell(2);
- c3.setCellFormula("COUNT(A1:A1)");
+ Cell c3 = r.createCell(2);
+ c3.setCellFormula("COUNT(A1:A1)");
assertEquals(0.0, c3.getNumericCellValue() );
- Cell c4 = r.createCell(3);
- c4.setCellFormula("COUNTA(A1:E1)");
+ Cell c4 = r.createCell(3);
+ c4.setCellFormula("COUNTA(A1:E1)");
assertEquals(0.0, c4.getNumericCellValue() );
- // Evaluate and test
- FormulaEvaluator fe = new XSSFFormulaEvaluator(wb);
-
- fe.evaluateFormulaCell(c1);
- fe.evaluateFormulaCell(c2);
- fe.evaluateFormulaCell(c3);
- fe.evaluateFormulaCell(c4);
-
- assertEquals(3.6, c1.getNumericCellValue(), 0.0001);
- assertEquals(17.5, c2.getNumericCellValue(), 0.0001);
- assertEquals(1, c3.getNumericCellValue(), 0.0001);
- assertEquals(4, c4.getNumericCellValue(), 0.0001);
- }
+ // Evaluate and test
+ FormulaEvaluator fe = new XSSFFormulaEvaluator(wb);
+
+ fe.evaluateFormulaCell(c1);
+ fe.evaluateFormulaCell(c2);
+ fe.evaluateFormulaCell(c3);
+ fe.evaluateFormulaCell(c4);
+
+ assertEquals(3.6, c1.getNumericCellValue(), 0.0001);
+ assertEquals(17.5, c2.getNumericCellValue(), 0.0001);
+ assertEquals(1, c3.getNumericCellValue(), 0.0001);
+ assertEquals(4, c4.getNumericCellValue(), 0.0001);
+ }
+
+ public void testSharedFormulas(){
+ XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("shared_formulas.xlsx");
+
+ XSSFSheet sheet = wb.getSheetAt(0);
+
+ FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
+ XSSFCell cell;
+
+ cell = sheet.getRow(1).getCell(0);
+ assertEquals("B2", cell.getCellFormula());
+ assertEquals("ProductionOrderConfirmation", evaluator.evaluate(cell).getStringValue());
+
+ cell = sheet.getRow(2).getCell(0);
+ assertEquals("B3", cell.getCellFormula());
+ assertEquals("RequiredAcceptanceDate", evaluator.evaluate(cell).getStringValue());
+
+ cell = sheet.getRow(3).getCell(0);
+ assertEquals("B4", cell.getCellFormula());
+ assertEquals("Header", evaluator.evaluate(cell).getStringValue());
+
+ cell = sheet.getRow(4).getCell(0);
+ assertEquals("B5", cell.getCellFormula());
+ assertEquals("UniqueDocumentNumberID", evaluator.evaluate(cell).getStringValue());
+ }
}
wb.removeName(0);\r
assertEquals(1, wb.getNumberOfNames());\r
}\r
+\r
+ public void testScope() {\r
+ XSSFWorkbook wb = new XSSFWorkbook();\r
+ wb.createSheet();\r
+ wb.createSheet();\r
+ \r
+ XSSFName name;\r
+\r
+ name = wb.createName();\r
+ name.setNameName("aaa");\r
+ name = wb.createName();\r
+ try {\r
+ name.setNameName("aaa");\r
+ fail("Expected exception");\r
+ } catch(Exception e){\r
+ assertEquals("The workbook already contains this name: aaa", e.getMessage());\r
+ }\r
+\r
+ name = wb.createName();\r
+ name.setSheetIndex(0);\r
+ name.setNameName("aaa");\r
+ name = wb.createName();\r
+ name.setSheetIndex(0);\r
+ try {\r
+ name.setNameName("aaa");\r
+ fail("Expected exception");\r
+ } catch(Exception e){\r
+ assertEquals("The sheet already contains this name: aaa", e.getMessage());\r
+ }\r
+\r
+ name = wb.createName();\r
+ name.setSheetIndex(1);\r
+ name.setNameName("aaa");\r
+ name = wb.createName();\r
+ name.setSheetIndex(1);\r
+ try {\r
+ name.setNameName("aaa");\r
+ fail("Expected exception");\r
+ } catch(Exception e){\r
+ assertEquals("The sheet already contains this name: aaa", e.getMessage());\r
+ }\r
+\r
+ int cnt = 0;\r
+ for (int i = 0; i < wb.getNumberOfNames(); i++) {\r
+ if("aaa".equals(wb.getNameAt(i).getNameName())) cnt++;\r
+ }\r
+ assertEquals(3, cnt);\r
+ }\r
+\r
}\r
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.RefPtg;
-import org.apache.poi.hssf.usermodel.HSSFCell;
-import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.usermodel.RecordInspector;
+import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.CellValue;
+import org.apache.poi.ss.formula.FormulaParser;
+import org.apache.poi.ss.formula.FormulaRenderer;
import org.apache.poi.util.LittleEndianInput;
/**
0x13,
0x42, 0x02, (byte)0xE4, 0x00,
};
-
+
/**
* The method <tt>SharedFormulaRecord.convertSharedFormulas()</tt> converts formulas from
* 'shared formula' to 'single cell formula' format. It is important that token operand
* incorrect encoding. The formula here is one such example (Excel displays #VALUE!).
*/
public void testConvertSharedFormulasOperandClasses_bug45123() {
-
+
LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(SHARED_FORMULA_WITH_REF_ARRAYS_DATA);
int encodedLen = in.readUShort();
Ptg[] sharedFormula = Ptg.readTokens(encodedLen, in);
-
+
Ptg[] convertedFormula = SharedFormulaRecord.convertSharedFormulas(sharedFormula, 100, 200);
-
+
RefPtg refPtg = (RefPtg) convertedFormula[1];
assertEquals("$C101", refPtg.toFormulaString());
if (refPtg.getPtgClass() == Ptg.CLASS_REF) {
throw new AssertionFailedError("Identified bug 45123");
}
-
+
confirmOperandClasses(sharedFormula, convertedFormula);
}
}
}
}
-
- /**
+
+ public void testConvertSharedFormulas() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFEvaluationWorkbook fpb = HSSFEvaluationWorkbook.create(wb);
+ Ptg[] sharedFormula, convertedFormula;
+
+ sharedFormula = FormulaParser.parse("A2", fpb);
+ convertedFormula = SharedFormulaRecord.convertSharedFormulas(sharedFormula, 0, 0);
+ confirmOperandClasses(sharedFormula, convertedFormula);
+ //conversion relative to [0,0] should return the original formula
+ assertEquals("A2", FormulaRenderer.toFormulaString(fpb, convertedFormula));
+
+ convertedFormula = SharedFormulaRecord.convertSharedFormulas(sharedFormula, 1, 0);
+ confirmOperandClasses(sharedFormula, convertedFormula);
+ //one row down
+ assertEquals("A3", FormulaRenderer.toFormulaString(fpb, convertedFormula));
+
+ convertedFormula = SharedFormulaRecord.convertSharedFormulas(sharedFormula, 1, 1);
+ confirmOperandClasses(sharedFormula, convertedFormula);
+ //one row down and one cell right
+ assertEquals("B3", FormulaRenderer.toFormulaString(fpb, convertedFormula));
+
+ sharedFormula = FormulaParser.parse("SUM(A1:C1)", fpb);
+ convertedFormula = SharedFormulaRecord.convertSharedFormulas(sharedFormula, 0, 0);
+ confirmOperandClasses(sharedFormula, convertedFormula);
+ assertEquals("SUM(A1:C1)", FormulaRenderer.toFormulaString(fpb, convertedFormula));
+
+ convertedFormula = SharedFormulaRecord.convertSharedFormulas(sharedFormula, 1, 0);
+ confirmOperandClasses(sharedFormula, convertedFormula);
+ assertEquals("SUM(A2:C2)", FormulaRenderer.toFormulaString(fpb, convertedFormula));
+
+ convertedFormula = SharedFormulaRecord.convertSharedFormulas(sharedFormula, 1, 1);
+ confirmOperandClasses(sharedFormula, convertedFormula);
+ assertEquals("SUM(B2:D2)", FormulaRenderer.toFormulaString(fpb, convertedFormula));
+ }
+
+ /**
* Make sure that POI preserves {@link SharedFormulaRecord}s
*/
public void testPreserveOnReserialize() {
}
}
+
+ public void testScope() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sh1 = wb.createSheet();
+ HSSFSheet sh2 = wb.createSheet();
+
+ HSSFName name;
+
+ name = wb.createName();
+ name.setNameName("aaa");
+ name = wb.createName();
+ try {
+ name.setNameName("aaa");
+ fail("Expected exception");
+ } catch(Exception e){
+ assertEquals("The workbook already contains this name: aaa", e.getMessage());
+ name.setNameName("aaa-2");
+ }
+
+ name = wb.createName();
+ name.setSheetIndex(0);
+ name.setNameName("aaa");
+ name = wb.createName();
+ name.setSheetIndex(0);
+ try {
+ name.setNameName("aaa");
+ fail("Expected exception");
+ } catch(Exception e){
+ assertEquals("The sheet already contains this name: aaa", e.getMessage());
+ name.setNameName("aaa-2");
+ }
+
+ name = wb.createName();
+ name.setSheetIndex(1);
+ name.setNameName("aaa");
+ name = wb.createName();
+ name.setSheetIndex(1);
+ try {
+ name.setNameName("aaa");
+ fail("Expected exception");
+ } catch(Exception e){
+ assertEquals("The sheet already contains this name: aaa", e.getMessage());
+ name.setNameName("aaa-2");
+ }
+
+ int cnt = 0;
+ for (int i = 0; i < wb.getNumberOfNames(); i++) {
+ if("aaa".equals(wb.getNameName(i))) cnt++;
+ }
+ assertEquals(3, cnt);
+ }
}