Use a common LoadTracks implementation for most search providers

This commit is contained in:
David Sansome 2012-06-10 20:55:51 +01:00
parent 99463215bf
commit c9745bca5d
18 changed files with 110 additions and 113 deletions

View File

@ -56,8 +56,6 @@ void GlobalSearch::ConnectProvider(SearchProvider* provider) {
SLOT(SearchFinishedSlot(int)));
connect(provider, SIGNAL(ArtLoaded(int,QImage)),
SLOT(ArtLoadedSlot(int,QImage)));
connect(provider, SIGNAL(TracksLoaded(int,MimeData*)),
SIGNAL(TracksLoaded(int,MimeData*)));
connect(provider, SIGNAL(destroyed(QObject*)),
SLOT(ProviderDestroyedSlot(QObject*)));
}
@ -278,12 +276,23 @@ bool GlobalSearch::FindCachedPixmap(const SearchProvider::Result& result,
return pixmap_cache_.find(result.pixmap_cache_key_, pixmap);
}
int GlobalSearch::LoadTracksAsync(const SearchProvider::Result& result) {
const int id = next_id_ ++;
MimeData* GlobalSearch::LoadTracks(const SearchProvider::ResultList& results) {
// Different providers might create MimeData in different ways, so it's not
// possible to combine different providers. Just take the results from a
// single provider.
if (results.isEmpty()) {
return NULL;
}
result.provider_->LoadTracksAsync(id, result);
SearchProvider* first_provider = results[0].provider_;
SearchProvider::ResultList results_copy;
foreach (const SearchProvider::Result& result, results) {
if (result.provider_ == first_provider) {
results_copy << result;
}
}
return id;
return first_provider->LoadTracks(results);
}
bool GlobalSearch::SetProviderEnabled(const SearchProvider* const_provider,

View File

@ -47,7 +47,7 @@ public:
int SearchAsync(const QString& query);
int LoadArtAsync(const SearchProvider::Result& result);
int LoadTracksAsync(const SearchProvider::Result& result);
MimeData* LoadTracks(const SearchProvider::ResultList& results);
QStringList GetSuggestions(int max);
void CancelSearch(int id);
@ -72,8 +72,6 @@ signals:
void ArtLoaded(int id, const QPixmap& pixmap);
void TracksLoaded(int id, MimeData* mime_data);
void ProviderAdded(const SearchProvider* provider);
void ProviderRemoved(const SearchProvider* provider);

View File

@ -109,8 +109,6 @@ GlobalSearchView::GlobalSearchView(Application* app, QWidget* parent)
Qt::QueuedConnection);
connect(engine_, SIGNAL(ArtLoaded(int,QPixmap)), SLOT(ArtLoaded(int,QPixmap)),
Qt::QueuedConnection);
connect(engine_, SIGNAL(TracksLoaded(int,MimeData*)), SLOT(TracksLoaded(int,MimeData*)),
Qt::QueuedConnection);
ReloadSettings();
}
@ -373,24 +371,54 @@ void GlobalSearchView::ArtLoaded(int id, const QPixmap& pixmap) {
}
}
void GlobalSearchView::LoadTracks() {
QModelIndex index = ui_->results->currentIndex();
if (!index.isValid())
index = front_proxy_->index(0, 0);
if (!index.isValid())
void GlobalSearchView::GetChildResults(const QStandardItem* item,
SearchProvider::ResultList* results,
QSet<const QStandardItem*>* visited) const {
if (visited->contains(item)) {
return;
}
visited->insert(item);
const SearchProvider::Result result =
index.data(Role_Result).value<SearchProvider::Result>();
engine_->LoadTracksAsync(result);
// Does this item have children?
if (item->rowCount()) {
// Yes - visit all the children
for (int i=0 ; i<item->rowCount() ; ++i) {
GetChildResults(item->child(i), results, visited);
}
} else {
// No - it's a song, add its result
results->append(item->data(Role_Result).value<SearchProvider::Result>());
}
}
void GlobalSearchView::TracksLoaded(int id, MimeData* mime_data) {
if (!mime_data)
return;
MimeData* GlobalSearchView::LoadSelectedTracks() {
// Get all selected model indexes
QModelIndexList indexes = ui_->results->selectionModel()->selectedRows();
if (indexes.isEmpty()) {
// There's nothing selected - take the first thing in the model that isn't
// a divider.
for (int i=0 ; i<front_proxy_->rowCount() ; ++i) {
QModelIndex index = front_proxy_->index(i, 0);
if (!index.data(LibraryModel::Role_IsDivider).toBool()) {
indexes << index;
break;
}
}
}
mime_data->from_doubleclick_ = true;
emit AddToPlaylist(mime_data);
// Still got nothing? Give up.
if (indexes.isEmpty()) {
return;
}
// Get all the results in these indexes
SearchProvider::ResultList results;
QSet<const QStandardItem*> visited;
foreach (const QModelIndex& index, indexes) {
GetChildResults(front_model_->itemFromIndex(front_proxy_->mapToSource(index)),
&results, &visited);
}
// Get a MimeData for these results
return engine_->LoadTracks(results);
}

View File

@ -73,12 +73,15 @@ private slots:
void AddResults(int id, const SearchProvider::ResultList& results);
void ArtLoaded(int id, const QPixmap& pixmap);
void TracksLoaded(int id, MimeData* mime_data);
private:
void LoadTracks();
MimeData* LoadSelectedTracks();
QStandardItem* BuildContainers(const Song& metadata, QStandardItem* parent,
ContainerKey* key, int level = 0);
void GetChildResults(const QStandardItem* item,
SearchProvider::ResultList* results,
QSet<const QStandardItem*>* visited) const;
private:
Application* app_;

View File

@ -113,13 +113,6 @@ void GroovesharkSearchProvider::AlbumArtLoaded(quint64 id, const QImage& image)
emit ArtLoaded(original_id, image);
}
void GroovesharkSearchProvider::LoadTracksAsync(int id, const Result& result) {
InternetSongMimeData* mime_data = new InternetSongMimeData(service_);
mime_data->songs << result.metadata_;
emit TracksLoaded(id, mime_data);
}
bool GroovesharkSearchProvider::IsLoggedIn() {
return (service_ && service_->IsLoggedIn());
}

View File

@ -34,7 +34,6 @@ class GroovesharkSearchProvider : public SearchProvider {
// SearchProvider
void SearchAsync(int id, const QString& query);
void LoadArtAsync(int id, const Result& result);
void LoadTracksAsync(int id, const Result& result);
bool IsLoggedIn();
void ShowConfig();

View File

@ -68,12 +68,11 @@ SearchProvider::ResultList LibrarySearchProvider::Search(int id, const QString&
return ret;
}
void LibrarySearchProvider::LoadTracksAsync(int id, const Result& result) {
SongMimeData* mime_data = new SongMimeData;
mime_data->backend = backend_;
mime_data->songs = SongList() << result.metadata_;
MimeData* LibrarySearchProvider::LoadTracks(const ResultList& results) {
MimeData* ret = SearchProvider::LoadTracks(results);
static_cast<SongMimeData*>(ret)->backend = backend_;
emit TracksLoaded(id, mime_data);
return ret;
}
QString LibrarySearchProvider::GetSuggestion() {

View File

@ -31,7 +31,7 @@ public:
Application* app, QObject* parent = 0);
ResultList Search(int id, const QString& query);
void LoadTracksAsync(int id, const Result& result);
MimeData* LoadTracks(const ResultList& results);
QString GetSuggestion();
private:

View File

@ -25,7 +25,8 @@ SavedRadioSearchProvider::SavedRadioSearchProvider(SavedRadio* service,
: SimpleSearchProvider(app, parent),
service_(service)
{
Init(tr("Your radio streams"), "savedradio", IconLoader::Load("document-open-remote"));
Init(tr("Your radio streams"), "savedradio", IconLoader::Load("document-open-remote"),
MimeDataContainsUrlsOnly);
connect(service_, SIGNAL(StreamsChanged()), SLOT(MaybeRecreateItems()));
@ -45,10 +46,3 @@ void SavedRadioSearchProvider::RecreateItems() {
SetItems(items);
}
void SavedRadioSearchProvider::LoadTracksAsync(int id, const Result& result) {
MimeData* mime_data = new MimeData;
mime_data->setUrls(QList<QUrl>() << result.metadata_.url());
emit TracksLoaded(id, mime_data);
}

View File

@ -26,8 +26,6 @@ class SavedRadioSearchProvider : public SimpleSearchProvider {
public:
SavedRadioSearchProvider(SavedRadio* service, Application* app, QObject* parent);
void LoadTracksAsync(int id, const Result& result);
protected:
void RecreateItems();

View File

@ -20,6 +20,7 @@
#include "playlist/songmimedata.h"
#include <QPainter>
#include <QUrl>
#include <QtConcurrentRun>
const int SearchProvider::kArtHeight = 32;
@ -123,9 +124,25 @@ void SearchProvider::LoadArtAsync(int id, const Result& result) {
emit ArtLoaded(id, QImage());
}
void SearchProvider::LoadTracksAsync(int id, const Result& result) {
SongMimeData* mime_data = new SongMimeData;
mime_data->songs = SongList() << result.metadata_;
MimeData* SearchProvider::LoadTracks(const ResultList& results) {
MimeData* mime_data = NULL;
emit TracksLoaded(id, mime_data);
if (mime_data_contains_urls_only()) {
mime_data = new MimeData;
} else {
SongMimeData* song_mime_data = new SongMimeData;
mime_data = song_mime_data;
foreach (const Result& result, results) {
song_mime_data->songs << result.metadata_;
}
}
QList<QUrl> urls;
foreach (const Result& result, results) {
urls << result.metadata_.url();
}
mime_data->setUrls(urls);
return mime_data;
}

View File

@ -91,7 +91,13 @@ public:
// Normally providers get enabled unless the user chooses otherwise.
// Setting this flag indicates that this provider is disabled by default
// instead.
DisabledByDefault = 0x40
DisabledByDefault = 0x40,
// The default implementation of LoadTracksAsync normally creates a
// SongMimeData containing the entire metadata for each result being loaded.
// Setting this flag will cause a plain MimeData to be created containing
// only the URLs of the results.
MimeDataContainsUrlsOnly = 0x80
};
Q_DECLARE_FLAGS(Hints, Hint)
@ -108,6 +114,7 @@ public:
bool can_give_suggestions() const { return hints() & CanGiveSuggestions; }
bool is_disabled_by_default() const { return hints() & DisabledByDefault; }
bool is_enabled_by_default() const { return !is_disabled_by_default(); }
bool mime_data_contains_urls_only() const { return hints() & MimeDataContainsUrlsOnly; }
// Starts a search. Must emit ResultsAvailable zero or more times and then
// SearchFinished exactly once, using this ID.
@ -117,9 +124,10 @@ public:
// ResultsAvailable. Must emit ArtLoaded exactly once with this ID.
virtual void LoadArtAsync(int id, const Result& result);
// Starts loading tracks for a result that was previously emitted by
// ResultsAvailable. Must emit TracksLoaded exactly once with this ID.
virtual void LoadTracksAsync(int id, const Result& result);
// Loads tracks for results that were previously emitted by ResultsAvailable.
// The default implementation creates a SongMimeData with one Song for each
// Result, unless the MimeDataContainsUrlsOnly flag is set.
virtual MimeData* LoadTracks(const ResultList& results);
// Returns an example search string to display in the UI. The provider should
// pick one of its items at random. Remember to set the CanGiveSuggestions
@ -139,8 +147,6 @@ signals:
void ArtLoaded(int id, const QImage& image);
void TracksLoaded(int id, MimeData* mime_data);
protected:
// These functions treat queries in the same way as LibraryQuery. They're
// useful for figuring out whether you got a result because it matched in

View File

@ -91,19 +91,12 @@ SearchProvider::ResultList SimpleSearchProvider::Search(int id, const QString& q
return ret;
}
void SimpleSearchProvider::LoadTracksAsync(int id, const Result& result) {
Song metadata = result.metadata_;
metadata.set_filetype(Song::Type_Stream);
SongMimeData* mime_data = new SongMimeData;
mime_data->songs = SongList() << metadata;
emit TracksLoaded(id, mime_data);
}
void SimpleSearchProvider::SetItems(const ItemList& items) {
QMutexLocker l(&items_mutex_);
items_ = items;
for (ItemList::iterator it = items_.begin() ; it != items_.end() ; ++it) {
it->metadata_.set_filetype(Song::Type_Stream);
}
}
QString SimpleSearchProvider::GetSuggestion() {

View File

@ -32,7 +32,6 @@ public:
ResultList Search(int id, const QString& query);
// SearchProvider
void LoadTracksAsync(int id, const Result& result);
QString GetSuggestion();
protected slots:

View File

@ -47,8 +47,6 @@ SpotifyServer* SpotifySearchProvider::server() {
SLOT(SearchFinishedSlot(pb::spotify::SearchResponse)));
connect(server_, SIGNAL(ImageLoaded(QString,QImage)),
SLOT(ArtLoadedSlot(QString,QImage)));
connect(server_, SIGNAL(AlbumBrowseResults(pb::spotify::BrowseAlbumResponse)),
SLOT(AlbumBrowseResponse(pb::spotify::BrowseAlbumResponse)));
connect(server_, SIGNAL(destroyed()), SLOT(ServerDestroyed()));
return server_;
@ -133,32 +131,6 @@ void SpotifySearchProvider::ArtLoadedSlot(const QString& id, const QImage& image
emit ArtLoaded(orig_id, ScaleAndPad(image));
}
void SpotifySearchProvider::LoadTracksAsync(int id, const Result& result) {
SongMimeData* mime_data = new SongMimeData;
mime_data->songs << result.metadata_;
emit TracksLoaded(id, mime_data);
}
void SpotifySearchProvider::AlbumBrowseResponse(const pb::spotify::BrowseAlbumResponse& response) {
QString uri = QStringFromStdString(response.uri());
QMap<QString, int>::iterator it = pending_tracks_.find(uri);
if (it == pending_tracks_.end())
return;
const int orig_id = it.value();
pending_tracks_.erase(it);
SongMimeData* mime_data = new SongMimeData;
for (int i=0 ; i<response.track_size() ; ++i) {
Song song;
SpotifyService::SongFromProtobuf(response.track(i), &song);
mime_data->songs << song;
}
emit TracksLoaded(orig_id, mime_data);
}
bool SpotifySearchProvider::IsLoggedIn() {
if (server()) {
return service_->IsLoggedIn();

View File

@ -33,7 +33,6 @@ public:
void SearchAsync(int id, const QString& query);
void LoadArtAsync(int id, const Result& result);
void LoadTracksAsync(int id, const Result& result);
bool IsLoggedIn();
void ShowConfig();
@ -43,8 +42,6 @@ private slots:
void SearchFinishedSlot(const pb::spotify::SearchResponse& response);
void ArtLoadedSlot(const QString& id, const QImage& image);
void AlbumBrowseResponse(const pb::spotify::BrowseAlbumResponse& response);
private:
SpotifyServer* server();

View File

@ -31,7 +31,7 @@ UrlSearchProvider::UrlSearchProvider(Application* app, QObject* parent)
QIcon icon = IconLoader::Load("applications-internet");
image_ = ScaleAndPad(icon.pixmap(kArtHeight, kArtHeight).toImage());
Init("URL", "url", icon);
Init("URL", "url", icon, MimeDataContainsUrlsOnly);
}
void UrlSearchProvider::SearchAsync(int id, const QString& query) {
@ -47,13 +47,6 @@ 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<QUrl>() << result.metadata_.url());
emit TracksLoaded(id, mime_data);
}
bool UrlSearchProvider::LooksLikeUrl(const QString& query) const {
return url_regex_.indexIn(query) == 0;
}

View File

@ -30,7 +30,6 @@ public:
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;