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