KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > swing > outline > TreePathSupport


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
20 package org.netbeans.swing.outline;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Enumeration JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.Set JavaDoc;
30 import javax.swing.event.TreeExpansionEvent JavaDoc;
31 import javax.swing.event.TreeExpansionListener JavaDoc;
32 import javax.swing.event.TreeWillExpandListener JavaDoc;
33 import javax.swing.tree.AbstractLayoutCache JavaDoc;
34 import javax.swing.tree.ExpandVetoException JavaDoc;
35 import javax.swing.tree.TreePath JavaDoc;
36
37 /** Manages expanded/collapsed paths for the Outline. Provides services similar
38  * to those JTree implements inside its own class body. Propagates changes
39  * in expanded state to the layout cache.
40  * <p>
41  * Principally what this class does is manage the state of expanded paths which
42  * are not visible, or whose parents have been closed/opened. Whereas the
43  * layout cache retains information only about what is visibly expanded, this
44  * class manages information about any path that has been expanded at some
45  * point in the lifetime of an Outline, so that for example, if A contains B
46  * contains C, and A and B and C are expanded, then the user collapses A,
47  * and later re&euml;expands A, B and C will retain their expanded state and
48  * appear as they did the last time A was expanded.
49  * <p>
50  * When nodes are removed, the OutlineModel must call removePath() for any
51  * defunct paths to avoid memory leaks by the TreePathSupport holding
52  * references to defunct nodes and not allowing them to be garbage collected.
53  * <p>
54  * Its <code>addTreeWillExpandListener</code> code supports
55  * <code>ExtTreeWillExpandListener</code>, so such a listener may be notified
56  * if some other listener vetos a pending expansion event.
57  *
58  * @author Tim Boudreau
59  */

