KickJava   Java API By Example, From Geeks To Geeks.

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


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 package org.openide.nodes;
20
21 import org.openide.util.HelpCtx;
22 import org.openide.util.Lookup;
23 import org.openide.util.Utilities;
24 import org.openide.util.actions.SystemAction;
25 import org.openide.util.datatransfer.*;
26
27 import java.awt.Image JavaDoc;
28 import java.awt.datatransfer.Transferable JavaDoc;
29
30 import java.beans.PropertyChangeEvent JavaDoc;
31 import java.beans.PropertyChangeListener JavaDoc;
32
33 import java.io.IOException JavaDoc;
34
35 import java.text.MessageFormat JavaDoc;
36
37 import java.util.*;
38
39 import javax.swing.Action JavaDoc;
40 import javax.swing.event.ChangeEvent JavaDoc;
41 import javax.swing.event.ChangeListener JavaDoc;
42 import org.openide.util.Exceptions;
43
44
45 /** A basic implementation of a node.
46 *
47 * <p>It simplifies creation of the display name, based on a message
48 * format and the system name. It also simplifies working with icons:
49 * one need only specify the base name and all icons will be loaded
50 * when needed. Other common requirements are handled as well.
51 *
52 * @author Jaroslav Tulach */

53 public class AbstractNode extends Node {
54     /** messages to create a resource identification for each type of
55     * icon from the base name for the icon.
56     */

57     private static final String JavaDoc[] icons = {
58         
59         // color 16x16
60
"", // NOI18N
61

62         // color 32x32
63
"32", // NOI18N
64

65         // mono 16x16
66
"", // NOI18N
67

68         // mono 32x32
69
"32", // NOI18N
70

71         // opened color 16x16
72
"Open", // NOI18N
73

74         // opened color 32x32
75
"Open32", // NOI18N
76

77         // opened mono 16x16
78
"Open", // NOI18N
79

80         // opened mono 32x32
81
"Open32" // NOI18N
82
};
83
84     /** To index normal icon from previous array use
85     * + ICON_BASE.
86     */

87     private static final int ICON_BASE = -1;
88
89     /** for indexing opened icons */
90     private static final int OPENED_ICON_BASE = 3;
91
92     /** empty array of paste types */
93     private static final PasteType[] NO_PASTE_TYPES = { };
94
95     /** empty array of new types */
96     private static final NewType[] NO_NEW_TYPES = { };
97
98     /** default icon base for all nodes */
99     private static final String JavaDoc DEFAULT_ICON_BASE = "org/openide/nodes/defaultNode"; // NOI18N
100
private static final String JavaDoc DEFAULT_ICON_EXTENSION = ".gif"; // NOI18N
101
private static final String JavaDoc DEFAULT_ICON = DEFAULT_ICON_BASE + DEFAULT_ICON_EXTENSION; // NOI18N
102

103     // maps class either to Boolean or to this
104
private static final WeakHashMap<Class JavaDoc, Object JavaDoc> overridesGetDefaultAction = new WeakHashMap<Class JavaDoc, Object JavaDoc>(32);
105
106     /** Message format to use for creation of the display name.
107     * It permits conversion of text from
108     * {@link #getName} to the one sent to {@link #setDisplayName}. The format can take
109     * one parameter, <code>{0}</code>, which will be filled by a value from <CODE>getName()</CODE>.
110     *
111     * <p>The default format just uses the simple name; subclasses may
112     * change it, though it will not take effect until the next {@link #setName} call.
113     *
114     * <p>Can be set to <CODE>null</CODE>. Then there is no connection between the
115     * name and display name; they may be independently modified. */

116     protected MessageFormat JavaDoc displayFormat;
117
118     /** Preferred action */
119     private Action preferredAction;
120
121     /** Resource base for icons (without suffix denoting right icon) */
122     private String JavaDoc iconBase = DEFAULT_ICON_BASE;
123
124     /** Resource extension for icons */
125     private String JavaDoc iconExtension = DEFAULT_ICON_EXTENSION;
126     
127     /** array of cookies for this node */
128     private Object JavaDoc lookup;
129
130     /** set of properties to use */
131     private Sheet sheet;
132
133     /** Actions for the node. They are used only for the pop-up menus
134      * of this node.
135      * @deprecated Override {@link #getActions(boolean)} instead of using
136      * this field.
137      */

138     @Deprecated JavaDoc protected SystemAction[] systemActions;
139     private SheetAndCookieListener sheetCookieL = null;
140
141     /** Create a new abstract node with a given child set.
142     * @param children the children to use for this node
143     */

144     public AbstractNode(Children children) {
145         this(children, null);
146     }
147
148     /** Create a new abstract node with a given child set and associated
149     * lookup. If you use this constructor, please do not call methods
150     * {@link #getCookieSet} and {@link #setCookieSet} they will throw an
151     * exception.
152     * <p>
153     * More info on the correct usage of constructor with Lookup can be found
154     * in the {@link Node#Node(org.openide.nodes.Children, org.openide.util.Lookup)}
155     * javadoc.
156     *
157     * @param children the children to use for this node
158     * @param lookup the lookup to provide content of {@link #getLookup}
159     * and also {@link #getCookie}
160     * @since 3.11
161     */

162     public AbstractNode(Children children, Lookup lookup) {
163         super(children, lookup);
164
165         // Setting the name to non-null value for the node
166
// to return "reasonable" name and displayName
167
// not using this.setName since the descendants
168
// can override it and might assume that it is
169
// not called from constructor (see e.g. DataNode)
170
super.setName(""); // NOI18N
171
}
172     
173     /** Fake node constructor with given CookieSet
174      */

175     AbstractNode(CookieSet set) {
176         super(Children.LEAF);
177         lookup = set;
178     }
179
180     /** Clone the node. If the object implements {@link Cloneable},
181     * that is used; otherwise a {@link FilterNode filter node}
182     * is created.
183     *
184     * @return copy of this node
185     */

186     public Node cloneNode() {
187         try {
188             if (this instanceof Cloneable JavaDoc) {
189                 return (Node) clone();
190             }
191         } catch (CloneNotSupportedException JavaDoc ex) {
192         }
193
194         return new FilterNode(this);
195     }
196
197     /** Set the system name. Fires a property change event.
198     * Also may change the display name according to {@link #displayFormat}.
199     *
200     * @param s the new name
201     */

202     public void setName(String JavaDoc s) {
203         super.setName(s);
204
205         MessageFormat JavaDoc mf = displayFormat;
206
207         if (mf != null) {
208             setDisplayName(mf.format(new Object JavaDoc[] { s }));
209         } else {
210             // additional hack, because if no display name is set, then it
211
// is taken from the getName, that means calling setName can
212
// also change display name
213
// fix of 10665
214
fireDisplayNameChange(null, null);
215         }
216     }
217
218     /** Change the icon.
219     * One need only specify the base resource name without extension;
220     * the real name of the icon is obtained by the applying icon message
221     * formats.
222     *
223     * The method effectively behaves as if it was just delegating
224     * to {@link #setIconBaseWithExtension(java.lang.String)}
225     * using <code>base + ".gif"</code> as parameter.
226     *
227     * @param base base resouce name (no initial slash)
228     * @deprecated Use {@link #setIconBaseWithExtension(java.lang.String)}
229     */

230     @Deprecated JavaDoc
231     public void setIconBase(String JavaDoc base) {
232         setIconBaseWithExtension(base, DEFAULT_ICON_EXTENSION);
233     }
234
235     /** Change the icon.
236     * One need only specify the base name of the icon resource,
237     * including the resource extension; the real name of the icon is obtained
238     * by inserting proper infixes into the resource name.
239     *
240     * <p>For example, for the base <code>org/foo/resource/MyIcon.png</code>
241     * the following images may be used according to the icon
242     * state and {@link java.beans.BeanInfo#getIcon presentation type}:
243     *
244     * <ul>
245     * <li><code>org/foo/resource/MyIcon.png</code>
246     * <li><code>org/foo/resource/MyIconOpen.png</code>
247     * <li><code>org/foo/resource/MyIcon32.png</code>
248     * <li><code>org/foo/resource/MyIconOpen32.png</code></ul>
249     *
250     * <P>
251     * This method may be used to dynamically switch between different sets
252     * of icons for different configurations. If the set is changed,
253     * an icon property change event is fired.
254     *
255     * @param baseExt base resouce name with extension (no initial slash)
256     * @since org.openide.nodes 6.5
257     */

258     public final void setIconBaseWithExtension(String JavaDoc baseExt) {
259         int lastDot = baseExt.lastIndexOf('.');
260         int lastSlash = baseExt.lastIndexOf('/');
261         
262         if ((lastSlash > lastDot) || (lastDot == -1)) { // no .extension
263
setIconBaseWithExtension(baseExt, "");
264         } else {
265             String JavaDoc base = baseExt.substring(0, lastDot);
266             String JavaDoc ext = baseExt.substring(lastDot);
267             setIconBaseWithExtension(base, ext);
268         }
269
270     }
271
272     /** Change the icon. */
273     private final void setIconBaseWithExtension(String JavaDoc base, String JavaDoc extension) {
274         if (base.equals(iconBase) && extension.equals(iconExtension)) {
275             return;
276         }
277
278         this.iconBase = base;
279         this.iconExtension = extension;
280         fireIconChange();
281         fireOpenedIconChange();
282     }
283
284     
285
286     /** Find an icon for this node. Uses an {@link #setIconBase icon set}.
287     *
288     * @param type constants from {@link java.beans.BeanInfo}
289     *
290     * @return icon to use to represent the bean
291     */

292     public Image JavaDoc getIcon(int type) {
293         return findIcon(type, ICON_BASE);
294     }
295
296     /** Finds an icon for this node when opened. This icon should represent the node
297     * only when it is opened (when it can have children).
298     *
299     * @param type as in {@link #getIcon}
300     * @return icon to use to represent the bean when opened
301     */

302     public Image JavaDoc getOpenedIcon(int type) {
303         return findIcon(type, OPENED_ICON_BASE);
304     }
305
306     public HelpCtx getHelpCtx() {
307         return HelpCtx.DEFAULT_HELP;
308     }
309
310     /** Tries to find the right icon for the iconbase.
311     * @param type type of icon (from BeanInfo constants)
312     * @param ib base where to scan in the array
313     */

314     private Image JavaDoc findIcon(int type, int ib) {
315         String JavaDoc res = iconBase + icons[type + ib] + iconExtension;
316         Image JavaDoc im = Utilities.loadImage(res, true);
317
318         if (im != null) {
319             return im;
320         }
321
322         // try the first icon
323
res = iconBase + icons[java.beans.BeanInfo.ICON_COLOR_16x16 + ib] + iconExtension;
324
325         im = Utilities.loadImage(res, true);
326
327         if (im != null) {
328             return im;
329         }
330
331         if (ib == OPENED_ICON_BASE) {
332             // try closed icon also
333
return findIcon(type, ICON_BASE);
334         }
335
336         // if still not found return default icon
337
return getDefaultIcon();
338     }
339
340     Image JavaDoc getDefaultIcon() {
341         Image JavaDoc i = Utilities.loadImage(DEFAULT_ICON, true);
342
343         if (i == null) {
344             throw new MissingResourceException("No default icon", "", DEFAULT_ICON); // NOI18N
345
}
346
347         return i;
348     }
349
350     /** Can this node be renamed?
351     * @return <code>false</code>
352     */

353     public boolean canRename() {
354         return false;
355     }
356
357     /** Can this node be destroyed?
358     * @return <CODE>false</CODE>
359     */

360     public boolean canDestroy() {
361         return false;
362     }
363
364     /** Set the set of properties.
365     * A listener is attached to the provided sheet
366     * and any change of the sheet is propagated to the node by
367     * firing a {@link #PROP_PROPERTY_SETS} change event.
368     *
369     * @param s the sheet to use
370     */

371     protected final synchronized void setSheet(Sheet s) {
372         setSheetImpl(s);
373         firePropertySetsChange(null, null);
374     }
375
376     private synchronized void setSheetImpl(Sheet s) {
377         if (sheetCookieL == null) {
378             sheetCookieL = new SheetAndCookieListener();
379         }
380
381         if (sheet != null) {
382             sheet.removePropertyChangeListener(sheetCookieL);
383         }
384
385         s.addPropertyChangeListener(sheetCookieL);
386         sheet = s;
387     }
388
389     /** Initialize a default
390     * property sheet; commonly overridden. If {@link #getSheet}
391     * is called and there is not yet a sheet,
392     * this method is called to allow a subclass
393     * to specify its properties.
394     * <P>
395     * <em>Warning:</em> Do not call <code>getSheet</code> in this method.
396     * <P>
397     * The default implementation returns an empty sheet.
398     *
399     * @return the sheet with initialized values (never <code>null</code>)
400     */

401     protected Sheet createSheet() {
402         return new Sheet();
403     }
404
405     /** Get the current property sheet. If the sheet has been
406      * previously set by a call to {@link #setSheet}, that sheet
407      * is returned. Otherwise {@link #createSheet} is called.
408      *
409      * @return the sheet (never <code>null</code>)
410      */

411     protected final synchronized Sheet getSheet() {
412         if (sheet != null) {
413             return sheet;
414         }
415
416         setSheetImpl(createSheet());
417
418         return sheet;
419     }
420
421     /** Get a list of property sets.
422     *
423     * @return the property sets for this node
424     * @see #getSheet
425     */

426     public PropertySet[] getPropertySets() {
427         Sheet s = getSheet();
428
429         return s.toArray();
430     }
431
432     boolean propertySetsAreKnown() {
433         return (sheet != null);
434     }
435
436     /** Copy this node to the clipboard.
437     *
438     * @return {@link org.openide.util.datatransfer.ExTransferable.Single} with one copy flavor
439     * @throws IOException if it could not copy
440     * @see NodeTransfer
441     */

442     public Transferable JavaDoc clipboardCopy() throws IOException JavaDoc {
443         return NodeTransfer.transferable(this, NodeTransfer.CLIPBOARD_COPY);
444     }
445
446     /** Cut this node to the clipboard.
447     *
448     * @return {@link org.openide.util.datatransfer.ExTransferable.Single} with one cut flavor
449     * @throws IOException if it could not cut
450     * @see NodeTransfer
451     */

452     public Transferable JavaDoc clipboardCut() throws IOException JavaDoc {
453         return NodeTransfer.transferable(this, NodeTransfer.CLIPBOARD_CUT);
454     }
455
456     /**
457     * This implementation only calls clipboardCopy supposing that
458     * copy to clipboard and copy by d'n'd are similar.
459     *
460     * @return transferable to represent this node during a drag
461     * @exception IOException when the
462     * cut cannot be performed
463     */

464     public Transferable JavaDoc drag() throws IOException JavaDoc {
465         return clipboardCopy();
466     }
467
468     /** Can this node be copied?
469     * @return <code>true</code>
470     */

471     public boolean canCopy() {
472         return true;
473     }
474
475     /** Can this node be cut?
476     * @return <code>false</code>
477     */

478     public boolean canCut() {
479         return false;
480     }
481
482     /** Accumulate the paste types that this node can handle
483     * for a given transferable.
484     * <P>
485     * The default implementation simply tests whether the transferable supports
486     * intelligent pasting via {@link NodeTransfer#findPaste}, and if so, it obtains the paste types
487     * from the {@link NodeTransfer.Paste transfer data} and inserts them into the set.
488     * <p>Subclass implementations should typically call super (first or last) so that they
489     * add to, rather than replace, a superclass's available paste types; especially as the
490     * default implementation in <code>AbstractNode</code> is generally desirable to retain.
491     *
492     * @param t a transferable containing clipboard data
493     * @param s a list of {@link PasteType}s that will have added to it all types
494     * valid for this node (ordered as they will be presented to the user)
495     */

496     protected void createPasteTypes(Transferable JavaDoc t, List<PasteType> s) {
497         NodeTransfer.Paste p = NodeTransfer.findPaste(t);
498
499         if (p != null) {
500             // adds all its types into the set
501
s.addAll(Arrays.asList(p.types(this)));
502         }
503     }
504
505     /** Determine which paste operations are allowed when a given transferable is in the clipboard.
506     * Subclasses should override {@link #createPasteTypes}.
507     *
508     * @param t the transferable in the clipboard
509     * @return array of operations that are allowed
510     */

511     public final PasteType[] getPasteTypes(Transferable JavaDoc t) {
512         List<PasteType> s = new LinkedList<PasteType>();
513         createPasteTypes(t, s);
514
515         return s.toArray(NO_PASTE_TYPES);
516     }
517
518     /** Default implementation that tries to delegate the implementation
519     * to the createPasteTypes method. Simply calls the method and
520     * tries to take the first provided argument. Ignores the action
521     * argument and index.
522     *
523     * @param t the transferable
524     * @param action the drag'n'drop action to do DnDConstants.ACTION_MOVE, ACTION_COPY, ACTION_LINK
525     * @param index index between children the drop occured at or -1 if not specified
526     * @return null if the transferable cannot be accepted or the paste type
527     * to execute when the drop occures
528     */

529     public PasteType getDropType(Transferable JavaDoc t, int action, int index) {
530         java.util.List JavaDoc<PasteType> s = new LinkedList<PasteType>();
531         createPasteTypes(t, s);
532
533         return s.isEmpty() ? null : s.get(0);
534     }
535
536     /* List new types that can be created in this node.
537     * @return new types
538     */

539     public NewType[] getNewTypes() {
540         return NO_NEW_TYPES;
541     }
542
543     /** Checks whether subclass overrides a method
544      */

545     private boolean overridesAMethod(String JavaDoc name, Class JavaDoc[] arguments) {
546         // we are subclass of AbstractNode
547
try {
548             java.lang.reflect.Method JavaDoc m = getClass().getMethod(name, arguments);
549
550             if (m.getDeclaringClass() != AbstractNode.class) {
551                 // ok somebody overriden the method
552
return true;
553             }
554         } catch (NoSuchMethodException JavaDoc ex) {
555             Exceptions.printStackTrace(ex);
556         }
557
558         return false;
559     }
560
561     /** Gets preferred action.
562       * By default, null.
563       * @return preferred action
564       * @see Node#getPreferredAction
565       * @since 3.29
566       */

567     public Action getPreferredAction() {
568         boolean delegate = false;
569
570         Class JavaDoc c = getClass();
571
572         if (c != AbstractNode.class) {
573             synchronized (overridesGetDefaultAction) {
574                 Object JavaDoc in = overridesGetDefaultAction.get(c);
575
576                 if (in == this) {
577                     // catched in a loop of overriding getDefaultAction and
578
// calling super.getDefaultAction
579
// pretend that we do not override
580
overridesGetDefaultAction.put(c, Boolean.FALSE);
581
582                     return preferredAction;
583                 }
584
585                 Boolean JavaDoc b;
586
587                 if (in == null) {
588                     b = overridesAMethod("getDefaultAction", new Class JavaDoc[0]) ? Boolean.TRUE : Boolean.FALSE; // NOI18N
589

590                     if (b.booleanValue()) {
591                         // check whether it is safe to call the getDefaultAction
592
overridesGetDefaultAction.put(c, this);
593                         getDefaultAction();
594
595                         if (overridesGetDefaultAction.get(c) == this) {
596                             // value unchanged, we have not been cought in a loop
597
overridesGetDefaultAction.put(c, b);
598                         }
599                     } else {
600                         overridesGetDefaultAction.put(c, b);
601                     }
602                 } else {
603                     b = (Boolean JavaDoc) in;
604                 }
605
606                 delegate = b.booleanValue();
607             }
608         }
609
610         return delegate ? getDefaultAction() : preferredAction;
611     }
612
613     /** Gets the default action. Overrides superclass method.
614     * @return if there is a default action set, then returns it
615      * @deprecated Use {@link #getPreferredAction} instead.
616     */

617     @Deprecated JavaDoc
618     public SystemAction getDefaultAction() {
619         Action a = getPreferredAction();
620
621         if (a instanceof SystemAction) {
622             return (SystemAction) a;
623         }
624
625         return null;
626     }
627
628     /** Set a default action for the node.
629     * @param action the new default action, or <code>null</code> for none
630     * @deprecated Override {@link #getPreferredAction} instead.
631     */

632     @Deprecated JavaDoc
633     public void setDefaultAction(SystemAction action) {
634         preferredAction = action;
635     }
636
637     /** Get all actions for the node.
638     * Initialized with {@link #createActions}, or with the superclass's list.
639     *
640     * @return actions for the node
641      * @deprecated Override {@link #getActions(boolean)} instead.
642     */

643     @Deprecated JavaDoc
644     public SystemAction[] getActions() {
645         if (systemActions == null) {
646             systemActions = createActions();
647
648             if (systemActions == null) {
649                 systemActions = super.getActions();
650             }
651         }
652
653         return systemActions;
654     }
655
656     /** Lazily initialize set of node's actions (overridable).
657     * The default implementation returns <code>null</code>.
658     * <p><em>Warning:</em> do not call {@link #getActions} within this method.
659     * @return array of actions for this node, or <code>null</code> to use the default node actions
660      * @deprecated Override {@link #getActions(boolean)} instead.
661     */

662     @Deprecated JavaDoc
663     protected SystemAction[] createActions() {
664         return null;
665     }
666
667     /** Does this node have a customizer?
668     * @return <CODE>false</CODE>
669     */

670     public boolean hasCustomizer() {
671         return false;
672     }
673
674     /** Get the customizer.
675     * @return <code>null</code> in the default implementation
676     */

677     public java.awt.Component JavaDoc getCustomizer() {
678         return null;
679     }
680
681     /** Set the cookie set.
682     * A listener is attached to the provided cookie set,
683     * and any change of the sheet is propagated to the node by
684     * firing {@link #PROP_COOKIE} change events.
685     *
686     * @param s the cookie set to use
687     * @deprecated just use getCookieSet().add(...) instead
688     * @exception IllegalStateException If you pass a Lookup instance into the constructor, this
689     * method cannot be called.
690     */

691     @Deprecated JavaDoc
692     protected final synchronized void setCookieSet(CookieSet s) {
693         if (internalLookup(false) != null) {
694             throw new IllegalStateException JavaDoc("CookieSet cannot be used when lookup is associated with the node"); // NOI18N
695
}
696
697         if (sheetCookieL == null) {
698             sheetCookieL = new SheetAndCookieListener();
699         }
700
701         CookieSet cookieSet = (CookieSet) lookup;
702
703         if (cookieSet != null) {
704             cookieSet.removeChangeListener(sheetCookieL);
705         }
706
707         s.addChangeListener(sheetCookieL);
708         lookup = s;
709
710         fireCookieChange();
711     }
712
713     /** Get the cookie set.
714     *
715     * @return the cookie set created by {@link #setCookieSet}, or an empty set (never <code>null</code>)
716     * @exception IllegalStateException If you pass a Lookup instance into the constructor, this
717     * method cannot be called.
718     */

719     protected final CookieSet getCookieSet() {
720         if (internalLookup(false) != null) {
721             throw new IllegalStateException JavaDoc("CookieSet cannot be used when lookup is associated with the node"); // NOI18N
722
}
723
724         CookieSet s = (CookieSet) lookup;
725
726         if (s != null) {
727             return s;
728         }
729
730         synchronized (this) {
731             if (lookup != null) {
732                 return (CookieSet) lookup;
733             }
734
735             // sets empty sheet and adds a listener to it
736
setCookieSet(new CookieSet());
737
738             return (CookieSet) lookup;
739         }
740     }
741
742     /** Get a cookie from the node.
743     * Uses the cookie set as determined by {@link #getCookieSet}.
744     *
745     * @param type the representation class
746     * @return the cookie or <code>null</code>
747     */

748     @Override JavaDoc
749     public <T extends Node.Cookie> T getCookie(Class JavaDoc<T> type) {
750         if (lookup instanceof CookieSet) {
751             CookieSet c = (CookieSet) lookup;
752
753             return c.getCookie(type);
754         } else {
755             return super.getCookie(type);
756         }
757     }
758
759     /** Get a serializable handle for this node.
760     * @return a {@link DefaultHandle} in the default implementation
761     */

762     public Handle getHandle() {
763         return DefaultHandle.createHandle(this);
764     }
765
766     /** Listener for changes in the sheet and the cookie set. */
767     private final class SheetAndCookieListener implements PropertyChangeListener JavaDoc, ChangeListener JavaDoc {
768         SheetAndCookieListener() {
769         }
770
771         public void propertyChange(PropertyChangeEvent JavaDoc ev) {
772             AbstractNode.this.firePropertySetsChange(null, null);
773         }
774
775         public void stateChanged(ChangeEvent JavaDoc ev) {
776             AbstractNode.this.fireCookieChange();
777         }
778     }
779 }
780
Popular Tags