Java/Swing JFC/Tree Model

Материал из Java эксперт
Перейти к: навигация, поиск

A tree model using the SortTreeModel with a File hierarchy as input

 
/*
Java Swing, 2nd Edition
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
ISBN: 0-596-00408-7
Publisher: O"Reilly 
*/
// SortTreeDemo.java
//This class creates a tree model using the SortTreeModel with
//a File hierarchy as input.
//
import java.io.File;
import java.util.ruparator;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
public class SortTreeDemo extends JFrame {
  public SortTreeDemo(String startDir) {
    super("SortTreeModel Demonstration");
    setSize(300, 400);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    PrettyFile f = new PrettyFile(startDir);
    DefaultMutableTreeNode root = new DefaultMutableTreeNode(f);
    SortTreeModel model = new SortTreeModel(root,
        new TreeStringComparator());
    fillModel(model, root);
    JTree tree = new JTree(model);
    getContentPane().add(new JScrollPane(tree));
  }
  protected void fillModel(SortTreeModel model, DefaultMutableTreeNode current) {
    PrettyFile pf = (PrettyFile) current.getUserObject();
    File f = pf.getFile();
    if (f.isDirectory()) {
      String files[] = f.list();
      // ignore "." files
      for (int i = 0; i < files.length; i++) {
        if (files[i].startsWith("."))
          continue;
        PrettyFile tmp = new PrettyFile(pf, files[i]);
        DefaultMutableTreeNode node = new DefaultMutableTreeNode(tmp);
        model.insertNodeInto(node, current);
        if (tmp.getFile().isDirectory()) {
          fillModel(model, node);
        }
      }
    }
  }
  public class PrettyFile {
    File f;
    public PrettyFile(String s) {
      f = new File(s);
    }
    public PrettyFile(PrettyFile pf, String s) {
      f = new File(pf.f, s);
    }
    public File getFile() {
      return f;
    }
    public String toString() {
      return f.getName();
    }
  }
  public static void main(String args[]) {
    SortTreeDemo demo = new SortTreeDemo(args.length == 1 ? args[0] : ".");
    demo.setVisible(true);
  }
}
//SortTreeModel.java
//This class is similar to the DefaultTreeModel, but it keeps
//a node"s children in alphabetical order.
//
class SortTreeModel extends DefaultTreeModel {
  private Comparator comparator;
  public SortTreeModel(TreeNode node, Comparator c) {
    super(node);
    comparator = c;
  }
  public SortTreeModel(TreeNode node, boolean asksAllowsChildren, Comparator c) {
    super(node, asksAllowsChildren);
    comparator = c;
  }
  public void insertNodeInto(MutableTreeNode child, MutableTreeNode parent) {
    int index = findIndexFor(child, parent);
    super.insertNodeInto(child, parent, index);
  }
  public void insertNodeInto(MutableTreeNode child, MutableTreeNode par, int i) {
    // The index is useless in this model, so just ignore it.
    insertNodeInto(child, par);
  }
  // Perform a recursive binary search on the children to find the right
  // insertion point for the next node.
  private int findIndexFor(MutableTreeNode child, MutableTreeNode parent) {
    int cc = parent.getChildCount();
    if (cc == 0) {
      return 0;
    }
    if (cc == 1) {
      return comparator.rupare(child, parent.getChildAt(0)) <= 0 ? 0 : 1;
    }
    return findIndexFor(child, parent, 0, cc - 1); // First & last index
  }
  private int findIndexFor(MutableTreeNode child, MutableTreeNode parent,
      int i1, int i2) {
    if (i1 == i2) {
      return comparator.rupare(child, parent.getChildAt(i1)) <= 0 ? i1
          : i1 + 1;
    }
    int half = (i1 + i2) / 2;
    if (comparator.rupare(child, parent.getChildAt(half)) <= 0) {
      return findIndexFor(child, parent, i1, half);
    }
    return findIndexFor(child, parent, half + 1, i2);
  }
}
//TreeStringComparator.java
//This class compares the contents of the userObject as strings.
//It"s case-insensitive.
//
class TreeStringComparator implements Comparator {
  public int compare(Object o1, Object o2) {
    if (!(o1 instanceof DefaultMutableTreeNode && o2 instanceof DefaultMutableTreeNode)) {
      throw new IllegalArgumentException(
          "Can only compare DefaultMutableTreeNode objects");
    }
    String s1 = ((DefaultMutableTreeNode) o1).getUserObject().toString();
    String s2 = ((DefaultMutableTreeNode) o2).getUserObject().toString();
    return s1.rupareToIgnoreCase(s2);
  }
}





