KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > nodes > BeanNode


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.nodes;
21
22 import java.awt.Image JavaDoc;
23 import java.beans.BeanDescriptor JavaDoc;
24 import java.beans.BeanInfo JavaDoc;
25 import java.beans.Beans JavaDoc;
26 import java.beans.Customizer JavaDoc;
27 import java.beans.EventSetDescriptor JavaDoc;
28 import java.beans.IndexedPropertyDescriptor JavaDoc;
29 import java.beans.IntrospectionException JavaDoc;
30 import java.beans.Introspector JavaDoc;
31 import java.beans.PropertyChangeEvent JavaDoc;
32 import java.beans.PropertyChangeListener JavaDoc;
33 import java.beans.PropertyDescriptor JavaDoc;
34 import java.beans.beancontext.BeanContext JavaDoc;
35 import java.beans.beancontext.BeanContextChild JavaDoc;
36 import java.beans.beancontext.BeanContextProxy JavaDoc;
37 import java.io.IOException JavaDoc;
38 import java.lang.reflect.Method JavaDoc;
39 import java.lang.reflect.Modifier JavaDoc;
40 import java.util.ArrayList JavaDoc;
41 import java.util.Enumeration JavaDoc;
42 import java.util.logging.Level JavaDoc;
43 import java.util.logging.Logger JavaDoc;
44 import javax.swing.Action JavaDoc;
45 import org.openide.util.Exceptions;
46 import org.openide.util.HelpCtx;
47 import org.openide.util.Utilities;
48 import org.openide.util.Lookup;
49 import org.openide.util.WeakListeners;
50 import org.openide.util.actions.SystemAction;
51
52 /**
53  * Represents a JavaBeans component as a node.
54 * <p>You may use this node type for an already-existing JavaBean (possibly
55 * using BeanContext) in order for its JavaBean properties to be reflected
56 * as corresponding node properties. Thus, it serves as a compatibility wrapper.
57 *
58 * @author Jan Jancura, Ian Formanek, Jaroslav Tulach
59  * @param T the type of bean to be represented
60 */

