git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@728749 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_5_BETA5
@@ -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 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()); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |