Add a flag that search providers can set to indicate they want some delay between user input and being asked to search

This commit is contained in:
David Sansome 2011-08-29 00:13:36 +01:00
parent 8dea8a2664
commit dbffe16d04
7 changed files with 78 additions and 13 deletions

View File

@ -22,6 +22,9 @@
#include <QStringBuilder>
#include <QUrl>
const int GlobalSearch::kDelayedSearchTimeoutMs = 200;
GlobalSearch::GlobalSearch(QObject* parent)
: QObject(parent),
next_id_(1)
@ -29,6 +32,8 @@ GlobalSearch::GlobalSearch(QObject* parent)
}
void GlobalSearch::AddProvider(SearchProvider* provider) {
Q_ASSERT(!provider->name().isEmpty());
connect(provider, SIGNAL(ResultsAvailable(int,SearchProvider::ResultList)),
SLOT(ResultsAvailableSlot(int,SearchProvider::ResultList)));
connect(provider, SIGNAL(SearchFinished(int)),
@ -44,14 +49,47 @@ void GlobalSearch::AddProvider(SearchProvider* provider) {
int GlobalSearch::SearchAsync(const QString& query) {
const int id = next_id_ ++;
int timer_id = -1;
pending_search_providers_[id] = providers_.count();
foreach (SearchProvider* provider, providers_) {
provider->SearchAsync(id, query);
if (provider->wants_delayed_queries()) {
if (timer_id == -1) {
timer_id = startTimer(kDelayedSearchTimeoutMs);
delayed_searches_[id].timer_id_ = timer_id;
delayed_searches_[id].query_ = query;
}
delayed_searches_[id].providers_ << provider;
} else {
provider->SearchAsync(id, query);
}
}
return id;
}
void GlobalSearch::CancelSearch(int id) {
if (delayed_searches_.contains(id)) {
killTimer(delayed_searches_[id].timer_id_);
delayed_searches_.remove(id);
}
}
void GlobalSearch::timerEvent(QTimerEvent* e) {
QMap<int, DelayedSearch>::iterator it;
for (it = delayed_searches_.begin() ; it != delayed_searches_.end() ; ++it) {
if (it.value().timer_id_ == e->timerId()) {
foreach (SearchProvider* provider, it.value().providers_) {
provider->SearchAsync(it.key(), it.value().query_);
}
delayed_searches_.erase(it);
return;
}
}
QObject::timerEvent(e);
}
QString GlobalSearch::PixmapCacheKey(const SearchProvider::Result& result) const {
return QString::number(qulonglong(result.provider_))
% "," % QString::number(int(result.type_))

View File

@ -30,11 +30,16 @@ class GlobalSearch : public QObject {
public:
GlobalSearch(QObject* parent = 0);
static const int kDelayedSearchTimeoutMs;
void AddProvider(SearchProvider* provider);
int SearchAsync(const QString& query);
int LoadArtAsync(const SearchProvider::Result& result);
void CancelSearch(int id);
void CancelArt(int id);
bool FindCachedPixmap(const SearchProvider::Result& result, QPixmap* pixmap) const;
signals:
@ -46,6 +51,9 @@ signals:
void ProviderDestroyed(SearchProvider* provider);
protected:
void timerEvent(QTimerEvent* e);
private slots:
void ResultsAvailableSlot(int id, SearchProvider::ResultList results);
void SearchFinishedSlot(int id);
@ -58,8 +66,16 @@ private:
QString PixmapCacheKey(const SearchProvider::Result& result) const;
private:
struct DelayedSearch {
int timer_id_;
QString query_;
QList<SearchProvider*> providers_;
};
QList<SearchProvider*> providers_;
QMap<int, DelayedSearch> delayed_searches_;
int next_id_;
QMap<int, int> pending_search_providers_;

View File

@ -141,6 +141,7 @@ void GlobalSearchWidget::TextEdited(const QString& text) {
}
clear_model_on_next_result_ = true;
engine_->CancelSearch(last_id_);
last_id_ = engine_->SearchAsync(trimmed_text);
}

View File

@ -27,10 +27,12 @@ LibrarySearchProvider::LibrarySearchProvider(LibraryBackendInterface* backend,
const QString& name,
const QIcon& icon,
QObject* parent)
: BlockingSearchProvider(name, icon, parent),
: BlockingSearchProvider(parent),
backend_(backend),
cover_loader_(new BackgroundThreadImplementation<AlbumCoverLoader, AlbumCoverLoader>(this))
{
Init(name, icon, false);
cover_loader_->Start(true);
cover_loader_->Worker()->SetDesiredHeight(kArtHeight);
cover_loader_->Worker()->SetPadOutputImage(true);

View File

@ -24,14 +24,17 @@
const int SearchProvider::kArtHeight = 32;
SearchProvider::SearchProvider(const QString& name, const QIcon& icon,
QObject* parent)
: QObject(parent),
name_(name),
icon_(icon)
SearchProvider::SearchProvider(QObject* parent)
: QObject(parent)
{
}
void SearchProvider::Init(const QString& name, const QIcon& icon, bool query_lag) {
name_ = name;
icon_ = icon;
query_lag_ = query_lag;
}
QStringList SearchProvider::TokenizeQuery(const QString& query) {
QStringList tokens(query.split(QRegExp("\\s+")));
@ -65,8 +68,8 @@ SearchProvider::Result::MatchQuality SearchProvider::MatchQuality(
return ret;
}
BlockingSearchProvider::BlockingSearchProvider(const QString& name, const QIcon& icon, QObject* parent)
: SearchProvider(name, icon, parent) {
BlockingSearchProvider::BlockingSearchProvider(QObject* parent)
: SearchProvider(parent) {
}
void BlockingSearchProvider::SearchAsync(int id, const QString& query) {

View File

@ -28,7 +28,7 @@ class SearchProvider : public QObject {
Q_OBJECT
public:
SearchProvider(const QString& name, const QIcon& icon, QObject* parent = 0);
SearchProvider(QObject* parent = 0);
static const int kArtHeight;
@ -70,6 +70,7 @@ public:
const QString& name() const { return name_; }
const QIcon& icon() const { return icon_; }
const bool wants_delayed_queries() const { return query_lag_; }
// Starts a search. Must emit ResultsAvailable zero or more times and then
// SearchFinished exactly once, using this ID.
@ -100,9 +101,13 @@ protected:
static QStringList TokenizeQuery(const QString& query);
static Result::MatchQuality MatchQuality(const QStringList& tokens, const QString& string);
// Subclasses must call this from their constructor
void Init(const QString& name, const QIcon& icon, bool query_lag);
private:
QString name_;
QIcon icon_;
bool query_lag_;
};
Q_DECLARE_METATYPE(SearchProvider::Result)
@ -112,8 +117,7 @@ class BlockingSearchProvider : public SearchProvider {
Q_OBJECT
public:
BlockingSearchProvider(const QString& name, const QIcon& icon,
QObject* parent = 0);
BlockingSearchProvider(QObject* parent = 0);
void SearchAsync(int id, const QString& query);

View File

@ -21,10 +21,11 @@
#include "internet/spotifyservice.h"
SpotifySearchProvider::SpotifySearchProvider(QObject* parent)
: SearchProvider("Spotify", QIcon(":icons/svg/spotify.svg"), parent),
: SearchProvider(parent),
server_(NULL),
service_(NULL)
{
Init("Spotify", QIcon(":icons/svg/spotify.svg"), true);
}
SpotifyServer* SpotifySearchProvider::server() {