You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1556 lines
64 KiB
1556 lines
64 KiB
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.base.Utils; |
|
import com.fr.base.io.IOFile; |
|
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.DialogActionListener; |
|
import com.fr.design.dialog.FineJOptionPane; |
|
import com.fr.design.file.HistoryTemplateListCache; |
|
import com.fr.design.gui.autocomplete.AutoCompleteExtraRefreshComponent; |
|
import com.fr.design.gui.autocomplete.CompletionCellRenderer; |
|
import com.fr.design.gui.autocomplete.CompletionProvider; |
|
import com.fr.design.gui.autocomplete.DefaultCompletionProvider; |
|
import com.fr.design.gui.autocomplete.FormulaCompletion; |
|
import com.fr.design.gui.autocomplete.FormulaPaneAutoCompletion; |
|
import com.fr.design.gui.ibutton.UIButton; |
|
import com.fr.design.gui.icheckbox.UICheckBox; |
|
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.DesignSizeI18nManager; |
|
import com.fr.design.i18n.Toolkit; |
|
import com.fr.design.layout.FRGUIPaneFactory; |
|
import com.fr.design.mainframe.DesignerContext; |
|
import com.fr.design.mainframe.JTemplate; |
|
import com.fr.design.parameter.ParameterInputNoneListenerPane; |
|
import com.fr.design.parameter.ParameterInputPane; |
|
import com.fr.design.utils.gui.GUICoreUtils; |
|
import com.fr.general.ComparatorUtils; |
|
import com.fr.general.FArray; |
|
import com.fr.log.FineLoggerFactory; |
|
import com.fr.parser.ArrayExpression; |
|
import com.fr.parser.BlockIntervalLiteral; |
|
import com.fr.parser.ColumnRowRangeInPage; |
|
import com.fr.parser.NumberLiteral; |
|
import com.fr.parser.SheetIntervalLiteral; |
|
import com.fr.record.analyzer.EnableMetrics; |
|
import com.fr.report.core.namespace.SimpleCellValueNameSpace; |
|
import com.fr.script.Calculator; |
|
import com.fr.script.ScriptConstants; |
|
import com.fr.script.checker.result.FormulaCheckResult; |
|
import com.fr.stable.EncodeConstants; |
|
import com.fr.stable.EssentialUtils; |
|
import com.fr.stable.ParameterProvider; |
|
import com.fr.stable.StringUtils; |
|
import com.fr.parser.CRAddress; |
|
import com.fr.stable.script.ColumnRowRange; |
|
import com.fr.stable.script.Expression; |
|
import com.fr.stable.script.Node; |
|
import com.fr.stable.script.Tiny; |
|
import com.fr.stable.script.TinyHunter; |
|
|
|
import java.awt.Window; |
|
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.JScrollPane; |
|
import javax.swing.JTree; |
|
import javax.swing.SwingUtilities; |
|
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.BorderLayout; |
|
import java.awt.Color; |
|
import java.awt.Component; |
|
import java.awt.Dimension; |
|
import java.awt.FlowLayout; |
|
import java.awt.event.ActionEvent; |
|
import java.awt.event.ActionListener; |
|
import java.awt.event.FocusEvent; |
|
import java.awt.event.FocusListener; |
|
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.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.text.NumberFormat; |
|
import java.util.ArrayList; |
|
import java.util.Arrays; |
|
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; |
|
|
|
/** |
|
* 公式编辑面板 |
|
* |
|
* @editor zhou |
|
* @since 2012-3-29下午1:50:53 |
|
*/ |
|
@EnableMetrics |
|
public class FormulaPane extends BasicPane implements KeyListener, UIFormula { |
|
public static final int DEFUAL_FOMULA_LENGTH = 103; |
|
public static final String ELLIPSIS = "..."; |
|
public static final char KEY_CODE_A = 'A'; |
|
public static final char KEY_CODE_Z = 'z'; |
|
public static final String NEWLINE = "\n"; |
|
public static final String FORMULA_ICON = "/com/fr/design/images/m_file/formula.png"; |
|
public static final String PARAM_ICON = "/com/fr/design/images/m_file/param.png"; |
|
private VariableTreeAndDescriptionArea variableTreeAndDescriptionArea; |
|
private RSyntaxTextArea formulaTextArea; |
|
private UITextField keyWordTextField = new UITextField(18); |
|
private int currentPosition = 0; |
|
private int beginPosition = 0; |
|
private int insertPosition = 0; |
|
protected static UICheckBox autoCompletionCheck; |
|
protected static UICheckBox checkBeforeColse; |
|
private JList tipsList; |
|
private JPopupMenu popupMenu; |
|
protected DefaultListModel listModel = new DefaultListModel(); |
|
private int ifHasBeenWriten = 0; |
|
private DefaultListModel functionTypeListModel = new DefaultListModel(); |
|
private QuickList functionTypeList; |
|
private DefaultListModel functionNameModel; |
|
private JList functionNameList; |
|
private UITableEditorPane<ParameterProvider> editor4CalPane; |
|
private FormulaPaneAutoCompletion autoCompletion; |
|
private DefaultCompletionProvider completionProvider; |
|
private static final Map<String, String> PARAM_PREFIX_MAP = new HashMap<>(); |
|
|
|
public static final int DESCRIPTION_TEXT_AREA_ROW = 16, DESCRIPTION_TEXT_AREA_COLUMN = 27; |
|
|
|
public FormulaPane() { |
|
initComponents(); |
|
} |
|
|
|
private void initFormulaTextAreaKeyListener() { |
|
formulaTextArea.addKeyListener(this); |
|
formulaTextArea.addKeyListener(new KeyAdapter() { |
|
//用来判断一下是不是组合键 |
|
|
|
@Override |
|
public void keyTyped(KeyEvent e) { |
|
if (inKeyCodeRange(e) && autoCompletionCheck.isSelected()) { |
|
autoCompletion.doCompletion(); |
|
} |
|
} |
|
|
|
private boolean inKeyCodeRange(KeyEvent e) { |
|
return (e.getKeyChar() >= KEY_CODE_A && e.getKeyChar() <= KEY_CODE_Z); |
|
} |
|
|
|
@Override |
|
public void keyReleased(KeyEvent e) { |
|
formulaTextArea.setForeground(Color.black); |
|
String text = formulaTextArea.getText(); |
|
// 判断在中文输入状态是否还包含提示符 要删掉 |
|
//Tips:You_Can_Input_B1_To_Input_The_Data_Of_The_First_Row_Second_Column |
|
String tip = "\n\n\n" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_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 (ifHasBeenWriten == 0) { |
|
formulaTextArea.setText(""); |
|
ifHasBeenWriten = 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); |
|
if (tipsList.getSelectedValue() != null) { |
|
fixFunctionNameList(tipsList.getSelectedValue().toString()); |
|
} |
|
} |
|
} |
|
}); |
|
} |
|
|
|
private void initFormulaTextArea() { |
|
formulaTextArea = new RSyntaxTextArea(); |
|
configFormulaArea(); |
|
initFormulaTextAreaKeyListener(); |
|
initFormulaTextAreaMouseListener(); |
|
} |
|
|
|
private void initKeyWordTextFieldKeyListener() { |
|
keyWordTextField.addKeyListener(new KeyListener() { |
|
@Override |
|
public void keyTyped(KeyEvent e) { |
|
//do nothing |
|
} |
|
|
|
@Override |
|
public void keyReleased(KeyEvent e) { |
|
//do nothing |
|
} |
|
|
|
@Override |
|
public void keyPressed(KeyEvent e) { |
|
if (e.getKeyCode() == KeyEvent.VK_ENTER) { |
|
String toFind = keyWordTextField.getText(); |
|
search(toFind, false); |
|
if (tipsList.getSelectedValue() != null) { |
|
fixFunctionNameList(tipsList.getSelectedValue().toString()); |
|
} |
|
e.consume(); |
|
} |
|
} |
|
}); |
|
} |
|
|
|
private void initTipsPane() { |
|
// tipsPane |
|
JPanel containerSPane = new JPanel(new BorderLayout(4, 1)); |
|
JPanel labelPane = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0), true); |
|
JPanel searchPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0), true); |
|
containerSPane.setPreferredSize(new Dimension(892, 23)); |
|
this.add(containerSPane, BorderLayout.NORTH); |
|
|
|
UIButton searchButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Search")); |
|
UILabel formulaLabel = new UILabel( |
|
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Input_Formula_In_The_Text_Area_Below") + ":"); |
|
formulaLabel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); |
|
|
|
labelPane.add(formulaLabel, BorderLayout.WEST); |
|
keyWordTextField.setPreferredSize(new Dimension(240, 23)); |
|
searchPane.add(keyWordTextField, BorderLayout.EAST); |
|
searchPane.add(searchButton, BorderLayout.EAST); |
|
|
|
containerSPane.add(labelPane, BorderLayout.WEST); |
|
containerSPane.add(searchPane, BorderLayout.EAST); |
|
|
|
initKeyWordTextFieldKeyListener(); |
|
tipsList = new JList(listModel); |
|
tipsList.addMouseListener(new DoubleClick()); |
|
searchButton.addActionListener(e -> { |
|
String toFind = keyWordTextField.getText(); |
|
search(toFind, false); |
|
popTips(); |
|
formulaTextArea.requestFocusInWindow(); |
|
if (tipsList.getSelectedValue() != null) { |
|
fixFunctionNameList(tipsList.getSelectedValue().toString()); |
|
} |
|
}); |
|
} |
|
|
|
protected void initComponents() { |
|
this.setLayout(new BorderLayout(4, 4)); |
|
|
|
initTextPane(); |
|
initTipsPane(); |
|
initVariableTreeAndDescriptionArea(); |
|
refocusInWindow(); |
|
} |
|
|
|
public void refocusInWindow() { |
|
SwingUtilities.invokeLater(() -> formulaTextArea.requestFocusInWindow()); |
|
} |
|
|
|
private void initVariableTreeAndDescriptionArea() { |
|
variableTreeAndDescriptionArea = new VariableTreeAndDescriptionArea(); |
|
this.add(variableTreeAndDescriptionArea, BorderLayout.SOUTH); |
|
} |
|
|
|
private void initTextPane() { |
|
// text |
|
JPanel textPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
|
this.add(textPane, BorderLayout.CENTER); |
|
JPanel checkBoxandbuttonPane = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane(); |
|
initFormulaTextArea(); |
|
|
|
UIScrollPane formulaTextAreaScrollPane = new UIScrollPane(formulaTextArea); |
|
formulaTextAreaScrollPane.setBorder(null); |
|
textPane.add(formulaTextAreaScrollPane, BorderLayout.CENTER); |
|
textPane.add(checkBoxandbuttonPane, BorderLayout.SOUTH); |
|
|
|
|
|
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(); |
|
checkBoxandbuttonPane.add(checkBoxPane, BorderLayout.WEST); |
|
//靠右流式布局 |
|
JPanel buttonPane = FRGUIPaneFactory.createRightFlowInnerContainer_S_Pane(); |
|
buttonPane.add(checkValidButton, BorderLayout.EAST); |
|
buttonPane.add(calButton, BorderLayout.EAST); |
|
checkBoxandbuttonPane.add(buttonPane, BorderLayout.EAST); |
|
if (autoCompletionCheck == null) { |
|
autoCompletionCheck = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Formula_AutoCompletion")); |
|
autoCompletionCheck.setSelected(true); |
|
} |
|
if (checkBeforeColse == null) { |
|
checkBeforeColse = new UICheckBox(Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Before_Closed")); |
|
checkBeforeColse.setSelected(true); |
|
} |
|
checkBoxPane.add(autoCompletionCheck, BorderLayout.WEST); |
|
checkBoxPane.add(checkBeforeColse, BorderLayout.WEST); |
|
extendCheckBoxPane(checkBoxPane); |
|
|
|
ParameterTableModel model = new ParameterTableModel(0); |
|
editor4CalPane = new UITableEditorPane<>(model); |
|
formulaTextArea.addFocusListener(new FocusListener() { |
|
@Override |
|
public void focusGained(FocusEvent e) { |
|
// 获得焦点时 安装 |
|
if (autoCompletion == null && autoCompletionCheck.isSelected()) { |
|
installAutoCompletion(); |
|
} |
|
} |
|
|
|
@Override |
|
public void focusLost(FocusEvent e) { |
|
// 失去焦点时 卸载 |
|
uninstallAutoCompletion(); |
|
} |
|
}); |
|
} |
|
|
|
private CompletionProvider createCompletionProvider() { |
|
if (completionProvider == null) { |
|
completionProvider = new DefaultCompletionProvider(); |
|
NameAndDescription[] nameAndDescriptions = FunctionConstants.ALL.getDescriptions(); |
|
for (NameAndDescription nameAndDescription : nameAndDescriptions) { |
|
completionProvider.addCompletion(new FormulaCompletion(completionProvider, nameAndDescription.getName(), BaseUtils.readIcon(FORMULA_ICON))); |
|
} |
|
|
|
VariableResolver variableResolver = VariableResolver.DEFAULT; |
|
List<String> allParameters = new ArrayList<>(); |
|
allParameters.addAll(Arrays.asList(variableResolver.resolveCurReportVariables())); |
|
allParameters.addAll(Arrays.asList(variableResolver.resolveColumnNames())); |
|
allParameters.addAll(Arrays.asList(variableResolver.resolveGlobalParameterVariables())); |
|
allParameters.addAll(Arrays.asList(variableResolver.resolveReportParameterVariables())); |
|
allParameters.addAll(Arrays.asList(variableResolver.resolveTableDataParameterVariables())); |
|
|
|
//先把参数前缀拿出来 |
|
for (String parameter : allParameters) { |
|
String paramWithoutPre; |
|
if (parameter.startsWith("$$")) { |
|
paramWithoutPre = parameter.substring(2); |
|
PARAM_PREFIX_MAP.put(paramWithoutPre, "$$"); |
|
} else if (parameter.startsWith("$")) { |
|
paramWithoutPre = parameter.substring(1); |
|
PARAM_PREFIX_MAP.put(paramWithoutPre, "$"); |
|
} else { |
|
paramWithoutPre = parameter; |
|
PARAM_PREFIX_MAP.put(paramWithoutPre, StringUtils.EMPTY); |
|
} |
|
completionProvider.addCompletion(new FormulaCompletion(completionProvider, paramWithoutPre, BaseUtils.readIcon(PARAM_ICON))); |
|
} |
|
|
|
return completionProvider; |
|
} |
|
return completionProvider; |
|
} |
|
|
|
public static boolean containsParam(String param) { |
|
return PARAM_PREFIX_MAP.containsKey(param); |
|
} |
|
|
|
public static String getParamPrefix(String param) { |
|
return PARAM_PREFIX_MAP.getOrDefault(param, StringUtils.EMPTY); |
|
} |
|
|
|
private void uninstallAutoCompletion() { |
|
if (autoCompletion != null) { |
|
autoCompletion.uninstall(); |
|
autoCompletion = null; |
|
} |
|
} |
|
|
|
private void installAutoCompletion() { |
|
CompletionProvider provider = createCompletionProvider(); |
|
autoCompletion = new FormulaPaneAutoCompletion(provider); |
|
autoCompletion.setListCellRenderer(new CompletionCellRenderer()); |
|
autoCompletion.install(formulaTextArea); |
|
autoCompletion.installExtraRefreshComponent(variableTreeAndDescriptionArea); |
|
} |
|
|
|
|
|
protected void extendCheckBoxPane(JPanel checkBoxPane) { |
|
|
|
// do nothing |
|
} |
|
|
|
private 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); |
|
} |
|
|
|
public class DoubleClick extends MouseAdapter { |
|
String singlePressContent; |
|
|
|
String doublePressContent; |
|
|
|
@Override |
|
public void mousePressed(MouseEvent e) { |
|
int index = tipsList.getSelectedIndex(); |
|
if (index != -1) { |
|
if (e.getClickCount() == 1) { |
|
singlePressContent = (String) listModel.getElementAt(index); |
|
} else if (e.getClickCount() == 2) { |
|
doublePressContent = (String) listModel.getElementAt(index); |
|
} |
|
} |
|
} |
|
|
|
@Override |
|
public void mouseReleased(MouseEvent e) { |
|
int index = tipsList.getSelectedIndex(); |
|
if (index != -1) { |
|
if (e.getClickCount() == 1) { |
|
if (ComparatorUtils.equals((String) listModel.getElementAt(index), singlePressContent)) { |
|
singleClickActuator(singlePressContent); |
|
} |
|
} else if (e.getClickCount() == 2) { |
|
if (ComparatorUtils.equals((String) listModel.getElementAt(index), doublePressContent)) { |
|
doubleClickActuator(doublePressContent); |
|
} |
|
if (popupMenu != null) { |
|
popupMenu.setVisible(false); |
|
} |
|
} |
|
} |
|
} |
|
|
|
private void singleClickActuator(String currentLineContent) { |
|
refreshDescriptionTextArea(currentLineContent); |
|
formulaTextArea.requestFocusInWindow(); |
|
if (tipsList.getSelectedValue() != null) { |
|
fixFunctionNameList(tipsList.getSelectedValue().toString()); |
|
} |
|
} |
|
|
|
private void doubleClickActuator(String currentLineContent) { |
|
if (ifHasBeenWriten == 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; |
|
ifHasBeenWriten = 1; |
|
listModel.removeAllElements(); |
|
} |
|
} |
|
|
|
@Override |
|
public void keyPressed(KeyEvent e) { |
|
if (ifHasBeenWriten == 0) { |
|
this.formulaTextArea.setText(StringUtils.EMPTY); |
|
} |
|
} |
|
|
|
//hugh:为啥会是10呢?搞不懂~~~ |
|
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; |
|
|
|
@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) //如果是删除符号 ,为了可读性 没有和其他按键的程序相融合 |
|
{ |
|
listModel.removeAllElements(); |
|
currentPosition = formulaTextArea.getCaretPosition(); |
|
insertPosition = currentPosition; |
|
beginPosition = getBeginPosition(); |
|
} else { |
|
if (this.formulaTextArea.getText().trim().length() == 0) { |
|
insertPosition = 0; |
|
this.listModel.removeAllElements(); |
|
} else { |
|
this.formulaTextArea.setForeground(Color.black); |
|
currentPosition = formulaTextArea.getCaretPosition(); |
|
beginPosition = getBeginPosition(); |
|
insertPosition = beginPosition; |
|
firstStepToFindTips(beginPosition); |
|
if (tipsList.getSelectedValue() != null) { |
|
fixFunctionNameList(tipsList.getSelectedValue().toString()); |
|
} |
|
ifHasBeenWriten = 1; |
|
} |
|
} |
|
} |
|
|
|
private void fixFunctionNameList(String functionName) { |
|
int signOfContinue = 1; |
|
int indexOfFunction = 0; |
|
boolean found = false; |
|
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(); |
|
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; |
|
found = true; |
|
} |
|
} |
|
|
|
if (signOfType == 1) { |
|
functionTypeList.setSelectedIndex(i); |
|
signOfType = 0; |
|
} |
|
} |
|
} |
|
if (found) { |
|
functionNameList.setSelectedIndex(indexOfFunction); |
|
functionNameList.ensureIndexIsVisible(indexOfFunction); |
|
} else { |
|
functionTypeList.setSelectedIndex(0); |
|
} |
|
} |
|
|
|
private 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 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); |
|
search(toFind, false); |
|
formulaTextArea.requestFocusInWindow(); |
|
} else { |
|
listModel.removeAllElements(); |
|
} |
|
} else { |
|
String toFind = textArea.substring(theBeginPosition, currentPosition); |
|
search(toFind, false); |
|
formulaTextArea.requestFocusInWindow(); |
|
} |
|
} |
|
|
|
private static boolean isNum(char tested) { |
|
return tested >= '0' && tested <= '9'; |
|
} |
|
|
|
private boolean isChar(char tested) { |
|
return tested >= 'A' && tested <= 'Z'; |
|
} |
|
|
|
@Override |
|
public void keyTyped(KeyEvent e) { |
|
// do nothing |
|
} |
|
|
|
private void popTips() { |
|
popupMenu = new JPopupMenu(); |
|
JScrollPane tipsScrollPane = new JScrollPane(tipsList); |
|
popupMenu.add(tipsScrollPane); |
|
tipsScrollPane.setPreferredSize(new Dimension(240, 146)); |
|
tipsScrollPane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); |
|
popupMenu.show(keyWordTextField, 0, 23); |
|
} |
|
|
|
protected void search(String keyWord, boolean findDescription) { |
|
listModel.removeAllElements(); |
|
keyWord = removeAllSpace(keyWord); |
|
if (keyWord.length() != 0) { |
|
NameAndDescription[] descriptions = FunctionConstants.ALL.getDescriptions(); |
|
int lengthOfDes = descriptions.length; |
|
List<String> list = new ArrayList<>(); |
|
for (int i = 0; i < lengthOfDes; i++) { |
|
NameAndDescription and = descriptions[i]; |
|
|
|
String functionName = and.searchResult(keyWord, findDescription); |
|
if (StringUtils.isNotBlank(functionName)) { |
|
list.add(functionName); |
|
} |
|
} |
|
Collections.sort(list, new SimilarComparator(keyWord)); |
|
for (String name : list) { |
|
listModel.addElement(name); |
|
} |
|
|
|
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; |
|
} |
|
|
|
/** |
|
* Apply text. |
|
*/ |
|
private void applyText(String text) { |
|
if (text == null || text.length() <= 0) { |
|
return; |
|
} |
|
if (ifHasBeenWriten == 0) { |
|
formulaTextArea.setForeground(Color.black); |
|
formulaTextArea.setText(""); |
|
ifHasBeenWriten = 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(); |
|
} |
|
|
|
@Override |
|
protected String title4PopupWindow() { |
|
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Formula_Definition"); |
|
} |
|
|
|
public BasicDialog showLargeWindow(Window window, DialogActionListener l) { |
|
Dimension dimension = DesignSizeI18nManager.getInstance().i18nDimension(this.getClass().getName()); |
|
BasicDialog basicDialog = super.showWindowWithCustomSize(window, l, dimension); |
|
basicDialog.setMinimumSize(new Dimension(900, 600)); |
|
basicDialog.setResizable(true); |
|
return basicDialog; |
|
} |
|
|
|
/** |
|
* Populate |
|
*/ |
|
public void populate(BaseFormula formula) { |
|
this.populate(formula, VariableResolver.DEFAULT); |
|
} |
|
|
|
public void populate(BaseFormula formula, VariableResolver variableResolver) { |
|
this.variableTreeAndDescriptionArea.populate(variableResolver); |
|
|
|
// set text |
|
if (formula != null) { |
|
String content = formula.getContent(); |
|
if (content.trim().equals("=")) { |
|
this.formulaTextArea.setForeground(Color.gray); |
|
//Tips:You_Can_Input_B1_To_Input_The_Data_Of_The_First_Row_Second_Column |
|
this.formulaTextArea.setText("\n\n\n" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Tips")); |
|
this.formulaTextArea.setCaretPosition(0); |
|
ifHasBeenWriten = 0; |
|
this.listModel.removeAllElements(); |
|
} else if (content.trim().charAt(0) == '=') { |
|
this.formulaTextArea.setText(content.trim().substring(1)); |
|
currentPosition = formulaTextArea.getCaretPosition(); |
|
beginPosition = getBeginPosition(); |
|
insertPosition = beginPosition; |
|
firstStepToFindTips(beginPosition); |
|
if (tipsList.getSelectedValue() != null) { |
|
fixFunctionNameList(tipsList.getSelectedValue().toString()); |
|
} |
|
ifHasBeenWriten = 1; |
|
} else { |
|
this.formulaTextArea.setText(content); |
|
currentPosition = formulaTextArea.getCaretPosition(); |
|
beginPosition = getBeginPosition(); |
|
insertPosition = beginPosition; |
|
firstStepToFindTips(beginPosition); |
|
if (tipsList.getSelectedValue() != null) { |
|
fixFunctionNameList(tipsList.getSelectedValue().toString()); |
|
} |
|
ifHasBeenWriten = 1; |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* update |
|
*/ |
|
public BaseFormula update() { |
|
BaseFormula formula; |
|
if (ifHasBeenWriten == 0) { |
|
formula = BaseFormula.createFormulaBuilder().build(); |
|
return formula; |
|
} else { |
|
String content = this.formulaTextArea.getText(); |
|
|
|
if (StringUtils.isEmpty(content) || content.trim().charAt(0) == '=') { |
|
formula = BaseFormula.createFormulaBuilder().build(content); |
|
} else { |
|
formula = BaseFormula.createFormulaBuilder().build("=" + content); |
|
} |
|
return formula; |
|
} |
|
} |
|
|
|
// check valid |
|
private final ActionListener checkValidActionListener = new ActionListener() { |
|
|
|
public void actionPerformed(ActionEvent evt) { |
|
// Execute Formula default cell element. |
|
String formulaText = formulaTextArea.getText().trim(); |
|
FormulaCheckResult checkResult = FormulaChecker.check(formulaText); |
|
confirmCheckResult(checkResult, checkResult.getTips()); |
|
} |
|
}; |
|
|
|
private void calculateFormula() { |
|
String formulaText = formulaTextArea.getText().trim(); |
|
String unSupportFormula = containsUnsupportedSimulationFormulas(formulaText); |
|
if (unSupportFormula != null) { |
|
showMessageDialog(Toolkit.i18nText("Fine-Design_Basic_Formula_Unsupported_Formulas") + ":" + unSupportFormula, false, true); |
|
return; |
|
} |
|
|
|
boolean calException = false; |
|
String messageTips; |
|
FormulaCheckResult checkResult = FormulaChecker.check(formulaText); |
|
if (checkResult.grammarValid()) { |
|
messageTips = checkResult.getTips() + NEWLINE; |
|
Map<String, Object> paramsMap = setParamsIfExist(formulaText); |
|
Calculator calculator = Calculator.createCalculator(); |
|
ParameterMapNameSpace parameterMapNameSpace = ParameterMapNameSpace.create(paramsMap); |
|
calculator.pushNameSpace(parameterMapNameSpace); |
|
|
|
JTemplate<?, ?> currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); |
|
if (currentEditingTemplate != null) { |
|
IOFile file = (IOFile) currentEditingTemplate.getTarget(); |
|
calculator.setAttribute(TableDataSource.KEY, file); |
|
calculator.pushNameSpace(TableDataNameSpace.getInstance()); |
|
calculator.pushNameSpace(SimpleCellValueNameSpace.getInstance()); |
|
} |
|
|
|
BaseFormula baseFormula = BaseFormula.createFormulaBuilder().build(formulaText); |
|
Object calResult; |
|
try { |
|
calResult = calculator.evalValue(baseFormula); |
|
String objectToString = EssentialUtils.objectToString(calResult); |
|
String result = objectToString.length() > DEFUAL_FOMULA_LENGTH ? |
|
objectToString.substring(0, DEFUAL_FOMULA_LENGTH - ELLIPSIS.length()) + ELLIPSIS : objectToString; |
|
messageTips = messageTips + Toolkit.i18nText("Fine-Design_Basic_Formula_Cal_Result") + ":" + result; |
|
} catch (Exception ce) { |
|
//模拟计算如果出现错误,则抛出错误 |
|
calResult = ce.getMessage(); |
|
calException = true; |
|
FineLoggerFactory.getLogger().error(ce.getMessage(), ce); |
|
messageTips = messageTips + Toolkit.i18nText("Fine-Design_Basic_Formula_Cal_Error") + ":" + calResult; |
|
} |
|
FineLoggerFactory.getLogger().info("value:{}", calResult); |
|
} else { |
|
messageTips = checkResult.getTips(); |
|
} |
|
if (checkResult.isValid()) { |
|
showMessageDialog(messageTips, checkResult.isValid(), calException); |
|
} else { |
|
confirmCheckResult(checkResult, messageTips); |
|
} |
|
} |
|
|
|
|
|
private final ActionListener calculateActionListener = new ActionListener() { |
|
|
|
@Override |
|
public void actionPerformed(ActionEvent e) { |
|
calculateFormula(); |
|
} |
|
}; |
|
|
|
private boolean confirmCheckResult(FormulaCheckResult checkResult, String messageTips) { |
|
if (checkResult.isValid()) { |
|
showMessageDialog(checkResult.getTips(), checkResult.isValid(), false); |
|
} else { |
|
int columns = checkResult.getFormulaCoordinates().getColumns() + 1; |
|
String position = StringUtils.EMPTY; |
|
if (columns > 0) { |
|
position = Toolkit.i18nText("Fine-Design_Basic_Formula_The") + columns |
|
+ Toolkit.i18nText("Fine-Design_Basic_Formula_Error_Position") + " "; |
|
} |
|
int confirmDialog = FineJOptionPane.showConfirmDialog( |
|
FormulaPane.this, |
|
position + messageTips, |
|
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), |
|
JOptionPane.YES_NO_OPTION, |
|
JOptionPane.WARNING_MESSAGE, |
|
null, |
|
new String[]{Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Result"), Toolkit.i18nText("Fine-Design_Basic_Formula_Continue")}, |
|
Toolkit.i18nText("Fine-Design_Basic_Formula_Check_Result")); |
|
if (confirmDialog == 0) { |
|
formulaTextArea.setCaretPosition(Math.max(columns, 0)); |
|
formulaTextArea.requestFocus(); |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private void showMessageDialog(String message, boolean formulaValid, boolean calException) { |
|
if (formulaValid && !calException) { |
|
FineJOptionPane.showMessageDialog( |
|
FormulaPane.this, |
|
message); |
|
} else { |
|
FineJOptionPane.showMessageDialog( |
|
FormulaPane.this, |
|
message, |
|
Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), |
|
JOptionPane.WARNING_MESSAGE); |
|
} |
|
} |
|
|
|
private String containsUnsupportedSimulationFormulas(String formulaText) { |
|
try { |
|
Expression expression = Calculator.createCalculator().parse(formulaText); |
|
UnsupportedFormulaScanner scanner = new UnsupportedFormulaScanner(); |
|
if (!scanner.travelFormula(expression.getConditionalExpression())) { |
|
return scanner.getUnSupportFormula(); |
|
} |
|
|
|
UnsupportedSimulationNodeHunter unsupportedSimulationFormulaHunter = new UnsupportedSimulationNodeHunter(); |
|
expression.traversal4Tiny(unsupportedSimulationFormulaHunter); |
|
return unsupportedSimulationFormulaHunter.isSupported() ? null : unsupportedSimulationFormulaHunter.getUnSupportedNode(); |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error("", e); |
|
} |
|
return null; |
|
} |
|
|
|
@Override |
|
public boolean confirmContinueBeforeDoOK() { |
|
if (checkBeforeColse.isSelected()) { |
|
String formula = formulaTextArea.getText().trim(); |
|
FormulaCheckResult checkResult = FormulaChecker.check(formula); |
|
if (!checkResult.isValid()) { |
|
return confirmCheckResult(checkResult, checkResult.getTips()); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
private Map<String, Object> setParamsIfExist(String formulaText) { |
|
Map<String, Object> parameterMap = new HashMap<>(); |
|
try { |
|
Calculator calculator = Calculator.createCalculator(); |
|
Expression expression = calculator.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 ParameterInputNoneListenerPane(parameters); |
|
pPane.showSmallWindow(new JFrame(), new DialogActionAdapter() { |
|
@Override |
|
public void doOk() { |
|
parameterMap.putAll(pPane.update()); |
|
} |
|
}).setVisible(true); |
|
//过滤出数组参数,如:[1,2] |
|
for (Map.Entry<String, Object> entry : parameterMap.entrySet()) { |
|
if (entry.getValue().toString().startsWith("[") && entry.getValue().toString().endsWith("]")) { |
|
Expression parse = calculator.parse(entry.getValue()); |
|
ArrayExpression arrayExpression = (ArrayExpression) parse.getConditionalExpression(); |
|
Node[] arrays = arrayExpression.getArrays(); |
|
List<Object> arrayList = new ArrayList<>(); |
|
for (Node array : arrays) { |
|
if (array instanceof NumberLiteral) { |
|
arrayList.add(NumberFormat.getInstance().parse(array.toString())); |
|
} else { |
|
arrayList.add(array); |
|
} |
|
} |
|
FArray<Object> fArray = new FArray<>(arrayList); |
|
parameterMap.put(entry.getKey(), fArray); |
|
} else if (Utils.isNumeric(entry.getValue().toString())) { |
|
try { |
|
Number number = NumberFormat.getInstance().parse(entry.getValue().toString()); |
|
parameterMap.put(entry.getKey(), number); |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().warn("", e); |
|
} |
|
} |
|
} |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error("", e); |
|
} |
|
return parameterMap; |
|
} |
|
|
|
private static class ParameterCellHunter extends TinyHunter { |
|
|
|
private final Set<Parameter> parameterList = new HashSet<>(); |
|
|
|
Parameter[] getParameterBooty() { |
|
return parameterList.toArray(new Parameter[0]); |
|
} |
|
|
|
public void hunter4Tiny(Tiny tiny) { |
|
String statement = tiny.getStatement(); |
|
if (StringUtils.isNotBlank(statement) && statement.startsWith(ScriptConstants.DETAIL_TAG)) { |
|
if (statement.startsWith(ScriptConstants.SUMMARY_TAG)) { |
|
parameterList.add(new Parameter(statement)); |
|
} else { |
|
parameterList.add(new Parameter(statement.substring(1))); |
|
} |
|
} else if (tiny.getClass() == ColumnRowRange.class || |
|
tiny.getClass() == SheetIntervalLiteral.class || tiny.getClass() == BlockIntervalLiteral.class) { |
|
parameterList.add(new Parameter(tiny.toString())); |
|
} |
|
} |
|
} |
|
|
|
private static class UnsupportedSimulationNodeHunter extends TinyHunter { |
|
|
|
private boolean supported = true; |
|
|
|
private String unSupportedNode; |
|
|
|
private String[] curReportVariables; |
|
|
|
public UnsupportedSimulationNodeHunter() { |
|
curReportVariables = VariableResolver.DEFAULT.resolveCurReportVariables(); |
|
} |
|
|
|
public boolean isSupported() { |
|
return supported; |
|
} |
|
|
|
public String getUnSupportedNode() { |
|
return unSupportedNode; |
|
} |
|
|
|
public void hunter4Tiny(Tiny tiny) { |
|
if (tiny.getClass() == ColumnRowRangeInPage.class || tiny.getClass() == CRAddress.class |
|
|| Arrays.asList(curReportVariables).contains(tiny.toString())) { |
|
supported = false; |
|
unSupportedNode = tiny.toString(); |
|
} |
|
} |
|
} |
|
|
|
public class VariableTreeAndDescriptionArea extends JPanel implements AutoCompleteExtraRefreshComponent { |
|
|
|
private JTree variablesTree; |
|
private UITextArea descriptionTextArea; |
|
|
|
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(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_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); |
|
functionTypeListModel.addElement(FunctionConstants.NEW); |
|
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() + "()"; |
|
applyText(insert); |
|
|
|
} |
|
if (SwingUtilities.isRightMouseButton(evt)) { |
|
JPopupMenu popupMenu = new JPopupMenu(); |
|
LookDetailAction lookDetailAction = new 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(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_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(DESCRIPTION_TEXT_AREA_ROW, DESCRIPTION_TEXT_AREA_COLUMN); |
|
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 + ((TextUserObject) 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) { |
|
DefaultMutableTreeNode selectedTreeNode = (DefaultMutableTreeNode) variablesTree.getLastSelectedPathComponent(); |
|
Object selectedValue = selectedTreeNode.getUserObject(); |
|
Object selectedParentValue = ((DefaultMutableTreeNode) selectedTreeNode.getParent()).getUserObject(); |
|
|
|
if (selectedValue == null) { |
|
return; |
|
} |
|
|
|
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"))) { |
|
descriptionTextArea.setText(com.fr.design.i18n.Toolkit.i18nText(FormulaConstants.getValueByKey(((TextUserObject) selectedValue).getText()))); |
|
} else { |
|
descriptionTextArea.setText(StringUtils.EMPTY); |
|
} |
|
} else if (selectedValue instanceof TextFolderUserObject) { |
|
descriptionTextArea.setText(StringUtils.EMPTY); |
|
} |
|
descriptionTextArea.moveCaretPosition(0); |
|
} |
|
}); |
|
} |
|
|
|
|
|
private void initVariablesTree() { |
|
JPanel panel = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
|
// vairable. |
|
variablesTree = new JTree(); |
|
UIScrollPane variablesTreePane = new UIScrollPane(variablesTree); |
|
variablesTreePane.setBorder(new UIRoundedBorder(UIConstants.LINE_COLOR, 1, UIConstants.ARC)); |
|
panel.add(this.createNamePane( |
|
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Variables") + ":", variablesTreePane), BorderLayout.WEST); |
|
variablesTree.setRootVisible(false); |
|
variablesTree.setShowsRootHandles(true); |
|
variablesTree.addMouseListener(applyTextMouseListener); |
|
variablesTree.setCellRenderer(applyTreeCellRenderer); |
|
|
|
initDescriptionTextArea(); |
|
|
|
UIScrollPane desScrollPane = new UIScrollPane(descriptionTextArea); |
|
desScrollPane.setBorder(null); |
|
panel.add(this.createNamePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Formula_Description") + ":", desScrollPane), BorderLayout.CENTER); |
|
initVariablesTreeSelectionListener(); |
|
this.add(panel, BorderLayout.CENTER); |
|
} |
|
|
|
private void initComponents() { |
|
this.setLayout(new BorderLayout(4, 4)); |
|
initVariablesTree(); |
|
initFunctionPane(); |
|
} |
|
|
|
private void initFunctionPane() { |
|
JPanel functionPane = new JPanel(new BorderLayout(4, 4)); |
|
this.add(functionPane, BorderLayout.WEST); |
|
initFunctionTypeList(functionPane); |
|
initFunctionNameList(functionPane); |
|
functionTypeList.setSelectedIndex(0); |
|
} |
|
|
|
@Override |
|
public void refresh(String replacementText) { |
|
refreshText(replacementText); |
|
} |
|
|
|
/* |
|
* 查看函数的详细信息 |
|
*/ |
|
private class LookDetailAction extends UpdateAction { |
|
|
|
public LookDetailAction() { |
|
this.setName(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_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 com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Function_Detail"); |
|
} |
|
}; |
|
basicPane.setLayout(FRGUIPaneFactory.createBorderLayout()); |
|
UITextArea desArea = new UITextArea(); |
|
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) { |
|
|
|
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 refreshText(String line) { |
|
fixFunctionNameList(line); |
|
refreshDescriptionTextArea(line); |
|
} |
|
|
|
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(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaD_Data_Fields"), |
|
BaseUtils.readIcon("/com/fr/design/images/dialog/table.png"), |
|
variableResolver.resolveColumnNames()).createMutableTreeNode()); |
|
|
|
// Set cutReport Variable |
|
rootNode.add(new TextFolderUserObject(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Variables"), |
|
BaseUtils.readIcon("/com/fr/design/images/dialog/variable.png"), |
|
variableResolver.resolveCurReportVariables()).createMutableTreeNode()); |
|
|
|
rootNode.add(new TextFolderUserObject(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Parameter_Source_Type_Tabledata"), |
|
BaseUtils.readIcon("/com/fr/design/images/dialog/parameter.gif"), |
|
variableResolver.resolveTableDataParameterVariables()).createMutableTreeNode()); |
|
|
|
rootNode.add(new TextFolderUserObject(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_ParameterD_Report_Parameter"), |
|
BaseUtils.readIcon("/com/fr/design/images/m_report/p.gif"), |
|
variableResolver.resolveReportParameterVariables()).createMutableTreeNode()); |
|
|
|
rootNode.add(new TextFolderUserObject(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_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 SimilarComparator implements Comparator<String> { |
|
|
|
private String searchKey; |
|
|
|
public SimilarComparator(String searchKey) { |
|
this.searchKey = searchKey.toLowerCase(); |
|
} |
|
|
|
/** |
|
* 把以关键词开头的和不以关键词开头的分别按照字母表顺序排序 |
|
* |
|
* @param o1 待比较对象1 |
|
* @param o2 待比较对象2 |
|
* @return 比较结果,1表示 o1 > o2, -1表示 o1 < o2, 0表示 o1 = o2 |
|
*/ |
|
@Override |
|
public int compare(String o1, String o2) { |
|
int result; |
|
boolean o1StartWith = o1.toLowerCase().startsWith(searchKey); |
|
boolean o2StartWith = o2.toLowerCase().startsWith(searchKey); |
|
if (o1StartWith) { |
|
result = o2StartWith ? o1.compareTo(o2) : -1; |
|
} else { |
|
result = o2StartWith ? 1 : o1.compareTo(o2); |
|
} |
|
return result; |
|
} |
|
} |
|
|
|
public static class TextFolderUserObject { |
|
|
|
private String text; |
|
private Icon icon; |
|
private String[] subNodes = new String[0]; |
|
|
|
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 { |
|
|
|
TextUserObject(String text) { |
|
this(text, text); |
|
} |
|
|
|
TextUserObject(String text, String displayText) { |
|
this.text = text; |
|
this.displayText = displayText; |
|
} |
|
|
|
public String getText() { |
|
return this.text; |
|
} |
|
|
|
String getDisplayText() { |
|
return this.displayText; |
|
} |
|
|
|
private String text; |
|
private String displayText; |
|
} |
|
|
|
public static void main(String[] args) { |
|
FunctionGroup group = FunctionConstants.ALL; |
|
NameAndDescription[] nameAndDescriptions = group.getDescriptions(); |
|
StringBuffer buffer = new StringBuffer(); |
|
for (NameAndDescription d : nameAndDescriptions) { |
|
String name = d.getName(); |
|
buffer.append("\""); |
|
buffer.append(name.toUpperCase()); |
|
buffer.append("\""); |
|
buffer.append("|"); |
|
buffer.append(NEWLINE); |
|
buffer.append("\""); |
|
buffer.append(name.toLowerCase()); |
|
buffer.append("\""); |
|
buffer.append("|"); |
|
buffer.append(NEWLINE); |
|
} |
|
FineLoggerFactory.getLogger().debug(buffer.toString()); |
|
} |
|
}
|
|
|