import java.awt.*;
import java.util.*;

import javax.swing.*;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.*;


/**
 * @author Remi Forax
 *
 */
public class HashTreeExample {

  static class MultiMapModel implements TreeModel {

    public MultiMapModel(Map root) {
      this.root=root;
    }

    public Object getRoot() {
      return root;
    }

    public int getChildCount(Object parent) {
      if (parent instanceof Map)
        return ((Map)parent).size();
      
      if (parent instanceof Map.Entry)
        return 1;
      
      return 0;
    }

    public boolean isLeaf(Object node) {
      return !(node instanceof Map || node instanceof Map.Entry);
    }

    public Object getChild(Object parent, int index) {
      if (parent instanceof Map)
        return getObjectAt(((Map)parent).entrySet(),index);
      
      if (parent instanceof Map.Entry)
        return ((Map.Entry)parent).getValue();
      
      throw new AssertionError();
    }

    public int getIndexOfChild(Object parent, Object child) {
      if (parent instanceof Map)
        return indexOf(((Map)parent).entrySet(),child);
      
      if (parent instanceof Map.Entry)
        return 0;
      
      throw new AssertionError();
    }
    
    private Object getObjectAt(Set set,int index) {
      Iterator it=set.iterator();
      for(int i=0;i<index;i++)
        it.next();
        
      return it.next();
    }
    
    private int indexOf(Set set,Object o) {
      Iterator it=set.iterator();
      for(int i=0;it.hasNext();i++)
        if (it.next().equals(o))
          return i;
        
      throw new IllegalArgumentException();
    }

    public void valueForPathChanged(TreePath path, Object newValue) {
      throw new UnsupportedOperationException();
    }
    
    public void addTreeModelListener(TreeModelListener l) {
    }

    public void removeTreeModelListener(TreeModelListener l) {
    }
    
    private final Map root;
  }

  public static void main(String[] args) {
    JFrame frame=new JFrame();
    
    HashMap map=new HashMap();
    map.put("toto","titi");
    
    LinkedHashMap map2=new LinkedHashMap();
    map2.put("tata","titi");
    map.put("titi",map2);
    
    final MultiMapModel model=new MultiMapModel(map);
    final JTree tree=new JTree(model);
    
    tree.setCellRenderer(new DefaultTreeCellRenderer() {
      public Component getTreeCellRendererComponent(
        JTree tree,Object value,boolean selected,
        boolean expanded,boolean leaf,int row,boolean hasFocus) {
          
        return super.getTreeCellRendererComponent(tree, 
          getLabelFor(value), selected, expanded, leaf, row, hasFocus);
      }
      
      private Object getLabelFor(Object value) {
        if (value instanceof Map)
          return value.getClass().getName();
        else
          if (value instanceof Map.Entry)
            return ((Map.Entry)value).getKey();
          else
            return value;
      }
    });
    
    frame.setContentPane(new JScrollPane(tree));
    frame.pack();
    frame.show();
  }
}
