mirror of https://github.com/apache/poi.git
1. added support for shared formulas in XSSF, see bug #464332. improved validation of workbook-global and sheet-global names
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@728749 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
010693edaf
commit
27f601e40e
|
@ -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">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>
|
||||
|
|
|
@ -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">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>
|
||||
|
|
|
@ -17,11 +17,7 @@
|
|||
|
||||
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;
|
||||
|
@ -106,7 +102,7 @@ public final class SharedFormulaRecord extends SharedValueRecordBase {
|
|||
* 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];
|
||||
|
||||
|
@ -116,14 +112,14 @@ public final class SharedFormulaRecord extends SharedValueRecordBase {
|
|||
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()),
|
||||
|
|
|
@ -83,20 +83,49 @@ public final class HSSFName implements Name {
|
|||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,8 +87,31 @@ public interface Name {
|
|||
* 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);
|
||||
|
||||
|
|
|
@ -24,16 +24,21 @@ import java.util.Date;
|
|||
|
||||
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.
|
||||
|
@ -50,6 +55,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellType;
|
|||
* </p>
|
||||
*/
|
||||
public final class XSSFCell implements Cell {
|
||||
private static POILogger logger = POILogFactory.getLogger(XSSFCell.class);
|
||||
|
||||
/**
|
||||
* The maximum number of columns in SpreadsheetML
|
||||
|
@ -108,7 +114,7 @@ public final class XSSFCell implements Cell {
|
|||
protected SharedStringsTable getSharedStringSource() {
|
||||
return sharedStringSource;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return table of cell styles shared across this workbook
|
||||
*/
|
||||
|
@ -122,8 +128,8 @@ public final class XSSFCell implements Cell {
|
|||
* @return the sheet this cell belongs to
|
||||
*/
|
||||
public XSSFSheet getSheet() {
|
||||
return getRow().getSheet();
|
||||
}
|
||||
return getRow().getSheet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the row this cell belongs to
|
||||
|
@ -131,8 +137,8 @@ public final class XSSFCell implements Cell {
|
|||
* @return the row this cell belongs to
|
||||
*/
|
||||
public XSSFRow getRow() {
|
||||
return row;
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the cell as a boolean.
|
||||
|
@ -321,7 +327,31 @@ public final class XSSFCell implements Cell {
|
|||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -363,7 +393,7 @@ public final class XSSFCell implements Cell {
|
|||
* @return zero-based column index of a column in a sheet.
|
||||
*/
|
||||
public int getColumnIndex() {
|
||||
return this.cellNum;
|
||||
return this.cellNum;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -372,8 +402,8 @@ public final class XSSFCell implements Cell {
|
|||
* @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
|
||||
|
@ -381,8 +411,8 @@ public final class XSSFCell implements 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.
|
||||
|
@ -406,8 +436,8 @@ public final class XSSFCell implements Cell {
|
|||
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);
|
||||
|
@ -486,7 +516,7 @@ public final class XSSFCell implements Cell {
|
|||
* 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));
|
||||
}
|
||||
|
||||
|
@ -507,7 +537,7 @@ public final class XSSFCell implements Cell {
|
|||
* 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 ));
|
||||
}
|
||||
|
||||
|
@ -765,8 +795,8 @@ public final class XSSFCell implements Cell {
|
|||
* @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
|
||||
|
@ -774,14 +804,14 @@ public final class XSSFCell implements 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,
|
||||
|
|
|
@ -137,17 +137,45 @@ public final class XSSFName implements Name {
|
|||
* 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);
|
||||
|
|
|
@ -63,7 +63,8 @@ public class XSSFRow implements Row, Comparable<XSSFRow> {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
|
|||
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.
|
||||
|
@ -147,6 +148,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
|
|||
|
||||
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);
|
||||
|
@ -1664,6 +1666,24 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
|
|||
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 {
|
||||
|
|
|
@ -19,83 +19,106 @@ package org.apache.poi.xssf.usermodel;
|
|||
|
||||
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 TestXSSFFormulaEvaluation(String name) {
|
||||
super(name);
|
||||
|
||||
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() );
|
||||
// Use system out logger
|
||||
System.setProperty(
|
||||
"org.apache.poi.util.POILogger",
|
||||
"org.apache.poi.util.SystemOutLogger"
|
||||
);
|
||||
}
|
||||
|
||||
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)");
|
||||
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("SUM(A1:E1)");
|
||||
Cell c2 = r.createCell(1);
|
||||
c2.setCellFormula("10/2");
|
||||
assertEquals(0.0, c2.getNumericCellValue() );
|
||||
|
||||
Cell c3 = r.createCell(2);
|
||||
c3.setCellFormula("COUNT(A1:A1)");
|
||||
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)");
|
||||
assertEquals(0.0, c2.getNumericCellValue() );
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,4 +109,53 @@ public class TestXSSFName extends TestCase {
|
|||
wb.removeName(0);
|
||||
assertEquals(1, wb.getNumberOfNames());
|
||||
}
|
||||
|
||||
public void testScope() {
|
||||
XSSFWorkbook wb = new XSSFWorkbook();
|
||||
wb.createSheet();
|
||||
wb.createSheet();
|
||||
|
||||
XSSFName 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 = 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 = 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());
|
||||
}
|
||||
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < wb.getNumberOfNames(); i++) {
|
||||
if("aaa".equals(wb.getNameAt(i).getNameName())) cnt++;
|
||||
}
|
||||
assertEquals(3, cnt);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -24,12 +24,10 @@ import junit.framework.TestCase;
|
|||
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;
|
||||
|
||||
/**
|
||||
|
@ -62,7 +60,7 @@ public final class TestSharedFormulaRecord extends TestCase {
|
|||
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
|
||||
|
@ -70,19 +68,19 @@ public final class TestSharedFormulaRecord extends TestCase {
|
|||
* 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);
|
||||
}
|
||||
|
||||
|
@ -97,8 +95,43 @@ public final class TestSharedFormulaRecord extends TestCase {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
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() {
|
||||
|
|
|
@ -549,4 +549,55 @@ public final class TestNamedRange extends TestCase {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue