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