Listing 16.1  JTree Displaying Its Nodes and Leaves (TJTree.java)
// Demonstrates how to create the Swing tree widget to
// represent hierarchical data.

/*
 * <Applet code = TJTree width = 350 height = 300>
 * </Applet>
 */

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

public class TJTree extends JApplet {
    Container container;

    public void init() {
        // 1. Get the handle on applet's content pane.
        container = this.getContentPane();

        // 2. Root node (col0 or root) of the tree.
        DefaultMutableTreeNode root =
            new DefaultMutableTreeNode("C:\\");

        // 3. Create the nodes in column 1.
        DefaultMutableTreeNode col11 =
            new DefaultMutableTreeNode("Docs");

        DefaultMutableTreeNode col12 =
            new DefaultMutableTreeNode("README");

        // 4. Add the nodes to the root.
        root.add(col11);
        root.add(col12);

        // 5. Create the nodes in column 2.
        DefaultMutableTreeNode col21 =
            new DefaultMutableTreeNode("API");
        DefaultMutableTreeNode col22 =
            new DefaultMutableTreeNode("index.html");

        // 6. Add the nodes to the node 1 in column 1.
        col11.add(col21);
        col11.add(col22);

        // 7. Create the nodes in column 3.
        DefaultMutableTreeNode col31 =
            new DefaultMutableTreeNode("Swing");

        // 8. Add the node to the node 2 in column 2.
        col21.add(col31);

        // 9. Create the nodes in column 4.
        DefaultMutableTreeNode col41 =
            new DefaultMutableTreeNode("JComponent.html");
        DefaultMutableTreeNode col42 =
            new DefaultMutableTreeNode("JButton.html");
        DefaultMutableTreeNode col43 =
            new DefaultMutableTreeNode("JLabel.html");

        // 10. Add the nodes to the node called Swing.
        col31.add(col41);
        col31.add(col42);
        col31.add(col43);

        // 11. Attach the root (of nodes) to the tree object.
        JTree tree = new JTree(root);

        // 12. Add the tree to a scroll pane and add the scroll pane
        // to the container.
        JScrollPane scrollPane = new JScrollPane(tree);
        container.add(scrollPane);
    }
}

Listing 16.2  JTree Displaying the File System Hierarchy Using the Custom Tree Model (TTreeModel.java)
// Demonstrates how to use custom data models in trees.

import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.*;

public class TTreeModel extends JFrame {
    public TTreeModel() {
        super("TTreeModel"); // Give a title to the frame

        // 1. Create an object of FileSystemModel, and create a tree
        // with that model. Add the tree to a scroll pane, and add
        // the scroll pane to the frame.
        FileSystemModel fileSystemDataModel = new FileSystemModel();
        JTree tree = new JTree(fileSystemDataModel);
        JScrollPane scrollPane = new JScrollPane(tree);
        getContentPane().add(scrollPane);

        // 2. Configure the frame and display it.
        addWindowListener(new WindowEventHandler());
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);        
        setSize(300, 250);
        show();
    }

    // 3. The main method.
    public static void main(String [] args) {
        TTreeModel frame = new TTreeModel();    
    }
    
    // 4. Define a listener class to close the frame.
    class WindowEventHandler extends WindowAdapter {
        public void windowClosing(WindowEvent evt) {
            System.exit(0);
        }
    }   
}

// 5. Custom data model that represents the file system data.
class FileSystemModel implements TreeModel {    
    private String root;   // The root identifier
    private Vector listeners; // Declare the listeners vector
    
    public FileSystemModel() {
        // 6. Get the home directory on your system.
        root = System.getProperty("user.home");

        // 7. For Windows 95, root is set to C:\ ("usr.home"
        // retrieves C:\WIN95).
        // You may implement a snippet like this for other OS also
        // like Windows NT, Macintosh, and so on.
        if (System.getProperty("os.name").equals("Windows 95")) {
            File tempFile = new File(root);
            root = tempFile.getParent();
        }

        // 8. Define the listeners vector.
        listeners = new Vector();
    }

    // 9. Retrieves the root of the tree hierarchy.
    public Object getRoot() {
        return (new File(root));
    }

    // 10. Retrieves the members in a directory based on an index.
    public Object getChild(Object parent, int index) {
        File directory = (File) parent;
        String[] directoryMembers = directory.list(); 
        return (new File(directory, directoryMembers[index]));
    }

    // 11. Retrieves the member count in a directory.
    public int getChildCount(Object parent) {
        File fileSystemMember = (File) parent;
             // fileSystemMember is a directory or file.

        // If a file system member is a directory.
        if (fileSystemMember.isDirectory()) {
            String[] directoryMembers = fileSystemMember.list();

            // Get the count of members in the directory.
            return directoryMembers.length;
        }

        // If the file system member is a file.
        else {
            // Return the member count as zero.
            return 0;
        }
    }

