KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > windows > TopComponent


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.windows;
21
22 import java.awt.EventQueue JavaDoc;
23 import java.awt.Image JavaDoc;
24 import java.awt.Toolkit JavaDoc;
25 import java.awt.event.ActionEvent JavaDoc;
26 import java.awt.event.ActionListener JavaDoc;
27 import java.awt.event.KeyEvent JavaDoc;
28 import java.beans.PropertyChangeEvent JavaDoc;
29 import java.beans.PropertyChangeListener JavaDoc;
30 import java.io.Externalizable JavaDoc;
31 import java.io.IOException JavaDoc;
32 import java.io.ObjectInput JavaDoc;
33 import java.io.ObjectInputStream JavaDoc;
34 import java.io.ObjectOutput JavaDoc;
35 import java.io.ObjectOutputStream JavaDoc;
36 import java.io.ObjectStreamException JavaDoc;
37 import java.io.Serializable JavaDoc;
38 import java.lang.ref.Reference JavaDoc;
39 import java.lang.ref.WeakReference JavaDoc;
40 import java.lang.reflect.InvocationTargetException JavaDoc;
41 import java.lang.reflect.Method JavaDoc;
42 import java.util.ArrayList JavaDoc;
43 import java.util.Arrays JavaDoc;
44 import java.util.Collection JavaDoc;
45 import java.util.List JavaDoc;
46 import java.util.Set JavaDoc;
47 import java.util.logging.Level JavaDoc;
48 import java.util.logging.LogRecord JavaDoc;
49 import java.util.logging.Logger JavaDoc;
50 import javax.accessibility.Accessible JavaDoc;
51 import javax.accessibility.AccessibleContext JavaDoc;
52 import javax.accessibility.AccessibleRole JavaDoc;
53 import javax.swing.Action JavaDoc;
54 import javax.swing.ActionMap JavaDoc;
55 import javax.swing.JComponent JavaDoc;
56 import javax.swing.KeyStroke JavaDoc;
57 import javax.swing.SwingUtilities JavaDoc;
58 import javax.swing.Timer JavaDoc;
59 import javax.swing.plaf.basic.BasicHTML JavaDoc;
60 import javax.swing.text.Keymap JavaDoc;
61 import org.openide.awt.UndoRedo;
62 import org.openide.nodes.Node;
63 import org.openide.nodes.NodeAdapter;
64 import org.openide.nodes.NodeListener;
65 import org.openide.util.ContextAwareAction;
66 import org.openide.util.HelpCtx;
67 import org.openide.util.Lookup;
68 import org.openide.util.NbBundle;
69 import org.openide.util.Utilities;
70 import org.openide.util.WeakListeners;
71 import org.openide.util.WeakSet;
72 import org.openide.util.actions.SystemAction;
73
74 /**
75  * Embeddable visual component to be displayed in NetBeans.
76  * This is the basic unit of display--windows should not be
77  * created directly, but rather use this class.
78  * A top component may correspond to a single window, but may also
79  * be a tab (e.g.) in a window. It may be docked or undocked,
80  * have selected nodes, supply actions, etc.
81  *
82  * Important serialization note: Serialization of this TopComponent is designed
83  * in a way that it's not desired to override writeReplace method. If you would
84  * like to resolve to something, please implement readResolve() method directly
85  * on your top component.
86  *
87  * @author Jaroslav Tulach, Petr Hamernik, Jan Jancura
88  */

