diff --git a/src/main/java/musicplayer/SwingUIModule.java b/src/main/java/musicplayer/SwingUIModule.java index 205854c..915f1ad 100644 --- a/src/main/java/musicplayer/SwingUIModule.java +++ b/src/main/java/musicplayer/SwingUIModule.java @@ -12,7 +12,7 @@ import musicplayer.player.GStreamerPlayer; import musicplayer.player.IPlayer; import musicplayer.player.VLCPlayer; import musicplayer.playlist.IPlaylist; -import musicplayer.playlist.JTablePlaylist; +import musicplayer.playlist.TabbedJTablePlaylist; import musicplayer.swingui.PlayerGUI; import musicplayer.util.ConfigManager; @@ -24,7 +24,7 @@ class SwingUIModule extends AbstractModule { @Override protected void configure() { bind(IDatabase.class).to(HibernateDatabase.class).in(Singleton.class); - bind(IPlaylist.class).to(JTablePlaylist.class).in(Singleton.class); + bind(IPlaylist.class).to(TabbedJTablePlaylist.class).in(Singleton.class); bind(ILibrary.class).to(JTreeLibrary.class).in(Singleton.class); bind(PlayerCallbackInterface.class).to(PlayerGUI.class); } diff --git a/src/main/java/musicplayer/playlist/TabbedJTablePlaylist.java b/src/main/java/musicplayer/playlist/TabbedJTablePlaylist.java new file mode 100644 index 0000000..65fe67b --- /dev/null +++ b/src/main/java/musicplayer/playlist/TabbedJTablePlaylist.java @@ -0,0 +1,229 @@ +package musicplayer.playlist; + +import musicplayer.model.Song; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * UI element containing tabbed instances of JTablePlaylist. + */ +public class TabbedJTablePlaylist extends JTabbedPane implements IPlaylist { + + private List playlists = new ArrayList<>(); + + /** + * UI element containing tabbed instances of JTablePlaylist. + */ + public TabbedJTablePlaylist(){ + JPanel newTabCreationComponent = new JPanel(new BorderLayout()); + newTabCreationComponent.setOpaque(false); + JButton addButton = new JButton("+"); + addButton.setBorderPainted(false); + addButton.setFocusPainted(false); + addButton.setContentAreaFilled(false); + newTabCreationComponent.add(addButton); + addTab("+", null); + setTabComponentAt(0, newTabCreationComponent); + addButton.addActionListener(e -> addPlaylistTab()); + addPlaylistTab(); + } + + /** + * @return The playlist in the currently active tab. + */ + private Optional getActivePlaylist(){ + //Pane components should only be JTablePlaylist or null + //noinspection SuspiciousMethodCalls + int playlistIndex = playlists.indexOf(getSelectedComponent()); + if(playlistIndex != -1){ + return Optional.of(playlists.get(playlistIndex)); + } + return Optional.empty(); + } + + /** + * Create a new JTablePlaylist in a new tab. + */ + private void addPlaylistTab(){ + JTablePlaylist playlist = new JTablePlaylist(); + playlists.add(playlist); + int newIndex = getTabCount() - 1; + insertTab("", null, playlist, null, newIndex); + setTabComponentAt(newIndex, new PlaylistTabComponent(this, "Playlist")); + setSelectedIndex(newIndex); + } + + /** + * Remove a playlist tab. + * @param i Index of tab to remove. + */ + public void removePlaylistTab(int i){ + if(i != -1 && getComponentAt(i) != null) { + JTablePlaylist tabbedPane = (JTablePlaylist) getComponentAt(i); + playlists.remove(tabbedPane); + remove(i); + } + if(playlists.isEmpty()){ + addPlaylistTab(); + } + } + + /** + * Add a song to the currently active playlist. + * @param song Song to add. + */ + @Override + public void addSong(Song song) { + getActivePlaylist().ifPresent(x -> x.addSong(song)); + } + + /** + * @return The first song in the currently active playlist. + */ + @Override + public Optional getFirst() { + return getActivePlaylist().flatMap(JTablePlaylist::getFirst); + } + + /** + * Get the next song in the playlist, relative to a given song. + * @param currentSong The song in the playlist to get the "next" song from. + * @return Next song. + */ + @Override + public Optional getNext(Song currentSong) { + return getActivePlaylist().flatMap(x -> x.getNext(currentSong)); + } + + /** + * Get the previous song in the playlist, relative to a given song. + * @param currentSong The song in the playlist to get the "previous" song from. + * @return Previous song. + */ + @Override + public Optional getPrevious(Song currentSong) { + return getActivePlaylist().flatMap(x -> x.getPrevious(currentSong)); + } + + /** + * Get a song from a playlist based on index. + * @param index Index of the song to get. + * @return Song at index. + */ + @Override + public Optional get(int index) { + return getActivePlaylist().flatMap(x -> x.get(index)); + } + + /** + * @return The currently active (i.e. playing) song in the playlist. + */ + @Override + public Optional getActive() { + return getActivePlaylist().flatMap(JTablePlaylist::getActive); + } + + /** + * @return List of songs in the current playlist. + */ + @Override + public List getSongList() { + return getActivePlaylist().map(JTablePlaylist::getSongList).orElse(new ArrayList<>()); + } + + /** + * Get the index of a given song in a playlist. + * @param song Song to get the index of. + * @return Index of song. + */ + @Override + public int getIndex(Song song) { + return getActivePlaylist().map(x -> x.getIndex(song)).orElse(-1); + } + + /** + * Delete a song from the active playlist. + * @param song Song to delete. + */ + @Override + public void delete(Song song) { + getActivePlaylist().ifPresent(x -> x.delete(song)); + } + + /** + * Delete a song from the active playlist. + * @param index Index of song to delete. + */ + @Override + public void delete(int index) { + getActivePlaylist().ifPresent(x -> x.delete(index)); + } + + /** + * Delete a number of songs from the playlist. + * @param index List of indexes of songs to be removed. + */ + @Override + public void delete(int[] index) { + getActivePlaylist().ifPresent(x -> x.delete(index)); + } + + /** + * Delete all songs from the active playlist. + */ + @Override + public void deleteAll() { + getActivePlaylist().ifPresent(JTablePlaylist::deleteAll); + } + + /** + * @return True if the active playlist is currently empty. + */ + @Override + public boolean isEmpty() { + return getActivePlaylist().map(JTablePlaylist::isEmpty).orElse(true); + } + + /** + * Set a song as the currently active song (i.e. currently playing) + * @param song Song currently playing. + */ + @Override + public void setPlayingSong(Song song) { + playlists.parallelStream().forEach(x -> x.setPlayingSong(song)); + } + + /** + * Set the playlist to show the state when playback has stopped. + */ + @Override + public void setStopped() { + playlists.parallelStream().forEach(JTablePlaylist::setStopped); + } + + /** + * Component used in the actual top of the tab to show playlist name and allow closing. + */ + private class PlaylistTabComponent extends JPanel{ + private final TabbedJTablePlaylist pane; + + public PlaylistTabComponent(final TabbedJTablePlaylist pane, final String tabName){ + super(new FlowLayout(FlowLayout.LEFT, 0, 0)); + this.pane = pane; + + JLabel tabLabel = new JLabel(tabName); + tabLabel.setOpaque(false); + add(tabLabel); + tabLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); + JButton closeButton = new JButton("x"); + closeButton.addActionListener(e -> pane.removePlaylistTab(pane.indexOfTabComponent(this))); + closeButton.setFocusPainted(false); + closeButton.setContentAreaFilled(false); + add(closeButton); + } + } +} diff --git a/src/main/java/musicplayer/swingui/PlayerGUI.java b/src/main/java/musicplayer/swingui/PlayerGUI.java index 470dc10..73dbd7c 100644 --- a/src/main/java/musicplayer/swingui/PlayerGUI.java +++ b/src/main/java/musicplayer/swingui/PlayerGUI.java @@ -123,7 +123,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface { this.setLayout(new BorderLayout(0, 0)); final JSplitPane libraryAndPlaylistPane = new JSplitPane(); libraryAndPlaylistPane.setDividerLocation(240); - libraryAndPlaylistPane.setRightComponent((JScrollPane) playlist); + libraryAndPlaylistPane.setRightComponent((Component) playlist); this.add(libraryAndPlaylistPane, BorderLayout.CENTER); libraryAndPlaylistPane.setLeftComponent(((JTreeLibrary)library).getLibraryPanel()); final JPanel controlPane = new JPanel();