From 87e10003489d0097a2c1ba1af609a4dc0c80984e Mon Sep 17 00:00:00 2001 From: hades Date: Mon, 27 Dec 2021 12:01:51 +0800 Subject: [PATCH 1/3] =?UTF-8?q?REPORT-64609=20=E7=A3=81=E7=9B=98=E7=A9=BA?= =?UTF-8?q?=E9=97=B4=E6=BB=A1=E6=97=B6=20=E4=BF=9D=E5=AD=98=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF=E9=80=A0=E6=88=90=E6=A8=A1=E6=9D=BF=E4=B8=A2=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fr/common/exception/ThrowableHandler.java | 12 ++++ .../com/fr/design/mainframe/JTemplate.java | 3 +- .../worker/save/SaveFailureHandler.java | 70 +++++++++++++++++++ .../com/fr/design/worker/save/SaveWorker.java | 7 +- 4 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 designer-base/src/main/java/com/fr/common/exception/ThrowableHandler.java create mode 100644 designer-base/src/main/java/com/fr/design/worker/save/SaveFailureHandler.java diff --git a/designer-base/src/main/java/com/fr/common/exception/ThrowableHandler.java b/designer-base/src/main/java/com/fr/common/exception/ThrowableHandler.java new file mode 100644 index 000000000..225d90e79 --- /dev/null +++ b/designer-base/src/main/java/com/fr/common/exception/ThrowableHandler.java @@ -0,0 +1,12 @@ +package com.fr.common.exception; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/12/27 + */ +public interface ThrowableHandler { + + boolean process(Throwable e); + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java index f1f72b48c..3e6ec0819 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java @@ -50,6 +50,7 @@ import com.fr.design.ui.util.UIUtil; import com.fr.design.utils.DesignUtils; import com.fr.design.worker.save.CallbackSaveWorker; import com.fr.design.worker.save.EmptyCallBackSaveWorker; +import com.fr.design.worker.save.SaveFailureHandler; import com.fr.design.write.submit.DBManipulationInWidgetEventPane; import com.fr.design.write.submit.DBManipulationPane; import com.fr.event.EventDispatcher; @@ -882,7 +883,7 @@ public abstract class JTemplate> export(); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); - JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), e.getMessage(), "Save Error", JOptionPane.ERROR_MESSAGE); + SaveFailureHandler.getInstance().process(e); return false; } this.editingFILE = editingFILE; diff --git a/designer-base/src/main/java/com/fr/design/worker/save/SaveFailureHandler.java b/designer-base/src/main/java/com/fr/design/worker/save/SaveFailureHandler.java new file mode 100644 index 000000000..31c622ab3 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/worker/save/SaveFailureHandler.java @@ -0,0 +1,70 @@ +package com.fr.design.worker.save; + +import com.fr.common.exception.ThrowableHandler; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.general.IOUtils; +import com.fr.workspace.exception.DiskSpaceFullException; +import java.awt.Frame; +import javax.swing.JOptionPane; + +/** + * @author hades + * @version 10.0 + * Created by hades on 2021/12/7 + */ +public class SaveFailureHandler implements ThrowableHandler { + + private static final SaveFailureHandler INSTANCE = new SaveFailureHandler(); + + public static SaveFailureHandler getInstance() { + return INSTANCE; + } + + @Override + public boolean process(Throwable e) { + for (Handler handler : Handler.values()) { + if (handler.process(e)) { + break; + } + } + return true; + } + + public enum Handler implements ThrowableHandler { + + FullDisk { + @Override + public boolean process(Throwable e) { + if (e.getCause() instanceof DiskSpaceFullException + || e instanceof DiskSpaceFullException + || e.getCause().getCause() instanceof DiskSpaceFullException) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine_Design_Template_Save_Failed_By_Full_Disk"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + JOptionPane.WARNING_MESSAGE, + IOUtils.readIcon("/com/fr/design/images/warnings/warning32.png")); + return true; + } + return false; + } + }, + + Other { + @Override + public boolean process(Throwable e) { + boolean minimized = (DesignerContext.getDesignerFrame().getExtendedState() & Frame.ICONIFIED ) != 0; + FineJOptionPane.showMessageDialog( + minimized ? null : DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design-Basic_Save_Failure"), + Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), + JOptionPane.ERROR_MESSAGE); + return true; + } + }; + + + + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/worker/save/SaveWorker.java b/designer-base/src/main/java/com/fr/design/worker/save/SaveWorker.java index f47a4f88e..c7a962c25 100644 --- a/designer-base/src/main/java/com/fr/design/worker/save/SaveWorker.java +++ b/designer-base/src/main/java/com/fr/design/worker/save/SaveWorker.java @@ -55,12 +55,7 @@ public class SaveWorker extends SwingWorker { } catch (Exception e) { processResult(); FineLoggerFactory.getLogger().error(e.getMessage(), e); - boolean minimized = (DesignerContext.getDesignerFrame().getExtendedState() & Frame.ICONIFIED ) != 0; - FineJOptionPane.showMessageDialog( - minimized ? null : DesignerContext.getDesignerFrame(), - Toolkit.i18nText("Fine-Design-Basic_Save_Failure"), - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), - JOptionPane.ERROR_MESSAGE); + SaveFailureHandler.getInstance().process(e); return; } processResult(); From 95dadd063a69dfbd3b5cabdf5b59cf8deefc124b Mon Sep 17 00:00:00 2001 From: hades Date: Mon, 10 Jan 2022 15:26:22 +0800 Subject: [PATCH 2/3] =?UTF-8?q?REPORT-65475=20AlphaFine=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E6=85=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../search/manager/impl/FileSearchManager.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/manager/impl/FileSearchManager.java b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/manager/impl/FileSearchManager.java index 0497828c7..327d0555c 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/manager/impl/FileSearchManager.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/alphafine/search/manager/impl/FileSearchManager.java @@ -11,10 +11,14 @@ import com.fr.design.mainframe.alphafine.cell.model.MoreModel; import com.fr.design.mainframe.alphafine.model.SearchResult; import com.fr.design.mainframe.alphafine.search.manager.fun.AlphaFineSearchProvider; import com.fr.file.filetree.FileNode; +import com.fr.file.filetree.FileNodes; import com.fr.general.ComparatorUtils; import com.fr.json.JSONObject; +import com.fr.rpc.ExceptionHandler; +import com.fr.rpc.RPCInvokerExceptionInfo; import com.fr.stable.StringUtils; import com.fr.stable.project.ProjectConstants; +import com.fr.workspace.WorkContext; /** @@ -74,7 +78,12 @@ public class FileSearchManager implements AlphaFineSearchProvider { return lessModelList; } AlphaFineHelper.checkCancel(); - fileNodes = FRContext.getFileNodes().list(ProjectConstants.REPORTLETS_NAME, AlphaFineConstants.FILE_EXTENSIONS, true); + fileNodes = WorkContext.getCurrent().get(FileNodes.class, new ExceptionHandler() { + @Override + public Object callHandler(RPCInvokerExceptionInfo exceptionInfo) { + return FRContext.getFileNodes().list(ProjectConstants.REPORTLETS_NAME, AlphaFineConstants.FILE_EXTENSIONS, true); + } + }).list(ProjectConstants.REPORTLETS_NAME, AlphaFineConstants.FILE_EXTENSIONS, true, false); isContainCpt = true; isContainFrm = true; doSearch(this.searchText); @@ -128,7 +137,12 @@ public class FileSearchManager implements AlphaFineSearchProvider { */ private void doFileContentSearch(String searchText) { if (DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().isContainFileContent()) { - FileNode[] fileNodes = FRContext.getFileNodes().filterFiles(searchText, ProjectConstants.REPORTLETS_NAME, new FileExtension[]{FileExtension.CPT, FileExtension.FRM}, true); + FileNode[] fileNodes = WorkContext.getCurrent().get(FileNodes.class, new ExceptionHandler() { + @Override + public Object callHandler(RPCInvokerExceptionInfo exceptionInfo) { + return FRContext.getFileNodes().filterFiles(searchText, ProjectConstants.REPORTLETS_NAME, new FileExtension[]{FileExtension.CPT, FileExtension.FRM}, true); + } + }).filterFiles(searchText, ProjectConstants.REPORTLETS_NAME, new FileExtension[]{FileExtension.CPT, FileExtension.FRM}, true, false); for (FileNode node : fileNodes) { FileModel model = new FileModel(node.getName(), node.getEnvPath()); if (!AlphaFineHelper.getFilterResult().contains(model) && !filterModelList.contains(model)) { From 697919f46aa1f94ca906d30ca4c9436572f61ac0 Mon Sep 17 00:00:00 2001 From: Starryi Date: Tue, 21 Dec 2021 14:59:09 +0800 Subject: [PATCH 3/3] =?UTF-8?q?REPORT-62688=20=E7=BB=84=E4=BB=B6=E5=95=86?= =?UTF-8?q?=E5=9F=8E=E9=9D=A2=E5=90=91=E9=A3=8E=E6=A0=BC=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【问题原因】 1. 设计器在线商城页面网页化 2. URL启动设计器安装主题文件 【改动思路】 同上 --- build.gradle | 4 + .../fr/design/mainframe/DesignerFrame.java | 7 + .../share/mini/MiniShopDisposingChecker.java | 37 +++ .../share/mini/MiniShopNativeTask.java | 11 + .../share/mini/MiniShopNativeTaskManager.java | 42 +++ .../FineStartupNotificationFactory.java | 33 ++ .../FineStartupNotificationProvider.java | 14 + .../Install4jStartupNotificationProvider.java | 35 +++ .../design/mainframe/FormParaWidgetPane.java | 11 +- .../config/ComponentReuseConfigManager.java | 4 + .../share/ui/online/OnlineWidgetRepoPane.java | 165 ++++++++-- .../share/ui/online/OnlineWidgetTabPane.java | 65 +++- .../installation/AsyncInstallation.java | 38 +++ .../installation/ComponentInstallation.java | 147 +++++++++ .../ComponentsPackageInstallation.java | 179 +++++++++++ .../ui/online/installation/Installation.java | 10 + .../TemplateThemeInstallation.java | 202 ++++++++++++ .../online/mini/MiniComponentShopDialog.java | 124 ++++++++ .../ui/online/mini/MiniComponentShopPane.java | 68 +++++ .../mini/bridge/ComposedNativeBridges.java | 26 ++ .../online/mini/bridge/NativeAuthBridge.java | 34 +++ .../mini/bridge/NativeBrowserBridge.java | 25 ++ .../mini/bridge/NativeProductBridge.java | 287 ++++++++++++++++++ .../online/mini/bridge/NativeTaskBridge.java | 89 ++++++ .../mainframe/share/util/OnlineShopUtils.java | 4 + .../java/com/fr/design/deeplink/DeepLink.java | 15 + .../fr/design/deeplink/DeepLinkManager.java | 133 ++++++++ .../TemplateThemeInstallationDeepLink.java | 53 ++++ .../main/java/com/fr/start/MainDesigner.java | 2 + 29 files changed, 1824 insertions(+), 40 deletions(-) create mode 100644 designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopDisposingChecker.java create mode 100644 designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTask.java create mode 100644 designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTaskManager.java create mode 100644 designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationFactory.java create mode 100644 designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationProvider.java create mode 100644 designer-base/src/main/java/com/fr/design/startup/Install4jStartupNotificationProvider.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/AsyncInstallation.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/ComponentInstallation.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/ComponentsPackageInstallation.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/Installation.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/TemplateThemeInstallation.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/MiniComponentShopDialog.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/MiniComponentShopPane.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/ComposedNativeBridges.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeAuthBridge.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeBrowserBridge.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeProductBridge.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeTaskBridge.java create mode 100644 designer-realize/src/main/java/com/fr/design/deeplink/DeepLink.java create mode 100644 designer-realize/src/main/java/com/fr/design/deeplink/DeepLinkManager.java create mode 100644 designer-realize/src/main/java/com/fr/design/deeplink/TemplateThemeInstallationDeepLink.java diff --git a/build.gradle b/build.gradle index a3892da96..ee08bdeea 100644 --- a/build.gradle +++ b/build.gradle @@ -44,6 +44,9 @@ allprojects { repositories { mavenLocal() + maven { + url 'https://maven.ej-technologies.com/repository' + } } idea { @@ -57,6 +60,7 @@ allprojects { } dependencies { + implementation 'com.install4j:install4j-runtime:8.0.4' implementation 'com.fr.third:jxbrowser:6.23' implementation 'com.fr.third:jxbrowser-mac:6.23' implementation 'com.fr.third:jxbrowser-win64:6.23' diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java index be841f79a..2534de526 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java @@ -28,6 +28,8 @@ import com.fr.design.fun.impl.AbstractTemplateTreeShortCutProvider; import com.fr.design.gui.iprogressbar.ProgressDialog; import com.fr.design.gui.iscrollbar.UIScrollBar; import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.share.mini.MiniShopDisposingChecker; +import com.fr.design.mainframe.share.mini.MiniShopNativeTaskManager; import com.fr.design.mainframe.toolbar.ToolBarMenuDock; import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; import com.fr.design.mainframe.vcs.common.VcsHelper; @@ -157,6 +159,11 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta @Override public void windowClosing(WindowEvent e) { + // 检查mini商城是否存在未结束的后台任务 + if (!MiniShopDisposingChecker.check()) { + return; + } + // 关闭前check if (!TemplateSavingChecker.check()) { return; diff --git a/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopDisposingChecker.java b/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopDisposingChecker.java new file mode 100644 index 000000000..dd76befe6 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopDisposingChecker.java @@ -0,0 +1,37 @@ +package com.fr.design.mainframe.share.mini; + +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; + +import javax.swing.JOptionPane; +import java.awt.Component; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/8 + */ +public class MiniShopDisposingChecker { + + public static boolean check() { + return check(DesignerContext.getDesignerFrame()); + } + + public static boolean check(Component optionParentComponent) { + if (MiniShopNativeTaskManager.getInstance().hasExecutingTasks()) { + int result = FineJOptionPane.showConfirmDialog( + optionParentComponent, + Toolkit.i18nText("Fine-Design_Share_Online_Mini_Shop_Close_Tip"), + "", + FineJOptionPane.YES_NO_OPTION + ); + if (result == JOptionPane.YES_OPTION) { + MiniShopNativeTaskManager.getInstance().cancelAllExecutingTasks(); + return true; + } + return false; + } + return true; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTask.java b/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTask.java new file mode 100644 index 000000000..9144f2fa0 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTask.java @@ -0,0 +1,11 @@ +package com.fr.design.mainframe.share.mini; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/8 + */ +public interface MiniShopNativeTask { + void execute(); + void cancel(); +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTaskManager.java b/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTaskManager.java new file mode 100644 index 000000000..514ff84c8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/share/mini/MiniShopNativeTaskManager.java @@ -0,0 +1,42 @@ +package com.fr.design.mainframe.share.mini; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/8 + */ +public class MiniShopNativeTaskManager { + private MiniShopNativeTaskManager() { + } + private static class HOLDER { + private static final MiniShopNativeTaskManager singleton = new MiniShopNativeTaskManager(); + } + public static MiniShopNativeTaskManager getInstance() { + return MiniShopNativeTaskManager.HOLDER.singleton; + } + + + private static final Set executingTasks = new HashSet<>(); + + public void addStartedTask(MiniShopNativeTask task) { + executingTasks.add(task); + } + + public void removeCompletedTask(MiniShopNativeTask task) { + executingTasks.remove(task); + } + + public boolean hasExecutingTasks() { + return !executingTasks.isEmpty(); + } + + public void cancelAllExecutingTasks() { + for (MiniShopNativeTask executingTask: executingTasks) { + executingTask.cancel(); + } + executingTasks.clear(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationFactory.java b/designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationFactory.java new file mode 100644 index 000000000..b303d491f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationFactory.java @@ -0,0 +1,33 @@ +package com.fr.design.startup; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/11 + */ +public class FineStartupNotificationFactory { + private static final FineStartupNotificationProvider DEFAULT = Install4jStartupNotificationProvider.getInstance(); + private static FineStartupNotificationProvider provider; + + public FineStartupNotificationFactory() { + } + + public static FineStartupNotificationProvider getNotification() { + return provider; + } + + public static void setLogger(@NotNull FineStartupNotificationProvider provider) { + FineStartupNotificationFactory.provider = provider; + } + + public static void reset() { + provider = DEFAULT; + } + + + static { + provider = DEFAULT; + } +} diff --git a/designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationProvider.java b/designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationProvider.java new file mode 100644 index 000000000..b90390a70 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/startup/FineStartupNotificationProvider.java @@ -0,0 +1,14 @@ +package com.fr.design.startup; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/11 + */ +public interface FineStartupNotificationProvider { + void registerStartupListener(Listener listener); + + interface Listener { + void startupPerformed(String parameters); + } +} diff --git a/designer-base/src/main/java/com/fr/design/startup/Install4jStartupNotificationProvider.java b/designer-base/src/main/java/com/fr/design/startup/Install4jStartupNotificationProvider.java new file mode 100644 index 000000000..dbc7be2b7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/startup/Install4jStartupNotificationProvider.java @@ -0,0 +1,35 @@ +package com.fr.design.startup; + +import com.install4j.api.launcher.StartupNotification; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/11 + */ +public class Install4jStartupNotificationProvider implements FineStartupNotificationProvider { + + private Install4jStartupNotificationProvider() { + } + private static final Install4jStartupNotificationProvider INSTANCE = new Install4jStartupNotificationProvider(); + public static Install4jStartupNotificationProvider getInstance() { + return INSTANCE; + } + + @Override + public void registerStartupListener(Listener listener) { + boolean supported = false; + try { + supported = Class.forName("com.install4j.api.launcher.StartupNotification") != null; + } catch (Throwable ignored) {} + + if (supported) { + StartupNotification.registerStartupListener(new StartupNotification.Listener() { + @Override + public void startupPerformed(String parameters) { + listener.startupPerformed(parameters); + } + }); + } + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormParaWidgetPane.java b/designer-form/src/main/java/com/fr/design/mainframe/FormParaWidgetPane.java index 7a084c2f0..85a074384 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormParaWidgetPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormParaWidgetPane.java @@ -18,6 +18,9 @@ import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.imenu.UIPopupMenu; import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.share.ui.online.OnlineWidgetRepoPane; +import com.fr.design.mainframe.share.ui.online.mini.MiniComponentShopDialog; +import com.fr.design.mainframe.share.util.OnlineShopUtils; import com.fr.design.module.DesignModuleFactory; import com.fr.design.ui.util.UIUtil; import com.fr.design.utils.gui.LayoutUtils; @@ -262,7 +265,13 @@ public class FormParaWidgetPane extends JPanel { jPanel.addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent e) { - FormWidgetDetailPane.getInstance().enterWidgetLib(); + if (OnlineShopUtils.testConnection()) { + MiniComponentShopDialog.getInstance().show(); + } else { + OnlineWidgetRepoPane.getInstance().switch2InternetErrorPane(); + FormWidgetDetailPane.getInstance().switch2Local(); + FormWidgetDetailPane.getInstance().enterWidgetLib(); + } } @Override diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/config/ComponentReuseConfigManager.java b/designer-form/src/main/java/com/fr/design/mainframe/share/config/ComponentReuseConfigManager.java index 78bc8af67..798bc359a 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/config/ComponentReuseConfigManager.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/config/ComponentReuseConfigManager.java @@ -22,6 +22,7 @@ public class ComponentReuseConfigManager { private static final String PROPERTIES_FILE_NAME = "reuse.properties"; private static final String MINI_SHOP_URL = "MINI_SHOP_URL"; + private static final String WEB_MINI_SHOP_URL = "WEB_MINI_SHOP_URL"; private static final String COMPONENT_UPLOAD_URL = "COMPONENT_UPLOAD_URL"; private static final String MARKET_LOGIN_URL = "MARKET_LOGIN_URL"; private static final String UPLOAD_REU_SUPPORT = "UPLOAD_REU_SUPPORT"; @@ -61,6 +62,9 @@ public class ComponentReuseConfigManager { return p; } + public String getWebMiniShopUrl() { + return loadAttribute(WEB_MINI_SHOP_URL, DesignerCloudURLManager.getInstance().acquireUrlByKind("component.miniShop")); + } public String getMiniShopUrl() { return loadAttribute(MINI_SHOP_URL, DesignerCloudURLManager.getInstance().acquireUrlByKind("af.reuseInfo")); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetRepoPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetRepoPane.java index b9e430fe4..b4d3bcc68 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetRepoPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetRepoPane.java @@ -1,29 +1,44 @@ package com.fr.design.mainframe.share.ui.online; import com.fr.base.BaseUtils; +import com.fr.base.Style; +import com.fr.config.constant.Constant; import com.fr.design.dialog.BasicPane; +import com.fr.design.form.util.FontTransformUtil; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.share.ui.base.LoadingPane; import com.fr.design.mainframe.share.ui.base.MouseClickListener; +import com.fr.design.mainframe.share.ui.online.mini.MiniComponentShopDialog; import com.fr.design.mainframe.share.util.OnlineShopUtils; +import com.fr.design.mainframe.theme.edit.ui.LabelUtils; import com.fr.form.share.bean.OnlineShareWidget; +import com.fr.general.FRFont; +import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; +import com.fr.stable.Constants; import com.fr.stable.StringUtils; import javax.swing.BorderFactory; +import javax.swing.BoxLayout; import javax.swing.JPanel; +import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingConstants; import javax.swing.SwingWorker; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; +import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.util.List; import java.util.concurrent.ExecutionException; @@ -35,13 +50,8 @@ public class OnlineWidgetRepoPane extends BasicPane { private static final String MARKET_URL = "https://market.fanruan.com/reuse"; private static List[] sharableWidgets; private OnlineWidgetTabPane componentTabPane; - private JPanel centerPane; private boolean isShowPackagePanel = false; - private CardLayout cardLayout; - private Status currentStatus; - - - enum Status {LOADING, DISCONNECTED, NORMAL} + private LoadableContentPane loadableContentPane; public static boolean loadWidgets() { if (sharableWidgets != null){ @@ -82,16 +92,15 @@ public class OnlineWidgetRepoPane extends BasicPane { } private void initPane() { - cardLayout = new CardLayout(); - this.setLayout(cardLayout); - this.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); - this.centerPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + this.setLayout(new BorderLayout()); + + this.loadableContentPane = new LoadableContentPane(createInternetErrorPane()); + this.loadableContentPane.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); - this.add(new LoadingPane(), Status.LOADING.name()); - this.add(this.centerPane, Status.NORMAL.name()); - this.add(createInternetErrorPane(), Status.DISCONNECTED.name()); + DisabledContentPane disabledContentPane = new DisabledContentPane(this.loadableContentPane); + this.add(disabledContentPane, BorderLayout.CENTER); - switchPane(Status.LOADING); + this.loadableContentPane.showLoading(); setContent(); } @@ -105,18 +114,15 @@ public class OnlineWidgetRepoPane extends BasicPane { } private void addCenterPane() { - this.centerPane.removeAll(); - this.centerPane.add(this.componentTabPane, BorderLayout.CENTER); - this.switchPane(Status.NORMAL); + JPanel contentPane = this.loadableContentPane.getContentPane(); + contentPane.removeAll(); + contentPane.setLayout(new BorderLayout()); + contentPane.add(this.componentTabPane, BorderLayout.CENTER); + this.loadableContentPane.showContent(); } public void switch2InternetErrorPane() { - switchPane(Status.DISCONNECTED); - } - - private void switchPane(Status status) { - this.currentStatus = status; - cardLayout.show(this, status.name()); + this.loadableContentPane.showError(); } private void synchronizedLoadingContent() { @@ -147,16 +153,18 @@ public class OnlineWidgetRepoPane extends BasicPane { if (componentTabPane != null) { componentTabPane.removeTabChangeListener(tabChangeListener); } - this.componentTabPane = new OnlineWidgetTabPane(sharableWidgets[0].toArray(new OnlineShareWidget[sharableWidgets[0].size()]), - sharableWidgets[1].toArray(new OnlineShareWidget[sharableWidgets[1].size()])); + this.componentTabPane = new OnlineWidgetTabPane( + sharableWidgets[0].toArray(new OnlineShareWidget[0]), + sharableWidgets[1].toArray(new OnlineShareWidget[0]) + ); this.componentTabPane.addTabChangeListener(tabChangeListener); } else { - switchPane(Status.DISCONNECTED); + this.loadableContentPane.showError(); } return loadWidgetsSuccess; } - private OnlineWidgetTabPane.TabChangeListener tabChangeListener = new OnlineWidgetTabPane.TabChangeListener() { + private final OnlineWidgetTabPane.TabChangeListener tabChangeListener = new OnlineWidgetTabPane.TabChangeListener() { @Override public void tabChange(int selectedIndex) { setShowPackagePanel(selectedIndex != 0); @@ -173,7 +181,7 @@ public class OnlineWidgetRepoPane extends BasicPane { private JPanel createInternetErrorPane() { JPanel panel = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 5); - UILabel imagePanel = new UILabel(BaseUtils.readIcon("/com/fr/base/images/share/internet_error.png")); + UILabel imagePanel = new UILabel(IOUtils.readIcon("/com/fr/base/images/share/internet_error.png")); imagePanel.setPreferredSize(new Dimension(240, 96)); imagePanel.setHorizontalAlignment(SwingConstants.CENTER); panel.add(imagePanel); @@ -240,4 +248,105 @@ public class OnlineWidgetRepoPane extends BasicPane { this.componentTabPane.completeEmbedFilter(); } } + + private static class LoadableContentPane extends JPanel { + private enum Status { + LOADING, + DISCONNECTED, + NORMAL + } + private final CardLayout cardLayout; + private final JPanel contentPane; + + public LoadableContentPane(JPanel errorPane) { + cardLayout = new CardLayout(); + this.setLayout(cardLayout); + + this.add(new LoadingPane(), Status.LOADING.name()); + contentPane = new JPanel(); + this.add(contentPane, Status.NORMAL.name()); + this.add(errorPane, Status.DISCONNECTED.name()); + } + + private void switchPane(Status status) { + cardLayout.show(this, status.name()); + } + + public void showLoading() { + switchPane(Status.LOADING); + } + + public void showError() { + switchPane(Status.DISCONNECTED); + } + + public void showContent() { + switchPane(Status.NORMAL); + } + + public JPanel getContentPane() { + return contentPane; + } + } + + private static class DisabledContentPane extends JPanel { + private final CardLayout cardLayout; + + public DisabledContentPane(JPanel contentPane) { + cardLayout = new CardLayout(); + this.setLayout(cardLayout); + + this.add(new MaskPane(), "Disabled"); + this.add(contentPane, "Enabled"); + + MiniComponentShopDialog.getInstance().addWindowAdapter(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + super.windowOpened(e); + setEnabled(false); + } + + @Override + public void windowClosed(WindowEvent e) { + super.windowClosed(e); + setEnabled(true); + } + }); + + setEnabled(true); + } + + @Override + public void setEnabled(boolean enabled) { + String constrains = enabled ? "Enabled" : "Disabled"; + cardLayout.show(this, constrains); + } + } + + private static class MaskPane extends JPanel { + private static final int PADDING = 30; + private final String text; + private final Style style; + public MaskPane() { + setLayout(new BorderLayout()); + + text = Toolkit.i18nText("Fine-Design_Share_Online_Repo_Pane_Forbidden_Tip"); + style = Style.getInstance(FRFont.getInstance().applyForeground(new Color(0x8F8F92))) + .deriveHorizontalAlignment(SwingConstants.CENTER) + .deriveVerticalAlignment(SwingConstants.CENTER) + .deriveTextStyle(Style.TEXTSTYLE_WRAPTEXT); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + + Graphics2D g2d = (Graphics2D) g; + g.translate(PADDING, 0); + BaseUtils.drawStringStyleInRotation(g2d, this.getWidth() - PADDING * 2, this.getHeight(), text, style, FontTransformUtil.getDesignerFontResolution()); + g.translate(-PADDING, 0); + + } + } + } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetTabPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetTabPane.java index 52ea26bc2..c7a25be00 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetTabPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/OnlineWidgetTabPane.java @@ -1,18 +1,29 @@ package com.fr.design.mainframe.share.ui.online; import com.fr.design.gui.ibutton.UITabGroup; +import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.EastRegionContainerPane; +import com.fr.design.mainframe.FormWidgetDetailPane; +import com.fr.design.mainframe.share.ComponentShareUtil; import com.fr.design.mainframe.share.collect.ComponentCollector; import com.fr.design.mainframe.share.sort.OnlineWidgetSortType; -import com.fr.design.mainframe.share.ComponentShareUtil; import com.fr.design.mainframe.share.ui.online.embed.OnlineEmbedFilterShowPane; +import com.fr.design.mainframe.share.ui.online.mini.MiniComponentShopDialog; import com.fr.design.mainframe.share.ui.online.widgetpackage.OnlineWidgetPackagesShowPane; +import com.fr.design.mainframe.share.util.OnlineShopUtils; import com.fr.form.share.bean.OnlineShareWidget; import javax.swing.BorderFactory; +import javax.swing.JButton; import javax.swing.JPanel; +import javax.swing.plaf.basic.BasicButtonUI; import java.awt.BorderLayout; import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.EventListener; import java.util.List; @@ -24,11 +35,14 @@ public class OnlineWidgetTabPane extends JPanel { private static final String COMPONENT = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Share"); private static final String COMPONENT_PACKAGE = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Share_Package"); private static final String COMPONENT_EMBED = "COMPONENT_EMBED"; + private static final int COMPONENT_PACKAGE_TAB_INDEX = 0; + private static final int COMPONENT_TAB_INDEX = 1; + private UITabGroup headGroup; private CardLayout cardLayout; private JPanel centerPane; private boolean packagePaneCreated = false; - private List tabChangeListeners; + private final List tabChangeListeners; private OnlineEmbedFilterShowPane embedFilterShowPane; public OnlineWidgetTabPane(OnlineShareWidget[] sharableWidgets, OnlineShareWidget[] sharableWidgetPackage) { @@ -44,12 +58,12 @@ public class OnlineWidgetTabPane extends JPanel { this.centerPane.add(new OnlineWidgetShowPane(sharableWidgets), COMPONENT); this.centerPane.add( embedFilterShowPane = new OnlineEmbedFilterShowPane(new OnlineWidgetShowPane(sharableWidgets, OnlineWidgetSortType.SALES)), COMPONENT_EMBED); //延迟组件包面板的初始化,防止组件面板里组件的缩略图和组件包面板里组件的缩略图一起加载 - this.headGroup = new UITabGroup(new String[]{COMPONENT, COMPONENT_PACKAGE}) { + this.headGroup = new UITabGroup(new String[]{COMPONENT_PACKAGE, COMPONENT}) { public void tabChanged(int newSelectedIndex) { for (TabChangeListener changeListener : tabChangeListeners) { changeListener.tabChange(newSelectedIndex); } - if (newSelectedIndex == 0) { + if (newSelectedIndex == COMPONENT_TAB_INDEX) { cardLayout.show(centerPane, ComponentShareUtil.needShowEmbedFilterPane() ? COMPONENT_EMBED : COMPONENT); } else { ComponentShareUtil.completeEmbedFilter(); @@ -64,15 +78,44 @@ public class OnlineWidgetTabPane extends JPanel { } }; - this.headGroup.setSelectedIndex(0); + this.headGroup.setSelectedIndex(COMPONENT_PACKAGE_TAB_INDEX); this.centerPane.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); - JPanel jPanel = FRGUIPaneFactory.createBorderLayout_S_Pane(); - jPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); - jPanel.add(headGroup, BorderLayout.CENTER); - this.add(jPanel, BorderLayout.NORTH); + JPanel fixedContentPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + fixedContentPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); + fixedContentPane.add(headGroup, BorderLayout.NORTH); + + fixedContentPane.add(createMiniShopEntryPane(), BorderLayout.CENTER); + this.add(fixedContentPane, BorderLayout.NORTH); this.add(centerPane, BorderLayout.CENTER); } + private JPanel createMiniShopEntryPane() { + JPanel container = FRGUIPaneFactory.createBorderLayout_S_Pane(); + container.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); + JButton button = new JButton(Toolkit.i18nText("Fine-Design_Share_Online_Mini_Shop_Entry_Text")); + button.setPreferredSize(new Dimension(button.getWidth(), 20)); + button.setUI(new BasicButtonUI()); + button.setOpaque(true); + button.setBackground(Color.WHITE); + button.setForeground(new Color(0x419BF9)); + button.setBorder(BorderFactory.createLineBorder(new Color(0x419BF9), 1, true)); + + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (OnlineShopUtils.testConnection()) { + MiniComponentShopDialog.getInstance().show(); + FormWidgetDetailPane.getInstance().switch2Local(); + FormWidgetDetailPane.getInstance().enterWidgetLib(); + } else { + OnlineWidgetRepoPane.getInstance().switch2InternetErrorPane(); + } + } + }); + container.add(button, BorderLayout.NORTH); + return container; + } + public void completeEmbedFilter(){ if (embedFilterShowPane!= null){ embedFilterShowPane.completeEmbedFilter(); @@ -85,8 +128,8 @@ public class OnlineWidgetTabPane extends JPanel { } } public void refreshPane() { - this.headGroup.setSelectedIndex(0); - this.cardLayout.show(centerPane, ComponentShareUtil.needShowEmbedFilterPane() ? COMPONENT_EMBED : COMPONENT); + this.headGroup.setSelectedIndex(COMPONENT_PACKAGE_TAB_INDEX); + this.cardLayout.show(centerPane, COMPONENT_PACKAGE); } public void refreshShowPaneUI(){ diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/AsyncInstallation.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/AsyncInstallation.java new file mode 100644 index 000000000..42602b865 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/AsyncInstallation.java @@ -0,0 +1,38 @@ +package com.fr.design.mainframe.share.ui.online.installation; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/5 + */ +public abstract class AsyncInstallation implements Installation { + private AsyncActionListener actionListener; + + public void setActionListener(AsyncActionListener actionListener) { + this.actionListener = actionListener; + } + + protected void notifyProgress(double value) { + if (this.actionListener != null) { + this.actionListener.onProgress(value); + } + } + protected void notifySuccess() { + if (this.actionListener != null) { + this.actionListener.onSuccess(); + } + } + protected void notifyFailed() { + if (this.actionListener != null) { + this.actionListener.onFailed(); + } + } + + public abstract void cancel(); + + public interface AsyncActionListener { + void onProgress(double value); + void onSuccess(); + void onFailed(); + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/ComponentInstallation.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/ComponentInstallation.java new file mode 100644 index 000000000..e6403e902 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/ComponentInstallation.java @@ -0,0 +1,147 @@ +package com.fr.design.mainframe.share.ui.online.installation; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.extra.Process; +import com.fr.design.login.DesignerLoginHelper; +import com.fr.design.login.DesignerLoginSource; +import com.fr.design.mainframe.share.collect.ComponentCollector; +import com.fr.design.mainframe.share.util.DownloadUtils; +import com.fr.design.mainframe.share.util.ShareComponentUtils; +import com.fr.form.share.Group; +import com.fr.form.share.bean.OnlineShareWidget; +import com.fr.form.share.group.DefaultShareGroup; +import com.fr.form.share.group.DefaultShareGroupManager; +import com.fr.form.share.utils.ShareUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; + +import javax.swing.SwingWorker; +import java.io.File; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/5 + */ +public class ComponentInstallation extends AsyncInstallation { + private final OnlineShareWidget widget; + private SwingWorker worker; + + public ComponentInstallation(OnlineShareWidget widget) { + this.widget = widget; + } + + @Override + public void install() { + if (!checkLoginStatus()) { + notifyFailed(); + return; + } + notifyProgress(0.0D); + worker = createWorker(); + worker.execute(); + } + + private SwingWorker createWorker() { + return new SwingWorker() { + + @Override + protected Boolean doInBackground() { + + String tempFilePath = fetchRemoteReuFile2TempDir(); + if (StringUtils.isEmpty(tempFilePath)) { + return false; + } + if (isCancelled()) { + return false; + } + ShareComponentUtils.checkReadMe(); + if (isCancelled()) { + return false; + } + installTempReuFile(tempFilePath); + StableUtils.deleteFile(new File(tempFilePath)); + return true; + } + + @Override + protected void done() { + boolean result = false; + try { + result = get(); + } catch (InterruptedException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + Thread.currentThread().interrupt(); + } catch (ExecutionException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + notifyProgress(0.0D); + if (result) { + notifySuccess(); + } else { + notifyFailed(); + } + } + }; + } + + private boolean checkLoginStatus() { + String userName = DesignerEnvManager.getEnvManager().getDesignerLoginUsername(); + if (StringUtils.isEmpty(userName)) { + DesignerLoginHelper.showLoginDialog(DesignerLoginSource.NORMAL); + return false; + } + return true; + } + + private String createLocalReuFilename() { + String filename = widget.getFileLoca(); + if (StringUtils.isEmpty(filename) || !filename.endsWith(".reu")) { + filename = widget.getName() + "." + widget.getUuid() + ".reu"; + } + return filename; + } + + private String fetchRemoteReuFile2TempDir() { + try { + String filename = createLocalReuFilename(); + return DownloadUtils.download(widget.getId(), filename, new Process() { + @Override + public void process(Double value) { + notifyProgress(value); + } + }); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + return null; + } + } + + private void installTempReuFile(String tempFilePath) { + File file = new File(tempFilePath); + try { + Group targetGroup = getTargetGroup(); + if (file.exists() && targetGroup.installUniqueIdModule(file)) { + ShareUtils.recordInstallTime(file.getName(), System.currentTimeMillis()); + ComponentCollector.getInstance().collectCmpDownLoad(widget.getUuid()); + } + } catch (IOException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + private Group getTargetGroup() { + return DefaultShareGroupManager.getInstance().getGroup(DefaultShareGroup.GROUP_NAME); + } + + @Override + public void cancel() { + if (worker != null) { + worker.cancel(false); + } + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/ComponentsPackageInstallation.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/ComponentsPackageInstallation.java new file mode 100644 index 000000000..56200a0c2 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/ComponentsPackageInstallation.java @@ -0,0 +1,179 @@ +package com.fr.design.mainframe.share.ui.online.installation; + +import com.fr.design.extra.Process; +import com.fr.design.mainframe.share.ui.base.ImitationProgress; +import com.fr.design.mainframe.share.util.DownloadUtils; +import com.fr.design.mainframe.share.util.InstallUtils; +import com.fr.design.mainframe.share.util.ShareComponentUtils; +import com.fr.form.share.Group; +import com.fr.form.share.bean.OnlineShareWidget; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StableUtils; +import org.jetbrains.annotations.Nullable; + +import javax.swing.SwingWorker; +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/5 + */ +public class ComponentsPackageInstallation extends AsyncInstallation { + private final OnlineShareWidget packageWidget; + private final int childrenCount; + private ImitationThread imitationThread; + private DownLoadSwingWorker worker; + + public ComponentsPackageInstallation(OnlineShareWidget packageWidget, int childrenCount) { + this.packageWidget = packageWidget; + this.childrenCount = childrenCount; + } + + @Override + public void install() { + + final Process downloadProcess = new Process() { + @Override + public void process(Double value) { + notifyProgress(0.8 * value); + } + }; + final Process installProcess = new Process() { + + @Override + public void process(Double value) { + notifyProgress(0.8 + 0.2 * value); + } + }; + + downloadProcess.process(0.0D); + + //假进度线程 + final ImitationProgress imitationProgress = new ImitationProgress(downloadProcess, childrenCount); + imitationThread = new ImitationThread(imitationProgress); + imitationThread.setName("Component-ImitationProcessThread"); + + //下载线程 + worker = new DownLoadSwingWorker(installProcess, packageWidget); + + imitationThread.start(); + worker.execute(); + } + + @Override + public void cancel() { + if (imitationThread != null) { + imitationThread.interrupt(); + } + if (worker != null) { + worker.cancel(false); + } + } + + /** + * 假进度线程 + */ + private static class ImitationThread extends Thread { + + private final ImitationProgress imitationProgress; + + public ImitationThread(ImitationProgress progress) { + imitationProgress = progress; + } + + @Override + public void run() { + imitationProgress.start(); + } + + public void complete() { + imitationProgress.completed(); + this.interrupt(); + } + + public void stopThread() { + imitationProgress.stop(); + this.interrupt(); + } + } + + private class DownLoadSwingWorker extends SwingWorker { + final Process installProcess; + final OnlineShareWidget onlineShareWidget; + + public DownLoadSwingWorker(Process installProcess, OnlineShareWidget onlineShareWidget) { + this.installProcess = installProcess; + this.onlineShareWidget = onlineShareWidget; + } + + @Override + @Nullable + protected Group doInBackground() { + final String filePath; + List failureList = new ArrayList<>(); + try { + filePath = DownloadUtils.downloadPackage(onlineShareWidget.getId(), onlineShareWidget.getName(), DownLoadSwingWorker.this::isCancelled); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + imitationThread.stopThread(); + return null; + } + if (this.isCancelled()) { + imitationThread.stopThread(); + StableUtils.deleteFile(new File(filePath)); + return null; + } + + //等待假进度线程结束 + imitationThread.complete(); + try { + imitationThread.join(); + } catch (InterruptedException ignore) { + } + + //再判断一次 + if (this.isCancelled()) { + StableUtils.deleteFile(new File(filePath)); + return null; + } + ShareComponentUtils.checkReadMe(); + //安装 + File file = new File(filePath); + installProcess.process(0.0D); + InstallUtils.InstallResult result = null; + try { + if (file.exists()) { + result = InstallUtils.installReusFile(file, System.currentTimeMillis(), failureList, installProcess); + } + } finally { + //删掉下载组件的目录 + StableUtils.deleteFile(file); + } + return result == null ? null : result.group; + } + + @Override + protected void done() { + Group group = null; + try { + group = get(); + } catch (InterruptedException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + Thread.currentThread().interrupt(); + } catch (ExecutionException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + notifyProgress(0.0D); + if (group != null) { + notifySuccess(); + } else { + notifyFailed(); + } + } + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/Installation.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/Installation.java new file mode 100644 index 000000000..3fc80a8bf --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/Installation.java @@ -0,0 +1,10 @@ +package com.fr.design.mainframe.share.ui.online.installation; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/5 + */ +public interface Installation { + void install(); +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/TemplateThemeInstallation.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/TemplateThemeInstallation.java new file mode 100644 index 000000000..f61af23d6 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/installation/TemplateThemeInstallation.java @@ -0,0 +1,202 @@ +package com.fr.design.mainframe.share.ui.online.installation; + +import com.fr.base.theme.FormTheme; +import com.fr.base.theme.FormThemeConfig; +import com.fr.base.theme.TemplateTheme; +import com.fr.base.theme.TemplateThemeConfig; +import com.fr.design.DesignerEnvManager; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.i18n.Toolkit; +import com.fr.design.login.DesignerLoginHelper; +import com.fr.design.login.DesignerLoginSource; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.share.ui.online.mini.MiniComponentShopDialog; +import com.fr.design.mainframe.share.util.DownloadUtils; +import com.fr.design.mainframe.theme.dialog.TemplateThemeUsingDialog; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; +import com.fr.transaction.CallBackAdaptor; +import com.fr.workspace.WorkContext; + +import javax.swing.JOptionPane; +import javax.swing.SwingWorker; +import java.awt.Window; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.concurrent.ExecutionException; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/5 + */ +public class TemplateThemeInstallation extends AsyncInstallation { + private final String themePath; + private SwingWorker worker; + + public TemplateThemeInstallation(String themePath) { + this.themePath = themePath; + } + + @Override + public void install() { + fetchTheme(); + } + + private void fetchTheme() { + if (!checkAuthority()) { + onThemeFetched(null); + return; + } + + worker = new SwingWorker() { + + @Override + protected FormTheme doInBackground() { + return DownloadUtils.downloadThemeFile(themePath); + } + + @Override + protected void done() { + FormTheme theme = null; + try { + theme = get(); + } catch (InterruptedException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + Thread.currentThread().interrupt(); + } catch (ExecutionException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + + onThemeFetched(theme); + } + }; + worker.execute(); + } + + private boolean checkAuthority() { + if (!WorkContext.getCurrent().isRoot()) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Share_Download_Suitable_Theme_No_Authority_Tip_Message"), + Toolkit.i18nText("Fine-Design_Share_Download_Suitable_Theme_No_Authority_Tip_Title"), + JOptionPane.WARNING_MESSAGE); + return false; + } + + String userName = DesignerEnvManager.getEnvManager().getDesignerLoginUsername(); + if (StringUtils.isEmpty(userName)) { + DesignerLoginHelper.showLoginDialog(DesignerLoginSource.NORMAL); + return false; + } + + return true; + } + + public void onThemeFetched(FormTheme theme) { + if (theme == null) { + notifyFailed(); + return; + } + saveTheme(theme); + } + + private FormTheme ensureThemeHasUniqueName(FormTheme theme, String expectedName) { + if (!FormThemeConfig.getInstance().contains(expectedName)) { + theme.setName(expectedName); + return theme; + } else { + String newName = (String) FineJOptionPane.showInputDialog( + DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Share_Rename_Suitable_Theme_Tip"), + Toolkit.i18nText("Fine-Design_Basic_Rename"), + FineJOptionPane.QUESTION_MESSAGE, null, null, + expectedName); + + return StringUtils.isEmpty(newName) ? null : ensureThemeHasUniqueName(theme, newName); + } + } + + private void saveTheme(FormTheme theme) { + final FormTheme uniqueNamedTheme = ensureThemeHasUniqueName(theme, theme.getName()); + if (uniqueNamedTheme != null) { + FormThemeConfig.getInstance().addTheme(theme, true, new CallBackAdaptor() { + @Override + public void afterCommit() { + super.afterCommit(); + onThemeSaved(uniqueNamedTheme); + } + + @Override + public void afterRollback() { + super.afterRollback(); + onThemeSaved(null); + } + }); + } else { + onThemeSaved(null); + } + } + + public void onThemeSaved(FormTheme theme) { + if (theme == null) { + notifyFailed(); + return; + } + + JTemplate currentTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (currentTemplate.getUsingTemplateThemeConfig() instanceof FormThemeConfig) { + TemplateThemeUsingDialog dialog = new TemplateThemeUsingDialog(); + dialog.addWindowListener(new UsingDialogAdapter(theme, currentTemplate)); + dialog.setVisible(true); + } else { + FineJOptionPane.showConfirmDialog( + MiniComponentShopDialog.getInstance().getContentPane(), + Toolkit.i18nText("Fine-Design_Share_Download_Suitable_Theme_Success_Tip"), + "", + FineJOptionPane.YES_NO_OPTION + ); + } + notifySuccess(); + } + + public void applyTheme(JTemplate template, final String name, Window dialog) { + TemplateThemeConfig config = template.getUsingTemplateThemeConfig(); + TemplateTheme theme = config.cachedFetch(name); + template.setTemplateTheme(theme); + dialog.repaint(); + } + + @Override + public void cancel() { + if (worker != null) { + worker.cancel(true); + } + } + + private class UsingDialogAdapter extends WindowAdapter { + private final FormTheme theme; + private final JTemplate currentFormTemplate; + + public UsingDialogAdapter(FormTheme theme, JTemplate currentFormTemplate) { + this.theme = theme; + this.currentFormTemplate = currentFormTemplate; + } + + @Override + public void windowOpened(WindowEvent e) { + super.windowOpened(e); + Window window = e.getWindow(); + int returnVal = FineJOptionPane.showConfirmDialog( + window, + Toolkit.i18nText("Fine-Design_Share_Apply_Suitable_Theme_Tip"), + Toolkit.i18nText("Fine-Design_Basic_Confirm"), + FineJOptionPane.OK_CANCEL_OPTION); + if (returnVal == JOptionPane.YES_OPTION) { + applyTheme(currentFormTemplate, theme.getName(), window); + } + window.removeWindowListener(this); + } + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/MiniComponentShopDialog.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/MiniComponentShopDialog.java new file mode 100644 index 000000000..29fbafbaf --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/MiniComponentShopDialog.java @@ -0,0 +1,124 @@ +package com.fr.design.mainframe.share.ui.online.mini; + +import com.fr.design.dialog.BasicDialog; +import com.fr.design.dialog.UIDialog; +import com.fr.design.mainframe.share.mini.MiniShopDisposingChecker; +import com.fr.general.IOUtils; + +import javax.swing.JFrame; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Window; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/4 + */ +public class MiniComponentShopDialog { + private static class HOLDER { + private static final MiniComponentShopDialog singleton = new MiniComponentShopDialog(); + } + public static MiniComponentShopDialog getInstance() { + return MiniComponentShopDialog.HOLDER.singleton; + } + + private final Set windowListeners = new HashSet<>(); + private JFrame frame; + + private JFrame createFrame() { + final JFrame frame = new JFrame(); + final MiniComponentShopPane shopPane = new MiniComponentShopPane(); + + frame.setSize(1200, 800); + frame.add(shopPane); + frame.setResizable(false); + frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + frame.addWindowListener(new WindowListener() { + @Override + public void windowOpened(WindowEvent e) { + for (WindowListener listener: windowListeners) { + listener.windowOpened(e); + } + } + + @Override + public void windowClosing(WindowEvent e) { + for (WindowListener listener : windowListeners) { + listener.windowClosing(e); + } + if (MiniShopDisposingChecker.check(frame.getContentPane())) { + e.getWindow().dispose(); + } + } + + @Override + public void windowClosed(WindowEvent e) { + for (WindowListener listener: windowListeners) { + listener.windowClosed(e); + } + getInstance().frame = null; + shopPane.dispose(); + } + + @Override + public void windowIconified(WindowEvent e) { + for (WindowListener listener: windowListeners) { + listener.windowIconified(e); + } + } + + @Override + public void windowDeiconified(WindowEvent e) { + for (WindowListener listener: windowListeners) { + listener.windowDeiconified(e); + } + } + + @Override + public void windowActivated(WindowEvent e) { + for (WindowListener listener: windowListeners) { + listener.windowActivated(e); + } + } + + @Override + public void windowDeactivated(WindowEvent e) { + for (WindowListener listener: windowListeners) { + listener.windowDeactivated(e); + } + } + }); + return frame; + } + + public void show() { + if (frame == null) { + frame = createFrame(); + } + frame.setVisible(true); + } + + public Container getContentPane() { + if (frame != null) { + return frame.getContentPane(); + } + return null; + } + + public Window getWindow() { + return frame; + } + + public void addWindowAdapter(WindowListener windowListener) { + windowListeners.add(windowListener); + if (frame != null) { + frame.removeWindowListener(windowListener); + frame.addWindowListener(windowListener); + } + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/MiniComponentShopPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/MiniComponentShopPane.java new file mode 100644 index 000000000..1fc0e24d6 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/MiniComponentShopPane.java @@ -0,0 +1,68 @@ +package com.fr.design.mainframe.share.ui.online.mini; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.mainframe.share.ui.online.mini.bridge.ComposedNativeBridges; +import com.fr.design.mainframe.share.util.OnlineShopUtils; +import com.fr.design.ui.ModernUIPane; +import com.fr.design.upm.event.CertificateEvent; +import com.fr.event.Event; +import com.fr.event.EventDispatcher; +import com.fr.event.Listener; +import com.teamdev.jxbrowser.chromium.JSObject; +import com.teamdev.jxbrowser.chromium.events.ScriptContextAdapter; +import com.teamdev.jxbrowser.chromium.events.ScriptContextEvent; + +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import java.awt.BorderLayout; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/12/20 + */ +public class MiniComponentShopPane extends JPanel { + private final ModernUIPane modernUIPane; + private final Listener loginListener; + private final Listener logoutListener; + + public MiniComponentShopPane() { + setLayout(new BorderLayout()); + DesignerEnvManager.getEnvManager().setOpenDebug(true); + modernUIPane = new ModernUIPane.Builder<>() + .withURL(OnlineShopUtils.getWebMiniShopPath()) + .prepare(new ScriptContextAdapter() { + @Override + public void onScriptContextCreated(ScriptContextEvent event) { + super.onScriptContextCreated(event); + JSObject window = event.getBrowser().executeJavaScriptAndReturnValue("window").asObject(); + window.asObject().setProperty("ShopHelper", new ComposedNativeBridges(window, JOptionPane.getFrameForComponent(MiniComponentShopPane.this))); + } + }) + .build(); + + add(modernUIPane, BorderLayout.CENTER); + + loginListener = new Listener() { + @Override + public void on(Event event, String param) { + modernUIPane.redirect(OnlineShopUtils.getWebMiniShopPath()); + } + }; + logoutListener = new Listener() { + @Override + public void on(Event event, String param) { + modernUIPane.redirect(OnlineShopUtils.getWebMiniShopPath()); + } + }; + + EventDispatcher.listen(CertificateEvent.LOGIN, loginListener); + EventDispatcher.listen(CertificateEvent.LOGOUT, logoutListener); + } + + public void dispose() { + modernUIPane.disposeBrowser(); + EventDispatcher.stopListen(loginListener); + EventDispatcher.stopListen(logoutListener); + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/ComposedNativeBridges.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/ComposedNativeBridges.java new file mode 100644 index 000000000..ea729a145 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/ComposedNativeBridges.java @@ -0,0 +1,26 @@ +package com.fr.design.mainframe.share.ui.online.mini.bridge; + +import com.teamdev.jxbrowser.chromium.JSAccessible; +import com.teamdev.jxbrowser.chromium.JSObject; + +import java.awt.Window; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/12/20 + */ +public class ComposedNativeBridges { + @JSAccessible + public final NativeBrowserBridge Browser; + @JSAccessible + public final NativeAuthBridge Auth; + @JSAccessible + public final NativeProductBridge Product; + + public ComposedNativeBridges(JSObject window, Window nativeWindow) { + this.Browser = new NativeBrowserBridge(nativeWindow); + this.Auth = new NativeAuthBridge(); + this.Product = new NativeProductBridge(window); + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeAuthBridge.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeAuthBridge.java new file mode 100644 index 000000000..a78a3b231 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeAuthBridge.java @@ -0,0 +1,34 @@ +package com.fr.design.mainframe.share.ui.online.mini.bridge; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.bridge.exec.JSBridge; +import com.fr.design.login.DesignerLoginHelper; +import com.fr.design.login.DesignerLoginSource; +import com.fr.design.mainframe.share.ui.online.mini.MiniComponentShopDialog; +import com.teamdev.jxbrowser.chromium.JSAccessible; + +import java.awt.Window; +import java.util.HashMap; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/12/20 + */ +public class NativeAuthBridge { + @JSAccessible + @JSBridge + public String getLoginUsername() { + return DesignerEnvManager.getEnvManager().getDesignerLoginUsername(); + } + + @JSAccessible + @JSBridge + public void goLogin() { + Window parentWindow = MiniComponentShopDialog.getInstance().getWindow(); + if (parentWindow != null) { + parentWindow.toFront(); + DesignerLoginHelper.showLoginDialog(DesignerLoginSource.NORMAL, new HashMap<>(), parentWindow); + } + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeBrowserBridge.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeBrowserBridge.java new file mode 100644 index 000000000..e06265874 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeBrowserBridge.java @@ -0,0 +1,25 @@ +package com.fr.design.mainframe.share.ui.online.mini.bridge; + +import com.fr.design.bridge.exec.JSBridge; +import com.teamdev.jxbrowser.chromium.JSAccessible; + +import java.awt.Window; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/12/20 + */ +public class NativeBrowserBridge { + private final Window nativeWindow; + + public NativeBrowserBridge(Window nativeWindow) { + this.nativeWindow = nativeWindow; + } + + @JSAccessible + @JSBridge + public void dispose() { + this.nativeWindow.dispose(); + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeProductBridge.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeProductBridge.java new file mode 100644 index 000000000..52379b7f8 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeProductBridge.java @@ -0,0 +1,287 @@ + +package com.fr.design.mainframe.share.ui.online.mini.bridge; + +import com.fr.design.bridge.exec.JSBridge; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.EastRegionContainerPane; +import com.fr.design.mainframe.FormWidgetDetailPane; +import com.fr.design.mainframe.share.ui.local.LocalWidgetRepoPane; +import com.fr.design.mainframe.share.ui.online.installation.AsyncInstallation; +import com.fr.design.mainframe.share.ui.online.installation.ComponentInstallation; +import com.fr.design.mainframe.share.ui.online.installation.ComponentsPackageInstallation; +import com.fr.design.mainframe.share.ui.online.installation.TemplateThemeInstallation; +import com.fr.design.mainframe.share.ui.online.mini.MiniComponentShopDialog; +import com.fr.form.share.Group; +import com.fr.form.share.SharableWidgetProvider; +import com.fr.form.share.bean.OnlineShareWidget; +import com.fr.form.share.group.DefaultShareGroupManager; +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.stable.StringUtils; +import com.teamdev.jxbrowser.chromium.JSAccessible; +import com.teamdev.jxbrowser.chromium.JSObject; + +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/12/20 + */ +public class NativeProductBridge { + private final JSObject window; + + public NativeProductBridge(JSObject window) { + this.window = window; + } + + @JSAccessible + @JSBridge + public String getDownloadedProductIds() { + Set uuidList = new HashSet<>(); + for (Group group : DefaultShareGroupManager.getInstance().getAllGroup()) { + SharableWidgetProvider[] widgetProviderList = group.getAllBindInfoList(); + for (SharableWidgetProvider widget: widgetProviderList) { + if (StringUtils.isNotEmpty(widget.getId())) { + uuidList.add(widget.getId()); + } + } + } + JSONArray array = JSONArray.create(uuidList); + return array.toString(); + } + + @JSAccessible + @JSBridge + public Object createProductDownloadTask(String json) { + return new ComponentInstallationTask(window, json); + } + + @JSAccessible + @JSBridge + public Object createProductsPackageDownloadTask(String json) { + return new ComponentsPackageInstallationTask(window, json); + } + + @JSAccessible + @JSBridge + public Object createTemplateThemeDownloadTask(String themePath) { + return new TemplateThemeInstallationTask(window, themePath); + } + + public static class ComponentInstallationTask extends NativeTaskBridge { + private final OnlineShareWidget widget; + private final ComponentInstallation action; + + public ComponentInstallationTask(JSObject window, String widgetJson) { + super(window); + + JSONObject object = new JSONObject(widgetJson); + widget = OnlineShareWidget.parseFromJSONObject(object); + action = new ComponentInstallation(widget); + action.setActionListener(new AsyncInstallation.AsyncActionListener() { + @Override + public void onProgress(double value) { + fireProgressEvent(Double.toString(value)); + } + + @Override + public void onSuccess() { + fireSuccessEvent(null); + if (!DesignerContext.getDesignerFrame().isActive()) { + LocalWidgetRepoPane.getInstance().refreshPane(); + FormWidgetDetailPane.getInstance().switch2Local(); + EastRegionContainerPane.getInstance().switchTabTo(EastRegionContainerPane.KEY_WIDGET_LIB); + } + } + + @Override + public void onFailed() { + fireFailureEvent(null); + } + }); + } + + @JSAccessible + @JSBridge + @Override + public void execute() { + super.execute(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + boolean allowedDownload = true; + if (!widget.isCompatibleWithCurrentEnv()) { + int result = FineJOptionPane.showConfirmDialog( + MiniComponentShopDialog.getInstance().getContentPane(), + Toolkit.i18nText("Fine-Design_Share_Online_Mini_Shop_Download_Incompatible_Component_Tip"), + "", + FineJOptionPane.YES_NO_OPTION + ); + allowedDownload = result == JOptionPane.YES_OPTION; + } + if (allowedDownload) { + fireStartEvent(null); + action.install(); + } else { + fireFailureEvent(null); + } + } + }); + } + + @JSAccessible + @JSBridge + @Override + public void cancel() { + super.cancel(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + action.cancel(); + } + }); + } + } + + public static class ComponentsPackageInstallationTask extends NativeTaskBridge { + + private final ComponentsPackageInstallation action; + private final OnlineShareWidget widget; + private final int childrenCount; + + public ComponentsPackageInstallationTask(JSObject window, String widgetJson) { + super(window); + JSONObject object = new JSONObject(widgetJson); + widget = OnlineShareWidget.parseFromJSONObject(object); + childrenCount = object.optInt("pkgsize", 0); + action = new ComponentsPackageInstallation(widget, childrenCount); + action.setActionListener(new AsyncInstallation.AsyncActionListener() { + @Override + public void onProgress(double value) { + fireProgressEvent(Double.toString(value)); + } + + @Override + public void onSuccess() { + fireSuccessEvent(null); + if (!DesignerContext.getDesignerFrame().isActive()) { + LocalWidgetRepoPane.getInstance().refreshPane(); + FormWidgetDetailPane.getInstance().switch2Local(); + EastRegionContainerPane.getInstance().switchTabTo(EastRegionContainerPane.KEY_WIDGET_LIB); + } + } + + @Override + public void onFailed() { + fireFailureEvent(null); + } + }); + } + + @JSAccessible + @JSBridge + @Override + public void execute() { + super.execute(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + boolean allowedDownload; + if (!widget.isCompatibleWithCurrentEnv()) { + int result = FineJOptionPane.showConfirmDialog( + MiniComponentShopDialog.getInstance().getContentPane(), + Toolkit.i18nText("Fine-Design_Share_Online_Mini_Shop_Download_Incompatible_Components_Package_Tip", childrenCount), + "", + FineJOptionPane.YES_NO_OPTION + ); + allowedDownload = result == JOptionPane.YES_OPTION; + } else { + int result = FineJOptionPane.showConfirmDialog( + MiniComponentShopDialog.getInstance().getContentPane(), + Toolkit.i18nText("Fine-Design_Share_Online_Mini_Shop_Download_Components_Package_Tip", childrenCount), + "", + FineJOptionPane.YES_NO_OPTION + ); + allowedDownload = result == JOptionPane.YES_OPTION; + } + if (allowedDownload) { + fireStartEvent(null); + action.install(); + } else { + fireFailureEvent(null); + } + } + }); + } + + @JSAccessible + @JSBridge + @Override + public void cancel() { + super.cancel(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + action.cancel(); + } + }); + } + } + + public static class TemplateThemeInstallationTask extends NativeTaskBridge { + private final TemplateThemeInstallation action; + public TemplateThemeInstallationTask(JSObject window, String themePath) { + super(window); + action = new TemplateThemeInstallation(themePath); + action.setActionListener(new AsyncInstallation.AsyncActionListener() { + @Override + public void onProgress(double value) { + fireProgressEvent(Double.toString(value)); + } + + @Override + public void onSuccess() { + fireSuccessEvent(null); + } + + @Override + public void onFailed() { + fireFailureEvent(null); + } + }); + } + + @JSAccessible + @JSBridge + @Override + public void execute() { + super.execute(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + fireStartEvent(null); + action.install(); + } + }); + } + + @JSAccessible + @JSBridge + @Override + public void cancel() { + super.cancel(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + action.cancel(); + } + }); + } + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeTaskBridge.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeTaskBridge.java new file mode 100644 index 000000000..c29fbc786 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/mini/bridge/NativeTaskBridge.java @@ -0,0 +1,89 @@ +package com.fr.design.mainframe.share.ui.online.mini.bridge; + +import com.fr.design.bridge.exec.JSBridge; +import com.fr.design.mainframe.share.mini.MiniShopNativeTask; +import com.fr.design.mainframe.share.mini.MiniShopNativeTaskManager; +import com.teamdev.jxbrowser.chromium.JSAccessible; +import com.teamdev.jxbrowser.chromium.JSFunction; +import com.teamdev.jxbrowser.chromium.JSObject; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/12/20 + */ +public class NativeTaskBridge implements MiniShopNativeTask { + + private final JSObject window; + + protected JSFunction startCb; + protected JSFunction progressCb; + protected JSFunction successCb; + protected JSFunction failureCb; + + public NativeTaskBridge(JSObject window) { + this.window = window; + } + + @JSBridge + @JSAccessible + public void setStartCallback(JSFunction cb) { + this.startCb = cb; + } + + @JSBridge + @JSAccessible + public void setProgressCallback(JSFunction cb) { + this.progressCb = cb; + } + + @JSBridge + @JSAccessible + public void setSuccessCallback(JSFunction cb) { + this.successCb = cb; + } + + @JSBridge + @JSAccessible + public void setFailureCallback(JSFunction cb) { + this.failureCb = cb; + } + + @JSBridge + @JSAccessible + @Override + public void execute() { + } + + @JSBridge + @JSAccessible + @Override + public void cancel() { + MiniShopNativeTaskManager.getInstance().removeCompletedTask(this); + } + + + protected void fireStartEvent(String event) { + MiniShopNativeTaskManager.getInstance().addStartedTask(this); + if (this.startCb != null) { + this.startCb.invoke(window, event); + } + } + protected void fireProgressEvent(String event) { + if (this.progressCb != null) { + this.progressCb.invoke(window, event); + } + } + protected void fireSuccessEvent(String event) { + MiniShopNativeTaskManager.getInstance().removeCompletedTask(this); + if (this.successCb != null) { + this.successCb.invoke(window, event); + } + } + protected void fireFailureEvent(String event) { + MiniShopNativeTaskManager.getInstance().removeCompletedTask(this); + if (this.failureCb != null) { + this.failureCb.invoke(window, event); + } + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/util/OnlineShopUtils.java b/designer-form/src/main/java/com/fr/design/mainframe/share/util/OnlineShopUtils.java index 7341d7cbb..d0fbd83d5 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/util/OnlineShopUtils.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/util/OnlineShopUtils.java @@ -42,6 +42,10 @@ public class OnlineShopUtils { } + public static String getWebMiniShopPath() { + return ComponentReuseConfigManager.getInstance().getWebMiniShopUrl(); + } + public static String getReuInfoPath() { return ComponentReuseConfigManager.getInstance().getMiniShopUrl(); } diff --git a/designer-realize/src/main/java/com/fr/design/deeplink/DeepLink.java b/designer-realize/src/main/java/com/fr/design/deeplink/DeepLink.java new file mode 100644 index 000000000..5b40c8845 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/deeplink/DeepLink.java @@ -0,0 +1,15 @@ +package com.fr.design.deeplink; + +import java.util.Map; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/6 + */ +public abstract class DeepLink { + + public abstract boolean accept(String url, String host, String path, Map params); + + public abstract void run(String url, String host, String path, Map params); +} diff --git a/designer-realize/src/main/java/com/fr/design/deeplink/DeepLinkManager.java b/designer-realize/src/main/java/com/fr/design/deeplink/DeepLinkManager.java new file mode 100644 index 000000000..b50bc2cbc --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/deeplink/DeepLinkManager.java @@ -0,0 +1,133 @@ +package com.fr.design.deeplink; + +import com.fr.design.constants.DesignerLaunchStatus; +import com.fr.design.startup.FineStartupNotificationFactory; +import com.fr.design.startup.FineStartupNotificationProvider; +import com.fr.event.Event; +import com.fr.event.EventDispatcher; +import com.fr.event.Listener; +import com.fr.event.Null; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; +import com.fr.third.org.apache.http.NameValuePair; +import com.fr.web.URLUtils; + +import javax.swing.SwingUtilities; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/6 + */ +public class DeepLinkManager { + + private DeepLinkManager(){} + private static final DeepLinkManager instance = new DeepLinkManager(); + public static DeepLinkManager getInstance(){ + return instance; + } + + private String pendingURL; + + private final List deepLinkList = new ArrayList<>(); + + private boolean isDesignerStartUpCompleted = false; + + private void register(DeepLink deepLink) { + if (deepLink != null) { + deepLinkList.add(deepLink); + } + } + + public void prepare() { + register(new TemplateThemeInstallationDeepLink()); + + FineStartupNotificationFactory.getNotification() + .registerStartupListener(new FineStartupNotificationProvider.Listener() { + @Override + public void startupPerformed(String parameters) { + if (canAcceptNewURL()) { + acceptNewURL(parameters); + if (canConsumePendingURL()) { + consumePendingURL(); + } + } + } + }); + + EventDispatcher.listen(DesignerLaunchStatus.STARTUP_COMPLETE, new Listener() { + @Override + public void on(Event event, Null param) { + isDesignerStartUpCompleted = true; + if (canConsumePendingURL()) { + consumePendingURL(); + } + } + }); + } + + private boolean canAcceptNewURL() { + return StringUtils.isEmpty(this.pendingURL); + } + + private void acceptNewURL(String url) { + this.pendingURL = url; + } + + private boolean canConsumePendingURL() { + return StringUtils.isNotEmpty(this.pendingURL) && isDesignerStartUpCompleted; + } + + private void consumePendingURL() { + String host = null; + String path = null; + Map params = new HashMap<>(); + + URL url = null; + try { + url = new URL(null, this.pendingURL, new URLStreamHandler() { + @Override + protected URLConnection openConnection(URL u) throws IOException { + return null; + } + }); + } catch (MalformedURLException ignored) {} + + if (url != null) { + host = url.getHost(); + path = url.getPath(); + + List pairs = URLUtils.parse(url.getQuery()); + for (NameValuePair pair: pairs) { + params.put(pair.getName(), pair.getValue()); + } + } + + FineLoggerFactory.getLogger().info("consume deep link: " + this.pendingURL); + performDeepLinks(this.pendingURL, host, path, params); + + this.pendingURL = null; + } + + private void performDeepLinks(String url, String host, String path, Map params) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + for (DeepLink deepLink: deepLinkList) { + if (deepLink.accept(url, host, path, params)) { + deepLink.run(url, host, path, params); + } + } + } + }); + } +} diff --git a/designer-realize/src/main/java/com/fr/design/deeplink/TemplateThemeInstallationDeepLink.java b/designer-realize/src/main/java/com/fr/design/deeplink/TemplateThemeInstallationDeepLink.java new file mode 100644 index 000000000..9c9d14669 --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/deeplink/TemplateThemeInstallationDeepLink.java @@ -0,0 +1,53 @@ +package com.fr.design.deeplink; + +import com.fr.design.mainframe.share.ui.online.installation.Installation; +import com.fr.design.mainframe.share.ui.online.installation.TemplateThemeInstallation; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.EncodeConstants; +import com.fr.stable.StringUtils; +import com.fr.third.springframework.web.util.UriUtils; + +import java.io.UnsupportedEncodingException; +import java.util.Map; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2022/1/10 + */ +public class TemplateThemeInstallationDeepLink extends DeepLink { + public TemplateThemeInstallationDeepLink() { + } + private static class Holder { + public static TemplateThemeInstallationDeepLink INSTANCE = new TemplateThemeInstallationDeepLink(); + } + public static TemplateThemeInstallationDeepLink getInstance() { + return TemplateThemeInstallationDeepLink.Holder.INSTANCE; + } + + public static final String HOST = "template_theme"; + public static final String PATH = "/add"; + public static final String FILE_KEY = "file"; + + @Override + public boolean accept(String url, String host, String path, Map params) { + return host != null && StringUtils.equals(HOST, host) + && path != null && StringUtils.equals(PATH, path) + && params != null && params.containsKey(FILE_KEY) + ; + } + + @Override + public void run(String url, String host, String path, Map params) { + String remoteFileAddress = (String) params.get(FILE_KEY); + try { + remoteFileAddress = UriUtils.decode(remoteFileAddress, EncodeConstants.ENCODING_UTF_8); + FineLoggerFactory.getLogger().info("TemplateThemeInstallationDeepLink: " + remoteFileAddress); + + Installation installation = new TemplateThemeInstallation(remoteFileAddress); + installation.install(); + } catch (UnsupportedEncodingException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } +} diff --git a/designer-realize/src/main/java/com/fr/start/MainDesigner.java b/designer-realize/src/main/java/com/fr/start/MainDesigner.java index f953df466..3e461af0a 100644 --- a/designer-realize/src/main/java/com/fr/start/MainDesigner.java +++ b/designer-realize/src/main/java/com/fr/start/MainDesigner.java @@ -11,6 +11,7 @@ import com.fr.design.actions.server.TemplateThemeManagerAction; import com.fr.design.actions.server.WidgetManagerAction; import com.fr.design.base.mode.DesignModeContext; import com.fr.design.constants.UIConstants; +import com.fr.design.deeplink.DeepLinkManager; import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.HistoryTemplateListPane; import com.fr.design.file.MutilTempalteTabPane; @@ -106,6 +107,7 @@ public class MainDesigner extends BaseDesigner { */ public static void main(String[] args) { + DeepLinkManager.getInstance().prepare(); StopWatch watch = new StopWatch(); watch.start(); DesignerLifecycleMonitorContext.getMonitor().beforeStart();