KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > explorer > view > NodeListModel


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.explorer.view;
20
21 import org.openide.nodes.Node;
22 import org.openide.util.*;
23
24 import java.beans.*;
25
26 import java.lang.ref.Reference JavaDoc;
27 import java.lang.ref.WeakReference JavaDoc;
28
29 import java.util.*;
30
31 import javax.swing.*;
32 import javax.swing.event.*;
33 import javax.swing.tree.*;
34
35
36 /** Model for displaying the nodes in list and choice.
37 *
38 * @author Jaroslav Tulach
39 */

40 public class NodeListModel extends AbstractListModel implements ComboBoxModel {
41     static final long serialVersionUID = -1926931095895356820L;
42
43     /** listener used to listen to changes in trees */
44     private transient Listener listener;
45
46     /** parent node */
47     private transient VisualizerNode parent;
48
49     /** originally selected item */
50     private transient Object JavaDoc selectedObject;
51
52     /** previous size */
53     private transient int size;
54
55     /** depth to display */
56     private int depth = 1;
57
58     /** map that assignes to each visualizer number of its children till
59     * the specified depth.
60     */

61     private Map<VisualizerNode, Info> childrenCount;
62
63     /** Creates new NodeTreeModel
64     */

65     public NodeListModel() {
66         parent = VisualizerNode.EMPTY;
67         selectedObject = VisualizerNode.EMPTY;
68         clearChildrenCount();
69     }
70
71     /** Creates new NodeTreeModel
72     * @param root the root of the model
73     */

74     public NodeListModel(Node root) {
75         this();
76         setNode(root);
77     }
78
79     /** Changes the root of the model. This is thread safe method.
80     * @param root the root of the model
81     */

82     public void setNode(final Node root) {
83         Mutex.EVENT.readAccess(
84             new Runnable JavaDoc() {
85                 public void run() {
86                     VisualizerNode v = VisualizerNode.getVisualizer(null, root);
87
88                     if (v == parent) {
89                         // no change
90
return;
91                     }
92
93                     removeAll();
94                     parent.removeNodeModel(listener());
95
96                     parent = v;
97                     selectedObject = v;
98                     clearChildrenCount();
99
100                     addAll();
101                     parent.addNodeModel(listener());
102                 }
103             }
104         );
105     }
106
107     /** Depth of nodes to display.
108     * @param depth the depth
109     */

110     public void setDepth(int depth) {
111         if (depth != this.depth) {
112             this.depth = depth;
113             clearChildrenCount();
114
115             Mutex.EVENT.readAccess(
116                 new Runnable JavaDoc() {
117                     public void run() {
118                         removeAll();
119                         addAll();
120                     }
121                 }
122             );
123         }
124     }
125
126     /** Getter for depth.
127     * @return number of levels to display
128     */

129     public int getDepth() {
130         return depth;
131     }
132
133     /** Getter for the listener. Only from AWT-QUEUE.
134     */

135     private Listener listener() {
136         if (listener == null) {
137             listener = new Listener(this);
138         }
139
140         return listener;
141     }
142
143     //
144
// model methods
145
//
146

147     /** Number of elements in the model.
148     */

149     public int getSize() {
150         int s = findSize(parent, -1, depth);
151
152         return s;
153     }
154
155     /** Child at given index.
156     */

157     public Object JavaDoc getElementAt(int i) {
158         return findElementAt(parent, i, -1, depth);
159     }
160
161     /** Finds index of given object.
162     * @param o object produced by this model
163     * @return index, or -1 if the object is not in the list
164     */

165     public int getIndex(Object JavaDoc o) {
166         getSize();
167
168         Info i = childrenCount.get(o);
169
170         return (i == null) ? (-1) : i.index;
171     }
172
173     /** Currently selected item.
174     */

175     public void setSelectedItem(Object JavaDoc anObject) {
176         if (selectedObject != anObject) {
177             selectedObject = anObject;
178             fireContentsChanged(this, -1, -1);
179         }
180     }
181
182     public Object JavaDoc getSelectedItem() {
183         return selectedObject;
184     }
185
186     //
187
// modification of the counting model
188
//
189
private void clearChildrenCount() {
190         childrenCount = new HashMap<VisualizerNode, Info>(17);
191     }
192
193     /** Finds size of sub children excluding vis node.
194     *
195     * @param vis the visualizer to find the size for
196     * @param index the index that should be assigned to vis
197     * @param depth the depth to scan
198     * @return number of children
199     */

200     private int findSize(VisualizerNode vis, int index, int depth) {
201         Info info = childrenCount.get(vis);
202
203         if (info != null) {
204             return info.childrenCount;
205         }
206
207         // only my children
208
int size = 0;
209
210         info = new Info();
211         info.depth = depth;
212         info.index = index;
213
214         if (depth-- > 0) {
215             Iterator it = vis.getChildren().iterator();
216
217             while (it.hasNext()) {
218                 VisualizerNode v = (VisualizerNode) it.next();
219
220                 // count node v
221
size++;
222
223                 // now count children of node v
224
size += findSize(v, index + size, depth);
225             }
226         }
227
228         info.childrenCount = size;
229         childrenCount.put(vis, info);
230
231         return size;
232     }
233
234     /** Finds the child with requested index.
235     *
236     * @param vis the visualizer to find the size for
237     * @param indx the index of requested child
238     * @param depth the depth to scan
239     * @return the children
240     */

241     private VisualizerNode findElementAt(VisualizerNode vis, int indx, int realIndx, int depth) {
242         if (--depth == 0) {
243             // last depth is handled in special way
244
return (VisualizerNode) vis.getChildAt(indx);
245         }
246
247         Iterator it = vis.getChildren().iterator();
248
249         while (it.hasNext()) {
250             VisualizerNode v = (VisualizerNode) it.next();
251
252             if (indx-- == 0) {
253                 return v;
254             }
255
256             int s = findSize(v, ++realIndx, depth);
257
258             if (indx < s) {
259                 // search this child
260
return findElementAt(v, indx, realIndx, depth);
261             }
262
263             // go to next child
264
indx -= s;
265             realIndx += s;
266         }
267
268         return vis;
269     }
270
271     /** Finds a depth for given model & object. Used from renderer.
272     * @param m model
273     * @param o the visualizer node
274     * @return depth or 0 if not found
275     */

276     static int findVisualizerDepth(ListModel m, VisualizerNode o) {
277         if (m instanceof NodeListModel) {
278             NodeListModel n = (NodeListModel) m;
279             Info i = n.childrenCount.get(o);
280
281             if (i != null) {
282                 return n.depth - i.depth - 1;
283             }
284         }
285
286         return 0;
287     }
288
289     //
290
// Modifications
291
//
292
final void addAll() {
293         size = getSize();
294
295         if (size > 0) {
296             fireIntervalAdded(this, 0, size - 1);
297         }
298     }
299
300     final void removeAll() {
301         if (size > 0) {
302             fireIntervalRemoved(this, 0, size - 1);
303         }
304     }
305
306     final void changeAll() {
307         size = getSize();
308
309         if (size > 0) {
310             fireContentsChanged(this, 0, size - 1);
311         }
312
313         clearChildrenCount();
314     }
315
316     final void added(VisualizerEvent.Added ev) {
317         VisualizerNode v = ev.getVisualizer();
318         int[] indices = ev.getArray();
319
320         //fire that model has been changed only when event source's (visualizer)
321
//children are shown in the list
322
if ((cachedDepth(v) <= 0) || (indices.length == 0)) {
323             return;
324         }
325
326         clearChildrenCount();
327         size = getSize();
328
329         int seg = (parent == v) ? 0 : getIndex(v);
330         fireIntervalAdded(this, indices[0] + seg, indices[indices.length - 1] + seg);
331     }
332
333     final void removed(VisualizerEvent.Removed ev) {
334         VisualizerNode v = ev.getVisualizer();
335         int[] indices = ev.getArray();
336
337         //fire that model has been changed only when event source's (visualizer)
338
//children are shown in the list
339
if ((cachedDepth(v) <= 0) || (indices.length == 0)) {
340             return;
341         }
342
343         clearChildrenCount();
344
345         int seg = (parent == v) ? 0 : getIndex(v);
346         fireIntervalRemoved(this, indices[0] + seg, indices[indices.length - 1] + seg);
347     }
348
349     final void update(VisualizerNode v) {
350         // ensure the model is computed
351
getSize();
352
353         Info i = childrenCount.get(v);
354
355         if (i != null) {
356             fireContentsChanged(this, i.index, i.index);
357         }
358     }
359
360     private int cachedDepth(VisualizerNode v) {
361         getSize();
362
363         Info i = childrenCount.get(v);
364
365         if (i != null) {
366             return i.depth;
367         }
368
369         // v is not in the model
370
return -1;
371     }
372
373     /** The listener */
374     private static final class Listener implements NodeModel {
375         /** weak reference to the model */
376         private Reference JavaDoc<NodeListModel> model;
377
378         /** Constructor.
379         */

380         public Listener(NodeListModel m) {
381             model = new WeakReference JavaDoc<NodeListModel>(m);
382         }
383
384         /** Getter for the model or null.
385         */

386         private NodeListModel get(VisualizerEvent ev) {
387             NodeListModel m = model.get();
388
389             if ((m == null) && (ev != null)) {
390                 ev.getVisualizer().removeNodeModel(this);
391
392                 return null;
393             }
394
395             return m;
396         }
397
398         /** Notification of children addded event. Modifies the list of nodes
399         * and fires info to all listeners.
400         */

401         public void added(VisualizerEvent.Added ev) {
402             NodeListModel m = get(ev);
403
404             if (m == null) {
405                 return;
406             }
407
408             m.added(ev);
409         }
410
411         /** Notification that children has been removed. Modifies the list of nodes
412         * and fires info to all listeners.
413         */

414         public void removed(VisualizerEvent.Removed ev) {
415             NodeListModel m = get(ev);
416
417             if (m == null) {
418                 return;
419             }
420
421             m.removed(ev);
422         }
423
424         /** Notification that children has been reordered. Modifies the list of nodes
425         * and fires info to all listeners.
426         */

427         public void reordered(VisualizerEvent.Reordered ev) {
428             NodeListModel m = get(ev);
429
430             if (m == null) {
431                 return;
432             }
433
434             m.changeAll();
435         }
436
437         /** Update a visualizer (change of name, icon, description, etc.)
438         */

439         public void update(VisualizerNode v) {
440             NodeListModel m = get(null);
441
442             if (m == null) {
443                 return;
444             }
445
446             m.update(v);
447         }
448
449         /** Notification about big change in children
450         */

451         public void structuralChange(VisualizerNode v) {
452             NodeListModel m = get(null);
453
454             if (m == null) {
455                 return;
456             }
457
458             m.changeAll();
459         }
460     }
461
462     /** Info for a component in model
463     */

464     private static final class Info extends Object JavaDoc {
465         public int childrenCount;
466         public int depth;
467         public int index;
468
469         Info() {
470         }
471
472         public String JavaDoc toString() {
473             return "Info[childrenCount=" + childrenCount + ", depth=" + depth + // NOI18N
474
", index=" + index; // NOI18N
475
}
476     }
477 }
478
Popular Tags