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.windows;

import org.openide.util.WeakListeners;
import java.beans.*;
import java.util.*;

import org.openide.nodes.*;
import org.openide.util.Lookup;
import org.openide.util.LookupEvent;
import org.openide.util.LookupListener;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup;

/**
 * Contents of the lookup for a top component.
 * Should contain its activated nodes, as well as their lookups merged.
 * Also contains an ActionMap instance which is a {@link DelegateActionMap}.
 * If there is no selection (as opposed to an empty selection), the lookup on Node
 * nonetheless contains one item assignable to Node but with a null instance (!).
 * If a node contains itself or another node in its lookup, this does not produce
 * any duplication in the top component lookup.
 * Queries on Node will return only nodes actually in the activated node list.
 * @author Jaroslav Tulach
 */
final class DefaultTopComponentLookup extends ProxyLookup implements LookupListener {
    /** component to work with */
    private TopComponent tc;
    /** lookup listener that is attached to all subnodes */
    private LookupListener listener;
    /** Map of (Node -> node Lookup.Result) the above lookup listener is attached to */
    private Map attachedTo;
    /** action map for the top component */
    private Lookup actionMap;
    
    /** Creates the lookup.
     * @param tc component to work on
    */
    public DefaultTopComponentLookup(TopComponent tc) {
        super ();
        
        this.tc = tc;
        this.listener = (LookupListener)WeakListeners.create(LookupListener.class, this, null);
        this.actionMap = Lookups.singleton (new DelegateActionMap (tc));
        
        updateLookups (tc.getActivatedNodes ());
    }
    
    /** Extracts activated nodes from a top component and
     * returns their lookups.
     */
    public void updateLookups (Node[] arr) {
        if (arr == null) {
            AbstractLookup.Content c = new AbstractLookup.Content();
            AbstractLookup l = new AbstractLookup(c);
            c.addPair (new NoNodesPair ());
            setLookups (new Lookup[] { l, actionMap });
            return;
        }
        
        Lookup[] lookups = new Lookup[arr.length];
        
        Map copy;
        synchronized (this) {
            if (attachedTo == null) {
                copy = Collections.EMPTY_MAP;
            } else {
                copy = new HashMap (attachedTo);
            }
        }
        
        for (int i = 0; i < arr.length; i++) {
            lookups[i] = arr[i].getLookup ();
            if (copy != null) {
                // node arr[i] remains there, so do not remove it
                copy.remove (arr[i]);
            }
        }
        
        for (Iterator it = copy.values().iterator(); it.hasNext(); ) {
            Lookup.Result res = (Lookup.Result)it.next ();
            res.removeLookupListener (listener);
        }
        
        synchronized (this) {
            attachedTo = null;
        }
        
        setLookups(new Lookup[] {
            new NoNodeLookup(new ProxyLookup(lookups), arr),
            Lookups.fixed(arr),
            actionMap,
        });
    }

    /** Change in one of the lookups we delegate to */
    public void resultChanged(LookupEvent ev) {
        updateLookups (tc.getActivatedNodes ());
    }
    
    /** Finds out whether a query for a class can be influenced 
     * by a state of the "nodes" lookup and whether we should 
     * initialize listening
     */
    private static boolean isNodeQuery (Class c) {
        return Node.class.isAssignableFrom (c) || c.isAssignableFrom (Node.class);
    }
    
    protected synchronized void beforeLookup (Template t) {
        if (attachedTo == null && isNodeQuery (t.getType ())) {
            Lookup[] arr = getLookups();
            
            attachedTo = new WeakHashMap (arr.length * 2);
            for (int i = 0; i < arr.length - 2; i++) {
                Lookup.Result res = arr[i].lookup (t);
                res.addLookupListener(listener);
                attachedTo.put (arr[i], res);
            }
        }
    }
    
    private static final class NoNodesPair extends AbstractLookup.Pair {
        public NoNodesPair () {
        }
        
        protected boolean creatorOf(Object obj) {
            return false;
        }
        
        public String getDisplayName() {
            return getId ();
        }
        
        public String getId() {
            return "none"; // NOI18N
        }
        
        public Object getInstance() {
            return null;
        }
        
        public Class getType() {
            return org.openide.nodes.Node.class;
        }
        
        protected boolean instanceOf(Class c) {
            return Node.class.isAssignableFrom (c);
        }
        
    } // end of NoNodesPair

    private static final Object PRESENT = new Object();

    /**
     * A proxying Lookup impl which yields no results when queried for Node,
     * and will never return any of the listed objects.
     */
    private static final class NoNodeLookup extends Lookup {
        
        private final Lookup delegate;
        private final Map verboten;
        
        public NoNodeLookup(Lookup del, Object[] exclude) {
            delegate = del;
            verboten = new IdentityHashMap();
            for (int i=0; i
            
            public ExclusionResult(Lookup.Result delegate, Map verboten) {
                this.delegate = delegate;
                this.verboten = verboten;
            }
            
            public Collection allInstances() {
                Collection c = delegate.allInstances();
                List ret = new ArrayList(c.size()); // upper bound
                
                for (Iterator it = c.iterator(); it.hasNext();) {
                    Object o = it.next();
                    if (!verboten.containsKey(o)) ret.add(o);
                }
                return ret;
            }
            
            public Set allClasses() {
                return delegate.allClasses(); // close enough
            }
            
            public Collection allItems() {
                Collection c = delegate.allItems();
                List ret = new ArrayList(c.size()); // upper bound
                for (Iterator it = c.iterator(); it.hasNext();) {
                    Lookup.Item i = (Lookup.Item)it.next();
                    if (!verboten.containsKey(i.getInstance())) ret.add(i);
                }
                return ret;
            }
            
            public void addLookupListener(LookupListener l) {
                synchronized (listeners) {
                    if (listeners.isEmpty()) {
                        delegate.addLookupListener(this);
                    }
                    listeners.add(l);
                }
            }
            
            public void removeLookupListener(LookupListener l) {
                synchronized (listeners) {
                    listeners.remove(l);
                    if (listeners.isEmpty()) {
                        delegate.removeLookupListener(this);
                    }
                }
            }
            
            public void resultChanged(LookupEvent ev) {
                LookupEvent ev2 = new LookupEvent(this);
                LookupListener[] ls;
                synchronized (listeners) {
                    ls = (LookupListener[])listeners.toArray(new LookupListener[listeners.size()]);
                }
                for (int i = 0; i < ls.length; i++) {
                    ls[i].resultChanged(ev2);
                }
            }
            
        }

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