/* * @(#)LookAndFeel.java 1.38 05/01/04 * * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package javax.swing; import java.awt.Font; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.Color; import java.awt.Component; import java.awt.SystemColor; import java.awt.Toolkit; import javax.swing.text.*; import javax.swing.border.*; import javax.swing.plaf.*; import java.net.URL; import com.sun.java.swing.SwingUtilities2; import java.util.StringTokenizer; /** * Completely characterizes a look and feel from the point of view * of the pluggable look and feel components. * * @version 1.38 01/04/05 * @author Tom Ball * @author Hans Muller */ public abstract class LookAndFeel { /** * Convenience method for initializing a component's foreground * and background color properties with values from the current * defaults table. The properties are only set if the current * value is either null or a UIResource. * * @param c the target component for installing default color/font properties * @param defaultBgName the key for the default background * @param defaultFgName the key for the default foreground * * @see #installColorsAndFont * @see UIManager#getColor */ public static void installColors(JComponent c, String defaultBgName, String defaultFgName) { Color bg = c.getBackground(); if (bg == null || bg instanceof UIResource) { c.setBackground(UIManager.getColor(defaultBgName)); } Color fg = c.getForeground(); if (fg == null || fg instanceof UIResource) { c.setForeground(UIManager.getColor(defaultFgName)); } } /** * Convenience method for initializing a components foreground * background and font properties with values from the current * defaults table. The properties are only set if the current * value is either null or a UIResource. * * @param c the target component for installing default color/font properties * @param defaultBgName the key for the default background * @param defaultFgName the key for the default foreground * @param defaultFontName the key for the default font * * @see #installColors * @see UIManager#getColor * @see UIManager#getFont */ public static void installColorsAndFont(JComponent c, String defaultBgName, String defaultFgName, String defaultFontName) { Font f = c.getFont(); if (f == null || f instanceof UIResource) { c.setFont(UIManager.getFont(defaultFontName)); } installColors(c, defaultBgName, defaultFgName); } /** * Convenience method for installing a component's default Border * object on the specified component if either the border is * currently null or already an instance of UIResource. * @param c the target component for installing default border * @param defaultBorderName the key specifying the default border */ public static void installBorder(JComponent c, String defaultBorderName) { Border b = c.getBorder(); if (b == null || b instanceof UIResource) { c.setBorder(UIManager.getBorder(defaultBorderName)); } } /** * Convenience method for un-installing a component's default * border on the specified component if the border is * currently an instance of UIResource. * @param c the target component for uninstalling default border */ public static void uninstallBorder(JComponent c) { if (c.getBorder() instanceof UIResource) { c.setBorder(null); } } /** * Convenience method for installing a property with the specified name * and value on a component if that property has not already been set * by the client program. This method is intended to be used by * UI delegate instances that need to specify a default value for a * property of primitive type (boolean, int, ..), but do not wish * to override a value set by the client. Since primitive property * values cannot be wrapped with the UIResource marker, this method * uses private state to determine whether the property has been set * by the client. * @throws IllegalArgumentException if the specified property is not * one which can be set using this method * @throws ClassCastException may be thrown if the property value * specified does not match the property's type * @throws NullPointerException may be thrown if c or propertyValue is null * @param c the target component for installing the property * @param propertyName String containing the name of the property to be set * @param propertyValue Object containing the value of the property */ public static void installProperty(JComponent c, String propertyName, Object propertyValue) { c.setUIProperty(propertyName, propertyValue); } /** * Convenience method for building lists of KeyBindings. *

* Return an array of KeyBindings, one for each KeyStroke,Action pair * in keyBindingList. A KeyStroke can either be a string in * the format specified by the KeyStroke.getKeyStroke * method or a KeyStroke object. *

* Actions are strings. Here's an example: *

     * 	JTextComponent.KeyBinding[] multilineBindings = makeKeyBindings( new Object[] {
     *          "UP", DefaultEditorKit.upAction,
     *        "DOWN", DefaultEditorKit.downAction,
     *     "PAGE_UP", DefaultEditorKit.pageUpAction,
     *   "PAGE_DOWN", DefaultEditorKit.pageDownAction,
     *       "ENTER", DefaultEditorKit.insertBreakAction,
     *         "TAB", DefaultEditorKit.insertTabAction
     *  });
     * 
* * @param keyBindingList an array of KeyStroke,Action pairs * @return an array of KeyBindings */ public static JTextComponent.KeyBinding[] makeKeyBindings(Object[] keyBindingList) { JTextComponent.KeyBinding[] rv = new JTextComponent.KeyBinding[keyBindingList.length / 2]; for(int i = 0; i < keyBindingList.length; i += 2) { KeyStroke keystroke = (keyBindingList[i] instanceof KeyStroke) ? (KeyStroke)keyBindingList[i] : KeyStroke.getKeyStroke((String)keyBindingList[i]); String action = (String)keyBindingList[i+1]; rv[i / 2] = new JTextComponent.KeyBinding(keystroke, action); } return rv; } /** * Creates a InputMap from keys. keys * describes the InputMap, with every even number item being a String * giving the KeyStroke as speced in * KeyStroke.getKeyStroke(String) * (or a KeyStroke), and every odd number item the Object * used to determine the associated Action in an ActionMap. * * @since 1.3 */ public static InputMap makeInputMap(Object[] keys) { InputMap retMap = new InputMapUIResource(); loadKeyBindings(retMap, keys); return retMap; } /** * Creates a ComponentInputMap from keys. keys * describes the InputMap, with every even number item being a String * giving * the KeyStroke as speced in KeyStroke.getKeyStroke(String) * (or a KeyStroke), and every odd number item the Object * used to determine the associated Action in an ActionMap. * * @since 1.3 */ public static ComponentInputMap makeComponentInputMap(JComponent c, Object[] keys) { ComponentInputMap retMap = new ComponentInputMapUIResource(c); loadKeyBindings(retMap, keys); return retMap; } /** * Loads the bindings in keys into retMap. * This does not remove any existing bindings in retMap. * keys * describes the InputMap, with every even number item being a String * giving * the KeyStroke as speced in KeyStroke.getKeyStroke(String) * (or a KeyStroke), and every odd number item the Object * used to determine the associated Action in an ActionMap. * * @since 1.3 */ public static void loadKeyBindings(InputMap retMap, Object[] keys) { if (keys != null) { for (int counter = 0, maxCounter = keys.length; counter < maxCounter; counter++) { Object keyStrokeO = keys[counter++]; KeyStroke ks = (keyStrokeO instanceof KeyStroke) ? (KeyStroke)keyStrokeO : KeyStroke.getKeyStroke((String)keyStrokeO); retMap.put(ks, keys[counter]); } } } /** * Utility method that creates a UIDefaults.LazyValue that creates * an ImageIcon UIResource for the specified gifFile * filename. */ public static Object makeIcon(final Class baseClass, final String gifFile) { return SwingUtilities2.makeIcon(baseClass, baseClass, gifFile); } /** * Invoked when the user attempts an invalid operation, * such as pasting into an uneditable JTextField * that has focus. The default implementation beeps. Subclasses * that wish different behavior should override this and provide * the additional feedback. * * @param component the Component the error occurred in, * may be null * indicating the error condition is not directly * associated with a Component * @since 1.4 */ public void provideErrorFeedback(Component component) { Toolkit toolkit = null; if (component != null) { toolkit = component.getToolkit(); } else { toolkit = Toolkit.getDefaultToolkit(); } toolkit.beep(); } // provideErrorFeedback() /** * Returns the value of the specified system desktop property by * invoking Toolkit.getDefaultToolkit().getDesktopProperty(). * If the current value of the specified property is null, the * fallbackValue is returned. * @param systemPropertyName the name of the system desktop property being queried * @param fallbackValue the object to be returned as the value if the system value is null * @return the current value of the desktop property * * @see java.awt.Toolkit#getDesktopProperty * */ public static Object getDesktopPropertyValue(String systemPropertyName, Object fallbackValue) { Object value = Toolkit.getDefaultToolkit().getDesktopProperty(systemPropertyName); if (value == null) { return fallbackValue; } else if (value instanceof Color) { return new ColorUIResource((Color)value); } else if (value instanceof Font) { return new FontUIResource((Font)value); } return value; } /** * Returns an Icon with a disabled appearance. * This method is used to generate a disabled Icon when * one has not been specified. For example, if you create a * JButton and only specify an Icon via * setIcon this method will be called to generate the * disabled Icon. If null is passed as icon * this method returns null. *

* Some look and feels might not render the disabled Icon, in which * case they will ignore this. * * @param component JComponent that will display the Icon, may be null * @param icon Icon to generate disable icon from. * @return Disabled icon, or null if a suitable Icon can not be * generated. * @since 1.5 */ public Icon getDisabledIcon(JComponent component, Icon icon) { if (icon instanceof ImageIcon) { return new IconUIResource(new ImageIcon(GrayFilter. createDisabledImage(((ImageIcon)icon).getImage()))); } return null; } /** * Returns an Icon for use by disabled * components that are also selected. This method is used to generate an * Icon for components that are in both the disabled and * selected states but do not have a specific Icon for this * state. For example, if you create a JButton and only * specify an Icon via setIcon this method * will be called to generate the disabled and selected * Icon. If null is passed as icon this method * returns null. *

* Some look and feels might not render the disabled and selected Icon, * in which case they will ignore this. * * @param component JComponent that will display the Icon, may be null * @param icon Icon to generate disabled and selected icon from. * @return Disabled and Selected icon, or null if a suitable Icon can not * be generated. * @since 1.5 */ public Icon getDisabledSelectedIcon(JComponent component, Icon icon) { return getDisabledIcon(component, icon); } /** * Return a short string that identifies this look and feel, e.g. * "CDE/Motif". This string should be appropriate for a menu item. * Distinct look and feels should have different names, e.g. * a subclass of MotifLookAndFeel that changes the way a few components * are rendered should be called "CDE/Motif My Way"; something * that would be useful to a user trying to select a L&F from a list * of names. */ public abstract String getName(); /** * Return a string that identifies this look and feel. This string * will be used by applications/services that want to recognize * well known look and feel implementations. Presently * the well known names are "Motif", "Windows", "Mac", "Metal". Note * that a LookAndFeel derived from a well known superclass * that doesn't make any fundamental changes to the look or feel * shouldn't override this method. */ public abstract String getID(); /** * Return a one line description of this look and feel implementation, * e.g. "The CDE/Motif Look and Feel". This string is intended for * the user, e.g. in the title of a window or in a ToolTip message. */ public abstract String getDescription(); /** * Returns true if the LookAndFeel returned * RootPaneUI instances support providing Window decorations * in a JRootPane. *

* The default implementation returns false, subclasses that support * Window decorations should override this and return true. * * @return True if the RootPaneUI instances created support client side * decorations * @see JDialog#setDefaultLookAndFeelDecorated * @see JFrame#setDefaultLookAndFeelDecorated * @see JRootPane#setWindowDecorationStyle * @since 1.4 */ public boolean getSupportsWindowDecorations() { return false; } /** * If the underlying platform has a "native" look and feel, and this * is an implementation of it, return true. For example a CDE/Motif * look and implementation would return true when the underlying * platform was Solaris. */ public abstract boolean isNativeLookAndFeel(); /** * Return true if the underlying platform supports and or permits * this look and feel. This method returns false if the look * and feel depends on special resources or legal agreements that * aren't defined for the current platform. * * @see UIManager#setLookAndFeel */ public abstract boolean isSupportedLookAndFeel(); /** * UIManager.setLookAndFeel calls this method before the first * call (and typically the only call) to getDefaults(). Subclasses * should do any one-time setup they need here, rather than * in a static initializer, because look and feel class objects * may be loaded just to discover that isSupportedLookAndFeel() * returns false. * * @see #uninitialize * @see UIManager#setLookAndFeel */ public void initialize() { } /** * UIManager.setLookAndFeel calls this method just before we're * replaced by a new default look and feel. Subclasses may * choose to free up some resources here. * * @see #initialize */ public void uninitialize() { } /** * This method is called once by UIManager.setLookAndFeel to create * the look and feel specific defaults table. Other applications, * for example an application builder, may also call this method. * * @see #initialize * @see #uninitialize * @see UIManager#setLookAndFeel */ public UIDefaults getDefaults() { return null; } /** * Returns a string that displays and identifies this * object's properties. * * @return a String representation of this object */ public String toString() { return "[" + getDescription() + " - " + getClass().getName() + "]"; } }