Browse Source

REPORT-75090 feat:设计器模板文件管理

feature/x
roger 2 years ago
parent
commit
a4a20d1440
  1. 39
      designer-base/src/main/java/com/fr/design/actions/file/DelFileAction.java
  2. 136
      designer-base/src/main/java/com/fr/design/actions/file/LocateAction.java
  3. 323
      designer-base/src/main/java/com/fr/design/actions/file/RenameAction.java
  4. 10
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/TableDataTreeSearchManager.java
  5. 6
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchCallBack.java
  6. 2
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchResult.java
  7. 6
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/common/TableDataSearchTask.java
  8. 2
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchCallBack.java
  9. 2
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchResult.java
  10. 8
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/control/pre/TableDataPreSearchTask.java
  11. 6
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TableDataSearchRemindPane.java
  12. 7
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/pane/TreeSearchToolbarPane.java
  13. 2
      designer-base/src/main/java/com/fr/design/data/datapane/management/search/searcher/TableDataTreeSearcher.java
  14. 545
      designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java
  15. 5
      designer-base/src/main/java/com/fr/design/file/FileOperations.java
  16. 163
      designer-base/src/main/java/com/fr/design/file/MutilTempalteTabPane.java
  17. 79
      designer-base/src/main/java/com/fr/design/file/TemplateDirTreePane.java
  18. 45
      designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java
  19. 73
      designer-base/src/main/java/com/fr/design/gui/itree/filetree/EnvFileTree.java
  20. 54
      designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateDirTree.java
  21. 113
      designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateFileTree.java
  22. 8
      designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/ExpandMutableTreeNode.java
  23. 5
      designer-base/src/main/java/com/fr/design/gui/itree/refreshabletree/RefreshableJTree.java
  24. 373
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java
  25. 63
      designer-base/src/main/java/com/fr/design/mainframe/manager/clip/TemplateTreeClipboard.java
  26. 190
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateDirTreeSearchManager.java
  27. 222
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateTreeSearchManager.java
  28. 164
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/TemplateDirTreeSearcher.java
  29. 163
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/TemplateTreeSearcher.java
  30. 49
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateDirSearchCallBack.java
  31. 59
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchCallBack.java
  32. 127
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchResult.java
  33. 75
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/common/TemplateSearchTask.java
  34. 211
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateDirSearchRemindPane.java
  35. 149
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateDirTreeSearchPane.java
  36. 212
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateSearchRemindPane.java
  37. 209
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateTreeSearchToolbarPane.java
  38. 32
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplateDirPreSearchTask.java
  39. 26
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplatePreSearchCallBack.java
  40. 58
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pre/TemplatePreSearchTask.java
  41. 19
      designer-base/src/main/java/com/fr/design/search/TreeSearchManager.java
  42. 2
      designer-base/src/main/java/com/fr/design/search/TreeSearchStatus.java
  43. 2
      designer-base/src/main/java/com/fr/design/search/TreeSearcher.java
  44. 2
      designer-base/src/main/java/com/fr/design/search/control/TreeSearchCallback.java
  45. 9
      designer-base/src/main/java/com/fr/design/search/control/TreeSearchResult.java
  46. 2
      designer-base/src/main/java/com/fr/design/search/control/TreeSearchTask.java
  47. 4
      designer-base/src/main/java/com/fr/design/search/event/TreeSearchStatusChangeEvent.java
  48. 2
      designer-base/src/main/java/com/fr/design/search/event/TreeSearchStatusChangeListener.java
  49. 16
      designer-base/src/main/java/com/fr/design/search/view/TreeSearchRendererHelper.java
  50. 19
      designer-base/src/main/java/com/fr/file/FILEChooserPane.java
  51. BIN
      designer-base/src/main/resources/com/fr/design/images/FileDealerPaneIcon/collapse-all.png
  52. BIN
      designer-base/src/main/resources/com/fr/design/images/FileDealerPaneIcon/locate.png
  53. BIN
      designer-base/src/main/resources/com/fr/design/images/m_edit/move.png

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

