1 /*
   2  * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.swing.event;
  27 
  28 import java.util.EventObject;
  29 import javax.swing.tree.TreePath;
  30 
  31 
  32 /**
  33  * Encapsulates information describing changes to a tree model, and
  34  * used to notify tree model listeners of the change.
  35  * For more information and examples see
  36  * <a
  37  href="http://java.sun.com/docs/books/tutorial/uiswing/events/treemodellistener.html">How to Write a Tree Model Listener</a>,
  38  * a section in <em>The Java Tutorial.</em>
  39  * <p>
  40  * <strong>Warning:</strong>
  41  * Serialized objects of this class will not be compatible with
  42  * future Swing releases. The current serialization support is
  43  * appropriate for short term storage or RMI between applications running
  44  * the same version of Swing.  As of 1.4, support for long term storage
  45  * of all JavaBeans<sup><font size="-2">TM</font></sup>
  46  * has been added to the <code>java.beans</code> package.
  47  * Please see {@link java.beans.XMLEncoder}.
  48  *
  49  * @author Rob Davis
  50  * @author Ray Ryan
  51  * @author Scott Violet
  52  */
  53 public class TreeModelEvent extends EventObject {
  54     /** Path to the parent of the nodes that have changed. */
  55     protected TreePath  path;
  56     /** Indices identifying the position of where the children were. */
  57     protected int[]     childIndices;
  58     /** Children that have been removed. */
  59     protected Object[]  children;
  60 
  61     /**
  62      * Used to create an event when nodes have been changed, inserted, or
  63      * removed, identifying the path to the parent of the modified items as
  64      * an array of Objects. All of the modified objects are siblings which are
  65      * direct descendents (not grandchildren) of the specified parent.
  66      * The positions at which the inserts, deletes, or changes occurred are
  67      * specified by an array of <code>int</code>. The indexes in that array
  68      * must be in order, from lowest to highest.
  69      * <p>
  70      * For changes, the indexes in the model correspond exactly to the indexes
  71      * of items currently displayed in the UI. As a result, it is not really
  72      * critical if the indexes are not in their exact order. But after multiple
  73      * inserts or deletes, the items currently in the UI no longer correspond
  74      * to the items in the model. It is therefore critical to specify the
  75      * indexes properly for inserts and deletes.
  76      * <p>
  77      * For inserts, the indexes represent the <i>final</i> state of the tree,
  78      * after the inserts have occurred. Since the indexes must be specified in
  79      * order, the most natural processing methodology is to do the inserts
  80      * starting at the lowest index and working towards the highest. Accumulate
  81      * a Vector of <code>Integer</code> objects that specify the
  82      * insert-locations as you go, then convert the Vector to an
  83      * array of <code>int</code> to create the event. When the postition-index
  84      * equals zero, the node is inserted at the beginning of the list. When the
  85      * position index equals the size of the list, the node is "inserted" at
  86      * (appended to) the end of the list.
  87      * <p>
  88      * For deletes, the indexes represent the <i>initial</i> state of the tree,
  89      * before the deletes have occurred. Since the indexes must be specified in
  90      * order, the most natural processing methodology is to use a delete-counter.
  91      * Start by initializing the counter to zero and start work through the
  92      * list from lowest to higest. Every time you do a delete, add the current
  93      * value of the delete-counter to the index-position where the delete occurred,
  94      * and append the result to a Vector of delete-locations, using
  95      * <code>addElement()</code>. Then increment the delete-counter. The index
  96      * positions stored in the Vector therefore reflect the effects of all previous
  97      * deletes, so they represent each object's position in the initial tree.
  98      * (You could also start at the highest index and working back towards the
  99      * lowest, accumulating a Vector of delete-locations as you go using the
 100      * <code>insertElementAt(Integer, 0)</code>.) However you produce the Vector
 101      * of initial-positions, you then need to convert the Vector of <code>Integer</code>
 102      * objects to an array of <code>int</code> to create the event.
 103      * <p>
 104      * <b>Notes:</b><ul>
 105      * <li>Like the <code>insertNodeInto</code> method in the
 106      *    <code>DefaultTreeModel</code> class, <code>insertElementAt</code>
 107      *    appends to the <code>Vector</code> when the index matches the size
 108      *    of the vector. So you can use <code>insertElementAt(Integer, 0)</code>
 109      *    even when the vector is empty.
 110      * <ul>To create a node changed event for the root node, specify the parent
 111      *     and the child indices as <code>null</code>.
 112      * </ul>
 113      *
 114      * @param source the Object responsible for generating the event (typically
 115      *               the creator of the event object passes <code>this</code>
 116      *               for its value)
 117      * @param path   an array of Object identifying the path to the
 118      *               parent of the modified item(s), where the first element
 119      *               of the array is the Object stored at the root node and
 120      *               the last element is the Object stored at the parent node
 121      * @param childIndices an array of <code>int</code> that specifies the
 122      *               index values of the removed items. The indices must be
 123      *               in sorted order, from lowest to highest
 124      * @param children an array of Object containing the inserted, removed, or
 125      *                 changed objects
 126      * @see TreePath
 127      */
 128     public TreeModelEvent(Object source, Object[] path, int[] childIndices,
 129                           Object[] children)
 130     {
 131         this(source, (path == null) ? null : new TreePath(path), childIndices, children);
 132     }
 133 
 134     /**
 135      * Used to create an event when nodes have been changed, inserted, or
 136      * removed, identifying the path to the parent of the modified items as
 137      * a TreePath object. For more information on how to specify the indexes
 138      * and objects, see
 139      * <code>TreeModelEvent(Object,Object[],int[],Object[])</code>.
 140      *
 141      * @param source the Object responsible for generating the event (typically
 142      *               the creator of the event object passes <code>this</code>
 143      *               for its value)
 144      * @param path   a TreePath object that identifies the path to the
 145      *               parent of the modified item(s)
 146      * @param childIndices an array of <code>int</code> that specifies the
 147      *               index values of the modified items
 148      * @param children an array of Object containing the inserted, removed, or
 149      *                 changed objects
 150      *
 151      * @see #TreeModelEvent(Object,Object[],int[],Object[])
 152      */
 153     public TreeModelEvent(Object source, TreePath path, int[] childIndices,
 154                           Object[] children)
 155     {
 156         super(source);
 157         this.path = path;
 158         this.childIndices = childIndices;
 159         this.children = children;
 160     }
 161 
 162     /**
 163      * Used to create an event when the node structure has changed in some way,
 164      * identifying the path to the root of a modified subtree as an array of
 165      * Objects. A structure change event might involve nodes swapping position,
 166      * for example, or it might encapsulate multiple inserts and deletes in the
 167      * subtree stemming from the node, where the changes may have taken place at
 168      * different levels of the subtree.
 169      * <blockquote>
 170      *   <b>Note:</b><br>
 171      *   JTree collapses all nodes under the specified node, so that only its
 172      *   immediate children are visible.
 173      * </blockquote>
 174      *
 175      * @param source the Object responsible for generating the event (typically
 176      *               the creator of the event object passes <code>this</code>
 177      *               for its value)
 178      * @param path   an array of Object identifying the path to the root of the
 179      *               modified subtree, where the first element of the array is
 180      *               the object stored at the root node and the last element
 181      *               is the object stored at the changed node
 182      * @see TreePath
 183      */
 184     public TreeModelEvent(Object source, Object[] path)
 185     {
 186         this(source, (path == null) ? null : new TreePath(path));
 187     }
 188 
 189     /**
 190      * Used to create an event when the node structure has changed in some way,
 191      * identifying the path to the root of the modified subtree as a TreePath
 192      * object. For more information on this event specification, see
 193      * <code>TreeModelEvent(Object,Object[])</code>.
 194      *
 195      * @param source the Object responsible for generating the event (typically
 196      *               the creator of the event object passes <code>this</code>
 197      *               for its value)
 198      * @param path   a TreePath object that identifies the path to the
 199      *               change. In the DefaultTreeModel,
 200      *               this object contains an array of user-data objects,
 201      *               but a subclass of TreePath could use some totally
 202      *               different mechanism -- for example, a node ID number
 203      *
 204      * @see #TreeModelEvent(Object,Object[])
 205      */
 206     public TreeModelEvent(Object source, TreePath path)
 207     {
 208         super(source);
 209         this.path = path;
 210         this.childIndices = new int[0];
 211     }
 212 
 213     /**
 214      * For all events, except treeStructureChanged,
 215      * returns the parent of the changed nodes.
 216      * For treeStructureChanged events, returns the ancestor of the
 217      * structure that has changed. This and
 218      * <code>getChildIndices</code> are used to get a list of the effected
 219      * nodes.
 220      * <p>
 221      * The one exception to this is a treeNodesChanged event that is to
 222      * identify the root, in which case this will return the root
 223      * and <code>getChildIndices</code> will return null.
 224      *
 225      * @return the TreePath used in identifying the changed nodes.
 226      * @see TreePath#getLastPathComponent
 227      */
 228     public TreePath getTreePath() { return path; }
 229 
 230     /**
 231      * Convenience method to get the array of objects from the TreePath
 232      * instance that this event wraps.
 233      *
 234      * @return an array of Objects, where the first Object is the one
 235      *         stored at the root and the last object is the one
 236      *         stored at the node identified by the path
 237      */
 238     public Object[] getPath() {
 239         if(path != null)
 240             return path.getPath();
 241         return null;
 242     }
 243 
 244     /**
 245      * Returns the objects that are children of the node identified by
 246      * <code>getPath</code> at the locations specified by
 247      * <code>getChildIndices</code>. If this is a removal event the
 248      * returned objects are no longer children of the parent node.
 249      *
 250      * @return an array of Object containing the children specified by
 251      *         the event
 252      * @see #getPath
 253      * @see #getChildIndices
 254      */
 255     public Object[] getChildren() {
 256         if(children != null) {
 257             int            cCount = children.length;
 258             Object[]       retChildren = new Object[cCount];
 259 
 260             System.arraycopy(children, 0, retChildren, 0, cCount);
 261             return retChildren;
 262         }
 263         return null;
 264     }
 265 
 266     /**
 267      * Returns the values of the child indexes. If this is a removal event
 268      * the indexes point to locations in the initial list where items
 269      * were removed. If it is an insert, the indices point to locations
 270      * in the final list where the items were added. For node changes,
 271      * the indices point to the locations of the modified nodes.
 272      *
 273      * @return an array of <code>int</code> containing index locations for
 274      *         the children specified by the event
 275      */
 276     public int[] getChildIndices() {
 277         if(childIndices != null) {
 278             int            cCount = childIndices.length;
 279             int[]          retArray = new int[cCount];
 280 
 281             System.arraycopy(childIndices, 0, retArray, 0, cCount);
 282             return retArray;
 283         }
 284         return null;
 285     }
 286 
 287     /**
 288      * Returns a string that displays and identifies this object's
 289      * properties.
 290      *
 291      * @return a String representation of this object
 292      */
 293     public String toString() {
 294         StringBuffer   retBuffer = new StringBuffer();
 295 
 296         retBuffer.append(getClass().getName() + " " +
 297                          Integer.toString(hashCode()));
 298         if(path != null)
 299             retBuffer.append(" path " + path);
 300         if(childIndices != null) {
 301             retBuffer.append(" indices [ ");
 302             for(int counter = 0; counter < childIndices.length; counter++)
 303                 retBuffer.append(Integer.toString(childIndices[counter])+ " ");
 304             retBuffer.append("]");
 305         }
 306         if(children != null) {
 307             retBuffer.append(" children [ ");
 308             for(int counter = 0; counter < children.length; counter++)
 309                 retBuffer.append(children[counter] + " ");
 310             retBuffer.append("]");
 311         }
 312         return retBuffer.toString();
 313     }
 314 }