From c1b93db3213970c86b766c92a0b0d546c9d1c2ae Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Mon, 18 Mar 2019 09:08:28 +0100 Subject: [PATCH] gui: use submenus for subdirs --- .../nikiroo/fanfix/library/BasicLibrary.java | 43 ++++++++ .../fanfix/reader/ui/GuiReaderFrame.java | 102 +++++++++++++----- 2 files changed, 118 insertions(+), 27 deletions(-) diff --git a/src/be/nikiroo/fanfix/library/BasicLibrary.java b/src/be/nikiroo/fanfix/library/BasicLibrary.java index 6dfacfbf..b3b49fdb 100644 --- a/src/be/nikiroo/fanfix/library/BasicLibrary.java +++ b/src/be/nikiroo/fanfix/library/BasicLibrary.java @@ -8,7 +8,9 @@ import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.TreeMap; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.data.MetaData; @@ -246,6 +248,47 @@ abstract public class BasicLibrary { return list; } + /** + * 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 + */ + public synchronized Map> getSourcesGrouped() { + 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; + } + /** * List all the known authors of stories. * diff --git a/src/be/nikiroo/fanfix/reader/ui/GuiReaderFrame.java b/src/be/nikiroo/fanfix/reader/ui/GuiReaderFrame.java index f4c5eb39..b1ba90c9 100644 --- a/src/be/nikiroo/fanfix/reader/ui/GuiReaderFrame.java +++ b/src/be/nikiroo/fanfix/reader/ui/GuiReaderFrame.java @@ -446,26 +446,37 @@ class GuiReaderFrame extends JFrame { JMenu sources = new JMenu("Sources"); sources.setMnemonic(KeyEvent.VK_S); - List tt = new ArrayList(); + Map> groupedSources = new HashMap>(); if (libOk) { - tt.addAll(reader.getLibrary().getSources()); + groupedSources = reader.getLibrary().getSourcesGrouped(); } - tt.add(0, null); - for (final String type : tt) { - JMenuItem item = new JMenuItem(type == null ? "All" : type); - item.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - removeBookPanes(); - addBookPane(type, true); - refreshBooks(); - } - }); - sources.add(item); + JMenuItem item = new JMenuItem("All"); + item.addActionListener(getActionOpenSource(null)); + sources.add(item); + sources.addSeparator(); + + for (final String type : groupedSources.keySet()) { + List list = groupedSources.get(type); + if (list.size() == 1 && list.get(0).isEmpty()) { + item = new JMenuItem(type); + item.addActionListener(getActionOpenSource(type)); + sources.add(item); + } else { + JMenu dir = new JMenu(type); + for (String sub : list) { + // " " instead of "" for the visual height + String itemName = sub.isEmpty() ? " " : sub; + String actualType = type; + if (!sub.isEmpty()) { + actualType += "/" + sub; + } - if (type == null) { - sources.addSeparator(); + item = new JMenuItem(itemName); + item.addActionListener(getActionOpenSource(actualType)); + dir.add(item); + } + sources.add(dir); } } @@ -510,6 +521,26 @@ class GuiReaderFrame extends JFrame { return bar; } + /** + * Return an {@link ActionListener} that will set the given source (type) as + * the selected/displayed one. + * + * @param type + * the type (source) to select + * + * @return the {@link ActionListener} + */ + private ActionListener getActionOpenSource(final String type) { + return new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + removeBookPanes(); + addBookPane(type, true); + refreshBooks(); + } + }; + } + /** * Populate a list of authors as {@link JMenuItem}s into the given * {@link JMenu}. @@ -725,24 +756,41 @@ class GuiReaderFrame extends JFrame { * @return the item */ private JMenuItem createMenuItemMoveTo(boolean libOk) { - JMenuItem changeTo = new JMenu("Move to"); + JMenu changeTo = new JMenu("Move to"); changeTo.setMnemonic(KeyEvent.VK_M); - List values = new ArrayList(); - values.add(null); + Map> groupedSources = new HashMap>(); if (libOk) { - values.addAll(reader.getLibrary().getSources()); + groupedSources = reader.getLibrary().getSourcesGrouped(); } - for (String value : values) { - JMenuItem item = new JMenuItem(value == null ? "New type..." - : value); + JMenuItem item = new JMenuItem("New type..."); + item.addActionListener(createMoveAction("SOURCE", null)); + changeTo.add(item); + changeTo.addSeparator(); - item.addActionListener(createMoveAction("SOURCE", value)); + for (final String type : groupedSources.keySet()) { + List list = groupedSources.get(type); + if (list.size() == 1 && list.get(0).isEmpty()) { + item = new JMenuItem(type); + item.addActionListener(createMoveAction("SOURCE", type)); + changeTo.add(item); + } else { + JMenu dir = new JMenu(type); + for (String sub : list) { + // " " instead of "" for the visual height + String itemName = sub.isEmpty() ? " " : sub; + String actualType = type; + if (!sub.isEmpty()) { + actualType += "/" + sub; + } - changeTo.add(item); - if (value == null) { - ((JMenu) changeTo).addSeparator(); + item = new JMenuItem(itemName); + item.addActionListener(createMoveAction("SOURCE", + actualType)); + dir.add(item); + } + changeTo.add(dir); } } -- 2.27.0