Browse Source

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

* commit 'e19fa1e976f5726f44de6d35c2171583152c7af1': (124 commits)
  REPORT-79889 远程设计下存储过程结果列表缓存刷新的问题
  import
  REPORT-79881 多结果数据集树节点图标查找性能问题
  REPORT-79845 同一个多结果数据集equals为false的问题
  REPORT-79344【运营产品化二期】埋点暂不生效 修改pr
  REPORT-79344【运营产品化二期】埋点暂不生效 修改部分埋点
  REPORT-79345 【冒烟】切换远程,日志刷报错write failed
  KERNEL-12469 js引擎j2v8剥离成独立插件
  KERNEL-12469 js引擎j2v8剥离成独立插件
  REPORT-79096【运营产品化二期】交互问题集合二 REPORT-79341【运营产品化二期】立即使用下载的模板名称目前是开头加了(1),是否可按浏览器规则
  REPORT-79096【运营产品化二期】交互问题集合二 REPORT-79341【运营产品化二期】立即使用下载的模板名称目前是开头加了(1),是否可按浏览器规则 1、改ui 2、改文件重名规则
  REPORT-79440 找不到驱动的话可以保存数据连接
  改一下写法
  REPORT-79492 复制多张模板,删除一部分,触发粘贴后没有定位到粘贴的位置
  REPORT-79456 【运营产品化二期】远程设计下 立即使用下载不成功 远程设计获取的下载路径是个url,不可用 改为下载到桌面
  REPORT-79341 【运营产品化二期】立即使用下载的模板名称目前是开头加了(1),是否可按浏览器规则 修改了重名规则 添加了异常处理
  REPORT-79182 选中的文件下有锁定的模板,异常提示
  REPORT-79343 【运营产品化二期】立即使用后打开的模板仍提示报存 1、打开前刷新目录
  代码质量问题
  REPORT-78748 搜索结果很多时,设计器界面处于卡死的状态
  ...
fix-lag
superman 2 years ago
parent
commit
ef8479421d
  1. 14
      designer-base/src/main/java/com/fr/design/DesignerEnvManager.java
  2. 3
      designer-base/src/main/java/com/fr/design/EnvChangeEntrance.java
  3. 50
      designer-base/src/main/java/com/fr/design/actions/file/DelFileAction.java
  4. 163
      designer-base/src/main/java/com/fr/design/actions/file/LocateAction.java
  5. 14
      designer-base/src/main/java/com/fr/design/actions/file/PreferencePane.java
  6. 347
      designer-base/src/main/java/com/fr/design/actions/file/RenameAction.java
  7. 41
      designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigManager.java
  8. 166
      designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigPane.java
  9. 28
      designer-base/src/main/java/com/fr/design/carton/CartonFiles.java
  10. 161
      designer-base/src/main/java/com/fr/design/carton/CartonThreadExecutorPool.java
  11. 45
      designer-base/src/main/java/com/fr/design/carton/CartonUploadMessage.java
  12. 407
      designer-base/src/main/java/com/fr/design/carton/EventDispatchThreadHangMonitor.java
  13. 407
      designer-base/src/main/java/com/fr/design/carton/FeedbackToolboxDialog.java
  14. 36
      designer-base/src/main/java/com/fr/design/carton/MonthlyCartonFile.java
  15. 312
      designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java
  16. 4
      designer-base/src/main/java/com/fr/design/components/tooltip/ModernToolTip.java
  17. 25
      designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java
  18. 102
      designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java
  19. 9
      designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java
  20. 75
      designer-base/src/main/java/com/fr/design/data/datapane/TableDataSourceOP.java
  21. 6
      designer-base/src/main/java/com/fr/design/data/datapane/TableDataTree.java
  22. 34
      designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java
  23. 3
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java
  24. 1
      designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionManagerPane.java
  25. 10
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/TableDataTreeSearchManager.java
  26. 6
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchCallBack.java
  27. 2
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchResult.java
  28. 15
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchTask.java
  29. 2
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchCallBack.java
  30. 2
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchResult.java
  31. 8
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchTask.java
  32. 6
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TableDataSearchRemindPane.java
  33. 7
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TreeSearchToolbarPane.java
  34. 2
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataTreeSearcher.java
  35. 9
      designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTableModel.java
  36. 87
      designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java
  37. 10
      designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/ProcedureDataPane.java
  38. 143
      designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataNameWrapper.java
  39. 325
      designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataWrapper.java
  40. 54
      designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataWrapperHelper.java
  41. 6
      designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java
  42. 4
      designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureNameWrapper.java
  43. 117
      designer-base/src/main/java/com/fr/design/deeplink/DeepLinkCore.java
  44. 17
      designer-base/src/main/java/com/fr/design/deeplink/DeepLinkPrepare.java
  45. 5
      designer-base/src/main/java/com/fr/design/dialog/UIDialog.java
  46. 35
      designer-base/src/main/java/com/fr/design/dialog/link/MessageWithLink.java
  47. 487
      designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java
  48. 208
      designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java
  49. 8
      designer-base/src/main/java/com/fr/design/file/FileOperations.java
  50. 20
      designer-base/src/main/java/com/fr/design/file/HistoryTemplateListCache.java
  51. 200
      designer-base/src/main/java/com/fr/design/file/MutilTempalteTabPane.java
  52. 82
      designer-base/src/main/java/com/fr/design/file/TemplateDirTreePane.java
  53. 8
      designer-base/src/main/java/com/fr/design/file/TemplateResource.java
  54. 125
      designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java
  55. 11
      designer-base/src/main/java/com/fr/design/file/impl/AbstractTemplateResource.java
  56. 135
      designer-base/src/main/java/com/fr/design/gui/date/UICalendarPanel.java
  57. 201
      designer-base/src/main/java/com/fr/design/gui/date/UIDatePicker.java
  58. 73
      designer-base/src/main/java/com/fr/design/gui/itree/filetree/EnvFileTree.java
  59. 53
      designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateDirTree.java
  60. 134
      designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateFileTree.java
  61. 8
      designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/ExpandMutableTreeNode.java
  62. 5
      designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java
  63. 29
      designer-base/src/main/java/com/fr/design/javascript/beautify/JavaScriptFormatHelper.java
  64. 11
      designer-base/src/main/java/com/fr/design/layout/FRGUIPaneFactory.java
  65. 8
      designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java
  66. 11
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrame.java
  67. 386
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java
  68. 207
      designer-base/src/main/java/com/fr/design/mainframe/JNullTemplate.java
  69. 13
      designer-base/src/main/java/com/fr/design/mainframe/JTemplate.java
  70. 66
      designer-base/src/main/java/com/fr/design/mainframe/manager/clip/TemplateTreeClipboard.java
  71. 205
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateDirTreeSearchManager.java
  72. 258
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateTreeSearchManager.java
  73. 195
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/TemplateDirTreeSearcher.java
  74. 193
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/TemplateTreeSearcher.java
  75. 53
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateDirSearchCallBack.java
  76. 63
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchCallBack.java
  77. 130
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchResult.java
  78. 79
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchTask.java
  79. 213
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateDirSearchRemindPane.java
  80. 152
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateDirTreeSearchPane.java
  81. 228
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateSearchRemindPane.java
  82. 212
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateTreeSearchToolbarPane.java
  83. 35
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplateDirPreSearchTask.java
  84. 33
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplatePreSearchCallBack.java
  85. 62
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplatePreSearchTask.java
  86. 6
      designer-base/src/main/java/com/fr/design/mainframe/share/collect/ComponentSender.java
  87. 2
      designer-base/src/main/java/com/fr/design/mainframe/theme/utils/DefaultThemedTemplateCellElementCase.java
  88. 194
      designer-base/src/main/java/com/fr/design/mainframe/toast/SimpleToast.java
  89. 35
      designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java
  90. 2
      designer-base/src/main/java/com/fr/design/report/WatermarkPane.java
  91. 2
      designer-base/src/main/java/com/fr/design/search/TreeSearchStatus.java
  92. 2
      designer-base/src/main/java/com/fr/design/search/TreeSearcher.java
  93. 2
      designer-base/src/main/java/com/fr/design/search/control/TreeSearchCallback.java
  94. 9
      designer-base/src/main/java/com/fr/design/search/control/TreeSearchResult.java
  95. 2
      designer-base/src/main/java/com/fr/design/search/control/TreeSearchTask.java
  96. 4
      designer-base/src/main/java/com/fr/design/search/event/TreeSearchStatusChangeEvent.java
  97. 2
      designer-base/src/main/java/com/fr/design/search/event/TreeSearchStatusChangeListener.java
  98. 16
      designer-base/src/main/java/com/fr/design/search/view/TreeSearchRendererHelper.java
  99. 2
      designer-base/src/main/java/com/fr/design/style/color/NewColorSelectPane.java
  100. 32
      designer-base/src/main/java/com/fr/design/utils/ColorUtils.java
  101. Some files were not shown because too many files have changed in this diff Show More

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

@ -6,6 +6,7 @@ package com.fr.design;
import com.fr.base.BaseXMLUtils;
import com.fr.base.Utils;
import com.fr.design.actions.help.alphafine.AlphaFineConfigManager;
import com.fr.design.carton.SwitchForSwingChecker;
import com.fr.design.constants.UIConstants;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.dialog.ErrorDialog;
@ -192,6 +193,8 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
private VcsConfigManager vcsConfigManager = VcsConfigManager.getInstance();
private DesignerStartupConfig designerStartupConfig = DesignerStartupConfig.getInstance();
private SwitchForSwingChecker switchForSwingChecker = SwitchForSwingChecker.getInstance();
public static final String CAS_CERTIFICATE_PATH = "certificatePath";
@ -1872,6 +1875,8 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
readDesignerLoginAttr(reader);
} else if (name.equals(fvsDesignerConfig.getName())) {
readFvsDesignerConfig(reader);
} else if (name.equals(SwitchForSwingChecker.XML_TAG)) {
readSwitchForSwingCheckerAttr(reader);
} else {
readLayout(reader, name);
}
@ -2091,6 +2096,10 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
reader.readXMLObject(DesignerPort.getInstance());
}
private void readSwitchForSwingCheckerAttr(XMLableReader reader) {
reader.readXMLObject(switchForSwingChecker);
}
/**
* Write XML.<br>
* The method will be invoked when save data to XML file.<br>
@ -2123,6 +2132,7 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
writeComponentReuseNotificationInfo(writer);
writeDesignerLoginAttr(writer);
writeFvsDesignerConfig(writer);
writeSwitchForSwingChecker(writer);
writer.end();
}
@ -2437,6 +2447,10 @@ public class DesignerEnvManager implements XMLReadable, XMLWriter {
this.fvsDesignerConfig.writeXML(writer);
}
private void writeSwitchForSwingChecker(XMLPrintWriter writer) {
this.switchForSwingChecker.writeXML(writer);
}
enum XmlHandler {
Self;

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

@ -1,6 +1,7 @@
package com.fr.design;
import com.fr.common.report.ReportState;
import com.fr.design.mainframe.manager.clip.TemplateTreeClipboard;
import com.fr.design.plugin.remind.PluginErrorDesignReminder;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.dialog.BasicDialog;
@ -150,6 +151,8 @@ public class EnvChangeEntrance {
model.envChanged();
}
NotificationCenter.getInstance().clearAllNotifications();
//切换环境后,清空粘贴板里面的内容
TemplateTreeClipboard.getInstance().reset();
return true;
}

50
designer-base/src/main/java/com/fr/design/actions/file/DelFileAction.java

@ -0,0 +1,50 @@
package com.fr.design.actions.file;
import com.fr.design.actions.UpdateAction;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.file.FileOperations;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrameFileDealerPane;
import com.fr.design.utils.TemplateUtils;
import javax.swing.JOptionPane;
import java.awt.event.ActionEvent;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
import static javax.swing.JOptionPane.YES_NO_OPTION;
/*
* 删除指定文件
*/
public class DelFileAction extends UpdateAction {
public DelFileAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Remove"));
this.setSmallIcon("/com/fr/design/images/FileDealerPaneIcon/remove");
}
@Override
public void actionPerformed(ActionEvent evt) {
FileOperations selectedOperation = DesignerFrameFileDealerPane.getInstance().getSelectedOperation();
if (!selectedOperation.access()) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return;
}
if (TemplateUtils.checkSelectedTemplateIsEditing()) {
if (FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Template_Is_Editing"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
YES_NO_OPTION) != JOptionPane.YES_OPTION) {
return;
}
}
selectedOperation.deleteFile();
DesignerFrameFileDealerPane.getInstance().stateChange();
DesignerContext.getDesignerFrame().setTitle();
}
}

163
designer-base/src/main/java/com/fr/design/actions/file/LocateAction.java

@ -0,0 +1,163 @@
package com.fr.design.actions.file;
import com.fr.design.actions.UpdateAction;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.file.TemplateTreePane;
import com.fr.design.gui.itree.filetree.TemplateFileTree;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.gui.itree.refreshabletree.RefreshableJTree;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.file.filetree.FileNode;
import com.fr.general.ComparatorUtils;
import com.fr.stable.CoreConstants;
import com.fr.stable.StableUtils;
import com.fr.stable.project.ProjectConstants;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.awt.event.ActionEvent;
import java.io.File;
/**
* 模板定位功能
*/
public class LocateAction extends UpdateAction {
public LocateAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Locate"));
this.setSmallIcon("/com/fr/design/images/FileDealerPaneIcon/locate.png");
}
@Override
public void actionPerformed(ActionEvent e) {
JTemplate<?, ?> current = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
gotoEditingTemplateLeaf(current.getEditingFILE().getPath(), false);
}
/**
* 在左侧模板树定位到指定模板
*
* @param locatedPath
*/
public static void gotoEditingTemplateLeaf(String locatedPath) {
gotoEditingTemplateLeaf(locatedPath, true);
}
private static void gotoEditingTemplateLeaf(String locatedPath, boolean needRefreshMode) {
if (locatedPath == null) {
return;
}
if (TemplateTreeSearchManager.getInstance().isInSearchMode()) {
TemplateTreeSearchManager.getInstance().outOfSearchMode();
}
DefaultTreeModel model = (DefaultTreeModel) getTemplateFileTree().getModel();
ExpandMutableTreeNode treeNode = (ExpandMutableTreeNode) model.getRoot();
if (needRefreshMode) {
treeNode.removeAllChildren();
ExpandMutableTreeNode[] childTreeNodes = getTemplateFileTree().loadChildTreeNodes(treeNode);
treeNode.addChildTreeNodes(childTreeNodes);
model.reload(treeNode);
}
recursiveSelectPath(treeNode, locatedPath, model);
TreePath selectedTreePath = getTemplateFileTree().getSelectionPath();
if (selectedTreePath != null) {
getTemplateFileTree().scrollPathToVisible(selectedTreePath);
}
}
private static TemplateFileTree getTemplateFileTree() {
return TemplateTreePane.getInstance().getTemplateFileTree();
}
private static void recursiveSelectPath(TreeNode treeNode, String currentPath, DefaultTreeModel m_model) {
for (int i = 0, len = treeNode.getChildCount(); i < len; i++) {
TreeNode node = treeNode.getChildAt(i);
// 取出当前的childTreeNode,并append到searchingPath后面
ExpandMutableTreeNode childTreeNode = (ExpandMutableTreeNode) node;
if (selectFilePath(childTreeNode, ProjectConstants.REPORTLETS_NAME, currentPath, m_model)) {
break;
}
if (!node.isLeaf()) {
for (int j = 0; j < node.getChildCount(); j++) {
recursiveSelectPath(node.getChildAt(j), currentPath, m_model);
}
}
}
}
/*
* 在currentTreeNode下找寻filePath
*
* prefix + currentTreeNode.getName() = currentTreeNode所对应的Path
*
* 返回currentTreeNode下是否找到了filePath
*/
private static boolean selectFilePath(ExpandMutableTreeNode currentTreeNode, String prefix, String filePath, DefaultTreeModel model) {
Object userObj = currentTreeNode.getUserObject();
if (!(userObj instanceof FileNode)) {
return false;
}
FileNode fileNode = (FileNode) userObj;
String nodePath = fileNode.getName();
String currentTreePath = StableUtils.pathJoin(prefix, nodePath);
boolean result = false;
// 如果equals,说明找到了,不必再找下去了
if (ComparatorUtils.equals(new File(currentTreePath), new File(filePath))) {
getTemplateFileTree().setSelectionPath(new TreePath(model.getPathToRoot(currentTreeNode)));
result = true;
}
// 如果当前路径是currentFilePath的ParentFile,则expandTreeNode,并继续往下找
else if (isParentFile(currentTreePath, filePath)) {
loadPendingChildTreeNode(currentTreeNode);
prefix = currentTreePath + CoreConstants.SEPARATOR;
for (int i = 0, len = currentTreeNode.getChildCount(); i < len; i++) {
ExpandMutableTreeNode childTreeNode = (ExpandMutableTreeNode) currentTreeNode.getChildAt(i);
if (selectFilePath(childTreeNode, prefix, filePath, model)) {
result = true;
}
}
}
return result;
}
protected static void loadPendingChildTreeNode(ExpandMutableTreeNode currentTreeNode) {
if (currentTreeNode.isLeaf()) {
return;
}
// 判断第一个孩子节点.UserObject是不是PENDING,如果是PENDING的话,需要重新加载这个TreeNode
ExpandMutableTreeNode flag = (ExpandMutableTreeNode) currentTreeNode.getFirstChild();
if (flag == null || !flag.getUserObject().toString().equals(RefreshableJTree.PENDING.toString())) {
return;
}
// 删除所有的节点.
currentTreeNode.removeAllChildren();
ExpandMutableTreeNode[] children = getTemplateFileTree().loadChildTreeNodes(currentTreeNode);
for (ExpandMutableTreeNode c : children) {
currentTreeNode.add(c);
}
}
private static boolean isParentFile(String var0, String var1) {
File var2 = new File(var0);
File var3 = new File(var1);
while (!ComparatorUtils.equals(var2, var3)) {
var3 = var3.getParentFile();
if (var3 == null) {
return false;
}
}
return true;
}
}

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

@ -241,9 +241,9 @@ public class PreferencePane extends BasicPane {
createLogPane(advancePane);
createLanPane(generalPane);
createStartupPagePane(generalPane);
// 先屏蔽下
// createStartupPagePane(generalPane);
createLengthPane(advancePane);
createServerPane(advancePane);
@ -655,13 +655,13 @@ public class PreferencePane extends BasicPane {
// ben:选择版本语言;
JPanel startupPagePaneWrapper = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane();
JPanel startupPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane("启动页配置");
JPanel startupPane = FRGUIPaneFactory.createTopVerticalTitledBorderPane(Toolkit.i18nText("Fine-Design_Startup_Page_Config"));
generalPane.add(startupPagePaneWrapper);
startupPagePaneWrapper.add(startupPane);
startupPageEnabledCheckBox = new UICheckBox("启动设计器时,自动打开启动页");
startupPageEnabledCheckBox = new UICheckBox(Toolkit.i18nText("Fine-Design_Startup_Page_Config_Check_Text"));
startupPane.add(startupPageEnabledCheckBox);
UILabel descLabel = new UILabel("注意:若在远程环境下直接关闭,再次启动时,启动速度会变慢");
UILabel descLabel = new UILabel(Toolkit.i18nText("Fine-Design_Startup_Page_Config_Desc"));
descLabel.setForeground(new Color(51, 51, 52, (int)Math.round(0.5 * 255)));
startupPane.add(descLabel);
}
@ -854,7 +854,7 @@ public class PreferencePane extends BasicPane {
previewResolutionBtnM.setEnabled(enabled);
this.cloudAnalyticsDelayCheckBox.setSelected(designerEnvManager.isCloudAnalyticsDelay());
// this.startupPageEnabledCheckBox.setSelected(designerEnvManager.isStartupPageEnabled());
this.startupPageEnabledCheckBox.setSelected(designerEnvManager.isStartupPageEnabled());
}
private int chooseCase(int sign) {
@ -921,7 +921,7 @@ public class PreferencePane extends BasicPane {
vcsConfigManager.setVcsEnable(this.vcsEnableCheckBox.isSelected());
vcsConfigManager.setSaveCommit(this.saveCommitCheckBox.isSelected());
vcsConfigManager.setUseInterval(this.useIntervalCheckBox.isSelected());
// designerEnvManager.setStartupPageEnabled(this.startupPageEnabledCheckBox.isSelected());
designerEnvManager.setStartupPageEnabled(this.startupPageEnabledCheckBox.isSelected());
Configurations.update(new Worker() {
@Override
public void run() {

347
designer-base/src/main/java/com/fr/design/actions/file/RenameAction.java

@ -0,0 +1,347 @@
package com.fr.design.actions.file;
import com.fr.base.BaseUtils;
import com.fr.chartx.TwoTuple;
import com.fr.design.DesignerEnvManager;
import com.fr.design.actions.UpdateAction;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.file.FileOperations;
import com.fr.design.file.HistoryTemplateListCache;
import com.fr.design.file.MutilTempalteTabPane;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.TableLayout;
import com.fr.design.layout.TableLayoutHelper;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrameFileDealerPane;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.design.mainframe.vcs.common.VcsHelper;
import com.fr.design.utils.TemplateUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.event.EventDispatcher;
import com.fr.file.FileNodeFILE;
import com.fr.file.filetree.FileNode;
import com.fr.general.ComparatorUtils;
import com.fr.stable.CoreConstants;
import com.fr.stable.StringUtils;
import com.fr.stable.project.ProjectConstants;
import com.fr.third.org.apache.commons.io.FilenameUtils;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.regex.Pattern;
import static javax.swing.JOptionPane.DEFAULT_OPTION;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
import static javax.swing.JOptionPane.YES_NO_OPTION;
/**
* 模板/目录重命名操作
*/
public class RenameAction extends UpdateAction {
private FileOperations selectedOperation;
public RenameAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Rename"));
this.setSmallIcon("/com/fr/design/images/FileDealerPaneIcon/rename");
}
@Override
public void actionPerformed(ActionEvent evt) {
selectedOperation = DesignerFrameFileDealerPane.getInstance().getSelectedOperation();
if (!selectedOperation.access()) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return;
}
FileNode node = selectedOperation.getFileNode();
String lock = node.getLock();
if (lock != null && !lock.equals(node.getUserID())) {
// 提醒被锁定模板无法重命名
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Unable_Rename_Locked_File"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return;
}
new FileRenameDialog(node);
MutilTempalteTabPane.getInstance().repaint();
DesignerFrameFileDealerPane.getInstance().stateChange();
}
/**
* 重命名对话框
* 支持快捷键EnterESC
*/
private class FileRenameDialog extends JDialog {
private UITextField nameField;
private UILabel warnLabel;
private UIButton confirmButton;
/**
* 操作的节点
*/
private FileNodeFILE fnf;
private KeyListener keyListener = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
dispose();
} else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (confirmButton.isEnabled()) {
confirmClose();
}
}
}
};
private FileRenameDialog(FileNode node) {
super(DesignerContext.getDesignerFrame(), true);
if (node == null) {
return;
}
fnf = new FileNodeFILE(node);
String oldName = fnf.getName();
String suffix = fnf.isDirectory() ? StringUtils.EMPTY : oldName.substring(oldName.lastIndexOf(CoreConstants.DOT), oldName.length());
oldName = StringUtils.replaceLast(oldName, suffix, StringUtils.EMPTY);
initPane(oldName);
}
private void initPane(String oldName) {
this.setLayout(new BorderLayout());
// 输入框前提示
UILabel newNameLabel = new UILabel(Toolkit.i18nText(
fnf.isDirectory() ?
"Fine-Design_Basic_Enter_New_Folder_Name" : "Fine-Design_Basic_Enter_New_File_Name")
);
newNameLabel.setHorizontalAlignment(SwingConstants.RIGHT);
newNameLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
//newNameLabel.setPreferredSize(new Dimension(118, 15));
// 重命名输入框
nameField = new UITextField(oldName);
nameField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
validInput();
}
@Override
public void insertUpdate(DocumentEvent e) {
validInput();
}
@Override
public void removeUpdate(DocumentEvent e) {
validInput();
}
});
nameField.selectAll();
nameField.setPreferredSize(new Dimension(170, 20));
JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 5));
topPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 0, 15));
topPanel.add(newNameLabel);
topPanel.add(nameField);
// 增加enter以及esc快捷键的支持
nameField.addKeyListener(keyListener);
// 重名提示
warnLabel = new UILabel();
warnLabel.setPreferredSize(new Dimension(300, 50));
warnLabel.setHorizontalAlignment(SwingConstants.LEFT);
warnLabel.setVerticalAlignment(SwingConstants.TOP);
warnLabel.setForeground(Color.RED);
warnLabel.setVisible(false);
JPanel midPanel = new JPanel(new BorderLayout());
midPanel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 15));
midPanel.add(warnLabel, BorderLayout.WEST);
// 确认按钮
confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Confirm"));
confirmButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
confirmClose();
}
});
// 取消按钮
UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel"));
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
JPanel buttonsPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0));
buttonsPane.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 10));
buttonsPane.add(confirmButton);
buttonsPane.add(cancelButton);
this.add(
TableLayoutHelper.createTableLayoutPane(
new Component[][]{
new Component[]{topPanel},
new Component[]{midPanel},
new Component[]{buttonsPane}
},
new double[]{TableLayout.FILL, TableLayout.PREFERRED, TableLayout.PREFERRED},
new double[]{TableLayout.FILL}
),
BorderLayout.CENTER);
this.setSize(340, 200);
this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Rename"));
this.setResizable(false);
this.setIconImage(BaseUtils.readImage("/com/fr/base/images/oem/logo.png"));
this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
GUICoreUtils.centerWindow(this);
this.setVisible(true);
}
private void confirmClose() {
if (TemplateUtils.checkSelectedTemplateIsEditing()) {
if (FineJOptionPane.showConfirmDialog(this,
Toolkit.i18nText("Fine-Design_Basic_Template_Is_Editing"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
YES_NO_OPTION) != JOptionPane.YES_OPTION) {
return;
}
}
String userInput = nameField.getText().trim();
String path = FilenameUtils.standard(fnf.getPath());
String oldName = fnf.getName();
String suffix = fnf.isDirectory() ? StringUtils.EMPTY : oldName.substring(oldName.lastIndexOf(CoreConstants.DOT), oldName.length());
oldName = StringUtils.replaceLast(oldName, suffix, StringUtils.EMPTY);
// 输入为空或者没有修改
if (ComparatorUtils.equals(userInput, oldName)) {
this.dispose();
return;
}
String parentPath = FilenameUtils.standard(fnf.getParent().getPath());
// 简单执行old new 替换是不可行的,例如 /abc/abc/abc/abc/
String newPath = parentPath + CoreConstants.SEPARATOR + userInput + suffix;
this.dispose();
//模版重命名
boolean success = selectedOperation.rename(fnf, path, newPath);
if (success) {
afterRename(path, newPath);
} else {
FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Rename_Failure"),
Toolkit.i18nText("Fine-Design_Basic_Error"),
DEFAULT_OPTION,
ERROR_MESSAGE);
}
}
private void afterRename(String path, String newPath) {
EventDispatcher.fire(DesignerFrameFileDealerPane.TEMPLATE_RENAME, new TwoTuple<>(path, newPath));
HistoryTemplateListCache.getInstance().rename(fnf, path, newPath);
DesignerEnvManager.getEnvManager().replaceRecentOpenedFilePath(fnf.isDirectory(), path, newPath);
selectedOperation.refreshParent();
if (!fnf.isDirectory()) {
//版本控制:未打开模板时重命名,是个纯文件操作
//不借助JTemplate的事件触发机制实现(需要新创建JTemplate,并添加监听,不确定会不会有问题)
path = path.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY);
VcsHelper.getInstance().moveVcs(path, newPath.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY));
}
DesignerContext.getDesignerFrame().setTitle();
LocateAction.gotoEditingTemplateLeaf(newPath);
}
private void validInput() {
String userInput = nameField.getText().trim();
String oldName = fnf.getName();
String suffix = fnf.isDirectory() ? StringUtils.EMPTY : oldName.substring(oldName.lastIndexOf(CoreConstants.DOT), oldName.length());
oldName = oldName.replaceAll(suffix, StringUtils.EMPTY);
if (StringUtils.isEmpty(userInput)) {
confirmButton.setEnabled(false);
return;
}
if (ComparatorUtils.equals(userInput, oldName)) {
warnLabel.setVisible(false);
confirmButton.setEnabled(true);
return;
}
String errorMsg = doCheck(userInput, suffix, fnf.isDirectory());
if (StringUtils.isNotEmpty(errorMsg)) {
nameField.selectAll();
// 如果文件名已存在,则灰掉确认按钮
warnLabel.setText(errorMsg);
warnLabel.setVisible(true);
confirmButton.setEnabled(false);
} else {
warnLabel.setVisible(false);
confirmButton.setEnabled(true);
}
}
private String doCheck (String userInput, String suffix, boolean isDirectory) {
String errorMsg = StringUtils.EMPTY;
if (selectedOperation.duplicated(userInput, suffix, false)) {
errorMsg = Toolkit.i18nText(isDirectory ?
"Fine-Design_Basic_Folder_Name_Duplicate" :
"Fine-Design_Basic_Template_File_Name_Duplicate",
userInput);
}
if (!Pattern.compile(DesignerFrameFileDealerPane.FILE_NAME_LIMIT).matcher(userInput).matches()) {
errorMsg = Toolkit.i18nText("Fine-Design_Basic_Template_Name_Illegal");
}
return errorMsg;
}
}
}

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

@ -10,18 +10,16 @@ import com.fr.stable.xml.XMLPrintWriter;
import com.fr.stable.xml.XMLReadable;
import com.fr.stable.xml.XMLable;
import com.fr.stable.xml.XMLableReader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.KeyStroke;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
/**
* AlphaFine配置类
@ -54,13 +52,17 @@ public class AlphaFineConfigManager implements XMLable {
*/
private boolean containRecommend = true;
/**
* 设置
* 功能
*/
private boolean containAction = true;
/**
* 帮助文档
*/
private boolean containDocument = true;
/**
* 我的模板
* */
private boolean containMyTemplate = true;
/**
* 模板
*/
@ -70,7 +72,7 @@ public class AlphaFineConfigManager implements XMLable {
*/
private boolean containFileContent;
/**
* 应用中心
* 插件中心
*/
private boolean containPlugin = true;
/**
@ -95,6 +97,11 @@ public class AlphaFineConfigManager implements XMLable {
*/
private boolean productDynamics = true;
/**
* 模板商城是否展示
* */
private boolean showTemplateShop = true;
private Map<String, String> actionSearchTextCache = new HashMap<>(8);
private String cacheBuildNO;
@ -326,6 +333,14 @@ public class AlphaFineConfigManager implements XMLable {
this.containDocument = containDocument;
}
public void setContainMyTemplate(boolean containMyTemplate) {
this.containMyTemplate = containMyTemplate;
}
public boolean isContainMyTemplate() {
return containMyTemplate;
}
public boolean isContainTemplate() {
return containTemplate;
}
@ -446,6 +461,14 @@ public class AlphaFineConfigManager implements XMLable {
return productDynamics && FRContext.isChineseEnv();
}
public boolean hasTemplateShop() {
return showTemplateShop && FRContext.isChineseEnv();
}
public void setShowTemplateShop(boolean showTemplateShop) {
this.showTemplateShop = showTemplateShop;
}
public void setProductDynamics(boolean productDynamics) {
this.productDynamics = productDynamics;
}

166
designer-base/src/main/java/com/fr/design/actions/help/alphafine/AlphaFineConfigPane.java

@ -1,17 +1,29 @@
package com.fr.design.actions.help.alphafine;
import com.fr.base.FRContext;
import com.fr.base.svg.IconUtils;
import com.fr.design.DesignerEnvManager;
import com.fr.design.dialog.BasicPane;
import com.fr.design.gui.icheckbox.UICheckBox;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.imenu.UIPopupMenu;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.TableLayoutHelper;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.log.FineLoggerFactory;
import javax.swing.*;
import java.awt.*;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
@ -25,14 +37,22 @@ import java.awt.event.MouseEvent;
public class AlphaFineConfigPane extends BasicPane {
private static final String TYPE = "pressed";
private static final String DISPLAY_TYPE = "+";
private static final Color LABEL_TEXT = new Color(0x919193);
private static final double COLUMN_GAP = 180;
private static final double ROW_GAP = 25;
private static final double COLUMN_WIDTH = 150;
private static final double ROW_HEIGHT = 25;
private KeyStroke shortCutKeyStore = null;
private UICheckBox enabledCheckbox, searchOnlineCheckbox, needSegmentationCheckbox, needIntelligentCustomerService, productDynamicsCheckbox, containActionCheckbox, containDocumentCheckbox, containTemplateCheckbox, containPluginCheckbox, containFileContentCheckbox;
private UICheckBox enabledCheckbox, searchOnlineCheckbox, needSegmentationCheckbox;
private UICheckBox productDynamicsCheckbox, containTemplateShopCheckbox, containDocumentCheckbox,
containPluginCheckbox, containActionCheckbox, containMyTemplateCheckbox;
private UITextField shortcutsField;
// 搜索范围-我的模板,相关组件
private JPanel containMyTemplatePane;
private JButton myTemplateSearchConfigButton;
private UIPopupMenu myTemplateSearchMenu;
private UICheckBox containTemplateNameSearchCheckbox, containFileContentSearchCheckbox;
public AlphaFineConfigPane() {
this.initComponents();
}
@ -45,15 +65,6 @@ public class AlphaFineConfigPane extends BasicPane {
createSearchConfigPane(contentPane);
this.setLayout(FRGUIPaneFactory.createBorderLayout());
this.add(contentPane, BorderLayout.NORTH);
}
private Component[][] initSearchRangeComponents() {
Component[][] components = new Component[][]{
new Component[]{productDynamicsCheckbox, containActionCheckbox, containDocumentCheckbox},
new Component[]{containTemplateCheckbox, containPluginCheckbox, containFileContentCheckbox},
};
return components;
}
private Component[][] initOnlineComponents() {
@ -63,24 +74,99 @@ public class AlphaFineConfigPane extends BasicPane {
return components;
}
// 搜索范围
private void createSearchConfigPane(JPanel contentPane) {
double[] rowSize = {ROW_GAP, ROW_GAP, ROW_GAP};
double[] columnSize = {COLUMN_GAP, COLUMN_GAP, COLUMN_GAP};
double[] rowSize = {ROW_HEIGHT, ROW_HEIGHT, ROW_HEIGHT};
double[] columnSize = {COLUMN_WIDTH, COLUMN_WIDTH, COLUMN_WIDTH};
JPanel northPane = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_Search_Range"));
productDynamicsCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Product_Dynamics"));
containActionCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Set"));
productDynamicsCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_AlphaFine_Product_News"));
containActionCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Function"));
containPluginCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Plugin_Addon"));
containDocumentCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Community_Help"));
containTemplateCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_Templates"));
containFileContentCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Templates_Content"));
needIntelligentCustomerService = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_Intelligent_Customer_Service"));
containMyTemplateCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Report_My_Templates"));
containFileContentSearchCheckbox = new UICheckBox(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Templates_Content"));
containTemplateShopCheckbox = new UICheckBox(Toolkit.i18nText("Fine-Design_Report_AlphaFine_Template_Shop"));
containMyTemplateCheckbox = new UICheckBox(Toolkit.i18nText("Fine-Design_Report_My_Templates"));
JPanel searchConfigPane = TableLayoutHelper.createTableLayoutPane(initSearchRangeComponents(), rowSize, columnSize);
northPane.add(searchConfigPane);
contentPane.add(northPane);
}
private Component[][] initSearchRangeComponents() {
// 我的模板checkbox设置,点击后
initMyTemplateSearchPane();
Component[][] components = new Component[][]{
new Component[]{productDynamicsCheckbox, containTemplateShopCheckbox, containDocumentCheckbox},
new Component[]{containPluginCheckbox, containActionCheckbox, containMyTemplatePane},
};
for (int i = 0; i < components.length; i++) {
for (int j = 0; j < components[i].length; j++) {
if (components[i][j] instanceof UICheckBox) {
UICheckBox box = (UICheckBox) components[i][j];
}
}
}
return components;
}
/**
* 搜索范围中的复选框有无选中的
* */
private boolean hasSelectedSearchRangeCheckBox() {
return productDynamicsCheckbox.isSelected() || containTemplateShopCheckbox.isSelected() || containDocumentCheckbox.isSelected()
|| containPluginCheckbox.isSelected() || containActionCheckbox.isSelected() || containMyTemplateCheckbox.isSelected();
}
// 搜索范围-我的模板
private void initMyTemplateSearchPane() {
containMyTemplatePane = new JPanel(new FlowLayout(FlowLayout.LEFT,4,5));
containMyTemplateCheckbox.setBorder(BorderFactory.createEmptyBorder());
containMyTemplateCheckbox.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (containMyTemplateCheckbox.isSelected()) {
myTemplateSearchConfigButton.setVisible(true);
} else {
myTemplateSearchConfigButton.setVisible(false);
}
}
}
);
myTemplateSearchConfigButton = new JButton();
myTemplateSearchConfigButton.setBorder(BorderFactory.createEmptyBorder());
myTemplateSearchConfigButton.setMargin(new Insets(0,0,0,0));
myTemplateSearchConfigButton.setIcon(IconUtils.readIcon("/com/fr/design/mainframe/alphafine/images/config.svg"));
myTemplateSearchMenu = new UIPopupMenu();
containTemplateNameSearchCheckbox = new UICheckBox(Toolkit.i18nText("Fine-Design_AlphaFine_Config_Name_Search"));
containFileContentSearchCheckbox = new UICheckBox(Toolkit.i18nText("Fine-Design_AlphaFine_Config_Content_Search"));
containTemplateNameSearchCheckbox.setSelected(true);
containTemplateNameSearchCheckbox.setEnabled(false);
containTemplateNameSearchCheckbox.setBackground(null);
containFileContentSearchCheckbox.setBackground(null);
myTemplateSearchMenu.add(containTemplateNameSearchCheckbox);
myTemplateSearchMenu.add(containFileContentSearchCheckbox);
myTemplateSearchConfigButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
GUICoreUtils.showPopupMenu(myTemplateSearchMenu, containMyTemplatePane, containMyTemplateCheckbox.getWidth(), containMyTemplatePane.getY());
}
@Override
public void mouseMoved(MouseEvent e) {
super.mouseMoved(e);
myTemplateSearchMenu.setVisible(false);
}
});
containMyTemplatePane.add("containMyTemplateCheckbox", containMyTemplateCheckbox);
containMyTemplatePane.add("myTemplateSearchConfigButton", myTemplateSearchConfigButton);
}
private void createShortcutsPane(JPanel contentPane) {
JPanel northPane = FRGUIPaneFactory.createTitledBorderPane(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_Shortcut_Config"));
shortcutsField = new UITextField();
@ -91,7 +177,7 @@ public class AlphaFineConfigPane extends BasicPane {
northPane.add(new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Open") + ":"));
northPane.add(shortcutsField);
UILabel label = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_AlphaFine_SetShortcuts"));
label.setForeground(Color.RED);
label.setForeground(LABEL_TEXT);
northPane.add(label);
contentPane.add(northPane);
}
@ -130,21 +216,21 @@ public class AlphaFineConfigPane extends BasicPane {
productDynamicsCheckbox.setEnabled(false);
containPluginCheckbox.setEnabled(false);
containDocumentCheckbox.setEnabled(false);
needIntelligentCustomerService.setEnabled(false);
containTemplateShopCheckbox.setEnabled(false);
productDynamicsCheckbox.setSelected(false);
containPluginCheckbox.setSelected(false);
containDocumentCheckbox.setSelected(false);
needIntelligentCustomerService.setSelected(false);
containTemplateShopCheckbox.setSelected(false);
} else {
productDynamicsCheckbox.setEnabled(true);
containPluginCheckbox.setEnabled(true);
containDocumentCheckbox.setEnabled(true);
needIntelligentCustomerService.setEnabled(true);
containTemplateShopCheckbox.setEnabled(true);
}
}
});
double[] rowSize = {ROW_GAP};
double[] columnSize = {COLUMN_GAP, COLUMN_GAP, COLUMN_GAP};
double[] rowSize = {ROW_HEIGHT};
double[] columnSize = {COLUMN_WIDTH, COLUMN_WIDTH, COLUMN_WIDTH};
JPanel onlinePane = TableLayoutHelper.createTableLayoutPane(initOnlineComponents(), rowSize, columnSize);
northPane.add(onlinePane);
contentPane.add(northPane);
@ -172,8 +258,10 @@ public class AlphaFineConfigPane extends BasicPane {
this.searchOnlineCheckbox.setSelected(enabled4Locale);
this.containActionCheckbox.setSelected(alphaFineConfigManager.isContainAction());
this.containTemplateCheckbox.setSelected(alphaFineConfigManager.isContainTemplate());
this.containFileContentCheckbox.setSelected(alphaFineConfigManager.isContainFileContent());
this.containMyTemplateCheckbox.setSelected(alphaFineConfigManager.isContainMyTemplate());
this.myTemplateSearchConfigButton.setVisible(alphaFineConfigManager.isContainMyTemplate());
this.containFileContentSearchCheckbox.setSelected(alphaFineConfigManager.isContainFileContent());
this.containDocumentCheckbox.setSelected(alphaFineConfigManager.isContainDocument() && enabled4Locale);
this.containDocumentCheckbox.setEnabled(enabled4Locale);
@ -184,13 +272,13 @@ public class AlphaFineConfigPane extends BasicPane {
this.productDynamicsCheckbox.setSelected(alphaFineConfigManager.isProductDynamics() && enabled4Locale);
this.productDynamicsCheckbox.setEnabled(enabled4Locale);
this.containTemplateShopCheckbox.setSelected(alphaFineConfigManager.hasTemplateShop() && enabled4Locale);
this.containTemplateShopCheckbox.setEnabled(enabled4Locale);
this.shortcutsField.setText(AlphaFineShortCutUtil.getDisplayShortCut(alphaFineConfigManager.getShortcuts()));
this.needSegmentationCheckbox.setSelected(alphaFineConfigManager.isNeedSegmentationCheckbox());
this.needIntelligentCustomerService.setSelected(alphaFineConfigManager.isNeedIntelligentCustomerService() && enabled4Locale);
this.needIntelligentCustomerService.setEnabled(enabled4Locale);
shortCutKeyStore = convert2KeyStroke(alphaFineConfigManager.getShortcuts());
}
@ -201,12 +289,12 @@ public class AlphaFineConfigPane extends BasicPane {
alphaFineConfigManager.setContainAction(this.containActionCheckbox.isSelected());
alphaFineConfigManager.setContainDocument(this.containDocumentCheckbox.isSelected());
alphaFineConfigManager.setProductDynamics(this.productDynamicsCheckbox.isSelected());
alphaFineConfigManager.setShowTemplateShop(this.containTemplateShopCheckbox.isSelected());
alphaFineConfigManager.setEnabled(this.enabledCheckbox.isSelected());
alphaFineConfigManager.setSearchOnLine(this.searchOnlineCheckbox.isSelected());
alphaFineConfigManager.setContainTemplate(this.containTemplateCheckbox.isSelected());
alphaFineConfigManager.setContainFileContent(this.containFileContentCheckbox.isSelected());
alphaFineConfigManager.setContainMyTemplate(this.containMyTemplateCheckbox.isSelected());
alphaFineConfigManager.setContainFileContent(this.containFileContentSearchCheckbox.isSelected());
alphaFineConfigManager.setNeedSegmentationCheckbox(this.needSegmentationCheckbox.isSelected());
alphaFineConfigManager.setNeedIntelligentCustomerService(this.needIntelligentCustomerService.isSelected());
alphaFineConfigManager.setShortcuts(shortCutKeyStore != null ? shortCutKeyStore.toString().replace(TYPE, DISPLAY_TYPE) : this.shortcutsField.getText());
designerEnvManager.setAlphaFineConfigManager(alphaFineConfigManager);
try {
@ -233,10 +321,10 @@ public class AlphaFineConfigPane extends BasicPane {
}
public UICheckBox getIsContainFileContentCheckbox() {
return containFileContentCheckbox;
return containFileContentSearchCheckbox;
}
public void setIsContainFileContentCheckbox(UICheckBox isContainFileContentCheckbox) {
this.containFileContentCheckbox = isContainFileContentCheckbox;
this.containFileContentSearchCheckbox = isContainFileContentCheckbox;
}
}

28
designer-base/src/main/java/com/fr/design/carton/CartonFiles.java

@ -0,0 +1,28 @@
package com.fr.design.carton;
import java.io.File;
public class CartonFiles {
private File easyCheckerFile;
private File timerCheckerFile;
public CartonFiles() {
}
public File getEasyCheckerFile() {
return easyCheckerFile;
}
public void setEasyCheckerFile(File easyCheckerFile) {
this.easyCheckerFile = easyCheckerFile;
}
public File getTimerCheckerFile() {
return timerCheckerFile;
}
public void setTimerCheckerFile(File timerCheckerFile) {
this.timerCheckerFile = timerCheckerFile;
}
}

161
designer-base/src/main/java/com/fr/design/carton/CartonThreadExecutorPool.java

@ -0,0 +1,161 @@
package com.fr.design.carton;
import com.fr.base.SimpleDateFormatThreadSafe;
import com.fr.design.i18n.Toolkit;
import com.fr.json.JSONObject;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
public class CartonThreadExecutorPool extends ThreadPoolExecutor {
private static final int MAX_LIVE_TIME = 3000;
private static final int MAX_WORKER_THREADS = 10;
/**
* 开启间隔检测后两次检测的相隔时间ms
*/
private static final long CHECK_INTERVAL_MS = 100;
private final ThreadLocal<StackTraceElement[]> startReportedStack = new ThreadLocal<>();
private volatile static CartonThreadExecutorPool cartonThreadExecutorPool;
private static final ConcurrentHashMap<Long, ThreadInfo> concurrentHashMap = new ConcurrentHashMap<>();
private static final SimpleDateFormatThreadSafe simpleDateFormatThreadSafe = new SimpleDateFormatThreadSafe();
private final static AtomicLong hangCount = new AtomicLong(0);
private Timer timer;
/**
* 一个变量用于控制easy监测模式的开关
*/
private boolean easyWitch = false;
public boolean isEasyWitch() {
return easyWitch;
}
public void setEasyWitch(boolean easyWitch) {
this.easyWitch = easyWitch;
}
private static class ThreadInfo {
private ThreadInfo () {
hangNumber = hangCount.getAndAdd(1);
}
private long hangNumber;
private final Thread eventThread = Thread.currentThread();
private StackTraceElement[] lastReportedStack;
private final long startTime = System.currentTimeMillis();
public void checkForHang() {
if (timeSoFar() > MAX_LIVE_TIME) {
examineHang();
}
}
private long timeSoFar() {
return (System.currentTimeMillis() - startTime);
}
private void examineHang() {
StackTraceElement[] currentStack = eventThread.getStackTrace();
if (lastReportedStack!=null && EventDispatchThreadHangMonitor.stacksEqual(currentStack, lastReportedStack)) {
return;
}
lastReportedStack = currentStack;
String stackTrace = EventDispatchThreadHangMonitor.stackTraceToString(currentStack);
JSONObject jsonObject = new JSONObject();
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"), simpleDateFormatThreadSafe.format(System.currentTimeMillis()));
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"), "swingWorker_" + hangNumber);
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Duration_Task_Execute"), timeSoFar() + "ms");
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Stack_Info"), stackTrace);
EventDispatchThreadHangMonitor.outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.TIMER_CHECK_FLAG);
EventDispatchThreadHangMonitor.checkForDeadlock();
}
}
/**
* 来自SwingWorker类
*/
public static ThreadFactory threadFactory =
new ThreadFactory() {
final ThreadFactory defaultFactory =
Executors.defaultThreadFactory();
@Override
public Thread newThread(final Runnable r) {
Thread thread =
defaultFactory.newThread(r);
thread.setName("SwingWorker-"
+ thread.getName());
thread.setDaemon(true);
return thread;
}
};
public static CartonThreadExecutorPool getTimerThreadExecutorPool () {
if (cartonThreadExecutorPool == null) {
synchronized (CartonThreadExecutorPool.class) {
if (cartonThreadExecutorPool == null) {
cartonThreadExecutorPool =
new CartonThreadExecutorPool(MAX_WORKER_THREADS, MAX_WORKER_THREADS,
10L, TimeUnit.MINUTES,
new LinkedBlockingQueue<Runnable>(),threadFactory
);
}
}
}
return cartonThreadExecutorPool;
}
private CartonThreadExecutorPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
simpleDateFormatThreadSafe.applyPattern("yyyy-MM-dd HH:mm:ss");
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
startReportedStack.set(t.getStackTrace());
concurrentHashMap.put(t.getId(), new ThreadInfo());
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
long currentThreadId = Thread.currentThread().getId();
long runTime = (System.currentTimeMillis() - concurrentHashMap.get(currentThreadId).startTime);
//加~是为了之后输出的时候换行。
if (isEasyWitch() && runTime > MAX_LIVE_TIME) {
JSONObject jsonObject = new JSONObject();
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"), simpleDateFormatThreadSafe.format(System.currentTimeMillis()));
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"), "swingWorker_" + concurrentHashMap.get(currentThreadId).hangNumber);
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Start_Time"), simpleDateFormatThreadSafe.format(concurrentHashMap.get(currentThreadId).startTime));
jsonObject.put(Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Total_Time"), runTime + "ms");
EventDispatchThreadHangMonitor.outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.EASY_CHECK_FLAG);
}
concurrentHashMap.remove(currentThreadId);
}
public class Checker extends TimerTask {
@Override
public void run() {
if (cartonThreadExecutorPool == null || concurrentHashMap.isEmpty()) {
return;
}
for (Map.Entry<Long, ThreadInfo> map : concurrentHashMap.entrySet()) {
map.getValue().checkForHang();
}
}
}
public void initTimer() {
timer = new Timer("CheckerSwingWorker",true);
timer.schedule(new Checker(), 0, CHECK_INTERVAL_MS);
}
public void stopTimer() {
if (timer != null) {
timer.cancel();
}
}
}

45
designer-base/src/main/java/com/fr/design/carton/CartonUploadMessage.java

@ -0,0 +1,45 @@
package com.fr.design.carton;
public class CartonUploadMessage {
private String hangCount;
private String slowTime;
private String threadTime;
private String info;
public CartonUploadMessage() {
}
public String getHangCount() {
return hangCount;
}
public void setHangCount(String hangCount) {
this.hangCount = hangCount;
}
public String getSlowTime() {
return slowTime;
}
public void setSlowTime(String slowTime) {
this.slowTime = slowTime;
}
public String getThreadTime() {
return threadTime;
}
public void setThreadTime(String threadTime) {
this.threadTime = threadTime;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}

407
designer-base/src/main/java/com/fr/design/carton/EventDispatchThreadHangMonitor.java

@ -0,0 +1,407 @@
package com.fr.design.carton;
import com.fr.concurrent.FineExecutors;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.ArrayUtils;
import com.fr.stable.ProductConstantsBase;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import com.fr.third.ibm.icu.text.SimpleDateFormat;
import org.jetbrains.annotations.NotNull;
import javax.swing.SwingUtilities;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.AWTEvent;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 参考自git swinghelper
* 用于卡顿检测
* 主要是两块内容
* 1.获取eventQueue中每个事件的执行时间
* 2.用一个Timer定时去检测当前执行任务的线程
*/
public final class EventDispatchThreadHangMonitor extends EventQueue {
/**
* 日期事件格式
*/
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static final EventDispatchThreadHangMonitor INSTANCE = new EventDispatchThreadHangMonitor();
/**
* 一个timer
*/
private Timer timer;
/**
* 开启间隔检测后两次检测的相隔时间ms
*/
private static final long CHECK_INTERVAL_MS = 100;
/**
* 最大的事件允许执行时间超过该时间则打印堆栈等相关信息
*/
private static final long UNREASONABLE_DISPATCH_DURATION_MS = 1500;
/**
* 事件唯一编码用于方便日志的查看
*/
private static long hangCount = 0;
/**
* 输出日志所在地址
*/
private static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log");
/**
* 类似于一个开关当该值为默认的false启动时定时任务在窗口开启前都不会对执行的事件进行检查
*/
private boolean haveShownSomeComponent = false;
/**
* 该链表为主要的实现定时任务的容器在重写的dispatchEvent中由pre方法将DispatchInfo加入到链表由post方法remove
*/
private final LinkedList<DispatchInfo> dispatches = new LinkedList<DispatchInfo>();
/**
* 一个变量用于控制easy监测模式的开关
*/
private boolean easyWitch = false;
private static ScheduledExecutorService scheduledExecutorService;
public boolean isEasyWitch() {
return easyWitch;
}
public void setEasyWitch(boolean easyWitch) {
this.easyWitch = easyWitch;
}
/**
* 一个变量用于记录Timer的开关
*/
public boolean isTimerWitch() {
return timerWitch;
}
public void setTimerWitch(boolean timerWitch) {
this.timerWitch = timerWitch;
}
private boolean timerWitch = false;
private synchronized static long getHangCount() {
return hangCount++;
}
/**
* @param a can not be null
* @param b can not be null
* @return
*/
public static boolean stacksEqual(@NotNull StackTraceElement[] a, @NotNull StackTraceElement[] b) {
if (!ArrayUtils.isSameLength(a, b)) {
return false;
}
for (int i = 0; i < a.length; ++i) {
if (!a[i].equals(b[i])) {
return false;
}
}
return true;
}
/**
* 用于判断是不是特定的堆栈
*/
public static boolean stackTraceElementIs(StackTraceElement e, String className, String methodName, boolean isNative) {
return e.getClassName().equals(className) && e.getMethodName().equals(methodName) && e.isNativeMethod() == isNative;
}
/**
* 用于判断某个堆栈是否在等待另一个事件
* 取当前堆栈前三层判断是是不是匹配等待堆栈的格式
*/
public static boolean isWaitingForNextEvent(StackTraceElement[] currentStack) {
return currentStack != null && currentStack.length >= 3 &&
stackTraceElementIs(currentStack[0], "java.lang.Object", "wait", true)
&& stackTraceElementIs(currentStack[1], "java.lang.Object", "wait", false)
&& stackTraceElementIs(currentStack[2], "java.awt.EventQueue", "getNextEvent", false);
}
/**
* event事件的包装类
*/
public static class DispatchInfo {
// 上一次被打印的堆栈ou
private StackTraceElement[] lastReportedStack;
//获取执行该事件的线程
private final Thread eventDispatchThread = Thread.currentThread();
//在队列中等待执行的事件最后未执行的时间,当有一个事件执行完后就遍历dispatches给该值赋当前时间
private long lastDispatchTimeMillis = System.currentTimeMillis();
//事件开始的时间
private final long startDispatchTimeMillis = System.currentTimeMillis();
//事件编号
private long hangNumber;
//构造函数,给当前对象赋一个递增的唯一编号
public DispatchInfo() {
hangNumber = getHangCount();
}
//定时调度任务检测的入口,如果执行时间大于设定的值就进入examineHang()方法
public void checkForHang() {
if (timeSoFar() > UNREASONABLE_DISPATCH_DURATION_MS) {
examineHang();
}
}
//超时堆栈的具体处理
private void examineHang() {
//获取执行线程的当前堆栈
StackTraceElement[] currentStack = eventDispatchThread.getStackTrace();
if (isWaitingForNextEvent(currentStack)) {
return;
}
//某个事件执行时间很长,定时处理时可能会连续打很多个堆栈,对同一个事件的相同堆栈只打一次
if (lastReportedStack !=null && stacksEqual(lastReportedStack, currentStack)) {
return;
}
String stackTrace = stackTraceToString(currentStack);
lastReportedStack = currentStack;
JSONObject jsonObject = new JSONObject();
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"), simpleDateFormat.format(System.currentTimeMillis()));
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"), "eventQueue_" + hangNumber);
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Duration_Task_Execute"), timeSoFar() + "ms");
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Stack_Info"), stackTrace);
outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.TIMER_CHECK_FLAG);
checkForDeadlock();
}
//记录连续运行了多长时间
private long timeSoFar() {
return (System.currentTimeMillis() - lastDispatchTimeMillis);
}
//记录一个事件从被分发到结束的总运行时间
private long totalTime() {
return (System.currentTimeMillis() - startDispatchTimeMillis);
}
//事件处理完后的时间判断
public void dispose() {
if (timeSoFar() > UNREASONABLE_DISPATCH_DURATION_MS) {
exportCartonLog(true);
} else if (lastReportedStack != null){
exportCartonLog(false);
}
}
/**
*
* @param flag 判断一下输出日志时要输出哪个时间
*/
private void exportCartonLog(boolean flag) {
JSONObject jsonObject = new JSONObject();
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time"), simpleDateFormat.format(System.currentTimeMillis()));
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number"), "eventQueue_" + hangNumber);
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Start_Time"), simpleDateFormat.format(startDispatchTimeMillis));
if (flag) {
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Total_Time"), timeSoFar() + "ms");
} else {
jsonObject.put(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Total_Time"), totalTime() + "ms");
}
outPutJournalLog(jsonObject.toString(), SwitchForSwingChecker.EASY_CHECK_FLAG);
}
}
public static void outPutJournalLog(String message, int flag) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
String date = simpleDateFormat.format(System.currentTimeMillis());
String filename = flag == SwitchForSwingChecker.EASY_CHECK_FLAG ? SwitchForSwingChecker.EASY_CHECKER_FILE_NAME: SwitchForSwingChecker.TIMER_CHECKER_FILE_NAME;
String[] split = date.split("-");
int month = StringUtils.isEmpty(split[1]) ? -1 : Integer.parseInt(split[1]);
String dirPath = StableUtils.pathJoin(JOURNAL_FILE_PATH, split[0], "month-" + month, date);
File dirFile = new File(dirPath);
File file = new File( StableUtils.pathJoin(dirPath, filename));
try {
if (!file.exists()) {
if (!dirFile.exists()) {
dirFile.mkdirs();
}
file.createNewFile();
}
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file, true));
String outputMessage = new StringBuilder(message.replaceAll("~", "\r\n")).append(",").append("\r\n").toString();
bufferedWriter.write(outputMessage);
bufferedWriter.close();
} catch (IOException e) {
FineLoggerFactory.getLogger().error("output fail", e);
}
}
private EventDispatchThreadHangMonitor() {
}
/**
* 参考SwingExplorer,在处理模态框时没有做特殊处理也不会输出卡顿堆栈
* 原因是SwingExplorer窗口一直有一个监听事件不断的addremove
* 由于卡顿日志输出的是事件连续执行的时间所以一个长时间存在的模态框被不断重复的监听事件刷新时间就不会输出了
* 当检测开关打开后在这里模拟一下监听事件给个不耗时的任务就可以
*/
public void startFilterModalWindow() {
scheduledExecutorService = FineExecutors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
//不用干事,切个片就可以
}
});
}
}, 0, 500, TimeUnit.MILLISECONDS);
}
public void stopFilterModalWindow() {
if (scheduledExecutorService != null) {
scheduledExecutorService.shutdown();
}
}
/**
* Sets up a timer to check for hangs frequently.
* 初始化一个Timer
*/
public void initTimer() {
final long initialDelayMs = 0;
final boolean daemon = true;
timer = new Timer("EventDispatchThreadHangMonitor", daemon);
timer.schedule(new HangChecker(), initialDelayMs, CHECK_INTERVAL_MS);
}
/**
* /消除Timer
*/
public void stopTimer() {
if (timer != null) {
timer.cancel();
}
}
/**
* /定时执行的任务
*/
public class HangChecker extends TimerTask {
@Override
public void run() {
synchronized (dispatches) {
//如果链表为空或者窗口还没启开,定时检测就不进行
if (dispatches.isEmpty() || !haveShownSomeComponent) {
return;
}
dispatches.getLast().checkForHang();
}
}
}
/**
* 将swing中默认的EventQueue换成自己的
*/
public static void initMonitoring() {
Toolkit.getDefaultToolkit().getSystemEventQueue().push(INSTANCE);
}
/**
* Overrides EventQueue.dispatchEvent to call our pre and post hooks either
* side of the system's event dispatch code.
* 重写
*/
@Override
protected void dispatchEvent(AWTEvent event) {
//如果两个开关都没开,那就不走重写方法了
if (!isEasyWitch() && !isTimerWitch()) {
super.dispatchEvent(event);
} else {
try {
preDispatchEvent();
super.dispatchEvent(event);
} finally {
postDispatchEvent();
if (!haveShownSomeComponent &&
event instanceof WindowEvent && event.getID() == WindowEvent.WINDOW_OPENED) {
haveShownSomeComponent = true;
}
}
}
}
/**
* Starts tracking a dispatch.
*/
private synchronized void preDispatchEvent() {
synchronized (dispatches) {
dispatches.addLast(new DispatchInfo());
}
}
/**
* Stops tracking a dispatch.
*/
private synchronized void postDispatchEvent() {
synchronized (dispatches) {
DispatchInfo justFinishedDispatch = dispatches.removeLast();
if (isEasyWitch()) {
justFinishedDispatch.dispose();
}
//嵌套最深的事件执行完毕后刷新链表中其他事件的lastDispatchTimeMillis
Thread currentEventDispatchThread = Thread.currentThread();
for (DispatchInfo dispatchInfo : dispatches) {
if (dispatchInfo.eventDispatchThread == currentEventDispatchThread) {
dispatchInfo.lastDispatchTimeMillis = System.currentTimeMillis();
}
}
}
}
/**
* 检查死锁
*/
public static void checkForDeadlock() {
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
long[] threadIds = threadBean.findDeadlockedThreads();
if (threadIds == null) {
return;
}
FineLoggerFactory.getLogger().warn("deadlock detected involving the following threads:");
ThreadInfo[] threadInfos = threadBean.getThreadInfo(threadIds, Integer.MAX_VALUE);
for (ThreadInfo info : threadInfos) {
FineLoggerFactory.getLogger().warn("Thread # {} {} ( {} ) waiting on {} held by {} {}", info.getThreadId(), info.getThreadName(),
info.getThreadState(), info.getLockName(), info.getLockOwnerName(), stackTraceToStringForConsole(info.getStackTrace()));
}
}
public static String stackTraceToString(StackTraceElement[] stackTrace) {
StringBuilder result = new StringBuilder();
for (StackTraceElement stackTraceElement : stackTrace) {
String indentation = " ";
result.append("~").append(indentation).append(stackTraceElement);
}
return result.toString();
}
public static String stackTraceToStringForConsole(StackTraceElement[] stackTrace) {
StringBuilder result = new StringBuilder();
for (StackTraceElement stackTraceElement : stackTrace) {
String indentation = " ";
result.append("\r\n").append(indentation).append(stackTraceElement);
}
return result.toString();
}
}

407
designer-base/src/main/java/com/fr/design/carton/FeedbackToolboxDialog.java

@ -0,0 +1,407 @@
package com.fr.design.carton;
import com.fr.decision.webservice.v10.log.download.utils.LogZipUtils;
import com.fr.design.DesignerEnvManager;
import com.fr.design.constants.UIConstants;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.env.DesignerWorkspaceInfo;
import com.fr.design.gui.date.UIDatePicker;
import com.fr.design.gui.ibutton.UIButton;
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.mainframe.DesignerContext;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.env.detect.ui.EnvDetectorDialog;
import com.fr.file.FILE;
import com.fr.file.FILEChooserPane;
import com.fr.file.FILEFactory;
import com.fr.file.filter.ChooseFileFilter;
import com.fr.general.GeneralUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import org.jetbrains.annotations.Nullable;
import com.fr.workspace.WorkContext;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.filechooser.FileSystemView;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.text.ParseException;
import java.util.List;
import java.util.Objects;
public class FeedbackToolboxDialog extends JDialog {
private UIDatePicker uiDatePicker;
private JPanel generalSettingPanel = null;
private UICheckBox easyCheckerButton = null;
private UICheckBox timerCheckerButton = null;
private UIButton uploadButton = null;
private UILabel exportLogLabel = null;
private final Color backgroundColor = new Color(240, 240, 243, 1);
private final Color lineColor = new Color(192, 192, 192, 120);
private JPanel body = null;
private static final String WORK_SPACE_PATH = "reportlets";
private static final int BUFFER_SIZE = 2 * 1024;
public FeedbackToolboxDialog(Frame owner) {
super(owner, Toolkit.i18nText("Fine-Design_Basic_Carton_Feedback_ToolBox"));
setResizable(false);
this.setLayout(FRGUIPaneFactory.createBorderLayout());
createBodyPanel();
add(body);
setSize(body.getPreferredSize());
setSwitches(!StringUtils.isEmpty(GeneralUtils.objectToString(uiDatePicker.getSelectedItem())));
repaint();
GUICoreUtils.centerWindow(this);
}
public void createBodyPanel() {
JPanel body = FRGUIPaneFactory.createBorderLayout_L_Pane();
body.setBackground(backgroundColor);
JPanel titlePane = createTitlePane();
JPanel tailPane = createTailPane();
JPanel midPane = createMidPane();
JPanel infoPane = createInfoPane();
body.add(titlePane, BorderLayout.NORTH);
body.add(tailPane, BorderLayout.SOUTH);
body.add(midPane, BorderLayout.CENTER);
midPane.add(infoPane, BorderLayout.NORTH);
Dimension dimension = new Dimension(662, 556);
body.setPreferredSize(dimension);
this.body = body;
}
private JPanel createInfoPane() {
JPanel northPane = FRGUIPaneFactory.createNColumnGridInnerContainer_Pane(2, 10, 10);
UILabel title = new UILabel();
//空格布局会好看一点
title.setText(" " + Toolkit.i18nText("Fine-Design_Basic_Carton_Record_Lag_Time") + ": ");
//判断一下当天是否有卡顿日志记录,如果有将日期设置为当天,如果没有设置为空
boolean cartonExists = SwitchForSwingChecker.isCartonExists();
if (cartonExists) {
this.uiDatePicker = new UIDatePicker(UIDatePicker.STYLE_CN_DATE1, this);
} else {
this.uiDatePicker = new UIDatePicker(UIDatePicker.STYLE_CN_DATE1, null, this);
}
Dimension dimension = new Dimension(160, 100);
uiDatePicker.setPreferredSize(dimension);
northPane.add(GUICoreUtils.createFlowPane(new Component[]{title, uiDatePicker}, FlowLayout.LEFT));
exportLogLabel = new UILabel();
exportLogLabel.setText(Toolkit.i18nText("Fine-Design_Basic_Carton_Export_Carton_Log"));
exportLogLabel.setForeground(UIConstants.FLESH_BLUE);
exportLogLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (exportLogLabel.isEnabled()) {
exportLogFile();
}
}
@Override
public void mouseEntered(MouseEvent evt) {
Object source = evt.getSource();
if (source instanceof UILabel) {
((UILabel) source).setCursor(new Cursor(Cursor.HAND_CURSOR));
}
}
});
northPane.add(GUICoreUtils.createFlowPane(exportLogLabel, FlowLayout.RIGHT));
return northPane;
}
private void exportLogFile() {
String selectDate = GeneralUtils.objectToString(uiDatePicker.getSelectedItem());
FILEChooserPane fileChooserPane = FILEChooserPane.getInstance();
StringBuilder fileName = new StringBuilder();
fileName.append(selectDate).append(Toolkit.i18nText("Fine-Design_Basic_Carton_Carton_Log"));
fileChooserPane.setFileNameTextField(fileName.toString(), " ");
fileChooserPane.removeAllFilter();
fileChooserPane.addChooseFILEFilter(new ChooseFileFilter("zip", Toolkit.i18nText("Fine-Design_Basic_Carton_Compile_File")));
//默认选择桌面
FILE desktop = FILEFactory.createFILE(FILEFactory.FILE_PREFIX + FileSystemView.getFileSystemView().getHomeDirectory().getPath());
fileChooserPane.setCurrentDirectory(desktop);
int chooseResult = fileChooserPane.showSaveDialog(DesignerContext.getDesignerFrame());
if (chooseResult == 0) {
FILE selectedFile = fileChooserPane.getSelectedFILE();
String path = selectedFile.getPath();
//selectDate 2002-03-09例子
String[] split = selectDate.split("-");
int month = Integer.parseInt(split[1]);
String sourceFilePath = StableUtils.pathJoin(SwitchForSwingChecker.JOURNAL_FILE_PATH, split[0], "month-" + month, selectDate);
File sourceFile = new File(sourceFilePath);
if (sourceFile.exists()) {
exportCartonLog(sourceFile, path, sourceFilePath);
}
fileChooserPane.removeAllFilter();
}
}
private JPanel createTailPane() {
JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
tailPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, lineColor));
JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
actionsPanel.setLayout(FRGUIPaneFactory.createM_BorderLayout());
{
uploadButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Carton_Upload_Carton_Log"));
uploadButton.addActionListener((e) -> {
try {
List<CartonUploadMessage> list = SwitchForSwingChecker.uploadJournalLog(uiDatePicker.getSelectedDate());
if (list.isEmpty()) {
FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine_Design_Basic_Upload_Fail"), UIManager.getString("OptionPane.messageDialogTitle"), JOptionPane.ERROR_MESSAGE);
} else {
FineJOptionPane.showMessageDialog(null, Toolkit.i18nText("Fine-Design_Basic_Upload_Success"));
}
} catch (ParseException parseException) {
FineLoggerFactory.getLogger().error("parse error", parseException);
}
});
actionsPanel.add(uploadButton, BorderLayout.WEST);
UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel"));
cancelButton.addActionListener((e) -> {
setVisible(false);
EnvDetectorDialog envDetectorDialog = new EnvDetectorDialog(DesignerContext.getDesignerFrame());
envDetectorDialog.setVisible(true);
dispose();
});
actionsPanel.add(cancelButton, BorderLayout.EAST);
}
UIButton currencySetButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Carton_General_Settings"));
currencySetButton.addActionListener((e -> {
createGeneralSettingPanel();
this.remove(body);
this.add(generalSettingPanel);
setSize(generalSettingPanel.getPreferredSize());
repaint();
setVisible(true);
}));
tailPanel.add(actionsPanel, BorderLayout.EAST);
tailPanel.add(currencySetButton, BorderLayout.WEST);
return tailPanel;
}
private JPanel createTitlePane() {
JPanel titlePane = FRGUIPaneFactory.createBorderLayout_M_Pane();
titlePane.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, lineColor));
UILabel uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Carton_Carton_Journal_Record"));
uiLabel.setForeground(UIConstants.FLESH_BLUE);
titlePane.add(uiLabel, BorderLayout.WEST);
return titlePane;
}
private JPanel createMidPane() {
JPanel midPanel = FRGUIPaneFactory.createBorderLayout_L_Pane();
return midPanel;
}
/**
* 下面是通用设置的面板
*/
private void createGeneralSettingPanel() {
JPanel generalSettingPanel = FRGUIPaneFactory.createBorderLayout_L_Pane();
JPanel tailPaneInGeneralSettings = createTailPaneInGeneralSettings();
generalSettingPanel.add(tailPaneInGeneralSettings, BorderLayout.SOUTH);
JPanel titlePaneInGeneralSettings = createTitlePaneInGeneralSettings();
generalSettingPanel.add(titlePaneInGeneralSettings, BorderLayout.NORTH);
JPanel midPanel = FRGUIPaneFactory.createBorderLayout_L_Pane();
generalSettingPanel.add(midPanel, BorderLayout.CENTER);
JPanel infoPane = createInfoPanelInGeneralSettings();
midPanel.add(infoPane, BorderLayout.NORTH);
Dimension dimension = new Dimension(662, 556);
generalSettingPanel.setPreferredSize(dimension);
generalSettingPanel.setBackground(backgroundColor);
this.generalSettingPanel = generalSettingPanel;
}
private JPanel createTitlePaneInGeneralSettings() {
JPanel titlePane = FRGUIPaneFactory.createBorderLayout_L_Pane();
titlePane.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, lineColor));
UILabel uiLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Carton_Carton_Journal_Record") + "/");
uiLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
createBodyPanel();
remove(generalSettingPanel);
add(body);
setPreferredSize(body.getPreferredSize());
setSwitches(!StringUtils.isEmpty(GeneralUtils.objectToString(uiDatePicker.getSelectedItem())));
repaint();
setVisible(true);
}
@Override
public void mouseEntered(MouseEvent evt) {
Object source = evt.getSource();
if (source instanceof UILabel) {
((UILabel) source).setCursor(new Cursor(Cursor.HAND_CURSOR));
}
}
});
UILabel uiCurrentLabel = new UILabel(Toolkit.i18nText("Fine-Design_Basic_Carton_General_Settings"));
uiCurrentLabel.setForeground(UIConstants.FLESH_BLUE);
titlePane.add(GUICoreUtils.createFlowPane(new Component[]{uiLabel, uiCurrentLabel}, FlowLayout.LEFT));
return titlePane;
}
private JPanel createTailPaneInGeneralSettings() {
JPanel tailPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
tailPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, lineColor));
JPanel actionsPanel = FRGUIPaneFactory.createBorderLayout_S_Pane();
actionsPanel.setLayout(FRGUIPaneFactory.createM_BorderLayout());
{
UIButton confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Save"));
confirmButton.addActionListener((e) -> {
if (easyCheckerButton.isSelected()) {
SwitchForSwingChecker.startEasyChecker();
} else {
SwitchForSwingChecker.stopEasyChecker();
}
if (timerCheckerButton.isSelected()) {
SwitchForSwingChecker.startTimerChecker();
} else {
SwitchForSwingChecker.stopTimerChecker();
}
createBodyPanel();
remove(generalSettingPanel);
add(body);
setPreferredSize(body.getPreferredSize());
setSwitches(!StringUtils.isEmpty(GeneralUtils.objectToString(uiDatePicker.getSelectedItem())));
repaint();
setVisible(true);
});
actionsPanel.add(confirmButton, BorderLayout.WEST);
UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel"));
cancelButton.addActionListener((e) -> {
createBodyPanel();
remove(generalSettingPanel);
add(body);
setPreferredSize(body.getPreferredSize());
repaint();
setVisible(true);
});
actionsPanel.add(cancelButton, BorderLayout.EAST);
}
tailPanel.add(actionsPanel, BorderLayout.EAST);
return tailPanel;
}
private JPanel createInfoPanelInGeneralSettings() {
JPanel infoPane = FRGUIPaneFactory.createNColumnGridInnerContainer_S_Pane(1);
easyCheckerButton = new UICheckBox(Toolkit.i18nText("Fine-Design_Basic_Carton_Operation_Time_Consuming_Detection"));
timerCheckerButton = new UICheckBox(Toolkit.i18nText("Fine-Design_Basic_Carton_Carton_Operation_Class_Capture"));
easyCheckerButton.setSelected(SwitchForSwingChecker.isEasyChecker());
timerCheckerButton.setSelected(SwitchForSwingChecker.isCheckerTimerSwitch());
infoPane.add(GUICoreUtils.createFlowPane(easyCheckerButton, FlowLayout.LEFT));
infoPane.add(GUICoreUtils.createFlowPane(timerCheckerButton, FlowLayout.LEFT));
return infoPane;
}
@Override
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
EnvDetectorDialog envDetectorDialog = new EnvDetectorDialog(DesignerContext.getDesignerFrame());
envDetectorDialog.setVisible(true);
}
}
/**
* 上传和导出卡顿日志的可用化处理如果没有选择日期就不可用
*/
public void setSwitches(boolean flag) {
uploadButton.setEnabled(flag);
exportLogLabel.setEnabled(flag);
}
/**
* 导出卡顿日志到本地或远程服务器WEB-INF下
*
* @param sourceFile 导出的卡顿日志所在文件夹
* @param path 文件需要导出到的路径
* @param sourceFilePath 导出的卡顿日志所在文件夹的路径
*/
private void exportCartonLog(File sourceFile, String path, String sourceFilePath) {
File[] files = sourceFile.listFiles();
if (!Objects.isNull(files)) {
try {
if (path.startsWith(WORK_SPACE_PATH)) {
if (WorkContext.getCurrent().isLocal()) {
String curEnvName = DesignerEnvManager.getEnvManager().getCurEnvName();
DesignerWorkspaceInfo workspaceInfo = DesignerEnvManager.getEnvManager().getWorkspaceInfo(curEnvName);
String workspaceInfoPath = workspaceInfo.getPath();
path = StableUtils.pathJoin(workspaceInfoPath, path);
LogZipUtils.compress(files, path, false);
} else {
String sourceFilePathZip = sourceFilePath + ".zip";
LogZipUtils.compress(files, sourceFilePathZip, false);
byte[] bytesByFile = getBytesByFile(sourceFilePathZip);
WorkContext.getWorkResource().write(path, bytesByFile);
LogZipUtils.delDir(sourceFilePathZip);
}
} else {
LogZipUtils.compress(files, path, false);
}
FineJOptionPane.showMessageDialog(this, Toolkit.i18nText("Fine-Design_Report_Exported_Successfully"));
} catch (Exception exception) {
FineJOptionPane.showMessageDialog(this, Toolkit.i18nText("Fine-Design_Report_Export_Failed"), UIManager.getString("OptionPane.messageDialogTitle"), JOptionPane.ERROR_MESSAGE);
FineLoggerFactory.getLogger().error("export file fail", exception);
}
}
}
/**
* 根据文件地址将文件转换成byte[]
*
* @param pathStr 本地文件目录
* @return 本地文件转成的byte[]
*/
@Nullable
private static byte[] getBytesByFile(String pathStr) {
File file = new File(pathStr);
try {
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream(BUFFER_SIZE);
byte[] b = new byte[BUFFER_SIZE];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
fis.close();
byte[] data = bos.toByteArray();
bos.close();
return data;
} catch (Exception e) {
FineLoggerFactory.getLogger().error("reading local file fail", e);
}
return null;
}
}

36
designer-base/src/main/java/com/fr/design/carton/MonthlyCartonFile.java

@ -0,0 +1,36 @@
package com.fr.design.carton;
import java.io.File;
public class MonthlyCartonFile {
private File currentMonthFile;
private File lastMonthFile;
private File nextMonthFile;
public MonthlyCartonFile() {
}
public File getCurrentMonthFile() {
return currentMonthFile;
}
public void setCurrentMonthFile(File currentMonthFile) {
this.currentMonthFile = currentMonthFile;
}
public File getLastMonthFile() {
return lastMonthFile;
}
public void setLastMonthFile(File lastMonthFile) {
this.lastMonthFile = lastMonthFile;
}
public File getNextMonthFile() {
return nextMonthFile;
}
public void setNextMonthFile(File nextMonthFile) {
this.nextMonthFile = nextMonthFile;
}
}

312
designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java

@ -0,0 +1,312 @@
package com.fr.design.carton;
import com.fr.design.i18n.Toolkit;
import com.fr.general.GeneralUtils;
import com.fr.json.JSON;
import com.fr.json.JSONArray;
import com.fr.json.JSONObject;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.ProductConstantsBase;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import com.fr.stable.xml.XMLPrintWriter;
import com.fr.stable.xml.XMLReadable;
import com.fr.stable.xml.XMLWriter;
import com.fr.stable.xml.XMLableReader;
import sun.awt.AppContext;
import javax.swing.SwingWorker;
import java.io.IOException;
import java.io.File;
import java.io.BufferedReader;
import java.io.FileReader;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Date;
import java.util.Calendar;
public class SwitchForSwingChecker implements XMLReadable, XMLWriter {
/**
* Designer4Debug类名
*/
private static final String DEBUG_MAIN_CLASS_NAME = "com.fr.start.Designer4Debug";
/**
* XML标签
*/
public static final String XML_TAG = "SwitchForSwingChecker";
/**
* 定时任务的开关
*/
private static boolean checkerTimerSwitch = false;
/**
* 简单记录事件执行时间的开关
*/
private static boolean easyChecker = false;
/**
* 一个标识位用于区分耗时任务时长检测(简单检测)和timer检测
*/
public static final int TIMER_CHECK_FLAG = 0;
public static final int EASY_CHECK_FLAG = 1;
/**
* 日志存储地址
*/
public static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log");
public static final String EASY_CHECKER_FILE_NAME = "easy_check_log.csv";
public static final String TIMER_CHECKER_FILE_NAME = "timer_check_log.csv";
public static boolean isCheckerTimerSwitch() {
return checkerTimerSwitch;
}
public static boolean isEasyChecker() {
return easyChecker;
}
public static volatile SwitchForSwingChecker switchForSwingChecker = new SwitchForSwingChecker();
public static SwitchForSwingChecker getInstance() {
return switchForSwingChecker;
}
public static void startTimerChecker() {
if (!checkerTimerSwitch) {
EventDispatchThreadHangMonitor.INSTANCE.initTimer();
CartonThreadExecutorPool.getTimerThreadExecutorPool().initTimer();
EventDispatchThreadHangMonitor.INSTANCE.setTimerWitch(true);
checkerTimerSwitch = true;
if (!easyChecker) {
EventDispatchThreadHangMonitor.INSTANCE.startFilterModalWindow();
}
}
}
public static void stopTimerChecker() {
if (checkerTimerSwitch) {
EventDispatchThreadHangMonitor.INSTANCE.stopTimer();
CartonThreadExecutorPool.getTimerThreadExecutorPool().stopTimer();
EventDispatchThreadHangMonitor.INSTANCE.setTimerWitch(false);
checkerTimerSwitch = false;
if (!easyChecker) {
EventDispatchThreadHangMonitor.INSTANCE.stopFilterModalWindow();
}
}
}
public static void startEasyChecker() {
if (!easyChecker) {
EventDispatchThreadHangMonitor.INSTANCE.setEasyWitch(true);
CartonThreadExecutorPool.getTimerThreadExecutorPool().setEasyWitch(true);
easyChecker = true;
if (!checkerTimerSwitch) {
EventDispatchThreadHangMonitor.INSTANCE.startFilterModalWindow();
}
}
}
public static void stopEasyChecker() {
if (easyChecker) {
EventDispatchThreadHangMonitor.INSTANCE.setEasyWitch(false);
CartonThreadExecutorPool.getTimerThreadExecutorPool().setEasyWitch(false);
easyChecker = false;
if (!checkerTimerSwitch) {
EventDispatchThreadHangMonitor.INSTANCE.stopFilterModalWindow();
}
}
}
/**
* 获取文件名字以及判断文件是否存在
*/
private static CartonFiles getFiles(String date) {
String[] split = date.split("-");
int month = StringUtils.isEmpty(split[1]) ? -1 : Integer.parseInt(split[1]);
String dirPath = StableUtils.pathJoin(JOURNAL_FILE_PATH, split[0], "month-" + month, date);
File file1 = new File(StableUtils.pathJoin(dirPath, EASY_CHECKER_FILE_NAME));
File file2 = new File(StableUtils.pathJoin(dirPath, TIMER_CHECKER_FILE_NAME));
File[] files = new File[2];
files[0] = file1;
files[1] = file2;
CartonFiles cartonFiles = new CartonFiles();
cartonFiles.setEasyCheckerFile(file1);
cartonFiles.setTimerCheckerFile(file2);
return cartonFiles;
}
/**
*处理文件
* 一共四种情况
* 两个文件都不存在
* 文件一存在文件二不存在
* 文件二存在文件一不存在
* 两个文件都存在
*/
private static List<CartonUploadMessage> getCartonLog(File easyFile, File timerFile) {
List<CartonUploadMessage> res = new ArrayList<>();
List<CartonUploadMessage> easyFileCartonLog = getEasyFileCartonLog(easyFile);
List<CartonUploadMessage> timerFileCartonLog = getTimerFileCartonLog(timerFile);
Map<String, CartonUploadMessage> easyFileMap = new HashMap<>();
for (CartonUploadMessage cartonUploadMessage : easyFileCartonLog) {
easyFileMap.put(cartonUploadMessage.getHangCount(), cartonUploadMessage);
res.add(cartonUploadMessage);
}
for (CartonUploadMessage cartonUploadMessage : timerFileCartonLog) {
String hangCount = cartonUploadMessage.getHangCount();
if (easyFileMap.containsKey(hangCount)) {
cartonUploadMessage.setThreadTime(easyFileMap.get(hangCount).getThreadTime());
}
res.add(cartonUploadMessage);
}
return res;
}
private static List<CartonUploadMessage> getTimerFileCartonLog(File file) {
List<CartonUploadMessage> res = new ArrayList<>();
try {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[");
BufferedReader bufferedReader1 = new BufferedReader(new FileReader(file));
String line1;
while ((line1 = bufferedReader1.readLine()) != null) {
stringBuilder.append(line1);
}
bufferedReader1.close();
stringBuilder.append("]");
JSONArray easyCheckerJSON = JSON.ARRAY.createJSON(GeneralUtils.objectToString(stringBuilder));
for (Object jsonObject : easyCheckerJSON) {
CartonUploadMessage cartonUploadMessage = new CartonUploadMessage();
JSONObject x = (JSONObject) jsonObject;
cartonUploadMessage.setHangCount(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number")));
cartonUploadMessage.setSlowTime(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time")));
cartonUploadMessage.setThreadTime("undefined");
//这个跟输出到文件中的格式匹配,参考EventDis里的stackTraceToString方法
String indentation = " ";
String logMessage = x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Stack_Info")).replaceAll(indentation, "\r\n ");
cartonUploadMessage.setInfo(logMessage);
res.add(cartonUploadMessage);
}
} catch (IOException e) {
FineLoggerFactory.getLogger().error("upload fail", e);
}
return res;
}
private static List<CartonUploadMessage> getEasyFileCartonLog(File file) {
List<CartonUploadMessage> res = new ArrayList<>();
try {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[");
BufferedReader bufferedReader1 = new BufferedReader(new FileReader(file));
String line1;
while ((line1 = bufferedReader1.readLine()) != null) {
stringBuilder.append(line1);
}
bufferedReader1.close();
stringBuilder.append("]");
JSONArray timerCheckerJSON = JSON.ARRAY.createJSON(GeneralUtils.objectToString(stringBuilder));
for (Object jsonObject : timerCheckerJSON) {
JSONObject x = (JSONObject) jsonObject;
CartonUploadMessage cartonUploadMessage = new CartonUploadMessage();
cartonUploadMessage.setHangCount(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Event_Number")));
cartonUploadMessage.setSlowTime(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Output_Time")));
cartonUploadMessage.setThreadTime(x.getString(Toolkit.i18nText("Fine-Design_Basic_Carton_Task_Total_Time")));
cartonUploadMessage.setInfo("undefined");
res.add(cartonUploadMessage);
}
} catch (IOException e) {
FineLoggerFactory.getLogger().error("upload fail", e);
}
return res;
}
/**
* /埋点方法上传卡顿信息入口
date为 2022-09-08的格式
*/
public static List<CartonUploadMessage> uploadJournalLog(Date dateTime) {
List<CartonUploadMessage> res = new ArrayList<>();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
CartonFiles files = getFiles(simpleDateFormat.format(dateTime));
File easyCheckerFile = files.getEasyCheckerFile();
File timerCheckerFile = files.getTimerCheckerFile();
if (easyCheckerFile.exists() && timerCheckerFile.exists()) {
return getCartonLog(easyCheckerFile, timerCheckerFile);
} else if (easyCheckerFile.exists()) {
return getEasyFileCartonLog(easyCheckerFile);
} else if (timerCheckerFile.exists()) {
return getTimerFileCartonLog(timerCheckerFile);
} else {
return res;
}
}
/**
* 初始化监控任务主要是替换EventQueue以及SwingWorker执行任务的线程池
*
*/
public static void initThreadMonitoring () {
String mainClass = System.getProperty("sun.java.command");
//判断一下,如果是以Designer4Debug启动,就不注册代码,不然会覆盖掉SwingExplorer,导致其无法使用
if (!StringUtils.equals(mainClass, DEBUG_MAIN_CLASS_NAME)) {
EventDispatchThreadHangMonitor.initMonitoring();
AppContext.getAppContext().put(SwingWorker.class, CartonThreadExecutorPool.getTimerThreadExecutorPool());
}
}
/**
* 判断是否有指定日期的卡顿日志没有就返回false
*/
public static boolean isCartonExists(Date date) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
String format = simpleDateFormat.format(date);
Calendar calendar = Calendar.getInstance();
int month = calendar.get(Calendar.MONTH) + 1;
int year = calendar.get(Calendar.YEAR);
File file = new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, String.valueOf(year), "month-" + month, format));
return file.exists();
}
public static boolean isCartonExists() {
return isCartonExists(new Date());
}
private void initSwitchChecker() {
if (easyChecker) {
EventDispatchThreadHangMonitor.INSTANCE.setEasyWitch(true);
CartonThreadExecutorPool.getTimerThreadExecutorPool().setEasyWitch(true);
}
if (checkerTimerSwitch) {
EventDispatchThreadHangMonitor.INSTANCE.initTimer();
CartonThreadExecutorPool.getTimerThreadExecutorPool().initTimer();
EventDispatchThreadHangMonitor.INSTANCE.setTimerWitch(true);
}
if (easyChecker || checkerTimerSwitch) {
EventDispatchThreadHangMonitor.INSTANCE.startFilterModalWindow();
}
}
@Override
public void readXML(XMLableReader reader) {
if (reader.isAttr()) {
checkerTimerSwitch = reader.getAttrAsBoolean("checkerTimerSwitch", false);
easyChecker = reader.getAttrAsBoolean("easyChecker", false);
}
try {
initSwitchChecker();
} catch (Throwable t) {
FineLoggerFactory.getLogger().error("read checker attr fail", t);
}
}
@Override
public void writeXML(XMLPrintWriter writer) {
writer.startTAG(XML_TAG);
writer.attr("checkerTimerSwitch", checkerTimerSwitch);
writer.attr("easyChecker", easyChecker);
writer.end();
}
}

4
designer-base/src/main/java/com/fr/design/components/tooltip/ModernToolTip.java

@ -12,11 +12,9 @@ import javax.swing.plaf.ToolTipUI;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.GeneralPath;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
@ -52,7 +50,7 @@ public class ModernToolTip extends UIToolTip {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(new Color(51, 51, 52, (int) Math.round(0.7 * 255)));
g2.fillRoundRect(0, 0, width, height, 0, 0);
g2.fillRoundRect(0, 0, width, height, 4, 4);
g2.setColor(Color.WHITE);
if (strs != null) {

25
designer-base/src/main/java/com/fr/design/data/BasicTableDataTreePane.java

@ -2,9 +2,8 @@ package com.fr.design.data;
import com.fr.base.BaseUtils;
import com.fr.base.TableData;
import com.fr.data.MultiResultTableData;
import com.fr.data.TableDataSource;
import com.fr.data.api.StoreProcedureAssist;
import com.fr.data.impl.storeproc.StoreProcedure;
import com.fr.design.DesignModelAdapter;
import com.fr.design.actions.UpdateAction;
import com.fr.design.data.datapane.TableDataCreatorProducer;
@ -13,7 +12,7 @@ import com.fr.design.data.datapane.TableDataSourceOP;
import com.fr.design.data.datapane.TableDataTree;
import com.fr.design.data.tabledata.ResponseDataSourceChange;
import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane;
import com.fr.design.data.tabledata.wrapper.StoreProcedureDataWrapper;
import com.fr.design.data.tabledata.wrapper.MultiResultTableDataWrapper;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper;
import com.fr.design.dialog.BasicDialog;
@ -184,7 +183,7 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp
private boolean isIncludeUnderline(String name) {
return ComparatorUtils.equals(name.indexOf(StoreProcedureAssist.GROUP_MARKER), -1) ? false : true;
return ComparatorUtils.equals(name.indexOf(MultiResultTableData.GROUP_MARKER), -1) ? false : true;
}
public abstract void addDataPane(final AbstractTableDataPane<?> uPanel, String paneName);
@ -441,16 +440,16 @@ public abstract class BasicTableDataTreePane extends DockingView implements Resp
data = selectedNO.getObject();
}
try {
if (((TableDataWrapper) Objects.requireNonNull(data)).getTableData() instanceof StoreProcedure) {
((StoreProcedure) (((TableDataWrapper) data).getTableData())).resetDataModelList();
if (data instanceof StoreProcedureDataWrapper) {
StoreProcedureDataWrapper oldSdw = ((StoreProcedureDataWrapper) data);
StoreProcedureDataWrapper newSdw = new StoreProcedureDataWrapper((StoreProcedure) oldSdw.getTableData(), oldSdw.getStoreprocedureName(), oldSdw.getTableDataName());
newSdw.previewData(StoreProcedureDataWrapper.PREVIEW_ONE);
if (((TableDataWrapper) Objects.requireNonNull(data)).getTableData() instanceof MultiResultTableData) {
((MultiResultTableData<?>) (((TableDataWrapper) data).getTableData())).resetDataModelList();
if (data instanceof MultiResultTableDataWrapper) {
MultiResultTableDataWrapper oldSdw = ((MultiResultTableDataWrapper) data);
MultiResultTableDataWrapper newSdw = new MultiResultTableDataWrapper((MultiResultTableData<?>) oldSdw.getTableData(), oldSdw.getMultiResultTableDataName(), oldSdw.getTableDataName());
newSdw.previewData(MultiResultTableDataWrapper.PREVIEW_ONE);
} else {
StoreProcedure storeProcedure = (StoreProcedure) ((TableDataWrapper) data).getTableData();
StoreProcedureDataWrapper storeProcedureDataWrapper = new StoreProcedureDataWrapper(storeProcedure, StringUtils.EMPTY, StringUtils.EMPTY);
storeProcedureDataWrapper.previewData(StoreProcedureDataWrapper.PREVIEW_ALL);
MultiResultTableData<?> tableData = (MultiResultTableData<?>) ((TableDataWrapper) data).getTableData();
MultiResultTableDataWrapper storeProcedureDataWrapper = new MultiResultTableDataWrapper(tableData, StringUtils.EMPTY, StringUtils.EMPTY);
storeProcedureDataWrapper.previewData(MultiResultTableDataWrapper.PREVIEW_ALL);
}
} else {
((TableDataWrapper) data).previewData();

102
designer-base/src/main/java/com/fr/design/data/DesignTableDataManager.java

@ -3,19 +3,22 @@ package com.fr.design.data;
import com.fr.base.StoreProcedureParameter;
import com.fr.base.TableData;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.data.MultiResultTableData;
import com.fr.data.TableDataSource;
import com.fr.data.TableDataSourceTailor;
import com.fr.data.core.DataCoreXmlUtils;
import com.fr.data.impl.EmbeddedTableData;
import com.fr.data.impl.NameDataModel;
import com.fr.data.impl.storeproc.ProcedureDataModel;
import com.fr.data.impl.storeproc.StoreProcedure;
import com.fr.data.impl.storeproc.StoreProcedureConstants;
import com.fr.data.impl.storeproc.StoreProcedureHelper;
import com.fr.data.operator.DataOperator;
import com.fr.design.DesignModelAdapter;
import com.fr.design.data.datapane.preview.PreviewTablePane;
import com.fr.design.data.tabledata.wrapper.MultiResultTableDataNameWrapper;
import com.fr.design.data.tabledata.wrapper.MultiResultTableDataWrapper;
import com.fr.design.data.tabledata.wrapper.ServerTableDataWrapper;
import com.fr.design.data.tabledata.wrapper.StoreProcedureDataWrapper;
import com.fr.design.data.tabledata.wrapper.StoreProcedureNameWrapper;
import com.fr.design.data.tabledata.wrapper.TableDataFactory;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.design.data.tabledata.wrapper.TemplateTableDataWrapper;
@ -188,7 +191,7 @@ public abstract class DesignTableDataManager {
public static void addDsChangeListener(ChangeListener l) {
JTemplate<?, ?> template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
String key = StringUtils.EMPTY;
if (template != null) {
if (JTemplate.isValid(template)) {
key = template.getPath();
}
List<ChangeListener> dsListeners = dsListenersMap.get(key);
@ -321,33 +324,44 @@ public abstract class DesignTableDataManager {
public static java.util.Map<String, TableDataWrapper> getAllDataSetIncludingProcedure(java.util.Map<String, TableDataWrapper> resMap) {
java.util.LinkedHashMap<String, TableDataWrapper> dsMap = new java.util.LinkedHashMap<String, TableDataWrapper>();
Iterator<Entry<String, TableDataWrapper>> entryIt = resMap.entrySet().iterator();
while (entryIt.hasNext()) {
String key = entryIt.next().getKey();
for (Entry<String, TableDataWrapper> entry : resMap.entrySet()) {
String key = entry.getKey();
TableDataWrapper tableDataWrapper = resMap.get(key);
if (tableDataWrapper.getTableData() instanceof StoreProcedure) {
StoreProcedure storeProcedure = (StoreProcedure) tableDataWrapper.getTableData();
boolean hasSchemaOrResult = false;
StoreProcedureParameter[] parameters = StoreProcedure.getSortPara(storeProcedure.getParameters());
if (tableDataWrapper.getTableData() instanceof MultiResultTableData) {
MultiResultTableData<?> tableData = (MultiResultTableData<?>) tableDataWrapper.getTableData();
String name = tableDataWrapper.getTableDataName();
List<String> resultNames = storeProcedure.getResultNames();
TableDataWrapper tdw = new StoreProcedureNameWrapper(name + "_Table", storeProcedure);
for (StoreProcedureParameter parameter : parameters) {
if (parameter.getSchema() != StoreProcedureConstants.IN) {
String parameterName = name + "_" + parameter.getName();
TableDataWrapper newTwd = new StoreProcedureDataWrapper(storeProcedure, name, parameterName, false);
dsMap.put(parameterName, newTwd);
hasSchemaOrResult = true;
List<String> resultNames = tableData.getResultNames();
TableDataWrapper tdw = new MultiResultTableDataNameWrapper(name + "_Table", tableData);
boolean hasSchemaOrResult = false;
// 存储过程的特殊处理,还有其它名称
if (tableData instanceof StoreProcedure) {
StoreProcedure storeProcedure = (StoreProcedure) tableData;
StoreProcedureParameter[] parameters = StoreProcedureHelper.getSortPara(storeProcedure.getParameters());
for (StoreProcedureParameter parameter : parameters) {
if (parameter.getSchema() != StoreProcedureConstants.IN) {
String parameterName = name + "_" + parameter.getName();
TableDataWrapper newTwd = new MultiResultTableDataWrapper(storeProcedure, name, parameterName, false);
dsMap.put(parameterName, newTwd);
hasSchemaOrResult = true;
}
}
}
} /*else {
// TODO getDataModelList是空的
for (String n : tableData.getResultNames()) {
String dmName = name + "_" + n;
dsMap.put(n, new MultiResultTableDataWrapper(tableData, name, dmName, false));
}
}*/
if (!resultNames.isEmpty()) {
hasSchemaOrResult = true;
for (int i = 0; i < resultNames.size(); i++) {
String parameterName = name + "_" + resultNames.get(i);
TableDataWrapper newTwd = new StoreProcedureDataWrapper(storeProcedure, name, parameterName, false);
dsMap.put(parameterName, newTwd);
for (String resultName : resultNames) {
String dmName = name + "_" + resultName;
TableDataWrapper newTwd = new MultiResultTableDataWrapper(tableData, name, dmName, false);
dsMap.put(dmName, newTwd);
}
}
@ -429,7 +443,7 @@ public abstract class DesignTableDataManager {
if (globalDsCache.containsKey(name)) {
resMap.put(name, globalDsCache.get(name));
} else {
TableDataWrapper tdw = new StoreProcedureNameWrapper(name, storeProcedure);
TableDataWrapper tdw = new MultiResultTableDataNameWrapper(name, storeProcedure);
resMap.put(name, tdw);
globalDsCache.put(name, tdw);
}
@ -599,29 +613,35 @@ public abstract class DesignTableDataManager {
* 所以用该方法不会对一个已经计算了的存储过程重复计算.和分页预览时处理机制一样这样对有多个返回数据集的存储过程来说很有必要
*
* @param needLoadingBar 是否需要进度条
* @param storeProcedure 存储过程
* @param tableData 存储过程
* @return 数据
*/
public static ProcedureDataModel[] createLazyDataModel(StoreProcedure storeProcedure, boolean needLoadingBar) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
XMLPrintWriter writer = XMLPrintWriter.create(out);
// 把storeProcedure写成xml文件到out
DataCoreXmlUtils.writeXMLStoreProcedure(writer, storeProcedure, null);
if (storeProcedure.getDataModelSize() > 0 && !storeProcedure.isFirstExpand()) {
return storeProcedure.creatLazyDataModel();
}
ParameterProvider[] inParameters = DataOperator.getInstance().getStoreProcedureParameters(storeProcedure);
public static NameDataModel[] createLazyDataModel(MultiResultTableData<?> tableData, boolean needLoadingBar) throws Exception {
Map<String, Object> parameterMap = new HashMap<>();
if (inParameters.length > 0 && !ComparatorUtils.equals(threadLocal.get(), NO_PARAMETER)) {// 检查Parameter.
showParaWindow(parameterMap, inParameters);
if (tableData instanceof StoreProcedure) {
StoreProcedure storeProcedure = (StoreProcedure) tableData;
ByteArrayOutputStream out = new ByteArrayOutputStream();
XMLPrintWriter writer = XMLPrintWriter.create(out);
// 把storeProcedure写成xml文件到out
DataCoreXmlUtils.writeXMLStoreProcedure(writer, storeProcedure, null);
if (storeProcedure.getDataModelList().size() > 0 && !storeProcedure.isFirstExpand()) {
return storeProcedure.getDataModelList().toArray(new ProcedureDataModel[0]);
}
ParameterProvider[] inParameters = DataOperator.getInstance().getStoreProcedureParameters(storeProcedure);
if (inParameters.length > 0 && !ComparatorUtils.equals(threadLocal.get(), NO_PARAMETER)) {// 检查Parameter.
showParaWindow(parameterMap, inParameters);
}
storeProcedure.setFirstExpand(false);
}
storeProcedure.setFirstExpand(false);
// 存储过程有些特殊处理
// 这个就简单直接获取暂存列表吧
// TODO 参数处理?
if (needLoadingBar) {
StoreProcedureDataWrapper.loadingBar.start();
MultiResultTableDataWrapper.loadingBar.start();
}
return DataOperator.getInstance().previewProcedureDataModel(storeProcedure, parameterMap, 0);
return DataOperator.getInstance().previewMultiResultTableData(tableData, parameterMap, 0);
}
private static void showParaWindow(final Map<String, Object> parameterMap, ParameterProvider[] inParameters) {

9
designer-base/src/main/java/com/fr/design/data/datapane/TableDataPaneListPane.java

@ -3,9 +3,8 @@ package com.fr.design.data.datapane;
import com.fr.base.TableData;
import com.fr.base.TableDataBean;
import com.fr.config.RemoteConfigEvent;
import com.fr.data.MultiResultTableData;
import com.fr.data.TableDataSource;
import com.fr.data.api.StoreProcedureAssist;
import com.fr.data.impl.storeproc.StoreProcedure;
import com.fr.design.data.BasicTableDataUtils;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.dialog.FineJOptionPane;
@ -69,10 +68,10 @@ public class TableDataPaneListPane extends JListControlPane implements TableData
return;
}
if (editingType instanceof StoreProcedure && isIncludeUnderline(tempName)) {
if (editingType instanceof MultiResultTableData<?> && isIncludeUnderline(tempName)) {
isNamePermitted = false;
nameableList.stopEditing();
FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(TableDataPaneListPane.this), Toolkit.i18nText("Fine-Design_Basic_Stored_Procedure_Name_Tips"));
FineJOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(TableDataPaneListPane.this), Toolkit.i18nText("Fine-Design_Basic_Multi_Result_Table_Data_Name_Tips"));
setIllegalIndex(editingIndex);
return;
}
@ -137,7 +136,7 @@ public class TableDataPaneListPane extends JListControlPane implements TableData
}
private boolean isIncludeUnderline(String name) {
return name.contains(StoreProcedureAssist.GROUP_MARKER);
return name.contains(MultiResultTableData.GROUP_MARKER);
}
/**

75
designer-base/src/main/java/com/fr/design/data/datapane/TableDataSourceOP.java

@ -2,20 +2,25 @@ package com.fr.design.data.datapane;
import com.fr.base.StoreProcedureParameter;
import com.fr.base.TableData;
import com.fr.data.MultiResultTableData;
import com.fr.data.TableDataSource;
import com.fr.data.impl.storeproc.StoreProcedure;
import com.fr.data.impl.storeproc.StoreProcedureConstants;
import com.fr.data.impl.storeproc.StoreProcedureHelper;
import com.fr.design.DesignModelAdapter;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.tabledata.wrapper.StoreProcedureDataWrapper;
import com.fr.design.data.tabledata.wrapper.StoreProcedureNameWrapper;
import com.fr.design.data.tabledata.wrapper.MultiResultTableDataNameWrapper;
import com.fr.design.data.tabledata.wrapper.MultiResultTableDataWrapper;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.gui.itree.refreshabletree.UserObjectOP;
import com.fr.general.NameObject;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
@ -155,9 +160,9 @@ public class TableDataSourceOP implements UserObjectOP<TableDataWrapper> {
list.add(initStoreProcedureNode(storeProcedureMap));
for (int i = 0; i < getNodeArrayFromMap(storeProcedureMap).length; i++) {
ExpandMutableTreeNode tmpNode = getNodeArrayFromMap(storeProcedureMap)[i];
if (((NameObject) tmpNode.getUserObject()).getObject() instanceof StoreProcedureNameWrapper) {
TableData tableData = ((StoreProcedureNameWrapper) (((NameObject) tmpNode.getUserObject()).getObject())).getStoreProcedure();
setStoreProcedureTree(tableData, tmpNode);
if (((NameObject) tmpNode.getUserObject()).getObject() instanceof MultiResultTableDataNameWrapper) {
TableData tableData = ((MultiResultTableDataNameWrapper) (((NameObject) tmpNode.getUserObject()).getObject())).getTableData();
setStoreProcedureTree((MultiResultTableData<?>) tableData, tmpNode);
serverlist.add(tmpNode);
}
}
@ -176,8 +181,8 @@ public class TableDataSourceOP implements UserObjectOP<TableDataWrapper> {
for (int i = 0; i < getNodeArrayFromMap(dataMap).length; i++) {
ExpandMutableTreeNode tmpNode = getNodeArrayFromMap(dataMap)[i];
TableData tableData = ((TableDataWrapper) (((NameObject) tmpNode.getUserObject()).getObject())).getTableData();
if (tableData instanceof StoreProcedure) {
setStoreProcedureTree(tableData, tmpNode);
if (tableData instanceof MultiResultTableData<?>) {
setStoreProcedureTree((MultiResultTableData<?>) tableData, tmpNode);
dataList.add(tmpNode);
} else {
dataList.add(tmpNode);
@ -185,31 +190,49 @@ public class TableDataSourceOP implements UserObjectOP<TableDataWrapper> {
}
}
protected void setStoreProcedureTree(TableData tableData, ExpandMutableTreeNode tmpNode) {
protected void setStoreProcedureTree(MultiResultTableData<?> tableData, ExpandMutableTreeNode tmpNode) {
ArrayList<String> nodeName = new ArrayList<>();
StoreProcedure storeProcedure = (StoreProcedure) tableData;
String name = ((NameObject) tmpNode.getUserObject()).getName();
StoreProcedureParameter[] parameters = StoreProcedure.getSortPara(storeProcedure.getParameters());
List<String> resultNames = storeProcedure.getResultNames();
List<String> resultNames = tableData.getResultNames();
boolean hasChild = false;
tmpNode.remove(0);
TableDataWrapper tdw = new StoreProcedureNameWrapper(name + "_Table1", storeProcedure);
TableDataWrapper tdw = new MultiResultTableDataNameWrapper(name + "_Table1", tableData);
ExpandMutableTreeNode childNode = new ExpandMutableTreeNode(new NameObject("Table", tdw));
childNode.add(new ExpandMutableTreeNode());
tmpNode.add(childNode);
for (StoreProcedureParameter parameter : parameters) {
if (parameter.getSchema() != StoreProcedureConstants.IN) {
if (!nodeName.contains(parameter.getName())) {
nodeName.add(parameter.getName());
hasChild = true;
String parameterName = name + "_" + parameter.getName();
TableDataWrapper newTwd = new StoreProcedureDataWrapper(storeProcedure, name, parameterName, false);
ExpandMutableTreeNode newChildNode = new ExpandMutableTreeNode(new NameObject(parameter.getName(), newTwd));
newChildNode.add(new ExpandMutableTreeNode());
tmpNode.add(newChildNode);
if (tableData instanceof StoreProcedure) {
StoreProcedure storeProcedure = (StoreProcedure) tableData;
StoreProcedureParameter[] parameters = StoreProcedureHelper.getSortPara(storeProcedure.getParameters());
for (StoreProcedureParameter parameter : parameters) {
if (parameter.getSchema() != StoreProcedureConstants.IN) {
if (!nodeName.contains(parameter.getName())) {
nodeName.add(parameter.getName());
hasChild = true;
String parameterName = name + "_" + parameter.getName();
TableDataWrapper newTwd = new MultiResultTableDataWrapper(tableData, name, parameterName, false);
ExpandMutableTreeNode newChildNode = new ExpandMutableTreeNode(new NameObject(parameter.getName(), newTwd));
newChildNode.add(new ExpandMutableTreeNode());
tmpNode.add(newChildNode);
}
}
}
}
} /*else {
if (tableData.getDataModelList().size() > 1) {
for (NameDataModel nameDataModel : tableData.getDataModelList()) {
if (!nodeName.contains(nameDataModel.getName())) {
nodeName.add(nameDataModel.getName());
hasChild = true;
String parameterName = name + "_" + nameDataModel.getName();
TableDataWrapper newTwd = new MultiResultTableDataWrapper(tableData, name, parameterName, false);
ExpandMutableTreeNode newChildNode = new ExpandMutableTreeNode(new NameObject(nameDataModel.getName(), newTwd));
newChildNode.add(new ExpandMutableTreeNode());
tmpNode.add(newChildNode);
}
}
}
}*/
if (!resultNames.isEmpty()) {
for (String resultName : resultNames) {
@ -217,7 +240,7 @@ public class TableDataSourceOP implements UserObjectOP<TableDataWrapper> {
nodeName.add(resultName);
hasChild = true;
String parameterName = name + "_" + resultName;
TableDataWrapper newTwd = new StoreProcedureDataWrapper(storeProcedure, name, parameterName, false);
TableDataWrapper newTwd = new MultiResultTableDataWrapper(tableData, name, parameterName, false);
ExpandMutableTreeNode newChildNode = new ExpandMutableTreeNode(new NameObject(resultName, newTwd));
newChildNode.add(new ExpandMutableTreeNode());
tmpNode.add(newChildNode);

6
designer-base/src/main/java/com/fr/design/data/datapane/TableDataTree.java

@ -1,7 +1,7 @@
package com.fr.design.data.datapane;
import com.fr.base.BaseUtils;
import com.fr.data.impl.storeproc.StoreProcedure;
import com.fr.data.MultiResultTableData;
import com.fr.design.constants.UIConstants;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.tabledata.wrapper.AbstractTableDataWrapper;
@ -379,7 +379,7 @@ public class TableDataTree extends UserObjectRefreshJTree<TableDataSourceOP> {
return false;
}
Object userObject = treeNode.getUserObject();
if (userObject instanceof NameObject && ((NameObject) userObject).getObject() instanceof AbstractTableDataWrapper) {
if (userObject instanceof NameObject && ((NameObject) userObject).getObject() instanceof TableDataWrapper) {
return true;
}
return false;
@ -462,7 +462,7 @@ public class TableDataTree extends UserObjectRefreshJTree<TableDataSourceOP> {
if (userObject instanceof NameObject) {
NameObject nameObject = (NameObject) userObject;
TableDataWrapper tableDataWrapper = (TableDataWrapper) nameObject.getObject();
return tableDataWrapper.getTableData() instanceof StoreProcedure;
return tableDataWrapper.getTableData() instanceof MultiResultTableData<?>;
}
return false;
}

34
designer-base/src/main/java/com/fr/design/data/datapane/TableDataTreePane.java

@ -1,6 +1,7 @@
package com.fr.design.data.datapane;
import com.fr.base.TableData;
import com.fr.data.MultiResultTableData;
import com.fr.data.TableDataSource;
import com.fr.data.impl.DBTableData;
import com.fr.data.impl.TableDataSourceDependent;
@ -15,10 +16,10 @@ import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.StrategyConfigAttrUtils;
import com.fr.design.data.datapane.auth.TableDataAuthHelper;
import com.fr.design.data.datapane.management.clip.TableDataTreeClipboard;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.datapane.management.search.pane.TableDataSearchRemindPane;
import com.fr.design.data.datapane.management.search.pane.TreeSearchToolbarPane;
import com.fr.design.data.datapane.management.search.searcher.TableDataSearchMode;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.tabledata.StoreProcedureWorkerListener;
import com.fr.design.data.tabledata.paste.TableDataFollowingPasteUtils;
import com.fr.design.data.tabledata.tabledatapane.AbstractTableDataPane;
@ -121,6 +122,7 @@ public class TableDataTreePane extends BasicTableDataTreePane {
/**
* 获取不必每次都refreshDockingView的数据集树面板
* 不会主动替换DesignModelAdapter需要保证使用时没有跨模板动作谨慎使用
*
* @param tc
* @return
*/
@ -484,7 +486,7 @@ public class TableDataTreePane extends BasicTableDataTreePane {
tdNamePanel.addPropertyChangeListener(new PropertyChangeAdapter() {
@Override
public void propertyChange() {
doPropertyChange(dg, tdNamePanel, oldName);
checkNameChange(tableDataPane, dg, tdNamePanel, oldName);
}
});
// 有些数据集(DBTableData)面板的初始化过程中是包含了SwingWorker处理(查询数据连接、查表等)的
@ -494,6 +496,34 @@ public class TableDataTreePane extends BasicTableDataTreePane {
});
}
private void checkNameChange(AbstractTableDataPane<?> tableDataPane, BasicDialog dg, BasicPane.NamePane nPanel, final String oldName) {
nPanel.setShowText(StringUtils.BLANK);
dg.setButtonEnabled(true);
String tempName = nPanel.getObjectName();
if (StringUtils.isBlank(tempName)) {
nPanel.setShowText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Table_Data_Empty_Name_Tips"));
dg.setButtonEnabled(false);
} else if (!ComparatorUtils.equals(oldName, tempName) && isDsNameRepeaded(tempName)) {
nPanel.setShowText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Table_Data_Duplicate_Name_Tips", tempName));
dg.setButtonEnabled(false);
} else if (oldName.length() >= PROCEDURE_NAME_INDEX && tableDataPane.updateBean() instanceof MultiResultTableData) {
if (isIncludeUnderline(tempName)) {
nPanel.setShowText(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Multi_Result_Table_Data_Name_Tips"));
dg.setButtonEnabled(false);
}
} else if (!BasicTableDataUtils.checkName(tempName)) {
dg.setButtonEnabled(false);
} else {
nPanel.setShowText(StringUtils.BLANK);
dg.setButtonEnabled(true);
}
}
private boolean isIncludeUnderline(String name) {
return !ComparatorUtils.equals(name.indexOf(MultiResultTableData.GROUP_MARKER), -1);
}
@Override
public void removeTableData(String sourceName) {
TableDataSource tds = this.tc.getBook();

3
designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionListPane.java

@ -1,6 +1,7 @@
package com.fr.design.data.datapane.connect;
import com.fr.config.RemoteConfigEvent;
import com.fr.data.driver.DriverClassNotFoundException;
import com.fr.data.impl.Connection;
import com.fr.data.impl.ConnectionBean;
import com.fr.data.impl.JDBCDatabaseConnection;
@ -231,6 +232,8 @@ public class ConnectionListPane extends JListControlPane implements ConnectionSh
Connection connection = connectionBean.getConnection();
try {
DataOperator.getInstance().validateConnectionSettings(connection);
} catch (DriverClassNotFoundException e) {
FineLoggerFactory.getLogger().info(e.getMessage());
} catch (Exception e) {
throw new SQLException(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Invalid_Config", connectionBean.getName()) + ", " + e.getMessage(), e.getCause());
}

1
designer-base/src/main/java/com/fr/design/data/datapane/connect/ConnectionManagerPane.java

@ -4,6 +4,7 @@ import com.fr.design.gui.frpane.LoadingBasicPane;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.file.ConnectionConfig;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.util.HashMap;

10
designer-base/src/main/java/com/fr/design/data/datapane/management/search/TableDataTreeSearchManager.java

@ -4,12 +4,12 @@ import com.fr.data.TableDataSource;
import com.fr.design.DesignModelAdapter;
import com.fr.design.data.datapane.TableDataTree;
import com.fr.design.data.datapane.TableDataTreePane;
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeListener;
import com.fr.design.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.search.event.TreeSearchStatusChangeListener;
import com.fr.design.data.datapane.management.search.searcher.TableDataSearchMode;
import com.fr.design.data.datapane.management.search.searcher.TableDataTreeSearcher;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
import com.fr.design.data.datapane.management.search.view.TreeSearchRendererHelper;
import com.fr.design.search.TreeSearchStatus;
import com.fr.design.search.view.TreeSearchRendererHelper;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
@ -101,7 +101,7 @@ public class TableDataTreeSearchManager {
public void switchToSearch(TableDataSearchMode searchMode, TableDataSource tableDataSource) {
setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN);
rendererHelper = new TreeSearchRendererHelper();
rendererHelper.save(getCurrentTableDataTree());
rendererHelper.save(getCurrentTableDataTree().getTableDataTreeCellRenderer());
treeSearcher = new TableDataTreeSearcher();
FineLoggerFactory.getLogger().debug("switch to table data search for mode: {}", searchMode.name());
treeSearcher.beforeSearch(searchMode, tableDataSource);

6
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchCallBack.java

@ -1,10 +1,10 @@
package com.fr.design.data.datapane.management.search.control.common;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.datapane.management.search.control.TreeSearchCallback;
import com.fr.design.data.datapane.management.search.control.TreeSearchResult;
import com.fr.design.search.control.TreeSearchCallback;
import com.fr.design.search.control.TreeSearchResult;
import com.fr.design.data.datapane.management.search.searcher.TableDataTreeSearcher;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
import com.fr.design.search.TreeSearchStatus;
import javax.swing.SwingUtilities;

2
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchResult.java

@ -1,6 +1,6 @@
package com.fr.design.data.datapane.management.search.control.common;
import com.fr.design.data.datapane.management.search.control.TreeSearchResult;
import com.fr.design.search.control.TreeSearchResult;
import java.util.ArrayList;
import java.util.List;

15
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchTask.java

@ -1,8 +1,9 @@
package com.fr.design.data.datapane.management.search.control.common;
import com.fr.design.data.datapane.management.search.control.TreeSearchCallback;
import com.fr.design.data.datapane.management.search.control.TreeSearchResult;
import com.fr.design.data.datapane.management.search.control.TreeSearchTask;
import com.fr.design.data.tabledata.wrapper.MultiResultTableDataWrapper;
import com.fr.design.search.control.TreeSearchCallback;
import com.fr.design.search.control.TreeSearchResult;
import com.fr.design.search.control.TreeSearchTask;
import com.fr.design.data.tabledata.wrapper.StoreProcedureDataWrapper;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.log.FineLoggerFactory;
@ -39,7 +40,7 @@ public class TableDataSearchTask implements TreeSearchTask {
TreeSearchResult result;
try {
if (isTableDataStoreProcedure(tableDataWrapper)) {
result = dealWithStoreProcedureTableDataWrapper((StoreProcedureDataWrapper) tableDataWrapper);
result = dealWithStoreProcedureTableDataWrapper((MultiResultTableDataWrapper) tableDataWrapper);
} else {
result = dealWithCommonTableDataWrapper(tableDataWrapper);
}
@ -87,11 +88,11 @@ public class TableDataSearchTask implements TreeSearchTask {
*
* @param procedureDataWrapper
*/
private TreeSearchResult dealWithStoreProcedureTableDataWrapper(StoreProcedureDataWrapper procedureDataWrapper) {
private TreeSearchResult dealWithStoreProcedureTableDataWrapper(MultiResultTableDataWrapper procedureDataWrapper) {
// 存储过程数据集名称,例如 Proc1_Table1
String tableDataName = procedureDataWrapper.getTableDataName();
// 存储过程名称,例如 Proc1
String storeProcedureName = procedureDataWrapper.getStoreprocedureName();
String storeProcedureName = procedureDataWrapper.getTableDataName();
// 存储过程子表名称,例如 Table1
String tableName = tableDataName.replaceFirst(storeProcedureName, StringUtils.EMPTY).replaceFirst("_", StringUtils.EMPTY);
boolean isStoreProcedureNameMatch = isMatchSearch(storeProcedureName, searchText);
@ -132,7 +133,7 @@ public class TableDataSearchTask implements TreeSearchTask {
* @return
*/
private boolean isTableDataStoreProcedure(TableDataWrapper tableDataWrapper) {
return tableDataWrapper instanceof StoreProcedureDataWrapper;
return tableDataWrapper instanceof MultiResultTableDataWrapper;
}
/**

2
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchCallBack.java

@ -1,6 +1,6 @@
package com.fr.design.data.datapane.management.search.control.pre;
import com.fr.design.data.datapane.management.search.control.TreeSearchResult;
import com.fr.design.search.control.TreeSearchResult;
import com.fr.design.data.datapane.management.search.control.common.TableDataSearchCallBack;
import com.fr.design.data.datapane.management.search.searcher.TableDataTreeSearcher;

2
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchResult.java

@ -1,6 +1,6 @@
package com.fr.design.data.datapane.management.search.control.pre;
import com.fr.design.data.datapane.management.search.control.TreeSearchResult;
import com.fr.design.search.control.TreeSearchResult;
import java.util.ArrayList;
import java.util.List;

8
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchTask.java

@ -1,11 +1,9 @@
package com.fr.design.data.datapane.management.search.control.pre;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.datapane.management.search.control.TreeSearchTask;
import com.fr.design.search.control.TreeSearchTask;
import com.fr.design.data.datapane.management.search.control.common.TableDataSearchResult;
import com.fr.design.data.datapane.management.search.control.TreeSearchCallback;
import com.fr.design.data.datapane.management.search.control.TreeSearchResult;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
import com.fr.design.search.control.TreeSearchCallback;
import com.fr.design.search.control.TreeSearchResult;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.log.FineLoggerFactory;

6
designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TableDataSearchRemindPane.java

@ -4,13 +4,13 @@ import com.fr.base.svg.IconUtils;
import com.fr.design.constants.UIConstants;
import com.fr.design.data.datapane.TableDataTree;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeListener;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.search.TreeSearchStatus;
import com.fr.design.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.search.event.TreeSearchStatusChangeListener;
import javax.swing.BorderFactory;
import javax.swing.JPanel;

7
designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TreeSearchToolbarPane.java

@ -5,9 +5,9 @@ import com.fr.design.DesignModelAdapter;
import com.fr.design.constants.UIConstants;
import com.fr.design.data.datapane.TableDataTreePane;
import com.fr.design.data.datapane.management.search.TableDataTreeSearchManager;
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.data.datapane.management.search.event.TreeSearchStatusChangeListener;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
import com.fr.design.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.search.event.TreeSearchStatusChangeListener;
import com.fr.design.search.TreeSearchStatus;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.gui.itoolbar.UIToolbar;
@ -16,7 +16,6 @@ import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.stable.StringUtils;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

2
designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataTreeSearcher.java

@ -9,6 +9,8 @@ import com.fr.design.data.datapane.management.search.control.common.TableDataSea
import com.fr.design.data.datapane.management.search.control.pre.TableDataPreSearchCallBack;
import com.fr.design.data.datapane.management.search.control.pre.TableDataPreSearchTask;
import com.fr.design.data.tabledata.wrapper.TableDataWrapper;
import com.fr.design.search.TreeSearchStatus;
import com.fr.design.search.TreeSearcher;
import java.util.HashSet;
import java.util.List;

9
designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTableModel.java

@ -3,7 +3,7 @@ package com.fr.design.data.datapane.preview;
import com.fr.cache.list.IntList;
import com.fr.data.AbstractDataModel;
import com.fr.data.impl.EmbeddedTableData.EmbeddedTDDataModel;
import com.fr.data.impl.storeproc.ProcedureDataModel;
import com.fr.data.impl.NameDataModel;
import com.fr.design.utils.DesignUtils;
import com.fr.general.data.DataModel;
import com.fr.general.data.TableDataException;
@ -32,8 +32,9 @@ public class PreviewTableModel extends AbstractTableModel {
}
public PreviewTableModel(DataModel sourceResultSet, int maxRowCount) {
if (sourceResultSet instanceof ProcedureDataModel) {
ProcedureDataModel rs = (ProcedureDataModel) sourceResultSet;
// 如果是这种NameDataModel,根据maxRowCount截断一下
if (sourceResultSet instanceof NameDataModel) {
NameDataModel rs = (NameDataModel) sourceResultSet;
try {
this.dataModel = createRowDataModel(rs, maxRowCount);
} catch (TableDataException e) {
@ -45,7 +46,7 @@ public class PreviewTableModel extends AbstractTableModel {
}
}
public static DataModel createRowDataModel(final ProcedureDataModel rs, int maxRowCount) throws TableDataException {
public static DataModel createRowDataModel(final NameDataModel rs, int maxRowCount) throws TableDataException {
int rowCount = rs.getRowCount();
if (maxRowCount == 0) {
maxRowCount = rowCount;

87
designer-base/src/main/java/com/fr/design/data/datapane/preview/PreviewTablePane.java

@ -8,7 +8,7 @@ import com.fr.base.TableData;
import com.fr.data.TableDataSource;
import com.fr.data.impl.DBTableData;
import com.fr.data.impl.EmbeddedTableData;
import com.fr.data.impl.storeproc.ProcedureDataModel;
import com.fr.data.impl.NameDataModel;
import com.fr.data.operator.DataOperator;
import com.fr.design.DesignerEnvManager;
import com.fr.design.data.DesignTableDataManager;
@ -28,6 +28,7 @@ import com.fr.design.mainframe.DesignerContext;
import com.fr.design.ui.util.UIUtil;
import com.fr.function.TIME;
import com.fr.general.FRFont;
import com.fr.general.data.DataModel;
import com.fr.log.FineLoggerFactory;
import javax.swing.BorderFactory;
@ -55,6 +56,7 @@ import java.awt.event.MouseEvent;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CancellationException;
/**
@ -62,13 +64,13 @@ import java.util.concurrent.CancellationException;
*/
public class PreviewTablePane extends BasicPane {
private TableData tableData;
private ProcedureDataModel storeProcedureDataModel;
private static UINumberField maxPreviewNumberField;
private DataModel dataModel;
private UINumberField maxPreviewNumberField;
private UINumberField currentRowsField;
private JTable preveiwTable;
private static AutoProgressBar progressBar;
private AutoProgressBar connectionBar;
private java.util.List<LoadedEventListener> listeners = new ArrayList<LoadedEventListener>();
private List<LoadedEventListener> listeners = new ArrayList<LoadedEventListener>();
private BasicDialog dialog;
private SwingWorker worker;
@ -152,8 +154,8 @@ public class PreviewTablePane extends BasicPane {
refreshLabel.setBackground(java.awt.Color.WHITE);
try {
populate(tableData);
if (storeProcedureDataModel != null) {
populateStoreDataSQL();
if (dataModel != null) {
setRowsLimitTableModel();
}
} catch (Exception e1) {
}
@ -423,7 +425,8 @@ public class PreviewTablePane extends BasicPane {
*
* @param storeProcedureDataModel storeProcedureDataModel
*/
public static void previewStoreData(ProcedureDataModel storeProcedureDataModel) {
@Deprecated
public static void previewStoreData(NameDataModel storeProcedureDataModel) {
previewStoreData(storeProcedureDataModel, -1, -1);
}
@ -434,13 +437,30 @@ public class PreviewTablePane extends BasicPane {
* @param keyIndex 实际值
* @param valueIndex 显示值
*/
public static void previewStoreData(final ProcedureDataModel storeProcedureDataModel, final int keyIndex, final int valueIndex) {
@Deprecated
public static void previewStoreData(final NameDataModel storeProcedureDataModel, final int keyIndex, final int valueIndex) {
previewDataModel(storeProcedureDataModel, keyIndex, valueIndex);
}
public static void previewDataModel(DataModel dataModel) {
previewDataModel(dataModel, -1, -1);
}
/**
* 直接预览数据集的结果集
*
* @param dataModel 结果集
* @param keyIndex
* @param valueIndex
*/
public static void previewDataModel(final DataModel dataModel, final int keyIndex, final int valueIndex) {
final PreviewTablePane previewTablePane = new PreviewTablePane();
previewTablePane.storeProcedureDataModel = storeProcedureDataModel;
previewTablePane.dataModel = dataModel;
previewTablePane.setBorder(BorderFactory.createTitledBorder(Toolkit.i18nText("Fine-Design_Basic_Data")));
try {
previewTablePane.populateStoreDataSQL();
previewTablePane.setRowsLimitTableModel();
previewTablePane.resetPreviewTableColumnColor();
if (keyIndex > -1) {
@ -457,27 +477,28 @@ public class PreviewTablePane extends BasicPane {
previewTablePane.showWindow(new JFrame()).setVisible(true);
}
/**
* 直接预览存储过程的所有返回数据集没有实际值和显示值
*
* @param storeProcedureDataModels storeProcedureDataModels
*/
public static void previewStoreDataWithAllDs(ProcedureDataModel[] storeProcedureDataModels) {
UITabbedPane tabPreviewpane = new UITabbedPane();
int tableSize = storeProcedureDataModels.length;
for (int i = 0; i < tableSize; i++) {
public static void previewMultiDataModels(NameDataModel[] nameDataModels) {
// tab窗口
UITabbedPane tabbedPane = new UITabbedPane();
for (NameDataModel nameDataModel : nameDataModels) {
// 单个结果集的展示面板
PreviewTablePane previewTablePane = new PreviewTablePane();
previewTablePane.storeProcedureDataModel = storeProcedureDataModels[i];
previewTablePane.dataModel = nameDataModel;
// 数据
previewTablePane.setBorder(BorderFactory.createTitledBorder(Toolkit.i18nText("Fine-Design_Basic_Data")));
try {
previewTablePane.populateStoreDataSQL();
// 带行数限制的数据集结果预览对象
previewTablePane.setRowsLimitTableModel();
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
tabPreviewpane.addTab(storeProcedureDataModels[i].getName(), previewTablePane);
tabbedPane.addTab(nameDataModel.getName(), previewTablePane);
}
BasicPane prieviewPane = new BasicPane() {
// 包含整个tab的容器窗口
BasicPane previewPane = new BasicPane() {
@Override
protected String title4PopupWindow() {
@ -485,15 +506,25 @@ public class PreviewTablePane extends BasicPane {
}
};
prieviewPane.setLayout(FRGUIPaneFactory.createBorderLayout());
prieviewPane.add(tabPreviewpane, BorderLayout.CENTER);
prieviewPane.showWindow(new JFrame()).setVisible(true);
previewPane.setLayout(FRGUIPaneFactory.createBorderLayout());
previewPane.add(tabbedPane, BorderLayout.CENTER);
previewPane.showWindow(new JFrame()).setVisible(true);
}
/**
* 直接预览存储过程的所有返回数据集没有实际值和显示值
*
* @param storeProcedureDataModels storeProcedureDataModels
*/
@Deprecated
public static void previewStoreDataWithAllDs(NameDataModel[] storeProcedureDataModels) {
previewMultiDataModels(storeProcedureDataModels);
}
private void populateStoreDataSQL() throws Exception {
private void setRowsLimitTableModel() throws Exception {
PreviewTableModel previewModel;
try {
previewModel = new PreviewTableModel(storeProcedureDataModel, (int) maxPreviewNumberField.getValue());
previewModel = new PreviewTableModel(dataModel, (int) maxPreviewNumberField.getValue());
} catch (Exception e) {
previewModel = new PreviewTableModel((int) maxPreviewNumberField.getValue());
}

10
designer-base/src/main/java/com/fr/design/data/tabledata/tabledatapane/ProcedureDataPane.java

@ -19,7 +19,7 @@ import com.fr.design.data.datapane.connect.ConnectionTableProcedurePane.DoubleCl
import com.fr.design.data.datapane.sqlpane.SQLEditPane;
import com.fr.design.data.tabledata.ResponseDataSourceChange;
import com.fr.design.data.tabledata.StoreProcedureWorkerListener;
import com.fr.design.data.tabledata.wrapper.StoreProcedureDataWrapper;
import com.fr.design.data.tabledata.wrapper.MultiResultTableDataWrapper;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.gui.icheckbox.UICheckBox;
import com.fr.design.gui.icontainer.UIScrollPane;
@ -290,8 +290,8 @@ public class ProcedureDataPane extends AbstractTableDataPane<StoreProcedure> imp
protected Void doInBackground() throws Exception {
DesignTableDataManager.setThreadLocal(DesignTableDataManager.NO_PARAMETER);
sp.setCalculating(true);
ProcedureDataModel[] dataModels = DesignTableDataManager.createLazyDataModel(sp, false);
sp.refreshDataModelListAndResultNames(dataModels);
ProcedureDataModel[] dataModels = (ProcedureDataModel[]) DesignTableDataManager.createLazyDataModel(sp, false);
sp.refreshResults(dataModels);
return null;
}
@ -382,8 +382,8 @@ public class ProcedureDataPane extends AbstractTableDataPane<StoreProcedure> imp
@Override
public void actionPerformed(ActionEvent evt) {
StoreProcedure sp = updateBeanWithOutExecute();
StoreProcedureDataWrapper storeProcedureDataWrapper = new StoreProcedureDataWrapper(this.procedureDataPane, sp, StringUtils.EMPTY, queryText.getText());
storeProcedureDataWrapper.previewData(StoreProcedureDataWrapper.PREVIEW_ALL);
MultiResultTableDataWrapper wrapper = new MultiResultTableDataWrapper(this.procedureDataPane, sp, StringUtils.EMPTY, queryText.getText());
wrapper.previewData(MultiResultTableDataWrapper.PREVIEW_ALL);
}
}

143
designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataNameWrapper.java

@ -0,0 +1,143 @@
package com.fr.design.data.tabledata.wrapper;
import com.fr.base.TableData;
import com.fr.data.MultiResultTableData;
import com.fr.data.impl.NameDataModel;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.preview.PreviewTablePane;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.log.FineLoggerFactory;
import com.fr.workspace.WorkContext;
import javax.swing.Icon;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 多结果数据集-结果包装
*
* @author rinoux
* @version 11.0
* Created by rinoux on 2022/8/12
*/
public final class MultiResultTableDataNameWrapper implements TableDataWrapper {
private NameDataModel dataModel;
private final String name;
private final MultiResultTableData<?> tableData;
private List<String> childrenList;
/**
* @param name 数据集名字
* @param tableData 数据集
*/
public MultiResultTableDataNameWrapper(String name, MultiResultTableData<?> tableData) {
this.name = name;
this.tableData = tableData;
}
/**
* 生成子节点
*
* @return 子节点
*/
public ExpandMutableTreeNode[] load() {
// 生成多数据集结果子节点
List<String> namelist = calculateColumnNameList();
ExpandMutableTreeNode[] res = new ExpandMutableTreeNode[namelist.size()];
for (int i = 0; i < res.length; i++) {
res[i] = new ExpandMutableTreeNode(namelist.get(i));
}
return res;
}
@Override
public String getTableDataName() {
return name;
}
@Override
public TableData getTableData() {
return tableData;
}
@Override
public Icon getIcon() {
return MultiResultTableDataWrapperHelper.getIcon(this.tableData.getClass());
}
private void createResult(boolean needLoadingBar) {
try {
// todo 啥意思?
dataModel = DesignTableDataManager.createLazyDataModel(tableData, needLoadingBar)[0];
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
/**
* 数据集执行结果返回的所有字段
* <p/>
* TODO:要不要加上Exception呢个人感觉很有必要
*
* @return 字段
*/
public List<String> calculateColumnNameList() {
if (childrenList != null) {
return childrenList;
}
childrenList = new ArrayList<>();
if (!WorkContext.getCurrent().isLocal()) {
try {
createResult(false);
childrenList = Arrays.asList(dataModel.getColumnNames());
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
} else {
if (dataModel == null) {
createResult(false);
}
if (dataModel != null) {
childrenList = Arrays.asList(dataModel.getColumnNames());
}
}
return childrenList;
}
/**
* 预览数据集
*/
public void previewData() {
if (dataModel == null) {
createResult(true);
}
PreviewTablePane.previewDataModel(dataModel);
}
/**
* 预览数据集带有显示值和实际值的标记结果
*
* @param keyIndex 显示值Index
* @param valueIndex 实际值index
*/
public void previewData(int keyIndex, int valueIndex) {
if (dataModel == null) {
createResult(true);
}
PreviewTablePane.previewDataModel(dataModel, keyIndex, valueIndex);
}
/**
* 是否异常
*
* @return 异常返回true
*/
public boolean isUnusual() {
return false;
}
}

325
designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataWrapper.java

@ -0,0 +1,325 @@
package com.fr.design.data.tabledata.wrapper;
import com.fr.base.TableData;
import com.fr.data.MultiResultTableData;
import com.fr.data.impl.NameDataModel;
import com.fr.data.impl.storeproc.StoreProcedure;
import com.fr.data.operator.DataOperator;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.preview.PreviewTablePane;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.gui.iprogressbar.AutoProgressBar;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.general.ComparatorUtils;
import com.fr.log.FineLoggerFactory;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
import java.awt.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CancellationException;
/**
* 多结果数据集包装
*
* @author rinoux
* @version 11.0
* Created by rinoux on 2022/8/12
*/
public final class MultiResultTableDataWrapper implements TableDataWrapper {
public static final int PREVIEW_ALL = 0;
public static final int PREVIEW_ONE = 1;
public static AutoProgressBar loadingBar;
private NameDataModel dataModel;
private final String dataModelName;
private final String tableDataName;
private final MultiResultTableData<?> tableData;
private List<String> columnNameList;
private AutoProgressBar connectionBar;
private NameDataModel[] dataModels;
private SwingWorker<?, ?> worker;
private int previewModel;
/**
* @param tableData 数据集
* @param tableDataName 数据集名称
* @param dataModelName 数据集的一个结果的名称全限定名称
*/
public MultiResultTableDataWrapper(MultiResultTableData<?> tableData, String tableDataName, String dataModelName) {
this(null, tableData, tableDataName, dataModelName, true);
}
/**
* @param tableData 数据集
* @param tableDataName 数据集名称
* @param dataModelName 数据集的一个结果的名称全限定名称
* @param needLoad 是否需要加载
*/
public MultiResultTableDataWrapper(MultiResultTableData<?> tableData, String tableDataName, String dataModelName, boolean needLoad) {
this(null, tableData, tableDataName, dataModelName, needLoad);
}
/**
* @param component 父容器
* @param tableData 数据集
* @param tableDataName 数据集名称
* @param dataModelName 数据集的一个结果的名称全限定名称
*/
public MultiResultTableDataWrapper(Component component, MultiResultTableData<?> tableData, String tableDataName, String dataModelName) {
this(component, tableData, tableDataName, dataModelName, true);
}
/**
* @param component loadingBar的父弹框如果不设置父弹框的话可能出现loadingBar隐藏在一个弹框后的情况
* @param tableData 多结果数据集
* @param tableDataName 多结果数据集的名字(某些情况下可以为空)
* @param dataModelName 多结果数据集一个返回数据集的名字
* @param needLoad 是否要加载
**/
public MultiResultTableDataWrapper(Component component, MultiResultTableData<?> tableData, String tableDataName, String dataModelName, boolean needLoad) {
this.dataModelName = dataModelName;
this.tableData = tableData;
this.tableDataName = tableDataName;
if (component == null) {
component = new JFrame();
}
if (needLoad) {
setWorker(component);
}
loadingBar = new AutoProgressBar(component, Toolkit.i18nText("Fine-Design_Basic_Loading_Data"), "", 0, 100) {
@Override
public void doMonitorCanceled() {
getWorker().cancel(true);
}
};
}
/**
* 数据集执行结果返回的所有字段
*
* @return 数据集执行结果返回的所有字段
* @date 2014-12-3-下午7:43:17
*/
@Override
public List<String> calculateColumnNameList() {
if (columnNameList != null) {
return columnNameList;
}
try {
createResults(false);
} catch (Exception e) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Engine_No_TableData"));
return new ArrayList<String>();
}
columnNameList = Arrays.asList(dataModel.getColumnNames());
return columnNameList;
}
/**
* 生成子节点
*
* @return 节点数组
* @date 2014-12-3-下午7:06:47
*/
@Override
public ExpandMutableTreeNode[] load() {
List<String> namelist;
if (tableData.isCalculating()) {
namelist = Arrays.asList(new String[0]);
} else {
namelist = calculateColumnNameList();
}
ExpandMutableTreeNode[] res = new ExpandMutableTreeNode[namelist.size()];
for (int i = 0; i < res.length; i++) {
res[i] = new ExpandMutableTreeNode(namelist.get(i));
}
return res;
}
private void createResults(boolean needLoadingBar) throws Exception {
this.dataModel = null;
dataModels = DesignTableDataManager.createLazyDataModel(tableData, needLoadingBar);
if (dataModels != null && dataModels.length != 0) {
for (NameDataModel dataModel : dataModels) {
if (ComparatorUtils.equals(this.dataModelName, tableDataName + MultiResultTableData.GROUP_MARKER + dataModel.getName())) {
this.dataModel = dataModel;
break;
}
}
}
}
@Override
public Icon getIcon() {
return MultiResultTableDataWrapperHelper.getIcon(this.tableData.getClass());
}
/**
* 预览数据
*
* @param previewModel 预览模式, 全部还是一个
* @date 2014-12-3-下午7:05:50
*/
public void previewData(final int previewModel) {
this.previewModel = previewModel;
connectionBar = new AutoProgressBar(new JFrame(), Toolkit.i18nText("Fine-Design_Basic_Utils_Now_Create_Connection"), "", 0, 100) {
@Override
public void doMonitorCanceled() {
connectionBar.close();
worker.cancel(true);
}
};
worker.execute();
}
private void setWorker(final Component parent) {
worker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
loadingBar.close();
PreviewTablePane.resetPreviewTable();
connectionBar.start();
// 存储过程需要先测试一下连接
if (tableData instanceof StoreProcedure) {
boolean status = DataOperator.getInstance().testConnection(((StoreProcedure) getTableData()).getDatabaseConnection());
if (!status) {
connectionBar.close();
throw new Exception(Toolkit.i18nText("Fine-Design_Basic_Database_Connection_Failed"));
}
}
connectionBar.close();
tableData.resetDataModelList();
// 获取结果
createResults(true);
return null;
}
@Override
public void done() {
try {
get();
loadingBar.close();
switch (previewModel) {
case MultiResultTableDataWrapper.PREVIEW_ALL:
PreviewTablePane.previewMultiDataModels(dataModels);
break;
case MultiResultTableDataWrapper.PREVIEW_ONE:
previewData();
break;
default:
break;
}
} catch (Exception e) {
loadingBar.close();
if (!(e instanceof CancellationException)) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
FineJOptionPane.showMessageDialog(parent, e.getMessage());
}
}
}
};
}
private SwingWorker getWorker() {
return this.worker;
}
// august:这个只是预览返回的一个数据集
/**
* 预览返回的一个数据集
*
* @date 2014-12-3-下午7:42:53
*/
@Override
public void previewData() {
previewData(-1, -1);
}
// august:这个只是预览返回的一个数据集
/**
* 预览返回的一个数据集带有显示值和实际值的标记结果
*
* @param keyIndex 实际值
* @param valueIndex 显示值
* @date 2014-12-3-下午7:42:27
*/
@Override
public void previewData(final int keyIndex, final int valueIndex) {
PreviewTablePane.previewDataModel(dataModel, keyIndex, valueIndex);
}
/**
* 预览返回的所有数据集只有在编辑多结果数据集时才用到
*/
public void previewAllTable() {
if (dataModel == null) {
try {
createResults(true);
} catch (Exception e) {
return;
}
}
PreviewTablePane.previewMultiDataModels(dataModels);
}
@Override
public String getTableDataName() {
// todo 这里返回数据集结果名称,带_的
return dataModelName;
}
public String getDataModelName() {
return dataModelName;
}
@Override
public TableData getTableData() {
return tableData;
}
/**
* 获取当前节点所属可编辑的数据集名称
*
* @return
*/
public String getMultiResultTableDataName() {
return tableDataName;
}
/**
* 是否异常
*
* @return 是否异常
*/
@Override
public boolean isUnusual() {
return false;
}
@Override
public boolean equals(Object obj) {
return obj instanceof MultiResultTableDataWrapper
&& ComparatorUtils.equals(this.getDataModelName(), ((MultiResultTableDataWrapper) obj).getDataModelName())
&& ComparatorUtils.equals(this.getTableData(), ((MultiResultTableDataWrapper) obj).getTableData())
&& ComparatorUtils.equals(this.getMultiResultTableDataName(), ((MultiResultTableDataWrapper) obj).getMultiResultTableDataName())
&& ComparatorUtils.equals(this.getTableDataName(), ((MultiResultTableDataWrapper) obj).getTableDataName());
}
}

54
designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/MultiResultTableDataWrapperHelper.java

@ -0,0 +1,54 @@
package com.fr.design.data.tabledata.wrapper;
import com.fr.base.TableData;
import com.fr.design.data.datapane.TableDataCreatorProducer;
import com.fr.design.data.datapane.TableDataNameObjectCreator;
import com.fr.design.fun.ServerTableDataDefineProvider;
import com.fr.design.fun.TableDataDefineProvider;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.event.Listener;
import com.fr.general.IOUtils;
import com.fr.plugin.context.PluginContext;
import com.fr.plugin.observer.PluginEventType;
import com.fr.stable.Filter;
import org.jetbrains.annotations.NotNull;
import javax.swing.Icon;
import java.util.HashMap;
import java.util.Map;
/**
* @author rinoux
* @version 11.0
* Created by rinoux on 2022/9/7
*/
class MultiResultTableDataWrapperHelper {
private static final Map<Class<? extends TableData>, Icon> TABLE_DATA_ICON_PATHS = new HashMap<>();
private static final String DEFAULT_MULTI_RESULT_TD_ICON = "/com/fr/design/images/data/multi.png";
static {
Listener<PluginContext> listener = new Listener<PluginContext>() {
@Override
public void on(Event event, PluginContext param) {
TABLE_DATA_ICON_PATHS.clear();
}
};
Filter<PluginContext> filter = pluginContext -> pluginContext.contain(TableDataDefineProvider.XML_TAG) || pluginContext.contain(ServerTableDataDefineProvider.XML_TAG);
EventDispatcher.listen(PluginEventType.AfterRun, listener, filter);
EventDispatcher.listen(PluginEventType.BeforeStop, listener, filter);
}
public static @NotNull Icon getIcon(@NotNull Class<? extends TableData> tableDataClass) {
return TABLE_DATA_ICON_PATHS.computeIfAbsent(tableDataClass, cls -> {
for (TableDataNameObjectCreator creator : TableDataCreatorProducer.getInstance().createReportTableDataCreator()) {
if (creator.createObject().getClass().isAssignableFrom(tableDataClass)) {
return IOUtils.readIcon(creator.getIconPath());
}
}
return IOUtils.readIcon(DEFAULT_MULTI_RESULT_TD_ICON);
});
}
}

6
designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureDataWrapper.java

@ -36,7 +36,9 @@ import java.util.concurrent.CancellationException;
*
* @author zhou
* @since 2012-4-12上午10:29:15
* @deprecated 请勿使用{@link MultiResultTableDataWrapper}
*/
@Deprecated
public final class StoreProcedureDataWrapper implements TableDataWrapper {
public static final int PREVIEW_ALL = 0;
public static final int PREVIEW_ONE = 1;
@ -74,7 +76,7 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
public StoreProcedureDataWrapper(Component component, StoreProcedure storeProcedure, String storeprocedureName, String dsName, boolean needLoad) {
this.dsName = dsName;
this.storeProcedure = storeProcedure;
this.storeProcedure.setCalculating(false);
/*this.storeProcedure.setCalculating(false);*/
this.storeprocedureName = storeprocedureName;
if (component == null) {
component = new JFrame();
@ -135,7 +137,7 @@ public final class StoreProcedureDataWrapper implements TableDataWrapper {
}
private void createStore(boolean needLoadingBar) throws Exception {
dataModels = DesignTableDataManager.createLazyDataModel(storeProcedure, needLoadingBar);
dataModels = (ProcedureDataModel[]) DesignTableDataManager.createLazyDataModel(storeProcedure, needLoadingBar);
if (dataModels != null && dataModels.length != 0) {
for (ProcedureDataModel dataModel : dataModels) {
if (ComparatorUtils.equals(this.dsName, storeprocedureName + "_" + dataModel.getName())) {

4
designer-base/src/main/java/com/fr/design/data/tabledata/wrapper/StoreProcedureNameWrapper.java

@ -27,7 +27,9 @@ import java.util.List;
*
* @author zhou
* @since 2012-4-12上午10:29:15
* @deprecated 请勿使用{@link MultiResultTableDataNameWrapper}
*/
@Deprecated
public final class StoreProcedureNameWrapper implements TableDataWrapper {
private ProcedureDataModel procedureDataModel;
private String name;
@ -74,7 +76,7 @@ public final class StoreProcedureNameWrapper implements TableDataWrapper {
private void createStore(boolean needLoadingBar) {
try {
procedureDataModel = DesignTableDataManager.createLazyDataModel(storeProcedure, needLoadingBar)[0];
procedureDataModel = (ProcedureDataModel) DesignTableDataManager.createLazyDataModel(storeProcedure, needLoadingBar)[0];
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}

117
designer-base/src/main/java/com/fr/design/deeplink/DeepLinkCore.java

@ -10,6 +10,7 @@ import com.fr.event.Null;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import com.fr.stable.os.OperatingSystem;
import com.fr.start.common.DesignerStartupContext;
import com.fr.third.org.apache.http.NameValuePair;
import com.fr.web.URLUtils;
@ -42,6 +43,8 @@ public class DeepLinkCore {
}
private String pendingURL;
private final List<DeepLinkPrepare> deepLinkPrepareList = new ArrayList<>();
private final List<DeepLink> deepLinkList = new ArrayList<>();
@ -50,6 +53,9 @@ public class DeepLinkCore {
public void register(DeepLink deepLink) {
if (deepLink != null) {
deepLinkList.add(deepLink);
if (deepLink instanceof DeepLinkPrepare) {
deepLinkPrepareList.add((DeepLinkPrepare) deepLink);
}
}
}
@ -128,39 +134,35 @@ public class DeepLinkCore {
private void acceptNewURL(String url) {
this.pendingURL = url;
UrlBean urlBean = UrlBean.create(this.pendingURL);
for (DeepLinkPrepare deepLinkPrepare : deepLinkPrepareList) {
deepLinkPrepare.prepare(urlBean.getUrl(), urlBean.getHost(), urlBean.getPath(), urlBean.getParams());
}
}
private boolean canConsumePendingURL() {
return StringUtils.isNotEmpty(this.pendingURL) && isDesignerStartupCompleted;
return StringUtils.isNotEmpty(this.pendingURL) && isAvailableConsumingTime();
}
/**
* 是否是可用的消耗时机
* 满足任一即可
* 1-设计器已经启动
* 2-出在设计器启动页页面
*
* @return /
*/
private boolean isAvailableConsumingTime() {
return isDesignerStartupCompleted || DesignerStartupContext.getInstance().isOnWaiting();
}
private void consumePendingURL() {
String host = null;
String path = null;
Map<String, Object> params = new HashMap<>();
URL url = null;
try {
url = new URL(null, this.pendingURL, new URLStreamHandler() {
@Override
protected URLConnection openConnection(URL u) throws IOException {
return null;
}
});
} catch (MalformedURLException ignored) {}
if (url != null) {
host = url.getHost();
path = url.getPath();
List<NameValuePair> pairs = URLUtils.parse(url.getQuery());
for (NameValuePair pair: pairs) {
params.put(pair.getName(), pair.getValue());
}
}
UrlBean urlBean = UrlBean.create(this.pendingURL);
FineLoggerFactory.getLogger().info("consume deep link: " + this.pendingURL);
performDeepLinks(this.pendingURL, host, path, params);
performDeepLinks(urlBean.getUrl(), urlBean.getHost(), urlBean.getPath(), urlBean.getParams());
markPendingURLConsumed();
}
@ -181,4 +183,67 @@ public class DeepLinkCore {
private void markPendingURLConsumed() {
this.pendingURL = null;
}
private static class UrlBean {
private String url;
private String host;
private String path;
private Map<String, Object> params;
public UrlBean(String url, String host, String path, Map<String, Object> params) {
this.url = url;
this.host = host;
this.path = path;
this.params = params;
}
public String getUrl() {
return url;
}
public String getHost() {
return host;
}
public String getPath() {
return path;
}
public Map<String, Object> getParams() {
return params;
}
public static UrlBean create(String pendingUrl) {
String host = null;
String path = null;
Map<String, Object> params = new HashMap<>();
URL url = null;
try {
url = new URL(null, pendingUrl, new URLStreamHandler() {
@Override
protected URLConnection openConnection(URL u) throws IOException {
return null;
}
});
} catch (MalformedURLException ignored) {
}
if (url != null) {
host = url.getHost();
path = url.getPath();
List<NameValuePair> pairs = URLUtils.parse(url.getQuery());
for (NameValuePair pair : pairs) {
params.put(pair.getName(), pair.getValue());
}
}
return new UrlBean(pendingUrl, host, path, params);
}
}
}

17
designer-base/src/main/java/com/fr/design/deeplink/DeepLinkPrepare.java

@ -0,0 +1,17 @@
package com.fr.design.deeplink;
import java.util.Map;
/**
* created by Harrison on 2022/08/23
**/
public interface DeepLinkPrepare {
/**
* 准备
*
* @param url 链接
* @return 成功/失败
*/
boolean prepare(String url, String host, String path, Map<String, Object> params);
}

5
designer-base/src/main/java/com/fr/design/dialog/UIDialog.java

@ -18,6 +18,7 @@ import java.awt.BorderLayout;
import java.awt.Dialog;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
@ -44,6 +45,10 @@ public abstract class UIDialog extends JDialog {
super(parent);
}
public UIDialog(Window parent) {
super(parent);
}
public UIDialog(Frame parent, BasicPane pane) {
this(parent, pane, true);

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

@ -22,7 +22,12 @@ import static com.fr.design.utils.LinkStrUtils.LABEL;
* Created by hades on 2020/10/23
*/
public class MessageWithLink extends JEditorPane {
private static final String HTML_BODY = "<body";
private static final String HTML_STYLE_FORMAT = " style=\"%s\"";
/**
* 直接放入 html 内容
* 如果有超链接标签 <a href=""></a> 的话将会自动点击匹配 url
@ -69,6 +74,34 @@ public class MessageWithLink extends JEditorPane {
this(frontMessage, linkName, link, backMessage, color, font, LABEL.getForeground());
}
public MessageWithLink(String htmlText, Font font) {
this(setHtmlFont(htmlText, font));
}
/**
* 将指定的字体赋给html文本
* 任何失败返回原html文本
* */
private static String setHtmlFont(String htmlText, Font font) {
try {
int bodyIndex = htmlText.indexOf(HTML_BODY);
StringBuilder sb = new StringBuilder();
String left = htmlText.substring(0, bodyIndex + HTML_BODY.length());
String right = htmlText.substring(bodyIndex + HTML_BODY.length());
sb.append(left);
sb.append(String.format(HTML_STYLE_FORMAT, LinkStrUtils.generateStyle(Color.WHITE, font, Color.BLACK)));
sb.append(right);
return sb.toString();
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e, e.getMessage());
}
return htmlText;
}
public MessageWithLink(String frontMessage, String linkName, String link, String backMessage, Color backgroundColor, Font font, Color fontColor) {
super("text/html", "<html><body style=\"" + LinkStrUtils.generateStyle(backgroundColor, font, fontColor) + "\">" + frontMessage + "<a href=\"" + link + "\">" + linkName + "</a>" + backMessage + "</body></html>");

487
designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java

@ -0,0 +1,487 @@
package com.fr.design.file;
import com.fr.design.actions.UpdateAction;
import com.fr.design.actions.file.DelFileAction;
import com.fr.design.actions.file.LocateAction;
import com.fr.design.actions.file.RenameAction;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.fun.impl.AbstractTemplateTreeDefineProcessor;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.imenu.UIPopupMenu;
import com.fr.design.gui.itree.filetree.TemplateDirTree;
import com.fr.design.gui.itree.filetree.TemplateFileTree;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrameFileDealerPane;
import com.fr.design.mainframe.manager.clip.TemplateTreeClipboard;
import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateDirTreeSearchPane;
import com.fr.design.mainframe.toast.DesignerToastMsgUtil;
import com.fr.design.mainframe.toast.ToastMsgDialog;
import com.fr.design.utils.TemplateUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.file.filetree.FileNode;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import com.fr.stable.collections.CollectionUtils;
import com.fr.stable.project.ProjectConstants;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
import static javax.swing.JOptionPane.YES_NO_OPTION;
/**
* 默认的模板右键处理方式包含重命名复制黏贴删除移动等功能
*/
public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefineProcessor {
private UIPopupMenu popupMenu;
private RenameAction renameAction;
private CopyAction copyAction;
private PasteAction pasteAction;
private DelFileAction delFileAction;
private MoveAction moveAction;
private LocateAction locateAction;
public static DefaultTemplateTreeDefineProcessor getInstance() {
return DefaultTemplateTreeDefineProcessor.HOLDER.singleton;
}
private static class HOLDER {
private static DefaultTemplateTreeDefineProcessor singleton = new DefaultTemplateTreeDefineProcessor();
}
private DefaultTemplateTreeDefineProcessor() {
initPane();
}
private void initPane() {
renameAction = new RenameAction();
copyAction = new CopyAction();
pasteAction = new PasteAction();
delFileAction = new DelFileAction();
moveAction = new MoveAction();
locateAction = new OpenInTemplateTreeAction();
//右键菜单
popupMenu = new UIPopupMenu();
popupMenu.add(renameAction.createMenuItem());
popupMenu.addSeparator();
popupMenu.add(copyAction.createMenuItem());
popupMenu.add(pasteAction.createMenuItem());
popupMenu.add(delFileAction.createMenuItem());
popupMenu.addSeparator();
popupMenu.add(moveAction.createMenuItem());
popupMenu.add(locateAction.createMenuItem());
}
@Override
public void rightClickAction(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
GUICoreUtils.showPopupMenu(popupMenu, e.getComponent(), e.getX(), e.getY());
checkButtonEnabled();
}
}
private void checkButtonEnabled() {
renameAction.setEnabled(false);
copyAction.setEnabled(false);
pasteAction.setEnabled(false);
delFileAction.setEnabled(false);
moveAction.setEnabled(false);
locateAction.setEnabled(false);
int length = getFileTree().getSelectionCount();
if (length == 0) {
//没有选中文件时,只能黏贴
if (!CollectionUtils.isEmpty(TemplateTreeClipboard.getInstance().takeFromClip())) {
pasteAction.setEnabled(true);
}
return;
}
if (length == 1) {
//选中一个时可以,可以重命名、黏贴
renameAction.setEnabled(true);
if (TemplateTreeSearchManager.getInstance().isInSearchMode()) {
//搜索模式开启定位当前模板
locateAction.setEnabled(true);
}
if (!CollectionUtils.isEmpty(TemplateTreeClipboard.getInstance().takeFromClip())) {
pasteAction.setEnabled(true);
}
}
moveAction.setEnabled(true);
delFileAction.setEnabled(true);
copyAction.setEnabled(true);
}
private TemplateFileTree getFileTree() {
return TemplateTreePane.getInstance().getTemplateFileTree();
}
private TemplateDirTree getDirTree() {
return TemplateDirTreePane.getInstance().getTemplateDirTree();
}
/**
* 复制功能
*/
private class CopyAction extends UpdateAction {
public CopyAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Copy"));
this.setMnemonic('C');
this.setSmallIcon("/com/fr/design/images/m_edit/copy");
}
@Override
public void actionPerformed(ActionEvent e) {
FileOperations selectedOperation = DesignerFrameFileDealerPane.getInstance().getSelectedOperation();
if (!selectedOperation.access()) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return;
}
//先记录所有的要复制的模板
List<ExpandMutableTreeNode> treeNodeList = TemplateTreeClipboard.getInstance().transferNameObjectArray2Map(getFileTree().getSelectedTreeNodes());
TemplateTreeClipboard.getInstance().addToClip(treeNodeList);
}
}
private class OpenInTemplateTreeAction extends LocateAction {
public OpenInTemplateTreeAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Locate_Node"));
}
@Override
public void actionPerformed(ActionEvent e) {
FileNode fileNode = getFileTree().getSelectedFileNode();
if (fileNode == null) {
return;
}
gotoEditingTemplateLeaf(fileNode.getEnvPath());
}
}
/**
* 黏贴功能
*/
private class PasteAction extends UpdateAction {
public PasteAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Action_Paste_Name"));
this.setMnemonic('P');
this.setSmallIcon("/com/fr/design/images/m_edit/paste");
}
@Override
public void actionPerformed(ActionEvent e) {
List<ExpandMutableTreeNode> treeNodeList = TemplateTreeClipboard.getInstance().takeFromClip();
if (!canPaste(treeNodeList)) {
return;
}
String targetDir = getTargetDir();
// 筛选可以黏贴的文件
ArrayList<ExpandMutableTreeNode> pasteNodes = new ArrayList<>();
ArrayList<ExpandMutableTreeNode> lockedNodes = new ArrayList<>();
for (ExpandMutableTreeNode treeNode : treeNodeList) {
FileOperationHelper.getInstance().checkFreeOrLock(treeNode, pasteNodes, lockedNodes);
}
if (pasteNodes.isEmpty() || !lockedNodes.isEmpty()) {
//提示:复制的文件都不能黏贴
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Confirm_Paste_Unlock_File"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return;
}
doPaste(targetDir, treeNodeList);
}
/**
* 检测是否能够黏贴
* @param treeNodeList
* @return
*/
private boolean canPaste(List<ExpandMutableTreeNode> treeNodeList) {
if (CollectionUtils.isEmpty(treeNodeList)) {
return false;
}
//确定目标目录并检查权限
FileOperations selectedOperation = DesignerFrameFileDealerPane.getInstance().getSelectedOperation();
if (!selectedOperation.access()) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return false;
}
//检测之前复制的文件是否被打开
if (TemplateUtils.checkTemplateIsEditing(treeNodeList.toArray(new ExpandMutableTreeNode[0]))) {
return FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Template_Is_Editing"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
YES_NO_OPTION) == JOptionPane.YES_OPTION;
}
return true;
}
private void doPaste(String targetDir, List<ExpandMutableTreeNode> pasteNodes) {
String targetFile = targetDir;
try {
if (StringUtils.isEmpty(targetDir) || !confirmTargetDir(targetDir, pasteNodes)) {
return;
}
for (ExpandMutableTreeNode node : pasteNodes) {
if (node.getUserObject() instanceof FileNode) {
FileNode fileNode = (FileNode) node.getUserObject();
String newTargetFile = FileOperationHelper.getInstance().copyFile(fileNode, targetDir);
if (StringUtils.isNotEmpty(newTargetFile)) {
targetFile = newTargetFile;
}
FineLoggerFactory.getLogger().debug("Template: {} paste to {} success.", fileNode.getEnvPath(), targetDir);
}
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e,"Template paste failed.", e.getMessage());
FineJOptionPane.showConfirmDialog(null,
Toolkit.i18nText("Fine-Design_Basic_Paste_Failure"),
Toolkit.i18nText("Fine-Design_Basic_Error"),
JOptionPane.DEFAULT_OPTION,
JOptionPane.ERROR_MESSAGE);
}
DesignerFrameFileDealerPane.getInstance().getSelectedOperation().refreshParent();
LocateAction.gotoEditingTemplateLeaf(targetFile);
}
/**
* 确认粘贴的目标目录是否是复制文件的子目录并确认是否继续执行粘贴任务
*
* @param targetDir 目标文件夹
* @param pasteNodes 待粘贴的文件
* @return 是否继续
*/
private boolean confirmTargetDir(String targetDir, List<ExpandMutableTreeNode> pasteNodes) {
List<ExpandMutableTreeNode> filterNodes = pasteNodes.stream().filter(
treeNode -> targetDir.startsWith(((FileNode) (treeNode.getUserObject())).getEnvPath())).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(filterNodes)) {
if (FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Confirm_Paste_Target_Dir"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
YES_NO_OPTION) != JOptionPane.YES_OPTION) {
return false;
}
//移除待粘贴文件中目标目录的父目录
pasteNodes.removeAll(filterNodes);
}
return true;
}
}
/**
* 移动功能
*/
private class MoveAction extends UpdateAction {
public MoveAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Move"));
this.setSmallIcon("/com/fr/design/images/m_edit/move");
}
@Override
public void actionPerformed(ActionEvent e) {
FileOperations selectedOperation = DesignerFrameFileDealerPane.getInstance().getSelectedOperation();
if (!selectedOperation.access()) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return;
}
// 筛选可以移动的文件
ArrayList<ExpandMutableTreeNode> moveNodes = new ArrayList<>();
ArrayList<ExpandMutableTreeNode> lockedNodes = new ArrayList<>();
for (ExpandMutableTreeNode treeNode : getFileTree().getSelectedTreeNodes()) {
FileOperationHelper.getInstance().checkFreeOrLock(treeNode, moveNodes, lockedNodes);
}
if (!lockedNodes.isEmpty()) {
// 提醒被锁定模板无法移动
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Unable_Move_Locked_File"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return;
}
new TemplateMoveDialog();
}
}
private class TemplateMoveDialog extends JDialog {
private static final String DIR = "dir";
private TemplateDirTreeSearchPane searchPane;
private TemplateDirTreePane dirTreePane;
private UIButton confirmButton;
private String targetFile;
public TemplateMoveDialog() {
super(DesignerContext.getDesignerFrame(), true);
this.setLayout(new BorderLayout());
searchPane = new TemplateDirTreeSearchPane();
add(searchPane, BorderLayout.NORTH);
CardLayout card;
JPanel cardPane = new JPanel(card = new CardLayout());
cardPane.add(TemplateDirTreePane.getInstance(), DIR);
dirTreePane = TemplateDirTreePane.getInstance();
card.show(cardPane, DIR);
add(cardPane, BorderLayout.CENTER);
cardPane.setBorder(BorderFactory.createEmptyBorder(10, 15, 0, 10));
dirTreePane.refresh();
// 确认按钮,默认就可用
confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Confirm"));
confirmButton.setPreferredSize(new Dimension(60, 25));
confirmButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
confirmClose();
}
});
confirmButton.setEnabled(true);
// 取消按钮
UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel"));
cancelButton.setPreferredSize(new Dimension(60, 25));
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0));
bottomPanel.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 10));
bottomPanel.add(confirmButton);
bottomPanel.add(cancelButton);
this.add(bottomPanel, BorderLayout.SOUTH);
this.setSize(new Dimension(600, 400));
this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Move"));
this.setResizable(false);
this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
GUICoreUtils.centerWindow(this);
this.setVisible(true);
}
private void confirmClose() {
//获取目录树中所选中的文件,并判断是否有权限
if (!checkBeforeMove()) {
return;
}
boolean moveSuccess = doMove();
dispose();
if (moveSuccess) {
ToastMsgDialog dialog = DesignerToastMsgUtil.createPromptDialog(Toolkit.i18nText("Fine-Design_Basic_Template_Moved_Success"));
dialog.setVisible(true);
DesignerFrameFileDealerPane.getInstance().getSelectedOperation().refresh();
LocateAction.gotoEditingTemplateLeaf(targetFile);
}
}
private boolean checkBeforeMove() {
if (getDirTree().getSelectionCount() != 0 && !TemplateDirTreePane.getInstance().selectedAccess()) {
FineJOptionPane.showMessageDialog(this,
Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return false;
}
if (TemplateUtils.checkSelectedTemplateIsEditing()) {
return FineJOptionPane.showConfirmDialog(this,
Toolkit.i18nText("Fine-Design_Basic_Template_Is_Editing"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
YES_NO_OPTION) == JOptionPane.YES_OPTION;
}
return true;
}
private boolean doMove() {
FileNode fileNode = getDirTree().getSelectedFileNode();
ExpandMutableTreeNode rootTreeNode = (ExpandMutableTreeNode) getDirTree().getModel().getRoot();
fileNode = fileNode == null ? (FileNode) rootTreeNode.getUserObject() : fileNode;
boolean moveSuccess = true;
try {
//待移动的文件可以有多个
ExpandMutableTreeNode[] sourceSelected = getFileTree().getSelectedTreeNodes();
for (ExpandMutableTreeNode treeNode : sourceSelected) {
FileNode sourceFileNode = (FileNode) treeNode.getUserObject();
targetFile = FileOperationHelper.getInstance().moveFile(sourceFileNode, fileNode.getEnvPath());
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
FineJOptionPane.showMessageDialog(this,
Toolkit.i18nText("Fine-Design_Basic_Template_Moved_Fail"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
moveSuccess = false;
}
return moveSuccess;
}
@Override
public void dispose() {
TemplateDirTreeSearchManager.getInstance().outOfSearchMode();
super.dispose();
}
}
/**
* 黏贴时确定黏贴的目录
*
* @return
*/
private String getTargetDir() {
int count = getFileTree().getSelectionCount();
String targetDir;
if (count == 0) {
targetDir = ProjectConstants.REPORTLETS_NAME;
} else {
FileNode fileNode = getFileTree().getSelectedFileNode();
targetDir = fileNode.getParent();
if (fileNode.isDirectory()) {
targetDir = StableUtils.pathJoin(targetDir, fileNode.getName());
}
}
return targetDir;
}
}

208
designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java

@ -0,0 +1,208 @@
package com.fr.design.file;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrameFileDealerPane;
import com.fr.design.mainframe.vcs.common.VcsHelper;
import com.fr.file.FileNodeFILE;
import com.fr.file.filetree.FileNode;
import com.fr.general.ComparatorUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.ArrayUtils;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import com.fr.stable.project.ProjectConstants;
import com.fr.workspace.WorkContext;
import com.fr.workspace.resource.ResourceIOException;
import java.util.ArrayList;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
/**
* 文件操作的辅助类
*/
public class FileOperationHelper {
private static final FileOperationHelper INSTANCE = new FileOperationHelper();
public static FileOperationHelper getInstance() {
return INSTANCE;
}
public String moveFile(FileNode sourceFileNode, String targetDir) {
String targetPath = copyFileAndVcs(sourceFileNode, targetDir);
FileNodeFILE nodeFILE = new FileNodeFILE(sourceFileNode);
if (nodeFILE.exists()) {
if (TemplateResourceManager.getResource().delete(nodeFILE)) {
HistoryTemplateListCache.getInstance().deleteFile(nodeFILE);
FineLoggerFactory.getLogger().info("template {} move to {} success.", sourceFileNode.getEnvPath(), targetDir);
} else {
//删除源文件失败,将复制过去的文件删掉
TemplateResourceManager.getResource().delete(new FileNodeFILE(new FileNode(targetPath, sourceFileNode.isDirectory())));
FineLoggerFactory.getLogger().error("template {} move to {} failed.", sourceFileNode.getEnvPath(), targetDir);
throw new ResourceIOException(String.format("template %s move to %s failed", sourceFileNode.getEnvPath(), targetDir));
}
}
return targetPath;
}
/**
* 拷贝文件的同时拷贝对应的版本控制文件
* @param sourceFile 源文件或目录
* @param targetDir 目标目录
* @return 复制后的目标文件的路径
*/
public String copyFileAndVcs(FileNode sourceFile, String targetDir) {
return copyFile(sourceFile, targetDir, true);
}
/**
* 只拷贝文件, 不拷贝对应的版本控制文件
* @param sourceFile 源文件或目录
* @param targetDir 目标目录
* @return 复制后的目标文件的路径
*/
public String copyFile(FileNode sourceFile, String targetDir) {
return copyFile(sourceFile, targetDir, false);
}
/**
* 检测节点是否被锁住了
* @param node 待检测节点
* @param dNodes 没有锁住的节点集合
* @param lNodes 锁住的节点集合
* @return 是否存在被锁住的文件
*/
public boolean checkFreeOrLock(ExpandMutableTreeNode node, ArrayList<ExpandMutableTreeNode> dNodes, ArrayList<ExpandMutableTreeNode> lNodes) {
// 自己没锁
boolean selfEmptyLock = false;
boolean dir = false;
Object userObj = node.getUserObject();
if (userObj instanceof FileNode) {
FileNode fileNode = (FileNode) userObj;
String lock = fileNode.getLock();
selfEmptyLock = lock == null || fileNode.getUserID().equals(lock);
dir = fileNode.isDirectory();
}
if (!dir) {
if (selfEmptyLock) {
dNodes.add(node);
} else {
lNodes.add(node);
}
return selfEmptyLock;
}
return checkChildNode(node, dNodes, lNodes, selfEmptyLock);
}
private boolean checkChildNode(ExpandMutableTreeNode node, ArrayList<ExpandMutableTreeNode> dNodes, ArrayList<ExpandMutableTreeNode> lNodes, boolean selfEmptyLock) {
ExpandMutableTreeNode[] children = TemplateTreePane.getInstance().getTemplateFileTree().loadChildTreeNodes(node);
boolean childrenEmptyLock = true;
for (ExpandMutableTreeNode child : children) {
childrenEmptyLock = checkFreeOrLock(child, dNodes, lNodes) && childrenEmptyLock;
}
boolean emptyLock = childrenEmptyLock && selfEmptyLock;
if (emptyLock) {
dNodes.add(node);
} else {
lNodes.add(node);
}
return emptyLock;
}
private String copyFile(FileNode sourceFile, String targetDir, boolean withCopyVcs) {
String sourcePath = sourceFile.getEnvPath();
if (!TemplateResourceManager.getResource().exist(sourcePath)) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Source_File_Not_Exist", sourcePath),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return StringUtils.EMPTY;
}
String name = getNoRepeatedName4Paste(targetDir, sourceFile.getName());
String targetFile = StableUtils.pathJoin(targetDir, name);
if (sourceFile.isDirectory()) {
copyDir(sourcePath, targetFile, withCopyVcs);
} else {
copyFile(sourcePath, targetFile, withCopyVcs);
}
return targetFile;
}
private void copyDir(String sourceDir, String targetDir, boolean withCopyVcs) {
FileNode[] fileNodes = TemplateTreePane.getInstance().getTemplateFileTree().listFile(sourceDir);
if (ArrayUtils.isEmpty(fileNodes)) {
//空目录:相当于新建一个目录
if (!DesignerFrameFileDealerPane.getInstance().getSelectedOperation().mkdir(targetDir)) {
throw new ResourceIOException(String.format("copy dir failed: from %s to %s.", sourceDir, targetDir));
}
return;
}
for (FileNode fileNode : fileNodes) {
if (fileNode.isDirectory()) {
copyDir(StableUtils.pathJoin(fileNode.getParent(), fileNode.getName()), StableUtils.pathJoin(targetDir, fileNode.getName()), withCopyVcs);
} else {
copyFile(StableUtils.pathJoin(sourceDir, fileNode.getName()), StableUtils.pathJoin(targetDir, fileNode.getName()), withCopyVcs);
}
}
}
private void copyFile(String sourcePath, String targetPath, boolean withCopyVcs) {
//检查源文件是不是还存在
if (!WorkContext.getWorkResource().exist(sourcePath)) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Source_File_Not_Exist", sourcePath),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
} else {
if (!TemplateResourceManager.getResource().copy(sourcePath, targetPath)) {
throw new ResourceIOException(String.format("copy file failed, from %s to %s", sourcePath, targetPath));
} else if (withCopyVcs){
sourcePath = sourcePath.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY);
targetPath = targetPath.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY);
VcsHelper.getInstance().moveVcs(sourcePath, targetPath);
}
}
}
/**
* 重名处理
*
* @param targetDir
* @param oldName
* @return
*/
private String getNoRepeatedName4Paste(String targetDir, String oldName) {
while (isNameRepeaded(targetDir, oldName)) {
int index = oldName.lastIndexOf(".");
if (index > 0) {
String oName = oldName.substring(0, index);
oName = oName + Toolkit.i18nText("Fine-Design_Table_Data_Copy_Of_Table_Data");
oldName = oName.concat(oldName.substring(index));
} else {
//目录重名
oldName = oldName + Toolkit.i18nText("Fine-Design_Table_Data_Copy_Of_Table_Data");
}
}
return oldName;
}
private boolean isNameRepeaded(String targetDir, String name) {
FileNode[] fileNodes = TemplateTreePane.getInstance().getTemplateFileTree().listFile(targetDir);
for (int i = 0; i < fileNodes.length; i++) {
if (ComparatorUtils.equals(name, fileNodes[i].getName())) {
return true;
}
}
return false;
}
}

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

@ -29,6 +29,11 @@ public interface FileOperations {
*/
void refresh();
/**
* 刷新父目录
*/
void refreshParent();
/**
* 删除文件
*/
@ -82,7 +87,8 @@ public interface FileOperations {
*
* @param newName 原名
* @param suffix 后缀名
* @param baseOnSelf 检验目录时是基于自身目录的子节点还是基于父目录的子节点进行校验
* @return 是否存在
*/
boolean duplicated(String newName, String suffix);
boolean duplicated(String newName, String suffix, boolean baseOnSelf);
}

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

@ -8,6 +8,7 @@ import com.fr.design.data.DesignTableDataManager;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrameFileDealerPane;
import com.fr.design.mainframe.JNullTemplate;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.JVirtualTemplate;
import com.fr.design.ui.util.UIUtil;
@ -19,6 +20,7 @@ import com.fr.plugin.context.PluginContext;
import com.fr.stable.CoreConstants;
import com.fr.stable.StringUtils;
import com.fr.third.org.apache.commons.io.FilenameUtils;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
@ -26,7 +28,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
/**
* 历史模板缓存
@ -97,8 +98,14 @@ public class HistoryTemplateListCache implements CallbackEvent {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
/**
* 需要使用 {@link JTemplate#isValid(JTemplate)} 来判断空
*
* @return 当前正在编辑的模板
*/
@Nullable
public JTemplate<?, ?> getCurrentEditingTemplate() {
return this.editingTemplate;
}
@ -109,8 +116,11 @@ public class HistoryTemplateListCache implements CallbackEvent {
*/
public void setCurrentEditingTemplate(JTemplate<?, ?> jt) {
this.editingTemplate = jt;
if (!JTemplate.isValid(jt)) {
return;
}
//如果当前历史面板中没有
if (contains(jt) == -1) {
addHistory();
}
@ -303,7 +313,7 @@ public class HistoryTemplateListCache implements CallbackEvent {
JTemplate<?, ?> template;
template = this.getCurrentEditingTemplate();
if (template != null) {
if (template != null && !(template instanceof JNullTemplate)) {
String editingPath = FilenameUtils.standard(template.getEditingFILE().getPath());
if (isDir ? editingPath.contains(from + CoreConstants.SEPARATOR) : editingPath.equals(from)) {
FILE renameFile = template.getEditingFILE();

200
designer-base/src/main/java/com/fr/design/file/MutilTempalteTabPane.java

@ -4,14 +4,18 @@ package com.fr.design.file;
import com.fr.base.BaseUtils;
import com.fr.base.GraphHelper;
import com.fr.base.vcs.DesignerMode;
import com.fr.design.actions.UpdateAction;
import com.fr.design.actions.file.LocateAction;
import com.fr.design.constants.UIConstants;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.gui.imenu.UIMenuItem;
import com.fr.design.gui.imenu.UIPopupMenu;
import com.fr.design.gui.imenu.UIScrollPopUpMenu;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.TemplateSavingChecker;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.design.utils.DesignUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.design.utils.gui.GUIPaintUtils;
@ -24,6 +28,8 @@ import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.Constants;
import com.fr.third.javax.annotation.Nonnull;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.lock.TplOperator;
import javax.swing.BorderFactory;
import javax.swing.ButtonModel;
@ -35,7 +41,9 @@ import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.MenuElement;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicMenuItemUI;
import java.awt.AWTEvent;
import java.awt.AlphaComposite;
@ -49,6 +57,7 @@ import java.awt.RenderingHints;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
@ -59,6 +68,11 @@ import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D;
import java.util.List;
import static com.fr.design.dialog.FineJOptionPane.showConfirmDialog;
import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
import static javax.swing.JOptionPane.OK_OPTION;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
/**
* Author : daisy
* Date: 13-8-5
@ -160,6 +174,192 @@ public class MutilTempalteTabPane extends JComponent {
};
java.awt.Toolkit.getDefaultToolkit().addAWTEventListener(awt, AWTEvent.MOUSE_EVENT_MASK);
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
int tplIndex = getTemplateIndex(e.getX());
if (tplIndex > -1) {
UIPopupMenu menu = new UIPopupMenu();
menu.setBorder(BorderFactory.createEmptyBorder(-3, 3, 3, 0));
for (CloseOption option : CloseOption.values()) {
menu.add(new UIMenuItem(new RightMenuCloseAction(option, tplIndex)));
}
menu.add(new CloseMenuItemJSeparator());
menu.add(new UIMenuItem(new OpenInTemplateTreeAction(tplIndex)));
int height = 0;
for (MenuElement subElement : menu.getSubElements()) {
if (subElement instanceof CloseMenuItemJSeparator) {
height += 10;
} else {
height += 25;
}
}
menu.setPreferredSize(new Dimension(170, height));
GUICoreUtils.showPopupMenu(menu, MutilTempalteTabPane.getInstance(), e.getX(), MutilTempalteTabPane.getInstance().getY() - 1 + MutilTempalteTabPane.getInstance().getHeight());
}
}
}
});
}
enum CloseOption {
Left(Toolkit.i18nText("Fine-Design_Close_templates_To_The_Left")) {
@Override
boolean shouldClose(int tplIndex, int i) {
return i < tplIndex;
}
},
Right(Toolkit.i18nText("Fine-Design_Close_templates_To_The_Right")) {
@Override
boolean shouldClose(int tplIndex, int i) {
return i > tplIndex;
}
},
All(Toolkit.i18nText("Fine-Design_Close_All_templates")),
Others(Toolkit.i18nText("Fine-Design_Close_Other_templates")) {
@Override
boolean shouldClose(int tplIndex, int i) {
return i != tplIndex;
}
};
String optionName;
CloseOption(String optionName) {
this.optionName = optionName;
}
boolean shouldClose(int tplIndex, int i) {
return true;
}
}
private static class CloseMenuItemJSeparator extends JSeparator {
@Override
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
d.height = 1;
return d;
}
@Override
public Color getForeground() {
return UIConstants.PRESSED_DARK_GRAY;
}
}
private class OpenInTemplateTreeAction extends LocateAction {
int tplIndex;
public OpenInTemplateTreeAction(int tplIndex) {
this.tplIndex = tplIndex;
this.setName(Toolkit.i18nText("Fine-Design_Open_In_Template_Tree"));
}
@Override
public void actionPerformed(ActionEvent e) {
//处于搜索模式时,先退出搜索模式,再定位
if (TemplateTreeSearchManager.getInstance().isInSearchMode()) {
TemplateTreeSearchManager.getInstance().outOfSearchMode();
TemplateTreePane.getInstance().refreshDockingView();
}
JTemplate<?, ?> template = openedTemplate.get(this.tplIndex);
locateTemplate(template);
}
private void locateTemplate(JTemplate<?, ?> template) {
FILE currentTemplate = template.getEditingFILE();
//模板不属于当前环境,跟预览一样先提示保存,再定位模板
if (!currentTemplate.exists()) {
int selVal = showConfirmDialog(
DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Web_Preview_Message"),
Toolkit.i18nText("Fine-Design_Basic_Preview_Tool_Tips"),
OK_CANCEL_OPTION,
WARNING_MESSAGE
);
if (OK_OPTION == selVal) {
CallbackSaveWorker worker = template.saveAs();
worker.start(template.getRuntimeId());
worker.addSuccessCallback(new Runnable() {
@Override
public void run() {
gotoEditingTemplateLeaf(template.getPath());
}
});
}
} else {
gotoEditingTemplateLeaf(template.getPath());
}
}
}
private class RightMenuCloseAction extends UpdateAction {
CloseOption option;
int tplIndex = -1;
public RightMenuCloseAction(CloseOption option, int tplIndex) {
this.option = option;
this.setName(option.optionName);
this.tplIndex = tplIndex;
}
@Override
public void actionPerformed(ActionEvent e) {
SaveSomeTemplatePane saveSomeTempaltePane = new SaveSomeTemplatePane(false);
if (saveSomeTempaltePane.showSavePane()) {
JTemplate<?, ?>[] templates = new JTemplate<?, ?>[openedTemplate.size()];
for (int i = 0; i < openedTemplate.size(); i++) {
templates[i] = openedTemplate.get(i);
}
JTemplate<?, ?> currentTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
closeTemplate(templates, currentTemplate);
if (option == CloseOption.All) {
DesignerContext.getDesignerFrame().addAndActivateJTemplate();
} else {
DesignerContext.getDesignerFrame().activateJTemplate(currentTemplate);
}
MutilTempalteTabPane.getInstance().repaint();
}
}
private void closeTemplate(JTemplate<?, ?>[] templates, JTemplate<?, ?> currentTemplate) {
for (int i = 0; i < templates.length; i++) {
if (option.shouldClose(tplIndex, i)) {
JTemplate<?, ?> jTemplate = templates[i];
if (jTemplate == currentTemplate) {
currentTemplate = option == CloseOption.All ? null : templates[tplIndex];
}
//判断关闭的模板是不是格式刷的被参照的模板
openedTemplate.remove(jTemplate);
if (jTemplate != currentTemplate) {
MutilTempalteTabPane.getInstance().closeFormat(jTemplate);
HistoryTemplateListCache.getInstance().closeSelectedReport(jTemplate);
closeAndFreeLock(jTemplate);
}
}
}
}
private void closeAndFreeLock(@Nonnull JTemplate<?, ?> template) {
FILE file = template.getEditingFILE();
// 只有是环境内的文件,才执行释放锁
if (file != null && file.isEnvFile()) {
// release lock
WorkContext.getCurrent().get(TplOperator.class).closeAndFreeFile(file.getPath());
}
}
}
public JTemplate getSelectedFile() {

82
designer-base/src/main/java/com/fr/design/file/TemplateDirTreePane.java

@ -0,0 +1,82 @@
package com.fr.design.file;
import com.fr.base.FRContext;
import com.fr.design.gui.itree.filetree.TemplateDirTree;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.DesignerFrameFileDealerPane;
import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateDirSearchRemindPane;
import com.fr.file.filetree.IOFileNodeFilter;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.ArrayUtils;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.tree.TreePath;
import java.awt.BorderLayout;
import java.awt.Color;
/**
* 目录树面板
*/
public class TemplateDirTreePane extends JPanel {
public static TemplateDirTreePane getInstance() {
return TemplateDirTreePane.HOLDER.singleton;
}
private static class HOLDER {
private static TemplateDirTreePane singleton = new TemplateDirTreePane();
}
private TemplateDirTree templateDirTree;
private TemplateDirSearchRemindPane remindPane;
public TemplateDirTreePane() {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
this.setBorder(BorderFactory.createLineBorder(Color.gray));
templateDirTree = new TemplateDirTree();
remindPane = new TemplateDirSearchRemindPane(getTemplateDirTree());
this.add(remindPane, BorderLayout.CENTER);
}
public TemplateDirTree getTemplateDirTree() {
return this.templateDirTree;
}
/**
* 判断所选的目录是否有权限
*
* @return
*/
public boolean selectedAccess() {
TreePath[] selectedTreePaths = templateDirTree.getSelectionPaths();
if (ArrayUtils.isEmpty(selectedTreePaths)) {
return false;
}
// 选中的是文件夹
TreePath treePath = selectedTreePaths[0];
ExpandMutableTreeNode currentTreeNode = (ExpandMutableTreeNode) treePath.getLastPathComponent();
return currentTreeNode != null && currentTreeNode.hasFullAuthority();
}
public void refresh() {
// 刷新远程文件夹权限
NodeAuthProcessor.getInstance().refresh();
templateDirTree.refresh();
DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(null);
FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_File_Tree_Refresh_Successfully") + "!");
}
/**
* 刷新
*/
public void refreshDockingView() {
templateDirTree.setFileNodeFilter(new IOFileNodeFilter(FRContext.getFileNodes().getSupportedTypes()));
templateDirTree.refreshEnv();
}
}

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

@ -67,5 +67,11 @@ public interface TemplateResource {
*/
boolean mkdir(String path);
/**
* 复制模板
* @param from 源模板路径
* @param to 目标模板路径
* @return
*/
boolean copy(String from, String to);
}

125
designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java

@ -7,7 +7,6 @@ import com.fr.base.FRContext;
import com.fr.design.ExtraDesignClassManager;
import com.fr.design.dialog.FineJOptionPane;
import com.fr.design.fun.TemplateTreeDefineProcessor;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.gui.itree.filetree.TemplateFileTree;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.i18n.Toolkit;
@ -17,6 +16,8 @@ import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrameFileDealerPane;
import com.fr.design.lock.LockInfoDialog;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateSearchRemindPane;
import com.fr.file.FILE;
import com.fr.file.FileNodeFILE;
import com.fr.file.filetree.FileNode;
@ -57,6 +58,9 @@ import java.util.Enumeration;
import java.util.Objects;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable;
@ -74,19 +78,19 @@ public class TemplateTreePane extends JPanel implements FileOperations {
}
private TemplateFileTree reportletsTree;
private TemplateSearchRemindPane remindPane;
private FileToolbarStateChangeListener toolBarStateChangeListener;
private TemplateTreePane() {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
this.setPreferredSize(new Dimension(250, super.getPreferredSize().height));
JPanel contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane();
this.add(contentPane, BorderLayout.CENTER);
reportletsTree = new TemplateFileTree();
remindPane = new TemplateSearchRemindPane(getTemplateFileTree());
this.add(remindPane, BorderLayout.CENTER);
ToolTipManager.sharedInstance().registerComponent(reportletsTree);
UIScrollPane scrollPane = new UIScrollPane(reportletsTree);
scrollPane.setBorder(null);
contentPane.add(scrollPane, BorderLayout.CENTER);
FileLockStateObservable.getInstance().addObserver(new Observer() {
@Override
@ -113,6 +117,8 @@ public class TemplateTreePane extends JPanel implements FileOperations {
TemplateTreeDefineProcessor processor = ExtraDesignClassManager.getInstance().getSingle(TemplateTreeDefineProcessor.XML_TAG);
if (processor != null) {
processor.rightClickAction(e);
} else {
DefaultTemplateTreeDefineProcessor.getInstance().rightClickAction(e);
}
}
}
@ -291,6 +297,23 @@ public class TemplateTreePane extends JPanel implements FileOperations {
FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_File_Tree_Refresh_Successfully") + "!");
}
/**
* 刷新父目录
*/
@Override
public void refreshParent() {
// 刷新远程文件夹权限
NodeAuthProcessor.getInstance().refresh();
if (reportletsTree.getSelectionCount() == 0) {
//没选中文件刷新根目录
reportletsTree.refresh();
}
reportletsTree.refreshParent(Objects.requireNonNull(reportletsTree.getSelectionPath()));
DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(null);
FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_File_Tree_Refresh_Successfully") + "!");
}
/**
* 删除文件
* 文件夹和文件均可删除
@ -307,7 +330,7 @@ public class TemplateTreePane extends JPanel implements FileOperations {
ArrayList<ExpandMutableTreeNode> deletableNodes = new ArrayList<>();
ArrayList<ExpandMutableTreeNode> lockedNodes = new ArrayList<>();
for (ExpandMutableTreeNode treeNode : treeNodes) {
checkFreeOrLock(treeNode, deletableNodes, lockedNodes);
FileOperationHelper.getInstance().checkFreeOrLock(treeNode, deletableNodes, lockedNodes);
}
if (lockedNodes.isEmpty()) {
@ -362,16 +385,23 @@ public class TemplateTreePane extends JPanel implements FileOperations {
}
}
}
refreshAfterDelete();
Set<FileNode> deletedFileNode = deletableNodes.stream().map(treeNode -> (FileNode) treeNode.getUserObject()).collect(Collectors.toSet());
refreshAfterDelete(deletedFileNode);
}
private void refreshAfterDelete() {
TreePath[] paths = reportletsTree.getSelectionPaths();
if (paths == null) {
reportletsTree.refresh();
} else {
for (TreePath path : Objects.requireNonNull(reportletsTree.getSelectionPaths())) {
reportletsTree.refreshParent(path);
private void refreshAfterDelete(Set<FileNode> deletedPaths) {
if (TemplateTreeSearchManager.getInstance().isInSearchMode()) {
TemplateTreeSearchManager.getInstance().deleteMatchedNode(deletedPaths);
TemplateTreeSearchManager.getInstance().updateTemplateTree();
TemplateTreeSearchManager.getInstance().setRefreshing(false);
} else {
TreePath[] paths = reportletsTree.getSelectionPaths();
if (paths == null) {
reportletsTree.refresh();
} else {
for (TreePath path : Objects.requireNonNull(reportletsTree.getSelectionPaths())) {
reportletsTree.refreshParent(path);
}
}
}
}
@ -395,41 +425,6 @@ public class TemplateTreePane extends JPanel implements FileOperations {
return success;
}
private boolean checkFreeOrLock(ExpandMutableTreeNode node, ArrayList<ExpandMutableTreeNode> dNodes, ArrayList<ExpandMutableTreeNode> lNodes) {
// 自己没锁
boolean selfEmptyLock = false;
Object userObj = node.getUserObject();
if (userObj instanceof FileNode) {
String lock = ((FileNode) userObj).getLock();
selfEmptyLock = lock == null || ((FileNode) userObj).getUserID().equals(lock);
}
if (node.isLeaf()) {
if (selfEmptyLock) {
dNodes.add(node);
} else {
lNodes.add(node);
}
return selfEmptyLock;
}
ExpandMutableTreeNode[] children = reportletsTree.loadChildTreeNodes(node);
boolean childrenEmptyLock = true;
for (ExpandMutableTreeNode child : children) {
childrenEmptyLock = checkFreeOrLock(child, dNodes, lNodes) && childrenEmptyLock;
}
boolean emptyLock = childrenEmptyLock && selfEmptyLock;
if (emptyLock) {
dNodes.add(node);
} else {
lNodes.add(node);
}
return emptyLock;
}
@Override
public void lockFile() {
@ -473,7 +468,7 @@ public class TemplateTreePane extends JPanel implements FileOperations {
ArrayList<ExpandMutableTreeNode> unlockedNodes = new ArrayList<>();
ArrayList<ExpandMutableTreeNode> lockedNodes = new ArrayList<>();
for (ExpandMutableTreeNode treeNode : treeNodes) {
checkFreeOrLock(treeNode, unlockedNodes, lockedNodes);
FileOperationHelper.getInstance().checkFreeOrLock(treeNode, unlockedNodes, lockedNodes);
}
if (!lockedNodes.isEmpty()) {
@ -508,32 +503,42 @@ public class TemplateTreePane extends JPanel implements FileOperations {
*
* @param newName 原名
* @param suffix 后缀名
* @param baseOnSelf 检验目录时是基于自身目录的子节点还是基于父目录的子节点进行校验
* @return 是否有重名的
*/
@Override
public boolean duplicated(String newName, String suffix) {
public boolean duplicated(String newName, String suffix, boolean baseOnSelf) {
// 选中的节点
TreePath treePath = reportletsTree.getSelectionPath();
if (treePath == null) {
return false;
}
DefaultMutableTreeNode currentTreeNode = (DefaultMutableTreeNode) treePath.getLastPathComponent();
TreeNode parentTreeNode = currentTreeNode.getParent();
Enumeration children = parentTreeNode.children();
boolean result = false;
Enumeration children = getChild(treePath, baseOnSelf);
while (children.hasMoreElements()) {
DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) children.nextElement();
Object object = childNode.getUserObject();
if (object instanceof FileNode) {
if (ComparatorUtils.equals(((FileNode) object).getName(), newName + suffix)) {
return true;
result = true;
}
} else {
return false;
}
}
return false;
return result;
}
private Enumeration getChild(TreePath treePath, boolean baseOnSelf) {
DefaultMutableTreeNode currentTreeNode = (DefaultMutableTreeNode) treePath.getLastPathComponent();
Enumeration children;
//现在可以在目录下创建目录,重命名时是基于所选节点的父目录的子目录进行校验,目录下新建子目录时,基于所选目录的子目录进行校验
if (reportletsTree.getSelectedFileNode().isDirectory() && baseOnSelf) {
children = currentTreeNode.children();
} else {
TreeNode parentTreeNode = currentTreeNode.getParent();
children = parentTreeNode.children();
}
return children;
}
}

11
designer-base/src/main/java/com/fr/design/file/impl/AbstractTemplateResource.java

@ -2,12 +2,7 @@ package com.fr.design.file.impl;
import com.fr.design.file.TemplateResource;
import com.fr.file.FILE;
import com.fr.workspace.WorkContext;
import com.fr.workspace.server.lock.TplOperator;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @author hades
@ -16,4 +11,10 @@ import java.io.OutputStream;
*/
public abstract class AbstractTemplateResource implements TemplateResource {
@Override
public boolean copy(String from, String to) {
byte[] data = WorkContext.getWorkResource().readFully(from);
WorkContext.getWorkResource().write(to, data);
return WorkContext.getWorkResource().length(to) > 0;
}
}

135
designer-base/src/main/java/com/fr/design/gui/date/UICalendarPanel.java

@ -2,6 +2,8 @@ package com.fr.design.gui.date;
import com.fr.base.BaseUtils;
import com.fr.base.background.GradientBackground;
import com.fr.design.carton.MonthlyCartonFile;
import com.fr.design.carton.SwitchForSwingChecker;
import com.fr.design.constants.UIConstants;
import com.fr.design.gui.ibutton.UIButton;
import com.fr.design.gui.ilable.UILabel;
@ -9,7 +11,10 @@ import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.utils.DesignUtils;
import com.fr.design.utils.gui.GUIPaintUtils;
import com.fr.general.GeneralUtils;
import com.fr.stable.Constants;
import com.fr.stable.ProductConstantsBase;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import javax.swing.BorderFactory;
@ -40,16 +45,20 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.RoundRectangle2D;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
public class UICalendarPanel extends JPanel {
private static final Font FONT_UI = DesignUtils.getDefaultGUIFont().applySize(12);
private static final Font FONT_BLACK = new Font(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Black_Font"), Font.PLAIN, 12);
private static final int WEEKDAY_COUNT = 7;
private static final int TOTAL_DAYS_COUNT = 42;
//卡顿日志所在地址
private static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log");
protected Color selectedBackground;
protected Color selectedForeground;
protected Color background;
@ -63,12 +72,27 @@ public class UICalendarPanel extends JPanel {
private boolean isSupportDateChangeListener = false;
private java.util.Date selectedDate = null;
private boolean isTimePicker;
private final Color LABEL_FORGE_GROUND = new Color(0x6F6F6);
private MouseListener todayListener;
private UIDayLabel lbToday;
/**
* 一个int类型用于判断日历是否是专门用于处理卡顿的设计器反馈箱中的日历
* 0表示是
* -1表示不是
*/
private boolean speciallyForCarton = false;
/**
* 年月格式
*/
final SimpleDateFormat monthFormat
= new SimpleDateFormat("yyyy-MM");
/**
* 年月格式2
*/
final SimpleDateFormat dayFormat
= new SimpleDateFormat("yyyy-MM-dd");
public UICalendarPanel() {
this(new Date(), false);
}
@ -77,6 +101,14 @@ public class UICalendarPanel extends JPanel {
this(new Date(), isTimerPicker);
}
/**
* 构造函数用于给speciallyForCarton赋值
*/
public UICalendarPanel(boolean isTimePicker, boolean speciallyForCarton) {
this(new Date(), isTimePicker);
this.speciallyForCarton = speciallyForCarton;
initTodayListener();
}
public UICalendarPanel(Date selectedDate, boolean isTimerPicker) {
this.selectedDate = selectedDate;
@ -106,7 +138,12 @@ public class UICalendarPanel extends JPanel {
updateHMS();
}
}
private void initTodayListener() {
if (speciallyForCarton && !SwitchForSwingChecker.isCartonExists()) {
lbToday.setEnabled(false);
lbToday.removeMouseListener(todayListener);
}
}
// << < yyyy/MM/dd > >>
private JPanel createNorthPane() {
JPanel pNorth = FRGUIPaneFactory.createX_AXISBoxInnerContainer_S_Pane();
@ -187,13 +224,13 @@ public class UICalendarPanel extends JPanel {
GradientPane pToday = new GradientPane(new GradientBackground(new Color(0x097BDA), new Color(0x40A3EE), GradientBackground.TOP2BOTTOM), false);
pToday.setPreferredSize(new Dimension(216, 18));
pToday.setLayout(new BorderLayout());
UIDayLabel lbToday = new UIDayLabel(new Date(), false);
lbToday = new UIDayLabel(new Date(), false);
lbToday.setForeground(new Color(0x000000));
lbToday.addMouseListener(createTodayListener(pToday, lbToday));
todayListener = createTodayListener(pToday, lbToday);
lbToday.addMouseListener(todayListener);
pToday.setBackground(new Color(0xF0F0F0));
pToday.add(lbToday, BorderLayout.CENTER);
pCenter.add(pToday, BorderLayout.SOUTH);
return pCenter;
}
@ -288,10 +325,67 @@ public class UICalendarPanel extends JPanel {
};
}
/**
*根据当月获取下个月
* 圈复杂度比较高就单独拿出来了
*/
private int getNextMonth(int month) {
int num = (month + 1) % 12;
return num == 0 ? 12 : num;
}
private int getYearOfNextMonth(int month, int year) {
return year + (month + 1) / 13;
}
/**
* 将配置目录中已有的所有卡顿日志文件的名字如2022-08-09加入到set中
*/
private void addFileIntoSet(Set<String> set, MonthlyCartonFile monthlyCartonFile) {
File currentMonthFile = monthlyCartonFile.getCurrentMonthFile();
File lastMonthFile = monthlyCartonFile.getLastMonthFile();
File nextMonthFile = monthlyCartonFile.getNextMonthFile();
File[] monthFiles = new File[3];
monthFiles[0] = lastMonthFile;
monthFiles[1] = currentMonthFile;
monthFiles[2] = nextMonthFile;
for (File file : monthFiles) {
if (file.exists() && file.isDirectory()) {
File[] files = file.listFiles();
for (File detailFile : files) {
set.add(detailFile.getName());
}
}
}
}
/**
* 给label设置属性
*/
private void setUIDayLabel(UIDayLabel label, boolean isCurrentMonth,
Calendar setupCalendar, Set<String> logSet) {
/**
* 区分开两种panel
*/
if (speciallyForCarton) {
if (!logSet.contains(GeneralUtils.objectToString(dayFormat.format(setupCalendar.getTime())))) {
label.setEnabled(false);
} else {
label.addMouseListener(dayBttListener);
}
} else {
label.addMouseListener(dayBttListener);
label.setEnabled(isCurrentMonth);
}
if (!isCurrentMonth) {
label.setForeground(LABEL_FORGE_GROUND);
}
}
/**
* 更新日期
*/
protected void updateDays() {
/**
* 用于处理卡顿日志日历的一些工具
*/
Set<String> logSet = new HashSet<>();
//更新月份
monthLabel.setText(monthFormat.format(calendar.getTime()));
days.removeAll();
@ -302,8 +396,29 @@ public class UICalendarPanel extends JPanel {
setupCalendar.set(Calendar.DAY_OF_MONTH, 1);
int first = setupCalendar.get(Calendar.DAY_OF_WEEK);
setupCalendar.add(Calendar.DATE, -first);
boolean isCurrentMonth = false;
if (speciallyForCarton) {
Calendar clone = (Calendar)setupCalendar.clone();
clone.add(Calendar.DATE, 1);
int year = clone.get(Calendar.YEAR);
//日历获取的月份是从0开始的
int month = clone.get(Calendar.MONTH) + 1;
//往后推一个月的年月份
int month2 = getNextMonth(month);
int year2 = getYearOfNextMonth(month, year);
//再往后推一个月的年月份
int month3 = getNextMonth(month2);
int year3 = getYearOfNextMonth(month2, year2);
//文件地址如:"C:\Users\23131\.FineReport110\journal_log\2022\month-9\2022-09-01"
MonthlyCartonFile monthlyCartonFile = new MonthlyCartonFile();
monthlyCartonFile.setCurrentMonthFile
(new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, String.valueOf(year2), "month-" + month2)));
monthlyCartonFile.setLastMonthFile
(new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, String.valueOf(year), "month-" + month)));
monthlyCartonFile.setNextMonthFile
(new File(StableUtils.pathJoin(JOURNAL_FILE_PATH, String.valueOf(year3), "month-" + month3)));
addFileIntoSet(logSet, monthlyCartonFile);
}
for (int i = 0; i < TOTAL_DAYS_COUNT; i++) {
setupCalendar.add(Calendar.DATE, 1);
GradientPane gp = new GradientPane(new GradientBackground(new Color(0xFEFEFE), new Color(0xF3F2F3), GradientBackground.TOP2BOTTOM), true);
@ -313,14 +428,10 @@ public class UICalendarPanel extends JPanel {
UIDayLabel label = new UIDayLabel(setupCalendar.getTime());
label.setHorizontalAlignment(SwingConstants.RIGHT);
label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 9));
label.addMouseListener(dayBttListener);
if ("1".equals(label.getText())) {
isCurrentMonth = !isCurrentMonth;
}
label.setEnabled(isCurrentMonth);
if (!isCurrentMonth) {
label.setForeground(new Color(0x6F6F6));
}
setUIDayLabel(label, isCurrentMonth, setupCalendar, logSet);
//当前选择的日期
if (setupCalendar.get(Calendar.DAY_OF_MONTH) == selectedCalendar.get(Calendar.DAY_OF_MONTH) && isCurrentMonth) {
gp.setGradientBackground(new GradientBackground(new Color(0x097BD9), new Color(0x41A3EE), GradientBackground.TOP2BOTTOM));
@ -534,6 +645,7 @@ public class UICalendarPanel extends JPanel {
this.setLayout(new GridLayout(6, 7, 1, 1));
this.setBackground(new Color(0xFFFFFF));
this.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, new Color(0xDADADA)));
}
public void paint(Graphics g) {
@ -754,7 +866,6 @@ public class UICalendarPanel extends JPanel {
public static void main(String[] args) {
JFrame frame = new JFrame();
UICalendarPanel calendarPanel = new UICalendarPanel();
final UITextField field = new UITextField();
field.setPreferredSize(new Dimension(120, 25));

201
designer-base/src/main/java/com/fr/design/gui/date/UIDatePicker.java

@ -7,6 +7,7 @@ import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.general.ComparatorUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import com.fr.design.carton.FeedbackToolboxDialog;
import javax.swing.BorderFactory;
import javax.swing.JComboBox;
@ -32,6 +33,11 @@ import java.util.Date;
* UIDatePicker
*/
public class UIDatePicker extends UIComboBox implements Serializable {
/**
* 用于记录本datePicker是否是由设计器卡顿优化箱上打开后续要去调用方法
*/
private FeedbackToolboxDialog feedbackToolboxDialog = null;
/**
* 日期格式类型
*/
@ -40,7 +46,7 @@ public class UIDatePicker extends UIComboBox implements Serializable {
public static final int STYLE_CN_DATETIME = 2;
public static final int STYLE_CN_DATETIME1 = 3;
public static final int STYLE_EN_DATE = 4;
public boolean isWillHide = false;
private boolean willHide = false;
/**
* 日期格式类型
*/
@ -67,23 +73,43 @@ public class UIDatePicker extends UIComboBox implements Serializable {
this(formatStyle, new Date());
}
public UIDatePicker(int formatStyle, Date initialDatetime) throws UnsupportedOperationException {
public UIDatePicker(int formatStyle, FeedbackToolboxDialog feedbackToolboxDialog) throws UnsupportedOperationException {
this(formatStyle, new Date(), feedbackToolboxDialog);
}
/**
*
* @param formatStyle
* @param initialDatetime
* @param feedbackToolboxDialog 判断该日历是否由设计器反馈工具箱打开
* @throws UnsupportedOperationException
*/
public UIDatePicker(int formatStyle, Date initialDatetime, FeedbackToolboxDialog feedbackToolboxDialog) throws UnsupportedOperationException {
this.setStyle(formatStyle);
//设置可编辑
this.setEditable(true);
this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
//设置编辑器属性(只能输入正确日期)
JTextField textField = ((JTextField) getEditor().getEditorComponent());
textField.setHorizontalAlignment(SwingConstants.CENTER);
dateDocument = new JDateDocument(textField, this.dateFormat);
if (feedbackToolboxDialog != null) {
dateDocument = new JDateDocument(textField, this.dateFormat, StringUtils.EMPTY);
this.feedbackToolboxDialog = feedbackToolboxDialog;
textField.setHorizontalAlignment(SwingConstants.LEFT);
//设置当前选择日期
this.setSelectedItem(initialDatetime);
} else {
dateDocument = new JDateDocument(textField, this.dateFormat);
this.setSelectedItem(initialDatetime == null ? new Date() : initialDatetime);
textField.setHorizontalAlignment(SwingConstants.CENTER);
}
textField.setDocument(dateDocument);
//设置Model为单值Model
this.setModel(model);
//设置当前选择日期
this.setSelectedItem(initialDatetime == null ? new Date() : initialDatetime);
updateUI();
updateUI();
}
public UIDatePicker(int formatStyle, Date initialDatetime) throws UnsupportedOperationException {
this(formatStyle, initialDatetime, null);
}
/**
@ -149,20 +175,20 @@ public class UIDatePicker extends UIComboBox implements Serializable {
* @return Date
*/
public Date getSelectedDate() throws ParseException {
synchronized (this) {
return dateFormat.parse(getSelectedItem().toString());
}
synchronized (this) {
return dateFormat.parse(getSelectedItem().toString());
}
}
/**
* 设置当前选择的日期
*/
public synchronized void setSelectedDate(Date date) throws ParseException {
if (date == null) {
this.setSelectedItem(null);
} else {
this.setSelectedItem(dateFormat.format(date));
}
if (date == null) {
this.setSelectedItem(null);
} else {
this.setSelectedItem(dateFormat.format(date));
}
}
@Override
@ -182,34 +208,36 @@ public class UIDatePicker extends UIComboBox implements Serializable {
*/
class DatePopup extends BasicComboPopup implements ChangeListener {
UICalendarPanel calendarPanel = null;
public DatePopup(JComboBox box) {
super(box);
setLayout(FRGUIPaneFactory.createBorderLayout());
calendarPanel = new UICalendarPanel(formatStyle > 1);
if (feedbackToolboxDialog != null) {
calendarPanel = new UICalendarPanel(formatStyle > 1, true);
} else {
calendarPanel = new UICalendarPanel(formatStyle > 1);
}
calendarPanel.addDateChangeListener(this);
add(calendarPanel, BorderLayout.CENTER);
setBorder(BorderFactory.createEmptyBorder());
}
@Override
public void hide() {
if (isWillHide) {
super.hide();
}
}
public void hide() {
if (willHide) {
super.hide();
}
}
@Override
public void show() {
if (isWillHide || UIDatePicker.this.isEnabled() == false) {
return;
}
if (calendarPanel != null) {
calendarPanel.resetHMSPaneSelectedNumberField();
}
super.show();
}
@Override
public void show() {
if (willHide || UIDatePicker.this.isEnabled() == false) {
return;
}
if (calendarPanel != null) {
calendarPanel.resetHMSPaneSelectedNumberField();
}
super.show();
}
/**
* 显示弹出面板
@ -223,16 +251,16 @@ public class UIDatePicker extends UIComboBox implements Serializable {
&& ComparatorUtils.equals(newValue, Boolean.TRUE)) { //SHOW
try {
String strDate = comboBox.getSelectedItem().toString();
synchronized (this) {
Date selectionDate = new Date();
if (StringUtils.isNotBlank(strDate)) {
synchronized (this) {
Date selectionDate = new Date();
if (StringUtils.isNotBlank(strDate)) {
selectionDate = dateFormat.parse(strDate);
}
calendarPanel.setSelectedDate(selectionDate);
calendarPanel.updateHMS();
}
calendarPanel.updateHMS();
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
} else if (ComparatorUtils.equals(oldValue, Boolean.TRUE)
&& ComparatorUtils.equals(newValue, Boolean.FALSE)) { //HIDE
@ -241,16 +269,21 @@ public class UIDatePicker extends UIComboBox implements Serializable {
super.firePropertyChange(propertyName, oldValue, newValue);
}
@Override
public void stateChanged(ChangeEvent e) {
if (calendarPanel.getSelectedDate() != null && dateFormat != null) {
String strDate = dateFormat.format(calendarPanel.getSelectedDate());
if (comboBox.isEditable() && comboBox.getEditor() != null) {
comboBox.configureEditor(comboBox.getEditor(), strDate);
}
comboBox.setSelectedItem(strDate);
}
comboBox.repaint();
setVisible(false);
if (calendarPanel.getSelectedDate() != null && dateFormat != null) {
String strDate = dateFormat.format(calendarPanel.getSelectedDate());
if (comboBox.isEditable() && comboBox.getEditor() != null) {
comboBox.configureEditor(comboBox.getEditor(), strDate);
}
comboBox.setSelectedItem(strDate);
}
comboBox.repaint();
setVisible(false);
//选择完日期,导出/上传按钮变可用
if (feedbackToolboxDialog != null) {
feedbackToolboxDialog.setSwitches(true);
}
}
}
@ -258,53 +291,53 @@ public class UIDatePicker extends UIComboBox implements Serializable {
protected ComboBoxUI getUIComboBoxUI() {
return new UIComboBoxUI() {
@Override
protected ComboPopup createPopup() {
return new DatePopup(comboBox);
}
@Override
public void mousePressed(MouseEvent e) {
if (UIDatePicker.this.isPopupVisible()) {
isWillHide = true;
UIDatePicker.this.hidePopup();
} else {
isWillHide = false;
UIDatePicker.this.showPopup();
}
}
};
protected ComboPopup createPopup() {
return new DatePopup(comboBox);
}
@Override
public void mousePressed(MouseEvent e) {
if (UIDatePicker.this.isPopupVisible()) {
willHide = true;
UIDatePicker.this.hidePopup();
} else {
willHide = false;
UIDatePicker.this.showPopup();
}
}
};
}
//设置dataFormat
public void setDateFormat(SimpleDateFormat format){
this.dateFormat = format;
}
//获取dateFormat
public SimpleDateFormat getDateFormat(){
return this.dateFormat;
}
public JDateDocument getDateDocument(){
return this.dateDocument;
}
public static void main(String[] args) {
LayoutManager layoutManager = null;
JFrame jf = new JFrame("test");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel content = (JPanel) jf.getContentPane();
content.setLayout(layoutManager);
UIDatePicker bb = new UIDatePicker();
if (args.length != 0) {
bb = new UIDatePicker(STYLE_CN_DATETIME);
}
bb.setEditable(true);
bb.setBounds(20, 20, bb.getPreferredSize().width, bb.getPreferredSize().height);
content.add(bb);
GUICoreUtils.centerWindow(jf);
jf.setSize(400, 400);
jf.setVisible(true);
}
public static void main(String[] args) {
LayoutManager layoutManager = null;
JFrame jf = new JFrame("test");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel content = (JPanel) jf.getContentPane();
content.setLayout(layoutManager);
UIDatePicker bb = new UIDatePicker();
if (args.length != 0) {
bb = new UIDatePicker(STYLE_CN_DATETIME);
}
bb.setEditable(true);
bb.setBounds(20, 20, bb.getPreferredSize().width, bb.getPreferredSize().height);
content.add(bb);
GUICoreUtils.centerWindow(jf);
jf.setSize(400, 400);
jf.setVisible(true);
}
}

73
designer-base/src/main/java/com/fr/design/gui/itree/filetree/EnvFileTree.java

@ -52,40 +52,6 @@ public class EnvFileTree extends RefreshableJTree {
/*一些自己的 init 放在这里,防止直接错误重写了父类的 init 方法导致子类不能使用 CheckBoxTree 的一些特性。*/
this.putClientProperty("JTree.lineStyle", "Angled");
// CellRenderer
// 这里新建一个Label作为render是因为JTree在动态刷新的时候,节点上render画布的的宽度不会变,会使得一部分比较长的数据显示为
DefaultTreeCellRenderer fileTreeCellRenderer = new DefaultTreeCellRenderer() {
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
ExpandMutableTreeNode treeNode = (ExpandMutableTreeNode) value;
Object userObj = treeNode.getUserObject();
if (userObj instanceof FileNode) {
FileNode node = (FileNode) userObj;
String lock = node.getLock();
String name = node.getName();
if (treeNode.hasFullAuthority()) {
if (lock != null && !lock.equals(node.getUserID())) {
name = name + Toolkit.i18nText("Fine-Design_Basic_Template_Status_Locked", "(", ")");
}
this.setIcon(FileTreeIcon.getIcon(node));
} else {
this.setIcon(FileTreeIcon.getFolderHalfImageIcon());
}
this.setText(name);
} else if (userObj == PENDING) {
this.setIcon(null);
this.setText(PENDING.toString());
}
this.setBorder(BorderFactory.createEmptyBorder(1, 0, 1, 0));
this.setBackgroundNonSelectionColor(UIConstants.TREE_BACKGROUND);
this.setTextSelectionColor(Color.WHITE);
this.setBackgroundSelectionColor(UIConstants.FLESH_BLUE);
return this;
}
};
this.setCellRenderer(fileTreeCellRenderer);
this.setRootVisible(false);
@ -93,6 +59,45 @@ public class EnvFileTree extends RefreshableJTree {
this.setEditable(false);
}
// CellRenderer
// 这里新建一个Label作为render是因为JTree在动态刷新的时候,节点上render画布的的宽度不会变,会使得一部分比较长的数据显示为
DefaultTreeCellRenderer fileTreeCellRenderer = new DefaultTreeCellRenderer() {
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
ExpandMutableTreeNode treeNode = (ExpandMutableTreeNode) value;
Object userObj = treeNode.getUserObject();
if (userObj instanceof FileNode) {
FileNode node = (FileNode) userObj;
String lock = node.getLock();
String name = node.getName();
if (treeNode.hasFullAuthority()) {
if (lock != null && !lock.equals(node.getUserID())) {
name = name + Toolkit.i18nText("Fine-Design_Basic_Template_Status_Locked", "(", ")");
}
this.setIcon(FileTreeIcon.getIcon(node));
} else {
this.setIcon(FileTreeIcon.getFolderHalfImageIcon());
}
this.setText(name);
} else if (userObj == PENDING) {
this.setIcon(null);
this.setText(PENDING.toString());
}
this.setBorder(BorderFactory.createEmptyBorder(1, 0, 1, 0));
this.setBackgroundNonSelectionColor(UIConstants.TREE_BACKGROUND);
this.setTextSelectionColor(Color.WHITE);
this.setBackgroundSelectionColor(UIConstants.FLESH_BLUE);
return this;
}
};
public DefaultTreeCellRenderer getFileTreeCellRenderer() {
return fileTreeCellRenderer;
}
private void setTreeRootPath(String path) {
if (path == null) {
path = "";

53
designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateDirTree.java

@ -0,0 +1,53 @@
package com.fr.design.gui.itree.filetree;
import com.fr.base.FRContext;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager;
import com.fr.file.filetree.FileNode;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
/*
* 目录树
*/
public class TemplateDirTree extends TemplateFileTree {
public TemplateDirTree() {
super();
}
/**
* 查找所有目录子节点
*
* @param path
* @return
*/
public FileNode[] listFile(String path) {
return Arrays.stream(FRContext.getFileNodes().list(path)).filter(FileNode::isDirectory).toArray(FileNode[]::new);
}
/**
* 搜索时刷新目录树
* @param root
*/
public void refreshTreeNode4TreeSearch(ExpandMutableTreeNode root) {
if (interceptRefresh(root)) {
return;
}
currentTreeMode.clear();
allTreeNode = TemplateDirTreeSearchManager.getInstance().allFileNodes().entrySet().stream().collect(
Collectors.toMap(Map.Entry::getKey, entry -> fileNodeArray2TreeNodeArray(new FileNode[]{entry.getValue()})[0]));
root.removeAllChildren();
FileNode[] treeNodes = TemplateDirTreeSearchManager.getInstance().matchesNode();
for (FileNode fileNode : treeNodes) {
ExpandMutableTreeNode treeNode = fileNodeArray2TreeNodeArray(new FileNode[]{fileNode})[0];
addToTreeModel(root, treeNode);
}
}
}

134
designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateFileTree.java

@ -6,10 +6,12 @@ import com.fr.design.ExtraDesignClassManager;
import com.fr.design.file.NodeAuthProcessor;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.mainframe.App;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.file.filetree.FileNode;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.ArrayUtils;
import com.fr.stable.StableUtils;
import com.fr.stable.collections.CollectionUtils;
import com.fr.stable.project.ProjectConstants;
import javax.swing.text.Position;
@ -17,15 +19,25 @@ import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/*
* 显示Env下的reportlets目录下面的所有cpt文件
*/
public class TemplateFileTree extends EnvFileTree {
protected Map<String, ExpandMutableTreeNode> allTreeNode = new ConcurrentHashMap<>();
protected Map<String, ExpandMutableTreeNode> calculateNode = new ConcurrentHashMap<>();
protected Map<String, List<String>> currentTreeMode = new ConcurrentHashMap<>();
private static final int MAX_NODE_EXPAND_NUM = 50;
private static final int MAX_MATCHED_NODE_NUM = 500;
public TemplateFileTree() {
super(ProjectConstants.REPORTLETS_NAME, null, null);
}
@ -213,7 +225,7 @@ public class TemplateFileTree extends EnvFileTree {
/*
* 把FileNode[]转成ExpandMutableTreeNode[]
*/
private ExpandMutableTreeNode[] fileNodeArray2TreeNodeArray(FileNode[] fileNodes) {
protected ExpandMutableTreeNode[] fileNodeArray2TreeNodeArray(FileNode[] fileNodes) {
return NodeAuthProcessor.getInstance().parser2TreeNodeArray(fileNodes);
}
@ -251,4 +263,124 @@ public class TemplateFileTree extends EnvFileTree {
return new FileNode[0];
}
/**
* 搜索时更新搜索结果
*/
@Override
public void refresh4TreeSearch() {
ExpandMutableTreeNode root = (ExpandMutableTreeNode) this.getModel().getRoot();
NodeAuthProcessor.getInstance().fixTreeNodeAuth(root);
refreshTreeNode4TreeSearch(root);
sortTreeNode(root);
((DefaultTreeModel) this.getModel()).reload(root);
if (currentTreeMode.keySet().size() < MAX_NODE_EXPAND_NUM || TemplateTreeSearchManager.getInstance().matchesNode().length < MAX_MATCHED_NODE_NUM) {
//要展开的节点比较多的话,全部展开会有性能问题
root.expandCurrentTreeNode(this);
}
}
/**
* 重新对整个目录树排序
*
* @param root 根节点
*/
private void sortTreeNode(ExpandMutableTreeNode root) {
List<ExpandMutableTreeNode> childFileNode = new ArrayList<>();
for (int i = 0; i < root.getChildCount(); i++) {
ExpandMutableTreeNode treeNode = (ExpandMutableTreeNode) root.getChildAt(i);
childFileNode.add(treeNode);
}
childFileNode = childFileNode.stream().sorted(Comparator.comparing(treeNode -> ((FileNode) (treeNode.getUserObject())),
new FileNodeComparator(FileNodeConstants.getSupportFileTypes()))).collect(Collectors.toList());
root.removeAllChildren();
root.addChildTreeNodes(childFileNode.toArray(new ExpandMutableTreeNode[0]));
for (ExpandMutableTreeNode treeNode : childFileNode) {
if (!treeNode.isLeaf()) {
sortTreeNode(treeNode);
}
}
}
protected void refreshTreeNode4TreeSearch(ExpandMutableTreeNode root) {
if (interceptRefresh(root)) {
return;
}
if (!TemplateTreeSearchManager.getInstance().isRefreshing()) {
currentTreeMode.clear();
calculateNode.clear();
allTreeNode = TemplateTreeSearchManager.getInstance().allFileNodes().entrySet().stream().collect(
Collectors.toMap(Map.Entry::getKey, entry -> fileNodeArray2TreeNodeArray(new FileNode[]{entry.getValue()})[0]));
TemplateTreeSearchManager.getInstance().setRefreshing(true);
root.removeAllChildren();
}
FileNode[] treeNodes = TemplateTreeSearchManager.getInstance().matchesNode();
//排序一下,保证父子节点的情况下,子节点排在前面,先添加到树结构中
List<FileNode> treeNodeList = Arrays.stream(treeNodes).sorted((t1, t2) -> t2.getEnvPath().compareToIgnoreCase(t1.getEnvPath())).collect(Collectors.toList());
for (FileNode fileNode : treeNodeList) {
if (!calculateNode.containsKey(fileNode.getEnvPath())) {
ExpandMutableTreeNode treeNode = fileNodeArray2TreeNodeArray(new FileNode[]{fileNode})[0];
addToTreeModel(root, treeNode);
calculateNode.put(fileNode.getEnvPath(), treeNode);
}
}
}
/**
* 将搜索匹配到的模板添加到搜索结果树里面
*
* @param root
* @param treeNode
*/
protected void addToTreeModel(ExpandMutableTreeNode root, ExpandMutableTreeNode treeNode) {
FileNode fileNode = (FileNode) treeNode.getUserObject();
String parentPath = fileNode.getParent();
removePending(treeNode);
while (!ProjectConstants.REPORTLETS_NAME.equals(parentPath)) {
ExpandMutableTreeNode parentNode = allTreeNode.get(parentPath);
if (parentNode == null) {
FineLoggerFactory.getLogger().info("{} parent path {} is not found in allTreeNode.", fileNode.getEnvPath(), parentPath);
break;
}
parentNode.setExpanded(true);
removePending(parentNode);
if (notContained(parentPath, treeNode)) {
parentNode.add(treeNode);
}
parentPath = ((FileNode) (parentNode.getUserObject())).getParent();
treeNode = parentNode;
}
//最外层节点
if (notContained(ProjectConstants.REPORTLETS_NAME, treeNode)) {
root.add(treeNode);
}
}
private boolean notContained(String parentPath, ExpandMutableTreeNode treeNode) {
List<String> childList = currentTreeMode.getOrDefault(parentPath, new ArrayList<>());
String name = ((FileNode) (treeNode.getUserObject())).getName();
boolean result = false;
if (CollectionUtils.isEmpty(childList)) {
childList.add(name);
result = true;
} else {
if (!childList.contains(name)) {
childList.add(name);
result = true;
}
}
currentTreeMode.put(parentPath, childList);
return result;
}
private void removePending(ExpandMutableTreeNode treeNode) {
if (treeNode.getChildCount() >= 1 && ((ExpandMutableTreeNode) treeNode.getFirstChild()).getUserObject() == PENDING) {
treeNode.remove(0);
}
}
}

8
designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/ExpandMutableTreeNode.java

@ -92,4 +92,12 @@ public class ExpandMutableTreeNode extends DefaultMutableTreeNode {
this.add(newChildNodes[i]);
}
}
@Override
public Object clone() {
ExpandMutableTreeNode cloned = (ExpandMutableTreeNode) super.clone();
cloned.setExpanded(this.isExpanded);
cloned.setFullAuthority(this.hasFullAuthority);
return cloned;
}
}

5
designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java

@ -150,6 +150,11 @@ public abstract class RefreshableJTree extends CheckBoxTree {
refresh((ExpandMutableTreeNode) path.getParentPath().getLastPathComponent(), StringUtils.EMPTY);
}
//刷新指定目录
public void refreshDir(TreePath path) {
refresh((ExpandMutableTreeNode) path.getLastPathComponent(), StringUtils.EMPTY);
}
public void refreshChildByName(String childName) {
refresh((ExpandMutableTreeNode) this.getModel().getRoot(), childName);
}

29
designer-base/src/main/java/com/fr/design/javascript/beautify/JavaScriptFormatHelper.java

@ -1,16 +1,13 @@
package com.fr.design.javascript.beautify;
import com.eclipsesource.v8.V8;
import com.eclipsesource.v8.V8Array;
import com.eclipsesource.v8.V8Object;
import com.eclipsesource.v8.utils.V8ObjectUtils;
import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.EncodeConstants;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class JavaScriptFormatHelper {
@ -33,22 +30,14 @@ public class JavaScriptFormatHelper {
* @see <a href="https://github.com/beautify-web/js-beautify">JSBeautify<a/>
*/
public static String beautify(String jsCode, BeautifyOption option) {
InputStream resourceAsStream = IOUtils.readResource("com/fr/design/javascript/beautify/beautify.js");
String result = jsCode;
V8 v8 = V8.createV8Runtime();
try {
v8.executeVoidScript(IOUtils.inputStream2String(resourceAsStream, EncodeConstants.ENCODING_UTF_8));
V8Array parameters = new V8Array(v8);
parameters.push(jsCode);
V8Object arg = V8ObjectUtils.toV8Object(v8, option.toFormatArgument());
parameters.push(arg);
result = v8.executeStringFunction("js_beautify_global", parameters);
parameters.release();
arg.release();
} catch (UnsupportedEncodingException e) {
try (InputStream resourceAsStream = IOUtils.readResource("com/fr/design/javascript/beautify/beautify.js")) {
ScriptEngine nashorn = new ScriptEngineManager().getEngineByName("JavaScript");
nashorn.eval(IOUtils.inputStream2String(resourceAsStream, EncodeConstants.ENCODING_UTF_8));
Invocable invocable = (Invocable) nashorn;
result = (String) invocable.invokeFunction("js_beautify_global", new Object[]{jsCode, option.toFormatArgument()});
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
} finally {
v8.release(true);
}
return result;
}

11
designer-base/src/main/java/com/fr/design/layout/FRGUIPaneFactory.java

@ -152,15 +152,18 @@ public class FRGUIPaneFactory {
return new FRGridLayout(nColumn);
}
public static LayoutManager createCenterLayout(JComponent centerBody) {
return createCenterLayout(centerBody, 0.5d, 0.3d);
}
/**
* centerBody 为中心创建一个布局
* 只有当且仅当有一个组件且希望组件 上下左右 居中时使用
* @param centerBody 中心组件
* @return 布局方式
*/
public static LayoutManager createCenterLayout(JComponent centerBody) {
public static LayoutManager createCenterLayout(JComponent centerBody, double factorX, double factorY) {
final double yFactor = 0.30;
return new LayoutManager() {
@Override
@ -185,8 +188,8 @@ public class FRGUIPaneFactory {
// 这个时候大小是不确定的
int bodyWidth = centerBody.getPreferredSize().width;
int bodyHeight = centerBody.getPreferredSize().height;
int labelX = (width - bodyWidth) / 2;
int labelY = (int) ((height - bodyHeight) * yFactor);
int labelX = (int) ((width - bodyWidth) * factorX);
int labelY = (int) ((height - bodyHeight) * factorY);
centerBody.setBounds(labelX, labelY, bodyWidth, bodyHeight);
}

8
designer-base/src/main/java/com/fr/design/mainframe/CenterRegionContainerPane.java

@ -156,7 +156,7 @@ public class CenterRegionContainerPane extends JPanel {
private void addExtraButtons() {
JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
if (jt == null) {
if (!JTemplate.isValid(jt)) {
return;
}
@ -172,7 +172,7 @@ public class CenterRegionContainerPane extends JPanel {
private void addCheckButton() {
JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
if (jt == null) {
if (!JTemplate.isValid(jt)) {
return;
}
combineUp.addSeparator(new Dimension(2, 16));
@ -185,7 +185,7 @@ public class CenterRegionContainerPane extends JPanel {
private void addShareButton() {
JTemplate<?, ?> jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
if (jt == null) {
if (!JTemplate.isValid(jt)) {
return;
}
@ -205,7 +205,7 @@ public class CenterRegionContainerPane extends JPanel {
protected void checkCombineUp(boolean flag, ArrayList<String> al) {
//Yvan: 检查当前是否为WORK_SHEET状态,因为只有WORK_SHEET中含有格式刷组件,此时是不需要进行checkComponentsByNames的
JTemplate<?, ?> jTemplate = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
if (jTemplate != null) {
if (JTemplate.isValid(jTemplate)) {
// 第一个条件满足后还需要添加一重判断,判断是编辑报表块还是参数面板,编辑报表块时则直接return
if (jTemplate.getMenuState() == DesignState.WORK_SHEET && !jTemplate.isUpMode()) {
return;

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

@ -696,7 +696,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
username = connection == null ? StringUtils.EMPTY : connection.getUserName();
}
defaultTitleSB.append(username).append("@").append(envName).append("[").append(workspace.getDescription()).append("]");
if (editingTemplate != null) {
if (JTemplate.isValid(editingTemplate)) {
String path = editingTemplate.getPath();
if (!editingTemplate.getEditingFILE().exists()) {
path = FILEFactory.MEM_PREFIX + path;
@ -815,6 +815,13 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
basePane.remove(layout.getLayoutComponent(BorderLayout.EAST));
basePane.add(designerOpenEmptyPanel, BorderLayout.CENTER);
resetToolkitByPlus(ToolBarMenuDock.NULLAVOID);
// 这里挺恶心的,是为了保证对插件的兼容性适配
// 不然的话,插件就会 npe
// 见 https://work.fineres.com/browse/REPORT-76091
HistoryTemplateListCache.getInstance().setCurrentEditingTemplate(JNullTemplate.NULL);
layeredPane.repaint();
}
@ -1081,7 +1088,7 @@ public class DesignerFrame extends JFrame implements JTemplateActionListener, Ta
}
JTemplate jt = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
if (jt != null) {
if (JTemplate.isValid(jt)) {
DesignerEnvManager.getEnvManager().setLastOpenFile(jt.getEditingFILE().getPath());
}

386
designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java

@ -8,6 +8,9 @@ import com.fr.design.DesignModelAdapter;
import com.fr.design.DesignerEnvManager;
import com.fr.design.ExtraDesignClassManager;
import com.fr.design.actions.UpdateAction;
import com.fr.design.actions.file.DelFileAction;
import com.fr.design.actions.file.LocateAction;
import com.fr.design.actions.file.RenameAction;
import com.fr.design.constants.UIConstants;
import com.fr.design.data.DesignTableDataManager;
import com.fr.design.data.datapane.TableDataTreePane;
@ -29,6 +32,8 @@ import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.TableLayout;
import com.fr.design.layout.TableLayoutHelper;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateTreeSearchToolbarPane;
import com.fr.design.mainframe.vcs.common.VcsHelper;
import com.fr.design.mainframe.vcs.ui.FileVersionsPanel;
import com.fr.design.menu.KeySetUtils;
@ -39,8 +44,6 @@ import com.fr.design.ui.util.UIUtil;
import com.fr.design.utils.DesignUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.event.Event;
import com.fr.event.EventDispatcher;
import com.fr.file.FileNodeFILE;
import com.fr.file.filetree.FileNode;
import com.fr.general.ComparatorUtils;
import com.fr.general.GeneralContext;
@ -81,14 +84,17 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarStateChangeListener, ResponseDataSourceChange {
public static final Event<TwoTuple<String, String>> TEMPLATE_RENAME = new Event<TwoTuple<String, String>>() {
public static final com.fr.event.Event<TwoTuple<String, String>> TEMPLATE_RENAME = new Event<TwoTuple<String, String>>() {
};
private static final String FILE = "file";
public static final String FILE_NAME_LIMIT = "^[^/\\\\:<>\\*\\|\"\\?]+$";
private static volatile DesignerFrameFileDealerPane THIS;
static {
@ -144,6 +150,13 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
private VcsAction vcsAction = new VcsAction();
//搜索
private SwitchAction switchAction = new SwitchAction();
private TemplateTreeSearchToolbarPane searchToolbarPane;
//定位、收起
private LocateAction locateAction = new LocateAction();
private CollapseAllAction collapseAllAction = new CollapseAllAction();
private DesignerFrameFileDealerPane() {
@ -158,7 +171,10 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
tooBarPane.add(parent, BorderLayout.CENTER);
tooBarPane.add(new UIMenuHighLight(), BorderLayout.SOUTH);
add(tooBarPane, BorderLayout.NORTH);
searchToolbarPane = new TemplateTreeSearchToolbarPane(toolBar);
searchToolbarPane.setPreferredSize(new Dimension(this.getWidth(), 23));
add(searchToolbarPane, BorderLayout.NORTH);
CardLayout card;
JPanel cardPane = new JPanel(card = new CardLayout());
cardPane.add(TemplateTreePane.getInstance(), FILE);
@ -191,6 +207,16 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
selectedOperation.refresh();
}
/**
* 刷新根目录并退出搜索模式
*/
public void refreshAndOutOfSearch() {
if (TemplateTreeSearchManager.getInstance().isInSearchMode()) {
TemplateTreeSearchManager.getInstance().outOfSearchMode();
}
refresh();
}
private JPanel createUpToolBarPane() {
JPanel panel = new JPanel(new BorderLayout());
panel.add(toolBar, BorderLayout.CENTER);
@ -285,6 +311,7 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
toolbarDef.addShortCut(shortCut);
}
addVcsAction(toolbarDef);
toolbarDef.addShortCut(locateAction, collapseAllAction, switchAction);
toolbarDef.updateToolBar(toolBar);
resetActionStatus();
refresh();
@ -422,6 +449,37 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
}
private class SwitchAction extends UpdateAction {
public SwitchAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Search"));
this.setMnemonic('S');
this.setSmallIcon("/com/fr/design/images/data/search");
}
@Override
public void actionPerformed(ActionEvent e) {
// 交换层级
searchToolbarPane.switchPane(TemplateTreeSearchToolbarPane.SEARCH_PANE);
TemplateTreePane.getInstance().refreshDockingView();
TemplateTreeSearchManager.getInstance().switchToSearch(TemplateTreePane.getInstance().getTemplateFileTree());
}
}
public class CollapseAllAction extends UpdateAction {
public CollapseAllAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Collapse_All"));
this.setSmallIcon("/com/fr/design/images/FileDealerPaneIcon/collapse-all.png");
}
@Override
public void actionPerformed(ActionEvent e) {
TemplateTreePane.getInstance().refreshDockingView();
refreshDockingView();
}
}
/**
* 版本管理
*/
@ -537,72 +595,6 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
}
}
/*
* 重命名文件
*/
private class RenameAction extends UpdateAction {
public RenameAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Rename"));
this.setSmallIcon("/com/fr/design/images/FileDealerPaneIcon/rename");
}
@Override
public void actionPerformed(ActionEvent evt) {
if (!selectedOperation.access()) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return;
}
FileNode node = selectedOperation.getFileNode();
String lock = node.getLock();
if (lock != null && !lock.equals(node.getUserID())) {
// 提醒被锁定模板无法重命名
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Unable_Rename_Locked_File"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return;
}
new FileRenameDialog(node);
MutilTempalteTabPane.getInstance().repaint();
stateChange();
}
}
/*
* 删除指定文件
*/
private class DelFileAction extends UpdateAction {
public DelFileAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Remove"));
this.setSmallIcon("/com/fr/design/images/FileDealerPaneIcon/remove");
}
@Override
public void actionPerformed(ActionEvent evt) {
if (!selectedOperation.access()) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return;
}
selectedOperation.deleteFile();
stateChange();
DesignerContext.getDesignerFrame().setTitle();
}
}
public void refreshRightToolBarBy(FileNode fileNode) {
if (rightToolBar != null) {
boolean locked = fileNode != null
@ -616,225 +608,6 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
}
}
/**
* 重命名对话框
* 支持快捷键EnterESC
*/
private class FileRenameDialog extends JDialog {
private UITextField nameField;
private UILabel warnLabel;
private UIButton confirmButton;
/**
* 操作的节点
*/
private FileNodeFILE fnf;
private FileRenameDialog(FileNode node) {
if (node == null) {
return;
}
fnf = new FileNodeFILE(node);
String oldName = fnf.getName();
String suffix = fnf.isDirectory() ? StringUtils.EMPTY : oldName.substring(oldName.lastIndexOf(CoreConstants.DOT), oldName.length());
oldName = StringUtils.replaceLast(oldName, suffix, StringUtils.EMPTY);
this.setLayout(new BorderLayout());
this.setModal(true);
// 输入框前提示
UILabel newNameLabel = new UILabel(Toolkit.i18nText(
fnf.isDirectory() ?
"Fine-Design_Basic_Enter_New_Folder_Name" : "Fine-Design_Basic_Enter_New_File_Name")
);
newNameLabel.setHorizontalAlignment(SwingConstants.RIGHT);
newNameLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
//newNameLabel.setPreferredSize(new Dimension(118, 15));
// 重命名输入框
nameField = new UITextField(oldName);
nameField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
validInput();
}
@Override
public void insertUpdate(DocumentEvent e) {
validInput();
}
@Override
public void removeUpdate(DocumentEvent e) {
validInput();
}
});
nameField.selectAll();
nameField.setPreferredSize(new Dimension(170, 20));
JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 5));
topPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 0, 15));
topPanel.add(newNameLabel);
topPanel.add(nameField);
// 增加enter以及esc快捷键的支持
nameField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
dispose();
} else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (confirmButton.isEnabled()) {
confirmClose();
}
}
}
});
// 重名提示
warnLabel = new UILabel();
warnLabel.setPreferredSize(new Dimension(300, 50));
warnLabel.setHorizontalAlignment(SwingConstants.LEFT);
warnLabel.setVerticalAlignment(SwingConstants.TOP);
warnLabel.setForeground(Color.RED);
warnLabel.setVisible(false);
JPanel midPanel = new JPanel(new BorderLayout());
midPanel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 15));
midPanel.add(warnLabel, BorderLayout.WEST);
// 确认按钮
confirmButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Confirm"));
confirmButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
confirmClose();
}
});
// 取消按钮
UIButton cancelButton = new UIButton(Toolkit.i18nText("Fine-Design_Basic_Cancel"));
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
JPanel buttonsPane = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0));
buttonsPane.setBorder(BorderFactory.createEmptyBorder(10, 15, 10, 10));
buttonsPane.add(confirmButton);
buttonsPane.add(cancelButton);
this.add(
TableLayoutHelper.createTableLayoutPane(
new Component[][]{
new Component[]{topPanel},
new Component[]{midPanel},
new Component[]{buttonsPane}
},
new double[]{TableLayout.FILL, TableLayout.PREFERRED, TableLayout.PREFERRED},
new double[]{TableLayout.FILL}
),
BorderLayout.CENTER);
this.setSize(340, 200);
this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Rename"));
this.setResizable(false);
this.setAlwaysOnTop(true);
this.setIconImage(BaseUtils.readImage("/com/fr/base/images/oem/logo.png"));
this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
GUICoreUtils.centerWindow(this);
this.setVisible(true);
}
private void confirmClose() {
String userInput = nameField.getText().trim();
// 处理不合法的文件夹名称
userInput = userInput.replaceAll("[\\\\/:*?\"<>|]", StringUtils.EMPTY);
String path = FilenameUtils.standard(fnf.getPath());
String oldName = fnf.getName();
String suffix = fnf.isDirectory() ? StringUtils.EMPTY : oldName.substring(oldName.lastIndexOf(CoreConstants.DOT), oldName.length());
oldName = StringUtils.replaceLast(oldName, suffix, StringUtils.EMPTY);
// 输入为空或者没有修改
if (ComparatorUtils.equals(userInput, oldName)) {
this.dispose();
return;
}
String parentPath = FilenameUtils.standard(fnf.getParent().getPath());
// 简单执行old new 替换是不可行的,例如 /abc/abc/abc/abc/
String newPath = parentPath + CoreConstants.SEPARATOR + userInput + suffix;
this.dispose();
//模版重命名
boolean success = selectedOperation.rename(fnf, path, newPath);
if (success) {
EventDispatcher.fire(TEMPLATE_RENAME, new TwoTuple<>(path, newPath));
HistoryTemplateListCache.getInstance().rename(fnf, path, newPath);
DesignerEnvManager.getEnvManager().replaceRecentOpenedFilePath(fnf.isDirectory(), path, newPath);
selectedOperation.refresh();
DesignerContext.getDesignerFrame().setTitle();
} else {
FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Rename_Failure"),
Toolkit.i18nText("Fine-Design_Basic_Error"),
JOptionPane.DEFAULT_OPTION,
JOptionPane.ERROR_MESSAGE);
}
}
private void validInput() {
String userInput = nameField.getText().trim();
String oldName = fnf.getName();
String suffix = fnf.isDirectory() ? StringUtils.EMPTY : oldName.substring(oldName.lastIndexOf(CoreConstants.DOT), oldName.length());
oldName = oldName.replaceAll(suffix, StringUtils.EMPTY);
if (StringUtils.isEmpty(userInput)) {
confirmButton.setEnabled(false);
return;
}
if (ComparatorUtils.equals(userInput, oldName)) {
warnLabel.setVisible(false);
confirmButton.setEnabled(true);
return;
}
if (selectedOperation.duplicated(userInput, suffix)) {
nameField.selectAll();
// 如果文件名已存在,则灰掉确认按钮
warnLabel.setText(
Toolkit.i18nText(fnf.isDirectory() ?
"Fine-Design_Basic_Folder_Name_Duplicate" :
"Fine-Design_Basic_Template_File_Name_Duplicate",
userInput));
warnLabel.setVisible(true);
confirmButton.setEnabled(false);
} else {
warnLabel.setVisible(false);
confirmButton.setEnabled(true);
}
}
}
/**
* 新建文件夹对话框
@ -967,19 +740,23 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
private void confirmClose() {
String userInput = nameField.getText().trim();
// 处理不合法的文件夹名称
userInput = userInput.replaceAll("[\\\\/:*?\"<>|]", StringUtils.EMPTY);
if (StringUtils.isEmpty(userInput)) {
return;
}
//新建文件夹
boolean success = selectedOperation.mkdir(
FilenameUtils.standard(selectedOperation.getFileNode().getParent() + CoreConstants.SEPARATOR + userInput)
);
FileNode selectedFileNode = selectedOperation.getFileNode();
String parentPath = selectedFileNode.getParent();
if (selectedFileNode.isDirectory()) {
//目录的话,父目录就是所选目录
parentPath = FilenameUtils.standard(parentPath + CoreConstants.SEPARATOR + selectedFileNode.getName());
}
String targetPath = FilenameUtils.standard(parentPath + CoreConstants.SEPARATOR + userInput);
boolean success = selectedOperation.mkdir(targetPath);
selectedOperation.refresh();
this.dispose();
LocateAction.gotoEditingTemplateLeaf(targetPath);
if (!success) {
FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Make_Failure"),
@ -999,13 +776,11 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
return;
}
if (selectedOperation.duplicated(userInput, StringUtils.EMPTY)) {
String errorMsg = doCheck(userInput, StringUtils.EMPTY);
if (StringUtils.isNotEmpty(errorMsg)) {
nameField.selectAll();
// 如果文件名已存在,则灰掉确认按钮
warnLabel.setText(
Toolkit.i18nText(
"Fine-Design_Basic_Folder_Name_Duplicate",
userInput));
// 如果检测出错,则灰掉确认按钮并提示
warnLabel.setText(errorMsg);
warnLabel.setVisible(true);
confirmButton.setEnabled(false);
} else {
@ -1015,6 +790,17 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
}
}
private String doCheck (String userInput, String suffix) {
String errorMsg = StringUtils.EMPTY;
if (selectedOperation.duplicated(userInput, suffix, true)) {
errorMsg = Toolkit.i18nText("Fine-Design_Basic_Folder_Name_Duplicate", userInput);
}
if (!Pattern.compile(FILE_NAME_LIMIT).matcher(userInput).matches()) {
errorMsg = Toolkit.i18nText("Fine-Design_Basic_Template_Name_Illegal");
}
return errorMsg;
}
private boolean isEnable() {
List<JTemplate<?, ?>> templates = HistoryTemplateListCache.getInstance().getHistoryList();
for (JTemplate<?, ?> template : templates) {

207
designer-base/src/main/java/com/fr/design/mainframe/JNullTemplate.java

@ -0,0 +1,207 @@
package com.fr.design.mainframe;
import com.fr.design.DesignModelAdapter;
import com.fr.design.designer.TargetComponent;
import com.fr.design.gui.frpane.HyperlinkGroupPane;
import com.fr.design.gui.frpane.HyperlinkGroupPaneActionProvider;
import com.fr.design.gui.imenu.UIMenuItem;
import com.fr.design.mainframe.template.info.TemplateProcessInfo;
import com.fr.design.menu.ShortCut;
import com.fr.design.menu.ToolBarDef;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JPanel;
/**
* created by Harrison on 2022/08/09
**/
public class JNullTemplate extends JTemplate {
public static final JTemplate NULL = new JNullTemplate();
@Override
public void copy() {
}
@Override
public boolean paste() {
return false;
}
@Override
public boolean cut() {
return false;
}
@Override
public AuthorityEditPane createAuthorityEditPane() {
return null;
}
@Override
public JPanel getEastUpPane() {
return null;
}
@Override
public JPanel getEastDownPane() {
return null;
}
@Override
public ToolBarDef[] toolbars4Target() {
return new ToolBarDef[0];
}
@Override
public JComponent[] toolBarButton4Form() {
return new JComponent[0];
}
@Override
public void refreshEastPropertiesPane() {
}
@Override
public TargetComponent getCurrentElementCasePane() {
return null;
}
@Override
public JComponent getCurrentReportComponentPane() {
return null;
}
@Override
public TemplateProcessInfo getProcessInfo() {
return null;
}
@Override
public void setJTemplateResolution(int resolution) {
}
@Override
public int getJTemplateResolution() {
return 0;
}
@Override
protected JComponent createCenterPane() {
return null;
}
@Override
public void removeTemplateSelection() {
}
@Override
public void refreshContainer() {
}
@Override
public void removeParameterPaneSelection() {
}
@Override
public void setScale(int resolution) {
}
@Override
public int getScale() {
return 0;
}
@Override
public int selfAdaptUpdate() {
return 0;
}
@Override
protected DesignModelAdapter createDesignModel() {
return null;
}
@Override
public UIMenuItem[] createMenuItem4Preview() {
return new UIMenuItem[0];
}
@Override
protected BaseUndoState<?> createUndoState() {
return null;
}
@Override
protected void applyUndoState(BaseUndoState baseUndoState) {
}
@Override
public String suffix() {
return null;
}
@Override
public ShortCut[] shortcut4TemplateMenu() {
return new ShortCut[0];
}
@Override
public ShortCut[] shortCuts4Authority() {
return new ShortCut[0];
}
@Override
public boolean isJWorkBook() {
return false;
}
@Override
public HyperlinkGroupPane getHyperLinkPane(HyperlinkGroupPaneActionProvider hyperlinkGroupPaneActionProvider) {
return null;
}
@Override
public HyperlinkGroupPane getHyperLinkPaneNoPop(HyperlinkGroupPaneActionProvider hyperlinkGroupPaneActionProvider) {
return null;
}
@Override
public void setAuthorityMode(boolean isUpMode) {
}
@Override
public Icon getIcon() {
return null;
}
@Override
public String route() {
return null;
}
@Override
public JPanel[] toolbarPanes4Form() {
return new JPanel[0];
}
@Override
public JComponent toolBar4Authority() {
return null;
}
@Override
public int getToolBarHeight() {
return 0;
}
}

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

@ -1787,7 +1787,7 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
HistoryTemplateListCache.getInstance().getCurrentEditingTemplate().template.getTemplateID())) {
refreshToolArea();
}
DesignerFrameFileDealerPane.getInstance().refresh();
DesignerFrameFileDealerPane.getInstance().refreshAndOutOfSearch();
DesignerFrameFileDealerPane.getInstance().stateChange();
}
});
@ -1973,5 +1973,14 @@ public abstract class JTemplate<T extends BaseBook, U extends BaseUndoState<?>>
public void setDesignerUIMode() {
DesignerUIModeConfig.getInstance().setAbsoluteMeasureUIMode();
}
/**
* 判断当前的模板是否是有效的模板
*
* @param jt 模板
* @return /
*/
public static boolean isValid(JTemplate jt) {
return jt != null && jt != JNullTemplate.NULL;
}
}

66
designer-base/src/main/java/com/fr/design/mainframe/manager/clip/TemplateTreeClipboard.java

@ -0,0 +1,66 @@
package com.fr.design.mainframe.manager.clip;
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import java.util.ArrayList;
import java.util.List;
/**
* 模板复制黏贴
*/
public class TemplateTreeClipboard {
private List<ExpandMutableTreeNode> clip = new ArrayList<>();
private static class Holder {
private static final TemplateTreeClipboard INSTANCE = new TemplateTreeClipboard();
}
private TemplateTreeClipboard() {
}
public static TemplateTreeClipboard getInstance() {
return TemplateTreeClipboard.Holder.INSTANCE;
}
public List<ExpandMutableTreeNode> transferNameObjectArray2Map(ExpandMutableTreeNode[] selectedTreeNodes) {
List<ExpandMutableTreeNode> resultMap = new ArrayList<>();
if (selectedTreeNodes == null) {
return resultMap;
}
for (ExpandMutableTreeNode selectTreeNode : selectedTreeNodes) {
ExpandMutableTreeNode cloned = (ExpandMutableTreeNode) selectTreeNode.clone();
if (cloned != null) {
resultMap.add(cloned);
}
}
return resultMap;
}
/**
* 添加选中的模板数据到剪切板覆盖原本剪切板内数据
*
* @param copyList
* @return
*/
public void addToClip(List<ExpandMutableTreeNode> copyList) {
this.clip = copyList;
}
/**
* 取出剪切板内的所有模板数据剪切板不清空
*
* @return
*/
public List<ExpandMutableTreeNode> takeFromClip() {
return clip;
}
/**
* 清空剪切板
*/
public void reset() {
clip.clear();
}
}

205
designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateDirTreeSearchManager.java

@ -0,0 +1,205 @@
package com.fr.design.mainframe.manager.search;
import com.fr.design.file.TemplateDirTreePane;
import com.fr.design.gui.itree.filetree.TemplateDirTree;
import com.fr.design.mainframe.manager.search.searcher.TemplateDirTreeSearcher;
import com.fr.design.mainframe.manager.search.searcher.TemplateTreeSearcher;
import com.fr.design.search.TreeSearchStatus;
import com.fr.design.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.search.event.TreeSearchStatusChangeListener;
import com.fr.design.search.view.TreeSearchRendererHelper;
import com.fr.file.filetree.FileNode;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import javax.swing.SwingUtilities;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class TemplateDirTreeSearchManager {
/**
* 文件树搜索器
*/
private TemplateTreeSearcher treeSearcher;
/**
* 搜索任务的状态
*/
private TreeSearchStatus treeSearchStatus;
/**
* 缓存上次搜索文本避免重复搜索
*/
private String lastSearchText;
/**
* 存储与复原 原本模板的UI
*/
private TreeSearchRendererHelper rendererHelper;
/**
* 搜索状态变化监听
*/
private List<TreeSearchStatusChangeListener> listeners = new ArrayList<>();
private TemplateDirTreeSearchManager() {
init();
}
private void init() {
this.treeSearchStatus = TreeSearchStatus.NOT_IN_SEARCH_MODE;
}
private static class Holder {
private static final TemplateDirTreeSearchManager INSTANCE = new TemplateDirTreeSearchManager();
}
public static TemplateDirTreeSearchManager getInstance() {
return TemplateDirTreeSearchManager.Holder.INSTANCE;
}
public TreeSearchStatus getTreeSearchStatus() {
return treeSearchStatus;
}
public void setTreeSearchStatus(TreeSearchStatus treeSearchStatus) {
this.treeSearchStatus = treeSearchStatus;
// 每次设置搜索状态,都触发下监听,让页面跟随变化
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
for (TreeSearchStatusChangeListener listener : listeners) {
listener.updateTreeSearchChange(new TreeSearchStatusChangeEvent(treeSearchStatus));
}
}
});
}
public void registerTreeSearchStatusChangeListener(TreeSearchStatusChangeListener listener) {
listeners.add(listener);
}
/**
* 获取当前的目录树
*
* @return
*/
private TemplateDirTree getCurrentTemplateDirTree() {
return TemplateDirTreePane.getInstance().getTemplateDirTree();
}
public void beforeSearch(TemplateDirTree templateDirTree) {
setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN);
rendererHelper = new TreeSearchRendererHelper();
rendererHelper.save(templateDirTree.getFileTreeCellRenderer());
treeSearcher = new TemplateDirTreeSearcher();
FineLoggerFactory.getLogger().debug("switch to template dir search");
treeSearcher.beforeSearch(templateDirTree);
}
/**
* 开始搜索
*
* @param searchText
*/
public void startSearch(String searchText) {
if (isRepeatSearch(searchText) || StringUtils.isEmpty(searchText)) {
return;
}
setTreeSearchStatus(TreeSearchStatus.SEARCHING);
rendererHelper.replaceTreeRenderer(getCurrentTemplateDirTree(), searchText);
FineLoggerFactory.getLogger().debug("start template dir search for search text: {}", searchText);
treeSearcher.startSearch(searchText);
}
/**
* 中断搜索
*/
public void stopSearch() {
setTreeSearchStatus(TreeSearchStatus.SEARCH_STOPPED);
FineLoggerFactory.getLogger().debug("stop template dir search for search text: {}", lastSearchText);
treeSearcher.stopSearch();
}
/**
* 搜索完成
*/
public void completeSearch() {
setTreeSearchStatus(TreeSearchStatus.SEARCH_COMPLETED);
FineLoggerFactory.getLogger().debug("complete template dir search for search text: {}", lastSearchText);
treeSearcher.completeSearch();
}
/**
* 退出搜索模式
*/
public void outOfSearchMode() {
setTreeSearchStatus(TreeSearchStatus.NOT_IN_SEARCH_MODE);
FineLoggerFactory.getLogger().info("out of template search");
lastSearchText = null;
if (treeSearcher != null) {
treeSearcher.exitSearch();
}
if (rendererHelper != null) {
rendererHelper.restore(getCurrentTemplateDirTree());
}
}
/**
* 所有匹配的目录节点
* @return
*/
public FileNode[] matchesNode() {
return treeSearcher.getMatchSets().toArray(new FileNode[0]);
}
/**
* 当前目录树中搜索的目录节点
* @return
*/
public Map<String, FileNode> allFileNodes() {
return treeSearcher.getAllTemplates();
}
/**
* 搜索结果是否为空
* @return
*/
public boolean isMatchSetsEmpty() {
return treeSearcher.isMatchSetsEmpty();
}
/**
* 恢复到模板树面板
*/
public void restoreTreePane() {
setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN);
lastSearchText = null;
if (rendererHelper != null) {
rendererHelper.restore(getCurrentTemplateDirTree());
}
}
/**
* 刷新树更新搜索的结果
*/
public void updateTemplateTree() {
getCurrentTemplateDirTree().refresh4TreeSearch();
}
private boolean isRepeatSearch(String searchText) {
boolean repeat = StringUtils.equals(lastSearchText, searchText);
lastSearchText = searchText;
return repeat;
}
/**
* 当前是否处于搜索模式
* @return
*/
public boolean isInSearchMode() {
return getTreeSearchStatus() != TreeSearchStatus.NOT_IN_SEARCH_MODE;
}
}

258
designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateTreeSearchManager.java

@ -0,0 +1,258 @@
package com.fr.design.mainframe.manager.search;
import com.fr.design.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.search.event.TreeSearchStatusChangeListener;
import com.fr.design.search.TreeSearchStatus;
import com.fr.design.search.view.TreeSearchRendererHelper;
import com.fr.design.file.TemplateTreePane;
import com.fr.design.gui.itree.filetree.TemplateFileTree;
import com.fr.design.mainframe.manager.search.searcher.TemplateTreeSearcher;
import com.fr.file.filetree.FileNode;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.StringUtils;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 文件树搜索管理器
*/
public class TemplateTreeSearchManager {
/**
* 文件树搜索器
*/
private TemplateTreeSearcher treeSearcher;
/**
* 搜索任务的状态
*/
private TreeSearchStatus treeSearchStatus;
/**
* 缓存上次搜索文本避免重复搜索
*/
private String lastSearchText;
/**
* 存储与复原 原本模板的UI
*/
private TreeSearchRendererHelper rendererHelper;
/**
* 是否在更新搜索结果的标识
*/
private AtomicBoolean isRefreshing = new AtomicBoolean(false);
/**
* 搜索状态变化监听
*/
private List<TreeSearchStatusChangeListener> listeners = new ArrayList<>();
private TemplateTreeSearchManager() {
init();
}
private void init() {
this.treeSearchStatus = TreeSearchStatus.NOT_IN_SEARCH_MODE;
}
private static class Holder {
private static final TemplateTreeSearchManager INSTANCE = new TemplateTreeSearchManager();
}
public static TemplateTreeSearchManager getInstance() {
return TemplateTreeSearchManager.Holder.INSTANCE;
}
public TreeSearchStatus getTreeSearchStatus() {
return treeSearchStatus;
}
public void setTreeSearchStatus(TreeSearchStatus treeSearchStatus) {
this.treeSearchStatus = treeSearchStatus;
// 每次设置搜索状态,都触发下监听,让页面跟随变化
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
for (TreeSearchStatusChangeListener listener : listeners) {
listener.updateTreeSearchChange(new TreeSearchStatusChangeEvent(treeSearchStatus));
}
}
});
}
public void registerTreeSearchStatusChangeListener(TreeSearchStatusChangeListener listener) {
listeners.add(listener);
}
/**
* 工具栏处切换到搜索面板
*
* @param templateFileTree
*/
public void switchToSearch(TemplateFileTree templateFileTree) {
setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN);
rendererHelper = new TreeSearchRendererHelper();
rendererHelper.save(templateFileTree.getFileTreeCellRenderer());
treeSearcher = new TemplateTreeSearcher();
FineLoggerFactory.getLogger().debug("switch to template search");
treeSearcher.beforeSearch(templateFileTree);
}
/**
* 获取当前的模板树
*
* @return
*/
private TemplateFileTree getCurrentTemplateTree() {
return TemplateTreePane.getInstance().getTemplateFileTree();
}
public boolean isMatchSetsEmpty() {
return treeSearcher.isMatchSetsEmpty();
}
/**
* 开始搜索
*
* @param searchText
*/
public void startSearch(String searchText) {
if (isRepeatSearch(searchText) || StringUtils.isEmpty(searchText)) {
return;
}
setTreeSearchStatus(TreeSearchStatus.SEARCHING);
rendererHelper.replaceTreeRenderer(getCurrentTemplateTree(), searchText);
FineLoggerFactory.getLogger().debug("start template search for search text: {}", searchText);
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
treeSearcher.startSearch(searchText);
return null;
}
}.execute();
}
/**
* 中断搜索
*/
public void stopSearch() {
setTreeSearchStatus(TreeSearchStatus.SEARCH_STOPPED);
FineLoggerFactory.getLogger().debug("stop template search for search text: {}", lastSearchText);
treeSearcher.stopSearch();
}
/**
* 搜索完成
*/
public void completeSearch() {
setTreeSearchStatus(TreeSearchStatus.SEARCH_COMPLETED);
setRefreshing(false);
FineLoggerFactory.getLogger().debug("complete template search for search text: {}", lastSearchText);
treeSearcher.completeSearch();
}
/**
* 刷新树更新搜索的结果
*/
public void updateTemplateTree() {
getCurrentTemplateTree().refresh4TreeSearch();
}
private boolean isRepeatSearch(String searchText) {
boolean repeat = StringUtils.equals(lastSearchText, searchText);
lastSearchText = searchText;
return repeat;
}
/**
* 切换回工具栏恢复数据集树UI
*/
public void restoreToolBarAndTreePane() {
setTreeSearchStatus(TreeSearchStatus.NOT_IN_SEARCH_MODE);
FineLoggerFactory.getLogger().info("out of template search");
if (treeSearcher != null) {
treeSearcher.exitSearch();
}
setRefreshing(false);
lastSearchText = null;
if (rendererHelper != null) {
rendererHelper.restore(getCurrentTemplateTree());
}
}
/**
* 恢复文件树UI
*/
public void restoreTreePane() {
setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN);
lastSearchText = null;
if (rendererHelper != null) {
rendererHelper.restore(getCurrentTemplateTree());
}
}
/**
* 所有匹配的目录节点
* @return
*/
public FileNode[] matchesNode() {
if (treeSearcher.getMatchSets().size() == 0) {
return new FileNode[0];
}
return treeSearcher.getMatchSets().toArray(new FileNode[0]);
}
public void deleteMatchedNode(Set<FileNode> fileNodes) {
Set<FileNode> deleteNode = new HashSet<>();
for (FileNode matchedNode : treeSearcher.getMatchSets()) {
if (fileNodes.stream().anyMatch(fileNode -> fileNode.getEnvPath().equals(matchedNode.getEnvPath()))) {
deleteNode.add(matchedNode);
}
}
treeSearcher.getMatchSets().removeAll(deleteNode);
}
/**
* 当前模板树中的所有模板节点
* @return
*/
public Map<String, FileNode> allFileNodes() {
return treeSearcher.getAllTemplates();
}
/**
* 是否处于搜索模式
* @return
*/
public boolean isInSearchMode() {
return getTreeSearchStatus() != TreeSearchStatus.NOT_IN_SEARCH_MODE;
}
/**
* 退出搜索模式
*/
public void outOfSearchMode() {
restoreToolBarAndTreePane();
}
/**
* 搜索结果数是否处于更新状态
* @return
*/
public boolean isRefreshing() {
return isRefreshing.get();
}
public void setRefreshing(boolean isRefreshing) {
this.isRefreshing.set(isRefreshing);
}
}

195
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/TemplateDirTreeSearcher.java

@ -0,0 +1,195 @@
package com.fr.design.mainframe.manager.search.searcher;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.gui.itree.filetree.TemplateFileTree;
import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager;
import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateDirSearchCallBack;
import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchTask;
import com.fr.design.mainframe.manager.search.searcher.control.pre.TemplateDirPreSearchTask;
import com.fr.design.mainframe.manager.search.searcher.control.pre.TemplatePreSearchCallBack;
import com.fr.design.search.TreeSearchStatus;
import com.fr.file.filetree.FileNode;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.project.ProjectConstants;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
* 目录搜索器
*/
public class TemplateDirTreeSearcher extends TemplateTreeSearcher {
private ExecutorService executorService;
private final Map<String, FileNode> allDirs = new ConcurrentHashMap<>();
private final AtomicInteger outLayerDirCount = new AtomicInteger(0);
private final Set<String> notCalculatedSets = new HashSet<>();
private final Set<String> calculatedSets = new HashSet<>();
private final Set<FileNode> matchSets = new HashSet<>();
private final Object lock = new Object();
public Set<FileNode> getMatchSets() {
return this.matchSets;
}
public boolean isMatchSetsEmpty() {
return matchSets.isEmpty();
}
public int getAllDirSize() {
return allDirs.size();
}
public Map<String, FileNode> getAllTemplates() {
return allDirs;
}
public int getCalculatedCount() {
return this.calculatedSets.size();
}
/**
* 将模板添加到已经计算过的集合中不管模板是不是匹配
*
* @param templateNames
*/
public synchronized void addToCalculatedSets(List<String> templateNames) {
for (String templateName : templateNames) {
FileNode fileNode = allDirs.get(templateName);
if (fileNode == null) {
return;
}
calculatedSets.add(templateName);
}
}
/**
* 将搜索匹配的目录添加到匹配的集合中
*
* @param matchNodes
*/
public synchronized void addToMatchSets(List<FileNode> matchNodes) {
matchSets.addAll(matchNodes);
}
/**
* 将目录添加到未计算的集合中
*
* @param fileNodes
*/
public synchronized void addToNotCalculatedSets(List<FileNode> fileNodes) {
synchronized (lock) {
Map<String, FileNode> chileMap = fileNodes.stream().collect(Collectors.toMap(FileNode::getEnvPath, treeNode -> treeNode));
notCalculatedSets.addAll(chileMap.keySet());
allDirs.putAll(chileMap);
outLayerDirCount.decrementAndGet();
lock.notify();
}
}
/**
* 正式搜索前预加载一下每个最外层目录里面的所有子节点
*
*/
public void beforeSearch(TemplateFileTree templateFileTree) {
executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new NamedThreadFactory(TemplateDirTreeSearcher.class));
collectOutLayerTemplate(templateFileTree);
preCalculateChild();
}
protected void preCalculateChild() {
for (String notCalculatedNode : notCalculatedSets) {
FileNode fileNode = allDirs.get(notCalculatedNode);
//计算最外层目录下的所有子节点
if (TemplateDirTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCH_NOT_BEGIN && fileNode.isDirectory()) {
executorService.execute(new TemplateDirPreSearchTask(new TemplatePreSearchCallBack(this), fileNode));
}
}
}
/**
* 收集下此次搜索需要进行取数最外层的FileNode
*
* @param templateFileTree
*/
private void collectOutLayerTemplate(TemplateFileTree templateFileTree) {
FileNode[] fileNodes = templateFileTree.listFile(ProjectConstants.REPORTLETS_NAME);
Map<String, FileNode> fileNodeMap = Arrays.stream(fileNodes).collect(Collectors.toMap(FileNode::getEnvPath, treeNode -> treeNode));
outLayerDirCount.addAndGet(fileNodes.length);
notCalculatedSets.addAll(fileNodeMap.keySet());
allDirs.putAll(fileNodeMap);
}
/**
* 开始搜索
*
* @param searchText
*/
@Override
public void startSearch(String searchText) {
reset();
do {
synchronized (lock) {
if (notCalculatedSets.isEmpty()) {
try {
lock.wait(100);
} catch (InterruptedException e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
for (String notCalculated : notCalculatedSets) {
FileNode fileNode = allDirs.get(notCalculated);
if (TemplateDirTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCHING) {
executorService.execute(new TemplateSearchTask(searchText, fileNode, new TemplateDirSearchCallBack(this)));
}
}
FineLoggerFactory.getLogger().info("[Template Search] At this stage calculate size: {}.", notCalculatedSets.size());
notCalculatedSets.clear();
}
} while (outLayerDirCount.get() != 0);
}
/**
* 停止搜索
*/
@Override
public void stopSearch() {
}
/**
* 完成搜索
*/
@Override
public void completeSearch() {
}
private void reset() {
matchSets.clear();
calculatedSets.clear();
notCalculatedSets.addAll(allDirs.keySet());
}
/**
* 退出搜索时的处理
*/
public void exitSearch() {
allDirs.clear();
executorService.shutdownNow();
}
}

193
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/TemplateTreeSearcher.java

@ -0,0 +1,193 @@
package com.fr.design.mainframe.manager.search.searcher;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchCallBack;
import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchTask;
import com.fr.design.mainframe.manager.search.searcher.control.pre.TemplatePreSearchCallBack;
import com.fr.design.mainframe.manager.search.searcher.control.pre.TemplatePreSearchTask;
import com.fr.design.search.TreeSearchStatus;
import com.fr.design.search.TreeSearcher;
import com.fr.design.gui.itree.filetree.TemplateFileTree;
import com.fr.file.filetree.FileNode;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.project.ProjectConstants;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
public class TemplateTreeSearcher implements TreeSearcher {
private ExecutorService executorService;
private final Map<String, FileNode> allTemplates = new ConcurrentHashMap<>();
private final Object lock = new Object();
private final AtomicInteger outLayerDirCount = new AtomicInteger(0);
private final Set<String> calculatedSets = new HashSet<>();
private final Set<String> notCalculatedSets = new HashSet<>();
private final Set<FileNode> matchSets = new HashSet<>();
public boolean isMatchSetsEmpty() {
return matchSets.isEmpty();
}
public int getAllTemplateSize() {
return allTemplates.size();
}
public Map<String, FileNode> getAllTemplates() {
return allTemplates;
}
public Set<FileNode> getMatchSets() {
return this.matchSets;
}
public int getCalculatedCount() {
return this.calculatedSets.size();
}
public int getOutLayerCount() {
return this.outLayerDirCount.get();
}
public synchronized void addToCalculatedSets(List<String> templateNames) {
for (String templateName : templateNames) {
FileNode fileNode = allTemplates.get(templateName);
if (fileNode == null) {
return;
}
calculatedSets.add(templateName);
}
}
/**
* 将搜索匹配的模板添加到匹配的集合中
*
* @param matchNodes
*/
public synchronized void addToMatchSets(List<FileNode> matchNodes) {
matchSets.addAll(matchNodes);
}
/**
* 将模板添加到未计算的集合中
*
* @param fileNodes
*/
public synchronized void addToNotCalculatedSets(List<FileNode> fileNodes) {
synchronized (lock) {
Map<String, FileNode> chileMap = fileNodes.stream().collect(Collectors.toMap(FileNode::getEnvPath, treeNode -> treeNode));
notCalculatedSets.addAll(chileMap.keySet());
allTemplates.putAll(chileMap);
outLayerDirCount.decrementAndGet();
lock.notify();
}
}
/**
* 正式搜索前预加载一下每个最外层目录里面的所有子节点
*
*/
public void beforeSearch(TemplateFileTree templateFileTree) {
executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new NamedThreadFactory(TemplateTreeSearcher.class));
collectOutLayerTemplate(templateFileTree);
preCalculateChild();
}
protected void preCalculateChild() {
for (String notCalculatedNode : notCalculatedSets) {
FileNode fileNode = allTemplates.get(notCalculatedNode);
//计算最外层目录下的所有子节点
if (TemplateTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCH_NOT_BEGIN && fileNode.isDirectory()) {
executorService.execute(new TemplatePreSearchTask(new TemplatePreSearchCallBack(this), fileNode));
}
}
}
/**
* 收集下此次搜索需要进行取数最外层的FileNode
*
* @param templateFileTree
*/
private void collectOutLayerTemplate(TemplateFileTree templateFileTree) {
FileNode[] fileNodes = templateFileTree.listFile(ProjectConstants.REPORTLETS_NAME);
Map<String, FileNode> fileNodeMap = Arrays.stream(fileNodes).collect(Collectors.toMap(FileNode::getEnvPath, treeNode -> treeNode));
long dirCount = Arrays.stream(fileNodes).filter(FileNode::isDirectory).count();
outLayerDirCount.addAndGet((int) dirCount);
notCalculatedSets.addAll(fileNodeMap.keySet());
allTemplates.putAll(fileNodeMap);
}
/**
* 开始搜索
*
* @param searchText
*/
@Override
public void startSearch(String searchText) {
reset();
do {
synchronized (lock) {
if (notCalculatedSets.isEmpty()) {
try {
lock.wait(100);
} catch (InterruptedException e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
}
}
for (String notCalculated : notCalculatedSets) {
FileNode fileNode = allTemplates.get(notCalculated);
if (TemplateTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCHING) {
executorService.execute(new TemplateSearchTask(searchText, fileNode, new TemplateSearchCallBack(this)));
}
}
FineLoggerFactory.getLogger().info("[Template Search] At this stage calculate size: {}.", notCalculatedSets.size());
notCalculatedSets.clear();
}
} while (outLayerDirCount.get() != 0);
}
/**
* 停止搜索
*/
@Override
public void stopSearch() {
}
/**
* 完成搜索
*/
@Override
public void completeSearch() {
}
private void reset() {
matchSets.clear();
calculatedSets.clear();
notCalculatedSets.addAll(allTemplates.keySet());
}
/**
* 退出搜索模式
*/
public void exitSearch() {
allTemplates.clear();
executorService.shutdownNow();
}
}

53
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateDirSearchCallBack.java

@ -0,0 +1,53 @@
package com.fr.design.mainframe.manager.search.searcher.control.common;
import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager;
import com.fr.design.mainframe.manager.search.searcher.TemplateDirTreeSearcher;
import com.fr.design.search.TreeSearchStatus;
import com.fr.design.search.control.TreeSearchCallback;
import com.fr.design.search.control.TreeSearchResult;
import javax.swing.SwingUtilities;
/**
* 目录树搜索回调处理
*/
public class TemplateDirSearchCallBack implements TreeSearchCallback {
protected TemplateDirTreeSearcher treeSearcher;
public TemplateDirSearchCallBack(TemplateDirTreeSearcher treeSearcher) {
this.treeSearcher = treeSearcher;
}
@Override
public void done(TreeSearchResult treeSearchResult) {
if (TemplateDirTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) {
return;
}
// 添加结果
addToTreeSearcher(treeSearchResult);
if (treeSearcher.getCalculatedCount() == treeSearcher.getAllDirSize()) {
updateTemplateTree();
}
}
/**
* 更新目录树搜索结果
*/
protected void updateTemplateTree() {
SwingUtilities.invokeLater(() -> {
if (TemplateDirTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) {
return;
}
TemplateDirTreeSearchManager.getInstance().updateTemplateTree();
TemplateDirTreeSearchManager.getInstance().completeSearch();
});
}
private void addToTreeSearcher(TreeSearchResult treeSearchResult) {
// 添加到已计算结果集
treeSearcher.addToCalculatedSets(treeSearchResult.getAddToCalculated());
// 添加到匹配结果集
treeSearcher.addToMatchSets(((TemplateSearchResult)treeSearchResult).getAddToMatchNode());
}
}

63
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchCallBack.java

@ -0,0 +1,63 @@
package com.fr.design.mainframe.manager.search.searcher.control.common;
import com.fr.design.search.control.TreeSearchCallback;
import com.fr.design.search.control.TreeSearchResult;
import com.fr.design.search.TreeSearchStatus;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.design.mainframe.manager.search.searcher.TemplateTreeSearcher;
import javax.swing.SwingUtilities;
/**
* 模板搜索回调处理
*/
public class TemplateSearchCallBack implements TreeSearchCallback {
protected TemplateTreeSearcher treeSearcher;
private static final int BATCH_SIZE = 500;
public TemplateSearchCallBack(TemplateTreeSearcher treeSearcher) {
this.treeSearcher = treeSearcher;
}
@Override
public void done(TreeSearchResult treeSearchResult) {
if (TemplateTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) {
return;
}
// 添加结果
addToTreeSearcher(treeSearchResult);
updateTemplateTree();
}
/**
* 更新目录树搜索结果
*/
protected void updateTemplateTree() {
int calculatedCount = treeSearcher.getCalculatedCount();
boolean allCalculated = calculatedCount == treeSearcher.getAllTemplateSize();
boolean isFinish = allCalculated && treeSearcher.getOutLayerCount() == 0;
if (calculatedCount % BATCH_SIZE == 0 || allCalculated) {
// 更新UI
updateOrFinish(isFinish);
}
}
protected void updateOrFinish(boolean isFinished) {
SwingUtilities.invokeLater(() -> {
if (TemplateTreeSearchManager.getInstance().getTreeSearchStatus() != TreeSearchStatus.SEARCHING) {
return;
}
TemplateTreeSearchManager.getInstance().updateTemplateTree();
if (isFinished) {
TemplateTreeSearchManager.getInstance().completeSearch();
}
});
}
protected void addToTreeSearcher(TreeSearchResult treeSearchResult) {
// 添加到已计算结果集
treeSearcher.addToCalculatedSets(treeSearchResult.getAddToCalculated());
// 添加到匹配结果集
treeSearcher.addToMatchSets(((TemplateSearchResult)treeSearchResult).getAddToMatchNode());
}
}

130
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchResult.java

@ -0,0 +1,130 @@
package com.fr.design.mainframe.manager.search.searcher.control.common;
import com.fr.design.search.control.TreeSearchResult;
import com.fr.file.filetree.FileNode;
import java.util.ArrayList;
import java.util.List;
/**
* 模板搜索结果
*/
public class TemplateSearchResult implements TreeSearchResult {
private boolean success;
private List<String> addToExpand;
private List<String> addToCalculated;
private List<FileNode> addToNotCalculated;
private List<FileNode> addToMatchNode;
protected TemplateSearchResult(TemplateSearchResult.Builder builder) {
this.success = builder.success;
this.addToMatchNode = builder.addToMatchNode;
this.addToExpand = builder.addToExpand;
this.addToCalculated = builder.addToCalculated;
this.addToNotCalculated = builder.addToNotCalculated;
}
public void setSuccess(boolean success) {
this.success = success;
}
public void setAddToMatchNode(List<FileNode> addToMatchNode) {
this.addToMatchNode = addToMatchNode;
}
public void setAddToExpand(List<String> addToExpand) {
this.addToExpand = addToExpand;
}
public void setAddToCalculated(List<String> addToCalculated) {
this.addToCalculated = addToCalculated;
}
public void setAddToNotCalculated(List<FileNode> addToNotCalculated) {
this.addToNotCalculated = addToNotCalculated;
}
@Override
public boolean isSuccess() {
return this.success;
}
@Override
public List<String> getAddToMatch() {
return new ArrayList<>();
}
public List<FileNode> getAddToMatchNode() {
return addToMatchNode;
}
@Override
public List<String> getAddToExpand() {
return this.addToExpand;
}
@Override
public List<String> getAddToCalculated() {
return this.addToCalculated;
}
public List<FileNode> getAddToNotCalculated() {
return this.addToNotCalculated;
}
public static class Builder {
private boolean success;
private List<FileNode> addToMatchNode;
private List<String> addToExpand;
private List<String> addToCalculated;
private List<FileNode> addToNotCalculated;
public Builder() {
this.success = false;
this.addToMatchNode = new ArrayList<>();
this.addToExpand = new ArrayList<>();
this.addToCalculated = new ArrayList<>();
this.addToNotCalculated = new ArrayList<>();
}
public TemplateSearchResult.Builder buildSuccess(boolean success) {
this.success = success;
return this;
}
public TemplateSearchResult.Builder buildAddToMatch(List<FileNode> addToMatch) {
this.addToMatchNode = addToMatch;
return this;
}
public TemplateSearchResult.Builder buildAddToExpand(List<String> addToExpand) {
this.addToExpand = addToExpand;
return this;
}
public TemplateSearchResult.Builder buildAddToCalculated(List<String> addToCalculated) {
this.addToCalculated = addToCalculated;
return this;
}
public TemplateSearchResult.Builder buildAddToNotCalculated(List<FileNode> addToNotCalculated) {
this.addToNotCalculated = addToNotCalculated;
return this;
}
public TemplateSearchResult build() {
return new TemplateSearchResult(this);
}
}
}

79
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchTask.java

@ -0,0 +1,79 @@
package com.fr.design.mainframe.manager.search.searcher.control.common;
import com.fr.design.search.control.TreeSearchCallback;
import com.fr.design.search.control.TreeSearchResult;
import com.fr.design.search.control.TreeSearchTask;
import com.fr.file.filetree.FileNode;
import com.fr.log.FineLoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
/**
* 模板搜索任务比较模板路径与搜索关键字是否匹配
*/
public class TemplateSearchTask implements TreeSearchTask {
/**
* 用户搜索的文本
*/
private String searchText;
/**
* 目录节点
*/
private FileNode fileNode;
private TreeSearchCallback callback;
public TemplateSearchTask(String searchText, FileNode fileNode, TreeSearchCallback callback) {
this.searchText = searchText;
this.fileNode = fileNode;
this.callback = callback;
}
@Override
public void run() {
TreeSearchResult result;
try {
result = dealWithTemplateWrapper(fileNode);
FineLoggerFactory.getLogger().debug("calculate template: {} succeeded", fileNode.getName());
} catch (Throwable e) {
FineLoggerFactory.getLogger().error(e, "calculate template: {} failed", fileNode.getName());
result = dealWithErrorTemplateWrapper(fileNode);
}
callback.done(result);
}
private TreeSearchResult dealWithTemplateWrapper(FileNode fileNode) {
String fileName = fileNode.getName();
boolean isNameMatch = isMatchSearch(fileName, searchText);
return new TemplateSearchResult.Builder()
.buildSuccess(true)
.buildAddToMatch(isNameMatch ? Arrays.asList(fileNode) : new ArrayList<>())
.buildAddToExpand(fileNode.isDirectory() ? Arrays.asList(fileName) : new ArrayList<>())
.buildAddToCalculated(Arrays.asList(fileNode.getEnvPath()))
.build();
}
/**
* 处理错误情况
*
* @param fileNode
*/
private TreeSearchResult dealWithErrorTemplateWrapper(FileNode fileNode) {
return new TemplateSearchResult.Builder().buildSuccess(false)
.buildAddToCalculated(Arrays.asList(fileNode.getEnvPath())).build();
}
/**
* 判断是否匹配搜索文本不区分大小写
*
* @param str
* @return
*/
private boolean isMatchSearch(String str, String searchText) {
return str.toUpperCase().contains(searchText.toUpperCase());
}
}

213
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateDirSearchRemindPane.java

@ -0,0 +1,213 @@
package com.fr.design.mainframe.manager.search.searcher.control.pane;
import com.fr.base.svg.IconUtils;
import com.fr.design.constants.UIConstants;
import com.fr.design.gui.itree.filetree.EnvFileTree;
import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager;
import com.fr.design.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.search.event.TreeSearchStatusChangeListener;
import com.fr.design.search.TreeSearchStatus;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.FlowLayout;
/**
* 目录树搜索提示面板整合了目录树面板和搜索时的提示面板
*/
public class TemplateDirSearchRemindPane extends JPanel implements TreeSearchStatusChangeListener {
private TemplateDirSearchRemindPane.RemindPane remindPane;
private TemplateDirSearchRemindPane.TreePane treePane;
public TemplateDirSearchRemindPane(EnvFileTree templateFileTree) {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
remindPane = new TemplateDirSearchRemindPane.RemindPane();
treePane = new TemplateDirSearchRemindPane.TreePane(templateFileTree);
// 初始状态
this.add(remindPane, BorderLayout.NORTH);
this.add(treePane, BorderLayout.CENTER);
TemplateDirTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this);
}
/**
* 根据搜索状态变化来调整自身面板的显示
*
* @param event
*/
@Override
public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) {
TreeSearchStatus status = event.getTreeSearchStatus();
if (status == TreeSearchStatus.SEARCH_NOT_BEGIN || status == TreeSearchStatus.NOT_IN_SEARCH_MODE) {
remindPane.onNotBegin();
treePane.onNotBegin();
} else if (status == TreeSearchStatus.SEARCHING) {
remindPane.onInSearching();
treePane.onInSearching();
} else if (status == TreeSearchStatus.SEARCH_STOPPED) {
remindPane.onStoppedSearching();
treePane.onStoppedSearching();
} else {
boolean matchSetsEmpty = TemplateDirTreeSearchManager.getInstance().isMatchSetsEmpty();
// 代表是否搜索出结果
remindPane.onDoneSearching(matchSetsEmpty);
treePane.onDoneSearching(matchSetsEmpty);
}
this.revalidate();
}
private interface TreeSearchStatusChange {
void onNotBegin();
void onInSearching();
void onStoppedSearching();
void onDoneSearching(boolean matchSetsEmpty);
}
private class TreePane extends JPanel implements TemplateDirSearchRemindPane.TreeSearchStatusChange {
private UIScrollPane scrollPane;
private JPanel notFoundPane;
private CardLayout cardLayout;
private static final String SCROLL_PANE = "scrollPane";
private static final String NOT_FOUND_PANE = "notFoundPane";
public TreePane(EnvFileTree templateFileTree) {
init(templateFileTree);
}
private void init(EnvFileTree templateFileTree) {
scrollPane = new UIScrollPane(templateFileTree);
scrollPane.setBorder(null);
notFoundPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(false, FlowLayout.CENTER, 0, 5);
UILabel emptyPicLabel = new UILabel();
emptyPicLabel.setIcon(IconUtils.readIcon("com/fr/base/images/share/no_match_icon.png"));
emptyPicLabel.setHorizontalAlignment(SwingConstants.CENTER);
emptyPicLabel.setPreferredSize(new Dimension(570, 100));
UILabel textLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Not_Match"), SwingConstants.CENTER);
textLabel.setForeground(Color.gray);
textLabel.setHorizontalAlignment(SwingConstants.CENTER);
textLabel.setPreferredSize(new Dimension(570, 20));
notFoundPane.add(emptyPicLabel);
notFoundPane.add(textLabel);
cardLayout = new CardLayout();
this.setLayout(cardLayout);
this.add(scrollPane, SCROLL_PANE);
this.add(notFoundPane, NOT_FOUND_PANE);
cardLayout.show(this, SCROLL_PANE);
}
@Override
public void onNotBegin() {
switchPane(SCROLL_PANE);
}
@Override
public void onInSearching() {
switchPane(SCROLL_PANE);
}
@Override
public void onStoppedSearching() {
switchPane(SCROLL_PANE);
}
@Override
public void onDoneSearching(boolean matchSetsEmpty) {
if (matchSetsEmpty) {
switchPane(NOT_FOUND_PANE);
}
}
private void switchPane(String paneName) {
cardLayout.show(this, paneName);
}
}
private static class RemindPane extends JPanel implements TemplateDirSearchRemindPane.TreeSearchStatusChange {
private static final String IN_SEARCHING = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_In_Searching");
private static final String STOP_SEARCHING = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Stop_Search");
private static final String SEARCHING_STOPPED = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Search_Stopped");
private static final String DONE_SEARCHING = Toolkit.i18nText("Fine-Design_Tree_Search_Search_Completed");
private UILabel textLabel;
private UILabel stopLabel;
private MouseListener stopSearch;
public RemindPane() {
init();
}
private void init() {
this.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0));
// 初始情况下为Not_Begin
textLabel = new UILabel();
textLabel.setForeground(Color.gray);
stopLabel = new UILabel();
stopLabel.setForeground(UIConstants.NORMAL_BLUE);
stopSearch = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
TemplateDirTreeSearchManager.getInstance().stopSearch();
}
};
stopLabel.addMouseListener(stopSearch);
this.add(textLabel);
this.add(stopLabel);
onNotBegin();
}
@Override
public void onNotBegin() {
this.setVisible(false);
}
@Override
public void onInSearching() {
this.textLabel.setVisible(false);
this.stopLabel.setText(STOP_SEARCHING);
this.stopLabel.setVisible(true);
this.setVisible(true);
}
@Override
public void onStoppedSearching() {
this.textLabel.setText(SEARCHING_STOPPED);
this.textLabel.setVisible(true);
this.stopLabel.setVisible(false);
this.setVisible(true);
}
@Override
public void onDoneSearching(boolean matchSetsEmpty) {
this.textLabel.setText(DONE_SEARCHING);
this.textLabel.setVisible(true);
this.stopLabel.setVisible(false);
this.setVisible(true);
}
}
}

152
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateDirTreeSearchPane.java

@ -0,0 +1,152 @@
package com.fr.design.mainframe.manager.search.searcher.control.pane;
import com.fr.base.svg.IconUtils;
import com.fr.design.constants.UIConstants;
import com.fr.design.file.TemplateDirTreePane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager;
import com.fr.design.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.search.event.TreeSearchStatusChangeListener;
import com.fr.stable.StringUtils;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Insets;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
/**
* 目录树搜索面板
*/
public class TemplateDirTreeSearchPane extends JPanel implements TreeSearchStatusChangeListener {
/**
* 搜索输入框
*/
private UITextField searchTextField;
/**
* 搜索面板
*/
private JPanel searchPane;
private final KeyAdapter enterPressed = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
TemplateDirTreeSearchManager.getInstance().startSearch(searchTextField.getText());
}
}
};
public TemplateDirTreeSearchPane() {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
this.setBorder(BorderFactory.createEmptyBorder(10, 15, 0, 10));
initSearchPane();
add(searchPane, BorderLayout.CENTER);
TemplateDirTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this);
TemplateDirTreePane.getInstance().refreshDockingView();
TemplateDirTreeSearchManager.getInstance().beforeSearch(TemplateDirTreePane.getInstance().getTemplateDirTree());
}
private void initSearchPane() {
searchPane = new JPanel(FRGUIPaneFactory.createBorderLayout());
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR));
searchPane.setBackground(Color.WHITE);
// 左侧搜索图标
UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search"));
searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 0));
searchLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// do nothing
}
});
// 中间输入框
initSearchTextField();
// 右侧返回图标
UILabel returnLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/clear"));
returnLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Tree_Search_Return"));
returnLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 11));
returnLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
TemplateDirTreeSearchManager.getInstance().outOfSearchMode();
TemplateDirTreePane.getInstance().refreshDockingView();
}
});
searchPane.add(searchLabel, BorderLayout.WEST);
searchPane.add(searchTextField, BorderLayout.CENTER);
searchPane.add(returnLabel, BorderLayout.EAST);
}
private void initSearchTextField() {
searchTextField = new UITextField(){
@Override
public Insets getInsets() {
return new Insets(2, 4, 0, 4);
}
};
searchTextField.setBorderPainted(false);
searchTextField.setPlaceholder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Template_Dir_Search_Press_Enter_For_Search"));
searchTextField.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.NORMAL_BLUE));
searchPane.repaint();
}
@Override
public void focusLost(FocusEvent e) {
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR));
searchPane.repaint();
}
});
this.searchTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
}
@Override
public void removeUpdate(DocumentEvent e) {
dealWithTextChange();
}
@Override
public void changedUpdate(DocumentEvent e) {
}
});
this.searchTextField.addKeyListener(enterPressed);
}
private void dealWithTextChange() {
if (StringUtils.isEmpty(searchTextField.getText()) && TemplateDirTreeSearchManager.getInstance().isInSearchMode()) {
// 如果是搜索模式下,看作是用户删除输入框文字,仅复原TemplateTreePane
TemplateDirTreeSearchManager.getInstance().restoreTreePane();
TemplateDirTreePane.getInstance().refreshDockingView();
}
}
/**
* 目录树不涉及到工具栏和搜索栏的切换无需实现
* @param event
*/
@Override
public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) {
}
}

228
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateSearchRemindPane.java

@ -0,0 +1,228 @@
package com.fr.design.mainframe.manager.search.searcher.control.pane;
import com.fr.base.svg.IconUtils;
import com.fr.design.constants.UIConstants;
import com.fr.design.gui.itree.filetree.EnvFileTree;
import com.fr.design.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.search.event.TreeSearchStatusChangeListener;
import com.fr.design.search.TreeSearchStatus;
import com.fr.design.gui.icontainer.UIScrollPane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.FlowLayout;
/**
* 模板搜索提示面板整合了模板树和提示面板
*/
public class TemplateSearchRemindPane extends JPanel implements TreeSearchStatusChangeListener {
private TemplateSearchRemindPane.RemindPane remindPane;
private TemplateSearchRemindPane.TreePane treePane;
public TemplateSearchRemindPane(EnvFileTree templateFileTree) {
this.setLayout(FRGUIPaneFactory.createBorderLayout());
remindPane = new TemplateSearchRemindPane.RemindPane();
treePane = new TemplateSearchRemindPane.TreePane(templateFileTree);
// 初始状态
this.add(remindPane, BorderLayout.NORTH);
this.add(treePane, BorderLayout.CENTER);
TemplateTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this);
}
/**
* 根据搜索状态变化来调整自身面板的显示
*
* @param event
*/
@Override
public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) {
TreeSearchStatus status = event.getTreeSearchStatus();
if (status == TreeSearchStatus.SEARCH_NOT_BEGIN || status == TreeSearchStatus.NOT_IN_SEARCH_MODE) {
remindPane.onNotBegin();
treePane.onNotBegin();
} else if (status == TreeSearchStatus.SEARCHING) {
remindPane.onInSearching();
treePane.onInSearching();
} else if (status == TreeSearchStatus.SEARCH_STOPPED) {
remindPane.onStoppedSearching();
treePane.onStoppedSearching();
} else {
boolean matchSetsEmpty = TemplateTreeSearchManager.getInstance().isMatchSetsEmpty();
// 代表是否搜索出结果
remindPane.onDoneSearching(matchSetsEmpty);
treePane.onDoneSearching(matchSetsEmpty);
}
this.revalidate();
}
private interface TreeSearchStatusChange {
/**
* 搜索未开始时
*/
void onNotBegin();
/**
* 搜索中
*/
void onInSearching();
/**
* 停止搜索
*/
void onStoppedSearching();
/**
* 搜索结束
* @param matchSetsEmpty
*/
void onDoneSearching(boolean matchSetsEmpty);
}
private class TreePane extends JPanel implements TemplateSearchRemindPane.TreeSearchStatusChange {
private UIScrollPane scrollPane;
private JPanel notFoundPane;
private CardLayout cardLayout;
private static final String SCROLL_PANE = "scrollPane";
private static final String NOT_FOUND_PANE = "notFoundPane";
public TreePane(EnvFileTree templateFileTree) {
init(templateFileTree);
}
private void init(EnvFileTree templateFileTree) {
scrollPane = new UIScrollPane(templateFileTree);
scrollPane.setBorder(null);
notFoundPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 5);
UILabel emptyPicLabel = new UILabel();
emptyPicLabel.setIcon(IconUtils.readIcon("com/fr/base/images/share/no_match_icon.png"));
emptyPicLabel.setHorizontalAlignment(SwingConstants.CENTER);
emptyPicLabel.setPreferredSize(new Dimension(240, 100));
UILabel textLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Not_Match"), SwingConstants.CENTER);
textLabel.setForeground(Color.gray);
textLabel.setHorizontalAlignment(SwingConstants.CENTER);
textLabel.setPreferredSize(new Dimension(240, 20));
notFoundPane.add(emptyPicLabel);
notFoundPane.add(textLabel);
notFoundPane.setBorder(BorderFactory.createEmptyBorder(80, 0, 0, 0));
cardLayout = new CardLayout();
this.setLayout(cardLayout);
this.add(scrollPane, SCROLL_PANE);
this.add(notFoundPane, NOT_FOUND_PANE);
cardLayout.show(this, SCROLL_PANE);
}
@Override
public void onNotBegin() {
switchPane(SCROLL_PANE);
}
@Override
public void onInSearching() {
switchPane(SCROLL_PANE);
}
@Override
public void onStoppedSearching() {
switchPane(SCROLL_PANE);
}
@Override
public void onDoneSearching(boolean matchSetsEmpty) {
if (matchSetsEmpty) {
switchPane(NOT_FOUND_PANE);
}
}
private void switchPane(String paneName) {
cardLayout.show(this, paneName);
}
}
private static class RemindPane extends JPanel implements TemplateSearchRemindPane.TreeSearchStatusChange {
private static final String IN_SEARCHING = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_In_Searching");
private static final String STOP_SEARCHING = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Stop_Search");
private static final String SEARCHING_STOPPED = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Search_Stopped");
private static final String DONE_SEARCHING = Toolkit.i18nText("Fine-Design_Tree_Search_Search_Completed");
private UILabel textLabel;
private UILabel stopLabel;
private MouseListener stopSearch;
public RemindPane() {
init();
}
private void init() {
this.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0));
// 初始情况下为Not_Begin
textLabel = new UILabel();
textLabel.setForeground(Color.gray);
stopLabel = new UILabel();
stopLabel.setForeground(UIConstants.NORMAL_BLUE);
stopSearch = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
TemplateTreeSearchManager.getInstance().stopSearch();
}
};
stopLabel.addMouseListener(stopSearch);
this.add(textLabel);
this.add(stopLabel);
onNotBegin();
}
@Override
public void onNotBegin() {
this.setVisible(false);
}
@Override
public void onInSearching() {
this.textLabel.setVisible(false);
this.stopLabel.setText(STOP_SEARCHING);
this.stopLabel.setVisible(true);
this.setVisible(true);
}
@Override
public void onStoppedSearching() {
this.textLabel.setText(SEARCHING_STOPPED);
this.textLabel.setVisible(true);
this.stopLabel.setVisible(false);
this.setVisible(true);
}
@Override
public void onDoneSearching(boolean matchSetsEmpty) {
this.textLabel.setText(DONE_SEARCHING);
this.textLabel.setVisible(true);
this.stopLabel.setVisible(false);
this.setVisible(true);
}
}
}

212
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateTreeSearchToolbarPane.java

@ -0,0 +1,212 @@
package com.fr.design.mainframe.manager.search.searcher.control.pane;
import com.fr.base.svg.IconUtils;
import com.fr.design.constants.UIConstants;
import com.fr.design.search.event.TreeSearchStatusChangeEvent;
import com.fr.design.search.event.TreeSearchStatusChangeListener;
import com.fr.design.search.TreeSearchStatus;
import com.fr.design.file.TemplateTreePane;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.gui.itextfield.UITextField;
import com.fr.design.gui.itoolbar.UIToolbar;
import com.fr.design.i18n.Toolkit;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.stable.StringUtils;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
/**
* 模板搜索工具栏
*/
public class TemplateTreeSearchToolbarPane extends JPanel implements TreeSearchStatusChangeListener {
public static final String TOOLBAR_PANE = "toolbarPane";
public static final String SEARCH_PANE = "searchPane";
/**
* 工具栏
*/
private UIToolbar toolbar;
/**
* 工具栏面板
*/
private JPanel toolbarPane;
/**
* 搜索面板
*/
private JPanel searchPane;
/**
* 搜索输入框
*/
private UITextField searchTextField;
/**
* 内容面板
*/
private JPanel contentPane;
/**
* 卡片布局管理器
*/
private CardLayout cardLayout;
private final KeyAdapter enterPressed = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
TemplateTreeSearchManager.getInstance().startSearch(searchTextField.getText());
}
}
};
public TemplateTreeSearchToolbarPane(UIToolbar toolbar) {
this.toolbar = toolbar;
this.setLayout(FRGUIPaneFactory.createBorderLayout());
initToolbarPane();
initSearchPane();
initContentPane();
add(contentPane, BorderLayout.CENTER);
setPreferredSize(new Dimension(240, 30));
TemplateTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this);
}
private void initContentPane() {
cardLayout = new CardLayout();
contentPane = new JPanel(cardLayout);
contentPane.add(searchPane, SEARCH_PANE);
contentPane.add(toolbarPane, TOOLBAR_PANE);
cardLayout.show(contentPane, TOOLBAR_PANE);
}
private void initSearchPane() {
searchPane = new JPanel(FRGUIPaneFactory.createBorderLayout());
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR));
searchPane.setBackground(Color.WHITE);
// 左侧搜索图标
UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search"));
searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 0));
searchLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// do nothing
}
});
// 中间输入框
initSearchTextField();
// 右侧返回图标
UILabel returnLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/clear"));
returnLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Tree_Search_Return"));
returnLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 11));
returnLabel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
TemplateTreeSearchManager.getInstance().outOfSearchMode();
TemplateTreePane.getInstance().refreshDockingView();
}
});
searchPane.add(searchLabel, BorderLayout.WEST);
searchPane.add(searchTextField, BorderLayout.CENTER);
searchPane.add(returnLabel, BorderLayout.EAST);
}
private void initSearchTextField() {
searchTextField = new UITextField(){
@Override
public Insets getInsets() {
return new Insets(2, 4, 0, 4);
}
};
searchTextField.setBorderPainted(false);
searchTextField.setPlaceholder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Template_Search_Press_Enter_For_Search"));
searchTextField.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.NORMAL_BLUE));
searchPane.repaint();
}
@Override
public void focusLost(FocusEvent e) {
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR));
searchPane.repaint();
}
});
this.searchTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
}
@Override
public void removeUpdate(DocumentEvent e) {
dealWithTextChange();
}
@Override
public void changedUpdate(DocumentEvent e) {
}
});
this.searchTextField.addKeyListener(enterPressed);
}
private void dealWithTextChange() {
if (StringUtils.isEmpty(searchTextField.getText()) && TemplateTreeSearchManager.getInstance().isInSearchMode()) {
// 如果是搜索模式下,看作是用户删除输入框文字,仅复原TemplateTreePane
TemplateTreeSearchManager.getInstance().restoreTreePane();
TemplateTreePane.getInstance().refreshDockingView();
}
}
private void initToolbarPane() {
toolbarPane = new JPanel();
toolbarPane.setLayout(FRGUIPaneFactory.createBorderLayout());
toolbarPane.add(toolbar, BorderLayout.CENTER);
}
/**
* 交换当前面板层级
*/
public void switchPane(String name) {
cardLayout.show(contentPane, name);
}
public void setPlaceHolder(String placeHolder) {
this.searchTextField.setPlaceholder(placeHolder);
}
/**
* 根据搜索状态变化来调整自身面板的显示
*
* @param event
*/
@Override
public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) {
TreeSearchStatus treeSearchStatus = event.getTreeSearchStatus();
if (treeSearchStatus == TreeSearchStatus.NOT_IN_SEARCH_MODE) {
this.searchTextField.setText(StringUtils.EMPTY);
switchPane(TOOLBAR_PANE);
} else {
switchPane(SEARCH_PANE);
}
}
}

35
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplateDirPreSearchTask.java

@ -0,0 +1,35 @@
package com.fr.design.mainframe.manager.search.searcher.control.pre;
import com.fr.design.file.TemplateDirTreePane;
import com.fr.design.search.control.TreeSearchCallback;
import com.fr.file.filetree.FileNode;
import java.util.List;
/**
* 目录树搜索时的前置处理跟模板搜索前置处理类似
*/
public class TemplateDirPreSearchTask extends TemplatePreSearchTask {
public TemplateDirPreSearchTask(TreeSearchCallback callback, FileNode fileNode) {
super(callback, fileNode);
}
/**
* 加载最外层目录下所有的子节点
*
* @param fileNodes
* @param fileNode
*/
protected void dealWithChildTemplate(List<FileNode> fileNodes, FileNode fileNode) {
FileNode[] childNodes = TemplateDirTreePane.getInstance().getTemplateDirTree().listFile(fileNode.getEnvPath());
for (FileNode childNode : childNodes) {
if (childNode.isDirectory()) {
fileNodes.add(childNode);
dealWithChildTemplate(fileNodes, childNode);
} else {
fileNodes.add(childNode);
}
}
}
}

33
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplatePreSearchCallBack.java

@ -0,0 +1,33 @@
package com.fr.design.mainframe.manager.search.searcher.control.pre;
import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchCallBack;
import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchResult;
import com.fr.design.search.control.TreeSearchResult;
import com.fr.design.mainframe.manager.search.searcher.TemplateTreeSearcher;
/**
* 模板搜索前置回调处理
* 主要是将最外层目录下的所有模板添加到未计算的集合中
*/
public class TemplatePreSearchCallBack extends TemplateSearchCallBack {
public TemplatePreSearchCallBack(TemplateTreeSearcher treeSearcher) {
super(treeSearcher);
}
@Override
public void done(TreeSearchResult searchResult) {
addToTreeSearcher(searchResult);
}
/**
* 将结果添加到未计算的集合中
*
* @param searchResult
*/
@Override
protected void addToTreeSearcher(TreeSearchResult searchResult) {
TemplateSearchResult templateSearchResult = (TemplateSearchResult) searchResult;
treeSearcher.addToNotCalculatedSets(templateSearchResult.getAddToNotCalculated());
}
}

62
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplatePreSearchTask.java

@ -0,0 +1,62 @@
package com.fr.design.mainframe.manager.search.searcher.control.pre;
import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchResult;
import com.fr.design.search.control.TreeSearchCallback;
import com.fr.design.search.control.TreeSearchResult;
import com.fr.design.search.control.TreeSearchTask;
import com.fr.design.file.TemplateTreePane;
import com.fr.file.filetree.FileNode;
import com.fr.log.FineLoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* 模板搜索前置任务
* 主要是计算最外层目录下面所有的子节点并记录到结果集中
*/
public class TemplatePreSearchTask implements TreeSearchTask {
protected TreeSearchCallback callback;
//最外层的目录节点
protected FileNode fileNode;
public TemplatePreSearchTask(TreeSearchCallback callback, FileNode fileNode) {
this.callback = callback;
this.fileNode = fileNode;
}
@Override
public void run() {
TreeSearchResult result;
try {
List<FileNode> allChildNode = new ArrayList<>();
dealWithChildTemplate(allChildNode, fileNode);
result = new TemplateSearchResult.Builder().buildAddToNotCalculated(allChildNode).buildSuccess(true).build();
FineLoggerFactory.getLogger().info("[Template Search] calculate {} child nodes success. total child node num is: {}", fileNode.getEnvPath(), allChildNode.size());
} catch (Exception e) {
FineLoggerFactory.getLogger().error("[Template Search] calculate {} child nodes failed", fileNode.getEnvPath());
result = new TemplateSearchResult.Builder().buildAddToNotCalculated(new ArrayList<>()).buildSuccess(false).build();
}
callback.done(result);
}
/**
* 加载最外层目录下所有的子节点
*
* @param fileNodes
* @param fileNode
*/
protected void dealWithChildTemplate(List<FileNode> fileNodes, FileNode fileNode) {
FileNode[] childNodes = TemplateTreePane.getInstance().getTemplateFileTree().listFile(fileNode.getEnvPath());
for (FileNode childNode : childNodes) {
if (childNode.isDirectory()) {
fileNodes.add(childNode);
dealWithChildTemplate(fileNodes, childNode);
} else {
fileNodes.add(childNode);
}
}
}
}

6
designer-base/src/main/java/com/fr/design/mainframe/share/collect/ComponentSender.java

@ -17,13 +17,7 @@ public class ComponentSender {
private static final String CLOUD_REUSE_URL = "https://cloud.fanruan.com/api/monitor/record_of_reusePlugin/single";
public static boolean send() {
long start = System.currentTimeMillis();
String content = ComponentCollector.getInstance().generateTotalInfo();
long end = System.currentTimeMillis();
FineLoggerFactory.getLogger().error("cal time cost {} ms", end - start);
return sendInfo(CLOUD_REUSE_URL, content);
}

2
designer-base/src/main/java/com/fr/design/mainframe/theme/utils/DefaultThemedTemplateCellElementCase.java

@ -33,7 +33,7 @@ public class DefaultThemedTemplateCellElementCase {
private static DefaultTemplateCellElement themingCellElement(DefaultTemplateCellElement cellElement) {
JTemplate<?,?> template = HistoryTemplateListCache.getInstance().getCurrentEditingTemplate();
if (template != null) {
if (JTemplate.isValid(template)) {
TemplateTheme theme = template.getTemplateTheme();
ThemedCellStyle themedCellStyle = theme.getCellStyleList().getUse4Default();
if (themedCellStyle != null) {

194
designer-base/src/main/java/com/fr/design/mainframe/toast/SimpleToast.java

@ -0,0 +1,194 @@
package com.fr.design.mainframe.toast;
import com.fr.concurrent.NamedThreadFactory;
import com.fr.design.dialog.UIDialog;
import com.fr.design.gui.ilable.UILabel;
import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.module.ModuleContext;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Window;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* toast弹窗
* */
public class SimpleToast extends UIDialog {
private static final int MIN_HEIGHT = 36;
private static final String TOAST_MSG_TIMER = "TOAST_MSG_TIMER";
private static final long DEFAULT_DISAPPEAR_DELAY = 5000;
private static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.MILLISECONDS;
private ScheduledExecutorService timer;
private int hideHeight = 0;
private JPanel contentPane;
private boolean show = false;
private Window parent;
private boolean autoDisappear;
public SimpleToast(Window parent, Icon icon, String text, boolean autoDisappear) {
super(parent);
this.parent = parent;
this.autoDisappear = autoDisappear;
JPanel panel = createContentPane(icon, text);
init(panel);
}
private JPanel createContentPane(Icon icon, String text) {
JPanel pane = FRGUIPaneFactory.createBorderLayout_S_Pane();
UILabel iconLabel = new UILabel(icon);
iconLabel.setVerticalAlignment(SwingConstants.TOP);
iconLabel.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0));
UILabel textLabel = new UILabel(text);
pane.add(iconLabel, BorderLayout.WEST);
pane.add(textLabel, BorderLayout.CENTER);
pane.setBorder(BorderFactory.createEmptyBorder(8, 15, 8, 15));
return pane;
}
private void init(JPanel panel) {
setFocusable(false);
setAutoRequestFocus(false);
setUndecorated(true);
contentPane = panel;
initComponent();
}
private void initComponent() {
this.getContentPane().setLayout(null);
this.getContentPane().add(contentPane);
Dimension dimension = calculatePreferSize();
hideHeight = dimension.height;
setSize(new Dimension(dimension.width, 0));
contentPane.setSize(dimension);
setRelativeLocation(dimension);
if (autoDisappear) {
disappear(contentPane);
}
}
private void setRelativeLocation(Dimension dimension) {
int positionX = parent.getLocationOnScreen().x + (parent.getWidth() - dimension.width) / 2;
int positionY = parent.getLocationOnScreen().y + 10;
this.setLocation(positionX, positionY);
}
private Dimension calculatePreferSize() {
Dimension contentDimension = contentPane.getPreferredSize();
int height = Math.max(MIN_HEIGHT, contentDimension.height);
return new Dimension(contentDimension.width, height);
}
public void display(JPanel outerPanel) {
show = true;
outerPanel.setLocation(0, -hideHeight);
ScheduledExecutorService tipToolTimer = createToastScheduleExecutorService();
tipToolTimer.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
SwingUtilities.invokeLater(()->{
displayStep(outerPanel, tipToolTimer);
});
}
}, 0, 50, TimeUnit.MILLISECONDS);
}
void displayStep(JPanel outerPanel, ScheduledExecutorService timer) {
Point point = outerPanel.getLocation();
if (point.y >= 0 && !timer.isShutdown()) {
timer.shutdown();
}
int showDistance = 5 + point.y < 0 ? 5 : -point.y;
outerPanel.setLocation(point.x, point.y + showDistance);
Dimension dimension = SimpleToast.this.getSize();
SimpleToast.this.setSize(new Dimension(dimension.width, dimension.height + showDistance));
}
private void disappear(JPanel outerPanel, long delay, TimeUnit timeUnit) {
timer = createToastScheduleExecutorService();
timer.schedule(new DisappearMotion(outerPanel), delay, timeUnit);
}
/**
* toast消失的动画效果
* */
class DisappearMotion implements Runnable {
JPanel panel;
DisappearMotion(JPanel panel) {
this.panel = panel;
}
@Override
public void run() {
ScheduledExecutorService tipToolTimer = createToastScheduleExecutorService();
tipToolTimer.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
SwingUtilities.invokeLater(()->{
disappearStep(tipToolTimer);
});
}
}, 0, 50, TimeUnit.MILLISECONDS);
}
void disappearStep(ScheduledExecutorService timer) {
Point point = panel.getLocation();
if (point.y <= -hideHeight && !timer.isShutdown()) {
timer.shutdown();
SimpleToast.this.setVisible(false);
SimpleToast.this.dispose();
SimpleToast.this.show = false;
}
panel.setLocation(point.x, point.y - 5);
Dimension dimension = SimpleToast.this.getSize();
SimpleToast.this.setSize(new Dimension(dimension.width, dimension.height - 5));
}
}
private void disappear(JPanel outerPanel) {
disappear(outerPanel, DEFAULT_DISAPPEAR_DELAY, DEFAULT_TIME_UNIT);
}
private ScheduledExecutorService createToastScheduleExecutorService() {
return ModuleContext.getExecutor().newSingleThreadScheduledExecutor(new NamedThreadFactory(TOAST_MSG_TIMER));
}
@Override
public void checkValid() throws Exception {
}
public void setVisible(boolean visible) {
super.setVisible(visible);
if (visible) {
display(contentPane);
}
}
@Override
public void dispose() {
super.dispose();
}
}

35
designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java

@ -13,6 +13,7 @@ import com.fr.design.mainframe.JTemplateActionListener;
import com.fr.design.mainframe.vcs.VcsConfigManager;
import com.fr.design.mainframe.vcs.ui.FileVersionTable;
import com.fr.general.IOUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.plugin.context.PluginContext;
import com.fr.plugin.manage.PluginManager;
import com.fr.report.entity.VcsEntity;
@ -26,6 +27,7 @@ import com.fr.workspace.server.vcs.git.config.GcConfig;
import javax.swing.Icon;
import javax.swing.border.EmptyBorder;
import java.awt.Color;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -49,6 +51,8 @@ public class VcsHelper implements JTemplateActionListener {
public final static int OFFSET = 2;
private static final int MINUTE = 60 * 1000;
private final static String VCS_PLUGIN_ID = "com.fr.plugin.vcs.v10";
private final static String VCS_FILE_SLASH = "/";
private final static String SERVICE_NAME_MOVE = "moveVcs";
private static final VcsHelper INSTANCE = new VcsHelper();
public static VcsHelper getInstance() {
@ -97,7 +101,7 @@ public class VcsHelper implements JTemplateActionListener {
} else if (editingFilePath.startsWith(vcsCacheDir)) {
editingFilePath = editingFilePath.replaceFirst(vcsCacheDir, StringUtils.EMPTY);
}
if (editingFilePath.startsWith("/")) {
if (editingFilePath.startsWith(VCS_FILE_SLASH)) {
editingFilePath = editingFilePath.substring(1);
}
return editingFilePath;
@ -140,7 +144,7 @@ public class VcsHelper implements JTemplateActionListener {
if (jt.getEditingFILE() instanceof VcsCacheFileNodeFile) {
operator.saveVersionFromCache(getCurrentUsername(), fileName, StringUtils.EMPTY, latestFileVersion + 1);
String path = DesignerFrameFileDealerPane.getInstance().getSelectedOperation().getFilePath();
FileVersionTable.getInstance().updateModel(1, WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst("/", "")));
FileVersionTable.getInstance().updateModel(1, WorkContext.getCurrent().get(VcsOperator.class).getVersions(path.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY)));
} else {
operator.saveVersion(getCurrentUsername(), fileName, StringUtils.EMPTY, latestFileVersion + 1);
}
@ -157,6 +161,33 @@ public class VcsHelper implements JTemplateActionListener {
fireVcs.shutdown();
}
/**
* 移动Vcs
* @param oldName
* @param newName
*/
public void moveVcs(String oldName, String newName) {
ExecutorService moveVcs = Executors.newSingleThreadExecutor(new NamedThreadFactory(SERVICE_NAME_MOVE));
moveVcs.execute(new Runnable() {
@Override
public void run() {
VcsOperator operator = WorkContext.getCurrent().get(VcsOperator.class);
String oldPath = oldName.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY);
List<VcsEntity> oldVcsEntities = operator.getVersions(oldPath);
for (VcsEntity oldVcsEntity : oldVcsEntities) {
operator.saveVersion(oldVcsEntity.getUsername(), newName.replaceFirst(VCS_FILE_SLASH, StringUtils.EMPTY), oldVcsEntity.getCommitMsg(), oldVcsEntity.getVersion());
operator.deleteVersion(oldPath, oldVcsEntity.getVersion());
}
FineLoggerFactory.getLogger().debug("moveVcs success. from {} to {}", oldName, newName);
if (GcConfig.getInstance().isGcEnable()) {
operator.gc();
}
}
});
moveVcs.shutdown();
}
@Override
public void templateOpened(JTemplate<?, ?> jt) {

2
designer-base/src/main/java/com/fr/design/report/WatermarkPane.java

@ -47,7 +47,7 @@ import java.awt.FlowLayout;
* Created by plough on 2018/5/15.
*/
public class WatermarkPane extends BasicPane {
private static final int MAX_WIDTH = 160;
private static final int MAX_WIDTH = 216;
// 水印预览面板
private WatermarkPreviewPane watermarkPreviewPane;

2
designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TreeSearchStatus.java → designer-base/src/main/java/com/fr/design/search/TreeSearchStatus.java

@ -1,4 +1,4 @@
package com.fr.design.data.datapane.management.search.searcher;
package com.fr.design.search;
/**
* @author Yvan

2
designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TreeSearcher.java → designer-base/src/main/java/com/fr/design/search/TreeSearcher.java

@ -1,4 +1,4 @@
package com.fr.design.data.datapane.management.search.searcher;
package com.fr.design.search;
/**

2
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/TreeSearchCallback.java → designer-base/src/main/java/com/fr/design/search/control/TreeSearchCallback.java

@ -1,4 +1,4 @@
package com.fr.design.data.datapane.management.search.control;
package com.fr.design.search.control;
/**

9
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/TreeSearchResult.java → designer-base/src/main/java/com/fr/design/search/control/TreeSearchResult.java

@ -1,4 +1,4 @@
package com.fr.design.data.datapane.management.search.control;
package com.fr.design.search.control;
import java.util.List;
@ -15,23 +15,24 @@ public interface TreeSearchResult {
boolean isSuccess();
/**
* 数据集名称匹配或者列名匹配时需要将数据集名称添加到匹配结果集中
* 数据匹配时需要将名称添加到匹配结果集中
*
* @return
*/
List<String> getAddToMatch();
/**
* 数据集有列名匹配时需要添加到展开结果集中
* 数据匹配时需要添加到展开结果集中
*
* @return
*/
List<String> getAddToExpand();
/**
* 数据完成计算后需要添加到完成结果集中
* 数据完成计算后需要添加到完成结果集中
*
* @return
*/
List<String> getAddToCalculated();
}

2
designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/TreeSearchTask.java → designer-base/src/main/java/com/fr/design/search/control/TreeSearchTask.java

@ -1,4 +1,4 @@
package com.fr.design.data.datapane.management.search.control;
package com.fr.design.search.control;
/**
* @author Yvan

4
designer-base/src/main/java/com/fr/design/data/datapane/management/search/event/TreeSearchStatusChangeEvent.java → designer-base/src/main/java/com/fr/design/search/event/TreeSearchStatusChangeEvent.java

@ -1,6 +1,6 @@
package com.fr.design.data.datapane.management.search.event;
package com.fr.design.search.event;
import com.fr.design.data.datapane.management.search.searcher.TreeSearchStatus;
import com.fr.design.search.TreeSearchStatus;
import java.util.EventObject;

2
designer-base/src/main/java/com/fr/design/data/datapane/management/search/event/TreeSearchStatusChangeListener.java → designer-base/src/main/java/com/fr/design/search/event/TreeSearchStatusChangeListener.java

@ -1,4 +1,4 @@
package com.fr.design.data.datapane.management.search.event;
package com.fr.design.search.event;
import java.util.EventListener;

16
designer-base/src/main/java/com/fr/design/data/datapane/management/search/view/TreeSearchRendererHelper.java → designer-base/src/main/java/com/fr/design/search/view/TreeSearchRendererHelper.java

@ -1,6 +1,6 @@
package com.fr.design.data.datapane.management.search.view;
package com.fr.design.search.view;
import com.fr.design.data.datapane.TableDataTree;
import com.fr.design.gui.itree.refreshabletree.RefreshableJTree;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;
@ -29,19 +29,19 @@ public class TreeSearchRendererHelper {
this.originTreeCellRenderer = originTreeCellRenderer;
}
public void replaceTreeRenderer(TableDataTree tableDataTree, String searchText) {
tableDataTree.setCellRenderer(getNewTreeCellRenderer(searchText));
public void replaceTreeRenderer(RefreshableJTree tree, String searchText) {
tree.setCellRenderer(getNewTreeCellRenderer(searchText));
}
public void save(TableDataTree tableDataTree) {
public void save(TreeCellRenderer originTreeCellRenderer) {
if (getOriginTreeCellRenderer() == null) {
setOriginTreeCellRenderer(tableDataTree.getTableDataTreeCellRenderer());
setOriginTreeCellRenderer(originTreeCellRenderer);
}
}
public void restore(TableDataTree tableDataTree) {
public void restore(RefreshableJTree tree) {
if (getOriginTreeCellRenderer() != null) {
tableDataTree.setCellRenderer(getOriginTreeCellRenderer());
tree.setCellRenderer(getOriginTreeCellRenderer());
}
}

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

@ -72,7 +72,7 @@ public class NewColorSelectPane extends BasicPane implements ColorSelectable {
}
public NewColorSelectPane(boolean isSupportTransparent) {
this(isSupportTransparent, true);
this(isSupportTransparent, !DesignerContext.getDesignerFrame().isServerConfig());
}
/**

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

@ -27,6 +27,38 @@ public class ColorUtils {
}
}
}
/**
* 递归的同步颜色如何组件的背景颜色等于默认颜色的话变更为 replaceColor
*
* @param component 组件
* @param replaceColor 替换颜色
* @param defaultColor 默认颜色
*/
public static void syncBackgroundIfAbsent(Component component, Color replaceColor, Color defaultColor) {
if (component.getBackground() != defaultColor) {
return;
}
component.setBackground(replaceColor);
if (component instanceof Container) {
Container container = (Container) component;
Component[] components = container.getComponents();
if (components != null) {
Arrays.stream(components).forEach((e) -> syncBackgroundIfAbsent(e, replaceColor, defaultColor));
}
}
}
/**
* 使背景透明
*
* @param component 组件
*/
public static void transparentBackground(Component component) {
syncBackgroundIfAbsent(component, new Color(0,0,0,0), ThemeUtils.BACK_COLOR);
}
public static boolean isDarkColor(Color color) {
if(color == null) {

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

Loading…
Cancel
Save