diff --git a/plugin.xml b/plugin.xml index ee8251f..fbbac50 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,7 +1,7 @@ - com.fr.solution.plugin - com.fr.solotion.plugin.designer.formula.editor + com.fr.solution.plugin + com.fr.solution.plugin.design.formula.script yes 3.0 @@ -13,12 +13,10 @@ [2017-12-10]初始化插件。
]]> - + - - + - - +
\ No newline at end of file diff --git a/src/com/fr/solution/plugin/design/formula/ScriptFormulaLocalFinder.java b/src/com/fr/solution/plugin/design/formula/ScriptFormulaLocalFinder.java index 41c7bb8..5349042 100644 --- a/src/com/fr/solution/plugin/design/formula/ScriptFormulaLocalFinder.java +++ b/src/com/fr/solution/plugin/design/formula/ScriptFormulaLocalFinder.java @@ -1,5 +1,11 @@ package com.fr.solution.plugin.design.formula; -public class ScriptFormulaLocalFinder { - +import com.fr.stable.fun.impl.AbstractLocaleFinder; + +public class ScriptFormulaLocalFinder extends AbstractLocaleFinder { + + @Override + public String find() { + return "com/fr/solution/plugin/design/formula/locale/formula"; + } } \ No newline at end of file diff --git a/src/com/fr/solution/plugin/design/formula/ScriptFormulaUI.java b/src/com/fr/solution/plugin/design/formula/ScriptFormulaUI.java new file mode 100644 index 0000000..05beb1e --- /dev/null +++ b/src/com/fr/solution/plugin/design/formula/ScriptFormulaUI.java @@ -0,0 +1,23 @@ +package com.fr.solution.plugin.design.formula; + +import com.fr.design.formula.UIFormula; +import com.fr.design.fun.impl.AbstractUIFormulaProcessor; +import com.fr.plugin.transform.ExecuteFunctionRecord; +import com.fr.plugin.transform.FunctionRecorder; +import com.fr.solution.plugin.design.formula.ui.ScriptFormulaPane; + +@FunctionRecorder(localeKey = "Script") +public class ScriptFormulaUI extends AbstractUIFormulaProcessor { + + @Override + @ExecuteFunctionRecord + public UIFormula appearanceFormula() { + return new ScriptFormulaPane(); + } + + @Override + @ExecuteFunctionRecord + public UIFormula appearanceWhenReserveFormula() { + return new ScriptFormulaPane(); + } +} diff --git a/src/com/fr/solution/plugin/design/formula/locale/formula.properties b/src/com/fr/solution/plugin/design/formula/locale/formula.properties new file mode 100644 index 0000000..500d3bf --- /dev/null +++ b/src/com/fr/solution/plugin/design/formula/locale/formula.properties @@ -0,0 +1,2 @@ +Plugin-Script_Formula_Title=Script Formula +Plugin-Basic_Formula_Title=Basic Formula \ No newline at end of file diff --git a/src/com/fr/solution/plugin/design/formula/locale/formula_en_US.properties b/src/com/fr/solution/plugin/design/formula/locale/formula_en_US.properties new file mode 100644 index 0000000..500d3bf --- /dev/null +++ b/src/com/fr/solution/plugin/design/formula/locale/formula_en_US.properties @@ -0,0 +1,2 @@ +Plugin-Script_Formula_Title=Script Formula +Plugin-Basic_Formula_Title=Basic Formula \ No newline at end of file diff --git a/src/com/fr/solution/plugin/design/formula/locale/formula_ja_JP.properties b/src/com/fr/solution/plugin/design/formula/locale/formula_ja_JP.properties new file mode 100644 index 0000000..500d3bf --- /dev/null +++ b/src/com/fr/solution/plugin/design/formula/locale/formula_ja_JP.properties @@ -0,0 +1,2 @@ +Plugin-Script_Formula_Title=Script Formula +Plugin-Basic_Formula_Title=Basic Formula \ No newline at end of file diff --git a/src/com/fr/solution/plugin/design/formula/locale/formula_zh_CN.properties b/src/com/fr/solution/plugin/design/formula/locale/formula_zh_CN.properties new file mode 100644 index 0000000..d570721 --- /dev/null +++ b/src/com/fr/solution/plugin/design/formula/locale/formula_zh_CN.properties @@ -0,0 +1,2 @@ +Plugin-Script_Formula_Title=脚本公式 +Plugin-Basic_Formula_Title=普通公式 \ No newline at end of file diff --git a/src/com/fr/solution/plugin/design/formula/ui/ScriptFormulaPane.java b/src/com/fr/solution/plugin/design/formula/ui/ScriptFormulaPane.java new file mode 100644 index 0000000..655a304 --- /dev/null +++ b/src/com/fr/solution/plugin/design/formula/ui/ScriptFormulaPane.java @@ -0,0 +1,732 @@ +package com.fr.solution.plugin.design.formula.ui; + +import com.fr.base.BaseFormula; +import com.fr.base.BaseUtils; +import com.fr.base.FRContext; +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.formula.FunctionConstants; +import com.fr.design.formula.FunctionGroup; +import com.fr.design.formula.NameAndDescription; +import com.fr.design.formula.UIFormula; +import com.fr.design.formula.VariableResolver; +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.itextarea.UITextArea; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.general.Inter; +import com.fr.solution.plugin.design.formula.ui.evt.OperateListener; +import com.fr.solution.plugin.design.formula.ui.type.CategoryFormulaPane; +import com.fr.stable.EncodeConstants; +import com.fr.stable.StringUtils; + +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +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.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.util.Locale; + +/** + * 组合了普通公式和脚本公式的编辑器面板 + */ +public class ScriptFormulaPane extends BasicPane implements UIFormula, OperateListener { + + private VariableTreeAndDescriptionArea variableTreeAndDescriptionArea; + + private CategoryFormulaPane formulaPane; + + private UITextField keyWordTextField = new UITextField(18); + + private JList tipsList; + private DefaultListModel listModel = new DefaultListModel(); + + private DefaultListModel functionTypeListModel = new DefaultListModel(); + private QuickList functionTypeList; + private DefaultListModel functionNameModel; + private JList functionNameList; + + public ScriptFormulaPane() { + initComponents(); + } + + + private void initKeyWordTextFieldKeyListener() { + keyWordTextField.addKeyListener(new KeyListener() { + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyReleased(KeyEvent e) { + } + + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + String toFind = keyWordTextField.getText(); + search(toFind, false); + fixFunctionNameList(); + e.consume(); + } + } + }); + } + + + protected void initComponents() { + this.setLayout(new BorderLayout(4, 4)); + // text + JPanel textPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + this.add(textPane, BorderLayout.CENTER); + JPanel checkBoxAndButtonPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); + UILabel formulaLabel = new UILabel(Inter.getLocText("FormulaD-Input_formula_in_the_text_area_below") + ":" + + " "); + formulaLabel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); + + formulaPane = new CategoryFormulaPane(); + formulaPane.setOperateListener(this); + + textPane.add(formulaLabel, BorderLayout.NORTH); + textPane.add(formulaPane, BorderLayout.CENTER); + textPane.add(checkBoxAndButtonPane, BorderLayout.SOUTH); + + initTipsPane(); + + UIButton checkValidButton = new UIButton(Inter.getLocText("FormulaD-Check_Valid")); + checkValidButton.addActionListener(checkValidActionListener); + + JPanel checkBoxPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); + checkBoxPane.setPreferredSize(new Dimension(450, 30)); + checkBoxAndButtonPane.add(checkBoxPane, BorderLayout.WEST); + checkBoxAndButtonPane.add(checkValidButton, BorderLayout.EAST); + extendCheckBoxPane(checkBoxPane); + variableTreeAndDescriptionArea = new VariableTreeAndDescriptionArea(); + this.add(variableTreeAndDescriptionArea, BorderLayout.SOUTH); + } + + private void initTipsPane() { + // tipsPane + JPanel tipsPane = new JPanel(new BorderLayout(4, 4)); + this.add(tipsPane, BorderLayout.EAST); + + JPanel searchPane = new JPanel(new BorderLayout(4, 4)); + searchPane.add(keyWordTextField, BorderLayout.CENTER); + UIButton searchButton = new UIButton(Inter.getLocText("FR-Designer_FormulaPane_Search")); + searchPane.add(searchButton, BorderLayout.EAST); + tipsPane.add(searchPane, BorderLayout.NORTH); + initKeyWordTextFieldKeyListener(); + tipsList = new JList(listModel); + tipsList.addMouseListener(new DoubleClick()); + UIScrollPane tipsScrollPane = new UIScrollPane(tipsList); + tipsScrollPane.setPreferredSize(new Dimension(170, 75)); + tipsScrollPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + tipsPane.add(tipsScrollPane, BorderLayout.CENTER); + searchButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + String toFind = keyWordTextField.getText(); + search(toFind, false); + formulaPane.onSearch(); + fixFunctionNameList(); + } + }); + } + + + protected void extendCheckBoxPane(JPanel checkBoxPane) { + + } + + @Override + public void clearMathListModel() { + listModel.removeAllElements(); + } + + public class DoubleClick extends MouseAdapter { + + @Override + public void mouseClicked(MouseEvent e) { + int index = tipsList.getSelectedIndex(); + if (index != -1) { + String currentLineContent = (String) listModel.getElementAt(index); + if (e.getClickCount() == 2) { + formulaPane.onDoubleClick(currentLineContent); + listModel.removeAllElements(); + } else if (e.getClickCount() == 1) { + refreshDescriptionTextArea(currentLineContent); + formulaPane.onSingleClick(); + fixFunctionNameList(); + } + } + } + } + + public void fixFunctionNameList() { + if (tipsList.getSelectedValue() != null) { + int signOfContinue = 1; + int indexOfFunction = 0; + for (int i = 0; i < functionTypeListModel.size(); i++) { + int signOfType = 0; + FunctionGroup functionType = (FunctionGroup) functionTypeListModel.getElementAt(i); + NameAndDescription[] nads = functionType.getDescriptions(); + if (signOfContinue == 1) { + functionNameModel.removeAllElements(); + String functionName = ((String) tipsList.getSelectedValue()); + for (int k = 0; k < nads.length; k++) { + functionNameModel.addElement(nads[k]); + if (functionName.equals(nads[k].getName()))//若相等,找出显示的函数的index,setSelectedIndex() + { + signOfType = 1; + signOfContinue = 0; + indexOfFunction = k; + } + } + + if (signOfType == 1) { + functionTypeList.setSelectedIndex(i); + signOfType = 0; + } + } + } + functionNameList.setSelectedIndex(indexOfFunction); + functionNameList.ensureIndexIsVisible(indexOfFunction); + } + + } + + public void search(String keyWord, boolean findDescription) { + listModel.removeAllElements(); + + keyWord = removeAllSpace(keyWord); + if (keyWord.length() != 0) { + NameAndDescription[] descriptions = FunctionConstants.ALL.getDescriptions(); + int lengthOfDes = descriptions.length; + for (int i = 0; i < lengthOfDes; i++) { + NameAndDescription and = descriptions[i]; + + String functionName = and.searchResult(keyWord, findDescription); + if (StringUtils.isNotBlank(functionName)) { + listModel.addElement(functionName); + } + } + + if (!listModel.isEmpty()) { + tipsList.setSelectedIndex(0); + refreshDescriptionTextArea((String) listModel.getElementAt(0)); + } + } + } + + private void refreshDescriptionTextArea(String line) { + NameAndDescription[] descriptions = FunctionConstants.ALL.getDescriptions(); + int length = descriptions.length; + for (int i = 0; i < length; i++) { + NameAndDescription function = descriptions[i]; + String functionName = function.getName(); + if (functionName.equals(line)) { + variableTreeAndDescriptionArea.descriptionTextArea.setText(function.getDesc()); + variableTreeAndDescriptionArea.descriptionTextArea.moveCaretPosition(0); + break; + } + } + } + + private String removeAllSpace(String toFind) { + + int index = toFind.indexOf(" "); + while (index != -1) { + toFind = toFind.substring(0, index) + toFind.substring(index + 1); + index = toFind.indexOf(" "); + } + return toFind; + } + + @Override + protected String title4PopupWindow() { + return Inter.getLocText("FormulaD-Formula_Definition"); + } + + /** + * Populate + */ + public void populate(BaseFormula formula) { + this.populate(formula, VariableResolver.DEFAULT); + } + + public void populate(BaseFormula formula, VariableResolver variableResolver) { + this.variableTreeAndDescriptionArea.populate(variableResolver); + } + + /** + * update + */ + public BaseFormula update() { + return formulaPane.updateBean(); + } + + protected ActionListener checkValidActionListener = new ActionListener() { + + public void actionPerformed(ActionEvent evt) { + formulaPane.checkContentValid(); + } + }; + + public class VariableTreeAndDescriptionArea extends JPanel { + + private JTree variablesTree; + private UITextArea descriptionTextArea; + + public VariableTreeAndDescriptionArea() { + this.initComponents(); + } + + private void initFunctionTypeList(JPanel functionPane) { + functionTypeList = new QuickList(functionTypeListModel); + UIScrollPane functionTypeScrollPane = new UIScrollPane(functionTypeList); + functionTypeScrollPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + functionTypeScrollPane.setPreferredSize(new Dimension(140, 200)); + functionPane.add(this.createNamePane(Inter.getLocText("FormulaD-Function_category") + ":", functionTypeScrollPane), BorderLayout.WEST); + initTypeListCellRenderer(); + initGroupTypeModel(); + initTypeListSelectionListener(); + } + + private void initTypeListCellRenderer() { + functionTypeList.setCellRenderer( + new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof FunctionGroup) { + this.setText(((FunctionGroup) value).getGroupName()); + } + return this; + } + }); + } + + private void initTypeListSelectionListener() { + functionTypeList.addListSelectionListener(new ListSelectionListener() { + public void valueChanged(ListSelectionEvent evt) { + Object selectedValue = ((JList) evt.getSource()).getSelectedValue(); + if (!(selectedValue instanceof FunctionGroup)) { + return; + } + NameAndDescription[] nads = ((FunctionGroup) selectedValue).getDescriptions(); + functionNameModel = (DefaultListModel) functionNameList.getModel(); + functionNameModel.clear(); + for (NameAndDescription nad : nads) { + functionNameModel.addElement(nad); + } + if (functionNameModel.size() > 0) { + functionNameList.setSelectedIndex(0); + functionNameList.ensureIndexIsVisible(0); + } + } + }); + } + + private void initGroupTypeModel() { + functionTypeListModel.addElement(FunctionConstants.COMMON); + for (int i = 0; i < FunctionConstants.EMBFUNCTIONS.length; i++) { + functionTypeListModel.addElement(FunctionConstants.EMBFUNCTIONS[i]); + } + functionTypeListModel.addElement(FunctionConstants.ALL); + functionTypeListModel.addElement(FunctionConstants.CUSTOM); + functionTypeListModel.addElement(FunctionConstants.PLUGIN); + + //hugh: 从函数分组插件中添加分组 + FunctionConstants.addFunctionGroupFromPlugins(functionTypeListModel); + } + + private void initFunctionNameListCellRenderer() { + functionNameList.setCellRenderer(new DefaultListCellRenderer() { + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof NameAndDescription) { + this.setText(((NameAndDescription) value).getName()); + } + return this; + } + }); + } + + private void initFunctionNameListSelectionListener() { + functionNameList.addListSelectionListener(new ListSelectionListener() { + + public void valueChanged(ListSelectionEvent evt) { + Object selectedValue = functionNameList.getSelectedValue(); + if (!(selectedValue instanceof NameAndDescription)) { + return; + } + + String description = ((NameAndDescription) selectedValue).getDesc(); + descriptionTextArea.setText(description); + setTextAreaText(description); + descriptionTextArea.moveCaretPosition(0); + } + }); + } + + private void initFunctionNameListMouseListener() { + functionNameList.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent evt) { + if (evt.getClickCount() >= 2) { + Object selectedValue = functionNameList.getSelectedValue(); + if (!(selectedValue instanceof NameAndDescription)) { + return; + } + String insert = ((NameAndDescription) selectedValue).getName() + "()"; + formulaPane.applyText(insert); + + } + if (SwingUtilities.isRightMouseButton(evt)) { + JPopupMenu popupMenu = new JPopupMenu(); + VariableTreeAndDescriptionArea.LookDetailAction lookDetailAction = new VariableTreeAndDescriptionArea.LookDetailAction(); + popupMenu.add(lookDetailAction); + + // peter: 只有弹出菜单有子菜单的时候,才需要弹出来. + GUICoreUtils.showPopupMenu(popupMenu, functionNameList, evt.getX() - 1, evt.getY() - 1); + } + } + }); + } + + private void initFunctionNameList(JPanel functionPane) { + functionNameList = new JList(new DefaultListModel()); + UIScrollPane functionNameScrollPane = new UIScrollPane(functionNameList); + functionNameScrollPane.setPreferredSize(new Dimension(140, 200)); + functionPane.add( + this.createNamePane(Inter.getLocText("FormulaD-Function_name") + ":", functionNameScrollPane), + BorderLayout.CENTER); + functionNameScrollPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + initFunctionNameListCellRenderer(); + initFunctionNameListSelectionListener(); + initFunctionNameListMouseListener(); + } + + private void initDescriptionTextArea() { + // Description + descriptionTextArea = new UITextArea(16, 27); + + UIScrollPane desScrollPane = new UIScrollPane(descriptionTextArea); + desScrollPane.setBorder(null); + this.add(this.createNamePane(Inter.getLocText("FR-Designer_FormulaPane_Formula_Description") + ":", desScrollPane), BorderLayout.EAST); + descriptionTextArea.setBackground(Color.white); + descriptionTextArea.setLineWrap(true); + descriptionTextArea.setWrapStyleWord(true); + descriptionTextArea.setEditable(false); + descriptionTextArea.addMouseListener(new MouseAdapter() { + + public void mouseClicked(MouseEvent evt) { + if (evt.getClickCount() >= 2) { + showPopupPane(); + } + } + }); + + } + + private StringBuilder getText(TextUserObject selectedValue, String path) throws IOException { + Reader desReader; + StringBuilder desBuf = new StringBuilder(); + InputStream desInputStream = BaseUtils.readResource(path + (selectedValue).displayText + ".txt"); + if (desInputStream == null) { + String description = ""; + desReader = new StringReader(description); + } else { + desReader = new InputStreamReader(desInputStream, EncodeConstants.ENCODING_UTF_8); + } + BufferedReader reader = new BufferedReader(desReader); + String lineText; + while ((lineText = reader.readLine()) != null) { + if (desBuf.length() > 0) { + desBuf.append('\n'); + } + desBuf.append(lineText); + } + reader.close(); + desReader.close(); + return desBuf; + } + + private void initVariablesTreeSelectionListener() { + variablesTree.addTreeSelectionListener(new TreeSelectionListener() { + public void valueChanged(TreeSelectionEvent e) { + Object selectedValue = ((DefaultMutableTreeNode) variablesTree.getLastSelectedPathComponent()).getUserObject(); + if (selectedValue == null) { + return; + } + StringBuilder desBuf = new StringBuilder(); + try { + String path; + Locale locale = FRContext.getLocale(); + if (locale.equals(Locale.CHINA)) { + path = "/com/fr/design/insert/formula/variable/cn/"; + } else { + path = "/com/fr/design/insert/formula/variable/en/"; + } + if (selectedValue instanceof TextUserObject) { + desBuf = getText((TextUserObject) selectedValue, path); + } + } catch (IOException exp) { + FRContext.getLogger().error(exp.getMessage(), exp); + } + descriptionTextArea.setText(desBuf.toString()); + descriptionTextArea.moveCaretPosition(0); + } + }); + } + + private void initVariablesTree() { + // vairable. + variablesTree = new JTree(); + UIScrollPane variablesTreePane = new UIScrollPane(variablesTree); + variablesTreePane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); + this.add(this.createNamePane( + Inter.getLocText("FR-Designer_FormulaPane_Variables") + ":", variablesTreePane), BorderLayout.CENTER); + variablesTree.setRootVisible(false); + variablesTree.setShowsRootHandles(true); + variablesTree.addMouseListener(applyTextMouseListener); + variablesTree.setCellRenderer(applyTreeCellRenderer); + + initDescriptionTextArea(); + + initVariablesTreeSelectionListener(); + } + + private void initComponents() { + this.setLayout(new BorderLayout(4, 4)); + // Function + JPanel functionPane = new JPanel(new BorderLayout(4, 4)); + this.add(functionPane, BorderLayout.WEST); + initFunctionTypeList(functionPane); + initFunctionNameList(functionPane); + initVariablesTree(); + // 选择: + functionTypeList.setSelectedIndex(0); + } + + /* + * 查看函数的详细信息 + */ + private class LookDetailAction extends UpdateAction { + + public LookDetailAction() { + this.setName(Inter.getLocText("FR-Designer_FormulaPane_Function_Detail")); + this.setMnemonic('L'); + this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_file/preview.png")); + } + + // 弹出的窗口中显示函数的用法明细 + public void actionPerformed(ActionEvent evt) { + showPopupPane(); + } + } + + private void showPopupPane() { + BasicPane basicPane = new BasicPane() { + @Override + protected String title4PopupWindow() { + return Inter.getLocText("FR-Designer_FormulaPane_Function_Detail"); + } + }; + basicPane.setLayout(FRGUIPaneFactory.createBorderLayout()); + UITextArea desArea = new UITextArea(); +// desArea。setEnabled(false); + desArea.setText(this.getTextAreaText()); + basicPane.add(new UIScrollPane(desArea), BorderLayout.CENTER); + BasicDialog dialog = basicPane.showWindow(DesignerContext.getDesignerFrame()); + dialog.setVisible(true); + } + + private String getTextAreaText() { + return this.descriptionTextArea.getText(); + } + + private void setTextAreaText(String text) { + this.descriptionTextArea.setText(text); + } + + private JPanel createNamePane(String name, JComponent comp) { + JPanel namePane = new JPanel(new BorderLayout(4, 4)); + namePane.add(new UILabel(name), BorderLayout.NORTH); + namePane.add(comp, BorderLayout.CENTER); + return namePane; + } + + private MouseListener applyTextMouseListener = new MouseAdapter() { + + public void mouseClicked(MouseEvent evt) { + if (evt.getClickCount() >= 2) { + Object source = evt.getSource(); + if (source instanceof JTree) { + JTree tree = (JTree) source; + TreePath selectedTreePah = tree.getSelectionPath(); + if (selectedTreePah != null) { + DefaultMutableTreeNode selectedTreeNode = (DefaultMutableTreeNode) selectedTreePah.getLastPathComponent(); + Object userObject = selectedTreeNode.getUserObject(); + if (userObject != null && userObject instanceof TextUserObject) { + formulaPane.applyText(((TextUserObject) userObject).getText()); + } + } + } + } + } + }; + private DefaultTreeCellRenderer applyTreeCellRenderer = new DefaultTreeCellRenderer() { + + public Component getTreeCellRendererComponent(JTree tree, + Object value, boolean selected, boolean expanded, + boolean leaf, int row, boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, selected, + expanded, leaf, row, hasFocus); + + DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value; + Object userObj = treeNode.getUserObject(); + + if (userObj instanceof TextUserObject) { + this.setIcon(null); + this.setText(((TextUserObject) userObj).getDisplayText()); + } else if (userObj instanceof TextFolderUserObject) { + TextFolderUserObject textUserObject = (TextFolderUserObject) userObj; + if (leaf) { + this.setText(textUserObject.getText()); + } else { + this.setText(textUserObject.getText() + " - [" + + treeNode.getChildCount() + "]"); + } + + this.setIcon(textUserObject.getIcon()); + } + + return this; + } + }; + + public void populate(VariableResolver variableResolver) { + // varibale tree. + DefaultTreeModel variableModel = (DefaultTreeModel) variablesTree.getModel(); + + DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode) variableModel.getRoot(); + rootNode.removeAllChildren(); + + if (variableResolver.isBindCell()) { + // 加上当前值"$$$" + DefaultMutableTreeNode bindCellNode = new DefaultMutableTreeNode(new TextUserObject("$$$")); + rootNode.add(bindCellNode); + } + + rootNode.add(new TextFolderUserObject(Inter.getLocText("FormulaD-Data_Fields"), + BaseUtils.readIcon("/com/fr/design/images/dialog/table.png"), + variableResolver.resolveColumnNames()).createMutableTreeNode()); + + // Set cutReport Variable + rootNode.add(new TextFolderUserObject(Inter.getLocText("FR-Designer_FormulaPane_Variables"), + BaseUtils.readIcon("/com/fr/design/images/dialog/variable.png"), + variableResolver.resolveCurReportVariables()).createMutableTreeNode()); + + rootNode.add(new TextFolderUserObject(Inter.getLocText(new String[]{"Datasource-Datasource", "Parameter"}), + BaseUtils.readIcon("/com/fr/design/images/dialog/parameter.gif"), + variableResolver.resolveTableDataParameterVariables()).createMutableTreeNode()); + + rootNode.add(new TextFolderUserObject(Inter.getLocText("ParameterD-Report_Parameter"), + BaseUtils.readIcon("/com/fr/design/images/m_report/p.gif"), + variableResolver.resolveReportParameterVariables()).createMutableTreeNode()); + + rootNode.add(new TextFolderUserObject(Inter.getLocText("M_Server-Global_Parameters"), + BaseUtils.readIcon("/com/fr/design/images/dialog/parameter.gif"), + variableResolver.resolveGlobalParameterVariables()).createMutableTreeNode()); + + variableModel.reload(); + // Expand + for (int row = 0; row < this.variablesTree.getRowCount(); row++) { + this.variablesTree.expandRow(row); + } + } + } + + public static class TextFolderUserObject { + + private String text; + private Icon icon; + private String[] subNodes = new String[0]; + + public TextFolderUserObject(String text, Icon icon, String[] subNodes) { + this.text = text; + this.icon = icon; + this.subNodes = subNodes; + } + + public String getText() { + return this.text; + } + + public Icon getIcon() { + return this.icon; + } + + MutableTreeNode createMutableTreeNode() { + DefaultMutableTreeNode variableTreeNode = new DefaultMutableTreeNode(this); + + for (String subNode : subNodes) { + variableTreeNode.add(new DefaultMutableTreeNode(new TextUserObject(subNode))); + } + + return variableTreeNode; + } + } + + public static class TextUserObject { + + public TextUserObject(String text) { + this(text, text); + } + + public TextUserObject(String text, String displayText) { + this.text = text; + this.displayText = displayText; + } + + public String getText() { + return this.text; + } + + public String getDisplayText() { + return this.displayText; + } + + private String text; + private String displayText; + } +} \ No newline at end of file diff --git a/src/com/fr/solution/plugin/design/formula/ui/evt/OperateListener.java b/src/com/fr/solution/plugin/design/formula/ui/evt/OperateListener.java new file mode 100644 index 0000000..3eff5f4 --- /dev/null +++ b/src/com/fr/solution/plugin/design/formula/ui/evt/OperateListener.java @@ -0,0 +1,10 @@ +package com.fr.solution.plugin.design.formula.ui.evt; + +public interface OperateListener { + + void clearMathListModel(); + + void search(String keyWord, boolean findDescription); + + void fixFunctionNameList(); +} diff --git a/src/com/fr/solution/plugin/design/formula/ui/type/CategoryFormulaPane.java b/src/com/fr/solution/plugin/design/formula/ui/type/CategoryFormulaPane.java new file mode 100644 index 0000000..565c0c7 --- /dev/null +++ b/src/com/fr/solution/plugin/design/formula/ui/type/CategoryFormulaPane.java @@ -0,0 +1,65 @@ +package com.fr.solution.plugin.design.formula.ui.type; + +import com.fr.base.BaseFormula; +import com.fr.design.beans.FurtherBasicBeanPane; +import com.fr.design.gui.frpane.UIRadioPane; +import com.fr.solution.plugin.design.formula.ui.evt.OperateListener; +import com.fr.solution.plugin.design.formula.ui.type.impl.NormalFormulaPane; +import com.fr.solution.plugin.design.formula.ui.type.impl.ScriptFormulaPane; + +import java.util.ArrayList; +import java.util.List; + +public class CategoryFormulaPane extends UIRadioPane{ + + private static final long serialVersionUID = 6102846618673364636L; + private List events; + + @Override + protected List> initPaneList() { + List> list = new ArrayList>(); + + NormalFormulaPane normal = new NormalFormulaPane(); + ScriptFormulaPane script = new ScriptFormulaPane(); + + list.add(normal); + list.add(script); + + if (events == null) { + events = new ArrayList(); + } + events.add(normal); + events.add(script); + + return list; + } + + public void onDoubleClick(String currentLineContent) { + events.get(cardNamesPane.getSelectedIndex()).onDoubleClick(currentLineContent); + } + + public void onSingleClick() { + events.get(cardNamesPane.getSelectedIndex()).onSingleClick(); + } + + public void applyText(String text) { + events.get(cardNamesPane.getSelectedIndex()).applyText(text); + } + + public void checkContentValid() { + events.get(cardNamesPane.getSelectedIndex()).checkContentValid(); + } + + public void onSearch() { + events.get(cardNamesPane.getSelectedIndex()).onSearch(); + } + + public void setOperateListener(OperateListener listener) { + events.get(cardNamesPane.getSelectedIndex()).setOperateListener(listener); + } + + @Override + protected String title4PopupWindow() { + return "Formula"; + } +} diff --git a/src/com/fr/solution/plugin/design/formula/ui/type/CommonEvent.java b/src/com/fr/solution/plugin/design/formula/ui/type/CommonEvent.java new file mode 100644 index 0000000..b6bb370 --- /dev/null +++ b/src/com/fr/solution/plugin/design/formula/ui/type/CommonEvent.java @@ -0,0 +1,18 @@ +package com.fr.solution.plugin.design.formula.ui.type; + +import com.fr.solution.plugin.design.formula.ui.evt.OperateListener; + +public interface CommonEvent { + + void onDoubleClick(String currentLineContent); + + void onSingleClick(); + + void applyText(String text); + + void checkContentValid(); + + void onSearch(); + + void setOperateListener(OperateListener listener); +} diff --git a/src/com/fr/solution/plugin/design/formula/ui/type/impl/NormalFormulaPane.java b/src/com/fr/solution/plugin/design/formula/ui/type/impl/NormalFormulaPane.java new file mode 100644 index 0000000..b396dda --- /dev/null +++ b/src/com/fr/solution/plugin/design/formula/ui/type/impl/NormalFormulaPane.java @@ -0,0 +1,358 @@ +package com.fr.solution.plugin.design.formula.ui.type.impl; + +import com.fr.base.Formula; +import com.fr.design.beans.FurtherBasicBeanPane; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.syntax.ui.rsyntaxtextarea.RSyntaxTextArea; +import com.fr.design.gui.syntax.ui.rsyntaxtextarea.SyntaxConstants; +import com.fr.general.FRLogger; +import com.fr.general.Inter; +import com.fr.parser.FRLexer; +import com.fr.parser.FRParser; +import com.fr.solution.plugin.design.formula.ui.evt.OperateListener; +import com.fr.solution.plugin.design.formula.ui.type.CommonEvent; +import com.fr.stable.ProductConstants; +import com.fr.stable.StringUtils; +import com.fr.stable.script.Expression; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.StringReader; + +public class NormalFormulaPane extends FurtherBasicBeanPane implements CommonEvent, KeyListener { + + private static final int KEY_10 = 10; + //上下左右 + private static final int KEY_37 = 37; + private static final int KEY_38 = 38; + private static final int KEY_39 = 39; + private static final int KEY_40 = 40; + + + private RSyntaxTextArea formulaTextArea; + private int currentPosition = 0; + private int beginPosition = 0; + private int insertPosition = 0; + private int ifHasBeenWritten = 0; + + private OperateListener operateListener; + + public NormalFormulaPane() { + setLayout(new BorderLayout()); + initFormulaTextArea(); + UIScrollPane formulaTextAreaScrollPane = new UIScrollPane(formulaTextArea); + formulaTextAreaScrollPane.setBorder(null); + add(formulaTextAreaScrollPane, BorderLayout.CENTER); + } + + private void initFormulaTextArea() { + formulaTextArea = new RSyntaxTextArea(); + configFormulaArea(); + initFormulaTextAreaKeyListener(); + initFormulaTextAreaMouseListener(); + } + + protected void configFormulaArea() { + formulaTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_FORMULA); + formulaTextArea.setAnimateBracketMatching(true); + formulaTextArea.setAntiAliasingEnabled(true); + formulaTextArea.setAutoIndentEnabled(true); + formulaTextArea.setCodeFoldingEnabled(true); + formulaTextArea.setUseSelectedTextColor(true); + formulaTextArea.setCloseCurlyBraces(true); + formulaTextArea.setBracketMatchingEnabled(true); + formulaTextArea.setAntiAliasingEnabled(true); + formulaTextArea.setCloseMarkupTags(true); + formulaTextArea.setLineWrap(true); + } + + private void initFormulaTextAreaKeyListener() { + formulaTextArea.addKeyListener(this); + formulaTextArea.addKeyListener(new KeyAdapter() { + public void keyReleased(KeyEvent e) { + formulaTextArea.setForeground(Color.black); + String text = formulaTextArea.getText(); + // 判断在中文输入状态是否还包含提示符 要删掉 + String tip = "\n\n\n" + Inter.getLocText("FR-Designer_FormulaPane_Tips"); + if (text.contains(tip)) { + text = text.substring(0, text.indexOf(tip)); + insertPosition = 0; + formulaTextArea.setText(text); + } + } + }); + } + + private void initFormulaTextAreaMouseListener() { + formulaTextArea.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + insertPosition = formulaTextArea.getCaretPosition(); + if (ifHasBeenWritten == 0) { + formulaTextArea.setText(""); + ifHasBeenWritten = 1; + formulaTextArea.setForeground(Color.black); + insertPosition = 0; + } + } + + @Override + public void mouseReleased(MouseEvent e) { + currentPosition = formulaTextArea.getCaretPosition(); + if (currentPosition == insertPosition) { + beginPosition = getBeginPosition(); + insertPosition = beginPosition; + firstStepToFindTips(beginPosition); + operateListener.fixFunctionNameList(); + } + } + }); + } + + protected int getBeginPosition() { + int i = currentPosition; + String textArea = formulaTextArea.getText(); + for (; i > 0; i--) { + String tested = textArea.substring(i - 1, i).toUpperCase(); + char[] testedChar = tested.toCharArray(); + if (isChar(testedChar[0]) || isNum(testedChar[0])) { + continue; + } else { + break; + } + } + return i; + } + + private static boolean isNum(char tested) { + return tested >= '0' && tested <= '9'; + } + + private boolean isChar(char tested) { + return tested >= 'A' && tested <= 'Z'; + } + + protected void firstStepToFindTips(int theBeginPosition) { + String textArea = formulaTextArea.getText(); + if (currentPosition > 0 && theBeginPosition < currentPosition) { + String next = textArea.substring(theBeginPosition, theBeginPosition + 1); + char[] nextChar = next.toCharArray(); + if (!isNum(nextChar[0])) { + String toFind = textArea.substring(theBeginPosition, currentPosition); + operateListener.search(toFind, false); + formulaTextArea.requestFocusInWindow(); + } else { + operateListener.clearMathListModel(); + } + } else { + String toFind = textArea.substring(theBeginPosition, currentPosition); + operateListener.search(toFind, false); + formulaTextArea.requestFocusInWindow(); + } + } + + @Override + public boolean accept(Object ob) { + return ob instanceof Formula; + } + + @Override + public void reset() { + + } + + @Override + public void populateBean(Formula formula) { + // set text + if (formula != null) { + String content = formula.getContent(); + if (content.trim().equals("=")) { + this.formulaTextArea.setForeground(Color.gray); + this.formulaTextArea.setText("\n\n\n" + Inter.getLocText("FR-Designer_FormulaPane_Tips")); + this.formulaTextArea.setCaretPosition(0); + ifHasBeenWritten = 0; + operateListener.clearMathListModel(); + } else if (content.trim().charAt(0) == '=') { + this.formulaTextArea.setText(content.trim().substring(1)); + currentPosition = formulaTextArea.getCaretPosition(); + beginPosition = getBeginPosition(); + insertPosition = beginPosition; + firstStepToFindTips(beginPosition); + operateListener.fixFunctionNameList(); + ifHasBeenWritten = 1; + } else { + this.formulaTextArea.setText(content); + currentPosition = formulaTextArea.getCaretPosition(); + beginPosition = getBeginPosition(); + insertPosition = beginPosition; + firstStepToFindTips(beginPosition); + operateListener.fixFunctionNameList(); + ifHasBeenWritten = 1; + } + } + + } + + @Override + public Formula updateBean() { + Formula formula; + if (ifHasBeenWritten == 0) { + return new Formula(); + } else { + String content = this.formulaTextArea.getText(); + + if (StringUtils.isEmpty(content) || content.trim().charAt(0) == '=') { + formula = new Formula(content); + } else { + formula = new Formula("=" + content); + } + return formula; + } + } + + @Override + public void keyTyped(KeyEvent e) { + + } + + + @Override + public void keyPressed(KeyEvent e) { + if (ifHasBeenWritten == 0) { + this.formulaTextArea.setText(StringUtils.EMPTY); + } + } + + + @Override + public void keyReleased(KeyEvent e) { + int key = e.getKeyCode(); + // 如果是删除符号 ,为了可读性 没有和其他按键的程序相融合 + if (key == KEY_38 || key == KEY_40 || key == KEY_37 || key == KEY_39 || key == KEY_10) { + operateListener.clearMathListModel(); + currentPosition = formulaTextArea.getCaretPosition(); + insertPosition = currentPosition; + beginPosition = getBeginPosition(); + } else { + if (this.formulaTextArea.getText().trim().length() == 0) { + insertPosition = 0; + operateListener.clearMathListModel(); + } else { + this.formulaTextArea.setForeground(Color.black); + currentPosition = formulaTextArea.getCaretPosition(); + beginPosition = getBeginPosition(); + insertPosition = beginPosition; + firstStepToFindTips(beginPosition); + operateListener.fixFunctionNameList(); + ifHasBeenWritten = 1; + } + } + } + + /** + * Apply text. + */ + public void applyText(String text) { + if (text == null || text.length() <= 0) { + return; + } + if (ifHasBeenWritten == 0) { + formulaTextArea.setForeground(Color.black); + formulaTextArea.setText(""); + ifHasBeenWritten = 1; + insertPosition = 0; + } + String textAll = formulaTextArea.getText(); + currentPosition = formulaTextArea.getCaretPosition(); + int insert = 0; + int current = 0; + if (insertPosition <= currentPosition) { + insert = insertPosition; + current = currentPosition; + } else { + insert = currentPosition; + current = insertPosition; + } + String beforeIndexOfInsertString = textAll.substring(0, insert); + String afterIndexofInsertString = textAll.substring(current); + formulaTextArea.setText(beforeIndexOfInsertString + text + afterIndexofInsertString); + formulaTextArea.getText(); + if (text.indexOf("()") != -1) { + formulaTextArea.setCaretPosition(insert + text.length() - 1); + } + formulaTextArea.requestFocus(); + insertPosition = formulaTextArea.getCaretPosition(); + } + + public void onDoubleClick(String currentLineContent) { + if (ifHasBeenWritten == 0) { + formulaTextArea.setForeground(Color.black); + formulaTextArea.setText(""); + } + formulaTextArea.setForeground(Color.black); + currentPosition = formulaTextArea.getCaretPosition(); + String output = currentLineContent + "()"; + String textAll = formulaTextArea.getText(); + String textReplaced; + int position = 0; + if (insertPosition <= currentPosition) { + textReplaced = textAll.substring(0, insertPosition) + output + textAll.substring(currentPosition); + position = insertPosition + output.length() - 1; + } else { + textReplaced = textAll.substring(0, currentPosition) + output + textAll.substring(insertPosition); + position = currentPosition + output.length() - 1; + } + formulaTextArea.setText(textReplaced); + formulaTextArea.requestFocusInWindow(); + formulaTextArea.setCaretPosition(position); + insertPosition = position; + ifHasBeenWritten = 1; + } + + public void onSingleClick() { + formulaTextArea.requestFocusInWindow(); + } + + public void checkContentValid() { + // Execute Formula default cell element. + String formulaText = formulaTextArea.getText().trim(); + + if (formulaText != null && formulaText.length() > 0) { + StringReader in = new StringReader(formulaText); + + FRLexer lexer = new FRLexer(in); + FRParser parser = new FRParser(lexer); + + Expression expression = null; + try { + expression = parser.parse(); + } catch (Exception e) { + FRLogger.getLogger().error(e.getMessage(), e); + } + + JOptionPane.showMessageDialog( + NormalFormulaPane.this, + (expression != null ? Inter.getLocText("FormulaD-Valid_Formula") : Inter.getLocText("FormulaD-Invalid_Formula")) + ".", ProductConstants.PRODUCT_NAME, + JOptionPane.INFORMATION_MESSAGE); + } + } + + public void onSearch() { + formulaTextArea.requestFocusInWindow(); + } + + @Override + public void setOperateListener(OperateListener operateListener) { + this.operateListener = operateListener; + } + + @Override + public String title4PopupWindow() { + return Inter.getLocText("Plugin-Basic_Formula_Title"); + } +} diff --git a/src/com/fr/solution/plugin/design/formula/ui/type/impl/ScriptFormulaPane.java b/src/com/fr/solution/plugin/design/formula/ui/type/impl/ScriptFormulaPane.java new file mode 100644 index 0000000..21a6161 --- /dev/null +++ b/src/com/fr/solution/plugin/design/formula/ui/type/impl/ScriptFormulaPane.java @@ -0,0 +1,96 @@ +package com.fr.solution.plugin.design.formula.ui.type.impl; + +import com.fr.base.Formula; +import com.fr.base.ScriptFormula; +import com.fr.design.beans.FurtherBasicBeanPane; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.syntax.ui.rsyntaxtextarea.RSyntaxTextArea; +import com.fr.design.gui.syntax.ui.rsyntaxtextarea.SyntaxConstants; +import com.fr.general.Inter; +import com.fr.solution.plugin.design.formula.ui.evt.OperateListener; +import com.fr.solution.plugin.design.formula.ui.type.CommonEvent; +import com.fr.stable.StringUtils; + +import java.awt.*; + +public class ScriptFormulaPane extends FurtherBasicBeanPane implements CommonEvent { + + private RSyntaxTextArea formulaTextArea; + + public ScriptFormulaPane() { + setLayout(new BorderLayout()); + formulaTextArea = new RSyntaxTextArea(); + formulaTextArea.setCloseCurlyBraces(true); + formulaTextArea.setLineWrap(true); + formulaTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); + formulaTextArea.setCodeFoldingEnabled(true); + formulaTextArea.setAntiAliasingEnabled(true); + UIScrollPane formulaTextAreaScrollPane = new UIScrollPane(formulaTextArea); + formulaTextAreaScrollPane.setBorder(null); + add(formulaTextAreaScrollPane, BorderLayout.CENTER); + } + + @Override + public boolean accept(Object ob) { + return ob instanceof ScriptFormula; + } + + @Override + public void reset() { + + } + + @Override + public void populateBean(ScriptFormula formula) { + if (formula != null) { + formulaTextArea.setText(formula.getContent()); + } + } + + @Override + public ScriptFormula updateBean() { + ScriptFormula formula; + String content = formulaTextArea.getText(); + if (StringUtils.isEmpty(content) || content.trim().charAt(0) == '=') { + formula = new ScriptFormula(content); + } else { + formula = new ScriptFormula("=" + content); + } + return formula; + } + + @Override + public void onDoubleClick(String currentLineContent) { + + } + + @Override + public void onSingleClick() { + + } + + @Override + public void applyText(String text) { + + } + + @Override + public void checkContentValid() { + + } + + @Override + public void onSearch() { + + } + + @Override + public void setOperateListener(OperateListener listener) { + + } + + @Override + public String title4PopupWindow() { + return Inter.getLocText("Plugin-Script_Formula_Title"); + } +}