/* * The GPLv3 licence : * ----------------- * Copyright (c) 2009 Ricardo Dias * * This file is part of MuVis. * * MuVis is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MuVis is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MuVis. If not, see <http://www.gnu.org/licenses/>. */ package muvis.view; import com.vlsolutions.swing.docking.DockKey; import com.vlsolutions.swing.docking.Dockable; import com.vlsolutions.swing.docking.DockingConstants; import javazoom.jlgui.basicplayer.BasicPlayerException; import muvis.Environment; import muvis.audio.AudioMetadata; import muvis.audio.MuVisAudioPlayer; import muvis.audio.playlist.Playlist; import muvis.util.JImagePanel; import muvis.util.Observable; import muvis.util.Observer; import muvis.util.Util; import muvis.view.controllers.*; import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Hashtable; import java.util.logging.Level; import java.util.logging.Logger; /** * This class implements the ControllerView for the musicplayer, handling the * interface functions and methods. * @author Ricardo */ public class MusicControllerView extends MusicControllerViewUI implements Dockable, ActionListener, ChangeListener, Observer { /** * @return the playingType */ public PlayingType getPlayingType() { return playingType; } public void playNextTrack() { getMusicPlayerActiveController().playNextTrack(); } public void playPreviousTrack() { getMusicPlayerActiveController().playPreviousTrack(); } public void stopPlayer() throws IOException { getMusicPlayerActiveController().stopTrack(); BufferedImage image = ImageIO.read(getClass().getResource("/images/not_available.jpg")); displayInfoPanel("Artist & album - not available", "Track name - not available", "Year - not available", image); } public void playTrack() { if (getMusicPlayerActiveController().isPlaying()) { getMusicPlayerActiveController().pauseTrack(); } else { getMusicPlayerActiveController().playTrack(); } } public void setPlayingType(PlayingType playingType) { if (PlayingType.FILTER_MODE.equals(playingType)){ filteredTracksRadioButton.doClick(); } else if (PlayingType.PLAYLIST_MODE.equals(playingType)) { playlistRadioButton.doClick(); } else if (PlayingType.GENERAL_MODE.equals(playingType)){ allTracksRadioButton.doClick(); } else if (PlayingType.INDIVIDUAL_TRACK.equals(playingType)){ try{ activeController.stopTrack(); } catch (Exception ex){} setMusicPlayerActiveController(individualTrackModeController); this.playingType = PlayingType.INDIVIDUAL_TRACK; } } public enum PlayingType { PLAYLIST_MODE, FILTER_MODE, GENERAL_MODE, INDIVIDUAL_TRACK } //dockable key private DockKey key; //Controller for the various playing modes available private MusicPlayerControllerInterface playlistModeController; private MusicPlayerControllerInterface filteredTracksModeController; private MusicPlayerControllerInterface allTracksModeController; private MusicPlayerControllerInterface individualTrackModeController; //The active controller for this player private MusicPlayerControllerInterface activeController; //Parent JFrame //Timer for updating the musicTimelineSlider private Timer musicTimelineTimer; private int timelineSliderValue = 0; private PlayingType playingType; public MusicControllerView(JFrame parent) { //initializing fields this.playlistModeController = new MusicPlayerPlaylistController(); this.filteredTracksModeController = new MusicPlayerFilterController(); this.allTracksModeController = new MusicPlayerGeneralController(); this.individualTrackModeController = new MusicPlayerIndividualTrackController(); this.activeController = playlistModeController; activeController.setEnable(true); playingType = PlayingType.PLAYLIST_MODE; filteredTracksRadioButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try{ activeController.stopTrack(); } catch (Exception ex){} setMusicPlayerActiveController(filteredTracksModeController); playingType = PlayingType.FILTER_MODE; } }); playlistRadioButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try{ activeController.stopTrack(); } catch (Exception ex){} setMusicPlayerActiveController(playlistModeController); playingType = PlayingType.PLAYLIST_MODE; } }); allTracksRadioButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try{ activeController.stopTrack(); } catch (Exception ex){} setMusicPlayerActiveController(allTracksModeController); playingType = PlayingType.GENERAL_MODE; } }); albumCoverPanel.addMouseListener( new MouseListener() { JFrame albumCoverPreview; @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2){ BufferedImage image = ((JImagePanel)e.getSource()).getImage(); if (albumCoverPreview == null || !albumCoverPreview.isVisible()){ albumCoverPreview = new JFrame("Album Cover"); JImagePanel albumPreviewPanel = new JImagePanel(image, 0, 0,image.getWidth(), image.getHeight()); albumCoverPreview.add(albumPreviewPanel); albumCoverPreview.setSize( new Dimension(image.getWidth(), image.getHeight())); albumCoverPreview.setVisible(true); } } } @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {} }); //register objects and listeners Environment.getEnvironmentInstance().getAudioPlayer().registerObserver(this); Environment.getEnvironmentInstance().getAudioPlaylist().registerObserver(this); playTrackButton.addActionListener(this); previousTrackButton.addActionListener(this); nextTrackButton.addActionListener(this); stopPlayerButton.addActionListener(this); volumeSlider.addChangeListener(this); musicTimelineSlider.setPaintTicks(true); musicTimelineSlider.addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { try { timelineSliderValue = musicTimelineSlider.getValue(); Environment.getEnvironmentInstance().getAudioPlayer().seek(timelineSliderValue); musicTimelineTimer.restart(); } catch (BasicPlayerException ex) { ex.printStackTrace(); } } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } }); //setting the volume volumeSlider.setValue((int) Environment.getEnvironmentInstance().getAudioPlayer().getVolume()); //Setting the properties for the timelineslider timer int delay = 1000; //milliseconds ActionListener taskPerformer = new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { int value = musicTimelineSlider.getValue(); if (value == 0) { value = timelineSliderValue; } musicTimelineSlider.setValue(value + 1); } }; musicTimelineTimer = new Timer(delay, taskPerformer); //initializing the dockable properties key = new DockKey("Music Player"); key.setTooltip("Music Player Controls and playing information"); key.setCloseEnabled(false); key.setMaximizeEnabled(false); key.setAutoHideBorder(DockingConstants.HIDE_BOTTOM); key.setFloatEnabled(true); key.setAutoHideEnabled(true); playlistRadioButton.setSelected(true); } @Override public DockKey getDockKey() { return key; } @Override public Component getComponent() { return this; } /** * Triggers an action in the objects registered in this handler * @param event */ @Override public void actionPerformed(ActionEvent event) { if (event.getSource() == playTrackButton) { playTrack(); } else if (event.getSource() == nextTrackButton) { playNextTrack(); } else if (event.getSource() == previousTrackButton) { playPreviousTrack(); } else if (event.getSource() == stopPlayerButton) { try{ stopPlayer(); } catch (Exception e){} } } /** * Generic method for displaying information in the info panel * @param artistAlbum * @param trackName * @param trackYear */ private void displayInfoPanel(String artistAlbum, String trackName, String trackYear, BufferedImage artwork) { artistAlbumInfoLabel.setText(artistAlbum); trackNameLabel.setText(trackName); trackyearLabel.setText(trackYear); ((JImagePanel)albumCoverPanel).setImage(artwork); } /*updates the info panel with the track being played - uses the controller * to get the information */ private void updateInfoPanel() { AudioMetadata metadata = getMusicPlayerActiveController().getTrackPlayingMetadata(); displayInfoPanel(metadata.getAuthor() + "-" + metadata.getAlbum(), metadata.getTitle(), metadata.getYear(), metadata.getArtwork()); } //updates the timelinesliderparameters private void updateTimelineParameters() { AudioMetadata metadata = getMusicPlayerActiveController().getTrackPlayingMetadata(); int length = (int) metadata.getDuration(); musicTimelineSlider.setMinimum(0); musicTimelineSlider.setMaximum(length); //Create the label table Hashtable labelTable = new Hashtable(); labelTable.put(new Integer(0), new JLabel("0")); labelTable.put(new Integer(length), new JLabel(Util.secondsToTimeDisplay(length))); musicTimelineSlider.setLabelTable(labelTable); key.setName("Music Player - Playing: " + metadata.getTitle() + " from " + metadata.getAuthor()); } /** * Handling changes in some elements * @param e */ @Override public void stateChanged(ChangeEvent e) { if (e.getSource() == volumeSlider) { try { //setting the volume to a new value getMusicPlayerActiveController().setPlayerVolume(volumeSlider.getValue()); } catch (BasicPlayerException ex) { ex.printStackTrace(); } } } /** * This method is the implementation of the observer pattern, for handling some * changes in the underlying model * @param obs */ @Override public void update(Observable obs, Object arg) { MuVisAudioPlayer player = Environment.getEnvironmentInstance().getAudioPlayer(); if (obs instanceof MuVisAudioPlayer) { if (MuVisAudioPlayer.Event.RESUMED.equals(arg) && player.isPlaying()) { //start the timer musicTimelineTimer.start(); playTrackButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/music/media-playback-pause.png"))); // NOI18N } else if (MuVisAudioPlayer.Event.NEW_TRACK_PLAYING.equals(arg)) { //start the time but... musicTimelineTimer.start(); //set the timelineslider because a new song is playing updateTimelineParameters(); updateInfoPanel(); musicTimelineSlider.setValue(0); playTrackButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/music/media-playback-pause.png"))); // NOI18N key.setNotification(true); } else if (MuVisAudioPlayer.Event.STOPPED.equals(arg)) { //stop the timer because the player is either stop or paused musicTimelineTimer.stop(); musicTimelineSlider.setValue(0); playTrackButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/music/media-playback-start.png"))); // NOI18N try { displayInfoPanel("Artist & album - not available", "Track name - not available", "Year - not available", ImageIO.read(getClass().getResource("/images/not_available.jpg"))); } catch (IOException ex) { Logger.getLogger(MusicControllerView.class.getName()).log(Level.SEVERE, null, ex); } key.setName("Music Player"); } else if (MuVisAudioPlayer.Event.PAUSED.equals(arg)) { musicTimelineTimer.stop(); playTrackButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/music/media-playback-start.png"))); // NOI18N } else if (MuVisAudioPlayer.Event.VOLUME_CHANGED.equals(arg)) { //volumeSlider.setValue((int) player.getVolume()); //this must be mapped to the interface space } } else if (obs instanceof Playlist) { if (Playlist.Event.NEW_CURSOR.equals(arg)) { //a new cursor is available - a new item is going to be played perhaps //set the vars for accomplishing this updateInfoPanel(); updateTimelineParameters(); } } } public void setMusicPlayerFilterController(MusicPlayerControllerInterface filterController){ filteredTracksModeController = filterController; } public MusicPlayerControllerInterface getMusicPlayerFilterController(){ return filteredTracksModeController; } public void setMusicPlayerGeneralController(MusicPlayerControllerInterface generalController){ allTracksModeController = generalController; } public MusicPlayerControllerInterface getMusicPlayerGeneralController(){ return allTracksModeController; } public void setMusicPlayerPlaylistController(MusicPlayerControllerInterface playlistModeController) { this.playlistModeController = playlistModeController; } public MusicPlayerControllerInterface getMusicPlayerPlaylistController() { return playlistModeController; } public MusicPlayerControllerInterface getMusicPlayerIndividualController() { return individualTrackModeController; } public void setMusicPlayerIndividualController(MusicPlayerControllerInterface individualController) { this.individualTrackModeController = individualController; } /** * @return the activeController */ public MusicPlayerControllerInterface getMusicPlayerActiveController() { return activeController; } /** * @param activeController the activeController to set */ public void setMusicPlayerActiveController(MusicPlayerControllerInterface activeController) { this.activeController.setEnable(false); //disable the previous controller this.activeController = activeController; this.activeController.setEnable(true); } }