Save This Page
Home » openjdk-7 » javax » swing » [javadoc | source]
    1   /*
    2    * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   package javax.swing;
   26   
   27   import java.awt.Component;
   28   import java.awt.Font;
   29   import java.awt.Color;
   30   import java.awt.Insets;
   31   import java.awt.Dimension;
   32   import java.awt.KeyboardFocusManager;
   33   import java.awt.KeyEventPostProcessor;
   34   import java.awt.Toolkit;
   35   
   36   import java.awt.event.KeyEvent;
   37   
   38   import java.security.AccessController;
   39   
   40   import javax.swing.plaf.ComponentUI;
   41   import javax.swing.border.Border;
   42   
   43   import javax.swing.event.SwingPropertyChangeSupport;
   44   import java.beans.PropertyChangeListener;
   45   
   46   import java.io.Serializable;
   47   import java.io.File;
   48   import java.io.FileInputStream;
   49   
   50   import java.util.ArrayList;
   51   import java.util.Properties;
   52   import java.util.StringTokenizer;
   53   import java.util.Vector;
   54   import java.util.Locale;
   55   
   56   import sun.awt.SunToolkit;
   57   import sun.awt.OSInfo;
   58   import sun.security.action.GetPropertyAction;
   59   import sun.swing.SwingUtilities2;
   60   import java.lang.reflect.Method;
   61   
   62   
   63   /**
   64    * {@code UIManager} manages the current look and feel, the set of
   65    * available look and feels, {@code PropertyChangeListeners} that
   66    * are notified when the look and feel changes, look and feel defaults, and
   67    * convenience methods for obtaining various default values.
   68    *
   69    * <h3>Specifying the look and feel</h3>
   70    *
   71    * The look and feel can be specified in two distinct ways: by
   72    * specifying the fully qualified name of the class for the look and
   73    * feel, or by creating an instance of {@code LookAndFeel} and passing
   74    * it to {@code setLookAndFeel}. The following example illustrates
   75    * setting the look and feel to the system look and feel:
   76    * <pre>
   77    *   UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
   78    * </pre>
   79    * The following example illustrates setting the look and feel based on
   80    * class name:
   81    * <pre>
   82    *   UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
   83    * </pre>
   84    * Once the look and feel has been changed it is imperative to invoke
   85    * {@code updateUI} on all {@code JComponents}. The method {@link
   86    * SwingUtilities#updateComponentTreeUI} makes it easy to apply {@code
   87    * updateUI} to a containment hierarchy. Refer to it for
   88    * details. The exact behavior of not invoking {@code
   89    * updateUI} after changing the look and feel is
   90    * unspecified. It is very possible to receive unexpected exceptions,
   91    * painting problems, or worse.
   92    *
   93    * <h3>Default look and feel</h3>
   94    *
   95    * The class used for the default look and feel is chosen in the following
   96    * manner:
   97    * <ol>
   98    *   <li>If the system property <code>swing.defaultlaf</code> is
   99    *       {@code non-null}, use its value as the default look and feel class
  100    *       name.
  101    *   <li>If the {@link java.util.Properties} file <code>swing.properties</code>
  102    *       exists and contains the key <code>swing.defaultlaf</code>,
  103    *       use its value as the default look and feel class name. The location
  104    *       that is checked for <code>swing.properties</code> may vary depending
  105    *       upon the implementation of the Java platform. In Sun's implementation
  106    *       the location is <code>${java.home}/lib/swing.properties</code>.
  107    *       Refer to the release notes of the implementation being used for
  108    *       further details.
  109    *   <li>Otherwise use the cross platform look and feel.
  110    * </ol>
  111    *
  112    * <h3>Defaults</h3>
  113    *
  114    * {@code UIManager} manages three sets of {@code UIDefaults}. In order, they
  115    * are:
  116    * <ol>
  117    *   <li>Developer defaults. With few exceptions Swing does not
  118    *       alter the developer defaults; these are intended to be modified
  119    *       and used by the developer.
  120    *   <li>Look and feel defaults. The look and feel defaults are
  121    *       supplied by the look and feel at the time it is installed as the
  122    *       current look and feel ({@code setLookAndFeel()} is invoked). The
  123    *       look and feel defaults can be obtained using the {@code
  124    *       getLookAndFeelDefaults()} method.
  125    *   <li>Sytem defaults. The system defaults are provided by Swing.
  126    * </ol>
  127    * Invoking any of the various {@code get} methods
  128    * results in checking each of the defaults, in order, returning
  129    * the first {@code non-null} value. For example, invoking
  130    * {@code UIManager.getString("Table.foreground")} results in first
  131    * checking developer defaults. If the developer defaults contain
  132    * a value for {@code "Table.foreground"} it is returned, otherwise
  133    * the look and feel defaults are checked, followed by the system defaults.
  134    * <p>
  135    * It's important to note that {@code getDefaults} returns a custom
  136    * instance of {@code UIDefaults} with this resolution logic built into it.
  137    * For example, {@code UIManager.getDefaults().getString("Table.foreground")}
  138    * is equivalent to {@code UIManager.getString("Table.foreground")}. Both
  139    * resolve using the algorithm just described. In many places the
  140    * documentation uses the word defaults to refer to the custom instance
  141    * of {@code UIDefaults} with the resolution logic as previously described.
  142    * <p>
  143    * When the look and feel is changed, {@code UIManager} alters only the
  144    * look and feel defaults; the developer and system defaults are not
  145    * altered by the {@code UIManager} in any way.
  146    * <p>
  147    * The set of defaults a particular look and feel supports is defined
  148    * and documented by that look and feel. In addition, each look and
  149    * feel, or {@code ComponentUI} provided by a look and feel, may
  150    * access the defaults at different times in their life cycle. Some
  151    * look and feels may agressively look up defaults, so that changing a
  152    * default may not have an effect after installing the look and feel.
  153    * Other look and feels may lazily access defaults so that a change to
  154    * the defaults may effect an existing look and feel. Finally, other look
  155    * and feels might not configure themselves from the defaults table in
  156    * any way. None-the-less it is usually the case that a look and feel
  157    * expects certain defaults, so that in general
  158    * a {@code ComponentUI} provided by one look and feel will not
  159    * work with another look and feel.
  160    * <p>
  161    * <strong>Warning:</strong>
  162    * Serialized objects of this class will not be compatible with
  163    * future Swing releases. The current serialization support is
  164    * appropriate for short term storage or RMI between applications running
  165    * the same version of Swing.  As of 1.4, support for long term storage
  166    * of all JavaBeans<sup><font size="-2">TM</font></sup>
  167    * has been added to the <code>java.beans</code> package.
  168    * Please see {@link java.beans.XMLEncoder}.
  169    *
  170    * @author Thomas Ball
  171    * @author Hans Muller
  172    */
  173   public class UIManager implements Serializable
  174   {
  175       /**
  176        * This class defines the state managed by the <code>UIManager</code>.  For
  177        * Swing applications the fields in this class could just as well
  178        * be static members of <code>UIManager</code> however we give them
  179        * "AppContext"
  180        * scope instead so that applets (and potentially multiple lightweight
  181        * applications running in a single VM) have their own state. For example,
  182        * an applet can alter its look and feel, see <code>setLookAndFeel</code>.
  183        * Doing so has no affect on other applets (or the browser).
  184        */
  185       private static class LAFState
  186       {
  187           Properties swingProps;
  188           private UIDefaults[] tables = new UIDefaults[2];
  189   
  190           boolean initialized = false;
  191           MultiUIDefaults multiUIDefaults = new MultiUIDefaults(tables);
  192           LookAndFeel lookAndFeel;
  193           LookAndFeel multiLookAndFeel = null;
  194           Vector auxLookAndFeels = null;
  195           SwingPropertyChangeSupport changeSupport;
  196   
  197           UIDefaults getLookAndFeelDefaults() { return tables[0]; }
  198           void setLookAndFeelDefaults(UIDefaults x) { tables[0] = x; }
  199   
  200           UIDefaults getSystemDefaults() { return tables[1]; }
  201           void setSystemDefaults(UIDefaults x) { tables[1] = x; }
  202   
  203           /**
  204            * Returns the SwingPropertyChangeSupport for the current
  205            * AppContext.  If <code>create</code> is a true, a non-null
  206            * <code>SwingPropertyChangeSupport</code> will be returned, if
  207            * <code>create</code> is false and this has not been invoked
  208            * with true, null will be returned.
  209            */
  210           public synchronized SwingPropertyChangeSupport
  211                                    getPropertyChangeSupport(boolean create) {
  212               if (create && changeSupport == null) {
  213                   changeSupport = new SwingPropertyChangeSupport(
  214                                            UIManager.class);
  215               }
  216               return changeSupport;
  217           }
  218       }
  219   
  220   
  221   
  222   
  223       /* Lock object used in place of class object for synchronization. (4187686)
  224        */
  225       private static final Object classLock = new Object();
  226   
  227   
  228       /* Cache the last referenced LAFState to improve performance
  229        * when accessing it.  The cache is based on last thread rather
  230        * than last AppContext because of the cost of looking up the
  231        * AppContext each time.  Since most Swing UI work is on the
  232        * EventDispatchThread, this hits often enough to justify the
  233        * overhead.  (4193032)
  234        */
  235       private static Thread currentLAFStateThread = null;
  236       private static LAFState currentLAFState = null;
  237   
  238   
  239       /**
  240        * Return the <code>LAFState</code> object, lazily create one if necessary.
  241        * All access to the <code>LAFState</code> fields is done via this method,
  242        * for example:
  243        * <pre>
  244        *     getLAFState().initialized = true;
  245        * </pre>
  246        */
  247       private static LAFState getLAFState() {
  248           // First check whether we're running on the same thread as
  249           // the last request.
  250           Thread thisThread = Thread.currentThread();
  251           if (thisThread == currentLAFStateThread) {
  252               return currentLAFState;
  253           }
  254   
  255           LAFState rv = (LAFState)SwingUtilities.appContextGet(
  256                   SwingUtilities2.LAF_STATE_KEY);
  257           if (rv == null) {
  258               synchronized (classLock) {
  259                   rv = (LAFState)SwingUtilities.appContextGet(
  260                           SwingUtilities2.LAF_STATE_KEY);
  261                   if (rv == null) {
  262                       SwingUtilities.appContextPut(
  263                               SwingUtilities2.LAF_STATE_KEY,
  264                               (rv = new LAFState()));
  265                   }
  266               }
  267           }
  268   
  269           currentLAFStateThread = thisThread;
  270           currentLAFState = rv;
  271   
  272           return rv;
  273       }
  274   
  275   
  276       /* Keys used for the properties file in <java.home>/lib/swing.properties.
  277        * See loadUserProperties(), initialize().
  278        */
  279   
  280       private static final String defaultLAFKey = "swing.defaultlaf";
  281       private static final String auxiliaryLAFsKey = "swing.auxiliarylaf";
  282       private static final String multiplexingLAFKey = "swing.plaf.multiplexinglaf";
  283       private static final String installedLAFsKey = "swing.installedlafs";
  284       private static final String disableMnemonicKey = "swing.disablenavaids";
  285   
  286       /**
  287        * Return a swing.properties file key for the attribute of specified
  288        * look and feel.  The attr is either "name" or "class", a typical
  289        * key would be: "swing.installedlaf.windows.name"
  290        */
  291       private static String makeInstalledLAFKey(String laf, String attr) {
  292           return "swing.installedlaf." + laf + "." + attr;
  293       }
  294   
  295       /**
  296        * The filename for swing.properties is a path like this (Unix version):
  297        * <java.home>/lib/swing.properties.  This method returns a bogus
  298        * filename if java.home isn't defined.
  299        */
  300       private static String makeSwingPropertiesFilename() {
  301           String sep = File.separator;
  302           // No need to wrap this in a doPrivileged as it's called from
  303           // a doPrivileged.
  304           String javaHome = System.getProperty("java.home");
  305           if (javaHome == null) {
  306               javaHome = "<java.home undefined>";
  307           }
  308           return javaHome + sep + "lib" + sep + "swing.properties";
  309       }
  310   
  311   
  312       /**
  313        * Provides a little information about an installed
  314        * <code>LookAndFeel</code> for the sake of configuring a menu or
  315        * for initial application set up.
  316        *
  317        * @see UIManager#getInstalledLookAndFeels
  318        * @see LookAndFeel
  319        */
  320       public static class LookAndFeelInfo {
  321           private String name;
  322           private String className;
  323   
  324           /**
  325            * Constructs a <code>UIManager</code>s
  326            * <code>LookAndFeelInfo</code> object.
  327            *
  328            * @param name      a <code>String</code> specifying the name of
  329            *                      the look and feel
  330            * @param className a <code>String</code> specifiying the name of
  331            *                      the class that implements the look and feel
  332            */
  333           public LookAndFeelInfo(String name, String className) {
  334               this.name = name;
  335               this.className = className;
  336           }
  337   
  338           /**
  339            * Returns the name of the look and feel in a form suitable
  340            * for a menu or other presentation
  341            * @return a <code>String</code> containing the name
  342            * @see LookAndFeel#getName
  343            */
  344           public String getName() {
  345               return name;
  346           }
  347   
  348           /**
  349            * Returns the name of the class that implements this look and feel.
  350            * @return the name of the class that implements this
  351            *              <code>LookAndFeel</code>
  352            * @see LookAndFeel
  353            */
  354           public String getClassName() {
  355               return className;
  356           }
  357   
  358           /**
  359            * Returns a string that displays and identifies this
  360            * object's properties.
  361            *
  362            * @return a <code>String</code> representation of this object
  363            */
  364           public String toString() {
  365               return getClass().getName() + "[" + getName() + " " + getClassName() + "]";
  366           }
  367       }
  368   
  369   
  370       /**
  371        * The default value of <code>installedLAFS</code> is used when no
  372        * swing.properties
  373        * file is available or if the file doesn't contain a "swing.installedlafs"
  374        * property.
  375        *
  376        * @see #initializeInstalledLAFs
  377        */
  378       private static LookAndFeelInfo[] installedLAFs;
  379   
  380       static {
  381           ArrayList iLAFs = new ArrayList(4);
  382           iLAFs.add(new LookAndFeelInfo(
  383                         "Metal", "javax.swing.plaf.metal.MetalLookAndFeel"));
  384           iLAFs.add(new LookAndFeelInfo("CDE/Motif",
  385                     "com.sun.java.swing.plaf.motif.MotifLookAndFeel"));
  386   
  387           // Only include windows on Windows boxs.
  388           OSInfo.OSType osType = AccessController.doPrivileged(OSInfo.getOSTypeAction());
  389           if (osType == OSInfo.OSType.WINDOWS) {
  390               iLAFs.add(new LookAndFeelInfo("Windows",
  391                           "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"));
  392               if (Toolkit.getDefaultToolkit().getDesktopProperty(
  393                       "win.xpstyle.themeActive") != null) {
  394                   iLAFs.add(new LookAndFeelInfo("Windows Classic",
  395                    "com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel"));
  396               }
  397           }
  398           else {
  399               // GTK is not shipped on Windows.
  400               iLAFs.add(new LookAndFeelInfo("GTK+",
  401                     "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"));
  402           }
  403           installedLAFs = (LookAndFeelInfo[])iLAFs.toArray(
  404                           new LookAndFeelInfo[iLAFs.size()]);
  405       }
  406   
  407   
  408       /**
  409        * Returns an array of {@code LookAndFeelInfo}s representing the
  410        * {@code LookAndFeel} implementations currently available. The
  411        * <code>LookAndFeelInfo</code> objects can be used by an
  412        * application to construct a menu of look and feel options for
  413        * the user, or to determine which look and feel to set at startup
  414        * time. To avoid the penalty of creating numerous {@code
  415        * LookAndFeel} objects, {@code LookAndFeelInfo} maintains the
  416        * class name of the {@code LookAndFeel} class, not the actual
  417        * {@code LookAndFeel} instance.
  418        * <p>
  419        * The following example illustrates setting the current look and feel
  420        * from an instance of {@code LookAndFeelInfo}:
  421        * <pre>
  422        *   UIManager.setLookAndFeel(info.getClassName());
  423        * </pre>
  424        *
  425        * @return an array of <code>LookAndFeelInfo</code> objects
  426        * @see #setLookAndFeel
  427        */
  428       public static LookAndFeelInfo[] getInstalledLookAndFeels() {
  429           maybeInitialize();
  430           LookAndFeelInfo[] ilafs = installedLAFs;
  431           LookAndFeelInfo[] rv = new LookAndFeelInfo[ilafs.length];
  432           System.arraycopy(ilafs, 0, rv, 0, ilafs.length);
  433           return rv;
  434       }
  435   
  436   
  437       /**
  438        * Sets the set of available look and feels. While this method does
  439        * not check to ensure all of the {@code LookAndFeelInfos} are
  440        * {@code non-null}, it is strongly recommended that only {@code non-null}
  441        * values are supplied in the {@code infos} array.
  442        *
  443        * @param infos set of <code>LookAndFeelInfo</code> objects specifying
  444        *        the available look and feels
  445        *
  446        * @see #getInstalledLookAndFeels
  447        * @throws NullPointerException if {@code infos} is {@code null}
  448        */
  449       public static void setInstalledLookAndFeels(LookAndFeelInfo[] infos)
  450           throws SecurityException
  451       {
  452           LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length];
  453           System.arraycopy(infos, 0, newInfos, 0, infos.length);
  454           installedLAFs = newInfos;
  455       }
  456   
  457   
  458       /**
  459        * Adds the specified look and feel to the set of available look
  460        * and feels. While this method allows a {@code null} {@code info},
  461        * it is strongly recommended that a {@code non-null} value be used.
  462        *
  463        * @param info a <code>LookAndFeelInfo</code> object that names the
  464        *          look and feel and identifies the class that implements it
  465        * @see #setInstalledLookAndFeels
  466        */
  467       public static void installLookAndFeel(LookAndFeelInfo info) {
  468           LookAndFeelInfo[] infos = getInstalledLookAndFeels();
  469           LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length + 1];
  470           System.arraycopy(infos, 0, newInfos, 0, infos.length);
  471           newInfos[infos.length] = info;
  472           setInstalledLookAndFeels(newInfos);
  473       }
  474   
  475   
  476       /**
  477        * Adds the specified look and feel to the set of available look
  478        * and feels. While this method does not check the
  479        * arguments in any way, it is strongly recommended that {@code
  480        * non-null} values be supplied.
  481        *
  482        * @param name descriptive name of the look and feel
  483        * @param className name of the class that implements the look and feel
  484        * @see #setInstalledLookAndFeels
  485        */
  486       public static void installLookAndFeel(String name, String className) {
  487           installLookAndFeel(new LookAndFeelInfo(name, className));
  488       }
  489   
  490   
  491       /**
  492        * Returns the current look and feel or <code>null</code>.
  493        *
  494        * @return current look and feel, or <code>null</code>
  495        * @see #setLookAndFeel
  496        */
  497       public static LookAndFeel getLookAndFeel() {
  498           maybeInitialize();
  499           return getLAFState().lookAndFeel;
  500       }
  501   
  502   
  503       /**
  504        * Sets the current look and feel to {@code newLookAndFeel}.
  505        * If the current look and feel is {@code non-null} {@code
  506        * uninitialize} is invoked on it. If {@code newLookAndFeel} is
  507        * {@code non-null}, {@code initialize} is invoked on it followed
  508        * by {@code getDefaults}. The defaults returned from {@code
  509        * newLookAndFeel.getDefaults()} replace those of the defaults
  510        * from the previous look and feel. If the {@code newLookAndFeel} is
  511        * {@code null}, the look and feel defaults are set to {@code null}.
  512        * <p>
  513        * A value of {@code null} can be used to set the look and feel
  514        * to {@code null}. As the {@code LookAndFeel} is required for
  515        * most of Swing to function, setting the {@code LookAndFeel} to
  516        * {@code null} is strongly discouraged.
  517        * <p>
  518        * This is a JavaBeans bound property.
  519        *
  520        * @param newLookAndFeel {@code LookAndFeel} to install
  521        * @throws UnsupportedLookAndFeelException if
  522        *          {@code newLookAndFeel} is {@code non-null} and
  523        *          {@code newLookAndFeel.isSupportedLookAndFeel()} returns
  524        *          {@code false}
  525        * @see #getLookAndFeel
  526        */
  527       public static void setLookAndFeel(LookAndFeel newLookAndFeel)
  528           throws UnsupportedLookAndFeelException
  529       {
  530           if ((newLookAndFeel != null) && !newLookAndFeel.isSupportedLookAndFeel()) {
  531               String s = newLookAndFeel.toString() + " not supported on this platform";
  532               throw new UnsupportedLookAndFeelException(s);
  533           }
  534   
  535           LAFState lafState = getLAFState();
  536           LookAndFeel oldLookAndFeel = lafState.lookAndFeel;
  537           if (oldLookAndFeel != null) {
  538               oldLookAndFeel.uninitialize();
  539           }
  540   
  541           lafState.lookAndFeel = newLookAndFeel;
  542           if (newLookAndFeel != null) {
  543               sun.swing.DefaultLookup.setDefaultLookup(null);
  544               newLookAndFeel.initialize();
  545               lafState.setLookAndFeelDefaults(newLookAndFeel.getDefaults());
  546           }
  547           else {
  548               lafState.setLookAndFeelDefaults(null);
  549           }
  550   
  551           SwingPropertyChangeSupport changeSupport = lafState.
  552                                            getPropertyChangeSupport(false);
  553           if (changeSupport != null) {
  554               changeSupport.firePropertyChange("lookAndFeel", oldLookAndFeel,
  555                                                newLookAndFeel);
  556           }
  557       }
  558   
  559   
  560       /**
  561        * Loads the {@code LookAndFeel} specified by the given class
  562        * name, using the current thread's context class loader, and
  563        * passes it to {@code setLookAndFeel(LookAndFeel)}.
  564        *
  565        * @param className  a string specifying the name of the class that implements
  566        *        the look and feel
  567        * @exception ClassNotFoundException if the <code>LookAndFeel</code>
  568        *           class could not be found
  569        * @exception InstantiationException if a new instance of the class
  570        *          couldn't be created
  571        * @exception IllegalAccessException if the class or initializer isn't accessible
  572        * @exception UnsupportedLookAndFeelException if
  573        *          <code>lnf.isSupportedLookAndFeel()</code> is false
  574        * @throws ClassCastException if {@code className} does not identify
  575        *         a class that extends {@code LookAndFeel}
  576        */
  577       public static void setLookAndFeel(String className)
  578           throws ClassNotFoundException,
  579                  InstantiationException,
  580                  IllegalAccessException,
  581                  UnsupportedLookAndFeelException
  582       {
  583           if ("javax.swing.plaf.metal.MetalLookAndFeel".equals(className)) {
  584               // Avoid reflection for the common case of metal.
  585               setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel());
  586           }
  587           else {
  588               Class lnfClass = SwingUtilities.loadSystemClass(className);
  589               setLookAndFeel((LookAndFeel)(lnfClass.newInstance()));
  590           }
  591       }
  592   
  593       /**
  594        * Returns the name of the <code>LookAndFeel</code> class that implements
  595        * the native system look and feel if there is one, otherwise
  596        * the name of the default cross platform <code>LookAndFeel</code>
  597        * class. This value can be overriden by setting the
  598        * <code>swing.systemlaf</code> system property.
  599        *
  600        * @return the <code>String</code> of the <code>LookAndFeel</code>
  601        *          class
  602        *
  603        * @see #setLookAndFeel
  604        * @see #getCrossPlatformLookAndFeelClassName
  605        */
  606       public static String getSystemLookAndFeelClassName() {
  607           String systemLAF = AccessController.doPrivileged(
  608                                new GetPropertyAction("swing.systemlaf"));
  609           if (systemLAF != null) {
  610               return systemLAF;
  611           }
  612           OSInfo.OSType osType = AccessController.doPrivileged(OSInfo.getOSTypeAction());
  613           if (osType == OSInfo.OSType.WINDOWS) {
  614               return "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
  615           } else {
  616               String desktop = AccessController.doPrivileged(new GetPropertyAction("sun.desktop"));
  617               Toolkit toolkit = Toolkit.getDefaultToolkit();
  618               if ("gnome".equals(desktop) &&
  619                       toolkit instanceof SunToolkit &&
  620                       ((SunToolkit) toolkit).isNativeGTKAvailable()) {
  621                   // May be set on Linux and Solaris boxs.
  622                   return "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
  623               }
  624               if (osType == OSInfo.OSType.SOLARIS) {
  625                   return "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
  626               }
  627           }
  628           return getCrossPlatformLookAndFeelClassName();
  629       }
  630   
  631   
  632       /**
  633        * Returns the name of the <code>LookAndFeel</code> class that implements
  634        * the default cross platform look and feel -- the Java
  635        * Look and Feel (JLF).  This value can be overriden by setting the
  636        * <code>swing.crossplatformlaf</code> system property.
  637        *
  638        * @return  a string with the JLF implementation-class
  639        * @see #setLookAndFeel
  640        * @see #getSystemLookAndFeelClassName
  641        */
  642       public static String getCrossPlatformLookAndFeelClassName() {
  643           String laf = (String)AccessController.doPrivileged(
  644                                new GetPropertyAction("swing.crossplatformlaf"));
  645           if (laf != null) {
  646               return laf;
  647           }
  648           return "javax.swing.plaf.metal.MetalLookAndFeel";
  649       }
  650   
  651   
  652       /**
  653        * Returns the defaults. The returned defaults resolve using the
  654        * logic specified in the class documentation.
  655        *
  656        * @return a <code>UIDefaults</code> object containing the default values
  657        */
  658       public static UIDefaults getDefaults() {
  659           maybeInitialize();
  660           return getLAFState().multiUIDefaults;
  661       }
  662   
  663       /**
  664        * Returns a font from the defaults. If the value for {@code key} is
  665        * not a {@code Font}, {@code null} is returned.
  666        *
  667        * @param key  an <code>Object</code> specifying the font
  668        * @return the <code>Font</code> object
  669        * @throws NullPointerException if {@code key} is {@code null}
  670        */
  671       public static Font getFont(Object key) {
  672           return getDefaults().getFont(key);
  673       }
  674   
  675       /**
  676        * Returns a font from the defaults that is appropriate
  677        * for the given locale. If the value for {@code key} is
  678        * not a {@code Font}, {@code null} is returned.
  679        *
  680        * @param key  an <code>Object</code> specifying the font
  681        * @param l the <code>Locale</code> for which the font is desired; refer
  682        *        to {@code UIDefaults} for details on how a {@code null}
  683        *        {@code Locale} is handled
  684        * @return the <code>Font</code> object
  685        * @throws NullPointerException if {@code key} is {@code null}
  686        * @since 1.4
  687        */
  688       public static Font getFont(Object key, Locale l) {
  689           return getDefaults().getFont(key,l);
  690       }
  691   
  692       /**
  693        * Returns a color from the defaults. If the value for {@code key} is
  694        * not a {@code Color}, {@code null} is returned.
  695        *
  696        * @param key  an <code>Object</code> specifying the color
  697        * @return the <code>Color</code> object
  698        * @throws NullPointerException if {@code key} is {@code null}
  699        */
  700       public static Color getColor(Object key) {
  701           return getDefaults().getColor(key);
  702       }
  703   
  704       /**
  705        * Returns a color from the defaults that is appropriate
  706        * for the given locale. If the value for {@code key} is
  707        * not a {@code Color}, {@code null} is returned.
  708        *
  709        * @param key  an <code>Object</code> specifying the color
  710        * @param l the <code>Locale</code> for which the color is desired; refer
  711        *        to {@code UIDefaults} for details on how a {@code null}
  712        *        {@code Locale} is handled
  713        * @return the <code>Color</code> object
  714        * @throws NullPointerException if {@code key} is {@code null}
  715        * @since 1.4
  716        */
  717       public static Color getColor(Object key, Locale l) {
  718           return getDefaults().getColor(key,l);
  719       }
  720   
  721       /**
  722        * Returns an <code>Icon</code> from the defaults. If the value for
  723        * {@code key} is not an {@code Icon}, {@code null} is returned.
  724        *
  725        * @param key  an <code>Object</code> specifying the icon
  726        * @return the <code>Icon</code> object
  727        * @throws NullPointerException if {@code key} is {@code null}
  728        */
  729       public static Icon getIcon(Object key) {
  730           return getDefaults().getIcon(key);
  731       }
  732   
  733       /**
  734        * Returns an <code>Icon</code> from the defaults that is appropriate
  735        * for the given locale. If the value for
  736        * {@code key} is not an {@code Icon}, {@code null} is returned.
  737        *
  738        * @param key  an <code>Object</code> specifying the icon
  739        * @param l the <code>Locale</code> for which the icon is desired; refer
  740        *        to {@code UIDefaults} for details on how a {@code null}
  741        *        {@code Locale} is handled
  742        * @return the <code>Icon</code> object
  743        * @throws NullPointerException if {@code key} is {@code null}
  744        * @since 1.4
  745        */
  746       public static Icon getIcon(Object key, Locale l) {
  747           return getDefaults().getIcon(key,l);
  748       }
  749   
  750       /**
  751        * Returns a border from the defaults. If the value for
  752        * {@code key} is not a {@code Border}, {@code null} is returned.
  753        *
  754        * @param key  an <code>Object</code> specifying the border
  755        * @return the <code>Border</code> object
  756        * @throws NullPointerException if {@code key} is {@code null}
  757        */
  758       public static Border getBorder(Object key) {
  759           return getDefaults().getBorder(key);
  760       }
  761   
  762       /**
  763        * Returns a border from the defaults that is appropriate
  764        * for the given locale.  If the value for
  765        * {@code key} is not a {@code Border}, {@code null} is returned.
  766        *
  767        * @param key  an <code>Object</code> specifying the border
  768        * @param l the <code>Locale</code> for which the border is desired; refer
  769        *        to {@code UIDefaults} for details on how a {@code null}
  770        *        {@code Locale} is handled
  771        * @return the <code>Border</code> object
  772        * @throws NullPointerException if {@code key} is {@code null}
  773        * @since 1.4
  774        */
  775       public static Border getBorder(Object key, Locale l) {
  776           return getDefaults().getBorder(key,l);
  777       }
  778   
  779       /**
  780        * Returns a string from the defaults. If the value for
  781        * {@code key} is not a {@code String}, {@code null} is returned.
  782        *
  783        * @param key  an <code>Object</code> specifying the string
  784        * @return the <code>String</code>
  785        * @throws NullPointerException if {@code key} is {@code null}
  786        */
  787       public static String getString(Object key) {
  788           return getDefaults().getString(key);
  789       }
  790   
  791       /**
  792        * Returns a string from the defaults that is appropriate for the
  793        * given locale.  If the value for
  794        * {@code key} is not a {@code String}, {@code null} is returned.
  795        *
  796        * @param key  an <code>Object</code> specifying the string
  797        * @param l the <code>Locale</code> for which the string is desired; refer
  798        *        to {@code UIDefaults} for details on how a {@code null}
  799        *        {@code Locale} is handled
  800        * @return the <code>String</code>
  801        * @since 1.4
  802        * @throws NullPointerException if {@code key} is {@code null}
  803        */
  804       public static String getString(Object key, Locale l) {
  805           return getDefaults().getString(key,l);
  806       }
  807   
  808       /**
  809        * Returns a string from the defaults that is appropriate for the
  810        * given locale.  If the value for
  811        * {@code key} is not a {@code String}, {@code null} is returned.
  812        *
  813        * @param key  an <code>Object</code> specifying the string
  814        * @param c {@code Component} used to determine the locale;
  815        *          {@code null} implies the default locale as
  816        *          returned by {@code Locale.getDefault()}
  817        * @return the <code>String</code>
  818        * @throws NullPointerException if {@code key} is {@code null}
  819        */
  820       static String getString(Object key, Component c) {
  821           Locale l = (c == null) ? Locale.getDefault() : c.getLocale();
  822           return getString(key, l);
  823       }
  824   
  825       /**
  826        * Returns an integer from the defaults. If the value for
  827        * {@code key} is not an {@code Integer}, or does not exist,
  828        * {@code 0} is returned.
  829        *
  830        * @param key  an <code>Object</code> specifying the int
  831        * @return the int
  832        * @throws NullPointerException if {@code key} is {@code null}
  833        */
  834       public static int getInt(Object key) {
  835           return getDefaults().getInt(key);
  836       }
  837   
  838       /**
  839        * Returns an integer from the defaults that is appropriate
  840        * for the given locale. If the value for
  841        * {@code key} is not an {@code Integer}, or does not exist,
  842        * {@code 0} is returned.
  843        *
  844        * @param key  an <code>Object</code> specifying the int
  845        * @param l the <code>Locale</code> for which the int is desired; refer
  846        *        to {@code UIDefaults} for details on how a {@code null}
  847        *        {@code Locale} is handled
  848        * @return the int
  849        * @throws NullPointerException if {@code key} is {@code null}
  850        * @since 1.4
  851        */
  852       public static int getInt(Object key, Locale l) {
  853           return getDefaults().getInt(key,l);
  854       }
  855   
  856       /**
  857        * Returns a boolean from the defaults which is associated with
  858        * the key value. If the key is not found or the key doesn't represent
  859        * a boolean value then {@code false} is returned.
  860        *
  861        * @param key  an <code>Object</code> specifying the key for the desired boolean value
  862        * @return the boolean value corresponding to the key
  863        * @throws NullPointerException if {@code key} is {@code null}
  864        * @since 1.4
  865        */
  866       public static boolean getBoolean(Object key) {
  867           return getDefaults().getBoolean(key);
  868       }
  869   
  870       /**
  871        * Returns a boolean from the defaults which is associated with
  872        * the key value and the given <code>Locale</code>. If the key is not
  873        * found or the key doesn't represent
  874        * a boolean value then {@code false} will be returned.
  875        *
  876        * @param key  an <code>Object</code> specifying the key for the desired
  877        *             boolean value
  878        * @param l the <code>Locale</code> for which the boolean is desired; refer
  879        *        to {@code UIDefaults} for details on how a {@code null}
  880        *        {@code Locale} is handled
  881        * @return the boolean value corresponding to the key
  882        * @throws NullPointerException if {@code key} is {@code null}
  883        * @since 1.4
  884        */
  885       public static boolean getBoolean(Object key, Locale l) {
  886           return getDefaults().getBoolean(key,l);
  887       }
  888   
  889       /**
  890        * Returns an <code>Insets</code> object from the defaults. If the value
  891        * for {@code key} is not an {@code Insets}, {@code null} is returned.
  892        *
  893        * @param key  an <code>Object</code> specifying the <code>Insets</code> object
  894        * @return the <code>Insets</code> object
  895        * @throws NullPointerException if {@code key} is {@code null}
  896        */
  897       public static Insets getInsets(Object key) {
  898           return getDefaults().getInsets(key);
  899       }
  900   
  901       /**
  902        * Returns an <code>Insets</code> object from the defaults that is
  903        * appropriate for the given locale. If the value
  904        * for {@code key} is not an {@code Insets}, {@code null} is returned.
  905        *
  906        * @param key  an <code>Object</code> specifying the <code>Insets</code> object
  907        * @param l the <code>Locale</code> for which the object is desired; refer
  908        *        to {@code UIDefaults} for details on how a {@code null}
  909        *        {@code Locale} is handled
  910        * @return the <code>Insets</code> object
  911        * @throws NullPointerException if {@code key} is {@code null}
  912        * @since 1.4
  913        */
  914       public static Insets getInsets(Object key, Locale l) {
  915           return getDefaults().getInsets(key,l);
  916       }
  917   
  918       /**
  919        * Returns a dimension from the defaults. If the value
  920        * for {@code key} is not a {@code Dimension}, {@code null} is returned.
  921        *
  922        * @param key  an <code>Object</code> specifying the dimension object
  923        * @return the <code>Dimension</code> object
  924        * @throws NullPointerException if {@code key} is {@code null}
  925        */
  926       public static Dimension getDimension(Object key) {
  927           return getDefaults().getDimension(key);
  928       }
  929   
  930       /**
  931        * Returns a dimension from the defaults that is appropriate
  932        * for the given locale. If the value
  933        * for {@code key} is not a {@code Dimension}, {@code null} is returned.
  934        *
  935        * @param key  an <code>Object</code> specifying the dimension object
  936        * @param l the <code>Locale</code> for which the object is desired; refer
  937        *        to {@code UIDefaults} for details on how a {@code null}
  938        *        {@code Locale} is handled
  939        * @return the <code>Dimension</code> object
  940        * @throws NullPointerException if {@code key} is {@code null}
  941        * @since 1.4
  942        */
  943       public static Dimension getDimension(Object key, Locale l) {
  944           return getDefaults().getDimension(key,l);
  945       }
  946   
  947       /**
  948        * Returns an object from the defaults.
  949        *
  950        * @param key  an <code>Object</code> specifying the desired object
  951        * @return the <code>Object</code>
  952        * @throws NullPointerException if {@code key} is {@code null}
  953        */
  954       public static Object get(Object key) {
  955           return getDefaults().get(key);
  956       }
  957   
  958       /**
  959        * Returns an object from the defaults that is appropriate for
  960        * the given locale.
  961        *
  962        * @param key  an <code>Object</code> specifying the desired object
  963        * @param l the <code>Locale</code> for which the object is desired; refer
  964        *        to {@code UIDefaults} for details on how a {@code null}
  965        *        {@code Locale} is handled
  966        * @return the <code>Object</code>
  967        * @throws NullPointerException if {@code key} is {@code null}
  968        * @since 1.4
  969        */
  970       public static Object get(Object key, Locale l) {
  971           return getDefaults().get(key,l);
  972       }
  973   
  974       /**
  975        * Stores an object in the developer defaults. This is a cover method
  976        * for {@code getDefaults().put(key, value)}. This only effects the
  977        * developer defaults, not the system or look and feel defaults.
  978        *
  979        * @param key    an <code>Object</code> specifying the retrieval key
  980        * @param value  the <code>Object</code> to store; refer to
  981        *               {@code UIDefaults} for details on how {@code null} is
  982        *               handled
  983        * @return the <code>Object</code> returned by {@link UIDefaults#put}
  984        * @throws NullPointerException if {@code key} is {@code null}
  985        * @see UIDefaults#put
  986        */
  987       public static Object put(Object key, Object value) {
  988           return getDefaults().put(key, value);
  989       }
  990   
  991       /**
  992        * Returns the appropriate {@code ComponentUI} implementation for
  993        * {@code target}. Typically, this is a cover for
  994        * {@code getDefaults().getUI(target)}. However, if an auxiliary
  995        * look and feel has been installed, this first invokes
  996        * {@code getUI(target)} on the multiplexing look and feel's
  997        * defaults, and returns that value if it is {@code non-null}.
  998        *
  999        * @param target the <code>JComponent</code> to return the
 1000        *        {@code ComponentUI} for
 1001        * @return the <code>ComponentUI</code> object for {@code target}
 1002        * @throws NullPointerException if {@code target} is {@code null}
 1003        * @see UIDefaults#getUI
 1004        */
 1005       public static ComponentUI getUI(JComponent target) {
 1006           maybeInitialize();
 1007           ComponentUI ui = null;
 1008           LookAndFeel multiLAF = getLAFState().multiLookAndFeel;
 1009           if (multiLAF != null) {
 1010               // This can return null if the multiplexing look and feel
 1011               // doesn't support a particular UI.
 1012               ui = multiLAF.getDefaults().getUI(target);
 1013           }
 1014           if (ui == null) {
 1015               ui = getDefaults().getUI(target);
 1016           }
 1017           return ui;
 1018       }
 1019   
 1020   
 1021       /**
 1022        * Returns the {@code UIDefaults} from the current look and feel,
 1023        * that were obtained at the time the look and feel was installed.
 1024        * <p>
 1025        * In general, developers should use the {@code UIDefaults} returned from
 1026        * {@code getDefaults()}. As the current look and feel may expect
 1027        * certain values to exist, altering the {@code UIDefaults} returned
 1028        * from this method could have unexpected results.
 1029        *
 1030        * @return <code>UIDefaults</code> from the current look and feel
 1031        * @see #getDefaults
 1032        * @see #setLookAndFeel(LookAndFeel)
 1033        * @see LookAndFeel#getDefaults
 1034        */
 1035       public static UIDefaults getLookAndFeelDefaults() {
 1036           maybeInitialize();
 1037           return getLAFState().getLookAndFeelDefaults();
 1038       }
 1039   
 1040       /**
 1041        * Finds the Multiplexing <code>LookAndFeel</code>.
 1042        */
 1043       private static LookAndFeel getMultiLookAndFeel() {
 1044           LookAndFeel multiLookAndFeel = getLAFState().multiLookAndFeel;
 1045           if (multiLookAndFeel == null) {
 1046               String defaultName = "javax.swing.plaf.multi.MultiLookAndFeel";
 1047               String className = getLAFState().swingProps.getProperty(multiplexingLAFKey, defaultName);
 1048               try {
 1049                   Class lnfClass = SwingUtilities.loadSystemClass(className);
 1050                   multiLookAndFeel = (LookAndFeel)lnfClass.newInstance();
 1051               } catch (Exception exc) {
 1052                   System.err.println("UIManager: failed loading " + className);
 1053               }
 1054           }
 1055           return multiLookAndFeel;
 1056       }
 1057   
 1058       /**
 1059        * Adds a <code>LookAndFeel</code> to the list of auxiliary look and feels.
 1060        * The auxiliary look and feels tell the multiplexing look and feel what
 1061        * other <code>LookAndFeel</code> classes for a component instance are to be used
 1062        * in addition to the default <code>LookAndFeel</code> class when creating a
 1063        * multiplexing UI.  The change will only take effect when a new
 1064        * UI class is created or when the default look and feel is changed
 1065        * on a component instance.
 1066        * <p>Note these are not the same as the installed look and feels.
 1067        *
 1068        * @param laf the <code>LookAndFeel</code> object
 1069        * @see #removeAuxiliaryLookAndFeel
 1070        * @see #setLookAndFeel
 1071        * @see #getAuxiliaryLookAndFeels
 1072        * @see #getInstalledLookAndFeels
 1073        */
 1074       static public void addAuxiliaryLookAndFeel(LookAndFeel laf) {
 1075           maybeInitialize();
 1076   
 1077           if (!laf.isSupportedLookAndFeel()) {
 1078               // Ideally we would throw an exception here, but it's too late
 1079               // for that.
 1080               return;
 1081           }
 1082           Vector v = getLAFState().auxLookAndFeels;
 1083           if (v == null) {
 1084               v = new Vector();
 1085           }
 1086   
 1087           if (!v.contains(laf)) {
 1088               v.addElement(laf);
 1089               laf.initialize();
 1090               getLAFState().auxLookAndFeels = v;
 1091   
 1092               if (getLAFState().multiLookAndFeel == null) {
 1093                   getLAFState().multiLookAndFeel = getMultiLookAndFeel();
 1094               }
 1095           }
 1096       }
 1097   
 1098       /**
 1099        * Removes a <code>LookAndFeel</code> from the list of auxiliary look and feels.
 1100        * The auxiliary look and feels tell the multiplexing look and feel what
 1101        * other <code>LookAndFeel</code> classes for a component instance are to be used
 1102        * in addition to the default <code>LookAndFeel</code> class when creating a
 1103        * multiplexing UI.  The change will only take effect when a new
 1104        * UI class is created or when the default look and feel is changed
 1105        * on a component instance.
 1106        * <p>Note these are not the same as the installed look and feels.
 1107        * @return true if the <code>LookAndFeel</code> was removed from the list
 1108        * @see #removeAuxiliaryLookAndFeel
 1109        * @see #getAuxiliaryLookAndFeels
 1110        * @see #setLookAndFeel
 1111        * @see #getInstalledLookAndFeels
 1112        */
 1113       static public boolean removeAuxiliaryLookAndFeel(LookAndFeel laf) {
 1114           maybeInitialize();
 1115   
 1116           boolean result;
 1117   
 1118           Vector v = getLAFState().auxLookAndFeels;
 1119           if ((v == null) || (v.size() == 0)) {
 1120               return false;
 1121           }
 1122   
 1123           result = v.removeElement(laf);
 1124           if (result) {
 1125               if (v.size() == 0) {
 1126                   getLAFState().auxLookAndFeels = null;
 1127                   getLAFState().multiLookAndFeel = null;
 1128               } else {
 1129                   getLAFState().auxLookAndFeels = v;
 1130               }
 1131           }
 1132           laf.uninitialize();
 1133   
 1134           return result;
 1135       }
 1136   
 1137       /**
 1138        * Returns the list of auxiliary look and feels (can be <code>null</code>).
 1139        * The auxiliary look and feels tell the multiplexing look and feel what
 1140        * other <code>LookAndFeel</code> classes for a component instance are
 1141        * to be used in addition to the default LookAndFeel class when creating a
 1142        * multiplexing UI.
 1143        * <p>Note these are not the same as the installed look and feels.
 1144        *
 1145        * @return list of auxiliary <code>LookAndFeel</code>s or <code>null</code>
 1146        * @see #addAuxiliaryLookAndFeel
 1147        * @see #removeAuxiliaryLookAndFeel
 1148        * @see #setLookAndFeel
 1149        * @see #getInstalledLookAndFeels
 1150        */
 1151       static public LookAndFeel[] getAuxiliaryLookAndFeels() {
 1152           maybeInitialize();
 1153   
 1154           Vector v = getLAFState().auxLookAndFeels;
 1155           if ((v == null) || (v.size() == 0)) {
 1156               return null;
 1157           }
 1158           else {
 1159               LookAndFeel[] rv = new LookAndFeel[v.size()];
 1160               for (int i = 0; i < rv.length; i++) {
 1161                   rv[i] = (LookAndFeel)v.elementAt(i);
 1162               }
 1163               return rv;
 1164           }
 1165       }
 1166   
 1167   
 1168       /**
 1169        * Adds a <code>PropertyChangeListener</code> to the listener list.
 1170        * The listener is registered for all properties.
 1171        *
 1172        * @param listener  the <code>PropertyChangeListener</code> to be added
 1173        * @see java.beans.PropertyChangeSupport
 1174        */
 1175       public static void addPropertyChangeListener(PropertyChangeListener listener)
 1176       {
 1177           synchronized (classLock) {
 1178               getLAFState().getPropertyChangeSupport(true).
 1179                                addPropertyChangeListener(listener);
 1180           }
 1181       }
 1182   
 1183   
 1184       /**
 1185        * Removes a <code>PropertyChangeListener</code> from the listener list.
 1186        * This removes a <code>PropertyChangeListener</code> that was registered
 1187        * for all properties.
 1188        *
 1189        * @param listener  the <code>PropertyChangeListener</code> to be removed
 1190        * @see java.beans.PropertyChangeSupport
 1191        */
 1192       public static void removePropertyChangeListener(PropertyChangeListener listener)
 1193       {
 1194           synchronized (classLock) {
 1195               getLAFState().getPropertyChangeSupport(true).
 1196                             removePropertyChangeListener(listener);
 1197           }
 1198       }
 1199   
 1200   
 1201       /**
 1202        * Returns an array of all the <code>PropertyChangeListener</code>s added
 1203        * to this UIManager with addPropertyChangeListener().
 1204        *
 1205        * @return all of the <code>PropertyChangeListener</code>s added or an empty
 1206        *         array if no listeners have been added
 1207        * @since 1.4
 1208        */
 1209       public static PropertyChangeListener[] getPropertyChangeListeners() {
 1210           synchronized(classLock) {
 1211               return getLAFState().getPropertyChangeSupport(true).
 1212                         getPropertyChangeListeners();
 1213           }
 1214       }
 1215   
 1216       private static Properties loadSwingProperties()
 1217       {
 1218           /* Don't bother checking for Swing properties if untrusted, as
 1219            * there's no way to look them up without triggering SecurityExceptions.
 1220            */
 1221           if (UIManager.class.getClassLoader() != null) {
 1222               return new Properties();
 1223           }
 1224           else {
 1225               final Properties props = new Properties();
 1226   
 1227               java.security.AccessController.doPrivileged(
 1228                   new java.security.PrivilegedAction() {
 1229                   public Object run() {
 1230                       try {
 1231                           File file = new File(makeSwingPropertiesFilename());
 1232   
 1233                           if (file.exists()) {
 1234                               // InputStream has been buffered in Properties
 1235                               // class
 1236                               FileInputStream ins = new FileInputStream(file);
 1237                               props.load(ins);
 1238                               ins.close();
 1239                           }
 1240                       }
 1241                       catch (Exception e) {
 1242                           // No such file, or file is otherwise non-readable.
 1243                       }
 1244   
 1245                       // Check whether any properties were overridden at the
 1246                       // command line.
 1247                       checkProperty(props, defaultLAFKey);
 1248                       checkProperty(props, auxiliaryLAFsKey);
 1249                       checkProperty(props, multiplexingLAFKey);
 1250                       checkProperty(props, installedLAFsKey);
 1251                       checkProperty(props, disableMnemonicKey);
 1252                       // Don't care about return value.
 1253                       return null;
 1254                   }
 1255               });
 1256               return props;
 1257           }
 1258       }
 1259   
 1260       private static void checkProperty(Properties props, String key) {
 1261           // No need to do catch the SecurityException here, this runs
 1262           // in a doPrivileged.
 1263           String value = System.getProperty(key);
 1264           if (value != null) {
 1265               props.put(key, value);
 1266           }
 1267       }
 1268   
 1269   
 1270       /**
 1271        * If a swing.properties file exist and it has a swing.installedlafs property
 1272        * then initialize the <code>installedLAFs</code> field.
 1273        *
 1274        * @see #getInstalledLookAndFeels
 1275        */
 1276       private static void initializeInstalledLAFs(Properties swingProps)
 1277       {
 1278           String ilafsString = swingProps.getProperty(installedLAFsKey);
 1279           if (ilafsString == null) {
 1280               return;
 1281           }
 1282   
 1283           /* Create a vector that contains the value of the swing.installedlafs
 1284            * property.  For example given "swing.installedlafs=motif,windows"
 1285            * lafs = {"motif", "windows"}.
 1286            */
 1287           Vector lafs = new Vector();
 1288           StringTokenizer st = new StringTokenizer(ilafsString, ",", false);
 1289           while (st.hasMoreTokens()) {
 1290               lafs.addElement(st.nextToken());
 1291           }
 1292   
 1293           /* Look up the name and class for each name in the "swing.installedlafs"
 1294            * list.  If they both exist then add a LookAndFeelInfo to
 1295            * the installedLafs array.
 1296            */
 1297           Vector ilafs = new Vector(lafs.size());
 1298           for(int i = 0; i < lafs.size(); i++) {
 1299               String laf = (String)lafs.elementAt(i);
 1300               String name = swingProps.getProperty(makeInstalledLAFKey(laf, "name"), laf);
 1301               String cls = swingProps.getProperty(makeInstalledLAFKey(laf, "class"));
 1302               if (cls != null) {
 1303                   ilafs.addElement(new LookAndFeelInfo(name, cls));
 1304               }
 1305           }
 1306   
 1307           installedLAFs = new LookAndFeelInfo[ilafs.size()];
 1308           for(int i = 0; i < ilafs.size(); i++) {
 1309               installedLAFs[i] = (LookAndFeelInfo)(ilafs.elementAt(i));
 1310           }
 1311       }
 1312   
 1313   
 1314       /**
 1315        * If the user has specified a default look and feel, use that.
 1316        * Otherwise use the look and feel that's native to this platform.
 1317        * If this code is called after the application has explicitly
 1318        * set it's look and feel, do nothing.
 1319        *
 1320        * @see #maybeInitialize
 1321        */
 1322       private static void initializeDefaultLAF(Properties swingProps)
 1323       {
 1324           if (getLAFState().lookAndFeel != null) {
 1325               return;
 1326           }
 1327   
 1328           String metalLnf = getCrossPlatformLookAndFeelClassName();
 1329           String lnfDefault = metalLnf;
 1330   
 1331           String lnfName = "<undefined>" ;
 1332           try {
 1333               lnfName = swingProps.getProperty(defaultLAFKey, lnfDefault);
 1334               setLookAndFeel(lnfName);
 1335           } catch (Exception e) {
 1336               try {
 1337                   lnfName = swingProps.getProperty(defaultLAFKey, metalLnf);
 1338                   setLookAndFeel(lnfName);
 1339               } catch (Exception e2) {
 1340                   throw new Error("can't load " + lnfName);
 1341               }
 1342           }
 1343       }
 1344   
 1345   
 1346       private static void initializeAuxiliaryLAFs(Properties swingProps)
 1347       {
 1348           String auxLookAndFeelNames = swingProps.getProperty(auxiliaryLAFsKey);
 1349           if (auxLookAndFeelNames == null) {
 1350               return;
 1351           }
 1352   
 1353           Vector auxLookAndFeels = new Vector();
 1354   
 1355           StringTokenizer p = new StringTokenizer(auxLookAndFeelNames,",");
 1356           String factoryName;
 1357   
 1358           /* Try to load each LookAndFeel subclass in the list.
 1359            */
 1360   
 1361           while (p.hasMoreTokens()) {
 1362               String className = p.nextToken();
 1363               try {
 1364                   Class lnfClass = SwingUtilities.loadSystemClass(className);
 1365                   LookAndFeel newLAF = (LookAndFeel)lnfClass.newInstance();
 1366                   newLAF.initialize();
 1367                   auxLookAndFeels.addElement(newLAF);
 1368               }
 1369               catch (Exception e) {
 1370                   System.err.println("UIManager: failed loading auxiliary look and feel " + className);
 1371               }
 1372           }
 1373   
 1374           /* If there were problems and no auxiliary look and feels were
 1375            * loaded, make sure we reset auxLookAndFeels to null.
 1376            * Otherwise, we are going to use the MultiLookAndFeel to get
 1377            * all component UI's, so we need to load it now.
 1378            */
 1379           if (auxLookAndFeels.size() == 0) {
 1380               auxLookAndFeels = null;
 1381           }
 1382           else {
 1383               getLAFState().multiLookAndFeel = getMultiLookAndFeel();
 1384               if (getLAFState().multiLookAndFeel == null) {
 1385                   auxLookAndFeels = null;
 1386               }
 1387           }
 1388   
 1389           getLAFState().auxLookAndFeels = auxLookAndFeels;
 1390       }
 1391   
 1392   
 1393       private static void initializeSystemDefaults(Properties swingProps) {
 1394           getLAFState().swingProps = swingProps;
 1395       }
 1396   
 1397   
 1398       /*
 1399        * This method is called before any code that depends on the
 1400        * <code>AppContext</code> specific LAFState object runs.  When the AppContext
 1401        * corresponds to a set of applets it's possible for this method
 1402        * to be re-entered, which is why we grab a lock before calling
 1403        * initialize().
 1404        */
 1405       private static void maybeInitialize() {
 1406           synchronized (classLock) {
 1407               if (!getLAFState().initialized) {
 1408                   getLAFState().initialized = true;
 1409                   initialize();
 1410               }
 1411           }
 1412       }
 1413   
 1414   
 1415       /*
 1416        * Only called by maybeInitialize().
 1417        */
 1418       private static void initialize() {
 1419           Properties swingProps = loadSwingProperties();
 1420           initializeSystemDefaults(swingProps);
 1421           initializeDefaultLAF(swingProps);
 1422           initializeAuxiliaryLAFs(swingProps);
 1423           initializeInstalledLAFs(swingProps);
 1424   
 1425           // Enable the Swing default LayoutManager.
 1426           String toolkitName = Toolkit.getDefaultToolkit().getClass().getName();
 1427           // don't set default policy if this is XAWT.
 1428           if (!"sun.awt.X11.XToolkit".equals(toolkitName)) {
 1429               if (FocusManager.isFocusManagerEnabled()) {
 1430                   KeyboardFocusManager.getCurrentKeyboardFocusManager().
 1431                       setDefaultFocusTraversalPolicy(
 1432                           new LayoutFocusTraversalPolicy());
 1433               }
 1434           }
 1435   
 1436           // Install Swing's PaintEventDispatcher
 1437           if (RepaintManager.HANDLE_TOP_LEVEL_PAINT) {
 1438               sun.awt.PaintEventDispatcher.setPaintEventDispatcher(
 1439                                           new SwingPaintEventDispatcher());
 1440           }
 1441           // Install a hook that will be invoked if no one consumes the
 1442           // KeyEvent.  If the source isn't a JComponent this will process
 1443           // key bindings, if the source is a JComponent it implies that
 1444           // processKeyEvent was already invoked and thus no need to process
 1445           // the bindings again, unless the Component is disabled, in which
 1446           // case KeyEvents will no longer be dispatched to it so that we
 1447           // handle it here.
 1448           KeyboardFocusManager.getCurrentKeyboardFocusManager().
 1449                   addKeyEventPostProcessor(new KeyEventPostProcessor() {
 1450                       public boolean postProcessKeyEvent(KeyEvent e) {
 1451                           Component c = e.getComponent();
 1452   
 1453                           if ((!(c instanceof JComponent) ||
 1454                                (c != null && !((JComponent)c).isEnabled())) &&
 1455                                   JComponent.KeyboardState.shouldProcess(e) &&
 1456                                   SwingUtilities.processKeyBindings(e)) {
 1457                               e.consume();
 1458                               return true;
 1459                           }
 1460                           return false;
 1461                       }
 1462                   });
 1463           try {
 1464               Method setRequestFocusControllerM = java.security.AccessController.doPrivileged(
 1465                       new java.security.PrivilegedExceptionAction<Method>() {
 1466                           public Method run() throws Exception {
 1467                               Method method =
 1468                               Component.class.getDeclaredMethod("setRequestFocusController",
 1469                                                                 sun.awt.RequestFocusController.class);
 1470                               method.setAccessible(true);
 1471                               return method;
 1472                           }
 1473                       });
 1474               setRequestFocusControllerM.invoke(null, JComponent.focusController);
 1475           } catch (Exception e) {
 1476               // perhaps we should log this
 1477               assert false;
 1478           }
 1479       }
 1480   }

Save This Page
Home » openjdk-7 » javax » swing » [javadoc | source]