}
public NameXPtg getNameXPtg(String name) {
- // TODO YK: passing UDFFinder.DEFAULT is temporary,
- // a proper design should take it from the parent HSSFWorkbook
- return _iBook.getNameXPtg(name, UDFFinder.DEFAULT);
+ return _iBook.getNameXPtg(name, _uBook.getUDFFinder());
}
/**
FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord();
return fra.getFormulaTokens();
}
+ public UDFFinder getUDFFinder(){
+ return _uBook.getUDFFinder();
+ }
private static final class Name implements EvaluationName {
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.formula.udf.AggregatingUDFFinder;
+import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.ss.formula.FormulaType;
private static POILogger log = POILogFactory.getLogger(HSSFWorkbook.class);
+ /**
+ * The locator of user-defined functions.
+ * By default includes functions from the Excel Analysis Toolpack
+ */
+ private UDFFinder _udfFinder = UDFFinder.DEFAULT;
+
public static HSSFWorkbook create(InternalWorkbook book) {
return new HSSFWorkbook(book);
}
}
}
- public CreationHelper getCreationHelper() {
+ public HSSFCreationHelper getCreationHelper() {
return new HSSFCreationHelper(this);
}
private static byte[] newUID() {
return new byte[16];
}
+
+ /**
+ *
+ * Returns the locator of user-defined functions.
+ * The default instance extends the built-in functions with the Analysis Tool Pack
+ *
+ * @return the locator of user-defined functions
+ */
+ /*package*/ UDFFinder getUDFFinder(){
+ return _udfFinder;
+ }
+
+ /**
+ * Register a new toolpack in this workbook.
+ *
+ * @param toopack the toolpack to register
+ */
+ public void addToolPack(UDFFinder toopack){
+ AggregatingUDFFinder udfs = (AggregatingUDFFinder)_udfFinder;
+ udfs.add(toopack);
+ }
+
}
import org.apache.poi.ss.formula.ptg.NamePtg;
import org.apache.poi.ss.formula.ptg.NameXPtg;
import org.apache.poi.ss.formula.ptg.Ptg;
+import org.apache.poi.ss.formula.udf.UDFFinder;
/**
* Abstracts a workbook for the purpose of formula evaluation.<br/>
int convertFromExternSheetIndex(int externSheetIndex);
ExternalName getExternalName(int externSheetIndex, int externNameIndex);
EvaluationName getName(NamePtg namePtg);
+ EvaluationName getName(String name, int sheetIndex);
String resolveNameXText(NameXPtg ptg);
Ptg[] getFormulaTokens(EvaluationCell cell);
+ UDFFinder getUDFFinder();
class ExternalSheet {
private final String _workbookName;
import org.apache.poi.ss.formula.functions.Choose;
import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.functions.IfFunc;
+import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder;
-import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException;
import org.apache.poi.ss.formula.eval.NotImplementedException;
private final Map<String, Integer> _sheetIndexesByName;
private CollaboratingWorkbooksEnvironment _collaboratingWorkbookEnvironment;
private final IStabilityClassifier _stabilityClassifier;
- private final UDFFinder _udfFinder;
+ private final AggregatingUDFFinder _udfFinder;
/**
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
_collaboratingWorkbookEnvironment = CollaboratingWorkbooksEnvironment.EMPTY;
_workbookIx = 0;
_stabilityClassifier = stabilityClassifier;
- _udfFinder = udfFinder == null ? UDFFinder.DEFAULT : udfFinder;
+
+ AggregatingUDFFinder defaultToolkit = // workbook can be null in unit tests
+ workbook == null ? null : (AggregatingUDFFinder)workbook.getUDFFinder();
+ if(defaultToolkit != null && udfFinder != null) {
+ defaultToolkit.add(udfFinder);
+ }
+ _udfFinder = defaultToolkit;
}
/**
}
/* package */ EvaluationName getName(String name, int sheetIndex) {
- NamePtg namePtg = null;
- if(_workbook instanceof HSSFEvaluationWorkbook){
- namePtg =((HSSFEvaluationWorkbook)_workbook).getName(name, sheetIndex).createPtg();
- }
+ NamePtg namePtg = _workbook.getName(name, sheetIndex).createPtg();
if(namePtg == null) {
return null;
*/
public final class AnalysisToolPak implements UDFFinder {
- public static final UDFFinder instance = new AnalysisToolPak();
-
- private static final class NotImplemented implements FreeRefFunction {
- private final String _functionName;
-
- public NotImplemented(String functionName) {
- _functionName = functionName;
- }
-
- public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
- throw new NotImplementedException(_functionName);
- }
- };
-
- 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);
-
- r(m, "ACCRINT", null);
- r(m, "ACCRINTM", null);
- r(m, "AMORDEGRC", null);
- r(m, "AMORLINC", null);
- r(m, "BESSELI", null);
- r(m, "BESSELJ", null);
- r(m, "BESSELK", null);
- r(m, "BESSELY", null);
- r(m, "BIN2DEC", null);
- r(m, "BIN2HEX", null);
- r(m, "BIN2OCT", null);
- r(m, "CO MPLEX", null);
- r(m, "CONVERT", null);
- r(m, "COUPDAYBS", null);
- r(m, "COUPDAYS", null);
- r(m, "COUPDAYSNC", null);
- r(m, "COUPNCD", null);
- r(m, "COUPNUM", null);
- r(m, "COUPPCD", null);
- r(m, "CUMIPMT", null);
- r(m, "CUMPRINC", null);
- r(m, "DEC2BIN", null);
- r(m, "DEC2HEX", null);
- r(m, "DEC2OCT", null);
- r(m, "DELTA", null);
- r(m, "DISC", null);
- r(m, "DOLLARDE", null);
- r(m, "DOLLARFR", null);
- r(m, "DURATION", null);
- r(m, "EDATE", null);
- r(m, "EFFECT", null);
- r(m, "EOMONTH", null);
- r(m, "ERF", null);
- r(m, "ERFC", null);
- r(m, "FACTDOUBLE", null);
- r(m, "FVSCHEDULE", null);
- r(m, "GCD", null);
- r(m, "GESTEP", null);
- r(m, "HEX2BIN", null);
- r(m, "HEX2DEC", null);
- r(m, "HEX2OCT", null);
- r(m, "IMABS", null);
- r(m, "IMAGINARY", null);
- r(m, "IMARGUMENT", null);
- r(m, "IMCONJUGATE", null);
- r(m, "IMCOS", null);
- r(m, "IMDIV", null);
- r(m, "IMEXP", null);
- r(m, "IMLN", null);
- r(m, "IMLOG10", null);
- r(m, "IMLOG2", null);
- r(m, "IMPOWER", null);
- r(m, "IMPRODUCT", null);
- r(m, "IMREAL", null);
- r(m, "IMSIN", null);
- r(m, "IMSQRT", null);
- r(m, "IMSUB", null);
- r(m, "IMSUM", null);
- r(m, "INTRATE", null);
- r(m, "ISEVEN", ParityFunction.IS_EVEN);
- r(m, "ISODD", ParityFunction.IS_ODD);
- r(m, "LCM", null);
- r(m, "MDURATION", null);
- r(m, "MROUND", null);
- r(m, "MULTINOMIAL", null);
- r(m, "NETWORKDAYS", null);
- r(m, "NOMINAL", null);
- r(m, "OCT2BIN", null);
- r(m, "OCT2DEC", null);
- r(m, "OCT2HEX", null);
- r(m, "ODDFPRICE", null);
- r(m, "ODDFYIELD", null);
- r(m, "ODDLPRICE", null);
- r(m, "ODDLYIELD", null);
- r(m, "PRICE", null);
- r(m, "PRICEDISC", null);
- r(m, "PRICEMAT", null);
- r(m, "QUOTIENT", null);
- r(m, "RANDBETWEEN", RandBetween.instance);
- r(m, "RECEIVED", null);
- r(m, "SERIESSUM", null);
- r(m, "SQRTPI", null);
- r(m, "TBILLEQ", null);
- r(m, "TBILLPRICE", null);
- r(m, "TBILLYIELD", null);
- r(m, "WEEKNUM", null);
- r(m, "WORKDAY", null);
- r(m, "XIRR", null);
- r(m, "XNPV", null);
- r(m, "YEARFRAC", YearFrac.instance);
- r(m, "YIELD", null);
- r(m, "YIELDDISC", null);
- r(m, "YIELDMAT", null);
-
- return m;
- }
-
- private static void r(Map<String, FreeRefFunction> m, String functionName, FreeRefFunction pFunc) {
- FreeRefFunction func = pFunc == null ? new NotImplemented(functionName) : pFunc;
- m.put(functionName, func);
- }
+ public static final UDFFinder instance = new AnalysisToolPak();
+
+ private static final class NotImplemented implements FreeRefFunction {
+ private final String _functionName;
+
+ public NotImplemented(String functionName) {
+ _functionName = functionName;
+ }
+
+ public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
+ throw new NotImplementedException(_functionName);
+ }
+ }
+
+ ;
+
+ 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>(108);
+
+ r(m, "ACCRINT", null);
+ r(m, "ACCRINTM", null);
+ r(m, "AMORDEGRC", null);
+ r(m, "AMORLINC", null);
+ r(m, "AVERAGEIF", null);
+ r(m, "AVERAGEIFS", null);
+ r(m, "BAHTTEXT", null);
+ r(m, "BESSELI", null);
+ r(m, "BESSELJ", null);
+ r(m, "BESSELK", null);
+ r(m, "BESSELY", null);
+ r(m, "BIN2DEC", null);
+ r(m, "BIN2HEX", null);
+ r(m, "BIN2OCT", null);
+ r(m, "COMPLEX", null);
+ r(m, "CONVERT", null);
+ r(m, "COUNTIFS", null);
+ r(m, "COUPDAYBS", null);
+ r(m, "COUPDAYS", null);
+ r(m, "COUPDAYSNC", null);
+ r(m, "COUPNCD", null);
+ r(m, "COUPNUM", null);
+ r(m, "COUPPCD", null);
+ r(m, "CUBEKPIMEMBER", null);
+ r(m, "CUBEMEMBER", null);
+ r(m, "CUBEMEMBERPROPERTY", null);
+ r(m, "CUBERANKEDMEMBER", null);
+ r(m, "CUBESET", null);
+ r(m, "CUBESETCOUNT", null);
+ r(m, "CUBEVALUE", null);
+ r(m, "CUMIPMT", null);
+ r(m, "CUMPRINC", null);
+ r(m, "DEC2BIN", null);
+ r(m, "DEC2HEX", null);
+ r(m, "DEC2OCT", null);
+ r(m, "DELTA", null);
+ r(m, "DISC", null);
+ r(m, "DOLLARDE", null);
+ r(m, "DOLLARFR", null);
+ r(m, "DURATION", null);
+ r(m, "EDATE", null);
+ r(m, "EFFECT", null);
+ r(m, "EOMONTH", null);
+ r(m, "ERF", null);
+ r(m, "ERFC", null);
+ r(m, "FACTDOUBLE", null);
+ r(m, "FVSCHEDULE", null);
+ r(m, "GCD", null);
+ r(m, "GESTEP", null);
+ r(m, "HEX2BIN", null);
+ r(m, "HEX2DEC", null);
+ r(m, "HEX2OCT", null);
+ r(m, "IFERROR", null);
+ r(m, "IMABS", null);
+ r(m, "IMAGINARY", null);
+ r(m, "IMARGUMENT", null);
+ r(m, "IMCONJUGATE", null);
+ r(m, "IMCOS", null);
+ r(m, "IMDIV", null);
+ r(m, "IMEXP", null);
+ r(m, "IMLN", null);
+ r(m, "IMLOG10", null);
+ r(m, "IMLOG2", null);
+ r(m, "IMPOWER", null);
+ r(m, "IMPRODUCT", null);
+ r(m, "IMREAL", null);
+ r(m, "IMSIN", null);
+ r(m, "IMSQRT", null);
+ r(m, "IMSUB", null);
+ r(m, "IMSUM", null);
+ r(m, "INTRATE", null);
+ r(m, "ISEVEN", ParityFunction.IS_EVEN);
+ r(m, "ISODD", ParityFunction.IS_ODD);
+ r(m, "JIS", null);
+ r(m, "LCM", null);
+ r(m, "MDURATION", null);
+ r(m, "MROUND", null);
+ r(m, "MULTINOMIAL", null);
+ r(m, "NETWORKDAYS", null);
+ r(m, "NOMINAL", null);
+ r(m, "OCT2BIN", null);
+ r(m, "OCT2DEC", null);
+ r(m, "OCT2HEX", null);
+ r(m, "ODDFPRICE", null);
+ r(m, "ODDFYIELD", null);
+ r(m, "ODDLPRICE", null);
+ r(m, "ODDLYIELD", null);
+ r(m, "PRICE", null);
+ r(m, "PRICEDISC", null);
+ r(m, "PRICEMAT", null);
+ r(m, "QUOTIENT", null);
+ r(m, "RANDBETWEEN", RandBetween.instance);
+ r(m, "RECEIVED", null);
+ r(m, "RTD", null);
+ r(m, "SERIESSUM", null);
+ r(m, "SQRTPI", null);
+ r(m, "SUMIFS", null);
+ r(m, "TBILLEQ", null);
+ r(m, "TBILLPRICE", null);
+ r(m, "TBILLYIELD", null);
+ r(m, "WEEKNUM", null);
+ r(m, "WORKDAY", null);
+ r(m, "XIRR", null);
+ r(m, "XNPV", null);
+ r(m, "YEARFRAC", YearFrac.instance);
+ r(m, "YIELD", null);
+ r(m, "YIELDDISC", null);
+ r(m, "YIELDMAT", null);
+
+ return m;
+ }
+
+ private static void r(Map<String, FreeRefFunction> m, String functionName, FreeRefFunction pFunc) {
+ FreeRefFunction func = pFunc == null ? new NotImplemented(functionName) : pFunc;
+ m.put(functionName, func);
+ }
}
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.udf.UDFFinder;
import org.apache.poi.ss.usermodel.Workbook;
/**
return _masterBook.getName(namePtg);
}
+ public EvaluationName getName(String name, int sheetIndex){
+ return _masterBook.getName(name, sheetIndex);
+ }
+
public EvaluationSheet getSheet(int sheetIndex) {
return getSharedSheet(getSheetName(sheetIndex));
}
return _masterBook.resolveNameXText(ptg);
}
+ public UDFFinder getUDFFinder(){
+ return _masterBook.getUDFFinder();
+ }
+
private static final class OrderedSheet implements Comparable<OrderedSheet> {
private final String _sheetName;
private final int _index;
private final FunctionMetadata[] _functionDataByIndex;
private final Map<String, FunctionMetadata> _functionDataByName;
- private static FunctionMetadataRegistry getInstance() {
+ public static FunctionMetadataRegistry getInstance() {
if (_instance == null) {
_instance = FunctionMetadataReader.createRegistry();
}
import org.apache.poi.ss.formula.functions.FreeRefFunction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
/**
* Collects add-in libraries and VB macro functions together into one UDF finder
*
* @author PUdalau
*/
-public final class AggregatingUDFFinder implements UDFFinder {
+public class AggregatingUDFFinder implements UDFFinder {
- private final UDFFinder[] _usedToolPacks;
+ private final Collection<UDFFinder> _usedToolPacks;
public AggregatingUDFFinder(UDFFinder ... usedToolPacks) {
- _usedToolPacks = usedToolPacks.clone();
+ _usedToolPacks = new ArrayList<UDFFinder>(usedToolPacks.length);
+ _usedToolPacks.addAll(Arrays.asList(usedToolPacks));
}
/**
}
return null;
}
+
+ /**
+ * Add a new toolpack
+ *
+ * @param toolPack the UDF toolpack to add
+ */
+ public void add(UDFFinder toolPack){
+ _usedToolPacks.add(toolPack);
+ }
}
}
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]);
+ m.put(functionNames[i].toUpperCase(), functionImpls[i]);
}
_functionsByName = m;
}
public FreeRefFunction findFunction(String name) {
- return _functionsByName.get(name);
+ return _functionsByName.get(name.toUpperCase());
}
}
import java.io.OutputStream;
import java.util.List;
+import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
/**
* @throws IllegalArgumentException if the supplied sheet index or state is invalid
*/
void setSheetHidden(int sheetIx, int hidden);
+
+ /**
+ * Register a new toolpack in this workbook.
+ *
+ * @param toopack the toolpack to register
+ */
+ void addToolPack(UDFFinder toopack);
+
}
--- /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.xssf.model;
+
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
+import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
+import org.apache.poi.ss.formula.udf.UDFFinder;
+import org.apache.poi.util.Internal;
+
+import java.util.HashMap;
+
+/**
+ * A UDFFinder that can retrieve functions both by name and by fake index.
+ *
+ * @author Yegor Kozlov
+ */
+@Internal
+public final class IndexedUDFFinder extends AggregatingUDFFinder {
+ private final HashMap<Integer, String> _funcMap;
+
+ public IndexedUDFFinder(UDFFinder... usedToolPacks) {
+ super(usedToolPacks);
+ _funcMap = new HashMap<Integer, String>();
+ }
+
+ public FreeRefFunction findFunction(String name) {
+ FreeRefFunction func = super.findFunction(name);
+ if (func != null) {
+ int idx = getFunctionIndex(name);
+ _funcMap.put(idx, name);
+ }
+ return func;
+ }
+
+ public String getFunctionName(int idx) {
+ return _funcMap.get(idx);
+ }
+
+ public int getFunctionIndex(String name) {
+ return name.hashCode();
+ }
+}
package org.apache.poi.xssf.usermodel;
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.ptg.NamePtg;
import org.apache.poi.ss.formula.ptg.NameXPtg;
import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.formula.FormulaParsingWorkbook;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
import org.apache.poi.ss.formula.FormulaType;
+import org.apache.poi.ss.formula.udf.UDFFinder;
+import org.apache.poi.xssf.model.IndexedUDFFinder;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
+import java.util.HashMap;
+
/**
* Internal POI use only
*
}
public NameXPtg getNameXPtg(String name) {
- // may require to return null to make tests pass
- throw new RuntimeException("Not implemented yet");
+ IndexedUDFFinder udfFinder = (IndexedUDFFinder)getUDFFinder();
+ FreeRefFunction func = udfFinder.findFunction(name);
+ if(func == null) return null;
+ else return new NameXPtg(0, udfFinder.getFunctionIndex(name));
}
+ public String resolveNameXText(NameXPtg n) {
+ int idx = n.getNameIndex();
+ IndexedUDFFinder udfFinder = (IndexedUDFFinder)getUDFFinder();
+ return udfFinder.getFunctionName(idx);
+ }
+
public EvaluationSheet getSheet(int sheetIndex) {
return new XSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex));
}
return _uBook.getSheetIndex(sheetName);
}
- /**
- * TODO - figure out what the hell this methods does in
- * HSSF...
- */
- public String resolveNameXText(NameXPtg n) {
- throw new RuntimeException("method not implemented yet");
- }
-
public String getSheetNameByExternSheet(int externSheetIndex) {
int sheetIndex = convertFromExternalSheetIndex(externSheetIndex);
return _uBook.getSheetName(sheetIndex);
return FormulaParser.parse(cell.getCellFormula(), frBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet()));
}
+ public UDFFinder getUDFFinder(){
+ return _uBook.getUDFFinder();
+ }
+
private static final class Name implements EvaluationName {
private final XSSFName _nameRecord;
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.formula.udf.AggregatingUDFFinder;
+import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.WorkbookUtil;
import org.apache.poi.util.*;
-import org.apache.poi.xssf.model.CalculationChain;
-import org.apache.poi.xssf.model.MapInfo;
-import org.apache.poi.xssf.model.SharedStringsTable;
-import org.apache.poi.xssf.model.StylesTable;
-import org.apache.poi.xssf.model.ThemesTable;
+import org.apache.poi.xssf.model.*;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
private ThemesTable theme;
+ /**
+ * The locator of user-defined functions.
+ * By default includes functions from the Excel Analysis Toolpack
+ */
+ private IndexedUDFFinder _udfFinder = new IndexedUDFFinder(UDFFinder.DEFAULT);
+
/**
* TODO
*/
workbook.setWorkbookProtection(CTWorkbookProtection.Factory.newInstance());
}
}
+
+ /**
+ *
+ * Returns the locator of user-defined functions.
+ * <p>
+ * The default instance extends the built-in functions with the Excel Analysis Tool Pack.
+ * To set / evaluate custom functions you need to register them as follows:
+ *
+ *
+ *
+ * </p>
+ * @return wrapped instance of UDFFinder that allows seeking functions both by index and name
+ */
+ /*package*/ UDFFinder getUDFFinder() {
+ return _udfFinder;
+ }
+
+ /**
+ * Register a new toolpack in this workbook.
+ *
+ * @param toopack the toolpack to register
+ */
+ public void addToolPack(UDFFinder toopack){
+ _udfFinder.add(toopack);
+ }
+
+
}
--- /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.xssf.usermodel;
+
+import org.apache.poi.ss.formula.BaseTestExternalFunctions;
+import org.apache.poi.xssf.XSSFITestDataProvider;
+
+/**
+ * Tests setting and evaluating user-defined functions in HSSF
+ */
+public final class TestXSSFExternalFunctions extends BaseTestExternalFunctions {
+
+ public TestXSSFExternalFunctions() {
+ super(XSSFITestDataProvider.instance);
+ }
+
+ public void testATP(){
+ baseTestInvokeATP("atp.xlsx");
+ }
+}
--- /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.usermodel;
+
+import org.apache.poi.hssf.HSSFITestDataProvider;
+import org.apache.poi.ss.formula.BaseTestExternalFunctions;
+
+/**
+ * Tests setting and evaluating user-defined functions in HSSF
+ */
+public final class TestHSSFExternalFunctions extends BaseTestExternalFunctions {
+
+ public TestHSSFExternalFunctions() {
+ super(HSSFITestDataProvider.instance);
+ }
+
+ public void testATP(){
+ baseTestInvokeATP("atp.xls");
+ }
+
+}
--- /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.ss.formula;
+
+import junit.framework.TestCase;
+import org.apache.poi.ss.ITestDataProvider;
+import org.apache.poi.ss.formula.eval.ErrorEval;
+import org.apache.poi.ss.formula.eval.StringEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.functions.FreeRefFunction;
+import org.apache.poi.ss.formula.udf.DefaultUDFFinder;
+import org.apache.poi.ss.formula.udf.UDFFinder;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * Test setting / evaluating of Analysis Toolpack and user-defined functions
+ *
+ * @author Yegor Kozlov
+ */
+public class BaseTestExternalFunctions extends TestCase {
+ // define two custom user-defined functions
+ 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");
+ }
+ }
+
+ /**
+ * register the two test UDFs in a UDF finder, to be passed to the workbook
+ */
+ private static UDFFinder customToolpack = new DefaultUDFFinder(
+ new String[] { "myFunc", "myFunc2"},
+ new FreeRefFunction[] { new MyFunc(), new MyFunc2()}
+ );
+
+
+ protected final ITestDataProvider _testDataProvider;
+
+ /**
+ * @param testDataProvider an object that provides test data in HSSF / XSSF specific way
+ */
+ protected BaseTestExternalFunctions(ITestDataProvider testDataProvider) {
+ _testDataProvider = testDataProvider;
+ }
+
+ public void testExternalFunctions() {
+ Workbook wb = _testDataProvider.createWorkbook();
+
+ Sheet sh = wb.createSheet();
+
+ Cell cell1 = sh.createRow(0).createCell(0);
+ cell1.setCellFormula("ISODD(1)+ISEVEN(2)"); // functions from the Excel Analysis Toolpack
+ assertEquals("ISODD(1)+ISEVEN(2)", cell1.getCellFormula());
+
+ Cell cell2 = sh.createRow(1).createCell(0);
+ try {
+ cell2.setCellFormula("MYFUNC(\"B1\")");
+ fail("Should fail because MYFUNC is an unknown function");
+ } catch (FormulaParseException e){
+ ; //expected
+ }
+
+ wb.addToolPack(customToolpack);
+
+ cell2.setCellFormula("MYFUNC(\"B1\")");
+ assertEquals("MYFUNC(\"B1\")", cell2.getCellFormula());
+
+ Cell cell3 = sh.createRow(2).createCell(0);
+ cell3.setCellFormula("MYFUNC2(\"C1\")&\"-\"&A2"); //where A2 is defined above
+ assertEquals("MYFUNC2(\"C1\")&\"-\"&A2", cell3.getCellFormula());
+
+ FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
+ assertEquals(2.0, evaluator.evaluate(cell1).getNumberValue());
+ assertEquals("B1abc", evaluator.evaluate(cell2).getStringValue());
+ assertEquals("C1abc2-B1abc", evaluator.evaluate(cell3).getStringValue());
+
+ }
+
+ /**
+ * test invoking saved ATP functions
+ *
+ * @param testFile either atp.xls or atp.xlsx
+ */
+ public void baseTestInvokeATP(String testFile){
+ Workbook wb = _testDataProvider.openSampleWorkbook(testFile);
+ FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
+
+ Sheet sh = wb.getSheetAt(0);
+ // these two are not imlemented in r
+ assertEquals("DELTA(1.3,1.5)", sh.getRow(0).getCell(1).getCellFormula());
+ assertEquals("COMPLEX(2,4)", sh.getRow(1).getCell(1).getCellFormula());
+
+ Cell cell2 = sh.getRow(2).getCell(1);
+ assertEquals("ISODD(2)", cell2.getCellFormula());
+ assertEquals(false, evaluator.evaluate(cell2).getBooleanValue());
+ assertEquals(Cell.CELL_TYPE_BOOLEAN, evaluator.evaluateFormulaCell(cell2));
+
+ Cell cell3 = sh.getRow(3).getCell(1);
+ assertEquals("ISEVEN(2)", cell3.getCellFormula());
+ assertEquals(true, evaluator.evaluate(cell3).getBooleanValue());
+ assertEquals(Cell.CELL_TYPE_BOOLEAN, evaluator.evaluateFormulaCell(cell3));
+
+ }
+
+}