1 /*
2  * Copyright (c) 1998, 2018, 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  * <h2><a id="fontStyle"></a>Font Style</h2>
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
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      */
getDefaultFontName(int key)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      */
getDefaultFontSize(int key)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      */
getDefaultFontStyle(int key)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      */
getDefaultPropertyName(int key)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      */
getName()215     public String getName() { return "Steel"; }
216 
217     /**
218      * Creates and returns an instance of {@code DefaultMetalTheme}.
219      */
DefaultMetalTheme()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      */
getPrimary1()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      */
getPrimary2()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      */
getPrimary3()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      */
getSecondary1()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      */
getSecondary2()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      */
getSecondary3()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      */
getControlTextFont()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      */
getSystemTextFont()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      */
getUserTextFont()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      */
getMenuTextFont()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      */
getWindowTitleFont()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      */
getSubTextFont()329     public FontUIResource getSubTextFont() {
330         return getFont(SUB_TEXT_FONT);
331     }
332 
getFont(int key)333     private FontUIResource getFont(int key) {
334         return fontDelegate.getFont(key);
335     }
336 
install()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      */
isSystemTheme()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
FontDelegate()366         public FontDelegate() {
367             fonts = new FontUIResource[6];
368         }
369 
getFont(int type)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          */
getPrivilegedFont(final int key)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 }
435