FileDocCategorySizeDatePackage
GUIResourceBundle.javaAPI DocExample9503Sat Jan 24 10:44:34 GMT 2004je3.gui

GUIResourceBundle.java

/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit http://www.davidflanagan.com/javaexamples3.
 */
package je3.gui;
import java.io.*;
import java.util.*;
import java.awt.*;

/**
 * This class extends ResourceBundle and adds methods to retrieve types of
 * resources commonly used in GUIs.  Additionally, it adds extensibility
 * by allowing ResourceParser objects to be registered to parse other
 * resource types.
 **/
public class GUIResourceBundle extends ResourceBundle {
    // The root object.  Required to parse certain resource types like Commands
    Object root;           

    // The resource bundle that actually contains the textual resources
    // This class is a wrapper around this bundle
    ResourceBundle bundle;

    /** Create a GUIResourceBundle wrapper around a specified bundle */
    public GUIResourceBundle(Object root, ResourceBundle bundle) {
	this.root = root;
	this.bundle = bundle;
    }

    /**
     * Load a named bundle and create a GUIResourceBundle around it.  This 
     * constructor takes advantage of the internationalization features of
     * the ResourceBundle.getBundle() method.
     **/
    public GUIResourceBundle(Object root, String bundleName)
	throws MissingResourceException
    {
	this.root = root;
	this.bundle = ResourceBundle.getBundle(bundleName);
    }

    /**
     * Create a PropertyResourceBundle from the specified stream and then
     * create a GUIResourceBundle wrapper for it
     **/
    public GUIResourceBundle(Object root, InputStream propertiesStream)
        throws IOException
    {
	this.root = root;
	this.bundle = new PropertyResourceBundle(propertiesStream);
    }

    /**
     * Create a PropertyResourceBundle from the specified properties file and
     * then create a GUIResourceBundle wrapper for it.
     **/
    public GUIResourceBundle(Object root, File propertiesFile) 
        throws IOException
    {
	this(root, new FileInputStream(propertiesFile));
    }

    /** This is one of the abstract methods of ResourceBundle */
    public Enumeration getKeys() { return bundle.getKeys(); }

    /** This is the other abstract method of ResourceBundle */
    protected Object handleGetObject(String key)
	throws MissingResourceException
    {
	return bundle.getObject(key);  // simply defer to the wrapped bundle
    }
    
    /** This is a property accessor method for our root object */
    public Object getRoot() { return root; }

    /** 
     * This method is like the inherited getString() method, except that 
     * when the named resource is not found, it returns the specified default 
     * instead of throwing an exception 
     **/
    public String getString(String key, String defaultValue) {
	try { return bundle.getString(key); }
	catch(MissingResourceException e) { return defaultValue; }
    }

    /**
     * Look up the named resource and parse it as a list of strings separated
     * by spaces, tabs, or commas.
     **/
    public java.util.List getStringList(String key)
	throws MissingResourceException
    {
	String s = getString(key);
	StringTokenizer t = new StringTokenizer(s, ", \t", false);
	ArrayList list = new ArrayList();
	while(t.hasMoreTokens()) list.add(t.nextToken());
	return list;
    }

    /** Like above, but return a default instead of throwing an exception */
    public java.util.List getStringList(String key,
					java.util.List defaultValue) {
	try { return getStringList(key); }
	catch(MissingResourceException e) { return defaultValue; }
    }

    /** Look up the named resource and try to interpret it as a boolean. */
    public boolean getBoolean(String key) throws MissingResourceException {
	String s = bundle.getString(key);
	s = s.toLowerCase();
	if (s.equals("true")) return true;
	else if (s.equals("false")) return false;
	else if (s.equals("yes")) return true;
	else if (s.equals("no")) return false;
	else if (s.equals("on")) return true;
	else if (s.equals("off")) return false;
	else {
	    throw new MalformedResourceException("boolean", key);
	}
    }

    /** As above, but return the default instead of throwing an exception */
    public boolean getBoolean(String key, boolean defaultValue) {
	try { return getBoolean(key); }
	catch(MissingResourceException e) {
	    if (e instanceof MalformedResourceException)
		System.err.println("WARNING: " + e.getMessage());
	    return defaultValue;
	}
    }

