Browse Source

Merge pull request #9195 in DESIGN/design from release/11.0 to final/11.0

* commit '480491d501b489c6a5aeba2739fe5c46cafbef47': (92 commits)
  REPORT-72468 决策报表-frm拖入tab块,tab内拖入两个图表块和两个文本域控件,重复随机拖拽调整组件位置,会突然出现组件重叠且错乱的现象
  REPORT-73318【设计器环境监测】服务器finedb有脏数据,设计器远程切换,过程很慢且没有自动监测弹窗 1-补充日志 2-修复一个问题,要执行完之后移除,不然在 UI 线程中不执行了
  REPORT-73475 FR11决策报表-附件客户模板,tablayout0的Tab0下拖入tab块,会添加一个重名为tablayout0的tab块
  import
  REPORT-72237 缓存配置面板显示在在所有应用最上方的问题
  REPORT-73318【设计器环境监测】服务器finedb有脏数据,设计器远程切换,过程很慢且没有自动监测弹窗 1-简化操作,不区分 设计器/服务器 启动。只在设计器启动后进行检测 2-切换环境的检测。切换环境后上次的任务需要停止执行。 3-FineDB 检测从捕获检测,切换到全量检测
  REPORT-73532 改下跳转预览
  REPORT-73532 F0017埋点新增content 处理兼容问题
  REPORT-73532 F0017埋点新增content 处理兼容问题
  REPORT-73586【设计器环境监测】远程连接失败后,触发手动检测,检测失败 更新注释
  REPORT-73586【设计器环境监测】远程连接失败后,触发手动检测,检测失败 和产品沟通,添加交互存在检测过程的异常
  REPORT-71901 安装/禁用图表插件,图表工具栏更新异常
  REPORT-73532 F0017埋点新增content
  REPORT-73557【设计器环境监测】预期外的启动弹窗交互与设计稿不一致 1、修改一下字体的实现,不然和其他的字体不统一。 2、初始化一下 UI
  REPORT-71476 新建保存后,目录没有选中模板,重命名不应该高亮
  REPORT-71908 组合图配置条件属性汇总字段值,设置后条件属性内容被清空了
  REPORT-73283【设计器环境监测】个别jar异常时,不会触发自动检测 改一个国际化信息
  REPORT-73557【设计器环境监测】预期外的启动弹窗交互与设计稿不一致 1-添加图标 2-处理 html 的 style, 使背景保持一致。
  REPORT-73262【设计器环境监测】右下角弹窗文字显示不全 右边的大小 Border 太大了, 更换一下。
  REPORT-71331 在选择表头区域时预览模板,预览效果异常
  ...
new-design
superman 3 years ago
parent
commit
1421d0419a
  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. 6
      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. 21
      designer-base/src/main/java/com/fr/design/components/notification/NotificationAction.java
  8. 391
      designer-base/src/main/java/com/fr/design/components/notification/NotificationDialog.java
  9. 39
      designer-base/src/main/java/com/fr/design/components/notification/NotificationDialogProperties.java
  10. 88
      designer-base/src/main/java/com/fr/design/components/notification/NotificationMessage.java
  11. 39
      designer-base/src/main/java/com/fr/design/components/notification/NotificationModel.java
  12. 16
      designer-base/src/main/java/com/fr/design/components/notification/NotificationType.java
  13. 78
      designer-base/src/main/java/com/fr/design/components/page/PageControlModel.java
  14. 151
      designer-base/src/main/java/com/fr/design/components/page/PageControlPanel.java
  15. 184
      designer-base/src/main/java/com/fr/design/components/table/TablePanel.java
  16. 24
      designer-base/src/main/java/com/fr/design/constants/DesignerColor.java
  17. 11
      designer-base/src/main/java/com/fr/design/data/datapane/SummaryMethodComboBox.java
  18. 5
      designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/DBTableDataPane.java
  19. 24
      designer-base/src/main/java/com/fr/design/dialog/FineJOptionPane.java
  20. 80
      designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java
  21. 22
      designer-base/src/main/java/com/fr/design/extra/exe/ReadUpdateOnlineExecutor.java
  22. 5
      designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java
  23. 39
      designer-base/src/main/java/com/fr/design/file/SaveSomeTemplatePane.java
  24. 18
      designer-base/src/main/java/com/fr/design/gui/frpane/TreeSettingPane.java
  25. 11
      designer-base/src/main/java/com/fr/design/gui/ilable/ActionLabel.java
  26. 138
      designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/TreeRootPane.java
  27. 10
      designer-base/src/main/java/com/fr/design/gui/style/BackgroundPane.java
  28. 5
      designer-base/src/main/java/com/fr/design/gui/style/BorderPane.java
  29. 20
      designer-base/src/main/java/com/fr/design/gui/style/FormatPane.java
  30. 7
      designer-base/src/main/java/com/fr/design/gui/style/TextFormatPane.java
  31. 6
      designer-base/src/main/java/com/fr/design/lock/LockInfoDialog.java
  32. 17
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
  33. 57
      designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
  34. 12
      designer-base/src/main/java/com/fr/design/mainframe/JTemplateActionListener.java
  35. 2
      designer-base/src/main/java/com/fr/design/mainframe/backgroundpane/NullBackgroundQuickPane.java
  36. 5
      designer-base/src/main/java/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java
  37. 15
      designer-base/src/main/java/com/fr/design/style/FormatPane.java
  38. 29
      designer-base/src/main/java/com/fr/design/ui/util/UIUtil.java
  39. 22
      designer-base/src/main/java/com/fr/design/update/ui/dialog/UpdateMainDialog.java
  40. 30
      designer-base/src/main/java/com/fr/design/utils/ColorUtils.java
  41. 63
      designer-base/src/main/java/com/fr/design/utils/LinkStrUtils.java
  42. 20
      designer-base/src/main/java/com/fr/design/utils/TemplateUtils.java
  43. 37
      designer-base/src/main/java/com/fr/design/worker/save/SaveFailureHandler.java
  44. 27
      designer-base/src/main/java/com/fr/env/EnvPrepare.java
  45. 226
      designer-base/src/main/java/com/fr/env/detect/EnvDetectorCenter.java
  46. 19
      designer-base/src/main/java/com/fr/env/detect/base/AbstractExceptionDetector.java
  47. 55
      designer-base/src/main/java/com/fr/env/detect/base/CatchExceptionDetector.java
  48. 146
      designer-base/src/main/java/com/fr/env/detect/base/DetectorBridge.java
  49. 18
      designer-base/src/main/java/com/fr/env/detect/base/DetectorConstants.java
  50. 53
      designer-base/src/main/java/com/fr/env/detect/base/DetectorManager.java
  51. 166
      designer-base/src/main/java/com/fr/env/detect/base/DetectorUtil.java
  52. 59
      designer-base/src/main/java/com/fr/env/detect/base/EnvDetectorConfig.java
  53. 25
      designer-base/src/main/java/com/fr/env/detect/base/ExceptionDetector.java
  54. 40
      designer-base/src/main/java/com/fr/env/detect/base/ThrowableBridge.java
  55. 4
      designer-base/src/main/java/com/fr/env/detect/base/package-info.java
  56. 147
      designer-base/src/main/java/com/fr/env/detect/bean/DetectorResult.java
  57. 22
      designer-base/src/main/java/com/fr/env/detect/bean/DetectorStatus.java
  58. 159
      designer-base/src/main/java/com/fr/env/detect/bean/DetectorType.java
  59. 36
      designer-base/src/main/java/com/fr/env/detect/bean/ExceptionLog.java
  60. 32
      designer-base/src/main/java/com/fr/env/detect/bean/ExceptionSolution.java
  61. 24
      designer-base/src/main/java/com/fr/env/detect/bean/ExceptionTips.java
  62. 83
      designer-base/src/main/java/com/fr/env/detect/bean/Message.java
  63. 11
      designer-base/src/main/java/com/fr/env/detect/bean/SolutionAction.java
  64. 106
      designer-base/src/main/java/com/fr/env/detect/impl/FineDbDirtyDetector.java
  65. 16
      designer-base/src/main/java/com/fr/env/detect/impl/FineDbLockedDetector.java
  66. 15
      designer-base/src/main/java/com/fr/env/detect/impl/FineDbPermissionDetector.java
  67. 15
      designer-base/src/main/java/com/fr/env/detect/impl/JarConflictDetector.java
  68. 156
      designer-base/src/main/java/com/fr/env/detect/impl/JarInconsistentDetector.java
  69. 159
      designer-base/src/main/java/com/fr/env/detect/impl/JarLackDetector.java
  70. 212
      designer-base/src/main/java/com/fr/env/detect/impl/converter/ClassConflictConvertor.java
  71. 59
      designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbLockedConverter.java
  72. 55
      designer-base/src/main/java/com/fr/env/detect/impl/converter/FineDbPermissionConverter.java
  73. 28
      designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableConverter.java
  74. 72
      designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableLogAppender.java
  75. 36
      designer-base/src/main/java/com/fr/env/detect/thowable/ThrowableStore.java
  76. 159
      designer-base/src/main/java/com/fr/env/detect/ui/DetectorErrorDialog.java
  77. 28
      designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorAction.java
  78. 569
      designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorDialog.java
  79. 40
      designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorItem.java
  80. 70
      designer-base/src/main/java/com/fr/env/detect/ui/EnvDetectorModel.java
  81. 18
      designer-base/src/main/java/com/fr/exit/ConfigToPropMigrator.java
  82. 117
      designer-base/src/main/java/com/fr/exit/DesignerExiter.java
  83. 8
      designer-base/src/main/java/com/fr/file/StashedFILE.java
  84. 3
      designer-base/src/main/java/com/fr/start/BaseDesigner.java
  85. 3
      designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_left.svg
  86. 3
      designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_right.svg
  87. 3
      designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_left.svg
  88. 3
      designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_right.svg
  89. BIN
      designer-base/src/main/resources/com/fr/design/standard/loading/loading-120.gif
  90. BIN
      designer-base/src/main/resources/com/fr/design/standard/loading/loading-64.gif
  91. 4
      designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_error.svg
  92. 3
      designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_success.svg
  93. 5
      designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning.svg
  94. 9
      designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning_window.svg
  95. 3
      designer-base/src/main/resources/com/fr/env/detect/detect.svg
  96. 3
      designer-base/src/main/resources/com/fr/env/detect/detect_normal.svg
  97. 43
      designer-base/src/test/java/com/fr/design/components/notification/NotificationDialogTest.java
  98. 12
      designer-base/src/test/java/com/fr/design/utils/DevDebugUtils.java
  99. 60
      designer-base/src/test/java/com/fr/design/utils/DevUtils.java
  100. 23
      designer-base/src/test/java/com/fr/env/detect/impl/converter/ClassConflictConvertorTest.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.utils.DesignUtils;
