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