1 19 20 package org.netbeans.modules.looks; 21 22 import java.util.ArrayList ; 23 import java.util.Collection ; 24 import java.util.Collections ; 25 import java.util.Enumeration ; 26 import java.util.HashMap ; 27 import java.lang.ref.WeakReference ; 28 import java.util.List ; 29 import java.util.TooManyListenersException ; 30 import javax.swing.event.ChangeListener ; 31 import javax.swing.event.EventListenerList ; 32 import org.netbeans.spi.looks.Look; 33 import org.netbeans.spi.looks.LookSelector; 34 import org.netbeans.spi.looks.LookProvider; 35 import org.netbeans.spi.looks.ChangeableLookProvider; 36 import org.netbeans.modules.looks.NamespaceLookProvider; 37 import org.openide.util.Enumerations; 38 39 43 public abstract class SelectorImplFactory { 44 45 46 47 private SelectorImplFactory() {} 48 49 public static SelectorImpl provider( LookProvider provider ) { 50 return new Impl( provider ); 51 } 52 53 public static SelectorImpl singleton( Look delegate ) { 54 return new Impl( delegate ); 55 } 56 57 public static SelectorImpl array( Look delegates[] ) { 58 return new Impl( delegates ); 59 } 60 61 public static SelectorImpl changeableProvider( ChangeableLookProvider provider ) { 62 return new Impl( provider ); 63 } 64 65 public static SelectorImpl namespaceProvider( NamespaceLookProvider provider, String prefix ) { 66 return new Impl( provider, null, prefix ); 67 } 68 69 public static SelectorImpl decorator( LookSelector selector, Look look, boolean asLast, boolean excludable ) { 70 SelectorImpl si = Accessor.DEFAULT.getSelectorImpl( selector ); 71 return new Impl( (Impl)si, look, asLast ? Boolean.TRUE : Boolean.FALSE ); 72 } 73 74 public static SelectorImpl first( LookSelector selector ) { 75 SelectorImpl si = Accessor.DEFAULT.getSelectorImpl( selector ); 76 return new Impl( (Impl)si ); 77 } 78 79 public static SelectorImpl namespaceTypes( String prefix ) { 80 return new Impl( null, prefix, true ); 81 } 82 83 public static SelectorImpl namespaceTypes( RegistryBridge registryBridge, String prefix ) { 84 return new Impl( registryBridge, prefix, true ); 85 } 86 87 public static SelectorImpl context( RegistryBridge registryBridge, String contextName ) { 88 return new Impl( registryBridge, contextName, false ); 89 } 90 91 public static SelectorImpl composite( LookSelector selectors[], boolean removeDuplicates ) { 92 Impl[] impls = new Impl[selectors.length]; 93 for ( int i = 0; i < selectors.length; i++ ) { 94 impls[i] = (Impl)Accessor.DEFAULT.getSelectorImpl( selectors[i] ); 95 } 96 return new Impl( impls, removeDuplicates ); 97 } 98 99 101 static class Impl implements SelectorImpl, ChangeListener , SelectorListener { 102 103 105 private static final int PROVIDER = 0; private static final int SINGLETON = 1; private static final int ARRAY = 2; private static final int DECORATOR_FIXED = 3; private static final int COMPOSITE_FIXED = 4; private static final int FIRST_FIXED = 5; 113 private static final int CHANGEABLE_PROVIDER = 100; private static final int NAMESPACE_PROVIDER = 101; private static final int NAMESPACE_TYPES = 102; private static final int DECORATOR_CHANGEABLE = 103; private static final int CONTEXT = 104; private static final int COMPOSITE_CHANGEABLE = 105; private static final int FIRST_CHANGEABLE = 106; 122 private static final int DECORATOR_Selector = 0; 124 private static final int DECORATOR_Look = 1; 125 private static final int DECORATOR_AsLast = 2; 126 private static final int DECORATOR_Cache = 3; 127 128 private static final int NAMESPACE_PROVIDER_Provider = 0; 129 private static final int NAMESPACE_PROVIDER_Prefix = 1; 130 131 private static final int NAMESPACE_TYPES_Prefix = 0; 132 private static final int CONTEXT_Prefix = NAMESPACE_TYPES_Prefix; 133 private static final int NAMESPACE_TYPES_Listener = 1; 134 private static final int CONTEXT_Listener = NAMESPACE_TYPES_Listener; 135 136 private static final int COMPOSITE_Delegates = 0; 137 private static final int COMPOSITE_RemoveDuplicates = 1; 138 139 private int type; private EventListenerList listeners; private LookSelector selector; private HashMap looksCache; 144 private Object delegate; private RegistryBridge rb; 147 149 151 Impl( int type, boolean cache ) { 152 this.type = type; 153 154 if ( cache ) { 155 this.looksCache = new HashMap (); 156 } 157 } 158 159 161 public Impl( LookProvider provider ) { 162 this( PROVIDER, false ); 163 this.delegate = provider; 164 } 165 166 public Impl( Look look ) { 167 this( SINGLETON, false ); 168 this.delegate = look; 169 } 170 171 public Impl( Look looks[] ) { 172 this( ARRAY, false ); 173 this.delegate = new Look[looks.length]; 174 System.arraycopy( looks, 0, (Look[])this.delegate, 0, looks.length ); 175 } 176 177 public Impl( Impl selectorImpl, Look look, Boolean asLast ) { 178 this( selectorImpl.isFixed() ? DECORATOR_FIXED : DECORATOR_CHANGEABLE, 179 selectorImpl.isFixed() ? false : true ); 180 this.delegate = new Object [] { selectorImpl, look, asLast, new HashMap () }; 181 } 182 183 public Impl( Impl selectorImpl ) { 184 this( selectorImpl.isFixed() ? FIRST_FIXED : FIRST_CHANGEABLE, 185 selectorImpl.isFixed() ? false : true ); 186 this.delegate = selectorImpl; 187 } 188 189 public Impl( ChangeableLookProvider provider ) { 190 this( CHANGEABLE_PROVIDER, true ); 191 this.delegate = provider; 192 } 193 194 public Impl( NamespaceLookProvider provider, RegistryBridge bridge, String prefix ) { 195 this( NAMESPACE_PROVIDER, true ); 196 this.delegate = new Object []{ provider, prefix }; 197 this.rb = bridge == null ? RegistryBridge.getDefault( null ) : bridge; 198 } 199 200 public Impl( RegistryBridge bridge, String prefix, boolean isTypes ) { 201 this( isTypes ? NAMESPACE_TYPES : CONTEXT , true ); 202 this.delegate = new Object [] { prefix, null }; 203 this.rb = bridge == null ? RegistryBridge.getDefault( null ) : bridge; 204 } 205 206 public Impl( Impl delegates[], boolean removeDuplicates ) { 207 this( allFixed( delegates ) ? COMPOSITE_FIXED : COMPOSITE_CHANGEABLE , !allFixed( delegates ) ); 208 this.delegate = new Object [] { delegates, removeDuplicates ? Boolean.TRUE : Boolean.FALSE }; 209 } 210 211 213 public synchronized void setLookSelector(LookSelector selector) throws TooManyListenersException { 214 if ( this.selector == null ) { 215 this.selector = selector; 216 } 217 else { 218 throw new TooManyListenersException (); 219 } 220 } 221 222 public Enumeration getLooks(Object representedObject) { 223 Object key = getKey4Object( representedObject ); 224 225 if ( key == null ) { return Enumerations.empty(); 227 } 228 else if ( key == SelectorImpl.FIXED ) { return getLooks4Key( representedObject ); 230 } 231 else { synchronized ( looksCache ) { 233 234 CacheItem ci = (CacheItem)looksCache.get( key ); 235 236 if ( ci == null ) { 237 Enumeration e = getLooks4Key( key ); 238 ci = new CacheItem( e ); 239 looksCache.put( key, ci ); 240 } 241 242 return ci.getEnumeration(); 243 } 244 } 245 } 246 247 public Object getKey4Object(Object representedObject) { 248 switch( type ) { 249 case PROVIDER: 251 case SINGLETON: 252 case ARRAY: 253 case COMPOSITE_FIXED: 254 case DECORATOR_FIXED: 255 case FIRST_FIXED: 256 return SelectorImpl.FIXED; 257 258 case CHANGEABLE_PROVIDER: 260 return ((ChangeableLookProvider)delegate).getKeyForObject( representedObject ); 261 case NAMESPACE_PROVIDER: 262 return ((NamespaceLookProvider)((Object [])delegate)[NAMESPACE_PROVIDER_Provider]).getKeyForObject( representedObject ); 263 case NAMESPACE_TYPES: 264 return representedObject.getClass(); 265 case CONTEXT: 266 return delegate; 267 268 270 case DECORATOR_CHANGEABLE: 271 SelectorImpl si = (SelectorImpl)((Object [])delegate)[DECORATOR_Selector]; 272 return si.getKey4Object( representedObject ); 273 case COMPOSITE_CHANGEABLE: 274 SelectorImpl sis[] = (SelectorImpl[])((Object [])delegate)[COMPOSITE_Delegates]; 275 Object keys[] = new Object [ sis.length ]; 276 for( int i = 0; i < sis.length; i++ ) { 277 Object key = sis[i].getKey4Object( representedObject ); 278 keys[i] = key == SelectorImpl.FIXED ? representedObject : key; 279 } 280 return keys; 281 282 case FIRST_CHANGEABLE: 283 SelectorImpl si2 = (SelectorImpl)delegate; 284 return si2.getKey4Object( representedObject ); 285 286 default: 287 throw new IllegalStateException ( "Unknown impl type " + type ); 289 } 290 291 } 292 293 public Enumeration getLooks4Key(Object key) { 294 switch( type ) { 295 296 case PROVIDER: 298 return ((LookProvider)delegate).getLooksForObject( key ); 299 case SINGLETON: 300 return Enumerations.singleton(delegate); 301 case ARRAY: 302 return Enumerations.array((Look[]) delegate); 303 304 305 case CHANGEABLE_PROVIDER: 307 return ((ChangeableLookProvider)delegate).getLooksForKey( key ); 308 case NAMESPACE_PROVIDER: 309 Enumeration names = ((NamespaceLookProvider)((Object [])delegate)[NAMESPACE_PROVIDER_Provider]).getNamesForKey( key ); 310 return TypesSearch.findLooks ("", names, rb ); case NAMESPACE_TYPES: 312 names = TypesSearch.namesForClass( (Class )key ); 313 return TypesSearch.findLooks ((String )((Object [])delegate)[NAMESPACE_TYPES_Prefix], names, rb ); 314 case CONTEXT: 315 String contextName = (String )((Object [])delegate)[CONTEXT_Prefix]; 316 names = rb.getNames( contextName ); 317 return TypesSearch.findLooks ( contextName + "/", names, rb ); 319 case DECORATOR_FIXED: 321 case DECORATOR_CHANGEABLE: 322 SelectorImpl si = (SelectorImpl)((Object [])delegate)[DECORATOR_Selector]; 323 Enumeration e = si.getLooks4Key( key ); 324 325 return Enumerations.convert(e, new Enumerations.Processor() { 326 public Object process(Object object, Collection ignore) { 327 return decorateLook((Look) object); 328 } 329 }); 330 331 case COMPOSITE_FIXED: 332 case COMPOSITE_CHANGEABLE: 333 SelectorImpl sis[] = (SelectorImpl[])((Object [])delegate)[COMPOSITE_Delegates]; 334 boolean removeDups = ((Boolean )((Object [])delegate)[COMPOSITE_RemoveDuplicates]).booleanValue(); 335 336 Object keys[] = null; 337 if ( type == COMPOSITE_CHANGEABLE ) { 338 keys = (Object [])key; } 340 341 343 List sk = new ArrayList (); 344 for( int i = 0; i < sis.length; i++ ) { 345 if ( keys != null && keys[i] == null ) { 346 continue; 348 } 349 sk.add( new Object [] { sis[i], keys == null ? key : keys[i] } ); 350 } 351 352 Enumeration selEnum = Enumerations.queue(Enumerations.array(sk.toArray()), new Enumerations.Processor() { 353 public Object process(Object object, Collection coll) { 354 if (object instanceof Object []) { 355 Object sk[] = (Object []) object; 356 Enumeration looksEnum = ((SelectorImpl) sk[0]).getLooks4Key(sk[1]); 357 coll.addAll(Collections.list(looksEnum)); 358 } 359 return object; 360 } 361 }); 362 363 Enumeration resEnum = Enumerations.filter(selEnum, new Enumerations.Processor() { 364 public Object process(Object object, Collection coll) { 365 if (object instanceof Look) { 366 return object; 367 } else { 368 return null; 369 } 370 } 371 }); 372 373 return removeDups ? Enumerations.removeDuplicates(resEnum) : resEnum; 374 375 case FIRST_FIXED: 376 case FIRST_CHANGEABLE: 377 SelectorImpl si2 = (SelectorImpl)delegate; 378 Enumeration e2 = si2.getLooks4Key( key ); 379 380 if (e2.hasMoreElements()) { 381 return Enumerations.singleton(e2.nextElement()); 382 } else { 383 return Enumerations.empty(); 384 } 385 386 default: 387 throw new IllegalStateException ( "Unknown impl type " + type ); } 389 } 390 391 public void addSelectorListener( SelectorListener listener) { 392 if ( !isFixed() ) { 393 if ( listeners == null) { 394 397 switch( type ) { 398 case CHANGEABLE_PROVIDER: 399 try { 400 ((ChangeableLookProvider)delegate).addChangeListener( this ); 401 } 402 catch ( TooManyListenersException e ) { 403 throw new IllegalStateException ( "Too many listeners on provider " + delegate ); 404 } 405 break; 406 case NAMESPACE_PROVIDER: 407 try { 408 ((NamespaceLookProvider)((Object [])delegate)[NAMESPACE_PROVIDER_Provider]).addChangeListener( this ); 409 } 410 catch ( TooManyListenersException e ) { 411 throw new IllegalStateException ( "Too many listeners on provider " + delegate ); 412 } 413 break; 414 case DECORATOR_CHANGEABLE: 415 ((Impl)((Object [])delegate)[DECORATOR_Selector]).addSelectorListener( this ); 416 break; 417 case NAMESPACE_TYPES: 418 case CONTEXT: 419 RbEventTranslator l = new RbEventTranslator(); 420 rb.addListener( ((String )((Object [])delegate)[NAMESPACE_TYPES_Prefix]), l ); 421 ((Object [])delegate)[NAMESPACE_TYPES_Listener] = l; 422 break; 423 case COMPOSITE_CHANGEABLE: 424 default: 426 } 428 429 } 430 431 synchronized ( Impl.class ) { 432 if (listeners == null) { 433 listeners = new EventListenerList (); 434 } 435 } 436 listeners.add( SelectorListener.class, listener ); 437 } 438 } 439 440 public void removeSelectorListener( SelectorListener listener) { 441 442 if ( !isFixed() ) { 443 synchronized( Impl.class ) { 444 if (listeners != null) { 445 listeners.remove( SelectorListener.class, listener); 446 } 447 } 448 449 if ( listeners.getListenerCount() == 0 ) { 450 switch( type ) { 452 case NAMESPACE_TYPES: 453 case CONTEXT: 454 rb.removeListener( (String )((Object [])delegate)[NAMESPACE_TYPES_Prefix], 455 (RbEventTranslator)((Object [])delegate)[NAMESPACE_TYPES_Listener] ); 456 break; 457 case DECORATOR_CHANGEABLE: 458 ((Impl)((Object [])delegate)[DECORATOR_Selector]).removeSelectorListener( this ); 459 break; 460 case COMPOSITE_CHANGEABLE: 461 default: 463 } 465 listeners = null; 467 } 468 469 } 470 } 471 472 public HashMap getCache() { 473 return looksCache; 474 } 475 476 477 479 public void stateChanged(javax.swing.event.ChangeEvent e) { 480 fireChange( new SelectorEvent( selector ) ); 481 } 482 483 485 public void contentsChanged( SelectorEvent event ) { 486 fireChange( new SelectorEvent( selector ) ); 487 } 488 489 491 492 private boolean isFixed() { 493 return type < CHANGEABLE_PROVIDER; 494 } 495 496 private static boolean allFixed( Impl[] impls ) { 497 for( int i = 0; i < impls.length; i++ ) { 498 if ( !impls[i].isFixed() ) { 499 return false; 500 } 501 } 502 return true; 503 } 504 505 protected void fireChange( SelectorEvent event ) { 506 507 Object [] arr; 508 509 synchronized( this ) { if ( looksCache != null ) { 511 looksCache = new HashMap (); 512 } 513 } 514 515 synchronized( Impl.class ) { 516 if (listeners == null) { 517 return; 518 } 519 arr = listeners.getListenerList(); 520 } 521 522 if ( arr.length == 0 ) { 523 return; 524 } 525 526 for (int i = arr.length - 1; i >= 0; i -= 2) { 527 SelectorListener l = (SelectorListener)arr[i]; 528 l.contentsChanged( event ); 529 } 530 } 531 532 533 535 private Look decorateLook( Look original ) { 536 537 HashMap decorationCache = (HashMap )((Object [])delegate)[DECORATOR_Cache]; 538 boolean asLast = ((Boolean )((Object [])delegate)[DECORATOR_AsLast]).booleanValue(); 539 Look decorator = (Look)((Object [])delegate)[DECORATOR_Look]; 540 541 synchronized ( decorationCache ) { 542 WeakReference ref = (WeakReference ) decorationCache.get( original ); 543 Look decoratedLook = ref == null ? null : (Look) ref.get(); 544 545 if ( decoratedLook == null ) { 546 547 decoratedLook = new CompositeLook( 549 "Decorated[" + original.getName(), 550 asLast ? new Look[] { original, decorator } : 551 new Look[] { decorator, original } ); 552 553 564 decorationCache.put( original, new WeakReference ( decoratedLook ) ); 565 } 566 return decoratedLook; 567 } 568 } 569 570 571 private class RbEventTranslator extends RegistryBridge.Listener { 572 573 public void selectorChanged() { 574 Impl.this.fireChange( new SelectorEvent( selector ) ); 575 } 576 577 } 578 579 } 580 581 585 static class CacheItem { 586 587 private Enumeration enumeration; 588 private List list; 589 590 public CacheItem( Enumeration enumeration ) { 591 this.enumeration = enumeration; 592 list = new ArrayList (); 593 } 594 595 596 public Enumeration getEnumeration() { 597 return new CacheEnumeration( this ); 598 } 599 600 public Object get( int index ) { 601 if ( index >= list.size() ) { 602 for( int i = list.size(); i <= index; i++ ) { 603 604 if ( !enumeration.hasMoreElements() ) { 605 return null; 606 } 607 608 list.add( enumeration.nextElement() ); 609 } 610 } 611 612 return list.get( index ); 613 } 614 615 boolean has( int index ) { 616 if ( index < list.size() ) { 617 return true; 618 } 619 else if ( index == list.size() ) { 620 return enumeration.hasMoreElements(); 621 } 622 else { 623 return get( index + 1 ) != null; 624 } 625 } 626 627 631 Collection getCachedLooks( boolean all ) { 632 List result = new ArrayList (); 633 if ( all ) { 634 for( Enumeration e = getEnumeration(); e.hasMoreElements(); ) { 635 result.add( e.nextElement() ); 636 } 637 638 639 } 640 else { 641 result.addAll( list ); 642 } 643 644 return result; 645 } 646 647 648 651 private static class CacheEnumeration implements Enumeration { 652 653 private CacheItem cacheItem; 654 int index; 655 656 public CacheEnumeration( CacheItem cacheItem ) { 657 this.cacheItem = cacheItem; 658 index = -1; 659 } 660 661 public boolean hasMoreElements() { 662 return cacheItem.has( index + 1 ); 663 } 664 665 public Object nextElement() { 666 return cacheItem.get( ++index ); 667 } 668 669 } 670 671 } 672 673 674 } 675 | Popular Tags |