1 package com.melloware.jukes.gui.view.dialogs;
2
3 import java.awt.BorderLayout;
4 import java.awt.Dimension;
5 import java.awt.Frame;
6 import java.io.File;
7 import java.io.IOException;
8 import java.util.ArrayList;
9 import java.util.Collection;
10 import java.util.Iterator;
11
12 import javax.swing.DefaultCellEditor;
13 import javax.swing.JButton;
14 import javax.swing.JComboBox;
15 import javax.swing.JComponent;
16 import javax.swing.JFileChooser;
17 import javax.swing.JOptionPane;
18 import javax.swing.JPanel;
19 import javax.swing.JSplitPane;
20 import javax.swing.JTable;
21 import javax.swing.JTextField;
22 import javax.swing.ListSelectionModel;
23 import javax.swing.RowSorter;
24 import javax.swing.event.ListSelectionEvent;
25 import javax.swing.event.ListSelectionListener;
26 import javax.swing.table.TableModel;
27 import javax.swing.table.TableRowSorter;
28
29 import org.apache.commons.io.FilenameUtils;
30 import org.apache.commons.lang.StringUtils;
31 import org.apache.commons.lang.math.NumberUtils;
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.action.ActionManager;
42 import com.jgoodies.uif.application.Application;
43 import com.jgoodies.uifextras.util.UIFactory;
44 import com.jgoodies.validation.Severity;
45 import com.melloware.jukes.exception.MusicTagException;
46 import com.melloware.jukes.file.FileUtil;
47 import com.melloware.jukes.file.MusicDirectory;
48 import com.melloware.jukes.file.filter.FilterFactory;
49 import com.melloware.jukes.file.image.ChooserImagePreview;
50 import com.melloware.jukes.file.image.ImageFactory;
51 import com.melloware.jukes.file.image.ImageFileView;
52 import com.melloware.jukes.file.tag.MusicTag;
53 import com.melloware.jukes.file.tag.TagFactory;
54 import com.melloware.jukes.gui.tool.Actions;
55 import com.melloware.jukes.gui.tool.Resources;
56 import com.melloware.jukes.gui.tool.Settings;
57 import com.melloware.jukes.gui.view.component.AlbumImage;
58 import com.melloware.jukes.gui.view.component.ComponentFactory;
59 import com.melloware.jukes.gui.view.component.EnhancedTableHeader;
60 import com.melloware.jukes.util.GuiUtil;
61 import com.melloware.jukes.util.JukesValidationMessage;
62 import com.melloware.jukes.util.MessageUtil;
63
64
65
66
67
68
69
70
71
72
73 @SuppressWarnings("unchecked")
74 public final class DiscAddDialog
75 extends AbstractDialog {
76
77 private static final Log LOG = LogFactory.getLog(DiscAddDialog.class);
78 private static final String TRACK_00 = "00";
79 private static final String TRACK_32 = "32";
80 private AlbumImage webImagePreview;
81 private EnhancedTableHeader header;
82 private File coverImage;
83 private JButton buttonCancel;
84 private JButton buttonSave;
85 private JComboBox genreField;
86 private JComponent buttonBar;
87 private JComponent splitPane;
88 private JTable tagTable;
89 private JTextField artistField;
90 private JTextField discField;
91 private JTextField yearField;
92 private MusicTagTableModel tableModel;
93 private Object[] tags;
94 private Settings settings;
95 private String directory;
96
97
98
99
100
101
102 public DiscAddDialog(Frame owner, Settings settings, File aFile) {
103 super(owner);
104 LOG.debug("Disc Add Dialog created.");
105 try {
106 this.settings = settings;
107 final MusicTag musicTag = TagFactory.getTag(aFile);
108 if (LOG.isDebugEnabled()) {
109 LOG.debug(musicTag.getHeaderInfo());
110 }
111
112 artistField = new JTextField(musicTag.getArtist());
113 artistField.setColumns(45);
114 discField = new JTextField(musicTag.getDisc());
115 discField.setColumns(45);
116 genreField = new JComboBox(MusicTag.getGenreTypes().toArray());
117 genreField.setSelectedItem(musicTag.getGenre());
118 if (genreField.getSelectedItem() == null) {
119 genreField.setSelectedItem("Other");
120 }
121 yearField = new JTextField(musicTag.getYear());
122 ((JTextField)yearField).setColumns(5);
123 tagTable = new JTable();
124 header = new EnhancedTableHeader(tagTable.getColumnModel(), tagTable);
125 tagTable.setTableHeader(header);
126
127
128 directory = FilenameUtils.getFullPath(aFile.getAbsolutePath());
129 webImagePreview = new AlbumImage();
130 final File dir = new File(directory);
131 coverImage = MusicDirectory.findLargestImageFile(dir);
132 updateCoverImage();
133
134
135 final Collection files = MusicDirectory.findMusicFiles(dir);
136 final ArrayList musicTags = new ArrayList();
137
138 if (files != null) {
139 final int padding = ((files.size() >= 100) ? 3 : 2);
140 int counter = 0;
141 for (Iterator iter = files.iterator(); iter.hasNext();) {
142 counter++;
143 final File element = (File)iter.next();
144 final MusicTag tag = TagFactory.getTag(element);
145 if ((StringUtils.equals(TRACK_00, tag.getTrack())) || (StringUtils.equals(TRACK_32, tag.getTrack()))) {
146 tag.setTrack(Integer.toString(counter), padding);
147 } else {
148 tag.setTrack(tag.getTrack(), padding);
149 }
150 musicTags.add(tag);
151 }
152 this.tags = musicTags.toArray();
153 loadTable();
154 }
155
156
157 } catch (MusicTagException ex) {
158 LOG.error("MusicTagException", ex);
159 }
160 }
161
162
163
164
165 public void doApply() {
166 LOG.debug("Save pressed.");
167
168 GuiUtil.setBusyCursor(this, true);
169
170
171 fillTags();
172
173
174 JukesValidationMessage result = MusicDirectory.createNewDisc(this.tags, this.coverImage,
175 new File(this.directory), null, true);
176 GuiUtil.setBusyCursor(this, false);
177
178 if (result.getSeverity() == Severity.OK) {
179
180 ActionManager.get(Actions.REFRESH_ID).actionPerformed(null);
181 super.doClose();
182 } else {
183 MessageUtil.showError(this, result.getMessage());
184 }
185 }
186
187
188
189
190 public void doCancel() {
191 LOG.debug("Cancel Pressed.");
192 super.doCancel();
193 }
194
195
196
197
198 public void findCover() {
199 final File currentDir = new File(this.directory);
200 JFileChooser chooser = new JFileChooser();
201 chooser.setApproveButtonText("Select");
202 chooser.setDialogTitle("Find Cover Image");
203 chooser.setCurrentDirectory(currentDir);
204 chooser.addChoosableFileFilter(FilterFactory.imageFileFilter());
205 chooser.setAcceptAllFileFilterUsed(false);
206 chooser.setFileView(new ImageFileView());
207 chooser.setAccessory(new ChooserImagePreview(chooser));
208 chooser.setMultiSelectionEnabled(false);
209 int returnVal = chooser.showOpenDialog(Application.getDefaultParentFrame());
210 if (returnVal != JFileChooser.APPROVE_OPTION) {
211 return;
212 }
213
214 File file = chooser.getSelectedFile();
215 this.coverImage = file;
216 updateCoverImage();
217 }
218
219
220
221
222 public void renameFiles() {
223 LOG.debug("Renaming Files");
224 updateTable();
225 MusicTag musicTag = null;
226 try {
227 GuiUtil.setBusyCursor(this, true);
228
229 fillTags();
230
231 for (int i = 0; i < tags.length; i++) {
232 musicTag = (MusicTag)tags[i];
233 if (musicTag.renameFile(this.settings.getFileFormatMusic())) {
234 LOG.debug("Renamed " + musicTag.getAbsolutePath());
235 }
236 }
237 } catch (Exception ex) {
238 LOG.error("Error renaming file: " + ex.getMessage(), ex);
239 } finally {
240 GuiUtil.setBusyCursor(this, false);
241 }
242 updateTable();
243 }
244
245
246
247
248
249 public void resetFromFilenames() {
250 LOG.debug("Constructing titles from filenames");
251 for (int i = 0; i < tags.length; i++) {
252 MusicTag tag = (MusicTag)tags[i];
253 tag.setTitle(tag.extractTitleFromFilename());
254 }
255 updateTable();
256 }
257
258
259
260
261 public void resetTrackNumbers() {
262 LOG.debug("Resetting track numbers.");
263 final int padding = ((tags.length >= 100) ? 3 : 2);
264 for (int i = 0; i < tags.length; i++) {
265 MusicTag tag = (MusicTag)tags[i];
266 tag.setTrack(String.valueOf(i + 1), padding);
267 }
268 updateTable();
269 }
270
271
272
273
274 public void titleCase() {
275 LOG.debug("Title casing all tracks");
276 for (int i = 0; i < tags.length; i++) {
277 MusicTag tag = (MusicTag)tags[i];
278 tag.setTitle(FileUtil.capitalize(tag.getTitle()));
279 }
280 updateTable();
281 }
282
283
284
285
286 public void updateComments() {
287 LOG.debug("Updating comments");
288 updateTable();
289 final String inputValue = StringUtils.defaultIfEmpty(JOptionPane.showInputDialog("Enter a comment: "), "");
290 for (int i = 0; i < tags.length; i++) {
291 final MusicTag tag = (MusicTag)tags[i];
292 tag.setComment(inputValue);
293 }
294 updateTable();
295 }
296
297
298
299
300 public void webSearch() {
301 LOG.debug("Web Search");
302 WebSearchDialog dialog = new WebSearchDialog((Frame)this.getParent(), this.settings);
303 dialog.setSelectedArtist(artistField.getText());
304 dialog.setSelectedDisc(discField.getText());
305 dialog.open();
306
307
308 if (dialog.hasBeenCanceled()) {
309 return;
310 }
311
312 if (StringUtils.isNotBlank(dialog.getSelectedArtist())) {
313 artistField.setText(dialog.getSelectedArtist());
314 }
315 if (StringUtils.isNotBlank(dialog.getSelectedDisc())) {
316 String end = StringUtils.substringAfterLast(discField.getText(), " -");
317 if (StringUtils.isNotBlank(end)) {
318 discField.setText(dialog.getSelectedDisc() + " -" + end);
319 } else {
320 discField.setText(dialog.getSelectedDisc());
321 }
322 }
323 if (StringUtils.isNotBlank(dialog.getSelectedYear())) {
324 if ((NumberUtils.isNumber(yearField.getText())) && (NumberUtils.isNumber(dialog.getSelectedYear()))) {
325 if (Integer.valueOf(dialog.getSelectedYear()).intValue() < Integer.valueOf(yearField.getText()).intValue()) {
326 yearField.setText(dialog.getSelectedYear());
327 }
328 }
329 }
330
331
332 Collection amazonTracks = dialog.getSelectedTracks();
333 if (amazonTracks != null) {
334 if (LOG.isDebugEnabled()) {
335 LOG.debug("Amazon Count = " + amazonTracks.size());
336 LOG.debug("Tag Count = " + tags.length);
337 }
338
339 if (amazonTracks.size() == tags.length) {
340 Object[] tracks = amazonTracks.toArray();
341 for (int i = 0; i < tags.length; i++) {
342 MusicTag musicTag = (MusicTag)tags[i];
343 musicTag.setTitle((String)tracks[i]);
344 }
345 }
346 }
347
348
349 if (dialog.getSelectedImage() != null) {
350 try {
351 if (this.coverImage == null) {
352 LOG.debug(this.directory);
353 String imageLocation = ImageFactory.saveImageWithFileFormat(dialog.getSelectedImage(),
354 this.settings.getFileFormatImage(),
355 FilenameUtils.getFullPath(this.directory),
356 artistField.getText(),
357 discField.getText());
358
359 this.coverImage = new File(imageLocation);
360 } else {
361 ImageFactory.saveImage(dialog.getSelectedImage(), this.coverImage.getAbsolutePath());
362 }
363 updateCoverImage();
364 } catch (IOException ex) {
365 LOG.error("Error saving cover image.", ex);
366 }
367 }
368
369 updateTable();
370 }
371
372
373
374
375
376
377 protected JComponent buildContent() {
378 JPanel content = new JPanel(new BorderLayout());
379 JButton[] buttons = new JButton[2];
380 JButton button = createApplyButton();
381 button.setText("Save");
382 button.setEnabled(true);
383 buttonSave = button;
384 buttonCancel = createCancelButton();
385 buttons[0] = buttonSave;
386 buttons[1] = buttonCancel;
387 buttonBar = ButtonBarFactory.buildRightAlignedBar(buttons);
388 splitPane = buildSplitPane();
389 content.add(splitPane, BorderLayout.CENTER);
390 content.add(buttonBar, BorderLayout.SOUTH);
391 return content;
392 }
393
394
395
396
397
398
399 protected JComponent buildHeader() {
400 final DiscAddHeaderPanel header = new DiscAddHeaderPanel(this, "Add New Disc ",
401 "Adds a new disc to the catalog. Any updates should be made here before adding to catalog.",
402 Resources.DISC_ADD_ICON);
403
404 return header;
405 }
406
407
408
409
410
411
412 protected JComponent buildMainPanel() {
413 FormLayout layout = new FormLayout("fill:pref:grow", "p, p, p");
414 PanelBuilder builder = new PanelBuilder(layout);
415 builder.setDefaultDialogBorder();
416 CellConstraints cc = new CellConstraints();
417 builder.add(buildDiscPanel(), cc.xy(1, 1));
418 builder.add(buildTagTablePanel(), cc.xy(1, 3));
419 return builder.getPanel();
420 }
421
422
423
424
425
426
427 protected void resizeHook(JComponent component) {
428
429 }
430
431
432
433
434
435
436 private JComponent buildDiscPanel() {
437 FormLayout layout = new FormLayout("right:max(14dlu;pref), 400px, pref, pref, pref, pref ,pref, fill:pref:grow",
438 "p, 4px, p, 4px, p, 4px, 4px");
439
440 PanelBuilder builder = new PanelBuilder(layout);
441 CellConstraints cc = new CellConstraints();
442
443 builder.addLabel("Artist: ", cc.xy(1, 1));
444 builder.add(artistField, cc.xyw(2, 1, 4));
445 builder.add(webImagePreview, cc.xywh(7, 1, 1, 7));
446 builder.add(ComponentFactory.createTitleCaseButton(artistField), cc.xy(6, 1));
447 builder.addLabel("Disc: ", cc.xy(1, 3));
448 builder.add(discField, cc.xyw(2, 3, 4));
449 builder.add(ComponentFactory.createTitleCaseButton(discField), cc.xy(6, 3));
450 builder.addLabel("Genre: ", cc.xy(1, 5));
451 builder.add(genreField, cc.xy(2, 5));
452 builder.addLabel("Year: ", cc.xy(4, 5));
453 builder.add(yearField, cc.xy(5, 5));
454 return builder.getPanel();
455 }
456
457
458
459
460
461 private JComponent buildSplitPane() {
462 splitPane = UIFactory.createStrippedSplitPane(JSplitPane.VERTICAL_SPLIT, buildDiscPanel(), buildTagTablePanel(),
463 0.25);
464 splitPane.setBorder(Borders.DIALOG_BORDER);
465 return splitPane;
466 }
467
468
469
470
471
472
473 private JComponent buildTagTablePanel() {
474
475
476 tagTable.setShowGrid(false);
477 tagTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
478 tagTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
479
480 ListSelectionModel rowSM = tagTable.getSelectionModel();
481 rowSM.addListSelectionListener(new ListSelectionListener() {
482 public void valueChanged(ListSelectionEvent e) {
483
484 if (e.getValueIsAdjusting()) {
485 return;
486 }
487 }
488 });
489
490 JComponent resultsPane = UIFactory.createTablePanel(tagTable);
491 resultsPane.setPreferredSize(new Dimension(300, 275));
492
493
494 FormLayout layout = new FormLayout("fill:pref:grow", "p");
495 PanelBuilder builder = new PanelBuilder(layout);
496 CellConstraints cc = new CellConstraints();
497 builder.add(resultsPane, cc.xy(1, 1));
498 return builder.getPanel();
499 }
500
501
502
503
504 private void fillTags() {
505
506 for (int i = 0; i < tags.length; i++) {
507 MusicTag tag = (MusicTag)tags[i];
508 tag.setArtist(artistField.getText());
509 tag.setDisc(discField.getText());
510 tag.setYear(yearField.getText());
511 tag.setGenre((String)genreField.getSelectedItem());
512 }
513 }
514
515
516
517
518 private void loadTable() {
519 if (LOG.isDebugEnabled()) {
520 LOG.debug("Loading table.");
521 }
522 tableModel = new MusicTagTableModel(tags);
523 RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(tableModel);
524 tagTable.setModel(tableModel);
525 tagTable.setRowSorter(sorter);
526 header.autoSizeColumns();
527
528
529 ((DefaultCellEditor)tagTable.getDefaultEditor(String.class)).setClickCountToStart(1);
530 tagTable.updateUI();
531 }
532
533
534
535
536 private void updateCoverImage() {
537 if ((this.coverImage != null) && (this.coverImage.exists())) {
538 webImagePreview.setImage(ImageFactory.getScaledImage(coverImage.getAbsolutePath(), 90, 90).getImage());
539 }
540 }
541
542
543
544
545 private void updateTable() {
546 GuiUtil.stopTableEditing(tagTable);
547 tableModel.fireTableDataChanged();
548 }
549
550 }