|
What this is
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, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2003 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.looks; import java.util.*; import java.lang.ref.WeakReference; import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; import org.netbeans.spi.looks.Look; import org.netbeans.spi.looks.LookSelector; import org.netbeans.spi.looks.LookProvider; import org.netbeans.spi.looks.ChangeableLookProvider; import org.netbeans.modules.looks.NamespaceLookProvider; import org.openide.util.enum.*; /** Factory for creating all kinds of selectors. * * @author Petr Hrebejk */ public abstract class SelectorImplFactory { /** It's a static factory */ private SelectorImplFactory() {} public static SelectorImpl provider( LookProvider provider ) { return new Impl( provider ); } public static SelectorImpl singleton( Look delegate ) { return new Impl( delegate ); } public static SelectorImpl array( Look delegates[] ) { return new Impl( delegates ); } public static SelectorImpl changeableProvider( ChangeableLookProvider provider ) { return new Impl( provider ); } public static SelectorImpl namespaceProvider( NamespaceLookProvider provider, String prefix ) { return new Impl( provider, null, prefix ); } public static SelectorImpl decorator( LookSelector selector, Look look, boolean asLast, boolean excludable ) { SelectorImpl si = Accessor.DEFAULT.getSelectorImpl( selector ); return new Impl( (Impl)si, look, asLast ? Boolean.TRUE : Boolean.FALSE ); } public static SelectorImpl first( LookSelector selector ) { SelectorImpl si = Accessor.DEFAULT.getSelectorImpl( selector ); return new Impl( (Impl)si ); } public static SelectorImpl namespaceTypes( String prefix ) { return new Impl( null, prefix, true ); } public static SelectorImpl namespaceTypes( RegistryBridge registryBridge, String prefix ) { return new Impl( registryBridge, prefix, true ); } public static SelectorImpl context( RegistryBridge registryBridge, String contextName ) { return new Impl( registryBridge, contextName, false ); } public static SelectorImpl composite( LookSelector selectors[], boolean removeDuplicates ) { Impl[] impls = new Impl[selectors.length]; for ( int i = 0; i < selectors.length; i++ ) { impls[i] = (Impl)Accessor.DEFAULT.getSelectorImpl( selectors[i] ); } return new Impl( impls, removeDuplicates ); } // Innerclasses ----------------------------------------------------------- static class Impl implements SelectorImpl, ChangeListener, SelectorListener { // Types // Fixed impls private static final int PROVIDER = 0; // (LookProvider) private static final int SINGLETON = 1; // (Look) private static final int ARRAY = 2; // (Look[]) private static final int DECORATOR_FIXED = 3; // (LookSelector-Fixed, Look) private static final int COMPOSITE_FIXED = 4; // (Impl[], boolean) private static final int FIRST_FIXED = 5; // (LookSelector-Fixed, Look) // Changeable impls private static final int CHANGEABLE_PROVIDER = 100; // (ChangeableProvider) private static final int NAMESPACE_PROVIDER = 101; // (NamespaceProvider, Context) private static final int NAMESPACE_TYPES = 102; // (Context) - in context by type private static final int DECORATOR_CHANGEABLE = 103; // (LookSelctor-Changeable), Look ) private static final int CONTEXT = 104; // (Context) - all in context private static final int COMPOSITE_CHANGEABLE = 105; // (Impl[], boolean) private static final int FIRST_CHANGEABLE = 106; // (LookSelector-Changeable, Look) // --- Extra indexes into arrays for various types of Impl private static final int DECORATOR_Selector = 0; private static final int DECORATOR_Look = 1; private static final int DECORATOR_AsLast = 2; private static final int DECORATOR_Cache = 3; private static final int NAMESPACE_PROVIDER_Provider = 0; private static final int NAMESPACE_PROVIDER_Prefix = 1; private static final int NAMESPACE_TYPES_Prefix = 0; private static final int CONTEXT_Prefix = NAMESPACE_TYPES_Prefix; private static final int NAMESPACE_TYPES_Listener = 1; private static final int CONTEXT_Listener = NAMESPACE_TYPES_Listener; private static final int COMPOSITE_Delegates = 0; private static final int COMPOSITE_RemoveDuplicates = 1; private int type; // Type of the impl private EventListenerList listeners; // Listeners for changeable impls. private LookSelector selector; // Selector which uses this impl private HashMap looksCache; // Cached results for keys private Object delegate; // Used impl types which delegate private RegistryBridge rb; // Used in context based impls. // Constructrors ------------------------------------------------------- // General constructor for all impls Impl( int type, boolean cache ) { this.type = type; if ( cache ) { this.looksCache = new HashMap(); } } // One constructor for each type of impl public Impl( LookProvider provider ) { this( PROVIDER, false ); this.delegate = provider; } public Impl( Look look ) { this( SINGLETON, false ); this.delegate = look; } public Impl( Look looks[] ) { this( ARRAY, false ); this.delegate = new Look[looks.length]; System.arraycopy( looks, 0, (Look[])this.delegate, 0, looks.length ); } public Impl( Impl selectorImpl, Look look, Boolean asLast ) { this( selectorImpl.isFixed() ? DECORATOR_FIXED : DECORATOR_CHANGEABLE, selectorImpl.isFixed() ? false : true ); this.delegate = new Object[] { selectorImpl, look, asLast, new HashMap() }; } public Impl( Impl selectorImpl ) { this( selectorImpl.isFixed() ? FIRST_FIXED : FIRST_CHANGEABLE, selectorImpl.isFixed() ? false : true ); this.delegate = selectorImpl; } public Impl( ChangeableLookProvider provider ) { this( CHANGEABLE_PROVIDER, true ); this.delegate = provider; } public Impl( NamespaceLookProvider provider, RegistryBridge bridge, String prefix ) { this( NAMESPACE_PROVIDER, true ); this.delegate = new Object[]{ provider, prefix }; this.rb = bridge == null ? RegistryBridge.getDefault( null ) : bridge; } public Impl( RegistryBridge bridge, String prefix, boolean isTypes ) { this( isTypes ? NAMESPACE_TYPES : CONTEXT , true ); this.delegate = new Object[] { prefix, null }; this.rb = bridge == null ? RegistryBridge.getDefault( null ) : bridge; } public Impl( Impl delegates[], boolean removeDuplicates ) { this( allFixed( delegates ) ? COMPOSITE_FIXED : COMPOSITE_CHANGEABLE , !allFixed( delegates ) ); this.delegate = new Object[] { delegates, removeDuplicates ? Boolean.TRUE : Boolean.FALSE }; } // Implementation of SelectorImpl interface ---------------------------- public synchronized void setLookSelector(LookSelector selector) throws TooManyListenersException { if ( this.selector == null ) { this.selector = selector; } else { throw new TooManyListenersException(); } } public Enumeration getLooks(Object representedObject) { Object key = getKey4Object( representedObject ); if ( key == null ) { // No key means no looks return EmptyEnumeration.EMPTY; } else if ( key == SelectorImpl.FIXED ) { // Means no caching return getLooks4Key( representedObject ); } else { // Here we have to cache synchronized ( looksCache ) { CacheItem ci = (CacheItem)looksCache.get( key ); if ( ci == null ) { Enumeration e = getLooks4Key( key ); ci = new CacheItem( e ); looksCache.put( key, ci ); } return ci.getEnumeration(); } } } public Object getKey4Object(Object representedObject) { switch( type ) { // Fixed impls case PROVIDER: case SINGLETON: case ARRAY: case COMPOSITE_FIXED: case DECORATOR_FIXED: case FIRST_FIXED: return SelectorImpl.FIXED; // Changeable impls case CHANGEABLE_PROVIDER: return ((ChangeableLookProvider)delegate).getKeyForObject( representedObject ); case NAMESPACE_PROVIDER: return ((NamespaceLookProvider)((Object[])delegate)[NAMESPACE_PROVIDER_Provider]).getKeyForObject( representedObject ); case NAMESPACE_TYPES: return representedObject.getClass(); case CONTEXT: return delegate; // Extra cases case DECORATOR_CHANGEABLE: SelectorImpl si = (SelectorImpl)((Object[])delegate)[DECORATOR_Selector]; return si.getKey4Object( representedObject ); case COMPOSITE_CHANGEABLE: SelectorImpl sis[] = (SelectorImpl[])((Object[])delegate)[COMPOSITE_Delegates]; Object keys[] = new Object[ sis.length ]; for( int i = 0; i < sis.length; i++ ) { Object key = sis[i].getKey4Object( representedObject ); keys[i] = key == SelectorImpl.FIXED ? representedObject : key; } return keys; case FIRST_CHANGEABLE: SelectorImpl si2 = (SelectorImpl)delegate; return si2.getKey4Object( representedObject ); default: throw new IllegalStateException( "Unknown impl type " + type ); //NOI18N } } public Enumeration getLooks4Key(Object key) { switch( type ) { // Fixed impls - here key will be the represented object case PROVIDER: return ((LookProvider)delegate).getLooksForObject( key ); case SINGLETON: return new SingletonEnumeration( delegate ); case ARRAY: return new ArrayEnumeration( (Look[])delegate ); // Changeable impls case CHANGEABLE_PROVIDER: return ((ChangeableLookProvider)delegate).getLooksForKey( key ); case NAMESPACE_PROVIDER: Enumeration names = ((NamespaceLookProvider)((Object[])delegate)[NAMESPACE_PROVIDER_Provider]).getNamesForKey( key ); return TypesSearch.findLooks ("", names, rb ); // NOI18N case NAMESPACE_TYPES: names = TypesSearch.namesForClass( (Class)key ); return TypesSearch.findLooks ((String)((Object[])delegate)[NAMESPACE_TYPES_Prefix], names, rb ); case CONTEXT: String contextName = (String)((Object[])delegate)[CONTEXT_Prefix]; names = rb.getNames( contextName ); return TypesSearch.findLooks ( contextName + "/", names, rb ); // NOI18N // Extra cases case DECORATOR_FIXED: case DECORATOR_CHANGEABLE: SelectorImpl si = (SelectorImpl)((Object[])delegate)[DECORATOR_Selector]; Enumeration e = si.getLooks4Key( key ); return new AlterEnumeration( e ) { public Object alter( Object object ) { return decorateLook( (Look)object ); } }; case COMPOSITE_FIXED: case COMPOSITE_CHANGEABLE: SelectorImpl sis[] = (SelectorImpl[])((Object[])delegate)[COMPOSITE_Delegates]; boolean removeDups = ((Boolean)((Object[])delegate)[COMPOSITE_RemoveDuplicates]).booleanValue(); Object keys[] = null; if ( type == COMPOSITE_CHANGEABLE ) { keys = (Object[])key; // Otherwise we have a rep. obj as a key; } //Object sk[][] = new Object[ sis.length ][2]; List sk = new ArrayList(); for( int i = 0; i < sis.length; i++ ) { if ( keys != null && keys[i] == null ) { // if not fixed but key is null continue; } sk.add( new Object[] { sis[i], keys == null ? key : keys[i] } ); } QueueEnumeration selEnum = new QueueEnumeration() { protected void process( Object object ) { if (object instanceof Object []) { Object sk[] = (Object[])object; Enumeration looksEnum = ((SelectorImpl)sk[0]).getLooks4Key( sk[1] ); put(Collections.list(looksEnum).toArray()); } } }; selEnum.put(sk.toArray()); Enumeration resEnum = new FilterEnumeration( selEnum ) { protected boolean accept( Object o ) { return o instanceof Look; } }; return removeDups ? new RemoveDuplicatesEnumeration( resEnum ) : resEnum; case FIRST_FIXED: case FIRST_CHANGEABLE: SelectorImpl si2 = (SelectorImpl)delegate; Enumeration e2 = si2.getLooks4Key( key ); if (e2.hasMoreElements()) { return new SingletonEnumeration(e2.nextElement()); } else { return EmptyEnumeration.EMPTY; } default: throw new IllegalStateException( "Unknown impl type " + type ); //NOI18N } } public void addSelectorListener( SelectorListener listener) { if ( !isFixed() ) { if ( listeners == null) { // Someone starts to listen in some cases we need to start // listening as well switch( type ) { case CHANGEABLE_PROVIDER: try { ((ChangeableLookProvider)delegate).addChangeListener( this ); } catch ( TooManyListenersException e ) { throw new IllegalStateException ( "Too many listeners on provider " + delegate ); } break; case NAMESPACE_PROVIDER: try { ((NamespaceLookProvider)((Object[])delegate)[NAMESPACE_PROVIDER_Provider]).addChangeListener( this ); } catch ( TooManyListenersException e ) { throw new IllegalStateException ( "Too many listeners on provider " + delegate ); } break; case DECORATOR_CHANGEABLE: ((Impl)((Object[])delegate)[DECORATOR_Selector]).addSelectorListener( this ); break; case NAMESPACE_TYPES: case CONTEXT: RbEventTranslator l = new RbEventTranslator(); rb.addListener( ((String)((Object[])delegate)[NAMESPACE_TYPES_Prefix]), l ); ((Object[])delegate)[NAMESPACE_TYPES_Listener] = l; break; case COMPOSITE_CHANGEABLE: // PENDING default: // Do nothing for other types } } synchronized ( Impl.class ) { if (listeners == null) { listeners = new EventListenerList (); } } listeners.add( SelectorListener.class, listener ); } } public void removeSelectorListener( SelectorListener listener) { if ( !isFixed() ) { synchronized( Impl.class ) { if (listeners != null) { listeners.remove( SelectorListener.class, listener); } } if ( listeners.getListenerCount() == 0 ) { // Nobody listens so stop listeneing switch( type ) { case NAMESPACE_TYPES: case CONTEXT: rb.removeListener( (String)((Object[])delegate)[NAMESPACE_TYPES_Prefix], (RbEventTranslator)((Object[])delegate)[NAMESPACE_TYPES_Listener] ); break; case DECORATOR_CHANGEABLE: ((Impl)((Object[])delegate)[DECORATOR_Selector]).removeSelectorListener( this ); break; case COMPOSITE_CHANGEABLE: // PENDING default: // Do nothing for other types } // Delete the listeners list in order to recreate on new add listeners = null; } } } public HashMap getCache() { return looksCache; } // Implementation of change listener ----------------------------------- public void stateChanged(javax.swing.event.ChangeEvent e) { fireChange( new SelectorEvent( selector ) ); } // Implementation of selector listener public void contentsChanged( SelectorEvent event ) { fireChange( new SelectorEvent( selector ) ); } // Private methods ----------------------------------------------------- private boolean isFixed() { return type < CHANGEABLE_PROVIDER; } private static boolean allFixed( Impl[] impls ) { for( int i = 0; i < impls.length; i++ ) { if ( !impls[i].isFixed() ) { return false; } } return true; } protected void fireChange( SelectorEvent event ) { Object[] arr; synchronized( this ) { // If something changed we need to reset thec cache if ( looksCache != null ) { looksCache = new HashMap(); } } synchronized( Impl.class ) { if (listeners == null) { return; } arr = listeners.getListenerList(); } if ( arr.length == 0 ) { return; } for (int i = arr.length - 1; i >= 0; i -= 2) { SelectorListener l = (SelectorListener)arr[i]; l.contentsChanged( event ); } } /** Used in DECORATOR_FIXED and DECORATOR_CHANGEABLE */ private Look decorateLook( Look original ) { HashMap decorationCache = (HashMap)((Object[])delegate)[DECORATOR_Cache]; boolean asLast = ((Boolean)((Object[])delegate)[DECORATOR_AsLast]).booleanValue(); Look decorator = (Look)((Object[])delegate)[DECORATOR_Look]; synchronized ( decorationCache ) { WeakReference ref = (WeakReference) decorationCache.get( original ); Look decoratedLook = ref == null ? null : (Look) ref.get(); if ( decoratedLook == null ) { // Compute the decorated look decoratedLook = new CompositeLook( "Decorated[" + original.getName(), asLast ? new Look[] { original, decorator } : new Look[] { decorator, original } ); /* // Compute decorated selector if necessary LookSelector decoratedSelector = LookNode.findLookSelector (original, null); if ( !excludable && decoratedSelector != null ) { decoratedSelector = new DecoratorSelector ( decoratedSelector, look, asLast, false ); } // Join decoratedLook = Looks.childrenSelectorProvider( "Decorated[" + original.getName(), decoratedLook, decoratedSelector ); */ decorationCache.put( original, new WeakReference( decoratedLook ) ); } return decoratedLook; } } private class RbEventTranslator extends RegistryBridge.Listener { public void selectorChanged() { Impl.this.fireChange( new SelectorEvent( selector ) ); } } } /** An item in the cache consist of list of already asked for Looks * and rest of the enumeration. This class is used in the SelectorEvent * class. */ static class CacheItem { private Enumeration enumeration; private List list; public CacheItem( Enumeration enumeration ) { this.enumeration = enumeration; list = new ArrayList(); } /** Return enumeration which caches */ public Enumeration getEnumeration() { return new CacheEnumeration( this ); } public Object get( int index ) { if ( index >= list.size() ) { for( int i = list.size(); i <= index; i++ ) { if ( !enumeration.hasMoreElements() ) { return null; } list.add( enumeration.nextElement() ); } } return list.get( index ); } boolean has( int index ) { if ( index < list.size() ) { return true; } else if ( index == list.size() ) { return enumeration.hasMoreElements(); } else { return get( index + 1 ) != null; } } /** Returns looks in the cache * @param all Should really all looks be returned (i.e. iterate through * the enum or should we only return content of the list */ Collection getCachedLooks( boolean all ) { List result = new ArrayList(); if ( all ) { for( Enumeration e = getEnumeration(); e.hasMoreElements(); ) { result.add( e.nextElement() ); } } else { result.addAll( list ); } return result; } /** Enumeration over the CacheItem. First iterates the List then the * enumaration and adds the items into the list */ private static class CacheEnumeration implements Enumeration { private CacheItem cacheItem; int index; public CacheEnumeration( CacheItem cacheItem ) { this.cacheItem = cacheItem; index = -1; } public boolean hasMoreElements() { return cacheItem.has( index + 1 ); } public Object nextElement() { return cacheItem.get( ++index ); } } } } |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 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.