package be.nikiroo.fanfix.reader.ui; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JTextField; import be.nikiroo.fanfix.data.MetaData; import be.nikiroo.fanfix.reader.ui.GuiReaderSearchByPanel.Waitable; import be.nikiroo.fanfix.searchable.BasicSearchable; /** * This panel represents a search panel that works for keywords and tags based * searches. * * @author niki */ public class GuiReaderSearchByNamePanel extends JPanel { private static final long serialVersionUID = 1L; private BasicSearchable searchable; private JTextField keywordsField; private JButton submitKeywords; private int page; private int maxPage; private List stories = new ArrayList(); private int storyItem; public GuiReaderSearchByNamePanel(final Waitable waitable) { super(new BorderLayout()); keywordsField = new JTextField(); add(keywordsField, BorderLayout.CENTER); 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) { new Thread(go).start(); } else { super.keyReleased(e); } } }); submitKeywords.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { new Thread(go).start(); } }); setSearchable(null); } /** * The {@link BasicSearchable} object use for the searches themselves. *

* Can be NULL, but no searches will work. * * @param searchable * the new searchable */ public void setSearchable(BasicSearchable searchable) { this.searchable = searchable; page = 1; maxPage = -1; storyItem = 0; stories = new ArrayList(); updateKeywords(""); } /** * The currently displayed page of result for the current search (see the * page 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 * page parameter of * {@link GuiReaderSearchByPanel#search(String, int, int)}). *

* 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 getStories() { return stories; } /** * Return the currently selected story (the item) if it was * specified in the latest, or 0 if not. *

* Note: this is thus a 1-based index, not a 0-based index. * * @return the item */ public int getStoryItem() { return storyItem; } /** * 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() { @Override public void run() { keywordsField.setText(keywords); } }); } } /** * Search for the given terms on the currently selected searchable. *

* 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 stories = new ArrayList(); int storyItem = 0; updateKeywords(keywords); int maxPage = -1; if (searchable != null) { try { maxPage = searchable.searchPages(keywords); } catch (IOException e) { GuiReaderSearchFrame.error(e); } } if (page > 0) { if (maxPage >= 0 && (page <= 0 || page > maxPage)) { throw new IndexOutOfBoundsException("Page " + page + " out of " + maxPage); } if (searchable != null) { try { stories = searchable.search(keywords, page); } catch (IOException e) { GuiReaderSearchFrame.error(e); } } if (item > 0 && item <= stories.size()) { storyItem = item; } else if (item > 0) { GuiReaderSearchFrame.error(String.format( "Story item does not exist: Search [%s], item %d", keywords, item)); } } this.page = page; this.maxPage = maxPage; this.stories = stories; this.storyItem = storyItem; } /** * 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); keywordsField.setEnabled(b); submitKeywords.setEnabled(b); } }