KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > util > ResourceBundleSupport


1 /* ========================================================================
2  * JCommon : a free general purpose class library for the Java(tm) platform
3  * ========================================================================
4  *
5  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
6  *
7  * Project Info: http://www.jfree.org/jcommon/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA.
23  *
24  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
25  * in the United States and other countries.]
26  *
27  * ---------------------
28  * ReadOnlyIterator.java
29  * ---------------------
30  * (C)opyright 2003, 2004, by Thomas Morgner and Contributors.
31  *
32  * Original Author: Thomas Morgner;
33  * Contributor(s): -;
34  *
35  * $Id: ResourceBundleSupport.java,v 1.10 2006/12/03 15:33:33 taqua Exp $
36  *
37  * Changes
38  * -------------------------
39  */

40 package org.jfree.util;
41
42 import java.awt.Image JavaDoc;
43 import java.awt.Toolkit JavaDoc;
44 import java.awt.event.InputEvent JavaDoc;
45 import java.awt.event.KeyEvent JavaDoc;
46 import java.awt.image.BufferedImage JavaDoc;
47 import java.lang.reflect.Field JavaDoc;
48 import java.net.URL JavaDoc;
49 import java.text.MessageFormat JavaDoc;
50 import java.util.Arrays JavaDoc;
51 import java.util.Locale JavaDoc;
52 import java.util.MissingResourceException JavaDoc;
53 import java.util.ResourceBundle JavaDoc;
54 import java.util.TreeMap JavaDoc;
55 import java.util.TreeSet JavaDoc;
56 import javax.swing.Icon JavaDoc;
57 import javax.swing.ImageIcon JavaDoc;
58 import javax.swing.JMenu JavaDoc;
59 import javax.swing.KeyStroke JavaDoc;
60
61 /**
62  * An utility class to ease up using property-file resource bundles.
63  * <p/>
64  * The class support references within the resource bundle set to minimize the
65  * occurence of duplicate keys. References are given in the format:
66  * <pre>
67  * a.key.name=@referenced.key
68  * </pre>
69  * <p/>
70  * A lookup to a key in an other resource bundle should be written by
71  * <pre>
72  * a.key.name=@@resourcebundle_name@referenced.key
73  * </pre>
74  *
75  * @author Thomas Morgner
76  */

