1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap.gui;
21
22 import java.awt.BorderLayout;
23 import java.awt.FlowLayout;
24 import java.awt.GridBagConstraints;
25 import java.awt.GridBagLayout;
26 import java.awt.event.ActionEvent;
27 import java.awt.event.ActionListener;
28 import java.awt.event.ItemEvent;
29 import java.awt.event.ItemListener;
30 import java.util.Hashtable;
31 import javax.swing.*;
32 import javax.swing.Action;
33 import javax.swing.ComboBoxModel;
34 import javax.swing.JCheckBox;
35 import javax.swing.JComboBox;
36 import javax.swing.JPanel;
37 import org.xnap.XNap;
38 import org.xnap.gui.component.EraseButton;
39 import org.xnap.gui.component.HistoryComboBox;
40 import org.xnap.gui.component.RangeBox;
41 import org.xnap.gui.component.XNapButton;
42 import org.xnap.gui.list.SearchProviderListCellRenderer;
43 import org.xnap.gui.shortcut.ShortcutManager;
44 import org.xnap.gui.util.FocusHandler;
45 import org.xnap.gui.util.GUIHelper;
46 import org.xnap.gui.util.GridBagHelper;
47 import org.xnap.gui.util.IconHelper;
48 import org.xnap.search.DefaultSearchFilter;
49 import org.xnap.search.LibrarySearch;
50 import org.xnap.search.MediaType;
51 import org.xnap.search.Search;
52 import org.xnap.search.SearchContainer;
53 import org.xnap.search.SearchFilter;
54 import org.xnap.search.SearchManager;
55 import org.xnap.search.SearchProvider;
56 import org.xnap.search.SearchProviderContainer;
57 import org.xnap.util.Preferences;
58
59 /***
60 * This class provides a panel with widgets to enter search queries
61 * and to set search options. The queries are passed to the
62 * {@link xnap.search.SearchManager SearchManager}.
63 */
64 public class AdvancedSearchQueryPanel extends JPanel
65 {
66
67
68
69 public static final int DEFAULT_UNIT_INDEX = 2;
70
71 public static final String UNITS[] = {
72 XNap.tr("B"), XNap.tr("KB"), XNap.tr("MB"), XNap.tr("GB")
73 };
74
75 public static final long FACTORS[] = {
76 1, 1024, 1024 * 1024, 1024 * 1024 * 1024
77 };
78
79
80
81
82 protected static Preferences prefs = Preferences.getInstance();
83
84 private HistoryComboBox jcbSearch;
85 private JComboBox jcbMediaType;
86 private RangeBox rbFilesize;
87 private JComboBox jcbFilesizeUnit;
88 private JComboBox jcbNetwork;
89 private JCheckBox jcbLocal;
90
91 private JPanel jpOptions;
92
93 private SearchProviderContainer spcNone;
94 private SearchProviderContainer spcAll;
95
96 private QueryAction acQuery = new QueryAction();
97
98 /***
99 * Maps {@link SearchProvider} objets to extra {@link JPanel}
100 * objects for additonal options.
101 */
102 private Hashtable panelByProvider = new Hashtable();
103
104 private SearchOptionsPanel currentOptionsPanel;
105
106
107
108 /***
109 * Constructs the search query panel.
110 *
111 * @param model model used by the HistoryComboBox
112 */
113 public AdvancedSearchQueryPanel(ComboBoxModel model)
114 {
115 setLayout(new GridBagLayout());
116
117
118 GridBagHelper.add(this, GUIHelper.createSeparator(XNap.tr("Text")));
119
120
121
122
123
124
125 EraseButton jbErase = new EraseButton();
126 GridBagHelper.addComponent(this, jbErase, GridBagConstraints.WEST);
127 ShortcutManager.getInstance().add(jbErase.getAction(), this);
128
129
130 jcbSearch = new HistoryComboBox(model, 20);
131 jcbSearch.setPreferences("search");
132 jcbSearch.addItemListener(new HistorySelectionListener());
133 GUIHelper.bindEnterKeyLocally(jcbSearch.getTextField(), acQuery);
134 jbErase.setTextField(jcbSearch.getTextField());
135 GridBagHelper.add(this, jcbSearch);
136
137
138 jpOptions = new JPanel(new GridBagLayout());
139 jpOptions.setBorder
140 (GUIHelper.createDefaultBorder(XNap.tr("Options")));
141 GridBagHelper.add(this, jpOptions);
142
143
144 JLabel l = GridBagHelper.addLabel(jpOptions, XNap.tr("Media Type"));
145 jcbMediaType = new JComboBox();
146 l.setLabelFor(jcbMediaType);
147 GridBagHelper.add(jpOptions, jcbMediaType);
148
149
150 l = GridBagHelper.addLabel(jpOptions, XNap.tr("Network"));
151 jcbNetwork = new JComboBox();
152 l.setLabelFor(jcbNetwork);
153 jcbNetwork.setRenderer(new SearchProviderListCellRenderer());
154 spcNone = new SearchProviderContainer(XNap.tr("None"));
155 jcbNetwork.addItem(spcNone);
156 spcAll = new SearchProviderContainer(XNap.tr("All"));
157 jcbNetwork.addItem(spcAll);
158 jcbNetwork.setSelectedIndex(1);
159 jcbNetwork.addActionListener(new ProviderListener());
160 GridBagHelper.add(jpOptions, jcbNetwork);
161
162
163 jcbLocal = new JCheckBox(XNap.tr("Local Library"));
164 jcbLocal.addActionListener(new QueryButtonListener());
165 GridBagHelper.add(jpOptions, jcbLocal);
166
167
168 JPanel jpFilesize = new JPanel(new GridBagLayout());
169 jpFilesize.setBorder
170 (GUIHelper.createDefaultBorder(XNap.tr("File size")));
171 GridBagHelper.add(this, jpFilesize);
172
173 rbFilesize = new RangeBox();
174 jcbFilesizeUnit = new JComboBox(UNITS);
175 jcbFilesizeUnit.setSelectedIndex(DEFAULT_UNIT_INDEX);
176 rbFilesize.setUnitComponent(jcbFilesizeUnit);
177 GridBagHelper.add(jpFilesize, rbFilesize, false);
178
179
180 jpOptions = new JPanel(new BorderLayout());
181 GridBagHelper.add(this, jpOptions);
182
183
184 JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.CENTER));
185 jpButtons.add(new XNapButton(acQuery));
186 GridBagHelper.add(this, jpButtons);
187
188 GridBagHelper.addVerticalSpacer(this);
189
190 acQuery.update();
191
192 addComponentListener(new FocusHandler(jcbSearch.getTextField()));
193 GUIHelper.setMnemonics(this);
194 }
195
196
197
198 public void addOptionsPanel(SearchProvider provider,
199 SearchOptionsPanel panel)
200 {
201 panelByProvider.put(provider, panel);
202 }
203
204 public void removeOptionsPanel(SearchProvider provider)
205 {
206 panelByProvider.remove(provider);
207 }
208
209 public Object[] getHistoryItems()
210 {
211 return jcbSearch.getHistoryItems();
212 }
213
214 void addToHistory(SearchFilter filter)
215 {
216 jcbSearch.addDistinctItemAtTop(filter);
217 }
218
219 DefaultSearchFilter getSearchFilter()
220 {
221 DefaultSearchFilter f = new DefaultSearchFilter();
222
223 f.put(SearchFilter.TEXT, jcbSearch.getText());
224 f.put(SearchFilter.MEDIA_TYPE, jcbMediaType.getSelectedItem());
225 long factor = FACTORS[jcbFilesizeUnit.getSelectedIndex()];
226 f.put(SearchFilter.MIN_FILESIZE,
227 (rbFilesize.getMinValue() != -1)
228 ? new Long(rbFilesize.getMinValue() * factor)
229 : null);
230 f.put(SearchFilter.MAX_FILESIZE,
231 (rbFilesize.getMaxValue() != -1)
232 ? new Long(rbFilesize.getMaxValue() * factor)
233 : null);
234
235 if (currentOptionsPanel != null) {
236 currentOptionsPanel.setOptions(f);
237 }
238
239
240 SearchProvider p = (SearchProvider)jcbNetwork.getSelectedItem();
241 f.put("searchProvider", p.getName());
242
243 return f;
244 }
245
246 void setSearchFilter(SearchFilter f)
247 {
248 setSearchFilter(f, true);
249 }
250
251 void setSearchFilter(SearchFilter f, boolean setText)
252 {
253 String name = (String)f.get("searchProvider");
254 if (name != null) {
255 boolean found = false;
256 for (int i = 0; i < jcbNetwork.getItemCount() && !found; i++) {
257 SearchProvider sp = (SearchProvider)jcbNetwork.getItemAt(i);
258 if (sp.getName().equals(name)) {
259 jcbNetwork.setSelectedItem(sp);
260 found = true;
261 }
262 }
263 if (!found) {
264 jcbNetwork.setSelectedItem(spcAll);
265 }
266 }
267
268 if (setText) {
269 jcbSearch.setText((String)f.get(SearchFilter.TEXT));
270 }
271 jcbMediaType.setSelectedItem(f.get(SearchFilter.MEDIA_TYPE));
272 }
273
274 /***
275 * Invoked by the {@link SearchPanel} when a {@link
276 * SearchProvider} has been added.
277 */
278 void providerAdded(SearchProvider provider)
279 {
280 spcAll.add(provider);
281 jcbNetwork.addItem(provider);
282
283 providerChanged();
284 }
285
286 /***
287 * Invoked by the {@link SearchPanel} when a {@link
288 * SearchProvider} has been removed.
289 */
290 void providerRemoved(SearchProvider provider)
291 {
292 spcAll.remove(provider);
293 jcbNetwork.removeItem(provider);
294
295 providerChanged();
296 }
297
298 private void providerChanged()
299 {
300 SearchProvider p = (SearchProvider)jcbNetwork.getSelectedItem();
301
302 jcbMediaType.removeAllItems();
303 MediaType[] types = p.getSupportedMediaTypes();
304 if (types != null) {
305 for (int i = 0; i < types.length; i++) {
306 jcbMediaType.addItem(types[i]);
307 }
308 }
309
310 if (currentOptionsPanel != null) {
311 jpOptions.remove(currentOptionsPanel.getComponent());
312 }
313
314 currentOptionsPanel = (SearchOptionsPanel)panelByProvider.get(p);
315 if (currentOptionsPanel != null) {
316 jpOptions.add(currentOptionsPanel.getComponent(),
317 BorderLayout.CENTER);
318 }
319
320 acQuery.update();
321 }
322
323 /***
324 * Performs a search.
325 */
326 private class QueryAction extends AbstractAction {
327
328 public QueryAction()
329 {
330 putValue(Action.NAME, XNap.tr("Query"));
331 putValue(Action.SHORT_DESCRIPTION, XNap.tr("Performs a search."));
332 putValue(IconHelper.XNAP_ICON, "filefind.png");
333 }
334
335 public void actionPerformed(ActionEvent event)
336 {
337 DefaultSearchFilter filter = getSearchFilter();
338
339 try {
340 filter.validate();
341 }
342 catch (Exception e) {
343 StatusBar.setText(e.getMessage());
344 return;
345 }
346
347 SearchProvider p = (SearchProvider)jcbNetwork.getSelectedItem();
348 Search search = p.search(filter);
349
350 if (jcbLocal.isSelected()) {
351 SearchContainer c = new SearchContainer(filter);
352 c.add(search);
353 c.add(new LibrarySearch(filter));
354 SearchManager.getInstance().handle(c);
355 }
356 else {
357 SearchManager.getInstance().handle(search);
358 }
359 }
360
361 public void update()
362 {
363 setEnabled(jcbLocal.isSelected()
364 || (spcAll.size() > 0
365 && jcbNetwork.getSelectedItem() != spcNone));
366 }
367
368 }
369
370 /***
371 * Updates the media types when a network is selected.
372 */
373 private class ProviderListener implements ActionListener
374 {
375 public void actionPerformed(ActionEvent event)
376 {
377 providerChanged();
378 }
379
380 }
381
382 /***
383 * Switches between advanced and simple view.
384 */
385 private class ShowSimpleAction extends AbstractAction {
386
387 public ShowSimpleAction()
388 {
389 putValue(Action.NAME, XNap.tr("Less Options"));
390 putValue(Action.SHORT_DESCRIPTION,
391 XNap.tr("Displays simple search options panel."));
392 putValue(IconHelper.XNAP_ICON, "2uparrow.png");
393 }
394
395 public void actionPerformed(ActionEvent event)
396 {
397 prefs.set("showAdvancedSearchOptions", "true");
398 }
399 }
400
401 /***
402 * Update the settings when the selected search filter object
403 * changes.
404 */
405 private class HistorySelectionListener implements ItemListener
406 {
407 public void itemStateChanged(ItemEvent event)
408 {
409 if (event.getStateChange() == ItemEvent.SELECTED) {
410 if (event.getItem() instanceof SearchFilter) {
411 setSearchFilter((SearchFilter)event.getItem(), false);
412 }
413 }
414 }
415 }
416
417 /***
418 * Disables the query button when no network is availabe and local search
419 * is not selected.
420 */
421 private class QueryButtonListener implements ActionListener
422 {
423 public void actionPerformed(ActionEvent event)
424 {
425 acQuery.update();
426 }
427
428 }
429
430 }
431