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.src.nodes;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.util.*;

import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.cookies.FilterCookie;
import org.openide.util.WeakListeners;
import org.openide.src.*;

/** Normal implementation of children list for a class element node.
* Semantics are similar to those of {@link SourceChildren}.
* @author Dafe Simonek, Jan Jancura
*/
public class ClassChildren extends Children.Keys implements FilterCookie {

    /** Support for PACKAGE modifier */
    private static int                  PPP_MASK = SourceElementFilter.PUBLIC +
            SourceElementFilter.PRIVATE +
            SourceElementFilter.PROTECTED;
    /** Converts property names to filter. */
    protected static HashMap              propToFilter;

    /** For sorting groups of elements. */
    private static Comparator           comparator = new Comparator () {
                public int compare (Object o1, Object o2) {
                    if (o1 instanceof MemberElement)
                        if (o2 instanceof MemberElement)
                            return ((MemberElement) o1).getName ().getName ().compareToIgnoreCase (
                                       ((MemberElement) o2).getName ().getName ()
                                   );
                        else
                            return -1;
                    else
                        if (o2 instanceof MemberElement)
                            return 1;
                        else
                            return 0;
                }
            };

    static {
        propToFilter = new HashMap ();
        propToFilter.put (ElementProperties.PROP_CLASSES, new Integer (ClassElementFilter.CLASS | ClassElementFilter.INTERFACE));
        propToFilter.put (ElementProperties.PROP_METHODS, new Integer (ClassElementFilter.METHOD));
        propToFilter.put (ElementProperties.PROP_FIELDS, new Integer (ClassElementFilter.FIELD));
        propToFilter.put (ElementProperties.PROP_CONSTRUCTORS, new Integer (ClassElementFilter.CONSTRUCTOR));
        propToFilter.put (ElementProperties.PROP_INITIALIZERS, new Integer (ClassElementFilter.CONSTRUCTOR));
    }

    /** The class element whose subelements are represented. */
    protected ClassElement              element;
    /** Filter for elements, or null to disable. */
    protected ClassElementFilter        filter;
    /** Factory for creating new child nodes. */
    protected ElementNodeFactory        factory;
    /** Weak listener to the element and filter changes */
    private PropertyChangeListener      wPropL;
    /** Listener to the element and filter changes. This reference must
    * be kept to prevent the listener from finalizing when we are alive */
    private ElementListener             propL;
    /** Central memory of mankind is used when some elements are changed */
    protected Collection[]              cpl;
    /** Flag saying whether we have our nodes initialized */
    private boolean                     nodesInited = false;


    // init ................................................................................

    /** Create class children with the default factory.
    * The children are initially unfiltered.
    * @param element attached class element (non-null)
    */
    public ClassChildren (final ClassElement element) {
        this(DefaultFactory.READ_WRITE, element);
    }

    /** Create class children.
    * The children are initially unfiltered.
    * @param factory the factory to use to create new children
    * @param element attached class element (non-null)
    */
    public ClassChildren (final ElementNodeFactory factory,
                          final ClassElement element) {
        super();
        this.element = element;
        this.factory = factory;
        this.filter = null;
    }


    /********** Implementation of filter cookie **********/

    /* @return The class of currently asociated filter or null
    * if no filter is asociated with these children.
    */
    public Class getFilterClass () {
        return ClassElementFilter.class;
    }

    /* @return The filter currently asociated with these children
    */
    public Object getFilter () {
        return filter;
    }

    /* Sets new filter for these children.
    * @param filter New filter. Null == disable filtering.
    */
    public void setFilter (final Object filter) {
        if (!(filter instanceof ClassElementFilter))
            throw new IllegalArgumentException();

        this.filter = (ClassElementFilter)filter;
        // change element nodes according to the new filter
        if (nodesInited)
            refreshAllKeys ();
    }


    // Children implementation ..............................................................

    /* Overrides initNodes to run the preparation task of the
    * source element, call refreshKeys and start to
    * listen to the changes in the element too. */
    protected void addNotify () {
        // listen to the changes in the class element
        if (wPropL == null) {
            propL = new ElementListener(this);
            wPropL = WeakListeners.propertyChange (propL, element);
        }
        refreshAllKeys ();
        element.addPropertyChangeListener (wPropL);
        nodesInited = true;
    }

    protected void removeNotify () {
        setKeys (java.util.Collections.EMPTY_SET);
        nodesInited = false;
    }
    
    private Node hookNodeName(Node n) {
        MemberElement el = (MemberElement)n.getCookie(MemberElement.class);
        if (el != null)
            el.addPropertyChangeListener(propL);
        return n;
    }

    /* Creates node for given key.
    * The node is created using node factory.
    */
    protected Node[] createNodes (final Object key) {
        if (key instanceof MethodElement) {
            return new Node[] { hookNodeName(factory.createMethodNode((MethodElement)key)) };
        }
        if (key instanceof FieldElement) {
            return new Node[] { hookNodeName(factory.createFieldNode((FieldElement)key)) };
        }
        if (key instanceof ConstructorElement) {
            return new Node[] { hookNodeName(factory.createConstructorNode((ConstructorElement)key)) };
        }
        if (key instanceof ClassElement) {
            return new Node[] { hookNodeName(factory.createClassNode((ClassElement)key)) };
        }
        if (key instanceof InitializerElement) {
            return new Node[] { hookNodeName(factory.createInitializerNode((InitializerElement)key)) };
        }
        // ?? unknown type
        return new Node[0];
    }


    /************** utility methods ************/

