X-Git-Url: http://git.nikiroo.be/?p=fanfix.git;a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Ffanfix%2Flibrary%2FMetaResultList.java;h=0903740cf9902b77ad8140b04e6a0fdb72c700db;hp=b5f3312282669624de6474dd7007e7a86c373080;hb=008b697abad5333455de13c773206495ee2b7530;hpb=4094d35262cee2bd2e41c0039b82bd0ef31041f8 diff --git a/src/be/nikiroo/fanfix/library/MetaResultList.java b/src/be/nikiroo/fanfix/library/MetaResultList.java index b5f3312..0903740 100644 --- a/src/be/nikiroo/fanfix/library/MetaResultList.java +++ b/src/be/nikiroo/fanfix/library/MetaResultList.java @@ -1,14 +1,21 @@ package be.nikiroo.fanfix.library; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; +import java.util.TreeMap; import be.nikiroo.fanfix.data.MetaData; +import be.nikiroo.utils.StringUtils; public class MetaResultList { + /** Max number of items before splitting in [A-B] etc. for eligible items */ + static private final int MAX = 20; + private List metas; // Lazy lists: @@ -42,7 +49,7 @@ public class MetaResultList { } sort(sources); } - + return sources; } @@ -66,6 +73,50 @@ public class MetaResultList { return linked; } + /** + * List all the known types (sources) of stories, grouped by directory + * ("Source_1/a" and "Source_1/b" will be grouped into "Source_1"). + *

+ * Note that an empty item in the list means a non-grouped source (type) -- + * e.g., you could have for Source_1: + *

+ * + * @return the grouped list + * + * @throws IOException + * in case of IOException + */ + public Map> getSourcesGrouped() throws IOException { + Map> map = new TreeMap>(); + for (String source : getSources()) { + String name; + String subname; + + int pos = source.indexOf('/'); + if (pos > 0 && pos < source.length() - 1) { + name = source.substring(0, pos); + subname = source.substring(pos + 1); + + } else { + name = source; + subname = ""; + } + + List list = map.get(name); + if (list == null) { + list = new ArrayList(); + map.put(name, list); + } + list.add(subname); + } + + return map; + } + public List getAuthors() { if (authors == null) { authors = new ArrayList(); @@ -75,10 +126,36 @@ public class MetaResultList { } sort(authors); } - + return authors; } + /** + * Return the list of authors, grouped by starting letter(s) if needed. + *

+ * If the number of authors is not too high, only one group with an empty + * name and all the authors will be returned. + *

+ * If not, the authors will be separated into groups: + *

    + *
  • *: any author whose name doesn't contain letters nor numbers + *
  • + *
  • 0-9: any author whose name starts with a number
  • + *
  • A-C (for instance): any author whose name starts with + * A, B or C
  • + *
+ * Note that the letters used in the groups can vary (except * and + * 0-9, which may only be present or not). + * + * @return the authors' names, grouped by letter(s) + * + * @throws IOException + * in case of IOException + */ + public Map> getAuthorsGrouped() throws IOException { + return group(getAuthors()); + } + public List getTags() { if (tags == null) { tags = new ArrayList(); @@ -90,10 +167,36 @@ public class MetaResultList { } sort(tags); } - + return tags; } + /** + * Return the list of tags, grouped by starting letter(s) if needed. + *

+ * If the number of tags is not too high, only one group with an empty name + * and all the tags will be returned. + *

+ * If not, the tags will be separated into groups: + *

    + *
  • *: any tag which name doesn't contain letters nor numbers + *
  • + *
  • 0-9: any tag which name starts with a number
  • + *
  • A-C (for instance): any tag which name starts with + * A, B or C
  • + *
+ * Note that the letters used in the groups can vary (except * and + * 0-9, which may only be present or not). + * + * @return the tags' names, grouped by letter(s) + * + * @throws IOException + * in case of IOException + */ + public Map> getTagsGrouped() throws IOException { + return group(getTags()); + } + // helper public List filter(String source, String author, String tag) { List sources = source == null ? null : Arrays.asList(source); @@ -172,7 +275,133 @@ public class MetaResultList { Collections.sort(result); return result; } - + + /** + * Return the list of values, grouped by starting letter(s) if needed. + *

+ * If the number of values is not too high, only one group with an empty + * name and all the values will be returned (see + * {@link MetaResultList#MAX}). + *

+ * If not, the values will be separated into groups: + *

    + *
  • *: any value which name doesn't contain letters nor numbers + *
  • + *
  • 0-9: any value which name starts with a number
  • + *
  • A-C (for instance): any value which name starts with + * A, B or C
  • + *
+ * Note that the letters used in the groups can vary (except * and + * 0-9, which may only be present or not). + * + * @param values + * the values to group + * + * @return the values, grouped by letter(s) + * + * @throws IOException + * in case of IOException + */ + private Map> group(List values) + throws IOException { + Map> groups = new TreeMap>(); + + // If all authors fit the max, just report them as is + if (values.size() <= MAX) { + groups.put("", values); + return groups; + } + + // Create groups A to Z, which can be empty here + for (char car = 'A'; car <= 'Z'; car++) { + groups.put(Character.toString(car), find(values, car)); + } + + // Collapse them + List keys = new ArrayList(groups.keySet()); + for (int i = 0; i + 1 < keys.size(); i++) { + String keyNow = keys.get(i); + String keyNext = keys.get(i + 1); + + List now = groups.get(keyNow); + List next = groups.get(keyNext); + + int currentTotal = now.size() + next.size(); + if (currentTotal <= MAX) { + String key = keyNow.charAt(0) + "-" + + keyNext.charAt(keyNext.length() - 1); + + List all = new ArrayList(); + all.addAll(now); + all.addAll(next); + + groups.remove(keyNow); + groups.remove(keyNext); + groups.put(key, all); + + keys.set(i, key); // set the new key instead of key(i) + keys.remove(i + 1); // remove the next, consumed key + i--; // restart at key(i) + } + } + + // Add "special" groups + groups.put("*", find(values, '*')); + groups.put("0-9", find(values, '0')); + + // Prune empty groups + keys = new ArrayList(groups.keySet()); + for (String key : keys) { + if (groups.get(key).isEmpty()) { + groups.remove(key); + } + } + + return groups; + } + + /** + * Get all the authors that start with the given character: + *
    + *
  • *: any author whose name doesn't contain letters nor numbers + *
  • + *
  • 0: any authors whose name starts with a number
  • + *
  • A (any capital latin letter): any author whose name starts + * with A
  • + *
+ * + * @param values + * the full list of authors + * @param car + * the starting character, *, 0 or a capital + * letter + * + * @return the authors that fulfil the starting letter + */ + private List find(List values, char car) { + List accepted = new ArrayList(); + for (String value : values) { + char first = '*'; + for (int i = 0; first == '*' && i < value.length(); i++) { + String san = StringUtils.sanitize(value, true, true); + char c = san.charAt(i); + if (c >= '0' && c <= '9') { + first = '0'; + } else if (c >= 'a' && c <= 'z') { + first = (char) (c - 'a' + 'A'); + } else if (c >= 'A' && c <= 'Z') { + first = c; + } + } + + if (first == car) { + accepted.add(value); + } + } + + return accepted; + } + /** * Sort the given {@link String} values, ignoring case. *