/* * Copyright(c) 2001-2010, FineReport Inc, All Rights Reserved. */ package com.fr.design.file; import com.fr.base.FRContext; import com.fr.design.ExtraDesignClassManager; import com.fr.design.dialog.FineJOptionPane; import com.fr.design.fun.TemplateTreeDefineProcessor; import com.fr.design.gui.itree.filetree.TemplateFileTree; import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; import com.fr.design.i18n.Toolkit; import com.fr.design.layout.FRGUIPaneFactory; import com.fr.design.lock.LockInfoUtils; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerFrameFileDealerPane; import com.fr.design.lock.LockInfoDialog; import com.fr.design.mainframe.JTemplate; import com.fr.design.mainframe.manager.search.searcher.control.pane.TemplateSearchRemindPane; import com.fr.file.FILE; import com.fr.file.FileNodeFILE; import com.fr.file.filetree.FileNode; import com.fr.file.filetree.IOFileNodeFilter; import com.fr.form.fit.web.editpreview.FileLockStateObservable; import com.fr.general.ComparatorUtils; import com.fr.general.IOUtils; import com.fr.log.FineLoggerFactory; import com.fr.workspace.base.UserInfo; import com.fr.stable.ArrayUtils; import com.fr.stable.CoreConstants; import com.fr.stable.StableUtils; import com.fr.stable.project.ProjectConstants; import com.fr.workspace.WorkContext; import com.fr.report.lock.LockInfoOperator; import java.util.UUID; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.ToolTipManager; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import java.awt.BorderLayout; import java.awt.Desktop; import java.awt.Dimension; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.Objects; import java.util.Observable; import java.util.Observer; import org.jetbrains.annotations.Nullable; import static javax.swing.JOptionPane.WARNING_MESSAGE; import static javax.swing.JOptionPane.YES_NO_OPTION; public class TemplateTreePane extends JPanel implements FileOperations { public static TemplateTreePane getInstance() { return HOLDER.singleton; } private static class HOLDER { private static TemplateTreePane singleton = new TemplateTreePane(); } private TemplateFileTree reportletsTree; private TemplateSearchRemindPane remindPane; private FileToolbarStateChangeListener toolBarStateChangeListener; private TemplateTreePane() { this.setLayout(FRGUIPaneFactory.createBorderLayout()); this.setPreferredSize(new Dimension(250, super.getPreferredSize().height)); reportletsTree = new TemplateFileTree(); remindPane = new TemplateSearchRemindPane(getTemplateFileTree()); this.add(remindPane, BorderLayout.CENTER); ToolTipManager.sharedInstance().registerComponent(reportletsTree); FileLockStateObservable.getInstance().addObserver(new Observer() { @Override public void update(Observable o, Object arg) { TemplateTreePane.this.refresh(); } }); /* * Tree.MouseAdapter */ MouseListener mouseFileTreeListener = new MouseAdapter() { @Override public void mousePressed(MouseEvent evt) { if (reportletsTree.getPathForLocation(evt.getX(), evt.getY()) != null && evt.getClickCount() == 2) { openFile(); } } @Override public void mouseClicked(MouseEvent e) { if (SwingUtilities.isRightMouseButton(e)) { TemplateTreeDefineProcessor processor = ExtraDesignClassManager.getInstance().getSingle(TemplateTreeDefineProcessor.XML_TAG); if (processor != null) { processor.rightClickAction(e); } else { DefaultTemplateTreeDefineProcessor.getInstance().rightClickAction(e); } } } @Override public void mouseReleased(MouseEvent e) { if (toolBarStateChangeListener != null) { toolBarStateChangeListener.stateChange(); } DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(reportletsTree.getSelectedFileNode()); } }; // lx: add mouse listener this.reportletsTree.addMouseListener(mouseFileTreeListener); this.reportletsTree.addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { openFile(); } } @Override public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { openFile(); } if (toolBarStateChangeListener != null) { toolBarStateChangeListener.stateChange(); } } @Override public void keyTyped(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { openFile(); } } }); } public TemplateFileTree getTemplateFileTree() { return this.reportletsTree; } /** * 选中的路径数 * * @return 选中的路径数 */ public int countSelectedPath() { TreePath[] treePaths = reportletsTree.getSelectionPaths(); if (treePaths == null) { return 0; } return treePaths.length; } /** * 选中的文件夹个数 * * @return 选中的文件夹个数 */ public int countSelectedFolder() { if (reportletsTree.getSelectedFolderPaths() == null) { return 0; } return reportletsTree.getSelectedFolderPaths().length; } /** * 选中的文件个数 * * @return 选中的文件 */ public int countSelectedFile() { if (reportletsTree.getSelectionPaths() == null) { return 0; } return reportletsTree.getSelectedTemplatePaths().length; } /** * 刷新 */ public void refreshDockingView() { reportletsTree.setFileNodeFilter(new IOFileNodeFilter(FRContext.getFileNodes().getSupportedTypes())); reportletsTree.refreshEnv(); } @Override public boolean mkdir(String path) { return TemplateResourceManager.getResource().mkdir(path); } /** * 打开选中的报表文件 */ @Override public void openFile() { // 判断是否是远程设计的锁定文件 FileNode node = reportletsTree.getSelectedFileNode(); if (node == null) { return; } String reportPath = reportletsTree.getSelectedTemplatePath(); final String selectedFilePath = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, reportPath); String lock = node.getLock(); boolean showLockInfo = LockInfoUtils.isCompatibleOperator() || LockInfoUtils.unableGetLockInfo() || WorkContext.getCurrent().get(LockInfoOperator.class).isTplUnLocked(selectedFilePath) ? (lock != null && !lock.equals(node.getUserID())) : WorkContext.getCurrent().get(LockInfoOperator.class).isTplLocked(selectedFilePath); if (showLockInfo) { UserInfo userInfo = WorkContext.getCurrent().get(LockInfoOperator.class).getUserInfo(selectedFilePath); node.setLock(UUID.randomUUID().toString()); // 对于开发者预览占位锁定 定位到tab中 checkDevelopForBiddenTemplate(selectedFilePath); LockInfoDialog.show(userInfo); return; } else { node.setLock(null); } DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(new FileNode(selectedFilePath, false))); } private void checkDevelopForBiddenTemplate(String selectedFilePath) { JTemplate template = getOpenedTemplate(selectedFilePath); if (template != null && template.isForbidden()) { DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(new FileNode(selectedFilePath, false))); } } @Nullable private JTemplate getOpenedTemplate(String path) { for (JTemplate template : HistoryTemplateListCache.getInstance().getHistoryList()) { if (ComparatorUtils.equals(template.getEditingFILE().getPath(), path)) { return template; } } return null; } /** * 打开文件夹 */ @Override public void showInExplorer() { FileNode fn = TemplateTreePane.this.reportletsTree.getSelectedFileNode(); String filePath = StableUtils.pathJoin(WorkContext.getCurrent().getPath(), fn.getEnvPath()); filePath = filePath.substring(0, filePath.lastIndexOf(CoreConstants.SEPARATOR)); try { Desktop.getDesktop().open(new File(filePath)); } catch (Exception e) { IOUtils.openWindowsFolder(StableUtils.pathJoin(WorkContext.getCurrent().getPath(), fn.getEnvPath())); } } /** * 刷新 */ @Override public void refresh() { // 刷新远程文件夹权限 NodeAuthProcessor.getInstance().refresh(); reportletsTree.refresh(); DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(null); FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_File_Tree_Refresh_Successfully") + "!"); } /** * 刷新父目录 */ @Override public void refreshParent() { // 刷新远程文件夹权限 NodeAuthProcessor.getInstance().refresh(); if (reportletsTree.getSelectionCount() == 0) { //没选中文件刷新根目录 reportletsTree.refresh(); } if (reportletsTree.getSelectedFileNode().isDirectory()) { reportletsTree.refreshDir(Objects.requireNonNull(reportletsTree.getSelectionPath())); } else { reportletsTree.refreshParent(Objects.requireNonNull(reportletsTree.getSelectionPath())); } DesignerFrameFileDealerPane.getInstance().refreshRightToolBarBy(null); FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_File_Tree_Refresh_Successfully") + "!"); } /** * 删除文件 * 文件夹和文件均可删除 *

* 当文件被锁时不能删除 * 当文件夹中包含被锁文件时不能删除 */ @Override public void deleteFile() { ExpandMutableTreeNode[] treeNodes = reportletsTree.getSelectedTreeNodes(); // 筛选可以删除的文件 ArrayList deletableNodes = new ArrayList<>(); ArrayList lockedNodes = new ArrayList<>(); for (ExpandMutableTreeNode treeNode : treeNodes) { checkFreeOrLock(treeNode, deletableNodes, lockedNodes); } if (lockedNodes.isEmpty()) { String tipContent = countSelectedFolder() > 0 ? Toolkit.i18nText("Fine-Design_Basic_Confirm_Delete_Folder") : Toolkit.i18nText("Fine-Design_Basic_Confirm_Delete_File"); if (FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), tipContent, Toolkit.i18nText("Fine-Design_Basic_Confirm"), YES_NO_OPTION) == JOptionPane.YES_OPTION) { // 删除所有选中的即可 if (!deleteNodes(Arrays.asList(treeNodes))) { FineJOptionPane.showConfirmDialog(null, Toolkit.i18nText("Fine-Design_Basic_Delete_Failure"), Toolkit.i18nText("Fine-Design_Basic_Error"), JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE); } } } else { String tipContent = countSelectedFolder() > 0 ? Toolkit.i18nText("Fine-Design_Basic_Confirm_Delete_Unlock_File_And_Folder") : Toolkit.i18nText("Fine-Design_Basic_Confirm_Delete_Unlock_File"); if (deletableNodes.isEmpty()) { // 提醒被锁定模板无法删除 FineJOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Unable_Delete_Locked_File"), Toolkit.i18nText("Fine-Design_Basic_Alert"), WARNING_MESSAGE); return; } if (FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), tipContent, Toolkit.i18nText("Fine-Design_Basic_Confirm"), YES_NO_OPTION) == JOptionPane.YES_OPTION) { // 删除其他 if (!deleteNodes(deletableNodes)) { FineJOptionPane.showConfirmDialog(null, Toolkit.i18nText("Fine-Design_Basic_Delete_Failure"), Toolkit.i18nText("Fine-Design_Basic_Error"), JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE); } } } refreshAfterDelete(); } private void refreshAfterDelete() { TreePath[] paths = reportletsTree.getSelectionPaths(); if (paths == null) { reportletsTree.refresh(); } else { for (TreePath path : Objects.requireNonNull(reportletsTree.getSelectionPaths())) { reportletsTree.refreshParent(path); } } } private boolean deleteNodes(Collection nodes) { boolean success = true; for (ExpandMutableTreeNode treeNode : nodes) { Object node = treeNode.getUserObject(); if (node instanceof FileNode) { FileNodeFILE nodeFILE = new FileNodeFILE((FileNode) node); if (nodeFILE.exists()) { if (TemplateResourceManager.getResource().delete(nodeFILE)) { HistoryTemplateListCache.getInstance().deleteFile(nodeFILE); } else { success = false; } } } } 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() { throw new UnsupportedOperationException("unsupport now"); } @Override public void unlockFile() { throw new UnsupportedOperationException("unsupport now"); } @Override public String getFilePath() { return reportletsTree.getSelectedTemplatePath(); } @Override public boolean access() { TreePath[] selectedTreePaths = reportletsTree.getSelectionPaths(); if (ArrayUtils.isEmpty(selectedTreePaths)) { return false; } // 选中的是文件夹 TreePath treePath = selectedTreePaths[0]; ExpandMutableTreeNode currentTreeNode = (ExpandMutableTreeNode) treePath.getLastPathComponent(); ExpandMutableTreeNode parentTreeNode = (ExpandMutableTreeNode) currentTreeNode.getParent(); return parentTreeNode != null && parentTreeNode.hasFullAuthority(); } @Override public boolean rename(FILE tplFile, String from, String to) { // 多人协作时判断是否有锁定的文件 ExpandMutableTreeNode[] treeNodes = reportletsTree.getSelectedTreeNodes(); // 筛选可以重命名的文件 ArrayList unlockedNodes = new ArrayList<>(); ArrayList lockedNodes = new ArrayList<>(); for (ExpandMutableTreeNode treeNode : treeNodes) { checkFreeOrLock(treeNode, unlockedNodes, lockedNodes); } if (!lockedNodes.isEmpty()) { FineJOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), Toolkit.i18nText("Fine-Design_Basic_Warn_Rename_Lock_File"), Toolkit.i18nText("Fine-Design_Basic_Alert"), JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE); return true; } try { // 接收的是WEB-INF下的路径 return TemplateResourceManager.getResource().rename(from, to); } catch (Exception e) { FineLoggerFactory.getLogger().error(e.getMessage(), e); return false; } } @Override public FileNode getFileNode() { return reportletsTree.getSelectedFileNode(); } public void setToolbarStateChangeListener(FileToolbarStateChangeListener listener) { this.toolBarStateChangeListener = listener; } /** * 仅支持在拥有完整权限的文件夹下进行新建和重命名操作,那么是可以看到改文件夹下所有文件的。 * * @param newName 原名 * @param suffix 后缀名 * @return 是否有重名的 */ @Override public boolean duplicated(String newName, String suffix) { // 选中的节点 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(); } 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; } } else { return false; } } return false; } }