1 /*
2  * Copyright (c) 1998, 2013, 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 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      */
getDefaultFontName(int key)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      */
getDefaultFontSize(int key)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      */
getDefaultFontStyle(int key)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      */
getDefaultPropertyName(int key)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      */
getName()214     public String getName() { return "Steel"; }
215 
216     /**
217      * Creates and returns an instance of {@code DefaultMetalTheme}.
218      */
DefaultMetalTheme()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      */
getPrimary1()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      */
getPrimary2()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      */
getPrimary3()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      */
getSecondary1()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      */
getSecondary2()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      */
getSecondary3()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      */
getControlTextFont()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 system text font
288      */
getSystemTextFont()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      */
getUserTextFont()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      */
getMenuTextFont()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      */
getWindowTitleFont()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      */
getSubTextFont()328     public FontUIResource getSubTextFont() {
329         return getFont(SUB_TEXT_FONT);
330     }
331 
getFont(int key)332     private FontUIResource getFont(int key) {
333         return fontDelegate.getFont(key);
334     }
335 
install()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      */
isSystemTheme()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
FontDelegate()365         public FontDelegate() {
366             fonts = new FontUIResource[6];
367         }
368 
getFont(int type)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          */
getPrivilegedFont(final int key)389         protected Font getPrivilegedFont(final int key) {
390             return java.security.AccessController.doPrivileged(
391                 new java.security.PrivilegedAction<Font>() {
392                     public Font 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 }
434