89 public class TopComponent extends JComponent JavaDoc implements Externalizable JavaDoc, Accessible JavaDoc, HelpCtx.Provider, Lookup.Provider {
90     /** UI logger to notify about invocation of an action */
91     private static Logger JavaDoc UILOG = Logger.getLogger("org.netbeans.ui.actions"); // NOI18N
92
/** generated Serialized Version UID */
93     static final long serialVersionUID = -3022538025284122942L;
94     /** top component logger */
95     static final Logger JavaDoc LOG = Logger.getLogger(TopComponent.class.getName());
96
97     /** Behavior in which a top component closed (by the user) in one workspace
98      * will be removed from <em>every</em> workspace.
99      * Also, {@link #close} is called.
100      * This is appropriate for top components such as Editor panes which
101      * the user expects to really close (and prompt to save) when closed
102      * in any
103      * @deprecated Do not use. It is redundant since workspaces are not supported anymore. */

104     @Deprecated JavaDoc
105     public static final int CLOSE_EACH = 0;
106
107     /** Behavior in which a top component closed (by the user) in one workspace
108      * may be left in other workspaces.
109      * Only when the last remaining manifestation in any workspace is closed
110      * will the object be deleted using {@link #close}.
111      * Appropriate for components containing no user data, for which closing
112      * the component is only likely to result from the user's wanting to remove
113      * it from active view (on the current workspace).
114      * @deprecated Do not use. It is redundant since workspaces are not supported anymore. */

115     @Deprecated JavaDoc
116     public static final int CLOSE_LAST = 1;
117
118     /** Persistence type of TopComponent instance. TopComponent is persistent. */
119     public static final int PERSISTENCE_ALWAYS = 0;
120
121     /** Persistence type of TopComponent instance. TopComponent is persistent only when
122      * it is opened in Mode. */

123     public static final int PERSISTENCE_ONLY_OPENED = 1;
124
125     /** Persistence type of TopComponent instance. TopComponent is not persistent. */
126     public static final int PERSISTENCE_NEVER = 2;
127
128     /** a lock for operations in default impl of getLookup */
129     private static Object JavaDoc defaultLookupLock = new Object JavaDoc();
130
131     /** Classes that have been warned about overriding preferredID() */
132     private static final Set JavaDoc<Class JavaDoc> warnedTCPIClasses = new WeakSet<Class JavaDoc>();
133
134     /** Used to print warning about getPersistenceType */
135     private static final Set JavaDoc<Class JavaDoc> warnedClasses = new WeakSet<Class JavaDoc>();
136
137     /** reference to Lookup with default implementation for the
138      * component or the lookup associated with the component itself
139      */

140     private Object JavaDoc defaultLookupRef;
141
142     /** Holds support for sync with node display name or null */
143     private NodeName nodeName;
144
145     // Do not use, deprecated.
146

147     /** constant for desired close operation */
148     private int closeOperation = CLOSE_LAST;
149
150     /** Icon of this <code>TopComponent</code> */
151     private transient Image JavaDoc icon;
152
153     /** Activated nodes of this <code>TopComponent</code>. */
154     private transient Node[] activatedNodes;
155
156     /** Localized display name of this <code>TopComponent</code>. */
157     private transient String JavaDoc displayName;
158
159     /** Holds localized display name of this <code>TopComponent</code> in html syntax,
160      * or null if not needed */

161     private String JavaDoc htmlDisplayName;
162     
163     /** identification of serialization version
164     * Used in CloneableTopComponent readObject method.
165     */

166     short serialVersion = 1;
167     private AttentionGetter attentionGetter = null;
168
169
170     /** Create a top component.
171     */

172     public TopComponent() {
173         this((Lookup) null);
174     }
175
176     /** Creates a top component for a provided lookup that will delegate
177      * take and synchronize activated nodes and ActionMap from a provided
178      * lookup. The lookup will also be returned from {@link #getLookup} method,
179      * if not overriden.
180      *
181      * @param lookup the lookup to associate with
182      * @since 4.19
183      */

184     public TopComponent(Lookup lookup) {
185         if (lookup != null) {
186             setLookup(lookup, true);
187         }
188
189         enableEvents(java.awt.AWTEvent.KEY_EVENT_MASK);
190
191         // #27731 TopComponent itself shouldn't get the focus.
192
// XXX What to do in case nothing in TopComponent is focusable?
193
setFocusable(false);
194         initActionMap(lookup);
195     }
196
197     // It is necessary so the old actions (clone and close from org.openide.actions package) remain working.
198

199     /** Initialized <code>ActionMap</code> of this <code>TopComponent</code>.
200      * @since 4.13 */

201     private void initActionMap(Lookup lookup) {
202         ActionMap JavaDoc inner = null;
203         if (lookup != null) {
204             inner = lookup.lookup(ActionMap JavaDoc.class);
205         }
206         if (inner == null) {
207             inner = new ActionMap JavaDoc();
208         }
209         
210         javax.swing.ActionMap JavaDoc am = new DelegateActionMap(this, inner);
211
212         if (this instanceof TopComponent.Cloneable) {
213             am.put(
214                 "cloneWindow",
215                 new javax.swing.AbstractAction JavaDoc() { // NOI18N
216
public void actionPerformed(ActionEvent JavaDoc evt) {
217                         TopComponent cloned = ((TopComponent.Cloneable) TopComponent.this).cloneComponent();
218                         cloned.open();
219                         cloned.requestActive();
220                     }
221                 }
222             );
223         }
224
225         am.put(
226             "closeWindow",
227             new javax.swing.AbstractAction JavaDoc() { // NOI18N
228
public void actionPerformed(ActionEvent JavaDoc evt) {
229                     TopComponent.this.close();
230                 }
231             }
232         );
233
234         setActionMap(am);
235     }
236
237     /** Getter for class that allows obtaining of information about components.
238     * It allows to find out which component is selected, which nodes are
239     * currently or has been activated and list of all components.
240     *
241     * @return the registry of components
242     */

243     public static final Registry getRegistry() {
244         return WindowManager.getDefault().getRegistry();
245     }
246
247     /** Get the set of activated nodes in this component.
248      * @return the activated nodes for this component or <code>null</code>, <code>null</code>
249      * means such component does not change {@link Registry#getActivatedNodes()} just
250      * {@link Registry#getCurrentNodes()} when this component gets activated */

251     public final Node[] getActivatedNodes() {
252         return activatedNodes;
253     }
254
255     /** Set the set of activated nodes in this component.
256     * @param activatedNodes activated nodes for this component
257     */

258     public final void setActivatedNodes(Node[] activatedNodes) {
259         boolean l = LOG.isLoggable(Level.FINER);
260
261         if (Arrays.equals(this.activatedNodes, activatedNodes)) {
262             if (l) {
263                 LOG.finer("No change to activatedNodes for " + this); // NOI18N
264
}
265             return;
266         }
267
268         Lookup lookup = getLookup(false);
269
270         if (lookup instanceof DefaultTopComponentLookup) {
271             if (l) {
272                 LOG.finer("Updating lookup " + lookup + " for " + this); // NOI18N
273
}
274             ((DefaultTopComponentLookup) lookup).updateLookups(activatedNodes);
275         }
276
277         Node[] old = this.activatedNodes;
278         this.activatedNodes = activatedNodes;
279
280         if (l) {
281             LOG.finer("activatedNodes changed: " + (activatedNodes == null ? "" : Arrays.asList(activatedNodes).toString())); // NOI18N
282
}
283         // notify all that are interested...
284
WindowManager.getDefault().topComponentActivatedNodesChanged(this, this.activatedNodes);
285
286         if (l) {
287             LOG.finer("window manager notified: " + this); // NOI18N
288
}
289
290
291         firePropertyChange("activatedNodes", old, this.activatedNodes); // NOI18N
292

293         if (l) {
294             LOG.finer("listeners notified: " + this); // NOI18N
295
}
296     }
297
298     /**
299      * Overwrite when you want to change default persistence type. Default
300      * persistence type is PERSISTENCE_ALWAYS.
301      * Return value should be constant over a given TC's lifetime.
302      * @return one of P_X constants
303      * @since 4.20
304      */

305     public int getPersistenceType() {
306         //First check for 'PersistenceType' client property for compatibility.
307
if (warnedClasses.add(getClass()) && !TopComponent.class.equals(getClass())) {
308             Logger.getAnonymousLogger().warning(
309                 "Note - " // NOI18N
310
+getClass().getName() + " ought to override getPersistenceType()" // NOI18N
311
+" rather than using the client property or accepting the default."
312             ); // NOI18N
313
}
314
315         String JavaDoc propValue = (String JavaDoc) getClientProperty("PersistenceType"); // NOI18N
316

317         if (propValue == null) {
318             return PERSISTENCE_ALWAYS;
319         } else if ("Never".equals(propValue)) { // NOI18N
320

321             return PERSISTENCE_NEVER;
322         } else if ("OnlyOpened".equals(propValue)) { // NOI18N
323

324             return PERSISTENCE_ONLY_OPENED;
325         } else {
326             return PERSISTENCE_ALWAYS;
327         }
328     }
329
330     /** Get the undo/redo support for this component.
331     * The default implementation returns a dummy support that cannot
332     * undo anything.
333     *
334     * @return undoable edit for this component
335     */

336     public UndoRedo getUndoRedo() {
337         return UndoRedo.NONE;
338     }
339
340     /** Shows this <code>TopComponent</code>.
341      * <em>Note:</em> This method only makes it visible, but does not
342      * activates it.
343      * @see #requestActive */

344     public void open() {
345         open(null);
346     }
347
348     /** Shows this <code>TopComponent</code> in current workspace.
349      * <em>Node:</em> Currently workspaces are not supported. The method has the same effect
350      * like {@link #open()}.
351      * @deprecated Use {@link #open()} instead. */

352     @Deprecated JavaDoc
353     public void open(Workspace workspace) {
354         WindowManager.getDefault().topComponentOpen(this);
355     }
356
357     /** Indicates whether this <code>TopComponent</code> is opened.
358     * @return true if given top component is opened, false otherwise */

359     public final boolean isOpened() {
360         return isOpened(null);
361     }
362
363     /** Indicates whether this <code>TopComponent</code> is opened in current workspace.
364      * <em>Node:</em> Currently workspaces are not supported. The method has the same effect
365      * like {@link #isOpened()}.
366      * @deprecated Use {@link #isOpened()} instead. */

367     @Deprecated JavaDoc
368     public final boolean isOpened(Workspace workspace) {
369         return WindowManager.getDefault().topComponentIsOpened(this);
370     }
371
372     /** Closes this <code>TopComponent</code>.
373      * @return true if top component was succesfully closed, false if
374      * top component for some reason refused to close. */

375     public final boolean close() {
376         return close(null);
377     }
378
379     /** Closes this <code>TopComponent</code> in current workspace.
380      * <em>Node:</em> Currently workspaces are not supported. The method has the same effect
381      * like {@link #close()}.
382      * @deprecated Use {@link #close()} instead. */

383     @Deprecated JavaDoc
384     public final boolean close(Workspace workspace) {
385         if (!isOpened()) {
386             return true;
387         }
388
389         if (canClose()) {
390             WindowManager.getDefault().topComponentClose(this);
391
392             return true;
393         } else {
394             return false;
395         }
396     }
397
398     /** This method is called when this <code>TopComponent</code> is about to close.
399      * Allows subclasses to decide if <code>TopComponent</code> is ready to close.
400      * @since 4.13 */

401     public boolean canClose() {
402         if (!isOpened()) {
403             return false;
404         }
405
406         return canClose(null, true);
407     }
408
409     /** This method is called when top component is about to close.
410      * Allows subclasses to decide if top component is ready for closing
411      * or not.<br>
412      * Default implementation always return true.
413      *
414      * @param workspace the workspace on which we are about to close or
415      * null which means that component will be closed
416      * on all workspaces where it is opened (CLOSE_EACH mode)
417      * @param last true if this is last workspace where top component is
418      * opened, false otherwise. If close operation is set to
419      * CLOSE_EACH, then this param is always true
420      * @return true if top component is ready to close, false otherwise.
421      * @deprecated Do not use anymore. Use {@link #canClose()} instead.
422      * Both parameters are redundant since workspaces are not supported anymore. */

423     @Deprecated JavaDoc
424     public boolean canClose(Workspace workspace, boolean last) {
425         return true;
426     }
427
428     /** Called only when top component was closed on all workspaces before and
429      * now is opened for the first time on some workspace. The intent is to
430      * provide subclasses information about TopComponent's life cycle across
431      * all existing workspaces.
432      * Subclasses will usually perform initializing tasks here.
433      * @deprecated Use {@link #componentOpened} instead. */

434     @Deprecated JavaDoc
435     protected void openNotify() {
436     }
437
438     /** Called only when top component was closed so that now it is closed
439      * on all workspaces in the system. The intent is to provide subclasses
440      * information about TopComponent's life cycle across workspaces.
441      * Subclasses will usually perform cleaning tasks here.
442      * @deprecated Use {@link #componentClosed} instead.
443      */

444     @Deprecated JavaDoc
445     protected void closeNotify() {
446     }
447
448     /** Gets the system actions which will appear in the popup menu of this component.
449      * @return array of system actions for this component
450      * @deprecated Use {@link #getActions()} instead.
451      */

452     @Deprecated JavaDoc
453     public SystemAction[] getSystemActions() {
454         return new SystemAction[0];
455     }
456
457     /** Gets the actions which will appear in the popup menu of this component.
458      * <p>Subclasses are encouraged to override this method to specify
459      * their own sets of actions.
460      * <p>Remember to call the super method when overriding and add your actions
461      * to the superclass' ones (in some order),
462      * because the default implementation provides support for standard
463      * component actions like save, close, and clone.
464      * @return array of actions for this component
465      * @since 3.32
466      */

467     public javax.swing.Action JavaDoc[] getActions() {
468         Action JavaDoc[] actions = WindowManager.getDefault().topComponentDefaultActions(this);
469
470         SystemAction[] sysActions = getSystemActions();
471
472         // If there are some sys actions (i.e. the subclass overrided the defautl impl) add them.
473
if (sysActions.length > 0) {
474             List JavaDoc<Action JavaDoc> acs = new ArrayList JavaDoc<Action JavaDoc>(Arrays.asList(actions));
475             acs.addAll(Arrays.asList(sysActions));
476
477             return acs.toArray(new Action JavaDoc[0]);
478         } else {
479             return actions;
480         }
481     }
482
483     /** Set the close mode for the component.
484      * @param closeOperation one of {@link #CLOSE_EACH} or {@link #CLOSE_LAST}
485      * @throws IllegalArgumentException if an unrecognized close mode was supplied
486      * @see #close()
487      * @deprecated Do not use. It is redundant since workspaces are not supported anymore. */

488     @Deprecated JavaDoc
489     public final void setCloseOperation(final int closeOperation) {
490         if ((closeOperation != CLOSE_EACH) && (closeOperation != CLOSE_LAST)) {
491             throw new IllegalArgumentException JavaDoc(
492                 NbBundle.getBundle(TopComponent.class).getString("EXC_UnknownOperation")
493             );
494         }
495
496         if (this.closeOperation == closeOperation) {
497             return;
498         }
499
500         this.closeOperation = closeOperation;
501         firePropertyChange("closeOperation", null, null); // NOI18N
502
}
503
504     /** Get the current close mode for this component.
505      * @return one of {@link #CLOSE_EACH} or {@link #CLOSE_LAST}
506      * @deprecated Do not use. It is redundant since workspaces are not supported anymore. */

507     @Deprecated JavaDoc
508     public final int getCloseOperation() {
509         return closeOperation;
510     }
511
512     /**
513      * Subclasses are encouraged to override this method to provide preferred value
514      * for unique TopComponent ID returned by {@link org.openide.windows.WindowManager#findTopComponentID}.
515      *
516      * Returned value should be a String, preferably describing semantics of
517      * TopComponent subclass, such as "PieChartViewer" or "HtmlEditor" etc.
518      * Value is then used by window system as prefix value for creating unique
519      * TopComponent ID.
520      *
521      * Returned String value should be preferably unique, but need not be.
522      * @since 4.13
523      */

524     protected String JavaDoc preferredID() {
525         Class JavaDoc clazz = getClass();
526
527         if (getPersistenceType() != PERSISTENCE_NEVER && warnedTCPIClasses.add(clazz)) {
528             Logger.getAnonymousLogger().warning(
529                 clazz.getName() + " should override preferredID()" //NOI18N
530
);
531         }
532
533         String JavaDoc name = getName();
534
535         // fix for #47021 and #47115
536
if (name == null) {
537             int ind = clazz.getName().lastIndexOf('.');
538             name = (ind == -1) ? clazz.getName() : clazz.getName().substring(ind + 1);
539         }
540
541         return name;
542     }
543
544     /** Called only when top component was closed on all workspaces before and
545      * now is opened for the first time on some workspace. The intent is to
546      * provide subclasses information about TopComponent's life cycle across
547      * all existing workspaces.
548      * Subclasses will usually perform initializing tasks here.
549      * @since 2.18 */

550     protected void componentOpened() {
551         openNotify();
552     }
553
554     /** Called only when top component was closed so that now it is closed
555      * on all workspaces in the system. The intent is to provide subclasses
556      * information about TopComponent's life cycle across workspaces.
557      * Subclasses will usually perform cleaning tasks here.
558      * @since 2.18 */

559     protected void componentClosed() {
560         closeNotify();
561     }
562
563     /** Called when <code>TopComponent</code> is about to be shown.
564      * Shown here means the component is selected or resides in it own cell
565      * in container in its <code>Mode</code>. The container is visible and not minimized.
566      * <p><em>Note:</em> component
567      * is considered to be shown, even its container window
568      * is overlapped by another window.</p>
569      * @since 2.18 */

570     protected void componentShowing() {
571     }
572
573     /** Called when <code>TopComponent</code> was hidden. <em>Nore</em>:
574      * <p><em>Note:</em> Beside typical situations when component is hidden,
575      * it is considered to be hidden even in that case
576      * the component is in <code>Mode</code> container hierarchy,
577      * the cointainer is visible, not minimized,
578      * but the component is neither selected nor in its own cell,
579      * i.e. it has it's own tab, but is not the selected one.
580      * @since 2.18 */

581     protected void componentHidden() {
582     }
583
584     /** Called when this component is activated.
585     * This happens when the parent window of this component gets focus
586     * (and this component is the preferred one in it), <em>or</em> when
587     * this component is selected in its window (and its window was already focussed).
588     * Remember to call the super method.
589     * The default implementation does nothing.
590     */

591     protected void componentActivated() {
592     }
593
594     /** Called when this component is deactivated.
595     * This happens when the parent window of this component loses focus
596     * (and this component is the preferred one in the parent),
597     * <em>or</em> when this component loses preference in the parent window
598     * (and the parent window is focussed).
599     * Remember to call the super method.
600     * The default implementation does nothing.
601     */

602     protected void componentDeactivated() {
603     }
604
605     /** Request focus for the window holding this top component.
606      * Also makes the component preferred in that window.
607      * The component will <em>not</em> be automatically {@link #open opened} first
608      * if it is not already.
609      * <p>Subclasses should override this method to transfer focus to desired
610      * focusable component. <code>TopComponent</code> itself is not focusable.
611      * See for example {@link org.openide.text.CloneableEditor#requestFocus}.
612      * @deprecated Use {@link #requestActive} instead to make TopComponent active
613      * in window system not only focused. This method should have been preserved
614      * for focus management only but not activation of <code>TopComponent</code> inside
615      * window system. The default implementation does nothing, and does not call
616      * super.requestFocus().
617      */

618     @Deprecated JavaDoc
619     public void requestFocus() {
620         if (isFocusable()) {
621             //Issue 44304 - output window is focusable when empty, need some
622
//way to give it focus
623
super.requestFocus();
624         }
625     }
626
627     /** Request focus for the top component inside focused window.
628      * Also makes the component preferred in that window.
629      * The component will <em>not</em> be automatically {@link #open opened} first
630      * if it is not already.
631      * <p>Subclasses should override this method to transfer focus to desired
632      * focusable component. <code>TopComponent</code> itself is not focusable.
633      * See for example {@link org.openide.text.CloneableEditor#requestFocusInWindow}.
634      * @deprecated Use {@link #requestActive} instead to make TopComponent active
635      * in window system not only focused. This method should have been preserved
636      * for focus management only but not activation of <code>TopComponent</code> inside
637      * window system. The default implementation does nothing, and does not call
638      * super.requestFocusInWindow(). */

639     @Deprecated JavaDoc
640     public boolean requestFocusInWindow() {
641         if (isFocusable()) {
642             return super.requestFocusInWindow();
643         } else {
644             return false;
645         }
646     }
647
648     /** Activates this <code>TopComponent<code> if it is opened.
649      * @since 4.13 */

650     public void requestActive() {
651         WindowManager.getDefault().topComponentRequestActive(this);
652     }
653
654     /**
655      * Attempts to bring the parent <code>Window</code> or <code>Frame</code>
656      * of this <code>TopComponent<code> to front of other windows.
657      * @since 5.8
658      */

659     public void toFront() {
660         WindowManager.getDefault().topComponentToFront(this);
661     }
662
663     /** Selects this <code>TopComponent</code>, if it is opened, but does not activate it
664      * unless it is in active mode already. */

665     public void requestVisible() {
666         WindowManager.getDefault().topComponentRequestVisible(this);
667         org.netbeans.modules.openide.windows.GlobalActionContextImpl.blickActionMap(getActionMap());
668     }
669
670     /**
671      * Cause this TopComponent's tab to flash or otherwise draw attention to
672      * itself. This method is thread-safe.
673      * <p>
674      * It will remain flashing until either <code>cancelRequestAttention</code>
675      * is called, the component becomes selected or its activated state changes,
676      * unless the <code>brief</code> argument is true, in which case it will stop
677      * after a few second.
678      * @param brief True if the tab should blink a few times and stop
679      * @since 5.1
680      */

681     public final void requestAttention(final boolean brief) {
682         //Reentrancy issues - always invoke later
683
EventQueue.invokeLater(
684             new Runnable JavaDoc() {
685                 public void run() {
686                     if ((attentionGetter != null) && !brief) {
687                         attentionGetter.kill();
688                     } else if (!brief) {
689                         WindowManager.getDefault().topComponentRequestAttention(TopComponent.this);
690                     } else if (attentionGetter != null) {
691                         attentionGetter.reset();
692                     } else {
693                         attentionGetter = new AttentionGetter();
694                     }
695                 }
696             }
697         );
698     }
699
700     /**
701      * Cause this TopComponent's tab to stop flashing if it was flashing.
702      * @since 5.1
703      */

704     public final void cancelRequestAttention() {
705         //Reentrancy issues - always invoke later
706
EventQueue.invokeLater(
707             new Runnable JavaDoc() {
708                 public void run() {
709                     if (attentionGetter != null) {
710                         attentionGetter.stop();
711                     } else {
712                         WindowManager.getDefault().topComponentCancelRequestAttention(TopComponent.this);
713                     }
714                 }
715             }
716         );
717     }
718
719     /** Set the name of this top component.
720     * The default implementation just notifies the window manager.
721     * @param name the new display name
722     */

723     public void setName(final String JavaDoc name) {
724         String JavaDoc old = getName();
725
726         if ((name != null) && (name.equals(old))) {
727             return;
728         }
729
730         super.setName(name);
731         firePropertyChange("name", old, name); // NOI18N
732

733         // XXX When displayName is null, it is used the name.
734
WindowManager.getDefault().topComponentDisplayNameChanged(this, name);
735     }
736
737     /** Sets localized display name of this <code>TopComponent</code>.
738      * @param displayName localized display name which is set
739      * @since 4.13 */

740     public void setDisplayName(String JavaDoc displayName) {
741         String JavaDoc old = this.displayName;
742
743         if ((displayName == old) || ((displayName != null) && displayName.equals(old))) {
744             return;
745         }
746
747         // warning if display name contains html tags
748
if (BasicHTML.isHTMLString(displayName)) {
749             Logger.getAnonymousLogger().warning(
750                 "Call of " + getClass().getName() + ".setDisplayName(\"" + displayName + "\")" +
751                 " shouldn't contain any HTML tags. Please use " + getClass().getName() + ".setHtmlDisplayName(String)" +
752                 "for such purpose. For details please see http://www.netbeans.org/issues/show_bug.cgi?id=66777.");
753         }
754         
755         this.displayName = displayName;
756         firePropertyChange("displayName", old, displayName); // NOI18N
757

758         WindowManager.getDefault().topComponentDisplayNameChanged(this, displayName);
759     }
760
761     /** Gets localized display name of this <code>TopComponent</code>.
762      * @return localized display name or <code>null</code> if there is none
763      * @since 4.13 */

764     public String JavaDoc getDisplayName() {
765         return displayName;
766     }
767     
768     /** Sets localized html display name of this <code>TopComponent</code>.
769      * Hmtl name usually contains basic html tags for text coloring and style.
770      * Html name may be null if not needed.
771      * Must apparently begin with <code>&lt;html&gt;</code>.
772      *
773      * @param htmlDisplayName localized html display name which is set
774      *
775      * @since 6.4
776      */

777     public void setHtmlDisplayName(String JavaDoc htmlDisplayName) {
778         String JavaDoc old = this.htmlDisplayName;
779
780         if ((htmlDisplayName == old) || ((htmlDisplayName != null) && htmlDisplayName.equals(old))) {
781             return;
782         }
783
784         this.htmlDisplayName = htmlDisplayName;
785         firePropertyChange("htmlDisplayName", old, htmlDisplayName); // NOI18N
786

787         WindowManager.getDefault().topComponentHtmlDisplayNameChanged(this, htmlDisplayName);
788     }
789
790     /** Gets localized display name of this <code>TopComponent</code> with added
791      * html tags for text coloring and/or font style. May return null.
792      * Must apparently begin with <code>&lt;html&gt;</code>.
793      *
794      * @return localized html display name or <code>null</code> if there is none
795      *
796      * @since 6.4
797      */

798     public String JavaDoc getHtmlDisplayName() {
799         return htmlDisplayName;
800     }
801     
802
803     /** Sets toolTip for this <code>TopComponent</code>, adds notification
804      * about the change to its <code>WindowManager.TopComponentManager</code>. */

805     public void setToolTipText(String JavaDoc toolTip) {
806         if ((toolTip != null) && toolTip.equals(getToolTipText())) {
807             return;
808         }
809
810         super.setToolTipText(toolTip);
811
812         // XXX #19428. Container updates name and tooltip in the same handler.
813
WindowManager.getDefault().topComponentToolTipChanged(this, toolTip);
814     }
815
816     /** Set the icon of this top component.
817     * The icon will be used for
818     * the component's representation on the screen, e.g. in a multiwindow's tab.
819     * The default implementation just notifies the window manager.
820     * @param icon New components' icon.
821     */

822     public void setIcon(final Image JavaDoc icon) {
823         if (icon == this.icon) {
824             return;
825         }
826
827         Image JavaDoc old = this.icon;
828         this.icon = icon;
829
830         WindowManager.getDefault().topComponentIconChanged(this, this.icon); // TEMP
831

832         firePropertyChange("icon", old, icon); // NOI18N
833
}
834
835     /** @return The icon of the top component */
836     public Image JavaDoc getIcon() {
837         return icon;
838     }
839
840     /** Get the help context for this component.
841     * Subclasses should generally override this to return specific help.
842     * @return the help context
843     */

844     public HelpCtx getHelpCtx() {
845         return new HelpCtx(TopComponent.class); // XXX #63303
846
}
847
848     /** Allows top component to specify list of modes into which can be docked
849      * by end user. Subclasses should override this method if they want to
850      * alter docking policy of top component. <p>
851      * So for example, by returning empty list, top component refuses
852      * to be docked anywhere. <p>
853      * Default implementation allows docking anywhere by returning
854      * input list unchanged.
855      *
856      * @param modes list of {@link Mode} which represent all modes of current
857      * workspace, can contain nulls. Items are structured in logical groups
858      * separated by null entries. <p>
859      * Input array also contains special constant modes for docking
860      * into newly created frames. Their names are "SingleNewMode",
861      * "MultiNewMode", "SplitNewMode", can be used for their
862      * recognition. Please note that names and existence of special modes
863      * can change in future releases.
864      *
865      * @return list of {@link Mode} which are available for dock, can contain nulls
866      * @since 2.14
867      */

868     public List JavaDoc<Mode> availableModes(List JavaDoc<Mode> modes) {
869         return modes;
870     }
871
872     /** Overrides superclass method, adds possible additional handling of global keystrokes
873      * in case this <code>TopComoponent</code> is ancestor of focused component. */

874     protected boolean processKeyBinding(KeyStroke JavaDoc ks, KeyEvent JavaDoc e, int condition, boolean pressed) {
875         boolean ret = super.processKeyBinding(ks, e, condition, pressed);
876
877         // XXX #30189 Reason of overriding: to process global shortcut.
878
if ((JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT == condition) && (ret == false) && !e.isConsumed()) { // NOI18N
879

880             Keymap JavaDoc km = Lookup.getDefault().lookup(Keymap JavaDoc.class);
881             Action JavaDoc action = (km != null) ? km.getAction(ks) : null;
882
883             if (action == null) {
884                 return false;
885             }
886
887             // If necessary create context aware instance.
888
if (action instanceof ContextAwareAction) {
889                 action = ((ContextAwareAction) action).createContextAwareInstance(getLookup());
890             } else if (SwingUtilities.getWindowAncestor(e.getComponent()) instanceof java.awt.Dialog JavaDoc) {
891                 // #30303 For 'old type' actions check the transmodal flag,
892
// if invoked in dialog. See ShorcutAndMenuKeyEventProcessor in core.
893
Object JavaDoc value = action.getValue("OpenIDE-Transmodal-Action"); // NOI18N
894

895                 if (!Boolean.TRUE.equals(value)) {
896                     return false;
897                 }
898             }
899
900             if (action.isEnabled()) {
901                 LogRecord JavaDoc rec = new LogRecord JavaDoc(Level.FINER, "UI_ACTION_KEY_PRESS"); // NOI18N
902
rec.setParameters(new Object JavaDoc[] { ks, ks.toString(), action, action.getClass().getName(), action.getValue(Action.NAME) });
903                 rec.setResourceBundle(NbBundle.getBundle(TopComponent.class));
904                 rec.setLoggerName(UILOG.getName());
905                 UILOG.log(rec);
906
907                 ActionEvent JavaDoc ev = new ActionEvent JavaDoc(this, ActionEvent.ACTION_PERFORMED, Utilities.keyToString(ks));
908                 action.actionPerformed(ev);
909             } else {
910                 Toolkit.getDefaultToolkit().beep();
911             }
912
913             return true;
914         } else {
915             return ret;
916         }
917     }
918
919     /** Serialize this top component.
920     * Subclasses wishing to store state must call the super method, then write to the stream.
921     * @param out the stream to serialize to
922     */

923     public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc {
924         out.writeObject(new Short JavaDoc(serialVersion));
925         out.writeInt(closeOperation);
926         out.writeObject(getName());
927         out.writeObject(getToolTipText());
928
929         if (getDisplayName() != null) {
930             out.writeObject(getDisplayName());
931         }
932
933         Node n = (nodeName == null) ? null : nodeName.getNode();
934         Node.Handle h = (n == null) ? null : n.getHandle();
935         out.writeObject(h);
936     }
937
938     /** Deserialize this top component.
939     * Subclasses wishing to store state must call the super method, then read from the stream.
940     * @param in the stream to deserialize from
941     */

942     public void readExternal(ObjectInput JavaDoc in) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
943         Object JavaDoc firstObject = in.readObject();
944
945         if (firstObject instanceof Integer JavaDoc) {
946             // backward compatibility read
947
serialVersion = 0;
948
949             closeOperation = ((Integer JavaDoc) firstObject).intValue();
950
951             // BCR: this is backward compatibility read and is likely not needed
952
// BCR: anymore. So let's just ignore the read of the data object
953
// BCR: DataObject obj = (DataObject)in.readObject();
954
in.readObject();
955
956             super.setName((String JavaDoc) in.readObject());
957             setToolTipText((String JavaDoc) in.readObject());
958
959             // initialize the connection to a data object
960

961             /* BCR: Remove this as we ignore the DataObject
962                         if (obj != null) {
963                             nodeName = new NodeName (this);
964                             nodeName.attach (obj.getNodeDelegate ());
965                         }
966             */

967         } else {
968             // new serialization
969
serialVersion = ((Short JavaDoc) firstObject).shortValue();
970
971             closeOperation = in.readInt();
972             super.setName((String JavaDoc) in.readObject());
973             setToolTipText((String JavaDoc) in.readObject());
974
975             Object JavaDoc obj = in.readObject();
976
977             if (obj instanceof String JavaDoc) {
978                 setDisplayName((String JavaDoc) obj);
979                 obj = in.readObject();
980             }
981
982             Node.Handle h = (Node.Handle) obj;
983
984             if (h != null) {
985                 Node n = h.getNode();
986                 NodeName.connect(this, n);
987             }
988         }
989
990         if ((closeOperation != CLOSE_EACH) && (closeOperation != CLOSE_LAST)) {
991             throw new IOException JavaDoc("invalid closeOperation: " + closeOperation); // NOI18N
992
}
993     }
994
995     /** Delegates instance of replacer class to be serialized instead
996     * of top component itself. Replacer class calls writeExternal and
997     * constructor, readExternal and readResolve methods properly, so
998     8 any top component can behave like any other externalizable object.
999     * Subclasses can override this method to perform their
1000    * serialization differentrly */

