1 package com.melloware.jukes.gui.view.editor;
2
3 import java.awt.Dimension;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.MouseAdapter;
6 import java.awt.event.MouseEvent;
7 import java.awt.event.MouseListener;
8 import java.io.File;
9 import java.io.IOException;
10 import java.text.MessageFormat;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.Iterator;
14 import java.util.List;
15
16 import javax.swing.DefaultListModel;
17 import javax.swing.JComboBox;
18 import javax.swing.JComponent;
19 import javax.swing.JFileChooser;
20 import javax.swing.JLabel;
21 import javax.swing.JList;
22 import javax.swing.JPopupMenu;
23 import javax.swing.JTextArea;
24 import javax.swing.JTextField;
25 import javax.swing.JToolBar;
26 import javax.swing.ListSelectionModel;
27 import javax.swing.ProgressMonitor;
28 import javax.swing.Timer;
29 import javax.swing.UIManager;
30 import javax.swing.text.JTextComponent;
31
32 import org.apache.commons.lang.StringEscapeUtils;
33 import org.apache.commons.lang.StringUtils;
34 import org.apache.commons.lang.SystemUtils;
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38 import com.jgoodies.binding.value.ValueModel;
39 import com.jgoodies.binding.adapter.ComboBoxAdapter;
40 import com.jgoodies.forms.builder.PanelBuilder;
41 import com.jgoodies.forms.layout.CellConstraints;
42 import com.jgoodies.forms.layout.FormLayout;
43 import com.jgoodies.uif.action.ActionManager;
44 import com.jgoodies.uif.application.Application;
45 import com.jgoodies.uif.builder.ToolBarBuilder;
46 import com.jgoodies.uif.component.ToolBarButton;
47 import com.jgoodies.uif.panel.SimpleInternalFrame;
48 import com.jgoodies.uif.util.ResourceUtils;
49 import com.jgoodies.uifextras.util.UIFactory;
50 import com.jgoodies.validation.util.ValidationUtils;
51 import com.jgoodies.validation.view.ValidationComponentUtils;
52 import com.melloware.jukes.db.HibernateDao;
53 import com.melloware.jukes.db.HibernateUtil;
54 import com.melloware.jukes.db.orm.Artist;
55 import com.melloware.jukes.db.orm.Disc;
56 import com.melloware.jukes.db.orm.Track;
57 import com.melloware.jukes.exception.InfrastructureException;
58 import com.melloware.jukes.file.filter.FilterFactory;
59 import com.melloware.jukes.file.filter.ImageFilter;
60 import com.melloware.jukes.file.image.ChooserImagePreview;
61 import com.melloware.jukes.file.image.ImageFactory;
62 import com.melloware.jukes.file.image.ImageFileView;
63 import com.melloware.jukes.file.tag.MusicTag;
64 import com.melloware.jukes.file.tag.TagFactory;
65 import com.melloware.jukes.gui.tool.Actions;
66 import com.melloware.jukes.gui.tool.Resources;
67 import com.melloware.jukes.gui.view.MainMenuBuilder;
68 import com.melloware.jukes.gui.view.component.AlbumImage;
69 import com.melloware.jukes.gui.view.component.ComponentFactory;
70 import com.melloware.jukes.gui.view.component.TrackListCellRenderer;
71 import com.melloware.jukes.gui.view.dialogs.WebSearchDialog;
72 import com.melloware.jukes.gui.view.tasks.TimerListener;
73 import com.melloware.jukes.gui.view.tasks.UpdateTagsTask;
74 import com.melloware.jukes.gui.view.validation.DiscValidationModel;
75 import com.melloware.jukes.gui.view.validation.ArtistValidationModel;
76 import com.melloware.jukes.gui.view.validation.IconFeedbackPanel;
77 import com.melloware.jukes.util.JukesValidationMessage;
78 import com.melloware.jukes.util.MessageUtil;
79 import com.melloware.jukes.gui.view.dialogs.FreeDBDialog;
80
81
82
83
84
85
86
87
88
89
90
91
92
93 @SuppressWarnings("unchecked")
94 public final class DiscEditor
95 extends AbstractEditor {
96
97 private static final Log LOG = LogFactory.getLog(DiscEditor.class);
98 private static final List GENRE_LIST = MusicTag.getGenreTypes();
99 private AlbumImage albumImage;
100 private DefaultListModel listModel;
101 private JComboBox genre;
102 private JComponent discPanel;
103 private JComponent genreEditor;
104 private JLabel genreLabel;
105 private JLabel location;
106 private JList trackList;
107 private JTextArea notesField;
108 private JTextComponent nameField;
109 private JTextComponent year;
110 private JTextComponent artistField;
111 private JToolBar headerToolbar;
112 private List tracks;
113 private SimpleInternalFrame listScrollPane;
114
115
116
117
118 public DiscEditor() {
119 super(Resources.DISC_TREE_ICON);
120 }
121
122
123
124
125 public Class getDomainClass() {
126 return Disc.class;
127 }
128
129
130
131
132 public JToolBar getHeaderToolBar() {
133 return headerToolbar;
134 }
135
136
137
138
139 public void build() {
140 initComponents();
141 initComponentAnnotations();
142 initEventHandling();
143
144 discPanel = buildDiscPanel();
145
146 FormLayout layout = new FormLayout("fill:pref:grow", "p, 12px, p, p, 12px, p, 12px, p, 12px, p");
147
148 setLayout(layout);
149 PanelBuilder builder = new PanelBuilder(layout, this);
150 builder.setDefaultDialogBorder();
151 CellConstraints cc = new CellConstraints();
152
153 builder.add(buildMusicPanel(), cc.xy(1, 1));
154 builder.add(buildHintAreaPane(), cc.xy(1, 3));
155 builder.addSeparator(Resources.getString("label.disc"), cc.xy(1, 4));
156 builder.add(discPanel, cc.xy(1, 6));
157 JComponent audit = buildAuditInfoPanel();
158 if (this.getSettings().isAuditInfo()) {
159 builder.addSeparator(Resources.getString("label.auditinfo"), cc.xy(1, 8));
160 builder.add(audit, cc.xy(1, 10));
161 }
162 }
163
164
165
166
167
168
169 public void commit() {
170 commit(this.getSettings().isUpdateTags());
171 }
172
173
174
175
176 public void delete() {
177 super.delete();
178 try {
179 if (!MessageUtil.confirmDelete(this)) {
180 return;
181 }
182
183 setBusyCursor(true);
184 HibernateUtil.beginTransaction();
185
186 Disc disc = getDisc();
187 final Artist artist = disc.getArtist();
188
189
190 artist.getDiscs().remove(disc);
191
192 artist.getDiscs().remove(disc);;
193 HibernateDao.delete(disc);
194 HibernateUtil.commitTransaction();
195
196
197
198 if (this.getSettings().isCopyImagesToDirectory()) {
199 final String oldImageName = ImageFactory.standardImageFileName(artist.getName(), disc.getName(), disc.getYear());
200 File oldImageFile = new File (oldImageName);
201 if ( oldImageFile.exists() ) {
202 if (!oldImageFile.delete()) {
203 LOG.debug("Error deleting file: " + oldImageFile.getAbsolutePath());
204 }
205 }
206 }
207
208
209 getValidationModel().setDirty(false);
210
211 if (artist.getDiscs().size() == 0) {
212
213 ActionManager.get(Actions.REFRESH_ID).actionPerformed(null);
214 } else {
215
216 this.getMainModule().refreshSelection(disc, Resources.NODE_DELETED);
217 }
218 } catch (Exception ex) {
219 final String errorMessage = ResourceUtils.getString("messages.ErrorDeletingDisc");
220 MessageUtil.showError(this, errorMessage);
221 LOG.error(errorMessage, ex);
222 HibernateUtil.rollbackTransaction();
223 } finally {
224 setBusyCursor(false);
225 }
226 }
227
228
229
230
231 public void findCover() {
232 Disc disc = getDisc();
233 if (disc.isNotValid()) {
234 final String errorMessage = ResourceUtils.getString("messages.discnotexists");
235 LOG.error(errorMessage);
236 MessageUtil.showError(this, errorMessage);
237 return;
238 }
239
240 updateModel();
241
242
243 boolean hasErrors = hasErrors();
244 if (hasErrors) {
245 LOG.error(Resources.MESSAGE_EDITOR_ERRORS);
246 MessageUtil.showError(this, Resources.MESSAGE_EDITOR_ERRORS);
247 return;
248 }
249
250 final File currentDir = new File(getDisc().getLocation());
251 JFileChooser chooser = new JFileChooser();
252 chooser.setApproveButtonText("Select");
253 chooser.setDialogTitle("Find Cover Image");
254 chooser.setCurrentDirectory(currentDir);
255 chooser.addChoosableFileFilter(FilterFactory.imageFileFilter());
256 chooser.setAcceptAllFileFilterUsed(false);
257 chooser.setFileView(new ImageFileView());
258 chooser.setAccessory(new ChooserImagePreview(chooser));
259 chooser.setMultiSelectionEnabled(false);
260 int returnVal = chooser.showOpenDialog(Application.getDefaultParentFrame());
261 if (returnVal != JFileChooser.APPROVE_OPTION) {
262 return;
263 }
264
265 File file = chooser.getSelectedFile();
266
267
268 String imageLocation;
269 try {
270 imageLocation = ImageFactory.saveImageToUserDefinedDirectory(file,
271 disc.getArtist().getName(),
272 disc.getName().toString(),
273 disc.getYear().toString());
274 } catch (IOException e) {
275
276 e.printStackTrace();
277 imageLocation = file.getAbsolutePath();
278 }
279
280 try {
281 setBusyCursor(true);
282 HibernateUtil.beginTransaction();
283 disc.setCoverUrl(imageLocation);
284 HibernateDao.persist(disc);
285 HibernateUtil.commitTransaction();
286
287
288 updateView();
289 } catch (InfrastructureException ex) {
290 final String errorMessage = ResourceUtils.getString("messages.DiscUnique");
291 MessageUtil.showError(this, errorMessage);
292 LOG.error(errorMessage, ex);
293 HibernateUtil.rollbackTransaction();
294 HibernateDao.refresh(disc);
295 } catch (Exception ex) {
296 final String errorMessage = ResourceUtils.getString("messages.ErrorUpdatingCoverImage");
297 MessageUtil.showError(this, errorMessage);
298 LOG.error(errorMessage, ex);
299 HibernateUtil.rollbackTransaction();
300 HibernateDao.refresh(disc);
301 } finally {
302 setBusyCursor(false);
303 }
304 }
305
306
307
308
309 public void renameFiles() {
310 if (getDisc().isNotValid()) {
311 final String errorMessage = ResourceUtils.getString("messages.discnotexists");
312 MessageUtil.showError(this, errorMessage);
313 LOG.error(errorMessage);
314 return;
315 }
316
317 updateModel();
318
319
320 boolean hasErrors = hasErrors();
321 if (hasErrors) {
322 LOG.error(Resources.MESSAGE_EDITOR_ERRORS);
323 MessageUtil.showError(this, Resources.MESSAGE_EDITOR_ERRORS);
324 return;
325 }
326
327 MusicTag musicTag = null;
328 try {
329 setBusyCursor(true);
330 for (Iterator iter = getDisc().getTracks().iterator(); iter.hasNext();) {
331 Track track = (Track)iter.next();
332 final File file = new File(track.getTrackUrl());
333
334 if (file.exists()) {
335 musicTag = TagFactory.getTag(file);
336 if (musicTag.renameFile(this.getSettings().getFileFormatMusic())) {
337 track.setTrackUrl(musicTag.getAbsolutePath());
338 }
339 }
340 }
341 commit(false);
342 } catch (InfrastructureException ex) {
343 LOG.error(ex.getMessage());
344 MessageUtil.showError(this, ex.getMessage());
345 } catch (Exception ex) {
346 final String errorMessage = ResourceUtils.getString("messages.ErrorRenamingFile");
347 MessageUtil.showError(this, errorMessage);
348 LOG.error(errorMessage, ex);
349 } finally {
350 setBusyCursor(false);
351 }
352 }
353
354
355
356
357 public void rollback() {
358 super.rollback();
359 try {
360 setBusyCursor(true);
361
362 Disc disc = getDisc();
363 HibernateDao.refresh(disc);
364 updateView();
365 super.rollback();
366 } catch (Exception ex) {
367 final String errorMessage = ResourceUtils.getString("messages.ErrorRefreshingDisc")+ ": "+ getDisc().getName();
368 MessageUtil.showError(this, errorMessage);
369 LOG.error(errorMessage, ex);
370 } finally {
371 setBusyCursor(false);
372 }
373 }
374
375
376
377
378 public void freeDBSearch() {
379 super.freeDBSearch();
380 final Disc disc = getDisc();
381 if (disc.isNotValid()) {
382 final String errorMessage = ResourceUtils.getString("messages.discnotexists");
383 MessageUtil.showError(this, errorMessage);
384 LOG.error(errorMessage);
385 return;
386 }
387
388 if (hasErrors()) {
389 LOG.error(Resources.MESSAGE_EDITOR_ERRORS);
390 MessageUtil.showError(this, Resources.MESSAGE_EDITOR_ERRORS);
391 return;
392 }
393 Iterator it;
394 final FreeDBDialog dialog = new FreeDBDialog(getMainFrame(), getSettings());
395 dialog.setSelectedArtist(disc.getArtist().getName());
396 dialog.setSelectedDisc(disc.getName());
397
398 float[] trackLength = new float[disc.getTracks().size()];
399 it = disc.getTracks().iterator();
400 int i = 0;
401 while (it.hasNext()) {
402 trackLength[i] = ((Track) it.next()).getDuration();
403 i++;
404 }
405 dialog.setTrackLength(trackLength);
406 dialog.open();
407
408
409 if (dialog.hasBeenCanceled()) {
410 return;
411 }
412
413
414 boolean modified = false;
415
416
417 final String[] checkList = { "- Disc", "-Disc", "- disc" };
418 if (((StringUtils.isNotBlank(dialog.getSelectedDisc()))
419 && (StringUtils.indexOfAny(nameField.getText(), checkList) <= 0))) {
420 if (!(dialog.getSelectedDisc().equals(nameField.getText()))) {
421 disc.setName(dialog.getSelectedDisc());
422 nameField.setText(dialog.getSelectedDisc());
423 modified = true;
424 }
425 }
426 if ((StringUtils.isNotBlank(dialog.getSelectedYear()))
427 && (Integer.valueOf(dialog.getSelectedYear()).intValue() != Integer.valueOf(year.getText()).intValue())) {
428 disc.setYear(dialog.getSelectedYear());
429 year.setText(dialog.getSelectedYear());
430 modified = true;
431 }
432
433 if (StringUtils.isNotBlank(dialog.getSelectedArtist())) {
434 if (!(dialog.getSelectedArtist().equals(artistField.getText()))) {
435 artistField.setText(dialog.getSelectedArtist());
436 modified = true;
437 }
438 }
439
440 if (StringUtils.isNotBlank(dialog.getSelectedGenre())) {
441 if (!(dialog.getSelectedGenre().equals(genre.getSelectedItem()))) {
442 genre.setSelectedItem(dialog.getSelectedGenre());
443 modified = true;
444 }
445 }
446
447 if (dialog.getSelectedTracks()!= null) {
448 if (dialog.getSelectedTracks().size() == disc.getTracks().size()) {
449 int ii = 0;
450 List trackList = new ArrayList(dialog.getSelectedTracks());
451 for (Iterator iter = getDisc().getTracks().iterator(); iter.hasNext();) {
452 Track track = (Track)iter.next();
453 track.setName(trackList.get(ii).toString());
454 ii = ii + 1;
455 }
456 modified = true;
457 } else {
458 final String errorMessage = ResourceUtils.getString("messages.WrongNumberOfTracks");
459 MessageUtil.showwarn(this, errorMessage);
460 LOG.error(errorMessage);
461 }
462 }
463
464
465 if (modified) {
466 updateModel();
467 updateView();
468 }
469 }
470
471
472
473
474
475
476 protected String getTitleSuffix() {
477 return getDisc().getDisplayText(getSettings().getDisplayFormatDisc());
478 }
479
480
481
482
483 protected void updateModel() {
484 Disc disc = getDisc();
485 Artist foundArtist = null;
486
487 if (!StringUtils.equals(disc.getName(), nameField.getText())) {
488 disc.setName(nameField.getText());
489 }
490
491 if (!StringUtils.equalsIgnoreCase(disc.getYear(), year.getText())) {
492 disc.setYear(year.getText());
493 }
494 if (!StringUtils.equalsIgnoreCase(disc.getGenre(), (String)genre.getSelectedItem())) {
495 disc.setGenre((String)genre.getSelectedItem());
496 }
497
498 if (!StringUtils.equalsIgnoreCase(disc.getNotes(), notesField.getText())) {
499 disc.setNotes(notesField.getText());
500 }
501
502
503 if ((artistField.getText()== null) || (ValidationUtils.isBlank(artistField.getText()))) {
504 final String errorMessage = ResourceUtils.getString("messages.UpdateModel")+ Resources.MESSAGE_EDITOR_ERRORS
505 + "\n " + ResourceUtils.getString("messages.ArtistNameMandatory");
506 MessageUtil.showError(this, errorMessage);
507 LOG.error(errorMessage);
508 } else if (!StringUtils.equalsIgnoreCase(disc.getArtist().getName() , artistField.getText())) {
509
510 try {
511 setBusyCursor(true);
512
513 final String resource = ResourceUtils.getString("hql.artist.findCaseSensitive");
514 final String hql = MessageFormat.format(resource,
515 new Object[] { StringEscapeUtils.escapeSql(artistField.getText()) });
516 foundArtist = (Artist)HibernateDao.findUniqueByQuery(hql);
517
518 if (foundArtist == null) {
519 final String errorMessage = ResourceUtils.getString("messages.ErrorUpdatingArtistNotFound") + artistField.getText();
520 LOG.error(errorMessage);
521 MessageUtil.showError(this, errorMessage);
522 }
523 if (foundArtist != null) {
524
525 disc.setArtist(foundArtist);
526 }
527 } catch (InfrastructureException ex) {
528 final String errorMessage = ResourceUtils.getString("messages.ArtistNameUnique");
529 LOG.error(errorMessage);
530 MessageUtil.showError(this, errorMessage);
531 } catch (Exception ex) {
532 final String errorMessage = ResourceUtils.getString("messages.ErrorUpdatingArtist");
533 LOG.error(errorMessage, ex);
534 MessageUtil.showError(this, errorMessage);
535 } finally {
536 setBusyCursor(false);
537 }
538
539 }
540 }
541
542
543
544
545
546
547 public void webSearch() {
548 super.webSearch();
549 final Disc disc = getDisc();
550 if (disc.isNotValid()) {
551 final String errorMessage = ResourceUtils.getString("messages.discnotexists");
552 MessageUtil.showError(this, errorMessage);
553 LOG.error(errorMessage);
554 return;
555 }
556
557 if (hasErrors()) {
558 LOG.error(Resources.MESSAGE_EDITOR_ERRORS);
559 MessageUtil.showError(this, Resources.MESSAGE_EDITOR_ERRORS);
560 return;
561 }
562
563 final WebSearchDialog dialog = new WebSearchDialog(getMainFrame(), getSettings());
564 dialog.setSelectedArtist(disc.getArtist().getName());
565 dialog.setSelectedDisc(disc.getName());
566 dialog.open();
567
568
569 if (dialog.hasBeenCanceled()) {
570 return;
571 }
572
573
574 boolean modified = false;
575
576
577 final String[] checkList = { "- Disc", "-Disc", "- disc" };
578 if (((StringUtils.isNotBlank(dialog.getSelectedDisc()))
579 && (StringUtils.indexOfAny(nameField.getText(), checkList) <= 0))) {
580 if (!(dialog.getSelectedDisc().equals(nameField.getText()))) {
581 disc.setName(dialog.getSelectedDisc());
582 nameField.setText(dialog.getSelectedDisc());
583 modified = true;
584 }
585 }
586 if ((StringUtils.isNotBlank(dialog.getSelectedYear()))
587 && (Integer.valueOf(dialog.getSelectedYear()).intValue() != Integer.valueOf(year.getText()).intValue())) {
588 disc.setYear(dialog.getSelectedYear());
589 year.setText(dialog.getSelectedYear());
590 modified = true;
591 }
592 if (dialog.getSelectedImage() != null) {
593 try {
594 if (StringUtils.isNotBlank(disc.getCoverUrl())) {
595 ImageFactory.saveImage(dialog.getSelectedImage(), disc.getCoverUrl());
596 } else {
597 String filename = disc.getLocation() + SystemUtils.FILE_SEPARATOR + "cover." + ImageFilter.JPG;
598 ImageFactory.saveImage(dialog.getSelectedImage(), filename);
599 disc.setCoverUrl(filename);
600 }
601 albumImage.setImage(ImageFactory.getDiscImage(disc.getCoverUrl()).getImage());
602
603 final File coverFile = new File(disc.getCoverUrl());
604 ImageFactory.saveImageToUserDefinedDirectory(coverFile,
605 disc.getArtist().getName(),
606 disc.getName(),
607 disc.getYear());
608 } catch (IOException ex) {
609 final String errorMessage = ResourceUtils.getString("messages.ErrorSavingCoverImage");
610 MessageUtil.showError(this, errorMessage);
611 LOG.error(errorMessage, ex);
612 }
613 }
614 if (StringUtils.isNotBlank(dialog.getSelectedArtist())) {
615 if (!(dialog.getSelectedArtist().equals(artistField.getText()))) {
616 artistField.setText(dialog.getSelectedArtist());
617 modified = true;
618 }
619 }
620
621 if (dialog.getSelectedTracks()!= null) {
622 if (dialog.getSelectedTracks().size() == disc.getTracks().size()) {
623 int ii = 0;
624 List trackList = new ArrayList(dialog.getSelectedTracks());
625 for (Iterator iter = getDisc().getTracks().iterator(); iter.hasNext();) {
626 Track track = (Track)iter.next();
627 track.setName(trackList.get(ii).toString());
628 ii = ii + 1;
629 }
630 modified = true;
631 } else {
632 final String errorMessage = ResourceUtils.getString("messages.WrongNumberOfTracks");
633 MessageUtil.showwarn(this, errorMessage);
634 LOG.error(errorMessage);
635 }
636 }
637
638
639 if (modified) {
640 updateModel();
641 updateView();
642 }
643 }
644
645
646
647
648 protected void updateView() {
649 Disc disc = getDisc();
650 final String currentCoverUrl;
651
652 genre.setSelectedItem(null);
653
654 nameField.setText(disc.getName());
655 year.setText(disc.getYear());
656 genre.setSelectedItem(disc.getGenre());
657 genreLabel.setText(disc.getGenre());
658 location.setText(disc.getLocation());
659 location.setToolTipText(disc.getLocation());
660 notesField.setText(disc.getNotes());
661 artistField.setText(disc.getArtist().getName());
662 createdDateLabel.setText(DATE_FORMAT.format(disc.getCreatedDate()));
663 createdByLabel.setText(disc.getCreatedUser());
664 modifiedDateLabel.setText(DATE_FORMAT.format(disc.getModifiedDate()));
665 modifiedByLabel.setText(disc.getModifiedUser());
666 listModel.removeAllElements();
667 tracks = new ArrayList();
668 for (Iterator iter = disc.getTracks().iterator(); iter.hasNext();) {
669 final Track track = (Track)iter.next();
670 final String name = track.getDisplayText(getSettings().getDisplayFormatTrack());
671 final JukesValidationMessage message = new JukesValidationMessage(name, null, track);
672 tracks.add(message);
673 }
674 Collections.sort(tracks, TrackListCellRenderer.TRACK_COMPARATOR);
675 for (Iterator iter = tracks.iterator(); iter.hasNext();) {
676 JukesValidationMessage message = (JukesValidationMessage)iter.next();
677 listModel.addElement(message);
678 }
679
680
681 int dimension = this.getSettings().getCoverSizeLarge();
682 albumImage.setDisc(disc);
683 if (this.getSettings().isCopyImagesToDirectory()) {
684 currentCoverUrl = ImageFactory.standardImageFileName(disc.getArtist().getName(), disc.getName(), disc.getYear());
685 }
686 else {
687 currentCoverUrl = disc.getCoverUrl();
688 }
689 albumImage.setImage(ImageFactory.getScaledImage(currentCoverUrl, dimension, dimension).getImage());
690 }
691
692
693
694
695
696
697 private Disc getDisc() {
698 return (Disc)getModel();
699 }
700
701
702
703
704
705
706 private JComponent buildDiscPanel() {
707
708 FormLayout layout = new FormLayout("right:max(14dlu;pref), 4dlu, left:min(80dlu;pref):grow, pref, 4dlu, pref, 25px",
709 "p, 4px, p, 4px, p, 4px, p, 4px, p, 4px, p, 4px");
710
711 layout.setRowGroups(new int[][] {
712 { 1, 3, 5 }
713 });
714 PanelBuilder builder = new PanelBuilder(layout);
715 CellConstraints cc = new CellConstraints();
716
717 builder.addLabel(Resources.getString("label.artist") + ": ", cc.xy(1, 1));
718 builder.add(artistField, cc.xyw(3, 1, 3));
719
720 builder.addLabel(Resources.getString("label.name") + ": ", cc.xy(1, 3));
721 builder.add(nameField, cc.xyw(3, 3, 3));
722 builder.add(ComponentFactory.createTitleCaseButton(nameField), cc.xy(6, 3));
723 builder.addLabel(Resources.getString("label.genre") + ": ", cc.xy(1, 5));
724 builder.add(genreLabel, cc.xyw(2, 5, 2));
725 builder.add(genre, cc.xyw(3, 5, 3));
726 builder.addLabel(Resources.getString("label.year") + ": ", cc.xy(1, 7));
727 builder.add(year, cc.xy(3, 7));
728 builder.addLabel(Resources.getString("label.file") + ": ", cc.xy(1, 9));
729 builder.add(location, cc.xyw(3, 9, 5));
730 builder.addLabel(Resources.getString("label.notes") + ": ", cc.xy(1, 11, "left,top"));
731 builder.add(notesField, cc.xyw(3, 11, 3));
732
733 return new IconFeedbackPanel(getValidationModel().getValidationResultModel(), builder.getPanel());
734 }
735
736
737
738
739
740
741 private JComponent buildMusicPanel() {
742 FormLayout layout = new FormLayout("left:pref, 4dlu, right:pref", "p");
743
744 layout.setRowGroups(new int[][] {
745 { 1 }
746 });
747 PanelBuilder builder = new PanelBuilder(layout);
748 CellConstraints cc = new CellConstraints();
749 builder.add(listScrollPane, cc.xy(1, 1, "left,top"));
750 builder.add(albumImage, cc.xy(3, 1, "left,top"));
751 return builder.getPanel();
752 }
753
754 private JToolBar buildToolBar() {
755 final ToolBarBuilder bar = new ToolBarBuilder("Disc Toolbar");
756 ToolBarButton button = null;
757 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.UNLOCK_ID);
758 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
759 bar.add(button);
760 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.COMMIT_ID);
761 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
762 bar.add(button);
763 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.ROLLBACK_ID);
764 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
765 bar.add(button);
766 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.DELETE_ID);
767 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
768 bar.add(button);
769 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.FILE_RENAME_ID);
770 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
771 bar.add(button);
772 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.DISC_COVER_ID);
773 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
774 bar.add(button);
775 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.DISC_WEB_ID);
776 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
777 bar.add(button);
778 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.FREE_DB_ID);
779 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
780 bar.add(button);
781 return bar.getToolBar();
782 }
783
784
785
786
787
788
789
790 private void commit(boolean aUpdateTags) {
791 super.commit();
792 final Disc disc = getDisc();
793 final String temporaryDiscName = disc.getName();
794 final String temporaryDiscYear = disc.getYear();
795 final String temporaryDiscGenre = disc.getGenre();
796 final String temporaryDiscNotes = disc.getNotes();
797 final String oldImageName = ImageFactory.standardImageFileName(disc.getArtist().getName(), disc.getName(), disc.getYear());
798 Artist foundArtist = null;
799 Artist artist = null;
800
801 if ((artistField.getText()== null) || (ValidationUtils.isBlank(artistField.getText()))) {
802 final String errorMessage = Resources.MESSAGE_EDITOR_ERRORS + "\n" + ResourceUtils.getString("messages.ArtistNameMandatory");
803 MessageUtil.showError(this, errorMessage);
804 LOG.error(errorMessage);
805 return;
806 }
807
808 if (artistField.getText().length() > 100) {
809 final String errorMessage = Resources.MESSAGE_EDITOR_ERRORS + "\n" + ResourceUtils.getString("messages.ArtistNameLength") + " <= 100";
810 MessageUtil.showError(this, errorMessage);
811 LOG.error(errorMessage);
812 return;
813 }
814
815 if (notesField.getText().length() > 500) {
816 final String errorMessage = Resources.MESSAGE_EDITOR_ERRORS + "\n" + ResourceUtils.getString("messages.NotesLength");
817 MessageUtil.showError(this, errorMessage);
818 LOG.error(errorMessage);
819 return;
820 }
821
822 boolean artistChanged = (!StringUtils.equalsIgnoreCase(disc.getArtist().getName() , artistField.getText()));
823
824
825 boolean hasErrors = hasErrors();
826 if (hasErrors) {
827 LOG.error(Resources.MESSAGE_EDITOR_ERRORS);
828 MessageUtil.showError(this, Resources.MESSAGE_EDITOR_ERRORS);
829 return;
830 }
831
832
833 if (artistChanged) {
834 try {
835 setBusyCursor(true);
836
837 final String resource = ResourceUtils.getString("hql.artist.findCaseSensitive");
838 final String hql = MessageFormat.format(resource,
839 new Object[] { StringEscapeUtils.escapeSql(artistField.getText()) });
840 foundArtist = (Artist)HibernateDao.findUniqueByQuery(hql);
841 if (foundArtist == null) {
842
843 artist = new Artist();
844 artist.setName(artistField.getText());
845 artist.setNotes("");
846 HibernateUtil.beginTransaction();
847 HibernateDao.saveOrUpdate(artist);
848 HibernateUtil.commitTransaction();
849 } else {
850
851 LOG.debug("DiscEditor - Change Artist, Artist was found in Database: " + artistField.getText());
852 }
853 } catch (InfrastructureException ex) {
854 final String errorMessage = ResourceUtils.getString("messages.ArtistNameUnique");
855 MessageUtil.showError(this, errorMessage);
856 LOG.error(errorMessage);
857 } catch (Exception ex) {
858 final String errorMessage = ResourceUtils.getString("messages.ErrorUpdatingArtist");
859 MessageUtil.showError(this, errorMessage);
860 LOG.error(errorMessage, ex);
861 } finally {
862 setBusyCursor(false);
863 }
864 }
865
866 updateModel();
867
868
869 try {
870 setBusyCursor(true);
871 HibernateUtil.beginTransaction();
872 HibernateDao.saveOrUpdate(disc);
873 HibernateUtil.commitTransaction();
874
875
876 if (this.getSettings().isCopyImagesToDirectory()) {
877 File oldImageFile = new File (oldImageName);
878 if ( oldImageFile.exists() ) {
879 final String newImageName = ImageFactory.standardImageFileName(artistField.getText(), disc.getName(), disc.getYear());
880 final File newImageFile = new File (newImageName);
881 oldImageFile.renameTo(newImageFile);
882 }
883 }
884
885 updateView();
886 this.getMainModule().refreshSelection(disc, Resources.NODE_CHANGED);
887 if (artistChanged) {
888 this.getMainModule().refreshTree();
889 }
890 } catch (InfrastructureException ex) {
891 final String errorMessage = ResourceUtils.getString("messages.DiscUnique");
892 MessageUtil.showError(this, errorMessage);
893 LOG.error(errorMessage);
894 HibernateUtil.rollbackTransaction();
895
896 disc.setName(temporaryDiscName);
897 disc.setYear(temporaryDiscYear);
898 disc.setGenre(temporaryDiscGenre);
899 disc.setNotes(temporaryDiscNotes);
900 nameField.setText(temporaryDiscName);
901 year.setText(temporaryDiscYear);
902 genre.setSelectedItem(temporaryDiscGenre);
903 notesField.setText(temporaryDiscNotes);
904
905
906 updateModel();
907
908
909 final Object selectedNode = this.getMainModule().getSelection();
910 this.getMainModule().refreshTree(selectedNode);
911 rollback();
912 hasErrors = true;
913 getValidationModel().setDirty(false);
914 } catch (Exception ex) {
915 final String errorMessage = ResourceUtils.getString("messages.ErrorUpdatingDisc");
916 MessageUtil.showError(this, errorMessage);
917 LOG.error(errorMessage, ex);
918 HibernateUtil.rollbackTransaction();
919 HibernateDao.refresh(disc);
920 hasErrors = true;
921 } finally {
922 setBusyCursor(false);
923 }
924
925 if (!hasErrors) {
926 if (aUpdateTags) {
927
928 task = new UpdateTagsTask(disc);
929
930 UIManager.put("ProgressMonitor.progressText", Resources.getString("label.ProgressTitle"));
931 UIManager.put("OptionPane.cancelButtonText", Resources.getString("label.Cancel"));
932 progressMonitor = new ProgressMonitor(getMainFrame(), Resources.getString("messages.updatetracks"), "",
933 0, (int)task.getLengthOfTask());
934 progressMonitor.setProgress(0);
935 progressMonitor.setMillisToDecideToPopup(10);
936 task.go();
937 timer = new Timer(50, null);
938 timer.addActionListener(new TimerListener(progressMonitor, task, timer));
939 timer.start();
940 } else {
941 MessageUtil.showSuccess(this);
942 }
943 super.commit();
944 }
945 }
946
947
948
949
950 private void initComponentAnnotations() {
951 ValidationComponentUtils.setInputHint(nameField, Resources.getString("messages.NameIsMandatory"));
952 ValidationComponentUtils.setMandatory(nameField, true);
953 ValidationComponentUtils.setMessageKey(nameField, "Disc.Name");
954 ValidationComponentUtils.setInputHint(year, Resources.getString("messages.YearIsMandatory"));
955 ValidationComponentUtils.setMandatory(year, true);
956 ValidationComponentUtils.setMessageKey(year, "Disc.Year");
957 ValidationComponentUtils.setInputHint(genre, Resources.getString("messages.GenreIsMandatory"));
958 ValidationComponentUtils.setMandatory(genre, true);
959 ValidationComponentUtils.setMessageKey(genre, "Disc.Genre");
960 ValidationComponentUtils.setInputHint(notesField, Resources.getString("messages.NotesLength"));
961 ValidationComponentUtils.setMessageKey(notesField, "Disc.Notes");
962
963 ValidationComponentUtils.setInputHint(artistField, Resources.getString("messages.ArtistIsMandatory"));
964 ValidationComponentUtils.setMessageKey(artistField, "Artist.Name");
965 ValidationComponentUtils.setMandatory(artistField, true);
966
967 ValidationComponentUtils.setInputHint(genreEditor, Resources.getString("messages.GenreIsMandatory"));
968 }
969
970
971
972
973 private void initComponents() {
974 validationModel = new DiscValidationModel(new Disc());
975 ArtistValidationModel artistValidationModel = new ArtistValidationModel (new Artist());
976
977 headerToolbar = buildToolBar();
978 nameField = ComponentFactory.createTextField(validationModel.getModel(Disc.PROPERTYNAME_NAME), false);
979
980 artistField = ComponentFactory.createTextField(artistValidationModel.getModel(Artist.PROPERTYNAME_NAME), false);
981
982 year = ComponentFactory.createTextField(validationModel.getModel(Disc.PROPERTYNAME_YEAR), false);
983 ((JTextField)year).setColumns(5);
984 final ValueModel genreChoiceModel = validationModel.getModel(Disc.PROPERTYNAME_GENRE);
985 genreLabel = new JLabel();
986 genreLabel.setName("GENRE");
987
988
989 ComboBoxAdapter genreAdapter = new ComboBoxAdapter(GENRE_LIST.toArray(), genreChoiceModel);
990 genre = new JComboBox(genreAdapter);
991 genre.setEditable(true);
992
993 genreEditor = (JComponent)genre.getComponent(2);
994
995 notesField = ComponentFactory.createTextArea(getValidationModel().getModel(Disc.PROPERTYNAME_NOTES), false);
996 notesField.setLineWrap(true);
997 notesField.setWrapStyleWord(true);
998 notesField.setRows(3);
999 location = ComponentFactory.createLabel(getValidationModel().getModel(Disc.PROPERTYNAME_LOCATION));
1000 albumImage = new AlbumImage(new Dimension(this.getSettings().getCoverSizeLarge(), this.getSettings().getCoverSizeLarge()));
1001 listModel = new DefaultListModel();
1002
1003 trackList = new JList(listModel);
1004 trackList.setFocusable(true);
1005 trackList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
1006 trackList.setSelectedIndex(0);
1007 trackList.setVisibleRowCount(20);
1008 trackList.setCellRenderer(new TrackListCellRenderer(this.getSettings()));
1009 final JPopupMenu popup = MainMenuBuilder.buildPlayerPopupMenu(trackList);
1010 MouseListener popupListener = new ListPopupListener(popup);
1011 trackList.addMouseListener(popupListener);
1012 trackList.add(popup);
1013 listScrollPane = new SimpleInternalFrame(Resources.getString("label.tracks"));
1014 listScrollPane.setFrameIcon(Resources.TRACK_TREE_ICON);
1015 listScrollPane.setContent(UIFactory.createStrippedScrollPane(trackList));
1016 listScrollPane.setSelected(true);
1017 }
1018
1019
1020 private static class ListPopupListener
1021 extends MouseAdapter {
1022
1023 final JPopupMenu popup;
1024
1025 public ListPopupListener(JPopupMenu popup) {
1026 this.popup = popup;
1027 }
1028
1029 public void mousePressed(MouseEvent evt) {
1030 maybeShowPopup(evt);
1031
1032
1033
1034 if ((((evt.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) && (evt.getClickCount() == 2)) ||
1035 ((evt.getModifiers() & MouseEvent.BUTTON2_MASK) != 0))
1036 {
1037 LOG.debug("[List left double clicked or middle clicked].");
1038 JComponent source = (JComponent)evt.getSource();
1039 final ActionEvent event = new ActionEvent(source, 1, Actions.PLAYER_QUEUE_ID);
1040 source.putClientProperty(Resources.EDITOR_COMPONENT, source);
1041 ActionManager.get(Actions.PLAYER_QUEUE_ID).actionPerformed(event);
1042 }
1043 }
1044
1045 public void mouseReleased(MouseEvent e) {
1046 maybeShowPopup(e);
1047 }
1048
1049 private void maybeShowPopup(MouseEvent e) {
1050 if (e.isPopupTrigger()) {
1051 ActionManager.get(Actions.TRACK_PLAY_IMMEDIATE_ID).setEnabled(true);
1052
1053
1054 popup.show(e.getComponent(), e.getX(), e.getY());
1055 }
1056 }
1057
1058 }
1059
1060 }