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