Browse Source

Merge pull request #9325 in DESIGN/design from final/11.0 to persist/11.0

* commit '9962c24492dc5bec1854a54f58e91a5eae0d9fac': (118 commits)
  REPORT-71839 设计器启动时启动服务器,仍连曾断开的服务器,会有远程更新提醒
  REPORT-67316 决策报表-客户模板是绝对布局固定大小的,复制客户模板里的tab到一个新建的绝对布局固定大小frm,保存关闭再打开新建模板,tab下的报表块尺寸变了
  REPORT-71824 frm打开报表块编辑页面,切换工作目录无法打开当前frm
  REPORT-73808 海外版alphafine功能问题
  KERNEL-11501 去除classhelper
  REPORT-74100【冒烟】远程BI环境,13个jar全部提示缺失 BI 集成的 JAR 或者之前的环境, 这里需要进行判断是否需要进行检查。
  REPORT-73970 手动修改参数面板宽度未生效 1、REPORT-66771改动导致,在dolayout的时候修改了组件宽度 2、改为,在form宽度修改事件中修改组件宽度
  REPORT-73996-新建frm预览空白
  KERNEL-11531  修改下设计,ColoneCollector中触发clone()
  REPORT-73802 【设计器环境监测】windows下没有finedb权限,首次启动设计器能起来,第二次就启动失败了
  KERNEL-11531 数据链接越权漏洞调用com.fr.invoke.ClassHelper中遍历搜索对象存在空间时间效率问题导致宕机
  单独写一个 DefaultLoginKeys
  REPORT-72595 FR源码中存在加密密钥硬编码,建议放到配置文件中
  REPORT-73833【设计器环境检测】本地目录,只有finedb异常,自动弹窗没弹 需要对使用后埋点。之前是使用的 Stream. 埋点后 Stream 流就不能用了。 这边换成 Collection 适配一下。
  REPORT-73811 图表条件属性汇总字段值,汇总方式下拉内容显示了两遍
  REPORT-72819 弹窗显示不全
  REPORT-73833【设计器环境检测】本地目录,只有finedb异常,自动弹窗没弹 1-这里容易吞异常,修改一下。 2-标记为 Careful
  REPORT-73488 使用取色器配置颜色后,最近使用的颜色列表不会被更新
  KERNEL-11517 实现主题色时ClassHelper中遍历搜索对象存在性能问题
  REPORT-72851 去除无用导入
  ...
fix-lag
superman 2 years ago
parent
commit
42a5bbf486
  1. 24
      designer-base/src/main/java/com/fr/base/function/ThrowableRunnable.java
  2. 22
      designer-base/src/main/java/com/fr/design/DesignerEnvManager.java
  3. 10
      designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
  4. 10
      designer-base/src/main/java/com/fr/design/actions/file/ExitDesignerAction.java
  5. 7
      designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java
  6. 7
      designer-base/src/main/java/com/fr/design/actions/file/SwitchExistEnv.java
  7. 3
      designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigManager.java
  8. 21
      designer-base/src/main/java/com/fr/design/components/notification/NotificationAction.java
  9. 391
      designer-base/src/main/java/com/fr/design/components/notification/NotificationDialog.java
  10. 39
      designer-base/src/main/java/com/fr/design/components/notification/NotificationDialogProperties.java
  11. 88
      designer-base/src/main/java/com/fr/design/components/notification/NotificationMessage.java
  12. 39
      designer-base/src/main/java/com/fr/design/components/notification/NotificationModel.java
  13. 16
      designer-base/src/main/java/com/fr/design/components/notification/NotificationType.java
  14. 78
      designer-base/src/main/java/com/fr/design/components/page/PageControlModel.java
  15. 151
      designer-base/src/main/java/com/fr/design/components/page/PageControlPanel.java
  16. 184
      designer-base/src/main/java/com/fr/design/components/table/TablePanel.java
  17. 24
      designer-base/src/main/java/com/fr/design/constants/DesignerColor.java
  18. 11
      designer-base/src/main/java/com/fr/design/data/datapane/SummaryMethodComboBox.java
  19. 5
      designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java
  20. 24
      designer-base/src/main/java/com/fr/design/dialog/FineJOptionPane.java
  21. 80
      designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java
  22. 22
      designer-base/src/main/java/com/fr/design/extra/exe/ReadUpdateOnlineExecutor.java
  23. 42
      designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java
  24. 39
      designer-base/src/main/java/com/fr/design/file/SaveSomeTemplatePane.java
  25. 4
      designer-base/src/main/java/com/fr/design/formula/FormulaPane.java
  26. 18
      designer-base/src/main/java/com/fr/design/gui/frpane/TreeSettingPane.java
  27. 11
      designer-base/src/main/java/com/fr/design/gui/ilable/ActionLabel.java
  28. 138
      designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeRootPane.java
  29. 10
      designer-base/src/main/java/com/fr/design/gui/style/BackgroundPane.java
  30. 5
      designer-base/src/main/java/com/fr/design/gui/style/BorderPane.java
  31. 20
      designer-base/src/main/java/com/fr/design/gui/style/FormatPane.java
  32. 7
      designer-base/src/main/java/com/fr/design/gui/style/TextFormatPane.java
  33. 6
      designer-base/src/main/java/com/fr/design/lock/LockInfoDialog.java
  34. 48
      designer-base/src/main/java/com/fr/design/login/config/DefaultLoginKeys.java
  35. 9
      designer-base/src/main/java/com/fr/design/login/utils/DesignerLoginUtils.java
  36. 17
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
  37. 101
      designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
  38. 12
      designer-base/src/main/java/com/fr/design/mainframe/JTemplateActionListener.java
  39. 10
      designer-base/src/main/java/com/fr/design/mainframe/JTemplateFactory.java
  40. 3
      designer-base/src/main/java/com/fr/design/mainframe/NorthRegionContainerPane.java
  41. 37
      designer-base/src/main/java/com/fr/design/mainframe/authority/AuthorityTargetObjectCollector.java
  42. 80
      designer-base/src/main/java/com/fr/design/mainframe/authority/JTemplateAuthorityChecker.java
  43. 2
      designer-base/src/main/java/com/fr/design/mainframe/backgroundpane/NullBackgroundQuickPane.java
  44. 5
      designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeEditorPane.java
  45. 3
      designer-base/src/main/java/com/fr/design/mainframe/theme/ThemedFeatureController.java
  46. 144
      designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ui/ColorListExtendedPane.java
  47. 5
      designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java
  48. 91
      designer-base/src/main/java/com/fr/design/mod/ContentObjectManager.java
  49. 3
      designer-base/src/main/java/com/fr/design/mod/ContentReplacerCenter.java
  50. 26
      designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerActivator.java
  51. 28
      designer-base/src/main/java/com/fr/design/record/analyzer/Interceptor/CollectInterceptor.java
  52. 26
      designer-base/src/main/java/com/fr/design/record/analyzer/advice/CollectAdvice.java
  53. 15
      designer-base/src/main/java/com/fr/design/style/FormatPane.java
  54. 2
      designer-base/src/main/java/com/fr/design/style/color/ColorPicker.java
  55. 29
      designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java
  56. 22
      designer-base/src/main/java/com/fr/design/update/ui/dialog/UpdateMainDialog.java
  57. 30
      designer-base/src/main/java/com/fr/design/utils/ColorUtils.java
  58. 63
      designer-base/src/main/java/com/fr/design/utils/LinkStrUtils.java
  59. 20
      designer-base/src/main/java/com/fr/design/utils/TemplateUtils.java
  60. 21
      designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java
  61. 37
      designer-base/src/main/java/com/fr/design/worker/save/SaveFailureHandler.java
  62. 27
      designer-base/src/main/java/com/fr/env/EnvPrepare.java
  63. 226
      designer-base/src/main/java/com/fr/env/detect/EnvDetectorCenter.java
  64. 19
      designer-base/src/main/java/com/fr/env/detect/base/AbstractExceptionDetector.java
  65. 55
      designer-base/src/main/java/com/fr/env/detect/base/CatchExceptionDetector.java
  66. 157
      designer-base/src/main/java/com/fr/env/detect/base/DetectorBridge.java
  67. 18
      designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java
  68. 82
      designer-base/src/main/java/com/fr/env/detect/base/DetectorManager.java
  69. 166
      designer-base/src/main/java/com/fr/env/detect/base/DetectorUtil.java
  70. 59
      designer-base/src/main/java/com/fr/env/detect/base/EnvDetectorConfig.java
  71. 25
      designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetector.java
  72. 40
      designer-base/src/main/java/com/fr/env/detect/base/ThrowableBridge.java
  73. 4
      designer-base/src/main/java/com/fr/env/detect/base/package-info.java
  74. 147
      designer-base/src/main/java/com/fr/env/detect/bean/DetectorResult.java
  75. 22
      designer-base/src/main/java/com/fr/env/detect/bean/DetectorStatus.java
  76. 159
      designer-base/src/main/java/com/fr/env/detect/bean/DetectorType.java
  77. 36
      designer-base/src/main/java/com/fr/env/detect/bean/ExceptionLog.java
  78. 32
      designer-base/src/main/java/com/fr/env/detect/bean/ExceptionSolution.java
  79. 24
      designer-base/src/main/java/com/fr/env/detect/bean/ExceptionTips.java
  80. 83
      designer-base/src/main/java/com/fr/env/detect/bean/Message.java
  81. 11
      designer-base/src/main/java/com/fr/env/detect/bean/SolutionAction.java
  82. 46
      designer-base/src/main/java/com/fr/env/detect/impl/DetectorChain.java
  83. 106
      designer-base/src/main/java/com/fr/env/detect/impl/FineDbDirtyDetector.java
  84. 16
      designer-base/src/main/java/com/fr/env/detect/impl/FineDbLockedDetector.java
  85. 15
      designer-base/src/main/java/com/fr/env/detect/impl/FineDbPermissionDetector.java
  86. 15
      designer-base/src/main/java/com/fr/env/detect/impl/JarConflictDetector.java
  87. 156
      designer-base/src/main/java/com/fr/env/detect/impl/JarInconsistentDetector.java
  88. 164
      designer-base/src/main/java/com/fr/env/detect/impl/JarLackDetector.java
  89. 212
      designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassConflictConvertor.java
  90. 69
      designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbLockedConverter.java
  91. 84
      designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbPermissionConverter.java
  92. 28
      designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableConverter.java
  93. 72
      designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableLogAppender.java
  94. 36
      designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableStore.java
  95. 159
      designer-base/src/main/java/com/fr/env/detect/ui/DetectorErrorDialog.java
  96. 28
      designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java
  97. 569
      designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java
  98. 40
      designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorItem.java
  99. 70
      designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorModel.java
  100. 18
      designer-base/src/main/java/com/fr/exit/ConfigToPropMigrator.java
  101. Some files were not shown because too many files have changed in this diff Show More

24
designer-base/src/main/java/com/fr/base/function/ThrowableRunnable.java

@ -0,0 +1,24 @@
package com.fr.base.function;
import com.fr.log.FineLoggerFactory;
/**
* 可抛出异常的 Runnable
*
* created by Harrison on 2022/05/24
**/
public interface ThrowableRunnable<T extends Exception> {
void run() throws T;
static <T extends Exception> Runnable toRunnable(ThrowableRunnable<T> runnable) {
return () -> {
try {
runnable.run();
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
};
}
}

22
designer-base/src/main/java/com/fr/design/DesignerEnvManager.java

@ -29,6 +29,7 @@ import com.fr.design.style.color.ColorSelectConfigManager;
import com.fr.design.update.push.DesignerPushUpdateConfigManager; import com.fr.design.update.push.DesignerPushUpdateConfigManager;
import com.fr.design.utils.DesignUtils; import com.fr.design.utils.DesignUtils;
import com.fr.design.utils.DesignerPort; import com.fr.design.utils.DesignerPort;
import com.fr.env.detect.base.EnvDetectorConfig;
import com.fr.exit.DesignerExiter; import com.fr.exit.DesignerExiter;
import com.fr.file.FILEFactory; import com.fr.file.FILEFactory;
import com.fr.general.ComparatorUtils; import com.fr.general.ComparatorUtils;
@ -168,6 +169,12 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
private boolean embedServerLazyStartup = false; private boolean embedServerLazyStartup = false;
//最近使用的颜色 //最近使用的颜色
private ColorSelectConfigManager configManager = new ColorSelectConfigManager(); private ColorSelectConfigManager configManager = new ColorSelectConfigManager();
/**
* 环境检测配置
*/
private EnvDetectorConfig envDetectorConfig = EnvDetectorConfig.getInstance();
/** /**
* alphafine * alphafine
*/ */
@ -1820,6 +1827,8 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
readActiveStatus(reader); readActiveStatus(reader);
} else if (ComparatorUtils.equals(CAS_PARAS, name)) { } else if (ComparatorUtils.equals(CAS_PARAS, name)) {
readHttpsParas(reader); readHttpsParas(reader);
} else if (name.equals(EnvDetectorConfig.XML_TAG)) {
readEnvDetectorConfig(reader);
} else if (name.equals("AlphaFineConfigManager")) { } else if (name.equals("AlphaFineConfigManager")) {
readAlphaFineAttr(reader); readAlphaFineAttr(reader);
} else if (name.equals("RecentColors")) { } else if (name.equals("RecentColors")) {
@ -1856,6 +1865,10 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
private void readAlphaFineAttr(XMLableReader reader) { private void readAlphaFineAttr(XMLableReader reader) {
reader.readXMLObject(this.alphaFineConfigManager = AlphaFineConfigManager.getInstance()); reader.readXMLObject(this.alphaFineConfigManager = AlphaFineConfigManager.getInstance());
} }
private void readEnvDetectorConfig(XMLableReader reader) {
reader.readXMLObject(this.envDetectorConfig);
}
private void readHttpsParas(XMLableReader reader) { private void readHttpsParas(XMLableReader reader) {
String tempVal; String tempVal;
@ -2070,6 +2083,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
writeActiveStatus(writer); writeActiveStatus(writer);
writeHttpsParas(writer); writeHttpsParas(writer);
writeAlphaFineAttr(writer); writeAlphaFineAttr(writer);
writeEnvDetectorConfig(writer);
writeRecentColor(writer); writeRecentColor(writer);
writeOpenDebug(writer); writeOpenDebug(writer);
writeDesignerPushUpdateAttr(writer); writeDesignerPushUpdateAttr(writer);
@ -2113,6 +2127,12 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
writer.end(); writer.end();
} }
} }
private void writeEnvDetectorConfig(XMLPrintWriter writer) {
if (this.envDetectorConfig != null) {
this.envDetectorConfig.writeXML(writer);
}
}
//写入uuid //写入uuid
private void writeUUID(XMLPrintWriter writer) { private void writeUUID(XMLPrintWriter writer) {
@ -2220,7 +2240,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
writer.attr("layoutTemplateStyle", this.getLayoutTemplateStyle()); writer.attr("layoutTemplateStyle", this.getLayoutTemplateStyle());
writer.attr("showServerDatasetAuthTip", this.isShowServerDatasetAuthTip()); writer.attr("showServerDatasetAuthTip", this.isShowServerDatasetAuthTip());
writer.attr("useOptimizedUPM4Adapter", this.isUseOptimizedUPM4Adapter()); writer.attr("useOptimizedUPM4Adapter", this.isUseOptimizedUPM4Adapter());
writer.attr("propertiesUsable", false); writer.attr("propertiesUsable", this.isPropertiesUsable());
writer.end(); writer.end();
} }

10
designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java

@ -13,6 +13,7 @@ import com.fr.design.env.DesignerWorkspaceType;
import com.fr.design.env.RemoteDesignerWorkspaceInfo; import com.fr.design.env.RemoteDesignerWorkspaceInfo;
import com.fr.design.env.RemoteWorkspace; import com.fr.design.env.RemoteWorkspace;
import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.file.SaveSomeTemplatePane;
import com.fr.design.file.TemplateTreePane; import com.fr.design.file.TemplateTreePane;
import com.fr.design.i18n.Toolkit; import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerContext;
@ -388,6 +389,11 @@ public class EnvChangeEntrance {
@Override @Override
public void doOk() { public void doOk() {
SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true, SwingUtilities.getWindowAncestor(envListPane));
if (!saveSomeTemplatePane.showSavePane()) {
// 用户取消保存时,取消切换目录操作
return;
}
boolean changeResult = envListOkAction(envListPane, PopTipStrategy.LATER); boolean changeResult = envListOkAction(envListPane, PopTipStrategy.LATER);
// 切换完成后清理密码 // 切换完成后清理密码
updateNotRememberPwdEnv(); updateNotRememberPwdEnv();
@ -427,7 +433,9 @@ public class EnvChangeEntrance {
DesignerExiter.getInstance().execute(); DesignerExiter.getInstance().execute();
} else { } else {
updateNotRememberPwdEnv(); updateNotRememberPwdEnv();
VersionCheckUtils.showVersionCheckDialog(envListPane.getSelectedName()); if (DesignerContext.getDesignerFrame().isVisible()) {
VersionCheckUtils.showVersionCheckDialog(envListPane.getSelectedName());
}
} }
} }

10
designer-base/src/main/java/com/fr/design/actions/file/ExitDesignerAction.java

@ -3,6 +3,7 @@
*/ */
package com.fr.design.actions.file; package com.fr.design.actions.file;
import com.fr.design.file.SaveSomeTemplatePane;
import com.fr.design.mainframe.TemplateSavingChecker; import com.fr.design.mainframe.TemplateSavingChecker;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
@ -28,9 +29,14 @@ public class ExitDesignerAction extends UpdateAction {
* @param e 事件 * @param e 事件
*/ */
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
// 检查是否有正在保存的模板
if (!TemplateSavingChecker.check()) { if (!TemplateSavingChecker.check()) {
return; return;
} }
DesignerContext.getDesignerFrame().exit(); // 提示用户保存模板
SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true);
if (saveSomeTemplatePane.showSavePane()) {
DesignerContext.getDesignerFrame().exit();
}
} }
} }

7
designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java

@ -9,6 +9,7 @@ import com.fr.design.dialog.BasicPane;
import com.fr.design.dialog.DialogActionAdapter; import com.fr.design.dialog.DialogActionAdapter;
import com.fr.design.dialog.DialogActionListener; import com.fr.design.dialog.DialogActionListener;
import com.fr.design.editor.editor.IntegerEditor; import com.fr.design.editor.editor.IntegerEditor;
import com.fr.design.file.SaveSomeTemplatePane;
import com.fr.design.gui.frpane.UITabbedPane; import com.fr.design.gui.frpane.UITabbedPane;
import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ibutton.UIColorButton; import com.fr.design.gui.ibutton.UIColorButton;
@ -889,6 +890,12 @@ public class PreferencePane extends BasicPane {
if (!languageChanged) { if (!languageChanged) {
return; return;
} }
// 重启弹窗出现之前提示用户保存模板
SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(true, SwingUtilities.getWindowAncestor(this));
if (!saveSomeTempaltePane.showSavePane()) {
// 保存失败时,直接返回
return;
}
int rv = JOptionPane.showOptionDialog( int rv = JOptionPane.showOptionDialog(
null, null,
i18nText("Fine-Design_Basic_Language_Change_Successful"), i18nText("Fine-Design_Basic_Language_Change_Successful"),

7
designer-base/src/main/java/com/fr/design/actions/file/SwitchExistEnv.java

@ -5,6 +5,7 @@ import com.fr.design.EnvChangeEntrance;
import com.fr.design.actions.UpdateAction; import com.fr.design.actions.UpdateAction;
import com.fr.design.env.DesignerWorkspaceInfo; import com.fr.design.env.DesignerWorkspaceInfo;
import com.fr.design.file.HistoryTemplateListCache; import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.file.SaveSomeTemplatePane;
import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.JTemplate;
import com.fr.design.menu.KeySetUtils; import com.fr.design.menu.KeySetUtils;
import com.fr.design.menu.MenuDef; import com.fr.design.menu.MenuDef;
@ -66,7 +67,11 @@ public class SwitchExistEnv extends MenuDef {
// 打开配置目录面板 // 打开配置目录面板
EnvChangeEntrance.getInstance().chooseEnv(envName); EnvChangeEntrance.getInstance().chooseEnv(envName);
} else { } else {
EnvChangeEntrance.getInstance().switch2Env(envName); SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true);
if (saveSomeTemplatePane.showSavePane()) {
// 用户模板保存后,才进行切换目录操作
EnvChangeEntrance.getInstance().switch2Env(envName);
}
} }
} }

3
designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigManager.java

@ -1,5 +1,6 @@
package com.fr.design.actions.help.alphafine; package com.fr.design.actions.help.alphafine;
import com.fr.base.FRContext;
import com.fr.design.DesignerEnvManager; import com.fr.design.DesignerEnvManager;
import com.fr.general.ComparatorUtils; import com.fr.general.ComparatorUtils;
import com.fr.license.function.VT4FR; import com.fr.license.function.VT4FR;
@ -442,7 +443,7 @@ public class AlphaFineConfigManager implements XMLable {
} }
public boolean isProductDynamics() { public boolean isProductDynamics() {
return productDynamics; return productDynamics && FRContext.isChineseEnv();
} }
public void setProductDynamics(boolean productDynamics) { public void setProductDynamics(boolean productDynamics) {

21
designer-base/src/main/java/com/fr/design/components/notification/NotificationAction.java

@ -0,0 +1,21 @@
package com.fr.design.components.notification;
/**
* created by Harrison on 2022/05/24
**/
public interface NotificationAction {
/**
* 行为名
*
* @return 名称
*/
String name();
/**
* 行为动作
*
* @param args 参数
*/
void run(Object... args);
}

391
designer-base/src/main/java/com/fr/design/components/notification/NotificationDialog.java

@ -0,0 +1,391 @@
package com.fr.design.components.notification;
import com.fr.base.function.ThrowableRunnable;
import com.fr.base.svg.IconUtils;
import com.fr.design.components.page.PageControlModel;
import com.fr.design.components.page.PageControlPanel;
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.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.VerticalFlowLayout;
import com.fr.design.utils.LinkStrUtils;
import com.fr.env.detect.base.EnvDetectorConfig;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Desktop;
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.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* 右下角的提醒 <a href="https://kms.fineres.com/pages/viewpage.action?pageId=388333688">异常提醒</a>
* 相关使用方式见 <a href="https://kms.fineres.com/pages/viewpage.action?pageId=415212013">提醒组件</a>
*
* created by Harrison on 2022/05/24
**/
public class NotificationDialog extends JDialog {
/**
* 通知框的内部高度
*/
private static final int CONTENT_INNER_HEIGHT = 60;
/**
* 通知框如果出现滚动条后的内部宽度
*/
private static final int CONTENT_SCROLL_WIDTH = 280;
private static final int CONTENT_WIDTH = 300;
private static final int CONTENT_HEIGHT = 100;
/**
* 通知框的外部宽高
*/
private static final Dimension CONTENT_SIZE = new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT);
private static final Dimension BUTTON_DIMENSION = new Dimension(68, 20);
/**
* 标记 LABEL 没有作用
*/
private static final UILabel SIGN_LABEL = new UILabel("#");
/**
* 确认一个 LABEL 的宽高
*/
private static final Dimension SIGN_LABEL_DIMENSION = SIGN_LABEL.getPreferredSize();
private NotificationDialogProperties properties;
/* 数据 model */
private List<NotificationModel> notificationModels;
private PageControlModel pageControlModel;
private JPanel body;
private JPanel headerPanel;
private JPanel contentPanel;
private JPanel tailPanel;
public NotificationDialog(NotificationDialogProperties properties, List<NotificationModel> notificationModels) {
super(properties.getOwner());
setTitle(properties.getTitle());
this.properties = properties;
this.notificationModels = notificationModels;
this.pageControlModel = new PageControlModel(0, this.notificationModels.size());
initComponents();
}
public void initComponents() {
//UI 配置
configProperties();
this.body = FRGUIPaneFactory.createBorderLayout_L_Pane();
body.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
//首行
layoutHeaderPanel();
//消息内容
layoutContentPanel();
//查看详情
layoutTailPanel();
add(body);
Dimension dimension = body.getPreferredSize();
setSize(dimension.width, dimension.height);
Container parent = getParent();
setLocation((parent.getWidth() - dimension.width - 30 + parent.getX()),
parent.getY() + parent.getHeight() - dimension.height - 30);
}
public void open() {
setVisible(true);
}
private void configProperties() {
setModal(properties.isModal());
setFocusable(false);
setAutoRequestFocus(false);
setResizable(false);
}
protected JPanel createHeaderPanel() {
return null;
}
/**
* 内容
*
* @return 内容面板
*/
protected JPanel createContentPanel() {
JPanel contentPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
contentPanel.setBorder(BorderFactory.createEmptyBorder(8, 10, 8, 10));
contentPanel.setName("contentPanel");
NotificationModel model = getCurrentModel();
UILabel icon = new UILabel(getIconForType(model.getType()));
icon.setPreferredSize(new Dimension(16, 16));
JPanel iconPanel = FRGUIPaneFactory.createBorderLayout_L_Pane();
iconPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 10, 8));
iconPanel.add(icon, BorderLayout.NORTH);
contentPanel.add(iconPanel, BorderLayout.WEST);
JPanel centerPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
centerPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 5));
NotificationMessage[] messages = model.getMessages();
List<? extends JComponent> messageComponents = Arrays.stream(messages)
.map((messageModel) -> {
if (messageModel.getType() == NotificationMessage.Type.LINK) {
NotificationMessage.LinkMessage linkMessage = (NotificationMessage.LinkMessage) messageModel;
return new MessageWithLink(linkMessage.format(), ThrowableRunnable.toRunnable(() -> {
Desktop.getDesktop().browse(URI.create(linkMessage.getLink()));
}));
}
return new UILabel(LinkStrUtils.generateHtmlTag(messageModel.format()));
})
.collect(Collectors.toList());
// 当高度 大于 60 时,就会出现滚动条。
// 当出现滚动条时,需要将内部的宽度限制为 280, 否则会展示不出来
Function<Double, Integer> calStandardWidth = height -> height > CONTENT_INNER_HEIGHT ? CONTENT_SCROLL_WIDTH : CONTENT_WIDTH;
int widthUnit = messageComponents.stream()
.map((component) -> {
Dimension preferredSize = component.getPreferredSize();
double width = preferredSize.getWidth();
double widthFactor = Math.ceil(width / CONTENT_WIDTH);
// 这里的高度是没有限制宽度的,如果限制宽度,高度会变更,所以这里需要加上宽度的影响
return preferredSize.getHeight() + widthFactor * SIGN_LABEL_DIMENSION.getHeight();
})
.reduce(Double::sum)
.map(calStandardWidth)
.orElse(CONTENT_WIDTH);
messageComponents = messageComponents.stream()
.peek((component) -> {
Dimension preferredSize = component.getPreferredSize();
double componentWidth = preferredSize.getWidth();
double componentHeight = preferredSize.getHeight();
double heightFactor = Math.ceil(componentHeight / SIGN_LABEL_DIMENSION.getHeight());
double widthFactor = Math.ceil(componentWidth / widthUnit);
int realHeight = (int)Math.ceil(heightFactor + widthFactor - 1) * (int)(Math.ceil(SIGN_LABEL_DIMENSION.getHeight()));
component.setPreferredSize(new Dimension(widthUnit, realHeight));
})
.collect(Collectors.toList());
// 竖向排列
JPanel messageSummaryPanel = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, VerticalFlowLayout.TOP, 0, 0);
messageComponents.forEach(messageSummaryPanel::add);
JScrollPane jScrollPane = new JScrollPane(messageSummaryPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
jScrollPane.setBorder(BorderFactory.createEmptyBorder());
centerPanel.add(jScrollPane, BorderLayout.CENTER);
centerPanel.setPreferredSize(CONTENT_SIZE);
contentPanel.add(centerPanel, BorderLayout.CENTER);
return contentPanel;
}
/**
* 行动
*
* UI布局
* /翻页/不再提醒/提醒行为/我知道了
*
* @return 行动面板
*/
protected JPanel createTailPanel() {
JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_L_Pane();
tailPanel.setName("tailPanel");
// 翻页按钮效果
PageControlPanel pageControlPanel = new PageControlPanel(pageControlModel);
pageControlPanel.actions(new Runnable() {
@Override
public void run() {
pageControlModel = pageControlPanel.performPrevious();
refresh();
}
}, new Runnable() {
@Override
public void run() {
pageControlModel = pageControlPanel.performNext();
refresh();
}
});
tailPanel.add(pageControlPanel, BorderLayout.WEST);
// 行为效果
JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_M_Pane();
{
actionsPanel.setBorder(BorderFactory.createEmptyBorder());
actionsPanel.setName("actionsPanel");
UILabel notReminder = new UILabel();
notReminder.setText(Toolkit.i18nText("Fine-Design_Basic_Not_Reminder"));
notReminder.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// 配置处理
EnvDetectorConfig.getInstance().setEnabled(false);
// 点击事件
destroy();
}
});
Color color = new Color(65, 155, 249);
notReminder.setForeground(color);
actionsPanel.add(notReminder, BorderLayout.WEST);
JPanel buttonPanel = FRGUIPaneFactory.createBorderLayout_M_Pane();
buttonPanel.setBorder(BorderFactory.createEmptyBorder());
// real-action
NotificationModel currentModel = getCurrentModel();
NotificationAction action = currentModel.getAction();
if (action != null) {
UIButton actionButton = new UIButton(action.name());
actionButton.setPreferredSize(BUTTON_DIMENSION);
actionButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
action.run();
}
});
buttonPanel.add(actionButton, BorderLayout.WEST);
}
UIButton knowButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Know"));
knowButton.setPreferredSize(BUTTON_DIMENSION);
knowButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (pageControlModel.isLast()) {
destroy();
return;
}
pageControlModel = pageControlPanel.performNext();
refresh();
}
});
buttonPanel.add(knowButton, BorderLayout.EAST);
actionsPanel.add(buttonPanel, BorderLayout.EAST);
}
tailPanel.add(actionsPanel, BorderLayout.EAST);
return tailPanel;
}
private void refresh() {
layoutContentPanel();
layoutTailPanel();
this.repaint();
}
private void layoutHeaderPanel() {
this.headerPanel = layoutPanel(this.headerPanel, this::createHeaderPanel, BorderLayout.NORTH);
}
private void layoutTailPanel() {
this.tailPanel = layoutPanel(this.tailPanel, this::createTailPanel, BorderLayout.SOUTH);
}
private void layoutContentPanel() {
this.contentPanel = layoutPanel(this.contentPanel, this::createContentPanel, BorderLayout.CENTER);
}
private JPanel layoutPanel(JPanel oldPanel, Supplier<JPanel> supplier, Object constraints){
if (oldPanel != null) {
this.body.remove(oldPanel);
}
JPanel newPanel = supplier.get();
if (newPanel != null) {
this.body.add(newPanel, constraints);
}
return newPanel;
}
private NotificationModel getCurrentModel() {
int index = pageControlModel.getIndex();
return notificationModels.get(index);
}
protected Icon getIconForType(NotificationType type) {
String iconPath;
switch (type) {
case ERROR:
iconPath = "/com/fr/design/standard/reminder/reminder_error.svg";
break;
case INFO:
iconPath = "/com/fr/design/standard/reminder/reminder_success.svg";
break;
case WARNING:
iconPath = "/com/fr/design/standard/reminder/reminder_warning.svg";
break;
default:
return null;
}
return IconUtils.readIcon(iconPath);
}
private void destroy() {
setVisible(false);
dispose();
}
@Override
public void dispose() {
super.dispose();
// todo
}
}

