Store the playlist in the database. This is still quite slow.
This commit is contained in:
parent
dc782cfa5b
commit
af07b5becd
@ -78,5 +78,6 @@
|
||||
<file>schema-6.sql</file>
|
||||
<file>list-add.png</file>
|
||||
<file>document-save.png</file>
|
||||
<file>schema-7.sql</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
26
data/schema-7.sql
Normal file
26
data/schema-7.sql
Normal file
@ -0,0 +1,26 @@
|
||||
CREATE TABLE playlists (
|
||||
name TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE playlist_items (
|
||||
playlist INTEGER NOT NULL,
|
||||
type TEXT NOT NULL, /* Library, Stream, File, or Radio */
|
||||
|
||||
/* Library */
|
||||
library_id INTEGER,
|
||||
|
||||
/* Stream, File or Radio */
|
||||
url TEXT,
|
||||
|
||||
/* Stream or Radio */
|
||||
title TEXT,
|
||||
artist TEXT,
|
||||
album TEXT,
|
||||
length INTEGER,
|
||||
|
||||
/* Radio */
|
||||
radio_service TEXT
|
||||
);
|
||||
|
||||
UPDATE schema_version SET version=7;
|
||||
|
@ -76,6 +76,8 @@ set(CLEMENTINE-SOURCES
|
||||
stickyslider.cpp
|
||||
commandlineoptions.cpp
|
||||
settingsprovider.cpp
|
||||
libraryplaylistitem.cpp
|
||||
scopedtransaction.cpp
|
||||
)
|
||||
|
||||
# Header files that have Q_OBJECT in
|
||||
|
@ -505,7 +505,7 @@ void Library::InitQuery(GroupBy type, LibraryQuery* q) {
|
||||
q->SetColumnSpec("DISTINCT albumartist");
|
||||
break;
|
||||
case GroupBy_None:
|
||||
q->SetColumnSpec("ROWID, " + QString(Song::kColumnSpec));
|
||||
q->SetColumnSpec("ROWID, " + Song::kColumnSpec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "librarybackend.h"
|
||||
#include "libraryquery.h"
|
||||
#include "scopedtransaction.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
@ -32,7 +33,7 @@
|
||||
|
||||
|
||||
const char* LibraryBackend::kDatabaseName = "clementine.db";
|
||||
const int LibraryBackend::kSchemaVersion = 6;
|
||||
const int LibraryBackend::kSchemaVersion = 7;
|
||||
|
||||
int (*LibraryBackend::_sqlite3_create_function) (
|
||||
sqlite3*, const char*, int, int, void*,
|
||||
@ -359,7 +360,7 @@ void LibraryBackend::RemoveDirectory(const Directory& dir) {
|
||||
// Remove songs first
|
||||
DeleteSongs(FindSongsInDirectory(dir.id));
|
||||
|
||||
db.transaction();
|
||||
ScopedTransaction transaction(&db);
|
||||
|
||||
// Delete the subdirs that were in this directory
|
||||
QSqlQuery q("DELETE FROM subdirectories WHERE directory = :id", db);
|
||||
@ -375,13 +376,13 @@ void LibraryBackend::RemoveDirectory(const Directory& dir) {
|
||||
|
||||
emit DirectoryDeleted(dir);
|
||||
|
||||
db.commit();
|
||||
transaction.Commit();
|
||||
}
|
||||
|
||||
SongList LibraryBackend::FindSongsInDirectory(int id) {
|
||||
QSqlDatabase db(Connect());
|
||||
|
||||
QSqlQuery q("SELECT ROWID, " + QString(Song::kColumnSpec) +
|
||||
QSqlQuery q("SELECT ROWID, " + Song::kColumnSpec +
|
||||
" FROM songs WHERE directory = :directory", db);
|
||||
q.bindValue(":directory", id);
|
||||
q.exec();
|
||||
@ -407,7 +408,7 @@ void LibraryBackend::AddOrUpdateSubdirs(const SubdirectoryList& subdirs) {
|
||||
QSqlQuery delete_query("DELETE FROM subdirectories"
|
||||
" WHERE directory = :id AND path = :path", db);
|
||||
|
||||
db.transaction();
|
||||
ScopedTransaction transaction(&db);
|
||||
foreach (const Subdirectory& subdir, subdirs) {
|
||||
if (subdir.mtime == 0) {
|
||||
// Delete the subdirectory
|
||||
@ -437,7 +438,7 @@ void LibraryBackend::AddOrUpdateSubdirs(const SubdirectoryList& subdirs) {
|
||||
}
|
||||
}
|
||||
}
|
||||
db.commit();
|
||||
transaction.Commit();
|
||||
}
|
||||
|
||||
void LibraryBackend::AddOrUpdateSongs(const SongList& songs) {
|
||||
@ -446,13 +447,13 @@ void LibraryBackend::AddOrUpdateSongs(const SongList& songs) {
|
||||
QSqlQuery check_dir(
|
||||
"SELECT ROWID FROM directories WHERE ROWID = :id", db);
|
||||
QSqlQuery add_song(
|
||||
"INSERT INTO songs (" + QString(Song::kColumnSpec) + ")"
|
||||
" VALUES (" + QString(Song::kBindSpec) + ")", db);
|
||||
"INSERT INTO songs (" + Song::kColumnSpec + ")"
|
||||
" VALUES (" + Song::kBindSpec + ")", db);
|
||||
QSqlQuery update_song(
|
||||
"UPDATE songs SET " + QString(Song::kUpdateSpec) +
|
||||
"UPDATE songs SET " + Song::kUpdateSpec +
|
||||
" WHERE ROWID = :id", db);
|
||||
|
||||
db.transaction();
|
||||
ScopedTransaction transaction(&db);
|
||||
|
||||
SongList added_songs;
|
||||
SongList deleted_songs;
|
||||
@ -495,7 +496,7 @@ void LibraryBackend::AddOrUpdateSongs(const SongList& songs) {
|
||||
}
|
||||
}
|
||||
|
||||
db.commit();
|
||||
transaction.Commit();
|
||||
|
||||
if (!deleted_songs.isEmpty())
|
||||
emit SongsDeleted(deleted_songs);
|
||||
@ -511,14 +512,14 @@ void LibraryBackend::UpdateMTimesOnly(const SongList& songs) {
|
||||
|
||||
QSqlQuery q("UPDATE songs SET mtime = :mtime WHERE ROWID = :id", db);
|
||||
|
||||
db.transaction();
|
||||
ScopedTransaction transaction(&db);
|
||||
foreach (const Song& song, songs) {
|
||||
q.bindValue(":mtime", song.mtime());
|
||||
q.bindValue(":id", song.id());
|
||||
q.exec();
|
||||
CheckErrors(q.lastError());
|
||||
}
|
||||
db.commit();
|
||||
transaction.Commit();
|
||||
}
|
||||
|
||||
void LibraryBackend::DeleteSongs(const SongList &songs) {
|
||||
@ -526,13 +527,13 @@ void LibraryBackend::DeleteSongs(const SongList &songs) {
|
||||
|
||||
QSqlQuery q("DELETE FROM songs WHERE ROWID = :id", db);
|
||||
|
||||
db.transaction();
|
||||
ScopedTransaction transaction(&db);
|
||||
foreach (const Song& song, songs) {
|
||||
q.bindValue(":id", song.id());
|
||||
q.exec();
|
||||
CheckErrors(q.lastError());
|
||||
}
|
||||
db.commit();
|
||||
transaction.Commit();
|
||||
|
||||
emit SongsDeleted(songs);
|
||||
|
||||
@ -564,7 +565,7 @@ LibraryBackend::AlbumList LibraryBackend::GetAlbumsByArtist(const QString& artis
|
||||
|
||||
SongList LibraryBackend::GetSongs(const QString& artist, const QString& album, const QueryOptions& opt) {
|
||||
LibraryQuery query(opt);
|
||||
query.SetColumnSpec("ROWID, " + QString(Song::kColumnSpec));
|
||||
query.SetColumnSpec("ROWID, " + Song::kColumnSpec);
|
||||
query.AddCompilationRequirement(false);
|
||||
query.AddWhere("artist", artist);
|
||||
query.AddWhere("album", album);
|
||||
@ -583,7 +584,7 @@ SongList LibraryBackend::GetSongs(const QString& artist, const QString& album, c
|
||||
Song LibraryBackend::GetSongById(int id) {
|
||||
QSqlDatabase db(Connect());
|
||||
|
||||
QSqlQuery q("SELECT ROWID, " + QString(Song::kColumnSpec) + " FROM songs"
|
||||
QSqlQuery q("SELECT ROWID, " + Song::kColumnSpec + " FROM songs"
|
||||
" WHERE ROWID = :id", db);
|
||||
q.bindValue(":id", id);
|
||||
q.exec();
|
||||
@ -612,7 +613,7 @@ LibraryBackend::AlbumList LibraryBackend::GetCompilationAlbums(const QueryOption
|
||||
|
||||
SongList LibraryBackend::GetCompilationSongs(const QString& album, const QueryOptions& opt) {
|
||||
LibraryQuery query(opt);
|
||||
query.SetColumnSpec("ROWID, " + QString(Song::kColumnSpec));
|
||||
query.SetColumnSpec("ROWID, " + Song::kColumnSpec);
|
||||
query.AddCompilationRequirement(true);
|
||||
query.AddWhere("album", album);
|
||||
|
||||
@ -670,13 +671,13 @@ void LibraryBackend::UpdateCompilations() {
|
||||
" SET sampler = :sampler,"
|
||||
" effective_compilation = ((compilation OR :sampler OR forced_compilation_on) AND NOT forced_compilation_off) + 0"
|
||||
" WHERE album = :album", db);
|
||||
QSqlQuery find_songs("SELECT ROWID, " + QString(Song::kColumnSpec) + " FROM songs"
|
||||
QSqlQuery find_songs("SELECT ROWID, " + Song::kColumnSpec + " FROM songs"
|
||||
" WHERE album = :album AND sampler = :sampler", db);
|
||||
|
||||
SongList deleted_songs;
|
||||
SongList added_songs;
|
||||
|
||||
db.transaction();
|
||||
ScopedTransaction transaction(&db);
|
||||
|
||||
QMap<QString, CompilationInfo>::const_iterator it = compilation_info.constBegin();
|
||||
for ( ; it != compilation_info.constEnd() ; ++it) {
|
||||
@ -695,7 +696,7 @@ void LibraryBackend::UpdateCompilations() {
|
||||
}
|
||||
}
|
||||
|
||||
db.commit();
|
||||
transaction.Commit();
|
||||
|
||||
if (!deleted_songs.isEmpty()) {
|
||||
emit SongsDeleted(deleted_songs);
|
||||
@ -821,7 +822,7 @@ void LibraryBackend::ForceCompilation(const QString& artist, const QString& albu
|
||||
|
||||
// Get the songs before they're updated
|
||||
LibraryQuery query;
|
||||
query.SetColumnSpec("ROWID, " + QString(Song::kColumnSpec));
|
||||
query.SetColumnSpec("ROWID, " + Song::kColumnSpec);
|
||||
query.AddWhere("album", album);
|
||||
if (!artist.isNull())
|
||||
query.AddWhere("artist", artist);
|
||||
@ -872,3 +873,71 @@ void LibraryBackend::ForceCompilation(const QString& artist, const QString& albu
|
||||
bool LibraryBackend::ExecQuery(LibraryQuery *q) {
|
||||
return !CheckErrors(q->Exec(Connect()));
|
||||
}
|
||||
|
||||
LibraryBackendInterface::PlaylistList LibraryBackend::GetAllPlaylists() {
|
||||
qWarning() << "Not implemented:" << __PRETTY_FUNCTION__;
|
||||
return PlaylistList();
|
||||
}
|
||||
|
||||
PlaylistItemList LibraryBackend::GetPlaylistItems(int playlist) {
|
||||
QSqlDatabase db(Connect());
|
||||
|
||||
PlaylistItemList ret;
|
||||
|
||||
QSqlQuery q("SELECT songs.ROWID, " + Song::kJoinSpec + ","
|
||||
" p.type, p.url, p.title, p.artist, p.album, p.length,"
|
||||
" p.radio_service"
|
||||
" FROM playlist_items AS p"
|
||||
" LEFT JOIN songs"
|
||||
" ON p.library_id = songs.ROWID"
|
||||
" WHERE p.playlist = :playlist", db);
|
||||
q.bindValue(":playlist", playlist);
|
||||
q.exec();
|
||||
if (CheckErrors(q.lastError()))
|
||||
return ret;
|
||||
|
||||
while (q.next()) {
|
||||
// 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());
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
item->InitFromQuery(q);
|
||||
ret << item;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LibraryBackend::SavePlaylist(int playlist, const PlaylistItemList& items) {
|
||||
QSqlDatabase db(Connect());
|
||||
|
||||
QSqlQuery clear("DELETE FROM playlist_items WHERE playlist = :playlist", db);
|
||||
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);
|
||||
|
||||
ScopedTransaction transaction(&db);
|
||||
|
||||
// Clear the existing items in the playlist
|
||||
clear.exec();
|
||||
if (CheckErrors(clear.lastError()))
|
||||
return;
|
||||
|
||||
// Save the new ones
|
||||
foreach (const PlaylistItem* item, items) {
|
||||
insert.bindValue(":playlist", playlist);
|
||||
item->BindToQuery(&insert);
|
||||
|
||||
insert.exec();
|
||||
CheckErrors(insert.lastError());
|
||||
}
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "directory.h"
|
||||
#include "song.h"
|
||||
#include "libraryquery.h"
|
||||
#include "playlistitem.h"
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
@ -52,6 +53,12 @@ class LibraryBackendInterface : public QObject {
|
||||
};
|
||||
typedef QList<Album> AlbumList;
|
||||
|
||||
struct Playlist {
|
||||
int id;
|
||||
QString name;
|
||||
};
|
||||
typedef QList<Playlist> PlaylistList;
|
||||
|
||||
virtual void Stop() {};
|
||||
|
||||
// Get a list of directories in the library. Emits DirectoriesDiscovered.
|
||||
@ -60,6 +67,7 @@ class LibraryBackendInterface : public QObject {
|
||||
// Counts the songs in the library. Emits TotalSongCountUpdated
|
||||
virtual void UpdateTotalSongCountAsync() = 0;
|
||||
|
||||
// Functions for getting songs
|
||||
virtual SongList FindSongsInDirectory(int id) = 0;
|
||||
virtual SubdirectoryList SubdirsInDirectory(int id) = 0;
|
||||
|
||||
@ -78,12 +86,19 @@ class LibraryBackendInterface : public QObject {
|
||||
|
||||
virtual Song GetSongById(int id) = 0;
|
||||
|
||||
virtual bool ExecQuery(LibraryQuery* q) = 0;
|
||||
|
||||
// Add or remove directories to the library
|
||||
virtual void AddDirectory(const QString& path) = 0;
|
||||
virtual void RemoveDirectory(const Directory& dir) = 0;
|
||||
|
||||
// Update compilation flags on songs
|
||||
virtual void UpdateCompilationsAsync() = 0;
|
||||
|
||||
virtual bool ExecQuery(LibraryQuery* q) = 0;
|
||||
// Functions for getting playlists
|
||||
virtual PlaylistList GetAllPlaylists() = 0;
|
||||
virtual PlaylistItemList GetPlaylistItems(int playlist) = 0;
|
||||
virtual void SavePlaylist(int playlist, const PlaylistItemList& items) = 0;
|
||||
|
||||
public slots:
|
||||
virtual void LoadDirectories() = 0;
|
||||
@ -151,6 +166,10 @@ class LibraryBackend : public LibraryBackendInterface {
|
||||
|
||||
bool ExecQuery(LibraryQuery* q);
|
||||
|
||||
PlaylistList GetAllPlaylists();
|
||||
PlaylistItemList GetPlaylistItems(int playlist);
|
||||
void SavePlaylist(int playlist, const PlaylistItemList& items);
|
||||
|
||||
public slots:
|
||||
void LoadDirectories();
|
||||
void UpdateTotalSongCount();
|
||||
|
52
src/libraryplaylistitem.cpp
Normal file
52
src/libraryplaylistitem.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
/* This file is part of Clementine.
|
||||
|
||||
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 "libraryplaylistitem.h"
|
||||
|
||||
#include <QtDebug>
|
||||
#include <QSettings>
|
||||
|
||||
LibraryPlaylistItem::LibraryPlaylistItem(const QString& type)
|
||||
: PlaylistItem(type)
|
||||
{
|
||||
}
|
||||
|
||||
LibraryPlaylistItem::LibraryPlaylistItem(const Song& song)
|
||||
: PlaylistItem("Library"),
|
||||
song_(song)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QUrl LibraryPlaylistItem::Url() const {
|
||||
return QUrl::fromLocalFile(song_.filename());
|
||||
}
|
||||
|
||||
void LibraryPlaylistItem::Reload() {
|
||||
song_.InitFromFile(song_.filename(), song_.directory_id());
|
||||
}
|
||||
|
||||
void LibraryPlaylistItem::InitFromQuery(const QSqlQuery &query) {
|
||||
// Rows from the songs table come first
|
||||
song_.InitFromQuery(query);
|
||||
}
|
||||
|
||||
QVariant LibraryPlaylistItem::DatabaseValue(DatabaseColumn column) const {
|
||||
switch (column) {
|
||||
case Column_LibraryId: return song_.id();
|
||||
default: return PlaylistItem::DatabaseValue(column);
|
||||
}
|
||||
}
|
43
src/libraryplaylistitem.h
Normal file
43
src/libraryplaylistitem.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* This file is part of Clementine.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef LIBRARYPLAYLISTITEM_H
|
||||
#define LIBRARYPLAYLISTITEM_H
|
||||
|
||||
#include "playlistitem.h"
|
||||
#include "song.h"
|
||||
|
||||
class LibraryPlaylistItem : public PlaylistItem {
|
||||
public:
|
||||
LibraryPlaylistItem(const QString& type);
|
||||
LibraryPlaylistItem(const Song& song);
|
||||
|
||||
void InitFromQuery(const QSqlQuery &query);
|
||||
void BindToQuery(QSqlQuery *query) const;
|
||||
void Reload();
|
||||
|
||||
Song Metadata() const { return song_; }
|
||||
|
||||
QUrl Url() const;
|
||||
|
||||
protected:
|
||||
QVariant DatabaseValue(DatabaseColumn column) const;
|
||||
|
||||
private:
|
||||
Song song_;
|
||||
};
|
||||
|
||||
#endif // LIBRARYPLAYLISTITEM_H
|
@ -120,8 +120,6 @@ MainWindow::MainWindow(QNetworkAccessManager* network, QWidget *parent)
|
||||
library_sort_model_->setDynamicSortFilter(true);
|
||||
library_sort_model_->sort(0);
|
||||
|
||||
playlist_->Restore();
|
||||
|
||||
playlist_->IgnoreSorting(true);
|
||||
ui_.playlist->setModel(playlist_);
|
||||
ui_.playlist->setItemDelegates(library_);
|
||||
@ -226,6 +224,8 @@ MainWindow::MainWindow(QNetworkAccessManager* network, QWidget *parent)
|
||||
connect(library_, SIGNAL(ScanFinished()), SLOT(LibraryScanFinished()));
|
||||
connect(library_, SIGNAL(BackendReady(boost::shared_ptr<LibraryBackendInterface>)),
|
||||
cover_manager_, SLOT(SetBackend(boost::shared_ptr<LibraryBackendInterface>)));
|
||||
connect(library_, SIGNAL(BackendReady(boost::shared_ptr<LibraryBackendInterface>)),
|
||||
playlist_, SLOT(SetBackend(boost::shared_ptr<LibraryBackendInterface>)));
|
||||
|
||||
// Age filters
|
||||
QActionGroup* filter_age_group = new QActionGroup(this);
|
||||
@ -546,7 +546,7 @@ void MainWindow::AddLibraryItemToPlaylist(const QModelIndex& index) {
|
||||
idx = library_sort_model_->mapToSource(idx);
|
||||
|
||||
QModelIndex first_song =
|
||||
playlist_->InsertSongs(library_->GetChildSongs(idx));
|
||||
playlist_->InsertLibraryItems(library_->GetChildSongs(idx));
|
||||
|
||||
if (first_song.isValid() && player_->GetState() != Engine::Playing)
|
||||
player_->PlayAt(first_song.row(), Engine::First);
|
||||
|
@ -331,27 +331,16 @@ inline void AddMetadata(const QString& key, int metadata, QVariantMap* map) {
|
||||
|
||||
QVariantMap Player::GetMetadata(const PlaylistItem& item) const {
|
||||
QVariantMap ret;
|
||||
if (item.type() == PlaylistItem::Type_Song) {
|
||||
|
||||
const Song& song = item.Metadata();
|
||||
if (song.is_valid()) {
|
||||
AddMetadata("location", item.Url().toString(), &ret);
|
||||
AddMetadata("title", song.PrettyTitle(), &ret);
|
||||
AddMetadata("artist", song.artist(), &ret);
|
||||
AddMetadata("album", song.album(), &ret);
|
||||
AddMetadata("time", song.length(), &ret);
|
||||
AddMetadata("tracknumber", song.track(), &ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
AddMetadata("location", item.Url().toString(), &ret);
|
||||
const Song& song = item.Metadata();
|
||||
AddMetadata("title", song.PrettyTitle(), &ret);
|
||||
AddMetadata("artist", song.artist(), &ret);
|
||||
AddMetadata("album", song.album(), &ret);
|
||||
AddMetadata("time", song.length(), &ret);
|
||||
AddMetadata("tracknumber", song.track(), &ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
QVariantMap Player::GetMetadata() const {
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "radioplaylistitem.h"
|
||||
#include "radiomodel.h"
|
||||
#include "savedradio.h"
|
||||
#include "librarybackend.h"
|
||||
#include "libraryplaylistitem.h"
|
||||
|
||||
#include <QtDebug>
|
||||
#include <QMimeData>
|
||||
@ -334,7 +336,7 @@ bool Playlist::dropMimeData(const QMimeData* data, Qt::DropAction action, int ro
|
||||
|
||||
if (const SongMimeData* song_data = qobject_cast<const SongMimeData*>(data)) {
|
||||
// Dragged from the library
|
||||
InsertSongs(song_data->songs, row);
|
||||
InsertLibraryItems(song_data->songs, row);
|
||||
} else if (const RadioMimeData* radio_data = qobject_cast<const RadioMimeData*>(data)) {
|
||||
// Dragged from the Radio pane
|
||||
InsertRadioStations(radio_data->items, row);
|
||||
@ -457,6 +459,14 @@ QModelIndex Playlist::InsertItems(const QList<PlaylistItem*>& items, int after)
|
||||
return index(start, 0);
|
||||
}
|
||||
|
||||
QModelIndex Playlist::InsertLibraryItems(const SongList& songs, int after) {
|
||||
QList<PlaylistItem*> items;
|
||||
foreach (const Song& song, songs) {
|
||||
items << new LibraryPlaylistItem(song);
|
||||
}
|
||||
return InsertItems(items, after);
|
||||
}
|
||||
|
||||
QModelIndex Playlist::InsertSongs(const SongList& songs, int after) {
|
||||
QList<PlaylistItem*> items;
|
||||
foreach (const Song& song, songs) {
|
||||
@ -625,37 +635,34 @@ void Playlist::SetCurrentIsPaused(bool paused) {
|
||||
index(current_item_.row(), ColumnCount));
|
||||
}
|
||||
|
||||
void Playlist::Save() const {
|
||||
settings_->beginWriteArray("items", items_.count());
|
||||
for (int i=0 ; i<items_.count() ; ++i) {
|
||||
settings_->setArrayIndex(i);
|
||||
settings_->setValue("type", items_.at(i)->type_string());
|
||||
items_.at(i)->Save(settings_.get());
|
||||
void Playlist::SetBackend(boost::shared_ptr<LibraryBackendInterface> backend) {
|
||||
backend_ = backend;
|
||||
|
||||
Restore();
|
||||
}
|
||||
settings_->endArray();
|
||||
|
||||
void Playlist::Save() const {
|
||||
if (!backend_)
|
||||
return;
|
||||
|
||||
backend_->SavePlaylist(1, items_);
|
||||
|
||||
settings_->setValue("last_index", last_played_index());
|
||||
}
|
||||
|
||||
void Playlist::Restore() {
|
||||
if (!backend_)
|
||||
return;
|
||||
|
||||
qDeleteAll(items_);
|
||||
items_.clear();
|
||||
virtual_items_.clear();
|
||||
|
||||
int count = settings_->beginReadArray("items");
|
||||
for (int i=0 ; i<count ; ++i) {
|
||||
settings_->setArrayIndex(i);
|
||||
QString type(settings_->value("type").toString());
|
||||
items_ = backend_->GetPlaylistItems(1);
|
||||
|
||||
PlaylistItem* item = PlaylistItem::NewFromType(type);
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
item->Restore(*settings_.get());
|
||||
items_ << item;
|
||||
virtual_items_ << virtual_items_.count();
|
||||
}
|
||||
settings_->endArray();
|
||||
for (int i=0 ; i<items_.count() ; ++i) {
|
||||
virtual_items_ << i;
|
||||
};
|
||||
|
||||
reset();
|
||||
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include <QAbstractItemModel>
|
||||
#include <QList>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "playlistitem.h"
|
||||
#include "song.h"
|
||||
#include "radioitem.h"
|
||||
@ -27,6 +29,7 @@
|
||||
#include "settingsprovider.h"
|
||||
|
||||
class RadioService;
|
||||
class LibraryBackendInterface;
|
||||
|
||||
class Playlist : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
@ -102,7 +105,8 @@ class Playlist : public QAbstractListModel {
|
||||
void set_scrobbled(bool v) { has_scrobbled_ = v; }
|
||||
|
||||
// Changing the playlist
|
||||
QModelIndex InsertItems(const QList<PlaylistItem*>& items, int after = -1);
|
||||
QModelIndex InsertItems(const PlaylistItemList& items, int after = -1);
|
||||
QModelIndex InsertLibraryItems(const SongList& items, int after = -1);
|
||||
QModelIndex InsertSongs(const SongList& items, int after = -1);
|
||||
QModelIndex InsertRadioStations(const QList<RadioItem*>& items, int after = -1);
|
||||
QModelIndex InsertStreamUrls(const QList<QUrl>& urls, int after = -1);
|
||||
@ -126,6 +130,8 @@ class Playlist : public QAbstractListModel {
|
||||
|
||||
|
||||
public slots:
|
||||
void SetBackend(boost::shared_ptr<LibraryBackendInterface>);
|
||||
|
||||
void set_current_index(int index);
|
||||
void Paused();
|
||||
void Playing();
|
||||
@ -155,7 +161,9 @@ class Playlist : public QAbstractListModel {
|
||||
private:
|
||||
boost::scoped_ptr<SettingsProvider> settings_;
|
||||
|
||||
QList<PlaylistItem*> items_;
|
||||
boost::shared_ptr<LibraryBackendInterface> backend_;
|
||||
|
||||
PlaylistItemList items_;
|
||||
QList<int> virtual_items_; // Contains the indices into items_ in the order
|
||||
// that they will be played.
|
||||
|
||||
|
@ -17,25 +17,31 @@
|
||||
#include "playlistitem.h"
|
||||
#include "songplaylistitem.h"
|
||||
#include "radioplaylistitem.h"
|
||||
#include "libraryplaylistitem.h"
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
QString PlaylistItem::type_string() const {
|
||||
switch (type()) {
|
||||
case Type_Song: return "Song";
|
||||
case Type_Radio: return "Radio";
|
||||
default:
|
||||
qWarning() << "Invalid PlaylistItem type:" << type();
|
||||
return QString::null;
|
||||
}
|
||||
}
|
||||
|
||||
PlaylistItem* PlaylistItem::NewFromType(const QString& type) {
|
||||
if (type == "Song")
|
||||
return new SongPlaylistItem;
|
||||
if (type == "Library")
|
||||
return new LibraryPlaylistItem(type);
|
||||
if (type == "Stream" || type == "File")
|
||||
return new SongPlaylistItem(type);
|
||||
if (type == "Radio")
|
||||
return new RadioPlaylistItem;
|
||||
return new RadioPlaylistItem(type);
|
||||
|
||||
qWarning() << "Invalid PlaylistItem type:" << type;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,20 +21,16 @@
|
||||
#include <QUrl>
|
||||
|
||||
class Song;
|
||||
class SettingsProvider;
|
||||
|
||||
class QSqlQuery;
|
||||
|
||||
class PlaylistItem {
|
||||
public:
|
||||
PlaylistItem() {}
|
||||
PlaylistItem(const QString& type) : type_(type) {}
|
||||
virtual ~PlaylistItem() {}
|
||||
|
||||
static PlaylistItem* NewFromType(const QString& type);
|
||||
|
||||
enum Type {
|
||||
Type_Song,
|
||||
Type_Radio,
|
||||
};
|
||||
|
||||
enum Option {
|
||||
Default = 0x00,
|
||||
|
||||
@ -45,13 +41,12 @@ class PlaylistItem {
|
||||
};
|
||||
Q_DECLARE_FLAGS(Options, Option);
|
||||
|
||||
virtual Type type() const = 0;
|
||||
QString type_string() const;
|
||||
virtual QString type() const { return type_; }
|
||||
|
||||
virtual Options options() const { return Default; }
|
||||
|
||||
virtual void Save(SettingsProvider* settings) const = 0;
|
||||
virtual void Restore(const SettingsProvider& settings) = 0;
|
||||
virtual void InitFromQuery(const QSqlQuery& query) = 0;
|
||||
void BindToQuery(QSqlQuery* query) const;
|
||||
virtual void Reload() {}
|
||||
|
||||
virtual Song Metadata() const = 0;
|
||||
@ -69,8 +64,25 @@ class PlaylistItem {
|
||||
|
||||
virtual void SetTemporaryMetadata(const Song& metadata) {Q_UNUSED(metadata)}
|
||||
virtual void ClearTemporaryMetadata() {}
|
||||
|
||||
protected:
|
||||
enum DatabaseColumn {
|
||||
Column_LibraryId,
|
||||
Column_Url,
|
||||
Column_Title,
|
||||
Column_Artist,
|
||||
Column_Album,
|
||||
Column_Length,
|
||||
Column_RadioService,
|
||||
};
|
||||
|
||||
virtual QVariant DatabaseValue(DatabaseColumn) const {
|
||||
return QVariant(QVariant::String); }
|
||||
|
||||
QString type_;
|
||||
};
|
||||
typedef QList<PlaylistItem*> PlaylistItemList;
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(PlaylistItem::Options);
|
||||
|
||||
#endif // PLAYLISTITEM_H
|
||||
|
@ -21,15 +21,18 @@
|
||||
|
||||
#include <QSettings>
|
||||
#include <QApplication>
|
||||
#include <QtDebug>
|
||||
|
||||
RadioPlaylistItem::RadioPlaylistItem()
|
||||
: service_(NULL)
|
||||
RadioPlaylistItem::RadioPlaylistItem(const QString& type)
|
||||
: PlaylistItem(type),
|
||||
service_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
RadioPlaylistItem::RadioPlaylistItem(RadioService* service, const QUrl& url,
|
||||
const QString& title, const QString& artist)
|
||||
: service_(service),
|
||||
: PlaylistItem("Radio"),
|
||||
service_(service),
|
||||
url_(url),
|
||||
title_(title),
|
||||
artist_(artist)
|
||||
@ -37,22 +40,30 @@ RadioPlaylistItem::RadioPlaylistItem(RadioService* service, const QUrl& url,
|
||||
InitMetadata();
|
||||
}
|
||||
|
||||
void RadioPlaylistItem::Save(SettingsProvider* settings) const {
|
||||
settings->setValue("service", service_->name());
|
||||
settings->setValue("url", url_.toString());
|
||||
settings->setValue("title", title_);
|
||||
settings->setValue("artist", artist_);
|
||||
}
|
||||
void RadioPlaylistItem::InitFromQuery(const QSqlQuery &query) {
|
||||
// The song table gets joined first, plus one for the song ROWID
|
||||
const int row = Song::kColumns.count() + 1;
|
||||
|
||||
void RadioPlaylistItem::Restore(const SettingsProvider& settings) {
|
||||
service_ = RadioModel::ServiceByName(settings.value("service").toString());
|
||||
url_ = settings.value("url").toString();
|
||||
title_ = settings.value("title").toString();
|
||||
artist_ = settings.value("artist").toString();
|
||||
url_ = query.value(row + 1).toString();
|
||||
title_ = query.value(row + 2).toString();
|
||||
artist_ = query.value(row + 3).toString();
|
||||
QString service(query.value(row + 6).toString());
|
||||
|
||||
service_ = RadioModel::ServiceByName(service);
|
||||
|
||||
InitMetadata();
|
||||
}
|
||||
|
||||
QVariant RadioPlaylistItem::DatabaseValue(DatabaseColumn column) const {
|
||||
switch (column) {
|
||||
case Column_Url: return url_.toString();
|
||||
case Column_Title: return title_;
|
||||
case Column_Artist: return artist_;
|
||||
case Column_RadioService: return service_->name();
|
||||
default: return PlaylistItem::DatabaseValue(column);
|
||||
}
|
||||
}
|
||||
|
||||
void RadioPlaylistItem::InitMetadata() {
|
||||
if (!service_)
|
||||
metadata_.set_title(QApplication::translate("RadioPlaylistItem", "Radio service couldn't be loaded :-("));
|
||||
|
@ -26,15 +26,14 @@ class RadioService;
|
||||
|
||||
class RadioPlaylistItem : public PlaylistItem {
|
||||
public:
|
||||
RadioPlaylistItem();
|
||||
RadioPlaylistItem(const QString& type);
|
||||
RadioPlaylistItem(RadioService* service, const QUrl& url,
|
||||
const QString& title, const QString& artist);
|
||||
|
||||
Type type() const { return Type_Radio; }
|
||||
Options options() const;
|
||||
|
||||
void Save(SettingsProvider* settings) const;
|
||||
void Restore(const SettingsProvider& settings);
|
||||
void InitFromQuery(const QSqlQuery &query);
|
||||
void BindToQuery(QSqlQuery *query) const;
|
||||
|
||||
Song Metadata() const;
|
||||
|
||||
@ -46,6 +45,9 @@ class RadioPlaylistItem : public PlaylistItem {
|
||||
void SetTemporaryMetadata(const Song& metadata);
|
||||
void ClearTemporaryMetadata();
|
||||
|
||||
protected:
|
||||
QVariant DatabaseValue(DatabaseColumn) const;
|
||||
|
||||
private:
|
||||
void InitMetadata();
|
||||
|
||||
|
43
src/scopedtransaction.cpp
Normal file
43
src/scopedtransaction.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/* This file is part of Clementine.
|
||||
|
||||
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 "scopedtransaction.h"
|
||||
|
||||
#include <QSqlDatabase>
|
||||
#include <QtDebug>
|
||||
|
||||
ScopedTransaction::ScopedTransaction(QSqlDatabase* db)
|
||||
: db_(db),
|
||||
pending_(true)
|
||||
{
|
||||
}
|
||||
|
||||
ScopedTransaction::~ScopedTransaction() {
|
||||
if (pending_) {
|
||||
qDebug() << __PRETTY_FUNCTION__ << "Rolling back transaction";
|
||||
db_->rollback();
|
||||
}
|
||||
}
|
||||
|
||||
void ScopedTransaction::Commit() {
|
||||
if (!pending_) {
|
||||
qWarning() << "Tried to commit a ScopedTransaction twice";
|
||||
return;
|
||||
}
|
||||
|
||||
db_->commit();
|
||||
pending_ = false;
|
||||
}
|
39
src/scopedtransaction.h
Normal file
39
src/scopedtransaction.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* This file is part of Clementine.
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef SCOPEDTRANSACTION_H
|
||||
#define SCOPEDTRANSACTION_H
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
class QSqlDatabase;
|
||||
|
||||
// Opens a transaction on a database.
|
||||
// Rolls back the transaction if the object goes out of scope before Commit()
|
||||
// is called.
|
||||
class ScopedTransaction : boost::noncopyable {
|
||||
public:
|
||||
ScopedTransaction(QSqlDatabase* db);
|
||||
~ScopedTransaction();
|
||||
|
||||
void Commit();
|
||||
|
||||
private:
|
||||
QSqlDatabase* db_;
|
||||
bool pending_;
|
||||
};
|
||||
|
||||
#endif // SCOPEDTRANSACTION_H
|
54
src/song.cpp
54
src/song.cpp
@ -53,35 +53,35 @@ using boost::scoped_ptr;
|
||||
#include "engines/enginebase.h"
|
||||
#include "albumcoverloader.h"
|
||||
|
||||
const char* Song::kColumnSpec =
|
||||
"title, album, artist, albumartist, composer, "
|
||||
"track, disc, bpm, year, genre, comment, compilation, "
|
||||
"length, bitrate, samplerate, directory, filename, "
|
||||
"mtime, ctime, filesize, sampler, art_automatic, art_manual, "
|
||||
"filetype, playcount, lastplayed, rating, forced_compilation_on, "
|
||||
"forced_compilation_off, effective_compilation";
|
||||
static QStringList Prepend(const QString& text, const QStringList& list) {
|
||||
QStringList ret(list);
|
||||
for (int i=0 ; i<ret.count() ; ++i)
|
||||
ret[i].prepend(text);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static QStringList Updateify(const QStringList& list) {
|
||||
QStringList ret(list);
|
||||
for (int i=0 ; i<ret.count() ; ++i)
|
||||
ret[i].prepend(ret[i] + " = :");
|
||||
return ret;
|
||||
}
|
||||
|
||||
const QStringList Song::kColumns = QStringList()
|
||||
<< "title" << "album" << "artist" << "albumartist" << "composer" << "track"
|
||||
<< "disc" << "bpm" << "year" << "genre" << "comment" << "compilation"
|
||||
<< "length" << "bitrate" << "samplerate" << "directory" << "filename"
|
||||
<< "mtime" << "ctime" << "filesize" << "sampler" << "art_automatic"
|
||||
<< "art_manual" << "filetype" << "playcount" << "lastplayed" << "rating"
|
||||
<< "forced_compilation_on" << "forced_compilation_off"
|
||||
<< "effective_compilation";
|
||||
|
||||
const QString Song::kColumnSpec = Song::kColumns.join(", ");
|
||||
const QString Song::kJoinSpec = Prepend("songs.", Song::kColumns).join(", ");
|
||||
const QString Song::kBindSpec = Prepend(":", Song::kColumns).join(", ");
|
||||
const QString Song::kUpdateSpec = Updateify(Song::kColumns).join(", ");
|
||||
|
||||
const char* Song::kBindSpec =
|
||||
":title, :album, :artist, :albumartist, :composer, "
|
||||
":track, :disc, :bpm, :year, :genre, :comment, :compilation, "
|
||||
":length, :bitrate, :samplerate, :directory_id, :filename, "
|
||||
":mtime, :ctime, :filesize, :sampler, :art_automatic, :art_manual, "
|
||||
":filetype, :playcount, :lastplayed, :rating, :forced_compilation_on, "
|
||||
":forced_compilation_off, :effective_compilation";
|
||||
|
||||
const char* Song::kUpdateSpec =
|
||||
"title = :title, album = :album, artist = :artist, "
|
||||
"albumartist = :albumartist, composer = :composer, track = :track, "
|
||||
"disc = :disc, bpm = :bpm, year = :year, genre = :genre, "
|
||||
"comment = :comment, compilation = :compilation, length = :length, "
|
||||
"bitrate = :bitrate, samplerate = :samplerate, "
|
||||
"directory = :directory_id, filename = :filename, mtime = :mtime, "
|
||||
"ctime = :ctime, filesize = :filesize, sampler = :sampler, "
|
||||
"art_automatic = :art_automatic, art_manual = :art_manual, "
|
||||
"filetype = :filetype, playcount = :playcount, lastplayed = :lastplayed, "
|
||||
"rating = :rating, forced_compilation_on = :forced_compilation_on, "
|
||||
"forced_compilation_off = :forced_compilation_off, "
|
||||
"effective_compilation = :effective_compilation";
|
||||
|
||||
static TagLib::String QStringToTaglibString(const QString& s);
|
||||
|
||||
|
@ -56,9 +56,11 @@ class Song {
|
||||
Song(const Song& other);
|
||||
Song(FileRefFactory* factory);
|
||||
|
||||
static const char* kColumnSpec;
|
||||
static const char* kBindSpec;
|
||||
static const char* kUpdateSpec;
|
||||
static const QStringList kColumns;
|
||||
static const QString kColumnSpec;
|
||||
static const QString kJoinSpec;
|
||||
static const QString kBindSpec;
|
||||
static const QString kUpdateSpec;
|
||||
|
||||
// Don't change these values - they're stored in the database
|
||||
enum FileType {
|
||||
|
@ -15,74 +15,56 @@
|
||||
*/
|
||||
|
||||
#include "songplaylistitem.h"
|
||||
#include "settingsprovider.h"
|
||||
|
||||
#include <QtDebug>
|
||||
#include <QFile>
|
||||
#include <QSettings>
|
||||
|
||||
SongPlaylistItem::SongPlaylistItem()
|
||||
SongPlaylistItem::SongPlaylistItem(const QString& type)
|
||||
: PlaylistItem(type)
|
||||
{
|
||||
}
|
||||
|
||||
SongPlaylistItem::SongPlaylistItem(const Song& song)
|
||||
: song_(song)
|
||||
: PlaylistItem(song.filetype() == Song::Type_Stream ? "Stream" : "File"),
|
||||
song_(song)
|
||||
{
|
||||
}
|
||||
|
||||
void SongPlaylistItem::Save(SettingsProvider* settings) const {
|
||||
settings->setValue("filename", song_.filename());
|
||||
settings->setValue("art_automatic", song_.art_automatic());
|
||||
settings->setValue("art_manual", song_.art_manual());
|
||||
void SongPlaylistItem::InitFromQuery(const QSqlQuery &query) {
|
||||
// The song table gets joined first, plus one for the song ROWID
|
||||
const int row = Song::kColumns.count() + 1;
|
||||
|
||||
if (song_.filetype() == Song::Type_Stream) {
|
||||
SaveStream(settings);
|
||||
} else {
|
||||
SaveFile(settings);
|
||||
}
|
||||
}
|
||||
QString filename(query.value(row + 1).toString());
|
||||
|
||||
void SongPlaylistItem::SaveFile(SettingsProvider* settings) const {
|
||||
settings->setValue("stream", false);
|
||||
settings->setValue("library_directory", song_.directory_id());
|
||||
}
|
||||
if (type() == "Stream") {
|
||||
QString title(query.value(row + 2).toString());
|
||||
QString artist(query.value(row + 3).toString());
|
||||
QString album(query.value(row + 4).toString());
|
||||
int length(query.value(row + 5).toInt());
|
||||
if (title.isEmpty()) title = "Unknown";
|
||||
if (artist.isEmpty()) artist = "Unknown";
|
||||
if (album.isEmpty()) album = "Unknown";
|
||||
if (length == 0) length = -1;
|
||||
|
||||
void SongPlaylistItem::SaveStream(SettingsProvider* settings) const {
|
||||
settings->setValue("stream", true);
|
||||
settings->setValue("title", song_.title());
|
||||
settings->setValue("artist", song_.artist());
|
||||
settings->setValue("album", song_.album());
|
||||
settings->setValue("length", song_.length());
|
||||
}
|
||||
|
||||
void SongPlaylistItem::Restore(const SettingsProvider& settings) {
|
||||
song_.set_art_automatic(settings.value("art_automatic").toString());
|
||||
song_.set_art_manual(settings.value("art_manual").toString());
|
||||
|
||||
const bool stream = settings.value("stream", false).toBool();
|
||||
if (stream) {
|
||||
RestoreStream(settings);
|
||||
} else {
|
||||
RestoreFile(settings);
|
||||
}
|
||||
}
|
||||
|
||||
void SongPlaylistItem::RestoreFile(const SettingsProvider& settings) {
|
||||
QString filename(settings.value("filename").toString());
|
||||
|
||||
int directory_id(settings.value("library_directory", -1).toInt());
|
||||
song_.InitFromFile(filename, directory_id);
|
||||
}
|
||||
|
||||
void SongPlaylistItem::RestoreStream(const SettingsProvider& settings) {
|
||||
QString filename(settings.value("filename").toString());
|
||||
song_.set_filename(filename);
|
||||
song_.set_filetype(Song::Type_Stream);
|
||||
|
||||
song_.Init(settings.value("title", "Unknown").toString(),
|
||||
settings.value("artist", "Unknown").toString(),
|
||||
settings.value("album", "Unknown").toString(),
|
||||
settings.value("length", -1).toInt());
|
||||
song_.Init(title, artist, album, length);
|
||||
} else {
|
||||
song_.InitFromFile(filename, -1);
|
||||
}
|
||||
}
|
||||
|
||||
QVariant SongPlaylistItem::DatabaseValue(DatabaseColumn column) const {
|
||||
switch (column) {
|
||||
case Column_Url: return song_.filename();
|
||||
case Column_Title: return song_.title();
|
||||
case Column_Artist: return song_.artist();
|
||||
case Column_Album: return song_.album();
|
||||
case Column_Length: return song_.length();
|
||||
default: return PlaylistItem::DatabaseValue(column);
|
||||
}
|
||||
}
|
||||
|
||||
QUrl SongPlaylistItem::Url() const {
|
||||
|
@ -22,25 +22,20 @@
|
||||
|
||||
class SongPlaylistItem : public PlaylistItem {
|
||||
public:
|
||||
SongPlaylistItem();
|
||||
SongPlaylistItem(const QString& type);
|
||||
SongPlaylistItem(const Song& song);
|
||||
|
||||
Type type() const { return Type_Song; }
|
||||
|
||||
void Save(SettingsProvider* settings) const;
|
||||
void Restore(const SettingsProvider& settings);
|
||||
void InitFromQuery(const QSqlQuery &query);
|
||||
void Reload();
|
||||
|
||||
Song Metadata() const { return song_; }
|
||||
|
||||
QUrl Url() const;
|
||||
|
||||
private:
|
||||
void SaveFile(SettingsProvider* settings) const;
|
||||
void SaveStream(SettingsProvider* settings) const;
|
||||
protected:
|
||||
QVariant DatabaseValue(DatabaseColumn) const;
|
||||
|
||||
void RestoreFile(const SettingsProvider& settings);
|
||||
void RestoreStream(const SettingsProvider& settings);
|
||||
private:
|
||||
Song song_;
|
||||
};
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
using ::testing::_;
|
||||
using ::testing::Return;
|
||||
|
||||
MockPlaylistItem::MockPlaylistItem() {
|
||||
EXPECT_CALL(*this, Save(_))
|
||||
.WillRepeatedly(Return());
|
||||
MockPlaylistItem::MockPlaylistItem()
|
||||
: PlaylistItem("DummyType")
|
||||
{
|
||||
}
|
||||
|
@ -27,14 +27,10 @@ class MockPlaylistItem : public PlaylistItem {
|
||||
public:
|
||||
MockPlaylistItem();
|
||||
|
||||
MOCK_CONST_METHOD0(type,
|
||||
Type());
|
||||
MOCK_CONST_METHOD0(options,
|
||||
Options());
|
||||
MOCK_CONST_METHOD1(Save,
|
||||
void(SettingsProvider* settings));
|
||||
MOCK_METHOD1(Restore,
|
||||
void(const SettingsProvider& settings));
|
||||
MOCK_METHOD1(InitFromQuery,
|
||||
void(const QSqlQuery& settings));
|
||||
MOCK_METHOD0(Reload,
|
||||
void());
|
||||
MOCK_CONST_METHOD0(Metadata,
|
||||
@ -49,6 +45,8 @@ class MockPlaylistItem : public PlaylistItem {
|
||||
void(const Song& metadata));
|
||||
MOCK_METHOD0(ClearTemporaryMetadata,
|
||||
void());
|
||||
MOCK_METHOD1(DatabaseValue,
|
||||
QVariant(DatabaseColumn));
|
||||
};
|
||||
|
||||
#endif // MOCK_PLAYLISTITEM_H
|
||||
|
@ -47,8 +47,6 @@ class PlaylistTest : public ::testing::Test {
|
||||
metadata.Init(title, artist, album, length);
|
||||
|
||||
MockPlaylistItem* ret = new MockPlaylistItem;
|
||||
EXPECT_CALL(*ret, type())
|
||||
.WillRepeatedly(Return(PlaylistItem::Type_Song));
|
||||
EXPECT_CALL(*ret, Metadata())
|
||||
.WillRepeatedly(Return(metadata));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user