//Titel:        JTree
//Version:       1.0
//Copyright:     Copyright (c) 2003, 06
//Autor:         Dipl.-Inf., Dipl.-Ing. (FH) Michael Wilhelm
//Organisation:  HS Harz
//Beschreibung:  Einführung in JTree


// Einfaches Beispiel mit DefaultMutableTreeNode
// MvcTreeNodeRec liefert Zusatzinformationen, mit toString
// Klick Ereignis
// eigenes DatenModell, aufbauend auf die Klasse Person


import java.awt.*;
import javax.swing.*;

import java.awt.event.*;

import javax.swing.tree.DefaultMutableTreeNode;

import javax.swing.tree.*;

import javax.swing.event.*;

import java.io.*;

import java.util.Vector;

public class Tree09 extends JFrame {

  JTree jTree1;
  Person rootNode;

  int _index;


  public Tree09() {
    setGUI();
    this.setLocation(500,300);
  }

  private void setGUI() {
    setSize(400, 300);
    setTitle("JTree 9. Beispiel");
    this.getContentPane().setLayout( new BorderLayout() );

    //---------------------------------------
    rootNode = BuildTree();

    // treeModel = new DefaultTreeModel(rootNode);

       // 1. Aufruf des Konstruktors
    jTree1 = new GenealogyTree(rootNode);



     MouseListener ml = new MyMouseAdapter(jTree1);
     jTree1.addMouseListener(ml);


    jTree1.setBorder(BorderFactory.createLineBorder(Color.black));
    jTree1.setToolTipText("ToolTipp");
    jTree1.setShowsRootHandles(true);

      // Horizontale Linien
    jTree1.putClientProperty("JTree.lineStyle","Horizontal");
      // Mit Linien zwischen den Knoten
    jTree1.putClientProperty("JTree.lineStyle","Angled");

    this.getContentPane().add(jTree1, BorderLayout.CENTER);

    // Neue Version
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  }  // setGUI






  // ----------------------------
    // generiert den Familienbaum

  Person BuildTree() {
      //  Definition der Personen
        //the greatgrandparent generation
        Person a1 = new Person("Jack (great-granddaddy)");
        Person a2 = new Person("Jean (great-granny)");
        Person a3 = new Person("Albert (great-granddaddy)");
        Person a4 = new Person("Rae (great-granny)");
        Person a5 = new Person("Paul (great-granddaddy)");
        Person a6 = new Person("Josie (great-granny)");

        //the grandparent generation
        Person b1 = new Person("Peter (grandpa)");
        Person b2 = new Person("Zoe (grandma)");
        Person b3 = new Person("Simon (grandpa)");
        Person b4 = new Person("James (grandpa)");
        Person b5 = new Person("Bertha (grandma)");
        Person b6 = new Person("Veronica (grandma)");
        Person b7 = new Person("Anne (grandma)");
        Person b8 = new Person("Renee (grandma)");
        Person b9 = new Person("Joseph (grandpa)");

        //the parent generation
        Person c1 = new Person("Isabelle (mom)");
        Person c2 = new Person("Frank (dad)");
        Person c3 = new Person("Louis (dad)");
        Person c4 = new Person("Laurence (dad)");
        Person c5 = new Person("Valerie (mom)");
        Person c6 = new Person("Marie (mom)");
        Person c7 = new Person("Helen (mom)");
        Person c8 = new Person("Mark (dad)");
        Person c9 = new Person("Oliver (dad)");

        //the youngest generation
        Person d1 = new Person("Clement (boy)");
        Person d2 = new Person("Colin (boy)");

          // Erzeugen der Familien Hierachien
          // Alle Personen des temporären Arrays werden als Kinder eingetragen
        Person.linkFamily(a1,a2,new Person[] {b1,b2,b3,b4} );
        Person.linkFamily(a3,a4,new Person[] {b5,b6,b7} );
        Person.linkFamily(a5,a6,new Person[] {b8,b9} );
        Person.linkFamily(b3,b6,new Person[] {c1,c2,c3} );
        Person.linkFamily(b4,b5,new Person[] {c4,c5,c6} );
        Person.linkFamily(b8,b7,new Person[] {c7,c8,c9} );
        Person.linkFamily(c4,c7,new Person[] {d1,d2} );

        return a1;  // Root
  }  // BuildTree



  //Überschreiben, damit das Programm bei Herunterfahren des Systems beendet werden kann
  /*
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if(e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }
  */
  

  public static void main(String[] args) {
    Tree09 frame = new Tree09();
    frame.setVisible(true);
 }  // main



}  // Tree09






class MyMouseAdapter extends MouseAdapter {
   private JTree jTree1;

  public MyMouseAdapter(JTree jTree1) {
     this.jTree1 = jTree1;
  }

   public void mouseClicked(MouseEvent e) {
      int selRow = jTree1.getRowForLocation(e.getX(), e.getY());
      TreePath selPath = jTree1.getPathForLocation(e.getX(), e.getY());
      if(selRow != -1) {
         if(e.getClickCount() == 1) {
             mySingleClick(selRow, selPath);
         }
         else if(e.getClickCount() == 2) {
             myDoubleClick(selRow, selPath);
         }
     }
  }

  void  mySingleClick(int selRow, TreePath selPath) {
    System.out.println("mySingleClick: "+selRow);
  }

  void  myDoubleClick(int selRow, TreePath selPath) {
    System.out.println("myDoubleClick: "+selRow);
  }
  
}  // MyMouseAdapter





