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-2004 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.java.ui.nodes;

import java.beans.*;
import java.util.*;

import org.openide.cookies.SourceCookie;

import org.openide.loaders.DataObject;

import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;

import org.openide.src.*;
import org.openide.src.nodes.ClassElementNode;

import org.openide.util.Task;
import org.openide.util.TaskListener;
import org.openide.util.WeakListener;

import org.netbeans.api.java.comparators.JavaElementComparator;
import org.netbeans.modules.java.tools.MultiDataContainer;

/**
 * This node represents a single package. It is configured from an 
 * DataObject.Container and tries to visualize its contents:
 * 
    *
  • Any DataObject.Container found within the supplied container is * processed as a sub-package. If several Containers are found with the same * name, they are merged under the sub-package node. *
  • Any other DataObject is queried for its SourceCokie, if it yields something, * the nodes produced from the SourceCookie are sorted into the node's direct children. *
* * @author sd99038 * @version 0.1 */ public final class PackageNode extends AbstractNode { /** * Icons used to present the node. */ private static final String PACKAGE_ICON_BASE = "org/netbeans/modules/java/resources/package"; // NOI18N /** * The default format for displaying class element nodes. */ private static final ElementFormat CLASS_ELEMENT_FORMAT = new ElementFormat("{C}"); // NOI18N /** * Comparator for sorting classes - it compares class FQNs */ private static final Comparator CLASS_NAME_COMPARATOR = JavaElementComparator.createClassComparator( false, new int[] { JavaElementComparator.NAME }); /** * Initializes a node representing the given Container. */ public PackageNode(String packName, MultiDataContainer container) { super(new PackageChildren(container)); setName(packName); setIconBase(PACKAGE_ICON_BASE); } /** * A specialized Children class that produces two node types - PackageNodes * for sub-packages and ClassElementNodes for classes accepted by the filter. */ private static class PackageChildren extends Children.Keys implements PropertyChangeListener { /** * Container that represents package's contents. */ MultiDataContainer container; /** * Sorted collection of ClassElements contained within the package. */ Collection classElements; /** * Collection of sources that have been already seen/parsed. */ Collection parsingSources; /** * Holds a weak property change listener to the Container and to the * produced SourceElements. */ PropertyChangeListener weakListener; PackageChildren(MultiDataContainer cont) { this.container = cont; this.classElements = new TreeSet(CLASS_NAME_COMPARATOR); this.parsingSources = new LinkedList(); weakListener = WeakListener.propertyChange(this, null); cont.addPropertyChangeListener(weakListener); } public void addNotify() { refreshData(); } /** * Creates nodes for either ClassElements or sub-packages. Other * data type are not supported nor expected. */ protected Node[] createNodes(Object key) { if (key instanceof ClassElement) { Node n = createClassNode((ClassElement)key); if (n != null) return new Node[] { n }; } else if (key instanceof String) { String name = (String)key; MultiDataContainer cont = getPackageContainer(name); if (cont != null) { return new Node[] { createPackageNode((String)key, cont) }; } } return new Node[0]; } /** * Called when some source finishes parsing task. The method sorts the * class elements into the list of classes already recognized. */ private void sortInClasses(ClassElement[] cls) { synchronized (this) { classElements.addAll(Arrays.asList(cls)); } refreshKeys(); } /** * Forces a refresh of children nodes */ private void refreshKeys() { Collection containers = container.getContainers().keySet(); Collection keys = new ArrayList(containers.size() + classElements.size()); keys.addAll(containers); synchronized (this) { keys.addAll(classElements); } setKeys(keys); } /** * Creates a node for this class, if it passed the filter. */ protected final Node createClassNode(ClassElement c) { ClassElementNode node = new ClassElementNode(c, Children.LEAF, true); node.setElementFormat(CLASS_ELEMENT_FORMAT); return node; } /** * Creates a package node from a String. It uses the parent's package * data to extract appropriate container from the data. */ protected final Node createPackageNode(String name, MultiDataContainer data) { return new PackageNode(name, data); } private MultiDataContainer getPackageContainer(String name) { return (MultiDataContainer)this.container.getContainers().get(name); } /** * Refreshes content of the node from the represented Container. The method * schedules parsing on sources which are not yet parsed and attaches a listener * on them. Source which are already parsed are queried for classes they contain * The method builds up class list of those classes. ClassElements from the * objects which are being parsed on background will be filled in after * the parsing task finishes. */ private void refreshData() { DataObject[] contents = container.getChildren(); Collection myChildren = new ArrayList(contents.length); Collection newClassElements = new ArrayList(contents.length); for (int i = 0; i < contents.length; i++) { DataObject d = contents[i]; SourceCookie ck = (SourceCookie)d.getCookie(SourceCookie.class); if (ck != null) { SourceElement src = ck.getSource(); if (parsingSources.add(src)) { src.addPropertyChangeListener(weakListener); if (src.getStatus() == SourceElement.STATUS_NOT) { TaskListener l = new PrepareL(d, src); src.prepare().addTaskListener(l); } else { synchronized (this) { newClassElements.addAll(Arrays.asList(src.getAllClasses())); } } } } } synchronized (this) { classElements = newClassElements; } refreshKeys(); } public void propertyChange(PropertyChangeEvent evt) { Object source = evt.getSource(); String propName = evt.getPropertyName(); if (source == container) { if (MultiDataContainer.PROP_CONTAINERS.equals(propName) || MultiDataContainer.PROP_CHILDREN.equals(propName)) { refreshData(); } } else { if (ElementProperties.PROP_ALL_CLASSES.equals(evt.getPropertyName())) { refreshData(); } } } /** * Listener that watches parsing tasks. TODO - it should also watch * PROP_CLASSES changes on sources already registered :) */ private class PrepareL implements TaskListener { DataObject sourceDO; SourceElement srcElement; PrepareL(DataObject source, SourceElement src) { this.sourceDO = source; this.srcElement = src; } public void taskFinished(Task t) { t.removeTaskListener(this); sortInClasses(srcElement.getAllClasses()); } } } }
... 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.