From 598196006967b6ea4da21e7236fa21f51a9af12b Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Sun, 26 Apr 2020 01:39:24 +0200 Subject: [PATCH] move authrosGrouped to ResultList, add tagsGrouped --- library/BasicLibrary.java | 208 +++---------------------------- library/MetaResultList.java | 237 +++++++++++++++++++++++++++++++++++- 2 files changed, 249 insertions(+), 196 deletions(-) diff --git a/library/BasicLibrary.java b/library/BasicLibrary.java index a754c00..82f3fa2 100644 --- a/library/BasicLibrary.java +++ b/library/BasicLibrary.java @@ -378,213 +378,38 @@ abstract public class BasicLibrary { } /** - * List all the known types (sources) of stories. - * - * @return the sources - * - * @throws IOException - * in case of IOException + * @deprecated please use {@link BasicLibrary#getList()} and + * {@link MetaResultList#getSources()} instead. */ + @Deprecated public List getSources() throws IOException { - List list = new ArrayList(); - for (MetaData meta : getMetas(null)) { - String storySource = meta.getSource(); - if (!list.contains(storySource)) { - list.add(storySource); - } - } - - Collections.sort(list); - return list; + return getList().getSources(); } /** - * 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: - *

    - *
  • : empty, so source is "Source_1"
  • - *
  • a: empty, so source is "Source_1/a"
  • - *
  • b: empty, so source is "Source_1/b"
  • - *
- * - * @return the grouped list - * - * @throws IOException - * in case of IOException + * @deprecated please use {@link BasicLibrary#getList()} and + * {@link MetaResultList#getSourcesGrouped()} instead. */ + @Deprecated 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; + return getList().getSourcesGrouped(); } /** - * List all the known authors of stories. - * - * @return the authors - * - * @throws IOException - * in case of IOException + * @deprecated please use {@link BasicLibrary#getList()} and + * {@link MetaResultList#getAuthors()} instead. */ + @Deprecated public List getAuthors() throws IOException { - List list = new ArrayList(); - for (MetaData meta : getMetas(null)) { - String storyAuthor = meta.getAuthor(); - if (!list.contains(storyAuthor)) { - list.add(storyAuthor); - } - } - - Collections.sort(list); - return list; + return getList().getAuthors(); } /** - * Return the list of authors, grouped by starting letter(s) if needed. - *

- * If the number of author 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 authors 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 + * @deprecated please use {@link BasicLibrary#getList()} and + * {@link MetaResultList#getAuthorsGrouped()} instead. */ public Map> getAuthorsGrouped() throws IOException { - int MAX = 20; - - Map> groups = new TreeMap>(); - List authors = getAuthors(); - - // If all authors fit the max, just report them as is - if (authors.size() <= MAX) { - groups.put("", authors); - return groups; - } - - // Create groups A to Z, which can be empty here - for (char car = 'A'; car <= 'Z'; car++) { - groups.put(Character.toString(car), getAuthorsGroup(authors, 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("*", getAuthorsGroup(authors, '*')); - groups.put("0-9", getAuthorsGroup(authors, '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 authors - * 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 getAuthorsGroup(List authors, char car) { - List accepted = new ArrayList(); - for (String author : authors) { - char first = '*'; - for (int i = 0; first == '*' && i < author.length(); i++) { - String san = StringUtils.sanitize(author, 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(author); - } - } - - return accepted; + return getList().getAuthorsGrouped(); } /** @@ -638,8 +463,7 @@ abstract public class BasicLibrary { * @throws IOException * in case of IOException */ - public Story getStory(String luid, Progress pg) - throws IOException { + public Story getStory(String luid, Progress pg) throws IOException { Progress pgMetas = new Progress(); Progress pgStory = new Progress(); if (pg != null) { diff --git a/library/MetaResultList.java b/library/MetaResultList.java index b5f3312..0903740 100644 --- a/library/MetaResultList.java +++ b/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: + *

    + *
  • : empty, so source is "Source_1"
  • + *
  • a: empty, so source is "Source_1/a"
  • + *
  • b: empty, so source is "Source_1/b"
  • + *
+ * + * @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. * -- 2.27.0