    // 12. Returns the index of a given member in its directory.
    public int getIndexOfChild(Object parent, Object child) {
        File directory = (File) parent;
        File directoryMember = (File) child;
        String[] directoryMemberNames = directory.list();
        int result = -1;

        for (int i = 0; i<directoryMemberNames.length; ++i) {
            if ( directoryMember.getName().equals(
                                 directoryMemberNames[i] ) ) {
                result = i;
                break;
            }
        }
        // If no member with such name in the directory.
        return result;
    }

    // 13. Indicates whether a directory member is a tree leaf.
    public boolean isLeaf(Object node) {
         return ((File) node).isFile();
    }

    // 14. Method to add a tree model listener.
    public void addTreeModelListener(TreeModelListener l) {
        if (l != null && !listeners.contains(l)) {
            listeners.addElement(l);
        }
    }

    // 15. Method to remove a tree model listener.
    public void removeTreeModelListener(TreeModelListener l) {
        if (l != null) {
            listeners.removeElement(l);
        }
    }

    // A dumb method.
    public void valueForPathChanged(TreePath path, Object newValue) {
        // Does Nothing!
    }

    // 16. Additional methods that fire events whenever the model is
    // subjected to change. Possible changes can be nodes
    // inserted, nodes removed, structure changed, and so on.
    public void fireTreeNodesInserted(TreeModelEvent e) {
        Enumeration listenerCount = listeners.elements();
        while (listenerCount.hasMoreElements()) {
            TreeModelListener listener =
                (TreeModelListener) listenerCount.nextElement();
            listener.treeNodesInserted(e);
        }
    }

    public void fireTreeNodesRemoved(TreeModelEvent e) {
        Enumeration listenerCount = listeners.elements();
        while (listenerCount.hasMoreElements()) {
            TreeModelListener listener =
                (TreeModelListener) listenerCount.nextElement();
            listener.treeNodesRemoved(e);
        }

    }

    public void fireTreeNodesChanged(TreeModelEvent e) {
        Enumeration listenerCount = listeners.elements();
        while (listenerCount.hasMoreElements()) {
            TreeModelListener listener =
                (TreeModelListener) listenerCount.nextElement();
            listener.treeNodesChanged(e);
        }

    }

    public void fireTreeStructureChanged(TreeModelEvent e) {
        Enumeration listenerCount = listeners.elements();
        while (listenerCount.hasMoreElements()) {
            TreeModelListener listener =
                (TreeModelListener) listenerCount.nextElement();
            listener.treeStructureChanged(e);
        }

    }    
}

Listing 16.3  JTree Node Selections to Display a Document in an Editor Pane (TTreeSelectionEvent.java)
// Demonstrates the tree selection events and listeners.
import javax.swing.*;import javax.swing.tree.*;import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;

public class TTreeSelectionEvent extends JFrame {
    Container container;
    DefaultMutableTreeNode root;
    JScrollPane treeScrollPane;
    JScrollPane editorScrollPane;
    JEditorPane editorPane;

    public TTreeSelectionEvent() {
        // 1. Get the handle on applet's content pane and
        // create the tree nodes
        super("TTreeSelectionEvent");
        container = this.getContentPane();
        createTreeNodes();

        // 2. Attach the root of the nodes to the tree object
        // and set the tree to the SINGLE SELECTION mode.
        // Also, register a tree selection listener with the
        // tree object to listen to the respective events fired.
        JTree tree = new JTree(root);
        tree.getSelectionModel().setSelectionMode(
            TreeSelectionModel.SINGLE_TREE_SELECTION);
        tree.addTreeSelectionListener(new SelectionListener());

        // 3. Create scroll panes to display the tree, and the
        // editor component. Add the scroll panes to a split pane.
        // Add the split pane to the applet
        treeScrollPane = new JScrollPane(tree);

        editorPane = new JEditorPane();
        editorScrollPane = new JScrollPane(editorPane);
        JSplitPane splitPane = new JSplitPane(
                                    JSplitPane.HORIZONTAL_SPLIT,
                                    true,    // Continuous Layout
                                    treeScrollPane,
                                    editorScrollPane);
        // 4. Add the split pane to the frame.
        container.add(splitPane);

        // 5. Add the window closing listener.
        addWindowListener(new WindowEventHandler());

        // 6. Configure the frame.
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        setSize(350, 250);
        show();
    }

    // 7. Method that creates the tree nodes.
    public void createTreeNodes() {
        // 8. Root node (col0 (col-zero) or root) of the tree.
        root = new DefaultMutableTreeNode("C:\\");

        // 9. Create the nodes in column 1.
        //    and add them to the root
        DefaultMutableTreeNode col11 =
            new DefaultMutableTreeNode("JavaProg");
        root.add(col11);

        // 10. Create the nodes in column 2.
        DefaultMutableTreeNode col21 =
            new DefaultMutableTreeNode("Swing");

        // 11. Add the node to the node 2 in column 2.
        col11.add(col21);

        // 12. Create the nodes in column 3.
        DefaultMutableTreeNode col31 =
            new DefaultMutableTreeNode("JComponent.html");
        DefaultMutableTreeNode col32 =
            new DefaultMutableTreeNode("JButton.html");
        DefaultMutableTreeNode col33 =
            new DefaultMutableTreeNode("JLabel.html");

        // 13. Add the nodes to the node called Swing.
        col21.add(col31);
        col21.add(col32);
        col21.add(col33);
    }

