LookAndFeel.java 15 KB
Newer Older
Tom Tromey committed
1
/* LookAndFeel.java --
2
   Copyright (C) 2002, 2004, 2005, 2006,  Free Software Foundation, Inc.
Tom Tromey committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */


package javax.swing;

41
import java.awt.Color;
Tom Tromey committed
42
import java.awt.Component;
43
import java.awt.Font;
Tom Tromey committed
44
import java.awt.Toolkit;
45
import java.net.URL;
Tom Tromey committed
46

47 48 49 50 51
import javax.swing.border.Border;
import javax.swing.plaf.ComponentInputMapUIResource;
import javax.swing.plaf.IconUIResource;
import javax.swing.plaf.InputMapUIResource;
import javax.swing.plaf.UIResource;
52
import javax.swing.plaf.metal.MetalLookAndFeel;
Tom Tromey committed
53 54
import javax.swing.text.JTextComponent;

55
/**
56 57
 * A <i>look-and-feel</i> controls most aspects of the appearance and
 * operation of user interface components in <code>javax.swing</code>.  A
58
 * cross-platform look-and-feel (the {@link MetalLookAndFeel}) is provided.
59
 *
60 61 62
 * @see UIManager#getInstalledLookAndFeels()
 * @see UIManager#setLookAndFeel(LookAndFeel)
 */
Tom Tromey committed
63 64 65
public abstract class LookAndFeel
{
  /**
66 67
   * Creates and returns a look-and-feel specific defaults table.  This method
   * is called once by {@link UIManager#setLookAndFeel(LookAndFeel)} and
68
   * shouldn't be called again (as it creates a large table of defaults).
Tom Tromey committed
69
   *
70
   * @return The UI defaults.
Tom Tromey committed
71 72 73 74 75 76 77 78
   */
  public UIDefaults getDefaults()
  {
    return null;
  }

  /**
   * Returns a description of the look and feel.
79
   *
Tom Tromey committed
80 81 82 83
   * @return A description of the look and feel.
   */
  public abstract String getDescription();

84 85
  /**
   * Returns the value of <code>Toolkit.getDefaultToolkit()
86
   * .getDesktopProperty(systemPropertyName)</code>, or
87
   * <code>fallbackValue</code> if no such property is defined.
88
   *
89 90
   * @param systemPropertyName  the system property name.
   * @param fallbackValue  the fallback value.
91
   *
92 93
   * @return The property value or <code>fallbackValue</code>.
   */
94
  public static Object getDesktopPropertyValue(String systemPropertyName,
Tom Tromey committed
95 96
      Object fallbackValue)
  {
97 98
    Object value = Toolkit.getDefaultToolkit().getDesktopProperty(
        systemPropertyName);
Tom Tromey committed
99 100
    return value != null ? value : fallbackValue;
  }
101

Tom Tromey committed
102 103
  /**
   * Returns an identifier for the look and feel.
104
   *
Tom Tromey committed
105 106 107 108 109 110
   * @return An identifier for the look and feel.
   */
  public abstract String getID();

  /**
   * Returns the name for the look and feel.
111
   *
Tom Tromey committed
112 113 114 115 116
   * @return The name for the look and feel.
   */
  public abstract String getName();

  /**
117
   * Returns <code>true</code> when the look-and-feel supports window
118
   * decorations, and <code>false</code> otherwise. This default implementation
119
   * always returns <code>false</code> and needs to be overridden when the
120
   * derived look-and-feel supports this.
Tom Tromey committed
121
   *
122
   * @return <code>false</code>.
Tom Tromey committed
123 124 125 126 127 128 129
   *
   * @since 1.4
   */
  public boolean getSupportsWindowDecorations()
  {
    return false;
  }
130

Tom Tromey committed
131
  /**
132 133 134
   * Initializes the look-and-feel.  The
   * {@link UIManager#setLookAndFeel(LookAndFeel)} method calls this method
   * before the first call (and typically the only call) to
135
   * {@link #getDefaults()}.  This default implementation does nothing, but
136
   * subclasses can override this behaviour.
Tom Tromey committed
137 138 139
   */
  public void initialize()
  {
140 141
    // We do nothing here. This method is meant to be overridden by
    // LookAndFeel implementations.
Tom Tromey committed
142 143 144
  }

