|
What this is
This file is included in the DevDaily.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn
Java by Example" TM.
Other links
The source code
/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is NetBeans. The Initial Developer of the Original
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.openide.nodes;
import org.openide.util.WeakListeners;
import java.util.*;
import javax.swing.Action;
import javax.swing.JPopupMenu;
import org.openide.ErrorManager;
import org.openide.util.Lookup;
/** Utility class for operations on nodes.
*
* @author Jaroslav Tulach, Petr Hamernik, Dafe Simonek
*/
public final class NodeOp extends Object {
private NodeOp() {}
/** default node actions */
private static org.openide.util.actions.SystemAction[] defaultActions;
/** Get the default actions for all nodes.
* @return array of default actions
* @deprecated Do not use this method. It is useless now.
*/
public static org.openide.util.actions.SystemAction[] getDefaultActions () {
if (defaultActions == null) {
defaultActions = createFromNames (new String [] {
"Tools", "Properties" // NOI18N
});
}
return defaultActions;
}
/** @deprecated Useless. */
public static void setDefaultActions (org.openide.util.actions.SystemAction[] def) {
throw new SecurityException ();
}
/** Compute common menu for specified nodes.
* Provides only those actions supplied by all nodes in the list.
* @param nodes the nodes
* @return the menu for all nodes
*/
public static JPopupMenu findContextMenu (Node[] nodes) {
return findContextMenuImpl (nodes, null);
}
/** Method for finding popup menu for one or more nodes.
*
* @param nodes array of nodes
* @param actionMap maps keys to actions or null
* @return popup menu for this array
*/
static JPopupMenu findContextMenuImpl (Node[] nodes, javax.swing.ActionMap actionMap) {
Action[] arr = findActions (nodes);
// prepare lookup representing all the selected nodes
ArrayList allLookups = new ArrayList ();
for (int i = 0; i < nodes.length; i++) {
allLookups.add (nodes[i].getLookup ());
}
if (actionMap != null) {
allLookups.add (org.openide.util.lookup.Lookups.singleton(actionMap));
}
Lookup lookup = new org.openide.util.lookup.ProxyLookup (
(Lookup[])allLookups.toArray (new Lookup[allLookups.size()])
);
return org.openide.util.Utilities.actionsToPopup(arr, lookup);
}
/** Asks the provided nodes for their actions and those that are common,
* to all of them returns.
*
* @param nodes array of nodes to compose actions for
* @return array of actions for the nodes or empty array if no actions
* were found
* @since 3.29
*/
public static Action[] findActions (Node[] nodes) {
// hashtable: Action -> Integer
Map actions = new HashMap ();
Action[][] actionsByNode = new Action[nodes.length][];
// counts the number of occurences for each action
for (int n = 0; n < nodes.length; n++) {
actionsByNode[n] = nodes[n].getActions(false);
if (actionsByNode[n] == null) {
// XXX is this permitted by the API?!
// use default actions
actionsByNode[n] = defaultActions;
}
// keeps actions handled for this node iteration
HashSet counted = new HashSet ();
for (int i = 0; i < actionsByNode[n].length; i++) {
if (actionsByNode[n][i] != null) {
// if this action was handled for this node already, skip to next iteration
if (counted.contains (actionsByNode[n][i]))
continue;
counted.add (actionsByNode[n][i]);
Integer cntInt = (Integer)actions.get (actionsByNode[n][i]);
int cnt = cntInt == null ? 0 : cntInt.intValue ();
actions.put (actionsByNode[n][i], new Integer (cnt + 1));
}
}
}
// take all actions that are nodes.length number times
if (!actions.isEmpty ()) {
// keeps actions for which was menu item created already
ArrayList result = new ArrayList ();
HashSet counted = new HashSet ();
for (int i = 0; i < actionsByNode[0].length; i++) {
Action action = actionsByNode[0][i];
if (action != null) {
// if this action has menu item already, skip to next iteration
if (counted.contains (action))
continue;
counted.add (action);
Integer cntInt = (Integer)actions.get (action);
int cnt = cntInt == null ? 0 : cntInt.intValue ();
if (cnt == nodes.length) {
result.add (action);
}
} else {
// place a separator there
result.add (null);
}
}
return (Action[])result.toArray(new Action[result.size()]);
} else {
// no available actions
return new Action[0];
}
}
/** Test whether the second node is a (direct) child of the first one.
* @param parent parent node
* @param son son node
* @return true if so
*/
public static boolean isSon (Node parent, Node son) {
return son.getParentNode () == parent;
}
/** Find a path (by name) from one node to the root or a parent.
* @param node the node to start in
* @param parent parent node to stop in (can be null for the root)
* @return list of child names--i.e. a path from the parent to the child node
* @exception IllegalArgumentException if node 's getName()
* method returns null
*/
public static String[] createPath (Node node, Node parent) {
LinkedList ar = new LinkedList ();
while (node != null && node != parent) {
if (node.getName() == null) {
boolean isFilter = false;
if(node instanceof FilterNode) {
isFilter = true;
}
throw new IllegalArgumentException("Node:" + node.getClass() // NOI18N
+ "[" + node.getDisplayName() +"]" // NOI18N
+ (isFilter ? (" of original:" + ((FilterNode)node).getOriginal().getClass()) : "") // NOI18N
+ " gets null name!"); // NOI18N
}
ar.addFirst (node.getName ());
node = node.getParentNode ();
}
String[] res = new String [ar.size ()];
ar.toArray (res);
return res;
}
/** Look for a node child of given name.
* @param node node to search in
* @param name name of child to look for
* @return the found child, or null if there is no such child
*/
public static Node findChild (Node node, String name) {
return node.getChildren ().findChild (name);
}
/** Traverse a path from a parent node down, by an enumeration of names.
* @param start node to start searching at
* @param names enumeration of String s containing names of nodes
* along the path
* @return the node with such a path from the start node
* @exception NodeNotFoundException if the node with such name
* does not exists; the exception contains additional information
* about the failure.
*/
public static Node findPath (Node start, Enumeration names)
throws NodeNotFoundException {
int depth = 0;
while (names.hasMoreElements ()) {
String name = (String)names.nextElement ();
Node next = findChild (start, name);
if (next == null) {
// no element in list matched the name => fail
// fire exception with the last accessed node and the
// name of child that does not exists
throw new NodeNotFoundException (start, name, depth);
} else {
// go on next node
start = next;
}
// continue on next depth
depth++;
}
return start;
}
/** Traverse a path from a parent node down, by an enumeration of names.
* @param start node to start searching at
* @param names names of nodes
* along the path
* @return the node with such a path from the start node
* @exception NodeNotFoundException if the node with such name
* does not exists; the exception contains additional information
* about the failure.
*/
public static Node findPath (Node start, String[] names)
throws NodeNotFoundException {
return findPath (start, org.openide.util.Enumerations.array (names));
}
/** Find the root for a given node.
* @param node the node
* @return its root
*/
public static Node findRoot (Node node) {
for (;;) {
Node parent = node.getParentNode ();
if (parent == null) return node;
node = parent;
}
}
/** Compute a permutation between two arrays of nodes. The arrays
* must have the same size. The permutation then can be
* applied to the first array to create the
* second array.
*
* @param arr1 first array
* @param arr2 second array
* @return the permutation, or null if the arrays are the same
* @exception IllegalArgumentException if the arrays cannot be permuted to each other. Either
* they have different sizes or they do not contain the same elements.
*/
public static int[] computePermutation (Node[] arr1, Node[] arr2)
throws IllegalArgumentException {
if (arr1.length != arr2.length) {
int max = Math.max (arr1.length, arr2.length);
StringBuffer sb = new StringBuffer ();
for (int i = 0; i < max; i++) {
sb.append (i + " "); // NOI18N
if (i < arr1.length) {
sb.append (arr1[i].getName ());
} else {
sb.append ("---"); // NOI18N
}
sb.append (" = "); // NOI18N
if (i < arr2.length) {
sb.append (arr2[i].getName ());
} else {
sb.append ("---"); // NOI18N
}
sb.append ('\n');
}
throw new IllegalArgumentException (sb.toString ());
}
// creates map that assignes to nodes their original
// position
HashMap map = new HashMap ();
for (int i = 0; i < arr2.length; i++) {
map.put (arr2[i], new Integer (i));
}
// takes nodes one by one in the new order and
// creates permutation array
int[] perm = new int[arr1.length];
int diff = 0;
for (int i = 0; i < arr1.length; i++) {
// get the position of the i-th argument in the second array
Integer newPos = (Integer)map.get (arr1[i]);
if (newPos == null) {
// not permutation i-th element is missing in the array
throw new IllegalArgumentException ("Missing permutation index " + i); // NOI18N
}
// perm must move the object to the newPos
perm[i] = newPos.intValue ();
if (perm[i] != i) {
diff++;
}
}
return diff == 0 ? null : perm;
}
/** Takes array of nodes and creates array of handles. The nodes that do not
* have handles are not included in the resulting array.
*
* @param nodes array of nodes
* @return array of Node.Handles
*/
public static Node.Handle[] toHandles (Node[] nodes) {
LinkedList ll = new LinkedList ();
for (int i = 0; i < nodes.length; i++) {
Node.Handle h = nodes[i].getHandle();
if (h != null) {
ll.add (h);
}
}
return (Node.Handle[])ll.toArray (new Node.Handle[ll.size ()]);
}
/** Takes array of handles and creates array of nodes.
* @param handles array of handles
* @return array of nodes
* @exception IOException if a node cannot be created from the handle
*/
public static Node[] fromHandles (Node.Handle[] handles)
throws java.io.IOException {
Node[] arr = new Node[handles.length];
for (int i = 0; i < handles.length; i++) {
arr[i] = handles[i].getNode ();
}
return arr;
}
/** Creates a weak implementation of NodeListener.
*
* @param l the listener to delegate to
* @param source the source that the listener should detach from when
* listener l is freed, can be null
* @return a NodeListener delegating to l .
* @since 4.10
*/
public static NodeListener weakNodeListener (NodeListener l, Object source) {
return (NodeListener)org.openide.util.WeakListeners.create (NodeListener.class, l, source);
}
/** Utility method to remove dependency of this package on
* org.openide.actions. This method takes names of classes from
* that package and creates their instances.
*
* @param arr the array of names like "Tools", "Properties", etc. can
* contain nulls
*/
static org.openide.util.actions.SystemAction[] createFromNames (String[] arr) {
ErrorManager err = (ErrorManager)
org.openide.util.Lookup.getDefault ().lookup (ErrorManager.class);
LinkedList ll = new LinkedList ();
for (int i = 0; i < arr.length; i++) {
if (arr[i] == null) {
ll.add (null);
continue;
}
String name = "org.openide.actions." + arr[i] + "Action"; // NOI18N
try {
Class c = Class.forName (name);
ll.add (org.openide.util.actions.SystemAction.get (c));
} catch (ClassNotFoundException ex) {
if (err != null) {
err.log (err.INFORMATIONAL, "NodeOp.java: Missing class " + name); // NOI18N
}
// otherwise it is probably ok, that the class is missing
}
}
return (org.openide.util.actions.SystemAction[])ll.toArray (new org.openide.util.actions.SystemAction[ll.size ()]);
}
/** Notifies an exception to error manager or prints its it to stderr.
* @param ex exception to notify
*/
static void exception (Throwable ex) {
ErrorManager.getDefault ().notify (ErrorManager.INFORMATIONAL, ex);
}
/** Notifies an exception to error manager or prints its it to stderr.
* @param ex exception to notify
*/
static void warning (Throwable ex) {
ErrorManager.getDefault ().notify (ErrorManager.WARNING, ex);
}
}
|