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