/* This file is part of Clementine. Copyright 2010, David Sansome Clementine 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. Clementine 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 Clementine. If not, see . */ #ifndef PLAYLIST_H #define PLAYLIST_H #include #include #include #include "playlistitem.h" #include "playlistsequence.h" #include "core/song.h" #include "radio/radioitem.h" #include "smartplaylists/generator_fwd.h" class LibraryBackend; class PlaylistBackend; class PlaylistFilter; class Queue; class RadioService; class TaskManager; class QSortFilterProxyModel; class QUndoStack; namespace PlaylistUndoCommands { class InsertItems; class RemoveItems; class MoveItems; } class Playlist : public QAbstractListModel { Q_OBJECT friend class PlaylistUndoCommands::InsertItems; friend class PlaylistUndoCommands::RemoveItems; friend class PlaylistUndoCommands::MoveItems; public: Playlist(PlaylistBackend* backend, TaskManager* task_manager, LibraryBackend* library, int id, QObject* parent = 0); ~Playlist(); // Always add new columns to the end of this enum - the values are persisted enum Column { Column_Title = 0, Column_Artist, Column_Album, Column_AlbumArtist, Column_Composer, Column_Length, Column_Track, Column_Disc, Column_Year, Column_Genre, Column_BPM, Column_Bitrate, Column_Samplerate, Column_Filename, Column_BaseFilename, Column_Filesize, Column_Filetype, Column_DateCreated, Column_DateModified, Column_Rating, Column_PlayCount, Column_SkipCount, Column_LastPlayed, Column_Score, Column_Comment, ColumnCount }; enum Role { Role_IsCurrent = Qt::UserRole + 1, Role_IsPaused, Role_StopAfter, Role_QueuePosition, Role_CanSetRating, }; static const char* kRowsMimetype; static const char* kPlayNowMimetype; static bool CompareItems(int column, Qt::SortOrder order, PlaylistItemPtr a, PlaylistItemPtr b); static QString column_name(Column column); static bool column_is_editable(Playlist::Column column); static bool set_column_value(Song& song, Column column, const QVariant& value); // Persistence void Save() const; void Restore(); // Accessors QSortFilterProxyModel* proxy() const; Queue* queue() const { return queue_; } int id() const { return id_; } int current_index() const; int last_played_index() const; int next_index() const; int previous_index() const; bool stop_after_current() const; bool is_dynamic() const { return dynamic_playlist_; } const PlaylistItemPtr& item_at(int index) const { return items_[index]; } PlaylistItemPtr current_item() const { return current_item_; } PlaylistItem::Options current_item_options() const; Song current_item_metadata() const; PlaylistItemList library_items_by_id(int id) const; SongList GetAllSongs() const; quint64 GetTotalLength() const; // in seconds void set_sequence(PlaylistSequence* v); PlaylistSequence* sequence() const { return playlist_sequence_; } QUndoStack* undo_stack() const { return undo_stack_; } // Scrobbling int scrobble_point() const { return scrobble_point_; } bool has_scrobbled() const { return has_scrobbled_; } void set_scrobbled(bool v) { has_scrobbled_ = v; } // Changing the playlist QModelIndex InsertItems(const PlaylistItemList& items, int pos = -1); QModelIndex InsertLibraryItems(const SongList& items, int pos = -1); QModelIndex InsertSongs(const SongList& items, int pos = -1); QModelIndex InsertSongsOrLibraryItems(const SongList& items, int pos = -1); QModelIndex InsertRadioStations(const QList& items, int pos = -1, bool play_now = false); void InsertSmartPlaylist(smart_playlists::GeneratorPtr generator, int pos = -1, bool play_now = false); void InsertUrls(const QList& urls, bool play_now, int pos = -1); void StopAfter(int row); void ReloadItems(const QList& rows); // QAbstractListModel int rowCount(const QModelIndex& = QModelIndex()) const { return items_.count(); } int columnCount(const QModelIndex& = QModelIndex()) const { return ColumnCount; } QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; bool setData(const QModelIndex &index, const QVariant &value, int role); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; Qt::ItemFlags flags(const QModelIndex &index) const; QStringList mimeTypes() const; Qt::DropActions supportedDropActions() const; QMimeData* mimeData(const QModelIndexList& indexes) const; bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent); void sort(int column, Qt::SortOrder order); bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()); public slots: void set_current_index(int index); void Paused(); void Playing(); void Stopped(); void IgnoreSorting(bool value) { ignore_sorting_ = value; } void ClearStreamMetadata(); void SetStreamMetadata(const QUrl& url, const Song& song); void ItemChanged(PlaylistItemPtr item); void Clear(); void Shuffle(); void ShuffleModeChanged(PlaylistSequence::ShuffleMode mode); void RepopulateDynamicPlaylist(); void TurnOffDynamicPlaylist(); signals: void CurrentSongChanged(const Song& metadata); void EditingFinished(const QModelIndex& index); void PlayRequested(const QModelIndex& index); // Signals that the underlying list of items was changed, meaning that // something was added to it, removed from it or the ordering changed. void PlaylistChanged(); void DynamicModeChanged(bool dynamic); void LoadTracksError(const QString& message); private: void SetCurrentIsPaused(bool paused); void UpdateScrobblePoint(); void ReshuffleIndices(); int NextVirtualIndex(int i) const; int PreviousVirtualIndex(int i) const; bool FilterContainsVirtualIndex(int i) const; void TurnOnDynamicPlaylist(smart_playlists::GeneratorPtr gen); // Modify the playlist without changing the undo stack. These are used by // our friends in PlaylistUndoCommands QModelIndex InsertItemsWithoutUndo(const PlaylistItemList& items, int pos); PlaylistItemList RemoveItemsWithoutUndo(int pos, int count); void MoveItemsWithoutUndo(const QList& source_rows, int pos); void MoveItemsWithoutUndo(int start, const QList& dest_rows); void RemoveItemsNotInQueue(); private slots: void TracksAboutToBeDequeued(const QModelIndex&, int begin, int end); void TracksDequeued(); void TracksEnqueued(const QModelIndex&, int begin, int end); void QueueLayoutChanged(); void SongSaveComplete(); void ItemReloadComplete(); void ItemsLoaded(); private: bool is_loading_; PlaylistFilter* proxy_; Queue* queue_; QList temp_dequeue_change_indexes_; PlaylistBackend* backend_; TaskManager* task_manager_; LibraryBackend* library_; int id_; PlaylistItemList items_; QList virtual_items_; // Contains the indices into items_ in the order // that they will be played. // A map of library ID to playlist item - for fast lookups when library // items change. QMultiMap library_items_by_id_; QPersistentModelIndex current_item_index_; QPersistentModelIndex last_played_item_index_; QPersistentModelIndex stop_after_; bool current_is_paused_; int current_virtual_index_; PlaylistItemPtr current_item_; bool is_shuffled_; int scrobble_point_; bool has_scrobbled_; PlaylistSequence* playlist_sequence_; // Hack to stop QTreeView::setModel sorting the playlist bool ignore_sorting_; QUndoStack* undo_stack_; smart_playlists::GeneratorPtr dynamic_playlist_; }; QDataStream& operator <<(QDataStream&, const Playlist*); QDataStream& operator >>(QDataStream&, Playlist*&); #endif // PLAYLIST_H