Browse Source

Pull request #9852: REPORT-79128 触发两次粘贴,页面卡死,等不卡了在看目录层级,粘贴了好多层

Merge in DESIGN/design from ~ROGER.CHEN/design:release/11.0 to release/11.0

* commit '400df5f2663934bbd6cdb3d50673c8b548563aff':
  代码规范及右键增加定位模板功能
  添加注释
  REPORT-79128 触发两次粘贴,页面卡死,等不卡了在看目录层级,粘贴了好多层
newui
Roger.Chen 2 years ago
parent
commit
b7b6b956cc
  1. 4
      designer-base/src/main/java/com/fr/design/actions/file/LocateAction.java
  2. 18
      designer-base/src/main/java/com/fr/design/actions/file/RenameAction.java
  3. 242
      designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java
  4. 195
      designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java
  5. 3
      designer-base/src/main/java/com/fr/design/file/FileOperations.java
  6. 8
      designer-base/src/main/java/com/fr/design/file/TemplateResource.java
  7. 77
      designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java
  8. 11
      designer-base/src/main/java/com/fr/design/file/impl/AbstractTemplateResource.java
  9. 13
      designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateFileTree.java
  10. 8
      designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java
  11. 1
      designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateTreeSearchManager.java
  12. 35
      designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java

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

