ConfigItem: add all types except LOCALE (array still not working)
[fanfix.git] / src / be / nikiroo / utils / resources / MetaInfo.java
index 3a6e71ae1571469a421c216761ae7208b98ff675..d95e98c986a0e53266bbd203f95efa90066a7580 100644 (file)
@@ -1,7 +1,11 @@
 package be.nikiroo.utils.resources;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
 
 import be.nikiroo.utils.resources.Meta.Format;
 
@@ -14,14 +18,16 @@ import be.nikiroo.utils.resources.Meta.Format;
  * @param <E>
  *            the type of {@link Bundle} to edit
  */
-public class MetaInfo<E extends Enum<E>> {
+public class MetaInfo<E extends Enum<E>> implements Iterable<MetaInfo<E>> {
        private final Bundle<E> bundle;
        private final E id;
 
        private Meta meta;
+       private List<MetaInfo<E>> children = new ArrayList<MetaInfo<E>>();
 
        private String value;
-       private List<Runnable> reloadListeners = new ArrayList<Runnable>();
+       private List<Runnable> reloadedListeners = new ArrayList<Runnable>();
+       private List<Runnable> saveListeners = new ArrayList<Runnable>();
 
        private String name;
        private String description;
@@ -49,8 +55,14 @@ public class MetaInfo<E extends Enum<E>> {
 
                if (description == null) {
                        description = meta.description();
+                       if (description == null) {
+                               description = "";
+                       }
                        if (meta.info() != null && !meta.info().isEmpty()) {
-                               description += "\n" + meta.info();
+                               if (!description.isEmpty()) {
+                                       description += "\n\n";
+                               }
+                               description += meta.info();
                        }
                }
 
@@ -90,6 +102,16 @@ public class MetaInfo<E extends Enum<E>> {
                return meta.format();
        }
 
+       // for ComboBox, this is mostly a suggestion
+       public String[] getAllowedValues() {
+               return meta.list();
+       }
+
+       // TODO: use it!
+       public boolean isArray() {
+               return meta.array();
+       }
+
        /**
         * The value stored by this item, as a {@link String}.
         * 
@@ -178,7 +200,7 @@ public class MetaInfo<E extends Enum<E>> {
         */
        public void reload() {
                value = bundle.getString(id);
-               for (Runnable listener : reloadListeners) {
+               for (Runnable listener : reloadedListeners) {
                        try {
                                listener.run();
                        } catch (Exception e) {
@@ -188,17 +210,40 @@ public class MetaInfo<E extends Enum<E>> {
                }
        }
 
-       public void addReloadListener(Runnable listener) {
-               reloadListeners.add(listener);
+       // listeners will be called AFTER reload
+       public void addReloadedListener(Runnable listener) {
+               reloadedListeners.add(listener);
        }
 
        /**
         * Save the current value to the {@link Bundle}.
         */
        public void save() {
+               for (Runnable listener : saveListeners) {
+                       try {
+                               listener.run();
+                       } catch (Exception e) {
+                               // TODO: error management?
+                               e.printStackTrace();
+                       }
+               }
                bundle.setString(id, value);
        }
 
+       // listeners will be called BEFORE save
+       public void addSaveListener(Runnable listener) {
+               saveListeners.add(listener);
+       }
+
+       @Override
+       public Iterator<MetaInfo<E>> iterator() {
+               return children.iterator();
+       }
+
+       public List<MetaInfo<E>> getChildren() {
+               return children;
+       }
+
        /**
         * Create a list of {@link MetaInfo}, one for each of the item in the given
         * {@link Bundle}.
@@ -222,5 +267,52 @@ public class MetaInfo<E extends Enum<E>> {
                return list;
        }
 
-       // TODO: by groups, a-là Authors/Sources
+       // TODO: multiple levels?
+       static public <E extends Enum<E>> Map<MetaInfo<E>, List<MetaInfo<E>>> getGroupedItems(
+                       Class<E> type, Bundle<E> bundle) {
+               Map<MetaInfo<E>, List<MetaInfo<E>>> map = new TreeMap<MetaInfo<E>, List<MetaInfo<E>>>();
+               Map<MetaInfo<E>, List<MetaInfo<E>>> map1 = new TreeMap<MetaInfo<E>, List<MetaInfo<E>>>();
+
+               List<MetaInfo<E>> ungrouped = new ArrayList<MetaInfo<E>>();
+               for (MetaInfo<E> info : getItems(type, bundle)) {
+                       if (info.meta.group()) {
+                               List<MetaInfo<E>> list = new ArrayList<MetaInfo<E>>();
+                               map.put(info, list);
+                               map1.put(info, list);
+                       } else {
+                               ungrouped.add(info);
+                       }
+               }
+
+               for (int i = 0; i < ungrouped.size(); i++) {
+                       MetaInfo<E> info = ungrouped.get(i);
+                       MetaInfo<E> group = findParent(info, map.keySet());
+                       if (group != null) {
+                               map.get(group).add(info);
+                               ungrouped.remove(i--);
+                       }
+               }
+
+               if (ungrouped.size() > 0) {
+                       map.put(null, ungrouped);
+               }
+
+               return map;
+       }
+
+       static private <E extends Enum<E>> MetaInfo<E> findParent(MetaInfo<E> info,
+                       Set<MetaInfo<E>> candidates) {
+               MetaInfo<E> group = null;
+               for (MetaInfo<E> pcandidate : candidates) {
+                       if (info.id.toString().startsWith(pcandidate.id.toString())) {
+                               if (group == null
+                                               || group.id.toString().length() < pcandidate.id
+                                                               .toString().length()) {
+                                       group = pcandidate;
+                               }
+                       }
+               }
+
+               return group;
+       }
 }