KickJava   Java API By Example, From Geeks To Geeks.

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


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.windows;
20
21 import org.openide.nodes.Node;
22 import org.openide.util.Lookup;
23 import org.openide.util.LookupEvent;
24 import org.openide.util.LookupListener;
25 import org.openide.util.WeakListeners;
26 import org.openide.util.lookup.AbstractLookup;
27 import org.openide.util.lookup.Lookups;
28 import org.openide.util.lookup.ProxyLookup;
29
30 import java.util.ArrayList JavaDoc;
31 import java.util.Collection JavaDoc;
32 import java.util.Collections JavaDoc;
33 import java.util.HashMap JavaDoc;
34 import java.util.IdentityHashMap JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.Set JavaDoc;
39 import java.util.WeakHashMap JavaDoc;
40
41
42 /**
43  * Contents of the lookup for a top component.
44  * Should contain its activated nodes, as well as their lookups merged.
45  * Also contains an ActionMap instance which is a {@link DelegateActionMap}.
46  * If there is no selection (as opposed to an empty selection), the lookup on Node
47  * nonetheless contains one item assignable to Node but with a null instance (!).
48  * If a node contains itself or another node in its lookup, this does not produce
49  * any duplication in the top component lookup.
50  * Queries on Node will return only nodes actually in the activated node list.
51  * @author Jaroslav Tulach
52  */

