package com.limegroup.gnutella.gui.playlist; import java.io.File; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import com.limegroup.gnutella.gui.mp3.PlayList; import com.limegroup.gnutella.gui.tables.BasicDataLineModel; import com.limegroup.gnutella.gui.tables.DataLine; /** * A model for playlists. Keeps of track of what song is next, * what has/hasn't been played during shuffling, etc... */ public final class PlaylistModel extends BasicDataLineModel { /** * Whether or not songs are shuffling. */ private boolean _shuffle = false; /** * Indicates that the next song to return is before * the current one. */ private boolean _nextIsBefore = false; /** * The currently playing song. */ private File _currentSong; /** * Songs already played -- used for shuffling. */ private List _songsNotPlayed; /** * Constructs a new playlist model. */ PlaylistModel() { super( PlaylistDataLine.class ); } /** * Quickly updates all instead of iterating & calling udpate on each one. * @return null */ public Object refresh() { fireTableRowsUpdated(0, getRowCount()); return null; } /** * Creates a new ConnectionDataLine */ public DataLine createDataLine() { return new PlaylistDataLine(); } /** * Override default so new ones get added to the end */ public int add(Object o) { return add(o, getRowCount()); } /** * If shuffling, adds to the list of songs not played. */ public int add(DataLine dl, int row) { if(_shuffle) { _songsNotPlayed.add(dl.getInitializeObject()); Collections.shuffle(_songsNotPlayed); } return super.add(dl, row); } /** * If shuffling, removes the song from the songs not played. */ public void remove(int i) { File f = (File)get(i).getInitializeObject(); super.remove(i); if(_shuffle) _songsNotPlayed.remove(f); } /** * If shuffling, clears the songs not played. */ public void clear() { super.clear(); if(_shuffle) _songsNotPlayed.clear(); } /** * Gets the next song to play. */ File getNextSong() { int rowCount = getRowCount(); if(rowCount == 0) return null; boolean prior = _nextIsBefore; _nextIsBefore = false; if(_shuffle) { //fill up songs not played if empty if(_songsNotPlayed.isEmpty()) { for(int i = 0; i < rowCount; i++) _songsNotPlayed.add(get(i).getInitializeObject()); Collections.shuffle(_songsNotPlayed); } _currentSong = (File)_songsNotPlayed.remove(0); } else { int idx = getRow(_currentSong); // if we haven't played anything, alway get the first one. if(idx == -1) idx = 0; else if(prior) idx = (idx - 1 + rowCount) % rowCount; else idx = (idx + 1 + rowCount) % rowCount; _currentSong = (File)get(idx).getInitializeObject(); } return _currentSong; } /** * Sets the currently playing song. */ void setCurrentSong(File f) { if(_shuffle) _songsNotPlayed.remove(f); _currentSong = f; } /** * Gets the index of the currently playing song. */ int getCurrentSongIndex() { return getRow(_currentSong); } /** * Returns the list of all songs. */ List getSongs() { List l = new LinkedList(); for(int i = 0; i < getRowCount(); i++) { DataLine dl = get(i); l.add(dl.getInitializeObject()); } return l; } /** * Notification that the next song we want to play is BEFORE the current * song. */ void setBackwardsMode() { _nextIsBefore = true; } /** * Adds all songs from the playlist. */ void addSongs(PlayList list) { unsort(); List songs = list.getSongs(); for(Iterator i = songs.iterator(); i.hasNext(); ) add(i.next()); } /** * Sets whether or not shuffle is active. */ void setShuffle(boolean shuffle) { if(shuffle) _songsNotPlayed = new LinkedList(); else _songsNotPlayed = null; _shuffle = shuffle; } }