77 public class ResourceBundleSupport
78 {
79   /**
80    * The resource bundle that will be used for local lookups.
81    */

82   private ResourceBundle JavaDoc resources;
83
84   /**
85    * A cache for string values, as looking up the cache is faster than looking
86    * up the value in the bundle.
87    */

88   private TreeMap JavaDoc cache;
89   /**
90    * The current lookup path when performing non local lookups. This prevents
91    * infinite loops during such lookups.
92    */

93   private TreeSet JavaDoc lookupPath;
94
95   /**
96    * The name of the local resource bundle.
97    */

98   private String JavaDoc resourceBase;
99
100   /**
101    * The locale for this bundle.
102    */

103   private Locale JavaDoc locale;
104
105   /**
106    * Creates a new instance.
107    *
108    * @param baseName the base name of the resource bundle, a fully qualified
109    * class name
110    */

111   public ResourceBundleSupport(final Locale JavaDoc locale, final String JavaDoc baseName)
112   {
113     this(locale, ResourceBundle.getBundle(baseName, locale), baseName);
114   }
115
116   /**
117    * Creates a new instance.
118    *
119    * @param locale the locale for which this resource bundle is
120    * created.
121    * @param resourceBundle the resourcebundle
122    * @param baseName the base name of the resource bundle, a fully
123    * qualified class name
124    */

125   protected ResourceBundleSupport(final Locale JavaDoc locale,
126                                   final ResourceBundle JavaDoc resourceBundle,
127                                   final String JavaDoc baseName)
128   {
129     if (locale == null)
130     {
131       throw new NullPointerException JavaDoc("Locale must not be null");
132     }
133     if (resourceBundle == null)
134     {
135       throw new NullPointerException JavaDoc("Resources must not be null");
136     }
137     if (baseName == null)
138     {
139       throw new NullPointerException JavaDoc("BaseName must not be null");
140     }
141     this.locale = locale;
142     this.resources = resourceBundle;
143     this.resourceBase = baseName;
144     this.cache = new TreeMap JavaDoc();
145     this.lookupPath = new TreeSet JavaDoc();
146   }
147
148   /**
149    * Creates a new instance.
150    *
151    * @param locale the locale for which the resource bundle is
152    * created.
153    * @param resourceBundle the resourcebundle
154    */

155   public ResourceBundleSupport(final Locale JavaDoc locale,
156                                final ResourceBundle JavaDoc resourceBundle)
157   {
158     this(locale, resourceBundle, resourceBundle.toString());
159   }
160
161   /**
162    * Creates a new instance.
163    *
164    * @param baseName the base name of the resource bundle, a fully qualified
165    * class name
166    */

167   public ResourceBundleSupport(final String JavaDoc baseName)
168   {
169     this(Locale.getDefault(), ResourceBundle.getBundle(baseName), baseName);
170   }
171
172   /**
173    * Creates a new instance.
174    *
175    * @param resourceBundle the resourcebundle
176    * @param baseName the base name of the resource bundle, a fully
177    * qualified class name
178    */

179   protected ResourceBundleSupport(final ResourceBundle JavaDoc resourceBundle,
180                                   final String JavaDoc baseName)
181   {
182     this(Locale.getDefault(), resourceBundle, baseName);
183   }
184
185   /**
186    * Creates a new instance.
187    *
188    * @param resourceBundle the resourcebundle
189    */

190   public ResourceBundleSupport(final ResourceBundle JavaDoc resourceBundle)
191   {
192     this(Locale.getDefault(), resourceBundle, resourceBundle.toString());
193   }
194
195   /**
196    * The base name of the resource bundle.
197    *
198    * @return the resource bundle's name.
199    */

200   protected final String JavaDoc getResourceBase()
201   {
202     return this.resourceBase;
203   }
204
205   /**
206    * Gets a string for the given key from this resource bundle or one of its
207    * parents. If the key is a link, the link is resolved and the referenced
208    * string is returned instead.
209    *
210    * @param key the key for the desired string
211    * @return the string for the given key
212    * @throws NullPointerException if <code>key</code> is <code>null</code>
213    * @throws MissingResourceException if no object for the given key can be
214    * found
215    * @throws ClassCastException if the object found for the given key is
216    * not a string
217    */

218   public synchronized String JavaDoc getString(final String JavaDoc key)
219   {
220     final String JavaDoc retval = (String JavaDoc) this.cache.get(key);
221     if (retval != null)
222     {
223       return retval;
224     }
225     this.lookupPath.clear();
226     return internalGetString(key);
227   }
228
229   /**
230    * Performs the lookup for the given key. If the key points to a link the
231    * link is resolved and that key is looked up instead.
232    *
233    * @param key the key for the string
234    * @return the string for the given key
235    */

236   protected String JavaDoc internalGetString(final String JavaDoc key)
237   {
238     if (this.lookupPath.contains(key))
239     {
240       throw new MissingResourceException JavaDoc
241           ("InfiniteLoop in resource lookup",
242               getResourceBase(), this.lookupPath.toString());
243     }
244     final String JavaDoc fromResBundle = this.resources.getString(key);
245     if (fromResBundle.startsWith("@@"))
246     {
247       // global forward ...
248
final int idx = fromResBundle.indexOf('@', 2);
249       if (idx == -1)
250       {
251         throw new MissingResourceException JavaDoc
252             ("Invalid format for global lookup key.", getResourceBase(), key);
253       }
254       try
255       {
256         final ResourceBundle JavaDoc res = ResourceBundle.getBundle
257             (fromResBundle.substring(2, idx));
258         return res.getString(fromResBundle.substring(idx + 1));
259       }
260       catch (Exception JavaDoc e)
261       {
262         Log.error("Error during global lookup", e);
263         throw new MissingResourceException JavaDoc
264             ("Error during global lookup", getResourceBase(), key);
265       }
266     }
267     else if (fromResBundle.startsWith("@"))
268     {
269       // local forward ...
270
final String JavaDoc newKey = fromResBundle.substring(1);
271       this.lookupPath.add(key);
272       final String JavaDoc retval = internalGetString(newKey);
273
274       this.cache.put(key, retval);
275       return retval;
276     }
277     else
278     {
279       this.cache.put(key, fromResBundle);
280       return fromResBundle;
281     }
282   }
283
284   /**
285    * Returns an scaled icon suitable for buttons or menus.
286    *
287    * @param key the name of the resource bundle key
288    * @param large true, if the image should be scaled to 24x24, or false for
289    * 16x16
290    * @return the icon.
291    */

292   public Icon JavaDoc getIcon(final String JavaDoc key, final boolean large)
293   {
294     final String JavaDoc name = getString(key);
295     return createIcon(name, true, large);
296   }
297
298   /**
299    * Returns an unscaled icon.
300    *
301    * @param key the name of the resource bundle key
302    * @return the icon.
303    */

304   public Icon JavaDoc getIcon(final String JavaDoc key)
305   {
306     final String JavaDoc name = getString(key);
307     return createIcon(name, false, false);
308   }
309
310   /**
311    * Returns the mnemonic stored at the given resourcebundle key. The mnemonic
312    * should be either the symbolic name of one of the KeyEvent.VK_* constants
313    * (without the 'VK_') or the character for that key.
314    * <p/>
315    * For the enter key, the resource bundle would therefore either contain
316    * "ENTER" or "\n".
317    * <pre>
318    * a.resourcebundle.key=ENTER
319    * an.other.resourcebundle.key=\n
320    * </pre>
321    *
322    * @param key the resourcebundle key
323    * @return the mnemonic
324    */

325   public Integer JavaDoc getMnemonic(final String JavaDoc key)
326   {
327     final String JavaDoc name = getString(key);
328     return createMnemonic(name);
329   }
330
331
332   public Integer JavaDoc getOptionalMnemonic(final String JavaDoc key)
333   {
334     final String JavaDoc name = getString(key);
335     if (name != null && name.length() > 0)
336     {
337       return createMnemonic(name);
338     }
339     return null;
340   }
341
342   /**
343    * Returns the keystroke stored at the given resourcebundle key.
344    * <p/>
345    * The keystroke will be composed of a simple key press and the plattform's
346    * MenuKeyMask.
347    * <p/>
348    * The keystrokes character key should be either the symbolic name of one of
349    * the KeyEvent.VK_* constants or the character for that key.
350    * <p/>
351    * For the 'A' key, the resource bundle would therefore either contain
352    * "VK_A" or "a".
353    * <pre>
354    * a.resourcebundle.key=VK_A
355    * an.other.resourcebundle.key=a
356    * </pre>
357    *
358    * @param key the resourcebundle key
359    * @return the mnemonic
360    * @see Toolkit#getMenuShortcutKeyMask()
361    */

362   public KeyStroke JavaDoc getKeyStroke(final String JavaDoc key)
363   {
364     return getKeyStroke(key, getMenuKeyMask());
365   }
366
367   public KeyStroke JavaDoc getOptionalKeyStroke(final String JavaDoc key)
368   {
369     return getOptionalKeyStroke(key, getMenuKeyMask());
370   }
371
372   /**
373    * Returns the keystroke stored at the given resourcebundle key.
374    * <p/>
375    * The keystroke will be composed of a simple key press and the given
376    * KeyMask. If the KeyMask is zero, a plain Keystroke is returned.
377    * <p/>
378    * The keystrokes character key should be either the symbolic name of one of
379    * the KeyEvent.VK_* constants or the character for that key.
380    * <p/>
381    * For the 'A' key, the resource bundle would therefore either contain
382    * "VK_A" or "a".
383    * <pre>
384    * a.resourcebundle.key=VK_A
385    * an.other.resourcebundle.key=a
386    * </pre>
387    *
388    * @param key the resourcebundle key
389    * @return the mnemonic
390    * @see Toolkit#getMenuShortcutKeyMask()
391    */

392   public KeyStroke JavaDoc getKeyStroke(final String JavaDoc key, final int mask)
393   {
394     final String JavaDoc name = getString(key);
395     return KeyStroke.getKeyStroke(createMnemonic(name).intValue(), mask);
396   }
397
398   public KeyStroke JavaDoc getOptionalKeyStroke(final String JavaDoc key, final int mask)
399   {
400     final String JavaDoc name = getString(key);
401
402     if (name != null && name.length() > 0)
403     {
404       return KeyStroke.getKeyStroke(createMnemonic(name).intValue(), mask);
405     }
406     return null;
407   }
408
409   /**
410    * Returns a JMenu created from a resource bundle definition.
411    * <p/>
412    * The menu definition consists of two keys, the name of the menu and the
413    * mnemonic for that menu. Both keys share a common prefix, which is
414    * extended by ".name" for the name of the menu and ".mnemonic" for the
415    * mnemonic.
416    * <p/>
417    * <pre>
418    * # define the file menu
419    * menu.file.name=File
420    * menu.file.mnemonic=F
421    * </pre>
422    * The menu definition above can be used to create the menu by calling
423    * <code>createMenu ("menu.file")</code>.
424    *
425    * @param keyPrefix the common prefix for that menu
426    * @return the created menu
427    */

428   public JMenu JavaDoc createMenu(final String JavaDoc keyPrefix)
429   {
430     final JMenu JavaDoc retval = new JMenu JavaDoc();
431     retval.setText(getString(keyPrefix + ".name"));
432     retval.setMnemonic(getMnemonic(keyPrefix + ".mnemonic").intValue());
433     return retval;
434   }
435
436   /**
437    * Returns a URL pointing to a resource located in the classpath. The
438    * resource is looked up using the given key.
439    * <p/>
440    * Example: The load a file named 'logo.gif' which is stored in a java
441    * package named 'org.jfree.resources':
442    * <pre>
443    * mainmenu.logo=org/jfree/resources/logo.gif
444    * </pre>
445    * The URL for that file can be queried with: <code>getResource("mainmenu.logo");</code>.
446    *
447    * @param key the key for the resource
448    * @return the resource URL
449    */

450   public URL JavaDoc getResourceURL(final String JavaDoc key)
451   {
452     final String JavaDoc name = getString(key);
453     final URL JavaDoc in = ObjectUtilities.getResource(name, ResourceBundleSupport.class);
454     if (in == null)
455     {
456       Log.warn("Unable to find file in the class path: " + name + "; key=" + key);
457     }
458     return in;
459   }
460
461
462   /**
463    * Attempts to load an image from classpath. If this fails, an empty image
464    * icon is returned.
465    *
466    * @param resourceName the name of the image. The name should be a global
467    * resource name.
468    * @param scale true, if the image should be scaled, false otherwise
469    * @param large true, if the image should be scaled to 24x24, or
470    * false for 16x16
471    * @return the image icon.
472    */

473   private ImageIcon JavaDoc createIcon(final String JavaDoc resourceName, final boolean scale,
474                                final boolean large)
475   {
476     final URL JavaDoc in = ObjectUtilities.getResource(resourceName, ResourceBundleSupport.class);
477     ;
478     if (in == null)
479     {
480       Log.warn("Unable to find file in the class path: " + resourceName);
481       return new ImageIcon JavaDoc(createTransparentImage(1, 1));
482     }
483     final Image JavaDoc img = Toolkit.getDefaultToolkit().createImage(in);
484     if (img == null)
485     {
486       Log.warn("Unable to instantiate the image: " + resourceName);
487       return new ImageIcon JavaDoc(createTransparentImage(1, 1));
488     }
489     if (scale)
490     {
491       if (large)
492       {
493         return new ImageIcon JavaDoc(img.getScaledInstance(24, 24, Image.SCALE_SMOOTH));
494       }
495       return new ImageIcon JavaDoc(img.getScaledInstance(16, 16, Image.SCALE_SMOOTH));
496     }
497     return new ImageIcon JavaDoc(img);
498   }
499
500   /**
501    * Creates the Mnemonic from the given String. The String consists of the
502    * name of the VK constants of the class KeyEvent without VK_*.
503    *
504    * @param keyString the string
505    * @return the mnemonic as integer
506    */

507   private Integer JavaDoc createMnemonic(final String JavaDoc keyString)
508   {
509     if (keyString == null)
510     {
511       throw new NullPointerException JavaDoc("Key is null.");
512     }
513     if (keyString.length() == 0)
514     {
515       throw new IllegalArgumentException JavaDoc("Key is empty.");
516     }
517     int character = keyString.charAt(0);
518     if (keyString.startsWith("VK_"))
519     {
520       try
521       {
522         final Field JavaDoc f = KeyEvent JavaDoc.class.getField(keyString);
523         final Integer JavaDoc keyCode = (Integer JavaDoc) f.get(null);
524         character = keyCode.intValue();
525       }
526       catch (Exception JavaDoc nsfe)
527       {
528         // ignore the exception ...
529
}
530     }
531     return new Integer JavaDoc(character);
532   }
533
534   /**
535    * Returns the plattforms default menu shortcut keymask.
536    *
537    * @return the default key mask.
538    */

539   private int getMenuKeyMask()
540   {
541     try
542     {
543       return Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
544     }
545     catch (UnsupportedOperationException JavaDoc he)
546     {
547       // headless exception extends UnsupportedOperation exception,
548
// but the HeadlessException is not defined in older JDKs...
549
return InputEvent.CTRL_MASK;
550     }
551   }
552
553   /**
554    * Creates a transparent image. These can be used for aligning menu items.
555    *
556    * @param width the width.
557    * @param height the height.
558    * @return the created transparent image.
559    */

560   private BufferedImage JavaDoc createTransparentImage(final int width,
561                                                final int height)
562   {
563     final BufferedImage JavaDoc img = new BufferedImage JavaDoc(width, height, BufferedImage.TYPE_INT_ARGB);
564     final int[] data = img.getRGB(0, 0, width, height, null, 0, width);
565     Arrays.fill(data, 0x00000000);
566     img.setRGB(0, 0, width, height, data, 0, width);
567     return img;
568   }
569
570   /**
571    * Creates a transparent icon. The Icon can be used for aligning menu
572    * items.
573    *
574    * @param width the width of the new icon
575    * @param height the height of the new icon
576    * @return the created transparent icon.
577    */

578   public Icon JavaDoc createTransparentIcon(final int width, final int height)
579   {
580     return new ImageIcon JavaDoc(createTransparentImage(width, height));
581   }
582
583   /**
584    * Formats the message stored in the resource bundle (using a
585    * MessageFormat).
586    *
587    * @param key the resourcebundle key
588    * @param parameter the parameter for the message
589    * @return the formated string
590    */

591   public String JavaDoc formatMessage(final String JavaDoc key, final Object JavaDoc parameter)
592   {
593     return formatMessage(key, new Object JavaDoc[]{parameter});
594   }
595
596   /**
597    * Formats the message stored in the resource bundle (using a
598    * MessageFormat).
599    *
600    * @param key the resourcebundle key
601    * @param par1 the first parameter for the message
602    * @param par2 the second parameter for the message
603    * @return the formated string
604    */

605   public String JavaDoc formatMessage(final String JavaDoc key,
606                               final Object JavaDoc par1,
607                               final Object JavaDoc par2)
608   {
609     return formatMessage(key, new Object JavaDoc[]{par1, par2});
610   }
611
612   /**
613    * Formats the message stored in the resource bundle (using a
614    * MessageFormat).
615    *
616    * @param key the resourcebundle key
617    * @param parameters the parameter collection for the message
618    * @return the formated string
619    */

620   public String JavaDoc formatMessage(final String JavaDoc key, final Object JavaDoc[] parameters)
621   {
622     final MessageFormat JavaDoc format = new MessageFormat JavaDoc(getString(key));
623     format.setLocale(getLocale());
624     return format.format(parameters);
625   }
626
627   /**
628    * Returns the current locale for this resource bundle.
629    *
630    * @return the locale.
631    */

632   public Locale JavaDoc getLocale()
633   {
634     return locale;
635   }
636 }
637
Popular Tags