Merge branch 'subtree'
[fanfix.git] / src / be / nikiroo / utils / resources / MetaInfo.java
index 9f86843226136fc071e38e36df5ea62b8bd7be9e..70c6c43181bbff8f8885c1eca15a792eef03eac1 100644 (file)
@@ -27,8 +27,11 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
        private List<Runnable> saveListeners = new ArrayList<Runnable>();
 
        private String name;
+       private boolean hidden;
        private String description;
 
+       private boolean dirty;
+
        /**
         * Create a new {@link MetaInfo} from a value (without children).
         * <p>
@@ -88,6 +91,7 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
                }
 
                this.name = name;
+               this.hidden = meta.hidden();
                this.description = description;
 
                reload();
@@ -108,6 +112,16 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
        public String getName() {
                return name;
        }
+       
+       /**
+        * This item should be hidden from the user (she will still be able to
+        * modify it if she opens the file manually).
+        * 
+        * @return TRUE if it should stay hidden
+        */
+       public boolean isHidden() {
+               return hidden;
+       }
 
        /**
         * A description for this item: what it is or does, how to explain that item
@@ -139,7 +153,7 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
        /**
         * The allowed list of values that a {@link Format#FIXED_LIST} item is
         * allowed to be, or a list of suggestions for {@link Format#COMBO_LIST}
-        * items.
+        * items. Also works for {@link Format#LOCALE}.
         * <p>
         * Will always allow an empty string in addition to the rest.
         * 
@@ -157,6 +171,22 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
                return withEmpty;
        }
 
+       /**
+        * Return all the languages known by the program for this bundle.
+        * <p>
+        * This only works for {@link TransBundle}, and will return an empty list if
+        * this is not a {@link TransBundle}.
+        * 
+        * @return the known language codes
+        */
+       public List<String> getKnownLanguages() {
+               if (bundle instanceof TransBundle) {
+                       return ((TransBundle<E>) bundle).getKnownLanguages();
+               }
+
+               return new ArrayList<String>();
+       }
+
        /**
         * This item is a comma-separated list of values instead of a single value.
         * <p>
@@ -171,6 +201,42 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
                return meta.array();
        }
 
+       /**
+        * A manual flag to specify if the data 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 data 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>
@@ -187,15 +253,32 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
        /**
         * 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;
@@ -204,76 +287,120 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
        /**
         * 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);
        }
 
        /**
@@ -282,14 +409,18 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
         * <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);
        }
 
        /**
@@ -298,10 +429,15 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
         * <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);
        }
 
        /**
@@ -310,14 +446,18 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
         * 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);
        }
 
        /**
@@ -326,10 +466,15 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
         * 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);
        }
 
        /**
@@ -337,9 +482,17 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
         * 
         * @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) {
+                       this.value = BundleHelper.fromList(this.value, value, item);
+               } else {
+                       this.value = value;
+               }
        }
 
        /**
@@ -347,9 +500,13 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
         * 
         * @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);
        }
 
        /**
@@ -357,9 +514,13 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
         * 
         * @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);
        }
 
        /**
@@ -367,22 +528,30 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
         * 
         * @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);
        }
 
        /**
         * The value stored by this item, as a colour (represented here as an
         * {@link Integer}) if it represents a colour, or NULL if it doesn't.
         * <p>
-        * The returned colour value is an ARGB value.
+        * The colour value is an ARGB value.
         * 
         * @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);
        }
 
        /**
@@ -393,10 +562,13 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
         * 
         * @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);
        }
 
        /**
@@ -410,11 +582,11 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
                        value = null;
                }
 
-               for (Runnable listener : reloadedListeners) {
+               // Copy the list so we can create new listener in a listener
+               for (Runnable listener : new ArrayList<Runnable>(reloadedListeners)) {
                        try {
                                listener.run();
                        } catch (Exception e) {
-                               // TODO: error management?
                                e.printStackTrace();
                        }
                }
@@ -434,17 +606,27 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
 
        /**
         * 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() {
-               for (Runnable listener : saveListeners) {
+       public void save(boolean onlyIfDirty) {
+               // Copy the list so we can create new listener in a listener
+               for (Runnable listener : new ArrayList<Runnable>(saveListeners)) {
                        try {
                                listener.run();
                        } catch (Exception e) {
-                               // TODO: error management?
                                e.printStackTrace();
                        }
                }
-               bundle.setString(id, value);
+
+               if (!onlyIfDirty || isDirty()) {
+                       bundle.setString(id, value);
+               }
        }
 
        /**
@@ -479,6 +661,15 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
                return children;
        }
 
+       /**
+        * The number of sub-items, if any.
+        * 
+        * @return the number or 0
+        */
+       public int size() {
+               return children.size();
+       }
+
        @Override
        public Iterator<MetaInfo<E>> iterator() {
                return children.iterator();
@@ -503,8 +694,10 @@ public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
                List<MetaInfo<E>> shadow = new ArrayList<MetaInfo<E>>();
                for (E id : type.getEnumConstants()) {
                        MetaInfo<E> info = new MetaInfo<E>(type, bundle, id);
-                       list.add(info);
-                       shadow.add(info);
+                       if (!info.hidden) {
+                               list.add(info);
+                               shadow.add(info);
+                       }
                }
 
                for (int i = 0; i < list.size(); i++) {