package com.fr.design.javascript; import com.fr.base.svg.IconUtils; import com.fr.design.DesignerEnvManager; import com.fr.design.border.UIRoundedBorder; import com.fr.design.constants.KeyWords; 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.gui.autocomplete.AutoCompletion; import com.fr.design.gui.autocomplete.BasicCompletion; import com.fr.design.gui.autocomplete.CompletionProvider; import com.fr.design.gui.autocomplete.DefaultCompletionProvider; import com.fr.design.gui.autocomplete.ShorthandCompletion; import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.RSyntaxTextArea; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.SyntaxConstants; import com.fr.design.i18n.Toolkit; import com.fr.design.javascript.beautify.JavaScriptFormatHelper; import com.fr.design.javascript.jsapi.JSImplPopulateAction; import com.fr.design.javascript.jsapi.JSImplUpdateAction; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; import com.fr.general.IOUtils; import com.fr.js.JavaScriptImpl; import com.fr.stable.StringUtils; import com.fr.stable.collections.combination.Pair; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.SwingWorker; import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Cursor; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; public class JSContentPane extends BasicPane { protected RSyntaxTextArea contentTextArea; private UILabel funNameLabel = new UILabel(); private AutoCompletion ac; private static final Dimension FUNCTION_NAME_LABEL_SIZE = new Dimension(300, 80); private String[] defaultArgs; private int titleWidth = 180; private JPanel labelPane = new JPanel(new BorderLayout(6, 4));; private NewJavaScriptImplPane newJavaScriptImplPane = null; private JavaScriptImpl javaScript; private JSImplUpdateAction jsImplUpdateAction; private JSImplPopulateAction jsImplPopulateAction; private boolean modal; BasicDialog advancedEditorDialog ; private JLabel warningLabel; //用来标记当前显示状态 private boolean showWarning = false; private static final Color WARING_LABEL_BACKGROUND = Color.decode("#FFFBE6"); private static final Color WARING_LABEL_FOREGROUND = new Color(0, 0, 0, 216); private JPanel endBracketsPanel; public JSContentPane(){} public JSContentPane(String[] args) { defaultArgs = args; this.setLayout(FRGUIPaneFactory.createBorderLayout()); initFunctionTitle(args); JPanel jsParaPane = createJSParaPane(); if (needAdvancedEditor()) { addNewPaneLabel(); } this.add(jsParaPane, BorderLayout.NORTH); UIScrollPane sp = createContentTextAreaPanel(); initContentTextAreaListener(); this.add(sp, BorderLayout.CENTER); UILabel funNameLabel2 = new UILabel(); funNameLabel2.setText("}"); if (isNeedContentWarning()) { endBracketsPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); endBracketsPanel.add(funNameLabel2, BorderLayout.NORTH); warningLabel = initWarningLabel(); this.add(endBracketsPanel, BorderLayout.SOUTH); } else { this.add(funNameLabel2, BorderLayout.SOUTH); } } protected JLabel initWarningLabel() { JLabel warningLabel = new JLabel(StringUtils.EMPTY); warningLabel.setOpaque(true); warningLabel.setAlignmentX(LEFT_ALIGNMENT); // 设置左右 5px 的间距 warningLabel.setBorder(new EmptyBorder(0, 5, 0, 5)); warningLabel.setPreferredSize(new Dimension(200, 20)); warningLabel.setBackground(WARING_LABEL_BACKGROUND); warningLabel.setForeground(WARING_LABEL_FOREGROUND); addContentListener4Warning(); return warningLabel; } private void addContentListener4Warning() { contentTextArea.getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { checkContent(contentTextArea); } @Override public void removeUpdate(DocumentEvent e) { checkContent(contentTextArea); } @Override public void changedUpdate(DocumentEvent e) { checkContent(contentTextArea); } }); } private void checkContent(RSyntaxTextArea contentTextArea) { String content = contentTextArea.getText().trim(); Pair pair = checkContent(content); boolean matches = Boolean.TRUE.equals(pair.getFirst()); String tip = pair.getSecond() != null ? pair.getSecond() : StringUtils.EMPTY; // 更新提示 updateWarningTip(tip); if (matches == showWarning) { return; } if (matches) { addWarningLabel(); showWarning = true; } else { removeWarningLabel(); showWarning = false; } } protected void updateWarningTip(String tip) { if (!StringUtils.equals(warningLabel.getText(), tip)) { warningLabel.setText(tip); } } protected void removeWarningLabel() { endBracketsPanel.remove(warningLabel); endBracketsPanel.revalidate(); } protected void addWarningLabel() { endBracketsPanel.add(warningLabel, BorderLayout.SOUTH); endBracketsPanel.revalidate(); } public JSContentPane(String[] args,boolean modal) { this(args); this.modal = modal; } public void setJsImplUpdateAction(JSImplUpdateAction jsImplUpdateAction){ this.jsImplUpdateAction = jsImplUpdateAction; } public void setJsImplPopulateAction(JSImplPopulateAction jsImplPopulateAction){ this.jsImplPopulateAction = jsImplPopulateAction; } public void updateJSImpl(JavaScriptImpl javaScript){ this.javaScript = javaScript; } private void addNewPaneLabel(){ UILabel advancedEditorLabel = new UILabel(Toolkit.i18nText("Fine-Design_Advanced_Editor"), IconUtils.readIcon("com/fr/design/images/edit/advancedEditor.svg"), SwingConstants.LEFT); advancedEditorLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); advancedEditorLabel.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if(newJavaScriptImplPane == null){ newJavaScriptImplPane = new NewJavaScriptImplPane(defaultArgs); } jsImplUpdateAction.update(javaScript); newJavaScriptImplPane.populate(javaScript); if(advancedEditorDialog == null || !advancedEditorDialog.isVisible()) { advancedEditorDialog = newJavaScriptImplPane.showWindowWithCustomSize(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { @Override public void doOk() { if (javaScript != null) { newJavaScriptImplPane.updateBean(javaScript); jsImplPopulateAction.populate(javaScript); } } @Override public void doCancel() { super.doCancel(); } },new Dimension(900,800)); advancedEditorDialog.setModal(modal); advancedEditorDialog.setResizable(true); advancedEditorDialog.pack(); advancedEditorDialog.setVisible(true); } advancedEditorDialog.requestFocus(); } }); labelPane.add(advancedEditorLabel,BorderLayout.EAST); } protected UIScrollPane createContentTextAreaPanel(){ contentTextArea = new RSyntaxTextArea(); contentTextArea.setCloseCurlyBraces(true); contentTextArea.setLineWrap(true); contentTextArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); contentTextArea.setCodeFoldingEnabled(true); contentTextArea.setAntiAliasingEnabled(true); return new UIScrollPane(contentTextArea); } private void initContentTextAreaListener(){ contentTextArea.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { // 获得焦点时 安装 installAutoCompletion(); } @Override public void focusLost(FocusEvent e) { // 失去焦点时 卸载 uninstallAutoCompletion(); } }); } protected JPanel createJSParaPane(){ UILabel label = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Format_JavaScript"), IOUtils.readIcon("com/fr/design/images/edit/format.png"), SwingConstants.LEFT); label.setCursor(new Cursor(Cursor.HAND_CURSOR)); label.setToolTipText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Format_JavaScript")); label.addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { new SwingWorker() { @Override protected String doInBackground() throws Exception { return JavaScriptFormatHelper.beautify(contentTextArea.getText()); } @Override protected void done() { try { String text = get(); contentTextArea.setText(text); } catch (Exception ignore) { } } }.execute(); } }); labelPane.add(label,BorderLayout.CENTER); JPanel jsParaPane = new JPanel(new BorderLayout(4, 4)); jsParaPane.setPreferredSize(new Dimension(300, 80)); UIScrollPane scrollPane = new UIScrollPane(funNameLabel); scrollPane.setPreferredSize(FUNCTION_NAME_LABEL_SIZE); scrollPane.setBorder(new UIRoundedBorder(UIConstants.TITLED_BORDER_COLOR, 1, UIConstants.ARC)); jsParaPane.add(scrollPane, BorderLayout.WEST); jsParaPane.add(labelPane, BorderLayout.EAST); return jsParaPane; } protected void initFunctionTitle(String[] args){ funNameLabel = new UILabel(); this.setFunctionTitle(args); } private KeyStroke convert2KeyStroke(String ks) { return KeyStroke.getKeyStroke(ks.replace("+", "pressed")); } /** * 注册安装 自动补全监听 */ private void installAutoCompletion() { if (ac == null) { CompletionProvider provider = createCompletionProvider(); ac = new AutoCompletion(provider); String shortCuts = DesignerEnvManager.getEnvManager().getAutoCompleteShortcuts(); ac.setTriggerKey(convert2KeyStroke(shortCuts)); ac.install(contentTextArea); } } /** * 卸载移除 自动补全监听 */ private void uninstallAutoCompletion() { if (ac != null) { ac.uninstall(); ac = null; } } @Override protected String title4PopupWindow() { return "JS"; } public void populate(String js) { this.contentTextArea.setText(js); } public String update() { return this.contentTextArea.getText(); } public void reset() { this.contentTextArea.setText(null); } public void setFunctionTitle(String[] args) { funNameLabel.setText(createFunctionTitle(args)); } public void setFunctionTitle(String[] args, String[] defaultArgs) { String[] titles; if (defaultArgs == null) { titles = args; } else if (args == null) { titles = defaultArgs; } else { ArrayList list = new ArrayList(); for (String s : defaultArgs) { list.add(s); } for (String s : args) { list.add(s); } titles = (String[]) list.toArray(new String[list.size()]); } setFunctionTitle(titles); } /** * 用html,方便换行 * * @param args * @return */ private String createFunctionTitle(String[] args) { StringBuffer sb = new StringBuffer(); sb.append("
function("); int width = titleWidth; FontMetrics cellFM = this.getFontMetrics(this.getFont()); int tempwidth = 0; if (args != null) { for (int i = 0; i < args.length; i++) { if (args[i] == null) { continue; } if (cellFM.stringWidth(args[i]) < width) { tempwidth = tempwidth + cellFM.stringWidth(args[i]); if (tempwidth < width) { sb.append(args[i]); if (i != args.length - 1) { sb.append(","); } } else { tempwidth = 0; i = i - 1;// 后退一步 sb.append("

     "); } } else { sb.append("

     "); sb.append(args[i]); sb.append("

"); } } } sb.append("){
"); return sb.toString(); } private CompletionProvider createCompletionProvider() { DefaultCompletionProvider provider = new DefaultCompletionProvider(); for (String key : KeyWords.JAVASCRIPT) { provider.addCompletion(new BasicCompletion(provider, key)); } for (String[] key : KeyWords.JAVASCRIPT_SHORT) { provider.addCompletion(new ShorthandCompletion(provider, key[0], key[1], key[1])); } return provider; } protected boolean needAdvancedEditor() { return true; } /** * 是否支持内容提示 * @return 是否支持 */ protected boolean isNeedContentWarning() { return false; } /** * 自定义匹配js内容,并返回对应的提示文本 * @return <是否匹配,提示文本> */ protected Pair checkContent(String content) { return new Pair<>(false, StringUtils.EMPTY); } }