@ -8,6 +8,7 @@ import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode;
import com.fr.design.gui.itree.refreshabletree.RefreshableJTree;
import com.fr.design.i18n.Toolkit;
import com.fr.design.mainframe.JTemplate;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.file.filetree.FileNode;
import com.fr.general.ComparatorUtils;
import com.fr.stable.CoreConstants;
@ -49,6 +50,9 @@ public class LocateAction extends UpdateAction {
if (locatedPath == null) {
return;
}
if (TemplateTreeSearchManager.getInstance().isInSearchMode()) {
TemplateTreeSearchManager.getInstance().outOfSearchMode();
}
DefaultTreeModel model = (DefaultTreeModel) getTemplateFileTree().getModel();
ExpandMutableTreeNode treeNode = (ExpandMutableTreeNode) model.getRoot();

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

@ -17,6 +17,7 @@ import com.fr.design.layout.TableLayoutHelper;
import com.fr.design.mainframe.DesignerContext;
import com.fr.design.mainframe.DesignerFrameFileDealerPane;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.design.mainframe.vcs.common.VcsHelper;
import com.fr.design.utils.TemplateUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.event.EventDispatcher;
@ -25,6 +26,7 @@ import com.fr.file.filetree.FileNode;
import com.fr.general.ComparatorUtils;
import com.fr.stable.CoreConstants;
import com.fr.stable.StringUtils;
import com.fr.stable.project.ProjectConstants;
import com.fr.third.org.apache.commons.io.FilenameUtils;
import javax.swing.BorderFactory;
@ -123,6 +125,7 @@ public class RenameAction extends UpdateAction {
private FileRenameDialog(FileNode node) {
super(DesignerContext.getDesignerFrame(), true);
if (node == null) {
return;
}
@ -136,7 +139,6 @@ public class RenameAction extends UpdateAction {
private void initPane(String oldName) {
this.setLayout(new BorderLayout());
this.setModal(true);
// 输入框前提示
UILabel newNameLabel = new UILabel(Toolkit.i18nText(
@ -229,7 +231,6 @@ public class RenameAction extends UpdateAction {
this.setSize(340, 200);
this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Rename"));
this.setResizable(false);
this.setAlwaysOnTop(false);
this.setIconImage(BaseUtils.readImage("/com/fr/base/images/oem/logo.png"));
this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
GUICoreUtils.centerWindow(this);
@ -286,11 +287,14 @@ public class RenameAction extends UpdateAction {
HistoryTemplateListCache.getInstance().rename(fnf, path, newPath);
DesignerEnvManager.getEnvManager().replaceRecentOpenedFilePath(fnf.isDirectory(), path, newPath);
selectedOperation.refreshParent();
DesignerContext.getDesignerFrame().setTitle();
if (TemplateTreeSearchManager.getInstance().isInSearchMode()) {
TemplateTreeSearchManager.getInstance().outOfSearchMode();
LocateAction.gotoEditingTemplateLeaf(newPath);
if (!fnf.isDirectory()) {
//版本控制:未打开模板时重命名,是个纯文件操作
//不借助JTemplate的事件触发机制实现(需要新创建JTemplate,并添加监听,不确定会不会有问题)
path = path.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY);
VcsHelper.getInstance().moveVcs(path, newPath.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY));
}
DesignerContext.getDesignerFrame().setTitle();
LocateAction.gotoEditingTemplateLeaf(newPath);
}
@ -328,7 +332,7 @@ public class RenameAction extends UpdateAction {
private String doCheck (String userInput, String suffix, boolean isDirectory) {
String errorMsg = StringUtils.EMPTY;
if (selectedOperation.duplicated(userInput, suffix)) {
if (selectedOperation.duplicated(userInput, suffix, false)) {
errorMsg = Toolkit.i18nText(isDirectory ?
"Fine-Design_Basic_Folder_Name_Duplicate" :
"Fine-Design_Basic_Template_File_Name_Duplicate",

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

@ -18,18 +18,16 @@ import com.fr.design.mainframe.manager.clip.TemplateTreeClipboard;
import com.fr.design.mainframe.manager.search.TemplateDirTreeSearchManager;
import com.fr.design.mainframe.manager.search.TemplateTreeSearchManager;
import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateDirTreeSearchPane;
import com.fr.design.mainframe.toast.DesignerToastMsgUtil;
import com.fr.design.mainframe.toast.ToastMsgDialog;
import com.fr.design.utils.TemplateUtils;
import com.fr.design.utils.gui.GUICoreUtils;
import com.fr.file.FileNodeFILE;
import com.fr.file.filetree.FileNode;
import com.fr.general.ComparatorUtils;
import com.fr.log.FineLoggerFactory;
import com.fr.stable.ArrayUtils;
import com.fr.stable.StableUtils;
import com.fr.stable.StringUtils;
import com.fr.stable.collections.CollectionUtils;
import com.fr.stable.project.ProjectConstants;
import com.fr.workspace.WorkContext;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
@ -40,14 +38,13 @@ 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 java.util.stream.Collectors;
import static javax.swing.JOptionPane.INFORMATION_MESSAGE;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
import static javax.swing.JOptionPane.YES_NO_OPTION;
@ -62,6 +59,7 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
private PasteAction pasteAction;
private DelFileAction delFileAction;
private MoveAction moveAction;
private LocateAction locateAction;
public static DefaultTemplateTreeDefineProcessor getInstance() {
return DefaultTemplateTreeDefineProcessor.HOLDER.singleton;
@ -81,6 +79,7 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
pasteAction = new PasteAction();
delFileAction = new DelFileAction();
moveAction = new MoveAction();
locateAction = new OpenInTemplateTreeAction();
//右键菜单
popupMenu = new UIPopupMenu();
popupMenu.add(renameAction.createMenuItem());
@ -90,6 +89,7 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
popupMenu.add(delFileAction.createMenuItem());
popupMenu.addSeparator();
popupMenu.add(moveAction.createMenuItem());
popupMenu.add(locateAction.createMenuItem());
}
@Override
@ -106,6 +106,7 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
pasteAction.setEnabled(false);
delFileAction.setEnabled(false);
moveAction.setEnabled(false);
locateAction.setEnabled(false);
int length = getFileTree().getSelectionCount();
if (length == 0) {
//没有选中文件时,只能黏贴
@ -117,6 +118,10 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
if (length == 1) {
//选中一个时可以,可以重命名、黏贴
renameAction.setEnabled(true);
if (TemplateTreeSearchManager.getInstance().isInSearchMode()) {
//搜索模式开启定位当前模板
locateAction.setEnabled(true);
}
if (!CollectionUtils.isEmpty(TemplateTreeClipboard.getInstance().takeFromClip())) {
pasteAction.setEnabled(true);
}
@ -161,6 +166,22 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
}
}
private class OpenInTemplateTreeAction extends LocateAction {
public OpenInTemplateTreeAction() {
this.setName(Toolkit.i18nText("Fine-Design_Basic_Locate_Node"));
}
@Override
public void actionPerformed(ActionEvent e) {
FileNode fileNode = getFileTree().getSelectedFileNode();
if (fileNode == null) {
return;
}
gotoEditingTemplateLeaf(fileNode.getEnvPath());
}
}
/**
* 黏贴功能
*/
@ -184,7 +205,7 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
ArrayList<ExpandMutableTreeNode> pasteNodes = new ArrayList<>();
ArrayList<ExpandMutableTreeNode> lockedNodes = new ArrayList<>();
for (ExpandMutableTreeNode treeNode : treeNodeList) {
checkFreeOrLock(treeNode, pasteNodes, lockedNodes);
FileOperationHelper.getInstance().checkFreeOrLock(treeNode, pasteNodes, lockedNodes);
}
if (pasteNodes.isEmpty()) {
//提示:复制的文件都不能黏贴
@ -206,14 +227,6 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
doPaste(targetDir, pasteNodes);
}
}
// 移动时如果正在搜索,跳回原树
if (TemplateTreeSearchManager.getInstance().isInSearchMode()) {
TemplateTreeSearchManager.getInstance().outOfSearchMode();
}
DesignerFrameFileDealerPane.getInstance().getSelectedOperation().refreshParent();
String targetFile = StableUtils.pathJoin(targetDir, ((FileNode) (pasteNodes.get(0).getUserObject())).getName());
LocateAction.gotoEditingTemplateLeaf(targetFile);
}
/**
@ -246,18 +259,19 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
private void doPaste(String targetDir, List<ExpandMutableTreeNode> pasteNodes) {
String targetFile = targetDir;
try {
if (StringUtils.isEmpty(targetDir)) {
if (StringUtils.isEmpty(targetDir) || !confirmTargetDir(targetDir, pasteNodes)) {
return;
}
for (ExpandMutableTreeNode node : pasteNodes) {
if (node.getUserObject() instanceof FileNode) {
FileNode fileNode = (FileNode) node.getUserObject();
copyFile(fileNode, targetDir);
targetFile = FileOperationHelper.getInstance().copyFile(fileNode, targetDir);
FineLoggerFactory.getLogger().debug("Template: {} paste to {} success.", fileNode.getEnvPath(), targetDir);
}
}
} catch (HeadlessException e) {
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e,"Template paste failed.", e.getMessage());
FineJOptionPane.showConfirmDialog(null,
Toolkit.i18nText("Fine-Design_Basic_Paste_Failure"),
@ -265,6 +279,32 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
JOptionPane.DEFAULT_OPTION,
JOptionPane.ERROR_MESSAGE);
}
DesignerFrameFileDealerPane.getInstance().getSelectedOperation().refreshParent();
LocateAction.gotoEditingTemplateLeaf(targetFile);
}
/**
* 确认粘贴的目标目录是否是复制文件的子目录并确认是否继续执行粘贴任务
*
* @param targetDir 目标文件夹
* @param pasteNodes 待粘贴的文件
* @return 是否继续
*/
private boolean confirmTargetDir(String targetDir, List<ExpandMutableTreeNode> pasteNodes) {
List<ExpandMutableTreeNode> filterNodes = pasteNodes.stream().filter(
treeNode -> targetDir.startsWith(((FileNode) (treeNode.getUserObject())).getEnvPath())).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(filterNodes)) {
if (FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Confirm_Paste_Target_Dir"),
Toolkit.i18nText("Fine-Design_Basic_Alert"),
YES_NO_OPTION) != JOptionPane.YES_OPTION) {
return false;
}
//移除待粘贴文件中目标目录的父目录
pasteNodes.removeAll(filterNodes);
}
return true;
}
}
@ -290,15 +330,20 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
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;
ExpandMutableTreeNode[] selectedTreeNodes = getFileTree().getSelectedTreeNodes();
for (ExpandMutableTreeNode treeNode : selectedTreeNodes) {
if (treeNode.getUserObject() instanceof FileNode) {
FileNode node = (FileNode) treeNode.getUserObject();
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();
@ -314,8 +359,8 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
private String targetFile;
public TemplateMoveDialog() {
super(DesignerContext.getDesignerFrame(), true);
this.setLayout(new BorderLayout());
this.setModal(true);
searchPane = new TemplateDirTreeSearchPane();
add(searchPane, BorderLayout.NORTH);
@ -361,9 +406,8 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
this.setSize(new Dimension(600, 400));
this.setTitle(Toolkit.i18nText("Fine-Design_Basic_Move"));
this.setResizable(false);
this.setAlwaysOnTop(false);
this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
GUICoreUtils.setWindowCenter(DesignerContext.getDesignerFrame(), this);
GUICoreUtils.centerWindow(this);
this.setVisible(true);
}
@ -375,15 +419,9 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
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);
ToastMsgDialog dialog = DesignerToastMsgUtil.createPromptDialog(Toolkit.i18nText("Fine-Design_Basic_Template_Moved_Success"));
dialog.setVisible(true);
// 移动时如果正在搜索,跳回原树
if (TemplateTreeSearchManager.getInstance().isInSearchMode()) {
TemplateTreeSearchManager.getInstance().outOfSearchMode();
}
DesignerFrameFileDealerPane.getInstance().getSelectedOperation().refresh();
LocateAction.gotoEditingTemplateLeaf(targetFile);
}
@ -416,19 +454,7 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
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;
}
}
targetFile = FileOperationHelper.getInstance().moveFile(sourceFileNode, fileNode.getEnvPath());
}
} catch (Exception e) {
FineLoggerFactory.getLogger().error(e.getMessage(), e);
@ -448,45 +474,6 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
}
}
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;
}
/**
* 黏贴时确定黏贴的目录
*
@ -506,79 +493,4 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi
}
return targetDir;
}
private void copyDir(String sourceDir, String targetDir) {
FileNode[] fileNodes = getFileTree().listFile(sourceDir);
if (ArrayUtils.isEmpty(fileNodes)) {
//空目录:相当于新建一个目录
DesignerFrameFileDealerPane.getInstance().getSelectedOperation().mkdir(targetDir);
}
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", sourcePath),
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;
}
}

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

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

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

@ -87,7 +87,8 @@ public interface FileOperations {
*
* @param newName 原名
* @param suffix 后缀名
* @param baseOnSelf 检验目录时是基于自身目录的子节点还是基于父目录的子节点进行校验
* @return 是否存在
*/
boolean duplicated(String newName, String suffix);
boolean duplicated(String newName, String suffix, boolean baseOnSelf);
}

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

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

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

