import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;

/** DemoTree - demo of the <code>JTree</code> class.<p>
*
* A <code>JTree</code> is a useful interface component for displaying
* hierarchical data.  Like many other non-trivial Swing components,
* <code>JTree</code> doesn't contain any data; it simply
* provides a view of the data, presented as a tree.  The data are
* held in a data model, which may be passed as an argument to
* the tree's constructor.<p>
*
* The data are displayed vertically in rows.  Each row is 
* a <i>node</i>.  The top row is the <i>root</i> node.  Each
* <code>JTree</code> has precisely one root node, from which all other
* nodes descend.  A node may or may not contain other nodes, called
* <i>children</i>.  A node containing a child node is called
* a <i>branch</i> node.  A node that does not contain a child node is
* called a <i>leaf</i> node.<p>
*
* In this demo, we display all the symbols that can be generated directly
* from keys on a typical computer keyboard.  The symbols are organized
* hierarchically under the root node "Symbols" as three branch nodes
* named "Letters", "Digits", and "Punctuation".  Each branch node
* has a set of leaf nodes containing the symbols for that branch.<p>
*
* A key feature of <code>JTree</code> is the ability to collapse or expand
* branch nodes.  When collapsed only the node is visible.  When expanded,
* the child nodes are also visible.  Our demo tree is pre-loaded into a
* <code>JScrollPane</code> component.  Scrollbars automatically
* appear or disappear, as needed, as branch nodes are
* expanded or collapsed.<p>
*
* It is possible it install a listener
* that detects the collapsing and expanding of branch nodes
* (<code>TreeExpansionListener</code>), however this is not
* demonstrated here.<p>
*
* The most common listener for <code>JTree</code> is
* <code>TreeSelectionListener</code>, which generates an event
* each time a node is selected.  The event triggers
* a call to the listener's <code>valueChanged</code> method, passing
* a <code>TreeSelectionEvent</code> object as an argument.
* Our extended <code>JFrame</code>
* class (the application window) implements
* <code>TreeSelectionListener</code>.  In the <code>valueChanged</code>
* method we retrieve the node selected, and, if it is a leaf node,
* print its symbol on the console.<p>
*
* <b>Keyboard interaction</b>.
* The following are the Microsoft
* windows-style actions supported for <code>JTree</code>:<p>
*
* <pre>
*     JTree (Win32 L&F)
*     Navigate out forward                |  Tab
*     Navigate out backward               |  Shift+Tab
*     Expand entry                        |  Right
*     Collapse entry                      |  Left
*     Toggle expand/collapse for entry    |  Enter
*     Move up/down one entry              |  Up, Down
*     Move to first entry                 |  Home
*     Move to last visible entry          |  End
*     Block move vertical                 |  PgUp, PgDn
*     Block move left                     |  Ctrl+PgUp
*     Block move right                    |  Ctrl+PgDn
*     Block extend vertical               |  Shift+PgUp, Shift+PgDn
*     Select all                          |  Ctrl+A
*     Select all                          |  Ctrl+Slash
*     Deselect all                        |  Ctrl+\
*     Single select                       |  Ctrl+Spacebar
*     Range-select                        |  Shift+Spacebar
*     Extend selection up                 |  Shift+Up
*     Extend selection down               |  Shift+Down
*     Extend selection to start of data   |  Shift+Home
*     Extend selection to end of data     |  Shift+End
* </pre>
*
* For further details, consult the source code,
* the <code>JTree</code> API, and the Swing tutorial notes.
* <p>
*
* Screen snap (launch)...<br>
* <center><img src="DemoTree-1.gif"></center><p>
*
* Screen snap (with branch node expanded)...<br>
* <center><img src="DemoTree-2.gif"></center><p>
*
* @see <a href="DemoTree.java">source code</a>
* @author Scott MacKenzie, 2002
*/
public class DemoTree
{
   public static void main(String[] args)
   {
      // use look and feel for my system (Win32)
      try {
         UIManager.setLookAndFeel(
            UIManager.getSystemLookAndFeelClassName());
      } catch (Exception e) {}

      DemoTreeFrame frame = new DemoTreeFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setTitle("DemoTree");
      frame.pack();
      frame.show();
   }
}

class DemoTreeFrame extends JFrame implements TreeSelectionListener
{
   private JTree t;

   public DemoTreeFrame()
   {
      final String[] CATEGORIES = {
         "Letters",
         "Digits",
         "Punctuation"
      };

      final String[] SYMBOLS = {
         "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
         "0123456789",
         "~!@#$%^&*()_+`-={}|[]\\:\";'<>?,./"
      };

      // ----------------------------------
      // construct and configure components
      // ----------------------------------    

      DefaultMutableTreeNode top = new DefaultMutableTreeNode("Symbols");
      DefaultMutableTreeNode node;
      Character nodeSymbol;

      for (int i = 0; i < CATEGORIES.length; ++i)
      {
         top.add(new DefaultMutableTreeNode(CATEGORIES[i]));
         for (int j = 0; j < SYMBOLS[i].length(); ++j)
         {
            node = (DefaultMutableTreeNode)(top.getChildAt(i));
            nodeSymbol = new Character(SYMBOLS[i].charAt(j));
            node.add(new DefaultMutableTreeNode(nodeSymbol));
         }
      }

      // Create a JTree object, passing the data model as an argument
      // to the constructor.  (Note: The data model is represented
      // by the node at the top of the tree hierarchy.)

      t = new JTree(top);

      // Set the selection mode to "single" (only one node can be
      // selected at a time).

      TreeSelectionModel tsm = t.getSelectionModel();
      tsm.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

      // put the tree in a scroll pane to facilitate viewing

      JScrollPane sp = new JScrollPane(t);
      sp.setPreferredSize(new Dimension(150, 250));

      // -------------
      // add listeners
      // -------------

      t.addTreeSelectionListener(this);

      // ------------------
      // arrange components
      // ------------------

      JPanel p = new JPanel();
      p.add(sp);
      p.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

      this.setContentPane(p);
   }

   // --------------------------------------
   // implement TreeSelectionListener method
   // --------------------------------------

   public void valueChanged(TreeSelectionEvent tse)
   {
      // get the node that was selected   
      DefaultMutableTreeNode node =
         (DefaultMutableTreeNode)t.getLastSelectedPathComponent();

      // for this demo, we're only interested in leaf nodes
      if (!node.isLeaf())
         return;

      // get the symbol associated with the node and print it
      Object o = node.getUserObject();
      System.out.print(o);
   }
}

