From 691cb9a392f0ae4e8a6efbc11fb50d2f6e5eb833 Mon Sep 17 00:00:00 2001 From: David Sansome Date: Fri, 11 Nov 2011 22:11:25 +0000 Subject: [PATCH] Treat URLs specially in the global search widget --- src/CMakeLists.txt | 1 + src/globalsearch/globalsearch.cpp | 51 ++++++++++------ src/globalsearch/globalsearch.h | 5 ++ src/globalsearch/globalsearchitemdelegate.cpp | 2 +- src/globalsearch/savedradiosearchprovider.cpp | 5 +- src/globalsearch/urlsearchprovider.cpp | 59 +++++++++++++++++++ src/globalsearch/urlsearchprovider.h | 42 +++++++++++++ 7 files changed, 141 insertions(+), 24 deletions(-) create mode 100644 src/globalsearch/urlsearchprovider.cpp create mode 100644 src/globalsearch/urlsearchprovider.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9268da031..35688c93e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -134,6 +134,7 @@ set(SOURCES globalsearch/somafmsearchprovider.cpp globalsearch/tooltipactionwidget.cpp globalsearch/tooltipresultwidget.cpp + globalsearch/urlsearchprovider.cpp internet/digitallyimportedclient.cpp internet/digitallyimportedservicebase.cpp diff --git a/src/globalsearch/globalsearch.cpp b/src/globalsearch/globalsearch.cpp index b104d2f20..b3618d61b 100644 --- a/src/globalsearch/globalsearch.cpp +++ b/src/globalsearch/globalsearch.cpp @@ -17,6 +17,7 @@ #include "librarysearchprovider.h" #include "globalsearch.h" +#include "urlsearchprovider.h" #include "core/logging.h" #include "covers/albumcoverloader.h" @@ -32,7 +33,8 @@ const int GlobalSearch::kMaxResultsPerEmission = 100; GlobalSearch::GlobalSearch(QObject* parent) : QObject(parent), next_id_(1), - cover_loader_(new BackgroundThreadImplementation(this)) + cover_loader_(new BackgroundThreadImplementation(this)), + url_provider_(new UrlSearchProvider(this)) { cover_loader_->Start(true); cover_loader_->Worker()->SetDesiredHeight(SearchProvider::kArtHeight); @@ -42,11 +44,11 @@ GlobalSearch::GlobalSearch(QObject* parent) connect(cover_loader_->Worker().get(), SIGNAL(ImageLoaded(quint64,QImage)), SLOT(AlbumArtLoaded(quint64,QImage))); + + ConnectProvider(url_provider_); } -void GlobalSearch::AddProvider(SearchProvider* provider, bool enable_by_default) { - Q_ASSERT(!provider->name().isEmpty()); - +void GlobalSearch::ConnectProvider(SearchProvider* provider) { connect(provider, SIGNAL(ResultsAvailable(int,SearchProvider::ResultList)), SLOT(ResultsAvailableSlot(int,SearchProvider::ResultList))); connect(provider, SIGNAL(SearchFinished(int)), @@ -57,6 +59,12 @@ void GlobalSearch::AddProvider(SearchProvider* provider, bool enable_by_default) SIGNAL(TracksLoaded(int,MimeData*))); connect(provider, SIGNAL(destroyed(QObject*)), SLOT(ProviderDestroyedSlot(QObject*))); +} + +void GlobalSearch::AddProvider(SearchProvider* provider, bool enable_by_default) { + Q_ASSERT(!provider->name().isEmpty()); + + ConnectProvider(provider); ProviderData data; data.enabled_ = providers_state_preference_.contains(provider->id()) ? @@ -68,25 +76,29 @@ void GlobalSearch::AddProvider(SearchProvider* provider, bool enable_by_default) int GlobalSearch::SearchAsync(const QString& query) { const int id = next_id_ ++; + pending_search_providers_[id] = 0; int timer_id = -1; - pending_search_providers_[id] = 0; - foreach (SearchProvider* provider, providers_.keys()) { - if (!providers_[provider].enabled_) - continue; + if (url_provider_->LooksLikeUrl(query)) { + url_provider_->SearchAsync(id, query); + } else { + foreach (SearchProvider* provider, providers_.keys()) { + if (!providers_[provider].enabled_) + continue; - pending_search_providers_[id] ++; + pending_search_providers_[id] ++; - if (provider->wants_delayed_queries()) { - if (timer_id == -1) { - timer_id = startTimer(kDelayedSearchTimeoutMs); - delayed_searches_[timer_id].id_ = id; - delayed_searches_[timer_id].query_ = query; + if (provider->wants_delayed_queries()) { + if (timer_id == -1) { + timer_id = startTimer(kDelayedSearchTimeoutMs); + delayed_searches_[timer_id].id_ = id; + delayed_searches_[timer_id].query_ = query; + } + delayed_searches_[timer_id].providers_ << provider; + } else { + provider->SearchAsync(id, query); } - delayed_searches_[timer_id].providers_ << provider; - } else { - provider->SearchAsync(id, query); } } @@ -183,7 +195,7 @@ int GlobalSearch::LoadArtAsync(const SearchProvider::Result& result) { pending_art_searches_[id] = result.pixmap_cache_key_; - if (!providers_.contains(result.provider_) || + if (providers_.contains(result.provider_) && !providers_[result.provider_].enabled_) { emit ArtLoaded(id, QPixmap()); return id; @@ -192,7 +204,8 @@ int GlobalSearch::LoadArtAsync(const SearchProvider::Result& result) { if (result.provider_->art_is_in_song_metadata()) { quint64 loader_id = cover_loader_->Worker()->LoadImageAsync(result.metadata_); cover_loader_tasks_[loader_id] = id; - } else if (result.provider_->wants_serialised_art()) { + } else if (providers_.contains(result.provider_) && + result.provider_->wants_serialised_art()) { QueuedArt request; request.id_ = id; request.result_ = result; diff --git a/src/globalsearch/globalsearch.h b/src/globalsearch/globalsearch.h index 781ea4d84..2d56226c5 100644 --- a/src/globalsearch/globalsearch.h +++ b/src/globalsearch/globalsearch.h @@ -26,6 +26,7 @@ class AlbumCoverLoader; +class UrlSearchProvider; class GlobalSearch : public QObject { Q_OBJECT @@ -86,6 +87,7 @@ private slots: void ProviderDestroyedSlot(QObject* object); private: + void ConnectProvider(SearchProvider* provider); void HandleLoadedArt(int id, const QImage& image, SearchProvider* provider); void TakeNextQueuedArt(SearchProvider* provider); QString PixmapCacheKey(const SearchProvider::Result& result) const; @@ -124,6 +126,9 @@ private: // Used for providers with ArtIsInSongMetadata set. BackgroundThread* cover_loader_; QMap cover_loader_tasks_; + + // Special search provider that's used for queries that look like URLs + UrlSearchProvider* url_provider_; }; #endif // GLOBALSEARCH_H diff --git a/src/globalsearch/globalsearchitemdelegate.cpp b/src/globalsearch/globalsearchitemdelegate.cpp index c5a7693ee..c9512b3ce 100644 --- a/src/globalsearch/globalsearchitemdelegate.cpp +++ b/src/globalsearch/globalsearchitemdelegate.cpp @@ -133,7 +133,7 @@ void GlobalSearchItemDelegate::paint(QPainter* p, case globalsearch::Type_Track: case globalsearch::Type_Stream: { // Title - line_1 += m.title() + " "; + line_1 += m.PrettyTitle() + " "; // Artist - Album - Track n if (!m.artist().isEmpty()) { diff --git a/src/globalsearch/savedradiosearchprovider.cpp b/src/globalsearch/savedradiosearchprovider.cpp index ba1651980..016eb9b78 100644 --- a/src/globalsearch/savedradiosearchprovider.cpp +++ b/src/globalsearch/savedradiosearchprovider.cpp @@ -46,11 +46,8 @@ void SavedRadioSearchProvider::RecreateItems() { } void SavedRadioSearchProvider::LoadTracksAsync(int id, const Result& result) { - Song metadata = result.metadata_; - metadata.set_filetype(Song::Type_Stream); - MimeData* mime_data = new MimeData; - mime_data->setUrls(QList() << metadata.url()); + mime_data->setUrls(QList() << result.metadata_.url()); emit TracksLoaded(id, mime_data); } diff --git a/src/globalsearch/urlsearchprovider.cpp b/src/globalsearch/urlsearchprovider.cpp new file mode 100644 index 000000000..eb36e9f90 --- /dev/null +++ b/src/globalsearch/urlsearchprovider.cpp @@ -0,0 +1,59 @@ +/* This file is part of Clementine. + Copyright 2011, David Sansome + + 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 . +*/ + +#include "urlsearchprovider.h" +#include "core/mimedata.h" +#include "ui/iconloader.h" + +#include + +const char* UrlSearchProvider::kUrlRegex = "^[a-zA-Z][a-zA-Z0-9+-.]*://"; + +UrlSearchProvider::UrlSearchProvider(QObject* parent) + : SearchProvider(parent), + url_regex_(kUrlRegex) +{ + QIcon icon = IconLoader::Load("applications-internet"); + image_ = ScaleAndPad(icon.pixmap(kArtHeight, kArtHeight).toImage()); + + Init("URL", "url", icon); +} + +void UrlSearchProvider::SearchAsync(int id, const QString& query) { + Result result(this); + result.match_quality_ = globalsearch::Quality_AtStart; + result.type_ = globalsearch::Type_Stream; + result.metadata_.set_url(QUrl::fromUserInput(query)); + result.metadata_.set_filetype(Song::Type_Stream); + + emit ResultsAvailable(id, ResultList() << result); +} + +void UrlSearchProvider::LoadArtAsync(int id, const Result&) { + emit ArtLoaded(id, image_); +} + +void UrlSearchProvider::LoadTracksAsync(int id, const Result& result) { + MimeData* mime_data = new MimeData; + mime_data->setUrls(QList() << result.metadata_.url()); + + emit TracksLoaded(id, mime_data); +} + +bool UrlSearchProvider::LooksLikeUrl(const QString& query) const { + return url_regex_.indexIn(query) == 0; +} diff --git a/src/globalsearch/urlsearchprovider.h b/src/globalsearch/urlsearchprovider.h new file mode 100644 index 000000000..6283b7ff8 --- /dev/null +++ b/src/globalsearch/urlsearchprovider.h @@ -0,0 +1,42 @@ +/* This file is part of Clementine. + Copyright 2011, David Sansome + + 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 . +*/ + +#ifndef URLSEARCHPROVIDER_H +#define URLSEARCHPROVIDER_H + +#include "searchprovider.h" + +#include + +class UrlSearchProvider : public SearchProvider { +public: + UrlSearchProvider(QObject* parent); + + bool LooksLikeUrl(const QString& query) const; + + void SearchAsync(int id, const QString& query); + void LoadArtAsync(int id, const Result& result); + void LoadTracksAsync(int id, const Result& result); + +private: + static const char* kUrlRegex; + QRegExp url_regex_; + + QImage image_; +}; + +#endif // URLSEARCHPROVIDER_H