GUI search: code cleanup + jDoc
[fanfix.git] / src / be / nikiroo / fanfix / reader / ui / GuiReaderSearchFrame.java
CommitLineData
4357eb54
NR
1package be.nikiroo.fanfix.reader.ui;
2
3import java.awt.BorderLayout;
d16065ec 4import java.awt.Component;
4357eb54
NR
5import java.awt.EventQueue;
6import java.awt.event.ActionEvent;
7import java.awt.event.ActionListener;
4357eb54
NR
8import java.lang.reflect.InvocationTargetException;
9import java.util.ArrayList;
10import java.util.List;
11
4357eb54
NR
12import javax.swing.JComboBox;
13import javax.swing.JFrame;
08e2185a 14import javax.swing.JLabel;
4357eb54
NR
15import javax.swing.JPanel;
16import javax.swing.JScrollPane;
4357eb54
NR
17
18import be.nikiroo.fanfix.Instance;
19import be.nikiroo.fanfix.data.MetaData;
d16065ec 20import be.nikiroo.fanfix.reader.ui.GuiReaderBook.BookActionListener;
4357eb54
NR
21import be.nikiroo.fanfix.searchable.BasicSearchable;
22import be.nikiroo.fanfix.searchable.SearchableTag;
23import be.nikiroo.fanfix.supported.SupportType;
24
25/**
26 * This frame will allow you to search through the supported websites for new
27 * stories/comics.
28 *
29 * @author niki
30 */
6e950847
NR
31// JCombobox<E> not 1.6 compatible
32@SuppressWarnings({ "unchecked", "rawtypes" })
741e8467 33public class GuiReaderSearchFrame extends JFrame {
4357eb54
NR
34 private static final long serialVersionUID = 1L;
35
36 private List<SupportType> supportTypes;
4357eb54
NR
37 private int page;
38 private int maxPage;
39
415c7454 40 private JComboBox comboSupportTypes;
dc3b0033 41 private ActionListener comboSupportTypesListener;
9c598207 42 private GuiReaderSearchByPanel searchPanel;
4357eb54
NR
43
44 private boolean seeWordcount;
45 private GuiReaderGroup books;
46
741e8467 47 public GuiReaderSearchFrame(final GuiReader reader) {
4357eb54
NR
48 super("Browse stories");
49 setLayout(new BorderLayout());
50 setSize(800, 600);
51
7cc1e743 52 page = 1;
4357eb54
NR
53 maxPage = -1;
54
55 supportTypes = new ArrayList<SupportType>();
dc3b0033 56 supportTypes.add(null);
4357eb54
NR
57 for (SupportType type : SupportType.values()) {
58 if (BasicSearchable.getSearchable(type) != null) {
59 supportTypes.add(type);
60 }
61 }
4357eb54 62
415c7454 63 comboSupportTypes = new JComboBox(
4357eb54 64 supportTypes.toArray(new SupportType[] {}));
dc3b0033
NR
65
66 comboSupportTypesListener = new ActionListener() {
4357eb54
NR
67 @Override
68 public void actionPerformed(ActionEvent e) {
dc3b0033
NR
69 final SupportType support = (SupportType) comboSupportTypes
70 .getSelectedItem();
9c598207 71 setWaiting(true);
dc3b0033
NR
72 new Thread(new Runnable() {
73 @Override
74 public void run() {
75 try {
76 updateSupportType(support);
77 } finally {
78 setWaiting(false);
79 }
80 }
81 }).start();
4357eb54 82 }
dc3b0033
NR
83 };
84 comboSupportTypes.addActionListener(comboSupportTypesListener);
85
08e2185a
NR
86 JPanel searchSites = new JPanel(new BorderLayout());
87 searchSites.add(comboSupportTypes, BorderLayout.CENTER);
88 searchSites.add(new JLabel(" " + "Website : "), BorderLayout.WEST);
4357eb54 89
dc3b0033 90 searchPanel = new GuiReaderSearchByPanel(
9c598207 91 new GuiReaderSearchByPanel.Waitable() {
7cc1e743 92 @Override
9c598207
NR
93 public void setWaiting(boolean waiting) {
94 GuiReaderSearchFrame.this.setWaiting(waiting);
7cc1e743 95 }
7cc1e743 96
dc3b0033
NR
97 @Override
98 public void fireEvent() {
99 updatePages(searchPanel.getPage(),
100 searchPanel.getMaxPage());
101 List<GuiReaderBookInfo> infos = new ArrayList<GuiReaderBookInfo>();
102 for (MetaData meta : searchPanel.getStories()) {
103 infos.add(GuiReaderBookInfo.fromMeta(meta));
104 }
105
106 updateBooks(infos);
107
108 // ! 1-based index !
109 int item = searchPanel.getStoryItem();
110 if (item > 0 && item <= books.getBooksCount()) {
111 books.setSelectedBook(item - 1, false);
112 }
113 }
114 });
4357eb54 115
08e2185a
NR
116 JPanel top = new JPanel(new BorderLayout());
117 top.add(searchSites, BorderLayout.NORTH);
ce5a42e7 118 top.add(searchPanel, BorderLayout.CENTER);
4357eb54
NR
119
120 add(top, BorderLayout.NORTH);
121
122 books = new GuiReaderGroup(reader, null, null);
d16065ec
NR
123 books.setActionListener(new BookActionListener() {
124 @Override
125 public void select(GuiReaderBook book) {
126 }
127
128 @Override
129 public void popupRequested(GuiReaderBook book, Component target,
130 int x, int y) {
131 }
132
133 @Override
134 public void action(GuiReaderBook book) {
135 new GuiReaderSearchAction(reader.getLibrary(), book.getInfo())
136 .setVisible(true);
137 }
138 });
4357eb54
NR
139 JScrollPane scroll = new JScrollPane(books);
140 scroll.getVerticalScrollBar().setUnitIncrement(16);
141 add(scroll, BorderLayout.CENTER);
4357eb54
NR
142 }
143
dc3b0033
NR
144 /**
145 * Update the {@link SupportType} currently displayed to the user.
146 * <p>
147 * Will also cause a search for the new base tags of the given support if
148 * not NULL.
149 * <p>
150 * This operation can be long and should be run outside the UI thread.
151 *
152 * @param supportType
153 * the new {@link SupportType}
154 */
155 private void updateSupportType(final SupportType supportType) {
156 inUi(new Runnable() {
81acd363
NR
157 @Override
158 public void run() {
dc3b0033
NR
159 books.clear();
160
161 comboSupportTypes
162 .removeActionListener(comboSupportTypesListener);
163 comboSupportTypes.setSelectedItem(supportType);
164 comboSupportTypes.addActionListener(comboSupportTypesListener);
165
7cc1e743 166 }
dc3b0033
NR
167 });
168
169 searchPanel.setSupportType(supportType);
7cc1e743
NR
170 }
171
dc3b0033
NR
172 /**
173 * Update the pages and the lined buttons currently displayed on screen.
174 * <p>
175 * Those are the same pages and maximum pages used by
176 * {@link GuiReaderSearchByPanel#search(String, int, int)} and
177 * {@link GuiReaderSearchByPanel#searchTag(SearchableTag, int, int)}.
178 *
179 * @param page
180 * the current page of results
181 * @param maxPage
182 * the maximum number of pages of results
183 */
9c598207 184 private void updatePages(final int page, final int maxPage) {
7cc1e743
NR
185 inUi(new Runnable() {
186 @Override
187 public void run() {
9c598207 188 GuiReaderSearchFrame.this.page = page;
7cc1e743
NR
189 GuiReaderSearchFrame.this.maxPage = maxPage;
190
191 // TODO: gui
9c598207 192 System.out.println("page: " + page);
81acd363
NR
193 System.out.println("max page: " + maxPage);
194 }
195 });
196 }
197
dc3b0033
NR
198 /**
199 * Update the currently displayed books.
200 *
201 * @param infos
202 * the new books
203 */
81acd363
NR
204 private void updateBooks(final List<GuiReaderBookInfo> infos) {
205 inUi(new Runnable() {
206 @Override
207 public void run() {
208 books.refreshBooks(infos, seeWordcount);
209 }
210 });
211 }
212
dc3b0033
NR
213 /**
214 * Search for the given terms on the currently selected searchable. This
215 * will update the displayed books if needed.
216 * <p>
217 * This operation is asynchronous.
218 *
219 * @param keywords
220 * the keywords to search for
221 * @param page
222 * the page of results to load
223 * @param item
224 * the item to select (or 0 for none by default)
225 */
4357eb54
NR
226 public void search(final SupportType searchOn, final String keywords,
227 final int page, final int item) {
9c598207
NR
228 setWaiting(true);
229 new Thread(new Runnable() {
7cc1e743
NR
230 @Override
231 public void run() {
dc3b0033
NR
232 try {
233 updateSupportType(searchOn);
234 searchPanel.search(keywords, page, item);
235 } finally {
236 setWaiting(false);
237 }
7cc1e743 238 }
9c598207 239 }).start();
4357eb54
NR
240 }
241
dc3b0033
NR
242 /**
243 * Search for the given tag on the currently selected searchable. This will
244 * update the displayed books if needed.
245 * <p>
246 * If the tag contains children tags, those will be displayed so you can
247 * select them; if the tag is a leaf tag, the linked stories will be
248 * displayed.
249 * <p>
250 * This operation is asynchronous.
251 *
252 * @param tag
253 * the tag to search for, or NULL for base tags
254 * @param page
255 * the page of results to load
256 * @param item
257 * the item to select (or 0 for none by default)
258 */
c499d79f
NR
259 public void searchTag(final SupportType searchOn, final int page,
260 final int item, final SearchableTag tag) {
9c598207
NR
261 setWaiting(true);
262 new Thread(new Runnable() {
c499d79f
NR
263 @Override
264 public void run() {
dc3b0033
NR
265 try {
266 updateSupportType(searchOn);
267 searchPanel.searchTag(tag, page, item);
268 } finally {
269 setWaiting(false);
270 }
4357eb54 271 }
9c598207 272 }).start();
bf2b37b0
NR
273 }
274
4357eb54
NR
275 /**
276 * Process the given action in the main Swing UI thread.
277 * <p>
278 * The code will make sure the current thread is the main UI thread and, if
279 * not, will switch to it before executing the runnable.
280 * <p>
281 * Synchronous operation.
282 *
283 * @param run
284 * the action to run
285 */
741e8467 286 static void inUi(final Runnable run) {
4357eb54
NR
287 if (EventQueue.isDispatchThread()) {
288 run.run();
289 } else {
290 try {
291 EventQueue.invokeAndWait(run);
292 } catch (InterruptedException e) {
bf2b37b0 293 error(e);
4357eb54 294 } catch (InvocationTargetException e) {
bf2b37b0 295 error(e);
4357eb54
NR
296 }
297 }
298 }
c499d79f 299
dc3b0033
NR
300 /**
301 * An error occurred, inform the user and/or log the error.
302 *
303 * @param e
304 * the error
305 */
741e8467 306 static void error(Exception e) {
bf2b37b0
NR
307 Instance.getTraceHandler().error(e);
308 }
309
dc3b0033
NR
310 /**
311 * An error occurred, inform the user and/or log the error.
312 *
313 * @param e
314 * the error message
315 */
741e8467
NR
316 static void error(String e) {
317 Instance.getTraceHandler().error(e);
318 }
7cc1e743 319
9c598207
NR
320 /**
321 * Enables or disables this component, depending on the value of the
322 * parameter <code>b</code>. An enabled component can respond to user input
323 * and generate events. Components are enabled initially by default.
324 * <p>
325 * Disabling this component will also affect its children.
326 *
327 * @param b
328 * If <code>true</code>, this component is enabled; otherwise
329 * this component is disabled
330 */
331 @Override
332 public void setEnabled(boolean b) {
333 super.setEnabled(b);
334 books.setEnabled(b);
335 searchPanel.setEnabled(b);
336 }
337
dc3b0033
NR
338 /**
339 * Set the item in wait mode, blocking it from accepting UI input.
340 *
341 * @param waiting
342 * TRUE for wait more, FALSE to restore normal mode
343 */
9c598207 344 private void setWaiting(final boolean waiting) {
c499d79f
NR
345 inUi(new Runnable() {
346 @Override
347 public void run() {
741e8467 348 GuiReaderSearchFrame.this.setEnabled(!waiting);
c499d79f
NR
349 }
350 });
351 }
4357eb54 352}