You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
466 lines
16 KiB
466 lines
16 KiB
/* |
|
* Copyright(c) 2001-2010, FineReport Inc, All Rights Reserved. |
|
*/ |
|
package com.fr.design.file; |
|
|
|
import com.fr.base.FRContext; |
|
import com.fr.base.io.FileAssistUtilsOperator; |
|
import com.fr.design.DesignerEnvManager; |
|
import com.fr.design.env.DesignerWorkspaceInfo; |
|
import com.fr.design.gui.icontainer.UIScrollPane; |
|
import com.fr.design.gui.itree.filetree.TemplateFileTree; |
|
import com.fr.design.gui.itree.refreshabletree.ExpandMutableTreeNode; |
|
import com.fr.design.i18n.Toolkit; |
|
import com.fr.design.layout.FRGUIPaneFactory; |
|
import com.fr.design.mainframe.DesignerContext; |
|
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.general.ComparatorUtils; |
|
import com.fr.general.IOUtils; |
|
import com.fr.log.FineLoggerFactory; |
|
import com.fr.stable.CoreConstants; |
|
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.connect.WorkspaceConnection; |
|
|
|
import javax.swing.JOptionPane; |
|
import javax.swing.JPanel; |
|
import javax.swing.ToolTipManager; |
|
import javax.swing.UIManager; |
|
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 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 FileToolbarStateChangeListener toolBarStateChangeListener; |
|
|
|
private TemplateTreePane() { |
|
this.setLayout(FRGUIPaneFactory.createBorderLayout()); |
|
this.setPreferredSize(new Dimension(250, super.getPreferredSize().height)); |
|
JPanel contentPane = FRGUIPaneFactory.createBorderLayout_S_Pane(); |
|
this.add(contentPane, BorderLayout.CENTER); |
|
|
|
reportletsTree = new TemplateFileTree(); |
|
ToolTipManager.sharedInstance().registerComponent(reportletsTree); |
|
UIScrollPane scrollPane = new UIScrollPane(reportletsTree); |
|
scrollPane.setBorder(null); |
|
contentPane.add(scrollPane, BorderLayout.CENTER); |
|
|
|
/* |
|
* Tree.MouseAdapter |
|
*/ |
|
MouseListener mouseFileTreeListener = new MouseAdapter() { |
|
|
|
@Override |
|
public void mousePressed(MouseEvent evt) { |
|
if (evt.getClickCount() == 2) { |
|
openFile(); |
|
} |
|
} |
|
|
|
@Override |
|
public void mouseReleased(MouseEvent e) { |
|
if (toolBarStateChangeListener != null) { |
|
toolBarStateChangeListener.stateChange(); |
|
} |
|
} |
|
}; |
|
// 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 WorkContext.getWorkResource().createDirectory(path); |
|
} |
|
|
|
/** |
|
* 打开选中的报表文件 |
|
*/ |
|
@Override |
|
public void openFile() { |
|
// 判断是否是远程设计的锁定文件 |
|
if (!WorkContext.getCurrent().isLocal()) { |
|
FileNode node = reportletsTree.getSelectedFileNode(); |
|
if (node == null) { |
|
return; |
|
} |
|
|
|
String envName = DesignerEnvManager.getEnvManager().getCurEnvName(); |
|
DesignerWorkspaceInfo info = DesignerEnvManager.getEnvManager().getWorkspaceInfo(envName); |
|
|
|
String username = null; |
|
if (info != null) { |
|
WorkspaceConnection connection = info.getConnection(); |
|
username = connection == null ? StringUtils.EMPTY : connection.getUserName(); |
|
} |
|
String lock = node.getLock(); |
|
if (lock != null && !lock.equals(username)) { |
|
return; |
|
} |
|
} |
|
String reportPath = reportletsTree.getSelectedTemplatePath(); |
|
final String selectedFilePath = StableUtils.pathJoin(ProjectConstants.REPORTLETS_NAME, reportPath); |
|
DesignerContext.getDesignerFrame().openTemplate(new FileNodeFILE(new FileNode(selectedFilePath, false))); |
|
} |
|
|
|
/** |
|
* 打开文件夹 |
|
*/ |
|
@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() { |
|
reportletsTree.refresh(); |
|
FineLoggerFactory.getLogger().info(Toolkit.i18nText("Fine-Design_Basic_Template_File_Tree_Refresh_Successfully") + "!"); |
|
} |
|
|
|
/** |
|
* 删除文件 |
|
* 文件夹和文件均可删除 |
|
* <p> |
|
* 当文件被锁时不能删除 |
|
* 当文件夹中包含被锁文件时不能删除 |
|
*/ |
|
@Override |
|
public void deleteFile() { |
|
|
|
|
|
ExpandMutableTreeNode[] treeNodes = reportletsTree.getSelectedTreeNodes(); |
|
// 筛选可以删除的文件 |
|
ArrayList<ExpandMutableTreeNode> deletableNodes = new ArrayList<>(); |
|
ArrayList<ExpandMutableTreeNode> 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 (JOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), |
|
tipContent, |
|
UIManager.getString("OptionPane.messageDialogTitle"), |
|
YES_NO_OPTION) |
|
== JOptionPane.YES_OPTION) { |
|
// 删除所有选中的即可 |
|
if (!deleteNodes(Arrays.asList(treeNodes))) { |
|
JOptionPane.showConfirmDialog(null, |
|
Toolkit.i18nText("Fine-Design_Basic_Delete_Failure"), |
|
UIManager.getString("OptionPane.messageDialogTitle"), |
|
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 (JOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), |
|
tipContent, |
|
UIManager.getString("OptionPane.messageDialogTitle"), |
|
YES_NO_OPTION) |
|
== JOptionPane.YES_OPTION) { |
|
// 删除其他 |
|
if (!deleteNodes(deletableNodes)) { |
|
JOptionPane.showConfirmDialog(null, |
|
Toolkit.i18nText("Fine-Design_Basic_Delete_Failure"), |
|
UIManager.getString("OptionPane.messageDialogTitle"), |
|
JOptionPane.DEFAULT_OPTION, |
|
JOptionPane.ERROR_MESSAGE); |
|
} |
|
} |
|
} |
|
reportletsTree.refresh(); |
|
} |
|
|
|
private boolean deleteNodes(Collection<ExpandMutableTreeNode> 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()) { |
|
FileAssistUtilsOperator fileAssistUtils = WorkContext.getCurrent().get(FileAssistUtilsOperator.class); |
|
if (fileAssistUtils.moveToTrash(nodeFILE.getPath())) { |
|
HistoryTemplateListCache.getInstance().deleteFile(nodeFILE); |
|
} else { |
|
success = false; |
|
} |
|
} |
|
} |
|
} |
|
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() { |
|
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 (selectedTreePaths == null || selectedTreePaths.length != 1) { |
|
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<ExpandMutableTreeNode> unlockedNodes = new ArrayList<>(); |
|
ArrayList<ExpandMutableTreeNode> lockedNodes = new ArrayList<>(); |
|
for (ExpandMutableTreeNode treeNode : treeNodes) { |
|
checkFreeOrLock(treeNode, unlockedNodes, lockedNodes); |
|
} |
|
|
|
if (!lockedNodes.isEmpty()) { |
|
JOptionPane.showConfirmDialog(DesignerContext.getDesignerFrame(), |
|
Toolkit.i18nText("Fine-Design_Basic_Warn_Rename_Lock_File"), |
|
UIManager.getString("OptionPane.messageDialogTitle"), |
|
JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE); |
|
return true; |
|
} |
|
|
|
try { |
|
// com.fr.io.utils.ResourceIOUtils 接收的是WEB-INF下的路径 |
|
return WorkContext.getWorkResource().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(); |
|
TreeNode parentTreeNode = currentTreeNode.getParent(); |
|
|
|
Enumeration 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; |
|
} |
|
}
|
|
|