1 /*
   2  * Copyright (c) 1998, 2014, 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 precedence 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&trade;
  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 @SuppressWarnings("serial") // Same-version serialization only
  92 public class DefaultMetalTheme extends MetalTheme {
  93     /**
  94      * Whether or not fonts should be plain.  This is only used if
  95      * the defaults property 'swing.boldMetal' == "false".
  96      */
  97     private static final boolean PLAIN_FONTS;
  98 
  99     /**
 100      * Names of the fonts to use.
 101      */
 102     private static final String[] fontNames = {
 103         Font.DIALOG,Font.DIALOG,Font.DIALOG,Font.DIALOG,Font.DIALOG,Font.DIALOG
 104     };
 105     /**
 106      * Styles for the fonts.  This is ignored if the defaults property
 107      * <code>swing.boldMetal</code> is false, or PLAIN_FONTS is true.
 108      */
 109     private static final int[] fontStyles = {
 110         Font.BOLD, Font.PLAIN, Font.PLAIN, Font.BOLD, Font.BOLD, Font.PLAIN
 111     };
 112     /**
 113      * Sizes for the fonts.
 114      */
 115     private static final int[] fontSizes = {
 116         12, 12, 12, 12, 12, 10
 117     };
 118 
 119     // note the properties listed here can currently be used by people
 120     // providing runtimes to hint what fonts are good.  For example the bold
 121     // dialog font looks bad on a Mac, so Apple could use this property to
 122     // hint at a good font.
 123     //
 124     // However, we don't promise to support these forever.  We may move
 125     // to getting these from the swing.properties file, or elsewhere.
 126     /**
 127      * System property names used to look up fonts.
 128      */
 129     private static final String[] defaultNames = {
 130         "swing.plaf.metal.controlFont",
 131         "swing.plaf.metal.systemFont",
 132         "swing.plaf.metal.userFont",
 133         "swing.plaf.metal.controlFont",
 134         "swing.plaf.metal.controlFont",
 135         "swing.plaf.metal.smallFont"
 136     };
 137 
 138     /**
 139      * Returns the ideal font name for the font identified by key.
 140      */
 141     static String getDefaultFontName(int key) {
 142         return fontNames[key];
 143     }
 144 
 145     /**
 146      * Returns the ideal font size for the font identified by key.
 147      */
 148     static int getDefaultFontSize(int key) {
 149         return fontSizes[key];
 150     }
 151 
 152     /**
 153      * Returns the ideal font style for the font identified by key.
 154      */
 155     static int getDefaultFontStyle(int key) {
 156         if (key != WINDOW_TITLE_FONT) {
 157             Object boldMetal = null;
 158             if (AppContext.getAppContext().get(
 159                     SwingUtilities2.LAF_STATE_KEY) != null) {
 160                 // Only access the boldMetal key if a look and feel has
 161                 // been loaded, otherwise we'll trigger loading the look
 162                 // and feel.
 163                 boldMetal = UIManager.get("swing.boldMetal");
 164             }
 165             if (boldMetal != null) {
 166                 if (Boolean.FALSE.equals(boldMetal)) {
 167                     return Font.PLAIN;
 168                 }
 169             }
 170             else if (PLAIN_FONTS) {
 171                 return Font.PLAIN;
 172             }
 173         }
 174         return fontStyles[key];
 175     }
 176 
 177     /**
 178      * Returns the default used to look up the specified font.
 179      */
 180     static String getDefaultPropertyName(int key) {
 181         return defaultNames[key];
 182     }
 183 
 184     static {
 185         Object boldProperty = java.security.AccessController.doPrivileged(
 186             new GetPropertyAction("swing.boldMetal"));
 187         if (boldProperty == null || !"false".equals(boldProperty)) {
 188             PLAIN_FONTS = false;
 189         }
 190         else {
 191             PLAIN_FONTS = true;
 192         }
 193     }
 194 
 195     private static final ColorUIResource primary1 = new ColorUIResource(
 196                               102, 102, 153);
 197     private static final ColorUIResource primary2 = new ColorUIResource(153,
 198                               153, 204);
 199     private static final ColorUIResource primary3 = new ColorUIResource(
 200                               204, 204, 255);
 201     private static final ColorUIResource secondary1 = new ColorUIResource(
 202                               102, 102, 102);
 203     private static final ColorUIResource secondary2 = new ColorUIResource(
 204                               153, 153, 153);
 205     private static final ColorUIResource secondary3 = new ColorUIResource(
 206                               204, 204, 204);
 207 
 208     private FontDelegate fontDelegate;
 209 
 210     /**
 211      * Returns the name of this theme. This returns {@code "Steel"}.
 212      *
 213      * @return the name of this theme.
 214      */
 215     public String getName() { return "Steel"; }
 216 
 217     /**
 218      * Creates and returns an instance of {@code DefaultMetalTheme}.
 219      */
 220     public DefaultMetalTheme() {
 221         install();
 222     }
 223 
 224     /**
 225      * Returns the primary 1 color. This returns a color with rgb values
 226      * of 102, 102, and 153, respectively.
 227      *
 228      * @return the primary 1 color
 229      */
 230     protected ColorUIResource getPrimary1() { return primary1; }
 231 
 232     /**
 233      * Returns the primary 2 color. This returns a color with rgb values
 234      * of 153, 153, 204, respectively.
 235      *
 236      * @return the primary 2 color
 237      */
 238     protected ColorUIResource getPrimary2() { return primary2; }
 239 
 240     /**
 241      * Returns the primary 3 color. This returns a color with rgb values
 242      * 204, 204, 255, respectively.
 243      *
 244      * @return the primary 3 color
 245      */
 246     protected ColorUIResource getPrimary3() { return primary3; }
 247 
 248     /**
 249      * Returns the secondary 1 color. This returns a color with rgb values
 250      * 102, 102, and 102, respectively.
 251      *
 252      * @return the secondary 1 color
 253      */
 254     protected ColorUIResource getSecondary1() { return secondary1; }
 255 
 256     /**
 257      * Returns the secondary 2 color. This returns a color with rgb values
 258      * 153, 153, and 153, respectively.
 259      *
 260      * @return the secondary 2 color
 261      */
 262     protected ColorUIResource getSecondary2() { return secondary2; }
 263 
 264     /**
 265      * Returns the secondary 3 color. This returns a color with rgb values
 266      * 204, 204, and 204, respectively.
 267      *
 268      * @return the secondary 3 color
 269      */
 270     protected ColorUIResource getSecondary3() { return secondary3; }
 271 
 272 
 273     /**
 274      * Returns the control text font. This returns Dialog, 12pt. If
 275      * plain fonts have been enabled as described in <a href="#fontStyle">
 276      * font style</a>, the font style is plain. Otherwise the font style is
 277      * bold.
 278      *
 279      * @return the control text font
 280      */
 281     public FontUIResource getControlTextFont() {
 282         return getFont(CONTROL_TEXT_FONT);
 283     }
 284 
 285     /**
 286      * Returns the system text font. This returns Dialog, 12pt, plain.
 287      *
 288      * @return the system text font
 289      */
 290     public FontUIResource getSystemTextFont() {
 291         return getFont(SYSTEM_TEXT_FONT);
 292     }
 293 
 294     /**
 295      * Returns the user text font. This returns Dialog, 12pt, plain.
 296      *
 297      * @return the user text font
 298      */
 299     public FontUIResource getUserTextFont() {
 300         return getFont(USER_TEXT_FONT);
 301     }
 302 
 303     /**
 304      * Returns the menu text font. This returns Dialog, 12pt. If
 305      * plain fonts have been enabled as described in <a href="#fontStyle">
 306      * font style</a>, the font style is plain. Otherwise the font style is
 307      * bold.
 308      *
 309      * @return the menu text font
 310      */
 311     public FontUIResource getMenuTextFont() {
 312         return getFont(MENU_TEXT_FONT);
 313     }
 314 
 315     /**
 316      * Returns the window title font. This returns Dialog, 12pt, bold.
 317      *
 318      * @return the window title font
 319      */
 320     public FontUIResource getWindowTitleFont() {
 321         return getFont(WINDOW_TITLE_FONT);
 322     }
 323 
 324     /**
 325      * Returns the sub-text font. This returns Dialog, 10pt, plain.
 326      *
 327      * @return the sub-text font
 328      */
 329     public FontUIResource getSubTextFont() {
 330         return getFont(SUB_TEXT_FONT);
 331     }
 332 
 333     private FontUIResource getFont(int key) {
 334         return fontDelegate.getFont(key);
 335     }
 336 
 337     void install() {
 338         if (MetalLookAndFeel.isWindows() &&
 339                              MetalLookAndFeel.useSystemFonts()) {
 340             fontDelegate = new WindowsFontDelegate();
 341         }
 342         else {
 343             fontDelegate = new FontDelegate();
 344         }
 345     }
 346 
 347     /**
 348      * Returns true if this is a theme provided by the core platform.
 349      */
 350     boolean isSystemTheme() {
 351         return (getClass() == DefaultMetalTheme.class);
 352     }
 353 
 354     /**
 355      * FontDelegates add an extra level of indirection to obtaining fonts.
 356      */
 357     private static class FontDelegate {
 358         private static int[] defaultMapping = {
 359             CONTROL_TEXT_FONT, SYSTEM_TEXT_FONT,
 360             USER_TEXT_FONT, CONTROL_TEXT_FONT,
 361             CONTROL_TEXT_FONT, SUB_TEXT_FONT
 362         };
 363         FontUIResource fonts[];
 364 
 365         // menu and window are mapped to controlFont
 366         public FontDelegate() {
 367             fonts = new FontUIResource[6];
 368         }
 369 
 370         public FontUIResource getFont(int type) {
 371             int mappedType = defaultMapping[type];
 372             if (fonts[type] == null) {
 373                 Font f = getPrivilegedFont(mappedType);
 374 
 375                 if (f == null) {
 376                     f = new Font(getDefaultFontName(type),
 377                              getDefaultFontStyle(type),
 378                              getDefaultFontSize(type));
 379                 }
 380                 fonts[type] = new FontUIResource(f);
 381             }
 382             return fonts[type];
 383         }
 384 
 385         /**
 386          * This is the same as invoking
 387          * <code>Font.getFont(key)</code>, with the exception
 388          * that it is wrapped inside a <code>doPrivileged</code> call.
 389          */
 390         protected Font getPrivilegedFont(final int key) {
 391             return java.security.AccessController.doPrivileged(
 392                 new java.security.PrivilegedAction<Font>() {
 393                     public Font run() {
 394                         return Font.getFont(getDefaultPropertyName(key));
 395                     }
 396                 }
 397                 );
 398         }
 399     }
 400 
 401     /**
 402      * The WindowsFontDelegate uses DesktopProperties to obtain fonts.
 403      */
 404     private static class WindowsFontDelegate extends FontDelegate {
 405         private MetalFontDesktopProperty[] props;
 406         private boolean[] checkedPriviledged;
 407 
 408         public WindowsFontDelegate() {
 409             props = new MetalFontDesktopProperty[6];
 410             checkedPriviledged = new boolean[6];
 411         }
 412 
 413         public FontUIResource getFont(int type) {
 414             if (fonts[type] != null) {
 415                 return fonts[type];
 416             }
 417             if (!checkedPriviledged[type]) {
 418                 Font f = getPrivilegedFont(type);
 419 
 420                 checkedPriviledged[type] = true;
 421                 if (f != null) {
 422                     fonts[type] = new FontUIResource(f);
 423                     return fonts[type];
 424                 }
 425             }
 426             if (props[type] == null) {
 427                 props[type] = new MetalFontDesktopProperty(type);
 428             }
 429             // While passing null may seem bad, we don't actually use
 430             // the table and looking it up is rather expensive.
 431             return (FontUIResource)props[type].createValue(null);
 432         }
 433     }
 434 }