1 /*
   2  * Copyright (c) 1998, 2006, 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.plaf.metal;
  27 
  28 import javax.swing.plaf.*;
  29 import javax.swing.*;
  30 import java.awt.*;
  31 
  32 import sun.awt.AppContext;
  33 import sun.security.action.GetPropertyAction;
  34 import sun.swing.SwingUtilities2;
  35 
  36 /**
  37  * A concrete implementation of {@code MetalTheme} providing
  38  * the original look of the Java Look and Feel, code-named "Steel". Refer
  39  * to {@link MetalLookAndFeel#setCurrentTheme} for details on changing
  40  * the default theme.
  41  * <p>
  42  * All colors returned by {@code DefaultMetalTheme} are completely
  43  * opaque.
  44  *
  45  * <h3><a name="fontStyle"></a>Font Style</h3>
  46  *
  47  * {@code DefaultMetalTheme} uses bold fonts for many controls.  To make all
  48  * controls (with the exception of the internal frame title bars and
  49  * client decorated frame title bars) use plain fonts you can do either of
  50  * the following:
  51  * <ul>
  52  * <li>Set the system property <code>swing.boldMetal</code> to
  53  *     <code>false</code>.  For example,
  54  *     <code>java&nbsp;-Dswing.boldMetal=false&nbsp;MyApp</code>.
  55  * <li>Set the defaults property <code>swing.boldMetal</code> to
  56  *     <code>Boolean.FALSE</code>.  For example:
  57  *     <code>UIManager.put("swing.boldMetal",&nbsp;Boolean.FALSE);</code>
  58  * </ul>
  59  * The defaults property <code>swing.boldMetal</code>, if set,
  60  * takes precendence over the system property of the same name. After
  61  * setting this defaults property you need to re-install
  62  * <code>MetalLookAndFeel</code>, as well as update the UI
  63  * of any previously created widgets. Otherwise the results are undefined.
  64  * The following illustrates how to do this:
  65  * <pre>
  66  *   // turn off bold fonts
  67  *   UIManager.put("swing.boldMetal", Boolean.FALSE);
  68  *
  69  *   // re-install the Metal Look and Feel
  70  *   UIManager.setLookAndFeel(new MetalLookAndFeel());
  71  *
  72  *   // Update the ComponentUIs for all Components. This
  73  *   // needs to be invoked for all windows.
  74  *   SwingUtilities.updateComponentTreeUI(rootComponent);
  75  * </pre>
  76  * <p>
  77  * <strong>Warning:</strong>
  78  * Serialized objects of this class will not be compatible with
  79  * future Swing releases. The current serialization support is
  80  * appropriate for short term storage or RMI between applications running
  81  * the same version of Swing.  As of 1.4, support for long term storage
  82  * of all JavaBeans<sup><font size="-2">TM</font></sup>
  83  * has been added to the <code>java.beans</code> package.
  84  * Please see {@link java.beans.XMLEncoder}.
  85  *
  86  * @see MetalLookAndFeel
  87  * @see MetalLookAndFeel#setCurrentTheme
  88  *
  89  * @author Steve Wilson
  90  */
  91 public class DefaultMetalTheme extends MetalTheme {
  92     /**
  93      * Whether or not fonts should be plain.  This is only used if
  94      * the defaults property 'swing.boldMetal' == "false".
  95      */
  96     private static final boolean PLAIN_FONTS;
  97 
  98     /**
  99      * Names of the fonts to use.
 100      */
 101     private static final String[] fontNames = {
 102         Font.DIALOG,Font.DIALOG,Font.DIALOG,Font.DIALOG,Font.DIALOG,Font.DIALOG
 103     };
 104     /**
 105      * Styles for the fonts.  This is ignored if the defaults property
 106      * <code>swing.boldMetal</code> is false, or PLAIN_FONTS is true.
 107      */
 108     private static final int[] fontStyles = {
 109         Font.BOLD, Font.PLAIN, Font.PLAIN, Font.BOLD, Font.BOLD, Font.PLAIN
 110     };
 111     /**
 112      * Sizes for the fonts.
 113      */
 114     private static final int[] fontSizes = {
 115         12, 12, 12, 12, 12, 10
 116     };
 117 
 118     // note the properties listed here can currently be used by people
 119     // providing runtimes to hint what fonts are good.  For example the bold
 120     // dialog font looks bad on a Mac, so Apple could use this property to
 121     // hint at a good font.
 122     //
 123     // However, we don't promise to support these forever.  We may move
 124     // to getting these from the swing.properties file, or elsewhere.
 125     /**
 126      * System property names used to look up fonts.
 127      */
 128     private static final String[] defaultNames = {
 129         "swing.plaf.metal.controlFont",
 130         "swing.plaf.metal.systemFont",
 131         "swing.plaf.metal.userFont",
 132         "swing.plaf.metal.controlFont",
 133         "swing.plaf.metal.controlFont",
 134         "swing.plaf.metal.smallFont"
 135     };
 136 
 137     /**
 138      * Returns the ideal font name for the font identified by key.
 139      */
 140     static String getDefaultFontName(int key) {
 141         return fontNames[key];
 142     }
 143 
 144     /**
 145      * Returns the ideal font size for the font identified by key.
 146      */
 147     static int getDefaultFontSize(int key) {
 148         return fontSizes[key];
 149     }
 150 
 151     /**
 152      * Returns the ideal font style for the font identified by key.
 153      */
 154     static int getDefaultFontStyle(int key) {
 155         if (key != WINDOW_TITLE_FONT) {
 156             Object boldMetal = null;
 157             if (AppContext.getAppContext().get(
 158                     SwingUtilities2.LAF_STATE_KEY) != null) {
 159                 // Only access the boldMetal key if a look and feel has
 160                 // been loaded, otherwise we'll trigger loading the look
 161                 // and feel.
 162                 boldMetal = UIManager.get("swing.boldMetal");
 163             }
 164             if (boldMetal != null) {
 165                 if (Boolean.FALSE.equals(boldMetal)) {
 166                     return Font.PLAIN;
 167                 }
 168             }
 169             else if (PLAIN_FONTS) {
 170                 return Font.PLAIN;
 171             }
 172         }
 173         return fontStyles[key];
 174     }
 175 
 176     /**
 177      * Returns the default used to look up the specified font.
 178      */
 179     static String getDefaultPropertyName(int key) {
 180         return defaultNames[key];
 181     }
 182 
 183     static {
 184         Object boldProperty = java.security.AccessController.doPrivileged(
 185             new GetPropertyAction("swing.boldMetal"));
 186         if (boldProperty == null || !"false".equals(boldProperty)) {
 187             PLAIN_FONTS = false;
 188         }
 189         else {
 190             PLAIN_FONTS = true;
 191         }
 192     }
 193 
 194     private static final ColorUIResource primary1 = new ColorUIResource(
 195                               102, 102, 153);
 196     private static final ColorUIResource primary2 = new ColorUIResource(153,
 197                               153, 204);
 198     private static final ColorUIResource primary3 = new ColorUIResource(
 199                               204, 204, 255);
 200     private static final ColorUIResource secondary1 = new ColorUIResource(
 201                               102, 102, 102);
 202     private static final ColorUIResource secondary2 = new ColorUIResource(
 203                               153, 153, 153);
 204     private static final ColorUIResource secondary3 = new ColorUIResource(
 205                               204, 204, 204);
 206 
 207     private FontDelegate fontDelegate;
 208 
 209     /**
 210      * Returns the name of this theme. This returns {@code "Steel"}.
 211      *
 212      * @return the name of this theme.
 213      */
 214     public String getName() { return "Steel"; }
 215 
 216     /**
 217      * Creates and returns an instance of {@code DefaultMetalTheme}.
 218      */
 219     public DefaultMetalTheme() {
 220         install();
 221     }
 222 
 223     /**
 224      * Returns the primary 1 color. This returns a color with rgb values
 225      * of 102, 102, and 153, respectively.
 226      *
 227      * @return the primary 1 color
 228      */
 229     protected ColorUIResource getPrimary1() { return primary1; }
 230 
 231     /**
 232      * Returns the primary 2 color. This returns a color with rgb values
 233      * of 153, 153, 204, respectively.
 234      *
 235      * @return the primary 2 color
 236      */
 237     protected ColorUIResource getPrimary2() { return primary2; }
 238 
 239     /**
 240      * Returns the primary 3 color. This returns a color with rgb values
 241      * 204, 204, 255, respectively.
 242      *
 243      * @return the primary 3 color
 244      */
 245     protected ColorUIResource getPrimary3() { return primary3; }
 246 
 247     /**
 248      * Returns the secondary 1 color. This returns a color with rgb values
 249      * 102, 102, and 102, respectively.
 250      *
 251      * @return the secondary 1 color
 252      */
 253     protected ColorUIResource getSecondary1() { return secondary1; }
 254 
 255     /**
 256      * Returns the secondary 2 color. This returns a color with rgb values
 257      * 153, 153, and 153, respectively.
 258      *
 259      * @return the secondary 2 color
 260      */
 261     protected ColorUIResource getSecondary2() { return secondary2; }
 262 
 263     /**
 264      * Returns the secondary 3 color. This returns a color with rgb values
 265      * 204, 204, and 204, respectively.
 266      *
 267      * @return the secondary 3 color
 268      */
 269     protected ColorUIResource getSecondary3() { return secondary3; }
 270 
 271 
 272     /**
 273      * Returns the control text font. This returns Dialog, 12pt. If
 274      * plain fonts have been enabled as described in <a href="#fontStyle">
 275      * font style</a>, the font style is plain. Otherwise the font style is
 276      * bold.
 277      *
 278      * @return the control text font
 279      */
 280     public FontUIResource getControlTextFont() {
 281         return getFont(CONTROL_TEXT_FONT);
 282     }
 283 
 284     /**
 285      * Returns the system text font. This returns Dialog, 12pt, plain.
 286      *
 287      * @return the sytem text font
 288      */
 289     public FontUIResource getSystemTextFont() {
 290         return getFont(SYSTEM_TEXT_FONT);
 291     }
 292 
 293     /**
 294      * Returns the user text font. This returns Dialog, 12pt, plain.
 295      *
 296      * @return the user text font
 297      */
 298     public FontUIResource getUserTextFont() {
 299         return getFont(USER_TEXT_FONT);
 300     }
 301 
 302     /**
 303      * Returns the menu text font. This returns Dialog, 12pt. If
 304      * plain fonts have been enabled as described in <a href="#fontStyle">
 305      * font style</a>, the font style is plain. Otherwise the font style is
 306      * bold.
 307      *
 308      * @return the menu text font
 309      */
 310     public FontUIResource getMenuTextFont() {
 311         return getFont(MENU_TEXT_FONT);
 312     }
 313 
 314     /**
 315      * Returns the window title font. This returns Dialog, 12pt, bold.
 316      *
 317      * @return the window title font
 318      */
 319     public FontUIResource getWindowTitleFont() {
 320         return getFont(WINDOW_TITLE_FONT);
 321     }
 322 
 323     /**
 324      * Returns the sub-text font. This returns Dialog, 10pt, plain.
 325      *
 326      * @return the sub-text font
 327      */
 328     public FontUIResource getSubTextFont() {
 329         return getFont(SUB_TEXT_FONT);
 330     }
 331 
 332     private FontUIResource getFont(int key) {
 333         return fontDelegate.getFont(key);
 334     }
 335 
 336     void install() {
 337         if (MetalLookAndFeel.isWindows() &&
 338                              MetalLookAndFeel.useSystemFonts()) {
 339             fontDelegate = new WindowsFontDelegate();
 340         }
 341         else {
 342             fontDelegate = new FontDelegate();
 343         }
 344     }
 345 
 346     /**
 347      * Returns true if this is a theme provided by the core platform.
 348      */
 349     boolean isSystemTheme() {
 350         return (getClass() == DefaultMetalTheme.class);
 351     }
 352 
 353     /**
 354      * FontDelegates add an extra level of indirection to obtaining fonts.
 355      */
 356     private static class FontDelegate {
 357         private static int[] defaultMapping = {
 358             CONTROL_TEXT_FONT, SYSTEM_TEXT_FONT,
 359             USER_TEXT_FONT, CONTROL_TEXT_FONT,
 360             CONTROL_TEXT_FONT, SUB_TEXT_FONT
 361         };
 362         FontUIResource fonts[];
 363 
 364         // menu and window are mapped to controlFont
 365         public FontDelegate() {
 366             fonts = new FontUIResource[6];
 367         }
 368 
 369         public FontUIResource getFont(int type) {
 370             int mappedType = defaultMapping[type];
 371             if (fonts[type] == null) {
 372                 Font f = getPrivilegedFont(mappedType);
 373 
 374                 if (f == null) {
 375                     f = new Font(getDefaultFontName(type),
 376                              getDefaultFontStyle(type),
 377                              getDefaultFontSize(type));
 378                 }
 379                 fonts[type] = new FontUIResource(f);
 380             }
 381             return fonts[type];
 382         }
 383 
 384         /**
 385          * This is the same as invoking
 386          * <code>Font.getFont(key)</code>, with the exception
 387          * that it is wrapped inside a <code>doPrivileged</code> call.
 388          */
 389         protected Font getPrivilegedFont(final int key) {
 390             return (Font)java.security.AccessController.doPrivileged(
 391                 new java.security.PrivilegedAction() {
 392                     public Object run() {
 393                         return Font.getFont(getDefaultPropertyName(key));
 394                     }
 395                 }
 396                 );
 397         }
 398     }
 399 
 400     /**
 401      * The WindowsFontDelegate uses DesktopProperties to obtain fonts.
 402      */
 403     private static class WindowsFontDelegate extends FontDelegate {
 404         private MetalFontDesktopProperty[] props;
 405         private boolean[] checkedPriviledged;
 406 
 407         public WindowsFontDelegate() {
 408             props = new MetalFontDesktopProperty[6];
 409             checkedPriviledged = new boolean[6];
 410         }
 411 
 412         public FontUIResource getFont(int type) {
 413             if (fonts[type] != null) {
 414                 return fonts[type];
 415             }
 416             if (!checkedPriviledged[type]) {
 417                 Font f = getPrivilegedFont(type);
 418 
 419                 checkedPriviledged[type] = true;
 420                 if (f != null) {
 421                     fonts[type] = new FontUIResource(f);
 422                     return fonts[type];
 423                 }
 424             }
 425             if (props[type] == null) {
 426                 props[type] = new MetalFontDesktopProperty(type);
 427             }
 428             // While passing null may seem bad, we don't actually use
 429             // the table and looking it up is rather expensive.
 430             return (FontUIResource)props[type].createValue(null);
 431         }
 432     }
 433 }