From 547a009d736f9359be867af13db40d3576c55eae Mon Sep 17 00:00:00 2001 From: David Sansome Date: Sat, 9 Oct 2010 13:34:28 +0000 Subject: [PATCH] Show all the artist info at once rather than as it arrives, make resizing the text areas smoother, remove duplicate biogoraphies. --- src/songinfo/artistinfofetcher.cpp | 37 +++++++++++++++++++++++++++-- src/songinfo/artistinfofetcher.h | 15 +++++++++++- src/songinfo/artistinfoprovider.h | 1 + src/songinfo/artistinfoview.cpp | 30 +++++++++++------------ src/songinfo/artistinfoview.h | 4 ++-- src/songinfo/echonestartistinfo.cpp | 28 ++++++++++++++-------- src/widgets/autosizedtextedit.cpp | 6 ++++- src/widgets/autosizedtextedit.h | 3 +++ 8 files changed, 92 insertions(+), 32 deletions(-) diff --git a/src/songinfo/artistinfofetcher.cpp b/src/songinfo/artistinfofetcher.cpp index 9f326ffab..fd49602e3 100644 --- a/src/songinfo/artistinfofetcher.cpp +++ b/src/songinfo/artistinfofetcher.cpp @@ -26,14 +26,47 @@ ArtistInfoFetcher::ArtistInfoFetcher(QObject* parent) void ArtistInfoFetcher::AddProvider(ArtistInfoProvider* provider) { providers_ << provider; - connect(provider, SIGNAL(ImageReady(int,QUrl)), SIGNAL(ImageReady(int,QUrl))); - connect(provider, SIGNAL(InfoReady(int,CollapsibleInfoPane::Data)), SIGNAL(InfoReady(int,CollapsibleInfoPane::Data))); + connect(provider, SIGNAL(ImageReady(int,QUrl)), SLOT(ImageReady(int,QUrl))); + connect(provider, SIGNAL(InfoReady(int,CollapsibleInfoPane::Data)), SLOT(InfoReady(int,CollapsibleInfoPane::Data))); + connect(provider, SIGNAL(Finished(int)), SLOT(ProviderFinished(int))); } int ArtistInfoFetcher::FetchInfo(const QString& artist) { const int id = next_id_ ++; + results_[id] = Result(); + foreach (ArtistInfoProvider* provider, providers_) { + waiting_for_[id].append(provider); provider->FetchInfo(id, artist); } return id; } + +void ArtistInfoFetcher::ImageReady(int id, const QUrl& url) { + if (!results_.contains(id)) + return; + results_[id].images_ << url; +} + +void ArtistInfoFetcher::InfoReady(int id, const CollapsibleInfoPane::Data& data) { + if (!results_.contains(id)) + return; + results_[id].info_ << data; +} + +void ArtistInfoFetcher::ProviderFinished(int id) { + if (!results_.contains(id)) + return; + if (!waiting_for_.contains(id)) + return; + + ArtistInfoProvider* provider = qobject_cast(sender()); + if (!waiting_for_[id].contains(provider)) + return; + + waiting_for_[id].removeAll(provider); + if (waiting_for_[id].isEmpty()) { + emit ResultReady(id, results_.take(id)); + waiting_for_.remove(id); + } +} diff --git a/src/songinfo/artistinfofetcher.h b/src/songinfo/artistinfofetcher.h index e329391be..afdf8d685 100644 --- a/src/songinfo/artistinfofetcher.h +++ b/src/songinfo/artistinfofetcher.h @@ -17,6 +17,7 @@ #ifndef ARTISTINFOFETCHER_H #define ARTISTINFOFETCHER_H +#include #include #include @@ -30,11 +31,20 @@ class ArtistInfoFetcher : public QObject { public: ArtistInfoFetcher(QObject* parent = 0); + struct Result { + QList images_; + QList info_; + }; + int FetchInfo(const QString& artist); signals: + void ResultReady(int id, const ArtistInfoFetcher::Result& result); + +private slots: void ImageReady(int id, const QUrl& url); - void InfoReady(int id, const CollapsibleInfoPane::Data&); + void InfoReady(int id, const CollapsibleInfoPane::Data& data); + void ProviderFinished(int id); private: void AddProvider(ArtistInfoProvider* provider); @@ -42,6 +52,9 @@ private: private: QList providers_; + QMap results_; + QMap > waiting_for_; + int next_id_; }; diff --git a/src/songinfo/artistinfoprovider.h b/src/songinfo/artistinfoprovider.h index a42caebb5..36ecbd861 100644 --- a/src/songinfo/artistinfoprovider.h +++ b/src/songinfo/artistinfoprovider.h @@ -33,6 +33,7 @@ public: signals: void ImageReady(int id, const QUrl& url); void InfoReady(int id, const CollapsibleInfoPane::Data& data); + void Finished(int id); }; #endif // ARTISTINFOPROVIDER_H diff --git a/src/songinfo/artistinfoview.cpp b/src/songinfo/artistinfoview.cpp index 8a66aed48..7f35baccf 100644 --- a/src/songinfo/artistinfoview.cpp +++ b/src/songinfo/artistinfoview.cpp @@ -34,8 +34,8 @@ ArtistInfoView::ArtistInfoView(NetworkAccessManager* network, QWidget *parent) image_view_(NULL), section_container_(NULL) { - connect(fetcher_, SIGNAL(ImageReady(int,QUrl)), SLOT(ImageReady(int,QUrl))); - connect(fetcher_, SIGNAL(InfoReady(int,CollapsibleInfoPane::Data)), SLOT(InfoReady(int,CollapsibleInfoPane::Data))); + connect(fetcher_, SIGNAL(ResultReady(int,ArtistInfoFetcher::Result)), + SLOT(ResultReady(int,ArtistInfoFetcher::Result))); // Add the top-level scroll area setLayout(new QVBoxLayout); @@ -88,8 +88,14 @@ bool ArtistInfoView::NeedsUpdate(const Song& old_metadata, const Song& new_metad } void ArtistInfoView::Update(const Song& metadata) { - Clear(); current_request_id_ = fetcher_->FetchInfo(metadata.artist()); +} + +void ArtistInfoView::ResultReady(int id, const ArtistInfoFetcher::Result& result) { + if (id != current_request_id_) + return; + + Clear(); // Image view goes at the top image_view_ = new PrettyImageView(network_); @@ -102,20 +108,12 @@ void ArtistInfoView::Update(const Song& metadata) { section_container_->layout()->setSpacing(1); section_container_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); container_->insertWidget(1, section_container_); -} -void ArtistInfoView::ImageReady(int id, const QUrl& url) { - if (id != current_request_id_) - return; - - image_view_->AddImage(url); -} - -void ArtistInfoView::InfoReady(int id, const CollapsibleInfoPane::Data& data) { - if (id != current_request_id_) { - delete data.contents_; - return; + foreach (const QUrl& url, result.images_) { + image_view_->AddImage(url); } - AddSection(new CollapsibleInfoPane(data, this)); + foreach (const CollapsibleInfoPane::Data& data, result.info_) { + AddSection(new CollapsibleInfoPane(data, this)); + } } diff --git a/src/songinfo/artistinfoview.h b/src/songinfo/artistinfoview.h index 1648cb2a2..cdd39fd07 100644 --- a/src/songinfo/artistinfoview.h +++ b/src/songinfo/artistinfoview.h @@ -17,6 +17,7 @@ #ifndef ARTISTINFOVIEW_H #define ARTISTINFOVIEW_H +#include "artistinfofetcher.h" #include "collapsibleinfopane.h" #include "songinfobase.h" @@ -42,8 +43,7 @@ private: void Clear(); private slots: - void ImageReady(int id, const QUrl& url); - void InfoReady(int id, const CollapsibleInfoPane::Data& data); + void ResultReady(int id, const ArtistInfoFetcher::Result& result); private: ArtistInfoFetcher* fetcher_; diff --git a/src/songinfo/echonestartistinfo.cpp b/src/songinfo/echonestartistinfo.cpp index ec4b8c2b9..bee1f8841 100644 --- a/src/songinfo/echonestartistinfo.cpp +++ b/src/songinfo/echonestartistinfo.cpp @@ -24,6 +24,8 @@ struct EchoNestArtistInfo::Request { Request(int id) : id_(id), artist_(new Echonest::Artist) {} + bool is_finished() const { return pending_replies_.isEmpty(); } + int id_; boost::scoped_ptr artist_; QList pending_replies_; @@ -33,7 +35,6 @@ EchoNestArtistInfo::EchoNestArtistInfo(QObject* parent) : ArtistInfoProvider(parent) { site_relevance_["wikipedia"] = 100; - site_relevance_["last.fm"] = 60; site_relevance_["lastfm"] = 60; site_relevance_["amazon"] = 30; @@ -41,7 +42,6 @@ EchoNestArtistInfo::EchoNestArtistInfo(QObject* parent) site_icons_["aol"] = QIcon(":/providers/aol.png"); site_icons_["cdbaby"] = QIcon(":/providers/cdbaby.png"); site_icons_["lastfm"] = QIcon(":/last.fm/as.png"); - site_icons_["last.fm"] = QIcon(":/last.fm/as.png"); site_icons_["mog"] = QIcon(":/providers/mog.png"); site_icons_["mtvmusic"] = QIcon(":/providers/mtvmusic.png"); site_icons_["myspace"] = QIcon(":/providers/myspace.png"); @@ -77,7 +77,7 @@ EchoNestArtistInfo::RequestPtr EchoNestArtistInfo::ReplyFinished(QNetworkReply* request->pending_replies_.removeAll(reply); - if (request->pending_replies_.isEmpty()) { + if (request->is_finished()) { requests_.removeAll(request); } @@ -93,6 +93,9 @@ void EchoNestArtistInfo::ImagesFinished() { foreach (const Echonest::ArtistImage& image, request->artist_->images()) { emit ImageReady(request->id_, image.url()); } + + if (request->is_finished()) + emit Finished(request->id_); } void EchoNestArtistInfo::BiographiesFinished() { @@ -101,19 +104,21 @@ void EchoNestArtistInfo::BiographiesFinished() { QSet already_seen; foreach (const Echonest::Biography& bio, request->artist_->biographies()) { - if (already_seen.contains(bio.text())) + QString canonical_site = bio.site().toLower(); + canonical_site.replace(QRegExp("[^a-z]"),""); + + if (already_seen.contains(canonical_site)) continue; - already_seen.insert(bio.text()); + already_seen.insert(canonical_site); CollapsibleInfoPane::Data data; data.title_ = tr("Biography from %1").arg(bio.site()); data.type_ = CollapsibleInfoPane::Data::Type_Biography; - const QString site = bio.site().toLower(); - if (site_relevance_.contains(site)) - data.relevance_ = site_relevance_[site]; - if (site_icons_.contains(site)) - data.icon_ = site_icons_[site]; + if (site_relevance_.contains(canonical_site)) + data.relevance_ = site_relevance_[canonical_site]; + if (site_icons_.contains(canonical_site)) + data.icon_ = site_icons_[canonical_site]; AutoSizedTextEdit* editor = new AutoSizedTextEdit; editor->setHtml(bio.text()); @@ -121,4 +126,7 @@ void EchoNestArtistInfo::BiographiesFinished() { emit InfoReady(request->id_, data); } + + if (request->is_finished()) + emit Finished(request->id_); } diff --git a/src/widgets/autosizedtextedit.cpp b/src/widgets/autosizedtextedit.cpp index d29a9986e..cda6f700b 100644 --- a/src/widgets/autosizedtextedit.cpp +++ b/src/widgets/autosizedtextedit.cpp @@ -19,7 +19,8 @@ #include AutoSizedTextEdit::AutoSizedTextEdit(QWidget* parent) - : QTextEdit(parent) + : QTextEdit(parent), + last_width_(-1) { setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -27,6 +28,9 @@ AutoSizedTextEdit::AutoSizedTextEdit(QWidget* parent) void AutoSizedTextEdit::resizeEvent(QResizeEvent* e) { const int w = qMax(100, width()); + if (w == last_width_) + return; + last_width_ = w; document()->setTextWidth(w); setMinimumHeight(document()->size().height()); diff --git a/src/widgets/autosizedtextedit.h b/src/widgets/autosizedtextedit.h index c9f09fb10..e705a4f26 100644 --- a/src/widgets/autosizedtextedit.h +++ b/src/widgets/autosizedtextedit.h @@ -30,6 +30,9 @@ public: protected: void resizeEvent(QResizeEvent* e); void wheelEvent(QWheelEvent* e); + +private: + int last_width_; }; #endif // AUTOSIZEDTEXTEDIT_H