1 package be
.nikiroo
.fanfix
.reader
.ui
;
3 import java
.awt
.BorderLayout
;
6 import javax
.swing
.JPanel
;
7 import javax
.swing
.JTabbedPane
;
8 import javax
.swing
.event
.ChangeEvent
;
9 import javax
.swing
.event
.ChangeListener
;
11 import be
.nikiroo
.fanfix
.data
.MetaData
;
12 import be
.nikiroo
.fanfix
.searchable
.BasicSearchable
;
13 import be
.nikiroo
.fanfix
.searchable
.SearchableTag
;
14 import be
.nikiroo
.fanfix
.supported
.SupportType
;
17 * This panel represents a search panel that works for keywords and tags based
22 public class GuiReaderSearchByPanel
extends JPanel
{
23 private static final long serialVersionUID
= 1L;
25 private Waitable waitable
;
27 private boolean searchByTags
;
28 private JTabbedPane searchTabs
;
29 private GuiReaderSearchByNamePanel byName
;
30 private GuiReaderSearchByTagPanel byTag
;
33 * This interface represents an item that wan be put in "wait" mode. It is
34 * supposed to be used for long running operations during which we want to
35 * disable UI interactions.
37 * It also allows reporting an event to the item.
41 public interface Waitable
{
43 * Set the item in wait mode, blocking it from accepting UI input.
46 * TRUE for wait more, FALSE to restore normal mode
48 public void setWaiting(boolean waiting
);
51 * Notify the {@link Waitable} that an event occured (i.e., new stories
54 public void fireEvent();
58 * Create a new {@link GuiReaderSearchByPanel}.
61 * the waitable we can wait on for long UI operations
63 public GuiReaderSearchByPanel(Waitable waitable
) {
64 setLayout(new BorderLayout());
66 this.waitable
= waitable
;
69 byName
= new GuiReaderSearchByNamePanel(waitable
);
70 byTag
= new GuiReaderSearchByTagPanel(waitable
);
72 searchTabs
= new JTabbedPane();
73 searchTabs
.addTab("By name", byName
);
74 searchTabs
.addTab("By tags", byTag
);
75 searchTabs
.addChangeListener(new ChangeListener() {
77 public void stateChanged(ChangeEvent e
) {
78 searchByTags
= (searchTabs
.getSelectedComponent() == byTag
);
82 add(searchTabs
, BorderLayout
.CENTER
);
83 updateSearchBy(searchByTags
);
87 * Set the new {@link SupportType}.
89 * This operation can be long and should be run outside the UI thread.
91 * Note that if a non-searchable {@link SupportType} is used, an
92 * {@link IllegalArgumentException} will be thrown.
95 * the support mode, must be searchable or NULL
97 * @throws IllegalArgumentException
98 * if the {@link SupportType} is not NULL but not searchable
99 * (see {@link BasicSearchable#getSearchable(SupportType)})
101 public void setSupportType(SupportType supportType
) {
102 BasicSearchable searchable
= BasicSearchable
.getSearchable(supportType
);
103 if (searchable
== null && supportType
!= null) {
104 throw new IllegalArgumentException("Unupported support type: "
108 byName
.setSearchable(searchable
);
109 byTag
.setSearchable(searchable
);
113 * The currently displayed page of result for the current search (see the
114 * <tt>page</tt> parameter of
115 * {@link GuiReaderSearchByPanel#search(String, int, int)} or
116 * {@link GuiReaderSearchByPanel#searchTag(SupportType, int, int, SearchableTag)}
119 * @return the currently displayed page of results
121 public int getPage() {
123 return byName
.getPage();
126 return byTag
.getPage();
130 * The number of pages of result for the current search (see the
131 * <tt>page</tt> parameter of
132 * {@link GuiReaderSearchByPanel#search(String, int, int)} or
133 * {@link GuiReaderSearchByPanel#searchTag(SupportType, int, int, SearchableTag)}
136 * For an unknown number or when not applicable, -1 is returned.
138 * @return the number of pages of results or -1
140 public int getMaxPage() {
142 return byName
.getMaxPage();
145 return byTag
.getMaxPage();
149 * Set the page of results to display for the current search. This will
150 * cause {@link Waitable#fireEvent()} to be called if needed.
152 * This operation can be long and should be run outside the UI thread.
155 * the page of results to set
157 * @throw IndexOutOfBoundsException if the page is out of bounds
159 public void setPage(int page
) {
161 searchTag(byTag
.getCurrentTag(), page
, 0);
163 search(byName
.getCurrentKeywords(), page
, 0);
168 * The currently loaded stories (the result of the latest search).
170 * @return the stories
172 public List
<MetaData
> getStories() {
174 return byName
.getStories();
177 return byTag
.getStories();
181 * Return the currently selected story (the <tt>item</tt>) if it was
182 * specified in the latest, or 0 if not.
184 * Note: this is thus a 1-based index, <b>not</b> a 0-based index.
188 public int getStoryItem() {
190 return byName
.getStoryItem();
193 return byTag
.getStoryItem();
197 * Update the kind of searches to make: search by keywords or search by tags
198 * (it will impact what the user can see and interact with on the UI).
201 * TRUE for tag-based searches, FALSE for keywords-based searches
203 private void updateSearchBy(final boolean byTag
) {
204 GuiReaderSearchFrame
.inUi(new Runnable() {
208 searchTabs
.setSelectedIndex(0);
210 searchTabs
.setSelectedIndex(1);
217 * Search for the given terms on the currently selected searchable. This
218 * will cause {@link Waitable#fireEvent()} to be called if needed.
220 * This operation can be long and should be run outside the UI thread.
223 * the keywords to search for
225 * the page of results to load
227 * the item to select (or 0 for none by default)
229 * @throw IndexOutOfBoundsException if the page is out of bounds
231 public void search(final String keywords
, final int page
, final int item
) {
232 updateSearchBy(false);
233 byName
.search(keywords
, page
, item
);
234 waitable
.fireEvent();
238 * Search for the given tag on the currently selected searchable. This will
239 * cause {@link Waitable#fireEvent()} to be called if needed.
241 * If the tag contains children tags, those will be displayed so you can
242 * select them; if the tag is a leaf tag, the linked stories will be
245 * This operation can be long and should be run outside the UI thread.
248 * the tag to search for, or NULL for base tags
250 * the page of results to load
252 * the item to select (or 0 for none by default)
254 * @throw IndexOutOfBoundsException if the page is out of bounds
256 public void searchTag(final SearchableTag tag
, final int page
,
258 updateSearchBy(true);
259 byTag
.searchTag(tag
, page
, item
);
260 waitable
.fireEvent();
264 * Enables or disables this component, depending on the value of the
265 * parameter <code>b</code>. An enabled component can respond to user input
266 * and generate events. Components are enabled initially by default.
268 * Disabling this component will also affect its children.
271 * If <code>true</code>, this component is enabled; otherwise
272 * this component is disabled
275 public void setEnabled(boolean b
) {
277 searchTabs
.setEnabled(b
);
278 byName
.setEnabled(b
);