From 5f42f329b6d1dd0d61f49dd9947fe487c39160ee Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Sat, 16 Mar 2019 20:04:33 +0100 Subject: [PATCH] gui: separate authors into subgroups --- TODO.md | 4 +- .../nikiroo/fanfix/library/BasicLibrary.java | 111 ++++++++++++++++++ .../fanfix/reader/ui/GuiReaderFrame.java | 72 +++++++++--- 3 files changed, 166 insertions(+), 21 deletions(-) diff --git a/TODO.md b/TODO.md index e213ce5..98119e7 100644 --- a/TODO.md +++ b/TODO.md @@ -9,7 +9,7 @@ My current planning for Fanfix (but not everything appears on this list): - [x] [e-Hentai](https://e-hentai.org/) requested - [x] Find some FR comics/manga websites - [ ] Find more FR thingies -- [ ] A GUI library +- [x] A GUI library - [x] Make one - [x] Make it run when no args passed - [x] Fix the UI, it is ugly @@ -22,7 +22,7 @@ My current planning for Fanfix (but not everything appears on this list): - [x] options screen - [x] support progress events - [x] Real menus - - [ ] Store the long lists in [A-B], [BA-BB], ... + - [x] Store the long lists in [A-B], [BA-BB], ... - [ ] A TUI library - [x] Choose an output (Jexer) - [x] Implement it from --set-reader to the actual window diff --git a/src/be/nikiroo/fanfix/library/BasicLibrary.java b/src/be/nikiroo/fanfix/library/BasicLibrary.java index 29a3cf9..f6daed6 100644 --- a/src/be/nikiroo/fanfix/library/BasicLibrary.java +++ b/src/be/nikiroo/fanfix/library/BasicLibrary.java @@ -4,9 +4,11 @@ import java.io.File; import java.io.IOException; import java.net.URL; import java.net.UnknownHostException; +import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map.Entry; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.data.MetaData; @@ -17,6 +19,7 @@ import be.nikiroo.fanfix.supported.BasicSupport; import be.nikiroo.fanfix.supported.SupportType; import be.nikiroo.utils.Image; import be.nikiroo.utils.Progress; +import be.nikiroo.utils.StringUtils; /** * Manage a library of Stories: import, export, list, modify. @@ -261,6 +264,114 @@ abstract public class BasicLibrary { return list; } + /** + * 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: + *

+ * 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) + */ + public List>> getAuthorsGrouped() { + int MAX = 20; + + List>> groups = new ArrayList>>(); + List authors = getAuthors(); + + if (authors.size() <= MAX) { + groups.add(new SimpleEntry>("", authors)); + return groups; + } + + groups.add(new SimpleEntry>("*", getAuthorsGroup( + authors, '*'))); + groups.add(new SimpleEntry>("0-9", + getAuthorsGroup(authors, '0'))); + + for (char car = 'A'; car <= 'Z'; car++) { + groups.add(new SimpleEntry>(Character + .toString(car), getAuthorsGroup(authors, car))); + } + + // do NOT collapse * and [0-9] with the rest + for (int i = 2; i + 1 < groups.size(); i++) { + Entry> now = groups.get(i); + Entry> next = groups.get(i + 1); + int currentTotal = now.getValue().size() + next.getValue().size(); + if (currentTotal <= MAX) { + String key = now.getKey().charAt(0) + "-" + + next.getKey().charAt(next.getKey().length() - 1); + List all = new ArrayList(); + all.addAll(now.getValue()); + all.addAll(next.getValue()); + groups.set(i, new SimpleEntry>(key, all)); + groups.remove(i + 1); + i--; + } + } + + for (int i = 0; i < groups.size(); i++) { + if (groups.get(i).getValue().size() == 0) { + groups.remove(i); + i--; + } + } + + 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 fulfill 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; + } + /** * List all the stories in the {@link BasicLibrary}. *

diff --git a/src/be/nikiroo/fanfix/reader/ui/GuiReaderFrame.java b/src/be/nikiroo/fanfix/reader/ui/GuiReaderFrame.java index 8d3142c..d849a43 100644 --- a/src/be/nikiroo/fanfix/reader/ui/GuiReaderFrame.java +++ b/src/be/nikiroo/fanfix/reader/ui/GuiReaderFrame.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -467,27 +468,29 @@ class GuiReaderFrame extends JFrame { JMenu authors = new JMenu("Authors"); authors.setMnemonic(KeyEvent.VK_A); - List aa = new ArrayList(); - if (libOk) { - aa.addAll(reader.getLibrary().getAuthors()); - } - aa.add(0, null); - for (final String author : aa) { - JMenuItem item = new JMenuItem(author == null ? "All" - : author.isEmpty() ? "[unknown]" : author); - item.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - removeBookPanes(); - addBookPane(author, false); - refreshBooks(); - } - }); - authors.add(item); + List>> authorGroups = reader.getLibrary() + .getAuthorsGrouped(); + if (authorGroups.size() > 1) { + // Multiple groups - if (author == null || author.isEmpty()) { - authors.addSeparator(); + // null -> "All" authors special item + populateMenuAuthorList(authors, Arrays.asList((String) null)); + + for (Entry> group : authorGroups) { + JMenu thisGroup = new JMenu(group.getKey()); + populateMenuAuthorList(thisGroup, group.getValue()); + authors.add(thisGroup); + } + } else { + // Only one group + + // null -> "All" authors special item + List authorNames = new ArrayList(); + authorNames.add(null); + if (authorGroups.size() > 0) { + authorNames.addAll(authorGroups.get(0).getValue()); } + populateMenuAuthorList(authors, authorNames); } bar.add(authors); @@ -501,6 +504,37 @@ class GuiReaderFrame extends JFrame { return bar; } + /** + * Populate a list of authors as {@link JMenuItem}s into the given + * {@link JMenu}. + *

+ * Each item will select the author when clicked. + * + * @param authors + * the parent {@link JMenuItem} + * @param names + * the authors' names + */ + private void populateMenuAuthorList(JMenu authors, List names) { + for (final String name : names) { + JMenuItem item = new JMenuItem(name == null ? "All" + : name.isEmpty() ? "[unknown]" : name); + item.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + removeBookPanes(); + addBookPane(name, false); + refreshBooks(); + } + }); + authors.add(item); + + if (name == null || name.isEmpty()) { + authors.addSeparator(); + } + } + } + /** * Create the Fanfix Configuration menu item. * -- 2.27.0