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