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);
150 // TODO: reset all
151 }
152 }
153
154 private void updateSearchBy(final boolean byTag) {
155 if (byTag != this.searchByTags) {
156 inUi(new Runnable() {
157 @Override
158 public void run() {
159 if (!byTag) {
160 searchTabs.setSelectedIndex(0);
161 } else {
162 searchTabs.setSelectedIndex(1);
163 }
164 }
165 });
166 }
167 }
168
169 private void updatePages(final int page, final Integer maxPage) {
170 inUi(new Runnable() {
171 @Override
172 public void run() {
173 GuiReaderSearch.this.page = page;
174 GuiReaderSearch.this.maxPage = maxPage;
175 // TODO: gui
176 System.out.println("page: " + page);
177 System.out.println("max page: " + maxPage);
178 }
179 });
180 }
181
08e2185a 182 // cannot be NULL
81acd363 183 private void updateKeywords(final String keywords) {
08e2185a
NR
184 if (!keywords.equals(this.keywords)) {
185 inUi(new Runnable() {
186 @Override
187 public void run() {
188 GuiReaderSearch.this.keywords = keywords;
189 keywordsField.setText(keywords);
190 }
191 });
192 }
81acd363
NR
193 }
194
195 // can be NULL
196 private void updateTags(final SearchableTag tag) {
197 inUi(new Runnable() {
198 @Override
199 public void run() {
200 // TODO
201 }
202 });
203 }
204
205 private void updateBooks(final List<GuiReaderBookInfo> infos) {
c499d79f 206 setWaitingScreen(true);
81acd363
NR
207 inUi(new Runnable() {
208 @Override
209 public void run() {
210 books.refreshBooks(infos, seeWordcount);
c499d79f 211 setWaitingScreen(false);
81acd363
NR
212 }
213 });
214 }
215
216 // item 0 = no selection, else = default selection
4357eb54
NR
217 public void search(final SupportType searchOn, final String keywords,
218 final int page, final int item) {
81acd363 219
08e2185a
NR
220 setWaitingScreen(true);
221
81acd363
NR
222 updateSupportType(searchOn);
223 updateSearchBy(false);
224 updateKeywords(keywords);
225 updatePages(page, maxPage);
4357eb54
NR
226
227 new Thread(new Runnable() {
228 @Override
229 public void run() {
230 BasicSearchable search = BasicSearchable
231 .getSearchable(searchOn);
232
233 if (page <= 0) {
234 int maxPage = -1;
235 try {
236 maxPage = search.searchPages(keywords);
237 } catch (IOException e) {
238 Instance.getTraceHandler().error(e);
239 }
240 updateBooks(new ArrayList<GuiReaderBookInfo>());
241 updatePages(0, maxPage);
242 } else {
243 List<GuiReaderBookInfo> infos = new ArrayList<GuiReaderBookInfo>();
244 try {
245 for (MetaData meta : search.search(keywords, page)) {
246 infos.add(GuiReaderBookInfo.fromMeta(meta));
247 }
248 } catch (IOException e) {
249 Instance.getTraceHandler().error(e);
250 }
251
252 updateBooks(infos);
253 updatePages(page, maxPage);
254
255 // ! 1-based index !
256 if (item > 0 && item <= books.getBooksCount()) {
257 // TODO: "click" on item ITEM
258 }
259 }
08e2185a
NR
260
261 setWaitingScreen(false);
4357eb54
NR
262 }
263 }).start();
264 }
265
c499d79f
NR
266 public void searchTag(final SupportType searchOn, final int page,
267 final int item, final SearchableTag tag) {
268
269 setWaitingScreen(true);
4357eb54 270
81acd363
NR
271 updateSupportType(searchOn);
272 updateSearchBy(true);
273 updateTags(tag);
274 updatePages(page, maxPage);
4357eb54 275
c499d79f
NR
276 new Thread(new Runnable() {
277 @Override
278 public void run() {
279 BasicSearchable search = BasicSearchable
280 .getSearchable(searchOn);
4357eb54 281
c499d79f
NR
282 if (tag != null) {
283 int maxPage = 0;
81acd363 284 try {
c499d79f 285 maxPage = search.searchPages(tag);
81acd363 286 } catch (IOException e) {
81acd363
NR
287 Instance.getTraceHandler().error(e);
288 }
4357eb54 289
c499d79f
NR
290 updatePages(page, maxPage);
291
292 if (page > 0) {
293 List<MetaData> metas = null;
294 List<SearchableTag> subtags = null;
295 int count;
296
297 if (tag.isLeaf()) {
298 try {
299 metas = search.search(tag, page);
300 } catch (IOException e) {
301 metas = new ArrayList<MetaData>();
302 Instance.getTraceHandler().error(e);
303 }
304 count = metas.size();
4357eb54 305 } else {
c499d79f
NR
306 subtags = tag.getChildren();
307 count = subtags.size();
308 }
309
310 if (item > 0) {
311 if (item <= count) {
312 if (metas != null) {
313 MetaData meta = metas.get(item - 1);
314 // TODO: select story
315 } else {
316 SearchableTag subtag = subtags
317 .get(item - 1);
318 // TODO: search on tag
319 }
320 }
4357eb54 321 }
4357eb54
NR
322 }
323 }
c499d79f 324 setWaitingScreen(false);
4357eb54 325 }
c499d79f 326 }).start();
4357eb54
NR
327 }
328
329 /**
330 * Process the given action in the main Swing UI thread.
331 * <p>
332 * The code will make sure the current thread is the main UI thread and, if
333 * not, will switch to it before executing the runnable.
334 * <p>
335 * Synchronous operation.
336 *
337 * @param run
338 * the action to run
339 */
c499d79f 340 private void inUi(final Runnable run) {
4357eb54
NR
341 if (EventQueue.isDispatchThread()) {
342 run.run();
343 } else {
344 try {
345 EventQueue.invokeAndWait(run);
346 } catch (InterruptedException e) {
347 Instance.getTraceHandler().error(e);
348 } catch (InvocationTargetException e) {
349 Instance.getTraceHandler().error(e);
350 }
351 }
352 }
c499d79f
NR
353
354 private void setWaitingScreen(final boolean waiting) {
355 inUi(new Runnable() {
356 @Override
357 public void run() {
358 GuiReaderSearch.this.setEnabled(!waiting);
08e2185a
NR
359 books.setEnabled(!waiting);
360 submitKeywords.setEnabled(!waiting);
c499d79f
NR
361 }
362 });
363 }
4357eb54 364}