KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > src > nodes > SourceChildren


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.openide.src.nodes;
21
22 import java.beans.PropertyChangeListener JavaDoc;
23 import java.beans.PropertyChangeEvent JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.LinkedList JavaDoc;
26 import java.util.Arrays JavaDoc;
27 import java.util.List JavaDoc;
28
29 import org.openide.nodes.Children;
30 import org.openide.nodes.Node;
31 import org.openide.cookies.FilterCookie;
32 import org.openide.src.ElementProperties;
33 import org.openide.src.SourceElement;
34 import org.openide.src.ClassElement;
35 import org.openide.util.WeakListeners;
36
37 /** Normal implementation of children for source element nodes.
38 * <P>
39 * Ordering and filtering of the children can be customized
40 * using {@link SourceElementFilter}.
41 * {@link FilterCookie} is implemented to provide a means
42 * for user customization of the filter.
43 * <p>The child list listens to changes in the source element, as well as the filter, and
44 * automatically updates itself as appropriate.
45 * <p>A child factory can be used to cause the children list to create
46 * non-{@link DefaultFactory default} child nodes, if desired, both at the time of the creation
47 * of the children list, and when new children are added.
48 * <p>The children list may be unattached to any source element temporarily,
49 * in which case it will have no children (except possibly an error indicator).
50 *
51 * @author Dafe Simonek, Jan Jancura
52 */

