From 72cbf90689c5985f443fe626bd3641f6bc36f0d1 Mon Sep 17 00:00:00 2001 From: David Sansome Date: Wed, 14 Apr 2010 22:05:41 +0000 Subject: [PATCH] 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. --- src/librarybackend.cpp | 19 ++++++++------ src/librarybackend.h | 6 +++-- src/main.cpp | 1 + src/player.cpp | 8 +++--- src/playlist.cpp | 56 +++++++++++++++++++++--------------------- src/playlist.h | 7 +++--- src/playlistitem.cpp | 16 ++++++------ src/playlistitem.h | 4 ++- 8 files changed, 64 insertions(+), 53 deletions(-) diff --git a/src/librarybackend.cpp b/src/librarybackend.cpp index b44f2c5a4..fd8183f48 100644 --- a/src/librarybackend.cpp +++ b/src/librarybackend.cpp @@ -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 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 item, items) { + insert.bindValue(0, playlist); item->BindToQuery(&insert); insert.exec(); diff --git a/src/librarybackend.h b/src/librarybackend.h index 45aaca5ba..0ae4b0b15 100644 --- a/src/librarybackend.h +++ b/src/librarybackend.h @@ -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 { diff --git a/src/main.cpp b/src/main.cpp index 8df9b90a2..588178be5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -85,6 +85,7 @@ int main(int argc, char *argv[]) { qRegisterMetaType("Subdirectory"); qRegisterMetaType("SubdirectoryList"); qRegisterMetaType("SongList"); + qRegisterMetaType("PlaylistItemList"); qRegisterMetaType("Engine::State"); qRegisterMetaType("Equalizer::Params"); qRegisterMetaTypeStreamOperators("Equalizer::Params"); diff --git a/src/player.cpp b/src/player.cpp index 10c5eb5a6..0ad4e2a07 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -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 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 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 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 item = playlist_->current_item(); if (item) { return GetMetadata(*item); } diff --git a/src/playlist.cpp b/src/playlist.cpp index 41a3d0cc6..72f2f1b07 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -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& 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 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 urls, int after) { return InsertSongs(songs, after); } -QModelIndex Playlist::InsertItems(const QList& 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& items, int after) } QModelIndex Playlist::InsertLibraryItems(const SongList& songs, int after) { - QList items; + PlaylistItemList items; foreach (const Song& song, songs) { - items << new LibraryPlaylistItem(song); + items << boost::shared_ptr(new LibraryPlaylistItem(song)); } return InsertItems(items, after); } QModelIndex Playlist::InsertSongs(const SongList& songs, int after) { - QList items; + PlaylistItemList items; foreach (const Song& song, songs) { - items << new SongPlaylistItem(song); + items << boost::shared_ptr(new SongPlaylistItem(song)); } return InsertItems(items, after); } QModelIndex Playlist::InsertRadioStations(const QList& items, int after) { - QList 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( + new RadioPlaylistItem(item->service, item->Url(), item->Title(), item->Artist())); } return InsertItems(playlist_items, after); } QModelIndex Playlist::InsertStreamUrls(const QList& urls, int after) { - QList 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(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 _a, + boost::shared_ptr _b) { + boost::shared_ptr a = order == Qt::AscendingOrder ? _a : _b; + boost::shared_ptr 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 old_persistent_mappings; + QMap > 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 it(old_persistent_mappings); + QMapIterator > it(old_persistent_mappings); while (it.hasNext()) { it.next(); for (int col=0 ; colSavePlaylist(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 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 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 Playlist::current_item() const { int i = current_index(); if (i == -1) - return NULL; + return boost::shared_ptr(); return item_at(i); } PlaylistItem::Options Playlist::current_item_options() const { - PlaylistItem* item = current_item(); + boost::shared_ptr 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 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(); diff --git a/src/playlist.h b/src/playlist.h index 760e8abea..a778c7c3f 100644 --- a/src/playlist.h +++ b/src/playlist.h @@ -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 a, + boost::shared_ptr 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& item_at(int index) const { return items_[index]; } + boost::shared_ptr current_item() const; PlaylistItem::Options current_item_options() const; Song current_item_metadata() const; diff --git a/src/playlistitem.cpp b/src/playlistitem.cpp index a93cba584..b0da9c3c8 100644 --- a/src/playlistitem.cpp +++ b/src/playlistitem.cpp @@ -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)); } diff --git a/src/playlistitem.h b/src/playlistitem.h index 391efe508..02d835bfb 100644 --- a/src/playlistitem.h +++ b/src/playlistitem.h @@ -20,6 +20,8 @@ #include #include +#include + class Song; class QSqlQuery; @@ -81,7 +83,7 @@ class PlaylistItem { QString type_; }; -typedef QList PlaylistItemList; +typedef QList > PlaylistItemList; Q_DECLARE_OPERATORS_FOR_FLAGS(PlaylistItem::Options);