KickJava   Java API By Example, From Geeks To Geeks.

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


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.io.Externalizable JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.ObjectInput JavaDoc;
25 import java.io.ObjectInputStream JavaDoc;
26 import java.io.ObjectOutput JavaDoc;
27 import java.io.Serializable JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.Enumeration JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.Set JavaDoc;
33 import org.openide.util.NbBundle;
34 import org.openide.util.io.NbMarshalledObject;
35
36 /** A top component which may be cloned.
37 * Typically cloning is harmless, i.e. the data contents (if any)
38 * of the component are the same, and the new component is merely
39 * a different presentation.
40 * Also, a list of all cloned components is kept.
41 *
42 * @author Jaroslav Tulach
43 */

44 public abstract class CloneableTopComponent extends TopComponent implements Externalizable JavaDoc, TopComponent.Cloneable {
45     /** generated Serialized Version UID */
46     static final long serialVersionUID = 4893753008783256289L;
47
48     // say what? --jglick
49

50     /* Empty set that should save work with testing like
51     * <pre>
52     * if (ref == null || ref.isEmpty ()) {
53     * CloneableTopComponent c = new CloneableTopComponent (obj);
54     * ref = c.getReference ();
55     * }
56     * </pre>
57     * Instead one can always set <CODE>ref = Ref.EMPTY</CODE> and test only if
58     * <CODE>ref.isEmpty</CODE> returns <CODE>true</CODE>.
59     */

60
61     /** Empty clone-sister list.
62     */

63     public static final Ref EMPTY = new Ref();
64
65     /** reference with list of components */
66     private Ref ref;
67
68     /** Create a cloneable top component.
69     */

70     public CloneableTopComponent() {
71     }
72
73     /** Clone the top component and register the clone.
74     * @return the new component
75     */

76     public final Object JavaDoc clone() {
77         return cloneComponent();
78     }
79
80     /** Clone the top component and register the clone.
81     * Simply calls createClonedObject () and registers the component to
82     * Ref.
83     *
84     * @return the new cloneable top component
85     */

86     public final CloneableTopComponent cloneTopComponent() {
87         CloneableTopComponent top = createClonedObject();
88
89         // register the component if it has not been registered before
90
top.setReference(getReference());
91
92         return top;
93     }
94
95     /** Clone the top component and register the clone.
96     * @return the new component
97     */

98     public final TopComponent cloneComponent() {
99         return cloneTopComponent();
100     }
101
102     /** Called from {@link #clone} to actually create a new component from this one.
103     * The default implementation only clones the object by calling {@link Object#clone}.
104     * Subclasses may leave this as is, assuming they have no special needs for the cloned
105     * data besides copying it from one object to the other. If they do, the superclass
106     * method should be called, and the returned object modified appropriately.
107     * @return a copy of this object
108     */

109     protected CloneableTopComponent createClonedObject() {
110         try {
111             // clones the component using serialization
112
NbMarshalledObject o = new NbMarshalledObject(this);
113             return (CloneableTopComponent) o.get();
114         } catch (IOException JavaDoc ex) {
115             throw new AssertionError JavaDoc(ex);
116         } catch (ClassNotFoundException JavaDoc ex) {
117             throw new AssertionError JavaDoc(ex);
118         }
119     }
120
121     /** Get a list of all components which are clone-sisters of this one.
122     *
123     * @return the clone registry for this component's group
124     */

125     public synchronized final Ref getReference() {
126         if (ref == null) {
127             ref = new Ref(this);
128         }
129
130         return ref;
131     }
132
133     /** Changes the reference to which this components belongs.
134     * @param another the new reference this component should belong
135     */

136     public synchronized final void setReference(Ref another) {
137         if (another == EMPTY) {
138             throw new IllegalArgumentException JavaDoc(
139                 NbBundle.getBundle(CloneableTopComponent.class).getString("EXC_CannotAssign")
140             );
141         }
142
143         if (ref != null) {
144             // Remove from old ref, we are going to belong to 'another' reference.
145
ref.removeComponent(this);
146         }
147
148         // Register with the new reference.
149
another.register(this);
150
151         // Finally set the field.
152
ref = another;
153     }
154
155     /** Overrides superclass method, adds unregistering from references.
156      * @see Ref */

157     protected void componentClosed() {
158         super.componentClosed();
159
160         if (!isOpened()) {
161             getReference().unregister(this);
162         }
163     }
164
165     /**
166      * Unregisters this component from its clone list.
167      * {@inheritDoc}
168      */

169     public boolean canClose() {
170         if (!isOpened()) {
171             return false;
172         }
173
174         return getReference().unregister(this);
175     }
176
177     @SuppressWarnings JavaDoc("deprecation")
178     public boolean canClose(Workspace workspace, boolean last) {
179         if (last) {
180             return getReference().unregister(this);
181         }
182
183         return true;
184     }
185
186     /** Called when the last component in a clone group is closing.
187     * The default implementation just returns <code>true</code>.
188     * Subclasses may specify some hooks to run.
189     * @return <CODE>true</CODE> if the component is ready to be
190     * closed, <CODE>false</CODE> to cancel
191     */

192     protected boolean closeLast() {
193         return true;
194     }
195
196     public void readExternal(ObjectInput JavaDoc oi) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
197         super.readExternal(oi);
198
199         if (serialVersion != 0) {
200             // since serialVersion > 0
201
// the reference object is also stored
202
Ref ref = (Ref) oi.readObject();
203
204             if (ref != null) {
205                 setReference(ref);
206             }
207         }
208     }
209
210     public void writeExternal(ObjectOutput JavaDoc oo) throws java.io.IOException JavaDoc {
211         super.writeExternal(oo);
212
213         oo.writeObject(ref);
214     }
215
216     /** Keeps track of a group of sister clones.
217     * <P>
218     * <B>Warning:</B>
219     * For proper use
220     * subclasses should have method readResolve () and implement it
221     * in right way to deal with separate serialization of TopComponent.
222     */