1001    protected Object JavaDoc writeReplace() throws ObjectStreamException JavaDoc {
1002        return new Replacer(this);
1003    }
1004
1005    /* Read accessible context
1006     * @return - accessible context
1007     */

1008    public AccessibleContext JavaDoc getAccessibleContext() {
1009        if (accessibleContext == null) {
1010            accessibleContext = new JComponent.AccessibleJComponent JavaDoc() {
1011                        public AccessibleRole JavaDoc getAccessibleRole() {
1012                            return AccessibleRole.PANEL;
1013                        }
1014
1015                        public String JavaDoc getAccessibleName() {
1016                            if (accessibleName != null) {
1017                                return accessibleName;
1018                            }
1019
1020                            return getName();
1021                        }
1022
1023                        /* Fix for 19344: Null accessible decription of all TopComponents on JDK1.4 */
1024                        public String JavaDoc getToolTipText() {
1025                            return TopComponent.this.getToolTipText();
1026                        }
1027                    };
1028        }
1029
1030        return accessibleContext;
1031    }
1032
1033    /** Gets lookup which represents context of this component. By default
1034     * the lookup delegates to result of <code>getActivatedNodes</code>
1035     * method and result of this component <code>ActionMap</code> delegate.
1036     *
1037     * @return a lookup with designates context of this component
1038     * @see org.openide.util.ContextAwareAction
1039     * @see org.openide.util.Utilities#actionsToPopup(Action[], Lookup)
1040     * @since 3.29
1041     */

