System.err.print(StringUtils.fromTime(now) + ": ");
e.printStackTrace();
} else {
- error(e.getMessage());
+ error(e.toString());
}
}
}
* resource file)
*/
public String getString(E id, String def) {
+ return getString(id, def, -1);
+ }
+
+ /**
+ * Return the value associated to the given id as a {@link String}.
+ * <p>
+ * If no value is associated, take the default one if any.
+ *
+ * @param id
+ * the id of the value to get
+ * @param def
+ * the default value when it is not present in the config file
+ * @param item
+ * the item number to get for an array of values, or -1 for
+ * non-arrays
+ *
+ * @return the associated value, or NULL if not found (not present in the
+ * resource file)
+ */
+ public String getString(E id, String def, int item) {
String rep = getString(id.name(), null);
if (rep == null) {
try {
}
}
- if (rep == null) {
- rep = def;
+ //TODO: is it ok? need to jDoc?
+ if (rep == null || rep.isEmpty()) {
+ return def;
+ }
+
+ if (item >= 0) {
+ List<String> values = BundleHelper.parseList(rep, item);
+ if (values != null && item < values.size()) {
+ return values.get(item);
+ }
+
+ return null;
}
return rep;
setString(id.name(), value);
}
+ /**
+ * Set the value associated to the given id as a {@link String}.
+ *
+ * @param id
+ * the id of the value to set
+ * @param value
+ * the value
+ * @param item
+ * the item number to get for an array of values, or -1 for
+ * non-arrays
+ *
+ */
+ public void setString(E id, String value, int item) {
+ if (item < 0) {
+ setString(id.name(), value);
+ } else {
+ List<String> values = getList(id);
+ for (int i = values.size(); i < item; i++) {
+ values.add(null);
+ }
+ values.set(item, value);
+ setString(id.name(), BundleHelper.fromList(values));
+ }
+ }
+
/**
* Return the value associated to the given id as a {@link String} suffixed
* with the runtime value "_suffix" (that is, "_" and suffix).
* resource file)
*/
public String getStringX(E id, String suffix) {
+ return getStringX(id, suffix, null, -1);
+ }
+
+ /**
+ * Return the value associated to the given id as a {@link String} suffixed
+ * with the runtime value "_suffix" (that is, "_" and suffix).
+ * <p>
+ * Will only accept suffixes that form an existing id.
+ * <p>
+ * If no value is associated, take the default one if any.
+ *
+ * @param id
+ * the id of the value to get
+ * @param suffix
+ * the runtime suffix
+ * @param def
+ * the default value when it is not present in the config file
+ *
+ * @return the associated value, or NULL if not found (not present in the
+ * resource file)
+ */
+ public String getStringX(E id, String suffix, String def) {
+ return getStringX(id, suffix, def, -1);
+ }
+
+ /**
+ * Return the value associated to the given id as a {@link String} suffixed
+ * with the runtime value "_suffix" (that is, "_" and suffix).
+ * <p>
+ * Will only accept suffixes that form an existing id.
+ * <p>
+ * If no value is associated, take the default one if any.
+ *
+ * @param id
+ * the id of the value to get
+ * @param suffix
+ * the runtime suffix
+ * @param item
+ * the item number to get for an array of values, or -1 for
+ * non-arrays
+ * @param def
+ * the default value when it is not present in the config file
+ * @param item
+ * the item number to get for an array of values, or -1 for
+ * non-arrays
+ *
+ * @return the associated value, or NULL if not found (not present in the
+ * resource file)
+ */
+ public String getStringX(E id, String suffix, String def, int item) {
String key = id.name()
+ (suffix == null ? "" : "_" + suffix.toUpperCase());
try {
id = Enum.valueOf(type, key);
- return getString(id);
+ return getString(id, def, item);
} catch (IllegalArgumentException e) {
-
}
return null;
* the value
*/
public void setStringX(E id, String suffix, String value) {
+ setStringX(id, suffix, value, -1);
+ }
+
+ /**
+ * Set the value associated to the given id as a {@link String} suffixed
+ * with the runtime value "_suffix" (that is, "_" and suffix).
+ * <p>
+ * Will only accept suffixes that form an existing id.
+ *
+ * @param id
+ * the id of the value to set
+ * @param suffix
+ * the runtime suffix
+ * @param value
+ * the value
+ * @param item
+ * the item number to get for an array of values, or -1 for
+ * non-arrays
+ */
+ public void setStringX(E id, String suffix, String value, int item) {
String key = id.name()
+ (suffix == null ? "" : "_" + suffix.toUpperCase());
try {
id = Enum.valueOf(type, key);
- setString(id, value);
+ setString(id, value, item);
} catch (IllegalArgumentException e) {
-
}
}
* @return the associated value
*/
public Boolean getBoolean(E id) {
- String str = getString(id);
- return BundleHelper.parseBoolean(str);
+ return BundleHelper.parseBoolean(getString(id), -1);
}
/**
* @return the associated value
*/
public boolean getBoolean(E id, boolean def) {
- Boolean b = getBoolean(id);
- if (b != null)
- return b;
+ Boolean value = getBoolean(id);
+ if (value != null) {
+ return value;
+ }
+
+ return def;
+ }
+
+ /**
+ * Return the value associated to the given id as a {@link Boolean}.
+ * <p>
+ * If no value is associated, take the default one if any.
+ *
+ * @param id
+ * the id of the value to get
+ * @param def
+ * the default value when it is not present in the config file or
+ * if it is not a boolean value
+ * @param item
+ * the item number to get for an array of values, or -1 for
+ * non-arrays
+ *
+ * @return the associated value
+ */
+ public Boolean getBoolean(E id, boolean def, int item) {
+ String value = getString(id);
+ if (value != null) {
+ return BundleHelper.parseBoolean(value, item);
+ }
return def;
}
*
*/
public void setBoolean(E id, boolean value) {
- setString(id.name(), BundleHelper.fromBoolean(value));
+ setBoolean(id, value, -1);
+ }
+
+ /**
+ * Set the value associated to the given id as a {@link Boolean}.
+ *
+ * @param id
+ * the id of the value to set
+ * @param value
+ * the value
+ * @param item
+ * the item number to get for an array of values, or -1 for
+ * non-arrays
+ *
+ */
+ public void setBoolean(E id, boolean value, int item) {
+ setString(id, BundleHelper.fromBoolean(value), item);
}
/**
* @return the associated value
*/
public Integer getInteger(E id) {
- return BundleHelper.parseInteger(getString(id));
+ String value = getString(id);
+ if (value != null) {
+ return BundleHelper.parseInteger(value, -1);
+ }
+
+ return null;
}
/**
* @return the associated value
*/
public int getInteger(E id, int def) {
- Integer i = getInteger(id);
- if (i != null)
- return i;
+ Integer value = getInteger(id);
+ if (value != null) {
+ return value;
+ }
+
+ return def;
+ }
+
+ /**
+ * Return the value associated to the given id as an int.
+ * <p>
+ * If no value is associated, take the default one if any.
+ *
+ * @param id
+ * the id of the value to get
+ * @param def
+ * the default value when it is not present in the config file or
+ * if it is not a int value
+ * @param item
+ * the item number to get for an array of values, or -1 for
+ * non-arrays
+ *
+ * @return the associated value
+ */
+ public Integer getInteger(E id, int def, int item) {
+ String value = getString(id);
+ if (value != null) {
+ return BundleHelper.parseInteger(value, item);
+ }
return def;
}
*
*/
public void setInteger(E id, int value) {
- setString(id.name(), BundleHelper.fromInteger(value));
+ setInteger(id, value, -1);
+ }
+
+ /**
+ * Set the value associated to the given id as a {@link Integer}.
+ *
+ * @param id
+ * the id of the value to set
+ * @param value
+ * the value
+ * @param item
+ * the item number to get for an array of values, or -1 for
+ * non-arrays
+ *
+ */
+ public void setInteger(E id, int value, int item) {
+ setString(id, BundleHelper.fromInteger(value), item);
}
/**
* @return the associated value
*/
public Character getCharacter(E id) {
- return BundleHelper.parseCharacter(getString(id));
+ return BundleHelper.parseCharacter(getString(id), -1);
}
/**
* @return the associated value
*/
public char getCharacter(E id, char def) {
- Character car = getCharacter(id);
- if (car != null)
- return car;
+ Character value = getCharacter(id);
+ if (value != null) {
+ return value;
+ }
+
+ return def;
+ }
+
+ /**
+ * Return the value associated to the given id as a {@link Character}.
+ * <p>
+ * If no value is associated, take the default one if any.
+ *
+ * @param id
+ * the id of the value to get
+ * @param def
+ * the default value when it is not present in the config file or
+ * if it is not a char value
+ *
+ * @return the associated value
+ */
+ public Character getCharacter(E id, char def, int item) {
+ String value = getString(id);
+ if (value != null) {
+ return BundleHelper.parseCharacter(value, item);
+ }
return def;
}
+ /**
+ * Set the value associated to the given id as a {@link Character}.
+ *
+ * @param id
+ * the id of the value to set
+ * @param value
+ * the value
+ *
+ */
+ public void setCharacter(E id, char value) {
+ setCharacter(id, value, -1);
+ }
+
+ /**
+ * Set the value associated to the given id as a {@link Character}.
+ *
+ * @param id
+ * the id of the value to set
+ * @param value
+ * the value
+ * @param item
+ * the item number to get for an array of values, or -1 for
+ * non-arrays
+ *
+ */
+ public void setCharacter(E id, char value, int item) {
+ setString(id, BundleHelper.fromCharacter(value), item);
+ }
+
/**
* Return the value associated to the given id as a colour if it is found
* and can be parsed.
* @return the associated value
*/
public Integer getColor(E id) {
- return BundleHelper.parseColor(getString(id));
+ return BundleHelper.parseColor(getString(id), -1);
+ }
+
+ /**
+ * Return the value associated to the given id as a colour if it is found
+ * and can be parsed.
+ * <p>
+ * The returned value is an ARGB value.
+ * <p>
+ * If no value is associated, take the default one if any.
+ *
+ * @param id
+ * the id of the value to get
+ *
+ * @return the associated value
+ */
+ public int getColor(E id, int def) {
+ Integer value = getColor(id);
+ if (value != null) {
+ return value;
+ }
+
+ return def;
+ }
+
+ /**
+ * Return the value associated to the given id as a colour if it is found
+ * and can be parsed.
+ * <p>
+ * The returned value is an ARGB value.
+ * <p>
+ * If no value is associated, take the default one if any.
+ *
+ * @param id
+ * the id of the value to get
+ *
+ * @return the associated value
+ */
+ public Integer getColor(E id, int def, int item) {
+ String value = getString(id);
+ if (value != null) {
+ return BundleHelper.parseColor(value, item);
+ }
+
+ return def;
}
/**
* the new colour
*/
public void setColor(E id, Integer color) {
- setString(id, BundleHelper.fromColor(color));
+ setColor(id, color, -1);
+ }
+
+ /**
+ * Set the value associated to the given id as a Color.
+ *
+ * @param id
+ * the id of the value to set
+ * @param value
+ * the value
+ * @param item
+ * the item number to get for an array of values, or -1 for
+ * non-arrays
+ *
+ */
+ public void setColor(E id, int value, int item) {
+ setString(id, BundleHelper.fromColor(value), item);
}
/**
* not found or cannot be parsed as a list
*/
public List<String> getList(E id) {
- return BundleHelper.parseList(getString(id));
+ return BundleHelper.parseList(getString(id), -1);
+ }
+
+ /**
+ * Return the value associated to the given id as a list of values if it is
+ * found and can be parsed.
+ * <p>
+ * If no value is associated, take the default one if any.
+ *
+ * @param id
+ * the id of the value to get
+ *
+ * @return the associated list, empty if the value is empty, NULL if it is
+ * not found or cannot be parsed as a list
+ */
+ public List<String> getList(E id, List<String> def) {
+ List<String> value = getList(id);
+ if (value != null) {
+ return value;
+ }
+
+ return def;
+ }
+
+ /**
+ * Return the value associated to the given id as a list of values if it is
+ * found and can be parsed.
+ * <p>
+ * If no value is associated, take the default one if any.
+ *
+ * @param id
+ * the id of the value to get
+ *
+ * @return the associated list, empty if the value is empty, NULL if it is
+ * not found or cannot be parsed as a list
+ */
+ public List<String> getList(E id, List<String> def, int item) {
+ String value = getString(id);
+ if (value != null) {
+ return BundleHelper.parseList(value, item);
+ }
+
+ return def;
}
/**
* the new list of values
*/
public void setList(E id, List<String> list) {
- setString(id, BundleHelper.fromList(list));
+ setList(id, list, -1);
+ }
+
+ /**
+ * Set the value associated to the given id as a {@link List}.
+ *
+ * @param id
+ * the id of the value to set
+ * @param value
+ * the value
+ * @param item
+ * the item number to get for an array of values, or -1 for
+ * non-arrays
+ *
+ */
+ public void setList(E id, List<String> value, int item) {
+ setString(id, BundleHelper.fromList(value), item);
}
/**
}
if (array) {
- builder.append("\n# (This item accepts a list of escaped comma-separated values)");
+ builder.append("\n# (This item accepts a list of ^escaped comma-separated values)");
}
}
*
* @param str
* the input {@link String}
+ * @param item
+ * the item number to use for an array of values, or -1 for
+ * non-arrays
*
* @return the converted {@link Boolean} or NULL
*/
- static public Boolean parseBoolean(String str) {
- if (str != null && str.length() > 0) {
- if (str.equalsIgnoreCase("true") || str.equalsIgnoreCase("on")
- || str.equalsIgnoreCase("yes"))
- return true;
- if (str.equalsIgnoreCase("false") || str.equalsIgnoreCase("off")
- || str.equalsIgnoreCase("no"))
- return false;
-
+ static public Boolean parseBoolean(String str, int item) {
+ str = getItem(str, item);
+ if (str == null) {
+ return null;
}
+ if (str.equalsIgnoreCase("true") || str.equalsIgnoreCase("on")
+ || str.equalsIgnoreCase("yes"))
+ return true;
+ if (str.equalsIgnoreCase("false") || str.equalsIgnoreCase("off")
+ || str.equalsIgnoreCase("no"))
+ return false;
+
return null;
}
*
* @param str
* the input {@link String}
+ * @param item
+ * the item number to use for an array of values, or -1 for
+ * non-arrays
*
* @return the converted {@link Integer} or NULL
*/
- static public Integer parseInteger(String str) {
+ static public Integer parseInteger(String str, int item) {
+ str = getItem(str, item);
+ if (str == null) {
+ return null;
+ }
+
try {
return Integer.parseInt(str);
} catch (Exception e) {
return Integer.toString(value);
}
- /**
- * Return a {@link String} representation of the given {@link Integer}.
- *
- * @param value
- * the input value
- *
- * @return the raw {@link String} value that correspond to it
- */
- static public String fromBoolean(int value) {
- return Integer.toString(value);
- }
-
/**
* Convert the given {@link String} into a {@link Character} if it
* represents a {@link Character}, or NULL if it doesn't.
*
* @param str
* the input {@link String}
+ * @param item
+ * the item number to use for an array of values, or -1 for
+ * non-arrays
*
* @return the converted {@link Character} or NULL
*/
- static public Character parseCharacter(String str) {
+ static public Character parseCharacter(String str, int item) {
+ str = getItem(str, item);
+ if (str == null) {
+ return null;
+ }
+
String s = str.trim();
if (s.length() == 1) {
return s.charAt(0);
*
* @param str
* the input {@link String}
+ * @param item
+ * the item number to use for an array of values, or -1 for
+ * non-arrays
*
* @return the converted colour as an {@link Integer} value or NULL
*/
- static Integer parseColor(String str) {
+ static Integer parseColor(String str, int item) {
+ str = getItem(str, item);
+ if (str == null) {
+ return null;
+ }
+
Integer rep = null;
str = str.trim();
return "#" + rs + gs + bs + as;
}
+ /**
+ * The size of this raw list.
+ *
+ * @param raw
+ * the raw list
+ *
+ * @return its size if it is a list, -1 if not
+ */
+ static public int getListSize(String raw) {
+ List<String> list = parseList(raw, -1);
+ if (list == null) {
+ return -1;
+ }
+
+ return list.size();
+ }
+
/**
* Return a {@link String} representation of the given list of values.
* <p>
* The list of values is comma-separated and each value is surrounded by
- * double-quotes; backslashes and double-quotes are escaped by a backslash.
+ * double-quotes; caret (^) and double-quotes (") are escaped by a caret.
*
* @param str
* the input value
+ * @param item
+ * the item number to use for an array of values, or -1 for
+ * non-arrays
+ *
* @return the raw {@link String} value that correspond to it
*/
- static public List<String> parseList(String str) {
+ static public List<String> parseList(String str, int item) {
if (str == null) {
return null;
}
+
+ if (item >= 0) {
+ str = getItem(str, item);
+ }
+
List<String> list = new ArrayList<String>();
try {
boolean inQuote = false;
inQuote = !inQuote;
break;
- case '\\':
+ case '^':
// We don't process it here
builder.append(car);
prevIsBackSlash = true;
/**
* Return a {@link String} representation of the given list of values.
+ * <p>
+ * NULL will be assimilated to an empty {@link String}.
*
* @param list
* the input value
if (builder.length() > 0) {
builder.append(", ");
}
- builder.append(escape(item));
+ builder.append(escape(item == null ? "" : item));
}
return builder.toString();
}
/**
- * Escape the given value for list formating (no \\, no \n).
+ * Escape the given value for list formating (no carets, no NEWLINES...).
* <p>
* You can unescape it with {@link BundleHelper#unescape(String)}
*
*/
static public String escape(String value) {
return '"' + value//
- .replace("\\", "\\\\") //
- .replace("\"", "\\\"") //
- .replace("\n", "\\\n") //
- .replace("\r", "\\\r") //
+ .replace("^", "^^") //
+ .replace("\"", "^\"") //
+ .replace("\n", "^\n") //
+ .replace("\r", "^\r") //
+ '"';
}
/**
- * Unescape the given value for list formating (change \\n into \n and so
- * on).
+ * Unescape the given value for list formating (change ^n into NEWLINE and
+ * so on).
* <p>
* You can escape it with {@link BundleHelper#escape(String)}
*
case 'R':
builder.append('\r');
break;
- default: // includes \ and "
+ default: // includes ^ and "
builder.append(car);
break;
}
+ prevIsBackslash = false;
} else {
- if (car == '\\') {
+ if (car == '^') {
prevIsBackslash = true;
} else {
builder.append(car);
return builder.toString();
}
+
+ /**
+ * Retrieve the specific item in the given value, assuming it is an array.
+ *
+ * @param value
+ * the value to look into
+ * @param item
+ * the item number to get for an array of values, or -1 for
+ * non-arrays (in that case, simply return the value as-is)
+ *
+ * @return the value as-is for non arrays, the item <tt>item</tt> if found,
+ * NULL if not
+ */
+ static private String getItem(String value, int item) {
+ if (item >= 0) {
+ value = null;
+ List<String> values = parseList(value, -1);
+ if (values != null && item < values.size()) {
+ value = values.get(item);
+ }
+ }
+
+ return value;
+ }
}
import java.util.Iterator;
import java.util.List;
+import be.nikiroo.fanfix.data.MetaData;
import be.nikiroo.utils.resources.Meta.Format;
/**
private String name;
private String description;
+ private boolean dirty;
+
/**
* Create a new {@link MetaInfo} from a value (without children).
* <p>
return meta.array();
}
+ /**
+ * A manual flag to specify if the {@link MetaData} has been changed or not,
+ * which can be used by {@link MetaInfo#save(boolean)}.
+ *
+ * @return TRUE if it is dirty (if it has changed)
+ */
+ public boolean isDirty() {
+ return dirty;
+ }
+
+ /**
+ * A manual flag to specify that the {@link MetaData} has been changed,
+ * which can be used by {@link MetaInfo#save(boolean)}.
+ */
+ public void setDirty() {
+ this.dirty = true;
+ }
+
+ /**
+ * The number of items in this item if it {@link MetaInfo#isArray()}, or -1
+ * if not.
+ *
+ * @param useDefaultIfEmpty
+ * check the size of the default list instead if the list is
+ * empty
+ *
+ * @return -1 or the number of items
+ */
+ public int getListSize(boolean useDefaultIfEmpty) {
+ if (!isArray()) {
+ return -1;
+ }
+
+ return BundleHelper.getListSize(getString(-1, useDefaultIfEmpty));
+ }
+
/**
* This item is only used as a group, not as an option.
* <p>
/**
* The value stored by this item, as a {@link String}.
*
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
* @param useDefaultIfEmpty
* use the default value instead of NULL if the setting is not
* set
*
* @return the value
*/
- public String getString(boolean useDefaultIfEmpty) {
+ public String getString(int item, boolean useDefaultIfEmpty) {
+ if (isArray() && item >= 0) {
+ List<String> values = BundleHelper.parseList(value, -1);
+ if (values != null && item < values.size()) {
+ return values.get(item);
+ }
+
+ if (useDefaultIfEmpty) {
+ return getDefaultString(item);
+ }
+
+ return null;
+ }
+
if (value == null && useDefaultIfEmpty) {
- return getDefaultString();
+ return getDefaultString(item);
}
return value;
/**
* The default value of this item, as a {@link String}.
*
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ *
* @return the default value
*/
- public String getDefaultString() {
+ public String getDefaultString(int item) {
+ if (isArray() && item >= 0) {
+ List<String> values = BundleHelper.parseList(meta.def(), item);
+ if (values != null && item < values.size()) {
+ return values.get(item);
+ }
+
+ return null;
+ }
+
return meta.def();
}
/**
* The value stored by this item, as a {@link Boolean}.
*
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
* @param useDefaultIfEmpty
* use the default value instead of NULL if the setting is not
* set
*
* @return the value
*/
- public Boolean getBoolean(boolean useDefaultIfEmpty) {
- return BundleHelper.parseBoolean(getString(useDefaultIfEmpty));
+ public Boolean getBoolean(int item, boolean useDefaultIfEmpty) {
+ return BundleHelper
+ .parseBoolean(getString(item, useDefaultIfEmpty), -1);
}
/**
* The default value of this item, as a {@link Boolean}.
*
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ *
* @return the default value
*/
- public Boolean getDefaultBoolean() {
- return BundleHelper.parseBoolean(getDefaultString());
+ public Boolean getDefaultBoolean(int item) {
+ return BundleHelper.parseBoolean(getDefaultString(item), -1);
}
/**
* The value stored by this item, as a {@link Character}.
*
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
* @param useDefaultIfEmpty
* use the default value instead of NULL if the setting is not
* set
*
* @return the value
*/
- public Character getCharacter(boolean useDefaultIfEmpty) {
- return BundleHelper.parseCharacter(getString(useDefaultIfEmpty));
+ public Character getCharacter(int item, boolean useDefaultIfEmpty) {
+ return BundleHelper.parseCharacter(getString(item, useDefaultIfEmpty),
+ -1);
}
/**
* The default value of this item, as a {@link Character}.
*
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ *
* @return the default value
*/
- public Character getDefaultCharacter() {
- return BundleHelper.parseCharacter(getDefaultString());
+ public Character getDefaultCharacter(int item) {
+ return BundleHelper.parseCharacter(getDefaultString(item), -1);
}
/**
* The value stored by this item, as an {@link Integer}.
*
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
* @param useDefaultIfEmpty
* use the default value instead of NULL if the setting is not
* set
*
* @return the value
*/
- public Integer getInteger(boolean useDefaultIfEmpty) {
- return BundleHelper.parseInteger(getString(useDefaultIfEmpty));
+ public Integer getInteger(int item, boolean useDefaultIfEmpty) {
+ return BundleHelper
+ .parseInteger(getString(item, useDefaultIfEmpty), -1);
}
/**
* The default value of this item, as an {@link Integer}.
*
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ *
* @return the default value
*/
- public Integer getDefaultInteger() {
- return BundleHelper.parseInteger(getDefaultString());
+ public Integer getDefaultInteger(int item) {
+ return BundleHelper.parseInteger(getDefaultString(item), -1);
}
/**
* <p>
* The returned colour value is an ARGB value.
*
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
* @param useDefaultIfEmpty
* use the default value instead of NULL if the setting is not
* set
*
* @return the value
*/
- public Integer getColor(boolean useDefaultIfEmpty) {
- return BundleHelper.parseColor(getString(useDefaultIfEmpty));
+ public Integer getColor(int item, boolean useDefaultIfEmpty) {
+ return BundleHelper.parseColor(getString(item, useDefaultIfEmpty), -1);
}
/**
* <p>
* The returned colour value is an ARGB value.
*
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ *
* @return the value
*/
- public Integer getDefaultColor() {
- return BundleHelper.parseColor(getDefaultString());
+ public Integer getDefaultColor(int item) {
+ return BundleHelper.parseColor(getDefaultString(item), -1);
}
/**
* The list of values is comma-separated and each value is surrounded by
* double-quotes; backslashes and double-quotes are escaped by a backslash.
*
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
* @param useDefaultIfEmpty
* use the default value instead of NULL if the setting is not
* set
*
* @return the value
*/
- public List<String> getList(boolean useDefaultIfEmpty) {
- return BundleHelper.parseList(getString(useDefaultIfEmpty));
+ public List<String> getList(int item, boolean useDefaultIfEmpty) {
+ return BundleHelper.parseList(getString(item, useDefaultIfEmpty), -1);
}
/**
* The list of values is comma-separated and each value is surrounded by
* double-quotes; backslashes and double-quotes are escaped by a backslash.
*
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ *
* @return the value
*/
- public List<String> getDefaultList() {
- return BundleHelper.parseList(getDefaultString());
+ public List<String> getDefaultList(int item) {
+ return BundleHelper.parseList(getDefaultString(item), -1);
}
/**
*
* @param value
* the new value
- */
- public void setString(String value) {
- this.value = value;
+ * @param item
+ * the item number to set for an array of values, or -1 to set
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ */
+ public void setString(String value, int item) {
+ if (isArray() && item >= 0) {
+ List<String> values = BundleHelper.parseList(this.value, -1);
+ for (int i = values.size(); i <= item; i++) {
+ values.add(null);
+ }
+ values.set(item, value);
+ this.value = BundleHelper.fromList(values);
+ } else {
+ this.value = value;
+ }
}
/**
*
* @param value
* the new value
+ * @param item
+ * the item number to set for an array of values, or -1 to set
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
*/
- public void setBoolean(boolean value) {
- setString(BundleHelper.fromBoolean(value));
+ public void setBoolean(boolean value, int item) {
+ setString(BundleHelper.fromBoolean(value), item);
}
/**
*
* @param value
* the new value
+ * @param item
+ * the item number to set for an array of values, or -1 to set
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
*/
- public void setCharacter(char value) {
- setString(BundleHelper.fromCharacter(value));
+ public void setCharacter(char value, int item) {
+ setString(BundleHelper.fromCharacter(value), item);
}
/**
*
* @param value
* the new value
+ * @param item
+ * the item number to set for an array of values, or -1 to set
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
*/
- public void setInteger(int value) {
- setString(BundleHelper.fromInteger(value));
+ public void setInteger(int value, int item) {
+ setString(BundleHelper.fromInteger(value), item);
}
/**
*
* @param value
* the value
+ * @param item
+ * the item number to set for an array of values, or -1 to set
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
*/
- public void setColor(int value) {
- setString(BundleHelper.fromColor(value));
+ public void setColor(int value, int item) {
+ setString(BundleHelper.fromColor(value), item);
}
/**
*
* @param value
* the {@link String} representation
- *
+ * @param item
+ * the item number to set for an array of values, or -1 to set
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
*/
- public void setList(List<String> value) {
- setString(BundleHelper.fromList(value));
+ public void setList(List<String> value, int item) {
+ setString(BundleHelper.fromList(value), item);
}
/**
try {
listener.run();
} catch (Exception e) {
- // TODO: error management?
e.printStackTrace();
}
}
/**
* Save the current value to the {@link Bundle}.
+ * <p>
+ * Note that listeners will be called <b>before</b> the dirty check and
+ * <b>before</b> saving the value.
+ *
+ * @param onlyIfDirty
+ * only save the data if the dirty flag is set (will reset the
+ * dirty flag)
*/
- public void save() {
+ public void save(boolean onlyIfDirty) {
for (Runnable listener : saveListeners) {
try {
listener.run();
} catch (Exception e) {
- // TODO: error management?
e.printStackTrace();
}
}
- bundle.setString(id, value);
+
+ if (!onlyIfDirty || isDirty()) {
+ bundle.setString(id, value);
+ }
}
/**
@Override
public void actionPerformed(ActionEvent e) {
for (MetaInfo<E> item : items) {
- item.save();
+ item.save(true);
}
try {
package be.nikiroo.utils.ui;
import java.awt.BorderLayout;
-import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
-import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
-import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
-import javax.swing.Icon;
+import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JColorChooser;
-import javax.swing.JComboBox;
import javax.swing.JComponent;
-import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
-import javax.swing.JPasswordField;
-import javax.swing.JSpinner;
import javax.swing.JTextField;
import be.nikiroo.utils.Image;
import be.nikiroo.utils.StringUtils;
import be.nikiroo.utils.StringUtils.Alignment;
import be.nikiroo.utils.resources.Bundle;
-import be.nikiroo.utils.resources.Meta.Format;
import be.nikiroo.utils.resources.MetaInfo;
/**
/** The original value before current changes. */
private Object orig;
+ private List<Integer> dirtyBits;
+
+ protected MetaInfo<E> info;
+
+ private JComponent field;
+ private List<JComponent> fields = new ArrayList<JComponent>();
/**
* Create a new {@link ConfigItem} for the given {@link MetaInfo}.
* different horisontal position)
*/
public ConfigItem(MetaInfo<E> info, int nhgap) {
- this.setLayout(new BorderLayout());
-
- // TODO: support arrays
- Format fmt = info.getFormat();
- if (info.isArray()) {
- fmt = Format.STRING;
- }
+ this(info, true);
- switch (fmt) {
+ ConfigItem<E> configItem;
+ switch (info.getFormat()) {
case BOOLEAN:
- addBooleanField(info, nhgap);
+ configItem = new ConfigItemBoolean<E>(info);
break;
case COLOR:
- addColorField(info, nhgap);
+ configItem = new ConfigItemColor<E>(info);
break;
case FILE:
- addBrowseField(info, nhgap, false);
+ configItem = new ConfigItemBrowse<E>(info, false);
break;
case DIRECTORY:
- addBrowseField(info, nhgap, true);
+ configItem = new ConfigItemBrowse<E>(info, true);
break;
case COMBO_LIST:
- addComboboxField(info, nhgap, true);
+ configItem = new ConfigItemCombobox<E>(info, true);
break;
case FIXED_LIST:
- addComboboxField(info, nhgap, false);
+ configItem = new ConfigItemCombobox<E>(info, false);
break;
case INT:
- addIntField(info, nhgap);
+ configItem = new ConfigItemInteger<E>(info);
break;
case PASSWORD:
- addPasswordField(info, nhgap);
+ configItem = new ConfigItemPassword<E>(info);
break;
case STRING:
case LOCALE: // TODO?
default:
- addStringField(info, nhgap);
+ configItem = new ConfigItemString<E>(info);
break;
}
- }
- private void reload(Object value) {
- // We consider "" and NULL to be equals
- if ("".equals(value)) {
- value = null;
- }
- orig = value;
- }
+ if (info.isArray()) {
+ this.setLayout(new BorderLayout());
+ add(label(nhgap), BorderLayout.WEST);
+
+ final JPanel main = new JPanel();
+ main.setLayout(new BoxLayout(main, BoxLayout.Y_AXIS));
+ int size = info.getListSize(false);
+ for (int i = 0; i < size; i++) {
+ JComponent field = configItem.createComponent(i);
+ main.add(field);
+ }
- private boolean isChanged(Object newValue) {
- // We consider "" and NULL to be equals
- if ("".equals(newValue)) {
- newValue = null;
- }
+ // TODO: image
+ final JButton add = new JButton("+");
+ final ConfigItem<E> fconfigItem = configItem;
+ add.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ JComponent field = fconfigItem
+ .createComponent(fconfigItem.info
+ .getListSize(false));
+ main.add(field);
+
+ // TODO this doesn't woooooorkk
+ add.invalidate();
+ field.invalidate();
+ main.invalidate();
+ ConfigItem.this.repaint();
+ ConfigItem.this.validate();
+ ConfigItem.this.repaint();
+ }
+ });
- if (newValue == null) {
- return orig != null;
- }
+ JPanel tmp = new JPanel(new BorderLayout());
+ tmp.add(add, BorderLayout.WEST);
- return !newValue.equals(orig);
- }
+ JPanel mainPlus = new JPanel(new BorderLayout());
+ mainPlus.add(main, BorderLayout.CENTER);
+ mainPlus.add(tmp, BorderLayout.SOUTH);
- private void addStringField(final MetaInfo<E> info, int nhgap) {
- final JTextField field = new JTextField();
- field.setToolTipText(info.getDescription());
- String value = info.getString(false);
- reload(value);
- field.setText(value);
+ add(mainPlus, BorderLayout.CENTER);
+ } else {
+ this.setLayout(new BorderLayout());
+ add(label(nhgap), BorderLayout.WEST);
- info.addReloadedListener(new Runnable() {
- @Override
- public void run() {
- String value = info.getString(false);
- reload(value);
- field.setText(value);
- }
- });
- info.addSaveListener(new Runnable() {
- @Override
- public void run() {
- String value = field.getText();
- if (isChanged(value)) {
- info.setString(value);
- }
- }
- });
-
- this.add(label(info, nhgap), BorderLayout.WEST);
- this.add(field, BorderLayout.CENTER);
-
- setPreferredSize(field);
+ JComponent field = configItem.createComponent(-1);
+ add(field, BorderLayout.CENTER);
+ }
}
- private void addBooleanField(final MetaInfo<E> info, int nhgap) {
- final JCheckBox field = new JCheckBox();
- field.setToolTipText(info.getDescription());
- Boolean state = info.getBoolean(true);
-
- // Should not happen!
- if (state == null) {
- System.err
- .println("No default value given for BOOLEAN parameter \""
- + info.getName() + "\", we consider it is FALSE");
- state = false;
+ /**
+ * Prepare a new {@link ConfigItem} instance, linked to the given
+ * {@link MetaInfo}.
+ *
+ * @param info
+ * the info
+ * @param autoDirtyHandling
+ * TRUE to automatically manage the setDirty/Save operations,
+ * FALSE if you want to do it yourself via
+ * {@link ConfigItem#setDirtyItem(int)}
+ */
+ protected ConfigItem(MetaInfo<E> info, boolean autoDirtyHandling) {
+ this.info = info;
+ if (!autoDirtyHandling) {
+ dirtyBits = new ArrayList<Integer>();
}
+ }
- reload(state);
- field.setSelected(state);
-
- info.addReloadedListener(new Runnable() {
- @Override
- public void run() {
- Boolean state = info.getBoolean(true);
- if (state == null) {
- state = false;
- }
-
- reload(state);
- field.setSelected(state);
- }
- });
- info.addSaveListener(new Runnable() {
- @Override
- public void run() {
- boolean state = field.isSelected();
- if (isChanged(state)) {
- info.setBoolean(state);
- }
- }
- });
+ /**
+ * Create an empty graphical component to be used later by
+ * {@link ConfigItem#getField(int)}.
+ * <p>
+ * Note that {@link ConfigItem#reload(int)} will be called after it was
+ * created.
+ *
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ *
+ * @return the graphical component
+ */
+ protected JComponent createField(@SuppressWarnings("unused") int item) {
+ // Not used by the main class, only the sublasses
+ return null;
+ }
- this.add(label(info, nhgap), BorderLayout.WEST);
- this.add(field, BorderLayout.CENTER);
+ /**
+ * Get the information from the {@link MetaInfo} in the subclass preferred
+ * format.
+ *
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ *
+ * @return the information in the subclass preferred format
+ */
+ protected Object getFromInfo(@SuppressWarnings("unused") int item) {
+ // Not used by the main class, only the subclasses
+ return null;
+ }
- setPreferredSize(field);
+ /**
+ * Set the value to the {@link MetaInfo}.
+ *
+ * @param value
+ * the value in the subclass preferred format
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ */
+ protected void setToInfo(@SuppressWarnings("unused") Object value,
+ @SuppressWarnings("unused") int item) {
+ // Not used by the main class, only the subclasses
}
- private void addColorField(final MetaInfo<E> info, int nhgap) {
- final JTextField field = new JTextField();
- field.setToolTipText(info.getDescription());
- String value = info.getString(false);
- reload(value);
- field.setText(value);
+ /**
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ *
+ * @return
+ */
+ protected Object getFromField(@SuppressWarnings("unused") int item) {
+ // Not used by the main class, only the subclasses
+ return null;
+ }
- info.addReloadedListener(new Runnable() {
- @Override
- public void run() {
- String value = info.getString(false);
- reload(value);
- field.setText(value);
- }
- });
- info.addSaveListener(new Runnable() {
- @Override
- public void run() {
- String value = field.getText();
- if (isChanged(value)) {
- info.setString(value);
- }
- }
- });
+ /**
+ * Set the value (in the subclass preferred format) into the field.
+ *
+ * @param value
+ * the value in the subclass preferred format
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ */
+ protected void setToField(@SuppressWarnings("unused") Object value,
+ @SuppressWarnings("unused") int item) {
+ // Not used by the main class, only the subclasses
+ }
- this.add(label(info, nhgap), BorderLayout.WEST);
- JPanel pane = new JPanel(new BorderLayout());
+ /**
+ * Create a new field for the given graphical component at the given index
+ * (note that the component is usually created by
+ * {@link ConfigItem#createField(int)}).
+ *
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ * @param field
+ * the graphical component
+ */
+ private void setField(int item, JComponent field) {
+ if (item < 0) {
+ this.field = field;
+ return;
+ }
- final JButton colorWheel = new JButton();
- colorWheel.setIcon(getIcon(17, info.getColor(true)));
- colorWheel.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- Integer icol = info.getColor(true);
- if (icol == null) {
- icol = new Color(255, 255, 255, 255).getRGB();
- }
- Color initialColor = new Color(icol, true);
- Color newColor = JColorChooser.showDialog(ConfigItem.this,
- info.getName(), initialColor);
- if (newColor != null) {
- info.setColor(newColor.getRGB());
- field.setText(info.getString(false));
- colorWheel.setIcon(getIcon(17, info.getColor(true)));
- }
- }
- });
- pane.add(colorWheel, BorderLayout.WEST);
- pane.add(field, BorderLayout.CENTER);
- this.add(pane, BorderLayout.CENTER);
+ for (int i = fields.size(); i <= item; i++) {
+ fields.add(null);
+ }
- setPreferredSize(pane);
+ fields.set(item, field);
}
- private void addBrowseField(final MetaInfo<E> info, int nhgap,
- final boolean dir) {
- final JTextField field = new JTextField();
- field.setToolTipText(info.getDescription());
- String value = info.getString(false);
- reload(value);
- field.setText(value);
-
- info.addReloadedListener(new Runnable() {
- @Override
- public void run() {
- String value = info.getString(false);
- reload(value);
- field.setText(value);
- }
- });
- info.addSaveListener(new Runnable() {
- @Override
- public void run() {
- String value = field.getText();
- if (isChanged(value)) {
- info.setString(value);
- }
- }
- });
-
- JButton browseButton = new JButton("...");
- browseButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- JFileChooser chooser = new JFileChooser();
- chooser.setCurrentDirectory(null);
- chooser.setFileSelectionMode(dir ? JFileChooser.DIRECTORIES_ONLY
- : JFileChooser.FILES_ONLY);
- if (chooser.showOpenDialog(ConfigItem.this) == JFileChooser.APPROVE_OPTION) {
- File file = chooser.getSelectedFile();
- if (file != null) {
- String value = file.getAbsolutePath();
- if (isChanged(value)) {
- info.setString(value);
- }
- field.setText(value);
- }
- }
- }
- });
+ /**
+ * Retrieve the associated graphical component that was created with
+ * {@link ConfigItem#createField(int)}.
+ *
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ *
+ * @return the graphical component
+ */
+ protected JComponent getField(int item) {
+ if (item < 0) {
+ return field;
+ }
- JPanel pane = new JPanel(new BorderLayout());
- this.add(label(info, nhgap), BorderLayout.WEST);
- pane.add(browseButton, BorderLayout.WEST);
- pane.add(field, BorderLayout.CENTER);
- this.add(pane, BorderLayout.CENTER);
+ if (item < fields.size()) {
+ return fields.get(item);
+ }
- setPreferredSize(pane);
+ return null;
}
- private void addComboboxField(final MetaInfo<E> info, int nhgap,
- boolean editable) {
- // rawtypes for Java 1.6 (and 1.7 ?) support
- @SuppressWarnings({ "rawtypes", "unchecked" })
- final JComboBox field = new JComboBox(info.getAllowedValues());
- field.setEditable(editable);
- String value = info.getString(false);
- reload(value);
- field.setSelectedItem(value);
-
- info.addReloadedListener(new Runnable() {
- @Override
- public void run() {
- String value = info.getString(false);
- reload(value);
- field.setSelectedItem(value);
- }
- });
- info.addSaveListener(new Runnable() {
- @Override
- public void run() {
- Object item = field.getSelectedItem();
- String value = item == null ? null : item.toString();
- if (isChanged(value)) {
- info.setString(value);
- }
- }
- });
-
- this.add(label(info, nhgap), BorderLayout.WEST);
- this.add(field, BorderLayout.CENTER);
+ /**
+ * Manually specify that the given item is "dirty" and thus should be saved
+ * when asked.
+ * <p>
+ * Has no effect if the class is using automatic dirty handling (see
+ * {@link ConfigItem#ConfigItem(MetaInfo, boolean)}).
+ *
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ */
+ protected void setDirtyItem(int item) {
+ if (dirtyBits != null) {
+ dirtyBits.add(item);
+ }
+ }
- setPreferredSize(field);
+ /**
+ * Check if the value changed since the last load/save into the linked
+ * {@link MetaInfo}.
+ * <p>
+ * Note that we consider NULL and an Empty {@link String} to be equals.
+ *
+ * @param value
+ * the value to test
+ *
+ * @return TRUE if it has
+ */
+ protected boolean hasValueChanged(Object value) {
+ // We consider "" and NULL to be equals
+ return !orig.equals(value == null ? "" : value);
}
- private void addPasswordField(final MetaInfo<E> info, int nhgap) {
- final JPasswordField field = new JPasswordField();
- field.setToolTipText(info.getDescription());
- String value = info.getString(false);
- reload(value);
- field.setText(value);
+ /**
+ * Reload the values to what they currently are in the {@link MetaInfo}.
+ *
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ */
+ protected void reload(int item) {
+ Object value = getFromInfo(item);
+ setToField(value, item);
- info.addReloadedListener(new Runnable() {
- @Override
- public void run() {
- String value = info.getString(false);
- reload(value);
- field.setText(value);
- }
- });
- info.addSaveListener(new Runnable() {
- @Override
- public void run() {
- String value = new String(field.getPassword());
- if (isChanged(value)) {
- info.setString(value);
- }
- }
- });
+ // We consider "" and NULL to be equals
+ orig = (value == null ? "" : value);
+ }
- this.add(label(info, nhgap), BorderLayout.WEST);
- this.add(field, BorderLayout.CENTER);
+ /**
+ * If the item has been modified, set the {@link MetaInfo} to dirty then
+ * modify it to, reflect the changes so it can be saved later.
+ * <p>
+ * This method does <b>not</b> call {@link MetaInfo#save(boolean)}.
+ *
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ */
+ protected void save(int item) {
+ Object value = getFromField(item);
+
+ boolean dirty = false;
+ if (dirtyBits != null) {
+ dirty = dirtyBits.remove((Integer) item);
+ } else {
+ // We consider "" and NULL to be equals
+ dirty = hasValueChanged(value);
+ }
- setPreferredSize(field);
+ if (dirty) {
+ info.setDirty();
+ setToInfo(value, item);
+ orig = (value == null ? "" : value);
+ }
}
- private void addIntField(final MetaInfo<E> info, int nhgap) {
- final JSpinner field = new JSpinner();
- field.setToolTipText(info.getDescription());
- int value = info.getInteger(true) == null ? 0 : info.getInteger(true);
- reload(value);
- field.setValue(value);
+ /**
+ *
+ * @param item
+ * the item number to get for an array of values, or -1 to get
+ * the whole value (has no effect if {@link MetaInfo#isArray()}
+ * is FALSE)
+ * @param addTo
+ * @param nhgap
+ */
+ protected JComponent createComponent(final int item) {
+ setField(item, createField(item));
+ reload(item);
info.addReloadedListener(new Runnable() {
@Override
public void run() {
- int value = info.getInteger(true) == null ? 0 : info
- .getInteger(true);
- reload(value);
- field.setValue(value);
+ reload(item);
}
});
info.addSaveListener(new Runnable() {
@Override
public void run() {
- int value = field.getValue() == null ? 0 : (Integer) field
- .getValue();
- if (isChanged(value)) {
- info.setInteger(value);
- }
+ save(item);
}
});
- this.add(label(info, nhgap), BorderLayout.WEST);
- this.add(field, BorderLayout.CENTER);
-
+ JComponent field = getField(item);
setPreferredSize(field);
+
+ return field;
}
/**
* Create a label which width is constrained in lock steps.
*
- * @param info
- * the {@link MetaInfo} for which we want to add a label
* @param nhgap
* negative horisontal gap in pixel to use for the label, i.e.,
* the step lock sized labels will start smaller by that amount
*
* @return the label
*/
- private JComponent label(final MetaInfo<E> info, int nhgap) {
+ protected JComponent label(int nhgap) {
final JLabel label = new JLabel(info.getName());
Dimension ps = label.getPreferredSize();
return pane;
}
- /**
- * Return an {@link Icon} to use as a colour badge for the colour field
- * controls.
- *
- * @param size
- * the size of the badge
- * @param color
- * the colour of the badge, which can be NULL (will return
- * transparent white)
- *
- * @return the badge
- */
- private Icon getIcon(int size, Integer color) {
- // Allow null values
- if (color == null) {
- color = new Color(255, 255, 255, 255).getRGB();
- }
-
- Color c = new Color(color, true);
- int avg = (c.getRed() + c.getGreen() + c.getBlue()) / 3;
- Color border = (avg >= 128 ? Color.BLACK : Color.WHITE);
-
- BufferedImage img = new BufferedImage(size, size,
- BufferedImage.TYPE_4BYTE_ABGR);
-
- Graphics2D g = img.createGraphics();
- try {
- g.setColor(c);
- g.fillRect(0, 0, img.getWidth(), img.getHeight());
- g.setColor(border);
- g.drawRect(0, 0, img.getWidth() - 1, img.getHeight() - 1);
- } finally {
- g.dispose();
- }
-
- return new ImageIcon(img);
- }
-
- private void setPreferredSize(JComponent field) {
+ protected void setPreferredSize(JComponent field) {
int height = Math
.max(getMinimumHeight(), field.getMinimumSize().height);
setPreferredSize(new Dimension(200, height));
--- /dev/null
+package be.nikiroo.utils.ui;
+
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+
+import be.nikiroo.utils.resources.MetaInfo;
+
+public class ConfigItemBoolean<E extends Enum<E>> extends ConfigItem<E> {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Create a new {@link ConfigItemBoolean} for the given {@link MetaInfo}.
+ *
+ * @param info
+ * the {@link MetaInfo}
+ */
+ public ConfigItemBoolean(MetaInfo<E> info) {
+ super(info, true);
+ }
+
+ @Override
+ protected Object getFromField(int item) {
+ JCheckBox field = (JCheckBox) getField(item);
+ if (field != null) {
+ return field.isSelected();
+ }
+
+ return null;
+ }
+
+ @Override
+ protected Object getFromInfo(int item) {
+ return info.getBoolean(item, false);
+ }
+
+ @Override
+ protected void setToField(Object value, int item) {
+ JCheckBox field = (JCheckBox) getField(item);
+ if (field != null) {
+ // Should not happen if config enum is correct
+ // (but this is not enforced)
+ if (value == null) {
+ value = false;
+ }
+
+ field.setSelected((Boolean) value);
+ }
+ }
+
+ @Override
+ protected void setToInfo(Object value, int item) {
+ info.setBoolean((Boolean) value, item);
+ }
+
+ @Override
+ protected JComponent createField(int item) {
+ // Should not happen!
+ if (getFromInfo(item) == null) {
+ System.err
+ .println("No default value given for BOOLEAN parameter \""
+ + info.getName() + "\", we consider it is FALSE");
+ }
+
+ return new JCheckBox();
+ }
+}
--- /dev/null
+package be.nikiroo.utils.ui;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import be.nikiroo.utils.resources.MetaInfo;
+
+public class ConfigItemBrowse<E extends Enum<E>> extends ConfigItem<E> {
+ private static final long serialVersionUID = 1L;
+
+ private boolean dir;
+ private Map<JComponent, JTextField> fields = new HashMap<JComponent, JTextField>();
+
+ /**
+ * Create a new {@link ConfigItemBrowse} for the given {@link MetaInfo}.
+ *
+ * @param info
+ * the {@link MetaInfo}
+ * @param dir
+ * TRUE for directory browsing, FALSE for file browsing
+ */
+ public ConfigItemBrowse(MetaInfo<E> info, boolean dir) {
+ super(info, false);
+ this.dir = dir;
+ }
+
+ @Override
+ protected Object getFromField(int item) {
+ JTextField field = fields.get(getField(item));
+ if (field != null) {
+ return new File(field.getText());
+ }
+
+ return null;
+ }
+
+ @Override
+ protected Object getFromInfo(int item) {
+ String path = info.getString(item, false);
+ if (path != null && !path.isEmpty()) {
+ return new File(path);
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void setToField(Object value, int item) {
+ JTextField field = fields.get(getField(item));
+ if (field != null) {
+ field.setText(value == null ? "" : ((File) value).getPath());
+ }
+ }
+
+ @Override
+ protected void setToInfo(Object value, int item) {
+ info.setString(((File) value).getPath(), item);
+ }
+
+ @Override
+ protected JComponent createField(final int item) {
+ final JPanel pane = new JPanel(new BorderLayout());
+ final JTextField field = new JTextField();
+ field.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyTyped(KeyEvent e) {
+ File file = null;
+ if (!field.getText().isEmpty()) {
+ file = new File(field.getText());
+ }
+
+ if (hasValueChanged(file)) {
+ setDirtyItem(item);
+ }
+ }
+ });
+
+ final JButton browseButton = new JButton("...");
+ browseButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ JFileChooser chooser = new JFileChooser();
+ chooser.setCurrentDirectory((File) getFromInfo(item));
+ chooser.setFileSelectionMode(dir ? JFileChooser.DIRECTORIES_ONLY
+ : JFileChooser.FILES_ONLY);
+ if (chooser.showOpenDialog(ConfigItemBrowse.this) == JFileChooser.APPROVE_OPTION) {
+ File file = chooser.getSelectedFile();
+ if (file != null) {
+ setToField(file, item);
+ if (hasValueChanged(file)) {
+ setDirtyItem(item);
+ }
+ }
+ }
+ }
+ });
+
+ pane.add(browseButton, BorderLayout.WEST);
+ pane.add(field, BorderLayout.CENTER);
+
+ fields.put(pane, field);
+ return pane;
+ }
+}
--- /dev/null
+package be.nikiroo.utils.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.image.BufferedImage;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JColorChooser;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import be.nikiroo.utils.resources.MetaInfo;
+
+public class ConfigItemColor<E extends Enum<E>> extends ConfigItem<E> {
+ private static final long serialVersionUID = 1L;
+
+ private Map<JComponent, JTextField> fields = new HashMap<JComponent, JTextField>();
+
+ /**
+ * Create a new {@link ConfigItemColor} for the given {@link MetaInfo}.
+ *
+ * @param info
+ * the {@link MetaInfo}
+ */
+ public ConfigItemColor(MetaInfo<E> info) {
+ super(info, true);
+ }
+
+ @Override
+ protected Object getFromField(int item) {
+ JTextField field = fields.get(getField(item));
+ if (field != null) {
+ return field.getText();
+ }
+
+ return null;
+ }
+
+ @Override
+ protected Object getFromInfo(int item) {
+ return info.getString(item, false);
+ }
+
+ @Override
+ protected void setToField(Object value, int item) {
+ JTextField field = fields.get(getField(item));
+ if (field != null) {
+ field.setText(value == null ? "" : value.toString());
+ }
+ // TODO: change color too
+ }
+
+ @Override
+ protected void setToInfo(Object value, int item) {
+ info.setString((String) value, item);
+ }
+
+ private int getFromInfoColor(int item) {
+ Integer color = info.getColor(item, true);
+ if (color == null) {
+ return new Color(255, 255, 255, 255).getRGB();
+ }
+
+ return color;
+ }
+
+ @Override
+ protected JComponent createField(final int item) {
+ final JPanel pane = new JPanel(new BorderLayout());
+ final JTextField field = new JTextField();
+
+ final JButton colorWheel = new JButton();
+ colorWheel.setIcon(getIcon(17, getFromInfoColor(item)));
+ colorWheel.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ int icol = getFromInfoColor(item);
+ Color initialColor = new Color(icol, true);
+ Color newColor = JColorChooser.showDialog(ConfigItemColor.this,
+ info.getName(), initialColor);
+ if (newColor != null) {
+ info.setColor(newColor.getRGB(), item);
+ field.setText(info.getString(item, false));
+ colorWheel.setIcon(getIcon(17, info.getColor(item, true)));
+ }
+ }
+ });
+
+ pane.add(colorWheel, BorderLayout.WEST);
+ pane.add(field, BorderLayout.CENTER);
+
+ fields.put(pane, field);
+ return pane;
+ }
+
+ /**
+ * Return an {@link Icon} to use as a colour badge for the colour field
+ * controls.
+ *
+ * @param size
+ * the size of the badge
+ * @param color
+ * the colour of the badge, which can be NULL (will return
+ * transparent white)
+ *
+ * @return the badge
+ */
+ static private Icon getIcon(int size, Integer color) {
+ // Allow null values
+ if (color == null) {
+ color = new Color(255, 255, 255, 255).getRGB();
+ }
+
+ Color c = new Color(color, true);
+ int avg = (c.getRed() + c.getGreen() + c.getBlue()) / 3;
+ Color border = (avg >= 128 ? Color.BLACK : Color.WHITE);
+
+ BufferedImage img = new BufferedImage(size, size,
+ BufferedImage.TYPE_4BYTE_ABGR);
+
+ Graphics2D g = img.createGraphics();
+ try {
+ g.setColor(c);
+ g.fillRect(0, 0, img.getWidth(), img.getHeight());
+ g.setColor(border);
+ g.drawRect(0, 0, img.getWidth() - 1, img.getHeight() - 1);
+ } finally {
+ g.dispose();
+ }
+
+ return new ImageIcon(img);
+ }
+}
--- /dev/null
+package be.nikiroo.utils.ui;
+
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+
+import be.nikiroo.utils.resources.MetaInfo;
+
+public class ConfigItemCombobox<E extends Enum<E>> extends ConfigItem<E> {
+ private static final long serialVersionUID = 1L;
+
+ private boolean editable;
+
+ /**
+ * Create a new {@link ConfigItemCombobox} for the given {@link MetaInfo}.
+ *
+ * @param info
+ * the {@link MetaInfo}
+ * @param editable
+ * allows the user to type in another value not in the list
+ */
+ public ConfigItemCombobox(MetaInfo<E> info, boolean editable) {
+ super(info, true);
+ this.editable = editable;
+ }
+
+ @Override
+ protected Object getFromField(int item) {
+ // rawtypes for Java 1.6 (and 1.7 ?) support
+ @SuppressWarnings("rawtypes")
+ JComboBox field = (JComboBox) getField(item);
+ if (field != null) {
+ return field.getSelectedItem();
+ }
+
+ return null;
+ }
+
+ @Override
+ protected Object getFromInfo(int item) {
+ return info.getString(item, false);
+ }
+
+ @Override
+ protected void setToField(Object value, int item) {
+ // rawtypes for Java 1.6 (and 1.7 ?) support
+ @SuppressWarnings("rawtypes")
+ JComboBox field = (JComboBox) getField(item);
+ if (field != null) {
+ field.setSelectedItem(value);
+ }
+ }
+
+ @Override
+ protected void setToInfo(Object value, int item) {
+ info.setString((String) value, item);
+ }
+
+ // rawtypes for Java 1.6 (and 1.7 ?) support
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ protected JComponent createField(int item) {
+ JComboBox field = new JComboBox(info.getAllowedValues());
+ field.setEditable(editable);
+ return field;
+ }
+}
--- /dev/null
+package be.nikiroo.utils.ui;
+
+import javax.swing.JComponent;
+import javax.swing.JSpinner;
+
+import be.nikiroo.utils.resources.MetaInfo;
+
+public class ConfigItemInteger<E extends Enum<E>> extends ConfigItem<E> {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Create a new {@link ConfigItemInteger} for the given {@link MetaInfo}.
+ *
+ * @param info
+ * the {@link MetaInfo}
+ */
+ public ConfigItemInteger(MetaInfo<E> info) {
+ super(info, true);
+ }
+
+ @Override
+ protected Object getFromField(int item) {
+ JSpinner field = (JSpinner) getField(item);
+ if (field != null) {
+ return field.getValue();
+ }
+
+ return null;
+ }
+
+ @Override
+ protected Object getFromInfo(int item) {
+ return info.getInteger(item, false);
+ }
+
+ @Override
+ protected void setToField(Object value, int item) {
+ JSpinner field = (JSpinner) getField(item);
+ if (field != null) {
+ field.setValue(value == null ? 0 : (Integer) value);
+ }
+ }
+
+ @Override
+ protected void setToInfo(Object value, int item) {
+ info.setInteger((Integer) value, item);
+ }
+
+ @Override
+ protected JComponent createField(int item) {
+ return new JSpinner();
+ }
+}
--- /dev/null
+package be.nikiroo.utils.ui;
+
+import javax.swing.JComponent;
+import javax.swing.JPasswordField;
+
+import be.nikiroo.utils.resources.MetaInfo;
+
+public class ConfigItemPassword<E extends Enum<E>> extends ConfigItem<E> {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Create a new {@link ConfigItemPassword} for the given {@link MetaInfo}.
+ *
+ * @param info
+ * the {@link MetaInfo}
+ */
+ public ConfigItemPassword(MetaInfo<E> info) {
+ super(info, true);
+ }
+
+ @Override
+ protected Object getFromField(int item) {
+ JPasswordField field = (JPasswordField) getField(item);
+ if (field != null) {
+ return new String(field.getPassword());
+ }
+
+ return null;
+ }
+
+ @Override
+ protected Object getFromInfo(int item) {
+ return info.getString(item, false);
+ }
+
+ @Override
+ protected void setToField(Object value, int item) {
+ JPasswordField field = (JPasswordField) getField(item);
+ if (field != null) {
+ field.setText(value == null ? "" : value.toString());
+ }
+ }
+
+ @Override
+ protected void setToInfo(Object value, int item) {
+ info.setString((String) value, item);
+ }
+
+ @Override
+ protected JComponent createField(int item) {
+ return new JPasswordField();
+ }
+}
--- /dev/null
+package be.nikiroo.utils.ui;
+
+import javax.swing.JComponent;
+import javax.swing.JTextField;
+
+import be.nikiroo.utils.resources.MetaInfo;
+
+public class ConfigItemString<E extends Enum<E>> extends ConfigItem<E> {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Create a new {@link ConfigItemString} for the given {@link MetaInfo}.
+ *
+ * @param info
+ * the {@link MetaInfo}
+ */
+ public ConfigItemString(MetaInfo<E> info) {
+ super(info, true);
+ }
+
+ @Override
+ protected Object getFromField(int item) {
+ JTextField field = (JTextField) getField(item);
+ if (field != null) {
+ return field.getText();
+ }
+
+ return null;
+ }
+
+ @Override
+ protected Object getFromInfo(int item) {
+ return info.getString(item, false);
+ }
+
+ @Override
+ protected void setToField(Object value, int item) {
+ JTextField field = (JTextField) getField(item);
+ if (field != null) {
+ field.setText(value == null ? "" : value.toString());
+ }
+ }
+
+ @Override
+ protected void setToInfo(Object value, int item) {
+ info.setString((String) value, item);
+ }
+
+ @Override
+ protected JComponent createField(int item) {
+ return new JTextField();
+ }
+}