Improve internet classes
This commit is contained in:
parent
aa43d42cdb
commit
2f72c41cda
@ -286,7 +286,6 @@ set(SOURCES
|
||||
internet/internetservices.cpp
|
||||
internet/internetservice.cpp
|
||||
internet/internetplaylistitem.cpp
|
||||
internet/internetsearch.cpp
|
||||
internet/internetsearchview.cpp
|
||||
internet/internetsearchmodel.cpp
|
||||
internet/internetsearchsortmodel.cpp
|
||||
@ -472,7 +471,6 @@ set(HEADERS
|
||||
internet/internetservices.h
|
||||
internet/internetservice.h
|
||||
internet/internetsongmimedata.h
|
||||
internet/internetsearch.h
|
||||
internet/internetsearchview.h
|
||||
internet/internetsearchmodel.h
|
||||
internet/localredirectserver.h
|
||||
|
@ -61,7 +61,7 @@
|
||||
# include "dbus/metatypes.h"
|
||||
#endif
|
||||
|
||||
#include "internet/internetsearch.h"
|
||||
#include "internet/internetsearchview.h"
|
||||
|
||||
void RegisterMetaTypes() {
|
||||
|
||||
@ -117,7 +117,7 @@ void RegisterMetaTypes() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
qRegisterMetaType<InternetSearch::ResultList>("InternetSearch::ResultList");
|
||||
qRegisterMetaType<InternetSearch::Result>("InternetSearch::Result");
|
||||
qRegisterMetaType<InternetSearchView::ResultList>("InternetSearchView::ResultList");
|
||||
qRegisterMetaType<InternetSearchView::Result>("InternetSearchView::Result");
|
||||
|
||||
}
|
||||
|
@ -1,318 +0,0 @@
|
||||
/*
|
||||
* Strawberry Music Player
|
||||
* This code was part of Clementine (GlobalSearch)
|
||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry 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.
|
||||
*
|
||||
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringBuilder>
|
||||
#include <QUrl>
|
||||
#include <QRegExp>
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
#include <QSize>
|
||||
#include <QTimerEvent>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/song.h"
|
||||
#include "core/mimedata.h"
|
||||
#include "covermanager/albumcoverloader.h"
|
||||
#include "internet/internetsongmimedata.h"
|
||||
#include "internetsearch.h"
|
||||
#include "internetservice.h"
|
||||
#include "internetservices.h"
|
||||
|
||||
const int InternetSearch::kDelayedSearchTimeoutMs = 200;
|
||||
const int InternetSearch::kArtHeight = 32;
|
||||
|
||||
InternetSearch::InternetSearch(Application *app, Song::Source source, QObject *parent)
|
||||
: QObject(parent),
|
||||
app_(app),
|
||||
source_(source),
|
||||
service_(app->internet_services()->ServiceBySource(source)),
|
||||
searches_next_id_(1),
|
||||
art_searches_next_id_(1) {
|
||||
|
||||
cover_loader_options_.desired_height_ = kArtHeight;
|
||||
cover_loader_options_.pad_output_image_ = true;
|
||||
cover_loader_options_.scale_output_image_ = true;
|
||||
|
||||
connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64, QUrl, QImage)), SLOT(AlbumCoverLoaded(quint64, QUrl, QImage)));
|
||||
connect(this, SIGNAL(SearchAsyncSig(const int, const QString&, const SearchType)), this, SLOT(DoSearchAsync(const int, const QString&, const SearchType)));
|
||||
|
||||
connect(service_, SIGNAL(SearchUpdateStatus(const int, const QString&)), SLOT(UpdateStatusSlot(const int, const QString&)));
|
||||
connect(service_, SIGNAL(SearchProgressSetMaximum(const int, const int)), SLOT(ProgressSetMaximumSlot(const int, const int)));
|
||||
connect(service_, SIGNAL(SearchUpdateProgress(const int, const int)), SLOT(UpdateProgressSlot(const int, const int)));
|
||||
connect(service_, SIGNAL(SearchResults(const int, const SongList&, const QString&)), SLOT(SearchDone(const int, const SongList&, const QString&)));
|
||||
|
||||
}
|
||||
|
||||
InternetSearch::~InternetSearch() {}
|
||||
|
||||
QStringList InternetSearch::TokenizeQuery(const QString &query) {
|
||||
|
||||
QStringList tokens(query.split(QRegExp("\\s+")));
|
||||
|
||||
for (QStringList::iterator it = tokens.begin(); it != tokens.end(); ++it) {
|
||||
(*it).remove('(');
|
||||
(*it).remove(')');
|
||||
(*it).remove('"');
|
||||
|
||||
const int colon = (*it).indexOf(":");
|
||||
if (colon != -1) {
|
||||
(*it).remove(0, colon + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return tokens;
|
||||
|
||||
}
|
||||
|
||||
bool InternetSearch::Matches(const QStringList &tokens, const QString &string) {
|
||||
|
||||
for (const QString &token : tokens) {
|
||||
if (!string.contains(token, Qt::CaseInsensitive)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
int InternetSearch::SearchAsync(const QString &query, const SearchType type) {
|
||||
|
||||
const int id = searches_next_id_++;
|
||||
|
||||
emit SearchAsyncSig(id, query, type);
|
||||
|
||||
return id;
|
||||
|
||||
}
|
||||
|
||||
void InternetSearch::SearchAsync(const int id, const QString &query, const SearchType type) {
|
||||
|
||||
const int service_id = service_->Search(query, type);
|
||||
pending_searches_[service_id] = PendingState(id, TokenizeQuery(query));
|
||||
|
||||
}
|
||||
|
||||
void InternetSearch::DoSearchAsync(const int id, const QString &query, const SearchType type) {
|
||||
|
||||
int timer_id = startTimer(kDelayedSearchTimeoutMs);
|
||||
delayed_searches_[timer_id].id_ = id;
|
||||
delayed_searches_[timer_id].query_ = query;
|
||||
delayed_searches_[timer_id].type_ = type;
|
||||
|
||||
}
|
||||
|
||||
void InternetSearch::SearchDone(const int service_id, const SongList &songs, const QString &error) {
|
||||
|
||||
if (!pending_searches_.contains(service_id)) return;
|
||||
|
||||
// Map back to the original id.
|
||||
const PendingState state = pending_searches_.take(service_id);
|
||||
const int search_id = state.orig_id_;
|
||||
|
||||
if (songs.isEmpty()) {
|
||||
emit SearchError(search_id, error);
|
||||
return;
|
||||
}
|
||||
|
||||
ResultList results;
|
||||
for (const Song &song : songs) {
|
||||
Result result;
|
||||
result.metadata_ = song;
|
||||
results << result;
|
||||
}
|
||||
|
||||
if (results.isEmpty()) return;
|
||||
|
||||
// Load cached pixmaps into the results
|
||||
for (InternetSearch::ResultList::iterator it = results.begin(); it != results.end(); ++it) {
|
||||
it->pixmap_cache_key_ = PixmapCacheKey(*it);
|
||||
}
|
||||
|
||||
emit AddResults(search_id, results);
|
||||
|
||||
MaybeSearchFinished(search_id);
|
||||
|
||||
}
|
||||
|
||||
void InternetSearch::MaybeSearchFinished(const int id) {
|
||||
|
||||
if (pending_searches_.keys(PendingState(id, QStringList())).isEmpty()) {
|
||||
emit SearchFinished(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InternetSearch::CancelSearch(const int id) {
|
||||
|
||||
QMap<int, DelayedSearch>::iterator it;
|
||||
for (it = delayed_searches_.begin(); it != delayed_searches_.end(); ++it) {
|
||||
if (it.value().id_ == id) {
|
||||
killTimer(it.key());
|
||||
delayed_searches_.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
service_->CancelSearch();
|
||||
|
||||
}
|
||||
|
||||
void InternetSearch::timerEvent(QTimerEvent *e) {
|
||||
|
||||
QMap<int, DelayedSearch>::iterator it = delayed_searches_.find(e->timerId());
|
||||
if (it != delayed_searches_.end()) {
|
||||
SearchAsync(it.value().id_, it.value().query_, it.value().type_);
|
||||
delayed_searches_.erase(it);
|
||||
return;
|
||||
}
|
||||
|
||||
QObject::timerEvent(e);
|
||||
|
||||
}
|
||||
|
||||
QString InternetSearch::PixmapCacheKey(const InternetSearch::Result &result) const {
|
||||
return "internet:" % result.metadata_.url().toString();
|
||||
}
|
||||
|
||||
bool InternetSearch::FindCachedPixmap(const InternetSearch::Result &result, QPixmap *pixmap) const {
|
||||
return pixmap_cache_.find(result.pixmap_cache_key_, pixmap);
|
||||
}
|
||||
|
||||
int InternetSearch::LoadAlbumCoverAsync(const InternetSearch::Result &result) {
|
||||
|
||||
const int id = art_searches_next_id_++;
|
||||
|
||||
pending_art_searches_[id] = result.pixmap_cache_key_;
|
||||
|
||||
quint64 loader_id = app_->album_cover_loader()->LoadImageAsync(cover_loader_options_, result.metadata_);
|
||||
cover_loader_tasks_[loader_id] = id;
|
||||
|
||||
return id;
|
||||
|
||||
}
|
||||
|
||||
void InternetSearch::AlbumCoverLoaded(const quint64 id, const QUrl &cover_url, const QImage &image) {
|
||||
|
||||
Q_UNUSED(cover_url);
|
||||
|
||||
if (!cover_loader_tasks_.contains(id)) return;
|
||||
int orig_id = cover_loader_tasks_.take(id);
|
||||
|
||||
const QString key = pending_art_searches_.take(orig_id);
|
||||
|
||||
QPixmap pixmap = QPixmap::fromImage(image);
|
||||
pixmap_cache_.insert(key, pixmap);
|
||||
|
||||
emit AlbumCoverLoaded(orig_id, pixmap);
|
||||
|
||||
}
|
||||
|
||||
QImage InternetSearch::ScaleAndPad(const QImage &image) {
|
||||
|
||||
if (image.isNull()) return QImage();
|
||||
|
||||
const QSize target_size = QSize(kArtHeight, kArtHeight);
|
||||
|
||||
if (image.size() == target_size) return image;
|
||||
|
||||
// Scale the image down
|
||||
QImage copy;
|
||||
copy = image.scaled(target_size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
// Pad the image to kHeight x kHeight
|
||||
if (copy.size() == target_size) return copy;
|
||||
|
||||
QImage padded_image(kArtHeight, kArtHeight, QImage::Format_ARGB32);
|
||||
padded_image.fill(0);
|
||||
|
||||
QPainter p(&padded_image);
|
||||
p.drawImage((kArtHeight - copy.width()) / 2, (kArtHeight - copy.height()) / 2, copy);
|
||||
p.end();
|
||||
|
||||
return padded_image;
|
||||
|
||||
}
|
||||
|
||||
MimeData *InternetSearch::LoadTracks(const ResultList &results) {
|
||||
|
||||
if (results.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ResultList results_copy;
|
||||
for (const Result &result : results) {
|
||||
results_copy << result;
|
||||
}
|
||||
|
||||
SongList songs;
|
||||
for (const Result &result : results) {
|
||||
songs << result.metadata_;
|
||||
}
|
||||
|
||||
InternetSongMimeData *internet_song_mime_data = new InternetSongMimeData(service_);
|
||||
internet_song_mime_data->songs = songs;
|
||||
MimeData *mime_data = internet_song_mime_data;
|
||||
|
||||
QList<QUrl> urls;
|
||||
for (const Result &result : results) {
|
||||
urls << result.metadata_.url();
|
||||
}
|
||||
mime_data->setUrls(urls);
|
||||
|
||||
return mime_data;
|
||||
|
||||
}
|
||||
|
||||
void InternetSearch::UpdateStatusSlot(const int service_id, const QString &text) {
|
||||
|
||||
if (!pending_searches_.contains(service_id)) return;
|
||||
const PendingState state = pending_searches_[service_id];
|
||||
const int search_id = state.orig_id_;
|
||||
emit UpdateStatus(search_id, text);
|
||||
|
||||
}
|
||||
|
||||
void InternetSearch::ProgressSetMaximumSlot(const int service_id, const int max) {
|
||||
|
||||
if (!pending_searches_.contains(service_id)) return;
|
||||
const PendingState state = pending_searches_[service_id];
|
||||
const int search_id = state.orig_id_;
|
||||
emit ProgressSetMaximum(search_id, max);
|
||||
|
||||
}
|
||||
|
||||
void InternetSearch::UpdateProgressSlot(const int service_id, const int progress) {
|
||||
|
||||
if (!pending_searches_.contains(service_id)) return;
|
||||
const PendingState state = pending_searches_[service_id];
|
||||
const int search_id = state.orig_id_;
|
||||
emit UpdateProgress(search_id, progress);
|
||||
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
/*
|
||||
* Strawberry Music Player
|
||||
* This code was part of Clementine (GlobalSearch)
|
||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry 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.
|
||||
*
|
||||
* Strawberry 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 Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INTERNETSEARCH_H
|
||||
#define INTERNETSEARCH_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QMetaType>
|
||||
#include <QSet>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
#include <QPixmapCache>
|
||||
|
||||
#include "core/song.h"
|
||||
#include "covermanager/albumcoverloaderoptions.h"
|
||||
|
||||
class QTimerEvent;
|
||||
class Application;
|
||||
class MimeData;
|
||||
class AlbumCoverLoader;
|
||||
class InternetService;
|
||||
|
||||
class InternetSearch : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit InternetSearch(Application *app, Song::Source source, QObject *parent = nullptr);
|
||||
~InternetSearch();
|
||||
|
||||
enum SearchType {
|
||||
SearchType_Artists = 1,
|
||||
SearchType_Albums = 2,
|
||||
SearchType_Songs = 3,
|
||||
};
|
||||
|
||||
struct Result {
|
||||
Song metadata_;
|
||||
QString pixmap_cache_key_;
|
||||
};
|
||||
typedef QList<Result> ResultList;
|
||||
|
||||
static const int kDelayedSearchTimeoutMs;
|
||||
|
||||
Application *application() const { return app_; }
|
||||
Song::Source source() const { return source_; }
|
||||
InternetService *service() const { return service_; }
|
||||
|
||||
int SearchAsync(const QString &query, SearchType type);
|
||||
int LoadAlbumCoverAsync(const InternetSearch::Result &result);
|
||||
|
||||
void CancelSearch(const int id);
|
||||
void CancelArt(const int id);
|
||||
|
||||
// Loads tracks for results that were previously emitted by ResultsAvailable.
|
||||
// The implementation creates a SongMimeData with one Song for each Result.
|
||||
MimeData *LoadTracks(const ResultList &results);
|
||||
|
||||
signals:
|
||||
void SearchAsyncSig(const int id, const QString &query, const SearchType type);
|
||||
void ResultsAvailable(const int id, const InternetSearch::ResultList &results);
|
||||
void AddResults(const int id, const InternetSearch::ResultList &results);
|
||||
void SearchError(const int id, const QString &error);
|
||||
void SearchFinished(const int id);
|
||||
void UpdateStatus(const int id, const QString &text);
|
||||
void ProgressSetMaximum(const int id, const int progress);
|
||||
void UpdateProgress(const int id, const int max);
|
||||
|
||||
void AlbumCoverLoaded(const int id, const QPixmap &pixmap);
|
||||
|
||||
protected:
|
||||
|
||||
struct PendingState {
|
||||
PendingState() : orig_id_(-1) {}
|
||||
PendingState(int orig_id, QStringList tokens)
|
||||
: orig_id_(orig_id), tokens_(tokens) {}
|
||||
int orig_id_;
|
||||
QStringList tokens_;
|
||||
|
||||
bool operator<(const PendingState &b) const {
|
||||
return orig_id_ < b.orig_id_;
|
||||
}
|
||||
|
||||
bool operator==(const PendingState &b) const {
|
||||
return orig_id_ == b.orig_id_;
|
||||
}
|
||||
};
|
||||
|
||||
void timerEvent(QTimerEvent *e);
|
||||
|
||||
// These functions treat queries in the same way as CollectionQuery.
|
||||
// They're useful for figuring out whether you got a result because it matched in the song title or the artist/album name.
|
||||
static QStringList TokenizeQuery(const QString &query);
|
||||
static bool Matches(const QStringList &tokens, const QString &string);
|
||||
|
||||
private slots:
|
||||
void DoSearchAsync(const int id, const QString &query, const SearchType type);
|
||||
void SearchDone(const int service_id, const SongList &songs, const QString &error);
|
||||
|
||||
void AlbumCoverLoaded(const quint64 id, const QUrl &cover_url, const QImage &image);
|
||||
|
||||
void UpdateStatusSlot(const int id, const QString &text);
|
||||
void ProgressSetMaximumSlot(const int id, const int progress);
|
||||
void UpdateProgressSlot(const int id, const int max);
|
||||
|
||||
private:
|
||||
void SearchAsync(const int id, const QString &query, const SearchType type);
|
||||
bool FindCachedPixmap(const InternetSearch::Result &result, QPixmap *pixmap) const;
|
||||
QString PixmapCacheKey(const InternetSearch::Result &result) const;
|
||||
void MaybeSearchFinished(const int id);
|
||||
void ShowConfig() {}
|
||||
static QImage ScaleAndPad(const QImage &image);
|
||||
|
||||
private:
|
||||
struct DelayedSearch {
|
||||
int id_;
|
||||
QString query_;
|
||||
SearchType type_;
|
||||
};
|
||||
|
||||
static const int kArtHeight;
|
||||
|
||||
Application *app_;
|
||||
Song::Source source_;
|
||||
InternetService *service_;
|
||||
int searches_next_id_;
|
||||
int art_searches_next_id_;
|
||||
|
||||
QMap<int, DelayedSearch> delayed_searches_;
|
||||
QMap<int, QString> pending_art_searches_;
|
||||
QPixmapCache pixmap_cache_;
|
||||
AlbumCoverLoaderOptions cover_loader_options_;
|
||||
QMap<quint64, int> cover_loader_tasks_;
|
||||
|
||||
QMap<int, PendingState> pending_searches_;
|
||||
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(InternetSearch::Result)
|
||||
Q_DECLARE_METATYPE(InternetSearch::ResultList)
|
||||
|
||||
#endif // INTERNETSEARCH_H
|
@ -32,12 +32,14 @@
|
||||
|
||||
#include "core/mimedata.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "internetsearch.h"
|
||||
#include "internetsongmimedata.h"
|
||||
#include "internetservice.h"
|
||||
#include "internetsearchmodel.h"
|
||||
#include "internetsearchview.h"
|
||||
|
||||
InternetSearchModel::InternetSearchModel(InternetSearch *engine, QObject *parent)
|
||||
InternetSearchModel::InternetSearchModel(InternetService *service, QObject *parent)
|
||||
: QStandardItemModel(parent),
|
||||
engine_(engine),
|
||||
service_(service),
|
||||
proxy_(nullptr),
|
||||
use_pretty_covers_(true),
|
||||
artist_icon_(IconLoader::Load("folder-sound")),
|
||||
@ -52,11 +54,11 @@ InternetSearchModel::InternetSearchModel(InternetSearch *engine, QObject *parent
|
||||
|
||||
}
|
||||
|
||||
void InternetSearchModel::AddResults(const InternetSearch::ResultList &results) {
|
||||
void InternetSearchModel::AddResults(const InternetSearchView::ResultList &results) {
|
||||
|
||||
int sort_index = 0;
|
||||
|
||||
for (const InternetSearch::Result &result : results) {
|
||||
for (const InternetSearchView::Result &result : results) {
|
||||
QStandardItem *parent = invisibleRootItem();
|
||||
|
||||
// Find (or create) the container nodes for this result if we can.
|
||||
@ -277,7 +279,7 @@ void InternetSearchModel::Clear() {
|
||||
clear();
|
||||
}
|
||||
|
||||
InternetSearch::ResultList InternetSearchModel::GetChildResults(const QModelIndexList &indexes) const {
|
||||
InternetSearchView::ResultList InternetSearchModel::GetChildResults(const QModelIndexList &indexes) const {
|
||||
|
||||
QList<QStandardItem*> items;
|
||||
for (const QModelIndex &index : indexes) {
|
||||
@ -287,9 +289,9 @@ InternetSearch::ResultList InternetSearchModel::GetChildResults(const QModelInde
|
||||
|
||||
}
|
||||
|
||||
InternetSearch::ResultList InternetSearchModel::GetChildResults(const QList<QStandardItem*> &items) const {
|
||||
InternetSearchView::ResultList InternetSearchModel::GetChildResults(const QList<QStandardItem*> &items) const {
|
||||
|
||||
InternetSearch::ResultList results;
|
||||
InternetSearchView::ResultList results;
|
||||
QSet<const QStandardItem*> visited;
|
||||
|
||||
for (QStandardItem *item : items) {
|
||||
@ -300,7 +302,7 @@ InternetSearch::ResultList InternetSearchModel::GetChildResults(const QList<QSta
|
||||
|
||||
}
|
||||
|
||||
void InternetSearchModel::GetChildResults(const QStandardItem *item, InternetSearch::ResultList *results, QSet<const QStandardItem*> *visited) const {
|
||||
void InternetSearchModel::GetChildResults(const QStandardItem *item, InternetSearchView::ResultList *results, QSet<const QStandardItem*> *visited) const {
|
||||
|
||||
if (visited->contains(item)) {
|
||||
return;
|
||||
@ -322,7 +324,7 @@ void InternetSearchModel::GetChildResults(const QStandardItem *item, InternetSea
|
||||
// No - maybe it's a song, add its result if valid
|
||||
QVariant result = item->data(Role_Result);
|
||||
if (result.isValid()) {
|
||||
results->append(result.value<InternetSearch::Result>());
|
||||
results->append(result.value<InternetSearchView::Result>());
|
||||
}
|
||||
else {
|
||||
// Maybe it's a provider then?
|
||||
@ -344,15 +346,17 @@ void InternetSearchModel::GetChildResults(const QStandardItem *item, InternetSea
|
||||
}
|
||||
|
||||
QMimeData *InternetSearchModel::mimeData(const QModelIndexList &indexes) const {
|
||||
return engine_->LoadTracks(GetChildResults(indexes));
|
||||
|
||||
return LoadTracks(GetChildResults(indexes));
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
void GatherResults(const QStandardItem *parent, InternetSearch::ResultList *results) {
|
||||
void GatherResults(const QStandardItem *parent, InternetSearchView::ResultList *results) {
|
||||
|
||||
QVariant result_variant = parent->data(InternetSearchModel::Role_Result);
|
||||
if (result_variant.isValid()) {
|
||||
InternetSearch::Result result = result_variant.value<InternetSearch::Result>();
|
||||
InternetSearchView::Result result = result_variant.value<InternetSearchView::Result>();
|
||||
(*results).append(result);
|
||||
}
|
||||
|
||||
@ -369,7 +373,7 @@ void InternetSearchModel::SetGroupBy(const CollectionModel::Grouping &grouping,
|
||||
|
||||
if (regroup_now && group_by_ != old_group_by) {
|
||||
// Walk the tree gathering the results we have already
|
||||
InternetSearch::ResultList results;
|
||||
InternetSearchView::ResultList results;
|
||||
GatherResults(invisibleRootItem(), &results);
|
||||
|
||||
// Reset the model and re-add all the results using the new grouping.
|
||||
@ -378,3 +382,34 @@ void InternetSearchModel::SetGroupBy(const CollectionModel::Grouping &grouping,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MimeData *InternetSearchModel::LoadTracks(const InternetSearchView::ResultList &results) const {
|
||||
|
||||
if (results.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
InternetSearchView::ResultList results_copy;
|
||||
for (const InternetSearchView::Result &result : results) {
|
||||
results_copy << result;
|
||||
}
|
||||
|
||||
SongList songs;
|
||||
for (const InternetSearchView::Result &result : results) {
|
||||
songs << result.metadata_;
|
||||
}
|
||||
|
||||
InternetSongMimeData *internet_song_mime_data = new InternetSongMimeData(service_);
|
||||
internet_song_mime_data->songs = songs;
|
||||
MimeData *mime_data = internet_song_mime_data;
|
||||
|
||||
QList<QUrl> urls;
|
||||
for (const InternetSearchView::Result &result : results) {
|
||||
urls << result.metadata_.url();
|
||||
}
|
||||
mime_data->setUrls(urls);
|
||||
|
||||
return mime_data;
|
||||
|
||||
}
|
||||
|
||||
|
@ -37,16 +37,19 @@
|
||||
|
||||
#include "core/song.h"
|
||||
#include "collection/collectionmodel.h"
|
||||
#include "internetsearch.h"
|
||||
#include "internetsearchview.h"
|
||||
|
||||
class QMimeData;
|
||||
class QSortFilterProxyModel;
|
||||
|
||||
class MimeData;
|
||||
class InternetService;
|
||||
|
||||
class InternetSearchModel : public QStandardItemModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit InternetSearchModel(InternetSearch *engine, QObject *parent = nullptr);
|
||||
explicit InternetSearchModel(InternetService *service, QObject *parent = nullptr);
|
||||
|
||||
enum Role {
|
||||
Role_Result = CollectionModel::LastRole,
|
||||
@ -61,25 +64,29 @@ class InternetSearchModel : public QStandardItemModel {
|
||||
};
|
||||
|
||||
void set_proxy(QSortFilterProxyModel *proxy) { proxy_ = proxy; }
|
||||
void set_use_pretty_covers(bool pretty) { use_pretty_covers_ = pretty; }
|
||||
void set_use_pretty_covers(const bool pretty) { use_pretty_covers_ = pretty; }
|
||||
void SetGroupBy(const CollectionModel::Grouping &grouping, bool regroup_now);
|
||||
|
||||
void Clear();
|
||||
|
||||
InternetSearch::ResultList GetChildResults(const QModelIndexList &indexes) const;
|
||||
InternetSearch::ResultList GetChildResults(const QList<QStandardItem*> &items) const;
|
||||
InternetSearchView::ResultList GetChildResults(const QModelIndexList &indexes) const;
|
||||
InternetSearchView::ResultList GetChildResults(const QList<QStandardItem*> &items) const;
|
||||
|
||||
QMimeData *mimeData(const QModelIndexList &indexes) const;
|
||||
|
||||
// Loads tracks for results that were previously emitted by ResultsAvailable.
|
||||
// The implementation creates a SongMimeData with one Song for each Result.
|
||||
MimeData *LoadTracks(const InternetSearchView::ResultList &results) const;
|
||||
|
||||
public slots:
|
||||
void AddResults(const InternetSearch::ResultList &results);
|
||||
void AddResults(const InternetSearchView::ResultList &results);
|
||||
|
||||
private:
|
||||
QStandardItem *BuildContainers(const Song &metadata, QStandardItem *parent, ContainerKey *key, int level = 0);
|
||||
void GetChildResults(const QStandardItem *item, InternetSearch::ResultList *results, QSet<const QStandardItem*> *visited) const;
|
||||
void GetChildResults(const QStandardItem *item, InternetSearchView::ResultList *results, QSet<const QStandardItem*> *visited) const;
|
||||
|
||||
private:
|
||||
InternetSearch *engine_;
|
||||
InternetService *service_;
|
||||
QSortFilterProxyModel *proxy_;
|
||||
bool use_pretty_covers_;
|
||||
QIcon artist_icon_;
|
||||
|
@ -28,9 +28,9 @@
|
||||
|
||||
#include "core/song.h"
|
||||
#include "collection/collectionmodel.h"
|
||||
#include "internetsearch.h"
|
||||
#include "internetsearchmodel.h"
|
||||
#include "internetsearchsortmodel.h"
|
||||
#include "internetsearchview.h"
|
||||
|
||||
InternetSearchSortModel::InternetSearchSortModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent) {}
|
||||
@ -58,8 +58,8 @@ bool InternetSearchSortModel::lessThan(const QModelIndex &left, const QModelInde
|
||||
}
|
||||
|
||||
// Otherwise we're comparing songs. Sort by disc, track, then title.
|
||||
const InternetSearch::Result r1 = left.data(InternetSearchModel::Role_Result).value<InternetSearch::Result>();
|
||||
const InternetSearch::Result r2 = right.data(InternetSearchModel::Role_Result).value<InternetSearch::Result>();
|
||||
const InternetSearchView::Result r1 = left.data(InternetSearchModel::Role_Result).value<InternetSearchView::Result>();
|
||||
const InternetSearchView::Result r2 = right.data(InternetSearchModel::Role_Result).value<InternetSearchView::Result>();
|
||||
|
||||
#define CompareInt(field) \
|
||||
if (r1.metadata_.field() < r2.metadata_.field()) return true; \
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
* Strawberry Music Player
|
||||
* This code was part of Clementine (GlobalSearch)
|
||||
* Copyright 2012, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
* Copyright 2018-2020, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -24,18 +24,25 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
#include <QPixmapCache>
|
||||
#include <QScopedPointer>
|
||||
#include <QMetaType>
|
||||
|
||||
#include "core/song.h"
|
||||
#include "collection/collectionmodel.h"
|
||||
#include "covermanager/albumcoverloaderoptions.h"
|
||||
#include "settings/settingsdialog.h"
|
||||
#include "internetsearch.h"
|
||||
|
||||
class QSortFilterProxyModel;
|
||||
class QMimeData;
|
||||
@ -48,11 +55,13 @@ class QKeyEvent;
|
||||
class QShowEvent;
|
||||
class QHideEvent;
|
||||
class QContextMenuEvent;
|
||||
class QTimerEvent;
|
||||
|
||||
class QModelIndex;
|
||||
class Application;
|
||||
class MimeData;
|
||||
class GroupByDialog;
|
||||
class AlbumCoverLoader;
|
||||
class InternetService;
|
||||
class InternetSearchModel;
|
||||
class Ui_InternetSearchView;
|
||||
|
||||
@ -63,80 +72,127 @@ class InternetSearchView : public QWidget {
|
||||
explicit InternetSearchView(QWidget *parent = nullptr);
|
||||
~InternetSearchView();
|
||||
|
||||
void Init(Application *app, InternetSearch *engine, const QString &settings_group, const SettingsDialog::Page settings_page, const bool artists = false, const bool albums = false, const bool songs = false);
|
||||
enum SearchType {
|
||||
SearchType_Artists = 1,
|
||||
SearchType_Albums = 2,
|
||||
SearchType_Songs = 3,
|
||||
};
|
||||
struct Result {
|
||||
Song metadata_;
|
||||
QString pixmap_cache_key_;
|
||||
};
|
||||
typedef QList<Result> ResultList;
|
||||
|
||||
static const int kSwapModelsTimeoutMsec;
|
||||
void Init(Application *app, InternetService *service);
|
||||
|
||||
void LazyLoadAlbumCover(const QModelIndex &index);
|
||||
|
||||
protected:
|
||||
struct PendingState {
|
||||
PendingState() : orig_id_(-1) {}
|
||||
PendingState(int orig_id, QStringList tokens) : orig_id_(orig_id), tokens_(tokens) {}
|
||||
int orig_id_;
|
||||
QStringList tokens_;
|
||||
|
||||
bool operator<(const PendingState &b) const {
|
||||
return orig_id_ < b.orig_id_;
|
||||
}
|
||||
|
||||
bool operator==(const PendingState &b) const {
|
||||
return orig_id_ == b.orig_id_;
|
||||
}
|
||||
};
|
||||
|
||||
void showEvent(QShowEvent *e);
|
||||
void hideEvent(QHideEvent *e);
|
||||
bool eventFilter(QObject *object, QEvent *event);
|
||||
bool eventFilter(QObject *object, QEvent *e);
|
||||
void timerEvent(QTimerEvent *e);
|
||||
|
||||
public slots:
|
||||
void ReloadSettings();
|
||||
void StartSearch(const QString &query);
|
||||
// These functions treat queries in the same way as CollectionQuery.
|
||||
// They're useful for figuring out whether you got a result because it matched in the song title or the artist/album name.
|
||||
static QStringList TokenizeQuery(const QString &query);
|
||||
static bool Matches(const QStringList &tokens, const QString &string);
|
||||
|
||||
private:
|
||||
struct DelayedSearch {
|
||||
int id_;
|
||||
QString query_;
|
||||
SearchType type_;
|
||||
};
|
||||
|
||||
bool SearchKeyEvent(QKeyEvent *e);
|
||||
bool ResultsContextMenuEvent(QContextMenuEvent *e);
|
||||
void FocusSearchField();
|
||||
void OpenSettingsDialog();
|
||||
|
||||
MimeData *SelectedMimeData();
|
||||
|
||||
void SetSearchType(const SearchType type);
|
||||
|
||||
int SearchAsync(const QString &query, SearchType type);
|
||||
void SearchAsync(const int id, const QString &query, const SearchType type);
|
||||
void SearchError(const int id, const QString &error);
|
||||
void CancelSearch(const int id);
|
||||
|
||||
QString PixmapCacheKey(const Result &result) const;
|
||||
bool FindCachedPixmap(const Result &result, QPixmap *pixmap) const;
|
||||
static QImage ScaleAndPad(const QImage &image);
|
||||
int LoadAlbumCoverAsync(const Result &result);
|
||||
|
||||
signals:
|
||||
void AddToPlaylist(QMimeData *data);
|
||||
void AddArtistsSignal(SongList songs);
|
||||
void AddAlbumsSignal(SongList songs);
|
||||
void AddSongsSignal(SongList songs);
|
||||
void AddToPlaylist(QMimeData*);
|
||||
void AddArtistsSignal(SongList);
|
||||
void AddAlbumsSignal(SongList);
|
||||
void AddSongsSignal(SongList);
|
||||
|
||||
private slots:
|
||||
void SwapModels();
|
||||
void TextEdited(const QString &text);
|
||||
void StartSearch(const QString &query);
|
||||
void SearchDone(const int service_id, const SongList &songs, const QString &error);
|
||||
|
||||
void UpdateStatus(const int id, const QString &text);
|
||||
void ProgressSetMaximum(const int id, const int progress);
|
||||
void UpdateProgress(const int id, const int max);
|
||||
void AddResults(const int id, const InternetSearch::ResultList &results);
|
||||
void SearchError(const int id, const QString &error);
|
||||
void AlbumCoverLoaded(const int id, const QPixmap &pixmap);
|
||||
void AddResults(const int id, const ResultList &results);
|
||||
|
||||
void FocusOnFilter(QKeyEvent *event);
|
||||
void FocusOnFilter(QKeyEvent *e);
|
||||
|
||||
void AddSelectedToPlaylist();
|
||||
void LoadSelected();
|
||||
void OpenSelectedInNewPlaylist();
|
||||
void AddSelectedToPlaylistEnqueue();
|
||||
|
||||
void SearchForThis();
|
||||
|
||||
void SearchArtistsClicked(bool);
|
||||
void SearchAlbumsClicked(bool);
|
||||
void SearchSongsClicked(bool);
|
||||
void GroupByClicked(QAction *action);
|
||||
void SetSearchType(const InternetSearch::SearchType type);
|
||||
void SetGroupBy(const CollectionModel::Grouping &g);
|
||||
|
||||
void AddArtists();
|
||||
void AddAlbums();
|
||||
void AddSongs();
|
||||
void SearchForThis();
|
||||
void OpenSettingsDialog();
|
||||
|
||||
void SearchArtistsClicked(const bool);
|
||||
void SearchAlbumsClicked(const bool);
|
||||
void SearchSongsClicked(const bool);
|
||||
void GroupByClicked(QAction *action);
|
||||
void SetGroupBy(const CollectionModel::Grouping &g);
|
||||
|
||||
void AlbumCoverLoaded(const quint64 id, const QUrl&, const QImage &image);
|
||||
|
||||
public slots:
|
||||
void ReloadSettings();
|
||||
|
||||
private:
|
||||
MimeData *SelectedMimeData();
|
||||
|
||||
bool SearchKeyEvent(QKeyEvent *event);
|
||||
bool ResultsContextMenuEvent(QContextMenuEvent *event);
|
||||
static const int kSwapModelsTimeoutMsec;
|
||||
static const int kDelayedSearchTimeoutMs;
|
||||
static const int kArtHeight;
|
||||
|
||||
private:
|
||||
Application *app_;
|
||||
InternetSearch *engine_;
|
||||
QString settings_group_;
|
||||
SettingsDialog::Page settings_page_;
|
||||
InternetService *service_;
|
||||
Ui_InternetSearchView *ui_;
|
||||
QScopedPointer<GroupByDialog> group_by_dialog_;
|
||||
bool artists_;
|
||||
bool albums_;
|
||||
bool songs_;
|
||||
|
||||
QMenu *context_menu_;
|
||||
QList<QAction*> context_actions_;
|
||||
QActionGroup *group_by_actions_;
|
||||
|
||||
int last_search_id_;
|
||||
|
||||
// Like graphics APIs have a front buffer and a back buffer, there's a front model and a back model
|
||||
// The front model is the one that's shown in the UI and the back model is the one that lies in wait.
|
||||
// current_model_ will point to either the front or the back model.
|
||||
@ -148,13 +204,24 @@ class InternetSearchView : public QWidget {
|
||||
QSortFilterProxyModel *back_proxy_;
|
||||
QSortFilterProxyModel *current_proxy_;
|
||||
|
||||
QMap<int, QModelIndex> art_requests_;
|
||||
|
||||
QTimer *swap_models_timer_;
|
||||
|
||||
InternetSearch::SearchType search_type_;
|
||||
bool error_;
|
||||
SearchType search_type_;
|
||||
bool search_error_;
|
||||
int last_search_id_;
|
||||
int searches_next_id_;
|
||||
int art_searches_next_id_;
|
||||
|
||||
QMap<int, DelayedSearch> delayed_searches_;
|
||||
QMap<int, PendingState> pending_searches_;
|
||||
QMap<int, QString> pending_art_searches_;
|
||||
QMap<int, QModelIndex> art_requests_;
|
||||
AlbumCoverLoaderOptions cover_loader_options_;
|
||||
QMap<quint64, quint64> cover_loader_tasks_;
|
||||
QPixmapCache pixmap_cache_;
|
||||
|
||||
};
|
||||
Q_DECLARE_METATYPE(InternetSearchView::Result)
|
||||
Q_DECLARE_METATYPE(InternetSearchView::ResultList)
|
||||
|
||||
#endif // INTERNETSEARCHVIEW_H
|
||||
|
@ -10,6 +10,9 @@
|
||||
<height>660</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Internet Search View</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
@ -39,7 +42,7 @@
|
||||
<item>
|
||||
<widget class="QSearchField" name="search" native="true">
|
||||
<property name="placeholderText" stdset="0">
|
||||
<string>Search for anything</string>
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -62,58 +65,65 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="layout_searchby">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetFixedSize</enum>
|
||||
<widget class="QWidget" name="widget_searchby" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_searchby">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Search type</string>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radiobutton_search_artists">
|
||||
<property name="text">
|
||||
<string>ar&tists</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radiobutton_search_albums">
|
||||
<property name="text">
|
||||
<string>a&lbums</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radiobutton_search_songs">
|
||||
<property name="text">
|
||||
<string>son&gs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radiobutton_search_artists">
|
||||
<property name="text">
|
||||
<string>artists</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radiobutton_search_albums">
|
||||
<property name="text">
|
||||
<string>albums</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radiobutton_search_songs">
|
||||
<property name="text">
|
||||
<string>songs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="spacer_searchby">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="layout_progress">
|
||||
@ -215,7 +225,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>398</width>
|
||||
<height>511</height>
|
||||
<height>528</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
|
@ -22,9 +22,10 @@
|
||||
|
||||
#include "internetservice.h"
|
||||
#include "core/song.h"
|
||||
#include "settings/settingsdialog.h"
|
||||
|
||||
class Application;
|
||||
|
||||
InternetService::InternetService(Song::Source source, const QString &name, const QString &url_scheme, Application *app, QObject *parent)
|
||||
: QObject(parent), app_(app), source_(source), name_(name), url_scheme_(url_scheme) {
|
||||
InternetService::InternetService(Song::Source source, const QString &name, const QString &url_scheme, const QString &settings_group, SettingsDialog::Page settings_page, Application *app, QObject *parent)
|
||||
: QObject(parent), app_(app), source_(source), name_(name), url_scheme_(url_scheme), settings_group_(settings_group), settings_page_(settings_page) {
|
||||
}
|
||||
|
@ -28,7 +28,8 @@
|
||||
#include <QIcon>
|
||||
|
||||
#include "core/song.h"
|
||||
#include "internetsearch.h"
|
||||
#include "settings/settingsdialog.h"
|
||||
#include "internetsearchview.h"
|
||||
|
||||
class QSortFilterProxyModel;
|
||||
class Application;
|
||||
@ -39,7 +40,7 @@ class InternetService : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit InternetService(Song::Source source, const QString &name, const QString &url_scheme, Application *app, QObject *parent = nullptr);
|
||||
explicit InternetService(Song::Source source, const QString &name, const QString &url_scheme, const QString &settings_group, SettingsDialog::Page settings_page, Application *app, QObject *parent = nullptr);
|
||||
|
||||
virtual ~InternetService() {}
|
||||
virtual void Exit() {}
|
||||
@ -47,13 +48,15 @@ class InternetService : public QObject {
|
||||
virtual Song::Source source() const { return source_; }
|
||||
virtual QString name() const { return name_; }
|
||||
virtual QString url_scheme() const { return url_scheme_; }
|
||||
virtual QString settings_group() const { return settings_group_; }
|
||||
virtual SettingsDialog::Page settings_page() const { return settings_page_; }
|
||||
virtual bool has_initial_load_settings() const { return false; }
|
||||
virtual void InitialLoadSettings() {}
|
||||
virtual void ReloadSettings() {}
|
||||
virtual QIcon Icon() { return Song::IconForSource(source_); }
|
||||
virtual bool oauth() { return false; }
|
||||
virtual bool authenticated() { return false; }
|
||||
virtual int Search(const QString &query, InternetSearch::SearchType type) { Q_UNUSED(query); Q_UNUSED(type); return 0; }
|
||||
virtual int Search(const QString &query, InternetSearchView::SearchType type) { Q_UNUSED(query); Q_UNUSED(type); return 0; }
|
||||
virtual void CancelSearch() {}
|
||||
|
||||
virtual CollectionBackend *artists_collection_backend() { return nullptr; }
|
||||
@ -129,10 +132,13 @@ class InternetService : public QObject {
|
||||
|
||||
protected:
|
||||
Application *app_;
|
||||
|
||||
private:
|
||||
Song::Source source_;
|
||||
QString name_;
|
||||
QString url_scheme_;
|
||||
QString settings_group_;
|
||||
SettingsDialog::Page settings_page_;
|
||||
|
||||
};
|
||||
Q_DECLARE_METATYPE(InternetService*)
|
||||
|
@ -57,15 +57,15 @@ InternetSongsView::InternetSongsView(Application *app, InternetService *service,
|
||||
ui_->filter->SetCollectionModel(service_->songs_collection_model());
|
||||
|
||||
connect(ui_->view, SIGNAL(GetSongs()), SLOT(GetSongs()));
|
||||
connect(ui_->view, SIGNAL(RemoveSongs(const SongList&)), service_, SIGNAL(RemoveSongs(const SongList&)));
|
||||
connect(ui_->view, SIGNAL(RemoveSongs(SongList)), service_, SIGNAL(RemoveSongs(SongList)));
|
||||
|
||||
connect(ui_->refresh, SIGNAL(clicked()), SLOT(GetSongs()));
|
||||
connect(ui_->close, SIGNAL(clicked()), SLOT(AbortGetSongs()));
|
||||
connect(ui_->abort, SIGNAL(clicked()), SLOT(AbortGetSongs()));
|
||||
connect(service_, SIGNAL(SongsResults(const SongList&, const QString&)), SLOT(SongsFinished(const SongList&, const QString&)));
|
||||
connect(service_, SIGNAL(SongsUpdateStatus(const QString&)), ui_->status, SLOT(setText(const QString&)));
|
||||
connect(service_, SIGNAL(SongsProgressSetMaximum(const int)), ui_->progressbar, SLOT(setMaximum(const int)));
|
||||
connect(service_, SIGNAL(SongsUpdateProgress(const int)), ui_->progressbar, SLOT(setValue(const int)));
|
||||
connect(service_, SIGNAL(SongsResults(SongList, QString)), SLOT(SongsFinished(SongList, QString)));
|
||||
connect(service_, SIGNAL(SongsUpdateStatus(QString)), ui_->status, SLOT(setText(QString)));
|
||||
connect(service_, SIGNAL(SongsProgressSetMaximum(int)), ui_->progressbar, SLOT(setMaximum(int)));
|
||||
connect(service_, SIGNAL(SongsUpdateProgress(int)), ui_->progressbar, SLOT(setValue(int)));
|
||||
|
||||
connect(service_->songs_collection_model(), SIGNAL(TotalArtistCountUpdated(int)), ui_->view, SLOT(TotalArtistCountUpdated(int)));
|
||||
connect(service_->songs_collection_model(), SIGNAL(TotalAlbumCountUpdated(int)), ui_->view, SLOT(TotalAlbumCountUpdated(int)));
|
||||
|
@ -40,14 +40,12 @@
|
||||
#include "internettabsview.h"
|
||||
#include "internetcollectionview.h"
|
||||
#include "internetcollectionviewcontainer.h"
|
||||
#include "internetsearchview.h"
|
||||
#include "ui_internettabsview.h"
|
||||
|
||||
InternetTabsView::InternetTabsView(Application *app, InternetService *service, InternetSearch *engine, const QString &settings_group, const SettingsDialog::Page settings_page, QWidget *parent)
|
||||
InternetTabsView::InternetTabsView(Application *app, InternetService *service, const QString &settings_group, const SettingsDialog::Page settings_page, QWidget *parent)
|
||||
: QWidget(parent),
|
||||
app_(app),
|
||||
service_(service),
|
||||
engine_(engine),
|
||||
settings_group_(settings_group),
|
||||
settings_page_(settings_page),
|
||||
ui_(new Ui_InternetTabsView)
|
||||
@ -55,10 +53,10 @@ InternetTabsView::InternetTabsView(Application *app, InternetService *service, I
|
||||
|
||||
ui_->setupUi(this);
|
||||
|
||||
ui_->search_view->Init(app, engine, settings_group, settings_page, service_->artists_collection_model(), service_->albums_collection_model(), service_->songs_collection_model());
|
||||
connect(ui_->search_view, SIGNAL(AddArtistsSignal(const SongList&)), service_, SIGNAL(AddArtists(const SongList&)));
|
||||
connect(ui_->search_view, SIGNAL(AddAlbumsSignal(const SongList&)), service_, SIGNAL(AddAlbums(const SongList&)));
|
||||
connect(ui_->search_view, SIGNAL(AddSongsSignal(const SongList&)), service_, SIGNAL(AddSongs(const SongList&)));
|
||||
ui_->search_view->Init(app, service);
|
||||
connect(ui_->search_view, SIGNAL(AddArtistsSignal(SongList)), service_, SIGNAL(AddArtists(SongList)));
|
||||
connect(ui_->search_view, SIGNAL(AddAlbumsSignal(SongList)), service_, SIGNAL(AddAlbums(SongList)));
|
||||
connect(ui_->search_view, SIGNAL(AddSongsSignal(SongList)), service_, SIGNAL(AddSongs(SongList)));
|
||||
|
||||
if (service_->artists_collection_model()) {
|
||||
ui_->artists_collection->stacked()->setCurrentWidget(ui_->artists_collection->internetcollection_page());
|
||||
@ -70,15 +68,15 @@ InternetTabsView::InternetTabsView(Application *app, InternetService *service, I
|
||||
ui_->artists_collection->filter()->SetCollectionModel(service_->artists_collection_model());
|
||||
|
||||
connect(ui_->artists_collection->view(), SIGNAL(GetSongs()), SLOT(GetArtists()));
|
||||
connect(ui_->artists_collection->view(), SIGNAL(RemoveSongs(const SongList&)), service_, SIGNAL(RemoveArtists(const SongList&)));
|
||||
connect(ui_->artists_collection->view(), SIGNAL(RemoveSongs(SongList)), service_, SIGNAL(RemoveArtists(SongList)));
|
||||
|
||||
connect(ui_->artists_collection->button_refresh(), SIGNAL(clicked()), SLOT(GetArtists()));
|
||||
connect(ui_->artists_collection->button_close(), SIGNAL(clicked()), SLOT(AbortGetArtists()));
|
||||
connect(ui_->artists_collection->button_abort(), SIGNAL(clicked()), SLOT(AbortGetArtists()));
|
||||
connect(service_, SIGNAL(ArtistsResults(const SongList&, const QString&)), SLOT(ArtistsFinished(const SongList&, const QString&)));
|
||||
connect(service_, SIGNAL(ArtistsUpdateStatus(const QString&)), ui_->artists_collection->status(), SLOT(setText(const QString&)));
|
||||
connect(service_, SIGNAL(ArtistsProgressSetMaximum(const int)), ui_->artists_collection->progressbar(), SLOT(setMaximum(const int)));
|
||||
connect(service_, SIGNAL(ArtistsUpdateProgress(const int)), ui_->artists_collection->progressbar(), SLOT(setValue(const int)));
|
||||
connect(service_, SIGNAL(ArtistsResults(SongList, QString)), SLOT(ArtistsFinished(SongList, QString)));
|
||||
connect(service_, SIGNAL(ArtistsUpdateStatus(QString)), ui_->artists_collection->status(), SLOT(setText(QString)));
|
||||
connect(service_, SIGNAL(ArtistsProgressSetMaximum(int)), ui_->artists_collection->progressbar(), SLOT(setMaximum(int)));
|
||||
connect(service_, SIGNAL(ArtistsUpdateProgress(int)), ui_->artists_collection->progressbar(), SLOT(setValue(int)));
|
||||
|
||||
connect(service_->artists_collection_model(), SIGNAL(TotalArtistCountUpdated(int)), ui_->artists_collection->view(), SLOT(TotalArtistCountUpdated(int)));
|
||||
connect(service_->artists_collection_model(), SIGNAL(TotalAlbumCountUpdated(int)), ui_->artists_collection->view(), SLOT(TotalAlbumCountUpdated(int)));
|
||||
@ -101,15 +99,15 @@ InternetTabsView::InternetTabsView(Application *app, InternetService *service, I
|
||||
ui_->albums_collection->filter()->SetCollectionModel(service_->albums_collection_model());
|
||||
|
||||
connect(ui_->albums_collection->view(), SIGNAL(GetSongs()), SLOT(GetAlbums()));
|
||||
connect(ui_->albums_collection->view(), SIGNAL(RemoveSongs(const SongList&)), service_, SIGNAL(RemoveAlbums(const SongList&)));
|
||||
connect(ui_->albums_collection->view(), SIGNAL(RemoveSongs(SongList)), service_, SIGNAL(RemoveAlbums(SongList)));
|
||||
|
||||
connect(ui_->albums_collection->button_refresh(), SIGNAL(clicked()), SLOT(GetAlbums()));
|
||||
connect(ui_->albums_collection->button_close(), SIGNAL(clicked()), SLOT(AbortGetAlbums()));
|
||||
connect(ui_->albums_collection->button_abort(), SIGNAL(clicked()), SLOT(AbortGetAlbums()));
|
||||
connect(service_, SIGNAL(AlbumsResults(const SongList&, const QString&)), SLOT(AlbumsFinished(const SongList&, const QString&)));
|
||||
connect(service_, SIGNAL(AlbumsUpdateStatus(const QString&)), ui_->albums_collection->status(), SLOT(setText(const QString&)));
|
||||
connect(service_, SIGNAL(AlbumsProgressSetMaximum(const int)), ui_->albums_collection->progressbar(), SLOT(setMaximum(const int)));
|
||||
connect(service_, SIGNAL(AlbumsUpdateProgress(const int)), ui_->albums_collection->progressbar(), SLOT(setValue(const int)));
|
||||
connect(service_, SIGNAL(AlbumsResults(SongList, QString)), SLOT(AlbumsFinished(SongList, QString)));
|
||||
connect(service_, SIGNAL(AlbumsUpdateStatus(QString)), ui_->albums_collection->status(), SLOT(setText(QString)));
|
||||
connect(service_, SIGNAL(AlbumsProgressSetMaximum(int)), ui_->albums_collection->progressbar(), SLOT(setMaximum(int)));
|
||||
connect(service_, SIGNAL(AlbumsUpdateProgress(int)), ui_->albums_collection->progressbar(), SLOT(setValue(int)));
|
||||
|
||||
connect(service_->albums_collection_model(), SIGNAL(TotalArtistCountUpdated(int)), ui_->albums_collection->view(), SLOT(TotalArtistCountUpdated(int)));
|
||||
connect(service_->albums_collection_model(), SIGNAL(TotalAlbumCountUpdated(int)), ui_->albums_collection->view(), SLOT(TotalAlbumCountUpdated(int)));
|
||||
@ -132,15 +130,15 @@ InternetTabsView::InternetTabsView(Application *app, InternetService *service, I
|
||||
ui_->songs_collection->filter()->SetCollectionModel(service_->songs_collection_model());
|
||||
|
||||
connect(ui_->songs_collection->view(), SIGNAL(GetSongs()), SLOT(GetSongs()));
|
||||
connect(ui_->songs_collection->view(), SIGNAL(RemoveSongs(const SongList&)), service_, SIGNAL(RemoveSongs(const SongList&)));
|
||||
connect(ui_->songs_collection->view(), SIGNAL(RemoveSongs(SongList)), service_, SIGNAL(RemoveSongs(SongList)));
|
||||
|
||||
connect(ui_->songs_collection->button_refresh(), SIGNAL(clicked()), SLOT(GetSongs()));
|
||||
connect(ui_->songs_collection->button_close(), SIGNAL(clicked()), SLOT(AbortGetSongs()));
|
||||
connect(ui_->songs_collection->button_abort(), SIGNAL(clicked()), SLOT(AbortGetSongs()));
|
||||
connect(service_, SIGNAL(SongsResults(const SongList&, const QString&)), SLOT(SongsFinished(const SongList&, const QString&)));
|
||||
connect(service_, SIGNAL(SongsUpdateStatus(const QString&)), ui_->songs_collection->status(), SLOT(setText(const QString&)));
|
||||
connect(service_, SIGNAL(SongsProgressSetMaximum(const int)), ui_->songs_collection->progressbar(), SLOT(setMaximum(const int)));
|
||||
connect(service_, SIGNAL(SongsUpdateProgress(const int)), ui_->songs_collection->progressbar(), SLOT(setValue(const int)));
|
||||
connect(service_, SIGNAL(SongsResults(SongList, QString)), SLOT(SongsFinished(SongList, QString)));
|
||||
connect(service_, SIGNAL(SongsUpdateStatus(QString)), ui_->songs_collection->status(), SLOT(setText(QString)));
|
||||
connect(service_, SIGNAL(SongsProgressSetMaximum(int)), ui_->songs_collection->progressbar(), SLOT(setMaximum(int)));
|
||||
connect(service_, SIGNAL(SongsUpdateProgress(int)), ui_->songs_collection->progressbar(), SLOT(setValue(int)));
|
||||
|
||||
connect(service_->songs_collection_model(), SIGNAL(TotalArtistCountUpdated(int)), ui_->songs_collection->view(), SLOT(TotalArtistCountUpdated(int)));
|
||||
connect(service_->songs_collection_model(), SIGNAL(TotalAlbumCountUpdated(int)), ui_->songs_collection->view(), SLOT(TotalAlbumCountUpdated(int)));
|
||||
|
@ -35,7 +35,6 @@ class QContextMenuEvent;
|
||||
|
||||
class Application;
|
||||
class InternetService;
|
||||
class InternetSearch;
|
||||
class InternetCollectionView;
|
||||
class InternetSearchView;
|
||||
|
||||
@ -43,7 +42,7 @@ class InternetTabsView : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit InternetTabsView(Application *app, InternetService *service, InternetSearch *engine, const QString &settings_group, const SettingsDialog::Page settings_page, QWidget *parent = nullptr);
|
||||
explicit InternetTabsView(Application *app, InternetService *service, const QString &settings_group, const SettingsDialog::Page settings_page, QWidget *parent = nullptr);
|
||||
~InternetTabsView();
|
||||
|
||||
void ReloadSettings();
|
||||
@ -68,7 +67,6 @@ class InternetTabsView : public QWidget {
|
||||
private:
|
||||
Application *app_;
|
||||
InternetService *service_;
|
||||
InternetSearch *engine_;
|
||||
QString settings_group_;
|
||||
SettingsDialog::Page settings_page_;
|
||||
Ui_InternetTabsView *ui_;
|
||||
|
@ -10,9 +10,18 @@
|
||||
<height>660</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="windowTitle">
|
||||
<string>Internet Tabs View</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_internettabsview">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabs">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
|
@ -67,7 +67,7 @@ const char *SubsonicService::kSongsFtsTable = "subsonic_songs_fts";
|
||||
const int SubsonicService::kMaxRedirects = 3;
|
||||
|
||||
SubsonicService::SubsonicService(Application *app, QObject *parent)
|
||||
: InternetService(Song::Source_Subsonic, "Subsonic", "subsonic", app, parent),
|
||||
: InternetService(Song::Source_Subsonic, "Subsonic", "subsonic", SubsonicSettingsPage::kSettingsGroup, SettingsDialog::Page_Subsonic, app, parent),
|
||||
app_(app),
|
||||
network_(new QNetworkAccessManager),
|
||||
url_handler_(new SubsonicUrlHandler(app, this)),
|
||||
|
Loading…
x
Reference in New Issue
Block a user