import java.awt.BorderLayout;
import java.awt.event.*;
import java.util.*;
import java.util.Enumeration;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.*;
import javax.swing.tree.TreeNode;

/**
 * @author Remi Forax
 *
 */
public class MutableTreeExample {

  public static class MyTreeModel extends DefaultTreeModel {

    public MyTreeModel(Object value) {
      super(null);
      setRoot(new MyTreeNode(null,value));
    }
    
    public MyTreeNode getRootTreeNode() {
      return (MyTreeNode)getRoot();
    }
    
    public void valueForPathChanged(TreePath path, Object newValue) {
      MyTreeNode node=(MyTreeNode)path.getLastPathComponent();
      node.setValue(newValue);
      
      nodeChanged(node);
    }

    public class MyTreeNode implements TreeNode {

      MyTreeNode(MyTreeNode parent, Object value) {
        this.parent= parent;
        this.value= value;
      }

      public int getChildCount() {
        return list.size();
      }

      public boolean getAllowsChildren() {
        return true;
      }

      public boolean isLeaf() {
        return list.isEmpty();
      }

      public Enumeration children() {
        return Collections.enumeration(list);
      }

      public TreeNode getParent() {
        return parent;
      }

      public TreeNode getChildAt(int index) {
        return (MyTreeNode)list.get(index);
      }

      public int getIndex(TreeNode node) {
        return list.indexOf(node);
      }

      public String toString() {
        return value.toString();
      }

      public MyTreeNode add(Object value) {
        MyTreeNode child= new MyTreeNode(this, value);
        list.add(child);

        /*
        TreeNode[] path=getPathToRoot(this);

        fireTreeNodesInserted(MyTreeModel.this, path,
          new int[]{list.size()-1}, new Object[]{child});
        */
          
        nodesWereInserted(this, new int[]{list.size()-1});
        
        return child;
      }
      
      public Object getValue() {
        return value;
      }
      
      public void setValue(Object value) {
        this.value=value;
      }

      private Object value;
      private final MyTreeNode parent;
      private final ArrayList list= new ArrayList();
    }

  }

  public static void main(String[] args) {

    MyTreeModel model= new MyTreeModel("root");
    MyTreeModel.MyTreeNode root=model.getRootTreeNode();
    
    MyTreeModel.MyTreeNode  node1=root.add("item 1");
    node1.add("sous item 1");
    
    MyTreeModel.MyTreeNode  node2=root.add("item 2");
    node2.add("sous item 1");
    node2.add("sous item 2");
    
    final JTree tree=new JTree(model);
    tree.setEditable(true);
    
    final JFrame frame=new JFrame();
    
    final JButton button=new JButton("add");
    button.setEnabled(false);
    button.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        String text=JOptionPane.showInputDialog(frame,"entrer un nom");
        if (text==null)
          return;
          
        MyTreeModel.MyTreeNode node=
          (MyTreeModel.MyTreeNode)tree.getSelectionPath().getLastPathComponent();
        
        node.add(text);
      }
    });
    
    tree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
      public void valueChanged(TreeSelectionEvent e) {
        button.setEnabled(tree.getSelectionPath()!=null);
      }
    });
    
    JPanel panel=new JPanel(new BorderLayout());
    panel.add(new JScrollPane(tree),BorderLayout.CENTER);
    panel.add(button,BorderLayout.SOUTH);
    
    frame.setContentPane(panel);
    frame.pack();
    frame.show();
  }
}
