From 50a2aaf5b388e7d534a09bb6c20e31de6aad479b Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Fri, 24 Apr 2020 17:43:40 +0200 Subject: [PATCH] breadcrumbs panel --- .../nikiroo/fanfix_swing/gui/BooksPanel.java | 12 +-- .../fanfix_swing/gui/BreadCrumbsPanel.java | 79 +++++++++++++++++ .../fanfix_swing/gui/BrowserPanel.java | 6 +- .../nikiroo/fanfix_swing/gui/MainFrame.java | 46 ++++++++-- .../fanfix_swing/gui/PropertiesFrame.java | 2 +- .../nikiroo/fanfix_swing/gui/SearchBar.java | 2 +- .../fanfix_swing/gui/browser/BasicTab.java | 10 +-- .../gui/importer/ImporterFrame.java | 4 +- .../gui/importer/ImporterItem.java | 6 +- .../fanfix_swing/gui/utils/DataNodeBook.java | 86 +++++++++++++++++++ .../gui/utils/DataTreeAuthors.java | 33 +++++++ .../gui/utils/DataTreeSources.java | 55 ++++++++++++ .../fanfix_swing/gui/utils/DataTreeTag.java | 48 +++++++++++ 13 files changed, 361 insertions(+), 28 deletions(-) create mode 100644 src/be/nikiroo/fanfix_swing/gui/BreadCrumbsPanel.java create mode 100644 src/be/nikiroo/fanfix_swing/gui/utils/DataNodeBook.java create mode 100644 src/be/nikiroo/fanfix_swing/gui/utils/DataTreeAuthors.java create mode 100644 src/be/nikiroo/fanfix_swing/gui/utils/DataTreeSources.java create mode 100644 src/be/nikiroo/fanfix_swing/gui/utils/DataTreeTag.java diff --git a/src/be/nikiroo/fanfix_swing/gui/BooksPanel.java b/src/be/nikiroo/fanfix_swing/gui/BooksPanel.java index a2462fa5..4f169544 100644 --- a/src/be/nikiroo/fanfix_swing/gui/BooksPanel.java +++ b/src/be/nikiroo/fanfix_swing/gui/BooksPanel.java @@ -26,13 +26,13 @@ import be.nikiroo.fanfix_swing.gui.book.BookInfo; import be.nikiroo.fanfix_swing.gui.book.BookLine; import be.nikiroo.fanfix_swing.gui.book.BookPopup; import be.nikiroo.fanfix_swing.gui.book.BookPopup.Informer; -import be.nikiroo.fanfix_swing.gui.utils.DelayWorker; -import be.nikiroo.fanfix_swing.gui.utils.ListModel; -import be.nikiroo.fanfix_swing.gui.utils.ListModel.Predicate; import be.nikiroo.utils.compat.JList6; import be.nikiroo.utils.compat.ListCellRenderer6; -import be.nikiroo.fanfix_swing.gui.utils.ListenerPanel; -import be.nikiroo.fanfix_swing.gui.utils.UiHelper; +import be.nikiroo.utils.ui.DelayWorker; +import be.nikiroo.utils.ui.ListModel; +import be.nikiroo.utils.ui.ListModel.Predicate; +import be.nikiroo.utils.ui.ListenerPanel; +import be.nikiroo.utils.ui.UIUtils; public class BooksPanel extends ListenerPanel { static public final String INVALIDATE_CACHE = "invalidate_cache"; @@ -67,7 +67,7 @@ public class BooksPanel extends ListenerPanel { list = initList(); setListMode(listMode); - add(UiHelper.scroll(list), BorderLayout.CENTER); + add(UIUtils.scroll(list, false), BorderLayout.CENTER); } // null or empty -> all sources diff --git a/src/be/nikiroo/fanfix_swing/gui/BreadCrumbsPanel.java b/src/be/nikiroo/fanfix_swing/gui/BreadCrumbsPanel.java new file mode 100644 index 00000000..cae9e0d3 --- /dev/null +++ b/src/be/nikiroo/fanfix_swing/gui/BreadCrumbsPanel.java @@ -0,0 +1,79 @@ +package be.nikiroo.fanfix_swing.gui; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import be.nikiroo.fanfix.Instance; +import be.nikiroo.fanfix.library.BasicLibrary; +import be.nikiroo.fanfix_swing.gui.book.BookInfo; +import be.nikiroo.fanfix_swing.gui.book.BookInfo.Type; +import be.nikiroo.fanfix_swing.gui.utils.DataNodeBook; +import be.nikiroo.fanfix_swing.gui.utils.DataTreeAuthors; +import be.nikiroo.fanfix_swing.gui.utils.DataTreeSources; +import be.nikiroo.fanfix_swing.gui.utils.DataTreeTag; +import be.nikiroo.utils.ui.BreadCrumbsBar; +import be.nikiroo.utils.ui.DataNode; +import be.nikiroo.utils.ui.DataTree; + +public class BreadCrumbsPanel extends BreadCrumbsBar { + public BreadCrumbsPanel() { + super(new DataTree() { + @Override + protected DataNode extractData() throws IOException { + List> children = null; + + children = new DataTreeSources().loadData().getChildren(); + DataNode sources = new DataNode( + children, new DataNodeBook(Type.SOURCE, "Sources", true, + !children.isEmpty())); + children = new DataTreeAuthors().loadData().getChildren(); + DataNode authors = new DataNode( + children, new DataNodeBook(Type.AUTHOR, "Authors", true, + !children.isEmpty())); + children = new DataTreeTag().loadData().getChildren(); + DataNode tags = new DataNode( + children, new DataNodeBook(Type.TAG, "Tags", true, + !children.isEmpty())); + + return new DataNode( + Arrays.asList(sources, authors, tags), + new DataNodeBook(null, false)); + } + + @Override + protected boolean checkFilter(String filter, + DataNodeBook userData) { + return userData.toString().contains(filter.toLowerCase()); + } + }); + } + + public BookInfo getHighlight() { + DataNode node = getSelectedNode(); + + if (node != null && node.getUserData() != null) { + BasicLibrary lib = Instance.getInstance().getLibrary(); + + DataNodeBook book = node.getUserData(); + if (book.getType() != null) { + switch (book.getType()) { + case SOURCE: + return BookInfo.fromSource(lib, + book.isRoot() ? null : book.getPath()); + case AUTHOR: + return BookInfo.fromAuthor(lib, + book.isRoot() ? null : book.getPath()); + case TAG: + return BookInfo.fromTag(lib, + book.isRoot() ? null : book.getPath()); + + default: + break; + } + } + } + + return null; + } +} diff --git a/src/be/nikiroo/fanfix_swing/gui/BrowserPanel.java b/src/be/nikiroo/fanfix_swing/gui/BrowserPanel.java index 8ac78396..d526e20b 100644 --- a/src/be/nikiroo/fanfix_swing/gui/BrowserPanel.java +++ b/src/be/nikiroo/fanfix_swing/gui/BrowserPanel.java @@ -20,8 +20,8 @@ import be.nikiroo.fanfix_swing.gui.browser.AuthorTab; import be.nikiroo.fanfix_swing.gui.browser.BasicTab; import be.nikiroo.fanfix_swing.gui.browser.SourceTab; import be.nikiroo.fanfix_swing.gui.browser.TagsTab; -import be.nikiroo.fanfix_swing.gui.utils.ListenerPanel; import be.nikiroo.fanfix_swing.gui.utils.UiHelper; +import be.nikiroo.utils.ui.ListenerPanel; /** * Panel dedicated to browse the stories through different means: by authors, by @@ -158,7 +158,7 @@ public class BrowserPanel extends ListenerPanel { * Return a special "all" {@link BookInfo} of the correct type when nothing * is selected. * - * @return the {@link BookInfo} to highlight, can be NULL + * @return the {@link BookInfo} to highlight, cannot be NULL */ public BookInfo getHighlight() { String selected1 = null; @@ -182,7 +182,7 @@ public class BrowserPanel extends ListenerPanel { } // ...what? - return null; + return BookInfo.fromSource(lib, selected1); } /** diff --git a/src/be/nikiroo/fanfix_swing/gui/MainFrame.java b/src/be/nikiroo/fanfix_swing/gui/MainFrame.java index f74db0ae..7e568bee 100644 --- a/src/be/nikiroo/fanfix_swing/gui/MainFrame.java +++ b/src/be/nikiroo/fanfix_swing/gui/MainFrame.java @@ -3,15 +3,17 @@ package be.nikiroo.fanfix_swing.gui; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.List; import javax.swing.JComponent; import javax.swing.JFrame; -import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JSplitPane; +import be.nikiroo.fanfix_swing.gui.book.BookInfo; import be.nikiroo.fanfix_swing.gui.importer.ImporterFrame; import be.nikiroo.utils.Version; @@ -19,6 +21,7 @@ public class MainFrame extends JFrame { private BooksPanel books; private DetailsPanel details; private BrowserPanel browser; + private BreadCrumbsPanel goBack; private ImporterFrame importer = new ImporterFrame(); public MainFrame(boolean sidePanel, boolean detailsPanel) { @@ -26,11 +29,12 @@ public class MainFrame extends JFrame { setSize(800, 600); setJMenuBar(createMenuBar()); - sidePanel = true; - detailsPanel = true; + // TODO: setSidePanel() and setDetailsPanel(); browser = new BrowserPanel(); books = new BooksPanel(true); + details = new DetailsPanel(); + goBack = new BreadCrumbsPanel(); JComponent other = null; boolean orientationH = true; @@ -38,15 +42,14 @@ public class MainFrame extends JFrame { other = browser; } else if (sidePanel && detailsPanel) { JComponent side = browser; - details = new DetailsPanel(); other = split(side, details, false, 0.5, 1); } else if (!sidePanel && !detailsPanel) { orientationH = false; - other = new JLabel("<< Go back"); + other = goBack; + goBack.setVertical(false); } else if (!sidePanel && detailsPanel) { - JComponent goBack = new JLabel("<< Go back"); - details = new DetailsPanel(); other = split(goBack, details, false, 0.5, 1); + goBack.setVertical(true); } browser.addActionListener(new ActionListener() { @@ -58,6 +61,35 @@ public class MainFrame extends JFrame { details.setBook(browser.getHighlight()); } }); + goBack.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + BookInfo book = goBack.getHighlight(); + List sources = new ArrayList(); + List authors = new ArrayList(); + List tags = new ArrayList(); + + if (book != null && book.getMainInfo() != null) { + switch (book.getType()) { + case SOURCE: + sources.add(book.getMainInfo()); + break; + case AUTHOR: + authors.add(book.getMainInfo()); + break; + case TAG: + tags.add(book.getMainInfo()); + break; + + default: + break; + } + } + + books.loadData(sources, authors, tags); + details.setBook(book); + } + }); books.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { diff --git a/src/be/nikiroo/fanfix_swing/gui/PropertiesFrame.java b/src/be/nikiroo/fanfix_swing/gui/PropertiesFrame.java index db0654bf..915c2550 100644 --- a/src/be/nikiroo/fanfix_swing/gui/PropertiesFrame.java +++ b/src/be/nikiroo/fanfix_swing/gui/PropertiesFrame.java @@ -30,7 +30,7 @@ public class PropertiesFrame extends JFrame { setTitle(Instance.getInstance().getTransGui().getString( StringIdGui.TITLE_STORY, meta.getLuid(), meta.getTitle())); - PropertiesPane desc = new PropertiesPane(lib, meta); + PropertiesPanel desc = new PropertiesPanel(lib, meta); setSize(800, (int) desc.getPreferredSize().getHeight() + 2 * desc.getBorderThickness()); diff --git a/src/be/nikiroo/fanfix_swing/gui/SearchBar.java b/src/be/nikiroo/fanfix_swing/gui/SearchBar.java index 0be2f080..76fb2a74 100644 --- a/src/be/nikiroo/fanfix_swing/gui/SearchBar.java +++ b/src/be/nikiroo/fanfix_swing/gui/SearchBar.java @@ -11,11 +11,11 @@ import javax.swing.JButton; import javax.swing.JTextField; import javax.swing.SwingUtilities; -import be.nikiroo.fanfix_swing.gui.utils.ListenerPanel; import be.nikiroo.fanfix_swing.gui.utils.UiHelper; import be.nikiroo.fanfix_swing.images.IconGenerator; import be.nikiroo.fanfix_swing.images.IconGenerator.Icon; import be.nikiroo.fanfix_swing.images.IconGenerator.Size; +import be.nikiroo.utils.ui.ListenerPanel; /** * A generic search/filter bar. diff --git a/src/be/nikiroo/fanfix_swing/gui/browser/BasicTab.java b/src/be/nikiroo/fanfix_swing/gui/browser/BasicTab.java index a4d67518..6edb0f3f 100644 --- a/src/be/nikiroo/fanfix_swing/gui/browser/BasicTab.java +++ b/src/be/nikiroo/fanfix_swing/gui/browser/BasicTab.java @@ -22,13 +22,13 @@ import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreePath; import be.nikiroo.fanfix_swing.gui.SearchBar; -import be.nikiroo.fanfix_swing.gui.utils.ListenerPanel; -import be.nikiroo.fanfix_swing.gui.utils.TreeCellSpanner; -import be.nikiroo.fanfix_swing.gui.utils.TreeSnapshot; -import be.nikiroo.fanfix_swing.gui.utils.UiHelper; import be.nikiroo.fanfix_swing.images.IconGenerator; import be.nikiroo.fanfix_swing.images.IconGenerator.Icon; import be.nikiroo.fanfix_swing.images.IconGenerator.Size; +import be.nikiroo.utils.ui.ListenerPanel; +import be.nikiroo.utils.ui.TreeCellSpanner; +import be.nikiroo.utils.ui.TreeSnapshot; +import be.nikiroo.utils.ui.UIUtils; public abstract class BasicTab extends ListenerPanel { private int totalCount = 0; @@ -86,7 +86,7 @@ public abstract class BasicTab extends ListenerPanel { } }); - add(UiHelper.scroll(tree), BorderLayout.CENTER); + add(UIUtils.scroll(tree, false), BorderLayout.CENTER); searchBar = new SearchBar(); add(searchBar, BorderLayout.NORTH); diff --git a/src/be/nikiroo/fanfix_swing/gui/importer/ImporterFrame.java b/src/be/nikiroo/fanfix_swing/gui/importer/ImporterFrame.java index 7db93374..6c0b9134 100644 --- a/src/be/nikiroo/fanfix_swing/gui/importer/ImporterFrame.java +++ b/src/be/nikiroo/fanfix_swing/gui/importer/ImporterFrame.java @@ -23,10 +23,10 @@ import be.nikiroo.fanfix.reader.BasicReader; import be.nikiroo.fanfix.supported.BasicSupport; import be.nikiroo.fanfix_swing.Actions; import be.nikiroo.fanfix_swing.gui.SearchBar; -import be.nikiroo.fanfix_swing.gui.utils.ListModel; -import be.nikiroo.fanfix_swing.gui.utils.ListModel.Predicate; import be.nikiroo.utils.Progress; import be.nikiroo.utils.compat.JList6; +import be.nikiroo.utils.ui.ListModel; +import be.nikiroo.utils.ui.ListModel.Predicate; public class ImporterFrame extends JFrame { private ListModel data; diff --git a/src/be/nikiroo/fanfix_swing/gui/importer/ImporterItem.java b/src/be/nikiroo/fanfix_swing/gui/importer/ImporterItem.java index f3f6b042..532c5f63 100644 --- a/src/be/nikiroo/fanfix_swing/gui/importer/ImporterItem.java +++ b/src/be/nikiroo/fanfix_swing/gui/importer/ImporterItem.java @@ -13,11 +13,11 @@ import javax.swing.ListCellRenderer; import javax.swing.SwingUtilities; import be.nikiroo.fanfix_swing.gui.utils.CoverImager; -import be.nikiroo.fanfix_swing.gui.utils.ListModel; -import be.nikiroo.fanfix_swing.gui.utils.ListModel.Hoverable; -import be.nikiroo.fanfix_swing.gui.utils.ListenerPanel; import be.nikiroo.utils.Progress; import be.nikiroo.utils.Progress.ProgressListener; +import be.nikiroo.utils.ui.ListModel; +import be.nikiroo.utils.ui.ListenerPanel; +import be.nikiroo.utils.ui.ListModel.Hoverable; public class ImporterItem extends ListenerPanel implements Hoverable { static public final String CHANGE = "change"; diff --git a/src/be/nikiroo/fanfix_swing/gui/utils/DataNodeBook.java b/src/be/nikiroo/fanfix_swing/gui/utils/DataNodeBook.java new file mode 100644 index 00000000..1e26d153 --- /dev/null +++ b/src/be/nikiroo/fanfix_swing/gui/utils/DataNodeBook.java @@ -0,0 +1,86 @@ +package be.nikiroo.fanfix_swing.gui.utils; + +import be.nikiroo.fanfix_swing.gui.book.BookInfo; +import be.nikiroo.fanfix_swing.gui.book.BookInfo.Type; + +public class DataNodeBook { + private Type type; + private String subname; + private String name; + private boolean children; + private boolean root; + + private String display; + + // root node + public DataNodeBook(Type type, boolean children) { + this(type, null, null, children); + this.root = true; + } + + public DataNodeBook(Type type, String name, boolean root, + boolean children) { + this(type, name, null, children); + this.root = root; + } + + // no root, no children, empty path + public DataNodeBook(Type type, String name) { + this(type, name, null, false); + this.root = false; + } + + // name empty = main value for the group + // not root + public DataNodeBook(Type type, String name, String subname, + boolean children) { + this.type = type; + this.name = name == null ? "" : name; + this.subname = subname == null ? "" : subname; + this.children = children; + this.root = false; + } + + public BookInfo.Type getType() { + return type; + } + + public String getPath() { + String slash = ""; + if (!name.isEmpty()) { + if (children || !subname.isEmpty()) { + slash = "/"; + } + } + + return name + slash + subname; + } + + public String getName() { + return name; + } + + public String getDisplay() { + if (display != null) + return display; + + if (!subname.isEmpty()) { + return subname; + } + + return name; + } + + public void setDisplay(String display) { + this.display = display; + } + + public boolean isRoot() { + return root; + } + + @Override + public String toString() { + return getDisplay(); + } +} diff --git a/src/be/nikiroo/fanfix_swing/gui/utils/DataTreeAuthors.java b/src/be/nikiroo/fanfix_swing/gui/utils/DataTreeAuthors.java new file mode 100644 index 00000000..a46a49c5 --- /dev/null +++ b/src/be/nikiroo/fanfix_swing/gui/utils/DataTreeAuthors.java @@ -0,0 +1,33 @@ +package be.nikiroo.fanfix_swing.gui.utils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import be.nikiroo.fanfix.Instance; +import be.nikiroo.fanfix_swing.gui.book.BookInfo.Type; +import be.nikiroo.utils.ui.DataNode; +import be.nikiroo.utils.ui.DataTree; + +public class DataTreeAuthors extends DataTree { + @Override + protected boolean checkFilter(String filter, DataNodeBook userData) { + return userData.toString().toLowerCase().contains(filter.toLowerCase()); + } + + @Override + protected DataNode extractData() throws IOException { + List> nodes = new ArrayList>(); + + // TODO: getResult() -> getTagList, getAuthorList... ? + List authors = Instance.getInstance().getLibrary().getAuthors(); + for (String author : authors) { + nodes.add(new DataNode(null, + new DataNodeBook(Type.AUTHOR, author))); + } + + return new DataNode(nodes, + new DataNodeBook(Type.AUTHOR, !nodes.isEmpty())); + } +} diff --git a/src/be/nikiroo/fanfix_swing/gui/utils/DataTreeSources.java b/src/be/nikiroo/fanfix_swing/gui/utils/DataTreeSources.java new file mode 100644 index 00000000..188765ab --- /dev/null +++ b/src/be/nikiroo/fanfix_swing/gui/utils/DataTreeSources.java @@ -0,0 +1,55 @@ +package be.nikiroo.fanfix_swing.gui.utils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import be.nikiroo.fanfix.Instance; +import be.nikiroo.fanfix_swing.gui.book.BookInfo.Type; +import be.nikiroo.utils.ui.DataNode; +import be.nikiroo.utils.ui.DataTree; + +public class DataTreeSources extends DataTree { + @Override + protected boolean checkFilter(String filter, DataNodeBook userData) { + // TODO + return userData.toString().toLowerCase().contains(filter.toLowerCase()); + } + + @Override + protected DataNode extractData() throws IOException { + List> nodes = new ArrayList>(); + + Map> sourcesGrouped = Instance.getInstance() + .getLibrary().getSourcesGrouped(); + + List sources = new ArrayList(sourcesGrouped.keySet()); + sort(sources); + for (String source : sources) { + List children = sourcesGrouped.get(source); + boolean hasChildren = (children.size() > 1) || (children.size() == 1 + && !children.get(0).trim().isEmpty()); + + List> subnodes = new ArrayList>(); + if (hasChildren) { + sort(children); + for (String subSource : children) { + boolean baseSubSource = subSource.isEmpty() + && children.size() > 1; + DataNodeBook book = new DataNodeBook(Type.SOURCE, source, + subSource, false); + if (baseSubSource) + book.setDisplay("*"); + subnodes.add(new DataNode(null, book)); + } + } + + nodes.add(new DataNode(subnodes, + new DataNodeBook(Type.SOURCE, source, "", hasChildren))); + } + + return new DataNode(nodes, + new DataNodeBook(Type.SOURCE, !nodes.isEmpty())); + } +} diff --git a/src/be/nikiroo/fanfix_swing/gui/utils/DataTreeTag.java b/src/be/nikiroo/fanfix_swing/gui/utils/DataTreeTag.java new file mode 100644 index 00000000..445d2bf3 --- /dev/null +++ b/src/be/nikiroo/fanfix_swing/gui/utils/DataTreeTag.java @@ -0,0 +1,48 @@ +package be.nikiroo.fanfix_swing.gui.utils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import be.nikiroo.fanfix.Instance; +import be.nikiroo.fanfix.data.MetaData; +import be.nikiroo.fanfix.library.MetaResultList; +import be.nikiroo.fanfix_swing.gui.book.BookInfo.Type; +import be.nikiroo.utils.ui.DataNode; +import be.nikiroo.utils.ui.DataTree; + +public class DataTreeTag extends DataTree { + @Override + protected boolean checkFilter(String filter, DataNodeBook userData) { + return userData.toString().toLowerCase().contains(filter.toLowerCase()); + } + + @Override + protected DataNode extractData() throws IOException { + List> nodes = new ArrayList>(); + + List tagList = new ArrayList(); + MetaResultList metas = Instance.getInstance().getLibrary().getList(); + // TODO: getTagList, getAuthorList... ? + for (MetaData meta : metas.getMetas()) { + List tags = meta.getTags(); + if (tags != null) { + for (String tag : tags) { + if (!tagList.contains(tag)) { + tagList.add(tag); + } + } + } + } + sort(tagList); + + for (String tag : tagList) { + nodes.add(new DataNode(null, + new DataNodeBook(Type.TAG, tag))); + } + + return new DataNode(nodes, + new DataNodeBook(Type.TAG, !nodes.isEmpty())); + } +} -- 2.27.0