    // 14. Define the tree selection listener.
    class SelectionListener implements TreeSelectionListener {
        URL url;

        // 15. Method that needs to be implemented.
        public void valueChanged(TreeSelectionEvent se) {
            // Obtain the source.
            JTree tree = (JTree) se.getSource(); 
            // Obtain the selected node.
            DefaultMutableTreeNode selectedNode =
                (DefaultMutableTreeNode)
                     tree.getLastSelectedPathComponent();
            // Obtain the selected node name.
            String selectedNodeName = selectedNode.toString();
            
            // If the node is a leaf, obtain its URL string.
            if (selectedNode.isLeaf()) {
            String urlString = "file:" +
                               System.getProperty("user.dir") +
                               System.getProperty("file.separator") +
                               selectedNodeName;
            System.out.println(urlString);

            try { 
                // Create URL object.           
                url = new URL(urlString);
            } catch(MalformedURLException urlex) {
                System.out.println(�Marlformed URL Exception.�);
            }

            try {
                 // Display the resource at the specified URL.
                 editorPane.setPage(url);
            } catch(IOException ex) {
                 System.out.println("The selected file was not found.");
                 System.out.println(ex);
            }
            } 
        }
    }
    // 16. Event handler for window closing.
    class WindowEventHandler extends WindowAdapter {
        public void windowClosing(WindowEvent evt) {
            System.exit(0);
        }
    }
    // 17. The main method.
    public static void main(String[] args) {
        TTreeSelectionEvent frame = new TTreeSelectionEvent();        
    }
}              

Listing 16.4  DefaultTreeCellRenderer Example (TTreeCellRenderer.java)
// Demonstrates how to customize the display of
// the tree nodes (or leaves).

/*
 * <Applet code = TTreeCellRenderer width = 350 height = 300>
 * </Applet>
 */

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

public class TTreeCellRenderer extends JApplet {
    Container container;

    public void init() {
        // 1. Get the handle on applet's content pane.
        container = this.getContentPane();

        // 2. Root node (col0 or root) of the tree.
        DefaultMutableTreeNode root =
            new DefaultMutableTreeNode("C:\\");

        // 3. Create the nodes in column 1.
        DefaultMutableTreeNode col11 =
            new DefaultMutableTreeNode("Docs");

        DefaultMutableTreeNode col12 =
            new DefaultMutableTreeNode("Others");


        // 4. Add the nodes to the root.
        root.add(col11);
        root.add(col12);

        // 5. Create the nodes in column 2.
        DefaultMutableTreeNode col21 =
            new DefaultMutableTreeNode("API");

        DefaultMutableTreeNode col22 =
            new DefaultMutableTreeNode("Bla...");


        // 6. Add these nodes to node 1 in column 1.
        col11.add(col21);
        col12.add(col22);

        // 7. Create the nodes in column 3.
        DefaultMutableTreeNode col31 =
            new DefaultMutableTreeNode("Swing");

        // 8. Add the node to node 2 in column 2.
        col21.add(col31);

        // 9. Create the nodes in column 4.
        DefaultMutableTreeNode col41 =
            new DefaultMutableTreeNode("JComponent.html");
        DefaultMutableTreeNode col42 =
            new DefaultMutableTreeNode("JButton.html");
        DefaultMutableTreeNode col43 =
            new DefaultMutableTreeNode("JLabel.html");

        // 10. Add the nodes to the node called Swing.
        col31.add(col41);
        col31.add(col42);
        col31.add(col43);

        // 11. Attach the root (of nodes) to the tree object.
        JTree tree = new JTree(root);

        // 12. Get the reference to the existing (default) renderer.
        DefaultTreeCellRenderer renderer =
            (DefaultTreeCellRenderer) tree.getCellRenderer();

        // 13. Prepare the cell height for the new icons.
        tree.setRowHeight(30); // 30 pixels

        // 14. Attach the new icons for the leaves nodes when opened,
        // and nodes when closed.
        renderer.setLeafIcon(new ImageIcon("leafIcon.gif"));
        renderer.setOpenIcon(new ImageIcon("fileOpen.gif"));
        renderer.setClosedIcon(new ImageIcon("fileClosed.gif"));

        // 15. Customize the text colors.
        renderer.setFont(new Font("Monospaced", // font name
                                  Font.BOLD|Font.ITALIC, // font type
                                  15)); // Font size.
        renderer.setTextNonSelectionColor(Color.blue);
        renderer.setTextSelectionColor(Color.white);

        // 16. Customize the background of the tree node-cells.
        renderer.setBackgroundNonSelectionColor(Color.white);
        renderer.setBackgroundSelectionColor(Color.gray);
        renderer.setBorderSelectionColor(Color.lightGray);

        // 17. Finally, add the tree to a scroll pane and the scroll pane
        // to the container.
        JScrollPane scrollPane = new JScrollPane(tree);
        container.add(scrollPane);
    }
}