53 final class DefaultTopComponentLookup extends ProxyLookup implements LookupListener {
54     private static final Object JavaDoc PRESENT = new Object JavaDoc();
55
56     /** component to work with */
57     private TopComponent tc;
58
59     /** lookup listener that is attached to all subnodes */
60     private LookupListener listener;
61
62     /** Map of (Lookup -> node Lookup.Result) the above lookup listener is attached to */
63     private Map JavaDoc<Lookup,Lookup.Result> attachedTo;
64
65     /** action map for the top component */
66     private Lookup actionMap;
67
68     /** Creates the lookup.
69      * @param tc component to work on
70     */

71     public DefaultTopComponentLookup(TopComponent tc) {
72         super();
73
74         this.tc = tc;
75         this.listener = (LookupListener) WeakListeners.create(LookupListener.class, this, null);
76         this.actionMap = Lookups.singleton(new DelegateActionMap(tc));
77
78         updateLookups(tc.getActivatedNodes());
79     }
80
81     /** Extracts activated nodes from a top component and
82      * returns their lookups.
83      */

84     public void updateLookups(Node[] arr) {
85         if (arr == null) {
86             AbstractLookup.Content c = new AbstractLookup.Content();
87             AbstractLookup l = new AbstractLookup(c);
88             c.addPair(new NoNodesPair());
89             setLookups(new Lookup[] { l, actionMap });
90
91             return;
92         }
93
94         Lookup[] lookups = new Lookup[arr.length];
95
96         Map JavaDoc<Lookup,Lookup.Result> copy;
97
98         synchronized (this) {
99             if (attachedTo == null) {
100                 copy = Collections.emptyMap();
101             } else {
102                 copy = new HashMap JavaDoc<Lookup,Lookup.Result>(attachedTo);
103             }
104         }
105
106         for (int i = 0; i < arr.length; i++) {
107             lookups[i] = arr[i].getLookup();
108
109             if (copy != null) {
110                 // node arr[i] remains there, so do not remove it
111
copy.remove(arr[i]);
112             }
113         }
114
115         for (Iterator JavaDoc<Lookup.Result> it = copy.values().iterator(); it.hasNext();) {
116             Lookup.Result res = it.next();
117             res.removeLookupListener(listener);
118         }
119
120         synchronized (this) {
121             attachedTo = null;
122         }
123
124         setLookups(new Lookup[] { new NoNodeLookup(new ProxyLookup(lookups), arr), Lookups.fixed((Object JavaDoc[])arr), actionMap, });
125     }
126
127     /** Change in one of the lookups we delegate to */
128     public void resultChanged(LookupEvent ev) {
129         updateLookups(tc.getActivatedNodes());
130     }
131
132     /** Finds out whether a query for a class can be influenced
133      * by a state of the "nodes" lookup and whether we should
134      * initialize listening
135      */

136     private static boolean isNodeQuery(Class JavaDoc<?> c) {
137         return Node.class.isAssignableFrom(c) || c.isAssignableFrom(Node.class);
138     }
139
140     protected synchronized void beforeLookup(Template<?> t) {
141         if ((attachedTo == null) && isNodeQuery(t.getType())) {
142             Lookup[] arr = getLookups();
143
144             attachedTo = new WeakHashMap JavaDoc<Lookup,Lookup.Result>(arr.length * 2);
145
146             for (int i = 0; i < (arr.length - 2); i++) {
147                 Lookup.Result<?> res = arr[i].lookup(t);
148                 res.addLookupListener(listener);
149                 attachedTo.put(arr[i], res);
150             }
151         }
152     }
153
154     private static final class NoNodesPair extends AbstractLookup.Pair {
155         public NoNodesPair() {
156         }
157
158         protected boolean creatorOf(Object JavaDoc obj) {
159             return false;
160         }
161
162         public String JavaDoc getDisplayName() {
163             return getId();
164         }
165
166         public String JavaDoc getId() {
167             return "none"; // NOI18N
168
}
169
170         public Object JavaDoc getInstance() {
171             return null;
172         }
173
174         public Class JavaDoc getType() {
175             return org.openide.nodes.Node.class;
176         }
177
178         protected boolean instanceOf(Class JavaDoc c) {
179             return Node.class.isAssignableFrom(c);
180         }
181     }
182      // end of NoNodesPair
183

184     // XXX try to use Lookups.exclude; cf. comments in #53058
185

186     /**
187      * A proxying Lookup impl which yields no results when queried for Node,
188      * and will never return any of the listed objects.
189      */

190     private static final class NoNodeLookup extends Lookup {
191         private final Lookup delegate;
192         private final Map JavaDoc<Object JavaDoc,Object JavaDoc> verboten;
193
194         public NoNodeLookup(Lookup del, Object JavaDoc[] exclude) {
195             delegate = del;
196             verboten = new IdentityHashMap JavaDoc<Object JavaDoc,Object JavaDoc>();
197
198             for (int i = 0; i < exclude.length; verboten.put(exclude[i++], PRESENT))
199                 ;
200         }
201
202         public <T> T lookup(Class JavaDoc<T> clazz) {
203             if (clazz == Node.class) {
204                 return null;
205             } else {
206                 T o = delegate.lookup(clazz);
207
208                 if (verboten.containsKey(o)) {
209                     // There might be another one of the same class.
210
for( T o2 : lookupAll(clazz) ) {
211
212                         if (!verboten.containsKey(o2)) {
213                             // OK, use this one.
214
return o2;
215                         }
216                     }
217
218                     // All such instances were excluded.
219
return null;
220                 } else {
221                     return o;
222                 }
223             }
224         }
225
226         @SuppressWarnings JavaDoc("unchecked")
227         public <T> Lookup.Result<T> lookup(Lookup.Template<T> template) {
228             if (template.getType() == Node.class) {
229                 return Lookup.EMPTY.lookup(new Lookup.Template(Node.class));
230             } else {
231                 return new ExclusionResult<T>(delegate.lookup(template), verboten);
232             }
233         }
234
235         /**
236          * A lookup result excluding some instances.
237          */

238         private static final class ExclusionResult<T> extends Lookup.Result<T> implements LookupListener {
239             private final Lookup.Result<T> delegate;
240             private final Map JavaDoc<Object JavaDoc,Object JavaDoc> verboten;
241             private final List JavaDoc<LookupListener> listeners = new ArrayList JavaDoc<LookupListener>();
242
243             public ExclusionResult(Lookup.Result<T> delegate, Map JavaDoc<Object JavaDoc,Object JavaDoc> verboten) {
244                 this.delegate = delegate;
245                 this.verboten = verboten;
246             }
247
248             public Collection JavaDoc<? extends T> allInstances() {
249                 Collection JavaDoc<? extends T> c = delegate.allInstances();
250                 List JavaDoc<T> ret = new ArrayList JavaDoc<T>(c.size()); // upper bound
251

252                 for (Iterator JavaDoc<? extends T> it = c.iterator(); it.hasNext();) {
253                     T o = it.next();
254
255                     if (!verboten.containsKey(o)) {
256                         ret.add(o);
257                     }
258                 }
259
260                 return ret;
261             }
262
263             public Set JavaDoc<Class JavaDoc<? extends T>> allClasses() {
264                 return delegate.allClasses(); // close enough
265
}
266
267             public Collection JavaDoc<? extends Lookup.Item<T>> allItems() {
268                 Collection JavaDoc<? extends Lookup.Item<T>> c = delegate.allItems();
269                 List JavaDoc<Lookup.Item<T>> ret = new ArrayList JavaDoc<Lookup.Item<T>>(c.size()); // upper bound
270

271                 for (Iterator JavaDoc<? extends Lookup.Item<T>> it = c.iterator(); it.hasNext();) {
272                     Lookup.Item<T> i = it.next();
273
274                     if (!verboten.containsKey(i.getInstance())) {
275                         ret.add(i);
276                     }
277                 }
278
279                 return ret;
280             }
281
282             public void addLookupListener(LookupListener l) {
283                 synchronized (listeners) {
284                     if (listeners.isEmpty()) {
285                         delegate.addLookupListener(this);
286                     }
287
288                     listeners.add(l);
289                 }
290             }
291
292             public void removeLookupListener(LookupListener l) {
293                 synchronized (listeners) {
294                     listeners.remove(l);
295
296                     if (listeners.isEmpty()) {
297                         delegate.removeLookupListener(this);
298                     }
299                 }
300             }
301
302             public void resultChanged(LookupEvent ev) {
303                 LookupEvent ev2 = new LookupEvent(this);
304                 LookupListener[] ls;
305
306                 synchronized (listeners) {
307                     ls = (LookupListener[]) listeners.toArray(new LookupListener[listeners.size()]);
308                 }
309
310                 for (int i = 0; i < ls.length; i++) {
311                     ls[i].resultChanged(ev2);
312                 }
313             }
314         }
315     }
316 }
317
Popular Tags