/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.config;
import freenet.l10n.BaseL10n;
import freenet.l10n.NodeL10n;
import freenet.pluginmanager.FredPluginConfigurable;
import freenet.support.HTMLNode;
/**
* A config option.
*/
public abstract class Option<T> {
/** The parent SubConfig object */
protected final SubConfig config;
/** The option name */
protected final String name;
/** The sort order */
protected final int sortOrder;
/** Is this config variable expert-only? */
protected final boolean expert;
/** Is this config variable to be written out even if it uses the default value? */
protected final boolean forceWrite;
/** Short description of value e.g. "FCP port" */
protected final String shortDesc;
/** Long description of value e.g. "The TCP port to listen for FCP connections on" */
protected final String longDesc;
/** The configCallback associated to the Option */
protected final ConfigCallback<T> cb;
protected T defaultValue;
protected T currentValue;
public static enum DataType {
STRING, NUMBER, BOOLEAN, STRING_ARRAY
};
/** Data type : used to make it possible to make user inputs more friendly in FCP apps */
final DataType dataType;
Option(SubConfig config, String name, ConfigCallback<T> cb, int sortOrder, boolean expert, boolean forceWrite,
String shortDesc, String longDesc, DataType dataType) {
this.config = config;
this.name = name;
this.cb = cb;
this.sortOrder = sortOrder;
this.expert = expert;
this.shortDesc = shortDesc;
this.longDesc = longDesc;
this.forceWrite = forceWrite;
this.dataType = dataType;
}
/**
* Set this option's current value to a string. Will call the callback. Does not care whether
* the value of the option has changed.
*/
public final void setValue(String val) throws InvalidConfigValueException, NodeNeedRestartException {
T x = parseString(val);
set(x);
}
protected abstract T parseString(String val) throws InvalidConfigValueException;
protected abstract String toString(T val);
protected String toDisplayString(T val) {
return toString(val);
}
protected final void set(T val) throws InvalidConfigValueException, NodeNeedRestartException {
try {
cb.set(val);
currentValue = val;
} catch (NodeNeedRestartException e) {
currentValue = val;
throw e;
}
}
/**
* Get the current value of the option as a string.
*/
public final String getValueString() {
return toString(currentValue);
}
/**
* Get the current value of the option as a string suited to end-user display.
*/
public final String getValueDisplayString() {
return toDisplayString(currentValue);
}
/** Set to a value from the config file; this is not passed on to the callback, as we
* expect the client-side initialization to check the value. The callback is not valid
* until the client calls finishedInitialization().
* @throws InvalidConfigValueException
*/
public final void setInitialValue(String val) throws InvalidConfigValueException {
currentValue = parseString(val);
}
/**
* Call the callback with the current value of the option.
*/
public void forceUpdate() throws InvalidConfigValueException, NodeNeedRestartException {
setValue(getValueString());
}
public String getName(){
return name;
}
/** Used in alt="" to label a box with the option name used in the config file.
* FIXME get rid of said alt=""? Not much use for most users. See caller. */
public String getShortDesc(){
return shortDesc;
}
/** Not used outside the class. */
private String getLongDesc(){
return longDesc;
}
public boolean isExpert(){
return expert;
}
public boolean isForcedWrite(){
return forceWrite;
}
public int getSortOrder(){
return sortOrder;
}
public DataType getDataType() {
return dataType;
}
public String getDataTypeStr() {
switch(dataType) {
case STRING:
return "string";
case NUMBER:
return "number";
case BOOLEAN:
return "boolean";
case STRING_ARRAY:
return "stringArray";
default: return null;
}
}
/**
* Get the current value. This is the value in use if we have finished initialization, otherwise
* it is the value set at startup (possibly the default).
*/
public final T getValue() {
if (config.hasFinishedInitialization())
return currentValue = cb.get();
else
return currentValue;
}
/**
* Is this option set to the default?
*/
public boolean isDefault() {
getValue();
return (currentValue == null ? false : currentValue.equals(defaultValue));
}
/**
* Set to the default. Don't use after completed initialization, as this does not call the
* callback.
*/
public final void setDefault() {
currentValue = defaultValue;
}
public final String getDefault() {
return toString(defaultValue);
}
public final ConfigCallback<T> getCallback() {
return cb;
}
/** Useful for plugins as can pass own BaseL10n in */
public String getLocalisedShortDesc(BaseL10n l10n) {
return l10n.getString(getShortDesc(), "default", getDefault());
}
/** Get the localised short description */
public String getLocalisedShortDesc() {
return getLocalisedShortDesc(NodeL10n.getBase());
}
/** Useful for plugins as can pass own BaseL10n in */
public String getLocalisedLongDesc(BaseL10n l10n) {
return l10n.getString(getLongDesc(), "default", getDefault());
}
/** Get the localised long description */
public String getLocalisedLongDesc() {
return getLocalisedLongDesc(NodeL10n.getBase());
}
/** Get the localised short description as an HTMLNode, possibly with translation link */
public HTMLNode getShortDescNode(FredPluginConfigurable plugin) {
return (plugin == null) ? NodeL10n.getBase()
.getHTMLNode(getShortDesc(), new String[] { "default" } , new String[] { getDefault() }) : new HTMLNode("#",
plugin.getString(getShortDesc()));
}
public HTMLNode getShortDescNode() {
return getShortDescNode(null);
}
/** Get the localised long description as an HTMLNode, possibly with translation link */
public HTMLNode getLongDescNode(FredPluginConfigurable plugin) {
return (plugin == null) ? NodeL10n.getBase()
.getHTMLNode(getLongDesc(), new String[] { "default" } , new String[] { getDefault() }) : new HTMLNode("#",
plugin.getString(getLongDesc()));
}
public HTMLNode getLongDescNode() {
return getLongDescNode(null);
}
}