|
|
|
@ -2,32 +2,67 @@ package com.fr.design.formula;
|
|
|
|
|
|
|
|
|
|
import com.fr.base.BaseFormula; |
|
|
|
|
import com.fr.base.BaseUtils; |
|
|
|
|
import com.fr.base.Parameter; |
|
|
|
|
import com.fr.base.ParameterMapNameSpace; |
|
|
|
|
import com.fr.base.TableDataNameSpace; |
|
|
|
|
import com.fr.data.TableDataSource; |
|
|
|
|
import com.fr.design.actions.UpdateAction; |
|
|
|
|
import com.fr.design.border.UIRoundedBorder; |
|
|
|
|
import com.fr.design.constants.UIConstants; |
|
|
|
|
import com.fr.design.dialog.BasicDialog; |
|
|
|
|
import com.fr.design.dialog.BasicPane; |
|
|
|
|
import com.fr.design.dialog.DialogActionAdapter; |
|
|
|
|
import com.fr.design.dialog.FineJOptionPane; |
|
|
|
|
import com.fr.design.file.HistoryTemplateListCache; |
|
|
|
|
import com.fr.design.gui.ibutton.UIButton; |
|
|
|
|
import com.fr.design.gui.icontainer.UIScrollPane; |
|
|
|
|
import com.fr.design.gui.ilable.UILabel; |
|
|
|
|
import com.fr.design.gui.ilist.QuickList; |
|
|
|
|
import com.fr.design.gui.itableeditorpane.ParameterTableModel; |
|
|
|
|
import com.fr.design.gui.itableeditorpane.UITableEditorPane; |
|
|
|
|
import com.fr.design.gui.itextarea.UITextArea; |
|
|
|
|
import com.fr.design.gui.itextfield.UITextField; |
|
|
|
|
import com.fr.design.gui.syntax.ui.rsyntaxtextarea.RSyntaxTextArea; |
|
|
|
|
import com.fr.design.gui.syntax.ui.rsyntaxtextarea.SyntaxConstants; |
|
|
|
|
import com.fr.design.i18n.Toolkit; |
|
|
|
|
import com.fr.design.layout.FRGUIPaneFactory; |
|
|
|
|
import com.fr.design.mainframe.DesignerContext; |
|
|
|
|
import com.fr.design.parameter.ParameterInputPane; |
|
|
|
|
import com.fr.design.utils.gui.GUICoreUtils; |
|
|
|
|
import com.fr.general.ComparatorUtils; |
|
|
|
|
import com.fr.log.FineLoggerFactory; |
|
|
|
|
import com.fr.main.impl.WorkBook; |
|
|
|
|
import com.fr.parser.FRLexer; |
|
|
|
|
import com.fr.parser.FRParser; |
|
|
|
|
import com.fr.report.core.namespace.SimpleCellValueNameSpace; |
|
|
|
|
import com.fr.script.Calculator; |
|
|
|
|
import com.fr.script.ScriptConstants; |
|
|
|
|
import com.fr.script.checker.FunctionCheckerDispatcher; |
|
|
|
|
import com.fr.script.checker.exception.FunctionCheckWrongException; |
|
|
|
|
import com.fr.script.rules.FunctionParameterType; |
|
|
|
|
import com.fr.script.rules.FunctionRule; |
|
|
|
|
import com.fr.stable.EncodeConstants; |
|
|
|
|
import com.fr.stable.ParameterProvider; |
|
|
|
|
import com.fr.stable.StringUtils; |
|
|
|
|
import com.fr.stable.UtilEvalError; |
|
|
|
|
import com.fr.stable.script.ColumnRowRange; |
|
|
|
|
import com.fr.stable.script.Expression; |
|
|
|
|
|
|
|
|
|
import javax.swing.*; |
|
|
|
|
import com.fr.stable.script.Node; |
|
|
|
|
import com.fr.stable.script.Tiny; |
|
|
|
|
import com.fr.stable.script.TinyHunter; |
|
|
|
|
|
|
|
|
|
import javax.swing.BorderFactory; |
|
|
|
|
import javax.swing.DefaultListCellRenderer; |
|
|
|
|
import javax.swing.DefaultListModel; |
|
|
|
|
import javax.swing.Icon; |
|
|
|
|
import javax.swing.JComponent; |
|
|
|
|
import javax.swing.JFrame; |
|
|
|
|
import javax.swing.JList; |
|
|
|
|
import javax.swing.JOptionPane; |
|
|
|
|
import javax.swing.JPanel; |
|
|
|
|
import javax.swing.JPopupMenu; |
|
|
|
|
import javax.swing.JTree; |
|
|
|
|
import javax.swing.SwingUtilities; |
|
|
|
|
import javax.swing.event.ListSelectionEvent; |
|
|
|
|
import javax.swing.event.ListSelectionListener; |
|
|
|
|
import javax.swing.event.TreeSelectionEvent; |
|
|
|
@ -37,7 +72,10 @@ import javax.swing.tree.DefaultTreeCellRenderer;
|
|
|
|
|
import javax.swing.tree.DefaultTreeModel; |
|
|
|
|
import javax.swing.tree.MutableTreeNode; |
|
|
|
|
import javax.swing.tree.TreePath; |
|
|
|
|
import java.awt.*; |
|
|
|
|
import java.awt.BorderLayout; |
|
|
|
|
import java.awt.Color; |
|
|
|
|
import java.awt.Component; |
|
|
|
|
import java.awt.Dimension; |
|
|
|
|
import java.awt.event.ActionEvent; |
|
|
|
|
import java.awt.event.ActionListener; |
|
|
|
|
import java.awt.event.KeyAdapter; |
|
|
|
@ -55,7 +93,11 @@ import java.io.StringReader;
|
|
|
|
|
import java.util.ArrayList; |
|
|
|
|
import java.util.Collections; |
|
|
|
|
import java.util.Comparator; |
|
|
|
|
import java.util.HashMap; |
|
|
|
|
import java.util.HashSet; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.util.Map; |
|
|
|
|
import java.util.Set; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 公式编辑面板 |
|
|
|
@ -65,6 +107,8 @@ import java.util.List;
|
|
|
|
|
*/ |
|
|
|
|
public class FormulaPane extends BasicPane implements KeyListener, UIFormula { |
|
|
|
|
|
|
|
|
|
public static final String VALID_FORMULA = Toolkit.i18nText("Fine-Design_Basic_FormulaD_Valid_Formula"); |
|
|
|
|
public static final String INVALID_FORMULA = Toolkit.i18nText("Fine-Design_Basic_FormulaD_Invalid_Formula"); |
|
|
|
|
private VariableTreeAndDescriptionArea variableTreeAndDescriptionArea; |
|
|
|
|
private RSyntaxTextArea formulaTextArea; |
|
|
|
|
private UITextField keyWordTextField = new UITextField(18); |
|
|
|
@ -78,6 +122,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
|
|
|
|
|
private QuickList functionTypeList; |
|
|
|
|
private DefaultListModel functionNameModel; |
|
|
|
|
private JList functionNameList; |
|
|
|
|
private UITableEditorPane<ParameterProvider> editor4CalPane; |
|
|
|
|
|
|
|
|
|
public FormulaPane() { |
|
|
|
|
initComponents(); |
|
|
|
@ -201,6 +246,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
|
|
|
|
|
|
|
|
|
|
private void initTextPane() { |
|
|
|
|
// text
|
|
|
|
|
|
|
|
|
|
JPanel textPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
|
|
|
|
this.add(textPane, BorderLayout.CENTER); |
|
|
|
|
JPanel checkBoxandbuttonPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); |
|
|
|
@ -217,13 +263,19 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UIButton checkValidButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Check_Valid")); |
|
|
|
|
UIButton calButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Formula_Cal_Button")); |
|
|
|
|
checkValidButton.addActionListener(checkValidActionListener); |
|
|
|
|
calButton.addActionListener(calculateActionListener); |
|
|
|
|
|
|
|
|
|
JPanel checkBoxPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); |
|
|
|
|
checkBoxPane.setPreferredSize(new Dimension(450, 30)); |
|
|
|
|
checkBoxandbuttonPane.add(checkBoxPane, BorderLayout.WEST); |
|
|
|
|
checkBoxandbuttonPane.add(checkValidButton, BorderLayout.EAST); |
|
|
|
|
checkBoxandbuttonPane.add(calButton, BorderLayout.EAST); |
|
|
|
|
extendCheckBoxPane(checkBoxPane); |
|
|
|
|
|
|
|
|
|
ParameterTableModel model = new ParameterTableModel(0); |
|
|
|
|
editor4CalPane = new UITableEditorPane<>(model); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -585,39 +637,150 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// check valid
|
|
|
|
|
private ActionListener checkValidActionListener = new ActionListener() { |
|
|
|
|
private final ActionListener checkValidActionListener = new ActionListener() { |
|
|
|
|
|
|
|
|
|
public void actionPerformed(ActionEvent evt) { |
|
|
|
|
// Execute Formula default cell element.
|
|
|
|
|
String formulaText = formulaTextArea.getText().trim(); |
|
|
|
|
String formulaValidMessage = getFormulaValidMessage(formulaText); |
|
|
|
|
FineJOptionPane.showMessageDialog( |
|
|
|
|
FormulaPane.this, |
|
|
|
|
formulaValidMessage + ".", |
|
|
|
|
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), |
|
|
|
|
JOptionPane.INFORMATION_MESSAGE); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
if (formulaText != null && formulaText.length() > 0) { |
|
|
|
|
StringReader in = new StringReader(formulaText); |
|
|
|
|
private static String getFormulaValidMessage(String formulaText) { |
|
|
|
|
StringReader in = new StringReader(formulaText); |
|
|
|
|
|
|
|
|
|
FRLexer lexer = new FRLexer(in); |
|
|
|
|
FRParser parser = new FRParser(lexer); |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
Expression expression = parser.parse(); |
|
|
|
|
Node node = expression.getConditionalExpression(); |
|
|
|
|
return FunctionCheckerDispatcher.getInstance() |
|
|
|
|
.getFunctionChecker(node) |
|
|
|
|
.checkFunction(node) ? VALID_FORMULA : INVALID_FORMULA; |
|
|
|
|
} catch (FunctionCheckWrongException ce) { |
|
|
|
|
List<FunctionRule> rules = ce.getRules(); |
|
|
|
|
String functionName = ce.getFunctionName(); |
|
|
|
|
StringBuilder errorMsg = new StringBuilder(functionName + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Error_Tips") + ":"); |
|
|
|
|
for (int i = 0; i < rules.size(); i++) { |
|
|
|
|
errorMsg.append("("); |
|
|
|
|
for (FunctionParameterType functionParameterType : rules.get(i).getParameterList()) { |
|
|
|
|
errorMsg.append(getTypeString(functionParameterType)).append(","); |
|
|
|
|
} |
|
|
|
|
if (",".equals(errorMsg.charAt(errorMsg.length() - 1) + "")) { |
|
|
|
|
errorMsg.deleteCharAt(errorMsg.length() - 1); |
|
|
|
|
} |
|
|
|
|
errorMsg.append(")"); |
|
|
|
|
if (i != rules.size() - 1) { |
|
|
|
|
errorMsg.append(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Or")); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return errorMsg.toString(); |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
|
|
|
return INVALID_FORMULA; |
|
|
|
|
// alex:继续往下面走,expression为null时告知不合法公式
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static String getTypeString(FunctionParameterType type) { |
|
|
|
|
switch (type) { |
|
|
|
|
case NUMBER: |
|
|
|
|
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Number"); |
|
|
|
|
case STRING: |
|
|
|
|
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_String"); |
|
|
|
|
case ANY: |
|
|
|
|
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Any"); |
|
|
|
|
case DATE: |
|
|
|
|
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Date"); |
|
|
|
|
case BOOLEAN: |
|
|
|
|
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Boolean"); |
|
|
|
|
case ARRAY: |
|
|
|
|
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Check_ParamType_Array"); |
|
|
|
|
} |
|
|
|
|
return ""; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
FRLexer lexer = new FRLexer(in); |
|
|
|
|
FRParser parser = new FRParser(lexer); |
|
|
|
|
private final ActionListener calculateActionListener = new ActionListener() { |
|
|
|
|
@Override |
|
|
|
|
public void actionPerformed(ActionEvent e) { |
|
|
|
|
String formulaText = formulaTextArea.getText().trim(); |
|
|
|
|
String messageTips = getFormulaValidMessage(formulaText).equals(VALID_FORMULA) ? " " : getFormulaValidMessage(formulaText) + "\n"; |
|
|
|
|
Map<String, Object> paramsMap = setParamsIfExist(formulaText); |
|
|
|
|
Calculator calculator = Calculator.createCalculator(); |
|
|
|
|
ParameterMapNameSpace parameterMapNameSpace = ParameterMapNameSpace.create(paramsMap); |
|
|
|
|
calculator.pushNameSpace(parameterMapNameSpace); |
|
|
|
|
|
|
|
|
|
WorkBook workBook = (WorkBook) HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getTarget(); |
|
|
|
|
calculator.pushNameSpace(SimpleCellValueNameSpace.getInstance()); |
|
|
|
|
TableDataSource tableDataSource = workBook.getReport(0).getTableDataSource(); |
|
|
|
|
calculator.setAttribute(TableDataSource.KEY, tableDataSource); |
|
|
|
|
calculator.pushNameSpace(TableDataNameSpace.getInstance()); |
|
|
|
|
BaseFormula baseFormula = BaseFormula.createFormulaBuilder().build(formulaText); |
|
|
|
|
try { |
|
|
|
|
Object value = calculator.evalValue(baseFormula); |
|
|
|
|
messageTips = messageTips + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_Cal_Result") + ":" + value; |
|
|
|
|
FineLoggerFactory.getLogger().info("value:{}", value); |
|
|
|
|
} catch (UtilEvalError utilEvalError) { |
|
|
|
|
FineLoggerFactory.getLogger().error("", utilEvalError); |
|
|
|
|
} |
|
|
|
|
FineJOptionPane.showMessageDialog( |
|
|
|
|
FormulaPane.this, |
|
|
|
|
messageTips, |
|
|
|
|
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), |
|
|
|
|
JOptionPane.INFORMATION_MESSAGE); |
|
|
|
|
|
|
|
|
|
Expression expression = null; |
|
|
|
|
try { |
|
|
|
|
expression = parser.parse(); |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
|
|
|
// alex:继续往下面走,expression为null时告知不合法公式
|
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
private Map<String, Object> setParamsIfExist(String formulaText) { |
|
|
|
|
Map<String, Object> parameterMap = new HashMap<>(); |
|
|
|
|
try { |
|
|
|
|
Expression expression = Calculator.createCalculator().parse(formulaText); |
|
|
|
|
ParameterCellHunter parameterCellHunter = new ParameterCellHunter(); |
|
|
|
|
expression.traversal4Tiny(parameterCellHunter); |
|
|
|
|
Parameter[] parameters = parameterCellHunter.getParameterBooty(); |
|
|
|
|
|
|
|
|
|
if (parameters.length < 1 && editor4CalPane.update().size() < 1) { |
|
|
|
|
return parameterMap; |
|
|
|
|
} |
|
|
|
|
ParameterInputPane pPane = new ParameterInputPane(parameters); |
|
|
|
|
pPane.showSmallWindow(new JFrame(), new DialogActionAdapter() { |
|
|
|
|
@Override |
|
|
|
|
public void doOk() { |
|
|
|
|
parameterMap.putAll(pPane.update()); |
|
|
|
|
} |
|
|
|
|
}).setVisible(true); |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
FineLoggerFactory.getLogger().error("", e); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return parameterMap; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static class ParameterCellHunter extends TinyHunter { |
|
|
|
|
|
|
|
|
|
private final Set<Parameter> parameterList = new HashSet<>(); |
|
|
|
|
|
|
|
|
|
Parameter[] getParameterBooty() { |
|
|
|
|
|
|
|
|
|
FineJOptionPane.showMessageDialog( |
|
|
|
|
FormulaPane.this, |
|
|
|
|
/* |
|
|
|
|
* alex:仅仅只需要根据expression是否为null作合法性判断 |
|
|
|
|
* 不需要eval |
|
|
|
|
* TODO 但有个问题,有些函数的参数个数是有规定的,何以判别之 |
|
|
|
|
*/ |
|
|
|
|
(expression != null ? com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Valid_Formula") : com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Invalid_Formula")) + ".", |
|
|
|
|
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), |
|
|
|
|
JOptionPane.INFORMATION_MESSAGE); |
|
|
|
|
return parameterList.toArray(new Parameter[0]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void hunter4Tiny(Tiny tiny) { |
|
|
|
|
String statement = tiny.getStatement(); |
|
|
|
|
if (StringUtils.isNotBlank(statement) && statement.startsWith(ScriptConstants.DETAIL_TAG)) { |
|
|
|
|
parameterList.add(new Parameter(statement.substring(1))); |
|
|
|
|
} else if (tiny.getClass().equals(ColumnRowRange.class)) { |
|
|
|
|
parameterList.add(new Parameter(tiny.toString())); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public class VariableTreeAndDescriptionArea extends JPanel { |
|
|
|
|
|
|
|
|
@ -805,13 +968,13 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
|
|
|
|
|
public void valueChanged(TreeSelectionEvent e) { |
|
|
|
|
DefaultMutableTreeNode selectedTreeNode = (DefaultMutableTreeNode) variablesTree.getLastSelectedPathComponent(); |
|
|
|
|
Object selectedValue = selectedTreeNode.getUserObject(); |
|
|
|
|
Object selectedParentValue = ((DefaultMutableTreeNode)selectedTreeNode.getParent()).getUserObject(); |
|
|
|
|
Object selectedParentValue = ((DefaultMutableTreeNode) selectedTreeNode.getParent()).getUserObject(); |
|
|
|
|
|
|
|
|
|
if (selectedValue == null) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (selectedValue instanceof TextUserObject) { |
|
|
|
|
if (selectedValue instanceof TextUserObject) { |
|
|
|
|
//有公式说明的条件:1.属于TextUserObject 2.parent是系统参数
|
|
|
|
|
if (ComparatorUtils.equals(((TextFolderUserObject) selectedParentValue).getText(), |
|
|
|
|
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Variables"))) { |
|
|
|
@ -1010,6 +1173,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 把以关键词开头的和不以关键词开头的分别按照字母表顺序排序 |
|
|
|
|
* |
|
|
|
|
* @param o1 待比较对象1 |
|
|
|
|
* @param o2 待比较对象2 |
|
|
|
|
* @return 比较结果,1表示 o1 > o2, -1表示 o1 < o2, 0表示 o1 = o2 |
|
|
|
|