39
designer-base/src/main/java/com/fr/design/components/notification/NotificationDialogProperties.java

@ -0,0 +1,39 @@
package com.fr.design.components.notification;
import java.awt.Frame;
/**
* 通知会话的属性
*
* created by Harrison on 2022/05/24
**/
public class NotificationDialogProperties {
private Frame owner;
private String title;
private boolean modal;
public NotificationDialogProperties(Frame owner, String title) {
this.owner = owner;
this.title = title;
this.modal = false;
}
public void setModal(boolean modal) {
this.modal = modal;
}
public Frame getOwner() {
return owner;
}
public String getTitle() {
return title;
}
public boolean isModal() {
return modal;
}
}

88
designer-base/src/main/java/com/fr/design/components/notification/NotificationMessage.java

@ -0,0 +1,88 @@
package com.fr.design.components.notification;
import com.fr.design.utils.LinkStrUtils;
/**
* created by Harrison on 2022/05/24
**/
public interface NotificationMessage {
/**
* 格式化
*
* @return 通知信息
*/
String format();
/**
* 类型
*
* @return 类型
*/
Type getType();
enum Type {
/**
* 简单型
*/
SIMPLE,
/**
* 链接
*/
LINK
}
class SimpleMessage implements NotificationMessage {
private String text;
public SimpleMessage(String text) {
this.text = text;
}
@Override
public String format() {
return text;
}
@Override
public Type getType() {
return Type.SIMPLE;
}
}
class LinkMessage implements NotificationMessage {
private String text;
private String link;
public LinkMessage(String text, String link) {
this.text = text;
this.link = link;
}
public String getText() {
return text;
}
public String getLink() {
return link;
}
@Override
public String format() {
return LinkStrUtils.generateHtmlTag(text);
}
@Override
public Type getType() {
return Type.LINK;
}
}
}

39
designer-base/src/main/java/com/fr/design/components/notification/NotificationModel.java

@ -0,0 +1,39 @@
package com.fr.design.components.notification;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class NotificationModel {
private final NotificationType type;
private final NotificationMessage[] messages;
@Nullable
private final NotificationAction action;
public NotificationModel(NotificationType type, @Nullable NotificationAction action, List<NotificationMessage> messages) {
this(type, action, messages.toArray(new NotificationMessage[0]));
}
public NotificationModel(NotificationType type, @Nullable NotificationAction action, NotificationMessage... messages) {
this.type = type;
this.messages = messages;
this.action = action;
}
public NotificationType getType() {
return type;
}
public NotificationMessage[] getMessages() {
return messages == null ? new NotificationMessage[0] : messages;
}
public @Nullable NotificationAction getAction() {
return action;
}
}

16
designer-base/src/main/java/com/fr/design/components/notification/NotificationType.java

@ -0,0 +1,16 @@
package com.fr.design.components.notification;
/**
* 提醒类型
* 决定图标种类
*
* created by Harrison on 2022/05/27
**/
public enum NotificationType {
INFO,
ERROR,
WARNING
}

78
designer-base/src/main/java/com/fr/design/components/page/PageControlModel.java

@ -0,0 +1,78 @@
package com.fr.design.components.page;
/**
* created by Harrison on 2022/05/26
**/
public class PageControlModel {
/**
* 当前索引
*
* = (页数-1)
*/
private int index;
/**
* 总页数
*/
private int summary;
public PageControlModel(int index, int summary) {
this.index = index;
this.summary = summary;
}
public PageControlModel() {
}
public PageControlModel previous() {
this.index--;
return this;
}
public PageControlModel next() {
this.index++;
return this;
}
/**
* 页数
* index+1
*
* @return 页数
*/
public int getNumber() {
return index + 1;
}
public boolean isFirst() {
return getNumber() == 1;
}
public boolean isLast() {
return getNumber() == getSummary();
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public int getSummary() {
return summary;
}
public void setSummary(int summary) {
this.summary = summary;
}
public String toContent() {
return getNumber() + "/" + this.summary;
}
}

151
designer-base/src/main/java/com/fr/design/components/page/PageControlPanel.java

@ -0,0 +1,151 @@
package com.fr.design.components.page;
import com.fr.base.svg.IconUtils;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.function.Function;
/**
* 翻页组件
* 相关使用方式见 <a href="https://kms.fineres.com/pages/viewpage.action?pageId=415212013">翻页组件</a>
*
* created by Harrison on 2022/05/26
**/
public class PageControlPanel extends JPanel {
private static final long serialVersionUID = 8140501834691131305L;
private static final Dimension PAGE_CONTROL_BUTTON_DIMENSION = new Dimension(20, 20);
private UIButton previous;
private Runnable previousAction;
private UILabel content;
private PageControlModel model;
private UIButton next;
private Runnable nextAction;
public PageControlPanel(PageControlModel model) {
this.model = model;
setBorder(BorderFactory.createEmptyBorder());
setLayout(new BorderLayout(6, 0));
this.previous = new UIButton();
previous.setPreferredSize(PAGE_CONTROL_BUTTON_DIMENSION);
previous.setIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_enable_left.svg"));
previous.setDisabledIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_disable_left.svg"));
previous.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
performAction(previousAction);
}
});
this.add(previous, BorderLayout.WEST);
this.content = new UILabel(model.toContent());
this.add(content, BorderLayout.CENTER);
next = new UIButton();
next.setPreferredSize(PAGE_CONTROL_BUTTON_DIMENSION);
next.setIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_enable_right.svg"));
next.setDisabledIcon(IconUtils.readIcon("/com/fr/design/standard/arrow/arrow_disable_right.svg"));
next.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
performAction(nextAction);
}
});
this.add(next, BorderLayout.EAST);
refresh();
}
public PageControlModel performPrevious() {
update(PageControlModel::previous);
return this.model;
}
public PageControlModel performNext() {
update(PageControlModel::next);
return this.model;
}
public PageControlModel getModel() {
return this.model;
}
public void update(PageControlModel model) {
this.model.setIndex(model.getIndex());
this.model.setSummary(model.getSummary());
refresh();
}
public void update(Function<PageControlModel, PageControlModel> updateAction) {
PageControlModel newModel = updateAction.apply(this.model);
update(newModel);
refresh();
}
public void refresh() {
this.content.setText(this.model.toContent());
this.content.repaint();
this.previous.setEnabled(true);
this.next.setEnabled(true);
if (model.getNumber() == 1) {
// 禁用上一个
disableButton(this.previous);
// 禁用next
if (model.getNumber() == model.getSummary()) {
disableButton(this.next);
}
return;
}
// 禁用next
if (model.getNumber() == model.getSummary()) {
disableButton(this.next);
}
}
private void enable(UIButton button) {
button.setEnabled(true);
}
private void disableButton(UIButton button) {
button.setEnabled(false);
}
private void performAction(Runnable action) {
if (action != null) {
action.run();
refresh();
}
}
public void actions(Runnable previousAction, Runnable nextAction) {
this.previousAction = previousAction;
this.nextAction = nextAction;
}
}

184
designer-base/src/main/java/com/fr/design/components/table/TablePanel.java

@ -0,0 +1,184 @@
package com.fr.design.components.table;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.utils.ColorUtils;
import com.fr.third.org.apache.commons.lang3.ArrayUtils;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
/**
* 表头
* 内容
*
* 适用于需要一个表格的 Panel
*
* created by Harrison on 2022/05/26
**/
public class TablePanel extends JPanel {
private static final Color DEFAULT_HEADER_COLOR = new Color(232, 232, 233);
private static final Color DEFAULT_ODD_ROW_COLOR = new Color(245, 245, 247);
private static final Color DEFAULT_EVEN_ROW_COLOR = Color.WHITE;
private JPanel headerPanel;
private JPanel[] headerItemPanels;
private JPanel contentPanel;
private JPanel[][] cellPanels;
public TablePanel(int row, int column) {
setLayout(FRGUIPaneFactory.createBorderLayout());
/* header 部分 */
this.headerPanel = new JPanel();
headerPanel.setLayout(FRGUIPaneFactory.createNColumnGridLayout(column));
headerPanel.setName("header-panel");
headerPanel.setPreferredSize(new Dimension(640, 24));
// border
headerPanel.setBorder(BorderFactory.createLineBorder(new Color(218, 218, 221)));
syncHeaderColor(headerPanel);
headerItemPanels = new JPanel[column];
for (int i = 0; i < column; i++) {
JPanel headerItemWrapper = FRGUIPaneFactory.createBorderLayout_S_Pane();
syncHeaderColor(headerItemWrapper);
headerItemWrapper.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
JPanel headerItemPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
headerItemPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
headerItemPanels[i] = headerItemPanel;
UILabel label = new UILabel();
syncHeaderColor(label);
headerItemPanel.add(new UILabel(), BorderLayout.CENTER);
headerItemWrapper.add(headerItemPanel, BorderLayout.WEST);
if (i != column - 1) {
JSeparator separator = new JSeparator(JSeparator.VERTICAL);
separator.setBackground(new Color(218, 218, 221));
headerItemWrapper.add(separator, BorderLayout.EAST);
}
headerPanel.add(headerItemWrapper);
}
/* content 部分 */
contentPanel = new JPanel();
contentPanel.setLayout(new GridLayout(row, 1));
contentPanel.setBorder(BorderFactory.createLineBorder(new Color(218, 218, 221)));
cellPanels = new JPanel[row][column];
for (int i = 0; i < row; i++) {
JPanel rowPanel = new JPanel();
// 获取行号
Color rowColor = getRowColorByRowNumber(i + 1);
rowPanel.setBackground(rowColor);
rowPanel.setLayout(FRGUIPaneFactory.createNColumnGridLayout(column));
rowPanel.setName("row-" + i);
rowPanel.setBorder(BorderFactory.createEmptyBorder());
rowPanel.setPreferredSize(new Dimension(640, 24));
for (int j = 0; j < column; j++) {
JPanel rowItemPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
rowItemPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
rowItemPanel.setName("rowItemPanel-"+ i + "-" + j);
final UILabel empty = new UILabel();
empty.setPreferredSize(new Dimension(210, 24));
rowItemPanel.setBackground(rowPanel.getBackground());
rowItemPanel.add(empty, BorderLayout.CENTER);
rowPanel.add(rowItemPanel);
cellPanels[i][j] = rowItemPanel;
}
contentPanel.add(rowPanel);
}
add(headerPanel, BorderLayout.NORTH);
add(contentPanel, BorderLayout.SOUTH);
}
/**
* 获取行的颜色
*
* @param row 行号
* @return 颜色
*/
private Color getRowColorByRowNumber(int row) {
Color rowColor;
if (row % 2 != 0) {
rowColor = DEFAULT_EVEN_ROW_COLOR;
} else {
rowColor = DEFAULT_ODD_ROW_COLOR;
}
return rowColor;
}
public void updateHeaders(String[] headers) {
for (int i = 0; i < headers.length; i++) {
String header = headers[i];
UILabel headerContent = new UILabel(header);
JPanel headerItemPanel = headerItemPanels[i];
if (ArrayUtils.getLength(headerItemPanel.getComponents()) == 1) {
headerItemPanel.remove(0);
}
headerItemPanel.add(headerContent);
syncHeaderColor(headerItemPanel);
}
}
public void updateCell(int row, int column, Component component) {
int x = row - 1;
int y = column - 1;
syncCellColor(row, component);
JPanel cellPanel = this.cellPanels[x][y];
if (ArrayUtils.getLength(cellPanel.getComponents()) == 1) {
cellPanel.remove(0);
}
cellPanel.add(component);
}
public void updateCell(int row, int column, String value) {
UILabel cellContent = new UILabel(value);
syncCellColor(row, cellContent);
this.updateCell(row, column, cellContent);
}
private void syncHeaderColor(Component component) {
ColorUtils.syncBackground(component, DEFAULT_HEADER_COLOR);
}
private void syncCellColor(int row, Component component) {
Color rowColor = getRowColorByRowNumber(row);
ColorUtils.syncBackground(component, rowColor);
component.setBackground(rowColor);
}
}

24
designer-base/src/main/java/com/fr/design/constants/DesignerColor.java

@ -0,0 +1,24 @@
package com.fr.design.constants;
import java.awt.Color;
/**
* <a href="https://www.figma.com/file/G2f40rv7cY8zpDDYbt6pY2/%E8%AE%BE%E8%AE%A1%E5%99%A811.0%E8%A7%84%E8%8C%83%E6%95%B4%E7%90%86">设计器规范</a>
* 将相关的逻辑抽象过来
* 如果后面更改的话 可以统一修改
* 如果换版本可以换成 v2 这种类推
*
* created by Harrison on 2022/05/26
**/
public interface DesignerColor {
interface Button {
interface Primary {
Color PRESSED = new Color(29, 122, 220);
Color HOVER = new Color(84, 165, 249);
Color NORMAL = new Color(65, 155, 249);
}
}
}

11
designer-base/src/main/java/com/fr/design/data/datapane/SummaryMethodComboBox.java

@ -40,10 +40,13 @@ public class SummaryMethodComboBox extends UIComboBox {
* 更新公式选择. * 更新公式选择.
*/ */
public void populateBean(AbstractDataFunction function) { public void populateBean(AbstractDataFunction function) {
for (int i = 0; i < CLASS_ARRAY.length; i++) { if (function != null) {
if (function != null && ComparatorUtils.equals(function.getClass(), CLASS_ARRAY[i])) { for (int i = 0; i < CLASS_ARRAY.length; i++) {
setSelectedIndex(i); if (this.getModel() != null && this.getModel().getSize() > i
break; && ComparatorUtils.equals(function.getClass(), CLASS_ARRAY[i])) {
setSelectedIndex(i);
break;
}
} }
} }
} }

5
designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java

@ -66,6 +66,7 @@ import javax.swing.JPanel;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JSplitPane; import javax.swing.JSplitPane;
import javax.swing.JToolBar; import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException; import javax.swing.text.BadLocationException;
import javax.swing.text.Document; import javax.swing.text.Document;
import java.awt.BorderLayout; import java.awt.BorderLayout;
@ -303,7 +304,7 @@ public class DBTableDataPane extends AbstractTableDataPane<DBTableData> {
//显示对应的配置 //显示对应的配置
strategyConfigPane.populateBean(populateStrategyConfig); strategyConfigPane.populateBean(populateStrategyConfig);
BasicDialog dlg = strategyConfigPane.showMediumWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { BasicDialog dlg = strategyConfigPane.showMediumWindow(SwingUtilities.getWindowAncestor(DBTableDataPane.this), new DialogActionAdapter() {
@Override @Override
public void doOk() { public void doOk() {
super.doOk(); super.doOk();
@ -314,7 +315,7 @@ public class DBTableDataPane extends AbstractTableDataPane<DBTableData> {
} }
} }
}); });
dlg.setAlwaysOnTop(true); //dlg.setAlwaysOnTop(true);
dlg.setVisible(true); dlg.setVisible(true);
} }
}); });

24
designer-base/src/main/java/com/fr/design/dialog/FineJOptionPane.java

@ -8,6 +8,7 @@ import javax.swing.JDialog;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import java.awt.Component; import java.awt.Component;
import java.awt.HeadlessException; import java.awt.HeadlessException;
import java.awt.event.ActionListener;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -184,6 +185,29 @@ public class FineJOptionPane extends JOptionPane {
messageType, icon, options, initialValue); messageType, icon, options, initialValue);
} }
/**
* 带确认+取消按钮的弹出框并绑定确认事件
*
* @param parentComponent 父容器
* @param message 具体的提示消息
* @param title 标题
* @param icon 图标
* @param initialValue 初始选项
* @throws HeadlessException
*/
public static int showConfirmDialogWithOkListener(Component parentComponent, Object message,
String title, Icon icon, Object initialValue, ActionListener listener)
throws HeadlessException {
int val = showOptionDialog(parentComponent, message, title, JOptionPane.DEFAULT_OPTION,
FineJOptionPane.WARNING_MESSAGE, icon, OPTION_OK_CANCEL, initialValue);
if (val == JOptionPane.OK_OPTION && listener!=null) {
listener.actionPerformed(null);
}
return val;
}
/** /**
* 指定消息内容的输入弹出框 * 指定消息内容的输入弹出框
* @param message 消息内容 * @param message 消息内容

80
designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java

@ -1,16 +1,18 @@
package com.fr.design.dialog.link; package com.fr.design.dialog.link;
import com.fr.design.gui.ilable.UILabel; import com.fr.design.utils.LinkStrUtils;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import javax.swing.JEditorPane; import javax.swing.JEditorPane;
import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import java.awt.Color; import java.awt.Color;
import java.awt.Desktop; import java.awt.Desktop;
import java.awt.Font; import java.awt.Font;
import java.net.URI; import java.net.URI;
import java.net.URL;
import static com.fr.design.utils.LinkStrUtils.LABEL;
/** /**
* 用来构建JOptionPane带超链的消息提示 * 用来构建JOptionPane带超链的消息提示
@ -20,9 +22,28 @@ import java.net.URI;
* Created by hades on 2020/10/23 * Created by hades on 2020/10/23
*/ */
public class MessageWithLink extends JEditorPane { public class MessageWithLink extends JEditorPane {
/**
* 直接放入 html 内容
* 如果有超链接标签 <a href=""></a> 的话将会自动点击匹配 url
*
* @param htmlText html内容
*/
public MessageWithLink(String htmlText) {
super("text/html", htmlText);
initListener();
setEditable(false);
setBorder(null);
}
private static final UILabel LABEL = new UILabel(); public MessageWithLink(String htmlText, Runnable action) {
super("text/html", htmlText);
initListener(action);
setEditable(false);
setBorder(null);
}
public MessageWithLink(String message, String linkName, String link) { public MessageWithLink(String message, String linkName, String link) {
this(message, linkName, link, LABEL.getBackground(), LABEL.getFont()); this(message, linkName, link, LABEL.getBackground(), LABEL.getFont());
@ -49,36 +70,45 @@ public class MessageWithLink extends JEditorPane {
} }
public MessageWithLink(String frontMessage, String linkName, String link, String backMessage, Color backgroundColor, Font font, Color fontColor) { public MessageWithLink(String frontMessage, String linkName, String link, String backMessage, Color backgroundColor, Font font, Color fontColor) {
super("text/html", "<html><body style=\"" + generateStyle(backgroundColor, font, fontColor) + "\">" + frontMessage + "<a href=\"" + link + "\">" + linkName + "</a>" + backMessage + "</body></html>");
super("text/html", "<html><body style=\"" + LinkStrUtils.generateStyle(backgroundColor, font, fontColor) + "\">" + frontMessage + "<a href=\"" + link + "\">" + linkName + "</a>" + backMessage + "</body></html>");
initListener(link); initListener(link);
setEditable(false); setEditable(false);
setBorder(null); setBorder(null);
} }
protected void initListener(String link) { protected void initListener() {
addHyperlinkListener(new HyperlinkListener() {
@Override addHyperlinkListener(hyperlinkEvent -> {
public void hyperlinkUpdate(HyperlinkEvent e) { try {
if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) { if (hyperlinkEvent.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
try { URL url = hyperlinkEvent.getURL();
Desktop.getDesktop().browse(URI.create(link)); Desktop.getDesktop().browse(url.toURI());
} catch (Exception exception) {
FineLoggerFactory.getLogger().error(exception.getMessage(), exception);
}
} }
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
});
}
protected void initListener(Runnable runnable) {
addHyperlinkListener(e -> {
if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
runnable.run();
} }
}); });
} }
private static StringBuilder generateStyle(Color backgroundColor, Font font, Color fontColor) { protected void initListener(String link) {
// 构建相同风格样式
StringBuilder style = new StringBuilder("font-family:" + font.getFamily() + ";"); initListener(() -> {
style.append("font-weight:").append(font.isBold() ? "bold" : "normal").append(";"); try {
style.append("font-size:").append(font.getSize()).append("pt;"); Desktop.getDesktop().browse(URI.create(link));
style.append("color:rgb(").append(fontColor.getRed()).append(",").append(fontColor.getGreen()).append(",").append(fontColor.getBlue()).append(");"); } catch (Exception e) {
style.append("background-color: rgb(").append(backgroundColor.getRed()).append(",").append(backgroundColor.getGreen()).append(",").append(backgroundColor.getBlue()).append(");"); FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
return style; });
} }
} }

22
designer-base/src/main/java/com/fr/design/extra/exe/ReadUpdateOnlineExecutor.java

@ -1,15 +1,24 @@
package com.fr.design.extra.exe; package com.fr.design.extra.exe;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.extra.PluginsReaderFromStore; import com.fr.design.extra.PluginsReaderFromStore;
import com.fr.design.extra.Process; import com.fr.design.extra.Process;
import com.fr.design.i18n.Toolkit;
import com.fr.design.utils.DesignUtils;
import com.fr.general.SiteBlockedException;
import com.fr.json.JSONArray; import com.fr.json.JSONArray;
import com.fr.json.JSONObject; import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.plugin.view.PluginView; import com.fr.plugin.view.PluginView;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import javax.swing.JOptionPane;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List; import java.util.List;
import static com.fr.design.dialog.FineJOptionPane.OPTION_OK_CANCEL;
/** /**
* Created by vito on 16/4/19. * Created by vito on 16/4/19.
*/ */
@ -41,6 +50,19 @@ public class ReadUpdateOnlineExecutor implements Executor {
jsonArray.put(jsonObject); jsonArray.put(jsonObject);
} }
result = jsonArray.toString(); result = jsonArray.toString();
} catch (SiteBlockedException e1) {
FineJOptionPane.showConfirmDialogWithOkListener(null,
e1.getMessage(),
Toolkit.i18nText("Fine-Design_Basic_Alert"), null, null,
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DesignUtils.visitEnvServerByParameters(
"#management/system/normal",
null,
null);
}
});
} catch (Exception e) { } catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e); FineLoggerFactory.getLogger().error(e.getMessage(), e);
} }

42
designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java

