KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.io.IOException JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Enumeration JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.LinkedList JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.Set JavaDoc;
30 import java.util.logging.Level JavaDoc;
31 import java.util.logging.Logger JavaDoc;
32 import javax.swing.Action JavaDoc;
33 import javax.swing.ActionMap JavaDoc;
34 import javax.swing.JPopupMenu JavaDoc;
35 import org.openide.util.Enumerations;
36 import org.openide.util.Lookup;
37 import org.openide.util.Utilities;
38 import org.openide.util.WeakListeners;
39 import org.openide.util.actions.SystemAction;
40 import org.openide.util.lookup.Lookups;
41 import org.openide.util.lookup.ProxyLookup;
42
43 /** Utility class for operations on nodes.
44  *
45  * @author Jaroslav Tulach, Petr Hamernik, Dafe Simonek
46  */

47 public final class NodeOp extends Object JavaDoc {
48     /** default node actions */
49     private static SystemAction[] defaultActions;
50
51     private NodeOp() {
52     }
53
54     /** Get the default actions for all nodes.
55     * @return array of default actions
56      * @deprecated Do not use this method. It is useless now.
57     */

58     @Deprecated JavaDoc
59     public static SystemAction[] getDefaultActions() {
60         if (defaultActions == null) {
61             defaultActions = createFromNames(new String JavaDoc[] {"Tools", "Properties"}); // NOI18N
62
}
63
64         return defaultActions;
65     }
66
67     /** @deprecated Useless. */
68     @Deprecated JavaDoc
69     public static void setDefaultActions(SystemAction[] def) {
70         throw new SecurityException JavaDoc();
71     }
72
73     /** Compute common menu for specified nodes.
74     * Provides only those actions supplied by all nodes in the list.
75     * @param nodes the nodes
76     * @return the menu for all nodes
77     */

78     public static JPopupMenu JavaDoc findContextMenu(Node[] nodes) {
79         return findContextMenuImpl(nodes, null);
80     }
81
82     /** Method for finding popup menu for one or more nodes.
83     *
84     * @param nodes array of nodes
85     * @param actionMap maps keys to actions or null
86     * @return popup menu for this array
87     */

88     static JPopupMenu JavaDoc findContextMenuImpl(Node[] nodes, ActionMap JavaDoc actionMap) {
89         Action JavaDoc[] arr = findActions(nodes);
90
91         // prepare lookup representing all the selected nodes
92
List JavaDoc<Lookup> allLookups = new ArrayList JavaDoc<Lookup>();
93
94         for (Node n : nodes) {
95             allLookups.add(n.getLookup());
96         }
97
98         if (actionMap != null) {
99             allLookups.add(Lookups.singleton(actionMap));
100         }
101
102         Lookup lookup = new ProxyLookup(allLookups.toArray(new Lookup[allLookups.size()]));
103
104         return Utilities.actionsToPopup(arr, lookup);
105     }
106
107     /** Asks the provided nodes for their actions and those that are common,
108      * to all of them returns.
109      *
110      * @param nodes array of nodes to compose actions for
111      * @return array of actions for the nodes or empty array if no actions
112      * were found
113      * @since 3.29
114      */

115     public static Action JavaDoc[] findActions(Node[] nodes) {
116         Map JavaDoc<Action JavaDoc,Integer JavaDoc> actions = new HashMap JavaDoc<Action JavaDoc,Integer JavaDoc>();
117
118         Action JavaDoc[][] actionsByNode = new Action JavaDoc[nodes.length][];
119
120         // counts the number of occurences for each action
121
for (int n = 0; n < nodes.length; n++) {
122             actionsByNode[n] = nodes[n].getActions(false);
123
124             if (actionsByNode[n] == null) {
125                 // XXX is this permitted by the API?!
126
// use default actions
127
actionsByNode[n] = defaultActions;
128             }
129
130             // keeps actions handled for this node iteration
131
Set JavaDoc<Action JavaDoc> counted = new HashSet JavaDoc<Action JavaDoc>();
132
133             for (Action JavaDoc a : actionsByNode[n]) {
134                 if (a != null) {
135                     // if this action was handled for this node already, skip to next iteration
136
if (counted.contains(a)) {
137                         continue;
138                     }
139
140                     counted.add(a);
141
142                     Integer JavaDoc cntInt = actions.get(a);
143                     actions.put(a, cntInt == null ? 1 : cntInt + 1);
144                 }
145             }
146         }
147
148         // take all actions that are nodes.length number times
149
if (!actions.isEmpty()) {
150             // keeps actions for which was menu item created already
151
List JavaDoc<Action JavaDoc> result = new ArrayList JavaDoc<Action JavaDoc>();
152             Set JavaDoc<Action JavaDoc> counted = new HashSet JavaDoc<Action JavaDoc>();
153
154             for (Action JavaDoc action : actionsByNode[0]) {
155
156                 if (action != null) {
157                     // if this action has menu item already, skip to next iteration
158
if (counted.contains(action)) {
159                         continue;
160                     }
161
162                     counted.add(action);
163
164                     Integer JavaDoc cntInt = actions.get(action);
165
166                     int cnt = (cntInt == null) ? 0 : cntInt;
167
168                     if (cnt == nodes.length) {
169                         result.add(action);
170                     }
171                 } else {
172                     // place a separator there
173
result.add(null);
174                 }
175             }
176
177             return result.toArray(new Action JavaDoc[result.size()]);
178         } else {
179             // no available actions
180
return new Action JavaDoc[0];
181         }
182     }
183
184     /** Test whether the second node is a (direct) child of the first one.
185     * @param parent parent node
186     * @param son son node
187     * @return <code>true</code> if so
188     */

189     public static boolean isSon(Node parent, Node son) {
190         return son.getParentNode() == parent;
191     }
192
193     /** Find a path (by name) from one node to the root or a parent.
194      * @param node the node to start in
195      * @param parent parent node to stop in (can be <code>null</code> for the root)
196      * @return list of child names--i.e. a path from the parent to the child node
197      * @exception IllegalArgumentException if <code>node</code>'s getName()
198      * method returns <code>null</code>
199      */

200     public static String JavaDoc[] createPath(Node node, Node parent) {
201         LinkedList JavaDoc<String JavaDoc> ar = new LinkedList JavaDoc<String JavaDoc>();
202
203         while ((node != null) && (node != parent)) {
204             if (node.getName() == null) {
205                 boolean isFilter = false;
206
207                 if (node instanceof FilterNode) {
208                     isFilter = true;
209                 }
210
211                 throw new IllegalArgumentException JavaDoc(
212                     "Node:" + node.getClass() // NOI18N
213
+"[" + node.getDisplayName() + "]" // NOI18N
214
+(isFilter ? (" of original:" + ((FilterNode) node).getOriginal().getClass()) : "") // NOI18N
215
+" gets null name!"
216                 ); // NOI18N
217
}
218
219             ar.addFirst(node.getName());
220             node = node.getParentNode();
221         }
222
223         String JavaDoc[] res = new String JavaDoc[ar.size()];
224         ar.toArray(res);
225
226         return res;
227     }
228
229     /** Look for a node child of given name.
230     * @param node node to search in
231     * @param name name of child to look for
232     * @return the found child, or <code>null</code> if there is no such child
233     */

234     public static Node findChild(Node node, String JavaDoc name) {
235         return node.getChildren().findChild(name);
236     }
237
238     /** Traverse a path from a parent node down, by an enumeration of names.
239     * @param start node to start searching at
240     * @param names enumeration of names of nodes
241     * along the path
242     * @return the node with such a path from the start node
243     * @exception NodeNotFoundException if the node with such name
244     * does not exists; the exception contains additional information
245     * about the failure.
246     */

247     public static Node findPath(Node start, Enumeration JavaDoc<String JavaDoc> names)
248     throws NodeNotFoundException {
249         int depth = 0;
250
251         while (names.hasMoreElements()) {
252             String JavaDoc name = names.nextElement();
253             Node next = findChild(start, name);
254
255             if (next == null) {
256                 // no element in list matched the name => fail
257
// fire exception with the last accessed node and the
258
// name of child that does not exists
259
throw new NodeNotFoundException(start, name, depth);
260             } else {
261                 // go on next node
262
start = next;
263             }
264
265             // continue on next depth
266
depth++;
267         }
268
269         return start;
270     }
271
272     /** Traverse a path from a parent node down, by an enumeration of names.
273      * @param start node to start searching at
274      * @param names names of nodes
275      * along the path
276      * @return the node with such a path from the start node
277      * @exception NodeNotFoundException if the node with such name
278      * does not exists; the exception contains additional information
279      * about the failure.
280      */

281     public static Node findPath(Node start, String JavaDoc[] names)
282     throws NodeNotFoundException {
283         return findPath(start, Enumerations.array(names));
284     }
285
286     /** Find the root for a given node.
287     * @param node the node
288     * @return its root
289     */

290     public static Node findRoot(Node node) {
291         for (;;) {
292             Node parent = node.getParentNode();
293
294             if (parent == null) {
295                 return node;
296             }
297
298             node = parent;
299         }
300     }
301
302     /** Compute a permutation between two arrays of nodes. The arrays
303     * must have the same size. The permutation then can be
304     * applied to the first array to create the
305     * second array.
306     *
307     * @param arr1 first array
308     * @param arr2 second array
309     * @return the permutation, or <code>null</code> if the arrays are the same
310     * @exception IllegalArgumentException if the arrays cannot be permuted to each other. Either
311     * they have different sizes or they do not contain the same elements.
312     */

313     public static int[] computePermutation(Node[] arr1, Node[] arr2)
314     throws IllegalArgumentException JavaDoc {
315         if (arr1.length != arr2.length) {
316             int max = Math.max(arr1.length, arr2.length);
317             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
318
319             for (int i = 0; i < max; i++) {
320                 sb.append(i + " "); // NOI18N
321

322                 if (i < arr1.length) {
323                     sb.append(arr1[i].getName());
324                 } else {
325                     sb.append("---"); // NOI18N
326
}
327
328                 sb.append(" = "); // NOI18N
329

330                 if (i < arr2.length) {
331                     sb.append(arr2[i].getName());
332                 } else {
333                     sb.append("---"); // NOI18N
334
}
335
336                 sb.append('\n');
337             }
338
339             throw new IllegalArgumentException JavaDoc(sb.toString());
340         }
341
342         // creates map that assignes to nodes their original
343
// position
344
Map JavaDoc<Node,Integer JavaDoc> map = new HashMap JavaDoc<Node,Integer JavaDoc>();
345
346         for (int i = 0; i < arr2.length; i++) {
347             map.put(arr2[i], i);
348         }
349
350         // takes nodes one by one in the new order and
351
// creates permutation array
352
int[] perm = new int[arr1.length];
353         int diff = 0;
354
355         for (int i = 0; i < arr1.length; i++) {
356             // get the position of the i-th argument in the second array
357
Integer JavaDoc newPos = map.get(arr1[i]);
358
359             if (newPos == null) {
360                 // not permutation i-th element is missing in the array
361
throw new IllegalArgumentException JavaDoc("Missing permutation index " + i); // NOI18N
362
}
363
364             // perm must move the object to the newPos
365
perm[i] = newPos;
366
367             if (perm[i] != i) {
368                 diff++;
369             }
370         }
371
372         return (diff == 0) ? null : perm;
373     }
374
375     /** Takes array of nodes and creates array of handles. The nodes that do not
376     * have handles are not included in the resulting array.
377     *
378     * @param nodes array of nodes
379     * @return array of Node.Handles
380     */

381     public static Node.Handle[] toHandles(Node[] nodes) {
382         List JavaDoc<Node.Handle> ll = new LinkedList JavaDoc<Node.Handle>();
383
384         for (Node n : nodes) {
385             Node.Handle h = n.getHandle();
386
387             if (h != null) {
388                 ll.add(h);
389             }
390         }
391
392         return ll.toArray(new Node.Handle[ll.size()]);
393     }
394
395     /** Takes array of handles and creates array of nodes.
396     * @param handles array of handles
397     * @return array of nodes
398     * @exception IOException if a node cannot be created from the handle
399     */

400     public static Node[] fromHandles(Node.Handle[] handles)
401     throws IOException JavaDoc {
402         Node[] arr = new Node[handles.length];
403
404         for (int i = 0; i < handles.length; i++) {
405             arr[i] = handles[i].getNode();
406         }
407
408         return arr;
409     }
410
411     /** Creates a weak implementation of NodeListener.
412      *
413      * @param l the listener to delegate to
414      * @param source the source that the listener should detach from when
415      * listener <CODE>l</CODE> is freed, can be <CODE>null</CODE>
416      * @return a NodeListener delegating to <CODE>l</CODE>.
417      * @since 4.10
418      */

419     public static NodeListener weakNodeListener(NodeListener l, Object JavaDoc source) {
420         return WeakListeners.create(NodeListener.class, l, source);
421     }
422
423     /** Utility method to remove dependency of this package on
424      * org.openide.actions. This method takes names of classes from
425      * that package and creates their instances.
426      *
427      * @param arr the array of names like "Tools", "Properties", etc. can
428      * contain nulls
429      */

430     static SystemAction[] createFromNames(String JavaDoc[] arr) {
431         List JavaDoc<SystemAction> ll = new LinkedList JavaDoc<SystemAction>();
432
433         for (String JavaDoc n : arr) {
434             if (n == null) {
435                 ll.add(null);
436
437                 continue;
438             }
439
440             String JavaDoc name = "org.openide.actions." + n + "Action"; // NOI18N
441

442             try {
443                 ClassLoader JavaDoc l = Lookup.getDefault().lookup(ClassLoader JavaDoc.class);
444                 if (l == null) {
445                     l = Thread.currentThread().getContextClassLoader();
446                 }
447                 if (l == null) {
448                     l = NodeOp.class.getClassLoader();
449                 }
450                 Class JavaDoc<? extends SystemAction> c = Class.forName(name, true, l).asSubclass(SystemAction.class);
451                 ll.add(SystemAction.get(c));
452             } catch (ClassNotFoundException JavaDoc ex) {
453                 Logger.getAnonymousLogger().log(Level.WARNING, "NodeOp.java: Missing class " + name, ex); // NOI18N
454

455                 // otherwise it is probably ok, that the class is missing
456
}
457         }
458
459         return ll.toArray(new SystemAction[ll.size()]);
460     }
461
462     /** Notifies an exception to error manager or prints its it to stderr.
463      * @param ex exception to notify
464      */

465     static void exception(Throwable JavaDoc ex) {
466         Logger.getLogger(NodeOp.class.getName()).log(Level.WARNING, null, ex);
467     }
468
469     /** Notifies an exception to error manager or prints its it to stderr.
470      * @param ex exception to notify
471      */

472     static void warning(Throwable JavaDoc ex) {
473         Logger.getLogger(NodeOp.class.getName()).log(Level.WARNING, null, ex);
474     }
475 }
476
Popular Tags