* @param index
* the index of the book to select, can be outside the bounds
* (either all the items will be unselected or the first or last
- * book will then be selected, see <tt>forceRange>/tt>)
+ * book will then be selected, see <tt>forceRange></tt>)
* @param forceRange
* TRUE to constraint the index to the first/last element, FALSE
* to unselect when outside the range
import javax.swing.JTextField;
import be.nikiroo.fanfix.data.MetaData;
+import be.nikiroo.fanfix.reader.ui.GuiReaderSearchByPanel.Waitable;
import be.nikiroo.fanfix.searchable.BasicSearchable;
/**
private List<MetaData> stories = new ArrayList<MetaData>();
private int storyItem;
- public GuiReaderSearchByNamePanel(final Runnable fireEvent) {
+ public GuiReaderSearchByNamePanel(final Waitable waitable) {
super(new BorderLayout());
keywordsField = new JTextField();
submitKeywords = new JButton("Search");
add(submitKeywords, BorderLayout.EAST);
+ // should be done out of UI
+ final Runnable go = new Runnable() {
+ @Override
+ public void run() {
+ waitable.setWaiting(true);
+ try {
+ search(keywordsField.getText(), 1, 0);
+ waitable.fireEvent();
+ } finally {
+ waitable.setWaiting(false);
+ }
+ }
+ };
+
keywordsField.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
- search(keywordsField.getText(), 1, 0);
+ new Thread(go).start();
} else {
super.keyReleased(e);
}
submitKeywords.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- search(keywordsField.getText(), 1, 0);
- fireEvent.run();
- }
- }).start();
+ new Thread(go).start();
}
});
updateKeywords("");
}
+ /**
+ * The currently displayed page of result for the current search (see the
+ * <tt>page</tt> parameter of
+ * {@link GuiReaderSearchByNamePanel#search(String, int, int)}).
+ *
+ * @return the currently displayed page of results
+ */
public int getPage() {
return page;
}
+ /**
+ * The number of pages of result for the current search (see the
+ * <tt>page</tt> parameter of
+ * {@link GuiReaderSearchByPanel#search(String, int, int)}).
+ * <p>
+ * For an unknown number or when not applicable, -1 is returned.
+ *
+ * @return the number of pages of results or -1
+ */
public int getMaxPage() {
return maxPage;
}
+ /**
+ * Return the keywords used for the current search.
+ *
+ * @return the keywords
+ */
public String getCurrentKeywords() {
return keywordsField.getText();
}
+ /**
+ * The currently loaded stories (the result of the latest search).
+ *
+ * @return the stories
+ */
public List<MetaData> getStories() {
return stories;
}
- // selected item or 0 if none ! one-based !
+ /**
+ * Return the currently selected story (the <tt>item</tt>) if it was
+ * specified in the latest, or 0 if not.
+ * <p>
+ * Note: this is thus a 1-based index, <b>not</b> a 0-based index.
+ *
+ * @return the item
+ */
public int getStoryItem() {
return storyItem;
}
- // cannot be NULL
+ /**
+ * Update the keywords displayed on screen.
+ *
+ * @param keywords
+ * the keywords
+ */
private void updateKeywords(final String keywords) {
if (!keywords.equals(keywordsField.getText())) {
GuiReaderSearchFrame.inUi(new Runnable() {
}
}
- // item 0 = no selection, else = default selection
- // throw if page > max
+ /**
+ * Search for the given terms on the currently selected searchable.
+ * <p>
+ * This operation can be long and should be run outside the UI thread.
+ *
+ * @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)
+ *
+ * @throw IndexOutOfBoundsException if the page is out of bounds
+ */
public void search(String keywords, int page, int item) {
List<MetaData> stories = new ArrayList<MetaData>();
int storyItem = 0;
updateKeywords(keywords);
int maxPage = -1;
- try {
- maxPage = searchable.searchPages(keywords);
- } catch (IOException e) {
- GuiReaderSearchFrame.error(e);
+ if (searchable != null) {
+ try {
+ maxPage = searchable.searchPages(keywords);
+ } catch (IOException e) {
+ GuiReaderSearchFrame.error(e);
+ }
}
if (page > 0) {
+ maxPage);
}
- try {
- stories = searchable.search(keywords, page);
- } catch (IOException e) {
- GuiReaderSearchFrame.error(e);
- stories = new ArrayList<MetaData>();
+ if (searchable != null) {
+ try {
+ stories = searchable.search(keywords, page);
+ } catch (IOException e) {
+ GuiReaderSearchFrame.error(e);
+ }
}
if (item > 0 && item <= stories.size()) {
package be.nikiroo.fanfix.reader.ui;
import java.awt.BorderLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
public class GuiReaderSearchByPanel extends JPanel {
private static final long serialVersionUID = 1L;
- private int actionEventId = ActionEvent.ACTION_FIRST;
-
private Waitable waitable;
private boolean searchByTags;
-
private JTabbedPane searchTabs;
private GuiReaderSearchByNamePanel byName;
private GuiReaderSearchByTagPanel byTag;
- private List<ActionListener> actions = new ArrayList<ActionListener>();
-
+ /**
+ * This interface represents an item that wan be put in "wait" mode. It is
+ * supposed to be used for long running operations during which we want to
+ * disable UI interactions.
+ * <p>
+ * It also allows reporting an event to the item.
+ *
+ * @author niki
+ */
public interface Waitable {
+ /**
+ * Set the item in wait mode, blocking it from accepting UI input.
+ *
+ * @param waiting
+ * TRUE for wait more, FALSE to restore normal mode
+ */
public void setWaiting(boolean waiting);
+
+ /**
+ * Notify the {@link Waitable} that an event occured (i.e., new stories
+ * were found).
+ */
+ public void fireEvent();
}
- // will throw illegalArgEx if bad support type, NULL allowed
- public GuiReaderSearchByPanel(final SupportType supportType,
- Waitable waitable) {
+ /**
+ * Create a new {@link GuiReaderSearchByPanel}.
+ *
+ * @param waitable
+ * the waitable we can wait on for long UI operations
+ */
+ public GuiReaderSearchByPanel(Waitable waitable) {
setLayout(new BorderLayout());
this.waitable = waitable;
searchByTags = false;
- Runnable fireEvent = new Runnable() {
- @Override
- public void run() {
- fireAction();
- }
- };
-
- byName = new GuiReaderSearchByNamePanel(fireEvent);
- byTag = new GuiReaderSearchByTagPanel(fireEvent);
+ byName = new GuiReaderSearchByNamePanel(waitable);
+ byTag = new GuiReaderSearchByTagPanel(waitable);
searchTabs = new JTabbedPane();
searchTabs.addTab("By name", byName);
add(searchTabs, BorderLayout.CENTER);
updateSearchBy(searchByTags);
- setSupportType(supportType);
}
+ /**
+ * Set the new {@link SupportType}.
+ * <p>
+ * This operation can be long and should be run outside the UI thread.
+ * <p>
+ * Note that if a non-searchable {@link SupportType} is used, an
+ * {@link IllegalArgumentException} will be thrown.
+ *
+ * @param supportType
+ * the support mode, must be searchable or NULL
+ *
+ * @throws IllegalArgumentException
+ * if the {@link SupportType} is not NULL but not searchable
+ * (see {@link BasicSearchable#getSearchable(SupportType)})
+ */
public void setSupportType(SupportType supportType) {
BasicSearchable searchable = BasicSearchable.getSearchable(supportType);
if (searchable == null && supportType != null) {
- throw new java.lang.IllegalArgumentException(
- "Unupported support type: " + supportType);
+ throw new IllegalArgumentException("Unupported support type: "
+ + supportType);
}
byName.setSearchable(searchable);
byTag.setSearchable(searchable);
}
+ /**
+ * The currently displayed page of result for the current search (see the
+ * <tt>page</tt> parameter of
+ * {@link GuiReaderSearchByPanel#search(String, int, int)} or
+ * {@link GuiReaderSearchByPanel#searchTag(SupportType, int, int, SearchableTag)}
+ * ).
+ *
+ * @return the currently displayed page of results
+ */
public int getPage() {
if (!searchByTags) {
return byName.getPage();
return byTag.getPage();
}
+ /**
+ * The number of pages of result for the current search (see the
+ * <tt>page</tt> parameter of
+ * {@link GuiReaderSearchByPanel#search(String, int, int)} or
+ * {@link GuiReaderSearchByPanel#searchTag(SupportType, int, int, SearchableTag)}
+ * ).
+ * <p>
+ * For an unknown number or when not applicable, -1 is returned.
+ *
+ * @return the number of pages of results or -1
+ */
public int getMaxPage() {
if (!searchByTags) {
return byName.getMaxPage();
return byTag.getMaxPage();
}
- // throw outOfBounds if needed
+ /**
+ * Set the page of results to display for the current search. This will
+ * cause {@link Waitable#fireEvent()} to be called if needed.
+ * <p>
+ * This operation can be long and should be run outside the UI thread.
+ *
+ * @param page
+ * the page of results to set
+ *
+ * @throw IndexOutOfBoundsException if the page is out of bounds
+ */
public void setPage(int page) {
if (searchByTags) {
searchTag(byTag.getCurrentTag(), page, 0);
}
}
- // actions will be fired in UIthread
- public void addActionListener(ActionListener action) {
- actions.add(action);
- }
-
- public boolean removeActionListener(ActionListener action) {
- return actions.remove(action);
- }
-
+ /**
+ * The currently loaded stories (the result of the latest search).
+ *
+ * @return the stories
+ */
public List<MetaData> getStories() {
if (!searchByTags) {
return byName.getStories();
return byTag.getStories();
}
- // selected item or 0 if none ! one-based !
+ /**
+ * Return the currently selected story (the <tt>item</tt>) if it was
+ * specified in the latest, or 0 if not.
+ * <p>
+ * Note: this is thus a 1-based index, <b>not</b> a 0-based index.
+ *
+ * @return the item
+ */
public int getStoryItem() {
if (!searchByTags) {
return byName.getStoryItem();
return byTag.getStoryItem();
}
- private void fireAction() {
- GuiReaderSearchFrame.inUi(new Runnable() {
- @Override
- public void run() {
- ActionEvent ae = new ActionEvent(GuiReaderSearchByPanel.this,
- actionEventId, "stories found");
-
- actionEventId++;
- if (actionEventId > ActionEvent.ACTION_LAST) {
- actionEventId = ActionEvent.ACTION_FIRST;
- }
-
- for (ActionListener action : actions) {
- try {
- action.actionPerformed(ae);
- } catch (Exception e) {
- GuiReaderSearchFrame.error(e);
- }
- }
- }
- });
- }
-
+ /**
+ * Update the kind of searches to make: search by keywords or search by tags
+ * (it will impact what the user can see and interact with on the UI).
+ *
+ * @param byTag
+ * TRUE for tag-based searches, FALSE for keywords-based searches
+ */
private void updateSearchBy(final boolean byTag) {
GuiReaderSearchFrame.inUi(new Runnable() {
@Override
});
}
- // slow, start in UI mode
+ /**
+ * Search for the given terms on the currently selected searchable. This
+ * will cause {@link Waitable#fireEvent()} to be called if needed.
+ * <p>
+ * This operation can be long and should be run outside the UI thread.
+ *
+ * @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)
+ *
+ * @throw IndexOutOfBoundsException if the page is out of bounds
+ */
public void search(final String keywords, final int page, final int item) {
- waitable.setWaiting(true);
updateSearchBy(false);
- new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- byName.search(keywords, page, item);
- fireAction();
- } finally {
- waitable.setWaiting(false);
- }
- }
- }).start();
+ byName.search(keywords, page, item);
+ waitable.fireEvent();
}
- // slow, start in UI mode
- // tag: null = base tags
+ /**
+ * Search for the given tag on the currently selected searchable. This will
+ * cause {@link Waitable#fireEvent()} to be called if needed.
+ * <p>
+ * 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.
+ * <p>
+ * This operation can be long and should be run outside the UI thread.
+ *
+ * @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)
+ *
+ * @throw IndexOutOfBoundsException if the page is out of bounds
+ */
public void searchTag(final SearchableTag tag, final int page,
final int item) {
- waitable.setWaiting(true);
updateSearchBy(true);
- new Thread(new Runnable() {
- @Override
- public void run() {
- try {
-
- byTag.searchTag(tag, page, item);
- fireAction();
- } finally {
- waitable.setWaiting(false);
- }
- }
- }).start();
+ byTag.searchTag(tag, page, item);
+ waitable.fireEvent();
}
/**
import javax.swing.ListCellRenderer;
import be.nikiroo.fanfix.data.MetaData;
+import be.nikiroo.fanfix.reader.ui.GuiReaderSearchByPanel.Waitable;
import be.nikiroo.fanfix.searchable.BasicSearchable;
import be.nikiroo.fanfix.searchable.SearchableTag;
+import be.nikiroo.fanfix.supported.SupportType;
/**
* This panel represents a search panel that works for keywords and tags based
private static final long serialVersionUID = 1L;
private BasicSearchable searchable;
- private Runnable fireEvent;
+ private Waitable waitable;
private SearchableTag currentTag;
private JPanel tagBars;
private List<MetaData> stories = new ArrayList<MetaData>();
private int storyItem;
- public GuiReaderSearchByTagPanel(Runnable fireEvent) {
+ public GuiReaderSearchByTagPanel(Waitable waitable) {
setLayout(new BorderLayout());
- this.fireEvent = fireEvent;
+ this.waitable = waitable;
combos = new ArrayList<JComboBox>();
page = 1;
maxPage = -1;
/**
* The {@link BasicSearchable} object use for the searches themselves.
* <p>
+ * This operation can be long and should be run outside the UI thread.
+ * <p>
* Can be NULL, but no searches will work.
*
* @param searchable
updateTags(null);
}
+ /**
+ * The currently displayed page of result for the current search (see the
+ * <tt>page</tt> parameter of
+ * {@link GuiReaderSearchByTagPanel#searchTag(SupportType, int, int, SearchableTag)}
+ * ).
+ *
+ * @return the currently displayed page of results
+ */
public int getPage() {
return page;
}
+ /**
+ * The number of pages of result for the current search (see the
+ * <tt>page</tt> parameter of
+ * {@link GuiReaderSearchByPanel#searchTag(SupportType, int, int, SearchableTag)}
+ * ).
+ * <p>
+ * For an unknown number or when not applicable, -1 is returned.
+ *
+ * @return the number of pages of results or -1
+ */
public int getMaxPage() {
return maxPage;
}
+ /**
+ * Return the tag used for the current search.
+ *
+ * @return the tag (which can be NULL, for "base tags")
+ */
public SearchableTag getCurrentTag() {
return currentTag;
}
+ /**
+ * The currently loaded stories (the result of the latest search).
+ *
+ * @return the stories
+ */
public List<MetaData> getStories() {
return stories;
}
- // selected item or 0 if none ! one-based !
+ /**
+ * Return the currently selected story (the <tt>item</tt>) if it was
+ * specified in the latest, or 0 if not.
+ * <p>
+ * Note: this is thus a 1-based index, <b>not</b> a 0-based index.
+ *
+ * @return the item
+ */
public int getStoryItem() {
return storyItem;
}
- // update and reset the tagsbar
- // can be NULL, for base tags
+ /**
+ * Update the tags displayed on screen and reset the tags bar.
+ * <p>
+ * This operation can be long and should be run outside the UI thread.
+ *
+ * @param tag
+ * the tag to use, or NULL for base tags
+ */
private void updateTags(final SearchableTag tag) {
final List<SearchableTag> parents = new ArrayList<SearchableTag>();
SearchableTag parent = (tag == null) ? null : tag;
});
}
- // must be quick and no thread change
+ /**
+ * Add a tags bar (do not remove possible previous ones).
+ * <p>
+ * Will always add an "empty" (NULL) tag as first option.
+ *
+ * @param tags
+ * the tags to display
+ * @param selected
+ * the selected tag if any, or NULL for none
+ */
private void addTagBar(List<SearchableTag> tags,
final SearchableTag selected) {
tags.add(0, null);
tagBars.add(combo);
}
+ /**
+ * The action to do on {@link JComboBox} selection.
+ * <p>
+ * The content of the action is:
+ * <ul>
+ * <li>Remove all tags bar below this one</li>
+ * <li>Load the subtags if any in anew tags bar</li>
+ * <li>Load the related stories if the tag was a leaf tag and notify the
+ * {@link Waitable} (via {@link Waitable#fireEvent()})</li>
+ * </ul>
+ *
+ * @param comboIndex
+ * the index of the related {@link JComboBox}
+ *
+ * @return the action
+ */
private ActionListener createComboTagAction(final int comboIndex) {
return new ActionListener() {
@Override
new Thread(new Runnable() {
@Override
public void run() {
- final List<SearchableTag> children = getChildrenForTag(tag);
- if (children != null) {
- GuiReaderSearchFrame.inUi(new Runnable() {
- @Override
- public void run() {
- addTagBar(children, tag);
+ waitable.setWaiting(true);
+ try {
+ final List<SearchableTag> children = getChildrenForTag(tag);
+ if (children != null) {
+ GuiReaderSearchFrame.inUi(new Runnable() {
+ @Override
+ public void run() {
+ addTagBar(children, tag);
+ }
+ });
+ }
+
+ if (tag != null && tag.isLeaf()) {
+ storyItem = 0;
+ try {
+ searchable.fillTag(tag);
+ page = 1;
+ stories = searchable.search(tag, 1);
+ maxPage = searchable.searchPages(tag);
+ } catch (IOException e) {
+ GuiReaderSearchFrame.error(e);
+ page = 0;
+ maxPage = -1;
+ stories = new ArrayList<MetaData>();
}
- });
- }
- if (tag != null && tag.isLeaf()) {
- storyItem = 0;
- try {
- searchable.fillTag(tag);
- page = 1;
- stories = searchable.search(tag, 1);
- maxPage = searchable.searchPages(tag);
- } catch (IOException e) {
- GuiReaderSearchFrame.error(e);
- page = 0;
- maxPage = -1;
- stories = new ArrayList<MetaData>();
+ waitable.fireEvent();
}
-
- fireEvent.run();
+ } finally {
+ waitable.setWaiting(false);
}
}
}).start();
};
}
- // sync, add children of tag, NULL = base tags
- // return children of the tag or base tags or NULL
+ /**
+ * Get the children of the given tag (or the base tags if the given tag is
+ * NULL).
+ * <p>
+ * This action will "fill" ({@link BasicSearchable#fillTag(SearchableTag)})
+ * the given tag if needed first.
+ * <p>
+ * This operation can be long and should be run outside the UI thread.
+ *
+ * @param tag
+ * the tag to search into or NULL for the base tags
+ * @return the children
+ */
private List<SearchableTag> getChildrenForTag(final SearchableTag tag) {
List<SearchableTag> children = new ArrayList<SearchableTag>();
if (tag == null) {
return children;
}
- // slow
- // tag: null = base tags
- // throw if page > max, but only if stories
+ /**
+ * Search for the given tag on the currently selected searchable.
+ * <p>
+ * 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.
+ * <p>
+ * This operation can be long and should be run outside the UI thread.
+ *
+ * @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)
+ *
+ * @throw IndexOutOfBoundsException if the page is out of bounds
+ */
public void searchTag(SearchableTag tag, int page, int item) {
List<MetaData> stories = new ArrayList<MetaData>();
int storyItem = 0;
private static final long serialVersionUID = 1L;
private List<SupportType> supportTypes;
- private SupportType supportType;
private int page;
private int maxPage;
private JComboBox comboSupportTypes;
+ private ActionListener comboSupportTypesListener;
private GuiReaderSearchByPanel searchPanel;
private boolean seeWordcount;
maxPage = -1;
supportTypes = new ArrayList<SupportType>();
+ 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) {
+ final SupportType support = (SupportType) comboSupportTypes
+ .getSelectedItem();
setWaiting(true);
- updateSupportType(
- (SupportType) comboSupportTypes.getSelectedItem(),
- new Runnable() {
- @Override
- public void run() {
- setWaiting(false);
- }
- });
+ 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);
- searchPanel = new GuiReaderSearchByPanel(supportType,
+ searchPanel = new GuiReaderSearchByPanel(
new GuiReaderSearchByPanel.Waitable() {
@Override
public void setWaiting(boolean waiting) {
GuiReaderSearchFrame.this.setWaiting(waiting);
}
- });
- searchPanel.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- updatePages(searchPanel.getPage(), searchPanel.getMaxPage());
- List<GuiReaderBookInfo> infos = new ArrayList<GuiReaderBookInfo>();
- for (MetaData meta : searchPanel.getStories()) {
- infos.add(GuiReaderBookInfo.fromMeta(meta));
- }
-
- updateBooks(infos);
-
- // ! 1-based index !
- int item = searchPanel.getStoryItem();
- if (item > 0 && item <= books.getBooksCount()) {
- // TODO: "click" on item ITEM
- }
- }
- });
+ @Override
+ public void fireEvent() {
+ updatePages(searchPanel.getPage(),
+ searchPanel.getMaxPage());
+ List<GuiReaderBookInfo> infos = new ArrayList<GuiReaderBookInfo>();
+ for (MetaData meta : searchPanel.getStories()) {
+ infos.add(GuiReaderBookInfo.fromMeta(meta));
+ }
+
+ 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);
add(scroll, BorderLayout.CENTER);
}
- private void updateSupportType(final SupportType supportType,
- final Runnable inUi) {
- this.supportType = supportType;
- comboSupportTypes.setSelectedItem(supportType);
- books.clear();
-
- new Thread(new Runnable() {
+ /**
+ * Update the {@link SupportType} currently displayed to the user.
+ * <p>
+ * Will also cause a search for the new base tags of the given support if
+ * not NULL.
+ * <p>
+ * 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() {
- searchPanel.setSupportType(supportType);
- inUi(inUi);
+ books.clear();
+
+ comboSupportTypes
+ .removeActionListener(comboSupportTypesListener);
+ comboSupportTypes.setSelectedItem(supportType);
+ comboSupportTypes.addActionListener(comboSupportTypesListener);
+
}
- }).start();
+ });
+
+ searchPanel.setSupportType(supportType);
}
+ /**
+ * Update the pages and the lined buttons currently displayed on screen.
+ * <p>
+ * 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
});
}
+ /**
+ * Update the currently displayed books.
+ *
+ * @param infos
+ * the new books
+ */
private void updateBooks(final List<GuiReaderBookInfo> infos) {
- setWaiting(true);
inUi(new Runnable() {
@Override
public void run() {
books.refreshBooks(infos, seeWordcount);
- setWaiting(false);
}
});
}
- // 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.
+ * <p>
+ * 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) {
setWaiting(true);
new Thread(new Runnable() {
@Override
public void run() {
- searchPanel.setSupportType(searchOn);
- searchPanel.search(keywords, page, item);
- inUi(new Runnable() {
- @Override
- public void run() {
- setWaiting(false);
- }
- });
+ try {
+ updateSupportType(searchOn);
+ searchPanel.search(keywords, page, item);
+ } finally {
+ setWaiting(false);
+ }
}
}).start();
}
- // tag: null = base tags
+ /**
+ * Search for the given tag on the currently selected searchable. This will
+ * update the displayed books if needed.
+ * <p>
+ * 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.
+ * <p>
+ * 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) {
setWaiting(true);
new Thread(new Runnable() {
@Override
public void run() {
- searchPanel.setSupportType(searchOn);
- searchPanel.searchTag(tag, page, item);
- inUi(new Runnable() {
- @Override
- public void run() {
- setWaiting(false);
- }
- });
+ try {
+ updateSupportType(searchOn);
+ searchPanel.searchTag(tag, page, item);
+ } finally {
+ setWaiting(false);
+ }
}
}).start();
}
}
}
+ /**
+ * An error occurred, inform the user and/or log the error.
+ *
+ * @param e
+ * the error
+ */
static void error(Exception e) {
Instance.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);
}
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