1042    public Lookup getLookup() {
1043        return getLookup(true);
1044    }
1045
1046    /**
1047     * @param init should a lookup be initialized if it is not?
1048     * @return lookup or null
1049     */

1050    private Lookup getLookup(boolean init) {
1051        synchronized (defaultLookupLock) {
1052            if (defaultLookupRef instanceof Lookup) {
1053                return (Lookup) defaultLookupRef;
1054            }
1055
1056            if (defaultLookupRef instanceof Object JavaDoc[]) {
1057                return (Lookup) ((Object JavaDoc[]) defaultLookupRef)[0];
1058            }
1059
1060            if (defaultLookupRef instanceof java.lang.ref.Reference JavaDoc) {
1061                Object JavaDoc l = ((java.lang.ref.Reference JavaDoc) defaultLookupRef).get();
1062
1063                if (l instanceof Lookup) {
1064                    return (Lookup) l;
1065                }
1066            }
1067
1068            if (!init) {
1069                return null;
1070            }
1071
1072            Lookup lookup = new DefaultTopComponentLookup(this); // Lookup of activated nodes and action map
1073
defaultLookupRef = new java.lang.ref.WeakReference JavaDoc<Lookup>(lookup);
1074
1075            return lookup;
1076        }
1077    }
1078
1079    /** Associates the provided lookup with the component. So it will
1080     * be returned from {@link #getLookup} method.
1081     *
1082     * @param lookup the lookup to associate
1083     * @exception IllegalStateException if there already is a lookup registered
1084     * with this component
1085     * @since 4.23
1086     */

