Frames | No Frames |
1: /* TreePath.java -- 2: Copyright (C) 2002, 2005, 2006, Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing.tree; 40: 41: import java.io.Serializable; 42: import java.util.Arrays; 43: 44: /** 45: * A <code>TreePath</code> represents a sequence of tree elements that form 46: * a path starting from the root of a tree. A tree element can be represented 47: * by any {@link Object}. 48: * 49: * @author Andrew Selkirk 50: */ 51: public class TreePath implements Serializable 52: { 53: static final long serialVersionUID = 4380036194768077479L; 54: 55: /** 56: * The actual patch. The {@link DefaultTreeSelectionModel#clone()} 57: * assumes that the TreePath is immutable, so it is marked final here. 58: */ 59: private final Object[] path; 60: 61: /** 62: * The parent path (to be reused). 63: */ 64: private transient TreePath parentPath; 65: 66: 67: /** 68: * Creates a path from the list of objects representing tree elements. The 69: * incoming array is copied so that subsequent changes do not affect this 70: * tree path. 71: * 72: * @param path the elements in the path (<code>null</code> not permitted). 73: * 74: * @throws IllegalArgumentException if <code>path</code> is <code>null</code>. 75: */ 76: public TreePath(Object[] path) 77: { 78: if (path == null) 79: throw new IllegalArgumentException("Null 'path' not permitted."); 80: this.path = new Object[path.length]; 81: System.arraycopy(path, 0, this.path, 0, path.length); 82: } 83: 84: /** 85: * Creates a new path from a single element. 86: * 87: * @param element the element (<code>null</code> not permitted). 88: * 89: * @throws IllegalArgumentException if <code>element</code> is 90: * <code>null</code>. 91: */ 92: public TreePath(Object element) 93: { 94: path = new Object[1]; 95: path[0] = element; 96: } 97: 98: /** 99: * Creates a new tree path by adding the specified <code>element</code> to 100: * the <code>path</code>. 101: * 102: * @param path a tree path. 103: * @param element a path element. 104: */ 105: protected TreePath(TreePath path, Object element) 106: { 107: if (element == null) 108: throw new NullPointerException("Null 'element' argument."); 109: Object[] treepath = path.getPath(); 110: 111: // Create Tree Path 112: this.path = new Object[treepath.length + 1]; 113: System.arraycopy(treepath, 0, this.path, 0, treepath.length); 114: this.path[treepath.length] = element; 115: } 116: 117: /** 118: * Creates a new tree path using the first <code>length</code> elements 119: * from the given array. 120: * 121: * @param path the path elements. 122: * @param length the path length. 123: */ 124: protected TreePath(Object[] path, int length) 125: { 126: // Create Path 127: this.path = new Object[length]; 128: System.arraycopy(path, 0, this.path, 0, length); 129: } 130: 131: /** 132: * Default constructor. 133: */ 134: protected TreePath() 135: { 136: path = new Object[0]; 137: } 138: 139: 140: /** 141: * Returns a hashcode for the path. 142: * 143: * @return A hashcode. 144: */ 145: public int hashCode() 146: { 147: return getLastPathComponent().hashCode(); 148: } 149: 150: /** 151: * Tests this path for equality with an arbitrary object. An object is 152: * considered equal to this path if and only if: 153: * <ul> 154: * <li>the object is not <code>null</code>;</li> 155: * <li>the object is an instanceof {@link TreePath};</li> 156: * <li>the object contains the same elements in the same order as this 157: * {@link TreePath};</li> 158: * </ul> 159: * 160: * @param object the object (<code>null</code> permitted). 161: * 162: * @return <code>true</code> if <code>obj</code> is equal to this tree path, 163: * and <code>false</code> otherwise. 164: */ 165: public boolean equals(Object object) 166: { 167: Object[] treepath; 168: int index; 169: 170: if (object instanceof TreePath) 171: { 172: treepath = ((TreePath) object).getPath(); 173: if (treepath.length != path.length) 174: return false; 175: for (index = 0; index < path.length; index++) 176: { 177: if (!path[index].equals(treepath[index])) 178: return false; 179: } 180: 181: // Tree Path's are equals 182: return true; 183: } 184: 185: // Unequal 186: return false; 187: } 188: 189: /** 190: * Returns a string representation of this path. 191: * 192: * @return A string representation of this path. 193: */ 194: public String toString() 195: { 196: if (path.length == 1) 197: return String.valueOf(path[0]); 198: else 199: return Arrays.asList(path).toString(); 200: } 201: 202: /** 203: * Returns an array containing the path elements. 204: * 205: * @return An array containing the path elements. 206: */ 207: public Object[] getPath() 208: { 209: return (Object[]) path.clone(); 210: } 211: 212: /** 213: * Returns the last object in the path. 214: * 215: * @return The last object in the path. 216: */ 217: public Object getLastPathComponent() 218: { 219: return path[path.length - 1]; 220: } 221: 222: /** 223: * Returns the number of elements in the path. 224: * 225: * @return The number of elements in the path. 226: */ 227: public int getPathCount() 228: { 229: return path.length; 230: } 231: 232: /** 233: * Returns the element at the specified position in the path. 234: * 235: * @param position the element position (<code>0 < N - 1</code>, where 236: * <code>N</code> is the number of elements in the path). 237: * 238: * @return The element at the specified position. 239: * 240: * @throws IllegalArgumentException if <code>position</code> is outside the 241: * valid range. 242: */ 243: public Object getPathComponent(int position) 244: { 245: if (position < 0 || position >= getPathCount()) 246: throw new IllegalArgumentException("Invalid position: " + position); 247: return path[position]; 248: } 249: 250: /** 251: * Returns <code>true</code> if <code>path</code> is a descendant of this 252: * path, and <code>false</code> otherwise. If <code>path</code> is 253: * <code>null</code>, this method returns <code>false</code>. 254: * 255: * @param path the path to check (<code>null</code> permitted). 256: * 257: * @return <code>true</code> if <code>path</code> is a descendant of this 258: * path, and <code>false</code> otherwise 259: */ 260: public boolean isDescendant(TreePath path) 261: { 262: if (path == null) 263: return false; 264: int count = getPathCount(); 265: int otherPathLength = path.getPathCount(); 266: if (otherPathLength < count) 267: return false; 268: while (otherPathLength > count) 269: { 270: otherPathLength--; 271: path = path.getParentPath(); 272: } 273: 274: return equals(path); 275: } 276: 277: /** 278: * Creates a new path that is equivalent to this path plus the specified 279: * element. 280: * 281: * @param element the element. 282: * 283: * @return A tree path. 284: */ 285: public TreePath pathByAddingChild(Object element) 286: { 287: return new TreePath(this, element); 288: } 289: 290: /** 291: * Returns the parent path, which is a path containing all the same elements 292: * as this path, except for the last one. If this path contains only one 293: * element, the method returns <code>null</code>. 294: * 295: * @return The parent path, or <code>null</code> if this path has only one 296: * element. 297: */ 298: public TreePath getParentPath() 299: { 300: // If this path has only one element, then we return null. That 301: // is what the JDK does. 302: if (path.length <= 1) 303: return null; 304: 305: // Reuse the parent path, if possible. The parent path is requested 306: // during the tree repainting, so reusing generates a lot less garbage. 307: if (parentPath == null) 308: parentPath = new TreePath(this.getPath(), path.length - 1); 309: 310: return parentPath; 311: } 312: }