bug 57840: merge changes from ^/poi/branches/xssf_structured_references to ^/poi/trunk
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1747657 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
commit
12d7fb30a4
@ -31,53 +31,53 @@ import org.apache.poi.ss.formula.FormulaType;
|
|||||||
*/
|
*/
|
||||||
public final class HSSFFormulaParser {
|
public final class HSSFFormulaParser {
|
||||||
|
|
||||||
private static FormulaParsingWorkbook createParsingWorkbook(HSSFWorkbook book) {
|
private static FormulaParsingWorkbook createParsingWorkbook(HSSFWorkbook book) {
|
||||||
return HSSFEvaluationWorkbook.create(book);
|
return HSSFEvaluationWorkbook.create(book);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HSSFFormulaParser() {
|
private HSSFFormulaParser() {
|
||||||
// no instances of this class
|
// no instances of this class
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method for parsing cell formulas. see {@link #parse(String, HSSFWorkbook, int, int)}
|
* Convenience method for parsing cell formulas. see {@link #parse(String, HSSFWorkbook, int, int)}
|
||||||
*/
|
*/
|
||||||
public static Ptg[] parse(String formula, HSSFWorkbook workbook) throws FormulaParseException {
|
public static Ptg[] parse(String formula, HSSFWorkbook workbook) throws FormulaParseException {
|
||||||
return parse(formula, workbook, FormulaType.CELL);
|
return parse(formula, workbook, FormulaType.CELL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param formulaType a constant from {@link FormulaType}
|
* @param formulaType a constant from {@link FormulaType}
|
||||||
* @return the parsed formula tokens
|
* @return the parsed formula tokens
|
||||||
* @throws FormulaParseException if the formula has incorrect syntax or is otherwise invalid
|
* @throws FormulaParseException if the formula has incorrect syntax or is otherwise invalid
|
||||||
*/
|
*/
|
||||||
public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType) throws FormulaParseException {
|
public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType) throws FormulaParseException {
|
||||||
return parse(formula, workbook, formulaType, -1);
|
return parse(formula, workbook, formulaType, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param formula the formula to parse
|
* @param formula the formula to parse
|
||||||
* @param workbook the parent workbook
|
* @param workbook the parent workbook
|
||||||
* @param formulaType a constant from {@link FormulaType}
|
* @param formulaType a constant from {@link FormulaType}
|
||||||
* @param sheetIndex the 0-based index of the sheet this formula belongs to.
|
* @param sheetIndex the 0-based index of the sheet this formula belongs to.
|
||||||
* The sheet index is required to resolve sheet-level names. <code>-1</code> means that
|
* The sheet index is required to resolve sheet-level names. <code>-1</code> means that
|
||||||
* the scope of the name will be ignored and the parser will match named ranges only by name
|
* the scope of the name will be ignored and the parser will match named ranges only by name
|
||||||
*
|
*
|
||||||
* @return the parsed formula tokens
|
* @return the parsed formula tokens
|
||||||
* @throws FormulaParseException if the formula has incorrect syntax or is otherwise invalid
|
* @throws FormulaParseException if the formula has incorrect syntax or is otherwise invalid
|
||||||
*/
|
*/
|
||||||
public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType, int sheetIndex) throws FormulaParseException {
|
public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType, int sheetIndex) throws FormulaParseException {
|
||||||
return FormulaParser.parse(formula, createParsingWorkbook(workbook), formulaType, sheetIndex);
|
return FormulaParser.parse(formula, createParsingWorkbook(workbook), formulaType, sheetIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static method to convert an array of {@link Ptg}s in RPN order
|
* Static method to convert an array of {@link Ptg}s in RPN order
|
||||||
* to a human readable string format in infix mode.
|
* to a human readable string format in infix mode.
|
||||||
* @param book used for defined names and 3D references
|
* @param book used for defined names and 3D references
|
||||||
* @param ptgs must not be <code>null</code>
|
* @param ptgs must not be <code>null</code>
|
||||||
* @return a human readable String
|
* @return a human readable String
|
||||||
*/
|
*/
|
||||||
public static String toFormulaString(HSSFWorkbook book, Ptg[] ptgs) {
|
public static String toFormulaString(HSSFWorkbook book, Ptg[] ptgs) {
|
||||||
return FormulaRenderer.toFormulaString(HSSFEvaluationWorkbook.create(book), ptgs);
|
return FormulaRenderer.toFormulaString(HSSFEvaluationWorkbook.create(book), ptgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
(the "License"); you may not use this file except in compliance with
|
(the "License"); you may not use this file except in compliance with
|
||||||
the License. You may obtain a copy of the License at
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@ -38,6 +38,7 @@ import org.apache.poi.ss.formula.ptg.NameXPtg;
|
|||||||
import org.apache.poi.ss.formula.ptg.Ptg;
|
import org.apache.poi.ss.formula.ptg.Ptg;
|
||||||
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
|
import org.apache.poi.ss.formula.ptg.Ref3DPtg;
|
||||||
import org.apache.poi.ss.formula.udf.UDFFinder;
|
import org.apache.poi.ss.formula.udf.UDFFinder;
|
||||||
|
import org.apache.poi.ss.usermodel.Table;
|
||||||
import org.apache.poi.ss.util.AreaReference;
|
import org.apache.poi.ss.util.AreaReference;
|
||||||
import org.apache.poi.ss.util.CellReference;
|
import org.apache.poi.ss.util.CellReference;
|
||||||
import org.apache.poi.util.POILogFactory;
|
import org.apache.poi.util.POILogFactory;
|
||||||
@ -264,7 +265,16 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E
|
|||||||
return extIx;
|
return extIx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public SpreadsheetVersion getSpreadsheetVersion(){
|
public SpreadsheetVersion getSpreadsheetVersion(){
|
||||||
return SpreadsheetVersion.EXCEL97;
|
return SpreadsheetVersion.EXCEL97;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws IllegalStateException: data tables are not supported in Excel 97-2003 format
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Table getTable(String name) {
|
||||||
|
throw new IllegalStateException("XSSF-style tables are not supported for HSSF");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,7 @@ package org.apache.poi.ss.formula;
|
|||||||
import org.apache.poi.ss.SpreadsheetVersion;
|
import org.apache.poi.ss.SpreadsheetVersion;
|
||||||
import org.apache.poi.ss.formula.ptg.Ptg;
|
import org.apache.poi.ss.formula.ptg.Ptg;
|
||||||
import org.apache.poi.ss.usermodel.Name;
|
import org.apache.poi.ss.usermodel.Name;
|
||||||
|
import org.apache.poi.ss.usermodel.Table;
|
||||||
import org.apache.poi.ss.util.AreaReference;
|
import org.apache.poi.ss.util.AreaReference;
|
||||||
import org.apache.poi.ss.util.CellReference;
|
import org.apache.poi.ss.util.CellReference;
|
||||||
|
|
||||||
@ -31,46 +32,51 @@ import org.apache.poi.ss.util.CellReference;
|
|||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
*/
|
*/
|
||||||
public interface FormulaParsingWorkbook {
|
public interface FormulaParsingWorkbook {
|
||||||
/**
|
/**
|
||||||
* named range name matching is case insensitive
|
* named range name matching is case insensitive
|
||||||
*/
|
*/
|
||||||
EvaluationName getName(String name, int sheetIndex);
|
EvaluationName getName(String name, int sheetIndex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the underlying workbook
|
* Return the underlying workbook
|
||||||
*/
|
*/
|
||||||
Name createName();
|
Name createName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an external name (named range, function, user-defined function) Ptg
|
* XSSF Only - gets a table that exists in the worksheet
|
||||||
*/
|
*/
|
||||||
Ptg getNameXPtg(String name, SheetIdentifier sheet);
|
Table getTable(String name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produce the appropriate Ptg for a 3d cell reference
|
* Return an external name (named range, function, user-defined function) Ptg
|
||||||
*/
|
*/
|
||||||
Ptg get3DReferencePtg(CellReference cell, SheetIdentifier sheet);
|
Ptg getNameXPtg(String name, SheetIdentifier sheet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produce the appropriate Ptg for a 3d cell reference
|
||||||
|
*/
|
||||||
|
Ptg get3DReferencePtg(CellReference cell, SheetIdentifier sheet);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produce the appropriate Ptg for a 3d area reference
|
* Produce the appropriate Ptg for a 3d area reference
|
||||||
*/
|
*/
|
||||||
Ptg get3DReferencePtg(AreaReference area, SheetIdentifier sheet);
|
Ptg get3DReferencePtg(AreaReference area, SheetIdentifier sheet);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets the externSheet index for a sheet from this workbook
|
* gets the externSheet index for a sheet from this workbook
|
||||||
*/
|
*/
|
||||||
int getExternalSheetIndex(String sheetName);
|
int getExternalSheetIndex(String sheetName);
|
||||||
/**
|
/**
|
||||||
* gets the externSheet index for a sheet from an external workbook
|
* gets the externSheet index for a sheet from an external workbook
|
||||||
* @param workbookName e.g. "Budget.xls"
|
* @param workbookName e.g. "Budget.xls"
|
||||||
* @param sheetName a name of a sheet in that workbook
|
* @param sheetName a name of a sheet in that workbook
|
||||||
*/
|
*/
|
||||||
int getExternalSheetIndex(String workbookName, String sheetName);
|
int getExternalSheetIndex(String workbookName, String sheetName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an enum holding spreadhseet properties specific to an Excel version (
|
* Returns an enum holding spreadhseet properties specific to an Excel version (
|
||||||
* max column and row numbers, max arguments to a function, etc.)
|
* max column and row numbers, max arguments to a function, etc.)
|
||||||
*/
|
*/
|
||||||
SpreadsheetVersion getSpreadsheetVersion();
|
SpreadsheetVersion getSpreadsheetVersion();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -46,199 +46,199 @@ import org.apache.poi.ss.util.CellReference.NameType;
|
|||||||
* For POI internal use only
|
* For POI internal use only
|
||||||
*/
|
*/
|
||||||
public final class OperationEvaluationContext {
|
public final class OperationEvaluationContext {
|
||||||
public static final FreeRefFunction UDF = UserDefinedFunction.instance;
|
public static final FreeRefFunction UDF = UserDefinedFunction.instance;
|
||||||
private final EvaluationWorkbook _workbook;
|
private final EvaluationWorkbook _workbook;
|
||||||
private final int _sheetIndex;
|
private final int _sheetIndex;
|
||||||
private final int _rowIndex;
|
private final int _rowIndex;
|
||||||
private final int _columnIndex;
|
private final int _columnIndex;
|
||||||
private final EvaluationTracker _tracker;
|
private final EvaluationTracker _tracker;
|
||||||
private final WorkbookEvaluator _bookEvaluator;
|
private final WorkbookEvaluator _bookEvaluator;
|
||||||
|
|
||||||
public OperationEvaluationContext(WorkbookEvaluator bookEvaluator, EvaluationWorkbook workbook, int sheetIndex, int srcRowNum,
|
public OperationEvaluationContext(WorkbookEvaluator bookEvaluator, EvaluationWorkbook workbook, int sheetIndex, int srcRowNum,
|
||||||
int srcColNum, EvaluationTracker tracker) {
|
int srcColNum, EvaluationTracker tracker) {
|
||||||
_bookEvaluator = bookEvaluator;
|
_bookEvaluator = bookEvaluator;
|
||||||
_workbook = workbook;
|
_workbook = workbook;
|
||||||
_sheetIndex = sheetIndex;
|
_sheetIndex = sheetIndex;
|
||||||
_rowIndex = srcRowNum;
|
_rowIndex = srcRowNum;
|
||||||
_columnIndex = srcColNum;
|
_columnIndex = srcColNum;
|
||||||
_tracker = tracker;
|
_tracker = tracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EvaluationWorkbook getWorkbook() {
|
public EvaluationWorkbook getWorkbook() {
|
||||||
return _workbook;
|
return _workbook;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRowIndex() {
|
public int getRowIndex() {
|
||||||
return _rowIndex;
|
return _rowIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getColumnIndex() {
|
public int getColumnIndex() {
|
||||||
return _columnIndex;
|
return _columnIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
SheetRangeEvaluator createExternSheetRefEvaluator(ExternSheetReferenceToken ptg) {
|
SheetRangeEvaluator createExternSheetRefEvaluator(ExternSheetReferenceToken ptg) {
|
||||||
return createExternSheetRefEvaluator(ptg.getExternSheetIndex());
|
return createExternSheetRefEvaluator(ptg.getExternSheetIndex());
|
||||||
}
|
}
|
||||||
SheetRangeEvaluator createExternSheetRefEvaluator(String firstSheetName, String lastSheetName, int externalWorkbookNumber) {
|
SheetRangeEvaluator createExternSheetRefEvaluator(String firstSheetName, String lastSheetName, int externalWorkbookNumber) {
|
||||||
ExternalSheet externalSheet = _workbook.getExternalSheet(firstSheetName, lastSheetName, externalWorkbookNumber);
|
ExternalSheet externalSheet = _workbook.getExternalSheet(firstSheetName, lastSheetName, externalWorkbookNumber);
|
||||||
return createExternSheetRefEvaluator(externalSheet);
|
return createExternSheetRefEvaluator(externalSheet);
|
||||||
}
|
}
|
||||||
SheetRangeEvaluator createExternSheetRefEvaluator(int externSheetIndex) {
|
SheetRangeEvaluator createExternSheetRefEvaluator(int externSheetIndex) {
|
||||||
ExternalSheet externalSheet = _workbook.getExternalSheet(externSheetIndex);
|
ExternalSheet externalSheet = _workbook.getExternalSheet(externSheetIndex);
|
||||||
return createExternSheetRefEvaluator(externalSheet);
|
return createExternSheetRefEvaluator(externalSheet);
|
||||||
}
|
}
|
||||||
SheetRangeEvaluator createExternSheetRefEvaluator(ExternalSheet externalSheet) {
|
SheetRangeEvaluator createExternSheetRefEvaluator(ExternalSheet externalSheet) {
|
||||||
WorkbookEvaluator targetEvaluator;
|
WorkbookEvaluator targetEvaluator;
|
||||||
int otherFirstSheetIndex;
|
int otherFirstSheetIndex;
|
||||||
int otherLastSheetIndex = -1;
|
int otherLastSheetIndex = -1;
|
||||||
if (externalSheet == null || externalSheet.getWorkbookName() == null) {
|
if (externalSheet == null || externalSheet.getWorkbookName() == null) {
|
||||||
// sheet is in same workbook
|
// sheet is in same workbook
|
||||||
targetEvaluator = _bookEvaluator;
|
targetEvaluator = _bookEvaluator;
|
||||||
if(externalSheet == null) {
|
if(externalSheet == null) {
|
||||||
otherFirstSheetIndex = 0;
|
otherFirstSheetIndex = 0;
|
||||||
} else {
|
} else {
|
||||||
otherFirstSheetIndex = _workbook.getSheetIndex(externalSheet.getSheetName());
|
otherFirstSheetIndex = _workbook.getSheetIndex(externalSheet.getSheetName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (externalSheet instanceof ExternalSheetRange) {
|
if (externalSheet instanceof ExternalSheetRange) {
|
||||||
String lastSheetName = ((ExternalSheetRange)externalSheet).getLastSheetName();
|
String lastSheetName = ((ExternalSheetRange)externalSheet).getLastSheetName();
|
||||||
otherLastSheetIndex = _workbook.getSheetIndex(lastSheetName);
|
otherLastSheetIndex = _workbook.getSheetIndex(lastSheetName);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// look up sheet by name from external workbook
|
// look up sheet by name from external workbook
|
||||||
String workbookName = externalSheet.getWorkbookName();
|
String workbookName = externalSheet.getWorkbookName();
|
||||||
try {
|
try {
|
||||||
targetEvaluator = _bookEvaluator.getOtherWorkbookEvaluator(workbookName);
|
targetEvaluator = _bookEvaluator.getOtherWorkbookEvaluator(workbookName);
|
||||||
} catch (WorkbookNotFoundException e) {
|
} catch (WorkbookNotFoundException e) {
|
||||||
throw new RuntimeException(e.getMessage(), e);
|
throw new RuntimeException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
otherFirstSheetIndex = targetEvaluator.getSheetIndex(externalSheet.getSheetName());
|
otherFirstSheetIndex = targetEvaluator.getSheetIndex(externalSheet.getSheetName());
|
||||||
if (externalSheet instanceof ExternalSheetRange) {
|
if (externalSheet instanceof ExternalSheetRange) {
|
||||||
String lastSheetName = ((ExternalSheetRange)externalSheet).getLastSheetName();
|
String lastSheetName = ((ExternalSheetRange)externalSheet).getLastSheetName();
|
||||||
otherLastSheetIndex = targetEvaluator.getSheetIndex(lastSheetName);
|
otherLastSheetIndex = targetEvaluator.getSheetIndex(lastSheetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (otherFirstSheetIndex < 0) {
|
if (otherFirstSheetIndex < 0) {
|
||||||
throw new RuntimeException("Invalid sheet name '" + externalSheet.getSheetName()
|
throw new RuntimeException("Invalid sheet name '" + externalSheet.getSheetName()
|
||||||
+ "' in bool '" + workbookName + "'.");
|
+ "' in bool '" + workbookName + "'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (otherLastSheetIndex == -1) {
|
if (otherLastSheetIndex == -1) {
|
||||||
// Reference to just one sheet
|
// Reference to just one sheet
|
||||||
otherLastSheetIndex = otherFirstSheetIndex;
|
otherLastSheetIndex = otherFirstSheetIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
SheetRefEvaluator[] evals = new SheetRefEvaluator[otherLastSheetIndex-otherFirstSheetIndex+1];
|
SheetRefEvaluator[] evals = new SheetRefEvaluator[otherLastSheetIndex-otherFirstSheetIndex+1];
|
||||||
for (int i=0; i<evals.length; i++) {
|
for (int i=0; i<evals.length; i++) {
|
||||||
int otherSheetIndex = i+otherFirstSheetIndex;
|
int otherSheetIndex = i+otherFirstSheetIndex;
|
||||||
evals[i] = new SheetRefEvaluator(targetEvaluator, _tracker, otherSheetIndex);
|
evals[i] = new SheetRefEvaluator(targetEvaluator, _tracker, otherSheetIndex);
|
||||||
}
|
}
|
||||||
return new SheetRangeEvaluator(otherFirstSheetIndex, otherLastSheetIndex, evals);
|
return new SheetRangeEvaluator(otherFirstSheetIndex, otherLastSheetIndex, evals);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return <code>null</code> if either workbook or sheet is not found
|
* @return <code>null</code> if either workbook or sheet is not found
|
||||||
*/
|
*/
|
||||||
private SheetRefEvaluator createExternSheetRefEvaluator(String workbookName, String sheetName) {
|
private SheetRefEvaluator createExternSheetRefEvaluator(String workbookName, String sheetName) {
|
||||||
WorkbookEvaluator targetEvaluator;
|
WorkbookEvaluator targetEvaluator;
|
||||||
if (workbookName == null) {
|
if (workbookName == null) {
|
||||||
targetEvaluator = _bookEvaluator;
|
targetEvaluator = _bookEvaluator;
|
||||||
} else {
|
} else {
|
||||||
if (sheetName == null) {
|
if (sheetName == null) {
|
||||||
throw new IllegalArgumentException("sheetName must not be null if workbookName is provided");
|
throw new IllegalArgumentException("sheetName must not be null if workbookName is provided");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
targetEvaluator = _bookEvaluator.getOtherWorkbookEvaluator(workbookName);
|
targetEvaluator = _bookEvaluator.getOtherWorkbookEvaluator(workbookName);
|
||||||
} catch (WorkbookNotFoundException e) {
|
} catch (WorkbookNotFoundException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int otherSheetIndex = sheetName == null ? _sheetIndex : targetEvaluator.getSheetIndex(sheetName);
|
int otherSheetIndex = sheetName == null ? _sheetIndex : targetEvaluator.getSheetIndex(sheetName);
|
||||||
if (otherSheetIndex < 0) {
|
if (otherSheetIndex < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new SheetRefEvaluator(targetEvaluator, _tracker, otherSheetIndex);
|
return new SheetRefEvaluator(targetEvaluator, _tracker, otherSheetIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SheetRangeEvaluator getRefEvaluatorForCurrentSheet() {
|
public SheetRangeEvaluator getRefEvaluatorForCurrentSheet() {
|
||||||
SheetRefEvaluator sre = new SheetRefEvaluator(_bookEvaluator, _tracker, _sheetIndex);
|
SheetRefEvaluator sre = new SheetRefEvaluator(_bookEvaluator, _tracker, _sheetIndex);
|
||||||
return new SheetRangeEvaluator(_sheetIndex, sre);
|
return new SheetRangeEvaluator(_sheetIndex, sre);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a cell or area reference dynamically.
|
* Resolves a cell or area reference dynamically.
|
||||||
* @param workbookName the name of the workbook containing the reference. If <code>null</code>
|
* @param workbookName the name of the workbook containing the reference. If <code>null</code>
|
||||||
* the current workbook is assumed. Note - to evaluate formulas which use multiple workbooks,
|
* the current workbook is assumed. Note - to evaluate formulas which use multiple workbooks,
|
||||||
* a {@link CollaboratingWorkbooksEnvironment} must be set up.
|
* a {@link CollaboratingWorkbooksEnvironment} must be set up.
|
||||||
* @param sheetName the name of the sheet containing the reference. May be <code>null</code>
|
* @param sheetName the name of the sheet containing the reference. May be <code>null</code>
|
||||||
* (when <tt>workbookName</tt> is also null) in which case the current workbook and sheet is
|
* (when <tt>workbookName</tt> is also null) in which case the current workbook and sheet is
|
||||||
* assumed.
|
* assumed.
|
||||||
* @param refStrPart1 the single cell reference or first part of the area reference. Must not
|
* @param refStrPart1 the single cell reference or first part of the area reference. Must not
|
||||||
* be <code>null</code>.
|
* be <code>null</code>.
|
||||||
* @param refStrPart2 the second part of the area reference. For single cell references this
|
* @param refStrPart2 the second part of the area reference. For single cell references this
|
||||||
* parameter must be <code>null</code>
|
* parameter must be <code>null</code>
|
||||||
* @param isA1Style specifies the format for <tt>refStrPart1</tt> and <tt>refStrPart2</tt>.
|
* @param isA1Style specifies the format for <tt>refStrPart1</tt> and <tt>refStrPart2</tt>.
|
||||||
* Pass <code>true</code> for 'A1' style and <code>false</code> for 'R1C1' style.
|
* Pass <code>true</code> for 'A1' style and <code>false</code> for 'R1C1' style.
|
||||||
* TODO - currently POI only supports 'A1' reference style
|
* TODO - currently POI only supports 'A1' reference style
|
||||||
* @return a {@link RefEval} or {@link AreaEval}
|
* @return a {@link RefEval} or {@link AreaEval}
|
||||||
*/
|
*/
|
||||||
public ValueEval getDynamicReference(String workbookName, String sheetName, String refStrPart1,
|
public ValueEval getDynamicReference(String workbookName, String sheetName, String refStrPart1,
|
||||||
String refStrPart2, boolean isA1Style) {
|
String refStrPart2, boolean isA1Style) {
|
||||||
if (!isA1Style) {
|
if (!isA1Style) {
|
||||||
throw new RuntimeException("R1C1 style not supported yet");
|
throw new RuntimeException("R1C1 style not supported yet");
|
||||||
}
|
}
|
||||||
SheetRefEvaluator se = createExternSheetRefEvaluator(workbookName, sheetName);
|
SheetRefEvaluator se = createExternSheetRefEvaluator(workbookName, sheetName);
|
||||||
if (se == null) {
|
if (se == null) {
|
||||||
return ErrorEval.REF_INVALID;
|
return ErrorEval.REF_INVALID;
|
||||||
}
|
}
|
||||||
SheetRangeEvaluator sre = new SheetRangeEvaluator(_sheetIndex, se);
|
SheetRangeEvaluator sre = new SheetRangeEvaluator(_sheetIndex, se);
|
||||||
|
|
||||||
// ugly typecast - TODO - make spreadsheet version more easily accessible
|
// ugly typecast - TODO - make spreadsheet version more easily accessible
|
||||||
SpreadsheetVersion ssVersion = ((FormulaParsingWorkbook)_workbook).getSpreadsheetVersion();
|
SpreadsheetVersion ssVersion = ((FormulaParsingWorkbook)_workbook).getSpreadsheetVersion();
|
||||||
|
|
||||||
NameType part1refType = classifyCellReference(refStrPart1, ssVersion);
|
NameType part1refType = classifyCellReference(refStrPart1, ssVersion);
|
||||||
switch (part1refType) {
|
switch (part1refType) {
|
||||||
case BAD_CELL_OR_NAMED_RANGE:
|
case BAD_CELL_OR_NAMED_RANGE:
|
||||||
return ErrorEval.REF_INVALID;
|
return ErrorEval.REF_INVALID;
|
||||||
case NAMED_RANGE:
|
case NAMED_RANGE:
|
||||||
EvaluationName nm = ((FormulaParsingWorkbook)_workbook).getName(refStrPart1, _sheetIndex);
|
EvaluationName nm = ((FormulaParsingWorkbook)_workbook).getName(refStrPart1, _sheetIndex);
|
||||||
if(!nm.isRange()){
|
if(!nm.isRange()){
|
||||||
throw new RuntimeException("Specified name '" + refStrPart1 + "' is not a range as expected.");
|
throw new RuntimeException("Specified name '" + refStrPart1 + "' is not a range as expected.");
|
||||||
}
|
}
|
||||||
return _bookEvaluator.evaluateNameFormula(nm.getNameDefinition(), this);
|
return _bookEvaluator.evaluateNameFormula(nm.getNameDefinition(), this);
|
||||||
}
|
}
|
||||||
if (refStrPart2 == null) {
|
if (refStrPart2 == null) {
|
||||||
// no ':'
|
// no ':'
|
||||||
switch (part1refType) {
|
switch (part1refType) {
|
||||||
case COLUMN:
|
case COLUMN:
|
||||||
case ROW:
|
case ROW:
|
||||||
return ErrorEval.REF_INVALID;
|
return ErrorEval.REF_INVALID;
|
||||||
case CELL:
|
case CELL:
|
||||||
CellReference cr = new CellReference(refStrPart1);
|
CellReference cr = new CellReference(refStrPart1);
|
||||||
return new LazyRefEval(cr.getRow(), cr.getCol(), sre);
|
return new LazyRefEval(cr.getRow(), cr.getCol(), sre);
|
||||||
}
|
}
|
||||||
throw new IllegalStateException("Unexpected reference classification of '" + refStrPart1 + "'.");
|
throw new IllegalStateException("Unexpected reference classification of '" + refStrPart1 + "'.");
|
||||||
}
|
}
|
||||||
NameType part2refType = classifyCellReference(refStrPart1, ssVersion);
|
NameType part2refType = classifyCellReference(refStrPart1, ssVersion);
|
||||||
switch (part2refType) {
|
switch (part2refType) {
|
||||||
case BAD_CELL_OR_NAMED_RANGE:
|
case BAD_CELL_OR_NAMED_RANGE:
|
||||||
return ErrorEval.REF_INVALID;
|
return ErrorEval.REF_INVALID;
|
||||||
case NAMED_RANGE:
|
case NAMED_RANGE:
|
||||||
throw new RuntimeException("Cannot evaluate '" + refStrPart1
|
throw new RuntimeException("Cannot evaluate '" + refStrPart1
|
||||||
+ "'. Indirect evaluation of defined names not supported yet");
|
+ "'. Indirect evaluation of defined names not supported yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (part2refType != part1refType) {
|
if (part2refType != part1refType) {
|
||||||
// LHS and RHS of ':' must be compatible
|
// LHS and RHS of ':' must be compatible
|
||||||
return ErrorEval.REF_INVALID;
|
return ErrorEval.REF_INVALID;
|
||||||
}
|
}
|
||||||
int firstRow, firstCol, lastRow, lastCol;
|
int firstRow, firstCol, lastRow, lastCol;
|
||||||
switch (part1refType) {
|
switch (part1refType) {
|
||||||
case COLUMN:
|
case COLUMN:
|
||||||
firstRow =0;
|
firstRow =0;
|
||||||
if (part2refType.equals(NameType.COLUMN))
|
if (part2refType.equals(NameType.COLUMN))
|
||||||
{
|
{
|
||||||
@ -252,7 +252,7 @@ public final class OperationEvaluationContext {
|
|||||||
lastCol = parseColRef(refStrPart2);
|
lastCol = parseColRef(refStrPart2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ROW:
|
case ROW:
|
||||||
// support of cell range in the form of integer:integer
|
// support of cell range in the form of integer:integer
|
||||||
firstCol = 0;
|
firstCol = 0;
|
||||||
if (part2refType.equals(NameType.ROW))
|
if (part2refType.equals(NameType.ROW))
|
||||||
@ -265,61 +265,61 @@ public final class OperationEvaluationContext {
|
|||||||
firstRow = parseRowRef(refStrPart1);
|
firstRow = parseRowRef(refStrPart1);
|
||||||
lastRow = parseRowRef(refStrPart2);
|
lastRow = parseRowRef(refStrPart2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CELL:
|
case CELL:
|
||||||
CellReference cr;
|
CellReference cr;
|
||||||
cr = new CellReference(refStrPart1);
|
cr = new CellReference(refStrPart1);
|
||||||
firstRow = cr.getRow();
|
firstRow = cr.getRow();
|
||||||
firstCol = cr.getCol();
|
firstCol = cr.getCol();
|
||||||
cr = new CellReference(refStrPart2);
|
cr = new CellReference(refStrPart2);
|
||||||
lastRow = cr.getRow();
|
lastRow = cr.getRow();
|
||||||
lastCol = cr.getCol();
|
lastCol = cr.getCol();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unexpected reference classification of '" + refStrPart1 + "'.");
|
throw new IllegalStateException("Unexpected reference classification of '" + refStrPart1 + "'.");
|
||||||
}
|
}
|
||||||
return new LazyAreaEval(firstRow, firstCol, lastRow, lastCol, sre);
|
return new LazyAreaEval(firstRow, firstCol, lastRow, lastCol, sre);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int parseRowRef(String refStrPart) {
|
private static int parseRowRef(String refStrPart) {
|
||||||
return CellReference.convertColStringToIndex(refStrPart);
|
return CellReference.convertColStringToIndex(refStrPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int parseColRef(String refStrPart) {
|
private static int parseColRef(String refStrPart) {
|
||||||
return Integer.parseInt(refStrPart) - 1;
|
return Integer.parseInt(refStrPart) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NameType classifyCellReference(String str, SpreadsheetVersion ssVersion) {
|
private static NameType classifyCellReference(String str, SpreadsheetVersion ssVersion) {
|
||||||
int len = str.length();
|
int len = str.length();
|
||||||
if (len < 1) {
|
if (len < 1) {
|
||||||
return CellReference.NameType.BAD_CELL_OR_NAMED_RANGE;
|
return CellReference.NameType.BAD_CELL_OR_NAMED_RANGE;
|
||||||
}
|
}
|
||||||
return CellReference.classifyCellReference(str, ssVersion);
|
return CellReference.classifyCellReference(str, ssVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FreeRefFunction findUserDefinedFunction(String functionName) {
|
public FreeRefFunction findUserDefinedFunction(String functionName) {
|
||||||
return _bookEvaluator.findUserDefinedFunction(functionName);
|
return _bookEvaluator.findUserDefinedFunction(functionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueEval getRefEval(int rowIndex, int columnIndex) {
|
public ValueEval getRefEval(int rowIndex, int columnIndex) {
|
||||||
SheetRangeEvaluator sre = getRefEvaluatorForCurrentSheet();
|
SheetRangeEvaluator sre = getRefEvaluatorForCurrentSheet();
|
||||||
return new LazyRefEval(rowIndex, columnIndex, sre);
|
return new LazyRefEval(rowIndex, columnIndex, sre);
|
||||||
}
|
}
|
||||||
public ValueEval getRef3DEval(Ref3DPtg rptg) {
|
public ValueEval getRef3DEval(Ref3DPtg rptg) {
|
||||||
SheetRangeEvaluator sre = createExternSheetRefEvaluator(rptg.getExternSheetIndex());
|
SheetRangeEvaluator sre = createExternSheetRefEvaluator(rptg.getExternSheetIndex());
|
||||||
return new LazyRefEval(rptg.getRow(), rptg.getColumn(), sre);
|
return new LazyRefEval(rptg.getRow(), rptg.getColumn(), sre);
|
||||||
}
|
}
|
||||||
public ValueEval getRef3DEval(Ref3DPxg rptg) {
|
public ValueEval getRef3DEval(Ref3DPxg rptg) {
|
||||||
SheetRangeEvaluator sre = createExternSheetRefEvaluator(
|
SheetRangeEvaluator sre = createExternSheetRefEvaluator(
|
||||||
rptg.getSheetName(), rptg.getLastSheetName(), rptg.getExternalWorkbookNumber());
|
rptg.getSheetName(), rptg.getLastSheetName(), rptg.getExternalWorkbookNumber());
|
||||||
return new LazyRefEval(rptg.getRow(), rptg.getColumn(), sre);
|
return new LazyRefEval(rptg.getRow(), rptg.getColumn(), sre);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueEval getAreaEval(int firstRowIndex, int firstColumnIndex,
|
public ValueEval getAreaEval(int firstRowIndex, int firstColumnIndex,
|
||||||
int lastRowIndex, int lastColumnIndex) {
|
int lastRowIndex, int lastColumnIndex) {
|
||||||
SheetRangeEvaluator sre = getRefEvaluatorForCurrentSheet();
|
SheetRangeEvaluator sre = getRefEvaluatorForCurrentSheet();
|
||||||
return new LazyAreaEval(firstRowIndex, firstColumnIndex, lastRowIndex, lastColumnIndex, sre);
|
return new LazyAreaEval(firstRowIndex, firstColumnIndex, lastRowIndex, lastColumnIndex, sre);
|
||||||
}
|
}
|
||||||
public ValueEval getArea3DEval(Area3DPtg aptg) {
|
public ValueEval getArea3DEval(Area3DPtg aptg) {
|
||||||
SheetRangeEvaluator sre = createExternSheetRefEvaluator(aptg.getExternSheetIndex());
|
SheetRangeEvaluator sre = createExternSheetRefEvaluator(aptg.getExternSheetIndex());
|
||||||
return new LazyAreaEval(aptg.getFirstRow(), aptg.getFirstColumn(),
|
return new LazyAreaEval(aptg.getFirstRow(), aptg.getFirstColumn(),
|
||||||
@ -348,8 +348,8 @@ public final class OperationEvaluationContext {
|
|||||||
);
|
);
|
||||||
return getExternalNameXEval(externName, workbookName);
|
return getExternalNameXEval(externName, workbookName);
|
||||||
}
|
}
|
||||||
public ValueEval getNameXEval(NameXPxg nameXPxg) {
|
public ValueEval getNameXEval(NameXPxg nameXPxg) {
|
||||||
ExternalSheet externSheet = _workbook.getExternalSheet(nameXPxg.getSheetName(), null, nameXPxg.getExternalWorkbookNumber());
|
ExternalSheet externSheet = _workbook.getExternalSheet(nameXPxg.getSheetName(), null, nameXPxg.getExternalWorkbookNumber());
|
||||||
if(externSheet == null || externSheet.getWorkbookName() == null) {
|
if(externSheet == null || externSheet.getWorkbookName() == null) {
|
||||||
// External reference to our own workbook's name
|
// External reference to our own workbook's name
|
||||||
return getLocalNameXEval(nameXPxg);
|
return getLocalNameXEval(nameXPxg);
|
||||||
@ -363,8 +363,8 @@ public final class OperationEvaluationContext {
|
|||||||
nameXPxg.getExternalWorkbookNumber()
|
nameXPxg.getExternalWorkbookNumber()
|
||||||
);
|
);
|
||||||
return getExternalNameXEval(externName, workbookName);
|
return getExternalNameXEval(externName, workbookName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueEval getLocalNameXEval(NameXPxg nameXPxg) {
|
private ValueEval getLocalNameXEval(NameXPxg nameXPxg) {
|
||||||
// Look up the sheet, if present
|
// Look up the sheet, if present
|
||||||
int sIdx = -1;
|
int sIdx = -1;
|
||||||
@ -383,7 +383,7 @@ public final class OperationEvaluationContext {
|
|||||||
return new FunctionNameEval(name);
|
return new FunctionNameEval(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private ValueEval getLocalNameXEval(NameXPtg nameXPtg) {
|
private ValueEval getLocalNameXEval(NameXPtg nameXPtg) {
|
||||||
String name = _workbook.resolveNameXText(nameXPtg);
|
String name = _workbook.resolveNameXText(nameXPtg);
|
||||||
|
|
||||||
// Try to parse it as a name
|
// Try to parse it as a name
|
||||||
@ -406,8 +406,11 @@ public final class OperationEvaluationContext {
|
|||||||
// Must be an external function
|
// Must be an external function
|
||||||
return new FunctionNameEval(name);
|
return new FunctionNameEval(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public int getSheetIndex() {
|
||||||
|
return _sheetIndex;
|
||||||
|
}
|
||||||
|
|
||||||
private ValueEval getExternalNameXEval(ExternalName externName, String workbookName) {
|
private ValueEval getExternalNameXEval(ExternalName externName, String workbookName) {
|
||||||
try {
|
try {
|
||||||
// Fetch the workbook this refers to, and the name as defined with that
|
// Fetch the workbook this refers to, and the name as defined with that
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -17,13 +17,18 @@
|
|||||||
|
|
||||||
package org.apache.poi.ss.formula.functions;
|
package org.apache.poi.ss.formula.functions;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.formula.FormulaParseException;
|
||||||
|
import org.apache.poi.ss.formula.FormulaParser;
|
||||||
|
import org.apache.poi.ss.formula.FormulaParsingWorkbook;
|
||||||
|
import org.apache.poi.ss.formula.OperationEvaluationContext;
|
||||||
import org.apache.poi.ss.formula.eval.BlankEval;
|
import org.apache.poi.ss.formula.eval.BlankEval;
|
||||||
import org.apache.poi.ss.formula.eval.ErrorEval;
|
import org.apache.poi.ss.formula.eval.ErrorEval;
|
||||||
import org.apache.poi.ss.formula.eval.EvaluationException;
|
import org.apache.poi.ss.formula.eval.EvaluationException;
|
||||||
import org.apache.poi.ss.formula.eval.MissingArgEval;
|
import org.apache.poi.ss.formula.eval.MissingArgEval;
|
||||||
import org.apache.poi.ss.formula.eval.OperandResolver;
|
import org.apache.poi.ss.formula.eval.OperandResolver;
|
||||||
import org.apache.poi.ss.formula.eval.ValueEval;
|
import org.apache.poi.ss.formula.eval.ValueEval;
|
||||||
import org.apache.poi.ss.formula.OperationEvaluationContext;
|
import org.apache.poi.ss.formula.ptg.Area3DPxg;
|
||||||
|
import org.apache.poi.ss.usermodel.Table;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation for Excel function INDIRECT<p/>
|
* Implementation for Excel function INDIRECT<p/>
|
||||||
@ -42,198 +47,210 @@ import org.apache.poi.ss.formula.OperationEvaluationContext;
|
|||||||
*/
|
*/
|
||||||
public final class Indirect implements FreeRefFunction {
|
public final class Indirect implements FreeRefFunction {
|
||||||
|
|
||||||
public static final FreeRefFunction instance = new Indirect();
|
public static final FreeRefFunction instance = new Indirect();
|
||||||
|
|
||||||
private Indirect() {
|
private Indirect() {
|
||||||
// enforce singleton
|
// enforce singleton
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
|
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
|
||||||
if (args.length < 1) {
|
if (args.length < 1) {
|
||||||
return ErrorEval.VALUE_INVALID;
|
return ErrorEval.VALUE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isA1style;
|
boolean isA1style;
|
||||||
String text;
|
String text;
|
||||||
try {
|
try {
|
||||||
ValueEval ve = OperandResolver.getSingleValue(args[0], ec.getRowIndex(), ec
|
ValueEval ve = OperandResolver.getSingleValue(args[0], ec.getRowIndex(), ec
|
||||||
.getColumnIndex());
|
.getColumnIndex());
|
||||||
text = OperandResolver.coerceValueToString(ve);
|
text = OperandResolver.coerceValueToString(ve);
|
||||||
switch (args.length) {
|
switch (args.length) {
|
||||||
case 1:
|
case 1:
|
||||||
isA1style = true;
|
isA1style = true;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
isA1style = evaluateBooleanArg(args[1], ec);
|
isA1style = evaluateBooleanArg(args[1], ec);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return ErrorEval.VALUE_INVALID;
|
return ErrorEval.VALUE_INVALID;
|
||||||
}
|
}
|
||||||
} catch (EvaluationException e) {
|
} catch (EvaluationException e) {
|
||||||
return e.getErrorEval();
|
return e.getErrorEval();
|
||||||
}
|
}
|
||||||
|
|
||||||
return evaluateIndirect(ec, text, isA1style);
|
return evaluateIndirect(ec, text, isA1style);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean evaluateBooleanArg(ValueEval arg, OperationEvaluationContext ec)
|
private static boolean evaluateBooleanArg(ValueEval arg, OperationEvaluationContext ec)
|
||||||
throws EvaluationException {
|
throws EvaluationException {
|
||||||
ValueEval ve = OperandResolver.getSingleValue(arg, ec.getRowIndex(), ec.getColumnIndex());
|
ValueEval ve = OperandResolver.getSingleValue(arg, ec.getRowIndex(), ec.getColumnIndex());
|
||||||
|
|
||||||
if (ve == BlankEval.instance || ve == MissingArgEval.instance) {
|
if (ve == BlankEval.instance || ve == MissingArgEval.instance) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// numeric quantities follow standard boolean conversion rules
|
// numeric quantities follow standard boolean conversion rules
|
||||||
// for strings, only "TRUE" and "FALSE" (case insensitive) are valid
|
// for strings, only "TRUE" and "FALSE" (case insensitive) are valid
|
||||||
return OperandResolver.coerceValueToBoolean(ve, false).booleanValue();
|
return OperandResolver.coerceValueToBoolean(ve, false).booleanValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ValueEval evaluateIndirect(OperationEvaluationContext ec, String text,
|
private static ValueEval evaluateIndirect(final OperationEvaluationContext ec, String text,
|
||||||
boolean isA1style) {
|
boolean isA1style) {
|
||||||
// Search backwards for '!' because sheet names can contain '!'
|
|
||||||
int plingPos = text.lastIndexOf('!');
|
// Search backwards for '!' because sheet names can contain '!'
|
||||||
|
int plingPos = text.lastIndexOf('!');
|
||||||
|
|
||||||
String workbookName;
|
String workbookName;
|
||||||
String sheetName;
|
String sheetName;
|
||||||
String refText; // whitespace around this gets trimmed OK
|
String refText; // whitespace around this gets trimmed OK
|
||||||
if (plingPos < 0) {
|
if (plingPos < 0) {
|
||||||
workbookName = null;
|
workbookName = null;
|
||||||
sheetName = null;
|
sheetName = null;
|
||||||
refText = text;
|
refText = text;
|
||||||
} else {
|
} else {
|
||||||
String[] parts = parseWorkbookAndSheetName(text.subSequence(0, plingPos));
|
String[] parts = parseWorkbookAndSheetName(text.subSequence(0, plingPos));
|
||||||
if (parts == null) {
|
if (parts == null) {
|
||||||
return ErrorEval.REF_INVALID;
|
return ErrorEval.REF_INVALID;
|
||||||
}
|
}
|
||||||
workbookName = parts[0];
|
workbookName = parts[0];
|
||||||
sheetName = parts[1];
|
sheetName = parts[1];
|
||||||
refText = text.substring(plingPos + 1);
|
refText = text.substring(plingPos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
String refStrPart1;
|
if (Table.isStructuredReference.matcher(refText).matches()) {
|
||||||
String refStrPart2;
|
// The argument is structured reference
|
||||||
|
Area3DPxg areaPtg = null;
|
||||||
|
try {
|
||||||
|
areaPtg = FormulaParser.parseStructuredReference(refText, (FormulaParsingWorkbook) ec.getWorkbook(), ec.getRowIndex());
|
||||||
|
} catch (FormulaParseException e) {
|
||||||
|
return ErrorEval.REF_INVALID;
|
||||||
|
}
|
||||||
|
return ec.getArea3DEval(areaPtg);
|
||||||
|
} else {
|
||||||
|
// The argument is regular reference
|
||||||
|
String refStrPart1;
|
||||||
|
String refStrPart2;
|
||||||
|
int colonPos = refText.indexOf(':');
|
||||||
|
if (colonPos < 0) {
|
||||||
|
refStrPart1 = refText.trim();
|
||||||
|
refStrPart2 = null;
|
||||||
|
} else {
|
||||||
|
refStrPart1 = refText.substring(0, colonPos).trim();
|
||||||
|
refStrPart2 = refText.substring(colonPos + 1).trim();
|
||||||
|
}
|
||||||
|
return ec.getDynamicReference(workbookName, sheetName, refStrPart1, refStrPart2, isA1style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int colonPos = refText.indexOf(':');
|
/**
|
||||||
if (colonPos < 0) {
|
* @return array of length 2: {workbookName, sheetName,}. Second element will always be
|
||||||
refStrPart1 = refText.trim();
|
* present. First element may be null if sheetName is unqualified.
|
||||||
refStrPart2 = null;
|
* Returns <code>null</code> if text cannot be parsed.
|
||||||
} else {
|
*/
|
||||||
refStrPart1 = refText.substring(0, colonPos).trim();
|
private static String[] parseWorkbookAndSheetName(CharSequence text) {
|
||||||
refStrPart2 = refText.substring(colonPos + 1).trim();
|
int lastIx = text.length() - 1;
|
||||||
}
|
if (lastIx < 0) {
|
||||||
return ec.getDynamicReference(workbookName, sheetName, refStrPart1, refStrPart2, isA1style);
|
return null;
|
||||||
}
|
}
|
||||||
|
if (canTrim(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
char firstChar = text.charAt(0);
|
||||||
|
if (Character.isWhitespace(firstChar)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (firstChar == '\'') {
|
||||||
|
// workbookName or sheetName needs quoting
|
||||||
|
// quotes go around both
|
||||||
|
if (text.charAt(lastIx) != '\'') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
firstChar = text.charAt(1);
|
||||||
|
if (Character.isWhitespace(firstChar)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String wbName;
|
||||||
|
int sheetStartPos;
|
||||||
|
if (firstChar == '[') {
|
||||||
|
int rbPos = text.toString().lastIndexOf(']');
|
||||||
|
if (rbPos < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
wbName = unescapeString(text.subSequence(2, rbPos));
|
||||||
|
if (wbName == null || canTrim(wbName)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
sheetStartPos = rbPos + 1;
|
||||||
|
} else {
|
||||||
|
wbName = null;
|
||||||
|
sheetStartPos = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
// else - just sheet name
|
||||||
* @return array of length 2: {workbookName, sheetName,}. Second element will always be
|
String sheetName = unescapeString(text.subSequence(sheetStartPos, lastIx));
|
||||||
* present. First element may be null if sheetName is unqualified.
|
if (sheetName == null) { // note - when quoted, sheetName can
|
||||||
* Returns <code>null</code> if text cannot be parsed.
|
// start/end with whitespace
|
||||||
*/
|
return null;
|
||||||
private static String[] parseWorkbookAndSheetName(CharSequence text) {
|
}
|
||||||
int lastIx = text.length() - 1;
|
return new String[] { wbName, sheetName, };
|
||||||
if (lastIx < 0) {
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (canTrim(text)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
char firstChar = text.charAt(0);
|
|
||||||
if (Character.isWhitespace(firstChar)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (firstChar == '\'') {
|
|
||||||
// workbookName or sheetName needs quoting
|
|
||||||
// quotes go around both
|
|
||||||
if (text.charAt(lastIx) != '\'') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
firstChar = text.charAt(1);
|
|
||||||
if (Character.isWhitespace(firstChar)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String wbName;
|
|
||||||
int sheetStartPos;
|
|
||||||
if (firstChar == '[') {
|
|
||||||
int rbPos = text.toString().lastIndexOf(']');
|
|
||||||
if (rbPos < 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
wbName = unescapeString(text.subSequence(2, rbPos));
|
|
||||||
if (wbName == null || canTrim(wbName)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
sheetStartPos = rbPos + 1;
|
|
||||||
} else {
|
|
||||||
wbName = null;
|
|
||||||
sheetStartPos = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// else - just sheet name
|
if (firstChar == '[') {
|
||||||
String sheetName = unescapeString(text.subSequence(sheetStartPos, lastIx));
|
int rbPos = text.toString().lastIndexOf(']');
|
||||||
if (sheetName == null) { // note - when quoted, sheetName can
|
if (rbPos < 0) {
|
||||||
// start/end with whitespace
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
CharSequence wbName = text.subSequence(1, rbPos);
|
||||||
return new String[] { wbName, sheetName, };
|
if (canTrim(wbName)) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
CharSequence sheetName = text.subSequence(rbPos + 1, text.length());
|
||||||
|
if (canTrim(sheetName)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new String[] { wbName.toString(), sheetName.toString(), };
|
||||||
|
}
|
||||||
|
// else - just sheet name
|
||||||
|
return new String[] { null, text.toString(), };
|
||||||
|
}
|
||||||
|
|
||||||
if (firstChar == '[') {
|
/**
|
||||||
int rbPos = text.toString().lastIndexOf(']');
|
* @return <code>null</code> if there is a syntax error in any escape sequence
|
||||||
if (rbPos < 0) {
|
* (the typical syntax error is a single quote character not followed by another).
|
||||||
return null;
|
*/
|
||||||
}
|
private static String unescapeString(CharSequence text) {
|
||||||
CharSequence wbName = text.subSequence(1, rbPos);
|
int len = text.length();
|
||||||
if (canTrim(wbName)) {
|
StringBuilder sb = new StringBuilder(len);
|
||||||
return null;
|
int i = 0;
|
||||||
}
|
while (i < len) {
|
||||||
CharSequence sheetName = text.subSequence(rbPos + 1, text.length());
|
char ch = text.charAt(i);
|
||||||
if (canTrim(sheetName)) {
|
if (ch == '\'') {
|
||||||
return null;
|
// every quote must be followed by another
|
||||||
}
|
i++;
|
||||||
return new String[] { wbName.toString(), sheetName.toString(), };
|
if (i >= len) {
|
||||||
}
|
return null;
|
||||||
// else - just sheet name
|
}
|
||||||
return new String[] { null, text.toString(), };
|
ch = text.charAt(i);
|
||||||
}
|
if (ch != '\'') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.append(ch);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
private static boolean canTrim(CharSequence text) {
|
||||||
* @return <code>null</code> if there is a syntax error in any escape sequence
|
int lastIx = text.length() - 1;
|
||||||
* (the typical syntax error is a single quote character not followed by another).
|
if (lastIx < 0) {
|
||||||
*/
|
return false;
|
||||||
private static String unescapeString(CharSequence text) {
|
}
|
||||||
int len = text.length();
|
if (Character.isWhitespace(text.charAt(0))) {
|
||||||
StringBuilder sb = new StringBuilder(len);
|
return true;
|
||||||
int i = 0;
|
}
|
||||||
while (i < len) {
|
if (Character.isWhitespace(text.charAt(lastIx))) {
|
||||||
char ch = text.charAt(i);
|
return true;
|
||||||
if (ch == '\'') {
|
}
|
||||||
// every quote must be followed by another
|
return false;
|
||||||
i++;
|
}
|
||||||
if (i >= len) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ch = text.charAt(i);
|
|
||||||
if (ch != '\'') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sb.append(ch);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean canTrim(CharSequence text) {
|
|
||||||
int lastIx = text.length() - 1;
|
|
||||||
if (lastIx < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (Character.isWhitespace(text.charAt(0))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (Character.isWhitespace(text.charAt(lastIx))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -36,9 +36,9 @@ public final class Area3DPxg extends AreaPtgBase implements Pxg3D {
|
|||||||
private String firstSheetName;
|
private String firstSheetName;
|
||||||
private String lastSheetName;
|
private String lastSheetName;
|
||||||
|
|
||||||
public Area3DPxg(int externalWorkbookNumber, SheetIdentifier sheetName, String arearef) {
|
public Area3DPxg(int externalWorkbookNumber, SheetIdentifier sheetName, String arearef) {
|
||||||
this(externalWorkbookNumber, sheetName, new AreaReference(arearef));
|
this(externalWorkbookNumber, sheetName, new AreaReference(arearef));
|
||||||
}
|
}
|
||||||
public Area3DPxg(int externalWorkbookNumber, SheetIdentifier sheetName, AreaReference arearef) {
|
public Area3DPxg(int externalWorkbookNumber, SheetIdentifier sheetName, AreaReference arearef) {
|
||||||
super(arearef);
|
super(arearef);
|
||||||
this.externalWorkbookNumber = externalWorkbookNumber;
|
this.externalWorkbookNumber = externalWorkbookNumber;
|
||||||
@ -57,8 +57,8 @@ public final class Area3DPxg extends AreaPtgBase implements Pxg3D {
|
|||||||
this(-1, sheetName, arearef);
|
this(-1, sheetName, arearef);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
sb.append(getClass().getName());
|
sb.append(getClass().getName());
|
||||||
sb.append(" [");
|
sb.append(" [");
|
||||||
@ -76,8 +76,8 @@ public final class Area3DPxg extends AreaPtgBase implements Pxg3D {
|
|||||||
sb.append(formatReferenceAsString());
|
sb.append(formatReferenceAsString());
|
||||||
sb.append("]");
|
sb.append("]");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getExternalWorkbookNumber() {
|
public int getExternalWorkbookNumber() {
|
||||||
return externalWorkbookNumber;
|
return externalWorkbookNumber;
|
||||||
}
|
}
|
||||||
|
@ -31,272 +31,272 @@ import org.apache.poi.util.LittleEndianOutput;
|
|||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
public abstract class AreaPtgBase extends OperandPtg implements AreaI {
|
public abstract class AreaPtgBase extends OperandPtg implements AreaI {
|
||||||
/**
|
/**
|
||||||
* TODO - (May-2008) fix subclasses of AreaPtg 'AreaN~' which are used in shared formulas.
|
* TODO - (May-2008) fix subclasses of AreaPtg 'AreaN~' which are used in shared formulas.
|
||||||
* see similar comment in ReferencePtg
|
* see similar comment in ReferencePtg
|
||||||
*/
|
*/
|
||||||
protected final RuntimeException notImplemented() {
|
protected final RuntimeException notImplemented() {
|
||||||
return new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
return new RuntimeException("Coding Error: This method should never be called. This ptg should be converted");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** zero based, unsigned 16 bit */
|
/** zero based, unsigned 16 bit */
|
||||||
private int field_1_first_row;
|
private int field_1_first_row;
|
||||||
/** zero based, unsigned 16 bit */
|
/** zero based, unsigned 16 bit */
|
||||||
private int field_2_last_row;
|
private int field_2_last_row;
|
||||||
/** zero based, unsigned 8 bit */
|
/** zero based, unsigned 8 bit */
|
||||||
private int field_3_first_column; //BitFields: (first row relative, first col relative, first column number)
|
private int field_3_first_column; //BitFields: (first row relative, first col relative, first column number)
|
||||||
/** zero based, unsigned 8 bit */
|
/** zero based, unsigned 8 bit */
|
||||||
private int field_4_last_column; //BitFields: (last row relative, last col relative, last column number)
|
private int field_4_last_column; //BitFields: (last row relative, last col relative, last column number)
|
||||||
|
|
||||||
private final static BitField rowRelative = BitFieldFactory.getInstance(0x8000);
|
private final static BitField rowRelative = BitFieldFactory.getInstance(0x8000);
|
||||||
private final static BitField colRelative = BitFieldFactory.getInstance(0x4000);
|
private final static BitField colRelative = BitFieldFactory.getInstance(0x4000);
|
||||||
private final static BitField columnMask = BitFieldFactory.getInstance(0x3FFF);
|
private final static BitField columnMask = BitFieldFactory.getInstance(0x3FFF);
|
||||||
|
|
||||||
protected AreaPtgBase() {
|
protected AreaPtgBase() {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AreaPtgBase(AreaReference ar) {
|
protected AreaPtgBase(AreaReference ar) {
|
||||||
CellReference firstCell = ar.getFirstCell();
|
CellReference firstCell = ar.getFirstCell();
|
||||||
CellReference lastCell = ar.getLastCell();
|
CellReference lastCell = ar.getLastCell();
|
||||||
setFirstRow(firstCell.getRow());
|
setFirstRow(firstCell.getRow());
|
||||||
setFirstColumn(firstCell.getCol() == -1 ? 0 : firstCell.getCol());
|
setFirstColumn(firstCell.getCol() == -1 ? 0 : firstCell.getCol());
|
||||||
setLastRow(lastCell.getRow());
|
setLastRow(lastCell.getRow());
|
||||||
setLastColumn(lastCell.getCol() == -1 ? 0xFF : lastCell.getCol());
|
setLastColumn(lastCell.getCol() == -1 ? 0xFF : lastCell.getCol());
|
||||||
setFirstColRelative(!firstCell.isColAbsolute());
|
setFirstColRelative(!firstCell.isColAbsolute());
|
||||||
setLastColRelative(!lastCell.isColAbsolute());
|
setLastColRelative(!lastCell.isColAbsolute());
|
||||||
setFirstRowRelative(!firstCell.isRowAbsolute());
|
setFirstRowRelative(!firstCell.isRowAbsolute());
|
||||||
setLastRowRelative(!lastCell.isRowAbsolute());
|
setLastRowRelative(!lastCell.isRowAbsolute());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AreaPtgBase(int firstRow, int lastRow, int firstColumn, int lastColumn,
|
protected AreaPtgBase(int firstRow, int lastRow, int firstColumn, int lastColumn,
|
||||||
boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
|
boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
|
||||||
|
|
||||||
if (lastRow >= firstRow) {
|
if (lastRow >= firstRow) {
|
||||||
setFirstRow(firstRow);
|
setFirstRow(firstRow);
|
||||||
setLastRow(lastRow);
|
setLastRow(lastRow);
|
||||||
setFirstRowRelative(firstRowRelative);
|
setFirstRowRelative(firstRowRelative);
|
||||||
setLastRowRelative(lastRowRelative);
|
setLastRowRelative(lastRowRelative);
|
||||||
} else {
|
} else {
|
||||||
setFirstRow(lastRow);
|
setFirstRow(lastRow);
|
||||||
setLastRow(firstRow);
|
setLastRow(firstRow);
|
||||||
setFirstRowRelative(lastRowRelative);
|
setFirstRowRelative(lastRowRelative);
|
||||||
setLastRowRelative(firstRowRelative);
|
setLastRowRelative(firstRowRelative);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastColumn >= firstColumn) {
|
if (lastColumn >= firstColumn) {
|
||||||
setFirstColumn(firstColumn);
|
setFirstColumn(firstColumn);
|
||||||
setLastColumn(lastColumn);
|
setLastColumn(lastColumn);
|
||||||
setFirstColRelative(firstColRelative);
|
setFirstColRelative(firstColRelative);
|
||||||
setLastColRelative(lastColRelative);
|
setLastColRelative(lastColRelative);
|
||||||
} else {
|
} else {
|
||||||
setFirstColumn(lastColumn);
|
setFirstColumn(lastColumn);
|
||||||
setLastColumn(firstColumn);
|
setLastColumn(firstColumn);
|
||||||
setFirstColRelative(lastColRelative);
|
setFirstColRelative(lastColRelative);
|
||||||
setLastColRelative(firstColRelative);
|
setLastColRelative(firstColRelative);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort the first and last row and columns in-place to the preferred (top left:bottom right) order
|
* Sort the first and last row and columns in-place to the preferred (top left:bottom right) order
|
||||||
* Note: Sort only occurs when an instance is constructed or when this method is called.
|
* Note: Sort only occurs when an instance is constructed or when this method is called.
|
||||||
*
|
*
|
||||||
* <p>For example, <code>$E5:B$10</code> becomes <code>B5:$E$10</code></p>
|
* <p>For example, <code>$E5:B$10</code> becomes <code>B5:$E$10</code></p>
|
||||||
*/
|
*/
|
||||||
public void sortTopLeftToBottomRight() {
|
public void sortTopLeftToBottomRight() {
|
||||||
if (getFirstRow() > getLastRow()) {
|
if (getFirstRow() > getLastRow()) {
|
||||||
//swap first row and last row numbers and relativity
|
//swap first row and last row numbers and relativity
|
||||||
//Note: cannot just swap the fields because row relativity is stored in fields 3 and 4
|
//Note: cannot just swap the fields because row relativity is stored in fields 3 and 4
|
||||||
final int firstRow = getFirstRow();
|
final int firstRow = getFirstRow();
|
||||||
final boolean firstRowRel = isFirstRowRelative();
|
final boolean firstRowRel = isFirstRowRelative();
|
||||||
setFirstRow(getLastRow());
|
setFirstRow(getLastRow());
|
||||||
setFirstRowRelative(isLastRowRelative());
|
setFirstRowRelative(isLastRowRelative());
|
||||||
setLastRow(firstRow);
|
setLastRow(firstRow);
|
||||||
setLastRowRelative(firstRowRel);
|
setLastRowRelative(firstRowRel);
|
||||||
}
|
}
|
||||||
if (getFirstColumn() > getLastColumn()) {
|
if (getFirstColumn() > getLastColumn()) {
|
||||||
//swap first column and last column numbers and relativity
|
//swap first column and last column numbers and relativity
|
||||||
//Note: cannot just swap the fields because row relativity is stored in fields 3 and 4
|
//Note: cannot just swap the fields because row relativity is stored in fields 3 and 4
|
||||||
final int firstCol = getFirstColumn();
|
final int firstCol = getFirstColumn();
|
||||||
final boolean firstColRel = isFirstColRelative();
|
final boolean firstColRel = isFirstColRelative();
|
||||||
setFirstColumn(getLastColumn());
|
setFirstColumn(getLastColumn());
|
||||||
setFirstColRelative(isLastColRelative());
|
setFirstColRelative(isLastColRelative());
|
||||||
setLastColumn(firstCol);
|
setLastColumn(firstCol);
|
||||||
setLastColRelative(firstColRel);
|
setLastColRelative(firstColRel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void readCoordinates(LittleEndianInput in) {
|
protected final void readCoordinates(LittleEndianInput in) {
|
||||||
field_1_first_row = in.readUShort();
|
field_1_first_row = in.readUShort();
|
||||||
field_2_last_row = in.readUShort();
|
field_2_last_row = in.readUShort();
|
||||||
field_3_first_column = in.readUShort();
|
field_3_first_column = in.readUShort();
|
||||||
field_4_last_column = in.readUShort();
|
field_4_last_column = in.readUShort();
|
||||||
}
|
}
|
||||||
protected final void writeCoordinates(LittleEndianOutput out) {
|
protected final void writeCoordinates(LittleEndianOutput out) {
|
||||||
out.writeShort(field_1_first_row);
|
out.writeShort(field_1_first_row);
|
||||||
out.writeShort(field_2_last_row);
|
out.writeShort(field_2_last_row);
|
||||||
out.writeShort(field_3_first_column);
|
out.writeShort(field_3_first_column);
|
||||||
out.writeShort(field_4_last_column);
|
out.writeShort(field_4_last_column);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the first row in the area
|
* @return the first row in the area
|
||||||
*/
|
*/
|
||||||
public final int getFirstRow() {
|
public final int getFirstRow() {
|
||||||
return field_1_first_row;
|
return field_1_first_row;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sets the first row
|
* sets the first row
|
||||||
* @param rowIx number (0-based)
|
* @param rowIx number (0-based)
|
||||||
*/
|
*/
|
||||||
public final void setFirstRow(int rowIx) {
|
public final void setFirstRow(int rowIx) {
|
||||||
field_1_first_row = rowIx;
|
field_1_first_row = rowIx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return last row in the range (x2 in x1,y1-x2,y2)
|
* @return last row in the range (x2 in x1,y1-x2,y2)
|
||||||
*/
|
*/
|
||||||
public final int getLastRow() {
|
public final int getLastRow() {
|
||||||
return field_2_last_row;
|
return field_2_last_row;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param rowIx last row number in the area
|
* @param rowIx last row number in the area
|
||||||
*/
|
*/
|
||||||
public final void setLastRow(int rowIx) {
|
public final void setLastRow(int rowIx) {
|
||||||
field_2_last_row = rowIx;
|
field_2_last_row = rowIx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the first column number in the area.
|
* @return the first column number in the area.
|
||||||
*/
|
*/
|
||||||
public final int getFirstColumn() {
|
public final int getFirstColumn() {
|
||||||
return columnMask.getValue(field_3_first_column);
|
return columnMask.getValue(field_3_first_column);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the first column number + the options bit settings unstripped
|
* @return the first column number + the options bit settings unstripped
|
||||||
*/
|
*/
|
||||||
public final short getFirstColumnRaw() {
|
public final short getFirstColumnRaw() {
|
||||||
return (short) field_3_first_column; // TODO
|
return (short) field_3_first_column; // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return whether or not the first row is a relative reference or not.
|
* @return whether or not the first row is a relative reference or not.
|
||||||
*/
|
*/
|
||||||
public final boolean isFirstRowRelative() {
|
public final boolean isFirstRowRelative() {
|
||||||
return rowRelative.isSet(field_3_first_column);
|
return rowRelative.isSet(field_3_first_column);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sets the first row to relative or not
|
* sets the first row to relative or not
|
||||||
* @param rel is relative or not.
|
* @param rel is relative or not.
|
||||||
*/
|
*/
|
||||||
public final void setFirstRowRelative(boolean rel) {
|
public final void setFirstRowRelative(boolean rel) {
|
||||||
field_3_first_column=rowRelative.setBoolean(field_3_first_column,rel);
|
field_3_first_column=rowRelative.setBoolean(field_3_first_column,rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return isrelative first column to relative or not
|
* @return isrelative first column to relative or not
|
||||||
*/
|
*/
|
||||||
public final boolean isFirstColRelative() {
|
public final boolean isFirstColRelative() {
|
||||||
return colRelative.isSet(field_3_first_column);
|
return colRelative.isSet(field_3_first_column);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set whether the first column is relative
|
* set whether the first column is relative
|
||||||
*/
|
*/
|
||||||
public final void setFirstColRelative(boolean rel) {
|
public final void setFirstColRelative(boolean rel) {
|
||||||
field_3_first_column=colRelative.setBoolean(field_3_first_column,rel);
|
field_3_first_column=colRelative.setBoolean(field_3_first_column,rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the first column in the area
|
* set the first column in the area
|
||||||
*/
|
*/
|
||||||
public final void setFirstColumn(int colIx) {
|
public final void setFirstColumn(int colIx) {
|
||||||
field_3_first_column=columnMask.setValue(field_3_first_column, colIx);
|
field_3_first_column=columnMask.setValue(field_3_first_column, colIx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the first column irrespective of the bitmasks
|
* set the first column irrespective of the bitmasks
|
||||||
*/
|
*/
|
||||||
public final void setFirstColumnRaw(int column) {
|
public final void setFirstColumnRaw(int column) {
|
||||||
field_3_first_column = column;
|
field_3_first_column = column;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return lastcolumn in the area
|
* @return lastcolumn in the area
|
||||||
*/
|
*/
|
||||||
public final int getLastColumn() {
|
public final int getLastColumn() {
|
||||||
return columnMask.getValue(field_4_last_column);
|
return columnMask.getValue(field_4_last_column);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return last column and bitmask (the raw field)
|
* @return last column and bitmask (the raw field)
|
||||||
*/
|
*/
|
||||||
public final short getLastColumnRaw() {
|
public final short getLastColumnRaw() {
|
||||||
return (short) field_4_last_column;
|
return (short) field_4_last_column;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return last row relative or not
|
* @return last row relative or not
|
||||||
*/
|
*/
|
||||||
public final boolean isLastRowRelative() {
|
public final boolean isLastRowRelative() {
|
||||||
return rowRelative.isSet(field_4_last_column);
|
return rowRelative.isSet(field_4_last_column);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set whether the last row is relative or not
|
* set whether the last row is relative or not
|
||||||
* @param rel <code>true</code> if the last row relative, else
|
* @param rel <code>true</code> if the last row relative, else
|
||||||
* <code>false</code>
|
* <code>false</code>
|
||||||
*/
|
*/
|
||||||
public final void setLastRowRelative(boolean rel) {
|
public final void setLastRowRelative(boolean rel) {
|
||||||
field_4_last_column=rowRelative.setBoolean(field_4_last_column,rel);
|
field_4_last_column=rowRelative.setBoolean(field_4_last_column,rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return lastcol relative or not
|
* @return lastcol relative or not
|
||||||
*/
|
*/
|
||||||
public final boolean isLastColRelative() {
|
public final boolean isLastColRelative() {
|
||||||
return colRelative.isSet(field_4_last_column);
|
return colRelative.isSet(field_4_last_column);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set whether the last column should be relative or not
|
* set whether the last column should be relative or not
|
||||||
*/
|
*/
|
||||||
public final void setLastColRelative(boolean rel) {
|
public final void setLastColRelative(boolean rel) {
|
||||||
field_4_last_column=colRelative.setBoolean(field_4_last_column,rel);
|
field_4_last_column=colRelative.setBoolean(field_4_last_column,rel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the last column in the area
|
* set the last column in the area
|
||||||
*/
|
*/
|
||||||
public final void setLastColumn(int colIx) {
|
public final void setLastColumn(int colIx) {
|
||||||
field_4_last_column=columnMask.setValue(field_4_last_column, colIx);
|
field_4_last_column=columnMask.setValue(field_4_last_column, colIx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the last column irrespective of the bitmasks
|
* set the last column irrespective of the bitmasks
|
||||||
*/
|
*/
|
||||||
public final void setLastColumnRaw(short column) {
|
public final void setLastColumnRaw(short column) {
|
||||||
field_4_last_column = column;
|
field_4_last_column = column;
|
||||||
}
|
}
|
||||||
protected final String formatReferenceAsString() {
|
protected final String formatReferenceAsString() {
|
||||||
CellReference topLeft = new CellReference(getFirstRow(),getFirstColumn(),!isFirstRowRelative(),!isFirstColRelative());
|
CellReference topLeft = new CellReference(getFirstRow(),getFirstColumn(),!isFirstRowRelative(),!isFirstColRelative());
|
||||||
CellReference botRight = new CellReference(getLastRow(),getLastColumn(),!isLastRowRelative(),!isLastColRelative());
|
CellReference botRight = new CellReference(getLastRow(),getLastColumn(),!isLastRowRelative(),!isLastColRelative());
|
||||||
|
|
||||||
if(AreaReference.isWholeColumnReference(SpreadsheetVersion.EXCEL97, topLeft, botRight)) {
|
if(AreaReference.isWholeColumnReference(SpreadsheetVersion.EXCEL97, topLeft, botRight)) {
|
||||||
return (new AreaReference(topLeft, botRight)).formatAsString();
|
return (new AreaReference(topLeft, botRight)).formatAsString();
|
||||||
}
|
}
|
||||||
return topLeft.formatAsString() + ":" + botRight.formatAsString();
|
return topLeft.formatAsString() + ":" + botRight.formatAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toFormulaString() {
|
public String toFormulaString() {
|
||||||
return formatReferenceAsString();
|
return formatReferenceAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getDefaultOperandClass() {
|
public byte getDefaultOperandClass() {
|
||||||
return Ptg.CLASS_REF;
|
return Ptg.CLASS_REF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ import org.apache.poi.xssf.usermodel.BaseXSSFEvaluationWorkbook;
|
|||||||
* SXSSF wrapper around the SXSSF and XSSF workbooks
|
* SXSSF wrapper around the SXSSF and XSSF workbooks
|
||||||
*/
|
*/
|
||||||
public final class SXSSFEvaluationWorkbook extends BaseXSSFEvaluationWorkbook {
|
public final class SXSSFEvaluationWorkbook extends BaseXSSFEvaluationWorkbook {
|
||||||
private SXSSFWorkbook _uBook;
|
private final SXSSFWorkbook _uBook;
|
||||||
|
|
||||||
public static SXSSFEvaluationWorkbook create(SXSSFWorkbook book) {
|
public static SXSSFEvaluationWorkbook create(SXSSFWorkbook book) {
|
||||||
if (book == null) {
|
if (book == null) {
|
||||||
@ -41,16 +41,19 @@ public final class SXSSFEvaluationWorkbook extends BaseXSSFEvaluationWorkbook {
|
|||||||
super(book.getXSSFWorkbook());
|
super(book.getXSSFWorkbook());
|
||||||
_uBook = book;
|
_uBook = book;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getSheetIndex(EvaluationSheet evalSheet) {
|
public int getSheetIndex(EvaluationSheet evalSheet) {
|
||||||
SXSSFSheet sheet = ((SXSSFEvaluationSheet)evalSheet).getSXSSFSheet();
|
SXSSFSheet sheet = ((SXSSFEvaluationSheet)evalSheet).getSXSSFSheet();
|
||||||
return _uBook.getSheetIndex(sheet);
|
return _uBook.getSheetIndex(sheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public EvaluationSheet getSheet(int sheetIndex) {
|
public EvaluationSheet getSheet(int sheetIndex) {
|
||||||
return new SXSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex));
|
return new SXSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Ptg[] getFormulaTokens(EvaluationCell evalCell) {
|
public Ptg[] getFormulaTokens(EvaluationCell evalCell) {
|
||||||
SXSSFCell cell = ((SXSSFEvaluationCell)evalCell).getSXSSFCell();
|
SXSSFCell cell = ((SXSSFEvaluationCell)evalCell).getSXSSFCell();
|
||||||
SXSSFEvaluationWorkbook frBook = SXSSFEvaluationWorkbook.create(_uBook);
|
SXSSFEvaluationWorkbook frBook = SXSSFEvaluationWorkbook.create(_uBook);
|
||||||
|
@ -17,7 +17,10 @@
|
|||||||
|
|
||||||
package org.apache.poi.xssf.usermodel;
|
package org.apache.poi.xssf.usermodel;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.poi.ss.SpreadsheetVersion;
|
import org.apache.poi.ss.SpreadsheetVersion;
|
||||||
import org.apache.poi.ss.formula.EvaluationName;
|
import org.apache.poi.ss.formula.EvaluationName;
|
||||||
@ -36,6 +39,8 @@ import org.apache.poi.ss.formula.ptg.Ptg;
|
|||||||
import org.apache.poi.ss.formula.ptg.Ref3DPxg;
|
import org.apache.poi.ss.formula.ptg.Ref3DPxg;
|
||||||
import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
|
import org.apache.poi.ss.formula.udf.IndexedUDFFinder;
|
||||||
import org.apache.poi.ss.formula.udf.UDFFinder;
|
import org.apache.poi.ss.formula.udf.UDFFinder;
|
||||||
|
import org.apache.poi.ss.usermodel.Table;
|
||||||
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.apache.poi.ss.util.AreaReference;
|
import org.apache.poi.ss.util.AreaReference;
|
||||||
import org.apache.poi.ss.util.CellReference;
|
import org.apache.poi.ss.util.CellReference;
|
||||||
import org.apache.poi.util.NotImplemented;
|
import org.apache.poi.util.NotImplemented;
|
||||||
@ -46,31 +51,31 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
|
|||||||
* Internal POI use only - parent of XSSF and SXSSF evaluation workbooks
|
* Internal POI use only - parent of XSSF and SXSSF evaluation workbooks
|
||||||
*/
|
*/
|
||||||
public abstract class BaseXSSFEvaluationWorkbook implements FormulaRenderingWorkbook, EvaluationWorkbook, FormulaParsingWorkbook {
|
public abstract class BaseXSSFEvaluationWorkbook implements FormulaRenderingWorkbook, EvaluationWorkbook, FormulaParsingWorkbook {
|
||||||
protected final XSSFWorkbook _uBook;
|
protected final XSSFWorkbook _uBook;
|
||||||
|
|
||||||
protected BaseXSSFEvaluationWorkbook(XSSFWorkbook book) {
|
protected BaseXSSFEvaluationWorkbook(XSSFWorkbook book) {
|
||||||
_uBook = book;
|
_uBook = book;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int convertFromExternalSheetIndex(int externSheetIndex) {
|
private int convertFromExternalSheetIndex(int externSheetIndex) {
|
||||||
return externSheetIndex;
|
return externSheetIndex;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* XSSF doesn't use external sheet indexes, so when asked treat
|
* XSSF doesn't use external sheet indexes, so when asked treat
|
||||||
* it just as a local index
|
* it just as a local index
|
||||||
*/
|
*/
|
||||||
public int convertFromExternSheetIndex(int externSheetIndex) {
|
public int convertFromExternSheetIndex(int externSheetIndex) {
|
||||||
return externSheetIndex;
|
return externSheetIndex;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @return the external sheet index of the sheet with the given internal
|
* @return the external sheet index of the sheet with the given internal
|
||||||
* index. Used by some of the more obscure formula and named range things.
|
* index. Used by some of the more obscure formula and named range things.
|
||||||
* Fairly easy on XSSF (we think...) since the internal and external
|
* Fairly easy on XSSF (we think...) since the internal and external
|
||||||
* indices are the same
|
* indices are the same
|
||||||
*/
|
*/
|
||||||
private int convertToExternalSheetIndex(int sheetIndex) {
|
private int convertToExternalSheetIndex(int sheetIndex) {
|
||||||
return sheetIndex;
|
return sheetIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getExternalSheetIndex(String sheetName) {
|
public int getExternalSheetIndex(String sheetName) {
|
||||||
int sheetIndex = _uBook.getSheetIndex(sheetName);
|
int sheetIndex = _uBook.getSheetIndex(sheetName);
|
||||||
@ -131,37 +136,37 @@ public abstract class BaseXSSFEvaluationWorkbook implements FormulaRenderingWork
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return EvaluationName wrapper around the matching XSSFName (named range)
|
* Return EvaluationName wrapper around the matching XSSFName (named range)
|
||||||
* @param name case-aware but case-insensitive named range in workbook
|
* @param name case-aware but case-insensitive named range in workbook
|
||||||
* @param sheetIndex index of sheet if named range scope is limited to one sheet
|
* @param sheetIndex index of sheet if named range scope is limited to one sheet
|
||||||
* if named range scope is global to the workbook, sheetIndex is -1.
|
* if named range scope is global to the workbook, sheetIndex is -1.
|
||||||
* @return If name is a named range in the workbook, returns
|
* @return If name is a named range in the workbook, returns
|
||||||
* EvaluationName corresponding to that named range
|
* EvaluationName corresponding to that named range
|
||||||
* Returns null if there is no named range with the same name and scope in the workbook
|
* Returns null if there is no named range with the same name and scope in the workbook
|
||||||
*/
|
*/
|
||||||
public EvaluationName getName(String name, int sheetIndex) {
|
public EvaluationName getName(String name, int sheetIndex) {
|
||||||
for (int i = 0; i < _uBook.getNumberOfNames(); i++) {
|
for (int i = 0; i < _uBook.getNumberOfNames(); i++) {
|
||||||
XSSFName nm = _uBook.getNameAt(i);
|
XSSFName nm = _uBook.getNameAt(i);
|
||||||
String nameText = nm.getNameName();
|
String nameText = nm.getNameName();
|
||||||
int nameSheetindex = nm.getSheetIndex();
|
int nameSheetindex = nm.getSheetIndex();
|
||||||
if (name.equalsIgnoreCase(nameText) &&
|
if (name.equalsIgnoreCase(nameText) &&
|
||||||
(nameSheetindex == -1 || nameSheetindex == sheetIndex)) {
|
(nameSheetindex == -1 || nameSheetindex == sheetIndex)) {
|
||||||
return new Name(nm, i, this);
|
return new Name(nm, i, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sheetIndex == -1 ? null : getName(name, -1);
|
return sheetIndex == -1 ? null : getName(name, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSheetName(int sheetIndex) {
|
public String getSheetName(int sheetIndex) {
|
||||||
return _uBook.getSheetName(sheetIndex);
|
return _uBook.getSheetName(sheetIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
|
public ExternalName getExternalName(int externSheetIndex, int externNameIndex) {
|
||||||
throw new IllegalStateException("HSSF-style external references are not supported for XSSF");
|
throw new IllegalStateException("HSSF-style external references are not supported for XSSF");
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExternalName getExternalName(String nameName, String sheetName, int externalWorkbookNumber) {
|
public ExternalName getExternalName(String nameName, String sheetName, int externalWorkbookNumber) {
|
||||||
if (externalWorkbookNumber > 0) {
|
if (externalWorkbookNumber > 0) {
|
||||||
// External reference - reference is 1 based, link table is 0 based
|
// External reference - reference is 1 based, link table is 0 based
|
||||||
int linkNumber = externalWorkbookNumber - 1;
|
int linkNumber = externalWorkbookNumber - 1;
|
||||||
@ -186,7 +191,7 @@ public abstract class BaseXSSFEvaluationWorkbook implements FormulaRenderingWork
|
|||||||
int nameIdx = _uBook.getNameIndex(nameName);
|
int nameIdx = _uBook.getNameIndex(nameName);
|
||||||
return new ExternalName(nameName, nameIdx, 0); // TODO Is this right?
|
return new ExternalName(nameName, nameIdx, 0); // TODO Is this right?
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -194,7 +199,7 @@ public abstract class BaseXSSFEvaluationWorkbook implements FormulaRenderingWork
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public NameXPxg getNameXPtg(String name, SheetIdentifier sheet) {
|
public NameXPxg getNameXPtg(String name, SheetIdentifier sheet) {
|
||||||
// First, try to find it as a User Defined Function
|
// First, try to find it as a User Defined Function
|
||||||
IndexedUDFFinder udfFinder = (IndexedUDFFinder)getUDFFinder();
|
IndexedUDFFinder udfFinder = (IndexedUDFFinder)getUDFFinder();
|
||||||
FreeRefFunction func = udfFinder.findFunction(name);
|
FreeRefFunction func = udfFinder.findFunction(name);
|
||||||
if (func != null) {
|
if (func != null) {
|
||||||
@ -223,7 +228,7 @@ public abstract class BaseXSSFEvaluationWorkbook implements FormulaRenderingWork
|
|||||||
} else {
|
} else {
|
||||||
return new NameXPxg(sheetName, name);
|
return new NameXPxg(sheetName, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Ptg get3DReferencePtg(CellReference cell, SheetIdentifier sheet) {
|
public Ptg get3DReferencePtg(CellReference cell, SheetIdentifier sheet) {
|
||||||
if (sheet._bookName != null) {
|
if (sheet._bookName != null) {
|
||||||
int bookIndex = resolveBookIndex(sheet._bookName);
|
int bookIndex = resolveBookIndex(sheet._bookName);
|
||||||
@ -259,102 +264,151 @@ public abstract class BaseXSSFEvaluationWorkbook implements FormulaRenderingWork
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExternalSheet getExternalSheet(int externSheetIndex) {
|
public ExternalSheet getExternalSheet(int externSheetIndex) {
|
||||||
throw new IllegalStateException("HSSF-style external references are not supported for XSSF");
|
throw new IllegalStateException("HSSF-style external references are not supported for XSSF");
|
||||||
}
|
}
|
||||||
public ExternalSheet getExternalSheet(String firstSheetName, String lastSheetName, int externalWorkbookNumber) {
|
public ExternalSheet getExternalSheet(String firstSheetName, String lastSheetName, int externalWorkbookNumber) {
|
||||||
String workbookName;
|
String workbookName;
|
||||||
if (externalWorkbookNumber > 0) {
|
if (externalWorkbookNumber > 0) {
|
||||||
// External reference - reference is 1 based, link table is 0 based
|
// External reference - reference is 1 based, link table is 0 based
|
||||||
int linkNumber = externalWorkbookNumber - 1;
|
int linkNumber = externalWorkbookNumber - 1;
|
||||||
ExternalLinksTable linkTable = _uBook.getExternalLinksTable().get(linkNumber);
|
ExternalLinksTable linkTable = _uBook.getExternalLinksTable().get(linkNumber);
|
||||||
workbookName = linkTable.getLinkedFileName();
|
workbookName = linkTable.getLinkedFileName();
|
||||||
} else {
|
} else {
|
||||||
// Internal reference
|
// Internal reference
|
||||||
workbookName = null;
|
workbookName = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastSheetName == null || firstSheetName.equals(lastSheetName)) {
|
if (lastSheetName == null || firstSheetName.equals(lastSheetName)) {
|
||||||
return new ExternalSheet(workbookName, firstSheetName);
|
return new ExternalSheet(workbookName, firstSheetName);
|
||||||
} else {
|
} else {
|
||||||
return new ExternalSheetRange(workbookName, firstSheetName, lastSheetName);
|
return new ExternalSheetRange(workbookName, firstSheetName, lastSheetName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotImplemented
|
@NotImplemented
|
||||||
public int getExternalSheetIndex(String workbookName, String sheetName) {
|
public int getExternalSheetIndex(String workbookName, String sheetName) {
|
||||||
throw new RuntimeException("not implemented yet");
|
throw new RuntimeException("not implemented yet");
|
||||||
}
|
}
|
||||||
public int getSheetIndex(String sheetName) {
|
public int getSheetIndex(String sheetName) {
|
||||||
return _uBook.getSheetIndex(sheetName);
|
return _uBook.getSheetIndex(sheetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSheetFirstNameByExternSheet(int externSheetIndex) {
|
public String getSheetFirstNameByExternSheet(int externSheetIndex) {
|
||||||
int sheetIndex = convertFromExternalSheetIndex(externSheetIndex);
|
int sheetIndex = convertFromExternalSheetIndex(externSheetIndex);
|
||||||
return _uBook.getSheetName(sheetIndex);
|
return _uBook.getSheetName(sheetIndex);
|
||||||
}
|
}
|
||||||
public String getSheetLastNameByExternSheet(int externSheetIndex) {
|
public String getSheetLastNameByExternSheet(int externSheetIndex) {
|
||||||
// XSSF does multi-sheet references differently, so this is the same as the first
|
// XSSF does multi-sheet references differently, so this is the same as the first
|
||||||
return getSheetFirstNameByExternSheet(externSheetIndex);
|
return getSheetFirstNameByExternSheet(externSheetIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNameText(NamePtg namePtg) {
|
public String getNameText(NamePtg namePtg) {
|
||||||
return _uBook.getNameAt(namePtg.getIndex()).getNameName();
|
return _uBook.getNameAt(namePtg.getIndex()).getNameName();
|
||||||
}
|
}
|
||||||
public EvaluationName getName(NamePtg namePtg) {
|
public EvaluationName getName(NamePtg namePtg) {
|
||||||
int ix = namePtg.getIndex();
|
int ix = namePtg.getIndex();
|
||||||
return new Name(_uBook.getNameAt(ix), ix, this);
|
return new Name(_uBook.getNameAt(ix), ix, this);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public XSSFName createName() {
|
public XSSFName createName() {
|
||||||
return _uBook.createName();
|
return _uBook.createName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String caseInsensitive(String s) {
|
||||||
|
return s.toUpperCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: data tables are stored at the workbook level in XSSF, but are bound to a single sheet.
|
||||||
|
* The current code structure has them hanging off XSSFSheet, but formulas reference them
|
||||||
|
* only by name (names are global, and case insensitive).
|
||||||
|
* This map stores names as lower case for case-insensitive lookups.
|
||||||
|
*
|
||||||
|
* FIXME: Caching tables by name here for fast formula lookup means the map is out of date if
|
||||||
|
* a table is renamed or added/removed to a sheet after the map is created.
|
||||||
|
*
|
||||||
|
* Perhaps tables can be managed similar to PivotTable references above?
|
||||||
|
*/
|
||||||
|
private Map<String, XSSFTable> _tableCache = null;
|
||||||
|
private Map<String, XSSFTable> getTableCache() {
|
||||||
|
if ( _tableCache != null ) {
|
||||||
|
return _tableCache;
|
||||||
|
}
|
||||||
|
// FIXME: use org.apache.commons.collections.map.CaseInsensitiveMap
|
||||||
|
_tableCache = new HashMap<String, XSSFTable>();
|
||||||
|
|
||||||
|
for (Sheet sheet : _uBook) {
|
||||||
|
for (XSSFTable tbl : ((XSSFSheet)sheet).getTables()) {
|
||||||
|
String lname = caseInsensitive(tbl.getName());
|
||||||
|
_tableCache.put(lname, tbl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _tableCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the data table with the given name (case insensitive).
|
||||||
|
* Tables are cached for performance (formula evaluation looks them up by name repeatedly).
|
||||||
|
* After the first table lookup, adding or removing a table from the document structure will cause trouble.
|
||||||
|
* This is meant to be used on documents whose structure is essentially static at the point formulas are evaluated.
|
||||||
|
*
|
||||||
|
* @param name the data table name (case-insensitive)
|
||||||
|
* @return The Data table in the workbook named <tt>name</tt>, or <tt>null</tt> if no table is named <tt>name</tt>.
|
||||||
|
* @since 3.15 beta 2
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public XSSFTable getTable(String name) {
|
||||||
|
if (name == null) return null;
|
||||||
|
String lname = caseInsensitive(name);
|
||||||
|
return getTableCache().get(lname);
|
||||||
|
}
|
||||||
|
|
||||||
public UDFFinder getUDFFinder(){
|
public UDFFinder getUDFFinder(){
|
||||||
return _uBook.getUDFFinder();
|
return _uBook.getUDFFinder();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class Name implements EvaluationName {
|
private static final class Name implements EvaluationName {
|
||||||
|
|
||||||
private final XSSFName _nameRecord;
|
private final XSSFName _nameRecord;
|
||||||
private final int _index;
|
private final int _index;
|
||||||
private final FormulaParsingWorkbook _fpBook;
|
private final FormulaParsingWorkbook _fpBook;
|
||||||
|
|
||||||
public Name(XSSFName name, int index, FormulaParsingWorkbook fpBook) {
|
public Name(XSSFName name, int index, FormulaParsingWorkbook fpBook) {
|
||||||
_nameRecord = name;
|
_nameRecord = name;
|
||||||
_index = index;
|
_index = index;
|
||||||
_fpBook = fpBook;
|
_fpBook = fpBook;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Ptg[] getNameDefinition() {
|
public Ptg[] getNameDefinition() {
|
||||||
|
|
||||||
return FormulaParser.parse(_nameRecord.getRefersToFormula(), _fpBook, FormulaType.NAMEDRANGE, _nameRecord.getSheetIndex());
|
return FormulaParser.parse(_nameRecord.getRefersToFormula(), _fpBook, FormulaType.NAMEDRANGE, _nameRecord.getSheetIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNameText() {
|
public String getNameText() {
|
||||||
return _nameRecord.getNameName();
|
return _nameRecord.getNameName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasFormula() {
|
public boolean hasFormula() {
|
||||||
// TODO - no idea if this is right
|
// TODO - no idea if this is right
|
||||||
CTDefinedName ctn = _nameRecord.getCTName();
|
CTDefinedName ctn = _nameRecord.getCTName();
|
||||||
String strVal = ctn.getStringValue();
|
String strVal = ctn.getStringValue();
|
||||||
return !ctn.getFunction() && strVal != null && strVal.length() > 0;
|
return !ctn.getFunction() && strVal != null && strVal.length() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFunctionName() {
|
public boolean isFunctionName() {
|
||||||
return _nameRecord.isFunctionName();
|
return _nameRecord.isFunctionName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRange() {
|
public boolean isRange() {
|
||||||
return hasFormula(); // TODO - is this right?
|
return hasFormula(); // TODO - is this right?
|
||||||
}
|
}
|
||||||
public NamePtg createPtg() {
|
public NamePtg createPtg() {
|
||||||
return new NamePtg(_index);
|
return new NamePtg(_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpreadsheetVersion getSpreadsheetVersion(){
|
public SpreadsheetVersion getSpreadsheetVersion(){
|
||||||
return SpreadsheetVersion.EXCEL2007;
|
return SpreadsheetVersion.EXCEL2007;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -406,9 +406,9 @@ public final class XSSFCell implements Cell {
|
|||||||
if (cachedValueType != expectedTypeCode) {
|
if (cachedValueType != expectedTypeCode) {
|
||||||
throw typeMismatch(expectedTypeCode, cachedValueType, true);
|
throw typeMismatch(expectedTypeCode, cachedValueType, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a string value for the cell.
|
* Set a string value for the cell.
|
||||||
*
|
*
|
||||||
* @param str value to set the cell to. For formulas we'll set the formula
|
* @param str value to set the cell to. For formulas we'll set the formula
|
||||||
@ -506,7 +506,7 @@ public final class XSSFCell implements Cell {
|
|||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(sheet.getWorkbook());
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(sheet.getWorkbook());
|
||||||
SharedFormula sf = new SharedFormula(SpreadsheetVersion.EXCEL2007);
|
SharedFormula sf = new SharedFormula(SpreadsheetVersion.EXCEL2007);
|
||||||
|
|
||||||
Ptg[] ptgs = FormulaParser.parse(sharedFormula, fpb, FormulaType.CELL, sheetIndex);
|
Ptg[] ptgs = FormulaParser.parse(sharedFormula, fpb, FormulaType.CELL, sheetIndex, getRowIndex());
|
||||||
Ptg[] fmla = sf.convertSharedFormulas(ptgs,
|
Ptg[] fmla = sf.convertSharedFormulas(ptgs,
|
||||||
getRowIndex() - ref.getFirstRow(), getColumnIndex() - ref.getFirstColumn());
|
getRowIndex() - ref.getFirstRow(), getColumnIndex() - ref.getFirstColumn());
|
||||||
return FormulaRenderer.toFormulaString(fpb, fmla);
|
return FormulaRenderer.toFormulaString(fpb, fmla);
|
||||||
@ -550,7 +550,7 @@ public final class XSSFCell implements Cell {
|
|||||||
|
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
//validate through the FormulaParser
|
//validate through the FormulaParser
|
||||||
FormulaParser.parse(formula, fpb, formulaType, wb.getSheetIndex(getSheet()));
|
FormulaParser.parse(formula, fpb, formulaType, wb.getSheetIndex(getSheet()), getRowIndex());
|
||||||
|
|
||||||
CTCellFormula f = CTCellFormula.Factory.newInstance();
|
CTCellFormula f = CTCellFormula.Factory.newInstance();
|
||||||
f.setStringValue(formula);
|
f.setStringValue(formula);
|
||||||
@ -925,8 +925,8 @@ public final class XSSFCell implements Cell {
|
|||||||
throw new IllegalArgumentException("Illegal cell type: " + cellType);
|
throw new IllegalArgumentException("Illegal cell type: " + cellType);
|
||||||
}
|
}
|
||||||
if (cellType != CELL_TYPE_FORMULA && _cell.isSetF()) {
|
if (cellType != CELL_TYPE_FORMULA && _cell.isSetF()) {
|
||||||
_cell.unsetF();
|
_cell.unsetF();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,29 +27,32 @@ import org.apache.poi.ss.formula.ptg.Ptg;
|
|||||||
* Internal POI use only
|
* Internal POI use only
|
||||||
*/
|
*/
|
||||||
public final class XSSFEvaluationWorkbook extends BaseXSSFEvaluationWorkbook {
|
public final class XSSFEvaluationWorkbook extends BaseXSSFEvaluationWorkbook {
|
||||||
public static XSSFEvaluationWorkbook create(XSSFWorkbook book) {
|
public static XSSFEvaluationWorkbook create(XSSFWorkbook book) {
|
||||||
if (book == null) {
|
if (book == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new XSSFEvaluationWorkbook(book);
|
return new XSSFEvaluationWorkbook(book);
|
||||||
}
|
}
|
||||||
|
|
||||||
private XSSFEvaluationWorkbook(XSSFWorkbook book) {
|
private XSSFEvaluationWorkbook(XSSFWorkbook book) {
|
||||||
super(book);
|
super(book);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSheetIndex(EvaluationSheet evalSheet) {
|
@Override
|
||||||
XSSFSheet sheet = ((XSSFEvaluationSheet)evalSheet).getXSSFSheet();
|
public int getSheetIndex(EvaluationSheet evalSheet) {
|
||||||
return _uBook.getSheetIndex(sheet);
|
XSSFSheet sheet = ((XSSFEvaluationSheet)evalSheet).getXSSFSheet();
|
||||||
}
|
return _uBook.getSheetIndex(sheet);
|
||||||
|
}
|
||||||
|
|
||||||
public EvaluationSheet getSheet(int sheetIndex) {
|
@Override
|
||||||
return new XSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex));
|
public EvaluationSheet getSheet(int sheetIndex) {
|
||||||
}
|
return new XSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Ptg[] getFormulaTokens(EvaluationCell evalCell) {
|
public Ptg[] getFormulaTokens(EvaluationCell evalCell) {
|
||||||
XSSFCell cell = ((XSSFEvaluationCell)evalCell).getXSSFCell();
|
XSSFCell cell = ((XSSFEvaluationCell)evalCell).getXSSFCell();
|
||||||
XSSFEvaluationWorkbook frBook = XSSFEvaluationWorkbook.create(_uBook);
|
XSSFEvaluationWorkbook frBook = XSSFEvaluationWorkbook.create(_uBook);
|
||||||
return FormulaParser.parse(cell.getCellFormula(), frBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet()));
|
return FormulaParser.parse(cell.getCellFormula(), frBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet()), cell.getRowIndex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,7 +192,7 @@ public final class XSSFName implements Name {
|
|||||||
public void setRefersToFormula(String formulaText) {
|
public void setRefersToFormula(String formulaText) {
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(_workbook);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(_workbook);
|
||||||
//validate through the FormulaParser
|
//validate through the FormulaParser
|
||||||
FormulaParser.parse(formulaText, fpb, FormulaType.NAMEDRANGE, getSheetIndex());
|
FormulaParser.parse(formulaText, fpb, FormulaType.NAMEDRANGE, getSheetIndex(), -1);
|
||||||
|
|
||||||
_ctName.setStringValue(formulaText);
|
_ctName.setStringValue(formulaText);
|
||||||
}
|
}
|
||||||
@ -203,7 +203,7 @@ public final class XSSFName implements Name {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(_workbook);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(_workbook);
|
||||||
Ptg[] ptgs = FormulaParser.parse(formulaText, fpb, FormulaType.NAMEDRANGE, getSheetIndex());
|
Ptg[] ptgs = FormulaParser.parse(formulaText, fpb, FormulaType.NAMEDRANGE, getSheetIndex(), -1);
|
||||||
return Ptg.doesFormulaReferToDeletedCell(ptgs);
|
return Ptg.doesFormulaReferToDeletedCell(ptgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,13 +24,17 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.apache.poi.POIXMLDocumentPart;
|
import org.apache.poi.POIXMLDocumentPart;
|
||||||
import org.apache.poi.openxml4j.opc.PackagePart;
|
import org.apache.poi.openxml4j.opc.PackagePart;
|
||||||
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
||||||
|
import org.apache.poi.ss.usermodel.Table;
|
||||||
import org.apache.poi.ss.util.CellReference;
|
import org.apache.poi.ss.util.CellReference;
|
||||||
import org.apache.poi.xssf.usermodel.helpers.XSSFXmlColumnPr;
|
import org.apache.poi.xssf.usermodel.helpers.XSSFXmlColumnPr;
|
||||||
|
import org.apache.poi.util.StringUtil;
|
||||||
import org.apache.xmlbeans.XmlException;
|
import org.apache.xmlbeans.XmlException;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTable;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTable;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn;
|
||||||
@ -48,10 +52,12 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.TableDocument;
|
|||||||
*
|
*
|
||||||
* @author Roberto Manicardi
|
* @author Roberto Manicardi
|
||||||
*/
|
*/
|
||||||
public class XSSFTable extends POIXMLDocumentPart {
|
public class XSSFTable extends POIXMLDocumentPart implements Table {
|
||||||
|
|
||||||
private CTTable ctTable;
|
private CTTable ctTable;
|
||||||
private List<XSSFXmlColumnPr> xmlColumnPr;
|
private List<XSSFXmlColumnPr> xmlColumnPr;
|
||||||
|
private CTTableColumn[] ctColumns;
|
||||||
|
private HashMap<String, Integer> columnMap;
|
||||||
private CellReference startCellReference;
|
private CellReference startCellReference;
|
||||||
private CellReference endCellReference;
|
private CellReference endCellReference;
|
||||||
private String commonXPath;
|
private String commonXPath;
|
||||||
@ -107,7 +113,7 @@ public class XSSFTable extends POIXMLDocumentPart {
|
|||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CTTable getCTTable(){
|
public CTTable getCTTable() {
|
||||||
return ctTable;
|
return ctTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,32 +123,41 @@ public class XSSFTable extends POIXMLDocumentPart {
|
|||||||
* @return true if the Table element contain mappings
|
* @return true if the Table element contain mappings
|
||||||
*/
|
*/
|
||||||
public boolean mapsTo(long id){
|
public boolean mapsTo(long id){
|
||||||
boolean maps =false;
|
|
||||||
|
|
||||||
List<XSSFXmlColumnPr> pointers = getXmlColumnPrs();
|
List<XSSFXmlColumnPr> pointers = getXmlColumnPrs();
|
||||||
|
|
||||||
for (XSSFXmlColumnPr pointer: pointers) {
|
for (XSSFXmlColumnPr pointer: pointers) {
|
||||||
if (pointer.getMapId()==id) {
|
if (pointer.getMapId()==id) {
|
||||||
maps=true;
|
return true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return maps;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* caches table columns for performance.
|
||||||
|
* Updated via updateHeaders
|
||||||
|
* @since 3.15 beta 2
|
||||||
|
*/
|
||||||
|
private CTTableColumn[] getTableColumns() {
|
||||||
|
if (ctColumns == null) {
|
||||||
|
ctColumns = ctTable.getTableColumns().getTableColumnArray();
|
||||||
|
}
|
||||||
|
return ctColumns;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Calculates the xpath of the root element for the table. This will be the common part
|
* Calculates the xpath of the root element for the table. This will be the common part
|
||||||
* of all the mapping's xpaths
|
* of all the mapping's xpaths
|
||||||
|
* Note: this function caches the result for performance. To flush the cache {@link #updateHeaders()} must be called.
|
||||||
*
|
*
|
||||||
* @return the xpath of the table's root element
|
* @return the xpath of the table's root element
|
||||||
*/
|
*/
|
||||||
public String getCommonXpath() {
|
public String getCommonXpath() {
|
||||||
if (commonXPath == null) {
|
if (commonXPath == null) {
|
||||||
String[] commonTokens = {};
|
String[] commonTokens = {};
|
||||||
for (CTTableColumn column :ctTable.getTableColumns().getTableColumnArray()) {
|
for (CTTableColumn column : getTableColumns()) {
|
||||||
if (column.getXmlColumnPr()!=null) {
|
if (column.getXmlColumnPr()!=null) {
|
||||||
String xpath = column.getXmlColumnPr().getXpath();
|
String xpath = column.getXmlColumnPr().getXpath();
|
||||||
String[] tokens = xpath.split("/");
|
String[] tokens = xpath.split("/");
|
||||||
@ -166,21 +181,24 @@ public class XSSFTable extends POIXMLDocumentPart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commonXPath = "";
|
commonTokens[0] = "";
|
||||||
for (int i = 1 ; i< commonTokens.length;i++) {
|
commonXPath = StringUtil.join(commonTokens, "/");
|
||||||
commonXPath +="/"+commonTokens[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return commonXPath;
|
return commonXPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note this list is static - once read, it does not notice later changes to the underlying column structures
|
||||||
|
* To clear the cache, call {@link #updateHeaders}
|
||||||
|
* @return List of XSSFXmlColumnPr
|
||||||
|
*/
|
||||||
public List<XSSFXmlColumnPr> getXmlColumnPrs() {
|
public List<XSSFXmlColumnPr> getXmlColumnPrs() {
|
||||||
|
|
||||||
if (xmlColumnPr==null) {
|
if (xmlColumnPr==null) {
|
||||||
xmlColumnPr = new ArrayList<XSSFXmlColumnPr>();
|
xmlColumnPr = new ArrayList<XSSFXmlColumnPr>();
|
||||||
for (CTTableColumn column:ctTable.getTableColumns().getTableColumnArray()) {
|
for (CTTableColumn column: getTableColumns()) {
|
||||||
if (column.getXmlColumnPr()!=null) {
|
if (column.getXmlColumnPr()!=null) {
|
||||||
XSSFXmlColumnPr columnPr = new XSSFXmlColumnPr(this,column,column.getXmlColumnPr());
|
XSSFXmlColumnPr columnPr = new XSSFXmlColumnPr(this,column,column.getXmlColumnPr());
|
||||||
xmlColumnPr.add(columnPr);
|
xmlColumnPr.add(columnPr);
|
||||||
@ -283,7 +301,7 @@ public class XSSFTable extends POIXMLDocumentPart {
|
|||||||
* Headers <em>must</em> be in sync, otherwise Excel will display a
|
* Headers <em>must</em> be in sync, otherwise Excel will display a
|
||||||
* "Found unreadable content" message on startup.
|
* "Found unreadable content" message on startup.
|
||||||
*/
|
*/
|
||||||
public void updateHeaders(){
|
public void updateHeaders() {
|
||||||
XSSFSheet sheet = (XSSFSheet)getParent();
|
XSSFSheet sheet = (XSSFSheet)getParent();
|
||||||
CellReference ref = getStartCellReference();
|
CellReference ref = getStartCellReference();
|
||||||
if(ref == null) return;
|
if(ref == null) return;
|
||||||
@ -301,6 +319,83 @@ public class XSSFTable extends POIXMLDocumentPart {
|
|||||||
}
|
}
|
||||||
cellnum++;
|
cellnum++;
|
||||||
}
|
}
|
||||||
|
ctColumns = null;
|
||||||
|
columnMap = null;
|
||||||
|
xmlColumnPr = null;
|
||||||
|
commonXPath = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String caseInsensitive(String s) {
|
||||||
|
return s.toUpperCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the relative column index of a column in this table having the header name <code>column</code>.
|
||||||
|
* The column index is relative to the left-most column in the table, 0-indexed.
|
||||||
|
* Returns <code>-1</code> if <code>column</code> is not a header name in table.
|
||||||
|
*
|
||||||
|
* Note: this function caches column names for performance. To flush the cache (because columns
|
||||||
|
* have been moved or column headers have been changed), {@link #updateHeaders()} must be called.
|
||||||
|
*
|
||||||
|
* @since 3.15 beta 2
|
||||||
|
*/
|
||||||
|
public int findColumnIndex(String column) {
|
||||||
|
if (columnMap == null) {
|
||||||
|
// FIXME: replace with org.apache.commons.collections.map.CaseInsensitiveMap
|
||||||
|
int count = getTableColumns().length;
|
||||||
|
columnMap = new HashMap<String, Integer>(count);
|
||||||
|
|
||||||
|
for (int i=0; i < count; i++) {
|
||||||
|
String columnName = getTableColumns()[i].getName();
|
||||||
|
columnMap.put(caseInsensitive(columnName), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Table column names with special characters need a single quote escape
|
||||||
|
// but the escape is not present in the column definition
|
||||||
|
Integer idx = columnMap.get(caseInsensitive(column.replace("'", "")));
|
||||||
|
return idx == null ? -1 : idx.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.15 beta 2
|
||||||
|
*/
|
||||||
|
public String getSheetName() {
|
||||||
|
return getXSSFSheet().getSheetName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.15 beta 2
|
||||||
|
*/
|
||||||
|
public boolean isHasTotalsRow() {
|
||||||
|
return ctTable.getTotalsRowShown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.15 beta 2
|
||||||
|
*/
|
||||||
|
public int getStartColIndex() {
|
||||||
|
return getStartCellReference().getCol();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.15 beta 2
|
||||||
|
*/
|
||||||
|
public int getStartRowIndex() {
|
||||||
|
return getStartCellReference().getRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.15 beta 2
|
||||||
|
*/
|
||||||
|
public int getEndColIndex() {
|
||||||
|
return getEndCellReference().getCol();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.15 beta 2
|
||||||
|
*/
|
||||||
|
public int getEndRowIndex() {
|
||||||
|
return getEndCellReference().getRow();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import java.util.HashMap;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -1761,7 +1762,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
* Get the document's embedded files.
|
* Get the document's embedded files.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<PackagePart> getAllEmbedds() throws OpenXML4JException {
|
public List<PackagePart> getAllEmbedds() throws OpenXML4JException {
|
||||||
List<PackagePart> embedds = new LinkedList<PackagePart>();
|
List<PackagePart> embedds = new LinkedList<PackagePart>();
|
||||||
|
|
||||||
for(XSSFSheet sheet : sheets){
|
for(XSSFSheet sheet : sheets){
|
||||||
@ -1928,7 +1929,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
*/
|
*/
|
||||||
@Internal
|
@Internal
|
||||||
public MapInfo getMapInfo(){
|
public MapInfo getMapInfo(){
|
||||||
return mapInfo;
|
return mapInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1945,92 +1946,92 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
throw new RuntimeException("Not Implemented - see bug #57184");
|
throw new RuntimeException("Not Implemented - see bug #57184");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies a boolean value that indicates whether structure of workbook is locked. <br/>
|
* Specifies a boolean value that indicates whether structure of workbook is locked. <br/>
|
||||||
* A value true indicates the structure of the workbook is locked. Worksheets in the workbook can't be moved,
|
* A value true indicates the structure of the workbook is locked. Worksheets in the workbook can't be moved,
|
||||||
* deleted, hidden, unhidden, or renamed, and new worksheets can't be inserted.<br/>
|
* deleted, hidden, unhidden, or renamed, and new worksheets can't be inserted.<br/>
|
||||||
* A value of false indicates the structure of the workbook is not locked.<br/>
|
* A value of false indicates the structure of the workbook is not locked.<br/>
|
||||||
*
|
*
|
||||||
* @return true if structure of workbook is locked
|
* @return true if structure of workbook is locked
|
||||||
*/
|
*/
|
||||||
public boolean isStructureLocked() {
|
public boolean isStructureLocked() {
|
||||||
return workbookProtectionPresent() && workbook.getWorkbookProtection().getLockStructure();
|
return workbookProtectionPresent() && workbook.getWorkbookProtection().getLockStructure();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies a boolean value that indicates whether the windows that comprise the workbook are locked. <br/>
|
* Specifies a boolean value that indicates whether the windows that comprise the workbook are locked. <br/>
|
||||||
* A value of true indicates the workbook windows are locked. Windows are the same size and position each time the
|
* A value of true indicates the workbook windows are locked. Windows are the same size and position each time the
|
||||||
* workbook is opened.<br/>
|
* workbook is opened.<br/>
|
||||||
* A value of false indicates the workbook windows are not locked.
|
* A value of false indicates the workbook windows are not locked.
|
||||||
*
|
*
|
||||||
* @return true if windows that comprise the workbook are locked
|
* @return true if windows that comprise the workbook are locked
|
||||||
*/
|
*/
|
||||||
public boolean isWindowsLocked() {
|
public boolean isWindowsLocked() {
|
||||||
return workbookProtectionPresent() && workbook.getWorkbookProtection().getLockWindows();
|
return workbookProtectionPresent() && workbook.getWorkbookProtection().getLockWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies a boolean value that indicates whether the workbook is locked for revisions.
|
* Specifies a boolean value that indicates whether the workbook is locked for revisions.
|
||||||
*
|
*
|
||||||
* @return true if the workbook is locked for revisions.
|
* @return true if the workbook is locked for revisions.
|
||||||
*/
|
*/
|
||||||
public boolean isRevisionLocked() {
|
public boolean isRevisionLocked() {
|
||||||
return workbookProtectionPresent() && workbook.getWorkbookProtection().getLockRevision();
|
return workbookProtectionPresent() && workbook.getWorkbookProtection().getLockRevision();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locks the structure of workbook.
|
* Locks the structure of workbook.
|
||||||
*/
|
*/
|
||||||
public void lockStructure() {
|
public void lockStructure() {
|
||||||
safeGetWorkbookProtection().setLockStructure(true);
|
safeGetWorkbookProtection().setLockStructure(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unlocks the structure of workbook.
|
* Unlocks the structure of workbook.
|
||||||
*/
|
*/
|
||||||
public void unLockStructure() {
|
public void unLockStructure() {
|
||||||
safeGetWorkbookProtection().setLockStructure(false);
|
safeGetWorkbookProtection().setLockStructure(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locks the windows that comprise the workbook.
|
* Locks the windows that comprise the workbook.
|
||||||
*/
|
*/
|
||||||
public void lockWindows() {
|
public void lockWindows() {
|
||||||
safeGetWorkbookProtection().setLockWindows(true);
|
safeGetWorkbookProtection().setLockWindows(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unlocks the windows that comprise the workbook.
|
* Unlocks the windows that comprise the workbook.
|
||||||
*/
|
*/
|
||||||
public void unLockWindows() {
|
public void unLockWindows() {
|
||||||
safeGetWorkbookProtection().setLockWindows(false);
|
safeGetWorkbookProtection().setLockWindows(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locks the workbook for revisions.
|
* Locks the workbook for revisions.
|
||||||
*/
|
*/
|
||||||
public void lockRevision() {
|
public void lockRevision() {
|
||||||
safeGetWorkbookProtection().setLockRevision(true);
|
safeGetWorkbookProtection().setLockRevision(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unlocks the workbook for revisions.
|
* Unlocks the workbook for revisions.
|
||||||
*/
|
*/
|
||||||
public void unLockRevision() {
|
public void unLockRevision() {
|
||||||
safeGetWorkbookProtection().setLockRevision(false);
|
safeGetWorkbookProtection().setLockRevision(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the workbook password.
|
* Sets the workbook password.
|
||||||
*
|
*
|
||||||
* @param password if null, the password will be removed
|
* @param password if null, the password will be removed
|
||||||
* @param hashAlgo if null, the password will be set as XOR password (Excel 2010 and earlier)
|
* @param hashAlgo if null, the password will be set as XOR password (Excel 2010 and earlier)
|
||||||
* otherwise the given algorithm is used for calculating the hash password (Excel 2013)
|
* otherwise the given algorithm is used for calculating the hash password (Excel 2013)
|
||||||
*/
|
*/
|
||||||
public void setWorkbookPassword(String password, HashAlgorithm hashAlgo) {
|
public void setWorkbookPassword(String password, HashAlgorithm hashAlgo) {
|
||||||
if (password == null && !workbookProtectionPresent()) return;
|
if (password == null && !workbookProtectionPresent()) return;
|
||||||
setPassword(safeGetWorkbookProtection(), password, hashAlgo, "workbook");
|
setPassword(safeGetWorkbookProtection(), password, hashAlgo, "workbook");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the password against the stored hash, the hashing method will be determined
|
* Validate the password against the stored hash, the hashing method will be determined
|
||||||
@ -2073,9 +2074,9 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean workbookProtectionPresent() {
|
private boolean workbookProtectionPresent() {
|
||||||
return workbook.isSetWorkbookProtection();
|
return workbook.isSetWorkbookProtection();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CTWorkbookProtection safeGetWorkbookProtection() {
|
private CTWorkbookProtection safeGetWorkbookProtection() {
|
||||||
if (!workbookProtectionPresent()){
|
if (!workbookProtectionPresent()){
|
||||||
@ -2083,7 +2084,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
}
|
}
|
||||||
return workbook.getWorkbookProtection();
|
return workbook.getWorkbookProtection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Returns the locator of user-defined functions.
|
* Returns the locator of user-defined functions.
|
||||||
@ -2261,4 +2262,24 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
|
|||||||
public SpreadsheetVersion getSpreadsheetVersion() {
|
public SpreadsheetVersion getSpreadsheetVersion() {
|
||||||
return SpreadsheetVersion.EXCEL2007;
|
return SpreadsheetVersion.EXCEL2007;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the data table with the given name (case insensitive).
|
||||||
|
*
|
||||||
|
* @param name the data table name (case-insensitive)
|
||||||
|
* @return The Data table in the workbook named <tt>name</tt>, or <tt>null</tt> if no table is named <tt>name</tt>.
|
||||||
|
* @since 3.15 beta 2
|
||||||
|
*/
|
||||||
|
public XSSFTable getTable(String name) {
|
||||||
|
if (name != null && sheets != null) {
|
||||||
|
for (XSSFSheet sheet : sheets) {
|
||||||
|
for (XSSFTable tbl : sheet.getTables()) {
|
||||||
|
if (name.equalsIgnoreCase(tbl.getName())) {
|
||||||
|
return tbl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ public final class XSSFFormulaUtils {
|
|||||||
String formula = f.getStringValue();
|
String formula = f.getStringValue();
|
||||||
if (formula != null && formula.length() > 0) {
|
if (formula != null && formula.length() > 0) {
|
||||||
int sheetIndex = _wb.getSheetIndex(cell.getSheet());
|
int sheetIndex = _wb.getSheetIndex(cell.getSheet());
|
||||||
Ptg[] ptgs = FormulaParser.parse(formula, _fpwb, FormulaType.CELL, sheetIndex);
|
Ptg[] ptgs = FormulaParser.parse(formula, _fpwb, FormulaType.CELL, sheetIndex, cell.getRowIndex());
|
||||||
for (Ptg ptg : ptgs) {
|
for (Ptg ptg : ptgs) {
|
||||||
updatePtg(ptg, oldName, newName);
|
updatePtg(ptg, oldName, newName);
|
||||||
}
|
}
|
||||||
@ -113,7 +113,8 @@ public final class XSSFFormulaUtils {
|
|||||||
String formula = name.getRefersToFormula();
|
String formula = name.getRefersToFormula();
|
||||||
if (formula != null) {
|
if (formula != null) {
|
||||||
int sheetIndex = name.getSheetIndex();
|
int sheetIndex = name.getSheetIndex();
|
||||||
Ptg[] ptgs = FormulaParser.parse(formula, _fpwb, FormulaType.NAMEDRANGE, sheetIndex);
|
int rowIndex = -1; //don't care
|
||||||
|
Ptg[] ptgs = FormulaParser.parse(formula, _fpwb, FormulaType.NAMEDRANGE, sheetIndex, rowIndex);
|
||||||
for (Ptg ptg : ptgs) {
|
for (Ptg ptg : ptgs) {
|
||||||
updatePtg(ptg, oldName, newName);
|
updatePtg(ptg, oldName, newName);
|
||||||
}
|
}
|
||||||
|
@ -134,8 +134,9 @@ public final class XSSFRowShifter {
|
|||||||
XSSFName name = wb.getNameAt(i);
|
XSSFName name = wb.getNameAt(i);
|
||||||
String formula = name.getRefersToFormula();
|
String formula = name.getRefersToFormula();
|
||||||
int sheetIndex = name.getSheetIndex();
|
int sheetIndex = name.getSheetIndex();
|
||||||
|
final int rowIndex = -1; //don't care, named ranges are not allowed to include structured references
|
||||||
|
|
||||||
Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.NAMEDRANGE, sheetIndex);
|
Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.NAMEDRANGE, sheetIndex, rowIndex);
|
||||||
if (shifter.adjustFormula(ptgs, sheetIndex)) {
|
if (shifter.adjustFormula(ptgs, sheetIndex)) {
|
||||||
String shiftedFmla = FormulaRenderer.toFormulaString(fpb, ptgs);
|
String shiftedFmla = FormulaRenderer.toFormulaString(fpb, ptgs);
|
||||||
name.setRefersToFormula(shiftedFmla);
|
name.setRefersToFormula(shiftedFmla);
|
||||||
@ -218,10 +219,11 @@ public final class XSSFRowShifter {
|
|||||||
XSSFSheet sheet = row.getSheet();
|
XSSFSheet sheet = row.getSheet();
|
||||||
XSSFWorkbook wb = sheet.getWorkbook();
|
XSSFWorkbook wb = sheet.getWorkbook();
|
||||||
int sheetIndex = wb.getSheetIndex(sheet);
|
int sheetIndex = wb.getSheetIndex(sheet);
|
||||||
|
final int rowIndex = row.getRowNum();
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL, sheetIndex);
|
Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL, sheetIndex, rowIndex);
|
||||||
String shiftedFmla = null;
|
String shiftedFmla = null;
|
||||||
if (shifter.adjustFormula(ptgs, sheetIndex)) {
|
if (shifter.adjustFormula(ptgs, sheetIndex)) {
|
||||||
shiftedFmla = FormulaRenderer.toFormulaString(fpb, ptgs);
|
shiftedFmla = FormulaRenderer.toFormulaString(fpb, ptgs);
|
||||||
@ -238,6 +240,7 @@ public final class XSSFRowShifter {
|
|||||||
public void updateConditionalFormatting(FormulaShifter shifter) {
|
public void updateConditionalFormatting(FormulaShifter shifter) {
|
||||||
XSSFWorkbook wb = sheet.getWorkbook();
|
XSSFWorkbook wb = sheet.getWorkbook();
|
||||||
int sheetIndex = wb.getSheetIndex(sheet);
|
int sheetIndex = wb.getSheetIndex(sheet);
|
||||||
|
final int rowIndex = -1; //don't care, structured references not allowed in conditional formatting
|
||||||
|
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
CTWorksheet ctWorksheet = sheet.getCTWorksheet();
|
CTWorksheet ctWorksheet = sheet.getCTWorksheet();
|
||||||
@ -283,7 +286,7 @@ public final class XSSFRowShifter {
|
|||||||
String[] formulaArray = cfRule.getFormulaArray();
|
String[] formulaArray = cfRule.getFormulaArray();
|
||||||
for (int i = 0; i < formulaArray.length; i++) {
|
for (int i = 0; i < formulaArray.length; i++) {
|
||||||
String formula = formulaArray[i];
|
String formula = formulaArray[i];
|
||||||
Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL, sheetIndex);
|
Ptg[] ptgs = FormulaParser.parse(formula, fpb, FormulaType.CELL, sheetIndex, rowIndex);
|
||||||
if (shifter.adjustFormula(ptgs, sheetIndex)) {
|
if (shifter.adjustFormula(ptgs, sheetIndex)) {
|
||||||
String shiftedFmla = FormulaRenderer.toFormulaString(fpb, ptgs);
|
String shiftedFmla = FormulaRenderer.toFormulaString(fpb, ptgs);
|
||||||
cfRule.setFormulaArray(i, shiftedFmla);
|
cfRule.setFormulaArray(i, shiftedFmla);
|
||||||
|
@ -18,6 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.poi.ss.formula;
|
package org.apache.poi.ss.formula;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
import org.apache.poi.ss.formula.ptg.AbstractFunctionPtg;
|
import org.apache.poi.ss.formula.ptg.AbstractFunctionPtg;
|
||||||
@ -28,7 +33,7 @@ import org.apache.poi.xssf.XSSFTestDataSamples;
|
|||||||
import org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook;
|
import org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test {@link FormulaParser}'s handling of row numbers at the edge of the
|
* Test {@link FormulaParser}'s handling of row numbers at the edge of the
|
||||||
@ -36,8 +41,9 @@ import junit.framework.TestCase;
|
|||||||
*
|
*
|
||||||
* @author David North
|
* @author David North
|
||||||
*/
|
*/
|
||||||
public class TestFormulaParser extends TestCase {
|
public class TestFormulaParser {
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testHSSFFailsForOver65536() {
|
public void testHSSFFailsForOver65536() {
|
||||||
FormulaParsingWorkbook workbook = HSSFEvaluationWorkbook.create(new HSSFWorkbook());
|
FormulaParsingWorkbook workbook = HSSFEvaluationWorkbook.create(new HSSFWorkbook());
|
||||||
try {
|
try {
|
||||||
@ -49,16 +55,19 @@ public class TestFormulaParser extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testHSSFPassCase() {
|
public void testHSSFPassCase() {
|
||||||
FormulaParsingWorkbook workbook = HSSFEvaluationWorkbook.create(new HSSFWorkbook());
|
FormulaParsingWorkbook workbook = HSSFEvaluationWorkbook.create(new HSSFWorkbook());
|
||||||
FormulaParser.parse("Sheet1!1:65536", workbook, FormulaType.CELL, 0);
|
FormulaParser.parse("Sheet1!1:65536", workbook, FormulaType.CELL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testXSSFWorksForOver65536() {
|
public void testXSSFWorksForOver65536() {
|
||||||
FormulaParsingWorkbook workbook = XSSFEvaluationWorkbook.create(new XSSFWorkbook());
|
FormulaParsingWorkbook workbook = XSSFEvaluationWorkbook.create(new XSSFWorkbook());
|
||||||
FormulaParser.parse("Sheet1!1:65537", workbook, FormulaType.CELL, 0);
|
FormulaParser.parse("Sheet1!1:65537", workbook, FormulaType.CELL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testXSSFFailCase() {
|
public void testXSSFFailCase() {
|
||||||
FormulaParsingWorkbook workbook = XSSFEvaluationWorkbook.create(new XSSFWorkbook());
|
FormulaParsingWorkbook workbook = XSSFEvaluationWorkbook.create(new XSSFWorkbook());
|
||||||
try {
|
try {
|
||||||
@ -71,6 +80,7 @@ public class TestFormulaParser extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// copied from org.apache.poi.hssf.model.TestFormulaParser
|
// copied from org.apache.poi.hssf.model.TestFormulaParser
|
||||||
|
@Test
|
||||||
public void testMacroFunction() throws Exception {
|
public void testMacroFunction() throws Exception {
|
||||||
// testNames.xlsm contains a VB function called 'myFunc'
|
// testNames.xlsm contains a VB function called 'myFunc'
|
||||||
final String testFile = "testNames.xlsm";
|
final String testFile = "testNames.xlsm";
|
||||||
@ -126,6 +136,7 @@ public class TestFormulaParser extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testParserErrors() throws Exception {
|
public void testParserErrors() throws Exception {
|
||||||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("testNames.xlsm");
|
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("testNames.xlsm");
|
||||||
try {
|
try {
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
package org.apache.poi.ss.formula;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
|
import org.apache.poi.ss.usermodel.CellValue;
|
||||||
|
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||||
|
import org.apache.poi.ss.usermodel.Table;
|
||||||
|
import org.apache.poi.xssf.XSSFTestDataSamples;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests Excel Table expressions (structured references)
|
||||||
|
* @see <a href="https://support.office.com/en-us/article/Using-structured-references-with-Excel-tables-F5ED2452-2337-4F71-BED3-C8AE6D2B276E">
|
||||||
|
* Excel Structured Reference Syntax
|
||||||
|
* </a>
|
||||||
|
*/
|
||||||
|
public class TestStructuredReferences {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the regular expression used in INDIRECT() evaluation to recognize structured references
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testTableExpressionSyntax() {
|
||||||
|
assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("abc[col1]").matches());
|
||||||
|
assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("_abc[col1]").matches());
|
||||||
|
assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("_[col1]").matches());
|
||||||
|
assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("\\[col1]").matches());
|
||||||
|
assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("\\[col1]").matches());
|
||||||
|
assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("\\[#This Row]").matches());
|
||||||
|
assertTrue("Valid structured reference syntax didn't match expression", Table.isStructuredReference.matcher("\\[ [col1], [col2] ]").matches());
|
||||||
|
|
||||||
|
// can't have a space between the table name and open bracket
|
||||||
|
assertFalse("Invalid structured reference syntax didn't fail expression", Table.isStructuredReference.matcher("\\abc [ [col1], [col2] ]").matches());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTableFormulas() throws Exception {
|
||||||
|
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("StructuredReferences.xlsx");
|
||||||
|
try {
|
||||||
|
|
||||||
|
final FormulaEvaluator eval = new XSSFFormulaEvaluator(wb);
|
||||||
|
confirm(eval, wb.getSheet("Table").getRow(5).getCell(0), 49);
|
||||||
|
confirm(eval, wb.getSheet("Formulas").getRow(0).getCell(0), 209);
|
||||||
|
} finally {
|
||||||
|
wb.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void confirm(FormulaEvaluator fe, Cell cell, double expectedResult) {
|
||||||
|
fe.clearAllCachedResultValues();
|
||||||
|
CellValue cv = fe.evaluate(cell);
|
||||||
|
if (cv.getCellType() != Cell.CELL_TYPE_NUMERIC) {
|
||||||
|
fail("expected numeric cell type but got " + cv.formatAsString());
|
||||||
|
}
|
||||||
|
assertEquals(expectedResult, cv.getNumberValue(), 0.0);
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,8 @@ import static org.junit.Assert.assertNotNull;
|
|||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
|
||||||
@ -41,12 +43,15 @@ import org.junit.Test;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public final class TestXSSFFormulaParser {
|
public final class TestXSSFFormulaParser {
|
||||||
private static Ptg[] parse(FormulaParsingWorkbook fpb, String fmla) {
|
private static Ptg[] parse(FormulaParsingWorkbook fpb, String fmla) {
|
||||||
return FormulaParser.parse(fmla, fpb, FormulaType.CELL, -1);
|
return FormulaParser.parse(fmla, fpb, FormulaType.CELL, -1);
|
||||||
}
|
}
|
||||||
|
private static Ptg[] parse(FormulaParsingWorkbook fpb, String fmla, int rowIndex) {
|
||||||
|
return FormulaParser.parse(fmla, fpb, FormulaType.CELL, -1, rowIndex);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void basicParsing() {
|
public void basicParsing() throws IOException {
|
||||||
XSSFWorkbook wb = new XSSFWorkbook();
|
XSSFWorkbook wb = new XSSFWorkbook();
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
Ptg[] ptgs;
|
Ptg[] ptgs;
|
||||||
@ -118,10 +123,12 @@ public final class TestXSSFFormulaParser {
|
|||||||
assertEquals(AttrPtg.class, ptgs[1].getClass());
|
assertEquals(AttrPtg.class, ptgs[1].getClass());
|
||||||
assertEquals("Sheet1!A1:B3", ptgs[0].toFormulaString());
|
assertEquals("Sheet1!A1:B3", ptgs[0].toFormulaString());
|
||||||
assertEquals("SUM", ptgs[1].toFormulaString());
|
assertEquals("SUM", ptgs[1].toFormulaString());
|
||||||
|
|
||||||
|
wb.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void builtInFormulas() {
|
public void builtInFormulas() throws IOException {
|
||||||
XSSFWorkbook wb = new XSSFWorkbook();
|
XSSFWorkbook wb = new XSSFWorkbook();
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
Ptg[] ptgs;
|
Ptg[] ptgs;
|
||||||
@ -134,10 +141,12 @@ public final class TestXSSFFormulaParser {
|
|||||||
assertEquals(2, ptgs.length);
|
assertEquals(2, ptgs.length);
|
||||||
assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof IntPtg);
|
assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof IntPtg);
|
||||||
assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof FuncPtg);
|
assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof FuncPtg);
|
||||||
|
|
||||||
|
wb.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void formaulReferncesSameWorkbook() {
|
public void formulaReferencesSameWorkbook() throws IOException {
|
||||||
// Use a test file with "other workbook" style references
|
// Use a test file with "other workbook" style references
|
||||||
// to itself
|
// to itself
|
||||||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("56737.xlsx");
|
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("56737.xlsx");
|
||||||
@ -153,10 +162,12 @@ public final class TestXSSFFormulaParser {
|
|||||||
assertEquals(null, ((NameXPxg)ptgs[0]).getSheetName());
|
assertEquals(null, ((NameXPxg)ptgs[0]).getSheetName());
|
||||||
assertEquals("NR_Global_B2",((NameXPxg)ptgs[0]).getNameName());
|
assertEquals("NR_Global_B2",((NameXPxg)ptgs[0]).getNameName());
|
||||||
assertEquals("[0]!NR_Global_B2",((NameXPxg)ptgs[0]).toFormulaString());
|
assertEquals("[0]!NR_Global_B2",((NameXPxg)ptgs[0]).toFormulaString());
|
||||||
|
|
||||||
|
wb.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void formulaReferencesOtherSheets() {
|
public void formulaReferencesOtherSheets() throws IOException {
|
||||||
// Use a test file with the named ranges in place
|
// Use a test file with the named ranges in place
|
||||||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("56737.xlsx");
|
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("56737.xlsx");
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
@ -193,10 +204,12 @@ public final class TestXSSFFormulaParser {
|
|||||||
assertEquals(1, ptgs.length);
|
assertEquals(1, ptgs.length);
|
||||||
assertEquals(NamePtg.class, ptgs[0].getClass());
|
assertEquals(NamePtg.class, ptgs[0].getClass());
|
||||||
assertEquals("NR_Global_B2",((NamePtg)ptgs[0]).toFormulaString(fpb));
|
assertEquals("NR_Global_B2",((NamePtg)ptgs[0]).toFormulaString(fpb));
|
||||||
|
|
||||||
|
wb.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void formulaReferencesOtherWorkbook() {
|
public void formulaReferencesOtherWorkbook() throws IOException {
|
||||||
// Use a test file with the external linked table in place
|
// Use a test file with the external linked table in place
|
||||||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("ref-56737.xlsx");
|
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("ref-56737.xlsx");
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
@ -228,6 +241,8 @@ public final class TestXSSFFormulaParser {
|
|||||||
assertEquals(null, ((NameXPxg)ptgs[0]).getSheetName());
|
assertEquals(null, ((NameXPxg)ptgs[0]).getSheetName());
|
||||||
assertEquals("NR_Global_B2",((NameXPxg)ptgs[0]).getNameName());
|
assertEquals("NR_Global_B2",((NameXPxg)ptgs[0]).getNameName());
|
||||||
assertEquals("[1]!NR_Global_B2",((NameXPxg)ptgs[0]).toFormulaString());
|
assertEquals("[1]!NR_Global_B2",((NameXPxg)ptgs[0]).toFormulaString());
|
||||||
|
|
||||||
|
wb.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -241,7 +256,7 @@ public final class TestXSSFFormulaParser {
|
|||||||
* (but not evaluate - that's elsewhere in the test suite)
|
* (but not evaluate - that's elsewhere in the test suite)
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void multiSheetReferencesHSSFandXSSF() throws Exception {
|
public void multiSheetReferencesHSSFandXSSF() throws IOException {
|
||||||
Workbook[] wbs = new Workbook[] {
|
Workbook[] wbs = new Workbook[] {
|
||||||
HSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xls"),
|
HSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xls"),
|
||||||
XSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xlsx")
|
XSSFTestDataSamples.openSampleWorkbook("55906-MultiSheetRefs.xlsx")
|
||||||
@ -363,6 +378,8 @@ public final class TestXSSFFormulaParser {
|
|||||||
newF = s1.getRow(0).createCell(11, Cell.CELL_TYPE_FORMULA);
|
newF = s1.getRow(0).createCell(11, Cell.CELL_TYPE_FORMULA);
|
||||||
newF.setCellFormula("MIN(Sheet1:Sheet2!A1:B2)");
|
newF.setCellFormula("MIN(Sheet1:Sheet2!A1:B2)");
|
||||||
assertEquals("MIN(Sheet1:Sheet2!A1:B2)", newF.getCellFormula());
|
assertEquals("MIN(Sheet1:Sheet2!A1:B2)", newF.getCellFormula());
|
||||||
|
|
||||||
|
wb.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,7 +391,7 @@ public final class TestXSSFFormulaParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test58648Single() {
|
public void test58648Single() throws IOException {
|
||||||
XSSFWorkbook wb = new XSSFWorkbook();
|
XSSFWorkbook wb = new XSSFWorkbook();
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
Ptg[] ptgs;
|
Ptg[] ptgs;
|
||||||
@ -384,10 +401,12 @@ public final class TestXSSFFormulaParser {
|
|||||||
2, ptgs.length);
|
2, ptgs.length);
|
||||||
assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
|
assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
|
||||||
assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof ParenthesisPtg);
|
assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof ParenthesisPtg);
|
||||||
|
|
||||||
|
wb.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test58648Basic() {
|
public void test58648Basic() throws IOException {
|
||||||
XSSFWorkbook wb = new XSSFWorkbook();
|
XSSFWorkbook wb = new XSSFWorkbook();
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
Ptg[] ptgs;
|
Ptg[] ptgs;
|
||||||
@ -431,10 +450,12 @@ public final class TestXSSFFormulaParser {
|
|||||||
assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
|
assertTrue("Had " + Arrays.toString(ptgs), ptgs[0] instanceof RefPtg);
|
||||||
assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof ParenthesisPtg);
|
assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof ParenthesisPtg);
|
||||||
assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof ParenthesisPtg);
|
assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof ParenthesisPtg);
|
||||||
|
|
||||||
|
wb.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test58648FormulaParsing() {
|
public void test58648FormulaParsing() throws IOException {
|
||||||
Workbook wb = XSSFTestDataSamples.openSampleWorkbook("58648.xlsx");
|
Workbook wb = XSSFTestDataSamples.openSampleWorkbook("58648.xlsx");
|
||||||
|
|
||||||
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
|
||||||
@ -460,10 +481,12 @@ public final class TestXSSFFormulaParser {
|
|||||||
Cell cell = sheet.getRow(1).getCell(4);
|
Cell cell = sheet.getRow(1).getCell(4);
|
||||||
|
|
||||||
assertEquals(5d, cell.getNumericCellValue(), 0d);
|
assertEquals(5d, cell.getNumericCellValue(), 0d);
|
||||||
|
|
||||||
|
wb.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWhitespaceInFormula() {
|
public void testWhitespaceInFormula() throws IOException {
|
||||||
XSSFWorkbook wb = new XSSFWorkbook();
|
XSSFWorkbook wb = new XSSFWorkbook();
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
Ptg[] ptgs;
|
Ptg[] ptgs;
|
||||||
@ -505,10 +528,12 @@ public final class TestXSSFFormulaParser {
|
|||||||
assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof AreaPtg);
|
assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof AreaPtg);
|
||||||
assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof AreaPtg);
|
assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof AreaPtg);
|
||||||
assertTrue("Had " + Arrays.toString(ptgs), ptgs[3] instanceof IntersectionPtg);
|
assertTrue("Had " + Arrays.toString(ptgs), ptgs[3] instanceof IntersectionPtg);
|
||||||
|
|
||||||
|
wb.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWhitespaceInComplexFormula() {
|
public void testWhitespaceInComplexFormula() throws IOException {
|
||||||
XSSFWorkbook wb = new XSSFWorkbook();
|
XSSFWorkbook wb = new XSSFWorkbook();
|
||||||
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
Ptg[] ptgs;
|
Ptg[] ptgs;
|
||||||
@ -529,5 +554,172 @@ public final class TestXSSFFormulaParser {
|
|||||||
assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof RefPtg);
|
assertTrue("Had " + Arrays.toString(ptgs), ptgs[1] instanceof RefPtg);
|
||||||
assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof AreaPtg);
|
assertTrue("Had " + Arrays.toString(ptgs), ptgs[2] instanceof AreaPtg);
|
||||||
assertTrue("Had " + Arrays.toString(ptgs), ptgs[3] instanceof NameXPxg);
|
assertTrue("Had " + Arrays.toString(ptgs), ptgs[3] instanceof NameXPxg);
|
||||||
|
|
||||||
|
wb.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseStructuredReferences() throws IOException {
|
||||||
|
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("StructuredReferences.xlsx");
|
||||||
|
|
||||||
|
XSSFEvaluationWorkbook fpb = XSSFEvaluationWorkbook.create(wb);
|
||||||
|
Ptg[] ptgs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
The following cases are tested (copied from FormulaParser.parseStructuredReference)
|
||||||
|
1 Table1[col]
|
||||||
|
2 Table1[[#Totals],[col]]
|
||||||
|
3 Table1[#Totals]
|
||||||
|
4 Table1[#All]
|
||||||
|
5 Table1[#Data]
|
||||||
|
6 Table1[#Headers]
|
||||||
|
7 Table1[#Totals]
|
||||||
|
8 Table1[#This Row]
|
||||||
|
9 Table1[[#All],[col]]
|
||||||
|
10 Table1[[#Headers],[col]]
|
||||||
|
11 Table1[[#Totals],[col]]
|
||||||
|
12 Table1[[#All],[col1]:[col2]]
|
||||||
|
13 Table1[[#Data],[col1]:[col2]]
|
||||||
|
14 Table1[[#Headers],[col1]:[col2]]
|
||||||
|
15 Table1[[#Totals],[col1]:[col2]]
|
||||||
|
16 Table1[[#Headers],[#Data],[col2]]
|
||||||
|
17 Table1[[#This Row], [col1]]
|
||||||
|
18 Table1[ [col1]:[col2] ]
|
||||||
|
*/
|
||||||
|
|
||||||
|
final String tbl = "\\_Prime.1";
|
||||||
|
final String noTotalsRowReason = ": Tables without a Totals row should return #REF! on [#Totals]";
|
||||||
|
|
||||||
|
////// Case 1: Evaluate Table1[col] with apostrophe-escaped #-signs ////////
|
||||||
|
ptgs = parse(fpb, "SUM("+tbl+"[calc='#*'#])");
|
||||||
|
assertEquals(2, ptgs.length);
|
||||||
|
|
||||||
|
// Area3DPxg [sheet=Table ! A2:A7]
|
||||||
|
assertTrue(ptgs[0] instanceof Area3DPxg);
|
||||||
|
Area3DPxg ptg0 = (Area3DPxg) ptgs[0];
|
||||||
|
assertEquals("Table", ptg0.getSheetName());
|
||||||
|
assertEquals("A2:A7", ptg0.format2DRefAsString());
|
||||||
|
// Note: structured references are evaluated and resolved to regular 3D area references.
|
||||||
|
assertEquals("Table!A2:A7", ptg0.toFormulaString());
|
||||||
|
|
||||||
|
// AttrPtg [sum ]
|
||||||
|
assertTrue(ptgs[1] instanceof AttrPtg);
|
||||||
|
AttrPtg ptg1 = (AttrPtg) ptgs[1];
|
||||||
|
assertTrue(ptg1.isSum());
|
||||||
|
|
||||||
|
////// Case 1: Evaluate "Table1[col]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[Name]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[col]", "Table!B2:B7", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
////// Case 2: Evaluate "Table1[[#Totals],[col]]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[[#Totals],[col]]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[[#Totals],[col]]" + noTotalsRowReason, ErrPtg.REF_INVALID, ptgs[0]);
|
||||||
|
|
||||||
|
////// Case 3: Evaluate "Table1[#Totals]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[#Totals]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[#Totals]" + noTotalsRowReason, ErrPtg.REF_INVALID, ptgs[0]);
|
||||||
|
|
||||||
|
////// Case 4: Evaluate "Table1[#All]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[#All]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[#All]", "Table!A1:C7", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
////// Case 5: Evaluate "Table1[#Data]" (excludes Header and Data rows) ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[#Data]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[#Data]", "Table!A2:C7", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
////// Case 6: Evaluate "Table1[#Headers]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[#Headers]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[#Headers]", "Table!A1:C1", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
////// Case 7: Evaluate "Table1[#Totals]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[#Totals]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[#Totals]" + noTotalsRowReason, ErrPtg.REF_INVALID, ptgs[0]);
|
||||||
|
|
||||||
|
////// Case 8: Evaluate "Table1[#This Row]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[#This Row]", 2);
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[#This Row]", "Table!A3:C3", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
////// Evaluate "Table1[@]" (equivalent to "Table1[#This Row]") ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[@]", 2);
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table!A3:C3", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
////// Evaluate "Table1[#This Row]" when rowIndex is outside Table ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[#This Row]", 10);
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[#This Row]", ErrPtg.VALUE_INVALID, ptgs[0]);
|
||||||
|
|
||||||
|
////// Evaluate "Table1[@]" when rowIndex is outside Table ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[@]", 10);
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[@]", ErrPtg.VALUE_INVALID, ptgs[0]);
|
||||||
|
|
||||||
|
////// Evaluate "Table1[[#Data],[col]]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[[#Data], [Number]]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[[#Data],[col]]", "Table!C2:C7", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
|
||||||
|
////// Case 9: Evaluate "Table1[[#All],[col]]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[[#All], [Number]]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[[#All],[col]]", "Table!C1:C7", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
////// Case 10: Evaluate "Table1[[#Headers],[col]]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[[#Headers], [Number]]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
// also acceptable: Table1!B1
|
||||||
|
assertEquals("Table1[[#Headers],[col]]", "Table!C1:C1", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
////// Case 11: Evaluate "Table1[[#Totals],[col]]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[[#Totals],[Name]]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[[#Totals],[col]]" + noTotalsRowReason, ErrPtg.REF_INVALID, ptgs[0]);
|
||||||
|
|
||||||
|
////// Case 12: Evaluate "Table1[[#All],[col1]:[col2]]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[[#All], [Name]:[Number]]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[[#All],[col1]:[col2]]", "Table!B1:C7", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
////// Case 13: Evaluate "Table1[[#Data],[col]:[col2]]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[[#Data], [Name]:[Number]]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[[#Data],[col]:[col2]]", "Table!B2:C7", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
////// Case 14: Evaluate "Table1[[#Headers],[col1]:[col2]]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[[#Headers], [Name]:[Number]]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[[#Headers],[col1]:[col2]]", "Table!B1:C1", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
////// Case 15: Evaluate "Table1[[#Totals],[col]:[col2]]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[[#Totals], [Name]:[Number]]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[[#Totals],[col]:[col2]]" + noTotalsRowReason, ErrPtg.REF_INVALID, ptgs[0]);
|
||||||
|
|
||||||
|
////// Case 16: Evaluate "Table1[[#Headers],[#Data],[col]]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[[#Headers],[#Data],[Number]]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[[#Headers],[#Data],[col]]", "Table!C1:C7", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
////// Case 17: Evaluate "Table1[[#This Row], [col1]]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[[#This Row], [Number]]", 2);
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
// also acceptable: Table!C3
|
||||||
|
assertEquals("Table1[[#This Row], [col1]]", "Table!C3:C3", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
////// Case 18: Evaluate "Table1[[col]:[col2]]" ////////
|
||||||
|
ptgs = parse(fpb, tbl+"[[Name]:[Number]]");
|
||||||
|
assertEquals(1, ptgs.length);
|
||||||
|
assertEquals("Table1[[col]:[col2]]", "Table!B2:C7", ptgs[0].toFormulaString());
|
||||||
|
|
||||||
|
wb.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1137,7 +1137,7 @@ public final class TestXSSFSheet extends BaseTestXSheet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See bug #50829
|
* See bug #50829 test data tables
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void tables() throws IOException {
|
public void tables() throws IOException {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,7 @@ import org.junit.runners.Suite;
|
|||||||
@Suite.SuiteClasses({
|
@Suite.SuiteClasses({
|
||||||
TestDrawingManager.class,
|
TestDrawingManager.class,
|
||||||
TestDrawingManager2.class,
|
TestDrawingManager2.class,
|
||||||
TestFormulaParser.class,
|
//TestFormulaParser.class, //converted to junit4
|
||||||
TestFormulaParserEval.class,
|
TestFormulaParserEval.class,
|
||||||
TestFormulaParserIf.class,
|
TestFormulaParserIf.class,
|
||||||
TestLinkTable.class,
|
TestLinkTable.class,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -38,67 +38,67 @@ import org.apache.poi.util.LittleEndianInput;
|
|||||||
*/
|
*/
|
||||||
public final class TestSharedFormulaRecord extends TestCase {
|
public final class TestSharedFormulaRecord extends TestCase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sample spreadsheet known to have one sheet with 4 shared formula ranges
|
* A sample spreadsheet known to have one sheet with 4 shared formula ranges
|
||||||
*/
|
*/
|
||||||
private static final String SHARED_FORMULA_TEST_XLS = "SharedFormulaTest.xls";
|
private static final String SHARED_FORMULA_TEST_XLS = "SharedFormulaTest.xls";
|
||||||
/**
|
/**
|
||||||
* Binary data for an encoded formula. Taken from attachment 22062 (bugzilla 45123/45421).
|
* Binary data for an encoded formula. Taken from attachment 22062 (bugzilla 45123/45421).
|
||||||
* The shared formula is in Sheet1!C6:C21, with text "SUMPRODUCT(--(End_Acct=$C6),--(End_Bal))"
|
* The shared formula is in Sheet1!C6:C21, with text "SUMPRODUCT(--(End_Acct=$C6),--(End_Bal))"
|
||||||
* This data is found at offset 0x1A4A (within the shared formula record).
|
* This data is found at offset 0x1A4A (within the shared formula record).
|
||||||
* The critical thing about this formula is that it contains shared formula tokens (tRefN*,
|
* The critical thing about this formula is that it contains shared formula tokens (tRefN*,
|
||||||
* tAreaN*) with operand class 'array'.
|
* tAreaN*) with operand class 'array'.
|
||||||
*/
|
*/
|
||||||
private static final byte[] SHARED_FORMULA_WITH_REF_ARRAYS_DATA = {
|
private static final byte[] SHARED_FORMULA_WITH_REF_ARRAYS_DATA = {
|
||||||
0x1A, 0x00,
|
0x1A, 0x00,
|
||||||
0x63, 0x02, 0x00, 0x00, 0x00,
|
0x63, 0x02, 0x00, 0x00, 0x00,
|
||||||
0x6C, 0x00, 0x00, 0x02, (byte)0x80, // tRefNA
|
0x6C, 0x00, 0x00, 0x02, (byte)0x80, // tRefNA
|
||||||
0x0B,
|
0x0B,
|
||||||
0x15,
|
0x15,
|
||||||
0x13,
|
0x13,
|
||||||
0x13,
|
0x13,
|
||||||
0x63, 0x03, 0x00, 0x00, 0x00,
|
0x63, 0x03, 0x00, 0x00, 0x00,
|
||||||
0x15,
|
0x15,
|
||||||
0x13,
|
0x13,
|
||||||
0x13,
|
0x13,
|
||||||
0x42, 0x02, (byte)0xE4, 0x00,
|
0x42, 0x02, (byte)0xE4, 0x00,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The method <tt>SharedFormulaRecord.convertSharedFormulas()</tt> converts formulas from
|
* The method <tt>SharedFormulaRecord.convertSharedFormulas()</tt> converts formulas from
|
||||||
* 'shared formula' to 'single cell formula' format. It is important that token operand
|
* 'shared formula' to 'single cell formula' format. It is important that token operand
|
||||||
* classes are preserved during this transformation, because Excel may not tolerate the
|
* classes are preserved during this transformation, because Excel may not tolerate the
|
||||||
* incorrect encoding. The formula here is one such example (Excel displays #VALUE!).
|
* incorrect encoding. The formula here is one such example (Excel displays #VALUE!).
|
||||||
*/
|
*/
|
||||||
public void testConvertSharedFormulasOperandClasses_bug45123() {
|
public void testConvertSharedFormulasOperandClasses_bug45123() {
|
||||||
|
|
||||||
LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(SHARED_FORMULA_WITH_REF_ARRAYS_DATA);
|
LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(SHARED_FORMULA_WITH_REF_ARRAYS_DATA);
|
||||||
int encodedLen = in.readUShort();
|
int encodedLen = in.readUShort();
|
||||||
Ptg[] sharedFormula = Ptg.readTokens(encodedLen, in);
|
Ptg[] sharedFormula = Ptg.readTokens(encodedLen, in);
|
||||||
|
|
||||||
SharedFormula sf = new SharedFormula(SpreadsheetVersion.EXCEL97);
|
SharedFormula sf = new SharedFormula(SpreadsheetVersion.EXCEL97);
|
||||||
Ptg[] convertedFormula = sf.convertSharedFormulas(sharedFormula, 100, 200);
|
Ptg[] convertedFormula = sf.convertSharedFormulas(sharedFormula, 100, 200);
|
||||||
|
|
||||||
RefPtg refPtg = (RefPtg) convertedFormula[1];
|
RefPtg refPtg = (RefPtg) convertedFormula[1];
|
||||||
assertEquals("$C101", refPtg.toFormulaString());
|
assertEquals("$C101", refPtg.toFormulaString());
|
||||||
if (refPtg.getPtgClass() == Ptg.CLASS_REF) {
|
if (refPtg.getPtgClass() == Ptg.CLASS_REF) {
|
||||||
throw new AssertionFailedError("Identified bug 45123");
|
throw new AssertionFailedError("Identified bug 45123");
|
||||||
}
|
}
|
||||||
|
|
||||||
confirmOperandClasses(sharedFormula, convertedFormula);
|
confirmOperandClasses(sharedFormula, convertedFormula);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void confirmOperandClasses(Ptg[] originalPtgs, Ptg[] convertedPtgs) {
|
private static void confirmOperandClasses(Ptg[] originalPtgs, Ptg[] convertedPtgs) {
|
||||||
assertEquals(originalPtgs.length, convertedPtgs.length);
|
assertEquals(originalPtgs.length, convertedPtgs.length);
|
||||||
for (int i = 0; i < convertedPtgs.length; i++) {
|
for (int i = 0; i < convertedPtgs.length; i++) {
|
||||||
Ptg originalPtg = originalPtgs[i];
|
Ptg originalPtg = originalPtgs[i];
|
||||||
Ptg convertedPtg = convertedPtgs[i];
|
Ptg convertedPtg = convertedPtgs[i];
|
||||||
if (originalPtg.getPtgClass() != convertedPtg.getPtgClass()) {
|
if (originalPtg.getPtgClass() != convertedPtg.getPtgClass()) {
|
||||||
throw new ComparisonFailure("Different operand class for token[" + i + "]",
|
throw new ComparisonFailure("Different operand class for token[" + i + "]",
|
||||||
String.valueOf(originalPtg.getPtgClass()), String.valueOf(convertedPtg.getPtgClass()));
|
String.valueOf(originalPtg.getPtgClass()), String.valueOf(convertedPtg.getPtgClass()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testConvertSharedFormulas() {
|
public void testConvertSharedFormulas() {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
@ -138,111 +138,111 @@ public final class TestSharedFormulaRecord extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make sure that POI preserves {@link SharedFormulaRecord}s
|
* Make sure that POI preserves {@link SharedFormulaRecord}s
|
||||||
*/
|
*/
|
||||||
public void testPreserveOnReserialize() {
|
public void testPreserveOnReserialize() {
|
||||||
HSSFWorkbook wb;
|
HSSFWorkbook wb;
|
||||||
HSSFSheet sheet;
|
HSSFSheet sheet;
|
||||||
HSSFCell cellB32769;
|
HSSFCell cellB32769;
|
||||||
HSSFCell cellC32769;
|
HSSFCell cellC32769;
|
||||||
|
|
||||||
// Reading directly from XLS file
|
// Reading directly from XLS file
|
||||||
wb = HSSFTestDataSamples.openSampleWorkbook(SHARED_FORMULA_TEST_XLS);
|
wb = HSSFTestDataSamples.openSampleWorkbook(SHARED_FORMULA_TEST_XLS);
|
||||||
sheet = wb.getSheetAt(0);
|
sheet = wb.getSheetAt(0);
|
||||||
cellB32769 = sheet.getRow(32768).getCell(1);
|
cellB32769 = sheet.getRow(32768).getCell(1);
|
||||||
cellC32769 = sheet.getRow(32768).getCell(2);
|
cellC32769 = sheet.getRow(32768).getCell(2);
|
||||||
// check reading of formulas which are shared (two cells from a 1R x 8C range)
|
// check reading of formulas which are shared (two cells from a 1R x 8C range)
|
||||||
assertEquals("B32770*2", cellB32769.getCellFormula());
|
assertEquals("B32770*2", cellB32769.getCellFormula());
|
||||||
assertEquals("C32770*2", cellC32769.getCellFormula());
|
assertEquals("C32770*2", cellC32769.getCellFormula());
|
||||||
confirmCellEvaluation(wb, cellB32769, 4);
|
confirmCellEvaluation(wb, cellB32769, 4);
|
||||||
confirmCellEvaluation(wb, cellC32769, 6);
|
confirmCellEvaluation(wb, cellC32769, 6);
|
||||||
// Confirm this example really does have SharedFormulas.
|
// Confirm this example really does have SharedFormulas.
|
||||||
// there are 3 others besides the one at A32769:H32769
|
// there are 3 others besides the one at A32769:H32769
|
||||||
assertEquals(4, countSharedFormulas(sheet));
|
assertEquals(4, countSharedFormulas(sheet));
|
||||||
|
|
||||||
|
|
||||||
// Re-serialize and check again
|
// Re-serialize and check again
|
||||||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||||
sheet = wb.getSheetAt(0);
|
sheet = wb.getSheetAt(0);
|
||||||
cellB32769 = sheet.getRow(32768).getCell(1);
|
cellB32769 = sheet.getRow(32768).getCell(1);
|
||||||
cellC32769 = sheet.getRow(32768).getCell(2);
|
cellC32769 = sheet.getRow(32768).getCell(2);
|
||||||
assertEquals("B32770*2", cellB32769.getCellFormula());
|
assertEquals("B32770*2", cellB32769.getCellFormula());
|
||||||
confirmCellEvaluation(wb, cellB32769, 4);
|
confirmCellEvaluation(wb, cellB32769, 4);
|
||||||
assertEquals(4, countSharedFormulas(sheet));
|
assertEquals(4, countSharedFormulas(sheet));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUnshareFormulaDueToChangeFormula() {
|
public void testUnshareFormulaDueToChangeFormula() {
|
||||||
HSSFWorkbook wb;
|
HSSFWorkbook wb;
|
||||||
HSSFSheet sheet;
|
HSSFSheet sheet;
|
||||||
HSSFCell cellB32769;
|
HSSFCell cellB32769;
|
||||||
HSSFCell cellC32769;
|
HSSFCell cellC32769;
|
||||||
|
|
||||||
wb = HSSFTestDataSamples.openSampleWorkbook(SHARED_FORMULA_TEST_XLS);
|
wb = HSSFTestDataSamples.openSampleWorkbook(SHARED_FORMULA_TEST_XLS);
|
||||||
sheet = wb.getSheetAt(0);
|
sheet = wb.getSheetAt(0);
|
||||||
cellB32769 = sheet.getRow(32768).getCell(1);
|
cellB32769 = sheet.getRow(32768).getCell(1);
|
||||||
cellC32769 = sheet.getRow(32768).getCell(2);
|
cellC32769 = sheet.getRow(32768).getCell(2);
|
||||||
|
|
||||||
// Updating cell formula, causing it to become unshared
|
// Updating cell formula, causing it to become unshared
|
||||||
cellB32769.setCellFormula("1+1");
|
cellB32769.setCellFormula("1+1");
|
||||||
confirmCellEvaluation(wb, cellB32769, 2);
|
confirmCellEvaluation(wb, cellB32769, 2);
|
||||||
// currently (Oct 2008) POI handles this by exploding the whole shared formula group
|
// currently (Oct 2008) POI handles this by exploding the whole shared formula group
|
||||||
assertEquals(3, countSharedFormulas(sheet)); // one less now
|
assertEquals(3, countSharedFormulas(sheet)); // one less now
|
||||||
// check that nearby cell of the same group still has the same formula
|
// check that nearby cell of the same group still has the same formula
|
||||||
assertEquals("C32770*2", cellC32769.getCellFormula());
|
assertEquals("C32770*2", cellC32769.getCellFormula());
|
||||||
confirmCellEvaluation(wb, cellC32769, 6);
|
confirmCellEvaluation(wb, cellC32769, 6);
|
||||||
}
|
}
|
||||||
public void testUnshareFormulaDueToDelete() {
|
public void testUnshareFormulaDueToDelete() {
|
||||||
HSSFWorkbook wb;
|
HSSFWorkbook wb;
|
||||||
HSSFSheet sheet;
|
HSSFSheet sheet;
|
||||||
HSSFCell cell;
|
HSSFCell cell;
|
||||||
final int ROW_IX = 2;
|
final int ROW_IX = 2;
|
||||||
|
|
||||||
// changing shared formula cell to blank
|
// changing shared formula cell to blank
|
||||||
wb = HSSFTestDataSamples.openSampleWorkbook(SHARED_FORMULA_TEST_XLS);
|
wb = HSSFTestDataSamples.openSampleWorkbook(SHARED_FORMULA_TEST_XLS);
|
||||||
sheet = wb.getSheetAt(0);
|
sheet = wb.getSheetAt(0);
|
||||||
|
|
||||||
assertEquals("A$1*2", sheet.getRow(ROW_IX).getCell(1).getCellFormula());
|
assertEquals("A$1*2", sheet.getRow(ROW_IX).getCell(1).getCellFormula());
|
||||||
cell = sheet.getRow(ROW_IX).getCell(1);
|
cell = sheet.getRow(ROW_IX).getCell(1);
|
||||||
cell.setCellType(HSSFCell.CELL_TYPE_BLANK);
|
cell.setCellType(HSSFCell.CELL_TYPE_BLANK);
|
||||||
assertEquals(3, countSharedFormulas(sheet));
|
assertEquals(3, countSharedFormulas(sheet));
|
||||||
|
|
||||||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||||
sheet = wb.getSheetAt(0);
|
sheet = wb.getSheetAt(0);
|
||||||
assertEquals("A$1*2", sheet.getRow(ROW_IX+1).getCell(1).getCellFormula());
|
assertEquals("A$1*2", sheet.getRow(ROW_IX+1).getCell(1).getCellFormula());
|
||||||
|
|
||||||
// deleting shared formula cell
|
// deleting shared formula cell
|
||||||
wb = HSSFTestDataSamples.openSampleWorkbook(SHARED_FORMULA_TEST_XLS);
|
wb = HSSFTestDataSamples.openSampleWorkbook(SHARED_FORMULA_TEST_XLS);
|
||||||
sheet = wb.getSheetAt(0);
|
sheet = wb.getSheetAt(0);
|
||||||
|
|
||||||
assertEquals("A$1*2", sheet.getRow(ROW_IX).getCell(1).getCellFormula());
|
assertEquals("A$1*2", sheet.getRow(ROW_IX).getCell(1).getCellFormula());
|
||||||
cell = sheet.getRow(ROW_IX).getCell(1);
|
cell = sheet.getRow(ROW_IX).getCell(1);
|
||||||
sheet.getRow(ROW_IX).removeCell(cell);
|
sheet.getRow(ROW_IX).removeCell(cell);
|
||||||
assertEquals(3, countSharedFormulas(sheet));
|
assertEquals(3, countSharedFormulas(sheet));
|
||||||
|
|
||||||
wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
wb = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||||
sheet = wb.getSheetAt(0);
|
sheet = wb.getSheetAt(0);
|
||||||
assertEquals("A$1*2", sheet.getRow(ROW_IX+1).getCell(1).getCellFormula());
|
assertEquals("A$1*2", sheet.getRow(ROW_IX+1).getCell(1).getCellFormula());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void confirmCellEvaluation(HSSFWorkbook wb, HSSFCell cell, double expectedValue) {
|
private static void confirmCellEvaluation(HSSFWorkbook wb, HSSFCell cell, double expectedValue) {
|
||||||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
|
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
|
||||||
CellValue cv = fe.evaluate(cell);
|
CellValue cv = fe.evaluate(cell);
|
||||||
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
|
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
|
||||||
assertEquals(expectedValue, cv.getNumberValue(), 0.0);
|
assertEquals(expectedValue, cv.getNumberValue(), 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the number of {@link SharedFormulaRecord}s encoded for the specified sheet
|
* @return the number of {@link SharedFormulaRecord}s encoded for the specified sheet
|
||||||
*/
|
*/
|
||||||
private static int countSharedFormulas(HSSFSheet sheet) {
|
private static int countSharedFormulas(HSSFSheet sheet) {
|
||||||
Record[] records = RecordInspector.getRecords(sheet, 0);
|
Record[] records = RecordInspector.getRecords(sheet, 0);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i = 0; i < records.length; i++) {
|
for (int i = 0; i < records.length; i++) {
|
||||||
Record rec = records[i];
|
Record rec = records[i];
|
||||||
if(rec instanceof SharedFormulaRecord) {
|
if(rec instanceof SharedFormulaRecord) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,32 +36,32 @@ import org.junit.Test;
|
|||||||
* Tests for the INDIRECT() function.</p>
|
* Tests for the INDIRECT() function.</p>
|
||||||
*/
|
*/
|
||||||
public final class TestIndirect {
|
public final class TestIndirect {
|
||||||
// convenient access to namespace
|
// convenient access to namespace
|
||||||
// private static final ErrorEval EE = null;
|
// private static final ErrorEval EE = null;
|
||||||
|
|
||||||
private static void createDataRow(HSSFSheet sheet, int rowIndex, double... vals) {
|
private static void createDataRow(HSSFSheet sheet, int rowIndex, double... vals) {
|
||||||
HSSFRow row = sheet.createRow(rowIndex);
|
HSSFRow row = sheet.createRow(rowIndex);
|
||||||
for (int i = 0; i < vals.length; i++) {
|
for (int i = 0; i < vals.length; i++) {
|
||||||
row.createCell(i).setCellValue(vals[i]);
|
row.createCell(i).setCellValue(vals[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HSSFWorkbook createWBA() {
|
private static HSSFWorkbook createWBA() {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
HSSFSheet sheet1 = wb.createSheet("Sheet1");
|
HSSFSheet sheet1 = wb.createSheet("Sheet1");
|
||||||
HSSFSheet sheet2 = wb.createSheet("Sheet2");
|
HSSFSheet sheet2 = wb.createSheet("Sheet2");
|
||||||
HSSFSheet sheet3 = wb.createSheet("John's sales");
|
HSSFSheet sheet3 = wb.createSheet("John's sales");
|
||||||
|
|
||||||
createDataRow(sheet1, 0, 11, 12, 13, 14);
|
createDataRow(sheet1, 0, 11, 12, 13, 14);
|
||||||
createDataRow(sheet1, 1, 21, 22, 23, 24);
|
createDataRow(sheet1, 1, 21, 22, 23, 24);
|
||||||
createDataRow(sheet1, 2, 31, 32, 33, 34);
|
createDataRow(sheet1, 2, 31, 32, 33, 34);
|
||||||
|
|
||||||
createDataRow(sheet2, 0, 50, 55, 60, 65);
|
createDataRow(sheet2, 0, 50, 55, 60, 65);
|
||||||
createDataRow(sheet2, 1, 51, 56, 61, 66);
|
createDataRow(sheet2, 1, 51, 56, 61, 66);
|
||||||
createDataRow(sheet2, 2, 52, 57, 62, 67);
|
createDataRow(sheet2, 2, 52, 57, 62, 67);
|
||||||
|
|
||||||
createDataRow(sheet3, 0, 30, 31, 32);
|
createDataRow(sheet3, 0, 30, 31, 32);
|
||||||
createDataRow(sheet3, 1, 33, 34, 35);
|
createDataRow(sheet3, 1, 33, 34, 35);
|
||||||
|
|
||||||
HSSFName name1 = wb.createName();
|
HSSFName name1 = wb.createName();
|
||||||
name1.setNameName("sales1");
|
name1.setNameName("sales1");
|
||||||
@ -75,131 +75,131 @@ public final class TestIndirect {
|
|||||||
row.createCell(0).setCellValue("sales1"); //A4
|
row.createCell(0).setCellValue("sales1"); //A4
|
||||||
row.createCell(1).setCellValue("sales2"); //B4
|
row.createCell(1).setCellValue("sales2"); //B4
|
||||||
|
|
||||||
return wb;
|
return wb;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HSSFWorkbook createWBB() {
|
private static HSSFWorkbook createWBB() {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
HSSFSheet sheet1 = wb.createSheet("Sheet1");
|
HSSFSheet sheet1 = wb.createSheet("Sheet1");
|
||||||
HSSFSheet sheet2 = wb.createSheet("Sheet2");
|
HSSFSheet sheet2 = wb.createSheet("Sheet2");
|
||||||
HSSFSheet sheet3 = wb.createSheet("## Look here!");
|
HSSFSheet sheet3 = wb.createSheet("## Look here!");
|
||||||
|
|
||||||
createDataRow(sheet1, 0, 400, 440, 480, 520);
|
createDataRow(sheet1, 0, 400, 440, 480, 520);
|
||||||
createDataRow(sheet1, 1, 420, 460, 500, 540);
|
createDataRow(sheet1, 1, 420, 460, 500, 540);
|
||||||
|
|
||||||
createDataRow(sheet2, 0, 50, 55, 60, 65);
|
createDataRow(sheet2, 0, 50, 55, 60, 65);
|
||||||
createDataRow(sheet2, 1, 51, 56, 61, 66);
|
createDataRow(sheet2, 1, 51, 56, 61, 66);
|
||||||
|
|
||||||
createDataRow(sheet3, 0, 42);
|
createDataRow(sheet3, 0, 42);
|
||||||
|
|
||||||
return wb;
|
return wb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBasic() throws Exception {
|
public void testBasic() throws Exception {
|
||||||
|
|
||||||
HSSFWorkbook wbA = createWBA();
|
HSSFWorkbook wbA = createWBA();
|
||||||
HSSFCell c = wbA.getSheetAt(0).createRow(5).createCell(2);
|
HSSFCell c = wbA.getSheetAt(0).createRow(5).createCell(2);
|
||||||
HSSFFormulaEvaluator feA = new HSSFFormulaEvaluator(wbA);
|
HSSFFormulaEvaluator feA = new HSSFFormulaEvaluator(wbA);
|
||||||
|
|
||||||
// non-error cases
|
// non-error cases
|
||||||
confirm(feA, c, "INDIRECT(\"C2\")", 23);
|
confirm(feA, c, "INDIRECT(\"C2\")", 23);
|
||||||
confirm(feA, c, "INDIRECT(\"$C2\")", 23);
|
confirm(feA, c, "INDIRECT(\"$C2\")", 23);
|
||||||
confirm(feA, c, "INDIRECT(\"C$2\")", 23);
|
confirm(feA, c, "INDIRECT(\"C$2\")", 23);
|
||||||
confirm(feA, c, "SUM(INDIRECT(\"Sheet2!B1:C3\"))", 351); // area ref
|
confirm(feA, c, "SUM(INDIRECT(\"Sheet2!B1:C3\"))", 351); // area ref
|
||||||
confirm(feA, c, "SUM(INDIRECT(\"Sheet2! B1 : C3 \"))", 351); // spaces in area ref
|
confirm(feA, c, "SUM(INDIRECT(\"Sheet2! B1 : C3 \"))", 351); // spaces in area ref
|
||||||
confirm(feA, c, "SUM(INDIRECT(\"'John''s sales'!A1:C1\"))", 93); // special chars in sheet name
|
confirm(feA, c, "SUM(INDIRECT(\"'John''s sales'!A1:C1\"))", 93); // special chars in sheet name
|
||||||
confirm(feA, c, "INDIRECT(\"'Sheet1'!B3\")", 32); // redundant sheet name quotes
|
confirm(feA, c, "INDIRECT(\"'Sheet1'!B3\")", 32); // redundant sheet name quotes
|
||||||
confirm(feA, c, "INDIRECT(\"sHeet1!B3\")", 32); // case-insensitive sheet name
|
confirm(feA, c, "INDIRECT(\"sHeet1!B3\")", 32); // case-insensitive sheet name
|
||||||
confirm(feA, c, "INDIRECT(\" D3 \")", 34); // spaces around cell ref
|
confirm(feA, c, "INDIRECT(\" D3 \")", 34); // spaces around cell ref
|
||||||
confirm(feA, c, "INDIRECT(\"Sheet1! D3 \")", 34); // spaces around cell ref
|
confirm(feA, c, "INDIRECT(\"Sheet1! D3 \")", 34); // spaces around cell ref
|
||||||
confirm(feA, c, "INDIRECT(\"A1\", TRUE)", 11); // explicit arg1. only TRUE supported so far
|
confirm(feA, c, "INDIRECT(\"A1\", TRUE)", 11); // explicit arg1. only TRUE supported so far
|
||||||
|
|
||||||
confirm(feA, c, "INDIRECT(\"A1:G1\")", 13); // de-reference area ref (note formula is in C4)
|
confirm(feA, c, "INDIRECT(\"A1:G1\")", 13); // de-reference area ref (note formula is in C4)
|
||||||
|
|
||||||
confirm(feA, c, "SUM(INDIRECT(A4))", 50); // indirect defined name
|
confirm(feA, c, "SUM(INDIRECT(A4))", 50); // indirect defined name
|
||||||
confirm(feA, c, "SUM(INDIRECT(B4))", 351); // indirect defined name pointinh to other sheet
|
confirm(feA, c, "SUM(INDIRECT(B4))", 351); // indirect defined name pointinh to other sheet
|
||||||
|
|
||||||
// simple error propagation:
|
// simple error propagation:
|
||||||
|
|
||||||
// arg0 is evaluated to text first
|
// arg0 is evaluated to text first
|
||||||
confirm(feA, c, "INDIRECT(#DIV/0!)", ErrorEval.DIV_ZERO);
|
confirm(feA, c, "INDIRECT(#DIV/0!)", ErrorEval.DIV_ZERO);
|
||||||
confirm(feA, c, "INDIRECT(#DIV/0!)", ErrorEval.DIV_ZERO);
|
confirm(feA, c, "INDIRECT(#DIV/0!)", ErrorEval.DIV_ZERO);
|
||||||
confirm(feA, c, "INDIRECT(#NAME?, \"x\")", ErrorEval.NAME_INVALID);
|
confirm(feA, c, "INDIRECT(#NAME?, \"x\")", ErrorEval.NAME_INVALID);
|
||||||
confirm(feA, c, "INDIRECT(#NUM!, #N/A)", ErrorEval.NUM_ERROR);
|
confirm(feA, c, "INDIRECT(#NUM!, #N/A)", ErrorEval.NUM_ERROR);
|
||||||
|
|
||||||
// arg1 is evaluated to boolean before arg0 is decoded
|
// arg1 is evaluated to boolean before arg0 is decoded
|
||||||
confirm(feA, c, "INDIRECT(\"garbage\", #N/A)", ErrorEval.NA);
|
confirm(feA, c, "INDIRECT(\"garbage\", #N/A)", ErrorEval.NA);
|
||||||
confirm(feA, c, "INDIRECT(\"garbage\", \"\")", ErrorEval.VALUE_INVALID); // empty string is not valid boolean
|
confirm(feA, c, "INDIRECT(\"garbage\", \"\")", ErrorEval.VALUE_INVALID); // empty string is not valid boolean
|
||||||
confirm(feA, c, "INDIRECT(\"garbage\", \"flase\")", ErrorEval.VALUE_INVALID); // must be "TRUE" or "FALSE"
|
confirm(feA, c, "INDIRECT(\"garbage\", \"flase\")", ErrorEval.VALUE_INVALID); // must be "TRUE" or "FALSE"
|
||||||
|
|
||||||
|
|
||||||
// spaces around sheet name (with or without quotes makes no difference)
|
// spaces around sheet name (with or without quotes makes no difference)
|
||||||
confirm(feA, c, "INDIRECT(\"'Sheet1 '!D3\")", ErrorEval.REF_INVALID);
|
confirm(feA, c, "INDIRECT(\"'Sheet1 '!D3\")", ErrorEval.REF_INVALID);
|
||||||
confirm(feA, c, "INDIRECT(\" Sheet1!D3\")", ErrorEval.REF_INVALID);
|
confirm(feA, c, "INDIRECT(\" Sheet1!D3\")", ErrorEval.REF_INVALID);
|
||||||
confirm(feA, c, "INDIRECT(\"'Sheet1' !D3\")", ErrorEval.REF_INVALID);
|
confirm(feA, c, "INDIRECT(\"'Sheet1' !D3\")", ErrorEval.REF_INVALID);
|
||||||
|
|
||||||
|
|
||||||
confirm(feA, c, "SUM(INDIRECT(\"'John's sales'!A1:C1\"))", ErrorEval.REF_INVALID); // bad quote escaping
|
confirm(feA, c, "SUM(INDIRECT(\"'John's sales'!A1:C1\"))", ErrorEval.REF_INVALID); // bad quote escaping
|
||||||
confirm(feA, c, "INDIRECT(\"[Book1]Sheet1!A1\")", ErrorEval.REF_INVALID); // unknown external workbook
|
confirm(feA, c, "INDIRECT(\"[Book1]Sheet1!A1\")", ErrorEval.REF_INVALID); // unknown external workbook
|
||||||
confirm(feA, c, "INDIRECT(\"Sheet3!A1\")", ErrorEval.REF_INVALID); // unknown sheet
|
confirm(feA, c, "INDIRECT(\"Sheet3!A1\")", ErrorEval.REF_INVALID); // unknown sheet
|
||||||
// if (false) { // TODO - support evaluation of defined names
|
// if (false) { // TODO - support evaluation of defined names
|
||||||
// confirm(feA, c, "INDIRECT(\"Sheet1!IW1\")", ErrorEval.REF_INVALID); // bad column
|
// confirm(feA, c, "INDIRECT(\"Sheet1!IW1\")", ErrorEval.REF_INVALID); // bad column
|
||||||
// confirm(feA, c, "INDIRECT(\"Sheet1!A65537\")", ErrorEval.REF_INVALID); // bad row
|
// confirm(feA, c, "INDIRECT(\"Sheet1!A65537\")", ErrorEval.REF_INVALID); // bad row
|
||||||
// }
|
// }
|
||||||
confirm(feA, c, "INDIRECT(\"Sheet1!A 1\")", ErrorEval.REF_INVALID); // space in cell ref
|
confirm(feA, c, "INDIRECT(\"Sheet1!A 1\")", ErrorEval.REF_INVALID); // space in cell ref
|
||||||
|
|
||||||
wbA.close();
|
wbA.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultipleWorkbooks() throws Exception {
|
public void testMultipleWorkbooks() throws Exception {
|
||||||
HSSFWorkbook wbA = createWBA();
|
HSSFWorkbook wbA = createWBA();
|
||||||
HSSFCell cellA = wbA.getSheetAt(0).createRow(10).createCell(0);
|
HSSFCell cellA = wbA.getSheetAt(0).createRow(10).createCell(0);
|
||||||
HSSFFormulaEvaluator feA = new HSSFFormulaEvaluator(wbA);
|
HSSFFormulaEvaluator feA = new HSSFFormulaEvaluator(wbA);
|
||||||
|
|
||||||
HSSFWorkbook wbB = createWBB();
|
HSSFWorkbook wbB = createWBB();
|
||||||
HSSFCell cellB = wbB.getSheetAt(0).createRow(10).createCell(0);
|
HSSFCell cellB = wbB.getSheetAt(0).createRow(10).createCell(0);
|
||||||
HSSFFormulaEvaluator feB = new HSSFFormulaEvaluator(wbB);
|
HSSFFormulaEvaluator feB = new HSSFFormulaEvaluator(wbB);
|
||||||
|
|
||||||
String[] workbookNames = { "MyBook", "Figures for January", };
|
String[] workbookNames = { "MyBook", "Figures for January", };
|
||||||
HSSFFormulaEvaluator[] evaluators = { feA, feB, };
|
HSSFFormulaEvaluator[] evaluators = { feA, feB, };
|
||||||
HSSFFormulaEvaluator.setupEnvironment(workbookNames, evaluators);
|
HSSFFormulaEvaluator.setupEnvironment(workbookNames, evaluators);
|
||||||
|
|
||||||
confirm(feB, cellB, "INDIRECT(\"'[Figures for January]## Look here!'!A1\")", 42); // same wb
|
confirm(feB, cellB, "INDIRECT(\"'[Figures for January]## Look here!'!A1\")", 42); // same wb
|
||||||
confirm(feA, cellA, "INDIRECT(\"'[Figures for January]## Look here!'!A1\")", 42); // across workbooks
|
confirm(feA, cellA, "INDIRECT(\"'[Figures for January]## Look here!'!A1\")", 42); // across workbooks
|
||||||
|
|
||||||
// 2 level recursion
|
// 2 level recursion
|
||||||
confirm(feB, cellB, "INDIRECT(\"[MyBook]Sheet2!A1\")", 50); // set up (and check) first level
|
confirm(feB, cellB, "INDIRECT(\"[MyBook]Sheet2!A1\")", 50); // set up (and check) first level
|
||||||
confirm(feA, cellA, "INDIRECT(\"'[Figures for January]Sheet1'!A11\")", 50); // points to cellB
|
confirm(feA, cellA, "INDIRECT(\"'[Figures for January]Sheet1'!A11\")", 50); // points to cellB
|
||||||
|
|
||||||
wbB.close();
|
wbB.close();
|
||||||
wbA.close();
|
wbA.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void confirm(FormulaEvaluator fe, Cell cell, String formula,
|
private static void confirm(FormulaEvaluator fe, Cell cell, String formula,
|
||||||
double expectedResult) {
|
double expectedResult) {
|
||||||
fe.clearAllCachedResultValues();
|
fe.clearAllCachedResultValues();
|
||||||
cell.setCellFormula(formula);
|
cell.setCellFormula(formula);
|
||||||
CellValue cv = fe.evaluate(cell);
|
CellValue cv = fe.evaluate(cell);
|
||||||
if (cv.getCellType() != Cell.CELL_TYPE_NUMERIC) {
|
if (cv.getCellType() != Cell.CELL_TYPE_NUMERIC) {
|
||||||
fail("expected numeric cell type but got " + cv.formatAsString());
|
fail("expected numeric cell type but got " + cv.formatAsString());
|
||||||
}
|
}
|
||||||
assertEquals(expectedResult, cv.getNumberValue(), 0.0);
|
assertEquals(expectedResult, cv.getNumberValue(), 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void confirm(FormulaEvaluator fe, Cell cell, String formula,
|
private static void confirm(FormulaEvaluator fe, Cell cell, String formula,
|
||||||
ErrorEval expectedResult) {
|
ErrorEval expectedResult) {
|
||||||
fe.clearAllCachedResultValues();
|
fe.clearAllCachedResultValues();
|
||||||
cell.setCellFormula(formula);
|
cell.setCellFormula(formula);
|
||||||
CellValue cv = fe.evaluate(cell);
|
CellValue cv = fe.evaluate(cell);
|
||||||
if (cv.getCellType() != Cell.CELL_TYPE_ERROR) {
|
if (cv.getCellType() != Cell.CELL_TYPE_ERROR) {
|
||||||
fail("expected error cell type but got " + cv.formatAsString());
|
fail("expected error cell type but got " + cv.formatAsString());
|
||||||
}
|
}
|
||||||
int expCode = expectedResult.getErrorCode();
|
int expCode = expectedResult.getErrorCode();
|
||||||
if (cv.getErrorValue() != expCode) {
|
if (cv.getErrorValue() != expCode) {
|
||||||
fail("Expected error '" + ErrorEval.getText(expCode)
|
fail("Expected error '" + ErrorEval.getText(expCode)
|
||||||
+ "' but got '" + cv.formatAsString() + "'.");
|
+ "' but got '" + cv.formatAsString() + "'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user