2010-05-20 23:21:55 +02:00
|
|
|
/* This file is part of Clementine.
|
2010-11-20 14:27:10 +01:00
|
|
|
Copyright 2010, David Sansome <me@davidsansome.com>
|
2010-05-20 23:21:55 +02:00
|
|
|
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "playlistbackend.h"
|
2011-11-12 17:12:03 +01:00
|
|
|
#include "playlistcontainer.h"
|
2010-05-20 23:21:55 +02:00
|
|
|
#include "playlistmanager.h"
|
2011-11-12 17:12:03 +01:00
|
|
|
#include "playlistview.h"
|
2012-02-12 14:41:50 +01:00
|
|
|
#include "core/application.h"
|
2011-04-28 19:50:45 +02:00
|
|
|
#include "core/logging.h"
|
2012-02-12 14:41:50 +01:00
|
|
|
#include "core/player.h"
|
2010-08-03 16:59:18 +02:00
|
|
|
#include "core/songloader.h"
|
2010-06-12 23:20:53 +02:00
|
|
|
#include "core/utilities.h"
|
2010-06-18 16:26:46 +02:00
|
|
|
#include "library/librarybackend.h"
|
|
|
|
#include "library/libraryplaylistitem.h"
|
2010-05-23 00:20:00 +02:00
|
|
|
#include "playlistparsers/playlistparser.h"
|
2010-11-18 21:19:33 +01:00
|
|
|
#include "smartplaylists/generator.h"
|
2010-05-23 00:20:00 +02:00
|
|
|
|
2013-05-23 20:09:35 +02:00
|
|
|
#include <QFileDialog>
|
2010-05-23 00:20:00 +02:00
|
|
|
#include <QFileInfo>
|
2013-05-23 20:09:35 +02:00
|
|
|
#include <QFuture>
|
|
|
|
#include <QFutureWatcher>
|
2013-07-18 00:37:31 +02:00
|
|
|
#include <QMessageBox>
|
2010-06-13 14:45:05 +02:00
|
|
|
#include <QtDebug>
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2010-11-18 21:19:33 +01:00
|
|
|
using smart_playlists::GeneratorPtr;
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
PlaylistManager::PlaylistManager(Application* app, QObject* parent)
|
|
|
|
: PlaylistManagerInterface(app, parent),
|
|
|
|
app_(app),
|
|
|
|
playlist_backend_(nullptr),
|
|
|
|
library_backend_(nullptr),
|
|
|
|
sequence_(nullptr),
|
|
|
|
parser_(nullptr),
|
|
|
|
current_(-1),
|
|
|
|
active_(-1) {
|
2012-02-12 14:41:50 +01:00
|
|
|
connect(app_->player(), SIGNAL(Paused()), SLOT(SetActivePaused()));
|
|
|
|
connect(app_->player(), SIGNAL(Playing()), SLOT(SetActivePlaying()));
|
|
|
|
connect(app_->player(), SIGNAL(Stopped()), SLOT(SetActiveStopped()));
|
2013-05-23 20:09:35 +02:00
|
|
|
|
|
|
|
settings_.beginGroup(Playlist::kSettingsGroup);
|
2010-05-20 23:21:55 +02:00
|
|
|
}
|
|
|
|
|
2010-05-21 12:29:17 +02:00
|
|
|
PlaylistManager::~PlaylistManager() {
|
2014-02-10 14:29:07 +01:00
|
|
|
for (const Data& data : playlists_.values()) {
|
|
|
|
delete data.p;
|
|
|
|
}
|
2010-05-21 12:29:17 +02:00
|
|
|
}
|
|
|
|
|
2010-05-20 23:21:55 +02:00
|
|
|
void PlaylistManager::Init(LibraryBackend* library_backend,
|
|
|
|
PlaylistBackend* playlist_backend,
|
2011-04-28 22:48:53 +02:00
|
|
|
PlaylistSequence* sequence,
|
|
|
|
PlaylistContainer* playlist_container) {
|
2010-05-20 23:21:55 +02:00
|
|
|
library_backend_ = library_backend;
|
|
|
|
playlist_backend_ = playlist_backend;
|
|
|
|
sequence_ = sequence;
|
2010-12-11 11:35:07 +01:00
|
|
|
parser_ = new PlaylistParser(library_backend, this);
|
2011-04-28 22:48:53 +02:00
|
|
|
playlist_container_ = playlist_container;
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(library_backend_, SIGNAL(SongsDiscovered(SongList)),
|
|
|
|
SLOT(SongsDiscovered(SongList)));
|
|
|
|
connect(library_backend_, SIGNAL(SongsStatisticsChanged(SongList)),
|
|
|
|
SLOT(SongsDiscovered(SongList)));
|
|
|
|
connect(library_backend_, SIGNAL(SongsRatingChanged(SongList)),
|
|
|
|
SLOT(SongsDiscovered(SongList)));
|
2010-06-18 16:26:46 +02:00
|
|
|
|
2014-02-10 14:29:07 +01:00
|
|
|
for (const PlaylistBackend::Playlist& p :
|
|
|
|
playlist_backend->GetAllOpenPlaylists()) {
|
2013-05-11 23:17:54 +02:00
|
|
|
AddPlaylist(p.id, p.name, p.special_type, p.ui_path, p.favorite);
|
2010-05-20 23:21:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// If no playlist exists then make a new one
|
2014-02-07 16:34:20 +01:00
|
|
|
if (playlists_.isEmpty()) New(tr("Playlist"));
|
2010-12-07 22:14:40 +01:00
|
|
|
|
|
|
|
emit PlaylistManagerInitialized();
|
2010-05-20 23:21:55 +02:00
|
|
|
}
|
|
|
|
|
2011-02-13 19:37:45 +01:00
|
|
|
QList<Playlist*> PlaylistManager::GetAllPlaylists() const {
|
2011-01-17 00:46:58 +01:00
|
|
|
QList<Playlist*> result;
|
|
|
|
|
2014-02-10 14:29:07 +01:00
|
|
|
for (const Data& data : playlists_.values()) {
|
|
|
|
result.append(data.p);
|
|
|
|
}
|
2011-01-17 00:46:58 +01:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2011-05-29 14:55:18 +02:00
|
|
|
QItemSelection PlaylistManager::selection(int id) const {
|
2011-02-04 12:17:31 +01:00
|
|
|
QMap<int, Data>::const_iterator it = playlists_.find(id);
|
|
|
|
return it->selection;
|
|
|
|
}
|
|
|
|
|
2011-04-28 19:50:45 +02:00
|
|
|
Playlist* PlaylistManager::AddPlaylist(int id, const QString& name,
|
2012-10-31 07:04:22 +01:00
|
|
|
const QString& special_type,
|
2014-02-07 16:34:20 +01:00
|
|
|
const QString& ui_path, bool favorite) {
|
2012-02-12 14:41:50 +01:00
|
|
|
Playlist* ret = new Playlist(playlist_backend_, app_->task_manager(),
|
2013-05-11 23:17:54 +02:00
|
|
|
library_backend_, id, special_type, favorite);
|
2010-05-20 23:21:55 +02:00
|
|
|
ret->set_sequence(sequence_);
|
2012-10-31 07:04:22 +01:00
|
|
|
ret->set_ui_path(ui_path);
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(ret, SIGNAL(CurrentSongChanged(Song)),
|
|
|
|
SIGNAL(CurrentSongChanged(Song)));
|
2010-12-08 01:09:17 +01:00
|
|
|
connect(ret, SIGNAL(PlaylistChanged()), SLOT(OneOfPlaylistsChanged()));
|
2010-06-12 23:20:53 +02:00
|
|
|
connect(ret, SIGNAL(PlaylistChanged()), SLOT(UpdateSummaryText()));
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(ret, SIGNAL(EditingFinished(QModelIndex)),
|
|
|
|
SIGNAL(EditingFinished(QModelIndex)));
|
2010-06-15 20:24:08 +02:00
|
|
|
connect(ret, SIGNAL(LoadTracksError(QString)), SIGNAL(Error(QString)));
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(ret, SIGNAL(PlayRequested(QModelIndex)),
|
|
|
|
SIGNAL(PlayRequested(QModelIndex)));
|
|
|
|
connect(playlist_container_->view(),
|
|
|
|
SIGNAL(ColumnAlignmentChanged(ColumnAlignmentMap)), ret,
|
|
|
|
SLOT(SetColumnAlignment(ColumnAlignmentMap)));
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2010-05-21 12:29:17 +02:00
|
|
|
playlists_[id] = Data(ret, name);
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2013-05-11 23:17:54 +02:00
|
|
|
emit PlaylistAdded(id, name, favorite);
|
2010-05-20 23:21:55 +02:00
|
|
|
|
|
|
|
if (current_ == -1) {
|
2010-05-21 12:29:17 +02:00
|
|
|
SetCurrentPlaylist(id);
|
2010-05-20 23:21:55 +02:00
|
|
|
}
|
|
|
|
if (active_ == -1) {
|
2010-05-21 12:29:17 +02:00
|
|
|
SetActivePlaylist(id);
|
2010-05-20 23:21:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-04-28 19:50:45 +02:00
|
|
|
void PlaylistManager::New(const QString& name, const SongList& songs,
|
|
|
|
const QString& special_type) {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (name.isNull()) return;
|
2011-03-20 18:38:15 +01:00
|
|
|
|
2011-04-28 19:50:45 +02:00
|
|
|
int id = playlist_backend_->CreatePlaylist(name, special_type);
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
if (id == -1) qFatal("Couldn't create playlist");
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2013-05-11 23:17:54 +02:00
|
|
|
Playlist* playlist = AddPlaylist(id, name, special_type, QString(), false);
|
2010-12-11 11:35:07 +01:00
|
|
|
playlist->InsertSongsOrLibraryItems(songs);
|
2010-05-22 22:28:11 +02:00
|
|
|
|
2010-05-21 12:29:17 +02:00
|
|
|
SetCurrentPlaylist(id);
|
2013-08-17 15:54:39 +02:00
|
|
|
|
|
|
|
// If the name is just "Playlist", append the id
|
|
|
|
if (name == tr("Playlist")) {
|
|
|
|
Rename(id, QString("%1 %2").arg(name).arg(id));
|
|
|
|
}
|
2010-05-20 23:21:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistManager::Load(const QString& filename) {
|
2010-05-23 00:20:00 +02:00
|
|
|
QFileInfo info(filename);
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2014-04-02 15:57:01 +02:00
|
|
|
int id = playlist_backend_->CreatePlaylist(info.baseName(), QString());
|
2010-05-23 00:20:00 +02:00
|
|
|
|
2014-04-07 15:27:47 +02:00
|
|
|
if (id == -1) {
|
|
|
|
emit Error(tr("Couldn't create playlist"));
|
|
|
|
return;
|
|
|
|
}
|
2010-08-03 16:59:18 +02:00
|
|
|
|
2014-04-02 15:57:01 +02:00
|
|
|
Playlist* playlist = AddPlaylist(id, info.baseName(), QString(), QString(), false);
|
2010-08-03 16:59:18 +02:00
|
|
|
|
2014-04-02 15:57:01 +02:00
|
|
|
QList<QUrl> urls;
|
|
|
|
playlist->InsertUrls(urls << QUrl::fromLocalFile(filename));
|
2010-05-20 23:21:55 +02:00
|
|
|
}
|
|
|
|
|
2010-05-21 12:29:17 +02:00
|
|
|
void PlaylistManager::Save(int id, const QString& filename) {
|
2013-05-23 20:09:35 +02:00
|
|
|
if (playlists_.contains(id)) {
|
|
|
|
parser_->Save(playlist(id)->GetAllSongs(), filename);
|
|
|
|
} else {
|
2014-02-07 16:34:20 +01:00
|
|
|
// Playlist is not in the playlist manager: probably save action was
|
|
|
|
// triggered
|
2013-05-23 20:09:35 +02:00
|
|
|
// from the left side bar and the playlist isn't loaded.
|
|
|
|
QFuture<Song> future = playlist_backend_->GetPlaylistSongs(id);
|
|
|
|
QFutureWatcher<Song>* watcher = new QFutureWatcher<Song>(this);
|
|
|
|
watcher->setFuture(future);
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
NewClosure(watcher, SIGNAL(finished()), this,
|
|
|
|
SLOT(ItemsLoadedForSavePlaylist(QFutureWatcher<Song>*, QString)),
|
|
|
|
watcher, filename);
|
2013-05-23 20:09:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void PlaylistManager::ItemsLoadedForSavePlaylist(QFutureWatcher<Song>* watcher,
|
|
|
|
const QString& filename) {
|
2010-05-23 00:20:00 +02:00
|
|
|
|
2013-05-23 20:09:35 +02:00
|
|
|
SongList song_list = watcher->future().results();
|
|
|
|
parser_->Save(song_list, filename);
|
2010-05-20 23:21:55 +02:00
|
|
|
}
|
|
|
|
|
2013-05-23 20:09:35 +02:00
|
|
|
void PlaylistManager::SaveWithUI(int id, const QString& suggested_filename) {
|
|
|
|
QString filename = settings_.value("last_save_playlist").toString();
|
|
|
|
|
|
|
|
// We want to use the playlist tab name as a default filename, but in the
|
|
|
|
// same directory as the last saved file.
|
|
|
|
|
|
|
|
// Strip off filename components until we find something that's a folder
|
|
|
|
forever {
|
|
|
|
QFileInfo fileinfo(filename);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (filename.isEmpty() || fileinfo.isDir()) break;
|
2013-05-23 20:09:35 +02:00
|
|
|
|
|
|
|
filename = filename.section('/', 0, -2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use the home directory as a fallback in case the path is empty.
|
2014-02-07 16:34:20 +01:00
|
|
|
if (filename.isEmpty()) filename = QDir::homePath();
|
2013-05-23 20:09:35 +02:00
|
|
|
|
|
|
|
// Add the suggested filename
|
2014-02-07 16:34:20 +01:00
|
|
|
filename += "/" + suggested_filename + "." + parser()->default_extension();
|
2013-05-23 20:09:35 +02:00
|
|
|
|
|
|
|
QString default_filter = parser()->default_filter();
|
|
|
|
|
|
|
|
filename = QFileDialog::getSaveFileName(
|
2014-02-07 16:34:20 +01:00
|
|
|
nullptr, tr("Save playlist", "Title of the playlist save dialog."),
|
|
|
|
filename, parser()->filters(), &default_filter);
|
2013-05-23 20:09:35 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
if (filename.isNull()) return;
|
2013-05-23 20:09:35 +02:00
|
|
|
|
|
|
|
settings_.setValue("last_save_playlist", filename);
|
|
|
|
|
|
|
|
Save(id == -1 ? current_id() : id, filename);
|
|
|
|
}
|
|
|
|
|
2010-05-21 12:29:17 +02:00
|
|
|
void PlaylistManager::Rename(int id, const QString& new_name) {
|
|
|
|
Q_ASSERT(playlists_.contains(id));
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2010-05-21 12:29:17 +02:00
|
|
|
playlist_backend_->RenamePlaylist(id, new_name);
|
|
|
|
playlists_[id].name = new_name;
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2010-05-21 12:29:17 +02:00
|
|
|
emit PlaylistRenamed(id, new_name);
|
2010-05-20 23:21:55 +02:00
|
|
|
}
|
|
|
|
|
2013-05-11 23:17:54 +02:00
|
|
|
void PlaylistManager::Favorite(int id, bool favorite) {
|
2013-05-12 23:36:32 +02:00
|
|
|
|
2013-06-29 16:16:52 +02:00
|
|
|
if (playlists_.contains(id)) {
|
2014-02-07 16:34:20 +01:00
|
|
|
// If playlists_ contains this playlist, its means it's opened: star or
|
|
|
|
// unstar it.
|
2013-06-29 16:16:52 +02:00
|
|
|
playlist_backend_->FavoritePlaylist(id, favorite);
|
|
|
|
playlists_[id].p->set_favorite(favorite);
|
|
|
|
} else {
|
|
|
|
Q_ASSERT(!favorite);
|
2014-02-07 16:34:20 +01:00
|
|
|
// Otherwise it means user wants to remove this playlist from the left
|
|
|
|
// panel,
|
2013-06-29 16:16:52 +02:00
|
|
|
// while it's not visible in the playlist tabbar either, because it has been
|
|
|
|
// closed: delete it.
|
|
|
|
playlist_backend_->RemovePlaylist(id);
|
|
|
|
}
|
2013-05-11 23:17:54 +02:00
|
|
|
emit PlaylistFavorited(id, favorite);
|
|
|
|
}
|
|
|
|
|
2012-10-31 07:04:22 +01:00
|
|
|
bool PlaylistManager::Close(int id) {
|
2010-05-20 23:21:55 +02:00
|
|
|
// Won't allow removing the last playlist
|
2014-02-07 16:34:20 +01:00
|
|
|
if (playlists_.count() <= 1 || !playlists_.contains(id)) return false;
|
2010-05-21 12:29:17 +02:00
|
|
|
|
2010-12-18 20:37:29 +01:00
|
|
|
int next_id = -1;
|
2014-02-10 14:29:07 +01:00
|
|
|
for (int possible_next_id : playlists_.keys()) {
|
2010-12-18 20:37:29 +01:00
|
|
|
if (possible_next_id != id) {
|
|
|
|
next_id = possible_next_id;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-02-07 16:34:20 +01:00
|
|
|
if (next_id == -1) return false;
|
2010-05-21 12:29:17 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
if (id == active_) SetActivePlaylist(next_id);
|
|
|
|
if (id == current_) SetCurrentPlaylist(next_id);
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2010-05-21 12:29:17 +02:00
|
|
|
Data data = playlists_.take(id);
|
2013-05-11 23:17:54 +02:00
|
|
|
emit PlaylistClosed(id);
|
|
|
|
|
|
|
|
if (!data.p->is_favorite()) {
|
|
|
|
playlist_backend_->RemovePlaylist(id);
|
|
|
|
emit PlaylistDeleted(id);
|
|
|
|
}
|
2010-05-21 12:29:17 +02:00
|
|
|
delete data.p;
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2012-10-31 07:04:22 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistManager::Delete(int id) {
|
|
|
|
if (!Close(id)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
playlist_backend_->RemovePlaylist(id);
|
|
|
|
emit PlaylistDeleted(id);
|
2010-05-20 23:21:55 +02:00
|
|
|
}
|
|
|
|
|
2010-12-08 01:09:17 +01:00
|
|
|
void PlaylistManager::OneOfPlaylistsChanged() {
|
|
|
|
emit PlaylistChanged(qobject_cast<Playlist*>(sender()));
|
|
|
|
}
|
|
|
|
|
2010-05-21 12:29:17 +02:00
|
|
|
void PlaylistManager::SetCurrentPlaylist(int id) {
|
|
|
|
Q_ASSERT(playlists_.contains(id));
|
|
|
|
current_ = id;
|
2010-05-20 23:21:55 +02:00
|
|
|
emit CurrentChanged(current());
|
2010-06-12 23:20:53 +02:00
|
|
|
UpdateSummaryText();
|
2010-05-20 23:21:55 +02:00
|
|
|
}
|
|
|
|
|
2010-05-21 12:29:17 +02:00
|
|
|
void PlaylistManager::SetActivePlaylist(int id) {
|
|
|
|
Q_ASSERT(playlists_.contains(id));
|
2010-05-20 23:51:01 +02:00
|
|
|
|
|
|
|
// Kinda a hack: unset the current item from the old active playlist before
|
|
|
|
// setting the new one
|
2014-02-07 16:34:20 +01:00
|
|
|
if (active_ != -1 && active_ != id) active()->set_current_row(-1);
|
2010-05-20 23:51:01 +02:00
|
|
|
|
2010-05-21 12:29:17 +02:00
|
|
|
active_ = id;
|
|
|
|
emit ActiveChanged(active());
|
2010-11-20 19:49:54 +01:00
|
|
|
|
|
|
|
sequence_->SetUsingDynamicPlaylist(active()->is_dynamic());
|
2010-05-20 23:21:55 +02:00
|
|
|
}
|
|
|
|
|
2013-03-20 15:33:53 +01:00
|
|
|
void PlaylistManager::SetActiveToCurrent() {
|
|
|
|
// Check if we need to update the active playlist.
|
|
|
|
// By calling SetActiveToCurrent, the playlist manager emits the signal
|
|
|
|
// "ActiveChanged". This signal causes the network remote module to
|
|
|
|
// send all playlists to the clients, even no change happend.
|
|
|
|
if (current_id() != active_id()) {
|
|
|
|
SetActivePlaylist(current_id());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void PlaylistManager::ClearCurrent() { current()->Clear(); }
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void PlaylistManager::ShuffleCurrent() { current()->Shuffle(); }
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2012-07-06 00:00:33 +02:00
|
|
|
void PlaylistManager::RemoveDuplicatesCurrent() {
|
|
|
|
current()->RemoveDuplicateSongs();
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void PlaylistManager::SetActivePlaying() { active()->Playing(); }
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void PlaylistManager::SetActivePaused() { active()->Paused(); }
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void PlaylistManager::SetActiveStopped() { active()->Stopped(); }
|
2010-05-20 23:21:55 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void PlaylistManager::SetActiveStreamMetadata(const QUrl& url,
|
|
|
|
const Song& song) {
|
2010-05-20 23:21:55 +02:00
|
|
|
active()->SetStreamMetadata(url, song);
|
|
|
|
}
|
2010-05-21 12:37:24 +02:00
|
|
|
|
2010-12-17 01:21:20 +01:00
|
|
|
void PlaylistManager::RateCurrentSong(double rating) {
|
|
|
|
active()->RateSong(active()->current_index(), rating);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistManager::RateCurrentSong(int rating) {
|
|
|
|
RateCurrentSong(rating / 5.0);
|
|
|
|
}
|
|
|
|
|
2010-05-21 12:37:24 +02:00
|
|
|
void PlaylistManager::ChangePlaylistOrder(const QList<int>& ids) {
|
|
|
|
playlist_backend_->SetPlaylistOrder(ids);
|
|
|
|
}
|
2010-06-12 23:20:53 +02:00
|
|
|
|
|
|
|
void PlaylistManager::UpdateSummaryText() {
|
|
|
|
int tracks = current()->rowCount();
|
2011-02-13 19:34:30 +01:00
|
|
|
quint64 nanoseconds = 0;
|
2010-06-13 14:45:05 +02:00
|
|
|
int selected = 0;
|
|
|
|
|
|
|
|
// Get the length of the selected tracks
|
2014-02-10 14:29:07 +01:00
|
|
|
for (const QItemSelectionRange& range : playlists_[current_id()].selection) {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!range.isValid()) continue;
|
2010-06-18 18:06:51 +02:00
|
|
|
|
2010-06-13 14:45:05 +02:00
|
|
|
selected += range.bottom() - range.top() + 1;
|
2014-02-07 16:34:20 +01:00
|
|
|
for (int i = range.top(); i <= range.bottom(); ++i) {
|
|
|
|
qint64 length =
|
|
|
|
range.model()->index(i, Playlist::Column_Length).data().toLongLong();
|
|
|
|
if (length > 0) nanoseconds += length;
|
2010-06-13 14:45:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString summary;
|
|
|
|
if (selected > 1) {
|
|
|
|
summary += tr("%1 selected of").arg(selected) + " ";
|
|
|
|
} else {
|
2011-02-13 19:34:30 +01:00
|
|
|
nanoseconds = current()->GetTotalLength();
|
2010-06-13 14:45:05 +02:00
|
|
|
}
|
2010-06-12 23:20:53 +02:00
|
|
|
|
|
|
|
// TODO: Make the plurals translatable
|
2010-06-13 14:45:05 +02:00
|
|
|
summary += tracks == 1 ? tr("1 track") : tr("%1 tracks").arg(tracks);
|
2010-06-12 23:20:53 +02:00
|
|
|
|
2011-02-13 19:34:30 +01:00
|
|
|
if (nanoseconds)
|
|
|
|
summary += " - [ " + Utilities::WordyTimeNanosec(nanoseconds) + " ]";
|
2010-06-12 23:20:53 +02:00
|
|
|
|
|
|
|
emit SummaryTextChanged(summary);
|
|
|
|
}
|
2010-06-13 14:45:05 +02:00
|
|
|
|
2010-09-25 17:30:47 +02:00
|
|
|
void PlaylistManager::SelectionChanged(const QItemSelection& selection) {
|
|
|
|
playlists_[current_id()].selection = selection;
|
2010-06-13 14:45:05 +02:00
|
|
|
UpdateSummaryText();
|
|
|
|
}
|
2010-06-18 16:26:46 +02:00
|
|
|
|
|
|
|
void PlaylistManager::SongsDiscovered(const SongList& songs) {
|
|
|
|
// Some songs might've changed in the library, let's update any playlist
|
|
|
|
// items we have that match those songs
|
|
|
|
|
2014-02-10 14:29:07 +01:00
|
|
|
for (const Song& song : songs) {
|
|
|
|
for (const Data& data : playlists_) {
|
2010-06-18 16:26:46 +02:00
|
|
|
PlaylistItemList items = data.p->library_items_by_id(song.id());
|
2014-02-10 14:29:07 +01:00
|
|
|
for (PlaylistItemPtr item : items) {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (item->Metadata().directory_id() != song.directory_id()) continue;
|
2010-06-18 16:26:46 +02:00
|
|
|
static_cast<LibraryPlaylistItem*>(item.get())->SetMetadata(song);
|
2010-10-23 22:58:20 +02:00
|
|
|
data.p->ItemChanged(item);
|
2010-06-18 16:26:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-10-24 17:38:12 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void PlaylistManager::PlaySmartPlaylist(GeneratorPtr generator, bool as_new,
|
|
|
|
bool clear) {
|
2010-10-24 17:38:12 +02:00
|
|
|
if (as_new) {
|
|
|
|
New(generator->name());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (clear) {
|
|
|
|
current()->Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
current()->InsertSmartPlaylist(generator);
|
|
|
|
}
|
2011-03-10 19:01:35 +01:00
|
|
|
|
|
|
|
// When Player has processed the new song chosen by the user...
|
|
|
|
void PlaylistManager::SongChangeRequestProcessed(const QUrl& url, bool valid) {
|
2014-02-10 14:29:07 +01:00
|
|
|
for (Playlist* playlist : GetAllPlaylists()) {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (playlist->ApplyValidityOnCurrentSong(url, valid)) {
|
2011-03-19 10:41:00 +01:00
|
|
|
return;
|
2011-03-10 19:01:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-03-19 10:41:00 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void PlaylistManager::InsertUrls(int id, const QList<QUrl>& urls, int pos,
|
2013-07-31 19:06:29 +02:00
|
|
|
bool play_now, bool enqueue) {
|
|
|
|
Q_ASSERT(playlists_.contains(id));
|
|
|
|
|
|
|
|
playlists_[id].p->InsertUrls(urls, pos, play_now, enqueue);
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void PlaylistManager::RemoveItemsWithoutUndo(int id,
|
|
|
|
const QList<int>& indices) {
|
2013-07-31 19:06:29 +02:00
|
|
|
Q_ASSERT(playlists_.contains(id));
|
|
|
|
|
|
|
|
playlists_[id].p->RemoveItemsWithoutUndo(indices);
|
|
|
|
}
|
|
|
|
|
2011-03-19 10:41:00 +01:00
|
|
|
void PlaylistManager::InvalidateDeletedSongs() {
|
2014-02-10 14:29:07 +01:00
|
|
|
for (Playlist* playlist : GetAllPlaylists()) {
|
2011-03-19 10:41:00 +01:00
|
|
|
playlist->InvalidateDeletedSongs();
|
|
|
|
}
|
|
|
|
}
|
2011-03-25 20:16:12 +01:00
|
|
|
|
2011-04-21 23:56:37 +02:00
|
|
|
void PlaylistManager::RemoveDeletedSongs() {
|
2014-02-10 14:29:07 +01:00
|
|
|
for (Playlist* playlist : GetAllPlaylists()) {
|
2011-04-21 23:56:37 +02:00
|
|
|
playlist->RemoveDeletedSongs();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-25 20:16:12 +01:00
|
|
|
QString PlaylistManager::GetNameForNewPlaylist(const SongList& songs) {
|
|
|
|
if (songs.isEmpty()) {
|
|
|
|
return tr("Playlist");
|
|
|
|
}
|
|
|
|
|
|
|
|
QSet<QString> artists;
|
|
|
|
QSet<QString> albums;
|
|
|
|
|
2014-02-10 14:29:07 +01:00
|
|
|
for (const Song& song : songs) {
|
2014-02-07 16:34:20 +01:00
|
|
|
artists << (song.artist().isEmpty() ? tr("Unknown") : song.artist());
|
|
|
|
albums << (song.album().isEmpty() ? tr("Unknown") : song.album());
|
2011-03-25 20:16:12 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
if (artists.size() > 1) {
|
2011-03-25 20:16:12 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool various_artists = artists.size() > 1;
|
|
|
|
|
|
|
|
QString result;
|
2014-02-07 16:34:20 +01:00
|
|
|
if (various_artists) {
|
2011-03-25 20:16:12 +01:00
|
|
|
result = tr("Various artists");
|
|
|
|
} else {
|
|
|
|
result = artists.values().first();
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!various_artists && albums.size() == 1) {
|
2011-03-25 20:16:12 +01:00
|
|
|
result += " - " + albums.toList().first();
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2012-10-31 07:04:22 +01:00
|
|
|
|
|
|
|
void PlaylistManager::Open(int id) {
|
|
|
|
if (playlists_.contains(id)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const PlaylistBackend::Playlist& p = playlist_backend_->GetPlaylist(id);
|
|
|
|
if (p.id != id) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-11 23:17:54 +02:00
|
|
|
AddPlaylist(p.id, p.name, p.special_type, p.ui_path, p.favorite);
|
2012-10-31 07:04:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void PlaylistManager::SetCurrentOrOpen(int id) {
|
|
|
|
Open(id);
|
|
|
|
SetCurrentPlaylist(id);
|
|
|
|
}
|
2013-04-16 13:57:04 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
bool PlaylistManager::IsPlaylistOpen(int id) { return playlists_.contains(id); }
|