1087    protected final void associateLookup(Lookup lookup) {
1088        setLookup(lookup, true);
1089    }
1090
1091    /** Associates the provided lookup with the component. So it will
1092     * be returned from {@link #getLookup} method.
1093     *
1094     * @param lookup the lookup to associate
1095     * @param sync synchronize return value of {@link #getActivatedNodes} with the
1096     * content of lookup?
1097     * @exception IllegalStateException if there already is a lookup registered
1098     * with this component
1099     */

1100    final void setLookup(Lookup lookup, boolean sync) {
1101        synchronized (defaultLookupLock) {
1102            if (defaultLookupRef != null) {
1103                throw new IllegalStateException JavaDoc(
1104                    "Trying to set lookup " + lookup + " but there already is " + defaultLookupRef +
1105                    " for component: " + this
1106                ); // NOI18N
1107
}
1108
1109            defaultLookupRef = lookup;
1110
1111            if (sync) {
1112                defaultLookupRef = new Object JavaDoc[] { defaultLookupRef, new SynchronizeNodes(lookup) };
1113            }
1114            if (LOG.isLoggable(Level.FINE)) {
1115                LOG.fine("setLookup with " + lookup + " and sync: " + sync + " on " + this); // NOI18N
1116
}
1117        }
1118    }
1119
1120    private void attachNodeName(NodeName nodeName) {
1121        this.nodeName = nodeName;
1122    }
1123
1124    /** Each top component that wishes to be cloned should implement
1125    * this interface, so CloneAction can check it and call the cloneComponent
1126    * method.
1127    */

