diff --git a/build.gradle b/build.gradle index 72b457c57e..268fdbc456 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,7 @@ ext { outputPath = "build" ignoreTestFailureSetting = true languageLevelSetting = 1.8 + jxBrowserVersion = '7.26' } applyGlobalConfigPathIfExist() @@ -104,8 +105,8 @@ allprojects { implementation 'com.fr.messenger:fine-messenger:' + carinaVersion implementation 'com.install4j:install4j-runtime:8.0.4' implementation 'com.fr.third:jxbrowser:6.23' - implementation 'com.fr.third:jxbrowser-v7:7.22' - implementation 'com.fr.third:jxbrowser-swing-v7:7.22' + implementation "com.fr.third:jxbrowser-v7:${jxBrowserVersion}" + implementation "com.fr.third:jxbrowser-swing-v7:${jxBrowserVersion}" implementation 'com.fr.third.server:servlet-api:3.0' implementation 'org.swingexplorer:swexpl:2.0.1' implementation 'org.swingexplorer:swag:1.0' @@ -125,21 +126,29 @@ allprojects { implementation 'com.fr.report:engine-chart:' + frDevVersion implementation 'com.fr.report:engine-i18n:' + frDevVersion implementation 'com.fr.design:design-i18n:' + frDevVersion + implementation 'com.fine.swing.ui:layout:1.0-SNAPSHOT' testImplementation 'org.easymock:easymock:3.5.1' testImplementation 'org.powermock:powermock-module-junit4:1.7.1' testImplementation 'org.powermock:powermock-api-easymock:1.7.1' + testImplementation 'org.powermock:powermock-api-mockito2:1.7.4' testImplementation 'junit:junit:4.12' } - if (OperatingSystem.current().isMacOsX()) { + // 目前开发工程适配 mac_x64, mac_aarch64, windows_x64 + if (OperatingSystem.current().isMacOsX() && "aarch64".equals(System.getProperty("os.arch"))) { + dependencies { + // jxbrowser 6.23不支持M1,因此没有本地库,但是6.23jar还是需要留着,用来兼容 + implementation "com.fr.third:jxbrowser-mac-arm-v7:${jxBrowserVersion}" + } + } else if (OperatingSystem.current().isMacOsX()) { dependencies { implementation 'com.fr.third:jxbrowser-mac:6.23' - implementation 'com.fr.third:jxbrowser-mac-v7:7.22' + implementation "com.fr.third:jxbrowser-mac-v7:${jxBrowserVersion}" } } else if (OperatingSystem.current().isWindows()) { dependencies { implementation 'com.fr.third:jxbrowser-win64:6.23' - implementation 'com.fr.third:jxbrowser-win64-v7:7.22' + implementation "com.fr.third:jxbrowser-win64-v7:${jxBrowserVersion}" } } } diff --git a/designer-base/src/main/java/com/fr/base/svg/SVGIcon.java b/designer-base/src/main/java/com/fr/base/svg/SVGIcon.java index 172b10dac5..832fd33e91 100644 --- a/designer-base/src/main/java/com/fr/base/svg/SVGIcon.java +++ b/designer-base/src/main/java/com/fr/base/svg/SVGIcon.java @@ -1,9 +1,12 @@ package com.fr.base.svg; +import com.fr.design.utils.SvgDrawUtils; import com.fr.general.IOUtils; -import javax.swing.*; -import java.awt.*; +import javax.swing.Icon; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -34,10 +37,7 @@ public class SVGIcon implements Icon { public void paintIcon(Component c, Graphics g, int x, int y) { if (HI_DPI_SURPORT) { Graphics2D graphics = (Graphics2D) g.create(x, y, image.getWidth(null), image.getHeight(null)); - float scale = SYSTEM_SCALE; - graphics.scale(1 / scale, 1 / scale); - graphics.drawImage(image, 0, 0, null); - graphics.scale(1.0D, 1.0D); + SvgDrawUtils.doDrawSVG(graphics, () -> SvgDrawUtils.drawImage(graphics, image, 0, 0, null)); graphics.dispose(); } else { g.drawImage(image, x, y, null); diff --git a/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java b/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java index 6ef93b3146..68e22fd2a9 100644 --- a/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java +++ b/designer-base/src/main/java/com/fr/design/DesignerEnvManager.java @@ -310,7 +310,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter, AsyncXmlReada private static boolean asyncInitEnvManager() { AtomicBoolean noEx = new AtomicBoolean(false); - OptimizeUtil.open(DesignerEnvManager.class.getSimpleName().toLowerCase(), OptimizeUtil.Module.COMMON, () -> { + OptimizeUtil.initiateOpen(DesignerEnvManager.class.getSimpleName().toLowerCase(), () -> { try { designerEnvManager.initElements(designerEnvManager.getDesignerEnvFile()); noEx.set(true); @@ -901,13 +901,18 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter, AsyncXmlReada } public boolean isCloudAnalyticsDelay() { - return designerPushUpdateConfigManager.isCloudAnalyticsDelay(); + return designerPushUpdateConfigManager.isCloudAnalyticsDelay() || designerPushUpdateConfigManager.isUseCloudAnalyticsDelayFirst(); } public void setCloudAnalyticsDelay(boolean cloudAnalyticsDelay) { designerPushUpdateConfigManager.setCloudAnalyticsDelay(cloudAnalyticsDelay); } + public void setUseCloudAnalyticsDelayFirst(boolean useCloudAnalyticsDelayFirst) { + designerPushUpdateConfigManager.setUseCloudAnalyticsDelayFirst(useCloudAnalyticsDelayFirst); + } + + /** * 设计器登录相关配置 */ @@ -1023,6 +1028,14 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter, AsyncXmlReada designerLoginConfigManager.setUseOldVersionLogin(useOldVersionLogin); } + public boolean isUseNewPluginFirst() { + return designerLoginConfigManager.isUseNewPluginFirst(); + } + + public void setUseNewPluginFirst(boolean useNewPluginFirst) { + designerLoginConfigManager.setUseNewPluginFirst(useNewPluginFirst); + } + /** * 内置服务器是否使用时启动 * @@ -1896,6 +1909,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter, AsyncXmlReada .init("jdkHome", (e) -> this.jdkHome = e.getElementValue()) .init("lastBBSTime", DesignerEnvManager.this::readLastBBSTime) .init("lastBBSNewsTime", DesignerEnvManager.this::readLastBBSNewsTime) + .init("uuid", DesignerEnvManager.this::readUUID) .init("ActivationKey", DesignerEnvManager.this::readActiveKey) .init("status", DesignerEnvManager.this::readActiveStatus) .init(CAS_PARAS, DesignerEnvManager.this::readHttpsParas) diff --git a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java index bb55c90205..ca659e5f34 100644 --- a/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java +++ b/designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java @@ -14,13 +14,16 @@ import com.fr.design.env.DesignerWorkspaceInfoContext; import com.fr.design.env.DesignerWorkspaceType; import com.fr.design.env.RemoteDesignerWorkspaceInfo; import com.fr.design.env.RemoteWorkspace; +import com.fr.design.env.processor.RemoteDesignerWorkspaceInfoProcessor; import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.SaveSomeTemplatePane; import com.fr.design.file.TemplateTreePane; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.manager.clip.TemplateTreeClipboard; import com.fr.design.notification.NotificationCenter; +import com.fr.design.plugin.remind.PluginErrorDesignReminder; import com.fr.design.utils.DesignUtils; import com.fr.design.versioncheck.VersionCheckUtils; import com.fr.env.EnvListPane; @@ -31,6 +34,7 @@ import com.fr.invoke.Reflect; import com.fr.json.JSONArray; import com.fr.locale.InterProviderFactory; import com.fr.log.FineLoggerFactory; +import com.fr.performance.profile.PerformancePoint; import com.fr.process.ProcessEventPipe; import com.fr.process.engine.core.CarryMessageEvent; import com.fr.process.engine.core.FineProcessContext; @@ -41,12 +45,14 @@ import com.fr.start.server.ServerTray; import com.fr.workspace.WorkContext; import com.fr.workspace.WorkContextCallback; import com.fr.workspace.Workspace; +import com.fr.workspace.WorkspaceSwitchProcess; import com.fr.workspace.base.WorkspaceAPI; import com.fr.workspace.connect.WorkspaceConnectionInfo; import com.fr.workspace.engine.base.FineObjectPool; import com.fr.workspace.engine.channel.http.FunctionalHttpRequest; import com.fr.workspace.engine.exception.WorkspaceConnectionException; import com.fr.workspace.engine.rpc.WorkspaceProxyPool; +import static javax.swing.JOptionPane.QUESTION_MESSAGE; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; @@ -58,15 +64,17 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Optional; import java.util.Properties; import java.util.Set; -import java.util.HashSet; - -import static javax.swing.JOptionPane.QUESTION_MESSAGE; public class EnvChangeEntrance { + private static final String BRANCH_TAG = "#"; + private static final String BRANCH_BEGIN = "-"; + private static final int BRANCH_SUB_LENGTH = 13; public static EnvChangeEntrance getInstance() { return HOLDER.singleton; @@ -100,56 +108,139 @@ public class EnvChangeEntrance { } } + /** + * 插件进行用户名转换 + * + * @param workspaceInfo 环境信息 + */ + private DesignerWorkspaceInfo customUserName(DesignerWorkspaceInfo workspaceInfo) { + //本地环境直接返回 + if (workspaceInfo == null || workspaceInfo.getType() == DesignerWorkspaceType.Local) { + return workspaceInfo; + } + RemoteDesignerWorkspaceInfoProcessor processor = ExtraDesignClassManager.getInstance().getSingle(RemoteDesignerWorkspaceInfoProcessor.XML_TAG); + if (processor == null) { + return workspaceInfo; + } + try { + WorkspaceConnectionInfo workspaceConnectionInfo = processor.customUserName(workspaceInfo.getConnection()); + return (RemoteDesignerWorkspaceInfo) ((RemoteDesignerWorkspaceInfo) workspaceInfo).cloneWithConnectionInfo(workspaceConnectionInfo); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + return workspaceInfo; + } + } + + /** * 切换到新环境 * * @param envName 新工作环境名称 + * @param strategy 提示策略 * @return 是否成功 */ private boolean switch2Env(final String envName, PopTipStrategy strategy) { - DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); - DesignerWorkspaceInfo selectedEnv = envManager.getWorkspaceInfo(envName); - DesignerWorkspaceInfoContext.setWorkspaceInfo(selectedEnv); - WorkspaceConnectionInfo connectionInfo = selectedEnv.getConnection(); + + WorkspaceSwitchProcess lastProcess = WorkContext.getSwitcher().getProcess(); + PerformancePoint performancePoint = PerformancePoint.create(); + + boolean switchStatus = doSwitch2Env(envName, strategy); + + WorkspaceSwitchProcess currentProcess = WorkContext.getSwitcher().getProcess(); + // 如果相同,代表根本没切换 == + if (lastProcess != currentProcess) { + // 记录切换耗时 + recordSwitchInfos(performancePoint, switchStatus); + // 触发切换埋点 + triggerSwitchMetric(); + } + return switchStatus; + } + + /** + * 由云端运维,触发切换埋点 + * 内部空实现 + * 见 实现 + */ + private void triggerSwitchMetric() { + } + + /** + * 切换到新环境 + * 1. 先获取选中的环境 + * 2. 生成工作目录 + * 3. 验证工作目录 + * 4. 触发切换操作 + * 5. 触发可能存在异常的切换后动作 + * 6. 触发切换后动作 + * + * @param envName 新工作环境名称 + * @return 是否成功 + */ + private boolean doSwitch2Env(final String envName, PopTipStrategy strategy) { + + DesignerWorkspaceInfo selectedEnv = getSelectedEnv(envName); EnvBackupHelper.getInstance().backup(); try { Workspace workspace = DesignerWorkspaceGenerator.generate(selectedEnv); - boolean checkValid = workspace != null && selectedEnv.checkValid(); - if (!checkValid) { + if (notValid(workspace, selectedEnv)) { return false; } // 更新目标环境 EnvBackupHelper.getInstance().prepare4switch(workspace); - WorkContext.switchTo(workspace, new WorkContextCallback() { - @Override - public void done() { - DesignerEnvManager.getEnvManager().setCurEnvName(envName); - DesignUtils.refreshDesignerFrame(); - DesignTableDataManager.fireDSChanged(new HashMap()); - if (WorkContext.getCurrent().isLocal()) { - //初始化一下serverTray - ServerTray.init(); - } - EnvBackupHelper.getInstance().success(); - } - }); - // REPORT-25688如果是war包部署的服务器,给与提示 - if (WorkContext.getCurrent().isWarDeploy()) { - FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine-Design_Basic_War_Deploy_Tip"), - Toolkit.i18nText("Fine-Design_Basic_Message"), JOptionPane.INFORMATION_MESSAGE); - } - //REPORT-13810如果只是添加了工作目录,没有切换,这里ToolArea也是要显示新建的工作目录 - JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - if (template != null) { - template.refreshToolArea(); - } - PluginErrorDesignReminder.getInstance().remindStartFailedPlugins(); + doSwitchAction(envName, workspace); + afterSwitchWithEx(); } catch (Exception exception) { // 失败的处理 EnvBackupHelper.getInstance().failed(); WorkspaceExceptionHandler.getInstance().handleInSwitch(exception, selectedEnv); return false; } + afterSwitch(); + return true; + } + + private DesignerWorkspaceInfo getSelectedEnv(String envName) { + + DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); + DesignerWorkspaceInfo selectedEnv = customUserName(envManager.getWorkspaceInfo(envName)); + DesignerWorkspaceInfoContext.setWorkspaceInfo(selectedEnv); + return selectedEnv; + } + + private static boolean notValid(Workspace workspace, DesignerWorkspaceInfo selectedEnv) throws Exception { + boolean checkValid = workspace != null && selectedEnv.checkValid(); + return !checkValid; + } + + private void doSwitchAction(String envName, Workspace workspace) { + + //如果是相同环境 + if (isSameEnv(workspace)) { + //目前切换到相同环境需要更新一下名字,后续如果有别的操作直接往里面加就行了 + switch2SameEnv(envName); + } else { + //切换到新环境,做下封装 + switch2OtherEnv(workspace, envName); + } + } + + private static void afterSwitchWithEx() { + EnvBackupHelper.getInstance().success(); + // REPORT-25688如果是war包部署的服务器,给与提示 + if (WorkContext.getCurrent().isWarDeploy()) { + FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine-Design_Basic_War_Deploy_Tip"), + Toolkit.i18nText("Fine-Design_Basic_Message"), JOptionPane.INFORMATION_MESSAGE); + } + //REPORT-13810如果只是添加了工作目录,没有切换,这里ToolArea也是要显示新建的工作目录 + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (JTemplate.isValid(template)) { + template.refreshToolArea(); + } + PluginErrorDesignReminder.getInstance().remindStartFailedPlugins(); + } + + private static void afterSwitch() { TemplateTreePane.getInstance().refreshDockingView(); DesignModelAdapter model = DesignModelAdapter.getCurrentModelAdapter(); if (model != null) { @@ -158,7 +249,59 @@ public class EnvChangeEntrance { NotificationCenter.getInstance().clearAllNotifications(); //切换环境后,清空粘贴板里面的内容 TemplateTreeClipboard.getInstance().reset(); - return true; + } + + private static void recordSwitchInfos(PerformancePoint performancePoint, boolean switchSuccess) { + + performancePoint.end(elapsed -> { + WorkspaceSwitchProcess process = WorkContext.getSwitcher().getProcess(); + Optional.ofNullable(process) + .ifPresent((e) -> { + e.recordSwitchElapsed(elapsed); + e.setSwitchSuccess(switchSuccess); + }); + }); + } + + /** + * 切换到其他环境 + * + * @param workspace 要切换的环境 + * @param envName 要切换的环境名称 + */ + private void switch2OtherEnv(Workspace workspace, String envName) { + WorkContext.switchTo(workspace, new WorkContextCallback() { + @Override + public void done() { + DesignerEnvManager.getEnvManager().setCurEnvName(envName); + DesignUtils.refreshDesignerFrame(); + DesignTableDataManager.fireDSChanged(new HashMap()); + if (WorkContext.getCurrent().isLocal()) { + //初始化一下serverTray + ServerTray.init(); + } + } + }); + } + + /** + * 切换到相同环境要做的事情 + * + * @param envName 当前的环境名 + */ + private void switch2SameEnv(String envName) { + //当前环境名称可能重命名更改过,需要更新一下,防止启动失败 + DesignerEnvManager.getEnvManager().setCurEnvName(envName); + } + + /** + * 是否切换到相同环境 + * + * @param workspace 要切换的环境 + * @return 是则返回true + */ + private boolean isSameEnv(Workspace workspace) { + return AssistUtils.equals(WorkContext.getCurrent(), workspace); } /** @@ -206,13 +349,14 @@ public class EnvChangeEntrance { return true; } - /** + /** * 对选择的环境做服务检测 + * * @param selectedEnv 选择的工作环境 */ public void showServiceDialog(DesignerWorkspaceInfo selectedEnv) throws Exception { //是否需要做服务校验 - if(needCheckBranch(selectedEnv)) { + if (needCheckBranch(selectedEnv)) { String localBranch; String remoteBranch; WorkspaceConnectionInfo connectionInfo = selectedEnv.getConnection(); @@ -233,18 +377,18 @@ public class EnvChangeEntrance { StringBuilder textBuilder = new StringBuilder(); for (Class clazz : noExistServiceSet) { WorkspaceAPI workspaceAPI = (WorkspaceAPI) clazz.getAnnotation(WorkspaceAPI.class); - if(workspaceAPI == null){ + if (workspaceAPI == null) { FineLoggerFactory.getLogger().info("workspace service {} get annotation failed", clazz); continue; } - if(workspaceAPI.ignore()){ + if (workspaceAPI.ignore()) { continue; } String descriptionOfCN = InterProviderFactory.getProvider().getLocText(workspaceAPI.description()); textBuilder.append(descriptionOfCN).append("\n"); } String areaText = textBuilder.toString(); - if(StringUtils.isEmpty(areaText)){ + if (StringUtils.isEmpty(areaText)) { return; } @@ -256,24 +400,25 @@ public class EnvChangeEntrance { * 判断是否需要做版本验证,判断依据为 * 1、选择的环境为远程环境 * 2、一个月内不弹出是否勾选 + * * @param selectedEnv 选择的环境 * @return */ - private boolean needCheckBranch(DesignerWorkspaceInfo selectedEnv){ - if(selectedEnv.getType() == DesignerWorkspaceType.Remote){ + private boolean needCheckBranch(DesignerWorkspaceInfo selectedEnv) { + if (selectedEnv.getType() == DesignerWorkspaceType.Remote) { try { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); Calendar calendar = Calendar.getInstance(); - if(StringUtils.isEmpty(selectedEnv.getRemindTime())){ + if (StringUtils.isEmpty(selectedEnv.getRemindTime())) { return true; } //获取记录的时间 Date remindTime = format.parse(selectedEnv.getRemindTime()); calendar.setTime(remindTime); //获取一个月后的时间 - calendar.add(Calendar.MONTH,1); + calendar.add(Calendar.MONTH, 1); //与当前时间作对比,然后判断是否提示 - if(new Date().after(calendar.getTime())){ + if (new Date().after(calendar.getTime())) { return true; } } catch (ParseException e) { @@ -285,21 +430,22 @@ public class EnvChangeEntrance { /** * 获取不存在的服务列表 + * * @param info 环境连接信息 * @return 以Set形式返回不存在的服务 */ - public Set getNoExistServiceSet(WorkspaceConnectionInfo info){ + public Set getNoExistServiceSet(WorkspaceConnectionInfo info) { Set noExistServiceSet = new HashSet(); Set remoteServiceSet = new HashSet(); Set localServiceSet = FineObjectPool.getInstance().getServerPool().keySet(); try { - JSONArray serviceArray = new FunctionalHttpRequest(info).getServiceList(); - for(int i = 0; i < serviceArray.size(); i++){ - try{ + JSONArray serviceArray = new FunctionalHttpRequest(info).getServiceList(info); + for (int i = 0; i < serviceArray.size(); i++) { + try { Class clazz = Class.forName((String) serviceArray.get(i)); remoteServiceSet.add(clazz); - } catch (Exception e){ + } catch (Exception e) { continue; } } @@ -309,12 +455,12 @@ public class EnvChangeEntrance { } catch (WorkspaceConnectionException e) { FineLoggerFactory.getLogger().info(e.getMessage()); //根据本地的服务列表做逐一检测 - for(Class clazz : localServiceSet) { + for (Class clazz : localServiceSet) { Method testMethod = Reflect.on(Method.class).create(clazz, "connectTest", new Class[0], String.class, new Class[0], 1025, 8, null, null, null, null).get(); WorkspaceProxyPool proxyPool = (WorkspaceProxyPool) (((RemoteWorkspace) WorkContext.getCurrent()).getClient()).getPool(); Result result = proxyPool.testInvoker(testMethod); Exception invokeException = (Exception) result.getException(); - if(invokeException != null){ + if (invokeException != null) { Exception cause = (Exception) invokeException.getCause(); //获取被包装最底层的异常 while (cause != null) { @@ -322,26 +468,27 @@ public class EnvChangeEntrance { cause = (Exception) invokeException.getCause(); } //该异常表示服务不存在 - if(invokeException instanceof ClassNotFoundException){ + if (invokeException instanceof ClassNotFoundException) { noExistServiceSet.add(clazz); } } } return noExistServiceSet; - } catch (Exception e){ - FineLoggerFactory.getLogger().error(e.getMessage(),e); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); return noExistServiceSet; } } /** * 格式化分支版本号 + * * @param branch 初始的分支版本号 * @return 格式化后的版本号 */ - private String formatBranch(String branch){ - if(branch.contains("#")){ - return branch.substring(branch.lastIndexOf("-") + 1, branch.length() - 13); + private String formatBranch(String branch) { + if (branch.contains(BRANCH_TAG)) { + return branch.substring(branch.lastIndexOf(BRANCH_BEGIN) + 1, branch.length() - BRANCH_SUB_LENGTH); } return branch; } @@ -375,7 +522,7 @@ public class EnvChangeEntrance { @Override public void doOk() { SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true, SwingUtilities.getWindowAncestor(envListPane)); - if (!saveSomeTemplatePane.showSavePane()) { + if (!saveSomeTemplatePane.showSavePane(true)) { // 用户取消保存时,取消切换目录操作 return; } diff --git a/designer-base/src/main/java/com/fr/design/actions/community/BBSAction.java b/designer-base/src/main/java/com/fr/design/actions/community/BBSAction.java index 1acbbe4170..ed487578c8 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/BBSAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/BBSAction.java @@ -1,14 +1,22 @@ package com.fr.design.actions.community; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.login.AbstractDesignerSSO; import com.fr.design.menu.MenuKeySet; -import com.fr.general.CloudCenter; - -import javax.swing.*; +import javax.swing.KeyStroke; public class BBSAction extends AbstractDesignerSSO { + /** + * 云中心帆软社区页在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Bbs"; + + /** + * 云中心帆软社区页默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Bbs_Default"; public BBSAction() { this.setMenuKeySet(BBS); @@ -20,7 +28,7 @@ public class BBSAction extends AbstractDesignerSSO { @Override public String getJumpUrl() { - return CloudCenter.getInstance().acquireUrlByKind("bbs", "http://bbs.fanruan.com/"); + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); } public static final MenuKeySet BBS = new MenuKeySet() { diff --git a/designer-base/src/main/java/com/fr/design/actions/community/BugAction.java b/designer-base/src/main/java/com/fr/design/actions/community/BugAction.java index 5365e556b6..9da1539a5a 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/BugAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/BugAction.java @@ -1,13 +1,23 @@ package com.fr.design.actions.community; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.login.AbstractDesignerSSO; import com.fr.design.menu.MenuKeySet; -import com.fr.general.CloudCenter; -import javax.swing.*; +import javax.swing.KeyStroke; public class BugAction extends AbstractDesignerSSO { + /** + * 云中心产品反馈页在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Bugs"; + + /** + * 云中心产品反馈页默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Bugs_Default"; + public BugAction() { this.setMenuKeySet(BUG); this.setName(getMenuKeySet().getMenuName()); @@ -17,7 +27,7 @@ public class BugAction extends AbstractDesignerSSO { @Override public String getJumpUrl() { - return CloudCenter.getInstance().acquireUrlByKind("bbs.bugs", "https://service.fanruan.com/PF/FR/feedback?type=2"); + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); } public static final MenuKeySet BUG = new MenuKeySet() { diff --git a/designer-base/src/main/java/com/fr/design/actions/community/CenterAction.java b/designer-base/src/main/java/com/fr/design/actions/community/CenterAction.java index 6ae03f1a8a..093070b55c 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/CenterAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/CenterAction.java @@ -1,7 +1,7 @@ package com.fr.design.actions.community; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.menu.MenuKeySet; -import com.fr.general.CloudCenter; import javax.swing.KeyStroke; @@ -9,6 +9,17 @@ import javax.swing.KeyStroke; * Created by XINZAI on 2018/8/23. */ public class CenterAction extends UpAction { + + /** + * 云中心活动中心页在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Act_Center"; + + /** + * 云中心活动中心页默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Act_Center_Default"; + public CenterAction() { this.setMenuKeySet(CENTER); this.setName(getMenuKeySet().getMenuName()); @@ -18,7 +29,7 @@ public class CenterAction extends UpAction { @Override public String getJumpUrl() { - return CloudCenter.getInstance().acquireUrlByKind("bbs.center", "http://bbs.fanruan.com/events/"); + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); } public static final MenuKeySet CENTER = new MenuKeySet() { diff --git a/designer-base/src/main/java/com/fr/design/actions/community/CusDemandAction.java b/designer-base/src/main/java/com/fr/design/actions/community/CusDemandAction.java index 007eeb9abf..ef4cea39de 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/CusDemandAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/CusDemandAction.java @@ -1,18 +1,28 @@ package com.fr.design.actions.community; import com.fr.base.BaseUtils; - +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.menu.MenuKeySet; import com.fr.design.utils.BrowseUtils; -import com.fr.general.CloudCenter; -import javax.swing.KeyStroke; +import javax.swing.KeyStroke; import java.awt.event.ActionEvent; /** * Created by XINZAI on 2018/8/23. */ public class CusDemandAction extends UpAction{ + + /** + * 云中心发布需求页在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Demand"; + + /** + * 云中心发布需求页默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Demand_Default"; + public CusDemandAction() { this.setMenuKeySet(DEMAND); @@ -25,7 +35,7 @@ public class CusDemandAction extends UpAction{ @Override public void actionPerformed(ActionEvent arg0) { - String url = CloudCenter.getInstance().acquireUrlByKind("bbs.demand", "https://market.fanruan.com/demand"); + String url = LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); BrowseUtils.browser(url); } diff --git a/designer-base/src/main/java/com/fr/design/actions/community/FacebookFansAction.java b/designer-base/src/main/java/com/fr/design/actions/community/FacebookFansAction.java index e5ff4dd472..05ef85e44f 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/FacebookFansAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/FacebookFansAction.java @@ -1,14 +1,24 @@ package com.fr.design.actions.community; -import com.fr.base.svg.IconUtils; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.menu.MenuKeySet; import com.fr.design.utils.BrowseUtils; -import com.fr.general.CloudCenter; + import javax.swing.KeyStroke; import java.awt.event.ActionEvent; public class FacebookFansAction extends UpAction { + /** + * 云中心facebook页在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_FaceBook"; + + /** + * 云中心facebook页默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_FaceBook_Default"; + public FacebookFansAction() { this.setMenuKeySet(FACEBOOKFANS); this.setName(getMenuKeySet().getMenuName()); @@ -18,7 +28,7 @@ public class FacebookFansAction extends UpAction { @Override public void actionPerformed(ActionEvent arg0) { - BrowseUtils.browser(CloudCenter.getInstance().acquireUrlByKind("facebook.fans.tw", "https://www.facebook.com/twfinereport")); + BrowseUtils.browser(LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT)); } public static final MenuKeySet FACEBOOKFANS = new MenuKeySet() { diff --git a/designer-base/src/main/java/com/fr/design/actions/community/NeedAction.java b/designer-base/src/main/java/com/fr/design/actions/community/NeedAction.java index 62d4b9c95f..33279060b6 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/NeedAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/NeedAction.java @@ -1,13 +1,23 @@ package com.fr.design.actions.community; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.login.AbstractDesignerSSO; import com.fr.design.menu.MenuKeySet; -import com.fr.general.CloudCenter; -import javax.swing.*; +import javax.swing.KeyStroke; public class NeedAction extends AbstractDesignerSSO { + /** + * 云中心产品反馈页在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Need"; + + /** + * 云中心产品反馈页默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Need_Default"; + public NeedAction() { this.setMenuKeySet(NEED); this.setName(getMenuKeySet().getMenuName()); @@ -18,7 +28,7 @@ public class NeedAction extends AbstractDesignerSSO { @Override public String getJumpUrl() { - return CloudCenter.getInstance().acquireUrlByKind("bbs.needs", "https://service.fanruan.com/PF/FR/feedback?type=1"); + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY ,PROPS_LINK_KEY_DEFAULT); } public static final MenuKeySet NEED = new MenuKeySet() { diff --git a/designer-base/src/main/java/com/fr/design/actions/community/QuestionAction.java b/designer-base/src/main/java/com/fr/design/actions/community/QuestionAction.java index 5b44112254..e56359139a 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/QuestionAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/QuestionAction.java @@ -1,13 +1,23 @@ package com.fr.design.actions.community; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.login.AbstractDesignerSSO; import com.fr.design.menu.MenuKeySet; -import com.fr.general.CloudCenter; -import javax.swing.*; +import javax.swing.KeyStroke; public class QuestionAction extends AbstractDesignerSSO { + /** + * 云中心问答页在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Question"; + + /** + * 云中心问答页默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Question_Default"; + public QuestionAction() { this.setMenuKeySet(QUESTIONS); this.setName(getMenuKeySet().getMenuName()); @@ -18,7 +28,7 @@ public class QuestionAction extends AbstractDesignerSSO { @Override public String getJumpUrl() { - return CloudCenter.getInstance().acquireUrlByKind("bbs.questions", "http://bbs.fanruan.com/wenda"); + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY ,PROPS_LINK_KEY_DEFAULT); } public static final MenuKeySet QUESTIONS = new MenuKeySet() { diff --git a/designer-base/src/main/java/com/fr/design/actions/community/SignAction.java b/designer-base/src/main/java/com/fr/design/actions/community/SignAction.java index 8c29ee5e66..29817e36a6 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/SignAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/SignAction.java @@ -1,14 +1,23 @@ package com.fr.design.actions.community; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.login.AbstractDesignerSSO; import com.fr.design.menu.MenuKeySet; -import com.fr.general.CloudCenter; - -import javax.swing.*; +import javax.swing.KeyStroke; public class SignAction extends AbstractDesignerSSO { + /** + * 云中心认证落地页在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Aut"; + + /** + * 云中心认证落地页默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Aut_Default"; + public SignAction() { this.setMenuKeySet(SIGN); this.setName(getMenuKeySet().getMenuName()); @@ -18,7 +27,7 @@ public class SignAction extends AbstractDesignerSSO { @Override public String getJumpUrl() { - return CloudCenter.getInstance().acquireUrlByKind("bbs.aut", "https://bbs.fanruan.com/certification/"); + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY ,PROPS_LINK_KEY_DEFAULT); } public static final MenuKeySet SIGN = new MenuKeySet() { diff --git a/designer-base/src/main/java/com/fr/design/actions/community/StudyPlanAction.java b/designer-base/src/main/java/com/fr/design/actions/community/StudyPlanAction.java index d0dcc4195d..0d2e79905d 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/StudyPlanAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/StudyPlanAction.java @@ -1,10 +1,21 @@ package com.fr.design.actions.community; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.i18n.Toolkit; import com.fr.design.login.AbstractDesignerSSO; -import com.fr.general.CloudCenter; public class StudyPlanAction extends AbstractDesignerSSO { + + /** + * 云中心帆软学院在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Study"; + + /** + * 云中心帆软学院默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Study_Default"; + public StudyPlanAction() { this.setName(Toolkit.i18nText("Fine-Design_Study_Plan")); this.setSmallIcon("/com/fr/design/images/bbs/studyPlan"); @@ -12,6 +23,6 @@ public class StudyPlanAction extends AbstractDesignerSSO { @Override public String getJumpUrl() { - return CloudCenter.getInstance().acquireUrlByKind("bbs.studyPlan", "https://edu.fanruan.com/studypath/finereport"); + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY ,PROPS_LINK_KEY_DEFAULT); } } diff --git a/designer-base/src/main/java/com/fr/design/actions/community/TechSolutionAction.java b/designer-base/src/main/java/com/fr/design/actions/community/TechSolutionAction.java index 8975555780..f0e4f3ac30 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/TechSolutionAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/TechSolutionAction.java @@ -1,8 +1,8 @@ package com.fr.design.actions.community; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.login.AbstractDesignerSSO; import com.fr.design.menu.MenuKeySet; -import com.fr.general.CloudCenter; import javax.swing.KeyStroke; @@ -10,6 +10,17 @@ import javax.swing.KeyStroke; * Created by XINZAI on 2018/8/23. */ public class TechSolutionAction extends AbstractDesignerSSO { + + /** + * 云中心社区在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Community"; + + /** + * 云中心社区默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Community_Default"; + public TechSolutionAction() { this.setMenuKeySet(TSO); this.setName(getMenuKeySet().getMenuName()); @@ -20,7 +31,7 @@ public class TechSolutionAction extends AbstractDesignerSSO { @Override public String getJumpUrl() { - return CloudCenter.getInstance().acquireUrlByKind("bbs.solution", "http://bbs.fanruan.com/forum-113-1.html"); + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY ,PROPS_LINK_KEY_DEFAULT); } public static final MenuKeySet TSO = new MenuKeySet() { diff --git a/designer-base/src/main/java/com/fr/design/actions/community/TemplateStoreAction.java b/designer-base/src/main/java/com/fr/design/actions/community/TemplateStoreAction.java index eec904ebd6..3c17df9b56 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/TemplateStoreAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/TemplateStoreAction.java @@ -1,21 +1,28 @@ package com.fr.design.actions.community; import com.fr.base.BaseUtils; -import com.fr.design.actions.UpdateAction; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.login.AbstractDesignerSSO; import com.fr.design.mainframe.share.collect.ComponentCollector; import com.fr.design.menu.MenuKeySet; -import com.fr.design.utils.BrowseUtils; -import com.fr.general.CloudCenter; import javax.swing.KeyStroke; -import java.awt.event.ActionEvent; /** * created by Harrison on 2020/03/24 **/ public class TemplateStoreAction extends AbstractDesignerSSO { - + + /** + * 云中心组件商城模板在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Market_Template"; + + /** + * 云中心组件商城模板默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Market_Template_Default"; + public TemplateStoreAction() { this.setMenuKeySet(TEMPLATE); @@ -47,6 +54,6 @@ public class TemplateStoreAction extends AbstractDesignerSSO { @Override public String getJumpUrl() { ComponentCollector.getInstance().collectTepMenuEnterClick(); - return CloudCenter.getInstance().acquireUrlByKind("design.market.template", "https://market.fanruan.com/template"); + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY ,PROPS_LINK_KEY_DEFAULT); } } diff --git a/designer-base/src/main/java/com/fr/design/actions/community/UpAction.java b/designer-base/src/main/java/com/fr/design/actions/community/UpAction.java index 05022ecf8c..e0c6404836 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/UpAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/UpAction.java @@ -1,14 +1,24 @@ package com.fr.design.actions.community; import com.fr.base.BaseUtils; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.login.AbstractDesignerSSO; import com.fr.design.menu.MenuKeySet; -import com.fr.general.CloudCenter; import javax.swing.KeyStroke; public class UpAction extends AbstractDesignerSSO { + /** + * 云中心工单中心在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Bbs_Update"; + + /** + * 云中心工单中心默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Bbs_Update_Default"; + public UpAction() { this.setMenuKeySet(UPDATE); this.setName(getMenuKeySet().getMenuName()); @@ -18,7 +28,7 @@ public class UpAction extends AbstractDesignerSSO { @Override public String getJumpUrl() { - return CloudCenter.getInstance().acquireUrlByKind("bbs.update", "http://bbs.fanruan.com/forum.php?mod=collection&action=view&ctid=10"); + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY ,PROPS_LINK_KEY_DEFAULT); } public static final MenuKeySet UPDATE = new MenuKeySet() { diff --git a/designer-base/src/main/java/com/fr/design/actions/community/WorkOrderCenterAction.java b/designer-base/src/main/java/com/fr/design/actions/community/WorkOrderCenterAction.java index d1168eca70..03e634a4ad 100644 --- a/designer-base/src/main/java/com/fr/design/actions/community/WorkOrderCenterAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/community/WorkOrderCenterAction.java @@ -1,7 +1,7 @@ package com.fr.design.actions.community; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.i18n.Toolkit; -import com.fr.general.CloudCenter; /** * @Description 工单中心 @@ -9,6 +9,17 @@ import com.fr.general.CloudCenter; * @Date 2021/3/8 14:02 **/ public class WorkOrderCenterAction extends UpAction { + + /** + * 云中心工单中心在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Work_Order_Center"; + + /** + * 云中心工单中心默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Work_Order_Center_Default"; + public WorkOrderCenterAction() { this.setSmallIcon("/com/fr/design/images/bbs/workOrderCenter"); this.setName(Toolkit.i18nText("Fine-Design_Basic_Commuinity_Work_Order_Center")); @@ -16,6 +27,6 @@ public class WorkOrderCenterAction extends UpAction { @Override public String getJumpUrl() { - return CloudCenter.getInstance().acquireUrlByKind("bbs.work.order.center", "https://service.fanruan.com/ticket"); + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java b/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java index 94e52e0595..c913d0f5df 100644 --- a/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java +++ b/designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java @@ -36,12 +36,15 @@ import com.fr.design.layout.TableLayoutHelper; import com.fr.design.layout.VerticalFlowLayout; import com.fr.design.mainframe.vcs.VcsConfigManager; import com.fr.design.mainframe.vcs.common.VcsHelper; +import com.fr.design.mainframe.vcs.ui.UIPositiveIntEditor; +import com.fr.design.mainframe.vcs.ui.VcsMovePanel; import com.fr.design.os.impl.SupportOSImpl; import com.fr.design.unit.UnitConvertUtil; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.design.widget.FRWidgetFactory; import com.fr.general.ComparatorUtils; import com.fr.general.FRFont; +import com.fr.general.GeneralContext; import com.fr.general.IOUtils; import com.fr.general.Inter; import com.fr.general.log.Log4jConfig; @@ -49,14 +52,22 @@ import com.fr.io.attr.ImageExportAttr; import com.fr.locale.InterProviderFactory; import com.fr.log.FineLoggerFactory; import com.fr.report.ReportConfigManager; +import com.fr.scheduler.tool.FineScheduler; import com.fr.stable.Constants; import com.fr.stable.os.OperatingSystem; import com.fr.third.apache.logging.log4j.Level; +import com.fr.third.guava.collect.BiMap; +import com.fr.third.guava.collect.HashBiMap; import com.fr.transaction.Configurations; import com.fr.transaction.Worker; +import com.fr.transaction.WorkerAdaptor; import com.fr.workspace.WorkContext; +import com.fr.workspace.server.vcs.VcsConfig; import com.fr.workspace.server.vcs.VcsOperator; import com.fr.workspace.server.vcs.git.config.GcConfig; +import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanOperator; +import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanSchedule; +import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanService; import org.jetbrains.annotations.NotNull; import javax.swing.BorderFactory; @@ -65,6 +76,7 @@ import javax.swing.ButtonGroup; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFileChooser; +import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; @@ -77,14 +89,7 @@ import javax.swing.UIManager; import javax.swing.border.EmptyBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dialog; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.Font; -import java.awt.Window; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; @@ -95,6 +100,7 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.text.DecimalFormat; +import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.concurrent.ExecutionException; @@ -122,6 +128,7 @@ public class PreferencePane extends BasicPane { private static final int PREFERENCE_LABEL_MAX_WIDTH = 460; private static final int OFFSET_HEIGHT = 60; + private static final int VCS_FILL_TOTAL = 5; private static final String TYPE = "pressed"; private static final String DISPLAY_TYPE = "+"; private static final String BACK_SLASH = "BACK_SLASH"; @@ -149,6 +156,34 @@ public class PreferencePane extends BasicPane { private static final Level[] LOG = {Level.FATAL, Level.ERROR, Level.WARN, Level.INFO, Level.DEBUG}; + private static final int ONE_DAY_INT = 1; + private static final int ONE_WEEK_INT = 7; + private static final int ONE_MONTH_INT = 30; + private static final int THREE_MONTH_INT = 90; + private static final int SIX_MONTH_INT = 180; + + private static final int ONE_DAY_INDEX = 0; + private static final int ONE_WEEK_INDEX = 1; + private static final int ONE_MONTH_INDEX = 2; + private static final int THREE_MONTH_INDEX = 3; + private static final int SIX_MONTH_INDEX = 4; + private static final String ONE_DAY = Toolkit.i18nText("Fine-Design_Vcs_Auto_Clean_ONE_DAY"); + private static final String ONE_WEEK = Toolkit.i18nText("Fine-Design_Vcs_Auto_Clean_ONE_WEEK"); + private static final String ONE_MONTH = Toolkit.i18nText("Fine-Design_Vcs_Auto_Clean_ONE_MONTH"); + private static final String THREE_MONTH = Toolkit.i18nText("Fine-Design_Vcs_Auto_Clean_THREE_MONTH"); + private static final String SIX_MONTH = Toolkit.i18nText("Fine-Design_Vcs_Auto_Clean_SIX_MONTH"); + private static final String[] INTERVAL = { + ONE_DAY, + ONE_WEEK, + ONE_MONTH, + THREE_MONTH, + SIX_MONTH + }; + + private static final int DEFAULT_INDEX = 3; + + private BasicDialog basicDialog; + private boolean languageChanged; // 是否修改了设计器语言设置 //设置是否支持undo private UICheckBox supportUndoCheckBox; @@ -186,10 +221,24 @@ public class PreferencePane extends BasicPane { private UICheckBox cloudAnalyticsDelayCheckBox; private UICheckBox vcsEnableCheckBox; + private UICheckBox useVcsAutoSaveScheduleCheckBox; + + private UICheckBox useVcsAutoCleanScheduleCheckBox; + + private UIComboBox autoCleanIntervalComboBox; + private UIComboBox autoCleanRetainIntervalComboBox; + + private UIPositiveIntEditor autoSaveIntervalEditor; private UICheckBox saveCommitCheckBox; private UICheckBox useIntervalCheckBox; + private VcsMovePanel movePanel; + + private JPanel saveIntervalPane; + private JPanel autoCleanPane; + + private JPanel gcControlPane; private UICheckBox startupPageEnabledCheckBox; - private IntegerEditor saveIntervalEditor; + private UIPositiveIntEditor saveIntervalEditor; private UICheckBox gcEnableCheckBox; private UIButton gcButton; private UILabel remindVcsLabel; @@ -201,7 +250,7 @@ public class PreferencePane extends BasicPane { private JProgressBar gcProgressBar; private Timer gcProgressTimer; private UIButton gcOkButton = new UIButton(i18nText("Fine-Design_Report_OK")); - + private UIRadioButton previewResolutionBtnS; private UIRadioButton previewResolutionBtnM; @@ -209,7 +258,15 @@ public class PreferencePane extends BasicPane { private UIRadioButton previewRenderQuality; private static final int DPI_SCALE_S = 1; private static final int DPI_SCALE_M = 2; - + private static final BiMap INDEX_DAY_MAP = HashBiMap.create(new HashMap() { + { + put(ONE_DAY_INDEX, ONE_DAY_INT); + put(ONE_WEEK_INDEX, ONE_WEEK_INT); + put(ONE_MONTH_INDEX, ONE_MONTH_INT); + put(SIX_MONTH_INDEX, SIX_MONTH_INT); + put(THREE_MONTH_INDEX, THREE_MONTH_INT); + } + }); public PreferencePane() { this.initComponents(); } @@ -223,17 +280,30 @@ public class PreferencePane extends BasicPane { JPanel generalPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); UIScrollPane generalScrollPane = patchScroll(generalPane); jtabPane.addTab(i18nText("Fine-Design_Basic_General"), generalScrollPane); - + JPanel advancePane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); UIScrollPane adviceScrollPane = patchScroll(advancePane); jtabPane.addTab(i18nText("Fine-Design_Basic_Advanced"), adviceScrollPane); - + //初始化vcs总面板 + JPanel vcsParentPane = new JPanel(); + CardLayout cardLayout = new CardLayout(); + vcsParentPane.setLayout(cardLayout); + //vcs配置面板 + JPanel vcsPane = new JPanel(new BorderLayout()); + //添加滚动条 + UIScrollPane vcsScrollPane = patchScroll(vcsPane); + //配置面板作为vcs总面板的一张卡片 + vcsParentPane.add(vcsScrollPane, VcsMovePanel.SETTING); + jtabPane.addTab(i18nText("Fine-Design_Vcs_Title"), vcsParentPane); + contentPane.add(jtabPane, BorderLayout.NORTH); createFunctionPane(generalPane); createEditPane(generalPane); createColorSettingPane(generalPane); - createVcsSettingPane(generalPane); + + // vcsPane + createVcsSettingPane(vcsPane, vcsParentPane, cardLayout); // ConfPane JPanel confLocationPane = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane(); @@ -242,7 +312,7 @@ public class PreferencePane extends BasicPane { createLogPane(advancePane); createLanPane(generalPane); - + createStartupPagePane(generalPane); createLengthPane(advancePane); @@ -309,7 +379,7 @@ public class PreferencePane extends BasicPane { designerStartupOption.add(cloudAnalyticsDelayCheckBox); advancePane.add(designerStartupOption); } - + private JPanel createImageExportSettingPane() { previewResolutionBtnS = new UIRadioButton(i18nText("Fine-Design_Image_Export_SD"), true); previewResolutionBtnM = new UIRadioButton(i18nText("Fine-Design_Image_Export_HD")); @@ -345,20 +415,34 @@ public class PreferencePane extends BasicPane { generalPanelWithScroll.setPreferredSize(new Dimension(generalPane.getWidth(), 600)); return generalPanelWithScroll; } - - private void createVcsSettingPane(JPanel generalPane) { - JPanel vcsPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Vcs_Title")); - generalPane.add(vcsPane); + + private void createVcsSettingPane(JPanel generalPane,JPanel parentPane, CardLayout cardLayout) { + //迁移面板 + movePanel = createMovePane(cardLayout, parentPane); + generalPane.add(movePanel, BorderLayout.NORTH); + JPanel savePane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Vcs_Save_Setting")); + JPanel vcsPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Vcs_Clean_Setting")); + JPanel containPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); + containPane.add(savePane); + containPane.add(vcsPane); + //填充一下面板 + fillPane(containPane, VCS_FILL_TOTAL); + generalPane.add(containPane, BorderLayout.CENTER); remindVcsLabel = new UILabel(i18nText("Fine-Design_Vcs_Remind")); remindVcsLabel.setVisible(!VcsHelper.getInstance().needInit()); vcsEnableCheckBox = new UICheckBox(i18nText("Fine-Design_Vcs_SaveAuto")); + + saveIntervalPane = createSaveIntervalPane(); saveCommitCheckBox = new UICheckBox(i18nText("Fine-Design_Vcs_No_Delete")); - saveIntervalEditor = new IntegerEditor(60); + saveIntervalEditor = new UIPositiveIntEditor(60); useIntervalCheckBox = new UICheckBox(); + savePane.add(vcsEnableCheckBox); + savePane.add(saveIntervalPane); //gc面板 + gcControlPane = createGcControlPane(); + JPanel enableVcsPanel = new JPanel(FRGUIPaneFactory.createLeftZeroLayout()); - enableVcsPanel.add(vcsEnableCheckBox); enableVcsPanel.add(remindVcsLabel); JPanel intervalPanel = new JPanel(FRGUIPaneFactory.createLeftZeroLayout()); final UILabel everyLabel = new UILabel(i18nText("Fine-Design_Vcs_Every")); @@ -367,6 +451,8 @@ public class PreferencePane extends BasicPane { intervalPanel.add(everyLabel); intervalPanel.add(saveIntervalEditor); intervalPanel.add(delayLabel); + autoCleanPane = createAutoCleanPane(); + checkAutoScheduleStartAndUpdateStatus(); vcsEnableCheckBox.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { @@ -388,34 +474,104 @@ public class PreferencePane extends BasicPane { }); vcsPane.add(enableVcsPanel); vcsPane.add(intervalPanel); - vcsPane.add(saveCommitCheckBox); + if (VcsHelper.getInstance().isLegacyMode()) { + vcsPane.add(saveCommitCheckBox); + } + vcsPane.add(autoCleanPane); + boolean support = VcsHelper.getInstance().checkV2FunctionSupport(); + saveIntervalPane.setVisible(support); + autoCleanPane.setVisible(support); + if (VcsHelper.getInstance().isLegacyMode()) { + // 老版本时才显示gc选项 + vcsPane.add(gcControlPane); + } + } - initGcControlPane(vcsPane); + private void fillPane(JPanel containPane, int total) { + for (int i = 0; i < total; i++) { + containPane.add(new JPanel()); + } } - private void initGcControlPane(JPanel vcsPane) { - JPanel gcControlPane = createGcControlPane(); - new SwingWorker() { + private VcsMovePanel createMovePane(CardLayout cardLayout, JPanel parentPane) { + return new VcsMovePanel(cardLayout, parentPane, new VcsMovePanel.MoveCallBack(){ @Override - protected Boolean doInBackground() throws Exception { - return WorkContext.getCurrent().get(VcsOperator.class).isLegacyMode(); + public void doCallBack(boolean useV2) { + saveIntervalPane.setVisible(useV2); + autoCleanPane.setVisible(useV2); + gcControlPane.setVisible(!useV2); + saveCommitCheckBox.setVisible(!useV2); + useVcsAutoCleanScheduleCheckBox.setSelected(useV2); + useVcsAutoSaveScheduleCheckBox.setSelected(useV2); + checkAutoScheduleStartAndUpdateStatus(); + useVcsAutoSaveScheduleCheckBox.setEnabled(useV2); } + }, basicDialog); + }; + + private JPanel createAutoCleanPane() { + JPanel autoCleanPane = new JPanel(FRGUIPaneFactory.createLeftZeroLayout()); + useVcsAutoCleanScheduleCheckBox = new UICheckBox(); + autoCleanIntervalComboBox = new UIComboBox(INTERVAL); + autoCleanIntervalComboBox.setSelectedIndex(DEFAULT_INDEX); + autoCleanRetainIntervalComboBox = new UIComboBox(INTERVAL); + autoCleanRetainIntervalComboBox.setSelectedIndex(DEFAULT_INDEX); + autoCleanPane.add(useVcsAutoCleanScheduleCheckBox); + autoCleanPane.add(new UILabel(i18nText("Fine-Design_Vcs_Auto_Clean_Every"))); + autoCleanPane.add(autoCleanIntervalComboBox); + autoCleanPane.add(new UILabel(i18nText("Fine-Design_Vcs_Auto_Clean_Content"))); + autoCleanPane.add(autoCleanRetainIntervalComboBox); + autoCleanPane.add(new UILabel(i18nText("Fine-Design_Vcs_Auto_Clean_Last"))); + autoCleanPane.setVisible(false); + return autoCleanPane; + } - @Override - protected void done() { - try { - if (Boolean.TRUE.equals(get())) { - // 老版本时才显示gc选项 - vcsPane.add(gcControlPane); - vcsPane.updateUI(); + private void checkAutoScheduleStartAndUpdateStatus() { + if (!VcsHelper.getInstance().isLegacyMode()) { + new SwingWorker() { + @Override + protected Boolean doInBackground() throws Exception { + return WorkContext.getCurrent().get(VcsAutoCleanOperator.class).isSupport(); + } + @Override + protected void done() { + try { + boolean useAutoClean = get(); + updateAutoCleanEnabled(useAutoClean); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); } - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e, "[Vcs] retrieve legacy mode error: {}", e.getMessage()); } - } - }.execute(); + }.execute(); + } else { + updateAutoCleanEnabled(false); + } } + private void updateAutoCleanEnabled(boolean b) { + useVcsAutoCleanScheduleCheckBox.setEnabled(b); + autoCleanIntervalComboBox.setEnabled(b); + autoCleanRetainIntervalComboBox.setEnabled(b); + if (autoCleanPane != null) { + autoCleanPane.setToolTipText(b ? null : Toolkit.i18nText("Fine-Design_Vcs_Server_Start_Hover")); + } + } + + private JPanel createSaveIntervalPane() { + JPanel saveIntervalPane = new JPanel(FRGUIPaneFactory.createLeftZeroLayout()); + useVcsAutoSaveScheduleCheckBox = new UICheckBox(); + autoSaveIntervalEditor = new UIPositiveIntEditor(60); + saveIntervalPane.add(useVcsAutoSaveScheduleCheckBox); + saveIntervalPane.add(new UILabel(i18nText("Fine-Design_Vcs_Every"))); + saveIntervalPane.add(autoSaveIntervalEditor); + saveIntervalPane.add(new UILabel(i18nText("Fine-Design_Vcs_Save_Delay"))); + useVcsAutoSaveScheduleCheckBox.setEnabled(!VcsHelper.getInstance().isLegacyMode()); + saveIntervalPane.setVisible(false); + return saveIntervalPane; + } + + + /** * 模创建板版本gc 配置操作面板 * @@ -486,7 +642,7 @@ public class PreferencePane extends BasicPane { private void createEditPane(JPanel generalPane) { //samuel:编辑器设置 - JPanel editPane = FRGUIPaneFactory.createTitledBorderPane(i18nText("Fine-Design_Basic_Editor_Preference")); + JPanel editPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(i18nText("Fine-Design_Basic_Editor_Preference")); generalPane.add(editPane); //设置是否支持将字符串编辑为公式 @@ -496,7 +652,6 @@ public class PreferencePane extends BasicPane { //是否默认转化 defaultStringToFormulaBox = new UICheckBox(i18nText("Fine-Design_Basic_Always")); - editPane.add(defaultStringToFormulaBox); //不支持转化则不能默认执行 supportStringToFormulaBox.addActionListener(new ActionListener() { @Override @@ -508,7 +663,12 @@ public class PreferencePane extends BasicPane { keyStrokePane.add(new UILabel(i18nText("Fine-Design_Basic_Support_Auto_Complete_Shortcut") + ":"), BorderLayout.WEST); shortCutLabel = new UILabel(); keyStrokePane.add(shortCutLabel, BorderLayout.CENTER); - editPane.add(keyStrokePane); + keyStrokePane.setBorder(new EmptyBorder(0, 10,0,0)); + + JPanel defaultExecutePane = new JPanel(FRGUIPaneFactory.createLeftZeroVgapNormalHgapLayout()); + defaultExecutePane.add(defaultStringToFormulaBox); + defaultExecutePane.add(keyStrokePane); + editPane.add(defaultExecutePane); shortCutLabel.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { @@ -796,7 +956,8 @@ public class PreferencePane extends BasicPane { defaultStringToFormulaBox.setSelected(false); } VcsConfigManager vcsConfigManager = designerEnvManager.getVcsConfigManager(); - if (WorkContext.getCurrent().isCluster()) { + //如果是集群并且是老版本则不可用 + if (VcsHelper.getInstance().isLegacyMode() && WorkContext.getCurrent().isCluster()) { vcsEnableCheckBox.setEnabled(false); gcEnableCheckBox.setEnabled(false); } @@ -819,6 +980,12 @@ public class PreferencePane extends BasicPane { gcEnableCheckBox.setSelected(GcConfig.getInstance().isGcEnable()); gcButton.setEnabled(gcEnableCheckBox.isSelected()); + useVcsAutoSaveScheduleCheckBox.setSelected(vcsConfigManager.isUseAutoSave()); + useVcsAutoCleanScheduleCheckBox.setSelected(VcsConfig.getInstance().isUseV2AutoClean()); + autoSaveIntervalEditor.setValue(vcsConfigManager.getAutoSaveInterval()); + autoCleanIntervalComboBox.setSelectedIndex(getIndex(VcsConfig.getInstance().getV2CleanInterval())); + autoCleanRetainIntervalComboBox.setSelectedIndex(getIndex(VcsConfig.getInstance().getV2RetainInterval())); + gridLineColorTBButton.setColor(designerEnvManager.getGridLineColor()); paginationLineColorTBButton.setColor(designerEnvManager.getPaginationLineColor()); @@ -834,8 +1001,7 @@ public class PreferencePane extends BasicPane { this.portEditor.setValue(new Integer(designerEnvManager.getEmbedServerPort())); if (useOptimizedUPMCheckbox != null) { - useOptimizedUPMCheckbox.setSelected(ServerPreferenceConfig.getInstance().isUseOptimizedUPM() - || DesignerEnvManager.getEnvManager().isUseOptimizedUPM4Adapter()); + useOptimizedUPMCheckbox.setSelected(checkOptimizedUPMUse()); } if (useNewVersionLoginCheckbox != null) { @@ -879,6 +1045,15 @@ public class PreferencePane extends BasicPane { this.startupPageEnabledCheckBox.setSelected(designerEnvManager.isStartupPageEnabled()); } + private boolean checkOptimizedUPMUse() { + //如果是没手动配置过则默认开启 + //isUseNewPluginFirst如果为true说明没手动配置过,直接开启 + //走到这里说明checkBox不为空,机型肯定符合 + return DesignerEnvManager.getEnvManager().isUseNewPluginFirst() + || ServerPreferenceConfig.getInstance().isUseOptimizedUPM() + || DesignerEnvManager.getEnvManager().isUseOptimizedUPM4Adapter(); + } + private int chooseCase(int sign) { switch (sign) { case 0: @@ -898,6 +1073,14 @@ public class PreferencePane extends BasicPane { } } + private int getDay(int dateIndex) { + return INDEX_DAY_MAP.getOrDefault(dateIndex, THREE_MONTH_INT); + } + + private int getIndex(int day) { + return INDEX_DAY_MAP.inverse().getOrDefault(day, THREE_MONTH_INDEX); + } + /** * The method of update. */ @@ -936,13 +1119,30 @@ public class PreferencePane extends BasicPane { designerEnvManager.setJoinProductImprove(this.joinProductImproveCheckBox.isSelected()); designerEnvManager.setEmbedServerLazyStartup(this.embedServerLazyStartupCheckBox.isSelected()); designerEnvManager.setImageCompress(this.imageCompressPanelCheckBox.isSelected()); - designerEnvManager.setUseOptimizedUPM4Adapter(this.useOptimizedUPMCheckbox != null && this.useOptimizedUPMCheckbox.isSelected()); - designerEnvManager.setCloudAnalyticsDelay(this.cloudAnalyticsDelayCheckBox.isSelected()); + boolean optimizedUPMFlag = this.useOptimizedUPMCheckbox != null && this.useOptimizedUPMCheckbox.isSelected(); + designerEnvManager.setUseOptimizedUPM4Adapter(optimizedUPMFlag); + //只有取消掉使用新插件管理器这个选项才需要把useNewPluginFirst置false(意味着用户手动配置了,如果勾选着的话,这个useNewPluginFirst为true就行了) + designerEnvManager.setUseNewPluginFirst(optimizedUPMFlag); + boolean cloudDelayFlag = this.cloudAnalyticsDelayCheckBox.isSelected(); + designerEnvManager.setCloudAnalyticsDelay(cloudDelayFlag); + // cloudDelayFlag默认为true,如果用户手动配置过才会是false,则后续的云端运维配置都按照用户意愿来 + designerEnvManager.setUseCloudAnalyticsDelayFirst(cloudDelayFlag); VcsConfigManager vcsConfigManager = designerEnvManager.getVcsConfigManager(); vcsConfigManager.setSaveInterval(this.saveIntervalEditor.getValue()); vcsConfigManager.setVcsEnable(this.vcsEnableCheckBox.isSelected()); vcsConfigManager.setSaveCommit(this.saveCommitCheckBox.isSelected()); vcsConfigManager.setUseInterval(this.useIntervalCheckBox.isSelected()); + vcsConfigManager.setUseAutoSave(this.useVcsAutoSaveScheduleCheckBox.isSelected()); + vcsConfigManager.setAutoSaveInterval(this.autoSaveIntervalEditor.getValue()); + Configurations.update(new WorkerAdaptor(VcsConfig.class) { + @Override + public void run() { + VcsConfig.getInstance().setUseV2AutoClean(useVcsAutoCleanScheduleCheckBox.isSelected()); + VcsConfig.getInstance().setV2CleanInterval(getDay(autoCleanIntervalComboBox.getSelectedIndex())); + VcsConfig.getInstance().setV2RetainInterval(getDay(autoCleanRetainIntervalComboBox.getSelectedIndex())); + } + }); + dealWithSchedule(); designerEnvManager.setStartupPageEnabled(this.startupPageEnabledCheckBox.isSelected()); Configurations.update(new Worker() { @Override @@ -1017,6 +1217,36 @@ public class PreferencePane extends BasicPane { } + private void dealWithSchedule() { + new SwingWorker() { + @Override + protected Void doInBackground() throws Exception { + boolean v2FunctionSupport = VcsHelper.getInstance().checkV2FunctionSupport(); + if (v2FunctionSupport) { + //如果支持V2 + if (useVcsAutoSaveScheduleCheckBox.isSelected()) { + FineLoggerFactory.getLogger().info("[VcsV2] start auto save!"); + VcsHelper.getInstance().startAutoSave(autoSaveIntervalEditor.getValue()); + } else { + VcsHelper.getInstance().stopAutoSave(); + } + if (useVcsAutoCleanScheduleCheckBox.isEnabled()) { + if (useVcsAutoCleanScheduleCheckBox.isSelected()) { + FineLoggerFactory.getLogger().info("[VcsV2] start auto clean!"); + WorkContext.getCurrent().get(VcsAutoCleanOperator.class).addOrUpdateVcsAutoCleanJob( + VcsAutoCleanService.VCS_AUTO_CLEAN_JOB_NAME, + getDay(autoCleanIntervalComboBox.getSelectedIndex()), + VcsAutoCleanSchedule.class); + } else { + WorkContext.getCurrent().get(VcsAutoCleanOperator.class).stopVcsAutoCleanJob(VcsAutoCleanService.VCS_AUTO_CLEAN_JOB_NAME); + } + } + } + return null; + } + }.execute(); + } + // 如果语言设置改变了,则显示重启对话框 public void showRestartDialog() { if (!languageChanged) { @@ -1045,12 +1275,14 @@ public class PreferencePane extends BasicPane { @Override public BasicDialog showWindow(Window window) { - return showWindow(window, new DialogActionAdapter() { + basicDialog = showWindow(window, new DialogActionAdapter() { @Override public void doOk() { languageChanged = !ComparatorUtils.equals(languageComboBox.getSelectedItem(), DesignerEnvManager.getEnvManager(false).getLanguage()); } }); + movePanel.setParentDialog(basicDialog); + return basicDialog; } @Override diff --git a/designer-base/src/main/java/com/fr/design/actions/file/SwitchExistEnv.java b/designer-base/src/main/java/com/fr/design/actions/file/SwitchExistEnv.java index 33761a92e2..1a421c5fd0 100644 --- a/designer-base/src/main/java/com/fr/design/actions/file/SwitchExistEnv.java +++ b/designer-base/src/main/java/com/fr/design/actions/file/SwitchExistEnv.java @@ -7,6 +7,7 @@ import com.fr.design.env.DesignerWorkspaceInfo; import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.SaveSomeTemplatePane; import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.vcs.ui.VcsMovingExitOption; import com.fr.design.menu.KeySetUtils; import com.fr.design.menu.MenuDef; import com.fr.design.menu.SeparatorDef; @@ -60,6 +61,11 @@ public class SwitchExistEnv extends MenuDef { * @param e 事件 */ public void actionPerformed(ActionEvent e) { + //检查是否正在迁移,如果正在迁移就弹出弹窗让用户选择 + if (!VcsMovingExitOption.ShowDialogAndConfirmSwitch()) { + //如果用户选择取消切换环境则返回,不然说明用户就是想切换,则往下走 + return; + } final String envName = getName(); DesignerEnvManager envManager = DesignerEnvManager.getEnvManager(); DesignerWorkspaceInfo selectedEnv = envManager.getWorkspaceInfo(envName); @@ -68,7 +74,7 @@ public class SwitchExistEnv extends MenuDef { EnvChangeEntrance.getInstance().chooseEnv(envName); } else { SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true); - if (saveSomeTemplatePane.showSavePane()) { + if (saveSomeTemplatePane.showSavePane(true)) { // 用户模板保存后,才进行切换目录操作 EnvChangeEntrance.getInstance().switch2Env(envName); } diff --git a/designer-base/src/main/java/com/fr/design/actions/file/export/AbstractExportAction.java b/designer-base/src/main/java/com/fr/design/actions/file/export/AbstractExportAction.java index d8b7b81ab2..f62243a8c4 100644 --- a/designer-base/src/main/java/com/fr/design/actions/file/export/AbstractExportAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/file/export/AbstractExportAction.java @@ -136,7 +136,7 @@ public abstract class AbstractExportAction> extends JT int returnVal = FineJOptionPane.showConfirmDialog( DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Utils_Would_You_Like_To_Save") + " \"" + e.getEditingFILE() + "\" ?", - Toolkit.i18nText("Fine-Design_Basic_Confirm"), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE ); diff --git a/designer-base/src/main/java/com/fr/design/actions/help/FineUIAction.java b/designer-base/src/main/java/com/fr/design/actions/help/FineUIAction.java index 0839c14767..3037322275 100644 --- a/designer-base/src/main/java/com/fr/design/actions/help/FineUIAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/help/FineUIAction.java @@ -3,14 +3,15 @@ package com.fr.design.actions.help; import com.fr.design.actions.UpdateAction; import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.DialogActionAdapter; +import com.fr.design.jxbrowser.JxUIPane; import com.fr.design.mainframe.DesignerContext; -import com.fr.design.ui.ModernUIPane; import com.fr.locale.InterProviderFactory; import com.fr.web.struct.AssembleComponent; import com.fr.web.struct.Atom; import com.fr.web.struct.browser.RequestClient; import com.fr.web.struct.category.ScriptPath; import com.fr.web.struct.impl.FineUI; +import com.teamdev.jxbrowser.js.JsAccessible; import java.awt.event.ActionEvent; @@ -27,14 +28,8 @@ public class FineUIAction extends UpdateAction { @Override public void actionPerformed(final ActionEvent e) { - ModernUIPane pane = new ModernUIPane.Builder<>() -// .prepare(new ScriptContextAdapter() { -// @Override -// public void onScriptContextCreated(ScriptContextEvent event) { -// JSValue pool = event.getBrowser().executeJavaScriptAndReturnValue("window.Pool"); -// pool.asObject().setProperty("i18n", new I18n()); -// } -// }) + JxUIPane pane = new JxUIPane.Builder<>() + .bindNamespace("i18n", new I18n()) .withComponent(new AssembleComponent() { @Override @@ -44,20 +39,21 @@ public class FineUIAction extends UpdateAction { @Override public Atom[] refer() { - return new Atom[] {FineUI.KEY}; + return new Atom[]{FineUI.KEY}; } }) .build(); - BasicDialog dialog = pane.showLargeWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { + BasicDialog dialog = pane.showLargeWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { @Override public void doOk() { // Do nothing } }); - dialog.setVisible(true); + dialog.setVisible(true); } + @JsAccessible public static class I18n { public String i18nText(String key) { diff --git a/designer-base/src/main/java/com/fr/design/actions/help/SystemInfoPane.java b/designer-base/src/main/java/com/fr/design/actions/help/SystemInfoPane.java index c51fc24a35..06bf05a920 100644 --- a/designer-base/src/main/java/com/fr/design/actions/help/SystemInfoPane.java +++ b/designer-base/src/main/java/com/fr/design/actions/help/SystemInfoPane.java @@ -41,16 +41,12 @@ public class SystemInfoPane extends JPanel { for (int i = 0; i < keys.length; i++) { Object[] tableRowData = new Object[2]; String keyValue = keys[i].toString(); - // james:屏蔽掉exe4j的内容 - if (keyValue.indexOf("exe4j") != -1) { - continue; - } - // james:这个也是exe4j的东东 - if ("install4j.exeDir".equals(keyValue)) { + + if (needToShield(keyValue)) { continue; } - if(keyValue.indexOf("FineReport") != -1){ + if(keyValue.contains("FineReport")){ keys[i] = keyValue.replaceAll("FineReport", ProductConstants.APP_NAME); } @@ -66,4 +62,14 @@ public class SystemInfoPane extends JPanel { add(new JScrollPane(table), BorderLayout.CENTER); } + + /** + * 是否属于需要屏蔽的内容(当前屏蔽掉exe4j与jxbrowser的内容) + * + * @param keyValue 对应的key值 + * @return 需要屏蔽则返回true + */ + private boolean needToShield(String keyValue) { + return keyValue.contains("exe4j") || keyValue.contains("jxbrowser") || "install4j.exeDir".equals(keyValue); + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/actions/help/TutorialAction.java b/designer-base/src/main/java/com/fr/design/actions/help/TutorialAction.java index f185323b8c..faf0614533 100644 --- a/designer-base/src/main/java/com/fr/design/actions/help/TutorialAction.java +++ b/designer-base/src/main/java/com/fr/design/actions/help/TutorialAction.java @@ -1,9 +1,9 @@ package com.fr.design.actions.help; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.i18n.Toolkit; import com.fr.design.login.AbstractDesignerSSO; import com.fr.design.menu.MenuKeySet; -import com.fr.general.CloudCenter; import com.fr.general.GeneralContext; import com.fr.general.http.HttpToolbox; import com.fr.stable.CommonUtils; @@ -18,6 +18,16 @@ import java.awt.event.KeyEvent; public class TutorialAction extends AbstractDesignerSSO { + /** + * 云中心社区帮助文档在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Help"; + + /** + * 云中心社区帮助文档默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Help_Default"; + public TutorialAction() { this.setMenuKeySet(HELP_TUTORIAL); this.setName(getMenuKeySet().getMenuName()); @@ -28,7 +38,7 @@ public class TutorialAction extends AbstractDesignerSSO { @Override public String getJumpUrl() { - return CloudCenter.getInstance().acquireUrlByKind(createDocKey(), "http://help.finereport.com"); + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); } // 生成帮助文档 sitecenter key, help.zh_CN.10 diff --git a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/RemindPane.java b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/RemindPane.java index 1d8d99266e..aeab19aca3 100644 --- a/designer-base/src/main/java/com/fr/design/actions/help/alphafine/RemindPane.java +++ b/designer-base/src/main/java/com/fr/design/actions/help/alphafine/RemindPane.java @@ -4,10 +4,21 @@ import com.fr.design.dialog.UIDialog; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ilable.UILabel; import com.fr.general.IOUtils; - - -import javax.swing.*; -import java.awt.*; +import com.fr.general.locale.image.I18nImage; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.LayoutManager; +import java.awt.Rectangle; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -23,8 +34,10 @@ public class RemindPane extends JPanel { private Icon checkIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/check.png"); private Icon unCheckIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/uncheck.png"); private Icon closeIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/remind_close.png"); - private Icon labelIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/remind.png"); - private Icon openIcon = IOUtils.readIcon("com/fr/design/mainframe/alphafine/images/open.png"); + private static final String REMIND_IMAGE_URL = "/com/fr/design/mainframe/alphafine/images/open/open.png"; + private Icon labelIcon = new ImageIcon(I18nImage.getImage(REMIND_IMAGE_URL)); + private static final String OPEN_IMAGE_URL = "/com/fr/design/mainframe/alphafine/images/open/open.png"; + private final Icon openIcon = new ImageIcon(I18nImage.getImage(OPEN_IMAGE_URL)); private static final int WIDTH = 600; private static final int HEIGHT = 400; diff --git a/designer-base/src/main/java/com/fr/design/components/table/TablePanel.java b/designer-base/src/main/java/com/fr/design/components/table/TablePanel.java index 317a171954..b2e8ceb35a 100644 --- a/designer-base/src/main/java/com/fr/design/components/table/TablePanel.java +++ b/designer-base/src/main/java/com/fr/design/components/table/TablePanel.java @@ -161,6 +161,20 @@ public class TablePanel extends JPanel { } cellPanel.add(component); } + + /** + * 为单元格Panel更新tooltip + * + * @param row 行数 + * @param column 列数 + * @param value tooltip值 + */ + public void updateCellToolTip(int row, int column, String value) { + int x = row - 1; + int y = column - 1; + JPanel cellPanel = this.cellPanels[x][y]; + cellPanel.setToolTipText(value); + } public void updateCell(int row, int column, String value) { diff --git a/designer-base/src/main/java/com/fr/design/condition/LiteConditionPane.java b/designer-base/src/main/java/com/fr/design/condition/LiteConditionPane.java index 98f5f36530..82c8ec340f 100644 --- a/designer-base/src/main/java/com/fr/design/condition/LiteConditionPane.java +++ b/designer-base/src/main/java/com/fr/design/condition/LiteConditionPane.java @@ -224,7 +224,7 @@ public abstract class LiteConditionPane extends BasicBeanPa } int returnVal = FineJOptionPane.showConfirmDialog(SwingUtilities.getWindowAncestor(LiteConditionPane.this), - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Are_You_Sure_To_Remove_The_Selected_Item") + "?", com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Remove"), + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Are_You_Sure_To_Remove_The_Selected_Item") + "?", com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.OK_CANCEL_OPTION); if (returnVal == JOptionPane.OK_OPTION) { DefaultTreeModel treeModel = (DefaultTreeModel) conditionsTree.getModel(); diff --git a/designer-base/src/main/java/com/fr/design/constants/DesignerLaunchStatus.java b/designer-base/src/main/java/com/fr/design/constants/DesignerLaunchStatus.java index 4720c8e103..9e50551cfc 100644 --- a/designer-base/src/main/java/com/fr/design/constants/DesignerLaunchStatus.java +++ b/designer-base/src/main/java/com/fr/design/constants/DesignerLaunchStatus.java @@ -11,6 +11,11 @@ import com.fr.event.Null; * @date 2019-06-18 */ public enum DesignerLaunchStatus implements Event { + /** + * 界面前置事件初始化完成 + */ + UI_PRE_INIT_COMPLETE, + /** * 初始化环境完成 */ @@ -46,4 +51,14 @@ public enum DesignerLaunchStatus implements Event { status = state; EventDispatcher.fire(DesignerLaunchStatus.getStatus()); } + + /** + * 设置状态并异步触发事件 + * + * @param state 当前启动状态 + */ + public static void setStatusAndAsyncFire(DesignerLaunchStatus state) { + status = state; + EventDispatcher.asyncFire(DesignerLaunchStatus.getStatus()); + } } diff --git a/designer-base/src/main/java/com/fr/design/constants/UIConstants.java b/designer-base/src/main/java/com/fr/design/constants/UIConstants.java index da05a79dd5..eba4a5634a 100644 --- a/designer-base/src/main/java/com/fr/design/constants/UIConstants.java +++ b/designer-base/src/main/java/com/fr/design/constants/UIConstants.java @@ -153,10 +153,10 @@ public interface UIConstants { public static final BufferedImage DRAG_BAR = IOUtils.readImage("com/fr/design/images/control/bar.png"); public static final BufferedImage DRAG_BAR_LIGHT = IOUtils.readImage("com/fr/design/images/control/bar-light.png"); - public static final BufferedImage ARROW_NORTH = IOUtils.readImage("com/fr/design/images/control/up_arrow.png"); - public static final BufferedImage ARROW_SOUTH = IOUtils.readImage("com/fr/design/images/control/down_arrow.png"); - public static final BufferedImage ARROW_EAST = IOUtils.readImage("com/fr/design/images/control/east_arrow.png"); - public static final BufferedImage ARROW_WEST = IOUtils.readImage("com/fr/design/images/control/west_arrow.png"); + public static final Image ARROW_NORTH = SVGLoader.load("/com/fr/design/standard/arrowlinear/up_arrow.svg"); + public static final Image ARROW_SOUTH = SVGLoader.load("/com/fr/design/standard/arrowlinear/down_arrow.svg"); + public static final Image ARROW_EAST = SVGLoader.load("/com/fr/design/standard/arrowlinear/east_arrow.svg"); + public static final Image ARROW_WEST = SVGLoader.load("/com/fr/design/standard/arrowlinear/west_arrow.svg"); public static final BufferedImage DRAG_BAR_RIGHT = IOUtils.readImage("com/fr/design/images/control/barm.png"); public static final BufferedImage DRAG_BAR_LEFT = IOUtils.readImage("com/fr/design/images/control/barl.png"); @@ -172,24 +172,24 @@ public interface UIConstants { public static final Image DRAG_LINE = SVGLoader.load("/com/fr/design/standard/dot_line_normal.svg"); public static final BufferedImage ACCESSIBLE_EDITOR_DOT = IOUtils.readImage("com/fr/design/images/control/dot.png"); public static final BufferedImage DRAG_DOT_VERTICAL = IOUtils.readImage("com/fr/design/images/control/dotv.png"); - public static final BufferedImage POP_BUTTON_DOWN = IOUtils.readImage("com/fr/design/images/buttonicon/popdownarrow.png"); - public static final BufferedImage POP_BUTTON_UP = IOUtils.readImage("com/fr/design/images/buttonicon/popuparrow.png"); + public static final Image POP_BUTTON_DOWN = SVGLoader.load("/com/fr/design/standard/poparrow/pop_down_arrow.svg"); + public static final Image POP_BUTTON_UP = SVGLoader.load("/com/fr/design/standard/poparrow/pop_up_arrow.svg"); public static final BufferedImage DRAG_DOWN_SELECTED_SMALL = IOUtils.readImage("com/fr/design/images/buttonicon/downSelected.png"); public static final BufferedImage DRAG_LEFT_NORMAL_SMALL = IOUtils.readImage("com/fr/design/images/buttonicon/leftNormal.png"); public static final BufferedImage WATERMARK_BACKGROUND = IOUtils.readImage("/com/fr/design/images/dialog/watermark/" + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_WaterMark_Background_Icon_File_Name")); public static final int MODEL_NORMAL = 0; public static final int MODEL_PRESS = 1; - public static final Icon ARROW_DOWN_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/arrowdown.png"); + public static final Icon ARROW_DOWN_ICON = IconUtils.readIcon("/com/fr/design/standard/arrowlinear/down_arrow.svg"); public static final Icon ARROW_UP_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/arrowup.png"); public static final Icon YES_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/yes.png"); public static final Icon CHOOSEN_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/select_item.png"); public static final Icon PRE_WIDGET_ICON = IOUtils.readIcon("com/fr/design/images/buttonicon/prewidget.png"); public static final Icon PRE_WIDGET_NORMAL_ICON = IconUtils.readIcon("com/fr/design/images/buttonicon/prewidget"); public static final Icon EDIT_NORMAL_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/edit"); - public static final Icon EDIT_PRESSED_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/edit"); + public static final Icon EDIT_PRESSED_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/edit_pressed.svg"); public static final Icon HIDE_NORMAL_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/hide"); - public static final Icon HIDE_PRESSED_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/hide"); + public static final Icon HIDE_PRESSED_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/hide_pressed.svg"); public static final Icon VIEW_NORMAL_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/view"); //public static final Icon VIEW_PRESSED_ICON = IconUtils.readIcon("/com/fr/design/standard/uimode/view"); @@ -221,7 +221,7 @@ public interface UIConstants { public static final int BUTTON_GROUP_ARC = 0; public static final int LARGEARC = 6; public static final Stroke BS = new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 2f, new float[]{3, 1}, 0); - public static final Icon PREVIEW_DOWN = IOUtils.readIcon("com/fr/design/images/buttonicon/prevew_down_icon.png"); + public static final Icon PREVIEW_DOWN = IconUtils.readIcon("/com/fr/design/standard/preview_down_icon"); public static final Icon CLOSE_OF_AUTHORITY = IOUtils.readIcon("/com/fr/design/images/m_report/close.png"); public static final Icon CLOSE_OVER_AUTHORITY = IOUtils.readIcon("/com/fr/design/images/m_report/close_over.png"); public static final Icon CLOSE_PRESS_AUTHORITY = IOUtils.readIcon("/com/fr/design/images/m_report/close_press.png"); diff --git a/designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java b/designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java index b3a076a92b..af9850172b 100644 --- a/designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java +++ b/designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java @@ -5,14 +5,17 @@ import com.fr.base.TableData; import com.fr.base.svg.IconUtils; import com.fr.data.MultiResultTableData; import com.fr.data.TableDataSource; +import com.fr.data.impl.DBTableData; import com.fr.design.DesignModelAdapter; import com.fr.design.actions.UpdateAction; import com.fr.design.data.datapane.TableDataCreatorProducer; import com.fr.design.data.datapane.TableDataNameObjectCreator; import com.fr.design.data.datapane.TableDataSourceOP; import com.fr.design.data.datapane.TableDataTree; +import com.fr.design.data.datapane.auth.TableDataAuthHelper; import com.fr.design.data.tabledata.ResponseDataSourceChange; import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane; +import com.fr.design.data.tabledata.tabledatapane.loading.TableDataLoadingPane; import com.fr.design.data.tabledata.wrapper.MultiResultTableDataWrapper; import com.fr.design.data.tabledata.wrapper.TableDataWrapper; import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper; @@ -42,6 +45,8 @@ import javax.swing.DefaultCellEditor; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; import javax.swing.tree.TreeCellEditor; @@ -51,6 +56,7 @@ import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.util.Collection; import java.util.EventObject; import java.util.HashMap; import java.util.HashSet; @@ -449,7 +455,45 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp storeProcedureDataWrapper.previewData(MultiResultTableDataWrapper.PREVIEW_ALL); } } else { - ((TableDataWrapper) data).previewData(); + TableDataWrapper wrapper = ((TableDataWrapper) data); + if (TableDataAuthHelper.needCheckAuthWhenEdit(wrapper.getTableData())) { + // 先打开一个Loading面板 + TableDataLoadingPane loadingPane = new TableDataLoadingPane(); + BasicDialog loadingDialog = loadingPane.showLargeWindow(SwingUtilities.getWindowAncestor(BasicTableDataTreePane.this), null); + // 查询权限 + new SwingWorker() { + @Override + protected Boolean doInBackground() throws Exception { + // 获取无权限连接名称集合 + Collection noAuthConnections = TableDataAuthHelper.getNoAuthConnections(); + // 获取当前数据集对应的数据连接名称 + String connectionName = TableDataAuthHelper.getConnectionNameByDBTableData((DBTableData) wrapper.getTableData()); + return !noAuthConnections.contains(connectionName); + } + + @Override + protected void done() { + try { + Boolean hasAuth = get(); + if (hasAuth) { + // 有权限时,关闭Loading面板,打开编辑面板 + loadingDialog.setVisible(false); + wrapper.previewData(); + } else { + // 无权限时,给出无权限提示 + loadingPane.switchTo(TableDataLoadingPane.NO_AUTH_PANE_NAME); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error("loading connection error in remote design", e.getMessage()); + // 查询权限失败时,给出报错提示 + loadingPane.switchTo(TableDataLoadingPane.ERROR_NAME); + } + } + }.execute(); + loadingDialog.setVisible(true); + } else { + wrapper.previewData(); + } } } catch (Exception ex) { diff --git a/designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java b/designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java index 4b3b058cf8..9c049c5c33 100644 --- a/designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java +++ b/designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java @@ -33,6 +33,7 @@ import com.fr.file.ProcedureConfig; import com.fr.general.ComparatorUtils; import com.fr.general.data.DataModel; import com.fr.general.data.TableDataException; +import com.fr.general.sql.sqlnote.SqlNoteConstants; import com.fr.log.FineLoggerFactory; import com.fr.script.Calculator; import com.fr.stable.ArrayUtils; @@ -573,6 +574,7 @@ public abstract class DesignTableDataManager { parameter.setValue(parameterMap.get(parameter.getName())); } } + addTemplateInfoIfNeed(parameterMap); PreviewSourceBean bean = new PreviewSourceBean(); TableDataSource source = TableDataSourceTailor.extractTableData(tableDataSource); bean.setDataSource(source); @@ -605,6 +607,12 @@ public abstract class DesignTableDataManager { } } + private static void addTemplateInfoIfNeed(Map parameterMap) { + if (JTemplate.isValid(HistoryTemplateListCache.getInstance().getCurrentEditingTemplate())) { + parameterMap.put(SqlNoteConstants.SQL_NOTE_TEMPLATE, HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getEditingFILE().getPath()); + } + } + private static boolean checkBean(PreviewSourceBean bean) { // dataName为空说明是新建的,得用tabledata传 return !bean.getDataName().isEmpty(); @@ -687,6 +695,7 @@ public abstract class DesignTableDataManager { if (needLoadingBar) { MultiResultTableDataWrapper.loadingBar.start(); } + addTemplateInfoIfNeed(parameterMap); return DataOperator.getInstance().previewMultiResultTableData(tableData, parameterMap, 0); } diff --git a/designer-base/src/main/java/com/fr/design/data/MapCompareUtils.java b/designer-base/src/main/java/com/fr/design/data/MapCompareUtils.java deleted file mode 100644 index 331e980834..0000000000 --- a/designer-base/src/main/java/com/fr/design/data/MapCompareUtils.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.fr.design.data; - -import org.jetbrains.annotations.NotNull; - -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * @author rinoux - * @version 10.0 - * Created by rinoux on 2022/3/28 - */ -public final class MapCompareUtils { - - - /** - * 对比两个map 查找出相比orig,other中有哪些是新增的、删除的或者被修改的,并分别进行处理 - * - * 对比时默认用equals方法来判断是否为 EntryEventKind#UPDATED - * - * @param orig 原始map - * @param other 参考的新map - * @param eventHandler 有区别时的事件处理器 - * @param K - * @param V - */ - public static void contrastMapEntries(@NotNull Map orig, @NotNull Map other, @NotNull EventHandler eventHandler) { - - contrastMapEntries(orig, other, eventHandler, UpdateRule.DEFAULT); - } - - /** - * 对比两个map 查找出相比orig,other中有哪些是新增的、删除的或者被修改的,并分别进行处理 - * - * 对比时用自定义的规则来判断是否为 EntryEventKind#UPDATED - * - * @param orig 原始map - * @param other 参考的新map - * @param eventHandler 有区别时的事件处理器 - * @param updateRule 自定义的Update事件判定规则 - * @param - * @param - */ - public static void contrastMapEntries(@NotNull Map orig, @NotNull Map other, @NotNull EventHandler eventHandler, @NotNull UpdateRule updateRule) { - - Map copiedOrig = new LinkedHashMap<>(orig); - - other.forEach((k, v) -> { - V existedV = copiedOrig.remove(k); - if (existedV != null) { - if (updateRule.needUpdate(existedV, v)) { - eventHandler.on(EntryEventKind.UPDATED, k, v); - } - } else { - eventHandler.on(EntryEventKind.ADDED, k, v); - } - }); - - copiedOrig.forEach((k, v) -> eventHandler.on(EntryEventKind.REMOVED, k, v)); - } - - - /** - * 事件处理器,对应比较后的三种结果的事件处理 - * @param - * @param - */ - public interface EventHandler { - void on(EntryEventKind entryEventKind, K k, V v); - } - - /** - * 数据被修改(EntryEventKind.UPDATED) 的判定规则 - * @param - * @param - */ - public interface UpdateRule { - - EntryEventKind eventKind = EntryEventKind.UPDATED; - - UpdateRule DEFAULT = new UpdateRule() {}; - - default boolean needUpdate(V origin, V v) { - return !v.equals(origin); - } - } - - public enum EntryEventKind { - ADDED, - REMOVED, - UPDATED; - } -} diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java index 47b1d4d247..a58317c15f 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/ChoosePane.java @@ -357,7 +357,6 @@ public class ChoosePane extends BasicBeanPane implements Refresha */ @Override public void refresh() { - DBUtils.refreshDatabase(); String schema = StringUtils.isEmpty(schemaBox.getSelectedItem()) ? null : schemaBox.getSelectedItem(); DataCoreUtils.refreshTables(getConnection(), TableProcedure.TABLE, schema); FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Refresh_Successfully") + "!", com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Refresh_Database"), diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/ESDStrategyConfigPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/ESDStrategyConfigPane.java index 4cbf4eb540..9d9ce6524b 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/ESDStrategyConfigPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/ESDStrategyConfigPane.java @@ -6,6 +6,7 @@ import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.ilable.ActionLabel; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.esd.common.CacheConstants; @@ -30,8 +31,8 @@ import java.net.URI; import java.text.ParseException; import java.util.ArrayList; import java.util.Collections; -import java.util.List; import java.util.Date; +import java.util.List; /** * @author rinoux @@ -39,7 +40,18 @@ import java.util.Date; * Created by rinoux on 2020/7/22 */ public class ESDStrategyConfigPane extends BasicBeanPane { - private static final String CRON_HELP_URL = "http://help.fanruan.com/finereport/doc-view-693.html"; + + /** + * 云中心定时调度执行频率表达式设定帮助文档链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Cron_Help"; + + /** + * 云中心定时调度执行频率表达式设定帮助文档默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Cron_Help_Default"; + + private static final String CRON_HELP_URL = LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); private UIRadioButton selectAutoUpdate; private UIRadioButton selectBySchema; private UICheckBox shouldEvolve; diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java index 39774e4d70..89825196b5 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java @@ -233,17 +233,7 @@ public class TableDataPaneListPane extends JListControlPane implements TableData @Override public void update(Map tableDataMap) { - Nameable[] tableDataArray = this.update(); - List tableDataBeans = new ArrayList<>(); - Map map = MapUtils.invertMap(getDsNameChangedMap()); - for (int i = 0; i < tableDataArray.length; i++) { - NameObject nameObject = (NameObject) tableDataArray[i]; - String oldName = map.get(nameObject.getName()); - if (oldName == null) { - oldName = StringUtils.EMPTY; - } - tableDataBeans.add(new TableDataBean(nameObject.getName(), oldName, (TableData) nameObject.getObject())); - } + List tableDataBeans = getUpdateTableDataBeans(); try { WorkContext.getCurrent().get(TableDataOperator.class, new ExceptionHandler() { @Override @@ -257,6 +247,25 @@ public class TableDataPaneListPane extends JListControlPane implements TableData } } + /** + * 获取更新时的数据集快照 + * + * @return 快照 + */ + private List getUpdateTableDataBeans() { + Nameable[] tableDataArray = this.update(); + List tableDataBeans = new ArrayList<>(); + Map map = MapUtils.invertMap(getDsNameChangedMap()); + for (int i = 0; i < tableDataArray.length; i++) { + NameObject nameObject = (NameObject) tableDataArray[i]; + String oldName = map.get(nameObject.getName()); + if (oldName == null) { + oldName = StringUtils.EMPTY; + } + tableDataBeans.add(new TableDataBean(nameObject.getName(), oldName, (TableData) nameObject.getObject())); + } + return tableDataBeans; + } private boolean saveByOldWay(List tableDataBean) { try { return TableDataOperatorImpl.getInstance().saveTableData(tableDataBean); diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java index 57ad09d0e7..149fa87dc2 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java @@ -229,7 +229,7 @@ public class TableDataTreePane extends BasicTableDataTreePane { private TreeSearchToolbarPane initToolBarPane() { // toolbar addMenuDef = new MenuDef(Toolkit.i18nText("Fine-Design_Basic_Action_Add")); - addMenuDef.setIconPath("/com/fr/design/standard/addpopup/addPopup"); + addMenuDef.setDisabledIcon("/com/fr/design/standard/addpopup/addPopup", true); createAddMenuDef(); // 创建插件监听 createPluginListener(); diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java index 613eed9a48..79e75a0b83 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionTableProcedurePane.java @@ -21,6 +21,7 @@ import com.fr.general.GeneralContext; import com.fr.stable.ArrayUtils; import javax.swing.BorderFactory; +import javax.swing.DefaultComboBoxModel; import javax.swing.JPanel; import javax.swing.ToolTipManager; import javax.swing.event.DocumentEvent; @@ -109,6 +110,8 @@ public class ConnectionTableProcedurePane extends BasicPane { if (parent != null) { parent.switchTo(SwitchableTableDataPane.CONTENT_PANE_NAME); } + DefaultComboBoxModel model = ((DefaultComboBoxModel) itemComboBox.getModel()); + model.removeElement(EMPTY); } @Override diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/DBCPAttrPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/DBCPAttrPane.java index 86e7633be0..ebfd195d8e 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/DBCPAttrPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/DBCPAttrPane.java @@ -1,6 +1,7 @@ package com.fr.design.data.datapane.connect; import com.fr.base.GraphHelper; +import com.fr.data.core.db.dialect.DialectFactory; import com.fr.data.impl.JDBCDatabaseConnection; import com.fr.data.pool.DBCPConnectionPoolAttr; import com.fr.design.dialog.BasicDialog; @@ -31,6 +32,7 @@ import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -43,7 +45,7 @@ public class DBCPAttrPane extends BasicPane { private static final int ORACLE_DEFAULT_FETCHSIZE = 128; private static final int DB2_DEFAULT_FETCHSIZE = 50; private static final int POSTGRE_DEFAULT_FETCHSIZE = 10000; - private static final int EMPTY_FETCHSIZE = -2; + private static final int INVALID_FETCHSIZE = -1; // carl:DBCP的一些属性 private IntegerEditor DBCP_INITIAL_SIZE = new IntegerEditor(); private IntegerEditor DBCP_MIN_IDLE = new IntegerEditor(); @@ -114,12 +116,25 @@ public class DBCPAttrPane extends BasicPane { this.DBCP_MINEVICTABLEIDLETIMEMILLIS.setValue(dbcpAttr.getMinEvictableIdleTimeMillis() / TIME_MULTIPLE); this.DBCP_NUMTESTSPEREVICTIONRUN.setValue(dbcpAttr.getNumTestsPerEvictionRun()); this.DBCP_TIMEBETWEENEVICTIONRUNSMILLS.setValue(dbcpAttr.getTimeBetweenEvictionRunsMillis()); - Integer fetchSize = DEFAULT_FETCHSIZE_MAP.get(JDBCConnectionDef.getInstance().getDatabaseName()); - if (fetchSize != null) { - if (jdbcDatabase.getFetchSize() == EMPTY_FETCHSIZE) { - this.FETCHSIZE.setText(StringUtils.EMPTY); + + /* + * 填充FetchSize输入框逻辑: + * + * 1. 如果JDBCDatabaseConnection里的fetchSize是有效值(>0),则显示该有效值 + * 2. 如果JDBCDatabaseConnection里的fetchSize是无效值(<=0): + * 2.1 如果我们对这种数据库有默认值(如oracle、db2、pgsql),就显示对应数据库的默认值,因为要避免性能问题,这几种数据库不支持关闭fetchSize + * 2.2 如果我们对这种数据库无默认值,就显示-1 + */ + + int fetchSize = jdbcDatabase.getFetchSize(); + String databaseName = JDBCConnectionDef.getInstance().getDatabaseName(); + if (DialectFactory.isValidFetchSize(fetchSize)) { + this.FETCHSIZE.setText(String.valueOf(fetchSize)); + } else { + if (DEFAULT_FETCHSIZE_MAP.containsKey(databaseName)) { + this.FETCHSIZE.setText(String.valueOf(DEFAULT_FETCHSIZE_MAP.get(databaseName))); } else { - this.FETCHSIZE.setText(jdbcDatabase.getFetchSize() == -1 ? String.valueOf(fetchSize) : String.valueOf(jdbcDatabase.getFetchSize())); + this.FETCHSIZE.setText(String.valueOf(INVALID_FETCHSIZE)); } } } @@ -137,12 +152,34 @@ public class DBCPAttrPane extends BasicPane { dbcpAttr.setMinEvictableIdleTimeMillis(((Number) this.DBCP_MINEVICTABLEIDLETIMEMILLIS.getValue()).intValue() * TIME_MULTIPLE); dbcpAttr.setNumTestsPerEvictionRun(((Number) this.DBCP_NUMTESTSPEREVICTIONRUN.getValue()).intValue()); dbcpAttr.setTimeBetweenEvictionRunsMillis(((Number) this.DBCP_TIMEBETWEENEVICTIONRUNSMILLS.getValue()).intValue()); - Integer fetchSize = DEFAULT_FETCHSIZE_MAP.get(JDBCConnectionDef.getInstance().getDatabaseName()); - if (fetchSize != null) { - if (StringUtils.isEmpty(this.FETCHSIZE.getText())) { - jdbcDatabase.setFetchSize(EMPTY_FETCHSIZE); + + /* + * FetchSize设置逻辑: + * + * 1. 如果客户界面上的fetchSize框留空: + * 1.1 如果我们对这种数据库有默认值(如oracle、db2、pgsql),就存对应数据库的默认值,否则会有性能问题,这几种数据库我们是不支持关闭fetchSize的 + * 1.2 如果我们对这种数据库没有默认值,就置为-1 + * 2. 如果客户界面上的fetchSize框非空: + * 2.1 如果fetchSize是个有效值(>0),就使用该值 + * 2.2 如果fetchSize是个无效值(<=0),就置为-1 + * + * -1带来的结果,就是我们Dialect不会putExecutor,最终不会执行java.sql.Statement.setFetchSize + */ + String fetchSizeText = this.FETCHSIZE.getText(); + String databaseName = JDBCConnectionDef.getInstance().getDatabaseName(); + + if (StringUtils.isEmpty(fetchSizeText)) { + if (DEFAULT_FETCHSIZE_MAP.containsKey(databaseName)) { + Optional.ofNullable(DEFAULT_FETCHSIZE_MAP.get(databaseName)).ifPresent(jdbcDatabase::setFetchSize); + } else { + jdbcDatabase.setFetchSize(INVALID_FETCHSIZE); + } + } else { + int fetchSizeSet = Integer.parseInt(fetchSizeText); + if (DialectFactory.isValidFetchSize(fetchSizeSet)) { + jdbcDatabase.setFetchSize(fetchSizeSet); } else { - jdbcDatabase.setFetchSize(Integer.parseInt(this.FETCHSIZE.getText())); + jdbcDatabase.setFetchSize(INVALID_FETCHSIZE); } } } diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/connect/DatabaseConnectionPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/connect/DatabaseConnectionPane.java index be7ea004a1..d857ec14a4 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/connect/DatabaseConnectionPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/connect/DatabaseConnectionPane.java @@ -446,6 +446,7 @@ public abstract class DatabaseConnectionPane dataMaskMark = LocaleCenter.getMark(DataMaskMark.class); + URL url = new URL(dataMaskMark.getValue()); Desktop.getDesktop().browse(url.toURI()); } catch (Exception e) { FineLoggerFactory.getLogger().error(e, "open browse of table data desensitization help document failed for {}", e.getMessage()); diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleChoosePane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleChoosePane.java index d37ed152d2..54b139a3dd 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleChoosePane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleChoosePane.java @@ -18,9 +18,13 @@ import com.fr.stable.StringUtils; import com.fr.stable.collections.CollectionUtils; import javax.swing.AbstractCellEditor; +import javax.swing.BorderFactory; +import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTable; +import javax.swing.SwingConstants; import javax.swing.SwingUtilities; +import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import java.awt.CardLayout; @@ -132,6 +136,16 @@ public class DesensitizationRuleChoosePane extends JPanel { this.setDefaultRenderer(DesensitizationRuleStatusPane.class, new DesensitizationRuleStatusPane()); this.createTable().getColumnModel().getColumn(0).setMaxWidth(20); this.createTable().getColumnModel().getColumn(3).setMaxWidth(60); + this.createTable().getColumnModel().getColumn(3).setHeaderRenderer(new DefaultTableCellRenderer() { + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JLabel headerLabel = new JLabel(value != null ? value.toString() : ""); + headerLabel.setToolTipText((String) value); + headerLabel.setHorizontalAlignment(SwingConstants.CENTER); + headerLabel.setBorder(BorderFactory.createMatteBorder(0, 0, 3, 0, new Color(216, 216, 216, 175))); + return headerLabel; + } + }); } @Override diff --git a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleEditPane.java b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleEditPane.java index 5a0515a59e..76b032ee3d 100644 --- a/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleEditPane.java +++ b/designer-base/src/main/java/com/fr/design/data/datapane/preview/desensitization/view/rule/DesensitizationRuleEditPane.java @@ -1,5 +1,7 @@ package com.fr.design.data.datapane.preview.desensitization.view.rule; +import com.fine.swing.ui.layout.Column; +import com.fine.swing.ui.layout.Layouts; import com.fr.data.desensitize.rule.base.DesensitizationCondition; import com.fr.data.desensitize.rule.base.DesensitizationRule; import com.fr.data.desensitize.rule.base.DesensitizationRuleSource; @@ -28,6 +30,10 @@ import java.awt.event.FocusListener; import java.util.Arrays; import java.util.Set; +import static com.fine.swing.ui.layout.Layouts.cell; +import static com.fine.swing.ui.layout.Layouts.column; +import static com.fine.swing.ui.layout.Layouts.row; + /** * 脱敏规则编辑页 * @@ -157,26 +163,29 @@ public class DesensitizationRuleEditPane extends BasicBeanPane column = column( + 4, + row( + cell(new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Part_One") + StringUtils.BLANK)), + cell(retainFrontTextField), + cell(new UILabel(StringUtils.BLANK + Toolkit.i18nText("Fine-Design_Report_Desensitization_Part_Two") + StringUtils.BLANK)), + cell(retainBackTextField), + cell(new UILabel(StringUtils.BLANK + Toolkit.i18nText("Fine-Design_Report_Desensitization_Part_Four") + StringUtils.BLANK)) + ), + row( + cell(new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_Part_Three") + StringUtils.BLANK)), + cell(firstSymbolTextField) + ) + ); // 整体替换 JPanel characterAllReplacePane = FRGUIPaneFactory.createLeftFlowZeroGapBorderPane(); UILabel allReplaceLabel = new UILabel(Toolkit.i18nText("Fine-Design_Report_Desensitization_All_Character_Replace_By") + StringUtils.BLANK); @@ -186,7 +195,7 @@ public class DesensitizationRuleEditPane extends BasicBeanPane implemen } private void checkParameter() { - String[] paramTexts = new String[2]; - paramTexts[0] = this.sqlTextPane.getText(); - paramTexts[1] = this.pageQuery; - Parameter[] parameters = ParameterHelper.analyze4Parameters(paramTexts, false); + Parameter[] parameters = getParameters(); if (parameters.length < 1 && this.editorPane.update().size() < 1) { return; @@ -443,6 +441,14 @@ public class DBTableDataPane extends AbstractTableDataPane implemen refreshParameters(); } + @NotNull + private Parameter[] getParameters() { + String[] paramTexts = new String[2]; + paramTexts[0] = SqlUtils.clearSqlComments(this.sqlTextPane.getText()); + paramTexts[1] = SqlUtils.clearSqlComments(this.pageQuery); + return ParameterHelper.analyze4Parameters(paramTexts, false); + } + @Override public void populateBean(DBTableData dbTableData) { this.dbTableData = dbTableData; diff --git a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/MultiTDTableDataPane.java b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/MultiTDTableDataPane.java index 4a153bfaac..66674f166a 100644 --- a/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/MultiTDTableDataPane.java +++ b/designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/MultiTDTableDataPane.java @@ -294,6 +294,7 @@ public class MultiTDTableDataPane extends AbstractTableDataPane imp "com.microsoft.sqlserver.jdbc.SQLServerDriver", "com.ibm.db2.jcc.DB2Driver", "com.mysql.jdbc.Driver", - "org.gjt.mm.mysql.Driver" + "org.gjt.mm.mysql.Driver", + "dm.jdbc.driver.DmDriver" }; // 需要隐藏面板的数据库的驱动 private static final String PREVIEW_BUTTON = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Preview"); private ConnectionTableProcedurePane connectionTableProcedurePane; diff --git a/designer-base/src/main/java/com/fr/design/dcm/UniversalDatabasePane.java b/designer-base/src/main/java/com/fr/design/dcm/UniversalDatabasePane.java index e29a9f6698..f195acaca1 100644 --- a/designer-base/src/main/java/com/fr/design/dcm/UniversalDatabasePane.java +++ b/designer-base/src/main/java/com/fr/design/dcm/UniversalDatabasePane.java @@ -1,12 +1,9 @@ package com.fr.design.dcm; import com.fr.design.dialog.BasicPane; -import com.fr.design.ui.ModernUIPane; -import com.teamdev.jxbrowser.chromium.JSValue; -import com.teamdev.jxbrowser.chromium.events.ScriptContextAdapter; -import com.teamdev.jxbrowser.chromium.events.ScriptContextEvent; +import com.fr.design.jxbrowser.JxUIPane; -import java.awt.*; +import java.awt.BorderLayout; /** * @author richie @@ -15,8 +12,6 @@ import java.awt.*; */ public class UniversalDatabasePane extends BasicPane { - private ModernUIPane modernUIPane; - @Override protected String title4PopupWindow() { return "Database"; @@ -24,15 +19,9 @@ public class UniversalDatabasePane extends BasicPane { public UniversalDatabasePane() { setLayout(new BorderLayout()); - modernUIPane = new ModernUIPane.Builder<>() + JxUIPane modernUIPane = new JxUIPane.Builder<>() .withComponent(UniversalDatabaseComponent.KEY) - .prepare(new ScriptContextAdapter() { - @Override - public void onScriptContextCreated(ScriptContextEvent event) { - JSValue window = event.getBrowser().executeJavaScriptAndReturnValue("window"); - window.asObject().setProperty("DcmHelper", UniversalDcmBridge.getBridge(event.getBrowser())); - } - }) + .bindWindow("DcmHelper", UniversalDcmBridge::getBridge) .build(); add(modernUIPane, BorderLayout.CENTER); } diff --git a/designer-base/src/main/java/com/fr/design/dcm/UniversalDcmBridge.java b/designer-base/src/main/java/com/fr/design/dcm/UniversalDcmBridge.java index 577acada97..3d569ea2c9 100644 --- a/designer-base/src/main/java/com/fr/design/dcm/UniversalDcmBridge.java +++ b/designer-base/src/main/java/com/fr/design/dcm/UniversalDcmBridge.java @@ -2,8 +2,8 @@ package com.fr.design.dcm; import com.fr.decision.webservice.bean.BaseBean; import com.fr.design.bridge.exec.JSBridge; -import com.teamdev.jxbrowser.chromium.Browser; -import com.teamdev.jxbrowser.chromium.JSObject; +import com.teamdev.jxbrowser.js.JsAccessible; +import com.teamdev.jxbrowser.js.JsObject; /** * @author richie @@ -11,20 +11,28 @@ import com.teamdev.jxbrowser.chromium.JSObject; * Created by richie on 2019-05-17 * 桥接Java和JavaScript的类 */ +@JsAccessible public class UniversalDcmBridge { - public static UniversalDcmBridge getBridge(Browser browser) { - return new UniversalDcmBridge(browser); + /** + * 获取 js-java bridge + * + * @param window 全局环境 + * @return bridge + */ + public static UniversalDcmBridge getBridge(JsObject window) { + return new UniversalDcmBridge(window); } - private JSObject window; + private JsObject window; - private UniversalDcmBridge(Browser browser) { - this.window = browser.executeJavaScriptAndReturnValue("window").asObject(); + private UniversalDcmBridge(JsObject window) { + this.window = window; } /** * 获取所有的数据连接 + * * @return 数据连接集合 */ @JSBridge diff --git a/designer-base/src/main/java/com/fr/design/deeplink/DeepLinkCore.java b/designer-base/src/main/java/com/fr/design/deeplink/DeepLinkCore.java index c9b80ebf72..d4e7ce34a8 100644 --- a/designer-base/src/main/java/com/fr/design/deeplink/DeepLinkCore.java +++ b/designer-base/src/main/java/com/fr/design/deeplink/DeepLinkCore.java @@ -167,6 +167,22 @@ public class DeepLinkCore { markPendingURLConsumed(); } + /** + * 符合条件的url才处理 + * + * @param url 接收到的url + * @return true:处理; false:不处理 + */ + public boolean accept(String url) { + UrlBean urlBean = UrlBean.create(url); + for (DeepLink deepLink: deepLinkList) { + if (deepLink.accept(urlBean.getUrl(), urlBean.getHost(), urlBean.getPath(), urlBean.getParams())) { + return true; + } + } + return false; + } + private void performDeepLinks(String url, String host, String path, Map params) { SwingUtilities.invokeLater(new Runnable() { @Override diff --git a/designer-base/src/main/java/com/fr/design/dialog/BasicPane.java b/designer-base/src/main/java/com/fr/design/dialog/BasicPane.java index 75626441bf..5b77b9571a 100644 --- a/designer-base/src/main/java/com/fr/design/dialog/BasicPane.java +++ b/designer-base/src/main/java/com/fr/design/dialog/BasicPane.java @@ -75,6 +75,26 @@ public abstract class BasicPane extends JPanel { return dg; } + /** + * 显示小窗口并允许自定义需不需要按钮 + * + * @param window 窗口 + * @param isNeedButtonsPane 是否需要确定删除按钮 + * @return 对话框 + */ + public BasicDialog showSmallWindow(Window window, boolean isNeedButtonsPane) { + BasicDialog dg; + if (window instanceof Frame) { + dg = new DIALOG((Frame) window, isNeedButtonsPane); + } else { + dg = new DIALOG((Dialog) window, isNeedButtonsPane); + } + dg.setBasicDialogSize(BasicDialog.SMALL); + GUICoreUtils.centerWindow(dg); + dg.setResizable(false); + return dg; + } + /** * 图表类型选择时 弹出的按钮大小, 不适合用最大最小, 因为图表大小 默认是规定好的, 那么界面大小也是必须配合. diff --git a/designer-base/src/main/java/com/fr/design/dialog/FineJOptionPane.java b/designer-base/src/main/java/com/fr/design/dialog/FineJOptionPane.java index 4e0b4e520d..a5f890de6d 100644 --- a/designer-base/src/main/java/com/fr/design/dialog/FineJOptionPane.java +++ b/designer-base/src/main/java/com/fr/design/dialog/FineJOptionPane.java @@ -39,7 +39,7 @@ public class FineJOptionPane extends JOptionPane { } private final static String MESSAGE_DIALOG_TITLE = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Message"); - private final static String CONFIRM_DIALOG_TITLE = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Confirm"); + private final static String CONFIRM_DIALOG_TITLE = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"); private final static String INPUT_DIALOG_TITLE = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"); /** diff --git a/designer-base/src/main/java/com/fr/design/editlock/EditLockChangeChecker.java b/designer-base/src/main/java/com/fr/design/editlock/EditLockChangeChecker.java index 5a8004fbce..5ad21c5346 100644 --- a/designer-base/src/main/java/com/fr/design/editlock/EditLockChangeChecker.java +++ b/designer-base/src/main/java/com/fr/design/editlock/EditLockChangeChecker.java @@ -34,7 +34,7 @@ public abstract class EditLockChangeChecker { */ public void start() { this.scheduler = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("EditLockChangeChecker")); - this.scheduler.scheduleAtFixedRate(new Runnable() { + this.scheduler.scheduleWithFixedDelay(new Runnable() { @Override public void run() { // 判断是否为远程设计环境 diff --git a/designer-base/src/main/java/com/fr/design/editor/DoubleDeckValueEditorPane.java b/designer-base/src/main/java/com/fr/design/editor/DoubleDeckValueEditorPane.java index 6e6c3d8b9b..800e1596bd 100644 --- a/designer-base/src/main/java/com/fr/design/editor/DoubleDeckValueEditorPane.java +++ b/designer-base/src/main/java/com/fr/design/editor/DoubleDeckValueEditorPane.java @@ -304,7 +304,7 @@ public class DoubleDeckValueEditorPane extends BasicPane implements UIObserver, if (designerEnvManager.isSupportStringToFormula()) { if (!designerEnvManager.isDefaultStringToFormula()) { int returnValue = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Edit_String_To_Formula") - + "?", com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_OPTION); + + "?", com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.YES_NO_OPTION); if (returnValue == JOptionPane.OK_OPTION) { setCurrentEditor(j); diff --git a/designer-base/src/main/java/com/fr/design/editor/ValueEditorPane.java b/designer-base/src/main/java/com/fr/design/editor/ValueEditorPane.java index 503929e228..b19e243850 100644 --- a/designer-base/src/main/java/com/fr/design/editor/ValueEditorPane.java +++ b/designer-base/src/main/java/com/fr/design/editor/ValueEditorPane.java @@ -285,7 +285,7 @@ public class ValueEditorPane extends BasicPane implements UIObserver, GlobalName if (designerEnvManager.isSupportStringToFormula()) { if (!designerEnvManager.isDefaultStringToFormula()) { int returnValue = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Edit_String_To_Formula") - + "?", com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_OPTION); + + "?", com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.YES_NO_OPTION); if (returnValue == JOptionPane.OK_OPTION) { setCurrentEditor(j); diff --git a/designer-base/src/main/java/com/fr/design/editor/editor/NumberEditor.java b/designer-base/src/main/java/com/fr/design/editor/editor/NumberEditor.java index d811ad89b7..26b81f8a4b 100644 --- a/designer-base/src/main/java/com/fr/design/editor/editor/NumberEditor.java +++ b/designer-base/src/main/java/com/fr/design/editor/editor/NumberEditor.java @@ -38,7 +38,7 @@ public abstract class NumberEditor extends Editor { */ public NumberEditor(T value, String name) { this.setLayout(FRGUIPaneFactory.createBorderLayout()); - numberField = new UINumberField(); + numberField = createNumberField(); this.add(numberField, BorderLayout.CENTER); this.numberField.addKeyListener(textKeyListener); this.numberField.setHorizontalAlignment(UITextField.RIGHT); @@ -46,6 +46,14 @@ public abstract class NumberEditor extends Editor { this.setName(name); } + /** + * 创建NumberField对象 + * + */ + protected UINumberField createNumberField() { + return new UINumberField(); + } + /** * 给numberField加键盘事件 * diff --git a/designer-base/src/main/java/com/fr/design/env/RemoteDesignerWorkspaceInfo.java b/designer-base/src/main/java/com/fr/design/env/RemoteDesignerWorkspaceInfo.java index 920a13dbfb..39abe75cfb 100644 --- a/designer-base/src/main/java/com/fr/design/env/RemoteDesignerWorkspaceInfo.java +++ b/designer-base/src/main/java/com/fr/design/env/RemoteDesignerWorkspaceInfo.java @@ -6,6 +6,7 @@ import com.fr.log.FineLoggerFactory; import com.fr.security.SecurityToolbox; import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; +import com.fr.stable.fun.mark.Immutable; import com.fr.stable.project.ProjectConstants; import com.fr.stable.xml.XMLPrintWriter; import com.fr.stable.xml.XMLableReader; @@ -166,6 +167,15 @@ public class RemoteDesignerWorkspaceInfo implements DesignerWorkspaceInfo { return object; } + /** + * clone一个自定义连接信息的RemoteDesignerWorkspaceInfo + */ + public Object cloneWithConnectionInfo(WorkspaceConnectionInfo workspaceConnectionInfo) throws CloneNotSupportedException { + RemoteDesignerWorkspaceInfo object = (RemoteDesignerWorkspaceInfo) super.clone(); + object.connection = workspaceConnectionInfo; + return object; + } + @Override public boolean checkValid() throws Exception { diff --git a/designer-base/src/main/java/com/fr/design/env/processor/AbstractRemoteDesignerWorkspaceInfoProcessor.java b/designer-base/src/main/java/com/fr/design/env/processor/AbstractRemoteDesignerWorkspaceInfoProcessor.java new file mode 100644 index 0000000000..6917f1745f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/env/processor/AbstractRemoteDesignerWorkspaceInfoProcessor.java @@ -0,0 +1,24 @@ +package com.fr.design.env.processor; + +import com.fr.stable.fun.mark.API; + + +/** + * 远程设计自定义用户名接口实现抽象类 + * + * @author John.Ying + * @since 11.0 + * Created on 2023/5/17 + */ +@API(level = RemoteDesignerWorkspaceInfoProcessor.CURRENT_LEVEL) +public abstract class AbstractRemoteDesignerWorkspaceInfoProcessor implements RemoteDesignerWorkspaceInfoProcessor { + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } + + @Override + public int layerIndex() { + return DEFAULT_LAYER_INDEX; + } +} diff --git a/designer-base/src/main/java/com/fr/design/env/processor/RemoteDesignerWorkspaceInfoProcessor.java b/designer-base/src/main/java/com/fr/design/env/processor/RemoteDesignerWorkspaceInfoProcessor.java new file mode 100644 index 0000000000..b74d21159f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/env/processor/RemoteDesignerWorkspaceInfoProcessor.java @@ -0,0 +1,25 @@ +package com.fr.design.env.processor; + +import com.fr.stable.fun.mark.Immutable; +import com.fr.workspace.connect.WorkspaceConnectionInfo; + +/** + * 远程设计自定义用户名接口 + * px:为了二开插件开的接口,不建议实现,后面可能会变动 + * + * @author John.Ying + * @since 11.0 + * Created on 2023/5/17 + */ +public interface RemoteDesignerWorkspaceInfoProcessor extends Immutable { + + String XML_TAG = "RemoteDesignerWorkspaceInfoProcessor"; + + int CURRENT_LEVEL = 1; + + /** + * 根据链接信息自定义用户名 + */ + WorkspaceConnectionInfo customUserName(WorkspaceConnectionInfo workspaceInfo); + +} diff --git a/designer-base/src/main/java/com/fr/design/extra/PluginBatchModifyDetailPane.java b/designer-base/src/main/java/com/fr/design/extra/PluginBatchModifyDetailPane.java new file mode 100644 index 0000000000..3c086b7ea8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/extra/PluginBatchModifyDetailPane.java @@ -0,0 +1,184 @@ +package com.fr.design.extra; + +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; + + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * 插件批量处理弹窗面板 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/5/19 + */ +public class PluginBatchModifyDetailPane { + private UILabel message = new UILabel(); + private UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Report_OK")); + private UILabel uiLabel = new UILabel(); + private UILabel directUiLabel = new UILabel(); + private UILabel detailLabel = new UILabel(); + + private JPanel upPane; + private JPanel midPane; + private JPanel downPane; + private JPanel hiddenPanel; + private JTextArea jta; + private JDialog dialog; + + /** + * 弹窗面板默认大小 + */ + public static final Dimension DEFAULT = new Dimension(380, 150); + + /** + * 弹窗面板展开大小 + */ + public static final Dimension DEFAULT_PRO = new Dimension(380, 270); + + public PluginBatchModifyDetailPane(Dialog parent) { + init(parent); + } + + private void init(Dialog parent) { + message.setBorder(BorderFactory.createEmptyBorder(8, 5, 0, 0)); + dialog = new JDialog(parent, Toolkit.i18nText("Fine-Design_Basic_Plugin_Manager"), true); + dialog.setSize(DEFAULT); + JPanel jp = new JPanel(); + initUpPane(); + initDownPane(); + initMidPane(); + initHiddenPanel(); + initListener(); + jp.setLayout(new BoxLayout(jp, BoxLayout.Y_AXIS)); + jp.add(upPane); + jp.add(midPane); + jp.add(hiddenPanel); + jp.add(downPane); + hiddenPanel.setVisible(false); + dialog.add(jp); + dialog.setResizable(false); + dialog.setLocationRelativeTo(SwingUtilities.getWindowAncestor(parent)); + } + + private void initDownPane() { + downPane = new JPanel(); + downPane.setLayout(new FlowLayout(FlowLayout.RIGHT, 15, 9)); + downPane.add(cancelButton); + } + + private void initUpPane() { + upPane = new JPanel(); + uiLabel = new UILabel(UIManager.getIcon("OptionPane.errorIcon")); + upPane.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 10)); + upPane.add(uiLabel); + upPane.add(message); + } + + private void initMidPane() { + midPane = new JPanel(); + midPane.add(directUiLabel); + midPane.add(detailLabel); + midPane.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0)); + detailLabel.setText(Toolkit.i18nText("Fine_Designer_Look_Detail")); + detailLabel.setForeground(Color.BLUE); + detailLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + directUiLabel.setIcon(UIManager.getIcon("OptionPane.narrow.right")); + } + + private void initHiddenPanel() { + hiddenPanel = new JPanel(); + hiddenPanel.setLayout(new BorderLayout(2, 0)); + hiddenPanel.add(new JPanel(), BorderLayout.WEST); + hiddenPanel.add(new JPanel(), BorderLayout.EAST); + JPanel borderPanel = new JPanel(); + borderPanel.setLayout(new BorderLayout()); + jta = new JTextArea(); + JScrollPane jsp = new JScrollPane(jta); + jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + jta.setEditable(false); + borderPanel.add(jsp, BorderLayout.CENTER); + hiddenPanel.add(borderPanel); + } + + /** + * 补充更详细的报错信息 + * + * @param message 信息 + */ + public void updateDetailArea(String message) { + jta.append(message + "\n"); + } + + private void initListener() { + detailLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (hiddenPanel.isVisible()) { + hiddenPanel.setVisible(false); + dialog.setSize(DEFAULT); + detailLabel.setText(Toolkit.i18nText("Fine_Designer_Look_Detail")); + directUiLabel.setIcon(UIManager.getIcon("OptionPane.narrow.right")); + } else { + dialog.setSize(DEFAULT_PRO); + hiddenPanel.setVisible(true); + detailLabel.setText(Toolkit.i18nText("Fine_Designer_Hide_Detail")); + directUiLabel.setIcon(UIManager.getIcon("OptionPane.narrow.down")); + } + } + + }); + cancelButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + hiddenPanel.removeAll(); + dialog.dispose(); + } + }); + } + + /** + * 更新标题 + * @param title 标题 + */ + public void updateTitle(String title) { + dialog.setTitle(title); + } + + /** + * 更新展示信息 + * + * @param failedCount 处理失败个数 + * @param successCount 处理成功个数 + */ + public void updateMessage(int failedCount, int successCount) { + message.setText(Toolkit.i18nText("Fine-Design_Basic_Plugin_Batch_Modify_Info", failedCount, successCount)); + } + + /** + * 显示面板 + */ + public void show() { + dialog.setVisible(true); + } +} diff --git a/designer-base/src/main/java/com/fr/design/extra/PluginOperateUtils.java b/designer-base/src/main/java/com/fr/design/extra/PluginOperateUtils.java index 379daab28e..aa506e679f 100644 --- a/designer-base/src/main/java/com/fr/design/extra/PluginOperateUtils.java +++ b/designer-base/src/main/java/com/fr/design/extra/PluginOperateUtils.java @@ -3,6 +3,8 @@ package com.fr.design.extra; import com.fr.design.DesignerEnvManager; import com.fr.design.bridge.exec.JSCallback; import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.extra.exe.callback.BatchModifyStatusCallback; +import com.fr.design.extra.exe.callback.BatchUpdateOnlineCallback; import com.fr.design.extra.exe.callback.InstallFromDiskCallback; import com.fr.design.extra.exe.callback.InstallOnlineCallback; import com.fr.design.extra.exe.callback.ModifyStatusCallback; @@ -28,11 +30,13 @@ import com.fr.plugin.view.PluginView; import com.fr.plugin.xml.PluginElementName; import com.fr.plugin.xml.PluginXmlElement; import com.fr.stable.StringUtils; +import com.teamdev.jxbrowser.chromium.JSArray; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import java.io.File; import java.net.HttpURLConnection; +import java.util.ArrayList; import java.util.List; @@ -65,12 +69,14 @@ public class PluginOperateUtils { public static void updatePluginOnline(List pluginMarkerList, JSCallback jsCallback) { - for (int i = 0; i < pluginMarkerList.size(); i++) { - updatePluginOnline(pluginMarkerList.get(i), jsCallback); + int size = pluginMarkerList.size(); + BatchUpdateOnlineCallback batchUpdateOnlineCallback = size <= 1 ? BatchUpdateOnlineCallback.NONE : new BatchUpdateOnlineCallback(jsCallback, size); + for (int i = 0; i < size; i++) { + updatePluginOnline(pluginMarkerList.get(i), jsCallback, batchUpdateOnlineCallback); } } - public static void updatePluginOnline(PluginMarker pluginMarker, JSCallback jsCallback) { + private static void updatePluginOnline(PluginMarker pluginMarker, JSCallback jsCallback, BatchUpdateOnlineCallback batchUpdateOnlineCallback) { try { JSONObject latestPluginInfo = PluginUtils.getLatestPluginInfo(pluginMarker.getPluginID()); String latestPluginVersion = latestPluginInfo.getString("version"); @@ -79,11 +85,25 @@ public class PluginOperateUtils { //当前已经安装的相同ID插件marker PluginMarker currentMarker = PluginMarkerAdapter.create(PluginUtils.getInstalledPluginMarkerByID(pluginMarker.getPluginID()), pluginName); PluginTask pluginTask = PluginTask.updateTask(currentMarker, toPluginMarker); - PluginControllerHelper.updateOnline(currentMarker, toPluginMarker, new UpdateOnlineCallback(pluginTask, jsCallback), PluginExtraInfo.newBuilder().username(DesignerEnvManager.getEnvManager().getDesignerLoginUsername()).build()); + if (!batchUpdateOnlineCallback.equals(BatchUpdateOnlineCallback.NONE)) { + batchUpdateOnlineCallback.createInnerPreTaskCallback(pluginTask, jsCallback); + PluginControllerHelper.updateOnline(currentMarker, toPluginMarker, batchUpdateOnlineCallback.getInnerPreTaskCallback(), PluginExtraInfo.newBuilder().username(DesignerEnvManager.getEnvManager().getDesignerLoginUsername()).build()); + } else { + PluginControllerHelper.updateOnline(currentMarker, toPluginMarker, new UpdateOnlineCallback(pluginTask, jsCallback), PluginExtraInfo.newBuilder().username(DesignerEnvManager.getEnvManager().getDesignerLoginUsername()).build()); + } } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); } + } + /** + * 更新插件 + * + * @param pluginMarker 插件marker + * @param jsCallback 回调 + */ + public static void updatePluginOnline(PluginMarker pluginMarker, JSCallback jsCallback) { + updatePluginOnline(pluginMarker, jsCallback, BatchUpdateOnlineCallback.NONE); } @@ -92,6 +112,40 @@ public class PluginOperateUtils { } + + + private static void dealWithPluginActive(PluginMarker pluginMarker, BatchModifyStatusCallback modifyStatusCallback) { + PluginContext plugin = PluginManager.getContext(pluginMarker); + boolean running = plugin.isRunning(); + modifyStatusCallback.updateActiveStatus(running); + changePluginActive(running, pluginMarker, modifyStatusCallback, plugin); + + } + + private static void changePluginActive(boolean isRunning, PluginMarker pluginMarker, PluginTaskCallback modifyStatusCallback, PluginContext plugin) { + if (isRunning) { + PluginXmlElement forbidReminder = plugin.getXml().getElement(PluginElementName.ForbidReminder); + if (forbidReminder != null && forbidReminder.getContent() != null) { + // 禁用前提示 + int rv = FineJOptionPane.showConfirmDialog( + null, + forbidReminder.getContent(), + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.WARNING_MESSAGE + ); + if (rv == JOptionPane.OK_OPTION) { + PluginManager.getController().forbidPersistently(pluginMarker, modifyStatusCallback); + } + } else { + // 正常禁用 + PluginManager.getController().forbidPersistently(pluginMarker, modifyStatusCallback); + } + } else { + PluginManager.getController().enablePersistently(pluginMarker, modifyStatusCallback); + } + } + public static void setPluginActive(String pluginInfo, JSCallback jsCallback) { SwingUtilities.invokeLater(new Runnable() { @@ -99,28 +153,29 @@ public class PluginOperateUtils { public void run() { PluginMarker pluginMarker = PluginUtils.createPluginMarker(pluginInfo); PluginContext plugin = PluginManager.getContext(pluginMarker); - boolean isRunning = plugin.isRunning(); - PluginTaskCallback modifyStatusCallback = new ModifyStatusCallback(isRunning, jsCallback); - if (isRunning) { - PluginXmlElement forbidReminder = plugin.getXml().getElement(PluginElementName.ForbidReminder); - if (forbidReminder != null && forbidReminder.getContent() != null) { - // 禁用前提示 - int rv = FineJOptionPane.showConfirmDialog( - null, - forbidReminder.getContent(), - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Plugin_Warning"), - JOptionPane.OK_CANCEL_OPTION, - JOptionPane.WARNING_MESSAGE - ); - if (rv == JOptionPane.OK_OPTION) { - PluginManager.getController().forbidPersistently(pluginMarker, modifyStatusCallback); - } - } else { - // 正常禁用 - PluginManager.getController().forbidPersistently(pluginMarker, modifyStatusCallback); - } - } else { - PluginManager.getController().enablePersistently(pluginMarker, modifyStatusCallback); + boolean running = plugin.isRunning() || plugin.isPrepare(); + PluginTaskCallback modifyStatusCallback = new ModifyStatusCallback(running, jsCallback); + changePluginActive(running, pluginMarker, modifyStatusCallback, plugin); + } + }); + } + + /** + * 批量启用或禁用插件 + * + * @param pluginIDs 要处理的插件信息 + * @param jsCallback 回调函数 + */ + public static void setPluginActive(List pluginIDs, JSCallback jsCallback) { + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + int len = pluginIDs.size(); + BatchModifyStatusCallback modifyStatusCallback = new BatchModifyStatusCallback(jsCallback, len); + for (String pluginInfo : pluginIDs) { + PluginMarker pluginMarker = PluginUtils.createPluginMarker(pluginInfo); + dealWithPluginActive(pluginMarker, modifyStatusCallback); } } }); @@ -255,8 +310,7 @@ public class PluginOperateUtils { private static String getPluginName(PluginContext pluginContext, PluginMarker pluginMarker) { if (pluginContext != null) { return pluginContext.getName(); - } - else if (pluginMarker instanceof PluginMarkerAdapter) { + } else if (pluginMarker instanceof PluginMarkerAdapter) { return ((PluginMarkerAdapter) pluginMarker).getPluginName(); } return pluginMarker == null ? StringUtils.EMPTY : pluginMarker.getPluginID(); diff --git a/designer-base/src/main/java/com/fr/design/extra/PluginUtils.java b/designer-base/src/main/java/com/fr/design/extra/PluginUtils.java index a0b9bcb248..12209a67a7 100644 --- a/designer-base/src/main/java/com/fr/design/extra/PluginUtils.java +++ b/designer-base/src/main/java/com/fr/design/extra/PluginUtils.java @@ -270,8 +270,8 @@ public class PluginUtils { jo.put("vendor", pluginContext.getVendor()); jo.put("price", pluginContext.getPrice()); jo.put("requiredJarTime", pluginContext.getRequiredJarTime()); - // 前端需求的active实际上是插件的运行状态,通过isRunning()获取 - jo.put("active", pluginContext.isRunning()); + // 前端需求的active实际上是插件的运行状态,通过isRunning()或isPrepare()获取 + jo.put("active", pluginContext.isRunning() || pluginContext.isPrepare()); jo.put("hidden", pluginContext.isHidden()); jo.put("free", pluginContext.isFree()); jo.put("licDamaged", pluginContext.isLicDamaged()); diff --git a/designer-base/src/main/java/com/fr/design/extra/exe/callback/AbstractBatchModifyStatusCallback.java b/designer-base/src/main/java/com/fr/design/extra/exe/callback/AbstractBatchModifyStatusCallback.java new file mode 100644 index 0000000000..1b3663a2ba --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/extra/exe/callback/AbstractBatchModifyStatusCallback.java @@ -0,0 +1,127 @@ +package com.fr.design.extra.exe.callback; + +import com.fr.design.bridge.exec.JSCallback; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.extra.PluginBatchModifyDetailPane; +import com.fr.design.extra.PluginOperateUtils; +import com.fr.design.i18n.Toolkit; +import com.fr.design.plugin.DesignerPluginContext; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.context.PluginMarker; +import com.fr.plugin.manage.control.PluginTask; +import com.fr.plugin.manage.control.PluginTaskResult; +import com.fr.plugin.manage.control.ProgressCallback; +import com.fr.stable.StringUtils; + +import javax.swing.JOptionPane; +import java.util.HashMap; +import java.util.Map; + +/** + * 带进度条的批量处理的callback + *
  • content与title是处理完成后弹出的面板的内容与标题,子类需要在done之前设定好对应的信息 + *
  • 进度条是以 当前完成任务数/总任务数 来计算的 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/6/6 + */ +public abstract class AbstractBatchModifyStatusCallback implements ProgressCallback { + protected JSCallback jsCallback; + protected Map resultMap = new HashMap<>(); + protected String content = StringUtils.EMPTY; + protected String title = StringUtils.EMPTY; + public int pluginCount = 0; + public int allPluginCount = 0; + public int successCount = 0; + public int failedCount = 0; + public static final int HUNDRED_PERCENT = 100; + public static final String PERCENT = "%"; + public static final String DEFAULT = "default"; + + public AbstractBatchModifyStatusCallback() { + } + + public AbstractBatchModifyStatusCallback(JSCallback jsCallback, int size) { + this.jsCallback = jsCallback; + this.allPluginCount = size; + } + + @Override + public void done(PluginTaskResult result) { + String pluginInfo = PluginOperateUtils.getSuccessInfo(result); + if (result.isSuccess()) { + successCount++; + String modifyMessage = updateMessage(pluginInfo); + FineLoggerFactory.getLogger().info(modifyMessage); + } else { + failedCount++; + resultMap.put(getPluginName(result), pluginInfo); + } + updateProgressAndCheckCompletion(); + } + + + /** + * 获取插件名 + * + * @param result 任务结果 + * @return 插件名 + */ + public String getPluginName(PluginTaskResult result) { + PluginTask pluginTask = result.getCurrentTask(); + if (pluginTask != null) { + PluginMarker pluginMarker = pluginTask.getToMarker(); + if (pluginMarker != null) { + return pluginMarker.getPluginID(); + } + } + return DEFAULT; + } + + + /** + * 更新当前Map状态,进度条,如果全部都更新完了就回调 + */ + public void updateProgressAndCheckCompletion() { + pluginCount++; + updateProgress(StringUtils.EMPTY, (double) pluginCount / allPluginCount); + if (pluginCount == allPluginCount) { + jsCallback.execute("success"); + showMessageDialog(); + } + } + + /** + * 展示信息面板 + */ + public void showMessageDialog() { + if (failedCount == 0) { + FineJOptionPane.showMessageDialog(DesignerPluginContext.getPluginDialog(), + content, + title, + JOptionPane.INFORMATION_MESSAGE); + } else { + PluginBatchModifyDetailPane detailPane = new PluginBatchModifyDetailPane(DesignerPluginContext.getPluginDialog()); + for (String key : resultMap.keySet()) { + detailPane.updateDetailArea(resultMap.get(key)); + } + detailPane.updateMessage(failedCount, successCount); + detailPane.updateTitle(title); + detailPane.show(); + } + } + + + @Override + public void updateProgress(String description, double progress) { + jsCallback.execute(progress * HUNDRED_PERCENT + PERCENT); + } + + /** + * 更新处理成功返回的日志信息 + * + * @return 返回的日志信息 + */ + abstract public String updateMessage(String pluginInfo); +} diff --git a/designer-base/src/main/java/com/fr/design/extra/exe/callback/BatchModifyStatusCallback.java b/designer-base/src/main/java/com/fr/design/extra/exe/callback/BatchModifyStatusCallback.java new file mode 100644 index 0000000000..00c0e8b07a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/extra/exe/callback/BatchModifyStatusCallback.java @@ -0,0 +1,43 @@ +package com.fr.design.extra.exe.callback; + + +import com.fr.design.bridge.exec.JSCallback; + +import com.fr.design.i18n.Toolkit; + + +/** + * 批量启用/禁用插件的Callback + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/5/18 + */ +public class BatchModifyStatusCallback extends AbstractBatchModifyStatusCallback { + private boolean active; + private boolean operatorFlag = false; + + public BatchModifyStatusCallback(JSCallback jsCallback, int size) { + super(jsCallback, size); + } + + + @Override + public String updateMessage(String pluginInfo) { + return active ? pluginInfo + Toolkit.i18nText("Fine-Design_Basic_Plugin_Has_Been_Disabled_Duplicate") : pluginInfo + Toolkit.i18nText("Fine-Design_Plugin_Has_Been_Actived_Duplicate"); + } + + /** + * 更新启用/禁用信息 + * + * @param active + */ + public void updateActiveStatus(boolean active) { + if (!operatorFlag) { + this.active = active; + this.operatorFlag = true; + this.title = active ? Toolkit.i18nText("Fine-Design_Basic_Plugin_Stop") : Toolkit.i18nText("Fine-Design_Basic_Plugin_Start"); + this.content = active ? Toolkit.i18nText("Fine-Design_Basic_Plugin_Batch_Modify_Stop_Success") : Toolkit.i18nText("Fine-Design_Basic_Plugin_Batch_Modify_Start_Success"); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/extra/exe/callback/BatchUpdateOnlineCallback.java b/designer-base/src/main/java/com/fr/design/extra/exe/callback/BatchUpdateOnlineCallback.java new file mode 100644 index 0000000000..6d93ac1a10 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/extra/exe/callback/BatchUpdateOnlineCallback.java @@ -0,0 +1,77 @@ +package com.fr.design.extra.exe.callback; + + +import com.fr.design.bridge.exec.JSCallback; +import com.fr.design.i18n.Toolkit; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.manage.control.PluginTask; +import com.fr.plugin.manage.control.PluginTaskResult; + + +/** + * 批量更新的callback + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/6/6 + */ +public class BatchUpdateOnlineCallback extends AbstractBatchModifyStatusCallback{ + public static final BatchUpdateOnlineCallback NONE = new BatchUpdateOnlineCallback(); + + /** + * 可自动处理前置任务的callback,用来处理实际更新逻辑 + */ + private InnerUpdateCallback innerPreTaskCallback; + + public BatchUpdateOnlineCallback() { + } + + public BatchUpdateOnlineCallback(JSCallback jsCallback, int size) { + super(jsCallback, size); + this.title = Toolkit.i18nText("Fine-Design_Basic_Plugin_Update"); + this.content = Toolkit.i18nText("Fine-Design_Basic_Plugin_Update_Success"); + } + + /** + * 更新任务 + * + * @param pluginTask 任务 + * @param jsCallback callback + */ + public void createInnerPreTaskCallback(PluginTask pluginTask, JSCallback jsCallback) { + innerPreTaskCallback = new InnerUpdateCallback(pluginTask, jsCallback); + } + + + + public InnerUpdateCallback getInnerPreTaskCallback() { + return innerPreTaskCallback; + } + + @Override + public String updateMessage(String pluginInfo) { + return pluginInfo + Toolkit.i18nText("Fine-Design_Basic_Plugin_Update_Success"); + } + + /** + * 可自动处理前置任务的callback,用来处理实际更新逻辑 + */ + public class InnerUpdateCallback extends UpdateOnlineCallback { + + + public InnerUpdateCallback(PluginTask pluginTask, JSCallback jsCallback) { + super(pluginTask, jsCallback); + + } + + @Override + public void updateProgress(String description, double aProgress) { + //不进行处理 + } + + @Override + public void allDone(PluginTaskResult result) { + BatchUpdateOnlineCallback.this.done(result); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginCallBackHelper.java b/designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginCallBackHelper.java index fc5f957f63..8fe64dc29a 100644 --- a/designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginCallBackHelper.java +++ b/designer-base/src/main/java/com/fr/design/extra/exe/callback/handle/PluginCallBackHelper.java @@ -2,6 +2,7 @@ package com.fr.design.extra.exe.callback.handle; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.dialog.link.MessageWithLink; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.i18n.Toolkit; import com.fr.plugin.error.PluginErrorCode; import com.fr.plugin.manage.control.PluginTaskResult; @@ -16,7 +17,19 @@ public class PluginCallBackHelper { private static final String REFERENCE = Toolkit.i18nText("Fine-Design_Basic_Plugin_File_Validate_Reference"); private static final String HELP_DOCUMENT_NAME = Toolkit.i18nText("Fine-Design_Basic_Plugin_File_Validate_HELP_DOCUMENT_NAME"); private static final String CONNECTOR = "-"; - private static final String HELP_DOCUMENT_LINK = Toolkit.i18nText("Fine-Design_Basic_Plugin_File_Validate_HELP_DOCUMENT_LINK"); + + /** + * 云中心第三方插件安装失败说明帮助文档在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design_Basic_Plugin_File_Validate_HELP_DOCUMENT_LINK"; + + /** + * 云中心第三方插件安装失败说明帮助文档默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design_Basic_Plugin_File_Validate_HELP_DOCUMENT_LINK_Default"; + + + private static final String HELP_DOCUMENT_LINK = LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); /** diff --git a/designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java b/designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java index 1bcfe3c622..1d2048fa28 100644 --- a/designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java +++ b/designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java @@ -28,7 +28,6 @@ import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; import com.fr.stable.collections.CollectionUtils; import com.fr.stable.project.ProjectConstants; -import com.fr.workspace.WorkContext; import javax.swing.BorderFactory; import javax.swing.JDialog; @@ -221,6 +220,7 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi /** * 检测是否能够黏贴 + * * @param treeNodeList * @return */ @@ -271,7 +271,7 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi } } } catch (Exception e) { - FineLoggerFactory.getLogger().error(e,"Template paste failed.", e.getMessage()); + FineLoggerFactory.getLogger().error(e, "Template paste failed.", e.getMessage()); FineJOptionPane.showConfirmDialog(null, Toolkit.i18nText("Fine-Design_Basic_Paste_Failure"), Toolkit.i18nText("Fine-Design_Basic_Error"), @@ -286,7 +286,7 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi /** * 确认粘贴的目标目录是否是复制文件的子目录,并确认是否继续执行粘贴任务 * - * @param targetDir 目标文件夹 + * @param targetDir 目标文件夹 * @param pasteNodes 待粘贴的文件 * @return 是否继续 */ @@ -433,6 +433,14 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi WARNING_MESSAGE); return false; } + // 检查移动的源文件夹是否为目标文件夹相同文件夹或子文件夹 + if (FileOperationHelper.getInstance().isSubDirectoryOrSame(getFileTree().getSelectedTreeNodes(), getTargetFileNode())) { + FineJOptionPane.showMessageDialog(this, + Toolkit.i18nText("Fine-Design_Basic_Move_To_SubDirectory"), + Toolkit.i18nText("Fine-Design_Basic_Alert"), + WARNING_MESSAGE); + return false; + } if (TemplateUtils.checkSelectedTemplateIsEditing()) { return FineJOptionPane.showConfirmDialog(this, Toolkit.i18nText("Fine-Design_Basic_Template_Is_Editing"), @@ -443,9 +451,7 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi } private boolean doMove() { - FileNode fileNode = getDirTree().getSelectedFileNode(); - ExpandMutableTreeNode rootTreeNode = (ExpandMutableTreeNode) getDirTree().getModel().getRoot(); - fileNode = fileNode == null ? (FileNode) rootTreeNode.getUserObject() : fileNode; + FileNode fileNode = getTargetFileNode(); boolean moveSuccess = true; try { //待移动的文件可以有多个 @@ -465,6 +471,12 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi return moveSuccess; } + private FileNode getTargetFileNode() { + FileNode fileNode = getDirTree().getSelectedFileNode(); + ExpandMutableTreeNode rootTreeNode = (ExpandMutableTreeNode) getDirTree().getModel().getRoot(); + return fileNode == null ? (FileNode) rootTreeNode.getUserObject() : fileNode; + } + @Override public void dispose() { TemplateDirTreeSearchManager.getInstance().outOfSearchMode(); diff --git a/designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java b/designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java index a3abaf4606..8bf57ae4ee 100644 --- a/designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java +++ b/designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java @@ -16,7 +16,10 @@ import com.fr.stable.StringUtils; import com.fr.stable.project.ProjectConstants; import com.fr.workspace.WorkContext; import com.fr.workspace.resource.ResourceIOException; +import org.jetbrains.annotations.NotNull; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import static javax.swing.JOptionPane.WARNING_MESSAGE; @@ -32,6 +35,38 @@ public class FileOperationHelper { return INSTANCE; } + /** + * 检查目标文件夹是否为多个源文件夹中的任一文件夹,或者任一文件夹的子文件夹 + * + * @param fileNodes 需移动的源文件 + * @param targetNode 移动后的目标文件夹 + * @return + */ + public boolean isSubDirectoryOrSame(@NotNull ExpandMutableTreeNode[] fileNodes, @NotNull FileNode targetNode) { + for (ExpandMutableTreeNode treeNode : fileNodes) { + FileNode sourceFileNode = (FileNode) treeNode.getUserObject(); + if (isSubDirectoryOrSame(sourceFileNode, targetNode)) { + return true; + } + } + return false; + } + + /** + * 检查目标文件夹是否为源文件夹,或源文件夹的子文件夹 + * + * @param sourceFileNode 需移动的源文件 + * @param targetNode 移动后的目标文件夹 + */ + public boolean isSubDirectoryOrSame(@NotNull FileNode sourceFileNode, @NotNull FileNode targetNode) { + if (!sourceFileNode.isDirectory() || !targetNode.isDirectory()) { + return false; + } + Path sourceDir = Paths.get(sourceFileNode.getEnvPath()).normalize(); + Path targetDir = Paths.get(targetNode.getEnvPath()).normalize(); + return targetDir.startsWith(sourceDir); + } + public String moveFile(FileNode sourceFileNode, String targetDir) { String targetPath = copyFileAndVcs(sourceFileNode, targetDir); FileNodeFILE nodeFILE = new FileNodeFILE(sourceFileNode); @@ -51,8 +86,9 @@ public class FileOperationHelper { /** * 拷贝文件的同时拷贝对应的版本控制文件 + * * @param sourceFile 源文件或目录 - * @param targetDir 目标目录 + * @param targetDir 目标目录 * @return 复制后的目标文件的路径 */ public String copyFileAndVcs(FileNode sourceFile, String targetDir) { @@ -61,8 +97,9 @@ public class FileOperationHelper { /** * 只拷贝文件, 不拷贝对应的版本控制文件 + * * @param sourceFile 源文件或目录 - * @param targetDir 目标目录 + * @param targetDir 目标目录 * @return 复制后的目标文件的路径 */ public String copyFile(FileNode sourceFile, String targetDir) { @@ -71,7 +108,8 @@ public class FileOperationHelper { /** * 检测节点是否被锁住了 - * @param node 待检测节点 + * + * @param node 待检测节点 * @param dNodes 没有锁住的节点集合 * @param lNodes 锁住的节点集合 * @return 是否存在被锁住的文件 @@ -165,7 +203,7 @@ public class FileOperationHelper { } else { if (!TemplateResourceManager.getResource().copy(sourcePath, targetPath)) { throw new ResourceIOException(String.format("copy file failed, from %s to %s", sourcePath, targetPath)); - } else if (withCopyVcs){ + } else if (withCopyVcs) { sourcePath = sourcePath.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY); targetPath = targetPath.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY); VcsHelper.getInstance().moveVcs(sourcePath, targetPath); diff --git a/designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java b/designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java index 86820aa227..f895a4f5b4 100644 --- a/designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java +++ b/designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java @@ -268,7 +268,8 @@ public class HistoryTemplateListCache implements CallbackEvent { boolean replaceWithJVirtualTemplate = overTemplate.getEditingFILE().exists() && overTemplate.isALLSaved() && overTemplate != editingTemplate - && overTemplate.checkEnable(); + && overTemplate.checkEnable() + && overTemplate.supportCache(); if (replaceWithJVirtualTemplate) { closeVirtualSelectedReport(overTemplate); historyList.set(i, new JVirtualTemplate(overTemplate.getEditingFILE())); @@ -297,7 +298,9 @@ public class HistoryTemplateListCache implements CallbackEvent { int index = iterator.nextIndex(); if (size == index + 1 && index > 0) { //如果删除的是后一个Tab,则定位到前一个 - MultiTemplateTabPane.getInstance().setSelectedIndex(index - 1); + MultiTemplateTabPane.getInstance().setSelectedIndex( + MultiTemplateTabPane.getInstance().calNextShowJTemplateIndex(index - 1)); + } } } diff --git a/designer-base/src/main/java/com/fr/design/file/MultiTemplateTabMenuFactory.java b/designer-base/src/main/java/com/fr/design/file/MultiTemplateTabMenuFactory.java new file mode 100644 index 0000000000..6210f7ba68 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/file/MultiTemplateTabMenuFactory.java @@ -0,0 +1,349 @@ +package com.fr.design.file; + +import com.fr.base.svg.IconUtils; +import com.fr.design.constants.UIConstants; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.imenu.UIMenuItem; +import com.fr.design.gui.imenu.UIScrollPopUpMenu; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.utils.TemplateUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.collections.CollectionUtils; + +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 右侧下拉菜单的工厂类 + * @author Carlson + * @since 11.0 + * created on 2023-04-14 + **/ +public class MultiTemplateTabMenuFactory { + + private static final Icon CLOSE = IconUtils.readIcon("/com/fr/design/standard/close/close"); + private static final Icon MOUSE_OVER_CLOSE = IconUtils.readIcon("/com/fr/design/standard/close/close_mouseover.svg"); + private static final Icon MOUSE_PRESS_CLOSE = IconUtils.readIcon("/com/fr/design/standard/close/close_press.svg"); + + private static final int ITEM_SIZE = 25; + + private UIScrollPopUpMenu menu = null; + + private static MultiTemplateTabMenuFactory INSTANCE = new MultiTemplateTabMenuFactory(); + + private MultiTemplateTabMenuFactory() { + + } + + /** + * 返回右侧下拉菜单的工厂类 + * @return + */ + public static MultiTemplateTabMenuFactory getInstance() { + return INSTANCE; + } + + /** + * tab上的下拉菜单 + */ + public UIScrollPopUpMenu createMenu() { + menu = new UIScrollPopUpMenu(); + menu.setBorder(BorderFactory.createEmptyBorder(-3, 3, 3, 0)); + + menu.add(initCloseOther()); + menu.add(createEmptyRow()); + menu.addSeparator(); + menu.add(createEmptyRow()); + menu.add(createCategory(Toolkit.i18nText("Fine-Design_Basic_Tab_Current_Category_Templates"))); + Component[] items = createCurrentCategory(); + for (Component item : items) { + menu.add(item); + } + items = createOtherCategory(); + if (items.length > 0) { + menu.addSeparator(); + menu.add(createEmptyRow()); + menu.add(createCategory(Toolkit.i18nText("Fine-Design_Basic_Tab_Other_Category_Templates"))); + for (Component item : items) { + menu.add(item); + } + } + Dimension dimension = menu.getPreferredSize(); + dimension.width += ITEM_SIZE; + menu.setPreferredSize(dimension); + return menu; + } + + /** + * 关闭其它按钮 + */ + private UIMenuItem initCloseOther() { + UIMenuItem closeOther = new UIMenuItem(Toolkit.i18nText("Fine-Design_Basic_Tab_Close_Other_Templates_Of_Current_Category")); + closeOther.setHorizontalAlignment(SwingConstants.CENTER); + Dimension dimension = closeOther.getPreferredSize(); + dimension.height = ITEM_SIZE; + closeOther.setPreferredSize(dimension); + String currentOperator = getCurrentTabOperatorType(); + closeOther.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + MultiTemplateTabPane.getInstance().closeOtherByOperatorType(currentOperator); + } + }); + if (MultiTemplateTabPane.getInstance().getOpenedJTemplatesByOperator(currentOperator).size() <= 1) { + closeOther.setEnabled(false); + } + return closeOther; + } + + + /** + * 美观用 + */ + private JPanel createEmptyRow() { + return new JPanel() { + @Override + public Dimension getPreferredSize() { + Dimension d = super.getPreferredSize(); + d.height = 1; + return d; + } + }; + } + + /** + * 模板分类item + */ + private UIButton createCategory(String categoryName) { + UIButton button = new UIButton(categoryName); + button.setBorderPainted(false); + button.setExtraPainted(false); + button.setPreferredSize(new Dimension(menu.getWidth(), ITEM_SIZE)); + button.setOpaque(true); + button.setBackground(UIConstants.NORMAL_BACKGROUND); + button.setHorizontalAlignment(SwingConstants.LEFT); + button.setForeground(UIConstants.FLESH_BLUE); + return button; + } + + /** + * 创建 当前分类模板 item数组 + */ + private Component[] createCurrentCategory() { + return createListDownItem(MultiTemplateTabPane.getInstance().getOpenedJTemplatesByOperator(getCurrentTabOperatorType())); + } + + private String getCurrentTabOperatorType(){ + JTemplate jTemplate= HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + return jTemplate.getTemplateTabOperatorType(); + } + + /** + * 创建 其它分类模板 item数组 + */ + private Component[] createOtherCategory() { + String currentOperator = getCurrentTabOperatorType(); + List> openedTemplates = new ArrayList<>(); + Map>> map = MultiTemplateTabPane.getInstance().getOpenedJTemplatesByCategory(); + for (Map.Entry>> entry : map.entrySet()) { + if (!StringUtils.equals(currentOperator, entry.getKey())) { + openedTemplates.addAll(entry.getValue()); + } + } + return createListDownItem(openedTemplates); + } + + /** + * 根据template列表创建多个item + */ + private Component[] createListDownItem(List> openedTemplates) { + if (!CollectionUtils.isEmpty(openedTemplates)) { + Component[] templates = new Component[openedTemplates.size()]; + for (int i = 0; i < openedTemplates.size(); i++) { + templates[i] = createListDownMenuItem(openedTemplates.get(i)); + } + return templates; + } + return new Component[0]; + } + + /** + * 根据template对象创建item + */ + private Component createListDownMenuItem(JTemplate template) { + JPanel jPanel = new JPanel(); + jPanel.setPreferredSize(new Dimension(menu.getWidth(), ITEM_SIZE)); + jPanel.setLayout(new BorderLayout()); + + MenuItemButtonGroup menuItemButtonGroup = new MenuItemButtonGroup(template); + if (template == HistoryTemplateListCache.getInstance().getCurrentEditingTemplate()) { + menuItemButtonGroup.templateButton.setForeground(UIConstants.FLESH_BLUE); + } + + jPanel.add(menuItemButtonGroup.iconButton, BorderLayout.WEST); + jPanel.add(menuItemButtonGroup.templateButton, BorderLayout.CENTER); + jPanel.add(menuItemButtonGroup.closeButton, BorderLayout.EAST); + + return jPanel; + } + + /** + * menu的item由模板图标、模板名、模板关闭按钮组成 + */ + private class MenuItemButtonGroup { + + private final UIButton iconButton; + private final UIButton templateButton; + private final UIButton closeButton; + + public MenuItemButtonGroup(JTemplate template) { + iconButton = createIconButton(template); + templateButton = createTemplateButton(template); + closeButton = createCloseButton(); + initListener(template); + } + + /** + * item[0] 模板图标按钮初始化 + */ + private UIButton createIconButton(JTemplate template) { + UIButton button = new UIButton(template.getIcon(), template.getIcon(), template.getIcon()); + button.setPreferredSize(new Dimension(ITEM_SIZE, ITEM_SIZE)); + button.setOpaque(true); + button.setBackground(UIConstants.NORMAL_BACKGROUND); + return button; + } + + /** + * item[1] 切换模板按钮初始化 + */ + private UIButton createTemplateButton(JTemplate template) { + UIButton button = new UIButton(TemplateUtils.createLockeTemplatedName(template, template.getTemplateName())); + button.setBorderPainted(false); + button.setExtraPainted(false); + button.setPreferredSize(new Dimension(menu.getWidth() - ITEM_SIZE * 2, ITEM_SIZE)); + button.setOpaque(true); + button.setBackground(UIConstants.NORMAL_BACKGROUND); + button.setHorizontalAlignment(SwingConstants.LEFT); + return button; + } + + /** + * item[2] 关闭模板图标按钮初始化 + */ + private UIButton createCloseButton() { + UIButton button = new UIButton(CLOSE, MOUSE_OVER_CLOSE, MOUSE_PRESS_CLOSE); + button.setPreferredSize(new Dimension(ITEM_SIZE, ITEM_SIZE)); + button.setOpaque(true); + button.setBackground(UIConstants.NORMAL_BACKGROUND); + button.setVisible(false); + return button; + } + + private void initListener(JTemplate template) { + initIconButtonListener(); + initTemplateButtonListener(template); + initCloseButtonListener(template); + } + + /** + * item[0] 模板图标按钮鼠标事件 + */ + private void initIconButtonListener() { + iconButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + fireMouseEnteredEvent(); + } + + @Override + public void mouseExited(MouseEvent e) { + fireMouseExitedEvent(); + } + }); + } + + /** + * item[1] 切换模板按钮鼠标事件 + */ + private void initTemplateButtonListener(JTemplate template) { + templateButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + menu.setVisible(false); + MultiTemplateTabPane.getInstance().switchJTemplate(template); + } + + @Override + public void mouseEntered(MouseEvent e) { + fireMouseEnteredEvent(); + } + + @Override + public void mouseExited(MouseEvent e) { + fireMouseExitedEvent(); + } + }); + } + + /** + * item[2] 关闭模板按钮鼠标事件 + */ + private void initCloseButtonListener(JTemplate template) { + closeButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + menu.setVisible(false); + MultiTemplateTabPane.getInstance().setIsCloseCurrent(template == HistoryTemplateListCache.getInstance().getCurrentEditingTemplate()); + MultiTemplateTabPane.getInstance().closeFormat(template); + MultiTemplateTabPane.getInstance().closeSpecifiedTemplate(template); + } + + @Override + public void mouseEntered(MouseEvent e) { + fireMouseEnteredEvent(); + } + + @Override + public void mouseExited(MouseEvent e) { + fireMouseExitedEvent(); + } + }); + } + + /** + * mouse移入item范围 + */ + private void fireMouseEnteredEvent() { + iconButton.setBackground(UIConstants.HOVER_BLUE); + templateButton.setBackground(UIConstants.HOVER_BLUE); + closeButton.setBackground(UIConstants.HOVER_BLUE); + closeButton.setVisible(true); + } + + /** + * mouse移出item范围 + */ + private void fireMouseExitedEvent() { + iconButton.setBackground(UIConstants.NORMAL_BACKGROUND); + templateButton.setBackground(UIConstants.NORMAL_BACKGROUND); + closeButton.setBackground(UIConstants.NORMAL_BACKGROUND); + closeButton.setVisible(false); + } + + } + +} diff --git a/designer-base/src/main/java/com/fr/design/file/MultiTemplateTabPane.java b/designer-base/src/main/java/com/fr/design/file/MultiTemplateTabPane.java index 8e302fd977..8f2783a3ca 100644 --- a/designer-base/src/main/java/com/fr/design/file/MultiTemplateTabPane.java +++ b/designer-base/src/main/java/com/fr/design/file/MultiTemplateTabPane.java @@ -1,7 +1,6 @@ package com.fr.design.file; -import com.fr.base.BaseUtils; import com.fr.base.GraphHelper; import com.fr.base.svg.IconUtils; import com.fr.base.vcs.DesignerMode; @@ -19,7 +18,6 @@ import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.TemplateSavingChecker; import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; import com.fr.design.utils.DesignUtils; -import com.fr.design.utils.TemplateUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.design.utils.gui.GUIPaintUtils; import com.fr.design.worker.WorkerManager; @@ -42,11 +40,11 @@ import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; -import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.MenuElement; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; +import javax.swing.ToolTipManager; import javax.swing.plaf.basic.BasicMenuItemUI; import java.awt.AWTEvent; import java.awt.AlphaComposite; @@ -70,6 +68,8 @@ import java.awt.geom.Line2D; import java.awt.geom.Path2D; import java.awt.geom.RoundRectangle2D; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import static com.fr.design.dialog.FineJOptionPane.showConfirmDialog; import static javax.swing.JOptionPane.OK_CANCEL_OPTION; @@ -213,6 +213,35 @@ public class MultiTemplateTabPane extends JComponent { }); } + + /** + * 模板可以关闭的条件 + */ + class CloseCondition { + private CloseOption closeOption; + + public CloseCondition(CloseOption closeOption) { + this.closeOption = closeOption; + } + + /** + * 判断模板是否可以关闭,两个条件:1、是否满足CloseOption里面的条件(在左侧、在右侧等)2、是否和当前正在编辑模板属于同一种模板tab操作类型 + * @param closeJTemplate + * @param tplIndex + * @param i + * @return + */ + public boolean shouldClose(JTemplate closeJTemplate, int tplIndex, int i) { + boolean matchOption = this.closeOption.shouldClose(tplIndex, i); + JTemplate currentTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (!JTemplate.isValid(currentTemplate)) { + return matchOption; + } + return matchOption && ComparatorUtils.equals(closeJTemplate.getTemplateTabOperatorType(), + currentTemplate.getTemplateTabOperatorType()); + } + } + enum CloseOption { Left(Toolkit.i18nText("Fine-Design_Close_templates_To_The_Left")) { @Override @@ -323,29 +352,34 @@ public class MultiTemplateTabPane extends JComponent { @Override public void actionPerformed(ActionEvent e) { - SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(false); - if (saveSomeTempaltePane.showSavePane()) { + //只有关闭所有模板才需要判断当前模板,关闭左侧、右侧、其他都不需要 + SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(option == CloseOption.All); + CloseCondition closeCondition = new CloseCondition(option); + if (saveSomeTemplatePane.showSavePane(closeCondition, false)) { JTemplate[] templates = new JTemplate[openedTemplate.size()]; for (int i = 0; i < openedTemplate.size(); i++) { templates[i] = openedTemplate.get(i); } JTemplate currentTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - closeTemplate(templates, currentTemplate); + closeTemplate(closeCondition, templates, currentTemplate); - if (option == CloseOption.All) { + if (openedTemplate.size() == 0) { DesignerContext.getDesignerFrame().addAndActivateJTemplate(); + } else if (option == CloseOption.All){ + //openedTemplate(0)是JVirtualTemplate时需重新打开 + openedTemplate.get(0).activeOldJTemplate(); } else { - DesignerContext.getDesignerFrame().activateJTemplate(currentTemplate); + currentTemplate.activeOldJTemplate(); } MultiTemplateTabPane.getInstance().repaint(); } } - private void closeTemplate(JTemplate[] templates, JTemplate currentTemplate) { + private void closeTemplate(CloseCondition closeCondition, JTemplate[] templates, JTemplate currentTemplate) { for (int i = 0; i < templates.length; i++) { - if (option.shouldClose(tplIndex, i)) { + if (closeCondition.shouldClose(templates[i], tplIndex, i)) { JTemplate jTemplate = templates[i]; if (jTemplate == currentTemplate) { currentTemplate = option == CloseOption.All ? null : templates[tplIndex]; @@ -378,6 +412,46 @@ public class MultiTemplateTabPane extends JComponent { return openedTemplate.get(selectedIndex); } + /** + * 关闭所有指定模板tab操作类型的模板 + * @param operatorType + */ + public void closeOtherByOperatorType(String operatorType){ + JTemplate currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(false); + if (saveSomeTempaltePane.showSavePane(null, false, true)) { + List> openedTemplate = HistoryTemplateListCache.getInstance().getHistoryList(); + + JTemplate[] templates = new JTemplate[openedTemplate.size()]; + for (int i = 0; i < openedTemplate.size(); i++) { + templates[i] = openedTemplate.get(i); + } + closeTemplate(templates, currentEditingTemplate, operatorType); + + DesignerContext.getDesignerFrame().activateJTemplate(currentEditingTemplate); + MultiTemplateTabPane.getInstance().repaint(); + } + } + + /** + * 关闭指定的非当前编辑模板 + * @param templates + * @param operatorType + */ + private static void closeTemplate(JTemplate[] templates, JTemplate currentEditingTemplate, String operatorType) { + for (int i = 0; i < templates.length; i++) { + JTemplate jTemplate = templates[i]; + boolean needClose = ComparatorUtils.equals(operatorType, jTemplate.getTemplateTabOperatorType()) + && jTemplate != currentEditingTemplate; + if (!needClose) { + continue; + } + MultiTemplateTabPane.getInstance().closeFormat(jTemplate); + HistoryTemplateListCache.getInstance().closeSelectedReport(jTemplate); + MultiTemplateTabPane.getInstance().closeAndFreeLock(jTemplate); + } + } + /** * 关闭掉当前已打开文件列表中指定的文件 @@ -478,11 +552,7 @@ public class MultiTemplateTabPane extends JComponent { private String tempalteShowName(JTemplate template) { - String name = TemplateUtils.createLockeTemplatedName(template, template.getTemplateName()); - if (!template.isSaved() && !name.endsWith(" *")) { - name += " *"; - } - return name; + return template.getTabShowName(template); } /** @@ -500,40 +570,7 @@ public class MultiTemplateTabPane extends JComponent { private void showListDown() { - - UIScrollPopUpMenu menu = new UIScrollPopUpMenu(); - menu.setBorder(BorderFactory.createEmptyBorder(-3, 3, 3, 0)); - menu.add(initCloseOther()); - JSeparator separator = new JSeparator() { - @Override - public Dimension getPreferredSize() { - Dimension d = super.getPreferredSize(); - d.height = 1; - return d; - } - }; - menu.add(new JPanel() { - @Override - public Dimension getPreferredSize() { - Dimension d = super.getPreferredSize(); - d.height = 1; - return d; - } - }); - separator.setForeground(UIConstants.LINE_COLOR); - menu.add(separator); - menu.add(new JPanel() { - @Override - public Dimension getPreferredSize() { - Dimension d = super.getPreferredSize(); - d.height = 1; - return d; - } - }); - UIMenuItem[] items = createListDownTemplate(); - for (int i = 0; i < items.length; i++) { - menu.add(items[i]); - } + UIScrollPopUpMenu menu = MultiTemplateTabMenuFactory.getInstance().createMenu(); GUICoreUtils.showPopupMenu(menu, MultiTemplateTabPane.getInstance(), MultiTemplateTabPane.getInstance().getWidth() - menu.getPreferredSize().width, getY() - 1 + getHeight()); } @@ -583,6 +620,9 @@ public class MultiTemplateTabPane extends JComponent { //从可以开始展示在tab面板上的tab开始画 for (int i = minPaintIndex; i <= maxPaintIndex; i++) { JTemplate template = openedTemplate.get(i); + if (!showJTemplateTab(template)){ + continue; + } Icon icon = template.getIcon(); String name = tempalteShowName(template); //如果tab名字的长度大于最大能显示的英文字符长度,则进行省略号处理 @@ -717,13 +757,67 @@ public class MultiTemplateTabPane extends JComponent { minPaintIndex = 0; maxPaintIndex = openedTemplate.size() - 1; } + //需要根据每个tab的宽度重新check下实际的maxPaintIndex和minPaintIndex + checkActualPaintIndex(); + } + + /** + * 先计算出需要补充的tab个数 + * @return + */ + private int calTabCountComplemented(){ + int a = 0; + for (int i = minPaintIndex; i <= maxPaintIndex; i++) { + JTemplate template = openedTemplate.get(i); + if (!showJTemplateTab(template)) { + a++; + } + } + return a; + } + + + /** + * 由于可能存在宽度为0的tab,所以这边需要重新check下,先往后补,再往前补 + */ + private void checkActualPaintIndex(){ + int tabCount = calTabCountComplemented(); + if (tabCount == 0){ + return; + } + if (maxPaintIndex < openedTemplate.size() - 1) { + for (int i = maxPaintIndex + 1; i < openedTemplate.size(); i++) { + JTemplate template = openedTemplate.get(i); + if (showJTemplateTab(template)) { + tabCount--; + } + maxPaintIndex++; + if (tabCount == 0){ + return; + } + } + } + if (minPaintIndex > 0){ + for (int i = minPaintIndex - 1; i >= 0; i--) { + JTemplate template = openedTemplate.get(i); + if (showJTemplateTab(template)) { + tabCount--; + } + minPaintIndex--; + if (tabCount == 0){ + return; + } + } + } } //个数小于最多能容纳的个数的情况下,看看宽度每个要画多少 private void calculateRealAverageWidth(double maxwidth, int templateNum) { + JTemplate jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + List> showTemplates = getOpenedJTemplatesByOperator(jTemplate.getTemplateTabOperatorType()); - int num = openedTemplate.size() > templateNum ? templateNum : openedTemplate.size(); + int num = Math.min(showTemplates.size(), templateNum); realWidth = (int) (maxwidth / (num)); if (realWidth > MAXWIDTH) { realWidth = MAXWIDTH; @@ -906,7 +1000,7 @@ public class MultiTemplateTabPane extends JComponent { if (!specifiedTemplate.isALLSaved() && !DesignerMode.isVcsMode()) { specifiedTemplate.stopEditing(); int returnVal = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Utils_Would_You_Like_To_Save") + " \"" + specifiedTemplate.getEditingFILE() + "\" ?", - Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (returnVal == JOptionPane.YES_OPTION) { CallbackSaveWorker worker = specifiedTemplate.save(); worker.addSuccessCallback(new Runnable() { @@ -932,7 +1026,7 @@ public class MultiTemplateTabPane extends JComponent { activePrevTemplateAfterClose(); } - private void closeAndFreeLock(@Nonnull JTemplate template) { + public void closeAndFreeLock(@Nonnull JTemplate template) { FILE file = template.getEditingFILE(); // 只有是环境内的文件,才执行释放锁 if (file != null && file.isEnvFile()) { @@ -986,9 +1080,12 @@ public class MultiTemplateTabPane extends JComponent { // selectIndex 没有变化,但是对应的模板已经变成了前一张模板 if (closeIconIndex == selectedIndex || isCloseCurrent) { // 如果当前关闭的模板在最右侧,那么预览上一个,防止数组越界 + // 关闭的模板是当前选中的模板时,需要重新计算下一个待展示的模板的index if (selectedIndex >= maxPaintIndex) { // selectIndex 不会 <0 因为如果关闭的是打开的最后一个模板,那么关闭之后 openedTemplate.isEmpty() = true - selectedIndex--; + selectedIndex = calNextShowJTemplateIndex(selectedIndex - 1); + } else { + selectedIndex = calNextShowJTemplateIndex(selectedIndex); } isCloseCurrent = false; } @@ -1005,6 +1102,16 @@ public class MultiTemplateTabPane extends JComponent { } } + /** + * 计算下一个可以展示的模板index + * @param currentIndex + * @return + */ + public int calNextShowJTemplateIndex(int currentIndex) { + JTemplate jTemplate= HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + return MultiTemplateTabUtils.calShowTemplateIndex(currentIndex, openedTemplate, jTemplate.getTemplateTabOperatorType()); + } + private boolean isOverCloseIcon(int evtX) { boolean isOverCloseIcon = false; @@ -1027,7 +1134,7 @@ public class MultiTemplateTabPane extends JComponent { private int getTemplateIndex(int evtX) { int textX = 0; for (int i = minPaintIndex; i <= maxPaintIndex; i++) { - int textWidth = realWidth; + int textWidth = showJTemplateTab(openedTemplate.get(i)) ? realWidth : 0; if (evtX >= textX && evtX < textX + textWidth) { return i; } @@ -1089,6 +1196,7 @@ public class MultiTemplateTabPane extends JComponent { private class MultiTemplateTabMouseListener implements MouseListener { + private boolean oldLightWeightPopupEnabled; /** * 鼠标进入 @@ -1097,7 +1205,8 @@ public class MultiTemplateTabPane extends JComponent { */ @Override public void mouseEntered(MouseEvent e) { - // do nothing + this.oldLightWeightPopupEnabled = ToolTipManager.sharedInstance().isLightWeightPopupEnabled(); + ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false); } /** @@ -1107,6 +1216,9 @@ public class MultiTemplateTabPane extends JComponent { */ @Override public void mouseExited(MouseEvent e) { + ToolTipManager.sharedInstance().setEnabled(false); + ToolTipManager.sharedInstance().setEnabled(true); + ToolTipManager.sharedInstance().setLightWeightPopupEnabled(this.oldLightWeightPopupEnabled); listDownMode = LIST_DOWN; closeIconIndex = -1; mouseOveredIndex = -1; @@ -1184,29 +1296,44 @@ public class MultiTemplateTabPane extends JComponent { //没有点击关闭和ListDown按钮,则切换到点击的模板处 closeIconIndex = -1; clodeMode = CLOSE; - int tempSelectedIndex = selectedIndex; - if (selectedIndex != getTemplateIndex(evtX) && getTemplateIndex(evtX) != -1) { - openedTemplate.get(selectedIndex).stopEditing(); - selectedIndex = getTemplateIndex(evtX); - //如果在权限编辑情况下,不允许切换到表单类型的工作簿 - if (DesignerMode.isAuthorityEditing() && !openedTemplate.get(selectedIndex).isJWorkBook()) { - DesignerContext.getDesignerFrame().addAndActivateJTemplate(openedTemplate.get(tempSelectedIndex)); - FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Form_Authority_Edited_Cannot_Be_Supported") - + "!", Toolkit.i18nText("Fine-Design_Basic_Alert"), JOptionPane.WARNING_MESSAGE); - MultiTemplateTabPane.this.repaint(); - return; - } - JTemplate evtXTemplate = openedTemplate.get(getTemplateIndex(evtX)); - evtXTemplate.activeNewJTemplate(); - } + switchJTemplate(getTemplateIndex(evtX)); isShowList = false; } MultiTemplateTabPane.this.repaint(); - - } + } + /** + * 切换到指定模板 + * @param jTemplate + */ + public void switchJTemplate(JTemplate jTemplate) { + int switchIndex = this.openedTemplate.indexOf(jTemplate); + if (switchIndex >= 0) { + switchJTemplate(switchIndex); + } + } + /** + * 切换到指定index + * @param switchIndex + */ + private void switchJTemplate(int switchIndex){ + int tempSelectedIndex = selectedIndex; + if (selectedIndex != switchIndex && switchIndex != -1) { + openedTemplate.get(selectedIndex).stopEditing(); + selectedIndex = switchIndex; + //如果在权限编辑情况下,不允许切换到表单类型的工作簿 + if (DesignerMode.isAuthorityEditing() && !openedTemplate.get(selectedIndex).isJWorkBook()) { + DesignerContext.getDesignerFrame().addAndActivateJTemplate(openedTemplate.get(tempSelectedIndex)); + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Form_Authority_Edited_Cannot_Be_Supported") + + "!", Toolkit.i18nText("Fine-Design_Basic_Alert"), JOptionPane.WARNING_MESSAGE); + MultiTemplateTabPane.this.repaint(); + return; + } + JTemplate evtXTemplate = openedTemplate.get(switchIndex); + evtXTemplate.activeNewJTemplate(); + } } private boolean checkCurrentClose(JTemplate template) { @@ -1251,5 +1378,34 @@ public class MultiTemplateTabPane extends JComponent { } } + /** + * 判断是否显示在tab栏上 + * @param jTemplate + * @return + */ + private boolean showJTemplateTab(JTemplate jTemplate){ + JTemplate current = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + return ComparatorUtils.equals(current.getTemplateTabOperatorType(), jTemplate.getTemplateTabOperatorType()); + } + + /** + * 获取tab操作类型的模板 + * @param operator + * @return + */ + public List> getOpenedJTemplatesByOperator(String operator) { + return openedTemplate.stream().filter((jTemplate) -> ComparatorUtils.equals(jTemplate.getTemplateTabOperatorType(), operator)) + .collect(Collectors.toList()); + } + + /** + * 根据tab操作类型进行分类 + * @return + */ + public Map>> getOpenedJTemplatesByCategory() { + return openedTemplate.stream() + .collect(Collectors.groupingBy(JTemplate::getTemplateTabOperatorType)); + } + } diff --git a/designer-base/src/main/java/com/fr/design/file/MultiTemplateTabUtils.java b/designer-base/src/main/java/com/fr/design/file/MultiTemplateTabUtils.java new file mode 100644 index 0000000000..344abe64f2 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/file/MultiTemplateTabUtils.java @@ -0,0 +1,59 @@ +package com.fr.design.file; + +import com.fr.design.mainframe.JTemplate; +import com.fr.general.ComparatorUtils; + +import java.util.List; +import java.util.function.Predicate; + +public class MultiTemplateTabUtils { + /** + * 计算离currentIndex最近的相同模式的模板index值(优先左边) + * + * @param currentIndex 当前index + * @param openedTemplate 模板list + * @param type 当前显示模式 + * @return + */ + public static int calShowTemplateIndex(int currentIndex, List> openedTemplate, String type) { + if (currentIndex < 0 || currentIndex > openedTemplate.size() - 1) { + return -1; + } + int result = getShowJTemplateTab(currentIndex, openedTemplate, template -> showJTemplateTab(type, template)); + if (result != -1) return result; + return getShowJTemplateTab(currentIndex, openedTemplate, template -> !showJTemplateTab(type, template)); + } + + /** + * 先从左找,再从右找离得最近的满足条件的模板 + * + * @param currentIndex 当前index + * @param openedTemplate 模板list + * @param predicate + * @return + */ + private static int getShowJTemplateTab(int currentIndex, List> openedTemplate, Predicate> predicate) { + for (int i = currentIndex; i >= 0; i--) { + if (predicate.test(openedTemplate.get(i))) { + return i; + } + } + for (int i = currentIndex + 1; i < openedTemplate.size(); i++) { + if (predicate.test(openedTemplate.get(i))) { + return i; + } + } + return -1; + } + + /** + * 是否显示模板 + * + * @param type 模板类型 + * @param jTemplate 模板 + * @return + */ + private static boolean showJTemplateTab(String type, JTemplate jTemplate) { + return ComparatorUtils.equals(type, jTemplate.getTemplateTabOperatorType()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/file/NewTemplatePane.java b/designer-base/src/main/java/com/fr/design/file/NewTemplatePane.java index dae921a1c8..81f82e78c6 100644 --- a/designer-base/src/main/java/com/fr/design/file/NewTemplatePane.java +++ b/designer-base/src/main/java/com/fr/design/file/NewTemplatePane.java @@ -81,11 +81,19 @@ public abstract class NewTemplatePane extends JComponent implements MouseListene } if (isOverNewIcon(evtX) && newWorkBookIconMode != GRAY_NEW_CPT) { newWorkBookIconMode = getMousePressNew(); - DesignerContext.getDesignerFrame().addAndActivateJTemplate(); + createNewTemplate(); } this.repaint(); } + + /** + * 新建模板 + */ + protected void createNewTemplate() { + DesignerContext.getDesignerFrame().addAndActivateJTemplate(); + } + /** *鼠标松开 * @param e 事件 diff --git a/designer-base/src/main/java/com/fr/design/file/SaveSomeTemplatePane.java b/designer-base/src/main/java/com/fr/design/file/SaveSomeTemplatePane.java index 72945b31c9..1517309ef1 100644 --- a/designer-base/src/main/java/com/fr/design/file/SaveSomeTemplatePane.java +++ b/designer-base/src/main/java/com/fr/design/file/SaveSomeTemplatePane.java @@ -17,6 +17,7 @@ import com.fr.design.mainframe.JTemplate; import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -47,6 +48,7 @@ public class SaveSomeTemplatePane extends BasicPane { /** * 支持自定义设置 dialog的父窗口 + * * @param isNeedTojudgeCurrent * @param parent */ @@ -79,11 +81,14 @@ public class SaveSomeTemplatePane extends BasicPane { this.isJudgeCurrentEditingTemplate = isNeedTojudgeCurrent; } - private void initTemplatesChoosePane() { + + private void initTemplatesChoosePane(boolean judgeJTemplateMustSave) { templatesChoosePane.setBorder(BorderFactory.createTitledBorder("")); for (int i = 0; i < unSavedTemplate.size(); i++) { templateCheckBoxes[i] = new UICheckBox(unSavedTemplate.get(i).getEditingFILE().getName()); templateCheckBoxes[i].setSelected(true); + boolean needSave = judgeJTemplateMustSave && unSavedTemplate.get(i).needSaveBeforeSwitchEnv(); + templateCheckBoxes[i].setEnabled(!needSave); } final UIList templatesList = new UIList(templateCheckBoxes); @@ -103,7 +108,10 @@ public class SaveSomeTemplatePane extends BasicPane { boolean isSelected = chooseAllCheckBox.isSelected(); for (int i = 0; i < templatesList.getModel().getSize(); i++) { UICheckBox checkBox = (UICheckBox) templatesList.getModel().getElementAt(i); - checkBox.setSelected(isSelected); + boolean mustSaveBeforeSwitchEnv = judgeJTemplateMustSave && unSavedTemplate.get(i).needSaveBeforeSwitchEnv(); + checkBox.setSelected(mustSaveBeforeSwitchEnv || isSelected); + templateCheckBoxes[i].setEnabled(!mustSaveBeforeSwitchEnv); + } templatesList.repaint(); } @@ -116,8 +124,10 @@ public class SaveSomeTemplatePane extends BasicPane { if (index < 0) { return; } + boolean mustSaveBeforeSwitchEnv = judgeJTemplateMustSave + && unSavedTemplate.get(index).needSaveBeforeSwitchEnv(); UICheckBox checkBox = (UICheckBox) templatesList.getModel().getElementAt(index); - checkBox.setSelected(!checkBox.isSelected()); + checkBox.setSelected(mustSaveBeforeSwitchEnv ||!checkBox.isSelected()); //根据templateCheckBoxes中的选择情况来更新全选框的状态 int selectedCount = calculateSelectedNum(); @@ -139,7 +149,7 @@ public class SaveSomeTemplatePane extends BasicPane { /** * 获取templateCheckBoxes中状态为选中状态的CheckBox数量 - * */ + */ private int calculateSelectedNum() { int count = 0; for (UICheckBox checkBox : templateCheckBoxes) { @@ -152,7 +162,40 @@ public class SaveSomeTemplatePane extends BasicPane { public boolean showSavePane() { - populate(); + return showSavePane(false); + } + + /** + * 显示保存模板提醒面板 + * + * @param judgeJTemplateMustSave 模板是否必须保存 + * @return + */ + public boolean showSavePane(boolean judgeJTemplateMustSave) { + return showSavePane(null, judgeJTemplateMustSave); + } + + /** + * 显示保存模板提醒面板 + * + * @param option 具体关闭操作 + * @param judgeJTemplateMustSave 模板是否必须保存 + * @return + */ + public boolean showSavePane(@Nullable MultiTemplateTabPane.CloseCondition option, boolean judgeJTemplateMustSave) { + return showSavePane(option, judgeJTemplateMustSave, false); + } + + /** + * 显示保存模板提醒面板 + * + * @param option 具体关闭操作 + * @param judgeJTemplateMustSave 模板是否必须保存 + * @param judgeSameTabType 是否只包含当前编辑的模板类型 + * @return + */ + public boolean showSavePane(@Nullable MultiTemplateTabPane.CloseCondition option, boolean judgeJTemplateMustSave, boolean judgeSameTabType) { + initAndPopulate(option, judgeJTemplateMustSave, judgeSameTabType); //如果有未保存的文件 ,则跳出保存对话框,选择要存储的项目 if (!unSavedTemplate.isEmpty()) { dialog.setVisible(true); @@ -162,19 +205,29 @@ public class SaveSomeTemplatePane extends BasicPane { return isAllSaved; } - public void populate() { - java.util.List> opendedTemplate = HistoryTemplateListPane.getInstance().getHistoryList(); + protected java.util.List> getOpenedTemplatesToProcess(){ + return HistoryTemplateListPane.getInstance().getHistoryList(); + } + + private void initAndPopulate(@Nullable MultiTemplateTabPane.CloseCondition option, boolean judgeJTemplateMustSave, boolean judgeSameTabType) { + java.util.List> opendedTemplate = getOpenedTemplatesToProcess(); JTemplate currentTemplate = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate(); + int currentIndex = opendedTemplate.indexOf(currentTemplate); for (int i = 0; i < opendedTemplate.size(); i++) { - if (isneedToAdd(opendedTemplate.get(i), currentTemplate)) { + //满足关闭条件的才继续判断文件是否发生了改动 + boolean needClose = option == null || option.shouldClose(opendedTemplate.get(i), currentIndex, i); + if (judgeSameTabType) { + needClose &= ComparatorUtils.equals(opendedTemplate.get(i).getTemplateTabOperatorType(), currentTemplate.getTemplateTabOperatorType()); + } + if (needClose && isneedToAdd(opendedTemplate.get(i), currentTemplate)) { unSavedTemplate.add(opendedTemplate.get(i)); } } templateCheckBoxes = new UICheckBox[unSavedTemplate.size()]; - initTemplatesChoosePane(); + initTemplatesChoosePane(judgeJTemplateMustSave); } - private boolean isneedToAdd(JTemplate template, JTemplate currentTemplate) { + protected boolean isneedToAdd(JTemplate template, JTemplate currentTemplate) { //所有模板都判断是不是保存 if (isJudgeCurrentEditingTemplate) { return !template.isALLSaved(); @@ -194,7 +247,7 @@ public class SaveSomeTemplatePane extends BasicPane { specifiedTemplate.stopEditing(); return specifiedTemplate.saveTemplate(); } - FineLoggerFactory.getLogger().info( com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Template_Already_Saved", specifiedTemplate.getEditingFILE().getName())); + FineLoggerFactory.getLogger().info(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Template_Already_Saved", specifiedTemplate.getEditingFILE().getName())); return true; } diff --git a/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java b/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java index 306ce0f886..d60a45135d 100644 --- a/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java +++ b/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java @@ -18,6 +18,7 @@ import com.fr.design.lock.LockInfoDialog; import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateSearchRemindPane; +import com.fr.design.mainframe.vcs.common.VcsHelper; import com.fr.file.FILE; import com.fr.file.FileNodeFILE; import com.fr.file.filetree.FileNode; @@ -38,6 +39,7 @@ import java.util.UUID; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; import javax.swing.ToolTipManager; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreeNode; @@ -59,9 +61,11 @@ import java.util.Objects; import java.util.Observable; import java.util.Observer; import java.util.Set; +import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import com.fr.workspace.server.repository.template.TemplateRepository; +import com.fr.workspace.server.vcs.VcsOperator; import org.jetbrains.annotations.Nullable; @@ -342,17 +346,11 @@ public class TemplateTreePane extends JPanel implements FileOperations { if (FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), tipContent, - Toolkit.i18nText("Fine-Design_Basic_Confirm"), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), YES_NO_OPTION) == JOptionPane.YES_OPTION) { // 删除所有选中的即可 - if (!deleteNodes(Arrays.asList(treeNodes))) { - FineJOptionPane.showConfirmDialog(null, - Toolkit.i18nText("Fine-Design_Basic_Delete_Failure"), - Toolkit.i18nText("Fine-Design_Basic_Error"), - JOptionPane.DEFAULT_OPTION, - JOptionPane.ERROR_MESSAGE); - } + deleteNodes(Arrays.asList(treeNodes)); } } else { @@ -373,21 +371,13 @@ public class TemplateTreePane extends JPanel implements FileOperations { if (FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), tipContent, - Toolkit.i18nText("Fine-Design_Basic_Confirm"), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), YES_NO_OPTION) == JOptionPane.YES_OPTION) { // 删除其他 - if (!deleteNodes(deletableNodes)) { - FineJOptionPane.showConfirmDialog(null, - Toolkit.i18nText("Fine-Design_Basic_Delete_Failure"), - Toolkit.i18nText("Fine-Design_Basic_Error"), - JOptionPane.DEFAULT_OPTION, - JOptionPane.ERROR_MESSAGE); - } + deleteNodes(deletableNodes); } } - Set deletedFileNode = deletableNodes.stream().map(treeNode -> (FileNode) treeNode.getUserObject()).collect(Collectors.toSet()); - refreshAfterDelete(deletedFileNode); } private void refreshAfterDelete(Set deletedPaths) { @@ -407,23 +397,54 @@ public class TemplateTreePane extends JPanel implements FileOperations { } } - private boolean deleteNodes(Collection nodes) { - - boolean success = true; - for (ExpandMutableTreeNode treeNode : nodes) { - Object node = treeNode.getUserObject(); - if (node instanceof FileNode) { - FileNodeFILE nodeFILE = new FileNodeFILE((FileNode) node); - if (nodeFILE.exists()) { - if (TemplateResourceManager.getResource().delete(nodeFILE)) { - HistoryTemplateListCache.getInstance().deleteFile(nodeFILE); - } else { - success = false; + private void deleteNodes(Collection nodes) { + new SwingWorker(){ + @Override + protected Boolean doInBackground() throws Exception { + boolean success = true; + for (ExpandMutableTreeNode treeNode : nodes) { + Object node = treeNode.getUserObject(); + if (node instanceof FileNode) { + FileNodeFILE nodeFILE = new FileNodeFILE((FileNode) node); + if (nodeFILE.exists()) { + if (!VcsHelper.getInstance().isLegacyMode()) { + try { + WorkContext.getCurrent().get(VcsOperator.class).recycleVersion(VcsHelper.getInstance().getCurrentUsername(), nodeFILE.getPath()); + } catch (Exception e) { + FineLoggerFactory.getLogger().error("[VcsV2] recycle {} failed", nodeFILE.getName()); + } + } + if (TemplateResourceManager.getResource().delete(nodeFILE)) { + HistoryTemplateListCache.getInstance().deleteFile(nodeFILE); + } else { + success = false; + } + } } } + return success; } - } - return success; + @Override + protected void done() { + try { + if (!get()) { + showErrorDialog(); + } + Set deletedFileNode = nodes.stream().map(treeNode -> (FileNode) treeNode.getUserObject()).collect(Collectors.toSet()); + refreshAfterDelete(deletedFileNode); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + }.execute(); + } + + private void showErrorDialog() { + FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), + Toolkit.i18nText("Fine-Design_Basic_Delete_Failure"), + Toolkit.i18nText("Fine-Design_Basic_Error"), + JOptionPane.DEFAULT_OPTION, + JOptionPane.ERROR_MESSAGE); } diff --git a/designer-base/src/main/java/com/fr/design/formula/DefaultTinyFormulaPane.java b/designer-base/src/main/java/com/fr/design/formula/DefaultTinyFormulaPane.java new file mode 100644 index 0000000000..05053eec4f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/formula/DefaultTinyFormulaPane.java @@ -0,0 +1,17 @@ +package com.fr.design.formula; + +import com.fr.base.BaseFormula; + +/** + * @author Carlson + * @version 11.0 + * Created by Carlson on 2023/8/14 17:15 + * @description 默认的公式输入面板(包含一个输入框和一个F(x)按钮),清空公式内容后不会显示“$$$”,主要在图表配置面板里使用 + **/ +public class DefaultTinyFormulaPane extends TinyFormulaPane{ + + @Override + protected void populateTextField(BaseFormula fm) { + formulaTextField.setText(fm.getContent()); + } +} diff --git a/designer-base/src/main/java/com/fr/design/formula/FormulaPane.java b/designer-base/src/main/java/com/fr/design/formula/FormulaPane.java index f53930602c..f41c044b74 100644 --- a/designer-base/src/main/java/com/fr/design/formula/FormulaPane.java +++ b/designer-base/src/main/java/com/fr/design/formula/FormulaPane.java @@ -34,6 +34,7 @@ import com.fr.design.gui.itextarea.UITextArea; import com.fr.design.gui.itextfield.UITextField; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.RSyntaxTextArea; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.SyntaxConstants; +import com.fr.design.i18n.DesignSizeI18nManager; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; @@ -742,7 +743,8 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { } public BasicDialog showLargeWindow(Window window, DialogActionListener l) { - BasicDialog basicDialog = super.showWindowWithCustomSize(window, l, new Dimension(900, 600)); + Dimension dimension = DesignSizeI18nManager.getInstance().i18nDimension(this.getClass().getName()); + BasicDialog basicDialog = super.showWindowWithCustomSize(window, l, dimension); basicDialog.setMinimumSize(new Dimension(900, 600)); basicDialog.setResizable(true); return basicDialog; @@ -1196,7 +1198,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { private void initDescriptionTextArea() { // Description - descriptionTextArea = new UITextArea(DESCRIPTION_TEXT_AREA_ROW,DESCRIPTION_TEXT_AREA_COLUMN); + descriptionTextArea = new UITextArea(DESCRIPTION_TEXT_AREA_ROW, DESCRIPTION_TEXT_AREA_COLUMN); descriptionTextArea.setBackground(Color.white); descriptionTextArea.setLineWrap(true); descriptionTextArea.setWrapStyleWord(true); @@ -1282,7 +1284,7 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula { desScrollPane.setBorder(null); panel.add(this.createNamePane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_FormulaPane_Formula_Description") + ":", desScrollPane), BorderLayout.CENTER); initVariablesTreeSelectionListener(); - this.add(panel,BorderLayout.CENTER); + this.add(panel, BorderLayout.CENTER); } private void initComponents() { diff --git a/designer-base/src/main/java/com/fr/design/formula/TinyFormulaPane.java b/designer-base/src/main/java/com/fr/design/formula/TinyFormulaPane.java index d3060b42b8..e5594ddd11 100644 --- a/designer-base/src/main/java/com/fr/design/formula/TinyFormulaPane.java +++ b/designer-base/src/main/java/com/fr/design/formula/TinyFormulaPane.java @@ -11,9 +11,11 @@ import com.fr.design.gui.itextfield.UITextField; import com.fr.design.layout.TableLayout; import com.fr.design.mainframe.DesignerContext; - -import javax.swing.*; -import java.awt.*; +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Cursor; +import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; diff --git a/designer-base/src/main/java/com/fr/design/fun/DefaultValueAdjustProvider.java b/designer-base/src/main/java/com/fr/design/fun/DefaultValueAdjustProvider.java index 1e553735dd..f534163b04 100644 --- a/designer-base/src/main/java/com/fr/design/fun/DefaultValueAdjustProvider.java +++ b/designer-base/src/main/java/com/fr/design/fun/DefaultValueAdjustProvider.java @@ -14,7 +14,7 @@ import java.awt.Font; */ public interface DefaultValueAdjustProvider extends Selectable { String MARK_STRING = "DefaultValueAdjustProvider"; - int CURRENT_LEVEL = 1; + int CURRENT_LEVEL = 2; /** * 调整单元格对象默认值 diff --git a/designer-base/src/main/java/com/fr/design/fun/impl/AbstractDefaultValueAdjustProvider.java b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractDefaultValueAdjustProvider.java index b2fc58ba8f..cb1357abe3 100644 --- a/designer-base/src/main/java/com/fr/design/fun/impl/AbstractDefaultValueAdjustProvider.java +++ b/designer-base/src/main/java/com/fr/design/fun/impl/AbstractDefaultValueAdjustProvider.java @@ -9,9 +9,13 @@ import com.fr.stable.fun.mark.API; @API(level = DefaultValueAdjustProvider.CURRENT_LEVEL) public abstract class AbstractDefaultValueAdjustProvider extends AbstractProvider implements DefaultValueAdjustProvider { + //1.16及之前发布版本插件里面没有实现currentAPILevel方法,运行时候会走到主jar,拿到-2。 + //1.16.1及之后发布版本插件实现currentAPILevel方法,编译插件的时候,会把DefaultValueAdjustProvider.CURRENT_LEVEL的值编译给插件,比如1.16.1会拿到2。 + private static final int OLD_CURRENT_LEVEL = -2; + @Override public int currentAPILevel() { - return CURRENT_LEVEL; + return OLD_CURRENT_LEVEL; } public String mark4Provider() { diff --git a/designer-base/src/main/java/com/fr/design/gui/UILookAndFeel.java b/designer-base/src/main/java/com/fr/design/gui/UILookAndFeel.java index a8e45b24cf..c33f3e0fc2 100644 --- a/designer-base/src/main/java/com/fr/design/gui/UILookAndFeel.java +++ b/designer-base/src/main/java/com/fr/design/gui/UILookAndFeel.java @@ -1,5 +1,6 @@ package com.fr.design.gui; +import com.fr.base.svg.IconUtils; import com.fr.design.gui.borders.UIFrameBorder; import com.fr.design.gui.borders.UIInternalFrameBorder; import com.fr.design.gui.borders.UITableHeaderBorder; @@ -160,10 +161,10 @@ public class UILookAndFeel extends MetalLookAndFeel { table.put("Tree.collapsedIcon", loadIcon("TreePlusIcon.png", this)); table.put("Tree.openIcon", loadIcon("TreeFolderOpenedIcon.png", this)); table.put("Tree.closedIcon", loadIcon("TreeFolderClosedIcon.png", this)); - table.put("Tree.leafIcon", loadIcon("TreeLeafIcon.svg", this)); + table.put("Tree.leafIcon", loadIcon("TreeLeafIcon.png", this)); table.put("FileView.directoryIcon", loadIcon("DirectoryIcon.png", this)); table.put("FileView.computerIcon", loadIcon("ComputerIcon.png", this)); - table.put("FileView.fileIcon", loadIcon("FileIcon.svg", this)); + table.put("FileView.fileIcon", IconUtils.readIcon("/com/fr/design/images/lookandfeel/FileIcon.svg")); table.put("FileView.floppyDriveIcon", loadIcon("FloppyIcon.png", this)); table.put("FileView.hardDriveIcon", loadIcon("HarddiskIcon.png", this)); table.put("FileChooser.detailsViewIcon", loadIcon("FileDetailsIcon.png", this)); diff --git a/designer-base/src/main/java/com/fr/design/gui/autocomplete/AbstractCompletionProvider.java b/designer-base/src/main/java/com/fr/design/gui/autocomplete/AbstractCompletionProvider.java index a03e3d8b00..ceacb715ce 100644 --- a/designer-base/src/main/java/com/fr/design/gui/autocomplete/AbstractCompletionProvider.java +++ b/designer-base/src/main/java/com/fr/design/gui/autocomplete/AbstractCompletionProvider.java @@ -8,12 +8,14 @@ */ package com.fr.design.gui.autocomplete; +import com.fr.stable.StringUtils; + +import javax.swing.text.JTextComponent; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import javax.swing.text.JTextComponent; /** @@ -186,7 +188,9 @@ public abstract class AbstractCompletionProvider while (index= paramPrefix.length()) ? text.substring(index - paramPrefix.length(), index) : StringUtils.EMPTY; + if (!FormulaPane.getParamPrefix(replacement).equals(prefix)) { + replacement = paramPrefix + replacement; + } + textComp.replaceSelection(replacement); } else { textComp.replaceSelection(replacement + "()"); int caretPosition = textComp.getCaretPosition(); diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/JListControlPane.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/JListControlPane.java index ee05422caa..dfece2e133 100644 --- a/designer-base/src/main/java/com/fr/design/gui/controlpane/JListControlPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/JListControlPane.java @@ -17,16 +17,20 @@ import com.fr.stable.Nameable; import com.fr.stable.StringUtils; import com.fr.stable.core.PropertyChangeAdapter; -import javax.swing.DefaultListCellRenderer; +import javax.swing.BorderFactory; import javax.swing.DefaultListModel; +import javax.swing.Icon; +import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JPopupMenu; +import javax.swing.ListCellRenderer; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.BorderLayout; +import java.awt.Color; import java.awt.Component; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -343,21 +347,48 @@ public abstract class JListControlPane extends JControlPane implements ListContr } protected class NameableListCellRenderer extends - DefaultListCellRenderer { + JPanel implements ListCellRenderer { + + private final JLabel textLabel; + private final JLabel iconLabel; + + /** + * JList默认单元格渲染器的选中背景色 + */ + private final Color selectedBgColor = new Color(65, 155, 249); + protected NameableListCellRenderer() { + setLayout(new BorderLayout()); + this.textLabel = new JLabel(); + this.iconLabel = new JLabel(); + this.textLabel.setBorder(BorderFactory.createEmptyBorder(1, 0, 1, 1)); + this.iconLabel.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 0)); + add(this.textLabel, BorderLayout.CENTER); + add(this.iconLabel, BorderLayout.WEST); + this.iconLabel.setBackground(Color.WHITE); + //iconLabel和textLabel的背景颜色不会被JList背景颜色覆盖,开发者自定义 + this.textLabel.setOpaque(true); + this.iconLabel.setOpaque(true); + } + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - super.getListCellRendererComponent(list, value, index, isSelected, - cellHasFocus); if (value instanceof ListModelElement) { ListModelElement element = ((ListModelElement) value); Nameable nameable = element.wrapper; - this.setText(nameable.getName()); + this.textLabel.setText(nameable.getName()); boolean iconSet = false; + if(isSelected) { + this.textLabel.setBackground(selectedBgColor); + this.textLabel.setForeground(Color.WHITE); + } else { + this.textLabel.setBackground(Color.WHITE); + this.textLabel.setForeground(Color.BLACK); + } for (NameableCreator creator : JListControlPane.this.creators()) { if (creator.menuIcon() != null && creator.acceptObject2Populate(nameable) != null) { - this.setIcon(creator.menuIcon()); + this.iconLabel.setIcon(creator.menuIcon()); this.setToolTipText(creator.createTooltip()); iconSet = true; break; @@ -369,8 +400,16 @@ public abstract class JListControlPane extends JControlPane implements ListContr } return this; } - } + /** + * 改造后兼容子类NoIconNameableListCellRenderer使用,添加此setIcon函数 + * + * @param icon 图标,可为null + */ + public void setIcon(Icon icon) { + this.iconLabel.setIcon(icon); + } + } @Override public BasicBeanPane createPaneByCreators(NameableCreator creator) { return Reflect.on(creator.getUpdatePane()).create().get(); diff --git a/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java index ed07ecc2d5..3b7aa02606 100644 --- a/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/controlpane/UIListGroupControlPane.java @@ -28,14 +28,7 @@ import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; -import java.awt.AlphaComposite; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.Graphics2D; +import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.lang.reflect.Constructor; @@ -125,6 +118,9 @@ public abstract class UIListGroupControlPane extends UIControlPane implements Li for (int i = 0, size = widget.getListenerSize(); i < size; i++) { Listener listener = widget.getListener(i); if (!listener.isDefault()) { + if (StringUtils.isEmpty(listener.getEventName())) { + continue; + } String eventName = switchLang(listener.getEventName()) + (nameObjectList.size() + 1); NameObject nameObject = new NameObject(eventName, listener); nameObjectList.add(nameObject); @@ -146,7 +142,7 @@ public abstract class UIListGroupControlPane extends UIControlPane implements Li } this.checkButtonEnabled(); refreshEventListWrapperPane(); - this.checkGroupPaneSize(); + this.updateGroupPaneSize(contentPane); isPopulating = false; } @@ -214,7 +210,7 @@ public abstract class UIListGroupControlPane extends UIControlPane implements Li nameEdList.addModNameActionListener(new ModNameActionListener() { @Override public void nameModed(int index, String oldName, String newName) { - checkGroupPaneSize(); + updateGroupPaneSize(contentPane); saveSettings(); } }); @@ -304,24 +300,30 @@ public abstract class UIListGroupControlPane extends UIControlPane implements Li public void onAddItem(NameableCreator creator) { updateSelectedNameList(creator); getCommonHandlers().onAddItem(creator); - checkGroupPaneSize(); + updateGroupPaneSize(contentPane); } @Override public void onRemoveItem() { getCommonHandlers().onRemoveItem(); refreshEventListWrapperPane(); - checkGroupPaneSize(); + updateGroupPaneSize(contentPane); } @Override public void onCopyItem() { getCommonHandlers().onCopyItem(); - checkGroupPaneSize(); + updateGroupPaneSize(contentPane); } - private void checkGroupPaneSize() { + /** + * 根据父面板更新对应的面板宽度 + * (如果小于父面板的宽度就填充到与父面板宽度一致) + * + * @param parentPane 父面板 + */ + private void updateGroupPaneSize(JPanel parentPane) { int width = 180; Iterator> iterator = nameEdListMap.entrySet().iterator(); while (iterator.hasNext()) { @@ -331,7 +333,9 @@ public abstract class UIListGroupControlPane extends UIControlPane implements Li width = Math.max(width, calculateUIListMaxCellWidth(uiList.getModel(), uiList.getFontMetrics(uiList.getFont()))); } iterator = nameEdListMap.entrySet().iterator(); - width += 30; + //contentPane是外层的Panel,如果不进行判断的话宽度就可能会小于contentPanel,右侧会有空隙 + //所以需要判断一下,如果外层比较宽就取外层的宽度,防止空隙出现 + width = Math.max(width + 30, parentPane == null ? 0 : parentPane.getWidth()); while (iterator.hasNext()) { Map.Entry entry = iterator.next(); ListWrapperPane wrapperPane = entry.getValue(); diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/EditingStringListPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/EditingStringListPane.java index 7168db0b5c..ebe6abb672 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/EditingStringListPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/EditingStringListPane.java @@ -153,7 +153,7 @@ public abstract class EditingStringListPane extends BasicBeanPane> if (selected != null) { int re = FineJOptionPane.showConfirmDialog(SwingUtilities.getWindowAncestor(EditingStringListPane.this), Toolkit.i18nText("Fine-Design_Basic_Sure_To_Delete") + selected.toString() + "?", - Toolkit.i18nText("Fine-Design_Basic_Confirm"), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.OK_CANCEL_OPTION); if (re == JOptionPane.OK_OPTION) { JListUtils.removeSelectedListItems(jlist); diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/designer/component/FontSizeComboPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/FontSizeComboPane.java similarity index 60% rename from designer-form/src/main/java/com/fr/design/widget/ui/designer/component/FontSizeComboPane.java rename to designer-base/src/main/java/com/fr/design/gui/frpane/FontSizeComboPane.java index 57df97ee12..a89b41d4a1 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/designer/component/FontSizeComboPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/FontSizeComboPane.java @@ -1,7 +1,9 @@ -package com.fr.design.widget.ui.designer.component; +package com.fr.design.gui.frpane; import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.stable.collections.CollectionUtils; + import javax.swing.JPanel; import java.awt.BorderLayout; import java.util.Vector; @@ -13,15 +15,22 @@ public class FontSizeComboPane extends JPanel{ private static final int MAX_FONT_SIZE = 100; private UIComboBox comboBox; public FontSizeComboPane(){ - initComponent(); + this(null); } - public void initComponent(){ - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - Vector integerList = new Vector(); - for (int i = 1; i < MAX_FONT_SIZE; i++) { - integerList.add(i); + + public FontSizeComboPane(Vector fontSizes){ + initComponent(fontSizes); + } + + public void initComponent(Vector fontSizes){ + if(CollectionUtils.isEmpty(fontSizes)) { + fontSizes = new Vector<>(); + for (int i = 1; i < MAX_FONT_SIZE; i++) { + fontSizes.add(i); + } } - comboBox = new UIComboBox(integerList); + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + comboBox = new UIComboBox(fontSizes); comboBox.setEditable(true); this.add(comboBox, BorderLayout.CENTER); } diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/JTreeControlPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/JTreeControlPane.java index 4c4785be01..342221fd20 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/JTreeControlPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/JTreeControlPane.java @@ -215,7 +215,7 @@ public class JTreeControlPane extends ControlPane { public void actionPerformed(ActionEvent e) { // TODO remove tree node int val = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Are_You_Sure_To_Remove_The_Selected_Item") + "?", - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Remove"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (val != JOptionPane.OK_OPTION) { return; } diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/RegPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/RegPane.java index f84d0f5fdb..ea92ee73ce 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/RegPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/RegPane.java @@ -394,6 +394,7 @@ public class RegPane extends BasicPane { private static class RegLengthPane extends DisplayPane { private UISpinner minLenSpinner; private UISpinner maxLenSpinner; + private final int DEFAULT_WIDTH = 60; public RegLengthPane(){ this.setLayout(FRGUIPaneFactory.createBorderLayout()); @@ -403,8 +404,11 @@ public class RegPane extends BasicPane { maxLenSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, 0); UILabel minLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Reg_Min_Length")); UILabel maxLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Reg_Max_Length")); - minLabel.setPreferredSize(new Dimension(60, 20)); - maxLabel.setPreferredSize(new Dimension(60, 20)); + int minLabelWidth = Math.max(minLabel.getPreferredSize().width, DEFAULT_WIDTH); + int maxLabelWidth = Math.max(maxLabel.getPreferredSize().width, DEFAULT_WIDTH); + + minLabel.setPreferredSize(new Dimension(minLabelWidth, 20)); + maxLabel.setPreferredSize(new Dimension(maxLabelWidth, 20)); double f = TableLayout.FILL; double p = TableLayout.PREFERRED; Component[][] components = new Component[][]{ diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/UITabbedPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/UITabbedPane.java index fd2fcc3755..27cff9c5e3 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/UITabbedPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/UITabbedPane.java @@ -126,7 +126,7 @@ public class UITabbedPane extends JTabbedPane{ * @param i tab索引 */ public void doRemoveTab(int i){ - int re = FineJOptionPane.showConfirmDialog(SwingUtilities.getWindowAncestor(UITabbedPane.this), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Sure_To_Delete")+ "?", com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Remove") + int re = FineJOptionPane.showConfirmDialog(SwingUtilities.getWindowAncestor(UITabbedPane.this), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Sure_To_Delete")+ "?", com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt") , JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (re == JOptionPane.OK_OPTION) { super.removeTabAt(i); diff --git a/designer-base/src/main/java/com/fr/design/gui/frpane/tree/layer/config/LayerDataControlPane.java b/designer-base/src/main/java/com/fr/design/gui/frpane/tree/layer/config/LayerDataControlPane.java index eedc12058d..1bf9d604fc 100644 --- a/designer-base/src/main/java/com/fr/design/gui/frpane/tree/layer/config/LayerDataControlPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/frpane/tree/layer/config/LayerDataControlPane.java @@ -179,7 +179,7 @@ public class LayerDataControlPane extends ControlPane { public void actionPerformed(ActionEvent e) { // TODO remove tree node int val = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Are_You_Sure_To_Remove_The_Selected_Item") + "?", - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Remove"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (val != JOptionPane.OK_OPTION) { return; } diff --git a/designer-base/src/main/java/com/fr/design/gui/icontainer/UIEastResizableContainer.java b/designer-base/src/main/java/com/fr/design/gui/icontainer/UIEastResizableContainer.java index f00fbee498..cec4b840a7 100644 --- a/designer-base/src/main/java/com/fr/design/gui/icontainer/UIEastResizableContainer.java +++ b/designer-base/src/main/java/com/fr/design/gui/icontainer/UIEastResizableContainer.java @@ -5,10 +5,21 @@ import com.fr.design.base.mode.DesignModeContext; import com.fr.design.constants.UIConstants; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.mainframe.DesignerContext; +import com.fr.design.utils.SvgDrawUtils; import com.fr.design.utils.gui.GUICoreUtils; -import javax.swing.*; -import java.awt.*; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.LayoutManager; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; @@ -313,7 +324,6 @@ public class UIEastResizableContainer extends JPanel { @Override public void paint(Graphics g) { Image button; - if (containerWidth == leftPaneWidth) { if (model == UIConstants.MODEL_NORMAL) { button = UIConstants.DRAG_LEFT_NORMAL; @@ -327,7 +337,7 @@ public class UIEastResizableContainer extends JPanel { button = UIConstants.DRAG_RIGHT_PRESS; } } - g.drawImage(button, 18, 7, this); + SvgDrawUtils.doDrawSVG(g, () -> SvgDrawUtils.drawImage(g, button, 10, 7, null)); } } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/gui/icontainer/UIResizableContainer.java b/designer-base/src/main/java/com/fr/design/gui/icontainer/UIResizableContainer.java index 8e562cc3ce..a7682107ec 100644 --- a/designer-base/src/main/java/com/fr/design/gui/icontainer/UIResizableContainer.java +++ b/designer-base/src/main/java/com/fr/design/gui/icontainer/UIResizableContainer.java @@ -3,12 +3,22 @@ package com.fr.design.gui.icontainer; import com.fr.base.vcs.DesignerMode; import com.fr.design.constants.UIConstants; import com.fr.design.mainframe.DesignerContext; -import com.fr.design.utils.SvgPaintUtils; -import com.fr.stable.Constants; +import com.fr.design.utils.SvgDrawUtils; import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.stable.Constants; -import javax.swing.*; -import java.awt.*; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.LayoutManager; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; @@ -411,11 +421,9 @@ public class UIResizableContainer extends JPanel { Image upButton = (upModel == UIConstants.MODEL_NORMAL ? UIConstants.DRAG_UP_NORMAL : UIConstants.DRAG_UP_PRESS); Image downButton = (downModel == UIConstants.MODEL_NORMAL ? UIConstants.DRAG_DOWN_NORMAL : UIConstants.DRAG_DOWN_PRESS); g.drawImage(UIConstants.DRAG_BAR_LIGHT, 0, 0, getWidth(), getHeight(), null); - SvgPaintUtils.beforePaint((Graphics2D) g); - g.drawImage(UIConstants.DRAG_LINE, (getWidth() - toolPaneHeight) / 2, 3, null); - g.drawImage(upButton, ARROW_MARGIN, 1, null); - g.drawImage(downButton, getWidth() - toolPaneHeight - ARROW_MARGIN, 1, null); - SvgPaintUtils.afterPaint((Graphics2D) g); + SvgDrawUtils.doDrawSVG(g, () -> SvgDrawUtils.drawImage(g, UIConstants.DRAG_LINE, (getWidth() - toolPaneHeight) / 2, 3, null)); + SvgDrawUtils.doDrawSVG(g, () -> SvgDrawUtils.drawImage(g, upButton, ARROW_MARGIN, 0, null)); + SvgDrawUtils.doDrawSVG(g, () -> SvgDrawUtils.drawImage(g, downButton, (getWidth() - toolPaneHeight - ARROW_MARGIN), 0, null)); } } @@ -512,7 +520,7 @@ public class UIResizableContainer extends JPanel { button = UIConstants.DRAG_LEFT_PRESS; } } - g.drawImage(button, -1, ARROW_MARGIN_VERTICAL, this); + SvgDrawUtils.doDrawSVG(g, () -> SvgDrawUtils.drawImage(g, button, -6, ARROW_MARGIN_VERTICAL, VerticalToolPane.this)); } else { g.drawImage(UIConstants.DRAG_BAR_LIGHT, 0, 0, toolPaneHeight, getHeight(), null); if (containerWidth == toolPaneHeight) { @@ -528,7 +536,7 @@ public class UIResizableContainer extends JPanel { button = UIConstants.DRAG_RIGHT_PRESS; } } - g.drawImage(button, 2, ARROW_MARGIN_VERTICAL, this); + SvgDrawUtils.doDrawSVG(g, () -> SvgDrawUtils.drawImage(g, button, 10, ARROW_MARGIN_VERTICAL, VerticalToolPane.this)); } if (isLeftRightDragEnabled) { g.drawImage(UIConstants.DRAG_DOT_VERTICAL, 2, getHeight() / 2, 5, toolPaneHeight, null); diff --git a/designer-base/src/main/java/com/fr/design/gui/ilist/JNameEdList.java b/designer-base/src/main/java/com/fr/design/gui/ilist/JNameEdList.java index 4c530c0fcc..f4c3cfe920 100644 --- a/designer-base/src/main/java/com/fr/design/gui/ilist/JNameEdList.java +++ b/designer-base/src/main/java/com/fr/design/gui/ilist/JNameEdList.java @@ -11,15 +11,20 @@ import com.fr.stable.core.PropertyChangeAdapter; import javax.swing.ListModel; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; -import java.util.ArrayList; -import java.util.Vector; import java.awt.Component; import java.awt.Rectangle; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; +import java.util.ArrayList; +import java.util.Vector; public class JNameEdList extends UIList implements CellEditorListener { - private static final int ICON_WIDTH = 20; + + /** + * 原值为20,设计器图标由png替换为svg之后JNameEdList的icon大小为16x16 + * 重命名是会出现左侧一部分带有背景色的渲染 + */ + private static final int ICON_WIDTH = 16; private boolean editable = true; // kunsnat: 是否强制ListName是数字 (int型) @@ -175,7 +180,8 @@ public class JNameEdList extends UIList implements CellEditorListener { } public void setIllegalIndex(int index) { - setNameAt(NameInspector.ILLEGAL_NAME_HOLDER, index); + //环境如果重名会被命名为请重命名,这个请重命名也会重复,后面加个索引区别一下 + setNameAt(NameInspector.ILLEGAL_NAME_HOLDER + index, index); this.repaint(); } diff --git a/designer-base/src/main/java/com/fr/design/gui/imenutable/UIMenuTableUI.java b/designer-base/src/main/java/com/fr/design/gui/imenutable/UIMenuTableUI.java index 32b33cbab2..74024a86fe 100644 --- a/designer-base/src/main/java/com/fr/design/gui/imenutable/UIMenuTableUI.java +++ b/designer-base/src/main/java/com/fr/design/gui/imenutable/UIMenuTableUI.java @@ -76,7 +76,7 @@ public class UIMenuTableUI extends UITableUI{ public void mousePressed(MouseEvent e) { if (e.getX() >= table.getWidth() - 20) { int val = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Are_You_Sure_To_Remove_The_Selected_Item") + "?", - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Remove"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (val == JOptionPane.OK_OPTION) { uiTable.removeLine(table.rowAtPoint(e.getPoint())); uiTable.fireTargetChanged(); diff --git a/designer-base/src/main/java/com/fr/design/gui/itable/UITableUI.java b/designer-base/src/main/java/com/fr/design/gui/itable/UITableUI.java index 71e80027c3..93ce206299 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itable/UITableUI.java +++ b/designer-base/src/main/java/com/fr/design/gui/itable/UITableUI.java @@ -134,7 +134,7 @@ public class UITableUI extends BasicTableUI { } if (!table.isEditing()) { int val = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Are_You_Sure_To_Remove_The_Selected_Item") + "?", - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Remove"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (val == JOptionPane.OK_OPTION) { ((UITable) table).removeLine(table.rowAtPoint(e.getPoint())); ((UITable) table).fireTargetChanged(); diff --git a/designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableModelAdapter.java b/designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableModelAdapter.java index 87e21c75be..8b046f3d08 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableModelAdapter.java +++ b/designer-base/src/main/java/com/fr/design/gui/itableeditorpane/UITableModelAdapter.java @@ -4,6 +4,7 @@ import com.fr.base.BaseUtils; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.mainframe.DesignerContext; import com.fr.log.FineLoggerFactory; +import org.jetbrains.annotations.Nullable; import javax.swing.JOptionPane; import javax.swing.JTable; @@ -64,6 +65,20 @@ public abstract class UITableModelAdapter extends AbstractTableModel implemen return null; } + /** + * 获取映射后的值 + * + * @param row 行 + * @return 值 + */ + @Nullable + public T getConvertRowSelectedValue(int row) { + if (table.getSelectedRow() >= 0) { + return list.get(table.convertRowIndexToModel(row)); + } + return null; + } + public void setColumnClass(Class[] classes) { this.classes = classes; } @@ -256,7 +271,7 @@ public abstract class UITableModelAdapter extends AbstractTableModel implemen component = DesignerContext.getDesignerFrame(); } int val = FineJOptionPane.showConfirmDialog(component, getDeleteTipText() - , com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Remove"), + , com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (val != JOptionPane.OK_OPTION) { return; diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/filetree/FileNodeConstants.java b/designer-base/src/main/java/com/fr/design/gui/itree/filetree/FileNodeConstants.java index 036196f827..242865aeca 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itree/filetree/FileNodeConstants.java +++ b/designer-base/src/main/java/com/fr/design/gui/itree/filetree/FileNodeConstants.java @@ -12,9 +12,8 @@ import com.fr.report.ExtraReportClassManager; import com.fr.report.fun.ReportSupportedFileProvider; import com.fr.workspace.server.repository.template.TemplateRepository; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; +import java.util.LinkedHashSet; import java.util.Set; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -24,7 +23,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; */ public class FileNodeConstants { - private static List supportFileType; + private static Set supportFileType; private static ReadWriteLock rwl = new ReentrantReadWriteLock(); private FileNodeConstants() { @@ -48,16 +47,14 @@ public class FileNodeConstants { private static void addAppExtensions(FileExtension[] extensions) { for (int i = 0, size = extensions.length; i < size; i++) { - if (!supportFileType.contains(extensions[i].getExtension())) { - supportFileType.add(extensions[i].getExtension()); - } + supportFileType.add(extensions[i].getExtension()); } } private static void initSupportedTypes() { try { rwl.writeLock().lock(); - supportFileType = new ArrayList(); + supportFileType = new LinkedHashSet<>(); //通过插件扩展的 Set providers = ExtraReportClassManager.getInstance().getArray(ReportSupportedFileProvider.XML_TAG); for (ReportSupportedFileProvider provider : providers) { diff --git a/designer-base/src/main/java/com/fr/design/gui/style/TranslucentBorderSpecialPane.java b/designer-base/src/main/java/com/fr/design/gui/style/TranslucentBorderSpecialPane.java index cc49820de5..dee7364ff3 100644 --- a/designer-base/src/main/java/com/fr/design/gui/style/TranslucentBorderSpecialPane.java +++ b/designer-base/src/main/java/com/fr/design/gui/style/TranslucentBorderSpecialPane.java @@ -16,6 +16,7 @@ import com.fr.design.gui.frpane.UIPercentDragPane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.icombobox.LineComboBox; import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; @@ -26,8 +27,8 @@ import com.fr.design.style.color.NewColorSelectBox; import com.fr.env.utils.DesignerInteractionHistory; import com.fr.general.Background; import com.fr.general.IOUtils; -import com.fr.i18n.UrlI18nManager; import com.fr.general.act.BorderPacker; +import com.fr.i18n.UrlI18nManager; import com.fr.stable.Constants; import com.fr.stable.GraphDrawHelper; import com.fr.stable.ProjectLibrary; @@ -45,10 +46,10 @@ import javax.swing.event.ChangeListener; import javax.swing.plaf.basic.BasicButtonUI; import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Component; import java.awt.Cursor; import java.awt.Desktop; import java.awt.Dimension; -import java.awt.FlowLayout; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; @@ -78,7 +79,18 @@ import java.util.Arrays; public class TranslucentBorderSpecialPane extends AbstractBorderPackerPane implements UIObserver { private final int SETTING_LABEL_WIDTH = 60; private final Style DEFAULT_IMAGE_LAYOUT_STYLE = Style.DEFAULT_STYLE.deriveImageLayout(Constants.IMAGE_DEFAULT); - private final String TWEAK_NINE_POINT_HELP_URL = "https://help.fanruan.com/finereport/doc-view-4135.html"; + + /** + * 云中心点九图帮助文档在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Nine_Patch"; + + /** + * 云中心点九图帮助文档默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Nine_Patch_Default"; + + private final String TWEAK_NINE_POINT_HELP_URL = LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); private UIObserverListener uiObserverListener; @@ -125,7 +137,9 @@ public class TranslucentBorderSpecialPane extends AbstractBorderPackerPane imple } }); - tweakNinePointButton = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Style_Border_Image_Config_Nine_Point_Fill")); + String buttonText = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget_Style_Border_Image_Config_Nine_Point_Fill"); + tweakNinePointButton = new UIButton(buttonText); + tweakNinePointButton.setToolTipText(buttonText); borderImageOpacityPane = new UIPercentDragPane(); } @@ -162,23 +176,28 @@ public class TranslucentBorderSpecialPane extends AbstractBorderPackerPane imple borderedImagePreviewPane.setPreferredSize(new Dimension(145, 145)); borderedImagePreviewPane.add(imagePreviewPane, BorderLayout.CENTER); - JPanel tweakNinePointComposedPane = new JPanel(); - tweakNinePointComposedPane.setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0)); - tweakNinePointButton.setPreferredSize(new Dimension(145, 16)); - tweakNinePointComposedPane.add(tweakNinePointHelpButton); - tweakNinePointComposedPane.add(tweakNinePointButton); - return TableLayoutHelper.createGapTableLayoutPane( new JComponent[][]{ {null, borderedImagePreviewPane}, {null, chooseImageButton}, - {tweakNinePointComposedPane, null}, + {null, createTweakNinePointComposedPane()}, {null, new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Widget-Style_Alpha"))}, {null, this.borderImageOpacityPane} }, rowSize, columnSize, IntervalConstants.INTERVAL_L1, IntervalConstants.INTERVAL_L1); } + private JPanel createTweakNinePointComposedPane() { + double p = TableLayout.PREFERRED; + double f = TableLayout.FILL; + return TableLayoutHelper.createGapTableLayoutPane( + new Component[][]{ + {tweakNinePointHelpButton, tweakNinePointButton} + }, + new double[]{p}, + new double[]{p, f}, + new int[][]{{1, 1}}, 0, 0); + } private void initImageFileChooserIfNotExist() { if (imageFileChooser == null) { imageFileChooser = new ImageFileChooser(); diff --git a/designer-base/src/main/java/com/fr/design/i18n/LocaleLinkProvider.java b/designer-base/src/main/java/com/fr/design/i18n/LocaleLinkProvider.java new file mode 100644 index 0000000000..4a819069a7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/i18n/LocaleLinkProvider.java @@ -0,0 +1,47 @@ +package com.fr.design.i18n; + +import com.fr.general.CloudCenter; +import com.fr.stable.StringUtils; + +/** + * 国际化链接获取工具 + * 根据配置文件key获取云中心key对应的链接或者默认链接 + * + * @author obo + * @since 11.0 + * Created on 2023/4/7 + */ +public final class LocaleLinkProvider { + + private LocaleLinkProvider(){}; + + /** + * 单一实例 + */ + private static final LocaleLinkProvider INSTANCE = new LocaleLinkProvider(); + + /** + * 返回LocaleLinkProvider的单一实例 + * + * @return LocaleLinkProvider单一实例 + */ + public static LocaleLinkProvider getInstance(){ + return INSTANCE; + } + + /** + * 根据配置文件项中的key获取链接 + * + * @param propsKey 配置项key + * @param defaultKey 默认链接项key + * @return 对应的生成器 + */ + public String getLink(String propsKey, String defaultKey) { + String cloudKey = DesignI18nImpl.getInstance().i18nText(propsKey); + String url = CloudCenter.getInstance().acquireUrlByKind(cloudKey); + if(StringUtils.isEmpty(url)) { + return DesignI18nImpl.getInstance().i18nText(defaultKey); + } + return url; + } +} diff --git a/designer-base/src/main/java/com/fr/design/icon/WarningIcon.java b/designer-base/src/main/java/com/fr/design/icon/WarningIcon.java index 08d5b5a55a..a50bb39969 100644 --- a/designer-base/src/main/java/com/fr/design/icon/WarningIcon.java +++ b/designer-base/src/main/java/com/fr/design/icon/WarningIcon.java @@ -1,12 +1,17 @@ package com.fr.design.icon; import com.fr.base.svg.SVGLoader; -import com.fr.design.utils.SvgPaintUtils; +import com.fr.base.svg.SystemScaleUtils; +import com.fr.design.utils.SvgDrawUtils; import com.fr.log.FineLoggerFactory; import javax.swing.GrayFilter; import javax.swing.ImageIcon; -import java.awt.*; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.MediaTracker; import java.awt.image.ImageObserver; /** @@ -20,7 +25,8 @@ public class WarningIcon extends ImageIcon { }; protected final static MediaTracker TRACKER = new MediaTracker(COMPONENT); private final static Image WARNING_IMAGE = SVGLoader.load("/com/fr/design/standard/warning.svg"); - + private static final boolean HI_DPI_SUPPORT = SystemScaleUtils.isJreHiDPIEnabled(); + public static final float SYSTEM_SCALE = SystemScaleUtils.sysScale(); private Image mainImage = null; private ImageObserver imageObserver; private int width = -1; @@ -36,14 +42,15 @@ public class WarningIcon extends ImageIcon { @Override public synchronized void paintIcon(Component c, Graphics g, int x, int y) { - SvgPaintUtils.beforePaint((Graphics2D) g); + //裁剪绘制svg的位置,以免影响到图标右侧的文字 + Graphics2D graphics = (Graphics2D) g.create(x, y, WARNING_IMAGE.getWidth(null), WARNING_IMAGE.getHeight(null)); if (mainImage != null) { - g.drawImage(mainImage, x, y, c); + SvgDrawUtils.doDrawSVG(graphics, () -> SvgDrawUtils.drawImage(graphics, mainImage, x, y, null)); } if (WARNING_IMAGE != null) { - g.drawImage(WARNING_IMAGE, x, y, c); + SvgDrawUtils.doDrawSVG(graphics, () -> SvgDrawUtils.drawImage(graphics, WARNING_IMAGE, x, y, null)); } - SvgPaintUtils.afterPaint((Graphics2D) g); + graphics.dispose(); } /** @@ -91,7 +98,8 @@ public class WarningIcon extends ImageIcon { * @return the width in pixels of this icon */ public int getIconWidth() { - return width; + //如果环境支持高清化,drawImage可能会缩放绘制的图像比例,需要保证svg正常显示的同时调整绘制范围 + return HI_DPI_SUPPORT ? (int) (width / SYSTEM_SCALE) : width; } /** @@ -100,7 +108,8 @@ public class WarningIcon extends ImageIcon { * @return the height in pixels of this icon */ public int getIconHeight() { - return height; + //如果环境支持高清化,drawImage可能会缩放绘制的图像比例,需要保证svg正常显示的同时调整绘制范围 + return HI_DPI_SUPPORT ? (int) (height / SYSTEM_SCALE) : height; } { diff --git a/designer-base/src/main/java/com/fr/design/javascript/JSContentWithDescriptionPane.java b/designer-base/src/main/java/com/fr/design/javascript/JSContentWithDescriptionPane.java index 8e8ef45b9f..4116f4f1d0 100644 --- a/designer-base/src/main/java/com/fr/design/javascript/JSContentWithDescriptionPane.java +++ b/designer-base/src/main/java/com/fr/design/javascript/JSContentWithDescriptionPane.java @@ -14,18 +14,39 @@ import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.itextarea.UITextArea; import com.fr.design.gui.itextfield.PlaceholderTextField; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.i18n.Toolkit; import com.fr.design.javascript.jsapi.JSAPITreeHelper; import com.fr.design.javascript.jsapi.JSAPIUserObject; import com.fr.design.layout.FRGUIPaneFactory; -import com.fr.general.CloudCenter; import com.fr.general.ComparatorUtils; +import com.fr.general.GeneralContext; import com.fr.general.http.HttpToolbox; import com.fr.json.JSONArray; import com.fr.json.JSONException; import com.fr.json.JSONObject; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; + +import javax.swing.BorderFactory; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.SwingWorker; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; @@ -50,24 +71,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import javax.swing.BorderFactory; -import javax.swing.DefaultListCellRenderer; -import javax.swing.DefaultListModel; -import javax.swing.JComponent; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.JTree; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreeNode; -import javax.swing.tree.TreePath; +import java.util.Locale; +import java.util.concurrent.ExecutionException; public class JSContentWithDescriptionPane extends JSContentPane implements KeyListener { @@ -117,6 +122,15 @@ public class JSContentWithDescriptionPane extends JSContentPane implements KeyLi private static final String RELOAD_CARD = "reloadCard"; private static final String DOC_LIST_CARD = "docListCard"; + /** + * 云中心Js高级编辑器帮助链接前缀在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Js_Editor"; + + /** + * 云中心Js高级编辑器帮助链接前缀在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Js_Editor_Default"; public JSContentWithDescriptionPane(String[] args) { this.setLayout(new BorderLayout()); //=============================== @@ -352,27 +366,55 @@ public class JSContentWithDescriptionPane extends JSContentPane implements KeyLi private void doHelpDocumentSearch() { Object value = interfaceNameList.getSelectedValue(); if (value != null) { - String url = CloudCenter.getInstance().acquireUrlByKind("af.doc_search", DOCUMENT_SEARCH_URL) + value.toString(); - try { + new SwingWorker, Void>() { + @Override + protected List doInBackground() { + List helpDocuments = new ArrayList<>(); + updateHelpDocuments(value, helpDocuments); + return helpDocuments; + } + + @Override + protected void done() { + try { + List helpDocuments = get(); + DefaultListModel helpDOCModel = (DefaultListModel) helpDOCList.getModel(); + helpDOCModel.clear(); + for (HelpDocument helpDocument : helpDocuments) { + helpDOCModel.addElement(helpDocument); + } + } catch (InterruptedException | ExecutionException e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + }.execute(); + } + } + + private void updateHelpDocuments(Object value, List helpDocuments) { + String url = LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT) + value.toString(); + try { + JSONArray jsonArray = null; + //目前简中繁中之外的语言高级编辑器功能及文档不完善,右侧展示的文档链接列表暂时为空白 + if(GeneralContext.isChineseEnv()) { String result = HttpToolbox.get(url); JSONObject jsonObject = new JSONObject(result); - JSONArray jsonArray = jsonObject.optJSONArray("list"); - if (jsonArray != null) { - DefaultListModel helpDOCModel = (DefaultListModel) helpDOCList.getModel(); - helpDOCModel.clear(); - for (int i = 0; i < jsonArray.length(); i++) { - JSONObject resultJSONObject = jsonArray.optJSONObject(i); - String docURL = resultJSONObject.optString("url"); - String name = resultJSONObject.optString("title").trim(); - HelpDocument helpDocument = new HelpDocument(docURL, name); - helpDOCModel.addElement(helpDocument); - } + jsonArray = jsonObject.optJSONArray("list"); + } + if (jsonArray != null) { + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject resultJSONObject = jsonArray.optJSONObject(i); + String docURL = resultJSONObject.optString("url"); + String name = resultJSONObject.optString("title").trim(); + HelpDocument helpDocument = new HelpDocument(docURL, name); + helpDocuments.add(helpDocument); } - } catch (JSONException e) { - FineLoggerFactory.getLogger().debug(e.getMessage(), e); - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); } + } catch (JSONException e) { + FineLoggerFactory.getLogger().debug(e.getMessage(), e); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); } } diff --git a/designer-base/src/main/java/com/fr/design/jxbrowser/BrowserExecutor.java b/designer-base/src/main/java/com/fr/design/jxbrowser/BrowserExecutor.java new file mode 100644 index 0000000000..f21609ef6b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/jxbrowser/BrowserExecutor.java @@ -0,0 +1,40 @@ +package com.fr.design.jxbrowser; + +import com.fr.design.bridge.exec.JSExecutor; +import com.teamdev.jxbrowser.js.JsFunction; +import com.teamdev.jxbrowser.js.JsObject; + +/** + * 用于 jxbrowser 执行后的回调执行器 + * 适配7.15之后 + * + * @author vito + * @since 11.0 + * Created on 2023/6/8 + */ +public class BrowserExecutor implements JSExecutor { + + /** + * 创建一个回调执行器 + * + * @param window js环境的window对象 + * @param callback 回调 + * @return 执行器 + */ + public static BrowserExecutor create(JsObject window, JsFunction callback) { + return new BrowserExecutor(window, callback); + } + + private final JsObject window; + private final JsFunction callback; + + private BrowserExecutor(JsObject window, JsFunction callback) { + this.window = window; + this.callback = callback; + } + + @Override + public void executor(String newValue) { + callback.invoke(window, newValue); + } +} diff --git a/designer-base/src/main/java/com/fr/design/jxbrowser/JxEngine.java b/designer-base/src/main/java/com/fr/design/jxbrowser/JxEngine.java new file mode 100644 index 0000000000..bb2c1f7375 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/jxbrowser/JxEngine.java @@ -0,0 +1,140 @@ +package com.fr.design.jxbrowser; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.ui.ModernUIConstants; +import com.fr.log.FineLoggerFactory; +import com.fr.value.ClearableLazyValue; +import com.fr.web.struct.AssembleComponent; +import com.teamdev.jxbrowser.engine.Engine; +import com.teamdev.jxbrowser.engine.EngineOptions; +import com.teamdev.jxbrowser.engine.RenderingMode; +import com.teamdev.jxbrowser.engine.event.EngineCrashed; +import com.teamdev.jxbrowser.net.Network; +import com.teamdev.jxbrowser.net.Scheme; +import com.teamdev.jxbrowser.net.callback.VerifyCertificateCallback; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.Map; + +/** + * 可重复启动的 Jxbrowser 引擎 + * 手动创建的引擎,应当自己负责管理声明周期 {@link #newInstance()} + * 单例的引擎,由系统管理生命周期,使用后仅需清理browser和map等数据 + * {@link #getEngine()} 和 {@link #getPublicEngineInstance()} + * + * @author vito + * @since 11.0 + * Created on 2023/6/8 + */ +public class JxEngine { + + private static final JxEngine INSTANCE = new JxEngine(); + + private AssembleComponent component; + private Map parameterMap = Collections.emptyMap(); + + + private final ClearableLazyValue ENGINE = ClearableLazyValue.create(() -> { + EngineOptions.Builder builder = EngineOptions + .newBuilder(RenderingMode.HARDWARE_ACCELERATED) + .addSwitch("--disable-google-traffic") + .addScheme(Scheme.of(ModernUIConstants.EMB_TAG), + new NxInterceptRequestCallback(this::getComponent, this::getParameterMap)); + Engine engine = Engine.newInstance(builder.build()); + engine.on(EngineCrashed.class, (event) -> { + FineLoggerFactory.getLogger().error("jxBrowser engine crashed with exitCode: {}", event.exitCode()); + event.engine().close(); + }); + if (DesignerEnvManager.getEnvManager().isOpenDebug()) { + // 调试模式下,禁止HTTPS证书验证,使得可以正常访问商城测试服务器等 + Network network = engine.network(); + network.set(VerifyCertificateCallback.class, params -> VerifyCertificateCallback.Response.valid()); + } + return engine; + }); + + public Map getParameterMap() { + return Collections.unmodifiableMap(parameterMap); + } + + public void setMap(Map parameterMap) { + if (parameterMap == null) { + return; + } + this.parameterMap = parameterMap; + } + + /** + * 清理map + */ + public void clearMap() { + this.parameterMap = Collections.emptyMap(); + } + + public AssembleComponent getComponent() { + return component; + } + + public void setComponent(AssembleComponent component) { + this.component = component; + } + + /** + * 清理component + */ + public void clearComponent() { + this.component = null; + } + + /** + * 获取单例引擎包装,能够更新渲染 + * 从单例获取的引擎不用负责关闭, + * 应用系统管理声明周期 + * + * @return jxbrowser 引擎包装类 + */ + public static JxEngine getInstance() { + return INSTANCE; + } + + /** + * 获取公共引擎,公共引擎使用后不用关闭引擎,但需要自己管理 browser。 + * 应用系统管理引擎生命周期 + * + * @return 引擎 + */ + @NotNull + public Engine getEngine() { + return ENGINE.getValue(); + } + + /** + * 关闭引擎 + */ + public void close() { + ENGINE.getValue().close(); + ENGINE.drop(); + } + + + /** + * 获取公共引擎,公共引擎使用后不用关闭引擎,但需要自己管理 browser。 + * 应用系统管理引擎生命周期 + * + * @return 引擎 + */ + public static Engine getPublicEngineInstance() { + return getInstance().ENGINE.getValue(); + } + + /** + * 创建一个新的引擎,创建引擎使用后需负责关闭引擎 + * 但可以独立使用 map 和 component + * + * @return 引擎 + */ + public static JxEngine newInstance() { + return new JxEngine(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/jxbrowser/JxUIPane.java b/designer-base/src/main/java/com/fr/design/jxbrowser/JxUIPane.java new file mode 100644 index 0000000000..463cf39b7d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/jxbrowser/JxUIPane.java @@ -0,0 +1,572 @@ +package com.fr.design.jxbrowser; + +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.stable.StringUtils; +import com.fr.stable.collections.combination.Pair; +import com.fr.stable.os.OperatingSystem; +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.event.Observer; +import com.teamdev.jxbrowser.frame.Frame; +import com.teamdev.jxbrowser.js.JsObject; +import com.teamdev.jxbrowser.view.swing.BrowserView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.SwingUtilities; +import java.awt.BorderLayout; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import static com.fr.design.ui.ModernUIConstants.COMPONENT_TAG; +import static com.fr.design.ui.ModernUIConstants.DEFAULT_EXPRESSION; +import static com.fr.design.ui.ModernUIConstants.DEFAULT_NAMESPACE; +import static com.fr.design.ui.ModernUIConstants.DEFAULT_VARIABLE; +import static com.fr.design.ui.ModernUIConstants.DOT; +import static com.fr.design.ui.ModernUIConstants.EMB_TAG; +import static com.fr.design.ui.ModernUIConstants.SCHEME_HEADER; +import static com.fr.design.ui.ModernUIConstants.WINDOW; + +/** + * 基于v7 jxbrowser 实现 + * 用于加载 html5 的Swing容器,可以在设计选项设置中打开调试窗口, + * 示例可查看:com.fr.design.ui.JxUIPaneTest + * + * @author vito + * @since 11.0 + * Created on 2023-06-12 + */ +public class JxUIPane extends ModernUIPane { + + /** + * 冒号 + */ + public static final String COLON = ":"; + private static final String COLON_ESCAPE = "\\:"; + + private Browser browser; + private String namespace = "Pool"; + private String variable = "data"; + private String expression = "update()"; + + private JxUIPane() { + super(); + } + + private void initialize() { + setLayout(new BorderLayout()); + if (browser != null) { + return; + } + initDebugIfNeeded(); + // 使用公共引擎创建浏览器 + browser = JxEngine.getPublicEngineInstance().newBrowser(); + add(BrowserView.newInstance(browser), BorderLayout.CENTER); + } + + /** + * 按需初始化debug界面UI + */ + private void initDebugIfNeeded() { + if (DesignerEnvManager.getEnvManager().isOpenDebug()) { + UIToolbar toolbar = new UIToolbar(); + add(toolbar, BorderLayout.NORTH); + UIButton openDebugButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Open_Debug_Window")); + openDebugButton.addActionListener(e -> browser.devTools().show()); + toolbar.add(openDebugButton); + UIButton reloadButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Reload")); + reloadButton.addActionListener(e -> browser.navigation().reloadIgnoringCache()); + toolbar.add(reloadButton); + UIButton closeButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Close_Window")); + closeButton.addActionListener(e -> SwingUtilities.getWindowAncestor(JxUIPane.this).setVisible(false)); + toolbar.add(closeButton); + } + } + + /** + * 在初始化时进行注入JS的方法,只被build调用 + * + * @param injectJsCallback 回调 + */ + private void initInjectJs(InjectJsCallback injectJsCallback) { + browser.set(InjectJsCallback.class, params -> { + // 初始化的时候,就把命名空间对象初始化好,确保window.a.b.c("a.b.c"为命名空间)对象都是初始化过的 + params.frame().executeJavaScript(String.format(ModernUIConstants.SCRIPT_INIT_NAME_SPACE, namespace)); + return injectJsCallback.on(params); + }); + } + + /** + * 设置 InjectJsCallback。 + * 这个方法解决重复InjectJsCallback被覆盖的问题。 + * 用于本类内部方法使用,如{@link #populate(Object)} + * + * @param injectJsCallback 回调 + */ + private void setInjectJsCallback(InjectJsCallback injectJsCallback) { + Optional callback = browser.get(InjectJsCallback.class); + if (callback.isPresent()) { + browser.set(InjectJsCallback.class, params -> { + callback.get().on(params); + return injectJsCallback.on(params); + }); + } else { + browser.set(InjectJsCallback.class, injectJsCallback); + } + } + + + /** + * 转向一个新的地址,相当于重新加载 + * + * @param url 新的地址 + */ + @Override + public void redirect(String url) { + browser.navigation().loadUrl(encodeWindowsPath(url)); + } + + /** + * 转向一个新的地址,相当于重新加载 + * + * @param url 新的地址 + * @param map 初始化参数 + */ + @Override + public void redirect(String url, Map map) { + setMap(map); + browser.navigation().loadUrl(encodeWindowsPath(url)); + } + + private void setMap(Map map) { + JxEngine.getInstance().setMap(map); + } + + private void setComponent(AssembleComponent component) { + JxEngine.getInstance().setComponent(component); + } + + @Override + protected String title4PopupWindow() { + return "ModernUI7"; + } + + + @Override + public void populate(final T t) { + setInjectJsCallback(params -> { + executeJsObject(params.frame(), WINDOW + DOT + namespace) + .ifPresent(ns -> ns.putProperty(variable, t)); + return InjectJsCallback.Response.proceed(); + }); + } + + @Override + @Nullable + public T update() { + if (browser.mainFrame().isPresent()) { + return browser.mainFrame().get().executeJavaScript("window." + namespace + "." + expression); + } + return null; + } + + /** + * 关闭浏览器 + */ + public void disposeBrowser() { + if (browser != null) { + browser.close(); + browser = null; + JxEngine.getInstance().clearMap(); + JxEngine.getInstance().clearComponent(); + } + + } + + /** + * 清理浏览器缓存 + */ + public void clearCache() { + if (browser != null) { + browser.engine().httpCache().clear(); + } + } + + /** + * 执行一段js + * + * @param javaScript 待执行的js脚本 + * @see JxUIPane#executeJS(String) + */ + public void executeJavaScript(String javaScript) { + if (browser != null) { + browser.mainFrame().ifPresent(frame -> frame.executeJavaScript(javaScript)); + } + } + + /** + * 获取js对象 + * 注意:类内部使用,用于简化编码,提供 Optional 包装 + * + * @param frame 页面frame对象 + * @param name 变量命名 + * @return js对象 + */ + private static Optional executeJsObject(Frame frame, String name) { + return Optional.ofNullable(frame.executeJavaScript(name)); + } + + /** + * 执行js脚本并返回,使用范围包含{@link JxUIPane#executeJavaScript(String)},可以代替使用 + * + * @param name 变量命名 + * @return js对象 + */ + public

    Optional

    executeJS(String name) { + if (browser != null) { + Optional frame = browser.mainFrame(); + if (frame.isPresent()) { + return Optional.ofNullable(frame.get().executeJavaScript(name)); + } + } + return Optional.empty(); + } + + /** + * 由于自定义scheme目前走的是url,因此路径会被自动转化,比如windows路径下对冒号问题 + * C:\\abc 变成 /C/abc,这里对冒号进行编码转义 + */ + private static String encodeWindowsPath(String path) { + if (OperatingSystem.isWindows() && path.startsWith(EMB_TAG + SCHEME_HEADER)) { + String s = path.split(EMB_TAG + SCHEME_HEADER)[1]; + return EMB_TAG + SCHEME_HEADER + s.replace(COLON, COLON_ESCAPE); + } + return path; + } + + /** + * JxUIPane 的建造者 + * + * @param 参数 + */ + public static class Builder extends ModernUIPane.Builder { + private String namespace; + private String variable; + private String expression; + private InjectJsCallback callback; + + private Pair listenerPair; + private final Map namespacePropertyMap; + private final Map propertyMap; + + private final Map buildPropertyMap; + private Object variableProperty; + private Map parameterMap; + private AssembleComponent component; + private String url; + private String html; + + public Builder() { + // 为了兼容继承关系,但又不允许创建,用这个方式先处理一下 + super((ModernUIPane) null); + this.namespace = DEFAULT_NAMESPACE; + this.variable = DEFAULT_VARIABLE; + this.expression = DEFAULT_EXPRESSION; + this.callback = null; + this.listenerPair = null; + this.namespacePropertyMap = new HashMap<>(); + this.propertyMap = new HashMap<>(); + this.buildPropertyMap = new HashMap<>(); + this.variableProperty = null; + this.parameterMap = null; + this.component = null; + this.url = StringUtils.EMPTY; + this.html = StringUtils.EMPTY; + } + + /** + * 注入一个回调,回调的js会在初始化进行执行 + * + * @param callback 回调 + * @return builder + */ + public Builder prepare(InjectJsCallback callback) { + this.callback = callback; + return this; + } + + @Override + public Builder prepareForV6(ScriptContextListener contextListener) { + return this; + } + + @Override + public Builder prepareForV6(LoadListener loadListener) { + return this; + } + + @Override + public JxUIPane.Builder prepareForV7(InjectJsCallback callback) { + prepare(callback); + return this; + } + + @Override + public JxUIPane.Builder prepareForV7(Class event, Observer listener) { + listenerPair = new Pair<>(event, listener); + return this; + } + + /** + * 加载jar包中的资源 + * + * @param path 资源路径 + */ + public JxUIPane.Builder withEMB(final String path) { + this.url = EMB_TAG + SCHEME_HEADER + path; + return this; + } + + /** + * 加载jar包中的资源 + * + * @param path 资源路径 + */ + public JxUIPane.Builder withEMB(final String path, Map map) { + this.parameterMap = map; + this.url = EMB_TAG + SCHEME_HEADER + path; + return this; + } + + /** + * 加载url指向的资源 + * + * @param url 文件的地址 + */ + public JxUIPane.Builder withURL(final String url) { + this.url = url; + return this; + } + + /** + * 加载url指向的资源 + * + * @param url 文件的地址 + */ + public JxUIPane.Builder withURL(final String url, Map map) { + this.parameterMap = map; + this.url = url; + return this; + } + + /** + * 加载Atom组件 + * + * @param component Atom组件 + */ + public JxUIPane.Builder withComponent(AssembleComponent component) { + return withComponent(component, null); + } + + /** + * 加载Atom组件 + * + * @param component Atom组件 + */ + public JxUIPane.Builder withComponent(AssembleComponent component, Map map) { + this.parameterMap = map; + this.component = component; + this.url = COMPONENT_TAG; + return this; + } + + + /** + * 加载html文本内容 + * + * @param html 要加载html文本内容 + */ + public JxUIPane.Builder withHTML(String html) { + this.html = html; + return this; + } + + /** + * 设置该前端页面做数据交换所使用的对象 + * 相当于: + * const namespace = "Pool"; + * 调用: + * window[namespace]; + * 默认下结构如: + * window.Pool + * + * @param namespace 对象名 + */ + public JxUIPane.Builder namespace(String namespace) { + this.namespace = namespace; + return this; + } + + /** + * java端往js端传数据时使用的变量名字 + * 默认值为 data + * 相当于: + * const variable = "data"; + * 调用: + * window[namespace][variable]; + * 默认下结构如: + * window.Pool.data + * + * @param name 变量的名字 + */ + public JxUIPane.Builder variable(String name) { + this.variable = name; + return this; + } + + /** + * js端往java端传数据时执行的函数表达式 + * + * @param expression 函数表达式 + */ + public JxUIPane.Builder expression(String expression) { + this.expression = expression; + return this; + } + + /** + * 注入一个java对象到js中,绑定在全局变量window的指定变量variable。 + * variable 可由 {@link #namespace(String)} 设置,默认值为 data + * 这个方法仅在在加载的网页上执行 JavaScript 之前注入 + * 相当于: + * window[namespace][property] = javaObject + * 默认下: + * window.Pool[property] = javaObject + * + * @param obj java对象 + * @return 链式对象 + */ + public JxUIPane.Builder bindNamespace(String property, @Nullable Object obj) { + this.namespacePropertyMap.put(property, obj); + return this; + } + + /** + * 注入一个java对象到js中,绑定在全局变量window的指定变量variable。 + * variable 可由 {@link #variable(String)} 设置,默认值为 data + * 这个方法仅在在加载的网页上执行 JavaScript 之前注入 + * 相当于: + * window[namespace][variable] = javaObject + * 默认下: + * window.Pool.data = javaObject + * + * @param obj java对象 + * @return 链式对象 + */ + public JxUIPane.Builder bindVariable(@NotNull Object obj) { + this.variableProperty = obj; + return this; + } + + /** + * 注入一个java对象到js中,绑定在全局变量 window的 + * property指定的变量。这个方法仅在在加载的网页上执 + * 行 JavaScript 之前注入 + * 相当于: + * window[property] = javaObject + * + * @param property 属性 + * @param obj java对象 + * @return 链式对象 + * @see #bindWindow(String, PropertyBuild) + */ + public JxUIPane.Builder bindWindow(String property, @Nullable Object obj) { + this.propertyMap.put(property, obj); + return this; + } + + /** + * 注入一个java对象到js中。绑定在全局变量 window的property指定的变量。 + * PropertyBuild用于动态生成绑定属性。个方法仅在在加载的网页上执行 + * JavaScript 之前注入 + * 相当于: + * window[property] = javaObject + * + * @param property 属性构建器 + * @param obj java对象 + * @return 链式对象 + * @see #bindWindow(String, Object) + */ + public JxUIPane.Builder bindWindow(String property, PropertyBuild obj) { + buildPropertyMap.put(property, obj); + return this; + } + + /** + * 构建 + */ + public JxUIPane build() { + JxUIPane pane = new JxUIPane<>(); + pane.namespace = namespace; + pane.variable = variable; + pane.expression = expression; + pane.setMap(parameterMap); + pane.setComponent(component); + pane.initialize(); + injectJs(pane); + if (!Objects.isNull(listenerPair)) { + pane.browser.navigation().on(listenerPair.getFirst(), listenerPair.getSecond()); + } + if (StringUtils.isNotEmpty(this.url)) { + pane.browser.navigation().loadUrl(encodeWindowsPath(this.url)); + } else if (StringUtils.isNotEmpty(this.html)) { + pane.browser.mainFrame().ifPresent(f -> f.loadHtml(html)); + } + return pane; + } + + /** + * 由于 InjectJsCallback 的回调机制,在初始化期间,只有 + * 在 InjectJsCallback 中 putProperty 才能生效。 + * 因此,嵌套回调分别做默认初始化、putProperty、外置初始化 + */ + private void injectJs(JxUIPane pane) { + pane.initInjectJs(params -> { + Frame frame = params.frame(); + if (!propertyMap.isEmpty()) { + propertyMap.forEach((key, value) -> + executeJsObject(frame, WINDOW) + .ifPresent(window -> window.putProperty(key, value))); + } + if (!buildPropertyMap.isEmpty()) { + buildPropertyMap.forEach((key, value) -> + executeJsObject(frame, WINDOW) + .ifPresent(window -> window.putProperty(key, value.build(window)))); + } + if (!namespacePropertyMap.isEmpty()) { + namespacePropertyMap.forEach((key, value) -> + executeJsObject(frame, WINDOW + DOT + namespace) + .ifPresent(pool -> pool.putProperty(key, value))); + } + if (variableProperty != null) { + executeJsObject(frame, WINDOW + DOT + namespace) + .ifPresent(pool -> pool.putProperty(variable, variableProperty)); + } + if (callback != null) { + return callback.on(params); + } + return InjectJsCallback.Response.proceed(); + }); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/jxbrowser/MimeType.java b/designer-base/src/main/java/com/fr/design/jxbrowser/MimeType.java new file mode 100644 index 0000000000..654de0d729 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/jxbrowser/MimeType.java @@ -0,0 +1,112 @@ +package com.fr.design.jxbrowser; + +import com.fr.stable.StringUtils; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Optional; + +/** + * jxbrowser 使用的一些媒体类型 + * + * @author vito + * @since 11.0 + * Created on 2023/6/13 + */ +public enum MimeType { + /** + * html 格式 + */ + HTML(".html", "text/html"), + /** + * CSS 格式 + */ + CSS(".css", "text/css"), + /** + * js 格式 + */ + JS(".js", "text/javascript"), + /** + * svg 格式 + */ + SVG(".svg", "image/svg+xml"), + /** + * png 格式 + */ + PNG(".png", "image/png"), + + /** + * jpg 格式 + */ + JPG(".jpg", "image/jpeg"), + + /** + * jpeg 格式 + */ + JPEG(".jpeg", "image/jpeg"), + + /** + * gif 格式 + */ + GIF(".gif", "image/gif"), + /** + * woff 字体格式 + */ + WOFF(".woff", "font/woff"), + /** + * ttf 字体格式 + */ + TTF(".ttf", "truetype"), + + /** + * MS 嵌入式开放字体 + */ + EOT(".eot", "embedded-opentype"); + + private final String suffix; + private final String mimeType; + + MimeType(String suffix, String mimeType) { + this.suffix = suffix; + this.mimeType = mimeType; + } + + public String getMimeType() { + return mimeType; + } + + /** + * 获取指定路径对应的 mimetype,优先匹配常量中的类型 + * 如果没有,尝试使用 Files.probeContentType 检测 + * 如果没有,默认返回 text/html + * + * @param resourcePath 资源路径 + * @return MimeType + */ + public static String parseMimeType(String resourcePath) { + if (StringUtils.isBlank(resourcePath)) { + return HTML.mimeType; + } + Optional mimeType = Arrays.stream(values()) + .filter(type -> resourcePath.endsWith(type.suffix)) + .findFirst(); + if (mimeType.isPresent()) { + return mimeType.get().mimeType; + } else { + return getFileMimeType(resourcePath); + } + } + + private static String getFileMimeType(String finalPath) { + Path file = new File(finalPath).toPath(); + try { + String s = Files.probeContentType(file); + return StringUtils.isEmpty(s) ? HTML.mimeType : s; + } catch (IOException e) { + return HTML.mimeType; + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/jxbrowser/NxInterceptRequestCallback.java b/designer-base/src/main/java/com/fr/design/jxbrowser/NxInterceptRequestCallback.java new file mode 100644 index 0000000000..58d45a61f2 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/jxbrowser/NxInterceptRequestCallback.java @@ -0,0 +1,183 @@ +package com.fr.design.jxbrowser; + +import com.fr.base.TemplateUtils; +import com.fr.design.ui.ModernRequestClient; +import com.fr.design.ui.ModernUIConstants; +import com.fr.general.IOUtils; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.EncodeConstants; +import com.fr.stable.StringUtils; +import com.fr.web.struct.AssembleComponent; +import com.fr.web.struct.AtomBuilder; +import com.fr.web.struct.PathGroup; +import com.fr.web.struct.category.ScriptPath; +import com.fr.web.struct.category.StylePath; +import com.teamdev.jxbrowser.net.HttpHeader; +import com.teamdev.jxbrowser.net.HttpStatus; +import com.teamdev.jxbrowser.net.UrlRequest; +import com.teamdev.jxbrowser.net.UrlRequestJob; +import com.teamdev.jxbrowser.net.callback.InterceptUrlRequestCallback; +import org.jetbrains.annotations.NotNull; + +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; + +import static com.fr.design.ui.ModernUIConstants.COMPONENT_TAG; + +/** + * jxbrowser7 自定义 scheme 处理回调 + * + * @author vito + * @since 11.0 + * Created on 2023/6/8 + */ +public class NxInterceptRequestCallback implements InterceptUrlRequestCallback { + + private static final String COLON_DECODE_ESCAPE = "/:"; + private static final String SCHEME_SPLIT = ":/"; + private Supplier component; + + private Supplier> renderParameterBuild; + + public NxInterceptRequestCallback(Supplier> renderParameterBuild) { + this.renderParameterBuild = renderParameterBuild; + } + + public NxInterceptRequestCallback(Supplier component, + Supplier> renderParameterBuild) { + this.component = component; + this.renderParameterBuild = renderParameterBuild; + } + + /** + * 主要包括 atom 和 emb协议的文件链接处理, + * 去掉file文件协议的支持,因此jxbrowser 7之后不支持覆盖内置协议,详细见 + * {@link com.teamdev.jxbrowser.net.internal.NonInterceptableScheme} + * + * @param params 参数 + * @return 响应 + */ + @Override + public Response on(Params params) { + UrlRequest urlRequest = params.urlRequest(); + String path = urlRequest.url().replace(COLON_DECODE_ESCAPE, JxUIPane.COLON); + Optional urlRequestJobOptional; + if (path.startsWith(COMPONENT_TAG)) { + String text = htmlText(renderParameterBuild.get()); + urlRequestJobOptional = generateBasicUrlRequestJob(params, + "text/html", text.getBytes(StandardCharsets.UTF_8)); + } else { + urlRequestJobOptional = generateFileProtocolUrlRequestJob(params, path); + } + return urlRequestJobOptional + .map(Response::intercept) + .orElseGet(Response::proceed); + } + + protected Optional generateFileProtocolUrlRequestJob(Params params, String path) { + try { + String resourcePath = getResourcePath(path); + InputStream inputStream = getResourceStream(resourcePath); + String mimeType = MimeType.parseMimeType(resourcePath); + byte[] bytes; + if (isHtml(mimeType)) { + String text = IOUtils.inputStream2String(inputStream, EncodeConstants.ENCODING_UTF_8); + text = TemplateUtils.renderParameter4Tpl(text, renderParameterBuild.get()); + bytes = text.getBytes(StandardCharsets.UTF_8); + } else { + bytes = IOUtils.inputStream2Bytes(inputStream); + } + return generateBasicUrlRequestJob(params, mimeType, bytes); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + return Optional.empty(); + } + + /** + * 获取资源文件流 + * + * @param path 文件路径 + * @return 输入流 + * @throws Exception IO异常 + */ + private InputStream getResourceStream(String path) { + return IOUtils.readResource(path); + } + + private static String getResourcePath(String path) throws UnsupportedEncodingException { + int index = path.indexOf("="); + if (index > 0) { + path = path.substring(index + 1); + } else { + // jxbrowser 7之后,协议会自动补齐双斜杠// + int i = path.indexOf(SCHEME_SPLIT); + path = path.substring(i + SCHEME_SPLIT.length()); + // 通过自定义协议之后的url会自动encode一些中文字符,这里做一个decode,否则会导致路径访问失败 + path = URLDecoder.decode(path, StandardCharsets.UTF_8.name()); + } + return path; + } + + private boolean isHtml(String mimeType) { + return MimeType.HTML.getMimeType().equals(mimeType); + } + + private Optional generateBasicUrlRequestJob(Params params, String mimeType, byte[] bytes) { + if (StringUtils.isEmpty(mimeType)) { + return Optional.empty(); + } + UrlRequestJob.Options options = UrlRequestJob.Options + .newBuilder(HttpStatus.OK) + .addHttpHeader(HttpHeader.of("Content-Type", mimeType)) + .build(); + UrlRequestJob urlRequestJob = params.newUrlRequestJob(options); + urlRequestJob.write(bytes); + urlRequestJob.complete(); + return Optional.of(urlRequestJob); + } + + private String htmlText(Map map) { + return component.get() == null ? + StringUtils.EMPTY : + parseComponent(component.get(), map); + } + + @NotNull + private static String parseComponent(AssembleComponent component, Map map) { + PathGroup pathGroup = AtomBuilder.create().buildAssembleFilePath(ModernRequestClient.KEY, component); + StylePath[] stylePaths = pathGroup.toStylePathGroup(); + StringBuilder styleText = new StringBuilder(); + for (StylePath path : stylePaths) { + if (StringUtils.isNotBlank(path.toFilePath())) { + styleText.append(""); + } + } + String result = ModernUIConstants.HTML_TPL.replaceAll("##style##", styleText.toString()); + ScriptPath[] scriptPaths = pathGroup.toScriptPathGroup(); + StringBuilder scriptText = new StringBuilder(); + for (ScriptPath path : scriptPaths) { + if (StringUtils.isNotBlank(path.toFilePath())) { + scriptText.append(""); + } + } + result = result.replaceAll("##script##", scriptText.toString()); + if (map != null) { + for (Map.Entry entry : map.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + result = result.replaceAll("\\$\\{" + key + "}", value); + } + } + return result; + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/jxbrowser/PropertyBuild.java b/designer-base/src/main/java/com/fr/design/jxbrowser/PropertyBuild.java new file mode 100644 index 0000000000..ca82ca2475 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/jxbrowser/PropertyBuild.java @@ -0,0 +1,20 @@ +package com.fr.design.jxbrowser; + +import com.teamdev.jxbrowser.js.JsObject; + +/** + * 属性构建器 + * + * @author vito + * @since 11.0 + * Created on 2023/6/8 + */ +public interface PropertyBuild { + /** + * 构建属性 + * + * @param window js环境的window对象 + * @return 待注入java对象 + */ + Object build(JsObject window); +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/locale/impl/BbsRegisterMark.java b/designer-base/src/main/java/com/fr/design/locale/impl/BbsRegisterMark.java index afe1c8eef3..dfa425a3c0 100644 --- a/designer-base/src/main/java/com/fr/design/locale/impl/BbsRegisterMark.java +++ b/designer-base/src/main/java/com/fr/design/locale/impl/BbsRegisterMark.java @@ -1,13 +1,8 @@ package com.fr.design.locale.impl; -import com.fr.general.CloudCenter; -import com.fr.general.GeneralContext; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.general.locale.LocaleMark; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - /** * @author hades * @version 10.0 @@ -15,24 +10,19 @@ import java.util.Map; */ public class BbsRegisterMark implements LocaleMark { - private final Map map = new HashMap<>(); - private static final String BBS_REGISTER_CN = CloudCenter.getInstance().acquireUrlByKind("bbs.register", "https://id.fanruan.com/register/register.php?clueSource=activityfr"); - private static final String BBS_REGISTER_TW = CloudCenter.getInstance().acquireUrlByKind("bbs.register", "https://id.fanruan.com/register/register.php?clueSource=activityfr"); - private static final String BBS_REGISTER_EN = CloudCenter.getInstance().acquireUrlByKind("bbs.register.en_US", "https://id.fanruan.com/en/register/register.php"); - private static final String BBS_REGISTER_KR = CloudCenter.getInstance().acquireUrlByKind("bbs.register.en_US", "https://id.fanruan.com/en/register/register.php"); - private static final String BBS_REGISTER_JP = CloudCenter.getInstance().acquireUrlByKind("bbs.register.en_US", "https://id.fanruan.com/en/register/register.php"); + /** + * 云中心新账户中心链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_New_Account_Center"; - public BbsRegisterMark() { - map.put(Locale.CHINA, BBS_REGISTER_CN); - map.put(Locale.KOREA, BBS_REGISTER_KR); - map.put(Locale.JAPAN, BBS_REGISTER_JP); - map.put(Locale.US, BBS_REGISTER_EN); - map.put(Locale.TAIWAN, BBS_REGISTER_TW); - } + /** + * 云中心新账户中心链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_New_Account_Center_Default"; + public BbsRegisterMark() {} @Override public String getValue() { - String result = map.get(GeneralContext.getLocale()); - return result == null ? BBS_REGISTER_EN : result; + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); } } diff --git a/designer-base/src/main/java/com/fr/design/locale/impl/BbsResetMark.java b/designer-base/src/main/java/com/fr/design/locale/impl/BbsResetMark.java index 27db28e416..49092d4f25 100644 --- a/designer-base/src/main/java/com/fr/design/locale/impl/BbsResetMark.java +++ b/designer-base/src/main/java/com/fr/design/locale/impl/BbsResetMark.java @@ -1,13 +1,8 @@ package com.fr.design.locale.impl; -import com.fr.general.CloudCenter; -import com.fr.general.GeneralContext; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.general.locale.LocaleMark; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - /** * @author hades * @version 10.0 @@ -15,24 +10,21 @@ import java.util.Map; */ public class BbsResetMark implements LocaleMark { - private final Map map = new HashMap<>(); - private static final String BBS_RESET_CN = CloudCenter.getInstance().acquireUrlByKind("bbs.reset", "https://id.fanruan.com/forget/forget.php?clue=activityfr"); - private static final String BBS_RESET_TW = CloudCenter.getInstance().acquireUrlByKind("bbs.reset", "https://id.fanruan.com/forget/forget.php?clue=activityfr"); - private static final String BBS_RESET_EN = CloudCenter.getInstance().acquireUrlByKind("bbs.reset.en_US", "https://id.fanruan.com/en/forget/forget.php"); - private static final String BBS_RESET_KR = CloudCenter.getInstance().acquireUrlByKind("bbs.reset.en_US", "https://id.fanruan.com/en/forget/forget.php"); - private static final String BBS_RESET_JP = CloudCenter.getInstance().acquireUrlByKind("bbs.reset.en_US", "https://id.fanruan.com/en/forget/forget.php"); - public BbsResetMark() { - map.put(Locale.CHINA, BBS_RESET_CN); - map.put(Locale.KOREA, BBS_RESET_KR); - map.put(Locale.JAPAN, BBS_RESET_JP); - map.put(Locale.US, BBS_RESET_EN); - map.put(Locale.TAIWAN, BBS_RESET_TW); - } + /** + * 云中心老账户中心链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Account_Center"; + + /** + * 云中心老账户中心链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Account_Center_Default"; + + public BbsResetMark() {} @Override public String getValue() { - String result = map.get(GeneralContext.getLocale()); - return result == null ? BBS_RESET_EN : result; + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); } } diff --git a/designer-base/src/main/java/com/fr/design/locale/impl/BbsSpaceMark.java b/designer-base/src/main/java/com/fr/design/locale/impl/BbsSpaceMark.java index 999c732845..a0b21d271a 100644 --- a/designer-base/src/main/java/com/fr/design/locale/impl/BbsSpaceMark.java +++ b/designer-base/src/main/java/com/fr/design/locale/impl/BbsSpaceMark.java @@ -1,13 +1,8 @@ package com.fr.design.locale.impl; -import com.fr.general.CloudCenter; -import com.fr.general.GeneralContext; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.general.locale.LocaleMark; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - /** * @author hades * @version 10.0 @@ -15,25 +10,20 @@ import java.util.Map; */ public class BbsSpaceMark implements LocaleMark { - private final Map map = new HashMap<>(); - private static final String BBS_SPACE_CN = CloudCenter.getInstance().acquireUrlByKind("bbs.default", "http://bbs.fanruan.com/home.php?mod=space&do=pm"); - private static final String BBS_SPACE_TW = CloudCenter.getInstance().acquireUrlByKind("bbs.default", "http://bbs.fanruan.com/home.php?mod=space&do=pm"); - private static final String BBS_SPACE_EN = CloudCenter.getInstance().acquireUrlByKind("bbs.default.en_US", "https://community.finereport.com/home.php?mod=space&do=pm"); - private static final String BBS_SPACE_KR = CloudCenter.getInstance().acquireUrlByKind("bbs.default.en_US", "https://community.finereport.com/home.php?mod=space&do=pm"); - private static final String BBS_SPACE_JP = CloudCenter.getInstance().acquireUrlByKind("bbs.default.en_US", "https://community.finereport.com/home.php?mod=space&do=pm"); + /** + * 云中心帆软社区消息中心链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Message_Center"; - public BbsSpaceMark() { - map.put(Locale.CHINA, BBS_SPACE_CN); - map.put(Locale.KOREA, BBS_SPACE_KR); - map.put(Locale.JAPAN, BBS_SPACE_JP); - map.put(Locale.US, BBS_SPACE_EN); - map.put(Locale.TAIWAN, BBS_SPACE_TW); - } + /** + * 云中心帆软社区消息中心链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Message_Center_Default"; + + public BbsSpaceMark() {} @Override public String getValue() { - String result = map.get(GeneralContext.getLocale()); - return result == null ? BBS_SPACE_EN : result; + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); } - } diff --git a/designer-base/src/main/java/com/fr/design/locale/impl/DataMaskMark.java b/designer-base/src/main/java/com/fr/design/locale/impl/DataMaskMark.java new file mode 100644 index 0000000000..11312657b9 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/locale/impl/DataMaskMark.java @@ -0,0 +1,30 @@ +package com.fr.design.locale.impl; + +import com.fr.design.i18n.LocaleLinkProvider; +import com.fr.general.locale.LocaleMark; + + +/** + * 根据图片信息生成获取国际化服务器图标工具 + * + * @author obo + * @since 11.0 + * Created on 2023/4/19 + */ +public class DataMaskMark implements LocaleMark { + + /** + * 云中心数据脱敏帮助链接链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Data_Mask"; + + /** + * 云中心数据脱敏默认帮助链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design_Report_Desensitization_Help_Document_Url"; + + @Override + public String getValue() { + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); + } +} diff --git a/designer-base/src/main/java/com/fr/design/locale/impl/LineEngineMark.java b/designer-base/src/main/java/com/fr/design/locale/impl/LineEngineMark.java new file mode 100644 index 0000000000..ebb5fd09a3 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/locale/impl/LineEngineMark.java @@ -0,0 +1,28 @@ +package com.fr.design.locale.impl; + +import com.fr.design.i18n.LocaleLinkProvider; +import com.fr.general.locale.LocaleMark; + +/** + * 根据国际化获取启用行式引擎执行层式报表帮助文档链接 + * + * @author obo + * @since 11.0 + * Created on 2023/4/19 + */ +public class LineEngineMark implements LocaleMark { + + /** + * 云中心启用行式引擎执行层式报表帮助链接链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Line_Engine"; + + /** + * 云中心启用行式引擎执行层式报表默认帮助链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Line_Engine_Default"; + @Override + public String getValue() { + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); + } +} diff --git a/designer-base/src/main/java/com/fr/design/locale/impl/VideoMark.java b/designer-base/src/main/java/com/fr/design/locale/impl/VideoMark.java index 2521c82c23..571c5e02e9 100644 --- a/designer-base/src/main/java/com/fr/design/locale/impl/VideoMark.java +++ b/designer-base/src/main/java/com/fr/design/locale/impl/VideoMark.java @@ -16,7 +16,7 @@ public class VideoMark implements LocaleMark { private Map map = new HashMap<>(); private static final String VIDEO_EN = CloudCenter.getInstance().acquireUrlByKind("bbs.video.en_US", "http://www.finereport.com/en/Learning-path"); - private static final String VIDEO_CN = CloudCenter.getInstance().acquireUrlByKind("bbs.video.zh_CN", "https://edu.fanruan.com/video?class1=16&class2=0"); + private static final String VIDEO_CN = CloudCenter.getInstance().acquireUrlByKind("bbs.video.zh_CN", "https://home.fanruan.com/finereport/video"); private static final String VIDEO_TW = CloudCenter.getInstance().acquireUrlByKind("bbs.video.zh_TW", "http://www.finereport.com/tw/video"); public VideoMark() { diff --git a/designer-base/src/main/java/com/fr/design/lock/LockFileReSaveEnum.java b/designer-base/src/main/java/com/fr/design/lock/LockFileReSaveEnum.java new file mode 100644 index 0000000000..3feeb0a0b5 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/lock/LockFileReSaveEnum.java @@ -0,0 +1,64 @@ +package com.fr.design.lock; + +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.file.TemplateTreePane; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.utils.TemplateUtils; +import com.fr.file.FileNodeFILE; +import com.fr.file.filetree.FileNode; +import com.fr.stable.StableUtils; +import com.fr.stable.project.ProjectConstants; + +/** + * 被锁住的文件重新保存副本时的处理枚举类 + * + * @author Roger + * @since 11.0 + * Created on 2023/12/21 + */ +public enum LockFileReSaveEnum { + + /** + * 保存目录树里面的模板副本 + */ + TEMPLATE_TREE() { + @Override + public void action() { + FileNode node = TemplateTreePane.getInstance().getFileNode(); + if (node == null) { + return; + } + final String selectedFilePath = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, TemplateTreePane.getInstance().getFilePath()); + TemplateUtils.createAndReOpenTemplate( + Toolkit.i18nText("Fine_Design_Template_Lock_Copy"), + new FileNodeFILE(new FileNode(selectedFilePath, false)), + false, + true); + } + }, + + /** + * 保存设计器里面已经打开的模板副本 + */ + HISTORY_TEMPLATE_CACHE() { + @Override + public void action() { + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (JTemplate.isValid(template)) { + TemplateUtils.createAndOpenTemplate( + Toolkit.i18nText("Fine_Design_Template_Backup"), + new FileNodeFILE(new FileNode(template.getPath(), false)), + true, + true, + //另存之后需要关闭的模板 + template); + } + } + }; + + /** + * 如何保存模板副本 + */ + public abstract void action(); +} diff --git a/designer-base/src/main/java/com/fr/design/lock/LockInfoDialog.java b/designer-base/src/main/java/com/fr/design/lock/LockInfoDialog.java index 003215ca6c..c183dac2e9 100644 --- a/designer-base/src/main/java/com/fr/design/lock/LockInfoDialog.java +++ b/designer-base/src/main/java/com/fr/design/lock/LockInfoDialog.java @@ -8,15 +8,14 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerFrameFileDealerPane; -import com.fr.design.utils.TemplateUtils; import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.file.FileNodeFILE; -import com.fr.file.filetree.FileNode; import com.fr.general.IOUtils; -import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; -import com.fr.stable.project.ProjectConstants; import com.fr.workspace.base.UserInfo; + +import javax.swing.BorderFactory; +import javax.swing.JDialog; +import javax.swing.JPanel; import java.awt.BorderLayout; import java.awt.Color; import java.awt.FlowLayout; @@ -24,9 +23,6 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import javax.swing.BorderFactory; -import javax.swing.JDialog; -import javax.swing.JPanel; /** * @author hades @@ -37,8 +33,11 @@ public class LockInfoDialog extends JDialog { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm"); - public LockInfoDialog(UserInfo userInfo) { + private final LockFileReSaveEnum saveEnum; + + public LockInfoDialog(UserInfo userInfo, LockFileReSaveEnum saveEnum) { super(DesignerContext.getDesignerFrame()); + this.saveEnum = saveEnum; JPanel panel = new JPanel(new BorderLayout()); panel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); panel.add(createContentPane(userInfo), BorderLayout.CENTER); @@ -94,16 +93,7 @@ public class LockInfoDialog extends JDialog { @Override public void actionPerformed(ActionEvent e) { dispose(); - FileNode node = TemplateTreePane.getInstance().getFileNode(); - if (node == null) { - return; - } - final String selectedFilePath = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, TemplateTreePane.getInstance().getFilePath()); - TemplateUtils.createAndOpenTemplate( - Toolkit.i18nText("Fine_Design_Template_Lock_Copy"), - new FileNodeFILE(new FileNode(selectedFilePath, false)), - false, - true); + saveEnum.action(); } }); cancelButton.addActionListener(new ActionListener() { @@ -118,9 +108,25 @@ public class LockInfoDialog extends JDialog { } + /** + * 显示模板被人锁住了的弹窗信息 + * + * @param userInfo 拥有锁的用户信息 + */ public static void show(UserInfo userInfo) { DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(TemplateTreePane.getInstance().getFileNode()); - new LockInfoDialog(userInfo); + new LockInfoDialog(userInfo, LockFileReSaveEnum.TEMPLATE_TREE); + } + + /** + * 显示模板被人锁住了的弹窗信息,并以指定方式保存副本模板 + * + * @param userInfo 拥有锁的用户信息 + * @param saveEnum 指定保存副本模板的处理方式 + */ + public static void show(UserInfo userInfo, LockFileReSaveEnum saveEnum) { + DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(TemplateTreePane.getInstance().getFileNode()); + new LockInfoDialog(userInfo, saveEnum); } } diff --git a/designer-base/src/main/java/com/fr/design/lock/TemplateLockInfoReSave.java b/designer-base/src/main/java/com/fr/design/lock/TemplateLockInfoReSave.java new file mode 100644 index 0000000000..f1f927abb1 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/lock/TemplateLockInfoReSave.java @@ -0,0 +1,56 @@ +package com.fr.design.lock; + +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.mainframe.JTemplate; +import com.fr.event.Event; +import com.fr.event.EventDispatcher; +import com.fr.event.Listener; +import com.fr.log.FineLoggerFactory; +import com.fr.report.lock.LockInfoOperator; +import com.fr.stable.collections.CollectionUtils; +import com.fr.workspace.WorkContext; +import com.fr.workspace.Workspace; +import com.fr.workspace.WorkspaceEvent; + +import java.util.List; + +/** + * 更新模板锁信息 + * + * @author Roger + * @since 11.0 + * Created on 2023/12/11 + */ +public class TemplateLockInfoReSave { + + private static Listener listener = new Listener() { + @Override + public void on(Event event, Workspace workspace) { + List> templates = HistoryTemplateListCache.getInstance().getHistoryList(); + if (CollectionUtils.isEmpty(templates)) { + return; + } + String[] paths = templates.stream().map(JTemplate::getPath).toArray(String[]::new); + String[] lockedPath = WorkContext.getCurrent().get(LockInfoOperator.class).lockTemplates(paths); + FineLoggerFactory.getLogger().warn("template lock failed:{}", String.join(";", lockedPath)); + } + }; + + /** + * 启动监听 + */ + public static void startListener() { + if (!WorkContext.getCurrent().isLocal()) { + EventDispatcher.listen(WorkspaceEvent.ConnectSuccess, listener); + } + } + + /** + * 停止事件监听 + */ + public static void stopListener() { + if (!WorkContext.getCurrent().isLocal()) { + EventDispatcher.stopListen(listener); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/login/DesignerLoginBridge.java b/designer-base/src/main/java/com/fr/design/login/DesignerLoginBridge.java index 4d0ba8a41c..ad7d180552 100644 --- a/designer-base/src/main/java/com/fr/design/login/DesignerLoginBridge.java +++ b/designer-base/src/main/java/com/fr/design/login/DesignerLoginBridge.java @@ -5,10 +5,11 @@ import com.fr.design.bridge.exec.JSCallback; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.gui.ilable.ActionLabel; import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.i18n.Toolkit; +import com.fr.design.jxbrowser.BrowserExecutor; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.locale.impl.BbsResetMark; -import com.fr.design.login.executor.DesignerLoginBrowserExecutor; import com.fr.design.login.executor.DesignerLoginExecutor; import com.fr.design.login.executor.DesignerSendCaptchaExecutor; import com.fr.design.login.executor.DesignerSmsLoginExecutor; @@ -20,40 +21,58 @@ import com.fr.general.CloudCenter; import com.fr.general.locale.LocaleCenter; import com.fr.general.locale.LocaleMark; import com.fr.log.FineLoggerFactory; -import com.teamdev.jxbrowser.chromium.Browser; -import com.teamdev.jxbrowser.chromium.JSFunction; -import com.teamdev.jxbrowser.chromium.JSObject; +import com.teamdev.jxbrowser.js.JsAccessible; +import com.teamdev.jxbrowser.js.JsFunction; +import com.teamdev.jxbrowser.js.JsObject; + +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; import java.awt.Desktop; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.net.URI; import java.util.Map; import java.util.Set; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.SwingUtilities; /** + * 设计器登录通行证js-java桥 + * * @author Lanlan * @version 10.0 * Created by Lanlan on 2021/5/21 */ +@JsAccessible public class DesignerLoginBridge { - private Map params; + /** + * 云中心组件商城模板在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Market_Template"; + + /** + * 云中心组件商城模板默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Market_Template_Default"; - public static DesignerLoginBridge getBridge(Browser browser, Map params) { - return new DesignerLoginBridge(browser, params); + private final Map params; + + /** + * 获取 js-java bridge + * + * @param window 全局环境 + * @return bridge + */ + public static DesignerLoginBridge getBridge(JsObject window, Map params) { + return new DesignerLoginBridge(window, params); } - private JSObject window; + private final JsObject window; - private DesignerLoginBridge(Browser browser, Map params) { + private DesignerLoginBridge(JsObject window, Map params) { this.params = params; - this.window = browser.executeJavaScriptAndReturnValue("window").asObject(); + this.window = window; Set> entries = params.entrySet(); for (Map.Entry entry : entries) { - this.window.setProperty(entry.getKey(), entry.getValue()); + this.window.putProperty(entry.getKey(), entry.getValue()); } } @@ -71,7 +90,7 @@ public class DesignerLoginBridge { getHyperlinkPane( com.fr.design.i18n.Toolkit.i18nText("Fine-Designer_Guide_Login_Success_Title"), com.fr.design.i18n.Toolkit.i18nText("Fine-Designer_Guide_Login_Success_Hyperlink_Text"), - CloudCenter.getInstance().acquireUrlByKind("designer.premium.template", "https://market.fanruan.com/template") + LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT) ) ); } else if (source == DesignerLoginSource.BBS_JUMP) { @@ -171,9 +190,9 @@ public class DesignerLoginBridge { * @param callback 回调函数 */ @JSBridge - public void normalLogin(String username, String password, final JSFunction callback) { + public void normalLogin(String username, String password, final JsFunction callback) { DesignerLoginTaskWorker worker = new DesignerLoginTaskWorker<>( - new JSCallback(DesignerLoginBrowserExecutor.create(window, callback)), + new JSCallback(BrowserExecutor.create(window, callback)), new DesignerLoginExecutor(username, password)); worker.execute(); } @@ -186,9 +205,9 @@ public class DesignerLoginBridge { * @param callback 回调函数 */ @JSBridge - public void sendCaptcha(String regionCode, String phone, final JSFunction callback) { + public void sendCaptcha(String regionCode, String phone, final JsFunction callback) { DesignerLoginTaskWorker worker = new DesignerLoginTaskWorker<>( - new JSCallback(DesignerLoginBrowserExecutor.create(window, callback)), + new JSCallback(BrowserExecutor.create(window, callback)), new DesignerSendCaptchaExecutor(regionCode, phone)); worker.execute(); } @@ -202,9 +221,9 @@ public class DesignerLoginBridge { * @param callback 回调函数 */ @JSBridge - public void smsLogin(String regionCode, String phone, String code, final JSFunction callback) { + public void smsLogin(String regionCode, String phone, String code, final JsFunction callback) { DesignerLoginTaskWorker worker = new DesignerLoginTaskWorker<>( - new JSCallback(DesignerLoginBrowserExecutor.create(window, callback)), + new JSCallback(BrowserExecutor.create(window, callback)), new DesignerSmsLoginExecutor(regionCode, phone, code)); worker.execute(); } @@ -219,9 +238,9 @@ public class DesignerLoginBridge { * @param callback 回调函数 */ @JSBridge - public void smsRegister(String regionCode, String phone, String password, String regToken, final JSFunction callback) { + public void smsRegister(String regionCode, String phone, String password, String regToken, final JsFunction callback) { DesignerLoginTaskWorker worker = new DesignerLoginTaskWorker<>( - new JSCallback(DesignerLoginBrowserExecutor.create(window, callback)), + new JSCallback(BrowserExecutor.create(window, callback)), new DesignerSmsRegisterExecutor(regionCode, phone, password, regToken)); worker.execute(); } @@ -263,13 +282,10 @@ public class DesignerLoginBridge { private JPanel getHyperlinkPane(String title, String hyperlinkText, String hyperlink) { ActionLabel actionLabel = new ActionLabel(hyperlinkText); - actionLabel.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - try { - Desktop.getDesktop().browse(new URI(hyperlink)); - } catch (Exception ignore) { - } + actionLabel.addActionListener(e -> { + try { + Desktop.getDesktop().browse(new URI(hyperlink)); + } catch (Exception ignore) { } }); JPanel panel = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); diff --git a/designer-base/src/main/java/com/fr/design/login/DesignerLoginPane.java b/designer-base/src/main/java/com/fr/design/login/DesignerLoginPane.java index be5df3a84d..73811c0c83 100644 --- a/designer-base/src/main/java/com/fr/design/login/DesignerLoginPane.java +++ b/designer-base/src/main/java/com/fr/design/login/DesignerLoginPane.java @@ -2,21 +2,23 @@ package com.fr.design.login; import com.fr.design.DesignerEnvManager; import com.fr.design.dialog.BasicPane; +import com.fr.design.jxbrowser.JxUIPane; import com.fr.design.login.utils.DesignerLoginUtils; -import com.fr.design.ui.ModernUIPane; -import com.teamdev.jxbrowser.chromium.JSValue; -import com.teamdev.jxbrowser.chromium.events.ScriptContextAdapter; -import com.teamdev.jxbrowser.chromium.events.ScriptContextEvent; + import java.awt.BorderLayout; import java.util.Map; /** + * 设计器登录通行证面板 + * * @author Lanlan * @version 10.0 * Created by Lanlan on 2021/5/21 */ public class DesignerLoginPane extends BasicPane { + private static final String DESIGNER_LOGIN_HELPER = "DesignerLoginHelper"; + @Override protected String title4PopupWindow() { return "DESIGNER_LOGIN"; @@ -27,14 +29,8 @@ public class DesignerLoginPane extends BasicPane { params.put("lastLoginType", String.valueOf(DesignerEnvManager.getEnvManager().getLastLoginType().getType())); params.put("lastLoginAccount", DesignerEnvManager.getEnvManager().getLastLoginAccount()); setLayout(new BorderLayout()); - ModernUIPane modernUIPane = new ModernUIPane.Builder<>() - .prepare(new ScriptContextAdapter() { - @Override - public void onScriptContextCreated(ScriptContextEvent event) { - JSValue window = event.getBrowser().executeJavaScriptAndReturnValue("window"); - window.asObject().setProperty("DesignerLoginHelper", DesignerLoginBridge.getBridge(event.getBrowser(), params)); - } - }) + JxUIPane modernUIPane = new JxUIPane.Builder<>() + .bindWindow(DESIGNER_LOGIN_HELPER, window -> DesignerLoginBridge.getBridge(window, params)) .withEMB(DesignerLoginHelper.getMainResourcePath(), DesignerLoginUtils.renderMap()) .build(); add(modernUIPane, BorderLayout.CENTER); diff --git a/designer-base/src/main/java/com/fr/design/login/config/DesignerLoginConfigManager.java b/designer-base/src/main/java/com/fr/design/login/config/DesignerLoginConfigManager.java index b0fb0e292a..35e97add6a 100644 --- a/designer-base/src/main/java/com/fr/design/login/config/DesignerLoginConfigManager.java +++ b/designer-base/src/main/java/com/fr/design/login/config/DesignerLoginConfigManager.java @@ -75,6 +75,13 @@ public class DesignerLoginConfigManager implements XMLReadable, XMLWriter { */ private boolean useOldVersionLogin = false; + /** + * 是否手动配置过新插件管理 + *
  • 11.0.18版本开始全部认为没有手动配置过,符合机型的都默认开启新插件管理,如果需要关闭需要再次手动配置
  • + *
  • 如果手动配置过则置为false
  • + */ + private boolean useNewPluginFirst = true; + private DesignerLoginConfigManager() { } @@ -103,6 +110,7 @@ public class DesignerLoginConfigManager implements XMLReadable, XMLWriter { this.setLoginRemindBeforeJumpBBS(reader.getAttrAsBoolean("loginRemindBeforeJumpBBS", true)); this.setPluginRemindOnFirstLaunch(reader.getAttrAsBoolean("pluginRemindOnFirstLaunch", true)); this.setUseOldVersionLogin(reader.getAttrAsBoolean("useOldVersionLogin", false)); + this.setUseNewPluginFirst(reader.getAttrAsBoolean("useNewPluginFirst", true)); } } @@ -123,6 +131,7 @@ public class DesignerLoginConfigManager implements XMLReadable, XMLWriter { writer.attr("loginRemindBeforeJumpBBS", loginRemindBeforeJumpBBS); writer.attr("pluginRemindOnFirstLaunch", pluginRemindOnFirstLaunch); writer.attr("useOldVersionLogin", useOldVersionLogin); + writer.attr("useNewPluginFirst", useNewPluginFirst); writer.end(); } @@ -237,4 +246,12 @@ public class DesignerLoginConfigManager implements XMLReadable, XMLWriter { public void setUseOldVersionLogin(boolean useOldVersionLogin) { this.useOldVersionLogin = useOldVersionLogin; } + + public boolean isUseNewPluginFirst() { + return useNewPluginFirst; + } + + public void setUseNewPluginFirst(boolean useNewPluginFirst) { + this.useNewPluginFirst = useNewPluginFirst; + } } diff --git a/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuideBridge.java b/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuideBridge.java index 9b9c561e7c..e45323a0ed 100644 --- a/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuideBridge.java +++ b/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuideBridge.java @@ -6,26 +6,31 @@ import com.fr.design.dialog.FineJOptionPane; import com.fr.design.i18n.Toolkit; import com.fr.design.login.DesignerLoginHelper; import com.fr.design.login.DesignerLoginSource; -import com.teamdev.jxbrowser.chromium.Browser; -import com.teamdev.jxbrowser.chromium.JSObject; +import com.teamdev.jxbrowser.js.JsAccessible; + import javax.swing.JOptionPane; import javax.swing.SwingUtilities; /** + * 设计器登录指南面板的js-java桥 + * * @author Lanlan * @version 10.0 * Created by Lanlan on 2021/5/21 */ +@JsAccessible public class DesignerGuideBridge { - public static DesignerGuideBridge getBridge(Browser browser) { - return new DesignerGuideBridge(browser); + /** + * 获取 js-java bridge + * + * @return bridge + */ + public static DesignerGuideBridge getBridge() { + return new DesignerGuideBridge(); } - private JSObject window; - - private DesignerGuideBridge(Browser browser) { - this.window = browser.executeJavaScriptAndReturnValue("window").asObject(); + private DesignerGuideBridge() { } @JSBridge @@ -40,31 +45,28 @@ public class DesignerGuideBridge { DesignerLoginHelper.showLoginDialog(DesignerLoginSource.GUIDE); checkDoNotRemind(doNotRemind); } else { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - String[] options = new String[]{ - com.fr.design.i18n.Toolkit.i18nText("Fine-Designer_Login_Quit"), - com.fr.design.i18n.Toolkit.i18nText("Fine-Designer_Login_Return_Login") - }; - int rv = FineJOptionPane.showConfirmDialog( - DesignerGuideHelper.getDialog(), - com.fr.design.i18n.Toolkit.i18nText("Fine-Designer_Login_Quit_Tip"), - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), - JOptionPane.YES_NO_OPTION, - JOptionPane.WARNING_MESSAGE, - null, - options, - options[1] - ); - if (rv == JOptionPane.YES_OPTION) { - DesignerGuideHelper.closeWindow(); - checkDoNotRemind(doNotRemind); - } else if (rv == JOptionPane.NO_OPTION) { - DesignerLoginHelper.showLoginDialog(DesignerLoginSource.GUIDE); - DesignerGuideHelper.closeWindow(); - checkDoNotRemind(doNotRemind); - } + SwingUtilities.invokeLater(() -> { + String[] options = new String[]{ + Toolkit.i18nText("Fine-Designer_Login_Quit"), + Toolkit.i18nText("Fine-Designer_Login_Return_Login") + }; + int rv = FineJOptionPane.showConfirmDialog( + DesignerGuideHelper.getDialog(), + Toolkit.i18nText("Fine-Designer_Login_Quit_Tip"), + Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), + JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE, + null, + options, + options[1] + ); + if (rv == JOptionPane.YES_OPTION) { + DesignerGuideHelper.closeWindow(); + checkDoNotRemind(doNotRemind); + } else if (rv == JOptionPane.NO_OPTION) { + DesignerLoginHelper.showLoginDialog(DesignerLoginSource.GUIDE); + DesignerGuideHelper.closeWindow(); + checkDoNotRemind(doNotRemind); } }); } diff --git a/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuideHelper.java b/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuideHelper.java index 3e4c0dae51..05956da7c3 100644 --- a/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuideHelper.java +++ b/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuideHelper.java @@ -10,9 +10,12 @@ import com.fr.design.os.impl.SupportOSImpl; import com.fr.design.update.push.DesignerPushUpdateManager; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; + import javax.swing.WindowConstants; /** + * 设计器登录指南帮助类 + * * @author Lanlan * @version 10.0 * Created by Lanlan on 2021/5/21 diff --git a/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuidePane.java b/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuidePane.java index 64bd316ef5..9e2277b1fb 100644 --- a/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuidePane.java +++ b/designer-base/src/main/java/com/fr/design/login/guide/DesignerGuidePane.java @@ -1,20 +1,22 @@ package com.fr.design.login.guide; import com.fr.design.dialog.BasicPane; +import com.fr.design.jxbrowser.JxUIPane; import com.fr.design.login.guide.utils.DesignerGuideUtils; -import com.fr.design.ui.ModernUIPane; -import com.teamdev.jxbrowser.chromium.JSValue; -import com.teamdev.jxbrowser.chromium.events.ScriptContextAdapter; -import com.teamdev.jxbrowser.chromium.events.ScriptContextEvent; + import java.awt.BorderLayout; /** + * 设计器登录帆软通行证的指南面板 + * * @author Lanlan * @version 10.0 * Created by Lanlan on 2021/5/21 */ public class DesignerGuidePane extends BasicPane { + private static final String DESIGNER_GUIDE_HELPER = "DesignerGuideHelper"; + @Override protected String title4PopupWindow() { return "DESIGNER_GUIDE"; @@ -22,14 +24,8 @@ public class DesignerGuidePane extends BasicPane { public DesignerGuidePane() { setLayout(new BorderLayout()); - ModernUIPane modernUIPane = new ModernUIPane.Builder<>() - .prepare(new ScriptContextAdapter() { - @Override - public void onScriptContextCreated(ScriptContextEvent event) { - JSValue window = event.getBrowser().executeJavaScriptAndReturnValue("window"); - window.asObject().setProperty("DesignerGuideHelper", DesignerGuideBridge.getBridge(event.getBrowser())); - } - }) + JxUIPane modernUIPane = new JxUIPane.Builder<>() + .bindWindow(DESIGNER_GUIDE_HELPER, w -> DesignerGuideBridge.getBridge()) .withEMB(DesignerGuideHelper.getMainResourcePath(), DesignerGuideUtils.renderMap()) .build(); add(modernUIPane, BorderLayout.CENTER); diff --git a/designer-base/src/main/java/com/fr/design/login/message/DesignerMessageHelper.java b/designer-base/src/main/java/com/fr/design/login/message/DesignerMessageHelper.java index f3768629b4..58960d170c 100644 --- a/designer-base/src/main/java/com/fr/design/login/message/DesignerMessageHelper.java +++ b/designer-base/src/main/java/com/fr/design/login/message/DesignerMessageHelper.java @@ -77,6 +77,7 @@ public class DesignerMessageHelper { String url = CloudCenter.getInstance().acquireUrlByKind("designer.message.push", "https://market.fanruan.com/api/v1/message/designer"); Map params = new HashMap<>(); params.put("designerId", DesignerEnvManager.getEnvManager().getUUID()); + params.put("lang", DesignerEnvManager.getEnvManager().getLanguage().toString()); String result = HttpToolbox.post(url, params); JSONObject response = JSONFactory.createJSON(JSON.OBJECT, result); String status = response.optString(STATUS); diff --git a/designer-base/src/main/java/com/fr/design/login/socketio/LoginAuthServer.java b/designer-base/src/main/java/com/fr/design/login/socketio/LoginAuthServer.java index 2353965581..b0c57418ac 100644 --- a/designer-base/src/main/java/com/fr/design/login/socketio/LoginAuthServer.java +++ b/designer-base/src/main/java/com/fr/design/login/socketio/LoginAuthServer.java @@ -1,5 +1,12 @@ package com.fr.design.login.socketio; +import com.fr.cbb.websocket.core.WebSocketAckRequest; +import com.fr.cbb.websocket.core.WebSocketClientProvider; +import com.fr.cbb.websocket.core.WebSocketConfiguration; +import com.fr.cbb.websocket.core.WebSocketServerFactory; +import com.fr.cbb.websocket.core.WebSocketServerProvider; +import com.fr.cbb.websocket.holder.EventHolder; +import com.fr.cbb.websocket.listener.SocketDataListener; import com.fr.concurrent.NamedThreadFactory; import com.fr.design.DesignerEnvManager; import com.fr.design.login.DesignerLoginType; @@ -7,11 +14,6 @@ import com.fr.design.login.bean.BBSAccountLogin; import com.fr.design.upm.event.CertificateEvent; import com.fr.event.EventDispatcher; import com.fr.log.FineLoggerFactory; -import com.fr.third.socketio.AckRequest; -import com.fr.third.socketio.Configuration; -import com.fr.third.socketio.SocketIOClient; -import com.fr.third.socketio.SocketIOServer; -import com.fr.third.socketio.listener.DataListener; import java.net.URLDecoder; import java.util.concurrent.ExecutorService; @@ -27,7 +29,7 @@ public class LoginAuthServer { private AtomicBoolean started = new AtomicBoolean(false); - private SocketIOServer server; + private WebSocketServerProvider server; private static final String HOSTNAME = "localhost"; private static final int PORT = 41925; @@ -46,10 +48,10 @@ public class LoginAuthServer { } private LoginAuthServer() { - Configuration config = new Configuration(); + WebSocketConfiguration config = new WebSocketConfiguration(); config.setHostname(HOSTNAME); config.setPort(PORT); - server = new SocketIOServer(config); + server = WebSocketServerFactory.registerWebSocketServer(config); initEventListener(); } @@ -87,9 +89,9 @@ public class LoginAuthServer { } private void initEventListener() { - server.addEventListener("bbsAccountLogin", BBSAccountLogin.class, new DataListener() { + server.addEventListener(EventHolder.build("bbsAccountLogin", BBSAccountLogin.class, new SocketDataListener() { @Override - public void onData(SocketIOClient client, BBSAccountLogin data, AckRequest ackRequest) throws Exception { + public void onData(WebSocketClientProvider client, BBSAccountLogin data, WebSocketAckRequest ackRequest) throws Exception { // 保存登录信息到.FineReport100配置中 int uid = data.getUid(); if (uid > 0) { @@ -106,6 +108,6 @@ public class LoginAuthServer { EventDispatcher.fire(CertificateEvent.LOGIN, username); } } - }); + })); } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java index b18b346525..3cceff5a75 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java @@ -230,12 +230,11 @@ public class CenterRegionContainerPane extends JPanel { // 颜色,字体那些按钮的工具栏 toolbarPane.add(toolbarComponent = ad.resetToolBar(toolbarComponent, plus), BorderLayout.CENTER); - if (strategy.hasToolBarPane(plus)) { - this.add(toolbarPane, BorderLayout.NORTH); - } else { - this.remove(toolbarPane); + JPanel customNorthPane = strategy.customNorthPane(toolbarPane,plus); + if (!isExist(customNorthPane)){ + this.removeNorth(); + this.add(customNorthPane, BorderLayout.NORTH); } - if (strategy.hasTemplateTabPane(plus)) { eastCenterPane.add(templateTabPane, BorderLayout.CENTER); } else { @@ -250,6 +249,26 @@ public class CenterRegionContainerPane extends JPanel { resetByDesignMode(); } + private void removeNorth(){ + Component[] components = this.getComponents(); + for(Component c : components){ + if (c!= centerTemplateCardPane){ + this.remove(c); + } + } + } + + + private boolean isExist(JPanel customNorthPane) { + Component[] components = this.getComponents(); + for (Component component : components) { + if (component == customNorthPane) { + return true; + } + } + return false; + } + private void resetByDesignMode() { if (DesignModeContext.isDuchampMode()) { eastPane.remove(largeToolbar); @@ -292,4 +311,11 @@ public class CenterRegionContainerPane extends JPanel { return toolbarComponentState; } + /** + * 重置下RegionContainerpane + */ + public void resetCenterRegionContainerPane(){ + templateTabPane.add(MultiTemplateTabPane.getInstance(), BorderLayout.CENTER); + } + } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DefaultToolKitConfig.java b/designer-base/src/main/java/com/fr/design/mainframe/DefaultToolKitConfig.java index 305c44aa21..73daf052f1 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/DefaultToolKitConfig.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/DefaultToolKitConfig.java @@ -2,6 +2,8 @@ package com.fr.design.mainframe; import com.fr.design.base.mode.DesignModeContext; import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; +import javax.swing.JPanel; + public class DefaultToolKitConfig implements ToolKitConfigStrategy { @Override @@ -18,4 +20,10 @@ public class DefaultToolKitConfig implements ToolKitConfigStrategy { public boolean hasToolBarPane(ToolBarMenuDockPlus plus) { return plus.hasToolBarPane(); } + + @Override + public JPanel customNorthPane(JPanel toolBarPane, ToolBarMenuDockPlus plus) { + CenterRegionContainerPane.getInstance().resetCenterRegionContainerPane(); + return toolBarPane; + } } 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 596eac60ed..f5f415fa6d 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 @@ -34,6 +34,7 @@ import com.fr.design.mainframe.share.mini.MiniShopDisposingChecker; import com.fr.design.mainframe.toolbar.ToolBarMenuDock; import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; import com.fr.design.mainframe.vcs.common.VcsHelper; +import com.fr.design.mainframe.vcs.ui.VcsMovingExitOption; import com.fr.design.menu.ShortCut; import com.fr.design.os.impl.MacOsAddListenerAction; import com.fr.design.os.impl.SupportOSImpl; @@ -161,6 +162,12 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta @Override public void windowClosing(WindowEvent e) { + //检查是否正在迁移,如果正在迁移就弹出弹窗让用户选择 + if (!VcsMovingExitOption.ShowDialogAndConfirmExit()) { + //如果用户选择取消退出则返回,不然说明用户就是想退出,则往下走 + return; + } + // 检查mini商城是否存在未结束的后台任务 if (!MiniShopDisposingChecker.check()) { return; @@ -790,7 +797,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta if (!editingTemplate.getEditingFILE().exists()) { int returnVal = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Utils_Would_You_Like_To_Save") + " \"" + editingTemplate.getEditingFILE() - + "\" ?", Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_OPTION, + + "\" ?", Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (returnVal == JOptionPane.YES_OPTION && editingTemplate.saveTemplate()) { editingTemplate.saveTemplate(); @@ -852,7 +859,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta if (jt == null || jt.getEditingFILE() == null) { return; } - if (currentTemplateDeactivateFail()) { + if (currentTemplateDeactivateFail(jt)) { return; } jt.addJTemplateActionListener(this); @@ -877,7 +884,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta if (jt == null || jt.getEditingFILE() == null) { return; } - if (currentTemplateDeactivateFail()) { + if (currentTemplateDeactivateFail(jt)) { return; } getCenterTemplateCardPane().showJTemplate(jt); @@ -939,9 +946,9 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta * * @return 是否停用失败 */ - private boolean currentTemplateDeactivateFail() { + private boolean currentTemplateDeactivateFail(JTemplate jt) { JTemplate currentEditingTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - return currentEditingTemplate != null && !currentEditingTemplate.deactivateTemplate(); + return currentEditingTemplate != null && !currentEditingTemplate.deactivateTemplate(jt); } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java index f3ab77cf4d..1a715fefa0 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java @@ -16,6 +16,7 @@ import com.fr.design.data.DesignTableDataManager; import com.fr.design.data.datapane.TableDataTreePane; import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager; import com.fr.design.data.tabledata.ResponseDataSourceChange; +import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.file.FileOperations; import com.fr.design.file.FileToolbarStateChangeListener; @@ -34,6 +35,8 @@ import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateTreeSearchToolbarPane; +import com.fr.design.mainframe.vcs.RecycleAction; +import com.fr.design.mainframe.vcs.common.VcsCloseTemplateHelper; import com.fr.design.mainframe.vcs.common.VcsHelper; import com.fr.design.mainframe.vcs.ui.FileVersionsPanel; import com.fr.design.menu.KeySetUtils; @@ -54,6 +57,7 @@ import com.fr.plugin.injectable.PluginModule; import com.fr.plugin.manage.PluginFilter; import com.fr.plugin.observer.PluginEvent; import com.fr.plugin.observer.PluginEventListener; +import com.fr.report.lock.LockInfoOperator; import com.fr.stable.CoreConstants; import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; @@ -152,6 +156,8 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt private VcsAction vcsAction = new VcsAction(); + private RecycleAction recycleAction = new RecycleAction(); + //搜索 private SwitchAction switchAction = new SwitchAction(); private TemplateTreeSearchToolbarPane searchToolbarPane; @@ -327,13 +333,17 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt if (VcsHelper.getInstance().needInit()) { vcsAction = new VcsAction(); - if (!WorkContext.getCurrent().isCluster()) { + if (!isLegacyOnCluster()) { vcsAction.setName(Toolkit.i18nText("Fine-Design_Vcs_Title")); } else { vcsAction.setName(Toolkit.i18nText("Fine-Design_Vcs_NotSupportRemote")); } toolbarDef.addShortCut(vcsAction); - + //11.0.19及其之后加入回收站逻辑 + if (VcsHelper.getInstance().checkV2FunctionSupport()) { + recycleAction = new RecycleAction(); + toolbarDef.addShortCut(recycleAction); + } } } @@ -384,12 +394,6 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt } } - private boolean isCurrentEditing(String path) { - JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - String editing = jt.getEditingFILE().getPath(); - return ComparatorUtils.equals(editing, path); - } - /** * 按钮状态改变 */ @@ -494,24 +498,26 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt public void actionPerformed(ActionEvent e) { String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); path = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, path); - - boolean isCurrentEditing = isCurrentEditing(path); - - // 如果模板已经打开了,关掉,避免出现2个同名tab(1个是模板,1个是版本) - closeOpenedTemplate(path, isCurrentEditing); - FileVersionsPanel fileVersionTablePanel = FileVersionsPanel.getInstance(); - fileVersionTablePanel.showFileVersionsPane(); - stateChange(); - + boolean currentEditing = VcsCloseTemplateHelper.isCurrentEditing(path); + if (VcsHelper.getInstance().isLegacyMode()) { + // 如果模板已经打开了,关掉,避免出现2个同名tab(1个是模板,1个是版本) + closeOpenedTemplate(path, currentEditing); + FileVersionsPanel fileVersionTablePanel = FileVersionsPanel.getInstance(); + fileVersionTablePanel.showFileVersionsPane(); + stateChange(); + } else { + VcsCloseTemplateHelper.checkTemplateSavedAndShowVcsNewPane(path, currentEditing); + } } + /** * 版本管理可用状态的监控 */ private void fireVcsActionChange(boolean enable) { if (!DesignerEnvManager.getEnvManager().getVcsConfigManager().isVcsEnable() || VcsHelper.getInstance().isUnSelectedTemplate() - || WorkContext.getCurrent().isCluster()) { + || isLegacyOnCluster()) { setEnabled(false); return; } @@ -539,7 +545,7 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt } private boolean pathSupportVcsAction(String path) { - if (FileExtension.CPT.matchExtension(path) || FileExtension.FRM.matchExtension(path)) { + if (FileExtension.CPT.matchExtension(path) || FileExtension.FRM.matchExtension(path) || FileExtension.VIS.matchExtension(path)) { return true; } return false; @@ -558,7 +564,6 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt } } - } /** @@ -811,6 +816,11 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt } } + private boolean isLegacyOnCluster() { + // 老模式且为集群,用于代替之前的只判断集群逻辑 + return WorkContext.getCurrent().isCluster() && VcsHelper.getInstance().isLegacyMode(); + } + private String doCheck (String userInput, String suffix) { String errorMsg = StringUtils.EMPTY; if (selectedOperation.duplicated(userInput, suffix, true)) { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java index b033fa6171..1357b48354 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/EastRegionContainerPane.java @@ -19,6 +19,7 @@ import com.fr.design.notification.SnapChat; import com.fr.design.notification.SnapChatFactory; import com.fr.design.ui.util.UIUtil; import com.fr.design.utils.DesignUtils; +import com.fr.design.utils.SvgDrawUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.design.utils.gui.GUIPaintUtils; import com.fr.log.FineLoggerFactory; @@ -689,6 +690,13 @@ public class EastRegionContainerPane extends UIEastResizableContainer { } + public void hideAllPopupDialog() { + for (PropertyItem item : propertyItemMap.values()) { + item.popToFrame(); + } + } + + private void resetPropertyIcons() { for (PropertyItem item : propertyItemMap.values()) { item.resetButtonIcon(); @@ -1313,7 +1321,7 @@ public class EastRegionContainerPane extends UIEastResizableContainer { } else { button = UIConstants.POP_BUTTON_UP; } - g.drawImage(button, ARROW_RANGE_START + 8, 4, 16, 16, null); + SvgDrawUtils.doDrawSVG(g, () -> SvgDrawUtils.drawImage(g, button, (ARROW_RANGE_START + 8), 4, null)); } } 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 24c543a00a..c9ca4260e8 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 @@ -4,8 +4,10 @@ import com.fanruan.product.ProductConstants; import com.fr.base.Parameter; import com.fr.base.TRL; import com.fr.base.extension.FileExtension; +import com.fr.base.info.TemplateSaveInfoContext; import com.fr.base.io.BaseBook; import com.fr.base.iofile.attr.DesignBanCopyAttrMark; +import com.fr.base.iofile.attr.ForkIdAttrMark; import com.fr.base.iofile.attr.TemplateIdAttrMark; import com.fr.base.iofile.attr.TemplateThemeAttrMark; import com.fr.base.svg.IconUtils; @@ -58,9 +60,12 @@ import com.fr.design.module.DesignModuleFactory; import com.fr.design.preview.PagePreview; import com.fr.design.ui.util.UIUtil; import com.fr.design.utils.DesignUtils; +import com.fr.design.utils.TemplateUtils; 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.worker.save.type.SaveType; +import com.fr.design.worker.save.type.SaveTypeWorker; import com.fr.design.write.submit.DBManipulationInWidgetEventPane; import com.fr.design.write.submit.DBManipulationPane; import com.fr.event.EventDispatcher; @@ -88,6 +93,7 @@ import com.fr.plugin.observer.PluginEventListener; import com.fr.plugin.observer.PluginEventType; import com.fr.plugin.observer.PluginListenerRegistration; import com.fr.report.InconsistentLockException; +import com.fr.report.LockedException; import com.fr.report.UnLockedException; import com.fr.report.cell.Elem; import com.fr.report.cell.cellattr.CellImage; @@ -96,7 +102,9 @@ import com.fr.stable.ArrayUtils; import com.fr.stable.Filter; import com.fr.stable.StringUtils; import com.fr.stable.core.UUID; +import com.fr.widgettheme.designer.WidgetThemeDisplayAction; import com.fr.workspace.WorkContext; +import com.fr.workspace.base.UserInfo; import com.fr.workspace.server.lock.TplOperator; import com.fr.workspace.server.repository.template.TemplateRepository; @@ -111,6 +119,8 @@ import java.awt.Dimension; import java.awt.FontMetrics; import java.io.ByteArrayOutputStream; import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; import java.util.Set; import java.util.concurrent.Callable; @@ -118,6 +128,8 @@ import java.util.concurrent.Callable; * 报表设计和表单设计的编辑区域(设计器编辑的IO文件) */ public abstract class JTemplate> extends TargetComponent implements ToolBarMenuDockPlus, DesignerProxy, JTemplateSave, TabChangeListener, ThemedTemplate { + + private static final String DEFAULT_TAB_OPERATOR = "DefaultTabOperator"; // TODO ALEX_SEP editingFILE这个属性一定要吗?如果非要不可,有没有可能保证不为null private static final int PREDEFINED_ICON_WIDTH = 27; @@ -332,6 +344,18 @@ public abstract class JTemplate> generateTemplateId(); } + /** + * 如果没有 forkId, 则计算 forkId + * 要求在 templateId, 创建后执行。 + */ + protected void computeForkIdIfAbsent() { + + ForkIdAttrMark forkIdAttrMark = this.template.getAttrMark(ForkIdAttrMark.XML_TAG); + if (forkIdAttrMark == null || StringUtils.isEmpty(forkIdAttrMark.getForkId())) { + this.template.addAttrMark(new ForkIdAttrMark(this.template.getTemplateID())); + } + } + /** * 收集图表信息 */ @@ -870,7 +894,10 @@ public abstract class JTemplate> return saveAsTemplate(isShowLoc); } collectInfo(); - return this.saveFile(); + TemplateSaveInfoContext.getInstance().startCollect(template); + boolean result = this.saveFile(); + TemplateSaveInfoContext.getInstance().stopCollect(result); + return result; } private boolean isCancelOperation(int operation) { @@ -957,9 +984,12 @@ public abstract class JTemplate> } // 在保存之前,初始化 templateID generateNewTemplateIdForSaveAs(); + computeForkIdIfAbsent(); this.editingFILE = editingFILE; + TemplateSaveInfoContext.getInstance().startCollect(template); boolean result = this.saveToNewFile(oldName); + TemplateSaveInfoContext.getInstance().stopCollect(result); if (result) { DesignerFrameFileDealerPane.getInstance().refresh(); collectInfoWhenSaveAs(originID); @@ -1103,7 +1133,7 @@ public abstract class JTemplate> //查找替换 tplMenu.addShortCut(new NameSeparator(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Replace_Name_Separate"))); tplMenu.addShortCut((ShortCut) DesignModuleFactory.getITReplaceAction()); - + tplMenu.insertShortCut(1, new WidgetThemeDisplayAction<>(this)); return new MenuDef[]{tplMenu}; } @@ -1131,7 +1161,10 @@ public abstract class JTemplate> * @param l 模板Listener */ public void addJTemplateActionListener(JTemplateActionListener l) { - this.listenerList.add(JTemplateActionListener.class, l); + List list = Arrays.asList(this.listenerList.getListeners(JTemplateActionListener.class)); + if (!list.contains(l)) { + this.listenerList.add(JTemplateActionListener.class, l); + } } /** @@ -1358,6 +1391,17 @@ public abstract class JTemplate> } + /** + * 将要激活打开其他模板,使当前模板灭活 + * 默认 do nothing 返回true + * + * @return true:成功停用当前模板 + */ + public boolean deactivateTemplate(JTemplate jTemplate) { + //兼容调用老的接口 + return deactivateTemplate(); + } + /** * 返回当前支持的超链界面pane * @@ -1677,24 +1721,7 @@ public abstract class JTemplate> if (!editingFILE.exists()) { return saveAs(showLoc); } - - CallbackSaveWorker worker = new CallbackSaveWorker(new Callable() { - @Override - public Boolean call() throws Exception { - return saveRealFileByWorker(); - } - }, this); - - worker.addSuccessCallback(new Runnable() { - @Override - public void run() { - callBackForSave(); - //在保存后的回调中执行预编译流程 - CptCompileUtil.compile(JTemplate.this); - } - }); - - return worker; + return getSaveCallBackSaveWorker(); } /** @@ -1742,6 +1769,8 @@ public abstract class JTemplate> } } + + private CallbackSaveWorker saveAs(boolean showLoc) { FILE editingFILE = this.getEditingFILE(); if (editingFILE == null) { @@ -1763,11 +1792,12 @@ public abstract class JTemplate> // 目标文件 editingFILE = fileChooser.getSelectedFILE(); } - FILE finalEditingFILE = editingFILE; CallbackSaveWorker worker = new CallbackSaveWorker(new Callable() { @Override public Boolean call() throws Exception { + TemplateSaveInfoContext.getInstance().startRecord(); + TemplateSaveInfoContext.getInstance().collectInfo(template.suffix()); return saveAs(finalEditingFILE, sourceFile, oldName); } }, this); @@ -1824,6 +1854,8 @@ public abstract class JTemplate> } // 在保存之前,初始化 templateID generateNewTemplateIdForSaveAs(); + computeForkIdIfAbsent(); + this.editingFILE = editingFILE; boolean result = this.saveToNewRealFile(oldName); if (result) { @@ -1864,10 +1896,104 @@ public abstract class JTemplate> return saveAs(true); } + /** + * 获取保存用到的saveWorker + */ + private CallbackSaveWorker getSaveCallBackSaveWorker() { + CallbackSaveWorker worker = new CallbackSaveWorker(new Callable() { + @Override + public Boolean call() throws Exception { + TemplateSaveInfoContext.getInstance().startRecord(); + TemplateSaveInfoContext.getInstance().collectInfo(template.suffix()); + return saveRealFileByWorker(); + } + }, this); + + worker.addSuccessCallback(new Runnable() { + @Override + public void run() { + callBackForSave(); + //在保存后的回调中执行预编译流程 + CptCompileUtil.compile(JTemplate.this); + } + }); + return worker; + } + + /** + * 获取保存的类别执行的callable + */ + private Callable getSaveTypeCallable() { + return () -> { + fireJTemplateSaveBefore(); + FILE editingFILE = getEditingFILE(); + // carl:editingFILE没有,当然不存了,虽然不会有这种情况 + if (editingFILE == null) { + return SaveType.TypeEnum.EMPTY; + } + // 检查一下editingFILE是不是已存在的文件,如果不存在则用saveAs + if (!editingFILE.exists()) { + return SaveType.TypeEnum.SAVE_AS; + } + return SaveType.TypeEnum.SAVE; + }; + } + + /** + * 根据保存类型获取对应的saveWorker + * + * @param saveType 保存类型 + */ + private CallbackSaveWorker getSaveTypeWorker(SaveType saveType) { + CallbackSaveWorker callbackSaveWorker; + switch (saveType.getType()) { + case EMPTY: + callbackSaveWorker = new EmptyCallBackSaveWorker(); + break; + case SAVE: + callbackSaveWorker = getSaveCallBackSaveWorker(); + break; + default: + callbackSaveWorker = saveAs(true); + } + return callbackSaveWorker; + } + + + @Override public void saveDirectly() { - CallbackSaveWorker worker = save(); - worker.start(getRuntimeId()); + if (isSaving()) { + // 处理连按ctrl+s触发多线程保存的问题 + // 这里为什么可以不用加锁而直接判断isSaving: + // 实测actionPerformed有线程安全的特性,同一时间只有一个AWT线程走到这里,setSaving是线程安全的(SaveTemplateAction.actionPerformed) + // 多线程场景是因为我们用了SwingWorker子线程处理保存 + return; + } + new SaveTypeWorker(getSaveTypeCallable(), this) { + @Override + protected void done() { + try { + SaveType saveType = get(); + CallbackSaveWorker callbackSaveWorker = getSaveTypeWorker(saveType); + //告诉一下后面执行的saveWorker,当前判断文件是否存在的操作是否已经进行了开始转圈的那个等待动画,避免重复 + callbackSaveWorker.setSlowly(saveType.isSlowly()); + callbackSaveWorker.start(getRuntimeId()); + //如果是空也就是不保存,需要恢复一下界面(如果saveTypeWorker里进行了操作的话) + if (callbackSaveWorker instanceof EmptyCallBackSaveWorker) { + setSaving(false); + if (saveType.isSlowly()) { + if (ComparatorUtils.equals(getName(), HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getName())) { + DesignerContext.getDesignerFrame().getCenterTemplateCardPane().hideCover(); + } + } + DesignerFrameFileDealerPane.getInstance().stateChange(); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + }.start(); } @Override @@ -1971,7 +2097,7 @@ public abstract class JTemplate> public void setDesignerUIMode() { DesignerUIModeConfig.getInstance().setAbsoluteMeasureUIMode(); } - + /** * 判断当前的模板是否是有效的模板 * @@ -1981,4 +2107,50 @@ public abstract class JTemplate> public static boolean isValid(JTemplate jt) { return jt != null && jt != JNullTemplate.NULL; } + + /** + * 获取此模板所使用的tab栏操作类型 + * @return + */ + public String getTemplateTabOperatorType(){ + return DEFAULT_TAB_OPERATOR; + } + + /** + * 当前模板是否可以被保存 + * @return 是/否 + */ + public boolean canBeSaved(){ + return true; + } + + /** + * 当前的模板是否支持缓存 + * + * @return 是/否 + */ + public boolean supportCache(){ + return true; + } + + /** + * 获取此模板在tab栏中显示的名称 + * @return + */ + public String getTabShowName(JTemplate jTemplate){ + String name = TemplateUtils.createLockeTemplatedName(jTemplate, jTemplate.getTemplateName()); + if (!jTemplate.isSaved() && !name.endsWith(" *")) { + name += " *"; + } + return name; + } + + /** + * 切换环境之前是否需要保存 + * @return + */ + public boolean needSaveBeforeSwitchEnv(){ + return false; + } + } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java index fcfa4292fa..d850e8e814 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java @@ -157,7 +157,8 @@ public class NorthRegionContainerPane extends JPanel { if (!DesignerEnvManager.getEnvManager().getAlphaFineConfigManager().isEnabled()) { ad.createAlphaFinePane().setVisible(false); } - northEastPane.add(ad.createGuideEntryPane()); + /// 新手引导功能,暂时屏蔽 + // northEastPane.add(ad.createGuideEntryPane()); northEastPane.add(ad.createNotificationCenterPane()); OSSupportCenter.buildAction(new OSBasedAction() { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/ToolKitConfigStrategy.java b/designer-base/src/main/java/com/fr/design/mainframe/ToolKitConfigStrategy.java index 67b1409b36..f2feff8042 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/ToolKitConfigStrategy.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/ToolKitConfigStrategy.java @@ -2,6 +2,9 @@ package com.fr.design.mainframe; import com.fr.design.mainframe.toolbar.ToolBarMenuDockPlus; +import javax.swing.JPanel; + + public interface ToolKitConfigStrategy { /** @@ -24,4 +27,11 @@ public interface ToolKitConfigStrategy { * @return */ boolean hasToolBarPane(ToolBarMenuDockPlus plus); + /** + * 定制工具栏 + * @param toolBarPane + * @param plus + * @return + */ + JPanel customNorthPane(JPanel toolBarPane, ToolBarMenuDockPlus plus); } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/chart/info/ChartInfoCollector.java b/designer-base/src/main/java/com/fr/design/mainframe/chart/info/ChartInfoCollector.java index 7c19278c20..e8b726b2d6 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/chart/info/ChartInfoCollector.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/chart/info/ChartInfoCollector.java @@ -7,6 +7,7 @@ import com.fr.chartx.config.info.constant.ConfigType; import com.fr.design.mainframe.burying.point.AbstractPointCollector; import com.fr.design.mainframe.template.info.TemplateProcessInfo; import com.fr.general.ComparatorUtils; +import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; import com.fr.stable.xml.XMLPrintWriter; import com.fr.stable.xml.XMLableReader; @@ -184,33 +185,44 @@ public class ChartInfoCollector extends AbstractPointCollector { */ @Override public void collectInfo(String templateId, String originID, TemplateProcessInfo processInfo, int timeConsume) { - if (!shouldCollectInfo()) { - return; - } - if (StringUtils.isEmpty(originID)) { - originID = templateId; - } - boolean testTemplate = isTestTemplate(processInfo); + // 捕获RuntimeException,不中断保存模板核心逻辑,避免出现保存失败弹窗 + try { + if (!shouldCollectInfo()) { + return; + } + if (StringUtils.isEmpty(originID)) { + originID = templateId; + } + boolean testTemplate = isTestTemplate(processInfo); - for (ChartInfo chartInfo : pointInfoMap.values()) { - if (originID.equals(chartInfo.getTemplateId())) { - chartInfo.setTemplateId(templateId); - chartInfo.setTestTemplate(testTemplate); + for (ChartInfo chartInfo : pointInfoMap.values()) { + if (chartInfo != null && originID.equals(chartInfo.getTemplateId())) { + chartInfo.setTemplateId(templateId); + chartInfo.setTestTemplate(testTemplate); + } } - } - for (ChartInfo chartInfo : chartInfoCacheMap.values()) { - BaseBook book = chartInfo.getBook(); - if ((book != null && templateId.equals(book.getTemplateID())) || - originID.equals(chartInfo.getTemplateId())) { - chartInfo.setTemplateId(templateId); - chartInfo.setTestTemplate(testTemplate); - pointInfoMap.put(chartInfo.getChartId(), chartInfo); + for (ChartInfo chartInfo : chartInfoCacheMap.values()) { + if (chartInfo == null) { + continue; + } + BaseBook book = chartInfo.getBook(); + if (accept(templateId, originID, chartInfo, book)) { + chartInfo.setTemplateId(templateId); + chartInfo.setTestTemplate(testTemplate); + pointInfoMap.put(chartInfo.getChartId(), chartInfo); + } } + // 每次更新之后,都同步到暂存文件中 + saveInfo(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); } + } - // 每次更新之后,都同步到暂存文件中 - saveInfo(); + private static boolean accept(String templateId, String originID, ChartInfo chartInfo, BaseBook book) { + return (book != null && templateId.equals(book.getTemplateID())) || + originID.equals(chartInfo.getTemplateId()); } private boolean isTestTemplate(TemplateProcessInfo processInfo) { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java b/designer-base/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java index 51fe2f816a..30ff6c8911 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/chart/mode/ChartEditContext.java @@ -3,6 +3,9 @@ package com.fr.design.mainframe.chart.mode; import com.fr.common.annotations.Open; import com.fr.design.base.mode.DesignModeContext; +import java.util.HashSet; +import java.util.Set; + /** * @author shine * @version 10.0 @@ -13,6 +16,19 @@ public class ChartEditContext { private static ChartEditMode current = ChartEditMode.NORMAL; + private static final Set features = new HashSet<>(); + + /** + * 功能点枚举 + */ + public enum DuchampFeature { + SUPPORT_REPORT_DATA + } + + /** + * 切换图表编辑模式 + * @param mode 图表编辑模式 + */ public static void switchTo(ChartEditMode mode) { current = mode; } @@ -33,4 +49,28 @@ public class ChartEditContext { public static boolean supportTheme() { return !DesignModeContext.isDuchampMode(); } + + /** + * 注册功能点 + */ + public static void addDuchampFeature(DuchampFeature feature) { + features.add(feature); + } + + /** + * 移除功能点 + */ + public static void removeDuchampFeature(DuchampFeature feature) { + features.remove(feature); + } + + /** + * 当前模式下是否支持单元格数据来源 + */ + public static boolean supportReportData() { + if (normalMode()) { + return true; + } + return features.contains(DuchampFeature.SUPPORT_REPORT_DATA); + } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/check/CheckFontInfoDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/check/CheckFontInfoDialog.java index 0671ed1b63..8274b65355 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/check/CheckFontInfoDialog.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/check/CheckFontInfoDialog.java @@ -4,10 +4,10 @@ import com.fr.design.dialog.link.MessageWithLink; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.DesignSizeI18nManager; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.general.CloudCenter; import com.fr.general.IOUtils; import javax.swing.BorderFactory; @@ -39,17 +39,27 @@ public class CheckFontInfoDialog extends JDialog implements ActionListener { private UILabel directUiLabel; private UILabel detailLabel; + /** + * 云中心插件管理帮助文档在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Server_Install_Font"; + + /** + * 云中心插件管理默认帮助文档在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Server_Install_Font_Default"; + public CheckFontInfoDialog(Frame parent, String areaText) { super(parent,true); //提示信息 JPanel imagePanel = new JPanel(); imageLabel = new UILabel(IOUtils.readIcon("com/fr/design/images/warnings/warning32.png")); imagePanel.add(imageLabel); - + String link = LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); JPanel messagePanel = FRGUIPaneFactory.createVerticalFlowLayout_S_Pane(true); MessageWithLink linkMessage = new MessageWithLink(Toolkit.i18nText("Fine_Designer_Check_Font_Message"), Toolkit.i18nText("Fine_Designer_Check_Font_Install_Font"), - CloudCenter.getInstance().acquireUrlByKind("help.install.font", "https://help.fanruan.com/finereport/doc-view-3999.html")); + link); linkMessage.setPreferredSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.mainframe.check.CheckFontInfoDialog.messageWithLink")); messagePanel.add(linkMessage); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/errorinfo/ErrorInfo.java b/designer-base/src/main/java/com/fr/design/mainframe/errorinfo/ErrorInfo.java index 61bed0a1ed..abcdd2f37d 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/errorinfo/ErrorInfo.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/errorinfo/ErrorInfo.java @@ -33,6 +33,10 @@ public class ErrorInfo { private String log; private String stackTrace; + private boolean starting; + + private boolean remote; + public ErrorInfo(String username, String uuid, String activekey) { this.username = username; this.uuid = uuid; @@ -51,6 +55,22 @@ public class ErrorInfo { this.username = username; } + public boolean isStarting() { + return starting; + } + + public void setStarting(boolean starting) { + this.starting = starting; + } + + public boolean isRemote() { + return remote; + } + + public void setRemote(boolean remote) { + this.remote = remote; + } + public String getUuid() { return uuid; } @@ -126,6 +146,8 @@ public class ErrorInfo { jo.put("logid", logid); jo.put("log", log); jo.put("stacktrace", stackTrace); + jo.put("starting", starting); + jo.put("remote", remote); saveFileToCache(jo); } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java b/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java index 13e5dc28f0..c0337e7b2c 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/guide/tip/BubbleTip.java @@ -37,7 +37,7 @@ public class BubbleTip implements GuideTip { int returnVal = FineJOptionPane.showConfirmDialog( currentGuide.getGuideView(), Toolkit.i18nText("Fine-Design_Guide_Option_Warning_Terminal"), - Toolkit.i18nText("Fine-Design_Basic_Confirm"), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (returnVal == JOptionPane.YES_OPTION) { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/messagecollect/StartErrorMessageCollector.java b/designer-base/src/main/java/com/fr/design/mainframe/messagecollect/StartErrorMessageCollector.java index ca3fd13ccc..03e3694814 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/messagecollect/StartErrorMessageCollector.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/messagecollect/StartErrorMessageCollector.java @@ -1,9 +1,15 @@ package com.fr.design.mainframe.messagecollect; +import com.fr.concurrent.NamedThreadFactory; import com.fr.design.DesignerEnvManager; import com.fr.design.mainframe.errorinfo.ErrorInfo; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; +import com.fr.start.common.DesignerStartupContext; +import com.fr.workspace.WorkContext; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** * @@ -15,9 +21,11 @@ public class StartErrorMessageCollector { private static final StartErrorMessageCollector INSTANCE = new StartErrorMessageCollector(); + private ExecutorService executorService = Executors.newSingleThreadExecutor(new NamedThreadFactory(StartErrorMessageCollector.this.getClass())); private String uuid; private String activeKey; + private boolean extraJudgeStart = false; public static StartErrorMessageCollector getInstance() { return INSTANCE; @@ -35,10 +43,29 @@ public class StartErrorMessageCollector { errorInfo.setLogid(id); errorInfo.setLog(msg); errorInfo.setStackTrace(detail); + errorInfo.setStarting(DesignerStartupContext.getInstance().isOnStartup() || extraJudgeStart); + errorInfo.setRemote(!WorkContext.getCurrent().isLocal()); errorInfo.saveAsJSON(); } + /** + * 异步记录 + */ + public void asyncRecord(String id, String msg, String detail) { + executorService.submit(() -> { + record(id, msg, detail); + StartErrorMessageCollector.getInstance().setExtraJudgeStart(false); + }); + } + public void record(String id, String msg) { record(id, msg, StringUtils.EMPTY); } + + public void setExtraJudgeStart(boolean extraJudgeStart) { + this.extraJudgeStart = extraJudgeStart; + } + + + } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/processor/AbstractMobileStyleDefinePaneCreator.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/processor/AbstractMobileStyleDefinePaneCreator.java new file mode 100644 index 0000000000..203a83f13c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/processor/AbstractMobileStyleDefinePaneCreator.java @@ -0,0 +1,23 @@ +package com.fr.design.mainframe.mobile.processor; + +import com.fr.stable.fun.mark.API; + +/** + * 移动端Form控件,样式模板,通用属性替换接口 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/4/11 + */ +@API(level = MobileStyleDefinePaneCreator.CURRENT_LEVEL) +public abstract class AbstractMobileStyleDefinePaneCreator implements MobileStyleDefinePaneCreator { + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } + + @Override + public int layerIndex() { + return DEFAULT_LAYER_INDEX; + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/processor/MobileStyleDefinePaneCreator.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/processor/MobileStyleDefinePaneCreator.java new file mode 100644 index 0000000000..3b5e2cb861 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/processor/MobileStyleDefinePaneCreator.java @@ -0,0 +1,40 @@ +package com.fr.design.mainframe.mobile.processor; + +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.mainframe.mobile.ui.MobileStyleCustomDefinePane; +import com.fr.form.ui.Widget; +import com.fr.form.ui.mobile.MobileCommonExtraStyle; +import com.fr.form.ui.mobile.MobileStyle; +import com.fr.stable.fun.mark.Immutable; +import org.jetbrains.annotations.Nullable; + +/** + * 移动端Form控件,样式模板,通用属性替换接口 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/4/11 + */ +public interface MobileStyleDefinePaneCreator extends Immutable { + String XML_TAG = "MobileStyleDefinePaneCreator"; + + int CURRENT_LEVEL = 1; + + /** + *

    创建通用属性样式界面,可替换{@link com.fr.design.mainframe.mobile.ui.MobileStyleDefinePane} + *

    每种样式的通用属性面板是一样的 + * + * @param widget 控件 + * @param customDefinePane 自定义面板 + * @param mobileStyle 移动端样式 + * @return + */ + @Nullable BasicBeanPane createBaseBeanPane(Widget widget, Class customDefinePane, Class mobileStyle); + + /** + * 替换通用属性面板,注册额外属性 + * + * @return 属性类 + */ + @Nullable Class classForCommonExtraStyle(Widget widget); +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/provider/checkboxgroup/CapsuleCheckboxGroupStyleProvider.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/provider/checkboxgroup/CapsuleCheckboxGroupStyleProvider.java new file mode 100644 index 0000000000..3f84336c33 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/provider/checkboxgroup/CapsuleCheckboxGroupStyleProvider.java @@ -0,0 +1,41 @@ +package com.fr.design.mainframe.mobile.provider.checkboxgroup; + +import com.fr.design.fun.impl.AbstractMobileWidgetStyleProvider; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.mobile.ui.MobileStyleCustomDefinePane; +import com.fr.design.mainframe.mobile.ui.radiogroup.CapsuleCustomDefinePane; +import com.fr.form.ui.mobile.MobileStyle; +import com.fr.form.ui.mobile.radiogroup.CapsuleMobileStyle; + +/** + * 移动端复选框provider + * @author crawford.zhou + * @since 11.0 + * Created on 2024/1/25 + */ +public class CapsuleCheckboxGroupStyleProvider extends AbstractMobileWidgetStyleProvider { + @Override + public Class classForMobileStyle() { + return CapsuleMobileStyle.class; + } + + @Override + public Class classForWidgetAppearance() { + return CapsuleCustomDefinePane.class; + } + + @Override + public String xTypeForWidget() { + return "checkboxgroup"; + } + + @Override + public String displayName() { + return Toolkit.i18nText("Fine-Plugin-RadioGroup_Capsule_Button"); + } + + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/provider/checkboxgroup/ImageCheckboxGroupStyleProvider.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/provider/checkboxgroup/ImageCheckboxGroupStyleProvider.java new file mode 100644 index 0000000000..bafb50a43b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/provider/checkboxgroup/ImageCheckboxGroupStyleProvider.java @@ -0,0 +1,40 @@ +package com.fr.design.mainframe.mobile.provider.checkboxgroup; + +import com.fr.design.fun.impl.AbstractMobileWidgetStyleProvider; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.mobile.ui.MobileStyleCustomDefinePane; +import com.fr.design.mainframe.mobile.ui.radiogroup.ImageCustomDefinePane; +import com.fr.form.ui.mobile.MobileStyle; +import com.fr.form.ui.mobile.radiogroup.ImageMobileStyle; +/** + * 移动端复选框provider + * @author crawford.zhou + * @since 11.0 + * Created on 2024/1/25 + */ +public class ImageCheckboxGroupStyleProvider extends AbstractMobileWidgetStyleProvider { + @Override + public Class classForMobileStyle() { + return ImageMobileStyle.class; + } + + @Override + public Class classForWidgetAppearance() { + return ImageCustomDefinePane.class; + } + + @Override + public String xTypeForWidget() { + return "checkboxgroup"; + } + + @Override + public String displayName() { + return Toolkit.i18nText("Fine-Plugin-RadioGroup_Graphic_Button"); + } + + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/provider/checkboxgroup/UnitedCheckboxGroupStyleProvider.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/provider/checkboxgroup/UnitedCheckboxGroupStyleProvider.java new file mode 100644 index 0000000000..81249fee8c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/provider/checkboxgroup/UnitedCheckboxGroupStyleProvider.java @@ -0,0 +1,40 @@ +package com.fr.design.mainframe.mobile.provider.checkboxgroup; + +import com.fr.design.fun.impl.AbstractMobileWidgetStyleProvider; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.mobile.ui.MobileStyleCustomDefinePane; +import com.fr.design.mainframe.mobile.ui.radiogroup.UnitedCustomDefinePane; +import com.fr.form.ui.mobile.MobileStyle; +import com.fr.form.ui.mobile.radiogroup.UnitedMobileStyle; +/** + * 移动端复选框provider + * @author crawford.zhou + * @since 11.0 + * Created on 2024/1/25 + */ +public class UnitedCheckboxGroupStyleProvider extends AbstractMobileWidgetStyleProvider { + @Override + public Class classForMobileStyle() { + return UnitedMobileStyle.class; + } + + @Override + public Class classForWidgetAppearance() { + return UnitedCustomDefinePane.class; + } + + @Override + public String xTypeForWidget() { + return "checkboxgroup"; + } + + @Override + public String displayName() { + return Toolkit.i18nText("Fine-Plugin-RadioGroup_Linkage_Button"); + } + + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileStyleDefinePane.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileStyleDefinePane.java index 6c03df00d5..e1af0670a8 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileStyleDefinePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileStyleDefinePane.java @@ -8,6 +8,7 @@ import com.fr.design.gui.icombobox.LineComboBox; import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.ispinner.UISpinner; +import com.fr.design.i18n.DesignSizeI18nManager; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayoutHelper; @@ -53,22 +54,28 @@ public class MobileStyleDefinePane extends BasicBeanPane { private UISpinner borderRadius; private NewColorSelectBox iconColor; private MobileStyleFontConfigPane fontConfigPane; + private MobileStyle mobileStyle; MobileStyleDefinePane(Widget widget, Class customBeanPaneClass, Class mobileStyleClazz) { this.widget = widget; this.customBeanPane = Reflect.on(customBeanPaneClass).create(widget).get(); this.mobileStyleClazz = mobileStyleClazz; + initMobileStyle(widget); init(); } + private void initMobileStyle(Widget widget) { + mobileStyle = widget.getMobileStyle() != null ? widget.getMobileStyle() : Reflect.on(mobileStyleClazz).create().get(); + } + @Override public void populateBean(MobileStyle ob) { this.customBeanPane.populateBean(ob); customCombo.setSelectedIndex(ob.isCommonCustom() ? 1 : 0); - if(ob.getCommonBackground() != null) { - colorSelectBox.setSelectObject(((ColorBackground)ob.getCommonBackground()).getColor()); + if (ob.getCommonBackground() != null) { + colorSelectBox.setSelectObject(((ColorBackground) ob.getCommonBackground()).getColor()); } borderType.setSelectedLineStyle(ob.getCommonBorderType()); if (ob.getCommonBorderColor() != null) { @@ -85,7 +92,7 @@ public class MobileStyleDefinePane extends BasicBeanPane { @Override public MobileStyle updateBean() { - MobileStyle mobileStyle = Reflect.on(mobileStyleClazz).create().get(); + mobileStyle = Reflect.on(mobileStyleClazz).create().get(); this.widget.setMobileStyle(mobileStyle); this.customBeanPane.updateBean(); mobileStyle.setCommonCustom(customCombo.getSelectedIndex() == 1); @@ -204,7 +211,7 @@ public class MobileStyleDefinePane extends BasicBeanPane { private UILabel createConfigLabel(String title) { UILabel label = new UILabel(title + ":", UILabel.RIGHT); - label.setPreferredSize(new Dimension(75, 20)); + label.setPreferredSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.mainframe.mobile.ui.MobileStyleDefinePane.configLabel")); return label; } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileStylePane.java index 3573427ca9..f32205b4cc 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileStylePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/MobileStylePane.java @@ -7,15 +7,25 @@ import com.fr.design.fun.MobileWidgetStyleProvider; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.form.ui.Widget; import com.fr.form.ui.container.WScaleLayout; +import com.fr.form.ui.mobile.MobileCommonExtraStyle; import com.fr.form.ui.mobile.MobileStyle; +import com.fr.form.ui.mobile.StyleClassMap; import com.fr.form.ui.widget.CRBoundsWidget; import com.fr.log.FineLoggerFactory; import com.fr.stable.ArrayUtils; +import com.fr.widgettheme.widget.mobile.provider.WidgetThemeMobileStyleDefinePaneCreator; -import javax.swing.*; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListCellRenderer; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Component; +import java.awt.Dimension; import java.util.HashMap; import java.util.Map; @@ -29,8 +39,8 @@ public class MobileStylePane extends BasicPane { private Map> map = new HashMap<>(); public MobileStylePane(Widget widget) { - if(widget instanceof WScaleLayout) { - this.widget = ((CRBoundsWidget)((WScaleLayout) widget).getBoundsWidget()).getWidget(); + if (widget instanceof WScaleLayout) { + this.widget = ((CRBoundsWidget) ((WScaleLayout) widget).getBoundsWidget()).getWidget(); } else { this.widget = widget; } @@ -63,13 +73,17 @@ public class MobileStylePane extends BasicPane { } private void init() { + initComponent(); + } + + private void initComponent() { this.setLayout(FRGUIPaneFactory.createBorderLayout()); listModel = new DefaultListModel<>(); card = new CardLayout(); right = FRGUIPaneFactory.createCardLayout_S_Pane(); right.setLayout(card); MobileWidgetStyleProvider[] styleProviders = getMobileWidgetStyleProviders(); - for(MobileWidgetStyleProvider styleProvider: styleProviders) { + for (MobileWidgetStyleProvider styleProvider : styleProviders) { this.addProvider2View(styleProvider); } this.addWestList(); @@ -108,6 +122,13 @@ public class MobileStylePane extends BasicPane { listModel.addElement(displayName); try { BasicBeanPane mobileStyleBasicBeanPane = new MobileStyleDefinePane(widget, appearanceClazz, mobileStyleClazz); + if (WidgetThemeMobileStyleDefinePaneCreator.createBaseBeanPane(widget, appearanceClazz, mobileStyleClazz) != null) { + mobileStyleBasicBeanPane = WidgetThemeMobileStyleDefinePaneCreator.createBaseBeanPane(widget, appearanceClazz, mobileStyleClazz); + Class extraStyle = WidgetThemeMobileStyleDefinePaneCreator.classForCommonExtraStyle(widget); + if (extraStyle != null) { + StyleClassMap.putCommonStyle(extraStyle.getName(), extraStyle.getName()); + } + } right.add(displayName, mobileStyleBasicBeanPane); map.put(displayName, mobileStyleBasicBeanPane); } catch (Exception e) { @@ -133,4 +154,5 @@ public class MobileStylePane extends BasicPane { styleProviders = ArrayUtils.insert(0, styleProviders, defaultMobileWidgetStyleProvider); return styleProviders; } + } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/CapsuleCustomDefinePane.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/CapsuleCustomDefinePane.java index 072a7a57a1..6bc3821b06 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/CapsuleCustomDefinePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/CapsuleCustomDefinePane.java @@ -36,11 +36,23 @@ public class CapsuleCustomDefinePane extends MobileStyleCustomDefinePane { private UIComboBox custom; private JPanel centerPane; + // 按钮排布+按钮排布下拉框panel; + private JPanel buttonAlignPane; + + // 固定列数 数字panel + private JPanel columnSizePane; private UISpinner leftSpinner; private UISpinner rightSpinner; private UISpinner topSpinner; private UISpinner bottomSpinner; + private UIComboBox layoutTypeCombo; + + private UIComboBox buttonAlignCombo; + + + private UISpinner columnSizeSpinner; + private JRadioButton leftAlignRadioButton; private JRadioButton centerAlignRadioButton; @@ -121,13 +133,95 @@ public class CapsuleCustomDefinePane extends MobileStyleCustomDefinePane { return FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 10); } + /** + * 初始化布局方式下拉框 + */ + private void initLayoutCombo() { + layoutTypeCombo = new UIComboBox(new String[]{ + Toolkit.i18nText("Fine-Plugin-RadioGroup_Layout_Single_Line"), + Toolkit.i18nText("Fine-Plugin-RadioGroup_Layout_Auto"), + Toolkit.i18nText("Fine-Plugin-RadioGroup_Layout_Fixed") + }); + layoutTypeCombo.setPreferredSize(new Dimension(DesignerUtils.NORMAL_COMBO_WIDTH, 20)); + layoutTypeCombo.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (layoutTypeCombo.getSelectedIndex() == DesignerUtils.K_LAYOUT_SINGLE) { + buttonAlignPane.setVisible(true); + columnSizePane.setVisible(false); + } + if (layoutTypeCombo.getSelectedIndex() == DesignerUtils.K_LAYOUT_AUTO) { + buttonAlignPane.setVisible(false); + columnSizePane.setVisible(false); + } + if (layoutTypeCombo.getSelectedIndex() == DesignerUtils.K_LAYOUT_FIXED) { + buttonAlignPane.setVisible(false); + columnSizePane.setVisible(true); + } + } + }); + } + + /** + * 初始化按钮排布面板 + */ + private void initButtonAlignPane() { + UILabel buttonAlignLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Alignment")); + buttonAlignCombo = new UIComboBox(new String[]{ + Toolkit.i18nText("Fine-Plugin-RadioGroup_Alignment_Nature"), + Toolkit.i18nText("Fine-Plugin-RadioGroup_Alignment_Center"), + }); + buttonAlignCombo.setPreferredSize(new Dimension(DesignerUtils.LARGE_COMBO_WIDTH, 20)); + buttonAlignPane = TableLayoutHelper.createGapTableLayoutPane( + new Component[][]{new Component[]{buttonAlignLabel, buttonAlignCombo}}, + TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, + LayoutConstants.VGAP_SMALL + ); + } + + /** + * 初始化固定列数面板 + */ + private void initColumnSizePane() { + UILabel columnSizeLabel = DesignerUtils.createConfigLabel(""); + columnSizeSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DesignerUtils.INITIAL_COLUMN_SIZE); + columnSizeSpinner.setPreferredSize(new Dimension(DesignerUtils.LARGE_COMBO_WIDTH, 20)); + columnSizePane = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{columnSizeLabel, columnSizeSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); + columnSizePane.setVisible(false); + } + + private JPanel initVPaddingConfig() { + + UILabel topLabel = new UILabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Padding_Top")); + topSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DesignerUtils.kDefaultVerticalPadding); + + UILabel bottomLabel = new UILabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Padding_Bottom")); + bottomSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DesignerUtils.kDefaultVerticalPadding); + JPanel topSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{topLabel, topSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); + JPanel bottomSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{bottomLabel, bottomSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); + + return TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{topSpinnerPanel, bottomSpinnerPanel}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W1, LayoutConstants.VGAP_SMALL); + + } + private JPanel initHPaddingConfig() { + UILabel leftLabel = new UILabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Padding_Left")); + leftSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DesignerUtils.kDefaultHorizontalPadding); + + UILabel rightLabel = new UILabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Padding_Right")); + rightSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DesignerUtils.kDefaultHorizontalPadding); + JPanel leftSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{leftLabel, leftSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); + JPanel rightSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{rightLabel, rightSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); + + return TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{leftSpinnerPanel, rightSpinnerPanel}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W1, LayoutConstants.VGAP_SMALL); + } + private void addPaddingPane() { + double p = TableLayout.PREFERRED; + double[] rowSize = {p, p, p}; + double[] columnSize = {p, p}; centerPane.add(DesignerUtils.createTitleSplitLine(Toolkit.i18nText("Fine-Plugin-RadioGroup_Layout"))); - UILabel paddingHintLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Button_Padding")); UILabel emptyHintLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("")); - UILabel buttonAlignHintLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Alignment")); - UILabel leftLabel = new UILabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Padding_Left")); leftSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DesignerUtils.kDefaultHorizontalPadding); @@ -140,33 +234,33 @@ public class CapsuleCustomDefinePane extends MobileStyleCustomDefinePane { UILabel bottomLabel = new UILabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Padding_Bottom")); bottomSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DesignerUtils.kDefaultVerticalPadding); + UILabel layoutTypeLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Layout_Type")); + initLayoutCombo(); + initButtonAlignPane(); + initColumnSizePane(); leftAlignRadioButton = new JRadioButton(Toolkit.i18nText("Fine-Plugin-RadioGroup_Alignment_Left"), true); centerAlignRadioButton = new JRadioButton(Toolkit.i18nText("Fine-Plugin-RadioGroup_Alignment_Center"), false); - JPanel leftSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{leftLabel, leftSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); - JPanel rightSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{rightLabel, rightSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); - JPanel topSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{topLabel, topSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); - JPanel bottomSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{bottomLabel, bottomSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); - - JPanel vPaddingSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{topSpinnerPanel, bottomSpinnerPanel}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W1, LayoutConstants.VGAP_SMALL); - JPanel hPaddingSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{leftSpinnerPanel, rightSpinnerPanel}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W1, LayoutConstants.VGAP_SMALL); - - JPanel layoutPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{leftAlignRadioButton, centerAlignRadioButton}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W1, LayoutConstants.VGAP_SMALL); + JPanel layoutTypePanel = TableLayoutHelper.createGapTableLayoutPane( + new Component[][]{new Component[]{layoutTypeCombo}}, + TableLayoutHelper.FILL_LASTCOLUMN, + IntervalConstants.INTERVAL_W1, + LayoutConstants.VGAP_SMALL + ); ButtonGroup layoutRadioButtonGroup = new ButtonGroup(); layoutRadioButtonGroup.add(leftAlignRadioButton); layoutRadioButtonGroup.add(centerAlignRadioButton); - - double p = TableLayout.PREFERRED; - double[] rowSize = {p, p, p}; - double[] columnSize = {p, p}; JPanel paddingPanel = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{ - {paddingHintLabel, vPaddingSpinnerPanel}, - {emptyHintLabel, hPaddingSpinnerPanel}, - {buttonAlignHintLabel, layoutPanel}, + {paddingHintLabel, initVPaddingConfig()}, + {emptyHintLabel, initHPaddingConfig()}, + {layoutTypeLabel, layoutTypePanel}, }, rowSize, columnSize, 10); + centerPane.add(paddingPanel); + centerPane.add(buttonAlignPane); + centerPane.add(columnSizePane); } private void addBackgroundPane() { @@ -240,7 +334,7 @@ public class CapsuleCustomDefinePane extends MobileStyleCustomDefinePane { UILabel initialFontLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Font_init")); initialFontConfPane = new FontConfigPane(); - initialFontConfPane.setFontColor(new Color(204, 204, 204)); + initialFontConfPane.setFontColor(new Color(102, 102, 102)); JPanel fontPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{initialFontLabel, initialFontConfPane}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_MEDIUM); centerPane.add(fontPanel); UILabel selectedFontLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Font_Select")); @@ -260,6 +354,9 @@ public class CapsuleCustomDefinePane extends MobileStyleCustomDefinePane { rightSpinner.setValue(mobileStyle.getRightPadding()); topSpinner.setValue(mobileStyle.getTopPadding()); bottomSpinner.setValue(mobileStyle.getBottomPadding()); + layoutTypeCombo.setSelectedIndex(mobileStyle.getButtonLayoutType()); + buttonAlignCombo.setSelectedIndex(mobileStyle.getButtonAlign()); + columnSizeSpinner.setValue(mobileStyle.getButtonColumnSize()); leftAlignRadioButton.setSelected(mobileStyle.getButtonAlign() == DesignerUtils.kAlignLeft); centerAlignRadioButton.setSelected(mobileStyle.getButtonAlign() == DesignerUtils.kAlignCenter); initialColorSelectBox.setSelectObject(mobileStyle.getInitialBackgroundColor()); @@ -285,7 +382,9 @@ public class CapsuleCustomDefinePane extends MobileStyleCustomDefinePane { mobileStyle.setRightPadding(rightSpinner.getValue()); mobileStyle.setTopPadding(topSpinner.getValue()); mobileStyle.setBottomPadding(bottomSpinner.getValue()); - mobileStyle.setButtonAlign(leftAlignRadioButton.isSelected() ? DesignerUtils.kAlignLeft : DesignerUtils.kAlignCenter); + mobileStyle.setButtonAlign(buttonAlignCombo.getSelectedIndex()); + mobileStyle.setButtonLayoutType(layoutTypeCombo.getSelectedIndex()); + mobileStyle.setButtonColumnSize((int)columnSizeSpinner.getValue()); mobileStyle.setInitialBackgroundColor(initialColorSelectBox.getSelectObject()); mobileStyle.setSelectedBackgroundColor(selectedColorSelectBox.getSelectObject()); mobileStyle.setBorderType(borderLineCombo.getSelectedLineStyle()); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/IconConfigPane.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/IconConfigPane.java index 08e0ecd09a..85f4f3601b 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/IconConfigPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/IconConfigPane.java @@ -1,5 +1,6 @@ package com.fr.design.mainframe.mobile.ui.radiogroup; +import com.fr.base.BaseUtils; import com.fr.base.IconManager; import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.DialogActionAdapter; @@ -12,11 +13,13 @@ import com.fr.design.web.CustomIconPane; import com.fr.form.ui.WidgetInfoConfig; import com.fr.general.ComparatorUtils; import com.fr.general.FRFont; +import com.fr.stable.ArrayUtils; import com.fr.stable.StringUtils; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; import javax.swing.plaf.basic.BasicButtonUI; import java.awt.*; import java.awt.event.ActionEvent; @@ -24,24 +27,125 @@ import java.awt.event.ActionListener; import java.util.ArrayList; public class IconConfigPane extends JPanel { + private final int northPaneWidth = 330; + private final int listenerStep = 2; + private final Icon addIcon = BaseUtils.readIcon("/com/fr/design/images/buttonicon/icon_add.png"); + + private final Icon deleteIcon = BaseUtils.readIcon("/com/fr/design/images/buttonicon/icon_delete.png"); private UIButton editIconButton; private UIButton deleteIconButton; private String curIconName; private IconButton selectIconButton; private ArrayList iconButtons = new ArrayList(); + private UIButton addCountButton; + + private UIButton deleteCountButton; + + private EventListenerList addCountListener = new EventListenerList(); + private EventListenerList deleteCountListener = new EventListenerList(); + + private JPanel northPane; + public IconConfigPane(int count) { - initComp(count); + initComp(count, false); + } + public IconConfigPane(int count, boolean canChangeCount) { + initComp(count, canChangeCount); } - public void initComp(int count) { - this.setLayout(FRGUIPaneFactory.createBorderLayout()); - JPanel panel = FRGUIPaneFactory.createNormalFlowInnerContainer_M_Pane(); - panel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0)); + /** + * 删除一个图标 + */ + public void deleteCount() { + if (!iconButtons.isEmpty()) { + northPane.remove(iconButtons.get(iconButtons.size() - 1)); + iconButtons.remove(iconButtons.size() - 1); + adjustNorthPaneHeight(); + IconConfigPane.this.revalidate(); // 重新验证并更新布局 + IconConfigPane.this.repaint(); // 可选:刷新JPanel以更新界面显示 + deleteCountButton.setEnabled(!iconButtons.isEmpty()); + } + deleteCountButton.setEnabled(!iconButtons.isEmpty()); + } + /** + * 添加一个图标 + */ + public void addCount() { + deleteCountButton.setEnabled(true); + IconButton iconButton = new IconButton(""); + selectIconButton = iconButton; + editIconButton.setEnabled(true); + iconButtons.add(iconButton); + int indexToInsert = northPane.getComponentCount() - 2; + deleteCountButton.setEnabled(!iconButtons.isEmpty()); + // 创建新的按钮并插入到倒数第三个组件后面 + northPane.add(iconButton, indexToInsert); + adjustNorthPaneHeight(); + IconConfigPane.this.revalidate(); // 重新验证并更新布局 + IconConfigPane.this.repaint(); // 可选:刷新JPanel以更新界面显示 + } + private void adjustNorthPaneHeight() { + northPane.setPreferredSize(new Dimension(northPaneWidth, getNorthPanelHeight(iconButtons.size()))); + } + + private int getNorthPanelHeight(int iconNum) { + return (int) Math.ceil((iconNum + 2) / 13.0) * 30; + } + + private void initAddAndDeleteCountButton(Boolean deleteCountButtonEnabled) { + addCountButton = new UIButton(addIcon); + addCountButton.setPreferredSize(new Dimension(20, 20)); + addCountButton.setName("add"); + deleteCountButton = new UIButton(deleteIcon); + deleteCountButton.setPreferredSize(new Dimension(20, 20)); + deleteCountButton.setName("delete"); + deleteCountButton.setEnabled(deleteCountButtonEnabled); + addCountButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fireAddCountListener(); + } + }); + deleteCountButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fireDeleteCountListener(); + } + }); + northPane.add(addCountButton); + northPane.add(deleteCountButton); + } + + /** + * 根据图标名称刷新字体配置面板 + * @param names 字体名称 + * @param canChangeCount 是否支持改变数目 + */ + public void refreshByIconNames(String[] names, Boolean canChangeCount) { + northPane.removeAll(); + northPane.setPreferredSize(new Dimension(northPaneWidth, getNorthPanelHeight(names.length))); + ArrayList newIconButtons = new ArrayList<>(); + for (String name : names) { + IconButton iconButton = new IconButton(name); + northPane.add(iconButton); + newIconButtons.add(iconButton); + } + iconButtons = newIconButtons; + if (canChangeCount) { + initAddAndDeleteCountButton(!ArrayUtils.isEmpty(names)); + } + IconConfigPane.this.revalidate(); + IconConfigPane.this.repaint(); + } + + /** + * 初始化编辑按钮 + */ + private void initEditIconButton() { editIconButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Edit")); editIconButton.setFont(FRFont.getInstance("Helvetica", Font.PLAIN, 12, Color.decode("#3A383A"))); editIconButton.setPreferredSize(new Dimension(62, 20)); - panel.add(editIconButton); editIconButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { final CustomIconPane cip = new CustomIconPane(){ @@ -62,11 +166,14 @@ public class IconConfigPane extends JPanel { } }); editIconButton.setEnabled(false); - + } + /** + * 初始化删除按钮 + */ + private void initDeleteIconButton() { deleteIconButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Delete")); deleteIconButton.setFont(FRFont.getInstance("Helvetica", Font.PLAIN, 12, Color.decode("#3A383A"))); deleteIconButton.setPreferredSize(new Dimension(62, 20)); - panel.add(deleteIconButton); deleteIconButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -75,30 +182,89 @@ public class IconConfigPane extends JPanel { } }); deleteIconButton.setEnabled(false); - - + } + /** + * 重载形式 + * @param count 图标数目 + * @param canChangeCount 是否可以动态增减 + */ + public void initComp(int count, boolean canChangeCount) { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + JPanel panel = FRGUIPaneFactory.createNormalFlowInnerContainer_M_Pane(); + panel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0)); + initEditIconButton(); + initDeleteIconButton(); + panel.add(editIconButton); + panel.add(deleteIconButton); + northPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); + northPane.setPreferredSize(new Dimension(northPaneWidth, getNorthPanelHeight(count))); this.add(panel, BorderLayout.CENTER); - - JPanel northPane = new JPanel(); - northPane.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); for (int i = 0; i < count; i++) { IconButton iconButton = new IconButton(""); northPane.add(iconButton); iconButtons.add(iconButton); } + if (canChangeCount) { + initAddAndDeleteCountButton(count != 0); + } this.add(northPane, BorderLayout.NORTH); } public void setShowIconImage() { selectIconButton.setIconName(curIconName); } + /** + * 添加事件的监听 + * @param changeListener 监听列表 + */ + public void addAddCountListener(ChangeListener changeListener) { + addCountListener.add(ChangeListener.class, changeListener); + } + /** + * 删除事件的监听 + * @param changeListener 监听列表 + */ + public void addDeleteCountListener(ChangeListener changeListener) { + deleteCountListener.add(ChangeListener.class, changeListener); + } + /** + * 点击增加按钮 + */ + public void fireAddCountListener() { + Object[] listeners = addCountListener.getListenerList(); + ChangeEvent e = null; + + for (int i = listeners.length - listenerStep; i >= 0; i -= listenerStep) { + if (listeners[i] == ChangeListener.class) { + if (e == null) { + e = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(e); + } + } + } + /** + * 点击删除按钮 + */ + public void fireDeleteCountListener() { + Object[] listeners = deleteCountListener.getListenerList(); + ChangeEvent e = null; + + for (int i = listeners.length - listenerStep; i >= 0; i -= listenerStep) { + if (listeners[i] == ChangeListener.class) { + if (e == null) { + e = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(e); + } + } + } public void populate(ArrayList iconArr) { for (int i = 0; i < iconButtons.size(); i++) { iconButtons.get(i).setIconName(iconArr.get(i)); } } - public ArrayList update() { ArrayList iconNames = new ArrayList(); for (int i = 0; i < iconButtons.size(); i++) { @@ -107,7 +273,6 @@ public class IconConfigPane extends JPanel { return iconNames; } - private class IconButton extends JToggleButton implements ActionListener { private String iconName; private Image iconImage = null; diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/ImageCustomDefinePane.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/ImageCustomDefinePane.java index 7288d3263c..c517e03571 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/ImageCustomDefinePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/ImageCustomDefinePane.java @@ -9,6 +9,7 @@ import com.fr.design.gui.ibutton.UIColorButton; import com.fr.design.gui.ibutton.UIToggleButton; import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.iscrollbar.UIScrollBar; import com.fr.design.gui.ispinner.UISpinner; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; @@ -23,11 +24,13 @@ import com.fr.form.ui.mobile.radiogroup.ImageMobileStyle; import com.fr.general.FRFont; import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; -import java.util.Arrays; public class ImageCustomDefinePane extends MobileStyleCustomDefinePane { @@ -36,12 +39,21 @@ public class ImageCustomDefinePane extends MobileStyleCustomDefinePane { private JPanel scrollPanel; private UIComboBox custom; private JPanel centerPane; + // 按钮排布+按钮排布下拉框panel; + private JPanel buttonAlignPane; + // 固定列数 数字panel + private JPanel columnSizePane; private UISpinner leftSpinner; private UISpinner rightSpinner; private UISpinner topSpinner; private UISpinner bottomSpinner; + private UIComboBox layoutTypeCombo; + + private UIComboBox buttonAlignCombo; + + private UISpinner columnSizeSpinner; private IconConfigPane initialIconConfigPane; private IconConfigPane selectedIconConfigPane; @@ -73,6 +85,14 @@ public class ImageCustomDefinePane extends MobileStyleCustomDefinePane { protected JPanel createContentPane() { return scrollPanel; } + + @Override + protected void setLeftContentPaneBounds(Container parent, UIScrollBar scrollBar, int beginY, int maxheight) { + int width = parent.getWidth(); + int height = parent.getHeight(); + leftcontentPane.setBounds(0, -beginY, width - scrollBar.getWidth() + getOverWidth(), leftcontentPane.getPreferredSize().height); + scrollBar.setBounds(width - scrollBar.getWidth(), 0, scrollBar.getWidth(), height); + } }; this.add(basicScrollPane); } @@ -115,67 +135,172 @@ public class ImageCustomDefinePane extends MobileStyleCustomDefinePane { return FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 10); } - private void addPaddingPane() { - centerPane.add(DesignerUtils.createTitleSplitLine(Toolkit.i18nText("Fine-Plugin-RadioGroup_Layout"))); + private void initLayoutCombo() { + layoutTypeCombo = new UIComboBox(new String[]{ + Toolkit.i18nText("Fine-Plugin-RadioGroup_Layout_Single_Line"), + Toolkit.i18nText("Fine-Plugin-RadioGroup_Layout_Auto"), + Toolkit.i18nText("Fine-Plugin-RadioGroup_Layout_Fixed") + }); + layoutTypeCombo.setPreferredSize(new Dimension(DesignerUtils.LARGE_COMBO_WIDTH, 20)); + layoutTypeCombo.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + if (layoutTypeCombo.getSelectedIndex() == DesignerUtils.K_LAYOUT_SINGLE) { + buttonAlignPane.setVisible(true); + columnSizePane.setVisible(false); + } + if (layoutTypeCombo.getSelectedIndex() == DesignerUtils.K_LAYOUT_AUTO) { + buttonAlignPane.setVisible(false); + columnSizePane.setVisible(false); + } + if (layoutTypeCombo.getSelectedIndex() == DesignerUtils.K_LAYOUT_FIXED) { + buttonAlignPane.setVisible(false); + columnSizePane.setVisible(true); + } + } + }); + } - UILabel paddingHintLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Button_Padding")); - UILabel emptyHintLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("")); + /** + * 初始化按钮排布面板 + */ + private void initButtonAlignPane() { + UILabel buttonAlignLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Alignment")); + buttonAlignCombo = new UIComboBox(new String[]{ + Toolkit.i18nText("Fine-Plugin-RadioGroup_Alignment_Nature"), + Toolkit.i18nText("Fine-Plugin-RadioGroup_Alignment_Split"), + }); + buttonAlignCombo.setSelectedIndex(1); + buttonAlignCombo.setPreferredSize(new Dimension(DesignerUtils.LARGE_COMBO_WIDTH, 20)); + buttonAlignPane = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{buttonAlignLabel, buttonAlignCombo}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); + } - UILabel leftLabel = new UILabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Padding_Left")); - leftSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DesignerUtils.kDefaultHorizontalPadding); + /** + * 初始化固定列数面板 + */ + private void initColumnSizePane() { + UILabel columnSizeLabel = DesignerUtils.createConfigLabel(""); + columnSizeSpinner = new UISpinner(1, Integer.MAX_VALUE, 1, DesignerUtils.INITIAL_COLUMN_SIZE); + columnSizeSpinner.setPreferredSize(new Dimension(DesignerUtils.LARGE_COMBO_WIDTH, 20)); + columnSizePane = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{columnSizeLabel, columnSizeSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); + columnSizePane.setVisible(false); + } - UILabel rightLabel = new UILabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Padding_Right")); - rightSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DesignerUtils.kDefaultHorizontalPadding); + private JPanel initVPaddingConfig() { UILabel topLabel = new UILabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Padding_Top")); topSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DesignerUtils.kDefaultVerticalPadding); UILabel bottomLabel = new UILabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Padding_Bottom")); bottomSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DesignerUtils.kDefaultVerticalPadding); + JPanel topSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{topLabel, topSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); + JPanel bottomSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{bottomLabel, bottomSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); + + return TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{topSpinnerPanel, bottomSpinnerPanel}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W1, LayoutConstants.VGAP_SMALL); + } + private JPanel initHPaddingConfig() { + UILabel leftLabel = new UILabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Padding_Left")); + leftSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DesignerUtils.kDefaultHorizontalPadding); + + UILabel rightLabel = new UILabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Padding_Right")); + rightSpinner = new UISpinner(0, Integer.MAX_VALUE, 1, DesignerUtils.kDefaultHorizontalPadding); JPanel leftSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{leftLabel, leftSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); JPanel rightSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{rightLabel, rightSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); - JPanel topSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{topLabel, topSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); - JPanel bottomSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{bottomLabel, bottomSpinner}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_SMALL); - JPanel vPaddingSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{topSpinnerPanel, bottomSpinnerPanel}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W1, LayoutConstants.VGAP_SMALL); - JPanel hPaddingSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{leftSpinnerPanel, rightSpinnerPanel}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W1, LayoutConstants.VGAP_SMALL); + return TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{leftSpinnerPanel, rightSpinnerPanel}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W1, LayoutConstants.VGAP_SMALL); + } + + private void addPaddingPane() { + centerPane.add(DesignerUtils.createTitleSplitLine(Toolkit.i18nText("Fine-Plugin-RadioGroup_Layout"))); + + UILabel paddingHintLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Button_Padding")); + UILabel emptyHintLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("")); + + UILabel layoutTypeLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Layout_Type")); + initLayoutCombo(); + initButtonAlignPane(); + initColumnSizePane(); double p = TableLayout.PREFERRED; - double[] rowSize = {p, p}; + double[] rowSize = {p, p, p}; double[] columnSize = {p, p}; JPanel paddingPanel = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{ - {paddingHintLabel, vPaddingSpinnerPanel}, - {emptyHintLabel, hPaddingSpinnerPanel}, + {paddingHintLabel, initVPaddingConfig()}, + {emptyHintLabel, initHPaddingConfig()}, + {layoutTypeLabel, layoutTypeCombo}, }, rowSize, columnSize, 10); centerPane.add(paddingPanel); + centerPane.add(buttonAlignPane); + centerPane.add(columnSizePane); } - private void addIconPane() { + /** + * 初始化默认字体配置面版 + */ + private void initInitialIconConfigPane() { + initialIconConfigPane = new IconConfigPane(8, true); + initialIconConfigPane.addAddCountListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + initialIconConfigPane.addCount(); + selectedIconConfigPane.addCount(); + } + }); + initialIconConfigPane.addDeleteCountListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + initialIconConfigPane.deleteCount(); + selectedIconConfigPane.deleteCount(); + } + }); + } + /** + * 初始化选择字体配置面板 + */ + private void initSelectedIconConfigPane() { + selectedIconConfigPane = new IconConfigPane(8, true); + selectedIconConfigPane.addAddCountListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + initialIconConfigPane.addCount(); + selectedIconConfigPane.addCount(); + } + }); + selectedIconConfigPane.addDeleteCountListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + initialIconConfigPane.deleteCount(); + selectedIconConfigPane.deleteCount(); + } + }); + } + private void addIconPane() { centerPane.add(DesignerUtils.createTitleSplitLine(Toolkit.i18nText("Fine-Plugin-RadioGroup_Icon"))); UILabel initialLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Icon_Init")); UILabel selectedLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Icon_Select")); - - initialIconConfigPane = new IconConfigPane(8); - selectedIconConfigPane = new IconConfigPane(8); - + initialLabel.setVerticalAlignment(SwingConstants.TOP); + initialLabel.setBorder(new EmptyBorder(5, 0, 0, 0)); + selectedLabel.setVerticalAlignment(SwingConstants.TOP); + selectedLabel.setBorder(new EmptyBorder(5, 0, 0, 0)); + initInitialIconConfigPane(); + initSelectedIconConfigPane(); JPanel container = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 5); - JPanel initialPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); - initialPane.add(initialLabel); - initialPane.add(initialIconConfigPane); + JPanel initialPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + initialPane.add(initialLabel, BorderLayout.WEST); + initialPane.add(initialIconConfigPane, BorderLayout.CENTER); container.add(initialPane); - JPanel selectedPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); - selectedPane.add(selectedLabel); - selectedPane.add(selectedIconConfigPane); + JPanel selectedPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + selectedPane.add(selectedLabel, BorderLayout.WEST); + selectedPane.add(selectedIconConfigPane, BorderLayout.CENTER); container.add(selectedPane); centerPane.add(container); - } private void addFontPane() { @@ -183,7 +308,7 @@ public class ImageCustomDefinePane extends MobileStyleCustomDefinePane { UILabel initialFontLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Font_init")); initialFontConfPane = new FontConfigPane(); - initialFontConfPane.setFontColor(new Color(204, 204, 204)); + initialFontConfPane.setFontColor(new Color(102, 102, 102)); JPanel fontPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{initialFontLabel, initialFontConfPane}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_MEDIUM); centerPane.add(fontPanel); UILabel selectedFontLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Font_Select")); @@ -205,8 +330,11 @@ public class ImageCustomDefinePane extends MobileStyleCustomDefinePane { rightSpinner.setValue(mobileStyle.getRightPadding()); topSpinner.setValue(mobileStyle.getTopPadding()); bottomSpinner.setValue(mobileStyle.getBottomPadding()); - initialIconConfigPane.populate(new ArrayList<>(Arrays.asList(mobileStyle.getInitialIconNames()))); - selectedIconConfigPane.populate(new ArrayList<>(Arrays.asList(mobileStyle.getSelectedIconNames()))); + layoutTypeCombo.setSelectedIndex(mobileStyle.getButtonLayoutType()); + buttonAlignCombo.setSelectedIndex(mobileStyle.getButtonAlign()); + columnSizeSpinner.setValue(mobileStyle.getButtonColumnSize()); + initialIconConfigPane.refreshByIconNames(mobileStyle.getInitialIconNames(), true); + selectedIconConfigPane.refreshByIconNames(mobileStyle.getSelectedIconNames(), true); if(mobileStyle.getInitialFont() != null) { initialFontConfPane.populate(mobileStyle.getInitialFont()); } @@ -224,6 +352,9 @@ public class ImageCustomDefinePane extends MobileStyleCustomDefinePane { mobileStyle.setRightPadding(rightSpinner.getValue()); mobileStyle.setTopPadding(topSpinner.getValue()); mobileStyle.setBottomPadding(bottomSpinner.getValue()); + mobileStyle.setButtonLayoutType(layoutTypeCombo.getSelectedIndex()); + mobileStyle.setButtonAlign(buttonAlignCombo.getSelectedIndex()); + mobileStyle.setButtonColumnSize((int)columnSizeSpinner.getValue()); ArrayList initialIconNamesList = initialIconConfigPane.update(); ArrayList selectedIconNamesList = selectedIconConfigPane.update(); mobileStyle.setInitialIconNames(initialIconNamesList.toArray(new String[initialIconNamesList.size()])); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/UnitedCustomDefinePane.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/UnitedCustomDefinePane.java index 8d9b425740..0badf3498d 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/UnitedCustomDefinePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/ui/radiogroup/UnitedCustomDefinePane.java @@ -41,6 +41,7 @@ public class UnitedCustomDefinePane extends MobileStyleCustomDefinePane { private UISpinner topSpinner; private UISpinner bottomSpinner; + private UIComboBox buttonAlignCombo; private NewColorSelectBox initialColorSelectBox; private NewColorSelectBox selectedColorSelectBox; @@ -117,7 +118,7 @@ public class UnitedCustomDefinePane extends MobileStyleCustomDefinePane { private void addPaddingPane() { centerPane.add(DesignerUtils.createTitleSplitLine(Toolkit.i18nText("Fine-Plugin-RadioGroup_Layout"))); - + UILabel buttonAlignLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Alignment")); UILabel paddingHintLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("Fine-Plugin-RadioGroup_Button_Padding")); UILabel emptyHintLabel = DesignerUtils.createConfigLabel(Toolkit.i18nText("")); @@ -140,13 +141,20 @@ public class UnitedCustomDefinePane extends MobileStyleCustomDefinePane { JPanel vPaddingSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{topSpinnerPanel, bottomSpinnerPanel}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W1, LayoutConstants.VGAP_SMALL); JPanel hPaddingSpinnerPanel = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{new Component[]{leftSpinnerPanel, rightSpinnerPanel}}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_W1, LayoutConstants.VGAP_SMALL); - + // 按钮排布下拉框 + buttonAlignCombo = new UIComboBox(new String[]{ + Toolkit.i18nText("Fine-Plugin-RadioGroup_Alignment_Nature"), + Toolkit.i18nText("Fine-Plugin-RadioGroup_Alignment_Split") + }); + buttonAlignCombo.setSelectedIndex(1); + buttonAlignCombo.setPreferredSize(new Dimension(DesignerUtils.NORMAL_COMBO_WIDTH, 20)); double p = TableLayout.PREFERRED; - double[] rowSize = {p, p}; + double[] rowSize = {p, p, p}; double[] columnSize = {p, p}; JPanel paddingPanel = TableLayoutHelper.createCommonTableLayoutPane(new Component[][]{ {paddingHintLabel, vPaddingSpinnerPanel}, {emptyHintLabel, hPaddingSpinnerPanel}, + {buttonAlignLabel, buttonAlignCombo} }, rowSize, columnSize, 10); centerPane.add(paddingPanel); @@ -234,6 +242,7 @@ public class UnitedCustomDefinePane extends MobileStyleCustomDefinePane { rightSpinner.setValue(mobileStyle.getRightPadding()); topSpinner.setValue(mobileStyle.getTopPadding()); bottomSpinner.setValue(mobileStyle.getBottomPadding()); + buttonAlignCombo.setSelectedIndex(mobileStyle.getButtonAlign()); initialColorSelectBox.setSelectObject(mobileStyle.getInitialBackgroundColor()); selectedColorSelectBox.setSelectObject(mobileStyle.getSelectedBackgroundColor()); borderLineCombo.setSelectedLineStyle(mobileStyle.getBorderType()); @@ -256,6 +265,7 @@ public class UnitedCustomDefinePane extends MobileStyleCustomDefinePane { mobileStyle.setRightPadding(rightSpinner.getValue()); mobileStyle.setTopPadding(topSpinner.getValue()); mobileStyle.setBottomPadding(bottomSpinner.getValue()); + mobileStyle.setButtonAlign(buttonAlignCombo.getSelectedIndex()); mobileStyle.setInitialBackgroundColor(initialColorSelectBox.getSelectObject()); mobileStyle.setSelectedBackgroundColor(selectedColorSelectBox.getSelectObject()); mobileStyle.setBorderType(borderLineCombo.getSelectedLineStyle()); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/utils/DesignerUtils.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/utils/DesignerUtils.java index bcadac1c74..fae27d5e93 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/mobile/utils/DesignerUtils.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/utils/DesignerUtils.java @@ -4,6 +4,7 @@ import com.fr.design.constants.LayoutConstants; import com.fr.design.designer.IntervalConstants; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.DesignSizeI18nManager; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.widget.UITitleSplitLine; import com.fr.design.style.color.NewColorSelectBox; @@ -16,10 +17,19 @@ import java.awt.*; public class DesignerUtils { public static final int NORMAL_COMBO_WIDTH = 152; + + public static final int LARGE_COMBO_WIDTH = 174; public static final int kDefaultHorizontalPadding = 0; public static final int kDefaultVerticalPadding = 15; public static final int kAlignLeft = 0; public static final int kAlignCenter = 1; + + public static final int K_LAYOUT_SINGLE = 0; + public static final int K_LAYOUT_AUTO = 1; + public static final int K_LAYOUT_FIXED = 2; + + public static final int INITIAL_COLUMN_SIZE = 1; + public static final int[] BORDER_LINE_STYLE_ARRAY = new int[]{ Constants.LINE_NONE, Constants.LINE_THIN, @@ -35,7 +45,7 @@ public class DesignerUtils { public static UILabel createConfigLabel(String title) { UILabel label = new UILabel(title, UILabel.RIGHT); - label.setPreferredSize(new Dimension(100, 20)); + label.setPreferredSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.design.mainframe.mobile.utils.DesignerUtils.configLabel")); return label; } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/mobile/utils/MobileStyleProviderManager.java b/designer-base/src/main/java/com/fr/design/mainframe/mobile/utils/MobileStyleProviderManager.java index 7c3194ba61..96113e90af 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/mobile/utils/MobileStyleProviderManager.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/mobile/utils/MobileStyleProviderManager.java @@ -1,5 +1,8 @@ package com.fr.design.mainframe.mobile.utils; +import com.fr.design.mainframe.mobile.provider.checkboxgroup.CapsuleCheckboxGroupStyleProvider; +import com.fr.design.mainframe.mobile.provider.checkboxgroup.ImageCheckboxGroupStyleProvider; +import com.fr.design.mainframe.mobile.provider.checkboxgroup.UnitedCheckboxGroupStyleProvider; import com.fr.design.mainframe.mobile.provider.combo.SimpleComboCheckBoxStyleProvider; import com.fr.design.mainframe.mobile.provider.combo.SimpleComboStyleProvider; import com.fr.design.mainframe.mobile.provider.date.NavigationStyleProvider; @@ -26,6 +29,9 @@ public class MobileStyleProviderManager { add(new CapsuleRadioGroupStyleProvider()); add(new UnitedRadioGroupStyleProvider()); add(new ImageRadioGroupStyleProvider()); + add(new CapsuleCheckboxGroupStyleProvider()); + add(new UnitedCheckboxGroupStyleProvider()); + add(new ImageCheckboxGroupStyleProvider()); }}; private static Set mobileParamUIProviderSet = new HashSet() {{ add(new MobileTopParamStyleProvider()); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/FormThemeProfilePane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/FormThemeProfilePane.java index eb15a657f5..922230b158 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/FormThemeProfilePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/FormThemeProfilePane.java @@ -11,7 +11,11 @@ import com.fr.design.mainframe.theme.edit.ChartStyleFormEditPane; import com.fr.design.mainframe.theme.edit.ComponentStyleEditPane; import com.fr.design.mainframe.theme.edit.FormBodyStyleEditPane; import com.fr.design.mainframe.theme.preview.FormThemePreviewPane; +import com.fr.design.mainframe.theme.preview.ReportThemePreviewPane; import com.fr.design.mainframe.theme.processor.ThemePreviewPaneProcessor; +import com.fr.widgettheme.theme.panel.WidgetDisplayFormThemePreviewPane; +import com.fr.widgettheme.theme.panel.WidgetDisplayReportThemePreviewPane; +import com.fr.widgettheme.util.WidgetThemeDesignerUtils; import javax.swing.JPanel; @@ -38,7 +42,7 @@ public class FormThemeProfilePane extends TemplateThemeProfilePane { if (processor != null) { return processor.createFormThemePreviewPane(); } - return new FormThemePreviewPane(); + return WidgetThemeDesignerUtils.enableWidgetEnhance() ? new WidgetDisplayFormThemePreviewPane() : new FormThemePreviewPane(); } @Override diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/ReportThemeProfilePane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/ReportThemeProfilePane.java index 57e6ddf5f1..3f654cae5c 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/ReportThemeProfilePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/ReportThemeProfilePane.java @@ -7,6 +7,8 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.theme.edit.ReportBodyStyleEditPane; import com.fr.design.mainframe.theme.preview.ReportThemePreviewPane; import com.fr.design.mainframe.theme.processor.ThemePreviewPaneProcessor; +import com.fr.widgettheme.theme.panel.WidgetDisplayReportThemePreviewPane; +import com.fr.widgettheme.util.WidgetThemeDesignerUtils; /** * @author Starryi @@ -26,7 +28,7 @@ public class ReportThemeProfilePane extends TemplateThemeProfilePane extends JPanel { } private static class ThumbnailPane extends JPanel { - private static final Image LOADING_IMAGE = Toolkit.getDefaultToolkit().createImage(ThumbnailPane.class.getResource("/com/fr/design/images/mainframe/loading.gif")); + private static final String LOADING_IMAGE_URL = "/com/fr/design/images/mainframe/loading/loading.gif"; + private static final Image LOADING_IMAGE = I18nImage.getImage(LOADING_IMAGE_URL); private Image thumbnail = null; @Override diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeEditorPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeEditorPane.java index 4f4c5138d4..5432109dc0 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeEditorPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeEditorPane.java @@ -5,6 +5,8 @@ import com.fr.base.theme.TemplateTheme; import com.fr.base.theme.TemplateThemeConfig; import com.fr.base.theme.settings.ThemedCellStyleList; import com.fr.base.theme.settings.ThemedColorScheme; +import com.fr.widgettheme.ThemePreviewTerminal; +import com.fr.widgettheme.util.WidgetThemeDesignerUtils; import com.fr.design.ExtraDesignClassManager; import com.fr.design.beans.BasicBeanPane; import com.fr.design.designer.IntervalConstants; @@ -28,6 +30,8 @@ import com.fr.general.GeneralContext; import com.fr.plugin.observer.PluginEvent; import com.fr.plugin.observer.PluginEventListener; import com.fr.stable.StringUtils; +import com.fr.widgettheme.theme.edit.ParamContainerStyleEditPane; +import com.fr.widgettheme.theme.edit.widget.WidgetStyleEditContainerPane; import javax.swing.BorderFactory; import javax.swing.JComponent; @@ -202,6 +206,10 @@ public abstract class TemplateThemeEditorPane extends J protected void refreshExtraAdvancedPane() { extraPaneList.clear(); + if(WidgetThemeDesignerUtils.enableWidgetEnhance()) { + extraPaneList.add(new ParamContainerStyleEditPane<>()); + extraPaneList.add(new WidgetStyleEditContainerPane<>()); + } Set> providers = ExtraDesignClassManager.getInstance().getArray(TemplateThemePaneProvider.XML_TAG); for (TemplateThemePaneProvider provider : providers) { insertShortCut(provider.getInsertPosition(extraPaneList.size()), provider.getTab()); @@ -333,4 +341,20 @@ public abstract class TemplateThemeEditorPane extends J } } } + + /** + * 开启控件显示增强时,从配置面板处获取主题样式预览的终端类型 + * 默认为PC端,兼容原有场景 + */ + public ThemePreviewTerminal getWidgetStyleEditorTerminal() { + if (!WidgetThemeDesignerUtils.enableWidgetEnhance()) { + return ThemePreviewTerminal.PC; + } + for (BasicBeanPane pane : extraPaneList) { + if (pane instanceof WidgetStyleEditContainerPane) { + return ((WidgetStyleEditContainerPane) pane).getTerminalStyle(); + } + } + return ThemePreviewTerminal.PC; + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeProfilePane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeProfilePane.java index 92acb5c71e..c79ccd9090 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeProfilePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeProfilePane.java @@ -14,12 +14,13 @@ import com.fr.design.mainframe.theme.dialog.TemplateThemeProfileDialog; import com.fr.design.mainframe.theme.edit.ui.LabelUtils; import com.fr.design.mainframe.theme.ui.AutoCheckTextField; import com.fr.design.mainframe.theme.ui.AutoCheckThemeNameTextField; -import com.fr.design.mainframe.theme.ui.BorderUtils; import com.fr.design.mainframe.toast.DesignerToastMsgUtil; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.log.FineLoggerFactory; import com.fr.stable.StringUtils; import com.fr.transaction.CallBackAdaptor; +import com.fr.widgettheme.ThemePreviewTerminal; +import com.fr.widgettheme.theme.widget.theme.WidgetThemeDisplayConstants; import javax.swing.BorderFactory; import javax.swing.JDialog; @@ -51,7 +52,8 @@ public abstract class TemplateThemeProfilePane extends protected TemplateThemePreviewPane themePreviewPane; protected TemplateThemeEditorPane themeEditorPane; - + protected UILabel leftTitleLabel; + protected UILabel leftTitlePromptLabel; protected boolean isPopulating = false; protected boolean isMutable = false; @@ -83,10 +85,9 @@ public abstract class TemplateThemeProfilePane extends private JPanel createLeftPane() { JPanel titleContainer = FRGUIPaneFactory.createBorderLayout_S_Pane(); titleContainer.setPreferredSize(new Dimension(LEFT_TITLE_PANE_WIDTH, LEFT_TITLE_PANE_HEIGHT)); - titleContainer.setBorder(BorderUtils.createTitleBorder(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Preview_Pane_Title"), TITLE_BORDER_FONT)); - JPanel previewContainer = FRGUIPaneFactory.createBorderLayout_S_Pane(); previewContainer.setBorder(BorderFactory.createEmptyBorder(5, 4, 10, 4)); + titleContainer.add(createTitlePane(), BorderLayout.NORTH); titleContainer.add(previewContainer, BorderLayout.CENTER); themePreviewPane = createThemePreviewPane(); @@ -103,7 +104,10 @@ public abstract class TemplateThemeProfilePane extends if (isPopulating) { return; } - themePreviewPane.refresh(updateBean()); + ThemePreviewTerminal terminal = themeEditorPane.getWidgetStyleEditorTerminal(); + themePreviewPane.refresh(updateBean(), terminal); + String prompt = terminal == ThemePreviewTerminal.PC ? Toolkit.i18nText("Fine-Design_Theme_Control_PC_Prompt") : Toolkit.i18nText("Fine-Design_Theme_Control_Mobile_Prompt"); + leftTitlePromptLabel.setText(prompt); saveButton.setEnabled(themeEditorPane.checkNameValid() && isMutable); } }); @@ -367,4 +371,20 @@ public abstract class TemplateThemeProfilePane extends @Override public void onSaved(TemplateTheme theme) {} } + + /** + * 创建预览界面标题面板 + */ + protected JPanel createTitlePane() { + JPanel titlePane = new JPanel(); + titlePane.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); + titlePane.setLayout(new BorderLayout()); + leftTitleLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Preview_Pane_Title")); + leftTitlePromptLabel = new UILabel(Toolkit.i18nText("Fine-Design_Theme_Control_PC_Prompt")); + leftTitleLabel.setForeground(WidgetThemeDisplayConstants.THEME_PREVIEW_TITLE_COLOR); + leftTitlePromptLabel.setForeground(WidgetThemeDisplayConstants.COMPATIBLE_STYLE_FONT_COLOR); + titlePane.add(leftTitleLabel, BorderLayout.WEST); + titlePane.add(leftTitlePromptLabel, BorderLayout.EAST); + return titlePane; + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/AbstractChartStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/AbstractChartStylePane.java index e96bcd7bb5..801e7e0ab0 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/AbstractChartStylePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/AbstractChartStylePane.java @@ -29,11 +29,11 @@ public abstract class AbstractChartStylePane extends BasicPane { protected void initPane() { this.setLayout(FRGUIPaneFactory.createBorderLayout()); - double e1 = 75; - double e = 155; + double labelWidth = 90; + double totalWidth = 155; double p = TableLayout.PREFERRED; - double[] columnSize = {e1, e}; - JPanel gapTableLayoutPane = TableLayoutHelper.createGapTableLayoutPane(getComponent(), getRows(p), columnSize, 20, LayoutConstants.VGAP_LARGE); + double[] columnSize = {labelWidth, totalWidth}; + JPanel gapTableLayoutPane = TableLayoutHelper.createGapTableLayoutPane(getComponent(), getRows(p), columnSize, 5, LayoutConstants.VGAP_LARGE); gapTableLayoutPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); UIScrollPane rightTopPane = new UIScrollPane(gapTableLayoutPane); rightTopPane.setBorder(BorderFactory.createEmptyBorder()); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartFontPane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartFontPane.java index a70870a61b..fb1e3660b9 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartFontPane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartFontPane.java @@ -2,7 +2,6 @@ package com.fr.design.mainframe.theme.edit.chart; import com.fr.base.BaseUtils; import com.fr.base.FRContext; -import com.fr.base.Utils; import com.fr.design.constants.LayoutConstants; import com.fr.design.dialog.BasicPane; import com.fr.design.event.UIObserverListener; @@ -79,11 +78,11 @@ public class ChartFontPane extends BasicPane { } protected JPanel getContentPane(JPanel buttonPane) { - double e1 = 75; - double e = 155; + double labelWidth = 90; + double totalWidth = 155; double p = TableLayout.PREFERRED; double[] rows = {p, p, p}; - double[] columnSize = {e1, e}; + double[] columnSize = {labelWidth, totalWidth}; UILabel text = new UILabel(getUILabelText(), SwingConstants.LEFT); Component[][] components = { new Component[]{null, null}, @@ -91,7 +90,7 @@ public class ChartFontPane extends BasicPane { new Component[]{null, buttonPane} }; - return TableLayoutHelper.createGapTableLayoutPane(components, rows, columnSize, 20, LayoutConstants.VGAP_LARGE); + return TableLayoutHelper.createGapTableLayoutPane(components, rows, columnSize, 5, LayoutConstants.VGAP_LARGE); } public String getUILabelText() { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartTitleAndBackgroundStylePane.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartTitleAndBackgroundStylePane.java index 5705935866..2dc0659d00 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartTitleAndBackgroundStylePane.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/edit/chart/ChartTitleAndBackgroundStylePane.java @@ -83,10 +83,13 @@ public class ChartTitleAndBackgroundStylePane extends AbstractChartStylePane { } protected Component[][] getComponent() { + String chartAreaBgLabelName = Toolkit.i18nText("Fine-Design_Chart_Area_Background_Color"); + UILabel chartAreaBgLabel = new UILabel(chartAreaBgLabelName); + chartAreaBgLabel.setToolTipText(chartAreaBgLabelName); return new Component[][]{ new Component[]{chartFontPane, null}, new Component[]{null, null}, - new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Chart_Area_Background_Color")), typeComboBox}, + new Component[]{chartAreaBgLabel, typeComboBox}, new Component[]{null, centerPane}, new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Chart_Grid_Line_Color")), mainGridColor} }; diff --git a/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ThemePreviewed.java b/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ThemePreviewed.java index bb2aa05c22..272c7716c8 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ThemePreviewed.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/theme/preview/ThemePreviewed.java @@ -1,5 +1,7 @@ package com.fr.design.mainframe.theme.preview; +import com.fr.widgettheme.ThemePreviewTerminal; + /** * @author Starryi * @version 1.0 @@ -7,4 +9,14 @@ package com.fr.design.mainframe.theme.preview; */ public interface ThemePreviewed { void refresh(T style); + + /** + * 根据主题预览样式类型进行刷新 + * + * @param style 样式,可以包含多个终端展现效果 + * @param terminal 终端类型 + */ + default void refresh(T style, ThemePreviewTerminal terminal) { + refresh(style); + } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java index 99579aae3d..e074885439 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java @@ -42,6 +42,7 @@ import com.fr.design.actions.server.GlobalTableDataAction; import com.fr.design.actions.server.PlatformManagerAction; import com.fr.design.actions.server.PluginManagerAction; import com.fr.design.base.mode.DesignModeContext; +import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.NewTemplatePane; import com.fr.design.fun.MenuHandler; import com.fr.design.fun.OemProcessor; @@ -275,7 +276,10 @@ public abstract class ToolBarMenuDock { insertTemplateExtendMenu(plus, menuDefs); // 添加模板菜单 - menuList.addAll(Arrays.asList(menuDefs)); + // 如果是JNullTemplate不能添加模板菜单,之前没有这个JNullTemplate所以没考虑 + if (JTemplate.isValid(HistoryTemplateListCache.getInstance().getCurrentEditingTemplate())) { + menuList.addAll(Arrays.asList(menuDefs)); + } // 添加服务器菜单 if (WorkContext.getCurrent() != null && WorkContext.getCurrent().isRoot()) { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/RecycleAction.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/RecycleAction.java new file mode 100644 index 0000000000..acd89f668d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/RecycleAction.java @@ -0,0 +1,31 @@ +package com.fr.design.mainframe.vcs; + +import com.fr.design.actions.UpdateAction; +import com.fr.design.dialog.BasicDialog; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.vcs.ui.RecycleSettingPane; + +import java.awt.event.ActionEvent; + +/** + * 回收站 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/4 + */ +public class RecycleAction extends UpdateAction { + + public RecycleAction() { + this.setSmallIcon("/com/fr/design/standard/vcslist/vcs_recycle", false); + this.setName(Toolkit.i18nText("Fine-Design_Vcs_Recycle")); + } + + @Override + public void actionPerformed(ActionEvent e) { + RecycleSettingPane pane = new RecycleSettingPane(); + BasicDialog dialog = pane.showWindow(DesignerContext.getDesignerFrame(), false); + dialog.setVisible(true); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/TableEntity.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/TableEntity.java new file mode 100644 index 0000000000..a143025ce0 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/TableEntity.java @@ -0,0 +1,25 @@ +package com.fr.design.mainframe.vcs; + +/** + * 表格选中包装类 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/11 + */ +public interface TableEntity { + + /** + * 是否选中 + * + * @return + */ + boolean isSelect(); + + /** + * 设置选中属性 + * + * @param select + */ + void setSelect(boolean select); +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/TableValueOperator.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/TableValueOperator.java new file mode 100644 index 0000000000..3fcc57cd02 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/TableValueOperator.java @@ -0,0 +1,21 @@ +package com.fr.design.mainframe.vcs; + + +/** + * 表格操作 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/11 + */ +public interface TableValueOperator { + + /** + * 获取对应列的值 + * + * @param o 表格内容 + * @param columnIndex 列数 + * @return 对应列的值 + */ + Object getValue(T o, int columnIndex); +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsConfigManager.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsConfigManager.java index f61bba67a8..98a951a6a8 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsConfigManager.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsConfigManager.java @@ -16,6 +16,10 @@ public class VcsConfigManager implements XMLReadable, XMLWriter { private boolean useInterval = true; private int saveInterval = 60; + private boolean useAutoSave = false; + + private int autoSaveInterval = 15; + public static VcsConfigManager getInstance() { return instance; } @@ -48,6 +52,23 @@ public class VcsConfigManager implements XMLReadable, XMLWriter { return saveInterval; } + public int getAutoSaveInterval() { + return autoSaveInterval; + } + + public void setAutoSaveInterval(int autoSaveInterval) { + this.autoSaveInterval = autoSaveInterval; + } + + public boolean isUseAutoSave() { + return useAutoSave; + } + + public void setUseAutoSave(boolean useAutoSave) { + this.useAutoSave = useAutoSave; + } + + public void setSaveInterval(int saveInterval) { this.saveInterval = saveInterval; } @@ -59,6 +80,8 @@ public class VcsConfigManager implements XMLReadable, XMLWriter { this.setSaveInterval(reader.getAttrAsInt("saveInterval", 60)); this.setUseInterval(reader.getAttrAsBoolean("useInterval", true)); this.setVcsEnable(reader.getAttrAsBoolean("vcsEnable", true)); + this.setAutoSaveInterval(reader.getAttrAsInt("autoSaveInterval", 15)); + this.setUseAutoSave(reader.getAttrAsBoolean("useAutoSave", true)); } } @@ -69,6 +92,8 @@ public class VcsConfigManager implements XMLReadable, XMLWriter { writer.attr("saveInterval", this.getSaveInterval()); writer.attr("useInterval", this.isUseInterval()); writer.attr("vcsEnable", this.isVcsEnable()); + writer.attr("autoSaveInterval", this.getAutoSaveInterval()); + writer.attr("useAutoSave", this.isUseAutoSave()); writer.end(); } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsExceptionUtils.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsExceptionUtils.java new file mode 100644 index 0000000000..9ab310bbac --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsExceptionUtils.java @@ -0,0 +1,37 @@ +package com.fr.design.mainframe.vcs; + +import com.fr.design.i18n.Toolkit; + +import java.io.IOException; +import java.util.HashMap; + +/** + * 版本管理异常处理工具类 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/24 + */ +public class VcsExceptionUtils { + + public static final HashMap EXCEPTION_MAP = new HashMap() { + { + put(IOException.class, Toolkit.i18nText("Fine-Design_Vcs_Exception_IO")); + put(UnsupportedOperationException.class, Toolkit.i18nText("Fine-Design_Vcs_Exception_Un_Support")); + } + }; + + + /** + * 根据异常返回结果描述文案 + */ + public static String createDetailByException(Exception e) { + for (Class key : EXCEPTION_MAP.keySet()) { + if (key.isAssignableFrom(e.getClass())) { + return EXCEPTION_MAP.get(key); + } + } + return Toolkit.i18nText("Fine-Design_Vcs_Exception_Unknown"); + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsOperatorWorker.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsOperatorWorker.java new file mode 100644 index 0000000000..799abcf17c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsOperatorWorker.java @@ -0,0 +1,288 @@ +package com.fr.design.mainframe.vcs; + +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.vcs.ui.VcsBatchProcessDetailPane; +import com.fr.design.mainframe.vcs.ui.VcsProgressDialog; +import com.fr.log.FineLoggerFactory; +import com.fr.report.entity.VcsEntity; +import com.fr.stable.StringUtils; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.vcs.VcsOperator; +import com.fr.workspace.server.vcs.v2.VcsTaskResult; + +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; + +/** + * 为版本中心、回收站、版本详情提供带进度条与结算面板的操作的worker + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/18 + */ +public class VcsOperatorWorker { + private int count = 0; + + private static final int FREQ = 6; + + private String successStr; + + private String title; + + private String failedStr; + + private String everyFailedStr; + + private VcsProgressDialog dialog; + + + private static final String PREFIX = "(v."; + private static final String TAIL = ")"; + + public VcsOperatorWorker(String title, String dealingStr, String successStr, String failedStr, String everyFailedStr) { + this.title = title; + this.successStr = successStr; + this.failedStr = failedStr; + this.everyFailedStr = everyFailedStr; + dialog = new VcsProgressDialog(title, dealingStr); + } + + public VcsOperatorWorker(String everyFailedStr) { + this.title = StringUtils.EMPTY; + this.successStr = StringUtils.EMPTY; + this.failedStr = StringUtils.EMPTY; + this.everyFailedStr = everyFailedStr; + } + + /** + * 快速创建用于删除的worker + * + * @return + */ + public static VcsOperatorWorker createDeleteWorker() { + return new VcsOperatorWorker( + Toolkit.i18nText("Fine-Design_Vcs_Delete_Progress_Title"), + Toolkit.i18nText("Fine-Design_Vcs_Delete_Progress_Tips"), + Toolkit.i18nText("Fine-Design_Vcs_Delete_Progress_Success"), + "Fine-Design_Vcs_Delete_Progress_Failed", + Toolkit.i18nText("Fine-Design_Vcs_Delete_Every_Failed")); + } + + + /** + * 快速创建用于还原的worker + * + * @return + */ + public static VcsOperatorWorker createRestoreWorker() { + return new VcsOperatorWorker( + Toolkit.i18nText("Fine-Design_Vcs_Restore_Progress_Title"), + Toolkit.i18nText("Fine-Design_Vcs_Restore_Progress_Tips"), + Toolkit.i18nText("Fine-Design_Vcs_Restore_Progress_Success"), + "Fine-Design_Vcs_Restore_Progress_Failed", + Toolkit.i18nText("Fine-Design_Vcs_Restore_Every_Failed")); + } + + + /** + * 快速创建用于还原的worker + * + * @return + */ + public static VcsOperatorWorker createUpdateWorker() { + return new VcsOperatorWorker(Toolkit.i18nText("Fine-Design_Vcs_Update_Every_Failed")); + } + + + /** + * 批量还原 + * + * @param vcsEntities 需要还原的版本 + */ + public void batchRestore(List vcsEntities, VcsTableOperatorListener listener) { + VcsProcessFailedWrapper wrapper = new VcsProcessFailedWrapper(); + startProcess(vcsEntities, wrapper, (vcsEntity, operator) -> { + String fileName = vcsEntity.getFilename(); + VcsTaskResult result = operator.restoreVersion(fileName); + if (!result.isSuccess()) { + wrapper.addFailedEntity(vcsEntity); + } + return result; + }, listener); + } + + + /** + * 批量删除 + * + * @param vcsEntities 需要删除的版本 + * @param all 是否需要删除所有版本 + */ + public void batchDelete(List vcsEntities, boolean all, VcsTableOperatorListener listener) { + VcsProcessFailedWrapper wrapper = new VcsProcessFailedWrapper(); + startProcess(vcsEntities, wrapper, (vcsEntity, operator) -> { + String fileName = vcsEntity.getFilename(); + VcsTaskResult result; + if (all) { + result = operator.deleteVersionForRecycle(fileName); + } else { + result = operator.deleteVersion(fileName, vcsEntity.getVersion(), VcsEntity.CommitType.TYPE_DEFAULT); + } + if (!result.isSuccess()) { + wrapper.addFailedEntity(vcsEntity); + } + return result; + }, listener); + } + + + /** + * 删除指定模板的全部历史版本 + * + * @param entity VcsEntity + */ + public void doDelete(VcsEntity entity, VcsTableOperatorListener listener) { + String fileName = entity.getFilename(); + start4Single(entity, (vcsEntity, operator) -> operator.deleteVersionForRecycle(fileName), fileName + everyFailedStr, listener); + } + + /** + * 删除指定模板的指定版本 + * + * @param entity 版本 + */ + public void deleteTargetVersion(VcsEntity entity, VcsTableOperatorListener listener) { + String fileName = entity.getFilename(); + int version = entity.getVersion(); + VcsEntity.CommitType commitType = entity.getCommitType(); + start4Single(entity, (vcsEntity, operator) -> operator.deleteVersion(fileName, version, commitType), fileName + everyFailedStr, listener); + } + + + /** + * 更新版本 + * + * @param entity 版本 + */ + public void updateEntityAnnotation(VcsEntity entity, VcsTableOperatorListener listener) { + start4Single(entity, (vcsEntity, operator) -> { + operator.updateVersion(entity); + return new VcsTaskResult(true); + }, everyFailedStr, listener); + } + + private void startProcess(List vcsEntities, VcsProcessFailedWrapper wrapper, VcsWorkerOperator workerOperator, VcsTableOperatorListener listener) { + try { + dialog.getProgressBar().setMaximum(vcsEntities.size()); + start4Batch(vcsEntities, wrapper, workerOperator, listener); + dialog.showDialog(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + /** + * 控制更新频率 + * + * @return 是否需要更新进度 + */ + private boolean needPublish() { + return (count > FREQ && count % FREQ == 0) || count < FREQ; + } + + private void start4Single(VcsEntity entity, VcsWorkerOperator vcsWorkerOperator, String failedTip, VcsTableOperatorListener listener) { + new SwingWorker() { + @Override + protected void done() { + try { + if (!get()) { + FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(DesignerContext.getDesignerFrame()), failedTip); + } else { + listener.updateUI(); + } + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + @Override + protected Boolean doInBackground() throws Exception { + try { + VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class); + VcsTaskResult result = vcsWorkerOperator.process(entity, operator); + return result.isSuccess(); + } catch (Exception e) { + return false; + } + } + }.execute(); + } + + private void start4Batch(List vcsEntities, VcsProcessFailedWrapper wrapper, VcsWorkerOperator workerOperator, VcsTableOperatorListener listener) { + new SwingWorker() { + @Override + protected Boolean doInBackground() throws Exception { + VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class); + for (VcsEntity vcsEntity : vcsEntities) { + workerOperator.process(vcsEntity, operator); + count++; + if (needPublish()) { + publish(count); + } + } + return wrapper.isAllSuccess(); + } + @Override + protected void process(List chunks) { + dialog.getProgressBar().setValue(chunks.get(chunks.size() - 1)); + } + @Override + protected void done() { + dialog.closeDialog(); + try { + List failedList = wrapper.getDetailFailedList(); + showErrorDetailPane(get(), failedList, failedList.size(), vcsEntities.size() - failedList.size()); + listener.updateUI(wrapper); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + }.execute(); + } + + + private void showErrorDetailPane(boolean result, List failedList, int failed, int success) { + if (result) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), successStr); + } else { + VcsBatchProcessDetailPane pane = new VcsBatchProcessDetailPane( + DesignerContext.getDesignerFrame(), + title, + Toolkit.i18nText(failedStr, failed, success) + ); + for (String msg : failedList) { + pane.updateDetailArea(msg + everyFailedStr); + } + pane.show(); + } + } + + /** + * Vcs面板操作处理接口 + * + */ + private interface VcsWorkerOperator { + + /** + * 处理 + * + * @param vcsEntity 版本 + * @param operator 操作类 + */ + VcsTaskResult process(VcsEntity vcsEntity, VcsOperator operator) throws Exception; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsProcessFailedWrapper.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsProcessFailedWrapper.java new file mode 100644 index 0000000000..93d7d93479 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsProcessFailedWrapper.java @@ -0,0 +1,74 @@ +package com.fr.design.mainframe.vcs; + +import com.fr.report.entity.VcsEntity; +import com.fr.stable.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * 版本管理处理失败列表的包装类 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/28 + */ +public class VcsProcessFailedWrapper { + private static final String PREFIX = "(v."; + private static final String TAIL = ")"; + + private List failedList = new ArrayList<>(); + + + /** + * 添加处理失败的VcsEntity + * + * @param entity entity + */ + public void addFailedEntity(VcsEntity entity) { + failedList.add(entity); + } + + + /** + * 获取用于展示的详细失败信息列表 + */ + public List getDetailFailedList() { + List detailList = new ArrayList<>(); + for (VcsEntity entity : failedList) { + detailList.add(entity.getFilename()+PREFIX+entity.getVersion()+TAIL); + } + return detailList; + } + + /** + * 获取处理失败的vcsEntity的名称列表 + */ + public List getFailedNameList() { + List detailList = new ArrayList<>(); + for (VcsEntity entity : failedList) { + detailList.add(entity.getFilename()); + } + return detailList; + } + + /** + * 是否失败 + */ + public boolean isFalse(VcsTableEntity entity) { + for (VcsEntity vcsEntity : failedList) { + if (StringUtils.equals(vcsEntity.getFilename(), entity.getFilename()) + && vcsEntity.getVersion() == entity.getEntity().getVersion()) { + return true; + } + } + return false; + } + + /** + * 处理是否全部成功 + */ + public boolean isAllSuccess() { + return failedList.isEmpty(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsRecycleSettingHelper.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsRecycleSettingHelper.java new file mode 100644 index 0000000000..3e6a5bab96 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsRecycleSettingHelper.java @@ -0,0 +1,49 @@ +package com.fr.design.mainframe.vcs; + +import com.fr.concurrent.NamedThreadFactory; +import com.fr.transaction.Configurations; +import com.fr.transaction.WorkerAdaptor; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.vcs.VcsConfig; +import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanOperator; +import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoCleanService; +import com.fr.workspace.server.vcs.v2.scheduler.VcsAutoRecycleSchedule; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * 版本管理界面配置回收事件的处理类 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/21 + */ +public class VcsRecycleSettingHelper { + + private static ExecutorService executorService = Executors.newSingleThreadExecutor(new NamedThreadFactory("VcsRecycle")); + + + /** + * 更新任务 + * + * @param day + */ + public static void updateJob(int day) { + executorService.execute(new Runnable() { + @Override + public void run() { + Configurations.update(new WorkerAdaptor(VcsConfig.class) { + @Override + public void run() { + VcsConfig.getInstance().setV2CleanRecycleInterval(day); + } + }); + WorkContext.getCurrent().get(VcsAutoCleanOperator.class).addOrUpdateVcsAutoCleanJob( + VcsAutoCleanService.VCS_AUTO_CLEAN_RECYCLE_JOB_NAME, + 1, + VcsAutoRecycleSchedule.class); + } + }); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsTableEntity.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsTableEntity.java new file mode 100644 index 0000000000..0739bb16b2 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsTableEntity.java @@ -0,0 +1,113 @@ +package com.fr.design.mainframe.vcs; + +import com.fr.report.entity.VcsEntity; +import com.fr.stable.StringUtils; + +/** + * 包装VcsEntity的用于表格展示与处理的类 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/10 + */ +public class VcsTableEntity implements TableEntity{ + + private boolean select = false; + + private static final String MB = "MB"; + + private static final String VERSION = "V."; + private static final double MB_SIZE = 1024.0 * 1024; + private VcsEntity entity; + + + public VcsTableEntity(VcsEntity entity) { + this.entity = entity; + } + + /** + * 获取模板名 + * + * @return 模板名 + */ + public String getFilename() { + return entity.getFilename(); + } + + /** + * 获取版本大小 + * + * @return 版本大小 + */ + public String getSize() { + double size = entity.getSize()/MB_SIZE; + if (size == 0) { + return StringUtils.EMPTY; + } + return String.format("%.3f", size) + MB; + } + + /** + * 获取修改时间 + * + * @return 修改时间 + */ + public String getTime() { + return entity.getTime().toLocaleString(); + } + + /** + * 获取用户名 + * + * @return 用户名 + */ + public String getUserName() { + return entity.getUsername(); + } + + + /** + * 获取备注 + * + * @return 备注 + */ + public String getCommitMsg() { + return entity.getCommitMsg(); + } + + /** + * 获取版本号 + * + * @return 版本号 + */ + public String getVersion() { + return VERSION + entity.getVersion(); + } + + /** + * 获取删除时间 + * + * @return 删除时间 + */ + public String getDeleteTime() { + return entity.getDeleteTime().toLocaleString(); + } + + @Override + public boolean isSelect() { + return select; + } + + @Override + public void setSelect(boolean select) { + this.select = select; + } + + public VcsEntity getEntity() { + return entity; + } + + public void setEntity(VcsEntity entity) { + this.entity = entity; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsTableOperatorListener.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsTableOperatorListener.java new file mode 100644 index 0000000000..a6f19572ec --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/VcsTableOperatorListener.java @@ -0,0 +1,32 @@ +package com.fr.design.mainframe.vcs; + +import java.util.List; + +/** + * 版本管理表格操作事件 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/27 + */ +public interface VcsTableOperatorListener { + + + /** + * 处理操作 + */ + default void doOperator(List entityList){} + + /** + * 更新界面 + */ + default void updateUI(){} + + + /** + * 根据处理失败的内容来更新界面 + * + * @param wrapper 失败内容 + */ + default void updateUI(VcsProcessFailedWrapper wrapper){} +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsCloseTemplateHelper.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsCloseTemplateHelper.java new file mode 100644 index 0000000000..8f258b3e0d --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsCloseTemplateHelper.java @@ -0,0 +1,113 @@ +package com.fr.design.mainframe.vcs.common; + +import com.fr.base.vcs.DesignerMode; +import com.fr.design.dialog.BasicDialog; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.file.MultiTemplateTabPane; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.vcs.ui.VcsNewPane; +import com.fr.design.worker.save.CallbackSaveWorker; +import com.fr.general.ComparatorUtils; +import com.fr.log.FineLoggerFactory; + +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +/** + * 版本管理关闭模板辅助类 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/27 + */ +public class VcsCloseTemplateHelper { + + /** + * 根据传入的pane与dialog生成指定面板的Vcs模板关闭的处理方法 + * 如果指定模板已经打开: + *

    1.如果该模板已保存,则正常打开新版本管理弹窗 + *

    2.如果该模板未保存,触发保存逻辑 + *

  • a.如果用户选择保存,则保存并不关闭模板,弹出新版本管理弹窗 + *
  • b.如果用户选择不保存,则关闭当前模板,弹出新版本管理弹窗 + *
  • c.如果用户选择取消, 则啥操作都不做 + * + * @param path 对应模板路径 + * @param isCurrentEditing 是否是正在编辑的模板 + * @param parent 生成的新版本管理的详情面板的父面板 + */ + public static void checkTemplateSavedAndShowVcsNewPane(String path, boolean isCurrentEditing, BasicDialog parent, VcsNewPane pane) { + VcsNewPaneWrapper wrapper = new VcsNewPaneWrapper(path, parent, pane); + for (JTemplate jTemplate : HistoryTemplateListCache.getInstance().getHistoryList()) { + if (ComparatorUtils.equals(jTemplate.getEditingFILE().getPath(), path)) { + if (!jTemplate.isALLSaved()) { + MultiTemplateTabPane.getInstance().setIsCloseCurrent(isCurrentEditing); + MultiTemplateTabPane.getInstance().closeFormat(jTemplate); + confirmCloseAndShowVcsNewPane(jTemplate, wrapper); + return; + } + } + } + wrapper.show(); + } + + + /** + * 自己生成新的VcsNewPane的Vcs模板关闭的处理方法 + */ + public static void checkTemplateSavedAndShowVcsNewPane(String path, boolean isCurrentEditing) { + checkTemplateSavedAndShowVcsNewPane(path, isCurrentEditing, null, null); + } + + + /** + * 是否是当前编辑的模板 + * + * @param path 对应模板路径 + * @return 是则返回true + */ + public static boolean isCurrentEditing(String path) { + JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (JTemplate.isValid(jt)) { + String editing = jt.getEditingFILE().getPath(); + return ComparatorUtils.equals(editing, path); + } + return false; + } + + + + + private static void confirmCloseAndShowVcsNewPane(JTemplate specifiedTemplate, VcsNewPaneWrapper wrapper) { + if (specifiedTemplate == null) { + return; + } + if (!specifiedTemplate.isALLSaved() && !DesignerMode.isVcsMode()) { + specifiedTemplate.stopEditing(); + int returnVal = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), + String.format("%s\"%s\" ?",Toolkit.i18nText("Fine-Design_Basic_Utils_Would_You_Like_To_Save"), specifiedTemplate.getEditingFILE()), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + if (returnVal == JOptionPane.YES_OPTION) { + CallbackSaveWorker worker = specifiedTemplate.save(); + worker.addSuccessCallback(() -> { + FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_Already_Saved", specifiedTemplate.getEditingFILE().getName())); + SwingUtilities.invokeLater(wrapper::show); + }); + worker.start(specifiedTemplate.getRuntimeId()); + } else if (returnVal == JOptionPane.NO_OPTION) { + closeTpl(specifiedTemplate); + wrapper.show(); + } + } else { + wrapper.show(); + } + } + + private static void closeTpl(JTemplate specifiedTemplate) { + HistoryTemplateListCache.getInstance().closeSelectedReport(specifiedTemplate); + MultiTemplateTabPane.getInstance().closeAndFreeLock(specifiedTemplate); + MultiTemplateTabPane.getInstance().activePrevTemplateAfterClose(); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java index c72fa68dc4..15787348fe 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java @@ -2,6 +2,7 @@ package com.fr.design.mainframe.vcs.common; import com.fr.concurrent.NamedThreadFactory; +import com.fr.config.ConfigEvent; import com.fr.design.DesignerEnvManager; import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.TemplateTreePane; @@ -12,14 +13,22 @@ import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.JTemplateActionListener; import com.fr.design.mainframe.vcs.VcsConfigManager; import com.fr.design.mainframe.vcs.ui.FileVersionTable; +import com.fr.event.Event; +import com.fr.event.EventDispatcher; +import com.fr.event.Listener; +import com.fr.event.ListenerAdaptor; import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; import com.fr.plugin.context.PluginContext; import com.fr.plugin.manage.PluginManager; import com.fr.report.entity.VcsEntity; +import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; import com.fr.stable.project.ProjectConstants; import com.fr.workspace.WorkContext; +import com.fr.workspace.Workspace; +import com.fr.workspace.WorkspaceEvent; +import com.fr.workspace.server.vcs.VcsFileUtils; import com.fr.workspace.server.vcs.VcsOperator; import com.fr.workspace.server.vcs.filesystem.VcsFileSystem; import com.fr.workspace.server.vcs.git.config.GcConfig; @@ -31,6 +40,8 @@ import java.awt.Color; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; /** * Created by XiaXiang on 2019/4/17. @@ -54,12 +65,90 @@ public class VcsHelper implements JTemplateActionListener { private final static String VCS_PLUGIN_ID = "com.fr.plugin.vcs.v10"; private final static String VCS_FILE_SLASH = "/"; private final static String SERVICE_NAME_MOVE = "moveVcs"; + private static final String VCS_VERSIONS = "reportlets_versions"; + private static final String VERSION_MARK = ".v"; private static final VcsHelper INSTANCE = new VcsHelper(); + private static ScheduledExecutorService saveSchedule; + + private volatile boolean legacyMode; + + private volatile boolean root; + public static VcsHelper getInstance() { return INSTANCE; } + private VcsHelper() { + VcsOperator op = WorkContext.getCurrent().get(VcsOperator.class); + // 开了设计器启动页面时一开始取不到VcsOperator,通过下面的切换环境事件再取,这边判断下 + if (op != null) { + try { + legacyMode = op.isLegacyMode(); + root = WorkContext.getCurrent().isLocal() || WorkContext.getCurrent().isRoot(); + } catch (Exception e) { + legacyMode = true; + root = false; + FineLoggerFactory.getLogger().error("[VcsHelper] init first failed ", e.getMessage()); + } + } + EventDispatcher.listen(ConfigEvent.READY, new ListenerAdaptor() { + @Override + protected void on(Event event) { + try { + legacyMode = WorkContext.getCurrent().get(VcsOperator.class).isLegacyMode(); + FineLoggerFactory.getLogger().info("[VcsHelper] legacyMode:{}", legacyMode); + } catch (Exception e) { + //保险起见走老逻辑 + legacyMode = true; + FineLoggerFactory.getLogger().error("[VcsHelper] get legacy failed", e.getMessage()); + } + } + }); + EventDispatcher.listen(WorkspaceEvent.AfterSwitch, new Listener() { + @Override + public void on(Event event, Workspace param) { + try { + root = WorkContext.getCurrent().isLocal() || WorkContext.getCurrent().isRoot() ; + } catch (Exception e) { + root = false; + FineLoggerFactory.getLogger().error("[VcsHelper] get root failed", e.getMessage()); + } + + } + }); + } + + /** + * 开始自动保存任务 + * + * @param interval 时间间隔 + */ + public void startAutoSave(int interval) { + stopAutoSave(); + saveSchedule = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("VcsAutoSaveSchedule")); + saveSchedule.scheduleWithFixedDelay(new Runnable() { + @Override + public void run() { + FineLoggerFactory.getLogger().info("[VcsV2] start to run auto save schedule"); + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (DesignerEnvManager.getEnvManager().getVcsConfigManager().isVcsEnable() && JTemplate.isValid(template)) { + fireAutoSaveVcs(template); + } + } + }, interval, interval, TimeUnit.MINUTES); + } + + /** + * 停止任务 + */ + public void stopAutoSave() { + if (saveSchedule != null && !saveSchedule.isShutdown()) { + saveSchedule.shutdown(); + } + } + + private int containsFolderCounts() { TemplateFileTree fileTree = TemplateTreePane.getInstance().getTemplateFileTree(); if (fileTree.getSelectionPaths() == null) { @@ -94,20 +183,12 @@ public class VcsHelper implements JTemplateActionListener { } private String getEditingFilename() { - String vcsCacheDir = VcsFileSystem.getInstance().getVcsCacheRelativePath(); JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); String editingFilePath = jt.getEditingFILE().getPath(); - if (editingFilePath.startsWith(ProjectConstants.REPORTLETS_NAME)) { - editingFilePath = editingFilePath.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY); - } else if (editingFilePath.startsWith(vcsCacheDir)) { - editingFilePath = editingFilePath.replaceFirst(vcsCacheDir, StringUtils.EMPTY); - } - if (editingFilePath.startsWith(VCS_FILE_SLASH)) { - editingFilePath = editingFilePath.substring(1); - } - return editingFilePath; + return VcsFileUtils.dealWithFilePath(editingFilePath); } + private boolean needDeleteVersion(VcsEntity entity) { VcsConfigManager configManager = DesignerEnvManager.getEnvManager().getVcsConfigManager(); if (entity == null || !configManager.isUseInterval()) { @@ -134,7 +215,6 @@ public class VcsHelper implements JTemplateActionListener { fireVcs.execute(new Runnable() { @Override public void run() { - String fileName = getEditingFilename(); VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class); VcsEntity entity = operator.getFileVersionByIndex(fileName, 0); @@ -157,7 +237,9 @@ public class VcsHelper implements JTemplateActionListener { } }); - fireVcs.shutdown(); + if (!fireVcs.isShutdown()) { + fireVcs.shutdown(); + } } /** @@ -173,13 +255,17 @@ public class VcsHelper implements JTemplateActionListener { VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class); String oldPath = oldName.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY); List oldVcsEntities = operator.getVersions(oldPath); - + String replaceName = newName.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY); for (VcsEntity oldVcsEntity : oldVcsEntities) { - operator.saveVersion(oldVcsEntity.getUsername(), newName.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY), oldVcsEntity.getCommitMsg(), oldVcsEntity.getVersion()); - operator.deleteVersion(oldPath, oldVcsEntity.getVersion()); + if (!VcsHelper.getInstance().isLegacyMode()) { + operator.renameVersion(oldVcsEntity, replaceName); + } else { + operator.saveVersion(oldVcsEntity.getUsername(), replaceName, oldVcsEntity.getCommitMsg(), oldVcsEntity.getVersion()); + operator.deleteVersion(oldPath, oldVcsEntity.getVersion()); + } } - FineLoggerFactory.getLogger().debug("moveVcs success. from {} to {}", oldName, newName); - if (GcConfig.getInstance().isGcEnable()) { + FineLoggerFactory.getLogger().debug("moveVcs success. from {} to {}", oldName, replaceName); + if (GcConfig.getInstance().isGcEnable() && VcsHelper.getInstance().isLegacyMode()) { operator.gc(); } } @@ -187,12 +273,85 @@ public class VcsHelper implements JTemplateActionListener { moveVcs.shutdown(); } + /** + * 判断是否为老模式 + * @return 是否为老模式 + */ + public boolean isLegacyMode() { + return legacyMode; + } + + /** + * 更新当前的legacyMode状态 + *
  • 目前用在迁移结束后更新模式为新模式
  • + * + */ + public void updateLegacyMode() { + this.legacyMode = !legacyMode; + } @Override public void templateOpened(JTemplate jt) { + try { + if (checkAutoSaveSupport()) { + startAutoSave(VcsConfigManager.getInstance().getAutoSaveInterval()); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } } + /** + * 响应版本管理自动保存 + * + *
  • 直接用template的file来保存的话相当于拿源文件来保存模板,这样用户做的改动会丢失
  • + *
  • 因此需要自己实现一下自动保存的逻辑,将当前模板的数据导出,再拿这个Byte[]去做我们需要的保存处理
  • + *
  • 保存后需要触发清理逻辑
  • + * + * @param jt 模板 + */ + public void fireAutoSaveVcs(final JTemplate jt) { + String fileName = getEditingFilename(); + VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class); + VcsEntity entity = operator.getFileVersionByIndex(fileName, 0); + boolean replace = needDeleteVersion(entity); + int latestFileVersion = 0; + if (entity != null) { + latestFileVersion = entity.getVersion(); + } + if (JTemplate.isValid(jt)) { + doSave(jt, fileName, latestFileVersion, replace, operator); + } + } + + private void doSave(JTemplate jt, String fileName, int latestFileVersion, boolean replace, VcsOperator operator) { + if (jt.getEditingFILE() instanceof VcsCacheFileNodeFile) { + operator.saveVersionFromCache(getCurrentUsername(), fileName, StringUtils.EMPTY, latestFileVersion + 1, replace); + String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); + List updatedList = WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY)); + SwingUtilities.invokeLater(() -> FileVersionTable.getInstance().updateModel(1, updatedList)); + } else { + autoSave(jt, getCurrentUsername(), fileName, latestFileVersion + 1, replace, operator); + } + if (GcConfig.getInstance().isGcEnable()) { + operator.gc(); + } + } + + private void autoSave(JTemplate jt, String currentUsername, String fileName, int nowVersion, boolean replace, VcsOperator operator) { + try { + if (JTemplate.isValid(jt) && !jt.isALLSaved()) { + operator.autoSave(currentUsername, fileName, StringUtils.EMPTY, nowVersion, jt.exportData(), replace); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + } + + + + /** * 模板保存时 处理. * @@ -202,13 +361,58 @@ public class VcsHelper implements JTemplateActionListener { public void templateSaved(JTemplate jt) { if (needInit() && DesignerEnvManager.getEnvManager().getVcsConfigManager().isVcsEnable() - && !WorkContext.getCurrent().isCluster()) { + // 如果是集群,在新版本下才生效 + && (!WorkContext.getCurrent().isCluster() || !VcsHelper.getInstance().isLegacyMode())) { fireVcs(jt); } } @Override public void templateClosed(JTemplate jt) { + try { + if (checkAutoSaveSupport()) { + stopAutoSave(); + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage()); + } + + } + + /** + * 判断是否支持V2功能 + * + * @return 支持返回true + */ + public boolean checkV2FunctionSupport() { + return !VcsHelper.getInstance().isLegacyMode() && root; + } + + /** + * 判断是否支持迁移功能 + * + * @return 支持返回true + */ + public boolean checkMoveFunctionSupport() { + return WorkContext.getCurrent().isLocal() || WorkContext.getCurrent().isRoot(); + } + /** + * 是否支持自动保存 + * + * @return 支持返回true + */ + public boolean checkAutoSaveSupport() { + return VcsConfigManager.getInstance().isUseAutoSave() && !VcsHelper.getInstance().isLegacyMode(); + } + + /** + * 获取文件路径 + * + * @param entity + * @return + */ + public String getFilePath(VcsEntity entity) { + return StableUtils.pathJoin(VCS_VERSIONS, entity.getFilename() + VERSION_MARK + entity.getVersion()); } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsNewPaneWrapper.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsNewPaneWrapper.java new file mode 100644 index 0000000000..179b7c9400 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsNewPaneWrapper.java @@ -0,0 +1,36 @@ +package com.fr.design.mainframe.vcs.common; + +import com.fr.design.dialog.BasicDialog; +import com.fr.design.mainframe.vcs.ui.VcsNewPane; + +/** + * 构建VcsNewPane的包装类 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/27 + */ +public class VcsNewPaneWrapper { + + private String path; + private BasicDialog dialog; + private VcsNewPane pane; + + public VcsNewPaneWrapper(String path, BasicDialog dialog, VcsNewPane pane) { + this.path = path; + this.dialog = dialog; + this.pane = pane; + } + + /** + * 显示面板 + */ + public void show() { + if (pane != null) { + pane.showDialog(dialog); + } else { + VcsNewPane newPane = new VcsNewPane(path); + newPane.showDialog(dialog); + } + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/AbstractSupportSelectTablePane.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/AbstractSupportSelectTablePane.java new file mode 100644 index 0000000000..75733121de --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/AbstractSupportSelectTablePane.java @@ -0,0 +1,407 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.base.svg.IconUtils; +import com.fr.design.data.tabledata.tabledatapane.loading.TipsPane; +import com.fr.design.dialog.BasicPane; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itableeditorpane.UITableEditAction; +import com.fr.design.gui.itableeditorpane.UITableEditorPane; +import com.fr.design.gui.itableeditorpane.UITableModelAdapter; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.vcs.TableEntity; +import com.fr.design.mainframe.vcs.TableValueOperator; +import com.fr.stable.StringUtils; + +import javax.swing.BorderFactory; +import javax.swing.DefaultCellEditor; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.RowSorter; +import javax.swing.SwingConstants; +import javax.swing.SwingWorker; +import javax.swing.UIManager; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.UIResource; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableRowSorter; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; +import java.util.concurrent.ExecutionException; + + +/** + * 比较通用的带全选功能的表格面板 + * + *

    整体划分为north与center两个面板(参考BorderLayout的布局),center部分用于置放表格,表格部分支持全选,north部分支持自定义,用于展示各种标签按钮输入框

    + *

    获取数据的时候不需要用SwingWorker(内部已经实现),考虑到大部分表格内容的展现需要去获取数据,而获取数据大部分都需要一定时间,因此为了防止UI冻结,在加载数据结束之前先展示进度条面板

    + *

    使用该面板你可能需要:

    + *
  • 自己封装一个实现TableEntity接口(该接口用于提供(选中/全选)功能),内部存放你要放入表格的类,例如VcsEntity,参考VcsTableEntity
  • + *
  • 初始化的时候赋予变量model值(如果有需要的话),该变量用于控制表格的数据类型,默认DefaultModel——分为5列,第一列为勾选框
  • + *
  • (一定要干的)初始化的时候赋予变量model内operators值,用于确认表格每一列getValueAt返回的值
  • + *
  • 上面板也允许自定义,重写initTableTopPane即可
  • + *
  • 要使用该面板可以参考:RecyclePane
  • + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/11 + */ +public abstract class AbstractSupportSelectTablePane extends BasicPane { + + public static final Color DEFAULT_HEADER_COLOR = new Color(232, 232, 233); + public static final Color DEFAULT_SELECT_TABLE_ROW_COLOR = new ColorUIResource(200, 221, 233); + private CardLayout layout; + + + protected JPanel contentPane; + + protected UITextField searchTextField = new UITextField();; + + protected UILabel deleteLabel = new UILabel(); + + /** + * 整体面板的center部分,用来放表格 + */ + protected UITableEditorPane tableContentPane; + + protected UITableModelAdapter model; + /** + * 整体面板的north部分 + */ + protected JPanel tableTopPane = new JPanel(); + /** + * 整体面板 + */ + protected JPanel tablePane = new JPanel(); + + private int selectCount = 0; + private static final String LOADING = "loading"; + private static final String TABLE ="table"; + + protected List entities; + + protected TableValueOperator operator; + + + public AbstractSupportSelectTablePane(String title, TableValueOperator operators, String[] tableNames, boolean needBorder) { + this.operator = operators; + this.model = new DefaultModel(tableNames, new Class[]{ + Boolean.class, + UILabel.class, + UILabel.class, + UILabel.class, + UILabel.class + + }); + init(title, needBorder); + } + + public AbstractSupportSelectTablePane(String title, TableValueOperator operators, boolean needBorder) { + this.operator = operators; + init(title, needBorder); + } + + /** + * 初始化 + * + */ + private void init(String title, boolean needBorder) { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + contentPane = new JPanel(); + layout = new CardLayout(); + contentPane.setLayout(layout); + contentPane.add(new TipsPane(true), LOADING); + this.add(contentPane); + new SwingWorker, Void>(){ + @Override + protected List doInBackground() { + return getTableList(); + } + @Override + protected void done() { + try { + entities = get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + contentPane.add(createTablePane(title, needBorder), TABLE); + layout.show(contentPane, TABLE); + } + }.execute(); + } + + /** + * 获取表格数据 + * + * @return 表格数据 + */ + abstract protected List getTableList(); + + private JPanel createTablePane(String title, boolean needBorder) { + tablePane = needBorder ? FRGUIPaneFactory.createTopVerticalTitledBorderPane(title) : new JPanel(); + if (isNeedTopPane()) { + initTableTopPane(); + initTopPaneListener(); + } + initTableContentPane(entities); + tablePane.setLayout(new BorderLayout()); + tablePane.add(tableTopPane, BorderLayout.NORTH); + tablePane.add(tableContentPane, BorderLayout.CENTER); + tableContentPane.getEditTable().getColumnModel().getColumn(0).setMaxWidth(50); + RowSorter> sorter = new TableRowSorter>(model) { + @Override + public boolean isSortable(int column) { + return column != 0; + } + }; + tableContentPane.getEditTable().setRowSorter(sorter); + return tablePane; + } + + /** + * 初始化表格面板 + * + * @param entities 表格数据 + */ + protected void initTableContentPane(List entities) { + tableContentPane = new UITableEditorPane<>(model); + model.setList(entities); + JTable table = tableContentPane.getEditTable(); + table.getTableHeader().setBackground(DEFAULT_HEADER_COLOR); + table.getTableHeader().setDefaultRenderer(new HeaderRenderer(tableContentPane.getEditTable())); + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + int row = ((JTable) e.getSource()).rowAtPoint(e.getPoint()); + int col = ((JTable) e.getSource()).columnAtPoint(e.getPoint()); + if (col == 0) { + T entity = model.getConvertRowSelectedValue(row); + //改变面板的各个状态 + changeComponentStatus(entity, row, col, table); + } + } + }); + initExtraListener4Table(table); + } + + /** + * 设定额外的表格事件 + * + * @param table 表格 + */ + protected void initExtraListener4Table(JTable table) { + //do nothing + } + + /** + * 是否需要上面板 + * + * @return + */ + protected boolean isNeedTopPane() { + return true; + } + + private void changeComponentStatus(T entity, int row, int col, JTable table) { + boolean select = entity.isSelect(); + entity.setSelect(!select); + table.setValueAt(entity.isSelect(), row, col); + if (select) { + selectCount--; + } else { + selectCount++; + } + //更新表头的勾选框状态 + HeaderRenderer renderer = (HeaderRenderer) table.getTableHeader().getDefaultRenderer(); + renderer.refreshHeader(table, selectCount >= table.getRowCount()); + changeExtraComponentStatus(); + } + + /** + * 更新额外组件的状态 + */ + protected void changeExtraComponentStatus() { + } + + public int getSelectCount() { + return selectCount; + } + + + /** + * 初始化上面板 + */ + abstract protected void initTableTopPane(); + + /** + * 初始化上面板事件 + */ + abstract protected void initTopPaneListener(); + + + /** + * 表头渲染 + */ + public class HeaderRenderer implements TableCellRenderer { + JTableHeader tableHeader; + final UICheckBox selectBox; + + public HeaderRenderer(JTable table) { + this.tableHeader = table.getTableHeader(); + tableHeader.setCursor(new Cursor(Cursor.HAND_CURSOR)); + selectBox = new UICheckBox(); + selectBox.setSelected(false); + tableHeader.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() > 0) { + //获得选中列 + int selectColumn = tableHeader.columnAtPoint(e.getPoint()); + if (selectColumn == 0) { + boolean value = !selectBox.isSelected(); + selectBox.setSelected(value); + selectAllOrNull(value); + selectCount = value ? table.getRowCount() : 0; + changeExtraComponentStatus(); + tableHeader.repaint(); + model.fireTableDataChanged(); + } + } + } + + private void selectAllOrNull(boolean value) { + int len = table.getRowCount(); + for (T entity : model.getList()) { + entity.setSelect(value); + } + } + }); + } + + /** + * 刷新表头 + * + * @param table + */ + public void refreshHeader(JTable table, boolean value) { + selectBox.setSelected(value); + int rowHeight = table.getRowHeight(); + table.updateUI(); + table.setRowHeight(rowHeight); + } + + @Override + public Component getTableCellRendererComponent(JTable table, + Object value, + boolean isSelected, + boolean hasFocus, + int row, int column) { + tableHeader = table.getTableHeader(); + tableHeader.setReorderingAllowed(false); + String valueStr = (String) value; + UILabel label = new UILabel(valueStr); + if (needIcon4Head(column)) { + label.setIcon(IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_sort")); + label.setHorizontalTextPosition(JLabel.LEFT); + label.setHorizontalAlignment(SwingConstants.LEFT); + } + selectBox.setHorizontalAlignment(SwingConstants.CENTER); + selectBox.setBorderPainted(true); + JComponent component = (column == 0) ? selectBox : label; + component.setForeground(tableHeader.getForeground()); + component.setBackground(tableHeader.getBackground()); + component.setFont(tableHeader.getFont()); + component.setBorder(UIManager.getBorder("TableHeader.cellBorder")); + return component; + } + + + } + + @Override + protected String title4PopupWindow() { + return StringUtils.EMPTY; + } + + /** + * 默认的数据model + */ + public class DefaultModel extends UITableModelAdapter { + + public DefaultModel(String[] tableNames, Class[] classes) { + super(tableNames); + setColumnClass(classes); + this.setDefaultEditor(Boolean.class, new BooleanEditor()); + this.setDefaultRenderer(Boolean.class, new BooleanRenderer()); + this.setDefaultRenderer(UILabel.class, new ToolTipTableCellRenderer()); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + T vcsEntity = this.getList().get(rowIndex); + return operator.getValue(vcsEntity, columnIndex); + } + + @Override + public boolean isCellEditable(int row, int col) { + return col == 0; + } + + + @Override + public UITableEditAction[] createAction() { + return new UITableEditAction[0]; + } + + + } + + /** + * 用于展示指定风格的checkbox的Editor + */ + public class BooleanEditor extends DefaultCellEditor { + public BooleanEditor() { + super(new UICheckBox()); + UICheckBox checkBox = (UICheckBox) getComponent(); + checkBox.setHorizontalAlignment(UICheckBox.CENTER); + } + } + + /** + * 用于展示指定风格的checkbox的渲染器 + */ + public class BooleanRenderer extends UICheckBox implements TableCellRenderer, UIResource { + public BooleanRenderer() { + super(); + setHorizontalAlignment(JLabel.CENTER); + setBorderPainted(true); + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column) { + setSelected((Boolean) table.getValueAt(row, 0)); + setUI(getUICheckBoxUI()); + setBorder(BorderFactory.createEmptyBorder()); + setBackground(isSelected ? DEFAULT_SELECT_TABLE_ROW_COLOR : Color.WHITE); + return this; + } + } + + + /** + * 表头的某列是否需要icon + * + * @param col 列 + * @return + */ + protected boolean needIcon4Head(int col) { + return col != 0; + } +} + diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/EditFileVersionDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/EditFileVersionDialog.java index 105a9b872a..2224bb1aec 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/EditFileVersionDialog.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/EditFileVersionDialog.java @@ -5,6 +5,7 @@ import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.itextarea.UITextArea; +import com.fr.design.i18n.Toolkit; import com.fr.design.layout.TableLayoutHelper; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerFrameFileDealerPane; @@ -55,13 +56,17 @@ public class EditFileVersionDialog extends UIDialog { private void initComponents() { JPanel fontPane = new JPanel(new BorderLayout()); - fontPane.add(new UILabel(" " + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Vcs_Version_Message") + ":"), BorderLayout.NORTH); + UILabel fontLabel = new UILabel(" " + Toolkit.i18nText("Fine-Design_Vcs_Version_Message") + ":"); + fontLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_Version_Message")); + fontPane.add(fontLabel, BorderLayout.NORTH); msgTestArea.setBorder(null); UIScrollPane scrollPane = new UIScrollPane(msgTestArea); + UILabel versionTip = new UILabel(" " + Toolkit.i18nText("Fine-Design_Vcs_Version_Number") + ":"); + versionTip.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_Version_Number")); Component[][] components = new Component[][]{ - new Component[]{new UILabel(" " + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Vcs_Version_Number") + ":"), versionLabel}, + new Component[]{versionTip, versionLabel}, new Component[]{fontPane, scrollPane} }; double[] rowSizes = new double[]{25, 100}; @@ -81,12 +86,7 @@ public class EditFileVersionDialog extends UIDialog { ok.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - entity.setCommitMsg(msgTestArea.getText()); - WorkContext.getCurrent().get(VcsOperator.class).updateVersion(entity); - setVisible(false); - String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); - FileVersionTable table = FileVersionTable.getInstance(); - table.updateModel(table.getSelectedRow(), WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst("/", StringUtils.EMPTY))); + doOK(); } }); @@ -101,4 +101,23 @@ public class EditFileVersionDialog extends UIDialog { public void checkValid() throws Exception { } + + /** + * 确定事件 + * + */ + public void doOK() { + entity.setCommitMsg(msgTestArea.getText()); + WorkContext.getCurrent().get(VcsOperator.class).updateVersion(entity); + setVisible(false); + String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath(); + FileVersionTable table = FileVersionTable.getInstance(); + table.updateModel(table.getSelectedRow(), WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst("/", StringUtils.EMPTY))); + } + + public UITextArea getMsgTestArea() { + return msgTestArea; + } + + } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/RecyclePane.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/RecyclePane.java new file mode 100644 index 0000000000..1aacaa9d7b --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/RecyclePane.java @@ -0,0 +1,406 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.base.svg.IconUtils; +import com.fr.design.dialog.BasicDialog; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itextfield.UITextField; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.vcs.VcsOperatorWorker; +import com.fr.design.mainframe.vcs.TableEntity; +import com.fr.design.mainframe.vcs.TableValueOperator; +import com.fr.design.mainframe.vcs.VcsProcessFailedWrapper; +import com.fr.design.mainframe.vcs.VcsTableEntity; +import com.fr.design.mainframe.vcs.VcsTableOperatorListener; +import com.fr.report.entity.VcsEntity; +import com.fr.stable.StringUtils; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.vcs.VcsOperator; + +import javax.swing.Icon; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.fr.design.i18n.Toolkit.i18nText; + +/** + * 回收面板 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/5 + */ +public class RecyclePane extends AbstractSupportSelectTablePane { + public static final Icon ICON_SEARCH = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_recycle_search"); + public static final Icon ICON_REFRESH = IconUtils.readSVGIcon("/com/fr/design/standard/vcslist/vcs_recycle_restore", IconUtils.ICON_TYPE_NORMAL); + public static final Icon ICON_REFRESH_DISABLE = IconUtils.readSVGIcon("/com/fr/design/standard/vcslist/vcs_recycle_restore", IconUtils.ICON_TYPE_DISABLED); + public static final Icon ICON_DELETE = IconUtils.readSVGIcon("/com/fr/design/standard/vcslist/vcs_recycle_delete", IconUtils.ICON_TYPE_NORMAL); + public static final Icon ICON_DELETE_DISABLE = IconUtils.readSVGIcon("/com/fr/design/standard/vcslist/vcs_recycle_delete", IconUtils.ICON_TYPE_DISABLED); + + private Set listenerSet = new HashSet<>(); + + protected UITextField searchTextField; + + protected UILabel deleteLabel; + + protected UILabel restoreLabel; + + private static final int COLUMNS_COUNT = 15; + private BasicDialog dialog; + + private BasicDialog parentDialog; + private List tableEntities; + + public RecyclePane() { + super(i18nText("Fine-Design_Vcs_Recycle"), (o, columnIndex) -> { + switch (columnIndex) { + case 0: + return o.isSelect(); + case 1: + return o.getFilename(); + case 2: + return o.getSize(); + case 3: + return o.getDeleteTime(); + case 4: + return o.getTime(); + default: + return o; + + } + }, new String[]{ + StringUtils.EMPTY, + Toolkit.i18nText("Fine-Design_Vcs_Template"), + Toolkit.i18nText("Fine-Design_Vcs_Recycle_Size"), + Toolkit.i18nText("Fine-Design_Vcs_Delete_Time"), + Toolkit.i18nText("Fine-Design_Vcs_Time") + }, false); + } + + public RecyclePane(String title, TableValueOperator operators, boolean needBorder) { + super(title, operators, needBorder); + } + + + @Override + protected List getTableList() { + List entityList = WorkContext.getCurrent().get(VcsOperator.class).getRecycleEntities(); + List tableEntities = new ArrayList<>(); + for (VcsEntity entity : entityList) { + tableEntities.add(new VcsTableEntity(entity)); + } + updateTableList(tableEntities); + return tableEntities; + } + + + @Override + protected void initTableTopPane() { + tableTopPane = new JPanel(); + tableTopPane.setLayout(new BorderLayout()); + JPanel leftPane = new JPanel(); + JPanel rightPane = new JPanel(); + //左边面板,包含搜索icon+搜索框 + if (isNeedSearch()) { + searchTextField = new UITextField(); + searchTextField.setPlaceholder(Toolkit.i18nText("Fine-Design_Vcs_Start_Search")); + searchTextField.setColumns(COLUMNS_COUNT); + leftPane.add(new UILabel(ICON_SEARCH)); + leftPane.add(searchTextField); + } + //右边面板,包括还原按钮+删除按钮 + if (isNeedRestore()) { + restoreLabel = new UILabel(ICON_REFRESH); + restoreLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); + restoreLabel.setDisabledIcon(ICON_REFRESH_DISABLE); + restoreLabel.setEnabled(false); + rightPane.add(restoreLabel); + } + if (isNeedDelete()) { + deleteLabel = new UILabel(ICON_DELETE); + deleteLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); + deleteLabel.setDisabledIcon(ICON_DELETE_DISABLE); + deleteLabel.setEnabled(false); + rightPane.add(deleteLabel); + } + tableTopPane.add(leftPane, BorderLayout.EAST); + tableTopPane.add(rightPane, BorderLayout.WEST); + } + + + @Override + protected void changeExtraComponentStatus() { + boolean canUseLabel = getSelectCount() > 0; + if (restoreLabel != null) { + restoreLabel.setEnabled(canUseLabel); + } + if (deleteLabel != null) { + deleteLabel.setEnabled(canUseLabel); + } + } + + @Override + protected void initTopPaneListener() { + initSearchTextFiledListener(); + initRestoreListener(); + initDeleteLabelListener(); + } + + private void initDeleteLabelListener() { + if (isNeedDelete()) { + deleteLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Delete")); + deleteLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + fireListener(new VcsResponseListener() { + @Override + public void doAfterChooseYes(List selectList) { + VcsOperatorWorker.createDeleteWorker(). batchDelete(selectList, isNeedDeleteAllVersion(), new VcsTableOperatorListener() { + @Override + public void updateUI(VcsProcessFailedWrapper wrapper) { + updateVcsUI(wrapper); + } + }); + } + }, true); + } + }); + } + } + + private void initRestoreListener() { + if (isNeedRestore()) { + restoreLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Restore")); + restoreLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + fireListener(new VcsResponseListener() { + @Override + public void doAfterChooseYes(List selectList) { + VcsOperatorWorker.createRestoreWorker().batchRestore(selectList, new VcsTableOperatorListener() { + @Override + public void updateUI(VcsProcessFailedWrapper wrapper) { + updateVcsUI(wrapper); + } + }); + } + }, false); + } + }); + } + } + + private void initSearchTextFiledListener() { + if (isNeedSearch()) { + searchTextField.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + String str = searchTextField.getText(); + model.setList(tableEntities.stream().filter(entity -> entity.getEntity().getFilename().contains(str)).collect(Collectors.toList())); + model.fireTableDataChanged(); + } + }); + } + + } + + + private void fireListener(VcsResponseListener listener, boolean isDelete) { + List selectList = model.getList().stream().filter(TableEntity::isSelect).map(VcsTableEntity::getEntity).collect(Collectors.toList()); + if (selectList.size() > 0) { + int selVal = FineJOptionPane.showConfirmDialog( + RecyclePane.this, + isDelete ? getDeleteTip(selectList.size()) : getRestoreTip(selectList.size()), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE); + if (selVal == JOptionPane.YES_OPTION) { + listener.doAfterChooseYes(selectList); + } + } + } + + private void updateVcsUI(VcsProcessFailedWrapper wrapper) { + tableEntities = model.getList().stream().filter(tableEntity -> !tableEntity.isSelect() || wrapper.isFalse(tableEntity)).collect(Collectors.toList()); + model.setList(new ArrayList<>(tableEntities)); + model.fireTableDataChanged(); + fireVcsListener(model.getList()); + } + + /** + * 显示弹窗 + * + */ + public void showDialog() { + dialog = this.showWindow(DesignerContext.getDesignerFrame(), false); + dialog.setVisible(true); + } + + /** + * 依据父弹窗显示弹窗 + * + * @param parent 父弹窗 + */ + public void showDialog(BasicDialog parent) { + this.parentDialog = parent; + dialog = this.showWindow(parent, false); + initDialogListener(dialog); + dialog.setVisible(true); + } + + protected void initDialogListener(BasicDialog dialog) { + } + + /** + * 关闭弹窗,如果有父弹窗,则一起关闭,如果有属性配置的弹窗面板要保存再关闭 + * + */ + public void saveSettingAndCloseDialog() { + if (dialog != null) { + dialog.doOK(); + dialog.dispose(); + } + if (parentDialog != null) { + parentDialog.doOK(); + parentDialog.dispose(); + } + } + + public BasicDialog getDialog() { + return dialog; + } + + public void setDialog(BasicDialog dialog) { + this.dialog = dialog; + } + + public BasicDialog getParentDialog() { + return parentDialog; + } + + public void setParentDialog(BasicDialog parentDialog) { + this.parentDialog = parentDialog; + } + + + /** + * 添加版本管理表格操作事件 + * + * @param listener 版本管理表格操作事件 + */ + public void addVcsListener(VcsTableOperatorListener listener) { + listenerSet.add(listener); + } + + /** + * 触发版本管理表格操作事件 + */ + public void fireVcsListener(List tableEntities) { + for (VcsTableOperatorListener listener : listenerSet) { + listener.doOperator(tableEntities); + } + } + + /** + * 删除范围 + * + * @return 默认删除全部版本 + */ + protected boolean isNeedDeleteAllVersion() { + return true; + } + + @Override + protected String title4PopupWindow() { + return i18nText("Fine-Design_Vcs_Recycle"); + } + + /** + * 删除提示 + * + * @return 默认需要 + */ + protected String getDeleteTip(int size) { + return Toolkit.i18nText("Fine-Design_Vcs_Delete_Select_All_Version_Forever", size); + } + + /** + * 还原提示 + * + * @return 默认需要 + */ + protected String getRestoreTip(int size) { + return Toolkit.i18nText("Fine-Design_Vcs_Restore_Select_All_Version", size); + } + + /** + * 是否需要还原功能 + * + * @return 默认需要 + */ + protected boolean isNeedRestore() { + return true; + } + + /** + * 是否需要搜索功能 + * + * @return 默认需要 + */ + protected boolean isNeedSearch() { + return true; + } + + /** + * 是否需要删除功能 + * + * @return 默认需要 + */ + protected boolean isNeedDelete() { + return true; + } + + + /** + * 更新数据列表 + * + * @param entities + */ + public void updateTableList(List entities) { + tableEntities = new ArrayList<>(entities); + } + + /** + * 移除指定元素 + * + * @param entity + */ + public void removeTarget(VcsTableEntity entity) { + tableEntities.remove(entity); + } + + /** + * 版本管理按钮事件响应 + */ + public interface VcsResponseListener { + + /** + * 选择确认之后要做的事情 + * + * @param selectList 所选上的内容 + */ + void doAfterChooseYes(List selectList); + + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/RecycleSettingPane.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/RecycleSettingPane.java new file mode 100644 index 0000000000..0653aad05f --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/RecycleSettingPane.java @@ -0,0 +1,103 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.design.dialog.BasicPane; +import com.fr.design.gui.frpane.UITabbedPane; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.ispinner.UISpinner; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.VerticalFlowLayout; +import com.fr.design.mainframe.vcs.VcsRecycleSettingHelper; +import com.fr.workspace.server.vcs.VcsConfig; + +import javax.swing.JPanel; +import javax.swing.ScrollPaneConstants; +import javax.swing.border.EmptyBorder; + +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + + +/** + * 回收站配置面板 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/21 + */ +public class RecycleSettingPane extends BasicPane { + + private static final int MIN_VALUE = 1; + + private static final int MAX_VALUE = 999; + + private static final int STEP = 1; + + private static final int DEFAULT_VALUE = 30; + + private UISpinner spinner; + + private UIButton button; + + public RecycleSettingPane() { + init(); + } + + private void init() { + + this.setLayout(new BorderLayout()); + UITabbedPane tabbedPane = new UITabbedPane(); + //回收站内容 + JPanel recyclePane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); + UIScrollPane recycleScrollPane = patchScroll(recyclePane); + tabbedPane.addTab(Toolkit.i18nText("Fine-Design_Vcs_Recycle_Content"), recycleScrollPane); + recyclePane.add(new RecyclePane()); + //通用设置 + JPanel settingPane = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); + UIScrollPane settingScrollPane = patchScroll(settingPane); + tabbedPane.addTab(Toolkit.i18nText("Fine-Design_Basic_Carton_General_Settings"), settingScrollPane); + settingPane.add(createSchedulePane()); + this.add(tabbedPane, BorderLayout.CENTER); + } + + private JPanel createSchedulePane() { + JPanel schedulePane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.TOP, 0, 0); + JPanel spinnerPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0(); + JPanel buttonPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0(); + spinnerPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Recycle_Schedule"))); + spinner = new UISpinner(MIN_VALUE, MAX_VALUE, STEP, DEFAULT_VALUE); + spinner.setValue(VcsConfig.getInstance().getV2CleanRecycleInterval()); + spinnerPane.add(spinner); + spinnerPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Recycle_Schedule_Day"))); + schedulePane.add(spinnerPane); + button = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Save")); + initButtonListener(); + buttonPane.add(button); + schedulePane.add(buttonPane); + return schedulePane; + } + + private void initButtonListener() { + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + VcsRecycleSettingHelper.updateJob((int) spinner.getValue()); + } + }); + } + + + private UIScrollPane patchScroll(JPanel generalPane) { + UIScrollPane generalPanelWithScroll = new UIScrollPane(generalPane, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + generalPanelWithScroll.setBorder(new EmptyBorder(0, 0, 0, 0)); + return generalPanelWithScroll; + } + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Vcs_Recycle"); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/ToolTipTableCellRenderer.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/ToolTipTableCellRenderer.java new file mode 100644 index 0000000000..bfb10e2057 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/ToolTipTableCellRenderer.java @@ -0,0 +1,32 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.general.GeneralUtils; +import com.fr.stable.StringUtils; + +import javax.swing.JTable; +import javax.swing.JLabel; +import javax.swing.table.DefaultTableCellRenderer; +import java.awt.*; + + +/** + * 带ToolTip的UILabel的表格渲染类 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/21 + */ +public class ToolTipTableCellRenderer extends DefaultTableCellRenderer { + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if(component instanceof JLabel) { + String toolTipText = GeneralUtils.objectToString(value); + if (StringUtils.isNotEmpty(toolTipText)) { + ((JLabel) component).setToolTipText(toolTipText); + } + } + return component; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/UIPositiveIntEditor.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/UIPositiveIntEditor.java new file mode 100644 index 0000000000..797d8bd1ef --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/UIPositiveIntEditor.java @@ -0,0 +1,59 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.design.editor.editor.IntegerEditor; +import com.fr.design.gui.itextfield.UIIntNumberField; +import com.fr.design.gui.itextfield.UINumberField; +import com.fr.stable.StringUtils; + + +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; + +/** + * 正整数输入框 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/25 + */ +public class UIPositiveIntEditor extends IntegerEditor { + private static final int DEFAULT_COLUMNS = 4; + + private static final int MIN = 1; + private static final int MAX = 99999; + + private static final int DEFAULT_VALUE = 60; + + public UIPositiveIntEditor(Integer value) { + super(value); + numberField.setMaxValue(MAX); + numberField.setMinValue(MIN); + initNumberFieldListener(); + } + + public UIPositiveIntEditor(Integer value, Integer min, Integer max) { + super(value); + numberField.setMaxValue(max); + numberField.setMinValue(min); + initNumberFieldListener(); + } + + private void initNumberFieldListener() { + numberField.addFocusListener(new FocusAdapter() { + @Override + public void focusLost(FocusEvent e) { + if (StringUtils.isEmpty(numberField.getTextValue())) { + numberField.setValue(DEFAULT_VALUE); + } + } + }); + } + + + @Override + protected UINumberField createNumberField() { + UIIntNumberField field = new UIIntNumberField(); + field.setColumns(DEFAULT_COLUMNS); + return field; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/UIPositiveIntSpinner.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/UIPositiveIntSpinner.java new file mode 100644 index 0000000000..3753cf817c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/UIPositiveIntSpinner.java @@ -0,0 +1,39 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.design.gui.ispinner.UISpinner; +import com.fr.design.gui.itextfield.UIIntNumberField; +import com.fr.design.gui.itextfield.UINumberField; + +/** + * 只允许输入正整数的Spinner + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/25 + */ +public class UIPositiveIntSpinner extends UISpinner { + private static final int DEFAULT_COLUMNS = 5; + + + public UIPositiveIntSpinner() { + } + + public UIPositiveIntSpinner(double minValue, double maxValue, double dierta) { + super(minValue, maxValue, dierta); + } + + public UIPositiveIntSpinner(double minValue, double maxValue, double dierta, double defaultValue) { + super(minValue, maxValue, dierta, defaultValue); + } + + public UIPositiveIntSpinner(double minValue, double maxValue, double dierta, double defaultValue, boolean fillNegativeNumber) { + super(minValue, maxValue, dierta, defaultValue, fillNegativeNumber); + } + + @Override + protected UINumberField initNumberField() { + UIIntNumberField field = new UIIntNumberField(); + field.setColumns(DEFAULT_COLUMNS); + return field; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsBatchProcessDetailPane.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsBatchProcessDetailPane.java new file mode 100644 index 0000000000..4421b7f301 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsBatchProcessDetailPane.java @@ -0,0 +1,156 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * 处理结果详细面板 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/19 + */ +public class VcsBatchProcessDetailPane { + + private UILabel message = new UILabel(); + private UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Report_OK")); + private UILabel uiLabel = new UILabel(); + private UILabel directUiLabel = new UILabel(); + private UILabel detailLabel = new UILabel(); + + private JPanel upPane; + private JPanel midPane; + private JPanel downPane; + private JPanel hiddenPanel; + private JTextArea jta; + private JDialog dialog; + + public static final Dimension DEFAULT = new Dimension(380, 150); + public static final Dimension DEFAULT_PRO = new Dimension(380, 270); + + public VcsBatchProcessDetailPane(Frame parent, String title, String msg) { + init(parent, title, msg); + } + + private void init(Frame parent, String title, String msg) { + message.setBorder(BorderFactory.createEmptyBorder(8, 5, 0, 0)); + message.setText(msg); + dialog = new JDialog(parent, title, true); + dialog.setSize(DEFAULT); + JPanel jp = new JPanel(); + initUpPane(); + initDownPane(); + initMidPane(); + initHiddenPanel(); + initListener(); + jp.setLayout(new BoxLayout(jp, BoxLayout.Y_AXIS)); + jp.add(upPane); + jp.add(midPane); + jp.add(hiddenPanel); + jp.add(downPane); + hiddenPanel.setVisible(false); + dialog.add(jp); + dialog.setResizable(false); + dialog.setLocationRelativeTo(SwingUtilities.getWindowAncestor(parent)); + } + + private void initDownPane() { + downPane = new JPanel(); + downPane.setLayout(new FlowLayout(FlowLayout.RIGHT, 15, 9)); + downPane.add(cancelButton); + } + + private void initUpPane() { + upPane = new JPanel(); + uiLabel = new UILabel(UIManager.getIcon("OptionPane.errorIcon")); + upPane.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 10)); + upPane.add(uiLabel); + upPane.add(message); + } + + private void initMidPane() { + midPane = new JPanel(); + midPane.add(directUiLabel); + midPane.add(detailLabel); + midPane.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0)); + detailLabel.setText(Toolkit.i18nText("Fine_Designer_Look_Detail")); + detailLabel.setForeground(Color.BLUE); + detailLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + directUiLabel.setIcon(UIManager.getIcon("OptionPane.narrow.right")); + } + + private void initHiddenPanel() { + hiddenPanel = new JPanel(); + hiddenPanel.setLayout(new BorderLayout(2, 0)); + hiddenPanel.add(new JPanel(), BorderLayout.WEST); + hiddenPanel.add(new JPanel(), BorderLayout.EAST); + JPanel borderPanel = new JPanel(); + borderPanel.setLayout(new BorderLayout()); + jta = new JTextArea(); + JScrollPane jsp = new JScrollPane(jta); + jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + jta.setEditable(false); + borderPanel.add(jsp, BorderLayout.CENTER); + hiddenPanel.add(borderPanel); + } + + /** + * 补充更详细的报错信息 + * + * @param message 信息 + */ + public void updateDetailArea(String message) { + jta.append(message + "\n"); + } + + private void initListener() { + detailLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (hiddenPanel.isVisible()) { + hiddenPanel.setVisible(false); + dialog.setSize(DEFAULT); + detailLabel.setText(Toolkit.i18nText("Fine_Designer_Look_Detail")); + directUiLabel.setIcon(UIManager.getIcon("OptionPane.narrow.right")); + } else { + dialog.setSize(DEFAULT_PRO); + hiddenPanel.setVisible(true); + detailLabel.setText(Toolkit.i18nText("Fine_Designer_Hide_Detail")); + directUiLabel.setIcon(UIManager.getIcon("OptionPane.narrow.down")); + } + } + + }); + cancelButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + hiddenPanel.removeAll(); + dialog.dispose(); + } + }); + } + + + /** + * 显示面板 + */ + public void show() { + dialog.setVisible(true); + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCellEditor.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCellEditor.java new file mode 100644 index 0000000000..9baebaebe1 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCellEditor.java @@ -0,0 +1,35 @@ +package com.fr.design.mainframe.vcs.ui; + +import javax.swing.AbstractCellEditor; +import javax.swing.JTable; +import javax.swing.table.TableCellEditor; +import java.awt.*; + +import static com.fr.design.mainframe.vcs.ui.AbstractSupportSelectTablePane.DEFAULT_SELECT_TABLE_ROW_COLOR; + +/** + * Vcs的表格Editor + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/20 + */ +public class VcsCellEditor extends AbstractCellEditor implements TableCellEditor { + + private final VcsOperatorPane vcsPanel; + + public VcsCellEditor(VcsOperatorPane vcsPanel) { + this.vcsPanel = vcsPanel; + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { + vcsPanel.setBackground(isSelected ? DEFAULT_SELECT_TABLE_ROW_COLOR : Color.WHITE); + return vcsPanel; + } + + @Override + public Object getCellEditorValue() { + return vcsPanel; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCellRender.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCellRender.java new file mode 100644 index 0000000000..952c52a060 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCellRender.java @@ -0,0 +1,29 @@ +package com.fr.design.mainframe.vcs.ui; + +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; +import java.awt.*; + +import static com.fr.design.mainframe.vcs.ui.AbstractSupportSelectTablePane.DEFAULT_SELECT_TABLE_ROW_COLOR; + +/** + * Vcs的表格Render + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/20 + */ +public class VcsCellRender implements TableCellRenderer { + + private final VcsOperatorPane vcsPanel; + + public VcsCellRender(VcsOperatorPane vcsPanel) { + this.vcsPanel = vcsPanel; + } + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + vcsPanel.setBackground(isSelected ? DEFAULT_SELECT_TABLE_ROW_COLOR : Color.WHITE); + return vcsPanel; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCenterPane.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCenterPane.java new file mode 100644 index 0000000000..b97de53991 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsCenterPane.java @@ -0,0 +1,268 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.base.svg.IconUtils; +import com.fr.design.dialog.BasicDialog; +import com.fr.design.dialog.DialogActionAdapter; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.file.TemplateTreePane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.lock.LockInfoUtils; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.vcs.VcsOperatorWorker; + +import com.fr.design.mainframe.vcs.VcsTableEntity; +import com.fr.design.mainframe.vcs.VcsTableOperatorListener; +import com.fr.design.mainframe.vcs.common.VcsCloseTemplateHelper; +import com.fr.file.FileNodeFILE; +import com.fr.file.filetree.FileNode; +import com.fr.report.entity.VcsEntity; +import com.fr.report.lock.LockInfoOperator; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.project.ProjectConstants; +import com.fr.workspace.WorkContext; +import com.fr.workspace.server.vcs.VcsOperator; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JOptionPane; +import javax.swing.JTable; +import javax.swing.SwingWorker; +import javax.swing.UIManager; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; + + +/** + * 版本中心面板 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/13 + */ +public class VcsCenterPane extends VcsNewPane { + + private UILabel manager; + private UILabel open; + private UILabel delete; + + private static final Icon MANAGER_ICON = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_center_manager"); + private static final Icon DELETE_ICON = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_operator_delete"); + private static final Icon OPEN_ICON = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_center_open"); + private static final Class[] CLASSES = new Class[]{ + Boolean.class, + UILabel.class, + UILabel.class, + UILabel.class, + VcsOperatorPane.class + }; + + private static final int OPERATOR_COL = 4; + private static final String[] COLUMN_NAMES = new String[]{ + StringUtils.EMPTY, + Toolkit.i18nText("Fine-Design_Vcs_Template"), + Toolkit.i18nText("Fine-Design_Vcs_Time"), + Toolkit.i18nText("Fine-Design_Vcs_Size"), + Toolkit.i18nText("Fine-Design_Vcs_Operator") + }; + + private static final String TITLE = Toolkit.i18nText("Fine-Design_Vcs_Center"); + + public VcsCenterPane() { + super(TITLE, (o, columnIndex) -> { + switch (columnIndex) { + case 0: + return o.isSelect(); + case 1: + return o.getFilename(); + case 2: + return o.getTime(); + case 3: + return o.getSize(); + default: + return o; + } + }, false, COLUMN_NAMES, CLASSES, OPERATOR_COL); + } + + @Override + public VcsOperatorPane createOperatorPane() { + manager = new UILabel(MANAGER_ICON); + manager.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Manager")); + open = new UILabel(OPEN_ICON); + open.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Open")); + delete = new UILabel(DELETE_ICON); + delete.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Delete")); + initManagerListener(); + initOpenListener(); + initDeleteListener(); + List components = new ArrayList<>(); + components.add(manager); + components.add(open); + components.add(delete); + return new VcsOperatorPane(components); + } + + private void initDeleteListener() { + delete.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + JTable table = tableContentPane.getEditTable(); + int row = table.getEditingRow(); + Object o = table.getValueAt(row, table.getEditingColumn()); + if (o instanceof VcsTableEntity) { + VcsEntity entity = ((VcsTableEntity) o).getEntity(); + String fileName = entity.getFilename(); + int selVal = FineJOptionPane.showConfirmDialog( + VcsCenterPane.this, + Toolkit.i18nText("Fine-Design_Vcs_Center_Delete", fileName), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE); + if (selVal == JOptionPane.YES_OPTION) { + VcsOperatorWorker.createDeleteWorker().doDelete(entity, new VcsTableOperatorListener() { + @Override + public void updateUI() { + removeTarget((VcsTableEntity) o); + model.fireTableRowsDeleted(row, row); + model.removeRow(row); + model.fireTableDataChanged(); + } + }); + } + } + } + }); + } + + + @Override + protected boolean needIcon4Head(int col) { + return col != 0 && col != OPERATOR_COL; + } + + private void initOpenListener() { + open.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + JTable table = tableContentPane.getEditTable(); + Object o = table.getValueAt(table.getEditingRow(), table.getEditingColumn()); + if (o instanceof VcsTableEntity) { + VcsEntity entity = ((VcsTableEntity) o).getEntity(); + saveSettingAndCloseDialog(); + showTemplate(entity.getFilename(), new FileNode(getTemplateTruePath(entity.getFilename()), false)); + } + } + }); + } + + private void showTemplate(String filename, FileNode node) { + new SwingWorker() { + @Override + protected Boolean doInBackground() throws Exception { + String selectedFilePath = getTemplateTruePath(filename); + String lock = node.getLock(); + return TemplateTreePane.needShowLockInfo(lock, selectedFilePath, node); + } + @Override + protected void done() { + try { + if (!get()) { + DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(node)); + } else { + FineJOptionPane.showMessageDialog(VcsCenterPane.this, Toolkit.i18nText("Fine-Design_Vcs_Open_Lock_Tip"), UIManager.getString("OptionPane.messageDialogTitle"), JOptionPane.ERROR_MESSAGE); + } + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + }.execute(); + } + + private void initManagerListener() { + manager.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + JTable table = tableContentPane.getEditTable(); + Object o = table.getValueAt(table.getEditingRow(), table.getEditingColumn()); + if (o instanceof VcsTableEntity) { + VcsEntity entity = ((VcsTableEntity) o).getEntity(); + String path = getTemplateTruePath(entity.getFilename()); + VcsNewPane pane = new VcsNewPane(path) { + @Override + protected String title4PopupWindow() { + return entity.getFilename()+Toolkit.i18nText("Fine-Design_Vcs_Version_Tips"); + } + }; + pane.addVcsListener(new VcsTableOperatorListener() { + @Override + public void doOperator(List entityList) { + if (entities.size() == 0) { + model.getList().remove(o); + model.fireTableDataChanged(); + } + } + }); + VcsCloseTemplateHelper.checkTemplateSavedAndShowVcsNewPane(path, VcsCloseTemplateHelper.isCurrentEditing(path), getDialog(), pane); + } + } + }); + } + + @Override + protected List getTableList() { + List entities = WorkContext.getCurrent().get(VcsOperator.class).getEveryVersion(); + List tableEntities = new ArrayList<>(); + for (VcsEntity entity : entities) { + tableEntities.add(new VcsTableEntity(entity)); + } + updateTableList(tableEntities); + return tableEntities; + } + + @Override + protected void initDialogListener(BasicDialog dialog) { + dialog.addDialogActionListener(new DialogActionAdapter() { + @Override + public void doOk() { + BasicDialog parent = getParentDialog(); + parent.doOK(); + parent.dispose(); + } + }); + } + + @Override + protected String title4PopupWindow() { + return TITLE; + } + + @Override + protected String getDeleteTip(int size) { + return Toolkit.i18nText("Fine-Design_Vcs_Delete_Select_All_Version"); + } + + @Override + protected boolean isNeedTopPane() { + return true; + } + + @Override + protected boolean isNeedRestore() { + return false; + } + + @Override + protected boolean isNeedSearch() { + return true; + } + + @Override + protected boolean isNeedDeleteAllVersion() { + return true; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsMovePanel.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsMovePanel.java new file mode 100644 index 0000000000..2c8401c94c --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsMovePanel.java @@ -0,0 +1,520 @@ +package com.fr.design.mainframe.vcs.ui; + + +import com.fr.base.svg.IconUtils; +import com.fr.design.dialog.BasicDialog; +import com.fr.design.dialog.BasicPane; +import com.fr.design.dialog.DialogActionAdapter; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ibutton.UIRadioButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.iprogressbar.ModernUIProgressBarUI; +import com.fr.design.gui.ispinner.UISpinner; +import com.fr.design.i18n.LocaleLinkProvider; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.VerticalFlowLayout; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; +import com.fr.design.mainframe.vcs.VcsExceptionUtils; +import com.fr.design.mainframe.vcs.common.VcsHelper; +import com.fr.design.utils.BrowseUtils; +import com.fr.design.utils.DesignUtils; +import com.fr.design.utils.ThemeUtils; +import com.fr.design.widget.FRWidgetFactory; +import com.fr.general.FRFont; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; +import com.fr.workspace.server.vcs.v2.move.VcsMoveService; +import com.fr.workspace.server.vcs.v2.move.VcsMoveStrategy; + +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import static javax.swing.JOptionPane.YES_NO_CANCEL_OPTION; +import static javax.swing.JOptionPane.YES_OPTION; + + +/** + * 迁移面板 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/6/13 + */ +public class VcsMovePanel extends BasicPane { + private static final FRFont FONT = DesignUtils + .getDefaultGUIFont() + .applySize(14) + .applyStyle(FRFont.BOLD); + + private static final Color BACK_GROUND_COLOR = new Color(202,232,255); + + //提示字体的颜色,直接模仿其他面板的写法 + private static final Color TIP_COLOR = new Color(51, 51, 52, (int)Math.round(0.5 * 255)); + + private static final Color LABEL_COLOR = new Color(34,149,233); + + private static final int MIN_VALUE = 1; + + private static final int MAX_VALUE = 999; + + private static final int STEP = 1; + + private static final int DEFAULT_VALUE = 5; + + private static final String HELP_KEY = "Fine-Design_Vcs_Move_Help_Link"; + + private static final String HELP_KEY_DEFAULT = "Fine-Design_Vcs_Move_Help_Link_Default"; + + private static final String HELP_URL = LocaleLinkProvider.getInstance().getLink(HELP_KEY, HELP_KEY_DEFAULT); + + public static final String SETTING = "SETTING"; + + public static final String PROCESS = "PROCESS"; + + public static final String SUCCESS = "SUCCESS"; + + public static final String FAILED = "FAILED"; + + public static boolean moving = false; + + private BasicDialog parentDialog; + private UILabel vcsUpdateExistLabel = new UILabel(); + + private UILabel vcsUpdateFireLabel = new UILabel(); + + private UIButton centerButton; + private BasicPane choosePane; + private CardLayout parentCard; + private JPanel parentPane; + private static final JProgressBar PROGRESS_BAR = new JProgressBar(); + + private JPanel progressPanel; + private UILabel tipLabel; + private UIButton successButton; + private UILabel iconLabel; + private UILabel successLabel; + private UILabel successTipLabel; + private UIButton failedButton; + private UILabel failedIconLabel; + private UILabel failedLabel; + private UILabel failedTipLabel; + + //保留全部 + private UIRadioButton moveAllButton; + //默认选项,保留部分 + private UIRadioButton moveDefaultButton; + //全部放弃 + private UIRadioButton moveNothingButton; + + private UIPositiveIntSpinner spinner; + + private MoveCallBack callBack; + + private JPanel updatePane; + + private boolean visible = false; + + private UILabel seeLabel; + private UILabel helpLabel; + + public VcsMovePanel(CardLayout cardLayout, JPanel parentPane, MoveCallBack callBack, BasicDialog parentDialog) { + this.parentCard = cardLayout; + this.parentPane = parentPane; + this.callBack = callBack; + this.setLayout(new BorderLayout()); + this.parentDialog = parentDialog; + updatePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane(); + updatePane.setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 0)); + //初始化顶部的面板 + initVcsLabel(updatePane); + //initVcsChoosePane + initVcsChoosePane(); + //初始化listener + initListener(); + this.add(updatePane); + checkVisible(); + //如果已经在迁移 + if (VcsMoveService.getInstance().isMoving()) { + initProcessPane(); + VcsMovePanel.this.getParentCard().show(getParentPane(), PROCESS); + } + } + + private void checkVisible() { + new SwingWorker() { + @Override + protected Boolean doInBackground() throws Exception { + return VcsHelper.getInstance().checkMoveFunctionSupport(); + } + @Override + protected void done() { + try { + boolean useMove = get(); + VcsMovePanel.this.setVisible(useMove); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + }.execute(); + } + + private void initProcessPane() { + JPanel processPane = new JPanel(); + JPanel body = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); + PROGRESS_BAR.setStringPainted(true); + PROGRESS_BAR.setUI(new ModernUIProgressBarUI()); + PROGRESS_BAR.setBorderPainted(false); + PROGRESS_BAR.setOpaque(false); + PROGRESS_BAR.setBorder(null); + PROGRESS_BAR.setSize(BasicDialog.MEDIUM); + body.add(PROGRESS_BAR); + body.add(new UILabel(StringUtils.BLANK)); + tipLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_While_Moving")); + tipLabel.setAlignmentX(CENTER_ALIGNMENT); + body.add(tipLabel); + processPane.add(body); + processPane.setLayout(FRGUIPaneFactory.createCenterLayout(body, 0.5f, 0.5f)); + parentPane.add(processPane, PROCESS); + } + + private void initVcsChoosePane() { + choosePane = new BasicPane() { + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Vcs_Deal_With_Entry"); + } + }; + VerticalFlowLayout layout = new VerticalFlowLayout(VerticalFlowLayout.TOP); + layout.setAlignLeft(true); + choosePane.setLayout(layout); + + //初始化上方的文字板块 + initTopDesc(); + //初始化中间区域的单选框 + initRadioButton(); + //初始化下方的Tip描述 + initTipDesc(); + } + + private void initTopDesc() { + UILabel label = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_How_To_Deal_With_Entry")); + choosePane.add(label); + } + + private void initTipDesc() { + UILabel descLabel = FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Desc")); + UILabel firstLabel = FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Tips_First")); + UILabel secondLabel = FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Tips_Second")); + descLabel.setForeground(TIP_COLOR); + firstLabel.setForeground(TIP_COLOR); + secondLabel.setForeground(TIP_COLOR); + choosePane.add(descLabel); + choosePane.add(firstLabel); + choosePane.add(secondLabel); + } + + private void initRadioButton() { + //保留全部 + moveAllButton = new UIRadioButton(Toolkit.i18nText("Fine-Design_Vcs_Move_All")); + //默认选项,保留部分 + moveDefaultButton = new UIRadioButton(Toolkit.i18nText("Fine-Design_Vcs_Move_Default")); + //全部放弃 + moveNothingButton = new UIRadioButton(Toolkit.i18nText("Fine-Design_Vcs_Move_Nothing")); + // 将按钮"保留部分"设置为选中状态 + moveDefaultButton.setSelected(true); + // 创建一个按钮组,添加三个按钮 + ButtonGroup buttonGroup = new ButtonGroup(); + buttonGroup.add(moveAllButton); + buttonGroup.add(moveDefaultButton); + buttonGroup.add(moveNothingButton); + + JPanel moveDefaultPanel = new JPanel(); + JPanel moveAllPane = new JPanel(); + JPanel moveNothingPane = new JPanel(); + moveAllPane.add(moveAllButton); + moveDefaultPanel.add(moveDefaultButton); + moveDefaultPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Default_Text_Left"))); + spinner = new UIPositiveIntSpinner(MIN_VALUE, MAX_VALUE, STEP, DEFAULT_VALUE); + moveDefaultPanel.add(spinner); + moveDefaultPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Default_Text_Right"))); + moveNothingPane.add(moveNothingButton); + choosePane.add(moveAllPane); + choosePane.add(moveDefaultPanel); + choosePane.add(moveNothingPane); + } + + private void initVcsLabel(JPanel parent) { + parent.removeAll(); + if (!VcsHelper.getInstance().isLegacyMode()) { + parent.setBackground(ThemeUtils.BACK_COLOR); + centerButton = new UIButton(Toolkit.i18nText("Fine-Design_Vcs_Center")); + parent.add(centerButton); + initVcsCenterListener(); + } else { + parent.setBackground(BACK_GROUND_COLOR); + vcsUpdateExistLabel = new UILabel(IconUtils.readIcon("/com/fr/design/vcs/vcs_move_icon.svg")); + vcsUpdateExistLabel.setText(Toolkit.i18nText("Fine-Design_Vcs_Can_Update")); + vcsUpdateFireLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Update")); + vcsUpdateFireLabel.setForeground(LABEL_COLOR); + vcsUpdateFireLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); + parent.add(vcsUpdateExistLabel); + parent.add(vcsUpdateFireLabel); + } + } + + private void initVcsCenterListener() { + centerButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + VcsCenterPane vcsCenterPane = new VcsCenterPane(); + vcsCenterPane.showDialog(parentDialog); + } + }); + } + + private void initListener() { + vcsUpdateFireLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + BasicDialog dlg = choosePane.showMediumWindow(SwingUtilities.getWindowAncestor(VcsMovePanel.this), new DialogActionAdapter() { + @Override + public void doOk() { + createConfirmPane(); + } + }); + dlg.setVisible(true); + } + }); + } + + private void createConfirmPane() { + VerticalFlowLayout layout = new VerticalFlowLayout(VerticalFlowLayout.TOP); + layout.setAlignLeft(true); + JPanel panel = new JPanel(); + panel.setLayout(layout); + UILabel titleLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Tip_Title")); + UILabel firstLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Tip_First")); + UILabel secondLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Tip_Second")); + titleLabel.setForeground(TIP_COLOR); + firstLabel.setForeground(TIP_COLOR); + secondLabel.setForeground(TIP_COLOR); + panel.add(new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Right_Now"))); + panel.add(titleLabel); + panel.add(firstLabel); + panel.add(secondLabel); + int value = FineJOptionPane.showConfirmDialog(SwingUtilities.getWindowAncestor(DesignerContext.getDesignerFrame()), panel, Toolkit.i18nText("Fine-Design_Vcs_Move_Title"), JOptionPane.YES_NO_OPTION); + processMove(value); + } + + private void processMove(int value) { + if (value == YES_OPTION) { + //进度条面板 + initProcessPane(); + VcsMovePanel.this.getParentCard().next(getParentPane()); + VcsMoveStrategy strategy; + if (moveDefaultButton.isSelected()) { + strategy = VcsMoveStrategy.createStrategy((int) spinner.getValue()); + } else if (moveNothingButton.isSelected()) { + strategy = VcsMoveStrategy.createStrategy(0); + } else { + strategy = VcsMoveStrategy.createStrategy(Integer.MAX_VALUE); + } + new MoveWorker(strategy).execute(); + } + } + + private void initSuccessPane() { + JPanel successPane = new JPanel(); + JPanel body = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); + successButton = new UIButton(Toolkit.i18nText("Fine-Design_Vcs_Move_Success_Go")); + initSuccessButtonListener(); + iconLabel = new UILabel(IconUtils.readIcon("/com/fr/design/vcs/move_success.svg")); + successLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Success")); + successLabel.setFont(FONT); + successTipLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Success_Tip")); + initStatusPane(successTipLabel, iconLabel, successLabel, successButton, body, SUCCESS, successPane); + } + + private void initSuccessButtonListener() { + successButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + doAfterMove(); + } + }); + } + + private void initFailedButtonListener() { + failedButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + doAfterMove(); + } + }); + } + + private void doAfterMove() { + visible = !VcsHelper.getInstance().isLegacyMode(); + initVcsLabel(updatePane); + updatePane.setVisible(!visible); + callBack.doCallBack(visible); + parentCard.show(parentPane, SETTING); + } + + public BasicDialog getParentDialog() { + return parentDialog; + } + + public void setParentDialog(BasicDialog parentDialog) { + this.parentDialog = parentDialog; + } + + @Override + protected String title4PopupWindow() { + return StringUtils.EMPTY; + } + + public CardLayout getParentCard() { + return parentCard; + } + + public JPanel getParentPane() { + return parentPane; + } + + private void initFailedPane(String detail) { + JPanel failedPane = new JPanel(); + JPanel body = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); + failedButton = new UIButton(Toolkit.i18nText("Fine-Design_Vcs_Move_Failed_Go")); + initFailedButtonListener(); + failedIconLabel = new UILabel(IconUtils.readIcon("/com/fr/design/vcs/move_failed.svg")); + failedLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Failed")); + failedLabel.setFont(FONT); + failedTipLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Failed_Tip", detail)); + initStatusPane(failedTipLabel, failedIconLabel, failedLabel, failedButton, body, FAILED, failedPane); + } + + private void initStatusPane(UILabel tipLabel, UILabel iconLabel, UILabel label, UIButton button, JPanel body, String tag,JPanel statusPane) { + tipLabel.setForeground(TIP_COLOR); + body.add(iconLabel); + body.add(new UILabel(StringUtils.BLANK)); + body.add(label); + body.add(new UILabel(StringUtils.BLANK)); + body.add(tipLabel); + body.add(new UILabel(StringUtils.BLANK)); + JPanel panel = createHelpPane(); + body.add(panel); + body.add(new UILabel(StringUtils.BLANK)); + body.add(button); + statusPane.add(body); + statusPane.setLayout(FRGUIPaneFactory.createCenterLayout(body, 0.5f, 0.5f)); + parentPane.add(statusPane, tag); + iconLabel.setAlignmentX(CENTER_ALIGNMENT); + label.setAlignmentX(CENTER_ALIGNMENT); + button.setAlignmentX(CENTER_ALIGNMENT); + tipLabel.setAlignmentX(CENTER_ALIGNMENT); + } + + private JPanel createHelpPane() { + JPanel panel = new JPanel(); + seeLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_See")); + seeLabel.setForeground(TIP_COLOR); + helpLabel = new UILabel(Toolkit.i18nText("Fine-Design_Vcs_Move_Help")); + helpLabel.setForeground(LABEL_COLOR); + helpLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); + helpLabel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + BrowseUtils.browser(HELP_URL); + } + }); + panel.add(seeLabel); + panel.add(helpLabel); + return panel; + } + + + private class MoveWorker extends SwingWorker { + + private VcsMoveStrategy strategy; + private String detail = StringUtils.EMPTY; + + public MoveWorker(VcsMoveStrategy strategy) { + this.strategy = strategy; + } + + @Override + protected Boolean doInBackground() throws Exception { + try { + //开始迁移 + VcsMoveService.getInstance().startMove(new VcsMoveService.BaseMoveServiceWhileMoving() { + @Override + public void publishProgress() { + int num = VcsMoveService.getInstance().getCurrentMove(); + publish(num); + } + @Override + public void prepare4Move() { + PROGRESS_BAR.setMaximum(VcsMoveService.getInstance().getTotal()); + } + }, strategy); + } catch (Exception e) { + VcsMoveService.getInstance().stopMoving(); + detail = VcsExceptionUtils.createDetailByException(e); + return false; + } + return true; + } + + @Override + protected void process(List chunks) { + PROGRESS_BAR.setValue(chunks.get(chunks.size() - 1)); + } + + @Override + protected void done() { + VcsMoveService.getInstance().stopMoving(); + try { + if (get()) { + initSuccessPane(); + VcsMovePanel.this.getParentCard().show(getParentPane(), SUCCESS); + VcsHelper.getInstance().updateLegacyMode(); + DesignerFrameFileDealerPane.getInstance().refreshDockingView(); + } else { + initFailedPane(detail); + VcsMovePanel.this.getParentCard().show(getParentPane(), FAILED); + FineLoggerFactory.getLogger().error("[VcsV2] Vcs move failed!"); + } + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + } + + /** + * 迁移回调事件 + * + */ + public static class MoveCallBack { + /** + * 处理回调 + */ + public void doCallBack(boolean visible){} + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsMovingExitOption.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsMovingExitOption.java new file mode 100644 index 0000000000..0c1469b877 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsMovingExitOption.java @@ -0,0 +1,54 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.workspace.server.vcs.v2.move.VcsMoveService; + +import javax.swing.JOptionPane; + +/** + * 版本管理迁移检查 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/18 + */ +public class VcsMovingExitOption { + + + /** + * 关闭前的检查 + * + * @return + */ + public static boolean ShowDialogAndConfirmExit() { + return showDialogAndChoose(Toolkit.i18nText("Fine-Design_Vcs_Close_Tips")); + } + + + /** + * 切换环境前的检查 + * + * @return + */ + public static boolean ShowDialogAndConfirmSwitch() { + return showDialogAndChoose(Toolkit.i18nText("Fine-Design_Vcs_Switch_Tips")); + } + + private static boolean showDialogAndChoose(String msg) { + if (VcsMoveService.getInstance().isMoving()) { + int result = FineJOptionPane.showConfirmDialog( + DesignerContext.getDesignerFrame(), + msg, + Toolkit.i18nText("Fine-Design_Basic_Tool_Tips"), + FineJOptionPane.YES_NO_OPTION + ); + return result == JOptionPane.YES_OPTION; + } + return true; + } + + + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsNewPane.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsNewPane.java new file mode 100644 index 0000000000..11da401226 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsNewPane.java @@ -0,0 +1,406 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.base.svg.IconUtils; +import com.fr.design.dialog.FineJOptionPane; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.file.MultiTemplateTabPane; +import com.fr.design.file.TemplateTreePane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.vcs.TableValueOperator; +import com.fr.design.mainframe.vcs.VcsOperatorWorker; +import com.fr.design.mainframe.vcs.VcsTableEntity; +import com.fr.design.mainframe.vcs.VcsTableOperatorListener; +import com.fr.design.mainframe.vcs.common.VcsCacheFileNodeFile; +import com.fr.design.mainframe.vcs.common.VcsHelper; +import com.fr.file.FileNodeFILE; +import com.fr.file.filetree.FileNode; +import com.fr.file.filetree.FileNodes; +import com.fr.io.utils.ResourceIOUtils; +import com.fr.report.InconsistentLockException; +import com.fr.report.entity.VcsEntity; +import com.fr.stable.StableUtils; +import com.fr.stable.StringUtils; +import com.fr.stable.project.ProjectConstants; +import com.fr.workspace.WorkContext; +import com.fr.workspace.resource.WorkResource; +import com.fr.workspace.server.vcs.VcsFileUtils; +import com.fr.workspace.server.vcs.VcsOperator; +import com.fr.workspace.server.vcs.v2.VcsTaskResult; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JOptionPane; +import javax.swing.JTable; +import javax.swing.SwingWorker; +import javax.swing.UIManager; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; + + +/** + * 版本管理交互优化新面板 + *
  • 采用表格的形式展现
  • + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/11 + */ +public class VcsNewPane extends RecyclePane { + + private String filePath = StringUtils.EMPTY; + + protected static int OPERATOR_COL = 5; + + protected static int EDIT_COL = 4; + + private static final String PATH = "path"; + + private static final int DOUBLE_CLICK_COUNT = 2; + protected VcsOperatorPane operatorPane; + private static final Icon PREVIEW_ICON = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_operator_preview"); + private static final Icon DELETE_ICON = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_operator_delete"); + private static final Icon RESTORE_ICON = IconUtils.readIcon("/com/fr/design/standard/vcslist/vcs_operator_restore"); + + private UILabel restore; + private UILabel delete; + private UILabel preview; + private static final String TITLE = Toolkit.i18nText("Fine-Design_Vcs_Title"); + private static final String[] COLUMN_NAMES = new String[]{ + StringUtils.EMPTY, + Toolkit.i18nText("Fine-Design_Vcs_Version"), + Toolkit.i18nText("Fine-Design_Vcs_Time"), + Toolkit.i18nText("Fine-Design_Vcs_User"), + Toolkit.i18nText("Fine-Design_Vcs_Annotation"), + Toolkit.i18nText("Fine-Design_Vcs_Operator") + + }; + + private static final Class[] CLASSES = new Class[]{ + Boolean.class, + UILabel.class, + UILabel.class, + UILabel.class, + UILabel.class, + VcsOperatorPane.class + }; + + + public VcsNewPane(String filePath) { + super(TITLE, (o, columnIndex) -> { + switch (columnIndex) { + case 0: + return o.isSelect(); + case 1: + return o.getVersion(); + case 2: + return o.getTime(); + case 3: + return o.getUserName(); + case 4: + return o.getCommitMsg(); + default: + return o; + } + }, false); + this.filePath = filePath; + initModel(COLUMN_NAMES, CLASSES, OPERATOR_COL); + } + + + private void initModel(String[] columns, Class[] classes, int operatorCol) { + this.model = new DefaultModel(columns, classes) { + @Override + public boolean isCellEditable(int row, int col) { + return col == 0 || col == operatorCol; + } + }; + this.operatorPane = createOperatorPane(); + this.model.setDefaultEditor(VcsOperatorPane.class, new VcsCellEditor(createOperatorPane())); + this.model.setDefaultRenderer(VcsOperatorPane.class, new VcsCellRender(createOperatorPane())); + this.model.setDefaultRenderer(UILabel.class, new ToolTipTableCellRenderer()); + } + + + public VcsNewPane(String title, TableValueOperator operators, boolean needBorder, String[] columns, Class[] classes, int operatorCol) { + super(title, operators, needBorder); + initModel(columns, classes, operatorCol); + } + + /** + * 创建操作面板 + * + * @return 操作面板 + */ + public VcsOperatorPane createOperatorPane() { + restore = new UILabel(RESTORE_ICON); + restore.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Restore")); + delete = new UILabel(DELETE_ICON); + delete.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Delete")); + preview = new UILabel(PREVIEW_ICON); + preview.setToolTipText(Toolkit.i18nText("Fine-Design_Vcs_ToolTip_Preview")); + initPreviewListener(); + initDeleteListener(); + initRestoreListener(); + List list = new ArrayList<>(); + list.add(restore); + list.add(delete); + list.add(preview); + return new VcsOperatorPane(list); + } + + private void initRestoreListener() { + restore.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + JTable table = tableContentPane.getEditTable(); + Object o = table.getValueAt(table.getEditingRow(), table.getEditingColumn()); + if (o instanceof VcsTableEntity) { + VcsEntity entity = ((VcsTableEntity) o).getEntity(); + int selVal = FineJOptionPane.showConfirmDialog( + VcsNewPane.this, + Toolkit.i18nText("Fine-Design_Vcs_Restore_This_Version_Tips"), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE); + if (selVal == JOptionPane.YES_OPTION) { + restoreEntity(entity); + VcsNewPane.this.saveSettingAndCloseDialog(); + } + } + } + }); + } + + + private void restoreEntity(VcsEntity entity) { + new SwingWorker() { + @Override + protected VcsTaskResult doInBackground() throws Exception { + String path = VcsHelper.getInstance().getFilePath(entity); + if (!WorkContext.getCurrent().get(WorkResource.class).exist(path)) { + return new VcsTaskResult(false, new FileNotFoundException()); + } + if (checkLock(entity.getFilename())) { + return new VcsTaskResult(false, new InconsistentLockException()); + } + //step1.设置还原的用户名 + entity.setUsername(VcsHelper.getInstance().getCurrentUsername()); + //step2.rollback到指定版本 + WorkContext.getCurrent().get(VcsOperator.class).rollbackTo(entity); + //最里面的文件系统的write会吞异常,这边就一直默认成功吧,日志里会体现失败的情况 + return new VcsTaskResult(true); + } + @Override + protected void done() { + try { + VcsTaskResult result = get(); + if (result.isSuccess()) { + //step3.如果原来原模板已经打开则关闭原模板,打开rollback后的新模板 + List> templateList = HistoryTemplateListCache.getInstance().getHistoryList(); + for (JTemplate template : templateList) { + if (StringUtils.equals(filePath, template.getPath())) { + MultiTemplateTabPane.getInstance().setIsCloseCurrent(HistoryTemplateListCache.getInstance().isCurrentEditingFile(filePath)); + MultiTemplateTabPane.getInstance().closeFormat(template); + MultiTemplateTabPane.getInstance().closeSpecifiedTemplate(template); + break; + } + } + DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(new FileNode(filePath, false))); + } else { + if (result.getException() instanceof FileNotFoundException) { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Warning_Template_Do_Not_Exsit")); + } else { + FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Vcs_Open_Lock_Tip"), UIManager.getString("OptionPane.messageDialogTitle"), JOptionPane.ERROR_MESSAGE); + } + } + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + }.execute(); + } + + private boolean checkLock(String filename) { + String selectedFilePath = getTemplateTruePath(filename); + FileNode node = new FileNode(getTemplateTruePath(filename), false); + String lock = node.getLock(); + return TemplateTreePane.needShowLockInfo(lock, selectedFilePath, node); + } + + /** + * 获取模板的路径 + */ + public String getTemplateTruePath(String filename) { + return StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, filename); + } + + private void initDeleteListener() { + delete.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + JTable table = tableContentPane.getEditTable(); + int row = table.getEditingRow(); + Object o = table.getValueAt(row, table.getEditingColumn()); + if (o instanceof VcsTableEntity) { + VcsEntity entity = ((VcsTableEntity) o).getEntity(); + int selVal = FineJOptionPane.showConfirmDialog( + VcsNewPane.this, + Toolkit.i18nText("Fine-Design_Vcs_Delete_This_Version_Tips"), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE); + if (selVal == JOptionPane.YES_OPTION) { + VcsOperatorWorker.createDeleteWorker().deleteTargetVersion(entity, new VcsTableOperatorListener() { + @Override + public void updateUI() { + model.fireTableRowsDeleted(row, row); + model.removeRow(row); + model.fireTableDataChanged(); + } + }); + fireVcsListener(model.getList()); + } + } + } + }); + } + + private void initPreviewListener() { + preview.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + JTable table = tableContentPane.getEditTable(); + Object o = table.getValueAt(table.getEditingRow(), table.getEditingColumn()); + if (o instanceof VcsTableEntity) { + VcsEntity entity = ((VcsTableEntity) o).getEntity(); + previewEntity(entity); + } + } + }); + } + + private void previewEntity(VcsEntity entity) { + new SwingWorker() { + @Override + protected String doInBackground() throws Exception { + //step1.将指定版本的历史文件读取出来,加上前缀放到cache中 + VcsOperator vcsOperator = WorkContext.getCurrent().get(VcsOperator.class); + String fileOfVersion = vcsOperator.getFileOfFileVersion( + entity.getFilename(), + entity.getVersion(), + Toolkit.i18nText("Fine-Design_Vcs_Prefix", entity.getVersion())); + return fileOfVersion; + } + @Override + protected void done() { + try { + //step2.再打开cache中的模板 + DesignerContext.getDesignerFrame().openTemplate(new VcsCacheFileNodeFile(new FileNode(get(), false))); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + }.execute(); + } + + @Override + protected boolean isNeedDeleteAllVersion() { + return false; + } + + @Override + protected List getTableList() { + List entityList = WorkContext.getCurrent().get(VcsOperator.class).getVersions(VcsFileUtils.dealWithFilePath(filePath)); + List tableEntities = new ArrayList<>(); + for (VcsEntity entity : entityList) { + tableEntities.add(new VcsTableEntity(entity)); + } + return tableEntities; + } + + @Override + protected String title4PopupWindow() { + return TITLE; + } + + @Override + protected String getDeleteTip(int size) { + return Toolkit.i18nText("Fine-Design_Vcs_Delete_Versions_Tips", size); + } + + @Override + protected boolean isNeedRestore() { + return false; + } + + @Override + protected boolean isNeedSearch() { + return false; + } + + @Override + protected void initExtraListener4Table(JTable table) { + table.addMouseMotionListener(new MouseMotionAdapter() { + @Override + public void mouseMoved(MouseEvent e) { + Point point = e.getPoint(); + int row = table.rowAtPoint(point); + int col = table.columnAtPoint(point); + if (col != 0) { + table.editCellAt(row, col); + } + } + }); + initEditListener(table); + } + + private void initEditListener(JTable table) { + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == DOUBLE_CLICK_COUNT) { + Point point = e.getPoint(); + int row = table.rowAtPoint(point); + int col = table.columnAtPoint(point); + if (col == EDIT_COL) { + Object o = table.getValueAt(row, OPERATOR_COL); + if (o instanceof VcsTableEntity) { + showDialog(((VcsTableEntity) o).getEntity()); + } + } + } + } + }); + } + + private void showDialog(VcsEntity entity) { + EditFileVersionDialog dialog = new EditFileVersionDialog(entity) { + @Override + public void doOK() { + entity.setCommitMsg(getMsgTestArea().getText()); + VcsOperatorWorker.createUpdateWorker().updateEntityAnnotation(entity, new VcsTableOperatorListener() { + @Override + public void updateUI() { + setVisible(false); + model.fireTableDataChanged(); + } + }); + } + }; + dialog.setVisible(true); + } + + @Override + protected boolean needIcon4Head(int col) { + return col != 0 && col != OPERATOR_COL; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsOperatorPane.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsOperatorPane.java new file mode 100644 index 0000000000..ce4db1e0d7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsOperatorPane.java @@ -0,0 +1,40 @@ +package com.fr.design.mainframe.vcs.ui; + + +import com.fr.design.layout.FRGUIPaneFactory; + +import javax.swing.JComponent; +import javax.swing.JPanel; + + + +import java.awt.*; + +import java.util.List; + + +/** + * 操作面板,用于置放常用的操作label + *

    例如 删除、还原、预览、打开模板等

    + *
  • 负责表格渲染 与 操作按钮置蓝+设定cursor
  • + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/13 + */ +public class VcsOperatorPane extends JPanel { + + public VcsOperatorPane(List iconJComponentMap) { + init(iconJComponentMap); + } + + + private void init(List iconJComponentMap) { + this.setLayout(FRGUIPaneFactory.createLeftZeroVgapNormalHgapLayout()); + for (JComponent value : iconJComponentMap) { + value.setCursor(new Cursor(Cursor.HAND_CURSOR)); + this.add(value); + } + } + +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsProgressDialog.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsProgressDialog.java new file mode 100644 index 0000000000..33b57e1f3e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/mainframe/vcs/ui/VcsProgressDialog.java @@ -0,0 +1,81 @@ +package com.fr.design.mainframe.vcs.ui; + +import com.fr.design.dialog.BasicDialog; +import com.fr.design.dialog.BasicPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.iprogressbar.ModernUIProgressBarUI; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.DesignerContext; +import com.fr.stable.StringUtils; + +import javax.swing.JPanel; +import javax.swing.JProgressBar; + +import static java.awt.Component.CENTER_ALIGNMENT; + +/** + * Vcs操作进度条面板 + * + * @author Destiny.Lin + * @since 11.0 + * Created on 2023/7/18 + */ +public class VcsProgressDialog{ + private JProgressBar progressBar = new JProgressBar(); + private UILabel tipLabel; + private BasicPane processPane; + + private BasicDialog dialog; + + public VcsProgressDialog(String title, String dealingStr) { + + processPane = new BasicPane() { + @Override + protected String title4PopupWindow() { + return title; + } + }; + JPanel body = FRGUIPaneFactory.createY_AXISBoxInnerContainer_L_Pane(); + progressBar.setStringPainted(true); + progressBar.setUI(new ModernUIProgressBarUI()); + progressBar.setBorderPainted(false); + progressBar.setOpaque(false); + progressBar.setBorder(null); + progressBar.setSize(BasicDialog.MEDIUM); + progressBar.setValue(0); + body.add(progressBar); + body.add(new UILabel(StringUtils.BLANK)); + tipLabel = new UILabel(dealingStr); + tipLabel.setAlignmentX(CENTER_ALIGNMENT); + body.add(tipLabel); + processPane.add(body); + processPane.setLayout(FRGUIPaneFactory.createCenterLayout(body, 0.5f, 0.5f)); + } + + + /** + * 展示面板 + * + */ + public void showDialog() { + dialog = processPane.showSmallWindow(DesignerContext.getDesignerFrame(), false); + dialog.setVisible(true); + } + + /** + * 关闭面板 + * + */ + public void closeDialog() { + dialog.setVisible(false); + } + + public JProgressBar getProgressBar() { + return progressBar; + } + + public void setProgressBar(JProgressBar progressBar) { + this.progressBar = progressBar; + } +} diff --git a/designer-base/src/main/java/com/fr/design/mainframe/widget/editors/DataBindingEditor.java b/designer-base/src/main/java/com/fr/design/mainframe/widget/editors/DataBindingEditor.java index 018bc75aeb..bad481e7af 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/widget/editors/DataBindingEditor.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/widget/editors/DataBindingEditor.java @@ -29,8 +29,8 @@ public class DataBindingEditor extends Editor { private final static int HORI_GAP = 1; private final static int VER_GAP = 7; - private TableDataComboBox tableDataComboBox; - private LazyComboBox columnNameComboBox; + protected TableDataComboBox tableDataComboBox; + protected LazyComboBox columnNameComboBox; private ItemListener tableDataComboBoxListener = new ItemListener() { public void itemStateChanged(ItemEvent evt) { boolean isInit = columnNameComboBox.getSelectedIndex() == -1; @@ -87,9 +87,16 @@ public class DataBindingEditor extends Editor { } }); columnNameComboBox.setEditable(true); + addComboBoxesAndSetPosition(); + columnNameComboBox.addItemListener(columnNameComboboxListener); + } + + /** + * 根据需求不同调整下拉框的位置 + */ + protected void addComboBoxesAndSetPosition() { this.add(tableDataComboBox, BorderLayout.NORTH); this.add(columnNameComboBox, BorderLayout.CENTER); - columnNameComboBox.addItemListener(columnNameComboboxListener); } protected TableDataSource getTableDataSource() { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/widget/editors/WidgetValueEditor.java b/designer-base/src/main/java/com/fr/design/mainframe/widget/editors/WidgetValueEditor.java index 4f5c7f28f3..48199a5e6b 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/widget/editors/WidgetValueEditor.java +++ b/designer-base/src/main/java/com/fr/design/mainframe/widget/editors/WidgetValueEditor.java @@ -5,6 +5,7 @@ package com.fr.design.mainframe.widget.editors; import java.awt.Component; +import java.awt.BorderLayout; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -30,6 +31,7 @@ public class WidgetValueEditor extends AbstractPropertyEditor { /** * 根据类型创建 + * 服务器 - 控件管理 * @param type 类型 * @param onlyServer 是否是服务器 * @return 编辑器 @@ -41,7 +43,7 @@ public class WidgetValueEditor extends AbstractPropertyEditor { case DataControl.TYPE_FORMULA: return new FormulaEditor(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Parameter_Formula")); case DataControl.TYPE_DATABINDING: - return onlyServer ? new ServerDataBindingEditor() : new DataBindingEditor(); + return onlyServer ? new WidgetValueServerDataBindingEditor() : new WidgetValueDataBindingEditor(); case DataControl.TYPE_STRING: return new TextEditor(); case DataControl.TYPE_BOOLEAN: @@ -70,6 +72,22 @@ public class WidgetValueEditor extends AbstractPropertyEditor { } return editor; } + + private static class WidgetValueDataBindingEditor extends DataBindingEditor { + @Override + protected void addComboBoxesAndSetPosition() { + this.add(tableDataComboBox, BorderLayout.CENTER); + this.add(columnNameComboBox, BorderLayout.EAST); + } + } + + private static class WidgetValueServerDataBindingEditor extends ServerDataBindingEditor { + @Override + protected void addComboBoxesAndSetPosition() { + this.add(tableDataComboBox, BorderLayout.CENTER); + this.add(columnNameComboBox, BorderLayout.EAST); + } + } public WidgetValueEditor(Object o) { this(o, false); diff --git a/designer-base/src/main/java/com/fr/design/menu/MenuDef.java b/designer-base/src/main/java/com/fr/design/menu/MenuDef.java index 798d4870af..ee82d256ec 100644 --- a/designer-base/src/main/java/com/fr/design/menu/MenuDef.java +++ b/designer-base/src/main/java/com/fr/design/menu/MenuDef.java @@ -3,25 +3,32 @@ package com.fr.design.menu; import com.fr.base.svg.IconUtils; import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.gui.ibutton.UIButton; -import com.fr.design.gui.imenu.*; +import com.fr.design.gui.imenu.UIHeadMenu; +import com.fr.design.gui.imenu.UIMenu; +import com.fr.design.gui.imenu.UIPopupEastAttrMenu; +import com.fr.design.gui.imenu.UIPopupMenu; +import com.fr.design.gui.imenu.UIScrollMenu; import com.fr.design.gui.iscrollbar.UIScrollBar; import com.fr.design.i18n.Toolkit; import com.fr.design.mainframe.JTemplate; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.stable.StringUtils; -import java.util.HashSet; -import java.util.Set; -import javax.swing.*; +import javax.swing.JMenu; +import javax.swing.JPopupMenu; +import javax.swing.JToolBar; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; -import java.awt.*; +import java.awt.Component; +import java.awt.Dimension; import java.awt.event.ContainerListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * Define Menu. @@ -46,6 +53,7 @@ public class MenuDef extends ShortCut { protected Boolean isEastAttr = false; protected char mnemonic; protected String iconPath; + private boolean needDisabled; protected String tooltip; //item List. private List shortcutList = new ArrayList(); @@ -112,9 +120,19 @@ public class MenuDef extends ShortCut { } public void setIconPath(String iconPath) { - this.iconPath = iconPath; + setDisabledIcon(iconPath, false); } + /** + * 设置不可用图标时,注意传递路径问题,若路径为"view_normal.svg",请传递"view",不带后缀 + * 读取disable图标的文件名应当为"xxx_disabled.svg",也是项目中的svg命名规范 + * 注意必须是svg图标路径才能使用此函数设置正常和禁用状态 + * + * */ + public void setDisabledIcon(String iconPath, boolean needDisabled) { + this.iconPath = iconPath; + this.needDisabled = needDisabled; + } public int getShortCutCount() { return this.shortcutList.size(); } @@ -183,6 +201,9 @@ public class MenuDef extends ShortCut { if (createdButton == null) { if (iconPath != null) { createdButton = new UIButton(IconUtils.readIcon(iconPath)); + if(needDisabled) { + createdButton.setDisabledIcon(IconUtils.readIcon(iconPath + IconUtils.ICON_TYPE_DISABLED)); + } createdButton.set4ToolbarButton(); } else { createdButton = new UIButton(name); diff --git a/designer-base/src/main/java/com/fr/design/os/impl/PMDialogAction.java b/designer-base/src/main/java/com/fr/design/os/impl/PMDialogAction.java index 16944da068..d4daa8f8bd 100644 --- a/designer-base/src/main/java/com/fr/design/os/impl/PMDialogAction.java +++ b/designer-base/src/main/java/com/fr/design/os/impl/PMDialogAction.java @@ -24,12 +24,18 @@ public class PMDialogAction implements OSBasedAction { DesignUtils.visitEnvServerByParameters( PLUGIN_MANAGER_ROUTE,null,null); return; } - if (ServerPreferenceConfig.getInstance().isUseOptimizedUPM() - || SupportOSImpl.MACOS_NEW_PLUGIN_MANAGEMENT.support() - || DesignerEnvManager.getEnvManager().isUseOptimizedUPM4Adapter()) { + if (checkUPMSupport()) { UpmFinder.showUPMDialog(); } else { WebViewDlgHelper.createPluginDialog(); } } + + private boolean checkUPMSupport() { + return ServerPreferenceConfig.getInstance().isUseOptimizedUPM() + || SupportOSImpl.MACOS_NEW_PLUGIN_MANAGEMENT.support() + || DesignerEnvManager.getEnvManager().isUseOptimizedUPM4Adapter() + //默认开启 + || DesignerEnvManager.getEnvManager().isUseNewPluginFirst(); + } } diff --git a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java index a4ddfcd4e8..e2c94a8f10 100644 --- a/designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java +++ b/designer-base/src/main/java/com/fr/design/record/analyzer/advice/MonitorAdvice.java @@ -88,8 +88,9 @@ public class MonitorAdvice implements DesignerAnalyzerAdvice { MessageRecorderFactory.getInstance().syncSubmit(message); } } - } catch (Exception ignore) { + } catch (Exception ex) { //埋点信息入库失败应该不能影响业务流程 + FineLoggerFactory.getLogger().debug("[Metric] failed to log message.", ex); } finally { sessionBinder.detachSession(); } @@ -113,7 +114,11 @@ public class MonitorAdvice implements DesignerAnalyzerAdvice { } public static void recordSQLDetail(String uuid) { - DBMeterFactory.getMeter().submit(uuid); + try { + DBMeterFactory.getMeter().submit(uuid); + } catch (Exception e) { + FineLoggerFactory.getLogger().debug("[Metric] failed to log sql detail.", e); + } } public static void recordSQL(Compute once, MeasureObject measureObject) { diff --git a/designer-base/src/main/java/com/fr/design/remote/ui/list/AddedMemberList.java b/designer-base/src/main/java/com/fr/design/remote/ui/list/AddedMemberList.java index 1fc67b2852..94d8c8be95 100644 --- a/designer-base/src/main/java/com/fr/design/remote/ui/list/AddedMemberList.java +++ b/designer-base/src/main/java/com/fr/design/remote/ui/list/AddedMemberList.java @@ -37,7 +37,7 @@ public class AddedMemberList extends MemberList { "Fine-Design_Basic_Utils_Are_You_Sure_To_Delete_The_User_And_Its_Design_Authorities"; if (member.isSelected() && member.hasAuthority()){ int val = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText(keyTitle), - Toolkit.i18nText("Fine-Design_Basic_Remove"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (val == JOptionPane.OK_OPTION) { member.setSelected(!member.isSelected()); ((DefaultListModel) getModel()).removeElement(member); diff --git a/designer-base/src/main/java/com/fr/design/remote/ui/list/AddingMemberList.java b/designer-base/src/main/java/com/fr/design/remote/ui/list/AddingMemberList.java index 5851ec48c6..5b59a839b7 100644 --- a/designer-base/src/main/java/com/fr/design/remote/ui/list/AddingMemberList.java +++ b/designer-base/src/main/java/com/fr/design/remote/ui/list/AddingMemberList.java @@ -39,7 +39,7 @@ public class AddingMemberList extends MemberList { "Fine-Design_Basic_Utils_Are_You_Sure_To_Delete_The_User_And_Its_Design_Authorities"; if (member.isSelected() && member.hasAuthority()){ int val = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText(keyTitle), - Toolkit.i18nText("Fine-Design_Basic_Remove"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (val == JOptionPane.OK_OPTION) { member.setSelected(!member.isSelected()); } diff --git a/designer-base/src/main/java/com/fr/design/style/background/image/ImagePreviewPane.java b/designer-base/src/main/java/com/fr/design/style/background/image/ImagePreviewPane.java index bc4f3f41cc..f24fed4ba0 100644 --- a/designer-base/src/main/java/com/fr/design/style/background/image/ImagePreviewPane.java +++ b/designer-base/src/main/java/com/fr/design/style/background/image/ImagePreviewPane.java @@ -9,6 +9,7 @@ import com.fr.base.Style; import com.fr.design.gui.iscrollbar.UIScrollBar; import com.fr.general.ImageWithSuffix; +import com.fr.log.FineLoggerFactory; import com.fr.stable.CoreGraphHelper; import javax.swing.JComponent; @@ -92,9 +93,14 @@ public class ImagePreviewPane extends JComponent implements Scrollable, ImagePre isLoading = false; CoreGraphHelper.waitForImage(image); - imageWidth = image.getWidth(null); - imageHeight = image.getHeight(null); - + if (image.getFineImage() != null && image.getImage() != null) { + try { + imageWidth = image.getWidth(null); + imageHeight = image.getHeight(null); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } this.setToolTipText("Image Size: " + imageWidth + "x" + imageHeight + "px"); } fireChangeListener(); diff --git a/designer-base/src/main/java/com/fr/design/style/color/ColorSelectDialog.java b/designer-base/src/main/java/com/fr/design/style/color/ColorSelectDialog.java index 23dcf8cc36..149ce1a17e 100644 --- a/designer-base/src/main/java/com/fr/design/style/color/ColorSelectDialog.java +++ b/designer-base/src/main/java/com/fr/design/style/color/ColorSelectDialog.java @@ -79,6 +79,7 @@ public class ColorSelectDialog extends MiddleChartDialog{ this.seletePane = seletePane; initComponent(); this.pane.populate(initialColor); + this.setLocationRelativeTo(null); } private void initComponent() { @@ -87,7 +88,8 @@ public class ColorSelectDialog extends MiddleChartDialog{ this.setBasicDialogSize(545,500); this.setResizable(false); - + this.applyClosingAction(); + this.applyEscapeAction(); JPanel buttonPane = new JPanel(); buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); diff --git a/designer-base/src/main/java/com/fr/design/ui/ModernUIConstants.java b/designer-base/src/main/java/com/fr/design/ui/ModernUIConstants.java index 8f7bf07034..9edd5bd57c 100644 --- a/designer-base/src/main/java/com/fr/design/ui/ModernUIConstants.java +++ b/designer-base/src/main/java/com/fr/design/ui/ModernUIConstants.java @@ -3,12 +3,28 @@ package com.fr.design.ui; import com.fr.general.IOUtils; /** + * 新式面板常量 + * * @author richie * @version 10.0 * Created by richie on 2019-03-05 */ public class ModernUIConstants { + public static final String WINDOW = "window"; + public static final String DOT = "."; + public static final String EMB_TAG = "emb"; + /** + * 从emb:dynamic 改为 emb://dynamic + * 7之后协议会自动在":"后加上斜杠,导致识别错误 + */ + public static final String COMPONENT_TAG = "emb://dynamic"; + + public static final String SCHEME_HEADER = "://"; + + public static final String DEFAULT_NAMESPACE = "Pool"; + public static final String DEFAULT_VARIABLE = "data"; + public static final String DEFAULT_EXPRESSION = "update()"; public static final String SCRIPT_INIT_NAME_SPACE = IOUtils.readResourceAsString("/com/fr/design/ui/InitNameSpace.js"); public static final String HTML_TPL = IOUtils.readResourceAsString("/com/fr/design/ui/tpl.html"); 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 5a0ead41e7..f3aceb8476 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 @@ -34,7 +34,10 @@ import java.util.Map; * @version 10.0 * Created by richie on 2019-03-04 * 用于加载html5的Swing容器,可以在设计选项设置中打开调试窗口,示例可查看:com.fr.design.ui.ModernUIPaneTest + * @see {@link com.fr.design.jxbrowser.JxUIPane} + * @deprecated 主要用于jxbrowser6,将在下个版本删除 */ +@Deprecated public class ModernUIPane extends BasicPane { private Browser browser; @@ -119,6 +122,7 @@ public class ModernUIPane extends BasicPane { /** * 转向一个新的地址,相当于重新加载 + * * @param url 新的地址 */ public void redirect(String url) { @@ -127,6 +131,7 @@ public class ModernUIPane extends BasicPane { /** * 转向一个新的地址,相当于重新加载 + * * @param url 新的地址 * @param map 初始化参数 */ @@ -161,7 +166,7 @@ public class ModernUIPane extends BasicPane { public void disposeBrowser() { - if(browser != null) { + if (browser != null) { browser.dispose(); browser = null; } @@ -191,6 +196,12 @@ public class ModernUIPane extends BasicPane { return null; } + + /** + * ModernUIPane 建造者 + * + * @param + */ public static class Builder implements BuilderDiff { private ModernUIPane pane; @@ -219,6 +230,7 @@ public class ModernUIPane extends BasicPane { /** * 加载jar包中的资源 + * * @param path 资源路径 */ public Builder withEMB(final String path) { @@ -229,6 +241,7 @@ public class ModernUIPane extends BasicPane { /** * 加载jar包中的资源 + * * @param path 资源路径 */ public Builder withEMB(final String path, Map map) { @@ -239,6 +252,7 @@ public class ModernUIPane extends BasicPane { /** * 加载url指向的资源 + * * @param url 文件的地址 */ public Builder withURL(final String url) { @@ -249,6 +263,7 @@ public class ModernUIPane extends BasicPane { /** * 加载url指向的资源 + * * @param url 文件的地址 */ public Builder withURL(final String url, Map map) { @@ -259,6 +274,7 @@ public class ModernUIPane extends BasicPane { /** * 加载Atom组件 + * * @param component Atom组件 */ public Builder withComponent(AssembleComponent component) { @@ -269,6 +285,7 @@ public class ModernUIPane extends BasicPane { /** * 加载Atom组件 + * * @param component Atom组件 */ public Builder withComponent(AssembleComponent component, Map map) { @@ -277,9 +294,9 @@ public class ModernUIPane extends BasicPane { return this; } - /** * 加载html文本内容 + * * @param html 要加载html文本内容 */ public Builder withHTML(String html) { @@ -290,6 +307,7 @@ public class ModernUIPane extends BasicPane { /** * 设置该前端页面做数据交换所使用的对象 + * * @param namespace 对象名 */ public Builder namespace(String namespace) { @@ -299,6 +317,7 @@ public class ModernUIPane extends BasicPane { /** * java端往js端传数据时使用的变量名字 + * * @param name 变量的名字 */ public Builder variable(String name) { @@ -308,6 +327,7 @@ public class ModernUIPane extends BasicPane { /** * js端往java端传数据时执行的函数表达式 + * * @param expression 函数表达式 */ public Builder expression(String expression) { 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 index 9e6168514f..99daa4555a 100644 --- 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 @@ -1,5 +1,6 @@ package com.fr.design.ui.compatible; +import com.fr.design.jxbrowser.JxUIPane; import com.fr.design.ui.ModernUIPane; import com.teamdev.jxbrowser.browser.callback.InjectJsCallback; import com.teamdev.jxbrowser.chromium.events.LoadListener; @@ -10,17 +11,45 @@ import com.teamdev.jxbrowser.event.Observer; * 封装jxbrwoser v6/v7的构建方式的差异 * * @author hades - * @version 10.0 - * Created by hades on 2021/6/13 + * @see {@link JxUIPane} + * @since 10.0 + * Created on 2021/6/13 + * @deprecated 6在下个版本弃用 */ +@Deprecated public interface BuilderDiff { + /** + * v6准备工作 + * + * @param contextListener 上下文监听器 + * @return 构造器 + */ ModernUIPane.Builder prepareForV6(ScriptContextListener contextListener); + /** + * v6准备工作 + * + * @param loadListener 加载监听器 + * @return 构造器 + */ ModernUIPane.Builder prepareForV6(LoadListener loadListener); + /** + * v7准备工作 + * + * @param callback 注入js回调器 + * @return 构造器 + */ ModernUIPane.Builder prepareForV7(InjectJsCallback callback); + /** + * v7准备工作 + * + * @param event 事件 + * @param listener 监听器 + * @return 构造器 + */ ModernUIPane.Builder prepareForV7(Class event, Observer listener); } 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 index 68b8950f7c..31774e90c9 100644 --- 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 @@ -1,36 +1,45 @@ package com.fr.design.ui.compatible; +import com.fr.design.jxbrowser.JxUIPane; import com.fr.design.ui.ModernUIPane; -import com.fr.stable.os.OperatingSystem; /** + * 根据版本选择构造器 + * * @author hades - * @version 10.0 - * Created by hades on 2021/6/13 + * @see {@link JxUIPane} + * @since 10.0 + * Created on 2021/6/13 + * @deprecated 6在下个版本弃用 */ public class ModernUIPaneFactory { + /** + * 获取一个 JxBrowser pane 的构造器 + * + * @param 参数 + * @return 构造器 + */ public static ModernUIPane.Builder modernUIPaneBuilder() { - if (isV7()) { - return new NewModernUIPane.Builder<>(); + return new JxUIPane.Builder<>(); } else { return new ModernUIPane.Builder<>(); } - } + /** + * 判断 JxBrowser 版本是否在7或之上 + * + * @return 是否7或之上 + */ public static boolean isV7() { - - // 7.15的class不存在时 走老版本 - boolean hasJxBrowserV7_15 = true; + boolean jxBrowserV7 = true; try { Class.forName("com.teamdev.jxbrowser.net.Scheme"); } catch (ClassNotFoundException e) { - hasJxBrowserV7_15 = false; + jxBrowserV7 = false; } - - return OperatingSystem.isWindows() && hasJxBrowserV7_15; - + return jxBrowserV7; } } 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 deleted file mode 100644 index 59df782cde..0000000000 --- a/designer-base/src/main/java/com/fr/design/ui/compatible/NewModernUIPane.java +++ /dev/null @@ -1,362 +0,0 @@ -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.event.Observer; -import com.teamdev.jxbrowser.js.JsObject; -import com.teamdev.jxbrowser.net.Network; -import com.teamdev.jxbrowser.net.Scheme; -import com.teamdev.jxbrowser.net.callback.VerifyCertificateCallback; -import com.teamdev.jxbrowser.view.swing.BrowserView; -import org.jetbrains.annotations.Nullable; - - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.util.Map; - -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 Scheme scheme; - private NxInterceptRequestCallback requestCallback; - - 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)); - - Browser debugger = browser.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() { - EngineOptions.Builder builder; - if (scheme != null && requestCallback != null) { - builder = EngineOptions.newBuilder(RenderingMode.HARDWARE_ACCELERATED).addSwitch("--disable-google-traffic").addScheme(scheme, requestCallback); - } else { - builder = EngineOptions.newBuilder(RenderingMode.HARDWARE_ACCELERATED).addSwitch("--disable-google-traffic"); - } - - if (DesignerEnvManager.getEnvManager().isOpenDebug()) { - builder.remoteDebuggingPort(9222); - } - - Engine engine = Engine.newInstance(builder.build()); - if (DesignerEnvManager.getEnvManager().isOpenDebug()) { - // 调试模式下,禁止HTTPS证书验证,使得可以正常访问商城测试服务器等 - Network network = engine.network(); - network.set(VerifyCertificateCallback.class, new VerifyCertificateCallback() { - @Nullable - @Override - public Response on(Params params) { - return VerifyCertificateCallback.Response.valid(); - } - }); - } - 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) { - if (requestCallback != null) { - requestCallback.setMap(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 void disposeBrowser() { - - if (browser != null) { - browser.engine().close(); - browser = null; - } - - } - - public void clearCache() { - if (browser != null) { - browser.engine().httpCache().clear(); - } - } - - public void executeJavaScript(String javaScript) { - if (browser != null) { - browser.mainFrame().ifPresent(frame -> { - frame.executeJavaScript(javaScript); - }); - } - } - - public static class Builder extends ModernUIPane.Builder { - - private NewModernUIPane pane = new NewModernUIPane<>(); - - public Builder() { - super((ModernUIPane)null); - } - - 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) { - pane.scheme = Scheme.of("emb"); - pane.requestCallback = new NxComplexInterceptRequestCallback(null); - pane.browser.navigation().loadUrl("emb:" + path); - return this; - } - - /** - * 加载url指向的资源 - * - * @param url 文件的地址 - */ - @Override - public NewModernUIPane.Builder withURL(final String url) { - pane.scheme = Scheme.of("file"); - pane.requestCallback = new NxComplexInterceptRequestCallback(null); - pane.browser.navigation().loadUrl(url); - return this; - } - - /** - * 加载url指向的资源 - * - * @param url 文件的地址 - */ - @Override - public NewModernUIPane.Builder withURL(final String url, Map map) { - pane.scheme = Scheme.of("file"); - pane.requestCallback = new NxInterceptRequestCallback(map); - pane.browser.navigation().loadUrl(url); - return this; - } - - /** - * 加载Atom组件 - * - * @param component Atom组件 - */ - @Override - public NewModernUIPane.Builder withComponent(AssembleComponent component) { - pane.scheme = Scheme.of("emb"); - pane.requestCallback = new NxComplexInterceptRequestCallback(component); - pane.browser.navigation().loadUrl("emb:dynamic"); - return this; - } - - /** - * 加载Atom组件 - * - * @param component Atom组件 - */ - @Override - public NewModernUIPane.Builder withComponent(AssembleComponent component, Map map) { - pane.scheme = Scheme.of("emb"); - pane.requestCallback = new NxComplexInterceptRequestCallback(component, map); - pane.browser.navigation().loadUrl("emb:dynamic"); - return this; - } - - - /** - * 加载html文本内容 - * - * @param html 要加载html文本内容 - */ - @Override - public NewModernUIPane.Builder withHTML(String html) { - pane.scheme = Scheme.of("html"); - pane.requestCallback = new NxInterceptRequestCallback(); - 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 ModernUIPane.Builder prepareForV7(Class event, Observer listener) { - - pane.browser.navigation().on(event, listener); - - return this; - } - - @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 deleted file mode 100644 index eb85495d40..0000000000 --- a/designer-base/src/main/java/com/fr/design/ui/compatible/NxComplexInterceptRequestCallback.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.fr.design.ui.compatible; - -import com.fr.design.ui.ModernRequestClient; -import com.fr.design.ui.ModernUIConstants; -import com.fr.general.IOUtils; -import com.fr.stable.StringUtils; -import com.fr.web.struct.AssembleComponent; -import com.fr.web.struct.AtomBuilder; -import com.fr.web.struct.PathGroup; -import com.fr.web.struct.category.ScriptPath; -import com.fr.web.struct.category.StylePath; - -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.Map; - -/** - * @author richie - * @version 10.0 - * Created by richie on 2020/3/25 - */ -public class NxComplexInterceptRequestCallback extends NxInterceptRequestCallback { - - private AssembleComponent component; - - public NxComplexInterceptRequestCallback(AssembleComponent component) { - this.component = component; - } - - public NxComplexInterceptRequestCallback(AssembleComponent component, Map map) { - super(map); - this.component = component; - } - - @Override - protected Response next(Params params, String path) { - if (path.startsWith("emb:dynamic")) { - String text = htmlText(map); - return Response.intercept(generateBasicUrlRequestJob(params, "text/html", text.getBytes(StandardCharsets.UTF_8))); - } else { - int index = path.indexOf("="); - if (index > 0) { - path = path.substring(index + 1); - } else { - path = path.substring(4); - } - InputStream inputStream = IOUtils.readResource(path); - if (inputStream == null) { - return Response.proceed(); - } - return Response.intercept(generateBasicUrlRequestJob(params, getMimeType(path), IOUtils.inputStream2Bytes(inputStream))); - } - } - - private String htmlText(Map map) { - PathGroup pathGroup = AtomBuilder.create().buildAssembleFilePath(ModernRequestClient.KEY, component); - StylePath[] stylePaths = pathGroup.toStylePathGroup(); - StringBuilder styleText = new StringBuilder(); - for (StylePath path : stylePaths) { - if (StringUtils.isNotBlank(path.toFilePath())) { - styleText.append(""); - } - } - String result = ModernUIConstants.HTML_TPL.replaceAll("##style##", styleText.toString()); - ScriptPath[] scriptPaths = pathGroup.toScriptPathGroup(); - StringBuilder scriptText = new StringBuilder(); - for (ScriptPath path : scriptPaths) { - if (StringUtils.isNotBlank(path.toFilePath())) { - scriptText.append(""); - } - } - result = result.replaceAll("##script##", scriptText.toString()); - if (map != null) { - for (Map.Entry entry : map.entrySet()) { - String key = entry.getKey(); - String value = entry.getValue(); - result = result.replaceAll("\\$\\{" + key + "}", value); - } - } - return result; - } -} \ No newline at end of file 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 deleted file mode 100644 index 32a8f8b610..0000000000 --- a/designer-base/src/main/java/com/fr/design/ui/compatible/NxInterceptRequestCallback.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.fr.design.ui.compatible; - -import com.fr.base.TemplateUtils; -import com.fr.general.IOUtils; -import com.fr.log.FineLoggerFactory; -import com.fr.stable.ArrayUtils; -import com.fr.stable.EncodeConstants; -import com.fr.stable.StringUtils; -import com.fr.third.org.apache.commons.codec.net.URLCodec; -import com.teamdev.jxbrowser.net.HttpHeader; -import com.teamdev.jxbrowser.net.HttpStatus; -import com.teamdev.jxbrowser.net.UrlRequest; -import com.teamdev.jxbrowser.net.UrlRequestJob; - -import com.teamdev.jxbrowser.net.callback.InterceptUrlRequestCallback; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Map; -import java.util.Optional; - -/** - * @author richie - * @version 10.0 - * Created by richie on 2020/3/25 - */ -public class NxInterceptRequestCallback implements InterceptUrlRequestCallback { - - Map map; - - public NxInterceptRequestCallback() { - } - - public NxInterceptRequestCallback(Map map) { - this.map = map; - } - - @Override - public Response on(Params params) { - UrlRequest urlRequest = params.urlRequest(); - String path = urlRequest.url(); - if (path.startsWith("file:")) { - Optional optional = generateFileProtocolUrlRequestJob(params, path); - if (optional.isPresent()) { - return Response.intercept(optional.get()); - } - } else { - return next(params, path); - } - return Response.proceed(); - } - - Response next(Params params, String path) { - return Response.proceed(); - } - - private Optional generateFileProtocolUrlRequestJob(Params params, String path) { - try { - String url = new URLCodec().decode(path); - String filePath = TemplateUtils.renderParameter4Tpl(url, map); - File file = new File(URI.create(filePath).getPath()); - InputStream inputStream = IOUtils.readResource(file.getAbsolutePath()); - String mimeType = getMimeType(path); - byte[] bytes; - if (isPlainText(mimeType)) { - String text = IOUtils.inputStream2String(inputStream, EncodeConstants.ENCODING_UTF_8); - text = TemplateUtils.renderParameter4Tpl(text, map); - bytes = text.getBytes(StandardCharsets.UTF_8); - } else { - bytes = IOUtils.inputStream2Bytes(inputStream); - } - return Optional.of(generateBasicUrlRequestJob(params, mimeType, bytes)); - } catch (Exception e) { - FineLoggerFactory.getLogger().error(e.getMessage(), e); - } - return Optional.empty(); - } - - private boolean isPlainText(String mimeType) { - return ArrayUtils.contains(new String[]{"text/html", "text/javascript", "text/css"}, mimeType); - } - - UrlRequestJob generateBasicUrlRequestJob(Params params, String mimeType, byte[] bytes) { - UrlRequestJob.Options options = UrlRequestJob.Options - .newBuilder(HttpStatus.OK) - .addHttpHeader(HttpHeader.of("Content-Type", mimeType)) - .build(); - UrlRequestJob urlRequestJob = params.newUrlRequestJob(options); - urlRequestJob.write(bytes); - urlRequestJob.complete(); - return urlRequestJob; - } - - 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"; - } - if (path.endsWith(".html")) { - return "text/html"; - } - if (path.endsWith(".css")) { - return "text/css"; - } - if (path.endsWith(".js")) { - return "text/javascript"; - } - if (path.endsWith(".svg")) { - return "image/svg+xml"; - } - if (path.endsWith(".png")) { - return "image/png"; - } - if (path.endsWith(".jpeg")) { - return "image/jpeg"; - } - if (path.endsWith(".gif")) { - return "image/gif"; - } - 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); - } catch (IOException e) { - return "text/html"; - } - } - - public void setMap(Map map) { - this.map = map; - } -} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/update/actions/NewFeatureAction.java b/designer-base/src/main/java/com/fr/design/update/actions/NewFeatureAction.java index 56db4cee9e..320a2a23dc 100644 --- a/designer-base/src/main/java/com/fr/design/update/actions/NewFeatureAction.java +++ b/designer-base/src/main/java/com/fr/design/update/actions/NewFeatureAction.java @@ -1,9 +1,8 @@ package com.fr.design.update.actions; -import com.fr.common.util.Strings; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.utils.BrowseUtils; -import com.fr.general.CloudCenter; import com.fr.log.FineLoggerFactory; import java.awt.event.ActionEvent; @@ -16,17 +15,22 @@ import java.awt.event.ActionListener; * */ public class NewFeatureAction implements ActionListener { + /** + * 云中心更新日志索引在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Latest_Update_Detail"; - public static String DEFAULT_UPDATE_DETAIL_URL = "https://help.fanruan.com/finereport/doc-view-4699.html"; + /** + * 云中心更新日志索引默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Latest_Update_Detail_Default"; + + public static String DEFAULT_UPDATE_DETAIL_URL = LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); @Override public void actionPerformed(ActionEvent e) { try { - String url = CloudCenter.getInstance().acquireConf("fr.latest.update.detil"); - if (Strings.isEmpty(url)) { - url = DEFAULT_UPDATE_DETAIL_URL; - } - BrowseUtils.browser(url); + BrowseUtils.browser(DEFAULT_UPDATE_DETAIL_URL); } catch (Exception ex) { FineLoggerFactory.getLogger().error(ex.getMessage()); } diff --git a/designer-base/src/main/java/com/fr/design/update/push/DesignerPushUpdateConfigManager.java b/designer-base/src/main/java/com/fr/design/update/push/DesignerPushUpdateConfigManager.java index 950d76d7b9..ea279bb036 100644 --- a/designer-base/src/main/java/com/fr/design/update/push/DesignerPushUpdateConfigManager.java +++ b/designer-base/src/main/java/com/fr/design/update/push/DesignerPushUpdateConfigManager.java @@ -15,7 +15,8 @@ public class DesignerPushUpdateConfigManager implements XMLReadable, XMLWriter { private static DesignerPushUpdateConfigManager singleton; private boolean autoPushUpdateEnabled = true; // 是否开启自动推送更新 - private boolean cloudAnalyticsDelay = false; // 是否云端运维模块延迟启动 + private boolean cloudAnalyticsDelay = true; // 是否云端运维模块延迟启动 + private boolean useCloudAnalyticsDelayFirst = true; // 默认打开,如果有手动改延迟启动配置则按客户配置的来 private String lastIgnoredVersion = StringUtils.EMPTY; // 最近一次跳过的更新版本 private DesignerPushUpdateConfigManager() { @@ -33,7 +34,8 @@ public class DesignerPushUpdateConfigManager implements XMLReadable, XMLWriter { if (reader.isAttr()) { this.setAutoPushUpdateEnabled(reader.getAttrAsBoolean("autoPushUpdateEnabled", true)); this.setLastIgnoredVersion(reader.getAttrAsString("lastIgnoredVersion", StringUtils.EMPTY)); - this.setCloudAnalyticsDelay(reader.getAttrAsBoolean("cloudAnalyticsDelay", false)); + this.setCloudAnalyticsDelay(reader.getAttrAsBoolean("cloudAnalyticsDelay", true)); + this.setUseCloudAnalyticsDelayFirst(reader.getAttrAsBoolean("useCloudAnalyticsDelayFirst", true)); } } @@ -43,6 +45,7 @@ public class DesignerPushUpdateConfigManager implements XMLReadable, XMLWriter { writer.attr("autoPushUpdateEnabled", autoPushUpdateEnabled); writer.attr("lastIgnoredVersion", lastIgnoredVersion); writer.attr("cloudAnalyticsDelay", cloudAnalyticsDelay); + writer.attr("useCloudAnalyticsDelayFirst", useCloudAnalyticsDelayFirst); writer.end(); } @@ -69,4 +72,12 @@ public class DesignerPushUpdateConfigManager implements XMLReadable, XMLWriter { public void setCloudAnalyticsDelay(boolean cloudAnalyticsDelay) { this.cloudAnalyticsDelay = cloudAnalyticsDelay; } + + public boolean isUseCloudAnalyticsDelayFirst() { + return useCloudAnalyticsDelayFirst; + } + + public void setUseCloudAnalyticsDelayFirst(boolean useCloudAnalyticsDelayFirst) { + this.useCloudAnalyticsDelayFirst = useCloudAnalyticsDelayFirst; + } } diff --git a/designer-base/src/main/java/com/fr/design/update/push/DesignerPushUpdateDialog.java b/designer-base/src/main/java/com/fr/design/update/push/DesignerPushUpdateDialog.java index e37877a4bb..1db0832c65 100644 --- a/designer-base/src/main/java/com/fr/design/update/push/DesignerPushUpdateDialog.java +++ b/designer-base/src/main/java/com/fr/design/update/push/DesignerPushUpdateDialog.java @@ -1,7 +1,7 @@ package com.fr.design.update.push; import com.fr.design.dialog.UIDialog; -import com.fr.design.ui.ModernUIPane; +import com.fr.design.jxbrowser.JxUIPane; import com.fr.design.utils.BrowseUtils; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.intelli.record.FocusPoint; @@ -14,20 +14,24 @@ import com.fr.web.struct.browser.RequestClient; import com.fr.web.struct.category.ScriptPath; import com.fr.web.struct.category.StylePath; import com.fr.web.struct.impl.FineUI; +import com.teamdev.jxbrowser.js.JsAccessible; import javax.swing.JPanel; -import javax.swing.SwingUtilities; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Frame; /** - * Created by plough on 2019/4/10. + * 设计器推送更新对话框 + * + * @author plough + * @since 10.0 + * Created on 2019/4/10. */ -class DesignerPushUpdateDialog extends UIDialog { +public class DesignerPushUpdateDialog extends UIDialog { public static final Dimension DEFAULT = new Dimension(640, 360); - private ModernUIPane jsPane; + private JxUIPane jsPane; private DesignerPushUpdateDialog(Frame parent) { super(parent); @@ -35,23 +39,23 @@ class DesignerPushUpdateDialog extends UIDialog { initComponents(); } - static void createAndShow(final Frame parent, final DesignerUpdateInfo updateInfo) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - DesignerPushUpdateDialog dialog = new DesignerPushUpdateDialog(parent); - dialog.populate(updateInfo); - dialog.showDialog(); - } - }); - + /** + * 创建并展示窗口 + * + * @param parent 父窗体 + * @param updateInfo 要展示的更新数据 + */ + public static void createAndShow(final Frame parent, final DesignerUpdateInfo updateInfo) { + DesignerPushUpdateDialog dialog = new DesignerPushUpdateDialog(parent); + dialog.populate(updateInfo); + dialog.showDialog(); } private void initComponents() { JPanel contentPane = (JPanel) getContentPane(); contentPane.setLayout(new BorderLayout()); - jsPane = new ModernUIPane.Builder() + jsPane = new JxUIPane.Builder() .withComponent(new AssembleComponent() { @Override public ScriptPath script(RequestClient req) { @@ -67,7 +71,7 @@ class DesignerPushUpdateDialog extends UIDialog { public Atom[] refer() { return new Atom[]{FineUI.KEY}; } - }).namespace("Pool").build(); + }).build(); contentPane.add(jsPane); } @@ -101,6 +105,7 @@ class DesignerPushUpdateDialog extends UIDialog { setVisible(true); } + @JsAccessible public class Model { private String version; private String content; @@ -163,6 +168,7 @@ class DesignerPushUpdateDialog extends UIDialog { exit(); } + @JsAccessible public String i18nText(String key) { return com.fr.design.i18n.Toolkit.i18nText(key); } @@ -180,9 +186,11 @@ class DesignerPushUpdateDialog extends UIDialog { private enum OperateType { CLOSE_WINDOW(0), UPDATE(1), REMIND_NEXT_TIME(2), SKIP(3); private int index; + OperateType(int index) { this.index = index; } + private String toText() { return String.valueOf(this.index); } diff --git a/designer-base/src/main/java/com/fr/design/update/push/DesignerUpdateInfo.java b/designer-base/src/main/java/com/fr/design/update/push/DesignerUpdateInfo.java index 3f7c23cd30..47fbca1716 100644 --- a/designer-base/src/main/java/com/fr/design/update/push/DesignerUpdateInfo.java +++ b/designer-base/src/main/java/com/fr/design/update/push/DesignerUpdateInfo.java @@ -12,9 +12,13 @@ import com.fr.stable.StringUtils; import java.security.InvalidParameterException; /** - * Created by plough on 2019/4/8. + * 设计器更新信息bean + * + * @author plough + * @since 10.0 + * Created on 2019/4/8. */ -class DesignerUpdateInfo { +public class DesignerUpdateInfo { private static final String KEY_VERSION = "version"; private static final String KEY_CONTENT = "content"; private static final String KEY_BACKGROUND_URL = "background"; @@ -32,7 +36,7 @@ class DesignerUpdateInfo { private final String backgroundUrl; // 推送背景图片 url private final String moreInfoUrl; // 更多新特性 - DesignerUpdateInfo(String currentVersion, String latestVersion, String lastIgnoredVersion, JSONObject pushData) { + public DesignerUpdateInfo(String currentVersion, String latestVersion, String lastIgnoredVersion, JSONObject pushData) { this.currentVersion = currentVersion; this.latestVersion = latestVersion; this.latestFullVersion = initLatestFullVersion(); 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 01369116d7..8f44ae197e 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 @@ -40,12 +40,13 @@ import com.teamdev.jxbrowser.chromium.Browser; import com.teamdev.jxbrowser.chromium.JSArray; import com.teamdev.jxbrowser.chromium.JSFunction; import com.teamdev.jxbrowser.chromium.JSObject; +import com.teamdev.jxbrowser.chromium.JSValue; -import java.awt.Desktop; import javax.swing.JFileChooser; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.filechooser.FileNameExtensionFilter; +import java.awt.Desktop; import java.io.File; import java.net.URI; import java.util.ArrayList; @@ -59,7 +60,9 @@ import java.util.concurrent.RunnableFuture; * @version 10.0 * Created by richie on 2019-04-12 * 桥接Java和JavaScript的类 + * @deprecated 用于jxbrowser6,下版本删除 */ +@Deprecated public class UpmBridge { public static UpmBridge getBridge(Browser browser) { @@ -78,6 +81,7 @@ public class UpmBridge { /** * 更新插件管理中心资源文件,这个方法仅仅是为了语义上的作用(更新) + * * @param callback 安装完成后的回调函数 */ @JSBridge @@ -96,6 +100,7 @@ public class UpmBridge { /** * 下载并安装插件管理中心的资源文件 + * * @param callback 安装完成后的回调函数 */ @JSBridge @@ -126,6 +131,7 @@ public class UpmBridge { /** * 获取upm的版本信息 + * * @return 版本信息 */ @JSBridge @@ -291,6 +297,23 @@ public class UpmBridge { PluginOperateUtils.setPluginActive(pluginID, jsCallback); } + /** + * 批量修改选中的插件的活跃状态 + * + * @param pluginIDs 要处理的插件ID + * @param callback 回调函数 + */ + @JSBridge + public void setAllPluginActive(JSArray pluginIDs, final JSFunction callback) { + JSCallback jsCallback = new JSCallback(UpmBrowserExecutor.create(window, callback)); + List list = new ArrayList<>(); + int len = pluginIDs.length(); + for (int i = 0; i < len; i++) { + list.add(pluginIDs.get(i).asString().getValue()); + } + PluginOperateUtils.setPluginActive(list, jsCallback); + } + /** * 选择文件对话框 * @@ -315,7 +338,7 @@ public class UpmBridge { @Override public String call() { FileChooserProvider fileChooserProvider = FileChooserFactory.createFileChooser( - FileChooserArgs.newBuilder(). + FileChooserArgs.newBuilder(). setFileSelectionMode(FileSelectionMode.FILE). setFilter(des, filter).build()); int result = fileChooserProvider.showDialog(UpmFinder.getDialog()); @@ -468,6 +491,7 @@ public class UpmBridge { /** * 使用系统浏览器打开网页 + * * @param url 要打开的网页 */ @JSBridge diff --git a/designer-base/src/main/java/com/fr/design/upm/NewUpmBridge.java b/designer-base/src/main/java/com/fr/design/upm/UpmBridgeV7.java similarity index 95% rename from designer-base/src/main/java/com/fr/design/upm/NewUpmBridge.java rename to designer-base/src/main/java/com/fr/design/upm/UpmBridgeV7.java index 6b9f1f85fc..f35ed11ac0 100644 --- a/designer-base/src/main/java/com/fr/design/upm/NewUpmBridge.java +++ b/designer-base/src/main/java/com/fr/design/upm/UpmBridgeV7.java @@ -28,7 +28,7 @@ import com.fr.stable.StringUtils; import com.teamdev.jxbrowser.js.JsAccessible; import com.teamdev.jxbrowser.js.JsFunction; import com.teamdev.jxbrowser.js.JsObject; - +import com.teamdev.jxbrowser.js.internal.JsArrayImpl; import javax.swing.JFileChooser; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; @@ -45,15 +45,16 @@ import java.util.concurrent.RunnableFuture; * Created by richie on 2019-04-12 * 桥接Java和JavaScript的类 */ -public class NewUpmBridge extends UpmBridge { +@JsAccessible +public class UpmBridgeV7 extends UpmBridge { - public static NewUpmBridge getBridge(JsObject jsObject) { - return new NewUpmBridge(jsObject); + public static UpmBridgeV7 getBridge(JsObject jsObject) { + return new UpmBridgeV7(jsObject); } private JsObject jsObject; - private NewUpmBridge(JsObject jsObject) { + private UpmBridgeV7(JsObject jsObject) { this.jsObject = jsObject; } @@ -264,6 +265,21 @@ public class NewUpmBridge extends UpmBridge { PluginOperateUtils.uninstallPlugin(pluginInfo, isForce, jsCallback); } + /** + * 批量修改选中的插件的活跃状态 + * + * @param pluginIDs 要处理的插件ID + * @param callback 回调函数 + */ + @JSBridge + @JsAccessible + public void setAllPluginActive(JsObject pluginIDs, final JsFunction callback) { + JSCallback jsCallback = new JSCallback(NewUpmBrowserExecutor.create(jsObject, callback)); + List array = ((JsArrayImpl) pluginIDs).toList(); + PluginOperateUtils.setPluginActive(array, jsCallback); + } + + /** * 从插件服务器上安装插件 * 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 576c5a9b96..1158f97aa3 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 @@ -8,6 +8,7 @@ import com.fr.design.i18n.Toolkit; import com.fr.design.login.utils.DesignerLoginUtils; import com.fr.design.mainframe.DesignerContext; import com.fr.design.plugin.DesignerPluginContext; +import com.fr.design.ui.ModernUIConstants; import com.fr.design.update.ui.dialog.UpdateMainDialog; import com.fr.event.Event; import com.fr.event.EventDispatcher; @@ -57,7 +58,8 @@ public class UpmFinder { } public static String getMainResourcePath() { - return "file:///" + StableUtils.pathJoin(installHome, MAIN_RESOURCE_PATH); + return ModernUIConstants.EMB_TAG + ModernUIConstants.SCHEME_HEADER + + StableUtils.pathJoin(installHome, MAIN_RESOURCE_PATH); } public static UIDialog getDialog() { @@ -82,7 +84,7 @@ public class UpmFinder { if (!checkUPMResourcesExist()) { // upm下载 int val = FineJOptionPane.showConfirmDialog(null, Toolkit.i18nText("Fine-Design_Basic_Plugin_Shop_Need_Install"), - Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (val == JOptionPane.OK_OPTION) { try { UpmResourceLoader.INSTANCE.download(); 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 23a712508e..3035835cf1 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 @@ -1,19 +1,13 @@ 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.jxbrowser.JxUIPane; 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.*; +import java.awt.BorderLayout; /** * @author richie @@ -23,7 +17,9 @@ import java.awt.*; */ public class UpmShowPane extends BasicPane { - private ModernUIPane modernUIPane; + public static final String PLUGIN_HELPER = "PluginHelper"; + + private final JxUIPane jxUIPane; @Override protected String title4PopupWindow() { @@ -32,28 +28,22 @@ public class UpmShowPane extends BasicPane { UpmShowPane() { setLayout(new BorderLayout()); - modernUIPane = new ModernUIPane.Builder<>() - .prepare(new ScriptContextAdapter() { - @Override - public void onScriptContextCreated(ScriptContextEvent event) { - JSValue window = event.getBrowser().executeJavaScriptAndReturnValue("window"); - window.asObject().setProperty("PluginHelper", UpmBridge.getBridge(event.getBrowser())); - } - }) + jxUIPane = new JxUIPane.Builder<>() + .bindWindow(PLUGIN_HELPER, UpmBridgeV7::getBridge) .withURL(UpmFinder.getMainResourcePath(), UpmUtils.renderMap()) .build(); EventDispatcher.listen(DownloadEvent.UPDATE, new Listener() { @Override public void on(Event event, String param) { - modernUIPane.redirect(UpmFinder.getMainResourcePath(), UpmUtils.renderMap()); + jxUIPane.redirect(UpmFinder.getMainResourcePath(), UpmUtils.renderMap()); } }); EventDispatcher.listen(DownloadEvent.UPDATE, new Listener() { @Override public void on(Event event, String param) { - modernUIPane.redirect(UpmFinder.getMainResourcePath(), UpmUtils.renderMap()); + jxUIPane.redirect(UpmFinder.getMainResourcePath(), UpmUtils.renderMap()); } }); - add(modernUIPane, BorderLayout.CENTER); + add(jxUIPane, BorderLayout.CENTER); } } diff --git a/designer-base/src/main/java/com/fr/design/upm/UpmUtils.java b/designer-base/src/main/java/com/fr/design/upm/UpmUtils.java index 3d8252b759..3c8fe1caec 100644 --- a/designer-base/src/main/java/com/fr/design/upm/UpmUtils.java +++ b/designer-base/src/main/java/com/fr/design/upm/UpmUtils.java @@ -4,6 +4,7 @@ import com.fr.common.annotations.Negative; import com.fr.config.ServerPreferenceConfig; import com.fr.general.CloudCenter; import com.fr.general.GeneralContext; +import com.fr.general.GeneralUtils; import com.fr.stable.StringUtils; import java.util.ArrayList; @@ -32,6 +33,7 @@ public class UpmUtils { Map map4Tpl = new HashMap<>(); map4Tpl.put("version", ServerPreferenceConfig.getInstance().getOptimizedUPMVersion()); map4Tpl.put("new_version", fetchLatestVersion()); + map4Tpl.put("designer_version", GeneralUtils.getVersion()); map4Tpl.put("language", GeneralContext.getLocale().toString()); return map4Tpl; } diff --git a/designer-base/src/main/java/com/fr/design/utils/DesignUtils.java b/designer-base/src/main/java/com/fr/design/utils/DesignUtils.java index afe21e2ccb..6715764ef4 100644 --- a/designer-base/src/main/java/com/fr/design/utils/DesignUtils.java +++ b/designer-base/src/main/java/com/fr/design/utils/DesignUtils.java @@ -28,7 +28,6 @@ import com.fr.stable.StableUtils; import com.fr.stable.StringUtils; import com.fr.stable.bridge.ObjectHolder; import com.fr.stable.os.OperatingSystem; -import com.fr.stable.plugin.ExtraDesignClassManagerProvider; import com.fr.start.ServerStarter; import com.fr.start.common.DesignerStartupContext; import com.fr.start.common.DesignerStartupUtil; @@ -68,8 +67,8 @@ import java.util.concurrent.TimeoutException; * Some util method of Designer */ public class DesignUtils { - private static int port = DesignerPort.getInstance().getMessagePort(); + private static Integer port; private static boolean started = false; @@ -82,6 +81,9 @@ public class DesignUtils { } public synchronized static int getPort() { + if (port == null) { + setPort(DesignerPort.getInstance().getMessagePort()); + } return port; } @@ -95,7 +97,6 @@ public class DesignUtils { return started; } - /** * 判断设计器端口是否被其他程序占用 * 尝试去通信,无回应就是其他程序占用端口,否则需要继续判断是否为设计器进程未关闭 @@ -105,7 +106,7 @@ public class DesignUtils { public static boolean isPortOccupied() { ExecutorService executor = null; Future future = null; - try (Socket socket = new Socket("localhost", port); + try (Socket socket = new Socket("localhost", getPort()); BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8)); PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8)))) { writer.println("check"); @@ -169,7 +170,7 @@ public class DesignUtils { if (lines == null || lines.length == 0) { return; } - try (Socket socket = new Socket("localhost", port)) { + try (Socket socket = new Socket("localhost", getPort())) { clientSend(lines, socket); } catch (Exception ignore) { @@ -192,7 +193,7 @@ public class DesignUtils { try { serverSocket = new ServerSocket(startPort); } catch (IOException e1) { - FineLoggerFactory.getLogger().error("Cannot create server socket on " + port); + FineLoggerFactory.getLogger().error("Cannot create server socket on " + getPort()); } while (true) { try { @@ -223,7 +224,7 @@ public class DesignUtils { @Override public void run() { DesignerStartupContext context = DesignerStartupContext.getInstance(); - + // 如果在启动页展示中 if (DesignerStartupUtil.openTemplateIfOnWaiting(f)) { return; @@ -233,12 +234,12 @@ public class DesignUtils { // 之前就有这样的问题 return; } - + // 打开模板 DesignerContext.getDesignerFrame().openTemplate(new FileFILE(f)); } }); - } else { + } else if (DeepLinkCore.getInstance().accept(line)) { String url = line; UIUtil.invokeLaterIfNeeded(new Runnable() { @Override @@ -252,7 +253,7 @@ public class DesignUtils { reader.close(); socket.close(); } else { - FineLoggerFactory.getLogger().error("Cannot create server socket on " + port); + FineLoggerFactory.getLogger().error("Cannot create server socket on " + getPort()); break; } } catch (IOException ignored) { @@ -346,7 +347,7 @@ public class DesignUtils { @Override protected FRFont compute() { FRFont guiFRFont; - Locale defaultLocale = Locale.getDefault(); + Locale defaultLocale = GeneralContext.getLocale(); // JDK9 之后宋体在计算label中字母的空间上出现问题,暂时先用雅黑兼容,以后再统一字体 if (StableUtils.getMajorJavaVersion() >= 9 && OperatingSystem.isWindows()) { guiFRFont = getNamedFont("Microsoft YaHei"); @@ -495,6 +496,7 @@ public class DesignUtils { /** * 获取设计器可用字体 + * * @return */ public static String[] getAvailableFontFamilyNames4Report() { diff --git a/designer-base/src/main/java/com/fr/design/utils/SvgDraw.java b/designer-base/src/main/java/com/fr/design/utils/SvgDraw.java new file mode 100644 index 0000000000..0ae7ff7af8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/utils/SvgDraw.java @@ -0,0 +1,16 @@ +package com.fr.design.utils; + +/** + * 绘制SVG图标的函数式接口 + * + * @author obo + * @since 11.0 + * Created on 2023/3/24 + */ +public interface SvgDraw { + + /** + * 绘制svg图标的具体逻辑,方法体 + * */ + void drawSVG(); +} diff --git a/designer-base/src/main/java/com/fr/design/utils/SvgDrawUtils.java b/designer-base/src/main/java/com/fr/design/utils/SvgDrawUtils.java new file mode 100644 index 0000000000..5754b2f8d7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/utils/SvgDrawUtils.java @@ -0,0 +1,73 @@ +package com.fr.design.utils; + +import com.fr.base.svg.SVGLoader; +import com.fr.base.svg.SystemScaleUtils; +import org.jetbrains.annotations.NotNull; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.ImageObserver; + +/** + * 用于绘制svg图片缩放(高分屏下) + * + * @author hades + * @since 11.0 + * Created on 2022/5/6 + */ +public class SvgDrawUtils { + + private static final boolean HI_DPI_ENABLED = SystemScaleUtils.isJreHiDPIEnabled(); + + /** + * 绘制svg前若环境支持高清化则对缩放比例进行适配 + * */ + public static void beforeDraw(Graphics2D g2) { + if (HI_DPI_ENABLED) { + g2.scale(1 / SVGLoader.SYSTEM_SCALE, 1 / SVGLoader.SYSTEM_SCALE); + } + } + + /** + * 绘制svg后还原缩放矩阵 + * */ + public static void afterDraw(Graphics2D g2) { + if (HI_DPI_ENABLED) { + g2.scale(SVGLoader.SYSTEM_SCALE, SVGLoader.SYSTEM_SCALE); + } + } + + /** + * 计算高缩放下绘制svg图标时新的的位置x,y + * @param position 旧坐标的值 + * @return 新的position值 + * */ + public static int calculatePosition(int position) { + return HI_DPI_ENABLED ? (int) (position * SVGLoader.SYSTEM_SCALE) : position; + } + + /** + * 绘制svg图像的完整逻辑 + * @param graphics 绘图 + * @param svgDraw 具体绘制逻辑 + * */ + public static void doDrawSVG(@NotNull Graphics graphics, @NotNull final SvgDraw svgDraw) { + SvgDrawUtils.beforeDraw((Graphics2D) graphics); + svgDraw.drawSVG(); + SvgDrawUtils.afterDraw((Graphics2D) graphics); + } + + /** + * 绘制前对坐标x和y进行处理 + * @param graphics 绘图 + * @param image svg的Image对象 + * @param x x坐标 + * @param y y坐标 + * @param imageObserver 图像观察器 + * */ + public static void drawImage(Graphics graphics, Image image, int x, int y, ImageObserver imageObserver) { + //如果环境支持高清化,在调整缩放比例时绘制svg会影响到位置的变化,若图标无确定裁剪位置,则需要进行调整 + graphics.drawImage(image, SvgDrawUtils.calculatePosition(x), SvgDrawUtils.calculatePosition(y), imageObserver); + } +} diff --git a/designer-base/src/main/java/com/fr/design/utils/SvgPaintUtils.java b/designer-base/src/main/java/com/fr/design/utils/SvgPaintUtils.java deleted file mode 100644 index fdb460eb41..0000000000 --- a/designer-base/src/main/java/com/fr/design/utils/SvgPaintUtils.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.fr.design.utils; - -import com.fr.base.svg.SVGLoader; -import com.fr.base.svg.SystemScaleUtils; -import java.awt.Graphics2D; - -/** - * 用于绘制svg图片缩放(高分屏下) - * - * @author hades - * @version 11.0 - * Created by hades on 2022/5/6 - */ -public class SvgPaintUtils { - - public static void beforePaint(Graphics2D g2) { - if (SystemScaleUtils.isJreHiDPIEnabled()) { - g2.scale(1 / SVGLoader.SYSTEM_SCALE, 1 / SVGLoader.SYSTEM_SCALE); - } - } - - public static void afterPaint(Graphics2D g2) { - if (SystemScaleUtils.isJreHiDPIEnabled()) { - g2.scale(SVGLoader.SYSTEM_SCALE, SVGLoader.SYSTEM_SCALE); - } - } - -} diff --git a/designer-base/src/main/java/com/fr/design/utils/TemplateUtils.java b/designer-base/src/main/java/com/fr/design/utils/TemplateUtils.java index e828552b45..efaef8695f 100644 --- a/designer-base/src/main/java/com/fr/design/utils/TemplateUtils.java +++ b/designer-base/src/main/java/com/fr/design/utils/TemplateUtils.java @@ -16,12 +16,18 @@ import com.fr.log.FineLoggerFactory; import com.fr.stable.ArrayUtils; import com.fr.stable.CoreConstants; import com.fanruan.product.ProductConstants; +import com.fr.stable.ProductConstants; +import com.fr.stable.StringUtils; import com.fr.workspace.WorkContext; import com.fr.workspace.server.lock.TplOperator; +import org.jetbrains.annotations.Nullable; import javax.swing.SwingWorker; import java.io.OutputStream; +import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; import java.util.stream.Collectors; /** @@ -33,22 +39,74 @@ public class TemplateUtils { /** * 创建新的模板文件并打开模板 - * @param prefix 模板文件名称前缀 - * @param file 模板文件 + * + * @param prefix 模板文件名称前缀 + * @param file 模板文件 * @param createByEditingTemplate 是否根据 当前编辑模板 来创建新模板 * 为true时以CurrentEditingTemplate为准创建新模板 * 为false时以传入的File文件为准创建新模板,此文件可以不是编辑状态 - * @param openNewTemplate 是否需要在创建后打开模板 + * @param openNewTemplate 是否需要在创建后打开模板 */ public static void createAndOpenTemplate(String prefix, FILE file, boolean createByEditingTemplate, boolean openNewTemplate) { - String fileName = file.getName(); + createAndOpenTemplate(prefix, file, createByEditingTemplate, openNewTemplate, null); + } + + /** + * 创建新的模板文件并并判断新的模板文件是否之前已经被开打,如果已经打开需要reOpen + * + * @param prefix 模板文件名称前缀 + * @param file 模板文件 + * @param createByEditingTemplate 是否根据 当前编辑模板 来创建新模板 + * 为true时以CurrentEditingTemplate为准创建新模板 + * 为false时以传入的File文件为准创建新模板,此文件可以不是编辑状态 + * @param openNewTemplate 是否需要在创建后打开模板 + */ + public static void createAndReOpenTemplate(String prefix, FILE file, boolean createByEditingTemplate, boolean openNewTemplate) { + String oldPath = file.getPath(); + file = getSavedFile(prefix, file); + if (file == null) { + return; + } + createAndOpenTemplate0(file, oldPath, createByEditingTemplate, openNewTemplate, null); + } + + /** + * 创建新的模板文件并打开模板,并在创建备份模板成功后执行doAfterCreate + * + * @param prefix 模板文件名称前缀 + * @param file 模板文件 + * @param createByEditingTemplate 是否根据 当前编辑模板 来创建新模板 + * 为true时以CurrentEditingTemplate为准创建新模板 + * 为false时以传入的File文件为准创建新模板,此文件可以不是编辑状态 + * @param openNewTemplate 是否需要在创建后打开模板 + * @param template 备份成功后需要关闭的模板 + */ + public static void createAndOpenTemplate(String prefix, FILE file, boolean createByEditingTemplate, boolean openNewTemplate, @Nullable JTemplate template) { String oldPath = file.getPath(); + file = getSavedFile(prefix, file); + if (file == null) { + return; + } + + createAndOpenTemplate0(file, oldPath, createByEditingTemplate, openNewTemplate, template); + } + + /** + * 返回值可以为null, 为null表示没有点击保存按钮或者传递进来的文件file本身不满足格式要求 + * + * @param prefix 模板文件名称前缀 + * @param file 模板文件 + * @return 最后选择的要保存的文件 + */ + @Nullable + private static FILE getSavedFile(String prefix, FILE file) { + String fileName = file.getName(); int indexOfLastDot = fileName.lastIndexOf(CoreConstants.DOT); if (indexOfLastDot < 0) { - return; + return null; } String suffix = fileName.substring(indexOfLastDot + 1); - FILEChooserPane fileChooserPane = FILEChooserPane.getInstance(true, true); + FILEChooserPane fileChooserPane = FILEChooserPane.getInstance(true, true); fileChooserPane.setFileNameTextField(prefix + fileName, suffix); FileExtension fileExtension = FileExtension.parse(suffix); fileChooserPane.addChooseFILEFilter(new ChooseFileFilter(fileExtension, ProductConstants.APP_NAME + Toolkit.i18nText("Fine-Design_Report_Template_File"))); @@ -57,36 +115,38 @@ public class TemplateUtils { fileChooserPane.enableFileNameTextFiled(); if (isCancel(result)) { - return; + return null; } if (isOk(result)) { - file = fileChooserPane.getSelectedFILE(); - _createAndOpenTemplate(file, oldPath, createByEditingTemplate, openNewTemplate); + return fileChooserPane.getSelectedFILE(); } - } - - private static void _createAndOpenTemplate(FILE file, String oldPath, boolean createByEditingTemplate, boolean openNewTemplate){ - new SwingWorker() { + return null; + } - @Override - protected Void doInBackground() throws Exception { - byte[] content = new byte[0]; - if (createByEditingTemplate) { - // 从当前编辑模板中生成备份文件 - JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - content = template.exportData(); - } else { - content = WorkContext.getWorkResource().readFully(oldPath); - } - if (ArrayUtils.isEmpty(content)) { - throw new Exception(oldPath + " content is empty" ); - } + /** + * 生成备份模板 + * + * @param file saveAs的模板文件 + * @param createByEditingTemplate 是否根据 当前编辑模板 来创建新模板 + * 为true时以CurrentEditingTemplate为准创建新模板 + * 为false时以传入的File文件为准创建新模板,此文件可以不是编辑状态 + * @param oldPath 被saveAs的文件路径 + */ + private static CompletableFuture createTemplate(FILE file, String oldPath, boolean createByEditingTemplate) { + return CompletableFuture.supplyAsync(() -> { + try { + // 读取模板数据 + byte[] content = getTemplateData(createByEditingTemplate, oldPath); OutputStream out = null; try { // 加锁 - WorkContext.getCurrent().get(TplOperator.class).saveAs(file.getPath()); + boolean saveAsLock = WorkContext.getCurrent().get(TplOperator.class).saveAs(file.getPath()); + if (!saveAsLock) { + // 加锁失败时,直接返回 + throw new RuntimeException("[RemoteDesign] back up template file failed"); + } out = file.asOutputStream(); out.write(content); } finally { @@ -98,19 +158,51 @@ public class TemplateUtils { // 解锁 WorkContext.getCurrent().get(TplOperator.class).closeAndFreeFile(file.getPath()); } - } - return null; + return true; + } catch (Exception e) { + SaveFailureHandler.getInstance().process(e); + FineLoggerFactory.getLogger().error(e.getMessage(), e); + return false; } + }); + } + /** + * 打开saveAs的新模板并关闭指定的旧模板 + * + * @param file 模板文件 + * @param openNewTemplate 是否需要打开新模板 + * @param template 需要关闭的模板 + */ + private static void openNewTemplateAndCloseOldTemplate(FILE file, boolean openNewTemplate, @Nullable JTemplate template) { + new SwingWorker>, Void>() { + @Override + protected List> doInBackground() throws Exception { + List> needCloseTemplate = new ArrayList<>(); + //判断一下要保存的副本文件是否已打开 + int index = HistoryTemplateListCache.getInstance().contains(file); + if (index != -1) { + WorkContext.getCurrent().get(TplOperator.class).closeAndFreeFile(file.getPath()); + needCloseTemplate.add(HistoryTemplateListCache.getInstance().getHistoryList().get(index)); + } + if (JTemplate.isValid(template)) { + //给要关闭的模板解锁 + WorkContext.getCurrent().get(TplOperator.class).closeAndFreeFile(template.getPath()); + needCloseTemplate.add(template); + } + return needCloseTemplate; + } @Override protected void done() { try { - get(); + //获取需要关闭的模板 + List> jTemplates = get(); + jTemplates.forEach(jTemplate -> HistoryTemplateListCache.getInstance().closeSelectedReport(jTemplate)); if (openNewTemplate) { DesignerContext.getDesignerFrame().openTemplate(file); } - // 备份成功刷新下目录树 展示出来备份的模板 + // 刷新下目录树 TemplateTreePane.getInstance().refresh(); } catch (Exception e) { SaveFailureHandler.getInstance().process(e); @@ -118,7 +210,40 @@ public class TemplateUtils { } } }.execute(); + } + + private static void createAndOpenTemplate0(FILE file, String oldPath, boolean createByEditingTemplate, boolean openNewTemplate, @Nullable JTemplate template) { + createTemplate(file, oldPath, createByEditingTemplate).thenApply((Function) aBoolean -> { + if (aBoolean) { + openNewTemplateAndCloseOldTemplate(file, openNewTemplate, template); + } + return null; + }); + } + /** + * 读取模板文件数据 + * + * @param readCurrentEditingTemplate 是否读取当前编辑模板 + * @param path 模板路径 + * @return 模板文件数据 + */ + private static byte[] getTemplateData(boolean readCurrentEditingTemplate, String path) throws Exception { + byte[] content = new byte[0]; + if (readCurrentEditingTemplate) { + // 从当前编辑模板中读取模板文件数据 + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (JTemplate.isValid(template)) { + content = template.exportData(); + } + } else { + // 从给定的模板路径中读取模板文件数据 + content = WorkContext.getWorkResource().readFully(path); + } + if (ArrayUtils.isEmpty(content)) { + throw new Exception(StringUtils.messageFormat("{} content is empty", path)); + } + return content; } private static boolean isCancel(int result) { diff --git a/designer-base/src/main/java/com/fr/design/utils/gui/AdjustWorkBookDefaultStyleUtils.java b/designer-base/src/main/java/com/fr/design/utils/gui/AdjustWorkBookDefaultStyleUtils.java index c3c087b4db..4bc1794561 100644 --- a/designer-base/src/main/java/com/fr/design/utils/gui/AdjustWorkBookDefaultStyleUtils.java +++ b/designer-base/src/main/java/com/fr/design/utils/gui/AdjustWorkBookDefaultStyleUtils.java @@ -18,13 +18,23 @@ public class AdjustWorkBookDefaultStyleUtils { private static final Color TEMPLATE_BACKGROUND = new Color(16, 11, 43); private static final Color CELL_ELEMENT_BORDER = new Color(110, 110, 110); private static final Color CELL_ELEMENT_FONT_FOREGROUND = Color.WHITE; + private static final Color CELL_ELEMENT_FONT_FOREGROUND_4_LIGHT_THEME = Color.BLACK; private static Color currentStoryBack = null; + private static boolean isDarkTheme = true; public static void setCurrentStoryBack(Color color) { currentStoryBack = color; } + public static void setIsDarkTheme(boolean isDarkTheme) { + AdjustWorkBookDefaultStyleUtils.isDarkTheme = isDarkTheme; + } + + private static Color getCellForegroundColor() { + return isDarkTheme ? CELL_ELEMENT_FONT_FOREGROUND : CELL_ELEMENT_FONT_FOREGROUND_4_LIGHT_THEME; + } + private static Color getCurrentStoryBack() { return currentStoryBack == null ? TEMPLATE_BACKGROUND : currentStoryBack; } @@ -39,7 +49,7 @@ public class AdjustWorkBookDefaultStyleUtils { public static Style adjustCellElement(Style style) { if (DesignModeContext.isDuchampMode()) { - style = style.deriveFRFont(style.getFRFont().applyForeground(CELL_ELEMENT_FONT_FOREGROUND)); + style = style.deriveFRFont(style.getFRFont().applyForeground(getCellForegroundColor())); style = style.deriveBorder(0, CELL_ELEMENT_BORDER, 0, CELL_ELEMENT_BORDER, 0, CELL_ELEMENT_BORDER, @@ -49,7 +59,7 @@ public class AdjustWorkBookDefaultStyleUtils { } public static Color adjustCellElementFontForeground(Color color) { - return DesignModeContext.isDuchampMode() ? CELL_ELEMENT_FONT_FOREGROUND : color; + return DesignModeContext.isDuchampMode() ? getCellForegroundColor() : color; } public static void adjustFloatElement(FloatElement floatElement) { diff --git a/designer-base/src/main/java/com/fr/design/utils/gui/GUICoreUtils.java b/designer-base/src/main/java/com/fr/design/utils/gui/GUICoreUtils.java index d90f2af422..91661301f1 100644 --- a/designer-base/src/main/java/com/fr/design/utils/gui/GUICoreUtils.java +++ b/designer-base/src/main/java/com/fr/design/utils/gui/GUICoreUtils.java @@ -792,7 +792,7 @@ public final class GUICoreUtils { return false; } - int returnVal = FineJOptionPane.showConfirmDialog(ancestorWindow, com.fr.design.i18n.Toolkit.i18nText(key), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Remove"), + int returnVal = FineJOptionPane.showConfirmDialog(ancestorWindow, com.fr.design.i18n.Toolkit.i18nText(key), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (returnVal == JOptionPane.OK_OPTION) { int minSelectedIndex = nodeList.getMinSelectionIndex(); diff --git a/designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java b/designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java index 0d10600b64..69ca667bb6 100644 --- a/designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java +++ b/designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java @@ -230,7 +230,7 @@ public class VersionCheckUtils { Set localServiceSet = FineObjectPool.getInstance().getServerPool().keySet(); try { - JSONArray serviceArray = new FunctionalHttpRequest(info).getServiceList(); + JSONArray serviceArray = new FunctionalHttpRequest(info).getServiceList(info); for (int i = 0; i < serviceArray.size(); i++) { try { Class clazz = Class.forName((String) serviceArray.get(i)); diff --git a/designer-base/src/main/java/com/fr/design/widget/btn/ButtonConstants.java b/designer-base/src/main/java/com/fr/design/widget/btn/ButtonConstants.java index 9be9a8fba4..3efc320d84 100644 --- a/designer-base/src/main/java/com/fr/design/widget/btn/ButtonConstants.java +++ b/designer-base/src/main/java/com/fr/design/widget/btn/ButtonConstants.java @@ -44,4 +44,20 @@ public class ButtonConstants { StableFactory.getMarkedClass(BridgeMark.SUBMIT_BUTTON, Widget.class), StableFactory.getMarkedClass(BridgeMark.TREE_NODE_TOGGLE_BUTTON, Widget.class) }; + + public static final String[] TYPES_BUTTON_NO_FREE = { + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Common"), + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Utils_Insert_Row"), + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Delete_Row"), + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Button_Type_Parameter_Submit"), + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_TreeNode") + }; + + public static final Class[] CLASSES_BUTTON_NO_FREE = { + Button.class, + StableFactory.getMarkedClass(BridgeMark.APPEND_ROW_BUTTON, Widget.class), + StableFactory.getMarkedClass(BridgeMark.DELETE_ROW_BUTTON, Widget.class), + StableFactory.getMarkedClass(BridgeMark.SUBMIT_BUTTON, Widget.class), + StableFactory.getMarkedClass(BridgeMark.TREE_NODE_TOGGLE_BUTTON, Widget.class) + }; } diff --git a/designer-base/src/main/java/com/fr/design/widget/btn/ButtonDetailPane.java b/designer-base/src/main/java/com/fr/design/widget/btn/ButtonDetailPane.java index 63d678577a..2b73a3fe7f 100644 --- a/designer-base/src/main/java/com/fr/design/widget/btn/ButtonDetailPane.java +++ b/designer-base/src/main/java/com/fr/design/widget/btn/ButtonDetailPane.java @@ -1,11 +1,9 @@ package com.fr.design.widget.btn; +import com.fr.design.beans.BasicBeanPane; import com.fr.design.gui.icombobox.DictionaryComboBox; import com.fr.design.dialog.BasicPane; -import com.fr.design.widget.btn.ButtonConstants; import com.fr.form.ui.Button; - - import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.event.ActionEvent; @@ -13,6 +11,7 @@ import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; + /** * Created by IntelliJ IDEA. * Author : Richer @@ -22,7 +21,7 @@ import java.util.List; */ public abstract class ButtonDetailPane extends BasicPane { private List ls = new ArrayList(); - + protected final List> extraPaneList = new ArrayList<>(); @Override public String title4PopupWindow() { return com.fr.design.i18n.Toolkit.i18nText("Button"); @@ -49,7 +48,10 @@ public abstract class ButtonDetailPane extends BasicPane { public abstract Class classType(); protected DictionaryComboBox createButtonTypeComboBox() { - final DictionaryComboBox dictionaryComboBox = new DictionaryComboBox(ButtonConstants.CLASSES4BUTTON, ButtonConstants.TYPES4BUTTON, false); + return createButtonTypeComboBox(false); + } + + private DictionaryComboBox initDictionaryComboBox(DictionaryComboBox dictionaryComboBox) { dictionaryComboBox.setSelectedItem(classType()); dictionaryComboBox.addActionListener(new ActionListener() { @Override @@ -59,4 +61,14 @@ public abstract class ButtonDetailPane extends BasicPane { }); return dictionaryComboBox; } + + protected DictionaryComboBox createButtonTypeComboBox(Boolean containsExtraPane) { + final DictionaryComboBox dictionaryComboBox; + if (!containsExtraPane) { + dictionaryComboBox = new DictionaryComboBox(ButtonConstants.CLASSES4BUTTON, ButtonConstants.TYPES4BUTTON, false); + } else { + dictionaryComboBox = new DictionaryComboBox(ButtonConstants.CLASSES_BUTTON_NO_FREE, ButtonConstants.TYPES_BUTTON_NO_FREE, false); + } + return initDictionaryComboBox(dictionaryComboBox); + } } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/widget/btn/ButtonWithHotkeysDetailPane.java b/designer-base/src/main/java/com/fr/design/widget/btn/ButtonWithHotkeysDetailPane.java index b75aeaa81f..d146c73099 100644 --- a/designer-base/src/main/java/com/fr/design/widget/btn/ButtonWithHotkeysDetailPane.java +++ b/designer-base/src/main/java/com/fr/design/widget/btn/ButtonWithHotkeysDetailPane.java @@ -6,6 +6,7 @@ import javax.swing.*; import com.fr.design.designer.IntervalConstants; import com.fr.design.foldablepane.UIExpandablePane; +import com.fr.design.gui.icombobox.DictionaryComboBox; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.itextfield.UITextField; import com.fr.design.layout.FRGUIPaneFactory; @@ -42,8 +43,9 @@ public abstract class ButtonWithHotkeysDetailPane extends Butt JPanel labelPane = FRGUIPaneFactory.createNormalFlowInnerContainer_S_Pane(); iconPane = new AccessibleIconEditor(); labelPane.add(iconPane); + Component comp = createCenterPane(); Component[][] n_components = { - {new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Button_Type")), createButtonTypeComboBox()}, + {new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Button_Type")), createCustomButtonTypeComboBox()}, {new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Button_Name")), buttonNameTextField = new UITextField()}, {new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Button_Icon")), iconPane}, {new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Button_Hot_keys")), hotkeysTextField = new UITextField()}, @@ -52,7 +54,6 @@ public abstract class ButtonWithHotkeysDetailPane extends Butt JPanel panel = TableLayoutHelper.createGapTableLayoutPane(n_components, rowSize, columnSize, IntervalConstants.INTERVAL_W1, IntervalConstants.INTERVAL_L1); panel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); advancePane.add(panel, BorderLayout.NORTH); - Component comp = createCenterPane(); if(comp != null ) { advancePane.add(comp,BorderLayout.CENTER); } @@ -63,6 +64,13 @@ public abstract class ButtonWithHotkeysDetailPane extends Butt protected abstract Component createCenterPane(); + /** + * 判断是按钮控件下拉框的种类:1.有自定义按钮 2.无自定义按钮 + */ + protected DictionaryComboBox createCustomButtonTypeComboBox() { + return createButtonTypeComboBox(); + } + @Override public void populate(T button) { if (button == null) { diff --git a/designer-base/src/main/java/com/fr/design/widget/component/NumberEditorValidatePane.java b/designer-base/src/main/java/com/fr/design/widget/component/NumberEditorValidatePane.java index 7fd88dd957..867d66cdfd 100644 --- a/designer-base/src/main/java/com/fr/design/widget/component/NumberEditorValidatePane.java +++ b/designer-base/src/main/java/com/fr/design/widget/component/NumberEditorValidatePane.java @@ -255,7 +255,6 @@ public class NumberEditorValidatePane extends JPanel { allowNegativeCheckBox.setSelected(e.isAllowNegative()); if (AssistUtils.equals(e.getMaxValue(),Double.MAX_VALUE)) { setMaxValueCheckBox.setSelected(false); - maxValueSpinner.setValue(Double.MAX_VALUE); maxValueSpinner.setEnabled(false); } else { setMaxValueCheckBox.setSelected(true); @@ -265,7 +264,6 @@ public class NumberEditorValidatePane extends JPanel { if (AssistUtils.equals(e.getMinValue(),-Double.MAX_VALUE)) { setMinValueCheckBox.setSelected(false); - minValueSpinner.setValue(-Double.MAX_VALUE); minValueSpinner.setEnabled(false); } else { diff --git a/designer-base/src/main/java/com/fr/design/worker/save/CallbackSaveWorker.java b/designer-base/src/main/java/com/fr/design/worker/save/CallbackSaveWorker.java index ed2597f1d7..b7a50a3af1 100644 --- a/designer-base/src/main/java/com/fr/design/worker/save/CallbackSaveWorker.java +++ b/designer-base/src/main/java/com/fr/design/worker/save/CallbackSaveWorker.java @@ -1,5 +1,6 @@ package com.fr.design.worker.save; +import com.fr.base.info.TemplateSaveInfoContext; import com.fr.common.util.Collections; import com.fr.design.mainframe.JTemplate; import java.util.LinkedList; @@ -34,6 +35,8 @@ public class CallbackSaveWorker extends SaveWorker { } successRunnableList = null; failRunnableList = null; + TemplateSaveInfoContext.getInstance().stopRecord(); + TemplateSaveInfoContext.getInstance().setSaveCompleted(success); } private void fireRunnable(List list) { 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 index 080b9ddbcd..bf6209cf6b 100644 --- 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 @@ -2,18 +2,17 @@ package com.fr.design.worker.save; import com.fr.common.exception.ThrowableHandler; import com.fr.design.dialog.FineJOptionPane; -import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.i18n.Toolkit; +import com.fr.design.lock.LockFileReSaveEnum; +import com.fr.design.lock.LockInfoDialog; import com.fr.design.mainframe.DesignerContext; -import com.fr.design.mainframe.JTemplate; import com.fr.design.ui.util.UIUtil; -import com.fr.design.utils.TemplateUtils; -import com.fr.file.FileNodeFILE; -import com.fr.file.filetree.FileNode; import com.fr.general.IOUtils; +import com.fr.report.InconsistentLockException; +import com.fr.report.LockedException; import com.fr.report.UnLockedException; +import com.fr.workspace.base.UserInfo; import com.fr.workspace.exception.DiskSpaceFullException; -import com.fr.report.InconsistentLockException; import java.awt.Frame; import javax.swing.JOptionPane; @@ -89,6 +88,25 @@ public class SaveFailureHandler implements ThrowableHandler { } }, + LOCKED { + @Override + public boolean process(Throwable e) { + LockedException exception = null; + if (e.getCause() instanceof LockedException) { + exception = (LockedException) e.getCause(); + } + if (e instanceof LockedException) { + exception = (LockedException) e; + } + if (exception != null) { + UserInfo userInfo = exception.getUserInfo(); + LockInfoDialog.show(userInfo, LockFileReSaveEnum.HISTORY_TEMPLATE_CACHE); + return true; + } + return false; + } + }, + Other { @Override public boolean process(Throwable e) { @@ -112,14 +130,7 @@ public class SaveFailureHandler implements ThrowableHandler { IOUtils.readIcon("/com/fr/design/images/warnings/warning32.png"), new Object[] {Toolkit.i18nText("Fine_Design_Template_SaveAs_Backup"), Toolkit.i18nText("Fine-Design_Basic_Button_Cancel")}, null); if (option == JOptionPane.YES_OPTION) { - JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - if (template != null) { - TemplateUtils.createAndOpenTemplate( - Toolkit.i18nText("Fine_Design_Template_Backup"), - new FileNodeFILE(new FileNode(template.getPath(), false)), - true, - false); - } + LockFileReSaveEnum.HISTORY_TEMPLATE_CACHE.action(); } } @@ -132,16 +143,7 @@ public class SaveFailureHandler implements ThrowableHandler { IOUtils.readIcon("/com/fr/design/images/warnings/warning32.png"), new Object[] {Toolkit.i18nText("Fine_Design_Template_SaveAs_Backup"), Toolkit.i18nText("Fine-Design_Basic_Button_Cancel")}, null); if (option == JOptionPane.YES_OPTION) { - JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); - if (template != null) { - TemplateUtils.createAndOpenTemplate( - Toolkit.i18nText("Fine_Design_Template_Backup"), - new FileNodeFILE(new FileNode(template.getPath(), false)), - true, - true); - // 创建并打开备份模板后,关闭原模板 - HistoryTemplateListCache.getInstance().closeSelectedReport(template); - } + LockFileReSaveEnum.HISTORY_TEMPLATE_CACHE.action(); } } 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 60d797c3e9..83b7c50d49 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 @@ -5,12 +5,16 @@ import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerFrameFileDealerPane; import com.fr.design.mainframe.EastRegionContainerPane; import com.fr.design.mainframe.JTemplate; +import com.fr.design.ui.util.UIUtil; import com.fr.design.worker.WorkerManager; +import com.fr.design.worker.save.type.SaveTypeWorker; import com.fr.general.ComparatorUtils; import com.fr.log.FineLoggerFactory; + import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; + +import com.fr.third.org.apache.commons.lang3.time.StopWatch; + import javax.swing.SwingWorker; /** @@ -34,6 +38,14 @@ public class SaveWorker extends SwingWorker { private boolean slowly; + public boolean isSlowly() { + return slowly; + } + + public void setSlowly(boolean slowly) { + this.slowly = slowly; + } + public SaveWorker(Callable callable, JTemplate template) { this.callable = callable; this.template = template; @@ -47,10 +59,11 @@ public class SaveWorker extends SwingWorker { @Override protected void done() { try { - success = get(); + success = get(); } catch (Exception e) { processResult(); FineLoggerFactory.getLogger().error(e.getMessage(), e); + WorkerManager.getInstance().removeWorker(taskName); SaveFailureHandler.getInstance().process(e); return; } @@ -62,6 +75,7 @@ public class SaveWorker extends SwingWorker { // 恢复界面 if (slowly && ComparatorUtils.equals(this.template.getName(), HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().getName())) { DesignerContext.getDesignerFrame().getCenterTemplateCardPane().hideCover(); + slowly = false; } DesignerFrameFileDealerPane.getInstance().stateChange(); WorkerManager.getInstance().removeWorker(taskName); @@ -69,21 +83,29 @@ public class SaveWorker extends SwingWorker { public void start(String taskName) { this.taskName = taskName; + StopWatch stopWatch = StopWatch.createStarted(); this.template.setSaving(true); this.execute(); // worker纳入管理 WorkerManager.getInstance().registerWorker(taskName, this); - try { - this.get(TIME_OUT, TimeUnit.MILLISECONDS); - } catch (TimeoutException timeoutException) { - slowly = true; - // 开始禁用 - EastRegionContainerPane.getInstance().updateAllPropertyPane(); - DesignerContext.getDesignerFrame().getCenterTemplateCardPane().showCover(); - DesignerFrameFileDealerPane.getInstance().stateChange(); - } catch (Exception exception) { - FineLoggerFactory.getLogger().error(exception.getMessage(), exception); - WorkerManager.getInstance().removeWorker(taskName); - } + SaveTypeWorker.SAVE_TYPE_POOL.execute(() -> { + while (true) { + if (stopWatch.getTime() > TIME_OUT || isDone()) { + if (!isDone()) { + slowly = true; + UIUtil.invokeLaterIfNeeded(() -> { + // 开始禁用 + if (slowly) { + EastRegionContainerPane.getInstance().updateAllPropertyPane(); + DesignerContext.getDesignerFrame().getCenterTemplateCardPane().showCover(); + DesignerFrameFileDealerPane.getInstance().stateChange(); + } + }); + } + stopWatch.stop(); + break; + } + } + }); } } diff --git a/designer-base/src/main/java/com/fr/design/worker/save/type/SaveType.java b/designer-base/src/main/java/com/fr/design/worker/save/type/SaveType.java new file mode 100644 index 0000000000..63cf6c4c7e --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/worker/save/type/SaveType.java @@ -0,0 +1,50 @@ +package com.fr.design.worker.save.type; + +/** + * 保存的类别 + * + * @author John.Ying + * @since 11.0 + * Created on 2023/4/14 + */ +public class SaveType { + + private TypeEnum type; + //保存时间是否慢(是否展示了保存中的UI界面) + private boolean slowly; + + public TypeEnum getType() { + return type; + } + + public void setType(TypeEnum saveType) { + this.type = saveType; + } + + public boolean isSlowly() { + return slowly; + } + + public void setSlowly(boolean slowly) { + this.slowly = slowly; + } + + /** + * 保存类型:save or saveAs or empty + */ + public enum TypeEnum { + /** + * 保存 + */ + SAVE, + /** + * 另存 + */ + SAVE_AS, + /** + * 空保存 + */ + EMPTY; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/worker/save/type/SaveTypeWorker.java b/designer-base/src/main/java/com/fr/design/worker/save/type/SaveTypeWorker.java new file mode 100644 index 0000000000..d415537eb4 --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/worker/save/type/SaveTypeWorker.java @@ -0,0 +1,81 @@ +package com.fr.design.worker.save.type; + + +import com.fr.concurrent.FineExecutors; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.DesignerFrameFileDealerPane; +import com.fr.design.mainframe.EastRegionContainerPane; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.ui.util.UIUtil; +import com.fr.third.org.apache.commons.lang3.time.StopWatch; + +import javax.swing.SwingWorker; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; + +/** + * 判断保存类别时执行的worker + * + * @author John.Ying + * @since 11.0 + * Created on 2023/4/14 + */ +public class SaveTypeWorker extends SwingWorker { + + public static final ExecutorService SAVE_TYPE_POOL = FineExecutors.newSingleThreadExecutor(); + + private final Callable callable; + + private static final int TIME_OUT = 400; + + private final JTemplate template; + + private final SaveType saveType; + + + + public SaveTypeWorker(Callable callable, JTemplate template) { + this.callable = callable; + this.template = template; + this.saveType = new SaveType(); + } + + @Override + protected SaveType doInBackground() throws Exception { + this.saveType.setType(callable.call()); + return this.saveType; + } + + @Override + protected void done() { + + } + + /** + * 启动saveTypeWorker + */ + public void start() { + StopWatch stopWatch = StopWatch.createStarted(); + this.template.setSaving(true); + this.execute(); + SAVE_TYPE_POOL.execute(() -> { + while (true) { + //大于最大等待时间或者worker已经完成该线程都要结束循环 + if (stopWatch.getTime() > TIME_OUT || isDone()) { + //如果是大于最大等待时间结束的,就需要进行等待中界面的覆盖 + if (!isDone()) { + saveType.setSlowly(true); + UIUtil.invokeLaterIfNeeded(() -> { + // 开始禁用 + EastRegionContainerPane.getInstance().updateAllPropertyPane(); + DesignerContext.getDesignerFrame().getCenterTemplateCardPane().showCover(); + DesignerFrameFileDealerPane.getInstance().stateChange(); + }); + } + stopWatch.stop(); + break; + } + } + }); + } +} diff --git a/designer-base/src/main/java/com/fr/env/CheckServiceDialog.java b/designer-base/src/main/java/com/fr/env/CheckServiceDialog.java index 032f16a769..6931fa6636 100644 --- a/designer-base/src/main/java/com/fr/env/CheckServiceDialog.java +++ b/designer-base/src/main/java/com/fr/env/CheckServiceDialog.java @@ -332,7 +332,7 @@ public class CheckServiceDialog extends JDialog implements ActionListener { String[] option = {Toolkit.i18nText("Fine-Design_Report_Yes"), Toolkit.i18nText("Fine-Design_Report_No")}; if (!jarConsistency) { int a = FineJOptionPane.showOptionDialog(getParent(), Toolkit.i18nText("Fine-Design_Basic_Sync_Info_Information"), - Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_OPTION, QUESTION_MESSAGE, IOUtils.readIcon("com/fr/design/icon/versioncheck/question.png"), option, 1); + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.YES_NO_OPTION, QUESTION_MESSAGE, IOUtils.readIcon("com/fr/design/icon/versioncheck/question.png"), option, 1); if (0 == a) { progressBar.setVisible(true); progressBar.setString(Toolkit.i18nText("Fine-Design_Update_Info_Wait_Message")); diff --git a/designer-base/src/main/java/com/fr/env/RemoteDesignLocaleMark.java b/designer-base/src/main/java/com/fr/env/RemoteDesignLocaleMark.java index 877a9224b2..dd95323617 100644 --- a/designer-base/src/main/java/com/fr/env/RemoteDesignLocaleMark.java +++ b/designer-base/src/main/java/com/fr/env/RemoteDesignLocaleMark.java @@ -1,11 +1,7 @@ package com.fr.env; -import com.fr.general.CloudCenter; -import com.fr.general.GeneralContext; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.general.locale.LocaleMark; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; /** * @author hades @@ -14,23 +10,21 @@ import java.util.Map; */ public class RemoteDesignLocaleMark implements LocaleMark { - private Map map = new HashMap<>(); - private static final String REMOTE_DESIGN_CN = CloudCenter.getInstance().acquireUrlByKind("help.remote.design.zh_CN", "https://help.fanruan.com/finereport/doc-view-3925.html"); - private static final String REMOTE_DESIGN_EN = CloudCenter.getInstance().acquireUrlByKind("help.remote.design.en_US", "https://help.fanruan.com/finereport-en/doc-view-3862.html"); + /** + * 云中心远程设计常见问题链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Remote_Design_Question"; + /** + * 云中心远程设计常见问题链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Remote_Design_Question_Default"; - public RemoteDesignLocaleMark() { - map.put(Locale.CHINA, REMOTE_DESIGN_CN); - map.put(Locale.KOREA, REMOTE_DESIGN_EN); - map.put(Locale.JAPAN, REMOTE_DESIGN_EN); - map.put(Locale.US, REMOTE_DESIGN_EN); - map.put(Locale.TAIWAN, REMOTE_DESIGN_CN); - } + public RemoteDesignLocaleMark() {} @Override public String getValue() { - String result = map.get(GeneralContext.getLocale()); - return result == null ? REMOTE_DESIGN_CN : result; + return LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); } } diff --git a/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java b/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java index 31bdaa979b..7be733b2b5 100644 --- a/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java +++ b/designer-base/src/main/java/com/fr/env/RemoteEnvPane.java @@ -5,6 +5,7 @@ import com.fr.design.ExtraDesignClassManager; import com.fr.design.beans.BasicBeanPane; import com.fr.design.border.UITitledBorder; import com.fr.design.env.RemoteDesignerWorkspaceInfo; +import com.fr.design.env.processor.RemoteDesignerWorkspaceInfoProcessor; import com.fr.design.fun.DesignerEnvProcessor; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.icheckbox.UICheckBox; @@ -579,8 +580,14 @@ public class RemoteEnvPane extends BasicBeanPane { private void tryConnectRemoteEnv() { final RemoteDesignerWorkspaceInfo remoteEnv = updateBean(); - final WorkspaceConnectionInfo connection = remoteEnv.getConnection(); - + WorkspaceConnectionInfo originalConnection = remoteEnv.getConnection(); + final WorkspaceConnectionInfo connection; + RemoteDesignerWorkspaceInfoProcessor processor = ExtraDesignClassManager.getInstance().getSingle(RemoteDesignerWorkspaceInfoProcessor.XML_TAG); + if (processor != null) { + connection = processor.customUserName(originalConnection); + } else { + connection = originalConnection; + } final SwingWorker worker = new SwingWorker() { @Override diff --git a/designer-base/src/main/java/com/fr/env/SyncFailedPluginsDialog.java b/designer-base/src/main/java/com/fr/env/SyncFailedPluginsDialog.java index fd4b98e33e..a0b07bd2c0 100644 --- a/designer-base/src/main/java/com/fr/env/SyncFailedPluginsDialog.java +++ b/designer-base/src/main/java/com/fr/env/SyncFailedPluginsDialog.java @@ -6,25 +6,18 @@ import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.itextarea.UITextArea; import com.fr.design.i18n.DesignSizeI18nManager; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.mainframe.DesignerContext; import com.fr.design.utils.gui.GUICoreUtils; -import com.fr.general.CloudCenter; import com.fr.general.ComparatorUtils; import com.fr.general.GeneralContext; import com.fr.general.IOUtils; import com.fr.json.JSONArray; import com.fr.json.JSONObject; import com.fr.stable.StringUtils; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.Locale; + import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JDialog; @@ -33,6 +26,14 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.UIManager; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.Locale; /** * @author pengda @@ -47,6 +48,16 @@ public class SyncFailedPluginsDialog extends JDialog { private RestartHelper restartHelper = new RestartHelper(); private UIButton restartButton; private boolean show = false; + + /** + * 云中心插件管理帮助文档在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Plugin_Management"; + + /** + * 云中心插件管理默认帮助文档在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Plugin_Management_Default"; public SyncFailedPluginsDialog(JFrame parent, JSONArray syncFailedPlugins) { super(parent, true); JPanel body = FRGUIPaneFactory.createBorderLayout_L_Pane(); @@ -62,7 +73,7 @@ public class SyncFailedPluginsDialog extends JDialog { JPanel messagePane = FRGUIPaneFactory.createBorderLayout_S_Pane(); MessageWithLink messageWithLink = new MessageWithLink(Toolkit.i18nText("Fine-Design_Basic_Sync_Plugin_Fail_Suggestion"),Toolkit.i18nText("Fine-Design_Basic_Sync_Deal_Immediately"), - CloudCenter.getInstance().acquireUrlByKind("help.installplugins", "https://help.fanruan.com/finereport/doc-view-2198.html")); + LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT)); messageWithLink.setPreferredSize(DesignSizeI18nManager.getInstance().i18nDimension("com.fr.env.SyncFailedPluginsDialog.messageWithLink")); messagePane.add(messageWithLink); diff --git a/designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java b/designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java index 4e4592dcde..61f08c344c 100644 --- a/designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java +++ b/designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java @@ -1,13 +1,33 @@ package com.fr.env.detect.base; +import com.fr.design.i18n.LocaleLinkProvider; + /** * created by Harrison on 2022/05/25 **/ public class DetectorConstants { + /** + * 云中心FineDB异常检测帮助文档在配置文件中对应的配置文件key + */ + private static final String FINE_DB_HELP_PROPS_LINK_KEY = "Fine-Design-CloudCenter_FineDB_Exception_Check"; + + /** + * 云中心FineDB异常检测帮助文档默认链接在配置文件中对应的配置文件key + */ + private static final String FINE_DB_HELP_PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_FineDB_Exception_Check_Default"; + + /** + * 云中心FineDB异常检测帮助文档在配置文件中对应的配置文件key + */ + private static final String JAR_HELP_PROPS_LINK_KEY = "Fine-Design-CloudCenter_Jar_Exception_Check"; + + /** + * 云中心FineDB异常检测帮助文档默认链接在配置文件中对应的配置文件key + */ + private static final String JAR_HELP_PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Jar_Exception_Check_Default"; + public static final String JAR_HELP_LINK = LocaleLinkProvider.getInstance().getLink(JAR_HELP_PROPS_LINK_KEY, JAR_HELP_PROPS_LINK_KEY_DEFAULT);; - public static final String JAR_HELP_LINK = "https://help.fanruan.com/finereport/doc-view-4700.html?source=3"; - - public static final String FINE_DB_HELP_LINK = "https://help.fanruan.com/finereport/doc-view-4701.html?source=3"; + public static final String FINE_DB_HELP_LINK = LocaleLinkProvider.getInstance().getLink(FINE_DB_HELP_PROPS_LINK_KEY, FINE_DB_HELP_PROPS_LINK_KEY_DEFAULT); public static final String SEPARATOR = "、"; public static final String BR_TAG = "
    "; diff --git a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java index da631cfdb8..ebd9ba460a 100644 --- a/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java +++ b/designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java @@ -161,6 +161,7 @@ public class EnvDetectorDialog extends JDialog { } }; detectButton.setForeground(Color.WHITE); + detectButton.setToolTipText(buttonStatus.getDesc()); detectButton.addActionListener(event -> { if (buttonStatus.isNotExecuting()) { startDetecting(); @@ -282,6 +283,7 @@ public class EnvDetectorDialog extends JDialog { UIUtil.invokeLaterIfNeeded(() -> { // 刷新按钮 detectButton.setText(buttonStatus.getDesc()); + detectButton.setToolTipText(detectButton.getText()); // 刷新面板 refreshBody(); }); @@ -291,6 +293,7 @@ public class EnvDetectorDialog extends JDialog { // 刷新按钮 detectButton.setText(buttonStatus.getDesc()); + detectButton.setToolTipText(detectButton.getText()); if (buttonStatus == EnvDetectorButtonStatus.A_NEW) { this.resultSummaryPane = new JPanel(); this.resultSummaryPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); @@ -356,6 +359,7 @@ public class EnvDetectorDialog extends JDialog { } EnvDetectorItem item = items.get(i); tablePanel.updateCell(row, 2, new UILabel(item.getDescription())); + tablePanel.updateCellToolTip(row, 2, item.getDescription()); DetectorResult result = item.getResult(); int detectRow = currentDetectIndex + 1; diff --git a/designer-base/src/main/java/com/fr/file/FILEChooserPane.java b/designer-base/src/main/java/com/fr/file/FILEChooserPane.java index 78c0378a1f..8bc913d8cc 100644 --- a/designer-base/src/main/java/com/fr/file/FILEChooserPane.java +++ b/designer-base/src/main/java/com/fr/file/FILEChooserPane.java @@ -131,6 +131,10 @@ public class FILEChooserPane extends BasicPane { public static final int JOPTIONPANE_CANCEL_OPTION = 3; + public static final String SEPARATOR_STRING = "/"; + + public static final char SEPARATOR_CHAR = '/'; + /** * alex:之所以在Pattern那里加个+,是因为有些路径会有两个甚至多个分隔符放在一起 @@ -948,7 +952,7 @@ public class FILEChooserPane extends BasicPane { if (access(selectedFile) && access(currentDirectory)) { if (selectedFile.exists()) { int selVal = FineJOptionPane.showConfirmDialog(dialog, Toolkit.i18nText("Fine-Design_Basic_Utils_Would_You_Like_To_Cover_The_Current_File") + " ?", - Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (selVal == JOptionPane.YES_OPTION) { option = JOPTIONPANE_OK_OPTION; saveDictionary(); @@ -1468,10 +1472,17 @@ public class FILEChooserPane extends BasicPane { for (int i = 0; i < this.buttonList.size(); i++) { this.buttonList.get(i).setForeground(null); if (((SetDirectoryAction) this.buttonList.get(i).getAction()).getDir() != null - && this.buttonList.get(i).getAction() instanceof SetDirectoryAction - && (ComparatorUtils.equals(((SetDirectoryAction) this.buttonList.get(i).getAction()).getDir().getPath(), dir.getPath()))) { - - this.buttonList.get(i).setForeground(Color.BLUE); + && this.buttonList.get(i).getAction() instanceof SetDirectoryAction) { + String actionPath = ((SetDirectoryAction) this.buttonList.get(i).getAction()).getDir().getPath(); + String dirPath = dir.getPath(); + //如果是报表环境,button的Action最后会跟上"/",这个是特意处理的,但是对应代码没有说明原因,不做修改 + //FILE的getPath不会带"/",这边针对这种情况加个处理,不建议直接改FILE + if (actionPath.endsWith(SEPARATOR_STRING) && !dirPath.endsWith(SEPARATOR_STRING)) { + dirPath = dirPath + SEPARATOR_STRING; + } + if (ComparatorUtils.equals(actionPath, dirPath)) { + this.buttonList.get(i).setForeground(Color.BLUE); + } } } } @@ -1481,7 +1492,7 @@ public class FILEChooserPane extends BasicPane { } public void populate(FILE dir) { - if (popDir != null && dir != null && popDir.toString().indexOf(dir.toString()) == 0) { + if (checkOnlyHighLight(dir)) { highLightButton(dir); return; } @@ -1532,6 +1543,24 @@ public class FILEChooserPane extends BasicPane { highLightButton(dir); } + /** + * 检查是不是只需要设置高亮即可 + * + * @param dir FILE + * @return 如果还要进行别的设置就返回false,如果只需要更新下高亮(通过点击上面的路径才会只需要更新高亮),返回true + */ + private boolean checkOnlyHighLight(FILE dir) { + if (popDir == null || dir == null) { + return false; + } + String popDirStr = popDir.toString(); + String dirStr = dir.toString(); + //前缀匹配是不够的,还要看下前缀匹配的下一位是不是'/' + //否则"test"和"test副本"明明不属于同个路径逻辑,也只更新高亮,应该是"test"和"test/副本"这样才可以通过 + //如果通过了indexOf的检查,因为不会存在相同的路径,popDirStr只会比dirStr大,看一下前缀匹配的下一位是不是'/',如果不是就得更新路径文本,不能只设置高亮 + return popDirStr.indexOf(dirStr) == 0 && popDirStr.length() > dirStr.length() && popDirStr.charAt(dirStr.length()) == SEPARATOR_CHAR; + } + // doLayout @Override public void doLayout() { diff --git a/designer-base/src/main/java/com/fr/start/server/FineEmbedServer.java b/designer-base/src/main/java/com/fr/start/server/FineEmbedServer.java index fc3d2a4e46..13f708e588 100644 --- a/designer-base/src/main/java/com/fr/start/server/FineEmbedServer.java +++ b/designer-base/src/main/java/com/fr/start/server/FineEmbedServer.java @@ -3,6 +3,8 @@ package com.fr.start.server; import com.fanruan.carina.Carina; import com.fr.event.EventDispatcher; import com.fr.workspace.WorkContext; +import com.fr.module.ModuleContext; +import com.fr.plugin.listener.SpecialPluginEvent; /** * Created by juhaoyu on 2018/6/6. @@ -20,6 +22,7 @@ public abstract class FineEmbedServer { public synchronized static void start() throws Exception { if (!isRunning()) { onStarting = true; + EventDispatcher.fire(SpecialPluginEvent.WITH_SERVER_AND_NOT_START_IN_REMOTE); EventDispatcher.fire(EmbedServerEvent.BeforeStart); DesignEmbedHelper.start(); onStarting = false; diff --git a/designer-base/src/main/java/com/fr/start/server/FineEmbedServerActivator.java b/designer-base/src/main/java/com/fr/start/server/FineEmbedServerActivator.java index 3f97b5dc42..ee87add736 100644 --- a/designer-base/src/main/java/com/fr/start/server/FineEmbedServerActivator.java +++ b/designer-base/src/main/java/com/fr/start/server/FineEmbedServerActivator.java @@ -1,5 +1,6 @@ package com.fr.start.server; +import com.fr.cbb.websocket.core.WebSocketEndpoint; import com.fr.design.DesignerEnvManager; import com.fr.log.FineLoggerFactory; import com.fr.module.Activator; @@ -12,7 +13,6 @@ import com.fr.third.springframework.web.context.support.AnnotationConfigWebAppli import com.fr.workspace.WorkContext; import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; -import org.apache.catalina.Wrapper; import org.apache.catalina.loader.WebappLoader; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.webresources.StandardRoot; @@ -79,10 +79,6 @@ public class FineEmbedServerActivator extends Activator { String contextPath = "/" + ProductConstants.getAppFolderName(); final Context context = tomcat.addContext(contextPath, docBase); context.setResources(new StandardRoot(context)); - Wrapper servlet = Tomcat.addServlet(context, "DruidStatView", "com.fr.third.alibaba.druid.support.http.StatViewServlet"); - context.addServletMappingDecoded("/druid/*", "DruidStatView"); - servlet.setLoadOnStartup(1); - servlet.setOverridable(true); Tomcat.initWebappDefaults(context); //覆盖tomcat的WebAppClassLoader context.setLoader(new FRTomcatLoader()); diff --git a/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupModel.java b/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupModel.java index 5ed94d82eb..e6e2ebb793 100644 --- a/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupModel.java +++ b/designer-base/src/main/java/com/fr/startup/metric/DesignerStartupModel.java @@ -39,6 +39,11 @@ public class DesignerStartupModel { * mode:模式,0-有设计器起动页;1-无设计器起始页 */ private int mode; + + /** + * jdkVersion:JDK版本 + */ + private String jdkVersion; public DesignerStartupModel() { } @@ -73,7 +78,15 @@ public class DesignerStartupModel { public void setInfo(MachineInfo info) { this.info = info; } - + + public String getJdkVersion() { + return jdkVersion; + } + + public void setJdkVersion(String jdkVersion) { + this.jdkVersion = jdkVersion; + } + public int getMode() { return mode; } @@ -83,7 +96,7 @@ public class DesignerStartupModel { } private void fillInfo() { - + this.setJdkVersion(System.getProperty("java.version")); MachineInfo info = new MachineInfo(); AbstractOperatingSystem operatingSystem = OperatingSystem.getOperatingSystem(); info.setSystem(operatingSystem.getDisplayString()); diff --git a/designer-base/src/main/java/com/fr/startup/ui/StartupPageWindow.java b/designer-base/src/main/java/com/fr/startup/ui/StartupPageWindow.java index 956f0701da..0dc3dbab15 100644 --- a/designer-base/src/main/java/com/fr/startup/ui/StartupPageWindow.java +++ b/designer-base/src/main/java/com/fr/startup/ui/StartupPageWindow.java @@ -1,6 +1,7 @@ package com.fr.startup.ui; import com.fr.base.svg.IconUtils; +import com.fr.concurrent.NamedThreadFactory; import com.fr.design.DesignerEnvManager; import com.fr.design.dialog.UIExpandDialog; import com.fr.design.gui.icontainer.UIScrollPane; @@ -8,6 +9,8 @@ import com.fr.design.gui.ilable.UILabel; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.VerticalFlowLayout; +import com.fr.design.mainframe.messagecollect.StartErrorMessageCollector; +import com.fr.design.mainframe.messagecollect.entity.DesignerErrorMessage; import com.fr.design.ui.util.UIUtil; import com.fr.design.utils.ColorUtils; import com.fr.design.utils.ThemeUtils; @@ -49,6 +52,8 @@ import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** * 启动页 @@ -253,6 +258,7 @@ public class StartupPageWindow extends JFrame { try { Void result = get(); setVisible(false); + StartErrorMessageCollector.getInstance().setExtraJudgeStart(false); } catch (Exception e) { // 处理错误 UIUtil.invokeLaterIfNeeded(() -> { @@ -269,6 +275,9 @@ public class StartupPageWindow extends JFrame { setEnabled(true); }); FineLoggerFactory.getLogger().error(e.getMessage(), e); + StartErrorMessageCollector.getInstance().asyncRecord(DesignerErrorMessage.UNEXCEPTED_START_FAILED.getId(), + DesignerErrorMessage.UNEXCEPTED_START_FAILED.getMessage(), + e.getMessage()); } finally { loadingPanel.hide(); } diff --git a/designer-base/src/main/java/com/fr/widgettheme/ParameterBackgroundStyleSettingPane.java b/designer-base/src/main/java/com/fr/widgettheme/ParameterBackgroundStyleSettingPane.java new file mode 100644 index 0000000000..144308c223 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/ParameterBackgroundStyleSettingPane.java @@ -0,0 +1,102 @@ +package com.fr.widgettheme; + +import com.fr.base.theme.TemplateTheme; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.constants.LayoutConstants; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.gui.ibutton.UIButtonGroup; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.widget.accessibles.AccessibleBackgroundEditor; +import com.fr.form.ui.container.WParameterLayout; +import com.fr.general.Background; +import org.jetbrains.annotations.Nullable; + +import javax.swing.JPanel; +import java.awt.BorderLayout; + +/** + * 设计器参数面板的“高级”设置增加背景的主题样式设置 + * + * @author Bruce.Deng + * @since 11.0 + * Created on 2023/2/20 + */ +public class ParameterBackgroundStyleSettingPane extends BasicBeanPane { + + public static final String[] FOLLOWING_THEME_STRING_ARRAYS = new String[]{ + Toolkit.i18nText("Fine-Design_Widget_Follow_Theme"), + Toolkit.i18nText("Fine-Design_Widget_Theme_Custom") + }; + + private UIButtonGroup head; + private JPanel customPane; + private AccessibleBackgroundEditor background; + + public ParameterBackgroundStyleSettingPane() { + this.setLayout(new BorderLayout(0, LayoutConstants.VGAP_SMALL)); + head = new UIButtonGroup(FOLLOWING_THEME_STRING_ARRAYS) { + @Override + public void setSelectedIndex(int newSelectedIndex, boolean fireChanged) { + //表示从跟随主题切换到自定义 + if (selectedIndex != newSelectedIndex && newSelectedIndex == 1) { + background.setValue(getThemeBackground()); + } + super.setSelectedIndex(newSelectedIndex, fireChanged); + } + }; + customPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + background = new AccessibleBackgroundEditor(); + customPane.add(background); + this.add(head, BorderLayout.NORTH); + this.add(customPane, BorderLayout.CENTER); + } + + private void attributeChange() { + customPane.setVisible(head.getSelectedIndex() == 1); + } + + @Override + public void populateBean(WParameterLayout wParameterLayout) { + if (wParameterLayout.isBackgroundFollowTheme()) { + head.setSelectedIndex(0); + } else { + head.setSelectedIndex(1); + background.setValue(wParameterLayout.getBackground()); + } + attributeChange(); + } + + @Override + @Nullable + public WParameterLayout updateBean() { + return null; + } + + @Override + public void updateBean(WParameterLayout wParameterLayout) { + attributeChange(); + if (head.getSelectedIndex() != 1) { + wParameterLayout.setBackgroundFollowTheme(true); + wParameterLayout.setBackground(getThemeBackground()); + } else { + wParameterLayout.setBackgroundFollowTheme(false); + wParameterLayout.setBackground((Background) background.getValue()); + } + } + + private Background getThemeBackground() { + JTemplate template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (JTemplate.isValid(template)) { + TemplateTheme theme = template.getTemplateTheme(); + return theme.getParamContainerStyle().getBackground(); + } + return (Background) background.getValue(); + } + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Widget_Theme_ParamContainer_Background"); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/ThemePreviewTerminal.java b/designer-base/src/main/java/com/fr/widgettheme/ThemePreviewTerminal.java new file mode 100644 index 0000000000..844e642191 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/ThemePreviewTerminal.java @@ -0,0 +1,62 @@ +package com.fr.widgettheme; + +import com.fr.base.theme.TemplateTheme; +import com.fr.widgettheme.theme.widget.style.MobileThemedWidgetStyle; +import com.fr.widgettheme.theme.widget.style.ThemedWidgetStyle; + +/** + * 主题样式预览终端类型 + * + * @author obo + * @since 11.0 + * Created on 2024/2/2 + */ +public enum ThemePreviewTerminal { + + /** + * 桌面端,为默认类型 + */ + PC(0) { + @Override + public ThemedWidgetStyle getThemeWidgetStyle(TemplateTheme theme) { + return (ThemedWidgetStyle) theme.getWidgetStyle(); + } + }, + + /** + * 移动端 + */ + MOBILE(1) { + @Override + public ThemedWidgetStyle getThemeWidgetStyle(TemplateTheme theme) { + return (MobileThemedWidgetStyle) theme.getMobileWidgetStyle(); + } + }; + + /** + * 类型码 + */ + final int code; + + ThemePreviewTerminal(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + + public abstract ThemedWidgetStyle getThemeWidgetStyle(TemplateTheme theme); + + /** + * 根据code获取对应的枚举 + */ + public static ThemePreviewTerminal getTypeByCode(int code) { + for (ThemePreviewTerminal type : ThemePreviewTerminal.values()) { + if (type.code == code) { + return type; + } + } + throw new IllegalArgumentException("Invalid ThemePreviewTerminalType code :" + code); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/designer/WidgetThemeDisplayAction.java b/designer-base/src/main/java/com/fr/widgettheme/designer/WidgetThemeDisplayAction.java new file mode 100644 index 0000000000..21c7f3ac93 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/designer/WidgetThemeDisplayAction.java @@ -0,0 +1,50 @@ +package com.fr.widgettheme.designer; + +import com.fr.base.io.BaseBook; +import com.fr.base.svg.IconUtils; +import com.fr.design.actions.JTemplateAction; +import com.fr.widgettheme.util.WidgetThemeDesignerUtils; +import com.fr.design.dialog.DialogActionAdapter; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.DesignerContext; +import com.fr.design.mainframe.JTemplate; +import com.fr.widgettheme.control.attr.WidgetDisplayEnhanceMarkAttr; + +import java.awt.event.ActionEvent; + +/** + * 控件主题显示增强菜单action + * + * @author Bruce.Deng + * @since 11.0 + * Created on 2022/11/28 + */ +public class WidgetThemeDisplayAction> extends JTemplateAction { + + public WidgetThemeDisplayAction(T jwb) { + super(jwb); + setName(Toolkit.i18nText("Fine-Design_Widget_Display_Enhance")); + this.setSmallIcon(IconUtils.readIcon("/com/fr/widgettheme/menu.svg")); + } + + @Override + public void actionPerformed(ActionEvent e) { + final T jTemplate = getEditingComponent(); + if (!JTemplate.isValid(jTemplate)) { + return; + } + BaseBook baseBook = jTemplate.getTarget(); + WidgetDisplayEnhanceMarkAttr attr = WidgetThemeDesignerUtils.getStrongestControlAttrFromTemplate(baseBook); + final WidgetThemeDisplayConfigPane configPane = new WidgetThemeDisplayConfigPane(); + configPane.populate(attr); + configPane.showSmallWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { + @Override + public void doOk() { + baseBook.addAttrMark(configPane.update()); + jTemplate.fireTargetModified(); + HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().activeOldJTemplate(); + } + }).setVisible(true); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/designer/WidgetThemeDisplayConfigPane.java b/designer-base/src/main/java/com/fr/widgettheme/designer/WidgetThemeDisplayConfigPane.java new file mode 100644 index 0000000000..ad96c00a9f --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/designer/WidgetThemeDisplayConfigPane.java @@ -0,0 +1,81 @@ +package com.fr.widgettheme.designer; + +import com.fr.design.dialog.BasicPane; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.VerticalFlowLayout; +import com.fr.widgettheme.control.attr.WidgetDisplayEnhanceMarkAttr; + +import javax.swing.JPanel; +import java.awt.Color; + +/** + * 控件主题显示增强配置窗口 + * + * @author Bruce.Deng + * @since 11.0 + * Created on 2022/11/28 + */ +public class WidgetThemeDisplayConfigPane extends BasicPane { + + private UICheckBox widgetEnhance; + + public WidgetThemeDisplayConfigPane() { + initComponents(); + } + + private void initComponents() { + VerticalFlowLayout layout = new VerticalFlowLayout(); + layout.setAlignLeft(true); + this.setLayout(layout); + JPanel northPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + this.add(northPane); + widgetEnhance = new UICheckBox(Toolkit.i18nText("Fine-Design_Widget_Enable_Display_Enhance")); + widgetEnhance.setSelected(true); + northPane.add(widgetEnhance); + + JPanel southPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + this.add(southPane); + UILabel label = new UILabel(Toolkit.i18nText("Fine-Design_Widget_Display_Enhance_Tip")); + label.setForeground(Color.GRAY); + southPane.add(label); + } + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Widget_Display_Enhance"); + } + + /** + * 根据属性填充pane选项 + * + * @param widgetDisplayEnhanceMarkAttr 控件显示增强属性 + */ + public void populate(WidgetDisplayEnhanceMarkAttr widgetDisplayEnhanceMarkAttr) { + if (widgetDisplayEnhanceMarkAttr == null) { + widgetDisplayEnhanceMarkAttr = new WidgetDisplayEnhanceMarkAttr(); + } + widgetEnhance.setSelected(widgetDisplayEnhanceMarkAttr.isWidgetEnhance()); + } + + /** + * 更新 + */ + public WidgetDisplayEnhanceMarkAttr update() { + WidgetDisplayEnhanceMarkAttr attr = new WidgetDisplayEnhanceMarkAttr(); + attr.setWidgetEnhance(widgetEnhance.isSelected()); + if (widgetEnhance.isSelected()) { + collectWidgetDisplayEnhanceRecord(); + } + return attr; + } + + /** + * 记录埋点信息,具体实现在云端运维插件,这里只作为切入点 + */ + private void collectWidgetDisplayEnhanceRecord() { + //记录埋点 + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/edit/ParamContainerBackgroundPane.java b/designer-base/src/main/java/com/fr/widgettheme/theme/edit/ParamContainerBackgroundPane.java new file mode 100644 index 0000000000..429df171ce --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/edit/ParamContainerBackgroundPane.java @@ -0,0 +1,88 @@ +package com.fr.widgettheme.theme.edit; + +import com.fr.design.ExtraDesignClassManager; +import com.fr.design.event.UIObserverListener; +import com.fr.design.fun.BackgroundQuickUIProvider; +import com.fr.design.gui.style.BackgroundPane; +import com.fr.design.mainframe.backgroundpane.BackgroundQuickPane; +import com.fr.design.mainframe.backgroundpane.ColorBackgroundQuickPane; +import com.fr.design.mainframe.backgroundpane.GradientBackgroundQuickPane; +import com.fr.design.mainframe.backgroundpane.ImageBackgroundQuickPane; +import com.fr.design.mainframe.backgroundpane.NullBackgroundQuickPane; +import com.fr.design.mainframe.backgroundpane.PatternBackgroundQuickPane; +import com.fr.design.mainframe.backgroundpane.TextureBackgroundQuickPane; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * 参数面板背景编辑窗口 + * + * @author Bruce.Deng + * @since 11.0 + * Created on 2023/1/5 + */ +public class ParamContainerBackgroundPane extends BackgroundPane { + + private NullBackgroundQuickPane nullBackgroundPane; + private ColorBackgroundQuickPane colorBackgroundPane; + private ImageBackgroundQuickPane imageBackgroundPane; + private GradientBackgroundQuickPane gradientBackgroundPane; + private TextureBackgroundQuickPane textureBackgroundPane; + private PatternBackgroundQuickPane patternBackgroundPane; + + public ParamContainerBackgroundPane() { + super(); + } + + + @Override + protected BackgroundQuickPane[] supportKindsOfBackgroundUI() { + nullBackgroundPane = new NullBackgroundQuickPane(); + + colorBackgroundPane = new ColorBackgroundQuickPane(true); + colorBackgroundPane.registerChangeListener(this::fireStateChanged); + + imageBackgroundPane = new ImageBackgroundQuickPane(); + imageBackgroundPane.registerChangeListener(this::fireStateChanged); + + gradientBackgroundPane = createGradientBackgroundQuickPane(); + gradientBackgroundPane.registerChangeListener(this::fireStateChanged); + + textureBackgroundPane = new TextureBackgroundQuickPane(); + textureBackgroundPane.registerChangeListener(this::fireStateChanged); + + patternBackgroundPane = new PatternBackgroundQuickPane(); + patternBackgroundPane.registerChangeListener(this::fireStateChanged); + + + return createBackgroundQuickPanes(); + } + + private BackgroundQuickPane[] createBackgroundQuickPanes() { + List kinds = new ArrayList<>(); + + kinds.add(nullBackgroundPane); + kinds.add(colorBackgroundPane); + kinds.add(imageBackgroundPane); + kinds.add(gradientBackgroundPane); + kinds.add(textureBackgroundPane); + kinds.add(patternBackgroundPane); + + Set providers = ExtraDesignClassManager.getInstance().getArray(BackgroundQuickUIProvider.MARK_STRING); + for (BackgroundQuickUIProvider provider : providers) { + BackgroundQuickPane newTypePane = provider.appearanceForBackground(); + newTypePane.registerChangeListener(this::fireStateChanged); + kinds.add(newTypePane); + } + + return kinds.toArray(new BackgroundQuickPane[kinds.size()]); + } + + + protected GradientBackgroundQuickPane createGradientBackgroundQuickPane() { + // 使用默认的150宽度构建渐变条 + return new GradientBackgroundQuickPane(); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/edit/ParamContainerStyleEditPane.java b/designer-base/src/main/java/com/fr/widgettheme/theme/edit/ParamContainerStyleEditPane.java new file mode 100644 index 0000000000..5f64b15bcc --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/edit/ParamContainerStyleEditPane.java @@ -0,0 +1,84 @@ +package com.fr.widgettheme.theme.edit; + +import com.fr.base.theme.TemplateTheme; +import com.fr.base.theme.settings.AbstractThemedParamContainerStyle; +import com.fr.base.theme.settings.DefaultThemedParamContainerStyle; +import com.fr.widgettheme.theme.widget.style.ThemedParamContainerStyle; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.designer.IntervalConstants; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Component; + +/** + * 参数面板样式编辑pane + * + * @author Bruce.Deng + * @since 11.0 + * Created on 2022/12/16 + */ +public class ParamContainerStyleEditPane extends BasicBeanPane { + public static final int LABEL_WIDTH = 60; + public static final int SETTING_WIDTH = 193; + + private final ParamContainerBackgroundPane backgroundPane; + + public ParamContainerStyleEditPane() { + backgroundPane = new ParamContainerBackgroundPane(); + + double p = TableLayout.PREFERRED; + + JPanel uiLabelPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + uiLabelPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Background")), BorderLayout.NORTH); + uiLabelPane.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); + JPanel backgroundLabeledPane = TableLayoutHelper.createCommonTableLayoutPane( + new Component[][]{ new Component[] { uiLabelPane, backgroundPane } }, + new double[] { p }, new double[] { LABEL_WIDTH, SETTING_WIDTH}, IntervalConstants.INTERVAL_L1 + ); + backgroundLabeledPane.setBorder(BorderFactory.createEmptyBorder( + IntervalConstants.INTERVAL_L1, + IntervalConstants.INTERVAL_L1, + IntervalConstants.INTERVAL_L1, + IntervalConstants.INTERVAL_L1 + )); + this.add(backgroundLabeledPane); + setBorder(BorderFactory.createEmptyBorder()); + } + + @Override + public void populateBean(T t) { + AbstractThemedParamContainerStyle paramContainerStyle = t.getParamContainerStyle(); + if (paramContainerStyle == null || paramContainerStyle instanceof DefaultThemedParamContainerStyle) { + paramContainerStyle = new ThemedParamContainerStyle(); + t.setParamContainerStyle(paramContainerStyle); + } + backgroundPane.populateBean(paramContainerStyle.getBackground()); + } + + @Override + public T updateBean() { + return null; + } + + @Override + public void updateBean(T t) { + ThemedParamContainerStyle style = (ThemedParamContainerStyle) t.getParamContainerStyle(); + if (style == null) { + style = new ThemedParamContainerStyle(); + t.setParamContainerStyle(style); + } + style.setBackground(backgroundPane.update()); + } + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Widget_Theme_ParamContainer"); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/edit/widget/DesktopWidgetStyleEditPane.java b/designer-base/src/main/java/com/fr/widgettheme/theme/edit/widget/DesktopWidgetStyleEditPane.java new file mode 100644 index 0000000000..4af7b9b6d1 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/edit/widget/DesktopWidgetStyleEditPane.java @@ -0,0 +1,177 @@ +package com.fr.widgettheme.theme.edit.widget; + +import com.fine.swing.ui.layout.Column; +import com.fr.base.background.ColorBackground; +import com.fr.base.theme.TemplateTheme; +import com.fr.design.gui.icombobox.LineComboBox; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.design.style.color.NewColorSelectBox; +import com.fr.design.utils.DesignUtils; +import com.fr.design.widget.FRWidgetFactory; +import com.fr.locale.InterProviderFactory; +import com.fr.stable.StringUtils; +import com.fr.util.ColorUtils; +import com.fr.widgettheme.theme.widget.style.BorderStyle; +import com.fr.widgettheme.theme.widget.style.ButtonBackgroundStyle; +import com.fr.widgettheme.theme.widget.style.ThemeTextStyle; +import com.fr.widgettheme.theme.widget.style.ThemedWidgetStyle; +import com.fr.widgettheme.theme.widget.theme.WidgetThemeDisplayConstants; +import com.fr.widgettheme.util.WidgetStyleComponentCombiner; +import com.fr.widgettheme.util.WidgetThemeDesignerUtils; + +import java.awt.Color; +import java.awt.Component; + +import static com.fine.swing.ui.layout.Layouts.cell; +import static com.fine.swing.ui.layout.Layouts.column; + + +/** + * 桌面端主题面板 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/3/28 + */ +public class DesktopWidgetStyleEditPane extends WidgetStyleEditPane { + + /** + * 字体名选择器 + */ + protected UIComboBox fontNameSelectBox; + + /** + * 下拉面板背景颜色 + */ + private NewColorSelectBox selectBackgroundColorBox; + + public DesktopWidgetStyleEditPane() { + super(); + } + + @Override + public Component[][] generateComponent() { + initSelectBackgroundColorBox(); + initFontNameSelectBox(); + return new Component[][]{ + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Color")), colorSelectBox}, + new Component[]{WidgetThemeDesignerUtils.createTopAlignmentLabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Widget_Background")), initBackGroundComponent()}, + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Border_Line")), lineComboBox}, + new Component[]{null, lineComboColorSelectBox}, + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Border_Radius")), borderRadiusSpinner}, + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Icon_Color")), iconColorSelectBox}, + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Text_Style")), fontNameSelectBox}, + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Text_Style")), WidgetStyleComponentCombiner.combineTextStyleComponent(fontSizePane, fontColorButton, italic, bold)}, + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Widget_Background_Select_Box")), selectBackgroundColorBox} + }; + } + + private Column initBackGroundComponent() { + return column(10, + cell(widgetBgColorSelectBox), + cell(FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Form_Widget-Style_Alpha"))), + cell(widgetBgAlphaDragPane)).getComponent(); + } + + private void initSelectBackgroundColorBox() { + selectBackgroundColorBox = new NewColorSelectBox(140, true); + selectBackgroundColorBox.setSelectObject(WidgetThemeDisplayConstants.DEFAULT_THEME_COLOR); + } + + private void initFontNameSelectBox() { + fontNameSelectBox = new UIComboBox(DesignUtils.getAvailableFontFamilyNames4Report()); + } + + @Override + public void populateBean(T t) { + ThemedWidgetStyle style = (ThemedWidgetStyle) t.getWidgetStyle(); + if (style == null) { + style = new ThemedWidgetStyle(); + t.setWidgetStyle(style); + } + colorSelectBox.setSelectObject(style.getThemeColor()); + selectBackgroundColorBox.setSelectObject(style.getSelectBackgroundColor()); + iconColorSelectBox.setSelectObject(style.getIconColor()); + populateBorder(style); + populateTextStyle(style); + populateWidgetBackground(style); + } + + @Override + public void updateBean(T t) { + ThemedWidgetStyle style = (ThemedWidgetStyle) t.getWidgetStyle(); + if (style == null) { + style = new ThemedWidgetStyle(); + t.setWidgetStyle(style); + } + updateBorderStyle(style); + updateTextStyle(style); + updateButtonBackground(style); + updateWidgetBackground(style); + style.setThemeColor(colorSelectBox.getSelectObject()); + style.setSelectBackgroundColor(selectBackgroundColorBox.getSelectObject()); + style.setIconColor(iconColorSelectBox.getSelectObject()); + } + + private void updateBorderStyle(ThemedWidgetStyle style) { + BorderStyle borderStyle = new BorderStyle(); + borderStyle.setLineType(lineComboBox.getSelectedLineStyle()); + borderStyle.setRadius((int) borderRadiusSpinner.getValue()); + borderStyle.setBorderColor(lineComboColorSelectBox.getSelectObject()); + style.setBorderStyle(borderStyle); + } + + private void updateTextStyle(ThemedWidgetStyle style) { + ThemeTextStyle textStyle = new ThemeTextStyle(); + textStyle.setFontSize(fontSizePane.getValue()); + textStyle.setFontColor(fontColorButton.getColor()); + textStyle.setName((String) fontNameSelectBox.getSelectedItem()); + textStyle.setBold(bold.isSelected()); + textStyle.setItalic(italic.isSelected()); + style.setTextStyle(textStyle); + } + + private void updateButtonBackground(ThemedWidgetStyle style) { + ButtonBackgroundStyle buttonBackgroundStyle = new ButtonBackgroundStyle(); + ColorBackground buttonBackground = ColorBackground.getInstance(style.getThemeColor()); + buttonBackgroundStyle.setInitialBackground(buttonBackground); + buttonBackgroundStyle.setOverBackground(buttonBackground); + buttonBackgroundStyle.setClickBackground(buttonBackground); + style.setButtonBackgroundStyle(buttonBackgroundStyle); + } + + private void updateWidgetBackground(ThemedWidgetStyle style) { + Color bgColor = widgetBgColorSelectBox.getSelectObject(); + style.setWidgetBackground(ColorUtils.createColorBackgroundWithAlpha(bgColor, widgetBgAlphaDragPane.updateBean())); + } + + private void populateTextStyle(ThemedWidgetStyle style) { + ThemeTextStyle textStyle = style.getTextStyle(); + fontSizePane.setValue(textStyle.getFontSize()); + fontColorButton.setColor(textStyle.getFontColor()); + bold.setSelected(textStyle.isBold()); + italic.setSelected(textStyle.isItalic()); + String fontName = StringUtils.isEmpty(textStyle.getName()) ? InterProviderFactory.getProvider().getLocText("Fine-Engine_Base_Song_TypeFace") : textStyle.getName(); + fontNameSelectBox.setSelectedItem(fontName); + } + + private void populateBorder(ThemedWidgetStyle style) { + lineComboBox.setSelectedLineStyle(style.getBorderStyle().getLineType()); + lineComboColorSelectBox.setSelectObject(style.getBorderStyle().getBorderColor()); + borderRadiusSpinner.setValue(style.getBorderStyle().getRadius()); + } + + private void populateWidgetBackground(ThemedWidgetStyle style) { + widgetBgColorSelectBox.setSelectObject(ColorUtils.ignoreColorAlpha(style.getWidgetBackground().getColor())); + widgetBgAlphaDragPane.populateBean(ColorUtils.roundColorAlphaDouble(style.getWidgetBackground().getColor())); + } + + @Override + public void initLineBox() { + lineComboBox = new LineComboBox(WidgetThemeDisplayConstants.BORDER_LINE_STYLE_ARRAY); + lineComboColorSelectBox = new NewColorSelectBox(WidgetThemeDisplayConstants.THEME_WIDGET_COMPONENT_WIDTH, true); + lineComboBox.addItemListener(e -> lineComboColorSelectBox.setVisible(!Integer.valueOf(0).equals(e.getItem()))); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/edit/widget/MobileWidgetStyleEditPane.java b/designer-base/src/main/java/com/fr/widgettheme/theme/edit/widget/MobileWidgetStyleEditPane.java new file mode 100644 index 0000000000..0e5200418f --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/edit/widget/MobileWidgetStyleEditPane.java @@ -0,0 +1,93 @@ +package com.fr.widgettheme.theme.edit.widget; + +import com.fr.base.theme.TemplateTheme; +import com.fr.design.gui.frpane.FontSizeComboPane; +import com.fr.design.style.color.NewColorSelectBox; +import com.fr.util.ColorUtils; +import com.fr.widgettheme.theme.widget.style.BorderStyle; +import com.fr.widgettheme.theme.widget.style.MobileThemedWidgetStyle; +import com.fr.design.gui.icombobox.LineComboBox; +import com.fr.widgettheme.theme.widget.style.ThemeTextStyle; +import com.fr.widgettheme.theme.widget.theme.WidgetThemeDisplayConstants; + +import java.util.Arrays; +import java.util.Vector; + +/** + * 移动端控件样式编辑面板 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/3/28 + */ +public class MobileWidgetStyleEditPane extends WidgetStyleEditPane { + /** + * 移动端字体列表 12-18 + */ + private static Vector FONT_SIZES = new Vector() { + { + addAll(Arrays.asList(12, 13, 14, 15, 16, 17, 18)); + } + }; + + public MobileWidgetStyleEditPane() { + super(); + } + + @Override + public void initLineBox() { + lineComboBox = new LineComboBox(WidgetThemeDisplayConstants.MOBILE_BORDER_LINE_STYLE_ARRAY); + lineComboBox.setSelectedLineStyle(com.fr.stable.Constants.LINE_THIN); + lineComboColorSelectBox = new NewColorSelectBox(WidgetThemeDisplayConstants.THEME_WIDGET_COMPONENT_WIDTH, true); + lineComboBox.addItemListener(e -> lineComboColorSelectBox.setVisible(!Integer.valueOf(0).equals(e.getItem()))); + } + + @Override + protected void initFontSizePane() { + fontSizePane = new FontSizeComboPane(FONT_SIZES); + } + + @Override + public void populateBean(T t) { + MobileThemedWidgetStyle style = (MobileThemedWidgetStyle) t.getMobileWidgetStyle(); + if (style == null) { + style = new MobileThemedWidgetStyle(); + t.setMobileWidgetStyle(style); + } + colorSelectBox.setSelectObject(style.getThemeColor()); + widgetBgColorSelectBox.setSelectObject(ColorUtils.ignoreColorAlpha(style.getWidgetBackground().getColor())); + widgetBgAlphaDragPane.populateBean(ColorUtils.roundColorAlphaDouble(style.getWidgetBackground().getColor())); + lineComboBox.setSelectedLineStyle(style.getBorderStyle().getLineType()); + lineComboColorSelectBox.setSelectObject(style.getBorderStyle().getBorderColor()); + iconColorSelectBox.setSelectObject(style.getIconColor()); + borderRadiusSpinner.setValue(style.getBorderStyle().getRadius()); + fontSizePane.setValue(style.getTextStyle().getFontSize()); + fontColorButton.setColor(style.getTextStyle().getFontColor()); + bold.setSelected(style.getTextStyle().isBold()); + italic.setSelected(style.getTextStyle().isItalic()); + } + + @Override + public void updateBean(T t) { + MobileThemedWidgetStyle style = (MobileThemedWidgetStyle) t.getMobileWidgetStyle(); + if (style == null) { + style = new MobileThemedWidgetStyle(); + t.setMobileWidgetStyle(style); + } + style.setThemeColor(colorSelectBox.getSelectObject()); + style.setWidgetBackground(ColorUtils.createColorBackgroundWithAlpha(widgetBgColorSelectBox.getSelectObject(), widgetBgAlphaDragPane.updateBean())); + BorderStyle borderStyle = new BorderStyle(); + borderStyle.setLineType(lineComboBox.getSelectedLineStyle()); + borderStyle.setRadius((int) borderRadiusSpinner.getValue()); + borderStyle.setBorderColor(lineComboColorSelectBox.getSelectObject()); + style.setBorderStyle(borderStyle); + style.setIconColor(iconColorSelectBox.getSelectObject()); + ThemeTextStyle textStyle = new ThemeTextStyle(); + textStyle.setFontSize(fontSizePane.getValue()); + textStyle.setFontColor(fontColorButton.getColor()); + textStyle.setBold(bold.isSelected()); + textStyle.setItalic(italic.isSelected()); + style.setTextStyle(textStyle); + } + +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/edit/widget/WidgetStyleEditContainerPane.java b/designer-base/src/main/java/com/fr/widgettheme/theme/edit/widget/WidgetStyleEditContainerPane.java new file mode 100644 index 0000000000..16e4a4f58c --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/edit/widget/WidgetStyleEditContainerPane.java @@ -0,0 +1,141 @@ +package com.fr.widgettheme.theme.edit.widget; + +import com.fr.base.theme.TemplateTheme; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.designer.IntervalConstants; +import com.fr.design.gui.ibutton.UIButtonGroup; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.widgettheme.ThemePreviewTerminal; +import org.jetbrains.annotations.Nullable; + +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/** + * 组件主题编辑容器,包含移动端控制面板和桌面端控制面板 + * 默认展开桌面端 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/3/28 + */ +public class WidgetStyleEditContainerPane extends BasicBeanPane { + private UIButtonGroup terminalStyleGroup; + private WidgetStyleEditPane desktop; + private WidgetStyleEditPane mobile; + + public WidgetStyleEditContainerPane() { + initComponent(); + } + + private void initComponent() { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + // 初始化按钮组,桌面端&移动端 + initButtonGroup(); + // 创建按钮组面板 + createButtonGroupPane(); + // 默认选中桌面端 + terminalStyleGroup.setSelectedIndex(0); + // cardLayout用来切换面板 + // 桌面端 + initDesktopPanel(); + // 移动端 + initMobilePanel(); + createCardContainer(); + initListener(); + } + + private void createCardContainer() { + JPanel cardPanel = FRGUIPaneFactory.createCardLayout_S_Pane(); + cardPanel.add(desktop, BorderLayout.CENTER); + cardPanel.add(mobile, BorderLayout.CENTER); + this.add(cardPanel, BorderLayout.CENTER); + } + + private void initMobilePanel() { + mobile = new MobileWidgetStyleEditPane<>(); + mobile.setVisible(false); + } + + private void initDesktopPanel() { + desktop = new DesktopWidgetStyleEditPane<>(); + // 默认可见性 + desktop.setVisible(true); + } + + private void createButtonGroupPane() { + Component[][] components = { + new Component[]{terminalStyleGroup}, + }; + final double p = TableLayout.PREFERRED; + double[] rowSize = {p}; + double[] columnSize = {p, p}; + int[][] rowCount = {{1, 1}}; + JPanel groupPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, IntervalConstants.INTERVAL_W1, IntervalConstants.INTERVAL_L1); + this.add(groupPane, BorderLayout.NORTH); + } + + /** + * 初始化按钮组 + */ + private void initButtonGroup() { + terminalStyleGroup = new UIButtonGroup<>(new String[]{ + Toolkit.i18nText("Fine-Design_Widget_Terminal_Desktop"), + Toolkit.i18nText("Fine-Design_Widget_Terminal_Mobile")}); + this.add(terminalStyleGroup, BorderLayout.NORTH); + terminalStyleGroup.setSelectedIndex(0); + } + + /** + * 初始化按钮组的listener + */ + private void initListener() { + terminalStyleGroup.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + showTerminalPane(); + } + }); + } + + /** + * 展示具体面板 + */ + private void showTerminalPane() { + desktop.setVisible(terminalStyleGroup.getSelectedIndex() == 0); + mobile.setVisible(terminalStyleGroup.getSelectedIndex() == 1); + } + + @Override + public void populateBean(T ob) { + desktop.populateBean(ob); + mobile.populateBean(ob); + } + + @Nullable + @Override + public T updateBean() { + return null; + } + + @Override + public void updateBean(T ob) { + desktop.updateBean(ob); + mobile.updateBean(ob); + } + + @Override + protected String title4PopupWindow() { + return Toolkit.i18nText("Fine-Design_Theme_Widget_Style"); + } + + public ThemePreviewTerminal getTerminalStyle() { + return ThemePreviewTerminal.getTypeByCode(terminalStyleGroup.getSelectedIndex()); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/edit/widget/WidgetStyleEditPane.java b/designer-base/src/main/java/com/fr/widgettheme/theme/edit/widget/WidgetStyleEditPane.java new file mode 100644 index 0000000000..bf6ad6c4fd --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/edit/widget/WidgetStyleEditPane.java @@ -0,0 +1,175 @@ +package com.fr.widgettheme.theme.edit.widget; + +import com.fine.swing.ui.layout.Column; +import com.fr.base.theme.TemplateTheme; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.designer.IntervalConstants; +import com.fr.design.gui.frpane.FontSizeComboPane; +import com.fr.design.gui.frpane.UIPercentDragPane; +import com.fr.design.gui.ibutton.UIColorButton; +import com.fr.design.gui.ibutton.UIToggleButton; +import com.fr.design.gui.icombobox.LineComboBox; +import com.fr.design.gui.icontainer.UIScrollPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.ispinner.UISpinner; +import com.fr.design.gui.style.FRFontPane; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.style.color.NewColorSelectBox; +import com.fr.design.widget.FRWidgetFactory; +import com.fr.general.IOUtils; +import com.fr.stable.StringUtils; +import com.fr.widgettheme.theme.widget.theme.WidgetThemeDisplayConstants; +import com.fr.widgettheme.util.WidgetStyleComponentCombiner; +import com.fr.widgettheme.util.WidgetThemeDesignerUtils; +import org.jetbrains.annotations.Nullable; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Component; + +import static com.fine.swing.ui.layout.Layouts.cell; +import static com.fine.swing.ui.layout.Layouts.column; + + +/** + * 组件样式编辑基础类 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/5/22 + */ +public class WidgetStyleEditPane extends BasicBeanPane { + + // 主题色 + protected NewColorSelectBox colorSelectBox; + + // 边框线型 + protected LineComboBox lineComboBox; + + /** + * 边框颜色 + */ + protected NewColorSelectBox lineComboColorSelectBox; + // 圆角边框 + protected UISpinner borderRadiusSpinner; + /** + * 文本样式面板 + */ + protected FontSizeComboPane fontSizePane; + + protected UIColorButton fontColorButton; + + /** + * 控件背景和透明度配置面板 + */ + protected NewColorSelectBox widgetBgColorSelectBox; + protected UIPercentDragPane widgetBgAlphaDragPane; + /** + * 图标颜色 + */ + protected NewColorSelectBox iconColorSelectBox; + + /** + * 字体粗体斜体配置 + */ + protected UIToggleButton bold; + protected UIToggleButton italic; + + protected JPanel leftPanel; + + public WidgetStyleEditPane() { + initComponents(); + } + + private void initComponents() { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + initCommonStyleEditor(); + double f = TableLayout.FILL; + final double p = TableLayout.PREFERRED; + double[] rowSize = {p, p, p, p, p, p, p, p, p}; + double[] columnSize = {p, WidgetThemeDisplayConstants.THEME_WIDGET_COMPONENTS_COL_WIDTH}; + int[][] rowCount = {{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}; + Component[][] components = generateComponent(); + JPanel customPane = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, IntervalConstants.INTERVAL_W1, IntervalConstants.INTERVAL_L1); + customPane.setBorder(BorderFactory.createEmptyBorder(20, 10, 20, 10)); + this.add(customPane, BorderLayout.NORTH); + UIScrollPane scrollPane = new UIScrollPane(customPane); + this.add(scrollPane); + } + + /** + * 初始化标签 + * + * @return components + */ + public Component[][] generateComponent() { + return new Component[][]{ + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Color")), colorSelectBox}, + new Component[]{WidgetThemeDesignerUtils.createTopAlignmentLabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Widget_Background")), initBackGroundComponent()}, + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Border_Line")), lineComboBox}, + new Component[]{null, lineComboColorSelectBox}, + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Border_Radius")), borderRadiusSpinner}, + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Icon_Color")), iconColorSelectBox}, + new Component[]{new UILabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Text_Style")), WidgetStyleComponentCombiner.combineTextStyleComponent(fontSizePane, fontColorButton, italic, bold)} + }; + } + + private Column initBackGroundComponent() { + return column(10, + cell(widgetBgColorSelectBox), + cell(FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Form_Widget-Style_Alpha"))), + cell(widgetBgAlphaDragPane) + ).getComponent(); + } + + private void initCommonStyleEditor() { + colorSelectBox = new NewColorSelectBox(WidgetThemeDisplayConstants.THEME_WIDGET_COMPONENT_WIDTH, true); + colorSelectBox.setSelectObject(WidgetThemeDisplayConstants.DEFAULT_THEME_COLOR); + widgetBgColorSelectBox = new NewColorSelectBox(WidgetThemeDisplayConstants.THEME_WIDGET_COMPONENT_WIDTH, true); + widgetBgAlphaDragPane = new UIPercentDragPane(); + initLineBox(); + borderRadiusSpinner = new UISpinner(0, Integer.MAX_VALUE, 1); + iconColorSelectBox = new NewColorSelectBox(WidgetThemeDisplayConstants.THEME_WIDGET_COMPONENT_WIDTH, true); + initFontSizePane(); + fontColorButton = new UIColorButton(); + bold = new UIToggleButton(IOUtils.readIcon("/com/fr/design/images/m_format/cellstyle/bold.png")); + italic = new UIToggleButton(IOUtils.readIcon("/com/fr/design/images/m_format/cellstyle/italic.png")); + } + + protected void initFontSizePane() { + fontSizePane = new FontSizeComboPane(FRFontPane.getFontSizes()); + } + + /** + * 初始化边框线型 + */ + public void initLineBox() { + } + + + @Override + public void populateBean(T t) { + + } + + @Nullable + @Override + public T updateBean() { + return null; + } + + @Override + public void updateBean(T t) { + } + + + @Override + protected String title4PopupWindow() { + return StringUtils.EMPTY; + } + +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ButtonStyleDefinedPane.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ButtonStyleDefinedPane.java new file mode 100644 index 0000000000..e65b372ac4 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ButtonStyleDefinedPane.java @@ -0,0 +1,75 @@ +package com.fr.widgettheme.theme.panel; + +import com.fr.widgettheme.theme.widget.style.ButtonBackgroundStyle; +import com.fr.design.dialog.BasicPane; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.widgettheme.theme.bean.ButtonBackground; +import com.fr.design.mainframe.widget.accessibles.AccessibleImgBackgroundEditor; +import com.fr.general.Background; + +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Component; + +/** + * 按钮样式定义窗口 + * + * @author obo + * @since 11.0 + * Created on 2023/11/13 + */ +public class ButtonStyleDefinedPane extends BasicPane { + + protected AccessibleImgBackgroundEditor initBackgroundPane; + protected AccessibleImgBackgroundEditor overBackgroundPane; + protected AccessibleImgBackgroundEditor clickBackgroundPane; + + public ButtonStyleDefinedPane() { + this.initComponents(); + } + + protected void initComponents() { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + initBackgroundPane = new AccessibleImgBackgroundEditor(); + overBackgroundPane = new AccessibleImgBackgroundEditor(); + clickBackgroundPane = new AccessibleImgBackgroundEditor(); + double f = TableLayout.FILL; + final double p = TableLayout.PREFERRED; + double[] rowSize = {p, p, p}; + double[] columnSize = {p, f}; + int[][] rowCount = {{1, 1},{1, 1},{1, 1}}; + Component[][] components = new Component[][]{ + new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Background_Initial")), initBackgroundPane}, + new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Background_Over")), overBackgroundPane}, + new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Background_Click")), clickBackgroundPane}, + }; + JPanel panel = TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, 7, 7); + this.add(panel, BorderLayout.CENTER); + + } + + /** + * 填充 + */ + public void populate(ButtonBackground buttonBackground) { + initBackgroundPane.setValue(buttonBackground.getInitialBackground()); + overBackgroundPane.setValue(buttonBackground.getOverBackground()); + clickBackgroundPane.setValue(buttonBackground.getClickBackground()); + } + + /** + * 更新 + */ + public ButtonBackgroundStyle update() { + return new ButtonBackgroundStyle((Background) initBackgroundPane.getValue(), (Background) overBackgroundPane.getValue(), (Background) clickBackgroundPane.getValue()); + } + + @Override + protected String title4PopupWindow() { + return null; + } + +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ControlPreviewCell.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ControlPreviewCell.java new file mode 100644 index 0000000000..ec36032713 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ControlPreviewCell.java @@ -0,0 +1,143 @@ +package com.fr.widgettheme.theme.panel; + +import com.fr.base.BaseUtils; +import com.fr.base.Style; +import com.fr.base.theme.TemplateTheme; +import com.fr.widgettheme.ThemePreviewTerminal; +import com.fr.widgettheme.theme.widget.style.ThemeTextStyle; +import com.fr.widgettheme.theme.widget.style.ThemedWidgetStyle; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.general.FRFont; +import com.fr.stable.Constants; +import com.fr.widgettheme.theme.widget.theme.WidgetThemeDisplayConstants; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JPanel; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.LayoutManager; +import java.awt.image.BufferedImage; + +/** + * 主题界面预览单元格子 + * + * @author John.Ying + * @since 11.0 + * Created on 2023/3/18 + */ +public class ControlPreviewCell extends JPanel { + protected static final LayoutManager DEFAULT = FRGUIPaneFactory.createRightFlowLayout(); + protected static final Color DEFAULT_COLOR = new Color(210, 210, 210); + protected static final Color DEFAULT_THEME_COLOR = new Color(54, 133, 242); + protected static final String DEFAULT_MESSAGE = ""; + protected static final int NO_SCALE_RESOLUTION = 100; + protected static final int DEFAULT_ALPHA = 255; + /** + * 格子文本数据 + */ + protected String value; + protected TemplateTheme reportTheme; + + /** + * 主题预览类型,默认为PC端 + */ + protected ThemePreviewTerminal themePreviewTerminal = ThemePreviewTerminal.PC; + /** + * 字体的颜色 + */ + protected Color textColor = DEFAULT_COLOR; + + public Color getTextColor() { + return textColor; + } + + public void setTextColor(Color textColor) { + this.textColor = textColor; + } + + public ControlPreviewCell() { + this(DEFAULT, DEFAULT_MESSAGE); + } + + public ControlPreviewCell(String value) { + this(DEFAULT, value); + } + + public ControlPreviewCell(LayoutManager layoutManager, String value) { + this.setLayout(layoutManager); + this.setOpaque(false); + this.value = value; + this.setPreferredSize(new Dimension(80, 30)); + } + + /** + * 主题样式变化后监听改变 + */ + public void refresh(TemplateTheme reportTheme, ThemePreviewTerminal type) { + this.reportTheme = reportTheme; + this.themePreviewTerminal = type; + ThemedWidgetStyle widgetStyle = this.themePreviewTerminal.getThemeWidgetStyle(reportTheme); + //主题色设置为透明或者插件启动前已有的主题启动插件后主题色为null + if (widgetStyle.getThemeColor() == null) { + widgetStyle.setThemeColor(DEFAULT_THEME_COLOR); + } + } + + /** + * 填充圆角矩形背景色 + */ + public void paintBgColor(Graphics g, ThemedWidgetStyle widgetStyle) { + this.paintBgColor(g, widgetStyle, DEFAULT_ALPHA); + } + + public Color getIconColor() { + return this.themePreviewTerminal.getThemeWidgetStyle(reportTheme).getIconColor(); + } + + protected Icon setStyleTwoIcon(Icon icon, Icon defaultIcon) { + if (this.reportTheme != null) { + if (icon instanceof ImageIcon) { + ImageIcon imageIcon = (ImageIcon) icon; + BufferedImage bufferedImage = ImageUtils.colorImage(ImageUtils.imageIconToBufferedImage(imageIcon), getIconColor()); + return new ImageIcon(bufferedImage); + } + } + return defaultIcon; + } + + /** + * 填充圆角矩形背景色 + */ + public void paintBgColor(Graphics g, ThemedWidgetStyle widgetStyle, int alpha) { + ThemedWidgetStyle themeWidgetStyle = this.themePreviewTerminal.getThemeWidgetStyle(this.reportTheme); + Color themeColor = themeWidgetStyle.getThemeColor(); + themeColor = themeColor == null ? WidgetThemeDisplayConstants.DEFAULT_TRANSPARENT_COLOR : themeColor; + g.setColor(new Color(themeColor.getRed(), themeColor.getGreen(), themeColor.getBlue(), alpha)); + g.fillRoundRect(0, 0, getSize().width - 1, getSize().height - 1, (int) widgetStyle.getBorderStyle().getRadius(), (int) widgetStyle.getBorderStyle().getRadius()); + //需要重新绘制一遍字体,否则会被颜色填充给遮住 + Graphics2D g2d = (Graphics2D) g.create(); + ThemeTextStyle textStyle = themeWidgetStyle.getTextStyle(); + FRFont font = FRFont.getInstance(textStyle.getName(), textStyle.getCompositeFontStyle(), textStyle.getFontSize(), textStyle.getFontColor()); + BaseUtils.drawStringStyleInRotation(g2d, getWidth(), getHeight(), this.value, + Style.getInstance(font).deriveHorizontalAlignment(Constants.LEFT) + .deriveTextStyle(Style.TEXTSTYLE_SINGLELINE), NO_SCALE_RESOLUTION); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + if (this.reportTheme == null) { + return; + } + Graphics2D g2d = (Graphics2D) g.create(); + ThemeTextStyle textStyle = this.themePreviewTerminal.getThemeWidgetStyle(reportTheme).getTextStyle(); + FRFont font = FRFont.getInstance(textStyle.getName(), textStyle.getCompositeFontStyle(), textStyle.getFontSize(), textStyle.getFontColor()); + //每个预览格子通用的字体绘制 + BaseUtils.drawStringStyleInRotation(g2d, getWidth(), getHeight(), this.value, + Style.getInstance(font).deriveHorizontalAlignment(Constants.LEFT) + .deriveTextStyle(Style.TEXTSTYLE_SINGLELINE), NO_SCALE_RESOLUTION); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ControlPreviewCellWithIcon.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ControlPreviewCellWithIcon.java new file mode 100644 index 0000000000..491af469f8 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ControlPreviewCellWithIcon.java @@ -0,0 +1,74 @@ +package com.fr.widgettheme.theme.panel; + + +import com.fr.base.svg.IconUtils; +import com.fr.widgettheme.theme.widget.style.ThemedWidgetStyle; +import com.fr.design.border.UIRoundedBorder; +import com.fr.stable.StringUtils; + +import javax.swing.Icon; +import javax.swing.JLabel; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.LayoutManager; + +/** + * 主题界面预览控件单元格子,控件图表直接用icon + * + * @author John.Ying + * @since 11.0 + * Created on 2023/3/18 + */ +public class ControlPreviewCellWithIcon extends ControlPreviewCell { + private static final int CONTROL_ALPHA = 16; + + JLabel jLabel; + Icon icon; + Icon defaultIcon; + + public ControlPreviewCellWithIcon() { + this(DEFAULT, DEFAULT_MESSAGE); + } + + public ControlPreviewCellWithIcon(String value) { + this(DEFAULT, value); + } + + public ControlPreviewCellWithIcon(LayoutManager layoutManager, String value) { + this.setLayout(layoutManager); + this.value = value; + this.setPreferredSize(new Dimension(100, 27)); + } + + /** + * 根据icon地址绘制一个图标,用jlabel进行展示 + * + * @param url icon地址 + */ + public void drawIcon(String url) { + if (StringUtils.isEmpty(url)) { + return; + } + defaultIcon = IconUtils.readIcon(url); + icon = setStyleTwoIcon(icon, defaultIcon); + this.jLabel = new JLabel(icon); + jLabel.setPreferredSize(new Dimension(21, 17)); + + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + ThemedWidgetStyle widgetStyle = (ThemedWidgetStyle) reportTheme.getWidgetStyle(); + //风格一边框不显示主题色 + Color borderColor = widgetStyle.getBorderStyle().getBorderColor(); + this.setBorder(new UIRoundedBorder(widgetStyle.getBorderStyle().getLineType() + , borderColor, (int) widgetStyle.getBorderStyle().getRadius())); + icon = setStyleTwoIcon(icon, defaultIcon); + this.jLabel.setIcon(icon); + this.add(jLabel, BorderLayout.EAST); + paintBgColor(g, widgetStyle, CONTROL_ALPHA); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ControlPreviewPane.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ControlPreviewPane.java new file mode 100644 index 0000000000..69a34fd3bc --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ControlPreviewPane.java @@ -0,0 +1,139 @@ +package com.fr.widgettheme.theme.panel; + +import com.fr.base.background.ColorBackground; +import com.fr.base.theme.TemplateTheme; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.theme.preview.ThemePreviewed; +import com.fr.general.Background; +import com.fr.widgettheme.ThemePreviewTerminal; + +import javax.swing.JPanel; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.List; + +/** + * 主题界面页面中的参数界面 + * + * @author John.Ying + * @since 11.0 + * Created on 2023/3/18 + */ +public class ControlPreviewPane extends JPanel implements ThemePreviewed { + + public static final int PREVIEW_WIDTH = 615; + + public static final int PREVIEW_HEIGHT = 62; + + /** + * 参数界面中放置的所有cell,用于监听主题样式变更 + */ + public final List list = new ArrayList<>(); + + private Background background; + + private static final String DATE_ICON_URL = "/com/fr/web/images/form/resources/date_16.png"; + + private static final String COMBOBOX_ICON_URL = "/com/fr/widgettheme/combobox.png"; + + @Override + public void refresh(TemplateTheme style) { + refresh(style, ThemePreviewTerminal.PC); + } + + @Override + public void refresh(TemplateTheme style, ThemePreviewTerminal type) { + this.background = style.getParamContainerStyle().getBackground(); + for (ControlPreviewCell controlPreviewCell : list) { + controlPreviewCell.refresh(style, type); + } + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + paintBackground((Graphics2D) g); + } + + protected void paintBackground(Graphics2D g2d) { + if (background == null) { + background = ColorBackground.getInstance(Color.WHITE); + } + background.paint(g2d, new Rectangle2D.Double(0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT)); + } + + /** + * 初始化参数界面,往里面添加各种cell + */ + public void initControlPreviewPane() { + initDateControlPane(); + initComboboxControlPane(); + initRadioButtonControlPane(); + initNormalButtonControlPane(); + } + + /** + * 初始化日期控件包括文字跟控件 + */ + private void initDateControlPane() { + TextPreviewCell dateTextCell = new TextPreviewCell(Toolkit.i18nText("Fine-Design_Theme_Control_Date_Text")); + dateTextCell.setPreferredSize(new Dimension(80, 30)); + ControlPreviewCellWithIcon dateEditorCell = new ControlPreviewCellWithIcon(Toolkit.i18nText("Fine-Design_Theme_Control_Date_Editor_Text")); + dateEditorCell.drawIcon(DATE_ICON_URL); + dateEditorCell.setTextColor(ControlPreviewCell.DEFAULT_COLOR); + this.add(dateTextCell); + this.add(dateEditorCell); + this.list.add(dateTextCell); + this.list.add(dateEditorCell); + } + + /** + * 初始化下拉框控件包括文件跟控件 + */ + private void initComboboxControlPane() { + TextPreviewCell comboBoxTextCell = new TextPreviewCell(Toolkit.i18nText("Fine-Design_Theme_Control_ComboBox_Text")); + comboBoxTextCell.setPreferredSize(new Dimension(60, 30)); + ControlPreviewCellWithIcon comboBoxControlPreviewCell = new ControlPreviewCellWithIcon(Toolkit.i18nText("Fine-Design_Theme_Control_ComboBox_Editor_Text")); + comboBoxControlPreviewCell.drawIcon(COMBOBOX_ICON_URL); + comboBoxControlPreviewCell.setTextColor(ControlPreviewCell.DEFAULT_COLOR); + this.add(comboBoxTextCell); + this.add(comboBoxControlPreviewCell); + this.list.add(comboBoxControlPreviewCell); + this.list.add(comboBoxTextCell); + } + + /** + * 初始化单选按钮组控件 + */ + private void initRadioButtonControlPane() { + RingControlPreviewCell ringControlPreviewCell = new RingControlPreviewCell(); + RoundControlPreviewCell roundControlPreviewCell = new RoundControlPreviewCell(); + + TextPreviewCell yearTextFieldCell = new TextPreviewCell(Toolkit.i18nText("Fine-Design_Theme_Control_Radio_Year")); + yearTextFieldCell.setPreferredSize(new Dimension(38, 30)); + TextPreviewCell monthTextFieldCell = new TextPreviewCell(Toolkit.i18nText("Fine-Design_Theme_Control_Radio_Month")); + monthTextFieldCell.setPreferredSize(new Dimension(38, 30)); + this.add(ringControlPreviewCell); + this.add(yearTextFieldCell); + this.add(roundControlPreviewCell); + this.add(monthTextFieldCell); + this.list.add(ringControlPreviewCell); + this.list.add(roundControlPreviewCell); + this.list.add(yearTextFieldCell); + this.list.add(monthTextFieldCell); + } + + /** + * 初始化按钮预览格子 + */ + private void initNormalButtonControlPane() { + NormalButtonPreviewCell normalButton = new NormalButtonPreviewCell(FRGUIPaneFactory.createCenterFlowLayout(), ControlPreviewCell.DEFAULT_MESSAGE); + this.add(normalButton); + this.list.add(normalButton); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ImageUtils.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ImageUtils.java new file mode 100644 index 0000000000..63da90e6f7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/ImageUtils.java @@ -0,0 +1,89 @@ +package com.fr.widgettheme.theme.panel; + +import javax.swing.ImageIcon; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.awt.image.WritableRaster; + +/** + * 控件主题Image处理工具类 + * + * @author obo + * @since 11.0 + * Created on 2023/11/13 + */ +public class ImageUtils { + + /** + * 根据主题色处理image + * + * @param image 图像 + * @param color 主题色 + * @return 处理结果 + */ + public static BufferedImage colorImage(BufferedImage image, Color color) { + int width = image.getWidth(); + int height = image.getHeight(); + WritableRaster raster = image.getRaster(); + + for (int xx = 0; xx < width; xx++) { + for (int yy = 0; yy < height; yy++) { + int[] pixels = raster.getPixel(xx, yy, (int[]) null); + setRedPixels(pixels, color); + setGreenPixels(pixels, color); + setBluePixels(pixels, color); + raster.setPixel(xx, yy, pixels); + } + } + return image; + } + + /** + * 处理红像素 + * + * @param pixels 像素数组 + * @param color 颜色 + */ + private static void setRedPixels(int[] pixels, Color color) { + pixels[0] = pixels[0] > 0 && pixels[0] < 255 ? color.getRed() : 255; + } + + /** + * 处理绿像素 + * + * @param pixels 像素数组 + * @param color 颜色 + */ + private static void setGreenPixels(int[] pixels, Color color) { + pixels[1] = pixels[1] > 0 && pixels[1] < 255 ? color.getGreen() : 255; + } + + /** + * 处理蓝像素 + * + * @param pixels 像素数组 + * @param color 颜色 + */ + private static void setBluePixels(int[] pixels, Color color) { + pixels[2] = pixels[2] > 0 && pixels[2] < 255 ? color.getBlue() : 255; + } + + /** + * ImageIcon转换为BufferImage + * + * @param icon imageIcon + * @return BufferedImage + */ + public static BufferedImage imageIconToBufferedImage(ImageIcon icon) { + BufferedImage bi = new BufferedImage( + icon.getIconWidth(), + icon.getIconHeight(), + BufferedImage.TYPE_INT_ARGB); + Graphics g = bi.createGraphics(); + icon.paintIcon(null, g, 0, 0); + g.dispose(); + return bi; + } + +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/NormalButtonPreviewCell.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/NormalButtonPreviewCell.java new file mode 100644 index 0000000000..9a1adf7f3d --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/NormalButtonPreviewCell.java @@ -0,0 +1,55 @@ +package com.fr.widgettheme.theme.panel; + +import com.fr.widgettheme.theme.widget.style.ThemeTextStyle; +import com.fr.widgettheme.theme.widget.style.ThemedWidgetStyle; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.i18n.Toolkit; +import com.fr.general.FRFont; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.LayoutManager; + +/** + * 主题参数面板按钮预览格子 + * + * @author John.Ying + * @since 11.0 + * Created on 2023/3/27 + */ +public class NormalButtonPreviewCell extends ControlPreviewCell { + + /** + * 按钮上的label + */ + private UILabel uiLabel; + + public NormalButtonPreviewCell() { + this(DEFAULT, DEFAULT_MESSAGE); + } + + public NormalButtonPreviewCell(String value) { + this(DEFAULT, value); + } + + public NormalButtonPreviewCell(LayoutManager layoutManager, String value) { + this.setLayout(layoutManager); + this.value = value; + this.uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Theme_Control_Normal_Button")); + this.setPreferredSize(new Dimension(80, 27)); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + ThemedWidgetStyle widgetStyle = this.themePreviewTerminal.getThemeWidgetStyle(this.reportTheme); + paintBgColor(g, widgetStyle); + uiLabel.setBackground(widgetStyle.getThemeColor()); + ThemeTextStyle textStyle = widgetStyle.getTextStyle(); + uiLabel.setForeground(textStyle.getFontColor()); + FRFont font = FRFont.getInstance(textStyle.getName(), textStyle.getCompositeFontStyle(), textStyle.getFontSize(), textStyle.getFontColor()); + uiLabel.setFont(font); + this.add(uiLabel, BorderLayout.CENTER); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/RingControlPreviewCell.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/RingControlPreviewCell.java new file mode 100644 index 0000000000..6d492688d4 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/RingControlPreviewCell.java @@ -0,0 +1,51 @@ +package com.fr.widgettheme.theme.panel; + + +import com.fr.widgettheme.theme.widget.style.ThemedWidgetStyle; + +import java.awt.Dimension; +import java.awt.LayoutManager; +import java.awt.Graphics2D; +import java.awt.Graphics; +import java.awt.Color; + +/** + * 主题界面预览控件单元格子,单选按钮组被选中的样子 + * + * @author John.Ying + * @since 11.0 + * Created on 2023/3/18 + */ +public class RingControlPreviewCell extends ControlPreviewCell { + /** + * 圆环厚度 + */ + private static final int THICK_NESS = 4; + + public RingControlPreviewCell() { + this(DEFAULT, DEFAULT_MESSAGE); + } + + public RingControlPreviewCell(String value) { + this(DEFAULT, value); + } + + public RingControlPreviewCell(LayoutManager layoutManager, String value) { + this.setLayout(layoutManager); + this.setOpaque(false); + this.value = value; + this.setPreferredSize(new Dimension(20, 30)); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + ThemedWidgetStyle widgetStyle = (ThemedWidgetStyle) reportTheme.getWidgetStyle(); + Graphics2D g2d = (Graphics2D) g.create(); + g2d.setColor(widgetStyle.getThemeColor()); + g2d.fillOval(5, 9, 15, 15); + g2d.setColor(Color.WHITE); + g2d.fillOval(5 + THICK_NESS, 9 + THICK_NESS, 15 - 2 * THICK_NESS, 15 - 2 * THICK_NESS); + } + +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/RoundControlPreviewCell.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/RoundControlPreviewCell.java new file mode 100644 index 0000000000..4b527dd4f6 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/RoundControlPreviewCell.java @@ -0,0 +1,44 @@ +package com.fr.widgettheme.theme.panel; + + +import com.fr.widgettheme.theme.widget.style.ThemedWidgetStyle; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.LayoutManager; + +/** + * 主题界面预览控件单元格子,单选按钮组未被选中的样子 + * + * @author John.Ying + * @since 11.0 + * Created on 2023/3/18 + */ +public class RoundControlPreviewCell extends ControlPreviewCell { + public RoundControlPreviewCell() { + this(DEFAULT, DEFAULT_MESSAGE); + } + + public RoundControlPreviewCell(String value) { + this(DEFAULT, value); + } + + public RoundControlPreviewCell(LayoutManager layoutManager, String value) { + this.setLayout(layoutManager); + this.setOpaque(false); + this.value = value; + this.setPreferredSize(new Dimension(23, 30)); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + ThemedWidgetStyle widgetStyle = (ThemedWidgetStyle) reportTheme.getWidgetStyle(); + Color borderColor = widgetStyle.getBorderStyle().getBorderColor(); + Graphics2D g2d = (Graphics2D) g.create(); + g2d.setColor(borderColor); + g2d.drawOval(5, 9, 15, 15); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/TextPreviewCell.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/TextPreviewCell.java new file mode 100644 index 0000000000..6549159b34 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/TextPreviewCell.java @@ -0,0 +1,33 @@ +package com.fr.widgettheme.theme.panel; + +import com.fr.base.theme.TemplateTheme; +import com.fr.widgettheme.ThemePreviewTerminal; +import com.fr.widgettheme.theme.widget.style.ThemeTextStyle; + +import java.awt.LayoutManager; + +/** + * 文字预览格子 + * + * @author John.Ying + * @since 11.0 + * Created on 2023/3/27 + */ +public class TextPreviewCell extends ControlPreviewCell { + + public TextPreviewCell(String value) { + this(DEFAULT, value); + } + + public TextPreviewCell(LayoutManager layoutManager, String value) { + this.setLayout(layoutManager); + this.value = value; + } + + @Override + public void refresh(TemplateTheme reportTheme, ThemePreviewTerminal type) { + super.refresh(reportTheme, type); + ThemeTextStyle textStyle = type.getThemeWidgetStyle(reportTheme).getTextStyle(); + textColor = textStyle.getFontColor(); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetDisplayFormThemePreviewPane.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetDisplayFormThemePreviewPane.java new file mode 100644 index 0000000000..587e473a87 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetDisplayFormThemePreviewPane.java @@ -0,0 +1,208 @@ +package com.fr.widgettheme.theme.panel; + +import com.fr.base.background.ColorBackground; +import com.fr.base.theme.FormTheme; +import com.fr.chart.chartattr.ChartCollection; +import com.fr.chart.chartdata.NormalChartData; +import com.fr.chart.charttypes.ChartTypeManager; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.theme.TemplateThemePreviewPane; +import com.fr.design.mainframe.theme.preview.ChartComponentPreviewPane; +import com.fr.design.mainframe.theme.preview.UINoOpaquePanel; +import com.fr.general.Background; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.chart.PiePlot4VanChart; +import com.fr.plugin.chart.attr.VanChartLegend; +import com.fr.plugin.chart.base.VanChartTools; +import com.fr.plugin.chart.column.VanChartColumnPlot; +import com.fr.plugin.chart.type.GradientType; +import com.fr.plugin.chart.type.RadiusType; +import com.fr.plugin.chart.vanchart.VanChart; +import com.fr.stable.Constants; +import com.fr.stable.StringUtils; +import com.fr.widgettheme.ThemePreviewTerminal; + +import javax.swing.JPanel; +import java.awt.AlphaComposite; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; + +import static com.fr.design.i18n.Toolkit.i18nText; +import static com.fr.widgettheme.util.ThemePreviewPaneInitHelper.initColumnPlot; +import static com.fr.widgettheme.util.ThemePreviewPaneInitHelper.initVanChartYAxis; +import static com.fr.widgettheme.util.ThemePreviewPaneInitHelper.initVanChartsTools; + +/** + * 主题界面预览控frm界面,就是主jar里的那个界面,做了简单的修改 + * + * @author John.Ying + * @since 11.0 + * Created on 2023/3/18 + */ +public class WidgetDisplayFormThemePreviewPane extends TemplateThemePreviewPane { + private WidgetThemeECComponentPreviewPane elementCasePane; + private Background background; + private ChartComponentPreviewPane columnChartPreviewPane; + private ChartComponentPreviewPane pieChartPreviewPane; + private ControlPreviewPane controlPreviewPane; + private float alpha = 1.0F; + + public WidgetDisplayFormThemePreviewPane() { + setLayout(FRGUIPaneFactory.createBorderLayout()); + controlPreviewPane = new ControlPreviewPane(); + controlPreviewPane.setLayout(FRGUIPaneFactory.createLabelFlowLayout()); + controlPreviewPane.setPreferredSize(new Dimension(615, 40)); + controlPreviewPane.initControlPreviewPane(); + JPanel content = new UINoOpaquePanel(); + content.setLayout(new BorderLayout()); + add(controlPreviewPane, BorderLayout.NORTH); + JPanel chartContent = createChartContent(); + content.add(chartContent, BorderLayout.CENTER); + content.add(elementCasePane = new WidgetThemeECComponentPreviewPane(), BorderLayout.SOUTH); + add(content, BorderLayout.CENTER); + } + + private JPanel createChartContent() { + JPanel chartContent = new UINoOpaquePanel(); + chartContent.setLayout(new BorderLayout()); + JPanel columnChartPanel = new UINoOpaquePanel() { + public Dimension getPreferredSize() { + return new Dimension(379, 314); + } + }; + columnChartPanel.setLayout(new BorderLayout()); + columnChartPreviewPane = createChartPreviewPane(initColumnChart(), i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_Comp_Title1")); + columnChartPanel.add(columnChartPreviewPane, BorderLayout.CENTER); + + JPanel pieChartPanel = new UINoOpaquePanel() { + public Dimension getPreferredSize() { + return new Dimension(236, 314); + } + }; + pieChartPanel.setLayout(new BorderLayout()); + pieChartPreviewPane = createChartPreviewPane(initPieChart(), i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_Comp_Title2")); + pieChartPanel.add(pieChartPreviewPane, BorderLayout.CENTER); + chartContent.add(columnChartPanel, BorderLayout.CENTER); + chartContent.add(pieChartPanel, BorderLayout.EAST); + return chartContent; + } + + private ChartComponentPreviewPane createChartPreviewPane(ChartCollection chartCollection, String title) { + ChartComponentPreviewPane chartComponentPreviewPane = new ChartComponentPreviewPane(title); + chartComponentPreviewPane.getContentPane().populate(chartCollection); + chartComponentPreviewPane.getContentPane().setCallbackEvent(this); + return chartComponentPreviewPane; + } + + @Override + public void refresh(FormTheme theme) { + refresh(theme, ThemePreviewTerminal.PC); + } + + @Override + public void refresh(FormTheme theme, ThemePreviewTerminal themeStyleType) { + background = theme.getBodyStyle().getStyle().getBackground(); + alpha = theme.getBodyStyle().getStyle().getAlpha(); + elementCasePane.refresh(theme); + columnChartPreviewPane.refresh(theme); + pieChartPreviewPane.refresh(theme); + controlPreviewPane.refresh(theme, themeStyleType); + repaint(); + } + + + protected void paintBackground(Graphics2D g2d) { + if (background == null) { + background = ColorBackground.getInstance(Color.WHITE); + } + Composite oldComposite = g2d.getComposite(); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); + background.paint(g2d, new Rectangle2D.Double(0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT)); + g2d.setComposite(oldComposite); + } + + /** + * 初始化柱形图 + * + * @return 存放图表 + */ + private ChartCollection initColumnChart() { + try { + VanChart chart = (VanChart) ChartTypeManager.getInstance().getCharts(VanChartColumnPlot.VAN_CHART_COLUMN_PLOT_ID)[0].clone(); + initColumnChartDetail(chart); + Object[] category = { + Toolkit.i18nText("Fine-Design_Chart_Category") + "1", + Toolkit.i18nText("Fine-Design_Chart_Category") + "2", + Toolkit.i18nText("Fine-Design_Chart_Category") + "3", + Toolkit.i18nText("Fine-Design_Chart_Category") + "4" + }; + Object[] series = { + Toolkit.i18nText("Fine-Design_Chart_Series") + "1", + Toolkit.i18nText("Fine-Design_Chart_Series") + "2" + }; + Object[][] value = { + {"250", "540", "300", "410"}, + {"180", "190", "170", "100"}, + }; + NormalChartData normalChartData = new NormalChartData(category, series, value); + chart.setPreViewChartData(normalChartData); + ChartCollection chartCollection = new ChartCollection(chart); + return chartCollection; + } catch (Exception ex) { + FineLoggerFactory.getLogger().error(ex.getMessage(), ex); + } + return null; + } + + private void initColumnChartDetail(VanChart chart) { + chart.getTitle().setTitleVisible(false); + initVanChartsTools(chart.getVanChartTools()); + VanChartColumnPlot plot = chart.getPlot(); + //Form中独有的setPosition,和Report中不同,先单独放在这里,不写在initPlot中 + plot.getLegend().setPosition(Constants.TOP); + initColumnPlot(plot); + initVanChartYAxis(plot.getDefaultYAxis()); + } + + /** + * 初始化饼图 + * + * @return chartCollection + */ + private ChartCollection initPieChart() { + try { + VanChart chart = (VanChart) ChartTypeManager.getInstance().getCharts(PiePlot4VanChart.VAN_CHART_PIE_PLOT)[0].clone(); + chart.getTitle().setTitleVisible(false); + VanChartTools vanChartTools = chart.getVanChartTools(); + vanChartTools.setSort(false); + vanChartTools.setExport(false); + vanChartTools.setFullScreen(false); + + PiePlot4VanChart plot = chart.getPlot(); + VanChartLegend legend = (VanChartLegend) plot.getLegend(); + legend.setPosition(Constants.BOTTOM); + legend.setCustomSize(true); + legend.setMaxHeight(28); + plot.getGradientStyle().setGradientType(GradientType.NONE); + plot.setInnerRadiusPercent(75); + plot.getRadius().setRadiusType(RadiusType.FIXED); + plot.getRadius().setRadius(70); + + Object[] category = {StringUtils.EMPTY}; + Object[] series = {"A1", "B1", "C1", "D1", "E1", "F1", "G1", "H1"}; + Object[][] value = {{45}, {24}, {12}, {8}, {5}, {3}, {2}, {1},}; + NormalChartData normalChartData = new NormalChartData(category, series, value); + chart.setPreViewChartData(normalChartData); + ChartCollection chartCollection = new ChartCollection(chart); + return chartCollection; + } catch (Exception ex) { + FineLoggerFactory.getLogger().error(ex.getMessage(), ex); + } + return null; + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetDisplayReportThemePreviewPane.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetDisplayReportThemePreviewPane.java new file mode 100644 index 0000000000..a943cf4c4c --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetDisplayReportThemePreviewPane.java @@ -0,0 +1,125 @@ +package com.fr.widgettheme.theme.panel; + +import com.fr.base.background.ColorBackground; +import com.fr.base.theme.ReportTheme; +import com.fr.chart.chartattr.ChartCollection; +import com.fr.chart.chartdata.NormalChartData; +import com.fr.chart.charttypes.ChartTypeManager; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.theme.TemplateThemePreviewPane; +import com.fr.design.mainframe.theme.preview.ChartPreviewPane; +import com.fr.general.Background; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.chart.column.VanChartColumnPlot; +import com.fr.plugin.chart.vanchart.VanChart; +import com.fr.widgettheme.ThemePreviewTerminal; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; + +import static com.fr.widgettheme.util.ThemePreviewPaneInitHelper.initColumnPlot; +import static com.fr.widgettheme.util.ThemePreviewPaneInitHelper.initVanChartYAxis; +import static com.fr.widgettheme.util.ThemePreviewPaneInitHelper.initVanChartsTools; + +/** + * 主题界面预览控cpt界面,就是主jar里的那个界面,做了简单的修改 + * + * @author John.Ying + * @since 11.0 + * Created on 2023/3/18 + */ +public class WidgetDisplayReportThemePreviewPane extends TemplateThemePreviewPane { + private Background background; + + private final WidgetThemeECReportPreviewPane reportPreviewPane; + + private final ChartPreviewPane chartPreviewPane; + + private final ControlPreviewPane controlPreviewPane; + + public WidgetDisplayReportThemePreviewPane() { + setLayout(FRGUIPaneFactory.createBorderLayout()); + chartPreviewPane = new ChartPreviewPane(); + chartPreviewPane.setPreferredSize(new Dimension(615, 207)); + chartPreviewPane.populate(initColumnChart()); + chartPreviewPane.setCallbackEvent(this); + reportPreviewPane = new WidgetThemeECReportPreviewPane(); + reportPreviewPane.setPreferredSize(new Dimension(615, 257)); + controlPreviewPane = new ControlPreviewPane(); + controlPreviewPane.setLayout(FRGUIPaneFactory.createLabelFlowLayout()); + controlPreviewPane.setPreferredSize(new Dimension(615, 40)); + controlPreviewPane.initControlPreviewPane(); + this.add(reportPreviewPane, BorderLayout.CENTER); + this.add(chartPreviewPane, BorderLayout.SOUTH); + this.add(controlPreviewPane, BorderLayout.NORTH); + } + + @Override + public void refresh(ReportTheme theme) { + refresh(theme, ThemePreviewTerminal.PC); + } + + @Override + public void refresh(ReportTheme theme, ThemePreviewTerminal terminal) { + background = theme.getBodyStyle().getBackground(); + reportPreviewPane.refresh(theme); + chartPreviewPane.refresh(theme); + controlPreviewPane.refresh(theme, terminal); + repaint(); + } + + + protected void paintBackground(Graphics2D g2d) { + if (background == null) { + background = ColorBackground.getInstance(Color.WHITE); + } + background.paint(g2d, new Rectangle2D.Double(0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT)); + } + + + /** + * 初始化柱形图 + * + * @return chartCollection + */ + private ChartCollection initColumnChart() { + try { + VanChart chart = (VanChart) ChartTypeManager.getInstance().getCharts(VanChartColumnPlot.VAN_CHART_COLUMN_PLOT_ID)[0].clone(); + initColumnChartDetail(chart); + Object[] category = { + Toolkit.i18nText("Fine-Design_Chart_Category") + "1", + Toolkit.i18nText("Fine-Design_Chart_Category") + "2", + Toolkit.i18nText("Fine-Design_Chart_Category") + "3", + Toolkit.i18nText("Fine-Design_Chart_Category") + "4" + }; + Object[] series = { + Toolkit.i18nText("Fine-Design_Chart_Series") + "1", + Toolkit.i18nText("Fine-Design_Chart_Series") + "2", + Toolkit.i18nText("Fine-Design_Chart_Series") + "3" + }; + Object[][] value = { + {"340", "510", "300", "250"}, + {"180", "360", "170", "100"}, + {"210", "205", "405", "190"} + }; + NormalChartData normalChartData = new NormalChartData(category, series, value); + chart.setPreViewChartData(normalChartData); + ChartCollection chartCollection = new ChartCollection(chart); + return chartCollection; + } catch (Exception ex) { + FineLoggerFactory.getLogger().error(ex.getMessage(), ex); + } + return null; + } + + private void initColumnChartDetail(VanChart chart) { + initVanChartsTools(chart.getVanChartTools()); + VanChartColumnPlot plot = chart.getPlot(); + initColumnPlot(plot); + initVanChartYAxis(plot.getDefaultYAxis()); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetThemeECComponentPreviewPane.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetThemeECComponentPreviewPane.java new file mode 100644 index 0000000000..a2a873ea38 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetThemeECComponentPreviewPane.java @@ -0,0 +1,35 @@ +package com.fr.widgettheme.theme.panel; + +import com.fr.base.theme.FormTheme; +import com.fr.design.mainframe.theme.preview.ComponentPreviewPane; + +import java.awt.Component; + +import static com.fr.design.i18n.Toolkit.i18nText; + +/** + * 决策报表主题界面的那个表格+标题部分 + * + * @author John.Ying + * @since 1.0 + * Created on 2021/3/18 + */ +public class WidgetThemeECComponentPreviewPane extends ComponentPreviewPane { + private WidgetThemeECPreviewPane contentPane; + + public WidgetThemeECComponentPreviewPane() { + super(i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_EC_Title")); + } + + @Override + protected Component createContentPane() { + contentPane = new WidgetThemeECPreviewPane(); + return contentPane; + } + + @Override + public void refresh(FormTheme theme) { + super.refresh(theme); + contentPane.refresh(theme); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetThemeECPreviewPane.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetThemeECPreviewPane.java new file mode 100644 index 0000000000..774ccf1c1e --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetThemeECPreviewPane.java @@ -0,0 +1,112 @@ +package com.fr.widgettheme.theme.panel; + +import com.fr.base.CellBorderSourceFlag; +import com.fr.base.theme.TemplateTheme; +import com.fr.base.theme.settings.ThemedCellStyleList; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.theme.preview.UINoOpaquePanel; +import com.fr.design.mainframe.theme.preview.ecpreview.AbstractECPreviewPane; +import com.fr.design.mainframe.theme.preview.ecpreview.cell.AbstractPreviewCell; +import com.fr.design.mainframe.theme.preview.ecpreview.cell.PreviewCell; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.util.ArrayList; +import java.util.List; + +/** + * 主题界面frm里的那个表格,做了简单修改,削减了几行重复内容,腾出控件参数面板的空间 + * + * @author John.Ying + * @since 11.0 + * Created on 2021/3/18 + */ +public class WidgetThemeECPreviewPane extends AbstractECPreviewPane { + private final List headerCellList = new ArrayList<>(); + private final List contentCellList = new ArrayList<>(); + private final List highLightCellList = new ArrayList<>(); + private final List assistCellList = new ArrayList<>(); + private static final int COL_COUNT = 5; + private static final int CONTENT_ROW_COUNT = 1; + + public WidgetThemeECPreviewPane() { + this.setPreferredSize(new Dimension(517, 158 - 36)); + this.setBorder(BorderFactory.createEmptyBorder(0, 1, 2, 1)); + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + JPanel titlePane = new UINoOpaquePanel(new GridLayout()); + JPanel extCenterPane = FRGUIPaneFactory.createBorderLayout_NO_Opaque_Pane(); + this.add(extCenterPane, BorderLayout.CENTER); + extCenterPane.add(titlePane, BorderLayout.NORTH); + for (int c = 0; c < COL_COUNT; c++) { + PreviewCell cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Header")); + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (c > 0) { + flag |= CellBorderSourceFlag.LEFT_BORDER_SOURCE_INNER; + } + if (c < COL_COUNT - 1) { + flag |= CellBorderSourceFlag.RIGHT_BORDER_SOURCE_INNER; + } + cell.setBorderSourceFlag(flag); + cell.setPreferredSize(new Dimension(103, 36)); + titlePane.add(cell); + headerCellList.add(cell); + } + JPanel contentPane = new UINoOpaquePanel(new GridLayout(1, 5, 0, 0)); + extCenterPane.add(contentPane, BorderLayout.CENTER); + for (int i = 0; i < COL_COUNT * CONTENT_ROW_COUNT; i++) { + PreviewCell cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Main_Text")); + int c = i % COL_COUNT; + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (c > 0) { + flag |= CellBorderSourceFlag.LEFT_BORDER_SOURCE_INNER; + } + if (c < COL_COUNT - 1) { + flag |= CellBorderSourceFlag.RIGHT_BORDER_SOURCE_INNER; + } + cell.setBorderSourceFlag(flag); + cell.setPreferredSize(new Dimension(103, 30)); + contentPane.add(cell); + contentCellList.add(cell); + } + + JPanel endPane = new UINoOpaquePanel(new GridLayout()); + extCenterPane.add(endPane, BorderLayout.SOUTH); + for (int c = 0; c < COL_COUNT; c++) { + PreviewCell cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Highlight_Text")); + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (c > 0) { + flag |= CellBorderSourceFlag.LEFT_BORDER_SOURCE_INNER; + } + if (c < COL_COUNT - 1) { + flag |= CellBorderSourceFlag.RIGHT_BORDER_SOURCE_INNER; + } + cell.setBorderSourceFlag(flag); + cell.setPreferredSize(new Dimension(103, 30)); + endPane.add(cell); + highLightCellList.add(cell); + } + + JPanel extSouthPane = FRGUIPaneFactory.createBorderLayout_NO_Opaque_Pane(); + PreviewCell assistCell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Assist_Text")); + assistCell.setBorderSourceFlag(CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER); + assistCell.setPreferredSize(new Dimension(123, 30)); + assistCellList.add(assistCell); + extSouthPane.add(assistCell); + this.add(extSouthPane, BorderLayout.SOUTH); + } + + @Override + public void refresh(TemplateTheme theme) { + ThemedCellStyleList cellStyleConfig = theme.getCellStyleList(); + refresh(headerCellList, cellStyleConfig.getUse4Header()); + refresh(contentCellList, cellStyleConfig.getUse4MainText()); + refresh(highLightCellList, cellStyleConfig.getUse4HighlightText()); + refresh(assistCellList, cellStyleConfig.getUse4SupportInfo()); + } + + +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetThemeECReportPreviewPane.java b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetThemeECReportPreviewPane.java new file mode 100644 index 0000000000..39cd48a566 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/theme/panel/WidgetThemeECReportPreviewPane.java @@ -0,0 +1,248 @@ +package com.fr.widgettheme.theme.panel; + +import com.fr.base.CellBorderSourceFlag; +import com.fr.base.theme.ReportTheme; +import com.fr.base.theme.TemplateTheme; +import com.fr.base.theme.settings.ThemedCellStyleList; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.mainframe.theme.preview.ThemePreviewed; +import com.fr.design.mainframe.theme.preview.UINoOpaquePanel; +import com.fr.design.mainframe.theme.preview.ecpreview.AbstractECPreviewPane; +import com.fr.design.mainframe.theme.preview.ecpreview.cell.AbstractPreviewCell; +import com.fr.design.mainframe.theme.preview.ecpreview.cell.CornerPreviewCell; +import com.fr.design.mainframe.theme.preview.ecpreview.cell.PreviewCell; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.awt.Point; +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.List; + +/** + * 主题界面report里的那个表格,做了简单修改,削减了几行重复内容,腾出控件参数面板的空间 + * + * @author John.Ying + * @since 1.0 + * Created on 2021/3/18 + */ +public class WidgetThemeECReportPreviewPane extends UINoOpaquePanel implements ThemePreviewed { + private final List headerTitleCellList = new ArrayList<>(); // 大标题样式单元格 + private final List headerCellList = new ArrayList<>(); // 表头样式单元格 + private final List titleCellList = new ArrayList<>(); // 小标题样式单元格 + private final List contentCellList = new ArrayList<>(); // 正文样式单元格 + private final List highLightCellList = new ArrayList<>(); // 高亮文本样式单元格 + private final List assistCellList = new ArrayList<>(); // 辅助信息样式单元格 + private static final int CONTENT_ROW_COUNT = 3; + private static final int COL_COUNT = 3; + + private final PreviewPane previewPane; + + public WidgetThemeECReportPreviewPane() { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + previewPane = new PreviewPane(); + this.add(previewPane, BorderLayout.CENTER); + } + + @Override + public void refresh(ReportTheme theme) { + previewPane.refresh(theme); + } + + + class PreviewPane extends AbstractECPreviewPane { + + + public PreviewPane() { + this.setPreferredSize(new Dimension(517, 208)); + this.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); + + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + JPanel northPane = createNorthPane(); + JPanel centerPane = createCenterPane(); + JPanel southPane = createSouthPane(); + this.add(northPane, BorderLayout.NORTH); + this.add(centerPane, BorderLayout.CENTER); + this.add(southPane, BorderLayout.SOUTH); + } + + private JPanel createNorthPane() { + JPanel northPane = FRGUIPaneFactory.createBorderLayout_NO_Opaque_Pane(); + AbstractPreviewCell bigTitleCell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_Cell_Style_Big_Title")); + bigTitleCell.setBorderSourceFlag(CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER); + bigTitleCell.setPreferredSize(new Dimension(615, 46)); + headerTitleCellList.add(bigTitleCell); + northPane.add(bigTitleCell, BorderLayout.NORTH); + CornerPreviewCell cornerCell = createCornerPreviewCell(); + titleCellList.add(cornerCell); + northPane.add(cornerCell, BorderLayout.WEST); + JPanel centerPane = FRGUIPaneFactory.createBorderLayout_NO_Opaque_Pane(); + northPane.add(centerPane, BorderLayout.CENTER); + PreviewCell cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Small_Title")); + cell.setBorderSourceFlag(CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER); + titleCellList.add(cell); + cell.setPreferredSize(new Dimension(308, 38)); + centerPane.add(cell, BorderLayout.NORTH); + JPanel eastSouthPane = new UINoOpaquePanel(new GridLayout()); + for (int c = 0; c < CONTENT_ROW_COUNT; c++) { + PreviewCell headerCell = createPreviewCellHeader(c); + headerCellList.add(headerCell); + eastSouthPane.add(headerCell); + } + centerPane.add(eastSouthPane, BorderLayout.CENTER); + return northPane; + } + + /** + * 创建CornerPreviewCell + */ + private CornerPreviewCell createCornerPreviewCell() { + CornerPreviewCell cornerCell = new CornerPreviewCell(new String[]{Toolkit.i18nText("Fine-Design_Basic_Column_Name"), + Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_EC_Data"), Toolkit.i18nText("Fine-Design_Basic_Template_Theme_Profile_Pane_Row_Name")}, + new Point2D[]{new Point(159, 71), new Point(225, 49)}); + cornerCell.setBorderSourceFlag(CellBorderSourceFlag.INVALID_BORDER_SOURCE); + cornerCell.setPreferredSize(new Dimension(225, 71)); + return cornerCell; + } + + /** + * 创建预览单元格标题 + * + * @param c 文本行数 + * @return PreviewCell + */ + private PreviewCell createPreviewCellHeader(int c) { + PreviewCell headerCell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Header")); + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (c > 0) { + flag |= CellBorderSourceFlag.LEFT_BORDER_SOURCE_INNER; + } + if (c < CONTENT_ROW_COUNT - 1) { + flag |= CellBorderSourceFlag.RIGHT_BORDER_SOURCE_INNER; + } + headerCell.setBorderSourceFlag(flag); + return headerCell; + } + + private JPanel createCenterPane() { + JPanel centerPane = FRGUIPaneFactory.createBorderLayout_NO_Opaque_Pane(); + JPanel westPane = FRGUIPaneFactory.createBorderLayout_NO_Opaque_Pane(); + centerPane.add(westPane, BorderLayout.WEST); + PreviewCell cell1 = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Small_Title")); + titleCellList.add(cell1); + cell1.setPreferredSize(new Dimension(112, 93)); + westPane.add(cell1, BorderLayout.WEST); + JPanel gridPane = createGridPane(); + + westPane.add(gridPane, BorderLayout.CENTER); + JPanel innerCenterPane = new UINoOpaquePanel(new GridLayout(3, 3)); + centerPane.add(innerCenterPane, BorderLayout.CENTER); + for (int i = 0; i < COL_COUNT*CONTENT_ROW_COUNT; i++) { + PreviewCell cell ; + int r = i / CONTENT_ROW_COUNT; + int c = i % CONTENT_ROW_COUNT; + if (c == CONTENT_ROW_COUNT - 1) { + cell = createPreviewCellHighlight(r); + highLightCellList.add(cell); + } else { + cell = createPreviewCellMain(r, c); + contentCellList.add(cell); + } + cell.setPreferredSize(new Dimension(123, 31)); + innerCenterPane.add(cell); + } + return centerPane; + } + + /** + * 创建高亮预览单元格 + * + * @param r 计算标志位 + * @return 单元格 + */ + private PreviewCell createPreviewCellHighlight(int r) { + PreviewCell cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Highlight_Text")); + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (r != 0) { + flag |= CellBorderSourceFlag.TOP_BORDER_SOURCE_INNER; + } + if (r != COL_COUNT - 1) { + flag |= CellBorderSourceFlag.BOTTOM_BORDER_SOURCE_INNER; + } + cell.setBorderSourceFlag(flag); + return cell; + } + + /** + * 创建正文预览单元格 + * + * @param r 计算标志位 + * @param c 计算标志位 + * @return 单元格 + */ + private PreviewCell createPreviewCellMain(int r, int c) { + PreviewCell cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Main_Text")); + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (r > 0) { + flag |= CellBorderSourceFlag.TOP_BORDER_SOURCE_INNER; + } + if (r < COL_COUNT - 1) { + flag |= CellBorderSourceFlag.BOTTOM_BORDER_SOURCE_INNER; + } + if (c > 0) { + flag |= CellBorderSourceFlag.LEFT_BORDER_SOURCE_INNER; + } + if (c < 1) { + flag |= CellBorderSourceFlag.RIGHT_BORDER_SOURCE_INNER; + } + cell.setBorderSourceFlag(flag); + return cell; + } + + private JPanel createGridPane() { + int rowCount = 3; + int columnCount = 1; + JPanel gridPane = new UINoOpaquePanel(new GridLayout(rowCount, columnCount)); + for (int r = 0; r < rowCount; r++) { + PreviewCell cell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Header")); + int flag = CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER; + if (r > 0) { + flag |= CellBorderSourceFlag.TOP_BORDER_SOURCE_INNER; + } + if (r < COL_COUNT - 1) { + flag |= CellBorderSourceFlag.BOTTOM_BORDER_SOURCE_INNER; + } + cell.setBorderSourceFlag(flag); + cell.setPreferredSize(new Dimension(113, 31)); + headerCellList.add(cell); + gridPane.add(cell); + } + return gridPane; + } + + private JPanel createSouthPane(){ + JPanel southPane = FRGUIPaneFactory.createBorderLayout_NO_Opaque_Pane(); + PreviewCell assistCell = new PreviewCell(Toolkit.i18nText("Fine-Design_Basic_Predefined_Style_Assist_Text")); + assistCell.setBorderSourceFlag(CellBorderSourceFlag.ALL_BORDER_SOURCE_OUTER); + assistCell.setPreferredSize(new Dimension(123, 30)); + assistCellList.add(assistCell); + southPane.add(assistCell, BorderLayout.CENTER); + return southPane; + } + + @Override + public void refresh(TemplateTheme theme) { + ThemedCellStyleList cellStyleConfig = theme.getCellStyleList(); + refresh(headerTitleCellList, cellStyleConfig.getUse4BigTitle()); + refresh(headerCellList, cellStyleConfig.getUse4Header()); + refresh(contentCellList, cellStyleConfig.getUse4MainText()); + refresh(titleCellList, cellStyleConfig.getUse4SmallTitle()); + refresh(highLightCellList, cellStyleConfig.getUse4HighlightText()); + refresh(assistCellList, cellStyleConfig.getUse4SupportInfo()); + } + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/widgettheme/util/ThemePreviewPaneInitHelper.java b/designer-base/src/main/java/com/fr/widgettheme/util/ThemePreviewPaneInitHelper.java new file mode 100644 index 0000000000..c7adedbbc7 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/util/ThemePreviewPaneInitHelper.java @@ -0,0 +1,70 @@ +package com.fr.widgettheme.util; + +import com.fr.base.BaseFormula; +import com.fr.chart.chartattr.Title; +import com.fr.design.i18n.Toolkit; +import com.fr.plugin.chart.attr.axis.VanChartAxis; +import com.fr.plugin.chart.base.AttrLabel; +import com.fr.plugin.chart.base.VanChartTools; +import com.fr.plugin.chart.column.VanChartColumnPlot; +import com.fr.plugin.chart.type.GradientType; + +/** + * 辅助report和form的控件显示主题预览窗口做初始化工作 + * 没有其他的用途,不要用在其他的地方,只是抽一些方法出来,降低复杂度 + * + * @author obo + * @since 11.0 + * Created on 2023/11/14 + */ +public class ThemePreviewPaneInitHelper { + private ThemePreviewPaneInitHelper() { + } + + /** + * 初始化图表工具 + * + * @param vanChartTools 图表工具 + */ + public static void initVanChartsTools(VanChartTools vanChartTools) { + vanChartTools.setSort(false); + vanChartTools.setExport(false); + vanChartTools.setFullScreen(false); + } + + /** + * 初始化柱形图绘图区 + * + * @param plot 绘图区 + */ + public static void initColumnPlot(VanChartColumnPlot plot) { + AttrLabel defaultAttrLabel = plot.getDefaultAttrLabel(); + defaultAttrLabel.setEnable(true); + defaultAttrLabel.getAttrLabelDetail().getBorder().setBorderStyle(0); + defaultAttrLabel.getAttrLabelDetail().getBackground().setBackground(null); + plot.getConditionCollection().getDefaultAttr().addDataSeriesCondition(defaultAttrLabel); + plot.getGradientStyle().setGradientType(GradientType.NONE); + plot.setSeriesOverlapPercent(30); + plot.setCategoryIntervalPercent(30); + } + + /** + * 初始化图表Y轴 + * + * @param yAxis 轴 + */ + public static void initVanChartYAxis(VanChartAxis yAxis) { + Title title = new Title(); + title.setTextObject(Toolkit.i18nText("Fine-Design_Chart_Axis_Title")); + title.getTextAttr().setRotation(-90); + title.getTextAttr().setThemed(true); + yAxis.setTitle(title); + yAxis.setShowAxisTitle(true); + yAxis.setCustomMaxValue(true); + yAxis.setCustomMinValue(true); + yAxis.setCustomMainUnit(true); + yAxis.setMaxValue(BaseFormula.createFormulaBuilder().build("=600")); + yAxis.setMinValue(BaseFormula.createFormulaBuilder().build("=0")); + yAxis.setMainUnit(BaseFormula.createFormulaBuilder().build("=200")); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/util/WidgetStyleComponentCombiner.java b/designer-base/src/main/java/com/fr/widgettheme/util/WidgetStyleComponentCombiner.java new file mode 100644 index 0000000000..6fd2757c9a --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/util/WidgetStyleComponentCombiner.java @@ -0,0 +1,131 @@ +package com.fr.widgettheme.util; + +import com.fr.design.designer.IntervalConstants; +import com.fr.design.gui.frpane.FontSizeComboPane; +import com.fr.design.gui.frpane.UIPercentDragPane; +import com.fr.design.gui.ibutton.UIColorButton; +import com.fr.design.gui.ibutton.UIToggleButton; +import com.fr.design.gui.icombobox.LineComboBox; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.style.color.NewColorSelectBox; +import com.fr.design.widget.FRWidgetFactory; + +import javax.swing.JPanel; +import java.awt.Component; + +/** + * 创建控件样式组合配置面板的工具类 + * + * @author obo + * @since 11.0 + * Created on 2023/12/21 + */ +public class WidgetStyleComponentCombiner { + + private static final double F = TableLayout.FILL; + private static final double P = TableLayout.PREFERRED; + + + private WidgetStyleComponentCombiner() { + } + + /** + * 组合主题文本样式配置面板 + * 包含字体大小下拉框和字体颜色按钮 + * + * @param fontSizePane 字体大小配置 + * @param fontColorButton 字体颜色配置 + * @param bold 粗体 + * @param italic 斜体 + * @return 文本样式面板 + */ + public static JPanel combineTextStyleComponent(FontSizeComboPane fontSizePane, UIColorButton fontColorButton, UIToggleButton bold, UIToggleButton italic) { + Component[][] components = {{fontSizePane, fontColorButton, bold, italic}}; + double[] rowSize = {P}; + double[] columnSize = {F, P, P, P}; + int[][] rowCount = {{1, 1, 1, 1}}; + return TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, 5, 5); + } + + /** + * 组合主题文本样式配置面板 + * 包含字体大小下拉框和字体颜色按钮 + * + * @param fontNameSelectBox 字体名配置 + * @param fontSizePane 字体大小配置 + * @param fontColorButton 字体颜色配置 + * @param bold 粗体 + * @param italic 斜体 + * @return 文本样式面板 + */ + public static JPanel combineTextStyleComponent(UIComboBox fontNameSelectBox, FontSizeComboPane fontSizePane, UIColorButton fontColorButton, UIToggleButton bold, UIToggleButton italic) { + Component[][] components = { + {fontNameSelectBox, null, null, null}, + {fontSizePane, fontColorButton, bold, italic} + }; + double[] rowSize = {P, P}; + double[] columnSize = {F, P, P, P}; + int[][] rowCount = { + {1, 1, 1, 1}, + {1, 1, 1, 1} + }; + return TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, 5, 5); + } + + /** + * 组合控件背景配置面板 + * + * @param colorSelectBox 颜色下拉框 + * @param alphaDragPane 透明度 + * @param columnWidth 列宽 + * @return 文本样式面板 + */ + public static JPanel combineWidgetBackgroundComponent(NewColorSelectBox colorSelectBox, + UIPercentDragPane alphaDragPane, + double columnWidth) { + Component[][] components = { + {colorSelectBox}, + {FRWidgetFactory.createLineWrapLabel(Toolkit.i18nText("Fine-Design_Form_Widget-Style_Alpha"))}, + {alphaDragPane} + }; + double[] rowSize = {P, P, P}; + double[] columnSize = {columnWidth}; + int[][] rowCount = {{1}, {1}, {1}}; + return TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, IntervalConstants.INTERVAL_L1, IntervalConstants.INTERVAL_L1); + } + + /** + * 组合控件边框配置面板 + * + * @param lineComboBox 字体大小配置 + * @param lineComboColorSelectBox 字体颜色配置 + * @return 文本样式面板 + */ + public static JPanel combineWidgetBorderComponent(LineComboBox lineComboBox, NewColorSelectBox lineComboColorSelectBox) { + return combineWidgetBorderComponent(lineComboBox, lineComboColorSelectBox, P); + } + + /** + * 组合控件边框配置面板 + * + * @param lineComboBox 字体大小配置 + * @param lineComboColorSelectBox 字体颜色配置 + * @param columnWidth 指定的列宽 + * @return 文本样式面板 + */ + public static JPanel combineWidgetBorderComponent(LineComboBox lineComboBox, + NewColorSelectBox lineComboColorSelectBox, + double columnWidth) { + Component[][] components = { + {lineComboBox}, + {lineComboColorSelectBox} + }; + double[] rowSize = {P, P}; + double[] columnSize = {columnWidth}; + int[][] rowCount = {{1}, {1}}; + return TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, IntervalConstants.INTERVAL_L1, IntervalConstants.INTERVAL_L1); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/util/WidgetThemeDesignerUtils.java b/designer-base/src/main/java/com/fr/widgettheme/util/WidgetThemeDesignerUtils.java new file mode 100644 index 0000000000..452fb945b0 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/util/WidgetThemeDesignerUtils.java @@ -0,0 +1,80 @@ +package com.fr.widgettheme.util; + +import com.fr.base.io.AttrMark; +import com.fr.base.io.IOFile; +import com.fr.base.theme.TemplateTheme; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.mainframe.JTemplate; +import com.fr.stable.StringUtils; +import com.fr.widgettheme.control.attr.WidgetDisplayEnhanceMarkAttr; +import com.fr.widgettheme.theme.widget.theme.WidgetThemeDisplayConstants; +import org.jetbrains.annotations.NotNull; + +import javax.swing.SwingConstants; +import java.awt.Color; + +/** + * 控件主题设计器部分工具类 + * + * @author obo + * @since 11.0 + * Created on 2023/11/13 + */ +public class WidgetThemeDesignerUtils { + + private WidgetThemeDesignerUtils() { + } + + /** + * 从 WorkBook 中加载 WatermarkAttr 属性对象 + * + * @param template AttrMark 对象,包括 WorkBook + * @return StrongestControlMarkAttr 对象 + */ + public static WidgetDisplayEnhanceMarkAttr getStrongestControlAttrFromTemplate(AttrMark template) { + return template.getAttrMark(WidgetDisplayEnhanceMarkAttr.XML_TAG); + } + + /** + * 判断是否启用了控件显示增强 + * + * @return 开启与否 + */ + public static boolean enableWidgetEnhance() { + JTemplate jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (JTemplate.isValid(jTemplate)) { + IOFile ioFile = (IOFile) jTemplate.getTarget(); + WidgetDisplayEnhanceMarkAttr mark = ioFile.getAttrMark(WidgetDisplayEnhanceMarkAttr.XML_TAG); + return mark != null && mark.isWidgetEnhance(); + } + return false; + } + /** + * 返回当前编辑模版的主题深浅 + */ + public static boolean isCurrentTemplateThemeDark() { + JTemplate jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + if (JTemplate.isValid(jTemplate)) { + TemplateTheme theme = jTemplate.getTemplateTheme(); + if (theme != null) { + return theme.isDark(); + } + return false; + } + throw new IllegalArgumentException("The current template is not valid"); + } + + /** + * 创建垂直方向顶部对齐的label + */ + @NotNull + public static UILabel createTopAlignmentLabel(String labelName) { + if(StringUtils.isEmpty(labelName)) { + return new UILabel(""); + } + UILabel label = new UILabel(labelName); + label.setVerticalAlignment(SwingConstants.TOP); + return label; + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/DisplayEnhanceMobileStyleDefinePane.java b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/DisplayEnhanceMobileStyleDefinePane.java new file mode 100644 index 0000000000..035fb32e5b --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/DisplayEnhanceMobileStyleDefinePane.java @@ -0,0 +1,341 @@ +package com.fr.widgettheme.widget.mobile.pane; + +import com.fr.base.background.ColorBackground; +import com.fr.design.gui.frpane.UIPercentDragPane; +import com.fr.util.ColorUtils; +import com.fr.widgettheme.theme.widget.style.MobileThemedWidgetStyle; +import com.fr.widgettheme.theme.widget.mobile.style.WidgetThemeMobileCommonExtraStyle; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.constants.LayoutConstants; +import com.fr.design.designer.IntervalConstants; +import com.fr.design.file.HistoryTemplateListCache; +import com.fr.design.gui.icombobox.LineComboBox; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.ispinner.UISpinner; +import com.fr.design.i18n.Toolkit; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.mainframe.JTemplate; +import com.fr.design.mainframe.mobile.ui.MobileStyleCustomDefinePane; +import com.fr.design.style.color.NewColorSelectBox; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.form.ui.Widget; +import com.fr.form.ui.mobile.MobileCommonExtraStyle; +import com.fr.form.ui.mobile.MobileStyle; +import com.fr.general.FRFont; +import com.fr.invoke.Reflect; +import com.fr.widgettheme.theme.widget.theme.WidgetThemeDisplayConstants; +import com.fr.stable.Constants; +import com.fr.stable.StringUtils; +import com.fr.widgettheme.util.WidgetStyleComponentCombiner; +import com.fr.widgettheme.util.WidgetThemeDesignerUtils; + +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.border.EmptyBorder; +import javax.swing.border.TitledBorder; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +/** + *

    开启控件显示增强后替换原通用属性面板 + *

    参考{@link com.fr.design.mainframe.mobile.ui.MobileStyleDefinePane} + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/4/11 + */ +public class DisplayEnhanceMobileStyleDefinePane extends BasicBeanPane { + public static final int NORMAL_COMBO_WIDTH = 152; + protected Widget widget; + protected MobileStyleCustomDefinePane customBeanPane; + protected Class mobileStyleClazz; + protected UIComboBox customCombo; + protected JPanel settingPane; + protected NewColorSelectBox themeColorSelectBox; + protected Color titleColor = new Color(47, 142, 241); + protected JPanel commonPane; + protected LineComboBox borderType; + protected NewColorSelectBox borderColorSelectBox; + protected UISpinner borderRadius; + protected MobileStyleFontConfigPane fontConfigPane; + protected NewColorSelectBox widgetBackgroundSelectBox; + protected UIPercentDragPane widgetBgAlphaDragPane; + protected NewColorSelectBox iconColorSelectBox; + + + protected MobileStyle mobileStyle; + + public DisplayEnhanceMobileStyleDefinePane(Widget widget, Class customBeanPaneClass, + Class mobileStyleClazz) { + this.widget = widget; + this.customBeanPane = Reflect.on(customBeanPaneClass).create(widget).get(); + this.mobileStyleClazz = mobileStyleClazz; + // 一些默认的情况,没有,需要初始化一下。 + initMobileStyle(widget); + init(); + } + + private void initMobileStyle(Widget widget) { + mobileStyle = widget.getMobileStyle() != null ? widget.getMobileStyle() : Reflect.on(mobileStyleClazz).create().get(); + } + + @Override + public void populateBean(MobileStyle ob) { + MobileCommonExtraStyle extraStyle = ob.getMobileCommonExtraStyle(); + if (extraStyle instanceof WidgetThemeMobileCommonExtraStyle) { + WidgetThemeMobileCommonExtraStyle style = (WidgetThemeMobileCommonExtraStyle) extraStyle; + customCombo.setSelectedIndex(style.isCustom() ? 1 : 0); + borderType.setSelectedLineStyle(style.getBorderType()); + borderRadius.setValue(style.getBorderRadius()); + if (style.getThemeColor() != null) { + themeColorSelectBox.setSelectObject(style.getThemeColor()); + } + if (style.getNewFont() != null) { + fontConfigPane.populateBean(style.getNewFont()); + } + if (style.getWidgetBackground() != null) { + Color color = ((ColorBackground) style.getWidgetBackground()).getColor(); + widgetBackgroundSelectBox.setSelectObject(ColorUtils.ignoreColorAlpha(color)); + widgetBgAlphaDragPane.populateBean(ColorUtils.roundColorAlphaDouble(color)); + } + if (style.getBorderColor() != null) { + borderColorSelectBox.setSelectObject(style.getBorderColor()); + } + if (style.getIconColor() != null) { + iconColorSelectBox.setSelectObject(style.getIconColor()); + } + } + this.customBeanPane.populateBean(ob); + } + + @Override + public MobileStyle updateBean() { + mobileStyle = Reflect.on(mobileStyleClazz).create().get(); + WidgetThemeMobileCommonExtraStyle extraStyle = new WidgetThemeMobileCommonExtraStyle(); + extraStyle.setCustom(customCombo.getSelectedIndex() == 1); + setThemeColor(extraStyle); + setIconColor(extraStyle); + setBorderType(extraStyle); + setBorderRadius(extraStyle); + setBorderColor(extraStyle); + setFontConfig(extraStyle); + setWidgetBackground(extraStyle); + mobileStyle.setMobileCommonExtraStyle(extraStyle); + this.widget.setMobileStyle(mobileStyle); + this.customBeanPane.updateBean(); + return mobileStyle; + } + + @Override + protected String title4PopupWindow() { + return StringUtils.EMPTY; + } + + private void init() { + this.setLayout(FRGUIPaneFactory.createBorderLayout()); + createGeneralPane(); + createCustomPane(); + } + + protected void createFontPane() { + Color fontColor = ColorUtils.hexToColor(WidgetThemeDesignerUtils.isCurrentTemplateThemeDark() ? WidgetThemeDisplayConstants.COLOR_CCFFFFFF_HEX : WidgetThemeDisplayConstants.COLOR_CC000000_HEX); + fontConfigPane = new MobileStyleFontConfigPane(fontColor); + settingPane.add(createLeftRightComponentsPane(createConfigLabel(Toolkit.i18nText("Fine-Design_Mobile_Widget_Font")), fontConfigPane)); + } + + private void createGeneralPane() { + createPreviewPane(); + createCommonPane(); + } + + private void createPreviewPane() { + JPanel mobileStylePreviewPane = Reflect.on(customBeanPane).call("createPreviewPane").get(); + if (mobileStylePreviewPane != null) { + JPanel previewPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + TitledBorder titledBorder = createTitledBorder(Toolkit.i18nText("Fine-Design_Basic_Widget_Style_Preview")); + previewPane.setBorder(titledBorder); + previewPane.setPreferredSize(new Dimension(500, 83)); + previewPane.add(mobileStylePreviewPane, BorderLayout.CENTER); + this.add(previewPane, BorderLayout.NORTH); + } + } + + private void createCommonPane() { + TitledBorder titledBorder = createTitledBorder(Toolkit.i18nText("Fine-Design_Mobile_Common_Attribute")); + commonPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 10); + commonPane.setBorder(titledBorder); + this.add(commonPane, BorderLayout.NORTH); + + + customCombo = new UIComboBox(new String[]{Toolkit.i18nText("Fine-Design_Mobile_Default"), Toolkit.i18nText("Fine-Design_Mobile_Custom")}); + customCombo.setSelectedIndex(0); + customCombo.setPreferredSize(new Dimension(NORMAL_COMBO_WIDTH + 15, 20)); + customCombo.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + boolean custom = customCombo.getSelectedIndex() == 1; + settingPane.setVisible(custom); + } + }); + commonPane.add(createLeftRightComponentsPane(createConfigLabel(Toolkit.i18nText("Fine-Design_Mobile_Attribute_Settings")), customCombo)); + + settingPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 10); + settingPane.setBorder(new EmptyBorder(-10, 0, 0, 0)); + settingPane.setVisible(false); + commonPane.add(settingPane); + createUniversalPane(); + } + + protected void createUniversalPane() { + // 主题色 + createThemePane(); + // 组件背景 + createBackgroundPane(); + // 边框线型 + createBorderLinePane(); + // 圆角边框 + createBorderRadiusPane(); + // 字体 + createFontPane(); + } + + + protected void createBackgroundPane() { + widgetBackgroundSelectBox = new NewColorSelectBox(NORMAL_COMBO_WIDTH); + widgetBgAlphaDragPane = new UIPercentDragPane(); + JPanel widgetBackgroundComponent = WidgetStyleComponentCombiner.combineWidgetBackgroundComponent(widgetBackgroundSelectBox, widgetBgAlphaDragPane, WidgetThemeDisplayConstants.THEME_MOBILE_WIDGET_BACKGROUND_WIDTH); + initBackgroundColor(); + settingPane.add(createLeftRightComponentsPane(createConfigLabel(Toolkit.i18nText("Fine-Design_Mobile_Widget_Background")), widgetBackgroundComponent)); + } + + protected void initBackgroundColor() { + Color widgetBackgroundColor = ColorUtils.hexToColor(WidgetThemeDesignerUtils.isCurrentTemplateThemeDark() ? WidgetThemeDisplayConstants.COLOR_000000_HEX : WidgetThemeDisplayConstants.COLOR_FFFFFF_HEX); + widgetBackgroundSelectBox.setSelectObject(widgetBackgroundColor); + widgetBgAlphaDragPane.populateBean(0); + } + + protected void createThemePane() { + themeColorSelectBox = new NewColorSelectBox(NORMAL_COMBO_WIDTH); + // 默认为当前模板选中的主题色 + themeColorSelectBox.setSelectObject(getCurrentTemplateThemeColor()); + settingPane.add(createLeftRightComponentsPane(createConfigLabel(Toolkit.i18nText("Fine-Design_Basic_Theme_Color")), themeColorSelectBox)); + } + + + protected void createBorderLinePane() { + borderType = new LineComboBox(WidgetThemeDisplayConstants.MOBILE_BORDER_LINE_STYLE_ARRAY); + borderColorSelectBox = new NewColorSelectBox(NORMAL_COMBO_WIDTH); + JPanel borderComponent = WidgetStyleComponentCombiner.combineWidgetBorderComponent(borderType, borderColorSelectBox); + initDefaultBorder(); + borderType.setPreferredSize(new Dimension(NORMAL_COMBO_WIDTH + 15, 20)); + // 边框线型 + settingPane.add(createLeftRightComponentsPane(createConfigLabel(Toolkit.i18nText("Fine-Design_Mobile_Widget_BorderType")), borderComponent)); + } + + protected void initDefaultBorder() { + borderType.setSelectedLineStyle(Constants.LINE_THIN); + borderColorSelectBox.setSelectObject(ColorUtils.hexToColor(WidgetThemeDesignerUtils.isCurrentTemplateThemeDark() ? WidgetThemeDisplayConstants.COLOR_26FFFFFF_HEX : WidgetThemeDisplayConstants.COLOR_26000000_HEX)); + } + + protected void createBorderRadiusPane() { + borderRadius = new UISpinner(0, Integer.MAX_VALUE, 1, 2); + borderRadius.setPreferredSize(new Dimension(NORMAL_COMBO_WIDTH + 20, 20)); + // 圆角边框 + settingPane.add(createLeftRightComponentsPane(createConfigLabel(Toolkit.i18nText("Fine-Design_Mobile_Widget_BorderRadius")), borderRadius)); + } + + protected void createCustomPane() { + JPanel configPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); + TitledBorder titledBorder = createTitledBorder(Toolkit.i18nText("Fine-Design_Report_Set")); + configPane.setBorder(titledBorder); + + configPane.add(this.customBeanPane, BorderLayout.CENTER); + + this.add(configPane, BorderLayout.CENTER); + } + + protected TitledBorder createTitledBorder(String title) { + TitledBorder titledBorder = GUICoreUtils.createTitledBorder(title, titleColor); + titledBorder.setTitleFont(FRFont.getInstance("PingFangSC-Regular", Font.PLAIN, 12)); + return titledBorder; + } + + protected UILabel createConfigLabel(String title) { + UILabel label = new UILabel(title, UILabel.LEFT); + label.setVerticalAlignment(SwingConstants.TOP); + label.setPreferredSize(new Dimension(75, 20)); + label.setBorder(new EmptyBorder(0, 15, 0, 0)); + return label; + } + + protected JPanel createLeftRightComponentsPane(Component... components) { + JPanel tableLayoutPane = TableLayoutHelper.createGapTableLayoutPane(new Component[][]{components}, TableLayoutHelper.FILL_LASTCOLUMN, IntervalConstants.INTERVAL_L1, LayoutConstants.VGAP_MEDIUM); + return tableLayoutPane; + } + + /** + * 获取当前编辑移动端控件样式主题色 + * + * @return + */ + protected Color getCurrentTemplateThemeColor() { + JTemplate jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); + Color themeColor = WidgetThemeDisplayConstants.DEFAULT_THEME_COLOR; + if (JTemplate.isValid(jTemplate)) { + MobileThemedWidgetStyle mobileWidgetStyle = (MobileThemedWidgetStyle) jTemplate.getTemplateTheme().getMobileWidgetStyle(); + mobileWidgetStyle = mobileWidgetStyle == null ? new MobileThemedWidgetStyle() : mobileWidgetStyle; + themeColor = mobileWidgetStyle.getThemeColor(); + } + return themeColor; + } + + protected void createIconColorSelectBox() { + iconColorSelectBox = new NewColorSelectBox(NORMAL_COMBO_WIDTH); + iconColorSelectBox.setSelectObject(getCurrentTemplateThemeColor()); + settingPane.add(createLeftRightComponentsPane(createConfigLabel(Toolkit.i18nText("Fine-Design_Widget_Theme_Icon_Color")), iconColorSelectBox)); + } + protected void setThemeColor(WidgetThemeMobileCommonExtraStyle extraStyle) { + if(themeColorSelectBox != null) { + extraStyle.setThemeColor(themeColorSelectBox.getSelectObject()); + } + } + protected void setIconColor(WidgetThemeMobileCommonExtraStyle extraStyle) { + if(iconColorSelectBox != null) { + extraStyle.setIconColor(iconColorSelectBox.getSelectObject()); + } + } + protected void setBorderType(WidgetThemeMobileCommonExtraStyle extraStyle) { + if(borderType != null) { + extraStyle.setBorderType(borderType.getSelectedLineStyle()); + } + } + protected void setBorderRadius(WidgetThemeMobileCommonExtraStyle extraStyle) { + if(borderRadius != null) { + extraStyle.setBorderRadius(borderRadius.getValue()); + } + } + protected void setBorderColor(WidgetThemeMobileCommonExtraStyle extraStyle) { + if(borderColorSelectBox != null) { + extraStyle.setBorderColor(borderColorSelectBox.getSelectObject()); + } + } + protected void setFontConfig(WidgetThemeMobileCommonExtraStyle extraStyle) { + + if(fontConfigPane != null) { + extraStyle.setNewFont(fontConfigPane.updateBean()); + } + } + protected void setWidgetBackground(WidgetThemeMobileCommonExtraStyle extraStyle) { + if(widgetBackgroundSelectBox != null && widgetBgAlphaDragPane != null) { + extraStyle.setWidgetBackground(ColorUtils.createColorBackgroundWithAlpha(widgetBackgroundSelectBox.getSelectObject(), widgetBgAlphaDragPane.updateBean())); + } + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/FileEditorMobileStyleDefinePane.java b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/FileEditorMobileStyleDefinePane.java new file mode 100644 index 0000000000..58e255b051 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/FileEditorMobileStyleDefinePane.java @@ -0,0 +1,66 @@ +package com.fr.widgettheme.widget.mobile.pane; + +import com.fr.base.background.ColorBackground; +import com.fr.util.ColorUtils; +import com.fr.widgettheme.theme.widget.mobile.style.FileEditorStyle; +import com.fr.design.mainframe.mobile.ui.MobileStyleCustomDefinePane; +import com.fr.form.ui.Widget; +import com.fr.form.ui.mobile.MobileCommonExtraStyle; +import com.fr.form.ui.mobile.MobileStyle; +import com.fr.invoke.Reflect; + +import java.awt.Color; + +/** + * 文件属性定义面板 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/5/19 + */ +public class FileEditorMobileStyleDefinePane extends DisplayEnhanceMobileStyleDefinePane { + + public FileEditorMobileStyleDefinePane(Widget widget, Class customBeanPaneClass, Class mobileStyleClazz) { + super(widget, customBeanPaneClass, mobileStyleClazz); + } + + @Override + public void populateBean(MobileStyle ob) { + MobileCommonExtraStyle extraStyle = ob.getMobileCommonExtraStyle(); + if (extraStyle instanceof FileEditorStyle) { + FileEditorStyle style = (FileEditorStyle) extraStyle; + customCombo.setSelectedIndex(style.isCustom() ? 1 : 0); + if (style.getWidgetBackground() != null) { + Color widgetBackgroundColor = ((ColorBackground) style.getWidgetBackground()).getColor(); + widgetBackgroundSelectBox.setSelectObject(ColorUtils.ignoreColorAlpha(widgetBackgroundColor)); + widgetBgAlphaDragPane.populateBean(ColorUtils.roundColorAlphaDouble(widgetBackgroundColor)); + } + borderType.setSelectedLineStyle(style.getBorderType()); + borderRadius.setValue(style.getBorderRadius()); + borderColorSelectBox.setSelectObject(style.getBorderColor()); + } + this.customBeanPane.populateBean(ob); + } + + @Override + public MobileStyle updateBean() { + mobileStyle = Reflect.on(mobileStyleClazz).create().get(); + FileEditorStyle extraStyle = new FileEditorStyle(); + extraStyle.setCustom(customCombo.getSelectedIndex() == 1); + extraStyle.setWidgetBackground(ColorUtils.createColorBackgroundWithAlpha(widgetBackgroundSelectBox.getSelectObject(), widgetBgAlphaDragPane.updateBean())); + extraStyle.setBorderType(borderType.getSelectedLineStyle()); + extraStyle.setBorderRadius(borderRadius.getValue()); + extraStyle.setBorderColor(borderColorSelectBox.getSelectObject()); + mobileStyle.setMobileCommonExtraStyle(extraStyle); + this.widget.setMobileStyle(mobileStyle); + this.customBeanPane.updateBean(); + return mobileStyle; + } + + @Override + protected void createUniversalPane() { + createBackgroundPane(); + createBorderLinePane(); + createBorderRadiusPane(); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/FreeButtonMobileStyleDefinePane.java b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/FreeButtonMobileStyleDefinePane.java new file mode 100644 index 0000000000..7c3af9b127 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/FreeButtonMobileStyleDefinePane.java @@ -0,0 +1,47 @@ +package com.fr.widgettheme.widget.mobile.pane; + +import com.fr.design.i18n.Toolkit; +import com.fr.design.mainframe.mobile.ui.MobileStyleCustomDefinePane; +import com.fr.form.ui.Widget; +import com.fr.form.ui.mobile.MobileStyle; +import com.fr.util.ColorUtils; +import com.fr.widgettheme.theme.widget.theme.WidgetThemeDisplayConstants; + +/** + * 按钮控件通用属性面板 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/5/25 + */ +public class FreeButtonMobileStyleDefinePane extends DisplayEnhanceMobileStyleDefinePane { + + public FreeButtonMobileStyleDefinePane(Widget widget, Class customBeanPaneClass, Class mobileStyleClazz) { + super(widget, customBeanPaneClass, mobileStyleClazz); + } + + @Override + protected void createUniversalPane() { + createBackgroundPane(); + createBorderLinePane(); + createBorderRadiusPane(); + createFontPane(); + } + + @Override + protected void initDefaultBorder() { + borderType.setSelectedLineStyle(com.fr.stable.Constants.LINE_NONE); + } + + @Override + protected void initBackgroundColor() { + widgetBackgroundSelectBox.setSelectObject(getCurrentTemplateThemeColor()); + widgetBgAlphaDragPane.populateBean(1); + } + + @Override + protected void createFontPane() { + fontConfigPane = new MobileStyleFontConfigPane(ColorUtils.hexToColor(WidgetThemeDisplayConstants.COLOR_FFFFFF_HEX)); + settingPane.add(createLeftRightComponentsPane(createConfigLabel(Toolkit.i18nText("Fine-Design_Mobile_Widget_Font")), fontConfigPane)); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/IconColorMobileStyleDefinePane.java b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/IconColorMobileStyleDefinePane.java new file mode 100644 index 0000000000..c93532cb67 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/IconColorMobileStyleDefinePane.java @@ -0,0 +1,36 @@ +package com.fr.widgettheme.widget.mobile.pane; + +import com.fr.design.mainframe.mobile.ui.MobileStyleCustomDefinePane; +import com.fr.form.ui.Widget; +import com.fr.form.ui.mobile.MobileStyle; +import com.fr.widgettheme.theme.widget.theme.WidgetThemeDisplayConstants; + +/** + * 带有图标颜色的移动端控件通用配置面板 + * + * @author obo + * @since 11.0 + * Created on 2024/1/25 + */ +public class IconColorMobileStyleDefinePane extends DisplayEnhanceMobileStyleDefinePane{ + + public IconColorMobileStyleDefinePane(Widget widget, Class customBeanPaneClass, Class mobileStyleClazz) { + super(widget, customBeanPaneClass, mobileStyleClazz); + } + + @Override + protected void createUniversalPane() { + // 主题色 + createThemePane(); + // 组件背景 + createBackgroundPane(); + // 边框线型 + createBorderLinePane(); + // 圆角边框 + createBorderRadiusPane(); + //图标颜色 + createIconColorSelectBox(); + // 字体 + createFontPane(); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/LabelMobileStyleDefinePane.java b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/LabelMobileStyleDefinePane.java new file mode 100644 index 0000000000..71c69a6dca --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/LabelMobileStyleDefinePane.java @@ -0,0 +1,33 @@ +package com.fr.widgettheme.widget.mobile.pane; + +import com.fr.design.mainframe.mobile.ui.MobileStyleCustomDefinePane; +import com.fr.form.ui.Widget; +import com.fr.form.ui.mobile.MobileStyle; +import com.fr.widgettheme.theme.widget.theme.WidgetThemeDisplayConstants; + +/** + * 标签控件属性定义面板 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/5/15 + */ +public class LabelMobileStyleDefinePane extends DisplayEnhanceMobileStyleDefinePane { + public LabelMobileStyleDefinePane(Widget widget, Class customBeanPaneClass, + Class mobileStyleClazz) { + super(widget, customBeanPaneClass, mobileStyleClazz); + } + + @Override + protected void createUniversalPane() { + createBackgroundPane(); + createBorderLinePane(); + createBorderRadiusPane(); + createFontPane(); + } + + @Override + protected void initDefaultBorder() { + borderType.setSelectedLineStyle(com.fr.stable.Constants.LINE_NONE); + } +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/MobileStyleFontConfigPane.java b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/MobileStyleFontConfigPane.java new file mode 100644 index 0000000000..6b02ec9ff0 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/MobileStyleFontConfigPane.java @@ -0,0 +1,151 @@ +package com.fr.widgettheme.widget.mobile.pane; + + +import com.fr.base.BaseUtils; +import com.fr.design.constants.LayoutConstants; +import com.fr.design.gui.ibutton.UIColorButton; +import com.fr.design.gui.ibutton.UIToggleButton; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.icombobox.UIComboBoxRenderer; +import com.fr.design.i18n.Toolkit; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.general.FRFont; +import com.fr.stable.Constants; +import com.fr.stable.StringUtils; + +import javax.swing.DefaultComboBoxModel; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.util.Vector; + +/** + * 移动端字体面板 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/5/22 + */ +public class MobileStyleFontConfigPane extends JPanel { + public static final int FONT_NONE = 0; + private static final int MAX_FONT_SIZE = 18; + private static final int MIN_FONT_SIZE = 12; + private static final Dimension BUTTON_SIZE = new Dimension(20, 18); + + /** + * 获取字体大小集合 + * + * @return 字体大小集合 + */ + public static Vector getFontSizes() { + Vector fontSizes = new Vector(); + for (int i = MIN_FONT_SIZE; i <= MAX_FONT_SIZE; i++) { + fontSizes.add(i); + } + return fontSizes; + } + + private UIComboBox fontSizeComboBox; + private UIColorButton color; + private UIToggleButton italic; + private UIToggleButton bold; + + public MobileStyleFontConfigPane() { + this.initComponent(new Color(0, 0, 0)); + } + + public MobileStyleFontConfigPane(Color defaultFontColor) { + this.initComponent(defaultFontColor); + } + + private void initComponent(Color defaultFontColor) { + fontSizeComboBox = new UIComboBox(); + fontSizeComboBox.setModel(new DefaultComboBoxModel(getFontSizes())); + fontSizeComboBox.setSelectedItem(16); + fontSizeComboBox.setPreferredSize(new Dimension(60, 20)); + fontSizeComboBox.setRenderer(new LineCellRenderer()); + color = new UIColorButton(); + color.setColor(defaultFontColor); + italic = new UIToggleButton(BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/italic.png")); + bold = new UIToggleButton(BaseUtils.readIcon("/com/fr/design/images/m_format/cellstyle/bold.png")); + + this.setButtonsTips(); + this.setButtonsSize(BUTTON_SIZE); + + Component[] componentFont = new Component[]{ + fontSizeComboBox, color, italic, bold + }; + + JPanel buttonPane = new JPanel(new BorderLayout()); + JPanel flowPane = GUICoreUtils.createFlowPane(componentFont, FlowLayout.LEFT, LayoutConstants.HGAP_LARGE); + // 4是flowPane的默认横向gap,但会导致最左边的控件和边上也有4的间隙,调整一下 + flowPane.setBorder(new EmptyBorder(0, -LayoutConstants.HGAP_LARGE, 0, 0)); + buttonPane.add(flowPane); + + this.setLayout(new BorderLayout(0, 0)); + this.add(buttonPane, BorderLayout.CENTER); + } + + private void setButtonsTips() { + color.setToolTipText(Toolkit.i18nText("Fine-Design_Report_Foreground")); + italic.setToolTipText(Toolkit.i18nText("Fine-Design_Report_Italic")); + bold.setToolTipText(Toolkit.i18nText("Fine-Design_Report_Bold")); + } + + private void setButtonsSize(Dimension size) { + color.setPreferredSize(size); + italic.setPreferredSize(size); + bold.setPreferredSize(size); + } + + /** + * 填充字体 + * + * @param frFont 字体 + */ + public void populateBean(FRFont frFont) { + fontSizeComboBox.setSelectedItem(frFont.getSize()); + color.setColor(frFont.getForeground()); + bold.setSelected(frFont.isBold()); + italic.setSelected(frFont.isItalic()); + } + + /** + * 更新字体 + */ + public FRFont updateBean() { + int style = Font.PLAIN; + style += this.bold.isSelected() ? Font.BOLD : Font.PLAIN; + style += this.italic.isSelected() ? Font.ITALIC : Font.PLAIN; + return FRFont.getInstance( + FRFont.DEFAULT_FONTNAME, + style, + Float.parseFloat(fontSizeComboBox.getSelectedItem().toString()), + color.getColor(), + Constants.LINE_NONE + ); + } + + private class LineCellRenderer extends UIComboBoxRenderer { + public LineCellRenderer() { + super(); + } + + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + JLabel renderer = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + int currentValue = ((Integer) value).intValue(); + if (currentValue == com.fr.design.mainframe.mobile.ui.MobileStyleFontConfigPane.FONT_NONE) { + renderer.setText(StringUtils.BLANK + Toolkit.i18nText("Fine-Design_Report_None")); + } + return renderer; + } + } + +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/TextAreaMobileStyleDefinePane.java b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/TextAreaMobileStyleDefinePane.java new file mode 100644 index 0000000000..db96ee38b1 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/pane/TextAreaMobileStyleDefinePane.java @@ -0,0 +1,33 @@ +package com.fr.widgettheme.widget.mobile.pane; + +import com.fr.design.mainframe.mobile.ui.MobileStyleCustomDefinePane; +import com.fr.form.ui.Widget; +import com.fr.form.ui.mobile.MobileStyle; +import com.fr.widgettheme.theme.widget.theme.WidgetThemeDisplayConstants; + +/** + * 文本域控件移动端配置面板 + * + * @author obo + * @since 11.0 + * Created on 2024/1/25 + */ +public class TextAreaMobileStyleDefinePane extends DisplayEnhanceMobileStyleDefinePane{ + public TextAreaMobileStyleDefinePane(Widget widget, Class customBeanPaneClass, Class mobileStyleClazz) { + super(widget, customBeanPaneClass, mobileStyleClazz); + } + + @Override + protected void createUniversalPane() { + // 主题色 + createThemePane(); + // 组件背景 + createBackgroundPane(); + // 边框线型 + createBorderLinePane(); + // 圆角边框 + createBorderRadiusPane(); + // 字体 + createFontPane(); + } +} diff --git a/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/provider/DisplayEnhanceMobileStyleFactory.java b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/provider/DisplayEnhanceMobileStyleFactory.java new file mode 100644 index 0000000000..fea523c684 --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/provider/DisplayEnhanceMobileStyleFactory.java @@ -0,0 +1,63 @@ +package com.fr.widgettheme.widget.mobile.provider; + +import com.fr.form.ui.TextArea; +import com.fr.widgettheme.theme.widget.mobile.style.WidgetThemeMobileCommonExtraStyle; +import com.fr.widgettheme.widget.mobile.pane.FileEditorMobileStyleDefinePane; +import com.fr.widgettheme.widget.mobile.pane.FreeButtonMobileStyleDefinePane; +import com.fr.widgettheme.widget.mobile.pane.LabelMobileStyleDefinePane; +import com.fr.widgettheme.theme.widget.mobile.style.FileEditorStyle; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.mainframe.mobile.ui.MobileStyleCustomDefinePane; +import com.fr.form.ui.FreeButton; +import com.fr.form.ui.Label; +import com.fr.form.ui.MultiFileEditor; +import com.fr.form.ui.Widget; +import com.fr.form.ui.mobile.MobileCommonExtraStyle; +import com.fr.form.ui.mobile.MobileStyle; +import com.fr.widgettheme.widget.mobile.pane.TextAreaMobileStyleDefinePane; + +/** + * 样式创建工厂 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/5/15 + */ +public class DisplayEnhanceMobileStyleFactory { + + /** + * 先写个简单工厂处理一下特殊的控件 + * + * @param widget + * @return 特殊控件的通用属性面板 + */ + public static BasicBeanPane createWidgetMobileStyleDefinePane(Widget widget, Class customDefinePane, Class mobileStyle) { + if (widget instanceof Label) { + return new LabelMobileStyleDefinePane(widget, customDefinePane, mobileStyle); + } + if (widget instanceof MultiFileEditor) { + return new FileEditorMobileStyleDefinePane(widget, customDefinePane, mobileStyle); + } + if (widget instanceof FreeButton) { + return new FreeButtonMobileStyleDefinePane(widget, customDefinePane, mobileStyle); + } + if (widget instanceof TextArea) { + return new TextAreaMobileStyleDefinePane(widget, customDefinePane, mobileStyle); + } + return null; + } + + /** + * 生成控件移动端通用属性 + * + * @param widget + * @return + */ + public static Class classForWidgetCommonExtraStyle(Widget widget) { + if (widget instanceof MultiFileEditor) { + return FileEditorStyle.class; + } + return WidgetThemeMobileCommonExtraStyle.class; + } + +} \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/provider/WidgetThemeMobileStyleDefinePaneCreator.java b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/provider/WidgetThemeMobileStyleDefinePaneCreator.java new file mode 100644 index 0000000000..a8aca84dcc --- /dev/null +++ b/designer-base/src/main/java/com/fr/widgettheme/widget/mobile/provider/WidgetThemeMobileStyleDefinePaneCreator.java @@ -0,0 +1,125 @@ +package com.fr.widgettheme.widget.mobile.provider; + +import com.fr.form.ui.ComboBox; +import com.fr.form.ui.ComboCheckBox; +import com.fr.form.ui.DateEditor; +import com.fr.form.ui.NumberEditor; +import com.fr.form.ui.Password; +import com.fr.form.ui.TextArea; +import com.fr.form.ui.TextEditor; +import com.fr.form.ui.TreeComboBoxEditor; +import com.fr.form.ui.TreeEditor; +import com.fr.widgettheme.util.WidgetThemeDesignerUtils; +import com.fr.widgettheme.utils.WidgetThemeServerUtils; +import com.fr.widgettheme.widget.mobile.pane.DisplayEnhanceMobileStyleDefinePane; +import com.fr.widgettheme.theme.widget.mobile.style.WidgetThemeMobileCommonExtraStyle; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.mainframe.mobile.ui.MobileStyleCustomDefinePane; +import com.fr.form.ui.FreeButton; +import com.fr.form.ui.Label; +import com.fr.form.ui.MultiFileEditor; +import com.fr.form.ui.Widget; +import com.fr.form.ui.mobile.MobileCommonExtraStyle; +import com.fr.form.ui.mobile.MobileStyle; +import com.fr.log.FineLoggerFactory; +import com.fr.widgettheme.widget.mobile.pane.IconColorMobileStyleDefinePane; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +/** + * 控件主题移动端样式窗口创建类 + * + * @author obo + * @since 11.0 + * Created on 2023/11/13 + */ +public class WidgetThemeMobileStyleDefinePaneCreator { + + private WidgetThemeMobileStyleDefinePaneCreator() { + } + + /** + * 需要特殊处理的控件集合 + */ + private static final Set> SPECIAL_WIDGET_SET = new HashSet<>(); + /** + * 带有图标颜色的控件集合 + */ + private static final Set> ICON_WIDGET_SET = new HashSet<>(); + + static { + SPECIAL_WIDGET_SET.add(FreeButton.class); + SPECIAL_WIDGET_SET.add(Label.class); + SPECIAL_WIDGET_SET.add(MultiFileEditor.class); + SPECIAL_WIDGET_SET.add(TextArea.class); + ICON_WIDGET_SET.add(TextEditor.class); + ICON_WIDGET_SET.add(NumberEditor.class); + ICON_WIDGET_SET.add(Password.class); + ICON_WIDGET_SET.add(DateEditor.class); + ICON_WIDGET_SET.add(ComboBox.class); + ICON_WIDGET_SET.add(ComboCheckBox.class); + ICON_WIDGET_SET.add(TreeComboBoxEditor.class); + ICON_WIDGET_SET.add(TreeEditor.class); + } + /** + * 创建移动端控件样式属性窗口 + * + * @param widget 控件 + * @param customDefinePane 窗口类 + * @param mobileStyle 样式类 + * @return 窗口 + */ + public static BasicBeanPane createBaseBeanPane(Widget widget, Class customDefinePane, Class mobileStyle) { + try { + if (WidgetThemeDesignerUtils.enableWidgetEnhance()) { + if (isSpecialWidget(widget)) { + return DisplayEnhanceMobileStyleFactory.createWidgetMobileStyleDefinePane(widget, customDefinePane, mobileStyle); + } else if (isIconWidget(widget)) { + return new IconColorMobileStyleDefinePane(widget, customDefinePane, mobileStyle); + } else { + return new DisplayEnhanceMobileStyleDefinePane(widget, customDefinePane, mobileStyle); + } + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error("[Strongest-Control]: create base bean pane failed.", e); + } + return null; + } + + /** + * 根据控件获取通用扩展属性类 + * + * @param widget 控件 + * @return class + */ + public static @NotNull Class classForCommonExtraStyle(Widget widget) { + if (isSpecialWidget(widget)) { + return DisplayEnhanceMobileStyleFactory.classForWidgetCommonExtraStyle(widget); + } else { + return WidgetThemeMobileCommonExtraStyle.class; + } + } + + /** + * 是否为普通控件 + * 按钮控件、标签控件、文件控件需要特殊处理 + * + * @param widget 控件 + * @return 是/否 + */ + private static boolean isSpecialWidget(Widget widget) { + return SPECIAL_WIDGET_SET.contains(widget.getClass()); + } + + /** + * 是否为带图标的控件 + * + * @param widget 控件 + * @return 是/否 + */ + private static boolean isIconWidget(Widget widget) { + return ICON_WIDGET_SET.contains(widget.getClass()) || WidgetThemeServerUtils.isNewComboBoxTreeEditor(widget); + } +} diff --git a/designer-base/src/main/resources/com/fr/design/config/default b/designer-base/src/main/resources/com/fr/design/config/default index f808a82379..b323302824 100644 --- a/designer-base/src/main/resources/com/fr/design/config/default +++ b/designer-base/src/main/resources/com/fr/design/config/default @@ -1 +1,2 @@ Fine-Designer_Login=i7hP48WAcuTrmxfN +Fine-Designer_Reu_Share_CERTIFICATE_PUBLIC_KEY=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtsz62CPSWXZE/IYZRiAuTSZkw1WOwer8+JFktK0uKLAUuQoBr+UjAMFtRA8W7JgKMDwZy/2liEAiXEOSPU/hrdV8DtT541LnGi1X/hXiRwuttPWYN3L2GYm/d5blU+FBNwghBIrdAxXTzYBc6P4KL/oYXnMdTIrkz8tYkG3QoFQIDAQAB \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties index 5098bc3c97..1405f81c6a 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_en.properties @@ -25,3 +25,7 @@ com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 com.fr.design.report.WatermarkSettingPane=720*600 com.fr.design.file.MultiTemplateTabPane.popUpMenu=350*65 com.fr.design.data.datapane.preview.desensitization.view.rule.DesensitizationRuleChoosePane.ruleEditPane=800*600 +com.fr.design.formula.FormulaPane=900*600 +com.fr.design.formula.FormulaPaneWhenReserveFormula=1200*600 +com.fr.design.mainframe.mobile.ui.MobileStyleDefinePane.configLabel=130*20 +com.fr.design.mainframe.mobile.utils.DesignerUtils.configLabel=140*20 diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties index 6c3ac0e58c..6af9a798c0 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ja_JP.properties @@ -24,3 +24,7 @@ com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 com.fr.design.report.WatermarkSettingPane=720*600 com.fr.design.file.MultiTemplateTabPane.popUpMenu=240*65 com.fr.design.data.datapane.preview.desensitization.view.rule.DesensitizationRuleChoosePane.ruleEditPane=800*600 +com.fr.design.formula.FormulaPane=900*600 +com.fr.design.formula.FormulaPaneWhenReserveFormula=900*600 +com.fr.design.mainframe.mobile.ui.MobileStyleDefinePane.configLabel=100*20 +com.fr.design.mainframe.mobile.utils.DesignerUtils.configLabel=130*20 diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties index eaa75e14a0..98ac411090 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_ko_KR.properties @@ -14,7 +14,7 @@ com.fr.design.report.fit.firstColumn=130*20 com.fr.design.report.fit.column=100*20 com.fr.design.lock.LockInfoDialog=500*180 com.fr.design.mainframe.ForbiddenPane.refreshButton=80*24 -com.fr.start.common.DesignerOpenEmptyPanel.createButton=70*24 +com.fr.start.common.DesignerOpenEmptyPanel.createButton=90*24 com.fr.design.cell.expand.sort.pane=267*165 com.fr.design.sort.rule.item=125*20 com.fr.design.ds.column.sort.pane=250*180 @@ -24,3 +24,7 @@ com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 com.fr.design.report.WatermarkSettingPane=720*600 com.fr.design.file.MultiTemplateTabPane.popUpMenu=240*65 com.fr.design.data.datapane.preview.desensitization.view.rule.DesensitizationRuleChoosePane.ruleEditPane=800*600 +com.fr.design.formula.FormulaPane=900*600 +com.fr.design.formula.FormulaPaneWhenReserveFormula=900*600 +com.fr.design.mainframe.mobile.ui.MobileStyleDefinePane.configLabel=75*20 +com.fr.design.mainframe.mobile.utils.DesignerUtils.configLabel=100*20 diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties index d1e84b4618..9c9e1bd92a 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh.properties @@ -24,3 +24,7 @@ com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog=600*500 com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 com.fr.design.report.WatermarkSettingPane=720*600 com.fr.design.file.MultiTemplateTabPane.popUpMenu=170*65 +com.fr.design.formula.FormulaPane=900*600 +com.fr.design.formula.FormulaPaneWhenReserveFormula=900*600 +com.fr.design.mainframe.mobile.ui.MobileStyleDefinePane.configLabel=75*20 +com.fr.design.mainframe.mobile.utils.DesignerUtils.configLabel=100*20 diff --git a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties index 82f86a3a43..03972b51c0 100644 --- a/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties +++ b/designer-base/src/main/resources/com/fr/design/i18n/dimension_zh_TW.properties @@ -23,3 +23,7 @@ com.fr.design.plugin.remind.PluginInvalidateRemindDialog.dialog=600*500 com.fr.design.plugin.remind.PluginInvalidateRemindDialog.centerPane=580*369 com.fr.design.report.WatermarkSettingPane=720*600 com.fr.design.file.MultiTemplateTabPane.popUpMenu=170*65 +com.fr.design.formula.FormulaPane=900*600 +com.fr.design.formula.FormulaPaneWhenReserveFormula=900*600 +com.fr.design.mainframe.mobile.ui.MobileStyleDefinePane.configLabel=75*20 +com.fr.design.mainframe.mobile.utils.DesignerUtils.configLabel=100*20 diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/icon_add.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/icon_add.png new file mode 100644 index 0000000000..170c4027db Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/buttonicon/icon_add.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/icon_delete.png b/designer-base/src/main/resources/com/fr/design/images/buttonicon/icon_delete.png new file mode 100644 index 0000000000..60f3b0343b Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/buttonicon/icon_delete.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/buttonicon/new_other_normal.svg b/designer-base/src/main/resources/com/fr/design/images/buttonicon/new_other_normal.svg new file mode 100644 index 0000000000..0b3799c9a9 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/buttonicon/new_other_normal.svg @@ -0,0 +1,4 @@ + + + + diff --git a/designer-base/src/main/resources/com/fr/design/images/control/down_arrow.png b/designer-base/src/main/resources/com/fr/design/images/control/down_arrow.png deleted file mode 100644 index 26a780d5e2..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/images/control/down_arrow.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/images/control/east_arrow.png b/designer-base/src/main/resources/com/fr/design/images/control/east_arrow.png deleted file mode 100644 index 918d75a9f9..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/images/control/east_arrow.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/images/control/up_arrow.png b/designer-base/src/main/resources/com/fr/design/images/control/up_arrow.png deleted file mode 100644 index 3d79ee07bd..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/images/control/up_arrow.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/images/control/west_arrow.png b/designer-base/src/main/resources/com/fr/design/images/control/west_arrow.png deleted file mode 100644 index 5693190f96..0000000000 Binary files a/designer-base/src/main/resources/com/fr/design/images/control/west_arrow.png and /dev/null differ diff --git a/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg.png b/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg.png index 9e731c557b..a302e257b2 100644 Binary files a/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg.png and b/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg_en.png b/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg_en.png new file mode 100644 index 0000000000..a302e257b2 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg_en.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg_zh.png b/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg_zh.png new file mode 100644 index 0000000000..55419d0a68 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg_zh.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg_zh_TW.png b/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg_zh_TW.png new file mode 100644 index 0000000000..6f9aa1036f Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/form/designer/widget/picture_widget_designer_bg_zh_TW.png differ diff --git a/designer-base/src/main/resources/com/fr/design/images/lookandfeel/TreeLeafIcon.svg b/designer-base/src/main/resources/com/fr/design/images/lookandfeel/TreeLeafIcon.svg new file mode 100644 index 0000000000..c2971da642 --- /dev/null +++ b/designer-base/src/main/resources/com/fr/design/images/lookandfeel/TreeLeafIcon.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/designer-base/src/main/resources/com/fr/design/images/mainframe/loading/loading.gif b/designer-base/src/main/resources/com/fr/design/images/mainframe/loading/loading.gif new file mode 100644 index 0000000000..ce2172ba41 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/mainframe/loading/loading.gif differ diff --git a/designer-base/src/main/resources/com/fr/design/images/mainframe/loading/loading_en.gif b/designer-base/src/main/resources/com/fr/design/images/mainframe/loading/loading_en.gif new file mode 100644 index 0000000000..26870d749c Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/mainframe/loading/loading_en.gif differ diff --git a/designer-base/src/main/resources/com/fr/design/images/mainframe/loading/loading_zh.gif b/designer-base/src/main/resources/com/fr/design/images/mainframe/loading/loading_zh.gif new file mode 100644 index 0000000000..c77b4fe100 Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/mainframe/loading/loading_zh.gif differ diff --git a/designer-base/src/main/resources/com/fr/design/images/mainframe/loading/loading_zh_TW.gif b/designer-base/src/main/resources/com/fr/design/images/mainframe/loading/loading_zh_TW.gif new file mode 100644 index 0000000000..c78edd7a9c Binary files /dev/null and b/designer-base/src/main/resources/com/fr/design/images/mainframe/loading/loading_zh_TW.gif differ diff --git a/designer-base/src/main/resources/com/fr/design/login/guide.css b/designer-base/src/main/resources/com/fr/design/login/guide.css deleted file mode 100644 index 12af5f6c3b..0000000000 --- a/designer-base/src/main/resources/com/fr/design/login/guide.css +++ /dev/null @@ -1,57 +0,0 @@ -.background-login-close { - color: white !important; - font-weight: bold; - font-size: 14px; -} -.background-guide-close { - background: url(./img/icon_install_normal.png) no-repeat center center; - background-size: cover; - width: 20px; - height: 20px; - cursor: pointer; -} -.background-guide-close:hover { - background-color: #E8E8E9; -} -.background-login-loading { - background: url(./img/login_loading.gif) no-repeat center center; -} -.background-plugin-need-update { - background: url(./img/icon_new.png) no-repeat center center; -} -.background-plugin-cant-use { - background: url(./img/icon_cantuse.png) no-repeat center center; -} -.background-plugin-is-disable { - background: url(./img/icon_disable.png) no-repeat center center; -} -.background-plugin-is-disable-new { - background: url(./img/icon_disable-new.png) no-repeat center center; -} -.background-plugin-selected { - background: url(./img/icon_marked.png) no-repeat center center; -} -.background-shop-title-close { - background: url(./img/icon_close40x40_normal.svg) no-repeat center center; -} -.background-dialog-confirm { - background: url(./img/warning.png) no-repeat center center; - background-size: contain; -} -.background-close-button { - background: url(./img/icon_close9x9_normal.png) no-repeat center center; -} -.background-close-button:hover { - background: url(./img/icon_close9x9_hover.png) no-repeat center center; -} -.designer-login-guide { - background: url(./img/login_guide.png) no-repeat center center; - background-size: cover; -} -.designer-guide-login-button { - font-size: 14px; - color: white; - border-radius: 4px; - background-color: #3685F2; -} - diff --git a/designer-base/src/main/resources/com/fr/design/login/guide.html b/designer-base/src/main/resources/com/fr/design/login/guide.html index aada842a10..bafec74c30 100644 --- a/designer-base/src/main/resources/com/fr/design/login/guide.html +++ b/designer-base/src/main/resources/com/fr/design/login/guide.html @@ -15,7 +15,7 @@ - + diff --git a/designer-chart/src/main/resources/com/fr/design/images/emptydata/emptydata.png b/designer-chart/src/main/resources/com/fr/design/images/emptydata/emptydata.png new file mode 100644 index 0000000000..ddb244479c Binary files /dev/null and b/designer-chart/src/main/resources/com/fr/design/images/emptydata/emptydata.png differ diff --git a/designer-chart/src/main/resources/com/fr/design/images/emptydata/emptydata_en.png b/designer-chart/src/main/resources/com/fr/design/images/emptydata/emptydata_en.png new file mode 100644 index 0000000000..ddb244479c Binary files /dev/null and b/designer-chart/src/main/resources/com/fr/design/images/emptydata/emptydata_en.png differ diff --git a/designer-chart/src/main/resources/com/fr/design/images/emptydata/emptydata_zh.png b/designer-chart/src/main/resources/com/fr/design/images/emptydata/emptydata_zh.png new file mode 100644 index 0000000000..cb5dfc00b4 Binary files /dev/null and b/designer-chart/src/main/resources/com/fr/design/images/emptydata/emptydata_zh.png differ diff --git a/designer-chart/src/main/resources/com/fr/design/images/emptydata/emptydata_zh_TW.png b/designer-chart/src/main/resources/com/fr/design/images/emptydata/emptydata_zh_TW.png new file mode 100644 index 0000000000..e6b7b9733a Binary files /dev/null and b/designer-chart/src/main/resources/com/fr/design/images/emptydata/emptydata_zh_TW.png differ diff --git a/designer-chart/src/main/resources/com/fr/design/images/us_emptydata.png b/designer-chart/src/main/resources/com/fr/design/images/us_emptydata.png deleted file mode 100644 index 46597ea7a1..0000000000 Binary files a/designer-chart/src/main/resources/com/fr/design/images/us_emptydata.png and /dev/null differ diff --git a/designer-chart/src/main/resources/com/fr/design/images/zh_emptydata.png b/designer-chart/src/main/resources/com/fr/design/images/zh_emptydata.png deleted file mode 100644 index 5a6c3a9624..0000000000 Binary files a/designer-chart/src/main/resources/com/fr/design/images/zh_emptydata.png and /dev/null differ diff --git a/designer-chart/src/main/resources/com/fr/van/chart/background/background.png b/designer-chart/src/main/resources/com/fr/van/chart/background/background.png new file mode 100644 index 0000000000..33f81790b9 Binary files /dev/null and b/designer-chart/src/main/resources/com/fr/van/chart/background/background.png differ diff --git a/designer-chart/src/main/resources/com/fr/van/chart/background/background_en.png b/designer-chart/src/main/resources/com/fr/van/chart/background/background_en.png new file mode 100644 index 0000000000..33f81790b9 Binary files /dev/null and b/designer-chart/src/main/resources/com/fr/van/chart/background/background_en.png differ diff --git a/designer-chart/src/main/resources/com/fr/van/chart/background.png b/designer-chart/src/main/resources/com/fr/van/chart/background/background_zh.png similarity index 100% rename from designer-chart/src/main/resources/com/fr/van/chart/background.png rename to designer-chart/src/main/resources/com/fr/van/chart/background/background_zh.png diff --git a/designer-chart/src/main/resources/com/fr/van/chart/background/background_zh_TW.png b/designer-chart/src/main/resources/com/fr/van/chart/background/background_zh_TW.png new file mode 100644 index 0000000000..794af8550c Binary files /dev/null and b/designer-chart/src/main/resources/com/fr/van/chart/background/background_zh_TW.png differ diff --git a/designer-form/src/main/java/com/fr/design/actions/NewFormAction.java b/designer-form/src/main/java/com/fr/design/actions/NewFormAction.java index aa50c13f69..d619c73007 100644 --- a/designer-form/src/main/java/com/fr/design/actions/NewFormAction.java +++ b/designer-form/src/main/java/com/fr/design/actions/NewFormAction.java @@ -6,16 +6,12 @@ import com.fr.design.widget.ui.designer.NewFormPane; import javax.swing.KeyStroke; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; - -import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; public class NewFormAction extends UpdateAction { public NewFormAction() { this.setMenuKeySet(NEW_FORM); - this.setName(getMenuKeySet().getMenuKeySetName()); - this.setMnemonic(getMenuKeySet().getMnemonic()); + this.setName(getMenuKeySet().getMenuName()); this.setSmallIcon("/com/fr/design/images/buttonicon/new_form3"); this.setAccelerator(getMenuKeySet().getKeyStroke()); } @@ -33,7 +29,7 @@ public class NewFormAction extends UpdateAction { public static final MenuKeySet NEW_FORM = new MenuKeySet() { @Override public char getMnemonic() { - return 'F'; + return 0; } @Override diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XAutoChartCreator.java b/designer-form/src/main/java/com/fr/design/designer/creator/XAutoChartCreator.java index 4c5b669b48..7d172d6c7a 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XAutoChartCreator.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XAutoChartCreator.java @@ -12,13 +12,14 @@ import com.fr.design.mainframe.EditingMouseListener; import com.fr.design.mainframe.FormDesigner; import com.fr.design.module.DesignModuleFactory; import com.fr.form.ui.ChartAutoEditor; -import com.fr.general.IOUtils; +import com.fr.general.locale.image.I18nImage; import com.fr.stable.Constants; import com.fr.stable.bridge.StableFactory; import javax.swing.JComponent; import javax.swing.JPanel; -import java.awt.*; +import java.awt.Dimension; +import java.awt.Graphics2D; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; @@ -38,6 +39,8 @@ public class XAutoChartCreator extends XChartEditor { super(editor, size); } + private static final String AUTO_CHART_IMAGE_PATH = "com/fr/design/form/images/autochartpreview/auto_chart_preview.png"; + /** * 返回组件默认名 * @@ -103,7 +106,7 @@ public class XAutoChartCreator extends XChartEditor { @Override public void paintForeground(Graphics2D g) { - BufferedImage bufferedImage = IOUtils.readImage("com/fr/design/form/images/auto_chart_preview.png"); + BufferedImage bufferedImage = I18nImage.getImage(AUTO_CHART_IMAGE_PATH); GraphHelper.paintImage( g, this.getWidth(), this.getHeight(), bufferedImage, Constants.IMAGE_ADJUST, diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XCreatorUtils.java b/designer-form/src/main/java/com/fr/design/designer/creator/XCreatorUtils.java index 1ebd19ec3d..4cb42a04ce 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XCreatorUtils.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XCreatorUtils.java @@ -33,6 +33,7 @@ import com.fr.form.ui.AbstractBorderStyleWidget; import com.fr.form.ui.Button; import com.fr.form.ui.CardAddButton; import com.fr.form.ui.CardSwitchButton; +import com.fr.form.ui.ChartEditor; import com.fr.form.ui.CheckBox; import com.fr.form.ui.CheckBoxGroup; import com.fr.form.ui.ComboBox; @@ -201,6 +202,8 @@ public class XCreatorUtils { private static void putExtraEditor() { if (DesignModuleFactory.getChartEditorClass() != null) { objectMap.put(DesignModuleFactory.getChartEditorClass(), XChartEditor.class); + } else { + objectMap.put(ChartEditor.class, XChartEditor.class); } } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XEditorHolder.java b/designer-form/src/main/java/com/fr/design/designer/creator/XEditorHolder.java index 8bcacb7d26..3291159a3a 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XEditorHolder.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XEditorHolder.java @@ -44,9 +44,7 @@ public class XEditorHolder extends XWidgetCreator { ComponentAdapter adapter = AdapterBus.getComponentAdapter(designer, this); editingMouseListener.startEditing(this, adapter.getDesignerEditor(), adapter); Rectangle rect = this.getBounds(); - int min = rect.x + rect.width / 2 - editingMouseListener.getMinMoveSize(); - int max = rect.x + rect.width / 2 + editingMouseListener.getMinMoveSize(); - if (e.getX() > min && e.getX() < max) { + if (checkMouseEditRangeValid(e, rect, editingMouseListener)) { ToolTipEditor.getInstance().showToolTip((XEditorHolder) this, e.getXOnScreen(), e.getYOnScreen()); } @@ -54,6 +52,29 @@ public class XEditorHolder extends XWidgetCreator { } } + /** + * 判断当前鼠标事件是否在可编辑区域内 + * + * @param e 鼠标事件 + * @param rect 区域 + * @param editingMouseListener 位置处理器 + * @return 是否位于可编辑区 + */ + private boolean checkMouseEditRangeValid(MouseEvent e, Rectangle rect, EditingMouseListener editingMouseListener) { + int horizontalValue = editingMouseListener.getDesigner().getHorizontalScaleValue(); + int verticalValue = editingMouseListener.getDesigner().getVerticalScaleValue(); + int minMoveSize = editingMouseListener.getMinMoveSize(); + + int minHorizontal = rect.x + rect.width / 2 - minMoveSize - horizontalValue; + int maxHorizontal = rect.x + rect.width / 2 + minMoveSize - horizontalValue; + int minVertical = rect.y + rect.height / 2 - minMoveSize - verticalValue; + int maxVertical = rect.y + rect.height / 2 + minMoveSize - verticalValue; + boolean xRangeValid = e.getX() > minHorizontal && e.getX() < maxHorizontal; + boolean yRangeValid = e.getY() > minVertical && e.getY() < maxVertical; + + return xRangeValid && yRangeValid; + } + @Override protected String getIconName() { return "text_field_16.png"; diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XNumberEditor.java b/designer-form/src/main/java/com/fr/design/designer/creator/XNumberEditor.java index 15cd30c6fd..8861d6fcbc 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XNumberEditor.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XNumberEditor.java @@ -6,7 +6,9 @@ package com.fr.design.designer.creator; import com.fr.base.BaseUtils; import com.fr.base.ScreenResolution; import com.fr.base.Style; +import com.fr.design.designer.properties.mobile.NumberEditorMobilePropertyUI; import com.fr.design.form.util.XCreatorConstants; +import com.fr.design.fun.WidgetPropertyUIProvider; import com.fr.design.mainframe.widget.editors.InChangeBooleanEditor; import com.fr.design.mainframe.widget.editors.SpinnerMaxNumberEditor; import com.fr.design.mainframe.widget.editors.SpinnerMinNumberEditor; @@ -91,15 +93,19 @@ public class XNumberEditor extends XWrapperedFieldEditor { } } - @Override + @Override protected JComponent initEditor() { setBorder(FIELDBORDER); return this; } - @Override - protected String getIconName() { - return "number_field_16.png"; - } + @Override + protected String getIconName() { + return "number_field_16.png"; + } + @Override + public WidgetPropertyUIProvider[] getWidgetPropertyUIProviders() { + return new WidgetPropertyUIProvider[]{new NumberEditorMobilePropertyUI(this)}; + } } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XPassword.java b/designer-form/src/main/java/com/fr/design/designer/creator/XPassword.java index 4194e4be03..29de6c9d05 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XPassword.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XPassword.java @@ -3,7 +3,9 @@ */ package com.fr.design.designer.creator; +import com.fr.design.designer.properties.mobile.PasswordMobilePropertyUI; import com.fr.design.form.util.XCreatorConstants; +import com.fr.design.fun.WidgetPropertyUIProvider; import com.fr.design.gui.ibutton.UIPasswordField; import com.fr.design.mainframe.widget.editors.RegexEditor; import com.fr.design.mainframe.widget.editors.WidgetValueEditor; @@ -68,4 +70,8 @@ public class XPassword extends XWrapperedFieldEditor { (CRPropertyDescriptor[]) ArrayUtils.addAll(sup, new CRPropertyDescriptor[]{regex, waterMark}); } + @Override + public WidgetPropertyUIProvider[] getWidgetPropertyUIProviders() { + return new WidgetPropertyUIProvider[]{new PasswordMobilePropertyUI(this)}; + } } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XPicture.java b/designer-form/src/main/java/com/fr/design/designer/creator/XPicture.java index 7dd23bd4ce..32bf212037 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XPicture.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XPicture.java @@ -9,6 +9,7 @@ import com.fr.design.mainframe.widget.renderer.PictureRenderer; import com.fr.design.mainframe.widget.renderer.UrlLinkRenderer; import com.fr.form.ui.PictureWidget; import com.fr.general.IOUtils; +import com.fr.general.locale.image.I18nImage; import com.fr.stable.ArrayUtils; import java.awt.Dimension; import java.awt.Image; @@ -59,7 +60,7 @@ public class XPicture extends XWidgetCreator { imgPanel.setBackgroundImage((Image) value); imgPanel.setImageDisplayMode(pictureWidget.getShowType()); } else { - imgPanel.setBackgroundImage(IOUtils.readImage("com/fr/design/images/form/designer/widget/picture_widget_designer_bg.png")); + imgPanel.setBackgroundImage(I18nImage.getImage("/com/fr/design/images/form/designer/widget/picture_widget_designer_bg.png")); imgPanel.setImageDisplayMode(0); } this.editor.add(imgPanel, "Center"); diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XTextArea.java b/designer-form/src/main/java/com/fr/design/designer/creator/XTextArea.java index 845fe43d9e..88d0391ceb 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XTextArea.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XTextArea.java @@ -6,7 +6,9 @@ package com.fr.design.designer.creator; import com.fr.base.BaseUtils; import com.fr.base.ScreenResolution; import com.fr.base.Style; +import com.fr.design.designer.properties.mobile.TextAreaMobilePropertyUI; import com.fr.design.form.util.XCreatorConstants; +import com.fr.design.fun.WidgetPropertyUIProvider; import com.fr.design.mainframe.widget.editors.RegexEditor; import com.fr.design.mainframe.widget.editors.WidgetValueEditor; import com.fr.design.mainframe.widget.renderer.RegexCellRencerer; @@ -25,8 +27,9 @@ import java.beans.IntrospectionException; /** * @author richer * @since 6.5.3 + * Created on 2016/3/29 */ -public class XTextArea extends XFieldEditor { +public class XTextArea extends XWrapperedFieldEditor { public XTextArea(TextArea widget, Dimension initSize) { super(widget, initSize); @@ -81,4 +84,10 @@ public class XTextArea extends XFieldEditor { protected String getIconName() { return "text_area_16.png"; } + + @Override + public WidgetPropertyUIProvider[] getWidgetPropertyUIProviders() { + return new WidgetPropertyUIProvider[]{new TextAreaMobilePropertyUI(this)}; + } + } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/XTextEditor.java b/designer-form/src/main/java/com/fr/design/designer/creator/XTextEditor.java index 00daae7c7d..a1aca00ed0 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/XTextEditor.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/XTextEditor.java @@ -6,7 +6,7 @@ package com.fr.design.designer.creator; import com.fr.base.BaseUtils; import com.fr.base.ScreenResolution; import com.fr.base.Style; -import com.fr.design.designer.properties.mobile.ScanCodeMobilePropertyUI; +import com.fr.design.designer.properties.mobile.TextEditorMobilePropertyUI; import com.fr.design.form.util.XCreatorConstants; import com.fr.design.fun.WidgetPropertyUIProvider; import com.fr.design.mainframe.widget.editors.RegexEditor; @@ -86,6 +86,6 @@ public class XTextEditor extends XWrapperedFieldEditor { @Override public WidgetPropertyUIProvider[] getWidgetPropertyUIProviders() { - return new WidgetPropertyUIProvider[] {new ScanCodeMobilePropertyUI(this)}; + return new WidgetPropertyUIProvider[]{new TextEditorMobilePropertyUI(this)}; } } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XCardSwitchButton.java b/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XCardSwitchButton.java index 85436c72fd..c77ac788b3 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XCardSwitchButton.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XCardSwitchButton.java @@ -10,6 +10,7 @@ import com.fr.design.designer.beans.models.SelectionModel; import com.fr.design.designer.creator.XButton; import com.fr.design.designer.creator.XCreator; import com.fr.design.designer.creator.XLayoutContainer; +import com.fr.design.designer.creator.XWAbsoluteLayout; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.file.HistoryTemplateListPane; import com.fr.design.gui.ilable.UILabel; @@ -25,16 +26,27 @@ import com.fr.form.ui.container.WTabTextDirection; import com.fr.form.ui.container.cardlayout.WCardTagLayout; import com.fr.form.ui.container.cardlayout.WTabFitLayout; import com.fr.general.Background; -import com.fr.general.act.BorderPacker; import com.fr.general.ComparatorUtils; import com.fr.general.FRFont; +import com.fr.general.act.BorderPacker; import com.fr.general.act.TitlePacker; import com.fr.general.cardtag.TemplateStyle; import com.fr.stable.unit.PT; -import javax.swing.*; +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JOptionPane; +import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; import javax.swing.plaf.basic.BasicLabelUI; -import java.awt.*; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.geom.Rectangle2D; import java.util.ArrayList; @@ -209,7 +221,7 @@ public class XCardSwitchButton extends XButton { private void deleteCard(XCardSwitchButton button, int index){ String titleName = button.getContentLabel().getText(); int value = FineJOptionPane.showConfirmDialog(null, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Confirm_Dialog_Content") + "“" + titleName + "”", - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_OPTION); + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.YES_NO_OPTION); if (value != JOptionPane.OK_OPTION) { return; } @@ -236,52 +248,43 @@ public class XCardSwitchButton extends XButton { //SwitchButton对应的XWCardLayout和XWCardTagLayout暂未存到xml中,重新打开时根据父子层关系获取 - private void initRelateLayout(){ - this.tagLayout = (XWCardTagLayout)this.getBackupParent(); + private void initRelateLayout() { + this.tagLayout = (XWCardTagLayout) this.getBackupParent(); XWCardTitleLayout titleLayout = (XWCardTitleLayout) this.tagLayout.getBackupParent(); - XWCardMainBorderLayout borderLayout = (XWCardMainBorderLayout)titleLayout.getBackupParent(); + XWCardMainBorderLayout borderLayout = (XWCardMainBorderLayout) titleLayout.getBackupParent(); this.cardLayout = borderLayout.getCardPart(); } - //是否进入点击关闭按钮区域 - private boolean isSelectedClose(MouseEvent e, FormDesigner designer){ + /** + *

    是否进入点击关闭按钮区域 + *

    计算逻辑: + *

    先得到鼠标的绝对坐标 -> tab布局的绝对坐标 -> 得到鼠标相对tab的坐标(有参数面板时要减去参数面板的高度) + *

    再计算删除区域位置的相对坐标,通过对比判定鼠标是否在点击关闭按钮区域内,即,鼠标的位置(ex,ey): + *

  • 当前点击tag删除区域的x坐标 < ex < 当前点击tag删除区域的x坐标 + 偏移量
  • + *
  • 当前点击tag删除区域的y坐标 < ey < 当前点击tag删除区域的y坐标 + 偏移量
  • + * + * @param e 鼠标事件 + * @param designer 表单编辑对象 + * @return true/false 在内/不在 + */ + private boolean isSelectedClose(MouseEvent e, FormDesigner designer) { int diff = designer.getHorizontalScaleValue(); // mouse position + // 这里是鼠标的绝对位置 int ex = e.getX() + diff; int ey = e.getY(); - - //获取tab布局的位置,鼠标相对于tab按钮的位置 - Container mainLayout = cardLayout.getBackupParent(); - Point point = mainLayout.getLocation(); - int y = 0; - int x = 0; - //遍历一下,不然是相对位置,嵌套后位置不对 - while (mainLayout.getParent() != null){ - if(mainLayout instanceof XWCardLayout){ - y += mainLayout.getY(); - } - - mainLayout = mainLayout.getParent(); - - if(mainLayout instanceof XWCardMainBorderLayout){ - x += mainLayout.getX(); - y += mainLayout.getY(); - } - } - double mainX = point.getX() + x; - double mainY = point.getY() + y; - + // 获取tab布局的位置,鼠标相对于tab按钮的位置 + double[] tabPositionInBody = getTabAbsolutePositionInBody(); // 参数界面对坐标的影响 JForm jform = (JForm) HistoryTemplateListPane.getInstance().getCurrentEditingTemplate(); - if(jform.getFormDesign().getParaComponent() != null){ + if (jform.getFormDesign().getParaComponent() != null) { ey -= jform.getFormDesign().getParaHeight(); } - //减掉tab布局的相对位置 - ex -= mainX; - ey -= mainY; + ex -= tabPositionInBody[0]; + ey -= tabPositionInBody[1]; XLayoutContainer titleLayout = tagLayout.getBackupParent(); Point titlePoint = titleLayout.getLocation(); @@ -291,10 +294,43 @@ public class XCardSwitchButton extends XButton { int width = button.getWidth(); // 鼠标进入按钮右侧删除图标区域 - double recX = position.getX() + titlePoint.getX() + (width - CLOSE_ICON_RIGHT_OFFSET); + double recX = position.getX() + titlePoint.getX() + (width - CLOSE_ICON_RIGHT_OFFSET); double recY = position.getY() + titlePoint.getY() + CLOSE_ICON_TOP_OFFSET; + // 比较的是相对位置的偏移量是否在一定距离内 + // 所以要得到鼠标相对于当前tab块的坐标 + return (recX < ex && ex < recX + CLOSE_ICON_RIGHT_OFFSET && ey < recY && ey > position.getY()); + } + + /** + * 获取tab布局在body内的绝对位置 + * + * @return + */ + private double[] getTabAbsolutePositionInBody() { + // 获取tab布局的位置,鼠标相对于tab按钮的位置 + Container mainLayout = cardLayout.getBackupParent(); + // 这个point是当前tab布局的相对坐标,是相对于父容器的坐标 + // 比如父级是一个absolute块,放在左上角,现在得到的point就是(0,0) + Point point = mainLayout.getLocation(); + int y = 0; + int x = 0; + // 遍历一下,不然是相对位置,嵌套后位置不对 + // 这里是要得到tab布局的绝对位置,所以要加上父组件的位置 + while (mainLayout.getParent() != null) { + if (mainLayout instanceof XWCardLayout) { + y += mainLayout.getY(); + } + + mainLayout = mainLayout.getParent(); - return (recX < ex && ex < recX + CLOSE_ICON_RIGHT_OFFSET && ey < recY && ey > position.getY()); + if ((mainLayout instanceof XWCardMainBorderLayout) || (mainLayout instanceof XWAbsoluteLayout)) { + x += mainLayout.getX(); + y += mainLayout.getY(); + } + } + double mainX = point.getX() + x; + double mainY = point.getY() + y; + return new double[]{mainX, mainY}; } //将当前switchButton改为选中状态 @@ -306,7 +342,7 @@ public class XCardSwitchButton extends XButton { } } - @Override + @Override public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; @@ -366,7 +402,7 @@ public class XCardSwitchButton extends XButton { private void deleteTabLayout(SelectionModel selectionModel, FormDesigner designer){ String titleName = this.getContentLabel().getText(); int value = FineJOptionPane.showConfirmDialog(null, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Confirm_Dialog_Content") + "“" + titleName + "”", - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_OPTION); + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.YES_NO_OPTION); if (value != JOptionPane.OK_OPTION) { return; } diff --git a/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTagLayout.java b/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTagLayout.java index 0353d53dd0..7ded6ee77e 100644 --- a/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTagLayout.java +++ b/designer-form/src/main/java/com/fr/design/designer/creator/cardlayout/XWCardTagLayout.java @@ -24,21 +24,25 @@ import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.imenu.UIPopupMenu; import com.fr.design.mainframe.EditingMouseListener; import com.fr.design.mainframe.FormDesigner; +import com.fr.design.mainframe.FormHierarchyTreePane; import com.fr.design.mainframe.WidgetPropertyPane; +import com.fr.design.utils.gui.LayoutUtils; import com.fr.form.ui.CardSwitchButton; import com.fr.form.ui.Widget; import com.fr.form.ui.container.WCardLayout; import com.fr.form.ui.container.WTabDisplayPosition; import com.fr.form.ui.container.cardlayout.WCardTagLayout; import com.fr.form.ui.container.cardlayout.WTabFitLayout; -import com.fr.general.act.BorderPacker; import com.fr.general.ComparatorUtils; import com.fr.general.FRFont; +import com.fr.general.act.BorderPacker; import com.fr.general.cardtag.DefaultTemplateStyle; import com.fr.stable.StringUtils; import javax.swing.border.Border; -import java.awt.*; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Rectangle; import java.awt.event.ContainerEvent; import java.awt.event.MouseEvent; import java.util.HashMap; @@ -434,7 +438,7 @@ public class XWCardTagLayout extends XWHorizontalBoxLayout { } - private void fixTitleLayout(XLayoutContainer parent){ + private void fixTitleLayout(XLayoutContainer parent) { FormDesigner formDesigner = WidgetPropertyPane.getInstance().getEditingFormDesigner(); LayoutAdapter layoutAdapter = AdapterBus.searchLayoutAdapter(formDesigner, parent); if (layoutAdapter != null) { @@ -443,4 +447,31 @@ public class XWCardTagLayout extends XWHorizontalBoxLayout { } } + /** + *

    对于tab组件,WCardMainBorderLayout里面有两个子容器: + *

  • WCardTitleLayout,里面包含两个部分,一个是CardAddButton,另一个是WCardTagLayout - tabpane0
  • + *
  • WCardLayout,里面放的是WTabFitLayout - tab00、tab10
  • + *

    在右侧组件树选择删除WCardTagLayout时(tabpane0),按照现在的产品逻辑,应该删除整个tab组件 + * + * @param creator 组件 + * @param designer 表单设计器 + */ + @Override + public void deleteRelatedComponent(XCreator creator, FormDesigner designer) { + XWCardTagLayout tagLayout = (XWCardTagLayout) creator; + // 先删除所有tab按钮 + tagLayout.removeAll(); + //逐层回溯找出最外层的XWCardMainBorderLayout + XWCardTitleLayout cardTitleLayout = (XWCardTitleLayout) tagLayout.getBackupParent(); + XWCardMainBorderLayout mainLayout = (XWCardMainBorderLayout) cardTitleLayout.getBackupParent(); + // 删除tab布局 + SelectionModel selectionModel = designer.getSelectionModel(); + if (mainLayout != null) { + selectionModel.setSelectedCreator(mainLayout); + selectionModel.deleteSelection(); + } + LayoutUtils.layoutRootContainer(designer.getRootComponent()); + FormHierarchyTreePane.getInstance().refreshRoot(); + selectionModel.setSelectedCreator(designer.getRootComponent()); + } } diff --git a/designer-form/src/main/java/com/fr/design/designer/properties/mobile/NumberEditorMobilePropertyUI.java b/designer-form/src/main/java/com/fr/design/designer/properties/mobile/NumberEditorMobilePropertyUI.java new file mode 100644 index 0000000000..67a8569f72 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/designer/properties/mobile/NumberEditorMobilePropertyUI.java @@ -0,0 +1,37 @@ +package com.fr.design.designer.properties.mobile; + +import com.fr.design.designer.creator.XCreator; +import com.fr.design.dialog.BasicPane; +import com.fr.design.fun.impl.AbstractWidgetPropertyUIProvider; +import com.fr.design.gui.itable.AbstractPropertyTable; +import com.fr.design.widget.ui.designer.mobile.NumberEditorMobileDefinePane; + +/** + * 数字控件属性面板注册 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/3/30 + */ +public class NumberEditorMobilePropertyUI extends AbstractWidgetPropertyUIProvider { + private XCreator xCreator; + + public NumberEditorMobilePropertyUI(XCreator xCreator) { + this.xCreator = xCreator; + } + + @Override + public AbstractPropertyTable createWidgetAttrTable() { + return null; + } + + @Override + public BasicPane createWidgetAttrPane() { + return new NumberEditorMobileDefinePane(xCreator); + } + + @Override + public String tableTitle() { + return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Mobile_Attr"); + } +} \ No newline at end of file diff --git a/designer-form/src/main/java/com/fr/design/designer/properties/mobile/PasswordMobilePropertyUI.java b/designer-form/src/main/java/com/fr/design/designer/properties/mobile/PasswordMobilePropertyUI.java new file mode 100644 index 0000000000..2c3b3b2270 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/designer/properties/mobile/PasswordMobilePropertyUI.java @@ -0,0 +1,37 @@ +package com.fr.design.designer.properties.mobile; + +import com.fr.design.designer.creator.XCreator; +import com.fr.design.dialog.BasicPane; +import com.fr.design.fun.impl.AbstractWidgetPropertyUIProvider; +import com.fr.design.gui.itable.AbstractPropertyTable; +import com.fr.design.widget.ui.designer.mobile.PasswordMobileDefinePane; + +/** + * 密码控件移动端属性注册 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/3/30 + */ +public class PasswordMobilePropertyUI extends AbstractWidgetPropertyUIProvider { + private XCreator xCreator; + + public PasswordMobilePropertyUI(XCreator xCreator) { + this.xCreator = xCreator; + } + + @Override + public AbstractPropertyTable createWidgetAttrTable() { + return null; + } + + @Override + public BasicPane createWidgetAttrPane() { + return new PasswordMobileDefinePane(xCreator); + } + + @Override + public String tableTitle() { + return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Mobile_Attr"); + } +} \ No newline at end of file diff --git a/designer-form/src/main/java/com/fr/design/designer/properties/mobile/TextAreaMobilePropertyUI.java b/designer-form/src/main/java/com/fr/design/designer/properties/mobile/TextAreaMobilePropertyUI.java new file mode 100644 index 0000000000..1c24e06bce --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/designer/properties/mobile/TextAreaMobilePropertyUI.java @@ -0,0 +1,37 @@ +package com.fr.design.designer.properties.mobile; + +import com.fr.design.designer.creator.XCreator; +import com.fr.design.dialog.BasicPane; +import com.fr.design.fun.impl.AbstractWidgetPropertyUIProvider; +import com.fr.design.gui.itable.AbstractPropertyTable; +import com.fr.design.widget.ui.designer.mobile.TextAreaAdvancedDefinePane; + +/** + * 文本域控件移动端属性 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/3/29 + */ +public class TextAreaMobilePropertyUI extends AbstractWidgetPropertyUIProvider { + private XCreator xCreator; + + public TextAreaMobilePropertyUI(XCreator xCreator) { + this.xCreator = xCreator; + } + + @Override + public AbstractPropertyTable createWidgetAttrTable() { + return null; + } + + @Override + public BasicPane createWidgetAttrPane() { + return new TextAreaAdvancedDefinePane(xCreator); + } + + @Override + public String tableTitle() { + return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Mobile_Attr"); + } +} \ No newline at end of file diff --git a/designer-form/src/main/java/com/fr/design/designer/properties/mobile/ScanCodeMobilePropertyUI.java b/designer-form/src/main/java/com/fr/design/designer/properties/mobile/TextEditorMobilePropertyUI.java similarity index 65% rename from designer-form/src/main/java/com/fr/design/designer/properties/mobile/ScanCodeMobilePropertyUI.java rename to designer-form/src/main/java/com/fr/design/designer/properties/mobile/TextEditorMobilePropertyUI.java index 85011ee2b9..531e2c4fc8 100644 --- a/designer-form/src/main/java/com/fr/design/designer/properties/mobile/ScanCodeMobilePropertyUI.java +++ b/designer-form/src/main/java/com/fr/design/designer/properties/mobile/TextEditorMobilePropertyUI.java @@ -5,13 +5,20 @@ import com.fr.design.designer.creator.XTextEditor; import com.fr.design.dialog.BasicPane; import com.fr.design.fun.impl.AbstractWidgetPropertyUIProvider; import com.fr.design.gui.itable.AbstractPropertyTable; -import com.fr.design.widget.ui.designer.mobile.ScanCodeMobileDefinePane; +import com.fr.design.widget.ui.designer.mobile.TextEditorMobileDefinePane; -public class ScanCodeMobilePropertyUI extends AbstractWidgetPropertyUIProvider { +/** + * 文本控件 + * + * @author Coral.Chen + * @since 11.0 + * Created on 2023/3/30 + */ +public class TextEditorMobilePropertyUI extends AbstractWidgetPropertyUIProvider { private XCreator xCreator; - public ScanCodeMobilePropertyUI(XTextEditor xTextEditor) { + public TextEditorMobilePropertyUI(XTextEditor xTextEditor) { this.xCreator = xTextEditor; } @@ -22,7 +29,7 @@ public class ScanCodeMobilePropertyUI extends AbstractWidgetPropertyUIProvider { @Override public BasicPane createWidgetAttrPane() { - return new ScanCodeMobileDefinePane(xCreator); + return new TextEditorMobileDefinePane(xCreator); } @Override diff --git a/designer-form/src/main/java/com/fr/design/fit/toolbar/SwitchAction.java b/designer-form/src/main/java/com/fr/design/fit/toolbar/SwitchAction.java index 3afe612537..bdda0b4db2 100644 --- a/designer-form/src/main/java/com/fr/design/fit/toolbar/SwitchAction.java +++ b/designer-form/src/main/java/com/fr/design/fit/toolbar/SwitchAction.java @@ -233,7 +233,7 @@ public class SwitchAction extends UpdateAction { int returnVal = FineJOptionPane.showConfirmDialog( DesignerContext.getDesignerFrame(), message, - Toolkit.i18nText("Fine-Design_Basic_Confirm"), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), YES_NO_OPTION); return returnVal == JOptionPane.YES_OPTION; } @@ -249,7 +249,7 @@ public class SwitchAction extends UpdateAction { int returnVal = FineJOptionPane.showConfirmDialog( DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Designer_Fit_Cover_File_Switch"), - Toolkit.i18nText("Fine-Design_Basic_Confirm"), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), YES_NO_OPTION); return returnVal == JOptionPane.YES_OPTION; } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java b/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java index 0555cf1723..801a342197 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/EditingMouseListener.java @@ -279,9 +279,7 @@ public class EditingMouseListener extends MouseInputAdapter { if (component instanceof XEditorHolder) { XEditorHolder xcreator = (XEditorHolder) component; Rectangle rect = xcreator.getBounds(); - int min = rect.x + rect.width / 2 - minMoveSize; - int max = rect.x + rect.width / 2 + minMoveSize; - if (e.getX() > min && e.getX() < max) { + if (checkCreatorRangeValid(e, rect)) { if (designer.getCursor().getType() != Cursor.HAND_CURSOR) { designer.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } @@ -673,8 +671,8 @@ public class EditingMouseListener extends MouseInputAdapter { currentEditor = designerEditor; currentXCreator = creator; Rectangle bounds = new Rectangle(1, 1, creator.getWidth() - 2, creator.getHeight() - 2); - bounds.x += (rect.x - designer.getArea().getHorizontalValue()); - bounds.y += (rect.y - designer.getArea().getVerticalValue()); + bounds.x += (rect.x - designer.getHorizontalScaleValue()); + bounds.y += (rect.y - designer.getVerticalScaleValue()); designerEditor.getEditorTarget().setBounds(bounds); designer.add(designerEditor.getEditorTarget()); designer.invalidate(); @@ -747,4 +745,19 @@ public class EditingMouseListener extends MouseInputAdapter { refreshTopXCreator(false); } + /** + * 判断当前鼠标移动事件是否在Creator有效范围内 + */ + private boolean checkCreatorRangeValid(MouseEvent e, Rectangle rect) { + int horizontalValue = designer.getHorizontalScaleValue(); + int verticalValue = designer.getVerticalScaleValue(); + + int minHorizontal = rect.x + rect.width / 2 - minMoveSize - horizontalValue; + int maxHorizontal = rect.x + rect.width / 2 + minMoveSize - horizontalValue; + int minVertical = rect.y + rect.height / 2 - minMoveSize - verticalValue; + int maxVertical = rect.y + rect.height / 2 + minMoveSize - verticalValue; + boolean xRangeValid = e.getX() > minHorizontal && e.getX() < maxHorizontal; + boolean yRangeValid = e.getY() > minVertical && e.getY() < maxVertical; + return xRangeValid && yRangeValid; + } } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormArea.java b/designer-form/src/main/java/com/fr/design/mainframe/FormArea.java index e515dd1f35..94886f9d46 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormArea.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormArea.java @@ -8,11 +8,11 @@ import com.fr.design.designer.creator.XCreatorUtils; import com.fr.design.designer.creator.XLayoutContainer; import com.fr.design.designer.creator.XWBorderLayout; import com.fr.design.designer.creator.XWFitLayout; +import com.fr.design.designer.creator.XWParameterLayout; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ibutton.UIButtonUI; import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.imenu.UIPopupMenu; -import com.fr.design.designer.creator.XWParameterLayout; import com.fr.design.gui.itextfield.UINumberField; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; @@ -540,21 +540,26 @@ public class FormArea extends JComponent implements ScrollRulerComponent { } //获取在容器的绝对位置 Rectangle rec = ComponentUtils.getRelativeBounds(creator); + // 组件实际大小、位置要考虑缩放 int dWidth = getDesignerWidth(); - if (rec.width <= dWidth && rec.x < getHorizontalValue()) { + double recRealWidth = rec.width * designer.getScale(); + double recRealX = rec.x * designer.getScale(); + if (recRealWidth <= dWidth && recRealX < getHorizontalValue()) { //在边界内部且x位置小于水平滚动条的值 - horScrollBar.setValue(rec.x); - } else if (rec.x + rec.width > dWidth + horizontalValue) { + horScrollBar.setValue((int) recRealX); + } else if (recRealX + recRealWidth > dWidth + horizontalValue) { //超出边界宽度 - horScrollBar.setValue(rec.x + rec.width - dWidth); + horScrollBar.setValue((int) (recRealX + recRealWidth - dWidth)); } int dHeight = getDesignerHeight(); - if (rec.height < dHeight && rec.y < getVerticalValue()) { + double recRealHeight = rec.height * designer.getScale(); + double recRealY = rec.y * designer.getScale(); + if (recRealHeight < dHeight && recRealY < getVerticalValue()) { //在边界内部且y位置小于竖直滚动条的值 - verScrollBar.setValue(rec.y); - } else if (rec.y + rec.height > dHeight + verticalValue) { + verScrollBar.setValue((int) recRealY); + } else if (recRealY + recRealHeight > dHeight + verticalValue) { //超出边界高度 - verScrollBar.setValue(rec.y + rec.height - dHeight); + verScrollBar.setValue((int) (recRealY + recRealHeight - dHeight)); } } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java index 27f6237269..09ef0c4cf3 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormDesigner.java @@ -1207,7 +1207,7 @@ public class FormDesigner extends TargetComponent

    implements TreeSelection } public XLayoutContainer getRootContainer(int y) { - XLayoutContainer container = y < paraHeight - formArea.getVerticalValue() ? paraComponent : rootComponent; + XLayoutContainer container = y < paraHeight - formArea.getVerticalValue() / scale ? paraComponent : rootComponent; if (container == null) { container = rootComponent; } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormEditToolBar.java b/designer-form/src/main/java/com/fr/design/mainframe/FormEditToolBar.java index b5fac75e5a..295aae7c9c 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormEditToolBar.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormEditToolBar.java @@ -289,7 +289,7 @@ public class FormEditToolBar extends BasicPane { return; } int val = FineJOptionPane.showConfirmDialog(FormEditToolBar.this, com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Are_You_Sure_To_Delete_The_Data") + "?", - com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_OPTION); + com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), JOptionPane.YES_NO_OPTION); if (val != JOptionPane.YES_OPTION) { return; } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/group/ui/GroupFileDialog.java b/designer-form/src/main/java/com/fr/design/mainframe/share/group/ui/GroupFileDialog.java index f4b79944ea..9979e2d9cd 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/group/ui/GroupFileDialog.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/group/ui/GroupFileDialog.java @@ -123,6 +123,7 @@ abstract public class GroupFileDialog extends BaseGroupDialog { private UILabel creteNewNameLabel() { // 输入框前提示 UILabel newNameLabel = new UILabel(Toolkit.i18nText("Fine-Design_Share_Group_Enter_New_Folder_Name")); + newNameLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Share_Group_Enter_New_Folder_Name")); newNameLabel.setHorizontalAlignment(SwingConstants.RIGHT); newNameLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10)); newNameLabel.setPreferredSize(new Dimension(84, 16)); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/actions/DownloadSuitableThemeAction.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/actions/DownloadSuitableThemeAction.java index 97e6d94013..cf5581cf8d 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/actions/DownloadSuitableThemeAction.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/actions/DownloadSuitableThemeAction.java @@ -209,7 +209,7 @@ public class DownloadSuitableThemeAction extends SharedComponentPopupAction { int returnVal = FineJOptionPane.showConfirmDialog( window, Toolkit.i18nText("Fine-Design_Share_Apply_Suitable_Theme_Tip"), - Toolkit.i18nText("Fine-Design_Basic_Confirm"), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), FineJOptionPane.OK_CANCEL_OPTION); if (returnVal == JOptionPane.YES_OPTION) { applyTheme(currentTemplate, theme.getName(), window); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/actions/Jump2DetailAction.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/actions/Jump2DetailAction.java index 9df0313820..b4d546727b 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/actions/Jump2DetailAction.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/actions/Jump2DetailAction.java @@ -1,17 +1,11 @@ package com.fr.design.mainframe.share.ui.actions; -import com.fr.design.actions.UpdateAction; -import com.fr.design.gui.imenu.UIMenuItem; -import com.fr.design.gui.imenu.UIMenuItemUI; +import com.fr.design.i18n.LocaleLinkProvider; import com.fr.design.i18n.Toolkit; -import com.fr.design.mainframe.share.ui.constants.ColorConstants; import com.fr.design.mainframe.share.ui.online.CarouselStateManger; import com.fr.stable.StringUtils; import javax.swing.Action; -import javax.swing.BorderFactory; -import javax.swing.SwingConstants; -import java.awt.Color; import java.awt.Desktop; import java.awt.event.ActionEvent; import java.io.IOException; @@ -24,7 +18,18 @@ import java.net.URISyntaxException; * Created by Starryi on 2021/9/28 */ public class Jump2DetailAction extends SharedComponentPopupAction { - private static final String ONLINE_WIDGET_DETAIL_FORMATTED_URL = "https://market.fanruan.com/reuse/%s"; + + /** + * 云中心组件市场组件详情在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Market_Detail"; + + /** + * 云中心组件市场组件详情默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Market_Detail_Default"; + + private static final String ONLINE_WIDGET_DETAIL_FORMATTED_URL = LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); private final String id; public Jump2DetailAction(String id) { 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 b4d3bcc68d..e7b60ce926 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 @@ -2,35 +2,30 @@ 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.LocaleLinkProvider; 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; @@ -47,7 +42,18 @@ import java.util.concurrent.ExecutionException; * Created by kerry on 2020-10-16 */ public class OnlineWidgetRepoPane extends BasicPane { - private static final String MARKET_URL = "https://market.fanruan.com/reuse"; + + /** + * 云中心组件市场在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY = "Fine-Design-CloudCenter_Market"; + + /** + * 云中心组件市场默认链接在配置文件中对应的配置文件key + */ + private static final String PROPS_LINK_KEY_DEFAULT = "Fine-Design-CloudCenter_Market_Default"; + + private static final String MARKET_URL = LocaleLinkProvider.getInstance().getLink(PROPS_LINK_KEY, PROPS_LINK_KEY_DEFAULT); private static List[] sharableWidgets; private OnlineWidgetTabPane componentTabPane; private boolean isShowPackagePanel = false; 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 index 4de568db7f..85ed94ee19 100644 --- 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 @@ -199,7 +199,7 @@ public class TemplateThemeInstallation extends AsyncInstallation { int returnVal = FineJOptionPane.showConfirmDialog( window, Toolkit.i18nText("Fine-Design_Share_Apply_Suitable_Theme_Tip"), - Toolkit.i18nText("Fine-Design_Basic_Confirm"), + Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), FineJOptionPane.OK_CANCEL_OPTION); if (returnVal == JOptionPane.YES_OPTION) { applyTheme(currentFormTemplate, theme.getName(), window); 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 index f9d3849f78..ccd13cc4a4 100644 --- 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 @@ -1,19 +1,12 @@ package com.fr.design.mainframe.share.ui.online.mini; +import com.fr.design.jxbrowser.JxUIPane; 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.ui.compatible.ModernUIPaneFactory; 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.browser.callback.InjectJsCallback; -import com.teamdev.jxbrowser.chromium.JSObject; -import com.teamdev.jxbrowser.chromium.events.ScriptContextAdapter; -import com.teamdev.jxbrowser.chromium.events.ScriptContextEvent; -import com.teamdev.jxbrowser.js.JsObject; -import org.jetbrains.annotations.Nullable; import javax.swing.JPanel; import java.awt.BorderLayout; @@ -24,34 +17,16 @@ import java.awt.BorderLayout; * Created by Starryi on 2021/12/20 */ public class MiniComponentShopPane extends JPanel { - private final ModernUIPane modernUIPane; + private static final String SHOP_HELPER = "ShopHelper"; + private final JxUIPane modernUIPane; private final Listener loginListener; private final Listener logoutListener; public MiniComponentShopPane() { setLayout(new BorderLayout()); - modernUIPane = ModernUIPaneFactory.modernUIPaneBuilder() + modernUIPane = new JxUIPane.Builder<>() .withURL(OnlineShopUtils.getWebMiniShopPath()) - .prepareForV6(new ScriptContextAdapter() { - @Override - public void onScriptContextCreated(ScriptContextEvent event) { - super.onScriptContextCreated(event); - JSObject window = event.getBrowser().executeJavaScriptAndReturnValue("window").asObject(); - window.setProperty("ShopHelper", new ComposedNativeBridges(window)); - } - }) - .prepareForV7(new InjectJsCallback() { - @Nullable - @Override - public Response on(Params params) { - // 7.x - JsObject window = params.frame().executeJavaScript("window"); - if (window != null) { - window.putProperty("ShopHelper", new ComposedNativeBridges(window)); - } - return InjectJsCallback.Response.proceed(); - } - }) + .bindWindow(SHOP_HELPER, ComposedNativeBridges::new) .build(); add(modernUIPane, BorderLayout.CENTER); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/widgetpackage/OnlineWidgetPackagesShowPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/widgetpackage/OnlineWidgetPackagesShowPane.java index d133cd0583..8a52051276 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/widgetpackage/OnlineWidgetPackagesShowPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/online/widgetpackage/OnlineWidgetPackagesShowPane.java @@ -82,7 +82,7 @@ public class OnlineWidgetPackagesShowPane extends AbstractOnlineWidgetShowPane { + Toolkit.i18nText("Fine-Design_Share_Total") + onlineWidgetSelectPane.getSharableWidgetNum() + Toolkit.i18nText("Fine-Design_Share_Piece"); - int returnValue = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), message, Toolkit.i18nText("Fine-Design_Basic_Confirm"), FineJOptionPane.YES_NO_OPTION); + int returnValue = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), message, Toolkit.i18nText("Fine-Design_Basic_Dialog_Prompt"), FineJOptionPane.YES_NO_OPTION); if (returnValue == FineJOptionPane.OK_OPTION && onlineWidgetSelectPane.getSharableWidgetNum() != 0) { downLoadPackage(); } diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/widgetfilter/FilterConfigPane.java b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/widgetfilter/FilterConfigPane.java index 8808a5d754..1a88ae1502 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/ui/widgetfilter/FilterConfigPane.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/ui/widgetfilter/FilterConfigPane.java @@ -149,6 +149,7 @@ public abstract class FilterConfigPane extends JPanel { private FilterCheckBox createCheckBox(WidgetFilterInfo filterInfo) { final FilterCheckBox checkBox = new FilterCheckBox(filterInfo.getName(), filterInfo); + checkBox.setToolTipText(filterInfo.getName()); checkBox.setBackground(Color.WHITE); checkBox.addItemListener(new ItemListener() { @Override diff --git a/designer-form/src/main/java/com/fr/design/mainframe/share/util/DownloadUtils.java b/designer-form/src/main/java/com/fr/design/mainframe/share/util/DownloadUtils.java index f1db4744fb..6775a17310 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/share/util/DownloadUtils.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/share/util/DownloadUtils.java @@ -3,6 +3,7 @@ package com.fr.design.mainframe.share.util; import com.fr.base.theme.FormTheme; import com.fr.design.DesignerEnvManager; import com.fr.design.extra.PluginConstants; +import com.fr.design.login.config.DefaultLoginKeys; import com.fr.form.share.base.CancelCheck; import com.fr.form.share.constants.ShareComponentConstants; import com.fr.ftp.util.Base64; @@ -45,10 +46,7 @@ import java.util.Set; * created by Harrison on 2020/05/27 **/ public class DownloadUtils { - private static final String CERTIFICATE_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtsz62CPSWXZE/IYZRiAuTSZkw\n" + - "1WOwer8+JFktK0uKLAUuQoBr+UjAMFtRA8W7JgKMDwZy/2liEAiXEOSPU/hrdV8D\n" + - "tT541LnGi1X/hXiRwuttPWYN3L2GYm/d5blU+FBNwghBIrdAxXTzYBc6P4KL/oYX\n" + - "nMdTIrkz8tYkG3QoFQIDAQAB"; + private static final String CERTIFICATE_PUBLIC_KEY = DefaultLoginKeys.getInstance().getKey("Fine-Designer_Reu_Share_CERTIFICATE_PUBLIC_KEY"); private static String getReusesUrl() { return StableUtils.pathJoin(OnlineShopUtils.getReuInfoPath(), "file/download"); diff --git a/designer-form/src/main/java/com/fr/design/parameter/RootDesignDefinePane.java b/designer-form/src/main/java/com/fr/design/parameter/RootDesignDefinePane.java index 86e3f49986..946303386b 100644 --- a/designer-form/src/main/java/com/fr/design/parameter/RootDesignDefinePane.java +++ b/designer-form/src/main/java/com/fr/design/parameter/RootDesignDefinePane.java @@ -28,6 +28,7 @@ import com.fr.design.mainframe.FormDesigner; import com.fr.design.mainframe.FormSelection; import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.widget.accessibles.AccessibleBackgroundEditor; +import com.fr.design.widgettheme.processor.WidgetThemeParaCreatorPaneAdder; import com.fr.design.utils.gui.LayoutUtils; import com.fr.design.utils.gui.UIComponentUtils; import com.fr.design.widget.ui.designer.AbstractDataModify; @@ -203,6 +204,7 @@ public class RootDesignDefinePane extends AbstractDataModify { private void refreshExtraAdvancedPane() { extraPaneList.clear(); backgroundPane.removeAll(); + WidgetThemeParaCreatorPaneAdder.add(creator, extraPaneList); Set> providers = ExtraDesignClassManager.getInstance().getArray(WidgetAdvancedPaneProvider.XML_TAG); for (WidgetAdvancedPaneProvider provider : providers) { if (!provider.accept(creator)) { @@ -368,12 +370,11 @@ public class RootDesignDefinePane extends AbstractDataModify { wParameterLayout.setParamsFireStopEdit(fireAfterEditor.isSelected()); JTemplate jTemplate = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate(); jTemplate.needAddTemplateIdAttr(useParamsTemplate.isSelected()); - wParameterLayout.setBackground((Background) background.getValue()); if (extraPaneList.isEmpty()) { - background.setValue(wParameterLayout.getBackground()); + wParameterLayout.setBackground((Background) background.getValue()); } else { for (BasicBeanPane pane : extraPaneList) { - pane.populateBean(wParameterLayout); + pane.updateBean(wParameterLayout); } } //设置参数模板面板的高度 diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/btn/AbstractExtraButtonPane.java b/designer-form/src/main/java/com/fr/design/widget/ui/btn/AbstractExtraButtonPane.java new file mode 100644 index 0000000000..79a71d56e0 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/widget/ui/btn/AbstractExtraButtonPane.java @@ -0,0 +1,129 @@ +package com.fr.design.widget.ui.btn; + +import com.fr.design.ExtraDesignClassManager; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.dialog.BasicPane; +import com.fr.design.fun.WidgetAdvancedPaneProvider; +import com.fr.design.gui.icombobox.DictionaryComboBox; +import com.fr.design.layout.FRGUIPaneFactory; +import com.fr.design.layout.TableLayout; +import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.widgettheme.processor.WidgetThemeCreatorPaneAdder; +import com.fr.design.widget.btn.ButtonWithHotkeysDetailPane; +import com.fr.form.ui.Button; +import com.fr.general.GeneralContext; +import com.fr.plugin.observer.PluginEvent; +import com.fr.plugin.observer.PluginEventListener; +import com.fr.stable.collections.CollectionUtils; +import org.jetbrains.annotations.Nullable; + +import javax.swing.JPanel; +import java.awt.Component; +import java.util.Set; + + + +/** + * 用来处理额外的按钮属性 + * + * @author John.Ying + * @since 11.0 + * Created on 2023/4/19 + */ +public abstract class AbstractExtraButtonPane extends ButtonWithHotkeysDetailPane { + protected JPanel extraPane; + protected boolean containsExtraPane; + protected static double F = TableLayout.FILL; + protected static double P = TableLayout.PREFERRED; + + protected void initExtraPane() { + initPluginListener(); + refreshExtraAdvancedPane(classType()); + } + + + /** + * 根据按钮类别判断需要返回什么类型的属性界面 + */ + protected void refreshExtraAdvancedPane(Class cls) { + extraPaneList.clear(); + WidgetThemeCreatorPaneAdder.add(cls, extraPaneList); + boolean containsExtraPane = !CollectionUtils.isEmpty(extraPaneList); + Set> providers = ExtraDesignClassManager.getInstance().getArray(WidgetAdvancedPaneProvider.XML_TAG); + for (WidgetAdvancedPaneProvider provider : providers) { + if (!provider.accept(cls)) { + continue; + } + insertShortCut(provider.getInsertPosition(extraPaneList.size()), provider.createExtraAdvancedPane()); + containsExtraPane = true; + } + if (containsExtraPane) { + extraPane = FRGUIPaneFactory.createYBoxEmptyBorderPane(); + for (BasicBeanPane pane : extraPaneList) { + extraPane.add(pane); + } + } + this.containsExtraPane = containsExtraPane; + + } + + protected void initPluginListener() { + GeneralContext.listenPluginRunningChanged(new PluginEventListener() { + @Override + public void on(PluginEvent event) { + refreshExtraAdvancedPane(classType()); + } + }, pluginContext -> pluginContext.getRuntime().contain(WidgetAdvancedPaneProvider.XML_TAG)); + } + + /** + * 插入配置项面板 + * + * @param index 插入的位置 + * @param pane 配置项面板 + */ + protected void insertShortCut(int index, BasicBeanPane pane) { + int size = extraPaneList.size(); + index = Math.min(index, size); + extraPaneList.add(index, pane); + } + + @Override + public void populate(T button) { + super.populate(button); + for (BasicBeanPane pane : extraPaneList) { + pane.populateBean(button); + } + } + + @Override + public T update() { + T button = super.update(); + for (BasicBeanPane pane : extraPaneList) { + pane.updateBean(button); + } + return button; + } + + + @Override + protected DictionaryComboBox createCustomButtonTypeComboBox() { + return createButtonTypeComboBox(containsExtraPane); + } + + /** + * 生成额外的属性界面 + */ + protected Component createExtraPane(@Nullable BasicPane pane) { + initExtraPane(); + Component[][] components = new Component[][]{ + new Component[]{pane, null}, + new Component[]{extraPane, null} + }; + double[] rowSize = {P, P}; + double[] columnSize = {P, F}; + int[][] rowCount = {{1, 1},{1, 1}}; + return TableLayoutHelper.createGapTableLayoutPane(components, rowSize, columnSize, rowCount, 10, 7); + } + +} diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/btn/FormSubmitButtonDetailPane.java b/designer-form/src/main/java/com/fr/design/widget/ui/btn/FormSubmitButtonDetailPane.java index acc2e76c4e..77a735df54 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/btn/FormSubmitButtonDetailPane.java +++ b/designer-form/src/main/java/com/fr/design/widget/ui/btn/FormSubmitButtonDetailPane.java @@ -1,22 +1,21 @@ package com.fr.design.widget.ui.btn; import com.fr.form.parameter.FormSubmitButton; -import com.fr.design.widget.btn.ButtonWithHotkeysDetailPane; import java.awt.*; /** - * Created by IntelliJ IDEA. - * Author : Richer - * Version: 6.5.6 - * Date : 11-11-15 - * Time : 下午6:25 + * 提交参数按钮 + * + * @author John.Ying + * @since 11.0 + * Created on 2023/4/19 */ -public class FormSubmitButtonDetailPane extends ButtonWithHotkeysDetailPane { +public class FormSubmitButtonDetailPane extends AbstractExtraButtonPane { @Override protected Component createCenterPane() { - return null; + return createExtraPane(null); } @Override @@ -37,4 +36,5 @@ public class FormSubmitButtonDetailPane extends ButtonWithHotkeysDetailPane extends AbstractDataMod protected UITextField labelNameTextField; private final List> extraPaneList = new ArrayList<>(); private JPanel extraPane; + protected boolean containsExtraPane; public ButtonDefinePane(XCreator creator){ super(creator); @@ -63,7 +66,8 @@ public abstract class ButtonDefinePane extends AbstractDataMod private void refreshAdvancedPane() { extraPaneList.clear(); - boolean containsExtraPane = false; + WidgetThemeParaCreatorPaneAdder.add(creator, extraPaneList); + containsExtraPane = CollectionUtils.isNotEmpty(extraPaneList); Set> providers = ExtraDesignClassManager.getInstance().getArray(WidgetAdvancedPaneProvider.XML_TAG); for (WidgetAdvancedPaneProvider provider : providers) { if (!provider.accept(creator)) { diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/designer/CheckBoxDefinePane.java b/designer-form/src/main/java/com/fr/design/widget/ui/designer/CheckBoxDefinePane.java index 7768402914..d73582df7b 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/designer/CheckBoxDefinePane.java +++ b/designer-form/src/main/java/com/fr/design/widget/ui/designer/CheckBoxDefinePane.java @@ -1,5 +1,6 @@ package com.fr.design.widget.ui.designer; +import com.finebi.cbb.utils.CollectionUtils; import com.fr.design.ExtraDesignClassManager; import com.fr.design.beans.BasicBeanPane; import com.fr.design.designer.IntervalConstants; @@ -11,7 +12,8 @@ import com.fr.design.gui.itextfield.UITextField; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; -import com.fr.design.widget.ui.designer.component.FontSizeComboPane; +import com.fr.design.widgettheme.processor.WidgetThemeParaCreatorPaneAdder; +import com.fr.design.gui.frpane.FontSizeComboPane; import com.fr.design.widget.ui.designer.component.FormWidgetValuePane; import com.fr.form.ui.CheckBox; import com.fr.general.GeneralContext; @@ -76,7 +78,8 @@ public class CheckBoxDefinePane extends AbstractDataModify { protected void refreshExtraAdvancedPane() { extraPaneList.clear(); - boolean containsExtraPane = false; + WidgetThemeParaCreatorPaneAdder.add(creator, extraPaneList); + boolean containsExtraPane = CollectionUtils.isNotEmpty(extraPaneList); Set> providers = ExtraDesignClassManager.getInstance().getArray(WidgetAdvancedPaneProvider.XML_TAG); for (WidgetAdvancedPaneProvider provider : providers) { if (!provider.accept(creator)) { diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/designer/ComboBoxDefinePane.java b/designer-form/src/main/java/com/fr/design/widget/ui/designer/ComboBoxDefinePane.java index 900072b7c0..583346868b 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/designer/ComboBoxDefinePane.java +++ b/designer-form/src/main/java/com/fr/design/widget/ui/designer/ComboBoxDefinePane.java @@ -27,7 +27,7 @@ public class ComboBoxDefinePane extends DictEditorDefinePane { public Component[] createWaterMarkPane() { waterMarkField = new UITextField(); - return new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_WaterMark")), waterMarkField}; + return new Component[]{new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_PlaceHolder")), waterMarkField}; } protected void populateSubDictionaryEditorBean(ComboBox ob){ diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/designer/DateEditorDefinePane.java b/designer-form/src/main/java/com/fr/design/widget/ui/designer/DateEditorDefinePane.java index 7df1e90909..06ccb13870 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/designer/DateEditorDefinePane.java +++ b/designer-form/src/main/java/com/fr/design/widget/ui/designer/DateEditorDefinePane.java @@ -1,5 +1,6 @@ package com.fr.design.widget.ui.designer; +import com.finebi.cbb.utils.CollectionUtils; import com.fr.base.FRContext; import com.fr.data.core.FormatField; import com.fr.design.ExtraDesignClassManager; @@ -14,6 +15,7 @@ import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.ilable.UILabel; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.widgettheme.processor.WidgetThemeParaCreatorPaneAdder; import com.fr.design.widget.component.DateValuePane; import com.fr.design.widget.component.UIComboBoxNoArrow; import com.fr.design.widget.ui.designer.component.FormWidgetValuePane; @@ -98,7 +100,8 @@ public class DateEditorDefinePane extends DirectWriteEditorDefinePane> providers = ExtraDesignClassManager.getInstance().getArray(WidgetAdvancedPaneProvider.XML_TAG); for (WidgetAdvancedPaneProvider provider : providers) { if (!provider.accept(creator)) { diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/designer/DirectWriteEditorDefinePane.java b/designer-form/src/main/java/com/fr/design/widget/ui/designer/DirectWriteEditorDefinePane.java index 53c38b6421..1a65f3bba6 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/designer/DirectWriteEditorDefinePane.java +++ b/designer-form/src/main/java/com/fr/design/widget/ui/designer/DirectWriteEditorDefinePane.java @@ -1,5 +1,6 @@ package com.fr.design.widget.ui.designer; +import com.finebi.cbb.utils.CollectionUtils; import com.fr.design.ExtraDesignClassManager; import com.fr.design.beans.BasicBeanPane; import com.fr.design.designer.IntervalConstants; @@ -9,6 +10,7 @@ import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.ilable.UILabel; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.widgettheme.processor.WidgetThemeParaCreatorPaneAdder; import com.fr.design.utils.gui.GUICoreUtils; import com.fr.design.widget.ui.designer.component.FormWidgetValuePane; import com.fr.form.ui.DirectWriteEditor; @@ -66,7 +68,8 @@ public abstract class DirectWriteEditorDefinePane e protected void refreshExtraAdvancedPane() { extraPaneList.clear(); - boolean containsExtraPane = false; + WidgetThemeParaCreatorPaneAdder.add(creator, extraPaneList); + boolean containsExtraPane = CollectionUtils.isNotEmpty(extraPaneList); Set> providers = ExtraDesignClassManager.getInstance().getArray(WidgetAdvancedPaneProvider.XML_TAG); for (WidgetAdvancedPaneProvider provider : providers) { if (!provider.accept(creator)) { diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/designer/FieldEditorDefinePane.java b/designer-form/src/main/java/com/fr/design/widget/ui/designer/FieldEditorDefinePane.java index 65aeec3a75..81499facc8 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/designer/FieldEditorDefinePane.java +++ b/designer-form/src/main/java/com/fr/design/widget/ui/designer/FieldEditorDefinePane.java @@ -20,7 +20,7 @@ import com.fr.design.gui.itextfield.UITextField; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; -import com.fr.design.widget.ui.designer.component.FontSizeComboPane; +import com.fr.design.gui.frpane.FontSizeComboPane; import com.fr.form.ui.FieldEditor; import com.fr.general.GeneralContext; import com.fr.log.FineLoggerFactory; diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/designer/FreeButtonDefinePane.java b/designer-form/src/main/java/com/fr/design/widget/ui/designer/FreeButtonDefinePane.java index 843f402f01..16a31b85ed 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/designer/FreeButtonDefinePane.java +++ b/designer-form/src/main/java/com/fr/design/widget/ui/designer/FreeButtonDefinePane.java @@ -41,10 +41,13 @@ public class FreeButtonDefinePane extends ButtonDefinePane { } public void populateSubButtonPane(FreeButton e) { + if (containsExtraPane) { + return; + } backgroundCompPane.populate(e); frFontPane.setVisible(e.isCustomStyle()); fontLabel.setVisible(e.isCustomStyle()); - if(e.isCustomStyle()){ + if (e.isCustomStyle()) { FRFont frFont = e.getFont(); if (frFont != null) { frFontPane.populateBean(e.getFont()); @@ -54,12 +57,14 @@ public class FreeButtonDefinePane extends ButtonDefinePane { public FreeButton updateSubButtonPane() { FreeButton freeButton = (FreeButton) creator.toData(); - backgroundCompPane.update(freeButton); - frFontPane.setVisible(freeButton.isCustomStyle()); - fontLabel.setVisible(freeButton.isCustomStyle()); - if(freeButton.isCustomStyle()){ - FRFont frFont = freeButton.getFont() == null ? FRFont.getInstance() : freeButton.getFont(); - freeButton.setFont(frFontPane.update(frFont)); + if (!containsExtraPane) { + backgroundCompPane.update(freeButton); + frFontPane.setVisible(freeButton.isCustomStyle()); + fontLabel.setVisible(freeButton.isCustomStyle()); + if (freeButton.isCustomStyle()) { + FRFont frFont = freeButton.getFont() == null ? FRFont.getInstance() : freeButton.getFont(); + freeButton.setFont(frFontPane.update(frFont)); + } } return freeButton; } diff --git a/designer-form/src/main/java/com/fr/design/widget/ui/designer/LabelDefinePane.java b/designer-form/src/main/java/com/fr/design/widget/ui/designer/LabelDefinePane.java index 040137141c..1776e2eb18 100644 --- a/designer-form/src/main/java/com/fr/design/widget/ui/designer/LabelDefinePane.java +++ b/designer-form/src/main/java/com/fr/design/widget/ui/designer/LabelDefinePane.java @@ -1,5 +1,6 @@ package com.fr.design.widget.ui.designer; +import com.finebi.cbb.utils.CollectionUtils; import com.fr.base.BaseUtils; import com.fr.design.ExtraDesignClassManager; import com.fr.design.beans.BasicBeanPane; @@ -15,6 +16,7 @@ import com.fr.design.gui.style.FRFontPane; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayoutHelper; +import com.fr.design.widgettheme.processor.WidgetThemeParaCreatorPaneAdder; import com.fr.design.widget.FRWidgetFactory; import com.fr.design.widget.ui.designer.component.FormWidgetValuePane; import com.fr.form.ui.Label; @@ -35,7 +37,11 @@ import java.util.Set; /** - * Created by ibm on 2017/8/3. + * 标签控件pane + * + * @author obo + * @version 11.0 + * Created on 2023/11/13 */ public class LabelDefinePane extends AbstractDataModify