// -----------------------------------------------------------------

   // Abgeleitete Klasse des JTree
   // verwendet ein eigenes Datenmodell
 class GenealogyTree extends JTree {
    GenealogyModel model;

       // 2. Aufruf des Konstruktors vom Hauptprogramm
    public GenealogyTree(Person graphNode) {
        // 3. Aufruf des Konstruktors des TreeModells
        super(new GenealogyModel(graphNode));
        getSelectionModel().setSelectionMode(
                TreeSelectionModel.SINGLE_TREE_SELECTION);
        DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
        Icon personIcon = null;
        renderer.setLeafIcon(personIcon);
        renderer.setClosedIcon(personIcon);
        renderer.setOpenIcon(personIcon);
        setCellRenderer(renderer);
    }

}




class Person {
    Person father;
    Person mother;
    Vector children;

    private String name;

    public Person(String name) {
        this.name = name;
        mother = father = null;
        children = new Vector();
    }

    /**
    *   Link together all members of a family.
    *
    *   @param pa the father
    *   @param ma the mother
    *   @param kids the children
    */
    public static void linkFamily(Person pa, Person ma, Person[] kids) {
        int len = kids.length;
        Person kid = null;
        for (int i = 0; i < len; i++) {
            kid = kids[i];
            pa.children.addElement(kid);
            ma.children.addElement(kid);
            kid.father = pa;
            kid.mother = ma;
        }
    }

/// getter methods ///////////////////////////////////

    public String toString() {
      return name;
    }

    public String getName() {
      return name;
    }

    public Person getFather() {
      return father;
    }

    public Person getMother() {
      return mother;
    }

    //  8.  hole die Anzahl der Kinder
    public int getChildCount() {
      return children.size();
    }

    public Person getChildAt(int i) {
        return (Person)children.elementAt(i);
    }
    public int getIndexOfChild(Person kid) {
        return children.indexOf(kid);
    }
}



class GenealogyModel implements TreeModel {
    private boolean showAncestors;
    private Vector treeModelListeners = new Vector();
    private Person rootPerson;

     // 4. Aufruf des Konstruktors des TreeModells
    public GenealogyModel(Person root) {
        showAncestors = false;
        rootPerson = root;
    }



//////////////// Fire events //////////////////////////////////////////////

    /**
     * The only event raised by this model is TreeStructureChanged with the
     * root as path, i.e. the whole tree has changed.
     */
    protected void fireTreeStructureChanged(Person oldRoot) {
        int len = treeModelListeners.size();
        TreeModelEvent e = new TreeModelEvent(this,
                                              new Object[] {oldRoot});
        for (int i = 0; i < len; i++) {
            ((TreeModelListener)treeModelListeners.elementAt(i)).
                    treeStructureChanged(e);
        }
    }


//////////////// TreeModel interface implementation ///////////////////////


    /**
     * Adds a listener for the TreeModelEvent posted after the tree changes.
     */
     // 5. Eintragen des Listeners
    public void addTreeModelListener(TreeModelListener l) {
        treeModelListeners.addElement(l);
    }

    /**
     * Returns the child of parent at index index in the parent's child array.
     */
    public Object getChild(Object parent, int index) {
        Person p = (Person)parent;
        System.out.println("getChild: "+p.getName()+"  Kind: "+p.getChildAt(index) );
        if (showAncestors) {
            if ((index > 0) && (p.getFather() != null)) {
                return p.getMother();
            }
            return p.getFather();
        }
        return p.getChildAt(index);
    }


    /**
     * Returns the index of child in parent.
     */
    public int getIndexOfChild(Object parent, Object child) {
        Person p = (Person)parent;
        if (showAncestors) {
            int count = 0;
            Person father = p.getFather();
            if (father != null) {
                count++;
                if (father == child) {
                    return 0;
                }
            }
            if (p.getMother() != child) {
                return count;
            }
            return -1;
        }
        return p.getIndexOfChild((Person)child);
    }

    /**
     * Returns the root of the tree.
     */
    //  6.  getRoot, Aufruf vom JTree
    public Object getRoot() {
        return rootPerson;
    }

    /**
     * Returns true if node is a leaf.
     */
    //  7.  ist der aktuelle Knoten ein Blatt ?
    public boolean isLeaf(Object node) {
        Person p = (Person)node;
        System.out.println("isLeaf: "+p.getName() );
        if (showAncestors) {
            return ((p.getFather() == null)
                 && (p.getMother() == null));
        }
         //  8.  hole die Anzahl der Kinder
        return p.getChildCount() == 0;
    }

    /**
     * Returns the number of children of parent.
     */
     //  8.  hole die Anzahl der Kinder
    public int getChildCount(Object parent) {
        Person p = (Person)parent;
        System.out.println("getChildCount: "+p.getName()+"   Count: "+p.getChildCount() );
        if (showAncestors) {
            int count = 0;
            if (p.getFather() != null) {
                count++;
            }
            if (p.getMother() != null) {
                count++;
            }
            return count;
        }
        return p.getChildCount();
    }



    /**
     * Removes a listener previously added with addTreeModelListener().
     */
    public void removeTreeModelListener(TreeModelListener l) {
        treeModelListeners.removeElement(l);
    }

    /**
     * Messaged when the user has altered the value for the item
     * identified by path to newValue.  Not used by this model.
     */
    public void valueForPathChanged(TreePath path, Object newValue) {
        System.out.println("*** valueForPathChanged : " + path + " --> " + newValue);
    }
}