import com.fr.design.utils.DesignerPort;
import com.fr.env.detect.base.EnvDetectorConfig;
import com.fr.exit.DesignerExiter;
import com.fr.file.FILEFactory;
import com.fr.general.ComparatorUtils;
@ -168,6 +169,12 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
private boolean embedServerLazyStartup = false;
//最近使用的颜色
private ColorSelectConfigManager configManager = new ColorSelectConfigManager();
/**
* 环境检测配置
*/
private EnvDetectorConfig envDetectorConfig = EnvDetectorConfig.getInstance();
/**
* alphafine
*/
@ -1820,6 +1827,8 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
readActiveStatus(reader);
} else if (ComparatorUtils.equals(CAS_PARAS, name)) {
readHttpsParas(reader);
} else if (name.equals(EnvDetectorConfig.XML_TAG)) {
readEnvDetectorConfig(reader);
} else if (name.equals("AlphaFineConfigManager")) {
readAlphaFineAttr(reader);
} else if (name.equals("RecentColors")) {
@ -1856,6 +1865,10 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
private void readAlphaFineAttr(XMLableReader reader) {
reader.readXMLObject(this.alphaFineConfigManager = AlphaFineConfigManager.getInstance());
}
private void readEnvDetectorConfig(XMLableReader reader) {
reader.readXMLObject(this.envDetectorConfig);
}
private void readHttpsParas(XMLableReader reader) {
String tempVal;
@ -2070,6 +2083,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
writeActiveStatus(writer);
writeHttpsParas(writer);
writeAlphaFineAttr(writer);
writeEnvDetectorConfig(writer);
writeRecentColor(writer);
writeOpenDebug(writer);
writeDesignerPushUpdateAttr(writer);
@ -2113,6 +2127,12 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
writer.end();
}
}
private void writeEnvDetectorConfig(XMLPrintWriter writer) {
if (this.envDetectorConfig != null) {
this.envDetectorConfig.writeXML(writer);
}
}
//写入uuid
private void writeUUID(XMLPrintWriter writer) {
@ -2220,7 +2240,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
writer.attr("layoutTemplateStyle", this.getLayoutTemplateStyle());
writer.attr("showServerDatasetAuthTip", this.isShowServerDatasetAuthTip());
writer.attr("useOptimizedUPM4Adapter", this.isUseOptimizedUPM4Adapter());
writer.attr("propertiesUsable", false);
writer.attr("propertiesUsable", this.isPropertiesUsable());
writer.end();
}

