1/*
2 * Copyright (c) 1997, 2017, 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
26package javax.swing;
27
28import java.awt.Font;
29import java.awt.event.InputEvent;
30import java.awt.event.KeyEvent;
31import java.awt.Color;
32import java.awt.Component;
33import java.awt.SystemColor;
34import java.awt.Toolkit;
35import sun.awt.SunToolkit;
36
37import javax.swing.text.*;
38import javax.swing.border.*;
39import javax.swing.plaf.*;
40
41import java.net.URL;
42import sun.swing.SwingUtilities2;
43import sun.swing.DefaultLayoutStyle;
44import sun.swing.ImageIconUIResource;
45
46import 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 id="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 id="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 */
152public 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 an {@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}
731