KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > apisupport > beanbrowser > WrapperKids


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.apisupport.beanbrowser;
21
22 import java.awt.Container JavaDoc;
23 import java.awt.datatransfer.Clipboard JavaDoc;
24 import java.beans.IntrospectionException JavaDoc;
25 import java.beans.PropertyChangeEvent JavaDoc;
26 import java.beans.PropertyChangeListener JavaDoc;
27 import java.io.File JavaDoc;
28 import java.lang.reflect.Method JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Collection JavaDoc;
31 import java.util.Collections JavaDoc;
32 import java.util.LinkedList JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.StringTokenizer JavaDoc;
35 import org.openide.ErrorManager;
36 import org.openide.cookies.InstanceCookie;
37 import org.openide.filesystems.FileObject;
38 import org.openide.filesystems.FileSystem;
39 import org.openide.filesystems.LocalFileSystem;
40 import org.openide.filesystems.MultiFileSystem;
41 import org.openide.filesystems.XMLFileSystem;
42 import org.openide.loaders.DataObject;
43 import org.openide.nodes.AbstractNode;
44 import org.openide.nodes.BeanNode;
45 import org.openide.nodes.Children;
46 import org.openide.nodes.FilterNode;
47 import org.openide.nodes.Node;
48 import org.openide.nodes.NodeAdapter;
49 import org.openide.nodes.NodeListener;
50 import org.openide.nodes.NodeMemberEvent;
51 import org.openide.nodes.NodeReorderEvent;
52 import org.openide.util.HelpCtx;
53 import org.openide.util.Lookup;
54 import org.openide.util.lookup.Lookups;
55
56 /** The fun stuff.
57  * Represents all the children of a wrapper node, including
58  * lots of special items for certain node types.
59  */

