- /*
- * @(#)LookAndFeel.java 1.36 04/05/05
- *
- * Copyright 2004 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 java.io.*;
-
- import java.util.StringTokenizer;
-
-
- /**
- * Completely characterizes a look and feel from the point of view
- * of the pluggable look and feel components.
- *
- * @version 1.36 05/05/04
- * @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.
- * <p>
- * Return an array of KeyBindings, one for each KeyStroke,Action pair
- * in <b>keyBindingList</b>. A KeyStroke can either be a string in
- * the format specified by the <code>KeyStroke.getKeyStroke</code>
- * method or a KeyStroke object.
- * <p>
- * Actions are strings. Here's an example:
- * <pre>
- * 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
- * });
- * </pre>
- *
- * @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 <code>keys</code>. <code>keys</code>
- * describes the InputMap, with every even number item being a String
- * giving the KeyStroke as speced in
- * <code>KeyStroke.getKeyStroke(String)</code>
- * (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 <code>keys</code>. <code>keys</code>
- * describes the InputMap, with every even number item being a String
- * giving
- * the KeyStroke as speced in <code>KeyStroke.getKeyStroke(String)</code>
- * (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 <code>keys</code> into <code>retMap</code>.
- * This does not remove any existing bindings in <code>retMap</code>.
- * <code>keys</code>
- * describes the InputMap, with every even number item being a String
- * giving
- * the KeyStroke as speced in <code>KeyStroke.getKeyStroke(String)</code>
- * (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 <code>gifFile</code>
- * filename.
- */
- public static Object makeIcon(final Class<?> baseClass, final String gifFile) {
- return new UIDefaults.LazyValue() {
- public Object createValue(UIDefaults table) {
- /* Copy resource into a byte array. This is
- * necessary because several browsers consider
- * Class.getResource a security risk because it
- * can be used to load additional classes.
- * Class.getResourceAsStream just returns raw
- * bytes, which we can convert to an image.
- */
- byte[] buffer = (byte[])
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- public Object run() {
- try {
- InputStream resource =
- baseClass.getResourceAsStream(gifFile);
- if (resource == null) {
- return null;
- }
- BufferedInputStream in =
- new BufferedInputStream(resource);
- ByteArrayOutputStream out =
- new ByteArrayOutputStream(1024);
- byte[] buffer = new byte[1024];
- int n;
- while ((n = in.read(buffer)) > 0) {
- out.write(buffer, 0, n);
- }
- in.close();
- out.flush();
- return out.toByteArray();
- } catch (IOException ioe) {
- System.err.println(ioe.toString());
- }
- return null;
- }
- });
-
- if (buffer == null) {
- System.err.println(baseClass.getName() + "/" +
- gifFile + " not found.");
- return null;
- }
- if (buffer.length == 0) {
- System.err.println("warning: " + gifFile +
- " is zero-length");
- return null;
- }
-
- return new IconUIResource(new ImageIcon(buffer));
- }
- };
- }
-
- /**
- * Invoked when the user attempts an invalid operation,
- * such as pasting into an uneditable <code>JTextField</code>
- * that has focus. The default implementation beeps. Subclasses
- * that wish different behavior should override this and provide
- * the additional feedback.
- *
- * @param component the <code>Component</code> the error occurred in,
- * may be <code>null</code>
- * indicating the error condition is not directly
- * associated with a <code>Component</code>
- * @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 <code>Toolkit.getDefaultToolkit().getDesktopProperty()</code>.
- * 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 <code>Icon</code> with a disabled appearance.
- * This method is used to generate a disabled <code>Icon</code> when
- * one has not been specified. For example, if you create a
- * <code>JButton</code> and only specify an <code>Icon</code> via
- * <code>setIcon</code> this method will be called to generate the
- * disabled <code>Icon</code>. If null is passed as <code>icon</code>
- * this method returns null.
- * <p>
- * 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 <code>Icon</code> for use by disabled
- * components that are also selected. This method is used to generate an
- * <code>Icon</code> for components that are in both the disabled and
- * selected states but do not have a specific <code>Icon</code> for this
- * state. For example, if you create a <code>JButton</code> and only
- * specify an <code>Icon</code> via <code>setIcon</code> this method
- * will be called to generate the disabled and selected
- * <code>Icon</code>. If null is passed as <code>icon</code> this method
- * returns null.
- * <p>
- * 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 <code>LookAndFeel</code> returned
- * <code>RootPaneUI</code> instances support providing Window decorations
- * in a <code>JRootPane</code>.
- * <p>
- * 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() + "]";
- }
- }