Commit | Line | Data |
---|---|---|
6628131d NR |
1 | package be.nikiroo.fanfix.reader.ui; |
2 | ||
3 | import java.awt.BorderLayout; | |
4 | import java.awt.event.ActionEvent; | |
5 | import java.awt.event.ActionListener; | |
6 | import java.util.ArrayList; | |
7 | import java.util.List; | |
8 | ||
9 | import javax.swing.JPanel; | |
10 | import javax.swing.JTabbedPane; | |
11 | import javax.swing.event.ChangeEvent; | |
12 | import javax.swing.event.ChangeListener; | |
13 | ||
14 | import be.nikiroo.fanfix.data.MetaData; | |
15 | import be.nikiroo.fanfix.searchable.BasicSearchable; | |
16 | import be.nikiroo.fanfix.searchable.SearchableTag; | |
17 | import be.nikiroo.fanfix.supported.SupportType; | |
18 | ||
19 | /** | |
20 | * This panel represents a search panel that works for keywords and tags based | |
21 | * searches. | |
22 | * | |
23 | * @author niki | |
24 | */ | |
25 | public class GuiReaderSearchByPanel extends JPanel { | |
26 | private static final long serialVersionUID = 1L; | |
27 | ||
28 | private int actionEventId = ActionEvent.ACTION_FIRST; | |
29 | ||
30 | private Waitable waitable; | |
31 | ||
32 | private boolean searchByTags; | |
33 | ||
34 | private JTabbedPane searchTabs; | |
35 | private GuiReaderSearchByNamePanel byName; | |
36 | private GuiReaderSearchByTagPanel byTag; | |
37 | ||
38 | private List<ActionListener> actions = new ArrayList<ActionListener>(); | |
39 | ||
40 | public interface Waitable { | |
41 | public void setWaiting(boolean waiting); | |
42 | } | |
43 | ||
44 | // will throw illegalArgEx if bad support type, NULL allowed | |
45 | public GuiReaderSearchByPanel(final SupportType supportType, | |
46 | Waitable waitable) { | |
47 | setLayout(new BorderLayout()); | |
48 | ||
49 | this.waitable = waitable; | |
50 | searchByTags = false; | |
51 | ||
52 | Runnable fireEvent = new Runnable() { | |
53 | @Override | |
54 | public void run() { | |
55 | fireAction(); | |
56 | } | |
57 | }; | |
58 | ||
59 | byName = new GuiReaderSearchByNamePanel(fireEvent); | |
60 | byTag = new GuiReaderSearchByTagPanel(fireEvent); | |
61 | ||
62 | searchTabs = new JTabbedPane(); | |
63 | searchTabs.addTab("By name", byName); | |
64 | searchTabs.addTab("By tags", byTag); | |
65 | searchTabs.addChangeListener(new ChangeListener() { | |
66 | @Override | |
67 | public void stateChanged(ChangeEvent e) { | |
68 | searchByTags = (searchTabs.getSelectedComponent() == byTag); | |
69 | } | |
70 | }); | |
71 | ||
72 | add(searchTabs, BorderLayout.CENTER); | |
73 | updateSearchBy(searchByTags); | |
74 | setSupportType(supportType); | |
75 | } | |
76 | ||
77 | public void setSupportType(SupportType supportType) { | |
78 | BasicSearchable searchable = BasicSearchable.getSearchable(supportType); | |
79 | if (searchable == null && supportType != null) { | |
80 | throw new java.lang.IllegalArgumentException( | |
81 | "Unupported support type: " + supportType); | |
82 | } | |
83 | ||
84 | byName.setSearchable(searchable); | |
85 | byTag.setSearchable(searchable); | |
86 | } | |
87 | ||
88 | public int getPage() { | |
89 | if (!searchByTags) { | |
90 | return byName.getPage(); | |
91 | } | |
92 | ||
93 | return byTag.getPage(); | |
94 | } | |
95 | ||
96 | public int getMaxPage() { | |
97 | if (!searchByTags) { | |
98 | return byName.getMaxPage(); | |
99 | } | |
100 | ||
101 | return byTag.getMaxPage(); | |
102 | } | |
103 | ||
104 | // throw outOfBounds if needed | |
105 | public void setPage(int page) { | |
106 | if (searchByTags) { | |
107 | searchTag(byTag.getCurrentTag(), page, 0); | |
108 | } else { | |
109 | search(byName.getCurrentKeywords(), page, 0); | |
110 | } | |
111 | } | |
112 | ||
113 | // actions will be fired in UIthread | |
114 | public void addActionListener(ActionListener action) { | |
115 | actions.add(action); | |
116 | } | |
117 | ||
118 | public boolean removeActionListener(ActionListener action) { | |
119 | return actions.remove(action); | |
120 | } | |
121 | ||
122 | public List<MetaData> getStories() { | |
123 | if (!searchByTags) { | |
124 | return byName.getStories(); | |
125 | } | |
126 | ||
127 | return byTag.getStories(); | |
128 | } | |
129 | ||
130 | // selected item or 0 if none ! one-based ! | |
131 | public int getStoryItem() { | |
132 | if (!searchByTags) { | |
133 | return byName.getStoryItem(); | |
134 | } | |
135 | ||
136 | return byTag.getStoryItem(); | |
137 | } | |
138 | ||
139 | private void fireAction() { | |
140 | GuiReaderSearchFrame.inUi(new Runnable() { | |
141 | @Override | |
142 | public void run() { | |
143 | ActionEvent ae = new ActionEvent(GuiReaderSearchByPanel.this, | |
144 | actionEventId, "stories found"); | |
145 | ||
146 | actionEventId++; | |
147 | if (actionEventId > ActionEvent.ACTION_LAST) { | |
148 | actionEventId = ActionEvent.ACTION_FIRST; | |
149 | } | |
150 | ||
151 | for (ActionListener action : actions) { | |
152 | try { | |
153 | action.actionPerformed(ae); | |
154 | } catch (Exception e) { | |
155 | GuiReaderSearchFrame.error(e); | |
156 | } | |
157 | } | |
158 | } | |
159 | }); | |
160 | } | |
161 | ||
162 | private void updateSearchBy(final boolean byTag) { | |
163 | GuiReaderSearchFrame.inUi(new Runnable() { | |
164 | @Override | |
165 | public void run() { | |
166 | if (!byTag) { | |
167 | searchTabs.setSelectedIndex(0); | |
168 | } else { | |
169 | searchTabs.setSelectedIndex(1); | |
170 | } | |
171 | } | |
172 | }); | |
173 | } | |
174 | ||
175 | // slow, start in UI mode | |
176 | public void search(final String keywords, final int page, final int item) { | |
177 | waitable.setWaiting(true); | |
178 | updateSearchBy(false); | |
179 | new Thread(new Runnable() { | |
180 | @Override | |
181 | public void run() { | |
182 | try { | |
183 | byName.search(keywords, page, item); | |
184 | fireAction(); | |
185 | } finally { | |
186 | waitable.setWaiting(false); | |
187 | } | |
188 | } | |
189 | }).start(); | |
190 | } | |
191 | ||
192 | // slow, start in UI mode | |
193 | // tag: null = base tags | |
194 | public void searchTag(final SearchableTag tag, final int page, | |
195 | final int item) { | |
196 | waitable.setWaiting(true); | |
197 | updateSearchBy(true); | |
198 | new Thread(new Runnable() { | |
199 | @Override | |
200 | public void run() { | |
201 | try { | |
202 | ||
203 | byTag.searchTag(tag, page, item); | |
204 | fireAction(); | |
205 | } finally { | |
206 | waitable.setWaiting(false); | |
207 | } | |
208 | } | |
209 | }).start(); | |
210 | } | |
211 | ||
212 | /** | |
213 | * Enables or disables this component, depending on the value of the | |
214 | * parameter <code>b</code>. An enabled component can respond to user input | |
215 | * and generate events. Components are enabled initially by default. | |
216 | * <p> | |
217 | * Disabling this component will also affect its children. | |
218 | * | |
219 | * @param b | |
220 | * If <code>true</code>, this component is enabled; otherwise | |
221 | * this component is disabled | |
222 | */ | |
223 | @Override | |
224 | public void setEnabled(boolean b) { | |
225 | super.setEnabled(b); | |
226 | searchTabs.setEnabled(b); | |
227 | byName.setEnabled(b); | |
228 | byTag.setEnabled(b); | |
229 | } | |
230 | } |