@ -0,0 +1,39 @@
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 java.awt.event.ActionEvent;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
/*
* 删除指定文件
*/
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;
}
selectedOperation.deleteFile();
DesignerFrameFileDealerPane.getInstance().stateChange();
DesignerContext.getDesignerFrame().setTitle();
}
}

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

@ -0,0 +1,136 @@
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.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.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());
}
public static void gotoEditingTemplateLeaf(String locatedPath) {
if (locatedPath == null) {
return;
}
DefaultTreeModel model = (DefaultTreeModel) TemplateTreePane.getInstance().getTemplateFileTree().getModel();
ExpandMutableTreeNode treeNode = (ExpandMutableTreeNode) model.getRoot();
recursiveSelectPath(treeNode, locatedPath, model);
TreePath selectedTreePath = TemplateTreePane.getInstance().getTemplateFileTree().getSelectionPath();
if (selectedTreePath != null) {
TemplateTreePane.getInstance().getTemplateFileTree().scrollPathToVisible(selectedTreePath);
}
}
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))) {
TemplateTreePane.getInstance().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 = TemplateTreePane.getInstance().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;
}
}

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

@ -0,0 +1,323 @@
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.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.stable.CoreConstants;
import com.fr.stable.StringUtils;
import com.fr.third.org.apache.commons.io.FilenameUtils;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JPanel;
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;
public class RenameAction extends UpdateAction {
private FileOperations selectedOperation;
public static final com.fr.event.Event<TwoTuple<String, String>> TEMPLATE_RENAME = new Event<TwoTuple<String, String>>() {
};
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) {
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());
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(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.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();
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.refreshParent();
DesignerContext.getDesignerFrame().setTitle();
} else {
FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Rename_Failure"),
Toolkit.i18nText("Fine-Design_Basic_Error"),
DEFAULT_OPTION,
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;
}
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)) {
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;
}
}
}

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;

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

@ -1,8 +1,8 @@
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.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;

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;

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

