diff --git a/data/data.qrc b/data/data.qrc
index d82d2194b..22edaf759 100644
--- a/data/data.qrc
+++ b/data/data.qrc
@@ -62,5 +62,7 @@
schema-1.sql
schema-2.sql
nocover.png
+ view-choose.png
+ download.png
diff --git a/data/download.png b/data/download.png
new file mode 100644
index 000000000..458890be1
Binary files /dev/null and b/data/download.png differ
diff --git a/data/view-choose.png b/data/view-choose.png
new file mode 100644
index 000000000..c0fa58ecf
Binary files /dev/null and b/data/view-choose.png differ
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 93eb15aef..f90b23417 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -52,6 +52,8 @@ set(CLEMENTINE-SOURCES
savedradio.cpp
stylesheetloader.cpp
shortcutsdialog.cpp
+ albumcovermanager.cpp
+ albumcoverloader.cpp
)
# Header files that have Q_OBJECT in
@@ -96,6 +98,8 @@ set(CLEMENTINE-MOC-HEADERS
addstreamdialog.h
savedradio.h
shortcutsdialog.h
+ albumcovermanager.h
+ albumcoverloader.h
)
# UI files
@@ -114,6 +118,7 @@ set(CLEMENTINE-UI
about.ui
addstreamdialog.ui
shortcutsdialog.ui
+ albumcovermanager.ui
)
# Resource files
diff --git a/src/albumcoverloader.cpp b/src/albumcoverloader.cpp
new file mode 100644
index 000000000..9af885427
--- /dev/null
+++ b/src/albumcoverloader.cpp
@@ -0,0 +1,70 @@
+#include "albumcoverloader.h"
+
+#include
+
+AlbumCoverLoader::AlbumCoverLoader(QObject* parent)
+ : QObject(parent),
+ height_(120),
+ next_id_(0)
+{
+}
+
+void AlbumCoverLoader::Clear() {
+ QMutexLocker l(&mutex_);
+ tasks_.clear();
+}
+
+quint64 AlbumCoverLoader::LoadImageAsync(const QString& art_automatic,
+ const QString& art_manual) {
+ Task task;
+ task.art_automatic = art_automatic;
+ task.art_manual = art_manual;
+
+ {
+ QMutexLocker l(&mutex_);
+ task.id = next_id_ ++;
+ tasks_.enqueue(task);
+ }
+
+ metaObject()->invokeMethod(this, "ProcessTasks", Qt::QueuedConnection);
+
+ return task.id;
+}
+
+void AlbumCoverLoader::ProcessTasks() {
+ forever {
+ // Get the next task
+ Task task;
+ {
+ QMutexLocker l(&mutex_);
+ if (tasks_.isEmpty())
+ return;
+ task = tasks_.dequeue();
+ }
+
+ // Try to load the image
+ QImage image;
+ if (!task.art_manual.isEmpty())
+ image.load(task.art_manual);
+ if (!task.art_automatic.isEmpty() && image.isNull())
+ image.load(task.art_automatic);
+
+ if (!image.isNull()) {
+ // Scale the image down
+ image = image.scaled(QSize(height_, height_), Qt::KeepAspectRatio, Qt::SmoothTransformation);
+
+ // Pad the image to height_ x height_
+ QImage bigger_image(height_, height_, QImage::Format_ARGB32);
+ bigger_image.fill(0);
+
+ QPainter p(&bigger_image);
+ p.drawImage((height_ - image.width()) / 2, (height_ - image.height()) / 2,
+ image);
+ p.end();
+
+ image = bigger_image;
+ }
+
+ emit ImageLoaded(task.id, image);
+ }
+}
diff --git a/src/albumcoverloader.h b/src/albumcoverloader.h
new file mode 100644
index 000000000..9e1958d35
--- /dev/null
+++ b/src/albumcoverloader.h
@@ -0,0 +1,42 @@
+#ifndef ALBUMCOVERLOADER_H
+#define ALBUMCOVERLOADER_H
+
+#include "backgroundthread.h"
+
+#include
+#include
+#include
+#include
+
+class AlbumCoverLoader : public QObject {
+ Q_OBJECT
+
+ public:
+ AlbumCoverLoader(QObject* parent = 0);
+
+ void SetDesiredHeight(int height) { height_ = height; }
+ quint64 LoadImageAsync(const QString& art_automatic, const QString& art_manual);
+
+ void Clear();
+
+ signals:
+ void ImageLoaded(quint64 id, const QImage& image);
+
+ private slots:
+ void ProcessTasks();
+
+ private:
+ struct Task {
+ quint64 id;
+ QString art_automatic;
+ QString art_manual;
+ };
+
+ int height_;
+
+ QMutex mutex_;
+ QQueue tasks_;
+ quint64 next_id_;
+};
+
+#endif // ALBUMCOVERLOADER_H
diff --git a/src/albumcovermanager.cpp b/src/albumcovermanager.cpp
new file mode 100644
index 000000000..e697df934
--- /dev/null
+++ b/src/albumcovermanager.cpp
@@ -0,0 +1,160 @@
+#include "albumcovermanager.h"
+#include "librarybackend.h"
+#include "libraryquery.h"
+
+#include
+#include
+#include
+#include
+
+const char* AlbumCoverManager::kSettingsGroup = "CoverManager";
+
+AlbumCoverManager::AlbumCoverManager(QWidget *parent)
+ : QDialog(parent),
+ cover_loader_(new BackgroundThread(this)),
+ artist_icon_(":/artist.png"),
+ all_artists_icon_(":/album.png")
+{
+ ui_.setupUi(this);
+
+ // Get a square version of nocover.png
+ QImage nocover(":/nocover.png");
+ nocover = nocover.scaled(120, 120, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ QImage square_nocover(120, 120, QImage::Format_ARGB32);
+ square_nocover.fill(0);
+ QPainter p(&square_nocover);
+ p.drawImage((120 - nocover.width()) / 2, (120 - nocover.height()) / 2, nocover);
+ p.end();
+ no_cover_icon_ = QPixmap::fromImage(square_nocover);
+
+ // View menu
+ QActionGroup* filter_group = new QActionGroup(this);
+ filter_all_ = filter_group->addAction("All albums");
+ filter_with_covers_ = filter_group->addAction("Albums with covers");
+ filter_without_covers_ = filter_group->addAction("Albums without covers");
+ filter_all_->setCheckable(true);
+ filter_with_covers_->setCheckable(true);
+ filter_without_covers_->setCheckable(true);
+ filter_group->setExclusive(true);
+ filter_all_->setChecked(true);
+
+ QMenu* view_menu = new QMenu(this);
+ view_menu->addActions(filter_group->actions());
+
+ ui_.view->setMenu(view_menu);
+
+ // Connections
+ connect(cover_loader_, SIGNAL(Initialised()), SLOT(CoverLoaderInitialised()));
+ connect(ui_.artists, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
+ SLOT(ArtistChanged(QListWidgetItem*)));
+ connect(ui_.filter, SIGNAL(textChanged(QString)), SLOT(UpdateFilter()));
+ connect(filter_group, SIGNAL(triggered(QAction*)), SLOT(UpdateFilter()));
+ connect(ui_.view, SIGNAL(clicked()), ui_.view, SLOT(showMenu()));
+
+ // Restore settings
+ QSettings s;
+ s.beginGroup(kSettingsGroup);
+
+ restoreGeometry(s.value("geometry").toByteArray());
+ if (!ui_.splitter->restoreState(s.value("splitter_state").toByteArray())) {
+ // Sensible default size for the artists view
+ ui_.splitter->setSizes(QList() << 200 << width() - 200);
+ }
+
+ cover_loader_->start();
+}
+
+void AlbumCoverManager::CoverLoaderInitialised() {
+ connect(cover_loader_->Worker().get(), SIGNAL(ImageLoaded(quint64,QImage)),
+ SLOT(CoverImageLoaded(quint64,QImage)));
+}
+
+void AlbumCoverManager::SetBackend(boost::shared_ptr backend) {
+ backend_ = backend;
+
+ if (isVisible())
+ Reset();
+}
+
+void AlbumCoverManager::showEvent(QShowEvent *) {
+ Reset();
+}
+
+void AlbumCoverManager::closeEvent(QCloseEvent *) {
+ QSettings s;
+ s.beginGroup(kSettingsGroup);
+
+ s.setValue("geometry", saveGeometry());
+ s.setValue("splitter_state", ui_.splitter->saveState());
+}
+
+void AlbumCoverManager::Reset() {
+ if (!backend_)
+ return;
+
+ ui_.artists->clear();
+ new QListWidgetItem(all_artists_icon_, "All artists", ui_.artists, All_Artists);
+
+ foreach (const QString& artist, backend_->GetAllArtists()) {
+ if (artist.isEmpty())
+ continue;
+
+ new QListWidgetItem(artist_icon_, artist, ui_.artists, Specific_Artist);
+ }
+}
+
+void AlbumCoverManager::ArtistChanged(QListWidgetItem* current) {
+ if (!backend_ || !cover_loader_->Worker())
+ return;
+ if (!current)
+ return;
+
+ QString artist;
+ if (current->type() == Specific_Artist)
+ artist = current->text();
+
+ ui_.albums->clear();
+ cover_loading_tasks_.clear();
+ cover_loader_->Worker()->Clear();
+
+ foreach (const LibraryBackend::AlbumArtInfo& info, backend_->GetAlbumArtInfo(artist)) {
+ QListWidgetItem* item = new QListWidgetItem(no_cover_icon_, info.album_name, ui_.albums);
+
+ if (!info.art_automatic.isEmpty() || !info.art_manual.isEmpty()) {
+ quint64 id = cover_loader_->Worker()->LoadImageAsync(
+ info.art_automatic, info.art_manual);
+ cover_loading_tasks_[id] = item;
+ }
+ }
+
+ UpdateFilter();
+}
+
+void AlbumCoverManager::CoverImageLoaded(quint64 id, const QImage &image) {
+ if (!cover_loading_tasks_.contains(id))
+ return;
+
+ QListWidgetItem* item = cover_loading_tasks_.take(id);
+
+ if (image.isNull())
+ return;
+
+ item->setIcon(QPixmap::fromImage(image));
+ UpdateFilter();
+}
+
+void AlbumCoverManager::UpdateFilter() {
+ const QString filter = ui_.filter->text().toLower();
+ const bool hide_with_covers = filter_without_covers_->isChecked();
+ const bool hide_without_covers = filter_with_covers_->isChecked();
+
+ for (int i=0 ; icount() ; ++i) {
+ QListWidgetItem* item = ui_.albums->item(i);
+ QString text = item->text();
+ bool has_cover = item->icon().cacheKey() != no_cover_icon_.cacheKey();
+
+ item->setHidden((!filter.isEmpty() && !text.toLower().contains(filter)) ||
+ (has_cover && hide_with_covers) ||
+ (!has_cover && hide_without_covers));
+ }
+}
diff --git a/src/albumcovermanager.h b/src/albumcovermanager.h
new file mode 100644
index 000000000..87fef13ec
--- /dev/null
+++ b/src/albumcovermanager.h
@@ -0,0 +1,59 @@
+#ifndef ALBUMCOVERMANAGER_H
+#define ALBUMCOVERMANAGER_H
+
+#include
+#include
+
+#include
+
+#include "ui_covermanager.h"
+#include "backgroundthread.h"
+#include "albumcoverloader.h"
+
+class LibraryBackend;
+
+class AlbumCoverManager : public QDialog {
+ Q_OBJECT
+ public:
+ AlbumCoverManager(QWidget *parent = 0);
+
+ static const char* kSettingsGroup;
+
+ void Reset();
+
+ public slots:
+ void SetBackend(boost::shared_ptr backend);
+
+ protected:
+ void showEvent(QShowEvent *);
+ void closeEvent(QCloseEvent *);
+
+ private slots:
+ void ArtistChanged(QListWidgetItem* current);
+ void CoverLoaderInitialised();
+ void CoverImageLoaded(quint64 id, const QImage& image);
+ void UpdateFilter();
+
+ private:
+ enum ArtistItemType {
+ All_Artists,
+ Specific_Artist,
+ };
+
+ private:
+ Ui::CoverManager ui_;
+ boost::shared_ptr backend_;
+
+ QAction* filter_all_;
+ QAction* filter_with_covers_;
+ QAction* filter_without_covers_;
+
+ BackgroundThread* cover_loader_;
+ QMap cover_loading_tasks_;
+
+ QIcon artist_icon_;
+ QIcon all_artists_icon_;
+ QIcon no_cover_icon_;
+};
+
+#endif // ALBUMCOVERMANAGER_H
diff --git a/src/albumcovermanager.ui b/src/albumcovermanager.ui
new file mode 100644
index 000000000..cceee6b2d
--- /dev/null
+++ b/src/albumcovermanager.ui
@@ -0,0 +1,175 @@
+
+
+ CoverManager
+
+
+
+ 0
+ 0
+ 827
+ 662
+
+
+
+ Cover Manager
+
+
+
+ 0
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ true
+
+
+
+
+
-
+
+
+ 0
+
+
-
+
+
+
+ :/clear.png:/clear.png
+
+
+ true
+
+
+
+ -
+
+
+ Enter search terms here
+
+
+
+ -
+
+
+ View
+
+
+
+ :/view-choose.png:/view-choose.png
+
+
+ QToolButton::MenuButtonPopup
+
+
+ Qt::ToolButtonTextBesideIcon
+
+
+ true
+
+
+
+ -
+
+
+ Fetch Missing Covers
+
+
+
+ :/download.png:/download.png
+
+
+
+
+
+ -
+
+
+ false
+
+
+
+ 120
+ 120
+
+
+
+ QAbstractItemView::ScrollPerPixel
+
+
+ QListView::LeftToRight
+
+
+ true
+
+
+ QListView::Adjust
+
+
+ 2
+
+
+ QListView::IconMode
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+ LineEdit
+ QLineEdit
+
+
+
+
+
+
+
+
+ clear
+ clicked()
+ filter
+ clear()
+
+
+ 329
+ 13
+
+
+ 367
+ 14
+
+
+
+
+ clear
+ clicked()
+ filter
+ setFocus()
+
+
+ 334
+ 20
+
+
+ 401
+ 13
+
+
+
+
+
diff --git a/src/clementine_el.ts b/src/clementine_el.ts
index fb0ea8d1b..613f318e5 100644
--- a/src/clementine_el.ts
+++ b/src/clementine_el.ts
@@ -567,6 +567,10 @@ p, li { white-space: pre-wrap; }
+
+
+
+
MultiLoadingIndicator
@@ -768,6 +772,109 @@ p, li { white-space: pre-wrap; }
+
+
+
+
+
+
+ ShortcutsDialog
+
+
+
+
+
+
+ Αναπαραγωγή
+
+
+
+ Παύση
+
+
+
+
+
+
+
+ Σταμάτημα
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
SomaFMService
diff --git a/src/clementine_es.ts b/src/clementine_es.ts
index 89601ddf9..acff5d253 100644
--- a/src/clementine_es.ts
+++ b/src/clementine_es.ts
@@ -550,6 +550,10 @@ p, li { white-space: pre-wrap; }
+
+
+
+
MultiLoadingIndicator
@@ -751,6 +755,109 @@ p, li { white-space: pre-wrap; }
+
+
+
+
+
+
+ ShortcutsDialog
+
+
+
+
+
+
+ Reproducir
+
+
+
+ Pausa
+
+
+
+
+
+
+
+ Detener
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
SomaFMService
diff --git a/src/clementine_ru.ts b/src/clementine_ru.ts
index 3d4efd85a..80ddb8476 100644
--- a/src/clementine_ru.ts
+++ b/src/clementine_ru.ts
@@ -545,6 +545,10 @@ p, li { white-space: pre-wrap; }
+
+
+
+
MultiLoadingIndicator
@@ -746,6 +750,109 @@ p, li { white-space: pre-wrap; }
+
+
+
+
+
+
+ ShortcutsDialog
+
+
+
+
+
+
+ Воспроизвести
+
+
+
+ Пауза
+
+
+
+
+
+
+
+ Стоп
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
SomaFMService
diff --git a/src/library.cpp b/src/library.cpp
index f614ec928..1ba820e9a 100644
--- a/src/library.cpp
+++ b/src/library.cpp
@@ -45,6 +45,8 @@ void Library::BackendInitialised() {
dir_model_->SetBackend(backend_->Worker());
+ emit BackendReady(backend_->Worker());
+
if (--waiting_for_threads_ == 0)
Initialise();
}
@@ -339,17 +341,17 @@ void Library::LazyPopulate(LibraryItem* item) {
break;
case LibraryItem::Type_CompilationAlbum:
- foreach (const Song& song, backend_->Worker()->GetCompilationSongs(query_options_, item->key))
+ foreach (const Song& song, backend_->Worker()->GetCompilationSongs(item->key, query_options_))
CreateSongNode(false, song, item);
break;
case LibraryItem::Type_Artist:
- foreach (const QString& album, backend_->Worker()->GetAlbumsByArtist(query_options_, item->key))
+ foreach (const QString& album, backend_->Worker()->GetAlbumsByArtist(item->key, query_options_))
CreateAlbumNode(false, album, item, false);
break;
case LibraryItem::Type_Album:
- foreach (const Song& song, backend_->Worker()->GetSongs(query_options_, item->parent->key, item->key))
+ foreach (const Song& song, backend_->Worker()->GetSongs(item->parent->key, item->key, query_options_))
CreateSongNode(false, song, item);
break;
diff --git a/src/library.h b/src/library.h
index 6d92751a6..3f27df8c6 100644
--- a/src/library.h
+++ b/src/library.h
@@ -50,6 +50,8 @@ class Library : public SimpleTreeModel {
void ScanStarted();
void ScanFinished();
+ void BackendReady(boost::shared_ptr backend);
+
public slots:
void SetFilterAge(int age);
void SetFilterText(const QString& text);
diff --git a/src/librarybackend.cpp b/src/librarybackend.cpp
index 0d88b3a2b..c15b48f95 100644
--- a/src/librarybackend.cpp
+++ b/src/librarybackend.cpp
@@ -321,11 +321,17 @@ QStringList LibraryBackend::GetAllArtists(const QueryOptions& opt) {
return ret;
}
-QStringList LibraryBackend::GetAlbumsByArtist(const QueryOptions& opt, const QString& artist) {
+QStringList LibraryBackend::GetAllAlbums(const QueryOptions &opt) {
+ return GetAlbumsByArtist(QString(), opt);
+}
+
+QStringList LibraryBackend::GetAlbumsByArtist(const QString& artist, const QueryOptions& opt) {
LibraryQuery query(opt);
query.SetColumnSpec("DISTINCT album");
query.AddCompilationRequirement(false);
- query.AddWhere("artist", artist);
+
+ if (!artist.isNull())
+ query.AddWhere("artist", artist);
QSqlQuery q(query.Query(Connect()));
q.exec();
@@ -338,7 +344,7 @@ QStringList LibraryBackend::GetAlbumsByArtist(const QueryOptions& opt, const QSt
return ret;
}
-SongList LibraryBackend::GetSongs(const QueryOptions& opt, const QString& artist, const QString& album) {
+SongList LibraryBackend::GetSongs(const QString& artist, const QString& album, const QueryOptions& opt) {
LibraryQuery query(opt);
query.SetColumnSpec("ROWID, " + QString(Song::kColumnSpec));
query.AddCompilationRequirement(false);
@@ -402,7 +408,7 @@ QStringList LibraryBackend::GetCompilationAlbums(const QueryOptions& opt) {
return ret;
}
-SongList LibraryBackend::GetCompilationSongs(const QueryOptions& opt, const QString& album) {
+SongList LibraryBackend::GetCompilationSongs(const QString& album, const QueryOptions& opt) {
LibraryQuery query(opt);
query.SetColumnSpec("ROWID, " + QString(Song::kColumnSpec));
query.AddCompilationRequirement(true);
@@ -515,4 +521,33 @@ void LibraryBackend::UpdateCompilations(QSqlQuery& find_songs, QSqlQuery& update
CheckErrors(update.lastError());
}
+QList
+ LibraryBackend::GetAlbumArtInfo(const QString& artist,
+ const QueryOptions& opt) {
+ QList ret;
+ LibraryQuery query(opt);
+ query.SetColumnSpec("album, art_automatic, art_manual");
+ query.SetOrderBy("album");
+ if (!artist.isNull())
+ query.AddWhere("artist", artist);
+
+ QSqlQuery q(query.Query(Connect()));
+ q.exec();
+ if (CheckErrors(q.lastError())) return ret;
+
+ QString last_album;
+ while (q.next()) {
+ if (q.value(0).toString() == last_album)
+ continue;
+
+ AlbumArtInfo info;
+ info.album_name = q.value(0).toString();
+ info.art_automatic = q.value(1).toString();
+ info.art_manual = q.value(2).toString();
+ ret << info;
+
+ last_album = info.album_name;
+ }
+ return ret;
+}
diff --git a/src/librarybackend.h b/src/librarybackend.h
index 4b05866eb..919b7c5c0 100644
--- a/src/librarybackend.h
+++ b/src/librarybackend.h
@@ -9,8 +9,7 @@
#include "directory.h"
#include "song.h"
-
-struct QueryOptions;
+#include "libraryquery.h"
class LibraryBackend : public QObject {
Q_OBJECT
@@ -18,6 +17,12 @@ class LibraryBackend : public QObject {
public:
LibraryBackend(QObject* parent = 0);
+ struct AlbumArtInfo {
+ QString album_name;
+ QString art_automatic;
+ QString art_manual;
+ };
+
// This actually refers to the location of the sqlite database
static QString DefaultDirectory();
@@ -29,13 +34,16 @@ class LibraryBackend : public QObject {
SongList FindSongsInDirectory(int id);
- QStringList GetAllArtists(const QueryOptions& opt);
- QStringList GetAlbumsByArtist(const QueryOptions& opt, const QString& artist);
- SongList GetSongs(const QueryOptions& opt, const QString& artist, const QString& album);
+ QStringList GetAllArtists(const QueryOptions& opt = QueryOptions());
+ QStringList GetAllAlbums(const QueryOptions& opt = QueryOptions());
+ QStringList GetAlbumsByArtist(const QString& artist, const QueryOptions& opt = QueryOptions());
+ SongList GetSongs(const QString& artist, const QString& album, const QueryOptions& opt = QueryOptions());
- bool HasCompilations(const QueryOptions& opt);
- QStringList GetCompilationAlbums(const QueryOptions& opt);
- SongList GetCompilationSongs(const QueryOptions& opt, const QString& album);
+ bool HasCompilations(const QueryOptions& opt = QueryOptions());
+ QStringList GetCompilationAlbums(const QueryOptions& opt = QueryOptions());
+ SongList GetCompilationSongs(const QString& album, const QueryOptions& opt = QueryOptions());
+
+ QList GetAlbumArtInfo(const QString& artist = QString(), const QueryOptions& opt = QueryOptions());
Song GetSongById(int id);
diff --git a/src/libraryquery.cpp b/src/libraryquery.cpp
index 8d5652bdb..5f72a958c 100644
--- a/src/libraryquery.cpp
+++ b/src/libraryquery.cpp
@@ -53,6 +53,9 @@ QSqlQuery LibraryQuery::Query(QSqlDatabase db) const {
if (!where_clauses_.isEmpty())
sql += " WHERE " + where_clauses_.join(" AND ");
+ if (!order_by_.isEmpty())
+ sql += " ORDER BY " + order_by_;
+
QSqlQuery q(sql, db);
// Bind values
diff --git a/src/libraryquery.h b/src/libraryquery.h
index e18337ddf..e6ec9ce7f 100644
--- a/src/libraryquery.h
+++ b/src/libraryquery.h
@@ -24,6 +24,7 @@ class LibraryQuery {
LibraryQuery(const QueryOptions& options);
void SetColumnSpec(const QString& spec) { column_spec_ = spec; }
+ void SetOrderBy(const QString& order_by) { order_by_ = order_by; }
void AddWhere(const QString& column, const QVariant& value);
void AddCompilationRequirement(bool compilation);
@@ -31,6 +32,7 @@ class LibraryQuery {
private:
QString column_spec_;
+ QString order_by_;
QStringList where_clauses_;
QVariantList bound_values_;
};
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index c3cc5bec6..4766291ce 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -18,6 +18,7 @@
#include "about.h"
#include "addstreamdialog.h"
#include "stylesheetloader.h"
+#include "albumcovermanager.h"
#include "qxtglobalshortcut.h"
@@ -54,6 +55,7 @@ MainWindow::MainWindow(QWidget *parent)
settings_dialog_(new SettingsDialog(this)),
add_stream_dialog_(new AddStreamDialog(this)),
shortcuts_dialog_(new ShortcutsDialog(this)),
+ cover_manager_(new AlbumCoverManager(this)),
playlist_menu_(new QMenu(this)),
library_sort_model_(new QSortFilterProxyModel(this)),
track_position_timer_(new QTimer(this))
@@ -114,6 +116,7 @@ MainWindow::MainWindow(QWidget *parent)
connect(ui_.action_add_stream, SIGNAL(triggered()), SLOT(AddStream()));
connect(ui_.action_hide_tray_icon, SIGNAL(triggered()), SLOT(HideShowTrayIcon()));
connect(ui_.action_global_shortcuts, SIGNAL(triggered()), shortcuts_dialog_, SLOT(show()));
+ connect(ui_.action_cover_manager, SIGNAL(triggered()), cover_manager_, SLOT(show()));
// Give actions to buttons
ui_.forward_button->setDefaultAction(ui_.action_next_track);
@@ -165,6 +168,8 @@ MainWindow::MainWindow(QWidget *parent)
connect(library_, SIGNAL(TotalSongCountUpdated(int)), ui_.library_view, SLOT(TotalSongCountUpdated(int)));
connect(library_, SIGNAL(ScanStarted()), SLOT(LibraryScanStarted()));
connect(library_, SIGNAL(ScanFinished()), SLOT(LibraryScanFinished()));
+ connect(library_, SIGNAL(BackendReady(boost::shared_ptr)),
+ cover_manager_, SLOT(SetBackend(boost::shared_ptr)));
// Age filters
QActionGroup* filter_age_group = new QActionGroup(this);
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 614965282..a2fa75092 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -22,6 +22,7 @@ class SettingsDialog;
class About;
class AddStreamDialog;
class ShortcutsDialog;
+class AlbumCoverManager;
class QSortFilterProxyModel;
class SystemTrayIcon;
@@ -104,6 +105,7 @@ class MainWindow : public QMainWindow {
SettingsDialog* settings_dialog_;
AddStreamDialog* add_stream_dialog_;
ShortcutsDialog* shortcuts_dialog_;
+ AlbumCoverManager* cover_manager_;
QMenu* playlist_menu_;
QAction* playlist_play_pause_;
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
index 6c6f702c1..8279190b8 100644
--- a/src/mainwindow.ui
+++ b/src/mainwindow.ui
@@ -309,7 +309,11 @@
-
-
+
+
+ Enter search terms here
+
+
-
@@ -353,6 +357,9 @@
false
+
+ false
+
@@ -434,7 +441,7 @@
0
0
804
- 24
+ 21
+
+
@@ -706,9 +720,23 @@
Configure &Global Shortcuts...
+
+
+
+ :/download.png:/download.png
+
+
+ Cover Manager
+
+
+
+ LineEdit
+ QLineEdit
+
+
BlockAnalyzer
QWidget
diff --git a/src/src.pro b/src/src.pro
index 25411cc4b..bee47a560 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -56,7 +56,9 @@ SOURCES += main.cpp \
addstreamdialog.cpp \
savedradio.cpp \
stylesheetloader.cpp \
- shortcutsdialog.cpp
+ shortcutsdialog.cpp \
+ covermanager.cpp \
+ coverloader.cpp
HEADERS += mainwindow.h \
player.h \
library.h \
@@ -113,7 +115,9 @@ HEADERS += mainwindow.h \
addstreamdialog.h \
savedradio.h \
stylesheetloader.h \
- shortcutsdialog.h
+ shortcutsdialog.h \
+ covermanager.h \
+ coverloader.h
FORMS += mainwindow.ui \
libraryconfig.ui \
fileview.ui \
@@ -127,7 +131,8 @@ FORMS += mainwindow.ui \
lastfmconfigdialog.ui \
about.ui \
addstreamdialog.ui \
- shortcutsdialog.ui
+ shortcutsdialog.ui \
+ covermanager.ui
RESOURCES += ../data/data.qrc \
translations.qrc
OTHER_FILES += ../data/schema.sql \