Browse Source

Merge branch 'feature/10.0' into release/10.0

# Conflicts:
#	designer-base/src/main/java/com/fr/design/gui/icombocheckbox/UICheckListPopup.java
feature/big-screen
vito 5 years ago
parent
commit
cfcd0ff50c
  1. 8
      .gitignore
  2. 82
      build.gradle
  3. 3
      designer-base/src/main/java/com/fr/design/bridge/exec/JSExecutor.java
  4. 18
      designer-base/src/main/java/com/fr/design/dcm/UniversalDatabasePane.java
  5. 12
      designer-base/src/main/java/com/fr/design/dcm/UniversalDcmBridge.java
  6. 12
      designer-base/src/main/java/com/fr/design/extra/LoginWebBridge.java
  7. 7
      designer-base/src/main/java/com/fr/design/extra/PluginWebBridge.java
  8. 234
      designer-base/src/main/java/com/fr/design/extra/QQLoginWebPane.java
  9. 15
      designer-base/src/main/java/com/fr/design/extra/WebViewDlgHelper.java
  10. 2
      designer-base/src/main/java/com/fr/design/gui/frpane/UIBubbleFloatPane.java
  11. 31
      designer-base/src/main/java/com/fr/design/gui/icombocheckbox/UICheckListPopup.java
  12. 17
      designer-base/src/main/java/com/fr/design/gui/icombocheckbox/UIComboCheckBox.java
  13. 1
      designer-base/src/main/java/com/fr/design/gui/ifilechooser/UINativeFileChooser.java
  14. 13
      designer-base/src/main/java/com/fr/design/gui/syntax/ui/rsyntaxtextarea/RSyntaxTextArea.java
  15. 3
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
  16. 20
      designer-base/src/main/java/com/fr/design/os/impl/MacOsAddListenerAction.java
  17. 68
      designer-base/src/main/java/com/fr/design/ui/Assistant.java
  18. 130
      designer-base/src/main/java/com/fr/design/ui/EmbProtocolHandler.java
  19. 147
      designer-base/src/main/java/com/fr/design/ui/ModernUIPane.java
  20. 85
      designer-base/src/main/java/com/fr/design/ui/NxComplexInterceptRequestCallback.java
  21. 134
      designer-base/src/main/java/com/fr/design/ui/NxInterceptRequestCallback.java
  22. 230
      designer-base/src/main/java/com/fr/design/upm/UpmBridge.java
  23. 2
      designer-base/src/main/java/com/fr/design/upm/UpmFinder.java
  24. 15
      designer-base/src/main/java/com/fr/design/upm/UpmShowPane.java
  25. 15
      designer-base/src/main/java/com/fr/design/upm/exec/UpmBrowserExecutor.java
  26. 200
      designer-base/src/main/java/com/fr/design/utils/AWTUtilities.java
  27. 3
      designer-base/src/main/java/com/fr/start/SplashWindow.java
  28. 41
      designer-base/src/test/java/com/fr/design/gui/icombocheckbox/UICheckListPopupTest.java
  29. 3
      designer-chart/build.gradle
  30. 3
      designer-form/build.gradle
  31. 4
      designer-realize/build.gradle
  32. 2
      designer-realize/src/main/java/com/fr/design/mainframe/alphafine/listener/ComponentHandler.java
  33. 29
      globalConfigHook.gradle
  34. BIN
      gradle/wrapper/gradle-wrapper.jar
  35. 6
      gradle/wrapper/gradle-wrapper.properties
  36. 172
      gradlew
  37. 84
      gradlew.bat
  38. 4
      pom.xml
  39. 12
      settings.gradle

8
.gitignore vendored

@ -3,6 +3,14 @@
.DS_Store
.classpath
.project
.gradle
target/
*/build
designer-base/${web-inf-path}
designer-chart/${web-inf-path}
designer-form/${web-inf-path}
designer-realize/${web-inf-path}

82
build.gradle

@ -0,0 +1,82 @@
import org.gradle.plugins.ide.idea.model.IdeaLanguageLevel
plugins {
id 'java'
id 'java-library'
id 'com.fr.common' version '1.0-SNAPSHOT'
}
//
ext {
frVersion = ""
outputPath = "build"
ignoreTestFailureSetting = true
languageLevelSetting = 1.8
}
applyGlobalConfigPathIfExist()
if (versions.frVersion) {
frVersion = versions.frVersion
}
def frDevVersion = "DEV" + frVersion
dependencies {
api project(':designer-base')
api project(':designer-chart')
api project(':designer-form')
api project(':designer-realize')
}
allprojects {
apply plugin: 'java'
apply plugin: 'java-library'
apply plugin: 'idea'
group 'com.fr.design'
version frDevVersion
sourceCompatibility = languageLevelSetting
targetCompatibility = languageLevelSetting
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
repositories {
mavenLocal()
}
idea {
module {
inheritOutputDirs = false
outputDir = file(outputPath +"/classes")
testOutputDir = file(outputPath +"/test-classes")
languageLevel = new IdeaLanguageLevel(sourceCompatibility)
targetBytecodeVersion = targetCompatibility
}
}
dependencies {
implementation 'com.fr.third:jxbrowser:7.5'
implementation 'com.fr.third:jxbrowser-swing:7.5'
implementation 'com.fr.third:jxbrowser-mac:7.5'
implementation 'com.fr.third:jxbrowser-win64:7.5'
implementation 'com.fr.third.server:servlet-api:3.0'
implementation 'org.swingexplorer:swexpl:2.0.1'
implementation 'org.swingexplorer:swag:1.0'
implementation 'net.java.dev.jna:jna:5.4.0'
implementation 'org.apache.tomcat:tomcat-catalina:8.5.32'
implementation 'io.socket:socket.io-client:0.7.0'
implementation 'com.fr.third:fine-third:' + frVersion
implementation 'com.fr.core:fine-core:' + frVersion
implementation 'com.fr.activator:fine-activator:' + frVersion
implementation 'com.fr.datasource:fine-datasource:' + frVersion
implementation 'com.fr.decision:fine-decision:' + frVersion
implementation 'com.fr.schedule:fine-schedule:' + frVersion
implementation 'com.fr.report:fine-report-engine:' + frDevVersion
testImplementation 'org.easymock:easymock:3.5.1'
testImplementation 'org.powermock:powermock-module-junit4:1.7.1'
testImplementation 'org.powermock:powermock-api-easymock:1.7.1'
testImplementation 'junit:junit:4.12'
}
}

3
designer-base/src/main/java/com/fr/design/bridge/exec/JSExecutor.java

@ -4,5 +4,8 @@ package com.fr.design.bridge.exec;
* Created by ibm on 2017/6/21.
*/
public interface JSExecutor {
String CALLBACK_FUNCTION_NAME = "action";
void executor(String newValue);
}

18
designer-base/src/main/java/com/fr/design/dcm/UniversalDatabasePane.java

@ -2,9 +2,8 @@ package com.fr.design.dcm;
import com.fr.design.dialog.BasicPane;
import com.fr.design.ui.ModernUIPane;
import com.teamdev.jxbrowser.chromium.JSValue;
import com.teamdev.jxbrowser.chromium.events.ScriptContextAdapter;
import com.teamdev.jxbrowser.chromium.events.ScriptContextEvent;
import com.teamdev.jxbrowser.browser.callback.InjectJsCallback;
import com.teamdev.jxbrowser.js.JsObject;
import java.awt.*;
@ -26,14 +25,13 @@ public class UniversalDatabasePane extends BasicPane {
setLayout(new BorderLayout());
modernUIPane = new ModernUIPane.Builder<>()
.withComponent(UniversalDatabaseComponent.KEY)
.prepare(new ScriptContextAdapter() {
@Override
public void onScriptContextCreated(ScriptContextEvent event) {
JSValue window = event.getBrowser().executeJavaScriptAndReturnValue("window");
window.asObject().setProperty("DcmHelper", UniversalDcmBridge.getBridge(event.getBrowser()));
.prepare(params -> {
JsObject window = params.frame().executeJavaScript("window");
if (window != null) {
window.putProperty("DcmHelper", UniversalDcmBridge.getBridge());
}
})
.build();
return InjectJsCallback.Response.proceed();
}).build();
add(modernUIPane, BorderLayout.CENTER);
}
}

12
designer-base/src/main/java/com/fr/design/dcm/UniversalDcmBridge.java

@ -2,8 +2,6 @@ package com.fr.design.dcm;
import com.fr.decision.webservice.bean.BaseBean;
import com.fr.design.bridge.exec.JSBridge;
import com.teamdev.jxbrowser.chromium.Browser;
import com.teamdev.jxbrowser.chromium.JSObject;
/**
* @author richie
@ -13,18 +11,18 @@ import com.teamdev.jxbrowser.chromium.JSObject;
*/
public class UniversalDcmBridge {
public static UniversalDcmBridge getBridge(Browser browser) {
return new UniversalDcmBridge(browser);
public static UniversalDcmBridge getBridge() {
return new UniversalDcmBridge();
}
private JSObject window;
private UniversalDcmBridge(Browser browser) {
this.window = browser.executeJavaScriptAndReturnValue("window").asObject();
private UniversalDcmBridge() {
}
/**
* 获取所有的数据连接
*
* @return 数据连接集合
*/
@JSBridge

12
designer-base/src/main/java/com/fr/design/extra/LoginWebBridge.java

@ -196,18 +196,6 @@ public class LoginWebBridge {
uiLabel.setBackground(LOGIN_BACKGROUND);
}
/**
* 弹出QQ授权页面
*/
public void showQQ() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
WebViewDlgHelper.createQQLoginDialog();
}
});
}
/**
* 关闭QQ授权窗口
*/

7
designer-base/src/main/java/com/fr/design/extra/PluginWebBridge.java

