X-Git-Url: http://git.nikiroo.be/?p=nikiroo-utils.git;a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2Fresources%2FBundle.java;h=4420109caa157a8358f1298b8186c71a05bec4c2;hp=1c63d69f04f84276eeaf19ee3a29e028f52fae54;hb=e9ca6bb892b5358a273807bff834945ffe7b0cee;hpb=ec1f3444e9f238ce1559d5fff32eb5a7ab8aba53 diff --git a/src/be/nikiroo/utils/resources/Bundle.java b/src/be/nikiroo/utils/resources/Bundle.java index 1c63d69..4420109 100644 --- a/src/be/nikiroo/utils/resources/Bundle.java +++ b/src/be/nikiroo/utils/resources/Bundle.java @@ -1,5 +1,6 @@ package be.nikiroo.utils.resources; +import java.awt.Color; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; @@ -8,23 +9,24 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; -import java.io.UnsupportedEncodingException; import java.io.Writer; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.MissingResourceException; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; -import be.nikiroo.utils.resources.Bundles; -import be.nikiroo.utils.resources.Meta; - /** - * This class encapsulate a {@link ResourceBundle} in UTF-8. It only allows to + * This class encapsulate a {@link ResourceBundle} in UTF-8. It allows to * retrieve values associated to an enumeration, and allows some additional * methods. + *