implements TreeModel to create tree model

 
/*
 * Copyright (c) 2000 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 2nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book (recommended),
 * visit http://www.davidflanagan.ru/javaexamples2.
 */
import java.awt.BorderLayout;
import java.awt.ruponent;
import java.awt.Container;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
/**
 * This class is a JTree subclass that displays the tree of AWT or Swing
 * component that make up a GUI.
 */
public class ComponentTree extends JTree {
  /**
   * All this constructor method has to do is set the TreeModel and
   * TreeCellRenderer objects for the tree. It is these classes (defined
   * below) that do all the real work.
   */
  public ComponentTree(Component c) {
    super(new ComponentTreeModel(c));
    setCellRenderer(new ComponentCellRenderer(getCellRenderer()));
  }
  /**
   * The TreeModel class puts hierarchical data in a form that the JTree can
   * display. This implementation interprets the containment hierarchy of a
   * Component for display by the ComponentTree class. Note that any kind of
   * Object can be a node in the tree, as long as the TreeModel knows how to
   * handle it.
   */
  static class ComponentTreeModel implements TreeModel {
    Component root; // The root object of the tree
    // Constructor: just remember the root object
    public ComponentTreeModel(Component root) {
      this.root = root;
    }
    // Return the root of the tree
    public Object getRoot() {
      return root;
    }
    // Is this node a leaf? (Leaf nodes are displayed differently by JTree)
    // Any node that isn"t a container is a leaf, since they cannot have
    // children. We also define containers with no children as leaves.
    public boolean isLeaf(Object node) {
      if (!(node instanceof Container))
        return true;
      Container c = (Container) node;
      return c.getComponentCount() == 0;
    }
    // How many children does this node have?
    public int getChildCount(Object node) {
      if (node instanceof Container) {
        Container c = (Container) node;
        return c.getComponentCount();
      }
      return 0;
    }
    // Return the specified child of a parent node.
    public Object getChild(Object parent, int index) {
      if (parent instanceof Container) {
        Container c = (Container) parent;
        return c.getComponent(index);
      }
      return null;
    }
    // Return the index of the child node in the parent node
    public int getIndexOfChild(Object parent, Object child) {
      if (!(parent instanceof Container))
        return -1;
      Container c = (Container) parent;
      Component[] children = c.getComponents();
      if (children == null)
        return -1;
      for (int i = 0; i < children.length; i++) {
        if (children[i] == child)
          return i;
      }
      return -1;
    }
    // This method is only required for editable trees, so it is not
    // implemented here.
    public void valueForPathChanged(TreePath path, Object newvalue) {
    }
    // This TreeModel never fires any events (since it is not editable)
    // so event listener registration methods are left unimplemented
    public void addTreeModelListener(TreeModelListener l) {
    }
    public void removeTreeModelListener(TreeModelListener l) {
    }
  }
  /**
   * A TreeCellRenderer displays each node of a tree. The default renderer
   * displays arbitrary Object nodes by calling their toString() method. The
   * Component.toString() method returns long strings with extraneous
   * information. Therefore, we use this "wrapper" implementation of
   * TreeCellRenderer to convert nodes from Component objects to useful String
   * values before passing those String values on to the default renderer.
   */
  static class ComponentCellRenderer implements TreeCellRenderer {
    TreeCellRenderer renderer; // The renderer we are a wrapper for
    // Constructor: just remember the renderer
    public ComponentCellRenderer(TreeCellRenderer renderer) {
      this.renderer = renderer;
    }
    // This is the only TreeCellRenderer method.
    // Compute the string to display, and pass it to the wrapped renderer
    public Component getTreeCellRendererComponent(JTree tree, Object value,
        boolean selected, boolean expanded, boolean leaf, int row,
        boolean hasFocus) {
      String newvalue = value.getClass().getName(); // Component type
      String name = ((Component) value).getName(); // Component name
      if (name != null)
        newvalue += " (" + name + ")"; // unless null
      // Use the wrapped renderer object to do the real work
      return renderer.getTreeCellRendererComponent(tree, newvalue,
          selected, expanded, leaf, row, hasFocus);
    }
  }
  /**
   * This main() method demonstrates the use of the ComponentTree class: it
   * puts a ComponentTree component in a Frame, and uses the ComponentTree to
   * display its own GUI hierarchy. It also adds a TreeSelectionListener to
   * display additional information about each component as it is selected
   */
  public static void main(String[] args) {
    // Create a frame for the demo, and handle window close requests
    JFrame frame = new JFrame("ComponentTree Demo");
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    // Create a scroll pane and a "message line" and add them to the
    // center and bottom of the frame.
    JScrollPane scrollpane = new JScrollPane();
    final JLabel msgline = new JLabel(" ");
    frame.getContentPane().add(scrollpane, BorderLayout.CENTER);
    frame.getContentPane().add(msgline, BorderLayout.SOUTH);
    // Now create the ComponentTree object, specifying the frame as the
    // component whose tree is to be displayed. Also set the tree"s font.
    JTree tree = new ComponentTree(frame);
    tree.setFont(new Font("SansSerif", Font.BOLD, 12));
    // Only allow a single item in the tree to be selected at once
    tree.getSelectionModel().setSelectionMode(
        TreeSelectionModel.SINGLE_TREE_SELECTION);
    // Add an event listener for notifications when
    // the tree selection state changes.
    tree.addTreeSelectionListener(new TreeSelectionListener() {
      public void valueChanged(TreeSelectionEvent e) {
        // Tree selections are referred to by "path"
        // We only care about the last node in the path
        TreePath path = e.getPath();
        Component c = (Component) path.getLastPathComponent();
        // Now we know what component was selected, so
        // display some information about it in the message line
        if (c.isShowing()) {
          Point p = c.getLocationOnScreen();
          msgline.setText("x: " + p.x + "  y: " + p.y + "  width: "
              + c.getWidth() + "  height: " + c.getHeight());
        } else {
          msgline.setText("component is not showing");
        }
      }
    });
    // Now that we"ve set up the tree, add it to the scrollpane
    scrollpane.setViewportView(tree);
    // Finally, set the size of the main window, and pop it up.
    frame.setSize(600, 400);
    frame.setVisible(true);
  }
}





