Source for javax.swing.UIManager

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