/* * This file is modified by Ivan Maidanski <ivmai@ivmaisoft.com> * Project name: JCGO-SUNAWT (http://www.ivmaisoft.com/jcgo/) ** * Comment: contains win32-specific fixes. */ /* * @(#)UIManager.java 1.103 03/01/23 * * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package javax.swing; import java.awt.Component; import java.awt.Container; import java.awt.Window; import java.awt.Font; import java.awt.Color; import java.awt.Insets; import java.awt.Dimension; import java.awt.KeyboardFocusManager; import java.awt.KeyEventPostProcessor; import java.awt.event.KeyEvent; import java.security.AccessController; import javax.swing.plaf.ComponentUI; import javax.swing.border.Border; import javax.swing.event.SwingPropertyChangeSupport; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.Serializable; import java.io.File; import java.io.FileInputStream; import java.io.BufferedInputStream; import java.util.Enumeration; import java.util.Hashtable; import java.util.Properties; import java.util.StringTokenizer; import java.util.Vector; import java.util.Locale; import sun.security.action.GetPropertyAction; /** * This class keeps track of the current look and feel and its * defaults. * The default look and feel class is chosen in the following manner: * <ol> * <li>If the system property <code>swing.defaultlaf</code> is * non-null, use it as the default look and feel class name. * <li>If the {@link java.util.Properties} file <code>swing.properties</code> * exists and contains the key <code>swing.defaultlaf</code>, * use its value as default look and feel class name. The location of * <code>swing.properties</code> may vary depending upon the * implementation of the Java platform. In Sun's implementation * this will reside in * <code>&java.home>/lib/swing.properties</code>. Refer to * the release notes of the implementation you are using for * further details. * <li>Otherwise use the Java look and feel. * </ol> * <p> * We manage three levels of defaults: user defaults, look * and feel defaults, system defaults. A call to <code>UIManager.get</code> * checks all three levels in order and returns the first non-<code>null</code> * value for a key, if any. A call to <code>UIManager.put</code> just * affects the user defaults. Note that a call to * <code>setLookAndFeel</code> doesn't affect the user defaults, it just * replaces the middle defaults "level". * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans<sup><font size="-2">TM</font></sup> * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @see javax.swing.plaf.metal * * @version 1.103 01/23/03 * @author Thomas Ball * @author Hans Muller */ public class UIManager implements Serializable { /** * This class defines the state managed by the <code>UIManager</code>. For * Swing applications the fields in this class could just as well * be static members of <code>UIManager</code> however we give them * "AppContext" * scope instead so that applets (and potentially multiple lightweight * applications running in a single VM) have their own state. For example, * an applet can alter its look and feel, see <code>setLookAndFeel</code>. * Doing so has no affect on other applets (or the browser). */ private static class LAFState { Properties swingProps; private UIDefaults[] tables = new UIDefaults[2]; boolean initialized = false; MultiUIDefaults multiUIDefaults = new MultiUIDefaults(tables); LookAndFeel lookAndFeel; LookAndFeel multiLookAndFeel = null; Vector auxLookAndFeels = null; SwingPropertyChangeSupport changeSupport = new SwingPropertyChangeSupport(UIManager.class); UIDefaults getLookAndFeelDefaults() { return tables[0]; } void setLookAndFeelDefaults(UIDefaults x) { tables[0] = x; } UIDefaults getSystemDefaults() { return tables[1]; } void setSystemDefaults(UIDefaults x) { tables[1] = x; } } /** * The <code>AppContext</code> key for our one <code>LAFState</code> instance. */ private static final Object lafStateACKey = new StringBuffer("LookAndFeel State"); /* Lock object used in place of class object for synchronization. (4187686) */ private static final Object classLock = new Object(); /* Cache the last referenced LAFState to improve performance * when accessing it. The cache is based on last thread rather * than last AppContext because of the cost of looking up the * AppContext each time. Since most Swing UI work is on the * EventDispatchThread, this hits often enough to justify the * overhead. (4193032) */ private static Thread currentLAFStateThread = null; private static LAFState currentLAFState = null; /** * Return the <code>LAFState</code> object, lazily create one if necessary. * All access to the <code>LAFState</code> fields is done via this method, * for example: * <pre> * getLAFState().initialized = true; * </pre> */ private static LAFState getLAFState() { // First check whether we're running on the same thread as // the last request. Thread thisThread = Thread.currentThread(); if (thisThread == currentLAFStateThread) { return currentLAFState; } LAFState rv = (LAFState)SwingUtilities.appContextGet(lafStateACKey); if (rv == null) { synchronized (classLock) { rv = (LAFState)SwingUtilities.appContextGet(lafStateACKey); if (rv == null) { SwingUtilities.appContextPut(lafStateACKey, (rv = new LAFState())); } } } currentLAFStateThread = thisThread; currentLAFState = rv; return rv; } /* Keys used for the properties file in <java.home>/lib/swing.properties. * See loadUserProperties(), initialize(). */ private static final String defaultLAFKey = "swing.defaultlaf"; private static final String auxiliaryLAFsKey = "swing.auxiliarylaf"; private static final String multiplexingLAFKey = "swing.plaf.multiplexinglaf"; private static final String installedLAFsKey = "swing.installedlafs"; private static final String disableMnemonicKey = "swing.disablenavaids"; /** * Return a swing.properties file key for the attribute of specified * look and feel. The attr is either "name" or "class", a typical * key would be: "swing.installedlaf.windows.name" */ private static String makeInstalledLAFKey(String laf, String attr) { return "swing.installedlaf." + laf + "." + attr; } /** * The filename for swing.properties is a path like this (Unix version): * <java.home>/lib/swing.properties. This method returns a bogus * filename if java.home isn't defined. */ private static String makeSwingPropertiesFilename() { String sep = File.separator; return AccessController.doPrivileged(new GetPropertyAction( "java.home", "<java.home undefined>")) + sep + "lib" + sep + "swing.properties"; } /** * Provides a little information about an installed * <code>LookAndFeel</code> for the sake of configuring a menu or * for initial application set up. * * @see UIManager#getInstalledLookAndFeels * @see LookAndFeel */ public static class LookAndFeelInfo { private String name; private String className; /** * Constructs a <code>UIManager</code>s * <code>LookAndFeelInfo</code> object. * * @param name a <code>String</code> specifying the name of * the look and feel * @param className a <code>String</code> specifiying the name of * the class that implements the look and feel */ public LookAndFeelInfo(String name, String className) { this.name = name; this.className = className; } /** * Returns the name of the look and feel in a form suitable * for a menu or other presentation * @return a <code>String</code> containing the name * @see LookAndFeel#getName */ public String getName() { return name; } /** * Returns the name of the class that implements this look and feel. * @return the name of the class that implements this * <code>LookAndFeel</code> * @see LookAndFeel */ public String getClassName() { return className; } /** * Returns a string that displays and identifies this * object's properties. * * @return a <code>String</code> representation of this object */ public String toString() { return getClass().getName() + "[" + getName() + " " + getClassName() + "]"; } } /** * The default value of <code>installedLAFS</code> is used when no * swing.properties * file is available or if the file doesn't contain a "swing.installedlafs" * property. * * @see #initializeInstalledLAFs */ private static LookAndFeelInfo[] installedLAFs = { new LookAndFeelInfo("Metal", "javax.swing.plaf.metal.MetalLookAndFeel"), new LookAndFeelInfo("CDE/Motif", "com.sun.java.swing.plaf.motif." + "MotifLookAndFeel"), new LookAndFeelInfo("Windows", "com.sun.java.swing.plaf.windows." + "WindowsLookAndFeel"), new LookAndFeelInfo("GTK", "com.sun.java.swing.plaf.gtk." + "GTKLookAndFeel") }; /** * Returns an array of objects that provide some information about the * <code>LookAndFeel</code> implementations that have been installed with this * software development kit. The <code>LookAndFeel</code> info objects can * used by an application to construct a menu of look and feel options for * the user or to set the look and feel at start up time. Note that * we do not return the <code>LookAndFeel</code> classes themselves here to * avoid the cost of unnecessarily loading them. * <p> * Given a <code>LookAndFeelInfo</code> object one can set the current * look and feel like this: * <pre> * UIManager.setLookAndFeel(info.getClassName()); * </pre> * @return an array of <code>LookAndFeelInfo</code> objects * * @see #setLookAndFeel */ public static LookAndFeelInfo[] getInstalledLookAndFeels() { maybeInitialize(); LookAndFeelInfo[] ilafs = installedLAFs; LookAndFeelInfo[] rv = new LookAndFeelInfo[ilafs.length]; System.arraycopy(ilafs, 0, rv, 0, ilafs.length); return rv; } /** * Replaces the current array of installed <code>LookAndFeelInfos</code>. * @param infos new array of <code>LookAndFeelInfo</code> objects * * @see #getInstalledLookAndFeels */ public static void setInstalledLookAndFeels(LookAndFeelInfo[] infos) throws SecurityException { LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length]; System.arraycopy(infos, 0, newInfos, 0, infos.length); installedLAFs = newInfos; } /** * Adds the specified look and feel to the current array and * then calls {@link #setInstalledLookAndFeels}. * @param info a <code>LookAndFeelInfo</code> object that names the * look and feel and identifies that class that implements it */ public static void installLookAndFeel(LookAndFeelInfo info) { LookAndFeelInfo[] infos = getInstalledLookAndFeels(); LookAndFeelInfo[] newInfos = new LookAndFeelInfo[infos.length + 1]; System.arraycopy(infos, 0, newInfos, 0, infos.length); newInfos[infos.length] = info; setInstalledLookAndFeels(newInfos); } /** * Creates a new look and feel and adds it to the current array. * Then calls {@link #setInstalledLookAndFeels}. * * @param name a <code>String</code> specifying the name of the * look and feel * @param className a <code>String</code> specifying the class name * that implements the look and feel */ public static void installLookAndFeel(String name, String className) { installLookAndFeel(new LookAndFeelInfo(name, className)); } /** * Returns the current default look and feel or <code>null</code>. * * @return the current default look and feel, or <code>null</code> * @see #setLookAndFeel */ public static LookAndFeel getLookAndFeel() { maybeInitialize(); return getLAFState().lookAndFeel; } /** * Sets the current default look and feel using a * <code>LookAndFeel</code> object. * <p> * This is a JavaBeans bound property. * * @param newLookAndFeel the <code>LookAndFeel</code> object * @exception UnsupportedLookAndFeelException if * <code>lnf.isSupportedLookAndFeel()</code> is false * @see #getLookAndFeel */ public static void setLookAndFeel(LookAndFeel newLookAndFeel) throws UnsupportedLookAndFeelException { if ((newLookAndFeel != null) && !newLookAndFeel.isSupportedLookAndFeel()) { String s = newLookAndFeel.toString() + " not supported on this platform"; throw new UnsupportedLookAndFeelException(s); } LookAndFeel oldLookAndFeel = getLAFState().lookAndFeel; if (oldLookAndFeel != null) { oldLookAndFeel.uninitialize(); } getLAFState().lookAndFeel = newLookAndFeel; if (newLookAndFeel != null) { newLookAndFeel.initialize(); getLAFState().setLookAndFeelDefaults(newLookAndFeel.getDefaults()); } else { getLAFState().setLookAndFeelDefaults(null); } getLAFState().changeSupport.firePropertyChange("lookAndFeel", oldLookAndFeel, newLookAndFeel); } /** * Sets the current default look and feel using a class name. * * @param className a string specifying the name of the class that implements * the look and feel * @exception ClassNotFoundException if the <code>LookAndFeel</code> * class could not be found * @exception InstantiationException if a new instance of the class * couldn't be created * @exception IllegalAccessException if the class or initializer isn't accessible * @exception UnsupportedLookAndFeelException if * <code>lnf.isSupportedLookAndFeel()</code> is false */ public static void setLookAndFeel(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException { Class lnfClass = SwingUtilities.loadSystemClass(className); setLookAndFeel((LookAndFeel)(lnfClass.newInstance())); } /** * Returns the name of the <code>LookAndFeel</code> class that implements * the native systems look and feel if there is one, otherwise * the name of the default cross platform <code>LookAndFeel</code> * class. * * @return the <code>String</code> of the <code>LookAndFeel</code> * class * * @see #setLookAndFeel * @see #getCrossPlatformLookAndFeelClassName */ public static String getSystemLookAndFeelClassName() { String osName = (String)AccessController.doPrivileged( new GetPropertyAction("os.name")); if (osName != null) { if (osName.indexOf("Windows") != -1) { return "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"; } /* else if ((osName.indexOf("Solaris") != -1) || (osName.indexOf("SunOS") != -1)) { return "com.sun.java.swing.plaf.motif.MotifLookAndFeel"; } else if (osName.indexOf("Mac") != -1 ) { return "com.sun.java.swing.plaf.mac.MacLookAndFeel"; } */ } return getCrossPlatformLookAndFeelClassName(); } /** * Returns the name of the <code>LookAndFeel</code> class that implements * the default cross platform look and feel -- the Java * Look and Feel (JLF). * * @return a string with the JLF implementation-class * @see #setLookAndFeel * @see #getSystemLookAndFeelClassName */ public static String getCrossPlatformLookAndFeelClassName() { return "javax.swing.plaf.metal.MetalLookAndFeel"; } /** * Returns the default values for this look and feel. * * @return a <code>UIDefaults</code> object containing the default values */ public static UIDefaults getDefaults() { maybeInitialize(); return getLAFState().multiUIDefaults; } /** * Returns a drawing font from the defaults table. * * @param key an <code>Object</code> specifying the font * @return the <code>Font</code> object */ public static Font getFont(Object key) { return getDefaults().getFont(key); } /** * Returns a drawing font from the defaults table that is appropriate * for the given locale. * * @param key an <code>Object</code> specifying the font * @param l the <code>Locale</code> for which the font is desired * @return the <code>Font</code> object * @since 1.4 */ public static Font getFont(Object key, Locale l) { return getDefaults().getFont(key,l); } /** * Returns a drawing color from the defaults table. * * @param key an <code>Object</code> specifying the color * @return the <code>Color</code> object */ public static Color getColor(Object key) { return getDefaults().getColor(key); } /** * Returns a drawing color from the defaults table that is appropriate * for the given locale. * * @param key an <code>Object</code> specifying the color * @param l the <code>Locale</code> for which the color is desired * @return the <code>Color</code> object * @since 1.4 */ public static Color getColor(Object key, Locale l) { return getDefaults().getColor(key,l); } /** * Returns an <code>Icon</code> from the defaults table. * * @param key an <code>Object</code> specifying the icon * @return the <code>Icon</code> object */ public static Icon getIcon(Object key) { return getDefaults().getIcon(key); } /** * Returns an <code>Icon</code> from the defaults table that is appropriate * for the given locale. * * @param key an <code>Object</code> specifying the icon * @param l the <code>Locale</code> for which the icon is desired * @return the <code>Icon</code> object * @since 1.4 */ public static Icon getIcon(Object key, Locale l) { return getDefaults().getIcon(key,l); } /** * Returns a border from the defaults table. * * @param key an <code>Object</code> specifying the border * @return the <code>Border</code> object */ public static Border getBorder(Object key) { return getDefaults().getBorder(key); } /** * Returns a border from the defaults table that is appropriate * for the given locale. * * @param key an <code>Object</code> specifying the border * @param l the <code>Locale</code> for which the border is desired * @return the <code>Border</code> object * @since 1.4 */ public static Border getBorder(Object key, Locale l) { return getDefaults().getBorder(key,l); } /** * Returns a string from the defaults table. * * @param key an <code>Object</code> specifying the string * @return the <code>String</code> */ public static String getString(Object key) { return getDefaults().getString(key); } /** * Returns a string from the defaults table that is appropriate for the * given locale. * * @param key an <code>Object</code> specifying the string * @param l the <code>Locale</code> for which the string is desired * @return the <code>String</code> */ public static String getString(Object key, Locale l) { return getDefaults().getString(key,l); } /** * Returns a string from the defaults table that is appropriate for the * given locale. * * @param key an <code>Object</code> specifying the string * @param c Component used to determine Locale, null implies use the * default Locale. * @return the <code>String</code> */ static String getString(Object key, Component c) { Locale l = (c == null) ? Locale.getDefault() : c.getLocale(); return getString(key, l); } /** * Returns an integer from the defaults table. * * @param key an <code>Object</code> specifying the int * @return the int */ public static int getInt(Object key) { return getDefaults().getInt(key); } /** * Returns an integer from the defaults table that is appropriate * for the given locale. * * @param key an <code>Object</code> specifying the int * @param l the <code>Locale</code> for which the int is desired * @return the int * @since 1.4 */ public static int getInt(Object key, Locale l) { return getDefaults().getInt(key,l); } /** * Returns an integer from the defaults table. If <code>key</code> does * not map to a valid <code>Integer</code>, or can not be convered from * a <code>String</code> to an integer, <code>default</code> is * returned. * * @param key an <code>Object</code> specifying the int * @param defaultValue Returned value if <code>key</code> is not available, * or is not an Integer * @return the int */ static int getInt(Object key, int defaultValue) { Object value = UIManager.get(key); if (value instanceof Integer) { return ((Integer)value).intValue(); } if (value instanceof String) { try { return Integer.parseInt((String)value); } catch (NumberFormatException nfe) {} } return defaultValue; } /** * Returns a boolean from the defaults table which is associated with * the key value. If the key is not found or the key doesn't represent * a boolean value then false will be returned. * * @param key an <code>Object</code> specifying the key for the desired boolean value * @return the boolean value corresponding to the key * @since 1.4 */ public static boolean getBoolean(Object key) { return getDefaults().getBoolean(key); } /** * Returns a boolean from the defaults table which is associated with * the key value and the given <code>Locale</code>. If the key is not * found or the key doesn't represent * a boolean value then false will be returned. * * @param key an <code>Object</code> specifying the key for the desired * boolean value * @param l the <code>Locale</code> for which the boolean is desired * @return the boolean value corresponding to the key * @since 1.4 */ public static boolean getBoolean(Object key, Locale l) { return getDefaults().getBoolean(key,l); } /** * Returns an <code>Insets</code> object from the defaults table. * * @param key an <code>Object</code> specifying the <code>Insets</code> object * @return the <code>Insets</code> object */ public static Insets getInsets(Object key) { return getDefaults().getInsets(key); } /** * Returns an <code>Insets</code> object from the defaults table that is * appropriate for the given locale. * * @param key an <code>Object</code> specifying the <code>Insets</code> object * @param l the <code>Locale</code> for which the object is desired * @return the <code>Insets</code> object * @since 1.4 */ public static Insets getInsets(Object key, Locale l) { return getDefaults().getInsets(key,l); } /** * Returns a dimension from the defaults table. * * @param key an <code>Object</code> specifying the dimension object * @return the <code>Dimension</code> object */ public static Dimension getDimension(Object key) { return getDefaults().getDimension(key); } /** * Returns a dimension from the defaults table that is appropriate * for the given locale. * * @param key an <code>Object</code> specifying the dimension object * @param l the <code>Locale</code> for which the object is desired * @return the <code>Dimension</code> object * @since 1.4 */ public static Dimension getDimension(Object key, Locale l) { return getDefaults().getDimension(key,l); } /** * Returns an object from the defaults table. * * @param key an <code>Object</code> specifying the desired object * @return the <code>Object</code> */ public static Object get(Object key) { return getDefaults().get(key); } /** * Returns an object from the defaults table that is appropriate for * the given locale. * * @param key an <code>Object</code> specifying the desired object * @param l the <code>Locale</code> for which the object is desired * @return the <code>Object</code> */ public static Object get(Object key, Locale l) { return getDefaults().get(key,l); } /** * Stores an object in the defaults table. * * @param key an <code>Object</code> specifying the retrieval key * @param value the <code>Object</code> to store * @return the <code>Object</code> returned by {@link UIDefaults#put} */ public static Object put(Object key, Object value) { return getDefaults().put(key, value); } /** * Returns the L&F object that renders the target component. * * @param target the <code>JComponent</code> to render * @return the <code>ComponentUI</code> object that renders the target component */ public static ComponentUI getUI(JComponent target) { maybeInitialize(); ComponentUI ui = null; LookAndFeel multiLAF = getLAFState().multiLookAndFeel; if (multiLAF != null) { // This can return null if the multiplexing look and feel // doesn't support a particular UI. ui = multiLAF.getDefaults().getUI(target); } if (ui == null) { ui = getDefaults().getUI(target); } return ui; } /** * Returns the default values for this look and feel. * * @return an <code>UIDefaults</code> object containing the default values */ public static UIDefaults getLookAndFeelDefaults() { maybeInitialize(); return getLAFState().getLookAndFeelDefaults(); } /** * Finds the Multiplexing <code>LookAndFeel</code>. */ private static LookAndFeel getMultiLookAndFeel(String defaultName) { LookAndFeel multiLookAndFeel = getLAFState().multiLookAndFeel; if (multiLookAndFeel == null) { String className = getLAFState().swingProps.getProperty(multiplexingLAFKey, defaultName); try { Class lnfClass = SwingUtilities.loadSystemClass(className); multiLookAndFeel = (LookAndFeel)lnfClass.newInstance(); } catch (Exception exc) { System.err.println("UIManager: failed loading " + className); } } return multiLookAndFeel; } /** * Adds a <code>LookAndFeel</code> to the list of auxiliary look and feels. * The auxiliary look and feels tell the multiplexing look and feel what * other <code>LookAndFeel</code> classes for a component instance are to be used * in addition to the default <code>LookAndFeel</code> class when creating a * multiplexing UI. The change will only take effect when a new * UI class is created or when the default look and feel is changed * on a component instance. * <p>Note these are not the same as the installed look and feels. * * @param laf the <code>LookAndFeel</code> object * @see #removeAuxiliaryLookAndFeel * @see #setLookAndFeel * @see #getAuxiliaryLookAndFeels * @see #getInstalledLookAndFeels */ static public void addAuxiliaryLookAndFeel(LookAndFeel laf) { maybeInitialize(); Vector v = getLAFState().auxLookAndFeels; if (v == null) { v = new Vector(); } if (!v.contains(laf)) { v.addElement(laf); laf.initialize(); getLAFState().auxLookAndFeels = v; if (getLAFState().multiLookAndFeel == null) { getLAFState().multiLookAndFeel = getMultiLookAndFeel( javax.swing.plaf.multi.MultiLookAndFeel.class.getName()); } } } /** * Removes a <code>LookAndFeel</code> from the list of auxiliary look and feels. * The auxiliary look and feels tell the multiplexing look and feel what * other <code>LookAndFeel</code> classes for a component instance are to be used * in addition to the default <code>LookAndFeel</code> class when creating a * multiplexing UI. The change will only take effect when a new * UI class is created or when the default look and feel is changed * on a component instance. * <p>Note these are not the same as the installed look and feels. * @return true if the <code>LookAndFeel</code> was removed from the list * @see #removeAuxiliaryLookAndFeel * @see #getAuxiliaryLookAndFeels * @see #setLookAndFeel * @see #getInstalledLookAndFeels */ static public boolean removeAuxiliaryLookAndFeel(LookAndFeel laf) { maybeInitialize(); boolean result; Vector v = getLAFState().auxLookAndFeels; if ((v == null) || (v.size() == 0)) { return false; } result = v.removeElement(laf); if (result) { if (v.size() == 0) { getLAFState().auxLookAndFeels = null; getLAFState().multiLookAndFeel = null; } else { getLAFState().auxLookAndFeels = v; } } laf.uninitialize(); return result; } /** * Returns the list of auxiliary look and feels (can be <code>null</code>). * The auxiliary look and feels tell the multiplexing look and feel what * other <code>LookAndFeel</code> classes for a component instance are * to be used in addition to the default LookAndFeel class when creating a * multiplexing UI. * <p>Note these are not the same as the installed look and feels. * * @return list of auxiliary <code>LookAndFeel</code>s or <code>null</code> * @see #addAuxiliaryLookAndFeel * @see #removeAuxiliaryLookAndFeel * @see #setLookAndFeel * @see #getInstalledLookAndFeels */ static public LookAndFeel[] getAuxiliaryLookAndFeels() { maybeInitialize(); Vector v = getLAFState().auxLookAndFeels; if ((v == null) || (v.size() == 0)) { return null; } else { LookAndFeel[] rv = new LookAndFeel[v.size()]; for (int i = 0; i < rv.length; i++) { rv[i] = (LookAndFeel)v.elementAt(i); } return rv; } } /** * Adds a <code>PropertyChangeListener</code> to the listener list. * The listener is registered for all properties. * * @param listener the <code>PropertyChangeListener</code> to be added * @see java.beans.PropertyChangeSupport */ public static void addPropertyChangeListener(PropertyChangeListener listener) { synchronized (classLock) { getLAFState().changeSupport.addPropertyChangeListener(listener); } } /** * Removes a <code>PropertyChangeListener</code> from the listener list. * This removes a <code>PropertyChangeListener</code> that was registered * for all properties. * * @param listener the <code>PropertyChangeListener</code> to be removed * @see java.beans.PropertyChangeSupport */ public static void removePropertyChangeListener(PropertyChangeListener listener) { synchronized (classLock) { getLAFState().changeSupport.removePropertyChangeListener(listener); } } /** * Returns an array of all the <code>PropertyChangeListener</code>s added * to this UIManager with addPropertyChangeListener(). * * @return all of the <code>PropertyChangeListener</code>s added or an empty * array if no listeners have been added * @since 1.4 */ public static PropertyChangeListener[] getPropertyChangeListeners() { synchronized(classLock) { return getLAFState().changeSupport.getPropertyChangeListeners(); } } private static Properties loadSwingProperties() { /* Don't bother checking for Swing properties if untrusted, as * there's no way to look them up without triggering SecurityExceptions. */ if (UIManager.class.getClassLoader() != null) { return new Properties(); } else { final Properties props = new Properties(); SwingUtilities.doPrivileged(new Runnable() { public void run() { try { File file = new File(makeSwingPropertiesFilename()); if (file.exists()) { // InputStream has been buffered in Properties // class FileInputStream ins = new FileInputStream(file); props.load(ins); ins.close(); } } catch (Exception e) { // No such file, or file is otherwise non-readable. } // Check whether any properties were overridden at the // command line. checkProperty(props, defaultLAFKey); checkProperty(props, auxiliaryLAFsKey); checkProperty(props, multiplexingLAFKey); checkProperty(props, installedLAFsKey); checkProperty(props, disableMnemonicKey); } }); return props; } } private static void checkProperty(Properties props, String key) { try { String value = System.getProperty(key); if (value != null) { props.put(key, value); } } catch (SecurityException e) { // If system won't give us a property, we don't want it! } } /** * If a swing.properties file exist and it has a swing.installedlafs property * then initialize the <code>installedLAFs</code> field. * * @see #getInstalledLookAndFeels */ private static void initializeInstalledLAFs(Properties swingProps) { String ilafsString = swingProps.getProperty(installedLAFsKey); if (ilafsString == null) { return; } /* Create a vector that contains the value of the swing.installedlafs * property. For example given "swing.installedlafs=motif,windows" * lafs = {"motif", "windows"}. */ Vector lafs = new Vector(); StringTokenizer st = new StringTokenizer(ilafsString, ",", false); while (st.hasMoreTokens()) { lafs.addElement(st.nextToken()); } /* Look up the name and class for each name in the "swing.installedlafs" * list. If they both exist then add a LookAndFeelInfo to * the installedLafs array. */ Vector ilafs = new Vector(lafs.size()); for(int i = 0; i < lafs.size(); i++) { String laf = (String)lafs.elementAt(i); String name = swingProps.getProperty(makeInstalledLAFKey(laf, "name"), laf); String cls = swingProps.getProperty(makeInstalledLAFKey(laf, "class")); if (cls != null) { ilafs.addElement(new LookAndFeelInfo(name, cls)); } } installedLAFs = new LookAndFeelInfo[ilafs.size()]; for(int i = 0; i < ilafs.size(); i++) { installedLAFs[i] = (LookAndFeelInfo)(ilafs.elementAt(i)); } } /** * If the user has specified a default look and feel, use that. * Otherwise use the look and feel that's native to this platform. * If this code is called after the application has explicitly * set it's look and feel, do nothing. * * @see #maybeInitialize */ private static void initializeDefaultLAF(Properties swingProps) { if (getLAFState().lookAndFeel != null) { return; } String metalLnf = getCrossPlatformLookAndFeelClassName(); String lnfDefault = metalLnf; String lnfName = "<undefined>" ; try { lnfName = swingProps.getProperty(defaultLAFKey, lnfDefault); setLookAndFeel(lnfName); } catch (Exception e) { try { lnfName = swingProps.getProperty(defaultLAFKey, metalLnf); setLookAndFeel(lnfName); } catch (Exception e2) { throw new Error("can't load " + lnfName); } } } private static void initializeAuxiliaryLAFs(Properties swingProps) { String auxLookAndFeelNames = swingProps.getProperty(auxiliaryLAFsKey); if (auxLookAndFeelNames == null) { return; } Vector auxLookAndFeels = new Vector(); StringTokenizer p = new StringTokenizer(auxLookAndFeelNames,","); String factoryName; /* Try to load each LookAndFeel subclass in the list. */ while (p.hasMoreTokens()) { String className = p.nextToken(); try { Class lnfClass = SwingUtilities.loadSystemClass(className); LookAndFeel newLAF = (LookAndFeel)lnfClass.newInstance(); newLAF.initialize(); auxLookAndFeels.addElement(newLAF); } catch (Exception e) { System.err.println("UIManager: failed loading auxiliary look and feel " + className); } } /* If there were problems and no auxiliary look and feels were * loaded, make sure we reset auxLookAndFeels to null. * Otherwise, we are going to use the MultiLookAndFeel to get * all component UI's, so we need to load it now. */ if (auxLookAndFeels.size() == 0) { auxLookAndFeels = null; } else { getLAFState().multiLookAndFeel = getMultiLookAndFeel("javax.swing.plaf.multi." + "MultiLookAndFeel"); if (getLAFState().multiLookAndFeel == null) { auxLookAndFeels = null; } } getLAFState().auxLookAndFeels = auxLookAndFeels; } private static void initializeSystemDefaults(Properties swingProps) { Object defaults[] = { "FocusManagerClassName", "javax.swing.DefaultFocusManager" }; getLAFState().setSystemDefaults(new UIDefaults(defaults)); getLAFState().swingProps = swingProps; } /* * This method is called before any code that depends on the * <code>AppContext</code> specific LAFState object runs. When the AppContext * corresponds to a set of applets it's possible for this method * to be re-entered, which is why we grab a lock before calling * initialize(). */ private static void maybeInitialize() { synchronized (classLock) { if (!getLAFState().initialized) { getLAFState().initialized = true; initialize(); } } } /* * Only called by maybeInitialize(). */ private static void initialize() { Properties swingProps = loadSwingProperties(); try { // We discourage the JIT during UI initialization. // JITing here tends to be counter-productive. java.lang.Compiler.disable(); initializeSystemDefaults(swingProps); initializeDefaultLAF(swingProps); initializeAuxiliaryLAFs(swingProps); initializeInstalledLAFs(swingProps); } finally { // Make sure to always re-enable the JIT. java.lang.Compiler.enable(); } // Enable the Swing default LayoutManager. if (FocusManager.isFocusManagerEnabled()) { KeyboardFocusManager.getCurrentKeyboardFocusManager(). setDefaultFocusTraversalPolicy( new LayoutFocusTraversalPolicy()); } // Install a hook that will be invoked if no one consumes the // KeyEvent. If the source isn't a JComponent this will process // key bindings, if the source is a JComponent it implies that // processKeyEvent was already invoked and thus no need to process // the bindings again, unless the Component is disabled, in which // case KeyEvents will no longer be dispatched to it so that we // handle it here. KeyboardFocusManager.getCurrentKeyboardFocusManager(). addKeyEventPostProcessor(new KeyEventPostProcessor() { public boolean postProcessKeyEvent(KeyEvent e) { Component c = e.getComponent(); if ((!(c instanceof JComponent) || (c != null && !((JComponent)c).isEnabled())) && JComponent.KeyboardState.shouldProcess(e) && SwingUtilities.processKeyBindings(e)) { e.consume(); return true; } return false; } }); } }