git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@816016 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_5-FINAL
@@ -33,9 +33,7 @@ import org.apache.poi.util.StringUtil; | |||
* @author Libin Roman (Vista Portal LDT. Developer) | |||
* @author Sergei Kozello (sergeikozello at mail.ru) | |||
* @author Glen Stampoultzis (glens at apache.org) | |||
* @version 1.0-pre | |||
* | |||
* Modified 8/31/09 by Petr Udalau - added method setFunction(boolean) | |||
* @author Petr Udalau - added method setFunction(boolean) | |||
*/ | |||
public final class NameRecord extends StandardRecord { | |||
public final static short sid = 0x0018; | |||
@@ -135,7 +133,7 @@ public final class NameRecord extends StandardRecord { | |||
/** | |||
* For named ranges, and built-in names | |||
* @return the 1-based sheet number. | |||
* @return the 1-based sheet number. | |||
*/ | |||
public int getSheetNumber() | |||
{ | |||
@@ -239,13 +237,13 @@ public final class NameRecord extends StandardRecord { | |||
public boolean isFunctionName() { | |||
return (field_1_option_flag & Option.OPT_FUNCTION_NAME) != 0; | |||
} | |||
/** | |||
* Indicates that the defined name refers to a user-defined function. | |||
* This attribute is used when there is an add-in or other code project associated with the file. | |||
* | |||
* @param value <code>true</code> indicates the name refers to a function. | |||
*/ | |||
/** | |||
* Indicates that the defined name refers to a user-defined function. | |||
* This attribute is used when there is an add-in or other code project associated with the file. | |||
* | |||
* @param value <code>true</code> indicates the name refers to a function. | |||
*/ | |||
public void setFunction(boolean function){ | |||
if (function) { | |||
field_1_option_flag |= Option.OPT_FUNCTION_NAME; | |||
@@ -351,7 +349,7 @@ public final class NameRecord extends StandardRecord { | |||
int field_8_length_description_text = field_15_description_text.length(); | |||
int field_9_length_help_topic_text = field_16_help_topic_text.length(); | |||
int field_10_length_status_bar_text = field_17_status_bar_text.length(); | |||
// size defined below | |||
out.writeShort(getOptionFlag()); | |||
out.writeByte(getKeyboardShortcut()); | |||
@@ -379,7 +377,7 @@ public final class NameRecord extends StandardRecord { | |||
} | |||
field_13_name_definition.serializeTokens(out); | |||
field_13_name_definition.serializeArrayConstantData(out); | |||
StringUtil.putCompressedUnicode( getCustomMenuText(), out); | |||
StringUtil.putCompressedUnicode( getDescriptionText(), out); | |||
StringUtil.putCompressedUnicode( getHelpTopicText(), out); | |||
@@ -388,14 +386,14 @@ public final class NameRecord extends StandardRecord { | |||
private int getNameRawSize() { | |||
if (isBuiltInName()) { | |||
return 1; | |||
} | |||
} | |||
int nChars = field_12_name_text.length(); | |||
if(field_11_nameIsMultibyte) { | |||
return 2 * nChars; | |||
} | |||
} | |||
return nChars; | |||
} | |||
protected int getDataSize() { | |||
return 13 // 3 shorts + 7 bytes | |||
+ getNameRawSize() | |||
@@ -456,7 +454,7 @@ public final class NameRecord extends StandardRecord { | |||
} | |||
} | |||
int nBytesAvailable = in.available() - (f7_customMenuLen | |||
int nBytesAvailable = in.available() - (f7_customMenuLen | |||
+ f8_descriptionTextLen + f9_helpTopicTextLen + f10_statusBarTextLen); | |||
field_13_name_definition = Formula.read(field_4_length_name_definition, in, nBytesAvailable); | |||
@@ -22,14 +22,17 @@ import java.util.Map; | |||
import org.apache.poi.hssf.record.formula.eval.ValueEval; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
import org.apache.poi.hssf.record.formula.toolpack.ToolPack; | |||
import org.apache.poi.hssf.record.formula.udf.UDFFinder; | |||
import org.apache.poi.ss.formula.OperationEvaluationContext; | |||
import org.apache.poi.ss.formula.eval.NotImplementedException; | |||
/** | |||
* Modified 09/07/09 by Petr Udalau - systematized work of ToolPacks. | |||
* @author Josh Micich | |||
* @author Petr Udalau - systematized work of add-in libraries and user defined functions. | |||
*/ | |||
public final class AnalysisToolPak implements ToolPack { | |||
public final class AnalysisToolPak implements UDFFinder { | |||
public static final UDFFinder instance = new AnalysisToolPak(); | |||
private static final class NotImplemented implements FreeRefFunction { | |||
private final String _functionName; | |||
@@ -42,13 +45,18 @@ public final class AnalysisToolPak implements ToolPack { | |||
throw new NotImplementedException(_functionName); | |||
} | |||
}; | |||
private Map<String, FreeRefFunction> _functionsByName = createFunctionsMap(); | |||
private final Map<String, FreeRefFunction> _functionsByName = createFunctionsMap(); | |||
private AnalysisToolPak() { | |||
// enforce singleton | |||
} | |||
public FreeRefFunction findFunction(String name) { | |||
return _functionsByName.get(name); | |||
} | |||
private Map<String, FreeRefFunction> createFunctionsMap() { | |||
Map<String, FreeRefFunction> m = new HashMap<String, FreeRefFunction>(100); | |||
@@ -153,16 +161,4 @@ public final class AnalysisToolPak implements ToolPack { | |||
FreeRefFunction func = pFunc == null ? new NotImplemented(functionName) : pFunc; | |||
m.put(functionName, func); | |||
} | |||
public void addFunction(String name, FreeRefFunction evaluator) { | |||
r(_functionsByName, name, evaluator); | |||
} | |||
public boolean containsFunction(String name) { | |||
return _functionsByName.containsKey(name); | |||
} | |||
public void removeFunction(String name) { | |||
_functionsByName.remove(name); | |||
} | |||
} |
@@ -18,8 +18,6 @@ | |||
package org.apache.poi.hssf.record.formula.eval; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
import org.apache.poi.hssf.record.formula.toolpack.MainToolPacksHandler; | |||
import org.apache.poi.ss.formula.EvaluationWorkbook; | |||
import org.apache.poi.ss.formula.OperationEvaluationContext; | |||
import org.apache.poi.ss.formula.eval.NotImplementedException; | |||
/** | |||
@@ -28,8 +26,7 @@ import org.apache.poi.ss.formula.eval.NotImplementedException; | |||
* <tt>AbstractFunctionPtg.field_2_fnc_index</tt> == 255) | |||
* | |||
* @author Josh Micich | |||
* | |||
* Modified 09/07/09 by Petr Udalau - Improved resolving of UDFs through the ToolPacks. | |||
* @author Petr Udalau - Improved resolving of UDFs through the ToolPacks. | |||
*/ | |||
final class UserDefinedFunction implements FreeRefFunction { | |||
@@ -40,60 +37,28 @@ final class UserDefinedFunction implements FreeRefFunction { | |||
} | |||
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { | |||
EvaluationWorkbook workbook = ec.getWorkbook(); | |||
int nIncomingArgs = args.length; | |||
if(nIncomingArgs < 1) { | |||
throw new RuntimeException("function name argument missing"); | |||
} | |||
ValueEval nameArg = args[0]; | |||
FreeRefFunction targetFunc; | |||
String functionName; | |||
if (nameArg instanceof NameEval) { | |||
targetFunc = findInternalUserDefinedFunction(workbook, (NameEval) nameArg); | |||
functionName = ((NameEval) nameArg).getFunctionName(); | |||
} else if (nameArg instanceof NameXEval) { | |||
targetFunc = findExternalUserDefinedFunction(workbook, (NameXEval) nameArg); | |||
functionName = ec.getWorkbook().resolveNameXText(((NameXEval) nameArg).getPtg()); | |||
} else { | |||
throw new RuntimeException("First argument should be a NameEval, but got (" | |||
+ nameArg.getClass().getName() + ")"); | |||
} | |||
FreeRefFunction targetFunc = ec.findUserDefinedFunction(functionName); | |||
if (targetFunc == null) { | |||
throw new NotImplementedException(functionName); | |||
} | |||
int nOutGoingArgs = nIncomingArgs -1; | |||
ValueEval[] outGoingArgs = new ValueEval[nOutGoingArgs]; | |||
System.arraycopy(args, 1, outGoingArgs, 0, nOutGoingArgs); | |||
return targetFunc.evaluate(outGoingArgs, ec); | |||
} | |||
private static FreeRefFunction findExternalUserDefinedFunction(EvaluationWorkbook workbook, | |||
NameXEval n) { | |||
String functionName = workbook.resolveNameXText(n.getPtg()); | |||
if(false) { | |||
System.out.println("received call to external user defined function (" + functionName + ")"); | |||
} | |||
// currently only looking for functions from the 'Analysis TookPak'(contained in MainToolPacksHandler) e.g. "YEARFRAC" or "ISEVEN" | |||
// not sure how much this logic would need to change to support other or multiple add-ins. | |||
FreeRefFunction result = MainToolPacksHandler.instance().findFunction(functionName); | |||
if (result != null) { | |||
return result; | |||
} | |||
throw new NotImplementedException(functionName); | |||
} | |||
private static FreeRefFunction findInternalUserDefinedFunction(EvaluationWorkbook workbook, | |||
NameEval functionNameEval) { | |||
String functionName = functionNameEval.getFunctionName(); | |||
if(false) { | |||
System.out.println("received call to internal user defined function (" + functionName + ")"); | |||
} | |||
FreeRefFunction functionEvaluator = workbook.findUserDefinedFunction(functionName); | |||
if (functionEvaluator == null) { | |||
functionEvaluator = MainToolPacksHandler.instance().findFunction(functionName); | |||
} | |||
if (functionEvaluator != null) { | |||
return functionEvaluator; | |||
} | |||
// TODO find the implementation for the user defined function | |||
throw new NotImplementedException(functionName); | |||
} | |||
} |
@@ -1,102 +0,0 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.hssf.record.formula.toolpack; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.apache.poi.hssf.record.formula.atp.AnalysisToolPak; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
/** | |||
* Contains all tool packs. Processing of UDF is through this class. | |||
* | |||
* @author PUdalau | |||
*/ | |||
public class MainToolPacksHandler{ | |||
private DefaultToolPack defaultToolPack; | |||
private List<ToolPack> usedToolPacks = new ArrayList<ToolPack>(); | |||
private static MainToolPacksHandler instance; | |||
/** | |||
* @return Unique instance of handler. | |||
*/ | |||
public static MainToolPacksHandler instance() { | |||
if (instance == null) { | |||
instance = new MainToolPacksHandler(); | |||
} | |||
return instance; | |||
} | |||
/** | |||
* @return Default tool pack(which is obligatory exists in handler). | |||
*/ | |||
public DefaultToolPack getDefaultToolPack() { | |||
return defaultToolPack; | |||
} | |||
private MainToolPacksHandler() { | |||
defaultToolPack = new DefaultToolPack(); | |||
usedToolPacks.add(defaultToolPack); | |||
usedToolPacks.add(new AnalysisToolPak()); | |||
} | |||
/** | |||
* Checks if such function exists in any registered tool pack. | |||
* @param name Name of function. | |||
* @return true if some tool pack contains such function. | |||
*/ | |||
public boolean containsFunction(String name) { | |||
for (ToolPack pack : usedToolPacks) { | |||
if (pack.containsFunction(name)) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
/** | |||
* Returns executor by specified name. Returns <code>null</code> if | |||
* function isn't contained by any registered tool pack. | |||
* | |||
* @param name | |||
* Name of function. | |||
* @return Function executor. | |||
*/ | |||
public FreeRefFunction findFunction(String name) { | |||
FreeRefFunction evaluatorForFunction; | |||
for (ToolPack pack : usedToolPacks) { | |||
evaluatorForFunction = pack.findFunction(name); | |||
if (evaluatorForFunction != null) { | |||
return evaluatorForFunction; | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* Registers new tool pack in handler. | |||
* @param pack Tool pack to add. | |||
*/ | |||
public void addToolPack(ToolPack pack) { | |||
usedToolPacks.add(pack); | |||
} | |||
} |
@@ -0,0 +1,52 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.hssf.record.formula.udf; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
/** | |||
* Collects add-in libraries and VB macro functions together into one UDF finder | |||
* | |||
* @author PUdalau | |||
*/ | |||
public final class AggregatingUDFFinder implements UDFFinder { | |||
private final UDFFinder[] _usedToolPacks; | |||
public AggregatingUDFFinder(UDFFinder ... usedToolPacks) { | |||
_usedToolPacks = usedToolPacks.clone(); | |||
} | |||
/** | |||
* Returns executor by specified name. Returns <code>null</code> if | |||
* function isn't contained by any registered tool pack. | |||
* | |||
* @param name Name of function. | |||
* @return Function executor. <code>null</code> if not found | |||
*/ | |||
public FreeRefFunction findFunction(String name) { | |||
FreeRefFunction evaluatorForFunction; | |||
for (UDFFinder pack : _usedToolPacks) { | |||
evaluatorForFunction = pack.findFunction(name); | |||
if (evaluatorForFunction != null) { | |||
return evaluatorForFunction; | |||
} | |||
} | |||
return null; | |||
} | |||
} |
@@ -15,7 +15,7 @@ | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.hssf.record.formula.toolpack; | |||
package org.apache.poi.hssf.record.formula.udf; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
@@ -23,29 +23,27 @@ import java.util.Map; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
/** | |||
* Default tool pack. | |||
* If you want to add some UDF, but you don't want to create new tool pack, use this. | |||
* | |||
* Default UDF finder - for adding your own user defined functions. | |||
* | |||
* @author PUdalau | |||
*/ | |||
public class DefaultToolPack implements ToolPack { | |||
private Map<String, FreeRefFunction> functionsByName = new HashMap<String, FreeRefFunction>(); | |||
public void addFunction(String name, FreeRefFunction evaluator) { | |||
if (evaluator != null){ | |||
functionsByName.put(name, evaluator); | |||
} | |||
} | |||
public boolean containsFunction(String name) { | |||
return functionsByName.containsKey(name); | |||
} | |||
public FreeRefFunction findFunction(String name) { | |||
return functionsByName.get(name); | |||
} | |||
public void removeFunction(String name) { | |||
functionsByName.remove(name); | |||
} | |||
public final class DefaultUDFFinder implements UDFFinder { | |||
private final Map<String, FreeRefFunction> _functionsByName; | |||
public DefaultUDFFinder(String[] functionNames, FreeRefFunction[] functionImpls) { | |||
int nFuncs = functionNames.length; | |||
if (functionImpls.length != nFuncs) { | |||
throw new IllegalArgumentException( | |||
"Mismatch in number of function names and implementations"); | |||
} | |||
HashMap<String, FreeRefFunction> m = new HashMap<String, FreeRefFunction>(nFuncs * 3 / 2); | |||
for (int i = 0; i < functionImpls.length; i++) { | |||
m.put(functionNames[i], functionImpls[i]); | |||
} | |||
_functionsByName = m; | |||
} | |||
public FreeRefFunction findFunction(String name) { | |||
return _functionsByName.get(name); | |||
} | |||
} |
@@ -15,42 +15,24 @@ | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.hssf.record.formula.toolpack; | |||
package org.apache.poi.hssf.record.formula.udf; | |||
import org.apache.poi.hssf.record.formula.atp.AnalysisToolPak; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
/** | |||
* Common interface for any new tool pack with executors for functions. | |||
* | |||
* Common interface for "Add-in" libraries and user defined function libraries. | |||
* | |||
* @author PUdalau | |||
*/ | |||
public interface ToolPack { | |||
public interface UDFFinder { | |||
public static final UDFFinder DEFAULT = new AggregatingUDFFinder(AnalysisToolPak.instance); | |||
/** | |||
* Returns executor by specified name. Returns <code>null</code> if tool | |||
* pack doesn't contains such function. | |||
* | |||
* Returns executor by specified name. Returns <code>null</code> if the function name is unknown. | |||
* | |||
* @param name Name of function. | |||
* @return Function executor. | |||
*/ | |||
FreeRefFunction findFunction(String name); | |||
/** | |||
* Add new function with executor. | |||
* @param name Name of function. | |||
* @param evaluator Function executor. | |||
*/ | |||
void addFunction(String name, FreeRefFunction evaluator); | |||
/** | |||
* Returns executor by specified name if it exists. | |||
* @param name Name of function. | |||
*/ | |||
void removeFunction(String name); | |||
/** | |||
* Checks if such function exists in tool pack. | |||
* @param name Name of function. | |||
* @return true if tool pack contains such function. | |||
*/ | |||
boolean containsFunction(String name); | |||
} |
@@ -6,7 +6,7 @@ | |||
(the "License"); you may not use this file except in compliance with | |||
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 | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
@@ -24,146 +24,145 @@ import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate; | |||
import org.apache.poi.hssf.record.formula.NamePtg; | |||
import org.apache.poi.hssf.record.formula.NameXPtg; | |||
import org.apache.poi.hssf.record.formula.Ptg; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
import org.apache.poi.ss.formula.*; | |||
import org.apache.poi.ss.SpreadsheetVersion; | |||
import org.apache.poi.ss.formula.EvaluationCell; | |||
import org.apache.poi.ss.formula.EvaluationName; | |||
import org.apache.poi.ss.formula.EvaluationSheet; | |||
import org.apache.poi.ss.formula.EvaluationWorkbook; | |||
import org.apache.poi.ss.formula.FormulaParsingWorkbook; | |||
import org.apache.poi.ss.formula.FormulaRenderingWorkbook; | |||
import org.apache.poi.ss.formula.FormulaType; | |||
/** | |||
* Internal POI use only | |||
* | |||
* @author Josh Micich | |||
* | |||
* Modified 09/07/09 by Petr Udalau - added methods for searching for UDFs of this Workbook. | |||
*/ | |||
public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, EvaluationWorkbook, FormulaParsingWorkbook { | |||
private final HSSFWorkbook _uBook; | |||
private final Workbook _iBook; | |||
public static HSSFEvaluationWorkbook create(HSSFWorkbook book) { | |||
if (book == null) { | |||
return null; | |||
} | |||
return new HSSFEvaluationWorkbook(book); | |||
} | |||
private HSSFEvaluationWorkbook(HSSFWorkbook book) { | |||
_uBook = book; | |||
_iBook = book.getWorkbook(); | |||
} | |||
public int getExternalSheetIndex(String sheetName) { | |||
int sheetIndex = _uBook.getSheetIndex(sheetName); | |||
return _iBook.checkExternSheet(sheetIndex); | |||
} | |||
public int getExternalSheetIndex(String workbookName, String sheetName) { | |||
return _iBook.getExternalSheetIndex(workbookName, sheetName); | |||
} | |||
public NameXPtg getNameXPtg(String name) { | |||
return _iBook.getNameXPtg(name); | |||
} | |||
/** | |||
* Lookup a named range by its name. | |||
* | |||
* @param name the name to search | |||
* @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 workbook-global names | |||
*/ | |||
public EvaluationName getName(String name, int sheetIndex) { | |||
for(int i=0; i < _iBook.getNumNames(); i++) { | |||
NameRecord nr = _iBook.getNameRecord(i); | |||
if (nr.getSheetNumber() == sheetIndex+1 && name.equalsIgnoreCase(nr.getNameText())) { | |||
return new Name(nr, i); | |||
} | |||
} | |||
return sheetIndex == -1 ? null : getName(name, -1); | |||
} | |||
public int getSheetIndex(EvaluationSheet evalSheet) { | |||
HSSFSheet sheet = ((HSSFEvaluationSheet)evalSheet).getHSSFSheet(); | |||
return _uBook.getSheetIndex(sheet); | |||
} | |||
public int getSheetIndex(String sheetName) { | |||
return _uBook.getSheetIndex(sheetName); | |||
} | |||
public String getSheetName(int sheetIndex) { | |||
return _uBook.getSheetName(sheetIndex); | |||
} | |||
public EvaluationSheet getSheet(int sheetIndex) { | |||
return new HSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex)); | |||
} | |||
public int convertFromExternSheetIndex(int externSheetIndex) { | |||
return _iBook.getSheetIndexFromExternSheetIndex(externSheetIndex); | |||
} | |||
public ExternalSheet getExternalSheet(int externSheetIndex) { | |||
return _iBook.getExternalSheet(externSheetIndex); | |||
} | |||
public String resolveNameXText(NameXPtg n) { | |||
return _iBook.resolveNameXText(n.getSheetRefIndex(), n.getNameIndex()); | |||
} | |||
public String getSheetNameByExternSheet(int externSheetIndex) { | |||
return _iBook.findSheetNameFromExternSheet(externSheetIndex); | |||
} | |||
public String getNameText(NamePtg namePtg) { | |||
return _iBook.getNameRecord(namePtg.getIndex()).getNameText(); | |||
} | |||
public EvaluationName getName(NamePtg namePtg) { | |||
int ix = namePtg.getIndex(); | |||
return new Name(_iBook.getNameRecord(ix), ix); | |||
} | |||
public Ptg[] getFormulaTokens(EvaluationCell evalCell) { | |||
HSSFCell cell = ((HSSFEvaluationCell)evalCell).getHSSFCell(); | |||
if (false) { | |||
// re-parsing the formula text also works, but is a waste of time | |||
// It is useful from time to time to run all unit tests with this code | |||
// to make sure that all formulas POI can evaluate can also be parsed. | |||
return HSSFFormulaParser.parse(cell.getCellFormula(), _uBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet())); | |||
} | |||
FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord(); | |||
return fra.getFormulaTokens(); | |||
} | |||
private static final class Name implements EvaluationName { | |||
private final NameRecord _nameRecord; | |||
private final int _index; | |||
public Name(NameRecord nameRecord, int index) { | |||
_nameRecord = nameRecord; | |||
_index = index; | |||
} | |||
public Ptg[] getNameDefinition() { | |||
return _nameRecord.getNameDefinition(); | |||
} | |||
public String getNameText() { | |||
return _nameRecord.getNameText(); | |||
} | |||
public boolean hasFormula() { | |||
return _nameRecord.hasFormula(); | |||
} | |||
public boolean isFunctionName() { | |||
return _nameRecord.isFunctionName(); | |||
} | |||
public boolean isRange() { | |||
return _nameRecord.hasFormula(); // TODO - is this right? | |||
} | |||
public NamePtg createPtg() { | |||
return new NamePtg(_index); | |||
} | |||
} | |||
public SpreadsheetVersion getSpreadsheetVersion(){ | |||
return SpreadsheetVersion.EXCEL97; | |||
} | |||
public FreeRefFunction findUserDefinedFunction(String functionName) { | |||
return _uBook.getUserDefinedFunction(functionName); | |||
} | |||
private final HSSFWorkbook _uBook; | |||
private final Workbook _iBook; | |||
public static HSSFEvaluationWorkbook create(HSSFWorkbook book) { | |||
if (book == null) { | |||
return null; | |||
} | |||
return new HSSFEvaluationWorkbook(book); | |||
} | |||
private HSSFEvaluationWorkbook(HSSFWorkbook book) { | |||
_uBook = book; | |||
_iBook = book.getWorkbook(); | |||
} | |||
public int getExternalSheetIndex(String sheetName) { | |||
int sheetIndex = _uBook.getSheetIndex(sheetName); | |||
return _iBook.checkExternSheet(sheetIndex); | |||
} | |||
public int getExternalSheetIndex(String workbookName, String sheetName) { | |||
return _iBook.getExternalSheetIndex(workbookName, sheetName); | |||
} | |||
public NameXPtg getNameXPtg(String name) { | |||
return _iBook.getNameXPtg(name); | |||
} | |||
/** | |||
* Lookup a named range by its name. | |||
* | |||
* @param name the name to search | |||
* @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 workbook-global names | |||
*/ | |||
public EvaluationName getName(String name, int sheetIndex) { | |||
for(int i=0; i < _iBook.getNumNames(); i++) { | |||
NameRecord nr = _iBook.getNameRecord(i); | |||
if (nr.getSheetNumber() == sheetIndex+1 && name.equalsIgnoreCase(nr.getNameText())) { | |||
return new Name(nr, i); | |||
} | |||
} | |||
return sheetIndex == -1 ? null : getName(name, -1); | |||
} | |||
public int getSheetIndex(EvaluationSheet evalSheet) { | |||
HSSFSheet sheet = ((HSSFEvaluationSheet)evalSheet).getHSSFSheet(); | |||
return _uBook.getSheetIndex(sheet); | |||
} | |||
public int getSheetIndex(String sheetName) { | |||
return _uBook.getSheetIndex(sheetName); | |||
} | |||
public String getSheetName(int sheetIndex) { | |||
return _uBook.getSheetName(sheetIndex); | |||
} | |||
public EvaluationSheet getSheet(int sheetIndex) { | |||
return new HSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex)); | |||
} | |||
public int convertFromExternSheetIndex(int externSheetIndex) { | |||
return _iBook.getSheetIndexFromExternSheetIndex(externSheetIndex); | |||
} | |||
public ExternalSheet getExternalSheet(int externSheetIndex) { | |||
return _iBook.getExternalSheet(externSheetIndex); | |||
} | |||
public String resolveNameXText(NameXPtg n) { | |||
return _iBook.resolveNameXText(n.getSheetRefIndex(), n.getNameIndex()); | |||
} | |||
public String getSheetNameByExternSheet(int externSheetIndex) { | |||
return _iBook.findSheetNameFromExternSheet(externSheetIndex); | |||
} | |||
public String getNameText(NamePtg namePtg) { | |||
return _iBook.getNameRecord(namePtg.getIndex()).getNameText(); | |||
} | |||
public EvaluationName getName(NamePtg namePtg) { | |||
int ix = namePtg.getIndex(); | |||
return new Name(_iBook.getNameRecord(ix), ix); | |||
} | |||
public Ptg[] getFormulaTokens(EvaluationCell evalCell) { | |||
HSSFCell cell = ((HSSFEvaluationCell)evalCell).getHSSFCell(); | |||
if (false) { | |||
// re-parsing the formula text also works, but is a waste of time | |||
// It is useful from time to time to run all unit tests with this code | |||
// to make sure that all formulas POI can evaluate can also be parsed. | |||
return HSSFFormulaParser.parse(cell.getCellFormula(), _uBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet())); | |||
} | |||
FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord(); | |||
return fra.getFormulaTokens(); | |||
} | |||
private static final class Name implements EvaluationName { | |||
private final NameRecord _nameRecord; | |||
private final int _index; | |||
public Name(NameRecord nameRecord, int index) { | |||
_nameRecord = nameRecord; | |||
_index = index; | |||
} | |||
public Ptg[] getNameDefinition() { | |||
return _nameRecord.getNameDefinition(); | |||
} | |||
public String getNameText() { | |||
return _nameRecord.getNameText(); | |||
} | |||
public boolean hasFormula() { | |||
return _nameRecord.hasFormula(); | |||
} | |||
public boolean isFunctionName() { | |||
return _nameRecord.isFunctionName(); | |||
} | |||
public boolean isRange() { | |||
return _nameRecord.hasFormula(); // TODO - is this right? | |||
} | |||
public NamePtg createPtg() { | |||
return new NamePtg(_index); | |||
} | |||
} | |||
public SpreadsheetVersion getSpreadsheetVersion(){ | |||
return SpreadsheetVersion.EXCEL97; | |||
} | |||
} |
@@ -24,6 +24,7 @@ import org.apache.poi.hssf.record.formula.eval.ErrorEval; | |||
import org.apache.poi.hssf.record.formula.eval.NumberEval; | |||
import org.apache.poi.hssf.record.formula.eval.StringEval; | |||
import org.apache.poi.hssf.record.formula.eval.ValueEval; | |||
import org.apache.poi.hssf.record.formula.udf.UDFFinder; | |||
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment; | |||
import org.apache.poi.ss.formula.IStabilityClassifier; | |||
import org.apache.poi.ss.formula.WorkbookEvaluator; | |||
@@ -64,9 +65,27 @@ public class HSSFFormulaEvaluator implements FormulaEvaluator { | |||
* evaluation begins. | |||
*/ | |||
public HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier) { | |||
_bookEvaluator = new WorkbookEvaluator(HSSFEvaluationWorkbook.create(workbook), stabilityClassifier); | |||
this(workbook, stabilityClassifier, null); | |||
} | |||
/** | |||
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only) | |||
*/ | |||
private HSSFFormulaEvaluator(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) { | |||
_bookEvaluator = new WorkbookEvaluator(HSSFEvaluationWorkbook.create(workbook), stabilityClassifier, udfFinder); | |||
} | |||
/** | |||
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code> | |||
* for the (conservative) assumption that any cell may have its definition changed after | |||
* evaluation begins. | |||
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only) | |||
*/ | |||
public static HSSFFormulaEvaluator create(HSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) { | |||
return new HSSFFormulaEvaluator(workbook, stabilityClassifier, udfFinder); | |||
} | |||
/** | |||
* Coordinates several formula evaluators together so that formulas that involve external | |||
* references can be evaluated. |
@@ -24,11 +24,9 @@ import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.io.PrintWriter; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.Hashtable; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.regex.Pattern; | |||
import org.apache.poi.POIDocument; | |||
@@ -64,12 +62,10 @@ import org.apache.poi.hssf.record.formula.Ptg; | |||
import org.apache.poi.hssf.record.formula.Ref3DPtg; | |||
import org.apache.poi.hssf.record.formula.SheetNameFormatter; | |||
import org.apache.poi.hssf.record.formula.UnionPtg; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
import org.apache.poi.hssf.util.CellReference; | |||
import org.apache.poi.poifs.filesystem.DirectoryNode; | |||
import org.apache.poi.poifs.filesystem.POIFSFileSystem; | |||
import org.apache.poi.ss.usermodel.CreationHelper; | |||
import org.apache.poi.ss.usermodel.Name; | |||
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; | |||
import org.apache.poi.ss.formula.FormulaType; | |||
import org.apache.poi.util.POILogFactory; | |||
@@ -86,9 +82,6 @@ import org.apache.poi.util.POILogger; | |||
* @author Andrew C. Oliver (acoliver at apache dot org) | |||
* @author Glen Stampoultzis (glens at apache.org) | |||
* @author Shawn Laubach (slaubach at apache dot org) | |||
* | |||
* | |||
* Modified 09/07/09 by Petr Udalau - added methods for work with UDFs of this Workbook. | |||
*/ | |||
public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook { | |||
private static final Pattern COMMA_PATTERN = Pattern.compile(","); | |||
@@ -167,9 +160,6 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
private static POILogger log = POILogFactory.getLogger(HSSFWorkbook.class); | |||
/** Map of user defined functions, key - function name, value - instance of FreeRefFunctions */ | |||
private Map<String, FreeRefFunction> udfFunctions; | |||
/** | |||
* Creates new HSSFWorkbook from scratch (start here!) | |||
@@ -186,7 +176,6 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
workbook = book; | |||
_sheets = new ArrayList( INITIAL_CAPACITY ); | |||
names = new ArrayList( INITIAL_CAPACITY ); | |||
udfFunctions = new HashMap<String, FreeRefFunction>(); | |||
} | |||
public HSSFWorkbook(POIFSFileSystem fs) throws IOException { | |||
@@ -278,7 +267,6 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
_sheets = new ArrayList(INITIAL_CAPACITY); | |||
names = new ArrayList(INITIAL_CAPACITY); | |||
udfFunctions = new HashMap<String, FreeRefFunction>(); | |||
// Grab the data from the workbook stream, however | |||
// it happens to be spelled. | |||
@@ -1627,25 +1615,6 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
} | |||
} | |||
} | |||
public FreeRefFunction getUserDefinedFunction(String functionName) { | |||
return udfFunctions.get(functionName); | |||
} | |||
public void registerUserDefinedFunction(String functionName, FreeRefFunction freeRefFunction) { | |||
Name udfDeclaration = getName(functionName); | |||
if (udfDeclaration == null) { | |||
udfDeclaration = createName(); | |||
} | |||
udfDeclaration.setNameName(functionName); | |||
udfDeclaration.setFunction(true); | |||
udfFunctions.put(functionName, freeRefFunction); | |||
} | |||
public List<String> getUserDefinedFunctionNames() { | |||
return new ArrayList<String>(udfFunctions.keySet()); | |||
} | |||
/** | |||
* Is the workbook protected with a password (not encrypted)? | |||
@@ -1729,5 +1698,4 @@ public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.userm | |||
public NameXPtg getNameXPtg(String name) { | |||
return workbook.getNameXPtg(name); | |||
} | |||
} |
@@ -20,7 +20,6 @@ package org.apache.poi.ss.formula; | |||
import org.apache.poi.hssf.record.formula.NamePtg; | |||
import org.apache.poi.hssf.record.formula.NameXPtg; | |||
import org.apache.poi.hssf.record.formula.Ptg; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
/** | |||
* Abstracts a workbook for the purpose of formula evaluation.<br/> | |||
@@ -28,8 +27,6 @@ import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
* For POI internal use only | |||
* | |||
* @author Josh Micich | |||
* | |||
* Modified 09/07/09 by Petr Udalau - added methods for searching for UDFs of this Workbook. | |||
*/ | |||
public interface EvaluationWorkbook { | |||
String getSheetName(int sheetIndex); | |||
@@ -54,17 +51,6 @@ public interface EvaluationWorkbook { | |||
String resolveNameXText(NameXPtg ptg); | |||
Ptg[] getFormulaTokens(EvaluationCell cell); | |||
/** | |||
* Find and return user defined function (UDF) contained by workbook with | |||
* specified name. | |||
* | |||
* @param functionName UDF name | |||
* @return instance of FreeRefFunction or null if no UDF with the specified | |||
* name exists. | |||
*/ | |||
FreeRefFunction findUserDefinedFunction(String functionName); | |||
class ExternalSheet { | |||
private final String _workbookName; | |||
private final String _sheetName; |
@@ -22,6 +22,7 @@ import org.apache.poi.hssf.record.formula.eval.AreaEval; | |||
import org.apache.poi.hssf.record.formula.eval.ErrorEval; | |||
import org.apache.poi.hssf.record.formula.eval.RefEval; | |||
import org.apache.poi.hssf.record.formula.eval.ValueEval; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
import org.apache.poi.ss.SpreadsheetVersion; | |||
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException; | |||
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet; | |||
@@ -256,4 +257,8 @@ public final class OperationEvaluationContext { | |||
} | |||
return CellReference.classifyCellReference(str, ssVersion); | |||
} | |||
public FreeRefFunction findUserDefinedFunction(String functionName) { | |||
return _bookEvaluator.findUserDefinedFunction(functionName); | |||
} | |||
} |
@@ -59,6 +59,8 @@ import org.apache.poi.hssf.record.formula.eval.OperationEval; | |||
import org.apache.poi.hssf.record.formula.eval.RefEval; | |||
import org.apache.poi.hssf.record.formula.eval.StringEval; | |||
import org.apache.poi.hssf.record.formula.eval.ValueEval; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
import org.apache.poi.hssf.record.formula.udf.UDFFinder; | |||
import org.apache.poi.hssf.util.CellReference; | |||
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException; | |||
import org.apache.poi.ss.formula.eval.NotImplementedException; | |||
@@ -87,12 +89,16 @@ public final class WorkbookEvaluator { | |||
private final Map<String, Integer> _sheetIndexesByName; | |||
private CollaboratingWorkbooksEnvironment _collaboratingWorkbookEnvironment; | |||
private final IStabilityClassifier _stabilityClassifier; | |||
private final UDFFinder _udfFinder; | |||
public WorkbookEvaluator(EvaluationWorkbook workbook, IStabilityClassifier stabilityClassifier) { | |||
this (workbook, null, stabilityClassifier); | |||
/** | |||
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only) | |||
*/ | |||
public WorkbookEvaluator(EvaluationWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) { | |||
this (workbook, null, stabilityClassifier, udfFinder); | |||
} | |||
/* package */ WorkbookEvaluator(EvaluationWorkbook workbook, IEvaluationListener evaluationListener, | |||
IStabilityClassifier stabilityClassifier) { | |||
IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) { | |||
_workbook = workbook; | |||
_evaluationListener = evaluationListener; | |||
_cache = new EvaluationCache(evaluationListener); | |||
@@ -101,6 +107,7 @@ public final class WorkbookEvaluator { | |||
_collaboratingWorkbookEnvironment = CollaboratingWorkbooksEnvironment.EMPTY; | |||
_workbookIx = 0; | |||
_stabilityClassifier = stabilityClassifier; | |||
_udfFinder = udfFinder == null ? UDFFinder.DEFAULT : udfFinder; | |||
} | |||
/** | |||
@@ -516,4 +523,7 @@ public final class WorkbookEvaluator { | |||
EvaluationCell cell = sheet.getCell(rowIndex, columnIndex); | |||
return evaluateAny(cell, sheetIndex, rowIndex, columnIndex, tracker); | |||
} | |||
public FreeRefFunction findUserDefinedFunction(String functionName) { | |||
return _udfFinder.findFunction(functionName); | |||
} | |||
} |
@@ -36,8 +36,6 @@ import org.apache.poi.ss.usermodel.Workbook; | |||
* updated after a call to {@link #getOrCreateUpdatableCell(String, int, int)}. | |||
* | |||
* @author Josh Micich | |||
* | |||
* Modified 09/07/09 by Petr Udalau - added methods for searching for UDFs of this Workbook. | |||
*/ | |||
final class ForkedEvaluationWorkbook implements EvaluationWorkbook { | |||
@@ -144,8 +142,4 @@ final class ForkedEvaluationWorkbook implements EvaluationWorkbook { | |||
return _index - o._index; | |||
} | |||
} | |||
public FreeRefFunction findUserDefinedFunction(String functionName) { | |||
return _masterBook.findUserDefinedFunction(functionName); | |||
} | |||
} |
@@ -22,6 +22,7 @@ import org.apache.poi.hssf.record.formula.eval.ErrorEval; | |||
import org.apache.poi.hssf.record.formula.eval.NumberEval; | |||
import org.apache.poi.hssf.record.formula.eval.StringEval; | |||
import org.apache.poi.hssf.record.formula.eval.ValueEval; | |||
import org.apache.poi.hssf.record.formula.udf.UDFFinder; | |||
import org.apache.poi.hssf.usermodel.HSSFCell; | |||
import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook; | |||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
@@ -47,9 +48,9 @@ public final class ForkedEvaluator { | |||
private WorkbookEvaluator _evaluator; | |||
private ForkedEvaluationWorkbook _sewb; | |||
private ForkedEvaluator(EvaluationWorkbook masterWorkbook, IStabilityClassifier stabilityClassifier) { | |||
private ForkedEvaluator(EvaluationWorkbook masterWorkbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) { | |||
_sewb = new ForkedEvaluationWorkbook(masterWorkbook); | |||
_evaluator = new WorkbookEvaluator(_sewb, stabilityClassifier); | |||
_evaluator = new WorkbookEvaluator(_sewb, stabilityClassifier, udfFinder); | |||
} | |||
private static EvaluationWorkbook createEvaluationWorkbook(Workbook wb) { | |||
if (wb instanceof HSSFWorkbook) { | |||
@@ -61,8 +62,17 @@ public final class ForkedEvaluator { | |||
// } | |||
throw new IllegalArgumentException("Unexpected workbook type (" + wb.getClass().getName() + ")"); | |||
} | |||
/** | |||
* @deprecated (Sep 2009) (reduce overloading) use {@link #create(Workbook, IStabilityClassifier, UDFFinder)} | |||
*/ | |||
public static ForkedEvaluator create(Workbook wb, IStabilityClassifier stabilityClassifier) { | |||
return new ForkedEvaluator(createEvaluationWorkbook(wb), stabilityClassifier); | |||
return create(wb, stabilityClassifier, null); | |||
} | |||
/** | |||
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only) | |||
*/ | |||
public static ForkedEvaluator create(Workbook wb, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) { | |||
return new ForkedEvaluator(createEvaluationWorkbook(wb), stabilityClassifier, udfFinder); | |||
} | |||
/** |
@@ -49,8 +49,6 @@ package org.apache.poi.ss.usermodel; | |||
* name.setRefersToFormula("IF(Loan_Amount*Interest_Rate>0,1,0)"); | |||
* | |||
* </blockquote></pre> | |||
* | |||
* Modified 8/31/09 by Petr Udalau - added method setFunction(boolean) | |||
*/ | |||
public interface Name { | |||
@@ -61,14 +59,14 @@ public interface Name { | |||
*/ | |||
String getSheetName(); | |||
/** | |||
/** | |||
* Gets the name of the named range | |||
* | |||
* @return named range name | |||
*/ | |||
String getNameName(); | |||
/** | |||
/** | |||
* Sets the name of the named range | |||
* | |||
* <p>The following is a list of syntax rules that you need to be aware of when you create and edit names.</p> | |||
@@ -118,7 +116,7 @@ public interface Name { | |||
void setNameName(String name); | |||
/** | |||
* Returns the formula that the name is defined to refer to. | |||
* Returns the formula that the name is defined to refer to. | |||
* | |||
* @return the reference for this name, <code>null</code> if it has not been set yet. Never empty string | |||
* @see #setRefersToFormula(String) |
@@ -21,15 +21,12 @@ import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.util.List; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; | |||
/** | |||
* High level representation of a Excel workbook. This is the first object most users | |||
* will construct whether they are reading or writing a workbook. It is also the | |||
* top level object for creating new sheets/etc. | |||
* | |||
* Modified 09/07/09 by Petr Udalau - added methods for work with UDFs of this Workbook. | |||
*/ | |||
public interface Workbook { | |||
@@ -189,7 +186,7 @@ public interface Workbook { | |||
* @param index of the sheet to remove (0-based) | |||
*/ | |||
void removeSheetAt(int index); | |||
/** | |||
* Sets the repeating rows and columns for a sheet (as found in | |||
* File->PageSetup->Sheet). This is function is included in the workbook | |||
@@ -374,7 +371,7 @@ public interface Workbook { | |||
* Sets the policy on what to do when | |||
* getting missing or blank cells from a row. | |||
* | |||
* This will then apply to all calls to | |||
* This will then apply to all calls to | |||
* {@link Row#getCell(int)} }. See | |||
* {@link MissingCellPolicy} | |||
*/ | |||
@@ -467,29 +464,4 @@ public interface Workbook { | |||
* @param hidden 0 for not hidden, 1 for hidden, 2 for very hidden | |||
*/ | |||
void setSheetHidden(int sheetIx, int hidden); | |||
/** | |||
* Find and return user defined function (UDF) with specified name. | |||
* | |||
* @param functionName | |||
* UDF name | |||
* @return instance of FreeRefFunction or null if no UDF with the specified | |||
* name exists. | |||
*/ | |||
FreeRefFunction getUserDefinedFunction(String functionName); | |||
/** | |||
* Add user defined function (UDF) to workbook | |||
* | |||
* @param name | |||
* @param function | |||
*/ | |||
void registerUserDefinedFunction(String name, FreeRefFunction function); | |||
/** | |||
* Returns user defined functions (UDF) names | |||
* | |||
* @return list of UDF names | |||
*/ | |||
List<String> getUserDefinedFunctionNames(); | |||
} |
@@ -20,7 +20,6 @@ package org.apache.poi.xssf.usermodel; | |||
import org.apache.poi.hssf.record.formula.NamePtg; | |||
import org.apache.poi.hssf.record.formula.NameXPtg; | |||
import org.apache.poi.hssf.record.formula.Ptg; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
import org.apache.poi.ss.formula.*; | |||
import org.apache.poi.ss.SpreadsheetVersion; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName; | |||
@@ -29,8 +28,6 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName; | |||
* Internal POI use only | |||
* | |||
* @author Josh Micich | |||
* | |||
* Modified 09/07/09 by Petr Udalau - added methods for searching for UDFs of this Workbook. | |||
*/ | |||
public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, EvaluationWorkbook, FormulaParsingWorkbook { | |||
@@ -180,8 +177,4 @@ public final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, E | |||
public SpreadsheetVersion getSpreadsheetVersion(){ | |||
return SpreadsheetVersion.EXCEL2007; | |||
} | |||
public FreeRefFunction findUserDefinedFunction(String functionName) { | |||
return _uBook.getUserDefinedFunction(functionName); | |||
} | |||
} |
@@ -24,6 +24,8 @@ import org.apache.poi.hssf.record.formula.eval.ErrorEval; | |||
import org.apache.poi.hssf.record.formula.eval.NumberEval; | |||
import org.apache.poi.hssf.record.formula.eval.StringEval; | |||
import org.apache.poi.hssf.record.formula.eval.ValueEval; | |||
import org.apache.poi.hssf.record.formula.udf.UDFFinder; | |||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
import org.apache.poi.ss.formula.IStabilityClassifier; | |||
import org.apache.poi.ss.formula.WorkbookEvaluator; | |||
import org.apache.poi.ss.usermodel.Cell; | |||
@@ -47,16 +49,31 @@ public class XSSFFormulaEvaluator implements FormulaEvaluator { | |||
private WorkbookEvaluator _bookEvaluator; | |||
public XSSFFormulaEvaluator(XSSFWorkbook workbook) { | |||
this(workbook, null); | |||
this(workbook, null, null); | |||
} | |||
/** | |||
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code> | |||
* for the (conservative) assumption that any cell may have its definition changed after | |||
* for the (conservative) assumption that any cell may have its definition changed after | |||
* evaluation begins. | |||
* @deprecated (Sep 2009) (reduce overloading) use {@link #create(HSSFWorkbook, IStabilityClassifier, UDFFinder)} | |||
*/ | |||
public XSSFFormulaEvaluator(XSSFWorkbook workbook, IStabilityClassifier stabilityClassifier) { | |||
_bookEvaluator = new WorkbookEvaluator(XSSFEvaluationWorkbook.create(workbook), stabilityClassifier); | |||
_bookEvaluator = new WorkbookEvaluator(XSSFEvaluationWorkbook.create(workbook), stabilityClassifier, null); | |||
} | |||
private XSSFFormulaEvaluator(XSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) { | |||
_bookEvaluator = new WorkbookEvaluator(XSSFEvaluationWorkbook.create(workbook), stabilityClassifier, udfFinder); | |||
} | |||
/** | |||
* @param stabilityClassifier used to optimise caching performance. Pass <code>null</code> | |||
* for the (conservative) assumption that any cell may have its definition changed after | |||
* evaluation begins. | |||
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only) | |||
*/ | |||
public static XSSFFormulaEvaluator create(XSSFWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) { | |||
return new XSSFFormulaEvaluator(workbook, stabilityClassifier, udfFinder); | |||
} | |||
/** | |||
* Should be called whenever there are major changes (e.g. moving sheets) to input cells |
@@ -32,7 +32,6 @@ import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.POIXMLException; | |||
import org.apache.poi.POIXMLProperties; | |||
import org.apache.poi.hssf.record.formula.SheetNameFormatter; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
import org.apache.poi.openxml4j.exceptions.OpenXML4JException; | |||
import org.apache.poi.openxml4j.opc.OPCPackage; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
@@ -41,7 +40,6 @@ import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; | |||
import org.apache.poi.openxml4j.opc.PackagingURIHelper; | |||
import org.apache.poi.openxml4j.opc.TargetMode; | |||
import org.apache.poi.ss.usermodel.Name; | |||
import org.apache.poi.ss.usermodel.Row; | |||
import org.apache.poi.ss.usermodel.Sheet; | |||
import org.apache.poi.ss.usermodel.Workbook; | |||
@@ -65,8 +63,6 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.*; | |||
* High level representation of a SpreadsheetML workbook. This is the first object most users | |||
* will construct whether they are reading or writing a workbook. It is also the | |||
* top level object for creating new sheets/etc. | |||
* | |||
* Modified 09/07/09 by Petr Udalau - added methods for work with UDFs of this Workbook. | |||
*/ | |||
public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<XSSFSheet> { | |||
private static final Pattern COMMA_PATTERN = Pattern.compile(","); | |||
@@ -133,9 +129,6 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X | |||
private List<XSSFPictureData> pictures; | |||
private static POILogger logger = POILogFactory.getLogger(XSSFWorkbook.class); | |||
/** Map of user defined functions, key - function name, value - instance of FreeRefFunctions */ | |||
private Map<String, FreeRefFunction> udfFunctions = new HashMap<String, FreeRefFunction>(); | |||
/** | |||
* Create a new SpreadsheetML workbook. | |||
@@ -1352,23 +1345,4 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X | |||
public MapInfo getMapInfo(){ | |||
return mapInfo; | |||
} | |||
public FreeRefFunction getUserDefinedFunction(String functionName) { | |||
return udfFunctions.get(functionName); | |||
} | |||
public void registerUserDefinedFunction(String functionName, FreeRefFunction freeRefFunction) { | |||
Name udfDeclaration = getName(functionName); | |||
if (udfDeclaration == null) { | |||
udfDeclaration = createName(); | |||
} | |||
udfDeclaration.setNameName(functionName); | |||
udfDeclaration.setFunction(true); | |||
udfFunctions.put(functionName, freeRefFunction); | |||
} | |||
public List<String> getUserDefinedFunctionNames() { | |||
return new ArrayList<String>(udfFunctions.keySet()); | |||
} | |||
} |
@@ -17,97 +17,79 @@ | |||
package org.apache.poi.hssf.record.formula.eval; | |||
import java.io.IOException; | |||
import junit.framework.TestCase; | |||
import org.apache.poi.hssf.HSSFTestDataSamples; | |||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||
import org.apache.poi.hssf.record.formula.toolpack.DefaultToolPack; | |||
import org.apache.poi.hssf.record.formula.toolpack.MainToolPacksHandler; | |||
import org.apache.poi.hssf.record.formula.toolpack.ToolPack; | |||
import org.apache.poi.hssf.record.formula.udf.DefaultUDFFinder; | |||
import org.apache.poi.hssf.record.formula.udf.AggregatingUDFFinder; | |||
import org.apache.poi.hssf.record.formula.udf.UDFFinder; | |||
import org.apache.poi.hssf.usermodel.HSSFCell; | |||
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; | |||
import org.apache.poi.hssf.usermodel.HSSFRow; | |||
import org.apache.poi.hssf.usermodel.HSSFSheet; | |||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
import org.apache.poi.ss.formula.OperationEvaluationContext; | |||
import org.apache.poi.ss.usermodel.Workbook; | |||
/** | |||
* | |||
* @author Josh Micich | |||
* | |||
* Modified 09/14/09 by Petr Udalau - Test of registering UDFs in workbook and | |||
* using ToolPacks. | |||
* @author Petr Udalau - registering UDFs in workbook and using ToolPacks. | |||
*/ | |||
public final class TestExternalFunction extends TestCase { | |||
private static class MyFunc implements FreeRefFunction { | |||
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { | |||
if (args.length != 1 || !(args[0] instanceof StringEval)) { | |||
return ErrorEval.VALUE_INVALID; | |||
} else { | |||
StringEval input = (StringEval) args[0]; | |||
return new StringEval(input.getStringValue() + "abc"); | |||
} | |||
} | |||
} | |||
private static class MyFunc2 implements FreeRefFunction { | |||
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { | |||
if (args.length != 1 || !(args[0] instanceof StringEval)) { | |||
return ErrorEval.VALUE_INVALID; | |||
} else { | |||
StringEval input = (StringEval) args[0]; | |||
return new StringEval(input.getStringValue() + "abc2"); | |||
} | |||
} | |||
} | |||
/** | |||
* Creates and registers user-defined function "MyFunc()" directly with POI. | |||
* This is VB function defined in "testNames.xls". In future there must be | |||
* some parser of VBA scripts which will register UDFs. | |||
*/ | |||
private void registerMyFunc(Workbook workbook) { | |||
workbook.registerUserDefinedFunction("myFunc", new MyFunc()); | |||
} | |||
/** | |||
* Creates example ToolPack which contains function "MyFunc2()". | |||
*/ | |||
private void createExampleToolPack() { | |||
ToolPack exampleToolPack = new DefaultToolPack(); | |||
exampleToolPack.addFunction("myFunc2", new MyFunc2()); | |||
MainToolPacksHandler.instance().addToolPack(exampleToolPack); | |||
} | |||
/** | |||
* Checks that an external function can get invoked from the formula | |||
* evaluator. | |||
* | |||
* @throws IOException | |||
* | |||
*/ | |||
public void testInvoke() { | |||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("testNames.xls"); | |||
HSSFSheet sheet = wb.getSheetAt(0); | |||
registerMyFunc(wb); | |||
createExampleToolPack(); | |||
HSSFRow row = sheet.getRow(0); | |||
HSSFCell myFuncCell = row.getCell(1); //=myFunc("_") | |||
HSSFCell myFunc2Cell = row.getCell(2); //=myFunc2("_") | |||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); | |||
try { | |||
assertEquals("_abc", fe.evaluate(myFuncCell).getStringValue()); | |||
assertEquals("_abc2", fe.evaluate(myFunc2Cell).getStringValue()); | |||
} catch (Exception e) { | |||
assertFalse(true); | |||
} | |||
} | |||
private static class MyFunc implements FreeRefFunction { | |||
public MyFunc() { | |||
// | |||
} | |||
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { | |||
if (args.length != 1 || !(args[0] instanceof StringEval)) { | |||
return ErrorEval.VALUE_INVALID; | |||
} | |||
StringEval input = (StringEval) args[0]; | |||
return new StringEval(input.getStringValue() + "abc"); | |||
} | |||
} | |||
private static class MyFunc2 implements FreeRefFunction { | |||
public MyFunc2() { | |||
// | |||
} | |||
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { | |||
if (args.length != 1 || !(args[0] instanceof StringEval)) { | |||
return ErrorEval.VALUE_INVALID; | |||
} | |||
StringEval input = (StringEval) args[0]; | |||
return new StringEval(input.getStringValue() + "abc2"); | |||
} | |||
} | |||
/** | |||
* Checks that an external function can get invoked from the formula | |||
* evaluator. | |||
*/ | |||
public void testInvoke() { | |||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("testNames.xls"); | |||
HSSFSheet sheet = wb.getSheetAt(0); | |||
/** | |||
* register the two test UDFs in a UDF finder, to be passed to the evaluator | |||
*/ | |||
UDFFinder udff1 = new DefaultUDFFinder(new String[] { "myFunc", }, | |||
new FreeRefFunction[] { new MyFunc(), }); | |||
UDFFinder udff2 = new DefaultUDFFinder(new String[] { "myFunc2", }, | |||
new FreeRefFunction[] { new MyFunc2(), }); | |||
UDFFinder udff = new AggregatingUDFFinder(udff1, udff2); | |||
HSSFRow row = sheet.getRow(0); | |||
HSSFCell myFuncCell = row.getCell(1); // =myFunc("_") | |||
HSSFCell myFunc2Cell = row.getCell(2); // =myFunc2("_") | |||
HSSFFormulaEvaluator fe = HSSFFormulaEvaluator.create(wb, null, udff); | |||
assertEquals("_abc", fe.evaluate(myFuncCell).getStringValue()); | |||
assertEquals("_abc2", fe.evaluate(myFunc2Cell).getStringValue()); | |||
} | |||
} |
@@ -44,7 +44,7 @@ public class TestWorkbookEvaluator extends TestCase { | |||
private static ValueEval evaluateFormula(Ptg[] ptgs) { | |||
OperationEvaluationContext ec = new OperationEvaluationContext(null, null, 0, 0, 0, null); | |||
return new WorkbookEvaluator(null, null).evaluateFormula(ec, ptgs); | |||
return new WorkbookEvaluator(null, null, null).evaluateFormula(ec, ptgs); | |||
} | |||
/** |
@@ -22,7 +22,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook; | |||
/** | |||
* Allows tests to execute {@link WorkbookEvaluator}s and track the internal workings. | |||
* | |||
* | |||
* @author Josh Micich | |||
*/ | |||
public final class WorkbookEvaluatorTestHelper { | |||
@@ -30,8 +30,8 @@ public final class WorkbookEvaluatorTestHelper { | |||
private WorkbookEvaluatorTestHelper() { | |||
// no instances of this class | |||
} | |||
public static WorkbookEvaluator createEvaluator(HSSFWorkbook wb, EvaluationListener listener) { | |||
return new WorkbookEvaluator(HSSFEvaluationWorkbook.create(wb), listener, null); | |||
return new WorkbookEvaluator(HSSFEvaluationWorkbook.create(wb), listener, null, null); | |||
} | |||
} |