1 package be
.nikiroo
.fanfix
.reader
.ui
;
3 import java
.awt
.BorderLayout
;
5 import java
.awt
.Component
;
6 import java
.awt
.EventQueue
;
7 import java
.awt
.event
.ActionEvent
;
8 import java
.awt
.event
.ActionListener
;
9 import java
.io
.IOException
;
10 import java
.lang
.reflect
.InvocationTargetException
;
11 import java
.util
.ArrayList
;
12 import java
.util
.List
;
14 import javax
.swing
.BoxLayout
;
15 import javax
.swing
.JButton
;
16 import javax
.swing
.JComboBox
;
17 import javax
.swing
.JFrame
;
18 import javax
.swing
.JLabel
;
19 import javax
.swing
.JList
;
20 import javax
.swing
.JPanel
;
21 import javax
.swing
.JScrollPane
;
22 import javax
.swing
.JTabbedPane
;
23 import javax
.swing
.JTextField
;
24 import javax
.swing
.ListCellRenderer
;
26 import be
.nikiroo
.fanfix
.Instance
;
27 import be
.nikiroo
.fanfix
.data
.MetaData
;
28 import be
.nikiroo
.fanfix
.reader
.ui
.GuiReaderBook
.BookActionListener
;
29 import be
.nikiroo
.fanfix
.searchable
.BasicSearchable
;
30 import be
.nikiroo
.fanfix
.searchable
.SearchableTag
;
31 import be
.nikiroo
.fanfix
.supported
.SupportType
;
34 * This frame will allow you to search through the supported websites for new
39 // JCombobox<E> not 1.6 compatible
40 @SuppressWarnings({ "unchecked", "rawtypes" })
41 public class GuiReaderSearch
extends JFrame
{
42 private static final long serialVersionUID
= 1L;
44 private List
<SupportType
> supportTypes
;
45 private SupportType supportType
;
46 private boolean searchByTags
;
47 private String keywords
;
51 private JPanel tagBars
;
52 private List
<JComboBox
> combos
;
54 private JComboBox comboSupportTypes
;
55 private JTabbedPane searchTabs
;
56 private JTextField keywordsField
;
57 private JButton submitKeywords
;
59 private boolean seeWordcount
;
60 private GuiReaderGroup books
;
62 public GuiReaderSearch(final GuiReader reader
) {
63 super("Browse stories");
64 setLayout(new BorderLayout());
71 supportTypes
= new ArrayList
<SupportType
>();
72 for (SupportType type
: SupportType
.values()) {
73 if (BasicSearchable
.getSearchable(type
) != null) {
74 supportTypes
.add(type
);
77 supportType
= supportTypes
.isEmpty() ?
null : supportTypes
.get(0);
79 comboSupportTypes
= new JComboBox(
80 supportTypes
.toArray(new SupportType
[] {}));
81 comboSupportTypes
.addActionListener(new ActionListener() {
83 public void actionPerformed(ActionEvent e
) {
84 updateSupportType((SupportType
) comboSupportTypes
88 JPanel searchSites
= new JPanel(new BorderLayout());
89 searchSites
.add(comboSupportTypes
, BorderLayout
.CENTER
);
90 searchSites
.add(new JLabel(" " + "Website : "), BorderLayout
.WEST
);
92 searchTabs
= new JTabbedPane();
93 searchTabs
.addTab("By name", createByNameSearchPanel());
94 searchTabs
.addTab("By tags", createByTagSearchPanel());
96 JPanel top
= new JPanel(new BorderLayout());
97 top
.add(searchSites
, BorderLayout
.NORTH
);
98 top
.add(searchTabs
, BorderLayout
.CENTER
);
100 add(top
, BorderLayout
.NORTH
);
102 books
= new GuiReaderGroup(reader
, null, null);
103 books
.setActionListener(new BookActionListener() {
105 public void select(GuiReaderBook book
) {
109 public void popupRequested(GuiReaderBook book
, Component target
,
114 public void action(GuiReaderBook book
) {
115 new GuiReaderSearchAction(reader
.getLibrary(), book
.getInfo())
119 JScrollPane scroll
= new JScrollPane(books
);
120 scroll
.getVerticalScrollBar().setUnitIncrement(16);
121 add(scroll
, BorderLayout
.CENTER
);
126 private JPanel
createByNameSearchPanel() {
127 JPanel byName
= new JPanel(new BorderLayout());
129 keywordsField
= new JTextField();
130 byName
.add(keywordsField
, BorderLayout
.CENTER
);
132 submitKeywords
= new JButton("Search");
133 byName
.add(submitKeywords
, BorderLayout
.EAST
);
135 // TODO: ENTER -> search
137 submitKeywords
.addActionListener(new ActionListener() {
139 public void actionPerformed(ActionEvent e
) {
140 search(supportType
, keywordsField
.getText(), page
, 0);
147 private JPanel
createByTagSearchPanel() {
148 combos
= new ArrayList
<JComboBox
>();
150 JPanel byTag
= new JPanel();
151 tagBars
= new JPanel();
152 tagBars
.setLayout(new BoxLayout(tagBars
, BoxLayout
.Y_AXIS
));
153 byTag
.add(tagBars
, BorderLayout
.NORTH
);
158 private void updateSupportType(SupportType supportType
) {
159 if (supportType
!= this.supportType
) {
160 this.supportType
= supportType
;
161 comboSupportTypes
.setSelectedItem(supportType
);
167 private void updateSearchBy(final boolean byTag
) {
168 if (byTag
!= this.searchByTags
) {
169 inUi(new Runnable() {
173 searchTabs
.setSelectedIndex(0);
175 searchTabs
.setSelectedIndex(1);
182 private void updatePages(final int page
, final Integer maxPage
) {
183 inUi(new Runnable() {
186 GuiReaderSearch
.this.page
= page
;
187 GuiReaderSearch
.this.maxPage
= maxPage
;
189 System
.out
.println("page: " + page
);
190 System
.out
.println("max page: " + maxPage
);
196 private void updateKeywords(final String keywords
) {
197 if (!keywords
.equals(this.keywords
)) {
198 inUi(new Runnable() {
201 GuiReaderSearch
.this.keywords
= keywords
;
202 keywordsField
.setText(keywords
);
208 // update and reset the tagsbar
209 // can be NULL, for base tags
210 private void updateTags(final SearchableTag tag
) {
211 final List
<SearchableTag
> parents
= new ArrayList
<SearchableTag
>();
212 SearchableTag parent
= (tag
== null) ?
null : tag
;
213 while (parent
!= null) {
215 parent
= parent
.getParent();
218 inUi(new Runnable() {
221 tagBars
.invalidate();
225 // TODO: select the right one
227 SearchableTag selectedChild
= parents
.isEmpty() ?
null
228 : parents
.get(parents
.size() - 1);
229 addTagBar(BasicSearchable
.getSearchable(supportType
)
230 .getTags(), selectedChild
);
231 } catch (IOException e
) {
235 for (int i
= parents
.size() - 1; i
>= 0; i
--) {
236 SearchableTag selectedChild
= null;
238 selectedChild
= parents
.get(i
- 1);
240 SearchableTag parent
= parents
.get(i
);
241 addTagBar(parent
.getChildren(), selectedChild
);
249 private void updateBooks(final List
<GuiReaderBookInfo
> infos
) {
250 setWaitingScreen(true);
251 inUi(new Runnable() {
254 books
.refreshBooks(infos
, seeWordcount
);
255 setWaitingScreen(false);
260 private void addTagBar(List
<SearchableTag
> tags
,
261 final SearchableTag selected
) {
264 final int comboIndex
= combos
.size();
266 final JComboBox combo
= new JComboBox(
267 tags
.toArray(new SearchableTag
[] {}));
268 combo
.setSelectedItem(selected
);
270 final ListCellRenderer basic
= combo
.getRenderer();
272 combo
.setRenderer(new ListCellRenderer() {
274 public Component
getListCellRendererComponent(JList list
,
275 Object value
, int index
, boolean isSelected
,
276 boolean cellHasFocus
) {
278 Object displayValue
= value
;
279 if (value
instanceof SearchableTag
) {
280 displayValue
= ((SearchableTag
) value
).getName();
282 displayValue
= "Select a tag...";
283 cellHasFocus
= false;
287 Component rep
= basic
.getListCellRendererComponent(list
,
288 displayValue
, index
, isSelected
, cellHasFocus
);
291 rep
.setForeground(Color
.GRAY
);
298 combo
.addActionListener(new ActionListener() {
300 public void actionPerformed(ActionEvent e
) {
301 final SearchableTag tag
= (SearchableTag
) combo
304 while (comboIndex
+ 1 < combos
.size()) {
305 JComboBox combo
= combos
.remove(comboIndex
+ 1);
306 tagBars
.remove(combo
);
309 addTagBar(tag
, new Runnable() {
313 SearchableTag tag
= ((SearchableTag
) combo
315 if (tag
!= null && tag
.isLeaf()) {
316 BasicSearchable searchable
= BasicSearchable
317 .getSearchable(supportType
);
318 List
<MetaData
> metas
= new ArrayList
<MetaData
>();
320 metas
= searchable
.search(tag
, 1);
322 searchable
.searchPages(tag
), 0);
323 } catch (IOException e
) {
328 setWaitingScreen(false);
339 // async, add children of tag, NULL = base tags
340 private void addTagBar(final SearchableTag tag
, final Runnable inUi
) {
341 new Thread(new Runnable() {
344 BasicSearchable searchable
= BasicSearchable
345 .getSearchable(supportType
);
347 List
<SearchableTag
> children
= new ArrayList
<SearchableTag
>();
350 List
<SearchableTag
> baseTags
= searchable
.getTags();
352 } catch (IOException e
) {
357 searchable
.fillTag(tag
);
358 } catch (IOException e
) {
363 children
= tag
.getChildren();
369 final List
<SearchableTag
> fchildren
= children
;
370 inUi(new Runnable() {
373 if (fchildren
!= null) {
374 addTagBar(fchildren
, tag
);
386 // item 0 = no selection, else = default selection
387 public void search(final SupportType searchOn
, final String keywords
,
388 final int page
, final int item
) {
390 setWaitingScreen(true);
392 updateSupportType(searchOn
);
393 updateSearchBy(false);
394 updateKeywords(keywords
);
395 updatePages(page
, maxPage
);
397 new Thread(new Runnable() {
400 BasicSearchable search
= BasicSearchable
401 .getSearchable(searchOn
);
405 maxPage
= search
.searchPages(keywords
);
406 } catch (IOException e
) {
411 updateBooks(new ArrayList
<GuiReaderBookInfo
>());
412 updatePages(0, maxPage
);
414 List
<MetaData
> results
;
416 results
= search
.search(keywords
, page
);
417 } catch (IOException e
) {
419 results
= new ArrayList
<MetaData
>();
422 search(results
, page
, maxPage
, item
);
425 if (item
> 0 && item
<= books
.getBooksCount()) {
426 // TODO: "click" on item ITEM
430 setWaitingScreen(false);
435 // tag: null = base tags
436 public void searchTag(final SupportType searchOn
, final int page
,
437 final int item
, final SearchableTag tag
) {
439 setWaitingScreen(true);
441 updateSupportType(searchOn
);
442 updateSearchBy(true);
444 updatePages(page
, maxPage
);
446 new Thread(new Runnable() {
449 BasicSearchable search
= BasicSearchable
450 .getSearchable(searchOn
);
455 } catch (IOException e
) {
461 maxPage
= search
.searchPages(tag
);
462 } catch (IOException e
) {
466 updatePages(page
, maxPage
);
469 List
<MetaData
> metas
= new ArrayList
<MetaData
>();
473 metas
= search
.search(tag
, page
);
474 } catch (IOException e
) {
478 List
<SearchableTag
> subtags
= tag
.getChildren();
479 if (item
> 0 && item
<= subtags
.size()) {
480 SearchableTag subtag
= subtags
.get(item
- 1);
482 metas
= search
.search(subtag
, page
);
483 maxPage
= subtag
.getPages();
484 } catch (IOException e
) {
490 updatePages(page
, maxPage
);
491 search(metas
, page
, maxPage
, item
);
495 setWaitingScreen(false);
500 // item 0 = no selection, else = default selection
501 public void search(final List
<MetaData
> results
, final int page
,
502 final int maxPage
, final int item
) {
504 updatePages(page
, maxPage
);
507 updateBooks(new ArrayList
<GuiReaderBookInfo
>());
508 updatePages(0, maxPage
);
510 List
<GuiReaderBookInfo
> infos
= new ArrayList
<GuiReaderBookInfo
>();
511 for (MetaData meta
: results
) {
512 infos
.add(GuiReaderBookInfo
.fromMeta(meta
));
518 if (item
> 0 && item
<= books
.getBooksCount()) {
519 // TODO: "click" on item ITEM
525 * Process the given action in the main Swing UI thread.
527 * The code will make sure the current thread is the main UI thread and, if
528 * not, will switch to it before executing the runnable.
530 * Synchronous operation.
535 private void inUi(final Runnable run
) {
536 if (EventQueue
.isDispatchThread()) {
540 EventQueue
.invokeAndWait(run
);
541 } catch (InterruptedException e
) {
543 } catch (InvocationTargetException e
) {
549 private void error(Exception e
) {
550 Instance
.getTraceHandler().error(e
);
553 private void setWaitingScreen(final boolean waiting
) {
554 inUi(new Runnable() {
557 GuiReaderSearch
.this.setEnabled(!waiting
);
558 books
.setEnabled(!waiting
);
559 submitKeywords
.setEnabled(!waiting
);