223     public static class Ref implements Serializable JavaDoc {
224         /** generated Serialized Version UID */
225         static final long serialVersionUID = 5543148876020730556L;
226
227         /** manipulation lock */
228         private static final Object JavaDoc LOCK = new Object JavaDoc();
229
230         /** Set of registered components. */
231         private transient /*final*/ Set JavaDoc<CloneableTopComponent> componentSet = new HashSet JavaDoc<CloneableTopComponent>(7);
232
233         /** Default constructor for creating empty reference.
234         */

235         protected Ref() {
236         }
237
238         /** Constructor.
239         * @param c the component to refer to
240         */

241         private Ref(CloneableTopComponent c) {
242             synchronized (LOCK) {
243                 componentSet.add(c);
244             }
245         }
246
247         /** Enumeration of all registered components.
248         * @return enumeration of CloneableTopComponent
249         */

250         public Enumeration JavaDoc<CloneableTopComponent> getComponents() {
251             Set JavaDoc<CloneableTopComponent> components;
252
253             synchronized (LOCK) {
254                 components = new HashSet JavaDoc<CloneableTopComponent>(componentSet);
255             }
256
257             return Collections.enumeration(components);
258         }
259
260         /** Test whether there is any component in this set.
261         * @return <CODE>true</CODE> if the reference set is empty
262         */

263         public boolean isEmpty() {
264             synchronized (LOCK) {
265                 return componentSet.isEmpty();
266             }
267         }
268
269         /** Retrieve an arbitrary component from the set.
270         * @return some component from the list of registered ones
271         * @exception NoSuchElementException if the set is empty
272          * @deprecated Use {@link #getArbitraryComponent} instead.
273          * It doesn't throw a runtime exception.
274         */

275         public CloneableTopComponent getAnyComponent() {
276             synchronized (LOCK) {
277                 return componentSet.iterator().next();
278             }
279         }
280
281         /** Gets arbitrary component from the set. Preferrably returns currently
282          * active component if found in the set.
283          * @return arbitratry <code>CloneableTopComponent</code> from the set
284          * or <code>null</code> if the set is empty
285          * @since 3.41 */

286         public CloneableTopComponent getArbitraryComponent() {
287             TopComponent activated = WindowManager.getDefault().getRegistry().getActivated();
288
289             synchronized (LOCK) {
290                 // prefer already active component
291
if (componentSet.contains(activated)) {
292                     return (CloneableTopComponent) activated;
293                 }
294
295                 Iterator JavaDoc<CloneableTopComponent> it = componentSet.iterator();
296
297                 if (it.hasNext()) {
298                     return it.next();
299                 } else {
300                     return null;
301                 }
302             }
303         }
304
305         /** Register new component.
306         * @param c the component to register
307         */

308         private final void register(CloneableTopComponent c) {
309             synchronized (LOCK) {
310                 componentSet.add(c);
311             }
312         }
313
314         /** Unregister the component. If this is the last asks if it is
315         * allowed to unregister it.
316         *
317         * @param c the component to unregister
318         * @return true if the component agreed to be unregister
319         */

320         private final boolean unregister(CloneableTopComponent c) {
321             int componentCount;
322
323             synchronized (LOCK) {
324                 if (!componentSet.contains(c)) {
325                     return true;
326                 }
327
328                 componentCount = componentSet.size();
329             }
330
331             if ((componentCount > 1) || c.closeLast()) {
332                 removeComponent(c);
333
334                 return true;
335             } else {
336                 return false;
337             }
338         }
339
340         private void removeComponent(CloneableTopComponent c) {
341             synchronized (LOCK) {
342                 componentSet.remove(c);
343             }
344         }
345
346         /** Adds also initializing of <code>componentSet</code> field. */
347         private void readObject(ObjectInputStream JavaDoc in) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
348             in.defaultReadObject();
349
350             synchronized (LOCK) {
351                 componentSet = new HashSet JavaDoc<CloneableTopComponent>(7);
352             }
353         }
354     }
355      // end of Ref
356
}
357
Popular Tags