git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@815928 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_5-FINAL
<changes> | <changes> | ||||
<release version="3.5-beta7" date="2009-??-??"> | <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">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">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> | <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.eval.ValueEval; | ||||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | 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.OperationEvaluationContext; | ||||
import org.apache.poi.ss.formula.eval.NotImplementedException; | 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 static final class NotImplemented implements FreeRefFunction { | ||||
private final String _functionName; | private final String _functionName; | ||||
throw new NotImplementedException(_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); | return _functionsByName.get(name); | ||||
} | } | ||||
private static Map<String, FreeRefFunction> createFunctionsMap() { | |||||
private Map<String, FreeRefFunction> createFunctionsMap() { | |||||
Map<String, FreeRefFunction> m = new HashMap<String, FreeRefFunction>(100); | Map<String, FreeRefFunction> m = new HashMap<String, FreeRefFunction>(100); | ||||
r(m, "ACCRINT", null); | r(m, "ACCRINT", null); | ||||
FreeRefFunction func = pFunc == null ? new NotImplemented(functionName) : pFunc; | FreeRefFunction func = pFunc == null ? new NotImplemented(functionName) : pFunc; | ||||
m.put(functionName, func); | 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; | 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.functions.FreeRefFunction; | ||||
import org.apache.poi.hssf.record.formula.toolpack.MainToolPacksHandler; | |||||
import org.apache.poi.ss.formula.EvaluationWorkbook; | import org.apache.poi.ss.formula.EvaluationWorkbook; | ||||
import org.apache.poi.ss.formula.OperationEvaluationContext; | import org.apache.poi.ss.formula.OperationEvaluationContext; | ||||
import org.apache.poi.ss.formula.eval.NotImplementedException; | import org.apache.poi.ss.formula.eval.NotImplementedException; | ||||
* <tt>AbstractFunctionPtg.field_2_fnc_index</tt> == 255) | * <tt>AbstractFunctionPtg.field_2_fnc_index</tt> == 255) | ||||
* | * | ||||
* @author Josh Micich | * @author Josh Micich | ||||
* | |||||
* Modified 09/07/09 by Petr Udalau - Improved resolving of UDFs through the ToolPacks. | |||||
*/ | */ | ||||
final class UserDefinedFunction implements FreeRefFunction { | final class UserDefinedFunction implements FreeRefFunction { | ||||
} | } | ||||
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { | public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) { | ||||
EvaluationWorkbook workbook = ec.getWorkbook(); | |||||
int nIncomingArgs = args.length; | int nIncomingArgs = args.length; | ||||
if(nIncomingArgs < 1) { | if(nIncomingArgs < 1) { | ||||
throw new RuntimeException("function name argument missing"); | throw new RuntimeException("function name argument missing"); | ||||
ValueEval nameArg = args[0]; | ValueEval nameArg = args[0]; | ||||
FreeRefFunction targetFunc; | FreeRefFunction targetFunc; | ||||
if (nameArg instanceof NameEval) { | if (nameArg instanceof NameEval) { | ||||
targetFunc = findInternalUserDefinedFunction((NameEval) nameArg); | |||||
targetFunc = findInternalUserDefinedFunction(workbook, (NameEval) nameArg); | |||||
} else if (nameArg instanceof NameXEval) { | } else if (nameArg instanceof NameXEval) { | ||||
targetFunc = findExternalUserDefinedFunction(ec.getWorkbook(), (NameXEval) nameArg); | |||||
targetFunc = findExternalUserDefinedFunction(workbook, (NameXEval) nameArg); | |||||
} else { | } else { | ||||
throw new RuntimeException("First argument should be a NameEval, but got (" | throw new RuntimeException("First argument should be a NameEval, but got (" | ||||
+ nameArg.getClass().getName() + ")"); | + nameArg.getClass().getName() + ")"); | ||||
if(false) { | if(false) { | ||||
System.out.println("received call to external user defined function (" + functionName + ")"); | 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. | // 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) { | if (result != null) { | ||||
return result; | return result; | ||||
} | } | ||||
throw new NotImplementedException(functionName); | throw new NotImplementedException(functionName); | ||||
} | } | ||||
private static FreeRefFunction findInternalUserDefinedFunction(NameEval functionNameEval) { | |||||
private static FreeRefFunction findInternalUserDefinedFunction(EvaluationWorkbook workbook, | |||||
NameEval functionNameEval) { | |||||
String functionName = functionNameEval.getFunctionName(); | String functionName = functionNameEval.getFunctionName(); | ||||
if(false) { | if(false) { | ||||
System.out.println("received call to internal user defined function (" + functionName + ")"); | 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 | // TODO find the implementation for the user defined function | ||||
throw new NotImplementedException(functionName); | throw new NotImplementedException(functionName); |
/* ==================================================================== | |||||
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); | |||||
} | |||||
} |
/* ==================================================================== | |||||
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); | |||||
} | |||||
} |
/* ==================================================================== | |||||
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.NamePtg; | ||||
import org.apache.poi.hssf.record.formula.NameXPtg; | import org.apache.poi.hssf.record.formula.NameXPtg; | ||||
import org.apache.poi.hssf.record.formula.Ptg; | 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.formula.*; | ||||
import org.apache.poi.ss.SpreadsheetVersion; | import org.apache.poi.ss.SpreadsheetVersion; | ||||
* Internal POI use only | * Internal POI use only | ||||
* | * | ||||
* @author Josh Micich | * @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 final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, EvaluationWorkbook, FormulaParsingWorkbook { | ||||
public SpreadsheetVersion getSpreadsheetVersion(){ | public SpreadsheetVersion getSpreadsheetVersion(){ | ||||
return SpreadsheetVersion.EXCEL97; | return SpreadsheetVersion.EXCEL97; | ||||
} | } | ||||
public FreeRefFunction findUserDefinedFunction(String functionName) { | |||||
return _uBook.getUserDefinedFunction(functionName); | |||||
} | |||||
} | } |
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.io.PrintWriter; | import java.io.PrintWriter; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.HashMap; | |||||
import java.util.Hashtable; | import java.util.Hashtable; | ||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
import java.util.regex.Pattern; | import java.util.regex.Pattern; | ||||
import org.apache.poi.POIDocument; | import org.apache.poi.POIDocument; | ||||
import org.apache.poi.hssf.record.formula.Ref3DPtg; | import org.apache.poi.hssf.record.formula.Ref3DPtg; | ||||
import org.apache.poi.hssf.record.formula.SheetNameFormatter; | import org.apache.poi.hssf.record.formula.SheetNameFormatter; | ||||
import org.apache.poi.hssf.record.formula.UnionPtg; | 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.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.usermodel.CreationHelper; | 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.usermodel.Row.MissingCellPolicy; | ||||
import org.apache.poi.ss.formula.FormulaType; | import org.apache.poi.ss.formula.FormulaType; | ||||
import org.apache.poi.util.POILogFactory; | import org.apache.poi.util.POILogFactory; | ||||
import org.apache.poi.util.POILogger; | import org.apache.poi.util.POILogger; | ||||
/** | /** | ||||
* High level representation of a workbook. This is the first object most users | * 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 | * will construct whether they are reading or writing a workbook. It is also the | ||||
* @author Glen Stampoultzis (glens at apache.org) | * @author Glen Stampoultzis (glens at apache.org) | ||||
* @author Shawn Laubach (slaubach at apache dot 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 { | public class HSSFWorkbook extends POIDocument implements org.apache.poi.ss.usermodel.Workbook { | ||||
private static final Pattern COMMA_PATTERN = Pattern.compile(","); | private static final Pattern COMMA_PATTERN = Pattern.compile(","); | ||||
private static POILogger log = POILogFactory.getLogger(HSSFWorkbook.class); | 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!) | * Creates new HSSFWorkbook from scratch (start here!) | ||||
workbook = book; | workbook = book; | ||||
_sheets = new ArrayList( INITIAL_CAPACITY ); | _sheets = new ArrayList( INITIAL_CAPACITY ); | ||||
names = new ArrayList( INITIAL_CAPACITY ); | names = new ArrayList( INITIAL_CAPACITY ); | ||||
udfFunctions = new HashMap<String, FreeRefFunction>(); | |||||
} | } | ||||
public HSSFWorkbook(POIFSFileSystem fs) throws IOException { | public HSSFWorkbook(POIFSFileSystem fs) throws IOException { | ||||
_sheets = new ArrayList(INITIAL_CAPACITY); | _sheets = new ArrayList(INITIAL_CAPACITY); | ||||
names = new ArrayList(INITIAL_CAPACITY); | names = new ArrayList(INITIAL_CAPACITY); | ||||
udfFunctions = new HashMap<String, FreeRefFunction>(); | |||||
// Grab the data from the workbook stream, however | // Grab the data from the workbook stream, however | ||||
// it happens to be spelled. | // 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)? | * Is the workbook protected with a password (not encrypted)? |
import org.apache.poi.hssf.record.formula.NamePtg; | import org.apache.poi.hssf.record.formula.NamePtg; | ||||
import org.apache.poi.hssf.record.formula.NameXPtg; | import org.apache.poi.hssf.record.formula.NameXPtg; | ||||
import org.apache.poi.hssf.record.formula.Ptg; | 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/> | * Abstracts a workbook for the purpose of formula evaluation.<br/> | ||||
* For POI internal use only | * For POI internal use only | ||||
* | * | ||||
* @author Josh Micich | * @author Josh Micich | ||||
* | |||||
* Modified 09/07/09 by Petr Udalau - added methods for searching for UDFs of this Workbook. | |||||
*/ | */ | ||||
public interface EvaluationWorkbook { | public interface EvaluationWorkbook { | ||||
String getSheetName(int sheetIndex); | String getSheetName(int sheetIndex); | ||||
String resolveNameXText(NameXPtg ptg); | String resolveNameXText(NameXPtg ptg); | ||||
Ptg[] getFormulaTokens(EvaluationCell cell); | 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 { | class ExternalSheet { | ||||
private final String _workbookName; | private final String _workbookName; | ||||
private final String _sheetName; | private final String _sheetName; |
import org.apache.poi.hssf.record.formula.NamePtg; | import org.apache.poi.hssf.record.formula.NamePtg; | ||||
import org.apache.poi.hssf.record.formula.NameXPtg; | import org.apache.poi.hssf.record.formula.NameXPtg; | ||||
import org.apache.poi.hssf.record.formula.Ptg; | 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.EvaluationCell; | ||||
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; | ||||
* updated after a call to {@link #getOrCreateUpdatableCell(String, int, int)}. | * updated after a call to {@link #getOrCreateUpdatableCell(String, int, int)}. | ||||
* | * | ||||
* @author Josh Micich | * @author Josh Micich | ||||
* | |||||
* Modified 09/07/09 by Petr Udalau - added methods for searching for UDFs of this Workbook. | |||||
*/ | */ | ||||
final class ForkedEvaluationWorkbook implements EvaluationWorkbook { | final class ForkedEvaluationWorkbook implements EvaluationWorkbook { | ||||
return _index - o._index; | return _index - o._index; | ||||
} | } | ||||
} | } | ||||
public FreeRefFunction findUserDefinedFunction(String functionName) { | |||||
return _masterBook.findUserDefinedFunction(functionName); | |||||
} | |||||
} | } |
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.util.List; | import java.util.List; | ||||
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; | |||||
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; | import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; | ||||
/** | /** | ||||
* High level representation of a Excel workbook. This is the first object most users | * 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 | * will construct whether they are reading or writing a workbook. It is also the | ||||
* top level object for creating new sheets/etc. | * 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 { | public interface Workbook { | ||||
* @param hidden 0 for not hidden, 1 for hidden, 2 for very hidden | * @param hidden 0 for not hidden, 1 for hidden, 2 for very hidden | ||||
*/ | */ | ||||
void setSheetHidden(int sheetIx, int 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.NamePtg; | ||||
import org.apache.poi.hssf.record.formula.NameXPtg; | import org.apache.poi.hssf.record.formula.NameXPtg; | ||||
import org.apache.poi.hssf.record.formula.Ptg; | 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.formula.*; | ||||
import org.apache.poi.ss.SpreadsheetVersion; | import org.apache.poi.ss.SpreadsheetVersion; | ||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName; | import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName; | ||||
* Internal POI use only | * Internal POI use only | ||||
* | * | ||||
* @author Josh Micich | * @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 final class XSSFEvaluationWorkbook implements FormulaRenderingWorkbook, EvaluationWorkbook, FormulaParsingWorkbook { | ||||
public SpreadsheetVersion getSpreadsheetVersion(){ | public SpreadsheetVersion getSpreadsheetVersion(){ | ||||
return SpreadsheetVersion.EXCEL2007; | return SpreadsheetVersion.EXCEL2007; | ||||
} | } | ||||
public FreeRefFunction findUserDefinedFunction(String functionName) { | |||||
return _uBook.getUserDefinedFunction(functionName); | |||||
} | |||||
} | } |
import org.apache.poi.POIXMLException; | import org.apache.poi.POIXMLException; | ||||
import org.apache.poi.POIXMLProperties; | import org.apache.poi.POIXMLProperties; | ||||
import org.apache.poi.hssf.record.formula.SheetNameFormatter; | 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.exceptions.OpenXML4JException; | ||||
import org.apache.poi.openxml4j.opc.OPCPackage; | import org.apache.poi.openxml4j.opc.OPCPackage; | ||||
import org.apache.poi.openxml4j.opc.PackagePart; | import org.apache.poi.openxml4j.opc.PackagePart; | ||||
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.usermodel.Name; | |||||
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; | ||||
* High level representation of a SpreadsheetML workbook. This is the first object most users | * 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 | * will construct whether they are reading or writing a workbook. It is also the | ||||
* top level object for creating new sheets/etc. | * 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> { | public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<XSSFSheet> { | ||||
private static final Pattern COMMA_PATTERN = Pattern.compile(","); | private static final Pattern COMMA_PATTERN = Pattern.compile(","); | ||||
private List<XSSFPictureData> pictures; | private List<XSSFPictureData> pictures; | ||||
private static POILogger logger = POILogFactory.getLogger(XSSFWorkbook.class); | 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. | * Create a new SpreadsheetML workbook. | ||||
return mapInfo; | 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 junit.framework.TestCase; | ||||
import org.apache.poi.hssf.HSSFTestDataSamples; | 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.HSSFCell; | ||||
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; | 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.HSSFRow; | ||||
import org.apache.poi.hssf.usermodel.HSSFSheet; | import org.apache.poi.hssf.usermodel.HSSFSheet; | ||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook; | 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 | * @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 { | 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); | |||||
} | |||||
} | |||||
} | } |