git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1039870 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_8_BETA1
} | } | ||||
public NameXPtg getNameXPtg(String name) { | 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(); | FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord(); | ||||
return fra.getFormulaTokens(); | return fra.getFormulaTokens(); | ||||
} | } | ||||
public UDFFinder getUDFFinder(){ | |||||
return _uBook.getUDFFinder(); | |||||
} | |||||
private static final class Name implements EvaluationName { | private static final class Name implements EvaluationName { | ||||
import org.apache.poi.hssf.util.CellReference; | import org.apache.poi.hssf.util.CellReference; | ||||
import org.apache.poi.poifs.filesystem.DirectoryNode; | import org.apache.poi.poifs.filesystem.DirectoryNode; | ||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem; | 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.CreationHelper; | ||||
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; | import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; | ||||
import org.apache.poi.ss.formula.FormulaType; | import org.apache.poi.ss.formula.FormulaType; | ||||
private static POILogger log = POILogFactory.getLogger(HSSFWorkbook.class); | 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) { | public static HSSFWorkbook create(InternalWorkbook book) { | ||||
return new HSSFWorkbook(book); | return new HSSFWorkbook(book); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
public CreationHelper getCreationHelper() { | |||||
public HSSFCreationHelper getCreationHelper() { | |||||
return new HSSFCreationHelper(this); | return new HSSFCreationHelper(this); | ||||
} | } | ||||
private static byte[] newUID() { | private static byte[] newUID() { | ||||
return new byte[16]; | 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.NamePtg; | ||||
import org.apache.poi.ss.formula.ptg.NameXPtg; | import org.apache.poi.ss.formula.ptg.NameXPtg; | ||||
import org.apache.poi.ss.formula.ptg.Ptg; | import org.apache.poi.ss.formula.ptg.Ptg; | ||||
import org.apache.poi.ss.formula.udf.UDFFinder; | |||||
/** | /** | ||||
* Abstracts a workbook for the purpose of formula evaluation.<br/> | * Abstracts a workbook for the purpose of formula evaluation.<br/> | ||||
int convertFromExternSheetIndex(int externSheetIndex); | int convertFromExternSheetIndex(int externSheetIndex); | ||||
ExternalName getExternalName(int externSheetIndex, int externNameIndex); | ExternalName getExternalName(int externSheetIndex, int externNameIndex); | ||||
EvaluationName getName(NamePtg namePtg); | EvaluationName getName(NamePtg namePtg); | ||||
EvaluationName getName(String name, int sheetIndex); | |||||
String resolveNameXText(NameXPtg ptg); | String resolveNameXText(NameXPtg ptg); | ||||
Ptg[] getFormulaTokens(EvaluationCell cell); | Ptg[] getFormulaTokens(EvaluationCell cell); | ||||
UDFFinder getUDFFinder(); | |||||
class ExternalSheet { | class ExternalSheet { | ||||
private final String _workbookName; | private final String _workbookName; |
import org.apache.poi.ss.formula.functions.Choose; | import org.apache.poi.ss.formula.functions.Choose; | ||||
import org.apache.poi.ss.formula.functions.FreeRefFunction; | import org.apache.poi.ss.formula.functions.FreeRefFunction; | ||||
import org.apache.poi.ss.formula.functions.IfFunc; | 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.ss.formula.udf.UDFFinder; | ||||
import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook; | |||||
import org.apache.poi.ss.util.CellReference; | import org.apache.poi.ss.util.CellReference; | ||||
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException; | import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException; | ||||
import org.apache.poi.ss.formula.eval.NotImplementedException; | import org.apache.poi.ss.formula.eval.NotImplementedException; | ||||
private final Map<String, Integer> _sheetIndexesByName; | private final Map<String, Integer> _sheetIndexesByName; | ||||
private CollaboratingWorkbooksEnvironment _collaboratingWorkbookEnvironment; | private CollaboratingWorkbooksEnvironment _collaboratingWorkbookEnvironment; | ||||
private final IStabilityClassifier _stabilityClassifier; | private final IStabilityClassifier _stabilityClassifier; | ||||
private final UDFFinder _udfFinder; | |||||
private final AggregatingUDFFinder _udfFinder; | |||||
/** | /** | ||||
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only) | * @param udfFinder pass <code>null</code> for default (AnalysisToolPak only) | ||||
_collaboratingWorkbookEnvironment = CollaboratingWorkbooksEnvironment.EMPTY; | _collaboratingWorkbookEnvironment = CollaboratingWorkbooksEnvironment.EMPTY; | ||||
_workbookIx = 0; | _workbookIx = 0; | ||||
_stabilityClassifier = stabilityClassifier; | _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) { | /* 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) { | if(namePtg == null) { | ||||
return null; | return null; |
*/ | */ | ||||
public final class AnalysisToolPak implements UDFFinder { | 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.EvaluationName; | ||||
import org.apache.poi.ss.formula.EvaluationSheet; | import org.apache.poi.ss.formula.EvaluationSheet; | ||||
import org.apache.poi.ss.formula.EvaluationWorkbook; | import org.apache.poi.ss.formula.EvaluationWorkbook; | ||||
import org.apache.poi.ss.formula.udf.UDFFinder; | |||||
import org.apache.poi.ss.usermodel.Workbook; | import org.apache.poi.ss.usermodel.Workbook; | ||||
/** | /** | ||||
return _masterBook.getName(namePtg); | return _masterBook.getName(namePtg); | ||||
} | } | ||||
public EvaluationName getName(String name, int sheetIndex){ | |||||
return _masterBook.getName(name, sheetIndex); | |||||
} | |||||
public EvaluationSheet getSheet(int sheetIndex) { | public EvaluationSheet getSheet(int sheetIndex) { | ||||
return getSharedSheet(getSheetName(sheetIndex)); | return getSharedSheet(getSheetName(sheetIndex)); | ||||
} | } | ||||
return _masterBook.resolveNameXText(ptg); | return _masterBook.resolveNameXText(ptg); | ||||
} | } | ||||
public UDFFinder getUDFFinder(){ | |||||
return _masterBook.getUDFFinder(); | |||||
} | |||||
private static final class OrderedSheet implements Comparable<OrderedSheet> { | private static final class OrderedSheet implements Comparable<OrderedSheet> { | ||||
private final String _sheetName; | private final String _sheetName; | ||||
private final int _index; | private final int _index; |
private final FunctionMetadata[] _functionDataByIndex; | private final FunctionMetadata[] _functionDataByIndex; | ||||
private final Map<String, FunctionMetadata> _functionDataByName; | private final Map<String, FunctionMetadata> _functionDataByName; | ||||
private static FunctionMetadataRegistry getInstance() { | |||||
public static FunctionMetadataRegistry getInstance() { | |||||
if (_instance == null) { | if (_instance == null) { | ||||
_instance = FunctionMetadataReader.createRegistry(); | _instance = FunctionMetadataReader.createRegistry(); | ||||
} | } |
import org.apache.poi.ss.formula.functions.FreeRefFunction; | 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 | * Collects add-in libraries and VB macro functions together into one UDF finder | ||||
* | * | ||||
* @author PUdalau | * @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) { | public AggregatingUDFFinder(UDFFinder ... usedToolPacks) { | ||||
_usedToolPacks = usedToolPacks.clone(); | |||||
_usedToolPacks = new ArrayList<UDFFinder>(usedToolPacks.length); | |||||
_usedToolPacks.addAll(Arrays.asList(usedToolPacks)); | |||||
} | } | ||||
/** | /** | ||||
} | } | ||||
return null; | 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); | HashMap<String, FreeRefFunction> m = new HashMap<String, FreeRefFunction>(nFuncs * 3 / 2); | ||||
for (int i = 0; i < functionImpls.length; i++) { | for (int i = 0; i < functionImpls.length; i++) { | ||||
m.put(functionNames[i], functionImpls[i]); | |||||
m.put(functionNames[i].toUpperCase(), functionImpls[i]); | |||||
} | } | ||||
_functionsByName = m; | _functionsByName = m; | ||||
} | } | ||||
public FreeRefFunction findFunction(String name) { | public FreeRefFunction findFunction(String name) { | ||||
return _functionsByName.get(name); | |||||
return _functionsByName.get(name.toUpperCase()); | |||||
} | } | ||||
} | } |
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.util.List; | import java.util.List; | ||||
import org.apache.poi.ss.formula.udf.UDFFinder; | |||||
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; | import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; | ||||
/** | /** | ||||
* @throws IllegalArgumentException if the supplied sheet index or state is invalid | * @throws IllegalArgumentException if the supplied sheet index or state is invalid | ||||
*/ | */ | ||||
void setSheetHidden(int sheetIx, int hidden); | void setSheetHidden(int sheetIx, int hidden); | ||||
/** | |||||
* Register a new toolpack in this workbook. | |||||
* | |||||
* @param toopack the toolpack to register | |||||
*/ | |||||
void addToolPack(UDFFinder toopack); | |||||
} | } |
/* ==================================================================== | |||||
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; | 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.NamePtg; | ||||
import org.apache.poi.ss.formula.ptg.NameXPtg; | import org.apache.poi.ss.formula.ptg.NameXPtg; | ||||
import org.apache.poi.ss.formula.ptg.Ptg; | import org.apache.poi.ss.formula.ptg.Ptg; | ||||
import org.apache.poi.ss.formula.FormulaParsingWorkbook; | import org.apache.poi.ss.formula.FormulaParsingWorkbook; | ||||
import org.apache.poi.ss.formula.FormulaRenderingWorkbook; | import org.apache.poi.ss.formula.FormulaRenderingWorkbook; | ||||
import org.apache.poi.ss.formula.FormulaType; | 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 org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName; | ||||
import java.util.HashMap; | |||||
/** | /** | ||||
* Internal POI use only | * Internal POI use only | ||||
* | * | ||||
} | } | ||||
public NameXPtg getNameXPtg(String name) { | 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) { | public EvaluationSheet getSheet(int sheetIndex) { | ||||
return new XSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex)); | return new XSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex)); | ||||
} | } | ||||
return _uBook.getSheetIndex(sheetName); | 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) { | public String getSheetNameByExternSheet(int externSheetIndex) { | ||||
int sheetIndex = convertFromExternalSheetIndex(externSheetIndex); | int sheetIndex = convertFromExternalSheetIndex(externSheetIndex); | ||||
return _uBook.getSheetName(sheetIndex); | return _uBook.getSheetName(sheetIndex); | ||||
return FormulaParser.parse(cell.getCellFormula(), frBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet())); | 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 static final class Name implements EvaluationName { | ||||
private final XSSFName _nameRecord; | private final XSSFName _nameRecord; |
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; | import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; | ||||
import org.apache.poi.openxml4j.opc.PackagingURIHelper; | import org.apache.poi.openxml4j.opc.PackagingURIHelper; | ||||
import org.apache.poi.openxml4j.opc.TargetMode; | 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.Row; | ||||
import org.apache.poi.ss.usermodel.Sheet; | import org.apache.poi.ss.usermodel.Sheet; | ||||
import org.apache.poi.ss.usermodel.Workbook; | import org.apache.poi.ss.usermodel.Workbook; | ||||
import org.apache.poi.ss.util.CellReference; | import org.apache.poi.ss.util.CellReference; | ||||
import org.apache.poi.ss.util.WorkbookUtil; | import org.apache.poi.ss.util.WorkbookUtil; | ||||
import org.apache.poi.util.*; | 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.XmlException; | ||||
import org.apache.xmlbeans.XmlObject; | import org.apache.xmlbeans.XmlObject; | ||||
import org.apache.xmlbeans.XmlOptions; | import org.apache.xmlbeans.XmlOptions; | ||||
private ThemesTable theme; | 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 | * TODO | ||||
*/ | */ | ||||
workbook.setWorkbookProtection(CTWorkbookProtection.Factory.newInstance()); | 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); | |||||
} | |||||
} | } |
/* ==================================================================== | |||||
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"); | |||||
} | |||||
} |
/* ==================================================================== | |||||
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"); | |||||
} | |||||
} |
/* ==================================================================== | |||||
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)); | |||||
} | |||||
} |