53 public class SourceChildren extends Children.Keys implements FilterCookie {
54
55     /** The key describing state of source element */
56     static final Object JavaDoc NOT_KEY = new Object JavaDoc();
57     /** The key describing state of source element */
58     static final Object JavaDoc ERROR_KEY = new Object JavaDoc();
59     /** PACKAGE modifier support */
60     private static int PPP_MASK = SourceElementFilter.PUBLIC +
61             SourceElementFilter.PRIVATE +
62             SourceElementFilter.PROTECTED;
63
64     /** The element whose subelements are represented. */
65     protected SourceElement element;
66     /** Filter for elements. Can be <code>null</code>, in which case
67     * modifier filtering is disabled, and ordering may be reset to the default order. */

68     protected SourceElementFilter filter;
69     /** Factory for obtaining class nodes. */
70     protected ElementNodeFactory factory;
71     /** Weak listener to the element and filter changes */
72     private PropertyChangeListener JavaDoc wPropL;
73     /** Listener to the element and filter changes. This reference must
74     * be kept to prevent the listener from finalizing when we are alive */

75     private ElementListener propL;
76     /** Flag saying whether we have our nodes initialized */
77     private boolean nodesInited = false;
78
79
80     // init ................................................................................
81

82     /** Create a children list with the default factory and no attached source element.
83     */

84     public SourceChildren () {
85         this (DefaultFactory.READ_WRITE, null);
86     }
87
88     /** Create a children list with the default factory.
89     * @param element source element to attach to, or <code>null</code>
90     */

91     public SourceChildren (final SourceElement element) {
92         this(DefaultFactory.READ_WRITE, element);
93     }
94
95     /** Create a children list with no attached source element.
96     * @param factory a factory for creating children
97     */

98     public SourceChildren (final ElementNodeFactory factory) {
99         this(factory, null);
100     }
101
102     /** Create a children list.
103     * @param factory a factory for creating children
104     * @param element source element to attach to, or <code>null</code>
105     */

106     public SourceChildren (final ElementNodeFactory factory,
107                            final SourceElement element) {
108         super();
109         this.element = element;
110         this.factory = factory;
111         this.filter = new SourceElementFilter ();
112     }
113
114
115     // FilterCookie implementation .............................................................
116

117     /* @return The class of currently asociated filter or null
118     * if no filter is asociated with these children.
119     */

120     public Class JavaDoc getFilterClass () {
121         return SourceElementFilter.class;
122     }
123
124     /* @return The filter currently asociated with these children
125     */

126     public Object JavaDoc getFilter () {
127         return filter;
128     }
129
130     /* Sets new filter for these children.
131     * @param filter New filter. Null == disable filtering.
132     */

133     public void setFilter (final Object JavaDoc filter) {
134         if (!(filter instanceof SourceElementFilter))
135             throw new IllegalArgumentException JavaDoc();
136
137         this.filter = (SourceElementFilter)filter;
138         // change element nodes according to the new filter
139
if (nodesInited)
140             refreshKeys ();
141     }
142
143
144     // Children implementation ..............................................................
145

146     /* Overrides initNodes to run the preparation task of the
147     * source element, call refreshKeys and start to
148     * listen to the changes in the element too. */

149     protected void addNotify () {
150         if (element != null) {
151             // listen to the source element property changes
152
if (wPropL == null) {
153                 propL = new ElementListener();
154                 wPropL = WeakListeners.propertyChange(propL, element);
155             }
156             element.addPropertyChangeListener (wPropL);
157             element.prepare();
158         }
159         refreshKeys ();
160         nodesInited = true;
161     }
162
163     protected void removeNotify () {
164         setKeys (java.util.Collections.EMPTY_SET);
165         nodesInited = false;
166     }
167
168     /* Create nodes for given key.
169     * The node is created using node factory.
170     */

171     protected Node[] createNodes (final Object JavaDoc key) {
172         // find out the type of the key and create appropriate node
173
if (key instanceof ClassElement)
174             return new Node[] { factory.createClassNode((ClassElement)key) };
175         if (NOT_KEY.equals(key))
176             return new Node[] { factory.createWaitNode() };
177         // never should get here
178
return new Node[] { factory.createErrorNode() };
179     }
180
181     /**
182      * If `initialize' is true, invokes the parser and waits for it to finish.
183      * If false, it just returns whatever nodes are available right now.
184      * @return array of nodes after the Children are fully initialized
185      */

186     public Node[] getNodes(boolean initialize) {
187         SourceElement el = element;
188         if (!initialize || el == null) {
189             return super.getNodes();
190         }
191         org.openide.util.Task t = el.prepare();
192         Node[] result;
193
194         t.waitFinished();
195         refreshKeys();
196         result = getNodes();
197         t.isFinished();
198         return result;
199     }
200
201     /* Find a child node.
202     * First makes sure any pending parse is done.
203     */

204     public Node findChild (String JavaDoc name) {
205         Node supe = super.findChild (name);
206         if (supe != null) {
207             return supe;
208         } else {
209             if (element != null) {
210                 // this may seem strange, but keeping the Task live till the end of
211
// the method may help keeping the structure data in memory
212
// (they're referenced from the task most probably)
213
org.openide.util.Task t = element.prepare ();
214                 t.waitFinished ();
215                 refreshKeys ();
216                 Node n = super.findChild (name);
217                 t.isFinished();
218                 return n;
219             } else {
220                 return null;
221             }
222         }
223     }
224
225
226     // main public methods ..................................................................
227

228     /** Get the currently attached source element.
229     * @return the element, or <code>null</code> if unattached
230     */

231     public SourceElement getElement () {
232         return element;
233     }
234
235     /** Set a new source element to get information about children from.
236     * @param element the new element, or <code>null</code> to detach
237     */

238     public void setElement (final SourceElement element) {
239         if (this.element != null) {
240             this.element.removePropertyChangeListener(wPropL);
241         }
242         this.element = element;
243         if (this.element != null) {
244             if (wPropL == null) {
245                 propL = new ElementListener();
246                 wPropL = WeakListeners.propertyChange(propL, this.element);
247             }
248             this.element.addPropertyChangeListener(wPropL);
249         }
250         // change element nodes according to the new element
251
if (nodesInited) {
252             if (this.element != null) this.element.prepare();
253             refreshKeys ();
254         }
255     }
256
257     // other methods ..........................................................................
258

259     /** Refreshes the keys according to the current state of the element and
260     * filter etc.
261     * (This method is also called when the change of properties occurs either
262     * in the filter or in the element)
263     * PENDING - (for Hanz - should be implemented better, change only the
264     * keys which belong to the changed property).
265     * @param evt the event describing changed property (or null to signalize
266     * that all keys should be refreshed)
267     */

268     private void refreshKeys () {
269         int status = (element == null) ? SourceElement.STATUS_ERROR
270                      : element.getStatus();
271         switch (status) {
272         case SourceElement.STATUS_NOT:
273             setKeys(new Object JavaDoc[] { NOT_KEY });
274
275             // start parsing
276
element.prepare ();
277
278             break;
279         case SourceElement.STATUS_ERROR:
280             setKeys(new Object JavaDoc[] { ERROR_KEY });
281             break;
282         case SourceElement.STATUS_PARTIAL:
283         case SourceElement.STATUS_OK:
284             refreshAllKeys();
285             break;
286         }
287     }
288
289     /** Updates all the keys (elements) according to the current
290     * filter and ordering */

291     private void refreshAllKeys () {
292         int[] order = (filter == null || (filter.getOrder() == null))
293                       ? SourceElementFilter.DEFAULT_ORDER : filter.getOrder();
294
295         final LinkedList JavaDoc keys = new LinkedList JavaDoc();
296         // build ordered and filtered keys for the subelements
297
for (int i = 0; i < order.length; i++)
298             addKeysOfType(keys, order[i]);
299
300         // set new keys
301
org.openide.src.nodes.SourceChildren.this.setKeys(keys);
302     }
303
304     /** Filters and adds the keys of specified type to the given
305     * key collection.
306     */

307     private void addKeysOfType (Collection JavaDoc keys, final int elementType) {
308         if (elementType == SourceElementFilter.IMPORT) {
309             // PENDING imports are not solved yet...maybe ImportsChildren???
310
//keys.addAll(Arrays.asList(element.getImports()));
311
return;
312         } else {
313             List JavaDoc cls;
314             if ((filter != null) && filter.isAllClasses()) {
315                 cls = Arrays.asList (element.getAllClasses ());
316             } else {
317                 cls = Arrays.asList (element.getClasses ());
318             }
319             for (int i = 0; i < cls.size() ; i++) {
320                 ClassElement classElement = (ClassElement)cls.get (i);
321                 int modifiers = classElement.getModifiers ();
322                 if ((modifiers & PPP_MASK) == 0) modifiers += SourceElementFilter.PACKAGE;
323                 if ((filter.getModifiers () & modifiers) == 0) continue;
324                 if (classElement.isClass ()) {
325                     if ((elementType & SourceElementFilter.CLASS) != 0) keys.add (classElement);
326                 } else
327                     if ((elementType & SourceElementFilter.INTERFACE) != 0) keys.add (classElement);
328             }
329         }
330     }
331
332
333     // innerclasses ...........................................................................
334

335     /** The listener for listening to the property changes in the filter.
336     */

337     private final class ElementListener implements PropertyChangeListener JavaDoc {
338         public void propertyChange (PropertyChangeEvent JavaDoc evt) {
339             boolean refresh = ElementProperties.PROP_CLASSES.equals(evt.getPropertyName());
340             if (!refresh && ElementProperties.PROP_STATUS.equals(evt.getPropertyName())) {
341                 Integer JavaDoc val = (Integer JavaDoc) evt.getNewValue();
342                 refresh = ((val == null) || (val.intValue() != SourceElement.STATUS_NOT));
343             }
344         if (refresh)
345                 javax.swing.SwingUtilities.invokeLater(new Runnable JavaDoc() {
346                     public void run() {
347                         refreshKeys();
348                     }
349                 });
350         }
351
352     } // end of ElementListener inner class
353
}
354
Popular Tags