1 package com.melloware.jukes.gui.view.dialogs;
2
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.Dimension;
6 import java.awt.Frame;
7 import java.awt.Image;
8 import java.awt.event.ActionEvent;
9 import java.util.Collection;
10 import java.util.Iterator;
11
12 import javax.swing.AbstractAction;
13 import javax.swing.Action;
14 import javax.swing.DefaultListModel;
15 import javax.swing.JButton;
16 import javax.swing.JComponent;
17 import javax.swing.JList;
18 import javax.swing.JPanel;
19 import javax.swing.JScrollPane;
20 import javax.swing.JSplitPane;
21 import javax.swing.JTable;
22 import javax.swing.JTextField;
23 import javax.swing.ListSelectionModel;
24 import javax.swing.RowSorter;
25 import javax.swing.event.ListSelectionEvent;
26 import javax.swing.event.ListSelectionListener;
27 import javax.swing.table.TableModel;
28 import javax.swing.table.TableRowSorter;
29
30 import org.apache.commons.lang.StringUtils;
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33
34 import com.jgoodies.forms.builder.PanelBuilder;
35 import com.jgoodies.forms.factories.Borders;
36 import com.jgoodies.forms.factories.ButtonBarFactory;
37 import com.jgoodies.forms.layout.CellConstraints;
38 import com.jgoodies.forms.layout.FormLayout;
39 import com.jgoodies.uif.AbstractDialog;
40 import com.jgoodies.uif.application.Application;
41 import com.jgoodies.uif.panel.SimpleInternalFrame;
42 import com.jgoodies.uif.util.Resizer;
43 import com.jgoodies.uif.util.Worker;
44 import com.jgoodies.uifextras.panel.HeaderPanel;
45 import com.jgoodies.uifextras.util.UIFactory;
46 import com.melloware.jukes.exception.WebServiceException;
47 import com.melloware.jukes.file.FileUtil;
48 import com.melloware.jukes.gui.tool.Resources;
49 import com.melloware.jukes.gui.tool.Settings;
50 import com.melloware.jukes.gui.view.MainFrame;
51 import com.melloware.jukes.gui.view.component.AlbumImage;
52 import com.melloware.jukes.gui.view.component.EnhancedTableHeader;
53 import com.melloware.jukes.gui.view.component.ExportableTable;
54 import com.melloware.jukes.util.GuiUtil;
55 import com.melloware.jukes.util.MessageUtil;
56 import com.melloware.jukes.ws.AmazonItem;
57 import com.melloware.jukes.ws.AmazonSearch;
58
59
60
61
62
63
64
65
66
67
68 public final class WebSearchDialog
69 extends AbstractDialog {
70
71 private static final Log LOG = LogFactory.getLog(WebSearchDialog.class);
72 private final AlbumImage webImagePreview;
73 private AmazonItem selection;
74 private Collection selectedTracks;
75 private DefaultListModel listModel;
76 private final EnhancedTableHeader header;
77 private final ExportableTable resultsTable;
78 private Image selectedImage;
79 private JButton buttonApply;
80 private JButton buttonCancel;
81 private JButton buttonSearch;
82 private JButton buttonStop;
83 private JComponent buttonBar;
84 private JComponent splitPane;
85 private JList list;
86 private final JTextField artistField;
87 private final JTextField discField;
88 private Object[] results;
89 private String selectedArtist;
90 private String selectedDisc;
91 private String selectedYear;
92 private RowSorter<TableModel> sorter;
93 private WebSearchTableModel tableModel;
94 private Worker worker;
95
96
97
98
99
100
101 public WebSearchDialog(Frame owner, Settings settings) {
102 super(owner);
103 LOG.debug("Web Search Dialog created.");
104 artistField = new JTextField();
105 discField = new JTextField();
106 resultsTable = new ExportableTable();
107 resultsTable.setEvenColor(settings.getRowColorEven());
108 resultsTable.setOddColor(settings.getRowColorOdd());
109 header = new EnhancedTableHeader(resultsTable.getColumnModel(), resultsTable);
110 resultsTable.setTableHeader(header);
111 webImagePreview = new AlbumImage();
112 webImagePreview.setPreferredSize(new Dimension(100, 100));
113 this.setPreferredSize(new Dimension(720, 576));
114 }
115
116
117
118
119
120
121 public String getSelectedArtist() {
122 return FileUtil.capitalize(this.selectedArtist);
123 }
124
125
126
127
128
129
130 public String getSelectedDisc() {
131 return FileUtil.capitalize(this.selectedDisc);
132 }
133
134
135
136
137
138
139 public Image getSelectedImage() {
140 return this.selectedImage;
141 }
142
143
144
145
146
147
148 public Collection getSelectedTracks() {
149 return this.selectedTracks;
150 }
151
152
153
154
155
156
157 public String getSelectedYear() {
158 return this.selectedYear;
159 }
160
161
162
163
164
165
166 public void setSelectedArtist(String aSelectedArtist) {
167 this.selectedArtist = aSelectedArtist;
168 artistField.setText(this.selectedArtist);
169 }
170
171
172
173
174
175
176 public void setSelectedDisc(String aSelectedDisc) {
177 this.selectedDisc = StringUtils.substringBeforeLast(aSelectedDisc, " - ");
178 discField.setText(this.selectedDisc);
179 }
180
181
182
183
184
185
186 public void setSelectedImage(Image aSelectedImage) {
187 this.selectedImage = aSelectedImage;
188 }
189
190
191
192
193
194
195 public void setSelectedTracks(Collection aSelectedTracks) {
196 this.selectedTracks = aSelectedTracks;
197 }
198
199
200
201
202
203
204 public void setSelectedYear(String aSelectedYear) {
205 this.selectedYear = aSelectedYear;
206 }
207
208
209
210
211 public void doApply() {
212 LOG.debug("Select pressed.");
213 AmazonItem item = selection;
214 setSelectedArtist(item.getArtist());
215 setSelectedDisc(item.getDisc());
216 setSelectedYear(item.getReleaseYear());
217 setSelectedImage(item.getBestImage());
218 setSelectedTracks(item.getTracks());
219 super.doClose();
220 }
221
222
223
224
225 public void doCancel() {
226 LOG.debug("Cancel Pressed.");
227 super.doCancel();
228 }
229
230
231
232
233 public void doSearch() {
234 LOG.debug("Searching...");
235
236 if ((StringUtils.isBlank(artistField.getText())) && (StringUtils.isBlank(discField.getText()))) {
237 LOG.warn("Please select either an artist or disc or both.");
238 return;
239 }
240 GuiUtil.setBusyCursor(this, true);
241 buttonSearch.setEnabled(false);
242 buttonCancel.setEnabled(false);
243 buttonApply.setEnabled(false);
244 buttonStop.setEnabled(true);
245
246
247
248
249
250 worker = new Worker() {
251 public Object construct() {
252 return doWork();
253 }
254
255 public void finished() {
256 threadFinished(get());
257 }
258 };
259 worker.start();
260
261 }
262
263
264
265
266 public void doStop() {
267 LOG.debug("Stopping...");
268 GuiUtil.setBusyCursor(this, false);
269 worker.interrupt();
270 buttonSearch.setEnabled(true);
271 buttonCancel.setEnabled(true);
272 buttonStop.setEnabled(false);
273 }
274
275
276
277
278
279
280 protected JComponent buildContent() {
281 JPanel content = new JPanel(new BorderLayout());
282 JButton[] buttons = new JButton[2];
283 JButton button = createApplyButton();
284 button.setText(Resources.getString("label.Select"));
285 button.setEnabled(false);
286 buttonApply = button;
287 buttonCancel = createCancelButton();
288 buttonCancel.setText(Resources.getString("label.Cancel"));
289 buttons[0] = buttonApply;
290 buttons[1] = buttonCancel;
291 buttonBar = ButtonBarFactory.buildRightAlignedBar(buttons);
292 splitPane = buildSplitPane();
293 content.add(splitPane, BorderLayout.CENTER);
294 content.add(buttonBar, BorderLayout.SOUTH);
295 return content;
296 }
297
298
299
300
301
302
303 protected JComponent buildHeader() {
304 return new HeaderPanel(Resources.getString("label.WebSearch"),
305 Resources.getString("label.WebSearchMessage"),
306 Resources.WEB_SEARCH_ICON);
307 }
308
309
310
311
312
313
314 protected JComponent buildMainPanel() {
315 FormLayout layout = new FormLayout("fill:pref:grow", "p, p, p, p, p, p, p, p, p, p, p");
316 PanelBuilder builder = new PanelBuilder(layout);
317 builder.setDefaultDialogBorder();
318 CellConstraints cc = new CellConstraints();
319 int row = 1;
320 row++;
321 builder.add(buildCriteria(), cc.xy(1, row++));
322 builder.add(buildResultsPanel(), cc.xy(1, 7));
323 return builder.getPanel();
324 }
325
326
327
328
329
330
331 protected void resizeHook(JComponent component) {
332 Resizer.ONE2ONE.resizeDialogContent(component);
333 }
334
335
336
337
338
339
340 private JComponent buildCriteria() {
341 FormLayout layout = new FormLayout("right:max(14dlu;pref), fill:pref:grow", "4px, p, 4px, p, 4px, p, 4px");
342
343 layout.setRowGroups(new int[][] {
344 { 2, 4 }
345 });
346 PanelBuilder builder = new PanelBuilder(layout);
347 CellConstraints cc = new CellConstraints();
348
349 JButton[] buttons = new JButton[2];
350
351
352 Action search = new AbstractAction(Resources.getString("label.Search"), Resources.THREAD_START_ICON) {
353
354 public void actionPerformed(ActionEvent evt) {
355 doSearch();
356 }
357 };
358 buttonSearch = new JButton(search);
359
360 Action stop = new AbstractAction(Resources.getString("label.Stop"), Resources.THREAD_STOP_ICON) {
361
362 public void actionPerformed(ActionEvent evt) {
363 doStop();
364 }
365 };
366 buttonStop = new JButton(stop);
367 buttonStop.setEnabled(false);
368
369 buttons[0] = buttonSearch;
370 buttons[1] = buttonStop;
371 JPanel searchButtonBar = ButtonBarFactory.buildCenteredBar(buttons);
372
373 builder.addLabel(Resources.getString("label.artist") +": ", cc.xy(1, 2));
374 builder.add(artistField, cc.xy(2, 2));
375 builder.addLabel(Resources.getString("label.disc") +": ", cc.xy(1, 4));
376 builder.add(discField, cc.xy(2, 4));
377 builder.add(searchButtonBar, cc.xyw(1, 6, 2));
378 return builder.getPanel();
379 }
380
381
382
383
384
385
386 private JComponent buildResultsPanel() {
387 final Component dialog = this;
388
389 resultsTable.setShowGrid(false);
390 resultsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
391 resultsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
392
393 ListSelectionModel rowSM = resultsTable.getSelectionModel();
394 rowSM.addListSelectionListener(new ListSelectionListener() {
395 public void valueChanged(ListSelectionEvent e) {
396
397 if (e.getValueIsAdjusting()) {
398 return;
399 }
400
401 ListSelectionModel lsm = (ListSelectionModel)e.getSource();
402 if (lsm.isSelectionEmpty()) {
403 selection = null;
404 buttonApply.setEnabled(false);
405 webImagePreview.setImage(null);
406 listModel.removeAllElements();
407 } else {
408 GuiUtil.setBusyCursor(dialog, true);
409 try {
410 int selectedRow = resultsTable.getSelectedRow();
411 selectedRow = sorter.convertRowIndexToModel(selectedRow);
412 selection = (AmazonItem)results[selectedRow];
413 buttonApply.setEnabled(true);
414 webImagePreview.setImage(selection.getSmallestImage());
415 listModel.removeAllElements();
416 int count = 0;
417 for (Iterator iter = selection.getTracks().iterator(); iter.hasNext();) {
418 String element = (String)iter.next();
419 count++;
420 listModel.addElement(count + ". " + element);
421 }
422 } catch (Exception ex) {
423 final MainFrame mainFrame = (MainFrame) Application.getDefaultParentFrame();
424 LOG.error("RuntimeException", ex);
425 MessageUtil.showError(mainFrame, "RuntimeException");
426 } finally {
427 GuiUtil.setBusyCursor(dialog, false);
428 }
429 }
430 }
431 });
432
433
434 listModel = new DefaultListModel();
435 list = new JList(listModel);
436 list.setFocusable(false);
437 list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
438 list.setSelectedIndex(0);
439 list.setVisibleRowCount(7);
440 JScrollPane listScrollPane = UIFactory.createStrippedScrollPane(list);
441 listScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
442 listScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
443 JPanel previewPanel = new JPanel(new BorderLayout());
444 previewPanel.add(webImagePreview, BorderLayout.NORTH);
445 previewPanel.add(listScrollPane, BorderLayout.CENTER);
446 final SimpleInternalFrame previewer = new SimpleInternalFrame(Resources.getString("label.Preview"));
447 previewer.add(previewPanel);
448 previewer.setPreferredSize(new Dimension(150, 304));
449
450 JComponent resultsPane = UIFactory.createTablePanel(resultsTable);
451 resultsPane.setPreferredSize(new Dimension(300, 300));
452
453
454 FormLayout layout = new FormLayout("fill:pref:grow, right:max(14dlu;pref)", "p");
455 layout.setRowGroups(new int[][] {
456 { 1 }
457 });
458 PanelBuilder builder = new PanelBuilder(layout);
459 CellConstraints cc = new CellConstraints();
460 builder.add(resultsPane, cc.xy(1, 1));
461 builder.add(previewer, cc.xy(2, 1));
462 builder.getPanel().setPreferredSize(new Dimension(450, 300));
463 return builder.getPanel();
464 }
465
466
467
468
469
470 private JComponent buildSplitPane() {
471 splitPane = UIFactory.createStrippedSplitPane(JSplitPane.VERTICAL_SPLIT, buildCriteria(), buildResultsPanel(),
472 0.25);
473 splitPane.setPreferredSize(new Dimension(630, 470));
474 splitPane.setBorder(Borders.DIALOG_BORDER);
475 return splitPane;
476 }
477
478
479
480
481
482 private Object doWork() {
483 Object result = null;
484 try {
485
486 try {
487 result = AmazonSearch.findItemsByArtistDisc(artistField.getText(), discField.getText());
488 } catch (WebServiceException ex) {
489 String message = Resources.getString("messages.ErrorQueryingWeb") + "\n\n" + ex.getMessage();
490 LOG.error(message);
491 MessageUtil.showError(this, message);
492 throw new InterruptedException(message);
493 }
494
495 if (Thread.interrupted()) {
496 LOG.debug("Thread interrupted.");
497 throw new InterruptedException();
498 }
499
500 } catch (InterruptedException e) {
501
502 return result;
503 }
504 return result;
505 }
506
507
508
509
510
511
512 private void threadFinished(Object result) {
513 if (LOG.isDebugEnabled()) {
514 LOG.debug("Thread Finished");
515 }
516 buttonSearch.setEnabled(true);
517 buttonCancel.setEnabled(true);
518 buttonStop.setEnabled(false);
519 GuiUtil.setBusyCursor(this, false);
520
521 if (result == null) {
522 results = null;
523 tableModel = new WebSearchTableModel(results);
524 tableModel.setData(null);
525 tableModel.fireTableDataChanged();
526 } else {
527 final Collection items = (Collection)result;
528 results = items.toArray();
529 tableModel = new WebSearchTableModel(results);
530 sorter = new TableRowSorter<TableModel>(tableModel);
531 resultsTable.setModel(tableModel);
532 resultsTable.setRowSorter(sorter);
533 header.autoSizeColumns();
534 }
535
536 resultsTable.updateUI();
537 splitPane.updateUI();
538 }
539
540 }