  /**
145 146 147 148
   * Convenience method for installing a component's default {@link Border}
   * object on the specified component if either the border is currently
   * <code>null</code> or already an instance of {@link UIResource}.
   *
149
   * @param c  the component (<code>null</code> not permitted).
150
   * @param defaultBorderName  the border name (for lookup in the UIDefaults
151
   *     table).
Tom Tromey committed
152 153 154
   */
  public static void installBorder(JComponent c, String defaultBorderName)
  {
155 156 157
    Border b = c.getBorder();
    if (b == null || b instanceof UIResource)
      c.setBorder(UIManager.getBorder(defaultBorderName));
Tom Tromey committed
158 159 160 161 162
  }

  /**
   * Convenience method for initializing a component's foreground and
   * background color properties with values from the current defaults table.
163
   *
164
   * @param c  the component (<code>null</code> not permitted).
165
   * @param defaultBgName  the key for the background color in the UIDefaults
166 167 168
   *     table.
   * @param defaultFgName  the key for the foreground color in the UIDefaults
   *     table.
Tom Tromey committed
169
   */
170 171
  public static void installColors(JComponent c, String defaultBgName,
                                   String defaultFgName)
Tom Tromey committed
172
  {
173 174 175 176 177 178 179 180 181
    // Install background.
    Color bg = c.getBackground();
    if (bg == null || bg instanceof UIResource)
      c.setBackground(UIManager.getColor(defaultBgName));

    // Install foreground.
    Color fg = c.getForeground();
    if (fg == null || fg instanceof UIResource)
      c.setForeground(UIManager.getColor(defaultFgName));
Tom Tromey committed
182 183 184
  }

  /**
185 186
   * Convenience method for initializing a component's foreground, background
   * and font properties with values from the current defaults table.
187
   *
188
   * @param component  the component (<code>null</code> not permitted).
189
   * @param defaultBgName  the key for the background color in the UIDefaults
190 191 192 193
   *     table.
   * @param defaultFgName  the key for the foreground color in the UIDefaults
   *     table.
   * @param defaultFontName  the key for the font in the UIDefaults table.
Tom Tromey committed
194 195
   */
  public static void installColorsAndFont(JComponent component,
196 197 198
                                          String defaultBgName,
                                          String defaultFgName,
                                          String defaultFontName)
Tom Tromey committed
199
  {
200 201 202 203 204 205
    // Install colors.
    installColors(component, defaultBgName, defaultFgName);
    // Install font.
    Font f = component.getFont();
    if (f == null || f instanceof UIResource)
      component.setFont(UIManager.getFont(defaultFontName));
Tom Tromey committed
206 207 208
  }

  /**
209
   * Returns <code>true</code> if the look-and-feel is the "native"
210
   * look-and-feel for the current platform, and <code>false</code> otherwise.
211
   * A native look-and-feel emulates the appearance and behaviour of the
212
   * default windowing system on the host operating system.
213
   *
Tom Tromey committed
214 215 216 217 218 219
   * @return A flag indicating whether or not this is the native look and feel
   *         for the current platform.
   */
  public abstract boolean isNativeLookAndFeel();

  /**
220 221
   * Returns <code>true</code> if the look-and-feel is supported on the
   * current operating system, and <code>false</code> otherwise.  This
222
   * mechanism is provided so that it is possible to prevent a look-and-feel
Tom Tromey committed
223 224
   * from being used on some operating systems (usually for legal, not
   * technical, reasons).
225
   *
226
   * @return A flag indicating whether or not the look-and-feel is supported
Tom Tromey committed
227 228 229 230 231
   *         on the current platform.
   */
  public abstract boolean isSupportedLookAndFeel();

