alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

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 Strings 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);
    }
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.