2011-08-28 22:33:59 +02:00
|
|
|
/* This file is part of Clementine.
|
|
|
|
Copyright 2010, David Sansome <me@davidsansome.com>
|
|
|
|
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "librarysearchprovider.h"
|
|
|
|
#include "globalsearch.h"
|
2011-11-11 23:11:25 +01:00
|
|
|
#include "urlsearchprovider.h"
|
2012-02-13 21:44:04 +01:00
|
|
|
#include "core/application.h"
|
2011-08-28 22:33:59 +02:00
|
|
|
#include "core/logging.h"
|
2011-11-04 23:31:19 +01:00
|
|
|
#include "covers/albumcoverloader.h"
|
2011-08-28 22:33:59 +02:00
|
|
|
|
2011-10-01 22:22:01 +02:00
|
|
|
#include <QSettings>
|
2011-08-28 23:52:24 +02:00
|
|
|
#include <QStringBuilder>
|
2012-02-26 16:05:46 +01:00
|
|
|
#include <QTimerEvent>
|
2011-08-28 23:52:24 +02:00
|
|
|
#include <QUrl>
|
|
|
|
|
2012-06-11 00:05:30 +02:00
|
|
|
#include <algorithm>
|
|
|
|
|
2011-08-29 01:13:36 +02:00
|
|
|
const int GlobalSearch::kDelayedSearchTimeoutMs = 200;
|
2011-10-01 22:22:01 +02:00
|
|
|
const char* GlobalSearch::kSettingsGroup = "GlobalSearch";
|
2012-06-24 22:14:40 +02:00
|
|
|
const int GlobalSearch::kMaxResultsPerEmission = 500;
|
2011-08-29 01:13:36 +02:00
|
|
|
|
2012-02-12 14:41:50 +01:00
|
|
|
GlobalSearch::GlobalSearch(Application* app, QObject* parent)
|
2014-02-07 16:34:20 +01:00
|
|
|
: QObject(parent),
|
|
|
|
app_(app),
|
|
|
|
next_id_(1),
|
|
|
|
url_provider_(new UrlSearchProvider(app, this)) {
|
2012-02-13 21:44:04 +01:00
|
|
|
cover_loader_options_.desired_height_ = SearchProvider::kArtHeight;
|
|
|
|
cover_loader_options_.pad_output_image_ = true;
|
|
|
|
cover_loader_options_.scale_output_image_ = true;
|
2011-11-04 23:31:19 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64, QImage)),
|
|
|
|
SLOT(AlbumArtLoaded(quint64, QImage)));
|
2011-08-28 22:33:59 +02:00
|
|
|
|
2011-11-11 23:11:25 +01:00
|
|
|
ConnectProvider(url_provider_);
|
|
|
|
}
|
2011-08-29 01:13:36 +02:00
|
|
|
|
2011-11-11 23:11:25 +01:00
|
|
|
void GlobalSearch::ConnectProvider(SearchProvider* provider) {
|
2014-02-07 16:34:20 +01:00
|
|
|
connect(provider, SIGNAL(ResultsAvailable(int, SearchProvider::ResultList)),
|
|
|
|
SLOT(ResultsAvailableSlot(int, SearchProvider::ResultList)));
|
|
|
|
connect(provider, SIGNAL(SearchFinished(int)), SLOT(SearchFinishedSlot(int)));
|
|
|
|
connect(provider, SIGNAL(ArtLoaded(int, QImage)),
|
|
|
|
SLOT(ArtLoadedSlot(int, QImage)));
|
2011-08-28 22:33:59 +02:00
|
|
|
connect(provider, SIGNAL(destroyed(QObject*)),
|
|
|
|
SLOT(ProviderDestroyedSlot(QObject*)));
|
2011-11-11 23:11:25 +01:00
|
|
|
}
|
|
|
|
|
2011-11-28 15:18:20 +01:00
|
|
|
void GlobalSearch::AddProvider(SearchProvider* provider) {
|
2011-11-11 23:11:25 +01:00
|
|
|
Q_ASSERT(!provider->name().isEmpty());
|
|
|
|
|
2011-11-28 15:18:20 +01:00
|
|
|
bool enabled = provider->is_enabled_by_default();
|
|
|
|
|
|
|
|
// Check if there is saved enabled/disabled state for this provider.
|
|
|
|
QSettings s;
|
|
|
|
s.beginGroup(kSettingsGroup);
|
|
|
|
QVariant enabled_variant = s.value("enabled_" + provider->id());
|
|
|
|
if (enabled_variant.isValid()) {
|
|
|
|
enabled = enabled_variant.toBool();
|
|
|
|
}
|
2011-08-28 22:33:59 +02:00
|
|
|
|
2011-11-28 15:18:20 +01:00
|
|
|
// Add data
|
2011-10-01 22:22:01 +02:00
|
|
|
ProviderData data;
|
2011-11-28 15:18:20 +01:00
|
|
|
data.enabled_ = enabled;
|
2011-10-01 22:22:01 +02:00
|
|
|
providers_[provider] = data;
|
|
|
|
|
2011-11-28 15:18:20 +01:00
|
|
|
ConnectProvider(provider);
|
2011-10-01 22:22:01 +02:00
|
|
|
emit ProviderAdded(provider);
|
2011-08-28 22:33:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int GlobalSearch::SearchAsync(const QString& query) {
|
2014-02-07 16:34:20 +01:00
|
|
|
const int id = next_id_++;
|
2011-10-16 22:57:28 +02:00
|
|
|
pending_search_providers_[id] = 0;
|
2011-10-01 22:22:01 +02:00
|
|
|
|
2011-11-11 23:11:25 +01:00
|
|
|
int timer_id = -1;
|
2011-10-16 22:57:28 +02:00
|
|
|
|
2011-11-11 23:11:25 +01:00
|
|
|
if (url_provider_->LooksLikeUrl(query)) {
|
|
|
|
url_provider_->SearchAsync(id, query);
|
|
|
|
} else {
|
2014-02-10 14:29:07 +01:00
|
|
|
for (SearchProvider* provider : providers_.keys()) {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!is_provider_usable(provider)) continue;
|
2011-11-11 23:11:25 +01:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
pending_search_providers_[id]++;
|
2011-11-11 23:11:25 +01:00
|
|
|
|
|
|
|
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);
|
2011-08-29 01:13:36 +02:00
|
|
|
}
|
|
|
|
}
|
2011-08-28 22:33:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2011-08-29 01:13:36 +02:00
|
|
|
void GlobalSearch::CancelSearch(int id) {
|
|
|
|
QMap<int, DelayedSearch>::iterator it;
|
2014-02-07 16:34:20 +01:00
|
|
|
for (it = delayed_searches_.begin(); it != delayed_searches_.end(); ++it) {
|
2011-08-29 01:18:17 +02:00
|
|
|
if (it.value().id_ == id) {
|
|
|
|
killTimer(it.key());
|
2011-08-29 01:13:36 +02:00
|
|
|
delayed_searches_.erase(it);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2011-08-29 01:18:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void GlobalSearch::timerEvent(QTimerEvent* e) {
|
|
|
|
QMap<int, DelayedSearch>::iterator it = delayed_searches_.find(e->timerId());
|
|
|
|
if (it != delayed_searches_.end()) {
|
2014-02-10 14:29:07 +01:00
|
|
|
for (SearchProvider* provider : it.value().providers_) {
|
2011-08-29 01:18:17 +02:00
|
|
|
provider->SearchAsync(it.value().id_, it.value().query_);
|
|
|
|
}
|
|
|
|
delayed_searches_.erase(it);
|
|
|
|
return;
|
|
|
|
}
|
2011-08-29 01:13:36 +02:00
|
|
|
|
|
|
|
QObject::timerEvent(e);
|
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
QString GlobalSearch::PixmapCacheKey(const SearchProvider::Result& result)
|
|
|
|
const {
|
|
|
|
return "globalsearch:" % QString::number(qulonglong(result.provider_)) % "," %
|
|
|
|
result.metadata_.url().toString();
|
2011-08-28 23:52:24 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GlobalSearch::ResultsAvailableSlot(int id,
|
|
|
|
SearchProvider::ResultList results) {
|
|
|
|
if (results.isEmpty()) return;
|
2011-08-28 23:52:24 +02:00
|
|
|
|
2011-11-08 22:49:20 +01:00
|
|
|
// Limit the number of results that are used from each emission.
|
|
|
|
// Just a sanity check to stop some providers (Jamendo) returning thousands
|
|
|
|
// of results.
|
|
|
|
if (results.count() > kMaxResultsPerEmission) {
|
|
|
|
SearchProvider::ResultList::iterator begin = results.begin();
|
|
|
|
std::advance(begin, kMaxResultsPerEmission);
|
|
|
|
results.erase(begin, results.end());
|
|
|
|
}
|
|
|
|
|
2011-08-28 23:52:24 +02:00
|
|
|
// Load cached pixmaps into the results
|
2014-02-07 16:34:20 +01:00
|
|
|
for (SearchProvider::ResultList::iterator it = results.begin();
|
|
|
|
it != results.end(); ++it) {
|
2011-08-28 23:52:24 +02:00
|
|
|
it->pixmap_cache_key_ = PixmapCacheKey(*it);
|
|
|
|
}
|
|
|
|
|
|
|
|
emit ResultsAvailable(id, results);
|
2011-08-28 22:33:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void GlobalSearch::SearchFinishedSlot(int id) {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!pending_search_providers_.contains(id)) return;
|
2011-08-28 22:33:59 +02:00
|
|
|
|
|
|
|
SearchProvider* provider = static_cast<SearchProvider*>(sender());
|
|
|
|
const int remaining = --pending_search_providers_[id];
|
|
|
|
|
|
|
|
emit ProviderSearchFinished(id, provider);
|
|
|
|
if (remaining == 0) {
|
|
|
|
emit SearchFinished(id);
|
|
|
|
pending_search_providers_.remove(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GlobalSearch::ProviderDestroyedSlot(QObject* object) {
|
|
|
|
SearchProvider* provider = static_cast<SearchProvider*>(object);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!providers_.contains(provider)) return;
|
2011-08-28 22:33:59 +02:00
|
|
|
|
2011-10-01 22:22:01 +02:00
|
|
|
providers_.remove(provider);
|
|
|
|
emit ProviderRemoved(provider);
|
2011-08-28 22:33:59 +02:00
|
|
|
|
|
|
|
// We have to abort any pending searches since we can't tell whether they
|
|
|
|
// were on this provider.
|
2014-02-10 14:29:07 +01:00
|
|
|
for (int id : pending_search_providers_.keys()) {
|
|
|
|
emit SearchFinished(id);
|
|
|
|
}
|
2011-08-28 22:33:59 +02:00
|
|
|
pending_search_providers_.clear();
|
|
|
|
}
|
|
|
|
|
2011-10-01 22:22:01 +02:00
|
|
|
QList<SearchProvider*> GlobalSearch::providers() const {
|
|
|
|
return providers_.keys();
|
|
|
|
}
|
|
|
|
|
2011-08-28 22:33:59 +02:00
|
|
|
int GlobalSearch::LoadArtAsync(const SearchProvider::Result& result) {
|
2014-02-07 16:34:20 +01:00
|
|
|
const int id = next_id_++;
|
2011-08-29 01:32:45 +02:00
|
|
|
|
2011-08-28 23:52:24 +02:00
|
|
|
pending_art_searches_[id] = result.pixmap_cache_key_;
|
2011-08-29 01:32:45 +02:00
|
|
|
|
2011-11-11 23:11:25 +01:00
|
|
|
if (providers_.contains(result.provider_) &&
|
2011-11-28 15:18:20 +01:00
|
|
|
!is_provider_usable(result.provider_)) {
|
2011-10-01 22:22:01 +02:00
|
|
|
emit ArtLoaded(id, QPixmap());
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2011-11-04 23:31:19 +01:00
|
|
|
if (result.provider_->art_is_in_song_metadata()) {
|
2012-02-13 21:44:04 +01:00
|
|
|
quint64 loader_id = app_->album_cover_loader()->LoadImageAsync(
|
2014-02-07 16:34:20 +01:00
|
|
|
cover_loader_options_, result.metadata_);
|
2011-11-04 23:31:19 +01:00
|
|
|
cover_loader_tasks_[loader_id] = id;
|
2011-11-11 23:11:25 +01:00
|
|
|
} else if (providers_.contains(result.provider_) &&
|
|
|
|
result.provider_->wants_serialised_art()) {
|
2011-08-29 01:32:45 +02:00
|
|
|
QueuedArt request;
|
|
|
|
request.id_ = id;
|
|
|
|
request.result_ = result;
|
|
|
|
|
2011-10-01 22:22:01 +02:00
|
|
|
QList<QueuedArt>* queued_art = &providers_[result.provider_].queued_art_;
|
2011-08-29 01:32:45 +02:00
|
|
|
|
2011-10-01 22:22:01 +02:00
|
|
|
queued_art->append(request);
|
|
|
|
|
|
|
|
if (queued_art->count() == 1) {
|
2011-08-29 01:32:45 +02:00
|
|
|
TakeNextQueuedArt(result.provider_);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
result.provider_->LoadArtAsync(id, result);
|
|
|
|
}
|
|
|
|
|
2011-08-28 22:33:59 +02:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2011-08-29 01:32:45 +02:00
|
|
|
void GlobalSearch::TakeNextQueuedArt(SearchProvider* provider) {
|
2011-10-01 22:22:01 +02:00
|
|
|
if (!providers_.contains(provider) ||
|
|
|
|
providers_[provider].queued_art_.isEmpty())
|
2011-08-29 01:32:45 +02:00
|
|
|
return;
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
const QueuedArt& data = providers_[provider].queued_art_.first();
|
2011-08-29 01:32:45 +02:00
|
|
|
provider->LoadArtAsync(data.id_, data.result_);
|
|
|
|
}
|
|
|
|
|
2011-08-28 23:52:24 +02:00
|
|
|
void GlobalSearch::ArtLoadedSlot(int id, const QImage& image) {
|
2011-08-29 01:32:45 +02:00
|
|
|
SearchProvider* provider = static_cast<SearchProvider*>(sender());
|
2011-11-04 23:31:19 +01:00
|
|
|
HandleLoadedArt(id, image, provider);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GlobalSearch::AlbumArtLoaded(quint64 id, const QImage& image) {
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!cover_loader_tasks_.contains(id)) return;
|
2011-11-04 23:31:19 +01:00
|
|
|
int orig_id = cover_loader_tasks_.take(id);
|
|
|
|
|
2014-02-06 16:49:49 +01:00
|
|
|
HandleLoadedArt(orig_id, image, nullptr);
|
2011-11-04 23:31:19 +01:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
void GlobalSearch::HandleLoadedArt(int id, const QImage& image,
|
|
|
|
SearchProvider* provider) {
|
2011-08-28 23:52:24 +02:00
|
|
|
const QString key = pending_art_searches_.take(id);
|
|
|
|
|
|
|
|
QPixmap pixmap = QPixmap::fromImage(image);
|
|
|
|
pixmap_cache_.insert(key, pixmap);
|
|
|
|
|
|
|
|
emit ArtLoaded(id, pixmap);
|
2011-08-29 01:32:45 +02:00
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
if (provider && providers_.contains(provider) &&
|
2011-10-01 22:22:01 +02:00
|
|
|
!providers_[provider].queued_art_.isEmpty()) {
|
2014-02-07 16:34:20 +01:00
|
|
|
providers_[provider].queued_art_.removeFirst();
|
2011-08-29 01:32:45 +02:00
|
|
|
TakeNextQueuedArt(provider);
|
|
|
|
}
|
2011-08-28 23:52:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GlobalSearch::FindCachedPixmap(const SearchProvider::Result& result,
|
|
|
|
QPixmap* pixmap) const {
|
|
|
|
return pixmap_cache_.find(result.pixmap_cache_key_, pixmap);
|
|
|
|
}
|
|
|
|
|
2012-06-10 21:55:51 +02:00
|
|
|
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()) {
|
2014-02-06 16:49:49 +01:00
|
|
|
return nullptr;
|
2012-06-10 21:55:51 +02:00
|
|
|
}
|
2011-08-29 03:37:55 +02:00
|
|
|
|
2012-06-10 21:55:51 +02:00
|
|
|
SearchProvider* first_provider = results[0].provider_;
|
|
|
|
SearchProvider::ResultList results_copy;
|
2014-02-10 14:29:07 +01:00
|
|
|
for (const SearchProvider::Result& result : results) {
|
2012-06-10 21:55:51 +02:00
|
|
|
if (result.provider_ == first_provider) {
|
|
|
|
results_copy << result;
|
|
|
|
}
|
|
|
|
}
|
2011-08-29 03:37:55 +02:00
|
|
|
|
2012-06-10 21:55:51 +02:00
|
|
|
return first_provider->LoadTracks(results);
|
2011-08-29 03:37:55 +02:00
|
|
|
}
|
|
|
|
|
2011-10-20 15:03:47 +02:00
|
|
|
bool GlobalSearch::SetProviderEnabled(const SearchProvider* const_provider,
|
2011-10-01 22:22:01 +02:00
|
|
|
bool enabled) {
|
|
|
|
SearchProvider* provider = const_cast<SearchProvider*>(const_provider);
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!providers_.contains(provider)) return true;
|
2011-10-01 22:22:01 +02:00
|
|
|
|
|
|
|
if (providers_[provider].enabled_ != enabled) {
|
2011-10-20 15:03:47 +02:00
|
|
|
// If we try to enable this provider but it is not logged in, don't change
|
|
|
|
// state, and show configuration menu, if any
|
|
|
|
if (enabled && !provider->IsLoggedIn()) {
|
|
|
|
provider->ShowConfig();
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
providers_[provider].enabled_ = enabled;
|
2012-06-19 22:07:58 +02:00
|
|
|
emit ProviderToggled(provider, enabled);
|
2011-10-20 16:36:12 +02:00
|
|
|
SaveProvidersSettings();
|
2011-10-20 15:03:47 +02:00
|
|
|
return true;
|
|
|
|
}
|
2011-10-01 22:22:01 +02:00
|
|
|
}
|
2011-10-20 15:03:47 +02:00
|
|
|
return true;
|
2011-10-01 22:22:01 +02:00
|
|
|
}
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
bool GlobalSearch::is_provider_enabled(const SearchProvider* const_provider)
|
|
|
|
const {
|
2011-10-01 22:22:01 +02:00
|
|
|
SearchProvider* provider = const_cast<SearchProvider*>(const_provider);
|
|
|
|
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!providers_.contains(provider)) return false;
|
2011-10-01 22:22:01 +02:00
|
|
|
return providers_[provider].enabled_;
|
|
|
|
}
|
|
|
|
|
2011-11-28 15:18:20 +01:00
|
|
|
bool GlobalSearch::is_provider_usable(SearchProvider* provider) const {
|
|
|
|
return is_provider_enabled(provider) && provider->IsLoggedIn();
|
|
|
|
}
|
|
|
|
|
2011-10-01 22:22:01 +02:00
|
|
|
void GlobalSearch::ReloadSettings() {
|
|
|
|
QSettings s;
|
|
|
|
s.beginGroup(kSettingsGroup);
|
|
|
|
|
2014-02-10 14:29:07 +01:00
|
|
|
for (SearchProvider* provider : providers_.keys()) {
|
2011-10-31 00:30:47 +01:00
|
|
|
QVariant value = s.value("enabled_" + provider->id());
|
2014-02-07 16:34:20 +01:00
|
|
|
if (!value.isValid()) continue;
|
2012-06-19 22:07:58 +02:00
|
|
|
const bool enabled = value.toBool();
|
2011-10-31 00:30:47 +01:00
|
|
|
|
2012-06-19 22:07:58 +02:00
|
|
|
if (enabled != providers_[provider].enabled_) {
|
|
|
|
providers_[provider].enabled_ = enabled;
|
|
|
|
emit ProviderToggled(provider, enabled);
|
|
|
|
}
|
2011-10-20 16:36:12 +02:00
|
|
|
}
|
|
|
|
}
|
2011-10-01 22:22:01 +02:00
|
|
|
|
2011-10-20 16:36:12 +02:00
|
|
|
void GlobalSearch::SaveProvidersSettings() {
|
|
|
|
QSettings s;
|
|
|
|
s.beginGroup(kSettingsGroup);
|
2014-02-10 14:29:07 +01:00
|
|
|
for (SearchProvider* provider : providers_.keys()) {
|
2011-10-31 00:30:47 +01:00
|
|
|
s.setValue("enabled_" + provider->id(), providers_[provider].enabled_);
|
2011-10-01 22:22:01 +02:00
|
|
|
}
|
|
|
|
}
|
2011-11-06 17:29:09 +01:00
|
|
|
|
2012-06-11 00:05:30 +02:00
|
|
|
QStringList GlobalSearch::GetSuggestions(int count) {
|
2011-11-06 17:29:09 +01:00
|
|
|
QStringList ret;
|
|
|
|
|
2012-06-11 00:05:30 +02:00
|
|
|
// Get count suggestions from each provider
|
2014-02-10 14:29:07 +01:00
|
|
|
for (SearchProvider* provider : providers_.keys()) {
|
2011-11-06 17:29:09 +01:00
|
|
|
if (is_provider_enabled(provider) && provider->can_give_suggestions()) {
|
2014-02-10 14:29:07 +01:00
|
|
|
for (QString suggestion : provider->GetSuggestions(count)) {
|
2012-06-11 00:05:30 +02:00
|
|
|
suggestion = suggestion.trimmed().toLower();
|
|
|
|
|
|
|
|
if (!suggestion.isEmpty()) {
|
|
|
|
ret << suggestion;
|
|
|
|
}
|
|
|
|
}
|
2011-11-06 17:29:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-11 00:05:30 +02:00
|
|
|
// Randomize the suggestions
|
|
|
|
std::random_shuffle(ret.begin(), ret.end());
|
2011-11-06 17:29:09 +01:00
|
|
|
|
2012-06-11 00:05:30 +02:00
|
|
|
// Only return the first count
|
|
|
|
while (ret.length() > count) {
|
|
|
|
ret.removeLast();
|
|
|
|
}
|
2011-11-06 17:29:09 +01:00
|
|
|
return ret;
|
|
|
|
}
|