Source for javax.swing.LookAndFeel

   1: /* LookAndFeel.java --
   2:    Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing;
  40: 
  41: import java.awt.Color;
  42: import java.awt.Component;
  43: import java.awt.Font;
  44: import java.awt.Toolkit;
  45: import java.net.URL;
  46: 
  47: import javax.swing.border.Border;
  48: import javax.swing.plaf.ComponentInputMapUIResource;
  49: import javax.swing.plaf.IconUIResource;
  50: import javax.swing.plaf.InputMapUIResource;
  51: import javax.swing.plaf.UIResource;
  52: import javax.swing.text.JTextComponent;
  53: 
  54: public abstract class LookAndFeel
  55: {
  56:   /**
  57:    * This method is called once by UIManager.setLookAndFeel to create
  58:    * the look and feel specific defaults table.
  59:    *
  60:    * @return the UI defaults
  61:    */
  62:   public UIDefaults getDefaults()
  63:   {
  64:     return null;
  65:   }
  66: 
  67:   /**
  68:    * Returns a description of the look and feel.
  69:    * 
  70:    * @return A description of the look and feel.
  71:    */
  72:   public abstract String getDescription();
  73: 
  74:   public static Object getDesktopPropertyValue(String systemPropertyName, 
  75:       Object fallbackValue)
  76:   {
  77:     Object value = Toolkit.getDefaultToolkit().getDesktopProperty(systemPropertyName);
  78:     return value != null ? value : fallbackValue;
  79:   }
  80:   
  81:   /**
  82:    * Returns an identifier for the look and feel.
  83:    * 
  84:    * @return An identifier for the look and feel.
  85:    */
  86:   public abstract String getID();
  87: 
  88:   /**
  89:    * Returns the name for the look and feel.
  90:    * 
  91:    * @return The name for the look and feel.
  92:    */
  93:   public abstract String getName();
  94: 
  95:   /**
  96:    * Returns true when the Look and Feel supports window decorations,
  97:    * false others. This method returns always false and needs to be overwritten
  98:    * when the derived Look and Feel supports this.
  99:    *
 100:    * @return false
 101:    *
 102:    * @since 1.4
 103:    */
 104:   public boolean getSupportsWindowDecorations()
 105:   {
 106:     return false;
 107:   }
 108:   
 109:   /**
 110:    * UIManager.setLookAndFeel calls this method before the first call
 111:    * (and typically the only call) to getDefaults(). 
 112:    */
 113:   public void initialize()
 114:   {
 115:     // We do nothing here. This method is meant to be overridden by
 116:     // LookAndFeel implementations.
 117:   }
 118: 
 119:   /**
 120:    * Convenience method for installing a component's default Border object
 121:    * on the specified component if either the border is currently null
 122:    * or already an instance of UIResource. 
 123:    */
 124:   public static void installBorder(JComponent c, String defaultBorderName)
 125:   {
 126:     Border b = c.getBorder();
 127:     if (b == null || b instanceof UIResource)
 128:       c.setBorder(UIManager.getBorder(defaultBorderName));
 129:   }
 130: 
 131:   /**
 132:    * Convenience method for initializing a component's foreground and
 133:    * background color properties with values from the current defaults table.
 134:    */
 135:   public static void installColors(JComponent c, String defaultBgName,
 136:                                    String defaultFgName)
 137:   {
 138:     // Install background.
 139:     Color bg = c.getBackground();
 140:     if (bg == null || bg instanceof UIResource)
 141:       c.setBackground(UIManager.getColor(defaultBgName));
 142: 
 143:     // Install foreground.
 144:     Color fg = c.getForeground();
 145:     if (fg == null || fg instanceof UIResource)
 146:       c.setForeground(UIManager.getColor(defaultFgName));
 147:   }
 148: 
 149:   /**
 150:    * Convenience method for initializing a components foreground background
 151:    * and font properties with values from the current defaults table. 
 152:    */
 153:   public static void installColorsAndFont(JComponent component,
 154:                                           String defaultBgName,
 155:                                           String defaultFgName,
 156:                                           String defaultFontName)
 157:   {
 158:     // Install colors.
 159:     installColors(component, defaultBgName, defaultFgName);
 160:     // Install font.
 161:     Font f = component.getFont();
 162:     if (f == null || f instanceof UIResource)
 163:       component.setFont(UIManager.getFont(defaultFontName));
 164:   }
 165: 
 166:   /**
 167:    * Returns <code>true</code> if the look and feel is the "native" look and
 168:    * feel for the current platform, and <code>false</code> otherwise.
 169:    * 
 170:    * @return A flag indicating whether or not this is the native look and feel
 171:    *         for the current platform.
 172:    */
 173:   public abstract boolean isNativeLookAndFeel();
 174: 
 175:   /**
 176:    * Returns <code>true</code> if the look and feel is supported on the 
 177:    * current operating system, and <code>false</code> otherwise.  This 
 178:    * mechanism is provided so that it is possible to prevent a look and feel
 179:    * from being used on some operating systems (usually for legal, not
 180:    * technical, reasons).
 181:    * 
 182:    * @return A flag indicating whether or not the look and feel is supported
 183:    *         on the current platform.
 184:    */
 185:   public abstract boolean isSupportedLookAndFeel();
 186: 
 187:   /**
 188:    * Loads the bindings in keys into retMap. Does not remove existing entries
 189:    * from retMap.  <code>keys</code> describes the InputMap, every even indexed
 190:    * item is either a KeyStroke or a String representing a KeyStroke and every
 191:    * odd indexed item is the Object associated with that KeyStroke in an 
 192:    * ActionMap.
 193:    * 
 194:    * @param retMap the InputMap into which we load bindings
 195:    * @param keys the Object array describing the InputMap as above
 196:    */
 197:   public static void loadKeyBindings(InputMap retMap, Object[] keys)
 198:   {
 199:     if (keys == null)
 200:       return;
 201:     for (int i = 0; i < keys.length - 1; i+= 2)
 202:       {
 203:         Object key = keys[i];
 204:         KeyStroke keyStroke;
 205:         if (key instanceof KeyStroke)
 206:           keyStroke = (KeyStroke)key;
 207:         else
 208:           keyStroke = KeyStroke.getKeyStroke((String)key);
 209:         retMap.put(keyStroke, keys[i+1]);
 210:       }
 211:   }
 212: 
 213:   /**
 214:    * Creates a ComponentInputMap from keys.  
 215:    * <code>keys</code> describes the InputMap, every even indexed
 216:    * item is either a KeyStroke or a String representing a KeyStroke and every
 217:    * odd indexed item is the Object associated with that KeyStroke in an 
 218:    * ActionMap.
 219:    * 
 220:    * @param c the JComponent associated with the ComponentInputMap
 221:    * @param keys the Object array describing the InputMap as above
 222:    */
 223:   public static ComponentInputMap makeComponentInputMap(JComponent c,
 224:                             Object[] keys)
 225:   {
 226:     ComponentInputMap retMap = new ComponentInputMapUIResource(c);
 227:     loadKeyBindings(retMap, keys);
 228:     return retMap;
 229:   }
 230: 
 231:   /**
 232:    * Utility method that creates a UIDefaults.LazyValue that creates an
 233:    * ImageIcon UIResource for the specified gifFile filename. 
 234:    */
 235:   public static Object makeIcon(Class baseClass, String gifFile)
 236:   {
 237:     final URL file = baseClass.getResource(gifFile);
 238:     return new UIDefaults.LazyValue() 
 239:       {
 240:         public Object createValue(UIDefaults table)
 241:         {
 242:           return new IconUIResource(new ImageIcon(file));
 243:         }
 244:       };
 245:   }
 246: 
 247:   /**
 248:    * Creates a InputMap from keys. 
 249:    * <code>keys</code> describes the InputMap, every even indexed
 250:    * item is either a KeyStroke or a String representing a KeyStroke and every
 251:    * odd indexed item is the Object associated with that KeyStroke in an 
 252:    * ActionMap.
 253:    * 
 254:    * @param keys the Object array describing the InputMap as above
 255:    */
 256:   public static InputMap makeInputMap(Object[] keys)
 257:   {
 258:     InputMap retMap = new InputMapUIResource();
 259:     loadKeyBindings(retMap, keys);
 260:     return retMap;
 261:   }
 262: 
 263:   /**
 264:    * Convenience method for building lists of KeyBindings.
 265:    * <code>keyBindingList</code> is an array of KeyStroke-Action pairs where
 266:    * even indexed elements are KeyStrokes or Strings representing KeyStrokes
 267:    * and odd indexed elements are the associated Actions.
 268:    * 
 269:    * @param keyBindingList the array of KeyStroke-Action pairs
 270:    * @return a JTextComponent.KeyBinding array
 271:    */
 272:   public static JTextComponent.KeyBinding[] makeKeyBindings(Object[] keyBindingList)
 273:   {
 274:     JTextComponent.KeyBinding[] retBindings = 
 275:       new JTextComponent.KeyBinding[keyBindingList.length / 2];
 276:     for (int i = 0; i < keyBindingList.length - 1; i+= 2)
 277:       {
 278:         KeyStroke stroke;
 279:         if (keyBindingList[i] instanceof KeyStroke)
 280:           stroke = (KeyStroke)keyBindingList[i];
 281:         else
 282:           stroke = KeyStroke.getKeyStroke((String)keyBindingList[i]);
 283:         retBindings[i/2] = new JTextComponent.KeyBinding(stroke, (String)keyBindingList[i+1]);
 284:       }
 285:     return retBindings;
 286:   }
 287: 
 288:   /**
 289:    * Invoked when the user attempts an invalid operation. The default implement
 290:    * just beeps. Subclasses that wish to change this need to override this
 291:    * method.
 292:    *
 293:    * @param component the component the error occured in
 294:    */
 295:   public void provideErrorFeedback(Component component)
 296:   {
 297:     Toolkit.getDefaultToolkit().beep();
 298:   }
 299: 
 300:   /**
 301:    * Returns a string that displays and identifies this object's properties.
 302:    *
 303:    * @return string containing the description and class name.
 304:    */
 305:   public String toString()
 306:   {
 307:     return getDescription() + " " + getClass().getName();
 308:   }
 309: 
 310:   /**
 311:    * UIManager.setLookAndFeel calls this method just before we're replaced by
 312:    * a new default look and feel. 
 313:    */
 314:   public void uninitialize()
 315:   {
 316:     // We do nothing here. This method is meant to be overridden by
 317:     // LookAndFeel implementations.
 318:   }
 319: 
 320:   /**
 321:    * Convenience method for un-installing a component's default border on the
 322:    * specified component if the border is currently an instance of UIResource.
 323:    */
 324:   public static void uninstallBorder(JComponent c)
 325:   {
 326:     if (c.getBorder() instanceof UIResource)
 327:       c.setBorder(null);
 328:   }
 329: }