001: /*
002: * $Id: DefaultTreeTableModel.java,v 1.2 2005/10/10 18:01:38 rbair Exp $
003: *
004: * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005: * Santa Clara, California 95054, U.S.A. All rights reserved.
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
020: */
021:
022: package org.jdesktop.swingx.treetable;
023:
024: import javax.swing.event.TreeModelEvent;
025: import javax.swing.event.TreeModelListener;
026: import javax.swing.tree.TreeNode;
027: import javax.swing.tree.TreePath;
028:
029: /**
030: * DefaultTreeTableModel is a concrete implementation of <code>AbstractTreeTableModel</code>
031: * and is provided purely as a convenience. Applications that use <code>JXTreeTable</code>
032: * are expected to provide their own implementation of a <code>TreeTableModel</code>,
033: * perhaps by extending this class.
034: *
035: * @author Ramesh Gupta
036: */
037: public class DefaultTreeTableModel extends AbstractTreeTableModel {
038:
039: protected boolean asksAllowsChildren;
040:
041: public DefaultTreeTableModel() {
042: this (null);
043: }
044:
045: public DefaultTreeTableModel(TreeNode root) {
046: this (root, false);
047: }
048:
049: public DefaultTreeTableModel(TreeNode root,
050: boolean asksAllowsChildren) {
051: super (root);
052: this .asksAllowsChildren = asksAllowsChildren;
053: }
054:
055: public void setRoot(TreeNode root) {
056: Object oldRoot = this .root;
057: this .root = root;
058: if (root == null && oldRoot != null) {
059: fireTreeStructureChanged(this , null);
060: } else {
061: nodeStructureChanged(root);
062: }
063: }
064:
065: /*
066: * Notifies all listeners that have registered interest for
067: * notification on this event type. The event instance
068: * is lazily created using the parameters passed into
069: * the fire method.
070: *
071: * @param source the node where the tree model has changed
072: * @param path the path to the root node
073: * @see EventListenerList
074: */
075: private void fireTreeStructureChanged(Object source, TreePath path) {
076: // Guaranteed to return a non-null array
077: Object[] listeners = listenerList.getListenerList();
078: TreeModelEvent e = null;
079: // Process the listeners last to first, notifying
080: // those that are interested in this event
081: for (int i = listeners.length - 2; i >= 0; i -= 2) {
082: if (listeners[i] == TreeModelListener.class) {
083: // Lazily create the event:
084: if (e == null)
085: e = new TreeModelEvent(source, path);
086: ((TreeModelListener) listeners[i + 1])
087: .treeStructureChanged(e);
088: }
089: }
090: }
091:
092: public boolean asksAllowsChildren() {
093: return asksAllowsChildren;
094: }
095:
096: public void setAsksAllowsChildren(boolean newValue) {
097: asksAllowsChildren = newValue;
098: }
099:
100: public Object getValueAt(Object node, int column) {
101: /**@todo Implement this org.jdesktopx.swing.treetable.TreeTableModel abstract method*/
102: return node + "@column " + column;
103: }
104:
105: public void setValueAt(Object value, Object node, int column) {
106: /**@todo Implement this org.jdesktopx.swing.treetable.TreeTableModel abstract method*/
107: }
108:
109: public TreeNode[] getPathToRoot(TreeNode node) {
110: return getPathToRoot(node, 0);
111: }
112:
113: protected TreeNode[] getPathToRoot(TreeNode node, int depth) {
114: TreeNode[] retNodes;
115: // This method recurses, traversing towards the root in order
116: // size the array. On the way back, it fills in the nodes,
117: // starting from the root and working back to the original node.
118:
119: /* Check for null, in case someone passed in a null node, or
120: they passed in an element that isn't rooted at root. */
121: if (node == null) {
122: if (depth == 0)
123: return null;
124: else
125: retNodes = new TreeNode[depth];
126: } else {
127: depth++;
128: if (node == root)
129: retNodes = new TreeNode[depth];
130: else
131: retNodes = getPathToRoot(node.getParent(), depth);
132: retNodes[retNodes.length - depth] = node;
133: }
134: return retNodes;
135: }
136:
137: /**
138: * @param node
139: * @return true if the specified node is a leaf node; false otherwise
140: */
141: public boolean isLeaf(Object node) {
142: if (node instanceof TreeNode) {
143: if (asksAllowsChildren) {
144: return !((TreeNode) node).getAllowsChildren();
145: }
146: }
147: return super .isLeaf(node);
148: }
149:
150: public void reload() {
151: TreeNode treeNode;
152: try {
153: treeNode = (TreeNode) root;
154: } catch (ClassCastException ex) {
155: return;
156: }
157:
158: reload(treeNode);
159: }
160:
161: public void reload(TreeNode node) {
162: if (node != null) {
163: fireTreeStructureChanged(this , getPathToRoot(node), null,
164: null);
165: }
166: }
167:
168: /**
169: * Invoke this method after you've inserted some TreeNodes into
170: * node. childIndices should be the index of the new elements and
171: * must be sorted in ascending order.
172: */
173: public void nodesWereInserted(TreeNode node, int[] childIndices) {
174: if (listenerList != null && node != null
175: && childIndices != null && childIndices.length > 0) {
176: int cCount = childIndices.length;
177: Object[] newChildren = new Object[cCount];
178:
179: for (int counter = 0; counter < cCount; counter++)
180: newChildren[counter] = node
181: .getChildAt(childIndices[counter]);
182: fireTreeNodesInserted(this , getPathToRoot(node),
183: childIndices, newChildren);
184: }
185: }
186:
187: /**
188: * Invoke this method after you've removed some TreeNodes from
189: * node. childIndices should be the index of the removed elements and
190: * must be sorted in ascending order. And removedChildren should be
191: * the array of the children objects that were removed.
192: */
193: public void nodesWereRemoved(TreeNode node, int[] childIndices,
194: Object[] removedChildren) {
195: if (node != null && childIndices != null) {
196: fireTreeNodesRemoved(this , getPathToRoot(node),
197: childIndices, removedChildren);
198: }
199: }
200:
201: /**
202: * Invoke this method after you've changed how the children identified by
203: * childIndicies are to be represented in the tree.
204: */
205: public void nodesChanged(TreeNode node, int[] childIndices) {
206: if (node != null) {
207: if (childIndices != null) {
208: int cCount = childIndices.length;
209:
210: if (cCount > 0) {
211: Object[] cChildren = new Object[cCount];
212:
213: for (int counter = 0; counter < cCount; counter++)
214: cChildren[counter] = node
215: .getChildAt(childIndices[counter]);
216: fireTreeNodesChanged(this , getPathToRoot(node),
217: childIndices, cChildren);
218: }
219: } else if (node == getRoot()) {
220: fireTreeNodesChanged(this , getPathToRoot(node), null,
221: null);
222: }
223: }
224: }
225:
226: /**
227: * Invoke this method if you've totally changed the children of
228: * node and its childrens children... This will post a
229: * treeStructureChanged event.
230: */
231: public void nodeStructureChanged(TreeNode node) {
232: if (node != null) {
233: fireTreeStructureChanged(this, getPathToRoot(node), null,
234: null);
235: }
236: }
237: }
|