@ -0,0 +1,545 @@
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.utils.gui.GUICoreUtils;
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.StableUtils;
import com.fr.stable.StringUtils;
import com.fr.stable.collections.CollectionUtils;
import com.fr.stable.project.ProjectConstants;
import com.fr.workspace.WorkContext;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
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.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import static javax.swing.JOptionPane.INFORMATION_MESSAGE;
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;
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();
//右键菜单
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());
}
@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);
int length = getFileTree().getSelectionCount();
if (length == 0) {
//没有选中文件时,只能黏贴
if (!CollectionUtils.isEmpty(TemplateTreeClipboard.getInstance().takeFromClip())) {
pasteAction.setEnabled(true);
}
return;
}
if (length == 1) {
//选中一个时可以,可以重命名、黏贴
renameAction.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 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) {
checkFreeOrLock(treeNode, pasteNodes, lockedNodes);
}
if (lockedNodes.isEmpty()) {
doPaste(targetDir, pasteNodes);
} else {
if (FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Confirm_Paste_Unlock_File"),
Toolkit.i18nText("Fine-Design_Basic_Confirm"),
YES_NO_OPTION)
== JOptionPane.YES_OPTION) {
// 黏贴其他可黏贴的文件
doPaste(targetDir, pasteNodes);
}
}
// 移动时如果正在搜索,跳回原树
if (TemplateTreeSearchManager.getInstance().isInSearchMode()) {
TemplateTreeSearchManager.getInstance().outOfSearchMode();
}
DesignerFrameFileDealerPane.getInstance().getSelectedOperation().refresh();
String targetFile = StableUtils.pathJoin(targetDir, ((FileNode) (pasteNodes.get(0).getUserObject())).getName());
LocateAction.gotoEditingTemplateLeaf(targetFile);
}
/**
* 检测是否能够黏贴
* @param treeNodeList
* @return
*/
private boolean canPaste(List<ExpandMutableTreeNode> treeNodeList) {
if (CollectionUtils.isEmpty(treeNodeList)) {
return false;
}
//确定目标目录并检查权限
FileOperations selectedOperation = DesignerFrameFileDealerPane.getInstance().getSelectedOperation();
if (getFileTree().getSelectionCount() != 0 && !selectedOperation.access()) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return false;
}
return true;
}
private void doPaste(String targetDir, List<ExpandMutableTreeNode> pasteNodes) {
try {
if (StringUtils.isEmpty(targetDir)) {
return;
}
if (pasteNodes.isEmpty()) {
//提示:复制的文件都不能黏贴
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Unable_Delete_Locked_File"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return;
}
for (ExpandMutableTreeNode node : pasteNodes) {
if (node.getUserObject() instanceof FileNode) {
FileNode fileNode = (FileNode) node.getUserObject();
copyFile(fileNode, targetDir);
FineLoggerFactory.getLogger().debug("Template: {} paste to {} success.", fileNode.getEnvPath(), targetDir);
}
}
} catch (HeadlessException 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);
}
}
}
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;
}
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_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() {
this.setLayout(new BorderLayout());
this.setModal(true);
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.setAlwaysOnTop(true);
this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
GUICoreUtils.setWindowCenter(DesignerContext.getDesignerFrame(), this);
this.setVisible(true);
}
private void confirmClose() {
//获取目录数中所选中的文件,并判断是否有权限
if (getFileTree().getSelectionCount() != 0 && !TemplateDirTreePane.getInstance().selectedAccess()) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
return;
}
boolean moveSuccess = doMove();
dispose();
if (moveSuccess) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Template_Moved_Success"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
INFORMATION_MESSAGE);
// 移动时如果正在搜索,跳回原树
if (TemplateTreeSearchManager.getInstance().isInSearchMode()) {
TemplateTreeSearchManager.getInstance().outOfSearchMode();
}
DesignerFrameFileDealerPane.getInstance().getSelectedOperation().refresh();
LocateAction.gotoEditingTemplateLeaf(targetFile);
}
}
private boolean doMove() {
FileNode fileNode = getDirTree().getSelectedFileNode();
fileNode = fileNode == null ? (FileNode) getFileTree().getModel().getRoot() : fileNode;
boolean moveSuccess = true;
try {
//待移动的文件可以有多个
ExpandMutableTreeNode[] sourceSelected = getFileTree().getSelectedTreeNodes();
for (ExpandMutableTreeNode treeNode : sourceSelected) {
FileNode sourceFileNode = (FileNode) treeNode.getUserObject();
targetFile = copyFile(sourceFileNode, fileNode.getEnvPath());
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(), fileNode.getEnvPath());
} else {
//删除失败,将复制过去的文件删掉
TemplateResourceManager.getResource().delete(new FileNodeFILE(targetFile));
FineLoggerFactory.getLogger().error("template {} move to {} failed.", sourceFileNode.getEnvPath(), fileNode.getEnvPath());
moveSuccess = false;
}
}
}
} 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();
}
}
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;
}
return checkChildNode(node, dNodes, lNodes, selfEmptyLock);
}
private boolean checkChildNode(ExpandMutableTreeNode node, ArrayList<ExpandMutableTreeNode> dNodes, ArrayList<ExpandMutableTreeNode> lNodes, boolean selfEmptyLock) {
ExpandMutableTreeNode[] children = getFileTree().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;
}
/**
* 黏贴时确定黏贴的目录
*
* @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;
}
private void copyDir(String sourceDir, String targetDir) {
FileNode[] fileNodes = getFileTree().listFile(sourceDir);
for (FileNode fileNode : fileNodes) {
if (fileNode.isDirectory()) {
copyDir(StableUtils.pathJoin(fileNode.getParent(), fileNode.getName()), StableUtils.pathJoin(targetDir, fileNode.getName()));
}
copyFile(StableUtils.pathJoin(sourceDir, fileNode.getName()), StableUtils.pathJoin(targetDir, fileNode.getName()));
}
}
private void copyFile(String sourcePath, String targetPath) {
//检查源文件是不是还存在
if (!WorkContext.getWorkResource().exist(sourcePath)) {
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Source_File_Not_Exist"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
WARNING_MESSAGE);
} else {
try {
byte[] data = WorkContext.getWorkResource().readFully(sourcePath);
WorkContext.getWorkResource().write(targetPath, data);
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
throw e;
}
}
}
private String copyFile(FileNode sourceFile, String targetDir) {
String name = getNoRepeatedName4Paste(targetDir, sourceFile.getName());
String targetFile = StableUtils.pathJoin(targetDir, name);
if (sourceFile.isDirectory()) {
copyDir(sourceFile.getEnvPath(), targetFile);
} else {
copyFile(sourceFile.getEnvPath(), targetFile);
}
return targetFile;
}
/**
* 重名处理
*
* @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 = getFileTree().listFile(targetDir);
for (int i = 0; i < fileNodes.length; i++) {
if (ComparatorUtils.equals(name, fileNodes[i].getName())) {
return true;
}
}
return false;
}
}

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

@ -29,6 +29,11 @@ public interface FileOperations {
*/
void refresh();
/**
* 刷新父目录
*/
void refreshParent();
/**
* 删除文件
*/

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

