Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/port80/eclipse/util/FontFactory.java


1   package com.port80.eclipse.util;
2   
3   import java.util.Collection;
4   import java.util.HashMap;
5   import java.util.HashSet;
6   import java.util.Iterator;
7   import java.util.Map;
8   import java.util.Set;
9   import java.util.StringTokenizer;
10  
11  import org.eclipse.swt.SWT;
12  import org.eclipse.swt.custom.ScrolledComposite;
13  import org.eclipse.swt.events.DisposeEvent;
14  import org.eclipse.swt.events.DisposeListener;
15  import org.eclipse.swt.graphics.Color;
16  import org.eclipse.swt.graphics.Font;
17  import org.eclipse.swt.graphics.FontData;
18  import org.eclipse.swt.layout.FillLayout;
19  import org.eclipse.swt.layout.RowLayout;
20  import org.eclipse.swt.widgets.Composite;
21  import org.eclipse.swt.widgets.Display;
22  import org.eclipse.swt.widgets.Label;
23  import org.eclipse.swt.widgets.Shell;
24  
25  import com.port80.util.Debug;
26  import com.port80.util.attr.IAttrFactory;
27  
28  /**
29   * SWT Font factory and cache.
30   */
31  public class FontFactory implements IAttrFactory, DisposeListener {
32  
33    ////////////////////////////////////////////////////////////////////////
34  
35    private static final String NAME = "FontFactory";
36    private static final boolean DEBUG = true;
37    private static boolean VERBOSE = Debug.isVerbose();
38  
39    private static final int DEFAULT_SIZE = 12;
40  
41    private static FontFactory fInstance = null;
42    private static Display fDisplay;
43  
44    ////////////////////////////////////////////////////////////////////////
45  
46    private Map fFontTable;
47  
48    ////////////////////////////////////////////////////////////////////////
49  
50    public FontFactory() {
51      fDisplay = Display.getDefault();
52      fFontTable = new HashMap();
53    }
54  
55    ////////////////////////////////////////////////////////////////////////
56  
57    public static FontFactory getDefault() {
58      if (fInstance == null)
59        fInstance = new FontFactory();
60      return fInstance;
61    }
62  
63    ////////////////////////////////////////////////////////////////////////
64  
65    /** 
66     * Create or get the specified font from cache if already created. 
67     * String representation of a font spec., accepted format:
68     * eg. "comic sans-bold italic-12"
69     */
70    public Font create(String spec) {
71      if (fInstance == null)
72        fInstance = new FontFactory();
73      if (DEBUG)
74        System.err.println(NAME + ".create(String): spec=" + spec);
75      int index=spec.indexOf(';');
76      if(index>=0) spec=spec.substring(0,index);
77      spec = spec.toLowerCase();
78      if (spec.startsWith("1|"))
79        spec = convertFontSpecFormat(spec);
80      Font ret = (Font) fFontTable.get(spec);
81      if (ret != null)
82        return ret;
83      FontData fontdata = parseFontSpec(spec);
84      ret = new Font(fDisplay, fontdata);
85      fFontTable.put(spec, ret);
86      return ret;
87    }
88  
89    public Font create(String fontname, int size, int style) {
90      if (fInstance == null)
91        fInstance = new FontFactory();
92      if (DEBUG)
93        System.err.println(NAME + ".create(): fontname=" + fontname + ", size=" + size + ", style=" + style);
94      String spec = getFontSpec(fontname, size, style);
95      Font ret = (Font) fFontTable.get(spec);
96      if (ret != null)
97        return ret;
98      ret = new Font(fDisplay, fontname, size, style);
99      if (ret == null && VERBOSE)
100       System.err.println("Error creating font: " + fontname + ", size=" + size + ", style=" + style);
101     fFontTable.put(spec, ret);
102     return ret;
103   }
104 
105   /** Derive a new Font from the given Font and new size. */
106   public Font deriveFont(Font font, int size) {
107     //FIXME: Not work for multiple FontData.
108     return deriveFont(font, size, font.getFontData()[0].getStyle());
109   }
110 
111   /** Derive a new Font from the given Font and new size and style. */
112   public Font deriveFont(Font font, int size, int style) {
113     FontData data = font.getFontData()[0];
114     if (size < 0)
115       size = data.getHeight();
116     return create(data.getName(), size, style);
117   }
118 
119   public void dispose(String spec) {
120     Font font = (Font) fFontTable.get(spec);
121     if (font != null) {
122       font.dispose();
123     }
124     if (VERBOSE)
125       System.err.println(NAME + ": disposed " + fFontTable.size() + " fonts.");
126     fFontTable.clear();
127   }
128 
129   ////////////////////////////////////////////////////////////////////////
130 
131   /**
132    * Dispose cached font resource.  
133    * Typically this should be listening to the main window DisposeEvent.
134    */
135   public void widgetDisposed(DisposeEvent e) {
136     dispose();
137   }
138 
139   public void dispose() {
140     Collection values = fFontTable.values();
141     Font font;
142     for (Iterator it = values.iterator(); it.hasNext();) {
143       font = (Font) it.next();
144       font.dispose();
145     }
146     if (VERBOSE)
147       System.err.println(NAME + ".dispose(): " + fFontTable.size() + " fonts.");
148     if (DEBUG) {
149       for (Iterator it = fFontTable.keySet().iterator(); it.hasNext();) {
150         String name = (String) it.next();
151         System.err.println("\t" + name);
152       }
153     }
154     fFontTable.clear();
155   }
156 
157   // IAttrFactory interface //////////////////////////////////////////////
158   //
159 
160   /** 
161    * Convert String representation of an attribute value to the
162    * appropriate object for storing in AttrTable. 
163    *
164    * String representation of a font spec., accepted format:
165    * eg. "comic sans-bold italic-12"
166    *  
167    * Note:  Case is insignificant in the font spec. but spaces in fontname is significant.
168    * Spaces and order in font style is not significant. Size must be an integer.
169    */
170   public Object createObject(String attrvalue) {
171     return create(attrvalue);
172   }
173 
174   public boolean isValid(Object a) {
175     return (a instanceof Font);
176   }
177 
178   public Class getObjectClass() {
179     return Font.class;
180   }
181   
182   /** The String representation of an attribute value. */
183   public String toString(Object attr) {
184     return attr.toString();
185   }
186 
187   /** The String representation of attribute type itself. */
188   public String toString() {
189     return NAME;
190   }
191 
192   /** Prompt user and present a user interface to obtain an
193        *  attribute value from user. */
194   public Object promptUser(String prompt) {
195     return null;
196   }
197 
198   ////////////////////////////////////////////////////////////////////////
199 
200   /**
201    * Convert FontData serialized format font spec. to foundry-family-style-size format.
202    */
203   public static String convertFontSpecFormat(String spec) {
204     // Assume FontData serailized format.
205     // 1|arial black|10|0|motif|1|-monotype-arial black-medium-r-normal--14-100-100-100-p-77-iso8859-15;
206     // Apparently, new FontData(spec) don't work, use new FontData(name, size, style).
207     String sizestr, stylestr, foundry;
208     int index, style;
209     index = spec.indexOf("|");
210     spec = spec.substring(index + 1);
211     index = spec.indexOf('|');
212     sizestr = spec.substring(index + 1);
213     spec = spec.substring(0, index);
214     // spec=arial black, sizestr=10|0|...
215     index = sizestr.indexOf('|');
216     stylestr = sizestr.substring(index + 1);
217     sizestr = sizestr.substring(0, index);
218     index = stylestr.indexOf('|');
219     foundry=stylestr.substring(index+1);
220     stylestr = stylestr.substring(0, index);
221     index=foundry.indexOf('-');
222     foundry=foundry.substring(index+1);
223     index=foundry.indexOf('-');
224     foundry=foundry.substring(0, index);
225     //
226     style = SWT.NORMAL;
227     if (stylestr != null && stylestr.length() > 0) {
228       try {
229         style = Integer.parseInt(stylestr);
230       } catch (Exception e) {
231       }
232     }
233     if ((style & SWT.BOLD) != 0)
234       stylestr = "bold";
235     else
236       stylestr = "";
237     if ((style & SWT.ITALIC) != 0)
238       if (stylestr.length() > 0)
239         stylestr += " italic";
240       else
241         stylestr = "italic";
242     return foundry+'-'+spec + '-' + stylestr + '-' + sizestr;
243   }
244 
245   ////////////////////////////////////////////////////////////////////////
246 
247   /** Parse a font spec. string. */
248   public static FontData parseFontSpec(String spec) {
249     String stylestr = null;
250     String sizestr = null;
251     int index;
252     int size;
253     int style;
254     index = spec.lastIndexOf('-');
255     if (index >= 0) {
256       sizestr = spec.substring(index + 1);
257       spec = spec.substring(0, index);
258     }
259     index = spec.lastIndexOf('-');
260     if (index >= 0) {
261       stylestr = spec.substring(index + 1);
262       spec = spec.substring(0, index);
263     }
264     //
265     style = SWT.NORMAL;
266     if (stylestr != null && stylestr.length() > 0) {
267       StringTokenizer st = new StringTokenizer(stylestr, " \t\n\r");
268       while (st.hasMoreTokens()) {
269         String s = st.nextToken();
270         if (s.equalsIgnoreCase("bold")) {
271           style |= SWT.BOLD;
272         } else if (s.equalsIgnoreCase("italic")) {
273           style |= SWT.ITALIC;
274         }
275       }
276     }
277     if (DEBUG)
278       System.err.println(
279         NAME
280           + ".create(String): fontname="
281           + spec
282           + ", stylestr="
283           + stylestr
284           + ", sizestr="
285           + sizestr);
286     //
287     size = DEFAULT_SIZE;
288     if (sizestr != null && sizestr.length() > 0) {
289       size = Integer.parseInt(sizestr);
290     }
291     return new FontData(spec, size, style);
292   }
293 
294   /**
295    * Create a clean formatted font spec.
296    */
297   private static String getFontSpec(String fontname, int size, int style) {
298     StringBuffer ret = new StringBuffer(fontname + "-");
299     if ((style & SWT.BOLD) != 0)
300       ret.append("bold");
301     if ((style & SWT.ITALIC) != 0) {
302       if (ret.charAt(ret.length() - 1) == '-')
303         ret.append("italic");
304       else
305         ret.append(" italic");
306     }
307     ret.append("-" + size);
308     return ret.toString();
309   }
310 
311   private static String getFontSpec(Font font) {
312     FontData fontdata = font.getFontData()[0];
313     return getFontSpec(fontdata.getName(), fontdata.getHeight(), fontdata.getStyle());
314   }
315 
316   ////////////////////////////////////////////////////////////////////////
317 
318   public static void main(String[] args) {
319     Display display = new Display();
320     Shell shell = new Shell(display);
321     shell.setText(NAME);
322     shell.addDisposeListener(FontFactory.getDefault());
323     shell.addDisposeListener(ColorFactory.getDefault());
324     //NOTE: Must have this to show the correct sized content.
325     shell.setLayout(new FillLayout());
326     ScrolledComposite scrolled = new ScrolledComposite(shell, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
327     //scrolled.setExpandHorizontal(true);
328     //scrolled.setExpandVertical(true);
329     Composite top = new Composite(scrolled, SWT.NONE);
330     scrolled.setContent(top);
331     //    Composite top = new Composite(shell, SWT.V_SCROLL | SWT.H_SCROLL);
332     // Set up the image canvas scroll bars.
333     //    ScrollBar horizontal = top.getHorizontalBar();
334     //    horizontal.setVisible(true);
335     //    horizontal.setMinimum(0);
336     //    horizontal.setEnabled(false);
337     //    ScrollBar vertical = top.getVerticalBar();
338     //    vertical.setVisible(true);
339     //    vertical.setMinimum(0);
340     //    vertical.setEnabled(false);
341     top.setLayout(new RowLayout(SWT.VERTICAL));
342     //
343     Label label;
344     Font font;
345     //
346     // User selected fonts
347     //
348     System.err.println("\n###\n### Specified fonts:\n###\n");
349     Color bg = ColorFactory.getDefault().create("lightyellow");
350     for (int i = 0; i < args.length; ++i) {
351       label = new Label(top, SWT.NONE);
352       System.err.println("Spec " + i + "=" + args[i]);
353       font = FontFactory.getDefault().create(args[i]);
354       label.setFont(font);
355       label.setBackground(bg);
356       label.setText("Font " + i + ": " + args[i] + ": abcdefgABCDEFG1234567");
357       //
358       label = new Label(top, SWT.NONE);
359       System.err.println("Derive " + i + "=" + args[i] + " size=14");
360       font = FontFactory.getDefault().deriveFont(font, 14);
361       label.setFont(font);
362       label.setBackground(bg);
363       label.setText("Font " + i + ": " + getFontSpec(font) + ": abcdefgABCDEFG1234567");
364     }
365     //
366     // All fonts.
367     //
368     System.err.println("\n###\n### All fonts:\n###\n");
369     FontData[] fonts;
370     FontData fontdata;
371     String fontname;
372     fonts = fDisplay.getFontList(null, true);
373     bg = ColorFactory.getDefault().create("yellow");
374     if (fonts != null) {
375       Set visited = new HashSet();
376       for (int i = 0; i < fonts.length; ++i) {
377         fontdata = fonts[i];
378         fontname = fontdata.getName();
379         if (visited.contains(fontname))
380           continue;
381         visited.add(fontname);
382         font =
383           FontFactory.getDefault().create(
384             fontname,
385             fontdata.getHeight(),
386             fontdata.getStyle());
387         label = new Label(top, SWT.NONE);
388         label.setBackground(bg);
389         label.setFont(font);
390         fontname = getFontSpec(fontname, fontdata.getHeight(), fontdata.getStyle());
391         label.setText(
392           "Font "
393             + i
394             + "="
395             + fontname
396             + ": abcdefgABCDEFG1234567"
397             + ": "
398             + fontdata.toString());
399       }
400     }
401     //NOTE: Must have this to show the ScrolledComposite and its scrollbars correctly.
402     top.setSize(top.computeSize(SWT.DEFAULT, SWT.DEFAULT));
403     shell.pack();
404     shell.open();
405     while (!shell.isDisposed())
406       if (!display.readAndDispatch())
407         display.sleep();
408     display.dispose();
409   }
410   ////////////////////////////////////////////////////////////////////////
411 }