comparison dwtx/jface/resource/FontRegistry.d @ 7:8a302fdb4140

Jface some window and resource classes
author Frank Benoit <benoit@tionex.de>
date Fri, 28 Mar 2008 23:32:40 +0100
parents
children 644f1334b451
comparison
equal deleted inserted replaced
6:1a6747be662d 7:8a302fdb4140
1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13 module dwtx.jface.resource.FontRegistry;
14
15 import dwtx.jface.resource.ResourceRegistry;
16 import dwtx.jface.resource.FontDescriptor;
17 import dwtx.jface.resource.StringConverter;
18 import dwtx.jface.resource.JFaceResources;
19 import dwtx.jface.resource.DataFormatException;
20
21 import tango.util.collection.ArraySeq;
22 import tango.util.collection.HashMap;
23 import tango.util.collection.model.Map;
24 import tango.util.collection.model.Seq;
25 import tango.util.collection.model.Set;
26 import tango.util.collection.model.SetView;
27 import tango.util.collection.HashSet;
28 // import java.util.Arrays;
29 // import java.util.Collections;
30 // import java.util.Enumeration;
31 // import java.util.HashMap;
32 // import java.util.Iterator;
33 // import java.util.List;
34 // import java.util.Map;
35 // import java.util.MissingResourceException;
36 // import java.util.Set;
37
38 import dwt.DWT;
39 import dwt.graphics.Font;
40 import dwt.graphics.FontData;
41 import dwt.widgets.Display;
42 import dwt.widgets.Shell;
43 import dwtx.core.runtime.Assert;
44
45 import dwt.dwthelper.ResourceBundle;
46 import dwt.dwthelper.utils;
47 import dwt.dwthelper.Runnable;
48
49 /**
50 * A font registry maintains a mapping between symbolic font names
51 * and DWT fonts.
52 * <p>
53 * A font registry owns all of the font objects registered
54 * with it, and automatically disposes of them when the DWT Display
55 * that creates the fonts is disposed. Because of this, clients do
56 * not need to (indeed, must not attempt to) dispose of font
57 * objects themselves.
58 * </p>
59 * <p>
60 * A special constructor is provided for populating a font registry
61 * from a property files using the standard Java resource bundle mechanism.
62 * </p>
63 * <p>
64 * Methods are provided for registering listeners that will be kept
65 * apprised of changes to list of registed fonts.
66 * </p>
67 * <p>
68 * Clients may instantiate this class (it was not designed to be subclassed).
69 * </p>
70 *
71 * Since 3.0 this class extends ResourceRegistry.
72 */
73 public class FontRegistry : ResourceRegistry {
74
75 /**
76 * FontRecord is a private helper class that holds onto a font
77 * and can be used to generate its bold and italic version.
78 */
79 private class FontRecord {
80
81 Font baseFont;
82
83 Font boldFont;
84
85 Font italicFont;
86
87 FontData[] baseData;
88
89 /**
90 * Create a new instance of the receiver based on the
91 * plain font and the data for it.
92 * @param plainFont The base looked up font.
93 * @param data The data used to look it up.
94 */
95 this(Font plainFont, FontData[] data) {
96 baseFont = plainFont;
97 baseData = data;
98 }
99
100 /**
101 * Dispose any of the fonts created for this record.
102 */
103 void dispose() {
104 baseFont.dispose();
105 if (boldFont !is null) {
106 boldFont.dispose();
107 }
108 if (italicFont !is null) {
109 italicFont.dispose();
110 }
111 }
112
113 /**
114 * Return the base Font.
115 * @return Font
116 */
117 public Font getBaseFont() {
118 return baseFont;
119 }
120
121 /**
122 * Return the bold Font. Create a bold version
123 * of the base font to get it.
124 * @return Font
125 */
126 public Font getBoldFont() {
127 if (boldFont !is null) {
128 return boldFont;
129 }
130
131 FontData[] boldData = getModifiedFontData(DWT.BOLD);
132 boldFont = new Font(Display.getCurrent(), boldData);
133 return boldFont;
134 }
135
136 /**
137 * Get a version of the base font data with the specified
138 * style.
139 * @param style the new style
140 * @return the font data with the style {@link FontData#FontData(String, int, int)}
141 * @see DWT#ITALIC
142 * @see DWT#NORMAL
143 * @see DWT#BOLD
144 * @todo Generated comment
145 */
146 private FontData[] getModifiedFontData(int style) {
147 FontData[] styleData = new FontData[baseData.length];
148 for (int i = 0; i < styleData.length; i++) {
149 FontData base = baseData[i];
150 styleData[i] = new FontData(base.getName(), base.getHeight(),
151 base.getStyle() | style);
152 }
153
154 return styleData;
155 }
156
157 /**
158 * Return the italic Font. Create an italic version of the
159 * base font to get it.
160 * @return Font
161 */
162 public Font getItalicFont() {
163 if (italicFont !is null) {
164 return italicFont;
165 }
166
167 FontData[] italicData = getModifiedFontData(DWT.ITALIC);
168 italicFont = new Font(Display.getCurrent(), italicData);
169 return italicFont;
170 }
171
172 /**
173 * Add any fonts that were allocated for this record to the
174 * stale fonts. Anything that matches the default font will
175 * be skipped.
176 * @param defaultFont The system default.
177 */
178 void addAllocatedFontsToStale(Font defaultFont) {
179 //Return all of the fonts allocated by the receiver.
180 //if any of them are the defaultFont then don't bother.
181 if (defaultFont !is baseFont && baseFont !is null) {
182 staleFonts.append(baseFont);
183 }
184 if (defaultFont !is boldFont && boldFont !is null) {
185 staleFonts.append(boldFont);
186 }
187 if (defaultFont !is italicFont && italicFont !is null) {
188 staleFonts.append(italicFont);
189 }
190 }
191 }
192
193 /**
194 * Table of known fonts, keyed by symbolic font name
195 * (key type: <code>String</code>,
196 * value type: <code>FontRecord</code>.
197 */
198 private Map!(String,FontRecord) stringToFontRecord;
199
200 /**
201 * Table of known font data, keyed by symbolic font name
202 * (key type: <code>String</code>,
203 * value type: <code>dwt.graphics.FontData[]</code>).
204 */
205 private Map!(String,FontData[]) stringToFontData;
206
207 /**
208 * Collection of Fonts that are now stale to be disposed
209 * when it is safe to do so (i.e. on shutdown).
210 * @see List
211 */
212 private Seq!(Font) staleFonts;
213
214 /**
215 * Runnable that cleans up the manager on disposal of the display.
216 */
217 protected Runnable displayRunnable;
218
219 /**
220 * Creates an empty font registry.
221 * <p>
222 * There must be an DWT Display created in the current
223 * thread before calling this method.
224 * </p>
225 */
226 public this() {
227 this(Display.getCurrent(), true);
228 }
229
230 /**
231 * Creates a font registry and initializes its content from
232 * a property file.
233 * <p>
234 * There must be an DWT Display created in the current
235 * thread before calling this method.
236 * </p>
237 * <p>
238 * The OS name (retrieved using <code>System.getProperty("os.name")</code>)
239 * is converted to lowercase, purged of whitespace, and appended
240 * as suffix (separated by an underscore <code>'_'</code>) to the given
241 * location string to yield the base name of a resource bundle
242 * acceptable to <code>ResourceBundle.getBundle</code>.
243 * The standard Java resource bundle mechanism is then used to locate
244 * and open the appropriate properties file, taking into account
245 * locale specific variations.
246 * </p>
247 * <p>
248 * For example, on the Windows 2000 operating system the location string
249 * <code>"com.example.myapp.Fonts"</code> yields the base name
250 * <code>"com.example.myapp.Fonts_windows2000"</code>. For the US English locale,
251 * this further elaborates to the resource bundle name
252 * <code>"com.example.myapp.Fonts_windows2000_en_us"</code>.
253 * </p>
254 * <p>
255 * If no appropriate OS-specific resource bundle is found, the
256 * process is repeated using the location as the base bundle name.
257 * </p>
258 * <p>
259 * The property file contains entries that look like this:
260 * <pre>
261 * textfont.0=MS Sans Serif-regular-10
262 * textfont.1=Times New Roman-regular-10
263 *
264 * titlefont.0=MS Sans Serif-regular-12
265 * titlefont.1=Times New Roman-regular-12
266 * </pre>
267 * Each entry maps a symbolic font names (the font registry keys) with
268 * a "<code>.<it>n</it></code> suffix to standard font names
269 * on the right. The suffix indicated order of preference:
270 * "<code>.0</code>" indicates the first choice,
271 * "<code>.1</code>" indicates the second choice, and so on.
272 * </p>
273 * The following example shows how to use the font registry:
274 * <pre>
275 * FontRegistry registry = new FontRegistry("com.example.myapp.fonts");
276 * Font font = registry.get("textfont");
277 * control.setFont(font);
278 * ...
279 * </pre>
280 *
281 * @param location the name of the resource bundle
282 * @param loader the ClassLoader to use to find the resource bundle
283 * @exception MissingResourceException if the resource bundle cannot be found
284 * @since 2.1
285 */
286 public this(String location, /+ClassLoader+/Object loader){
287 initInstance();
288 Display display = Display.getCurrent();
289 Assert.isNotNull(display);
290 // FIXE: need to respect loader
291 //readResourceBundle(location, loader);
292 readResourceBundle(location);
293
294 hookDisplayDispose(display);
295 }
296
297 private void initInstance(){
298 displayRunnable = new class Runnable {
299 public void run() {
300 clearCaches();
301 }
302 };
303 stringToFontRecord = new HashMap!(String,FontRecord);
304 //stringToFontRecord.capacity(7);
305
306 stringToFontData = new HashMap!(String,FontData[]);
307 //stringToFontData.capacity(7);
308
309 staleFonts = new ArraySeq!(Font);
310 }
311
312 /**
313 * Load the FontRegistry using the ClassLoader from the PlatformUI
314 * plug-in
315 * @param location the location to read the resource bundle from
316 * @throws MissingResourceException Thrown if a resource is missing
317 */
318 public this(String location) {
319 // FIXE:
320 // this(location, WorkbenchPlugin.getDefault().getDescriptor().getPluginClassLoader());
321 this(location, null);
322 }
323
324 /**
325 * Read the resource bundle at location. Look for a file with the
326 * extension _os_ws first, then _os then just the name.
327 * @param location - String - the location of the file.
328 */
329
330 private void readResourceBundle(String location) {
331 String osname = System.getProperty("os.name").trim(); //$NON-NLS-1$
332 String wsname = DWT.getPlatform();
333 osname = StringConverter.removeWhiteSpaces(osname).toLowerCase();
334 wsname = StringConverter.removeWhiteSpaces(wsname).toLowerCase();
335 String OSLocation = location;
336 String WSLocation = location;
337 ResourceBundle bundle = null;
338 if (osname !is null) {
339 OSLocation = location ~ "_" ~ osname; //$NON-NLS-1$
340 if (wsname !is null) {
341 WSLocation = OSLocation ~ "_" ~ wsname; //$NON-NLS-1$
342 }
343 }
344
345 try {
346 bundle = ResourceBundle.getBundle(WSLocation);
347 readResourceBundle(bundle, WSLocation);
348 } catch (MissingResourceException wsException) {
349 try {
350 bundle = ResourceBundle.getBundle(OSLocation);
351 readResourceBundle(bundle, WSLocation);
352 } catch (MissingResourceException osException) {
353 if (location !is OSLocation) {
354 bundle = ResourceBundle.getBundle(location);
355 readResourceBundle(bundle, WSLocation);
356 } else {
357 throw osException;
358 }
359 }
360 }
361 }
362
363 /**
364 * Creates an empty font registry.
365 *
366 * @param display the Display
367 */
368 public this(Display display) {
369 this(display, true);
370 }
371
372 /**
373 * Creates an empty font registry.
374 *
375 * @param display
376 * the <code>Display</code>
377 * @param cleanOnDisplayDisposal
378 * whether all fonts allocated by this <code>FontRegistry</code>
379 * should be disposed when the display is disposed
380 * @since 3.1
381 */
382 public this(Display display, bool cleanOnDisplayDisposal) {
383 initInstance();
384 Assert.isNotNull(display);
385 if (cleanOnDisplayDisposal) {
386 hookDisplayDispose(display);
387 }
388 }
389
390 /**
391 * Find the first valid fontData in the provided list. If none are valid
392 * return the first one regardless. If the list is empty return null. Return
393 * <code>null</code> if one cannot be found.
394 *
395 * @param fonts the font list
396 * @param display the display used
397 * @return the font data of the like describe above
398 *
399 * @deprecated use bestDataArray in order to support Motif multiple entry
400 * fonts.
401 */
402 public FontData bestData(FontData[] fonts, Display display) {
403 for (int i = 0; i < fonts.length; i++) {
404 FontData fd = fonts[i];
405
406 if (fd is null) {
407 break;
408 }
409
410 FontData[] fixedFonts = display.getFontList(fd.getName(), false);
411 if (isFixedFont(fixedFonts, fd)) {
412 return fd;
413 }
414
415 FontData[] scalableFonts = display.getFontList(fd.getName(), true);
416 if (scalableFonts.length > 0) {
417 return fd;
418 }
419 }
420
421 //None of the provided datas are valid. Return the
422 //first one as it is at least the first choice.
423 if (fonts.length > 0) {
424 return fonts[0];
425 }
426
427 //Nothing specified
428 return null;
429 }
430
431 /**
432 * Find the first valid fontData in the provided list.
433 * If none are valid return the first one regardless.
434 * If the list is empty return <code>null</code>.
435 *
436 * @param fonts list of fonts
437 * @param display the display
438 * @return font data like described above
439 * @deprecated use filterData in order to preserve
440 * multiple entry fonts on Motif
441 */
442 public FontData[] bestDataArray(FontData[] fonts, Display display) {
443
444 FontData bestData = bestData(fonts, display);
445 if (bestData is null) {
446 return null;
447 }
448
449 FontData[] datas = new FontData[1];
450 datas[0] = bestData;
451 return datas;
452 }
453
454 /**
455 * Removes from the list all fonts that do not exist in this system.
456 * If none are valid, return the first irregardless. If the list is
457 * empty return <code>null</code>.
458 *
459 * @param fonts the fonts to check
460 * @param display the display to check against
461 * @return the list of fonts that have been found on this system
462 * @since 3.1
463 */
464 public FontData [] filterData(FontData [] fonts, Display display) {
465 ArraySeq!(FontData) good = new ArraySeq!(FontData);
466 good.capacity(fonts.length);
467 for (int i = 0; i < fonts.length; i++) {
468 FontData fd = fonts[i];
469
470 if (fd is null) {
471 continue;
472 }
473
474 FontData[] fixedFonts = display.getFontList(fd.getName(), false);
475 if (isFixedFont(fixedFonts, fd)) {
476 good.append(fd);
477 }
478
479 FontData[] scalableFonts = display.getFontList(fd.getName(), true);
480 if (scalableFonts.length > 0) {
481 good.append(fd);
482 }
483 }
484
485
486 //None of the provided datas are valid. Return the
487 //first one as it is at least the first choice.
488 if (good.drained() && fonts.length > 0) {
489 good.append(fonts[0]);
490 }
491 else if (fonts.length is 0) {
492 return null;
493 }
494
495 return good.toArray();
496 }
497
498
499 /**
500 * Creates a new font with the given font datas or <code>null</code>
501 * if there is no data.
502 * @return FontRecord for the new Font or <code>null</code>.
503 */
504 private FontRecord createFont(String symbolicName, FontData[] fonts) {
505 Display display = Display.getCurrent();
506 if (display is null) {
507 return null;
508 }
509
510 FontData[] validData = filterData(fonts, display);
511 if (validData.length is 0) {
512 //Nothing specified
513 return null;
514 }
515
516 //Do not fire the update from creation as it is not a property change
517 put(symbolicName, validData, false);
518 Font newFont = new Font(display, validData);
519 return new FontRecord(newFont, validData);
520 }
521
522 /**
523 * Calculates the default font and returns the result.
524 * This method creates a font that must be disposed.
525 */
526 Font calculateDefaultFont() {
527 Display current = Display.getCurrent();
528 if (current is null) {
529 Shell shell = new Shell();
530 Font font = new Font(null, shell.getFont().getFontData());
531 shell.dispose();
532 return font;
533 }
534 return new Font(current, current.getSystemFont().getFontData());
535 }
536
537 /**
538 * Returns the default font data. Creates it if necessary.
539 * @return Font
540 */
541 public Font defaultFont() {
542 return defaultFontRecord().getBaseFont();
543 }
544
545 /**
546 * Returns the font descriptor for the font with the given symbolic
547 * font name. Returns the default font if there is no special value
548 * associated with that name
549 *
550 * @param symbolicName symbolic font name
551 * @return the font descriptor (never null)
552 *
553 * @since 3.3
554 */
555 public FontDescriptor getDescriptor(String symbolicName) {
556 Assert.isTrue(symbolicName.length > 0);
557 return FontDescriptor.createFrom(getFontData(symbolicName));
558 }
559
560
561
562 /**
563 * Returns the default font record.
564 */
565 private FontRecord defaultFontRecord() {
566
567 FontRecord record = cast(FontRecord) stringToFontRecord
568 .get(JFaceResources.DEFAULT_FONT);
569 if (record is null) {
570 Font defaultFont = calculateDefaultFont();
571 record = createFont(JFaceResources.DEFAULT_FONT, defaultFont
572 .getFontData());
573 defaultFont.dispose();
574 stringToFontRecord.add(JFaceResources.DEFAULT_FONT, record);
575 }
576 return record;
577 }
578
579 /**
580 * Returns the default font data. Creates it if necessary.
581 */
582 private FontData[] defaultFontData() {
583 return defaultFontRecord().baseData;
584 }
585
586 /**
587 * Returns the font data associated with the given symbolic font name.
588 * Returns the default font data if there is no special value associated
589 * with that name.
590 *
591 * @param symbolicName symbolic font name
592 * @return the font
593 */
594 public FontData[] getFontData(String symbolicName) {
595
596 Assert.isTrue(symbolicName.length > 0);
597 auto result = stringToFontData.get(symbolicName);
598 if (result.length is 0) {
599 return defaultFontData();
600 }
601
602 return result;
603 }
604
605 /**
606 * Returns the font associated with the given symbolic font name.
607 * Returns the default font if there is no special value associated
608 * with that name.
609 *
610 * @param symbolicName symbolic font name
611 * @return the font
612 */
613 public Font get(String symbolicName) {
614
615 return getFontRecord(symbolicName).getBaseFont();
616 }
617
618 /**
619 * Returns the bold font associated with the given symbolic font name.
620 * Returns the bolded default font if there is no special value associated
621 * with that name.
622 *
623 * @param symbolicName symbolic font name
624 * @return the font
625 * @since 3.0
626 */
627 public Font getBold(String symbolicName) {
628
629 return getFontRecord(symbolicName).getBoldFont();
630 }
631
632 /**
633 * Returns the italic font associated with the given symbolic font name.
634 * Returns the italic default font if there is no special value associated
635 * with that name.
636 *
637 * @param symbolicName symbolic font name
638 * @return the font
639 * @since 3.0
640 */
641 public Font getItalic(String symbolicName) {
642
643 return getFontRecord(symbolicName).getItalicFont();
644 }
645
646 /**
647 * Return the font record for the key.
648 * @param symbolicName The key for the record.
649 * @return FontRecird
650 */
651 private FontRecord getFontRecord(String symbolicName) {
652 Assert.isNotNull(symbolicName);
653 Object result1 = stringToFontRecord.get(symbolicName);
654 if (result1 !is null) {
655 return cast(FontRecord) result1;
656 }
657
658 auto result = stringToFontData.get(symbolicName);
659
660 FontRecord fontRecord;
661
662 if (result is null) {
663 fontRecord = defaultFontRecord();
664 } else {
665 fontRecord = createFont(symbolicName, result);
666 }
667
668 if (fontRecord is null) {
669 fontRecord = defaultFontRecord();
670 }
671
672 stringToFontRecord.add(symbolicName, fontRecord);
673 return fontRecord;
674
675 }
676
677 /* (non-Javadoc)
678 * @see dwtx.jface.resource.ResourceRegistry#getKeySet()
679 */
680 public SetView!(String) getKeySet() {
681 auto res = new HashSet!(String);
682 foreach( k, v; stringToFontData ){
683 res.add( k );
684 }
685 return res;
686 }
687
688 /* (non-Javadoc)
689 * @see dwtx.jface.resource.ResourceRegistry#hasValueFor(java.lang.String)
690 */
691 public bool hasValueFor(String fontKey) {
692 return stringToFontData.containsKey(fontKey);
693 }
694
695 /* (non-Javadoc)
696 * @see dwtx.jface.resource.ResourceRegistry#clearCaches()
697 */
698 protected void clearCaches() {
699 foreach( k,v; stringToFontRecord ){
700 v.dispose();
701 }
702
703 disposeFonts(staleFonts);
704 stringToFontRecord.clear();
705 staleFonts.clear();
706 }
707
708 /**
709 * Dispose of all of the fonts in this iterator.
710 * @param iterator over Collection of Font
711 */
712 private void disposeFonts( Seq!(Font) list ) {
713 foreach( fnt; list ){
714 fnt.dispose();
715 }
716 }
717
718 /**
719 * Hook a dispose listener on the DWT display.
720 */
721 private void hookDisplayDispose(Display display) {
722 display.disposeExec(displayRunnable);
723 }
724
725 /**
726 * Checks whether the given font is in the list of fixed fonts.
727 */
728 private bool isFixedFont(FontData[] fixedFonts, FontData fd) {
729 // Can't use FontData.equals() since some values aren't
730 // set if a fontdata isn't used.
731 int height = fd.getHeight();
732 String name = fd.getName();
733 for (int i = 0; i < fixedFonts.length; i++) {
734 FontData fixed = fixedFonts[i];
735 if (fixed.getHeight() is height && fixed.getName().equals(name)) {
736 return true;
737 }
738 }
739 return false;
740 }
741
742 /**
743 * Converts a String into a FontData object.
744 */
745 private FontData makeFontData(String value) {
746 try {
747 return StringConverter.asFontData(value.trim());
748 } catch (DataFormatException e) {
749 throw new MissingResourceException(
750 "Wrong font data format. Value is: \"" ~ value ~ "\"", this.classinfo.name, value); //$NON-NLS-2$//$NON-NLS-1$
751 }
752 }
753
754 /**
755 * Adds (or replaces) a font to this font registry under the given
756 * symbolic name.
757 * <p>
758 * A property change event is reported whenever the mapping from
759 * a symbolic name to a font changes. The source of the event is
760 * this registry; the property name is the symbolic font name.
761 * </p>
762 *
763 * @param symbolicName the symbolic font name
764 * @param fontData an Array of FontData
765 */
766 public void put(String symbolicName, FontData[] fontData) {
767 put(symbolicName, fontData, true);
768 }
769
770 /**
771 * Adds (or replaces) a font to this font registry under the given
772 * symbolic name.
773 * <p>
774 * A property change event is reported whenever the mapping from
775 * a symbolic name to a font changes. The source of the event is
776 * this registry; the property name is the symbolic font name.
777 * </p>
778 *
779 * @param symbolicName the symbolic font name
780 * @param fontData an Array of FontData
781 * @param update - fire a font mapping changed if true. False
782 * if this method is called from the get method as no setting
783 * has changed.
784 */
785 private void put(String symbolicName, FontData[] fontData, bool update) {
786
787 Assert.isNotNull(symbolicName);
788 Assert.isTrue(fontData.length > 0 );
789
790 FontData[] existing = stringToFontData.get(symbolicName);
791 if (ArrayEquals(existing, fontData)) {
792 return;
793 }
794
795 FontRecord oldFont = stringToFontRecord.get(symbolicName);
796 stringToFontRecord.removeKey(symbolicName);
797 stringToFontData.add(symbolicName, fontData);
798 if (update) {
799 fireMappingChanged(symbolicName, new ArrayWrapperT!(FontData)(existing), new ArrayWrapperT!(FontData)(fontData));
800 }
801
802 if (oldFont !is null) {
803 oldFont.addAllocatedFontsToStale(defaultFontRecord().getBaseFont());
804 }
805 }
806
807 /**
808 * Reads the resource bundle. This puts FontData[] objects
809 * in the mapping table. These will lazily be turned into
810 * real Font objects when requested.
811 */
812 private void readResourceBundle(ResourceBundle bundle, String bundleName) {
813 foreach( key; bundle.getKeys() ){
814 int pos = key.lastIndexOf('.');
815 if (pos is -1) {
816 stringToFontData.add(key, [ makeFontData(bundle.getString(key)) ]);
817 } else {
818 String name = key.substring(0, pos);
819 int i = 0;
820 try {
821 i = tango.text.convert.Integer.toInt(key.substring(pos + 1));
822 } catch (IllegalArgumentException e) {
823 //Panic the file can not be parsed.
824 throw new MissingResourceException(
825 "Wrong key format ", bundleName, key); //$NON-NLS-1$
826 }
827 FontData[] elements = stringToFontData.get(name);
828 if (elements is null) {
829 elements = new FontData[8];
830 stringToFontData.add(name, elements);
831 }
832 if (i > elements.length) {
833 FontData[] na = new FontData[i + 8];
834 System.arraycopy(elements, 0, na, 0, elements.length);
835 elements = na;
836 stringToFontData.add(name, elements);
837 }
838 elements[i] = makeFontData(bundle.getString(key));
839 }
840 }
841 }
842
843 /**
844 * Returns the font descriptor for the JFace default font.
845 *
846 * @return the font descriptor for the JFace default font
847 * @since 3.3
848 */
849 public FontDescriptor defaultFontDescriptor() {
850 return FontDescriptor.createFrom(defaultFontData());
851 }
852 }