6
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.RemoteWorkspace;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.file.SaveSomeTemplatePane;
import com.fr.design.file.TemplateTreePane;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
@ -388,6 +389,11 @@ public class EnvChangeEntrance {
@Override
public void doOk() {
SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true, SwingUtilities.getWindowAncestor(envListPane));
if (!saveSomeTemplatePane.showSavePane()) {
// 用户取消保存时,取消切换目录操作
return;
}
boolean changeResult = envListOkAction(envListPane, PopTipStrategy.LATER);
// 切换完成后清理密码
updateNotRememberPwdEnv();

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

@ -3,6 +3,7 @@
*/
package com.fr.design.actions.file;
import com.fr.design.file.SaveSomeTemplatePane;
import com.fr.design.mainframe.TemplateSavingChecker;
import java.awt.event.ActionEvent;
@ -28,9 +29,14 @@ public class ExitDesignerAction extends UpdateAction {
* @param e 事件
*/
public void actionPerformed(ActionEvent e) {
// 检查是否有正在保存的模板
if (!TemplateSavingChecker.check()) {
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.DialogActionListener;
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.ibutton.UIButton;
import com.fr.design.gui.ibutton.UIColorButton;
@ -889,6 +890,12 @@ public class PreferencePane extends BasicPane {
if (!languageChanged) {
return;
}
// 重启弹窗出现之前提示用户保存模板
SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(true, SwingUtilities.getWindowAncestor(this));
if (!saveSomeTempaltePane.showSavePane()) {
// 保存失败时,直接返回
return;
}
int rv = JOptionPane.showOptionDialog(
null,
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.env.DesignerWorkspaceInfo;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.file.SaveSomeTemplatePane;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.menu.KeySetUtils;
import com.fr.design.menu.MenuDef;
@ -66,7 +67,11 @@ public class SwitchExistEnv extends MenuDef {
// 打开配置目录面板
EnvChangeEntrance.getInstance().chooseEnv(envName);
} else {
EnvChangeEntrance.getInstance().switch2Env(envName);
SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true);
if (saveSomeTemplatePane.showSavePane()) {
// 用户模板保存后,才进行切换目录操作
EnvChangeEntrance.getInstance().switch2Env(envName);
}
}
}

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) {
for (int i = 0; i < CLASS_ARRAY.length; i++) {
if (function != null && ComparatorUtils.equals(function.getClass(), CLASS_ARRAY[i])) {
setSelectedIndex(i);
break;
if (function != null) {
for (int i = 0; i < CLASS_ARRAY.length; i++) {
if (this.getModel() != null && this.getModel().getSize() > i
&& 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.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import java.awt.BorderLayout;
@ -303,7 +304,7 @@ public class DBTableDataPane extends AbstractTableDataPane<DBTableData> {
//显示对应的配置
strategyConfigPane.populateBean(populateStrategyConfig);
BasicDialog dlg = strategyConfigPane.showMediumWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() {
BasicDialog dlg = strategyConfigPane.showMediumWindow(SwingUtilities.getWindowAncestor(DBTableDataPane.this), new DialogActionAdapter() {
@Override
public void doOk() {
super.doOk();
@ -314,7 +315,7 @@ public class DBTableDataPane extends AbstractTableDataPane<DBTableData> {
}
}
});
dlg.setAlwaysOnTop(true);
//dlg.setAlwaysOnTop(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 java.awt.Component;
import java.awt.HeadlessException;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
@ -184,6 +185,29 @@ public class FineJOptionPane extends JOptionPane {
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 消息内容

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

@ -1,16 +1,18 @@
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.stable.StringUtils;
import javax.swing.JEditorPane;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Font;
import java.net.URI;
import java.net.URL;
import static com.fr.design.utils.LinkStrUtils.LABEL;
/**
* 用来构建JOptionPane带超链的消息提示
@ -20,9 +22,28 @@ import java.net.URI;
* Created by hades on 2020/10/23
*/
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) {
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) {
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);
setEditable(false);
setBorder(null);
}
protected void initListener(String link) {
addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
try {
Desktop.getDesktop().browse(URI.create(link));
} catch (Exception exception) {
FineLoggerFactory.getLogger().error(exception.getMessage(), exception);
}
protected void initListener() {
addHyperlinkListener(hyperlinkEvent -> {
try {
if (hyperlinkEvent.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
URL url = hyperlinkEvent.getURL();
Desktop.getDesktop().browse(url.toURI());
}
} 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) {
// 构建相同风格样式
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;
protected void initListener(String link) {
initListener(() -> {
try {
Desktop.getDesktop().browse(URI.create(link));
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
});
}
}

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

@ -1,15 +1,24 @@
package com.fr.design.extra.exe;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.extra.PluginsReaderFromStore;
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.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.view.PluginView;
import com.fr.stable.StringUtils;
import javax.swing.JOptionPane;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import static com.fr.design.dialog.FineJOptionPane.OPTION_OK_CANCEL;
/**
* Created by vito on 16/4/19.
*/
@ -41,6 +50,19 @@ public class ReadUpdateOnlineExecutor implements Executor {
jsonArray.put(jsonObject);
}
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) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}

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

@ -353,7 +353,7 @@ public class HistoryTemplateListCache implements CallbackEvent {
int size = historyList.size();
for (int i = 0; i < size; i++) {
JTemplate<?, ?> template = historyList.get(i);
FILE file = template.templateToStashFile();
FILE file = template.templateToStashFile4Envchange();
if (file != null) {
stashFILEMap.put(i, file);
}
@ -382,7 +382,8 @@ public class HistoryTemplateListCache implements CallbackEvent {
}
FineLoggerFactory.getLogger().info("{} is being reloaded", stashedFile.getName());
JTemplate<?, ?> template = historyList.get(i);
template.refreshResource(stashedFile);
// 切换环境后,刷新资源并且将暂存的FILE替换到template中
template.refreshResourceAndEditingFILE(stashedFile);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}

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.log.FineLoggerFactory;
import com.fr.stable.ProductConstants;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
@ -43,17 +42,27 @@ public class SaveSomeTemplatePane extends BasicPane {
private boolean isJudgeCurrentEditingTemplate = true;
public SaveSomeTemplatePane(boolean isNeedTojudgeCurrent) {
this(isNeedTojudgeCurrent, DesignerContext.getDesignerFrame());
}
/**
* 支持自定义设置 dialog的父窗口
* @param isNeedTojudgeCurrent
* @param parent
*/
public SaveSomeTemplatePane(boolean isNeedTojudgeCurrent, Window parent) {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
if (this.dialog == null) {
this.dialog = this.showSmallWindow(DesignerContext.getDesignerFrame(), new DialogActionAdapter() {
this.dialog = this.showSmallWindow(parent, new DialogActionAdapter() {
@Override
public void doOk() {
isAllSaved = true;
for (int i = 0; i < templateCheckBoxes.length; i++) {
if (templateCheckBoxes[i].isSelected()) {
saveSelectedTemplate(unSavedTemplate.get(i));
// 当存在模板保存失败时,视为整体的isAllSaved失败
isAllSaved = saveSelectedTemplate(unSavedTemplate.get(i)) && isAllSaved;
}
}
isAllSaved = true;
}
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()) {
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()));
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() {
return com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Save");
}

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") + " :");
buildWayPanel.add(buildWayLabel);
buildBox = new UIComboBox(buildWay);
buildBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
cardChanged(buildBox.getSelectedIndex());
}
buildBox.addItemListener(e -> {
cardChanged(buildBox.getSelectedIndex());
});
buildWayPanel.add(buildBox);
@ -79,7 +75,15 @@ public class TreeSettingPane extends BasicPane implements DataCreatorUI {
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(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 {
private ActionListener actionListener;
private Color color;
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.addMouseMotionListener(mouseInputAdapter);
}
@ -33,7 +38,7 @@ public class ActionLabel extends UILabel {
public void paintComponent(Graphics _gfx) {
super.paintComponent(_gfx);
_gfx.setColor(Color.blue);
_gfx.setColor(this.color);
_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.BoxLayout;
import javax.swing.JPanel;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class TreeRootPane extends BasicPane {
// 是否支持多选(checkBoxTree)
//private JCheckBox multipleSelection;
private UICheckBox checkTypeCheckBox;
// richer:加载的方式,支持异步加载和完全加载
private UICheckBox loadTypeCheckBox;
private UICheckBox layerTypeCheckBox;
private UICheckBox returnFullPathCheckBox ;
public TreeRootPane() {
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JPanel checkTypePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0();
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.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
checkTypePane.add(checkTypeCheckBox);
this.add(checkTypePane);
JPanel loadTypePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0();
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.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
loadTypePane.add(loadTypeCheckBox);
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);
// 是否支持多选(checkBoxTree)
//private JCheckBox multipleSelection;
private UICheckBox checkTypeCheckBox;
// richer:加载的方式,支持异步加载和完全加载
private UICheckBox loadTypeCheckBox;
private UICheckBox layerTypeCheckBox;
private UICheckBox returnFullPathCheckBox;
public TreeRootPane() {
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JPanel checkTypePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0();
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.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
checkTypePane.add(checkTypeCheckBox);
this.add(checkTypePane);
JPanel loadTypePane = FRGUIPaneFactory.createBoxFlowInnerContainer_S_Pane_First0();
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.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
loadTypeCheckBox.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
UICheckBox checkBox = (UICheckBox) e.getSource();
doLoadTypeChange(checkBox.isSelected());
}
});
loadTypePane.add(loadTypeCheckBox);
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();
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")));
returnFullPathCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
this.add(returnFullPathPane);
}
@Override
protected String title4PopupWindow() {
return "tree";
}
public void populate(TreeAttr treeAttr) {
checkTypeCheckBox.setSelected(treeAttr.isMultipleSelection());
loadTypeCheckBox.setSelected(treeAttr.isAjax());
layerTypeCheckBox.setSelected(treeAttr.isSelectLeafOnly());
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")));
returnFullPathCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
this.add(returnFullPathPane);
}
private void doLoadTypeChange(Boolean selected) {
//给埋点插件提供一个方法,埋埋点用
}
@Override
protected String title4PopupWindow() {
return "tree";
}
public void populate(TreeAttr treeAttr) {
checkTypeCheckBox.setSelected(treeAttr.isMultipleSelection());
loadTypeCheckBox.setSelected(treeAttr.isAjax());
layerTypeCheckBox.setSelected(treeAttr.isSelectLeafOnly());
returnFullPathCheckBox.setSelected(treeAttr.isReturnFullPath());
}
}
public TreeAttr update() {
TreeAttr treeAttr = new TreeAttr();
treeAttr.setMultipleSelection(checkTypeCheckBox.isSelected());
treeAttr.setAjax(loadTypeCheckBox.isSelected());
treeAttr.setSelectLeafOnly(layerTypeCheckBox.isSelected());
public TreeAttr update() {
TreeAttr treeAttr = new TreeAttr();
treeAttr.setMultipleSelection(checkTypeCheckBox.isSelected());
treeAttr.setAjax(loadTypeCheckBox.isSelected());
treeAttr.setSelectLeafOnly(layerTypeCheckBox.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 lastSelectedPane = null;
public BackgroundPane() {
this.initComponents();
@ -62,6 +67,9 @@ public class BackgroundPane extends AbstractBasicStylePane {
@Override
public void itemStateChanged(ItemEvent e) {
cardlayout.show(centerPane, (String) typeComboBox.getSelectedItem());
if (e.getStateChange() == ItemEvent.DESELECTED) {
lastSelectedPane = currentPane;
}
currentPane = paneList[typeComboBox.getSelectedIndex()];
fireStateChanged();
}
@ -144,6 +152,8 @@ public class BackgroundPane extends AbstractBasicStylePane {
pane.populateBean(background);
typeComboBox.setSelectedIndex(i);
currentPane = paneList[i];
// 填充 初始化
lastSelectedPane = currentPane;
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.layout.TableLayout;
import com.fr.design.layout.TableLayoutHelper;
import com.fr.design.mainframe.backgroundpane.NullBackgroundQuickPane;
import com.fr.design.style.color.NewColorSelectBox;
import com.fr.design.utils.gui.AdjustWorkBookDefaultStyleUtils;
import com.fr.general.IOUtils;
@ -246,7 +247,9 @@ public class BorderPane extends AbstractBasicStylePane implements GlobalNameObse
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());
}
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 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 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.TitledBorder;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.text.Format;
@ -54,6 +64,7 @@ public class FormatPane extends AbstractBasicStylePane implements GlobalNameObse
private static final Integer[] TYPES = new Integer[]{
FormatContents.NULL, FormatContents.NUMBER,
FormatContents.CURRENCY, FormatContents.PERCENT,
FormatContents.THOUSANDTHS,
FormatContents.SCIENTIFIC, FormatContents.DATE,
FormatContents.TIME, FormatContents.TEXT};
@ -244,6 +255,9 @@ public class FormatPane extends AbstractBasicStylePane implements GlobalNameObse
} else if (pattern.indexOf("%") > 0) {
setPatternComboBoxAndList(FormatContents.PERCENT, pattern);
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) {
setPatternComboBoxAndList(FormatContents.SCIENTIFIC, pattern);
} 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[]{
FormatContents.NULL, FormatContents.NUMBER,
FormatContents.CURRENCY, FormatContents.PERCENT,
FormatContents.SCIENTIFIC,
FormatContents.THOUSANDTHS, FormatContents.SCIENTIFIC,
FormatContents.DATE, FormatContents.TIME,
FormatContents.TEXT};
@ -228,6 +228,9 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName
this.roundingBox.setSelected(((CoreDecimalFormat) format).getRoundingMode().equals(RoundingMode.HALF_UP));
} else if (pattern.indexOf("E") > 0) {
setPatternComboBoxAndList(FormatContents.SCIENTIFIC, pattern);
} else if (pattern.indexOf("‰") > 0) {
setPatternComboBoxAndList(FormatContents.THOUSANDTHS, pattern);
this.roundingBox.setSelected(((CoreDecimalFormat) format).getRoundingMode().equals(RoundingMode.HALF_UP));
} else {
setPatternComboBoxAndList(FormatContents.NUMBER, pattern);
}
@ -345,7 +348,7 @@ public class TextFormatPane extends AbstractBasicStylePane implements GlobalName
}
setTextFieldVisible(!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;
}
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() {

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();
SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(true);
// 只有一个文件未保存时
if (HistoryTemplateListCache.getInstance().getHistoryCount() == 1) {
int choose = saveSomeTempaltePane.saveLastOneTemplate();
if (choose != JOptionPane.CANCEL_OPTION) {
DesignerFrame.this.exit();
}
} else {
if (saveSomeTempaltePane.showSavePane()) {
DesignerFrame.this.exit();
}
SaveSomeTemplatePane saveSomeTemplatePane = new SaveSomeTemplatePane(true);
// 全部保存成功才退出
if (saveSomeTemplatePane.showSavePane()) {
DesignerFrame.this.exit();
}
}
@ -1225,4 +1218,4 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
public void setServerConfig(boolean serverConfig) {
this.serverConfig = serverConfig;
}
}
}

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

@ -442,20 +442,40 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
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() {
FILE file = this.getEditingFILE();
return new StashedFILE(file, exportBaseBook2ByteArray(), template.suffix());
}
private byte[] exportBaseBook2ByteArray() {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
BaseBook target = this.getTarget();
if (target != null) {
target.export(outputStream);
return new StashedFILE(file, outputStream.toByteArray(), template.suffix());
return outputStream.toByteArray();
}
// 如果 target == null 那么这个模板是被模板内存优化功能处理过的,不用处理
} catch (Exception e) {
FineLoggerFactory.getLogger().error("Export BaseBook to Byte Array Failed");
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
return null;
return new byte[0];
}
@ -492,6 +512,17 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
}
/**
* 刷新 模板资源 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) {
T newTemplate = JTemplateFactory.asIOFile(file, this.suffix());
if (newTemplate != null) {
@ -1014,7 +1045,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
// 过滤掉本地文件
boolean localFile = getEditingFILE() instanceof FileFILE;
boolean inconsistent = !localFile && getEditingFILE().exists()
&& !WorkContext.getCurrent().get(LockInfoOperator.class).isConsistentLock(getEditingFILE().getPath());
&& !WorkContext.getCurrent().get(LockInfoOperator.class).isConsistentLock(getEditingFILE().getPath());
if (inconsistent) {
throw new InconsistentLockException();
}
@ -1112,6 +1143,20 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
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 +1667,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
}
private CallbackSaveWorker save(boolean showLoc) {
fireJTemplateSaveBefore();
FILE editingFILE = this.getEditingFILE();
// carl:editingFILE没有,当然不存了,虽然不会有这种情况
if (editingFILE == null) {
@ -1738,6 +1784,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
refreshToolArea();
}
DesignerFrameFileDealerPane.getInstance().refresh();
DesignerFrameFileDealerPane.getInstance().stateChange();
}
});
return worker;
@ -1917,8 +1964,8 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
}
public void setDesignerUIMode(){
public void setDesignerUIMode() {
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 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) {
}
}

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

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

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

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

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

@ -1,9 +1,12 @@
package com.fr.design.ui.util;
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 javax.swing.SwingUtilities;
import java.util.concurrent.TimeUnit;
/**
* 一些常用的 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.UpdateInfoTableModel;
import com.fr.design.update.ui.widget.UpdateInfoTextAreaCellRender;
import com.fr.design.utils.DesignUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.general.*;
import com.fr.general.http.HttpToolbox;
@ -56,6 +57,7 @@ import java.util.*;
import java.util.List;
import java.util.concurrent.ExecutionException;
import static com.fr.design.dialog.FineJOptionPane.OPTION_OK_CANCEL;
import static java.nio.charset.StandardCharsets.*;
import static javax.swing.JOptionPane.QUESTION_MESSAGE;
@ -350,7 +352,25 @@ public class UpdateMainDialog extends UIDialog {
new SwingWorker<JSONObject, Void>() {
@Override
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

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 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 oldPath = file.getPath();
int indexOfLastDot = fileName.lastIndexOf(CoreConstants.DOT);
@ -49,19 +58,18 @@ public class TemplateUtils {
if (isOk(result)) {
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>() {
@Override
protected Void doInBackground() throws Exception {
byte[] content = new byte[0];
if (!needOpen) {
if (createByEditingTemplate) {
// 从当前编辑模板中生成备份文件
JTemplate<?, ?> template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
content = template.exportData();
@ -95,7 +103,7 @@ public class TemplateUtils {
protected void done() {
try {
get();
if (needOpen) {
if (openNewTemplate) {
DesignerContext.getDesignerFrame().openTemplate(file);
}
// 备份成功刷新下目录树 展示出来备份的模板

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

@ -22,6 +22,7 @@ import javax.swing.JOptionPane;
* @version 11.0
* Created by hades on 2021/12/7
*/
@SuppressWarnings("all")
public class SaveFailureHandler implements ThrowableHandler {
private static final SaveFailureHandler INSTANCE = new SaveFailureHandler();
@ -70,7 +71,7 @@ public class SaveFailureHandler implements ThrowableHandler {
@Override
public boolean process(Throwable e) {
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 false;
@ -81,7 +82,7 @@ public class SaveFailureHandler implements ThrowableHandler {
@Override
public boolean process(Throwable e) {
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 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(),
tip,
Toolkit.i18nText("Fine-Design_Basic_Alert"),
@ -113,10 +114,36 @@ public class SaveFailureHandler implements ThrowableHandler {
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)), 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();
// 展示效果
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);
return resultStream
.filter((e) -> e.getStatus() == DetectorStatus.EXCEPTION)
.collect(Collectors.toList());
}
/**
* 预期外的终止
*
* @return 检测结果
*/
public List<DetectorResult> terminateUnexpectedly() {
Stream<DetectorResult> resultStream = DetectorBridge.getInstance().detect();
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());
}
}

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

@ -0,0 +1,146 @@
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.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.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;
/**
* 检测器桥接逻辑
* [detect-core] - bridge - ui
*
* created by Harrison on 2022/05/13
**/
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(new FineDbDirtyDetector());
manager.register(new FineDbPermissionDetector());
manager.register(new FineDbLockedDetector());
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 能够检测出的异常情况
*/
public Stream<DetectorResult> detect() {
return detectorManager.getValue().detect();
}
/**
* 异常检测
* 当遇到异常时且异常难以处理直接导致服务器启动失败时调用
* 将异常添加进来统一检测
*
* @param throwable 异常
* @return 检测结果
*/
public Stream<DetectorResult> detect(Throwable throwable) {
ThrowableStore.getInstance().add(throwable);
Stream<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:";
}

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

@ -0,0 +1,53 @@
package com.fr.env.detect.base;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.bean.DetectorType;
import java.util.ArrayList;
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<ExceptionDetector> detectors = new ArrayList<>();
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);
List<DetectorResult> resultList = results.collect(Collectors.toList());
resultList.forEach(DetectorResult::log);
return resultList.stream();
}
public DetectorResult detect(DetectorType type) {
Optional<DetectorResult> result = detectors.stream()
.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();
}

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;
}
}

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

@ -0,0 +1,159 @@
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();
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;
}
}
}
}

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

@ -0,0 +1,59 @@
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;
/**
* 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) {
Throwable sign = throwable;
while (sign.getClass() != HsqlException.class) {
sign = sign.getCause();
}
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;
}
}

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

@ -0,0 +1,55 @@
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;
/**
* HSQL 下的权限检测
*
* created by Harrison on 2022/05/24
**/
public class FineDbPermissionConverter implements ThrowableConverter {
public static final String PERMISSION = "permission";
@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) {
Throwable sign = throwable;
while (sign.getClass() != HsqlException.class) {
sign = sign.getCause();
}
DetectorType type = DetectorType.FINE_DB_PERMISSION;
String message = sign.getMessage();
if (StringUtils.containsIgnoreCase(message, 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.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;
@ -62,9 +64,9 @@ public class ConfigToPropMigrator {
initDirectory();
try (Connection c = DriverManager.getConnection(url);
FileOutputStream entityOut = new FileOutputStream(PropertiesConstants.ENTITY_PROP_PATH);
FileOutputStream classHelperOut = new FileOutputStream(PropertiesConstants.CLASS_NAME_PROP_PATH);
FileOutputStream xmlEntityOut = new FileOutputStream(PropertiesConstants.XML_ENTITY_PROP_PATH)) {
OutputStreamWriter xmlEntityOut = new OutputStreamWriter(new FileOutputStream(PropertiesConstants.XML_ENTITY_PROP_PATH), StandardCharsets.UTF_8);
OutputStreamWriter entityOut = new OutputStreamWriter(new FileOutputStream(PropertiesConstants.ENTITY_PROP_PATH), StandardCharsets.UTF_8);
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_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);
ResultSet resultSet = query.executeQuery();
while (resultSet.next()) {
@ -94,19 +96,19 @@ public class ConfigToPropMigrator {
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);
ResultSet resultSet = query.executeQuery();
while (resultSet.next()) {
String id = resultSet.getString(1);
Blob value = resultSet.getBlob(2);
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() {

117
designer-base/src/main/java/com/fr/exit/DesignerExiter.java

@ -1,10 +1,26 @@
package com.fr.exit;
import com.fr.common.util.Collections;
import com.fr.design.RestartHelper;
import com.fr.design.dialog.ErrorDialog;
import com.fr.design.env.DesignerWorkspaceGenerator;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrame;
import com.fr.design.mainframe.messagecollect.StartErrorMessageCollector;
import com.fr.design.mainframe.messagecollect.entity.DesignerErrorMessage;
import com.fr.design.monitor.DesignerLifecycleMonitorContext;
import com.fr.env.detect.EnvDetectorCenter;
import com.fr.env.detect.bean.DetectorResult;
import com.fr.env.detect.ui.DetectorErrorDialog;
import com.fr.log.FineLoggerFactory;
import com.fr.process.engine.core.FineProcessContext;
import com.fr.process.engine.core.FineProcessEngineEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
/**
* @author hades
* @version 10.0
@ -17,7 +33,79 @@ public class DesignerExiter {
public static DesignerExiter getInstance() {
return INSTANCE;
}
/**
* 预期外的退出
* 首先检测是否有检测到的异常如果没有则运行默认行为
*
* @param defaultAction 默认行为
*/
public void exitUnexpectedly(Runnable defaultAction) {
// 尝试进行检测
List<DetectorResult> results = runAndGet(() -> EnvDetectorCenter.getInstance().terminateUnexpectedly(), ArrayList::new);
try {
if (!Collections.isEmpty(results)) {
showNewExitDialog(results);
}
} finally {
// 正常的话上面会直接退出, system.exit(0)
// 只有异常,或者不命中,才会走到这里
defaultAction.run();
}
}
public void exit(Throwable throwable) {
doThrowableAction(() -> {
FineLoggerFactory.getLogger().error(throwable.getMessage(), throwable);
}, () -> {
throwable.printStackTrace(System.err);
});
doThrowableAction(() -> {
StartErrorMessageCollector.getInstance().record(DesignerErrorMessage.UNEXCEPTED_START_FAILED.getId(),
DesignerErrorMessage.UNEXCEPTED_START_FAILED.getMessage(),
throwable.getMessage());
});
// 尝试进行检测
List<DetectorResult> results = runAndGet(() -> EnvDetectorCenter.getInstance().terminate(throwable), ArrayList::new);
if (Collections.isEmpty(results)) {
// 为空,则
showOldExitDialog(throwable);
} else {
showNewExitDialog(results);
}
}
private void showNewExitDialog(List<DetectorResult> results) {
DesignerFrame designerFrame = DesignerContext.getDesignerFrame();
DetectorErrorDialog errorDialog = new DetectorErrorDialog(designerFrame, results);
errorDialog.setVisible(true);
}
private void showOldExitDialog(Throwable throwable) {
ErrorDialog dialog = new ErrorDialog(null, Toolkit.i18nText("Fine-Design_Error_Start_Apology_Message"),
Toolkit.i18nText("Fine-Design_Error_Start_Report"),
throwable.getMessage()) {
@Override
protected void okEvent() {
dispose();
DesignerExiter.getInstance().execute();
}
@Override
protected void restartEvent() {
dispose();
RestartHelper.restart();
}
};
dialog.setVisible(true);
}
public void execute() {
DesignerLifecycleMonitorContext.getMonitor().beforeStop();
beforeExit();
@ -30,4 +118,31 @@ public class DesignerExiter {
private void beforeExit() {
DesignerWorkspaceGenerator.stop();
}
/* 忽视异常的调用方法 */
private void doThrowableAction(Runnable runnable) {
doThrowableAction(runnable, null);
}
private void doThrowableAction(Runnable runnable, Runnable defaultRunnable) {
try {
runnable.run();
} catch (Throwable ignore) {
if (defaultRunnable != null) {
defaultRunnable.run();
}
}
}
private <T> T runAndGet(Supplier<T> supplier, Supplier<T> defaultCallable) {
try {
return supplier.get();
} catch (Exception ignore) {
return defaultCallable.get();
}
}
}

8
designer-base/src/main/java/com/fr/file/StashedFILE.java

@ -87,6 +87,14 @@ public class StashedFILE extends AbstractFILE {
return false;
}
/**
* 获取内部FILE对象
* @return
*/
public FILE getInsideFILE() {
return file;
}
@Override
public String toString() {
return FILEFactory.MEM_PREFIX + getName();

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

@ -32,7 +32,6 @@ import com.fr.process.ProcessEventPipe;
import com.fr.process.engine.core.CarryMessageEvent;
import com.fr.process.engine.core.FineProcessContext;
import com.fr.stable.OperatingSystem;
import com.fr.start.event.LazyStartupEvent;
import com.fr.workspace.base.WorkspaceStatus;
@ -138,7 +137,7 @@ public abstract class BaseDesigner extends ToolBarMenuDock {
if (!isException) {
showDesignerFrame(true);
} else {
DesignerExiter.getInstance().execute();
DesignerExiter.getInstance().exit(e);
}
}
}

3
designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_left.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.70711 8L10.3536 11.6464C10.5488 11.8417 10.5488 12.1583 10.3536 12.3536C10.1583 12.5488 9.84171 12.5488 9.64645 12.3536L5.64645 8.35355C5.45118 8.15829 5.45118 7.84171 5.64645 7.64645L9.64645 3.64645C9.84171 3.45118 10.1583 3.45118 10.3536 3.64645C10.5488 3.84171 10.5488 4.15829 10.3536 4.35355L6.70711 8Z" fill="#C2C2C2"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

3
designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_disable_right.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.29289 8L5.64645 11.6464C5.45118 11.8417 5.45118 12.1583 5.64645 12.3536C5.84171 12.5488 6.15829 12.5488 6.35355 12.3536L10.3536 8.35355C10.5488 8.15829 10.5488 7.84171 10.3536 7.64645L6.35355 3.64645C6.15829 3.45118 5.84171 3.45118 5.64645 3.64645C5.45118 3.84171 5.45118 4.15829 5.64645 4.35355L9.29289 8Z" fill="#C2C2C2"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

3
designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_left.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.70711 8L10.3536 11.6464C10.5488 11.8417 10.5488 12.1583 10.3536 12.3536C10.1583 12.5488 9.84171 12.5488 9.64645 12.3536L5.64645 8.35355C5.45118 8.15829 5.45118 7.84171 5.64645 7.64645L9.64645 3.64645C9.84171 3.45118 10.1583 3.45118 10.3536 3.64645C10.5488 3.84171 10.5488 4.15829 10.3536 4.35355L6.70711 8Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

3
designer-base/src/main/resources/com/fr/design/standard/arrow/arrow_enable_right.svg

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.29289 8L5.64645 11.6464C5.45118 11.8417 5.45118 12.1583 5.64645 12.3536C5.84171 12.5488 6.15829 12.5488 6.35355 12.3536L10.3536 8.35355C10.5488 8.15829 10.5488 7.84171 10.3536 7.64645L6.35355 3.64645C6.15829 3.45118 5.84171 3.45118 5.64645 3.64645C5.45118 3.84171 5.45118 4.15829 5.64645 4.35355L9.29289 8Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

BIN
designer-base/src/main/resources/com/fr/design/standard/loading/loading-120.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

BIN
designer-base/src/main/resources/com/fr/design/standard/loading/loading-64.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

4
designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_error.svg

@ -0,0 +1,4 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.6886 8.16379C15.6886 12.0057 12.5493 15.1208 8.67764 15.1208C4.80595 15.1208 1.66669 12.0057 1.66669 8.16379C1.66669 4.32189 4.80595 1.20679 8.67764 1.20679C12.5493 1.20679 15.6886 4.32189 15.6886 8.16379Z" fill="#EB1D1F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.5105 6.19599C11.7451 5.96312 11.7451 5.58555 11.5105 5.35268C11.2758 5.1198 10.8953 5.1198 10.6606 5.35268L8.67761 7.32041L6.69461 5.35268C6.45993 5.1198 6.07944 5.1198 5.84476 5.35268C5.61008 5.58555 5.61008 5.96312 5.84476 6.19599L7.82776 8.16373L5.84476 10.1315C5.61008 10.3643 5.61008 10.7419 5.84476 10.9748C6.07944 11.2077 6.45993 11.2077 6.69461 10.9748L8.67761 9.00705L10.6606 10.9748C10.8953 11.2077 11.2758 11.2077 11.5105 10.9748C11.7451 10.7419 11.7451 10.3643 11.5105 10.1315L9.52747 8.16373L11.5105 6.19599Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 971 B

3
designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_success.svg

@ -0,0 +1,3 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.67764 15.4156C12.5493 15.4156 15.6886 12.3005 15.6886 8.45859C15.6886 4.61669 12.5493 1.50159 8.67764 1.50159C4.80595 1.50159 1.66669 4.61669 1.66669 8.45859C1.66669 12.3005 4.80595 15.4156 8.67764 15.4156ZM4.86229 8.12204C5.10492 7.89732 5.48519 7.91034 5.71164 8.1511L7.60931 10.1687L11.844 5.66646C12.0704 5.42569 12.4507 5.41268 12.6933 5.63739C12.9359 5.8621 12.9491 6.23945 12.7226 6.48021L8.04863 11.4495C7.81105 11.7021 7.40756 11.7021 7.16999 11.4495L4.833 8.96485C4.60655 8.72409 4.61966 8.34675 4.86229 8.12204Z" fill="#16C153"/>
</svg>

After

Width:  |  Height:  |  Size: 696 B

5
designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning.svg

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 8C15 11.8656 11.8656 15 8 15C4.13435 15 1 11.8656 1 8C1 4.13435 4.13435 1 8 1C11.8656 1 15 4.13435 15 8Z" fill="#FAAA39"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.43333 10.292C7.27777 10.4476 7.2 10.6365 7.2 10.8587C7.2 11.0809 7.27777 11.2698 7.43333 11.4254C7.58889 11.5809 7.77777 11.6587 8 11.6587C8.22222 11.6587 8.41111 11.5809 8.56666 11.4254C8.72222 11.2698 8.8 11.0809 8.8 10.8587C8.8 10.6365 8.72222 10.4476 8.56666 10.292C8.41111 10.1365 8.22222 10.0587 8 10.0587C7.77777 10.0587 7.58889 10.1365 7.43333 10.292Z" fill="white"/>
<rect x="7.3" y="4.22132" width="1.4" height="5" rx="0.7" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 780 B

9
designer-base/src/main/resources/com/fr/design/standard/reminder/reminder_warning_window.svg

@ -0,0 +1,9 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.70605 45C1.40405 45 0.0540464 42.646 1.70505 39.771L20.998 6.157C22.649 3.281 25.351 3.281 27.001 6.157L46.295 39.771C47.946 42.646 46.596 45 43.294 45H4.70605Z" fill="#FBB03B"/>
<mask id="mask0_1308_50594" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="1" y="4" width="46" height="41">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 45H47V4H1V45Z" fill="white"/>
</mask>
<g mask="url(#mask0_1308_50594)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M22 39H26V35H22V39ZM27 17L26 33H22L21 17H27Z" fill="white"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 688 B

3
designer-base/src/main/resources/com/fr/env/detect/detect.svg vendored

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2H14.5V5H1.5V2ZM1.5 6L1.5 14H14.5V6H1.5ZM15.5 6V14C15.5 14.5523 15.0523 15 14.5 15H1.5C0.947715 15 0.5 14.5523 0.5 14V2C0.5 1.44772 0.947715 1 1.5 1H14.5C15.0523 1 15.5 1.44772 15.5 2V5V6ZM6.67926 6.87216L7.10381 7.79011L8.53859 10.8923L9.06189 9.94086L9.20436 9.68182H9.5H12.5H13V10.6818H12.5H9.79564L8.93811 12.241L8.46141 13.1077L8.04619 12.2099L6.62074 9.12784L5.94232 10.415L5.80166 10.6818H5.5H3.5H3V9.68182H3.5H5.19834L6.20768 7.76686L6.67926 6.87216ZM3.5 3H2.5V4H3.5V3ZM4 3H5V4H4V3ZM6.5 3H5.5V4H6.5V3Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 685 B

3
designer-base/src/main/resources/com/fr/env/detect/detect_normal.svg vendored

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2H14.5V5H1.5V2ZM1.5 6L1.5 14H14.5V6H1.5ZM15.5 6V14C15.5 14.5523 15.0523 15 14.5 15H1.5C0.947715 15 0.5 14.5523 0.5 14V2C0.5 1.44772 0.947715 1 1.5 1H14.5C15.0523 1 15.5 1.44772 15.5 2V5V6ZM6.67926 6.87216L7.10381 7.79011L8.53859 10.8923L9.06189 9.94086L9.20436 9.68182H9.5H12.5H13V10.6818H12.5H9.79564L8.93811 12.241L8.46141 13.1077L8.04619 12.2099L6.62074 9.12784L5.94232 10.415L5.80166 10.6818H5.5H3.5H3V9.68182H3.5H5.19834L6.20768 7.76686L6.67926 6.87216ZM3.5 3H2.5V4H3.5V3ZM4 3H5V4H4V3ZM6.5 3H5.5V4H6.5V3Z" fill="#333334"/>
</svg>

After

Width:  |  Height:  |  Size: 685 B

43
designer-base/src/test/java/com/fr/design/components/notification/NotificationDialogTest.java

@ -0,0 +1,43 @@
package com.fr.design.components.notification;
import com.fr.design.utils.DevUtils;
import com.fr.third.guava.collect.Lists;
import java.awt.Frame;
import java.util.function.Consumer;
public class NotificationDialogTest {
public static void main(String[] args) {
testShow();
}
public static void testShow() {
DevUtils.show(new Consumer<Frame>() {
@Override
public void accept(Frame frame) {
NotificationModel model1 = new NotificationModel(NotificationType.WARNING, null, new NotificationMessage.LinkMessage("test", "abc"), new NotificationMessage.LinkMessage("abc", "aaa"));
NotificationModel model2 = new NotificationModel(NotificationType.INFO, new NotificationAction() {
@Override
public String name() {
return "action";
}
@Override
public void run(Object... args) {
System.out.println("1111");
}
}, new NotificationMessage.LinkMessage("1111 2222 33333333 4444 555 6666 66555 888 999 333 <br/> 3333 <br /> 444 <br/> 555 <br/>", ""),new NotificationMessage.LinkMessage("display <a href='#'>model2</a> test", "abc"));
NotificationDialogProperties properties = new NotificationDialogProperties(frame, "test");
NotificationDialog dialog = new NotificationDialog(properties, Lists.newArrayList(model1, model2));
dialog.setVisible(true);
}
});
}
}

12
designer-base/src/test/java/com/fr/design/utils/DevDebugUtils.java

@ -0,0 +1,12 @@
package com.fr.design.utils;
/**
* created by Harrison on 2022/05/26
**/
public class DevDebugUtils {
public static void main(String[] args) {
org.swingexplorer.Launcher.main(new String[]{"com.fr.design.utils.DevUtils"});
}
}

60
designer-base/src/test/java/com/fr/design/utils/DevUtils.java

@ -0,0 +1,60 @@
package com.fr.design.utils;
import com.fr.config.dao.DaoContext;
import com.fr.config.dao.impl.LocalClassHelperDao;
import com.fr.config.dao.impl.LocalEntityDao;
import com.fr.config.dao.impl.LocalXmlEntityDao;
import com.fr.design.ui.util.UIUtil;
import com.fr.transaction.Configurations;
import com.fr.transaction.LocalConfigurationHelper;
import javax.swing.JFrame;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Toolkit;
import java.util.function.Consumer;
/**
* 设计器的开发时工具
* 帮助进行 UI 页面的调试
* <p>
* created by Harrison on 2022/05/23
**/
public class DevUtils {
private static void prepare() {
DaoContext.setEntityDao(new LocalEntityDao());
DaoContext.setClassHelperDao(new LocalClassHelperDao());
DaoContext.setXmlEntityDao(new LocalXmlEntityDao());
Configurations.setHelper(new LocalConfigurationHelper());
}
public static void show(Consumer<Frame> consumer) {
DesignUtils.initLookAndFeel();
UIUtil.invokeLaterIfNeeded(() -> {
JFrame frame = new JFrame("dev-util");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
frame.setSize(dimension);
consumer.accept(frame);
frame.setVisible(true);
});
}
public static void main(String[] args) {
DevUtils.prepare();
DevUtils.show(new Consumer<Frame>() {
@Override
public void accept(Frame frame) {
}
});
}
}

23
designer-base/src/test/java/com/fr/env/detect/impl/converter/ClassConflictConvertorTest.java vendored

@ -0,0 +1,23 @@
package com.fr.env.detect.impl.converter;
import org.junit.Test;
public class ClassConflictConvertorTest {
@Test
public void testInnerFinder() {
ClassNotFoundException ex1 = new ClassNotFoundException("Class 111.222.333 not found");
Iterable<String> names = ClassConflictConvertor.Converter.CLASS.converter(ex1);
System.out.println();
}
@Test
public void testConverter() {
ClassNotFoundException ex1 = new ClassNotFoundException("com.zaxxer.hikari.HikariConfig");
ClassConflictConvertor convertor = new ClassConflictConvertor();
convertor.convert(ex1);
}
}

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

Loading…
Cancel
Save