1128    public static interface Cloneable {
1129        /** Creates a clone of this component
1130        * @return cloned component.
1131        */

1132        public TopComponent cloneComponent();
1133    }
1134
1135    /** Registry of all top components.
1136    * There is one instance that can be obtained via {@link TopComponent#getRegistry}
1137    * and it permits listening to the currently selected element, and to
1138    * the activated nodes assigned to it.
1139    */

1140    public static interface Registry {
1141        /** Name of property for the set of opened components. */
1142        public static final String JavaDoc PROP_OPENED = "opened"; // NOI18N
1143

1144        /** Name of property for the selected top component. */
1145        public static final String JavaDoc PROP_ACTIVATED = "activated"; // NOI18N
1146

1147        /** Name of property for currently selected nodes. */
1148        public static final String JavaDoc PROP_CURRENT_NODES = "currentNodes"; // NOI18N
1149

1150        /** Name of property for lastly activated nodes. */
1151        public static final String JavaDoc PROP_ACTIVATED_NODES = "activatedNodes"; // NOI18N
1152

1153        /** Name of property for listening to TopComponents opened through open() call,
1154         * either by user or programmatically.
1155         * Fired property change event returns opened TopComponent from its getNewValue()
1156         */

1157        public static final String JavaDoc PROP_TC_OPENED = "tcOpened"; // NOI18N
1158

1159        /** Name of property for listening to TopComponents closed through close() call,
1160         * either by user or programmatically.
1161         * Fired property change event returns closed TopComponent from its getNewValue().
1162         */

1163        public static final String JavaDoc PROP_TC_CLOSED = "tcClosed"; // NOI18N
1164

1165        /** Get reference to a set of all opened componets in the system.
1166        *
1167        * @return live read-only set of {@link TopComponent}s
1168        */

1169        public Set JavaDoc<TopComponent> getOpened();
1170
1171        /** Get the currently selected element.
1172        * @return the selected top component, or <CODE>null</CODE> if there is none
1173        */

1174        public TopComponent getActivated();
1175
1176        /** Getter for the currently selected nodes.
1177        * @return array of nodes or null if no component activated or it returns
1178        * null from getActivatedNodes ().
1179        */

1180        public Node[] getCurrentNodes();
1181
1182        /** Getter for the lastly activated nodes. Comparing
1183        * to previous method it always remembers the selected nodes
1184        * of the last component that had ones.
1185        *
1186        * @return array of nodes (not null)
1187        */

1188        public Node[] getActivatedNodes();
1189
1190        /** Add a property change listener.
1191        * @param l the listener to add
1192        */

1193        public void addPropertyChangeListener(PropertyChangeListener JavaDoc l);
1194
1195        /** Remove a property change listener.
1196        * @param l the listener to remove
1197        */

1198        public void removePropertyChangeListener(PropertyChangeListener JavaDoc l);
1199    }
1200
1201    private class AttentionGetter implements ActionListener JavaDoc {
1202        Timer JavaDoc timer = null;
1203
1204        public AttentionGetter() {
1205            reset();
1206        }
1207
1208        public void reset() {
1209            assert EventQueue.isDispatchThread();
1210
1211            if (timer != null) {
1212                timer.stop();
1213            }
1214
1215            start();
1216            timer = new Timer JavaDoc(3500, this);
1217            timer.setRepeats(false);
1218            timer.start();
1219        }
1220
1221        private void start() {
1222            WindowManager.getDefault().topComponentRequestAttention(TopComponent.this);
1223        }
1224
1225        public void kill() {
1226            timer.stop();
1227            attentionGetter = null;
1228        }
1229
1230        private void stop() {
1231            if (timer != null) {
1232                timer.stop();
1233            }
1234
1235            attentionGetter = null;
1236            WindowManager.getDefault().topComponentCancelRequestAttention(TopComponent.this);
1237            attentionGetter = null;
1238        }
1239
1240        public void actionPerformed(ActionEvent JavaDoc ae) {
1241            stop();
1242        }
1243    }
1244
1245    /** This class provides the connection between the node name and
1246     * a name of the component.
1247     *
1248     * @deprecated Please do not use. This support class does nothing much
1249     * useful. If you need to synchronize display name of your TopComponent
1250     * with some Node's display name, we recommend you to do it manually in
1251     * your client's code.
1252     */

