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