home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 22.1 KB | 661 lines |
- /*
- * @(#)UIManager.java 1.54 98/02/23
- *
- * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the confidential and proprietary information of Sun
- * Microsystems, Inc. ("Confidential Information"). You shall not disclose
- * such Confidential Information and shall use it only in accordance with the
- * terms of the license agreement you entered into with Sun.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
- * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
- * OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
- * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
- * ITS DERIVATIVES.
- *
- */
- package java.awt.swing;
-
- import java.awt.Container;
- import java.awt.Window;
- import java.awt.Font;
- import java.awt.Color;
-
- import java.awt.swing.plaf.ComponentUI;
- import java.awt.swing.border.Border;
-
- import java.beans.PropertyChangeSupport;
- 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;
-
-
- /**
- * This class keeps track of the current look and feel and its
- * defaults.
- * <p>
- * We manage three levels of defaults: user defaults, look
- * and feel defaults, system defaults. A call to UIManager.get()
- * checks all three levels in order and returns the first non-null
- * value for a key, if any. A call to UIManager.put() just
- * affects the user defaults. Note that a call to
- * setLookAndFeel() doesn't affect the user defaults, it just
- * replaces the middle defaults "level".
- * <p>
- * Warning: 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 Swing1.0 applications. It will
- * not be possible to load serialized Swing1.0 objects with future releases
- * of Swing. The JDK1.2 release of Swing will be the compatibility
- * baseline for the serialized form of Swing objects.
- *
- * @version 1.54 02/23/98
- * @author Thomas Ball
- * @author Hans Muller
- */
- public class UIManager implements Serializable
- {
- /**
- * This class defines the state managed by the UIManager. For
- * Swing applications the fields in this class could just as well
- * be static members of UIManager 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 it's look and feel, see setLookAndFeel().
- * Doing so has no affect on other applets (or the browser).
- */
- private static class LAFState
- {
- private UIDefaults[] tables = new UIDefaults[2];
-
- boolean initialized = false;
- MultiUIDefaults multiUIDefaults = new MultiUIDefaults(tables);
- LookAndFeel lookAndFeel;
- LookAndFeel multiLookAndFeel = null;
- Vector auxLookAndFeels = null;
- PropertyChangeSupport changeSupport = new PropertyChangeSupport(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 AppContext key for our one LAFState instance.
- */
- private static final Object lafStateACKey = new StringBuffer("LookAndFeel State");
-
-
- /**
- * Return the LAFState object, lazily create one if neccessary. All access
- * to the LAFState fields is done via this method, e.g.:
- * <pre>
- * getLAFState().initialized = true;
- * </pre>
- */
- private static LAFState getLAFState() {
- LAFState rv = (LAFState)SwingUtilities.appContextGet(lafStateACKey);
- if (rv != null) {
- return rv;
- }
- synchronized(UIManager.class) {
- rv = (LAFState)SwingUtilities.appContextGet(lafStateACKey);
- if (rv != null) {
- return rv;
- }
- SwingUtilities.appContextPut(lafStateACKey, (rv = new LAFState()));
- 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";
-
- /**
- * 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;
- String homeDir = System.getProperty("java.home", "<java.home undefined>");
- return homeDir + sep + "lib" + sep + "swing.properties";
- }
-
-
- /**
- * Provide a little information about an installed LookAndFeel
- * for the sake of configuring a menu or for initial application
- * set up.
- *
- * @see #getInstalledLookAndFeels
- * @see LookAndFeel
- */
- public static class LookAndFeelInfo {
- private String name;
- private String className;
-
- public LookAndFeelInfo(String name, String className) {
- this.name = name;
- this.className = className;
- }
-
- /**
- * @return a name suitable for a menu or other presentation
- * @see LookAndFeel#getName
- */
- public String getName() {
- return name;
- }
-
- /**
- * @return the name of the class that implements this LookAndFeel.
- * @see LookAndFeel
- */
- public String getClassName() {
- return className;
- }
-
- public String toString() {
- return getClass().getName() + "[" + getName() + " " + getClassName() + "]";
- }
- }
-
-
- /**
- * The default value of installedLAFS 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", "java.awt.swing.plaf.metal.MetalLookAndFeel"),
- new LookAndFeelInfo("CDE/Motif", "java.awt.swing.plaf.motif.MotifLookAndFeel"),
- new LookAndFeelInfo("Windows", "java.awt.swing.plaf.windows.WindowsLookAndFeel")
- };
-
-
- /**
- * Return an array of objects that provide some information about the
- * LookAndFeel implementations that have been installed with this
- * java development kit. The LookAndFeel info objects can be 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 LookAndFeel classes themselves here to avoid the
- * cost of unnecessarily loading them.
- * <p>
- * Given a LookAndFeelInfo object one can set the current look and feel
- * like this:
- * <pre>
- * UIManager.setLookAndFeel(info.getClassName());
- * </pre>
- *
- * @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 LookAndFeelInfos.
- *
- * @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 setInstalledLookAndFeels.
- *
- * @see #setInstalledLookAndFeels
- */
- 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);
- }
-
-
- public static void installLookAndFeel(String name, String className) {
- installLookAndFeel(new LookAndFeelInfo(name, className));
- }
-
-
- /**
- * Returns The current default look and feel, or null.
- *
- * @return The current default look and feel, or null.
- * @see #setLookAndFeel
- */
- public static LookAndFeel getLookAndFeel() {
- maybeInitialize();
- return getLAFState().lookAndFeel;
- }
-
-
- /**
- * Set the current default look and feel.
- * <p>
- * This is a JavaBeans bound property.
- *
- * @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);
- }
-
-
- /**
- * @exception ClassNotFoundException If the LookAndFeel class could not be found.
- * @exception InstantiationException If a new instance of the class couldn't be creatd.
- * @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 = Class.forName(className);
- setLookAndFeel((LookAndFeel)(lnfClass.newInstance()));
- }
-
-
- /**
- * Returns the name of the LookAndFeel class that implements
- * the native systems look and feel if there is one,
- * otherwise the name of the default cross platform LookAndFeel
- * class.
- *
- * @see #setLookAndFeel()
- * @see #getCrossPlatformLookAndFeelClassName
- */
- public static String getSystemLookAndFeelClassName() {
- String osName = System.getProperty("os.name");
- if (osName != null) {
- if (osName.indexOf("Windows") != -1) {
- return "java.awt.swing.plaf.windows.WindowsLookAndFeel";
- }
- else if (osName.indexOf("Solaris") != -1) {
- return "java.awt.swing.plaf.motif.MotifLookAndFeel";
- }
- }
- return getCrossPlatformLookAndFeelClassName();
- }
-
-
- /**
- * Returns the name of the LookAndFeel class that implements
- * the default cross platform look and feel, i.e. the "metal"
- * look and feel.
- *
- * @return "java.awt.swing.plaf.metal.MetalLookAndFeel"
- * @see #setLookAndFeel()
- * @see #getSystemLookAndFeelClassName
- */
- public static String getCrossPlatformLookAndFeelClassName() {
- return "java.awt.swing.plaf.metal.MetalLookAndFeel";
- }
-
-
- public static UIDefaults getDefaults() {
- maybeInitialize();
- return getLAFState().multiUIDefaults;
- }
-
- public static Font getFont(Object key) {
- return getDefaults().getFont(key);
- }
-
- public static Color getColor(Object key) {
- return getDefaults().getColor(key);
- }
-
- public static Icon getIcon(Object key) {
- return getDefaults().getIcon(key);
- }
-
- public static Border getBorder(Object key) {
- return getDefaults().getBorder(key);
- }
-
- public static String getString(Object key) {
- return getDefaults().getString(key);
- }
-
- public static Object get(Object key) {
- return getDefaults().get(key);
- }
-
- public static Object put(Object key, Object value) {
- return getDefaults().put(key, value);
- }
-
- 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;
- }
-
-
- public static UIDefaults getLookAndFeelDefaults() {
- maybeInitialize();
- return getLAFState().getLookAndFeelDefaults();
- }
-
-
- /**
- * Return the list of auxiliary look and feels (can be null). The
- * auxiliary look and feels tell the multiplexing look and feel what
- * other LookAndFeel 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.
- * @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;
- }
- }
-
-
- /**
- * Add a PropertyChangeListener to the listener list.
- * The listener is registered for all properties.
- *
- * @param listener The PropertyChangeListener to be added
- * @see java.beans.PropertyChangeSupport
- */
- public synchronized static void addPropertyChangeListener(PropertyChangeListener listener)
- {
- getLAFState().changeSupport.addPropertyChangeListener(listener);
- }
-
-
- /**
- * Remove a PropertyChangeListener from the listener list.
- * This removes a PropertyChangeListener that was registered
- * for all properties.
- *
- * @param listener The PropertyChangeListener to be removed
- * @see java.beans.PropertyChangeSupport
- */
- public synchronized static void removePropertyChangeListener(PropertyChangeListener listener)
- {
- getLAFState().changeSupport.removePropertyChangeListener(listener);
- }
-
-
- private static Properties loadSwingProperties()
- {
- Properties properties = new Properties();
-
- if (UIManager.class.getClassLoader() == null) {
- String sep = File.separator;
- try {
- File propertiesFile = new File(makeSwingPropertiesFilename());
- BufferedInputStream ins = new BufferedInputStream(
- new FileInputStream(propertiesFile));
- properties.load(ins);
- ins.close();
- }
- catch (Exception e) {
- properties.clear();
- }
- }
-
- return properties;
- }
-
-
- /**
- * If a swing.properties file exist and it has a swing.installedlafs property
- * then initialize the installedLAFs 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 expclicitly
- * 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);
- Class lnfClass = Class.forName(lnfName);
- setLookAndFeel((LookAndFeel)(lnfClass.newInstance()));
- } catch (Exception e) {
- try {
- lnfName = swingProps.getProperty(defaultLAFKey, metalLnf);
- Class lnfClass = Class.forName(lnfName);
- setLookAndFeel((LookAndFeel)(lnfClass.newInstance()));
- } 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 = Class.forName(className);
- auxLookAndFeels.addElement(lnfClass.newInstance());
- }
- 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 {
- String defaultName = "java.awt.swing.plaf.multi.MultiLookAndFeel";
- String className = swingProps.getProperty(multiplexingLAFKey, defaultName);
- try {
- Class lnfClass = Class.forName(className);
- getLAFState().multiLookAndFeel = (LookAndFeel)lnfClass.newInstance();
- }
- catch (Exception exc) {
- System.err.println("UIManager: failed loading " + className);
- auxLookAndFeels = null;
- }
- }
-
- getLAFState().auxLookAndFeels = auxLookAndFeels;
- }
-
-
- private static void initializeSystemDefaults(Properties swingProps)
- {
- Object defaults[] = {
- "FocusManagerClassName", "java.awt.swing.DefaultFocusManager"
- };
- getLAFState().setSystemDefaults(new UIDefaults(defaults));
- }
-
-
- private static void initialize()
- {
- Properties swingProps = loadSwingProperties();
- initializeSystemDefaults(swingProps);
- initializeDefaultLAF(swingProps);
- initializeAuxiliaryLAFs(swingProps);
- initializeInstalledLAFs(swingProps);
- }
-
-
- synchronized private static void maybeInitialize() {
- if (!getLAFState().initialized) {
- initialize();
- getLAFState().initialized = true;
- }
- }
- }
-