@ -308,11 +308,7 @@ public class TemplateTreePane extends JPanel implements FileOperations {
//没选中文件刷新根目录
reportletsTree.refresh();
}
if (reportletsTree.getSelectedFileNode().isDirectory()) {
reportletsTree.refreshDir(Objects.requireNonNull(reportletsTree.getSelectionPath()));
} else {
reportletsTree.refreshParent(Objects.requireNonNull(reportletsTree.getSelectionPath()));
}
reportletsTree.refreshParent(Objects.requireNonNull(reportletsTree.getSelectionPath()));
DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(null);
FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_File_Tree_Refresh_Successfully") + "!");
}
@ -334,7 +330,7 @@ public class TemplateTreePane extends JPanel implements FileOperations {
ArrayList<ExpandMutableTreeNode> deletableNodes = new ArrayList<>();
ArrayList<ExpandMutableTreeNode> lockedNodes = new ArrayList<>();
for (ExpandMutableTreeNode treeNode : treeNodes) {
checkFreeOrLock(treeNode, deletableNodes, lockedNodes);
FileOperationHelper.getInstance().checkFreeOrLock(treeNode, deletableNodes, lockedNodes);
}
if (lockedNodes.isEmpty()) {
@ -428,41 +424,6 @@ public class TemplateTreePane extends JPanel implements FileOperations {
return success;
}
private boolean checkFreeOrLock(ExpandMutableTreeNode node, ArrayList<ExpandMutableTreeNode> dNodes, ArrayList<ExpandMutableTreeNode> lNodes) {
// 自己没锁
boolean selfEmptyLock = false;
Object userObj = node.getUserObject();
if (userObj instanceof FileNode) {
String lock = ((FileNode) userObj).getLock();
selfEmptyLock = lock == null || ((FileNode) userObj).getUserID().equals(lock);
}
if (node.isLeaf()) {
if (selfEmptyLock) {
dNodes.add(node);
} else {
lNodes.add(node);
}
return selfEmptyLock;
}
ExpandMutableTreeNode[] children = reportletsTree.loadChildTreeNodes(node);
boolean childrenEmptyLock = true;
for (ExpandMutableTreeNode child : children) {
childrenEmptyLock = checkFreeOrLock(child, dNodes, lNodes) && childrenEmptyLock;
}
boolean emptyLock = childrenEmptyLock && selfEmptyLock;
if (emptyLock) {
dNodes.add(node);
} else {
lNodes.add(node);
}
return emptyLock;
}
@Override
public void lockFile() {
@ -506,7 +467,7 @@ public class TemplateTreePane extends JPanel implements FileOperations {
ArrayList<ExpandMutableTreeNode> unlockedNodes = new ArrayList<>();
ArrayList<ExpandMutableTreeNode> lockedNodes = new ArrayList<>();
for (ExpandMutableTreeNode treeNode : treeNodes) {
checkFreeOrLock(treeNode, unlockedNodes, lockedNodes);
FileOperationHelper.getInstance().checkFreeOrLock(treeNode, unlockedNodes, lockedNodes);
}
if (!lockedNodes.isEmpty()) {
@ -541,36 +502,42 @@ public class TemplateTreePane extends JPanel implements FileOperations {
*
* @param newName 原名
* @param suffix 后缀名
* @param baseOnSelf 检验目录时是基于自身目录的子节点还是基于父目录的子节点进行校验
* @return 是否有重名的
*/
@Override
public boolean duplicated(String newName, String suffix) {
public boolean duplicated(String newName, String suffix, boolean baseOnSelf) {
// 选中的节点
TreePath treePath = reportletsTree.getSelectionPath();
if (treePath == null) {
return false;
}
DefaultMutableTreeNode currentTreeNode = (DefaultMutableTreeNode) treePath.getLastPathComponent();
Enumeration children;
if (reportletsTree.getSelectedFileNode().isDirectory()) {
children = currentTreeNode.children();
} else {
TreeNode parentTreeNode = currentTreeNode.getParent();
children = parentTreeNode.children();
}
boolean result = false;
Enumeration children = getChild(treePath, baseOnSelf);
while (children.hasMoreElements()) {
DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) children.nextElement();
Object object = childNode.getUserObject();
if (object instanceof FileNode) {
if (ComparatorUtils.equals(((FileNode) object).getName(), newName + suffix)) {
return true;
result = true;
}
} else {
return false;
}
}
return false;
return result;
}
private Enumeration getChild(TreePath treePath, boolean baseOnSelf) {
DefaultMutableTreeNode currentTreeNode = (DefaultMutableTreeNode) treePath.getLastPathComponent();
Enumeration children;
//现在可以在目录下创建目录,重命名时是基于所选节点的父目录的子目录进行校验,目录下新建子目录时,基于所选目录的子目录进行校验
if (reportletsTree.getSelectedFileNode().isDirectory() && baseOnSelf) {
children = currentTreeNode.children();
} else {
TreeNode parentTreeNode = currentTreeNode.getParent();
children = parentTreeNode.children();
}
return children;
}
}

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

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

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

@ -33,6 +33,7 @@ import java.util.stream.Collectors;
public class TemplateFileTree extends EnvFileTree {
protected Map<String, ExpandMutableTreeNode> allTreeNode = new ConcurrentHashMap<>();
protected Map<String, ExpandMutableTreeNode> calculateNode = new ConcurrentHashMap<>();
protected Map<String, List<String>> currentTreeMode = new ConcurrentHashMap<>();
public TemplateFileTree() {
@ -303,6 +304,7 @@ public class TemplateFileTree extends EnvFileTree {
if (!TemplateTreeSearchManager.getInstance().isRefreshing()) {
currentTreeMode.clear();
calculateNode.clear();
allTreeNode = TemplateTreeSearchManager.getInstance().allFileNodes().entrySet().stream().collect(
Collectors.toMap(Map.Entry::getKey, entry -> fileNodeArray2TreeNodeArray(new FileNode[]{entry.getValue()})[0]));
TemplateTreeSearchManager.getInstance().setRefreshing(true);
@ -310,9 +312,14 @@ public class TemplateFileTree extends EnvFileTree {
}
FileNode[] treeNodes = TemplateTreeSearchManager.getInstance().matchesNode();
for (FileNode fileNode : treeNodes) {
ExpandMutableTreeNode treeNode = fileNodeArray2TreeNodeArray(new FileNode[]{fileNode})[0];
addToTreeModel(root, treeNode);
//排序一下,保证父子节点的情况下,子节点排在前面,先添加到树结构中
List<FileNode> treeNodeList = Arrays.stream(treeNodes).sorted((t1, t2) -> t2.getEnvPath().compareToIgnoreCase(t1.getEnvPath())).collect(Collectors.toList());
for (FileNode fileNode : treeNodeList) {
if (!calculateNode.containsKey(fileNode.getEnvPath())) {
ExpandMutableTreeNode treeNode = fileNodeArray2TreeNodeArray(new FileNode[]{fileNode})[0];
addToTreeModel(root, treeNode);
calculateNode.put(fileNode.getEnvPath(), treeNode);
}
}
}

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

@ -752,11 +752,11 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
//目录的话,父目录就是所选目录
parentPath = FilenameUtils.standard(parentPath + CoreConstants.SEPARATOR + selectedFileNode.getName());
}
boolean success = selectedOperation.mkdir(
FilenameUtils.standard(parentPath + CoreConstants.SEPARATOR + userInput)
);
String targetPath = FilenameUtils.standard(parentPath + CoreConstants.SEPARATOR + userInput);
boolean success = selectedOperation.mkdir(targetPath);
selectedOperation.refresh();
this.dispose();
LocateAction.gotoEditingTemplateLeaf(targetPath);
if (!success) {
FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(),
Toolkit.i18nText("Fine-Design_Basic_Make_Failure"),
@ -792,7 +792,7 @@ public class DesignerFrameFileDealerPane extends JPanel implements FileToolbarSt
private String doCheck (String userInput, String suffix) {
String errorMsg = StringUtils.EMPTY;
if (selectedOperation.duplicated(userInput, suffix)) {
if (selectedOperation.duplicated(userInput, suffix, true)) {
errorMsg = Toolkit.i18nText("Fine-Design_Basic_Folder_Name_Duplicate", userInput);
}
if (!Pattern.compile(FILE_NAME_LIMIT).matcher(userInput).matches()) {

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

@ -173,6 +173,7 @@ public class TemplateTreeSearchManager {
if (treeSearcher != null) {
treeSearcher.exitSearch();
}
setRefreshing(false);
lastSearchText = null;
if (rendererHelper != null) {
rendererHelper.restore(getCurrentTemplateTree());

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

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

Loading…
Cancel
Save