implements TreeModel to display File in a Tree

 
/*
 * This example is from the book "Java Foundation Classes in a Nutshell".
 * Written by David Flanagan. Copyright (c) 1999 by O"Reilly & Associates.  
 * You may distribute this source code for non-commercial purposes only.
 * You may study, modify, and use this example for any purpose, as long as
 * this notice is retained.  Note that this example is provided "as is",
 * WITHOUT WARRANTY of any kind either expressed or implied.
 */
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import java.io.File;
public class FileTreeDemo {
  public static void main(String[] args) {
    // Figure out where in the filesystem to start displaying
    File root;
    if (args.length > 0) root = new File(args[0]);
    else root = new File(System.getProperty("user.home"));
    // Create a TreeModel object to represent our tree of files
    FileTreeModel model = new FileTreeModel(root);
    // Create a JTree and tell it to display our model
    JTree tree = new JTree();
    tree.setModel(model);
    // The JTree can get big, so allow it to scroll.
    JScrollPane scrollpane = new JScrollPane(tree);
    
    // Display it all in a window and make the window appear
    JFrame frame = new JFrame("FileTreeDemo");
    frame.getContentPane().add(scrollpane, "Center");
    frame.setSize(400,600);
    frame.setVisible(true);
  }
}
/**
 * The methods in this class allow the JTree component to traverse
 * the file system tree, and display the files and directories.
 **/
class FileTreeModel implements TreeModel {
  // We specify the root directory when we create the model.
  protected File root;
  public FileTreeModel(File root) { this.root = root; }
  // The model knows how to return the root object of the tree
  public Object getRoot() { return root; }
  // Tell JTree whether an object in the tree is a leaf or not
  public boolean isLeaf(Object node) {  return ((File)node).isFile(); }
  // Tell JTree how many children a node has
  public int getChildCount(Object parent) {
    String[] children = ((File)parent).list();
    if (children == null) return 0;
    return children.length;
  }
  // Fetch any numbered child of a node for the JTree.
  // Our model returns File objects for all nodes in the tree.  The
  // JTree displays these by calling the File.toString() method.
  public Object getChild(Object parent, int index) {
    String[] children = ((File)parent).list();
    if ((children == null) || (index >= children.length)) return null;
    return new File((File) parent, children[index]);
  }
  // Figure out a child"s position in its parent node.
  public int getIndexOfChild(Object parent, Object child) {
    String[] children = ((File)parent).list();
    if (children == null) return -1;
    String childname = ((File)child).getName();
    for(int i = 0; i < children.length; i++) {
      if (childname.equals(children[i])) return i;
    }
    return -1;
  }
  // This method is only invoked by the JTree for editable trees.  
  // This TreeModel does not allow editing, so we do not implement 
  // this method.  The JTree editable property is false by default.
  public void valueForPathChanged(TreePath path, Object newvalue) {}
  // Since this is not an editable tree model, we never fire any events,
  // so we don"t actually have to keep track of interested listeners.
  public void addTreeModelListener(TreeModelListener l) {}
  public void removeTreeModelListener(TreeModelListener l) {}
}





