/* Jreepad - personal information manager. Copyright (C) 2004 Dan Stowell This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. The full license can be read online here: http://www.gnu.org/copyleft/gpl.html */ package jreepad; import java.awt.Cursor; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Enumeration; import java.util.Vector; import javax.swing.JTree; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; /** * The GUI component that displays the tree. * * @version $Id$ */ public class TreeView extends JTree { private JreepadTreeModel treeModel; public TreeView(JreepadTreeModel treeModel) { super(treeModel); this.treeModel = treeModel; getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); setExpandsSelectedPaths(true); setInvokesStopCellEditing(true); setEditable(true); DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(); renderer.setOpenIcon(null); renderer.setClosedIcon(null); renderer.setLeafIcon(null); setCellRenderer(renderer); // Add mouse listener - this will be used to implement drag-and-drop, context menu (?), etc addMouseListener(new TreeViewMouseListener()); } public void moveNode(JreepadNode node, JreepadNode newParent) { // First we need to make sure that the node is not a parent of the new parent // - otherwise things would go really wonky! if (node.isNodeDescendant(newParent)) return; JreepadNode oldParent = node.getParentNode(); // Now make a note of the expanded/collapsed state of the subtree of the moving node boolean thisOnesExpanded = isExpanded(getSelectionPath()); Enumeration enumer; Vector expanded; if (thisOnesExpanded) { enumer = getExpandedDescendants(getSelectionPath()); expanded = new Vector(); while (enumer.hasMoreElements()) expanded.add(enumer.nextElement()); } newParent.add(node); // Also removes from old parent treeModel.reload(oldParent); treeModel.reload(newParent); // If the destination node didn't previously have any children, then we'll expand it // if(newParent.getChildCount()==1) // Reapply the expanded/collapsed states } public void expandAll(JreepadNode thisNode, TreePath tp) { // It's at this point that we expand the current element expandPath(tp); Enumeration getKids = thisNode.children(); JreepadNode thisKid; while (getKids.hasMoreElements()) { thisKid = (JreepadNode)getKids.nextElement(); expandAll(thisKid, tp.pathByAddingChild(thisKid)); } } public void collapseAll(JreepadNode thisNode, TreePath tp) { Enumeration getKids = thisNode.children(); JreepadNode thisKid; while (getKids.hasMoreElements()) { thisKid = (JreepadNode)getKids.nextElement(); collapseAll(thisKid, tp.pathByAddingChild(thisKid)); } // It's at this point that we collapse the current element collapsePath(tp); } public TreePath[] getAllExpandedPaths() { JreepadNode root = (JreepadNode)treeModel.getRoot(); if (root.getChildCount() == 0) return new TreePath[] { new TreePath(root) }; Enumeration getPaths = getExpandedDescendants(new TreePath(root)); TreePath thisKid; Vector allPaths = new Vector(); while (getPaths.hasMoreElements()) { thisKid = (TreePath)getPaths.nextElement(); allPaths.add(thisKid); } TreePath[] ret = new TreePath[allPaths.size()]; for (int i = 0; i < ret.length; i++) ret[i] = (TreePath)allPaths.get(i); return ret; } // THIS FUNCTION SEEMS TO HAVE NO EFFECT, ON MY MACHINE AT LEAST! WHAT'S GOING ON? public void expandPaths(TreePath[] paths) { for (int i = 0; i < paths.length; i++) { expandPath(paths[i]); } } /** * Mouse control for the Tree View. */ private class TreeViewMouseListener extends MouseAdapter { private JreepadNode currentDragDropNode; public void mousePressed(MouseEvent e) { TreePath selPath = getPathForLocation(e.getX(), e.getY()); if (selPath != null) { currentDragDropNode = (JreepadNode)selPath.getLastPathComponent(); setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } } public void mouseReleased(MouseEvent e) { TreePath selPath = getPathForLocation(e.getX(), e.getY()); // System.out.println("Mouse released: path = " + selPath); if (selPath != null) { if (currentDragDropNode != null && currentDragDropNode.getParentNode() != null && currentDragDropNode.getParentNode() != (JreepadNode)selPath .getLastPathComponent() && currentDragDropNode != (JreepadNode)selPath.getLastPathComponent()) { // Then we need to perform a drag-and-drop operation! moveNode(currentDragDropNode, (JreepadNode)selPath.getLastPathComponent()); // Ensure that the destination node is open setSelectionPath(selPath.pathByAddingChild(currentDragDropNode)); } } setCursor(Cursor.getDefaultCursor()); currentDragDropNode = null; } public void mouseClicked(MouseEvent e) { TreePath selPath = getPathForLocation(e.getX(), e.getY()); if (selPath != null) { if (e.isPopupTrigger()) { // Now we can implement the pop-up content menu System.out.println("Context menu would be launched here!"); } } } } }