2010-03-24 00:11:46 +01:00
|
|
|
/* This file is part of Clementine.
|
2010-11-20 14:27:10 +01:00
|
|
|
Copyright 2010, David Sansome <me@davidsansome.com>
|
2010-03-24 00:11:46 +01:00
|
|
|
|
|
|
|
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/>.
|
|
|
|
*/
|
|
|
|
|
2010-02-28 19:04:50 +01:00
|
|
|
#include "albumcovermanager.h"
|
2010-06-12 19:13:01 +02:00
|
|
|
#include "albumcoversearcher.h"
|
2010-05-19 17:45:29 +02:00
|
|
|
#include "iconloader.h"
|
2010-05-10 23:50:31 +02:00
|
|
|
#include "ui_albumcovermanager.h"
|
2012-02-12 14:41:50 +01:00
|
|
|
#include "core/application.h"
|
2011-08-28 01:25:41 +02:00
|
|
|
#include "core/logging.h"
|
2011-06-26 17:07:48 +02:00
|
|
|
#include "core/utilities.h"
|
2011-04-02 15:34:06 +02:00
|
|
|
#include "covers/albumcoverfetcher.h"
|
2012-02-13 21:44:04 +01:00
|
|
|
#include "covers/albumcoverloader.h"
|
2011-04-27 21:10:37 +02:00
|
|
|
#include "covers/coverproviders.h"
|
2011-06-26 17:07:48 +02:00
|
|
|
#include "covers/coversearchstatisticsdialog.h"
|
2010-05-10 23:50:31 +02:00
|
|
|
#include "library/librarybackend.h"
|
|
|
|
#include "library/libraryquery.h"
|
2010-08-03 20:57:17 +02:00
|
|
|
#include "library/sqlrow.h"
|
2011-01-10 23:26:13 +01:00
|
|
|
#include "playlist/songmimedata.h"
|
2011-06-26 17:06:59 +02:00
|
|
|
#include "widgets/forcescrollperpixel.h"
|
2011-01-24 01:09:57 +01:00
|
|
|
#include "ui/albumcoverchoicecontroller.h"
|
2010-02-28 19:04:50 +01:00
|
|
|
|
|
|
|
#include <QActionGroup>
|
2010-12-14 18:31:39 +01:00
|
|
|
#include <QContextMenuEvent>
|
2010-02-28 20:56:18 +01:00
|
|
|
#include <QEvent>
|
2010-03-03 15:29:53 +01:00
|
|
|
#include <QFileDialog>
|
2010-12-14 18:31:39 +01:00
|
|
|
#include <QKeySequence>
|
|
|
|
#include <QLabel>
|
|
|
|
#include <QListWidget>
|
|
|
|
#include <QMenu>
|
2010-03-03 15:29:53 +01:00
|
|
|
#include <QMessageBox>
|
2010-12-14 18:31:39 +01:00
|
|
|
#include <QPainter>
|
2010-06-12 01:07:53 +02:00
|
|
|
#include <QProgressBar>
|
2010-12-14 18:31:39 +01:00
|
|
|
#include <QSettings>
|
|
|
|
#include <QShortcut>
|
2010-06-12 01:07:53 +02:00
|
|
|
#include <QTimer>
|
2010-02-28 19:04:50 +01:00
|
|
|
|
|
|
|
const char* AlbumCoverManager::kSettingsGroup = "CoverManager";
|
|
|
|
|
2012-02-12 14:41:50 +01:00
|
|
|
AlbumCoverManager::AlbumCoverManager(Application* app,
|
2011-07-23 20:34:41 +02:00
|
|
|
QWidget* parent,
|
2010-10-16 20:21:28 +02:00
|
|
|
QNetworkAccessManager* network)
|
2010-06-12 00:35:41 +02:00
|
|
|
: QMainWindow(parent),
|
2010-05-10 23:50:31 +02:00
|
|
|
ui_(new Ui_CoverManager),
|
2012-02-12 14:41:50 +01:00
|
|
|
app_(app),
|
2011-01-26 00:33:27 +01:00
|
|
|
album_cover_choice_controller_(new AlbumCoverChoiceController(this)),
|
2012-02-12 14:41:50 +01:00
|
|
|
cover_fetcher_(new AlbumCoverFetcher(app_->cover_providers(), this, network)),
|
2010-12-20 16:46:38 +01:00
|
|
|
cover_searcher_(NULL),
|
2010-05-19 17:45:29 +02:00
|
|
|
artist_icon_(IconLoader::Load("x-clementine-artist")),
|
|
|
|
all_artists_icon_(IconLoader::Load("x-clementine-album")),
|
2010-06-12 01:07:53 +02:00
|
|
|
context_menu_(new QMenu(this)),
|
|
|
|
progress_bar_(new QProgressBar(this)),
|
2011-06-26 17:07:48 +02:00
|
|
|
jobs_(0)
|
2010-06-12 01:07:53 +02:00
|
|
|
{
|
2010-05-10 23:50:31 +02:00
|
|
|
ui_->setupUi(this);
|
2010-06-12 17:18:16 +02:00
|
|
|
ui_->albums->set_cover_manager(this);
|
2010-02-28 19:04:50 +01:00
|
|
|
|
2010-05-19 17:45:29 +02:00
|
|
|
// Icons
|
|
|
|
ui_->action_fetch->setIcon(IconLoader::Load("download"));
|
|
|
|
ui_->view->setIcon(IconLoader::Load("view-choose"));
|
|
|
|
ui_->fetch->setIcon(IconLoader::Load("download"));
|
2010-06-12 17:18:16 +02:00
|
|
|
ui_->action_add_to_playlist->setIcon(IconLoader::Load("media-playback-start"));
|
|
|
|
ui_->action_load->setIcon(IconLoader::Load("media-playback-start"));
|
2010-05-19 17:45:29 +02:00
|
|
|
|
2012-02-12 14:41:50 +01:00
|
|
|
album_cover_choice_controller_->SetApplication(app_);
|
2011-01-26 00:33:27 +01:00
|
|
|
|
2010-02-28 19:04:50 +01:00
|
|
|
// 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);
|
2010-06-18 00:47:25 +02:00
|
|
|
p.setOpacity(0.4);
|
2010-02-28 19:04:50 +01:00
|
|
|
p.drawImage((120 - nocover.width()) / 2, (120 - nocover.height()) / 2, nocover);
|
|
|
|
p.end();
|
|
|
|
no_cover_icon_ = QPixmap::fromImage(square_nocover);
|
2010-06-12 01:07:53 +02:00
|
|
|
|
2012-02-12 14:41:50 +01:00
|
|
|
cover_searcher_ = new AlbumCoverSearcher(no_cover_icon_, app_, this);
|
2010-12-20 16:46:38 +01:00
|
|
|
|
2010-06-12 01:07:53 +02:00
|
|
|
// Set up the status bar
|
|
|
|
statusBar()->addPermanentWidget(progress_bar_);
|
|
|
|
progress_bar_->hide();
|
2010-12-14 18:09:41 +01:00
|
|
|
|
|
|
|
ui_->albums->setAttribute(Qt::WA_MacShowFocusRect, false);
|
|
|
|
ui_->artists->setAttribute(Qt::WA_MacShowFocusRect, false);
|
2010-12-14 18:31:39 +01:00
|
|
|
|
2010-12-14 18:55:08 +01:00
|
|
|
QShortcut* close = new QShortcut(QKeySequence::Close, this);
|
2010-12-14 18:31:39 +01:00
|
|
|
connect(close, SIGNAL(activated()), SLOT(close()));
|
2011-04-27 21:36:42 +02:00
|
|
|
|
|
|
|
ResetFetchCoversButton();
|
2010-03-26 13:22:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
AlbumCoverManager::~AlbumCoverManager() {
|
|
|
|
CancelRequests();
|
2010-05-10 23:50:31 +02:00
|
|
|
|
|
|
|
delete ui_;
|
2010-03-26 13:22:19 +01:00
|
|
|
}
|
2010-02-28 19:04:50 +01:00
|
|
|
|
2012-02-12 14:41:50 +01:00
|
|
|
LibraryBackend* AlbumCoverManager::backend() const {
|
|
|
|
return app_->library_backend();
|
|
|
|
}
|
|
|
|
|
2010-03-26 13:22:19 +01:00
|
|
|
void AlbumCoverManager::Init() {
|
2010-02-28 19:04:50 +01:00
|
|
|
// View menu
|
|
|
|
QActionGroup* filter_group = new QActionGroup(this);
|
2010-03-03 15:29:53 +01:00
|
|
|
filter_all_ = filter_group->addAction(tr("All albums"));
|
|
|
|
filter_with_covers_ = filter_group->addAction(tr("Albums with covers"));
|
|
|
|
filter_without_covers_ = filter_group->addAction(tr("Albums without covers"));
|
2010-02-28 19:04:50 +01:00
|
|
|
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());
|
|
|
|
|
2010-05-10 23:50:31 +02:00
|
|
|
ui_->view->setMenu(view_menu);
|
2010-02-28 19:04:50 +01:00
|
|
|
|
2010-03-03 15:29:53 +01:00
|
|
|
// Context menu
|
2011-01-24 01:09:57 +01:00
|
|
|
|
2011-01-26 00:33:27 +01:00
|
|
|
QList<QAction*> actions = album_cover_choice_controller_->GetAllActions();
|
2011-01-24 19:32:09 +01:00
|
|
|
|
2011-01-26 00:33:27 +01:00
|
|
|
connect(album_cover_choice_controller_->cover_from_file_action(),
|
|
|
|
SIGNAL(triggered()), this, SLOT(LoadCoverFromFile()));
|
2011-02-02 17:22:04 +01:00
|
|
|
connect(album_cover_choice_controller_->cover_to_file_action(),
|
|
|
|
SIGNAL(triggered()), this, SLOT(SaveCoverToFile()));
|
2011-01-26 00:33:27 +01:00
|
|
|
connect(album_cover_choice_controller_->cover_from_url_action(),
|
|
|
|
SIGNAL(triggered()), this, SLOT(LoadCoverFromURL()));
|
|
|
|
connect(album_cover_choice_controller_->search_for_cover_action(),
|
|
|
|
SIGNAL(triggered()), this, SLOT(SearchForCover()));
|
|
|
|
connect(album_cover_choice_controller_->unset_cover_action(),
|
|
|
|
SIGNAL(triggered()), this, SLOT(UnsetCover()));
|
|
|
|
connect(album_cover_choice_controller_->show_cover_action(),
|
|
|
|
SIGNAL(triggered()), this, SLOT(ShowCover()));
|
2011-01-24 19:32:09 +01:00
|
|
|
|
|
|
|
context_menu_->addActions(actions);
|
2010-06-12 17:18:16 +02:00
|
|
|
context_menu_->addSeparator();
|
|
|
|
context_menu_->addAction(ui_->action_load);
|
|
|
|
context_menu_->addAction(ui_->action_add_to_playlist);
|
2011-01-24 19:32:09 +01:00
|
|
|
|
2010-05-10 23:50:31 +02:00
|
|
|
ui_->albums->installEventFilter(this);
|
2010-03-03 15:29:53 +01:00
|
|
|
|
2010-02-28 19:04:50 +01:00
|
|
|
// Connections
|
2010-05-10 23:50:31 +02:00
|
|
|
connect(ui_->artists, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
|
2010-02-28 19:04:50 +01:00
|
|
|
SLOT(ArtistChanged(QListWidgetItem*)));
|
2010-05-10 23:50:31 +02:00
|
|
|
connect(ui_->filter, SIGNAL(textChanged(QString)), SLOT(UpdateFilter()));
|
2010-02-28 19:04:50 +01:00
|
|
|
connect(filter_group, SIGNAL(triggered(QAction*)), SLOT(UpdateFilter()));
|
2010-05-10 23:50:31 +02:00
|
|
|
connect(ui_->view, SIGNAL(clicked()), ui_->view, SLOT(showMenu()));
|
|
|
|
connect(ui_->fetch, SIGNAL(clicked()), SLOT(FetchAlbumCovers()));
|
2011-06-26 17:07:48 +02:00
|
|
|
connect(cover_fetcher_, SIGNAL(AlbumCoverFetched(quint64,QImage,CoverSearchStatistics)),
|
|
|
|
SLOT(AlbumCoverFetched(quint64,QImage,CoverSearchStatistics)));
|
2010-05-10 23:50:31 +02:00
|
|
|
connect(ui_->action_fetch, SIGNAL(triggered()), SLOT(FetchSingleCover()));
|
2010-06-12 17:18:16 +02:00
|
|
|
connect(ui_->albums, SIGNAL(doubleClicked(QModelIndex)), SLOT(AlbumDoubleClicked(QModelIndex)));
|
|
|
|
connect(ui_->action_add_to_playlist, SIGNAL(triggered()), SLOT(AddSelectedToPlaylist()));
|
|
|
|
connect(ui_->action_load, SIGNAL(triggered()), SLOT(LoadSelectedToPlaylist()));
|
2010-02-28 19:04:50 +01:00
|
|
|
|
|
|
|
// Restore settings
|
|
|
|
QSettings s;
|
|
|
|
s.beginGroup(kSettingsGroup);
|
|
|
|
|
|
|
|
restoreGeometry(s.value("geometry").toByteArray());
|
2010-05-10 23:50:31 +02:00
|
|
|
if (!ui_->splitter->restoreState(s.value("splitter_state").toByteArray())) {
|
2010-02-28 19:04:50 +01:00
|
|
|
// Sensible default size for the artists view
|
2010-05-10 23:50:31 +02:00
|
|
|
ui_->splitter->setSizes(QList<int>() << 200 << width() - 200);
|
2010-02-28 19:04:50 +01:00
|
|
|
}
|
|
|
|
|
2012-02-13 21:44:04 +01:00
|
|
|
connect(app_->album_cover_loader(),
|
|
|
|
SIGNAL(ImageLoaded(quint64,QImage)),
|
|
|
|
SLOT(CoverImageLoaded(quint64,QImage)));
|
|
|
|
|
2010-12-26 21:19:12 +01:00
|
|
|
cover_searcher_->Init(cover_fetcher_);
|
2011-06-26 17:06:59 +02:00
|
|
|
|
|
|
|
new ForceScrollPerPixel(ui_->albums, this);
|
2010-02-28 19:04:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumCoverManager::showEvent(QShowEvent *) {
|
|
|
|
Reset();
|
|
|
|
}
|
|
|
|
|
2010-06-12 01:07:53 +02:00
|
|
|
void AlbumCoverManager::closeEvent(QCloseEvent* e) {
|
|
|
|
if (!cover_fetching_tasks_.isEmpty()) {
|
|
|
|
boost::scoped_ptr<QMessageBox> message_box(new QMessageBox(
|
|
|
|
QMessageBox::Question, tr("Really cancel?"),
|
|
|
|
tr("Closing this window will stop searching for album covers."),
|
|
|
|
QMessageBox::Abort, this));
|
|
|
|
message_box->addButton(tr("Don't stop!"), QMessageBox::AcceptRole);
|
|
|
|
|
|
|
|
if (message_box->exec() != QMessageBox::Abort) {
|
|
|
|
e->ignore();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-28 20:25:52 +01:00
|
|
|
// Save geometry
|
2010-02-28 19:04:50 +01:00
|
|
|
QSettings s;
|
|
|
|
s.beginGroup(kSettingsGroup);
|
|
|
|
|
|
|
|
s.setValue("geometry", saveGeometry());
|
2010-05-10 23:50:31 +02:00
|
|
|
s.setValue("splitter_state", ui_->splitter->saveState());
|
2010-02-28 20:25:52 +01:00
|
|
|
|
|
|
|
// Cancel any outstanding requests
|
|
|
|
CancelRequests();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumCoverManager::CancelRequests() {
|
2012-02-13 21:44:04 +01:00
|
|
|
app_->album_cover_loader()->CancelTasks(
|
|
|
|
QSet<quint64>::fromList(cover_loading_tasks_.keys()));
|
2010-02-28 20:25:52 +01:00
|
|
|
cover_loading_tasks_.clear();
|
|
|
|
|
|
|
|
cover_fetching_tasks_.clear();
|
|
|
|
cover_fetcher_->Clear();
|
2010-06-12 01:07:53 +02:00
|
|
|
progress_bar_->hide();
|
|
|
|
statusBar()->clearMessage();
|
2011-04-27 21:36:42 +02:00
|
|
|
ResetFetchCoversButton();
|
2010-02-28 19:04:50 +01:00
|
|
|
}
|
|
|
|
|
2011-08-28 01:25:41 +02:00
|
|
|
static bool CompareNocase(const QString& left, const QString& right) {
|
|
|
|
return QString::localeAwareCompare(left, right) < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool CompareAlbumNameNocase(const LibraryBackend::Album& left,
|
|
|
|
const LibraryBackend::Album& right) {
|
|
|
|
return CompareNocase(left.album_name, right.album_name);
|
|
|
|
}
|
|
|
|
|
2010-02-28 19:04:50 +01:00
|
|
|
void AlbumCoverManager::Reset() {
|
2011-04-27 21:36:42 +02:00
|
|
|
ResetFetchCoversButton();
|
|
|
|
|
2010-05-10 23:50:31 +02:00
|
|
|
ui_->artists->clear();
|
|
|
|
new QListWidgetItem(all_artists_icon_, tr("All artists"), ui_->artists, All_Artists);
|
|
|
|
new QListWidgetItem(artist_icon_, tr("Various artists"), ui_->artists, Various_Artists);
|
2010-02-28 19:04:50 +01:00
|
|
|
|
2012-02-12 14:41:50 +01:00
|
|
|
QStringList artists(app_->library_backend()->GetAllArtistsWithAlbums());
|
2011-08-28 01:25:41 +02:00
|
|
|
qStableSort(artists.begin(), artists.end(), CompareNocase);
|
|
|
|
|
|
|
|
foreach (const QString& artist, artists) {
|
2010-02-28 19:04:50 +01:00
|
|
|
if (artist.isEmpty())
|
|
|
|
continue;
|
|
|
|
|
2010-05-10 23:50:31 +02:00
|
|
|
new QListWidgetItem(artist_icon_, artist, ui_->artists, Specific_Artist);
|
2010-02-28 19:04:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-27 21:36:42 +02:00
|
|
|
void AlbumCoverManager::ResetFetchCoversButton() {
|
2012-02-12 14:41:50 +01:00
|
|
|
ui_->fetch->setEnabled(app_->cover_providers()->HasAnyProviders());
|
2011-04-27 21:36:42 +02:00
|
|
|
}
|
|
|
|
|
2010-02-28 19:04:50 +01:00
|
|
|
void AlbumCoverManager::ArtistChanged(QListWidgetItem* current) {
|
|
|
|
if (!current)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QString artist;
|
|
|
|
if (current->type() == Specific_Artist)
|
|
|
|
artist = current->text();
|
|
|
|
|
2010-05-10 23:50:31 +02:00
|
|
|
ui_->albums->clear();
|
2010-03-03 15:29:53 +01:00
|
|
|
context_menu_items_.clear();
|
2010-02-28 20:25:52 +01:00
|
|
|
CancelRequests();
|
2010-02-28 19:04:50 +01:00
|
|
|
|
2010-03-12 01:54:18 +01:00
|
|
|
// Get the list of albums. How we do it depends on what thing we have
|
|
|
|
// selected in the artist list.
|
2010-05-09 02:10:26 +02:00
|
|
|
LibraryBackend::AlbumList albums;
|
2010-03-12 01:54:18 +01:00
|
|
|
switch (current->type()) {
|
2012-02-12 14:41:50 +01:00
|
|
|
case Various_Artists: albums = app_->library_backend()->GetCompilationAlbums(); break;
|
|
|
|
case Specific_Artist: albums = app_->library_backend()->GetAlbumsByArtist(current->text()); break;
|
2010-03-12 01:54:18 +01:00
|
|
|
case All_Artists:
|
2012-02-12 14:41:50 +01:00
|
|
|
default: albums = app_->library_backend()->GetAllAlbums(); break;
|
2010-03-12 01:54:18 +01:00
|
|
|
}
|
|
|
|
|
2011-08-28 01:25:41 +02:00
|
|
|
// Sort by album name. The list is already sorted by sqlite but it was done
|
|
|
|
// case sensitively.
|
|
|
|
qStableSort(albums.begin(), albums.end(), CompareAlbumNameNocase);
|
|
|
|
|
2010-05-09 02:10:26 +02:00
|
|
|
foreach (const LibraryBackend::Album& info, albums) {
|
2010-03-12 01:54:18 +01:00
|
|
|
// Don't show songs without an album, obviously
|
|
|
|
if (info.album_name.isEmpty())
|
|
|
|
continue;
|
|
|
|
|
2010-05-10 23:50:31 +02:00
|
|
|
QListWidgetItem* item = new QListWidgetItem(no_cover_icon_, info.album_name, ui_->albums);
|
2010-02-28 20:25:52 +01:00
|
|
|
item->setData(Role_ArtistName, info.artist);
|
|
|
|
item->setData(Role_AlbumName, info.album_name);
|
2011-04-28 14:27:53 +02:00
|
|
|
item->setData(Role_FirstUrl, info.first_url);
|
2010-06-12 17:18:16 +02:00
|
|
|
item->setData(Qt::TextAlignmentRole, QVariant(Qt::AlignTop | Qt::AlignHCenter));
|
|
|
|
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
|
2011-02-08 23:54:37 +01:00
|
|
|
item->setToolTip(info.artist + " - " + info.album_name);
|
2010-02-28 19:04:50 +01:00
|
|
|
|
|
|
|
if (!info.art_automatic.isEmpty() || !info.art_manual.isEmpty()) {
|
2012-02-13 21:44:04 +01:00
|
|
|
quint64 id = app_->album_cover_loader()->LoadImageAsync(
|
|
|
|
cover_loader_options_,
|
2011-04-28 14:27:53 +02:00
|
|
|
info.art_automatic, info.art_manual, info.first_url.toLocalFile());
|
2010-03-03 15:29:53 +01:00
|
|
|
item->setData(Role_PathAutomatic, info.art_automatic);
|
|
|
|
item->setData(Role_PathManual, info.art_manual);
|
2010-02-28 19:04:50 +01:00
|
|
|
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() {
|
2012-06-27 17:37:55 +02:00
|
|
|
const QString filter = ui_->filter->text().toLower();
|
2010-02-28 19:04:50 +01:00
|
|
|
const bool hide_with_covers = filter_without_covers_->isChecked();
|
|
|
|
const bool hide_without_covers = filter_with_covers_->isChecked();
|
|
|
|
|
2010-03-26 13:22:19 +01:00
|
|
|
HideCovers hide = Hide_None;
|
|
|
|
if (hide_with_covers) {
|
|
|
|
hide = Hide_WithCovers;
|
|
|
|
} else if (hide_without_covers) {
|
|
|
|
hide = Hide_WithoutCovers;
|
|
|
|
}
|
|
|
|
|
2010-05-10 23:50:31 +02:00
|
|
|
for (int i = 0; i < ui_->albums->count(); ++i) {
|
|
|
|
QListWidgetItem* item = ui_->albums->item(i);
|
2010-03-26 13:22:19 +01:00
|
|
|
item->setHidden(ShouldHide(*item, filter, hide));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AlbumCoverManager::ShouldHide(
|
|
|
|
const QListWidgetItem& item, const QString& filter, HideCovers hide) const {
|
|
|
|
bool has_cover = item.icon().cacheKey() != no_cover_icon_.cacheKey();
|
|
|
|
if (hide == Hide_WithCovers && has_cover) {
|
|
|
|
return true;
|
|
|
|
} else if (hide == Hide_WithoutCovers && !has_cover) {
|
|
|
|
return true;
|
|
|
|
}
|
2010-02-28 19:04:50 +01:00
|
|
|
|
2010-03-26 13:22:19 +01:00
|
|
|
if (filter.isEmpty()) {
|
|
|
|
return false;
|
2010-02-28 19:04:50 +01:00
|
|
|
}
|
2010-03-26 13:22:19 +01:00
|
|
|
|
|
|
|
QStringList query = filter.split(' ');
|
|
|
|
foreach (const QString& s, query) {
|
2010-12-17 00:38:27 +01:00
|
|
|
if (!item.text().contains(s, Qt::CaseInsensitive)
|
|
|
|
&& !item.data(Role_ArtistName).toString().contains(s, Qt::CaseInsensitive)) {
|
2010-03-26 16:04:38 +01:00
|
|
|
return true;
|
2010-03-26 13:22:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-26 16:04:38 +01:00
|
|
|
return false;
|
2010-02-28 19:04:50 +01:00
|
|
|
}
|
2010-02-28 20:25:52 +01:00
|
|
|
|
|
|
|
void AlbumCoverManager::FetchAlbumCovers() {
|
2010-05-10 23:50:31 +02:00
|
|
|
for (int i=0 ; i<ui_->albums->count() ; ++i) {
|
|
|
|
QListWidgetItem* item = ui_->albums->item(i);
|
2010-02-28 20:25:52 +01:00
|
|
|
if (item->isHidden())
|
|
|
|
continue;
|
|
|
|
if (item->icon().cacheKey() != no_cover_icon_.cacheKey())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
quint64 id = cover_fetcher_->FetchAlbumCover(
|
|
|
|
item->data(Role_ArtistName).toString(), item->data(Role_AlbumName).toString());
|
|
|
|
cover_fetching_tasks_[id] = item;
|
2010-06-12 01:07:53 +02:00
|
|
|
jobs_ ++;
|
2010-02-28 20:25:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!cover_fetching_tasks_.isEmpty())
|
2010-05-10 23:50:31 +02:00
|
|
|
ui_->fetch->setEnabled(false);
|
2010-06-12 01:07:53 +02:00
|
|
|
|
|
|
|
progress_bar_->setMaximum(jobs_);
|
|
|
|
progress_bar_->show();
|
2011-06-26 17:07:48 +02:00
|
|
|
fetch_statistics_ = CoverSearchStatistics();
|
2010-06-12 01:07:53 +02:00
|
|
|
UpdateStatusText();
|
2010-02-28 20:25:52 +01:00
|
|
|
}
|
|
|
|
|
2011-06-26 17:07:48 +02:00
|
|
|
void AlbumCoverManager::AlbumCoverFetched(quint64 id, const QImage& image,
|
|
|
|
const CoverSearchStatistics& statistics) {
|
2010-02-28 20:25:52 +01:00
|
|
|
if (!cover_fetching_tasks_.contains(id))
|
|
|
|
return;
|
|
|
|
|
|
|
|
QListWidgetItem* item = cover_fetching_tasks_.take(id);
|
2011-06-26 17:07:48 +02:00
|
|
|
if (!image.isNull()) {
|
2010-06-12 19:13:01 +02:00
|
|
|
SaveAndSetCover(item, image);
|
|
|
|
}
|
|
|
|
|
2011-04-27 21:36:42 +02:00
|
|
|
if (cover_fetching_tasks_.isEmpty()) {
|
|
|
|
ResetFetchCoversButton();
|
|
|
|
}
|
2010-02-28 20:25:52 +01:00
|
|
|
|
2011-06-26 17:07:48 +02:00
|
|
|
fetch_statistics_ += statistics;
|
2010-06-12 19:13:01 +02:00
|
|
|
UpdateStatusText();
|
|
|
|
}
|
2010-02-28 20:25:52 +01:00
|
|
|
|
2010-06-12 01:07:53 +02:00
|
|
|
void AlbumCoverManager::UpdateStatusText() {
|
|
|
|
QString message = tr("Got %1 covers out of %2 (%3 failed)")
|
2011-06-26 17:07:48 +02:00
|
|
|
.arg(fetch_statistics_.chosen_images_)
|
|
|
|
.arg(jobs_)
|
|
|
|
.arg(fetch_statistics_.missing_images_);
|
|
|
|
|
|
|
|
if (fetch_statistics_.bytes_transferred_) {
|
|
|
|
message += ", " + tr("%1 transferred")
|
|
|
|
.arg(Utilities::PrettySize(fetch_statistics_.bytes_transferred_));
|
|
|
|
}
|
|
|
|
|
2010-06-12 01:07:53 +02:00
|
|
|
statusBar()->showMessage(message);
|
2011-06-26 17:07:48 +02:00
|
|
|
progress_bar_->setValue(fetch_statistics_.chosen_images_ +
|
|
|
|
fetch_statistics_.missing_images_);
|
2010-06-12 01:07:53 +02:00
|
|
|
|
|
|
|
if (cover_fetching_tasks_.isEmpty()) {
|
|
|
|
QTimer::singleShot(2000, statusBar(), SLOT(clearMessage()));
|
|
|
|
progress_bar_->hide();
|
|
|
|
|
2011-06-26 17:07:48 +02:00
|
|
|
CoverSearchStatisticsDialog* dialog = new CoverSearchStatisticsDialog(this);
|
|
|
|
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
dialog->Show(fetch_statistics_);
|
|
|
|
|
2010-06-12 01:07:53 +02:00
|
|
|
jobs_ = 0;
|
|
|
|
}
|
2010-02-28 20:25:52 +01:00
|
|
|
}
|
2010-02-28 20:56:18 +01:00
|
|
|
|
2010-03-03 15:29:53 +01:00
|
|
|
bool AlbumCoverManager::eventFilter(QObject *obj, QEvent *event) {
|
2010-05-10 23:50:31 +02:00
|
|
|
if (obj == ui_->albums && event->type() == QEvent::ContextMenu) {
|
|
|
|
context_menu_items_ = ui_->albums->selectedItems();
|
2010-03-03 15:29:53 +01:00
|
|
|
if (context_menu_items_.isEmpty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool some_with_covers = false;
|
|
|
|
|
|
|
|
foreach (QListWidgetItem* item, context_menu_items_) {
|
|
|
|
if (item->icon().cacheKey() != no_cover_icon_.cacheKey())
|
|
|
|
some_with_covers = true;
|
|
|
|
}
|
|
|
|
|
2011-01-26 00:33:27 +01:00
|
|
|
album_cover_choice_controller_->cover_from_file_action()->setEnabled(context_menu_items_.size() == 1);
|
|
|
|
album_cover_choice_controller_->cover_from_url_action()->setEnabled(context_menu_items_.size() == 1);
|
|
|
|
album_cover_choice_controller_->show_cover_action()->setEnabled(some_with_covers && context_menu_items_.size() == 1);
|
|
|
|
album_cover_choice_controller_->unset_cover_action()->setEnabled(some_with_covers);
|
2012-02-12 14:41:50 +01:00
|
|
|
album_cover_choice_controller_->search_for_cover_action()->setEnabled(app_->cover_providers()->HasAnyProviders());
|
2010-03-03 15:29:53 +01:00
|
|
|
|
|
|
|
QContextMenuEvent* e = static_cast<QContextMenuEvent*>(event);
|
|
|
|
context_menu_->popup(e->globalPos());
|
|
|
|
return true;
|
|
|
|
}
|
2010-06-12 00:35:41 +02:00
|
|
|
return QMainWindow::eventFilter(obj, event);
|
2010-03-03 15:29:53 +01:00
|
|
|
}
|
|
|
|
|
2011-01-24 01:09:57 +01:00
|
|
|
Song AlbumCoverManager::GetSingleSelectionAsSong() {
|
|
|
|
return context_menu_items_.size() != 1
|
|
|
|
? Song()
|
|
|
|
: ItemAsSong(context_menu_items_[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
Song AlbumCoverManager::GetFirstSelectedAsSong() {
|
|
|
|
return context_menu_items_.isEmpty()
|
|
|
|
? Song()
|
|
|
|
: ItemAsSong(context_menu_items_[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
Song AlbumCoverManager::ItemAsSong(QListWidgetItem* item) {
|
|
|
|
Song result;
|
2010-03-03 15:29:53 +01:00
|
|
|
|
|
|
|
QString title = item->data(Role_AlbumName).toString();
|
|
|
|
if (!item->data(Role_ArtistName).toString().isNull())
|
2011-01-24 01:09:57 +01:00
|
|
|
result.set_title(item->data(Role_ArtistName).toString() + " - " + title);
|
|
|
|
else
|
|
|
|
result.set_title(title);
|
|
|
|
|
|
|
|
result.set_artist(item->data(Role_ArtistName).toString());
|
|
|
|
result.set_album(item->data(Role_AlbumName).toString());
|
|
|
|
|
2011-04-28 14:27:53 +02:00
|
|
|
result.set_url(item->data(Role_FirstUrl).toUrl());
|
2010-03-03 15:29:53 +01:00
|
|
|
|
2011-01-24 01:09:57 +01:00
|
|
|
result.set_art_automatic(item->data(Role_PathAutomatic).toString());
|
|
|
|
result.set_art_manual(item->data(Role_PathManual).toString());
|
2010-03-03 15:29:53 +01:00
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
// force validity
|
2011-01-24 01:09:57 +01:00
|
|
|
result.set_valid(true);
|
2011-01-24 18:53:31 +01:00
|
|
|
result.set_id(0);
|
|
|
|
|
2011-01-24 01:09:57 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumCoverManager::ShowCover() {
|
|
|
|
Song song = GetSingleSelectionAsSong();
|
|
|
|
if(!song.is_valid())
|
|
|
|
return;
|
2010-03-03 15:29:53 +01:00
|
|
|
|
2011-01-24 01:09:57 +01:00
|
|
|
album_cover_choice_controller_->ShowCover(song);
|
2010-03-03 15:29:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumCoverManager::FetchSingleCover() {
|
|
|
|
foreach (QListWidgetItem* item, context_menu_items_) {
|
|
|
|
quint64 id = cover_fetcher_->FetchAlbumCover(
|
|
|
|
item->data(Role_ArtistName).toString(), item->data(Role_AlbumName).toString());
|
|
|
|
cover_fetching_tasks_[id] = item;
|
2010-06-12 01:07:53 +02:00
|
|
|
jobs_ ++;
|
2010-03-03 15:29:53 +01:00
|
|
|
}
|
2010-06-12 01:07:53 +02:00
|
|
|
|
|
|
|
progress_bar_->setMaximum(jobs_);
|
|
|
|
progress_bar_->show();
|
|
|
|
UpdateStatusText();
|
2010-03-03 15:29:53 +01:00
|
|
|
}
|
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
|
|
|
|
void AlbumCoverManager::UpdateCoverInList(QListWidgetItem* item, const QString& cover) {
|
2012-02-13 21:44:04 +01:00
|
|
|
quint64 id = app_->album_cover_loader()->LoadImageAsync(
|
|
|
|
cover_loader_options_, QString(), cover);
|
2011-01-24 18:53:31 +01:00
|
|
|
item->setData(Role_PathManual, cover);
|
|
|
|
cover_loading_tasks_[id] = item;
|
|
|
|
}
|
|
|
|
|
2011-01-24 01:09:57 +01:00
|
|
|
void AlbumCoverManager::LoadCoverFromFile() {
|
|
|
|
Song song = GetSingleSelectionAsSong();
|
|
|
|
if(!song.is_valid())
|
2010-03-03 15:29:53 +01:00
|
|
|
return;
|
|
|
|
|
2011-01-24 01:09:57 +01:00
|
|
|
QListWidgetItem* item = context_menu_items_[0];
|
2010-12-15 21:15:46 +01:00
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
QString cover = album_cover_choice_controller_->LoadCoverFromFile(&song);
|
2010-03-03 15:29:53 +01:00
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
if (!cover.isEmpty()) {
|
|
|
|
UpdateCoverInList(item, cover);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-02 17:22:04 +01:00
|
|
|
void AlbumCoverManager::SaveCoverToFile() {
|
|
|
|
Song song = GetSingleSelectionAsSong();
|
|
|
|
if(!song.is_valid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
QImage image;
|
|
|
|
|
|
|
|
// load the image from disk
|
2011-02-02 22:01:08 +01:00
|
|
|
if(song.has_manually_unset_cover()) {
|
2011-02-02 17:22:04 +01:00
|
|
|
image = QImage(":/nocover.png");
|
|
|
|
} else {
|
|
|
|
if(!song.art_manual().isEmpty() && QFile::exists(song.art_manual())) {
|
|
|
|
image = QImage(song.art_manual());
|
|
|
|
} else if(!song.art_automatic().isEmpty() && QFile::exists(song.art_automatic())) {
|
|
|
|
image = QImage(song.art_automatic());
|
|
|
|
} else {
|
|
|
|
image = QImage(":/nocover.png");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
album_cover_choice_controller_->SaveCoverToFile(song, image);
|
|
|
|
}
|
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
void AlbumCoverManager::LoadCoverFromURL() {
|
|
|
|
Song song = GetSingleSelectionAsSong();
|
|
|
|
if(!song.is_valid())
|
2010-03-03 15:29:53 +01:00
|
|
|
return;
|
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
QListWidgetItem* item = context_menu_items_[0];
|
|
|
|
|
|
|
|
QString cover = album_cover_choice_controller_->LoadCoverFromURL(&song);
|
2010-03-03 15:29:53 +01:00
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
if (!cover.isEmpty()) {
|
|
|
|
UpdateCoverInList(item, cover);
|
|
|
|
}
|
2010-03-03 15:29:53 +01:00
|
|
|
}
|
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
void AlbumCoverManager::SearchForCover() {
|
|
|
|
Song song = GetFirstSelectedAsSong();
|
2011-01-24 01:09:57 +01:00
|
|
|
if(!song.is_valid())
|
2011-01-23 21:24:17 +01:00
|
|
|
return;
|
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
QListWidgetItem* item = context_menu_items_[0];
|
|
|
|
|
|
|
|
QString cover = album_cover_choice_controller_->SearchForCover(&song);
|
|
|
|
if (cover.isEmpty())
|
2011-01-23 21:24:17 +01:00
|
|
|
return;
|
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
// force the found cover on all of the selected items
|
|
|
|
foreach (QListWidgetItem* current, context_menu_items_) {
|
|
|
|
// don't save the first one twice
|
|
|
|
if(current != item) {
|
|
|
|
Song current_song = ItemAsSong(current);
|
|
|
|
album_cover_choice_controller_->SaveCover(¤t_song, cover);
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateCoverInList(current, cover);
|
|
|
|
}
|
2010-12-15 21:15:46 +01:00
|
|
|
}
|
|
|
|
|
2010-03-03 15:29:53 +01:00
|
|
|
void AlbumCoverManager::UnsetCover() {
|
2011-01-24 18:53:31 +01:00
|
|
|
Song song = GetFirstSelectedAsSong();
|
|
|
|
if(!song.is_valid())
|
|
|
|
return;
|
2011-01-24 01:09:57 +01:00
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
QListWidgetItem* item = context_menu_items_[0];
|
|
|
|
|
|
|
|
QString cover = album_cover_choice_controller_->UnsetCover(&song);
|
|
|
|
|
|
|
|
// force the 'none' cover on all of the selected items
|
|
|
|
foreach (QListWidgetItem* current, context_menu_items_) {
|
|
|
|
current->setIcon(no_cover_icon_);
|
|
|
|
current->setData(Role_PathManual, cover);
|
|
|
|
|
|
|
|
// don't save the first one twice
|
|
|
|
if(current != item) {
|
|
|
|
Song current_song = ItemAsSong(current);
|
|
|
|
album_cover_choice_controller_->SaveCover(¤t_song, cover);
|
|
|
|
}
|
2010-03-03 15:29:53 +01:00
|
|
|
}
|
|
|
|
}
|
2010-06-12 17:18:16 +02:00
|
|
|
|
|
|
|
SongList AlbumCoverManager::GetSongsInAlbum(const QModelIndex& index) const {
|
|
|
|
SongList ret;
|
|
|
|
|
|
|
|
LibraryQuery q;
|
|
|
|
q.SetColumnSpec("ROWID," + Song::kColumnSpec);
|
|
|
|
q.AddWhere("album", index.data(Role_AlbumName).toString());
|
|
|
|
q.SetOrderBy("disc, track, title");
|
|
|
|
|
|
|
|
QString artist = index.data(Role_ArtistName).toString();
|
|
|
|
q.AddCompilationRequirement(artist.isEmpty());
|
|
|
|
if (!artist.isEmpty())
|
|
|
|
q.AddWhere("artist", artist);
|
|
|
|
|
2012-02-12 14:41:50 +01:00
|
|
|
if (!app_->library_backend()->ExecQuery(&q))
|
2010-06-12 17:18:16 +02:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
while (q.Next()) {
|
|
|
|
Song song;
|
2011-06-17 22:00:10 +02:00
|
|
|
song.InitFromQuery(q, true);
|
2010-06-12 17:18:16 +02:00
|
|
|
ret << song;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
SongList AlbumCoverManager::GetSongsInAlbums(const QModelIndexList& indexes) const {
|
|
|
|
SongList ret;
|
|
|
|
foreach (const QModelIndex& index, indexes) {
|
|
|
|
ret << GetSongsInAlbum(index);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-01-10 23:26:13 +01:00
|
|
|
SongMimeData* AlbumCoverManager::GetMimeDataForAlbums(const QModelIndexList& indexes) const {
|
|
|
|
SongList songs = GetSongsInAlbums(indexes);
|
|
|
|
if (songs.isEmpty())
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
SongMimeData* data = new SongMimeData;
|
2012-02-12 14:41:50 +01:00
|
|
|
data->backend = app_->library_backend();
|
2011-01-10 23:26:13 +01:00
|
|
|
data->songs = songs;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2010-06-12 17:18:16 +02:00
|
|
|
void AlbumCoverManager::AlbumDoubleClicked(const QModelIndex &index) {
|
2011-01-10 23:26:13 +01:00
|
|
|
SongMimeData* data = GetMimeDataForAlbums(QModelIndexList() << index);
|
|
|
|
if (data) {
|
2011-01-24 22:16:26 +01:00
|
|
|
data->from_doubleclick_ = true;
|
2011-01-10 23:26:13 +01:00
|
|
|
emit AddToPlaylist(data);
|
|
|
|
}
|
2010-06-12 17:18:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumCoverManager::AddSelectedToPlaylist() {
|
2011-01-10 23:26:13 +01:00
|
|
|
emit AddToPlaylist(GetMimeDataForAlbums(ui_->albums->selectionModel()->selectedIndexes()));
|
2010-06-12 17:18:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void AlbumCoverManager::LoadSelectedToPlaylist() {
|
2011-01-10 23:26:13 +01:00
|
|
|
SongMimeData* data = GetMimeDataForAlbums(ui_->albums->selectionModel()->selectedIndexes());
|
|
|
|
if (data) {
|
|
|
|
data->clear_first_ = true;
|
|
|
|
emit AddToPlaylist(data);
|
|
|
|
}
|
2010-06-12 17:18:16 +02:00
|
|
|
}
|
2010-06-12 19:13:01 +02:00
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
void AlbumCoverManager::SaveAndSetCover(QListWidgetItem *item, const QImage &image) {
|
|
|
|
const QString artist = item->data(Role_ArtistName).toString();
|
|
|
|
const QString album = item->data(Role_AlbumName).toString();
|
2010-06-12 19:13:01 +02:00
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
QString path = album_cover_choice_controller_->SaveCoverInCache(artist, album, image);
|
2010-06-12 19:13:01 +02:00
|
|
|
|
2011-01-24 18:53:31 +01:00
|
|
|
// Save the image in the database
|
2012-02-12 14:41:50 +01:00
|
|
|
app_->library_backend()->UpdateManualAlbumArtAsync(artist, album, path);
|
2011-01-24 18:53:31 +01:00
|
|
|
|
|
|
|
// Update the icon in our list
|
2012-02-13 21:44:04 +01:00
|
|
|
quint64 id = app_->album_cover_loader()->LoadImageAsync(
|
|
|
|
cover_loader_options_, QString(), path);
|
2011-01-24 18:53:31 +01:00
|
|
|
item->setData(Role_PathManual, path);
|
|
|
|
cover_loading_tasks_[id] = item;
|
2010-06-12 19:13:01 +02:00
|
|
|
}
|