Source for javax.swing.UIDefaults

   1: /* UIDefaults.java -- database for all settings and interface bindings.
   2:    Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing;
  40: 
  41: import java.awt.Color;
  42: import java.awt.Dimension;
  43: import java.awt.Font;
  44: import java.awt.Insets;
  45: import java.beans.PropertyChangeListener;
  46: import java.beans.PropertyChangeSupport;
  47: import java.lang.reflect.Method;
  48: import java.util.Hashtable;
  49: import java.util.LinkedList;
  50: import java.util.ListIterator;
  51: import java.util.Locale;
  52: import java.util.MissingResourceException;
  53: import java.util.ResourceBundle;
  54: 
  55: import javax.swing.border.Border;
  56: import javax.swing.plaf.ComponentUI;
  57: import javax.swing.plaf.InputMapUIResource;
  58: 
  59: /**
  60:  * UIDefaults is a database where all settings and interface bindings are
  61:  * stored into. A PLAF implementation fills one of these (see for example
  62:  * plaf/basic/BasicLookAndFeel.java) with "ButtonUI" -> new BasicButtonUI().
  63:  *
  64:  * @author Ronald Veldema (rveldema@cs.vu.nl)
  65:  */
  66: public class UIDefaults extends Hashtable<Object, Object>
  67: {
  68: 
  69:   /** Our ResourceBundles. */
  70:   private LinkedList bundles;
  71: 
  72:   /** The default locale. */
  73:   private Locale defaultLocale;
  74: 
  75:   /** We use this for firing PropertyChangeEvents. */
  76:   private PropertyChangeSupport propertyChangeSupport;
  77: 
  78:   /**
  79:    * Used for lazy instantiation of UIDefaults values so that they are not
  80:    * all loaded when a Swing application starts up, but only the values that
  81:    * are really needed. An <code>ActiveValue</code> is newly instantiated
  82:    * every time when the value is requested, as opposed to the normal
  83:    * {@link LazyValue} that is only instantiated once.
  84:    */
  85:   public static interface ActiveValue
  86:   {
  87:     Object createValue(UIDefaults table);
  88:   }
  89: 
  90:   public static class LazyInputMap implements LazyValue
  91:   {
  92:     Object[] bind;
  93:     public LazyInputMap(Object[] bindings)
  94:     {
  95:       bind = bindings;
  96:     }
  97:     public Object createValue(UIDefaults table)
  98:     {
  99:       InputMapUIResource im = new InputMapUIResource();
 100:       for (int i = 0; 2 * i + 1 < bind.length; ++i)
 101:         {
 102:           Object curr = bind[2 * i];
 103:           if (curr instanceof KeyStroke)
 104:             im.put((KeyStroke) curr, bind[2 * i + 1]);
 105:           else
 106:             im.put(KeyStroke.getKeyStroke((String) curr),
 107:                   bind[2 * i + 1]);
 108:         }
 109:       return im;
 110:     }
 111:   }
 112: 
 113:   /**
 114:    * Used for lazy instantiation of UIDefaults values so that they are not
 115:    * all loaded when a Swing application starts up, but only the values that
 116:    * are really needed. A <code>LazyValue</code> is only instantiated once,
 117:    * as opposed to the {@link ActiveValue} that is newly created every time
 118:    * it is requested.
 119:    */
 120:   public static interface LazyValue
 121:   {
 122:     Object createValue(UIDefaults table);
 123:   }
 124: 
 125:   public static class ProxyLazyValue implements LazyValue
 126:   {
 127:     LazyValue inner;
 128:     public ProxyLazyValue(String s)
 129:     {
 130:       final String className = s;
 131:       inner = new LazyValue()
 132:         { 
 133:           public Object createValue(UIDefaults table) 
 134:           {
 135:             try
 136:               {
 137:                 return Class
 138:                   .forName(className)
 139:                   .getConstructor(new Class[] {})
 140:                   .newInstance(new Object[] {});
 141:               }
 142:             catch (Exception e)
 143:               {
 144:                 return null;
 145:               }
 146:           }
 147:         };
 148:     }
 149: 
 150:     public ProxyLazyValue(String c, String m)
 151:     {
 152:       final String className = c;
 153:       final String methodName = m;
 154:       inner = new LazyValue()
 155:         { 
 156:           public Object createValue(UIDefaults table) 
 157:           {
 158:             try 
 159:               {                
 160:                 return Class
 161:                   .forName(className)
 162:                   .getMethod(methodName, new Class[] {})
 163:                   .invoke(null, new Object[] {});
 164:               }
 165:             catch (Exception e)
 166:               {
 167:                 return null;
 168:               }
 169:           }
 170:         };
 171:     }
 172:     
 173:     public ProxyLazyValue(String c, Object[] os)
 174:     {
 175:       final String className = c;
 176:       final Object[] objs = os;
 177:       final Class[] clss = new Class[objs.length];
 178:       for (int i = 0; i < objs.length; ++i)
 179:         {
 180:           clss[i] = objs[i].getClass();
 181:         }      
 182:       inner = new LazyValue()
 183:         { 
 184:           public Object createValue(UIDefaults table) 
 185:           {            
 186:             try
 187:               {
 188:                 return Class
 189:                   .forName(className)
 190:                   .getConstructor(clss)
 191:                   .newInstance(objs);
 192:           }
 193:             catch (Exception e)
 194:           {
 195:                 return null;
 196:               }
 197:           }
 198:         };
 199:     }
 200: 
 201:     public ProxyLazyValue(String c, String m, Object[] os)
 202:     {
 203:       final String className = c;
 204:       final String methodName = m;
 205:       final Object[] objs = os;
 206:       final Class[] clss = new Class[objs.length];
 207:       for (int i = 0; i < objs.length; ++i)
 208:     {
 209:           clss[i] = objs[i].getClass();
 210:     }
 211:       inner = new LazyValue()
 212:         { 
 213:       public Object createValue(UIDefaults table)
 214:       {
 215:             try 
 216:               {
 217:                 return Class
 218:                   .forName(className)
 219:                   .getMethod(methodName, clss)
 220:                   .invoke(null, objs);
 221:               }
 222:             catch (Exception e)
 223:               {
 224:                 return null;
 225:               }
 226:           }
 227:         };
 228:     }
 229:     
 230:     public Object createValue(UIDefaults table)
 231:     {
 232:       return inner.createValue(table);
 233:     }
 234:   }
 235: 
 236:   /** Our serialVersionUID for serialization. */
 237:   private static final long serialVersionUID = 7341222528856548117L;
 238: 
 239:   /**
 240:    * Constructs a new empty UIDefaults instance.
 241:    */
 242:   public UIDefaults()
 243:   {
 244:     bundles = new LinkedList();
 245:     defaultLocale = Locale.getDefault();
 246:     propertyChangeSupport = new PropertyChangeSupport(this);
 247:   }
 248: 
 249:   /**
 250:    * Constructs a new UIDefaults instance and loads the specified entries.
 251:    * The entries are expected to come in pairs, that means
 252:    * <code>entries[0]</code> is a key, <code>entries[1]</code> is a value,
 253:    * <code>entries[2]</code> a key and so forth.
 254:    *
 255:    * @param entries the entries to initialize the UIDefaults instance with
 256:    */
 257:   public UIDefaults(Object[] entries)
 258:   {
 259:     this();
 260:     
 261:     for (int i = 0; (2 * i + 1) < entries.length; ++i)
 262:       put(entries[2 * i], entries[2 * i + 1]);
 263:   }
 264: 
 265:   /**
 266:    * Returns the entry for the specified <code>key</code> in the default
 267:    * locale.
 268:    *
 269:    * @return the entry for the specified <code>key</code>
 270:    */
 271:   public Object get(Object key)
 272:   {
 273:     return this.get(key, getDefaultLocale());
 274:   }
 275: 
 276:   /**
 277:    * Returns the entry for the specified <code>key</code> in the Locale
 278:    * <code>loc</code>.
 279:    *
 280:    * @param key the key for which we return the value
 281:    * @param loc the locale
 282:    */
 283:   public Object get(Object key, Locale loc)
 284:   {
 285:     Object obj = null;
 286: 
 287:     if (super.containsKey(key))
 288:       {
 289:         obj = super.get(key);
 290:       }
 291:     else if (key instanceof String)
 292:       {
 293:         String keyString = (String) key;
 294:         ListIterator i = bundles.listIterator(0);
 295:         while (i.hasNext())
 296:       {
 297:             String bundle_name = (String) i.next();
 298:             ResourceBundle res =
 299:               ResourceBundle.getBundle(bundle_name, loc);
 300:             if (res != null)
 301:               {
 302:                 try 
 303:                   {                    
 304:                     obj = res.getObject(keyString);
 305:                     break;
 306:                   }
 307:                 catch (MissingResourceException me)
 308:                   {
 309:                     // continue, this bundle has no such key
 310:                   }
 311:               }
 312:           }
 313:       }
 314: 
 315:     // now we've found the object, resolve it.
 316:     // nb: LazyValues aren't supported in resource bundles, so it's correct
 317:     // to insert their results in the locale-less hashtable.
 318: 
 319:     if (obj == null)
 320:       return null;
 321: 
 322:     if (obj instanceof LazyValue)
 323:       {
 324:         Object resolved = ((LazyValue) obj).createValue(this);
 325:         super.remove(key);
 326:         super.put(key, resolved);
 327:         return resolved;
 328:       }
 329:     else if (obj instanceof ActiveValue)
 330:       {
 331:         return ((ActiveValue) obj).createValue(this);
 332:       }    
 333: 
 334:     return obj;
 335:   }
 336: 
 337:   /**
 338:    * Puts a key and value into this UIDefaults object.<br>
 339:    * In contrast to
 340:    * {@link java.util.Hashtable}s <code>null</code>-values are accepted
 341:    * here and treated like #remove(key).
 342:    * <br>
 343:    * This fires a PropertyChangeEvent with key as name and the old and new
 344:    * values.
 345:    *
 346:    * @param key the key to put into the map
 347:    * @param value the value to put into the map
 348:    *
 349:    * @return the old value for key or <code>null</code> if <code>key</code>
 350:    *     had no value assigned
 351:    */
 352:   public Object put(Object key, Object value)
 353:   {
 354:     Object old = checkAndPut(key, value);
 355: 
 356:     if (key instanceof String && old != value)
 357:       firePropertyChange((String) key, old, value);
 358:     return old;
 359:   }
 360: 
 361:   /**
 362:    * Puts a set of key-value pairs into the map.
 363:    * The entries are expected to come in pairs, that means
 364:    * <code>entries[0]</code> is a key, <code>entries[1]</code> is a value,
 365:    * <code>entries[2]</code> a key and so forth.
 366:    * <br>
 367:    * If a value is <code>null</code> it is treated like #remove(key).
 368:    * <br>
 369:    * This unconditionally fires a PropertyChangeEvent with
 370:    * <code>&apos;UIDefaults&apos;</code> as name and <code>null</code> for
 371:    * old and new value.
 372:    *
 373:    * @param entries the entries to be put into the map
 374:    */
 375:   public void putDefaults(Object[] entries)
 376:   {
 377:     for (int i = 0; (2 * i + 1) < entries.length; ++i)
 378:   {
 379:         checkAndPut(entries[2 * i], entries[2 * i + 1]);
 380:       }
 381:     firePropertyChange("UIDefaults", null, null);
 382:   }
 383: 
 384:   /**
 385:    * Checks the value for <code>null</code> and put it into the Hashtable, if
 386:    * it is not <code>null</code>. If the value is <code>null</code> then
 387:    * remove the corresponding key.
 388:    *
 389:    * @param key the key to put into this UIDefauls table
 390:    * @param value the value to put into this UIDefaults table
 391:    *
 392:    * @return the old value for <code>key</code>
 393:    */
 394:   private Object checkAndPut(Object key, Object value)
 395:   {
 396:     Object old;
 397: 
 398:     if (value != null)
 399:       old = super.put(key, value);
 400:     else
 401:       old = super.remove(key);
 402: 
 403:     return old;
 404:   }
 405: 
 406:   /**
 407:    * Returns a font entry for the default locale.
 408:    *
 409:    * @param key the key to the requested entry
 410:    *
 411:    * @return the font entry for <code>key</code> or null if no such entry
 412:    *     exists
 413:    */
 414:   public Font getFont(Object key)
 415:   {
 416:     Object o = get(key);
 417:     return o instanceof Font ? (Font) o : null;
 418:   }
 419: 
 420:   /**
 421:    * Returns a font entry for a specic locale.
 422:    *
 423:    * @param key the key to the requested entry
 424:    * @param locale the locale to the requested entry
 425:    *
 426:    * @return the font entry for <code>key</code> or null if no such entry
 427:    *     exists
 428:    */
 429:   public Font getFont(Object key, Locale locale)
 430:   {
 431:     Object o = get(key, locale);
 432:     return o instanceof Font ? (Font) o : null;
 433:   }
 434: 
 435:   /**
 436:    * Returns a color entry for the default locale.
 437:    *
 438:    * @param key the key to the requested entry
 439:    *
 440:    * @return the color entry for <code>key</code> or null if no such entry
 441:    *     exists
 442:    */
 443:   public Color getColor(Object key)
 444:   {
 445:     Object o = get(key);
 446:     return o instanceof Color ? (Color) o : null;
 447:   }
 448: 
 449:   /**
 450:    * Returns a color entry for a specic locale.
 451:    *
 452:    * @param key the key to the requested entry
 453:    * @param locale the locale to the requested entry
 454:    *
 455:    * @return the color entry for <code>key</code> or null if no such entry
 456:    *     exists
 457:    */
 458:   public Color getColor(Object key, Locale locale)
 459:   {
 460:     Object o = get(key, locale);
 461:     return o instanceof Color ? (Color) o : null;
 462:   }
 463: 
 464:   /**
 465:    * Returns an icon entry for the default locale.
 466:    *
 467:    * @param key the key to the requested entry
 468:    *
 469:    * @return the icon entry for <code>key</code> or null if no such entry
 470:    *     exists
 471:    */
 472:   public Icon getIcon(Object key)
 473:   {
 474:     Object o = get(key);
 475:     return o instanceof Icon ? (Icon) o : null;
 476:   }
 477: 
 478:   /**
 479:    * Returns an icon entry for a specic locale.
 480:    *
 481:    * @param key the key to the requested entry
 482:    * @param locale the locale to the requested entry
 483:    *
 484:    * @return the icon entry for <code>key</code> or null if no such entry
 485:    *     exists
 486:    */
 487:   public Icon getIcon(Object key, Locale locale)
 488:   {
 489:     Object o = get(key, locale);
 490:     return o instanceof Icon ? (Icon) o : null;
 491:   }
 492: 
 493:   /**
 494:    * Returns a border entry for the default locale.
 495:    *
 496:    * @param key the key to the requested entry
 497:    *
 498:    * @return the border entry for <code>key</code> or null if no such entry
 499:    *     exists
 500:    */
 501:   public Border getBorder(Object key)
 502:   {
 503:     Object o = get(key);
 504:     return o instanceof Border ? (Border) o : null;
 505:   }
 506: 
 507:   /**
 508:    * Returns a border entry for a specic locale.
 509:    *
 510:    * @param key the key to the requested entry
 511:    * @param locale the locale to the requested entry
 512:    *
 513:    * @return the border entry for <code>key</code> or null if no such entry
 514:    *     exists
 515:    */
 516:   public Border getBorder(Object key, Locale locale)
 517:   {
 518:     Object o = get(key, locale);
 519:     return o instanceof Border ? (Border) o : null;
 520:   }
 521: 
 522:   /**
 523:    * Returns a string entry for the default locale.
 524:    *
 525:    * @param key the key to the requested entry
 526:    *
 527:    * @return the string entry for <code>key</code> or null if no such entry
 528:    *     exists
 529:    */
 530:   public String getString(Object key)
 531:   {
 532:     Object o = get(key);
 533:     return o instanceof String ? (String) o : null;
 534:   }
 535: 
 536:   /**
 537:    * Returns a string entry for a specic locale.
 538:    *
 539:    * @param key the key to the requested entry
 540:    * @param locale the locale to the requested entry
 541:    *
 542:    * @return the string entry for <code>key</code> or null if no such entry
 543:    *     exists
 544:    */
 545:   public String getString(Object key, Locale locale)
 546:   {
 547:     Object o = get(key, locale);
 548:     return o instanceof String ? (String) o : null;
 549:   }
 550: 
 551:   /**
 552:    * Returns an integer entry for the default locale.
 553:    *
 554:    * @param key the key to the requested entry
 555:    *
 556:    * @return the integer entry for <code>key</code> or null if no such entry
 557:    *     exists
 558:    */
 559:   public int getInt(Object key)
 560:   {
 561:     Object o = get(key);
 562:     return o instanceof Integer ? ((Integer) o).intValue() : 0;
 563:   }
 564: 
 565:   /**
 566:    * Returns an integer entry for a specic locale.
 567:    *
 568:    * @param key the key to the requested entry
 569:    * @param locale the locale to the requested entry
 570:    *
 571:    * @return the integer entry for <code>key</code> or null if no such entry
 572:    *     exists
 573:    */
 574:   public int getInt(Object key, Locale locale)
 575:   {
 576:     Object o = get(key, locale);
 577:     return o instanceof Integer ? ((Integer) o).intValue() : 0;
 578:   }
 579: 
 580:   /**
 581:    * Returns a boolean entry for the default locale.
 582:    *
 583:    * @param key the key to the requested entry
 584:    *
 585:    * @return The boolean entry for <code>key</code> or <code>false</code> if no 
 586:    *         such entry exists.
 587:    */
 588:   public boolean getBoolean(Object key)
 589:   {
 590:     return Boolean.TRUE.equals(get(key));
 591:   }
 592: 
 593:   /**
 594:    * Returns a boolean entry for a specic locale.
 595:    *
 596:    * @param key the key to the requested entry
 597:    * @param locale the locale to the requested entry
 598:    *
 599:    * @return the boolean entry for <code>key</code> or null if no such entry
 600:    *     exists
 601:    */
 602:   public boolean getBoolean(Object key, Locale locale)
 603:   {
 604:     return Boolean.TRUE.equals(get(key, locale));
 605:   }
 606: 
 607:   /**
 608:    * Returns an insets entry for the default locale.
 609:    *
 610:    * @param key the key to the requested entry
 611:    *
 612:    * @return the insets entry for <code>key</code> or null if no such entry
 613:    *     exists
 614:    */
 615:   public Insets getInsets(Object key) 
 616:   {
 617:     Object o = get(key);
 618:     return o instanceof Insets ? (Insets) o : null;
 619:   }
 620: 
 621:   /**
 622:    * Returns an insets entry for a specic locale.
 623:    *
 624:    * @param key the key to the requested entry
 625:    * @param locale the locale to the requested entry
 626:    *
 627:    * @return the boolean entry for <code>key</code> or null if no such entry
 628:    *     exists
 629:    */
 630:   public Insets getInsets(Object key, Locale locale) 
 631:   {
 632:     Object o = get(key, locale);
 633:     return o instanceof Insets ? (Insets) o : null;
 634:   }
 635: 
 636:   /**
 637:    * Returns a dimension entry for the default locale.
 638:    *
 639:    * @param key the key to the requested entry
 640:    *
 641:    * @return the dimension entry for <code>key</code> or null if no such entry
 642:    *     exists
 643:    */
 644:   public Dimension getDimension(Object key) 
 645:   {
 646:     Object o = get(key);
 647:     return o instanceof Dimension ? (Dimension) o : null;
 648:   }
 649: 
 650:   /**
 651:    * Returns a dimension entry for a specic locale.
 652:    *
 653:    * @param key the key to the requested entry
 654:    * @param locale the locale to the requested entry
 655:    *
 656:    * @return the boolean entry for <code>key</code> or null if no such entry
 657:    *     exists
 658:    */
 659:   public Dimension getDimension(Object key, Locale locale) 
 660:   {
 661:     Object o = get(key, locale);
 662:     return o instanceof Dimension ? (Dimension) o : null;
 663:   }
 664: 
 665:   /**
 666:    * Returns the ComponentUI class that renders a component. <code>id</code>
 667:    * is the ID for which the String value of the classname is stored in
 668:    * this UIDefaults map.
 669:    *
 670:    * @param id the ID of the UI class
 671:    * @param loader the ClassLoader to use
 672:    *
 673:    * @return the UI class for <code>id</code>
 674:    */
 675:   public Class<? extends ComponentUI> getUIClass(String id, ClassLoader loader)
 676:   {
 677:     String className = (String) get(id);
 678:     if (className == null)
 679:       return null;
 680:     try 
 681:       {
 682:         if (loader == null)
 683:           loader = ClassLoader.getSystemClassLoader();
 684:         return (Class<? extends ComponentUI>) loader.loadClass (className);
 685:       }
 686:     catch (Exception e)
 687:       {
 688:         return null;
 689:       }
 690:   }
 691: 
 692:   /**
 693:    * Returns the ComponentUI class that renders a component. <code>id</code>
 694:    * is the ID for which the String value of the classname is stored in
 695:    * this UIDefaults map.
 696:    *
 697:    * @param id the ID of the UI class
 698:    *
 699:    * @return the UI class for <code>id</code>
 700:    */
 701:   public Class<? extends ComponentUI> getUIClass(String id)
 702:   {
 703:     return getUIClass (id, null);
 704:   }
 705: 
 706:   /**
 707:    * If a key is requested in #get(key) that has no value, this method
 708:    * is called before returning <code>null</code>.
 709:    *
 710:    * @param msg the error message
 711:    */
 712:   protected void getUIError(String msg)
 713:   {
 714:     System.err.println ("UIDefaults.getUIError: " + msg);
 715:   }
 716: 
 717:   /**
 718:    * Returns the {@link ComponentUI} for the specified {@link JComponent}.
 719:    *
 720:    * @param target the component for which the ComponentUI is requested
 721:    *
 722:    * @return the {@link ComponentUI} for the specified {@link JComponent}
 723:    */
 724:   public ComponentUI getUI(JComponent target)
 725:   {
 726:     String classId = target.getUIClassID ();
 727:     Class cls = getUIClass (classId);
 728:     if (cls == null)
 729:       {
 730:         getUIError ("failed to locate UI class:" + classId);
 731:         return null;
 732:       }
 733: 
 734:     Method factory;
 735: 
 736:     try 
 737:       {
 738:         factory = cls.getMethod ("createUI", new Class[] { JComponent.class } );
 739:       }
 740:     catch (NoSuchMethodException nme)
 741:       {
 742:         getUIError ("failed to locate createUI method on " + cls.toString ());
 743:         return null;
 744:       }
 745: 
 746:     try
 747:       {
 748:         return (ComponentUI) factory.invoke (null, new Object[] { target });
 749:       }
 750:     catch (java.lang.reflect.InvocationTargetException ite)
 751:       {
 752:         getUIError ("InvocationTargetException ("+ ite.getTargetException() 
 753:             +") calling createUI(...) on " + cls.toString ());
 754:         return null;        
 755:       }
 756:     catch (Exception e)
 757:       {
 758:         getUIError ("exception calling createUI(...) on " + cls.toString ());
 759:         return null;        
 760:       }
 761:   }
 762: 
 763:   /**
 764:    * Adds a {@link PropertyChangeListener} to this UIDefaults map.
 765:    * Registered PropertyChangeListener are notified when values
 766:    * are beeing put into this UIDefaults map.
 767:    *
 768:    * @param listener the PropertyChangeListener to add
 769:    */
 770:   public void addPropertyChangeListener(PropertyChangeListener listener)
 771:   {
 772:     propertyChangeSupport.addPropertyChangeListener(listener);
 773:   }
 774: 
 775:   /**
 776:    * Removes a PropertyChangeListener from this UIDefaults map.
 777:    *
 778:    * @param listener the PropertyChangeListener to remove
 779:    */
 780:   public void removePropertyChangeListener(PropertyChangeListener listener)
 781:   {
 782:     propertyChangeSupport.removePropertyChangeListener(listener);
 783:   }
 784: 
 785:   /**
 786:    * Returns an array of all registered PropertyChangeListeners.
 787:    *
 788:    * @return all registered PropertyChangeListeners
 789:    */
 790:   public PropertyChangeListener[] getPropertyChangeListeners()
 791:   {
 792:     return propertyChangeSupport.getPropertyChangeListeners();
 793:   }
 794: 
 795:   /**
 796:    * Fires a PropertyChangeEvent.
 797:    *
 798:    * @param property the property name
 799:    * @param oldValue the old value
 800:    * @param newValue the new value
 801:    */
 802:   protected void firePropertyChange(String property,
 803:                     Object oldValue, Object newValue)
 804:   {
 805:     propertyChangeSupport.firePropertyChange(property, oldValue, newValue);
 806:   }
 807: 
 808:   /**
 809:    * Adds a ResourceBundle for localized values.
 810:    *
 811:    * @param name the name of the ResourceBundle to add
 812:    */
 813:   public void addResourceBundle(String name)
 814:   {
 815:     bundles.addFirst(name);
 816:   }
 817: 
 818:   /**
 819:    * Removes a ResourceBundle.
 820:    *
 821:    * @param name the name of the ResourceBundle to remove
 822:    */
 823:   public void removeResourceBundle(String name)
 824:   {
 825:     bundles.remove(name);
 826:   }
 827: 
 828:   /**
 829:    * Sets the current locale to <code>loc</code>.
 830:    *
 831:    * @param loc the Locale to be set
 832:    */
 833:   public void setDefaultLocale(Locale loc)
 834:   {
 835:     defaultLocale = loc;
 836:   }
 837: 
 838:   /**
 839:    * Returns the current default locale.
 840:    *
 841:    * @return the current default locale
 842:    */
 843:   public Locale getDefaultLocale()
 844:   {
 845:     return defaultLocale;
 846:   }
 847: }