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.ActionListener;
6 import java.io.File;
7 import java.text.MessageFormat;
8 import java.util.Collection;
9 import java.util.HashMap;
10 import java.util.Iterator;
11 import java.util.Random;
12
13 import javax.swing.JComponent;
14 import javax.swing.JTextArea;
15 import javax.swing.JToolBar;
16 import javax.swing.ProgressMonitor;
17 import javax.swing.Timer;
18 import javax.swing.UIManager;
19 import javax.swing.text.JTextComponent;
20
21 import org.apache.commons.lang.StringEscapeUtils;
22 import org.apache.commons.lang.StringUtils;
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25
26 import com.jgoodies.forms.builder.PanelBuilder;
27 import com.jgoodies.forms.layout.CellConstraints;
28 import com.jgoodies.forms.layout.FormLayout;
29 import com.jgoodies.uif.builder.ToolBarBuilder;
30 import com.jgoodies.uif.component.ToolBarButton;
31 import com.jgoodies.uif.util.ResourceUtils;
32 import com.jgoodies.validation.view.ValidationComponentUtils;
33 import com.melloware.jukes.db.HibernateDao;
34 import com.melloware.jukes.db.HibernateUtil;
35 import com.melloware.jukes.db.orm.Artist;
36 import com.melloware.jukes.db.orm.Disc;
37 import com.melloware.jukes.exception.InfrastructureException;
38 import com.melloware.jukes.file.image.ImageFactory;
39 import com.melloware.jukes.gui.tool.Actions;
40 import com.melloware.jukes.gui.tool.Resources;
41 import com.melloware.jukes.gui.view.component.AlbumImage;
42 import com.melloware.jukes.gui.view.component.ComponentFactory;
43 import com.melloware.jukes.gui.view.tasks.TimerListener;
44 import com.melloware.jukes.gui.view.tasks.UpdateTagsTask;
45 import com.melloware.jukes.gui.view.validation.ArtistValidationModel;
46 import com.melloware.jukes.gui.view.validation.IconFeedbackPanel;
47 import com.melloware.jukes.util.MessageUtil;
48
49
50
51
52
53
54
55
56
57
58
59
60
61 @SuppressWarnings("unchecked")
62 public final class ArtistEditor
63 extends AbstractEditor {
64
65 private static final Log LOG = LogFactory.getLog(ArtistEditor.class);
66 private AlbumImage image1;
67 private AlbumImage image2;
68 private AlbumImage image3;
69 private AlbumImage image4;
70 private AlbumImage image5;
71 private AlbumImage image6;
72 private JComponent artistPanel;
73 private JTextArea notesField;
74 private JTextComponent nameField;
75 private JToolBar headerToolbar;
76
77
78
79
80 public ArtistEditor() {
81 super(Resources.ARTIST_TREE_ICON);
82 }
83
84
85
86
87 public Class getDomainClass() {
88 return Artist.class;
89 }
90
91
92
93
94 public JToolBar getHeaderToolBar() {
95 return headerToolbar;
96 }
97
98
99
100
101 public void build() {
102 initComponents();
103 initComponentAnnotations();
104 initEventHandling();
105
106 artistPanel = buildArtistPanel();
107
108 FormLayout layout = new FormLayout("fill:pref:grow",
109 "max(14dlu;pref), 3dlu, p, 4px, p, 4px, p, 4px, p, 4px, p, 4px, p");
110
111 setLayout(layout);
112 PanelBuilder builder = new PanelBuilder(layout, this);
113 builder.setDefaultDialogBorder();
114 CellConstraints cc = new CellConstraints();
115
116 builder.add(buildHintAreaPane(), cc.xy(1, 1));
117 builder.addSeparator(Resources.getString("label.artist"), cc.xy(1, 3));
118 builder.add(artistPanel, cc.xy(1, 5));
119 builder.addSeparator(Resources.getString("label.featured.discs"), cc.xy(1, 7));
120 builder.add(buildThumbnailPanel(), cc.xy(1, 9));
121 JComponent audit = buildAuditInfoPanel();
122 if (this.getSettings().isAuditInfo()) {
123 builder.addSeparator(Resources.getString("label.auditinfo"), cc.xy(1, 11));
124 builder.add(audit, cc.xy(1, 13));
125 }
126
127 }
128
129
130
131
132
133
134 public void commit() {
135 commit(this.getSettings().isUpdateTags());
136 }
137
138
139
140
141 public void delete() {
142 super.delete();
143 try {
144 if (!MessageUtil.confirmDelete(this)) {
145 return;
146 }
147 setBusyCursor(true);
148
149 Artist artist = getArtist();
150 HibernateUtil.beginTransaction();
151
152
153 HibernateDao.delete(artist);
154 HibernateUtil.commitTransaction();
155
156
157
158 if (this.getSettings().isCopyImagesToDirectory()) {
159 for (Iterator iter = artist.getDiscs().iterator(); iter.hasNext();) {
160 Disc disc = (Disc)iter.next();
161 final String oldImageName = ImageFactory.standardImageFileName(artist.getName(), disc.getName(), disc.getYear());
162 File oldImageFile = new File (oldImageName);
163 if ( oldImageFile.exists() ) {
164 if (!oldImageFile.delete()) {
165 LOG.debug("Error deleting file: " + oldImageFile.getAbsolutePath());
166 }
167 }
168 }
169 }
170
171
172 getValidationModel().setDirty(false);
173
174 this.getMainModule().refreshSelection(null, Resources.NODE_DELETED);
175 } catch (Exception ex) {
176 final String errorMessage = ResourceUtils.getString("messages.ErrorDeletingArtist");
177 MessageUtil.showError(this, errorMessage);
178 LOG.error(errorMessage, ex);
179 HibernateUtil.rollbackTransaction();
180 } finally {
181 setBusyCursor(false);
182 }
183 }
184
185
186
187
188 public void rollback() {
189 super.rollback();
190 try {
191 setBusyCursor(true);
192
193 Artist artist = getArtist();
194 HibernateDao.refresh(artist);
195 updateView();
196 super.rollback();
197 } catch (Exception ex) {
198 final String errorMessage = ResourceUtils.getString("messages.ErrorRefreshingArtist");
199 MessageUtil.showError(this, errorMessage);
200 LOG.error(errorMessage, ex);
201 } finally {
202 setBusyCursor(false);
203 }
204 }
205
206
207
208
209
210
211 protected String getTitleSuffix() {
212 return getArtist().getName();
213 }
214
215
216
217
218 protected void updateModel() {
219 Artist artist = getArtist();
220
221 if (!StringUtils.equals(artist.getName(), nameField.getText())) {
222 artist.setName(nameField.getText());
223 }
224 if (!StringUtils.equalsIgnoreCase(artist.getNotes(), notesField.getText())) {
225 artist.setNotes(notesField.getText());
226 }
227 }
228
229
230
231
232 protected void updateView() {
233 Artist artist = getArtist();
234 nameField.setText(artist.getName());
235 notesField.setText(artist.getNotes());
236 createdDateLabel.setText(DATE_FORMAT.format(artist.getCreatedDate()));
237 createdByLabel.setText(artist.getCreatedUser());
238 modifiedDateLabel.setText(DATE_FORMAT.format(artist.getModifiedDate()));
239 modifiedByLabel.setText(artist.getModifiedUser());
240
241 image1.setDisc(null);
242 image2.setDisc(null);
243 image3.setDisc(null);
244 image4.setDisc(null);
245 image5.setDisc(null);
246 image6.setDisc(null);
247
248
249 Random random = new Random();
250
251 Collection discs = this.getDiscCollection();
252
253 HashMap map = new HashMap();
254 while ((map.size() < 6) && (map.size() <= (discs.size() - 1))) {
255 Integer rand = Integer.valueOf(random.nextInt(discs.size()));
256 map.put(rand, rand);
257 }
258 int count = 0;
259 Object[] array = discs.toArray();
260 Iterator iterator = map.values().iterator();
261 IMAGE_LOOP:
262 while (iterator.hasNext()) {
263 Integer element = (Integer)iterator.next();
264 Disc disc = (Disc)array[element.intValue()];
265 AlbumImage preview = null;
266 switch (count) {
267 case 0: {
268 preview = image1;
269 break;
270 }
271 case 1: {
272 preview = image2;
273 break;
274 }
275 case 2: {
276 preview = image3;
277 break;
278 }
279 case 3: {
280 preview = image4;
281 break;
282 }
283 case 4: {
284 preview = image5;
285 break;
286 }
287 case 5: {
288 preview = image6;
289 break;
290 }
291 default: {
292 break IMAGE_LOOP;
293 }
294 }
295 int dimension = this.getSettings().getCoverSizeSmall();
296 final String currentCoverUrl;
297 if (this.getSettings().isCopyImagesToDirectory()) {
298 currentCoverUrl = ImageFactory.standardImageFileName(disc.getArtist().getName(), disc.getName(), disc.getYear());
299 }
300 else {
301 currentCoverUrl = disc.getCoverUrl();
302 }
303 preview.setImage(ImageFactory.getScaledImage(currentCoverUrl, dimension, dimension).getImage());
304 preview.setDisc(disc);
305 count++;
306 }
307 }
308
309
310
311
312
313
314 private Artist getArtist() {
315 return (Artist)getModel();
316 }
317
318
319
320
321
322
323
324 private Collection getDiscCollection() {
325 Collection results = null;
326 final String filter = this.getSettings().getFilter();
327
328
329 if (StringUtils.isNotBlank(filter)) {
330 final String resource = ResourceUtils.getString("hql.filter.disc");
331 final String hql = MessageFormat.format(resource, new Object[] { getArtist().getId(), filter });
332 LOG.debug(hql);
333 results = HibernateDao.findByQuery(hql);
334 } else {
335
336 results = getArtist().getDiscs();
337 }
338
339 return results;
340 }
341
342
343
344
345
346
347 private JComponent buildArtistPanel() {
348 FormLayout layout = new FormLayout("right:max(14dlu;pref), 4dlu, left:min(80dlu;pref):grow, pref, 4dlu, 25px",
349 "p, 4px, p, 7px");
350
351 PanelBuilder builder = new PanelBuilder(layout);
352 CellConstraints cc = new CellConstraints();
353
354 builder.addLabel(Resources.getString("label.name") + ": ", cc.xy(1, 1));
355 builder.add(nameField, cc.xyw(3, 1, 3));
356 builder.add(ComponentFactory.createTitleCaseButton(nameField), cc.xy(6, 1));
357 builder.addLabel(Resources.getString("label.notes") + ": ", cc.xy(1, 3, "left,top"));
358 builder.add(notesField, cc.xyw(3, 3, 3));
359
360 return new IconFeedbackPanel(getValidationModel().getValidationResultModel(), builder.getPanel());
361 }
362
363
364
365
366
367
368 private JComponent buildThumbnailPanel() {
369 FormLayout layout = new FormLayout("4px, pref, pref, pref, pref, pref, pref, pref, 4px", "p, 7px");
370
371 PanelBuilder builder = new PanelBuilder(layout);
372 CellConstraints cc = new CellConstraints();
373
374 builder.add(image1, cc.xyw(2, 1, 1));
375 builder.add(image2, cc.xyw(3, 1, 1));
376 builder.add(image3, cc.xyw(4, 1, 1));
377 builder.add(image4, cc.xyw(5, 1, 1));
378 builder.add(image5, cc.xyw(6, 1, 1));
379 builder.add(image5, cc.xyw(7, 1, 1));
380 builder.add(image6, cc.xyw(8, 1, 1));
381
382 return builder.getPanel();
383 }
384
385 private JToolBar buildToolBar() {
386 final ToolBarBuilder bar = new ToolBarBuilder("Artist Toolbar");
387 ToolBarButton button = null;
388 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.UNLOCK_ID);
389 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
390 bar.add(button);
391 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.COMMIT_ID);
392 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
393 bar.add(button);
394 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.ROLLBACK_ID);
395 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
396 bar.add(button);
397 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.DELETE_ID);
398 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
399 bar.add(button);
400 return bar.getToolBar();
401 }
402
403
404
405
406
407
408
409 private void commit(boolean aUpdateTags) {
410 super.commit();
411 Artist artist = getArtist();
412 Artist foundArtist = null;
413 String oldArtistName = artist.getName();
414 boolean hasErrors = false;
415 boolean artistChanged = (!StringUtils.equals(artist.getName(), nameField.getText()));
416
417 boolean notesChanged = (!StringUtils.equalsIgnoreCase(artist.getNotes(), notesField.getText()));
418
419 if (notesChanged) {
420 artist.setNotes(notesField.getText());
421 }
422 if (artistChanged) {
423
424 try {
425 setBusyCursor(true);
426
427 final String resource = ResourceUtils.getString("hql.artist.findCaseSensitive");
428 final String hql = MessageFormat.format(resource,
429 new Object[] { StringEscapeUtils.escapeSql(nameField.getText()) });
430 foundArtist = (Artist)HibernateDao.findUniqueByQuery(hql);
431
432 if (foundArtist == null) {
433 updateModel();
434 }
435
436
437 hasErrors = hasErrors();
438 if (hasErrors) {
439 MessageUtil.showError(this, Resources.getString("messages.editorerrors"));
440 LOG.error(Resources.getString("messages.editorerrors"));
441 return;
442 }
443
444 HibernateUtil.beginTransaction();
445 if (foundArtist != null) {
446
447 for (Iterator iter = artist.getDiscs().iterator(); iter.hasNext();) {
448 Disc disc = (Disc)iter.next();
449 foundArtist.addDisc(disc);
450 }
451 HibernateDao.persist(foundArtist);
452 }
453 HibernateDao.saveOrUpdate(artist);
454 HibernateUtil.commitTransaction();
455
456
457 if (this.getSettings().isCopyImagesToDirectory()) {
458 for (Iterator iter = artist.getDiscs().iterator(); iter.hasNext();) {
459 Disc disc = (Disc)iter.next();
460 final String oldImageName = ImageFactory.standardImageFileName(oldArtistName, disc.getName(), disc.getYear());
461 File oldImageFile = new File (oldImageName);
462 if ( oldImageFile.exists() ) {
463 final String newImageName = ImageFactory.standardImageFileName(nameField.getText(), disc.getName(), disc.getYear());
464 final File newImageFile = new File (newImageName);
465 oldImageFile.renameTo(newImageFile);
466 }
467 }
468 }
469
470
471 updateView();
472 } catch (InfrastructureException ex) {
473 HibernateUtil.rollbackTransaction();
474 final String errorMessage = ResourceUtils.getString("messages.ArtistNameUnique");
475 MessageUtil.showError(this, errorMessage);
476 LOG.error(errorMessage);
477 HibernateDao.refresh(artist);
478 hasErrors = true;
479 } catch (Exception ex) {
480 HibernateUtil.rollbackTransaction();
481 final String errorMessage = ResourceUtils.getString("messages.ErrorUpdatingArtist");
482 MessageUtil.showError(this, errorMessage);
483 LOG.error(errorMessage, ex);
484 HibernateDao.refresh(artist);
485 hasErrors = true;
486 } finally {
487 setBusyCursor(false);
488 }
489
490 if (!hasErrors) {
491 if (aUpdateTags && artistChanged) {
492
493 final Artist whichArtist = (foundArtist == null) ? artist : foundArtist;
494 task = new UpdateTagsTask(whichArtist);
495
496 UIManager.put("ProgressMonitor.progressText", Resources.getString("label.ProgressTitle"));
497 UIManager.put("OptionPane.cancelButtonText", Resources.getString("label.Cancel"));
498
499 progressMonitor = new ProgressMonitor(getMainFrame(), Resources.getString("messages.updatetracks"), "",
500 0, (int)task.getLengthOfTask());
501 progressMonitor.setProgress(0);
502 progressMonitor.setMillisToDecideToPopup(10);
503 task.go();
504 timer = new Timer(50, null);
505 timer.addActionListener(new TimerListener(progressMonitor, task, timer));
506 timer.start();
507 } else {
508 MessageUtil.showSuccess(this);
509 }
510 super.commit();
511 }
512
513 if (foundArtist == null) {
514 this.getMainModule().refreshSelection(artist, Resources.NODE_CHANGED);
515 } else {
516 this.getMainModule().refreshTree();
517 }
518 }
519 }
520
521
522
523
524 private void initComponentAnnotations() {
525 ValidationComponentUtils.setInputHint(nameField, Resources.getString("messages.NameIsMandatory"));
526 ValidationComponentUtils.setMandatory(nameField, true);
527 ValidationComponentUtils.setMessageKey(nameField, "Artist.Name");
528 ValidationComponentUtils.setInputHint(notesField, Resources.getString("messages.NotesLength"));
529 ValidationComponentUtils.setMessageKey(notesField, "Artist.Notes");
530 }
531
532
533
534
535 private void initComponents() {
536 validationModel = new ArtistValidationModel(new Artist());
537 headerToolbar = buildToolBar();
538 final Dimension dimension = new Dimension(this.getSettings().getCoverSizeSmall(),
539 this.getSettings().getCoverSizeSmall());
540 image1 = new AlbumImage(dimension);
541 image2 = new AlbumImage(dimension);
542 image3 = new AlbumImage(dimension);
543 image4 = new AlbumImage(dimension);
544 image5 = new AlbumImage(dimension);
545 image6 = new AlbumImage(dimension);
546 nameField = ComponentFactory.createTextField(getValidationModel().getModel(Artist.PROPERTYNAME_NAME), false);
547 notesField = ComponentFactory.createTextArea(getValidationModel().getModel(Artist.PROPERTYNAME_NOTES), false);
548 notesField.setLineWrap(true);
549 notesField.setWrapStyleWord(true);
550 notesField.setRows(3);
551
552 ActionListener actionListener = new ActionListener() {
553 public void actionPerformed(ActionEvent event) {
554 AlbumImage preview = (AlbumImage)event.getSource();
555 if (preview.getDisc() != null) {
556 setBusyCursor(true);
557 getMainModule().selectNodeInTree(preview.getDisc());
558 setBusyCursor(false);
559 }
560 }
561 };
562 image1.addActionListener(actionListener);
563 image2.addActionListener(actionListener);
564 image3.addActionListener(actionListener);
565 image4.addActionListener(actionListener);
566 image5.addActionListener(actionListener);
567 image6.addActionListener(actionListener);
568
569 }
570
571 }