    /** Like getBoolean(), but for integers */
    public int getInt(String key) throws MissingResourceException {
	String s = bundle.getString(key);
	
	try {
	    // Use decode() instead of parseInt() so we support octal
	    // and hexadecimal numbers
	    return Integer.decode(s).intValue();
	} catch (NumberFormatException e) {
	    throw new MalformedResourceException("int", key);
	}
    }

    /** As above, but with a default value */
    public int getInt(String key, int defaultValue) {
	try { return getInt(key); }
	catch(MissingResourceException e) {
	    if (e instanceof MalformedResourceException)
		System.err.println("WARNING: " + e.getMessage());
	    return defaultValue;
	}
    }

    /** Return a resource of type double */
    public double getDouble(String key) throws MissingResourceException {
	String s = bundle.getString(key);
	
	try {
	    return Double.parseDouble(s);
	} catch (NumberFormatException e) {
	    throw new MalformedResourceException("double", key);
	}
    }

    /** As above, but with a default value */
    public double getDouble(String key, double defaultValue) {
	try { return getDouble(key); }
	catch(MissingResourceException e) {
	    if (e instanceof MalformedResourceException)
		System.err.println("WARNING: " + e.getMessage());
	    return defaultValue;
	}
    }

    /** Look up the named resource and convert to a Font */
    public Font getFont(String key) throws MissingResourceException {
	// Font.decode() always returns a Font object, so we can't check
	// whether the resource value was well-formed or not.
	return Font.decode(bundle.getString(key));
    }

    /** As above, but with a default value */
    public Font getFont(String key, Font defaultValue) {
	try { return getFont(key); }
	catch (MissingResourceException e) { return defaultValue; }
    }

    /** Look up the named resource, and convert to a Color */
    public Color getColor(String key) throws MissingResourceException {
	try {
	    return Color.decode(bundle.getString(key));
	}
	catch (NumberFormatException e) { 
	    // It would be useful to try to parse color names here as well
	    // as numeric color specifications
	    throw new MalformedResourceException("Color", key);
	}
    }

    /** As above, but with a default value */
    public Color getColor(String key, Color defaultValue) {
	try { return getColor(key); }
	catch(MissingResourceException e) {
	    if (e instanceof MalformedResourceException)
		System.err.println("WARNING: " + e.getMessage());
	    return defaultValue;
	}
    }

    /** A hashtable for mapping resource types to resource parsers */
    static HashMap parsers = new HashMap();

    /** An extension mechanism: register a parser for new resource types */
    public static void registerResourceParser(ResourceParser parser) {
	// Ask the ResourceParser what types it can parse
	Class[] supportedTypes = parser.getResourceTypes();
	// Register it in the hashtable for each of those types
	for(int i = 0; i < supportedTypes.length; i++)
	    parsers.put(supportedTypes[i], parser);
    }

    /** Look up a ResourceParser for the specified resource type */
    public static ResourceParser getResourceParser(Class type) {
	return (ResourceParser) parsers.get(type);
    }

    /**
     * Look for a ResourceParser for the named type, and if one is found, 
     * ask it to parse and return the named resource 
     **/
    public Object getResource(String key, Class type)
	throws MissingResourceException
    {
	// Get a parser for the specified type
	ResourceParser parser = (ResourceParser)parsers.get(type);
	if (parser == null) 
	    throw new MissingResourceException(
                  "No ResourceParser registered for " +
		  type.getName() + " resources",
		  type.getName(), key);
	
	try {  // Ask the parser to parse the resource
	    return parser.parse(this, key, type);
	}
	catch(MissingResourceException e) {
	    throw e;  // Rethrow MissingResourceException exceptions
	}
	catch(Exception e) {
	    // If any other type of exception occurs, convert it to
	    // a MalformedResourceException
	    String msg = "Malformed " + type.getName() + " resource: " +
		key + ": " + e.getMessage();
	    throw new MalformedResourceException(msg, type.getName(), key);
	}
    }

    /**
     * Like the 2-argument version of getResource, but return a default value
     * instead of throwing a MissingResourceException
     **/
    public Object getResource(String key, Class type, Object defaultValue) {
	try {  return getResource(key, type); }
	catch (MissingResourceException e) {
	    if (e instanceof MalformedResourceException)
		System.err.println("WARNING: " + e.getMessage());
	    return defaultValue;
	}
    }
}