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