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:
David Sansome 2010-04-14 22:05:41 +00:00
parent b16f789ac7
commit 72cbf90689
8 changed files with 64 additions and 53 deletions

View File

@ -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();

View File

@ -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 {

View File

@ -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");

View File

@ -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);
}

View File

@ -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();

View File

@ -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;

View File

@ -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));
}

View File

@ -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);