gui: use submenus for subdirs
authorNiki Roo <niki@nikiroo.be>
Mon, 18 Mar 2019 08:08:28 +0000 (09:08 +0100)
committerNiki Roo <niki@nikiroo.be>
Mon, 18 Mar 2019 08:08:28 +0000 (09:08 +0100)
src/be/nikiroo/fanfix/library/BasicLibrary.java
src/be/nikiroo/fanfix/reader/ui/GuiReaderFrame.java

index 6dfacfbf4b8f0d5d19eabdcfe7f21d2315a2ce0e..b3b49fdbce50ec5aa6b4877af9c42b2a949e39df 100644 (file)
@@ -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").
+        * <p>
+        * Note that an empty item in the list means a non-grouped source (type) --
+        * e.g., you could have for Source_1:
+        * <ul>
+        * <li><tt></tt>: empty, so source is "Source_1"</li>
+        * <li><tt>a</tt>: empty, so source is "Source_1/a"</li>
+        * <li><tt>b</tt>: empty, so source is "Source_1/b"</li>
+        * </ul>
+        * 
+        * @return the grouped list
+        */
+       public synchronized Map<String, List<String>> getSourcesGrouped() {
+               Map<String, List<String>> map = new TreeMap<String, List<String>>();
+               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<String> list = map.get(name);
+                       if (list == null) {
+                               list = new ArrayList<String>();
+                               map.put(name, list);
+                       }
+                       list.add(subname);
+               }
+
+               return map;
+       }
+
        /**
         * List all the known authors of stories.
         * 
index f4c5eb3997cc97373788fe21c8bb2d1d3d52c061..b1ba90c9acde6cca6d23ad060eaf9526bac0a479 100644 (file)
@@ -446,26 +446,37 @@ class GuiReaderFrame extends JFrame {
                JMenu sources = new JMenu("Sources");
                sources.setMnemonic(KeyEvent.VK_S);
 
-               List<String> tt = new ArrayList<String>();
+               Map<String, List<String>> groupedSources = new HashMap<String, List<String>>();
                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<String> 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<String> values = new ArrayList<String>();
-               values.add(null);
+               Map<String, List<String>> groupedSources = new HashMap<String, List<String>>();
                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<String> 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);
                        }
                }