From 905c76f551112dfa61181813b020a8d69e37d6eb Mon Sep 17 00:00:00 2001 From: roger Date: Mon, 29 Aug 2022 10:39:08 +0800 Subject: [PATCH] =?UTF-8?q?REPORT-79128=20=E8=A7=A6=E5=8F=91=E4=B8=A4?= =?UTF-8?q?=E6=AC=A1=E7=B2=98=E8=B4=B4=EF=BC=8C=E9=A1=B5=E9=9D=A2=E5=8D=A1?= =?UTF-8?q?=E6=AD=BB=EF=BC=8C=E7=AD=89=E4=B8=8D=E5=8D=A1=E4=BA=86=E5=9C=A8?= =?UTF-8?q?=E7=9C=8B=E7=9B=AE=E5=BD=95=E5=B1=82=E7=BA=A7=EF=BC=8C=E7=B2=98?= =?UTF-8?q?=E8=B4=B4=E4=BA=86=E5=A5=BD=E5=A4=9A=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fr/design/actions/file/RenameAction.java | 13 +- .../DefaultTemplateTreeDefineProcessor.java | 218 +++++------------- .../fr/design/file/FileOperationHelper.java | 193 ++++++++++++++++ .../com/fr/design/file/FileOperations.java | 3 +- .../com/fr/design/file/TemplateResource.java | 8 +- .../com/fr/design/file/TemplateTreePane.java | 51 +--- .../file/impl/AbstractTemplateResource.java | 11 +- .../gui/itree/filetree/TemplateFileTree.java | 13 +- .../DesignerFrameFileDealerPane.java | 8 +- .../search/TemplateTreeSearchManager.java | 1 + .../mainframe/vcs/common/VcsHelper.java | 30 ++- 11 files changed, 325 insertions(+), 224 deletions(-) create mode 100644 designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java diff --git a/designer-base/src/main/java/com/fr/design/actions/file/RenameAction.java b/designer-base/src/main/java/com/fr/design/actions/file/RenameAction.java index efa6d12164..4255bd4851 100644 --- a/designer-base/src/main/java/com/fr/design/actions/file/RenameAction.java +++ b/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,6 +287,12 @@ public class RenameAction extends UpdateAction { HistoryTemplateListCache.getInstance().rename(fnf, path, newPath); DesignerEnvManager.getEnvManager().replaceRecentOpenedFilePath(fnf.isDirectory(), path, newPath); selectedOperation.refreshParent(); + if (!fnf.isDirectory()) { + //版本控制:未打开模板时重命名,是个纯文件操作 + //不借助JTemplate的事件触发机制实现(需要新创建JTemplate,并添加监听,不确定会不会有问题) + path = path.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY); + VcsHelper.getInstance().moveVcs(path, newPath.replaceFirst(ProjectConstants.REPORTLETS_NAME, StringUtils.EMPTY)); + } DesignerContext.getDesignerFrame().setTitle(); if (TemplateTreeSearchManager.getInstance().isInSearchMode()) { TemplateTreeSearchManager.getInstance().outOfSearchMode(); @@ -328,7 +335,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", diff --git a/designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java b/designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java index 9f303c083c..77f9ed2df5 100644 --- a/designer-base/src/main/java/com/fr/design/file/DefaultTemplateTreeDefineProcessor.java +++ b/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; @@ -184,7 +181,7 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi ArrayList pasteNodes = new ArrayList<>(); ArrayList lockedNodes = new ArrayList<>(); for (ExpandMutableTreeNode treeNode : treeNodeList) { - checkFreeOrLock(treeNode, pasteNodes, lockedNodes); + FileOperationHelper.getInstance().checkFreeOrLock(treeNode, pasteNodes, lockedNodes); } if (pasteNodes.isEmpty()) { //提示:复制的文件都不能黏贴 @@ -206,14 +203,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 +235,19 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi private void doPaste(String targetDir, List 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 +255,36 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE); } + + // 粘贴时如果正在搜索,跳回原树 + if (TemplateTreeSearchManager.getInstance().isInSearchMode()) { + TemplateTreeSearchManager.getInstance().outOfSearchMode(); + } + DesignerFrameFileDealerPane.getInstance().getSelectedOperation().refreshParent(); + LocateAction.gotoEditingTemplateLeaf(targetFile); + } + + /** + * 确认粘贴的目标目录是否是复制文件的子目录,并确认是否继续执行粘贴任务 + * + * @param targetDir 目标文件夹 + * @param pasteNodes 待粘贴的文件 + * @return 是否继续 + */ + private boolean confirmTargetDir(String targetDir, List pasteNodes) { + List 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 +310,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 +339,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 +386,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,10 +399,8 @@ 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()) { @@ -416,19 +438,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 +458,6 @@ public class DefaultTemplateTreeDefineProcessor extends AbstractTemplateTreeDefi } } - private boolean checkFreeOrLock(ExpandMutableTreeNode node, ArrayList dNodes, ArrayList 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 dNodes, ArrayList 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 +477,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; - } } diff --git a/designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java b/designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java new file mode 100644 index 0000000000..d3bb405f6a --- /dev/null +++ b/designer-base/src/main/java/com/fr/design/file/FileOperationHelper.java @@ -0,0 +1,193 @@ +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 dNodes, ArrayList 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 dNodes, ArrayList 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); + } + for (FileNode fileNode : fileNodes) { + if (fileNode.isDirectory()) { + copyDir(StableUtils.pathJoin(fileNode.getParent(), fileNode.getName()), StableUtils.pathJoin(targetDir, fileNode.getName()), withCopyVcs); + } + 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; + } + +} diff --git a/designer-base/src/main/java/com/fr/design/file/FileOperations.java b/designer-base/src/main/java/com/fr/design/file/FileOperations.java index 578739373b..8c428af5e9 100644 --- a/designer-base/src/main/java/com/fr/design/file/FileOperations.java +++ b/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); } \ No newline at end of file diff --git a/designer-base/src/main/java/com/fr/design/file/TemplateResource.java b/designer-base/src/main/java/com/fr/design/file/TemplateResource.java index f394822d6b..0bc8b5c96f 100644 --- a/designer-base/src/main/java/com/fr/design/file/TemplateResource.java +++ b/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); } diff --git a/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java b/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java index 9bace59455..50a5158cb5 100644 --- a/designer-base/src/main/java/com/fr/design/file/TemplateTreePane.java +++ b/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 deletableNodes = new ArrayList<>(); ArrayList 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 dNodes, ArrayList 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 unlockedNodes = new ArrayList<>(); ArrayList lockedNodes = new ArrayList<>(); for (ExpandMutableTreeNode treeNode : treeNodes) { - checkFreeOrLock(treeNode, unlockedNodes, lockedNodes); + FileOperationHelper.getInstance().checkFreeOrLock(treeNode, unlockedNodes, lockedNodes); } if (!lockedNodes.isEmpty()) { @@ -541,10 +502,11 @@ 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(); @@ -553,7 +515,8 @@ public class TemplateTreePane extends JPanel implements FileOperations { } DefaultMutableTreeNode currentTreeNode = (DefaultMutableTreeNode) treePath.getLastPathComponent(); Enumeration children; - if (reportletsTree.getSelectedFileNode().isDirectory()) { + //现在可以在目录下创建目录,重命名时是基于所选节点的父目录的子目录进行校验,目录下新建子目录时,基于所选目录的子目录进行校验 + if (reportletsTree.getSelectedFileNode().isDirectory() && baseOnSelf) { children = currentTreeNode.children(); } else { TreeNode parentTreeNode = currentTreeNode.getParent(); diff --git a/designer-base/src/main/java/com/fr/design/file/impl/AbstractTemplateResource.java b/designer-base/src/main/java/com/fr/design/file/impl/AbstractTemplateResource.java index cb76792a13..58406c935c 100644 --- a/designer-base/src/main/java/com/fr/design/file/impl/AbstractTemplateResource.java +++ b/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; + } } diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateFileTree.java b/designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateFileTree.java index d312beb919..609e99e862 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itree/filetree/TemplateFileTree.java +++ b/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 allTreeNode = new ConcurrentHashMap<>(); + protected Map calculateNode = new ConcurrentHashMap<>(); protected Map> 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 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); + } } } diff --git a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java b/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java index e6bfff633c..04a513d5b6 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/DesignerFrameFileDealerPane.java +++ b/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()) { diff --git a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateTreeSearchManager.java b/designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateTreeSearchManager.java index 9375e5fb81..c9b875c562 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/manager/search/TemplateTreeSearchManager.java +++ b/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()); diff --git a/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java b/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java index 0ec5b9c4f5..9279ad455c 100644 --- a/designer-base/src/main/java/com/fr/design/mainframe/vcs/common/VcsHelper.java +++ b/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,28 @@ public class VcsHelper implements JTemplateActionListener { fireVcs.shutdown(); } + 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 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) {