@ -4,9 +4,12 @@ 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;
@ -24,6 +27,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 +40,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 +56,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;
@ -160,6 +168,161 @@ 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) {
JTemplate<?, ?> template = openedTemplate.get(this.tplIndex);
super.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 (currentTemplate == null) {
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() {

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

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

45
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,7 @@ 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.searcher.control.pane.TemplateSearchRemindPane;
import com.fr.file.FILE;
import com.fr.file.FileNodeFILE;
import com.fr.file.filetree.FileNode;
@ -74,19 +74,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 +113,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 +293,27 @@ 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();
}
if (reportletsTree.getSelectedFileNode().isDirectory()) {
reportletsTree.refreshDir(Objects.requireNonNull(reportletsTree.getSelectionPath()));
} else {
reportletsTree.refreshParent(Objects.requireNonNull(reportletsTree.getSelectionPath()));
}
DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(null);
FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_File_Tree_Refresh_Successfully") + "!");
}
/**
* 删除文件
* 文件夹和文件均可删除
@ -519,9 +542,13 @@ public class TemplateTreePane extends JPanel implements FileOperations {
return false;
}
DefaultMutableTreeNode currentTreeNode = (DefaultMutableTreeNode) treePath.getLastPathComponent();
TreeNode parentTreeNode = currentTreeNode.getParent();
Enumeration children = parentTreeNode.children();
Enumeration children;
if (reportletsTree.getSelectedFileNode().isDirectory()) {
children = currentTreeNode.children();
} else {
TreeNode parentTreeNode = currentTreeNode.getParent();
children = parentTreeNode.children();
}
while (children.hasMoreElements()) {
DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) children.nextElement();

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 = "";

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

@ -0,0 +1,54 @@
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.design.mainframe.manager.search.TemplateTreeSearchManager;
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 = TemplateTreeSearchManager.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);
}
}
}

113
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,22 @@ 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, List<String>> currentTreeMode = new ConcurrentHashMap<>();
public TemplateFileTree() {
super(ProjectConstants.REPORTLETS_NAME, null, null);
}
@ -213,7 +222,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 +260,106 @@ 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);
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();
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();
for (FileNode fileNode : treeNodes) {
ExpandMutableTreeNode treeNode = fileNodeArray2TreeNodeArray(new FileNode[]{fileNode})[0];
addToTreeModel(root, 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;
}
protected 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);
}

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

@ -3,11 +3,13 @@ package com.fr.design.mainframe;
import com.fr.base.BaseUtils;
import com.fr.base.extension.FileExtension;
import com.fr.base.vcs.DesignerMode;
import com.fr.chartx.TwoTuple;
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 +31,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;
@ -38,9 +42,6 @@ import com.fr.design.roleAuthority.RolesAlreadyEditedPane;
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 +82,15 @@ 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>>() {
};
private static final String FILE = "file";
public static final String FILE_NAME_LIMIT = "^[^/\\\\:<>\\*\\|\"\\?]+$";
private static volatile DesignerFrameFileDealerPane THIS;
static {
@ -144,6 +146,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 +167,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);
@ -285,6 +297,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 +435,36 @@ 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();
}
}
/**
* 版本管理
*/
@ -537,72 +580,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 +593,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,16 +725,20 @@ 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;
}
//新建文件夹
FileNode selectedFileNode = selectedOperation.getFileNode();
String parentPath = selectedFileNode.getParent();
if (selectedFileNode.isDirectory()) {
//目录的话,父目录就是所选目录
parentPath = FilenameUtils.standard(parentPath + CoreConstants.SEPARATOR + selectedFileNode.getName());
}
boolean success = selectedOperation.mkdir(
FilenameUtils.standard(selectedOperation.getFileNode().getParent() + CoreConstants.SEPARATOR + userInput)
FilenameUtils.standard(parentPath + CoreConstants.SEPARATOR + userInput)
);
selectedOperation.refresh();
this.dispose();
@ -999,13 +761,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 +775,17 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
}
}
private String doCheck (String userInput, String suffix) {
String errorMsg = StringUtils.EMPTY;
if (selectedOperation.duplicated(userInput, suffix)) {
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) {

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

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

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

@ -0,0 +1,190 @@
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.afterSearch();
}
if (rendererHelper != null) {
rendererHelper.restore(getCurrentTemplateDirTree());
}
}
/**
* 所有匹配的目录节点
* @return
*/
public FileNode[] matchesNode() {
return treeSearcher.getMatchSets().toArray(new FileNode[0]);
}
public Map<String, FileNode> allFileNodes() {
return treeSearcher.getAllTemplates();
}
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;
}
public boolean isInSearchMode() {
return getTreeSearchStatus() != TreeSearchStatus.NOT_IN_SEARCH_MODE;
}
}

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

