1 /* This file is part of Clementine.
2    Copyright 2010, David Sansome <me@davidsansome.com>
3 
4    Clementine is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8 
9    Clementine is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with Clementine.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #ifndef PLAYLISTMANAGER_H
19 #define PLAYLISTMANAGER_H
20 
21 #include <QColor>
22 #include <QItemSelection>
23 #include <QMap>
24 #include <QObject>
25 #include <QSettings>
26 
27 #include "core/song.h"
28 #include "playlist.h"
29 #include "smartplaylists/generator_fwd.h"
30 
31 class Application;
32 class LibraryBackend;
33 class PlaylistBackend;
34 class PlaylistContainer;
35 class PlaylistParser;
36 class PlaylistSequence;
37 class TaskManager;
38 
39 class QModelIndex;
40 class QUrl;
41 
42 class PlaylistManagerInterface : public QObject {
43   Q_OBJECT
44 
45  public:
PlaylistManagerInterface(Application * app,QObject * parent)46   PlaylistManagerInterface(Application* app, QObject* parent)
47       : QObject(parent) {}
48 
49   virtual int current_id() const = 0;
50   virtual int active_id() const = 0;
51 
52   virtual Playlist* playlist(int id) const = 0;
53   virtual Playlist* current() const = 0;
54   virtual Playlist* active() const = 0;
55 
56   // Returns the collection of playlists managed by this PlaylistManager.
57   virtual QList<Playlist*> GetAllPlaylists() const = 0;
58   // Grays out and reloads all deleted songs in all playlists.
59   virtual void InvalidateDeletedSongs() = 0;
60   // Removes all deleted songs from all playlists.
61   virtual void RemoveDeletedSongs() = 0;
62 
63   virtual QItemSelection selection(int id) const = 0;
64   virtual QItemSelection current_selection() const = 0;
65   virtual QItemSelection active_selection() const = 0;
66 
67   virtual QString GetPlaylistName(int index) const = 0;
68 
69   virtual LibraryBackend* library_backend() const = 0;
70   virtual PlaylistBackend* playlist_backend() const = 0;
71   virtual PlaylistSequence* sequence() const = 0;
72   virtual PlaylistParser* parser() const = 0;
73   virtual PlaylistContainer* playlist_container() const = 0;
74 
75  public slots:
76   virtual void New(const QString& name, const SongList& songs = SongList(),
77                    const QString& special_type = QString()) = 0;
78   virtual void Load(const QString& filename) = 0;
79   virtual void Save(int id, const QString& filename,
80                     Playlist::Path path_type) = 0;
81   virtual void Rename(int id, const QString& new_name) = 0;
82   virtual void Delete(int id) = 0;
83   virtual bool Close(int id) = 0;
84   virtual void Open(int id) = 0;
85   virtual void ChangePlaylistOrder(const QList<int>& ids) = 0;
86 
87   virtual void Enque(int id, int index) = 0;
88 
89   virtual void SongChangeRequestProcessed(const QUrl& url, bool valid) = 0;
90 
91   virtual void SetCurrentPlaylist(int id) = 0;
92   virtual void SetActivePlaylist(int id) = 0;
93   virtual void SetActiveToCurrent() = 0;
94 
95   virtual void SelectionChanged(const QItemSelection& selection) = 0;
96 
97   // Convenience slots that defer to either current() or active()
98   virtual void ClearCurrent() = 0;
99   virtual void ShuffleCurrent() = 0;
100   virtual void RemoveDuplicatesCurrent() = 0;
101   virtual void RemoveUnavailableCurrent() = 0;
102   virtual void SetActivePlaying() = 0;
103   virtual void SetActivePaused() = 0;
104   virtual void SetActiveStopped() = 0;
105   virtual void SetActiveStreamMetadata(const QUrl& url, const Song& song) = 0;
106   // Rate current song using 0.0 - 1.0 scale.
107   virtual void RateCurrentSong(double rating) = 0;
108   // Rate current song using 0 - 5 scale.
109   virtual void RateCurrentSong(int rating) = 0;
110 
111   virtual void PlaySmartPlaylist(smart_playlists::GeneratorPtr generator,
112                                  bool as_new, bool clear) = 0;
113 
114 signals:
115   void PlaylistManagerInitialized();
116 
117   void PlaylistAdded(int id, const QString& name, bool favorite);
118   void PlaylistDeleted(int id);
119   void PlaylistClosed(int id);
120   void PlaylistRenamed(int id, const QString& new_name);
121   void PlaylistFavorited(int id, bool favorite);
122   void CurrentChanged(Playlist* new_playlist);
123   void ActiveChanged(Playlist* new_playlist);
124 
125   void Error(const QString& message);
126   void SummaryTextChanged(const QString& summary);
127 
128   // Forwarded from individual playlists
129   void CurrentSongChanged(const Song& song);
130 
131   // Signals that one of manager's playlists has changed (new items, new
132   // ordering etc.) - the argument shows which.
133   void PlaylistChanged(Playlist* playlist);
134   void EditingFinished(const QModelIndex& index);
135   void PlayRequested(const QModelIndex& index);
136 };
137 
138 class PlaylistManager : public PlaylistManagerInterface {
139   Q_OBJECT
140 
141  public:
142   PlaylistManager(Application* app, QObject* parent = nullptr);
143   ~PlaylistManager();
144 
current_id()145   int current_id() const { return current_; }
active_id()146   int active_id() const { return active_; }
147 
playlist(int id)148   Playlist* playlist(int id) const { return playlists_[id].p; }
current()149   Playlist* current() const { return playlist(current_id()); }
active()150   Playlist* active() const { return playlist(active_id()); }
151 
152   // Returns the collection of playlists managed by this PlaylistManager.
153   QList<Playlist*> GetAllPlaylists() const;
154   // Grays out and reloads all deleted songs in all playlists.
155   void InvalidateDeletedSongs();
156   // Removes all deleted songs from all playlists.
157   void RemoveDeletedSongs();
158   // Returns true if the playlist is open
159   bool IsPlaylistOpen(int id);
160 
161   // Returns a pretty automatic name for playlist created from the given list of
162   // songs.
163   static QString GetNameForNewPlaylist(const SongList& songs);
164 
165   QItemSelection selection(int id) const;
current_selection()166   QItemSelection current_selection() const { return selection(current_id()); }
active_selection()167   QItemSelection active_selection() const { return selection(active_id()); }
168 
GetPlaylistName(int index)169   QString GetPlaylistName(int index) const { return playlists_[index].name; }
IsPlaylistFavorite(int index)170   bool IsPlaylistFavorite(int index) const {
171     return playlists_[index].p->is_favorite();
172   }
173 
174   void Init(LibraryBackend* library_backend, PlaylistBackend* playlist_backend,
175             PlaylistSequence* sequence, PlaylistContainer* playlist_container);
176 
library_backend()177   LibraryBackend* library_backend() const { return library_backend_; }
playlist_backend()178   PlaylistBackend* playlist_backend() const { return playlist_backend_; }
sequence()179   PlaylistSequence* sequence() const { return sequence_; }
parser()180   PlaylistParser* parser() const { return parser_; }
playlist_container()181   PlaylistContainer* playlist_container() const { return playlist_container_; }
182 
183  public slots:
184   void New(const QString& name, const SongList& songs = SongList(),
185            const QString& special_type = QString());
186   void Load(const QString& filename);
187   void Save(int id, const QString& filename, Playlist::Path path_type);
188   // Display a file dialog to let user choose a file before saving the file
189   void SaveWithUI(int id, const QString& playlist_name);
190   void Rename(int id, const QString& new_name);
191   void Favorite(int id, bool favorite);
192   void Delete(int id);
193   bool Close(int id);
194   void Open(int id);
195   void ChangePlaylistOrder(const QList<int>& ids);
196 
197   void Enque(int id, int index);
198 
199   void SetCurrentPlaylist(int id);
200   void SetActivePlaylist(int id);
201   void SetActiveToCurrent();
202 
203   void SelectionChanged(const QItemSelection& selection);
204 
205   // Makes a playlist current if it's open already, or opens it and makes it
206   // current if it is hidden.
207   void SetCurrentOrOpen(int id);
208 
209   // Convenience slots that defer to either current() or active()
210   void ClearCurrent();
211   void ShuffleCurrent();
212   void RemoveDuplicatesCurrent();
213   void RemoveUnavailableCurrent();
214   void SetActiveStreamMetadata(const QUrl& url, const Song& song);
215   // Rate current song using 0.0 - 1.0 scale.
216   void RateCurrentSong(double rating);
217   // Rate current song using 0 - 5 scale.
218   void RateCurrentSong(int rating);
219 
220   void PlaySmartPlaylist(smart_playlists::GeneratorPtr generator, bool as_new,
221                          bool clear);
222 
223   void SongChangeRequestProcessed(const QUrl& url, bool valid);
224 
225   void InsertUrls(int id, const QList<QUrl>& urls, int pos = -1,
226                   bool play_now = false, bool enqueue = false);
227   void InsertSongs(int id, const SongList& songs, int pos = -1,
228                    bool play_now = false, bool enqueue = false);
229   // Removes items with given indices from the playlist. This operation is not
230   // undoable.
231   void RemoveItemsWithoutUndo(int id, const QList<int>& indices);
232   // Remove the current playing song
233   void RemoveCurrentSong();
234 
235  private slots:
236   void SetActivePlaying();
237   void SetActivePaused();
238   void SetActiveStopped();
239 
240   void OneOfPlaylistsChanged();
241   void UpdateSummaryText();
242   void SongsDiscovered(const SongList& songs);
243   void ItemsLoadedForSavePlaylist(QFuture<SongList> future,
244                                   const QString& filename,
245                                   Playlist::Path path_type);
246 
247  private:
248   Playlist* AddPlaylist(int id, const QString& name,
249                         const QString& special_type, const QString& ui_path,
250                         bool favorite);
251 
252  private:
253   struct Data {
254     Data(Playlist* _p = nullptr, const QString& _name = QString())
pData255         : p(_p), name(_name) {}
256     Playlist* p;
257     QString name;
258     QItemSelection selection;
259   };
260 
261   Application* app_;
262   PlaylistBackend* playlist_backend_;
263   LibraryBackend* library_backend_;
264   PlaylistSequence* sequence_;
265   PlaylistParser* parser_;
266   PlaylistContainer* playlist_container_;
267 
268   // key = id
269   QMap<int, Data> playlists_;
270 
271   int current_;
272   int active_;
273 };
274 
275 #endif  // PLAYLISTMANAGER_H
276