    /** Updates all the keys (elements) according to the current filter &
    * ordering.
    */
    protected void refreshAllKeys () {
        cpl = new Collection [getOrder ().length];
        refreshKeys (ClassElementFilter.ALL);
    }

    /** Updates all the keys with given filter.
    */
    protected void refreshKeys (int filter) {
        int[] order = getOrder ();
        LinkedList keys = new LinkedList();
        // build ordered and filtered keys for the subelements
        for (int i = 0; i < order.length; i++) {
            if (((order[i] & filter) != 0) || (cpl [i] == null))
                keys.addAll (cpl [i] = getKeysOfType (order[i]));
            else
                keys.addAll (cpl [i]);
        }
        // set new keys
        ElementListener l = propL;
        if (l != null)
            l.updateElements(keys);
        setKeys(keys);
    }

    /** Filters and returns the keys of specified type.
    */
    protected Collection getKeysOfType (final int elementType) {
        LinkedList keys = new LinkedList();
        if ((elementType & ClassElementFilter.EXTENDS) != 0) {
            keys.add (element.getSuperclass ());
        }
        if ((elementType & ClassElementFilter.IMPLEMENTS) != 0) {
            keys.addAll (Arrays.asList (element.getInterfaces ()));
        }
        if ((elementType & ClassElementFilter.FIELD) != 0) {
            filterModifiers (element.getFields (), keys);
        }
        if ((elementType & ClassElementFilter.CONSTRUCTOR) != 0) {
            filterModifiers (element.getConstructors (), keys);
            keys.addAll (Arrays.asList (element.getInitializers ()));
        }
        if ((elementType & ClassElementFilter.METHOD) != 0) {
            filterModifiers (element.getMethods (), keys);
        }
        if ((elementType & (ClassElementFilter.CLASS + ClassElementFilter.INTERFACE)) != 0) {
            filterClassModifiers (element.getClasses (), keys, elementType);
        }
        if ((filter == null) || filter.isSorted ())
            Collections.sort (keys, comparator);
        return keys;
    }

    /** Returns order form filter.
    */
    protected int[] getOrder () {
        return (filter == null || (filter.getOrder() == null))
               ? ClassElementFilter.DEFAULT_ORDER : filter.getOrder();
    }

    /** Returns modifier filter form filter.
    */
    private int getModifierFilter () {
        if (filter == null) return ClassElementFilter.ALL_MODIFIERS;
        return filter.getModifiers ();
    }

    /** Filters MemberElements for modifiers, and adds them to the given collection.
    */
    private void filterModifiers (MemberElement[] elements, Collection keys) {
        int ff = getModifierFilter ();
        int i, k = elements.length;
        for (i = 0; i < k; i ++) {
            int f = elements [i].getModifiers ();
            if ((f & PPP_MASK) == 0) f += ClassElementFilter.PACKAGE;
            if ((f & ff) != 0) keys.add (elements [i]);
        }
    }

    /** Filters ClassElements for their type, and adds them to the given collection.
    */
    private void filterClassModifiers (ClassElement[] elements, Collection keys, int filter) {
        int ff = getModifierFilter ();
        int i, k = elements.length;
        for (i = 0; i < k; i ++) {
            int f = elements [i].getModifiers ();
            if ((f & PPP_MASK) == 0) f += ClassElementFilter.PACKAGE;
            if ((f & ff) == 0) continue;
            if (elements [i].isClass ()) {
                if ((filter & ClassElementFilter.CLASS) != 0) keys.add (elements [i]);
            } else
                if ((filter & ClassElementFilter.INTERFACE) != 0) keys.add (elements [i]);
        }
    }


    // innerclasses ...........................................................................

    /** The listener for listening to the property changes in the filter.
    */
    private static final class ElementListener extends java.lang.ref.WeakReference implements Runnable, PropertyChangeListener {
        Collection elements;

        ElementListener(ClassChildren cc) {
            super(cc, org.openide.util.Utilities.activeReferenceQueue());
        }

        ClassChildren getClassChildren() {
            Object o = get();
            return (ClassChildren)o;
        }

        /** This method is called when the change of properties occurs in the element.
        * PENDING - (for Hanz - should be implemented better, change only the
        * keys which belong to the changed property).
        * -> YES MY LORD! ANOTHER WISH?
        */
        public void propertyChange (PropertyChangeEvent evt) {
            Object src = evt.getSource();
            String propName = evt.getPropertyName();
            int filter;

            ClassChildren cc = getClassChildren();
            if (cc == null)
                return;

            if (src != cc.element) {
                if (src instanceof MemberElement &&
                    (propName == null || ElementProperties.PROP_NAME == propName)) {
                    if (src instanceof MethodElement)
                        filter = ClassElementFilter.METHOD;
                    else if (src instanceof ConstructorElement) 
                        filter = ClassElementFilter.CONSTRUCTOR;
                    else if (src instanceof FieldElement)
                        filter = ClassElementFilter.FIELD;
                    else
                        filter = ClassElementFilter.CLASS | ClassElementFilter.INTERFACE;
                } else
                    return;
            } else {
               Integer i = (Integer) cc.propToFilter.get (propName);
               if (i == null)
                   return;
               filter = i.intValue();
            }
            cc.refreshKeys (filter);
        }

        void updateElements(Collection c) {
            this.elements = c;
        }

        public void run() {
            // clean-up
            for (Iterator it = elements.iterator(); it.hasNext(); ) {
                Object o = it.next();
                if (!(o instanceof Element))
                    continue;
                Element el = (Element)o;
                el.removePropertyChangeListener(this);
            }
        }
    } // end of ElementListener inner class
}
... 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.