KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > ui > nodes > PackageNode


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;
21
22 import java.beans.*;
23 import java.util.*;
24
25 import org.openide.cookies.SourceCookie;
26
27 import org.openide.loaders.DataObject;
28
29 import org.openide.nodes.AbstractNode;
30 import org.openide.nodes.Children;
31 import org.openide.nodes.Node;
32
33 import org.openide.src.*;
34 import org.openide.src.nodes.ClassElementNode;
35
36 import org.openide.util.Task;
37 import org.openide.util.TaskListener;
38 import org.openide.util.WeakListeners;
39
40 import org.netbeans.api.java.comparators.JavaElementComparator;
41 import org.netbeans.modules.java.tools.MultiDataContainer;
42
43 /**
44  * This node represents a single package. It is configured from an
45  * DataObject.Container and tries to visualize its contents:
46  * <UL>
47  * <LI> Any DataObject.Container found within the supplied container is
48  * processed as a sub-package. If several Containers are found with the same
49  * name, they are merged under the sub-package node.
50  * <LI> Any other DataObject is queried for its SourceCokie, if it yields something,
51  * the nodes produced from the SourceCookie are sorted into the node's direct children.
52  * </UL>
53  *
54  * @author sd99038
55  * @version 0.1
56  */

57 public final class PackageNode extends AbstractNode {
58     /**
59      * Icons used to present the node.
60      */

61     private static final String JavaDoc PACKAGE_ICON_BASE = "org/netbeans/modules/java/resources/package"; // NOI18N
62

63     /**
64      * The default format for displaying class element nodes.
65      */

66     private static final ElementFormat CLASS_ELEMENT_FORMAT = new ElementFormat("{C}"); // NOI18N
67

68     /**
69      * Comparator for sorting classes - it compares class FQNs
70      */

71     private static final Comparator CLASS_NAME_COMPARATOR =
72                 JavaElementComparator.createClassComparator(
73                     false, new int[] {
74                         JavaElementComparator.NAME
75                     });
76     /**
77      * Initializes a node representing the given Container.
78      */

79     public PackageNode(String JavaDoc packName, MultiDataContainer container) {
80         super(new PackageChildren(container));
81         setName(packName);
82         setIconBase(PACKAGE_ICON_BASE);
83     }
84     
85     /**
86      * A specialized Children class that produces two node types - PackageNodes
87      * for sub-packages and ClassElementNodes for classes accepted by the filter.
88      */

89     private static class PackageChildren extends Children.Keys implements
90         PropertyChangeListener {
91         /**
92          * Container that represents package's contents.
93          */

94         MultiDataContainer container;
95         
96         /**
97          * Sorted collection of ClassElements contained within the package.
98          */

99         Collection classElements;
100
101         /**
102          * Collection of sources that have been already seen/parsed.
103          */

104         Collection parsingSources;
105         
106         /**
107          * Holds a weak property change listener to the Container and to the
108          * produced SourceElements.
109          */

110         PropertyChangeListener weakListener;
111
112         PackageChildren(MultiDataContainer cont) {
113             this.container = cont;
114             this.classElements = new TreeSet(CLASS_NAME_COMPARATOR);
115             this.parsingSources = new LinkedList();
116             weakListener = WeakListeners.propertyChange(this, null);
117             cont.addPropertyChangeListener(weakListener);
118         }
119         
120         public void addNotify() {
121             refreshData();
122         }
123        
124         /**
125          * Creates nodes for either ClassElements or sub-packages. Other
126          * data type are not supported nor expected.
127          */

128         protected Node[] createNodes(Object JavaDoc key) {
129             if (key instanceof ClassElement) {
130                 Node n = createClassNode((ClassElement)key);
131                 if (n != null)
132                     return new Node[] { n };
133             } else if (key instanceof String JavaDoc) {
134                 String JavaDoc name = (String JavaDoc)key;
135                 MultiDataContainer cont = getPackageContainer(name);
136                 if (cont != null) {
137                     return new Node[] {
138                         createPackageNode((String JavaDoc)key, cont)
139                     };
140                 }
141             }
142             return new Node[0];
143         }
144         
145         /**
146          * Called when some source finishes parsing task. The method sorts the
147          * class elements into the list of classes already recognized.
148          */

149         private void sortInClasses(ClassElement[] cls) {
150             synchronized (this) {
151                 classElements.addAll(Arrays.asList(cls));
152             }
153             refreshKeys();
154         }
155
156         /**
157          * Forces a refresh of children nodes
158          */

159         private void refreshKeys() {
160             Collection containers = container.getContainers().keySet();
161             Collection keys = new ArrayList(containers.size() + classElements.size());
162             keys.addAll(containers);
163             synchronized (this) {
164                 keys.addAll(classElements);
165             }
166             setKeys(keys);
167         }
168         
169         /**
170          * Creates a node for this class, if it passed the filter.
171          */

172         protected final Node createClassNode(ClassElement c) {
173             ClassElementNode node = new ClassElementNode(c, Children.LEAF, true);
174             node.setElementFormat(CLASS_ELEMENT_FORMAT);
175             return node;
176         }
177
178         /**
179          * Creates a package node from a String. It uses the parent's package
180          * data to extract appropriate container from the data.
181          */

182         protected final Node createPackageNode(String JavaDoc name, MultiDataContainer data) {
183             return new PackageNode(name, data);
184         }
185         
186         private MultiDataContainer getPackageContainer(String JavaDoc name) {
187             return (MultiDataContainer)this.container.getContainers().get(name);
188         }
189         
190         /**
191          * Refreshes content of the node from the represented Container. The method
192          * schedules parsing on sources which are not yet parsed and attaches a listener
193          * on them. Source which are already parsed are queried for classes they contain
194          * The method builds up class list of those classes. ClassElements from the
195          * objects which are being parsed on background will be filled in after
196          * the parsing task finishes.
197          */

198         private void refreshData() {
199             DataObject[] contents = container.getChildren();
200             Collection myChildren = new ArrayList(contents.length);
201             Collection newClassElements = new ArrayList(contents.length);
202             
203             for (int i = 0; i < contents.length; i++) {
204                 DataObject d = contents[i];
205                 
206                 SourceCookie ck = (SourceCookie)d.getCookie(SourceCookie.class);
207                 if (ck != null) {
208                     SourceElement src = ck.getSource();
209                     if (parsingSources.add(src)) {
210                         src.addPropertyChangeListener(weakListener);
211                         if (src.getStatus() == SourceElement.STATUS_NOT) {
212                             TaskListener l = new PrepareL(d, src);
213                             src.prepare().addTaskListener(l);
214                         } else {
215                             synchronized (this) {
216                                 newClassElements.addAll(Arrays.asList(src.getAllClasses()));
217                             }
218                         }
219                     }
220                 }
221             }
222             synchronized (this) {
223                 classElements = newClassElements;
224             }
225             refreshKeys();
226         }
227         
228         public void propertyChange(PropertyChangeEvent evt) {
229             Object JavaDoc source = evt.getSource();
230             String JavaDoc propName = evt.getPropertyName();
231             
232             if (source == container) {
233                 if (MultiDataContainer.PROP_CONTAINERS.equals(propName) ||
234                     MultiDataContainer.PROP_CHILDREN.equals(propName)) {
235                     refreshData();
236                 }
237             } else {
238                 if (ElementProperties.PROP_ALL_CLASSES.equals(evt.getPropertyName())) {
239                     refreshData();
240                 }
241             }
242         }
243         
244         /**
245          * Listener that watches parsing tasks. TODO - it should also watch
246          * PROP_CLASSES changes on sources already registered :)
247          */

248         private class PrepareL implements TaskListener {
249             DataObject sourceDO;
250             SourceElement srcElement;
251             
252             PrepareL(DataObject source, SourceElement src) {
253                 this.sourceDO = source;
254                 this.srcElement = src;
255             }
256             
257             public void taskFinished(Task t) {
258                 t.removeTaskListener(this);
259                 sortInClasses(srcElement.getAllClasses());
260             }
261         }
262     }
263 }
264
Popular Tags