60 class WrapperKids extends Children.Keys implements Cloneable JavaDoc {
61     
62     // Special keys:
63
private static final Object JavaDoc instanceKey = new Object JavaDoc() {
64         public String JavaDoc toString() {
65             return "Key for instance cookie.";
66         }
67     };
68     private static final Object JavaDoc rawBeanPropsKey = new Object JavaDoc() {
69         public String JavaDoc toString() {
70             return "Key for raw bean properties.";
71         }
72     };
73     private static final class NormalChildKey {
74         private final Node child;
75         public NormalChildKey(Node child) {
76             this.child = child;
77         }
78         public Node wrap() {
79             return Wrapper.make(child);
80         }
81     }
82     private static final class LookupProviderKey {
83         public final Lookup.Provider p;
84         public LookupProviderKey(Lookup.Provider p) {
85             this.p = p;
86         }
87     }
88     
89     private Node original;
90     private NodeListener nListener = null;
91     private PropertyChangeListener JavaDoc fsListener = null;
92     private FileSystem fileSystemToListenOn = null;
93     
94     WrapperKids(Node orig) {
95         original = orig;
96     }
97     // Probably not needed:
98
public Object JavaDoc clone() {
99         return new WrapperKids(original);
100     }
101     
102     /** Update all keys.
103      * Keys may be:
104      * <ol>
105      * <li> normalKey, for the original node's children.
106      * <li> A node property set--i.e. Properties, Expert.
107      * <li> instanceKey, if it is an instance.
108      * <li> A {@link Method} for cookies, representing the method to get a cookie from the object.
109      * <li> Itself (the instance) if a Node, Container, FileSystem, FileObject, or Clipboard.
110      * </ol>
111      */

112     private void updateKeys(final boolean addListeners) {
113         //Thread.dumpStack ();
114
//System.err.println ("original's class: " + original.getClass ().getName ());
115
Children.MUTEX.postWriteRequest(new Runnable JavaDoc() { public void run() {
116             List JavaDoc newkeys = new ArrayList JavaDoc();
117             Node[] children = original.getChildren().getNodes(/*intentionally:*/false);
118             for (int i = 0; i < children.length; i++) {
119                 newkeys.add(new NormalChildKey(children[i]));
120             }
121             newkeys.addAll(makePSKeys());
122             // For BeanNode, we assume that we already are displaying the "instance" right here anyway.
123
if (! (original instanceof BeanNode) && original.getCookie(InstanceCookie.class) != null)
124                 newkeys.add(instanceKey);
125             // BeanNode's which are actually representing interesting objects:
126
if (original instanceof BeanNode) {
127                 newkeys.add(rawBeanPropsKey);
128                 try {
129                     InstanceCookie cookie = (InstanceCookie) original.getCookie(InstanceCookie.class);
130                     Object JavaDoc instance = cookie.instanceCreate();
131                     Class JavaDoc[] recognized = { Node.class, Container JavaDoc.class, FileSystem.class, FileObject.class, Clipboard JavaDoc.class };
132                     for (int i = 0; i < recognized.length; i++)
133                         if (recognized[i].isInstance(instance))
134                             newkeys.add(instance);
135                     // Special listener handling:
136
if (instance instanceof FileSystem)
137                         fileSystemToListenOn = (FileSystem) instance;
138                     if (instance instanceof Lookup.Provider) {
139                         newkeys.add(new LookupProviderKey((Lookup.Provider)instance));
140                     }
141                 } catch (Exception JavaDoc e) {
142                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
143                 }
144             } else {
145                 newkeys.add(new LookupProviderKey(original));
146             }
147             setKeys(newkeys);
148             //System.err.println ("Setting keys for wrapper of " + original.getDisplayName () + "; count: " + newkeys.size ());
149
if (addListeners) {
150                 nListener = new NodeAdapter() {
151                     public void propertyChange(PropertyChangeEvent JavaDoc ev) {
152                         if (Node.PROP_PROPERTY_SETS.equals(ev.getPropertyName())) {
153                             updateKeys(false);
154                         }
155                     }
156                     // Could instead override filterChildren* methods:
157
public void childrenAdded(NodeMemberEvent ev) {
158                         updateKeys(false);
159                     }
160                     public void childrenRemoved(NodeMemberEvent ev) {
161                         updateKeys(false);
162                     }
163                     public void childrenReordered(NodeReorderEvent ev) {
164                         updateKeys(false);
165                     }
166                 };
167                 original.addNodeListener(nListener);
168                 if (fileSystemToListenOn != null) {
169                     fsListener = new PropertyChangeListener JavaDoc() {
170                         public void propertyChange(PropertyChangeEvent JavaDoc ev) {
171                             if (FileSystem.PROP_ROOT.equals(ev.getPropertyName())) {
172                                 updateKeys(false);
173                             }
174                         }
175                     };
176                     fileSystemToListenOn.addPropertyChangeListener(fsListener);
177                 }
178             }
179         }});
180     }
181     
182     /** Set the keys and attach a listener to the original node.
183      * If its list of children is changed, the normalKey
184      * may be added or removed.
185      */

186     protected void addNotify() {
187         //System.err.println ("addNotify called for wrapper of " + original.getDisplayName ());
188
updateKeys(true);
189     }
190     
191     protected void removeNotify() {
192         if (nListener != null) {
193             original.removeNodeListener(nListener);
194             nListener = null;
195         }
196         if (fsListener != null) {
197             fileSystemToListenOn.removePropertyChangeListener(fsListener);
198             fsListener = null;
199             fileSystemToListenOn = null;
200         }
201         setKeys(Collections.EMPTY_SET);
202     }
203     
204     /** Make a list of property set keys.
205      * One key (a Node.PropertySet) is added for every property set
206      * which contains at least one property which is not a primitive
207      * or of String or Class type.
208      * <p> Note that it is possible for a property to be of e.g. Object type,
209      * and have a displayed node, even though the actual value is a String, e.g.
210      * @return a list of keys
211      */

212     private Collection JavaDoc makePSKeys() {
213         Collection JavaDoc toret = new ArrayList JavaDoc();
214         Node.PropertySet[] pss = original.getPropertySets();
215         for (int i = 0; i < pss.length; i++) {
216             Node.PropertySet ps = pss[i];
217             Node.Property[] props = ps.getProperties();
218             boolean useme = false;
219             for (int j = 0; j < props.length; j++) {
220                 Node.Property prop = props[j];
221                 if (prop.canRead()) {
222                     Class JavaDoc type = prop.getValueType();
223                     if (! (type.isPrimitive() || type == String JavaDoc.class || type == Class JavaDoc.class)) {
224                         useme = true;
225                     }
226                 }
227             }
228             if (useme) toret.add(ps);
229         }
230         return toret;
231     }
232     
233     /** Actual interpret a key.
234      * Creates a node representing each key, e.g. a BeanNode for instanceKey,
235      * or for a Node.PropertySet, a PropSet node.
236      * @param key the key to interpret
237      * @return the (one) node to display for it
238      */

239     protected Node[] createNodes(Object JavaDoc key) {
240         if (key instanceof NormalChildKey) {
241             return new Node[] {((NormalChildKey) key).wrap()};
242         } else if (key instanceof Node.PropertySet) {
243             // A property set with subnodes for the properties.
244
return new Node[] { new PropSet(original, (Node.PropertySet) key) };
245         } else if (key == rawBeanPropsKey) {
246             // Raw bean properties, unfiltered by BeanInfo etc.
247
try {
248                 InstanceCookie inst = (InstanceCookie) original.getCookie(InstanceCookie.class);
249                 AbstractNode n = new AbstractNode(new RawBeanPropKids(inst.instanceCreate())) {
250                     public HelpCtx getHelpCtx() {
251                         return new HelpCtx("org.netbeans.modules.apisupport.beanbrowser");
252                     }
253                 };
254                 n.setName("Raw bean properties...");
255                 n.setIconBaseWithExtension("org/netbeans/modules/apisupport/beanbrowser/BeanBrowserIcon.gif");
256                 return new Node[] { n };
257             } catch (Exception JavaDoc e) {
258                 return new Node[] { Wrapper.make(PropSetKids.makeErrorNode(e)) };
259             }
260         } else if (key == instanceKey) {
261             // Something which can provide an instance object--e.g. the deserialized object
262
// from a .ser file.
263
try {
264                 InstanceCookie inst = (InstanceCookie) original.getCookie(InstanceCookie.class);
265                 Node node = new RefinedBeanNode(inst.instanceCreate());
266                 node.setShortDescription("Instance name: `" + inst.instanceName() +
267                         "'; normal node name: `" + node.getDisplayName() + "'; normal description: `" +
268                         node.getShortDescription() + "'");
269                 node.setDisplayName("Instance of class " + inst.instanceClass().getName());
270                 return new Node[] { Wrapper.make(node) };
271             } catch (Exception JavaDoc e) {
272                 return new Node[] { Wrapper.make(PropSetKids.makeErrorNode(e)) };
273             }
274         } else if (key instanceof Node) {
275             List JavaDoc toret = new LinkedList JavaDoc(); // List<Node>
276
// Show the actual node itself.
277
AbstractNode marker = new AbstractNode(new Children.Array()) {
278                 public HelpCtx getHelpCtx() {
279                     return new HelpCtx("org.netbeans.modules.apisupport.beanbrowser");
280                 }
281             };
282             marker.setName("An actual node here:");
283             marker.setIconBaseWithExtension("org/netbeans/modules/apisupport/beanbrowser/BeanBrowserIcon.gif");
284             marker.getChildren().add(new Node[] { Wrapper.make((Node) key) });
285             toret.add(marker);
286             if (key instanceof FilterNode) {
287                 // Try to separately show the original too:
288
try {
289                     Method JavaDoc m = FilterNode.class.getDeclaredMethod("getOriginal", new Class JavaDoc[] { });
290                     m.setAccessible(true);
291                     try {
292                         Node orig = (Node) m.invoke(key, new Object JavaDoc[] { });
293                         AbstractNode marker2 = new AbstractNode(new Children.Array()) {
294                             public HelpCtx getHelpCtx() {
295                                 return new HelpCtx("org.netbeans.modules.apisupport.beanbrowser");
296                             }
297                         };
298                         marker2.setName("The original from the filter node:");
299                         marker2.setIconBaseWithExtension("org/netbeans/modules/apisupport/beanbrowser/BeanBrowserIcon.gif");
300                         marker2.getChildren().add(new Node[] { PropSetKids.makeObjectNode(orig) });
301                         toret.add(marker2);
302                     } finally {
303                         m.setAccessible(false);
304                     }
305                 } catch (Exception JavaDoc e) {
306                     toret.add(Wrapper.make(PropSetKids.makeErrorNode(e)));
307                 }
308             }
309             return (Node[]) toret.toArray(new Node[toret.size()]);
310             // XXX should show getActions(true/false) rather than getActions()/getContextActions()
311
} else if (key instanceof Container JavaDoc) {
312             // An AWT Container with its subcomponents.
313
Children kids = new ContainerKids((Container JavaDoc) key);
314             AbstractNode n = new AbstractNode(kids) {
315                 public HelpCtx getHelpCtx() {
316                     return new HelpCtx("org.netbeans.modules.apisupport.beanbrowser");
317                 }
318             };
319             n.setName("Components...");
320             n.setIconBaseWithExtension("org/netbeans/modules/apisupport/beanbrowser/BeanBrowserIcon.gif");
321             return new Node[] { n };
322         } else if (key instanceof FileSystem) {
323             // "root" is not a declared Bean property of FileSystem's, so specially display it.
324
try {
325                 Node fsn = new RefinedBeanNode(((FileSystem) key).getRoot());
326                 fsn.setDisplayName("[root] " + fsn.getDisplayName());
327                 return new Node[] { Wrapper.make(fsn) };
328             } catch (IntrospectionException JavaDoc e) {
329                 return new Node[] { Wrapper.make(PropSetKids.makeErrorNode(e)) };
330             }
331         } else if (key instanceof FileObject) {
332             FileObject fo = (FileObject)key;
333             // Try to show: data object; attributes; possibly provenance.
334
List JavaDoc l = new LinkedList JavaDoc(); // List<Node>
335
// Display the corresponding DataObject.
336
// The node delegate is also available as a Bean property of the DO.
337
try {
338                 Node fsn = new RefinedBeanNode(DataObject.find(fo));
339                 fsn.setDisplayName("[data object] " + fsn.getDisplayName());
340                 l.add(Wrapper.make(fsn));
341             } catch (Exception JavaDoc e) { // DataObjectNotFoundException, IntrospectionException
342
l.add(Wrapper.make(PropSetKids.makeErrorNode(e)));
343             }
344             Children kids = new FileAttrKids(fo);
345             AbstractNode attrnode = new AbstractNode(kids) {
346                 public HelpCtx getHelpCtx() {
347                     return new HelpCtx("org.netbeans.modules.apisupport.beanbrowser");
348                 }
349             };
350             attrnode.setName("Attributes...");
351             attrnode.setIconBaseWithExtension("org/netbeans/modules/apisupport/beanbrowser/BeanBrowserIcon.gif");
352             l.add(attrnode);
353             try {
354                 FileSystem apparentFS = fo.getFileSystem();
355                 if (apparentFS instanceof MultiFileSystem) {
356                     // #18698: try to show provenance of the file object.
357
FileSystem fs = apparentFS;
358                     FileObject workingFO = fo;
359                     boolean project = false;
360                     while (fs instanceof MultiFileSystem) {
361                         if (fs.getClass().getName().equals("org.netbeans.core.projects.FilterFileSystem")) {
362                             // We could traverse it to the original filesystem, but that would
363
// be the $userdir/system/ LFS, which is not what we want to see.
364
project = true;
365                             break;
366                         }
367                         Method JavaDoc m = MultiFileSystem.class.getDeclaredMethod("findSystem", new Class JavaDoc[] {FileObject.class});
368                         m.setAccessible(true);
369                         try {
370                             //FileObject workingFO = fs.findResource(path);
371
FileSystem foundFS = (FileSystem)m.invoke(fs, new Object JavaDoc[] {workingFO});
372                             if (foundFS == fs) {
373                                 // no delegate
374
//System.err.println("no delegate for " + workingFO + " on " + fs);
375
break;
376                             } else {
377                                 Method JavaDoc m2 = MultiFileSystem.class.getDeclaredMethod("findResourceOn", new Class JavaDoc[] {FileSystem.class, String JavaDoc.class});
378                                 m2.setAccessible(true);
379                                 try {
380                                     FileObject newFO = (FileObject)m2.invoke(fs, new Object JavaDoc[] {foundFS, workingFO.getPath()});
381                                     if (newFO != null) {
382                                         //System.err.println("delegating " + fs + "/" + workingFO + " -> " + foundFS + "/" + newFO);
383
fs = foundFS;
384                                         workingFO = newFO;
385                                     } else {
386                                         //System.err.println("findResourceOn for " + fs + " with " + foundFS + " and " + workingFO + " -> null");
387
}
388                                 } finally {
389                                     m2.setAccessible(false);
390                                 }
391                             }
392                         } finally {
393                             m.setAccessible(false);
394                         }
395                     }
396                     if (project || fs != apparentFS) {
397                         String JavaDoc provenance = null;
398                         if (project) {
399                             provenance = "project";
400                         } else if (fs instanceof LocalFileSystem) {
401                             File JavaDoc dir = ((LocalFileSystem)fs).getRootDirectory();
402                             // #27151: netbeans.dirs
403
StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(System.getProperty("netbeans.dirs", ""), File.pathSeparator);
404                             while (tok.hasMoreTokens()) {
405                                 File JavaDoc system = new File JavaDoc(new File JavaDoc(tok.nextToken()), "system"); // NOI18N
406
if (dir.equals(system)) {
407                                     provenance = "NetBeans installation";
408                                     break;
409                                 }
410                             }
411                             if (provenance == null) {
412                                 File JavaDoc system1 = new File JavaDoc(new File JavaDoc(System.getProperty("netbeans.home")), "system");
413                                 File JavaDoc system2 = new File JavaDoc(new File JavaDoc(System.getProperty("netbeans.user")), "system");
414                                 if (dir.equals(system1)) {
415                                     provenance = "NetBeans installation";
416                                 } else if (dir.equals(system2)) {
417                                     provenance = "user directory";
418                                 }
419                             }
420                         } else if (fs instanceof XMLFileSystem) {
421                             // Well, a good guess at least. Note merged XMLFS's and
422
// module cache mean we cannot easily do better.
423
provenance = "module";
424                         }
425                         if (provenance != null) {
426                             //System.err.println("filesystem: " + fs + " path: " + workingFO);
427
l.add(PropSetKids.makePlainNode("Provenance: " + provenance));
428                         } else {
429                             // No well-known origin, just show the FS.
430
Node rfsn = new RefinedBeanNode(fs);
431                             rfsn.setDisplayName("[original file system] " + rfsn.getDisplayName());
432                             l.add(Wrapper.make(rfsn));
433                         }
434                     }
435                 }
436             } catch (Exception JavaDoc e) {
437                 l.add(Wrapper.make(PropSetKids.makeErrorNode(e)));
438             }
439             return (Node[])l.toArray(new Node[l.size()]);
440         } else if (key instanceof Clipboard JavaDoc) {
441             Children kids = new ClipboardKids((Clipboard JavaDoc) key);
442             AbstractNode n = new AbstractNode(kids) {
443                 public HelpCtx getHelpCtx() {
444                     return new HelpCtx("org.netbeans.modules.apisupport.beanbrowser");
445                 }
446             };
447             n.setName("Transferables...");
448             n.setIconBaseWithExtension("org/netbeans/modules/apisupport/beanbrowser/BeanBrowserIcon.gif");
449             return new Node[] { n };
450         } else if (key instanceof LookupProviderKey) { // #26617
451
Node n = LookupNode.localLookupNode(Lookups.proxy(((LookupProviderKey) key).p));
452             n.setDisplayName("Cookies...");
453             return new Node[] { n };
454         } else {
455             throw new RuntimeException JavaDoc("Weird key: " + key);
456         }
457     }
458     
459 }
460
Popular Tags