KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > ui > nodes > elements > ClassChildren


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.modules.java.ui.nodes.elements;
21
22 import java.util.*;
23
24 import org.openide.nodes.Children;
25 import org.openide.nodes.Node;
26 import org.openide.nodes.FilterNode;
27 import org.openide.cookies.FilterCookie;
28 import org.openide.src.ElementProperties;
29 import org.openide.ErrorManager;
30 import org.netbeans.jmi.javamodel.*;
31 import org.netbeans.modules.java.ui.nodes.SourceNodeFactory;
32 import org.netbeans.modules.javacore.internalapi.JavaMetamodel;
33 import org.netbeans.api.mdr.events.MDRChangeListener;
34 import org.netbeans.api.mdr.events.MDRChangeEvent;
35 import org.netbeans.api.mdr.events.AttributeEvent;
36 import org.netbeans.api.mdr.events.MDRChangeSource;
37
38 import javax.jmi.reflect.JmiException;
39 import javax.jmi.reflect.InvalidObjectException;
40
41 /** Normal implementation of children list for a class element node.
42 * @author Dafe Simonek, Jan Jancura, Jan Pokorsky
43 */

44 public class ClassChildren extends Children.Keys implements FilterCookie, ChildrenProvider.KeyHandler {
45
46     /** Support for PACKAGE modifier */
47     private static int PPP_MASK = SourceElementFilter.PUBLIC + SourceElementFilter.PRIVATE + SourceElementFilter.PROTECTED;
48     /** Converts property names to filter.
49      * XXX seems to be obsolete and can be removed; investigate Categories.FILTER_CATEGORIES
50      */

51     protected static HashMap propToFilter;
52
53     /** For sorting groups of elements. */
54     private static Comparator comparator = new Comparator() {
55                 public int compare(Object JavaDoc o1, Object JavaDoc o2) {
56                     if (o1 instanceof NamedElement)
57                         if (o2 instanceof NamedElement) {
58                             String JavaDoc o1Name = getName((NamedElement) o1);
59                             String JavaDoc o2Name = getName((NamedElement) o2);
60                             if (o1Name==null || o2Name==null) return 1;
61                             return o1Name.compareToIgnoreCase(o2Name);
62                         } else
63                             return -1;
64                     else
65                         if (o2 instanceof NamedElement)
66                             return 1;
67                         else
68                             return 0;
69                 }
70         
71                 private String JavaDoc getName(NamedElement el) {
72                     String JavaDoc name;
73                     if (el instanceof Constructor) {
74                         name = ((Constructor) el).getDeclaringClass().getName();
75                     } else if (el instanceof Initializer) {
76                         name = ""; // NOI18N
77
} else {
78                         name = el.getName();
79                     }
80                     return name;
81                 }
82             };
83
84     static {
85         propToFilter = new HashMap ();
86         propToFilter.put (ElementProperties.PROP_CLASSES, new Integer JavaDoc (ClassElementFilter.CLASS | ClassElementFilter.INTERFACE));
87         propToFilter.put (ElementProperties.PROP_METHODS, new Integer JavaDoc (ClassElementFilter.METHOD));
88         propToFilter.put (ElementProperties.PROP_FIELDS, new Integer JavaDoc (ClassElementFilter.FIELD));
89         propToFilter.put (ElementProperties.PROP_CONSTRUCTORS, new Integer JavaDoc (ClassElementFilter.CONSTRUCTOR));
90         propToFilter.put (ElementProperties.PROP_INITIALIZERS, new Integer JavaDoc (ClassElementFilter.CONSTRUCTOR));
91     }
92
93     /** The class element whose subelements are represented. */
94     protected ClassDefinition element;
95     /** Filter for elements, or <code>null</code> to disable. */
96     protected ClassElementFilter filter;
97     /** Factory for creating new child nodes. */
98     private SourceNodeFactory factory;
99     /**Weak listener to the element and filter changes. This reference must
100     * be kept to prevent the listener from finalizing when we are alive */

101     private JMIElementListener wPropL;
102     /** Flag saying whether we have our nodes initialized */
103     private boolean nodesInited = false;
104     private final ChildrenProvider chprovider = new ChildrenProvider(this);
105
106
107     // init ................................................................................
108

109     /** Create class children.
110     * The children are initially unfiltered.
111     * @param factory the factory to use to create new children
112     * @param element attached class element (non-<code>null</code>)
113     */

114     public ClassChildren(SourceNodeFactory factory, ClassDefinition element) {
115         if (factory == null) throw new NullPointerException JavaDoc("factory"); // NOI18N
116
if (element == null) throw new NullPointerException JavaDoc("element"); // NOI18N
117
this.element = element;
118         this.factory = factory;
119         this.filter = null;
120     }
121
122     protected SourceNodeFactory getFactory() {
123         return this.factory;
124     }
125
126     /********** Implementation of filter cookie **********/
127
128     /* @return The class of currently asociated filter or null
129     * if no filter is asociated with these children.
130     */

131     public Class JavaDoc getFilterClass () {
132         return ClassElementFilter.class;
133     }
134
135     /* @return The filter currently asociated with these children
136     */

137     public Object JavaDoc getFilter () {
138         return filter;
139     }
140
141     /* Sets new filter for these children.
142     * @param filter New filter. Null == disable filtering.
143     */

144     public void setFilter (final Object JavaDoc filter) {
145         if (!(filter instanceof ClassElementFilter))
146             throw new IllegalArgumentException JavaDoc();
147
148         this.filter = (ClassElementFilter)filter;
149         // change element nodes according to the new filter
150
if (nodesInited)
151             refreshAllKeys ();
152     }
153
154
155     // Children implementation ..............................................................
156

157     /* Overrides initNodes to run the preparation task of the
158     * source element, call refreshKeys and start to
159     * listen to the changes in the element too. */

160     protected void addNotify () {
161         super.addNotify();
162         // listen to the changes in the class element
163
if (wPropL == null) {
164             wPropL = new JMIElementListener(this);
165         }
166         refreshAllKeys ();
167         ((MDRChangeSource) element).addListener(wPropL);
168         nodesInited = true;
169     }
170
171     protected void removeNotify () {
172         chprovider.clear();
173         nodesInited = false;
174         super.removeNotify();
175     }
176     
177     protected final void hookNodeName(Element el) {
178         if (el instanceof MDRChangeSource) {
179             ((MDRChangeSource) el).addListener(wPropL);
180         }
181     }
182
183     /* Creates node for given key.
184     * The node is created using node factory.
185     */

186     protected final Node[] createNodes(Object JavaDoc key) {
187         Node[] nodes;
188         if (key instanceof Node) {
189             nodes = new Node[] {new FilterNode((Node) key)};
190         } else if (key instanceof Node[]) {
191             Node[] ns = (Node[]) key;
192             nodes = new Node[ns.length];
193             for (int i = 0; i < ns.length; i++) {
194                 Node orig = ns[i];
195                 nodes[i] = orig == null? orig: new FilterNode(orig);
196             }
197         } else {
198             nodes = new Node[] {factory.createErrorNode()};
199             ErrorManager.getDefault().notify(
200                     ErrorManager.WARNING,
201                     new IllegalStateException JavaDoc("key: " + key) // NOI18N
202
);
203         }
204         return nodes;
205     }
206     
207     protected Node[] createNodesImpl(Object JavaDoc key) throws JmiException {
208         Node n;
209         if (key instanceof Method) {
210             Method m = (Method) key;
211             hookNodeName(m);
212             n = factory.createMethodNode(m);
213         } else if (key instanceof Field) {
214             Field f = (Field) key;
215             hookNodeName(f);
216             n = factory.createFieldNode(f);
217         } else if (key instanceof Constructor) {
218             // does not change its name; it is always null
219
n = factory.createConstructorNode((Constructor) key);
220         } else if (key instanceof JavaEnum) {
221             JavaEnum en = (JavaEnum) key;
222             hookNodeName(en);
223             n = factory.createEnumNode(en);
224         } else if (key instanceof AnnotationType) {
225             AnnotationType at = (AnnotationType) key;
226             hookNodeName(at);
227             n = factory.createAnnotationTypeNode(at);
228         } else if (key instanceof JavaClass) {
229             JavaClass jc = (JavaClass) key;
230             hookNodeName(jc);
231             n = factory.createClassNode(jc);
232         } else if (key instanceof Initializer) {
233             // does not change its name; it is always null
234
n = factory.createInitializerNode((Initializer) key);
235         } else {
236             // ?? unknown type
237
n = factory.createErrorNode();
238         }
239         return new Node[] {n};
240     }
241
242     public final List collectKeys() {
243         List keys = new LinkedList();
244         int[] order = getOrder ();
245         try {
246             JavaMetamodel.getDefaultRepository().beginTrans(false);
247             try {
248                 if (!element.isValid()) {
249                     return keys;
250                 }
251                 List features = element.getFeatures();
252         
253                 List members = new ArrayList(features.size());
254                 filterModifiers(features, members);
255                 
256                 for (int i = 0; i < order.length; i++) {
257                     List keysOfType = getKeysOfType(members, order[i]);
258                     if ((this.filter == null) || this.filter.isSorted ()) {
259                         Collections.sort(keysOfType, comparator);
260                     }
261                     keys.addAll(keysOfType);
262                 }
263             } finally {
264                 JavaMetamodel.getDefaultRepository().endTrans();
265             }
266         } catch (InvalidObjectException ex) {
267             // some element is invalid. MDR will notify listeners about that change later
268
keys = Collections.EMPTY_LIST;
269         } catch (JmiException ex) {
270             ErrorManager.getDefault().notify(ErrorManager.WARNING, ex);
271         }
272         return keys;
273     }
274
275     public Node[] prepareNodes(Object JavaDoc key) {
276         return createNodesImpl(key);
277     }
278
279     public void presentKeys(List/*<Element>*/ keys, List/*<Node[]>*/ nodes) {
280         JMIElementListener l = wPropL;
281         if (l != null)
282             l.updateElements(keys);
283         setKeys(nodes);
284     }
285
286     public Node[] getNodes(boolean optimalResult) {
287         if (!optimalResult) {
288             return getNodes();
289         }
290         chprovider.waitFinished();
291         return getNodes();
292     }
293
294     public Node findChild(String JavaDoc name) {
295         Node n = super.findChild(name);
296         if (n == null) {
297             chprovider.waitFinished();
298             n = super.findChild(name);
299         }
300         return n;
301     }
302     
303     /************** utility methods ************/
304
305     /** Updates all the keys (elements) according to the current filter &
306     * ordering.
307     */

308     protected void refreshAllKeys() {
309         refreshKeys(ClassElementFilter.ALL);
310     }
311
312     /** Updates all the keys with given filter.
313     */

314     protected final void refreshKeys(int filter) {
315         if (!doRefresh(filter)) return;
316         chprovider.recomputeChildren();
317     }
318     
319     private boolean doRefresh(int filter) {
320         int[] order = getOrder();
321         for (int i = order.length - 1; i >= 0 ; i--) {
322             if ((order[i] & filter) != 0) {
323                 return true;
324             }
325         }
326         return false;
327     }
328     
329     /** Filters and returns the keys of specified type.
330     */

331     protected List getKeysOfType(Collection/*<ClassMemeber>*/ elements, final int elementType) {
332         List keys = new LinkedList();
333         if ((elementType & ClassElementFilter.EXTENDS) != 0) {
334             keys.add(element.getSuperClass());
335         }
336         if ((elementType & ClassElementFilter.IMPLEMENTS) != 0) {
337             keys.addAll(element.getInterfaces());
338         }
339         
340         Iterator it = elements.iterator();
341         while (it.hasNext()) {
342             Object JavaDoc member = it.next();
343             if ((elementType & ClassElementFilter.FIELD) != 0 && member instanceof Field && !(member instanceof EnumConstant)) {
344                 keys.add(member);
345             } else if ((elementType & ClassElementFilter.CONSTRUCTOR) != 0 &&
346                     (member instanceof Constructor || member instanceof Initializer)) {
347                 keys.add(member);
348             } else if ((elementType & ClassElementFilter.METHOD) != 0 && member instanceof Method) {
349                 keys.add(member);
350             }
351             if (member instanceof JavaClass) {
352                 boolean isInterface = ((JavaClass) member).isInterface();
353                 if ((elementType & ClassElementFilter.CLASS) != 0 && !isInterface) {
354                     keys.add(member);
355                 } else if ((elementType & ClassElementFilter.INTERFACE) != 0 && isInterface) {
356                     keys.add(member);
357                 }
358             }
359         }
360         
361         return keys;
362     }
363
364     /** Returns order form filter.
365     */

366     protected int[] getOrder () {
367         return (filter == null || (filter.getOrder() == null))
368                ? ClassElementFilter.DEFAULT_ORDER : filter.getOrder();
369     }
370
371     /** Returns modifier filter form filter.
372     */

373     private int getModifierFilter () {
374         if (filter == null) return ClassElementFilter.ALL_MODIFIERS;
375         return filter.getModifiers ();
376     }
377
378     /** Filters ClassMember for modifiers, and adds them to the given collection.
379     */

380     private void filterModifiers(Collection/*<ClassMember>*/ elements, Collection keys) {
381         int ff = getModifierFilter();
382         for (Iterator it = elements.iterator(); it.hasNext();) {
383             ClassMember element = (ClassMember) it.next();
384             int f = element.getModifiers();
385             if ((f & PPP_MASK) == 0) f += ClassElementFilter.PACKAGE;
386             if ((f & ff) != 0) keys.add(element);
387             
388         }
389     }
390
391     // innerclasses ...........................................................................
392

393     /** The listener for listening to the property changes in the filter.
394     */

395     private static final class JMIElementListener extends java.lang.ref.WeakReference JavaDoc implements Runnable JavaDoc, MDRChangeListener {
396         Collection elements;
397         MDRChangeSource celem;
398
399         JMIElementListener(ClassChildren cc) {
400             super(cc, org.openide.util.Utilities.activeReferenceQueue());
401             celem = (MDRChangeSource) cc.element;
402         }
403
404         ClassChildren getClassChildren() {
405             Object JavaDoc o = get();
406             return (ClassChildren) o;
407         }
408
409
410         public void change(MDRChangeEvent e) {
411             int filter;
412             final Object JavaDoc src = e.getSource();
413             
414             if ((src instanceof Element) && !((Element) src).isValid()) {
415                 return;
416             }
417             
418             ClassChildren cc = getClassChildren();
419             if (cc == null || !(e instanceof AttributeEvent))
420                 return;
421
422             AttributeEvent evt = (AttributeEvent) e;
423             String JavaDoc propName = evt.getAttributeName();
424             
425 // System.out.println(">>> Children listener: " + propName + ", cc: " + cc);
426
// String snode = cc.getNode().getClass().getName() + "@" + System.identityHashCode(cc.getNode());
427
// System.out.println("## MDRChangeEvent.node: " + snode);
428
// System.out.println("## ...MDRChangeEvent: " + e);
429
// if (e.isOfType(AttributeEvent.EVENTMASK_ATTRIBUTE)) {
430
// AttributeEvent ae = (AttributeEvent) e;
431
// System.out.println(" ## AttributeEvent.src: " + src.getClass().getName() + "@" + System.identityHashCode(this));
432
// System.out.println(" ## AttributeEvent.name: " + ae.getAttributeName());
433
// System.out.println(" ## AttributeEvent.old: " + ae.getOldElement());
434
// System.out.println(" ## AttributeEvent.new: " + ae.getNewElement());
435
// }
436
// System.out.println("----------------------------------------");
437

438             if (src != cc.element) {
439                 if (src instanceof Element &&
440                         (propName == null || ElementProperties.PROP_NAME == propName)) {
441                     filter = chooseFilter((Element) src);
442 // System.out.println(">>> FILTER due to name");
443
} else
444                     return;
445             } else if ("contents".equals(propName)) { // NOI18N
446
Element cm = (Element) evt.getOldElement();
447                 cm = (cm == null)? (Element) evt.getNewElement(): cm;
448                 filter = chooseFilter(cm);
449 // System.out.println(">>> FILTER due to content");
450
} else if ("constants".equals(propName)) { // NOI18N
451
filter = EnumFilter.CONSTANTS;
452             } else {
453                 return;
454 // Integer i = (Integer) cc.propToFilter.get(propName);
455
// if (i == null)
456
// return;
457
// filter = i.intValue();
458
}
459             if (cc.nodesInited) {
460                 cc.refreshKeys (filter);
461             }
462         }
463         
464         int chooseFilter(Element src) {
465             int filter;
466             if (src instanceof Method)
467                 filter = ClassElementFilter.METHOD;
468             else if ((src instanceof Constructor) || (src instanceof Initializer))
469                 filter = ClassElementFilter.CONSTRUCTOR;
470             else if (src instanceof Field)
471                 filter = ClassElementFilter.FIELD;
472             else if (src instanceof EnumConstant)
473                 filter = EnumFilter.CONSTANTS;
474             else if (src instanceof Attribute)
475                 filter = AnnotationTypeFilter.MEMBER;
476             else
477                 filter = ClassElementFilter.CLASS | ClassElementFilter.INTERFACE |
478                         EnumFilter.ENUM | AnnotationTypeFilter.ANNOTATION_TYPE;
479             return filter;
480         }
481
482         // see also hookNodeName
483
void updateElements(Collection c) {
484             Collection old = this.elements;
485             if (old != null) {
486                 old.removeAll(c);
487                 removeListeners(old);
488             }
489             this.elements = c;
490         }
491
492         public void run() {
493             // clean-up
494
celem.removeListener(this);
495             removeListeners(this.elements);
496         }
497         
498         private void removeListeners(Collection c) {
499             for (Iterator it = c.iterator(); it.hasNext(); ) {
500                 Object JavaDoc o = it.next();
501                 if (!(o instanceof MDRChangeSource))
502                     continue;
503                 MDRChangeSource el = (MDRChangeSource) o;
504                 el.removeListener(this);
505             }
506         }
507     } // end of JMIElementListener inner class
508

509 }
510
Popular Tags