@ -0,0 +1,222 @@
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 java.util.ArrayList;
import java.util.List;
import java.util.Map;
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);
treeSearcher.startSearch(searchText);
}
/**
* 中断搜索
*/
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.afterSearch();
}
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 Map<String, FileNode> allFileNodes() {
return treeSearcher.getAllTemplates();
}
public boolean isInSearchMode() {
return getTreeSearchStatus() != TreeSearchStatus.NOT_IN_SEARCH_MODE;
}
public void outOfSearchMode() {
restoreToolBarAndTreePane();
}
public boolean isRefreshing() {
return isRefreshing.get();
}
public void setRefreshing(boolean isRefreshing) {
this.isRefreshing.set(isRefreshing);
}
}

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

@ -0,0 +1,164 @@
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();
}
public synchronized void addToCalculatedSets(List<String> templateNames) {
for (String templateName : templateNames) {
FileNode fileNode = allDirs.get(templateName);
if (fileNode == null) {
return;
}
calculatedSets.add(templateName);
}
}
public synchronized void addToMatchSets(List<FileNode> matchNodes) {
matchSets.addAll(matchNodes);
}
public 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);
}
@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 afterSearch() {
allDirs.clear();
executorService.shutdownNow();
}
}

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

@ -0,0 +1,163 @@
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.*;
import java.util.concurrent.*;
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);
}
}
public synchronized void addToMatchSets(List<FileNode> matchNodes) {
matchSets.addAll(matchNodes);
}
public 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);
}
@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 afterSearch() {
allTemplates.clear();
executorService.shutdownNow();
}
}

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

