|
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
}
|