<changes>
<release version="3.5-beta7" date="2009-??-??">
+ <action dev="POI-DEVELOPERS" type="add">47809 - Improved work with user-defined functions</action>
<action dev="POI-DEVELOPERS" type="fix">47581 - fixed XSSFSheet.setColumnWidth to produce XML compatible with Mac Excel 2008</action>
<action dev="POI-DEVELOPERS" type="fix">47734 - removed unnecessary svn:executable flag from files in SVN trunk</action>
<action dev="POI-DEVELOPERS" type="fix">47543 - added javadoc how to avoid Excel crash when creating too many HSSFRichTextString cells</action>
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.ss.formula.OperationEvaluationContext;
import org.apache.poi.ss.formula.eval.NotImplementedException;
-public final class AnalysisToolPak {
+/**
+ * Modified 09/07/09 by Petr Udalau - systematized work of ToolPacks.
+ */
+public final class AnalysisToolPak implements ToolPack {
private static final class NotImplemented implements FreeRefFunction {
private final String _functionName;
throw new NotImplementedException(_functionName);
}
};
+
+ private Map<String, FreeRefFunction> _functionsByName = createFunctionsMap();
- private static Map<String, FreeRefFunction> _functionsByName = createFunctionsMap();
-
- private AnalysisToolPak() {
- // no instances of this class
- }
-
- public static FreeRefFunction findFunction(String name) {
+ public FreeRefFunction findFunction(String name) {
return _functionsByName.get(name);
}
-
- private static Map<String, FreeRefFunction> createFunctionsMap() {
+
+ private Map<String, FreeRefFunction> createFunctionsMap() {
Map<String, FreeRefFunction> m = new HashMap<String, FreeRefFunction>(100);
r(m, "ACCRINT", null);
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);
+ }
}
package org.apache.poi.hssf.record.formula.eval;
-import org.apache.poi.hssf.record.formula.atp.AnalysisToolPak;
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;
* <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.
*/
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;
if (nameArg instanceof NameEval) {
- targetFunc = findInternalUserDefinedFunction((NameEval) nameArg);
+ targetFunc = findInternalUserDefinedFunction(workbook, (NameEval) nameArg);
} else if (nameArg instanceof NameXEval) {
- targetFunc = findExternalUserDefinedFunction(ec.getWorkbook(), (NameXEval) nameArg);
+ targetFunc = findExternalUserDefinedFunction(workbook, (NameXEval) nameArg);
} else {
throw new RuntimeException("First argument should be a NameEval, but got ("
+ nameArg.getClass().getName() + ")");
if(false) {
System.out.println("received call to external user defined function (" + functionName + ")");
}
- // currently only looking for functions from the 'Analysis TookPak' e.g. "YEARFRAC" or "ISEVEN"
+ // 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 = AnalysisToolPak.findFunction(functionName);
+ FreeRefFunction result = MainToolPacksHandler.instance().findFunction(functionName);
if (result != null) {
return result;
}
throw new NotImplementedException(functionName);
}
- private static FreeRefFunction findInternalUserDefinedFunction(NameEval functionNameEval) {
+ 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);
--- /dev/null
+/* ====================================================================
+ 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.HashMap;
+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.
+ *
+ * @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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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);
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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 org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
+
+/**
+ * Common interface for any new tool pack with executors for functions.
+ *
+ * @author PUdalau
+ */
+public interface ToolPack {
+ /**
+ * Returns executor by specified name. Returns <code>null</code> if tool
+ * pack doesn't contains such function.
+ *
+ * @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);
+}
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;
* 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 {
public SpreadsheetVersion getSpreadsheetVersion(){
return SpreadsheetVersion.EXCEL97;
}
+
+ public FreeRefFunction findUserDefinedFunction(String functionName) {
+ return _uBook.getUserDefinedFunction(functionName);
+ }
}
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;
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;
import org.apache.poi.util.POILogger;
+
/**
* High level representation of a workbook. This is the first object most users
* will construct whether they are reading or writing a workbook. It is also the
* @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(",");
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!)
workbook = book;
_sheets = new ArrayList( INITIAL_CAPACITY );
names = new ArrayList( INITIAL_CAPACITY );
+ udfFunctions = new HashMap<String, FreeRefFunction>();
}
public HSSFWorkbook(POIFSFileSystem fs) throws IOException {
_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.
}
}
}
+
+ 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)?
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/>
* 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);
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;
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.EvaluationCell;
import org.apache.poi.ss.formula.EvaluationName;
import org.apache.poi.ss.formula.EvaluationSheet;
* 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 {
return _index - o._index;
}
}
+
+ public FreeRefFunction findUserDefinedFunction(String functionName) {
+ return _masterBook.findUserDefinedFunction(functionName);
+ }
}
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 {
* @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();
}
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;
* 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 {
public SpreadsheetVersion getSpreadsheetVersion(){
return SpreadsheetVersion.EXCEL2007;
}
+
+ public FreeRefFunction findUserDefinedFunction(String functionName) {
+ return _uBook.getUserDefinedFunction(functionName);
+ }
}
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;
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;
* 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(",");
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.
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());
+ }
+
}
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.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
-import org.apache.poi.hssf.usermodel.HSSFName;
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.eval.NotImplementedException;
-import org.apache.poi.ss.usermodel.CellValue;
+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.
*/
public final class TestExternalFunction extends TestCase {
- /**
- * Checks that an external function can get invoked from the formula evaluator.
- * @throws IOException
-
- */
- public void testInvoke() {
-
- HSSFWorkbook wb;
- HSSFSheet sheet;
- HSSFCell cell;
- if (false) {
- // TODO - this code won't work until we can create user-defined functions directly with POI
- wb = new HSSFWorkbook();
- sheet = wb.createSheet();
- wb.setSheetName(0, "Sheet1");
- HSSFName hssfName = wb.createName();
- hssfName.setNameName("myFunc");
-
- } else {
- // This sample spreadsheet already has a VB function called 'myFunc'
- wb = HSSFTestDataSamples.openSampleWorkbook("testNames.xls");
- sheet = wb.getSheetAt(0);
- HSSFRow row = sheet.createRow(0);
- cell = row.createCell(1);
- }
-
- cell.setCellFormula("myFunc()");
- String actualFormula=cell.getCellFormula();
- assertEquals("myFunc()", actualFormula);
-
- HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
- // Check out what ExternalFunction.evaluate() does:
- CellValue evalResult;
- try {
- evalResult = fe.evaluate(cell);
- } catch (NotImplementedException e) {
- assertEquals("Error evaluating cell Sheet1!B1", e.getMessage());
- assertEquals("myFunc", e.getCause().getMessage());
- return;
- }
- // TODO - make this test assert something more interesting as soon as ExternalFunction works a bit better
- assertNotNull(evalResult);
- }
+ 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);
+ }
+ }
}