View Javadoc

1   package com.melloware.jukes.gui.view;
2   
3   import java.awt.Dimension;
4   import java.awt.event.ActionEvent;
5   import java.awt.event.ActionListener;
6   import java.awt.event.MouseAdapter;
7   import java.awt.event.MouseEvent;
8   import java.awt.event.MouseListener;
9   import java.beans.PropertyChangeEvent;
10  import java.beans.PropertyChangeListener;
11  import java.io.File;
12  import java.io.IOException;
13  
14  import javax.swing.AbstractButton;
15  import javax.swing.JComponent;
16  import javax.swing.JFileChooser;
17  import javax.swing.JLabel;
18  import javax.swing.JList;
19  import javax.swing.JPopupMenu;
20  import javax.swing.JScrollPane;
21  import javax.swing.JToolBar;
22  import javax.swing.ListSelectionModel;
23  import javax.swing.ProgressMonitor;
24  import javax.swing.Timer;
25  import javax.swing.UIManager;
26  import javax.swing.border.TitledBorder;
27  import javax.swing.filechooser.FileFilter;
28  
29  import org.apache.commons.lang.StringUtils;
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.xml.sax.SAXParseException;
33  
34  import com.jgoodies.forms.builder.PanelBuilder;
35  import com.jgoodies.forms.layout.CellConstraints;
36  import com.jgoodies.forms.layout.FormLayout;
37  import com.jgoodies.uif.action.ActionManager;
38  import com.jgoodies.uif.application.Application;
39  import com.jgoodies.uif.builder.ToolBarBuilder;
40  import com.jgoodies.uif.panel.SimpleInternalFrame;
41  import com.jgoodies.uif.util.ResourceUtils;
42  import com.jgoodies.uifextras.util.UIFactory;
43  import com.melloware.jukes.db.orm.Disc;
44  import com.melloware.jukes.file.Disclist;
45  import com.melloware.jukes.file.filter.FilterFactory;
46  import com.melloware.jukes.file.image.ImageFactory;
47  import com.melloware.jukes.gui.tool.Actions;
48  import com.melloware.jukes.gui.tool.MainModule;
49  import com.melloware.jukes.gui.tool.Resources;
50  import com.melloware.jukes.gui.view.component.AlbumImage;
51  import com.melloware.jukes.gui.view.component.ComponentFactory;
52  import com.melloware.jukes.gui.view.component.DisclistCellRenderer;
53  import com.melloware.jukes.gui.view.component.DisclistListModel;
54  import com.melloware.jukes.gui.view.tasks.LoadDisclistTask;
55  import com.melloware.jukes.gui.view.tasks.TimerListener;
56  import com.melloware.jukes.util.GuiUtil;
57  import com.melloware.jukes.util.MessageUtil;
58  
59  /**
60   * Display the disclist and all the disclist options.
61   * <p>
62   * Copyright (c) 1999-2007 Melloware, Inc. <http://www.melloware.com>
63   * @author Emil A. Lefkof III <info@melloware.com>
64   * @version 4.0 2009 AZ Development
65   */
66  public final class DisclistPanel extends SimpleInternalFrame implements PropertyChangeListener {
67  
68     private static final Log LOG = LogFactory.getLog(DisclistPanel.class);
69     private AlbumImage albumImage;
70     private JLabel artist;
71     private JLabel bitrate;
72     private JLabel disc;
73     private JLabel year;
74     private final JList discList;
75     private JScrollPane disclistScrollPane;
76     private final Disclist disclist;
77     private final DisclistListModel disclistModel;
78  
79     /**
80      * Constructs a <code>DisclistPanel</code> for the given module.
81      * @param aDisclist provides the disclist class needed for display
82      */
83     DisclistPanel(Disclist aDisclist) {
84        super(Resources.DISCLIST_ICON, ResourceUtils.getString("label.disclist"));
85        LOG.debug("Disclist panel created.");
86  
87        this.disclist = aDisclist;
88        this.disclist.addPropertyChangeListener(this);
89  
90        // build disclist and assign listeners
91        disclistModel = new DisclistListModel(this.disclist, this);
92        discList = new JList(disclistModel);
93        discList.putClientProperty(Resources.EDITOR_COMPONENT, this);
94        discList.addKeyListener(disclistModel.getKeyTypedListener());
95  
96        // add right click menu to the disclist
97        final JPopupMenu popup = MainMenuBuilder.buildDisclistPopupMenu(this, discList);
98        MouseListener popupListener = new ListPopupListener(popup);
99        discList.addMouseListener(popupListener);
100       discList.add(popup);
101 
102       // build the panel
103       setToolBar(buildToolBar());
104       setContent(buildContent());
105       setSelected(true);
106    }
107 
108    /**
109     * Clears out selected items.
110     */
111    public void clearSelection() {
112       // clear the selection
113       discList.clearSelection();
114       if (disclist.size() > 0) {
115          discList.setSelectedIndex(0);
116       }
117    }
118 
119    /**
120     * Load a disclist from disk.
121     */
122    public void load() {
123       LOG.debug("Load disclist");
124       final JFileChooser chooser = new JFileChooser();
125       chooser.setDialogTitle(Resources.getString("label.LoadDisclist"));
126       chooser.setAcceptAllFileFilterUsed(false);
127       chooser.setFileFilter(FilterFactory.disclistFileFilter());
128       chooser.setMultiSelectionEnabled(false);
129       chooser.setFileHidingEnabled(true);
130       final int returnVal = chooser.showOpenDialog(Application.getDefaultParentFrame());
131       if (returnVal != JFileChooser.APPROVE_OPTION) {
132          return;
133       }
134 
135       final MainFrame mainFrame = (MainFrame) Application.getDefaultParentFrame();
136 
137       final File file = chooser.getSelectedFile();
138       if (LOG.isDebugEnabled()) {
139          LOG.debug("Absolute: " + file.getAbsolutePath());
140       }
141 
142       // now try and import the disclist
143       try {
144          GuiUtil.setBusyCursor(mainFrame, true);
145          final LoadDisclistTask task = new LoadDisclistTask(file, this.disclist);
146          // AZ: Put the Title of Progress Monitor Dialog Box and Cancel button
147          UIManager.put("ProgressMonitor.progressText", Resources.getString("label.ProgressTitle"));
148          UIManager.put("OptionPane.cancelButtonText", Resources.getString("label.Cancel"));
149 
150          final ProgressMonitor progressMonitor = new ProgressMonitor(Application.getDefaultParentFrame(), Resources
151                   .getString("messages.loaddiscs"), "", 0, task.getLengthOfTask());
152          progressMonitor.setProgress(0);
153          progressMonitor.setMillisToDecideToPopup(10);
154          task.go();
155          final Timer timer = new Timer(50, null);
156          timer.addActionListener(new TimerListener(progressMonitor, task, timer));
157          timer.start();
158 
159       } catch (IOException ex) {
160          final String errorMessage = ResourceUtils.getString("messages.ErrorLoadingFile") + ": \n\n" + ex.getMessage();
161          LOG.error(errorMessage, ex);
162          MessageUtil.showError(this, errorMessage); // AZ
163       } catch (SAXParseException spe) {
164          final String err = spe.toString() + "\nLine number: " + spe.getLineNumber() + "\nColumn number: "
165                   + spe.getColumnNumber() + "\nPublic ID: " + spe.getPublicId() + "\nSystem ID: " + spe.getSystemId();
166          LOG.error(err, spe);
167          MessageUtil.showError(this, err); // AZ
168       } catch (Exception ex) {
169          final String errorMessage = ResourceUtils.getString("messages.ErrorLoadingFile");
170          LOG.error(errorMessage, ex);
171          MessageUtil.showError(this, errorMessage); // AZ
172       } finally {
173          GuiUtil.setBusyCursor(mainFrame, false);
174       }
175    }
176 
177    /**
178     * Moves items down on the list.
179     */
180    public void moveDown() {
181       LOG.debug("Moving on down");
182       int[] selected = discList.getSelectedIndices();
183       if (selected.length <= 0) {
184          MessageUtil.showInformation(Application.getDefaultParentFrame(), ResourceUtils
185                   .getString("messages.SelectSomethingToMove"));
186       } else {
187          int[] newSelections = discList.getSelectedIndices();
188          for (int i = selected.length - 1; i >= 0; i--) {
189             int index = selected[i];
190             if (index == (this.disclist.size() - 1)) {
191                break;
192             }
193             this.disclist.moveDown(index);
194             newSelections[i] = (index + 1);
195 
196          }
197          discList.setSelectedIndices(newSelections);
198       }
199    }
200 
201    /**
202     * Moves items up on the list.
203     */
204    public void moveUp() {
205       LOG.debug("Moving on up");
206       int[] selected = discList.getSelectedIndices();
207       if (selected.length <= 0) {
208          MessageUtil.showInformation(Application.getDefaultParentFrame(), ResourceUtils
209                   .getString("messages.SelectSomethingToMove"));
210       } else {
211          int[] newSelections = discList.getSelectedIndices();
212          for (int i = 0; i < selected.length; i++) {
213             int index = selected[i];
214             if (index == 0) {
215                break;
216             }
217             this.disclist.moveUp(index);
218             newSelections[i] = (index - 1);
219          }
220          discList.setSelectedIndices(newSelections);
221       }
222    }
223 
224    /*
225     * If the disclist changes, update the frame
226     */
227    public void propertyChange(PropertyChangeEvent aEvt) {
228       // update current disc
229       final Disc currentdisc = this.disclist.getCurrentDisc();
230       if (currentdisc != null) {
231          albumImage.setDisc(currentdisc);
232          if (MainModule.SETTINGS.isCopyImagesToDirectory()) {
233             final String imageName = ImageFactory.standardImageFileName(currentdisc.getArtist().getName(), currentdisc
234                      .getName(), currentdisc.getYear());
235             albumImage.setImage(ImageFactory.getScaledImage(imageName, 150, 150).getImage());
236          } else {
237             if (StringUtils.isNotBlank(currentdisc.getCoverUrl())) {
238                albumImage.setImage(ImageFactory.getScaledImage(currentdisc.getCoverUrl(), 150, 150).getImage());
239             } else {
240                albumImage.setImage(null);
241             }
242          }
243          artist.setText(currentdisc.getArtist().getName());
244          disc.setText(currentdisc.getName());
245          year.setText(currentdisc.getYear());
246          bitrate.setText(currentdisc.getBitrate().toString() + " kbps");
247       }
248    }
249 
250    /**
251     * Removes disc from the disclist
252     */
253    public void removeDisc() {
254       LOG.debug("Remove disc");
255       int[] selected = discList.getSelectedIndices();
256       if (selected.length <= 0) {
257          MessageUtil.showInformation(Application.getDefaultParentFrame(), ResourceUtils
258                   .getString("messages.SelectSomethingToRemove"));
259       } else {
260          for (int i = selected.length - 1; i >= 0; i--) {
261             int index = selected[i];
262             this.disclist.remove(index);
263          }
264          this.clearSelection();
265       }
266    }
267 
268    /**
269     * Clears the disclist.
270     */
271    public void removeAllDiscs() {
272       LOG.debug("Remove ALL discs from disclist");
273       for (int i = disclist.size() - 1; i >= 0; i--) {
274          this.disclist.remove(i);
275       }
276       this.clearSelection();
277    }
278 
279    /**
280     * Saves the current disclist.
281     */
282    public void save() {
283       LOG.debug("Save disclist");
284       final JFileChooser chooser = new JFileChooser();
285       chooser.setDialogTitle(ResourceUtils.getString("label.SaveDisclist"));
286       chooser.setAcceptAllFileFilterUsed(false);
287       FileFilter lst = FilterFactory.disclistFileFilter();
288       chooser.addChoosableFileFilter(lst);
289       chooser.setFileFilter(lst);
290 
291       chooser.setMultiSelectionEnabled(false);
292       chooser.setFileHidingEnabled(true);
293       final int returnVal = chooser.showSaveDialog(Application.getDefaultParentFrame());
294       if (returnVal != JFileChooser.APPROVE_OPTION) {
295          return;
296       }
297       File file = chooser.getSelectedFile();
298       if (LOG.isDebugEnabled()) {
299          LOG.debug("Absolute: " + file.getAbsolutePath());
300       }
301 
302       // add the extension if missing
303       file = FilterFactory.forceLstExtension(file);
304 
305       try {
306          this.disclist.save(file);
307 
308          MessageUtil.showInformation(Application.getDefaultParentFrame(), ResourceUtils
309                   .getString("messages.DisclistSavedSuccessfully"));
310       } catch (IOException ex) {
311          final String errorMessage = ResourceUtils.getString("messages.ErrorWritingFile") + "\n\n" + ex.getMessage();
312          LOG.error(errorMessage, ex);
313          MessageUtil.showError(this, errorMessage); // AZ
314       } catch (Exception ex) {
315          final String errorMessage = ResourceUtils.getString("messages.ErrorWritingFile");
316          LOG.error(errorMessage, ex);
317          MessageUtil.showError(this, errorMessage); // AZ
318       }
319    }
320 
321    /**
322     * Builds and answers the content pane.
323     */
324    private JComponent buildContent() {
325 
326       JScrollPane scrollPane = UIFactory.createStrippedScrollPane(buildDisclist());
327       scrollPane.setMinimumSize(new Dimension(300, 100));
328       scrollPane.setPreferredSize(new Dimension(300, 100));
329       return scrollPane;
330    }
331 
332    private JComponent buildDisclist() {
333       discList.setFocusable(true);
334       discList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
335       discList.setSelectedIndex(0);
336       discList.setVisibleRowCount(13);
337       discList.setCellRenderer(new DisclistCellRenderer());
338       disclistScrollPane = new JScrollPane(discList);
339 
340       FormLayout layout = new FormLayout("left:275px, 4dlu, right:pref:grow", "p");
341 
342       layout.setRowGroups(new int[][] { { 1 } });
343       PanelBuilder builder = new PanelBuilder(layout);
344       CellConstraints cc = new CellConstraints();
345 
346       builder.add(disclistScrollPane, cc.xy(1, 1, "left,top"));
347       builder.add(buildDiscPanel(), cc.xy(3, 1, "left,top"));
348       return builder.getPanel();
349    }
350 
351    /**
352     * Builds and answers the toolbar.
353     */
354    private JToolBar buildToolBar() {
355       final ToolBarBuilder bar = new ToolBarBuilder("Disclist");
356       AbstractButton button = null;
357       button = ComponentFactory.createToolBarButton(Actions.DISCLIST_LOAD_ID);
358       button.putClientProperty(Resources.EDITOR_COMPONENT, this);
359       bar.add(button);
360       button = ComponentFactory.createToolBarButton(Actions.DISCLIST_SAVE_ID);
361       button.putClientProperty(Resources.EDITOR_COMPONENT, this);
362       bar.add(button);
363       button = ComponentFactory.createToolBarButton(Actions.DISCLIST_MOVEUP_ID);
364       button.putClientProperty(Resources.EDITOR_COMPONENT, this);
365       bar.add(button);
366       button = ComponentFactory.createToolBarButton(Actions.DISCLIST_MOVEDOWN_ID);
367       button.putClientProperty(Resources.EDITOR_COMPONENT, this);
368       bar.add(button);
369       button = ComponentFactory.createToolBarButton(Actions.DISCLIST_REMOVE_DISC_ID);
370       button.putClientProperty(Resources.EDITOR_COMPONENT, this);
371       bar.add(button);
372       button = ComponentFactory.createToolBarButton(Actions.DISCLIST_CLEAR_ID);
373       button.putClientProperty(Resources.EDITOR_COMPONENT, this);
374       bar.add(button);
375       button = ComponentFactory.createToolBarButton(Actions.DISCLIST_GOTO_ID);
376       button.putClientProperty(Resources.EDITOR_COMPONENT, discList);
377       bar.add(button);
378       button = ComponentFactory.createToolBarButton(Actions.DISCLIST_CLOSE_ID);
379       bar.add(button);
380       return bar.getToolBar();
381    }
382 
383    /**
384     * Builds the Disc editor panel.
385     * <p>
386     * @return the panel to edit disc info.
387     */
388    private JComponent buildDiscPanel() {
389       FormLayout layout = new FormLayout("pref, left:min(80dlu;pref):grow, 40dlu, pref, right:pref",
390                "4px, p, 4px, p, 4px, p, 4px, p, 4px, p, p, 75px");
391       PanelBuilder builder = new PanelBuilder(layout);
392       CellConstraints cc = new CellConstraints();
393 
394       final MainFrame mainFrame = (MainFrame) Application.getDefaultParentFrame();
395       artist = UIFactory.createBoldLabel("");
396       disc = UIFactory.createBoldLabel("");
397       year = UIFactory.createBoldLabel("");
398       bitrate = UIFactory.createBoldLabel("");
399       albumImage = new AlbumImage(new Dimension(170, 170));
400       ActionListener actionListener = new ActionListener() {
401          public void actionPerformed(ActionEvent event) {
402             AlbumImage preview = (AlbumImage) event.getSource();
403             if (preview.getDisc() != null) {
404                GuiUtil.setBusyCursor(mainFrame, true);
405                mainFrame.getMainModule().selectNodeInTree(preview.getDisc());
406                GuiUtil.setBusyCursor(mainFrame, false);
407             }
408          }
409       };
410       albumImage.addActionListener(actionListener);
411 
412       builder.addLabel(ResourceUtils.getString("label.artist") + ": ", cc.xy(1, 2));
413       builder.add(artist, cc.xyw(2, 2, 3));
414       builder.add(albumImage, cc.xywh(5, 2, 1, 11));
415       builder.addLabel(ResourceUtils.getString("label.disc") + ": ", cc.xy(1, 4));
416       builder.add(disc, cc.xyw(2, 4, 3));
417       builder.addLabel(ResourceUtils.getString("label.year") + ": ", cc.xy(1, 6));
418       builder.add(year, cc.xyw(2, 6, 3));
419       builder.addLabel(ResourceUtils.getString("label.bitrate") + ": ", cc.xy(1, 10));
420       builder.add(bitrate, cc.xyw(2, 10, 3));
421       // builder.add(mainFrame.getAnalyzer(), cc.xywh(1, 11, 4, 2));
422       final JComponent panel = builder.getPanel();
423       panel.setBorder(new TitledBorder(ResourceUtils.getString("label.currentdisc")));
424       return panel;
425    }
426 
427    // shows popups on right click of List nodes
428    private static class ListPopupListener extends MouseAdapter {
429 
430       final JPopupMenu popup;
431 
432       public ListPopupListener(JPopupMenu popup) {
433          this.popup = popup;
434       }
435 
436       @Override
437       public void mousePressed(MouseEvent evt) {
438          maybeShowPopup(evt);
439 
440          /**
441           * // left mouse button pressed twice, change current disc in disclist
442           * // middle mouse button pressed, change current disc in disclist if
443           * ((((evt.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) &&
444           * (evt.getClickCount() == 2)) || ((evt.getModifiers() &
445           * MouseEvent.BUTTON2_MASK) != 0)) { //dummy for double-click }
446           **/
447 
448          JComponent source = (JComponent) evt.getSource();
449          final ActionEvent event = new ActionEvent(source, 1, Actions.DISCLIST_SET_CURRENT_ID);
450          source.putClientProperty(Resources.EDITOR_COMPONENT, source);
451          ActionManager.get(Actions.DISCLIST_SET_CURRENT_ID).actionPerformed(event);
452       }
453 
454       @Override
455       public void mouseReleased(MouseEvent e) {
456          maybeShowPopup(e);
457       }
458 
459       private void maybeShowPopup(MouseEvent e) {
460          if (e.isPopupTrigger()) {
461             ActionManager.get(Actions.TRACK_PLAY_IMMEDIATE_ID).setEnabled(true);
462 
463             // popup the menu
464             popup.show(e.getComponent(), e.getX(), e.getY());
465          }
466       }
467 
468    }
469 
470 }