whitespace (tabs to spaces)

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/xssf_structured_references@1747625 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Javen O'Neal 2016-06-10 02:51:45 +00:00
parent 12a8f5b603
commit 1c2b9b3103
8 changed files with 1174 additions and 1174 deletions

View File

@ -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,

View File

@ -32,51 +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();
/** /**
* XSSF Only - gets a table that exists in the worksheet * XSSF Only - gets a table that exists in the worksheet
*/ */
Table getTable(String name); Table getTable(String name);
/** /**
* Return an external name (named range, function, user-defined function) Ptg * Return an external name (named range, function, user-defined function) Ptg
*/ */
Ptg getNameXPtg(String name, SheetIdentifier sheet); Ptg getNameXPtg(String name, SheetIdentifier sheet);
/** /**
* Produce the appropriate Ptg for a 3d cell reference * Produce the appropriate Ptg for a 3d cell reference
*/ */
Ptg get3DReferencePtg(CellReference cell, SheetIdentifier sheet); 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();
} }

View File

@ -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,7 +363,7 @@ 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
@ -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,10 +406,10 @@ 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() { public int getSheetIndex() {
return _sheetIndex; return _sheetIndex;
} }
private ValueEval getExternalNameXEval(ExternalName externName, String workbookName) { private ValueEval getExternalNameXEval(ExternalName externName, String workbookName) {
try { try {

File diff suppressed because it is too large Load Diff

View File

@ -49,78 +49,78 @@ 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(final OperationEvaluationContext ec, String text, private static ValueEval evaluateIndirect(final OperationEvaluationContext ec, String text,
boolean isA1style) { boolean isA1style) {
ec.getRowIndex(); ec.getRowIndex();
ec.getColumnIndex(); ec.getColumnIndex();
// Search backwards for '!' because sheet names can contain '!' // Search backwards for '!' because sheet names can contain '!'
int plingPos = text.lastIndexOf('!'); 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; String refStrPart1;
String refStrPart2; String refStrPart2;
if (Table.isStructuredReference.matcher(refText).matches()) { // The argument is structured reference if (Table.isStructuredReference.matcher(refText).matches()) { // The argument is structured reference
Area3DPxg areaPtg = null; Area3DPxg areaPtg = null;
try{ try{
@ -130,128 +130,128 @@ public final class Indirect implements FreeRefFunction {
} }
return ec.getArea3DEval(areaPtg); return ec.getArea3DEval(areaPtg);
} else { // The argumnet is regular reference } else { // The argumnet is regular reference
int colonPos = refText.indexOf(':'); int colonPos = refText.indexOf(':');
if (colonPos < 0) { if (colonPos < 0) {
refStrPart1 = refText.trim(); refStrPart1 = refText.trim();
refStrPart2 = null; refStrPart2 = null;
} else { } else {
refStrPart1 = refText.substring(0, colonPos).trim(); refStrPart1 = refText.substring(0, colonPos).trim();
refStrPart2 = refText.substring(colonPos + 1).trim(); refStrPart2 = refText.substring(colonPos + 1).trim();
} }
return ec.getDynamicReference(workbookName, sheetName, refStrPart1, refStrPart2, isA1style); return ec.getDynamicReference(workbookName, sheetName, refStrPart1, refStrPart2, isA1style);
} }
} }
/** /**
* @return array of length 2: {workbookName, sheetName,}. Second element will always be * @return array of length 2: {workbookName, sheetName,}. Second element will always be
* present. First element may be null if sheetName is unqualified. * present. First element may be null if sheetName is unqualified.
* Returns <code>null</code> if text cannot be parsed. * Returns <code>null</code> if text cannot be parsed.
*/ */
private static String[] parseWorkbookAndSheetName(CharSequence text) { private static String[] parseWorkbookAndSheetName(CharSequence text) {
int lastIx = text.length() - 1; int lastIx = text.length() - 1;
if (lastIx < 0) { if (lastIx < 0) {
return null; return null;
} }
if (canTrim(text)) { if (canTrim(text)) {
return null; return null;
} }
char firstChar = text.charAt(0); char firstChar = text.charAt(0);
if (Character.isWhitespace(firstChar)) { if (Character.isWhitespace(firstChar)) {
return null; return null;
} }
if (firstChar == '\'') { if (firstChar == '\'') {
// workbookName or sheetName needs quoting // workbookName or sheetName needs quoting
// quotes go around both // quotes go around both
if (text.charAt(lastIx) != '\'') { if (text.charAt(lastIx) != '\'') {
return null; return null;
} }
firstChar = text.charAt(1); firstChar = text.charAt(1);
if (Character.isWhitespace(firstChar)) { if (Character.isWhitespace(firstChar)) {
return null; return null;
} }
String wbName; String wbName;
int sheetStartPos; int sheetStartPos;
if (firstChar == '[') { if (firstChar == '[') {
int rbPos = text.toString().lastIndexOf(']'); int rbPos = text.toString().lastIndexOf(']');
if (rbPos < 0) { if (rbPos < 0) {
return null; return null;
} }
wbName = unescapeString(text.subSequence(2, rbPos)); wbName = unescapeString(text.subSequence(2, rbPos));
if (wbName == null || canTrim(wbName)) { if (wbName == null || canTrim(wbName)) {
return null; return null;
} }
sheetStartPos = rbPos + 1; sheetStartPos = rbPos + 1;
} else { } else {
wbName = null; wbName = null;
sheetStartPos = 1; sheetStartPos = 1;
} }
// else - just sheet name // else - just sheet name
String sheetName = unescapeString(text.subSequence(sheetStartPos, lastIx)); String sheetName = unescapeString(text.subSequence(sheetStartPos, lastIx));
if (sheetName == null) { // note - when quoted, sheetName can if (sheetName == null) { // note - when quoted, sheetName can
// start/end with whitespace // start/end with whitespace
return null; return null;
} }
return new String[] { wbName, sheetName, }; return new String[] { wbName, sheetName, };
} }
if (firstChar == '[') { if (firstChar == '[') {
int rbPos = text.toString().lastIndexOf(']'); int rbPos = text.toString().lastIndexOf(']');
if (rbPos < 0) { if (rbPos < 0) {
return null; return null;
} }
CharSequence wbName = text.subSequence(1, rbPos); CharSequence wbName = text.subSequence(1, rbPos);
if (canTrim(wbName)) { if (canTrim(wbName)) {
return null; return null;
} }
CharSequence sheetName = text.subSequence(rbPos + 1, text.length()); CharSequence sheetName = text.subSequence(rbPos + 1, text.length());
if (canTrim(sheetName)) { if (canTrim(sheetName)) {
return null; return null;
} }
return new String[] { wbName.toString(), sheetName.toString(), }; return new String[] { wbName.toString(), sheetName.toString(), };
} }
// else - just sheet name // else - just sheet name
return new String[] { null, text.toString(), }; return new String[] { null, text.toString(), };
} }
/** /**
* @return <code>null</code> if there is a syntax error in any escape sequence * @return <code>null</code> if there is a syntax error in any escape sequence
* (the typical syntax error is a single quote character not followed by another). * (the typical syntax error is a single quote character not followed by another).
*/ */
private static String unescapeString(CharSequence text) { private static String unescapeString(CharSequence text) {
int len = text.length(); int len = text.length();
StringBuilder sb = new StringBuilder(len); StringBuilder sb = new StringBuilder(len);
int i = 0; int i = 0;
while (i < len) { while (i < len) {
char ch = text.charAt(i); char ch = text.charAt(i);
if (ch == '\'') { if (ch == '\'') {
// every quote must be followed by another // every quote must be followed by another
i++; i++;
if (i >= len) { if (i >= len) {
return null; return null;
} }
ch = text.charAt(i); ch = text.charAt(i);
if (ch != '\'') { if (ch != '\'') {
return null; return null;
} }
} }
sb.append(ch); sb.append(ch);
i++; i++;
} }
return sb.toString(); return sb.toString();
} }
private static boolean canTrim(CharSequence text) { private static boolean canTrim(CharSequence text) {
int lastIx = text.length() - 1; int lastIx = text.length() - 1;
if (lastIx < 0) { if (lastIx < 0) {
return false; return false;
} }
if (Character.isWhitespace(text.charAt(0))) { if (Character.isWhitespace(text.charAt(0))) {
return true; return true;
} }
if (Character.isWhitespace(text.charAt(lastIx))) { if (Character.isWhitespace(text.charAt(lastIx))) {
return true; return true;
} }
return false; return false;
} }
} }

View File

@ -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
@ -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();
} }
} }
/** /**

View File

@ -1762,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){
@ -1929,7 +1929,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
*/ */
@Internal @Internal
public MapInfo getMapInfo(){ public MapInfo getMapInfo(){
return mapInfo; return mapInfo;
} }
/** /**
@ -1946,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
@ -2074,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()){

View File

@ -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;
} }
} }