Make CoverProviders not a singleton

This commit is contained in:
David Sansome 2011-07-23 19:34:41 +01:00
parent a1062eb96f
commit 38100f5e59
22 changed files with 100 additions and 52 deletions

View File

@ -24,8 +24,10 @@
const int AlbumCoverFetcher::kMaxConcurrentRequests = 5;
AlbumCoverFetcher::AlbumCoverFetcher(QObject* parent, QNetworkAccessManager* network)
AlbumCoverFetcher::AlbumCoverFetcher(CoverProviders* cover_providers,
QObject* parent, QNetworkAccessManager* network)
: QObject(parent),
cover_providers_(cover_providers),
network_(network ? network : new NetworkAccessManager(this)),
next_id_(0),
request_starter_(new QTimer(this))
@ -100,7 +102,7 @@ void AlbumCoverFetcher::StartRequests() {
connect(search, SIGNAL(AlbumCoverFetched(quint64, const QImage&)),
SLOT(SingleCoverFetched(quint64, const QImage&)));
search->Start();
search->Start(cover_providers_);
}
}

View File

@ -34,6 +34,7 @@ class QNetworkReply;
class QString;
class AlbumCoverFetcherSearch;
class CoverProviders;
// This class represents a single search-for-cover request. It identifies
// and describes the request.
@ -79,7 +80,8 @@ class AlbumCoverFetcher : public QObject {
Q_OBJECT
public:
AlbumCoverFetcher(QObject* parent = 0, QNetworkAccessManager* network = 0);
AlbumCoverFetcher(CoverProviders* cover_providers,
QObject* parent = 0, QNetworkAccessManager* network = 0);
virtual ~AlbumCoverFetcher() {}
static const int kMaxConcurrentRequests;
@ -103,6 +105,7 @@ class AlbumCoverFetcher : public QObject {
private:
void AddRequest(const CoverSearchRequest& req);
CoverProviders* cover_providers_;
QNetworkAccessManager* network_;
quint64 next_id_;

View File

@ -56,13 +56,11 @@ void AlbumCoverFetcherSearch::TerminateSearch() {
AllProvidersFinished();
}
void AlbumCoverFetcherSearch::Start() {
CoverProviders* providers = &CoverProviders::instance();
foreach(CoverProvider* provider, providers->List()) {
void AlbumCoverFetcherSearch::Start(CoverProviders* cover_providers) {
foreach(CoverProvider* provider, cover_providers->List()) {
connect(provider, SIGNAL(SearchFinished(int,QList<CoverSearchResult>)),
SLOT(ProviderSearchFinished(int,QList<CoverSearchResult>)));
const int id = providers->NextId();
const int id = cover_providers->NextId();
const bool success = provider->StartSearch(
request_.artist, request_.album, id);

View File

@ -24,6 +24,7 @@
#include <QObject>
class CoverProvider;
class CoverProviders;
class NetworkTimeouts;
class QNetworkAccessManager;
class QNetworkReply;
@ -39,7 +40,7 @@ class AlbumCoverFetcherSearch : public QObject {
AlbumCoverFetcherSearch(const CoverSearchRequest& request,
QNetworkAccessManager* network, QObject* parent);
void Start();
void Start(CoverProviders* cover_providers);
// Cancels all pending requests. No Finished signals will be emitted, and it
// is the caller's responsibility to delete the AlbumCoverFetcherSearch.

View File

@ -20,19 +20,18 @@
#include "coverproviders.h"
#include "core/logging.h"
CoverProviders::CoverProviders()
: QObject(NULL) {
CoverProviders::CoverProviders(QObject* parent)
: QObject(parent) {
}
void CoverProviders::AddProvider(CoverProvider* provider) {
{
QMutexLocker locker(&mutex_);
cover_providers_.insert(provider, provider->name());
connect(provider, SIGNAL(destroyed()), SLOT(ProviderDestroyed()));
}
qLog(Debug) << "Registered cover provider" << provider->name();
connect(provider, SIGNAL(destroyed()), SLOT(ProviderDestroyed()));
}
void CoverProviders::RemoveProvider(CoverProvider* provider) {

View File

@ -25,27 +25,22 @@
class AlbumCoverFetcherSearch;
class CoverProvider;
// This is a singleton, a global repository for cover providers.
// Each one of those has to register with CoverProviders' instance by invoking
// "CoverProviders::instance().AddCoverProvider(this)". Providers are
// automatically unregistered from the repository when they are deleted.
// The class is thread safe except for the initialization.
// This is a repository for cover providers.
// Providers are automatically unregistered from the repository when they are
// deleted. The class is thread safe.
class CoverProviders : public QObject {
Q_OBJECT
public:
// This performs lazy initialization of the CoverProviders which is not thread-safe!
static CoverProviders& instance() {
static CoverProviders instance_;
return instance_;
}
CoverProviders(QObject* parent = NULL);
// Lets a cover provider to register itself in the repository.
// Lets a cover provider register itself in the repository.
void AddProvider(CoverProvider* provider);
void RemoveProvider(CoverProvider* provider);
// Returns a list of cover providers
QList<CoverProvider*> List() const { return cover_providers_.keys(); }
// Returns true if this repository has at least one registered provider.
bool HasAnyProviders() const { return !cover_providers_.isEmpty(); }
@ -55,8 +50,6 @@ private slots:
void ProviderDestroyed();
private:
CoverProviders();
~CoverProviders() {}
Q_DISABLE_COPY(CoverProviders);
QMap<CoverProvider*, QString> cover_providers_;

View File

@ -42,12 +42,13 @@ QMap<QString, InternetService*>* InternetModel::sServices = NULL;
InternetModel::InternetModel(BackgroundThread<Database>* db_thread,
TaskManager* task_manager, PlayerInterface* player,
QObject* parent)
CoverProviders* cover_providers, QObject* parent)
: QStandardItemModel(parent),
db_thread_(db_thread),
merged_model_(new MergedProxyModel(this)),
task_manager_(task_manager),
player_(player)
player_(player),
cover_providers_(cover_providers)
{
if (!sServices) {
sServices = new QMap<QString, InternetService*>;

View File

@ -24,6 +24,7 @@
#include "ui/settingsdialog.h"
#include "widgets/multiloadingindicator.h"
class CoverProviders;
class Database;
class MergedProxyModel;
class PlayerInterface;
@ -40,7 +41,8 @@ class InternetModel : public QStandardItemModel {
public:
InternetModel(BackgroundThread<Database>* db_thread, TaskManager* task_manager,
PlayerInterface* player, QObject* parent = 0);
PlayerInterface* player, CoverProviders* cover_providers,
QObject* parent = 0);
enum Role {
// Services can use this role to distinguish between different types of
@ -138,6 +140,7 @@ public:
MergedProxyModel* merged_model() const { return merged_model_; }
TaskManager* task_manager() const { return task_manager_; }
PlayerInterface* player() const { return player_; }
CoverProviders* cover_providers() const { return cover_providers_; }
signals:
void StreamError(const QString& message);
@ -155,6 +158,7 @@ private:
MergedProxyModel* merged_model_;
TaskManager* task_manager_;
PlayerInterface* player_;
CoverProviders* cover_providers_;
};
#endif // INTERNETMODEL_H

View File

@ -106,7 +106,7 @@ LastFMService::LastFMService(InternetModel* parent)
add_custom_action_->setEnabled(false);
model()->player()->RegisterUrlHandler(url_handler_);
CoverProviders::instance().AddProvider(new LastFmCoverProvider(this));
model()->cover_providers()->AddProvider(new LastFmCoverProvider(this));
}
LastFMService::~LastFMService() {

View File

@ -129,6 +129,7 @@ bool LibraryItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view,
LibraryView::LibraryView(QWidget* parent)
: AutoExpandingTreeView(parent),
cover_providers_(NULL),
library_(NULL),
total_song_count_(-1),
nomusic_(":nomusic.png"),
@ -161,6 +162,10 @@ void LibraryView::ReloadSettings() {
}
}
void LibraryView::SetCoverProviders(CoverProviders* cover_providers) {
cover_providers_ = cover_providers;
}
void LibraryView::SetTaskManager(TaskManager *task_manager) {
task_manager_ = task_manager;
}
@ -461,7 +466,7 @@ void LibraryView::Delete() {
void LibraryView::EditTracks() {
if(!edit_tag_dialog_) {
edit_tag_dialog_.reset(new EditTagDialog(this));
edit_tag_dialog_.reset(new EditTagDialog(cover_providers_, this));
}
edit_tag_dialog_->SetSongs(GetSelectedSongs());
edit_tag_dialog_->SetTagCompleter(library_->backend());

View File

@ -61,6 +61,7 @@ class LibraryView : public AutoExpandingTreeView {
// this will return all of it's songs.
SongList GetSelectedSongs() const;
void SetCoverProviders(CoverProviders* cover_providers);
void SetTaskManager(TaskManager* task_manager);
void SetLibrary(LibraryModel* library);
void SetDeviceManager(DeviceManager* device_manager);
@ -111,6 +112,7 @@ class LibraryView : public AutoExpandingTreeView {
void ShowInVarious(bool on);
private:
CoverProviders* cover_providers_;
LibraryModel* library_;
DeviceManager* devices_;
TaskManager* task_manager_;

View File

@ -370,6 +370,10 @@ int main(int argc, char *argv[]) {
// Seed the random number generator
srand(time(NULL));
// Initialize the repository of cover providers. Last.fm registers itself
// when its service is created.
CoverProviders cover_providers;
// Create some key objects
scoped_ptr<BackgroundThread<Database> > database(
new BackgroundThreadImplementation<Database, Database>(NULL));
@ -377,11 +381,8 @@ int main(int argc, char *argv[]) {
TaskManager task_manager;
PlaylistManager playlists(&task_manager, NULL);
Player player(&playlists);
InternetModel internet_model(database.get(), &task_manager, &player, NULL);
// Initialize the repository of cover providers to avoid race conditions
// later
CoverProviders::instance();
InternetModel internet_model(database.get(), &task_manager, &player,
&cover_providers, NULL);
#ifdef Q_OS_LINUX
// In 11.04 Ubuntu decided that the system tray should be reserved for certain
@ -418,7 +419,8 @@ int main(int argc, char *argv[]) {
&player,
tray_icon.get(),
&osd,
&art_loader);
&art_loader,
&cover_providers);
#ifdef HAVE_DBUS
QObject::connect(&mpris, SIGNAL(RaiseMainWindow()), &w, SLOT(Raise()));
#endif

View File

@ -48,14 +48,13 @@ QSet<QString>* AlbumCoverChoiceController::sImageExtensions = NULL;
AlbumCoverChoiceController::AlbumCoverChoiceController(QWidget* parent)
: QWidget(parent),
cover_providers_(NULL),
cover_searcher_(new AlbumCoverSearcher(QIcon(":/nocover.png"), this)),
cover_fetcher_(new AlbumCoverFetcher(this)),
cover_fetcher_(NULL),
save_file_dialog_(NULL),
cover_from_url_dialog_(NULL),
library_(NULL)
{
cover_searcher_->Init(cover_fetcher_);
cover_from_file_ = new QAction(IconLoader::Load("document-open"), tr("Load cover from disk..."), this);
cover_to_file_ = new QAction(IconLoader::Load("document-save"), tr("Save cover to disk..."), this);
cover_from_url_ = new QAction(IconLoader::Load("download"), tr("Load cover from URL..."), this);
@ -71,6 +70,12 @@ AlbumCoverChoiceController::~AlbumCoverChoiceController()
{
}
void AlbumCoverChoiceController::SetCoverProviders(CoverProviders* cover_providers) {
cover_providers_ = cover_providers;
cover_fetcher_ = new AlbumCoverFetcher(cover_providers_, this);
cover_searcher_->Init(cover_fetcher_);
}
QList<QAction*> AlbumCoverChoiceController::GetAllActions() {
return QList<QAction*>() << cover_from_file_ << cover_to_file_
<< separator_

View File

@ -26,6 +26,7 @@
class AlbumCoverFetcher;
class AlbumCoverSearcher;
class CoverFromURLDialog;
class CoverProviders;
class LibraryBackend;
class QFileDialog;
class Song;
@ -38,6 +39,8 @@ class AlbumCoverChoiceController : public QWidget {
AlbumCoverChoiceController(QWidget* parent = 0);
~AlbumCoverChoiceController();
void SetCoverProviders(CoverProviders* cover_providers);
// Getters for all QActions implemented by this controller.
QAction* cover_from_file_action() const { return cover_from_file_; }
@ -112,6 +115,7 @@ private:
static bool IsKnownImageExtension(const QString& suffix);
static QSet<QString>* sImageExtensions;
CoverProviders* cover_providers_;
AlbumCoverSearcher* cover_searcher_;
AlbumCoverFetcher* cover_fetcher_;

View File

@ -48,14 +48,17 @@
const char* AlbumCoverManager::kSettingsGroup = "CoverManager";
AlbumCoverManager::AlbumCoverManager(LibraryBackend* backend, QWidget* parent,
AlbumCoverManager::AlbumCoverManager(LibraryBackend* backend,
CoverProviders* cover_providers,
QWidget* parent,
QNetworkAccessManager* network)
: QMainWindow(parent),
ui_(new Ui_CoverManager),
cover_providers_(cover_providers),
album_cover_choice_controller_(new AlbumCoverChoiceController(this)),
backend_(backend),
cover_loader_(new BackgroundThreadImplementation<AlbumCoverLoader, AlbumCoverLoader>(this)),
cover_fetcher_(new AlbumCoverFetcher(this, network)),
cover_fetcher_(new AlbumCoverFetcher(cover_providers_, this, network)),
cover_searcher_(NULL),
artist_icon_(IconLoader::Load("x-clementine-artist")),
all_artists_icon_(IconLoader::Load("x-clementine-album")),
@ -73,6 +76,7 @@ AlbumCoverManager::AlbumCoverManager(LibraryBackend* backend, QWidget* parent,
ui_->action_add_to_playlist->setIcon(IconLoader::Load("media-playback-start"));
ui_->action_load->setIcon(IconLoader::Load("media-playback-start"));
album_cover_choice_controller_->SetCoverProviders(cover_providers_);
album_cover_choice_controller_->SetLibrary(backend_);
// Get a square version of nocover.png
@ -258,7 +262,7 @@ void AlbumCoverManager::Reset() {
}
void AlbumCoverManager::ResetFetchCoversButton() {
ui_->fetch->setEnabled(CoverProviders::instance().HasAnyProviders());
ui_->fetch->setEnabled(cover_providers_->HasAnyProviders());
}
void AlbumCoverManager::ArtistChanged(QListWidgetItem* current) {
@ -450,7 +454,7 @@ bool AlbumCoverManager::eventFilter(QObject *obj, QEvent *event) {
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);
album_cover_choice_controller_->search_for_cover_action()->setEnabled(CoverProviders::instance().HasAnyProviders());
album_cover_choice_controller_->search_for_cover_action()->setEnabled(cover_providers_->HasAnyProviders());
QContextMenuEvent* e = static_cast<QContextMenuEvent*>(event);
context_menu_->popup(e->globalPos());

View File

@ -32,6 +32,7 @@
class AlbumCoverChoiceController;
class AlbumCoverFetcher;
class AlbumCoverSearcher;
class CoverProviders;
class LibraryBackend;
class LineEditInterface;
class SongMimeData;
@ -45,7 +46,9 @@ class QProgressBar;
class AlbumCoverManager : public QMainWindow {
Q_OBJECT
public:
AlbumCoverManager(LibraryBackend* backend, QWidget *parent = 0,
AlbumCoverManager(LibraryBackend* backend,
CoverProviders* cover_providers,
QWidget *parent = 0,
QNetworkAccessManager* network = 0);
~AlbumCoverManager();
@ -142,6 +145,7 @@ class AlbumCoverManager : public QMainWindow {
private:
Ui_CoverManager* ui_;
CoverProviders* cover_providers_;
AlbumCoverChoiceController* album_cover_choice_controller_;
LibraryBackend* backend_;

View File

@ -44,9 +44,10 @@
const char* EditTagDialog::kHintText = QT_TR_NOOP("(different across multiple songs)");
EditTagDialog::EditTagDialog(QWidget* parent)
EditTagDialog::EditTagDialog(CoverProviders* cover_providers, QWidget* parent)
: QDialog(parent),
ui_(new Ui_EditTagDialog),
cover_providers_(cover_providers),
album_cover_choice_controller_(new AlbumCoverChoiceController(this)),
backend_(NULL),
loading_(false),
@ -70,6 +71,8 @@ EditTagDialog::EditTagDialog(QWidget* parent)
SLOT(FetchTagSongChosen(Song, Song)));
connect(results_dialog_, SIGNAL(finished(int)), tag_fetcher_, SLOT(Cancel()));
album_cover_choice_controller_->SetCoverProviders(cover_providers);
ui_->setupUi(this);
ui_->splitter->setSizes(QList<int>() << 200 << width() - 200);
ui_->loading_container->hide();
@ -430,7 +433,7 @@ void EditTagDialog::UpdateSummaryTab(const Song& song) {
else
ui_->filename->setText(song.url().toString());
album_cover_choice_controller_->search_for_cover_action()->setEnabled(CoverProviders::instance().HasAnyProviders());
album_cover_choice_controller_->search_for_cover_action()->setEnabled(cover_providers_->HasAnyProviders());
}
void EditTagDialog::UpdateStatisticsTab(const Song& song) {

View File

@ -31,6 +31,7 @@
class AlbumCoverChoiceController;
class AlbumCoverLoader;
class CoverProviders;
class LibraryBackend;
class Ui_EditTagDialog;
@ -43,7 +44,7 @@ class EditTagDialog : public QDialog {
Q_OBJECT
public:
EditTagDialog(QWidget* parent = 0);
EditTagDialog(CoverProviders* cover_providers, QWidget* parent = 0);
~EditTagDialog();
static const char* kHintText;
@ -134,6 +135,7 @@ private:
private:
Ui_EditTagDialog* ui_;
CoverProviders* cover_providers_;
AlbumCoverChoiceController* album_cover_choice_controller_;
LibraryBackend* backend_;

View File

@ -157,6 +157,7 @@ MainWindow::MainWindow(
SystemTrayIcon* tray_icon,
OSD* osd,
ArtLoader* art_loader,
CoverProviders* cover_providers,
QWidget* parent)
: QMainWindow(parent),
ui_(new Ui_MainWindow),
@ -165,6 +166,7 @@ MainWindow::MainWindow(
osd_(osd),
task_manager_(task_manager),
database_(database),
cover_providers_(cover_providers),
internet_model_(internet_model),
playlist_backend_(NULL),
playlists_(playlist_manager),
@ -219,6 +221,7 @@ MainWindow::MainWindow(
// Initialise the UI
ui_->setupUi(this);
ui_->multi_loading_indicator->SetTaskManager(task_manager_);
ui_->now_playing->SetCoverProviders(cover_providers_);
ui_->now_playing->SetLibraryBackend(library_->backend());
int volume = player_->GetVolume();
@ -1876,7 +1879,7 @@ void MainWindow::ChangeLibraryQueryMode(QAction* action) {
void MainWindow::ShowCoverManager() {
if (!cover_manager_) {
cover_manager_.reset(new AlbumCoverManager(library_->backend()));
cover_manager_.reset(new AlbumCoverManager(library_->backend(), cover_providers_));
cover_manager_->Init();
// Cover manager connections
@ -1924,7 +1927,7 @@ void MainWindow::EnsureEditTagDialogCreated() {
if (edit_tag_dialog_)
return;
edit_tag_dialog_.reset(new EditTagDialog);
edit_tag_dialog_.reset(new EditTagDialog(cover_providers_));
connect(edit_tag_dialog_.get(), SIGNAL(accepted()), SLOT(EditTagDialogAccepted()));
connect(edit_tag_dialog_.get(), SIGNAL(Error(QString)), SLOT(ShowErrorDialog(QString)));
}

View File

@ -38,6 +38,7 @@ class ArtistInfoView;
class ArtLoader;
class BackgroundStreams;
class CommandlineOptions;
class CoverProviders;
class Database;
class DeviceManager;
class DeviceView;
@ -88,6 +89,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
SystemTrayIcon* tray_icon,
OSD* osd,
ArtLoader* art_loader,
CoverProviders* cover_providers,
QWidget *parent = 0);
~MainWindow();
@ -267,6 +269,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
boost::scoped_ptr<About> about_dialog_;
BackgroundThread<Database>* database_;
CoverProviders* cover_providers_;
InternetModel* internet_model_;
PlaylistBackend* playlist_backend_;
PlaylistManager* playlists_;

View File

@ -55,8 +55,9 @@ const int NowPlayingWidget::kBottomOffset = 0;
const int NowPlayingWidget::kTopBorder = 4;
NowPlayingWidget::NowPlayingWidget(QWidget *parent)
NowPlayingWidget::NowPlayingWidget(QWidget* parent)
: QWidget(parent),
cover_providers_(NULL),
album_cover_choice_controller_(new AlbumCoverChoiceController(this)),
cover_loader_(new BackgroundThreadImplementation<AlbumCoverLoader, AlbumCoverLoader>(this)),
kitten_loader_(NULL),
@ -134,6 +135,11 @@ NowPlayingWidget::NowPlayingWidget(QWidget *parent)
NowPlayingWidget::~NowPlayingWidget() {
}
void NowPlayingWidget::SetCoverProviders(CoverProviders* cover_providers) {
cover_providers_ = cover_providers;
album_cover_choice_controller_->SetCoverProviders(cover_providers_);
}
void NowPlayingWidget::CreateModeAction(Mode mode, const QString &text, QActionGroup *group, QSignalMapper* mapper) {
QAction* action = new QAction(text, group);
action->setCheckable(true);
@ -379,7 +385,8 @@ void NowPlayingWidget::contextMenuEvent(QContextMenuEvent* e) {
// initial 'enabled' values depending on the kitty mode
album_cover_choice_controller_->cover_from_file_action()->setEnabled(!aww_);
album_cover_choice_controller_->cover_from_url_action()->setEnabled(!aww_);
album_cover_choice_controller_->search_for_cover_action()->setEnabled(!aww_ && CoverProviders::instance().HasAnyProviders());
album_cover_choice_controller_->search_for_cover_action()->setEnabled(
!aww_ && cover_providers_->HasAnyProviders());
album_cover_choice_controller_->unset_cover_action()->setEnabled(!aww_);
album_cover_choice_controller_->show_cover_action()->setEnabled(!aww_);

View File

@ -27,6 +27,7 @@
class AlbumCoverChoiceController;
class AlbumCoverLoader;
class CoverProviders;
class FullscreenHypnotoad;
class LibraryBackend;
@ -60,6 +61,7 @@ public:
};
void SetLibraryBackend(LibraryBackend* backend);
void SetCoverProviders(CoverProviders* cover_providers);
void set_ideal_height(int height);
bool show_above_status_bar() const;
@ -111,6 +113,7 @@ private:
void DrawContents(QPainter* p);
private:
CoverProviders* cover_providers_;
AlbumCoverChoiceController* album_cover_choice_controller_;
BackgroundThread<AlbumCoverLoader>* cover_loader_;