@ -0,0 +1,49 @@
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;
}
if (treeSearchResult.isSuccess()) {
// 添加结果
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());
}
}

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

@ -0,0 +1,59 @@
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;
}
if (treeSearchResult.isSuccess()) {
// 添加结果
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());
}
}

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

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

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

@ -0,0 +1,75 @@
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).build();
}
/**
* 判断是否匹配搜索文本不区分大小写
*
* @param str
* @return
*/
private boolean isMatchSearch(String str, String searchText) {
return str.toUpperCase().contains(searchText.toUpperCase());
}
}

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

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

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

@ -0,0 +1,149 @@
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_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) {
}
}

212
designer-base/src/main/java/com/fr/design/mainframe/manager/search/searcher/control/pane/TemplateSearchRemindPane.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.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();
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);
}
}
}

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

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

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

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

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

@ -0,0 +1,26 @@
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) {
if (searchResult.isSuccess()) {
addToTreeSearcher(searchResult);
}
}
@Override
protected void addToTreeSearcher(TreeSearchResult searchResult) {
TemplateSearchResult templateSearchResult = (TemplateSearchResult) searchResult;
treeSearcher.addToNotCalculatedSets(templateSearchResult.getAddToNotCalculated());
}
}

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

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

19
designer-base/src/main/java/com/fr/design/search/TreeSearchManager.java

@ -0,0 +1,19 @@
package com.fr.design.search;
import com.fr.design.search.event.TreeSearchStatusChangeListener;
public interface TreeSearchManager {
/**
* 注册搜索状态监听器
*/
void registerTreeSearchStatusChangeListener(TreeSearchStatusChangeListener listener);
/**
* 是否搜出结果
* @return
*/
boolean isMatchSetsEmpty();
}

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

19
designer-base/src/main/java/com/fr/file/FILEChooserPane.java

@ -27,6 +27,7 @@ import com.fr.design.layout.FRGUIPaneFactory;
import com.fr.design.layout.TableLayout;
import com.fr.design.layout.TableLayoutHelper;
import com.fr.design.mainframe.DesignerFrame;
import com.fr.design.mainframe.DesignerFrameFileDealerPane;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.event.Event;
@ -104,6 +105,9 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static javax.swing.JOptionPane.DEFAULT_OPTION;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
/*
* FileChooserPane要高亮显示某Button,以显示当前路径
* 边距要调整
@ -887,7 +891,7 @@ public class FILEChooserPane extends BasicPane {
private void doOK() {
// 如果没有写文件名,不允许打开 or save
if (fileNameTextField.getText().length() == 0) {
if (fileNameTextField.getText().length() == 0 || !validInput()) {
return;
}
if (type == JFileChooser.OPEN_DIALOG) {
@ -918,6 +922,19 @@ public class FILEChooserPane extends BasicPane {
}
}
private boolean validInput() {
String name = fileNameTextField.getText().trim();
if (!Pattern.compile(DesignerFrameFileDealerPane.FILE_NAME_LIMIT).matcher(name).matches()) {
FineJOptionPane.showConfirmDialog(this,
Toolkit.i18nText("Fine-Design_Basic_Template_Name_Illegal"),
Toolkit.i18nText("Fine-Design_Basic_Error"),
DEFAULT_OPTION,
WARNING_MESSAGE);
return false;
}
return true;
}
private void saveDialog() {
String filename = fileNameTextField.getText();

BIN
designer-base/src/main/resources/com/fr/design/images/FileDealerPaneIcon/collapse-all.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

BIN
designer-base/src/main/resources/com/fr/design/images/FileDealerPaneIcon/locate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

BIN
designer-base/src/main/resources/com/fr/design/images/m_edit/move.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Loading…
Cancel
Save