package tk.amberide.ide.swing.tree.filesystem; import tk.amberide.ide.data.io.FileIO; import tk.amberide.ide.swing.tree.Trees; import java.awt.Component; import java.awt.Point; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.event.MouseEvent; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import java.util.TooManyListenersException; import javax.swing.Icon; import javax.swing.JLabel; import javax.swing.JTree; import javax.swing.filechooser.FileSystemView; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreePath; import tk.amberide.ide.swing.tree.filesystem.FileTreeModel.FileTreeNode; import java.awt.AWTEvent; import java.awt.dnd.DnDConstants; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; public class FileSystemTree extends JTree { private FileTreeTransferHandler handler = null; private boolean fileMovingEnabled = true; FileTreeNode draggedNode = null; protected ArrayList<FileTreeAdapter> adapters = new ArrayList<FileTreeAdapter>(); private final DropTargetListener dragExecutor = new DropTargetListener() { public void dragEnter(DropTargetDragEvent dtde) { } public void dragOver(DropTargetDragEvent dtde) { Point e = dtde.getLocation(); TreePath tp = getPathForLocation(e.x, e.y); if (tp != null) { draggedNode = ((FileTreeNode) tp.getLastPathComponent()); File targetDir = draggedNode.getFile(); if (targetDir.isFile()) { targetDir = targetDir.getParentFile(); } if (!targetDir.canWrite()) { dtde.acceptDrag(DnDConstants.ACTION_NONE); } else { File[] fileToDragged = handler.files; for (int i = 0; i < fileToDragged.length; i++) { if (fileToDragged[i].getParentFile() != null) { if (fileToDragged[i].getParentFile().equals(targetDir)) { dtde.acceptDrag(DnDConstants.ACTION_NONE); } } else { return; } } dtde.acceptDrag(DnDConstants.ACTION_MOVE); } } } public void dropActionChanged(DropTargetDragEvent dtde) { } public void dragExit(DropTargetEvent dte) { } public void drop(DropTargetDropEvent dtde) { } }; public FileSystemTree() { setRootVisible(false); setCellRenderer(new DefaultTreeCellRenderer() { protected Map<String, Icon> iconCache = new HashMap<String, Icon>(); protected FileSystemView fsv = FileSystemView.getFileSystemView(); @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { _outer: if ((value instanceof FileTreeNode)) { FileTreeNode node = (FileTreeNode) value; File file = node.getFile(); if (file != null) { String name = file.getName(); String ext = FileIO.getFileExtension(file); JLabel result = (JLabel) super.getTreeCellRendererComponent(tree, name, sel, expanded, leaf, row, hasFocus); Icon icon = iconCache.get(name); if (icon == null) { icon = fsv.getSystemIcon(file); for (FileTreeAdapter ad : adapters) { Icon ic = ad.getIcon(file, ext, node, icon); if (ic != icon) { icon = ic; } } iconCache.put(name, icon); } result.setIcon(icon); return result; } } return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); } }); setCellEditor(new FileTreeCellEditor()); setDragEnabled(false); setEditable(true); setTransferHandler(handler = new FileTreeTransferHandler()); setModel(new FileTreeModel()); addMouseMotionListener(new MouseAdapter() { @Override public void mouseDragged(MouseEvent e) { if (fileMovingEnabled) { TreePath path = getPathForLocation(e.getX(), e.getY()); if (path != null) { draggedNode = ((FileTreeNode) path.getLastPathComponent()); if (draggedNode.getFile() != null && draggedNode.getFile().isFile()) { handler.exportAsDrag(FileSystemTree.this, e, 2); } } } } }); addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent evt) { switch (evt.getKeyCode()) { case KeyEvent.VK_F2: startEditingAtPath(getSelectionPath()); break; } } }); } public void addFileTreeAdapter(FileTreeAdapter ftl) { adapters.add(ftl); addTreeExpansionListener(ftl); addTreeSelectionListener(ftl); addTreeWillExpandListener(ftl); addKeyListener(ftl); } @Override public void processEvent(AWTEvent evt) { super.processEvent(evt); if (evt instanceof MouseEvent) { MouseEvent me = (MouseEvent) evt; for (FileTreeAdapter ftl : adapters) { ftl.nodeClicked(me, getPathForRow(getClosestRowForLocation(me.getX(), me.getY()))); } } } void renameSelection(String newName) { TreePath tp = getSelectionPath(); if (tp == null) { return; } FileTreeNode ftn = (FileTreeNode) tp.getLastPathComponent(); File f = ftn.getFile(); File nf; if (f.renameTo(nf = new File(f.getParentFile(), newName))) { ftn.file = nf; repaint(); } } public void setFileMovingEnabled(boolean enabled) { fileMovingEnabled = enabled; } public boolean isFileMovingEnabled() { return fileMovingEnabled; } public void setFileRenamingEnabled(boolean enabled) { setEditable(enabled); } public boolean isFileTreeEnabled() { return isEditable(); } void setSelectedFile(File file) { String path = file.getPath(); StringTokenizer st = new StringTokenizer(path, "/" + File.separator); FileTreeNode node = (FileTreeNode) getModel().getRoot(); TreePath tp = new TreePath(getModel().getRoot()); if (path.startsWith("/")) { for (int i = 0; i < node.getChildCount(); i++) { FileTreeNode child = (FileTreeNode) node.getChildAt(i); if (child.toString().equals("/")) { node = child; tp = tp.pathByAddingChild(child); break; } } } while (st.hasMoreTokens()) { String element = st.nextToken(); boolean found = true; for (int i = 0; i < node.getChildCount(); i++) { FileTreeNode child = (FileTreeNode) node.getChildAt(i); String name = child.getFile().getName(); if ("".equals(name)) { name = child.getFile().getPath(); } if ((name.equals(element)) || (name.equals(element + "/")) || (name.equals(element + "\\"))) { node = child; tp = tp.pathByAddingChild(child); found = true; break; } } if (!found) { break; } } if (tp.getLastPathComponent() == getModel().getRoot()) { FileTreeNode rootNode = (FileTreeNode) getModel().getRoot(); if (rootNode.getChildCount() > 0) { tp = new TreePath( new Object[]{ rootNode, rootNode.getChildAt(0)}); } } expandPath(tp); setSelectionPath(tp); scrollPathToVisible(tp); } File[] getSelectedFiles() { TreePath[] tp = getSelectionPaths(); if (tp == null) { return null; } File[] files = new File[tp.length]; for (int i = 0; i < tp.length; i++) { files[i] = ((FileTreeNode) tp[i].getLastPathComponent()).getFile(); } return files; } @Override public void addNotify() { super.addNotify(); try { getDropTarget().addDropTargetListener(dragExecutor); } catch (TooManyListenersException ignored) { } } @Override public void removeNotify() { super.removeNotify(); getDropTarget().removeDropTargetListener(dragExecutor); } public void setRoot(File root) { setModel(new FileTreeModel(root)); synchronize(); } public File getRoot() { return getModel() != null ? ((FileTreeModel) getModel()).getRoot().file : null; } public void synchronize() { String state = Trees.getExpansionState(this, 0); setModel(new FileTreeModel(((FileTreeModel) getModel()).getRoot().file)); if (state != null) { Trees.restoreExpanstionState(this, 0, state); } repaint(); } }