Insert tree node

 
/*
 * Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002.
 * All rights reserved. Software written by Ian F. Darwin and others.
 * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS""
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee
 * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s,
 * pioneering role in inventing and promulgating (and standardizing) the Java 
 * language and environment is gratefully acknowledged.
 * 
 * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
 * inventing predecessor languages C and C++ is also gratefully acknowledged.
 */
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
/**
 * Simple JFC JTree demo
 * 
 * @version $Id: JTreeDemo.java,v 1.4 2002/08/25 01:31:29 ian Exp $
 */
public class JTreeDemo extends JFrame {
  JButton addButton, quitButton;
  JTree myTree;
  DefaultMutableTreeNode root, child;
  /** "main program" method - construct and show */
  public static void main(String[] av) {
    // create a JTreeDemo object, tell it to show up
    new JTreeDemo().setVisible(true);
  }
  /** Construct the object including its GUI */
  public JTreeDemo() {
    super("JTreeDemo");
    Container cp = getContentPane();
    cp.setLayout(new BorderLayout());
    root = new DefaultMutableTreeNode("root");
    child = new DefaultMutableTreeNode("Colors");
    root.add(child);
    child.add(new DefaultMutableTreeNode("Cyan"));
    child.add(new DefaultMutableTreeNode("Magenta"));
    child.add(new DefaultMutableTreeNode("Yellow"));
    child.add(new DefaultMutableTreeNode("Black"));
    myTree = new JTree(root);
    // cp.add(BorderLayout.CENTER, myTree);
    //JScrollPane scroller = new JScrollPane();
    //scroller.getViewport().add(myTree);
    JScrollPane scroller = new JScrollPane(myTree);
    cp.add(BorderLayout.CENTER, scroller);
    cp.add(BorderLayout.NORTH, addButton = new JButton("Add"));
    addButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        // Insert more nodes into the tree
        child = new DefaultMutableTreeNode("Flavors");
        child.add(new DefaultMutableTreeNode("Java"));
        child.add(new DefaultMutableTreeNode("Espresso"));
        child.add(new DefaultMutableTreeNode("Hey Joe!"));
        child.add(new DefaultMutableTreeNode("Charcoal"));
        child.add(new DefaultMutableTreeNode("Paint Remover"));
        // Notify the model, which will add it and create an event, and
        // send it up the tree...
        ((DefaultTreeModel) myTree.getModel()).insertNodeInto(child,
            root, 0);
      }
    });
    cp.add(BorderLayout.SOUTH, quitButton = new JButton("Exit"));
    quitButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        setVisible(false);
        dispose();
        System.exit(0);
      }
    });
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        setVisible(false);
        dispose();
        System.exit(0);
      }
    });
    pack();
  }
}





JTree application, showing default tree contents

 
/*
 * Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002.
 * All rights reserved. Software written by Ian F. Darwin and others.
 * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS""
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee
 * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s,
 * pioneering role in inventing and promulgating (and standardizing) the Java 
 * language and environment is gratefully acknowledged.
 * 
 * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for
 * inventing predecessor languages C and C++ is also gratefully acknowledged.
 */
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
/**
 * Simple JFC JTree Simple application, showing default tree contents. Note that
 * the JTree will display a silly demo with not Model provided.
 * 
 * @version $Id: JTreeSimple.java,v 1.2 2004/02/23 03:39:22 ian Exp $
 */
public class JTreeSimple extends JFrame {
  JButton addButton, quitButton;
  JTree myTree;
  /** "main program" method - construct and show */
  public static void main(String[] av) {
    // create a JTreeSimple object, tell it to show up
    new JTreeSimple().setVisible(true);
  }
  /** Construct the object including its GUI */
  public JTreeSimple() {
    super("JTreeSimple");
    Container cp = getContentPane();
    cp.setLayout(new BorderLayout());
    myTree = new JTree();
    JScrollPane scroller = new JScrollPane(myTree);
    cp.add(BorderLayout.CENTER, scroller);
    cp.add(BorderLayout.SOUTH, quitButton = new JButton("Exit"));
    quitButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        setVisible(false);
        dispose();
        System.exit(0);
      }
    });
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    pack();
  }
}





