       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      * @throws NullPointerException if {@code className} is {@code null}
     619      */
     620     @SuppressWarnings("deprecation")
     621     public static void setLookAndFeel(String className)
     622         throws ClassNotFoundException,
     623                InstantiationException,
     624                IllegalAccessException,
     625                UnsupportedLookAndFeelException
     626     {
     627         if ("javax.swing.plaf.metal.MetalLookAndFeel".equals(className)) {
     628             // Avoid reflection for the common case of metal.
     629             setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel());
     630         }
     631         else {
     632             Class<?> lnfClass = SwingUtilities.loadSystemClass(className);
     633             setLookAndFeel((LookAndFeel)(lnfClass.newInstance()));
     634         }
     635     }
     636
     637     /**
     638      * Returns the name of the <code>LookAndFeel</code> class that implements
     639      * the native system look and feel if there is one, otherwise
     640      * the name of the default cross platform <code>LookAndFeel</code>
     641      * class. This value can be overriden by setting the
     642      * <code>swing.systemlaf</code> system property.
     643      *
     644      * @return the <code>String</code> of the <code>LookAndFeel</code>
     645      *          class
     646      *
     647      * @see #setLookAndFeel
     648      * @see #getCrossPlatformLookAndFeelClassName
     649      */
     650     public static String getSystemLookAndFeelClassName() {
     651         String systemLAF = AccessController.doPrivileged(
     652                              new GetPropertyAction("swing.systemlaf"));
     653         if (systemLAF != null) {
     654             return systemLAF;
     655         }
     656         OSInfo.OSType osType = AccessController.doPrivileged(OSInfo.getOSTypeAction());
     657         if (osType == OSInfo.OSType.WINDOWS) {
     658             return "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
     659         } else {
     660             String desktop = AccessController.doPrivileged(new GetPropertyAction("sun.desktop"));
     661             Toolkit toolkit = Toolkit.getDefaultToolkit();
     662             if ("gnome".equals(desktop) &&
     663                     toolkit instanceof SunToolkit &&
     664                     ((SunToolkit) toolkit).isNativeGTKAvailable()) {
     665                 // May be set on Linux and Solaris boxs.
     666                 return "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
     667             }
     668             if (osType == OSInfo.OSType.MACOSX) {
     669                 if (toolkit.getClass() .getName()
     670                                        .equals("sun.lwawt.macosx.LWCToolkit")) {
     671                     return "com.apple.laf.AquaLookAndFeel";
     672                 }
     673             }
     674             if (osType == OSInfo.OSType.SOLARIS) {
     675                 return "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
     676             }
     677         }
     678         return getCrossPlatformLookAndFeelClassName();
     679     }
     680
     681
     682     /**
     683      * Returns the name of the <code>LookAndFeel</code> class that implements
     684      * the default cross platform look and feel -- the Java
     685      * Look and Feel (JLF).  This value can be overriden by setting the
     686      * <code>swing.crossplatformlaf</code> system property.
     687      *
     688      * @return  a string with the JLF implementation-class
     689      * @see #setLookAndFeel
     690      * @see #getSystemLookAndFeelClassName
     691      */
     692     public static String getCrossPlatformLookAndFeelClassName() {
     693         String laf = AccessController.doPrivileged(
     694                              new GetPropertyAction("swing.crossplatformlaf"));
     695         if (laf != null) {
     696             return laf;
     697         }
     698         return "javax.swing.plaf.metal.MetalLookAndFeel";
     699     }
     700
     701
     702     /**
     703      * Returns the defaults. The returned defaults resolve using the
     704      * logic specified in the class documentation.
     705      *
     706      * @return a <code>UIDefaults</code> object containing the default values
     707      */
     708     public static UIDefaults getDefaults() {
     709         maybeInitialize();
     710         return getLAFState().multiUIDefaults;
     711     }
     712
     713     /**
     714      * Returns a font from the defaults. If the value for {@code key} is
     715      * not a {@code Font}, {@code null} is returned.
     716      *
     717      * @param key  an <code>Object</code> specifying the font
     718      * @return the <code>Font</code> object
     719      * @throws NullPointerException if {@code key} is {@code null}
     720      */
     721     public static Font getFont(Object key) {
     722         return getDefaults().getFont(key);
     723     }
     724
     725     /**
     726      * Returns a font from the defaults that is appropriate
     727      * for the given locale. If the value for {@code key} is
     728      * not a {@code Font}, {@code null} is returned.
     729      *
     730      * @param key  an <code>Object</code> specifying the font
     731      * @param l the <code>Locale</code> for which the font is desired; refer
     732      *        to {@code UIDefaults} for details on how a {@code null}
     733      *        {@code Locale} is handled
     734      * @return the <code>Font</code> object
     735      * @throws NullPointerException if {@code key} is {@code null}
     736      * @since 1.4
     737      */
     738     public static Font getFont(Object key, Locale l) {
     739         return getDefaults().getFont(key,l);
     740     }
     741
     742     /**
     743      * Returns a color from the defaults. If the value for {@code key} is
     744      * not a {@code Color}, {@code null} is returned.
     745      *
     746      * @param key  an <code>Object</code> specifying the color
     747      * @return the <code>Color</code> object
     748      * @throws NullPointerException if {@code key} is {@code null}
     749      */
     750     public static Color getColor(Object key) {
     751         return getDefaults().getColor(key);
     752     }
     753
     754     /**
     755      * Returns a color from the defaults that is appropriate
     756      * for the given locale. If the value for {@code key} is
     757      * not a {@code Color}, {@code null} is returned.
     758      *
     759      * @param key  an <code>Object</code> specifying the color
     760      * @param l the <code>Locale</code> for which the color is desired; refer
     761      *        to {@code UIDefaults} for details on how a {@code null}
     762      *        {@code Locale} is handled
     763      * @return the <code>Color</code> object
     764      * @throws NullPointerException if {@code key} is {@code null}
     765      * @since 1.4
     766      */
     767     public static Color getColor(Object key, Locale l) {
     768         return getDefaults().getColor(key,l);
     769     }
     770
     771     /**
     772      * Returns an <code>Icon</code> from the defaults. If the value for
     773      * {@code key} is not an {@code Icon}, {@code null} is returned.
     774      *
     775      * @param key  an <code>Object</code> specifying the icon
     776      * @return the <code>Icon</code> object
     777      * @throws NullPointerException if {@code key} is {@code null}
     778      */
     779     public static Icon getIcon(Object key) {
     780         return getDefaults().getIcon(key);
     781     }
     782
     783     /**
     784      * Returns an <code>Icon</code> from the defaults that is appropriate
     785      * for the given locale. If the value for
     786      * {@code key} is not an {@code Icon}, {@code null} is returned.
     787      *
     788      * @param key  an <code>Object</code> specifying the icon
     789      * @param l the <code>Locale</code> for which the icon is desired; refer
     790      *        to {@code UIDefaults} for details on how a {@code null}
     791      *        {@code Locale} is handled
     792      * @return the <code>Icon</code> object
     793      * @throws NullPointerException if {@code key} is {@code null}
     794      * @since 1.4
     795      */
     796     public static Icon getIcon(Object key, Locale l) {
     797         return getDefaults().getIcon(key,l);
     798     }
     799
     800     /**
     801      * Returns a border from the defaults. If the value for
     802      * {@code key} is not a {@code Border}, {@code null} is returned.
     803      *
     804      * @param key  an <code>Object</code> specifying the border
     805      * @return the <code>Border</code> object
     806      * @throws NullPointerException if {@code key} is {@code null}
     807      */
     808     public static Border getBorder(Object key) {
     809         return getDefaults().getBorder(key);
     810     }
     811
     812     /**
     813      * Returns a border from the defaults that is appropriate
     814      * for the given locale.  If the value for
     815      * {@code key} is not a {@code Border}, {@code null} is returned.
     816      *
     817      * @param key  an <code>Object</code> specifying the border
     818      * @param l the <code>Locale</code> for which the border is desired; refer
     819      *        to {@code UIDefaults} for details on how a {@code null}
     820      *        {@code Locale} is handled
     821      * @return the <code>Border</code> object
     822      * @throws NullPointerException if {@code key} is {@code null}
     823      * @since 1.4
     824      */
     825     public static Border getBorder(Object key, Locale l) {
     826         return getDefaults().getBorder(key,l);
     827     }
     828
     829     /**
     830      * Returns a string from the defaults. If the value for
     831      * {@code key} is not a {@code String}, {@code null} is returned.
     832      *
     833      * @param key  an <code>Object</code> specifying the string
     834      * @return the <code>String</code>
     835      * @throws NullPointerException if {@code key} is {@code null}
     836      */
     837     public static String getString(Object key) {
     838         return getDefaults().getString(key);
     839     }
     840
     841     /**
     842      * Returns a string from the defaults that is appropriate for the
     843      * given locale.  If the value for
     844      * {@code key} is not a {@code String}, {@code null} is returned.
     845      *
     846      * @param key  an <code>Object</code> specifying the string
     847      * @param l the <code>Locale</code> for which the string is desired; refer
     848      *        to {@code UIDefaults} for details on how a {@code null}
     849      *        {@code Locale} is handled
     850      * @return the <code>String</code>
     851      * @since 1.4
     852      * @throws NullPointerException if {@code key} is {@code null}
     853      */
     854     public static String getString(Object key, Locale l) {
     855         return getDefaults().getString(key,l);
     856     }
     857
     858     /**
     859      * Returns a string from the defaults that is appropriate for the
     860      * given locale.  If the value for
     861      * {@code key} is not a {@code String}, {@code null} is returned.
     862      *
     863      * @param key  an <code>Object</code> specifying the string
     864      * @param c {@code Component} used to determine the locale;
     865      *          {@code null} implies the default locale as
     866      *          returned by {@code Locale.getDefault()}
     867      * @return the <code>String</code>
     868      * @throws NullPointerException if {@code key} is {@code null}
     869      */
     870     static String getString(Object key, Component c) {
     871         Locale l = (c == null) ? Locale.getDefault() : c.getLocale();
     872         return getString(key, l);
     873     }
     874
     875     /**
     876      * Returns an integer from the defaults. If the value for
     877      * {@code key} is not an {@code Integer}, or does not exist,
     878      * {@code 0} is returned.
     879      *
     880      * @param key  an <code>Object</code> specifying the int
     881      * @return the int
     882      * @throws NullPointerException if {@code key} is {@code null}
     883      */
     884     public static int getInt(Object key) {
     885         return getDefaults().getInt(key);
     886     }
     887
     888     /**
     889      * Returns an integer from the defaults that is appropriate
     890      * for the given locale. If the value for
     891      * {@code key} is not an {@code Integer}, or does not exist,
     892      * {@code 0} is returned.
     893      *
     894      * @param key  an <code>Object</code> specifying the int
     895      * @param l the <code>Locale</code> for which the int is desired; refer
     896      *        to {@code UIDefaults} for details on how a {@code null}
     897      *        {@code Locale} is handled
     898      * @return the int
     899      * @throws NullPointerException if {@code key} is {@code null}
     900      * @since 1.4
     901      */
     902     public static int getInt(Object key, Locale l) {
     903         return getDefaults().getInt(key,l);
     904     }
     905
     906     /**
     907      * Returns a boolean from the defaults which is associated with
     908      * the key value. If the key is not found or the key doesn't represent
     909      * a boolean value then {@code false} is returned.
     910      *
     911      * @param key  an <code>Object</code> specifying the key for the desired boolean value
     912      * @return the boolean value corresponding to the key
     913      * @throws NullPointerException if {@code key} is {@code null}
     914      * @since 1.4
     915      */
     916     public static boolean getBoolean(Object key) {
     917         return getDefaults().getBoolean(key);
     918     }
     919
     920     /**
     921      * Returns a boolean from the defaults which is associated with
     922      * the key value and the given <code>Locale</code>. If the key is not
     923      * found or the key doesn't represent
     924      * a boolean value then {@code false} will be returned.
     925      *
     926      * @param key  an <code>Object</code> specifying the key for the desired
     927      *             boolean value
     928      * @param l the <code>Locale</code> for which the boolean is desired; refer
     929      *        to {@code UIDefaults} for details on how a {@code null}
     930      *        {@code Locale} is handled
     931      * @return the boolean value corresponding to the key
     932      * @throws NullPointerException if {@code key} is {@code null}
     933      * @since 1.4
     934      */
     935     public static boolean getBoolean(Object key, Locale l) {
     936         return getDefaults().getBoolean(key,l);
     937     }
     938
     939     /**
     940      * Returns an <code>Insets</code> object from the defaults. If the value
     941      * for {@code key} is not an {@code Insets}, {@code null} is returned.
     942      *
     943      * @param key  an <code>Object</code> specifying the <code>Insets</code> object
     944      * @return the <code>Insets</code> object
     945      * @throws NullPointerException if {@code key} is {@code null}
     946      */
     947     public static Insets getInsets(Object key) {
     948         return getDefaults().getInsets(key);
     949     }
     950
     951     /**
     952      * Returns an <code>Insets</code> object from the defaults that is
     953      * appropriate for the given locale. If the value
     954      * for {@code key} is not an {@code Insets}, {@code null} is returned.
     955      *
     956      * @param key  an <code>Object</code> specifying the <code>Insets</code> object
     957      * @param l the <code>Locale</code> for which the object is desired; refer
     958      *        to {@code UIDefaults} for details on how a {@code null}
     959      *        {@code Locale} is handled
     960      * @return the <code>Insets</code> object
     961      * @throws NullPointerException if {@code key} is {@code null}
     962      * @since 1.4
     963      */
     964     public static Insets getInsets(Object key, Locale l) {
     965         return getDefaults().getInsets(key,l);
     966     }
     967
     968     /**
     969      * Returns a dimension from the defaults. If the value
     970      * for {@code key} is not a {@code Dimension}, {@code null} is returned.
     971      *
     972      * @param key  an <code>Object</code> specifying the dimension object
     973      * @return the <code>Dimension</code> object
     974      * @throws NullPointerException if {@code key} is {@code null}
     975      */
     976     public static Dimension getDimension(Object key) {
     977         return getDefaults().getDimension(key);
     978     }
     979
     980     /**
     981      * Returns a dimension from the defaults that is appropriate
     982      * for the given locale. If the value
     983      * for {@code key} is not a {@code Dimension}, {@code null} is returned.
     984      *
     985      * @param key  an <code>Object</code> specifying the dimension object
     986      * @param l the <code>Locale</code> for which the object is desired; refer
     987      *        to {@code UIDefaults} for details on how a {@code null}
     988      *        {@code Locale} is handled
     989      * @return the <code>Dimension</code> object
     990      * @throws NullPointerException if {@code key} is {@code null}
     991      * @since 1.4
     992      */
     993     public static Dimension getDimension(Object key, Locale l) {
     994         return getDefaults().getDimension(key,l);
     995     }
     996
     997     /**
     998      * Returns an object from the defaults.
     999      *
    1000      * @param key  an <code>Object</code> specifying the desired object
    1001      * @return the <code>Object</code>
    1002      * @throws NullPointerException if {@code key} is {@code null}
    1003      */
    1004     public static Object get(Object key) {
    1005         return getDefaults().get(key);
    1006     }
    1007
    1008     /**
    1009      * Returns an object from the defaults that is appropriate for
    1010      * the given locale.
    1011      *
    1012      * @param key  an <code>Object</code> specifying the desired object
    1013      * @param l the <code>Locale</code> for which the object is desired; refer
    1014      *        to {@code UIDefaults} for details on how a {@code null}
    1015      *        {@code Locale} is handled
    1016      * @return the <code>Object</code>
    1017      * @throws NullPointerException if {@code key} is {@code null}
    1018      * @since 1.4
    1019      */
    1020     public static Object get(Object key, Locale l) {
    1021         return getDefaults().get(key,l);
    1022     }
    1023
    1024     /**
    1025      * Stores an object in the developer defaults. This is a cover method
    1026      * for {@code getDefaults().put(key, value)}. This only effects the
    1027      * developer defaults, not the system or look and feel defaults.
    1028      *
    1029      * @param key    an <code>Object</code> specifying the retrieval key
    1030      * @param value  the <code>Object</code> to store; refer to
    1031      *               {@code UIDefaults} for details on how {@code null} is
    1032      *               handled
    1033      * @return the <code>Object</code> returned by {@link UIDefaults#put}
    1034      * @throws NullPointerException if {@code key} is {@code null}
    1035      * @see UIDefaults#put
    1036      */
    1037     public static Object put(Object key, Object value) {
    1038         return getDefaults().put(key, value);
    1039     }
    1040
    1041     /**
    1042      * Returns the appropriate {@code ComponentUI} implementation for
    1043      * {@code target}. Typically, this is a cover for
    1044      * {@code getDefaults().getUI(target)}. However, if an auxiliary
    1045      * look and feel has been installed, this first invokes
    1046      * {@code getUI(target)} on the multiplexing look and feel's
    1047      * defaults, and returns that value if it is {@code non-null}.
    1048      *
    1049      * @param target the <code>JComponent</code> to return the
    1050      *        {@code ComponentUI} for
    1051      * @return the <code>ComponentUI</code> object for {@code target}
    1052      * @throws NullPointerException if {@code target} is {@code null}
    1053      * @see UIDefaults#getUI
    1054      */
    1055     public static ComponentUI getUI(JComponent target) {
    1056         maybeInitialize();
    1057         maybeInitializeFocusPolicy(target);
    1058         ComponentUI ui = null;
    1059         LookAndFeel multiLAF = getLAFState().multiLookAndFeel;
    1060         if (multiLAF != null) {
    1061             // This can return null if the multiplexing look and feel
    1062             // doesn't support a particular UI.
    1063             ui = multiLAF.getDefaults().getUI(target);
    1064         }
    1065         if (ui == null) {
    1066             ui = getDefaults().getUI(target);
    1067         }
    1068         return ui;
    1069     }
    1070
    1071
    1072     /**
    1073      * Returns the {@code UIDefaults} from the current look and feel,
    1074      * that were obtained at the time the look and feel was installed.
    1075      * <p>
    1076      * In general, developers should use the {@code UIDefaults} returned from
    1077      * {@code getDefaults()}. As the current look and feel may expect
    1078      * certain values to exist, altering the {@code UIDefaults} returned
    1079      * from this method could have unexpected results.
    1080      *
    1081      * @return <code>UIDefaults</code> from the current look and feel
    1082      * @see #getDefaults
    1083      * @see #setLookAndFeel(LookAndFeel)
    1084      * @see LookAndFeel#getDefaults
    1085      */
    1086     public static UIDefaults getLookAndFeelDefaults() {
    1087         maybeInitialize();
    1088         return getLAFState().getLookAndFeelDefaults();
    1089     }
    1090
    1091     /**
    1092      * Finds the Multiplexing <code>LookAndFeel</code>.
    1093      */
    1094     @SuppressWarnings("deprecation")
    1095     private static LookAndFeel getMultiLookAndFeel() {
    1096         LookAndFeel multiLookAndFeel = getLAFState().multiLookAndFeel;
    1097         if (multiLookAndFeel == null) {
    1098             String defaultName = "javax.swing.plaf.multi.MultiLookAndFeel";
    1099             String className = getLAFState().swingProps.getProperty(multiplexingLAFKey, defaultName);
    1100             try {
    1101                 Class<?> lnfClass = SwingUtilities.loadSystemClass(className);
    1102                 multiLookAndFeel =
    1103                         (LookAndFeel)lnfClass.newInstance();
    1104             } catch (Exception exc) {
    1105                 System.err.println("UIManager: failed loading " + className);
    1106             }
    1107         }
    1108         return multiLookAndFeel;
    1109     }
    1110
    1111     /**
    1112      * Adds a <code>LookAndFeel</code> to the list of auxiliary look and feels.
    1113      * The auxiliary look and feels tell the multiplexing look and feel what
    1114      * other <code>LookAndFeel</code> classes for a component instance are to be used
    1115      * in addition to the default <code>LookAndFeel</code> class when creating a
    1116      * multiplexing UI.  The change will only take effect when a new
    1117      * UI class is created or when the default look and feel is changed
    1118      * on a component instance.
    1119      * <p>Note these are not the same as the installed look and feels.
    1120      *
    1121      * @param laf the <code>LookAndFeel</code> object
    1122      * @see #removeAuxiliaryLookAndFeel
    1123      * @see #setLookAndFeel
    1124      * @see #getAuxiliaryLookAndFeels
    1125      * @see #getInstalledLookAndFeels
    1126      */
    1127     public static void addAuxiliaryLookAndFeel(LookAndFeel laf) {
    1128         maybeInitialize();
    1129
    1130         if (!laf.isSupportedLookAndFeel()) {
    1131             // Ideally we would throw an exception here, but it's too late
    1132             // for that.
    1133             return;
    1134         }
    1135         Vector<LookAndFeel> v = getLAFState().auxLookAndFeels;
    1136         if (v == null) {
    1137             v = new Vector<LookAndFeel>();
    1138         }
    1139
    1140         if (!v.contains(laf)) {
    1141             v.addElement(laf);
    1142             laf.initialize();
    1143             getLAFState().auxLookAndFeels = v;
    1144
    1145             if (getLAFState().multiLookAndFeel == null) {
    1146                 getLAFState().multiLookAndFeel = getMultiLookAndFeel();
    1147             }
    1148         }
    1149     }
    1150
    1151     /**
    1152      * Removes a <code>LookAndFeel</code> from the list of auxiliary look and feels.
    1153      * The auxiliary look and feels tell the multiplexing look and feel what
    1154      * other <code>LookAndFeel</code> classes for a component instance are to be used
    1155      * in addition to the default <code>LookAndFeel</code> class when creating a
    1156      * multiplexing UI.  The change will only take effect when a new
    1157      * UI class is created or when the default look and feel is changed
    1158      * on a component instance.
    1159      * <p>Note these are not the same as the installed look and feels.
    1160      *
    1161      * @param laf the {@code LookAndFeel} to be removed
    1162      * @return true if the <code>LookAndFeel</code> was removed from the list
    1163      * @see #removeAuxiliaryLookAndFeel
    1164      * @see #getAuxiliaryLookAndFeels
    1165      * @see #setLookAndFeel
    1166      * @see #getInstalledLookAndFeels
    1167      */
    1168     public static boolean removeAuxiliaryLookAndFeel(LookAndFeel laf) {
    1169         maybeInitialize();
    1170
    1171         boolean result;
    1172
    1173         Vector<LookAndFeel> v = getLAFState().auxLookAndFeels;
    1174         if ((v == null) || (v.size() == 0)) {
    1175             return false;
    1176         }
    1177
    1178         result = v.removeElement(laf);
    1179         if (result) {
    1180             if (v.size() == 0) {
    1181                 getLAFState().auxLookAndFeels = null;
    1182                 getLAFState().multiLookAndFeel = null;
    1183             } else {
    1184                 getLAFState().auxLookAndFeels = v;
    1185             }
    1186         }
    1187         laf.uninitialize();
    1188
    1189         return result;
    1190     }
    1191
    1192     /**
    1193      * Returns the list of auxiliary look and feels (can be <code>null</code>).
    1194      * The auxiliary look and feels tell the multiplexing look and feel what
    1195      * other <code>LookAndFeel</code> classes for a component instance are
    1196      * to be used in addition to the default LookAndFeel class when creating a
    1197      * multiplexing UI.
    1198      * <p>Note these are not the same as the installed look and feels.
    1199      *
    1200      * @return list of auxiliary <code>LookAndFeel</code>s or <code>null</code>
    1201      * @see #addAuxiliaryLookAndFeel
    1202      * @see #removeAuxiliaryLookAndFeel
    1203      * @see #setLookAndFeel
    1204      * @see #getInstalledLookAndFeels
    1205      */
    1206     public static LookAndFeel[] getAuxiliaryLookAndFeels() {
    1207         maybeInitialize();
    1208
    1209         Vector<LookAndFeel> v = getLAFState().auxLookAndFeels;
    1210         if ((v == null) || (v.size() == 0)) {
    1211             return null;
    1212         }
    1213         else {
    1214             LookAndFeel[] rv = new LookAndFeel[v.size()];
    1215             for (int i = 0; i < rv.length; i++) {
    1216                 rv[i] = v.elementAt(i);
    1217             }
    1218             return rv;
    1219         }
    1220     }
    1221
    1222
    1223     /**
    1224      * Adds a <code>PropertyChangeListener</code> to the listener list.
    1225      * The listener is registered for all properties.
    1226      *
    1227      * @param listener  the <code>PropertyChangeListener</code> to be added
    1228      * @see java.beans.PropertyChangeSupport
    1229      */
    1230     public static void addPropertyChangeListener(PropertyChangeListener listener)
    1231     {
    1232         synchronized (classLock) {
    1233             getLAFState().getPropertyChangeSupport(true).
    1234                              addPropertyChangeListener(listener);
    1235         }
    1236     }
    1237
    1238
    1239     /**
    1240      * Removes a <code>PropertyChangeListener</code> from the listener list.
    1241      * This removes a <code>PropertyChangeListener</code> that was registered
    1242      * for all properties.
    1243      *
    1244      * @param listener  the <code>PropertyChangeListener</code> to be removed
    1245      * @see java.beans.PropertyChangeSupport
    1246      */
    1247     public static void removePropertyChangeListener(PropertyChangeListener listener)
    1248     {
    1249         synchronized (classLock) {
    1250             getLAFState().getPropertyChangeSupport(true).
    1251                           removePropertyChangeListener(listener);
    1252         }
    1253     }
    1254
    1255
    1256     /**
    1257      * Returns an array of all the <code>PropertyChangeListener</code>s added
    1258      * to this UIManager with addPropertyChangeListener().
    1259      *
    1260      * @return all of the <code>PropertyChangeListener</code>s added or an empty
    1261      *         array if no listeners have been added
    1262      * @since 1.4
    1263      */
    1264     public static PropertyChangeListener[] getPropertyChangeListeners() {
    1265         synchronized(classLock) {
    1266             return getLAFState().getPropertyChangeSupport(true).
    1267                       getPropertyChangeListeners();
    1268         }
    1269     }
    1270
    1271     private static Properties loadSwingProperties()
    1272     {
    1273         /* Don't bother checking for Swing properties if untrusted, as
    1274          * there's no way to look them up without triggering SecurityExceptions.
    1275          */
    1276         if (UIManager.class.getClassLoader() != null) {
    1277             return new Properties();
    1278         }
    1279         else {
    1280             final Properties props = new Properties();
    1281
    1282             java.security.AccessController.doPrivileged(
    1283                 new java.security.PrivilegedAction<Object>() {
    1284                 public Object run() {
    1285                     OSInfo.OSType osType = AccessController.doPrivileged(OSInfo.getOSTypeAction());
    1286                     if (osType == OSInfo.OSType.MACOSX) {
    1287                         props.put(defaultLAFKey, getSystemLookAndFeelClassName());
    1288                     }
    1289
    1290                     try {
    1291                         File file = new File(makeSwingPropertiesFilename());
    1292
    1293                         if (file.exists()) {
    1294                             // InputStream has been buffered in Properties
    1295                             // class
    1296                             FileInputStream ins = new FileInputStream(file);
    1297                             props.load(ins);
    1298                             ins.close();
    1299                         }
    1300                     }
    1301                     catch (Exception e) {
    1302                         // No such file, or file is otherwise non-readable.
    1303                     }
    1304
    1305                     // Check whether any properties were overridden at the
    1306                     // command line.
    1307                     checkProperty(props, defaultLAFKey);
    1308                     checkProperty(props, auxiliaryLAFsKey);
    1309                     checkProperty(props, multiplexingLAFKey);
    1310                     checkProperty(props, installedLAFsKey);
    1311                     checkProperty(props, disableMnemonicKey);
    1312                     // Don't care about return value.
    1313                     return null;
    1314                 }
    1315             });
    1316             return props;
    1317         }
    1318     }
    1319
    1320     private static void checkProperty(Properties props, String key) {
    1321         // No need to do catch the SecurityException here, this runs
    1322         // in a doPrivileged.
    1323         String value = System.getProperty(key);
    1324         if (value != null) {
    1325             props.put(key, value);
    1326         }
    1327     }
    1328
    1329
    1330     /**
    1331      * If a <code>swing.properties</code> file exist and it has a
    1332      * <code>swing.installedlafs</code> property
    1333      * then initialize the <code>installedLAFs</code> field.
    1334      *
    1335      * @see #getInstalledLookAndFeels
    1336      */
    1337     private static void initializeInstalledLAFs(Properties swingProps)
    1338     {
    1339         String ilafsString = swingProps.getProperty(installedLAFsKey);
    1340         if (ilafsString == null) {
    1341             return;
    1342         }
    1343
    1344         /* Create a vector that contains the value of the swing.installedlafs
    1345          * property.  For example given "swing.installedlafs=motif,windows"
    1346          * lafs = {"motif", "windows"}.
    1347          */
    1348         Vector<String> lafs = new Vector<String>();
    1349         StringTokenizer st = new StringTokenizer(ilafsString, ",", false);
    1350         while (st.hasMoreTokens()) {
    1351             lafs.addElement(st.nextToken());
    1352         }
    1353
    1354         /* Look up the name and class for each name in the "swing.installedlafs"
    1355          * list.  If they both exist then add a LookAndFeelInfo to
    1356          * the installedLafs array.
    1357          */
    1358         Vector<LookAndFeelInfo> ilafs = new Vector<LookAndFeelInfo>(lafs.size());
    1359         for (String laf : lafs) {
    1360             String name = swingProps.getProperty(makeInstalledLAFKey(laf, "name"), laf);
    1361             String cls = swingProps.getProperty(makeInstalledLAFKey(laf, "class"));
    1362             if (cls != null) {
    1363                 ilafs.addElement(new LookAndFeelInfo(name, cls));
    1364             }
    1365         }
    1366
    1367         LookAndFeelInfo[] installedLAFs = new LookAndFeelInfo[ilafs.size()];
    1368         for(int i = 0; i < ilafs.size(); i++) {
    1369             installedLAFs[i] = ilafs.elementAt(i);
    1370         }
    1371         getLAFState().installedLAFs = installedLAFs;
    1372     }
    1373
    1374
    1375     /**
    1376      * If the user has specified a default look and feel, use that.
    1377      * Otherwise use the look and feel that's native to this platform.
    1378      * If this code is called after the application has explicitly
    1379      * set it's look and feel, do nothing.
    1380      *
    1381      * @see #maybeInitialize
    1382      */
    1383     private static void initializeDefaultLAF(Properties swingProps)
    1384     {
    1385         if (getLAFState().lookAndFeel != null) {
    1386             return;
    1387         }
    1388
    1389         // Try to get default LAF from system property, then from AppContext
    1390         // (6653395), then use cross-platform one by default.
    1391         String lafName = null;
    1392         @SuppressWarnings("unchecked")
    1393         HashMap<Object, String> lafData =
    1394                 (HashMap) AppContext.getAppContext().remove("swing.lafdata");
    1395         if (lafData != null) {
    1396             lafName = lafData.remove("defaultlaf");
    1397         }
    1398         if (lafName == null) {
    1399             lafName = getCrossPlatformLookAndFeelClassName();
    1400         }
    1401         lafName = swingProps.getProperty(defaultLAFKey, lafName);
    1402
    1403         try {
    1404             setLookAndFeel(lafName);
    1405         } catch (Exception e) {
    1406             throw new Error("Cannot load " + lafName);
    1407         }
    1408
    1409         // Set any properties passed through AppContext (6653395).
    1410         if (lafData != null) {
    1411             for (Object key: lafData.keySet()) {
    1412                 UIManager.put(key, lafData.get(key));
    1413             }
    1414         }
    1415     }
    1416
    1417
    1418     @SuppressWarnings("deprecation")
    1419     private static void initializeAuxiliaryLAFs(Properties swingProps)
    1420     {
    1421         String auxLookAndFeelNames = swingProps.getProperty(auxiliaryLAFsKey);
    1422         if (auxLookAndFeelNames == null) {
    1423             return;
    1424         }
    1425
    1426         Vector<LookAndFeel> auxLookAndFeels = new Vector<LookAndFeel>();
    1427
    1428         StringTokenizer p = new StringTokenizer(auxLookAndFeelNames,",");
    1429         String factoryName;
    1430
    1431         /* Try to load each LookAndFeel subclass in the list.
    1432          */
    1433
    1434         while (p.hasMoreTokens()) {
    1435             String className = p.nextToken();
    1436             try {
    1437                 Class<?> lnfClass = SwingUtilities.loadSystemClass(className);
    1438                 LookAndFeel newLAF =
    1439                         (LookAndFeel)lnfClass.newInstance();
    1440                 newLAF.initialize();
    1441                 auxLookAndFeels.addElement(newLAF);
    1442             }
    1443             catch (Exception e) {
    1444                 System.err.println("UIManager: failed loading auxiliary look and feel " + className);
    1445             }
    1446         }
    1447
    1448         /* If there were problems and no auxiliary look and feels were
    1449          * loaded, make sure we reset auxLookAndFeels to null.
    1450          * Otherwise, we are going to use the MultiLookAndFeel to get
    1451          * all component UI's, so we need to load it now.
    1452          */
    1453         if (auxLookAndFeels.size() == 0) {
    1454             auxLookAndFeels = null;
    1455         }
    1456         else {
    1457             getLAFState().multiLookAndFeel = getMultiLookAndFeel();
    1458             if (getLAFState().multiLookAndFeel == null) {
    1459                 auxLookAndFeels = null;
    1460             }
    1461         }
    1462
    1463         getLAFState().auxLookAndFeels = auxLookAndFeels;
    1464     }
    1465
    1466
    1467     private static void initializeSystemDefaults(Properties swingProps) {
    1468         getLAFState().swingProps = swingProps;
    1469     }
    1470
    1471
    1472     /*
    1473      * This method is called before any code that depends on the
    1474      * <code>AppContext</code> specific LAFState object runs.  When the AppContext
    1475      * corresponds to a set of applets it's possible for this method
    1476      * to be re-entered, which is why we grab a lock before calling
    1477      * initialize().
    1478      */
    1479     private static void maybeInitialize() {
    1480         synchronized (classLock) {
    1481             if (!getLAFState().initialized) {
    1482                 getLAFState().initialized = true;
    1483                 initialize();
    1484             }
    1485         }
    1486     }
    1487
    1488     /*
    1489      * Sets default swing focus traversal policy.
    1490      */
    1491     @SuppressWarnings("deprecation")
    1492     private static void maybeInitializeFocusPolicy(JComponent comp) {
    1493         // Check for JRootPane which indicates that a swing toplevel
    1494         // is coming, in which case a swing default focus policy
    1495         // should be instatiated. See 7125044.
    1496         if (comp instanceof JRootPane) {
    1497             synchronized (classLock) {
    1498                 if (!getLAFState().focusPolicyInitialized) {
    1499                     getLAFState().focusPolicyInitialized = true;
    1500
    1501                     if (FocusManager.isFocusManagerEnabled()) {
    1502                         KeyboardFocusManager.getCurrentKeyboardFocusManager().
    1503                             setDefaultFocusTraversalPolicy(
    1504                                 new LayoutFocusTraversalPolicy());
    1505                     }
    1506                 }
    1507             }
    1508         }
    1509     }
    1510
    1511     /*
    1512      * Only called by maybeInitialize().
    1513      */
    1514     private static void initialize() {
    1515         Properties swingProps = loadSwingProperties();
    1516         initializeSystemDefaults(swingProps);
    1517         initializeDefaultLAF(swingProps);
    1518         initializeAuxiliaryLAFs(swingProps);
    1519         initializeInstalledLAFs(swingProps);
    1520
    1521         // Install Swing's PaintEventDispatcher
    1522         if (RepaintManager.HANDLE_TOP_LEVEL_PAINT) {
    1523             sun.awt.PaintEventDispatcher.setPaintEventDispatcher(
    1524                                         new SwingPaintEventDispatcher());
    1525         }
    1526         // Install a hook that will be invoked if no one consumes the
    1527         // KeyEvent.  If the source isn't a JComponent this will process
    1528         // key bindings, if the source is a JComponent it implies that
    1529         // processKeyEvent was already invoked and thus no need to process
    1530         // the bindings again, unless the Component is disabled, in which
    1531         // case KeyEvents will no longer be dispatched to it so that we
    1532         // handle it here.
    1533         KeyboardFocusManager.getCurrentKeyboardFocusManager().
    1534                 addKeyEventPostProcessor(new KeyEventPostProcessor() {
    1535                     public boolean postProcessKeyEvent(KeyEvent e) {
    1536                         Component c = e.getComponent();
    1537
    1538                         if ((!(c instanceof JComponent) ||
    1539                              (c != null && !c.isEnabled())) &&
    1540                                 JComponent.KeyboardState.shouldProcess(e) &&
    1541                                 SwingUtilities.processKeyBindings(e)) {
    1542                             e.consume();
    1543                             return true;
    1544                         }
    1545                         return false;
    1546                     }
    1547                 });
    1548         AWTAccessor.getComponentAccessor().
    1549             setRequestFocusController(JComponent.focusController);
    1550     }
    1551 }
    --- EOF ---