1253    @Deprecated JavaDoc
1254    public static class NodeName extends NodeAdapter {
1255        /** asociation with top component */
1256        private TopComponent top;
1257
1258        /** weak ref to node we are attached to or null */
1259        private Reference JavaDoc node;
1260
1261        /** Listener to node, used for weak listening */
1262        private NodeListener nodeL;
1263
1264        /** Connects a top component and a node. The name of
1265        * component will be updated as the name of the node
1266        * changes.
1267        *
1268        * @param top top compoonent to modify its name
1269        * @param n node to take name from
1270         *
1271         * @since 4.3
1272        */

1273        public static void connect(TopComponent top, Node n) {
1274            new NodeName(top).attach(n);
1275        }
1276
1277        /** Constructs new name adapter that
1278         * can be attached to any node and will listen on changes
1279         * of its display name and modify the name of the component.
1280         *
1281         * @param top top component to modify its name
1282         *
1283         * @deprecated Please do not use, public just by an accident.
1284         */

1285        @Deprecated JavaDoc
1286        public NodeName(TopComponent top) {
1287            this.top = top;
1288        }
1289
1290        /** Listens to Node.PROP_DISPLAY_NAME.
1291         *
1292         * @deprecated Please do not use, public just by an accident.
1293        */

1294        @Deprecated JavaDoc
1295        public void propertyChange(PropertyChangeEvent JavaDoc ev) {
1296            if (ev.getPropertyName().equals(Node.PROP_DISPLAY_NAME)) {
1297                Node n = (Node) node.get();
1298                if (n != null) {
1299                    top.setName(n.getDisplayName());
1300                }
1301            }
1302        }
1303        
1304        /** Attaches itself to a given node.
1305        */

1306        private void attach(Node n) {
1307            synchronized (top) {
1308                node = new WeakReference JavaDoc<Node>(n);
1309                nodeL = WeakListeners.create(NodeListener.class, this, n);
1310                n.addNodeListener(nodeL);
1311                top.attachNodeName(this);
1312                top.setActivatedNodes(new Node[] { n });
1313                top.setName(n.getDisplayName());
1314            }
1315        }
1316
1317        private Node getNode() {
1318            return (Node) node.get();
1319        }
1320        
1321    } // end of NodeName
1322

1323    /** Instance of this class is serialized instead of TopComponent itself.
1324    * Emulates behaviour of serialization of externalizable objects
1325    * to keep TopComponent serialization compatible with previous versions. */

