1 package be
.nikiroo
.fanfix
.reader
.ui
;
3 import java
.awt
.BorderLayout
;
4 import java
.awt
.Component
;
5 import java
.awt
.EventQueue
;
6 import java
.awt
.event
.ActionEvent
;
7 import java
.awt
.event
.ActionListener
;
8 import java
.lang
.reflect
.InvocationTargetException
;
9 import java
.util
.ArrayList
;
10 import java
.util
.List
;
12 import javax
.swing
.JComboBox
;
13 import javax
.swing
.JFrame
;
14 import javax
.swing
.JLabel
;
15 import javax
.swing
.JPanel
;
16 import javax
.swing
.JScrollPane
;
18 import be
.nikiroo
.fanfix
.Instance
;
19 import be
.nikiroo
.fanfix
.data
.MetaData
;
20 import be
.nikiroo
.fanfix
.reader
.ui
.GuiReaderBook
.BookActionListener
;
21 import be
.nikiroo
.fanfix
.searchable
.BasicSearchable
;
22 import be
.nikiroo
.fanfix
.searchable
.SearchableTag
;
23 import be
.nikiroo
.fanfix
.supported
.SupportType
;
26 * This frame will allow you to search through the supported websites for new
31 // JCombobox<E> not 1.6 compatible
32 @SuppressWarnings({ "unchecked", "rawtypes" })
33 public class GuiReaderSearchFrame
extends JFrame
{
34 private static final long serialVersionUID
= 1L;
36 private List
<SupportType
> supportTypes
;
38 private JComboBox comboSupportTypes
;
39 private ActionListener comboSupportTypesListener
;
40 private GuiReaderSearchByPanel searchPanel
;
41 private GuiReaderNavBar navbar
;
43 private boolean seeWordcount
;
44 private GuiReaderGroup books
;
46 public GuiReaderSearchFrame(final GuiReader reader
) {
47 super("Browse stories");
48 setLayout(new BorderLayout());
51 supportTypes
= new ArrayList
<SupportType
>();
52 supportTypes
.add(null);
53 for (SupportType type
: SupportType
.values()) {
54 if (BasicSearchable
.getSearchable(type
) != null) {
55 supportTypes
.add(type
);
59 comboSupportTypes
= new JComboBox(
60 supportTypes
.toArray(new SupportType
[] {}));
62 comboSupportTypesListener
= new ActionListener() {
64 public void actionPerformed(ActionEvent e
) {
65 final SupportType support
= (SupportType
) comboSupportTypes
68 new Thread(new Runnable() {
72 updateSupportType(support
);
80 comboSupportTypes
.addActionListener(comboSupportTypesListener
);
82 JPanel searchSites
= new JPanel(new BorderLayout());
83 searchSites
.add(comboSupportTypes
, BorderLayout
.CENTER
);
84 searchSites
.add(new JLabel(" " + "Website : "), BorderLayout
.WEST
);
86 searchPanel
= new GuiReaderSearchByPanel(
87 new GuiReaderSearchByPanel
.Waitable() {
89 public void setWaiting(boolean waiting
) {
90 GuiReaderSearchFrame
.this.setWaiting(waiting
);
94 public void fireEvent() {
95 updatePages(searchPanel
.getPage(),
96 searchPanel
.getMaxPage());
97 List
<GuiReaderBookInfo
> infos
= new ArrayList
<GuiReaderBookInfo
>();
98 for (MetaData meta
: searchPanel
.getStories()) {
99 infos
.add(GuiReaderBookInfo
.fromMeta(meta
));
102 int page
= searchPanel
.getPage();
107 int max
= searchPanel
.getMaxPage();
110 navbar
.setIndex(page
);
115 int item
= searchPanel
.getStoryItem();
116 if (item
> 0 && item
<= books
.getBooksCount()) {
117 books
.setSelectedBook(item
- 1, false);
122 JPanel top
= new JPanel(new BorderLayout());
123 top
.add(searchSites
, BorderLayout
.NORTH
);
124 top
.add(searchPanel
, BorderLayout
.CENTER
);
126 add(top
, BorderLayout
.NORTH
);
128 books
= new GuiReaderGroup(reader
, null, null);
129 books
.setActionListener(new BookActionListener() {
131 public void select(GuiReaderBook book
) {
135 public void popupRequested(GuiReaderBook book
, Component target
,
140 public void action(GuiReaderBook book
) {
141 new GuiReaderSearchAction(reader
.getLibrary(), book
.getInfo())
145 JScrollPane scroll
= new JScrollPane(books
);
146 scroll
.getVerticalScrollBar().setUnitIncrement(16);
147 add(scroll
, BorderLayout
.CENTER
);
149 navbar
= new GuiReaderNavBar(-1, -1) {
150 private static final long serialVersionUID
= 1L;
153 protected String
computeLabel(int index
, int min
, int max
) {
157 return super.computeLabel(index
, min
, max
);
161 navbar
.addActionListener(new ActionListener() {
163 public void actionPerformed(ActionEvent e
) {
164 searchPanel
.setPage(navbar
.getIndex());
168 add(navbar
, BorderLayout
.SOUTH
);
172 * Update the {@link SupportType} currently displayed to the user.
174 * Will also cause a search for the new base tags of the given support if
177 * This operation can be long and should be run outside the UI thread.
180 * the new {@link SupportType}
182 private void updateSupportType(final SupportType supportType
) {
183 inUi(new Runnable() {
189 .removeActionListener(comboSupportTypesListener
);
190 comboSupportTypes
.setSelectedItem(supportType
);
191 comboSupportTypes
.addActionListener(comboSupportTypesListener
);
195 searchPanel
.setSupportType(supportType
);
199 * Update the pages and the lined buttons currently displayed on screen.
201 * Those are the same pages and maximum pages used by
202 * {@link GuiReaderSearchByPanel#search(String, int, int)} and
203 * {@link GuiReaderSearchByPanel#searchTag(SearchableTag, int, int)}.
206 * the current page of results
208 * the maximum number of pages of results
210 private void updatePages(final int page
, final int maxPage
) {
211 inUi(new Runnable() {
216 navbar
.setMax(maxPage
);
217 navbar
.setIndex(page
);
227 * Update the currently displayed books.
232 private void updateBooks(final List
<GuiReaderBookInfo
> infos
) {
233 inUi(new Runnable() {
236 books
.refreshBooks(infos
, seeWordcount
);
242 * Search for the given terms on the currently selected searchable. This
243 * will update the displayed books if needed.
245 * This operation is asynchronous.
248 * the keywords to search for
250 * the page of results to load
252 * the item to select (or 0 for none by default)
254 public void search(final SupportType searchOn
, final String keywords
,
255 final int page
, final int item
) {
257 new Thread(new Runnable() {
261 updateSupportType(searchOn
);
262 searchPanel
.search(keywords
, page
, item
);
271 * Search for the given tag on the currently selected searchable. This will
272 * update the displayed books if needed.
274 * If the tag contains children tags, those will be displayed so you can
275 * select them; if the tag is a leaf tag, the linked stories will be
278 * This operation is asynchronous.
281 * the tag to search for, or NULL for base tags
283 * the page of results to load
285 * the item to select (or 0 for none by default)
287 public void searchTag(final SupportType searchOn
, final int page
,
288 final int item
, final SearchableTag tag
) {
290 new Thread(new Runnable() {
294 updateSupportType(searchOn
);
295 searchPanel
.searchTag(tag
, page
, item
);
304 * Process the given action in the main Swing UI thread.
306 * The code will make sure the current thread is the main UI thread and, if
307 * not, will switch to it before executing the runnable.
309 * Synchronous operation.
314 static void inUi(final Runnable run
) {
315 if (EventQueue
.isDispatchThread()) {
319 EventQueue
.invokeAndWait(run
);
320 } catch (InterruptedException e
) {
322 } catch (InvocationTargetException e
) {
329 * An error occurred, inform the user and/or log the error.
334 static void error(Exception e
) {
335 Instance
.getTraceHandler().error(e
);
339 * An error occurred, inform the user and/or log the error.
344 static void error(String e
) {
345 Instance
.getTraceHandler().error(e
);
349 * Enables or disables this component, depending on the value of the
350 * parameter <code>b</code>. An enabled component can respond to user input
351 * and generate events. Components are enabled initially by default.
353 * Disabling this component will also affect its children.
356 * If <code>true</code>, this component is enabled; otherwise
357 * this component is disabled
360 public void setEnabled(boolean b
) {
363 searchPanel
.setEnabled(b
);
367 * Set the item in wait mode, blocking it from accepting UI input.
370 * TRUE for wait more, FALSE to restore normal mode
372 private void setWaiting(final boolean waiting
) {
373 inUi(new Runnable() {
376 GuiReaderSearchFrame
.this.setEnabled(!waiting
);