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