@ -533,13 +533,6 @@ public class PluginWebBridge {
threadPoolExecutor.submit(task);
}
/**
* 弹出QQ授权页面
*/
public void showQQ() {
LoginWebBridge.getHelper().showQQ();
}
/**
* 通过QQ登录后通知登录
*/

234
designer-base/src/main/java/com/fr/design/extra/QQLoginWebPane.java

@ -1,234 +0,0 @@
package com.fr.design.extra;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.general.CloudCenter;
import com.fr.general.ComparatorUtils;
import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.embed.swing.JFXPanel;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ButtonBuilder;
import javafx.scene.control.LabelBuilder;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.HBoxBuilder;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebEvent;
import javafx.scene.web.WebView;
import javafx.stage.Modality;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.WindowEvent;
import javafx.util.Callback;
import netscape.javascript.JSObject;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import java.awt.Toolkit;
/**
* Created by zhaohehe on 16/7/28.
*/
public class QQLoginWebPane extends JFXPanel {
private WebEngine webEngine;
private String url;
private static JSObject window;
private static int DEFAULT_PRIMARYSTAGE_WIDTH = 100;
private static int DEFAULT_PRIMARYSTAGE_HEIGHT = 100;
private static int DEFAULT_CONFIRM_WIDTH = 450;
private static int DEFAULT_CONFIRM_HEIGHT = 160;
private static int DEFAULT_OFFEST = 20;
class Delta {
double x, y;
}
public QQLoginWebPane(final String installHome) {
Platform.setImplicitExit(false);
Platform.runLater(new Runnable() {
@Override
public void run() {
BorderPane root = new BorderPane();
Scene scene = new Scene(root);
QQLoginWebPane.this.setScene(scene);
final WebView webView = new WebView();
webEngine = webView.getEngine();
url = "file:///" + installHome + "/scripts/qqLogin.html";
webEngine.load(url);
final Stage primaryStage = new Stage();
HBox layout = new HBox();
try {
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(new Scene(layout));
webView.getScene().getStylesheets().add(IOUtils.getResource("modal-dialog.css", getClass()).toExternalForm());
primaryStage.initStyle(StageStyle.UTILITY);
primaryStage.setScene(new Scene(new Group(), DEFAULT_PRIMARYSTAGE_WIDTH, DEFAULT_PRIMARYSTAGE_HEIGHT));
primaryStage.setX(0);
primaryStage.setY(Screen.getPrimary().getBounds().getHeight() + DEFAULT_PRIMARYSTAGE_HEIGHT);
primaryStage.show();
} catch (Exception e) {
FineLoggerFactory.getLogger().info(e.getMessage());
}
webEngine.setConfirmHandler(new Callback<String, Boolean>() {
@Override
public Boolean call(String msg) {
Boolean confirmed = confirm(primaryStage, msg, webView);
return confirmed;
}
});
configWebEngine();
webView.setContextMenuEnabled(false);//屏蔽右键
root.setCenter(webView);
}
});
}
private void configWebEngine() {
webEngine.locationProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, final String oldValue, String newValue) {
disableLink(webEngine);
// webView好像默认以手机版显示网页,浏览器里过滤掉这个跳转
if (ComparatorUtils.equals(newValue, url) || ComparatorUtils.equals(newValue, CloudCenter.getInstance().acquireUrlByKind("bbs.mobile"))) {
return;
}
LoginWebBridge.getHelper().openUrlAtLocalWebBrowser(webEngine, newValue);
}
});
webEngine.setOnAlert(new EventHandler<WebEvent<String>>() {
@Override
public void handle(WebEvent<String> event) {
showAlert(event.getData());
}
});
webEngine.getLoadWorker().stateProperty().addListener(
new ChangeListener<Worker.State>() {
public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
if (newState == Worker.State.SUCCEEDED) {
window = (JSObject) webEngine.executeScript("window");
window.setMember("QQLoginHelper", LoginWebBridge.getHelper());
}
}
}
);
}
private void showAlert(final String message) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
FineJOptionPane.showMessageDialog(QQLoginWebPane.this, message);
}
});
}
private void disableLink(final WebEngine eng) {
try {
// webView端不跳转 虽然webView可以指定本地浏览器打开某个链接,但是当本地浏览器跳转到指定链接的同时,webView也做了跳转,
// 为了避免出现在一个600*400的资讯框里加载整个网页的情况,webView不跳转到新网页
Platform.runLater(new Runnable() {
@Override
public void run() {
eng.executeScript("location.reload()");
LoginWebBridge.getHelper().closeQQWindow();
}
});
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
private Boolean confirm(final Stage parent, String msg, final WebView webView) {
final BooleanProperty confirmationResult = new SimpleBooleanProperty();
// initialize the confirmation dialog
final Stage dialog = new Stage(StageStyle.UTILITY);
dialog.setX(Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - DEFAULT_CONFIRM_WIDTH / 2.0D + DEFAULT_OFFEST);
dialog.setY(Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 + DEFAULT_OFFEST);
dialog.setHeight(DEFAULT_CONFIRM_HEIGHT);
dialog.setWidth(DEFAULT_CONFIRM_WIDTH);
dialog.setIconified(false);
dialog.initOwner(parent);
dialog.initModality(Modality.WINDOW_MODAL);
dialog.setScene(
new Scene(
HBoxBuilder.create().styleClass("modal-dialog").children(
LabelBuilder.create().text(msg).build(),
ButtonBuilder.create().text(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_BBSLogin_Switch_Account")).defaultButton(true).onAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
// take action and close the dialog.
confirmationResult.set(true);
webView.getEngine().reload();
dialog.close();
}
}).build(),
ButtonBuilder.create().text(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Engine_Cancel")).cancelButton(true).onAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
// abort action and close the dialog.
confirmationResult.set(false);
dialog.close();
}
}).build()
).build()
, Color.TRANSPARENT
)
);
configDrag(dialog);
// style and show the dialog.
dialog.getScene().getStylesheets().add(IOUtils.getResource("modal-dialog.css", getClass()).toExternalForm());
dialog.setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent event) {
event.consume();
dialog.close();
}
});
dialog.showAndWait();
return confirmationResult.get();
}
private void configDrag(final Stage dialog) {
// allow the dialog to be dragged around.
final Node root = dialog.getScene().getRoot();
final Delta dragDelta = new Delta();
root.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
// record a delta distance for the drag and drop operation.
dragDelta.x = dialog.getX() - mouseEvent.getScreenX();
dragDelta.y = dialog.getY() - mouseEvent.getScreenY();
}
});
root.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
dialog.setX(mouseEvent.getScreenX() + dragDelta.x);
dialog.setY(mouseEvent.getScreenY() + dragDelta.y);
}
});
}
}

15
designer-base/src/main/java/com/fr/design/extra/WebViewDlgHelper.java