60 public final class TreePathSupport {
61     private OutlineModel mdl;
62     private Map JavaDoc expandedPaths = new HashMap JavaDoc();
63     private List JavaDoc eListeners = new ArrayList JavaDoc();
64     private List JavaDoc weListeners = new ArrayList JavaDoc();
65     private AbstractLayoutCache JavaDoc layout;
66     
67     /** Creates a new instance of TreePathSupport */
68     public TreePathSupport(OutlineModel mdl, AbstractLayoutCache JavaDoc layout) {
69         this.mdl = mdl;
70         this.layout = layout;
71     }
72     
73     /** Clear all expanded path data. This is called if the tree model fires
74      * a structural change, and any or all of the nodes it contains may no
75      * longer be present. */

76     public void clear() {
77         expandedPaths.clear();
78     }
79     
80     /** Expand a path. Notifies the layout cache of the change,
81      * stores the expanded path info (so reexpanding a parent node also reexpands
82      * this path if a parent node containing it is later collapsed). Fires
83      * TreeWillExpand and TreeExpansion events. */

84     public void expandPath (TreePath JavaDoc path) {
85         if (Boolean.TRUE.equals(expandedPaths.get(path))) {
86             //It's already expanded, don't waste cycles firing bogus events
87
return;
88         }
89         TreeExpansionEvent JavaDoc e = new TreeExpansionEvent JavaDoc (this, path);
90         try {
91             fireTreeWillExpand(e, true);
92             expandedPaths.put(path, Boolean.TRUE);
93             layout.setExpandedState(path, true);
94             fireTreeExpansion(e, true);
95         } catch (ExpandVetoException JavaDoc eve) {
96             fireTreeExpansionVetoed (e, eve);
97         }
98     }
99     
100     /** Collapse a path. Notifies the layout cache of the change,
101      * stores the expanded path info (so reexpanding a parent node also reexpands
102      * this path if a parent node containing it is later collapsed). Fires
103      * TreeWillExpand and TreeExpansion events. */

104     public void collapsePath (TreePath JavaDoc path) {
105         if (Boolean.FALSE.equals(expandedPaths.get(path))) {
106             //It's already collapsed, don't waste cycles firing bogus events
107
return;
108         }
109         TreeExpansionEvent JavaDoc e = new TreeExpansionEvent JavaDoc (this, path);
110         try {
111             fireTreeWillExpand(e, false);
112             expandedPaths.put(path, Boolean.FALSE);
113             layout.setExpandedState(path, false);
114             fireTreeExpansion(e, false);
115         } catch (ExpandVetoException JavaDoc eve) {
116             fireTreeExpansionVetoed (e, eve);
117         }
118     }
119     
120     /** Remove a path's data from the list of known paths. Called when
121      * a tree model deletion event occurs */

122     public void removePath (TreePath JavaDoc path) {
123         expandedPaths.remove(path);
124     }
125     
126     private void fireTreeExpansion (TreeExpansionEvent JavaDoc e, boolean expanded) {
127         int size = eListeners.size();
128         
129         TreeExpansionListener JavaDoc[] listeners = new TreeExpansionListener JavaDoc[size];
130         synchronized (this) {
131             listeners = (TreeExpansionListener JavaDoc[]) eListeners.toArray(listeners);
132         }
133         for (int i=0; i < listeners.length; i++) {
134             if (expanded) {
135                 listeners[i].treeExpanded(e);
136             } else {
137                 listeners[i].treeCollapsed(e);
138             }
139         }
140     }
141     
142     private void fireTreeWillExpand (TreeExpansionEvent JavaDoc e, boolean expanded) throws ExpandVetoException JavaDoc {
143         int size = eListeners.size();
144         
145         TreeWillExpandListener JavaDoc[] listeners = new TreeWillExpandListener JavaDoc[size];
146         synchronized (this) {
147             listeners = (TreeWillExpandListener JavaDoc[]) weListeners.toArray(listeners);
148         }
149         for (int i=0; i < listeners.length; i++) {
150             if (expanded) {
151                 listeners[i].treeWillExpand(e);
152             } else {
153                 listeners[i].treeWillCollapse(e);
154             }
155         }
156     }
157     
158     private void fireTreeExpansionVetoed (TreeExpansionEvent JavaDoc e, ExpandVetoException JavaDoc ex) {
159         int size = eListeners.size();
160         
161         TreeWillExpandListener JavaDoc[] listeners = new TreeWillExpandListener JavaDoc[size];
162         synchronized (this) {
163             listeners = (TreeWillExpandListener JavaDoc[]) weListeners.toArray(listeners);
164         }
165         for (int i=0; i < listeners.length; i++) {
166             if (listeners[i] instanceof ExtTreeWillExpandListener) {
167                 ((ExtTreeWillExpandListener) listeners[i]).treeExpansionVetoed(e,
168                     ex);
169             }
170         }
171     }
172     
173     
174     public boolean hasBeenExpanded(TreePath JavaDoc path) {
175     return (path != null && expandedPaths.get(path) != null);
176     }
177
178     /**
179      * Returns true if the node identified by the path is currently expanded,
180      *
181      * @param path the <code>TreePath</code> specifying the node to check
182      * @return false if any of the nodes in the node's path are collapsed,
183      * true if all nodes in the path are expanded
184      */

185     public boolean isExpanded(TreePath JavaDoc path) {
186     if(path == null)
187         return false;
188
189     // Is this node expanded?
190
Object JavaDoc value = expandedPaths.get(path);
191
192     if(value == null || !((Boolean JavaDoc)value).booleanValue())
193         return false;
194
195     // It is, make sure its parent is also expanded.
196
TreePath JavaDoc parentPath = path.getParentPath();
197
198     if(parentPath != null)
199         return isExpanded(parentPath);
200         return true;
201     }
202     
203      protected void removeDescendantToggledPaths(Enumeration JavaDoc toRemove) {
204      if(toRemove != null) {
205          while(toRemove.hasMoreElements()) {
206                  TreePath JavaDoc[] descendants = getDescendantToggledPaths(
207                     (TreePath JavaDoc) toRemove.nextElement());
208                  for (int i=0; i < descendants.length; i++) {
209                      expandedPaths.remove(descendants[i]);
210                  }
211          }
212      }
213      }
214      
215     protected TreePath JavaDoc[] getDescendantToggledPaths(TreePath JavaDoc parent) {
216     if(parent == null)
217         return null;
218
219     ArrayList JavaDoc descendants = new ArrayList JavaDoc();
220         Iterator JavaDoc nodes = expandedPaths.keySet().iterator();
221         TreePath JavaDoc path;
222         while (nodes.hasNext()) {
223             path = (TreePath JavaDoc) nodes.next();
224             if (parent.isDescendant(path)) {
225                 descendants.add(path);
226             }
227         }
228         TreePath JavaDoc[] result = new TreePath JavaDoc[descendants.size()];
229         return (TreePath JavaDoc[]) descendants.toArray(result);
230     }
231     
232     public boolean isVisible(TreePath JavaDoc path) {
233         if(path != null) {
234         TreePath JavaDoc parentPath = path.getParentPath();
235
236         if(parentPath != null) {
237         return isExpanded(parentPath);
238             }
239         // Root.
240
return true;
241     }
242         return false;
243     }
244     
245     public TreePath JavaDoc[] getExpandedDescendants(TreePath JavaDoc parent) {
246         TreePath JavaDoc[] result = new TreePath JavaDoc[0];
247     if(isExpanded(parent)) {
248             TreePath JavaDoc path;
249             Object JavaDoc value;
250             List JavaDoc results = null;
251
252             if (!expandedPaths.isEmpty()) {
253
254                 Iterator JavaDoc i = expandedPaths.keySet().iterator();
255
256                 while(i.hasNext()) {
257                     path = (TreePath JavaDoc) i.next();
258                     value = expandedPaths.get(path);
259
260                     // Add the path if it is expanded, a descendant of parent,
261
// and it is visible (all parents expanded). This is rather
262
// expensive!
263
if(path != parent && value != null &&
264                        ((Boolean JavaDoc)value).booleanValue() &&
265                         parent.isDescendant(path) && isVisible(path)) {
266                         if (results == null) {
267                             results = new ArrayList JavaDoc();
268                         }
269                         results.add (path);
270                     }
271                 }
272                 if (results != null) {
273                     result = (TreePath JavaDoc[]) results.toArray(result);
274                 }
275             }
276         }
277         return result;
278     }
279     
280     /** Add a TreeExpansionListener. If the TreeWillExpandListener implements
281      * ExtTreeExpansionListener, it will be notified if another
282      * TreeWillExpandListener vetoes the expansion event */

283     public synchronized void addTreeExpansionListener (TreeExpansionListener JavaDoc l) {
284         eListeners.add(l);
285     }
286     
287     public synchronized void removeTreeExpansionListener (TreeExpansionListener JavaDoc l) {
288         eListeners.remove(l);
289     }
290     
291     public synchronized void addTreeWillExpandListener (TreeExpansionListener JavaDoc l) {
292         weListeners.add(l);
293     }
294     
295     public synchronized void removeTreeWillExpandListener (TreeExpansionListener JavaDoc l) {
296         weListeners.remove(l);
297     }
298 }
299
Popular Tags