GNU Classpath (0.91) | |
Frames | No Frames |
1: /* DefaultTreeModel.java -- 2: Copyright (C) 2002, 2004, 2005 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: package javax.swing.tree; 39: 40: import gnu.classpath.NotImplementedException; 41: 42: import java.io.IOException; 43: import java.io.ObjectInputStream; 44: import java.io.ObjectOutputStream; 45: import java.io.Serializable; 46: import java.util.EventListener; 47: 48: import javax.swing.event.EventListenerList; 49: import javax.swing.event.TreeModelEvent; 50: import javax.swing.event.TreeModelListener; 51: 52: /** 53: * DefaultTreeModel 54: * 55: * @author Andrew Selkirk 56: */ 57: public class DefaultTreeModel 58: implements Serializable, TreeModel 59: { 60: static final long serialVersionUID = -2621068368932566998L; 61: 62: /** 63: * root 64: */ 65: protected TreeNode root = null; 66: 67: /** 68: * listenerList 69: */ 70: protected EventListenerList listenerList = new EventListenerList(); 71: 72: /** 73: * asksAllowsChildren 74: */ 75: protected boolean asksAllowsChildren; 76: 77: /** 78: * Constructor DefaultTreeModel where any node can have children. 79: * 80: * @param root the tree root. 81: */ 82: public DefaultTreeModel(TreeNode root) 83: { 84: this (root, false); 85: } 86: 87: /** 88: * Create the DefaultTreeModel that may check if the nodes can have 89: * children or not. 90: * 91: * @param aRoot the tree root. 92: * @param asksAllowsChildren if true, each node is asked if it can have 93: * children. If false, the model does not care about this, supposing, that 94: * any node can have children. 95: */ 96: public DefaultTreeModel(TreeNode aRoot, boolean asksAllowsChildren) 97: { 98: if (aRoot == null) 99: aRoot = new DefaultMutableTreeNode(); 100: this.root = aRoot; 101: this.asksAllowsChildren = asksAllowsChildren; 102: } 103: 104: /** 105: * writeObject 106: * 107: * @param obj the object. 108: * @exception IOException TODO 109: */ 110: private void writeObject(ObjectOutputStream obj) throws IOException 111: { 112: // TODO 113: } 114: 115: /** 116: * readObject 117: * 118: * @param value0 TODO 119: * @exception IOException TODO 120: * @exception ClassNotFoundException TODO 121: */ 122: private void readObject(ObjectInputStream value0) throws IOException, 123: ClassNotFoundException 124: { 125: // TODO 126: } 127: 128: /** 129: * asksAllowsChildren 130: * 131: * @return boolean 132: */ 133: public boolean asksAllowsChildren() 134: { 135: return asksAllowsChildren; 136: } 137: 138: /** 139: * setAsksAllowsChildren 140: * 141: * @param value TODO 142: */ 143: public void setAsksAllowsChildren(boolean value) 144: { 145: asksAllowsChildren = value; 146: } 147: 148: /** 149: * setRoot 150: * 151: * @param root the root node. 152: */ 153: public void setRoot(TreeNode root) 154: { 155: this.root = root; 156: } 157: 158: /** 159: * getRoot 160: * 161: * @return Object 162: */ 163: public Object getRoot() 164: { 165: return root; 166: } 167: 168: /** 169: * getIndexOfChild 170: * 171: * @param parent TODO 172: * @param child TODO 173: * @return int 174: */ 175: public int getIndexOfChild(Object parent, Object child) 176: { 177: for (int i = 0; i < getChildCount(parent); i++) 178: { 179: if (getChild(parent, i).equals(child)) 180: return i; 181: } 182: return -1; 183: } 184: 185: /** 186: * getChild 187: * 188: * @param node TODO 189: * @param idx TODO 190: * @return Object 191: */ 192: public Object getChild(Object node, int idx) 193: { 194: if (node instanceof TreeNode) 195: return ((TreeNode) node).getChildAt(idx); 196: else 197: return null; 198: } 199: 200: /** 201: * getChildCount 202: * 203: * @param node TODO 204: * @return int 205: */ 206: public int getChildCount(Object node) 207: { 208: if (node instanceof TreeNode) 209: return ((TreeNode) node).getChildCount(); 210: else 211: return 0; 212: } 213: 214: /** 215: * isLeaf 216: * 217: * @param node TODO 218: * @return boolean 219: */ 220: public boolean isLeaf(Object node) 221: { 222: if (node instanceof TreeNode) 223: return ((TreeNode) node).isLeaf(); 224: else 225: return true; 226: } 227: 228: /** 229: * <p> 230: * Invoke this method if you've modified the TreeNodes upon which this model 231: * depends. The model will notify all of its listeners that the model has 232: * changed. It will fire the events, necessary to update the layout caches and 233: * repaint the tree. The tree will <i>not</i> be properly refreshed if you 234: * call the JTree.repaint instead. 235: * </p> 236: * <p> 237: * This method will refresh the information about whole tree from the root. If 238: * only part of the tree should be refreshed, it is more effective to call 239: * {@link #reload(TreeNode)}. 240: * </p> 241: */ 242: public void reload() 243: { 244: // Need to duplicate the code because the root can formally be 245: // no an instance of the TreeNode. 246: int n = getChildCount(root); 247: int[] childIdx = new int[n]; 248: Object[] children = new Object[n]; 249: 250: for (int i = 0; i < n; i++) 251: { 252: childIdx[i] = i; 253: children[i] = getChild(root, i); 254: } 255: 256: fireTreeStructureChanged(this, new Object[] { root }, childIdx, children); 257: } 258: 259: /** 260: * Invoke this method if you've modified the TreeNodes upon which this model 261: * depends. The model will notify all of its listeners that the model has 262: * changed. It will fire the events, necessary to update the layout caches and 263: * repaint the tree. The tree will <i>not</i> be properly refreshed if you 264: * call the JTree.repaint instead. 265: * 266: * @param node - the tree node, from which the tree nodes have changed 267: * (inclusive). If you do not know this node, call {@link #reload()} 268: * instead. 269: */ 270: public void reload(TreeNode node) 271: { 272: int n = getChildCount(node); 273: int[] childIdx = new int[n]; 274: Object[] children = new Object[n]; 275: 276: for (int i = 0; i < n; i++) 277: { 278: childIdx[i] = i; 279: children[i] = getChild(node, i); 280: } 281: 282: fireTreeStructureChanged(this, getPathToRoot(node), childIdx, children); 283: } 284: 285: /** 286: * Messaged when the user has altered the value for the item 287: * identified by path to newValue. If newValue signifies a truly new 288: * value the model should post a treeNodesChanged event. 289: * This sets the user object of the TreeNode identified by 290: * path and posts a node changed. If you use custom user objects 291: * in the TreeModel you're going to need to subclass this and set 292: * the user object of the changed node to something meaningful. 293: * 294: * @param path - path to the node that the user has altered 295: * @param newValue - the new value from the TreeCellEditor 296: */ 297: public void valueForPathChanged(TreePath path, Object newValue) 298: { 299: Object node = path.getLastPathComponent(); 300: if (node instanceof MutableTreeNode) 301: { 302: ((MutableTreeNode) node).setUserObject(newValue); 303: int[] ci = null; 304: Object[] c = null; 305: Object[] parentPath = path.getPath(); 306: if (path.getPathCount() > 1) 307: { 308: Object parent = ((TreeNode) node).getParent(); 309: ci = new int[1]; 310: ci[0] = getIndexOfChild(parent, node); 311: node = newValue; 312: path = path.getParentPath().pathByAddingChild(node); 313: c = new Object[1]; 314: c[0] = node; 315: parentPath = path.getParentPath().getPath(); 316: } 317: 318: fireTreeNodesChanged(this, parentPath, ci, c); 319: } 320: } 321: 322: /** 323: * Invoked this to insert newChild at location index in parents children. 324: * This will then message nodesWereInserted to create the appropriate event. 325: * This is the preferred way to add children as it will create the 326: * appropriate event. 327: * 328: * @param newChild is the node to add to the parent's children 329: * @param parent is the parent of the newChild 330: * @param index is the index of the newChild 331: */ 332: public void insertNodeInto(MutableTreeNode newChild, MutableTreeNode parent, 333: int index) 334: { 335: newChild.setParent(parent); 336: parent.insert(newChild, index); 337: int[] childIndices = new int[1]; 338: childIndices[0] = index; 339: nodesWereInserted(parent, childIndices); 340: } 341: 342: /** 343: * Message this to remove node from its parent. This will message 344: * nodesWereRemoved to create the appropriate event. This is the preferred 345: * way to remove a node as it handles the event creation for you. 346: * 347: * @param node to be removed 348: */ 349: public void removeNodeFromParent(MutableTreeNode node) 350: { 351: TreeNode parent = node.getParent(); 352: Object[] children = new Object[1]; 353: children[0] = node; 354: int[] childIndices = new int[1]; 355: childIndices[0] = getIndexOfChild(parent, node); 356: node.removeFromParent(); 357: nodesWereRemoved(parent, childIndices, children); 358: } 359: 360: /** 361: * Invoke this method after you've changed how node is to be represented 362: * in the tree. 363: * 364: * @param node that was changed 365: */ 366: public void nodeChanged(TreeNode node) 367: { 368: TreeNode parent = node.getParent(); 369: int[] childIndices = new int[1]; 370: childIndices[0] = getIndexOfChild(parent, node); 371: Object[] children = new Object[1]; 372: children[0] = node; 373: fireTreeNodesChanged(this, getPathToRoot(node), childIndices, children); 374: } 375: 376: /** 377: * Invoke this method after you've inserted some TreeNodes 378: * into node. childIndices should be the index of the new elements and must 379: * be sorted in ascending order. 380: * 381: * @param parent that had a child added to 382: * @param childIndices of the children added 383: */ 384: public void nodesWereInserted(TreeNode parent, int[] childIndices) 385: { 386: Object[] children = new Object[childIndices.length]; 387: for (int i = 0; i < children.length; i++) 388: children[i] = getChild(parent, childIndices[i]); 389: fireTreeNodesInserted(this, getPathToRoot(parent), childIndices, children); 390: } 391: 392: /** 393: * Invoke this method after you've removed some TreeNodes from node. 394: * childIndices should be the index of the removed elements and 395: * must be sorted in ascending order. And removedChildren should be the 396: * array of the children objects that were removed. 397: * 398: * @param parent that had a child added to 399: * @param childIndices of the children added 400: * @param removedChildren are all the children removed from parent. 401: */ 402: public void nodesWereRemoved(TreeNode parent, int[] childIndices, 403: Object[] removedChildren) 404: { 405: fireTreeNodesRemoved(this, getPathToRoot(parent), childIndices, 406: removedChildren); 407: } 408: 409: /** 410: * Invoke this method after you've changed how the children identified by 411: * childIndices are to be represented in the tree. 412: * 413: * @param node that is the parent of the children that changed in a tree. 414: * @param childIndices are the child nodes that changed. 415: */ 416: public void nodesChanged(TreeNode node, int[] childIndices) 417: { 418: Object[] children = new Object[childIndices.length]; 419: for (int i = 0; i < children.length; i++) 420: children[i] = getChild(node, childIndices[i]); 421: fireTreeNodesChanged(this, getPathToRoot(node), childIndices, children); 422: } 423: 424: /** 425: * Invoke this method if you've totally changed the children of node and 426: * its childrens children. This will post a treeStructureChanged event. 427: * 428: * @param node that had its children and grandchildren changed. 429: */ 430: public void nodeStructureChanged(TreeNode node) 431: { 432: int n = getChildCount(root); 433: int[] childIdx = new int[n]; 434: Object[] children = new Object[n]; 435: 436: for (int i = 0; i < n; i++) 437: { 438: childIdx[i] = i; 439: children[i] = getChild(root, i); 440: } 441: 442: fireTreeStructureChanged(this, new Object[] { root }, childIdx, children); 443: } 444: 445: /** 446: * Builds the parents of node up to and including the root node, where 447: * the original node is the last element in the returned array. The 448: * length of the returned array gives the node's depth in the tree. 449: * 450: * @param node - the TreeNode to get the path for 451: * @return TreeNode[] - the path from node to the root 452: */ 453: public TreeNode[] getPathToRoot(TreeNode node) 454: { 455: return getPathToRoot(node, 0); 456: } 457: 458: /** 459: * Builds the parents of node up to and including the root node, where 460: * the original node is the last element in the returned array. The 461: * length of the returned array gives the node's depth in the tree. 462: * 463: * @param node - the TreeNode to get the path for 464: * @param depth - an int giving the number of steps already taken 465: * towards the root (on recursive calls), used to size the returned array 466: * @return an array of TreeNodes giving the path from the root to the 467: * specified node 468: */ 469: protected TreeNode[] getPathToRoot(TreeNode node, int depth) 470: { 471: if (node == null) 472: { 473: if (depth == 0) 474: return null; 475: 476: return new TreeNode[depth]; 477: } 478: 479: TreeNode[] path = getPathToRoot(node.getParent(), depth + 1); 480: path[path.length - depth - 1] = node; 481: return path; 482: } 483: 484: /** 485: * Registers a listere to the model. 486: * 487: * @param listener the listener to add 488: */ 489: public void addTreeModelListener(TreeModelListener listener) 490: { 491: listenerList.add(TreeModelListener.class, listener); 492: } 493: 494: /** 495: * Removes a listener from the model. 496: * 497: * @param listener the listener to remove 498: */ 499: public void removeTreeModelListener(TreeModelListener listener) 500: { 501: listenerList.remove(TreeModelListener.class, listener); 502: } 503: 504: /** 505: * Returns all registered <code>TreeModelListener</code> listeners. 506: * 507: * @return an array of listeners. 508: * 509: * @since 1.4 510: */ 511: public TreeModelListener[] getTreeModelListeners() 512: { 513: return (TreeModelListener[]) listenerList 514: .getListeners(TreeModelListener.class); 515: } 516: 517: /** 518: * Notifies all listeners that have registered interest for notification 519: * on this event type. The event instance is lazily created using the parameters 520: * passed into the fire method. 521: * 522: * @param source the node being changed 523: * @param path the path to the root node 524: * @param childIndices the indices of the changed elements 525: * @param children the changed elements 526: */ 527: protected void fireTreeNodesChanged(Object source, Object[] path, 528: int[] childIndices, Object[] children) 529: { 530: TreeModelEvent event = new TreeModelEvent(source, path, childIndices, 531: children); 532: 533: TreeModelListener[] listeners = getTreeModelListeners(); 534: 535: for (int i = listeners.length - 1; i >= 0; --i) 536: listeners[i].treeNodesChanged(event); 537: } 538: 539: /** 540: * fireTreeNodesInserted 541: * 542: * @param source the node where new nodes got inserted 543: * @param path the path to the root node 544: * @param childIndices the indices of the new elements 545: * @param children the new elements 546: */ 547: protected void fireTreeNodesInserted(Object source, Object[] path, 548: int[] childIndices, Object[] children) 549: { 550: TreeModelEvent event = new TreeModelEvent(source, path, childIndices, 551: children); 552: TreeModelListener[] listeners = getTreeModelListeners(); 553: 554: for (int i = listeners.length - 1; i >= 0; --i) 555: listeners[i].treeNodesInserted(event); 556: } 557: 558: /** 559: * fireTreeNodesRemoved 560: * 561: * @param source the node where nodes got removed- 562: * @param path the path to the root node 563: * @param childIndices the indices of the removed elements 564: * @param children the removed elements 565: */ 566: protected void fireTreeNodesRemoved(Object source, Object[] path, 567: int[] childIndices, Object[] children) 568: { 569: TreeModelEvent event = new TreeModelEvent(source, path, childIndices, 570: children); 571: TreeModelListener[] listeners = getTreeModelListeners(); 572: 573: for (int i = listeners.length - 1; i >= 0; --i) 574: listeners[i].treeNodesRemoved(event); 575: } 576: 577: /** 578: * fireTreeStructureChanged 579: * 580: * @param source the node where the model has changed 581: * @param path the path to the root node 582: * @param childIndices the indices of the affected elements 583: * @param children the affected elements 584: */ 585: protected void fireTreeStructureChanged(Object source, Object[] path, 586: int[] childIndices, Object[] children) 587: { 588: TreeModelEvent event = new TreeModelEvent(source, path, childIndices, 589: children); 590: TreeModelListener[] listeners = getTreeModelListeners(); 591: 592: for (int i = listeners.length - 1; i >= 0; --i) 593: listeners[i].treeStructureChanged(event); 594: } 595: 596: /** 597: * Returns the registered listeners of a given type. 598: * 599: * @param listenerType the listener type to return 600: * 601: * @return an array of listeners 602: * 603: * @since 1.3 604: */ 605: public EventListener[] getListeners(Class listenerType) 606: { 607: return listenerList.getListeners(listenerType); 608: } 609: }
GNU Classpath (0.91) |