001: /*
002: * Copyright (c) 2001-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JGoodies Karsten Lentzsch nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package com.jgoodies.looks;
032:
033: import java.awt.Font;
034: import java.awt.Toolkit;
035: import java.util.Locale;
036:
037: /**
038: * Provides static access to popular Windows fonts.
039: * The sizes of the font constants are specified in
040: * <em>typographic points</em>, approximately 1/72 of an inch.<p>
041: *
042: * TODO: Consider changing the visibility of the package private methods
043: * to public. As an alternative we may provide a FontPolicy that can
044: * emulate the font choice on Windows XP/2000 and Windows Vista for
045: * different software resolutions (96dpi/120dpi) and desktop font size settings
046: * (Normal/Large/Extra Large).
047: *
048: * @author Karsten Lentzsch
049: * @version $Revision: 1.13 $
050: *
051: * @see FontSet
052: * @see FontSets
053: * @see FontPolicy
054: * @see FontPolicies
055: *
056: * @since 2.0
057: */
058: public final class Fonts {
059:
060: /**
061: * The name of the default dialog font on western Windows XP.
062: */
063: public static final String TAHOMA_NAME = "Tahoma";
064:
065: /**
066: * The name of the default dialog font on western Windows Vista.
067: */
068: public static final String SEGOE_UI_NAME = "Segoe UI";
069:
070: // Physical Fonts *********************************************************
071:
072: /**
073: * This is the default font on western XP with 96dpi and normal fonts.
074: * Ascent=11, descent=3, height=14, dbuX=6, dbuY=12, 14dluY=21px.
075: */
076: public static final Font TAHOMA_11PT = new Font(TAHOMA_NAME,
077: Font.PLAIN, 11);
078:
079: /**
080: * Ascent=13, descent=3, height=16, dbuX=8, dbuY=13, 14dluY=22.75px.
081: */
082: public static final Font TAHOMA_13PT = new Font(TAHOMA_NAME,
083: Font.PLAIN, 13);
084:
085: /**
086: * Ascent=14, descent=3, height=17, dbuX=8, dbuY=14, 14dluY=24.5px.
087: */
088: public static final Font TAHOMA_14PT = new Font(TAHOMA_NAME,
089: Font.PLAIN, 14);
090:
091: /**
092: * This is Segoe UI 9pt, the default font on western Vista with 96dpi.
093: * Ascent=13, descent=4, height=17, dbuX=7, dbuY=13, 13dluY=21.125px.
094: */
095: public static final Font SEGOE_UI_12PT = new Font(SEGOE_UI_NAME,
096: Font.PLAIN, 12);
097:
098: /**
099: * Ascent=14, descent=4, height=18, dbuX=8, dbuY=14, 13dluY=22.75px.
100: */
101: public static final Font SEGOE_UI_13PT = new Font(SEGOE_UI_NAME,
102: Font.PLAIN, 13);
103:
104: /**
105: * Ascent=16, descent=5, height=21, dbuX=9, dbuY=16, 13dluY=26px.
106: */
107: public static final Font SEGOE_UI_15PT = new Font(SEGOE_UI_NAME,
108: Font.PLAIN, 15);
109:
110: // Default Windows Fonts **************************************************
111:
112: /**
113: * The default icon font on western Windows XP with 96dpi
114: * and the dialog font desktop setting "Normal".
115: */
116: public static final Font WINDOWS_XP_96DPI_NORMAL = TAHOMA_11PT;
117:
118: /**
119: * The default GUI font on western Windows XP with 96dpi
120: * and the dialog font desktop setting "Normal".
121: */
122: public static final Font WINDOWS_XP_96DPI_DEFAULT_GUI = TAHOMA_11PT;
123:
124: /**
125: * The default icon font on western Windows XP with 96dpi
126: * and the dialog font desktop setting "Large".
127: */
128: public static final Font WINDOWS_XP_96DPI_LARGE = TAHOMA_13PT;
129:
130: /**
131: * The default icon font on western Windows XP with 120dpi
132: * and the dialog font desktop setting "Normal".
133: */
134: public static final Font WINDOWS_XP_120DPI_NORMAL = TAHOMA_14PT;
135:
136: /**
137: * The default GUI font on western Windows XP with 120dpi
138: * and the dialog font desktop setting "Normal".
139: */
140: public static final Font WINDOWS_XP_120DPI_DEFAULT_GUI = TAHOMA_13PT;
141:
142: /**
143: * The default icon font on western Windows Vista with 96dpi
144: * and the dialog font desktop setting "Normal".
145: */
146: public static final Font WINDOWS_VISTA_96DPI_NORMAL = SEGOE_UI_12PT;
147:
148: /**
149: * The default icon font on western Windows Vista with 96dpi
150: * and the dialog font desktop setting "Large".
151: */
152: public static final Font WINDOWS_VISTA_96DPI_LARGE = SEGOE_UI_15PT;
153:
154: /**
155: * The default icon font on western Windows Vista with 101dpi
156: * and the dialog font desktop setting "Normal".<P>
157: *
158: * TODO: Check if this shall be removed or not.
159: */
160: static final Font WINDOWS_VISTA_101DPI_NORMAL = SEGOE_UI_13PT;
161:
162: /**
163: * The default icon font on western Windows Vista with 120dpi
164: * and the dialog font desktop setting "Normal".
165: */
166: public static final Font WINDOWS_VISTA_120DPI_NORMAL = SEGOE_UI_15PT;
167:
168: // Desktop Property Font Keys *********************************************
169:
170: /**
171: * The desktop property key used to lookup the DEFAULTGUI font.
172: * This font scales with the software resolution only
173: * but works in western and non-western Windows environments.
174: *
175: * @see #getWindowsControlFont()
176: */
177: static final String WINDOWS_DEFAULT_GUI_FONT_KEY = "win.defaultGUI.font";
178:
179: /**
180: * The desktop property key used to lookup Windows' icon font.
181: * This font scales with the software resolution and
182: * the desktop font size setting (Normal/Large/Extra Large).
183: * However, in some non-western Windows environments
184: * this font cannot display the locale's glyphs.<p>
185: *
186: * Implementation Note: Windows uses the icon font to label icons
187: * in the Windows Explorer and other places. It seems to me that
188: * this works in non-western environments due to font chaining.
189: *
190: * @see #getWindowsControlFont()
191: */
192: static final String WINDOWS_ICON_FONT_KEY = "win.icon.font";
193:
194: // Instance Creation ******************************************************
195:
196: private Fonts() {
197: // Override default constructor; prevents instantation.
198: }
199:
200: // Font Lookup ************************************************************
201:
202: static Font getDefaultGUIFontWesternModernWindowsNormal() {
203: return LookUtils.IS_LOW_RESOLUTION ? WINDOWS_XP_96DPI_DEFAULT_GUI
204: : WINDOWS_XP_120DPI_DEFAULT_GUI;
205: }
206:
207: static Font getDefaultIconFontWesternModernWindowsNormal() {
208: return LookUtils.IS_LOW_RESOLUTION ? WINDOWS_XP_96DPI_NORMAL
209: : WINDOWS_XP_120DPI_NORMAL;
210: }
211:
212: static Font getDefaultIconFontWesternWindowsVistaNormal() {
213: return LookUtils.IS_LOW_RESOLUTION ? WINDOWS_VISTA_96DPI_NORMAL
214: : WINDOWS_VISTA_120DPI_NORMAL;
215: }
216:
217: /**
218: * Returns the Windows control font used by the JGoodies Looks version 1.x.
219: * It is intended for visual backward compatibility only.
220: * The font returned is the default GUI font that scales with the resolution
221: * (96dpi, 120dpi, etc) but not with the desktop font size settings
222: * (normal, large, extra large).<p>
223: *
224: * On Windows Vista, the font may be completely wrong.
225: *
226: * @return the Windows default GUI font that scales with the resolution,
227: * but not the desktop font size setting
228: *
229: * @throws UnsupportedOperationException on non-Windows platforms
230: */
231: static Font getLooks1xWindowsControlFont() {
232: if (!LookUtils.IS_OS_WINDOWS)
233: throw new UnsupportedOperationException();
234:
235: return getDesktopFont(WINDOWS_DEFAULT_GUI_FONT_KEY);
236: }
237:
238: /**
239: * Looks up and returns the Windows control font. Returns the Windows icon
240: * title font unless it is inappropriate for the Windows version,
241: * Java renderer, or locale.<p>
242: *
243: * The icon title font scales with the resolution (96dpi, 101dpi, 120dpi, etc)
244: * and the desktop font size settings (normal, large, extra large).
245: * Older versions may return a poor font. Also, since Java 1.4 and Java 5
246: * render the Windows Vista icon font Segoe UI poorly,
247: * we return the default GUI font in these environments.<p>
248: *
249: * The last check is, if the icon font can display text in the
250: * default locale. Therefore we test if the locale's localized display name
251: * can be displayed by the icon font. For example, Tahoma can display
252: * "English", "Deutsch", but not the display name for "Chinese" in Chinese.
253: *
254: * @return the Windows control font
255: *
256: * @throws UnsupportedOperationException on non-Windows platforms
257: */
258: public static Font getWindowsControlFont() {
259: if (!LookUtils.IS_OS_WINDOWS)
260: throw new UnsupportedOperationException();
261:
262: Font defaultGUIFont = getDefaultGUIFont();
263: // Return the default GUI font on older Windows versions.
264: if (LookUtils.IS_OS_WINDOWS_95 || LookUtils.IS_OS_WINDOWS_98
265: || LookUtils.IS_OS_WINDOWS_NT
266: || LookUtils.IS_OS_WINDOWS_ME)
267: return defaultGUIFont;
268:
269: // Java 1.4 and Java 5 raster the Segoe UI poorly,
270: // so we use the older Tahoma, if it can display the localized text.
271: if (LookUtils.IS_OS_WINDOWS_VISTA && LookUtils.IS_JAVA_1_4_OR_5) {
272: Font tahoma = getDefaultGUIFontWesternModernWindowsNormal();
273: return Boolean.TRUE.equals(canDisplayLocalizedText(tahoma,
274: Locale.getDefault())) ? tahoma : defaultGUIFont;
275: }
276:
277: Font iconFont = getDesktopFont(WINDOWS_ICON_FONT_KEY);
278: return Boolean.TRUE.equals(canDisplayLocalizedText(iconFont,
279: Locale.getDefault())) ? iconFont : defaultGUIFont;
280: }
281:
282: /**
283: * Looks up and returns the Windows defaultGUI font.
284: * Works around a bug with Java 1.4.2_11, 1.5.0_07, and 1.6 b89
285: * in the Vista Beta2, where the win.defaultGUI.font desktop property
286: * returns null. In this case a logical "Dialog" font is used as fallback.
287: *
288: * @return the Windows defaultGUI font, or a dialog font as fallback.
289: */
290: private static Font getDefaultGUIFont() {
291: Font font = getDesktopFont(WINDOWS_DEFAULT_GUI_FONT_KEY);
292: if (font != null)
293: return font;
294: return new Font("Dialog", Font.PLAIN, 12);
295: }
296:
297: /**
298: * Checks and answers whether the given font can display text
299: * that is localized for the specified locale.
300: * Returns <code>null</code> if we can't test it.<p>
301: *
302: * First checks, if the locale's display language is available
303: * in localized form, for example "Deutsch" for the German locale.
304: * If so, we check if the given font can display the localized
305: * display language.<p>
306: *
307: * Otherwise we check some known combinations of fonts and locales
308: * and return the associated results. For all other combinations,
309: * <code>null</code> is returned to indicate that we don't know
310: * whether the font can display text in the given locale.
311: *
312: * @param font the font to be tested
313: * @param locale the locale to be used
314: * @return <code>Boolean.TRUE</code> if the font can display the locale's text,
315: * <code>Boolean.FALSE</code> if not,
316: * <code>null</code> if we don't know
317: *
318: * @since 2.0.4
319: */
320: public static Boolean canDisplayLocalizedText(Font font,
321: Locale locale) {
322: if (localeHasLocalizedDisplayLanguage(locale)) {
323: return Boolean.valueOf(canDisplayLocalizedDisplayLanguage(
324: font, locale));
325: }
326: String fontName = font.getName();
327: String language = locale.getLanguage();
328: if ("Tahoma".equals(fontName)) {
329: if ("hi".equals(language))
330: return Boolean.FALSE;
331: else if ("ja".equals(language))
332: return Boolean.FALSE;
333: else if ("ko".equals(language))
334: return Boolean.FALSE;
335: else if ("zh".equals(language))
336: return Boolean.FALSE;
337: }
338: if ("Microsoft Sans Serif".equals(fontName)) {
339: if ("ja".equals(language))
340: return Boolean.FALSE;
341: else if ("ko".equals(language))
342: return Boolean.FALSE;
343: else if ("zh".equals(language))
344: return Boolean.FALSE;
345: }
346: return null;
347: }
348:
349: /**
350: * Checks and answers if the given font can display the locale's
351: * localized display language, for example "English" for English,
352: * "Deutsch" for German, etc.
353: * The test invokes <code>Font#canDisplayUpTo</code> on the localized
354: * display language. In a Chinese locale this test
355: * will check if the font can display Chinese glyphs.
356: *
357: * @param font the font to be tested
358: * @param locale the locale to be used
359: * @return true if the font can display the locale's localized display language,
360: * false otherwise
361: */
362: private static boolean canDisplayLocalizedDisplayLanguage(
363: Font font, Locale locale) {
364: String testString = locale.getDisplayLanguage(locale);
365: int index = font.canDisplayUpTo(testString);
366: return index == -1;
367: }
368:
369: /**
370: * Checks and answers whether the locale's display language
371: * is available in a localized form, for example "Deutsch" for the
372: * German locale.
373: *
374: * @param locale the Locale to test
375: * @return true if the display language is localized, false if not
376: */
377: private static boolean localeHasLocalizedDisplayLanguage(
378: Locale locale) {
379: if (locale.getLanguage().equals(Locale.ENGLISH.getLanguage()))
380: return true;
381: String englishDisplayLanguage = locale
382: .getDisplayLanguage(Locale.ENGLISH);
383: String localizedDisplayLanguage = locale
384: .getDisplayLanguage(locale);
385: return !(englishDisplayLanguage
386: .equals(localizedDisplayLanguage));
387: }
388:
389: /**
390: * Looks up and returns a font using the default toolkit's
391: * desktop properties.
392: *
393: * @param fontName the name of the font to return
394: * @return the font
395: */
396: private static Font getDesktopFont(String fontName) {
397: Toolkit toolkit = Toolkit.getDefaultToolkit();
398: return (Font) toolkit.getDesktopProperty(fontName);
399: }
400:
401: }
|