| FontStore.java |
1 /**
2 * Distribution License:
3 * JSword is free software; you can redistribute it and/or modify it under
4 * the terms of the GNU Lesser General Public License, version 2.1 as published by
5 * the Free Software Foundation. This program is distributed in the hope
6 * that it will be useful, but WITHOUT ANY WARRANTY; without even the
7 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8 * See the GNU Lesser General Public License for more details.
9 *
10 * The License is available on the internet at:
11 * http://www.gnu.org/copyleft/lgpl.html
12 * or by writing to:
13 * Free Software Foundation, Inc.
14 * 59 Temple Place - Suite 330
15 * Boston, MA 02111-1307, USA
16 *
17 * Copyright: 2007
18 * The copyright to this program is held by it's authors.
19 *
20 * ID: $Id: org.eclipse.jdt.ui.prefs 1178 2006-11-06 12:48:02Z dmsmith $
21 */
22 package org.crosswire.common.swing;
23
24 import java.awt.Font;
25 import java.io.IOException;
26 import java.net.URI;
27
28 import org.crosswire.common.util.FileUtil;
29 import org.crosswire.common.util.Language;
30 import org.crosswire.common.util.Logger;
31 import org.crosswire.common.util.NetUtil;
32 import org.crosswire.common.util.PropertyMap;
33 import org.crosswire.common.util.ResourceUtil;
34
35 /**
36 * Font Store maintains a persistent, hierarchical store of user font
37 * preferences. A font preference consists of the name of a resource and a font
38 * specification for that resource. The name of the resource may be any unique
39 * value that follows the rules for a property key. The font specification is
40 * the font itself or a string representation of the font that can be turned
41 * into a font with <code>Font.decode(String)</code>.
42 * <p>
43 * Many languages share the same script. Rather than setting a font spec for
44 * many resources with the same language, this class makes it possible to set a
45 * font spec for each language.
46 * </p>
47 * <p>
48 * Thus, the look up hierarchy begins with an exact match for the requested
49 * resource. If it does not work the lookup continues in the following order:
50 * the specified language's font, the fallback font, and the default font. Of
51 * course, if that does not work, use any font that Java thinks is appropriate,
52 * but use the size and style of the default font. Since scripts are shared by
53 * many languages, this FontStore supports the setting of Language defaults. If
54 * the requested language font does not exist a more general one will be
55 * provided.
56 * </p>
57 * <p>
58 * Note: Some languages are represented as transliterations and others have more
59 * than one script, which may or may not be supported by a single font.
60 * </p>
61 *
62 * @see gnu.lgpl.License for license details.<br>
63 * The copyright to this program is held by it's authors.
64 * @author DM Smith [dmsmith555 at yahoo dot com]
65 */
66 public class FontStore {
67
68 /**
69 * Create an new FontStore with the given persistent store.
70 *
71 * @param storeName
72 * The name of the store, used as a file name and as a label
73 * inside the fontStore.
74 * @param fontDir
75 * The location where the fontStore can be stored.
76 */
77 public FontStore(String storeName, URI fontDir) {
78 if (fontDir == null) {
79 throw new IllegalArgumentException("fontStore cannot be null");
80 }
81 this.storeName = storeName;
82 this.fontStore = NetUtil.lengthenURI(fontDir, this.storeName + FileUtil.EXTENSION_PROPERTIES);
83 this.fontMap = new PropertyMap();
84 }
85
86 /**
87 * @return the defaultFont
88 */
89 public String getDefaultFont() {
90 load();
91 defaultFont = fontMap.get(DEFAULT_KEY, DEFAULT_FONT);
92 return defaultFont;
93 }
94
95 /**
96 * @param defaultFont
97 * the defaultFont to set
98 */
99 public void setDefaultFont(String defaultFont) {
100 load();
101 this.defaultFont = defaultFont;
102 fontMap.put(DEFAULT_KEY, defaultFont);
103 store();
104 }
105
106 /**
107 * Store a font specification for the resource.
108 *
109 * @param resource
110 * the resource
111 * @param font
112 * the font
113 */
114 public void setFont(String resource, Font font) {
115 if (resource == null || font == null) {
116 return;
117 }
118 load();
119 fontMap.put(resource, GuiConvert.font2String(font));
120 store();
121 }
122
123 /**
124 * Store a font specification for the language.
125 *
126 * @param lang
127 * the language
128 * @param font
129 * the font
130 */
131 public void setFont(Language lang, Font font) {
132 if (lang == null || font == null) {
133 return;
134 }
135 load();
136 fontMap.put(new StringBuilder(LANG_KEY_PREFIX).append(lang.getCode()).toString(), GuiConvert.font2String(font));
137 store();
138 }
139
140 /**
141 * Remove the font settings for a given key
142 *
143 * @param key
144 * the book initials or language code
145 */
146 public void resetFont(String key) {
147 load();
148 fontMap.remove(key);
149 store();
150 }
151
152 /**
153 * Get a font for the specified resource. If it does not work try the
154 * following in order: the specified language's font, the fallback font, and
155 * the default font. Of course, if that does not work, use any font that
156 * Java thinks is appropriate, but use the size and style of the default
157 * font.
158 *
159 * @param resource
160 * the name of the resource for whom the font is stored.
161 * @param lang
162 * the language of the resource
163 * @param fallback
164 * the fontspec for the fallback font
165 * @return the requested font if possible. A fallback font otherwise.
166 */
167 public Font getFont(String resource, Language lang, String fallback) {
168 load();
169
170 String fontSpec = null;
171 if (resource != null) {
172 fontSpec = fontMap.get(resource);
173 }
174
175 if (fontSpec != null) {
176 Font obtainedFont = obtainFont(fontSpec);
177 if (obtainedFont != null) {
178 return obtainedFont;
179 }
180 fontSpec = null;
181 }
182
183 if (lang != null) {
184 fontSpec = fontMap.get(new StringBuilder(LANG_KEY_PREFIX).append(lang.getCode()).toString());
185 }
186
187 if (fontSpec != null) {
188 Font obtainedFont = obtainFont(fontSpec);
189 if (obtainedFont != null) {
190 return obtainedFont;
191 }
192 }
193
194 fontSpec = fallback;
195 if (fontSpec != null) {
196 Font obtainedFont = obtainFont(fontSpec);
197 if (obtainedFont != null) {
198 return obtainedFont;
199 }
200 }
201
202 return GuiConvert.string2Font(defaultFont);
203 }
204
205 /**
206 * @return the storeName
207 */
208 protected String getStoreName() {
209 return storeName;
210 }
211
212 /**
213 * @param storeName
214 * the storeName to set
215 */
216 protected void setStoreName(String storeName) {
217 this.storeName = storeName;
218 }
219
220 /**
221 * @return the fontStore
222 */
223 protected URI getFontStore() {
224 return fontStore;
225 }
226
227 /**
228 * @param fontStore
229 * the fontStore to set
230 */
231 protected void setFontStore(URI fontStore) {
232 this.fontStore = fontStore;
233 }
234
235 /**
236 * @return the loaded
237 */
238 protected boolean isLoaded() {
239 return loaded;
240 }
241
242 /**
243 * @param loaded
244 * the loaded to set
245 */
246 protected void setLoaded(boolean loaded) {
247 this.loaded = loaded;
248 }
249
250 /**
251 * @return the fontMap
252 */
253 protected PropertyMap getFontMap() {
254 return fontMap;
255 }
256
257 /**
258 * @param fontMap
259 * the fontMap to set
260 */
261 protected void setFontMap(PropertyMap fontMap) {
262 this.fontMap = fontMap;
263 }
264
265 /**
266 * Load the store, if it has not been loaded.
267 */
268 protected void load() {
269 if (loaded) {
270 return;
271 }
272
273 try {
274 fontMap = ResourceUtil.getProperties(storeName);
275 loaded = true;
276 } catch (IOException e) {
277 log.error("Unable to load the font store: " + fontStore);
278 fontMap = new PropertyMap();
279 }
280 }
281
282 /**
283 * Store the store, if it exists.
284 */
285 protected void store() {
286 load();
287
288 try {
289 NetUtil.storeProperties(fontMap, fontStore, storeName);
290 } catch (IOException ex) {
291 log.error("Failed to save BibleDesktop UI Translation", ex);
292 }
293 }
294
295 protected Font obtainFont(String fontSpec) {
296 if (fontSpec != null) {
297 // Creating a font never fails. Java just silently does
298 // substitution.
299 // Ensure that substitution does not happen.
300 Font obtainedFont = GuiConvert.string2Font(fontSpec);
301 String obtainedFontSpec = GuiConvert.font2String(obtainedFont);
302 if (obtainedFontSpec != null && obtainedFontSpec.equalsIgnoreCase(fontSpec)) {
303 return obtainedFont;
304 }
305 }
306 return null;
307 }
308
309 protected static final String DEFAULT_FONT = "Dialog-PLAIN-12";
310 protected static final String LANG_KEY_PREFIX = "lang.";
311 protected static final String DEFAULT_KEY = "default";
312
313 private String storeName;
314 private String defaultFont;
315 private URI fontStore;
316 private boolean loaded;
317 private PropertyMap fontMap;
318
319 private static final Logger log = Logger.getLogger(FontStore.class);
320 }
321