X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Ffanfix%2Freader%2Fui%2FGuiReaderSearchFrame.java;h=def9fc6f80c9ff7e4f5e5e2f1c55a4faea085680;hb=1387a30ab59dbf4071f2c5e5e0e08ca98c75b726;hp=dcbf92740586466635177aa0fb781589f068a816;hpb=741e846789c07ef6ddbfb0e9de1c7f4664d41ad5;p=nikiroo-utils.git diff --git a/src/be/nikiroo/fanfix/reader/ui/GuiReaderSearchFrame.java b/src/be/nikiroo/fanfix/reader/ui/GuiReaderSearchFrame.java index dcbf927..def9fc6 100644 --- a/src/be/nikiroo/fanfix/reader/ui/GuiReaderSearchFrame.java +++ b/src/be/nikiroo/fanfix/reader/ui/GuiReaderSearchFrame.java @@ -1,27 +1,19 @@ package be.nikiroo.fanfix.reader.ui; import java.awt.BorderLayout; -import java.awt.Color; import java.awt.Component; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; -import javax.swing.BoxLayout; -import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; -import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; -import javax.swing.JTabbedPane; -import javax.swing.JTextField; -import javax.swing.ListCellRenderer; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.data.MetaData; @@ -42,19 +34,11 @@ public class GuiReaderSearchFrame extends JFrame { private static final long serialVersionUID = 1L; private List supportTypes; - private SupportType supportType; - private boolean searchByTags; - private String keywords; - private int page; - private int maxPage; - - private JPanel tagBars; - private List combos; private JComboBox comboSupportTypes; - private JTabbedPane searchTabs; - private JTextField keywordsField; - private JButton submitKeywords; + private ActionListener comboSupportTypesListener; + private GuiReaderSearchByPanel searchPanel; + private GuiReaderNavBar navbar; private boolean seeWordcount; private GuiReaderGroup books; @@ -64,38 +48,80 @@ public class GuiReaderSearchFrame extends JFrame { setLayout(new BorderLayout()); setSize(800, 600); - page = 1; // TODO - maxPage = -1; - searchByTags = false; - supportTypes = new ArrayList(); + supportTypes.add(null); for (SupportType type : SupportType.values()) { if (BasicSearchable.getSearchable(type) != null) { supportTypes.add(type); } } - supportType = supportTypes.isEmpty() ? null : supportTypes.get(0); comboSupportTypes = new JComboBox( supportTypes.toArray(new SupportType[] {})); - comboSupportTypes.addActionListener(new ActionListener() { + + comboSupportTypesListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - updateSupportType((SupportType) comboSupportTypes - .getSelectedItem()); + final SupportType support = (SupportType) comboSupportTypes + .getSelectedItem(); + setWaiting(true); + new Thread(new Runnable() { + @Override + public void run() { + try { + updateSupportType(support); + } finally { + setWaiting(false); + } + } + }).start(); } - }); + }; + comboSupportTypes.addActionListener(comboSupportTypesListener); + JPanel searchSites = new JPanel(new BorderLayout()); searchSites.add(comboSupportTypes, BorderLayout.CENTER); searchSites.add(new JLabel(" " + "Website : "), BorderLayout.WEST); - searchTabs = new JTabbedPane(); - searchTabs.addTab("By name", createByNameSearchPanel()); - searchTabs.addTab("By tags", createByTagSearchPanel()); + searchPanel = new GuiReaderSearchByPanel( + new GuiReaderSearchByPanel.Waitable() { + @Override + public void setWaiting(boolean waiting) { + GuiReaderSearchFrame.this.setWaiting(waiting); + } + + @Override + public void fireEvent() { + updatePages(searchPanel.getPage(), + searchPanel.getMaxPage()); + List infos = new ArrayList(); + for (MetaData meta : searchPanel.getStories()) { + infos.add(GuiReaderBookInfo.fromMeta(meta)); + } + + int page = searchPanel.getPage(); + if (page <= 0) { + navbar.setMin(1); + navbar.setMax(1); + } else { + int max = searchPanel.getMaxPage(); + navbar.setMin(1); + navbar.setMax(max); + navbar.setIndex(page); + } + updateBooks(infos); + + // ! 1-based index ! + int item = searchPanel.getStoryItem(); + if (item > 0 && item <= books.getBooksCount()) { + books.setSelectedBook(item - 1, false); + } + } + }); JPanel top = new JPanel(new BorderLayout()); top.add(searchSites, BorderLayout.NORTH); - top.add(searchTabs, BorderLayout.CENTER); + top.add(searchPanel, BorderLayout.CENTER); add(top, BorderLayout.NORTH); @@ -120,407 +146,160 @@ public class GuiReaderSearchFrame extends JFrame { scroll.getVerticalScrollBar().setUnitIncrement(16); add(scroll, BorderLayout.CENTER); - updateTags(null); - } - - private JPanel createByNameSearchPanel() { - JPanel byName = new JPanel(new BorderLayout()); - - keywordsField = new JTextField(); - byName.add(keywordsField, BorderLayout.CENTER); + navbar = new GuiReaderNavBar(-1, -1) { + private static final long serialVersionUID = 1L; - submitKeywords = new JButton("Search"); - byName.add(submitKeywords, BorderLayout.EAST); - - // TODO: ENTER -> search + @Override + protected String computeLabel(int index, int min, int max) { + if (index <= 0) { + return ""; + } + return super.computeLabel(index, min, max); + } + }; - submitKeywords.addActionListener(new ActionListener() { + navbar.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - search(supportType, keywordsField.getText(), page, 0); + searchPanel.setPage(navbar.getIndex()); } }); - return byName; - } - - private JPanel createByTagSearchPanel() { - combos = new ArrayList(); - - JPanel byTag = new JPanel(); - tagBars = new JPanel(); - tagBars.setLayout(new BoxLayout(tagBars, BoxLayout.Y_AXIS)); - byTag.add(tagBars, BorderLayout.NORTH); - - return byTag; + add(navbar, BorderLayout.SOUTH); } - private void updateSupportType(SupportType supportType) { - if (supportType != this.supportType) { - this.supportType = supportType; - comboSupportTypes.setSelectedItem(supportType); - books.clear(); - updateTags(null); - } - } - - private void updateSearchBy(final boolean byTag) { - if (byTag != this.searchByTags) { - inUi(new Runnable() { - @Override - public void run() { - if (!byTag) { - searchTabs.setSelectedIndex(0); - } else { - searchTabs.setSelectedIndex(1); - } - } - }); - } - } - - private void updatePages(final int page, final Integer maxPage) { + /** + * Update the {@link SupportType} currently displayed to the user. + *

+ * Will also cause a search for the new base tags of the given support if + * not NULL. + *

+ * This operation can be long and should be run outside the UI thread. + * + * @param supportType + * the new {@link SupportType} + */ + private void updateSupportType(final SupportType supportType) { inUi(new Runnable() { @Override public void run() { - GuiReaderSearchFrame.this.page = page; - GuiReaderSearchFrame.this.maxPage = maxPage; - // TODO: gui - System.out.println("page: " + page); - System.out.println("max page: " + maxPage); + books.clear(); + + comboSupportTypes + .removeActionListener(comboSupportTypesListener); + comboSupportTypes.setSelectedItem(supportType); + comboSupportTypes.addActionListener(comboSupportTypesListener); } }); - } - // cannot be NULL - private void updateKeywords(final String keywords) { - if (!keywords.equals(this.keywords)) { - inUi(new Runnable() { - @Override - public void run() { - GuiReaderSearchFrame.this.keywords = keywords; - keywordsField.setText(keywords); - } - }); - } + searchPanel.setSupportType(supportType); } - // update and reset the tagsbar - // can be NULL, for base tags - private void updateTags(final SearchableTag tag) { - final List parents = new ArrayList(); - SearchableTag parent = (tag == null) ? null : tag; - while (parent != null) { - parents.add(parent); - parent = parent.getParent(); - } - + /** + * Update the pages and the lined buttons currently displayed on screen. + *

+ * Those are the same pages and maximum pages used by + * {@link GuiReaderSearchByPanel#search(String, int, int)} and + * {@link GuiReaderSearchByPanel#searchTag(SearchableTag, int, int)}. + * + * @param page + * the current page of results + * @param maxPage + * the maximum number of pages of results + */ + private void updatePages(final int page, final int maxPage) { inUi(new Runnable() { @Override public void run() { - tagBars.invalidate(); - tagBars.removeAll(); - - // TODO: Slow UI - // TODO: select the right one - try { - SearchableTag selectedChild = parents.isEmpty() ? null - : parents.get(parents.size() - 1); - addTagBar(BasicSearchable.getSearchable(supportType) - .getTags(), selectedChild); - } catch (IOException e) { - error(e); - } - - for (int i = parents.size() - 1; i >= 0; i--) { - SearchableTag selectedChild = null; - if (i > 0) { - selectedChild = parents.get(i - 1); - } - SearchableTag parent = parents.get(i); - addTagBar(parent.getChildren(), selectedChild); + if (maxPage >= 1) { + navbar.setMin(1); + navbar.setMax(maxPage); + navbar.setIndex(page); + } else { + navbar.setMin(-1); + navbar.setMax(-1); } - - tagBars.validate(); } }); } + /** + * Update the currently displayed books. + * + * @param infos + * the new books + */ private void updateBooks(final List infos) { - setWaitingScreen(true); inUi(new Runnable() { @Override public void run() { books.refreshBooks(infos, seeWordcount); - setWaitingScreen(false); - } - }); - } - - private void addTagBar(List tags, - final SearchableTag selected) { - tags.add(0, null); - - final int comboIndex = combos.size(); - - final JComboBox combo = new JComboBox( - tags.toArray(new SearchableTag[] {})); - combo.setSelectedItem(selected); - - final ListCellRenderer basic = combo.getRenderer(); - - combo.setRenderer(new ListCellRenderer() { - @Override - public Component getListCellRendererComponent(JList list, - Object value, int index, boolean isSelected, - boolean cellHasFocus) { - - Object displayValue = value; - if (value instanceof SearchableTag) { - displayValue = ((SearchableTag) value).getName(); - } else { - displayValue = "Select a tag..."; - cellHasFocus = false; - isSelected = false; - } - - Component rep = basic.getListCellRendererComponent(list, - displayValue, index, isSelected, cellHasFocus); - - if (value == null) { - rep.setForeground(Color.GRAY); - } - - return rep; - } - }); - - combo.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - final SearchableTag tag = (SearchableTag) combo - .getSelectedItem(); - if (tag != null) { - while (comboIndex + 1 < combos.size()) { - JComboBox combo = combos.remove(comboIndex + 1); - tagBars.remove(combo); - } - - addTagBar(tag, new Runnable() { - @Override - public void run() { - // TODO: slow ui - SearchableTag tag = ((SearchableTag) combo - .getSelectedItem()); - if (tag != null && tag.isLeaf()) { - BasicSearchable searchable = BasicSearchable - .getSearchable(supportType); - List metas = new ArrayList(); - try { - metas = searchable.search(tag, 1); - search(metas, 1, - searchable.searchPages(tag), 0); - } catch (IOException e) { - error(e); - } - } - - setWaitingScreen(false); - } - }); - } } }); - - combos.add(combo); - tagBars.add(combo); - } - - // async, add children of tag, NULL = base tags - private void addTagBar(final SearchableTag tag, final Runnable inUi) { - new Thread(new Runnable() { - @Override - public void run() { - BasicSearchable searchable = BasicSearchable - .getSearchable(supportType); - - List children = new ArrayList(); - if (tag == null) { - try { - List baseTags = searchable.getTags(); - children = baseTags; - } catch (IOException e) { - error(e); - } - } else { - try { - searchable.fillTag(tag); - } catch (IOException e) { - error(e); - } - - if (!tag.isLeaf()) { - children = tag.getChildren(); - } else { - children = null; - } - } - - final List fchildren = children; - inUi(new Runnable() { - @Override - public void run() { - if (fchildren != null) { - addTagBar(fchildren, tag); - } - - if (inUi != null) { - inUi.run(); - } - } - }); - } - }).start(); } - // item 0 = no selection, else = default selection + /** + * Search for the given terms on the currently selected searchable. This + * will update the displayed books if needed. + *

+ * This operation is asynchronous. + * + * @param keywords + * the keywords to search for + * @param page + * the page of results to load + * @param item + * the item to select (or 0 for none by default) + */ public void search(final SupportType searchOn, final String keywords, final int page, final int item) { - - setWaitingScreen(true); - - updateSupportType(searchOn); - updateSearchBy(false); - updateKeywords(keywords); - updatePages(page, maxPage); - + setWaiting(true); new Thread(new Runnable() { @Override public void run() { - BasicSearchable search = BasicSearchable - .getSearchable(searchOn); - - int maxPage = -1; try { - maxPage = search.searchPages(keywords); - } catch (IOException e) { - error(e); + updateSupportType(searchOn); + searchPanel.search(keywords, page, item); + } finally { + setWaiting(false); } - - if (page <= 0) { - updateBooks(new ArrayList()); - updatePages(0, maxPage); - } else { - List results; - try { - results = search.search(keywords, page); - } catch (IOException e) { - error(e); - results = new ArrayList(); - } - - search(results, page, maxPage, item); - - // ! 1-based index ! - if (item > 0 && item <= books.getBooksCount()) { - // TODO: "click" on item ITEM - } - } - - setWaitingScreen(false); } }).start(); } - // tag: null = base tags + /** + * Search for the given tag on the currently selected searchable. This will + * update the displayed books if needed. + *

+ * If the tag contains children tags, those will be displayed so you can + * select them; if the tag is a leaf tag, the linked stories will be + * displayed. + *

+ * This operation is asynchronous. + * + * @param tag + * the tag to search for, or NULL for base tags + * @param page + * the page of results to load + * @param item + * the item to select (or 0 for none by default) + */ public void searchTag(final SupportType searchOn, final int page, final int item, final SearchableTag tag) { - - setWaitingScreen(true); - - updateSupportType(searchOn); - updateSearchBy(true); - updateTags(tag); - updatePages(page, maxPage); - + setWaiting(true); new Thread(new Runnable() { @Override public void run() { - BasicSearchable search = BasicSearchable - .getSearchable(searchOn); - - if (tag != null) { - try { - search.fillTag(tag); - } catch (IOException e) { - error(e); - } - - int maxPage = 0; - try { - maxPage = search.searchPages(tag); - } catch (IOException e) { - error(e); - } - - updatePages(page, maxPage); - - if (page > 0) { - List metas = new ArrayList(); - - if (tag.isLeaf()) { - try { - metas = search.search(tag, page); - } catch (IOException e) { - error(e); - } - } else { - List subtags = tag.getChildren(); - if (item > 0 && item <= subtags.size()) { - SearchableTag subtag = subtags.get(item - 1); - try { - metas = search.search(subtag, page); - maxPage = subtag.getPages(); - } catch (IOException e) { - error(e); - } - } - } - - updatePages(page, maxPage); - search(metas, page, maxPage, item); - } + try { + updateSupportType(searchOn); + searchPanel.searchTag(tag, page, item); + } finally { + setWaiting(false); } - - setWaitingScreen(false); } }).start(); } - // item 0 = no selection, else = default selection - public void search(final List results, final int page, - final int maxPage, final int item) { - - updatePages(page, maxPage); - - if (page <= 0) { - updateBooks(new ArrayList()); - updatePages(0, maxPage); - } else { - List infos = new ArrayList(); - for (MetaData meta : results) { - infos.add(GuiReaderBookInfo.fromMeta(meta)); - } - - updateBooks(infos); - - // ! 1-based index ! - if (item > 0 && item <= books.getBooksCount()) { - // TODO: "click" on item ITEM - } - } - } - /** * Process the given action in the main Swing UI thread. *

@@ -546,21 +325,55 @@ public class GuiReaderSearchFrame extends JFrame { } } + /** + * An error occurred, inform the user and/or log the error. + * + * @param e + * the error + */ static void error(Exception e) { - Instance.getTraceHandler().error(e); + Instance.getInstance().getTraceHandler().error(e); } + /** + * An error occurred, inform the user and/or log the error. + * + * @param e + * the error message + */ static void error(String e) { - Instance.getTraceHandler().error(e); + Instance.getInstance().getTraceHandler().error(e); } - - private void setWaitingScreen(final boolean waiting) { + + /** + * Enables or disables this component, depending on the value of the + * parameter b. An enabled component can respond to user input + * and generate events. Components are enabled initially by default. + *

+ * Disabling this component will also affect its children. + * + * @param b + * If true, this component is enabled; otherwise + * this component is disabled + */ + @Override + public void setEnabled(boolean b) { + super.setEnabled(b); + books.setEnabled(b); + searchPanel.setEnabled(b); + } + + /** + * Set the item in wait mode, blocking it from accepting UI input. + * + * @param waiting + * TRUE for wait more, FALSE to restore normal mode + */ + private void setWaiting(final boolean waiting) { inUi(new Runnable() { @Override public void run() { GuiReaderSearchFrame.this.setEnabled(!waiting); - books.setEnabled(!waiting); - submitKeywords.setEnabled(!waiting); } }); }