GUI search
[fanfix.git] / src / be / nikiroo / fanfix / reader / ui / GuiReaderSearch.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;
8import java.io.IOException;
9import java.lang.reflect.InvocationTargetException;
10import java.util.ArrayList;
11import java.util.List;
12
13import javax.swing.JButton;
14import javax.swing.JComboBox;
15import javax.swing.JFrame;
08e2185a 16import javax.swing.JLabel;
4357eb54
NR
17import javax.swing.JPanel;
18import javax.swing.JScrollPane;
19import javax.swing.JTabbedPane;
20import javax.swing.JTextField;
21
22import be.nikiroo.fanfix.Instance;
23import be.nikiroo.fanfix.data.MetaData;
d16065ec 24import be.nikiroo.fanfix.reader.ui.GuiReaderBook.BookActionListener;
4357eb54
NR
25import be.nikiroo.fanfix.searchable.BasicSearchable;
26import be.nikiroo.fanfix.searchable.SearchableTag;
27import be.nikiroo.fanfix.supported.SupportType;
28
29/**
30 * This frame will allow you to search through the supported websites for new
31 * stories/comics.
32 *
33 * @author niki
34 */
35public class GuiReaderSearch extends JFrame {
36 private static final long serialVersionUID = 1L;
37
38 private List<SupportType> supportTypes;
39 private SupportType supportType;
81acd363 40 private boolean searchByTags;
4357eb54
NR
41 private List<SearchableTag> tags;
42 private String keywords;
43 private int page;
44 private int maxPage;
45
46 private JComboBox<SupportType> comboSupportTypes;
47 private JTabbedPane searchTabs;
81acd363 48 private JTextField keywordsField;
08e2185a 49 private JButton submitKeywords;
4357eb54
NR
50
51 private boolean seeWordcount;
52 private GuiReaderGroup books;
53
d16065ec 54 public GuiReaderSearch(final GuiReader reader) {
4357eb54
NR
55 super("Browse stories");
56 setLayout(new BorderLayout());
57 setSize(800, 600);
58
59 tags = new ArrayList<SearchableTag>();
60 page = 1; // TODO
61 maxPage = -1;
81acd363 62 searchByTags = false;
4357eb54
NR
63
64 supportTypes = new ArrayList<SupportType>();
65 for (SupportType type : SupportType.values()) {
66 if (BasicSearchable.getSearchable(type) != null) {
67 supportTypes.add(type);
68 }
69 }
70 supportType = supportTypes.isEmpty() ? null : supportTypes.get(0);
71
4357eb54
NR
72 comboSupportTypes = new JComboBox<SupportType>(
73 supportTypes.toArray(new SupportType[] {}));
74 comboSupportTypes.addActionListener(new ActionListener() {
75 @Override
76 public void actionPerformed(ActionEvent e) {
81acd363 77 updateSupportType((SupportType) comboSupportTypes
4357eb54
NR
78 .getSelectedItem());
79 }
80 });
08e2185a
NR
81 JPanel searchSites = new JPanel(new BorderLayout());
82 searchSites.add(comboSupportTypes, BorderLayout.CENTER);
83 searchSites.add(new JLabel(" " + "Website : "), BorderLayout.WEST);
4357eb54 84
4357eb54
NR
85 searchTabs = new JTabbedPane();
86 searchTabs.addTab("By name", createByNameSearchPanel());
87 searchTabs.addTab("By tags", createByTagSearchPanel());
88
08e2185a
NR
89 JPanel top = new JPanel(new BorderLayout());
90 top.add(searchSites, BorderLayout.NORTH);
4357eb54
NR
91 top.add(searchTabs, BorderLayout.CENTER);
92
93 add(top, BorderLayout.NORTH);
94
95 books = new GuiReaderGroup(reader, null, null);
d16065ec
NR
96 books.setActionListener(new BookActionListener() {
97 @Override
98 public void select(GuiReaderBook book) {
99 }
100
101 @Override
102 public void popupRequested(GuiReaderBook book, Component target,
103 int x, int y) {
104 }
105
106 @Override
107 public void action(GuiReaderBook book) {
108 new GuiReaderSearchAction(reader.getLibrary(), book.getInfo())
109 .setVisible(true);
110 }
111 });
4357eb54
NR
112 JScrollPane scroll = new JScrollPane(books);
113 scroll.getVerticalScrollBar().setUnitIncrement(16);
114 add(scroll, BorderLayout.CENTER);
115 }
116
4357eb54
NR
117 private JPanel createByNameSearchPanel() {
118 JPanel byName = new JPanel(new BorderLayout());
119
81acd363 120 keywordsField = new JTextField();
4357eb54
NR
121 byName.add(keywordsField, BorderLayout.CENTER);
122
08e2185a
NR
123 submitKeywords = new JButton("Search");
124 byName.add(submitKeywords, BorderLayout.EAST);
4357eb54
NR
125
126 // TODO: ENTER -> search
127
08e2185a 128 submitKeywords.addActionListener(new ActionListener() {
4357eb54
NR
129 @Override
130 public void actionPerformed(ActionEvent e) {
131 search(supportType, keywordsField.getText(), page, 0);
132 }
133 });
134
135 return byName;
136 }
137
138 private JPanel createByTagSearchPanel() {
139 JPanel byTag = new JPanel();
140 JPanel searchBars = new JPanel();
141 add(searchBars, BorderLayout.NORTH);
142
143 return byTag;
144 }
145
81acd363
NR
146 private void updateSupportType(SupportType supportType) {
147 if (supportType != this.supportType) {
148 this.supportType = supportType;
149 comboSupportTypes.setSelectedItem(supportType);
a12b668f
NR
150 books.clear();
151 // TODO: reset all tags
81acd363
NR
152 }
153 }
154
155 private void updateSearchBy(final boolean byTag) {
156 if (byTag != this.searchByTags) {
157 inUi(new Runnable() {
158 @Override
159 public void run() {
160 if (!byTag) {
161 searchTabs.setSelectedIndex(0);
162 } else {
163 searchTabs.setSelectedIndex(1);
164 }
165 }
166 });
167 }
168 }
169
170 private void updatePages(final int page, final Integer maxPage) {
171 inUi(new Runnable() {
172 @Override
173 public void run() {
174 GuiReaderSearch.this.page = page;
175 GuiReaderSearch.this.maxPage = maxPage;
176 // TODO: gui
177 System.out.println("page: " + page);
178 System.out.println("max page: " + maxPage);
179 }
180 });
181 }
182
08e2185a 183 // cannot be NULL
81acd363 184 private void updateKeywords(final String keywords) {
08e2185a
NR
185 if (!keywords.equals(this.keywords)) {
186 inUi(new Runnable() {
187 @Override
188 public void run() {
189 GuiReaderSearch.this.keywords = keywords;
190 keywordsField.setText(keywords);
191 }
192 });
193 }
81acd363
NR
194 }
195
196 // can be NULL
197 private void updateTags(final SearchableTag tag) {
198 inUi(new Runnable() {
199 @Override
200 public void run() {
201 // TODO
202 }
203 });
204 }
205
206 private void updateBooks(final List<GuiReaderBookInfo> infos) {
c499d79f 207 setWaitingScreen(true);
81acd363
NR
208 inUi(new Runnable() {
209 @Override
210 public void run() {
211 books.refreshBooks(infos, seeWordcount);
c499d79f 212 setWaitingScreen(false);
81acd363
NR
213 }
214 });
215 }
216
217 // item 0 = no selection, else = default selection
4357eb54
NR
218 public void search(final SupportType searchOn, final String keywords,
219 final int page, final int item) {
81acd363 220
08e2185a
NR
221 setWaitingScreen(true);
222
81acd363
NR
223 updateSupportType(searchOn);
224 updateSearchBy(false);
225 updateKeywords(keywords);
226 updatePages(page, maxPage);
4357eb54
NR
227
228 new Thread(new Runnable() {
229 @Override
230 public void run() {
231 BasicSearchable search = BasicSearchable
232 .getSearchable(searchOn);
233
234 if (page <= 0) {
235 int maxPage = -1;
236 try {
237 maxPage = search.searchPages(keywords);
238 } catch (IOException e) {
239 Instance.getTraceHandler().error(e);
240 }
241 updateBooks(new ArrayList<GuiReaderBookInfo>());
242 updatePages(0, maxPage);
243 } else {
244 List<GuiReaderBookInfo> infos = new ArrayList<GuiReaderBookInfo>();
245 try {
246 for (MetaData meta : search.search(keywords, page)) {
247 infos.add(GuiReaderBookInfo.fromMeta(meta));
248 }
249 } catch (IOException e) {
250 Instance.getTraceHandler().error(e);
251 }
252
253 updateBooks(infos);
254 updatePages(page, maxPage);
255
256 // ! 1-based index !
257 if (item > 0 && item <= books.getBooksCount()) {
258 // TODO: "click" on item ITEM
259 }
260 }
08e2185a
NR
261
262 setWaitingScreen(false);
4357eb54
NR
263 }
264 }).start();
265 }
266
c499d79f
NR
267 public void searchTag(final SupportType searchOn, final int page,
268 final int item, final SearchableTag tag) {
269
270 setWaitingScreen(true);
4357eb54 271
81acd363
NR
272 updateSupportType(searchOn);
273 updateSearchBy(true);
274 updateTags(tag);
275 updatePages(page, maxPage);
4357eb54 276
c499d79f
NR
277 new Thread(new Runnable() {
278 @Override
279 public void run() {
280 BasicSearchable search = BasicSearchable
281 .getSearchable(searchOn);
4357eb54 282
c499d79f
NR
283 if (tag != null) {
284 int maxPage = 0;
81acd363 285 try {
c499d79f 286 maxPage = search.searchPages(tag);
81acd363 287 } catch (IOException e) {
81acd363
NR
288 Instance.getTraceHandler().error(e);
289 }
4357eb54 290
c499d79f
NR
291 updatePages(page, maxPage);
292
293 if (page > 0) {
294 List<MetaData> metas = null;
295 List<SearchableTag> subtags = null;
296 int count;
297
298 if (tag.isLeaf()) {
299 try {
300 metas = search.search(tag, page);
301 } catch (IOException e) {
302 metas = new ArrayList<MetaData>();
303 Instance.getTraceHandler().error(e);
304 }
305 count = metas.size();
4357eb54 306 } else {
c499d79f
NR
307 subtags = tag.getChildren();
308 count = subtags.size();
309 }
310
311 if (item > 0) {
312 if (item <= count) {
313 if (metas != null) {
314 MetaData meta = metas.get(item - 1);
315 // TODO: select story
316 } else {
317 SearchableTag subtag = subtags
318 .get(item - 1);
319 // TODO: search on tag
320 }
321 }
4357eb54 322 }
4357eb54
NR
323 }
324 }
c499d79f 325 setWaitingScreen(false);
4357eb54 326 }
c499d79f 327 }).start();
4357eb54
NR
328 }
329
330 /**
331 * Process the given action in the main Swing UI thread.
332 * <p>
333 * The code will make sure the current thread is the main UI thread and, if
334 * not, will switch to it before executing the runnable.
335 * <p>
336 * Synchronous operation.
337 *
338 * @param run
339 * the action to run
340 */
c499d79f 341 private void inUi(final Runnable run) {
4357eb54
NR
342 if (EventQueue.isDispatchThread()) {
343 run.run();
344 } else {
345 try {
346 EventQueue.invokeAndWait(run);
347 } catch (InterruptedException e) {
348 Instance.getTraceHandler().error(e);
349 } catch (InvocationTargetException e) {
350 Instance.getTraceHandler().error(e);
351 }
352 }
353 }
c499d79f
NR
354
355 private void setWaitingScreen(final boolean waiting) {
356 inUi(new Runnable() {
357 @Override
358 public void run() {
359 GuiReaderSearch.this.setEnabled(!waiting);
08e2185a
NR
360 books.setEnabled(!waiting);
361 submitKeywords.setEnabled(!waiting);
c499d79f
NR
362 }
363 });
364 }
4357eb54 365}