61 public class BeanNode<T> extends AbstractNode {
62     // static ..................................................................................................................
63

64     /** Icon base for bean nodes */
65     private static final String JavaDoc ICON_BASE = "org/openide/nodes/beans.gif"; // NOI18N
66

67     // variables .............................................................................................................
68

69     /** bean */
70     private final T bean;
71
72     /** bean info for the bean */
73     private BeanInfo JavaDoc beanInfo;
74
75     /** functions to operate on beans */
76     private Method JavaDoc nameGetter = null;
77     private Method JavaDoc nameSetter = null;
78
79     /** remove PropertyChangeListener method */
80     private Method JavaDoc removePCLMethod = null;
81
82     /** listener for properties */
83     private PropL propertyChangeListener = null;
84
85     /** is synchronization of name in progress */
86     private boolean synchronizeName;
87     
88     // init ..................................................................................................................
89

90     /**
91     * Constructs a node for a JavaBean. If the bean is a {@link BeanContext},
92     * creates a child list as well.
93     *
94     * @param bean the bean this node will be based on
95     * @throws IntrospectionException if the bean cannot be analyzed
96     */

97     public BeanNode(T bean) throws IntrospectionException JavaDoc {
98         this(bean, null, null);
99     }
100
101     /** Constructs a node for a JavaBean with a defined child list.
102     * Intended for use by subclasses with different strategies for computing the children.
103     * @param bean the bean this node will be based on
104     * @param children children for the node (default if null)
105     * @throws IntrospectionException if the bean cannot be analyzed
106     */

107     protected BeanNode(T bean, Children children)
108     throws IntrospectionException JavaDoc {
109         this(bean, children, null);
110     }
111
112     /** Constructs a node for a JavaBean.
113      * The subclass can provide its own {@link Children} implementation
114      * or leave the default implementation.
115      * It can also provide a Lookup, but if you provide one, please do not call
116      * methods {@link #getCookieSet} and {@link #setCookieSet} they will
117      * throw an exception.
118      * <p>More info on the correct usage of constructor with Lookup can be found
119      * in the {@link Node#Node(org.openide.nodes.Children, org.openide.util.Lookup)}
120      * javadoc.
121      *
122      * @param bean the bean this node will be based on
123      * @param children children for the node (default if null)
124      * @param lkp the lookup to provide content of {@link #getLookup}
125      * and also {@link #getCookie}
126      * @throws IntrospectionException if the bean cannot be analyzed
127      * @since 6.9
128      */

129     protected BeanNode(T bean, Children children, Lookup lkp)
130     throws IntrospectionException JavaDoc {
131         super((children == null) ? getChildren(bean) : children, lkp);
132
133         if (bean == null) {
134             throw new NullPointerException JavaDoc("cannot make a node for a null bean"); // NOI18N
135
}
136
137         this.bean = bean;
138
139         try {
140             initialization(lkp != null);
141         } catch (IntrospectionException JavaDoc ie) {
142             throw ie;
143         } catch (RuntimeException JavaDoc re) {
144             throw mkie(re);
145         } catch (LinkageError JavaDoc le) {
146             throw mkie(le);
147         }
148     }
149     
150     private static Children getChildren(Object JavaDoc bean) {
151         if (bean instanceof BeanContext JavaDoc) {
152             return new BeanChildren((BeanContext JavaDoc) bean);
153         }
154
155         if (bean instanceof BeanContextProxy JavaDoc) {
156             BeanContextChild JavaDoc bch = ((BeanContextProxy JavaDoc) bean).getBeanContextProxy();
157
158             if (bch instanceof BeanContext JavaDoc) {
159                 return new BeanChildren((BeanContext JavaDoc) bch);
160             }
161         }
162
163         return Children.LEAF;
164     }
165
166     private static IntrospectionException JavaDoc mkie(Throwable JavaDoc t) {
167         return (IntrospectionException JavaDoc) new IntrospectionException JavaDoc(t.toString()).initCause(t);
168     }
169
170     /** Set whether or not to keep the node name and Bean name synchronized automatically.
171     * If enabled, the node will listen to changes in the name of the bean
172     * and update the (system) name of the node appropriately. The name of the bean can
173     * be obtained by calling <code>getName ()</code>, <code>getDisplayName ()</code> or from {@link BeanDescriptor#getDisplayName}.
174     * <p>Also when the (system) name of the node is changing, the change propagates if possible to
175     * methods <code>setName (String)</code> or <code>setDisplayName (String)</code>. (This
176     * does not apply to setting the display name of the node, however.)
177     * <P>
178     * By default this feature is turned on.
179     *
180     * @param watch <code>true</code> if the name of the node should be synchronized with
181     * the name of the bean, <code>false</code> if the name of the node should be independent
182     * or manually updated
183     *
184     */

185     protected void setSynchronizeName(boolean watch) {
186         synchronizeName = watch;
187     }
188
189     /** Provides access to the bean represented by this BeanNode.
190     * @return instance of the bean represented by this BeanNode
191     */

192     protected T getBean() {
193         return bean;
194     }
195
196     /** Detaches all listeners from the bean and destroys it.
197     * @throws IOException if there was a problem
198     */

199     public void destroy() throws IOException JavaDoc {
200         if (removePCLMethod != null) {
201             try {
202                 Object JavaDoc o = Beans.getInstanceOf(bean, removePCLMethod.getDeclaringClass());
203                 removePCLMethod.invoke(o, new Object JavaDoc[] { propertyChangeListener });
204             } catch (Exception JavaDoc e) {
205                 NodeOp.exception(e);
206             }
207         }
208
209         super.destroy();
210     }
211
212     /** Can this node be removed?
213     * @return <CODE>true</CODE> in this implementation
214     */

215     public boolean canDestroy() {
216         return true;
217     }
218
219     /** Set the node name.
220     * Also may attempt to change the name of the bean,
221     * according to {@link #setSynchronizeName}.
222     * @param s the new name
223     */

224     public void setName(String JavaDoc s) {
225         if (synchronizeName) {
226             Method JavaDoc m = nameSetter;
227
228             if (m != null) {
229                 try {
230                     m.invoke(bean, new Object JavaDoc[] { s });
231                 } catch (Exception JavaDoc e) {
232                     NodeOp.exception(e);
233                 }
234             }
235         }
236
237         super.setName(s);
238     }
239
240     /** Can this node be renamed?
241     * @return <code>true</code> if there is no name synchronization, or there is
242     * a valid setter method for the name
243     */

244     public boolean canRename() {
245         return !synchronizeName || (nameSetter != null);
246     }
247
248     /** Get an icon for this node in the closed state.
249     * Uses the Bean's icon if possible.
250     *
251     * @param type constant from {@link java.beans.BeanInfo}
252     * @return icon to use
253     */

254     public Image JavaDoc getIcon(int type) {
255         Image JavaDoc image = beanInfo.getIcon(type);
256
257         if (image != null) {
258             return image;
259         }
260
261         return super.getIcon(type);
262     }
263
264     /** Get an icon for this node in the open state.
265     *
266     * @param type type constants
267     * @return icon to use. The default implementation just uses {@link #getIcon}.
268     */

269     public Image JavaDoc getOpenedIcon(int type) {
270         return getIcon(type);
271     }
272
273     public HelpCtx getHelpCtx() {
274         HelpCtx h = HelpCtx.findHelp(bean);
275
276         if (h != HelpCtx.DEFAULT_HELP) {
277             return h;
278         } else {
279             return new HelpCtx(BeanNode.class);
280         }
281     }
282
283     /** Prepare node properties based on the bean, storing them into the current property sheet.
284     * Called when the bean info is ready.
285     * This implementation always creates a set for standard properties
286     * and may create a set for expert ones if there are any.
287     * @see #computeProperties
288     * @param bean bean to compute properties for
289     * @param info information about the bean
290     */

291     protected void createProperties(T bean, BeanInfo JavaDoc info) {
292         Descriptor JavaDoc d = computeProperties(bean, beanInfo);
293
294         Sheet sets = getSheet();
295         Sheet.Set pset = Sheet.createPropertiesSet();
296         pset.put(d.property);
297
298         BeanDescriptor JavaDoc bd = info.getBeanDescriptor();
299
300         if ((bd != null) && (bd.getValue("propertiesHelpID") != null)) { // NOI18N
301
pset.setValue("helpID", bd.getValue("propertiesHelpID")); // NOI18N
302
}
303
304         sets.put(pset);
305
306         if (d.expert.length != 0) {
307             Sheet.Set eset = Sheet.createExpertSet();
308             eset.put(d.expert);
309
310             if ((bd != null) && (bd.getValue("expertHelpID") != null)) { // NOI18N
311
eset.setValue("helpID", bd.getValue("expertHelpID")); // NOI18N
312
}
313
314             sets.put(eset);
315         }
316     }
317
318     /** Can this node be copied?
319     * @return <code>true</code> in the default implementation
320     */

321     public boolean canCopy() {
322         return true;
323     }
324
325     /** Can this node be cut?
326     * @return <code>false</code> in the default implementation
327     */

328     public boolean canCut() {
329         return false;
330     }
331
332     public Action JavaDoc[] getActions(boolean context) {
333         return NodeOp.createFromNames(
334             new String JavaDoc[] { "Copy", null, "Tools", "Properties" // NOI18N
335
}
336         );
337     }
338
339     /* Test if there is a customizer for this node. If <CODE>true</CODE>
340     * the customizer can be obtained via <CODE>getCustomizer</CODE> method.
341     *
342     * @return <CODE>true</CODE> if there is a customizer.
343     */

344     public boolean hasCustomizer() {
345         // true if we have already computed beanInfo and it has customizer class
346
return beanInfo.getBeanDescriptor().getCustomizerClass() != null;
347     }
348
349     /* Returns the customizer component.
350     * @return the component or <CODE>null</CODE> if there is no customizer
351     */

352     public java.awt.Component JavaDoc getCustomizer() {
353         Class JavaDoc clazz = beanInfo.getBeanDescriptor().getCustomizerClass();
354
355         if (clazz == null) {
356             return null;
357         }
358
359         Object JavaDoc o;
360
361         try {
362             o = clazz.newInstance();
363         } catch (InstantiationException JavaDoc e) {
364             NodeOp.exception(e);
365
366             return null;
367         } catch (IllegalAccessException JavaDoc e) {
368             NodeOp.exception(e);
369
370             return null;
371         }
372
373         if (!(o instanceof Customizer JavaDoc)) {
374             // no customizer => no fun
375
// [PENDING] this ought to perform some sort of notification!
376
return null;
377         }
378
379         Customizer JavaDoc cust = ((Customizer JavaDoc) o);
380
381         TMUtil.attachCustomizer(this, cust);
382
383         // looking for the component
384
java.awt.Component JavaDoc comp = null;
385
386         if (o instanceof java.awt.Component JavaDoc) {
387             comp = (java.awt.Component JavaDoc) o;
388         } else {
389             // create the dialog from descriptor
390
comp = TMUtil.createDialog(o);
391         }
392
393         if (comp == null) {
394             // no component provided
395
return null;
396         }
397
398         cust.setObject(bean);
399
400         if (removePCLMethod == null) {
401             cust.addPropertyChangeListener(
402                 new PropertyChangeListener JavaDoc() {
403                     public void propertyChange(PropertyChangeEvent JavaDoc e) {
404                         firePropertyChange(e.getPropertyName(), e.getOldValue(), e.getNewValue());
405                     }
406                 }
407             );
408         }
409
410         return comp;
411     }
412
413     /** Computes a descriptor for properties from a bean info.
414     * <p>Property code names are taken from the property descriptor names
415      * according to the JavaBeans specification. For example, a pair of
416      * methods <code>getFoo</code> and <code>setFoo</code> would result in
417      * a node property with code name <code>foo</code>. If you call
418      * <code>MyBean.setFoo(...)</code>, this should result in a property
419      * change event with name <code>foo</code>; if you are using these
420      * properties in some other context (attached to something other than
421      * a <code>BeanNode</code>) then be careful to fire changes with the correct
422      * name, or there may be problems with refreshing display of the property etc.
423     * @param bean bean to create properties for
424     * @param info about the bean
425     * @return three property lists
426     */

427     public static Descriptor JavaDoc computeProperties(Object JavaDoc bean, BeanInfo JavaDoc info) {
428         ArrayList JavaDoc<Node.Property> property = new ArrayList JavaDoc<Node.Property>();
429         ArrayList JavaDoc<Node.Property> expert = new ArrayList JavaDoc<Node.Property>();
430         ArrayList JavaDoc<Node.Property> hidden = new ArrayList JavaDoc<Node.Property>();
431
432         PropertyDescriptor JavaDoc[] propertyDescriptor = info.getPropertyDescriptors();
433
434         int k = propertyDescriptor.length;
435
436         for (int i = 0; i < k; i++) {
437             if (propertyDescriptor[i].getPropertyType() == null) {
438                 continue;
439             }
440
441             Node.Property prop;
442
443             if (propertyDescriptor[i] instanceof IndexedPropertyDescriptor JavaDoc) {
444                 IndexedPropertyDescriptor JavaDoc p = (IndexedPropertyDescriptor JavaDoc) propertyDescriptor[i];
445
446                 if ((p.getReadMethod() != null) && (!p.getReadMethod().getReturnType().isArray())) {
447                     // this is fix for #17728. This situation should never happen
448
// But if the BeanInfo (IndexedPropertyDescriptor) is wrong
449
// we will ignore this property
450
continue;
451                 }
452
453                 IndexedPropertySupport support = new IndexedPropertySupport(
454                         bean, p.getPropertyType(), p.getIndexedPropertyType(), p.getReadMethod(), p.getWriteMethod(),
455                         p.getIndexedReadMethod(), p.getIndexedWriteMethod()
456                     );
457                 support.setName(p.getName());
458                 support.setDisplayName(p.getDisplayName());
459                 support.setShortDescription(p.getShortDescription());
460
461                 for (Enumeration JavaDoc e = p.attributeNames(); e.hasMoreElements();) {
462                     String JavaDoc aname = (String JavaDoc) e.nextElement();
463                     support.setValue(aname, p.getValue(aname));
464                 }
465
466                 prop = support;
467             } else {
468                 PropertyDescriptor JavaDoc p = propertyDescriptor[i];
469
470                 // Note that PS.R sets the method accessible even if it is e.g.
471
// defined as public in a package-accessible superclass.
472
PropertySupport.Reflection support = new PropertySupport.Reflection(
473                         bean, p.getPropertyType(), p.getReadMethod(), p.getWriteMethod()
474                     );
475                 support.setName(p.getName());
476                 support.setDisplayName(p.getDisplayName());
477                 support.setShortDescription(p.getShortDescription());
478                 support.setPropertyEditorClass(p.getPropertyEditorClass());
479
480                 for (Enumeration JavaDoc e = p.attributeNames(); e.hasMoreElements();) {
481                     String JavaDoc aname = (String JavaDoc) e.nextElement();
482                     support.setValue(aname, p.getValue(aname));
483                 }
484
485                 prop = support;
486             }
487
488             // Propagate helpID's.
489
Object JavaDoc help = propertyDescriptor[i].getValue("helpID"); // NOI18N
490

491             if ((help != null) && (help instanceof String JavaDoc)) {
492                 prop.setValue("helpID", help); // NOI18N
493
}
494
495             // Add to right category.
496
if (propertyDescriptor[i].isHidden()) {
497                 // hidden property
498
hidden.add(prop);
499             } else {
500                 if (propertyDescriptor[i].isExpert()) {
501                     expert.add(prop);
502                     prop.setExpert(true);
503                 } else {
504                     property.add(prop);
505                 }
506             }
507         }
508          // for
509

510         return new Descriptor JavaDoc(property, expert, hidden);
511     }
512
513     //
514
//
515
// Initialization methods
516
//
517
//
518

519     /** Performs initialization of the node
520     */

521     private void initialization(boolean hasLookup) throws IntrospectionException JavaDoc {
522         setIconBaseWithExtension(ICON_BASE);
523
524         setSynchronizeName(true);
525
526         // Find the first public superclass of the actual class.
527
// Should not introspect on a private class, because then the method objects
528
// used for the property descriptors will not be callable without an
529
// IllegalAccessException, even if overriding a public method from a public superclass.
530
Class JavaDoc clazz = bean.getClass();
531
532         while (!Modifier.isPublic(clazz.getModifiers()) && !hasExplicitBeanInfo(clazz)) {
533             clazz = clazz.getSuperclass();
534
535             if (clazz == null) {
536                 clazz = Object JavaDoc.class; // in case it was an interface
537
}
538         }
539
540         beanInfo = Utilities.getBeanInfo(clazz);
541
542         // resolving the name of this bean
543
registerName();
544         setNameSilently(getNameForBean());
545
546         BeanDescriptor JavaDoc descriptor = beanInfo.getBeanDescriptor();
547         String JavaDoc sd = descriptor.getShortDescription();
548
549         if (!Utilities.compareObjects(sd, descriptor.getDisplayName())) {
550             setShortDescription(sd);
551         }
552
553         // add propertyChangeListener
554
EventSetDescriptor JavaDoc[] eventSetDescriptors = beanInfo.getEventSetDescriptors();
555         int i;
556         int k = eventSetDescriptors.length;
557         Method JavaDoc method = null;
558
559         for (i = 0; i < k; i++) {
560             method = eventSetDescriptors[i].getAddListenerMethod();
561
562             if (
563                 (method != null) && method.getName().equals("addPropertyChangeListener") && // NOI18N
564
Modifier.isPublic(method.getModifiers())
565             ) {
566                 break;
567             }
568         }
569
570         if (i != k) {
571             try {
572                 Object JavaDoc o = Beans.getInstanceOf(bean, method.getDeclaringClass());
573                 propertyChangeListener = new PropL();
574                 method.invoke(o, new Object JavaDoc[] { WeakListeners.propertyChange(propertyChangeListener, o) });
575                 removePCLMethod = eventSetDescriptors[i].getRemoveListenerMethod();
576             } catch (Exception JavaDoc e) {
577                 // Warning, not info: likely to call e.g. getters or other things used
578
// during startup of the bean, so it is not good to swallow errors here
579
// (e.g. SharedClassObject.initialize throws RuntimeException -> it is
580
// caught here and probably someone wants to know).
581
Exceptions.attachMessage(e,
582                                          "Trying to invoke " + method +
583                                          " where introspected class is " +
584                                          clazz.getName()); // NOI18N
585
NodeOp.warning(e);
586             }
587         }
588
589         createProperties(bean, beanInfo);
590
591         for (Enumeration JavaDoc e = beanInfo.getBeanDescriptor().attributeNames(); e.hasMoreElements();) {
592             String JavaDoc aname = (String JavaDoc) e.nextElement();
593             setValue(aname, beanInfo.getBeanDescriptor().getValue(aname));
594         }
595
596         if (!hasLookup) {
597             Node.Cookie instanceCookie = TMUtil.createInstanceCookie(bean);
598
599             if (instanceCookie != null) {
600                 getCookieSet().add(instanceCookie);
601             }
602         }
603     }
604
605     /** Checks whether there is an explicit bean info for given class.
606     * @param clazz the class to test
607     * @return true if explicit bean info exists
608     */

609     private boolean hasExplicitBeanInfo(Class JavaDoc<?> clazz) {
610         String JavaDoc className = clazz.getName();
611         int indx = className.lastIndexOf('.');
612         className = className.substring(indx + 1);
613
614         String JavaDoc[] paths = Introspector.getBeanInfoSearchPath();
615
616         for (int i = 0; i < paths.length; i++) {
617             String JavaDoc s = paths[i] + '.' + className + "BeanInfo"; // NOI18N
618

619             try {
620                 // test if such class exists
621
Class.forName(s);
622
623                 return true;
624             } catch (ClassNotFoundException JavaDoc ex) {
625                 // OK, this is normal.
626
}
627         }
628
629         return false;
630     }
631
632     // name resolving methods
633

634     /**
635     * Finds setter and getter methods for the name of the bean. Resisters listener
636     * for changing of name.
637     */

638     private void registerName() {
639         // [PENDING] ought to use introspection, rather than look up the methods by name --jglick
640
Class JavaDoc<?> clazz = bean.getClass();
641
642         // Do not want to use getName, even if public, on a private class:
643
while (!Modifier.isPublic(clazz.getModifiers())) {
644             clazz = clazz.getSuperclass();
645
646             if (clazz == null) {
647                 clazz = Object JavaDoc.class;
648             }
649         }
650
651         // find getter for the name
652
try {
653             try {
654                 nameGetter = clazz.getMethod("getName"); // NOI18N
655

656                 if (nameGetter.getReturnType() != String JavaDoc.class) {
657                     throw new NoSuchMethodException JavaDoc();
658                 }
659             } catch (NoSuchMethodException JavaDoc e) {
660                 try {
661                     nameGetter = clazz.getMethod("getDisplayName"); // NOI18N
662

663                     if (nameGetter.getReturnType() != String JavaDoc.class) {
664                         throw new NoSuchMethodException JavaDoc();
665                     }
666                 } catch (NoSuchMethodException JavaDoc ee) {
667                     nameGetter = null;
668
669                     return;
670                 }
671             }
672         } catch (SecurityException JavaDoc se) {
673             NodeOp.exception(se);
674             nameGetter = null;
675
676             return;
677         }
678
679         // this code tests wheter everything is fine and the getter is
680
// invokable
681
try {
682             // make sure this is cast to String too:
683
String JavaDoc result = (String JavaDoc) nameGetter.invoke(bean);
684         } catch (Exception JavaDoc e) {
685             Exceptions.attachMessage(e,
686                                      "Bad method: " + clazz.getName() + "." +
687                                      nameGetter.getName());
688             Logger.getLogger(BeanNode.class.getName()).log(Level.WARNING, null, e);
689
690             nameGetter = null;
691
692             return;
693         }
694
695         // find the setter for the name
696
try {
697             try {
698                 // tries to find method setName (String)
699
nameSetter = clazz.getMethod("setName", String JavaDoc.class); // NOI18N
700

701                 if (nameSetter.getReturnType() != Void.TYPE) {
702                     throw new NoSuchMethodException JavaDoc();
703                 }
704             } catch (NoSuchMethodException JavaDoc e) {
705                 try {
706                     nameSetter = clazz.getMethod("setDisplayName", String JavaDoc.class); // NOI18N
707

708                     if (nameSetter.getReturnType() != Void.TYPE) {
709                         throw new NoSuchMethodException JavaDoc();
710                     }
711                 } catch (NoSuchMethodException JavaDoc ee) {
712                     nameSetter = null;
713                 }
714             }
715         } catch (SecurityException JavaDoc se) {
716             NodeOp.exception(se);
717         }
718     }
719
720     /**
721     * Returns name of the bean.
722     */

723     private String JavaDoc getNameForBean() {
724         if (nameGetter != null) {
725             try {
726                 String JavaDoc name = (String JavaDoc) nameGetter.invoke(bean);
727
728                 return (name != null) ? name : ""; // NOI18N
729
} catch (Exception JavaDoc ex) {
730                 NodeOp.warning(ex);
731             }
732         }
733
734         BeanDescriptor JavaDoc descriptor = beanInfo.getBeanDescriptor();
735
736         return descriptor.getDisplayName();
737     }
738
739     /** To allow inner classes to access the super.setName method.
740     */

741     void setNameSilently(String JavaDoc name) {
742         super.setName(name);
743     }
744
745     public Action JavaDoc getPreferredAction() {
746         // default action is org.openide.actions.PropertiesAction
747
SystemAction[] arr = NodeOp.createFromNames(new String JavaDoc[] { "Properties" }); // NOI18N
748

749         return (arr.length == 1) ? arr[0] : null;
750     }
751
752     /** Descriptor of three types of properties. Regular,
753     * expert and hidden.
754     */

755     public static final class Descriptor extends Object JavaDoc {
756         /** Regular properties. */
757         public final Node.Property[] property;
758
759         /** Expert properties. */
760         public final Node.Property[] expert;
761
762         /** Hidden properties. */
763         public final Node.Property[] hidden;
764
765         /** private constructor */
766         Descriptor(ArrayList JavaDoc<Node.Property> p, ArrayList JavaDoc<Node.Property> e, ArrayList JavaDoc<Node.Property> h) {
767             property = new Node.Property[p.size()];
768             p.toArray(property);
769
770             expert = new Node.Property[e.size()];
771             e.toArray(expert);
772
773             hidden = new Node.Property[h.size()];
774             h.toArray(hidden);
775         }
776     }
777
778     /** Property change listener to update the properties of the node and
779     * also the name of the node (sometimes)
780     */

781     private final class PropL extends Object JavaDoc implements PropertyChangeListener JavaDoc {
782         PropL() {
783         }
784
785         public void propertyChange(PropertyChangeEvent JavaDoc e) {
786             String JavaDoc name = e.getPropertyName();
787
788             if (name == null) {
789                 firePropertyChange(null, e.getOldValue(), e.getNewValue());
790             } else {
791                 PropertyDescriptor JavaDoc[] arr = beanInfo.getPropertyDescriptors();
792
793                 for (int i = 0; i < arr.length; i++) {
794                     if (arr[i].isHidden()) {
795                         continue;
796                     }
797
798                     if (name.equals(arr[i].getName())) {
799                         firePropertyChange(e.getPropertyName(), e.getOldValue(), e.getNewValue());
800
801                         break;
802                     }
803                 }
804             }
805
806             if (synchronizeName) {
807                 if ((name == null) || name.equals("name") || name.equals("displayName")) { // NOI18N
808

809                     String JavaDoc newName = getNameForBean();
810
811                     if (!newName.equals(getName())) {
812                         setNameSilently(newName);
813                     }
814                 }
815             }
816         }
817     }
818 }
819
Popular Tags