1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
/* * @(#)TreePath.java 1.31 05/11/17 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package javax.swing.tree; import java.io.*; import java.util.Vector; /** * Represents a path to a node. A TreePath is an array of Objects that are * vended from a TreeModel. The elements of the array are ordered such * that the root is always the first element (index 0) of the array. * TreePath is Serializable, but if any * components of the path are not serializable, it will not be written * out. * <p> * For further information and examples of using tree paths, * see <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/tree.html">How to Use Trees</a> * in <em>The Java Tutorial.</em> * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans<sup><font size="-2">TM</font></sup> * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @version 1.31 11/17/05 * @author Scott Violet * @author Philip Milne */ public class TreePath extends Object implements Serializable { /** Path representing the parent, null if lastPathComponent represents * the root. */ private TreePath parentPath; /** Last path component. */ transient private Object lastPathComponent; /** * Constructs a path from an array of Objects, uniquely identifying * the path from the root of the tree to a specific node, as returned * by the tree's data model. * <p> * The model is free to return an array of any Objects it needs to * represent the path. The DefaultTreeModel returns an array of * TreeNode objects. The first TreeNode in the path is the root of the * tree, the last TreeNode is the node identified by the path. * * @param path an array of Objects representing the path to a node */ public TreePath(Object[] path) { if(path == null || path.length == 0) throw new IllegalArgumentException("path in TreePath must be non null and not empty."); lastPathComponent = path[path.length - 1]; if(path.length > 1) parentPath = new TreePath(path, path.length - 1); } /** * Constructs a TreePath containing only a single element. This is * usually used to construct a TreePath for the the root of the TreeModel. * <p> * @param singlePath an Object representing the path to a node * @see #TreePath(Object[]) */ public TreePath(Object singlePath) { if(singlePath == null) throw new IllegalArgumentException("path in TreePath must be non null."); lastPathComponent = singlePath; parentPath = null; } /** * Constructs a new TreePath, which is the path identified by * <code>parent</code> ending in <code>lastElement</code>. */ protected TreePath(TreePath parent, Object lastElement) { if(lastElement == null) throw new IllegalArgumentException("path in TreePath must be non null."); parentPath = parent; lastPathComponent = lastElement; } /** * Constructs a new TreePath with the identified path components of * length <code>length</code>. */ protected TreePath(Object[] path, int length) { lastPathComponent = path[length - 1]; if(length > 1) parentPath = new TreePath(path, length - 1); } /** * Primarily provided for subclasses * that represent paths in a different manner. * If a subclass uses this constructor, it should also override * the <code>getPath</code>, * <code>getPathCount</code>, and * <code>getPathComponent</code> methods, * and possibly the <code>equals</code> method. */ protected TreePath() { } /** * Returns an ordered array of Objects containing the components of this * TreePath. The first element (index 0) is the root. * * @return an array of Objects representing the TreePath * @see #TreePath(Object[]) */ public Object[] getPath() { int i = getPathCount(); Object[] result = new Object[i--]; for(TreePath path = this; path != null; path = path.parentPath) { result[i--] = path.lastPathComponent; } return result; } /** * Returns the last component of this path. For a path returned by * DefaultTreeModel this will return an instance of TreeNode. * * @return the Object at the end of the path * @see #TreePath(Object[]) */ public Object getLastPathComponent() { return lastPathComponent; } /** * Returns the number of elements in the path. * * @return an int giving a count of items the path */ public int getPathCount() { int result = 0; for(TreePath path = this; path != null; path = path.parentPath) { result++; } return result; } /** * Returns the path component at the specified index. * * @param element an int specifying an element in the path, where * 0 is the first element in the path * @return the Object at that index location * @throws IllegalArgumentException if the index is beyond the length * of the path * @see #TreePath(Object[]) */ public Object getPathComponent(int element) { int pathLength = getPathCount(); if(element < 0 || element >= pathLength) throw new IllegalArgumentException("Index " + element + " is out of the specified range"); TreePath path = this; for(int i = pathLength-1; i != element; i--) { path = path.parentPath; } return path.lastPathComponent; } /** * Tests two TreePaths for equality by checking each element of the * paths for equality. Two paths are considered equal if they are of * the same length, and contain * the same elements (<code>.equals</code>). * * @param o the Object to compare */ public boolean equals(Object o) { if(o == this) return true; if(o instanceof TreePath) { TreePath oTreePath = (TreePath)o; if(getPathCount() != oTreePath.getPathCount()) return false; for(TreePath path = this; path != null; path = path.parentPath) { if (!(path.lastPathComponent.equals (oTreePath.lastPathComponent))) { return false; } oTreePath = oTreePath.parentPath; } return true; } return false; } /** * Returns the hashCode for the object. The hash code of a TreePath * is defined to be the hash code of the last component in the path. * * @return the hashCode for the object */ public int hashCode() { return lastPathComponent.hashCode(); } /** * Returns true if <code>aTreePath</code> is a * descendant of this * TreePath. A TreePath P1 is a descendant of a TreePath P2 * if P1 contains all of the components that make up * P2's path. * For example, if this object has the path [a, b], * and <code>aTreePath</code> has the path [a, b, c], * then <code>aTreePath</code> is a descendant of this object. * However, if <code>aTreePath</code> has the path [a], * then it is not a descendant of this object. By this definition * a TreePath is always considered a descendant of itself. That is, * <code>aTreePath.isDescendant(aTreePath)</code> returns true. * * @return true if <code>aTreePath</code> is a descendant of this path */ public boolean isDescendant(TreePath aTreePath) { if(aTreePath == this) return true; if(aTreePath != null) { int pathLength = getPathCount(); int oPathLength = aTreePath.getPathCount(); if(oPathLength < pathLength) // Can't be a descendant, has fewer components in the path. return false; while(oPathLength-- > pathLength) aTreePath = aTreePath.getParentPath(); return equals(aTreePath); } return false; } /** * Returns a new path containing all the elements of this object * plus <code>child</code>. <code>child</code> will be the last element * of the newly created TreePath. * This will throw a NullPointerException * if child is null. */ public TreePath pathByAddingChild(Object child) { if(child == null) throw new NullPointerException("Null child not allowed"); return new TreePath(this, child); } /** * Returns a path containing all the elements of this object, except * the last path component. */ public TreePath getParentPath() { return parentPath; } /** * Returns a string that displays and identifies this * object's properties. * * @return a String representation of this object */ public String toString() { StringBuffer tempSpot = new StringBuffer("["); for(int counter = 0, maxCounter = getPathCount();counter < maxCounter; counter++) { if(counter > 0) tempSpot.append(", "); tempSpot.append(getPathComponent(counter)); } tempSpot.append("]"); return tempSpot.toString(); } // Serialization support. private void writeObject(ObjectOutputStream s) throws IOException { s.defaultWriteObject(); Vector values = new Vector(); boolean writePath = true; if(lastPathComponent != null && (lastPathComponent instanceof Serializable)) { values.addElement("lastPathComponent"); values.addElement(lastPathComponent); } s.writeObject(values); } private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); Vector values = (Vector)s.readObject(); int indexCounter = 0; int maxCounter = values.size(); if(indexCounter < maxCounter && values.elementAt(indexCounter). equals("lastPathComponent")) { lastPathComponent = values.elementAt(++indexCounter); indexCounter++; } } }