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