+ * It also sports a writable change map, and you can save back the + * {@link Bundle} to file with {@link Bundle#updateFile(String)}. * * @author niki * @@ -35,6 +37,7 @@ public class Bundle> { protected Class type; protected Enum name; private ResourceBundle map; + private Map changeMap; /** * Create a new {@link Bundles} of the given name. @@ -48,7 +51,8 @@ public class Bundle> { protected Bundle(Class type, Enum name) { this.type = type; this.name = name; - setBundle(name, Locale.getDefault()); + this.changeMap = new HashMap(); + setBundle(name, Locale.getDefault(), false); } /** @@ -61,7 +65,20 @@ public class Bundle> { * resource file) */ public String getString(E id) { - return getStringX(id, ""); + return getStringX(id, null); + } + + /** + * Set the value associated to the given id as a {@link String}. + * + * @param mame + * the id of the value to get + * @param value + * the value + * + */ + public void setString(E id, String value) { + setStringX(id, null, value); } /** @@ -78,8 +95,7 @@ public class Bundle> { */ public String getStringX(E id, String suffix) { String key = id.name() - + ((suffix == null || suffix.isEmpty()) ? "" : "_" - + suffix.toUpperCase()); + + (suffix == null ? "" : "_" + suffix.toUpperCase()); if (containsKey(key)) { return getString(key).trim(); @@ -88,6 +104,24 @@ public class Bundle> { return null; } + /** + * Set the value associated to the given id as a {@link String} suffixed + * with the runtime value "_suffix" (that is, "_" and suffix). + * + * @param mame + * the id of the value to get + * @param suffix + * the runtime suffix + * @param value + * the value + */ + public void setStringX(E id, String suffix, String value) { + String key = id.name() + + (suffix == null ? "" : "_" + suffix.toUpperCase()); + + setString(key, value); + } + /** * Return the value associated to the given id as a {@link Boolean}. * @@ -112,7 +146,7 @@ public class Bundle> { } /** - * Return the value associated to the given id as a {@link boolean}. + * Return the value associated to the given id as a {@link Boolean}. * * @param mame * the id of the value to get @@ -174,20 +208,91 @@ public class Bundle> { * * @return the associated value */ - public char getChar(E id) { + public Character getCharacter(E id) { String s = getString(id).trim(); if (s.length() > 0) { return s.charAt(0); } - return ' '; + return null; + } + + /** + * Return the value associated to the given id as a {@link Character}. + * + * @param mame + * 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 char getCharacter(E id, char def) { + String s = getString(id).trim(); + if (s.length() > 0) { + return s.charAt(0); + } + + return def; + } + + /** + * Return the value associated to the given id as a {@link Color}. + * + * @param the + * id of the value to get + * + * @return the associated value + */ + public Color getColor(E id) { + Color color = null; + + String bg = getString(id).trim(); + if (bg.startsWith("#") && (bg.length() == 7 || bg.length() == 9)) { + try { + int r = Integer.parseInt(bg.substring(1, 3), 16); + int g = Integer.parseInt(bg.substring(3, 5), 16); + int b = Integer.parseInt(bg.substring(5, 7), 16); + int a = 255; + if (bg.length() == 9) { + a = Integer.parseInt(bg.substring(7, 9), 16); + } + color = new Color(r, g, b, a); + } catch (NumberFormatException e) { + color = null; // no changes + } + } + + return color; + } + + /** + * Set the value associated to the given id as a {@link Color}. + * + * @param the + * id of the value to get + * + * @return the associated value + */ + public void setColor(E id, Color color) { + String r = Integer.toString(color.getRed(), 16); + String g = Integer.toString(color.getGreen(), 16); + String b = Integer.toString(color.getBlue(), 16); + String a = ""; + if (color.getAlpha() < 255) { + a = Integer.toString(color.getAlpha(), 16); + } + + setString(id, "#" + r + g + b + a); } /** - * Create/update the .properties file. Will use the most likely candidate as - * base if the file does not already exists and this resource is - * translatable (for instance, "en_US" will use "en" as a base if the - * resource is a translation file). + * Create/update the .properties file. + *

+ * Will use the most likely candidate as base if the file does not already + * exists and this resource is translatable (for instance, "en_US" will use + * "en" as a base if the resource is a translation file). * * @param path * the path where the .properties files are @@ -223,6 +328,18 @@ public class Bundle> { writer.close(); } + /** + * Reload the {@link Bundle} data files. + * + * @param resetToDefault + * reset to the default configuration (do not look into the + * possible user configuration files, only take the original + * configuration) + */ + public void reload(boolean resetToDefault) { + setBundle(name, null, resetToDefault); + } + /** * Check if the internal map contains the given key. * @@ -232,40 +349,55 @@ public class Bundle> { * @return true if it does */ protected boolean containsKey(String key) { - try { - map.getObject(key); + if (changeMap.containsKey(key)) { return true; - } catch (MissingResourceException e) { - return false; } + + if (map != null) { + try { + map.getObject(key); + return true; + } catch (MissingResourceException e) { + } + } + + return false; } /** - * Get the value for the given key if it exists in the internal map. + * Get the value for the given key if it exists in the internal map, or NULL + * if not. * * @param key * the key to check for * - * @return true if it does + * @return the value, or NULL */ protected String getString(String key) { - if (containsKey(key)) { - try { - // Note: it is also possible to fix the borked charset issue - // with a custom ResourceBundle#Control class, but this one, - // while a workaround, depend less upon the JRE classes, which - // may change - return new String(map.getString(key).getBytes("ISO-8859-1"), - "UTF-8"); - } catch (UnsupportedEncodingException e) { - // Those 2 encodings are always supported - e.printStackTrace(); - } + if (changeMap.containsKey(key)) { + return changeMap.get(key); + } + + if (map != null && containsKey(key)) { + return map.getString(key); } return null; } + /** + * Set the value for this key, in the change map (it is kept in memory, not + * yet on disk). + * + * @param key + * the key + * @param value + * the associated value + */ + protected void setString(String key, String value) { + changeMap.put(key, value); + } + /** * Return formated, display-able information from the {@link Meta} field * given. Each line will always starts with a "#" character. @@ -380,7 +512,7 @@ public class Bundle> { value = ""; } - String[] lines = value.replaceAll("\\\t", "\\\\\\t").split("\n"); + String[] lines = value.replaceAll("\t", "\\\\\\t").split("\n"); for (int i = 0; i < lines.length; i++) { writer.write(lines[i]); if (i < lines.length - 1) { @@ -406,18 +538,23 @@ public class Bundle> { } /** - * Change the currently used bundle. + * Change the currently used bundle, and reset all changes. * * @param name * the name of the bundle to load * @param locale * the {@link Locale} to use + * @param resetToDefault + * reset to the default configuration (do not look into the + * possible user configuration files, only take the original + * configuration) */ - protected void setBundle(Enum name, Locale locale) { + protected void setBundle(Enum name, Locale locale, boolean resetToDefault) { map = null; + changeMap.clear(); String dir = Bundles.getDirectory(); - if (dir != null) { + if (!resetToDefault && dir != null) { try { File file = getPropertyFile(dir, name.name(), locale); if (file != null) { @@ -431,8 +568,47 @@ public class Bundle> { } if (map == null) { - map = ResourceBundle.getBundle(type.getPackage().getName() + "." - + name.name(), locale); + try { + map = ResourceBundle.getBundle(type.getPackage().getName() + + "." + name.name(), locale, + new FixedResourceBundleControl()); + } catch (Exception e) { + // We have no bundle for this Bundle + map = null; + } + } + } + + /** + * Take a snapshot of the changes in memory in this {@link Bundle} made by + * the "set" methods ( {@link Bundle#setString(Enum, String)}...) at the + * current time. + * + * @return a snapshot to use with {@link Bundle#restoreChanges(Object)} + */ + protected Object takeChangesSnapshot() { + return new HashMap(changeMap); + } + + /** + * Restore a snapshot taken with {@link Bundle}, or reset the current + * changes if the snapshot is NULL. + * + * @param snap + * the snapshot or NULL + */ + @SuppressWarnings("unchecked") + protected void restoreChanges(Object snap) { + if (snap == null) { + changeMap.clear(); + } else { + if (snap instanceof Map) { + changeMap = (Map) snap; + } else { + throw new Error( + "Restoring changes in a Bundle must be done on a changes snapshot, " + + "or NULL to discard current changes"); + } } }