View Javadoc

1   package com.melloware.jukes.gui.tool;
2   
3   import java.awt.Component;
4   import java.awt.Cursor;
5   import java.awt.Desktop;
6   import java.awt.EventQueue;
7   import java.awt.Frame;
8   import java.awt.GridLayout;
9   import java.awt.event.ActionEvent;
10  import java.io.File;
11  import java.io.FileInputStream;
12  import java.io.FileOutputStream;
13  import java.io.IOException;
14  import java.net.URI;
15  import java.net.URL;
16  import java.util.ArrayList;
17  import java.util.Collection;
18  import java.util.HashMap;
19  import java.util.Iterator;
20  import java.util.List;
21  import java.util.prefs.Preferences;
22  
23  import javax.swing.JComboBox;
24  import javax.swing.JComponent;
25  import javax.swing.JFileChooser;
26  import javax.swing.JLabel;
27  import javax.swing.JList;
28  import javax.swing.JOptionPane;
29  import javax.swing.JPanel;
30  import javax.swing.JTable;
31  import javax.swing.JTextArea;
32  import javax.swing.JToggleButton;
33  import javax.swing.JTree;
34  import javax.swing.UIManager;
35  import javax.swing.filechooser.FileFilter;
36  import javax.swing.text.JTextComponent;
37  import javax.swing.tree.TreePath;
38  
39  import javazoom.jlgui.basicplayer.BasicPlayer;
40  import net.sf.jasperreports.engine.JRException;
41  import net.sf.jasperreports.engine.JasperFillManager;
42  import net.sf.jasperreports.engine.JasperPrint;
43  import net.sf.jasperreports.view.JasperViewer;
44  
45  import org.apache.commons.io.FileUtils;
46  import org.apache.commons.lang.StringUtils;
47  import org.apache.commons.lang.SystemUtils;
48  import org.apache.commons.logging.Log;
49  import org.apache.commons.logging.LogFactory;
50  import org.hibernate.HibernateException;
51  import org.hibernate.exception.JDBCConnectionException;
52  
53  import com.jgoodies.uif.application.Application;
54  import com.jgoodies.uif.util.ResourceUtils;
55  import com.jgoodies.uifextras.convenience.DefaultAboutDialog;
56  import com.jgoodies.uifextras.convenience.SetupManager;
57  import com.jgoodies.uifextras.convenience.TipOfTheDayDialog;
58  import com.l2fprod.common.swing.JDirectoryChooser;
59  import com.melloware.jukes.db.Database;
60  import com.melloware.jukes.db.HibernateDao;
61  import com.melloware.jukes.db.HibernateUtil;
62  import com.melloware.jukes.db.orm.Artist;
63  import com.melloware.jukes.db.orm.Disc;
64  import com.melloware.jukes.db.orm.Track;
65  import com.melloware.jukes.exception.InfrastructureException;
66  import com.melloware.jukes.file.Disclist;
67  import com.melloware.jukes.file.FileUtil;
68  import com.melloware.jukes.file.MusicDirectory;
69  import com.melloware.jukes.file.Playlist;
70  import com.melloware.jukes.file.filter.FilterFactory;
71  import com.melloware.jukes.gui.view.DisclistPanel;
72  import com.melloware.jukes.gui.view.FilterPanel;
73  import com.melloware.jukes.gui.view.MainFrame;
74  import com.melloware.jukes.gui.view.PlaylistPanel;
75  import com.melloware.jukes.gui.view.component.AlbumImage;
76  import com.melloware.jukes.gui.view.dialogs.DifferenceToolDialog;
77  import com.melloware.jukes.gui.view.dialogs.DiscAddDialog;
78  import com.melloware.jukes.gui.view.dialogs.DiscFindDialog;
79  import com.melloware.jukes.gui.view.dialogs.DiscRemoveDialog;
80  import com.melloware.jukes.gui.view.dialogs.DiscTableModel;
81  import com.melloware.jukes.gui.view.dialogs.GenresToolDialog;
82  import com.melloware.jukes.gui.view.dialogs.LocationChangeDialog;
83  import com.melloware.jukes.gui.view.dialogs.MemoryDialog;
84  import com.melloware.jukes.gui.view.dialogs.SearchDialog;
85  import com.melloware.jukes.gui.view.dialogs.SearchTableModel;
86  import com.melloware.jukes.gui.view.dialogs.StatisticsDialog;
87  import com.melloware.jukes.gui.view.dialogs.TrackAddDialog;
88  import com.melloware.jukes.gui.view.dialogs.XMLExportDialog;
89  import com.melloware.jukes.gui.view.dialogs.XMLImportDialog;
90  import com.melloware.jukes.gui.view.editor.AbstractEditor;
91  import com.melloware.jukes.gui.view.node.AbstractTreeNode;
92  import com.melloware.jukes.gui.view.node.ArtistNode;
93  import com.melloware.jukes.gui.view.preferences.PreferencesDialog;
94  import com.melloware.jukes.util.GuiUtil;
95  import com.melloware.jukes.util.JukesValidationMessage;
96  import com.melloware.jukes.util.MessageUtil;
97  
98  /**
99   * Provides all application-level behavior. Most of the methods in this class
100  * will be invoked by <code>AbstractActions</code> as defined in the
101  * <code>Actions</code> class.
102  * <p>
103  * Copyright (c) 2006 Melloware, Inc. <http://www.melloware.com>
104  * @author Emil A. Lefkof III <info@melloware.com>
105  * @version 4.0 AZ 2009, 2010
106  */
107 public final class MainController {
108 
109    private static final Log LOG = LogFactory.getLog(MainController.class);
110    private static final String LINE_BREAK = "\n\n";
111    private static final String ERROR_WRITING_FILE = Resources.getString("label.Errorwritingfile");
112    private static final String ERROR_URL = Resources.getString("label.Enterurl");
113 
114    /**
115     * Refers to the module that provides all high-level models. Used to modify
116     * the project and access the domain object tree.
117     * @see #getMainModule()
118     */
119    private final MainModule mainModule;
120 
121    // Instance Creation ******************************************************
122 
123    /**
124     * Constructs the <code>MainController</code> for the given main module. Many
125     * methods require that the default parent frame is set once it is available.
126     * @param mainModule provides bound properties and high-level models
127     * @see #setDefaultParentFrame(Frame)
128     */
129    public MainController(final MainModule mainModule) {
130       this.mainModule = mainModule;
131 
132    }
133 
134    /**
135     * Backs up the database to zip file.
136     * <p>
137     * @param aEvent the Actionevent fired
138     */
139    @SuppressWarnings("deprecation")
140    public void backupTool(final ActionEvent aEvent) {
141       LOG.debug("Backup Database");
142       if (MessageUtil.confirmBackup(getDefaultParentFrame())) {
143          final File zip = MainModule.SETTINGS.getFileBackup();
144          getMainFrame().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));// AZ:
145          // set
146          // busy
147          // cursor
148          Database.backupDatabase(HibernateUtil.getSession().connection(), zip.getAbsolutePath());
149          getMainFrame().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));// AZ:
150          // switch
151          // off
152          // busy
153          // cursor
154          MessageUtil.showTaskCompleted(getDefaultParentFrame());
155       }
156 
157    }
158 
159    /**
160     * Checks if we shall show a tip of the day: asks the TipOfTheDayDialog
161     * whether it is enabled, and the SetupManager, if we are not running for the
162     * first time. We don't want to disturb the user the first time, where we
163     * already have opened some extra panels from the setup process.
164     * <p>
165     * Opens the tip of the day dialog in the event dispatch thread.
166     */
167    public void checkForOpenTipOfTheDayDialog() {
168       if ((SetupManager.usageCount() > 1) && (TipOfTheDayDialog.isShowingTips())) {
169          EventQueue.invokeLater(new Runnable() {
170             public void run() {
171                openTipOfTheDayDialog();
172             }
173          });
174       }
175    }
176 
177    /**
178     * Opens the Directory chooser dialog.
179     * <p>
180     * @param aEvent the Action Event fired for this button
181     */
182    public void chooseDirectory(final ActionEvent aEvent) {
183       final JComponent button = (JComponent) aEvent.getSource();
184       final JTextComponent text = (JTextComponent) button.getClientProperty(Resources.TEXT_COMPONENT);
185       final JDirectoryChooser chooser = new JDirectoryChooser();
186       final JTextArea accessory = new JTextArea(Resources.getString("label.SelectDirectory"));
187       chooser.setSelectedFile(new File(text.getText()));
188       accessory.setLineWrap(true);
189       accessory.setWrapStyleWord(true);
190       accessory.setEditable(false);
191       accessory.setOpaque(false);
192       accessory.setFont(UIManager.getFont("Tree.font"));
193       chooser.setAccessory(accessory);
194       chooser.setMultiSelectionEnabled(false);
195 
196       final int choice = chooser.showOpenDialog(button);
197       if (choice == JDirectoryChooser.APPROVE_OPTION) {
198          final File dir = chooser.getSelectedFile();
199          LOG.debug("Directory selected: " + dir.getAbsolutePath());
200          text.setText(dir.getAbsolutePath());
201       }
202    }
203 
204    /**
205     * Chooses a file and puts it in the text component listed.
206     * <p>
207     * @param aEvent the Action Event fired for this button
208     */
209    public void chooseFile(final ActionEvent aEvent) {
210       final JComponent button = (JComponent) aEvent.getSource();
211       final JTextComponent text = (JTextComponent) button.getClientProperty(Resources.TEXT_COMPONENT);
212       final JFileChooser chooser = new JFileChooser();
213       chooser.setDialogTitle((String) button.getClientProperty(Resources.FILE_CHOOSER_TITLE));
214       chooser.setFileFilter((FileFilter) button.getClientProperty(Resources.FILE_CHOOSER_FILTER));
215       chooser.setMultiSelectionEnabled(false);
216       chooser.setFileHidingEnabled(true);
217       final int returnVal = chooser.showOpenDialog(this.getDefaultParentFrame());
218       if (returnVal != JFileChooser.APPROVE_OPTION) {
219          return;
220       }
221       final File file = chooser.getSelectedFile();
222       text.setText(file.getAbsolutePath());
223       if (LOG.isDebugEnabled()) {
224          LOG.debug(file.getAbsolutePath());
225 
226       }
227    }
228 
229    /**
230     * Commits the object to the database and updates tags if necessary.
231     * <p>
232     * @param aEvent the Action Event fired for this button
233     */
234    public void commit(final ActionEvent aEvent) {
235       LOG.debug("Commit Changes");
236       final JComponent button = (JComponent) aEvent.getSource();
237       final AbstractEditor editor = (AbstractEditor) button.getClientProperty(Resources.EDITOR_COMPONENT);
238       editor.commit();
239    }
240 
241    /**
242     * Connects to the database and refreshes the whole application.
243     * <p>
244     * @param aEvent the Action Event fired for this button
245     */
246    @SuppressWarnings("deprecation")
247    public void connect(final ActionEvent aEvent) {
248       LOG.debug("Connecting to database.");
249       final MainFrame mainFrame = (MainFrame) Application.getDefaultParentFrame();
250       try {
251          // first shut the database and Hibernate down.
252          HibernateUtil.shutdown();
253          Database.shutdown();
254 
255          // now try and connect to the database listed in the preferences
256          String dbLocation = MainModule.SETTINGS.getDatabaseLocation().getAbsolutePath();
257          dbLocation = dbLocation + SystemUtils.FILE_SEPARATOR + Resources.APPLICATION_LOCATION;
258 
259          // start database
260          Database.startup(dbLocation, Resources.APPLICATION_LOCATION);
261 
262          // initializes Hibernate
263          HibernateUtil.initialize();
264          HibernateUtil.getSession().clear();
265 
266          // set the write delay on the HSQL database so writes are immediate
267          Database.setWriteDelay(HibernateUtil.getSession().connection(), "FALSE");
268 
269          // now refresh the tree
270          getMainModule().refreshTree();
271       } catch (JDBCConnectionException ex) {
272          final String errorMessage = ResourceUtils.getString("messages.NotValidConnection");
273          MessageUtil.showError(mainFrame, errorMessage); // AZ
274          LOG.error(errorMessage);
275       } catch (Exception ex) {
276          final String errorMessage = ResourceUtils.getString("messages.ErrorConnect");
277          MessageUtil.showError(mainFrame, errorMessage); // AZ
278          LOG.error(errorMessage, ex);
279          System.exit(1);
280       }
281    }
282 
283    /**
284     * Redirects to the www.melloware.com homepage.
285     * <p>
286     * @param aEvent the Action Event fired for this button
287     */
288    public void contactUs(final ActionEvent aEvent) {
289       LOG.debug("Contact Us");
290       try {
291          if (Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
292             Desktop.getDesktop().browse(new URI(Resources.APPLICATION_URL));
293          }
294       } catch (UnsupportedOperationException ex) {
295          LOG.warn(ex.getMessage() + LINE_BREAK + ERROR_URL + Resources.APPLICATION_URL);
296       } catch (Exception ex) {
297          LOG.warn(ex.getMessage() + LINE_BREAK + ERROR_URL + Resources.APPLICATION_URL);
298       }
299    }
300 
301    /**
302     * Deletes the object and all its descendants but not any files they may
303     * point to.
304     * <p>
305     * @param aEvent the Action Event fired for this button
306     */
307    public void delete(final ActionEvent aEvent) {
308       LOG.debug("Delete Item");
309       final JComponent source = (JComponent) aEvent.getSource();
310       final Object editor = source.getClientProperty(Resources.EDITOR_COMPONENT);
311       if (editor == null) {
312          return;
313       }
314 
315       if (editor instanceof AbstractEditor) {
316          ((AbstractEditor) editor).delete();
317       } else if (editor instanceof JTree) {
318          final JTree tree = (JTree) editor;
319          final TreePath path = tree.getSelectionPath();
320 
321          // if it's not a AbstractTreeNode, don't do anything
322          if (path.getLastPathComponent() instanceof AbstractTreeNode) {
323             LOG.debug("Tree Node Delete");
324             ((AbstractTreeNode) path.getLastPathComponent()).delete();
325          }
326       }
327 
328    }
329 
330    /**
331     * Displays the difference tool dialog.
332     * <p>
333     * @param aEvent the Action Event fired for this button
334     */
335    public void differenceTool(final ActionEvent aEvent) {
336       LOG.debug("Difference Tool Dialog");
337       new DifferenceToolDialog(getDefaultParentFrame(), MainModule.SETTINGS).open();
338 
339    }
340 
341    /**
342     * AZ Displays the check genres tool dialog.
343     * <p>
344     * @param aEvent the Action Event fired for this button
345     */
346    public void genresTool(final ActionEvent aEvent) {
347       LOG.debug("Genres Check Dialog");
348       new GenresToolDialog(getDefaultParentFrame(), MainModule.SETTINGS).open();
349    }
350 
351    /**
352     * Adds a single disc to the catalog by making the user select a directory.
353     * <p>
354     * @param aEvent the Action Event fired for this button
355     */
356    public void discAdd(final ActionEvent aEvent) {
357       LOG.debug("Add New Disc");
358       final JFileChooser openDialog = new JFileChooser();
359       final MainFrame mainFrame = (MainFrame) Application.getDefaultParentFrame();
360       openDialog.setDialogTitle(Resources.getString("label.AddNewDisc"));
361       final File currentDir = MainModule.SETTINGS.getStartInDirectory();
362       openDialog.setCurrentDirectory(currentDir);
363       openDialog.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);// AZ
364       openDialog.setAcceptAllFileFilterUsed(false);// AZ
365 
366       openDialog.setMultiSelectionEnabled(false);
367       openDialog.setSelectedFile(null);
368       final int returnVal = openDialog.showOpenDialog(this.getDefaultParentFrame());
369       if (returnVal != JFileChooser.APPROVE_OPTION) {
370          return;
371       }
372       final File dir = openDialog.getSelectedFile();
373 
374       // Look for music files in selected directory
375       // AZ
376       final Collection files = MusicDirectory.findMusicFiles(dir);
377       if (files.isEmpty()) {
378          String message = Resources.getString("messages.NoMusicFilesFound");
379          MessageUtil.showError(mainFrame, message);
380          return;
381       } else {
382          File file = (File) files.toArray()[0];
383          LOG.debug(file.getAbsolutePath());
384 
385          new DiscAddDialog(getDefaultParentFrame(), MainModule.SETTINGS, file).open();
386       }
387    }
388 
389    /**
390     * AZ Adds a single track to the catalog
391     * <p>
392     * @param aEvent the Action Event fired for this button
393     */
394    public void trackAdd(final ActionEvent aEvent) {
395       LOG.debug("Add Single Track");
396       final JFileChooser openDialog = new JFileChooser();
397       openDialog.setDialogTitle(Resources.getString("label.AddNewTrack"));
398       final File currentDir = MainModule.SETTINGS.getStartInDirectory();
399       openDialog.setCurrentDirectory(currentDir);
400       openDialog.setFileFilter(FilterFactory.musicFileFilter());
401       openDialog.setMultiSelectionEnabled(false);
402       openDialog.setSelectedFile(null);
403       final int returnVal = openDialog.showOpenDialog(this.getDefaultParentFrame());
404       if (returnVal != JFileChooser.APPROVE_OPTION) {
405          return;
406       }
407       final File file = openDialog.getSelectedFile();
408 
409       LOG.debug(file.getAbsolutePath());
410 
411       new TrackAddDialog(getDefaultParentFrame(), MainModule.SETTINGS, file).open();
412    }
413 
414    /**
415     * AZ Search FreeDB for album
416     * <p>
417     * @param aEvent the Action Event fired for this button
418     */
419    public void freeDB(final ActionEvent aEvent) {
420       LOG.debug("Search FreeDB");
421       final JComponent button = (JComponent) aEvent.getSource();
422       final Object editor = button.getClientProperty(Resources.EDITOR_COMPONENT);
423       if (editor != null) {
424          if (editor instanceof AbstractEditor) {
425             ((AbstractEditor) editor).freeDBSearch();
426          } else if (editor instanceof DiscAddDialog) {
427             ((DiscAddDialog) editor).freeDBSearch();
428          }
429       }
430    }
431 
432    /**
433     * Updates all of the comments at once.
434     * <p>
435     * @param aEvent the ActionEvent fired
436     */
437    public void discAddComments(final ActionEvent aEvent) {
438       LOG.debug("Update comments all at once.");
439       final JComponent button = (JComponent) aEvent.getSource();
440       final Object editor = button.getClientProperty(Resources.EDITOR_COMPONENT);
441       if ((editor != null) && (editor instanceof DiscAddDialog)) {
442          ((DiscAddDialog) editor).updateComments();
443       }
444    }
445 
446    /**
447     * Resets all tracks titles based on filename.
448     * <p>
449     * @param aEvent the ActionEvent fired
450     */
451    public void discAddResetFromFilename(final ActionEvent aEvent) {
452       LOG.debug("Reset Titles from filenames.");
453       final JComponent button = (JComponent) aEvent.getSource();
454       final Object editor = button.getClientProperty(Resources.EDITOR_COMPONENT);
455       if ((editor != null) && (editor instanceof DiscAddDialog)) {
456          ((DiscAddDialog) editor).resetFromFilenames();
457       }
458    }
459 
460    /**
461     * Resets all track numbers in a disc if they are really screwed up.
462     * <p>
463     * @param aEvent the ActionEvent fired
464     */
465    public void discAddResetTrackNumbers(final ActionEvent aEvent) {
466       LOG.debug("Reset Track Numbers.");
467       final JComponent button = (JComponent) aEvent.getSource();
468       final Object editor = button.getClientProperty(Resources.EDITOR_COMPONENT);
469       if ((editor != null) && (editor instanceof DiscAddDialog)) {
470          ((DiscAddDialog) editor).resetTrackNumbers();
471       }
472    }
473 
474    /**
475     * Title cases all tracks in a disc.
476     * <p>
477     * @param aEvent the ActionEvent fired
478     */
479    public void discAddTitleCase(final ActionEvent aEvent) {
480       LOG.debug("Title case all tracks.");
481       final JComponent button = (JComponent) aEvent.getSource();
482       final Object editor = button.getClientProperty(Resources.EDITOR_COMPONENT);
483       if ((editor != null) && (editor instanceof DiscAddDialog)) {
484          ((DiscAddDialog) editor).titleCase();
485       }
486    }
487 
488    /**
489     * Uses a file chooser to let the user select another cover image.
490     * <p>
491     * @param aEvent the Action Event fired for this button
492     */
493    public void discCoverImage(final ActionEvent aEvent) {
494       LOG.debug("Finding new cover image");
495       final JComponent button = (JComponent) aEvent.getSource();
496 
497       final Object editor = button.getClientProperty(Resources.EDITOR_COMPONENT);
498       LOG.debug(editor);
499       if (editor != null) {
500          if (editor instanceof AbstractEditor) {
501             ((AbstractEditor) editor).findCover();
502          } else if (editor instanceof DiscAddDialog) {
503             ((DiscAddDialog) editor).findCover();
504          }
505       }
506    }
507 
508    /**
509     * Opens the Disc Finder dialog.
510     * <p>
511     * @param aEvent the Action Event fired for this button
512     */
513    public void discFinder(final ActionEvent aEvent) {
514       LOG.debug("Disc Finder Dialog");
515       new DiscFindDialog(getDefaultParentFrame(), MainModule.SETTINGS).open();
516    }
517 
518    /**
519     * Opens the Disc Remover dialog.
520     * <p>
521     * @param aEvent the Action Event fired for this button
522     */
523    public void discRemover(final ActionEvent aEvent) {
524       LOG.debug("Disc Remover Dialog");
525       new DiscRemoveDialog(getDefaultParentFrame()).open();
526    }
527 
528    /**
529     * Uses the Amazon.com web service to find album information and covers.
530     * <p>
531     * @param aEvent the Action Event fired for this button
532     */
533    public void discWebSearch(final ActionEvent aEvent) {
534       LOG.debug("Web Search");
535       final JComponent button = (JComponent) aEvent.getSource();
536       final Object editor = button.getClientProperty(Resources.EDITOR_COMPONENT);
537       if (editor != null) {
538          if (editor instanceof AbstractEditor) {
539             ((AbstractEditor) editor).webSearch();
540          } else if (editor instanceof DiscAddDialog) {
541             ((DiscAddDialog) editor).webSearch();
542          }
543       }
544    }
545 
546    /**
547     * Launches a browser and send to the PayPal website
548     */
549    public void donate() {
550       try {
551          if (Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
552             Desktop.getDesktop().browse(new URL(Resources.APPLICATION_DONATE_URL).toURI());
553          }
554       } catch (UnsupportedOperationException ex) {
555          LOG.warn(ex.getMessage() + LINE_BREAK + ERROR_URL + Resources.APPLICATION_DONATE_URL);
556       } catch (Exception ex) {
557          LOG.warn(ex.getMessage() + LINE_BREAK + ERROR_URL + Resources.APPLICATION_DONATE_URL);
558       }
559    }
560 
561    /**
562     * Exports a catalog to a text file the user selects with a chooser.
563     * <p>
564     * @param aEvent the Action Event fired for this button
565     */
566    @SuppressWarnings("unchecked")
567    public void exportCatalog(final ActionEvent aEvent) {
568       LOG.debug("Export Catalog");
569       final MainFrame mainFrame = (MainFrame) Application.getDefaultParentFrame();
570       final JFileChooser chooser = new JFileChooser();
571       chooser.setDialogTitle(Resources.getString("label.ExportCatalog"));
572       chooser.setFileFilter(FilterFactory.textFileFilter());
573       chooser.setMultiSelectionEnabled(false);
574       chooser.setFileHidingEnabled(true);
575       final int returnVal = chooser.showSaveDialog(this.getDefaultParentFrame());
576       if (returnVal != JFileChooser.APPROVE_OPTION) {
577          return;
578       }
579       File file = chooser.getSelectedFile();
580       if (LOG.isDebugEnabled()) {
581          LOG.debug(file.getAbsolutePath());
582       }
583       // add the extension if missing
584       file = FilterFactory.forceTextExtension(file);
585 
586       try {
587          // now query the catalog and save the results to the file
588          final ArrayList results = new ArrayList();
589          final Collection discs = HibernateDao.findByQuery(Resources.getString("hql.export.catalog"));
590 
591          for (final Iterator iter = discs.iterator(); iter.hasNext();) {
592             final Object[] disc = (Object[]) iter.next();
593             results.add(disc[0] + Resources.TAB + disc[1] + Resources.TAB + disc[2] + Resources.TAB + disc[3]
594                      + Resources.TAB + disc[4] + Resources.TAB + disc[5]);
595          }
596          FileUtils.writeLines(file, "UTF-8", results);// AZ UTF-8
597 
598          MessageUtil.showInformation(getDefaultParentFrame(), Resources
599                   .getString("messages.Catalogexportedsuccessfully"));
600       } catch (IOException ex) {
601          MessageUtil.showError(mainFrame, ERROR_WRITING_FILE + LINE_BREAK + ex.getMessage()); // AZ
602          LOG.error(ERROR_WRITING_FILE + LINE_BREAK + ex.getMessage(), ex);
603       } catch (InfrastructureException ex) {
604          MessageUtil.showError(mainFrame, "Infrastructure Exception: " + LINE_BREAK + ex.getMessage()); // AZ
605          LOG.error(ERROR_WRITING_FILE + LINE_BREAK + ex.getMessage(), ex);
606       } catch (Exception ex) {
607          MessageUtil.showError(mainFrame, ERROR_WRITING_FILE + LINE_BREAK + ex.getMessage()); // AZ
608          LOG.error("Unexpected error writing file.", ex);
609       }
610    }
611 
612    /**
613     * Renames the file to track number - title.mp3.
614     * <p>
615     * @param aEvent the Action Event fired for this button
616     */
617    public void fileRename(final ActionEvent aEvent) {
618       LOG.debug("Renaming File");
619       final JComponent button = (JComponent) aEvent.getSource();
620       final Object editor = button.getClientProperty(Resources.EDITOR_COMPONENT);
621       if (editor != null) {
622          if (editor instanceof AbstractEditor) {
623             ((AbstractEditor) editor).renameFiles();
624          } else if (editor instanceof DiscAddDialog) {
625             ((DiscAddDialog) editor).renameFiles();
626          }
627       }
628    }
629 
630    /**
631     * Applies the current filter to the tree.
632     * <p>
633     * @param aEvent the Action Event fired for this button
634     */
635    public void filter(final ActionEvent aEvent) {
636       LOG.debug("Filter applied.");
637       final JToggleButton button = (JToggleButton) aEvent.getSource();
638       final FilterPanel editor = (FilterPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
639       if (button.isSelected()) {
640          LOG.debug("Button Selected");
641          editor.applyFilter();
642       } else {
643          LOG.debug("Button Deselected");
644          editor.removeFilter();
645       }
646    }
647 
648    /**
649     * Clears the current filter.
650     * <p>
651     * @param aEvent the Action Event fired for this button
652     */
653    public void filterClear(final ActionEvent aEvent) {
654       LOG.debug("Filter cleared.");
655       final JComponent button = (JComponent) aEvent.getSource();
656       final FilterPanel editor = (FilterPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
657       editor.clearFilter();
658 
659    }
660 
661    /**
662     * Closes the filter window.
663     * <p>
664     * @param aEvent the Action Event fired for this button
665     */
666    public void filterClose(final ActionEvent aEvent) {
667       LOG.debug("Close Filter.");
668       getMainFrame().getMainPageBuilder().setFilterVisible(false);
669    }
670 
671    /**
672     * Displays or hides the filter window.
673     * <p>
674     * @param aEvent the Action Event fired for this button
675     */
676    public void filterDisplay(final ActionEvent aEvent) {
677       LOG.debug("Filter displayed/hidden.");
678       final boolean visible = !getMainFrame().getMainPageBuilder().isFilterVisible();
679       getMainFrame().getMainPageBuilder().setFilterVisible(visible);
680    }
681 
682    /**
683     * Launches the browser to the forums website.
684     */
685    public void forums() {
686       try {
687          if (Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
688             Desktop.getDesktop().browse(new URI(Resources.APPLICATION_FORUMS_URL));
689          }
690       } catch (UnsupportedOperationException ex) {
691          LOG.warn(ex.getMessage() + LINE_BREAK + ERROR_URL + Resources.APPLICATION_FORUMS_URL);
692       } catch (Exception ex) {
693          LOG.warn(ex.getMessage() + LINE_BREAK + ERROR_URL + Resources.APPLICATION_FORUMS_URL);
694       }
695    }
696 
697    /**
698     * Hides the main window.
699     */
700    public void hideMainWindow() {
701       if (SystemUtils.IS_OS_WINDOWS) {
702          final MainFrame mainframe = (MainFrame) getDefaultParentFrame();
703          mainframe.getTrayIcon().hideWindow();
704       }
705    }
706 
707    /**
708     * Updates the language of the application to aLanguage.
709     * <p>
710     * @param aEvent the ActionEvent fired
711     * @param aLanguage the language to change to
712     */
713    public void language(final ActionEvent aEvent, final String aLanguage) {
714       LOG.debug("Language change to " + aLanguage);
715       // MessageUtil.showwarn(getDefaultParentFrame(), "Language support not
716       // implemented yet");
717       MainModule.SETTINGS.setLocale(aLanguage);
718       getMainModule().storeState();
719       MessageUtil.showInformation(getDefaultParentFrame(), Resources.getString("messages.update.language"));
720    }
721 
722    /**
723     * Opens the global location change tool.
724     * <p>
725     * @param aEvent the Action Event fired for this button
726     */
727    public void locationTool(final ActionEvent aEvent) {
728       LOG.debug("Location Tool Dialog");
729       new LocationChangeDialog(getDefaultParentFrame(), MainModule.SETTINGS).open();
730    }
731 
732    /**
733     * Displays the memory usage and provide garbage collection.
734     * <p>
735     * @param aEvent the Action Event fired for this button
736     */
737    public void memory(final ActionEvent aEvent) {
738       LOG.debug("Memory Dialog");
739       new MemoryDialog(getDefaultParentFrame()).open();
740 
741    }
742 
743    /**
744     * Plays the next track in the playlist.
745     * <p>
746     * @param aEvent the actionevent fired
747     */
748    public void playerNext(final ActionEvent aEvent) {
749       LOG.debug("Player Next");
750       final Runnable update = new Runnable() {
751          public void run() {
752             final Playlist playlist = getMainFrame().getPlaylist();
753             if (playlist.hasNext()) {
754                final Track track = (Track) playlist.getNext();
755                if (track.isValid()) {
756                   getMainFrame().getPlayer().play(track.getTrackUrl());
757                }
758 
759             }
760          }
761       };
762       EventQueue.invokeLater(update);
763    }
764 
765    /**
766     * Pauses the media player.
767     * <p>
768     * @param aEvent the actionevent fired
769     */
770    public void playerPause(final ActionEvent aEvent) {
771       LOG.debug("Player Pause/Resume");
772       final Runnable update = new Runnable() {
773          public void run() {
774             final MainFrame mainFrame = (MainFrame) getDefaultParentFrame();
775             mainFrame.getPlayer().pause();
776          }
777       };
778       EventQueue.invokeLater(update);
779    }
780 
781    /**
782     * Plays the media player.
783     * <p>
784     * @param aEvent the actionevent fired
785     */
786    public void playerPlay(final ActionEvent aEvent) {
787       LOG.debug("Player Play");
788       final Runnable update = new Runnable() {
789          public void run() {
790             final MainFrame mainFrame = (MainFrame) getDefaultParentFrame();
791             LOG.debug("Status: " + mainFrame.getPlayer().getStatus());
792             if (mainFrame.getPlayer().getStatus() == -1) {
793                playerNext(null);
794             } else {
795                mainFrame.getPlayer().play();
796             }
797          }
798       };
799       EventQueue.invokeLater(update);
800 
801    }
802 
803    /**
804     * Plays the previous track in the playlist.
805     * <p>
806     * @param aEvent the actionevent fired
807     */
808    public void playerPrevious(final ActionEvent aEvent) {
809       LOG.debug("Player Previous");
810       final Runnable update = new Runnable() {
811          public void run() {
812             final Playlist playlist = getMainFrame().getPlaylist();
813             if (playlist.hasPrevious()) {
814                final Track trackCurrent = (Track) playlist.getPrevious();
815 
816                // if elapsed time is greater than 2 then replay this song
817                if (getMainFrame().getPlayer().getElapsedTime() > 2000) {
818                   LOG.debug("Player Previous: REPLAY current song");
819                   playerNext(null);
820                } else {
821                   final Track trackPrevious = (Track) playlist.getPrevious();
822                   if ((trackPrevious != null) && (trackPrevious.isValid())) {
823                      LOG.debug("Player Previous: PLAY previous song in playlist");
824                      playerNext(null);
825                   } else if ((trackCurrent != null) && (trackCurrent.isValid())) {
826                      playerNext(null);
827                   }
828                }
829             }
830          }
831       };
832       EventQueue.invokeLater(update);
833 
834    }
835 
836    /**
837     * Stops the media player.
838     * <p>
839     * @param aEvent the actionevent fired
840     */
841    public void playerStop(final ActionEvent aEvent) {
842       LOG.debug("Player Stop");
843       final Runnable update = new Runnable() {
844          public void run() {
845             MainFrame mainFrame = (MainFrame) getDefaultParentFrame();
846             mainFrame.getPlayer().stop();
847          }
848       };
849       EventQueue.invokeLater(update);
850    }
851 
852    /**
853     * Plays the selected track immediately.
854     * <p>
855     * @param aEvent the Action Event fired for this button
856     */
857    public void playImmediately(final ActionEvent aEvent) {
858       LOG.debug("Play Immediately");
859       final JComponent source = (JComponent) aEvent.getSource();
860       final Object editor = source.getClientProperty(Resources.EDITOR_COMPONENT);
861       final Runnable update = new Runnable() {
862          public void run() {
863 
864             if (editor != null) {
865                final Player player = getMainFrame().getPlayer();
866                final Playlist playlist = getMainFrame().getPlaylist();
867 
868                if (editor instanceof JTree) {
869                   final JTree tree = (JTree) editor;
870                   for (int i = 0; i < tree.getSelectionPaths().length; i++) {
871                      final TreePath path = tree.getSelectionPaths()[i];
872                      if (path.getLastPathComponent() instanceof AbstractTreeNode) {
873                         final AbstractTreeNode node = (AbstractTreeNode) path.getLastPathComponent();
874                         // AZ look for filtered discs
875                         if (node instanceof ArtistNode) {
876                            final int nodeCount = node.getChildCount();
877                            if (nodeCount > 0) {
878                               for (int ii = 0; ii < node.getChildCount(); ii++) {
879                                  final AbstractTreeNode childNode = (AbstractTreeNode) node.getChildAt(ii);
880                                  playlist.addNext(childNode.getModel());
881                               }
882                            }
883                         } else {
884                            playlist.addNext(node.getModel());
885                         }
886                      }
887                   }
888                }
889 
890                if (editor instanceof JList) {
891                   final JList list = (JList) editor;
892                   final Object[] selections = list.getSelectedValues();
893                   for (int i = selections.length - 1; i >= 0; i--) {
894                      Track track = null;
895                      if (selections[i] instanceof JukesValidationMessage) {
896                         final JukesValidationMessage message = (JukesValidationMessage) selections[i];
897                         track = (Track) message.getDomainObject();
898                         playlist.addNext(track);
899                      } else if (selections[i] instanceof Track) {
900                         track = (Track) selections[i];
901                         playlist.addNext(track);
902                      }
903                   }
904                }
905                if (editor instanceof JTable) {
906                   final JTable table = (JTable) editor;
907                   final int[] selections = table.getSelectedRows();
908                   final SearchTableModel model = (SearchTableModel) table.getModel();
909                   for (int i = 0; i < selections.length; i++) {
910                      int selectedRow = selections[i];
911                      selectedRow = table.getRowSorter().convertRowIndexToModel(selectedRow);
912                      Track track = (Track) model.getData()[selectedRow];
913                      playlist.addNext(track);
914                   }
915                }
916                if (editor instanceof AlbumImage) {
917                   final AlbumImage image = (AlbumImage) editor;
918                   if (image.getDisc() != null) {
919                      playlist.addNext(image.getDisc());
920                   }
921                }
922                final Track next = (Track) playlist.getNextImmediate();
923                if (next != null) {
924                   player.play(next.getTrackUrl());
925                }
926 
927             }
928          }
929       };
930       EventQueue.invokeLater(update);
931    }
932 
933    /**
934     * Closes the playlist.
935     * <p>
936     * @param aEvent the Actionevent fired
937     */
938    public void playlistClose(final ActionEvent aEvent) {
939       LOG.debug("Close Playlist.");
940       getMainFrame().getMainPageBuilder().setPlaylistVisible(false);
941 
942    }
943 
944    /**
945     * Shows or hides the playlist.
946     * <p>
947     * @param aEvent the Actionevent fired
948     */
949    public void playlistDisplay(final ActionEvent aEvent) {
950       LOG.debug("Playlist displayed/hidden.");
951       String currentPanel = getMainFrame().getMainPageBuilder().panelVisible();
952       boolean visible;
953       if (currentPanel == "playlistPanel") {
954          visible = false;
955       } else {
956          visible = true;
957       }
958       getMainFrame().getMainPageBuilder().setPlaylistVisible(visible);
959 
960    }
961 
962    /**
963     * Go to the track in the navigator.
964     * <p>
965     * @param aEvent the Actionevent fired
966     */
967    public void playlistGoto(final ActionEvent aEvent) {
968       LOG.debug("Playlist goto.");
969       final Track selection;
970       final JComponent button = (JComponent) aEvent.getSource();
971       final JList editor = (JList) button.getClientProperty(Resources.EDITOR_COMPONENT);
972       try {
973          GuiUtil.setBusyCursor(getDefaultParentFrame(), true);
974          if (editor.getSelectedValue() != null) {
975             // AZ - ensure the availability of tree node
976             selection = (Track) editor.getSelectedValue();
977             String query = " and upper(disc.name) = '"
978                      + selection.getDisc().getName().toUpperCase().replaceAll("'", "''") + "'";
979             String filter = MainModule.SETTINGS.getFilter();
980             if (!(MainModule.SETTINGS.isShowDefaultTree() && !StringUtils.isNotBlank(filter))) {
981                filter = query;
982             }
983             MainModule.SETTINGS.setFilter(filter);
984             getMainModule().refreshTree();
985             getMainModule().selectNodeInTree(editor.getSelectedValue());
986          } else {
987             MessageUtil.showInformation(Application.getDefaultParentFrame(), ResourceUtils
988                      .getString("messages.SelectSomethingToGoTo"));
989          }
990       } finally {
991          GuiUtil.setBusyCursor(getDefaultParentFrame(), false);
992       }
993    }
994 
995    /**
996     * Loads a playlist from a file.
997     * <p>
998     * @param aEvent the Action Event fired for this button
999     */
1000    public void playlistLoad(final ActionEvent aEvent) {
1001       LOG.debug("Load Playlist");
1002       final JComponent button = (JComponent) aEvent.getSource();
1003       final PlaylistPanel editor = (PlaylistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1004       editor.load();
1005    }
1006 
1007    /**
1008     * Moves a track down on the playlist.
1009     * <p>
1010     * @param aEvent the Actionevent fired
1011     */
1012    public void playlistMoveDown(final ActionEvent aEvent) {
1013       LOG.debug("Move down playlist");
1014       final JComponent button = (JComponent) aEvent.getSource();
1015       final PlaylistPanel editor = (PlaylistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1016       editor.moveDown();
1017 
1018    }
1019 
1020    /**
1021     * Moves the selected tracks over to the other list.
1022     * <p>
1023     * @param aEvent the Action Event fired for this button
1024     */
1025    public void playlistMoveOver(final ActionEvent aEvent) {
1026       LOG.debug("Move over playlist");
1027       final JComponent button = (JComponent) aEvent.getSource();
1028       final PlaylistPanel editor = (PlaylistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1029       editor.moveOver();
1030 
1031    }
1032 
1033    /**
1034     * Moves a track up on the playlist.
1035     * <p>
1036     * @param aEvent the Actionevent fired
1037     */
1038    public void playlistMoveUp(final ActionEvent aEvent) {
1039       LOG.debug("Move up playlist");
1040       final JComponent button = (JComponent) aEvent.getSource();
1041       final PlaylistPanel editor = (PlaylistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1042       editor.moveUp();
1043    }
1044 
1045    /**
1046     * Removes tracks from the playlist.
1047     * <p>
1048     * @param aEvent the Actionevent fired
1049     */
1050    public void playlistRemoveTracks(final ActionEvent aEvent) {
1051       LOG.debug("Remove tracks from playlist");
1052       final JComponent button = (JComponent) aEvent.getSource();
1053       final PlaylistPanel editor = (PlaylistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1054       editor.removeTracks();
1055       editor.repaint(); // AZ repaint PlaylistPanel
1056       // getMainFrame().getMainPageBuilder().refreshUI();
1057    }
1058 
1059    /**
1060     * Clears all tracks from the playlist.
1061     * <p>
1062     * @param aEvent the Actionevent fired
1063     */
1064    public void playlistClear(ActionEvent aEvent) {
1065       LOG.debug("Clear tracks from playlist");
1066       final JComponent button = (JComponent) aEvent.getSource();
1067       final PlaylistPanel editor = (PlaylistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1068       editor.removeAllTracks();
1069       editor.repaint(); // AZ repaint PlaylistPanel
1070       // getMainFrame().getMainPageBuilder().refreshUI();
1071 
1072    }
1073 
1074    /**
1075     * Saves a playlist to disk.
1076     * <p>
1077     * @param aEvent the Action Event fired for this button
1078     */
1079    public void playlistSave(final ActionEvent aEvent) {
1080       LOG.debug("Save playlist.");
1081       final JComponent button = (JComponent) aEvent.getSource();
1082       final PlaylistPanel editor = (PlaylistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1083       editor.save();
1084    }
1085 
1086    /**
1087     * Toggles between shuffling the catalog or not.
1088     * <p>
1089     * @param aEvent the Action Event fired for this button
1090     */
1091    public void playlistShuffleCatalog(final ActionEvent aEvent) {
1092       LOG.debug("Shuffle catalog.");
1093       final JToggleButton button = (JToggleButton) aEvent.getSource();
1094       final PlaylistPanel editor = (PlaylistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1095       editor.shuffleCatalog(button.isSelected());
1096 
1097       if (button.isSelected()) {
1098          final Player player = getMainFrame().getPlayer();
1099          // if the player was stopped then play the next song
1100          if ((player.getStatus() == BasicPlayer.STOPPED) || (player.getStatus() == BasicPlayer.UNKNOWN)) {
1101             playerNext(null);
1102          }
1103       }
1104    }
1105 
1106    /**
1107     * Toggles between shuffling the playlist or not.
1108     * <p>
1109     * @param aEvent the Action Event fired for this button
1110     */
1111    public void playlistShuffleList(final ActionEvent aEvent) {
1112       LOG.debug("Shuffle playlist.");
1113       final JToggleButton button = (JToggleButton) aEvent.getSource();
1114       final PlaylistPanel editor = (PlaylistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1115       editor.shufflePlaylist(button.isSelected());
1116    }
1117 
1118    /**
1119     * Toggles between history and current playlist.
1120     * <p>
1121     * @param aEvent the Action Event fired for this button
1122     */
1123    public void playlistToggle(final ActionEvent aEvent) {
1124       LOG.debug("Toggle playlist.");
1125       final JToggleButton button = (JToggleButton) aEvent.getSource();
1126       final PlaylistPanel editor = (PlaylistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1127       editor.toggle(!button.isSelected());
1128    }
1129 
1130    /**
1131     * Export preferences to an XML file.
1132     * <p>
1133     * @param aEvent the Action Event fired for this button
1134     */
1135    public void preferencesExport(final ActionEvent aEvent) {
1136       LOG.debug("Export Preferences");
1137       final MainFrame mainFrame = (MainFrame) Application.getDefaultParentFrame();
1138       final JFileChooser chooser = new JFileChooser();
1139       chooser.setDialogTitle(Resources.getString("label.ExportPreferences"));
1140       chooser.setFileFilter(FilterFactory.xmlFileFilter());
1141       chooser.setMultiSelectionEnabled(false);
1142       chooser.setFileHidingEnabled(true);
1143       final int returnVal = chooser.showSaveDialog(this.getDefaultParentFrame());
1144       if (returnVal != JFileChooser.APPROVE_OPTION) {
1145          return;
1146       }
1147       File file = chooser.getSelectedFile();
1148       if (LOG.isDebugEnabled()) {
1149          LOG.debug(file.getAbsolutePath());
1150       }
1151 
1152       // add the extension if missing
1153       file = FilterFactory.forceXmlExtension(file);
1154 
1155       // now try and save the prefernces to a file
1156       try {
1157          final Preferences prefs = Application.getUserPreferences();
1158          final FileOutputStream stream = new FileOutputStream(file);
1159          prefs.exportSubtree(stream);
1160 
1161          MessageUtil.showInformation(getDefaultParentFrame(), Resources
1162                   .getString("messages.Preferencesexportedsuccessfully"));
1163       } catch (IOException ex) {
1164          MessageUtil.showError(mainFrame, ERROR_WRITING_FILE + LINE_BREAK + ex.getMessage()); // AZ
1165          LOG.error(ERROR_WRITING_FILE + LINE_BREAK + ex, ex);
1166       } catch (Exception ex) {
1167          MessageUtil.showError(mainFrame, ERROR_WRITING_FILE); // AZ
1168          LOG.error("Unexpected error writing file.", ex);
1169       }
1170    }
1171 
1172    /**
1173     * Import preferences from an XML file.
1174     * <p>
1175     * @param aEvent the Action Event fired for this button
1176     */
1177    public void preferencesImport(final ActionEvent aEvent) {
1178       LOG.debug("Import Preferences");
1179       final MainFrame mainFrame = (MainFrame) Application.getDefaultParentFrame();
1180       final JFileChooser chooser = new JFileChooser();
1181       chooser.setDialogTitle(Resources.getString("label.ImportPreferences"));
1182       chooser.setFileFilter(FilterFactory.xmlFileFilter());
1183       chooser.setMultiSelectionEnabled(false);
1184       chooser.setFileHidingEnabled(true);
1185       final int returnVal = chooser.showOpenDialog(this.getDefaultParentFrame());
1186       if (returnVal != JFileChooser.APPROVE_OPTION) {
1187          return;
1188       }
1189       final File file = chooser.getSelectedFile();
1190       if (LOG.isDebugEnabled()) {
1191          LOG.debug(file.getAbsolutePath());
1192       }
1193 
1194       // now try and import the preferences from a file
1195       try {
1196          final FileInputStream stream = new FileInputStream(file);
1197          Preferences.importPreferences(stream);
1198 
1199          MainModule.SETTINGS.restoreFrom(Application.getUserPreferences());
1200 
1201          MessageUtil.showInformation(getDefaultParentFrame(), Resources
1202                   .getString("messages.Preferencesimportedsuccessfully"));
1203       } catch (IOException ex) {
1204          MessageUtil.showError(mainFrame, ERROR_WRITING_FILE + LINE_BREAK + ex.getMessage()); // AZ
1205          LOG.error(ERROR_WRITING_FILE + LINE_BREAK + ex.getMessage(), ex);
1206       } catch (Exception ex) {
1207          MessageUtil.showError(mainFrame, ERROR_WRITING_FILE); // AZ
1208          LOG.error("Unexpected error writing file.", ex);
1209       }
1210    }
1211 
1212    /**
1213     * Adds track(s) to the bottom of the queue.
1214     * <p>
1215     * @param aEvent the Action Event fired for this button
1216     */
1217    public void queue(final ActionEvent aEvent) {
1218       LOG.debug("Queue");
1219       final JComponent source = (JComponent) aEvent.getSource();
1220       final Component editor = (Component) source.getClientProperty(Resources.EDITOR_COMPONENT);
1221       if (editor != null) {
1222          final Playlist playlist = getMainFrame().getPlaylist();
1223          // check if the playlist is empty. If it is then set a flag to
1224          // start playing the next song immediately
1225          // final boolean startPlaying = (playlist.sizeNext() == 0);
1226 
1227          if (editor instanceof JTree) {
1228             final JTree tree = (JTree) editor;
1229             for (int i = 0; i < tree.getSelectionPaths().length; i++) {
1230                final TreePath path = tree.getSelectionPaths()[i];
1231                if (path.getLastPathComponent() instanceof AbstractTreeNode) {
1232                   final AbstractTreeNode node = (AbstractTreeNode) path.getLastPathComponent();
1233                   // AZ look for filtered discs
1234                   if (node instanceof ArtistNode) {
1235                      final int nodeCount = node.getChildCount();
1236                      if (nodeCount > 0) {
1237                         for (int ii = 0; ii < node.getChildCount(); ii++) {
1238                            final AbstractTreeNode childNode = (AbstractTreeNode) node.getChildAt(ii);
1239                            playlist.add(childNode.getModel());
1240                         }
1241                      }
1242                   } else {
1243                      playlist.add(node.getModel());
1244                   }
1245                }
1246             }
1247          }
1248 
1249          if (editor instanceof JList) {
1250             final JList list = (JList) editor;
1251             final Object[] selections = list.getSelectedValues();
1252             for (int i = 0; i < selections.length; i++) {
1253                final JukesValidationMessage message = (JukesValidationMessage) selections[i];
1254                playlist.add(message.getDomainObject());
1255             }
1256          }
1257 
1258          if (editor instanceof JTable) {
1259             final JTable table = (JTable) editor;
1260             final int[] selections = table.getSelectedRows();
1261             if (table.getModel() instanceof DiscTableModel) { // AZ - processing
1262                // of
1263                // DiscTableModel
1264                // added
1265                final DiscTableModel model = (DiscTableModel) table.getModel();
1266                for (int i = 0; i < selections.length; i++) {
1267                   int selectedRow = selections[i];
1268                   selectedRow = table.getRowSorter().convertRowIndexToModel(selectedRow);
1269                   playlist.add(model.getData()[selectedRow]);
1270                }
1271             } else {
1272                final SearchTableModel model = (SearchTableModel) table.getModel();
1273                for (int i = 0; i < selections.length; i++) {
1274                   int selectedRow = selections[i];
1275                   selectedRow = table.getRowSorter().convertRowIndexToModel(selectedRow);
1276                   playlist.add(model.getData()[selectedRow]);
1277                }
1278             }
1279          }
1280          if (editor instanceof AlbumImage) {
1281             final AlbumImage image = (AlbumImage) editor;
1282             if (image.getDisc() != null) {
1283                playlist.add(image.getDisc());
1284             }
1285          }
1286 
1287          getMainFrame().getMainPageBuilder().refreshUI();
1288       }
1289    }
1290 
1291    /**
1292     * Adds track(s) to the top of the queue.
1293     * <p>
1294     * @param aEvent the Action Event fired for this button
1295     */
1296    /**
1297     * @param aEvent
1298     */
1299    /**
1300     * @param aEvent
1301     */
1302    public void queueNext(final ActionEvent aEvent) {
1303       LOG.debug("Queue Next");
1304       final JComponent source = (JComponent) aEvent.getSource();
1305       final Component editor = (Component) source.getClientProperty(Resources.EDITOR_COMPONENT);
1306       if (editor != null) {
1307          final Playlist playlist = getMainFrame().getPlaylist();
1308 
1309          if (editor instanceof JTree) {
1310             final JTree tree = (JTree) editor;
1311             for (int i = tree.getSelectionPaths().length - 1; i >= 0; i--) {
1312                final TreePath path = tree.getSelectionPaths()[i];
1313                if (path.getLastPathComponent() instanceof AbstractTreeNode) {
1314                   final AbstractTreeNode node = (AbstractTreeNode) path.getLastPathComponent();
1315                   // AZ look for filtered discs
1316                   if (node instanceof ArtistNode) {
1317                      final int nodeCount = node.getChildCount();
1318                      if (nodeCount > 0) {
1319                         for (int ii = 0; ii < node.getChildCount(); ii++) {
1320                            final AbstractTreeNode childNode = (AbstractTreeNode) node.getChildAt(ii);
1321                            playlist.addNext(childNode.getModel());
1322                         }
1323                      }
1324                   } else {
1325                      playlist.addNext(node.getModel());
1326                   }
1327                }
1328             }
1329          }
1330 
1331          if (editor instanceof JList) {
1332             final JList list = (JList) editor;
1333             final Object[] selections = list.getSelectedValues();
1334             for (int i = selections.length - 1; i >= 0; i--) {
1335                final JukesValidationMessage message = (JukesValidationMessage) selections[i];
1336                playlist.addNext(message.getDomainObject());
1337             }
1338          }
1339 
1340          if (editor instanceof JTable) {
1341             final JTable table = (JTable) editor;
1342             final int[] selections = table.getSelectedRows();
1343             if (table.getModel() instanceof DiscTableModel) { // AZ - processing
1344                // of
1345                // DiscTableModel
1346                // added
1347                final DiscTableModel model = (DiscTableModel) table.getModel();
1348                for (int i = 0; i < selections.length; i++) {
1349                   int selectedRow = selections[i];
1350                   selectedRow = table.getRowSorter().convertRowIndexToModel(selectedRow);
1351                   playlist.addNext(model.getData()[selectedRow]);
1352                }
1353             } else {
1354                final SearchTableModel model = (SearchTableModel) table.getModel();
1355                for (int i = 0; i < selections.length; i++) {
1356                   int selectedRow = selections[i];
1357                   selectedRow = table.getRowSorter().convertRowIndexToModel(selectedRow);
1358                   playlist.addNext(model.getData()[selectedRow]);
1359                }
1360             }
1361          }
1362 
1363          if (editor instanceof AlbumImage) {
1364             final AlbumImage image = (AlbumImage) editor;
1365             if (image.getDisc() != null) {
1366                playlist.addNext(image.getDisc());
1367             }
1368          }
1369 
1370          getMainFrame().getMainPageBuilder().refreshUI();
1371       }
1372    }
1373 
1374    /**
1375     * Refreshes the data from the database and reloads the tree
1376     * <p>
1377     * @param aEvent the Action Event fired for this button
1378     */
1379    public void refresh(final ActionEvent aEvent) {
1380       LOG.debug("Refreshing Data.");
1381       GuiUtil.setBusyCursor(getDefaultParentFrame(), true);
1382       // completely evict the session and clear all loaded objects.
1383       // HibernateUtil.getSession().clear();
1384 
1385       // refresh the tree
1386       getMainModule().refreshTree();
1387       GuiUtil.setBusyCursor(getDefaultParentFrame(), false);
1388    }
1389 
1390    /**
1391     * Rolls changes back to orginal form.
1392     * <p>
1393     * @param aEvent the Action Event fired for this button
1394     */
1395    public void rollback(final ActionEvent aEvent) {
1396       LOG.debug("Rollback Changes");
1397       final JComponent button = (JComponent) aEvent.getSource();
1398       final AbstractEditor editor = (AbstractEditor) button.getClientProperty(Resources.EDITOR_COMPONENT);
1399       editor.rollback();
1400    }
1401 
1402    /**
1403     * Searches the database.
1404     * <p>
1405     * @param aEvent the actionevent fired
1406     */
1407    public void search(final ActionEvent aEvent) {
1408       LOG.debug("Search");
1409       final SearchDialog dialog = new SearchDialog(getDefaultParentFrame(), MainModule.SETTINGS);
1410       dialog.open();
1411 
1412       if (!dialog.hasBeenCanceled()) {
1413          try {
1414             GuiUtil.setBusyCursor(getDefaultParentFrame(), true);
1415             getMainModule().selectNodeInTree(dialog.getSelection());
1416          } finally {
1417             GuiUtil.setBusyCursor(getDefaultParentFrame(), false);
1418          }
1419       }
1420 
1421    }
1422 
1423    /**
1424     * Shows the main window.
1425     */
1426    public void showMainWindow() {
1427       if (SystemUtils.IS_OS_WINDOWS) {
1428          final MainFrame mainframe = (MainFrame) getDefaultParentFrame();
1429          mainframe.getTrayIcon().showWindow();
1430       }
1431    }
1432 
1433    /**
1434     * Displays the statistics dialog.
1435     * <p>
1436     * @param aEvent the Action Event fired for this button
1437     */
1438    public void statistics(final ActionEvent aEvent) {
1439       LOG.debug("Statistics Dialog");
1440       final MainFrame mainframe = (MainFrame) getDefaultParentFrame();
1441 
1442       GuiUtil.setBusyCursor(mainframe, true);// AZ
1443       new StatisticsDialog(getDefaultParentFrame()).open();
1444       GuiUtil.setBusyCursor(mainframe, false);// AZ
1445    }
1446 
1447    /**
1448     * Converts the associated TextComponent to title case.
1449     * <p>
1450     * @param aEvent the Action Event fired for this button
1451     */
1452    public void titleCase(final ActionEvent aEvent) {
1453       final JComponent button = (JComponent) aEvent.getSource();
1454       final JTextComponent text = (JTextComponent) button.getClientProperty(Resources.TEXT_COMPONENT);
1455       if (LOG.isDebugEnabled()) {
1456          LOG.debug("Capitalizing '" + text.getText() + "'");
1457       }
1458       text.setText(FileUtil.capitalize(text.getText()));
1459    }
1460 
1461    /**
1462     * Unlocks the current editor for editing.
1463     * <p>
1464     * @param aEvent the Action Event fired for this button
1465     */
1466    public void unlock(final ActionEvent aEvent) {
1467       LOG.debug("Unlock item for editing");
1468       final JComponent button = (JComponent) aEvent.getSource();
1469       final AbstractEditor editor = (AbstractEditor) button.getClientProperty(Resources.EDITOR_COMPONENT);
1470       editor.unlock();
1471    }
1472 
1473    /**
1474     * Displays a report with all albums without cover artwork.
1475     * <p>
1476     * @param aEvent the Action Event fired for this button
1477     */
1478    public void reportNoCoverArt(ActionEvent aEvent) {
1479       LOG.debug("Report: Albums Without Cover Artwork");
1480       runReport("/reports/nocoverart.jasper", new HashMap());
1481    }
1482 
1483    /**
1484     * Displays a report with the entire catalog in alphabetical order.
1485     * <p>
1486     * @param aEvent the Action Event fired for this button
1487     */
1488    public void reportCatalog(ActionEvent aEvent) {
1489       LOG.debug("Report: Catalog");
1490       runReport("/reports/catalog.jasper", new HashMap());
1491    }
1492 
1493    /**
1494     * AZ Displays a report to display all albums for specified artist.
1495     * <p>
1496     * @param aEvent the Action Event fired for this button
1497     */
1498    public void reportAlbumsForArtist(ActionEvent aEvent) {
1499       LOG.debug("Report: Albums for Artist");
1500 
1501       final HashMap<String, String> map = new HashMap<String, String>();
1502       // get list of all artists sorted by artist name
1503       GuiUtil.setBusyCursor(getDefaultParentFrame(), true);
1504       final String hql = ResourceUtils.getString("hql.artist.all.sorted");
1505       final List artistsList = HibernateDao.findByQuery(hql);
1506       final List artistNames = new ArrayList();
1507       Artist artist;
1508       String artistName;
1509       final Object[] artists;
1510       for (int i = 0; i < artistsList.size(); i++) {
1511          artist = (Artist) artistsList.get(i);
1512          artistName = artist.getName();
1513          if (artistName.length() > 40) {
1514             artistName = artistName.substring(0, 40);
1515          }
1516          artistNames.add(artistName);
1517       }
1518       artists = artistNames.toArray();
1519       JComboBox artistField = new JComboBox(artists);
1520       JPanel panel = new JPanel();
1521       panel.add(new JLabel(Resources.getString("label.SelectArtistName")));
1522       panel.add(artistField);
1523       Integer response = JOptionPane.showConfirmDialog(null, panel, Resources.getString("label.AlbumsforArtistReport"),
1524                JOptionPane.OK_CANCEL_OPTION);
1525       final String selectedArtistName = artistField.getSelectedItem().toString();
1526       GuiUtil.setBusyCursor(getDefaultParentFrame(), false);
1527       if (response == 0) {
1528          if (StringUtils.isNotEmpty(selectedArtistName)) {
1529             map.put("selectedartist", selectedArtistName);
1530             runReport("/reports/albumsforartist.jasper", map);
1531          }
1532       }
1533    }
1534 
1535    /**
1536     * AZ Displays a report with the entire catalog in alphabetical order of
1537     * genres.
1538     * <p>
1539     * @param aEvent the Action Event fired for this button
1540     */
1541    public void reportCatalogByGenres(ActionEvent aEvent) {
1542       LOG.debug("Report: Catalog By Genres");
1543       runReport("/reports/catalogbygenres.jasper", new HashMap());
1544    }
1545 
1546    /**
1547     * Displays a report with the list of discs in the range of bitrates.
1548     * <p>
1549     * @param aEvent the Action Event fired for this button
1550     */
1551    public void reportBitrate(ActionEvent aEvent) {
1552       LOG.debug("Report: Bitrate");
1553       final HashMap<String, Integer> map = new HashMap<String, Integer>();
1554       JComboBox bitrateFromField = new JComboBox(Resources.BITRATES);
1555       JComboBox bitrateToField = new JComboBox(Resources.BITRATES);
1556 
1557       JPanel panel = new JPanel();
1558       panel.add(new JLabel(Resources.getString("label.bitrateFrom")));
1559       panel.add(bitrateFromField);
1560       panel.add(new JLabel(Resources.getString("label.bitrateTo")));
1561       panel.add(bitrateToField);
1562       GridLayout grid = new GridLayout(); // Create a layout manager
1563       grid.setVgap(10);
1564       grid.setColumns(2);
1565       grid.setRows(2);
1566       panel.setLayout(grid);
1567 
1568       Integer response = JOptionPane.showConfirmDialog(null, panel, Resources.getString("label.BitrateReport"),
1569                JOptionPane.OK_CANCEL_OPTION);
1570       if (response == 0) {
1571          int bitrateFrom = Integer.parseInt(bitrateFromField.getSelectedItem().toString());
1572          int bitrateTo = Integer.parseInt(bitrateToField.getSelectedItem().toString());
1573          if (bitrateFrom > bitrateTo) {
1574             MessageUtil.showError(null, Resources.getString("messages.BitrateError"));
1575          } else {
1576             map.put("bitratefrom", bitrateFrom);
1577             map.put("bitrateto", bitrateTo);
1578             runReport("/reports/bitrate.jasper", map);
1579          }
1580       }
1581    }
1582 
1583    /**
1584     * AZ Displays a report to display all genres used.
1585     * <p>
1586     * @param aEvent the Action Event fired for this button
1587     */
1588    public void reportGenres(ActionEvent aEvent) {
1589       LOG.debug("Report: Genres");
1590       final HashMap<String, Integer> map = new HashMap<String, Integer>();
1591       runReport("/reports/genres.jasper", map);
1592    }
1593 
1594    /**
1595     * Invokes the application shutdown mechanism. Currently it uses the poor
1596     * assumption that the default parent frame is an instance of
1597     * <code>AbstractMainFrame</code>.
1598     * <p>
1599     */
1600    void aboutToExitApplication() {
1601       ((MainFrame) getDefaultParentFrame()).aboutToExitApplication();
1602    }
1603 
1604    /**
1605     * Opens the about dialog.
1606     */
1607    void helpAbout() {
1608       new DefaultAboutDialog(getDefaultParentFrame()).open();
1609    }
1610 
1611    /**
1612     * Opens the tip-of-the-day dialog.
1613     */
1614    void openTipOfTheDayDialog() {
1615       final String tipIndexPath = Application.getConfiguration().getTipIndexPath();
1616       new TipOfTheDayDialog(getDefaultParentFrame(), tipIndexPath).open();
1617    }
1618 
1619    /**
1620     * Opens the preferences dialog.
1621     */
1622    void preferences() {
1623       new PreferencesDialog(getDefaultParentFrame(), MainModule.SETTINGS).open();
1624    }
1625 
1626    /**
1627     * Gets the default parent frame of the application.
1628     * <p>
1629     * @return the default parent frame
1630     */
1631    private Frame getDefaultParentFrame() {
1632       return Application.getDefaultParentFrame();
1633    }
1634 
1635    /**
1636     * Gets the main frame of the application.
1637     * <p>
1638     * @return the main frame of the application
1639     */
1640    private MainFrame getMainFrame() {
1641       return (MainFrame) getDefaultParentFrame();
1642    }
1643 
1644    /**
1645     * Gets the MainModule of the application.
1646     * <p>
1647     * @return the MainModule of the application
1648     */
1649    private MainModule getMainModule() {
1650       return mainModule;
1651    }
1652 
1653    /**
1654     * Runs a Jasper Report that should be found in the classpath.
1655     * <p>
1656     * @param aReport the location on the classpath to find the report
1657     * @param aParameters the hashmap of parameters
1658     */
1659    @SuppressWarnings("deprecation")
1660    private void runReport(String aReport, HashMap aParameters) {
1661       try {
1662          GuiUtil.setBusyCursor(getDefaultParentFrame(), true);
1663          final JasperPrint print = JasperFillManager.fillReport(MainController.class.getResourceAsStream(aReport),
1664                   aParameters, HibernateUtil.getSession().connection());
1665          GuiUtil.setBusyCursor(getDefaultParentFrame(), false);
1666          JasperViewer.viewReport(print, false);
1667       } catch (HibernateException ex) {
1668          LOG.error("HibernateException", ex);
1669       } catch (InfrastructureException ex) {
1670          LOG.error("InfrastructureException", ex);
1671       } catch (JRException ex) {
1672          LOG.error("JRException", ex);
1673       }
1674    }
1675 
1676    /**
1677     * Closes the disclist.
1678     * <p>
1679     * @param aEvent the Actionevent fired
1680     */
1681    public void disclistClose(final ActionEvent aEvent) {
1682       LOG.debug("Close Disclist.");
1683       getMainFrame().getMainPageBuilder().setDisclistVisible(false);
1684    }
1685 
1686    /**
1687     * Go to the disc in the navigator.
1688     * <p>
1689     * @param aEvent the Actionevent fired
1690     */
1691    public void disclistGoto(final ActionEvent aEvent) {
1692       LOG.debug("Disclist goto.");
1693       final Disc selection;
1694       final JComponent button = (JComponent) aEvent.getSource();
1695       final JList editor = (JList) button.getClientProperty(Resources.EDITOR_COMPONENT);
1696       try {
1697          GuiUtil.setBusyCursor(getDefaultParentFrame(), true);
1698          if (editor.getSelectedValue() != null) {
1699             // AZ - ensure the availability of tree node
1700             selection = (Disc) editor.getSelectedValue();
1701             String query = " and upper(disc.name) = '" + selection.getName().toUpperCase().replaceAll("'", "''") + "'";
1702             String filter = MainModule.SETTINGS.getFilter();
1703             if (!(MainModule.SETTINGS.isShowDefaultTree() && !StringUtils.isNotBlank(filter))) {
1704                filter = query;
1705             }
1706             MainModule.SETTINGS.setFilter(filter);
1707             getMainModule().refreshTree();
1708             getMainModule().selectNodeInTree(editor.getSelectedValue());
1709          } else {
1710             MessageUtil.showInformation(Application.getDefaultParentFrame(), ResourceUtils
1711                      .getString("messages.SelectSomethingToGoTo"));
1712          }
1713       } finally {
1714          GuiUtil.setBusyCursor(getDefaultParentFrame(), false);
1715       }
1716    }
1717 
1718    /**
1719     * Loads a disclist from a file.
1720     * <p>
1721     * @param aEvent the Action Event fired for this button
1722     */
1723    public void disclistLoad(final ActionEvent aEvent) {
1724       LOG.debug("Load Disclist");
1725       final JComponent button = (JComponent) aEvent.getSource();
1726       final DisclistPanel editor = (DisclistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1727       editor.load();
1728    }
1729 
1730    /**
1731     * Moves a track down on the disclist.
1732     * <p>
1733     * @param aEvent the Actionevent fired
1734     */
1735    public void disclistMoveDown(final ActionEvent aEvent) {
1736       LOG.debug("Move down disclist");
1737       final JComponent button = (JComponent) aEvent.getSource();
1738       final DisclistPanel editor = (DisclistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1739       editor.moveDown();
1740    }
1741 
1742    /**
1743     * Moves a track up on the disclist.
1744     * <p>
1745     * @param aEvent the Actionevent fired
1746     */
1747    public void disclistMoveUp(final ActionEvent aEvent) {
1748       LOG.debug("Move up disclist");
1749       final JComponent button = (JComponent) aEvent.getSource();
1750       final DisclistPanel editor = (DisclistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1751       editor.moveUp();
1752    }
1753 
1754    /**
1755     * Removes tracks from the disclist.
1756     * <p>
1757     * @param aEvent the Actionevent fired
1758     */
1759    public void disclistRemoveTracks(final ActionEvent aEvent) {
1760       LOG.debug("Remove discs from disclist");
1761       final JComponent button = (JComponent) aEvent.getSource();
1762       final DisclistPanel editor = (DisclistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1763       editor.removeDisc();
1764       editor.repaint(); // repaint DisclistPanel
1765       // getMainFrame().getMainPageBuilder().refreshUI();
1766    }
1767 
1768    /**
1769     * Clears all tracks from the disclist.
1770     * <p>
1771     * @param aEvent the Actionevent fired
1772     */
1773    public void disclistClear(ActionEvent aEvent) {
1774       LOG.debug("Clear discs from disclist");
1775       final JComponent button = (JComponent) aEvent.getSource();
1776       final DisclistPanel editor = (DisclistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1777       editor.removeAllDiscs();
1778       editor.repaint();
1779    }
1780 
1781    /**
1782     * Saves a disclist to disk.
1783     * <p>
1784     * @param aEvent the Action Event fired for this button
1785     */
1786    public void disclistSave(final ActionEvent aEvent) {
1787       LOG.debug("Save disclist.");
1788       final JComponent button = (JComponent) aEvent.getSource();
1789       final DisclistPanel editor = (DisclistPanel) button.getClientProperty(Resources.EDITOR_COMPONENT);
1790       editor.save();
1791    }
1792 
1793    /**
1794     * Shows or hides the disclist.
1795     * <p>
1796     * @param aEvent the Actionevent fired
1797     */
1798    public void disclistDisplay(final ActionEvent aEvent) {
1799       LOG.debug("Disclist displayed/hidden.");
1800       String currentPanel = getMainFrame().getMainPageBuilder().panelVisible();
1801       boolean visible;
1802       if (currentPanel == "disclistPanel") {
1803          visible = false;
1804       } else {
1805          visible = true;
1806       }
1807       getMainFrame().getMainPageBuilder().setDisclistVisible(visible);
1808 
1809    }
1810 
1811    /**
1812     * Adds disc(s) to the bottom of the disclist.
1813     * <p>
1814     * @param aEvent the Action Event fired for this button
1815     */
1816    public void addToDisclist(final ActionEvent aEvent) {
1817       LOG.debug("Add to disclist");
1818       final MainFrame mainFrame = (MainFrame) Application.getDefaultParentFrame();
1819       final JComponent source = (JComponent) aEvent.getSource();
1820       final Component editor = (Component) source.getClientProperty(Resources.EDITOR_COMPONENT);
1821       if (editor != null) {
1822 
1823          final Disclist disclist = getMainFrame().getDisclist();
1824          if (editor instanceof JTree) {
1825             final JTree tree = (JTree) editor;
1826             for (int i = 0; i < tree.getSelectionPaths().length; i++) {
1827                final TreePath path = tree.getSelectionPaths()[i];
1828                if (path.getLastPathComponent() instanceof AbstractTreeNode) {
1829                   final AbstractTreeNode node = (AbstractTreeNode) path.getLastPathComponent();
1830                   // AZ look for filtered discs
1831                   if (node instanceof ArtistNode) {
1832                      final int nodeCount = node.getChildCount();
1833                      if (nodeCount > 0) {
1834                         for (int ii = 0; ii < node.getChildCount(); ii++) {
1835                            final AbstractTreeNode childNode = (AbstractTreeNode) node.getChildAt(ii);
1836                            disclist.add(childNode.getModel());
1837                         }
1838                      }
1839                   } else {
1840                      disclist.add(node.getModel());
1841                   }
1842                }
1843             }
1844          }
1845 
1846          if (editor instanceof JList) {
1847             final JList list = (JList) editor;
1848             final Object[] selections = list.getSelectedValues();
1849             for (int i = 0; i < selections.length; i++) {
1850                final JukesValidationMessage message = (JukesValidationMessage) selections[i];
1851                disclist.add(message.getDomainObject());
1852             }
1853          }
1854          if (editor instanceof JTable) {
1855             final JTable table = (JTable) editor;
1856             final int[] selections = table.getSelectedRows();
1857             if (selections.length == 0) {
1858                MessageUtil.showMessage(mainFrame, Resources.getString("messages.SelectDisc"));
1859                ;
1860             }
1861             if (table.getModel() instanceof DiscTableModel) { // AZ - processing
1862                // of
1863                // DiscTableModel
1864                // added
1865                final DiscTableModel model = (DiscTableModel) table.getModel();
1866                for (int i = 0; i < selections.length; i++) {
1867                   int selectedRow = selections[i];
1868                   selectedRow = table.getRowSorter().convertRowIndexToModel(selectedRow);
1869                   disclist.add(model.getData()[selectedRow]);
1870                }
1871             } else {
1872                final SearchTableModel model = (SearchTableModel) table.getModel();
1873                for (int i = 0; i < selections.length; i++) {
1874                   int selectedRow = selections[i];
1875                   selectedRow = table.getRowSorter().convertRowIndexToModel(selectedRow);
1876                   disclist.add(model.getData()[selectedRow]);
1877                }
1878             }
1879          }
1880          if (editor instanceof AlbumImage) {
1881             final AlbumImage image = (AlbumImage) editor;
1882             if (image.getDisc() != null) {
1883                disclist.add(image.getDisc());
1884             }
1885          }
1886          getMainFrame().getMainPageBuilder().refreshUI();
1887       }
1888    }
1889 
1890    /**
1891     * Set selected disc as current disc.
1892     * <p>
1893     * @param aEvent the Action Event fired for this button
1894     */
1895    public void setCurrent(final ActionEvent aEvent) {
1896       LOG.debug("Set disc as current");
1897       final Disclist disclist = getMainFrame().getDisclist();
1898       Disc currentDisc = disclist.getCurrentDisc();
1899       final JComponent source = (JComponent) aEvent.getSource();
1900       final Component editor = (Component) source.getClientProperty(Resources.EDITOR_COMPONENT);
1901       if (editor instanceof JList) {
1902          final JList list = (JList) editor;
1903          final Object[] selections = list.getSelectedValues();
1904          if (selections.length != 0) {
1905             currentDisc = (Disc) selections[0];
1906             disclist.setCurrentDisc(currentDisc);
1907             disclist.updateState();
1908          }
1909       }
1910    }
1911 
1912    /**
1913     * AZ Displays the XML Export tool dialog.
1914     * <p>
1915     * @param aEvent the Action Event fired for this button
1916     */
1917    public void xmlExport(final ActionEvent aEvent) {
1918       LOG.debug("XML Export Dialog");
1919       // Select xml-file to write to
1920       final JFileChooser chooser = new JFileChooser();
1921       chooser.setDialogTitle(Resources.getString("label.ExportCatalog"));
1922       chooser.setFileFilter(FilterFactory.xmlFileFilter());
1923       chooser.setMultiSelectionEnabled(false);
1924       chooser.setFileHidingEnabled(true);
1925       final int returnVal = chooser.showSaveDialog(this.getDefaultParentFrame());
1926       if (returnVal != JFileChooser.APPROVE_OPTION) {
1927          return;
1928       }
1929       File file = chooser.getSelectedFile();
1930       // add the extension if missing
1931       file = FilterFactory.forceXmlExtension(file);
1932 
1933       // open dialog with progress bar and run export Thread
1934       new XMLExportDialog(getDefaultParentFrame(), MainModule.SETTINGS, file).open();
1935    }
1936 
1937    /**
1938     * AZ Displays the XML Import tool dialog.
1939     * <p>
1940     * @param aEvent the Action Event fired for this button
1941     */
1942    public void xmlImport(final ActionEvent aEvent) {
1943       LOG.debug("XML Import Dialog");
1944       // Select xml-file to read from
1945       final JFileChooser chooser = new JFileChooser();
1946       chooser.setDialogTitle(Resources.getString("label.ImportCatalog"));
1947       chooser.setFileFilter(FilterFactory.xmlFileFilter());
1948       chooser.setMultiSelectionEnabled(false);
1949       chooser.setFileHidingEnabled(true);
1950       final int returnVal = chooser.showOpenDialog(this.getDefaultParentFrame());
1951       if (returnVal != JFileChooser.APPROVE_OPTION) {
1952          return;
1953       }
1954       File file = chooser.getSelectedFile();
1955       // add the extension if missing
1956       file = FilterFactory.forceXmlExtension(file);
1957 
1958       // open dialog with progress bar and run import Thread
1959       new XMLImportDialog(getDefaultParentFrame(), MainModule.SETTINGS, file).open();
1960    }
1961 
1962 }