org.jfree.util.ResourceBundleSupport Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jcommon Show documentation
Show all versions of jcommon Show documentation
JCommon is a free general purpose Java class library that is used in
several projects at www.jfree.org, including JFreeChart and
JFreeReport.
/* ========================================================================
* JCommon : a free general purpose class library for the Java(tm) platform
* ========================================================================
*
* (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ---------------------
* ReadOnlyIterator.java
* ---------------------
* (C)opyright 2003-2008, by Thomas Morgner and Contributors.
*
* Original Author: Thomas Morgner;
* Contributor(s): David Gilbert (for Object Refinery Limited);
*
* $Id: ResourceBundleSupport.java,v 1.12 2008/12/18 09:57:32 mungady Exp $
*
* Changes
* -------
* 18-Dec-2008 : Use ResourceBundleWrapper - see JFreeChart patch 1607918 by
* Jess Thrysoee (DG);
*
*/
package org.jfree.util;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.lang.reflect.Field;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JMenu;
import javax.swing.KeyStroke;
/**
* An utility class to ease up using property-file resource bundles.
*
* The class support references within the resource bundle set to minimize the
* occurence of duplicate keys. References are given in the format:
*
* [email protected]
*
*
* A lookup to a key in an other resource bundle should be written by
*
* a.key.name=@@[email protected]
*
*
* @author Thomas Morgner
*/
public class ResourceBundleSupport
{
/**
* The resource bundle that will be used for local lookups.
*/
private ResourceBundle resources;
/**
* A cache for string values, as looking up the cache is faster than looking
* up the value in the bundle.
*/
private TreeMap cache;
/**
* The current lookup path when performing non local lookups. This prevents
* infinite loops during such lookups.
*/
private TreeSet lookupPath;
/**
* The name of the local resource bundle.
*/
private String resourceBase;
/**
* The locale for this bundle.
*/
private Locale locale;
/**
* Creates a new instance.
*
* @param locale the locale.
* @param baseName the base name of the resource bundle, a fully qualified
* class name
*/
public ResourceBundleSupport(final Locale locale, final String baseName)
{
this(locale, ResourceBundleWrapper.getBundle(baseName, locale), baseName);
}
/**
* Creates a new instance.
*
* @param locale the locale for which this resource bundle is
* created.
* @param resourceBundle the resourcebundle
* @param baseName the base name of the resource bundle, a fully
* qualified class name
*/
protected ResourceBundleSupport(final Locale locale,
final ResourceBundle resourceBundle,
final String baseName)
{
if (locale == null)
{
throw new NullPointerException("Locale must not be null");
}
if (resourceBundle == null)
{
throw new NullPointerException("Resources must not be null");
}
if (baseName == null)
{
throw new NullPointerException("BaseName must not be null");
}
this.locale = locale;
this.resources = resourceBundle;
this.resourceBase = baseName;
this.cache = new TreeMap();
this.lookupPath = new TreeSet();
}
/**
* Creates a new instance.
*
* @param locale the locale for which the resource bundle is
* created.
* @param resourceBundle the resourcebundle
*/
public ResourceBundleSupport(final Locale locale,
final ResourceBundle resourceBundle)
{
this(locale, resourceBundle, resourceBundle.toString());
}
/**
* Creates a new instance.
*
* @param baseName the base name of the resource bundle, a fully qualified
* class name
*/
public ResourceBundleSupport(final String baseName)
{
this(Locale.getDefault(), ResourceBundleWrapper.getBundle(baseName),
baseName);
}
/**
* Creates a new instance.
*
* @param resourceBundle the resourcebundle
* @param baseName the base name of the resource bundle, a fully
* qualified class name
*/
protected ResourceBundleSupport(final ResourceBundle resourceBundle,
final String baseName)
{
this(Locale.getDefault(), resourceBundle, baseName);
}
/**
* Creates a new instance.
*
* @param resourceBundle the resourcebundle
*/
public ResourceBundleSupport(final ResourceBundle resourceBundle)
{
this(Locale.getDefault(), resourceBundle, resourceBundle.toString());
}
/**
* The base name of the resource bundle.
*
* @return the resource bundle's name.
*/
protected final String getResourceBase()
{
return this.resourceBase;
}
/**
* Gets a string for the given key from this resource bundle or one of its
* parents. If the key is a link, the link is resolved and the referenced
* string is returned instead.
*
* @param key the key for the desired string
* @return the string for the given key
* @throws NullPointerException if key
is null
* @throws MissingResourceException if no object for the given key can be
* found
* @throws ClassCastException if the object found for the given key is
* not a string
*/
public synchronized String getString(final String key)
{
final String retval = (String) this.cache.get(key);
if (retval != null)
{
return retval;
}
this.lookupPath.clear();
return internalGetString(key);
}
/**
* Performs the lookup for the given key. If the key points to a link the
* link is resolved and that key is looked up instead.
*
* @param key the key for the string
* @return the string for the given key
*/
protected String internalGetString(final String key)
{
if (this.lookupPath.contains(key))
{
throw new MissingResourceException
("InfiniteLoop in resource lookup",
getResourceBase(), this.lookupPath.toString());
}
final String fromResBundle = this.resources.getString(key);
if (fromResBundle.startsWith("@@"))
{
// global forward ...
final int idx = fromResBundle.indexOf('@', 2);
if (idx == -1)
{
throw new MissingResourceException
("Invalid format for global lookup key.", getResourceBase(), key);
}
try
{
final ResourceBundle res = ResourceBundleWrapper.getBundle
(fromResBundle.substring(2, idx));
return res.getString(fromResBundle.substring(idx + 1));
}
catch (Exception e)
{
Log.error("Error during global lookup", e);
throw new MissingResourceException
("Error during global lookup", getResourceBase(), key);
}
}
else if (fromResBundle.startsWith("@"))
{
// local forward ...
final String newKey = fromResBundle.substring(1);
this.lookupPath.add(key);
final String retval = internalGetString(newKey);
this.cache.put(key, retval);
return retval;
}
else
{
this.cache.put(key, fromResBundle);
return fromResBundle;
}
}
/**
* Returns an scaled icon suitable for buttons or menus.
*
* @param key the name of the resource bundle key
* @param large true, if the image should be scaled to 24x24, or false for
* 16x16
* @return the icon.
*/
public Icon getIcon(final String key, final boolean large)
{
final String name = getString(key);
return createIcon(name, true, large);
}
/**
* Returns an unscaled icon.
*
* @param key the name of the resource bundle key
* @return the icon.
*/
public Icon getIcon(final String key)
{
final String name = getString(key);
return createIcon(name, false, false);
}
/**
* Returns the mnemonic stored at the given resourcebundle key. The mnemonic
* should be either the symbolic name of one of the KeyEvent.VK_* constants
* (without the 'VK_') or the character for that key.
*
* For the enter key, the resource bundle would therefore either contain
* "ENTER" or "\n".
*
* a.resourcebundle.key=ENTER
* an.other.resourcebundle.key=\n
*
*
* @param key the resourcebundle key
* @return the mnemonic
*/
public Integer getMnemonic(final String key)
{
final String name = getString(key);
return createMnemonic(name);
}
/**
* Returns an optional mnemonic.
*
* @param key the key.
*
* @return The mnemonic.
*/
public Integer getOptionalMnemonic(final String key)
{
final String name = getString(key);
if (name != null && name.length() > 0)
{
return createMnemonic(name);
}
return null;
}
/**
* Returns the keystroke stored at the given resourcebundle key.
*
* The keystroke will be composed of a simple key press and the plattform's
* MenuKeyMask.
*
* The keystrokes character key should be either the symbolic name of one of
* the KeyEvent.VK_* constants or the character for that key.
*
* For the 'A' key, the resource bundle would therefore either contain
* "VK_A" or "a".
*
* a.resourcebundle.key=VK_A
* an.other.resourcebundle.key=a
*
*
* @param key the resourcebundle key
* @return the mnemonic
* @see Toolkit#getMenuShortcutKeyMask()
*/
public KeyStroke getKeyStroke(final String key)
{
return getKeyStroke(key, getMenuKeyMask());
}
/**
* Returns an optional key stroke.
*
* @param key the key.
*
* @return The key stroke.
*/
public KeyStroke getOptionalKeyStroke(final String key)
{
return getOptionalKeyStroke(key, getMenuKeyMask());
}
/**
* Returns the keystroke stored at the given resourcebundle key.
*
* The keystroke will be composed of a simple key press and the given
* KeyMask. If the KeyMask is zero, a plain Keystroke is returned.
*
* The keystrokes character key should be either the symbolic name of one of
* the KeyEvent.VK_* constants or the character for that key.
*
* For the 'A' key, the resource bundle would therefore either contain
* "VK_A" or "a".
*
* a.resourcebundle.key=VK_A
* an.other.resourcebundle.key=a
*
*
* @param key the resourcebundle key.
* @param mask the mask.
*
* @return the mnemonic
* @see Toolkit#getMenuShortcutKeyMask()
*/
public KeyStroke getKeyStroke(final String key, final int mask)
{
final String name = getString(key);
return KeyStroke.getKeyStroke(createMnemonic(name).intValue(), mask);
}
/**
* Returns an optional key stroke.
*
* @param key the key.
* @param mask the mask.
*
* @return The key stroke.
*/
public KeyStroke getOptionalKeyStroke(final String key, final int mask)
{
final String name = getString(key);
if (name != null && name.length() > 0)
{
return KeyStroke.getKeyStroke(createMnemonic(name).intValue(), mask);
}
return null;
}
/**
* Returns a JMenu created from a resource bundle definition.
*
* The menu definition consists of two keys, the name of the menu and the
* mnemonic for that menu. Both keys share a common prefix, which is
* extended by ".name" for the name of the menu and ".mnemonic" for the
* mnemonic.
*
*
* # define the file menu
* menu.file.name=File
* menu.file.mnemonic=F
*
* The menu definition above can be used to create the menu by calling
* createMenu ("menu.file")
.
*
* @param keyPrefix the common prefix for that menu
* @return the created menu
*/
public JMenu createMenu(final String keyPrefix)
{
final JMenu retval = new JMenu();
retval.setText(getString(keyPrefix + ".name"));
retval.setMnemonic(getMnemonic(keyPrefix + ".mnemonic").intValue());
return retval;
}
/**
* Returns a URL pointing to a resource located in the classpath. The
* resource is looked up using the given key.
*
* Example: The load a file named 'logo.gif' which is stored in a java
* package named 'org.jfree.resources':
*
* mainmenu.logo=org/jfree/resources/logo.gif
*
* The URL for that file can be queried with: getResource("mainmenu.logo");
.
*
* @param key the key for the resource
* @return the resource URL
*/
public URL getResourceURL(final String key)
{
final String name = getString(key);
final URL in = ObjectUtilities.getResource(name, ResourceBundleSupport.class);
if (in == null)
{
Log.warn("Unable to find file in the class path: " + name + "; key=" + key);
}
return in;
}
/**
* Attempts to load an image from classpath. If this fails, an empty image
* icon is returned.
*
* @param resourceName the name of the image. The name should be a global
* resource name.
* @param scale true, if the image should be scaled, false otherwise
* @param large true, if the image should be scaled to 24x24, or
* false for 16x16
* @return the image icon.
*/
private ImageIcon createIcon(final String resourceName, final boolean scale,
final boolean large)
{
final URL in = ObjectUtilities.getResource(resourceName, ResourceBundleSupport.class);
;
if (in == null)
{
Log.warn("Unable to find file in the class path: " + resourceName);
return new ImageIcon(createTransparentImage(1, 1));
}
final Image img = Toolkit.getDefaultToolkit().createImage(in);
if (img == null)
{
Log.warn("Unable to instantiate the image: " + resourceName);
return new ImageIcon(createTransparentImage(1, 1));
}
if (scale)
{
if (large)
{
return new ImageIcon(img.getScaledInstance(24, 24, Image.SCALE_SMOOTH));
}
return new ImageIcon(img.getScaledInstance(16, 16, Image.SCALE_SMOOTH));
}
return new ImageIcon(img);
}
/**
* Creates the Mnemonic from the given String. The String consists of the
* name of the VK constants of the class KeyEvent without VK_*.
*
* @param keyString the string
* @return the mnemonic as integer
*/
private Integer createMnemonic(final String keyString)
{
if (keyString == null)
{
throw new NullPointerException("Key is null.");
}
if (keyString.length() == 0)
{
throw new IllegalArgumentException("Key is empty.");
}
int character = keyString.charAt(0);
if (keyString.startsWith("VK_"))
{
try
{
final Field f = KeyEvent.class.getField(keyString);
final Integer keyCode = (Integer) f.get(null);
character = keyCode.intValue();
}
catch (Exception nsfe)
{
// ignore the exception ...
}
}
return new Integer(character);
}
/**
* Returns the plattforms default menu shortcut keymask.
*
* @return the default key mask.
*/
private int getMenuKeyMask()
{
try
{
return Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
}
catch (UnsupportedOperationException he)
{
// headless exception extends UnsupportedOperation exception,
// but the HeadlessException is not defined in older JDKs...
return InputEvent.CTRL_MASK;
}
}
/**
* Creates a transparent image. These can be used for aligning menu items.
*
* @param width the width.
* @param height the height.
* @return the created transparent image.
*/
private BufferedImage createTransparentImage(final int width,
final int height)
{
final BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
final int[] data = img.getRGB(0, 0, width, height, null, 0, width);
Arrays.fill(data, 0x00000000);
img.setRGB(0, 0, width, height, data, 0, width);
return img;
}
/**
* Creates a transparent icon. The Icon can be used for aligning menu
* items.
*
* @param width the width of the new icon
* @param height the height of the new icon
* @return the created transparent icon.
*/
public Icon createTransparentIcon(final int width, final int height)
{
return new ImageIcon(createTransparentImage(width, height));
}
/**
* Formats the message stored in the resource bundle (using a
* MessageFormat).
*
* @param key the resourcebundle key
* @param parameter the parameter for the message
* @return the formated string
*/
public String formatMessage(final String key, final Object parameter)
{
return formatMessage(key, new Object[]{parameter});
}
/**
* Formats the message stored in the resource bundle (using a
* MessageFormat).
*
* @param key the resourcebundle key
* @param par1 the first parameter for the message
* @param par2 the second parameter for the message
* @return the formated string
*/
public String formatMessage(final String key,
final Object par1,
final Object par2)
{
return formatMessage(key, new Object[]{par1, par2});
}
/**
* Formats the message stored in the resource bundle (using a
* MessageFormat).
*
* @param key the resourcebundle key
* @param parameters the parameter collection for the message
* @return the formated string
*/
public String formatMessage(final String key, final Object[] parameters)
{
final MessageFormat format = new MessageFormat(getString(key));
format.setLocale(getLocale());
return format.format(parameters);
}
/**
* Returns the current locale for this resource bundle.
*
* @return the locale.
*/
public Locale getLocale()
{
return this.locale;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy