Source for javax.swing.UIManager

   1: /* UIManager.java -- 
   2:    Copyright (C) 2002, 2003, 2004, 2005, 2006,  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.io.Serializable;
  48: import java.util.Locale;
  49: 
  50: import javax.swing.border.Border;
  51: import javax.swing.plaf.ComponentUI;
  52: import javax.swing.plaf.metal.MetalLookAndFeel;
  53: 
  54: /**
  55:  * Manages the current {@link LookAndFeel} and any auxiliary {@link LookAndFeel}
  56:  * instances.
  57:  */
  58: public class UIManager implements Serializable
  59: {
  60:   /**
  61:    * Represents the basic information about a {@link LookAndFeel} (LAF), so 
  62:    * that a list of installed LAFs can be presented without actually loading 
  63:    * the LAF class(es).
  64:    */
  65:   public static class LookAndFeelInfo
  66:   {
  67:     String name, clazz;
  68:     
  69:     /**
  70:      * Creates a new instance.
  71:      * 
  72:      * @param name  the look and feel name.
  73:      * @param clazz  the look and feel class name.
  74:      */
  75:     public LookAndFeelInfo(String name, 
  76:                String clazz)
  77:     {
  78:       this.name  = name;
  79:       this.clazz = clazz;
  80:     }
  81: 
  82:     /**
  83:      * Returns the name of the look and feel.
  84:      * 
  85:      * @return The name of the look and feel.
  86:      */
  87:     public String getName()
  88:     {
  89:       return name;
  90:     }
  91:     
  92:     /**
  93:      * Returns the fully qualified class name for the {@link LookAndFeel}.
  94:      * 
  95:      * @return The fully qualified class name for the {@link LookAndFeel}.
  96:      */
  97:     public String getClassName()
  98:     {
  99:       return clazz;
 100:     }
 101: 
 102:     /**
 103:      * Returns a String representation of the LookAndFeelInfo object.
 104:      *
 105:      * @return a String representation of the LookAndFeelInfo object
 106:      */
 107:     public String toString()
 108:     {
 109:       StringBuffer s = new StringBuffer();
 110:       s.append(getClass().getName());
 111:       s.append('[');
 112:       s.append(getName());
 113:       s.append(' ');
 114:       s.append(getClassName());
 115:       s.append(']');
 116:       return s.toString();
 117:     }
 118:   }
 119: 
 120:   private static final long serialVersionUID = -5547433830339189365L;
 121: 
 122:   /** The installed look and feel(s). */
 123:   static LookAndFeelInfo [] installed = {
 124:     new LookAndFeelInfo("Metal", "javax.swing.plaf.metal.MetalLookAndFeel"),
 125:     new LookAndFeelInfo("GNU", "gnu.javax.swing.plaf.gnu.GNULookAndFeel")
 126:   };
 127: 
 128:   /** The installed auxiliary look and feels. */
 129:   static LookAndFeel[] auxLookAndFeels;
 130:   
 131:   /** The current look and feel. */
 132:   static LookAndFeel currentLookAndFeel;
 133:   
 134:   static UIDefaults currentUIDefaults;
 135: 
 136:   /**
 137:    * UIDefaults set by the user.
 138:    */
 139:   static UIDefaults userUIDefaults;
 140: 
 141:   /** Property change listener mechanism. */
 142:   static PropertyChangeSupport listeners
 143:       = new PropertyChangeSupport(UIManager.class);
 144: 
 145:   static
 146:   {
 147:     String defaultlaf = System.getProperty("swing.defaultlaf");
 148:     try {
 149:       if (defaultlaf != null)
 150:         {
 151:           Class lafClass = Class.forName(defaultlaf);
 152:           LookAndFeel laf = (LookAndFeel) lafClass.newInstance();
 153:           setLookAndFeel(laf);
 154:         }
 155:       else
 156:         {
 157:           setLookAndFeel(new MetalLookAndFeel());
 158:         }
 159:     }
 160:     catch (Exception ex)
 161:       {
 162:         System.err.println("cannot initialize Look and Feel: " + defaultlaf);
 163:         System.err.println("error: " + ex.toString());
 164:         System.err.println("falling back to Metal Look and Feel");
 165:         try
 166:           {
 167:             setLookAndFeel(new MetalLookAndFeel());
 168:           }
 169:         catch (Exception ex2)
 170:         {
 171:           throw (Error) new AssertionError("There must be no problem installing"
 172:                                            + " the MetalLookAndFeel.")
 173:                                            .initCause(ex2);
 174:         }
 175:       }
 176:   }
 177: 
 178:   /**
 179:    * Creates a new instance of the <code>UIManager</code>.  There is no need
 180:    * to construct an instance of this class, since all methods are static.
 181:    */
 182:   public UIManager()
 183:   {
 184:     // Do nothing here.
 185:   }
 186: 
 187:   /**
 188:    * Add a <code>PropertyChangeListener</code> to the listener list.
 189:    *
 190:    * @param listener the listener to add
 191:    */
 192:   public static void addPropertyChangeListener(PropertyChangeListener listener)
 193:   {
 194:     listeners.addPropertyChangeListener(listener);
 195:   }
 196: 
 197:   /**
 198:    * Remove a <code>PropertyChangeListener</code> from the listener list.
 199:    *
 200:    * @param listener the listener to remove
 201:    */
 202:   public static void removePropertyChangeListener(PropertyChangeListener 
 203:           listener)
 204:   {
 205:     listeners.removePropertyChangeListener(listener);
 206:   }
 207: 
 208:   /**
 209:    * Returns an array of all added <code>PropertyChangeListener</code> objects.
 210:    *
 211:    * @return an array of listeners
 212:    *
 213:    * @since 1.4
 214:    */
 215:   public static PropertyChangeListener[] getPropertyChangeListeners()
 216:   {
 217:     return listeners.getPropertyChangeListeners();
 218:   }
 219: 
 220:   /**
 221:    * Add a {@link LookAndFeel} to the list of auxiliary look and feels.
 222:    * 
 223:    * @param laf  the auxiliary look and feel (<code>null</code> not permitted).
 224:    * 
 225:    * @throws NullPointerException if <code>laf</code> is <code>null</code>.
 226:    * 
 227:    * @see #getAuxiliaryLookAndFeels()
 228:    */
 229:   public static void addAuxiliaryLookAndFeel(LookAndFeel laf)
 230:   {
 231:     if (laf == null)
 232:       throw new NullPointerException("Null 'laf' argument.");
 233:     if (auxLookAndFeels == null)
 234:       {
 235:         auxLookAndFeels = new LookAndFeel[1];
 236:         auxLookAndFeels[0] = laf;
 237:         return;
 238:       }
 239:     
 240:     LookAndFeel[] temp = new LookAndFeel[auxLookAndFeels.length + 1];
 241:     System.arraycopy(auxLookAndFeels, 0, temp, 0, auxLookAndFeels.length);             
 242:     auxLookAndFeels = temp;
 243:     auxLookAndFeels[auxLookAndFeels.length - 1] = laf;
 244:   }
 245:     
 246:   /**
 247:    * Removes a {@link LookAndFeel} (LAF) from the list of auxiliary LAFs.
 248:    * 
 249:    * @param laf  the LAF to remove.
 250:    * 
 251:    * @return <code>true</code> if the LAF was removed, and <code>false</code>
 252:    *         otherwise.
 253:    */
 254:   public static boolean removeAuxiliaryLookAndFeel(LookAndFeel laf)
 255:   {
 256:     if (auxLookAndFeels == null)
 257:       return false;
 258:     int count = auxLookAndFeels.length;
 259:     if (count == 1 && auxLookAndFeels[0] == laf)
 260:       {
 261:         auxLookAndFeels = null;
 262:         return true;
 263:       }
 264:     for (int i = 0; i < count; i++)
 265:       {
 266:         if (auxLookAndFeels[i] == laf)
 267:           {
 268:             LookAndFeel[] temp = new LookAndFeel[auxLookAndFeels.length - 1];
 269:             if (i == 0)
 270:               {
 271:                 System.arraycopy(auxLookAndFeels, 1, temp, 0, count - 1);  
 272:               }
 273:             else if (i == count - 1)
 274:               {
 275:                 System.arraycopy(auxLookAndFeels, 0, temp, 0, count - 1);
 276:               }
 277:             else 
 278:               {
 279:                 System.arraycopy(auxLookAndFeels, 0, temp, 0, i);
 280:                 System.arraycopy(auxLookAndFeels, i + 1, temp, i, 
 281:                         count - i - 1);
 282:               }
 283:             auxLookAndFeels = temp;
 284:             return true;
 285:           }        
 286:       }
 287:     return false;
 288:   }
 289: 
 290:   /**
 291:    * Returns an array (possibly <code>null</code>) containing the auxiliary
 292:    * {@link LookAndFeel}s that are in use.  These are used by the 
 293:    * {@link javax.swing.plaf.multi.MultiLookAndFeel} class.
 294:    * 
 295:    * @return The auxiliary look and feels (possibly <code>null</code>).
 296:    * 
 297:    * @see #addAuxiliaryLookAndFeel(LookAndFeel)
 298:    */
 299:   public static LookAndFeel[] getAuxiliaryLookAndFeels()
 300:   {
 301:     return auxLookAndFeels;
 302:   }
 303: 
 304:   /**
 305:    * Returns an object from the {@link UIDefaults} table for the current
 306:    * {@link LookAndFeel}.
 307:    * 
 308:    * @param key  the key.
 309:    * 
 310:    * @return The object.
 311:    */
 312:   public static Object get(Object key)
 313:   {
 314:     Object val = null;
 315:     if (userUIDefaults != null)
 316:       val = userUIDefaults.get(key);
 317:     if (val == null)
 318:       val = getLookAndFeelDefaults().get(key);
 319:     return val;
 320:   }
 321: 
 322:   /**
 323:    * Returns an object from the {@link UIDefaults} table for the current
 324:    * {@link LookAndFeel}.
 325:    * 
 326:    * @param key  the key.
 327:    * 
 328:    * @return The object.
 329:    */
 330:   public static Object get(Object key, Locale locale)
 331:   {
 332:     Object val = null;
 333:     if (userUIDefaults != null)
 334:       val = userUIDefaults.get(key, locale);
 335:     if (val == null)
 336:       val = getLookAndFeelDefaults().get(key, locale);
 337:     return val;
 338:   }
 339: 
 340:   /**
 341:    * Returns a boolean value from the defaults table,
 342:    * <code>false</code> if key is not present.
 343:    *
 344:    * @since 1.4
 345:    */
 346:   public static boolean getBoolean(Object key)
 347:   {
 348:     Boolean value = (Boolean) get(key);
 349:     return value != null ? value.booleanValue() : false;
 350:   }
 351:   
 352:   /**
 353:    * Returns a boolean value from the defaults table,
 354:    * <code>false</code> if key is not present.
 355:    *
 356:    * @since 1.4
 357:    */
 358:   public static boolean getBoolean(Object key, Locale locale)
 359:   {
 360:     Boolean value = (Boolean) get(key, locale);
 361:     return value != null ? value.booleanValue() : false;
 362:   }
 363:     
 364:   /**
 365:    * Returns a border from the defaults table. 
 366:    */
 367:   public static Border getBorder(Object key)
 368:   {
 369:     return (Border) get(key);
 370:   }
 371:     
 372:   /**
 373:    * Returns a border from the defaults table.
 374:    *
 375:    * @since 1.4
 376:    */
 377:   public static Border getBorder(Object key, Locale locale)
 378:   {
 379:     return (Border) get(key, locale);
 380:   }
 381:     
 382:   /**
 383:    * Returns a drawing color from the defaults table. 
 384:    */
 385:   public static Color getColor(Object key)
 386:   {
 387:     return (Color) get(key);
 388:   }
 389: 
 390:   /**
 391:    * Returns a drawing color from the defaults table. 
 392:    */
 393:   public static Color getColor(Object key, Locale locale)
 394:   {
 395:     return (Color) get(key);
 396:   }
 397: 
 398:   /**
 399:    * The fully qualified class name of the cross platform (Metal) look and feel.
 400:    * This string can be passed to Class.forName()
 401:    * 
 402:    * @return <code>"javax.swing.plaf.metal.MetalLookAndFeel"</code>
 403:    */
 404:   public static String getCrossPlatformLookAndFeelClassName()
 405:   {    
 406:     return "javax.swing.plaf.metal.MetalLookAndFeel";
 407:   }
 408: 
 409:   /**
 410:    * Returns the default values for this look and feel. 
 411:    * 
 412:    * @return The {@link UIDefaults} for the current {@link LookAndFeel}.
 413:    */
 414:   public static UIDefaults getDefaults()
 415:   {
 416:     return currentUIDefaults;
 417:   }
 418: 
 419:   /**
 420:    * Returns a dimension from the defaults table. 
 421:    */
 422:   public static Dimension getDimension(Object key)
 423:   {
 424:     return (Dimension) get(key);
 425:   }
 426: 
 427:   /**
 428:    * Returns a dimension from the defaults table. 
 429:    */
 430:   public static Dimension getDimension(Object key, Locale locale)
 431:   {
 432:     return (Dimension) get(key, locale);
 433:   }
 434: 
 435:   /**
 436:    * Retrieves a font from the defaults table of the current
 437:    * LookAndFeel.
 438:    *
 439:    * @param key an Object that specifies the font. Typically,
 440:    *        this is a String such as
 441:    *        <code>TitledBorder.font</code>.
 442:    */
 443:   public static Font getFont(Object key)
 444:   {
 445:     return (Font) get(key);
 446:   }
 447: 
 448:   /**
 449:    * Retrieves a font from the defaults table of the current
 450:    * LookAndFeel.
 451:    *
 452:    * @param key an Object that specifies the font. Typically,
 453:    *        this is a String such as
 454:    *        <code>TitledBorder.font</code>.
 455:    */
 456:   public static Font getFont(Object key, Locale locale)
 457:   {
 458:     return (Font) get(key ,locale);
 459:   }
 460: 
 461:   /**
 462:    * Returns an Icon from the defaults table.
 463:    */
 464:   public static Icon getIcon(Object key)
 465:   {
 466:     return (Icon) get(key);
 467:   }
 468:   
 469:   /**
 470:    * Returns an Icon from the defaults table.
 471:    */
 472:   public static Icon getIcon(Object key, Locale locale)
 473:   {
 474:     return (Icon) get(key, locale);
 475:   }
 476:   
 477:   /**
 478:    * Returns an Insets object from the defaults table.
 479:    */
 480:   public static Insets getInsets(Object key)
 481:   {
 482:     Object o = get(key);
 483:     if (o instanceof Insets)
 484:       return (Insets) o;
 485:     else
 486:       return null;
 487:   }
 488: 
 489:   /**
 490:    * Returns an Insets object from the defaults table.
 491:    */
 492:   public static Insets getInsets(Object key, Locale locale)
 493:   {
 494:     Object o = get(key, locale);
 495:     if (o instanceof Insets)
 496:       return (Insets) o;
 497:     else
 498:       return null;
 499:   }
 500: 
 501:   /**
 502:    * Returns an array containing information about the {@link LookAndFeel}s
 503:    * that are installed.
 504:    * 
 505:    * @return A list of the look and feels that are available (installed).
 506:    */
 507:   public static LookAndFeelInfo[] getInstalledLookAndFeels()
 508:   {
 509:     return installed;
 510:   }
 511: 
 512:   public static int getInt(Object key)
 513:   {
 514:     Integer x = (Integer) get(key);
 515:     if (x == null)
 516:       return 0;
 517:     return x.intValue();
 518:   }
 519: 
 520:   public static int getInt(Object key, Locale locale)
 521:   {
 522:     Integer x = (Integer) get(key, locale);
 523:     if (x == null)
 524:       return 0;
 525:     return x.intValue();
 526:   }
 527: 
 528:   /**
 529:    * Returns the current look and feel (which may be <code>null</code>).
 530:    * 
 531:    * @return The current look and feel.
 532:    * 
 533:    * @see #setLookAndFeel(LookAndFeel)
 534:    */
 535:   public static LookAndFeel getLookAndFeel()
 536:   {
 537:     return currentLookAndFeel;
 538:   }
 539: 
 540:   /**
 541:    * Returns the <code>UIDefaults</code> table of the currently active
 542:    * look and feel.
 543:    * 
 544:    * @return The {@link UIDefaults} for the current {@link LookAndFeel}.
 545:    */
 546:   public static UIDefaults getLookAndFeelDefaults()
 547:   {
 548:     return currentUIDefaults;
 549:   }
 550: 
 551:   /**
 552:    * Returns a string from the defaults table.
 553:    */
 554:   public static String getString(Object key)
 555:   {
 556:     return (String) get(key);
 557:   }
 558:   
 559:   /**
 560:    * Returns a string from the defaults table.
 561:    */
 562:   public static String getString(Object key, Locale locale)
 563:   {
 564:     return (String) get(key, locale);
 565:   }
 566:   
 567:   /**
 568:    * Returns the name of the {@link LookAndFeel} class that implements the
 569:    * native systems look and feel if there is one, otherwise the name
 570:    * of the default cross platform LookAndFeel class.
 571:    * 
 572:    * @return The fully qualified class name for the system look and feel.
 573:    * 
 574:    * @see #getCrossPlatformLookAndFeelClassName()
 575:    */
 576:   public static String getSystemLookAndFeelClassName()
 577:   {
 578:     return getCrossPlatformLookAndFeelClassName();
 579:   }
 580: 
 581:   /**
 582:    * Returns UI delegate from the current {@link LookAndFeel} that renders the 
 583:    * target component.
 584:    * 
 585:    * @param target  the target component.
 586:    */
 587:   public static ComponentUI getUI(JComponent target)
 588:   {
 589:     ComponentUI ui = null;
 590:     if (userUIDefaults != null
 591:         && userUIDefaults.get(target.getUIClassID()) != null)
 592:       ui = userUIDefaults.getUI(target);
 593:     if (ui == null)
 594:       ui = currentUIDefaults.getUI(target);
 595:     return ui;
 596:   }
 597: 
 598:   /**
 599:    * Creates a new look and feel and adds it to the current array.
 600:    * 
 601:    * @param name  the look and feel name.
 602:    * @param className  the fully qualified name of the class that implements the
 603:    *                   look and feel.
 604:    */
 605:   public static void installLookAndFeel(String name, String className)
 606:   {
 607:     installLookAndFeel(new LookAndFeelInfo(name, className));
 608:   }
 609: 
 610:   /**
 611:    * Adds the specified look and feel to the current array and then calls
 612:    * setInstalledLookAndFeels(javax.swing.UIManager.LookAndFeelInfo[]).
 613:    */
 614:   public static void installLookAndFeel(LookAndFeelInfo info)
 615:   {
 616:     LookAndFeelInfo[] newInstalled = new LookAndFeelInfo[installed.length + 1];
 617:     System.arraycopy(installed, 0, newInstalled, 0, installed.length);
 618:     newInstalled[newInstalled.length - 1] = info;
 619:     setInstalledLookAndFeels(newInstalled);
 620:   }
 621: 
 622:   /**
 623:    * Stores an object in the defaults table.
 624:    */
 625:   public static Object put(Object key, Object value)
 626:   {
 627:     Object old = get(key);
 628:     if (userUIDefaults == null)
 629:       userUIDefaults = new UIDefaults();
 630:     userUIDefaults.put(key, value);
 631:     return old;
 632:   }
 633: 
 634:   /**
 635:    * Replaces the current array of installed LookAndFeelInfos.
 636:    */
 637:   public static void setInstalledLookAndFeels(UIManager.LookAndFeelInfo[] infos)
 638:   {
 639:     installed = infos;
 640:   }
 641:   
 642:   /**
 643:    * Sets the current {@link LookAndFeel}.
 644:    * 
 645:    * @param newLookAndFeel  the new look and feel (<code>null</code> permitted).
 646:    * 
 647:    * @throws UnsupportedLookAndFeelException if the look and feel is not 
 648:    *         supported on the current platform.
 649:    * 
 650:    * @see LookAndFeel#isSupportedLookAndFeel()
 651:    */
 652:   public static void setLookAndFeel(LookAndFeel newLookAndFeel)
 653:     throws UnsupportedLookAndFeelException
 654:   {
 655:     if (newLookAndFeel != null && ! newLookAndFeel.isSupportedLookAndFeel())
 656:       throw new UnsupportedLookAndFeelException(newLookAndFeel.getName());
 657:     LookAndFeel oldLookAndFeel = currentLookAndFeel;
 658:     if (oldLookAndFeel != null)
 659:       oldLookAndFeel.uninitialize();
 660: 
 661:     // Set the current default look and feel using a LookAndFeel object. 
 662:     currentLookAndFeel = newLookAndFeel;
 663:     if (newLookAndFeel != null)
 664:       {
 665:         newLookAndFeel.initialize();
 666:         currentUIDefaults = newLookAndFeel.getDefaults();
 667:       }
 668:     else
 669:       {
 670:         currentUIDefaults = null;    
 671:       }
 672:     listeners.firePropertyChange("lookAndFeel", oldLookAndFeel, newLookAndFeel);
 673:     //revalidate();
 674:     //repaint();
 675:   }
 676: 
 677:   /**
 678:    * Set the current default look and feel using a class name.
 679:    * 
 680:    * @param className  the look and feel class name.
 681:    * 
 682:    * @throws UnsupportedLookAndFeelException if the look and feel is not 
 683:    *         supported on the current platform.
 684:    * 
 685:    * @see LookAndFeel#isSupportedLookAndFeel()
 686:    */
 687:   public static void setLookAndFeel(String className)
 688:     throws ClassNotFoundException, InstantiationException, IllegalAccessException,
 689:     UnsupportedLookAndFeelException
 690:   {
 691:     Class c = Class.forName(className);
 692:     LookAndFeel a = (LookAndFeel) c.newInstance(); // throws class-cast-exception
 693:     setLookAndFeel(a);
 694:   }
 695: }