1326    private static final class Replacer implements Serializable JavaDoc {
1327        /** SUID */
1328        static final long serialVersionUID = -8897067133215740572L;
1329
1330        /** Asociation with top component which is to be serialized using
1331        * this replacer */

1332        transient TopComponent tc;
1333
1334        public Replacer(TopComponent tc) {
1335            this.tc = tc;
1336        }
1337
1338        private void writeObject(ObjectOutputStream JavaDoc oos)
1339        throws IOException JavaDoc, ClassNotFoundException JavaDoc {
1340            // write the name of the top component first
1341
oos.writeObject(tc.getClass().getName());
1342
1343            // and now let top component to serialize itself
1344
tc.writeExternal(oos);
1345        }
1346
1347        private void readObject(ObjectInputStream JavaDoc ois)
1348        throws IOException JavaDoc, ClassNotFoundException JavaDoc {
1349            // read the name of top component's class, instantiate it
1350
// and read its attributes from the stream
1351
String JavaDoc name = (String JavaDoc) ois.readObject();
1352            name = org.openide.util.Utilities.translate(name);
1353
1354            try {
1355                ClassLoader JavaDoc loader = Lookup.getDefault().lookup(ClassLoader JavaDoc.class);
1356
1357                if (loader == null) {
1358                    loader = getClass().getClassLoader();
1359                }
1360
1361                Class JavaDoc tcClass = Class.forName(name, true, loader);
1362
1363                // instantiate class event if it has protected or private
1364
// default constructor
1365
java.lang.reflect.Constructor JavaDoc con = tcClass.getDeclaredConstructor(new Class JavaDoc[0]);
1366                con.setAccessible(true);
1367
1368                try {
1369                    tc = (TopComponent) con.newInstance(new Object JavaDoc[0]);
1370                } finally {
1371                    con.setAccessible(false);
1372                }
1373
1374                tc.readExternal(ois);
1375
1376                // call readResolve() if present and use resolved value
1377
Method JavaDoc resolveMethod = findReadResolveMethod(tcClass);
1378
1379                if (resolveMethod != null) {
1380                    // check exceptions clause
1381
Class JavaDoc[] result = resolveMethod.getExceptionTypes();
1382
1383                    if ((result.length == 1) && ObjectStreamException JavaDoc.class.equals(result[0])) {
1384                        // returned value type
1385
if (Object JavaDoc.class.equals(resolveMethod.getReturnType())) {
1386                            // make readResolve accessible (it can have any access modifier)
1387
resolveMethod.setAccessible(true);
1388
1389                            // invoke resolve method and accept its result
1390
try {
1391                                TopComponent unresolvedTc = tc;
1392                                tc = (TopComponent) resolveMethod.invoke(tc);
1393
1394                                if (tc == null) {
1395                                    throw new java.io.InvalidObjectException JavaDoc(
1396                                        "TopComponent.readResolve() cannot return null." // NOI18N
1397
+" See http://www.netbeans.org/issues/show_bug.cgi?id=27849 for more info." // NOI18N
1398
+" TopComponent:" + unresolvedTc
1399                                    ); // NOI18N
1400
}
1401                            } finally {
1402                                resolveMethod.setAccessible(false);
1403                            }
1404                        }
1405                    }
1406                }
1407            } catch (Exception JavaDoc exc) {
1408                Throwable JavaDoc th = exc;
1409
1410                // Extract target exception.
1411
if (th instanceof InvocationTargetException JavaDoc) {
1412                    th = ((InvocationTargetException JavaDoc) th).getTargetException();
1413                }
1414
1415                // IOException throw directly.
1416
if (th instanceof IOException JavaDoc) {
1417                    throw (IOException JavaDoc) th;
1418                }
1419
1420                // All others wrap into IOException.
1421
throw (IOException JavaDoc) new IOException JavaDoc(th.toString()).initCause(th);
1422            }
1423        }
1424
1425        /** Resolve to original top component instance */
1426        private Object JavaDoc readResolve() throws ObjectStreamException JavaDoc {
1427            return tc;
1428        }
1429
1430        /** Tries to find readResolve method in given class. Finds
1431        * both public and non-public occurences of the method and
1432        * searches also in superclasses */

1433        private static Method JavaDoc findReadResolveMethod(Class JavaDoc clazz) {
1434            Method JavaDoc result = null;
1435            Class JavaDoc[] params = new Class JavaDoc[0];
1436
1437            // first try public occurences
1438
try {
1439                result = clazz.getMethod("readResolve", params); // NOI18N
1440
} catch (NoSuchMethodException JavaDoc exc) {
1441                // public readResolve does not exist
1442
// now try non-public occurences; search also in superclasses
1443
for (Class JavaDoc i = clazz; (i != null) && (i != TopComponent.class); i = i.getSuperclass()) { // perf: TC and its superclasses do not have readResolve method
1444

1445                    try {
1446                        result = i.getDeclaredMethod("readResolve", params); // NOI18N
1447

1448                        // get out of cycle if method found
1449
break;
1450                    } catch (NoSuchMethodException JavaDoc exc2) {
1451                        // readResolve does not exist in current class
1452
}
1453                }
1454            }
1455
1456            return result;
1457        }
1458    }
1459     // end of Replacer inner class
1460

1461    /** Synchronization between Lookup and getActivatedNodes
1462     */

1463    private class SynchronizeNodes implements org.openide.util.LookupListener, Runnable JavaDoc {
1464        private Lookup.Result<Node> res;
1465
1466        public SynchronizeNodes(Lookup l) {
1467            res = l.lookup(new Lookup.Template<Node>(Node.class));
1468            res.addLookupListener(this);
1469            resultChanged(null);
1470        }
1471
1472        public void resultChanged(org.openide.util.LookupEvent ev) {
1473            boolean l = LOG.isLoggable(Level.FINE);
1474            if (l) {
1475                LOG.fine("lookup changed for " + TopComponent.this + " is visible: " + TopComponent.this.isVisible()); // NOI18N
1476
}
1477            if (TopComponent.this.isVisible() && EventQueue.isDispatchThread()) {
1478                // run immediatelly
1479
run();
1480            } else {
1481                // replan
1482
EventQueue.invokeLater(this);
1483            }
1484            if (l) {
1485                LOG.fine("lookup changed exit " + TopComponent.this); // NOI18N
1486
}
1487        }
1488
1489        public void run() {
1490            boolean l = LOG.isLoggable(Level.FINE);
1491
1492            Collection JavaDoc<? extends Node> nodes = res.allInstances();
1493
1494            if (l) {
1495                LOG.fine("setting nodes for " + TopComponent.this + " to " + nodes); // NOI18N
1496
}
1497            setActivatedNodes(nodes.toArray(new Node[0]));
1498            if (l) {
1499                LOG.fine("setting nodes done for " + TopComponent.this + " to " + nodes); // NOI18N
1500
}
1501        }
1502    }
1503     // end of SynchronizeNodes
1504
}
1505
Popular Tags