From 3fcc6e8e9ca1834aaff1f696c213cba21a1c596a Mon Sep 17 00:00:00 2001 From: richie Date: Wed, 27 Feb 2019 14:52:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=BC=E5=AE=B9=E4=B8=80=E4=B8=AA=E6=94=B9?= =?UTF-8?q?=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../formula/compat/FunctionConstants.java | 323 ++++++++++++++++++ .../design/formula/ui/GroupFormulaPane.java | 2 +- 2 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/fr/solution/plugin/design/formula/compat/FunctionConstants.java diff --git a/src/main/java/com/fr/solution/plugin/design/formula/compat/FunctionConstants.java b/src/main/java/com/fr/solution/plugin/design/formula/compat/FunctionConstants.java new file mode 100644 index 0000000..cb2b3f6 --- /dev/null +++ b/src/main/java/com/fr/solution/plugin/design/formula/compat/FunctionConstants.java @@ -0,0 +1,323 @@ +package com.fr.solution.plugin.design.formula.compat; + +import com.fr.design.formula.FunctionDefNAD; +import com.fr.design.formula.FunctionGroup; +import com.fr.design.formula.NameAndDescription; +import com.fr.design.formula.NameAndFunctionList; +import com.fr.design.formula.NameAndTypeAndFunctionList; +import com.fr.file.FunctionConfig; +import com.fr.function.AVERAGE; +import com.fr.function.CHAR; +import com.fr.function.COUNT; +import com.fr.function.DATE; +import com.fr.function.MAX; +import com.fr.function.MIN; +import com.fr.function.RANGE; +import com.fr.function.SUM; +import com.fr.function.TIME; +import com.fr.general.ComparatorUtils; +import com.fr.general.GeneralUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.ExtraClassManager; +import com.fr.stable.EncodeConstants; +import com.fr.stable.OperatingSystem; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.fun.FunctionDefContainer; +import com.fr.stable.fun.mark.Mutable; +import com.fr.stable.script.Function; +import com.fr.stable.script.FunctionDef; + +import javax.swing.DefaultListModel; +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.List; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-02-27 + */ +public final class FunctionConstants { + + public static FunctionGroup PLUGIN = getPluginFunctionGroup(); + public static FunctionGroup CUSTOM = getCustomFunctionGroup(); + public static NameAndFunctionList COMMON = getCommonFunctionList(); + public static NameAndTypeAndFunctionList[] EMBFUNCTIONS = getEmbededFunctionListArray(); + public static FunctionGroup ALL = getAllFunctionGroup(); + + static { + loadEmbededFunctions(); + } + + /** + * Don't let anyone instantiate this class. + */ + private FunctionConstants() {} + + private static void loadEmbededFunctions() { + String pkgName = "com.fr.function"; + Class iface = Function.class; + ClassLoader classloader = iface.getClassLoader(); + Enumeration urlEnumeration = null; + try { + urlEnumeration = classloader.getResources(pkgName.replace('.', '/')); + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + return; + } + while (urlEnumeration.hasMoreElements()) { + URL url = urlEnumeration.nextElement(); + String classFilePath = url.getFile(); + /* + * alex:url.getFile获取的地址中,如果有空格或中文会被URLEncoder.encode处理 + * 会变成%20这种%打头的东西,但是new File的时候%20是无法解析成空格,所以在此需要做URLDecoder.decode处理 + */ + try { + classFilePath = URLDecoder.decode(classFilePath, EncodeConstants.ENCODING_UTF_8); + } catch (UnsupportedEncodingException e1) { + FineLoggerFactory.getLogger().error(e1.getMessage(), e1); + } + FineLoggerFactory.getLogger().info("ClassFilePath:" + classFilePath); + if (isCustomFormulaPath(classFilePath)) { + continue; + } + for (String fileName : findClassNamesUnderFilePath(classFilePath)) { + try { + Class cls = Class.forName(pkgName + "." + fileName.substring(0, fileName.length() - 6)); + if (StableUtils.classInstanceOf(cls, iface)) { + Function inst; + inst = (Function)cls.newInstance(); + for (NameAndTypeAndFunctionList EMBFUNCTION : EMBFUNCTIONS) { + if (EMBFUNCTION.test(inst)) { + break; + } + } + } + } catch (Exception ignore) { + } catch (Throwable e) { + // 不要因为个别公式加载失败,而导致整个函数面板无法启动 + FineLoggerFactory.getLogger().error(e.getMessage()); + } + } + } + } + + private static boolean isCustomFormulaPath(String classFilePath) { + return !isJarPath(classFilePath) && isNotDebugMode(); + } + + private static boolean isNotDebugMode() { + return GeneralUtils.readBuildNO().contains("-"); + } + + private static boolean isJarPath(String classFilePath) { + return classFilePath.contains("!/"); + } + + /** + * 将函数分组插件中的函数添加到对应的列表中 + * @param listModel + */ + public static void addFunctionGroupFromPlugins(DefaultListModel listModel){ + //hugh:自定义函数分组 + Set containers = ExtraClassManager.getInstance().getArray(FunctionDefContainer.MARK_STRING); + if(!containers.isEmpty()){ + for(Mutable container : containers){ + listModel.addElement(createFunctionGroup((FunctionDefContainer)container)); + } + } + } + + /** + * 创建一个新的分组 + * @param container + * @return + */ + private static FunctionGroup createFunctionGroup(final FunctionDefContainer container){ + return new FunctionGroup() { + @Override + public String getGroupName() { + return container.getGroupName(); + } + + @Override + public NameAndDescription[] getDescriptions() { + FunctionDef[] fs = container.getFunctionDefs(); + int count = fs.length; + FunctionDefNAD[] nads = new FunctionDefNAD[count]; + for (int i = 0; i < count; i ++) { + nads[i] = new FunctionDefNAD(fs[i]); + } + return nads; + } + }; + } + + + private static String[] findClassNamesUnderFilePath(String filePath) { + java.util.List classNameList = new ArrayList(); + /* + * alex:如果是jar包中的class文件 + * file:/D:/opt/FineReport6.5/WebReport/WEB-INF/lib/fr-server-6.5.jar!/com/fr/rpt/script/function + */ + if (isJarPath(filePath)) { + String[] arr = filePath.split("!/"); + String jarPath = arr[0].substring(6); // alex:substring(6)去掉前面的file:/这六个字符 + String classPath = arr[1]; + if(classPath.endsWith("/")){ + classPath = classPath.substring(0, classPath.length() - 1); + } + if (!OperatingSystem.isWindows()){ + //windows里substring后是d:\123\456, mac下substring后是Application/123/456 + jarPath = StringUtils.perfectStart(jarPath, "/"); + } + + ZipFile zip; + try { + zip = new ZipFile(jarPath); + Enumeration entries = zip.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = (ZipEntry) entries.nextElement(); + if (entry.isDirectory()) { + continue; + } + + String entryName = entry.getName(); + if (!entryName.contains(classPath) || !entryName.endsWith(".class")) { + continue; + } + + classNameList.add(entryName.substring(classPath.length() + 1)); + } + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } else { + File dir = new File(filePath); + File[] files = dir.listFiles(); + if (files != null) { + for (File f : files) { + String fileName = f.getName(); + if (fileName.endsWith(".class")) { + classNameList.add(fileName); + } + } + } + } + + return classNameList.toArray(new String[0]); + } + + private static FunctionGroup getPluginFunctionGroup() { + return new FunctionGroup() { + @Override + public String getGroupName() { + return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Base_Formula_Plugin"); + } + + @Override + public NameAndDescription[] getDescriptions() { + FunctionDef[] fs = ExtraClassManager.getInstance().getFunctionDef(); + int count = fs.length; + FunctionDefNAD[] nads = new FunctionDefNAD[count]; + for (int i = 0; i < count; i ++) { + nads[i] = new FunctionDefNAD(fs[i]); + } + return nads; + } + }; + } + + private static FunctionGroup getCustomFunctionGroup() { + return new FunctionGroup() { + @Override + public String getGroupName() { + return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Custom_Function"); + } + + @Override + public NameAndDescription[] getDescriptions() { + FunctionConfig funtionManager = FunctionConfig.getInstance(); + if (funtionManager != null) { + int functionDefCount = funtionManager.getFunctionDefCount(); + + FunctionDefNAD[] nads = new FunctionDefNAD[functionDefCount]; + for (int i = 0; i < functionDefCount; i++) { + nads[i] = new FunctionDefNAD(funtionManager.getFunctionDef(i)); + } + + return nads; + } + + return new NameAndDescription[0]; + } + }; + } + + private static NameAndFunctionList getCommonFunctionList() { + return new NameAndFunctionList(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Most_Recently_Used"), new Function[] { + new SUM(), new COUNT(), new AVERAGE(), new CHAR(), new DATE(), new MAX(), new MIN(), new TIME(), new RANGE() + }); + } + + private static NameAndTypeAndFunctionList[] getEmbededFunctionListArray() { + return new NameAndTypeAndFunctionList[] { + new NameAndTypeAndFunctionList(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Math_&_Trig"), Function.MATH), + new NameAndTypeAndFunctionList(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Text"), Function.TEXT), + new NameAndTypeAndFunctionList(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Date_&_Time"), Function.DATETIME), + new NameAndTypeAndFunctionList(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Logical"), Function.LOGIC), + new NameAndTypeAndFunctionList(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Array"), Function.ARRAY), + new NameAndTypeAndFunctionList(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Report"), Function.REPORT), + new NameAndTypeAndFunctionList(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Other"), Function.OTHER), + new NameAndTypeAndFunctionList(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Function_Type_Hierarchy"), Function.HA) + }; + } + + private static FunctionGroup getAllFunctionGroup() { + return new FunctionGroup() { + @Override + public String getGroupName() { + return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_All"); + } + + @Override + public NameAndDescription[] getDescriptions() { + List all = new ArrayList(); + for (int i = 0; i < EMBFUNCTIONS.length; i++) { + all.addAll(Arrays.asList(EMBFUNCTIONS[i].getDescriptions())); + } + Collections.addAll(all, PLUGIN.getDescriptions()); + Collections.addAll(all, CUSTOM.getDescriptions()); + //hugh:自定义函数分组 + Set containers = ExtraClassManager.getInstance().getArray(FunctionDefContainer.MARK_STRING); + if(!containers.isEmpty()){ + for(Mutable container : containers){ + Collections.addAll(all,createFunctionGroup(((FunctionDefContainer)container)).getDescriptions()); + } + } + + Collections.sort(all, new Comparator() { + @Override + public int compare(NameAndDescription o1, NameAndDescription o2) { + return ComparatorUtils.compare(o1.getName(), o2.getName()); + } + }); + + return all.toArray(new NameAndDescription[0]); + } + }; + } +} + diff --git a/src/main/java/com/fr/solution/plugin/design/formula/ui/GroupFormulaPane.java b/src/main/java/com/fr/solution/plugin/design/formula/ui/GroupFormulaPane.java index 2a0d81b..5f61f31 100644 --- a/src/main/java/com/fr/solution/plugin/design/formula/ui/GroupFormulaPane.java +++ b/src/main/java/com/fr/solution/plugin/design/formula/ui/GroupFormulaPane.java @@ -14,7 +14,6 @@ import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.BasicPane; import com.fr.design.dialog.DialogActionAdapter; import com.fr.design.file.HistoryTemplateListPane; -import com.fr.design.formula.FunctionConstants; import com.fr.design.formula.FunctionGroup; import com.fr.design.formula.NameAndDescription; import com.fr.design.formula.UIFormula; @@ -34,6 +33,7 @@ import com.fr.general.GeneralUtils; import com.fr.general.Inter; import com.fr.report.core.namespace.SimpleCellValueNameSpace; import com.fr.script.Calculator; +import com.fr.solution.plugin.design.formula.compat.FunctionConstants; import com.fr.solution.plugin.design.formula.ui.evt.OperateListener; import com.fr.solution.plugin.design.formula.ui.type.CategoryFormulaPane; import com.fr.stable.ArrayUtils;