View Javadoc

1   package com.melloware.jukes.gui.view;
2   
3   import java.awt.BorderLayout;
4   import java.awt.Dimension;
5   import java.awt.EventQueue;
6   import java.awt.FlowLayout;
7   import java.awt.event.ActionEvent;
8   import java.awt.event.ActionListener;
9   import java.beans.PropertyChangeEvent;
10  import java.beans.PropertyChangeListener;
11  import java.util.Map;
12  import java.util.prefs.Preferences;
13  
14  import javax.swing.BorderFactory;
15  import javax.swing.JComponent;
16  import javax.swing.JLabel;
17  import javax.swing.JPanel;
18  import javax.swing.JProgressBar;
19  import javax.swing.JSlider;
20  import javax.swing.JSplitPane;
21  import javax.swing.JToolBar;
22  import javax.swing.Timer;
23  import javax.swing.event.ChangeEvent;
24  import javax.swing.event.ChangeListener;
25  
26  import javazoom.jlgui.basicplayer.BasicController;
27  import javazoom.jlgui.basicplayer.BasicPlayer;
28  import javazoom.jlgui.basicplayer.BasicPlayerEvent;
29  import javazoom.jlgui.basicplayer.BasicPlayerListener;
30  
31  import org.apache.commons.lang.StringUtils;
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.log4j.Level;
35  import org.apache.log4j.Logger;
36  
37  import com.jgoodies.looks.LookUtils;
38  import com.jgoodies.uif.action.ActionManager;
39  import com.jgoodies.uif.application.Application;
40  import com.jgoodies.uif.panel.SimpleInternalFrame;
41  import com.jgoodies.uif.util.ComponentTreeUtils;
42  import com.jgoodies.uifextras.util.ActionLabel;
43  import com.jgoodies.uifextras.util.UIFactory;
44  import com.melloware.jukes.db.HibernateUtil;
45  import com.melloware.jukes.db.orm.Track;
46  import com.melloware.jukes.file.Disclist;
47  import com.melloware.jukes.file.Playlist;
48  import com.melloware.jukes.file.image.ImageFactory;
49  import com.melloware.jukes.gui.tool.Actions;
50  import com.melloware.jukes.gui.tool.MainModule;
51  import com.melloware.jukes.gui.tool.Resources;
52  import com.melloware.jukes.gui.tool.Settings;
53  import com.melloware.jukes.gui.view.editor.ArtistEditor;
54  import com.melloware.jukes.gui.view.editor.DiscEditor;
55  import com.melloware.jukes.gui.view.editor.EditorPanel;
56  import com.melloware.jukes.gui.view.editor.EmptyPanel;
57  import com.melloware.jukes.gui.view.editor.TrackEditor;
58  import com.melloware.jukes.gui.view.editor.WelcomePanel;
59  import com.melloware.jukes.util.MessageUtil;
60  import com.melloware.jukes.util.TimeSpan;
61  
62  /**
63   * Builds the main page of the Jukes application: the tool bar, navigator, help
64   * navigation, all editors, the dynamic help viewer, and the status bar.
65   * <p>
66   * Copyright (c) 1999-2007 Melloware, Inc. <http://www.melloware.com>
67   * @author Emil A. Lefkof III <info@melloware.com>
68   * @version 4.0 AZ Development 2009, 2010
69   */
70  public final class MainPageBuilder implements BasicPlayerListener {
71  
72     private static final Log LOG = LogFactory.getLog(MainPageBuilder.class);
73     private static final Dimension PREFERRED_SIZE = LookUtils.IS_LOW_RESOLUTION ? new Dimension(800, 600)
74              : new Dimension(1024, 768);
75     private static final String MAIN_DIVIDER_LOCATION_KEY = "mainDividerLocation";
76     private static final String VIEWER_DIVIDER_LOCATION_KEY = "viewerDividerLocation";
77     private static final String NAVIGATOR_DIVIDER_LOCATION_KEY = "navigatorDividerLocation";
78     private static final String NAVIGATOR_VISIBLE_KEY = "navigatorVisible";
79     private static final String PLAYLIST_VISIBLE_KEY = "playlistVisible";
80     private static final String DISCLIST_VISIBLE_KEY = "disclistVisible"; // AZ
81     private static final TimeSpan TIMESPAN = new TimeSpan(0);
82     private ActionLabel trackField;
83     private EditorPanel editorPanel;
84     private FilterPanel filterPanel;
85     private JLabel bitrateField;
86     private JLabel durationField;
87     private JPanel mainPage;
88     private JProgressBar elapsedBar;
89     private JSplitPane editorPlaylistSplitPane;
90     private JSplitPane mainSplitPane;
91     private JSplitPane navigatorSplitPane;
92     private long elapsedTime;
93     private final MainFrame mainframe;
94     private final MainModule mainModule;
95     private Map audioInfo;
96     private NavigationPanelBuilder navigationPanel;
97     private final Playlist playlist;
98     private PlaylistPanel playlistPanel;
99     private final Disclist disclist; // AZ
100    private DisclistPanel disclistPanel; // AZ
101    private SimpleInternalFrame navigator;
102    private Timer timer;
103    private Boolean playlistVisible; // AZ
104    private Boolean disclistVisible; // AZ
105    private JSlider volumeSlider; // AZ
106 
107    /**
108     * Constructs a MainPageBuilder for the given main module.
109     * @param mainModule provides high-level models
110     */
111    MainPageBuilder(MainModule mainModule) {
112       this.mainModule = mainModule;
113       this.playlist = new Playlist();
114       this.disclist = new Disclist();
115       this.mainModule.addPropertyChangeListener(this.playlist);
116       this.mainModule.addPropertyChangeListener(this.disclist);
117       this.mainframe = (MainFrame) Application.getDefaultParentFrame();
118       MainModule.SETTINGS.addPropertyChangeListener(new PresentationSettingsChangeHandler());
119    }
120 
121    /**
122     * Gets the playlist.
123     * <p>
124     * @return Returns the playlist.
125     */
126    public Playlist getPlaylist() {
127       return this.playlist;
128    }
129 
130    /**
131     * Gets the disclist.
132     * <p>
133     * @return Returns the disclist.
134     */
135    public Disclist getDisclist() {
136       return this.disclist;
137    }
138 
139    /*
140     * (non-Javadoc)
141     * @see
142     * javazoom.jlgui.basicplayer.BasicPlayerListener#setController(javazoom.
143     * jlgui.basicplayer.BasicController)
144     */
145    public void setController(BasicController controller) {
146       if (LOG.isDebugEnabled()) {
147          LOG.debug("Controller " + controller);
148       }
149    }
150 
151    /**
152     * Sets the visibility of the filter panel.
153     */
154    public void setFilterVisible(boolean b) {
155       if (isFilterVisible() == b) {
156          return;
157       }
158       if (b) {
159          navigatorSplitPane.setTopComponent(navigator);
160          navigatorSplitPane.setBottomComponent(filterPanel);
161          int navigatorDividerLocation = Application.getUserPreferences().getInt(NAVIGATOR_DIVIDER_LOCATION_KEY, -1);
162          if ((navigatorDividerLocation > 50) && (navigatorDividerLocation < (mainPage.getHeight() - 50))) {
163             navigatorSplitPane.setDividerLocation(navigatorDividerLocation);
164          }
165       } else {
166          navigatorSplitPane.setTopComponent(navigator);
167          navigatorSplitPane.setBottomComponent(null);
168       }
169    }
170 
171    /**
172     * Sets the visibility of the playlist panel.
173     * <p>
174     * @param visible whether or not the window is visible
175     */
176    public void setPlaylistVisible(boolean visible) {
177       if (visible) {
178          editorPlaylistSplitPane.setTopComponent(editorPanel);
179          editorPlaylistSplitPane.setBottomComponent(playlistPanel);
180          int verticalDividerLocation = Application.getUserPreferences().getInt(VIEWER_DIVIDER_LOCATION_KEY, -1);
181          if ((verticalDividerLocation > 100) && (verticalDividerLocation < (mainPage.getHeight() - 50))) {
182             editorPlaylistSplitPane.setDividerLocation(verticalDividerLocation);
183          }
184          playlistVisible = true;
185       } else {
186          if (disclistVisible != null) {
187             if (disclistVisible) {
188                editorPlaylistSplitPane.setBottomComponent(disclistPanel);
189             } else {
190                editorPlaylistSplitPane.setBottomComponent(null);
191             }
192             editorPlaylistSplitPane.setTopComponent(editorPanel);
193             playlistVisible = false;
194          } else {
195             editorPlaylistSplitPane.setTopComponent(editorPanel);
196             editorPlaylistSplitPane.setBottomComponent(null);
197             playlistVisible = false;
198          }
199       }
200    }
201 
202    /**
203     * Answers if the filter panel is visible.
204     */
205    public boolean isFilterVisible() {
206       return navigatorSplitPane.getBottomComponent() != null;
207    }
208 
209    /**
210     * Answers if the playlist panel is visible.
211     */
212    public boolean isPlaylistVisible() {
213       return playlistVisible;
214       // return editorPlaylistSplitPane.getBottomComponent() != null;
215    }
216 
217    /*
218     * (non-Javadoc)
219     * @see
220     * javazoom.jlgui.basicplayer.BasicPlayerListener#opened(java.lang.Object,
221     * java.util.Map)
222     */
223    public void opened(Object stream, Map properties) {
224       audioInfo = properties;
225 
226       /*
227        * mp3.frequency.hz='44100' title='We' mp3.length.bytes='6078464'
228        * comment='Test Comments !' mp3.channels='2' date='2003'
229        * mp3.version.layer='3' mp3.framesize.bytes='413' mp3.id3tag.track='3'
230        * mp3.version.mpeg='1' mp3.bitrate.nominal.bps='229000'
231        * mp3.vbr.scale='78' copyright='copy' mp3.length.frames='8122'
232        * mp3.crc='false' album='The Sta no Expe' mp3.vbr='true'
233        * mp3.copyright='false' mp3.framerate.fps='38.28125'
234        * mp3.id3tag.v2='java.io.ByteArrayInputStream@13caecd'
235        * mp3.id3tag.v2.version='3' mp3.version.encoding='MPEG1L3'
236        * mp3.header.pos='2150' mp3.id3tag.genre='(18)Techno'
237        * mp3.original='false' mp3.mode='1' mp3.padding='false' author='Scer'
238        * duration='212167000' vbr='true' bitrate='229000'
239        */
240       final Track track = playlist.getCurrentTrack();
241       final String title = track.getName();
242       final String disc = track.getDisc().getName();
243       final String artist = track.getDisc().getArtist().getName();
244       final Long duration = Long.valueOf(track.getDuration() * 1000);
245       final String bitrate = (track.getBitrate().intValue()) + " kbps";
246       final Runnable updateList = new Runnable() {
247          public void run() {
248             trackField.setText(artist + " - " + disc + " - " + title);
249             bitrateField.setText(bitrate);
250             final int ms = (int) (duration.longValue());
251             TIMESPAN.setTime(duration.longValue());
252             durationField.setText(TIMESPAN.getMusicDuration());
253             elapsedBar.setValue(0);
254             elapsedBar.setMaximum(ms);
255 
256             // set the tray icon tooltip
257             if (mainframe.getTrayIcon() != null) {
258                mainframe.getTrayIcon().setToolTip(artist + " - " + title);
259             }
260 
261             // refresh the window
262             refreshUI();
263          }
264       };
265       EventQueue.invokeLater(updateList);
266 
267    }
268 
269    /*
270     * (non-Javadoc)
271     * @see javazoom.jlgui.basicplayer.BasicPlayerListener#progress(int, long,
272     * byte[], java.util.Map)
273     */
274    public void progress(int bytesread, long microseconds, byte[] pcmdata, Map properties) {
275       if (audioInfo.containsKey("audio.type")) {
276          String audioformat = (String) audioInfo.get("audio.type");
277          LOG.debug(audioformat);
278          /**
279           * AZ Suspended Spectrum analyzer if
280           * (audioformat.equalsIgnoreCase("mp3")) {
281           * mainframe.getAnalyzer().writeDSP(pcmdata); }
282           **/
283       }
284 
285       this.setElapsedTime(microseconds);
286    }
287 
288    /**
289     * Repaints the screen after a track changes.
290     */
291    public void refreshUI() {
292       navigator.updateUI();
293       editorPanel.updateUI();
294    }
295 
296    /**
297     * Restores the frame's state from the user preferences.
298     */
299    public void restoreFrom(Preferences userPrefs) {
300       int mainDividerLocation = userPrefs.getInt(MAIN_DIVIDER_LOCATION_KEY, -1);
301       int verticalDividerLocation = userPrefs.getInt(VIEWER_DIVIDER_LOCATION_KEY, -1);
302       int navigatorDividerLocation = userPrefs.getInt(NAVIGATOR_DIVIDER_LOCATION_KEY, -1);
303       setDisclistVisible(userPrefs.getBoolean(DISCLIST_VISIBLE_KEY, false)); // AZ
304       setPlaylistVisible(userPrefs.getBoolean(PLAYLIST_VISIBLE_KEY, true));
305       setFilterVisible(userPrefs.getBoolean(NAVIGATOR_VISIBLE_KEY, true));
306 
307       if ((mainDividerLocation > 100) && (mainDividerLocation < (mainPage.getWidth() - 50))) {
308          mainSplitPane.setDividerLocation(mainDividerLocation);
309       }
310       if ((verticalDividerLocation > 100) && (verticalDividerLocation < (mainPage.getHeight() - 50))) {
311          editorPlaylistSplitPane.setDividerLocation(verticalDividerLocation);
312       }
313       if ((navigatorDividerLocation > 50) && (navigatorDividerLocation < (mainPage.getHeight() - 50))) {
314          navigatorSplitPane.setDividerLocation(navigatorDividerLocation);
315       }
316    }
317 
318    /*
319     * (non-Javadoc)
320     * @see
321     * javazoom.jlgui.basicplayer.BasicPlayerListener#stateUpdated(javazoom.jlgui
322     * .basicplayer.BasicPlayerEvent)
323     */
324    public void stateUpdated(BasicPlayerEvent event) {
325       if (LOG.isDebugEnabled()) {
326          LOG.debug("stateUpdated : " + event.toString());
327       }
328       // final SpectrumTimeAnalyzer analyzer = mainframe.getAnalyzer(); //AZ
329       // Suspended Spectrum analyzer
330 
331       switch (event.getCode()) {
332       // case BasicPlayerEvent.PLAYING: {
333       // break;
334       // }
335       case BasicPlayerEvent.PLAYING:
336       case BasicPlayerEvent.OPENED:
337       case BasicPlayerEvent.RESUMED: {
338          mainframe.updateTrayIcon(ImageFactory.ICO_TRAYPLAY.getImage());
339          /**
340           * AZ Suspended Spectrum analyzer if
341           * ((audioInfo.containsKey("basicplayer.sourcedataline")) && (analyzer
342           * != null)) { analyzer.setupDSP((SourceDataLine)audioInfo.get(
343           * "basicplayer.sourcedataline"));
344           * analyzer.startDSP((SourceDataLine)audioInfo
345           * .get("basicplayer.sourcedataline")); }
346           **/
347          timer.start();
348          break;
349       }
350       case BasicPlayerEvent.PAUSED: {
351          timer.stop();
352          mainframe.updateTrayIcon(ImageFactory.ICO_TRAYPAUSE.getImage());
353          break;
354       }
355       case BasicPlayerEvent.STOPPED: {
356          timer.stop();
357          mainframe.updateTrayIcon(ImageFactory.ICO_TRAYSTOP.getImage());
358          /**
359           * AZ Suspended Spectrum analyzer if (analyzer != null) {
360           * analyzer.stopDSP(); analyzer.repaint(); }
361           **/
362 
363          final Runnable updateList = new Runnable() {
364             public void run() {
365                elapsedBar.setValue(0);
366                TIMESPAN.setTime(0);
367                elapsedBar.setString(TIMESPAN.getMusicDuration());
368             }
369          };
370          EventQueue.invokeLater(updateList);
371          break;
372       }
373       case BasicPlayerEvent.EOM: {
374          timer.stop();
375          final Track track = (Track) getPlaylist().getNext();
376          if (track != null) {
377             mainframe.getPlayer().play(track.getTrackUrl());
378          }
379          break;
380       }
381       default: {
382          break;
383       }
384       }
385    }
386 
387    /**
388     * Stores the frame's state in the user preferences.
389     */
390    public void storeIn(Preferences userPrefs) {
391       if (isPlaylistVisible()) {
392          int verticalDividerLocation = editorPlaylistSplitPane.getDividerLocation();
393          userPrefs.putInt(VIEWER_DIVIDER_LOCATION_KEY, verticalDividerLocation);
394       }
395       if (isFilterVisible()) {
396          int navigatorDividerLocation = navigatorSplitPane.getDividerLocation();
397          userPrefs.putInt(NAVIGATOR_DIVIDER_LOCATION_KEY, navigatorDividerLocation);
398       }
399       // AZ
400       if (isDisclistVisible()) {
401          int verticalDividerLocation = editorPlaylistSplitPane.getDividerLocation();
402          userPrefs.putInt(VIEWER_DIVIDER_LOCATION_KEY, verticalDividerLocation);
403       }
404       int mainDividerLocation = mainSplitPane.getDividerLocation();
405       userPrefs.putInt(MAIN_DIVIDER_LOCATION_KEY, mainDividerLocation);
406       userPrefs.putBoolean(NAVIGATOR_VISIBLE_KEY, isFilterVisible());
407       userPrefs.putBoolean(PLAYLIST_VISIBLE_KEY, isPlaylistVisible());
408       userPrefs.putBoolean(DISCLIST_VISIBLE_KEY, isDisclistVisible());
409    }
410 
411    /**
412     * Builds this panel with the horizontal <code>JSplitPane</code> in the
413     * center and a status bar in the south.
414     */
415    JComponent build() {
416       initComponents();
417 
418       mainPage = new RefreshedPanel();
419       mainPage.setLayout(new BorderLayout());
420       mainPage.add(new MainToolBarBuilder().build(), BorderLayout.NORTH);
421       mainPage.add(buildMainSplitPane(), BorderLayout.CENTER);
422       mainPage.add(buildStatusBar(), BorderLayout.SOUTH);
423       mainPage.setPreferredSize(PREFERRED_SIZE);
424 
425       return mainPage;
426    }
427 
428    /**
429     * Builds the <code>EditorPanel</code>, the <code>PlaylistPanel</code> and
430     * answers them wrapped by a stripped <code>JSplitPane</code>.
431     */
432    private JComponent buildEditorHelpPanel() {
433       editorPlaylistSplitPane = UIFactory.createStrippedSplitPane(JSplitPane.VERTICAL_SPLIT, buildEditorPanel(),
434                playlistPanel, 0.667);
435       return editorPlaylistSplitPane;
436    }
437 
438    /**
439     * Builds and answers the <code>EditorPanel</code>.
440     */
441    private EditorPanel buildEditorPanel() {
442       WelcomePanel welcomePanel = new WelcomePanel();
443 
444       editorPanel.addEditor(welcomePanel);
445       editorPanel.addEditor(new EmptyPanel());
446       editorPanel.addEditor(new ArtistEditor());
447       editorPanel.addEditor(new DiscEditor());
448       editorPanel.addEditor(new TrackEditor());
449 
450       editorPanel.setActiveEditor(welcomePanel);
451       return editorPanel;
452    }
453 
454    /**
455     * Builds the <code>Navigator</code>, the <code>HelpNavigator</code> and
456     * answers them wrapped by a stripped <code>JSplitPane</code>.
457     */
458    private JComponent buildFilterPanel() {
459       return UIFactory.createStrippedSplitPane(JSplitPane.VERTICAL_SPLIT, navigator, filterPanel, 0.64);
460    }
461 
462    /**
463     * Builds and answers the main <code>JSplitPane</code> that contains the
464     * navigation elements on the left, and the view panels on the right.
465     */
466    private JComponent buildMainSplitPane() {
467       navigatorSplitPane = (JSplitPane) buildFilterPanel();
468       mainSplitPane = UIFactory.createStrippedSplitPane(JSplitPane.HORIZONTAL_SPLIT, navigatorSplitPane,
469                buildEditorHelpPanel(), 0.25);
470       mainSplitPane.setBorder(BorderFactory.createEmptyBorder(6, 4, 0, 4));
471       return mainSplitPane;
472    }
473 
474    /**
475     * Builds and answers the status bar.
476     */
477    private JPanel buildStatusBar() {
478       final JPanel statusPanel = new JPanel(new BorderLayout());
479       final JPanel infoPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
480       final JToolBar toolbar = MainToolBarBuilder.buildPlayerToolBar();
481       toolbar.setBorder(BorderFactory.createEmptyBorder());
482       infoPanel.setBorder(BorderFactory.createEmptyBorder());
483       statusPanel.add(toolbar, BorderLayout.WEST);
484       statusPanel.add(infoPanel, BorderLayout.EAST);
485       statusPanel.setBorder(BorderFactory.createEmptyBorder());
486       infoPanel.add(trackField);
487       trackField.setBorder(BorderFactory.createEmptyBorder());
488       infoPanel.add(bitrateField);
489       bitrateField.setBorder(BorderFactory.createEmptyBorder());
490       infoPanel.add(durationField);
491       durationField.setBorder(BorderFactory.createEmptyBorder());
492       infoPanel.add(elapsedBar);
493       elapsedBar.setBorder(BorderFactory.createEmptyBorder());
494       infoPanel.add(volumeSlider);
495       volumeSlider.setBorder(BorderFactory.createEmptyBorder());
496       return statusPanel;
497    }
498 
499    /**
500     * Creates, binds and configures the subpanels and components.
501     */
502    private void initComponents() {
503       navigator = new SimpleInternalFrame(Resources.getString("navigator.label"));
504       navigator.setFrameIcon(Resources.NAVIGATOR_ICON);
505       navigationPanel = new NavigationPanelBuilder(mainModule);
506       navigator.setContent(navigationPanel.build());
507       navigator.setSelected(true);
508       navigator.setMinimumSize(new Dimension(100, 100));
509       navigator.setPreferredSize(new Dimension(160, 200));
510       navigator.setFrameIcon(Resources.NAVIGATOR_ICON);
511 
512       filterPanel = new FilterPanel(MainModule.SETTINGS);
513       filterPanel.setSelected(true);
514       filterPanel.setMinimumSize(new Dimension(100, 45));
515       filterPanel.setPreferredSize(new Dimension(100, 45));
516 
517       editorPanel = new EditorPanel(mainModule);
518       editorPanel.setMinimumSize(new Dimension(200, 100));
519       editorPanel.setPreferredSize(new Dimension(400, 200));
520 
521       playlistPanel = new PlaylistPanel(this.playlist);
522       playlistPanel.setName("playlistPanel");
523       playlistPanel.setMinimumSize(new Dimension(300, 100));
524       playlistPanel.setPreferredSize(new Dimension(300, 100));
525 
526       // AZ
527       disclistPanel = new DisclistPanel(this.disclist);
528       disclistPanel.setName("disclistPanel");
529       disclistPanel.setMinimumSize(new Dimension(300, 100));
530       disclistPanel.setPreferredSize(new Dimension(300, 100));
531 
532       trackField = new ActionLabel("");
533       trackField.addActionListener(new ActionListener() {
534 
535          // select the track in the editor
536          public void actionPerformed(ActionEvent event) {
537             LOG.debug("Track clicked");
538             if (playlist.getCurrentTrack() != null) {
539                mainModule.selectNodeInTree(playlist.getCurrentTrack());
540             }
541          }
542       });
543       bitrateField = UIFactory.createPlainLabel("");
544       durationField = UIFactory.createPlainLabel("");
545       elapsedBar = new JProgressBar(0, 1);
546       elapsedBar.setIndeterminate(false);
547       elapsedBar.setStringPainted(true);
548       elapsedBar.setString("");
549 
550       // Set volumeSlider
551       int iVolume = (int) (100 * mainframe.getPlayer().getVolume());
552       // Perform bounds test, -1 or >100 can occur in some undefined cases
553       if (iVolume > 100) {
554          iVolume = 100;
555       } else if (iVolume < 0) {
556          iVolume = 0;
557       }
558       volumeSlider = new JSlider();
559       volumeSlider.setValue(iVolume);
560       volumeSlider.setToolTipText(Resources.getString("label.Volume") + ": " + iVolume + " %");
561       volumeSlider.addChangeListener(new VolumeChangeAction());
562 
563       timer = new Timer(950, new ActionListener() {
564 
565          public void actionPerformed(ActionEvent aE) {
566             final int elapsed = (int) (getElapsedTime() / 1000);
567             TIMESPAN.setTime(elapsed);
568             elapsedBar.setValue(elapsed);
569             elapsedBar.setString(TIMESPAN.getMusicDuration());
570          }
571       });
572    }
573 
574    /**
575     * Gets the elapsedTime.
576     * <p>
577     * @return Returns the elapsedTime.
578     */
579    protected synchronized long getElapsedTime() {
580       return this.elapsedTime;
581    }
582 
583    /**
584     * Sets the elapsedTime.
585     * <p>
586     * @param aElapsedTime The elapsedTime to set.
587     */
588    protected synchronized void setElapsedTime(long aElapsedTime) {
589       this.elapsedTime = aElapsedTime;
590    }
591 
592    // Updates the application if settings changed
593    private class PresentationSettingsChangeHandler implements PropertyChangeListener {
594 
595       /**
596        * The presentation settings have changed.
597        * @param evt describes the property change
598        */
599       public void propertyChange(PropertyChangeEvent evt) {
600          final String[] props = { Settings.PROPERTYNAME_AUDIT_INFO, Settings.PROPERTYNAME_COVER_SIZE_LARGE,
601                   Settings.PROPERTYNAME_COVER_SIZE_SMALL };
602          final String[] refreshprops = { Settings.PROPERTYNAME_DISPLAY_FORMAT_DISC,
603                   Settings.PROPERTYNAME_DISPLAY_FORMAT_TRACK, Settings.PROPERTYNAME_NEW_FILE_IN_DAYS };
604          final String[] connectProps = { Settings.PROPERTYNAME_REMOTE_DATABASE_URL,
605                   Settings.PROPERTYNAME_DIRECTORY_DB_LOCATION };
606 
607          if (Settings.PROPERTYNAME_PLAYER_BUFFER_SIZE.equals(evt.getPropertyName())) {
608             LOG.debug("Buffer size changed");
609             BasicPlayer.EXTERNAL_BUFFER_SIZE = MainModule.SETTINGS.getPlayerBufferSize();
610          }
611 
612          if (Settings.PROPERTYNAME_LOG_LEVEL.equals(evt.getPropertyName())) {
613             LOG.info("Log Level changed");
614             Logger.getRootLogger().setLevel(Level.toLevel(MainModule.SETTINGS.getLogLevel()));
615             Logger.getLogger("com.melloware").setLevel(Level.toLevel(MainModule.SETTINGS.getLogLevel()));
616             Logger.getLogger("com.melloware.jukes.gui").setLevel(Level.toLevel(MainModule.SETTINGS.getLogLevel()));
617          }
618 
619          // if any of the editor settings changes reload
620          if (StringUtils.indexOfAny(evt.getPropertyName(), props) >= 0) {
621             LOG.debug("Editor options changed");
622             editorPanel.clearEditors();
623             buildEditorPanel();
624          }
625 
626          // do we need to reconnect on prop change
627          if (StringUtils.indexOfAny(evt.getPropertyName(), connectProps) >= 0) {
628             LOG.debug("DB Location changed, reconnecting to DB and refreshing tree.");
629             HibernateUtil.shutdown();
630             final String remoteURL = MainModule.SETTINGS.getRemoteDatabaseURL();
631             if ((StringUtils.isNotBlank(remoteURL)) && (!Settings.DEFAULT_REMOTE_DATABASE_URL.equals(remoteURL))) {
632                HibernateUtil.setRemoteUrl(remoteURL);
633             } else {
634                HibernateUtil.setRemoteUrl(null);
635             }
636             ActionManager.get(Actions.CONNECT_ID).actionPerformed(null);
637          }
638 
639          // do we need to refresh the tree on prop change
640          if (StringUtils.indexOfAny(evt.getPropertyName(), refreshprops) >= 0) {
641             LOG.debug("Navigation options changed.");
642             ActionManager.get(Actions.REFRESH_ID).actionPerformed(null);
643          }
644          /**
645           * AZ Suspended Spectrum analyzer if
646           * (Settings.PROPERTYNAME_ANALYZER_MODE.equals(evt.getPropertyName()))
647           * { mainframe.getAnalyzer().setDisplayMode(MainModule.SETTINGS.
648           * getAnalyzerMode()); }
649           **/
650       }
651    }
652 
653    private class RefreshedPanel extends JPanel {
654 
655       /**
656        * In case some panels are invisible, we explicitly update their UIs.
657        */
658       @Override
659       public void updateUI() {
660          super.updateUI();
661          if (getComponentCount() == 0) {
662             return;
663          }
664          if ((editorPlaylistSplitPane == null) || isPlaylistVisible()) {
665             return;
666          }
667          ComponentTreeUtils.updateComponentTreeUI(editorPlaylistSplitPane);
668       }
669 
670    }
671 
672    /**
673     * Sets the visibility of the disclist panel.
674     * <p>
675     * @param visible whether or not the window is visible
676     */
677    public void setDisclistVisible(boolean visible) {
678       if (visible) {
679          editorPlaylistSplitPane.setTopComponent(editorPanel);
680          editorPlaylistSplitPane.setBottomComponent(disclistPanel);
681          int verticalDividerLocation = Application.getUserPreferences().getInt(VIEWER_DIVIDER_LOCATION_KEY, -1);
682          if ((verticalDividerLocation > 100) && (verticalDividerLocation < (mainPage.getHeight() - 50))) {
683             editorPlaylistSplitPane.setDividerLocation(verticalDividerLocation);
684          }
685          disclistVisible = true;
686       } else {
687          if (playlistVisible != null) {
688             if (playlistVisible) {
689                editorPlaylistSplitPane.setBottomComponent(playlistPanel);
690             } else {
691                editorPlaylistSplitPane.setBottomComponent(null);
692             }
693             editorPlaylistSplitPane.setTopComponent(editorPanel);
694             disclistVisible = false;
695          } else {
696             editorPlaylistSplitPane.setTopComponent(editorPanel);
697             editorPlaylistSplitPane.setBottomComponent(null);
698             disclistVisible = false;
699          }
700       }
701    }
702 
703    /**
704     * Answers if the disclist panel is visible.
705     */
706    public boolean isDisclistVisible() {
707       // AZ
708       return disclistVisible;
709       // return editorPlaylistSplitPane.getBottomComponent() != null;
710    }
711 
712    /**
713     * Returns the name of list panel currently visible.
714     */
715    public String panelVisible() {
716       String panelName;
717       if (editorPlaylistSplitPane.getBottomComponent() != null) {
718          panelName = editorPlaylistSplitPane.getBottomComponent().getName();
719       } else {
720          panelName = "No Panel";
721       }
722       return panelName;
723    }
724 
725    public class VolumeChangeAction implements ChangeListener {
726       @Override
727       public void stateChanged(ChangeEvent e) {
728          int iVolume = volumeSlider.getValue();
729          float fVolume = iVolume / 100f;
730          try {
731             mainframe.getPlayer().setVolume(fVolume);
732             volumeSlider.setToolTipText(Resources.getString("label.Volume") + ": " + iVolume + " %");
733          } catch (Exception ex) {
734             LOG.error("Set Volume Exception: ", ex);
735             MessageUtil.showError(null, "Set Volume Exception: " + ex.getMessage());
736          }
737       }
738    }
739 
740 }