Improve internet classes
This commit is contained in:
parent
aa43d42cdb
commit
2f72c41cda
|
@ -286,7 +286,6 @@ set(SOURCES
|
||||||
internet/internetservices.cpp
|
internet/internetservices.cpp
|
||||||
internet/internetservice.cpp
|
internet/internetservice.cpp
|
||||||
internet/internetplaylistitem.cpp
|
internet/internetplaylistitem.cpp
|
||||||
internet/internetsearch.cpp
|
|
||||||
internet/internetsearchview.cpp
|
internet/internetsearchview.cpp
|
||||||
internet/internetsearchmodel.cpp
|
internet/internetsearchmodel.cpp
|
||||||
internet/internetsearchsortmodel.cpp
|
internet/internetsearchsortmodel.cpp
|
||||||
|
@ -472,7 +471,6 @@ set(HEADERS
|
||||||
internet/internetservices.h
|
internet/internetservices.h
|
||||||
internet/internetservice.h
|
internet/internetservice.h
|
||||||
internet/internetsongmimedata.h
|
internet/internetsongmimedata.h
|
||||||
internet/internetsearch.h
|
|
||||||
internet/internetsearchview.h
|
internet/internetsearchview.h
|
||||||
internet/internetsearchmodel.h
|
internet/internetsearchmodel.h
|
||||||
internet/localredirectserver.h
|
internet/localredirectserver.h
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
# include "dbus/metatypes.h"
|
# include "dbus/metatypes.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "internet/internetsearch.h"
|
#include "internet/internetsearchview.h"
|
||||||
|
|
||||||
void RegisterMetaTypes() {
|
void RegisterMetaTypes() {
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ void RegisterMetaTypes() {
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
qRegisterMetaType<InternetSearch::ResultList>("InternetSearch::ResultList");
|
qRegisterMetaType<InternetSearchView::ResultList>("InternetSearchView::ResultList");
|
||||||
qRegisterMetaType<InternetSearch::Result>("InternetSearch::Result");
|
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/mimedata.h"
|
||||||
#include "core/iconloader.h"
|
#include "core/iconloader.h"
|
||||||
#include "internetsearch.h"
|
#include "internetsongmimedata.h"
|
||||||
|
#include "internetservice.h"
|
||||||
#include "internetsearchmodel.h"
|
#include "internetsearchmodel.h"
|
||||||
|
#include "internetsearchview.h"
|
||||||
|
|
||||||
InternetSearchModel::InternetSearchModel(InternetSearch *engine, QObject *parent)
|
InternetSearchModel::InternetSearchModel(InternetService *service, QObject *parent)
|
||||||
: QStandardItemModel(parent),
|
: QStandardItemModel(parent),
|
||||||
engine_(engine),
|
service_(service),
|
||||||
proxy_(nullptr),
|
proxy_(nullptr),
|
||||||
use_pretty_covers_(true),
|
use_pretty_covers_(true),
|
||||||
artist_icon_(IconLoader::Load("folder-sound")),
|
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;
|
int sort_index = 0;
|
||||||
|
|
||||||
for (const InternetSearch::Result &result : results) {
|
for (const InternetSearchView::Result &result : results) {
|
||||||
QStandardItem *parent = invisibleRootItem();
|
QStandardItem *parent = invisibleRootItem();
|
||||||
|
|
||||||
// Find (or create) the container nodes for this result if we can.
|
// Find (or create) the container nodes for this result if we can.
|
||||||
|
@ -277,7 +279,7 @@ void InternetSearchModel::Clear() {
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
InternetSearch::ResultList InternetSearchModel::GetChildResults(const QModelIndexList &indexes) const {
|
InternetSearchView::ResultList InternetSearchModel::GetChildResults(const QModelIndexList &indexes) const {
|
||||||
|
|
||||||
QList<QStandardItem*> items;
|
QList<QStandardItem*> items;
|
||||||
for (const QModelIndex &index : indexes) {
|
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;
|
QSet<const QStandardItem*> visited;
|
||||||
|
|
||||||
for (QStandardItem *item : items) {
|
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)) {
|
if (visited->contains(item)) {
|
||||||
return;
|
return;
|
||||||
|
@ -322,7 +324,7 @@ void InternetSearchModel::GetChildResults(const QStandardItem *item, InternetSea
|
||||||
// No - maybe it's a song, add its result if valid
|
// No - maybe it's a song, add its result if valid
|
||||||
QVariant result = item->data(Role_Result);
|
QVariant result = item->data(Role_Result);
|
||||||
if (result.isValid()) {
|
if (result.isValid()) {
|
||||||
results->append(result.value<InternetSearch::Result>());
|
results->append(result.value<InternetSearchView::Result>());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Maybe it's a provider then?
|
// Maybe it's a provider then?
|
||||||
|
@ -344,15 +346,17 @@ void InternetSearchModel::GetChildResults(const QStandardItem *item, InternetSea
|
||||||
}
|
}
|
||||||
|
|
||||||
QMimeData *InternetSearchModel::mimeData(const QModelIndexList &indexes) const {
|
QMimeData *InternetSearchModel::mimeData(const QModelIndexList &indexes) const {
|
||||||
return engine_->LoadTracks(GetChildResults(indexes));
|
|
||||||
|
return LoadTracks(GetChildResults(indexes));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
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);
|
QVariant result_variant = parent->data(InternetSearchModel::Role_Result);
|
||||||
if (result_variant.isValid()) {
|
if (result_variant.isValid()) {
|
||||||
InternetSearch::Result result = result_variant.value<InternetSearch::Result>();
|
InternetSearchView::Result result = result_variant.value<InternetSearchView::Result>();
|
||||||
(*results).append(result);
|
(*results).append(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,7 +373,7 @@ void InternetSearchModel::SetGroupBy(const CollectionModel::Grouping &grouping,
|
||||||
|
|
||||||
if (regroup_now && group_by_ != old_group_by) {
|
if (regroup_now && group_by_ != old_group_by) {
|
||||||
// Walk the tree gathering the results we have already
|
// Walk the tree gathering the results we have already
|
||||||
InternetSearch::ResultList results;
|
InternetSearchView::ResultList results;
|
||||||
GatherResults(invisibleRootItem(), &results);
|
GatherResults(invisibleRootItem(), &results);
|
||||||
|
|
||||||
// Reset the model and re-add all the results using the new grouping.
|
// 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 "core/song.h"
|
||||||
#include "collection/collectionmodel.h"
|
#include "collection/collectionmodel.h"
|
||||||
#include "internetsearch.h"
|
#include "internetsearchview.h"
|
||||||
|
|
||||||
class QMimeData;
|
class QMimeData;
|
||||||
class QSortFilterProxyModel;
|
class QSortFilterProxyModel;
|
||||||
|
|
||||||
|
class MimeData;
|
||||||
|
class InternetService;
|
||||||
|
|
||||||
class InternetSearchModel : public QStandardItemModel {
|
class InternetSearchModel : public QStandardItemModel {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit InternetSearchModel(InternetSearch *engine, QObject *parent = nullptr);
|
explicit InternetSearchModel(InternetService *service, QObject *parent = nullptr);
|
||||||
|
|
||||||
enum Role {
|
enum Role {
|
||||||
Role_Result = CollectionModel::LastRole,
|
Role_Result = CollectionModel::LastRole,
|
||||||
|
@ -61,25 +64,29 @@ class InternetSearchModel : public QStandardItemModel {
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_proxy(QSortFilterProxyModel *proxy) { proxy_ = proxy; }
|
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 SetGroupBy(const CollectionModel::Grouping &grouping, bool regroup_now);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
InternetSearch::ResultList GetChildResults(const QModelIndexList &indexes) const;
|
InternetSearchView::ResultList GetChildResults(const QModelIndexList &indexes) const;
|
||||||
InternetSearch::ResultList GetChildResults(const QList<QStandardItem*> &items) const;
|
InternetSearchView::ResultList GetChildResults(const QList<QStandardItem*> &items) const;
|
||||||
|
|
||||||
QMimeData *mimeData(const QModelIndexList &indexes) 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:
|
public slots:
|
||||||
void AddResults(const InternetSearch::ResultList &results);
|
void AddResults(const InternetSearchView::ResultList &results);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStandardItem *BuildContainers(const Song &metadata, QStandardItem *parent, ContainerKey *key, int level = 0);
|
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:
|
private:
|
||||||
InternetSearch *engine_;
|
InternetService *service_;
|
||||||
QSortFilterProxyModel *proxy_;
|
QSortFilterProxyModel *proxy_;
|
||||||
bool use_pretty_covers_;
|
bool use_pretty_covers_;
|
||||||
QIcon artist_icon_;
|
QIcon artist_icon_;
|
||||||
|
|
|
@ -28,9 +28,9 @@
|
||||||
|
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
#include "collection/collectionmodel.h"
|
#include "collection/collectionmodel.h"
|
||||||
#include "internetsearch.h"
|
|
||||||
#include "internetsearchmodel.h"
|
#include "internetsearchmodel.h"
|
||||||
#include "internetsearchsortmodel.h"
|
#include "internetsearchsortmodel.h"
|
||||||
|
#include "internetsearchview.h"
|
||||||
|
|
||||||
InternetSearchSortModel::InternetSearchSortModel(QObject *parent)
|
InternetSearchSortModel::InternetSearchSortModel(QObject *parent)
|
||||||
: QSortFilterProxyModel(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.
|
// Otherwise we're comparing songs. Sort by disc, track, then title.
|
||||||
const InternetSearch::Result r1 = left.data(InternetSearchModel::Role_Result).value<InternetSearch::Result>();
|
const InternetSearchView::Result r1 = left.data(InternetSearchModel::Role_Result).value<InternetSearchView::Result>();
|
||||||
const InternetSearch::Result r2 = right.data(InternetSearchModel::Role_Result).value<InternetSearch::Result>();
|
const InternetSearchView::Result r2 = right.data(InternetSearchModel::Role_Result).value<InternetSearchView::Result>();
|
||||||
|
|
||||||
#define CompareInt(field) \
|
#define CompareInt(field) \
|
||||||
if (r1.metadata_.field() < r2.metadata_.field()) return true; \
|
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
|
* Strawberry Music Player
|
||||||
* This code was part of Clementine (GlobalSearch)
|
* This code was part of Clementine (GlobalSearch)
|
||||||
* Copyright 2012, David Sansome <me@davidsansome.com>
|
* 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
|
* Strawberry is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -24,18 +24,25 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QMap>
|
#include <QSet>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QMap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QImage>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
#include <QPixmapCache>
|
||||||
#include <QScopedPointer>
|
#include <QScopedPointer>
|
||||||
|
#include <QMetaType>
|
||||||
|
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
#include "collection/collectionmodel.h"
|
#include "collection/collectionmodel.h"
|
||||||
|
#include "covermanager/albumcoverloaderoptions.h"
|
||||||
#include "settings/settingsdialog.h"
|
#include "settings/settingsdialog.h"
|
||||||
#include "internetsearch.h"
|
|
||||||
|
|
||||||
class QSortFilterProxyModel;
|
class QSortFilterProxyModel;
|
||||||
class QMimeData;
|
class QMimeData;
|
||||||
|
@ -48,11 +55,13 @@ class QKeyEvent;
|
||||||
class QShowEvent;
|
class QShowEvent;
|
||||||
class QHideEvent;
|
class QHideEvent;
|
||||||
class QContextMenuEvent;
|
class QContextMenuEvent;
|
||||||
|
class QTimerEvent;
|
||||||
|
|
||||||
class QModelIndex;
|
|
||||||
class Application;
|
class Application;
|
||||||
class MimeData;
|
class MimeData;
|
||||||
class GroupByDialog;
|
class GroupByDialog;
|
||||||
|
class AlbumCoverLoader;
|
||||||
|
class InternetService;
|
||||||
class InternetSearchModel;
|
class InternetSearchModel;
|
||||||
class Ui_InternetSearchView;
|
class Ui_InternetSearchView;
|
||||||
|
|
||||||
|
@ -63,80 +72,127 @@ class InternetSearchView : public QWidget {
|
||||||
explicit InternetSearchView(QWidget *parent = nullptr);
|
explicit InternetSearchView(QWidget *parent = nullptr);
|
||||||
~InternetSearchView();
|
~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);
|
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 showEvent(QShowEvent *e);
|
||||||
void hideEvent(QHideEvent *e);
|
void hideEvent(QHideEvent *e);
|
||||||
bool eventFilter(QObject *object, QEvent *event);
|
bool eventFilter(QObject *object, QEvent *e);
|
||||||
|
void timerEvent(QTimerEvent *e);
|
||||||
|
|
||||||
public slots:
|
// These functions treat queries in the same way as CollectionQuery.
|
||||||
void ReloadSettings();
|
// They're useful for figuring out whether you got a result because it matched in the song title or the artist/album name.
|
||||||
void StartSearch(const QString &query);
|
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 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:
|
signals:
|
||||||
void AddToPlaylist(QMimeData *data);
|
void AddToPlaylist(QMimeData*);
|
||||||
void AddArtistsSignal(SongList songs);
|
void AddArtistsSignal(SongList);
|
||||||
void AddAlbumsSignal(SongList songs);
|
void AddAlbumsSignal(SongList);
|
||||||
void AddSongsSignal(SongList songs);
|
void AddSongsSignal(SongList);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void SwapModels();
|
void SwapModels();
|
||||||
void TextEdited(const QString &text);
|
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 UpdateStatus(const int id, const QString &text);
|
||||||
void ProgressSetMaximum(const int id, const int progress);
|
void ProgressSetMaximum(const int id, const int progress);
|
||||||
void UpdateProgress(const int id, const int max);
|
void UpdateProgress(const int id, const int max);
|
||||||
void AddResults(const int id, const InternetSearch::ResultList &results);
|
void AddResults(const int id, const ResultList &results);
|
||||||
void SearchError(const int id, const QString &error);
|
|
||||||
void AlbumCoverLoaded(const int id, const QPixmap &pixmap);
|
|
||||||
|
|
||||||
void FocusOnFilter(QKeyEvent *event);
|
void FocusOnFilter(QKeyEvent *e);
|
||||||
|
|
||||||
void AddSelectedToPlaylist();
|
void AddSelectedToPlaylist();
|
||||||
void LoadSelected();
|
void LoadSelected();
|
||||||
void OpenSelectedInNewPlaylist();
|
void OpenSelectedInNewPlaylist();
|
||||||
void AddSelectedToPlaylistEnqueue();
|
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 AddArtists();
|
||||||
void AddAlbums();
|
void AddAlbums();
|
||||||
void AddSongs();
|
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:
|
private:
|
||||||
MimeData *SelectedMimeData();
|
static const int kSwapModelsTimeoutMsec;
|
||||||
|
static const int kDelayedSearchTimeoutMs;
|
||||||
bool SearchKeyEvent(QKeyEvent *event);
|
static const int kArtHeight;
|
||||||
bool ResultsContextMenuEvent(QContextMenuEvent *event);
|
|
||||||
|
|
||||||
|
private:
|
||||||
Application *app_;
|
Application *app_;
|
||||||
InternetSearch *engine_;
|
InternetService *service_;
|
||||||
QString settings_group_;
|
|
||||||
SettingsDialog::Page settings_page_;
|
|
||||||
Ui_InternetSearchView *ui_;
|
Ui_InternetSearchView *ui_;
|
||||||
QScopedPointer<GroupByDialog> group_by_dialog_;
|
QScopedPointer<GroupByDialog> group_by_dialog_;
|
||||||
bool artists_;
|
|
||||||
bool albums_;
|
|
||||||
bool songs_;
|
|
||||||
|
|
||||||
QMenu *context_menu_;
|
QMenu *context_menu_;
|
||||||
QList<QAction*> context_actions_;
|
QList<QAction*> context_actions_;
|
||||||
QActionGroup *group_by_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
|
// 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.
|
// 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.
|
// current_model_ will point to either the front or the back model.
|
||||||
|
@ -148,13 +204,24 @@ class InternetSearchView : public QWidget {
|
||||||
QSortFilterProxyModel *back_proxy_;
|
QSortFilterProxyModel *back_proxy_;
|
||||||
QSortFilterProxyModel *current_proxy_;
|
QSortFilterProxyModel *current_proxy_;
|
||||||
|
|
||||||
QMap<int, QModelIndex> art_requests_;
|
|
||||||
|
|
||||||
QTimer *swap_models_timer_;
|
QTimer *swap_models_timer_;
|
||||||
|
|
||||||
InternetSearch::SearchType search_type_;
|
SearchType search_type_;
|
||||||
bool error_;
|
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
|
#endif // INTERNETSEARCHVIEW_H
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
<height>660</height>
|
<height>660</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Internet Search View</string>
|
||||||
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
|
@ -39,7 +42,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QSearchField" name="search" native="true">
|
<widget class="QSearchField" name="search" native="true">
|
||||||
<property name="placeholderText" stdset="0">
|
<property name="placeholderText" stdset="0">
|
||||||
<string>Search for anything</string>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -62,58 +65,65 @@
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="layout_searchby">
|
<widget class="QWidget" name="widget_searchby" native="true">
|
||||||
<property name="sizeConstraint">
|
<property name="minimumSize">
|
||||||
<enum>QLayout::SetFixedSize</enum>
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<widget class="QLabel" name="label_searchby">
|
<property name="spacing">
|
||||||
<property name="enabled">
|
<number>2</number>
|
||||||
<bool>true</bool>
|
</property>
|
||||||
</property>
|
<property name="leftMargin">
|
||||||
<property name="text">
|
<number>0</number>
|
||||||
<string>Search type</string>
|
</property>
|
||||||
</property>
|
<property name="topMargin">
|
||||||
<property name="margin">
|
<number>0</number>
|
||||||
<number>10</number>
|
</property>
|
||||||
</property>
|
<property name="rightMargin">
|
||||||
</widget>
|
<number>0</number>
|
||||||
</item>
|
</property>
|
||||||
<item>
|
<property name="bottomMargin">
|
||||||
<widget class="QRadioButton" name="radiobutton_search_artists">
|
<number>0</number>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>ar&tists</string>
|
<item>
|
||||||
</property>
|
<widget class="QRadioButton" name="radiobutton_search_artists">
|
||||||
</widget>
|
<property name="text">
|
||||||
</item>
|
<string>artists</string>
|
||||||
<item>
|
</property>
|
||||||
<widget class="QRadioButton" name="radiobutton_search_albums">
|
</widget>
|
||||||
<property name="text">
|
</item>
|
||||||
<string>a&lbums</string>
|
<item>
|
||||||
</property>
|
<widget class="QRadioButton" name="radiobutton_search_albums">
|
||||||
</widget>
|
<property name="text">
|
||||||
</item>
|
<string>albums</string>
|
||||||
<item>
|
</property>
|
||||||
<widget class="QRadioButton" name="radiobutton_search_songs">
|
</widget>
|
||||||
<property name="text">
|
</item>
|
||||||
<string>son&gs</string>
|
<item>
|
||||||
</property>
|
<widget class="QRadioButton" name="radiobutton_search_songs">
|
||||||
</widget>
|
<property name="text">
|
||||||
</item>
|
<string>songs</string>
|
||||||
<item>
|
</property>
|
||||||
<spacer name="horizontalSpacer">
|
</widget>
|
||||||
<property name="orientation">
|
</item>
|
||||||
<enum>Qt::Horizontal</enum>
|
<item>
|
||||||
</property>
|
<spacer name="spacer_searchby">
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="orientation">
|
||||||
<size>
|
<enum>Qt::Horizontal</enum>
|
||||||
<width>40</width>
|
</property>
|
||||||
<height>20</height>
|
<property name="sizeHint" stdset="0">
|
||||||
</size>
|
<size>
|
||||||
</property>
|
<width>40</width>
|
||||||
</spacer>
|
<height>20</height>
|
||||||
</item>
|
</size>
|
||||||
</layout>
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="layout_progress">
|
<layout class="QVBoxLayout" name="layout_progress">
|
||||||
|
@ -215,7 +225,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>398</width>
|
<width>398</width>
|
||||||
<height>511</height>
|
<height>528</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||||
|
|
|
@ -22,9 +22,10 @@
|
||||||
|
|
||||||
#include "internetservice.h"
|
#include "internetservice.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
|
#include "settings/settingsdialog.h"
|
||||||
|
|
||||||
class Application;
|
class Application;
|
||||||
|
|
||||||
InternetService::InternetService(Song::Source source, const QString &name, const QString &url_scheme, Application *app, QObject *parent)
|
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) {
|
: 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 <QIcon>
|
||||||
|
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
#include "internetsearch.h"
|
#include "settings/settingsdialog.h"
|
||||||
|
#include "internetsearchview.h"
|
||||||
|
|
||||||
class QSortFilterProxyModel;
|
class QSortFilterProxyModel;
|
||||||
class Application;
|
class Application;
|
||||||
|
@ -39,7 +40,7 @@ class InternetService : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
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 ~InternetService() {}
|
||||||
virtual void Exit() {}
|
virtual void Exit() {}
|
||||||
|
@ -47,13 +48,15 @@ class InternetService : public QObject {
|
||||||
virtual Song::Source source() const { return source_; }
|
virtual Song::Source source() const { return source_; }
|
||||||
virtual QString name() const { return name_; }
|
virtual QString name() const { return name_; }
|
||||||
virtual QString url_scheme() const { return url_scheme_; }
|
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 bool has_initial_load_settings() const { return false; }
|
||||||
virtual void InitialLoadSettings() {}
|
virtual void InitialLoadSettings() {}
|
||||||
virtual void ReloadSettings() {}
|
virtual void ReloadSettings() {}
|
||||||
virtual QIcon Icon() { return Song::IconForSource(source_); }
|
virtual QIcon Icon() { return Song::IconForSource(source_); }
|
||||||
virtual bool oauth() { return false; }
|
virtual bool oauth() { return false; }
|
||||||
virtual bool authenticated() { 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 void CancelSearch() {}
|
||||||
|
|
||||||
virtual CollectionBackend *artists_collection_backend() { return nullptr; }
|
virtual CollectionBackend *artists_collection_backend() { return nullptr; }
|
||||||
|
@ -129,10 +132,13 @@ class InternetService : public QObject {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Application *app_;
|
Application *app_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Song::Source source_;
|
Song::Source source_;
|
||||||
QString name_;
|
QString name_;
|
||||||
QString url_scheme_;
|
QString url_scheme_;
|
||||||
|
QString settings_group_;
|
||||||
|
SettingsDialog::Page settings_page_;
|
||||||
|
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(InternetService*)
|
Q_DECLARE_METATYPE(InternetService*)
|
||||||
|
|
|
@ -57,15 +57,15 @@ InternetSongsView::InternetSongsView(Application *app, InternetService *service,
|
||||||
ui_->filter->SetCollectionModel(service_->songs_collection_model());
|
ui_->filter->SetCollectionModel(service_->songs_collection_model());
|
||||||
|
|
||||||
connect(ui_->view, SIGNAL(GetSongs()), SLOT(GetSongs()));
|
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_->refresh, SIGNAL(clicked()), SLOT(GetSongs()));
|
||||||
connect(ui_->close, SIGNAL(clicked()), SLOT(AbortGetSongs()));
|
connect(ui_->close, SIGNAL(clicked()), SLOT(AbortGetSongs()));
|
||||||
connect(ui_->abort, 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(SongsResults(SongList, QString)), SLOT(SongsFinished(SongList, QString)));
|
||||||
connect(service_, SIGNAL(SongsUpdateStatus(const QString&)), ui_->status, SLOT(setText(const QString&)));
|
connect(service_, SIGNAL(SongsUpdateStatus(QString)), ui_->status, SLOT(setText(QString)));
|
||||||
connect(service_, SIGNAL(SongsProgressSetMaximum(const int)), ui_->progressbar, SLOT(setMaximum(const int)));
|
connect(service_, SIGNAL(SongsProgressSetMaximum(int)), ui_->progressbar, SLOT(setMaximum(int)));
|
||||||
connect(service_, SIGNAL(SongsUpdateProgress(const int)), ui_->progressbar, SLOT(setValue(const 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(TotalArtistCountUpdated(int)), ui_->view, SLOT(TotalArtistCountUpdated(int)));
|
||||||
connect(service_->songs_collection_model(), SIGNAL(TotalAlbumCountUpdated(int)), ui_->view, SLOT(TotalAlbumCountUpdated(int)));
|
connect(service_->songs_collection_model(), SIGNAL(TotalAlbumCountUpdated(int)), ui_->view, SLOT(TotalAlbumCountUpdated(int)));
|
||||||
|
|
|
@ -40,14 +40,12 @@
|
||||||
#include "internettabsview.h"
|
#include "internettabsview.h"
|
||||||
#include "internetcollectionview.h"
|
#include "internetcollectionview.h"
|
||||||
#include "internetcollectionviewcontainer.h"
|
#include "internetcollectionviewcontainer.h"
|
||||||
#include "internetsearchview.h"
|
|
||||||
#include "ui_internettabsview.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),
|
: QWidget(parent),
|
||||||
app_(app),
|
app_(app),
|
||||||
service_(service),
|
service_(service),
|
||||||
engine_(engine),
|
|
||||||
settings_group_(settings_group),
|
settings_group_(settings_group),
|
||||||
settings_page_(settings_page),
|
settings_page_(settings_page),
|
||||||
ui_(new Ui_InternetTabsView)
|
ui_(new Ui_InternetTabsView)
|
||||||
|
@ -55,10 +53,10 @@ InternetTabsView::InternetTabsView(Application *app, InternetService *service, I
|
||||||
|
|
||||||
ui_->setupUi(this);
|
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());
|
ui_->search_view->Init(app, service);
|
||||||
connect(ui_->search_view, SIGNAL(AddArtistsSignal(const SongList&)), service_, SIGNAL(AddArtists(const SongList&)));
|
connect(ui_->search_view, SIGNAL(AddArtistsSignal(SongList)), service_, SIGNAL(AddArtists(SongList)));
|
||||||
connect(ui_->search_view, SIGNAL(AddAlbumsSignal(const SongList&)), service_, SIGNAL(AddAlbums(const SongList&)));
|
connect(ui_->search_view, SIGNAL(AddAlbumsSignal(SongList)), service_, SIGNAL(AddAlbums(SongList)));
|
||||||
connect(ui_->search_view, SIGNAL(AddSongsSignal(const SongList&)), service_, SIGNAL(AddSongs(const SongList&)));
|
connect(ui_->search_view, SIGNAL(AddSongsSignal(SongList)), service_, SIGNAL(AddSongs(SongList)));
|
||||||
|
|
||||||
if (service_->artists_collection_model()) {
|
if (service_->artists_collection_model()) {
|
||||||
ui_->artists_collection->stacked()->setCurrentWidget(ui_->artists_collection->internetcollection_page());
|
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());
|
ui_->artists_collection->filter()->SetCollectionModel(service_->artists_collection_model());
|
||||||
|
|
||||||
connect(ui_->artists_collection->view(), SIGNAL(GetSongs()), SLOT(GetArtists()));
|
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_refresh(), SIGNAL(clicked()), SLOT(GetArtists()));
|
||||||
connect(ui_->artists_collection->button_close(), SIGNAL(clicked()), SLOT(AbortGetArtists()));
|
connect(ui_->artists_collection->button_close(), SIGNAL(clicked()), SLOT(AbortGetArtists()));
|
||||||
connect(ui_->artists_collection->button_abort(), 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(ArtistsResults(SongList, QString)), SLOT(ArtistsFinished(SongList, QString)));
|
||||||
connect(service_, SIGNAL(ArtistsUpdateStatus(const QString&)), ui_->artists_collection->status(), SLOT(setText(const QString&)));
|
connect(service_, SIGNAL(ArtistsUpdateStatus(QString)), ui_->artists_collection->status(), SLOT(setText(QString)));
|
||||||
connect(service_, SIGNAL(ArtistsProgressSetMaximum(const int)), ui_->artists_collection->progressbar(), SLOT(setMaximum(const int)));
|
connect(service_, SIGNAL(ArtistsProgressSetMaximum(int)), ui_->artists_collection->progressbar(), SLOT(setMaximum(int)));
|
||||||
connect(service_, SIGNAL(ArtistsUpdateProgress(const int)), ui_->artists_collection->progressbar(), SLOT(setValue(const 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(TotalArtistCountUpdated(int)), ui_->artists_collection->view(), SLOT(TotalArtistCountUpdated(int)));
|
||||||
connect(service_->artists_collection_model(), SIGNAL(TotalAlbumCountUpdated(int)), ui_->artists_collection->view(), SLOT(TotalAlbumCountUpdated(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());
|
ui_->albums_collection->filter()->SetCollectionModel(service_->albums_collection_model());
|
||||||
|
|
||||||
connect(ui_->albums_collection->view(), SIGNAL(GetSongs()), SLOT(GetAlbums()));
|
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_refresh(), SIGNAL(clicked()), SLOT(GetAlbums()));
|
||||||
connect(ui_->albums_collection->button_close(), SIGNAL(clicked()), SLOT(AbortGetAlbums()));
|
connect(ui_->albums_collection->button_close(), SIGNAL(clicked()), SLOT(AbortGetAlbums()));
|
||||||
connect(ui_->albums_collection->button_abort(), 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(AlbumsResults(SongList, QString)), SLOT(AlbumsFinished(SongList, QString)));
|
||||||
connect(service_, SIGNAL(AlbumsUpdateStatus(const QString&)), ui_->albums_collection->status(), SLOT(setText(const QString&)));
|
connect(service_, SIGNAL(AlbumsUpdateStatus(QString)), ui_->albums_collection->status(), SLOT(setText(QString)));
|
||||||
connect(service_, SIGNAL(AlbumsProgressSetMaximum(const int)), ui_->albums_collection->progressbar(), SLOT(setMaximum(const int)));
|
connect(service_, SIGNAL(AlbumsProgressSetMaximum(int)), ui_->albums_collection->progressbar(), SLOT(setMaximum(int)));
|
||||||
connect(service_, SIGNAL(AlbumsUpdateProgress(const int)), ui_->albums_collection->progressbar(), SLOT(setValue(const 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(TotalArtistCountUpdated(int)), ui_->albums_collection->view(), SLOT(TotalArtistCountUpdated(int)));
|
||||||
connect(service_->albums_collection_model(), SIGNAL(TotalAlbumCountUpdated(int)), ui_->albums_collection->view(), SLOT(TotalAlbumCountUpdated(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());
|
ui_->songs_collection->filter()->SetCollectionModel(service_->songs_collection_model());
|
||||||
|
|
||||||
connect(ui_->songs_collection->view(), SIGNAL(GetSongs()), SLOT(GetSongs()));
|
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_refresh(), SIGNAL(clicked()), SLOT(GetSongs()));
|
||||||
connect(ui_->songs_collection->button_close(), SIGNAL(clicked()), SLOT(AbortGetSongs()));
|
connect(ui_->songs_collection->button_close(), SIGNAL(clicked()), SLOT(AbortGetSongs()));
|
||||||
connect(ui_->songs_collection->button_abort(), 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(SongsResults(SongList, QString)), SLOT(SongsFinished(SongList, QString)));
|
||||||
connect(service_, SIGNAL(SongsUpdateStatus(const QString&)), ui_->songs_collection->status(), SLOT(setText(const QString&)));
|
connect(service_, SIGNAL(SongsUpdateStatus(QString)), ui_->songs_collection->status(), SLOT(setText(QString)));
|
||||||
connect(service_, SIGNAL(SongsProgressSetMaximum(const int)), ui_->songs_collection->progressbar(), SLOT(setMaximum(const int)));
|
connect(service_, SIGNAL(SongsProgressSetMaximum(int)), ui_->songs_collection->progressbar(), SLOT(setMaximum(int)));
|
||||||
connect(service_, SIGNAL(SongsUpdateProgress(const int)), ui_->songs_collection->progressbar(), SLOT(setValue(const 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(TotalArtistCountUpdated(int)), ui_->songs_collection->view(), SLOT(TotalArtistCountUpdated(int)));
|
||||||
connect(service_->songs_collection_model(), SIGNAL(TotalAlbumCountUpdated(int)), ui_->songs_collection->view(), SLOT(TotalAlbumCountUpdated(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 Application;
|
||||||
class InternetService;
|
class InternetService;
|
||||||
class InternetSearch;
|
|
||||||
class InternetCollectionView;
|
class InternetCollectionView;
|
||||||
class InternetSearchView;
|
class InternetSearchView;
|
||||||
|
|
||||||
|
@ -43,7 +42,7 @@ class InternetTabsView : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
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();
|
~InternetTabsView();
|
||||||
|
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
|
@ -68,7 +67,6 @@ class InternetTabsView : public QWidget {
|
||||||
private:
|
private:
|
||||||
Application *app_;
|
Application *app_;
|
||||||
InternetService *service_;
|
InternetService *service_;
|
||||||
InternetSearch *engine_;
|
|
||||||
QString settings_group_;
|
QString settings_group_;
|
||||||
SettingsDialog::Page settings_page_;
|
SettingsDialog::Page settings_page_;
|
||||||
Ui_InternetTabsView *ui_;
|
Ui_InternetTabsView *ui_;
|
||||||
|
|
|
@ -10,9 +10,18 @@
|
||||||
<height>660</height>
|
<height>660</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<property name="windowTitle">
|
||||||
|
<string>Internet Tabs View</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="layout_internettabsview">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTabWidget" name="tabs">
|
<widget class="QTabWidget" name="tabs">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
|
|
|
@ -67,7 +67,7 @@ const char *SubsonicService::kSongsFtsTable = "subsonic_songs_fts";
|
||||||
const int SubsonicService::kMaxRedirects = 3;
|
const int SubsonicService::kMaxRedirects = 3;
|
||||||
|
|
||||||
SubsonicService::SubsonicService(Application *app, QObject *parent)
|
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),
|
app_(app),
|
||||||
network_(new QNetworkAccessManager),
|
network_(new QNetworkAccessManager),
|
||||||
url_handler_(new SubsonicUrlHandler(app, this)),
|
url_handler_(new SubsonicUrlHandler(app, this)),
|
||||||
|
|
Loading…
Reference in New Issue