mirror of
https://github.com/clementine-player/Clementine
synced 2025-01-31 11:35:24 +01:00
Save the playlists in the background, and use shared_ptrs for all playlist items so they stay in scope after they've been deleted but while they're still being saved.
This commit is contained in:
parent
b16f789ac7
commit
72cbf90689
@ -900,7 +900,8 @@ PlaylistItemList LibraryBackend::GetPlaylistItems(int playlist) {
|
||||
// The song table gets joined first, plus one for the song ROWID
|
||||
const int row = Song::kColumns.count() + 1;
|
||||
|
||||
PlaylistItem* item = PlaylistItem::NewFromType(q.value(row + 0).toString());
|
||||
boost::shared_ptr<PlaylistItem> item(
|
||||
PlaylistItem::NewFromType(q.value(row + 0).toString()));
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
@ -911,6 +912,12 @@ PlaylistItemList LibraryBackend::GetPlaylistItems(int playlist) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LibraryBackend::SavePlaylistAsync(int playlist, const PlaylistItemList &items) {
|
||||
metaObject()->invokeMethod(this, "SavePlaylist", Qt::QueuedConnection,
|
||||
Q_ARG(int, playlist),
|
||||
Q_ARG(PlaylistItemList, items));
|
||||
}
|
||||
|
||||
void LibraryBackend::SavePlaylist(int playlist, const PlaylistItemList& items) {
|
||||
QSqlDatabase db(Connect());
|
||||
|
||||
@ -918,21 +925,19 @@ void LibraryBackend::SavePlaylist(int playlist, const PlaylistItemList& items) {
|
||||
QSqlQuery insert("INSERT INTO playlist_items"
|
||||
" (playlist, type, library_id, url, title, artist, album,"
|
||||
" length, radio_service)"
|
||||
" VALUES (:playlist, :type, :library_id, :url, :title,"
|
||||
" :artist, :album, :length, :radio_service)", db);
|
||||
|
||||
clear.bindValue(":playlist", playlist);
|
||||
" VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", db);
|
||||
|
||||
ScopedTransaction transaction(&db);
|
||||
|
||||
// Clear the existing items in the playlist
|
||||
clear.bindValue(":playlist", playlist);
|
||||
clear.exec();
|
||||
if (CheckErrors(clear.lastError()))
|
||||
return;
|
||||
|
||||
// Save the new ones
|
||||
foreach (const PlaylistItem* item, items) {
|
||||
insert.bindValue(":playlist", playlist);
|
||||
foreach (boost::shared_ptr<PlaylistItem> item, items) {
|
||||
insert.bindValue(0, playlist);
|
||||
item->BindToQuery(&insert);
|
||||
|
||||
insert.exec();
|
||||
|
@ -98,7 +98,7 @@ class LibraryBackendInterface : public QObject {
|
||||
// Functions for getting playlists
|
||||
virtual PlaylistList GetAllPlaylists() = 0;
|
||||
virtual PlaylistItemList GetPlaylistItems(int playlist) = 0;
|
||||
virtual void SavePlaylist(int playlist, const PlaylistItemList& items) = 0;
|
||||
virtual void SavePlaylistAsync(int playlist, const PlaylistItemList& items) = 0;
|
||||
|
||||
public slots:
|
||||
virtual void LoadDirectories() = 0;
|
||||
@ -110,6 +110,7 @@ class LibraryBackendInterface : public QObject {
|
||||
virtual void UpdateCompilations() = 0;
|
||||
virtual void UpdateManualAlbumArt(const QString& artist, const QString& album, const QString& art) = 0;
|
||||
virtual void ForceCompilation(const QString& artist, const QString& album, bool on) = 0;
|
||||
virtual void SavePlaylist(int playlist, const PlaylistItemList& items) = 0;
|
||||
|
||||
signals:
|
||||
void Error(const QString& message);
|
||||
@ -168,7 +169,7 @@ class LibraryBackend : public LibraryBackendInterface {
|
||||
|
||||
PlaylistList GetAllPlaylists();
|
||||
PlaylistItemList GetPlaylistItems(int playlist);
|
||||
void SavePlaylist(int playlist, const PlaylistItemList& items);
|
||||
void SavePlaylistAsync(int playlist, const PlaylistItemList& items);
|
||||
|
||||
public slots:
|
||||
void LoadDirectories();
|
||||
@ -180,6 +181,7 @@ class LibraryBackend : public LibraryBackendInterface {
|
||||
void UpdateCompilations();
|
||||
void UpdateManualAlbumArt(const QString& artist, const QString& album, const QString& art);
|
||||
void ForceCompilation(const QString& artist, const QString& album, bool on);
|
||||
void SavePlaylist(int playlist, const PlaylistItemList& items);
|
||||
|
||||
private:
|
||||
struct CompilationInfo {
|
||||
|
@ -85,6 +85,7 @@ int main(int argc, char *argv[]) {
|
||||
qRegisterMetaType<Subdirectory>("Subdirectory");
|
||||
qRegisterMetaType<SubdirectoryList>("SubdirectoryList");
|
||||
qRegisterMetaType<SongList>("SongList");
|
||||
qRegisterMetaType<PlaylistItemList>("PlaylistItemList");
|
||||
qRegisterMetaType<Engine::State>("Engine::State");
|
||||
qRegisterMetaType<Equalizer::Params>("Equalizer::Params");
|
||||
qRegisterMetaTypeStreamOperators<Equalizer::Params>("Equalizer::Params");
|
||||
|
@ -210,7 +210,7 @@ void Player::PlayAt(int index, Engine::TrackChangeType change) {
|
||||
playlist_->set_current_index(-1); // to reshuffle
|
||||
playlist_->set_current_index(index);
|
||||
|
||||
PlaylistItem* item = playlist_->item_at(index);
|
||||
boost::shared_ptr<PlaylistItem> item = playlist_->item_at(index);
|
||||
current_item_options_ = item->options();
|
||||
current_item_ = item->Metadata();
|
||||
|
||||
@ -231,7 +231,7 @@ void Player::StreamReady(const QUrl& original_url, const QUrl& media_url) {
|
||||
if (current_index == -1)
|
||||
return;
|
||||
|
||||
PlaylistItem* item = playlist_->item_at(current_index);
|
||||
boost::shared_ptr<PlaylistItem> item = playlist_->item_at(current_index);
|
||||
if (!item || item->Url() != original_url)
|
||||
return;
|
||||
|
||||
@ -256,7 +256,7 @@ void Player::Seek(int seconds) {
|
||||
}
|
||||
|
||||
void Player::EngineMetadataReceived(const Engine::SimpleMetaBundle& bundle) {
|
||||
PlaylistItem* item = playlist_->current_item();
|
||||
boost::shared_ptr<PlaylistItem> item = playlist_->current_item();
|
||||
if (item == NULL)
|
||||
return;
|
||||
|
||||
@ -344,7 +344,7 @@ QVariantMap Player::GetMetadata(const PlaylistItem& item) const {
|
||||
}
|
||||
|
||||
QVariantMap Player::GetMetadata() const {
|
||||
PlaylistItem* item = playlist_->current_item();
|
||||
boost::shared_ptr<PlaylistItem> item = playlist_->current_item();
|
||||
if (item) {
|
||||
return GetMetadata(*item);
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ Playlist::Playlist(QObject *parent, SettingsProvider* settings)
|
||||
}
|
||||
|
||||
Playlist::~Playlist() {
|
||||
qDeleteAll(items_);
|
||||
items_.clear();
|
||||
}
|
||||
|
||||
QVariant Playlist::headerData(int section, Qt::Orientation, int role) const {
|
||||
@ -143,7 +143,7 @@ QVariant Playlist::data(const QModelIndex& index, int role) const {
|
||||
case Qt::EditRole:
|
||||
case Qt::ToolTipRole:
|
||||
case Qt::DisplayRole: {
|
||||
PlaylistItem* item = items_[index.row()];
|
||||
const boost::shared_ptr<PlaylistItem>& item = items_[index.row()];
|
||||
Song song = item->Metadata();
|
||||
|
||||
// Don't forget to change Playlist::CompareItems when adding new columns
|
||||
@ -351,7 +351,7 @@ bool Playlist::dropMimeData(const QMimeData* data, Qt::DropAction action, int ro
|
||||
qStableSort(source_rows); // Make sure we take them in order
|
||||
|
||||
layoutAboutToBeChanged();
|
||||
QList<PlaylistItem*> moved_items;
|
||||
PlaylistItemList moved_items;
|
||||
|
||||
// Take the items out of the list first, keeping track of whether the
|
||||
// insertion point changes
|
||||
@ -439,7 +439,7 @@ QModelIndex Playlist::InsertPaths(QList<QUrl> urls, int after) {
|
||||
return InsertSongs(songs, after);
|
||||
}
|
||||
|
||||
QModelIndex Playlist::InsertItems(const QList<PlaylistItem*>& items, int after) {
|
||||
QModelIndex Playlist::InsertItems(const PlaylistItemList& items, int after) {
|
||||
if (items.isEmpty())
|
||||
return QModelIndex();
|
||||
|
||||
@ -460,37 +460,38 @@ QModelIndex Playlist::InsertItems(const QList<PlaylistItem*>& items, int after)
|
||||
}
|
||||
|
||||
QModelIndex Playlist::InsertLibraryItems(const SongList& songs, int after) {
|
||||
QList<PlaylistItem*> items;
|
||||
PlaylistItemList items;
|
||||
foreach (const Song& song, songs) {
|
||||
items << new LibraryPlaylistItem(song);
|
||||
items << boost::shared_ptr<PlaylistItem>(new LibraryPlaylistItem(song));
|
||||
}
|
||||
return InsertItems(items, after);
|
||||
}
|
||||
|
||||
QModelIndex Playlist::InsertSongs(const SongList& songs, int after) {
|
||||
QList<PlaylistItem*> items;
|
||||
PlaylistItemList items;
|
||||
foreach (const Song& song, songs) {
|
||||
items << new SongPlaylistItem(song);
|
||||
items << boost::shared_ptr<PlaylistItem>(new SongPlaylistItem(song));
|
||||
}
|
||||
return InsertItems(items, after);
|
||||
}
|
||||
|
||||
QModelIndex Playlist::InsertRadioStations(const QList<RadioItem*>& items, int after) {
|
||||
QList<PlaylistItem*> playlist_items;
|
||||
PlaylistItemList playlist_items;
|
||||
foreach (RadioItem* item, items) {
|
||||
if (!item->playable)
|
||||
continue;
|
||||
|
||||
playlist_items << new RadioPlaylistItem(item->service, item->Url(), item->Title(), item->Artist());
|
||||
playlist_items << boost::shared_ptr<PlaylistItem>(
|
||||
new RadioPlaylistItem(item->service, item->Url(), item->Title(), item->Artist()));
|
||||
}
|
||||
return InsertItems(playlist_items, after);
|
||||
}
|
||||
|
||||
QModelIndex Playlist::InsertStreamUrls(const QList<QUrl>& urls, int after) {
|
||||
QList<PlaylistItem*> playlist_items;
|
||||
PlaylistItemList playlist_items;
|
||||
foreach (const QUrl& url, urls) {
|
||||
playlist_items << new RadioPlaylistItem(
|
||||
RadioModel::ServiceByName(SavedRadio::kServiceName), url.toString(), url.toString(), QString());
|
||||
playlist_items << boost::shared_ptr<PlaylistItem>(new RadioPlaylistItem(
|
||||
RadioModel::ServiceByName(SavedRadio::kServiceName), url.toString(), url.toString(), QString()));
|
||||
}
|
||||
return InsertItems(playlist_items, after);
|
||||
}
|
||||
@ -521,9 +522,10 @@ QMimeData* Playlist::mimeData(const QModelIndexList& indexes) const {
|
||||
}
|
||||
|
||||
bool Playlist::CompareItems(int column, Qt::SortOrder order,
|
||||
const PlaylistItem* _a, const PlaylistItem* _b) {
|
||||
const PlaylistItem* a = order == Qt::AscendingOrder ? _a : _b;
|
||||
const PlaylistItem* b = order == Qt::AscendingOrder ? _b : _a;
|
||||
boost::shared_ptr<PlaylistItem> _a,
|
||||
boost::shared_ptr<PlaylistItem> _b) {
|
||||
boost::shared_ptr<PlaylistItem> a = order == Qt::AscendingOrder ? _a : _b;
|
||||
boost::shared_ptr<PlaylistItem> b = order == Qt::AscendingOrder ? _b : _a;
|
||||
|
||||
#define cmp(field) return a->Metadata().field() < b->Metadata().field()
|
||||
|
||||
@ -589,7 +591,7 @@ void Playlist::sort(int column, Qt::SortOrder order) {
|
||||
layoutAboutToBeChanged();
|
||||
|
||||
// This is a slow and nasty way to keep the persistent indices
|
||||
QMap<int, PlaylistItem*> old_persistent_mappings;
|
||||
QMap<int, boost::shared_ptr<PlaylistItem> > old_persistent_mappings;
|
||||
foreach (const QModelIndex& index, persistentIndexList()) {
|
||||
old_persistent_mappings[index.row()] = items_[index.row()];
|
||||
}
|
||||
@ -597,7 +599,7 @@ void Playlist::sort(int column, Qt::SortOrder order) {
|
||||
qStableSort(items_.begin(), items_.end(),
|
||||
boost::bind(&Playlist::CompareItems, column, order, _1, _2));
|
||||
|
||||
QMapIterator<int, PlaylistItem*> it(old_persistent_mappings);
|
||||
QMapIterator<int, boost::shared_ptr<PlaylistItem> > it(old_persistent_mappings);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
for (int col=0 ; col<ColumnCount ; ++col) {
|
||||
@ -645,7 +647,7 @@ void Playlist::Save() const {
|
||||
if (!backend_)
|
||||
return;
|
||||
|
||||
backend_->SavePlaylist(1, items_);
|
||||
backend_->SavePlaylistAsync(1, items_);
|
||||
|
||||
settings_->setValue("last_index", last_played_index());
|
||||
}
|
||||
@ -654,7 +656,6 @@ void Playlist::Restore() {
|
||||
if (!backend_)
|
||||
return;
|
||||
|
||||
qDeleteAll(items_);
|
||||
items_.clear();
|
||||
virtual_items_.clear();
|
||||
|
||||
@ -677,7 +678,7 @@ bool Playlist::removeRows(int row, int count, const QModelIndex& parent) {
|
||||
|
||||
// Remove items
|
||||
for (int i=0 ; i<count ; ++i)
|
||||
delete items_.takeAt(row);
|
||||
items_.removeAt(row);
|
||||
|
||||
endRemoveRows();
|
||||
|
||||
@ -719,7 +720,7 @@ void Playlist::SetStreamMetadata(const QUrl& url, const Song& song) {
|
||||
if (!current_item_.isValid())
|
||||
return;
|
||||
|
||||
PlaylistItem* item = items_[current_item_.row()];
|
||||
boost::shared_ptr<PlaylistItem> item = items_[current_item_.row()];
|
||||
if (item->Url() != url)
|
||||
return;
|
||||
|
||||
@ -739,7 +740,7 @@ void Playlist::ClearStreamMetadata() {
|
||||
if (!current_item_.isValid())
|
||||
return;
|
||||
|
||||
PlaylistItem* item = items_[current_item_.row()];
|
||||
boost::shared_ptr<PlaylistItem> item = items_[current_item_.row()];
|
||||
item->ClearTemporaryMetadata();
|
||||
UpdateScrobblePoint();
|
||||
|
||||
@ -751,16 +752,16 @@ bool Playlist::stop_after_current() const {
|
||||
stop_after_.row() == current_item_.row();
|
||||
}
|
||||
|
||||
PlaylistItem* Playlist::current_item() const {
|
||||
boost::shared_ptr<PlaylistItem> Playlist::current_item() const {
|
||||
int i = current_index();
|
||||
if (i == -1)
|
||||
return NULL;
|
||||
return boost::shared_ptr<PlaylistItem>();
|
||||
|
||||
return item_at(i);
|
||||
}
|
||||
|
||||
PlaylistItem::Options Playlist::current_item_options() const {
|
||||
PlaylistItem* item = current_item();
|
||||
boost::shared_ptr<PlaylistItem> item = current_item();
|
||||
if (!item)
|
||||
return PlaylistItem::Default;
|
||||
|
||||
@ -768,7 +769,7 @@ PlaylistItem::Options Playlist::current_item_options() const {
|
||||
}
|
||||
|
||||
Song Playlist::current_item_metadata() const {
|
||||
PlaylistItem* item = current_item();
|
||||
boost::shared_ptr<PlaylistItem> item = current_item();
|
||||
if (!item)
|
||||
return Song();
|
||||
|
||||
@ -784,7 +785,6 @@ void Playlist::UpdateScrobblePoint() {
|
||||
}
|
||||
|
||||
void Playlist::Clear() {
|
||||
qDeleteAll(items_);
|
||||
items_.clear();
|
||||
virtual_items_.clear();
|
||||
reset();
|
||||
|
@ -73,7 +73,8 @@ class Playlist : public QAbstractListModel {
|
||||
static const char* kSettingsGroup;
|
||||
|
||||
static bool CompareItems(int column, Qt::SortOrder order,
|
||||
const PlaylistItem* a, const PlaylistItem* b);
|
||||
boost::shared_ptr<PlaylistItem> a,
|
||||
boost::shared_ptr<PlaylistItem> b);
|
||||
|
||||
static QString column_name(Column column);
|
||||
static bool column_is_editable(Playlist::Column column);
|
||||
@ -90,8 +91,8 @@ class Playlist : public QAbstractListModel {
|
||||
int previous_index() const;
|
||||
bool stop_after_current() const;
|
||||
|
||||
PlaylistItem* item_at(int index) const { return items_[index]; }
|
||||
PlaylistItem* current_item() const;
|
||||
const boost::shared_ptr<PlaylistItem>& item_at(int index) const { return items_[index]; }
|
||||
boost::shared_ptr<PlaylistItem> current_item() const;
|
||||
|
||||
PlaylistItem::Options current_item_options() const;
|
||||
Song current_item_metadata() const;
|
||||
|
@ -34,14 +34,14 @@ PlaylistItem* PlaylistItem::NewFromType(const QString& type) {
|
||||
}
|
||||
|
||||
void PlaylistItem::BindToQuery(QSqlQuery* query) const {
|
||||
query->bindValue(":type", type());
|
||||
query->bindValue(":library_id", DatabaseValue(Column_LibraryId));
|
||||
query->bindValue(":url", DatabaseValue(Column_Url));
|
||||
query->bindValue(":title", DatabaseValue(Column_Title));
|
||||
query->bindValue(":artist", DatabaseValue(Column_Artist));
|
||||
query->bindValue(":album", DatabaseValue(Column_Album));
|
||||
query->bindValue(":length", DatabaseValue(Column_Length));
|
||||
query->bindValue(":radio_service", DatabaseValue(Column_RadioService));
|
||||
query->bindValue(1, type());
|
||||
query->bindValue(2, DatabaseValue(Column_LibraryId));
|
||||
query->bindValue(3, DatabaseValue(Column_Url));
|
||||
query->bindValue(4, DatabaseValue(Column_Title));
|
||||
query->bindValue(5, DatabaseValue(Column_Artist));
|
||||
query->bindValue(6, DatabaseValue(Column_Album));
|
||||
query->bindValue(7, DatabaseValue(Column_Length));
|
||||
query->bindValue(8, DatabaseValue(Column_RadioService));
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include <QStandardItem>
|
||||
#include <QUrl>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
class Song;
|
||||
|
||||
class QSqlQuery;
|
||||
@ -81,7 +83,7 @@ class PlaylistItem {
|
||||
|
||||
QString type_;
|
||||
};
|
||||
typedef QList<PlaylistItem*> PlaylistItemList;
|
||||
typedef QList<boost::shared_ptr<PlaylistItem> > PlaylistItemList;
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(PlaylistItem::Options);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user