  /**
232 233 234
   * Loads the bindings in keys into retMap. Does not remove existing entries
   * from retMap.  <code>keys</code> describes the InputMap, every even indexed
   * item is either a KeyStroke or a String representing a KeyStroke and every
235
   * odd indexed item is the Object associated with that KeyStroke in an
236
   * ActionMap.
237
   *
238 239
   * @param retMap the InputMap into which we load bindings
   * @param keys the Object array describing the InputMap as above
Tom Tromey committed
240 241 242
   */
  public static void loadKeyBindings(InputMap retMap, Object[] keys)
  {
243 244
    if (keys == null)
      return;
245
    for (int i = 0; i < keys.length - 1; i += 2)
246 247 248 249
      {
        Object key = keys[i];
        KeyStroke keyStroke;
        if (key instanceof KeyStroke)
250
          keyStroke = (KeyStroke) key;
251
        else
252 253
          keyStroke = KeyStroke.getKeyStroke((String) key);
        retMap.put(keyStroke, keys[i + 1]);
254
      }
Tom Tromey committed
255 256 257
  }

  /**
258
   * Creates a ComponentInputMap from keys.
259 260
   * <code>keys</code> describes the InputMap, every even indexed
   * item is either a KeyStroke or a String representing a KeyStroke and every
261
   * odd indexed item is the Object associated with that KeyStroke in an
262
   * ActionMap.
263
   *
264 265
   * @param c the JComponent associated with the ComponentInputMap
   * @param keys the Object array describing the InputMap as above
266
   *
267
   * @return A new input map.
Tom Tromey committed
268 269
   */
  public static ComponentInputMap makeComponentInputMap(JComponent c,
270
                                                        Object[] keys)
Tom Tromey committed
271
  {
272 273 274
    ComponentInputMap retMap = new ComponentInputMapUIResource(c);
    loadKeyBindings(retMap, keys);
    return retMap;
Tom Tromey committed
275 276 277 278
  }

  /**
   * Utility method that creates a UIDefaults.LazyValue that creates an
279
   * ImageIcon UIResource for the specified gifFile filename.
280
   *
281 282
   * @param baseClass  the base class for accessing the icon resource.
   * @param gifFile  the file name.
283 284
   *
   * @return A {@link UIDefaults.LazyValue} that serves up an
285
   *     {@link IconUIResource}.
Tom Tromey committed
286
   */
287
  public static Object makeIcon(Class<?> baseClass, String gifFile)
Tom Tromey committed
288
  {
289
    final URL file = baseClass.getResource(gifFile);
290
    return new UIDefaults.LazyValue()
291 292 293 294 295 296
      {
        public Object createValue(UIDefaults table)
        {
          return new IconUIResource(new ImageIcon(file));
        }
      };
Tom Tromey committed
297 298 299
  }

  /**
300
   * Creates a InputMap from keys.
301 302
   * <code>keys</code> describes the InputMap, every even indexed
   * item is either a KeyStroke or a String representing a KeyStroke and every
303
   * odd indexed item is the Object associated with that KeyStroke in an
304
   * ActionMap.
305
   *
306
   * @param keys the Object array describing the InputMap as above
307
   *
308
   * @return A new input map.
Tom Tromey committed
309 310 311
   */
  public static InputMap makeInputMap(Object[] keys)
  {
312 313 314
    InputMap retMap = new InputMapUIResource();
    loadKeyBindings(retMap, keys);
    return retMap;
Tom Tromey committed
315 316 317
  }

