Browse Source
Merge in DESIGN/design from ~ROGER.CHEN/design:feature/x to feature/x * commit '671a89c9e6378d56555df0a9321d5c286bd5f673': 改掉import * 添加类、方法的相关注释 解决冲突 REPORT-75090 feat:设计器模板文件管理feature/x
Roger.Chen
2 years ago
53 changed files with 3953 additions and 391 deletions
@ -0,0 +1,50 @@
|
||||
package com.fr.design.actions.file; |
||||
|
||||
import com.fr.design.actions.UpdateAction; |
||||
import com.fr.design.dialog.FineJOptionPane; |
||||
import com.fr.design.file.FileOperations; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.mainframe.DesignerContext; |
||||
import com.fr.design.mainframe.DesignerFrameFileDealerPane; |
||||
import com.fr.design.utils.TemplateUtils; |
||||
|
||||
import javax.swing.JOptionPane; |
||||
import java.awt.event.ActionEvent; |
||||
|
||||
import static javax.swing.JOptionPane.WARNING_MESSAGE; |
||||
import static javax.swing.JOptionPane.YES_NO_OPTION; |
||||
|
||||
/* |
||||
* 删除指定文件 |
||||
*/ |
||||
public class DelFileAction extends UpdateAction { |
||||
|
||||
public DelFileAction() { |
||||
|
||||
this.setName(Toolkit.i18nText("Fine-Design_Basic_Remove")); |
||||
this.setSmallIcon("/com/fr/design/images/FileDealerPaneIcon/remove"); |
||||
} |
||||
|
||||
@Override |
||||
public void actionPerformed(ActionEvent evt) { |
||||
FileOperations selectedOperation = DesignerFrameFileDealerPane.getInstance().getSelectedOperation(); |
||||
if (!selectedOperation.access()) { |
||||
FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), |
||||
Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"), |
||||
Toolkit.i18nText("Fine-Design_Basic_Alert"), |
||||
WARNING_MESSAGE); |
||||
return; |
||||
} |
||||
if (TemplateUtils.checkSelectedTemplateIsEditing()) { |
||||
if (FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), |
||||
Toolkit.i18nText("Fine-Design_Basic_Template_Is_Editing"), |
||||
Toolkit.i18nText("Fine-Design_Basic_Alert"), |
||||
YES_NO_OPTION) != JOptionPane.YES_OPTION) { |
||||
return; |
||||
} |
||||
} |
||||
selectedOperation.deleteFile(); |
||||
DesignerFrameFileDealerPane.getInstance().stateChange(); |
||||
DesignerContext.getDesignerFrame().setTitle(); |
||||
} |
||||
} |
@ -0,0 +1,144 @@
|
||||
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()); |
||||
} |
||||
|
||||
/** |
||||
* 在左侧模板树定位到指定模板 |
||||
* |
||||
* @param locatedPath |
||||
*/ |
||||
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; |
||||
} |
||||
} |
@ -0,0 +1,337 @@
|
||||
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.TemplateUtils; |
||||
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.JOptionPane; |
||||
import javax.swing.SwingConstants; |
||||
import javax.swing.event.DocumentEvent; |
||||
import javax.swing.event.DocumentListener; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Color; |
||||
import java.awt.Component; |
||||
import java.awt.Dimension; |
||||
import java.awt.FlowLayout; |
||||
import java.awt.event.ActionEvent; |
||||
import java.awt.event.ActionListener; |
||||
import java.awt.event.KeyAdapter; |
||||
import java.awt.event.KeyEvent; |
||||
import java.awt.event.KeyListener; |
||||
import java.util.regex.Pattern; |
||||
|
||||
import static javax.swing.JOptionPane.DEFAULT_OPTION; |
||||
import static javax.swing.JOptionPane.ERROR_MESSAGE; |
||||
import static javax.swing.JOptionPane.WARNING_MESSAGE; |
||||
import static javax.swing.JOptionPane.YES_NO_OPTION; |
||||
|
||||
/** |
||||
* 模板/目录重命名操作 |
||||
*/ |
||||
public class RenameAction extends UpdateAction { |
||||
|
||||
private FileOperations selectedOperation; |
||||
public 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(); |
||||
} |
||||
|
||||
/** |
||||
* 重命名对话框 |
||||
* 支持快捷键Enter,ESC |
||||
*/ |
||||
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() { |
||||
|
||||
if (TemplateUtils.checkSelectedTemplateIsEditing()) { |
||||
if (FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), |
||||
Toolkit.i18nText("Fine-Design_Basic_Template_Is_Editing"), |
||||
Toolkit.i18nText("Fine-Design_Basic_Alert"), |
||||
YES_NO_OPTION) == JOptionPane.NO_OPTION) { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
String userInput = nameField.getText().trim(); |
||||
|
||||
String path = FilenameUtils.standard(fnf.getPath()); |
||||
|
||||
String oldName = fnf.getName(); |
||||
String suffix = fnf.isDirectory() ? StringUtils.EMPTY : oldName.substring(oldName.lastIndexOf(CoreConstants.DOT), oldName.length()); |
||||
oldName = StringUtils.replaceLast(oldName, suffix, StringUtils.EMPTY); |
||||
|
||||
// 输入为空或者没有修改
|
||||
if (ComparatorUtils.equals(userInput, oldName)) { |
||||
this.dispose(); |
||||
return; |
||||
} |
||||
|
||||
String parentPath = FilenameUtils.standard(fnf.getParent().getPath()); |
||||
|
||||
// 简单执行old new 替换是不可行的,例如 /abc/abc/abc/abc/
|
||||
String newPath = parentPath + CoreConstants.SEPARATOR + userInput + suffix; |
||||
this.dispose(); |
||||
|
||||
//模版重命名
|
||||
boolean success = selectedOperation.rename(fnf, path, newPath); |
||||
|
||||
if (success) { |
||||
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; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,578 @@
|
||||
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.TemplateUtils; |
||||
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; |
||||
} |
||||
//确定目标目录并检查权限
|
||||
if (getDirTree().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 false; |
||||
} |
||||
//检测之前复制的文件是否被打开
|
||||
if (TemplateUtils.checkTemplateIsEditing(treeNodeList.toArray(new ExpandMutableTreeNode[0]))) { |
||||
return FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), |
||||
Toolkit.i18nText("Fine-Design_Basic_Template_Is_Editing"), |
||||
Toolkit.i18nText("Fine-Design_Basic_Alert"), |
||||
YES_NO_OPTION) == JOptionPane.YES_OPTION; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
|
||||
private void doPaste(String targetDir, List<ExpandMutableTreeNode> pasteNodes) { |
||||
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 (!checkBeforeMove()) { |
||||
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 checkBeforeMove() { |
||||
if (getDirTree().getSelectionCount() != 0 && !TemplateDirTreePane.getInstance().selectedAccess()) { |
||||
FineJOptionPane.showMessageDialog(this, |
||||
Toolkit.i18nText("Fine-Design_Basic_Template_Permission_Denied"), |
||||
Toolkit.i18nText("Fine-Design_Basic_Alert"), |
||||
WARNING_MESSAGE); |
||||
return false; |
||||
} |
||||
if (TemplateUtils.checkSelectedTemplateIsEditing()) { |
||||
return FineJOptionPane.showConfirmDialog(this, |
||||
Toolkit.i18nText("Fine-Design_Basic_Template_Is_Editing"), |
||||
Toolkit.i18nText("Fine-Design_Basic_Alert"), |
||||
YES_NO_OPTION) == JOptionPane.YES_OPTION; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
private boolean doMove() { |
||||
FileNode fileNode = getDirTree().getSelectedFileNode(); |
||||
ExpandMutableTreeNode rootTreeNode = (ExpandMutableTreeNode) getDirTree().getModel().getRoot(); |
||||
fileNode = fileNode == null ? (FileNode) rootTreeNode.getUserObject() : fileNode; |
||||
boolean moveSuccess = true; |
||||
try { |
||||
//待移动的文件可以有多个
|
||||
ExpandMutableTreeNode[] sourceSelected = getFileTree().getSelectedTreeNodes(); |
||||
for (ExpandMutableTreeNode treeNode : sourceSelected) { |
||||
FileNode sourceFileNode = (FileNode) treeNode.getUserObject(); |
||||
targetFile = 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; |
||||
} |
||||
} |
@ -0,0 +1,82 @@
|
||||
package com.fr.design.file; |
||||
|
||||
import com.fr.base.FRContext; |
||||
import com.fr.design.gui.itree.filetree.TemplateDirTree; |
||||
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.mainframe.DesignerFrameFileDealerPane; |
||||
import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateDirSearchRemindPane; |
||||
import com.fr.file.filetree.IOFileNodeFilter; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.ArrayUtils; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.JPanel; |
||||
import javax.swing.tree.TreePath; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Color; |
||||
|
||||
/** |
||||
* 目录树面板 |
||||
*/ |
||||
public class TemplateDirTreePane extends JPanel { |
||||
|
||||
public static TemplateDirTreePane getInstance() { |
||||
return TemplateDirTreePane.HOLDER.singleton; |
||||
} |
||||
|
||||
private static class HOLDER { |
||||
private static TemplateDirTreePane singleton = new TemplateDirTreePane(); |
||||
} |
||||
|
||||
private TemplateDirTree templateDirTree; |
||||
private TemplateDirSearchRemindPane remindPane; |
||||
|
||||
public TemplateDirTreePane() { |
||||
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||
this.setBorder(BorderFactory.createLineBorder(Color.gray)); |
||||
templateDirTree = new TemplateDirTree(); |
||||
remindPane = new TemplateDirSearchRemindPane(getTemplateDirTree()); |
||||
|
||||
this.add(remindPane, BorderLayout.CENTER); |
||||
} |
||||
|
||||
public TemplateDirTree getTemplateDirTree() { |
||||
return this.templateDirTree; |
||||
} |
||||
|
||||
/** |
||||
* 判断所选的目录是否有权限 |
||||
* |
||||
* @return |
||||
*/ |
||||
public boolean selectedAccess() { |
||||
TreePath[] selectedTreePaths = templateDirTree.getSelectionPaths(); |
||||
|
||||
if (ArrayUtils.isEmpty(selectedTreePaths)) { |
||||
return false; |
||||
} |
||||
// 选中的是文件夹
|
||||
TreePath treePath = selectedTreePaths[0]; |
||||
ExpandMutableTreeNode currentTreeNode = (ExpandMutableTreeNode) treePath.getLastPathComponent(); |
||||
return currentTreeNode != null && currentTreeNode.hasFullAuthority(); |
||||
} |
||||
|
||||
public void refresh() { |
||||
// 刷新远程文件夹权限
|
||||
NodeAuthProcessor.getInstance().refresh(); |
||||
templateDirTree.refresh(); |
||||
DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(null); |
||||
FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_File_Tree_Refresh_Successfully") + "!"); |
||||
} |
||||
|
||||
/** |
||||
* 刷新 |
||||
*/ |
||||
public void refreshDockingView() { |
||||
templateDirTree.setFileNodeFilter(new IOFileNodeFilter(FRContext.getFileNodes().getSupportedTypes())); |
||||
templateDirTree.refreshEnv(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,53 @@
|
||||
package com.fr.design.gui.itree.filetree; |
||||
|
||||
import com.fr.base.FRContext; |
||||
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; |
||||
import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager; |
||||
import com.fr.file.filetree.FileNode; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.Map; |
||||
import java.util.stream.Collectors; |
||||
|
||||
/* |
||||
* 目录树 |
||||
*/ |
||||
public class TemplateDirTree extends TemplateFileTree { |
||||
|
||||
public TemplateDirTree() { |
||||
super(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 查找所有目录子节点 |
||||
* |
||||
* @param path |
||||
* @return |
||||
*/ |
||||
public FileNode[] listFile(String path) { |
||||
return Arrays.stream(FRContext.getFileNodes().list(path)).filter(FileNode::isDirectory).toArray(FileNode[]::new); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 搜索时刷新目录树 |
||||
* @param root |
||||
*/ |
||||
public void refreshTreeNode4TreeSearch(ExpandMutableTreeNode root) { |
||||
if (interceptRefresh(root)) { |
||||
return; |
||||
} |
||||
currentTreeMode.clear(); |
||||
allTreeNode = TemplateDirTreeSearchManager.getInstance().allFileNodes().entrySet().stream().collect( |
||||
Collectors.toMap(Map.Entry::getKey, entry -> fileNodeArray2TreeNodeArray(new FileNode[]{entry.getValue()})[0])); |
||||
root.removeAllChildren(); |
||||
|
||||
FileNode[] treeNodes = TemplateDirTreeSearchManager.getInstance().matchesNode(); |
||||
for (FileNode fileNode : treeNodes) { |
||||
ExpandMutableTreeNode treeNode = fileNodeArray2TreeNodeArray(new FileNode[]{fileNode})[0]; |
||||
addToTreeModel(root, treeNode); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,66 @@
|
||||
package com.fr.design.mainframe.manager.clip; |
||||
|
||||
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 模板复制黏贴 |
||||
*/ |
||||
public class TemplateTreeClipboard { |
||||
|
||||
private List<ExpandMutableTreeNode> clip = new ArrayList<>(); |
||||
|
||||
private static class Holder { |
||||
private static final TemplateTreeClipboard INSTANCE = new TemplateTreeClipboard(); |
||||
} |
||||
|
||||
private TemplateTreeClipboard() { |
||||
} |
||||
|
||||
public static TemplateTreeClipboard getInstance() { |
||||
return TemplateTreeClipboard.Holder.INSTANCE; |
||||
} |
||||
|
||||
public List<ExpandMutableTreeNode> transferNameObjectArray2Map(ExpandMutableTreeNode[] selectedTreeNodes) { |
||||
List<ExpandMutableTreeNode> resultMap = new ArrayList<>(); |
||||
if (selectedTreeNodes == null) { |
||||
return resultMap; |
||||
} |
||||
for (ExpandMutableTreeNode selectTreeNode : selectedTreeNodes) { |
||||
ExpandMutableTreeNode cloned = (ExpandMutableTreeNode) selectTreeNode.clone(); |
||||
if (cloned != null) { |
||||
resultMap.add(cloned); |
||||
} |
||||
} |
||||
return resultMap; |
||||
} |
||||
|
||||
/** |
||||
* 添加选中的模板数据到剪切板,覆盖原本剪切板内数据 |
||||
* |
||||
* @param copyList |
||||
* @return |
||||
*/ |
||||
public void addToClip(List<ExpandMutableTreeNode> copyList) { |
||||
this.clip = copyList; |
||||
} |
||||
|
||||
/** |
||||
* 取出剪切板内的所有模板数据,剪切板不清空 |
||||
* |
||||
* @return |
||||
*/ |
||||
public List<ExpandMutableTreeNode> takeFromClip() { |
||||
return clip; |
||||
} |
||||
|
||||
/** |
||||
* 清空剪切板 |
||||
*/ |
||||
public void reset() { |
||||
clip.clear(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,205 @@
|
||||
package com.fr.design.mainframe.manager.search; |
||||
|
||||
import com.fr.design.file.TemplateDirTreePane; |
||||
import com.fr.design.gui.itree.filetree.TemplateDirTree; |
||||
import com.fr.design.mainframe.manager.search.searcher.TemplateDirTreeSearcher; |
||||
import com.fr.design.mainframe.manager.search.searcher.TemplateTreeSearcher; |
||||
import com.fr.design.search.TreeSearchStatus; |
||||
import com.fr.design.search.event.TreeSearchStatusChangeEvent; |
||||
import com.fr.design.search.event.TreeSearchStatusChangeListener; |
||||
import com.fr.design.search.view.TreeSearchRendererHelper; |
||||
import com.fr.file.filetree.FileNode; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import javax.swing.SwingUtilities; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
public class TemplateDirTreeSearchManager { |
||||
|
||||
/** |
||||
* 文件树搜索器 |
||||
*/ |
||||
private TemplateTreeSearcher treeSearcher; |
||||
|
||||
/** |
||||
* 搜索任务的状态 |
||||
*/ |
||||
private TreeSearchStatus treeSearchStatus; |
||||
|
||||
/** |
||||
* 缓存上次搜索文本,避免重复搜索 |
||||
*/ |
||||
private String lastSearchText; |
||||
|
||||
/** |
||||
* 存储与复原 原本模板的UI |
||||
*/ |
||||
private TreeSearchRendererHelper rendererHelper; |
||||
|
||||
/** |
||||
* 搜索状态变化监听 |
||||
*/ |
||||
private List<TreeSearchStatusChangeListener> listeners = new ArrayList<>(); |
||||
|
||||
private TemplateDirTreeSearchManager() { |
||||
init(); |
||||
} |
||||
|
||||
private void init() { |
||||
this.treeSearchStatus = TreeSearchStatus.NOT_IN_SEARCH_MODE; |
||||
} |
||||
|
||||
private static class Holder { |
||||
private static final TemplateDirTreeSearchManager INSTANCE = new TemplateDirTreeSearchManager(); |
||||
} |
||||
|
||||
public static TemplateDirTreeSearchManager getInstance() { |
||||
return TemplateDirTreeSearchManager.Holder.INSTANCE; |
||||
} |
||||
|
||||
public TreeSearchStatus getTreeSearchStatus() { |
||||
return treeSearchStatus; |
||||
} |
||||
|
||||
public void setTreeSearchStatus(TreeSearchStatus treeSearchStatus) { |
||||
this.treeSearchStatus = treeSearchStatus; |
||||
// 每次设置搜索状态,都触发下监听,让页面跟随变化
|
||||
SwingUtilities.invokeLater(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
for (TreeSearchStatusChangeListener listener : listeners) { |
||||
listener.updateTreeSearchChange(new TreeSearchStatusChangeEvent(treeSearchStatus)); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
public void registerTreeSearchStatusChangeListener(TreeSearchStatusChangeListener listener) { |
||||
listeners.add(listener); |
||||
} |
||||
|
||||
/** |
||||
* 获取当前的目录树 |
||||
* |
||||
* @return |
||||
*/ |
||||
private TemplateDirTree getCurrentTemplateDirTree() { |
||||
return TemplateDirTreePane.getInstance().getTemplateDirTree(); |
||||
} |
||||
|
||||
public void beforeSearch(TemplateDirTree templateDirTree) { |
||||
setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN); |
||||
rendererHelper = new TreeSearchRendererHelper(); |
||||
rendererHelper.save(templateDirTree.getFileTreeCellRenderer()); |
||||
treeSearcher = new TemplateDirTreeSearcher(); |
||||
FineLoggerFactory.getLogger().debug("switch to template dir search"); |
||||
treeSearcher.beforeSearch(templateDirTree); |
||||
} |
||||
|
||||
/** |
||||
* 开始搜索 |
||||
* |
||||
* @param searchText |
||||
*/ |
||||
public void startSearch(String searchText) { |
||||
if (isRepeatSearch(searchText) || StringUtils.isEmpty(searchText)) { |
||||
return; |
||||
} |
||||
setTreeSearchStatus(TreeSearchStatus.SEARCHING); |
||||
rendererHelper.replaceTreeRenderer(getCurrentTemplateDirTree(), searchText); |
||||
FineLoggerFactory.getLogger().debug("start template dir search for search text: {}", searchText); |
||||
treeSearcher.startSearch(searchText); |
||||
} |
||||
|
||||
/** |
||||
* 中断搜索 |
||||
*/ |
||||
public void stopSearch() { |
||||
setTreeSearchStatus(TreeSearchStatus.SEARCH_STOPPED); |
||||
FineLoggerFactory.getLogger().debug("stop template dir search for search text: {}", lastSearchText); |
||||
treeSearcher.stopSearch(); |
||||
} |
||||
|
||||
/** |
||||
* 搜索完成 |
||||
*/ |
||||
public void completeSearch() { |
||||
setTreeSearchStatus(TreeSearchStatus.SEARCH_COMPLETED); |
||||
FineLoggerFactory.getLogger().debug("complete template dir search for search text: {}", lastSearchText); |
||||
treeSearcher.completeSearch(); |
||||
} |
||||
|
||||
/** |
||||
* 退出搜索模式 |
||||
*/ |
||||
public void outOfSearchMode() { |
||||
setTreeSearchStatus(TreeSearchStatus.NOT_IN_SEARCH_MODE); |
||||
FineLoggerFactory.getLogger().info("out of template search"); |
||||
lastSearchText = null; |
||||
if (treeSearcher != null) { |
||||
treeSearcher.exitSearch(); |
||||
} |
||||
if (rendererHelper != null) { |
||||
rendererHelper.restore(getCurrentTemplateDirTree()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 所有匹配的目录节点 |
||||
* @return |
||||
*/ |
||||
public FileNode[] matchesNode() { |
||||
return treeSearcher.getMatchSets().toArray(new FileNode[0]); |
||||
} |
||||
|
||||
/** |
||||
* 当前目录树中搜索的目录节点 |
||||
* @return |
||||
*/ |
||||
public Map<String, FileNode> allFileNodes() { |
||||
return treeSearcher.getAllTemplates(); |
||||
} |
||||
|
||||
/** |
||||
* 搜索结果是否为空 |
||||
* @return |
||||
*/ |
||||
public boolean isMatchSetsEmpty() { |
||||
return treeSearcher.isMatchSetsEmpty(); |
||||
} |
||||
|
||||
/** |
||||
* 恢复到模板树面板 |
||||
*/ |
||||
public void restoreTreePane() { |
||||
setTreeSearchStatus(TreeSearchStatus.SEARCH_NOT_BEGIN); |
||||
lastSearchText = null; |
||||
if (rendererHelper != null) { |
||||
rendererHelper.restore(getCurrentTemplateDirTree()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 刷新树,更新搜索的结果 |
||||
*/ |
||||
public void updateTemplateTree() { |
||||
getCurrentTemplateDirTree().refresh4TreeSearch(); |
||||
} |
||||
|
||||
private boolean isRepeatSearch(String searchText) { |
||||
boolean repeat = StringUtils.equals(lastSearchText, searchText); |
||||
lastSearchText = searchText; |
||||
return repeat; |
||||
} |
||||
|
||||
/** |
||||
* 当前是否处于搜索模式 |
||||
* @return |
||||
*/ |
||||
public boolean isInSearchMode() { |
||||
return getTreeSearchStatus() != TreeSearchStatus.NOT_IN_SEARCH_MODE; |
||||
} |
||||
} |
@ -0,0 +1,237 @@
|
||||
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.exitSearch(); |
||||
} |
||||
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]); |
||||
} |
||||
|
||||
/** |
||||
* 当前模板树中的所有模板节点 |
||||
* @return |
||||
*/ |
||||
public Map<String, FileNode> allFileNodes() { |
||||
return treeSearcher.getAllTemplates(); |
||||
} |
||||
|
||||
/** |
||||
* 是否处于搜索模式 |
||||
* @return |
||||
*/ |
||||
public boolean isInSearchMode() { |
||||
return getTreeSearchStatus() != TreeSearchStatus.NOT_IN_SEARCH_MODE; |
||||
} |
||||
|
||||
/** |
||||
* 退出搜索模式 |
||||
*/ |
||||
public void outOfSearchMode() { |
||||
restoreToolBarAndTreePane(); |
||||
} |
||||
|
||||
/** |
||||
* 搜索结果数是否处于更新状态 |
||||
* @return |
||||
*/ |
||||
public boolean isRefreshing() { |
||||
return isRefreshing.get(); |
||||
} |
||||
|
||||
public void setRefreshing(boolean isRefreshing) { |
||||
this.isRefreshing.set(isRefreshing); |
||||
} |
||||
} |
@ -0,0 +1,195 @@
|
||||
package com.fr.design.mainframe.manager.search.searcher; |
||||
|
||||
import com.fr.concurrent.NamedThreadFactory; |
||||
import com.fr.design.gui.itree.filetree.TemplateFileTree; |
||||
import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager; |
||||
import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateDirSearchCallBack; |
||||
import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchTask; |
||||
import com.fr.design.mainframe.manager.search.searcher.control.pre.TemplateDirPreSearchTask; |
||||
import com.fr.design.mainframe.manager.search.searcher.control.pre.TemplatePreSearchCallBack; |
||||
import com.fr.design.search.TreeSearchStatus; |
||||
import com.fr.file.filetree.FileNode; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.project.ProjectConstants; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.HashSet; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.concurrent.ExecutorService; |
||||
import java.util.concurrent.Executors; |
||||
import java.util.concurrent.atomic.AtomicInteger; |
||||
import java.util.stream.Collectors; |
||||
|
||||
/** |
||||
* 目录搜索器 |
||||
*/ |
||||
public class TemplateDirTreeSearcher extends TemplateTreeSearcher { |
||||
|
||||
private ExecutorService executorService; |
||||
|
||||
private final Map<String, FileNode> allDirs = new ConcurrentHashMap<>(); |
||||
|
||||
private final AtomicInteger outLayerDirCount = new AtomicInteger(0); |
||||
|
||||
private final Set<String> notCalculatedSets = new HashSet<>(); |
||||
|
||||
private final Set<String> calculatedSets = new HashSet<>(); |
||||
|
||||
private final Set<FileNode> matchSets = new HashSet<>(); |
||||
|
||||
private final Object lock = new Object(); |
||||
|
||||
public Set<FileNode> getMatchSets() { |
||||
return this.matchSets; |
||||
} |
||||
|
||||
public boolean isMatchSetsEmpty() { |
||||
return matchSets.isEmpty(); |
||||
} |
||||
|
||||
public int getAllDirSize() { |
||||
return allDirs.size(); |
||||
} |
||||
|
||||
public Map<String, FileNode> getAllTemplates() { |
||||
return allDirs; |
||||
} |
||||
|
||||
public int getCalculatedCount() { |
||||
return this.calculatedSets.size(); |
||||
} |
||||
|
||||
/** |
||||
* 将模板添加到已经计算过的集合中,不管模板是不是匹配 |
||||
* |
||||
* @param templateNames |
||||
*/ |
||||
public synchronized void addToCalculatedSets(List<String> templateNames) { |
||||
for (String templateName : templateNames) { |
||||
FileNode fileNode = allDirs.get(templateName); |
||||
if (fileNode == null) { |
||||
return; |
||||
} |
||||
calculatedSets.add(templateName); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 将搜索匹配的目录添加到匹配的集合中 |
||||
* |
||||
* @param matchNodes |
||||
*/ |
||||
public synchronized void addToMatchSets(List<FileNode> matchNodes) { |
||||
matchSets.addAll(matchNodes); |
||||
} |
||||
|
||||
/** |
||||
* 将目录添加到未计算的集合中 |
||||
* |
||||
* @param fileNodes |
||||
*/ |
||||
public synchronized void addToNotCalculatedSets(List<FileNode> fileNodes) { |
||||
synchronized (lock) { |
||||
Map<String, FileNode> chileMap = fileNodes.stream().collect(Collectors.toMap(FileNode::getEnvPath, treeNode -> treeNode)); |
||||
notCalculatedSets.addAll(chileMap.keySet()); |
||||
allDirs.putAll(chileMap); |
||||
outLayerDirCount.decrementAndGet(); |
||||
lock.notify(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 正式搜索前,预加载一下每个最外层目录里面的所有子节点 |
||||
* |
||||
*/ |
||||
public void beforeSearch(TemplateFileTree templateFileTree) { |
||||
executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new NamedThreadFactory(TemplateDirTreeSearcher.class)); |
||||
collectOutLayerTemplate(templateFileTree); |
||||
preCalculateChild(); |
||||
} |
||||
|
||||
protected void preCalculateChild() { |
||||
for (String notCalculatedNode : notCalculatedSets) { |
||||
FileNode fileNode = allDirs.get(notCalculatedNode); |
||||
//计算最外层目录下的所有子节点
|
||||
if (TemplateDirTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCH_NOT_BEGIN && fileNode.isDirectory()) { |
||||
executorService.execute(new TemplateDirPreSearchTask(new TemplatePreSearchCallBack(this), fileNode)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 收集下此次搜索需要进行取数最外层的FileNode |
||||
* |
||||
* @param templateFileTree |
||||
*/ |
||||
private void collectOutLayerTemplate(TemplateFileTree templateFileTree) { |
||||
FileNode[] fileNodes = templateFileTree.listFile(ProjectConstants.REPORTLETS_NAME); |
||||
Map<String, FileNode> fileNodeMap = Arrays.stream(fileNodes).collect(Collectors.toMap(FileNode::getEnvPath, treeNode -> treeNode)); |
||||
outLayerDirCount.addAndGet(fileNodes.length); |
||||
notCalculatedSets.addAll(fileNodeMap.keySet()); |
||||
allDirs.putAll(fileNodeMap); |
||||
} |
||||
|
||||
/** |
||||
* 开始搜索 |
||||
* |
||||
* @param searchText |
||||
*/ |
||||
@Override |
||||
public void startSearch(String searchText) { |
||||
reset(); |
||||
do { |
||||
synchronized (lock) { |
||||
if (notCalculatedSets.isEmpty()) { |
||||
try { |
||||
lock.wait(100); |
||||
} catch (InterruptedException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
} |
||||
for (String notCalculated : notCalculatedSets) { |
||||
FileNode fileNode = allDirs.get(notCalculated); |
||||
if (TemplateDirTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCHING) { |
||||
executorService.execute(new TemplateSearchTask(searchText, fileNode, new TemplateDirSearchCallBack(this))); |
||||
} |
||||
} |
||||
FineLoggerFactory.getLogger().info("[Template Search] At this stage calculate size: {}.", notCalculatedSets.size()); |
||||
notCalculatedSets.clear(); |
||||
} |
||||
} while (outLayerDirCount.get() != 0); |
||||
} |
||||
|
||||
/** |
||||
* 停止搜索 |
||||
*/ |
||||
@Override |
||||
public void stopSearch() { |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 完成搜索 |
||||
*/ |
||||
@Override |
||||
public void completeSearch() { |
||||
|
||||
} |
||||
|
||||
private void reset() { |
||||
matchSets.clear(); |
||||
calculatedSets.clear(); |
||||
notCalculatedSets.addAll(allDirs.keySet()); |
||||
} |
||||
|
||||
/** |
||||
* 退出搜索时的处理 |
||||
*/ |
||||
public void exitSearch() { |
||||
allDirs.clear(); |
||||
executorService.shutdownNow(); |
||||
} |
||||
} |
@ -0,0 +1,193 @@
|
||||
package com.fr.design.mainframe.manager.search.searcher; |
||||
|
||||
import com.fr.concurrent.NamedThreadFactory; |
||||
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; |
||||
import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchCallBack; |
||||
import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchTask; |
||||
import com.fr.design.mainframe.manager.search.searcher.control.pre.TemplatePreSearchCallBack; |
||||
import com.fr.design.mainframe.manager.search.searcher.control.pre.TemplatePreSearchTask; |
||||
import com.fr.design.search.TreeSearchStatus; |
||||
import com.fr.design.search.TreeSearcher; |
||||
import com.fr.design.gui.itree.filetree.TemplateFileTree; |
||||
import com.fr.file.filetree.FileNode; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.project.ProjectConstants; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.HashSet; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.concurrent.Executors; |
||||
import java.util.concurrent.ExecutorService; |
||||
import java.util.concurrent.atomic.AtomicInteger; |
||||
import java.util.stream.Collectors; |
||||
|
||||
public class TemplateTreeSearcher implements TreeSearcher { |
||||
|
||||
private ExecutorService executorService; |
||||
|
||||
private final Map<String, FileNode> allTemplates = new ConcurrentHashMap<>(); |
||||
|
||||
private final Object lock = new Object(); |
||||
|
||||
private final AtomicInteger outLayerDirCount = new AtomicInteger(0); |
||||
|
||||
private final Set<String> calculatedSets = new HashSet<>(); |
||||
|
||||
private final Set<String> notCalculatedSets = new HashSet<>(); |
||||
|
||||
private final Set<FileNode> matchSets = new HashSet<>(); |
||||
|
||||
public boolean isMatchSetsEmpty() { |
||||
return matchSets.isEmpty(); |
||||
} |
||||
|
||||
public int getAllTemplateSize() { |
||||
return allTemplates.size(); |
||||
} |
||||
|
||||
public Map<String, FileNode> getAllTemplates() { |
||||
return allTemplates; |
||||
} |
||||
|
||||
public Set<FileNode> getMatchSets() { |
||||
return this.matchSets; |
||||
} |
||||
|
||||
public int getCalculatedCount() { |
||||
return this.calculatedSets.size(); |
||||
} |
||||
|
||||
public int getOutLayerCount() { |
||||
return this.outLayerDirCount.get(); |
||||
} |
||||
|
||||
public synchronized void addToCalculatedSets(List<String> templateNames) { |
||||
for (String templateName : templateNames) { |
||||
FileNode fileNode = allTemplates.get(templateName); |
||||
if (fileNode == null) { |
||||
return; |
||||
} |
||||
calculatedSets.add(templateName); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 将搜索匹配的模板添加到匹配的集合中 |
||||
* |
||||
* @param matchNodes |
||||
*/ |
||||
public synchronized void addToMatchSets(List<FileNode> matchNodes) { |
||||
matchSets.addAll(matchNodes); |
||||
} |
||||
|
||||
/** |
||||
* 将模板添加到未计算的集合中 |
||||
* |
||||
* @param fileNodes |
||||
*/ |
||||
public synchronized void addToNotCalculatedSets(List<FileNode> fileNodes) { |
||||
synchronized (lock) { |
||||
Map<String, FileNode> chileMap = fileNodes.stream().collect(Collectors.toMap(FileNode::getEnvPath, treeNode -> treeNode)); |
||||
notCalculatedSets.addAll(chileMap.keySet()); |
||||
allTemplates.putAll(chileMap); |
||||
outLayerDirCount.decrementAndGet(); |
||||
lock.notify(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 正式搜索前,预加载一下每个最外层目录里面的所有子节点 |
||||
* |
||||
*/ |
||||
public void beforeSearch(TemplateFileTree templateFileTree) { |
||||
executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new NamedThreadFactory(TemplateTreeSearcher.class)); |
||||
collectOutLayerTemplate(templateFileTree); |
||||
preCalculateChild(); |
||||
} |
||||
|
||||
protected void preCalculateChild() { |
||||
for (String notCalculatedNode : notCalculatedSets) { |
||||
FileNode fileNode = allTemplates.get(notCalculatedNode); |
||||
//计算最外层目录下的所有子节点
|
||||
if (TemplateTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCH_NOT_BEGIN && fileNode.isDirectory()) { |
||||
executorService.execute(new TemplatePreSearchTask(new TemplatePreSearchCallBack(this), fileNode)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 收集下此次搜索需要进行取数最外层的FileNode |
||||
* |
||||
* @param templateFileTree |
||||
*/ |
||||
private void collectOutLayerTemplate(TemplateFileTree templateFileTree) { |
||||
FileNode[] fileNodes = templateFileTree.listFile(ProjectConstants.REPORTLETS_NAME); |
||||
Map<String, FileNode> fileNodeMap = Arrays.stream(fileNodes).collect(Collectors.toMap(FileNode::getEnvPath, treeNode -> treeNode)); |
||||
long dirCount = Arrays.stream(fileNodes).filter(FileNode::isDirectory).count(); |
||||
outLayerDirCount.addAndGet((int) dirCount); |
||||
notCalculatedSets.addAll(fileNodeMap.keySet()); |
||||
allTemplates.putAll(fileNodeMap); |
||||
} |
||||
|
||||
/** |
||||
* 开始搜索 |
||||
* |
||||
* @param searchText |
||||
*/ |
||||
@Override |
||||
public void startSearch(String searchText) { |
||||
reset(); |
||||
do { |
||||
synchronized (lock) { |
||||
if (notCalculatedSets.isEmpty()) { |
||||
try { |
||||
lock.wait(100); |
||||
} catch (InterruptedException e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
} |
||||
for (String notCalculated : notCalculatedSets) { |
||||
FileNode fileNode = allTemplates.get(notCalculated); |
||||
if (TemplateTreeSearchManager.getInstance().getTreeSearchStatus() == TreeSearchStatus.SEARCHING) { |
||||
executorService.execute(new TemplateSearchTask(searchText, fileNode, new TemplateSearchCallBack(this))); |
||||
} |
||||
} |
||||
FineLoggerFactory.getLogger().info("[Template Search] At this stage calculate size: {}.", notCalculatedSets.size()); |
||||
notCalculatedSets.clear(); |
||||
} |
||||
} while (outLayerDirCount.get() != 0); |
||||
} |
||||
|
||||
/** |
||||
* 停止搜索 |
||||
*/ |
||||
@Override |
||||
public void stopSearch() { |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 完成搜索 |
||||
*/ |
||||
@Override |
||||
public void completeSearch() { |
||||
|
||||
} |
||||
|
||||
private void reset() { |
||||
matchSets.clear(); |
||||
calculatedSets.clear(); |
||||
notCalculatedSets.addAll(allTemplates.keySet()); |
||||
} |
||||
|
||||
/** |
||||
* 退出搜索模式 |
||||
*/ |
||||
public void exitSearch() { |
||||
allTemplates.clear(); |
||||
executorService.shutdownNow(); |
||||
} |
||||
} |
@ -0,0 +1,55 @@
|
||||
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()); |
||||
} |
||||
} |
@ -0,0 +1,65 @@
|
||||
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()); |
||||
} |
||||
} |
@ -0,0 +1,130 @@
|
||||
package com.fr.design.mainframe.manager.search.searcher.control.common; |
||||
|
||||
import com.fr.design.search.control.TreeSearchResult; |
||||
import com.fr.file.filetree.FileNode; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 模板搜索结果 |
||||
*/ |
||||
public class TemplateSearchResult implements TreeSearchResult { |
||||
|
||||
private boolean success; |
||||
|
||||
private List<String> addToExpand; |
||||
|
||||
private List<String> addToCalculated; |
||||
|
||||
private List<FileNode> addToNotCalculated; |
||||
|
||||
private List<FileNode> addToMatchNode; |
||||
|
||||
protected TemplateSearchResult(TemplateSearchResult.Builder builder) { |
||||
this.success = builder.success; |
||||
this.addToMatchNode = builder.addToMatchNode; |
||||
this.addToExpand = builder.addToExpand; |
||||
this.addToCalculated = builder.addToCalculated; |
||||
this.addToNotCalculated = builder.addToNotCalculated; |
||||
} |
||||
|
||||
public void setSuccess(boolean success) { |
||||
this.success = success; |
||||
} |
||||
|
||||
public void setAddToMatchNode(List<FileNode> addToMatchNode) { |
||||
this.addToMatchNode = addToMatchNode; |
||||
} |
||||
|
||||
public void setAddToExpand(List<String> addToExpand) { |
||||
this.addToExpand = addToExpand; |
||||
} |
||||
|
||||
public void setAddToCalculated(List<String> addToCalculated) { |
||||
this.addToCalculated = addToCalculated; |
||||
} |
||||
|
||||
public void setAddToNotCalculated(List<FileNode> addToNotCalculated) { |
||||
this.addToNotCalculated = addToNotCalculated; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isSuccess() { |
||||
return this.success; |
||||
} |
||||
|
||||
@Override |
||||
public List<String> getAddToMatch() { |
||||
return new ArrayList<>(); |
||||
} |
||||
|
||||
public List<FileNode> getAddToMatchNode() { |
||||
return addToMatchNode; |
||||
} |
||||
|
||||
@Override |
||||
public List<String> getAddToExpand() { |
||||
return this.addToExpand; |
||||
} |
||||
|
||||
@Override |
||||
public List<String> getAddToCalculated() { |
||||
return this.addToCalculated; |
||||
} |
||||
|
||||
public List<FileNode> getAddToNotCalculated() { |
||||
return this.addToNotCalculated; |
||||
} |
||||
|
||||
public static class Builder { |
||||
|
||||
private boolean success; |
||||
|
||||
private List<FileNode> addToMatchNode; |
||||
|
||||
private List<String> addToExpand; |
||||
|
||||
private List<String> addToCalculated; |
||||
|
||||
private List<FileNode> addToNotCalculated; |
||||
|
||||
|
||||
public Builder() { |
||||
this.success = false; |
||||
this.addToMatchNode = new ArrayList<>(); |
||||
this.addToExpand = new ArrayList<>(); |
||||
this.addToCalculated = new ArrayList<>(); |
||||
this.addToNotCalculated = new ArrayList<>(); |
||||
} |
||||
|
||||
public TemplateSearchResult.Builder buildSuccess(boolean success) { |
||||
this.success = success; |
||||
return this; |
||||
} |
||||
|
||||
public TemplateSearchResult.Builder buildAddToMatch(List<FileNode> addToMatch) { |
||||
this.addToMatchNode = addToMatch; |
||||
return this; |
||||
} |
||||
|
||||
public TemplateSearchResult.Builder buildAddToExpand(List<String> addToExpand) { |
||||
this.addToExpand = addToExpand; |
||||
return this; |
||||
} |
||||
|
||||
public TemplateSearchResult.Builder buildAddToCalculated(List<String> addToCalculated) { |
||||
this.addToCalculated = addToCalculated; |
||||
return this; |
||||
} |
||||
|
||||
public TemplateSearchResult.Builder buildAddToNotCalculated(List<FileNode> addToNotCalculated) { |
||||
this.addToNotCalculated = addToNotCalculated; |
||||
return this; |
||||
} |
||||
|
||||
public TemplateSearchResult build() { |
||||
return new TemplateSearchResult(this); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,78 @@
|
||||
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()); |
||||
} |
||||
} |
@ -0,0 +1,214 @@
|
||||
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); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,152 @@
|
||||
package com.fr.design.mainframe.manager.search.searcher.control.pane; |
||||
|
||||
import com.fr.base.svg.IconUtils; |
||||
import com.fr.design.constants.UIConstants; |
||||
import com.fr.design.file.TemplateDirTreePane; |
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.gui.itextfield.UITextField; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager; |
||||
import com.fr.design.search.event.TreeSearchStatusChangeEvent; |
||||
import com.fr.design.search.event.TreeSearchStatusChangeListener; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.JPanel; |
||||
import javax.swing.event.DocumentEvent; |
||||
import javax.swing.event.DocumentListener; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.Color; |
||||
import java.awt.Insets; |
||||
import java.awt.event.FocusEvent; |
||||
import java.awt.event.FocusListener; |
||||
import java.awt.event.KeyAdapter; |
||||
import java.awt.event.KeyEvent; |
||||
import java.awt.event.MouseAdapter; |
||||
import java.awt.event.MouseEvent; |
||||
|
||||
/** |
||||
* 目录树搜索面板 |
||||
*/ |
||||
public class TemplateDirTreeSearchPane extends JPanel implements TreeSearchStatusChangeListener { |
||||
|
||||
/** |
||||
* 搜索输入框 |
||||
*/ |
||||
private UITextField searchTextField; |
||||
|
||||
/** |
||||
* 搜索面板 |
||||
*/ |
||||
private JPanel searchPane; |
||||
|
||||
private final KeyAdapter enterPressed = new KeyAdapter() { |
||||
@Override |
||||
public void keyPressed(KeyEvent e) { |
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) { |
||||
TemplateDirTreeSearchManager.getInstance().startSearch(searchTextField.getText()); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
public TemplateDirTreeSearchPane() { |
||||
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||
this.setBorder(BorderFactory.createEmptyBorder(10, 15, 0, 10)); |
||||
initSearchPane(); |
||||
add(searchPane, BorderLayout.CENTER); |
||||
TemplateDirTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this); |
||||
TemplateDirTreePane.getInstance().refreshDockingView(); |
||||
TemplateDirTreeSearchManager.getInstance().beforeSearch(TemplateDirTreePane.getInstance().getTemplateDirTree()); |
||||
} |
||||
|
||||
private void initSearchPane() { |
||||
searchPane = new JPanel(FRGUIPaneFactory.createBorderLayout()); |
||||
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); |
||||
searchPane.setBackground(Color.WHITE); |
||||
// 左侧搜索图标
|
||||
UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search")); |
||||
searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 0)); |
||||
searchLabel.addMouseListener(new MouseAdapter() { |
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
// do nothing
|
||||
} |
||||
}); |
||||
|
||||
// 中间输入框
|
||||
initSearchTextField(); |
||||
|
||||
// 右侧返回图标
|
||||
UILabel returnLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/clear")); |
||||
returnLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Tree_Search_Return")); |
||||
returnLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 11)); |
||||
returnLabel.addMouseListener(new MouseAdapter() { |
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
TemplateDirTreeSearchManager.getInstance().outOfSearchMode(); |
||||
TemplateDirTreePane.getInstance().refreshDockingView(); |
||||
} |
||||
}); |
||||
|
||||
searchPane.add(searchLabel, BorderLayout.WEST); |
||||
searchPane.add(searchTextField, BorderLayout.CENTER); |
||||
searchPane.add(returnLabel, BorderLayout.EAST); |
||||
} |
||||
|
||||
private void initSearchTextField() { |
||||
searchTextField = new UITextField(){ |
||||
@Override |
||||
public Insets getInsets() { |
||||
return new Insets(2, 4, 0, 4); |
||||
} |
||||
}; |
||||
searchTextField.setBorderPainted(false); |
||||
searchTextField.setPlaceholder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Template_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) { |
||||
|
||||
} |
||||
} |
@ -0,0 +1,228 @@
|
||||
package com.fr.design.mainframe.manager.search.searcher.control.pane; |
||||
|
||||
import com.fr.base.svg.IconUtils; |
||||
import com.fr.design.constants.UIConstants; |
||||
import com.fr.design.gui.itree.filetree.EnvFileTree; |
||||
import com.fr.design.search.event.TreeSearchStatusChangeEvent; |
||||
import com.fr.design.search.event.TreeSearchStatusChangeListener; |
||||
import com.fr.design.search.TreeSearchStatus; |
||||
import com.fr.design.gui.icontainer.UIScrollPane; |
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.JPanel; |
||||
import javax.swing.SwingConstants; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.CardLayout; |
||||
import java.awt.Color; |
||||
import java.awt.Dimension; |
||||
import java.awt.event.MouseAdapter; |
||||
import java.awt.event.MouseEvent; |
||||
import java.awt.event.MouseListener; |
||||
import java.awt.FlowLayout; |
||||
|
||||
/** |
||||
* 模板搜索提示面板:整合了模板树和提示面板 |
||||
*/ |
||||
public class TemplateSearchRemindPane extends JPanel implements TreeSearchStatusChangeListener { |
||||
|
||||
private TemplateSearchRemindPane.RemindPane remindPane; |
||||
private TemplateSearchRemindPane.TreePane treePane; |
||||
|
||||
public TemplateSearchRemindPane(EnvFileTree templateFileTree) { |
||||
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||
remindPane = new TemplateSearchRemindPane.RemindPane(); |
||||
treePane = new TemplateSearchRemindPane.TreePane(templateFileTree); |
||||
// 初始状态
|
||||
this.add(remindPane, BorderLayout.NORTH); |
||||
this.add(treePane, BorderLayout.CENTER); |
||||
TemplateTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this); |
||||
} |
||||
|
||||
/** |
||||
* 根据搜索状态变化,来调整自身面板的显示 |
||||
* |
||||
* @param event |
||||
*/ |
||||
@Override |
||||
public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) { |
||||
TreeSearchStatus status = event.getTreeSearchStatus(); |
||||
if (status == TreeSearchStatus.SEARCH_NOT_BEGIN || status == TreeSearchStatus.NOT_IN_SEARCH_MODE) { |
||||
remindPane.onNotBegin(); |
||||
treePane.onNotBegin(); |
||||
} else if (status == TreeSearchStatus.SEARCHING) { |
||||
remindPane.onInSearching(); |
||||
treePane.onInSearching(); |
||||
} else if (status == TreeSearchStatus.SEARCH_STOPPED) { |
||||
remindPane.onStoppedSearching(); |
||||
treePane.onStoppedSearching(); |
||||
} else { |
||||
boolean matchSetsEmpty = TemplateTreeSearchManager.getInstance().isMatchSetsEmpty(); |
||||
// 代表是否搜索出结果
|
||||
remindPane.onDoneSearching(matchSetsEmpty); |
||||
treePane.onDoneSearching(matchSetsEmpty); |
||||
} |
||||
this.revalidate(); |
||||
} |
||||
|
||||
private interface TreeSearchStatusChange { |
||||
|
||||
/** |
||||
* 搜索未开始时 |
||||
*/ |
||||
void onNotBegin(); |
||||
|
||||
/** |
||||
* 搜索中 |
||||
*/ |
||||
void onInSearching(); |
||||
|
||||
/** |
||||
* 停止搜索 |
||||
*/ |
||||
void onStoppedSearching(); |
||||
|
||||
/** |
||||
* 搜索结束 |
||||
* @param matchSetsEmpty |
||||
*/ |
||||
void onDoneSearching(boolean matchSetsEmpty); |
||||
} |
||||
|
||||
private class TreePane extends JPanel implements TemplateSearchRemindPane.TreeSearchStatusChange { |
||||
|
||||
private UIScrollPane scrollPane; |
||||
|
||||
private JPanel notFoundPane; |
||||
|
||||
private CardLayout cardLayout; |
||||
|
||||
private static final String SCROLL_PANE = "scrollPane"; |
||||
|
||||
private static final String NOT_FOUND_PANE = "notFoundPane"; |
||||
|
||||
public TreePane(EnvFileTree templateFileTree) { |
||||
init(templateFileTree); |
||||
} |
||||
|
||||
private void init(EnvFileTree templateFileTree) { |
||||
|
||||
scrollPane = new UIScrollPane(templateFileTree); |
||||
scrollPane.setBorder(null); |
||||
|
||||
notFoundPane = FRGUIPaneFactory.createVerticalFlowLayout_Pane(true, FlowLayout.LEADING, 0, 5); |
||||
UILabel emptyPicLabel = new UILabel(); |
||||
emptyPicLabel.setIcon(IconUtils.readIcon("com/fr/base/images/share/no_match_icon.png")); |
||||
emptyPicLabel.setHorizontalAlignment(SwingConstants.CENTER); |
||||
emptyPicLabel.setPreferredSize(new Dimension(240, 100)); |
||||
UILabel textLabel = new UILabel(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Not_Match"), SwingConstants.CENTER); |
||||
textLabel.setForeground(Color.gray); |
||||
textLabel.setHorizontalAlignment(SwingConstants.CENTER); |
||||
textLabel.setPreferredSize(new Dimension(240, 20)); |
||||
notFoundPane.add(emptyPicLabel); |
||||
notFoundPane.add(textLabel); |
||||
notFoundPane.setBorder(BorderFactory.createEmptyBorder(80, 0, 0, 0)); |
||||
|
||||
cardLayout = new CardLayout(); |
||||
this.setLayout(cardLayout); |
||||
this.add(scrollPane, SCROLL_PANE); |
||||
this.add(notFoundPane, NOT_FOUND_PANE); |
||||
cardLayout.show(this, SCROLL_PANE); |
||||
} |
||||
|
||||
@Override |
||||
public void onNotBegin() { |
||||
switchPane(SCROLL_PANE); |
||||
} |
||||
|
||||
@Override |
||||
public void onInSearching() { |
||||
switchPane(SCROLL_PANE); |
||||
} |
||||
|
||||
@Override |
||||
public void onStoppedSearching() { |
||||
switchPane(SCROLL_PANE); |
||||
} |
||||
|
||||
@Override |
||||
public void onDoneSearching(boolean matchSetsEmpty) { |
||||
if (matchSetsEmpty) { |
||||
switchPane(NOT_FOUND_PANE); |
||||
} |
||||
} |
||||
|
||||
private void switchPane(String paneName) { |
||||
cardLayout.show(this, paneName); |
||||
} |
||||
} |
||||
|
||||
private static class RemindPane extends JPanel implements TemplateSearchRemindPane.TreeSearchStatusChange { |
||||
|
||||
private static final String IN_SEARCHING = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_In_Searching"); |
||||
private static final String STOP_SEARCHING = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Stop_Search"); |
||||
private static final String SEARCHING_STOPPED = com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Tree_Search_Search_Stopped"); |
||||
private static final String DONE_SEARCHING = Toolkit.i18nText("Fine-Design_Tree_Search_Search_Completed"); |
||||
|
||||
private UILabel textLabel; |
||||
|
||||
private UILabel stopLabel; |
||||
|
||||
private MouseListener stopSearch; |
||||
|
||||
public RemindPane() { |
||||
init(); |
||||
} |
||||
|
||||
private void init() { |
||||
this.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0)); |
||||
// 初始情况下为Not_Begin
|
||||
textLabel = new UILabel(); |
||||
textLabel.setForeground(Color.gray); |
||||
stopLabel = new UILabel(); |
||||
stopLabel.setForeground(UIConstants.NORMAL_BLUE); |
||||
stopSearch = new MouseAdapter() { |
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
TemplateTreeSearchManager.getInstance().stopSearch(); |
||||
} |
||||
}; |
||||
stopLabel.addMouseListener(stopSearch); |
||||
this.add(textLabel); |
||||
this.add(stopLabel); |
||||
onNotBegin(); |
||||
} |
||||
|
||||
@Override |
||||
public void onNotBegin() { |
||||
this.setVisible(false); |
||||
} |
||||
|
||||
@Override |
||||
public void onInSearching() { |
||||
this.textLabel.setVisible(false); |
||||
this.stopLabel.setText(STOP_SEARCHING); |
||||
this.stopLabel.setVisible(true); |
||||
this.setVisible(true); |
||||
} |
||||
|
||||
@Override |
||||
public void onStoppedSearching() { |
||||
this.textLabel.setText(SEARCHING_STOPPED); |
||||
this.textLabel.setVisible(true); |
||||
this.stopLabel.setVisible(false); |
||||
this.setVisible(true); |
||||
} |
||||
|
||||
@Override |
||||
public void onDoneSearching(boolean matchSetsEmpty) { |
||||
this.textLabel.setText(DONE_SEARCHING); |
||||
this.textLabel.setVisible(true); |
||||
this.stopLabel.setVisible(false); |
||||
this.setVisible(true); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,212 @@
|
||||
package com.fr.design.mainframe.manager.search.searcher.control.pane; |
||||
|
||||
import com.fr.base.svg.IconUtils; |
||||
import com.fr.design.constants.UIConstants; |
||||
import com.fr.design.search.event.TreeSearchStatusChangeEvent; |
||||
import com.fr.design.search.event.TreeSearchStatusChangeListener; |
||||
import com.fr.design.search.TreeSearchStatus; |
||||
import com.fr.design.file.TemplateTreePane; |
||||
import com.fr.design.gui.ilable.UILabel; |
||||
import com.fr.design.gui.itextfield.UITextField; |
||||
import com.fr.design.gui.itoolbar.UIToolbar; |
||||
import com.fr.design.i18n.Toolkit; |
||||
import com.fr.design.layout.FRGUIPaneFactory; |
||||
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
import javax.swing.BorderFactory; |
||||
import javax.swing.JPanel; |
||||
import javax.swing.event.DocumentEvent; |
||||
import javax.swing.event.DocumentListener; |
||||
import java.awt.BorderLayout; |
||||
import java.awt.CardLayout; |
||||
import java.awt.Color; |
||||
import java.awt.Dimension; |
||||
import java.awt.Insets; |
||||
import java.awt.event.FocusEvent; |
||||
import java.awt.event.FocusListener; |
||||
import java.awt.event.KeyAdapter; |
||||
import java.awt.event.KeyEvent; |
||||
import java.awt.event.MouseAdapter; |
||||
import java.awt.event.MouseEvent; |
||||
|
||||
/** |
||||
* 模板搜索工具栏 |
||||
*/ |
||||
public class TemplateTreeSearchToolbarPane extends JPanel implements TreeSearchStatusChangeListener { |
||||
|
||||
public static final String TOOLBAR_PANE = "toolbarPane"; |
||||
|
||||
public static final String SEARCH_PANE = "searchPane"; |
||||
|
||||
/** |
||||
* 工具栏 |
||||
*/ |
||||
private UIToolbar toolbar; |
||||
|
||||
/** |
||||
* 工具栏面板 |
||||
*/ |
||||
private JPanel toolbarPane; |
||||
|
||||
/** |
||||
* 搜索面板 |
||||
*/ |
||||
private JPanel searchPane; |
||||
|
||||
/** |
||||
* 搜索输入框 |
||||
*/ |
||||
private UITextField searchTextField; |
||||
|
||||
/** |
||||
* 内容面板 |
||||
*/ |
||||
private JPanel contentPane; |
||||
|
||||
/** |
||||
* 卡片布局管理器 |
||||
*/ |
||||
private CardLayout cardLayout; |
||||
|
||||
private final KeyAdapter enterPressed = new KeyAdapter() { |
||||
@Override |
||||
public void keyPressed(KeyEvent e) { |
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) { |
||||
TemplateTreeSearchManager.getInstance().startSearch(searchTextField.getText()); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
public TemplateTreeSearchToolbarPane(UIToolbar toolbar) { |
||||
this.toolbar = toolbar; |
||||
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||
initToolbarPane(); |
||||
initSearchPane(); |
||||
initContentPane(); |
||||
add(contentPane, BorderLayout.CENTER); |
||||
setPreferredSize(new Dimension(240, 30)); |
||||
TemplateTreeSearchManager.getInstance().registerTreeSearchStatusChangeListener(this); |
||||
} |
||||
|
||||
private void initContentPane() { |
||||
cardLayout = new CardLayout(); |
||||
contentPane = new JPanel(cardLayout); |
||||
contentPane.add(searchPane, SEARCH_PANE); |
||||
contentPane.add(toolbarPane, TOOLBAR_PANE); |
||||
cardLayout.show(contentPane, TOOLBAR_PANE); |
||||
} |
||||
|
||||
private void initSearchPane() { |
||||
searchPane = new JPanel(FRGUIPaneFactory.createBorderLayout()); |
||||
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); |
||||
searchPane.setBackground(Color.WHITE); |
||||
// 左侧搜索图标
|
||||
UILabel searchLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/search")); |
||||
searchLabel.setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 0)); |
||||
searchLabel.addMouseListener(new MouseAdapter() { |
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
// do nothing
|
||||
} |
||||
}); |
||||
// 中间输入框
|
||||
initSearchTextField(); |
||||
// 右侧返回图标
|
||||
UILabel returnLabel = new UILabel(IconUtils.readIcon("/com/fr/design/images/data/clear")); |
||||
returnLabel.setToolTipText(Toolkit.i18nText("Fine-Design_Tree_Search_Return")); |
||||
returnLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 11)); |
||||
returnLabel.addMouseListener(new MouseAdapter() { |
||||
@Override |
||||
public void mouseClicked(MouseEvent e) { |
||||
TemplateTreeSearchManager.getInstance().outOfSearchMode(); |
||||
TemplateTreePane.getInstance().refreshDockingView(); |
||||
} |
||||
}); |
||||
|
||||
searchPane.add(searchLabel, BorderLayout.WEST); |
||||
searchPane.add(searchTextField, BorderLayout.CENTER); |
||||
searchPane.add(returnLabel, BorderLayout.EAST); |
||||
} |
||||
|
||||
private void initSearchTextField() { |
||||
searchTextField = new UITextField(){ |
||||
@Override |
||||
public Insets getInsets() { |
||||
return new Insets(2, 4, 0, 4); |
||||
} |
||||
}; |
||||
searchTextField.setBorderPainted(false); |
||||
searchTextField.setPlaceholder(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Template_Search_Press_Enter_For_Search")); |
||||
searchTextField.addFocusListener(new FocusListener() { |
||||
@Override |
||||
public void focusGained(FocusEvent e) { |
||||
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.NORMAL_BLUE)); |
||||
searchPane.repaint(); |
||||
} |
||||
|
||||
@Override |
||||
public void focusLost(FocusEvent e) { |
||||
searchPane.setBorder(BorderFactory.createLineBorder(UIConstants.TOOLBAR_BORDER_COLOR)); |
||||
searchPane.repaint(); |
||||
} |
||||
}); |
||||
this.searchTextField.getDocument().addDocumentListener(new DocumentListener() { |
||||
@Override |
||||
public void insertUpdate(DocumentEvent e) { |
||||
} |
||||
|
||||
@Override |
||||
public void removeUpdate(DocumentEvent e) { |
||||
dealWithTextChange(); |
||||
} |
||||
|
||||
@Override |
||||
public void changedUpdate(DocumentEvent e) { |
||||
} |
||||
}); |
||||
this.searchTextField.addKeyListener(enterPressed); |
||||
} |
||||
|
||||
private void dealWithTextChange() { |
||||
if (StringUtils.isEmpty(searchTextField.getText()) && TemplateTreeSearchManager.getInstance().isInSearchMode()) { |
||||
// 如果是搜索模式下,看作是用户删除输入框文字,仅复原TemplateTreePane
|
||||
TemplateTreeSearchManager.getInstance().restoreTreePane(); |
||||
TemplateTreePane.getInstance().refreshDockingView(); |
||||
} |
||||
} |
||||
|
||||
private void initToolbarPane() { |
||||
toolbarPane = new JPanel(); |
||||
toolbarPane.setLayout(FRGUIPaneFactory.createBorderLayout()); |
||||
toolbarPane.add(toolbar, BorderLayout.CENTER); |
||||
} |
||||
|
||||
/** |
||||
* 交换当前面板层级 |
||||
*/ |
||||
public void switchPane(String name) { |
||||
cardLayout.show(contentPane, name); |
||||
} |
||||
|
||||
public void setPlaceHolder(String placeHolder) { |
||||
this.searchTextField.setPlaceholder(placeHolder); |
||||
} |
||||
|
||||
/** |
||||
* 根据搜索状态变化,来调整自身面板的显示 |
||||
* |
||||
* @param event |
||||
*/ |
||||
@Override |
||||
public void updateTreeSearchChange(TreeSearchStatusChangeEvent event) { |
||||
TreeSearchStatus treeSearchStatus = event.getTreeSearchStatus(); |
||||
if (treeSearchStatus == TreeSearchStatus.NOT_IN_SEARCH_MODE) { |
||||
this.searchTextField.setText(StringUtils.EMPTY); |
||||
switchPane(TOOLBAR_PANE); |
||||
} else { |
||||
switchPane(SEARCH_PANE); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,35 @@
|
||||
package com.fr.design.mainframe.manager.search.searcher.control.pre; |
||||
|
||||
import com.fr.design.file.TemplateDirTreePane; |
||||
import com.fr.design.search.control.TreeSearchCallback; |
||||
import com.fr.file.filetree.FileNode; |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 目录树搜索时的前置处理,跟模板搜索前置处理类似 |
||||
*/ |
||||
public class TemplateDirPreSearchTask extends TemplatePreSearchTask { |
||||
|
||||
public TemplateDirPreSearchTask(TreeSearchCallback callback, FileNode fileNode) { |
||||
super(callback, fileNode); |
||||
} |
||||
|
||||
/** |
||||
* 加载最外层目录下所有的子节点 |
||||
* |
||||
* @param fileNodes |
||||
* @param fileNode |
||||
*/ |
||||
protected void dealWithChildTemplate(List<FileNode> fileNodes, FileNode fileNode) { |
||||
FileNode[] childNodes = TemplateDirTreePane.getInstance().getTemplateDirTree().listFile(fileNode.getEnvPath()); |
||||
for (FileNode childNode : childNodes) { |
||||
if (childNode.isDirectory()) { |
||||
fileNodes.add(childNode); |
||||
dealWithChildTemplate(fileNodes, childNode); |
||||
} else { |
||||
fileNodes.add(childNode); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,35 @@
|
||||
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); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 将结果添加到未计算的集合中 |
||||
* |
||||
* @param searchResult |
||||
*/ |
||||
@Override |
||||
protected void addToTreeSearcher(TreeSearchResult searchResult) { |
||||
TemplateSearchResult templateSearchResult = (TemplateSearchResult) searchResult; |
||||
treeSearcher.addToNotCalculatedSets(templateSearchResult.getAddToNotCalculated()); |
||||
} |
||||
} |
@ -0,0 +1,62 @@
|
||||
package com.fr.design.mainframe.manager.search.searcher.control.pre; |
||||
|
||||
import com.fr.design.mainframe.manager.search.searcher.control.common.TemplateSearchResult; |
||||
import com.fr.design.search.control.TreeSearchCallback; |
||||
import com.fr.design.search.control.TreeSearchResult; |
||||
import com.fr.design.search.control.TreeSearchTask; |
||||
import com.fr.design.file.TemplateTreePane; |
||||
import com.fr.file.filetree.FileNode; |
||||
import com.fr.log.FineLoggerFactory; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 模板搜索前置任务 |
||||
* 主要是计算最外层目录下面所有的子节点,并记录到结果集中 |
||||
*/ |
||||
public class TemplatePreSearchTask implements TreeSearchTask { |
||||
|
||||
protected TreeSearchCallback callback; |
||||
|
||||
//最外层的目录节点
|
||||
protected FileNode fileNode; |
||||
|
||||
public TemplatePreSearchTask(TreeSearchCallback callback, FileNode fileNode) { |
||||
this.callback = callback; |
||||
this.fileNode = fileNode; |
||||
} |
||||
|
||||
@Override |
||||
public void run() { |
||||
TreeSearchResult result; |
||||
try { |
||||
List<FileNode> allChildNode = new ArrayList<>(); |
||||
dealWithChildTemplate(allChildNode, fileNode); |
||||
result = new TemplateSearchResult.Builder().buildAddToNotCalculated(allChildNode).buildSuccess(true).build(); |
||||
FineLoggerFactory.getLogger().info("[Template Search] calculate {} child nodes success. total child node num is: {}", fileNode.getEnvPath(), allChildNode.size()); |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error("[Template Search] calculate {} child nodes failed", fileNode.getEnvPath()); |
||||
result = new TemplateSearchResult.Builder().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); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.data.datapane.management.search.searcher; |
||||
package com.fr.design.search; |
||||
|
||||
/** |
||||
* @author Yvan |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.data.datapane.management.search.searcher; |
||||
package com.fr.design.search; |
||||
|
||||
|
||||
/** |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.data.datapane.management.search.control; |
||||
package com.fr.design.search.control; |
||||
|
||||
|
||||
/** |
@ -1,4 +1,4 @@
|
||||
package com.fr.design.data.datapane.management.search.control; |
||||
package com.fr.design.search.control; |
||||
|
||||
/** |
||||
* @author Yvan |
@ -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; |
||||
|
@ -1,4 +1,4 @@
|
||||
package com.fr.design.data.datapane.management.search.event; |
||||
package com.fr.design.search.event; |
||||
|
||||
import java.util.EventListener; |
||||
|
After Width: | Height: | Size: 177 B |
After Width: | Height: | Size: 335 B |
After Width: | Height: | Size: 328 B |
Loading…
Reference in new issue