1/*
2 * Copyright (c) 1998, 2017, 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
26package javax.swing.plaf.metal;
27
28import javax.swing.plaf.*;
29import javax.swing.*;
30import java.awt.*;
31
32import sun.awt.AppContext;
33import sun.security.action.GetPropertyAction;
34import 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 id="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
92public 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}
435