import java.awt.GridLayout;
import java.awt.Toolkit;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
//import javax.swing.tree.MyTreeNode;
//import javax.swing.tree.DefaultTreeModel;
//import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;

public class DynamicTree extends JPanel {
  static final long serialVersionUID = 42;

  protected MyTreeNode rootNode;
  protected MyTreeModel treeModel;
  protected JTree tree;
  private Toolkit toolkit = Toolkit.getDefaultToolkit();

  public DynamicTree() {
    super(new GridLayout(1,0));
        
    rootNode = new MyTreeNode("Root Node");
    treeModel = new MyTreeModel(rootNode);
    treeModel.addTreeModelListener(new MyTreeModelListener());
    tree = new JTree(treeModel);
    tree.setEditable(true);
    tree.getSelectionModel().setSelectionMode
      (TreeSelectionModel.SINGLE_TREE_SELECTION);
    tree.setShowsRootHandles(true);

    JScrollPane scrollPane = new JScrollPane(tree);
    add(scrollPane);
  }

  /** Remove all nodes except the root node. */
  public void clear() {
    rootNode.removeAllChildren();
    treeModel.reload();
  }

  /** Remove the currently selected node. */
  public void removeCurrentNode() {
    TreePath currentSelection = tree.getSelectionPath();
    if (currentSelection != null) {
      MyTreeNode currentNode = (MyTreeNode)
        (currentSelection.getLastPathComponent());
      MyTreeNode parent = currentNode.getParent();
      if (parent != null) {
        treeModel.removeNodeFromParent(currentNode);
        return;
      }
    } 

    // Either there was no selection, or the root was selected.
    toolkit.beep();
  }

  /** Add child to the currently selected node. */
  public MyTreeNode addObject(Object child) {
    MyTreeNode parentNode = null;
    TreePath parentPath = tree.getSelectionPath();

    if (parentPath == null) {
      parentNode = rootNode;
    } else {
      parentNode = (MyTreeNode)
        (parentPath.getLastPathComponent());
    }

    return addObject(parentNode, child, true);
  }

  public MyTreeNode addObject(MyTreeNode parent,
                                          Object child) {
    return addObject(parent, child, false);
  }

  public MyTreeNode addObject(MyTreeNode parent,
                                          Object child, 
                                          boolean shouldBeVisible) {
    MyTreeNode childNode = 
      new MyTreeNode(child);

    if (parent == null) {
      parent = rootNode;
    }
	
    //It is key to invoke this on the TreeModel, and NOT MyTreeNode
    treeModel.insertNodeInto(childNode, parent, 
                             parent.getChildCount());

    //Make sure the user can see the lovely new node.
    if (shouldBeVisible) {
      tree.scrollPathToVisible(new TreePath(childNode.getPath()));
    }
    return childNode;
  }

  class MyTreeModelListener implements TreeModelListener {
    public void treeNodesChanged(TreeModelEvent e) {
      MyTreeNode node;
      node = (MyTreeNode)(e.getTreePath().getLastPathComponent());

      /*
       * If the event lists children, then the changed
       * node is the child of the node we've already
       * gotten.  Otherwise, the changed node and the
       * specified node are the same.
       */
      if(e.getChildIndices() != null && e.getChildIndices().length > 0) {
        int index = e.getChildIndices()[0];
        node = node.getChildAt(index);
      }
      System.out.println("The user has finished editing the node.");
      System.out.println("New value: " + node.getUserObject());
    }
    public void treeNodesInserted(TreeModelEvent e) {
    }
    public void treeNodesRemoved(TreeModelEvent e) {
    }
    public void treeStructureChanged(TreeModelEvent e) {
    }
  }
}