  /**
318 319 320 321
   * Convenience method for building lists of KeyBindings.
   * <code>keyBindingList</code> is an array of KeyStroke-Action pairs where
   * even indexed elements are KeyStrokes or Strings representing KeyStrokes
   * and odd indexed elements are the associated Actions.
322
   *
323 324
   * @param keyBindingList the array of KeyStroke-Action pairs
   * @return a JTextComponent.KeyBinding array
Tom Tromey committed
325
   */
326 327
  public static JTextComponent.KeyBinding[] makeKeyBindings(
      Object[] keyBindingList)
Tom Tromey committed
328
  {
329
    JTextComponent.KeyBinding[] retBindings =
330
      new JTextComponent.KeyBinding[keyBindingList.length / 2];
331
    for (int i = 0; i < keyBindingList.length - 1; i += 2)
332 333 334
      {
        KeyStroke stroke;
        if (keyBindingList[i] instanceof KeyStroke)
335
          stroke = (KeyStroke) keyBindingList[i];
336
        else
337
          stroke = KeyStroke.getKeyStroke((String) keyBindingList[i]);
338
        retBindings[i / 2] = new JTextComponent.KeyBinding(stroke,
339
            (String) keyBindingList[i + 1]);
340 341
      }
    return retBindings;
Tom Tromey committed
342 343 344
  }

  /**
345 346
   * Invoked when the user attempts an invalid operation. The default
   * implementation just beeps. Subclasses that wish to change this need to
347
   * override this method.
Tom Tromey committed
348 349 350 351 352 353 354 355 356 357 358
   *
   * @param component the component the error occured in
   */
  public void provideErrorFeedback(Component component)
  {
    Toolkit.getDefaultToolkit().beep();
  }

  /**
   * Returns a string that displays and identifies this object's properties.
   *
359
   * @return string containing the description and class name.
Tom Tromey committed
360 361 362
   */
  public String toString()
  {
363
    return getDescription() + " " + getClass().getName();
Tom Tromey committed
364 365 366 367
  }

  /**
   * UIManager.setLookAndFeel calls this method just before we're replaced by
368
   * a new default look and feel.
Tom Tromey committed
369 370 371
   */
  public void uninitialize()
  {
372 373
    // We do nothing here. This method is meant to be overridden by
    // LookAndFeel implementations.
Tom Tromey committed
374 375 376 377 378
  }

  /**
   * Convenience method for un-installing a component's default border on the
   * specified component if the border is currently an instance of UIResource.
379
   *
380
   * @param c  the component (<code>null</code> not permitted).
Tom Tromey committed
381 382 383
   */
  public static void uninstallBorder(JComponent c)
  {
384 385
    if (c.getBorder() instanceof UIResource)
      c.setBorder(null);
Tom Tromey committed
386
  }
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432

  /**
   * This methods installs a UI property if it hasn't already been set by an
   * application. This method is used by UI delegates that install a default
   * value for a property with a primitive type but do not want to override
   * a value that has been set by an application.
   *
   * The supported properties depend on the actual type of the component and
   * are listed in the table below. The supported properties are of course
   * inherited to subclasses.
   *
   * <table>
   * <tr><th>Type</th><th>Supported properties</th></tr>
   * <tr><td><code>JComponent</code></td>
   *     <td><code>opaque, autoscrolls</code></td></tr>
   * <tr><td><code>AbstractButton</code></td>
   *     <td><code>borderPainted, rolloverEnabled, iconTextGap,
   *      contentAreaFilled</code></td></tr>
   * <tr><td><code>JDesktopPane</code></td>
   *     <td><code>dragMode</code></td></tr>
   * <tr><td><code>JSplitPane</code></td>
   *     <td><code>dividerSize, oneTouchExpandable</code></td></tr>
   * <tr><td><code>JTable</code></td>
   *     <td><code>rowHeight</code></td></tr>
   * <tr><td><code>JTree</code></td>
   *     <td><code>rowHeight, scrollsOnExpand, showsRootHandles</code></td></tr>
   * </table>
   *
   * @param c the component to install the property to
   * @param propertyName the name of the property
   * @param value the value of the property
   *
   * @throws IllegalArgumentException if the specified property cannot be set
   *         by this method
   * @throws ClassCastException if the property value does not match the
   *         property type
   * @throws NullPointerException if <code>c</code> or
   *         <code>propertyValue</code> is <code>null</code>
   *
   * @since 1.5
   */
  public static void installProperty(JComponent c, String propertyName,
                                     Object value)
  {
    c.setUIProperty(propertyName, value);
  }
Tom Tromey committed
433
}