Added a flexible mechanism for persistent boolean-, integer-, and
string-valued preferences built atop java.util.Properties.
How it works: the jvm is asked first, and then the user's prefs file, if it exists,
then the system-wide prefs file, and then the built-in preferences. Finally, for
robustness, a default may be optionally hard-coded in the source.
I made several things configurable, too:
the default Tibetan keyboard
the default font sizes and faces
whether you want developer-only features enabled
Savant's file extension (.savant)
etc.
The only known problems are the following:
The default location for the user's preferences file is windows-specific,
arbitrary, and not in the user documentation. Likewise for the location of the
system-wide preferences file. You can change them using 'java -D', though.
There is no "Save preferences" option yet, and closing the program does
not save preferences either.
2002-10-14 04:06:05 +00:00
|
|
|
/*
|
|
|
|
The contents of this file are subject to the THDL Open Community License
|
|
|
|
Version 1.0 (the "License"); you may not use this file except in compliance
|
|
|
|
with the License. You may obtain a copy of the License on the THDL web site
|
|
|
|
(http://www.thdl.org/).
|
|
|
|
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
|
|
|
License for the specific terms governing rights and limitations under the
|
|
|
|
License.
|
|
|
|
|
|
|
|
The Initial Developer of this software is the Tibetan and Himalayan Digital
|
|
|
|
Library (THDL). Portions created by the THDL are Copyright 2001 THDL.
|
|
|
|
All Rights Reserved.
|
|
|
|
|
|
|
|
Contributor(s): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package org.thdl.util;
|
|
|
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
import java.util.Properties;
|
|
|
|
|
|
|
|
import org.thdl.util.ThdlLazyException;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Provides a clean interface to the multi-tiered system of user
|
|
|
|
* preferences (also known as options).
|
|
|
|
*
|
|
|
|
* <p>The {@link java.util.Properties java.util.Properties} class
|
|
|
|
* makes it easy for us to provide a hierarchical preferences (that
|
|
|
|
* is, options) structure. One option a user might wish to set is the
|
|
|
|
* font size for Tibetan, for example. The highest precedence goes to
|
|
|
|
* a pref that the user set on the Java command line using something
|
|
|
|
* like <code>java -Dpref=value -jar jskad_or_whatever.jar</code>. If
|
|
|
|
* the user went to the trouble of doing this, we definitely want to
|
|
|
|
* respect his or her wish. The next highest precedence goes to an
|
|
|
|
* individual user's preferences file (a file readable and writable by
|
|
|
|
* {@link java.util.Properties java.util.Properties}, but also
|
|
|
|
* hand-editable), if one exists. Next is the system-wide preferences
|
|
|
|
* file, if one exists. Finally, we fall back on the preferences file
|
|
|
|
* shipped with the application inside the JAR.</p>
|
|
|
|
*
|
|
|
|
* <p>ThdlOptions is not instantiable. It contains only static
|
|
|
|
* methods for answering questions about the user's preferences.</p>
|
|
|
|
*
|
|
|
|
* <p>There are three kinds of preferences: boolean-valued preferences
|
|
|
|
* ("true" or "false"), integer-valued preferences, and string-valued
|
|
|
|
* preferences. Boolean-valued preferences should, by convention, be
|
|
|
|
* false by default. If you want to enable feature foo by default,
|
|
|
|
* but give a preference for disabling it, then call the preference
|
|
|
|
* "DisableFeatureFoo". If you want to disable feature foo by
|
|
|
|
* default, call it "EnableFeatureFoo". This makes the users' lives
|
|
|
|
* easier.</p>
|
|
|
|
*
|
|
|
|
* <p>ThdlOptions is a final class so that compilers can make this
|
2002-10-14 05:23:58 +00:00
|
|
|
* code run efficiently.</p>
|
|
|
|
*
|
|
|
|
* @author David Chandler
|
|
|
|
*/
|
Added a flexible mechanism for persistent boolean-, integer-, and
string-valued preferences built atop java.util.Properties.
How it works: the jvm is asked first, and then the user's prefs file, if it exists,
then the system-wide prefs file, and then the built-in preferences. Finally, for
robustness, a default may be optionally hard-coded in the source.
I made several things configurable, too:
the default Tibetan keyboard
the default font sizes and faces
whether you want developer-only features enabled
Savant's file extension (.savant)
etc.
The only known problems are the following:
The default location for the user's preferences file is windows-specific,
arbitrary, and not in the user documentation. Likewise for the location of the
system-wide preferences file. You can change them using 'java -D', though.
There is no "Save preferences" option yet, and closing the program does
not save preferences either.
2002-10-14 04:06:05 +00:00
|
|
|
public final class ThdlOptions {
|
|
|
|
/**
|
|
|
|
* So that you're not tempted to instantiate this class, the
|
|
|
|
* constructor is private: */
|
|
|
|
private ThdlOptions() {
|
|
|
|
// don't instantiate this class.
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the value of a boolean-valued option, or false if that
|
|
|
|
* option is set nowhere in the hierarchy of properties files.
|
|
|
|
*
|
|
|
|
* @param optionName the option whose value you wish to retrieve
|
|
|
|
* (note the naming conventions detailed in the class comment)
|
|
|
|
*/
|
|
|
|
public static boolean getBooleanOption(String optionName)
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
|
|
|
|
// Look to the System first.
|
|
|
|
String answer = getSystemValue(optionName);
|
|
|
|
if (answer == null) {
|
|
|
|
answer = userProperties.getProperty(optionName, "false");
|
|
|
|
}
|
|
|
|
return answer.equalsIgnoreCase("true");
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXMEDOC
|
|
|
|
private static String getSystemValue(String optionName) {
|
|
|
|
// Look to the System first.
|
|
|
|
String answer = null;
|
|
|
|
try {
|
|
|
|
answer = System.getProperty(optionName);
|
|
|
|
} catch (SecurityException e) {
|
|
|
|
if (!suppressErrs())
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
return answer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the value of a string-valued option, or null if that
|
|
|
|
* option is set nowhere in the hierarchy of properties files.
|
|
|
|
*
|
|
|
|
* @param optionName the option whose value you wish to retrieve
|
|
|
|
* (note the naming conventions detailed in the class comment) */
|
|
|
|
public static String getStringOption(String optionName)
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
// Look to the System first.
|
|
|
|
String answer = getSystemValue(optionName);
|
|
|
|
if (answer == null) {
|
|
|
|
answer = userProperties.getProperty(optionName, null);
|
|
|
|
}
|
|
|
|
return answer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the value of a string-valued option, or defaultValue if that
|
|
|
|
* option is set nowhere in the hierarchy of properties files.
|
|
|
|
*
|
|
|
|
* @param optionName the option whose value you wish to retrieve
|
|
|
|
* (note the naming conventions detailed in the class comment)
|
|
|
|
* @param defaultValue the default value */
|
|
|
|
public static String getStringOption(String optionName,
|
|
|
|
String defaultValue)
|
|
|
|
{
|
|
|
|
String x = getStringOption(optionName);
|
|
|
|
if (null == x)
|
|
|
|
return defaultValue;
|
|
|
|
else
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the value of an integer-valued option, or defaultValue
|
|
|
|
* if that option is set nowhere in the hierarchy of properties
|
|
|
|
* files or is set to something that cannot be decoded to an
|
|
|
|
* integer.
|
|
|
|
*
|
|
|
|
* @param optionName the option whose value you wish to retrieve
|
|
|
|
* (note the naming conventions detailed in the class comment)
|
|
|
|
* @param defaultValue the default value */
|
|
|
|
public static int getIntegerOption(String optionName, int defaultValue)
|
|
|
|
{
|
|
|
|
Integer x = getIntegerOption(optionName);
|
|
|
|
if (null == x)
|
|
|
|
return defaultValue;
|
|
|
|
else
|
|
|
|
return x.intValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the value of an integer-valued option, or null if that
|
|
|
|
* option is set nowhere in the hierarchy of properties files or
|
|
|
|
* is set to something that cannot be decoded to an integer.
|
|
|
|
*
|
|
|
|
* @param optionName the option whose value you wish to retrieve
|
|
|
|
* (note the naming conventions detailed in the class comment) */
|
|
|
|
public static Integer getIntegerOption(String optionName)
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
|
|
|
|
// Look to the System first.
|
|
|
|
String answer = getSystemValue(optionName);
|
|
|
|
if (answer == null) {
|
|
|
|
answer = userProperties.getProperty(optionName, null);
|
|
|
|
}
|
|
|
|
if (null == answer) {
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
return Integer.decode(answer);
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
if (getBooleanOption("thdl.debug"))
|
|
|
|
throw new ThdlLazyException(e);
|
|
|
|
else
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static boolean suppressErrs() {
|
|
|
|
return false; /* FIXME--make THIS configurable. */
|
|
|
|
}
|
|
|
|
private static void init() {
|
|
|
|
try {
|
|
|
|
initialize(ThdlOptions.class, "/options.txt",
|
|
|
|
suppressErrs());
|
|
|
|
} catch (FileNotFoundException e) {
|
|
|
|
if (!suppressErrs())
|
|
|
|
throw new ThdlLazyException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** the properties object that is chained to the system-wide
|
|
|
|
properties which is chained to the built-in properties which
|
|
|
|
is chained to the Java System properties */
|
|
|
|
private static Properties userProperties = null;
|
|
|
|
|
|
|
|
/** to avoid initializing twice */
|
|
|
|
private static boolean isInitialized = false;
|
|
|
|
|
|
|
|
/** Sets userProperties so that it represents the entire, chained
|
|
|
|
preferences hierarchy.
|
|
|
|
|
|
|
|
@param resourceHolder the class associated with the builtin
|
|
|
|
defaults properties file resource
|
|
|
|
@param resourceName the name of the builtin defaults
|
|
|
|
properties file resource
|
|
|
|
@param suppressErrors true if the show must go on, false if
|
|
|
|
you want unchecked exceptions thrown when bad things happen
|
|
|
|
|
|
|
|
@throws FileNotFoundException if !suppressErrors and if the
|
|
|
|
user gave the location of the system-wide or user preferences
|
|
|
|
files, but gave it incorrectly. */
|
|
|
|
private static void initialize(Class resourceHolder,
|
|
|
|
String resourceName,
|
|
|
|
boolean suppressErrors)
|
|
|
|
throws FileNotFoundException
|
|
|
|
{
|
|
|
|
if (isInitialized)
|
|
|
|
return;
|
|
|
|
isInitialized = true;
|
|
|
|
try {
|
|
|
|
|
|
|
|
// Get the application's built-in, default properties.
|
|
|
|
Properties defaultProperties
|
|
|
|
= getPropertiesFromResource(resourceHolder,
|
|
|
|
resourceName,
|
|
|
|
suppressErrors,
|
|
|
|
new Properties() /* empty */);
|
|
|
|
|
|
|
|
// Get the system's properties, if the system administrator
|
|
|
|
// has created any:
|
|
|
|
Properties systemWideProperties
|
|
|
|
= tryToGetPropsFromFile("thdl.system.wide.options.file",
|
|
|
|
// FIXME this default is
|
|
|
|
// system-dependent:
|
|
|
|
"C:\\thdl_opt.txt",
|
|
|
|
defaultProperties,
|
|
|
|
suppressErrors);
|
|
|
|
|
|
|
|
// Get the user's properties, if they've set any:
|
|
|
|
userProperties
|
|
|
|
= tryToGetPropsFromFile("thdl.user.options.file",
|
|
|
|
// FIXME this default is
|
|
|
|
// system-dependent:
|
|
|
|
"C:\\thdl_uopt.txt",
|
|
|
|
systemWideProperties,
|
|
|
|
suppressErrors);
|
|
|
|
} catch (SecurityException e) {
|
|
|
|
if (suppressErrors) {
|
|
|
|
if (userProperties == null) {
|
|
|
|
userProperties = new Properties(); // empty
|
|
|
|
} // else leave it as is.
|
|
|
|
} else {
|
|
|
|
throw new ThdlLazyException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns a new, nonnull Properties object if (1) a preferences
|
|
|
|
file is found at the location specified by the value of the
|
|
|
|
System property pName, if it is set, or at defaultLoc, if
|
|
|
|
pName is not set, and (2) if that file is successfully read
|
|
|
|
in. Otherwise, this returns defaultProps.
|
|
|
|
|
|
|
|
@param pName the name of the System property that overrides
|
|
|
|
this application's default idea of where to look for the file
|
|
|
|
@param defaultLoc the default preferences file name
|
|
|
|
@param suppressErrors true iff you want to proceed without
|
|
|
|
throwing exceptions whenever possible
|
|
|
|
|
|
|
|
@throws FileNotFoundException if !suppressErrors and if the
|
|
|
|
user gave the location of the system-wide or user preferences
|
|
|
|
files, but gave it incorrectly. @throws SecurityException if
|
|
|
|
playing with files or system properties is not OK */
|
|
|
|
private static Properties tryToGetPropsFromFile(String pName,
|
|
|
|
String defaultLoc,
|
|
|
|
Properties defaultProps,
|
|
|
|
boolean suppressErrors)
|
|
|
|
throws FileNotFoundException, SecurityException
|
|
|
|
{
|
|
|
|
Properties props = defaultProps;
|
|
|
|
String systemPropFileName = System.getProperty(pName, defaultLoc);
|
|
|
|
FileInputStream fis = null;
|
|
|
|
try {
|
|
|
|
fis = new FileInputStream(systemPropFileName);
|
|
|
|
} catch (FileNotFoundException e) {
|
|
|
|
if (null != System.getProperty(pName)) {
|
|
|
|
// the user explicitly set this, but not
|
|
|
|
// correctly.
|
|
|
|
if (!suppressErrors)
|
|
|
|
throw e;
|
|
|
|
} else {
|
|
|
|
// definitely suppress this. On a Mac or
|
|
|
|
// Unix/Linux box, this'll happen every time
|
|
|
|
// at present. (FIXME)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fis != null) {
|
|
|
|
props = getPropertiesFromStream(fis,
|
|
|
|
suppressErrors,
|
|
|
|
defaultProps);
|
|
|
|
}
|
|
|
|
return props;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// FIXMEDOC
|
|
|
|
private static Properties getPropertiesFromResource(Class resourceHolder,
|
|
|
|
String resourceName,
|
|
|
|
boolean suppressErrors,
|
|
|
|
Properties defaults)
|
|
|
|
{
|
|
|
|
InputStream in = resourceHolder.getResourceAsStream(resourceName);
|
|
|
|
return getPropertiesFromStream(in, suppressErrors, defaults);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXMEDOC
|
|
|
|
private static Properties getPropertiesFromStream(InputStream in,
|
|
|
|
boolean suppressErrors,
|
|
|
|
Properties defaults)
|
|
|
|
throws NullPointerException
|
|
|
|
{
|
|
|
|
Properties options;
|
|
|
|
if (defaults == null)
|
|
|
|
options = new Properties(); // empty properties list
|
|
|
|
else
|
|
|
|
options = new Properties(defaults);
|
|
|
|
try {
|
|
|
|
// Load props from the resource:
|
|
|
|
options.load(in);
|
|
|
|
return options;
|
|
|
|
} catch (Exception e) {
|
|
|
|
// e is an IOException or a SecurityException or, if the
|
|
|
|
// resource was not found, a NullPointerException.
|
|
|
|
if (suppressErrors) {
|
|
|
|
return options;
|
|
|
|
} else {
|
|
|
|
throw new ThdlLazyException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|