帆软报表设计器源代码。
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.
 
 
 
 

437 lines
15 KiB

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<Boolean, String> 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<String, Void>() {
@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("<html> <body> <div style='height:16px'>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("</p><p>&nbsp&nbsp&nbsp&nbsp&nbsp;");
}
} else {
sb.append("</p><p>&nbsp&nbsp&nbsp&nbsp&nbsp;");
sb.append(args[i]);
sb.append("</p>");
}
}
}
sb.append("){</div><body> </html>");
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<Boolean, String> checkContent(String content) {
return new Pair<>(false, StringUtils.EMPTY);
}
}