@ -1,12 +1,10 @@
package com.fr.design.file; package com.fr.design.file;
import com.fr.base.chart.chartdata.CallbackEvent; import com.fr.base.chart.chartdata.CallbackEvent;
import com.fr.base.io.BaseBook;
import com.fr.design.DesignerEnvManager; import com.fr.design.DesignerEnvManager;
import com.fr.design.base.mode.DesignModeContext; import com.fr.design.base.mode.DesignModeContext;
import com.fr.design.base.mode.DesignerMode; import com.fr.design.base.mode.DesignerMode;
import com.fr.design.data.DesignTableDataManager; import com.fr.design.data.DesignTableDataManager;
import com.fr.design.file.filter.ClassFilter;
import com.fr.design.i18n.Toolkit; import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrameFileDealerPane; import com.fr.design.mainframe.DesignerFrameFileDealerPane;
@ -16,10 +14,8 @@ import com.fr.design.ui.util.UIUtil;
import com.fr.file.FILE; import com.fr.file.FILE;
import com.fr.file.FileNodeFILE; import com.fr.file.FileNodeFILE;
import com.fr.general.ComparatorUtils; import com.fr.general.ComparatorUtils;
import com.fr.invoke.ClassHelper;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.plugin.context.PluginContext; import com.fr.plugin.context.PluginContext;
import com.fr.plugin.manage.PluginManager;
import com.fr.stable.CoreConstants; import com.fr.stable.CoreConstants;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import com.fr.third.org.apache.commons.io.FilenameUtils; import com.fr.third.org.apache.commons.io.FilenameUtils;
@ -353,7 +349,7 @@ public class HistoryTemplateListCache implements CallbackEvent {
int size = historyList.size(); int size = historyList.size();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
JTemplate<?, ?> template = historyList.get(i); JTemplate<?, ?> template = historyList.get(i);
FILE file = template.templateToStashFile(); FILE file = template.templateToStashFile4Envchange();
if (file != null) { if (file != null) {
stashFILEMap.put(i, file); stashFILEMap.put(i, file);
} }
@ -382,7 +378,8 @@ public class HistoryTemplateListCache implements CallbackEvent {
} }
FineLoggerFactory.getLogger().info("{} is being reloaded", stashedFile.getName()); FineLoggerFactory.getLogger().info("{} is being reloaded", stashedFile.getName());
JTemplate<?, ?> template = historyList.get(i); JTemplate<?, ?> template = historyList.get(i);
template.refreshResource(stashedFile); // 切换环境后,刷新资源并且将暂存的FILE替换到template中
template.refreshResourceAndEditingFILE(stashedFile);
} catch (Exception e) { } catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e); FineLoggerFactory.getLogger().error(e.getMessage(), e);
} }
@ -428,13 +425,10 @@ public class HistoryTemplateListCache implements CallbackEvent {
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
JTemplate<?, ?> template = historyList.get(i); JTemplate<?, ?> template = historyList.get(i);
FILE file = template.getEditingFILE(); FILE file = template.getEditingFILE();
boolean needReload = context == null || needReloadTemplate(context, template); FILE stashFile = template.templateToStashFile();
if (needReload) { if (stashFile != null) {
FILE stashFile = template.templateToStashFile(); FineLoggerFactory.getLogger().info("{} is being reloaded", file.getName());
if (stashFile != null) { template.refreshResource(stashFile);
FineLoggerFactory.getLogger().info("{} is being reloaded", file.getName());
template.refreshResource(stashFile);
}
} }
} }
FineLoggerFactory.getLogger().info("Plugin env change reload all template ended"); FineLoggerFactory.getLogger().info("Plugin env change reload all template ended");
@ -456,28 +450,6 @@ public class HistoryTemplateListCache implements CallbackEvent {
_reloadAllEditingTemplate(null); _reloadAllEditingTemplate(null);
} }
private boolean needReloadTemplate(PluginContext context, JTemplate<?, ?> template) {
BaseBook baseBook = template.getTarget();
if (baseBook != null) {
String name = template.getEditingFILE().getName();
String pluginId = context.getID();
long start = System.currentTimeMillis();
Set<ClassLoader> set = ClassHelper.getClassLoadersByFilter(baseBook, ClassFilter.getInstance());
FineLoggerFactory.getLogger().info("{} find plugin classloader spend: {} ms", name, (System.currentTimeMillis() - start));
if (set != null) {
for (ClassLoader classLoader : set) {
if (ComparatorUtils.equals(pluginId, PluginManager.detectLeakingPlugin(classLoader))) {
return true;
}
}
} else {
// set为null说明 检测classloader 这里返回true直接刷新 兜底行为
return true;
}
}
return false;
}
public void replaceCurrentEditingTemplate(JTemplate<?, ?> jt) { public void replaceCurrentEditingTemplate(JTemplate<?, ?> jt) {
int index = contains(this.editingTemplate); int index = contains(this.editingTemplate);
this.editingTemplate = jt; this.editingTemplate = jt;

39
designer-base/src/main/java/com/fr/design/file/SaveSomeTemplatePane.java

@ -17,7 +17,6 @@ import com.fr.design.mainframe.JTemplate;
import com.fr.general.ComparatorUtils; import com.fr.general.ComparatorUtils;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.stable.ProductConstants;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
@ -43,17 +42,27 @@ public class SaveSomeTemplatePane extends BasicPane {
private boolean isJudgeCurrentEditingTemplate = true; private boolean isJudgeCurrentEditingTemplate = true;
public SaveSomeTemplatePane(boolean isNeedTojudgeCurrent) { public SaveSomeTemplatePane(boolean isNeedTojudgeCurrent) {
this(isNeedTojudgeCurrent, DesignerContext.getDesignerFrame());
}
/**
* 支持自定义设置 dialog的父窗口
* @param isNeedTojudgeCurrent
* @param parent
*/
public SaveSomeTemplatePane(boolean isNeedTojudgeCurrent, Window parent) {
this.setLayout(FRGUIPaneFactory.createBorderLayout()); this.setLayout(FRGUIPaneFactory.createBorderLayout());
if (this.dialog == null) { if (this.dialog == null) {
this.dialog = this.showSmallWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() { this.dialog = this.showSmallWindow(parent, new DialogActionAdapter() {
@Override @Override
public void doOk() { public void doOk() {
isAllSaved = true;
for (int i = 0; i < templateCheckBoxes.length; i++) { for (int i = 0; i < templateCheckBoxes.length; i++) {
if (templateCheckBoxes[i].isSelected()) { if (templateCheckBoxes[i].isSelected()) {
saveSelectedTemplate(unSavedTemplate.get(i)); // 当存在模板保存失败时,视为整体的isAllSaved失败
isAllSaved = saveSelectedTemplate(unSavedTemplate.get(i)) && isAllSaved;
} }
} }
isAllSaved = true;
} }
public void doCancel() { public void doCancel() {
@ -180,31 +189,15 @@ public class SaveSomeTemplatePane extends BasicPane {
} }
private void saveSelectedTemplate(JTemplate<?, ?> specifiedTemplate) { private boolean saveSelectedTemplate(JTemplate<?, ?> specifiedTemplate) {
if (!specifiedTemplate.isSaved()) { if (!specifiedTemplate.isSaved()) {
specifiedTemplate.stopEditing(); specifiedTemplate.stopEditing();
specifiedTemplate.saveTemplate(); 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;
} }
public int saveLastOneTemplate() {
JTemplate<?, ?> specifiedTemplate = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate();
if (!specifiedTemplate.isALLSaved()) {
specifiedTemplate.stopEditing();
int returnVal = FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Utils_Would_You_Like_To_Save") + " \"" + specifiedTemplate.getEditingFILE() + "\" ?",
com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Confirm"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
if (returnVal == JOptionPane.YES_OPTION) {
specifiedTemplate.saveTemplate();
FineLoggerFactory.getLogger().info(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Template_Already_Saved", specifiedTemplate.getEditingFILE().getName()));
}
return returnVal;
}
return JOptionPane.YES_OPTION;
}
protected String title4PopupWindow() { protected String title4PopupWindow() {
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Save"); return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Save");
} }

4
designer-base/src/main/java/com/fr/design/formula/FormulaPane.java

@ -886,9 +886,9 @@ public class FormulaPane extends BasicPane implements KeyListener, UIFormula {
if (checkResult.isValid()) { if (checkResult.isValid()) {
showMessageDialog(checkResult.getTips(), checkResult.isValid(), false); showMessageDialog(checkResult.getTips(), checkResult.isValid(), false);
} else { } else {
int columns = checkResult.getFormulaCoordinates().getColumns(); int columns = checkResult.getFormulaCoordinates().getColumns() + 1;
String position = StringUtils.EMPTY; String position = StringUtils.EMPTY;
if (columns >= 0) { if (columns > 0) {
position = Toolkit.i18nText("Fine-Design_Basic_Formula_The") + columns position = Toolkit.i18nText("Fine-Design_Basic_Formula_The") + columns
+ Toolkit.i18nText("Fine-Design_Basic_Formula_Error_Position") + " "; + Toolkit.i18nText("Fine-Design_Basic_Formula_Error_Position") + " ";
} }

18
designer-base/src/main/java/com/fr/design/gui/frpane/TreeSettingPane.java

@ -62,12 +62,8 @@ public class TreeSettingPane extends BasicPane implements DataCreatorUI {
UILabel buildWayLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Build_Way") + " :"); UILabel buildWayLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Build_Way") + " :");
buildWayPanel.add(buildWayLabel); buildWayPanel.add(buildWayLabel);
buildBox = new UIComboBox(buildWay); buildBox = new UIComboBox(buildWay);
buildBox.addItemListener(new ItemListener() { buildBox.addItemListener(e -> {
cardChanged(buildBox.getSelectedIndex());
@Override
public void itemStateChanged(ItemEvent e) {
cardChanged(buildBox.getSelectedIndex());
}
}); });
buildWayPanel.add(buildBox); buildWayPanel.add(buildBox);
@ -79,7 +75,15 @@ public class TreeSettingPane extends BasicPane implements DataCreatorUI {
cardChanged(0); cardChanged(0);
} }
private void cardChanged(int index) { @Override
public void checkValid() throws Exception {
doBuildBoxSelect(buildBox.getSelectedIndex());
}
private void doBuildBoxSelect(Integer selectedIndex) {
}
private void cardChanged(int index) {
this.remove(controlPane); this.remove(controlPane);
this.remove(autoBuildPane); this.remove(autoBuildPane);

11
designer-base/src/main/java/com/fr/design/gui/ilable/ActionLabel.java

@ -13,11 +13,16 @@ import java.awt.event.MouseEvent;
*/ */
public class ActionLabel extends UILabel { public class ActionLabel extends UILabel {
private ActionListener actionListener; private ActionListener actionListener;
private Color color;
public ActionLabel(String text) { public ActionLabel(String text) {
super(text); this(text, Color.blue);
}
this.setForeground(Color.blue); public ActionLabel(String text, Color color) {
super(text);
this.color = color;
this.setForeground(color);
this.addMouseListener(mouseInputAdapter); this.addMouseListener(mouseInputAdapter);
this.addMouseMotionListener(mouseInputAdapter); this.addMouseMotionListener(mouseInputAdapter);
} }
@ -33,7 +38,7 @@ public class ActionLabel extends UILabel {
public void paintComponent(Graphics _gfx) { public void paintComponent(Graphics _gfx) {
super.paintComponent(_gfx); super.paintComponent(_gfx);
_gfx.setColor(Color.blue); _gfx.setColor(this.color);
_gfx.drawLine(0, this.getHeight() - 1, this.getWidth(), this.getHeight() - 1); _gfx.drawLine(0, this.getHeight() - 1, this.getWidth(), this.getHeight() - 1);
} }

138
designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeRootPane.java

@ -8,75 +8,89 @@ import com.fr.design.layout.FRGUIPaneFactory;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.JPanel; import javax.swing.JPanel;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class TreeRootPane extends BasicPane { public class TreeRootPane extends BasicPane {
// 是否支持多选(checkBoxTree) // 是否支持多选(checkBoxTree)
//private JCheckBox multipleSelection; //private JCheckBox multipleSelection;
private UICheckBox checkTypeCheckBox; private UICheckBox checkTypeCheckBox;
// richer:加载的方式,支持异步加载和完全加载 // richer:加载的方式,支持异步加载和完全加载
private UICheckBox loadTypeCheckBox; private UICheckBox loadTypeCheckBox;
private UICheckBox layerTypeCheckBox; private UICheckBox layerTypeCheckBox;
private UICheckBox returnFullPathCheckBox ; private UICheckBox returnFullPathCheckBox;
public TreeRootPane() { public TreeRootPane() {
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JPanel checkTypePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0(); JPanel checkTypePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0();
checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
checkTypeCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Mutiple_Selection_Or_Not")); checkTypeCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Mutiple_Selection_Or_Not"));
checkTypeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); checkTypeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
checkTypePane.add(checkTypeCheckBox); checkTypePane.add(checkTypeCheckBox);
this.add(checkTypePane); this.add(checkTypePane);
JPanel loadTypePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0(); JPanel loadTypePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0();
checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
loadTypeCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Load_By_Async")); loadTypeCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Widget_Load_By_Async"));
loadTypeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); loadTypeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
loadTypeCheckBox.addMouseListener(new MouseAdapter() {
loadTypePane.add(loadTypeCheckBox); @Override
this.add(loadTypePane); public void mouseClicked(MouseEvent e) {
UICheckBox checkBox = (UICheckBox) e.getSource();
JPanel leafSelectPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0(); doLoadTypeChange(checkBox.isSelected());
checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); }
leafSelectPane.add(layerTypeCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Select_Leaf_Only"))); });
layerTypeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
loadTypePane.add(loadTypeCheckBox);
this.add(leafSelectPane); this.add(loadTypePane);
JPanel leafSelectPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0();
checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
leafSelectPane.add(layerTypeCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Select_Leaf_Only")));
layerTypeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
this.add(leafSelectPane);
JPanel returnFullPathPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0(); JPanel returnFullPathPane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0();
checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); checkTypePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
returnFullPathPane.add(returnFullPathCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Return_Full_Path"))); returnFullPathPane.add(returnFullPathCheckBox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Tree_Return_Full_Path")));
returnFullPathCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); returnFullPathCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
this.add(returnFullPathPane); this.add(returnFullPathPane);
} }
@Override private void doLoadTypeChange(Boolean selected) {
protected String title4PopupWindow() { //给埋点插件提供一个方法,埋埋点用
return "tree"; }
}
@Override
public void populate(TreeAttr treeAttr) { protected String title4PopupWindow() {
checkTypeCheckBox.setSelected(treeAttr.isMultipleSelection()); return "tree";
loadTypeCheckBox.setSelected(treeAttr.isAjax()); }
layerTypeCheckBox.setSelected(treeAttr.isSelectLeafOnly());
public void populate(TreeAttr treeAttr) {
checkTypeCheckBox.setSelected(treeAttr.isMultipleSelection());
loadTypeCheckBox.setSelected(treeAttr.isAjax());
layerTypeCheckBox.setSelected(treeAttr.isSelectLeafOnly());
returnFullPathCheckBox.setSelected(treeAttr.isReturnFullPath()); returnFullPathCheckBox.setSelected(treeAttr.isReturnFullPath());
} }
public TreeAttr update() { public TreeAttr update() {
TreeAttr treeAttr = new TreeAttr(); TreeAttr treeAttr = new TreeAttr();
treeAttr.setMultipleSelection(checkTypeCheckBox.isSelected()); treeAttr.setMultipleSelection(checkTypeCheckBox.isSelected());
treeAttr.setAjax(loadTypeCheckBox.isSelected()); treeAttr.setAjax(loadTypeCheckBox.isSelected());
treeAttr.setSelectLeafOnly(layerTypeCheckBox.isSelected()); treeAttr.setSelectLeafOnly(layerTypeCheckBox.isSelected());
treeAttr.setReturnFullPath(returnFullPathCheckBox.isSelected()); treeAttr.setReturnFullPath(returnFullPathCheckBox.isSelected());
return treeAttr; return treeAttr;
} }
} }

10
designer-base/src/main/java/com/fr/design/gui/style/BackgroundPane.java

@ -34,6 +34,11 @@ public class BackgroundPane extends AbstractBasicStylePane {
//获取当前面板 //获取当前面板
protected BackgroundQuickPane currentPane = null; protected BackgroundQuickPane currentPane = null;
/**
* 记录上次选中的面板
*/
protected BackgroundQuickPane lastSelectedPane = null;
public BackgroundPane() { public BackgroundPane() {
this.initComponents(); this.initComponents();
@ -62,6 +67,9 @@ public class BackgroundPane extends AbstractBasicStylePane {
@Override @Override
public void itemStateChanged(ItemEvent e) { public void itemStateChanged(ItemEvent e) {
cardlayout.show(centerPane, (String) typeComboBox.getSelectedItem()); cardlayout.show(centerPane, (String) typeComboBox.getSelectedItem());
if (e.getStateChange() == ItemEvent.DESELECTED) {
lastSelectedPane = currentPane;
}
currentPane = paneList[typeComboBox.getSelectedIndex()]; currentPane = paneList[typeComboBox.getSelectedIndex()];
fireStateChanged(); fireStateChanged();
} }
@ -144,6 +152,8 @@ public class BackgroundPane extends AbstractBasicStylePane {
pane.populateBean(background); pane.populateBean(background);
typeComboBox.setSelectedIndex(i); typeComboBox.setSelectedIndex(i);
currentPane = paneList[i]; currentPane = paneList[i];
// 填充 初始化
lastSelectedPane = currentPane;
return; return;
} }
} }

5
designer-base/src/main/java/com/fr/design/gui/style/BorderPane.java

@ -15,6 +15,7 @@ import com.fr.design.gui.icombobox.LineComboBox;
import com.fr.design.gui.ilable.UILabel; import com.fr.design.gui.ilable.UILabel;
import com.fr.design.layout.TableLayout; import com.fr.design.layout.TableLayout;
import com.fr.design.layout.TableLayoutHelper; import com.fr.design.layout.TableLayoutHelper;
import com.fr.design.mainframe.backgroundpane.NullBackgroundQuickPane;
import com.fr.design.style.color.NewColorSelectBox; import com.fr.design.style.color.NewColorSelectBox;
import com.fr.design.utils.gui.AdjustWorkBookDefaultStyleUtils; import com.fr.design.utils.gui.AdjustWorkBookDefaultStyleUtils;
import com.fr.general.IOUtils; import com.fr.general.IOUtils;
@ -246,7 +247,9 @@ public class BorderPane extends AbstractBasicStylePane implements GlobalNameObse
style = AdjustWorkBookDefaultStyleUtils.adjustCellElement(Style.DEFAULT_STYLE); style = AdjustWorkBookDefaultStyleUtils.adjustCellElement(Style.DEFAULT_STYLE);
} }
if (backgroundPane.currentPane.isBackgroundChange()) { boolean isSetNullBackground = backgroundPane.currentPane instanceof NullBackgroundQuickPane
&& !(backgroundPane.lastSelectedPane instanceof NullBackgroundQuickPane);
if (backgroundPane.currentPane.isBackgroundChange() || isSetNullBackground) {
style = style.deriveBackground(backgroundPane.update()); style = style.deriveBackground(backgroundPane.update());
} }
if (BORDER_SET.contains(globalNameListener.getGlobalName())) { if (BORDER_SET.contains(globalNameListener.getGlobalName())) {

20
designer-base/src/main/java/com/fr/design/gui/style/FormatPane.java

@ -24,12 +24,22 @@ import com.fr.general.ComparatorUtils;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
import java.math.BigDecimal; import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.math.RoundingMode; import java.math.RoundingMode;
import javax.swing.*; import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.Border; import javax.swing.border.Border;
import javax.swing.border.TitledBorder; import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.ItemEvent; import java.awt.event.ItemEvent;
import java.awt.event.ItemListener; import java.awt.event.ItemListener;
import java.text.Format; import java.text.Format;
@ -54,6 +64,7 @@ public class FormatPane extends AbstractBasicStylePane implements GlobalNameObse
private static final Integer[] TYPES = new Integer[]{ private static final Integer[] TYPES = new Integer[]{
FormatContents.NULL, FormatContents.NUMBER, FormatContents.NULL, FormatContents.NUMBER,
FormatContents.CURRENCY, FormatContents.PERCENT, FormatContents.CURRENCY, FormatContents.PERCENT,
FormatContents.THOUSANDTHS,
FormatContents.SCIENTIFIC, FormatContents.DATE, FormatContents.SCIENTIFIC, FormatContents.DATE,
FormatContents.TIME, FormatContents.TEXT}; FormatContents.TIME, FormatContents.TEXT};
@ -244,6 +255,9 @@ public class FormatPane extends AbstractBasicStylePane implements GlobalNameObse
} else if (pattern.indexOf("%") > 0) { } else if (pattern.indexOf("%") > 0) {
setPatternComboBoxAndList(FormatContents.PERCENT, pattern); setPatternComboBoxAndList(FormatContents.PERCENT, pattern);
this.roundingBox.setSelected(((CoreDecimalFormat) format).getRoundingMode().equals(RoundingMode.HALF_UP)); this.roundingBox.setSelected(((CoreDecimalFormat) format).getRoundingMode().equals(RoundingMode.HALF_UP));
} else if (pattern.indexOf("‰") > 0) {
setPatternComboBoxAndList(FormatContents.THOUSANDTHS, pattern);
this.roundingBox.setSelected(((CoreDecimalFormat) format).getRoundingMode().equals(RoundingMode.HALF_UP));
} else if (pattern.indexOf("E") > 0) { } else if (pattern.indexOf("E") > 0) {
setPatternComboBoxAndList(FormatContents.SCIENTIFIC, pattern); setPatternComboBoxAndList(FormatContents.SCIENTIFIC, pattern);
} else { } else {

7
designer-base/src/main/java/com/fr/design/gui/style/TextFormatPane.java

@ -58,7 +58,7 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName
private static final Integer[] TYPES = new Integer[]{ private static final Integer[] TYPES = new Integer[]{
FormatContents.NULL, FormatContents.NUMBER, FormatContents.NULL, FormatContents.NUMBER,
FormatContents.CURRENCY, FormatContents.PERCENT, FormatContents.CURRENCY, FormatContents.PERCENT,
FormatContents.SCIENTIFIC, FormatContents.THOUSANDTHS, FormatContents.SCIENTIFIC,
FormatContents.DATE, FormatContents.TIME, FormatContents.DATE, FormatContents.TIME,
FormatContents.TEXT}; FormatContents.TEXT};
@ -228,6 +228,9 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName
this.roundingBox.setSelected(((CoreDecimalFormat) format).getRoundingMode().equals(RoundingMode.HALF_UP)); this.roundingBox.setSelected(((CoreDecimalFormat) format).getRoundingMode().equals(RoundingMode.HALF_UP));
} else if (pattern.indexOf("E") > 0) { } else if (pattern.indexOf("E") > 0) {
setPatternComboBoxAndList(FormatContents.SCIENTIFIC, pattern); setPatternComboBoxAndList(FormatContents.SCIENTIFIC, pattern);
} else if (pattern.indexOf("‰") > 0) {
setPatternComboBoxAndList(FormatContents.THOUSANDTHS, pattern);
this.roundingBox.setSelected(((CoreDecimalFormat) format).getRoundingMode().equals(RoundingMode.HALF_UP));
} else { } else {
setPatternComboBoxAndList(FormatContents.NUMBER, pattern); setPatternComboBoxAndList(FormatContents.NUMBER, pattern);
} }
@ -345,7 +348,7 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName
} }
setTextFieldVisible(!isTextOrNull()); setTextFieldVisible(!isTextOrNull());
setPreviewLabelVisible(!isTextOrNull()); setPreviewLabelVisible(!isTextOrNull());
setRoundingBoxVisible(getFormatContents() == FormatContents.PERCENT); setRoundingBoxVisible(getFormatContents() == FormatContents.PERCENT || getFormatContents() == FormatContents.THOUSANDTHS);
} }
} }

6
designer-base/src/main/java/com/fr/design/lock/LockInfoDialog.java

@ -99,7 +99,11 @@ public class LockInfoDialog extends JDialog {
return; return;
} }
final String selectedFilePath = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, TemplateTreePane.getInstance().getFilePath()); 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)), true); TemplateUtils.createAndOpenTemplate(
Toolkit.i18nText("Fine_Design_Template_Lock_Copy"),
new FileNodeFILE(new FileNode(selectedFilePath, false)),
false,
true);
} }
}); });
cancelButton.addActionListener(new ActionListener() { cancelButton.addActionListener(new ActionListener() {

48
designer-base/src/main/java/com/fr/design/login/config/DefaultLoginKeys.java

@ -0,0 +1,48 @@
package com.fr.design.login.config;
import com.fr.log.FineLoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* @author Lanlan
* @version 10.0
* Created by Lanlan on 2022/6/20
*/
public class DefaultLoginKeys {
private static final String FILENAME = "com/fr/design/config/default";
private static final DefaultLoginKeys INSTANCE = new DefaultLoginKeys();
public static DefaultLoginKeys getInstance() {
return INSTANCE;
}
private final Map<String, String> keys = new HashMap<>();
private DefaultLoginKeys() {
Properties properties = load();
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
String name = entry.getKey().toString();
keys.put(name, entry.getValue().toString());
}
}
public String getKey(String name) {
return keys.get(name);
}
private Properties load() {
Properties properties = new Properties();
try (InputStream inputStream = DefaultLoginKeys.class.getClassLoader().getResourceAsStream(FILENAME)) {
properties.load(inputStream);
} catch (IOException e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
return properties;
}
}

9
designer-base/src/main/java/com/fr/design/login/utils/DesignerLoginUtils.java

@ -1,6 +1,7 @@
package com.fr.design.login.utils; package com.fr.design.login.utils;
import com.fr.design.DesignerEnvManager; import com.fr.design.DesignerEnvManager;
import com.fr.design.login.config.DefaultLoginKeys;
import com.fr.design.mainframe.toast.DesignerToastMsgUtil; import com.fr.design.mainframe.toast.DesignerToastMsgUtil;
import com.fr.general.CloudCenter; import com.fr.general.CloudCenter;
import com.fr.general.CloudCenterConfig; import com.fr.general.CloudCenterConfig;
@ -28,8 +29,6 @@ public class DesignerLoginUtils {
private static final String PRODUCT_FINEREPORT = "product-finereport"; private static final String PRODUCT_FINEREPORT = "product-finereport";
private static final String KEY = "i7hP48WAcuTrmxfN";
public static Map<String, String> renderMap() { public static Map<String, String> renderMap() {
Map<String, String> map4Tpl = new HashMap<>(); Map<String, String> map4Tpl = new HashMap<>();
map4Tpl.put("language", GeneralContext.getLocale().toString()); map4Tpl.put("language", GeneralContext.getLocale().toString());
@ -86,7 +85,11 @@ public class DesignerLoginUtils {
jo.put("username", manager.getDesignerLoginUsername()); jo.put("username", manager.getDesignerLoginUsername());
jo.put("source", PRODUCT_FINEREPORT); jo.put("source", PRODUCT_FINEREPORT);
byte[] iv = randomIv(); byte[] iv = randomIv();
return new String(Hex.encode(iv)) + encrypt(jo.toString(), KEY.getBytes(), iv); return new String(Hex.encode(iv)) + encrypt(
jo.toString(),
DefaultLoginKeys.getInstance().getKey("Fine-Designer_Login").getBytes(),
iv
);
} }
private static byte[] randomIv() { private static byte[] randomIv() {

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

@ -172,17 +172,10 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
} }
//关闭前当前模板 停止编辑 //关闭前当前模板 停止编辑
HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().stopEditing(); HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().stopEditing();
SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(true); SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true);
// 只有一个文件未保存时 // 全部保存成功才退出
if (HistoryTemplateListCache.getInstance().getHistoryCount() == 1) { if (saveSomeTemplatePane.showSavePane()) {
int choose = saveSomeTempaltePane.saveLastOneTemplate(); DesignerFrame.this.exit();
if (choose != JOptionPane.CANCEL_OPTION) {
DesignerFrame.this.exit();
}
} else {
if (saveSomeTempaltePane.showSavePane()) {
DesignerFrame.this.exit();
}
} }
} }
@ -1225,4 +1218,4 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
public void setServerConfig(boolean serverConfig) { public void setServerConfig(boolean serverConfig) {
this.serverConfig = serverConfig; this.serverConfig = serverConfig;
} }
} }

101
designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java

@ -190,6 +190,10 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
public JTemplate(T t, FILE file, boolean isNewFile, Parameter[] parameters) { public JTemplate(T t, FILE file, boolean isNewFile, Parameter[] parameters) {
super(t); super(t);
if (isNewFile) {
// REPORT-58486: 必须在初始的UndoState创建前设置主题,使得初始的UndoState就包含了主题效果
setUpTheme4NewTemplate();
}
beforeInit(); beforeInit();
// 判断是否切换设计器状态到禁止拷贝剪切 // 判断是否切换设计器状态到禁止拷贝剪切
if (t.getAttrMark(DesignBanCopyAttrMark.XML_TAG) != null) { if (t.getAttrMark(DesignBanCopyAttrMark.XML_TAG) != null) {
@ -197,7 +201,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
} else if (!DesignModeContext.isVcsMode() && !DesignModeContext.isAuthorityEditing() && !DesignModeContext.isDuchampMode()) { } else if (!DesignModeContext.isVcsMode() && !DesignModeContext.isAuthorityEditing() && !DesignModeContext.isDuchampMode()) {
DesignModeContext.switchTo(com.fr.design.base.mode.DesignerMode.NORMAL); DesignModeContext.switchTo(com.fr.design.base.mode.DesignerMode.NORMAL);
} }
this.template = t; this.template = getTarget();
this.previewType = parserPreviewProvider(t.getPreviewType()); this.previewType = parserPreviewProvider(t.getPreviewType());
this.editingFILE = file; this.editingFILE = file;
this.setLayout(FRGUIPaneFactory.createBorderLayout()); this.setLayout(FRGUIPaneFactory.createBorderLayout());
@ -209,10 +213,6 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
} }
addCenterPane(); addCenterPane();
isNewCreateTpl = isNewFile; isNewCreateTpl = isNewFile;
if (isNewCreateTpl) {
// REPORT-58486: 必须在初始的UndoState创建前设置主题,使得初始的UndoState就包含了主题效果
setUpTheme4NewTemplate();
}
this.undoState = createUndoState(); this.undoState = createUndoState();
initAndStartPlugin(); initAndStartPlugin();
@ -442,20 +442,40 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
stopListenThemeConfig(); stopListenThemeConfig();
} }
/**
* 用于 切换工作目录 时的模板资源暂存
* @return
*/
public FILE templateToStashFile4Envchange() {
FILE file = this.getEditingFILE();
if (file.isEnvFile()) {
// 切换工作目录时,模板锁信息被清除,因此这里需要将环境相关模板文件转化为与环境无关的内存模板文件,再创建暂存文件
return new StashedFILE(new MemFILE(file.getName()), exportBaseBook2ByteArray(), template.suffix());
} else {
// 其它情况下,直接创建暂存文件
return templateToStashFile();
}
}
public FILE templateToStashFile() { public FILE templateToStashFile() {
FILE file = this.getEditingFILE(); FILE file = this.getEditingFILE();
return new StashedFILE(file, exportBaseBook2ByteArray(), template.suffix());
}
private byte[] exportBaseBook2ByteArray() {
try { try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
BaseBook target = this.getTarget(); BaseBook target = this.getTarget();
if (target != null) { if (target != null) {
target.export(outputStream); target.export(outputStream);
return new StashedFILE(file, outputStream.toByteArray(), template.suffix()); return outputStream.toByteArray();
} }
// 如果 target == null 那么这个模板是被模板内存优化功能处理过的,不用处理 // 如果 target == null 那么这个模板是被模板内存优化功能处理过的,不用处理
} catch (Exception e) { } catch (Exception e) {
FineLoggerFactory.getLogger().error("Export BaseBook to Byte Array Failed");
FineLoggerFactory.getLogger().error(e.getMessage(), e); FineLoggerFactory.getLogger().error(e.getMessage(), e);
} }
return null; return new byte[0];
} }
@ -479,19 +499,34 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
UIUtil.invokeLaterIfNeeded(new Runnable() { UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override @Override
public void run() { public void run() {
// 先移除旧的。 refreshDesignerFromResource();
removeCenterPane();
// 加入新的
addCenterPane();
refreshToolArea();
TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()).refreshDockingView();
} }
}); });
} }
protected void refreshDesignerFromResource() {
// 先移除旧的。
removeCenterPane();
// 加入新的
addCenterPane();
refreshToolArea();
TableDataTreePane.getInstance(DesignModelAdapter.getCurrentModelAdapter()).refreshDockingView();
}
/**
* 刷新 模板资源 EditingFILE
* 仅在切换工作目录reload模板时使用
* @param file
*/
public void refreshResourceAndEditingFILE(FILE file) {
// 这里替换EditingFILE是为了在切换工作目录后,将模板文件对象设置成环境无关文件对象
this.editingFILE = file instanceof StashedFILE ? ((StashedFILE) file).getInsideFILE() : file;
refreshResource(file);
}
private void setTargetByFile(FILE file) { private void setTargetByFile(FILE file) {
T newTemplate = JTemplateFactory.asIOFile(file, this.suffix()); T newTemplate = JTemplateFactory.asIOFile(file, this.suffix());
if (newTemplate != null) { if (newTemplate != null) {
@ -1014,7 +1049,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
// 过滤掉本地文件 // 过滤掉本地文件
boolean localFile = getEditingFILE() instanceof FileFILE; boolean localFile = getEditingFILE() instanceof FileFILE;
boolean inconsistent = !localFile && getEditingFILE().exists() boolean inconsistent = !localFile && getEditingFILE().exists()
&& !WorkContext.getCurrent().get(LockInfoOperator.class).isConsistentLock(getEditingFILE().getPath()); && !WorkContext.getCurrent().get(LockInfoOperator.class).isConsistentLock(getEditingFILE().getPath());
if (inconsistent) { if (inconsistent) {
throw new InconsistentLockException(); throw new InconsistentLockException();
} }
@ -1112,6 +1147,20 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
this.listenerList.remove(JTemplateActionListener.class, l); this.listenerList.remove(JTemplateActionListener.class, l);
} }
/**
* 模板保存前触发
*/
public void fireJTemplateSaveBefore() {
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == JTemplateActionListener.class) {
((JTemplateActionListener) listeners[i + 1]).templateSaveBefore(this);
}
}
this.repaint(30);
}
/** /**
* 触发模板关闭 * 触发模板关闭
*/ */
@ -1622,6 +1671,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
} }
private CallbackSaveWorker save(boolean showLoc) { private CallbackSaveWorker save(boolean showLoc) {
fireJTemplateSaveBefore();
FILE editingFILE = this.getEditingFILE(); FILE editingFILE = this.getEditingFILE();
// carl:editingFILE没有,当然不存了,虽然不会有这种情况 // carl:editingFILE没有,当然不存了,虽然不会有这种情况
if (editingFILE == null) { if (editingFILE == null) {
@ -1738,6 +1788,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
refreshToolArea(); refreshToolArea();
} }
DesignerFrameFileDealerPane.getInstance().refresh(); DesignerFrameFileDealerPane.getInstance().refresh();
DesignerFrameFileDealerPane.getInstance().stateChange();
} }
}); });
return worker; return worker;
@ -1879,10 +1930,10 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
protected void setUpTheme4NewTemplate() { protected void setUpTheme4NewTemplate() {
TemplateTheme theme = getUsingTemplateThemeConfig().cachedFetchTheme4NewTemplate(); TemplateTheme theme = getUsingTemplateThemeConfig().cachedFetchTheme4NewTemplate();
TemplateThemeAttrMark themeAttrMark = template.getAttrMark(TemplateThemeAttrMark.XML_TAG); TemplateThemeAttrMark themeAttrMark = getTarget().getAttrMark(TemplateThemeAttrMark.XML_TAG);
if (themeAttrMark == null) { if (themeAttrMark == null) {
themeAttrMark = new TemplateThemeAttrMark(); themeAttrMark = new TemplateThemeAttrMark();
template.addAttrMark(themeAttrMark); getTarget().addAttrMark(themeAttrMark);
} }
themeAttrMark.setName(theme.getName()); themeAttrMark.setName(theme.getName());
themeAttrMark.setDark(theme.isDark()); themeAttrMark.setDark(theme.isDark());
@ -1898,10 +1949,12 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
@Override @Override
public void setTemplateTheme(TemplateTheme newTheme, TemplateThemeCompatible compatible) { public void setTemplateTheme(TemplateTheme newTheme, TemplateThemeCompatible compatible) {
ThemedTemplate.super.setTemplateTheme(newTheme, compatible); if (templateThemeButton != null) {
String name = newTheme.getName(); ThemedTemplate.super.setTemplateTheme(newTheme, compatible);
templateThemeButton.setText(name); String name = newTheme.getName();
templateThemeButton.setToolTipText(name); templateThemeButton.setText(name);
templateThemeButton.setToolTipText(name);
}
} }
/** /**
@ -1917,8 +1970,8 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
} }
public void setDesignerUIMode(){ public void setDesignerUIMode() {
DesignerUIModeConfig.getInstance().setAbsoluteMeasureUIMode(); DesignerUIModeConfig.getInstance().setAbsoluteMeasureUIMode();
} }
} }

12
designer-base/src/main/java/com/fr/design/mainframe/JTemplateActionListener.java

@ -4,9 +4,15 @@ import java.util.EventListener;
public interface JTemplateActionListener extends EventListener { public interface JTemplateActionListener extends EventListener {
public void templateOpened(JTemplate<?, ?> jt); default void templateOpened(JTemplate<?, ?> jt) {
}
public void templateSaved(JTemplate<?, ?> jt); default void templateSaved(JTemplate<?, ?> jt) {
}
public void templateClosed(JTemplate<?, ?> jt); default void templateClosed(JTemplate<?, ?> jt) {
}
default void templateSaveBefore(JTemplate<?, ?> jt) {
}
} }

10
designer-base/src/main/java/com/fr/design/mainframe/JTemplateFactory.java

@ -1,7 +1,12 @@
package com.fr.design.mainframe; package com.fr.design.mainframe;
import com.fr.base.io.BaseBook; import com.fr.base.io.BaseBook;
import com.fr.base.theme.FineColorGather;
import com.fr.base.theme.FineColorManager;
import com.fr.base.theme.FineColorSynchronizer;
import com.fr.base.theme.TemplateThemeCompatible;
import com.fr.file.FILE; import com.fr.file.FILE;
import com.fr.form.main.Form;
import com.fr.stable.CoreConstants; import com.fr.stable.CoreConstants;
import com.fr.stable.StringUtils; import com.fr.stable.StringUtils;
@ -34,10 +39,7 @@ public final class JTemplateFactory {
String[] defaultAppExtensions = app.defaultExtensions(); String[] defaultAppExtensions = app.defaultExtensions();
for (String defaultAppExtension : defaultAppExtensions) { for (String defaultAppExtension : defaultAppExtensions) {
if (defaultAppExtension.equalsIgnoreCase(fileExtension)) { if (defaultAppExtension.equalsIgnoreCase(fileExtension)) {
JTemplate<?, ?> jt = app.openTemplate(file); return app.openTemplate(file);
if (jt != null) {
return jt;
}
} }
} }
} }

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

@ -100,8 +100,7 @@ public class NorthRegionContainerPane extends JPanel {
//优先级为-1,保证最后全面刷新一次 //优先级为-1,保证最后全面刷新一次
GeneralContext.listenPluginRunningChanged(pluginOnRunOrStopListener, pluginFilter); GeneralContext.listenPluginRunningChanged(pluginOnRunOrStopListener, pluginFilter);
// 在设计器启动时仅在最后一个插件启用时候进行刷新一次 如果插件启用过程中存在实现了设计器接口的插件 // 在设计器启动时仅在最后一个插件启用时候进行刷新一次 如果插件启用过程中存在实现了设计器接口的插件
boolean needRefresh = DesignerContext.getDesignerFrame() != null && DesignerContext.getDesignerFrame().isVisible() && existDesignExtraPlugin; if (existDesignExtraPlugin) {
if (needRefresh) {
refreshAll(northEastPane, ad); refreshAll(northEastPane, ad);
} }
} }

37
designer-base/src/main/java/com/fr/design/mainframe/authority/AuthorityTargetObjectCollector.java

@ -0,0 +1,37 @@
package com.fr.design.mainframe.authority;
import com.fr.base.CloneCollector;
import com.fr.base.Formula;
import com.fr.data.impl.NameDatabaseConnection;
import com.fr.data.impl.NameTableData;
import com.fr.report.cell.cellattr.core.group.DSColumn;
import com.fr.stable.FCloneable;
import java.util.ArrayList;
import java.util.List;
public class AuthorityTargetObjectCollector extends CloneCollector {
List<Object> targetObject = new ArrayList<>();
public AuthorityTargetObjectCollector(FCloneable rootObject) {
super(rootObject);
}
@Override
public void collect(Object object) {
if (object instanceof DSColumn || object instanceof Formula
|| object instanceof NameDatabaseConnection || object instanceof NameTableData) {
targetObject.add(object);
}
}
public List<Object> collectTargetObject() {
CloneCollector.setCollector(this);
this.targetObject = new ArrayList<>();
this.collect();
CloneCollector.clearCollector();
return targetObject;
}
}

80
designer-base/src/main/java/com/fr/design/mainframe/authority/JTemplateAuthorityChecker.java

@ -1,24 +1,24 @@
package com.fr.design.mainframe.authority; package com.fr.design.mainframe.authority;
import com.fr.base.CloneCollector;
import com.fr.design.dialog.FineJOptionPane; import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.i18n.Toolkit; import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.JTemplate;
import com.fr.design.mod.ModClassFilter;
import com.fr.file.ConnectionConfig; import com.fr.file.ConnectionConfig;
import com.fr.file.TableDataConfig; import com.fr.file.TableDataConfig;
import com.fr.invoke.ClassHelper;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.stable.Filter;
import com.fr.workspace.WorkContext; import com.fr.workspace.WorkContext;
import com.fr.workspace.server.authority.user.UserAuthority; import com.fr.workspace.server.authority.user.UserAuthority;
import java.util.Collection;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -77,24 +77,21 @@ public class JTemplateAuthorityChecker {
public boolean isAuthority() { public boolean isAuthority() {
long s = System.currentTimeMillis(); long s = System.currentTimeMillis();
//遍历模板对象,根据checkerMap.keySet()把感兴趣的对象找出来 List<Object> targetObjects = getTargetObjects();
Map<String, Collection<Object>> targetObjects = ClassHelper.searchObject(jTemplate.getTarget(), checkerMap.keySet(), ClassFilter.getInstance());
//找到对应的checker,对对象进行检查 //找到对应的checker,对对象进行检查
for (String name : targetObjects.keySet()) { for (Object targetObject : targetObjects) {
String name = targetObject.getClass().getName();
ElementAuthorityChecker checker = checkerMap.get(name); ElementAuthorityChecker checker = checkerMap.get(name);
for (Object object : targetObjects.get(name)) { if (authConnectionNames != null) {
if (authConnectionNames != null) { Set<String> noAuthName = checker.getNoAuthConnectionNames(targetObject, authConnectionNames);
Set<String> noAuthName = checker.getNoAuthConnectionNames(object, authConnectionNames); if (noAuthName != null) {
if (noAuthName != null) { authFailConnectionNames.addAll(noAuthName);
authFailConnectionNames.addAll(noAuthName);
}
} }
if (authDatasetNames != null) { }
Set<String> noAuthName = checker.getNoAuthDatasetNames(object, authDatasetNames); if (authDatasetNames != null) {
if (noAuthName != null) { Set<String> noAuthName = checker.getNoAuthDatasetNames(targetObject, authDatasetNames);
authFailDatasetNames.addAll(noAuthName); if (noAuthName != null) {
} authFailDatasetNames.addAll(noAuthName);
} }
} }
} }
@ -104,6 +101,18 @@ public class JTemplateAuthorityChecker {
return authFailConnectionNames.size() == 0 && authFailDatasetNames.size() == 0; return authFailConnectionNames.size() == 0 && authFailDatasetNames.size() == 0;
} }
private List<Object> getTargetObjects() {
List<Object> targetObjects = new ArrayList<>();
try {
AuthorityTargetObjectCollector authorityTargetObjectCollector
= new AuthorityTargetObjectCollector(jTemplate.getTarget());
targetObjects = authorityTargetObjectCollector.collectTargetObject();
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e, e.getMessage());
}
return targetObjects;
}
public void showAuthorityFailPromptDialog() { public void showAuthorityFailPromptDialog() {
StringBuffer stringBuffer = new StringBuffer(); StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(Toolkit.i18nText("Fine-Design-Basic_Save_Failure")); stringBuffer.append(Toolkit.i18nText("Fine-Design-Basic_Save_Failure"));
@ -151,38 +160,5 @@ public class JTemplateAuthorityChecker {
return stringBuffer.toString(); return stringBuffer.toString();
} }
static class ClassFilter implements Filter<String> {
private static final Set<String> FILTER_SET = new HashSet<>();
private static final Set<String> START_WITH_SET = new HashSet<>();
private static final Filter<String> INSTANCE = new ModClassFilter();
public static Filter<String> getInstance() {
return INSTANCE;
}
static {
FILTER_SET.add("java.awt.image.BufferedImage");
FILTER_SET.add("sun.awt.AppContext");
FILTER_SET.add("com.fr.poly.creator.ECBlockCreator");
FILTER_SET.add("io.netty.channel.nio.SelectedSelectionKeySet");
FILTER_SET.add("com.fr.form.ui.ElementCaseImage");
FILTER_SET.add("this$0");
START_WITH_SET.add("com.fr.design");
}
@Override
public boolean accept(String s) {
if (FILTER_SET.contains(s)) {
return true;
}
for (String start : START_WITH_SET) {
if (s.startsWith(start)) {
return true;
}
}
return false;
}
}
} }

2
designer-base/src/main/java/com/fr/design/mainframe/backgroundpane/NullBackgroundQuickPane.java

@ -35,7 +35,7 @@ public class NullBackgroundQuickPane extends BackgroundQuickPane {
@Override @Override
public boolean isBackgroundChange() { public boolean isBackgroundChange() {
return true; return false;
} }
/** /**

5
designer-base/src/main/java/com/fr/design/mainframe/theme/TemplateThemeEditorPane.java

@ -2,6 +2,7 @@ package com.fr.design.mainframe.theme;
import com.fr.base.theme.FineColorFlushUtils; import com.fr.base.theme.FineColorFlushUtils;
import com.fr.base.theme.FineColorManager; import com.fr.base.theme.FineColorManager;
import com.fr.base.theme.FineColorSynchronizer;
import com.fr.base.theme.TemplateTheme; import com.fr.base.theme.TemplateTheme;
import com.fr.base.theme.TemplateThemeConfig; import com.fr.base.theme.TemplateThemeConfig;
import com.fr.base.theme.settings.ThemedCellStyleList; import com.fr.base.theme.settings.ThemedCellStyleList;
@ -157,10 +158,8 @@ public abstract class TemplateThemeEditorPane<T extends TemplateTheme> extends J
return container; return container;
} }
private void onColorSchemeChanged(List<Color> colors) { private void onColorSchemeChanged(List<Color> colors) {
FineColorManager.FineColorReplaceByColorScheme replaceByColorScheme = new FineColorManager.FineColorReplaceByColorScheme(colors);
T theme = updateBean(); T theme = updateBean();
FineColorFlushUtils.replaceCacheObject(theme, replaceByColorScheme); theme = (T) FineColorSynchronizer.flush(theme, colors);
FineColorManager.traverse(theme, replaceByColorScheme);
populateBean4CustomEditors(theme); populateBean4CustomEditors(theme);
this.repaint(); this.repaint();
} }

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

@ -1,7 +1,6 @@
package com.fr.design.mainframe.theme; package com.fr.design.mainframe.theme;
import com.fr.workspace.WorkContext; import com.fr.workspace.WorkContext;
import com.fr.workspace.server.theme.SupportThemedCellInnerBorderFeature;
import com.fr.workspace.server.theme.ThemedCellBorderFeature; import com.fr.workspace.server.theme.ThemedCellBorderFeature;
/** /**
@ -12,6 +11,6 @@ import com.fr.workspace.server.theme.ThemedCellBorderFeature;
public class ThemedFeatureController { public class ThemedFeatureController {
public static boolean isCellStyleSupportInnerBorder() { public static boolean isCellStyleSupportInnerBorder() {
ThemedCellBorderFeature controller = WorkContext.getCurrent().get(ThemedCellBorderFeature.class); ThemedCellBorderFeature controller = WorkContext.getCurrent().get(ThemedCellBorderFeature.class);
return controller instanceof SupportThemedCellInnerBorderFeature; return controller.isSupport();
} }
} }

144
designer-base/src/main/java/com/fr/design/mainframe/theme/edit/ui/ColorListExtendedPane.java

@ -1,144 +0,0 @@
package com.fr.design.mainframe.theme.edit.ui;
import com.fr.base.theme.FineColorManager;
import com.fr.design.layout.FRGUIPaneFactory;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
/**
* @author Starryi
* @version 1.0
* Created by Starryi on 2021/8/7
*/
public class ColorListExtendedPane extends JPanel implements MouseListener {
public static final int DEFAULT_COLOR_COUNT = 8;
public static final int DEFAULT_EXTENDED_COUNT = 5;
public static final int DEFAULT_COLOR_SIZE = 16;
public static final int DEFAULT_COLOR_GAP = 3;
public static final ExtendedColorComputer DEFAULT_EXTENDED_COMPUTER = new ExtendedColorComputer() {
@Override
public Color computeExtendedColor(Color color, int index, int count) {
return FineColorManager.computeExtendedColor(color, index, count);
}
};
private final boolean selectable;
private final int colorCount;
private final int extendedCount;
private final int boxSize;
private final int boxGap;
private final List<Color> colorList = new ArrayList<>();
private ExtendedColorComputer extendedColorComputer = DEFAULT_EXTENDED_COMPUTER;
private int selectedColorIndex = -1;
private int selectedExtendedIndex = -1;
public ColorListExtendedPane() {
this(false, DEFAULT_COLOR_COUNT, DEFAULT_EXTENDED_COUNT, DEFAULT_COLOR_SIZE, DEFAULT_COLOR_GAP);
}
public ColorListExtendedPane(boolean selectable, int colorCount, int extendedCount, int boxSize, int boxGap) {
setLayout(FRGUIPaneFactory.createBorderLayout());
this.selectable = selectable;
this.colorCount = Math.max(1, colorCount);
this.extendedCount = extendedCount;
this.boxSize = boxSize;
this.boxGap = boxGap;
for (int i = 0; i < colorCount; i++) {
colorList.add(Color.WHITE);
}
int width = colorCount * boxSize + (colorCount - 1) * boxGap;
int height = extendedCount * boxSize + (extendedCount - 1) * boxGap;
setPreferredSize(new Dimension(width, height));
}
public void populate(List<Color> colors) {
if (colors.size() > 0) {
colorList.clear();
colorList.addAll(colors);
repaint();
}
}
public List<Color> update() {
return new ArrayList<>(colorList);
}
public void setExtendedColorComputer(ExtendedColorComputer extendedColorComputer) {
this.extendedColorComputer = extendedColorComputer;
}
@Override
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
int colorIndex = x / (boxSize + boxGap);
int colorX = colorIndex * (boxSize + boxGap);
int extendedIndex = y / boxSize;
int extendedY = extendedIndex * boxSize;
if (colorX <= x && x <= colorX + boxSize && extendedY <= y && y <= extendedY + boxSize) {
selectedColorIndex = colorIndex;
selectedExtendedIndex = extendedIndex;
} else {
selectedColorIndex = -1;
selectedExtendedIndex = -1;
}
repaint();
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
public interface ExtendedColorComputer {
Color computeExtendedColor(Color color, int index, int count);
}
@Override
public void paint(Graphics g) {
super.paint(g);
Color oldColor = g.getColor();
for (int i = 0; i < colorCount; i++) {
int x = i * (boxSize + boxGap);
for (int j = 0; j < extendedCount; j++) {
Color color = extendedColorComputer.computeExtendedColor(colorList.get(i), j, extendedCount);
g.setColor(color);
int y = j * (boxSize + boxGap);
g.fillRect(x, y, boxSize, boxSize);
}
}
g.setColor(oldColor);
}
}

5
designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java

@ -64,6 +64,7 @@ import com.fr.design.os.impl.SupportOSImpl;
import com.fr.design.remote.action.RemoteDesignAuthManagerAction; import com.fr.design.remote.action.RemoteDesignAuthManagerAction;
import com.fr.design.update.actions.SoftwareUpdateAction; import com.fr.design.update.actions.SoftwareUpdateAction;
import com.fr.design.utils.ThemeUtils; import com.fr.design.utils.ThemeUtils;
import com.fr.env.detect.ui.EnvDetectorAction;
import com.fr.general.ComparatorUtils; import com.fr.general.ComparatorUtils;
import com.fr.general.GeneralContext; import com.fr.general.GeneralContext;
import com.fr.general.locale.LocaleAction; import com.fr.general.locale.LocaleAction;
@ -572,7 +573,9 @@ public abstract class ToolBarMenuDock {
if (AlphaFineConfigManager.isALPHALicAvailable()) { if (AlphaFineConfigManager.isALPHALicAvailable()) {
shortCuts.add(new AlphaFineAction()); shortCuts.add(new AlphaFineAction());
} }
shortCuts.add(new EnvDetectorAction());
shortCuts.add(SeparatorDef.DEFAULT); shortCuts.add(SeparatorDef.DEFAULT);
if (DesignerEnvManager.getEnvManager().isOpenDebug()) { if (DesignerEnvManager.getEnvManager().isOpenDebug()) {
OSSupportCenter.buildAction(objects -> shortCuts.add(new FineUIAction()), SupportOSImpl.FINEUI); OSSupportCenter.buildAction(objects -> shortCuts.add(new FineUIAction()), SupportOSImpl.FINEUI);

91
designer-base/src/main/java/com/fr/design/mod/ContentObjectManager.java

@ -1,32 +1,15 @@
package com.fr.design.mod; package com.fr.design.mod;
import com.fr.base.Formula;
import com.fr.base.headerfooter.FormulaHFElement;
import com.fr.base.present.FormulaPresent;
import com.fr.chart.web.ChartHyperRelateCellLink;
import com.fr.chart.web.ChartHyperRelateFloatLink;
import com.fr.data.SimpleDSColumn;
import com.fr.data.condition.FormulaCondition;
import com.fr.data.impl.FormulaDictionary;
import com.fr.data.impl.NameTableData;
import com.fr.design.mod.impl.repalce.JavaScriptContentReplacer; import com.fr.design.mod.impl.repalce.JavaScriptContentReplacer;
import com.fr.design.mod.impl.repalce.VanChartHtmlLabelContentReplacer; import com.fr.design.mod.impl.repalce.VanChartHtmlLabelContentReplacer;
import com.fr.form.main.FormHyperlink; import com.fr.form.ui.Widget;
import com.fr.form.ui.CardSwitchButton;
import com.fr.form.ui.WidgetTitle;
import com.fr.invoke.ClassHelper;
import com.fr.js.JavaScriptImpl; import com.fr.js.JavaScriptImpl;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.chart.base.VanChartHtmlLabel; import com.fr.plugin.chart.base.VanChartHtmlLabel;
import com.fr.report.cell.cellattr.CellExpandAttr;
import com.fr.report.cell.cellattr.CellGUIAttr; import java.util.ArrayList;
import com.fr.report.cell.cellattr.core.RichChar;
import com.fr.report.cell.cellattr.core.group.DSColumn;
import com.fr.report.cell.cellattr.core.group.FunctionGrouper;
import com.fr.report.cell.cellattr.core.group.SelectCount;
import com.fr.stable.Filter;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -49,53 +32,36 @@ public class ContentObjectManager {
/** /**
* 放置所有需要替换内容的对象 * 放置所有需要替换内容的对象
*/ */
private Map<String, Collection<Object>> objectMap; private Map<String, Collection<Object>> objectMap = new HashMap<>();
private final Set<String> set = new HashSet<>();
private final Map<String, ContentReplacer> map = new HashMap<>(); private final Map<String, ContentReplacer> map = new HashMap<>();
private boolean needCollect = false;
private ContentObjectManager() { private ContentObjectManager() {
set.add(Formula.class.getName());
set.add(JavaScriptImpl.class.getName());
set.add(ChartHyperRelateCellLink.class.getName());
set.add(ChartHyperRelateFloatLink.class.getName());
set.add(VanChartHtmlLabel.class.getName());
set.add(NameTableData.class.getName());
set.add(SimpleDSColumn.class.getName());
set.add(DSColumn.class.getName());
set.add(FormHyperlink.class.getName());
set.add(CellExpandAttr.class.getName());
set.add(FormulaCondition.class.getName());
set.add(FormulaDictionary.class.getName());
set.add(FormulaHFElement.class.getName());
set.add(FormulaPresent.class.getName());
set.add(RichChar.class.getName());
set.add(CardSwitchButton.class.getName());
set.add(CellGUIAttr.class.getName());
set.add(SelectCount.class.getName());
set.add(WidgetTitle.class.getName());
set.add(FunctionGrouper.class.getName());
map.put(JavaScriptImpl.class.getName(), new JavaScriptContentReplacer()); map.put(JavaScriptImpl.class.getName(), new JavaScriptContentReplacer());
map.put(VanChartHtmlLabel.class.getName(), new VanChartHtmlLabelContentReplacer()); map.put(VanChartHtmlLabel.class.getName(), new VanChartHtmlLabelContentReplacer());
} }
public void searchObject(Object ob) { @Nullable
objectMap = ClassHelper.searchObject(ob, set, ModClassFilter.getInstance()); public Widget searchObject(Widget widget) {
} try {
needCollect = true;
public void searchObject(Object ob, Filter<String> filter) { objectMap.clear();
objectMap = ClassHelper.searchObject(ob, set, filter); Widget clonedWidget = (Widget) widget.clone();
needCollect = false;
return clonedWidget;
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
} finally {
// 防止抛出异常未重置
needCollect = false;
}
return null;
} }
public void searchObject(Object ob, Set<String> set, Filter<String> filter) {
objectMap = ClassHelper.searchObject(ob, set, filter);
}
public void clearObject() { public void clearObject() {
if (objectMap != null) { objectMap.clear();
objectMap.clear();
}
objectMap = null;
} }
@Nullable @Nullable
@ -103,8 +69,15 @@ public class ContentObjectManager {
return objectMap; return objectMap;
} }
public boolean needContentTip(Object ob, Set<String> nameSet) { public void collect(Object ob) {
objectMap = ClassHelper.searchObject(ob, set, ModClassFilter.getInstance()); if (needCollect) {
Collection<Object> collection = objectMap.computeIfAbsent(ob.getClass().getName(), k -> new ArrayList<>());
collection.add(ob);
}
}
public boolean needContentTip(Widget ob, Set<String> nameSet) {
collect(ob);
for (Map.Entry<String, Collection<Object>> entry : objectMap.entrySet()) { for (Map.Entry<String, Collection<Object>> entry : objectMap.entrySet()) {
for (Object o : entry.getValue()) { for (Object o : entry.getValue()) {
for (String name : nameSet) { for (String name : nameSet) {

3
designer-base/src/main/java/com/fr/design/mod/ContentReplacerCenter.java

@ -70,9 +70,6 @@ public class ContentReplacerCenter {
@Override @Override
public void on(Event event, ContentChangeItem param) { public void on(Event event, ContentChangeItem param) {
itemsMap.put(param.getChangeItem(), param); itemsMap.put(param.getChangeItem(), param);
long start = System.currentTimeMillis();
ContentObjectManager.getInstance().searchObject(param.getObject());
FineLoggerFactory.getLogger().debug("search object spend {} ms", (System.currentTimeMillis() - start));
FineLoggerFactory.getLogger().debug("search result: {}", ContentObjectManager.getInstance().getObjectMap() == null FineLoggerFactory.getLogger().debug("search result: {}", ContentObjectManager.getInstance().getObjectMap() == null
? null : ContentObjectManager.getInstance().getObjectMap().keySet()); ? null : ContentObjectManager.getInstance().getObjectMap().keySet());
List<ContentChangeItem> itemsCopy = new ArrayList<>(itemsMap.values()); List<ContentChangeItem> itemsCopy = new ArrayList<>(itemsMap.values());

26
designer-base/src/main/java/com/fr/design/record/analyzer/DesignerAnalyzerActivator.java

@ -1,8 +1,11 @@
package com.fr.design.record.analyzer; package com.fr.design.record.analyzer;
import com.fr.base.OptimizeUtil; import com.fr.base.OptimizeUtil;
import com.fr.collect.Collect;
import com.fr.design.record.analyzer.Interceptor.CollectInterceptor;
import com.fr.concurrent.NamedThreadFactory; import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.constants.DesignerLaunchStatus; import com.fr.design.constants.DesignerLaunchStatus;
import com.fr.design.record.analyzer.advice.CollectAdvice;
import com.fr.design.record.analyzer.advice.DBMonitorAdvice; import com.fr.design.record.analyzer.advice.DBMonitorAdvice;
import com.fr.design.record.analyzer.advice.FaultToleranceAdvice; import com.fr.design.record.analyzer.advice.FaultToleranceAdvice;
import com.fr.design.record.analyzer.advice.FocusAdvice; import com.fr.design.record.analyzer.advice.FocusAdvice;
@ -19,6 +22,7 @@ import com.fr.module.Activator;
import com.fr.module.extension.Prepare; import com.fr.module.extension.Prepare;
import com.fr.record.analyzer.AnalyzerConfiguration; import com.fr.record.analyzer.AnalyzerConfiguration;
import com.fr.record.analyzer.AnalyzerKey; import com.fr.record.analyzer.AnalyzerKey;
import com.fr.record.analyzer.Assistant;
import com.fr.record.analyzer.DBMetrics; import com.fr.record.analyzer.DBMetrics;
import com.fr.record.analyzer.FineAnalyzer; import com.fr.record.analyzer.FineAnalyzer;
import com.fr.record.analyzer.advice.AnalyzerAdviceKey; import com.fr.record.analyzer.advice.AnalyzerAdviceKey;
@ -26,7 +30,11 @@ import com.fr.record.analyzer.advice.FineAdviceAssistant;
import com.fr.record.analyzer.configuration.AnalyzerAssemblyFactory; import com.fr.record.analyzer.configuration.AnalyzerAssemblyFactory;
import com.fr.record.analyzer.configuration.FineAnalyzerAssemblyFactory; import com.fr.record.analyzer.configuration.FineAnalyzerAssemblyFactory;
import com.fr.stable.collections.CollectionUtils; import com.fr.stable.collections.CollectionUtils;
import com.fr.third.net.bytebuddy.description.type.TypeDescription;
import com.fr.third.net.bytebuddy.dynamic.DynamicType;
import com.fr.third.net.bytebuddy.implementation.MethodDelegation;
import com.fr.third.net.bytebuddy.matcher.ElementMatchers; import com.fr.third.net.bytebuddy.matcher.ElementMatchers;
import com.fr.third.net.bytebuddy.utility.JavaModule;
import com.fr.tolerance.FaultTolerance; import com.fr.tolerance.FaultTolerance;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -117,6 +125,24 @@ public class DesignerAnalyzerActivator extends Activator implements Prepare {
ElementMatchers.isAnnotatedWith(FaultTolerance.class), ElementMatchers.isAnnotatedWith(FaultTolerance.class),
FaultToleranceAdvice.class FaultToleranceAdvice.class
)); ));
// 保持M1 可用
addMutable(AnalyzerKey.KEY, AnalyzerConfiguration.create(new Assistant() {
@Override
public DynamicType.Builder<?> supply(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
return builder
.method(ElementMatchers.isAnnotatedWith(Collect.class))
.intercept(MethodDelegation.to(CollectInterceptor.class));
}
}));
addMutable(AnalyzerAdviceKey.KEY, FineAdviceAssistant.create(
ElementMatchers.isAnnotatedWith(Collect.class),
CollectAdvice.class
));
} }

28
designer-base/src/main/java/com/fr/design/record/analyzer/Interceptor/CollectInterceptor.java

@ -0,0 +1,28 @@
package com.fr.design.record.analyzer.Interceptor;
import com.fr.design.mod.ContentObjectManager;
import com.fr.third.net.bytebuddy.implementation.bind.annotation.AllArguments;
import com.fr.third.net.bytebuddy.implementation.bind.annotation.Origin;
import com.fr.third.net.bytebuddy.implementation.bind.annotation.RuntimeType;
import com.fr.third.net.bytebuddy.implementation.bind.annotation.SuperCall;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
/**
* 收集
*
* @author hades
* @version 11.0
* Created by hades on 2022/6/17
*/
public class CollectInterceptor {
@RuntimeType
public static Object intercept(@Origin Method method,
@SuperCall Callable<?> callable,
@AllArguments Object[] args) throws Exception {
Object result = callable.call();
ContentObjectManager.getInstance().collect(result);
return result;
}
}

26
designer-base/src/main/java/com/fr/design/record/analyzer/advice/CollectAdvice.java

@ -0,0 +1,26 @@
package com.fr.design.record.analyzer.advice;
import com.fr.design.mod.ContentObjectManager;
import com.fr.design.record.analyzer.DesignerAnalyzerAdvice;
import com.fr.third.net.bytebuddy.asm.Advice;
import com.fr.third.net.bytebuddy.implementation.bytecode.assign.Assigner;
import java.lang.reflect.Method;
/**
* @author hades
* @version 11.0
* Created by hades on 2022/6/17
*/
public class CollectAdvice implements DesignerAnalyzerAdvice {
@Advice.OnMethodExit(onThrowable = Exception.class)
public static void onMethodExit(@Advice.This(optional = true, typing = Assigner.Typing.DYNAMIC) Object self,
@Advice.Origin Method method,
@Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] args,
@Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object result) throws Exception {
ContentObjectManager.getInstance().collect(result);
}
}

15
designer-base/src/main/java/com/fr/design/style/FormatPane.java

@ -52,6 +52,7 @@ public class FormatPane extends BasicPane {
private UIRadioButton numberRadioButton; private UIRadioButton numberRadioButton;
private UIRadioButton currencyRadioButton; private UIRadioButton currencyRadioButton;
private UIRadioButton percentRadioButton; private UIRadioButton percentRadioButton;
private UIRadioButton thousandthsRadioButton;
private UIRadioButton scientificRadioButton; private UIRadioButton scientificRadioButton;
private UIRadioButton dateRadioButton; private UIRadioButton dateRadioButton;
private UIRadioButton timeRadioButton; private UIRadioButton timeRadioButton;
@ -99,6 +100,7 @@ public class FormatPane extends BasicPane {
categoryButtonGroup.add(numberRadioButton); categoryButtonGroup.add(numberRadioButton);
categoryButtonGroup.add(currencyRadioButton); categoryButtonGroup.add(currencyRadioButton);
categoryButtonGroup.add(percentRadioButton); categoryButtonGroup.add(percentRadioButton);
categoryButtonGroup.add(thousandthsRadioButton);
categoryButtonGroup.add(scientificRadioButton); categoryButtonGroup.add(scientificRadioButton);
categoryButtonGroup.add(dateRadioButton); categoryButtonGroup.add(dateRadioButton);
categoryButtonGroup.add(timeRadioButton); categoryButtonGroup.add(timeRadioButton);
@ -108,6 +110,7 @@ public class FormatPane extends BasicPane {
leftControlPane.add(this.createRadioCenterPane(numberRadioButton)); leftControlPane.add(this.createRadioCenterPane(numberRadioButton));
leftControlPane.add(this.createRadioCenterPane(currencyRadioButton)); leftControlPane.add(this.createRadioCenterPane(currencyRadioButton));
leftControlPane.add(this.createRadioCenterPane(percentRadioButton)); leftControlPane.add(this.createRadioCenterPane(percentRadioButton));
leftControlPane.add(this.createRadioCenterPane(thousandthsRadioButton));
leftControlPane.add(this.createRadioCenterPane(scientificRadioButton)); leftControlPane.add(this.createRadioCenterPane(scientificRadioButton));
leftControlPane.add(this.createRadioCenterPane(dateRadioButton)); leftControlPane.add(this.createRadioCenterPane(dateRadioButton));
leftControlPane.add(this.createRadioCenterPane(timeRadioButton)); leftControlPane.add(this.createRadioCenterPane(timeRadioButton));
@ -136,6 +139,8 @@ public class FormatPane extends BasicPane {
currencyRadioButton.setMnemonic('C'); currencyRadioButton.setMnemonic('C');
percentRadioButton = new UIRadioButton(FormatField.getInstance().getName(FormatContents.PERCENT)); percentRadioButton = new UIRadioButton(FormatField.getInstance().getName(FormatContents.PERCENT));
percentRadioButton.setMnemonic('P'); percentRadioButton.setMnemonic('P');
thousandthsRadioButton = new UIRadioButton(FormatField.getInstance().getName(FormatContents.THOUSANDTHS));
thousandthsRadioButton.setMnemonic('Q');
scientificRadioButton = new UIRadioButton(FormatField.getInstance().getName(FormatContents.SCIENTIFIC)); scientificRadioButton = new UIRadioButton(FormatField.getInstance().getName(FormatContents.SCIENTIFIC));
scientificRadioButton.setMnemonic('S'); scientificRadioButton.setMnemonic('S');
dateRadioButton = new UIRadioButton(FormatField.getInstance().getName(FormatContents.DATE)); dateRadioButton = new UIRadioButton(FormatField.getInstance().getName(FormatContents.DATE));
@ -149,6 +154,7 @@ public class FormatPane extends BasicPane {
numberRadioButton.addActionListener(radioActionListener); numberRadioButton.addActionListener(radioActionListener);
currencyRadioButton.addActionListener(radioActionListener); currencyRadioButton.addActionListener(radioActionListener);
percentRadioButton.addActionListener(radioActionListener); percentRadioButton.addActionListener(radioActionListener);
thousandthsRadioButton.addActionListener(radioActionListener);
scientificRadioButton.addActionListener(radioActionListener); scientificRadioButton.addActionListener(radioActionListener);
dateRadioButton.addActionListener(radioActionListener); dateRadioButton.addActionListener(radioActionListener);
timeRadioButton.addActionListener(radioActionListener); timeRadioButton.addActionListener(radioActionListener);
@ -234,6 +240,9 @@ public class FormatPane extends BasicPane {
} else if (pattern.endsWith("%")) { } else if (pattern.endsWith("%")) {
this.percentRadioButton.setSelected(true); this.percentRadioButton.setSelected(true);
this.applyRadioActionListener(this.percentRadioButton); this.applyRadioActionListener(this.percentRadioButton);
} else if (pattern.endsWith("‰")){
this.thousandthsRadioButton.setSelected(true);
this.applyRadioActionListener(this.thousandthsRadioButton);
} else if (pattern.indexOf("E") > 0) { } else if (pattern.indexOf("E") > 0) {
this.scientificRadioButton.setSelected(true); this.scientificRadioButton.setSelected(true);
this.applyRadioActionListener(this.scientificRadioButton); this.applyRadioActionListener(this.scientificRadioButton);
@ -259,6 +268,7 @@ public class FormatPane extends BasicPane {
scientificRadioButton.setEnabled(false); scientificRadioButton.setEnabled(false);
textRadioButton.setEnabled(false); textRadioButton.setEnabled(false);
percentRadioButton.setEnabled(false); percentRadioButton.setEnabled(false);
thousandthsRadioButton.setEnabled(false);
nullRadioButton.setEnabled(false); nullRadioButton.setEnabled(false);
dateRadioButton.setEnabled(false); dateRadioButton.setEnabled(false);
timeRadioButton.setEnabled(false); timeRadioButton.setEnabled(false);
@ -285,6 +295,7 @@ public class FormatPane extends BasicPane {
numberRadioButton.setEnabled(false); numberRadioButton.setEnabled(false);
currencyRadioButton.setEnabled(false); currencyRadioButton.setEnabled(false);
percentRadioButton.addActionListener(radioActionListener); percentRadioButton.addActionListener(radioActionListener);
thousandthsRadioButton.setEnabled(false);
scientificRadioButton.setEnabled(false); scientificRadioButton.setEnabled(false);
dateRadioButton.setEnabled(false); dateRadioButton.setEnabled(false);
timeRadioButton.setEnabled(false); timeRadioButton.setEnabled(false);
@ -333,6 +344,8 @@ public class FormatPane extends BasicPane {
return FormatContents.CURRENCY; return FormatContents.CURRENCY;
else if (percentRadioButton.isSelected()) else if (percentRadioButton.isSelected())
return FormatContents.PERCENT; return FormatContents.PERCENT;
else if (thousandthsRadioButton.isSelected())
return FormatContents.THOUSANDTHS;
else if (scientificRadioButton.isSelected()) else if (scientificRadioButton.isSelected())
return FormatContents.SCIENTIFIC; return FormatContents.SCIENTIFIC;
else if (dateRadioButton.isSelected()) else if (dateRadioButton.isSelected())
@ -453,6 +466,8 @@ public class FormatPane extends BasicPane {
contents = FormatContents.CURRENCY; contents = FormatContents.CURRENCY;
} else if (ComparatorUtils.equals(source,percentRadioButton)) { } else if (ComparatorUtils.equals(source,percentRadioButton)) {
contents = FormatContents.PERCENT; contents = FormatContents.PERCENT;
}else if (ComparatorUtils.equals(source,thousandthsRadioButton)){
contents = FormatContents.THOUSANDTHS;
} else if (ComparatorUtils.equals(source,scientificRadioButton)) { } else if (ComparatorUtils.equals(source,scientificRadioButton)) {
contents = FormatContents.SCIENTIFIC; contents = FormatContents.SCIENTIFIC;
} else if (ComparatorUtils.equals(source,dateRadioButton)) { } else if (ComparatorUtils.equals(source,dateRadioButton)) {

2
designer-base/src/main/java/com/fr/design/style/color/ColorPicker.java

@ -4,6 +4,7 @@ package com.fr.design.style.color;
* Created by plough on 2016/12/22. * Created by plough on 2016/12/22.
*/ */
import com.fr.design.DesignerEnvManager;
import com.fr.design.utils.gui.GUICoreUtils; import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.general.IOUtils; import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
@ -137,6 +138,7 @@ public class ColorPicker extends JDialog implements ActionListener {
timer.stop(); timer.stop();
if (setColor) { if (setColor) {
colorSelectable.setColor(colorToSet); colorSelectable.setColor(colorToSet);
DesignerEnvManager.getEnvManager().getColorConfigManager().addToColorQueue(new Color(colorToSet.getRGB()));
} }
this.dispose(); this.dispose();
} }

29
designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java

@ -1,9 +1,12 @@
package com.fr.design.ui.util; package com.fr.design.ui.util;
import com.fr.log.FineLoggerFactory; import com.fr.log.FineLoggerFactory;
import com.fr.third.guava.base.Stopwatch;
import com.fr.third.guava.base.Supplier;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import java.util.concurrent.TimeUnit;
/** /**
* 一些常用的 GUI 工具 * 一些常用的 GUI 工具
@ -52,4 +55,30 @@ public class UIUtil {
} }
} }
} }
/**
* 有些时候交互上需要有一些等待的效果
* 如果没有等待到 会让交互失去作用
*
* @param supplier 结果
* @param timeout 超时
* @param timeUnit 单位
* @return 结果
*/
public static <T> T waitUntil(Supplier<T> supplier, long timeout, TimeUnit timeUnit) {
Stopwatch st = Stopwatch.createStarted();
T result = supplier.get();
long elapsed = st.elapsed(timeUnit);
long minus = timeout - elapsed;
if (minus > 0) {
long value = timeUnit.toMillis(minus);
try {
Thread.sleep(value);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
return result;
}
} }

22
designer-base/src/main/java/com/fr/design/update/ui/dialog/UpdateMainDialog.java

@ -24,6 +24,7 @@ import com.fr.design.update.ui.widget.UpdateInfoTable;
import com.fr.design.update.ui.widget.UpdateInfoTableCellRender; import com.fr.design.update.ui.widget.UpdateInfoTableCellRender;
import com.fr.design.update.ui.widget.UpdateInfoTableModel; import com.fr.design.update.ui.widget.UpdateInfoTableModel;
import com.fr.design.update.ui.widget.UpdateInfoTextAreaCellRender; import com.fr.design.update.ui.widget.UpdateInfoTextAreaCellRender;
import com.fr.design.utils.DesignUtils;
import com.fr.design.utils.gui.GUICoreUtils; import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.general.*; import com.fr.general.*;
import com.fr.general.http.HttpToolbox; import com.fr.general.http.HttpToolbox;
@ -56,6 +57,7 @@ import java.util.*;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import static com.fr.design.dialog.FineJOptionPane.OPTION_OK_CANCEL;
import static java.nio.charset.StandardCharsets.*; import static java.nio.charset.StandardCharsets.*;
import static javax.swing.JOptionPane.QUESTION_MESSAGE; import static javax.swing.JOptionPane.QUESTION_MESSAGE;
@ -350,7 +352,25 @@ public class UpdateMainDialog extends UIDialog {
new SwingWorker<JSONObject, Void>() { new SwingWorker<JSONObject, Void>() {
@Override @Override
protected JSONObject doInBackground() throws Exception { protected JSONObject doInBackground() throws Exception {
return new JSONObject(HttpToolbox.get(CloudCenter.getInstance().acquireUrlByKind("jar11.update"))); try {
String url = CloudCenter.getInstance().acquireUrlByKind("jar11.update");
return new JSONObject(HttpToolbox.get(url));
} catch (SiteBlockedException e) {
stopLoading();
FineJOptionPane.showConfirmDialogWithOkListener(null,
e.getMessage(),
Toolkit.i18nText("Fine-Design_Basic_Alert"), null, null,
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DesignUtils.visitEnvServerByParameters(
"#management/system/normal",
null,
null);
}
});
}
return null;
} }
@Override @Override

30
designer-base/src/main/java/com/fr/design/utils/ColorUtils.java

@ -0,0 +1,30 @@
package com.fr.design.utils;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.util.Arrays;
/**
* created by Harrison on 2022/05/29
**/
public class ColorUtils {
/**
* 递归的同步颜色
*
* @param color 颜色
*/
public static void syncBackground(Component component, Color color) {
component.setBackground(color);
if (component instanceof Container) {
Container container = (Container) component;
Component[] components = container.getComponents();
if (components != null) {
Arrays.stream(components).forEach((e) -> syncBackground(e, color));
}
}
}
}

63
designer-base/src/main/java/com/fr/design/utils/LinkStrUtils.java

@ -0,0 +1,63 @@
package com.fr.design.utils;
import com.fr.design.gui.ilable.UILabel;
import com.fr.stable.StringUtils;
import javax.swing.JComponent;
import java.awt.Color;
import java.awt.Font;
/**
* created by Harrison on 2022/05/24
**/
public class LinkStrUtils {
public static final UILabel LABEL = new UILabel();
public static UILabel generateLabel(String html, JComponent templateLabel) {
String style = generateStyle(templateLabel.getBackground(), templateLabel.getFont(), templateLabel.getForeground());
String fullHtml = generateHtmlTag(style, html);
return new UILabel(fullHtml);
}
public static String generateHtmlTag(String html) {
String defaultStyle = generateDefaultStyle();
return generateHtmlTag(defaultStyle, html);
}
public static String generateHtmlTag(String style, String html) {
if (StringUtils.isEmpty(style)) {
throw new NullPointerException("style");
}
if (StringUtils.isEmpty(html)) {
throw new NullPointerException("html");
}
return "<html><body style=\"" + style + "\">" + html + "</body></html>";
}
public static String generateLinkTag(String link, String text) {
return "<a href=\"" + link + "\">" + text + "</a>";
}
public static String generateStyle(Color backgroundColor, Font font, Color fontColor) {
// 构建相同风格样式
StringBuilder style = new StringBuilder("font-family:" + font.getFamily() + ";");
style.append("font-weight:").append(font.isBold() ? "bold" : "normal").append(";");
style.append("font-size:").append(font.getSize()).append("pt;");
style.append("color:rgb(").append(fontColor.getRed()).append(",").append(fontColor.getGreen()).append(",").append(fontColor.getBlue()).append(");");
style.append("background-color: rgb(").append(backgroundColor.getRed()).append(",").append(backgroundColor.getGreen()).append(",").append(backgroundColor.getBlue()).append(");");
return style.toString();
}
public static String generateDefaultStyle() {
return generateStyle(LABEL.getBackground(), LABEL.getFont(), LABEL.getForeground());
}
}

20
designer-base/src/main/java/com/fr/design/utils/TemplateUtils.java

@ -27,7 +27,16 @@ import java.io.OutputStream;
*/ */
public class TemplateUtils { public class TemplateUtils {
public static void createAndOpenTemplate(String prefix, FILE file, boolean needOpen) { /**
* 创建新的模板文件并打开模板
* @param prefix 模板文件名称前缀
* @param file 模板文件
* @param createByEditingTemplate 是否根据 当前编辑模板 来创建新模板
* 为true时以CurrentEditingTemplate为准创建新模板
* 为false时以传入的File文件为准创建新模板此文件可以不是编辑状态
* @param openNewTemplate 是否需要在创建后打开模板
*/
public static void createAndOpenTemplate(String prefix, FILE file, boolean createByEditingTemplate, boolean openNewTemplate) {
String fileName = file.getName(); String fileName = file.getName();
String oldPath = file.getPath(); String oldPath = file.getPath();
int indexOfLastDot = fileName.lastIndexOf(CoreConstants.DOT); int indexOfLastDot = fileName.lastIndexOf(CoreConstants.DOT);
@ -49,19 +58,18 @@ public class TemplateUtils {
if (isOk(result)) { if (isOk(result)) {
file = fileChooserPane.getSelectedFILE(); file = fileChooserPane.getSelectedFILE();
_createAndOpenTemplate(file, oldPath, needOpen); _createAndOpenTemplate(file, oldPath, createByEditingTemplate, openNewTemplate);
} }
} }
private static void _createAndOpenTemplate(FILE file, String oldPath, boolean needOpen){ private static void _createAndOpenTemplate(FILE file, String oldPath, boolean createByEditingTemplate, boolean openNewTemplate){
new SwingWorker<Void, Void>() { new SwingWorker<Void, Void>() {
@Override @Override
protected Void doInBackground() throws Exception { protected Void doInBackground() throws Exception {
byte[] content = new byte[0]; byte[] content = new byte[0];
if (!needOpen) { if (createByEditingTemplate) {
// 从当前编辑模板中生成备份文件 // 从当前编辑模板中生成备份文件
JTemplate<?, ?> template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); JTemplate<?, ?> template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
content = template.exportData(); content = template.exportData();
@ -95,7 +103,7 @@ public class TemplateUtils {
protected void done() { protected void done() {
try { try {
get(); get();
if (needOpen) { if (openNewTemplate) {
DesignerContext.getDesignerFrame().openTemplate(file); DesignerContext.getDesignerFrame().openTemplate(file);
} }
// 备份成功刷新下目录树 展示出来备份的模板 // 备份成功刷新下目录树 展示出来备份的模板

21
designer-base/src/main/java/com/fr/design/versioncheck/VersionCheckUtils.java

@ -52,6 +52,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.swing.SwingWorker;
/** /**
* @author pengda * @author pengda
@ -95,9 +96,23 @@ public class VersionCheckUtils {
} }
public static void showVersionCheckDialog(String envName) { public static void showVersionCheckDialog(String envName) {
if (!VersionCheckUtils.versionCheck(envName)) { new SwingWorker<Boolean, Void>() {
showNotificationDialog(envName); @Override
} protected Boolean doInBackground() {
return !VersionCheckUtils.versionCheck(envName);
}
@Override
protected void done() {
try {
if (get()) {
showNotificationDialog(envName);
}
} catch (Exception e) {
FineLoggerFactory.getLogger().warn(e.getMessage(), e);
}
}
}.execute();
} }
private static void showNotificationDialog(String envName) { private static void showNotificationDialog(String envName) {

37
designer-base/src/main/java/com/fr/design/worker/save/SaveFailureHandler.java

@ -22,6 +22,7 @@ import javax.swing.JOptionPane;
* @version 11.0 * @version 11.0
* Created by hades on 2021/12/7 * Created by hades on 2021/12/7
*/ */
@SuppressWarnings("all")
public class SaveFailureHandler implements ThrowableHandler { public class SaveFailureHandler implements ThrowableHandler {
private static final SaveFailureHandler INSTANCE = new SaveFailureHandler(); private static final SaveFailureHandler INSTANCE = new SaveFailureHandler();
@ -70,7 +71,7 @@ public class SaveFailureHandler implements ThrowableHandler {
@Override @Override
public boolean process(Throwable e) { public boolean process(Throwable e) {
if (e.getCause() instanceof UnLockedException || e instanceof UnLockedException) { if (e.getCause() instanceof UnLockedException || e instanceof UnLockedException) {
processByBack(Toolkit.i18nText("Fine_Design_Template_Has_Been_UnLocked")); processUnLocked(Toolkit.i18nText("Fine_Design_Template_Has_Been_UnLocked"));
return true; return true;
} }
return false; return false;
@ -81,7 +82,7 @@ public class SaveFailureHandler implements ThrowableHandler {
@Override @Override
public boolean process(Throwable e) { public boolean process(Throwable e) {
if (e.getCause() instanceof InconsistentLockException || e instanceof InconsistentLockException) { if (e.getCause() instanceof InconsistentLockException || e instanceof InconsistentLockException) {
processByBack(Toolkit.i18nText("Fine_Design_Template_Save_Failed_By_Lock_Inconsistency")); processInconsistentLock(Toolkit.i18nText("Fine_Design_Template_Save_Failed_By_Lock_Inconsistency"));
return true; return true;
} }
return false; return false;
@ -102,7 +103,7 @@ public class SaveFailureHandler implements ThrowableHandler {
}; };
protected void processByBack(String tip) { protected void processUnLocked(String tip) {
int option = FineJOptionPane.showOptionDialog(DesignerContext.getDesignerFrame(), int option = FineJOptionPane.showOptionDialog(DesignerContext.getDesignerFrame(),
tip, tip,
Toolkit.i18nText("Fine-Design_Basic_Alert"), Toolkit.i18nText("Fine-Design_Basic_Alert"),
@ -113,10 +114,36 @@ public class SaveFailureHandler implements ThrowableHandler {
if (option == JOptionPane.YES_OPTION) { if (option == JOptionPane.YES_OPTION) {
JTemplate<?, ?> template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate(); JTemplate<?, ?> template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
if (template != null) { if (template != null) {
TemplateUtils.createAndOpenTemplate(Toolkit.i18nText("Fine_Design_Template_Backup"), new FileNodeFILE(new FileNode(template.getPath(), false)), false); TemplateUtils.createAndOpenTemplate(
Toolkit.i18nText("Fine_Design_Template_Backup"),
new FileNodeFILE(new FileNode(template.getPath(), false)),
true,
false);
}
}
}
protected void processInconsistentLock(String tip) {
int option = FineJOptionPane.showOptionDialog(DesignerContext.getDesignerFrame(),
tip,
Toolkit.i18nText("Fine-Design_Basic_Alert"),
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE,
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);
} }
} }
} }
} }
} }

27
designer-base/src/main/java/com/fr/env/EnvPrepare.java vendored

@ -0,0 +1,27 @@
package com.fr.env;
import com.fr.env.detect.EnvDetectorCenter;
import com.fr.module.Activator;
/**
* 设计器环境准备
* 更多的是一些钩子需要在环境启动切换时进行处理
* 使用监听 {@link com.fr.workspace.WorkspaceEvent} 只能满足
* before -> stop -> start -> after
* 现在支持 =>
* before -> stop -> prepare -> start -> after
*
* created by Harrison on 2022/05/29
**/
public class EnvPrepare extends Activator {
@Override
public void start() {
EnvDetectorCenter.getInstance().init();
}
@Override
public void stop() {
EnvDetectorCenter.getInstance().destroy();
}
}

226
designer-base/src/main/java/com/fr/env/detect/EnvDetectorCenter.java vendored

@ -0,0 +1,226 @@
package com.fr.env.detect;
import com.fr.common.util.Collections;
import com.fr.design.components.notification.NotificationDialog;
import com.fr.design.components.notification.NotificationDialogProperties;
import com.fr.design.components.notification.NotificationModel;
import com.fr.design.constants.DesignerLaunchStatus;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.ui.util.UIUtil;
import com.fr.env.detect.base.DetectorBridge;
import com.fr.env.detect.base.DetectorUtil;
import com.fr.env.detect.base.EnvDetectorConfig;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorStatus;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
import com.fr.event.Null;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.core.UUID;
import com.fr.task.Once;
import com.fr.update.delay.DelayHelper;
import com.fr.workspace.Workspace;
import com.fr.workspace.WorkspaceEvent;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 环境检测中心
*
* created by Harrison on 2022/05/27
**/
public class EnvDetectorCenter {
private final Listener<Null> START_UP_COMPLETE_LISTENER = new Listener<Null>() {
@Override
public void on(Event event, Null param) {
// startup 的监听,执行一次即可
EventDispatcher.stopListen(this);
FineLoggerFactory.getLogger().debug("startup complete, start detecting env");
stop();
}
};
private final Listener<Workspace> AFTER_SWITCH_LISTENER = new Listener<Workspace>() {
@Override
public void on(Event event, Workspace param) {
FineLoggerFactory.getLogger().debug("switch env complete, start detecting env");
stop();
}
};
private final Once launchOnce = new Once(() -> {
// 添加启动完成监听
EventDispatcher.listen(DesignerLaunchStatus.STARTUP_COMPLETE, START_UP_COMPLETE_LISTENER);
// 切换完成后的监听
EventDispatcher.listen(WorkspaceEvent.AfterSwitch, AFTER_SWITCH_LISTENER);
});
private final AtomicReference<DetectorProcess> PROCESS = new AtomicReference<>();
/**
* 当前还有什么动作未执行
* 如果切换环境这里的动作是要被清空的
* 从而防止切换环境后, 上一个动作的环境延续过来
*/
private final Set<String> pendingActions = new HashSet<>();
public static EnvDetectorCenter getInstance() {
return EnvDetectorCenterHolder.INSTANCE;
}
private static class EnvDetectorCenterHolder {
private static final EnvDetectorCenter INSTANCE = new EnvDetectorCenter();
}
/**
* 初始化
*/
public void init() {
// 如果已经启动了,则不再启动
if (PROCESS.get() != null) {
return;
}
start();
// 默认是启动
PROCESS.set(DetectorProcess.DESIGN_LAUNCH);
launchOnce.run();
}
/**
* 销毁一般用在模块关闭中
*/
public void destroy() {
// 清空
pendingActions.clear();
// 重置内容
DetectorBridge.getInstance().reset();
// 关闭逻辑
DetectorBridge.getInstance().stop();
PROCESS.set(null);
}
/**
* 启动
*/
public void start() {
DetectorBridge.getInstance().start();
}
/**
* 关闭
*/
public void stop() {
// 结束
DetectorBridge.getInstance().stop();
// id值
String uuid = UUID.randomUUID().toString();
// 确认当前的 action 是否有效
Supplier<Boolean> validAction = () -> pendingActions.contains(uuid);
// 30s后执行
Runnable detectorAction = () -> {
// 如果当前没开启,则直接返回
if (!EnvDetectorConfig.getInstance().isEnabled()) {
return;
}
// 如果当前不包含这个 id, 就不执行
if (!validAction.get()) {
return;
}
Stream<DetectorResult> resultStream = DetectorBridge.getInstance().detect().stream();
// 展示效果
NotificationDialogProperties properties = new NotificationDialogProperties(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Detect_Notification_Title"));
List<NotificationModel> notificationModels = resultStream
.filter(Objects::nonNull)
.filter((e) -> e.getStatus() == DetectorStatus.EXCEPTION)
.map(DetectorUtil::convert2Notification)
.collect(Collectors.toList());
if (Collections.isEmpty(notificationModels)) {
FineLoggerFactory.getLogger().debug("detector not found any exception");
return;
}
UIUtil.invokeLaterIfNeeded(() -> {
// 如果当前不包含这个 id, 就不执行
if (!validAction.get()) {
return;
}
NotificationDialog dialog = new NotificationDialog(properties, notificationModels);
dialog.open();
// 执行完移除
pendingActions.remove(uuid);
});
};
// 添加
pendingActions.add(uuid);
DelayHelper.delayCall(EnvDetectorCenter.class.getName(), detectorAction, 30, TimeUnit.SECONDS);
}
/**
* 使用预期外的错误进行展示
*
* @param throwable 异常
* @return
*/
public List<DetectorResult> terminate(Throwable throwable) {
Stream<DetectorResult> resultStream = DetectorBridge.getInstance().detect(throwable).stream();
return resultStream
.filter((e) -> e.getStatus() == DetectorStatus.EXCEPTION)
.collect(Collectors.toList());
}
/**
* 预期外的终止
*
* @return 检测结果
*/
public List<DetectorResult> terminateUnexpectedly() {
Stream<DetectorResult> resultStream = DetectorBridge.getInstance().detect().stream();
return resultStream
.filter((e) -> e.getStatus() == DetectorStatus.EXCEPTION)
.collect(Collectors.toList());
}
private enum DetectorProcess {
/**
* 设计器启动
*/
DESIGN_LAUNCH,
}
}

19
designer-base/src/main/java/com/fr/env/detect/base/AbstractExceptionDetector.java vendored

@ -0,0 +1,19 @@
package com.fr.env.detect.base;
import com.fr.env.detect.bean.DetectorType;
/**
* created by Harrison on 2022/05/13
**/
public abstract class AbstractExceptionDetector implements ExceptionDetector {
private DetectorType type;
public AbstractExceptionDetector(DetectorType type) {
this.type = type;
}
public DetectorType type() {
return type;
}
}

55
designer-base/src/main/java/com/fr/env/detect/base/CatchExceptionDetector.java vendored

@ -0,0 +1,55 @@
package com.fr.env.detect.base;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.thowable.ThrowableConverter;
import com.fr.env.detect.thowable.ThrowableStore;
import java.util.List;
/**
* created by Harrison on 2022/05/13
**/
public abstract class CatchExceptionDetector extends AbstractExceptionDetector {
private ThrowableStore throwableStore;
private ThrowableConverter throwableConverter;
public CatchExceptionDetector(DetectorType type, ThrowableConverter throwableConverter) {
super(type);
this.throwableStore = ThrowableStore.getInstance();
this.throwableConverter = throwableConverter;
}
public CatchExceptionDetector(DetectorType type, ThrowableStore throwableStore, ThrowableConverter throwableConverter) {
super(type);
this.throwableStore = throwableStore;
this.throwableConverter = throwableConverter;
}
public ThrowableStore getThrowableStore() {
return throwableStore;
}
public ThrowableConverter getThrowableConverter() {
return throwableConverter;
}
@Override
public DetectorResult detect() {
List<Throwable> throwableList = throwableStore.getAll();
for (Throwable throwable : throwableList) {
if (throwableConverter.accept(throwable)) {
DetectorResult result = throwableConverter.convert(throwable);
if (result == null) {
result = DetectorResult.normal(type());
}
return result;
}
}
return DetectorResult.normal(type());
}
}

157
designer-base/src/main/java/com/fr/env/detect/base/DetectorBridge.java vendored

@ -0,0 +1,157 @@
package com.fr.env.detect.base;
import com.fr.common.annotations.Careful;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.impl.DetectorChain;
import com.fr.env.detect.impl.FineDbDirtyDetector;
import com.fr.env.detect.impl.FineDbLockedDetector;
import com.fr.env.detect.impl.FineDbPermissionDetector;
import com.fr.env.detect.impl.JarConflictDetector;
import com.fr.env.detect.impl.JarInconsistentDetector;
import com.fr.env.detect.impl.JarLackDetector;
import com.fr.env.detect.thowable.ThrowableLogAppender;
import com.fr.env.detect.thowable.ThrowableStore;
import com.fr.log.FineLoggerFactory;
import com.fr.value.NotNullLazyValue;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 检测器桥接逻辑
* [detect-core] - bridge - ui
* 标记为谨慎类目前埋点依赖于包名方法名方法特征不能随意更改
*
* created by Harrison on 2022/05/13
**/
@Careful
public class DetectorBridge {
public static DetectorBridge getInstance() {
return DetectorBridgeHolder.INSTANCE;
}
private static class DetectorBridgeHolder {
private static final DetectorBridge INSTANCE = new DetectorBridge();
}
private final NotNullLazyValue<DetectorManager> detectorManager = new NotNullLazyValue<DetectorManager>() {
@Override
protected @NotNull DetectorManager compute() {
DetectorManager manager = new DetectorManager();
// 按照顺序构造检测链
manager.register(DetectorChain.construct(
new FineDbLockedDetector(),
new FineDbPermissionDetector(),
new FineDbDirtyDetector()));
manager.register(new JarInconsistentDetector());
manager.register(new JarLackDetector());
manager.register(new JarConflictDetector());
return manager;
}
};
private final AtomicBoolean hasStarted = new AtomicBoolean(false);
public void start() {
if (!hasStarted.get() && EnvDetectorConfig.getInstance().isEnabled()) {
// 开始注册异常处理
ThrowableLogAppender.getInstance().enable();
hasStarted.set(true);
}
}
public void stop() {
if (hasStarted.compareAndSet(true, false)) {
// 关闭异常处理
ThrowableLogAppender.getInstance().disable();
}
}
public void reset() {
ThrowableStore.getInstance().reset();
}
/**
* 针对某一项进行检测
* 主要用于手动检测时
*
* @param type 检测类型
* @return 检测结果
*/
@NotNull
public DetectorResult detect(DetectorType type) {
try {
return detectorManager.getValue().detect(type);
} catch (Exception e) {
FineLoggerFactory.getLogger().error("detect failed", e);
// 返回未知错误信息
return DetectorResult.unknown(type);
}
}
/**
* 针对某一项 \ 某一个异常进行检测
*
* @param type 类型
* @param throwable 异常
* @return 结果
*/
@NotNull
public DetectorResult detect(DetectorType type, Throwable throwable) {
ThrowableStore.getInstance().add(throwable);
DetectorResult result = detect(type);
ThrowableStore.getInstance().reset();
return result;
}
/**
* 异常检测
* 对异常统一检测
*
* @return 能够检测出的异常情况
*/
@NotNull
public Collection<DetectorResult> detect() {
Stream<DetectorResult> results = detectorManager.getValue().detect();
return results.collect(Collectors.toList());
}
/**
* 异常检测
* 当遇到异常时且异常难以处理直接导致服务器启动失败时调用
* 将异常添加进来统一检测
*
* @param throwable 异常
* @return 检测结果
*/
@NotNull
public Collection<DetectorResult> detect(Throwable throwable) {
ThrowableStore.getInstance().add(throwable);
Collection<DetectorResult> result = detect();
ThrowableStore.getInstance().reset();
return result;
}
}

18
designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java vendored

@ -0,0 +1,18 @@
package com.fr.env.detect.base;
/**
* created by Harrison on 2022/05/25
**/
public class DetectorConstants {
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 SEPARATOR = "、";
public static final String BR_TAG = "<br/>";
public static final String WEB_LIB_PATH = "%FR_HOME%\\webapps\\webroot\\WEB-INF\\lib:";
public static final String FR_HOME_LIB = "%FR_HOME%\\lib:";
}

82
designer-base/src/main/java/com/fr/env/detect/base/DetectorManager.java vendored

@ -0,0 +1,82 @@
package com.fr.env.detect.base;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.impl.DetectorChain;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 检测器中心
*
* created by Harrison on 2022/05/24
**/
class DetectorManager {
/**
* 检测链的列表
*/
private List<DetectorChain> chains = new ArrayList<>();
/**
* 单纯的检测器的列表
*/
private List<ExceptionDetector> detectors = new ArrayList<>();
public void register(DetectorChain chain) {
if (chain != null) {
chains.add(chain);
}
}
public void register(ExceptionDetector detector) {
if (detector != null) {
detectors.add(detector);
}
}
public Stream<DetectorResult> detect() {
Stream<DetectorResult> results = detectors.stream()
.map(ExceptionDetector::detect)
.filter(Objects::nonNull);
Stream<DetectorResult> chainResults = chains.stream()
.map(DetectorChain::detect)
.filter(Objects::nonNull);
List<DetectorResult> resultList = Stream.concat(results, chainResults)
.collect(Collectors.toList());
resultList.forEach(DetectorResult::log);
return resultList.stream();
}
public DetectorResult detect(DetectorType type) {
Stream<ExceptionDetector> chainDetectors = chains.stream()
.map(DetectorChain::getDetectors)
.flatMap(Collection::stream);
Stream<ExceptionDetector> allDetectors = Stream.concat(detectors.stream(), chainDetectors);
Optional<DetectorResult> result = allDetectors
.filter((detector -> type == detector.type()))
.findFirst()
.map(ExceptionDetector::detect);
// 记录日志
result.ifPresent(DetectorResult::log);
return result.orElse(DetectorResult.normal(type));
}
}

166
designer-base/src/main/java/com/fr/env/detect/base/DetectorUtil.java vendored

@ -0,0 +1,166 @@
package com.fr.env.detect.base;
import com.fr.base.function.ThrowableRunnable;
import com.fr.common.util.Collections;
import com.fr.design.components.notification.NotificationAction;
import com.fr.design.components.notification.NotificationMessage;
import com.fr.design.components.notification.NotificationModel;
import com.fr.design.components.notification.NotificationType;
import com.fr.design.dialog.link.MessageWithLink;
import com.fr.design.utils.LinkStrUtils;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.ExceptionSolution;
import com.fr.env.detect.bean.ExceptionTips;
import com.fr.env.detect.bean.Message;
import com.fr.env.detect.bean.SolutionAction;
import com.fr.general.build.BuildInfo;
import com.fr.third.org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import javax.swing.JComponent;
import java.awt.Desktop;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import static com.fr.env.detect.base.DetectorConstants.BR_TAG;
import static com.fr.env.detect.base.DetectorConstants.FR_HOME_LIB;
import static com.fr.env.detect.base.DetectorConstants.SEPARATOR;
import static com.fr.env.detect.base.DetectorConstants.WEB_LIB_PATH;
/**
* created by Harrison on 2022/05/25
**/
public class DetectorUtil {
/**
* 是否是设计器的 jar
*
* @param info 信息
* @return /
*/
public static boolean isDesignerJar(BuildInfo info) {
if (info == null) {
return false;
}
return StringUtils.contains(info.getJar(), "fine-report-designer");
}
/**
* 将结果转化为提醒的数据
*
* @param result 结果
* @return 数据
*/
public static NotificationModel convert2Notification(DetectorResult result) {
List<NotificationMessage> messages = new ArrayList<>();
Function<Message, Optional<NotificationMessage>> convert2NotificationMsg = message -> {
NotificationMessage notificationMessage = null;
if (message != null) {
Message.Type type = message.getType();
switch (type) {
case SIMPLE:
notificationMessage = (new NotificationMessage.SimpleMessage(message.get()));
break;
case LINK:
Message.Link linkMsg = (Message.Link) message;
notificationMessage = new NotificationMessage.LinkMessage(linkMsg.getText(), linkMsg.getLink());
break;
default:
break;
}
}
return Optional.ofNullable(notificationMessage);
};
ExceptionTips tips = result.getTips();
if (tips != null) {
convert2NotificationMsg
.apply(tips.getMessage())
.ifPresent(messages::add);
}
ExceptionSolution solution = result.getSolution();
if (solution != null) {
convert2NotificationMsg.apply(solution.getMessage())
.ifPresent(messages::add);
}
NotificationAction notificationAction = null;
if (solution != null) {
SolutionAction solutionAction = solution.getAction();
if (solutionAction != null) {
notificationAction = new NotificationAction() {
@Override
public String name() {
return solutionAction.name();
}
@Override
public void run(Object... args) {
solutionAction.run();
}
};
}
}
return new NotificationModel(NotificationType.WARNING, notificationAction, messages);
}
/**
* 将信息转化为展示的组件
*
* @param message 信息
* @return 组件
*/
public static JComponent convert2TextComponent(@NotNull Message message, JComponent template) {
if (message.getType() == Message.Type.LINK) {
Message.Link linkMsg = (Message.Link) message;
return new MessageWithLink(linkMsg.getText(), ThrowableRunnable.toRunnable(() -> {
Desktop.getDesktop().browse(URI.create(linkMsg.getLink()));
}));
}
return LinkStrUtils.generateLabel(message.get(), template);
}
/**
* lib 转化成合适的格式
* %FR_HOME%/lib
* %FR_HOME%/webapps/webroot/WEB-INF/lib
*
* @param libMap jar 路径, key为前缀
* @return 信息
*/
public static String concatLibFormatMsg(Map<String, List<String>> libMap) {
String webLibPath = WEB_LIB_PATH;
String homeLibPath = FR_HOME_LIB;
StringBuilder sb = new StringBuilder();
List<String> homeLibs = libMap.get(homeLibPath);
if (!Collections.isEmpty(homeLibs)) {
sb.append(homeLibPath);
sb.append(StringUtils.join(homeLibs, SEPARATOR));
}
List<String> webLibs = libMap.get(webLibPath);
if (!Collections.isEmpty(webLibs)) {
if (sb.length() != 0) {
sb.append(BR_TAG);
}
sb.append(webLibPath);
sb.append(StringUtils.join(webLibs, SEPARATOR));
}
return sb.toString();
}
}

59
designer-base/src/main/java/com/fr/env/detect/base/EnvDetectorConfig.java vendored

@ -0,0 +1,59 @@
package com.fr.env.detect.base;
import com.fr.design.DesignerEnvManager;
import com.fr.stable.xml.XMLPrintWriter;
import com.fr.stable.xml.XMLable;
import com.fr.stable.xml.XMLableReader;
/**
* created by Harrison on 2022/05/13
**/
public class EnvDetectorConfig implements XMLable {
public static final String XML_TAG = "EnvDetectorConfig";
private static final long serialVersionUID = -8170289826729582122L;
private static final EnvDetectorConfig INSTANCE = new EnvDetectorConfig();
public static EnvDetectorConfig getInstance() {
return INSTANCE;
}
private boolean enabled = true;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
save();
}
private void save() {
DesignerEnvManager.getEnvManager(false).saveXMLFile();
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public void readXML(XMLableReader reader) {
if (reader.isAttr()) {
this.setEnabled(reader.getAttrAsBoolean("isEnabled", true));
}
}
@Override
public void writeXML(XMLPrintWriter writer) {
writer.startTAG(XML_TAG);
writer.attr("isEnabled", this.isEnabled());
writer.end();
}
}

25
designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetector.java vendored

@ -0,0 +1,25 @@
package com.fr.env.detect.base;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
/**
* created by Harrison on 2022/05/13
**/
public interface ExceptionDetector {
/**
* 检测类型
*
* @return TYPE
*/
DetectorType type();
/**
* 检测结果
*
* @return 结果
*/
DetectorResult detect();
}

40
designer-base/src/main/java/com/fr/env/detect/base/ThrowableBridge.java vendored

@ -0,0 +1,40 @@
package com.fr.env.detect.base;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.thowable.ThrowableConverter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
* created by Harrison on 2022/05/13
**/
class ThrowableBridge {
private List<ThrowableConverter> throwableConverters = new ArrayList<>();
public void register(ThrowableConverter throwableConverter) {
if (throwableConverter != null) {
throwableConverters.add(throwableConverter);
}
}
/**
* throwable 转化成检测的结果
*
* @param throwable 异常
* @return 结果
*/
public Optional<DetectorResult> convert(Throwable throwable) {
return throwableConverters
.stream()
.filter((e) -> e.accept(throwable))
.map((e) -> e.convert(throwable))
.filter(Objects::nonNull)
.findFirst();
}
}

4
designer-base/src/main/java/com/fr/env/detect/base/package-info.java vendored

@ -0,0 +1,4 @@
/**
* 设计器环境检测 {@see https://kms.fineres.com/pages/viewpage.action?pageId=388333688}
*/
package com.fr.env.detect.base;

147
designer-base/src/main/java/com/fr/env/detect/bean/DetectorResult.java vendored

@ -0,0 +1,147 @@
package com.fr.env.detect.bean;
import org.jetbrains.annotations.Nullable;
/**
* 检测结果
*
* created by Harrison on 2022/05/13
**/
public class DetectorResult {
private DetectorType type;
private DetectorStatus status;
private ExceptionTips tips;
private ExceptionSolution solution;
private ExceptionLog log;
private DetectorResult(DetectorType type) {
this.type = type;
}
private DetectorResult(DetectorType type, ExceptionTips tips, ExceptionSolution solution, ExceptionLog log) {
this.type = type;
this.tips = tips;
this.solution = solution;
this.log = log;
}
public static DetectorResult unknown(DetectorType type) {
DetectorResult result = new DetectorResult(type);
result.status = DetectorStatus.UNKNOWN;
return result;
}
public static DetectorResult normal(DetectorType type) {
DetectorResult result = new DetectorResult(type);
result.status = DetectorStatus.NORMAL;
return result;
}
public static DetectorResult exception(DetectorType type, ExceptionTips tips, ExceptionSolution solution, ExceptionLog log) {
DetectorResult result = new DetectorResult(type, tips, solution, log);
result.status = DetectorStatus.EXCEPTION;
return result;
}
public DetectorStatus getStatus() {
return status;
}
public DetectorType getType() {
return type;
}
@Nullable
public ExceptionTips getTips() {
return tips;
}
@Nullable
public ExceptionSolution getSolution() {
return solution;
}
public void log() {
if (log != null) {
log.log();
}
}
public static DetectorResultBuilder builder() {
return new DetectorResultBuilder()
.withStatus(DetectorStatus.EXCEPTION);
}
public static final class DetectorResultBuilder {
private DetectorType type;
private DetectorStatus status;
private ExceptionTips tips;
private ExceptionSolution solution;
private ExceptionLog log;
private DetectorResultBuilder() {
}
public DetectorResultBuilder withType(DetectorType type) {
this.type = type;
return this;
}
public DetectorResultBuilder withStatus(DetectorStatus status) {
this.status = status;
return this;
}
public DetectorResultBuilder withTips(ExceptionTips tips) {
this.tips = tips;
return this;
}
public DetectorResultBuilder withTips(String message) {
Message.Simple simple = new Message.Simple(message);
this.tips = new ExceptionTips(simple);
return this;
}
public DetectorResultBuilder withSolution(ExceptionSolution solution) {
this.solution = solution;
return this;
}
public DetectorResultBuilder withSolution(String content, String link) {
Message.Link message = new Message.Link(content, link);
this.solution = new ExceptionSolution(message, null);
return this;
}
public DetectorResultBuilder withLog(String log, Object... args) {
this.log = ExceptionLog.create(log, args);
return this;
}
public DetectorResultBuilder withLog(ExceptionLog log) {
this.log = log;
return this;
}
public DetectorResult build() {
DetectorResult detectorResult = new DetectorResult(type, tips, solution, log);
detectorResult.status = this.status;
return detectorResult;
}
}
}

22
designer-base/src/main/java/com/fr/env/detect/bean/DetectorStatus.java vendored

@ -0,0 +1,22 @@
package com.fr.env.detect.bean;
/**
* created by Harrison on 2022/05/27
**/
public enum DetectorStatus {
/**
* 正常
*/
NORMAL,
/**
* 异常
*/
EXCEPTION,
/**
* 未知
*/
UNKNOWN,
}

159
designer-base/src/main/java/com/fr/env/detect/bean/DetectorType.java vendored

@ -0,0 +1,159 @@
package com.fr.env.detect.bean;
import com.fr.design.i18n.Toolkit;
/**
* 检测的原生数据
* 其实这里可以继续拆分到不同的逻辑下面的, 比如实际生成 DetectorResult 的地方 {@link com.fr.env.detect.base.ExceptionDetector}
* 不过目前没有必要先这样处理
*
* created by Harrison on 2022/05/13
**/
public enum DetectorType {
/**
* 缺少 JAR
*/
LACK_OF_JAR(Kind.JAR, WorkType.LOCAL,
"Fine_Design_Basic_Jar_Lacked_Desc",
"Fine_Design_Basic_Jar_Lack",
"Fine_Design_Basic_Jar_Solution",
"Fine_Design_Basic_Log_Jar_Lack"),
/**
* JAR 包版本不一致
*/
JAR_IN_CONSISTENCE(Kind.JAR, WorkType.SIMPLE,
"Fine_Design_Basic_Jar_InConsistent_Desc",
"Fine_Design_Basic_Jar_InConsistent",
"Fine_Design_Basic_Jar_Solution",
"Fine_Design_Basic_Log_Jar_InConsistent"),
/**
* JAR 包冲突
*/
JAR_CONFLICT(Kind.JAR, WorkType.REMOTE,
"Fine_Design_Basic_Jar_Problem_Desc",
"Fine_Design_Basic_Jar_Problem",
"Fine_Design_Basic_Jar_Solution",
"Fine_Design_Basic_Log_Jar_Problem"),
/**
* FineDB 权限问题
*/
FINE_DB_PERMISSION(Kind.FINE_DB, WorkType.LOCAL,
"Fine_Design_Basic_FineDB_Permission_Occupied_Desc",
"Fine_Design_Basic_FineDB_Permission_Occupied",
"Fine_Design_Basic_FineDB_Solution",
"Fine_Design_Basic_Log_FineDB_Permission_Occupied"),
/**
* FineDB
*/
FINE_DB_LOCKED(Kind.FINE_DB, WorkType.LOCAL,
"Fine_Design_Basic_FineDB_Locked_Desc",
"Fine_Design_Basic_FineDB_Locked",
"Fine_Design_Basic_FineDB_Solution",
"Fine_Design_Basic_Log_FineDB_Locked"),
/**
* FineDB 脏数据
*/
FINE_DB_DIRTY(Kind.FINE_DB, WorkType.SIMPLE,
"Fine_Design_Basic_FineDB_Dirty_Data_Desc",
"Fine_Design_Basic_FineDB_Dirty_Data",
"Fine_Design_Basic_FineDB_Dirty_Solution",
"Fine_Design_Basic_Log_FineDB_Dirty_Data")
;
private final Kind kind;
private final WorkType workType;
private final String descLocale;
private final String tipsLocale;
private final String solutionLocale;
private final String logLocale;
DetectorType(Kind kind, WorkType workType, String descLocale, String tipsLocale, String solutionLocale, String logLocale) {
this.kind = kind;
this.workType = workType;
this.descLocale = descLocale;
this.tipsLocale = tipsLocale;
this.solutionLocale = solutionLocale;
this.logLocale = logLocale;
}
public String getDescription() {
return Toolkit.i18nText(descLocale);
}
public String getDescLocale() {
return descLocale;
}
public Kind getKind() {
return kind;
}
public WorkType getWorkType() {
return workType;
}
public String getTipsLocale() {
return tipsLocale;
}
public String getSolutionLocale() {
return solutionLocale;
}
public String getLogLocale() {
return logLocale;
}
public enum Kind {
/**
* JAR 类型
*/
JAR("Fine_Design_Basic_Jar_Kind_Desc"),
/**
* FineDB 类型
*/
FINE_DB("Fine_Design_Basic_FineDB_Kind_Desc");
private final String locale;
Kind(String locale) {
this.locale = locale;
}
public String getDescription() {
return Toolkit.i18nText(this.locale);
}
}
public enum WorkType {
/**
* 本地
*/
LOCAL,
/**
* 远程
*/
REMOTE,
/**
* 全部
*/
SIMPLE
}
}

36
designer-base/src/main/java/com/fr/env/detect/bean/ExceptionLog.java vendored

@ -0,0 +1,36 @@
package com.fr.env.detect.bean;
import com.fr.log.FineLoggerFactory;
/**
* created by Harrison on 2022/05/13
**/
public class ExceptionLog {
private final String template;
private final Object[] args;
private ExceptionLog(String template, Object... args) {
this.template = template;
this.args = args;
}
public static ExceptionLog create(String template, Object... args) {
return new ExceptionLog(template, args);
}
public void log() {
FineLoggerFactory.getLogger().error(template, args);
}
public String getTemplate() {
return template;
}
public Object[] getArgs() {
return args;
}
}

32
designer-base/src/main/java/com/fr/env/detect/bean/ExceptionSolution.java vendored

@ -0,0 +1,32 @@
package com.fr.env.detect.bean;
import org.jetbrains.annotations.Nullable;
/**
* created by Harrison on 2022/05/13
**/
public class ExceptionSolution {
private Message message;
@Nullable
private SolutionAction action;
public static ExceptionSolution create(String text, String link, SolutionAction action) {
return new ExceptionSolution(new Message.Link(text, link), action);
}
public ExceptionSolution(Message message, @Nullable SolutionAction action) {
this.message = message;
this.action = action;
}
public Message getMessage() {
return message;
}
public @Nullable SolutionAction getAction() {
return action;
}
}

24
designer-base/src/main/java/com/fr/env/detect/bean/ExceptionTips.java vendored

@ -0,0 +1,24 @@
package com.fr.env.detect.bean;
/**
* 异常提示
*
* created by Harrison on 2022/05/13
**/
public class ExceptionTips {
private Message message;
public static ExceptionTips create(String text) {
return new ExceptionTips(new Message.Simple(text));
}
public ExceptionTips(Message message) {
this.message = message;
}
public Message getMessage() {
return message;
}
}

83
designer-base/src/main/java/com/fr/env/detect/bean/Message.java vendored

@ -0,0 +1,83 @@
package com.fr.env.detect.bean;
/**
* created by Harrison on 2022/05/24
**/
public interface Message {
/**
* 消息类型
*
* @return 类型
*/
Type getType();
/**
* 返回内容
*
* @return 内容
*/
String get();
enum Type {
/**
* 简单
*/
SIMPLE,
/**
* 链接
*/
LINK
}
class Simple implements Message {
private String message;
public Simple(String message) {
this.message = message;
}
@Override
public String get() {
return message;
}
@Override
public Type getType() {
return Type.SIMPLE;
}
}
class Link implements Message {
private String text;
private String link;
public Link(String text, String link) {
this.text = text;
this.link = link;
}
@Override
public String get() {
return getText();
}
public String getText() {
return text;
}
public String getLink() {
return link;
}
@Override
public Type getType() {
return Type.LINK;
}
}
}

11
designer-base/src/main/java/com/fr/env/detect/bean/SolutionAction.java vendored

@ -0,0 +1,11 @@
package com.fr.env.detect.bean;
/**
* created by Harrison on 2022/05/24
**/
public interface SolutionAction {
String name();
void run();
}

46
designer-base/src/main/java/com/fr/env/detect/impl/DetectorChain.java vendored

@ -0,0 +1,46 @@
package com.fr.env.detect.impl;
import com.fr.env.detect.base.ExceptionDetector;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorStatus;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 检测链
* 责任链模式 有先后顺序哪一个先获得哪一个先终止
*
* created by Harrison on 2022/06/16
**/
public class DetectorChain {
private List<ExceptionDetector> detectors = new ArrayList<>();
public static DetectorChain construct(ExceptionDetector... detectors) {
DetectorChain detectorChain = new DetectorChain();
detectorChain.detectors = Arrays.stream(detectors).collect(Collectors.toList());
return detectorChain;
}
@Nullable
public DetectorResult detect() {
for (ExceptionDetector detector : detectors) {
DetectorResult result = detector.detect();
if (result != null && result.getStatus() == DetectorStatus.EXCEPTION) {
return result;
}
}
return null;
}
public List<ExceptionDetector> getDetectors() {
return this.detectors;
}
}

106
designer-base/src/main/java/com/fr/env/detect/impl/FineDbDirtyDetector.java vendored

@ -0,0 +1,106 @@
package com.fr.env.detect.impl;
import com.fr.config.ConfigContext;
import com.fr.config.Configuration;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.i18n.Toolkit;
import com.fr.env.detect.base.AbstractExceptionDetector;
import com.fr.env.detect.base.DetectorConstants;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.bean.ExceptionSolution;
import com.fr.env.detect.bean.Message;
import com.fr.env.detect.bean.SolutionAction;
import com.fr.io.utils.ResourceIOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StableUtils;
import com.fr.stable.project.ProjectConstants;
import com.fr.third.org.hibernate.exception.GenericJDBCException;
import javax.swing.JOptionPane;
import java.util.Iterator;
import java.util.function.Function;
/**
* created by Harrison on 2022/05/25
**/
public class FineDbDirtyDetector extends AbstractExceptionDetector {
public FineDbDirtyDetector() {
super(DetectorType.FINE_DB_DIRTY);
}
@Override
public DetectorResult detect() {
Iterator<String> tableNames = ConfigContext.getConfigNames();
while (tableNames.hasNext()) {
String tableName = tableNames.next();
Class<? extends Configuration> configClass = ConfigContext.getConfigClass(tableName);
Configuration configuration = ConfigContext.getConfigInstance(configClass);
try {
// 尝试获取每一个值
configuration.mirror();
} catch (Throwable e) {
Function<Throwable, Boolean> isDirtyExFunction = throwable -> {
while (throwable != null) {
if (throwable instanceof GenericJDBCException) {
return true;
}
throwable = throwable.getCause();
}
return false;
};
boolean isDirtyEx = isDirtyExFunction.apply(e);
if (isDirtyEx) {
DetectorType detectorType = DetectorType.FINE_DB_DIRTY;
DetectorResult.DetectorResultBuilder builder = DetectorResult
.builder()
.withType(detectorType);
String tipsLocale = Toolkit.i18nText(detectorType.getTipsLocale(), tableName);
String solutionLocale = detectorType.getSolutionLocale();
ExceptionSolution exceptionSolution = new ExceptionSolution(new Message.Link(Toolkit.i18nText(solutionLocale, DetectorConstants.FINE_DB_HELP_LINK), DetectorConstants.FINE_DB_HELP_LINK), new SolutionAction() {
@Override
public String name() {
return Toolkit.i18nText("Fine-Design_Basic_Reset_Immediately");
}
@Override
public void run() {
boolean success = false;
try {
ResourceIOUtils.copy(StableUtils.pathJoin(ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.FINE_DB_NAME),
StableUtils.pathJoin(ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.FINE_DB_BAK_NAME));
success = ResourceIOUtils.delete(StableUtils.pathJoin(ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.FINE_DB_NAME));
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
// todo 最好的逻辑是,这里应该和 UI 隔离开的
if (!success) {
FineJOptionPane.showMessageDialog(null,
Toolkit.i18nText("Fine-Design_Error_Finedb_Backup_Reset_Result",
ResourceIOUtils.getRealPath(StableUtils.pathJoin(ProjectConstants.EMBED_DB_DIRECTORY, ProjectConstants.FINE_DB_NAME))),
Toolkit.i18nText("Fine-Design_Basic_Error"),
JOptionPane.ERROR_MESSAGE);
}
}
});
builder.withTips(tipsLocale)
.withSolution(exceptionSolution)
.withLog(Toolkit.i18nText(detectorType.getLogLocale(), tableName));
return builder.build();
}
}
}
return DetectorResult.normal(DetectorType.FINE_DB_DIRTY);
}
}

16
designer-base/src/main/java/com/fr/env/detect/impl/FineDbLockedDetector.java vendored

@ -0,0 +1,16 @@
package com.fr.env.detect.impl;
import com.fr.env.detect.base.CatchExceptionDetector;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.impl.converter.FineDbLockedConverter;
/**
* created by Harrison on 2022/05/26
**/
public class FineDbLockedDetector extends CatchExceptionDetector {
public FineDbLockedDetector() {
super(DetectorType.FINE_DB_LOCKED, new FineDbLockedConverter());
}
}

15
designer-base/src/main/java/com/fr/env/detect/impl/FineDbPermissionDetector.java vendored

@ -0,0 +1,15 @@
package com.fr.env.detect.impl;
import com.fr.env.detect.base.CatchExceptionDetector;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.impl.converter.FineDbPermissionConverter;
/**
* created by Harrison on 2022/05/26
**/
public class FineDbPermissionDetector extends CatchExceptionDetector {
public FineDbPermissionDetector() {
super(DetectorType.FINE_DB_PERMISSION, new FineDbPermissionConverter());
}
}

15
designer-base/src/main/java/com/fr/env/detect/impl/JarConflictDetector.java vendored

@ -0,0 +1,15 @@
package com.fr.env.detect.impl;
import com.fr.env.detect.base.CatchExceptionDetector;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.impl.converter.ClassConflictConvertor;
/**
* created by Harrison on 2022/05/26
**/
public class JarConflictDetector extends CatchExceptionDetector {
public JarConflictDetector() {
super(DetectorType.JAR_CONFLICT, new ClassConflictConvertor());
}
}

156
designer-base/src/main/java/com/fr/env/detect/impl/JarInconsistentDetector.java vendored

@ -0,0 +1,156 @@
package com.fr.env.detect.impl;
import com.fr.common.util.Collections;
import com.fr.design.i18n.Toolkit;
import com.fr.env.detect.base.AbstractExceptionDetector;
import com.fr.env.detect.base.DetectorConstants;
import com.fr.env.detect.base.DetectorUtil;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.bean.ExceptionLog;
import com.fr.env.detect.bean.ExceptionSolution;
import com.fr.env.detect.bean.ExceptionTips;
import com.fr.env.detect.bean.Message;
import com.fr.general.build.BuildInfo;
import com.fr.general.build.BuildInfoManager;
import com.fr.general.build.BuildInfoOperator;
import com.fr.general.build.impl.BuildInfoOperatorImpl;
import com.fr.third.guava.collect.MapDifference;
import com.fr.third.guava.collect.Maps;
import com.fr.third.org.apache.commons.lang3.StringUtils;
import com.fr.workspace.WorkContext;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
* created by Harrison on 2022/05/25
**/
public class JarInconsistentDetector extends AbstractExceptionDetector {
public static final String SEPARATOR = ",";
public JarInconsistentDetector() {
super(DetectorType.JAR_IN_CONSISTENCE);
}
/**
* 本地
* 先获取 Designer, 然后对其他的 JAR 信息匹配
* <p>
* 远程
* 两边一一对应匹配
*
* @return 结果
*/
@Override
public DetectorResult detect() {
if (WorkContext.getCurrent().isLocal()) {
return detectLocal();
} else {
return detectLocalAndRemote();
}
}
@NotNull
private DetectorResult detectLocalAndRemote() {
// 检测有哪些 JAR 包, 当前是否缺少对应的 JAR 包
BuildInfoOperator buildInfoOperator = WorkContext.getCurrent().get(BuildInfoOperator.class);
List<BuildInfo> buildInfos = buildInfoOperator.getBuildInfos();
// 远程情况
List<BuildInfo> localInfos = BuildInfoManager.getInstance().getInfos();
Map<String, String> localMap = groupBy(localInfos);
List<BuildInfo> remoteInfos = buildInfos;
Map<String, String> remoteMap = groupBy(remoteInfos);
MapDifference<String, String> difference = Maps.difference(localMap, remoteMap);
// 获取本地远程不一样的部分
Map<String, MapDifference.ValueDifference<String>> diffs = difference.entriesDiffering();
if (diffs.isEmpty()) {
return DetectorResult.normal(type());
}
Set<String> inConsistentJars = diffs.keySet();
String message = StringUtils.join(inConsistentJars, SEPARATOR);
Message.Simple tipsMessage = new Message.Simple(Toolkit.i18nText("Fine_Design_Basic_Detect_Server") + Toolkit.i18nText(type().getTipsLocale()) + message);
return DetectorResult.exception(type(),
new ExceptionTips(tipsMessage),
new ExceptionSolution(new Message.Link(Toolkit.i18nText(type().getSolutionLocale(),DetectorConstants.JAR_HELP_LINK)
, DetectorConstants.JAR_HELP_LINK), null),
ExceptionLog.create(Toolkit.i18nText(type().getLogLocale()) + message));
}
@NotNull
private DetectorResult detectLocal() {
// 本地的获取方式
BuildInfoOperator operator = new BuildInfoOperatorImpl();
List<BuildInfo> buildInfos = operator.getBuildInfos();
// 获取设计器的 build
Optional<String> designerBuild = buildInfos.stream()
.filter(DetectorUtil::isDesignerJar)
.map(BuildInfo::getGroupBuild)
.filter(StringUtils::isNotEmpty)
.findFirst();
// 如果 build
if (!designerBuild.isPresent()) {
return DetectorResult.normal(type());
}
// 获取所有的不一致的 build
List<BuildInfo> inConsistentInfos = buildInfos.stream()
.filter((e) -> {
// 不为空,且不相等
return StringUtils.isNotEmpty(e.getGroupBuild())
&& !StringUtils.equals(designerBuild.get(), e.getGroupBuild());
})
.collect(Collectors.toList());
// 没有直接返回
if (Collections.isEmpty(inConsistentInfos)) {
return DetectorResult.normal(type());
}
// 有的话
List<String> inConsistentJars = inConsistentInfos.stream()
.map(BuildInfo::getJar)
.collect(Collectors.toList());
String message = StringUtils.join(inConsistentJars, SEPARATOR);
String tipsMessage = Toolkit.i18nText("Fine_Design_Basic_Detect_Local") + Toolkit.i18nText(type().getTipsLocale()) + message;
return DetectorResult.exception(type(),
new ExceptionTips(new Message.Simple(tipsMessage)),
new ExceptionSolution(new Message.Link(Toolkit.i18nText(type().getSolutionLocale()), DetectorConstants.JAR_HELP_LINK), null),
ExceptionLog.create(Toolkit.i18nText(type().getLogLocale()) + message));
}
private Map<String, String> groupBy(List<BuildInfo> localInfos) {
Map<String, String> localMap = new HashMap<>();
for (BuildInfo localInfo : localInfos) {
String jar = localInfo.getJar();
String groupContent = localInfo.getGroupBuild();
// 不一致的 JAR 检测,忽视缺少的情况
if (StringUtils.isNotEmpty(groupContent)) {
localMap.put(jar, groupContent);
}
}
return localMap;
}
}

164
designer-base/src/main/java/com/fr/env/detect/impl/JarLackDetector.java vendored

@ -0,0 +1,164 @@
package com.fr.env.detect.impl;
import com.fr.common.util.Collections;
import com.fr.design.i18n.Toolkit;
import com.fr.env.detect.base.AbstractExceptionDetector;
import com.fr.env.detect.base.DetectorConstants;
import com.fr.env.detect.base.DetectorUtil;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.bean.ExceptionLog;
import com.fr.env.detect.bean.ExceptionSolution;
import com.fr.env.detect.bean.ExceptionTips;
import com.fr.env.detect.bean.Message;
import com.fr.general.build.BuildInfo;
import com.fr.general.build.BuildInfoManager;
import com.fr.general.build.BuildInfoOperator;
import com.fr.general.build.impl.BuildInfoOperatorImpl;
import com.fr.third.guava.collect.Lists;
import com.fr.third.org.apache.commons.lang3.StringUtils;
import com.fr.workspace.WorkContext;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static com.fr.env.detect.base.DetectorConstants.FR_HOME_LIB;
import static com.fr.env.detect.base.DetectorConstants.WEB_LIB_PATH;
/**
* created by Harrison on 2022/05/24
**/
public class JarLackDetector extends AbstractExceptionDetector {
public JarLackDetector() {
super(DetectorType.LACK_OF_JAR);
}
@Override
public DetectorResult detect() {
List<BuildInfo> lackInfos;
// 远程
if (!WorkContext.getCurrent().isLocal()) {
// 检测有哪些 JAR 包, 当前是否缺少对应的 JAR 包
BuildInfoOperator buildInfoOperator = WorkContext.getCurrent().get(BuildInfoOperator.class);
// 远程情况
List<BuildInfo> remoteInfos = buildInfoOperator.getBuildInfos();
// 本地情况
List<BuildInfo> localInfos = BuildInfoManager.getInstance().getInfos();
// 说明远程环境并不存在对应的 info.json, 直接忽略
if (Collections.isEmpty(remoteInfos)) {
return DetectorResult.normal(type());
}
Set<String> remoteSet = remoteInfos.stream()
.filter(this::isExistInfo)
.map(BuildInfo::getJar)
.collect(Collectors.toSet());
Predicate<BuildInfo> remoteNotContains = (e) -> !remoteSet.contains(e.getJar());
lackInfos = localInfos.stream()
.filter(this::isExistInfo)
// 不是设计器的 JAR
.filter((e) -> !DetectorUtil.isDesignerJar(e))
.filter(remoteNotContains)
.collect(Collectors.toList());
} else {
// 本地
// 检测有哪些 JAR 包, 当前是否缺少对应的 JAR 包
BuildInfoOperator buildInfoOperator = new BuildInfoOperatorImpl();
List<BuildInfo> buildInfos = buildInfoOperator.getBuildInfos();
lackInfos = buildInfos.stream()
.filter(this::isLackInfo)
.collect(Collectors.toList());
}
if (Collections.isEmpty(lackInfos)) {
return DetectorResult.normal(type());
}
Message tipsMsg = tipsMessage(lackInfos);
ExceptionLog exceptionLog = exceptionLog(lackInfos);
return DetectorResult.exception(type(),
new ExceptionTips(tipsMsg),
new ExceptionSolution(
new Message.Link(Toolkit.i18nText(type().getSolutionLocale()), DetectorConstants.JAR_HELP_LINK),
null), exceptionLog);
}
private ExceptionLog exceptionLog(List<BuildInfo> lackInfos) {
List<String> jarInfos = lackInfos.stream()
.map(BuildInfo::getJar)
.collect(Collectors.toList());
String message = StringUtils.join(jarInfos, ",");
return ExceptionLog.create(Toolkit.i18nText(type().getLogLocale()) + message);
}
private boolean isExistInfo(BuildInfo e) {
return !isLackInfo(e);
}
private boolean isLackInfo(BuildInfo e) {
return StringUtils.isEmpty(e.getGroupBuild());
}
private Message tipsMessage(List<BuildInfo> infos) {
Map<String, List<String>> libMap = groupByPath(infos, FR_HOME_LIB, WEB_LIB_PATH);
String content = DetectorUtil.concatLibFormatMsg(libMap);
DetectorType type = this.type();
String header = Toolkit.i18nText(type.getTipsLocale());
return new Message.Simple(header + content);
}
@NotNull
private Map<String, List<String>> groupByPath(List<BuildInfo> infos, String homeLibPath, String webLibPath) {
Map<String, List<String>> libMap = new HashMap<>();
for (BuildInfo info : infos) {
String key;
if (inHomeLib(info)) {
key = homeLibPath;
} else {
key = webLibPath;
}
libMap.compute(key, (keyA, value) -> {
if (Collections.isEmpty(value)) {
value = Lists.newArrayList(info.getJar());
} else {
value.add(info.getJar());
}
return value;
});
}
return libMap;
}
/**
* %FR_HOME%\lib
* 否则都是在 %FR_HOME%\webapps\webroot\WEB-INF\lib
*
* @param info JAR 信息
* @return 是否位于 HOME\LIB
*/
private boolean inHomeLib(BuildInfo info) {
return DetectorUtil.isDesignerJar(info);
}
}

212
designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassConflictConvertor.java vendored

@ -0,0 +1,212 @@
package com.fr.env.detect.impl.converter;
import com.fr.design.i18n.Toolkit;
import com.fr.env.detect.base.DetectorConstants;
import com.fr.env.detect.base.DetectorUtil;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.bean.ExceptionLog;
import com.fr.env.detect.bean.ExceptionSolution;
import com.fr.env.detect.bean.ExceptionTips;
import com.fr.env.detect.thowable.ThrowableConverter;
import com.fr.stable.EncodeConstants;
import com.fr.stable.resource.ResourceLoader;
import org.jetbrains.annotations.NotNull;
import javax.el.MethodNotFoundException;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 类抛出异常的转换
* 原则可以找不到但不要误报
*
* created by Harrison on 2022/05/24
**/
public class ClassConflictConvertor implements ThrowableConverter {
public static final String CLASSES = "classes";
public static final String SEPARATOR = "、";
/**
* 获取对应的 JAR 包名称
*/
private static final Pattern JAR_NAME_PATTERN = Pattern.compile("([\\w+-\\.]*\\.jar)");
private static final String WEB_INF_STRING = "WEB-INF";
private static final String JAR_URL_SUFFIX = ".jar!";
private static final String JAR_FILE_SUFFIX = ".jar";
private static final String FILE_URL_PREFIX = "file:";
private final Map<Class<?>, ClassNameConverter> throwableMap = new HashMap<>();
public ClassConflictConvertor() {
// 类异常
this.throwableMap.put(ClassNotFoundException.class, Converter.CLASS);
this.throwableMap.put(NoClassDefFoundError.class, Converter.CLASS);
this.throwableMap.put(ClassCastException.class, Converter.CLASS);
this.throwableMap.put(IncompatibleClassChangeError.class, Converter.CLASS);
// 方法异常
this.throwableMap.put(MethodNotFoundException.class, Converter.METHOD);
this.throwableMap.put(NoSuchMethodException.class, Converter.METHOD);
this.throwableMap.put(NoSuchMethodError.class, Converter.METHOD);
}
@Override
public boolean accept(Throwable throwable) {
Throwable sign = throwable;
while (sign != null) {
if (throwableMap.containsKey(sign.getClass())) {
return true;
}
sign = sign.getCause();
}
return false;
}
@Override
public DetectorResult convert(Throwable throwable) {
Iterable<String> classNames = Collections.emptyList();
Throwable sign = throwable;
while (sign != null) {
if (throwableMap.containsKey(sign.getClass())) {
classNames = throwableMap.get(sign.getClass())
.converter(throwable);
}
sign = sign.getCause();
}
Map<String, List<String>> libMap = new HashMap<>();
libMap.put(DetectorConstants.FR_HOME_LIB, new ArrayList<>());
libMap.put(DetectorConstants.WEB_LIB_PATH, new ArrayList<>());
Set<String> allPath = new HashSet<>();
for (String className : classNames) {
String classFile = convertClass2Path(className);
try {
Enumeration<URL> urls = ResourceLoader.getResources(classFile, this.getClass());
List<URL> urlList = new ArrayList<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
urlList.add(url);
}
for (URL url : urlList) {
String file = url.getFile();
String decodeFileStr = URLDecoder.decode(file, EncodeConstants.ENCODING_UTF_8);
if (decodeFileStr.contains(JAR_URL_SUFFIX)) {
String jarPath = decodeFileStr.substring(FILE_URL_PREFIX.length(), decodeFileStr.indexOf(JAR_URL_SUFFIX) + JAR_FILE_SUFFIX.length());
String jar = new File(jarPath).getName();
if (allPath.add(jar)) {
List<String> libPath;
if (file.contains(WEB_INF_STRING)) {
libPath = libMap.get(DetectorConstants.WEB_LIB_PATH);
} else {
libPath = libMap.get(DetectorConstants.FR_HOME_LIB);
}
libPath.add(jar);
}
}
}
} catch (IOException ignore) {
}
}
// 如果少于两个,则不需要提示
if (allPath.size() < 2) {
return null;
}
String msg = DetectorUtil.concatLibFormatMsg(libMap);
DetectorType type = DetectorType.JAR_CONFLICT;
return DetectorResult.exception(type,
ExceptionTips.create(Toolkit.i18nText(type.getTipsLocale()) + msg),
ExceptionSolution.create(Toolkit.i18nText(type.getSolutionLocale()), DetectorConstants.JAR_HELP_LINK, null),
ExceptionLog.create(Toolkit.i18nText(type.getLogLocale()) + msg));
}
@NotNull
private String convertClass2Path(String className) {
return "/" + className.replaceAll("\\.", "/") + ".class";
}
private interface ClassNameConverter {
/**
* 将异常解析为类名可能有多个
*
* @param throwable 异常
* @return 类名
*/
Iterable<String> converter(Throwable throwable);
}
public enum Converter implements ClassNameConverter {
/**
* 类匹配
*/
CLASS {
/**
* 匹配 111.222.333
* 至少有一个 111.
* 至少有一个 333
*/
private final Pattern CLASS_PATTERN = Pattern.compile("((\\w+\\.)+(\\w+))");
@Override
public Iterable<String> converter(Throwable throwable) {
String message = throwable.getMessage();
Matcher matcher = CLASS_PATTERN.matcher(message);
List<String> names = new ArrayList<>();
while (matcher.find()) {
String className = matcher.group();
names.add(className);
}
return names;
}
},
/**
* 方法匹配
*/
METHOD {
/**
* 后面有 .method()xxxx
*/
private final Pattern METHOD_PATTERN = Pattern.compile("((\\w+\\.)+(\\w+))(\\.\\w+\\(\\))");
@Override
public Iterable<String> converter(Throwable throwable) {
String message = throwable.getMessage();
Matcher matcher = METHOD_PATTERN.matcher(message);
List<String> names = new ArrayList<>();
while (matcher.find()) {
String className = matcher.group();
names.add(className);
}
return names;
}
}
}
}

69
designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbLockedConverter.java vendored

@ -0,0 +1,69 @@
package com.fr.env.detect.impl.converter;
import com.fr.design.i18n.Toolkit;
import com.fr.env.detect.base.DetectorConstants;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.thowable.ThrowableConverter;
import com.fr.third.org.apache.commons.lang3.StringUtils;
import com.fr.third.org.hsqldb.HsqlException;
import com.fr.workspace.WorkContext;
/**
* created by Harrison on 2022/05/24
**/
public class FineDbLockedConverter implements ThrowableConverter {
public static final String LOCK_FILE = "lockFile";
@Override
public boolean accept(Throwable throwable) {
Throwable sign = throwable;
while (sign != null) {
if (sign.getClass() == HsqlException.class) {
return true;
}
sign = sign.getCause();
}
return false;
}
/**
* 检测 FineDB 是否锁住
*
* @param throwable 异常
* @return 结果
*/
@Override
public DetectorResult convert(Throwable throwable) {
// 远程不执行
if (!WorkContext.getCurrent().isLocal()) {
return null;
}
Throwable sign = throwable;
while (sign != null && sign.getClass() != HsqlException.class) {
sign = sign.getCause();
}
if (sign == null) {
return null;
}
DetectorType type = DetectorType.FINE_DB_LOCKED;
String message = sign.getMessage();
if (StringUtils.containsIgnoreCase(message, LOCK_FILE)) {
return DetectorResult.builder()
.withType(type)
.withTips(Toolkit.i18nText(type.getTipsLocale()))
.withSolution(Toolkit.i18nText(type.getSolutionLocale(),DetectorConstants.FINE_DB_HELP_LINK), DetectorConstants.FINE_DB_HELP_LINK)
.withLog(Toolkit.i18nText(type.getLogLocale()))
.build();
}
return null;
}
}

84
designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbPermissionConverter.java vendored

@ -0,0 +1,84 @@
package com.fr.env.detect.impl.converter;
import com.fr.design.i18n.Toolkit;
import com.fr.env.detect.base.DetectorConstants;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.env.detect.thowable.ThrowableConverter;
import com.fr.stable.project.ProjectConstants;
import com.fr.third.org.apache.commons.io.FileUtils;
import com.fr.third.org.hsqldb.HsqlException;
import com.fr.workspace.WorkContext;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import java.util.Collection;
/**
* HSQL 下的权限检测
* <p>
* created by Harrison on 2022/05/24
**/
public class FineDbPermissionConverter implements ThrowableConverter {
public static final String EMBED_DB_NAME = "finedb";
@Override
public boolean accept(Throwable throwable) {
Throwable sign = throwable;
while (sign != null) {
if (sign.getClass() == HsqlException.class) {
return true;
}
sign = sign.getCause();
}
return false;
}
@Override
public DetectorResult convert(Throwable throwable) {
// 远程不执行
if (!WorkContext.getCurrent().isLocal()) {
return null;
}
Throwable sign = throwable;
while (sign != null && sign.getClass() != HsqlException.class) {
sign = sign.getCause();
}
if (sign == null) {
return null;
}
String fineDbDirectory = WorkContext.getCurrent().getPath() + File.separator + ProjectConstants.EMBED_DB_DIRECTORY + File.separator + EMBED_DB_NAME;
Collection<File> files = FileUtils.listFiles(new File(fineDbDirectory), null, true);
Boolean isPermitted = files.stream()
.map((file -> {
try {
// 进行权限判断
new RandomAccessFile(file, "rw");
return true;
} catch (FileNotFoundException e) {
return false;
}
}))
.reduce((a, b) -> a & b)
.orElse(Boolean.FALSE);
if (!isPermitted) {
DetectorType type = DetectorType.FINE_DB_PERMISSION;
return DetectorResult.builder()
.withType(type)
.withTips(Toolkit.i18nText(type.getTipsLocale()))
.withSolution(Toolkit.i18nText(type.getSolutionLocale(), DetectorConstants.FINE_DB_HELP_LINK),
DetectorConstants.FINE_DB_HELP_LINK)
.withLog(type.getLogLocale())
.build();
}
return null;
}
}

28
designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableConverter.java vendored

@ -0,0 +1,28 @@
package com.fr.env.detect.thowable;
import com.fr.env.detect.bean.DetectorResult;
import org.jetbrains.annotations.Nullable;
/**
* created by Harrison on 2022/05/13
**/
public interface ThrowableConverter {
/**
* 是否支持该异常
*
* @param throwable 异常
* @return /
*/
boolean accept(Throwable throwable);
/**
* 将异常转化为结果
*
* @param throwable 异常
* @return 转化结果
*/
@Nullable
DetectorResult convert(Throwable throwable);
}

72
designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableLogAppender.java vendored

@ -0,0 +1,72 @@
package com.fr.env.detect.thowable;
import com.fr.general.FRLogger;
import com.fr.log.LogHandler;
import com.fr.third.apache.logging.log4j.Level;
import com.fr.third.apache.logging.log4j.core.Filter;
import com.fr.third.apache.logging.log4j.core.Layout;
import com.fr.third.apache.logging.log4j.core.LogEvent;
import com.fr.third.apache.logging.log4j.core.appender.AbstractAppender;
import com.fr.third.apache.logging.log4j.core.config.Property;
import java.io.Serializable;
/**
* created by Harrison on 2022/05/13
**/
public class ThrowableLogAppender extends AbstractAppender {
public ThrowableLogAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions, Property[] properties) {
super(name, filter, layout, ignoreExceptions, properties);
}
public static ThrowableLogAppender getInstance() {
return ExceptionLogAppenderHolder.INSTANCE;
}
private static class ExceptionLogAppenderHolder {
private static final ThrowableLogAppender INSTANCE = new ThrowableLogAppender("exception-detect-appender", null, null, false, null);
}
private final LogHandler<ThrowableLogAppender> logHandler = toHandler();
@Override
public void append(LogEvent logEvent) {
try {
if (logEvent.getLevel() == Level.ERROR) {
Throwable thrown = logEvent.getThrown();
if (thrown != null) {
ThrowableStore.getInstance().add(thrown);
}
}
} catch (Throwable ignore) {
}
}
private LogHandler<ThrowableLogAppender> toHandler() {
final ThrowableLogAppender appender = this;
appender.start();
LogHandler<ThrowableLogAppender> handler = new LogHandler<ThrowableLogAppender>() {
@Override
public ThrowableLogAppender getHandler() {
return appender;
}
};
return handler;
}
public void enable() {
// 初始化一下,别出问题
logHandler.getHandler().start();
FRLogger.getLogger().addExtendLogAppender(logHandler);
}
public void disable() {
FRLogger.getLogger().removeExtendLogAppender(logHandler);
}
}

36
designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableStore.java vendored

@ -0,0 +1,36 @@
package com.fr.env.detect.thowable;
import java.util.ArrayList;
import java.util.List;
/**
* 异常存储中心
*
* created by Harrison on 2022/05/13
**/
public class ThrowableStore {
public static ThrowableStore getInstance() {
return ThrowableStoreHolder.INSTANCE;
}
private static class ThrowableStoreHolder {
private static final ThrowableStore INSTANCE = new ThrowableStore();
}
private List<Throwable> exceptions = new ArrayList<>();
public void add(Throwable throwable) {
if (throwable != null) {
exceptions.add(throwable);
}
}
public List<Throwable> getAll() {
return exceptions;
}
public void reset() {
exceptions.clear();
}
}

159
designer-base/src/main/java/com/fr/env/detect/ui/DetectorErrorDialog.java vendored

@ -0,0 +1,159 @@
package com.fr.env.detect.ui;
import com.fr.base.svg.IconUtils;
import com.fr.design.RestartHelper;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.utils.ColorUtils;
import com.fr.design.utils.DesignUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.env.detect.base.DetectorUtil;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.ExceptionSolution;
import com.fr.env.detect.bean.ExceptionTips;
import com.fr.env.detect.bean.Message;
import com.fr.exit.DesignerExiter;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
/**
* 未知错误框
* todo 其实这里可以将多个 error-dialog 抽象在一起的 时间不够 简单写写
* {@link com.fr.design.dialog.ErrorDialog}
*
* created by Harrison on 2022/05/29
**/
public class DetectorErrorDialog extends JDialog implements ActionListener {
public static final float FONT_BOLD_HEIGHT = 16f;
private UIButton okButton;
private UIButton restartButton;
public DetectorErrorDialog(Frame parent, List<DetectorResult> results) {
super(parent, true);
// 可能是还没初始化 UI 的时候出现的问题,初始化一下 UI
DesignUtils.initLookAndFeel();
JPanel northPane = FRGUIPaneFactory.createBorderLayout_L_Pane();
JPanel headerPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
headerPane.setLayout(new BorderLayout(15, 0));
UILabel iconLabel = new UILabel(IconUtils.readIcon("/com/fr/design/standard/reminder/reminder_warning_window.svg"));
headerPane.add(iconLabel, BorderLayout.WEST);
JPanel messagePane = FRGUIPaneFactory.createVerticalFlowLayout_S_Pane(true);
{
UILabel boldHeader = new UILabel(Toolkit.i18nText("Fine-Design_Error_Start_Apology_Message"));
Font font = boldHeader.getFont();
Font boldFont = font.deriveFont(FONT_BOLD_HEIGHT);
boldHeader.setFont(boldFont);
messagePane.add(boldHeader);
UILabel description = new UILabel(Toolkit.i18nText("Fine-Design_Send_Report_To_Us"));
messagePane.add(description);
}
headerPane.add(messagePane, BorderLayout.CENTER);
northPane.add(headerPane);
JPanel centerPane = FRGUIPaneFactory.createBorderLayout_L_Pane();
centerPane.setLayout(new BorderLayout(0, 5));
UILabel detailDesc = new UILabel(Toolkit.i18nText("Fine-Design_Problem_Detail_Message"));
centerPane.add(detailDesc, BorderLayout.NORTH);
JPanel detailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
detailPanel.setBorder(BorderFactory.createEmptyBorder(0, 20, 10, 10));
detailPanel.setLayout(new BorderLayout(0, 8));
for (DetectorResult result : results) {
JPanel detailItemPanel = FRGUIPaneFactory.createBorderLayout_L_Pane();
detailItemPanel.setLayout(new BorderLayout(0, 8));
ExceptionTips tips = result.getTips();
UILabel template = new UILabel();
template.setBackground(Color.white);
if (tips != null) {
Message tipsMsg = tips.getMessage();
detailItemPanel.add(DetectorUtil.convert2TextComponent(tipsMsg, template), BorderLayout.NORTH);
}
ExceptionSolution solution = result.getSolution();
if (solution != null) {
Message solutionMsg = solution.getMessage();
detailItemPanel.add(DetectorUtil.convert2TextComponent(solutionMsg, template), BorderLayout.CENTER);
}
detailPanel.add(detailItemPanel, BorderLayout.CENTER);
}
JScrollPane detailPanelWrapper = new JScrollPane(detailPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
ColorUtils.syncBackground(detailPanelWrapper, Color.WHITE);
centerPane.add(detailPanelWrapper, BorderLayout.CENTER);
JPanel southPane = FRGUIPaneFactory.createBorderLayout_L_Pane();
JPanel controlPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0));
okButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Ok"));
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
okEvent();
}
});
buttonPane.add(okButton);
restartButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Restart"));
restartButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
restartEvent();
}
});
buttonPane.add(restartButton);
controlPane.add(buttonPane, BorderLayout.EAST);
southPane.add(controlPane);
this.setTitle(Toolkit.i18nText("Fine-Design_Error_Start_Report"));
this.setResizable(false);
this.add(northPane, BorderLayout.NORTH);
this.add(centerPane, BorderLayout.CENTER);
this.add(southPane, BorderLayout.SOUTH);
this.setSize(new Dimension(650, 500));
GUICoreUtils.centerWindow(this);
}
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
protected void okEvent() {
dispose();
DesignerExiter.getInstance().execute();
}
protected void restartEvent() {
dispose();
RestartHelper.restart();
}
}

28
designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java vendored

@ -0,0 +1,28 @@
package com.fr.env.detect.ui;
import com.fr.design.actions.UpdateAction;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import java.awt.event.ActionEvent;
/**
* 工具栏里面的行为
*
* created by Harrison on 2022/05/29
**/
public class EnvDetectorAction extends UpdateAction {
public EnvDetectorAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Detect_Toolbar_Title"));
this.setSmallIcon("com/fr/env/detect/detect_normal.svg");
}
@Override
public void actionPerformed(ActionEvent e) {
EnvDetectorDialog dialog = new EnvDetectorDialog(DesignerContext.getDesignerFrame());
dialog.setVisible(true);
}
}

569
designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java vendored

@ -0,0 +1,569 @@
package com.fr.env.detect.ui;
import com.fr.base.svg.IconUtils;
import com.fr.design.components.notification.NotificationDialog;
import com.fr.design.components.notification.NotificationDialogProperties;
import com.fr.design.components.notification.NotificationModel;
import com.fr.design.components.table.TablePanel;
import com.fr.design.constants.DesignerColor;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ibutton.UIButtonUI;
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.ui.util.UIUtil;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.design.utils.gui.GUIPaintUtils;
import com.fr.env.detect.base.DetectorBridge;
import com.fr.env.detect.base.DetectorUtil;
import com.fr.env.detect.base.EnvDetectorConfig;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorStatus;
import com.fr.env.detect.bean.DetectorType;
import com.fr.log.FineLoggerFactory;
import org.jetbrains.annotations.NotNull;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.plaf.ButtonUI;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* created by Harrison on 2022/05/26
**/
public class EnvDetectorDialog extends JDialog {
private static final ImageIcon LOADING_ICON = getLoadingIcon();
private static final int TIMEOUT = 1000;
private static final Color SUCCESS_COLOR = new Color(22, 193, 83);
private static final Color DETAIL_FONT_COLOR = new Color(65, 155, 249);
private final JPanel body;
private final JPanel headerPanel;
private UIButton detectButton;
private JPanel resultSummaryPane;
private final TablePanel tablePanel;
private final JPanel tailPanel;
/* 数据 model */
private EnvDetectorModel model;
/* 流程 model */
/**
* 默认是第一个要检测
*/
private int currentDetectIndex = 0;
private EnvDetectorButtonStatus buttonStatus = EnvDetectorButtonStatus.START;
private SwingWorker<Void, Void> detectWorker = null;
/* config model */
private boolean detectOpen = EnvDetectorConfig.getInstance().isEnabled();
public EnvDetectorDialog(Frame owner) {
this(owner, null);
}
public EnvDetectorDialog(Frame owner, EnvDetectorModel model) {
super(owner);
configProperties();
if (model == null) {
this.model = new EnvDetectorModel();
} else {
this.model = model;
}
this.body = FRGUIPaneFactory.createBorderLayout_L_Pane();
Color backgroundColor = new Color(240, 240, 243, 1);
this.body.setBackground( backgroundColor);
this.headerPanel = createHeaderPanel();
body.add(headerPanel, BorderLayout.NORTH);
this.tablePanel = createTablePanel();
body.add(tablePanel, BorderLayout.CENTER);
/* tailPanel*/
this.tailPanel = createTailPanel();
body.add(tailPanel, BorderLayout.SOUTH);
add(body);
Dimension preferredSize = body.getPreferredSize();
setSize(preferredSize);
repaint();
pack();
GUICoreUtils.centerWindow(this);
}
/* header */
@NotNull
private JPanel createHeaderPanel() {
JPanel headerPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
headerPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 12, 0));
this.detectButton = new UIButton(buttonStatus.getDesc()) {
@Override
public ButtonUI getUI() {
return new UIButtonUI() {
@Override
protected void doExtraPainting(UIButton b, Graphics2D g2d, int w, int h, String selectedRoles) {
if (isPressed(b) && b.isPressedPainted()) {
GUIPaintUtils.fillPressed(g2d, 0, 0, w, h, b.isRoundBorder(), b.getRectDirection(), b.isDoneAuthorityEdited(selectedRoles),
DesignerColor.Button.Primary.PRESSED);
} else if (isRollOver(b)) {
GUIPaintUtils.fillRollOver(g2d, 0, 0, w, h, b.isRoundBorder(), b.getRectDirection(), b.isDoneAuthorityEdited(selectedRoles), b.isPressedPainted(),
DesignerColor.Button.Primary.HOVER);
} else if (b.isNormalPainted()) {
GUIPaintUtils.fillNormal(g2d, 0, 0, w, h, b.isRoundBorder(), b.getRectDirection(), b.isDoneAuthorityEdited(selectedRoles), b.isPressedPainted(),
DesignerColor.Button.Primary.NORMAL);
}
}
};
}
};
detectButton.setForeground(Color.WHITE);
detectButton.addActionListener(event -> {
if (buttonStatus.isNotExecuting()) {
startDetecting();
} else {
stopDetecting(detectButton);
}
});
detectButton.setPreferredSize(new Dimension(68, 20));
detectButton.setBorderPainted(false);
detectButton.setContentAreaFilled(false);
headerPanel.add(detectButton, BorderLayout.WEST);
return headerPanel;
}
private void startDetecting() {
// 重新检测的时候需要处理一些逻辑
if (buttonStatus == EnvDetectorButtonStatus.A_NEW) {
reInit();
}
// 执行前
buttonStatus = buttonStatus.next();
UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshHeader);
detectWorker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
List<EnvDetectorItem> items = model.getItems();
// 执行刷新
for (int i = currentDetectIndex; i < items.size(); i++) {
// 看一下是否关闭了, 有可能已经关闭了。
if (buttonStatus.isNotExecuting()) {
return null;
}
// 刷新一下面板-开始执行啦
UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshBody);
EnvDetectorItem item = items.get(i);
DetectorType type = item.getType();
// 执行检测, UI-当前在检测中
DetectorResult result = UIUtil.waitUntil(
() -> DetectorBridge.getInstance().detect(type),
TIMEOUT, TimeUnit.MILLISECONDS);
// 获取结果
item.setResult(result);
// 更新UI
// 只有还在运行中,才会真正的刷新面板
if (buttonStatus.isExecuting()) {
// 在刷新一下面板
UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshBody);
currentDetectIndex++;
}
}
return null;
}
@Override
protected void done() {
try {
this.get();
if (buttonStatus.isExecuting()) {
// 执行结束
buttonStatus = EnvDetectorButtonStatus.A_NEW;
UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshHeader);
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error("detect failed", e);
}
}
};
// 开始执行
detectWorker.execute();
}
private void reInit() {
currentDetectIndex = 0;
for (EnvDetectorItem e : model.getItems()) {
e.setResult(null);
}
// 刷新一下面板-开始执行啦
UIUtil.invokeLaterIfNeeded(EnvDetectorDialog.this::refreshBody);
}
private void stopDetecting(UIButton detectButton) {
buttonStatus = buttonStatus.next();
// 先停止
detectWorker.cancel(false);
// 更改-UI
// 执行中
UIUtil.invokeLaterIfNeeded(() -> {
// 刷新按钮
detectButton.setText(buttonStatus.getDesc());
// 刷新面板
refreshBody();
});
}
private void updateHeaderPanel() {
// 刷新按钮
detectButton.setText(buttonStatus.getDesc());
if (buttonStatus == EnvDetectorButtonStatus.A_NEW) {
this.resultSummaryPane = new JPanel();
this.resultSummaryPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
this.resultSummaryPane.setLayout(new BorderLayout(5, 0));
Boolean success = model.getResults()
.map((e) -> {
if (e != null && e.getStatus() == DetectorStatus.NORMAL) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}).reduce((a, b) -> a && b)
.orElse(Boolean.FALSE);
if (success) {
resultSummaryPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Detect_Result_Label")), BorderLayout.WEST);
UILabel successLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Detect_Result_Success"));
successLabel.setForeground(SUCCESS_COLOR);
resultSummaryPane.add(successLabel, BorderLayout.CENTER);
} else {
resultSummaryPane.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Detect_Result_Label")), BorderLayout.WEST);
UILabel resultLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Detect_Result_Error"));
resultLabel.setForeground(Color.RED);
resultSummaryPane.add(resultLabel, BorderLayout.CENTER);
}
this.headerPanel.add(BorderLayout.CENTER, resultSummaryPane);
} else {
if (resultSummaryPane != null) {
this.headerPanel.remove(resultSummaryPane);
}
}
}
/* table */
@NotNull
private TablePanel createTablePanel() {
TablePanel tablePanel = new TablePanel(18, 3);
tablePanel.updateHeaders(new String[] {
Toolkit.i18nText("Fine-Design_Basic_Detect_Kind"),
Toolkit.i18nText("Fine-Design_Basic_Detect_Item"),
Toolkit.i18nText("Fine-Design_Basic_Detect_Result")});
updateTable(tablePanel);
return tablePanel;
}
private void updateTable(TablePanel tablePanel) {
Map<DetectorType.Kind, List<EnvDetectorItem>> itemMap = model.getItemMap();
// 行号, 这边更新是通过 行/列 。 不是索引
int row = 1;
for (Map.Entry<DetectorType.Kind, List<EnvDetectorItem>> entry : itemMap.entrySet()) {
DetectorType.Kind kind = entry.getKey();
List<EnvDetectorItem> items = entry.getValue();
for (int i = 0; i < items.size(); i++) {
if (i == 0) {
tablePanel.updateCell(row, 1, kind.getDescription());
}
EnvDetectorItem item = items.get(i);
tablePanel.updateCell(row, 2, new UILabel(item.getDescription()));
DetectorResult result = item.getResult();
int detectRow = currentDetectIndex + 1;
if (result == null) {
// 处于非正在检测状态 或者 索引不等于当前行号的时候
UILabel label;
if (buttonStatus.isExecuting() && detectRow == row) {
// 正在检测索引
label = new UILabel(LOADING_ICON, UILabel.LEADING);
} else {
label = new UILabel("-");
}
tablePanel.updateCell(row, 3, label);
} else {
Component resultComponent = createResultComponent(result);
tablePanel.updateCell(row, 3, resultComponent);
}
row++;
}
}
}
private Component createResultComponent(DetectorResult result) {
JPanel statusPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
if (result.getStatus() == DetectorStatus.NORMAL) {
statusPanel.add(new UILabel(IconUtils.readIcon("/com/fr/design/standard/reminder/reminder_success.svg")), BorderLayout.WEST);
statusPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Normal")), BorderLayout.CENTER);
} else {
JPanel infoPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
{
infoPanel.add(new UILabel(IconUtils.readIcon("/com/fr/design/standard/reminder/reminder_error.svg")), BorderLayout.WEST);
infoPanel.add(new UILabel(Toolkit.i18nText("Fine-Design_Basic_Exception")), BorderLayout.CENTER);
}
statusPanel.add(infoPanel, BorderLayout.WEST);
// 如果结果是检测出的异常,则出现详细信息。
if (result.getStatus() == DetectorStatus.EXCEPTION) {
JPanel detailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
{
detailPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
UILabel detailLabel = new UILabel(Toolkit.i18nText("Fine_Designer_Look_Detail"));
detailLabel.setForeground(DETAIL_FONT_COLOR);
detailLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent mouseEvent) {
NotificationDialogProperties properties = new NotificationDialogProperties((Frame) EnvDetectorDialog.this.getOwner(), Toolkit.i18nText("Fine-Design_Basic_Detect_Notification_Title"));
Stream<DetectorResult> results = model.getResults();
List<NotificationModel> notificationModels = results
.filter(Objects::nonNull)
.filter((e) -> e.getStatus() == DetectorStatus.EXCEPTION)
.map(DetectorUtil::convert2Notification)
.collect(Collectors.toList());
NotificationDialog dialog = new NotificationDialog(properties, notificationModels);
dialog.open();
}
});
detailPanel.add(detailLabel, BorderLayout.CENTER);
}
statusPanel.add(detailPanel, BorderLayout.CENTER);
}
}
return statusPanel;
}
/* tail */
@NotNull
private JPanel createTailPanel() {
JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
tailPanel.setBorder(BorderFactory.createEmptyBorder(20, 0, 0, 0));
JPanel configPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
{
UICheckBox checkBox = new UICheckBox();
checkBox.setSelected(this.detectOpen);
checkBox.addChangeListener(e -> {
UICheckBox source = (UICheckBox) e.getSource();
EnvDetectorDialog.this.detectOpen = source.isSelected();
});
configPanel.add(checkBox, BorderLayout.WEST);
UILabel description = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Detect_Switch"));
configPanel.add(description, BorderLayout.EAST);
}
tailPanel.add(configPanel, BorderLayout.WEST);
JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
actionsPanel.setLayout(FRGUIPaneFactory.createM_BorderLayout());
{
UIButton confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Confirm"));
confirmButton.addActionListener((e) -> {
setVisible(false);
dispose();
// 配置处理
EnvDetectorConfig.getInstance().setEnabled(this.detectOpen);
});
actionsPanel.add(confirmButton, BorderLayout.WEST);
UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel"));
cancelButton.addActionListener((e) -> {
setVisible(false);
dispose();
});
actionsPanel.add(cancelButton, BorderLayout.EAST);
}
tailPanel.add(actionsPanel, BorderLayout.EAST);
return tailPanel;
}
private void refreshHeader() {
updateHeaderPanel();
pack();
repaint();
}
private void refreshBody() {
updateTable(this.tablePanel);
pack();
repaint();
}
private static ImageIcon getLoadingIcon() {
URL resource = EnvDetectorDialog.class.getResource("/com/fr/design/standard/loading/loading-120.gif");
if (resource == null) {
return null;
}
ImageIcon loadingIcon = new ImageIcon(resource);
int width = 16;
int height = 16;
loadingIcon.setImage(loadingIcon.getImage().getScaledInstance(width, height, Image.SCALE_DEFAULT));
return loadingIcon;
}
private void configProperties() {
setTitle(Toolkit.i18nText("Fine-Design_Basic_Detect_Title"));
setModal(false);
setFocusable(false);
setAutoRequestFocus(false);
setResizable(false);
}
/**
* 按钮的当前状态
*/
private enum EnvDetectorButtonStatus {
/**
* 开始 -> 停止
*/
START("Fine-Design_Basic_Detect_Start") {
@Override
public EnvDetectorButtonStatus next() {
return STOP;
}
},
/**
* 停止 -> 继续
*/
STOP("Fine-Design_Basic_Detect_Stop") {
@Override
public EnvDetectorButtonStatus next() {
return CONTINUE;
}
},
/**
* 继续 -> 停止
*/
CONTINUE("Fine-Design_Basic_Detect_Continue") {
@Override
public EnvDetectorButtonStatus next() {
return STOP;
}
},
/**
* 重新 -> 停止
*/
A_NEW("Fine-Design_Basic_Detect_A_New") {
@Override
public EnvDetectorButtonStatus next() {
return STOP;
}
}
;
private String descLocale;
EnvDetectorButtonStatus(String descLocale) {
this.descLocale = descLocale;
}
public String getDesc() {
return Toolkit.i18nText(descLocale);
}
/**
* 在执行中
*
* @return /
*/
public boolean isExecuting() {
return this == EnvDetectorButtonStatus.STOP;
};
/**
* 不在执行中
*
* @return /
*/
public boolean isNotExecuting() {
return !isExecuting();
}
public abstract EnvDetectorButtonStatus next();
}
private class EnvDetectorHeaderPanel extends JPanel {
}
}

40
designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorItem.java vendored

@ -0,0 +1,40 @@
package com.fr.env.detect.ui;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
/**
* 环境检测条目
*
* created by Harrison on 2022/05/27
**/
public class EnvDetectorItem {
private DetectorType type;
private DetectorResult result;
public EnvDetectorItem(DetectorType detectorType) {
this.type = detectorType;
}
public DetectorType getType() {
return type;
}
public String getKind() {
return this.type.getKind().getDescription();
}
public String getDescription() {
return this.type.getDescription();
}
public DetectorResult getResult() {
return result;
}
public void setResult(DetectorResult result) {
this.result = result;
}
}

70
designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorModel.java vendored

@ -0,0 +1,70 @@
package com.fr.env.detect.ui;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import com.fr.third.guava.collect.Lists;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 环境检测数据格式
*
* created by Harrison on 2022/05/27
**/
public class EnvDetectorModel {
/**
* 类型 -> list [{type-result}]
*/
private final Map<DetectorType.Kind, List<EnvDetectorItem>> itemMap = new LinkedHashMap<>();
public EnvDetectorModel() {
itemMap.put(DetectorType.Kind.JAR, Lists.newArrayList(
new EnvDetectorItem(DetectorType.LACK_OF_JAR),
new EnvDetectorItem(DetectorType.JAR_IN_CONSISTENCE),
new EnvDetectorItem(DetectorType.JAR_CONFLICT)));
itemMap.put(DetectorType.Kind.FINE_DB, Lists.newArrayList(
new EnvDetectorItem(DetectorType.FINE_DB_LOCKED),
new EnvDetectorItem(DetectorType.FINE_DB_PERMISSION),
new EnvDetectorItem(DetectorType.FINE_DB_DIRTY)));
}
public void update(DetectorType type, DetectorResult result) {
List<EnvDetectorItem> items = itemMap.get(type.getKind());
items.stream()
.filter((e) -> e.getType() == type)
.findFirst()
.ifPresent((e) -> {
e.setResult(result);
});
}
public Stream<DetectorResult> getResults() {
return getItems().stream()
.map(EnvDetectorItem::getResult);
}
public List<EnvDetectorItem> getItems() {
return itemMap.values().stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
public Map<DetectorType.Kind, List<EnvDetectorItem>> getItemMap() {
return this.itemMap;
}
}

18
designer-base/src/main/java/com/fr/exit/ConfigToPropMigrator.java

@ -10,6 +10,8 @@ import com.fr.workspace.WorkContext;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.sql.Blob; import java.sql.Blob;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
@ -62,9 +64,9 @@ public class ConfigToPropMigrator {
initDirectory(); initDirectory();
try (Connection c = DriverManager.getConnection(url); try (Connection c = DriverManager.getConnection(url);
FileOutputStream entityOut = new FileOutputStream(PropertiesConstants.ENTITY_PROP_PATH); OutputStreamWriter xmlEntityOut = new OutputStreamWriter(new FileOutputStream(PropertiesConstants.XML_ENTITY_PROP_PATH), StandardCharsets.UTF_8);
FileOutputStream classHelperOut = new FileOutputStream(PropertiesConstants.CLASS_NAME_PROP_PATH); OutputStreamWriter entityOut = new OutputStreamWriter(new FileOutputStream(PropertiesConstants.ENTITY_PROP_PATH), StandardCharsets.UTF_8);
FileOutputStream xmlEntityOut = new FileOutputStream(PropertiesConstants.XML_ENTITY_PROP_PATH)) { OutputStreamWriter classHelperOut = new OutputStreamWriter(new FileOutputStream(PropertiesConstants.CLASS_NAME_PROP_PATH), StandardCharsets.UTF_8)) {
processClassOrEntity(c, new Properties(), SELECT_FOR_ENTITY, entityOut); processClassOrEntity(c, new Properties(), SELECT_FOR_ENTITY, entityOut);
processClassOrEntity(c, new Properties(), SELECT_FOR_CLASSNAME, classHelperOut); processClassOrEntity(c, new Properties(), SELECT_FOR_CLASSNAME, classHelperOut);
@ -84,7 +86,7 @@ public class ConfigToPropMigrator {
} }
} }
private void processClassOrEntity(Connection c, Properties map, String sql, FileOutputStream outputStream) throws SQLException, IOException { private void processClassOrEntity(Connection c, Properties map, String sql, OutputStreamWriter writer) throws SQLException, IOException {
PreparedStatement query = c.prepareStatement(sql); PreparedStatement query = c.prepareStatement(sql);
ResultSet resultSet = query.executeQuery(); ResultSet resultSet = query.executeQuery();
while (resultSet.next()) { while (resultSet.next()) {
@ -94,19 +96,19 @@ public class ConfigToPropMigrator {
map.setProperty(id, value); map.setProperty(id, value);
} }
} }
map.store(outputStream, null); map.store(writer, null);
} }
private void processXmlEntity(Connection c, Properties map, FileOutputStream outputStream) throws SQLException, IOException { private void processXmlEntity(Connection c, Properties map, OutputStreamWriter writer) throws SQLException, IOException {
PreparedStatement query = c.prepareStatement(SELECT_FOR_XML_ENTITY); PreparedStatement query = c.prepareStatement(SELECT_FOR_XML_ENTITY);
ResultSet resultSet = query.executeQuery(); ResultSet resultSet = query.executeQuery();
while (resultSet.next()) { while (resultSet.next()) {
String id = resultSet.getString(1); String id = resultSet.getString(1);
Blob value = resultSet.getBlob(2); Blob value = resultSet.getBlob(2);
byte[] bytes = value.getBytes(1L, (int) value.length()); byte[] bytes = value.getBytes(1L, (int) value.length());
map.setProperty(id, new String(bytes)); map.setProperty(id, new String(bytes, StandardCharsets.UTF_8));
} }
map.store(outputStream, null); map.store(writer, null);
} }
public void deletePropertiesCache() { public void deletePropertiesCache() {

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save