@ -183,21 +183,6 @@ public class WebViewDlgHelper {
}
}
public static void createQQLoginDialog() {
try {
Class<?> clazz = Class.forName("com.fr.design.extra.QQLoginWebPane");
Constructor constructor = clazz.getConstructor(String.class);
Component webPane = (Component) constructor.newInstance(new File(installHome).getAbsolutePath());
UIDialog qqLoginDialog = new QQLoginDialog(DesignerContext.getDesignerFrame(), webPane);
LoginWebBridge.getHelper().setQQDialog(qqLoginDialog);
qqLoginDialog.setVisible(true);
} catch (Throwable ignored) {
// ignored
}
}
private static void confirmDownLoadShopJS() {
int rv = FineJOptionPane.showConfirmDialog(
null,

2
designer-base/src/main/java/com/fr/design/gui/frpane/UIBubbleFloatPane.java

@ -2,9 +2,9 @@ package com.fr.design.gui.frpane;
import com.fr.design.beans.BasicBeanPane;
import com.fr.design.dialog.UIDialog;
import com.fr.design.utils.AWTUtilities;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.Constants;
import com.sun.awt.AWTUtilities;
import javax.swing.JComponent;
import javax.swing.JPanel;

31
designer-base/src/main/java/com/fr/design/gui/icombocheckbox/UICheckListPopup.java

@ -36,14 +36,20 @@ public class UICheckListPopup extends UIPopupMenu {
private UIScrollPane jScrollPane;
private Color mouseEnteredColor = UIConstants.CHECKBOX_HOVER_SELECTED;
private int maxDisplayNumber = 8;
private boolean supportSelectAll = true;
public static final String COMMIT_EVENT = "commit";
public static final String SELECT_ALL = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Choose_All");
private static final String SELECT_ALL = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Choose_All");
private static final int CHECKBOX_HEIGHT = 25;
public UICheckListPopup(Object[] value) {
public UICheckListPopup(Object[] values) {
this(values, true);
}
public UICheckListPopup(Object[] value, boolean supportSelectAll) {
super();
values = value;
this.supportSelectAll = supportSelectAll;
initComponent();
}
@ -78,7 +84,9 @@ public class UICheckListPopup extends UIPopupMenu {
checkBoxList.clear();
//全选加在第一个位置
addOneCheckValue(SELECT_ALL);
if (supportSelectAll) {
addOneCheckValue(SELECT_ALL);
}
for (Object checkValue : values) {
addOneCheckValue(checkValue);
}
@ -151,7 +159,7 @@ public class UICheckListPopup extends UIPopupMenu {
private void addSelectListener() {
for (int i = 0; i < checkBoxList.size(); i++) {
JCheckBox checkBox = checkBoxList.get(i);
if (i == 0) {
if (supportSelectAll && i == 0) {
checkBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
@ -189,7 +197,8 @@ public class UICheckListPopup extends UIPopupMenu {
List<Object> allValue = Arrays.asList(values);
for (Object value : selectedValues.keySet()) {
int index = allValue.indexOf(value);
checkBoxList.get(index + 1).setSelected(selectedValues.get(value));
index = supportSelectAll ? index + 1 : index;
checkBoxList.get(index).setSelected(selectedValues.get(value));
}
}
@ -201,15 +210,19 @@ public class UICheckListPopup extends UIPopupMenu {
public Object[] getSelectedValues() {
List<Object> selectedValues = new ArrayList<Object>();
int selectCount = 0;
for (int i = 1; i < checkBoxList.size(); i++) {
int startIndex = supportSelectAll ? 1 : 0;
for (int i = startIndex; i < checkBoxList.size(); i++) {
if (checkBoxList.get(i).isSelected()) {
selectedValues.add(values[i - 1]);
int valueIndex = supportSelectAll ? i - 1 : i;
selectedValues.add(values[valueIndex]);
selectCount++;
}
}
//全选半选切换
switchSelectIcon(selectCount);
if (supportSelectAll) {
switchSelectIcon(selectCount);
}
return selectedValues.toArray(new Object[selectedValues.size()]);
}

17
designer-base/src/main/java/com/fr/design/gui/icombocheckbox/UIComboCheckBox.java

@ -59,8 +59,18 @@ public class UIComboCheckBox extends JComponent implements UIObserver, GlobalNam
private String multiComboName = StringUtils.EMPTY;
private boolean showOmitText = true;
private boolean supportSelectAll = true;
public UIComboCheckBox(Object[] value) {
this(value, DEFAULT_VALUE_SPERATOR);
this(value, DEFAULT_VALUE_SPERATOR, true);
}
public UIComboCheckBox(Object[] value, boolean supportSelectAll) {
this(value, DEFAULT_VALUE_SPERATOR, supportSelectAll);
}
public UIComboCheckBox(Object[] values, String valueSperator) {
this(values, valueSperator, true);
}
/**
@ -69,8 +79,9 @@ public class UIComboCheckBox extends JComponent implements UIObserver, GlobalNam
* @param value
* @param valueSperator
*/
public UIComboCheckBox(Object[] value, String valueSperator) {
public UIComboCheckBox(Object[] value, String valueSperator, boolean supportSelectAll) {
values = value;
this.supportSelectAll = supportSelectAll;
this.valueSperator = valueSperator;
initComponent();
}
@ -102,7 +113,7 @@ public class UIComboCheckBox extends JComponent implements UIObserver, GlobalNam
private void initComponent() {
this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
this.popup = new UICheckListPopup(values);
this.popup = new UICheckListPopup(values, supportSelectAll);
this.popup.addActionListener(new PopupAction());
this.editor = createEditor();
this.arrowButton = createArrowButton();

1
designer-base/src/main/java/com/fr/design/gui/ifilechooser/UINativeFileChooser.java

@ -1,5 +1,6 @@
package com.fr.design.gui.ifilechooser;
import com.fr.design.gui.ifilechooser.AbstractFileChooser;
import com.fr.design.mainframe.DesignerContext;
import com.fr.stable.os.OperatingSystem;

13
designer-base/src/main/java/com/fr/design/gui/syntax/ui/rsyntaxtextarea/RSyntaxTextArea.java

@ -9,16 +9,7 @@
*/
package com.fr.design.gui.syntax.ui.rsyntaxtextarea;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@ -604,7 +595,7 @@ private boolean fractionalFontMetricsEnabled;
SecurityManager sm = System.getSecurityManager();
if (sm!=null) {
try {
sm.checkSystemClipboardAccess();
sm.checkPermission(new AWTPermission("accessClipboard"));
} catch (SecurityException se) {
UIManager.getLookAndFeel().provideErrorFeedback(null);
return;

3
designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java

@ -509,7 +509,8 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
if (OperatingSystem.isMacos()) {
Class clazz = Class.forName("com.apple.eawt.Application");
BufferedImage icon = image.isEmpty() ? IOUtils.readImage("/com/fr/base/images/oem/logo.png") : image.get(image.size() - 1);
Reflect.on(Reflect.on(clazz).call("getApplication").get()).call("setDockIconImage", icon);
Object application = Reflect.on(clazz).call("getApplication").get();
Reflect.on(application).call("setDockIconImage", icon);
} else {
this.setIconImages(image);
}

20
designer-base/src/main/java/com/fr/design/os/impl/MacOsAddListenerAction.java

@ -9,11 +9,16 @@ import com.fr.invoke.Reflect;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.os.support.OSBasedAction;
import java.awt.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* com.apple.eawt.Application属于jdk1.8及以下mac jdk特有的api
* 在jdk9中被移除由Desktop.getDesktop().setQuitHandler等jdk9.0引入的新api替代
* 参见 https://stackoverflow.com/questions/38381824/how-can-i-use-apple-com-apple-eawt-functionality-on-java-8
*
* @author hades
* @version 10.0
* Created by hades on 2020/3/13
@ -28,10 +33,21 @@ public class MacOsAddListenerAction implements OSBasedAction {
Object quitInstance = getProxy(quitHandler, "handleQuitRequestWith", new QuitAction());
Class aboutHandler = Class.forName("com.apple.eawt.AboutHandler");
Object aboutInstance = getProxy(aboutHandler, "handleAbout", new AboutAction());
Reflect.on(Reflect.on(app).call("getApplication").get()).call("setQuitHandler", quitInstance)
Object application = Reflect.on(app).call("getApplication").get();
Reflect.on(application).call("setQuitHandler", quitInstance)
.call("setAboutHandler", aboutInstance);
} catch (ClassNotFoundException e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
// 上面的不能移除,同时要保证再jdk1.8下面能运行
// 抛出异常时 说明使用>=jdk9运行行设计器,但由于编译使用1.8构建,使用反射运行
try {
Class quitHandler = Class.forName("java.awt.desktop.QuitHandler");
Object quitInstance = getProxy(quitHandler, "handleQuitRequestWith", new QuitAction());
Class aboutHandler = Class.forName("java.awt.desktop.AboutHandler");
Object aboutInstance = getProxy(aboutHandler, "handleAbout", new AboutAction());
Reflect.on(Desktop.getDesktop()).call("setQuitHandler", quitInstance).call("setAboutHandler", aboutInstance);
} catch (ClassNotFoundException ex) {
FineLoggerFactory.getLogger().error(ex.getMessage(), ex);
}
}
}

68
designer-base/src/main/java/com/fr/design/ui/Assistant.java

@ -1,68 +0,0 @@
package com.fr.design.ui;
import com.fr.stable.StringUtils;
import com.teamdev.jxbrowser.chromium.Browser;
import com.teamdev.jxbrowser.chromium.BrowserContext;
import com.teamdev.jxbrowser.chromium.ProtocolService;
import com.teamdev.jxbrowser.chromium.URLResponse;
import javax.activation.MimetypesFileTypeMap;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* @author richie
* @version 10.0
* Created by richie on 2019-03-07
*/
public class Assistant {
public static URLResponse inputStream2Response(InputStream inputStream, String filePath) throws Exception {
URLResponse response = new URLResponse();
DataInputStream stream = new DataInputStream(inputStream);
byte[] data = new byte[stream.available()];
stream.readFully(data);
response.setData(data);
String mimeType = getMimeType(filePath);
response.getHeaders().setHeader("Content-Type", mimeType);
return response;
}
private static String getMimeType(String path) {
if (StringUtils.isBlank(path)) {
return "text/html";
}
if (path.endsWith(".html")) {
return "text/html";
}
if (path.endsWith(".css")) {
return "text/css";
}
if (path.endsWith(".js")) {
return "text/javascript";
}
if (path.endsWith(".svg")) {
return "image/svg+xml";
}
Path file = new File(path).toPath();
try {
return Files.probeContentType(file);
} catch (IOException e) {
return "text/html";
}
}
public static void setEmbProtocolHandler(Browser browser, EmbProtocolHandler handler) {
BrowserContext browserContext = browser.getContext();
ProtocolService protocolService = browserContext.getProtocolService();
// 支持读取jar包中文件的自定义协议————emb:/com/fr/design/images/bbs.png
protocolService.setProtocolHandler("emb", handler);
protocolService.setProtocolHandler("file", handler);
}
}

130
designer-base/src/main/java/com/fr/design/ui/EmbProtocolHandler.java

@ -1,130 +0,0 @@
package com.fr.design.ui;
import com.fr.base.TemplateUtils;
import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.EncodeConstants;
import com.fr.stable.StringUtils;
import com.fr.third.org.apache.commons.codec.net.URLCodec;
import com.fr.third.org.apache.commons.io.FileUtils;
import com.fr.third.org.apache.commons.io.FilenameUtils;
import com.fr.web.struct.AssembleComponent;
import com.fr.web.struct.AtomBuilder;
import com.fr.web.struct.PathGroup;
import com.fr.web.struct.category.ScriptPath;
import com.fr.web.struct.category.StylePath;
import com.teamdev.jxbrowser.chromium.ProtocolHandler;
import com.teamdev.jxbrowser.chromium.URLRequest;
import com.teamdev.jxbrowser.chromium.URLResponse;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* @author richie
* @version 10.0
* Created by richie on 2019-03-07
*/
public class EmbProtocolHandler implements ProtocolHandler {
private AssembleComponent component;
private Map<String, String> map;
public EmbProtocolHandler() {
}
public EmbProtocolHandler(AssembleComponent component) {
this.component = component;
}
public EmbProtocolHandler(AssembleComponent component, Map<String, String> map) {
this.component = component;
this.map = map;
}
public EmbProtocolHandler(Map<String, String> map) {
this.map = map;
}
@Override
public URLResponse onRequest(URLRequest req) {
InputStream inputStream = null;
try {
String path = req.getURL();
if (path.startsWith("file:")) {
String url = new URLCodec().decode(path);
String filePath = TemplateUtils.renderParameter4Tpl(url, map);
File file = new File(URI.create(filePath).getPath());
inputStream = IOUtils.readResource(file.getAbsolutePath());
String text = IOUtils.inputStream2String(inputStream, EncodeConstants.ENCODING_UTF_8);
text = TemplateUtils.renderParameter4Tpl(text, map);
return Assistant.inputStream2Response(new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)), path);
} else if (path.startsWith("emb:dynamic")) {
URLResponse response = new URLResponse();
response.setData(htmlText(map).getBytes());
response.getHeaders().setHeader("Content-Type", "text/html");
return response;
} else {
int index = path.indexOf("=");
if (index > 0) {
path = path.substring(index + 1);
} else {
path = path.substring(4);
}
inputStream = IOUtils.readResource(path);
return Assistant.inputStream2Response(inputStream, path);
}
} catch (Exception e) {
FineLoggerFactory.getLogger().info(e.getMessage());
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
}
return null;
}
private String htmlText(Map<String, String> map) {
PathGroup pathGroup = AtomBuilder.create().buildAssembleFilePath(ModernRequestClient.KEY, component);
StylePath[] stylePaths = pathGroup.toStylePathGroup();
StringBuilder styleText = new StringBuilder();
for (StylePath path : stylePaths) {
if (StringUtils.isNotBlank(path.toFilePath())) {
styleText.append("<link rel=\"stylesheet\" href=\"emb:");
styleText.append(path.toFilePath());
styleText.append("\"/>");
}
}
String result = ModernUIConstants.HTML_TPL.replaceAll("##style##", styleText.toString());
ScriptPath[] scriptPaths = pathGroup.toScriptPathGroup();
StringBuilder scriptText = new StringBuilder();
for (ScriptPath path : scriptPaths) {
if (StringUtils.isNotBlank(path.toFilePath())) {
scriptText.append("<script src=\"emb:");
scriptText.append(path.toFilePath());
scriptText.append("\"></script>");
}
}
result = result.replaceAll("##script##", scriptText.toString());
if (map != null) {
for (Map.Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
result = result.replaceAll("\\$\\{" + key + "}", value);
}
}
return result;
}
}

147
designer-base/src/main/java/com/fr/design/ui/ModernUIPane.java

@ -7,21 +7,18 @@ import com.fr.design.gui.itoolbar.UIToolbar;
import com.fr.design.i18n.Toolkit;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.web.struct.AssembleComponent;
import com.teamdev.jxbrowser.chromium.Browser;
import com.teamdev.jxbrowser.chromium.BrowserPreferences;
import com.teamdev.jxbrowser.chromium.JSValue;
import com.teamdev.jxbrowser.chromium.events.FinishLoadingEvent;
import com.teamdev.jxbrowser.chromium.events.LoadAdapter;
import com.teamdev.jxbrowser.chromium.events.LoadListener;
import com.teamdev.jxbrowser.chromium.events.ScriptContextAdapter;
import com.teamdev.jxbrowser.chromium.events.ScriptContextEvent;
import com.teamdev.jxbrowser.chromium.events.ScriptContextListener;
import com.teamdev.jxbrowser.chromium.swing.BrowserView;
import com.teamdev.jxbrowser.browser.Browser;
import com.teamdev.jxbrowser.browser.callback.InjectJsCallback;
import com.teamdev.jxbrowser.engine.Engine;
import com.teamdev.jxbrowser.engine.EngineOptions;
import com.teamdev.jxbrowser.engine.RenderingMode;
import com.teamdev.jxbrowser.js.JsObject;
import com.teamdev.jxbrowser.net.Network;
import com.teamdev.jxbrowser.net.callback.InterceptRequestCallback;
import com.teamdev.jxbrowser.view.swing.BrowserView;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Map;
/**
@ -42,9 +39,8 @@ public class ModernUIPane<T> extends BasicPane {
}
private void initialize() {
setLayout(new BorderLayout());
if (browser == null) {
setLayout(new BorderLayout());
BrowserPreferences.setChromiumSwitches("--disable-google-traffic");
if (DesignerEnvManager.getEnvManager().isOpenDebug()) {
UIToolbar toolbar = new UIToolbar();
add(toolbar, BorderLayout.NORTH);
@ -55,75 +51,67 @@ public class ModernUIPane<T> extends BasicPane {
UIButton closeButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Close_Window"));
toolbar.add(closeButton);
openDebugButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
showDebuggerDialog();
}
});
openDebugButton.addActionListener(e -> showDebuggerDialog());
reloadButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
browser.reloadIgnoringCache();
}
});
reloadButton.addActionListener(e -> browser.navigation().reloadIgnoringCache());
closeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.getWindowAncestor(ModernUIPane.this).setVisible(false);
}
});
BrowserPreferences.setChromiumSwitches("--remote-debugging-port=9222");
closeButton.addActionListener(e -> SwingUtilities.getWindowAncestor(ModernUIPane.this).setVisible(false));
initializeBrowser();
add(new BrowserView(browser), BorderLayout.CENTER);
add(BrowserView.newInstance(browser), BorderLayout.CENTER);
} else {
initializeBrowser();
add(new BrowserView(browser), BorderLayout.CENTER);
add(BrowserView.newInstance(browser), BorderLayout.CENTER);
}
}
}
private void showDebuggerDialog() {
JDialog dialog = new JDialog(SwingUtilities.getWindowAncestor(this));
Browser debugger = new Browser();
BrowserView debuggerView = new BrowserView(debugger);
Engine engine = Engine.newInstance(
EngineOptions.newBuilder(RenderingMode.HARDWARE_ACCELERATED)
.addSwitch("--disable-google-traffic")
.remoteDebuggingPort(9222).build());
Browser debugger = engine.newBrowser();
BrowserView debuggerView = BrowserView.newInstance(debugger);
dialog.add(debuggerView, BorderLayout.CENTER);
dialog.setSize(new Dimension(800, 400));
GUICoreUtils.centerWindow(dialog);
dialog.setVisible(true);
dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
debugger.loadURL(browser.getRemoteDebuggingURL());
browser.devTools().remoteDebuggingUrl().ifPresent(url -> {
debugger.navigation().loadUrl(url);
});
}
private void initializeBrowser() {
browser = new Browser();
Engine engine = Engine.newInstance(EngineOptions.newBuilder(RenderingMode.HARDWARE_ACCELERATED).addSwitch("--disable-google-traffic").build());
browser = engine.newBrowser();
// 初始化的时候,就把命名空间对象初始化好,确保window.a.b.c("a.b.c"为命名空间)对象都是初始化过的
browser.addScriptContextListener(new ScriptContextAdapter() {
@Override
public void onScriptContextCreated(ScriptContextEvent event) {
event.getBrowser().executeJavaScript(String.format(ModernUIConstants.SCRIPT_INIT_NAME_SPACE, namespace));
}
browser.set(InjectJsCallback.class, params -> {
params.frame().executeJavaScript(String.format(ModernUIConstants.SCRIPT_INIT_NAME_SPACE, namespace));
return InjectJsCallback.Response.proceed();
});
}
/**
* 转向一个新的地址相当于重新加载
*
* @param url 新的地址
*/
public void redirect(String url) {
browser.loadURL(url);
browser.navigation().loadUrl(url);
}
/**
* 转向一个新的地址相当于重新加载
*
* @param url 新的地址
* @param map 初始化参数
*/
public void redirect(String url, Map<String, String> map) {
Assistant.setEmbProtocolHandler(browser, new EmbProtocolHandler(map));
browser.loadURL(url);
Network network = browser.engine().network();
network.set(InterceptRequestCallback.class, new NxInterceptRequestCallback(network, map));
browser.navigation().loadUrl(url);
}
@Override
@ -133,19 +121,18 @@ public class ModernUIPane<T> extends BasicPane {
public void populate(final T t) {
browser.addScriptContextListener(new ScriptContextAdapter() {
@Override
public void onScriptContextCreated(ScriptContextEvent event) {
JSValue ns = event.getBrowser().executeJavaScriptAndReturnValue("window." + namespace);
ns.asObject().setProperty(variable, t);
browser.set(InjectJsCallback.class, params -> {
JsObject ns = params.frame().executeJavaScript("window." + namespace);
if (ns != null) {
ns.putProperty(variable, t);
}
return InjectJsCallback.Response.proceed();
});
}
public T update() {
JSValue jsValue = browser.executeJavaScriptAndReturnValue("window." + namespace + "." + expression);
if (jsValue.isObject()) {
return (T)jsValue.asJavaObject();
if (browser.mainFrame().isPresent()) {
return browser.mainFrame().get().executeJavaScript("window." + namespace + "." + expression);
}
return null;
}
@ -154,79 +141,89 @@ public class ModernUIPane<T> extends BasicPane {
private ModernUIPane<T> pane = new ModernUIPane<>();
public Builder<T> prepare(ScriptContextListener contextListener) {
pane.browser.addScriptContextListener(contextListener);
return this;
}
public Builder<T> prepare(LoadListener loadListener) {
pane.browser.addLoadListener(loadListener);
public Builder<T> prepare(InjectJsCallback callback) {
pane.browser.set(InjectJsCallback.class, callback);
return this;
}
/**
* 加载jar包中的资源
*
* @param path 资源路径
*/
public Builder<T> withEMB(final String path) {
Assistant.setEmbProtocolHandler(pane.browser, new EmbProtocolHandler());
pane.browser.loadURL("emb:" + path);
Network network = pane.browser.engine().network();
network.set(InterceptRequestCallback.class, new NxInterceptRequestCallback(network));
pane.browser.navigation().loadUrl("emb:" + path);
return this;
}
/**
* 加载url指向的资源
*
* @param url 文件的地址
*/
public Builder<T> withURL(final String url) {
Assistant.setEmbProtocolHandler(pane.browser, new EmbProtocolHandler());
pane.browser.loadURL(url);
Network network = pane.browser.engine().network();
network.set(InterceptRequestCallback.class, new NxInterceptRequestCallback(network));
pane.browser.navigation().loadUrl(url);
return this;
}
/**
* 加载url指向的资源
*
* @param url 文件的地址
*/
public Builder<T> withURL(final String url, Map<String, String> map) {
Assistant.setEmbProtocolHandler(pane.browser, new EmbProtocolHandler(map));
pane.browser.loadURL(url);
Network network = pane.browser.engine().network();
network.set(InterceptRequestCallback.class, new NxInterceptRequestCallback(network, map));
pane.browser.navigation().loadUrl(url);
return this;
}
/**
* 加载Atom组件
*
* @param component Atom组件
*/
public Builder<T> withComponent(AssembleComponent component) {
Assistant.setEmbProtocolHandler(pane.browser, new EmbProtocolHandler(component));
pane.browser.loadURL("emb:dynamic");
Network network = pane.browser.engine().network();
network.set(InterceptRequestCallback.class, new NxComplexInterceptRequestCallback(network, component));
pane.browser.navigation().loadUrl("emb:dynamic");
return this;
}
/**
* 加载Atom组件
*
* @param component Atom组件
*/
public Builder<T> withComponent(AssembleComponent component, Map<String, String> map) {
Assistant.setEmbProtocolHandler(pane.browser, new EmbProtocolHandler(component, map));
pane.browser.loadURL("emb:dynamic");
Network network = pane.browser.engine().network();
network.set(InterceptRequestCallback.class, new NxComplexInterceptRequestCallback(network, component, map));
pane.browser.navigation().loadUrl("emb:dynamic");
return this;
}
/**
* 加载html文本内容
*
* @param html 要加载html文本内容
*/
public Builder<T> withHTML(String html) {
Assistant.setEmbProtocolHandler(pane.browser, new EmbProtocolHandler());
pane.browser.loadHTML(html);
Network network = pane.browser.engine().network();
network.set(InterceptRequestCallback.class, new NxInterceptRequestCallback(network));
pane.browser.mainFrame().ifPresent(frame -> {
frame.loadHtml(html);
});
return this;
}
/**
* 设置该前端页面做数据交换所使用的对象
*
* @param namespace 对象名
*/
public Builder<T> namespace(String namespace) {
@ -236,6 +233,7 @@ public class ModernUIPane<T> extends BasicPane {
/**
* java端往js端传数据时使用的变量名字
*
* @param name 变量的名字
*/
public Builder<T> variable(String name) {
@ -245,6 +243,7 @@ public class ModernUIPane<T> extends BasicPane {
/**
* js端往java端传数据时执行的函数表达式
*
* @param expression 函数表达式
*/
public Builder<T> expression(String expression) {

85
designer-base/src/main/java/com/fr/design/ui/NxComplexInterceptRequestCallback.java

@ -0,0 +1,85 @@
package com.fr.design.ui;
import com.fr.general.IOUtils;
import com.fr.stable.StringUtils;
import com.fr.web.struct.AssembleComponent;
import com.fr.web.struct.AtomBuilder;
import com.fr.web.struct.PathGroup;
import com.fr.web.struct.category.ScriptPath;
import com.fr.web.struct.category.StylePath;
import com.teamdev.jxbrowser.net.Network;
import com.teamdev.jxbrowser.net.UrlRequest;
import com.teamdev.jxbrowser.net.callback.InterceptRequestCallback;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* @author richie
* @version 10.0
* Created by richie on 2020/3/25
*/
public class NxComplexInterceptRequestCallback extends NxInterceptRequestCallback {
private AssembleComponent component;
public NxComplexInterceptRequestCallback(Network network, AssembleComponent component) {
super(network);
this.component = component;
}
public NxComplexInterceptRequestCallback(Network network, AssembleComponent component, Map<String, String> map) {
super(network, map);
this.component = component;
}
@Override
protected Response next(UrlRequest urlRequest, String path) {
if (path.startsWith("emb:dynamic")) {
String text = htmlText(map);
return InterceptRequestCallback.Response.intercept(generateBasicUrlRequestJob(urlRequest, "text/html", text.getBytes(StandardCharsets.UTF_8)));
} else {
int index = path.indexOf("=");
if (index > 0) {
path = path.substring(index + 1);
} else {
path = path.substring(4);
}
InputStream inputStream = IOUtils.readResource(path);
return InterceptRequestCallback.Response.intercept(generateBasicUrlRequestJob(urlRequest, getMimeType(path), IOUtils.inputStream2Bytes(inputStream)));
}
}
private String htmlText(Map<String, String> map) {
PathGroup pathGroup = AtomBuilder.create().buildAssembleFilePath(ModernRequestClient.KEY, component);
StylePath[] stylePaths = pathGroup.toStylePathGroup();
StringBuilder styleText = new StringBuilder();
for (StylePath path : stylePaths) {
if (StringUtils.isNotBlank(path.toFilePath())) {
styleText.append("<link rel=\"stylesheet\" href=\"emb:");
styleText.append(path.toFilePath());
styleText.append("\"/>");
}
}
String result = ModernUIConstants.HTML_TPL.replaceAll("##style##", styleText.toString());
ScriptPath[] scriptPaths = pathGroup.toScriptPathGroup();
StringBuilder scriptText = new StringBuilder();
for (ScriptPath path : scriptPaths) {
if (StringUtils.isNotBlank(path.toFilePath())) {
scriptText.append("<script src=\"emb:");
scriptText.append(path.toFilePath());
scriptText.append("\"></script>");
}
}
result = result.replaceAll("##script##", scriptText.toString());
if (map != null) {
for (Map.Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
result = result.replaceAll("\\$\\{" + key + "}", value);
}
}
return result;
}
}

134
designer-base/src/main/java/com/fr/design/ui/NxInterceptRequestCallback.java

@ -0,0 +1,134 @@
package com.fr.design.ui;
import com.fr.base.TemplateUtils;
import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.ArrayUtils;
import com.fr.stable.EncodeConstants;
import com.fr.stable.StringUtils;
import com.fr.third.org.apache.commons.codec.net.URLCodec;
import com.teamdev.jxbrowser.net.HttpHeader;
import com.teamdev.jxbrowser.net.HttpStatus;
import com.teamdev.jxbrowser.net.Network;
import com.teamdev.jxbrowser.net.UrlRequest;
import com.teamdev.jxbrowser.net.UrlRequestJob;
import com.teamdev.jxbrowser.net.callback.InterceptRequestCallback;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
/**
* @author richie
* @version 10.0
* Created by richie on 2020/3/25
*/
public class NxInterceptRequestCallback implements InterceptRequestCallback {
Network network;
Map<String, String> map;
public NxInterceptRequestCallback(Network network) {
this.network = network;
}
public NxInterceptRequestCallback(Network network, Map<String, String> map) {
this.network = network;
this.map = map;
}
@Override
public Response on(Params params) {
UrlRequest urlRequest = params.urlRequest();
String path = urlRequest.url();
if (path.startsWith("file:")) {
Optional<UrlRequestJob> optional = generateFileProtocolUrlRequestJob(urlRequest, path);
if (optional.isPresent()) {
return InterceptRequestCallback.Response.intercept(optional.get());
}
} else {
return next(urlRequest, path);
}
return Response.proceed();
}
Response next(UrlRequest urlRequest, String path) {
return Response.proceed();
}
private Optional<UrlRequestJob> generateFileProtocolUrlRequestJob(UrlRequest urlRequest, String path) {
try {
String url = new URLCodec().decode(path);
String filePath = TemplateUtils.renderParameter4Tpl(url, map);
File file = new File(URI.create(filePath).getPath());
InputStream inputStream = IOUtils.readResource(file.getAbsolutePath());
String mimeType = getMimeType(path);
byte[] bytes;
if (isPlainText(mimeType)) {
String text = IOUtils.inputStream2String(inputStream, EncodeConstants.ENCODING_UTF_8);
text = TemplateUtils.renderParameter4Tpl(text, map);
bytes = text.getBytes(StandardCharsets.UTF_8);
} else {
bytes = IOUtils.inputStream2Bytes(inputStream);
}
return Optional.of(generateBasicUrlRequestJob(urlRequest, mimeType, bytes));
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
return Optional.empty();
}
private boolean isPlainText(String mimeType) {
return ArrayUtils.contains(new String[]{"text/html", "text/javascript", "text/css"}, mimeType);
}
UrlRequestJob generateBasicUrlRequestJob(UrlRequest urlRequest, String mimeType, byte[] bytes) {
UrlRequestJob.Options options = UrlRequestJob.Options
.newBuilder(urlRequest.id(), HttpStatus.OK)
.addHttpHeader(HttpHeader.of("Content-Type", mimeType))
.build();
UrlRequestJob urlRequestJob = network.newUrlRequestJob(options);
urlRequestJob.write(bytes);
urlRequestJob.complete();
return urlRequestJob;
}
String getMimeType(String path) {
if (StringUtils.isBlank(path)) {
return "text/html";
}
if (path.endsWith(".html")) {
return "text/html";
}
if (path.endsWith(".css")) {
return "text/css";
}
if (path.endsWith(".js")) {
return "text/javascript";
}
if (path.endsWith(".svg")) {
return "image/svg+xml";
}
if (path.endsWith(".png")) {
return "image/png";
}
if (path.endsWith(".jpeg")) {
return "image/jpeg";
}
if (path.endsWith(".gif")) {
return "image/gif";
}
Path file = new File(path).toPath();
try {
return Files.probeContentType(file);
} catch (IOException e) {
return "text/html";
}
}
}

230
designer-base/src/main/java/com/fr/design/upm/UpmBridge.java

@ -6,6 +6,7 @@ import com.fr.config.ServerPreferenceConfig;
import com.fr.decision.webservice.v10.plugin.helper.category.impl.UpmResourceLoader;
import com.fr.design.bridge.exec.JSBridge;
import com.fr.design.bridge.exec.JSCallback;
import com.fr.design.bridge.exec.JSExecutor;
import com.fr.design.extra.PluginOperateUtils;
import com.fr.design.extra.PluginUtils;
import com.fr.design.extra.exe.GetInstalledPluginsExecutor;
@ -28,10 +29,8 @@ import com.fr.log.FineLoggerFactory;
import com.fr.plugin.context.PluginMarker;
import com.fr.stable.ArrayUtils;
import com.fr.stable.StringUtils;
import com.teamdev.jxbrowser.chromium.Browser;
import com.teamdev.jxbrowser.chromium.JSArray;
import com.teamdev.jxbrowser.chromium.JSFunction;
import com.teamdev.jxbrowser.chromium.JSObject;
import com.teamdev.jxbrowser.js.JsAccessible;
import com.teamdev.jxbrowser.js.JsObject;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
@ -52,42 +51,45 @@ import java.util.concurrent.RunnableFuture;
*/
public class UpmBridge {
public static UpmBridge getBridge(Browser browser) {
return new UpmBridge(browser);
public static UpmBridge getBridge() {
return new UpmBridge();
}
private JSObject window;
private UpmBridge(Browser browser) {
this.window = browser.executeJavaScriptAndReturnValue("window").asObject();
private UpmBridge() {
}
/**
* 更新插件管理中心资源文件这个方法仅仅是为了语义上的作用更新
*
* @param callback 安装完成后的回调函数
*/
@JSBridge
public void update(final JSFunction callback) {
callback.invoke(window, "start", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Start"));
@JsAccessible
public void update(final JsObject callback) {
callback.call(JSExecutor.CALLBACK_FUNCTION_NAME, "start", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Start"));
try {
UpmResourceLoader.INSTANCE.download();
UpmResourceLoader.INSTANCE.install();
callback.invoke(window, "success", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Success"));
callback.call(JSExecutor.CALLBACK_FUNCTION_NAME, "success", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Success"));
EventDispatcher.fire(DownloadEvent.UPDATE, "success");
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
callback.invoke(window, "error", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Error"));
callback.call(JSExecutor.CALLBACK_FUNCTION_NAME, "error", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Error"));
}
}
/**
* 下载并安装插件管理中心的资源文件
*
* @param callback 安装完成后的回调函数
*/
@JSBridge
public void startDownload(final JSFunction callback) {
callback.invoke(window, "start", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Start"));
new SwingWorker<Void, Void>(){
@JsAccessible
public void startDownload(final JsObject callback) {
callback.call(JSExecutor.CALLBACK_FUNCTION_NAME, "start", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Start"));
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
UpmResourceLoader.INSTANCE.download();
@ -99,10 +101,10 @@ public class UpmBridge {
protected void done() {
try {
get();
callback.invoke(window, "success", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Success"));
callback.call(JSExecutor.CALLBACK_FUNCTION_NAME, "success", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Success"));
EventDispatcher.fire(DownloadEvent.SUCCESS, "success");
} catch (Exception e) {
callback.invoke(window, "error", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Error"));
callback.call(JSExecutor.CALLBACK_FUNCTION_NAME, "error", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Error"));
FineLoggerFactory.getLogger().error(e.getMessage(), e);
EventDispatcher.fire(DownloadEvent.ERROR, "error");
}
@ -112,37 +114,44 @@ public class UpmBridge {
/**
* 获取upm的版本信息
*
* @return 版本信息
*/
@JSBridge
@JsAccessible
public String getVersion() {
return ServerPreferenceConfig.getInstance().getOptimizedUPMVersion();
}
@JSBridge
@JsAccessible
public String i18nText(String key) {
return Toolkit.i18nText(key);
}
@JSBridge
@JsAccessible
public void closeWindow() {
UpmFinder.closeWindow();
}
@JSBridge
@JsAccessible
public boolean isDesigner() {
return true;
}
@JSBridge
public void getPackInfo(final JSFunction callback) {
callback.invoke(window, StringUtils.EMPTY);
@JsAccessible
public void getPackInfo(final JsObject callback) {
callback.call(JSExecutor.CALLBACK_FUNCTION_NAME, StringUtils.EMPTY);
}
@JSBridge
public void getPluginPrefix(final JSFunction callback) {
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(window, callback)), new GetPluginPrefixExecutor());
@JsAccessible
public void getPluginPrefix(final JsObject callback) {
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(callback)), new GetPluginPrefixExecutor());
task.execute();
}
@ -152,8 +161,9 @@ public class UpmBridge {
* @param callback 回调函数
*/
@JSBridge
public void getPluginCategories(final JSFunction callback) {
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(window, callback)), new GetPluginCategoriesExecutor());
@JsAccessible
public void getPluginCategories(final JsObject callback) {
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(callback)), new GetPluginCategoriesExecutor());
task.execute();
}
@ -164,8 +174,9 @@ public class UpmBridge {
* @param callback 回调函数
*/
@JSBridge
public void getPluginFromStoreNew(String info, final JSFunction callback) {
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(window, callback)), new GetPluginFromStoreExecutor(new JSONObject(info)));
@JsAccessible
public void getPluginFromStoreNew(String info, final JsObject callback) {
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(callback)), new GetPluginFromStoreExecutor(new JSONObject(info)));
task.execute();
}
@ -173,8 +184,9 @@ public class UpmBridge {
* 已安装插件检查更新
*/
@JSBridge
public void readUpdateOnline(final JSFunction callback) {
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(window, callback)), new ReadUpdateOnlineExecutor());
@JsAccessible
public void readUpdateOnline(final JsObject callback) {
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(callback)), new ReadUpdateOnlineExecutor());
task.execute();
}
@ -182,8 +194,9 @@ public class UpmBridge {
* 获取已经安装的插件的数组
*/
@JSBridge
public void getInstalledPlugins(final JSFunction callback) {
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(window, callback)), new GetInstalledPluginsExecutor());
@JsAccessible
public void getInstalledPlugins(final JsObject callback) {
UpmTaskWorker<Void> task = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(callback)), new GetInstalledPluginsExecutor());
task.execute();
}
@ -193,29 +206,36 @@ public class UpmBridge {
* @param pluginIDs 插件集合
*/
@JSBridge
public void updatePluginOnline(Object pluginIDs, final JSFunction callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback));
@JsAccessible
public void updatePluginOnline(JsObject pluginIDs, final JsObject callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(callback));
List<PluginMarker> pluginMarkerList = new ArrayList<>();
if (pluginIDs instanceof String) {
pluginMarkerList.add(PluginUtils.createPluginMarker(pluginIDs.toString()));
} else if (pluginIDs instanceof JSArray) {
JSArray pluginInfos = (JSArray) pluginIDs;
for (int i = 0, len = pluginInfos.length(); i < len; i++) {
String value = pluginInfos.get(i).asString().getValue();
pluginMarkerList.add(PluginUtils.createPluginMarker(value));
}
for (String key : pluginIDs.propertyNames()) {
pluginIDs.property(key).ifPresent(v -> {
pluginMarkerList.add(PluginUtils.createPluginMarker(GeneralUtils.objectToString(v)));
});
}
PluginOperateUtils.updatePluginOnline(pluginMarkerList, jsCallback);
}
@JSBridge
@JsAccessible
public void updatePluginOnline(String pluginID, final JsObject callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(callback));
List<PluginMarker> pluginMarkerList = new ArrayList<>();
pluginMarkerList.add(PluginUtils.createPluginMarker(pluginID));
PluginOperateUtils.updatePluginOnline(pluginMarkerList, jsCallback);
}
/**
* 搜索在线插件
*
* @param keyword 关键字
*/
@JSBridge
public void searchPlugin(String keyword, final JSFunction callback) {
UpmTaskWorker<Void> worker = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(window, callback)), new SearchOnlineExecutor(keyword));
@JsAccessible
public void searchPlugin(String keyword, final JsObject callback) {
UpmTaskWorker<Void> worker = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(callback)), new SearchOnlineExecutor(keyword));
worker.execute();
}
@ -225,8 +245,9 @@ public class UpmBridge {
* @param filePath 插件包的路径
*/
@JSBridge
public void installPluginFromDisk(final String filePath, final JSFunction callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback));
@JsAccessible
public void installPluginFromDisk(final String filePath, final JsObject callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(callback));
File file = new File(filePath);
PluginOperateUtils.installPluginFromDisk(file, jsCallback);
}
@ -237,8 +258,9 @@ public class UpmBridge {
* @param pluginInfo 插件信息
*/
@JSBridge
public void uninstallPlugin(final String pluginInfo, final boolean isForce, final JSFunction callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback));
@JsAccessible
public void uninstallPlugin(final String pluginInfo, final boolean isForce, final JsObject callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(callback));
PluginOperateUtils.uninstallPlugin(pluginInfo, isForce, jsCallback);
}
@ -249,8 +271,9 @@ public class UpmBridge {
* @param callback 回调函数
*/
@JSBridge
public void installPluginOnline(final String pluginInfo, final JSFunction callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback));
@JsAccessible
public void installPluginOnline(final String pluginInfo, final JsObject callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(callback));
PluginMarker pluginMarker = PluginUtils.createPluginMarker(pluginInfo);
PluginOperateUtils.installPluginOnline(pluginMarker, jsCallback);
}
@ -260,8 +283,10 @@ public class UpmBridge {
*
* @param filePath 插件包的路径
*/
public void updatePluginFromDisk(String filePath, final JSFunction callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback));
@JSBridge
@JsAccessible
public void updatePluginFromDisk(String filePath, final JsObject callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(callback));
File file = new File(filePath);
PluginOperateUtils.updatePluginFromDisk(file, jsCallback);
}
@ -272,8 +297,9 @@ public class UpmBridge {
* @param pluginID 插件ID
*/
@JSBridge
public void setPluginActive(String pluginID, final JSFunction callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback));
@JsAccessible
public void setPluginActive(String pluginID, final JsObject callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(callback));
PluginOperateUtils.setPluginActive(pluginID, jsCallback);
}
@ -283,6 +309,7 @@ public class UpmBridge {
* @return 选择的文件的路径
*/
@JSBridge
@JsAccessible
public String showFileChooser() {
return showFileChooserWithFilter(StringUtils.EMPTY, StringUtils.EMPTY);
}
@ -296,6 +323,7 @@ public class UpmBridge {
* 这里换用JFileChooser会卡死,不知道为什么
*/
@JSBridge
@JsAccessible
public String showFileChooserWithFilter(final String des, final String filter) {
RunnableFuture<String> future = new FutureTask<>(new Callable<String>() {
@Override
@ -318,7 +346,7 @@ public class UpmBridge {
try {
return future.get();
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
return null;
}
@ -331,31 +359,60 @@ public class UpmBridge {
* @return 选择的文件的路径
*/
@JSBridge
public String showFileChooserWithFilters(final String des, final Object args) {
RunnableFuture<String> future = new FutureTask<>(new Callable<String>() {
@Override
public String call() {
JFileChooser fileChooser = new JFileChooser();
List<String> filterList = new ArrayList<>();
if (args instanceof String) {
filterList.add(GeneralUtils.objectToString(args));
} else if (args instanceof JSArray) {
JSArray array = (JSArray)args;
for (int i = 0, len = array.length(); i < len; i ++) {
filterList.add(array.get(i).getStringValue());
}
}
String[] filters = filterList.toArray(new String[0]);
if (ArrayUtils.isNotEmpty(filters)) {
FileNameExtensionFilter filter = new FileNameExtensionFilter(des, UpmUtils.findMatchedExtension(filters));
fileChooser.setFileFilter(filter);
}
int result = fileChooser.showOpenDialog(UpmFinder.getDialog());
if (result == JFileChooser.APPROVE_OPTION) {
return fileChooser.getSelectedFile().getAbsolutePath();
}
return null;
@JsAccessible
public String showFileChooserWithFilters(final String des, final String args) {
RunnableFuture<String> future = new FutureTask<>(() -> {
JFileChooser fileChooser = new JFileChooser();
List<String> filterList = new ArrayList<>();
filterList.add(args);
String[] filters = filterList.toArray(new String[0]);
if (ArrayUtils.isNotEmpty(filters)) {
FileNameExtensionFilter filter = new FileNameExtensionFilter(des, UpmUtils.findMatchedExtension(filters));
fileChooser.setFileFilter(filter);
}
int result = fileChooser.showOpenDialog(UpmFinder.getDialog());
if (result == JFileChooser.APPROVE_OPTION) {
return fileChooser.getSelectedFile().getAbsolutePath();
}
return null;
});
SwingUtilities.invokeLater(future);
try {
return future.get();
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
return null;
}
/**
* 选择文件对话框
*
* @param des 过滤文件描述
* @param args 文件的后缀
* @return 选择的文件的路径
*/
@JSBridge
@JsAccessible
public String showFileChooserWithFilters(final String des, final JsObject args) {
RunnableFuture<String> future = new FutureTask<>(() -> {
JFileChooser fileChooser = new JFileChooser();
List<String> filterList = new ArrayList<>();
for (String key : args.propertyNames()) {
args.property(key).ifPresent(v -> {
filterList.add(GeneralUtils.objectToString(v));
});
}
String[] filters = filterList.toArray(new String[0]);
if (ArrayUtils.isNotEmpty(filters)) {
FileNameExtensionFilter filter = new FileNameExtensionFilter(des, UpmUtils.findMatchedExtension(filters));
fileChooser.setFileFilter(filter);
}
int result = fileChooser.showOpenDialog(UpmFinder.getDialog());
if (result == JFileChooser.APPROVE_OPTION) {
return fileChooser.getSelectedFile().getAbsolutePath();
}
return null;
});
SwingUtilities.invokeLater(future);
try {
@ -372,7 +429,8 @@ public class UpmBridge {
* 获取系统登录的用户名
*/
@JSBridge
public String getLoginInfo(final JSFunction callback) {
@JsAccessible
public String getLoginInfo(final JsObject callback) {
registerLoginInfo(callback);
return MarketConfig.getInstance().getBbsUsername();
}
@ -383,8 +441,9 @@ public class UpmBridge {
* @param callback 回调函数
*/
@JSBridge
public void registerLoginInfo(final JSFunction callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback));
@JsAccessible
public void registerLoginInfo(final JsObject callback) {
JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(callback));
String username = MarketConfig.getInstance().getBbsUsername();
if (StringUtils.isEmpty(username)) {
jsCallback.execute(StringUtils.EMPTY);
@ -404,14 +463,16 @@ public class UpmBridge {
* @param callback 回调函数
*/
@JSBridge
public void defaultLogin(String username, String password, final JSFunction callback) {
UpmTaskWorker<Void> worker = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(window, callback)), new PluginLoginExecutor(username, password));
@JsAccessible
public void defaultLogin(String username, String password, final JsObject callback) {
UpmTaskWorker<Void> worker = new UpmTaskWorker<>(new JSCallback(UpmBrowserExecutor.create(callback)), new PluginLoginExecutor(username, password));
worker.execute();
}
/**
* 清除用户信息
*/
@JsAccessible
public void clearUserInfo() {
MarketConfig.getInstance().setInShowBBsName(StringUtils.EMPTY);
FinePassportManager.getInstance().logout();
@ -422,6 +483,7 @@ public class UpmBridge {
* 打开论坛消息界面
*/
@JSBridge
@JsAccessible
public void getPriviteMessage() {
try {
String loginUrl = CloudCenter.getInstance().acquireUrlByKind("bbs.default");
@ -435,6 +497,7 @@ public class UpmBridge {
* 忘记密码
*/
@JSBridge
@JsAccessible
public void forgetHref() {
try {
Desktop.getDesktop().browse(new URI(CloudCenter.getInstance().acquireUrlByKind("bbs.reset")));
@ -447,6 +510,7 @@ public class UpmBridge {
* 立即注册
*/
@JSBridge
@JsAccessible
public void registerHref() {
try {
Desktop.getDesktop().browse(new URI(CloudCenter.getInstance().acquireUrlByKind("bbs.register")));
@ -457,9 +521,11 @@ public class UpmBridge {
/**
* 使用系统浏览器打开网页
*
* @param url 要打开的网页
*/
@JSBridge
@JsAccessible
public void openShopUrlAtWebBrowser(String url) {
if (Desktop.isDesktopSupported()) {
try {

2
designer-base/src/main/java/com/fr/design/upm/UpmFinder.java

@ -58,7 +58,7 @@ public class UpmFinder {
public static void showUPMDialog() {
boolean flag = true;
try {
Class.forName("com.teamdev.jxbrowser.chromium.Browser");
Class.forName("com.teamdev.jxbrowser.browser.Browser");
} catch (ClassNotFoundException e) {
flag = false;
}

15
designer-base/src/main/java/com/fr/design/upm/UpmShowPane.java

@ -6,9 +6,8 @@ import com.fr.design.upm.event.DownloadEvent;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
import com.teamdev.jxbrowser.chromium.JSValue;
import com.teamdev.jxbrowser.chromium.events.ScriptContextAdapter;
import com.teamdev.jxbrowser.chromium.events.ScriptContextEvent;
import com.teamdev.jxbrowser.browser.callback.InjectJsCallback;
import com.teamdev.jxbrowser.js.JsObject;
import java.awt.*;
@ -32,12 +31,10 @@ public class UpmShowPane extends BasicPane {
// 先屏蔽掉这个判断,后续可能修改交互
// if (UpmFinder.checkUPMResourcesExist()) {
modernUIPane = new ModernUIPane.Builder<>()
.prepare(new ScriptContextAdapter() {
@Override
public void onScriptContextCreated(ScriptContextEvent event) {
JSValue window = event.getBrowser().executeJavaScriptAndReturnValue("window");
window.asObject().setProperty("PluginHelper", UpmBridge.getBridge(event.getBrowser()));
}
.prepare(params -> {
JsObject window = params.frame().executeJavaScript("window");
window.putProperty("PluginHelper", UpmBridge.getBridge());
return InjectJsCallback.Response.proceed();
})
.withURL(UpmFinder.getMainResourcePath(), UpmUtils.renderMap())
.build();

15
designer-base/src/main/java/com/fr/design/upm/exec/UpmBrowserExecutor.java

@ -1,8 +1,7 @@
package com.fr.design.upm.exec;
import com.fr.design.bridge.exec.JSExecutor;
import com.teamdev.jxbrowser.chromium.JSFunction;
import com.teamdev.jxbrowser.chromium.JSObject;
import com.teamdev.jxbrowser.js.JsObject;
/**
* @author richie
@ -11,20 +10,18 @@ import com.teamdev.jxbrowser.chromium.JSObject;
*/
public class UpmBrowserExecutor implements JSExecutor {
public static UpmBrowserExecutor create(JSObject window, JSFunction callback) {
return new UpmBrowserExecutor(window, callback);
public static UpmBrowserExecutor create(JsObject callback) {
return new UpmBrowserExecutor(callback);
}
private JSObject window;
private JSFunction callback;
private JsObject callback;
private UpmBrowserExecutor(JSObject window, JSFunction callback) {
this.window = window;
private UpmBrowserExecutor(JsObject callback) {
this.callback = callback;
}
@Override
public void executor(String newValue) {
callback.invoke(window, newValue);
callback.call(JSExecutor.CALLBACK_FUNCTION_NAME, newValue);
}
}

200
designer-base/src/main/java/com/fr/design/utils/AWTUtilities.java

@ -0,0 +1,200 @@
package com.fr.design.utils;
import sun.awt.SunToolkit;
import java.awt.*;
/**
* 适配jdk10之后被移除的 com.sun.awt.AWTUtilities
* 参照 https://github.com/frohoff/jdk8u-dev-jdk/blob/master/src/share/classes/com/sun/awt/AWTUtilities.java中实现
*
* @author hades
* @version 10.0
* Created by hades on 2020/5/29
*/
public class AWTUtilities {
/**
* @param window the window to set the shape to
* @param shape the shape to set to the window
*
*/
public static void setWindowShape(Window window, Shape shape) {
if (window == null) {
throw new NullPointerException("The window argument should not be null.");
}
window.setShape(shape);
}
/**
*
*
* @param window the window to set the shape to
* @param opaque whether the window must be opaque (true),
* or translucent (false)
*
*/
public static void setWindowOpaque(Window window, boolean opaque) {
if (window == null) {
throw new NullPointerException("The window argument should not be null.");
}
if (!opaque && !isTranslucencySupported(Translucency.PERPIXEL_TRANSLUCENT)) {
throw new UnsupportedOperationException("The PERPIXEL_TRANSLUCENT translucency kind is not supported");
}
Color color = window.getBackground();
if (color == null) {
color = new Color(0, 0, 0, 0);
}
window.setBackground(new Color(color.getRed(), color.getGreen(), color.getBlue(), opaque ? 255 : 0));
}
public static enum Translucency {
/**
* Represents support in the underlying system for windows each pixel
* of which is guaranteed to be either completely opaque, with
* an alpha value of 1.0, or completely transparent, with an alpha
* value of 0.0.
*/
PERPIXEL_TRANSPARENT,
/**
* Represents support in the underlying system for windows all of
* the pixels of which have the same alpha value between or including
* 0.0 and 1.0.
*/
TRANSLUCENT,
/**
* Represents support in the underlying system for windows that
* contain or might contain pixels with arbitrary alpha values
* between and including 0.0 and 1.0.
*/
PERPIXEL_TRANSLUCENT;
}
/**
* Returns whether the given level of translucency is supported by
* the underlying system.
*
* Note that this method may sometimes return the value
* indicating that the particular level is supported, but
* the native windowing system may still not support the
* given level of translucency (due to the bugs in
* the windowing system).
*
* @param translucencyKind a kind of translucency support
* (either PERPIXEL_TRANSPARENT,
* TRANSLUCENT, or PERPIXEL_TRANSLUCENT)
* @return whether the given translucency kind is supported
*/
private static boolean isTranslucencySupported(Translucency translucencyKind) {
switch (translucencyKind) {
case PERPIXEL_TRANSPARENT:
return isWindowShapingSupported();
case TRANSLUCENT:
return isWindowOpacitySupported();
case PERPIXEL_TRANSLUCENT:
return isWindowTranslucencySupported();
}
return false;
}
/**
* Returns whether the windowing system supports changing the opacity
* value of top-level windows.
* Note that this method may sometimes return true, but the native
* windowing system may still not support the concept of
* translucency (due to the bugs in the windowing system).
*/
private static boolean isWindowOpacitySupported() {
Toolkit curToolkit = Toolkit.getDefaultToolkit();
if (!(curToolkit instanceof SunToolkit)) {
return false;
}
return ((SunToolkit)curToolkit).isWindowOpacitySupported();
}
/**
* Returns whether the windowing system supports changing the shape
* of top-level windows.
* Note that this method may sometimes return true, but the native
* windowing system may still not support the concept of
* shaping (due to the bugs in the windowing system).
*/
private static boolean isWindowShapingSupported() {
Toolkit curToolkit = Toolkit.getDefaultToolkit();
if (!(curToolkit instanceof SunToolkit)) {
return false;
}
return ((SunToolkit)curToolkit).isWindowShapingSupported();
}
private static boolean isWindowTranslucencySupported() {
/*
* Per-pixel alpha is supported if all the conditions are TRUE:
* 1. The toolkit is a sort of SunToolkit
* 2. The toolkit supports translucency in general
* (isWindowTranslucencySupported())
* 3. There's at least one translucency-capable
* GraphicsConfiguration
*/
Toolkit curToolkit = Toolkit.getDefaultToolkit();
if (!(curToolkit instanceof SunToolkit)) {
return false;
}
if (!((SunToolkit)curToolkit).isWindowTranslucencySupported()) {
return false;
}
GraphicsEnvironment env =
GraphicsEnvironment.getLocalGraphicsEnvironment();
// If the default GC supports translucency return true.
// It is important to optimize the verification this way,
// see CR 6661196 for more details.
if (isTranslucencyCapable(env.getDefaultScreenDevice()
.getDefaultConfiguration()))
{
return true;
}
// ... otherwise iterate through all the GCs.
GraphicsDevice[] devices = env.getScreenDevices();
for (int i = 0; i < devices.length; i++) {
GraphicsConfiguration[] configs = devices[i].getConfigurations();
for (int j = 0; j < configs.length; j++) {
if (isTranslucencyCapable(configs[j])) {
return true;
}
}
}
return false;
}
private static boolean isTranslucencyCapable(GraphicsConfiguration gc) {
if (gc == null) {
throw new NullPointerException("The gc argument should not be null");
}
/*
return gc.isTranslucencyCapable();
*/
Toolkit curToolkit = Toolkit.getDefaultToolkit();
if (!(curToolkit instanceof SunToolkit)) {
return false;
}
return ((SunToolkit)curToolkit).isTranslucencyCapable(gc);
}
}

3
designer-base/src/main/java/com/fr/start/SplashWindow.java

@ -2,9 +2,9 @@ package com.fr.start;
import com.fr.base.BaseUtils;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.utils.AWTUtilities;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.stable.OperatingSystem;
import com.sun.awt.AWTUtilities;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
@ -41,7 +41,6 @@ public class SplashWindow extends JFrame {
this.setAlwaysOnTop(false);
this.setUndecorated(true);
AWTUtilities.setWindowOpaque(this, false);
//使窗体背景透明
if (OperatingSystem.isWindows()) {
this.setBackground(new Color(0, 0, 0, 0));

41
designer-base/src/test/java/com/fr/design/gui/icombocheckbox/UICheckListPopupTest.java

@ -0,0 +1,41 @@
package com.fr.design.gui.icombocheckbox;
import junit.framework.TestCase;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* @author hades
* @version 10.0
* Created by hades on 2020/4/3
*/
public class UICheckListPopupTest extends TestCase {
@Test
public void testGetSelectedValues() {
Object[] values = new Object[]{"a", "b", "c"};
Map<Object, Boolean> map = new TreeMap<>();
map.put("a", true);
map.put("b", false);
map.put("c", true);
List<Object> list = new ArrayList<>();
for (Map.Entry<Object, Boolean> entry : map.entrySet()) {
if (entry.getValue()) {
list.add(entry.getKey());
}
}
Object[] selectValues = list.toArray();
UICheckListPopup uiCheckListPopup1 = new UICheckListPopup(values);
uiCheckListPopup1.setSelectedValue(map);
Assert.assertArrayEquals(selectValues, uiCheckListPopup1.getSelectedValues());
UICheckListPopup uiCheckListPopup2 = new UICheckListPopup(values, false);
uiCheckListPopup2.setSelectedValue(map);
Assert.assertArrayEquals(selectValues, uiCheckListPopup2.getSelectedValues());
}
}

3
designer-chart/build.gradle

@ -0,0 +1,3 @@
dependencies {
compile project(':designer-base')
}

3
designer-form/build.gradle

@ -0,0 +1,3 @@
dependencies {
compile project(':designer-base')
}

4
designer-realize/build.gradle

@ -0,0 +1,4 @@
dependencies {
compile project(':designer-form')
compile project(':designer-chart')
}

2
designer-realize/src/main/java/com/fr/design/mainframe/alphafine/listener/ComponentHandler.java

@ -1,6 +1,6 @@
package com.fr.design.mainframe.alphafine.listener;
import com.sun.awt.AWTUtilities;
import com.fr.design.utils.AWTUtilities;
import java.awt.*;
import java.awt.event.ComponentAdapter;

29
globalConfigHook.gradle

@ -0,0 +1,29 @@
def getRootGradle() {
def currentGradle = gradle
while (currentGradle.parent) {
currentGradle = currentGradle.parent
}
return currentGradle
}
def findHookIncludedBuild() {
def rootGradle = getRootGradle()
def hookProject = rootGradle.getIncludedBuilds()
.find({ build -> build.name == 'hook' })
return hookProject
}
def findGlobalConfig() {
def hookProject = findHookIncludedBuild()
if (hookProject) {
def path = hookProject.projectDir.parent + '/globalConfig.gradle'
if (file(path).exists()) {
return path
}
}
}
def globalConfigPath = findGlobalConfig()
if (globalConfigPath) {
apply from: globalConfigPath
}

BIN
gradle/wrapper/gradle-wrapper.jar vendored

Binary file not shown.

6
gradle/wrapper/gradle-wrapper.properties vendored

@ -0,0 +1,6 @@
#Wed Apr 22 15:17:12 CST 2020
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

172
gradlew vendored

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
gradlew.bat vendored

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

4
pom.xml

@ -28,8 +28,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>

12
settings.gradle

@ -0,0 +1,12 @@
pluginManagement {
repositories {
maven {
url 'http://mvn.finedevelop.com/repository/maven-public/'
}
gradlePluginPortal()
}
}
rootProject.name = 'design'
include 'designer-base', 'designer-chart', 'designer-form', 'designer-realize'
Loading…
Cancel
Save