TreeModel Support

  
/*
 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 * 
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 * - Redistribution in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following
 *   disclaimer in the documentation and/or other materials
 *   provided with the distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of
 * contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any
 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
 * EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY
 * DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR
 * RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE OR
 * ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE
 * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT,
 * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF
 * THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that this software is not designed, licensed or
 * intended for use in the design, construction, operation or
 * maintenance of any nuclear facility.
 */

import javax.swing.event.EventListenerList;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeModelEvent;
import javax.swing.tree.TreeModel;
/**
 * A Class that implements the listener registration and event fire methods for
 * a TreeModel. This class gets the implementation from DefaultTreeModel
 *
 * @version %I% %G%
 * @author  Mark Davidson
 */
public abstract class TreeModelSupport implements TreeModel {
    
    protected EventListenerList listenerList = new EventListenerList();
    /**
     * Adds a listener for the TreeModelEvent posted after the tree changes.
     *
     * @see     #removeTreeModelListener
     * @param   l       the listener to add
     */
    public void addTreeModelListener(TreeModelListener l) {
        listenerList.add(TreeModelListener.class, l);
    }
    /**
     * Removes a listener previously added with <B>addTreeModelListener()</B>.
     *
     * @see     #addTreeModelListener
     * @param   l       the listener to remove
     */
    public void removeTreeModelListener(TreeModelListener l) {
        listenerList.remove(TreeModelListener.class, l);
    }
    /*
     * Notify all listeners that have registered interest for
     * notification on this event type.  The event instance
     * is lazily created using the parameters passed into
     * the fire method.
     * @see EventListenerList
     */
    protected void fireTreeNodesChanged(Object source, Object[] path,
                                        int[] childIndices,
                                        Object[] children) {
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();
        TreeModelEvent e = null;
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length-2; i>=0; i-=2) {
            if (listeners[i]==TreeModelListener.class) {
                // Lazily create the event:
                if (e == null)
                    e = new TreeModelEvent(source, path,
                                           childIndices, children);
                ((TreeModelListener)listeners[i+1]).treeNodesChanged(e);
            }
        }
    }
    /*
     * Notify all listeners that have registered interest for
     * notification on this event type.  The event instance
     * is lazily created using the parameters passed into
     * the fire method.
     * @see EventListenerList
     */
    protected void fireTreeNodesInserted(Object source, Object[] path,
                                        int[] childIndices,
                                        Object[] children) {
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();
        TreeModelEvent e = null;
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length-2; i>=0; i-=2) {
            if (listeners[i]==TreeModelListener.class) {
                // Lazily create the event:
                if (e == null)
                    e = new TreeModelEvent(source, path,
                                           childIndices, children);
                ((TreeModelListener)listeners[i+1]).treeNodesInserted(e);
            }
        }
    }
    /*
     * Notify all listeners that have registered interest for
     * notification on this event type.  The event instance
     * is lazily created using the parameters passed into
     * the fire method.
     * @see EventListenerList
     */
    protected void fireTreeNodesRemoved(Object source, Object[] path,
                                        int[] childIndices,
                                        Object[] children) {
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();
        TreeModelEvent e = null;
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length-2; i>=0; i-=2) {
            if (listeners[i]==TreeModelListener.class) {
                // Lazily create the event:
                if (e == null)
                    e = new TreeModelEvent(source, path,
                                           childIndices, children);
                ((TreeModelListener)listeners[i+1]).treeNodesRemoved(e);
            }
        }
    }
    
    protected void fireTreeNodesRemoved(TreeModelEvent evt)  {
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length-2; i>=0; i-=2) {
            if (listeners[i]==TreeModelListener.class) {
                ((TreeModelListener)listeners[i+1]).treeStructureChanged(evt);
            }
        }
    }
    /*
     * Notify all listeners that have registered interest for
     * notification on this event type.  The event instance
     * is lazily created using the parameters passed into
     * the fire method.
     * @see EventListenerList
     */
    protected void fireTreeStructureChanged(Object source, Object[] path,
                                        int[] childIndices,
                                        Object[] children) {
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();
        TreeModelEvent e = null;
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length-2; i>=0; i-=2) {
            if (listeners[i]==TreeModelListener.class) {
                // Lazily create the event:
                if (e == null)
                    e = new TreeModelEvent(source, path,
                                           childIndices, children);
                ((TreeModelListener)listeners[i+1]).treeStructureChanged(e);
            }
        }
    }
}