1 /*
   2  * Copyright (c) 1997, 2013, 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 
  26 package javax.swing;
  27 
  28 import java.awt.Font;
  29 import java.awt.event.InputEvent;
  30 import java.awt.event.KeyEvent;
  31 import java.awt.Color;
  32 import java.awt.Component;
  33 import java.awt.SystemColor;
  34 import java.awt.Toolkit;
  35 import sun.awt.SunToolkit;
  36 
  37 import javax.swing.text.*;
  38 import javax.swing.border.*;
  39 import javax.swing.plaf.*;
  40 
  41 import java.net.URL;
  42 import sun.swing.SwingUtilities2;
  43 import sun.swing.DefaultLayoutStyle;
  44 import sun.swing.ImageIconUIResource;
  45 
  46 import java.util.StringTokenizer;
  47 
  48 
  49 /**
  50  * {@code LookAndFeel}, as the name implies, encapsulates a look and
  51  * feel. Beyond installing a look and feel most developers never need to
  52  * interact directly with {@code LookAndFeel}. In general only developers
  53  * creating a custom look and feel need to concern themselves with this class.
  54  * <p>
  55  * Swing is built upon the foundation that each {@code JComponent}
  56  * subclass has an implementation of a specific {@code ComponentUI}
  57  * subclass. The {@code ComponentUI} is often referred to as "the ui",
  58  * "component ui", or "look and feel delegate". The {@code ComponentUI}
  59  * subclass is responsible for providing the look and feel specific
  60  * functionality of the component. For example, {@code JTree} requires
  61  * an implementation of the {@code ComponentUI} subclass {@code
  62  * TreeUI}. The implementation of the specific {@code
  63  * ComponentUI} subclass is provided by the {@code LookAndFeel}. Each
  64  * {@code JComponent} subclass identifies the {@code ComponentUI}
  65  * subclass it requires by way of the {@code JComponent} method {@code
  66  * getUIClassID}.
  67  * <p>
  68  * Each {@code LookAndFeel} implementation must provide
  69  * an implementation of the appropriate {@code ComponentUI} subclass by
  70  * specifying a value for each of Swing's ui class ids in the {@code
  71  * UIDefaults} object returned from {@code getDefaults}. For example,
  72  * {@code BasicLookAndFeel} uses {@code BasicTreeUI} as the concrete
  73  * implementation for {@code TreeUI}. This is accomplished by {@code
  74  * BasicLookAndFeel} providing the key-value pair {@code
  75  * "TreeUI"-"javax.swing.plaf.basic.BasicTreeUI"}, in the
  76  * {@code UIDefaults} returned from {@code getDefaults}. Refer to
  77  * {@link UIDefaults#getUI(JComponent)} for details on how the implementation
  78  * of the {@code ComponentUI} subclass is obtained.
  79  * <p>
  80  * When a {@code LookAndFeel} is installed the {@code UIManager} does
  81  * not check that an entry exists for all ui class ids. As such,
  82  * random exceptions will occur if the current look and feel has not
  83  * provided a value for a particular ui class id and an instance of
  84  * the {@code JComponent} subclass is created.
  85  *
  86  * <h2>Recommendations for Look and Feels</h2>
  87  *
  88  * As noted in {@code UIManager} each {@code LookAndFeel} has the opportunity
  89  * to provide a set of defaults that are layered in with developer and
  90  * system defaults. Some of Swing's components require the look and feel
  91  * to provide a specific set of defaults. These are documented in the
  92  * classes that require the specific default.
  93  *
  94  * <h3><a name="defaultRecommendation">ComponentUIs and defaults</a></h3>
  95  *
  96  * All {@code ComponentUIs} typically need to set various properties
  97  * on the {@code JComponent} the {@code ComponentUI} is providing the
  98  * look and feel for. This is typically done when the {@code
  99  * ComponentUI} is installed on the {@code JComponent}. Setting a
 100  * property should only be done if the developer has not set the
 101  * property. For non-primitive values it is recommended that the
 102  * {@code ComponentUI} only change the property on the {@code
 103  * JComponent} if the current value is {@code null} or implements
 104  * {@code UIResource}. If the current value is {@code null} or
 105  * implements {@code UIResource} it indicates the property has not
 106  * been set by the developer, and the ui is free to change it.  For
 107  * example, {@code BasicButtonUI.installDefaults} only changes the
 108  * font on the {@code JButton} if the return value from {@code
 109  * button.getFont()} is {@code null} or implements {@code
 110  * UIResource}. On the other hand if {@code button.getFont()} returned
 111  * a {@code non-null} value that did not implement {@code UIResource}
 112  * then {@code BasicButtonUI.installDefaults} would not change the
 113  * {@code JButton}'s font.
 114  * <p>
 115  * For primitive values, such as {@code opaque}, the method {@code
 116  * installProperty} should be invoked.  {@code installProperty} only changes
 117  * the corresponding property if the value has not been changed by the
 118  * developer.
 119  * <p>
 120  * {@code ComponentUI} implementations should use the various install methods
 121  * provided by this class as they handle the necessary checking and install
 122  * the property using the recommended guidelines.
 123  *
 124  * <h3><a name="exceptions"></a>Exceptions</h3>
 125  *
 126  * All of the install methods provided by {@code LookAndFeel} need to
 127  * access the defaults if the value of the property being changed is
 128  * {@code null} or a {@code UIResource}. For example, installing the
 129  * font does the following:
 130  * <pre>
 131  *   JComponent c;
 132  *   Font font = c.getFont();
 133  *   if (font == null || (font instanceof UIResource)) {
 134  *       c.setFont(UIManager.getFont("fontKey"));
 135  *   }
 136  * </pre>
 137  * If the font is {@code null} or a {@code UIResource}, the
 138  * defaults table is queried with the key {@code fontKey}. All of
 139  * {@code UIDefault's} get methods throw a {@code
 140  * NullPointerException} if passed in {@code null}. As such, unless
 141  * otherwise noted each of the various install methods of {@code
 142  * LookAndFeel} throw a {@code NullPointerException} if the current
 143  * value is {@code null} or a {@code UIResource} and the supplied
 144  * defaults key is {@code null}. In addition, unless otherwise specified
 145  * all of the {@code install} methods throw a {@code NullPointerException} if
 146  * a {@code null} component is passed in.
 147  *
 148  * @author Tom Ball
 149  * @author Hans Muller
 150  * @since 1.2
 151  */
 152 public abstract class LookAndFeel
 153 {
 154 
 155     /**
 156      * Convenience method for setting a component's foreground
 157      * and background color properties with values from the
 158      * defaults.  The properties are only set if the current
 159      * value is either {@code null} or a {@code UIResource}.
 160      *
 161      * @param c component to set the colors on
 162      * @param defaultBgName key for the background
 163      * @param defaultFgName key for the foreground
 164      *
 165      * @see #installColorsAndFont
 166      * @see UIManager#getColor
 167      * @throws NullPointerException as described in
 168      *         <a href="#exceptions">exceptions</a>
 169      */
 170     public static void installColors(JComponent c,
 171                                      String defaultBgName,
 172                                      String defaultFgName)
 173     {
 174         Color bg = c.getBackground();
 175         if (bg == null || bg instanceof UIResource) {
 176             c.setBackground(UIManager.getColor(defaultBgName));
 177         }
 178 
 179         Color fg = c.getForeground();
 180         if (fg == null || fg instanceof UIResource) {
 181             c.setForeground(UIManager.getColor(defaultFgName));
 182         }
 183     }
 184 
 185 
 186     /**
 187      * Convenience method for setting a component's foreground,
 188      * background and font properties with values from the
 189      * defaults.  The properties are only set if the current
 190      * value is either {@code null} or a {@code UIResource}.
 191      *
 192      * @param c component set to the colors and font on
 193      * @param defaultBgName key for the background
 194      * @param defaultFgName key for the foreground
 195      * @param defaultFontName key for the font
 196      * @throws NullPointerException as described in
 197      *         <a href="#exceptions">exceptions</a>
 198      *
 199      * @see #installColors
 200      * @see UIManager#getColor
 201      * @see UIManager#getFont
 202      */
 203     public static void installColorsAndFont(JComponent c,
 204                                          String defaultBgName,
 205                                          String defaultFgName,
 206                                          String defaultFontName) {
 207         Font f = c.getFont();
 208         if (f == null || f instanceof UIResource) {
 209             c.setFont(UIManager.getFont(defaultFontName));
 210         }
 211 
 212         installColors(c, defaultBgName, defaultFgName);
 213     }
 214 
 215 
 216     /**
 217      * Convenience method for setting a component's border property with
 218      * a value from the defaults. The border is only set if the border is
 219      * {@code null} or an instance of {@code UIResource}.
 220      *
 221      * @param c component to set the border on
 222      * @param defaultBorderName key specifying the border
 223      * @throws NullPointerException as described in
 224      *         <a href="#exceptions">exceptions</a>
 225      */
 226     public static void installBorder(JComponent c, String defaultBorderName) {
 227         Border b = c.getBorder();
 228         if (b == null || b instanceof UIResource) {
 229             c.setBorder(UIManager.getBorder(defaultBorderName));
 230         }
 231     }
 232 
 233 
 234     /**
 235      * Convenience method for uninstalling a border. If the border of
 236      * the component is a {@code UIResource}, it is set to {@code
 237      * null}.
 238      *
 239      * @param c component to uninstall the border on
 240      * @throws NullPointerException if {@code c} is {@code null}
 241      */
 242     public static void uninstallBorder(JComponent c) {
 243         if (c.getBorder() instanceof UIResource) {
 244             c.setBorder(null);
 245         }
 246     }
 247 
 248     /**
 249      * Convenience method for installing a property with the specified name
 250      * and value on a component if that property has not already been set
 251      * by the developer.  This method is intended to be used by
 252      * ui delegate instances that need to specify a default value for a
 253      * property of primitive type (boolean, int, ..), but do not wish
 254      * to override a value set by the client.  Since primitive property
 255      * values cannot be wrapped with the {@code UIResource} marker, this method
 256      * uses private state to determine whether the property has been set
 257      * by the client.
 258      *
 259      * @throws IllegalArgumentException if the specified property is not
 260      *         one which can be set using this method
 261      * @throws ClassCastException if the property value has not been set
 262      *         by the developer and the type does not match the property's type
 263      * @throws NullPointerException if {@code c} is {@code null}, or the
 264      *         named property has not been set by the developer and
 265      *         {@code propertyValue} is {@code null}
 266      * @param c target component to set the property on
 267      * @param propertyName name of the property to set
 268      * @param propertyValue value of the property
 269      * @since 1.5
 270      */
 271     public static void installProperty(JComponent c,
 272                                        String propertyName, Object propertyValue) {
 273         // this is a special case because the JPasswordField's ancestor hierarchy
 274         // includes a class outside of javax.swing, thus we cannot call setUIProperty
 275         // directly.
 276         if (SunToolkit.isInstanceOf(c, "javax.swing.JPasswordField")) {
 277             if (!((JPasswordField)c).customSetUIProperty(propertyName, propertyValue)) {
 278                 c.setUIProperty(propertyName, propertyValue);
 279             }
 280         } else {
 281             c.setUIProperty(propertyName, propertyValue);
 282         }
 283     }
 284 
 285     /**
 286      * Convenience method for building an array of {@code
 287      * KeyBindings}. While this method is not deprecated, developers
 288      * should instead use {@code ActionMap} and {@code InputMap} for
 289      * supplying key bindings.
 290      * <p>
 291      * This method returns an array of {@code KeyBindings}, one for each
 292      * alternating {@code key-action} pair in {@code keyBindingList}.
 293      * A {@code key} can either be a {@code String} in the format
 294      * specified by the <code>KeyStroke.getKeyStroke</code> method, or
 295      * a {@code KeyStroke}. The {@code action} part of the pair is a
 296      * {@code String} that corresponds to the name of the {@code
 297      * Action}.
 298      * <p>
 299      * The following example illustrates creating a {@code KeyBinding} array
 300      * from six alternating {@code key-action} pairs:
 301      * <pre>
 302      *  JTextComponent.KeyBinding[] multilineBindings = makeKeyBindings( new Object[] {
 303      *          "UP", DefaultEditorKit.upAction,
 304      *        "DOWN", DefaultEditorKit.downAction,
 305      *     "PAGE_UP", DefaultEditorKit.pageUpAction,
 306      *   "PAGE_DOWN", DefaultEditorKit.pageDownAction,
 307      *       "ENTER", DefaultEditorKit.insertBreakAction,
 308      *         "TAB", DefaultEditorKit.insertTabAction
 309      *  });
 310      * </pre>
 311      * If {@code keyBindingList's} length is odd, the last element is
 312      * ignored.
 313      * <p>
 314      * Supplying a {@code null} value for either the {@code key} or
 315      * {@code action} part of the {@code key-action} pair results in
 316      * creating a {@code KeyBinding} with the corresponding value
 317      * {@code null}. As other parts of Swing's expect {@code non-null} values
 318      * in a {@code KeyBinding}, you should avoid supplying {@code null} as
 319      * either the {@code key} or {@code action} part of the {@code key-action}
 320      * pair.
 321      *
 322      * @param keyBindingList an array of {@code key-action} pairs
 323      * @return an array of {@code KeyBindings}
 324      * @throws NullPointerException if {@code keyBindingList} is {@code null}
 325      * @throws ClassCastException if the {@code key} part of the pair is
 326      *         not a {@code KeyStroke} or {@code String}, or the
 327      *         {@code action} part of the pair is not a {@code String}
 328      * @see ActionMap
 329      * @see InputMap
 330      * @see KeyStroke#getKeyStroke
 331      */
 332     public static JTextComponent.KeyBinding[] makeKeyBindings(Object[] keyBindingList)
 333     {
 334         JTextComponent.KeyBinding[] rv = new JTextComponent.KeyBinding[keyBindingList.length / 2];
 335 
 336         for(int i = 0; i < rv.length; i ++) {
 337             Object o = keyBindingList[2 * i];
 338             KeyStroke keystroke = (o instanceof KeyStroke)
 339                 ? (KeyStroke) o
 340                 : KeyStroke.getKeyStroke((String) o);
 341             String action = (String) keyBindingList[2 * i + 1];
 342             rv[i] = new JTextComponent.KeyBinding(keystroke, action);
 343         }
 344 
 345         return rv;
 346     }
 347 
 348     /**
 349      * Creates a {@code InputMapUIResource} from <code>keys</code>. This is
 350      * a convenience method for creating a new {@code InputMapUIResource},
 351      * invoking {@code loadKeyBindings(map, keys)}, and returning the
 352      * {@code InputMapUIResource}.
 353      *
 354      * @param keys alternating pairs of {@code keystroke-action key}
 355      *        pairs as described in {@link #loadKeyBindings}
 356      * @return newly created and populated {@code InputMapUIResource}
 357      * @see #loadKeyBindings
 358      *
 359      * @since 1.3
 360      */
 361     public static InputMap makeInputMap(Object[] keys) {
 362         InputMap retMap = new InputMapUIResource();
 363         loadKeyBindings(retMap, keys);
 364         return retMap;
 365     }
 366 
 367     /**
 368      * Creates a {@code ComponentInputMapUIResource} from
 369      * <code>keys</code>. This is a convenience method for creating a
 370      * new {@code ComponentInputMapUIResource}, invoking {@code
 371      * loadKeyBindings(map, keys)}, and returning the {@code
 372      * ComponentInputMapUIResource}.
 373      *
 374      * @param c component to create the {@code ComponentInputMapUIResource}
 375      *          with
 376      * @param keys alternating pairs of {@code keystroke-action key}
 377      *        pairs as described in {@link #loadKeyBindings}
 378      * @return newly created and populated {@code InputMapUIResource}
 379      * @throws IllegalArgumentException if {@code c} is {@code null}
 380      *
 381      * @see #loadKeyBindings
 382      * @see ComponentInputMapUIResource
 383      *
 384      * @since 1.3
 385      */
 386     public static ComponentInputMap makeComponentInputMap(JComponent c,
 387                                                           Object[] keys) {
 388         ComponentInputMap retMap = new ComponentInputMapUIResource(c);
 389         loadKeyBindings(retMap, keys);
 390         return retMap;
 391     }
 392 
 393 
 394     /**
 395      * Populates an {@code InputMap} with the specified bindings.
 396      * The bindings are supplied as a list of alternating
 397      * {@code keystroke-action key} pairs. The {@code keystroke} is either
 398      * an instance of {@code KeyStroke}, or a {@code String}
 399      * that identifies the {@code KeyStroke} for the binding. Refer
 400      * to {@code KeyStroke.getKeyStroke(String)} for the specific
 401      * format. The {@code action key} part of the pair is the key
 402      * registered in the {@code InputMap} for the {@code KeyStroke}.
 403      * <p>
 404      * The following illustrates loading an {@code InputMap} with two
 405      * {@code key-action} pairs:
 406      * <pre>
 407      *   LookAndFeel.loadKeyBindings(inputMap, new Object[] {
 408      *     "control X", "cut",
 409      *     "control V", "paste"
 410      *   });
 411      * </pre>
 412      * <p>
 413      * Supplying a {@code null} list of bindings ({@code keys}) does not
 414      * change {@code retMap} in any way.
 415      * <p>
 416      * Specifying a {@code null} {@code action key} results in
 417      * removing the {@code keystroke's} entry from the {@code InputMap}.
 418      * A {@code null} {@code keystroke} is ignored.
 419      *
 420      * @param retMap {@code InputMap} to add the {@code key-action}
 421      *               pairs to
 422      * @param keys bindings to add to {@code retMap}
 423      * @throws NullPointerException if {@code keys} is
 424      *         {@code non-null}, not empty, and {@code retMap} is
 425      *         {@code null}
 426      *
 427      * @see KeyStroke#getKeyStroke(String)
 428      * @see InputMap
 429      *
 430      * @since 1.3
 431      */
 432     public static void loadKeyBindings(InputMap retMap, Object[] keys) {
 433         if (keys != null) {
 434             for (int counter = 0, maxCounter = keys.length;
 435                  counter < maxCounter; counter++) {
 436                 Object keyStrokeO = keys[counter++];
 437                 KeyStroke ks = (keyStrokeO instanceof KeyStroke) ?
 438                                 (KeyStroke)keyStrokeO :
 439                                 KeyStroke.getKeyStroke((String)keyStrokeO);
 440                 retMap.put(ks, keys[counter]);
 441             }
 442         }
 443     }
 444 
 445     /**
 446      * Creates and returns a {@code UIDefault.LazyValue} that loads an
 447      * image. The returned value is an implementation of {@code
 448      * UIDefaults.LazyValue}. When {@code createValue} is invoked on
 449      * the returned object, the image is loaded. If the image is {@code
 450      * non-null}, it is then wrapped in an {@code Icon} that implements {@code
 451      * UIResource}. The image is loaded using {@code
 452      * Class.getResourceAsStream(gifFile)}.
 453      * <p>
 454      * This method does not check the arguments in any way. It is
 455      * strongly recommended that {@code non-null} values are supplied else
 456      * exceptions may occur when {@code createValue} is invoked on the
 457      * returned object.
 458      *
 459      * @param baseClass {@code Class} used to load the resource
 460      * @param gifFile path to the image to load
 461      * @return a {@code UIDefaults.LazyValue}; when resolved the
 462      *         {@code LazyValue} loads the specified image
 463      * @see UIDefaults.LazyValue
 464      * @see Icon
 465      * @see Class#getResourceAsStream(String)
 466      */
 467     public static Object makeIcon(final Class<?> baseClass, final String gifFile) {
 468         return SwingUtilities2.makeIcon_Unprivileged(baseClass, baseClass, gifFile);
 469     }
 470 
 471     /**
 472      * Returns the <code>LayoutStyle</code> for this look
 473      * and feel.  This never returns {@code null}.
 474      * <p>
 475      * You generally don't use the <code>LayoutStyle</code> from
 476      * the look and feel, instead use the <code>LayoutStyle</code>
 477      * method <code>getInstance</code>.
 478      *
 479      * @see LayoutStyle#getInstance
 480      * @return the <code>LayoutStyle</code> for this look and feel
 481      * @since 1.6
 482      */
 483     public LayoutStyle getLayoutStyle() {
 484         return DefaultLayoutStyle.getInstance();
 485     }
 486 
 487     /**
 488      * Invoked when the user attempts an invalid operation,
 489      * such as pasting into an uneditable <code>JTextField</code>
 490      * that has focus. The default implementation beeps. Subclasses
 491      * that wish different behavior should override this and provide
 492      * the additional feedback.
 493      *
 494      * @param component the <code>Component</code> the error occurred in,
 495      *                  may be <code>null</code>
 496      *                  indicating the error condition is not directly
 497      *                  associated with a <code>Component</code>
 498      * @since 1.4
 499      */
 500     public void provideErrorFeedback(Component component) {
 501         Toolkit toolkit = null;
 502         if (component != null) {
 503             toolkit = component.getToolkit();
 504         } else {
 505             toolkit = Toolkit.getDefaultToolkit();
 506         }
 507         toolkit.beep();
 508     } // provideErrorFeedback()
 509 
 510     /**
 511      * Returns the value of the specified system desktop property by
 512      * invoking <code>Toolkit.getDefaultToolkit().getDesktopProperty()</code>.
 513      * If the value of the specified property is {@code null},
 514      * {@code fallbackValue} is returned.
 515      *
 516      * @param systemPropertyName the name of the system desktop property being queried
 517      * @param fallbackValue the object to be returned as the value if the system value is null
 518      * @return the current value of the desktop property
 519      *
 520      * @see java.awt.Toolkit#getDesktopProperty
 521      *
 522      * @since 1.4
 523      */
 524     public static Object getDesktopPropertyValue(String systemPropertyName, Object fallbackValue) {
 525         Object value = Toolkit.getDefaultToolkit().getDesktopProperty(systemPropertyName);
 526         if (value == null) {
 527             return fallbackValue;
 528         } else if (value instanceof Color) {
 529             return new ColorUIResource((Color)value);
 530         } else if (value instanceof Font) {
 531             return new FontUIResource((Font)value);
 532         }
 533         return value;
 534     }
 535 
 536     /**
 537      * Returns an <code>Icon</code> with a disabled appearance.
 538      * This method is used to generate a disabled <code>Icon</code> when
 539      * one has not been specified.  For example, if you create a
 540      * <code>JButton</code> and only specify an <code>Icon</code> via
 541      * <code>setIcon</code> this method will be called to generate the
 542      * disabled <code>Icon</code>. If {@code null} is passed as
 543      * <code>icon</code> this method returns {@code null}.
 544      * <p>
 545      * Some look and feels might not render the disabled {@code Icon}, in which
 546      * case they will ignore this.
 547      *
 548      * @param component {@code JComponent} that will display the {@code Icon},
 549      *         may be {@code null}
 550      * @param icon {@code Icon} to generate the disabled icon from
 551      * @return disabled {@code Icon}, or {@code null} if a suitable
 552      *         {@code Icon} can not be generated
 553      * @since 1.5
 554      */
 555     public Icon getDisabledIcon(JComponent component, Icon icon) {
 556         if (icon instanceof ImageIcon) {
 557             return new ImageIconUIResource(GrayFilter.
 558                    createDisabledImage(((ImageIcon)icon).getImage()));
 559         }
 560         return null;
 561     }
 562 
 563     /**
 564      * Returns an <code>Icon</code> for use by disabled
 565      * components that are also selected. This method is used to generate an
 566      * <code>Icon</code> for components that are in both the disabled and
 567      * selected states but do not have a specific <code>Icon</code> for this
 568      * state.  For example, if you create a <code>JButton</code> and only
 569      * specify an <code>Icon</code> via <code>setIcon</code> this method
 570      * will be called to generate the disabled and selected
 571      * <code>Icon</code>. If {@code null} is passed as <code>icon</code> this
 572      * methods returns {@code null}.
 573      * <p>
 574      * Some look and feels might not render the disabled and selected
 575      * {@code Icon}, in which case they will ignore this.
 576      *
 577      * @param component {@code JComponent} that will display the {@code Icon},
 578      *        may be {@code null}
 579      * @param icon {@code Icon} to generate disabled and selected icon from
 580      * @return disabled and selected icon, or {@code null} if a suitable
 581      *         {@code Icon} can not be generated.
 582      * @since 1.5
 583      */
 584     public Icon getDisabledSelectedIcon(JComponent component, Icon icon) {
 585         return getDisabledIcon(component, icon);
 586     }
 587 
 588     /**
 589      * Return a short string that identifies this look and feel, e.g.
 590      * "CDE/Motif".  This string should be appropriate for a menu item.
 591      * Distinct look and feels should have different names, e.g.
 592      * a subclass of MotifLookAndFeel that changes the way a few components
 593      * are rendered should be called "CDE/Motif My Way"; something
 594      * that would be useful to a user trying to select a L&amp;F from a list
 595      * of names.
 596      *
 597      * @return short identifier for the look and feel
 598      */
 599     public abstract String getName();
 600 
 601 
 602     /**
 603      * Return a string that identifies this look and feel.  This string
 604      * will be used by applications/services that want to recognize
 605      * well known look and feel implementations.  Presently
 606      * the well known names are "Motif", "Windows", "Mac", "Metal".  Note
 607      * that a LookAndFeel derived from a well known superclass
 608      * that doesn't make any fundamental changes to the look or feel
 609      * shouldn't override this method.
 610      *
 611      * @return identifier for the look and feel
 612      */
 613     public abstract String getID();
 614 
 615 
 616     /**
 617      * Return a one line description of this look and feel implementation,
 618      * e.g. "The CDE/Motif Look and Feel".   This string is intended for
 619      * the user, e.g. in the title of a window or in a ToolTip message.
 620      *
 621      * @return short description for the look and feel
 622      */
 623     public abstract String getDescription();
 624 
 625 
 626     /**
 627      * Returns {@code true} if the <code>LookAndFeel</code> returned
 628      * <code>RootPaneUI</code> instances support providing {@code Window}
 629      * decorations in a <code>JRootPane</code>.
 630      * <p>
 631      * The default implementation returns {@code false}, subclasses that
 632      * support {@code Window} decorations should override this and return
 633      * {@code true}.
 634      *
 635      * @return {@code true} if the {@code RootPaneUI} instances created by
 636      *         this look and feel support client side decorations
 637      * @see JDialog#setDefaultLookAndFeelDecorated
 638      * @see JFrame#setDefaultLookAndFeelDecorated
 639      * @see JRootPane#setWindowDecorationStyle
 640      * @since 1.4
 641      */
 642     public boolean getSupportsWindowDecorations() {
 643         return false;
 644     }
 645 
 646     /**
 647      * If the underlying platform has a "native" look and feel, and
 648      * this is an implementation of it, return {@code true}.  For
 649      * example, when the underlying platform is Solaris running CDE
 650      * a CDE/Motif look and feel implementation would return {@code
 651      * true}.
 652      *
 653      * @return {@code true} if this look and feel represents the underlying
 654      *         platform look and feel
 655      */
 656     public abstract boolean isNativeLookAndFeel();
 657 
 658 
 659     /**
 660      * Return {@code true} if the underlying platform supports and or permits
 661      * this look and feel.  This method returns {@code false} if the look
 662      * and feel depends on special resources or legal agreements that
 663      * aren't defined for the current platform.
 664      *
 665      *
 666      * @return {@code true} if this is a supported look and feel
 667      * @see UIManager#setLookAndFeel
 668      */
 669     public abstract boolean isSupportedLookAndFeel();
 670 
 671 
 672     /**
 673      * Initializes the look and feel. While this method is public,
 674      * it should only be invoked by the {@code UIManager} when a
 675      * look and feel is installed as the current look and feel. This
 676      * method is invoked before the {@code UIManager} invokes
 677      * {@code getDefaults}. This method is intended to perform any
 678      * initialization for the look and feel. Subclasses
 679      * should do any one-time setup they need here, rather than
 680      * in a static initializer, because look and feel class objects
 681      * may be loaded just to discover that {@code isSupportedLookAndFeel()}
 682      * returns {@code false}.
 683      *
 684      * @see #uninitialize
 685      * @see UIManager#setLookAndFeel
 686      */
 687     public void initialize() {
 688     }
 689 
 690 
 691     /**
 692      * Uninitializes the look and feel. While this method is public,
 693      * it should only be invoked by the {@code UIManager} when
 694      * the look and feel is uninstalled. For example,
 695      * {@code UIManager.setLookAndFeel} invokes this when the look and
 696      * feel is changed.
 697      * <p>
 698      * Subclasses may choose to free up some resources here.
 699      *
 700      * @see #initialize
 701      * @see UIManager#setLookAndFeel
 702      */
 703     public void uninitialize() {
 704     }
 705 
 706     /**
 707      * Returns the look and feel defaults. While this method is public,
 708      * it should only be invoked by the {@code UIManager} when the
 709      * look and feel is set as the current look and feel and after
 710      * {@code initialize} has been invoked.
 711      *
 712      * @return the look and feel defaults
 713      * @see #initialize
 714      * @see #uninitialize
 715      * @see UIManager#setLookAndFeel
 716      */
 717     public UIDefaults getDefaults() {
 718         return null;
 719     }
 720 
 721     /**
 722      * Returns a string that displays and identifies this
 723      * object's properties.
 724      *
 725      * @return a String representation of this object
 726      */
 727     public String toString() {
 728         return "[" + getDescription() + " - " + getClass().getName() + "]";
 729     }
 730 }