git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1613437 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_11_BETA1
@@ -17,7 +17,9 @@ | |||
package org.apache.poi.ss.formula.ptg; | |||
import org.apache.poi.ss.formula.SheetIdentifier; | |||
import org.apache.poi.ss.formula.SheetNameFormatter; | |||
import org.apache.poi.ss.formula.SheetRangeIdentifier; | |||
import org.apache.poi.ss.util.AreaReference; | |||
import org.apache.poi.util.LittleEndianOutput; | |||
@@ -31,21 +33,27 @@ import org.apache.poi.util.LittleEndianOutput; | |||
*/ | |||
public final class Area3DPxg extends AreaPtgBase implements Pxg { | |||
private int externalWorkbookNumber = -1; | |||
private String sheetName; | |||
private String firstSheetName; | |||
private String lastSheetName; | |||
public Area3DPxg(int externalWorkbookNumber, String sheetName, String arearef) { | |||
public Area3DPxg(int externalWorkbookNumber, SheetIdentifier sheetName, String arearef) { | |||
this(externalWorkbookNumber, sheetName, new AreaReference(arearef)); | |||
} | |||
public Area3DPxg(int externalWorkbookNumber, String sheetName, AreaReference arearef) { | |||
public Area3DPxg(int externalWorkbookNumber, SheetIdentifier sheetName, AreaReference arearef) { | |||
super(arearef); | |||
this.externalWorkbookNumber = externalWorkbookNumber; | |||
this.sheetName = sheetName; | |||
this.firstSheetName = sheetName.getSheetIdentifier().getName(); | |||
if (sheetName instanceof SheetRangeIdentifier) { | |||
this.lastSheetName = ((SheetRangeIdentifier)sheetName).getLastSheetIdentifier().getName(); | |||
} else { | |||
this.lastSheetName = null; | |||
} | |||
} | |||
public Area3DPxg(String sheetName, String arearef) { | |||
public Area3DPxg(SheetIdentifier sheetName, String arearef) { | |||
this(sheetName, new AreaReference(arearef)); | |||
} | |||
public Area3DPxg(String sheetName, AreaReference arearef) { | |||
public Area3DPxg(SheetIdentifier sheetName, AreaReference arearef) { | |||
this(-1, sheetName, arearef); | |||
} | |||
@@ -60,6 +68,10 @@ public final class Area3DPxg extends AreaPtgBase implements Pxg { | |||
sb.append("] "); | |||
} | |||
sb.append("sheet=").append(getSheetName()); | |||
if (lastSheetName != null) { | |||
sb.append(" : "); | |||
sb.append("sheet=").append(lastSheetName); | |||
} | |||
sb.append(" ! "); | |||
sb.append(formatReferenceAsString()); | |||
sb.append("]"); | |||
@@ -70,11 +82,17 @@ public final class Area3DPxg extends AreaPtgBase implements Pxg { | |||
return externalWorkbookNumber; | |||
} | |||
public String getSheetName() { | |||
return sheetName; | |||
return firstSheetName; | |||
} | |||
public String getLastSheetName() { | |||
return lastSheetName; | |||
} | |||
public void setSheetName(String sheetName) { | |||
this.sheetName = sheetName; | |||
this.firstSheetName = sheetName; | |||
} | |||
public void setLastSheetName(String sheetName) { | |||
this.lastSheetName = sheetName; | |||
} | |||
public String format2DRefAsString() { | |||
@@ -88,7 +106,11 @@ public final class Area3DPxg extends AreaPtgBase implements Pxg { | |||
sb.append(externalWorkbookNumber); | |||
sb.append(']'); | |||
} | |||
SheetNameFormatter.appendFormat(sb, sheetName); | |||
SheetNameFormatter.appendFormat(sb, firstSheetName); | |||
if (lastSheetName != null) { | |||
sb.append(':'); | |||
SheetNameFormatter.appendFormat(sb, lastSheetName); | |||
} | |||
sb.append('!'); | |||
sb.append(formatReferenceAsString()); | |||
return sb.toString(); |
@@ -81,14 +81,14 @@ public final class Ref3DPxg extends RefPtgBase implements Pxg { | |||
public int getExternalWorkbookNumber() { | |||
return externalWorkbookNumber; | |||
} | |||
public String getSheetName() { // TODO Rename to getFirstSheetName | |||
public String getSheetName() { | |||
return firstSheetName; | |||
} | |||
public String getLastSheetName() { | |||
return lastSheetName; | |||
} | |||
public void setSheetName(String sheetName) { // TODO Rename to setFirstSheetName | |||
public void setSheetName(String sheetName) { | |||
this.firstSheetName = sheetName; | |||
} | |||
public void setLastSheetName(String sheetName) { |
@@ -200,13 +200,11 @@ public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E | |||
} | |||
} | |||
public Ptg get3DReferencePtg(AreaReference area, SheetIdentifier sheet) { | |||
String sheetName = sheet._sheetIdentifier.getName(); | |||
if (sheet._bookName != null) { | |||
int bookIndex = resolveBookIndex(sheet._bookName); | |||
return new Area3DPxg(bookIndex, sheetName, area); | |||
return new Area3DPxg(bookIndex, sheet, area); | |||
} else { | |||
return new Area3DPxg(sheetName, area); | |||
return new Area3DPxg(sheet, area); | |||
} | |||
} | |||
@@ -201,46 +201,46 @@ public final class TestXSSFFormulaEvaluation extends BaseTestFormulaEvaluator { | |||
Cell sumF = s1.getRow(2).getCell(0); | |||
assertNotNull(sumF); | |||
assertEquals("SUM(Sheet1:Sheet3!A1)", sumF.getCellFormula()); | |||
assertEquals("66", evaluator.evaluate(sumF).formatAsString()); | |||
assertEquals("66.0", evaluator.evaluate(sumF).formatAsString()); | |||
// Various Stats formulas on numbers | |||
Cell avgF = s1.getRow(2).getCell(1); | |||
assertNotNull(avgF); | |||
assertEquals("AVERAGE(Sheet1:Sheet3!A1)", avgF.getCellFormula()); | |||
assertEquals("22", evaluator.evaluate(avgF).formatAsString()); | |||
assertEquals("22.0", evaluator.evaluate(avgF).formatAsString()); | |||
Cell minF = s1.getRow(3).getCell(1); | |||
assertNotNull(minF); | |||
assertEquals("MIX(Sheet1:Sheet3!A$1)", minF.getCellFormula()); | |||
assertEquals("11", evaluator.evaluate(minF).formatAsString()); | |||
assertEquals("11.0", evaluator.evaluate(minF).formatAsString()); | |||
Cell maxF = s1.getRow(4).getCell(1); | |||
assertNotNull(maxF); | |||
assertEquals("MAX(Sheet1:Sheet3!A$1)", maxF.getCellFormula()); | |||
assertEquals("33", evaluator.evaluate(maxF).formatAsString()); | |||
assertEquals("33.0", evaluator.evaluate(maxF).formatAsString()); | |||
Cell countF = s1.getRow(5).getCell(1); | |||
assertNotNull(countF); | |||
assertEquals("COUNT(Sheet1:Sheet3!A$1)", countF.getCellFormula()); | |||
assertEquals("3", evaluator.evaluate(countF).formatAsString()); | |||
assertEquals("3.0", evaluator.evaluate(countF).formatAsString()); | |||
// Various CountAs on Strings | |||
Cell countA_1F = s1.getRow(2).getCell(2); | |||
assertNotNull(countA_1F); | |||
assertEquals("COUNTA(Sheet1:Sheet3!C1)", countA_1F.getCellFormula()); | |||
assertEquals("3", evaluator.evaluate(countA_1F).formatAsString()); | |||
assertEquals("3.0", evaluator.evaluate(countA_1F).formatAsString()); | |||
Cell countA_2F = s1.getRow(2).getCell(3); | |||
assertNotNull(countA_2F); | |||
assertEquals("COUNTA(Sheet1:Sheet3!D1)", countA_2F.getCellFormula()); | |||
assertEquals("0", evaluator.evaluate(countA_2F).formatAsString()); | |||
assertEquals("0.0", evaluator.evaluate(countA_2F).formatAsString()); | |||
Cell countA_3F = s1.getRow(2).getCell(4); | |||
assertNotNull(countA_3F); | |||
assertEquals("COUNTA(Sheet1:Sheet3!E1)", countA_3F.getCellFormula()); | |||
assertEquals("3", evaluator.evaluate(countA_3F).formatAsString()); | |||
assertEquals("3.0", evaluator.evaluate(countA_3F).formatAsString()); | |||
} | |||
} | |||
} |
@@ -31,6 +31,7 @@ import org.apache.poi.ss.formula.FormulaParsingWorkbook; | |||
import org.apache.poi.ss.formula.FormulaRenderingWorkbook; | |||
import org.apache.poi.ss.formula.FormulaType; | |||
import org.apache.poi.ss.formula.WorkbookDependentFormula; | |||
import org.apache.poi.ss.formula.ptg.Area3DPtg; | |||
import org.apache.poi.ss.formula.ptg.Area3DPxg; | |||
import org.apache.poi.ss.formula.ptg.AreaPtg; | |||
import org.apache.poi.ss.formula.ptg.AttrPtg; | |||
@@ -242,7 +243,9 @@ public final class TestXSSFFormulaParser { | |||
/** | |||
* A handful of functions (such as SUM, COUNTA, MIN) support | |||
* multi-sheet references (eg Sheet1:Sheet3!A1 = Cell A1 from | |||
* Sheets 1 through Sheet 3). | |||
* Sheets 1 through Sheet 3) and multi-sheet area references | |||
* (eg Sheet1:Sheet3!A1:B2 = Cells A1 through B2 from Sheets | |||
* 1 through Sheet 3). | |||
* This test, based on common test files for HSSF and XSSF, checks | |||
* that we can read and parse these kinds of references | |||
* (but not evaluate - that's elsewhere in the test suite) | |||
@@ -274,6 +277,24 @@ public final class TestXSSFFormulaParser { | |||
assertNotNull(maxF); | |||
assertEquals("MAX(Sheet1:Sheet3!A$1)", maxF.getCellFormula()); | |||
Cell sumFA = s1.getRow(2).getCell(7); | |||
assertNotNull(sumFA); | |||
assertEquals("SUM(Sheet1:Sheet3!A1:B2)", sumFA.getCellFormula()); | |||
Cell avgFA = s1.getRow(2).getCell(8); | |||
assertNotNull(avgFA); | |||
assertEquals("AVERAGE(Sheet1:Sheet3!A1:B2)", avgFA.getCellFormula()); | |||
Cell maxFA = s1.getRow(4).getCell(8); | |||
assertNotNull(maxFA); | |||
assertEquals("MAX(Sheet1:Sheet3!A$1:B$2)", maxFA.getCellFormula()); | |||
Cell countFA = s1.getRow(5).getCell(8); | |||
assertNotNull(countFA); | |||
assertEquals("COUNT(Sheet1:Sheet3!$A$1:$B$2)", countFA.getCellFormula()); | |||
// Create a formula parser | |||
FormulaParsingWorkbook fpb = null; | |||
if (wb instanceof HSSFWorkbook) | |||
@@ -324,10 +345,41 @@ public final class TestXSSFFormulaParser { | |||
assertEquals("MIN", toFormulaString(ptgs[1], fpb)); | |||
// Check we can round-trip - try to set a new one to a new cell | |||
// SUM to a range of cells over 3 workbooks | |||
ptgs = parse(fpb, "SUM(Sheet1:Sheet3!A1:B2)"); | |||
assertEquals(2, ptgs.length); | |||
if (wb instanceof HSSFWorkbook) { | |||
assertEquals(Area3DPtg.class, ptgs[0].getClass()); | |||
} else { | |||
assertEquals(Area3DPxg.class, ptgs[0].getClass()); | |||
} | |||
assertEquals("Sheet1:Sheet3!A1:B2", toFormulaString(ptgs[0], fpb)); | |||
assertEquals(AttrPtg.class, ptgs[1].getClass()); | |||
assertEquals("SUM", toFormulaString(ptgs[1], fpb)); | |||
// MIN to a range of cells over 3 workbooks, absolute reference | |||
ptgs = parse(fpb, "MIN(Sheet1:Sheet3!$A$1:$B$2)"); | |||
assertEquals(2, ptgs.length); | |||
if (wb instanceof HSSFWorkbook) { | |||
assertEquals(Area3DPtg.class, ptgs[0].getClass()); | |||
} else { | |||
assertEquals(Area3DPxg.class, ptgs[0].getClass()); | |||
} | |||
assertEquals("Sheet1:Sheet3!$A$1:$B$2", toFormulaString(ptgs[0], fpb)); | |||
assertEquals(FuncVarPtg.class, ptgs[1].getClass()); | |||
assertEquals("MIN", toFormulaString(ptgs[1], fpb)); | |||
// Check we can round-trip - try to set a new one to a new single cell | |||
Cell newF = s1.getRow(0).createCell(10, Cell.CELL_TYPE_FORMULA); | |||
newF.setCellFormula("SUM(Sheet2:Sheet3!A1)"); | |||
assertEquals("SUM(Sheet2:Sheet3!A1)", newF.getCellFormula()); | |||
// Check we can round-trip - try to set a new one to a cell range | |||
newF = s1.getRow(0).createCell(11, Cell.CELL_TYPE_FORMULA); | |||
newF.setCellFormula("MIN(Sheet1:Sheet2!A1:B2)"); | |||
assertEquals("MIN(Sheet1:Sheet2!A1:B2)", newF.getCellFormula()); | |||
} | |||
} | |||
private static String toFormulaString(Ptg ptg, FormulaParsingWorkbook wb) { |
@@ -465,6 +465,9 @@ public final class TestFormulaParser extends TestCase { | |||
HSSFCell cell = row.createCell(0); | |||
String formula = null; | |||
// References to a single cell: | |||
// One sheet | |||
cell.setCellFormula("Cash_Flow!A1"); | |||
formula = cell.getCellFormula(); | |||
@@ -479,6 +482,24 @@ public final class TestFormulaParser extends TestCase { | |||
cell.setCellFormula("Cash_Flow:\'Test Sheet\'!A1"); | |||
formula = cell.getCellFormula(); | |||
assertEquals("Cash_Flow:\'Test Sheet\'!A1", formula); | |||
// References to a range (area) of cells: | |||
// One sheet | |||
cell.setCellFormula("Cash_Flow!A1:B2"); | |||
formula = cell.getCellFormula(); | |||
assertEquals("Cash_Flow!A1:B2", formula); | |||
// Then the other | |||
cell.setCellFormula("\'Test Sheet\'!A1:B2"); | |||
formula = cell.getCellFormula(); | |||
assertEquals("\'Test Sheet\'!A1:B2", formula); | |||
// Now both | |||
cell.setCellFormula("Cash_Flow:\'Test Sheet\'!A1:B2"); | |||
formula = cell.getCellFormula(); | |||
assertEquals("Cash_Flow:\'Test Sheet\'!A1:B2", formula); | |||
} | |||
/** |