diff --git a/build.gradle b/build.gradle index cbc6d696c..804f1ad0f 100644 --- a/build.gradle +++ b/build.gradle @@ -60,10 +60,10 @@ allprojects { implementation 'com.fr.third:jxbrowser:6.23' implementation 'com.fr.third:jxbrowser-mac:6.23' implementation 'com.fr.third:jxbrowser-win64:6.23' - implementation 'com.fr.third:jxbrowser-v7:7.5' - implementation 'com.fr.third:jxbrowser-mac-v7:7.5' - implementation 'com.fr.third:jxbrowser-win64-v7:7.5' - implementation 'com.fr.third:jxbrowser-swing:7.5' + implementation 'com.fr.third:jxbrowser-v7:7.7' + implementation 'com.fr.third:jxbrowser-mac-v7:7.7' + implementation 'com.fr.third:jxbrowser-win64-v7:7.7' + implementation 'com.fr.third:jxbrowser-swing-v7:7.7' implementation 'com.fr.third.server:servlet-api:3.0' implementation 'org.swingexplorer:swexpl:2.0.1' implementation 'org.swingexplorer:swag:1.0' diff --git a/designer-base/src/main/java/com/fr/design/ui/ModernUIPane.java b/designer-base/src/main/java/com/fr/design/ui/ModernUIPane.java index 084820a13..8c7ed5ac5 100644 --- a/designer-base/src/main/java/com/fr/design/ui/ModernUIPane.java +++ b/designer-base/src/main/java/com/fr/design/ui/ModernUIPane.java @@ -5,8 +5,10 @@ import com.fr.design.dialog.BasicPane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.itoolbar.UIToolbar; import com.fr.design.i18n.Toolkit; +import com.fr.design.ui.compatible.BuilderDiff; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.web.struct.AssembleComponent; +import com.teamdev.jxbrowser.browser.callback.InjectJsCallback; import com.teamdev.jxbrowser.chromium.Browser; import com.teamdev.jxbrowser.chromium.BrowserType; import com.teamdev.jxbrowser.chromium.JSValue; @@ -42,6 +44,10 @@ public class ModernUIPane extends BasicPane { initialize(browserType); } + protected ModernUIPane() { + + } + private void initialize(BrowserType browserType) { if (browser == null) { setLayout(new BorderLayout()); @@ -151,7 +157,7 @@ public class ModernUIPane extends BasicPane { return null; } - public static class Builder { + public static class Builder implements BuilderDiff { private ModernUIPane pane; @@ -271,6 +277,22 @@ public class ModernUIPane extends BasicPane { return this; } + @Override + public Builder prepareForV6(ScriptContextListener contextListener) { + return prepare(contextListener); + } + + @Override + public Builder prepareForV6(LoadListener loadListener) { + return prepare(loadListener); + } + + @Override + public Builder prepareForV7(InjectJsCallback callback) { + // do nothing + return this; + } + public ModernUIPane build() { return pane; } diff --git a/designer-base/src/main/java/com/fr/design/ui/compatible/BuilderDiff.java b/designer-base/src/main/java/com/fr/design/ui/compatible/BuilderDiff.java new file mode 100644 index 000000000..33c817c94 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/ui/compatible/BuilderDiff.java @@ -0,0 +1,24 @@ +package com.fr.design.ui.compatible; + +import com.fr.design.ui.ModernUIPane; +import com.teamdev.jxbrowser.browser.callback.InjectJsCallback; +import com.teamdev.jxbrowser.chromium.events.LoadListener; +import com.teamdev.jxbrowser.chromium.events.ScriptContextListener; + +/** + * 封装jxbrwoser v6/v7的构建方式的差异 + * + * @author hades + * @version 10.0 + * Created by hades on 2021/6/13 + */ +public interface BuilderDiff { + + ModernUIPane.Builder prepareForV6(ScriptContextListener contextListener); + + ModernUIPane.Builder prepareForV6(LoadListener loadListener); + + ModernUIPane.Builder prepareForV7(InjectJsCallback callback); + + +} diff --git a/designer-base/src/main/java/com/fr/design/ui/compatible/ModernUIPaneFactory.java b/designer-base/src/main/java/com/fr/design/ui/compatible/ModernUIPaneFactory.java new file mode 100644 index 000000000..8616b647b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/ui/compatible/ModernUIPaneFactory.java @@ -0,0 +1,20 @@ +package com.fr.design.ui.compatible; + +import com.fr.design.ui.ModernUIPane; +import com.fr.stable.os.OperatingSystem; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/6/13 + */ +public class ModernUIPaneFactory { + + public static ModernUIPane.Builder modernUIPaneBuilder() { + if (OperatingSystem.isWindows()) { + return new NewModernUIPane.Builder<>(); + } else { + return new ModernUIPane.Builder<>(); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/ui/compatible/NewModernUIPane.java b/designer-base/src/main/java/com/fr/design/ui/compatible/NewModernUIPane.java new file mode 100644 index 000000000..ab883516c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/ui/compatible/NewModernUIPane.java @@ -0,0 +1,301 @@ +package com.fr.design.ui.compatible; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.itoolbar.UIToolbar; +import com.fr.design.i18n.Toolkit; +import com.fr.design.ui.ModernUIConstants; +import com.fr.design.ui.ModernUIPane; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.web.struct.AssembleComponent; +import com.teamdev.jxbrowser.browser.Browser; +import com.teamdev.jxbrowser.browser.callback.InjectJsCallback; +import com.teamdev.jxbrowser.chromium.events.LoadListener; +import com.teamdev.jxbrowser.chromium.events.ScriptContextListener; +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 java.awt.BorderLayout; +import java.awt.Dimension; +import java.util.Map; +import java.util.Optional; +import javax.swing.JDialog; +import javax.swing.SwingUtilities; +import javax.swing.WindowConstants; + +/** + * 基于v7 jxbrowser实现 + * + * @author richie + * @version 10.0 + * Created by richie on 2019-03-04 + * 用于加载html5的Swing容器,可以在设计选项设置中打开调试窗口,示例可查看:com.fr.design.ui.ModernUIPaneTest + */ +public class NewModernUIPane extends ModernUIPane { + + private Browser browser; + private String namespace = "Pool"; + private String variable = "data"; + private String expression = "update()"; + + private NewModernUIPane() { + super(); + initialize(); + } + + private void initialize() { + setLayout(new BorderLayout()); + if (browser == null) { + if (DesignerEnvManager.getEnvManager().isOpenDebug()) { + UIToolbar toolbar = new UIToolbar(); + add(toolbar, BorderLayout.NORTH); + UIButton openDebugButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Open_Debug_Window")); + toolbar.add(openDebugButton); + UIButton reloadButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Reload")); + toolbar.add(reloadButton); + UIButton closeButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Close_Window")); + toolbar.add(closeButton); + + openDebugButton.addActionListener(e -> showDebuggerDialog()); + + reloadButton.addActionListener(e -> browser.navigation().reloadIgnoringCache()); + + closeButton.addActionListener(e -> SwingUtilities.getWindowAncestor( + NewModernUIPane.this).setVisible(false)); + initializeBrowser(); + add(BrowserView.newInstance(browser), BorderLayout.CENTER); + } else { + initializeBrowser(); + add(BrowserView.newInstance(browser), BorderLayout.CENTER); + } + } + } + + private void showDebuggerDialog() { + JDialog dialog = new JDialog(SwingUtilities.getWindowAncestor(this)); + 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); + browser.devTools().remoteDebuggingUrl().ifPresent(url -> { + debugger.navigation().loadUrl(url); + }); + } + + private void initializeBrowser() { + 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.set(InjectJsCallback.class, params -> { + params.frame().executeJavaScript(String.format(ModernUIConstants.SCRIPT_INIT_NAME_SPACE, namespace)); + return InjectJsCallback.Response.proceed(); + }); + } + + /** + * 转向一个新的地址,相当于重新加载 + * + * @param url 新的地址 + */ + @Override + public void redirect(String url) { + browser.navigation().loadUrl(url); + } + + /** + * 转向一个新的地址,相当于重新加载 + * + * @param url 新的地址 + * @param map 初始化参数 + */ + @Override + public void redirect(String url, Map map) { + Network network = browser.engine().network(); + network.set(InterceptRequestCallback.class, new NxInterceptRequestCallback(network, map)); + browser.navigation().loadUrl(url); + } + + @Override + protected String title4PopupWindow() { + return "Modern"; + } + + @Override + public void populate(final T t) { + browser.set(InjectJsCallback.class, params -> { + JsObject ns = params.frame().executeJavaScript("window." + namespace); + if (ns != null) { + ns.putProperty(variable, t); + } + return InjectJsCallback.Response.proceed(); + }); + } + + @Override + public T update() { + if (browser.mainFrame().isPresent()) { + return browser.mainFrame().get().executeJavaScript("window." + namespace + "." + expression); + } + return null; + } + + public static class Builder extends ModernUIPane.Builder { + + private NewModernUIPane pane = new NewModernUIPane<>(); + + public NewModernUIPane.Builder prepare(InjectJsCallback callback) { + pane.browser.set(InjectJsCallback.class, callback); + return this; + } + + /** + * 加载jar包中的资源 + * + * @param path 资源路径 + */ + @Override + public NewModernUIPane.Builder withEMB(final String path) { + Network network = pane.browser.engine().network(); + network.set(InterceptRequestCallback.class, new NxComplexInterceptRequestCallback(network, null)); + pane.browser.navigation().loadUrl("emb:" + path); + return this; + } + + /** + * 加载url指向的资源 + * + * @param url 文件的地址 + */ + @Override + public NewModernUIPane.Builder withURL(final String url) { + Network network = pane.browser.engine().network(); + network.set(InterceptRequestCallback.class, new NxInterceptRequestCallback(network)); + pane.browser.navigation().loadUrl(url); + return this; + } + + /** + * 加载url指向的资源 + * + * @param url 文件的地址 + */ + @Override + public NewModernUIPane.Builder withURL(final String url, Map map) { + 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组件 + */ + @Override + public NewModernUIPane.Builder withComponent(AssembleComponent component) { + 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组件 + */ + @Override + public NewModernUIPane.Builder withComponent(AssembleComponent component, Map map) { + 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文本内容 + */ + @Override + public NewModernUIPane.Builder withHTML(String 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 对象名 + */ + @Override + public NewModernUIPane.Builder namespace(String namespace) { + pane.namespace = namespace; + return this; + } + + /** + * java端往js端传数据时使用的变量名字 + * + * @param name 变量的名字 + */ + @Override + public NewModernUIPane.Builder variable(String name) { + pane.variable = name; + return this; + } + + /** + * js端往java端传数据时执行的函数表达式 + * + * @param expression 函数表达式 + */ + @Override + public NewModernUIPane.Builder expression(String expression) { + pane.expression = expression; + return this; + } + + @Override + public NewModernUIPane.Builder prepareForV6(ScriptContextListener contextListener) { + // do nothing + return this; + } + + @Override + public NewModernUIPane.Builder prepareForV6(LoadListener loadListener) { + // do nothing + return this; + } + + @Override + public NewModernUIPane.Builder prepareForV7(InjectJsCallback callback) { + return prepare(callback); + } + + @Override + public NewModernUIPane build() { + return pane; + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/ui/compatible/NxComplexInterceptRequestCallback.java b/designer-base/src/main/java/com/fr/design/ui/compatible/NxComplexInterceptRequestCallback.java index 2c430bd34..f3147b652 100644 --- a/designer-base/src/main/java/com/fr/design/ui/compatible/NxComplexInterceptRequestCallback.java +++ b/designer-base/src/main/java/com/fr/design/ui/compatible/NxComplexInterceptRequestCallback.java @@ -49,6 +49,9 @@ public class NxComplexInterceptRequestCallback extends NxInterceptRequestCallbac path = path.substring(4); } InputStream inputStream = IOUtils.readResource(path); + if (inputStream == null) { + return Response.proceed(); + } return InterceptRequestCallback.Response.intercept(generateBasicUrlRequestJob(urlRequest, getMimeType(path), IOUtils.inputStream2Bytes(inputStream))); } } diff --git a/designer-base/src/main/java/com/fr/design/ui/compatible/NxInterceptRequestCallback.java b/designer-base/src/main/java/com/fr/design/ui/compatible/NxInterceptRequestCallback.java index 7b4977e77..e2ab7ad93 100644 --- a/designer-base/src/main/java/com/fr/design/ui/compatible/NxInterceptRequestCallback.java +++ b/designer-base/src/main/java/com/fr/design/ui/compatible/NxInterceptRequestCallback.java @@ -100,6 +100,11 @@ public class NxInterceptRequestCallback implements InterceptRequestCallback { } String getMimeType(String path) { + // 去除 xxx?xxx 后面部分 + int index = path.indexOf("?"); + if (index != -1) { + path = path.substring(0, path.indexOf("?")); + } if (StringUtils.isBlank(path)) { return "text/html"; } @@ -124,6 +129,15 @@ public class NxInterceptRequestCallback implements InterceptRequestCallback { if (path.endsWith(".gif")) { return "image/gif"; } + if (path.endsWith(".woff")) { + return "font/woff"; + } + if (path.endsWith(".ttf")) { + return "truetype"; + } + if (path.endsWith(".eot")) { + return "embedded-opentype"; + } Path file = new File(path).toPath(); try { return Files.probeContentType(file); diff --git a/designer-base/src/main/java/com/fr/design/upm/NewUpmBridge.java b/designer-base/src/main/java/com/fr/design/upm/NewUpmBridge.java new file mode 100644 index 000000000..a69871e7a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/upm/NewUpmBridge.java @@ -0,0 +1,502 @@ +package com.fr.design.upm; + +import com.fr.config.MarketConfig; +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.extra.PluginOperateUtils; +import com.fr.design.extra.PluginUtils; +import com.fr.design.extra.exe.GetInstalledPluginsExecutor; +import com.fr.design.extra.exe.GetPluginCategoriesExecutor; +import com.fr.design.extra.exe.GetPluginFromStoreExecutor; +import com.fr.design.extra.exe.GetPluginPrefixExecutor; +import com.fr.design.extra.exe.PluginLoginExecutor; +import com.fr.design.extra.exe.ReadUpdateOnlineExecutor; +import com.fr.design.extra.exe.SearchOnlineExecutor; +import com.fr.design.i18n.Toolkit; +import com.fr.design.upm.event.CertificateEvent; +import com.fr.design.upm.event.DownloadEvent; +import com.fr.design.upm.exec.NewUpmBrowserExecutor; +import com.fr.design.upm.task.UpmTaskWorker; +import com.fr.event.EventDispatcher; +import com.fr.general.GeneralUtils; +import com.fr.json.JSONObject; +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.js.JsAccessible; +import com.teamdev.jxbrowser.js.JsFunction; +import com.teamdev.jxbrowser.js.JsObject; + +import javax.swing.JFileChooser; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.FutureTask; +import java.util.concurrent.RunnableFuture; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-04-12 + * 桥接Java和JavaScript的类 + */ +public class NewUpmBridge extends UpmBridge { + + public static NewUpmBridge getBridge(JsObject jsObject) { + return new NewUpmBridge(jsObject); + } + + private JsObject jsObject; + + private NewUpmBridge(JsObject jsObject) { + this.jsObject = jsObject; + } + + /** + * 更新插件管理中心资源文件,这个方法仅仅是为了语义上的作用(更新) + * + * @param callback 安装完成后的回调函数 + */ + @JSBridge + @JsAccessible + public void update(final JsFunction callback) { + callback.invoke(jsObject, "start", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Start")); + try { + UpmResourceLoader.INSTANCE.download(); + UpmResourceLoader.INSTANCE.install(); + callback.invoke(jsObject, "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(jsObject, "error", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Error")); + } + } + + /** + * 下载并安装插件管理中心的资源文件 + * + * @param callback 安装完成后的回调函数 + */ + @JSBridge + @JsAccessible + public void startDownload(final JsFunction callback) { + callback.invoke(jsObject, "start", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Start")); + new SwingWorker() { + @Override + protected Void doInBackground() throws Exception { + UpmResourceLoader.INSTANCE.download(); + UpmResourceLoader.INSTANCE.install(); + return null; + } + + @Override + protected void done() { + try { + get(); + callback.invoke(jsObject, "success", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Success")); + EventDispatcher.fire(DownloadEvent.SUCCESS, "success"); + } catch (Exception e) { + callback.invoke(jsObject, "error", Toolkit.i18nText("Fine-Design_Basic_Update_Plugin_Manager_Download_Error")); + FineLoggerFactory.getLogger().error(e.getMessage(), e); + EventDispatcher.fire(DownloadEvent.ERROR, "error"); + } + } + }.execute(); + } + + /** + * 获取upm的版本信息 + * + * @return 版本信息 + */ + @JSBridge + @JsAccessible + @Override + public String getVersion() { + return super.getVersion(); + } + + @JSBridge + @JsAccessible + @Override + public String i18nText(String key) { + return super.i18nText(key); + } + + @JSBridge + @JsAccessible + @Override + public void closeWindow() { + super.closeWindow(); + } + + @JSBridge + @JsAccessible + @Override + public boolean isDesigner() { + return super.isDesigner(); + } + + @JSBridge + @JsAccessible + public void getPackInfo(final JsFunction callback) { + callback.invoke(jsObject, StringUtils.EMPTY); + } + + @JSBridge + @JsAccessible + public void getPluginPrefix(final JsFunction callback) { + UpmTaskWorker task = new UpmTaskWorker<>(new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)), new GetPluginPrefixExecutor()); + task.execute(); + } + + /** + * 在线获取插件分类 + * + * @param callback 回调函数 + */ + @JSBridge + @JsAccessible + public void getPluginCategories(final JsFunction callback) { + UpmTaskWorker task = new UpmTaskWorker<>(new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)), new GetPluginCategoriesExecutor()); + task.execute(); + } + + /** + * 根据条件获取在线插件 + * + * @param info 插件信息 + * @param callback 回调函数 + */ + @JSBridge + @JsAccessible + public void getPluginFromStoreNew(String info, final JsFunction callback) { + UpmTaskWorker task = new UpmTaskWorker<>(new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)), new GetPluginFromStoreExecutor(new JSONObject(info))); + task.execute(); + } + + /** + * 已安装插件检查更新 + */ + @JSBridge + @JsAccessible + public void readUpdateOnline(final JsFunction callback) { + UpmTaskWorker task = new UpmTaskWorker<>(new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)), new ReadUpdateOnlineExecutor()); + task.execute(); + } + + /** + * 获取已经安装的插件的数组 + */ + @JSBridge + @JsAccessible + public void getInstalledPlugins(final JsFunction callback) { + UpmTaskWorker task = new UpmTaskWorker<>(new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)), new GetInstalledPluginsExecutor()); + task.execute(); + } + + /** + * 从插件服务器上更新选中的插件 + * + * @param pluginIDs 插件集合 + */ + @JSBridge + @JsAccessible + public void updatePluginOnline(JsObject pluginIDs, final JsFunction callback) { + JSCallback jsCallback = new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)); + List pluginMarkerList = new ArrayList<>(); + 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 JsFunction callback) { + JSCallback jsCallback = new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)); + List pluginMarkerList = new ArrayList<>(); + pluginMarkerList.add(PluginUtils.createPluginMarker(pluginID)); + PluginOperateUtils.updatePluginOnline(pluginMarkerList, jsCallback); + } + + /** + * 搜索在线插件 + * + * @param keyword 关键字 + */ + @JSBridge + @JsAccessible + public void searchPlugin(String keyword, final JsFunction callback) { + UpmTaskWorker worker = new UpmTaskWorker<>(new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)), new SearchOnlineExecutor(keyword)); + worker.execute(); + } + + /** + * 从磁盘上选择插件安装包进行安装 + * + * @param filePath 插件包的路径 + */ + @JSBridge + @JsAccessible + public void installPluginFromDisk(final String filePath, final JsFunction callback) { + JSCallback jsCallback = new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)); + File file = new File(filePath); + PluginOperateUtils.installPluginFromDisk(file, jsCallback); + } + + /** + * 卸载当前选中的插件 + * + * @param pluginInfo 插件信息 + */ + @JSBridge + @JsAccessible + public void uninstallPlugin(final String pluginInfo, final boolean isForce, final JsFunction callback) { + JSCallback jsCallback = new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)); + PluginOperateUtils.uninstallPlugin(pluginInfo, isForce, jsCallback); + } + + /** + * 从插件服务器上安装插件 + * + * @param pluginInfo 插件的ID + * @param callback 回调函数 + */ + @JSBridge + @JsAccessible + public void installPluginOnline(final String pluginInfo, final JsFunction callback) { + JSCallback jsCallback = new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)); + PluginMarker pluginMarker = PluginUtils.createPluginMarker(pluginInfo); + PluginOperateUtils.installPluginOnline(pluginMarker, jsCallback); + } + + /** + * 从磁盘上选择插件安装包进行插件升级 + * + * @param filePath 插件包的路径 + */ + @JSBridge + @JsAccessible + public void updatePluginFromDisk(String filePath, final JsFunction callback) { + JSCallback jsCallback = new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)); + File file = new File(filePath); + PluginOperateUtils.updatePluginFromDisk(file, jsCallback); + } + + /** + * 修改选中的插件的活跃状态 + * + * @param pluginID 插件ID + */ + @JSBridge + @JsAccessible + public void setPluginActive(String pluginID, final JsFunction callback) { + JSCallback jsCallback = new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)); + PluginOperateUtils.setPluginActive(pluginID, jsCallback); + } + + /** + * 选择文件对话框 + * + * @return 选择的文件的路径 + */ + @JSBridge + @JsAccessible + @Override + public String showFileChooser() { + return super.showFileChooser(); + } + + /** + * 选择文件对话框 + * + * @param des 过滤文件描述 + * @param filter 文件的后缀 + * @return 选择的文件的路径 + * 这里换用JFileChooser会卡死,不知道为什么 + */ + @JSBridge + @JsAccessible + @Override + public String showFileChooserWithFilter(final String des, final String filter) { + return super.showFileChooserWithFilter(des, filter); + } + + /** + * 选择文件对话框 + * + * @param des 过滤文件描述 + * @param args 文件的后缀 + * @return 选择的文件的路径 + */ + @JSBridge + @JsAccessible + public String showFileChooserWithFilters(final String des, final String args) { + RunnableFuture future = new FutureTask<>(() -> { + JFileChooser fileChooser = new JFileChooser(); + List 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 future = new FutureTask<>(() -> { + JFileChooser fileChooser = new JFileChooser(); + List 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 { + return future.get(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return null; + } + + ////////登录相关/////// + + /** + * 获取系统登录的用户名 + */ + @JSBridge + @JsAccessible + public String getLoginInfo(final JsFunction callback) { + registerLoginInfo(callback); + return MarketConfig.getInstance().getBbsUsername(); + } + + /** + * 系统登录注册 + * + * @param callback 回调函数 + */ + @JSBridge + @JsAccessible + public void registerLoginInfo(final JsFunction callback) { + JSCallback jsCallback = new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)); + String username = MarketConfig.getInstance().getBbsUsername(); + if (StringUtils.isEmpty(username)) { + jsCallback.execute(StringUtils.EMPTY); + EventDispatcher.fire(CertificateEvent.LOGOUT, StringUtils.EMPTY); + } else { + jsCallback.execute(username); + EventDispatcher.fire(CertificateEvent.LOGIN, username); + } + } + + + /** + * 设计器端的用户登录 + * + * @param username 用户名 + * @param password 密码 + * @param callback 回调函数 + */ + @JSBridge + @JsAccessible + public void defaultLogin(String username, String password, final JsFunction callback) { + UpmTaskWorker worker = new UpmTaskWorker<>(new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)), new PluginLoginExecutor(username, password)); + worker.execute(); + } + + /** + * 清除用户信息 + */ + @JsAccessible + @JSBridge + @Override + public void clearUserInfo() { + super.clearUserInfo(); + } + + /** + * 打开论坛消息界面 + */ + @JSBridge + @JsAccessible + @Override + public void getPriviteMessage() { + super.getPriviteMessage(); + } + + /** + * 忘记密码 + */ + @JSBridge + @JsAccessible + @Override + public void forgetHref() { + super.forgetHref(); + } + + /** + * 立即注册 + */ + @JSBridge + @JsAccessible + @Override + public void registerHref() { + super.registerHref(); + } + + /** + * 使用系统浏览器打开网页 + * + * @param url 要打开的网页 + */ + @JSBridge + @JsAccessible + @Override + public void openShopUrlAtWebBrowser(String url) { + super.openShopUrlAtWebBrowser(url); + } +} diff --git a/designer-base/src/main/java/com/fr/design/upm/UpmBridge.java b/designer-base/src/main/java/com/fr/design/upm/UpmBridge.java index ad933d7d2..fb40d5434 100644 --- a/designer-base/src/main/java/com/fr/design/upm/UpmBridge.java +++ b/designer-base/src/main/java/com/fr/design/upm/UpmBridge.java @@ -66,6 +66,10 @@ public class UpmBridge { this.window = browser.executeJavaScriptAndReturnValue("window").asObject(); } + protected UpmBridge() { + + } + /** * 更新插件管理中心资源文件,这个方法仅仅是为了语义上的作用(更新) * @param callback 安装完成后的回调函数 diff --git a/designer-base/src/main/java/com/fr/design/upm/UpmFinder.java b/designer-base/src/main/java/com/fr/design/upm/UpmFinder.java index 2ea539faf..db0661b1f 100644 --- a/designer-base/src/main/java/com/fr/design/upm/UpmFinder.java +++ b/designer-base/src/main/java/com/fr/design/upm/UpmFinder.java @@ -15,6 +15,7 @@ import com.fr.event.Listener; import com.fr.general.GeneralContext; import com.fr.log.FineLoggerFactory; import com.fr.stable.StableUtils; +import com.fr.stable.os.OperatingSystem; import com.fr.workspace.Workspace; import com.fr.workspace.WorkspaceEvent; @@ -31,7 +32,7 @@ public class UpmFinder { private static final String UPM_DIR = "/upm"; private static final String MAIN_RESOURCE_PATH = UPM_DIR + "/plugin_design.html"; - private static final String JXBROWSER = "com.teamdev.jxbrowser.chromium.Browser"; + private static final String JXBROWSER = OperatingSystem.isWindows() ? "com.teamdev.jxbrowser.browser.Browser" : "com.teamdev.jxbrowser.chromium.Browser"; public static String installHome = FRContext.getCommonOperator().getWebRootPath(); diff --git a/designer-base/src/main/java/com/fr/design/upm/UpmShowPane.java b/designer-base/src/main/java/com/fr/design/upm/UpmShowPane.java index 1bc4b9e94..0384b5c29 100644 --- a/designer-base/src/main/java/com/fr/design/upm/UpmShowPane.java +++ b/designer-base/src/main/java/com/fr/design/upm/UpmShowPane.java @@ -2,14 +2,17 @@ package com.fr.design.upm; import com.fr.design.dialog.BasicPane; import com.fr.design.ui.ModernUIPane; +import com.fr.design.ui.compatible.ModernUIPaneFactory; 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.browser.callback.InjectJsCallback; import com.teamdev.jxbrowser.chromium.JSValue; import com.teamdev.jxbrowser.chromium.events.ScriptContextAdapter; import com.teamdev.jxbrowser.chromium.events.ScriptContextEvent; +import com.teamdev.jxbrowser.js.JsObject; import java.awt.*; /** @@ -29,16 +32,23 @@ public class UpmShowPane extends BasicPane { UpmShowPane() { setLayout(new BorderLayout()); -// 先屏蔽掉这个判断,后续可能修改交互 -// if (UpmFinder.checkUPMResourcesExist()) { - modernUIPane = new ModernUIPane.Builder<>() - .prepare(new ScriptContextAdapter() { + modernUIPane = ModernUIPaneFactory.modernUIPaneBuilder() + .prepareForV6(new ScriptContextAdapter() { @Override public void onScriptContextCreated(ScriptContextEvent event) { + // 6.x JSValue window = event.getBrowser().executeJavaScriptAndReturnValue("window"); window.asObject().setProperty("PluginHelper", UpmBridge.getBridge(event.getBrowser())); } }) + .prepareForV7(params -> { + // 7.x + JsObject window = params.frame().executeJavaScript("window"); + if (window != null) { + window.putProperty("PluginHelper", NewUpmBridge.getBridge(window)); + } + return InjectJsCallback.Response.proceed(); + }) .withURL(UpmFinder.getMainResourcePath(), UpmUtils.renderMap()) .build(); EventDispatcher.listen(DownloadEvent.UPDATE, new Listener() { @@ -47,23 +57,6 @@ public class UpmShowPane extends BasicPane { modernUIPane.redirect(UpmFinder.getMainResourcePath(), UpmUtils.renderMap()); } }); -// } else { -// modernUIPane = new ModernUIPane.Builder<>() -// .withComponent(WarnComponent.KEY) -// .prepare(new ScriptContextAdapter() { -// @Override -// public void onScriptContextCreated(ScriptContextEvent event) { -// JSValue window = event.getBrowser().executeJavaScriptAndReturnValue("window"); -// window.asObject().setProperty("PluginHelper", UpmBridge.getBridge(event.getBrowser())); -// } -// }).build(); -// EventDispatcher.listen(DownloadEvent.SUCCESS, new Listener() { -// @Override -// public void on(Event event, String param) { -// modernUIPane.redirect(UpmFinder.getMainResourcePath(), UpmUtils.renderMap()); -// } -// }); -// } add(modernUIPane, BorderLayout.CENTER); } } diff --git a/designer-base/src/main/java/com/fr/design/upm/exec/NewUpmBrowserExecutor.java b/designer-base/src/main/java/com/fr/design/upm/exec/NewUpmBrowserExecutor.java new file mode 100644 index 000000000..04ab5620f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/upm/exec/NewUpmBrowserExecutor.java @@ -0,0 +1,30 @@ +package com.fr.design.upm.exec; + +import com.fr.design.bridge.exec.JSExecutor; +import com.teamdev.jxbrowser.js.JsFunction; +import com.teamdev.jxbrowser.js.JsObject; + +/** + * @author richie + * @version 10.0 + * Created by richie on 2019-04-18 + */ +public class NewUpmBrowserExecutor implements JSExecutor { + + public static NewUpmBrowserExecutor create(JsObject window, JsFunction callback) { + return new NewUpmBrowserExecutor(window, callback); + } + + private final JsFunction callback; + private final JsObject window; + + private NewUpmBrowserExecutor(JsObject window, JsFunction callback) { + this.window = window; + this.callback = callback; + } + + @Override + public void executor(String newValue) { + callback.invoke(window, newValue); + } +}