Improve coding style and formatting in dbquery code
This commit is contained in:
parent
a32db9e33d
commit
8e59c5b24f
|
@ -59,36 +59,37 @@ QUrl QueryResultsModel::webUrl(const QModelIndex &index)
|
|||
|
||||
TagValue QueryResultsModel::fieldValue(int row, KnownField knownField) const
|
||||
{
|
||||
if (row < m_results.size()) {
|
||||
const SongDescription &res = m_results.at(row);
|
||||
switch (knownField) {
|
||||
case KnownField::Title:
|
||||
returnValue(title);
|
||||
case KnownField::Album:
|
||||
returnValue(album);
|
||||
case KnownField::Artist:
|
||||
returnValue(artist);
|
||||
case KnownField::Genre:
|
||||
returnValue(genre);
|
||||
case KnownField::Year:
|
||||
returnValue(year);
|
||||
case KnownField::TrackPosition:
|
||||
return TagValue(PositionInSet(res.track, res.totalTracks));
|
||||
case KnownField::PartNumber:
|
||||
return TagValue(res.track);
|
||||
case KnownField::TotalParts:
|
||||
return TagValue(res.totalTracks);
|
||||
case KnownField::Cover:
|
||||
if (!res.cover.isEmpty()) {
|
||||
TagValue tagValue(res.cover.data(), static_cast<size_t>(res.cover.size()), TagDataType::Picture);
|
||||
tagValue.setMimeType(containerMimeType(parseSignature(res.cover.data(), res.cover.size())));
|
||||
return tagValue;
|
||||
}
|
||||
break;
|
||||
case KnownField::Lyrics:
|
||||
returnValue(lyrics);
|
||||
default:;
|
||||
if (row >= m_results.size()) {
|
||||
return TagValue();
|
||||
}
|
||||
const SongDescription &res = m_results.at(row);
|
||||
switch (knownField) {
|
||||
case KnownField::Title:
|
||||
returnValue(title);
|
||||
case KnownField::Album:
|
||||
returnValue(album);
|
||||
case KnownField::Artist:
|
||||
returnValue(artist);
|
||||
case KnownField::Genre:
|
||||
returnValue(genre);
|
||||
case KnownField::Year:
|
||||
returnValue(year);
|
||||
case KnownField::TrackPosition:
|
||||
return TagValue(PositionInSet(res.track, res.totalTracks));
|
||||
case KnownField::PartNumber:
|
||||
return TagValue(res.track);
|
||||
case KnownField::TotalParts:
|
||||
return TagValue(res.totalTracks);
|
||||
case KnownField::Cover:
|
||||
if (!res.cover.isEmpty()) {
|
||||
TagValue tagValue(res.cover.data(), static_cast<size_t>(res.cover.size()), TagDataType::Picture);
|
||||
tagValue.setMimeType(containerMimeType(parseSignature(res.cover.data(), res.cover.size())));
|
||||
return tagValue;
|
||||
}
|
||||
break;
|
||||
case KnownField::Lyrics:
|
||||
returnValue(lyrics);
|
||||
default:;
|
||||
}
|
||||
return TagValue();
|
||||
}
|
||||
|
@ -97,38 +98,39 @@ TagValue QueryResultsModel::fieldValue(int row, KnownField knownField) const
|
|||
|
||||
QVariant QueryResultsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (index.isValid() && index.row() < m_results.size()) {
|
||||
const SongDescription &res = m_results.at(index.row());
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (index.column()) {
|
||||
case TitleCol:
|
||||
return res.title;
|
||||
case AlbumCol:
|
||||
return res.album;
|
||||
case ArtistCol:
|
||||
return res.artist;
|
||||
case GenreCol:
|
||||
return res.genre;
|
||||
case YearCol:
|
||||
return res.year;
|
||||
case TrackCol:
|
||||
if (res.track) {
|
||||
return res.track;
|
||||
} else {
|
||||
return QString();
|
||||
}
|
||||
case TotalTracksCol:
|
||||
if (res.totalTracks) {
|
||||
return res.totalTracks;
|
||||
} else {
|
||||
return QString();
|
||||
}
|
||||
default:;
|
||||
if (!index.isValid() || index.row() >= m_results.size()) {
|
||||
return QVariant();
|
||||
}
|
||||
const SongDescription &res = m_results.at(index.row());
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (index.column()) {
|
||||
case TitleCol:
|
||||
return res.title;
|
||||
case AlbumCol:
|
||||
return res.album;
|
||||
case ArtistCol:
|
||||
return res.artist;
|
||||
case GenreCol:
|
||||
return res.genre;
|
||||
case YearCol:
|
||||
return res.year;
|
||||
case TrackCol:
|
||||
if (res.track) {
|
||||
return res.track;
|
||||
} else {
|
||||
return QString();
|
||||
}
|
||||
case TotalTracksCol:
|
||||
if (res.totalTracks) {
|
||||
return res.totalTracks;
|
||||
} else {
|
||||
return QString();
|
||||
}
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -186,11 +188,12 @@ int QueryResultsModel::columnCount(const QModelIndex &parent) const
|
|||
|
||||
const QByteArray *QueryResultsModel::cover(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.parent().isValid() && index.row() < m_results.size()) {
|
||||
const QByteArray &cover = m_results.at(index.row()).cover;
|
||||
if (!cover.isEmpty()) {
|
||||
return &cover;
|
||||
}
|
||||
if (!index.isValid() || index.row() >= m_results.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto &cover = m_results.at(index.row()).cover;
|
||||
if (!cover.isEmpty()) {
|
||||
return &cover;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -216,11 +219,12 @@ bool QueryResultsModel::fetchCover(const QModelIndex &index)
|
|||
|
||||
const QString *QueryResultsModel::lyrics(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.parent().isValid() && index.row() < m_results.size()) {
|
||||
const QString &lyrics = m_results.at(index.row()).lyrics;
|
||||
if (!lyrics.isEmpty()) {
|
||||
return &lyrics;
|
||||
}
|
||||
if (!index.isValid() || index.row() >= m_results.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto &lyrics = m_results.at(index.row()).lyrics;
|
||||
if (!lyrics.isEmpty()) {
|
||||
return &lyrics;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -268,16 +272,16 @@ HttpResultsModel::~HttpResultsModel()
|
|||
*/
|
||||
void HttpResultsModel::handleInitialReplyFinished()
|
||||
{
|
||||
auto *reply = static_cast<QNetworkReply *>(sender());
|
||||
auto *const reply = static_cast<QNetworkReply *>(sender());
|
||||
QByteArray data;
|
||||
if (auto *newReply = evaluateReplyResults(reply, data, false)) {
|
||||
if (auto *const newReply = evaluateReplyResults(reply, data, false)) {
|
||||
addReply(newReply, this, &HttpResultsModel::handleInitialReplyFinished);
|
||||
} else {
|
||||
if (!data.isEmpty()) {
|
||||
parseInitialResults(data);
|
||||
}
|
||||
setResultsAvailable(true); // update status, emit resultsAvailable()
|
||||
return;
|
||||
}
|
||||
if (!data.isEmpty()) {
|
||||
parseInitialResults(data);
|
||||
}
|
||||
setResultsAvailable(true); // update status, emit resultsAvailable()
|
||||
}
|
||||
|
||||
QNetworkReply *HttpResultsModel::evaluateReplyResults(QNetworkReply *reply, QByteArray &data, bool alwaysFollowRedirection)
|
||||
|
@ -286,37 +290,35 @@ QNetworkReply *HttpResultsModel::evaluateReplyResults(QNetworkReply *reply, QByt
|
|||
reply->deleteLater();
|
||||
m_replies.removeAll(reply);
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
const QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||
if (!redirectionTarget.isNull()) {
|
||||
// there's a redirection available
|
||||
// -> resolve new URL
|
||||
const QUrl newUrl = reply->url().resolved(redirectionTarget.toUrl());
|
||||
// -> ask user whether to follow redirection unless alwaysFollowRedirection is true
|
||||
if (!alwaysFollowRedirection) {
|
||||
const QString message
|
||||
= tr("<p>Do you want to redirect form <i>%1</i> to <i>%2</i>?</p>").arg(reply->url().toString(), newUrl.toString());
|
||||
alwaysFollowRedirection
|
||||
= QMessageBox::question(nullptr, tr("Search"), message, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes;
|
||||
}
|
||||
if (alwaysFollowRedirection) {
|
||||
return networkAccessManager().get(QNetworkRequest(newUrl));
|
||||
} else {
|
||||
m_errorList << tr("Redirection to: ") + newUrl.toString();
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
if ((data = reply->readAll()).isEmpty()) {
|
||||
m_errorList << tr("Server replied no data.");
|
||||
}
|
||||
#ifdef DEBUG_BUILD
|
||||
cerr << "Results from HTTP query:" << endl;
|
||||
cerr << data.data() << endl;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
m_errorList << reply->errorString();
|
||||
return nullptr;
|
||||
}
|
||||
const auto redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||
if (redirectionTarget.isNull()) {
|
||||
// read all data if it is not redirection
|
||||
if ((data = reply->readAll()).isEmpty()) {
|
||||
m_errorList << tr("Server replied no data.");
|
||||
}
|
||||
#ifdef DEBUG_BUILD
|
||||
cerr << "Results from HTTP query:" << endl;
|
||||
cerr << data.data() << endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// there's a redirection available
|
||||
// -> resolve new URL
|
||||
const auto newUrl = reply->url().resolved(redirectionTarget.toUrl());
|
||||
// -> ask user whether to follow redirection unless alwaysFollowRedirection is true
|
||||
if (!alwaysFollowRedirection) {
|
||||
const auto message = tr("<p>Do you want to redirect form <i>%1</i> to <i>%2</i>?</p>").arg(reply->url().toString(), newUrl.toString());
|
||||
alwaysFollowRedirection = QMessageBox::question(nullptr, tr("Search"), message, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes;
|
||||
}
|
||||
if (alwaysFollowRedirection) {
|
||||
return networkAccessManager().get(QNetworkRequest(newUrl));
|
||||
}
|
||||
m_errorList << tr("Redirection to: ") + newUrl.toString();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -325,40 +327,41 @@ QNetworkReply *HttpResultsModel::evaluateReplyResults(QNetworkReply *reply, QByt
|
|||
*/
|
||||
void HttpResultsModel::abort()
|
||||
{
|
||||
if (!m_replies.isEmpty()) {
|
||||
qDeleteAll(m_replies);
|
||||
m_replies.clear();
|
||||
// must update status manually because handleReplyFinished() won't be called anymore
|
||||
m_errorList << tr("Aborted by user.");
|
||||
setResultsAvailable(true);
|
||||
if (m_replies.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
qDeleteAll(m_replies);
|
||||
m_replies.clear();
|
||||
// must update status manually because handleReplyFinished() won't be called anymore
|
||||
m_errorList << tr("Aborted by user.");
|
||||
setResultsAvailable(true);
|
||||
}
|
||||
|
||||
void HttpResultsModel::handleCoverReplyFinished(QNetworkReply *reply, const QString &albumId, int row)
|
||||
{
|
||||
QByteArray data;
|
||||
if (auto *newReply = evaluateReplyResults(reply, data, true)) {
|
||||
if (auto *const newReply = evaluateReplyResults(reply, data, true)) {
|
||||
addReply(newReply, bind(&HttpResultsModel::handleCoverReplyFinished, this, newReply, albumId, row));
|
||||
} else {
|
||||
if (!data.isEmpty()) {
|
||||
parseCoverResults(albumId, row, data);
|
||||
}
|
||||
setResultsAvailable(true);
|
||||
return;
|
||||
}
|
||||
if (!data.isEmpty()) {
|
||||
parseCoverResults(albumId, row, data);
|
||||
}
|
||||
setResultsAvailable(true);
|
||||
}
|
||||
|
||||
void HttpResultsModel::parseCoverResults(const QString &albumId, int row, const QByteArray &data)
|
||||
{
|
||||
// add cover -> determine album ID and row
|
||||
if (!albumId.isEmpty() && row < m_results.size()) {
|
||||
if (!data.isEmpty()) {
|
||||
m_coverData[albumId] = data;
|
||||
m_results[row].cover = data;
|
||||
emit coverAvailable(index(row, 0));
|
||||
}
|
||||
} else {
|
||||
if (albumId.isEmpty() || row >= m_results.size()) {
|
||||
m_errorList << tr("Internal error: context for cover reply invalid");
|
||||
setResultsAvailable(true);
|
||||
return;
|
||||
}
|
||||
if (!data.isEmpty()) {
|
||||
m_coverData[albumId] = data;
|
||||
m_results[row].cover = data;
|
||||
emit coverAvailable(index(row, 0));
|
||||
}
|
||||
setFetchingCover(false);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ static const QString defaultLyricsWikiaUrl(QStringLiteral("https://lyrics.wikia.
|
|||
|
||||
QUrl lyricsWikiaApiUrl()
|
||||
{
|
||||
const QString &lyricsWikiaUrl = Settings::values().dbQuery.lyricsWikiaUrl;
|
||||
const auto &lyricsWikiaUrl = Settings::values().dbQuery.lyricsWikiaUrl;
|
||||
return QUrl((lyricsWikiaUrl.isEmpty() ? defaultLyricsWikiaUrl : lyricsWikiaUrl) + QStringLiteral("/api.php"));
|
||||
}
|
||||
|
||||
|
@ -33,33 +33,35 @@ LyricsWikiaResultsModel::LyricsWikiaResultsModel(SongDescription &&initialSongDe
|
|||
|
||||
bool LyricsWikiaResultsModel::fetchCover(const QModelIndex &index)
|
||||
{
|
||||
if (!index.parent().isValid() && index.row() < m_results.size()) {
|
||||
SongDescription &desc = m_results[index.row()];
|
||||
if (!desc.cover.isEmpty()) {
|
||||
// cover is already available -> nothing to do
|
||||
} else if (!desc.albumId.isEmpty()) {
|
||||
try {
|
||||
// the item belongs to an album which cover has already been fetched
|
||||
desc.cover = m_coverData.at(desc.albumId);
|
||||
} catch (const out_of_range &) {
|
||||
if (desc.coverUrl.isEmpty()) {
|
||||
// request the cover URL
|
||||
auto *reply = requestAlbumDetails(desc);
|
||||
addReply(reply, bind(&LyricsWikiaResultsModel::handleAlbumDetailsReplyFinished, this, reply, index.row()));
|
||||
setFetchingCover(true);
|
||||
return false;
|
||||
} else {
|
||||
// request the cover art
|
||||
auto *reply = networkAccessManager().get(QNetworkRequest(QUrl(desc.coverUrl)));
|
||||
addReply(reply, bind(&LyricsWikiaResultsModel::handleCoverReplyFinished, this, reply, desc.albumId, index.row()));
|
||||
setFetchingCover(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (index.parent().isValid() || index.row() >= m_results.size()) {
|
||||
return true;
|
||||
}
|
||||
SongDescription &desc = m_results[index.row()];
|
||||
if (!desc.cover.isEmpty()) {
|
||||
// cover is already available -> nothing to do
|
||||
return true;
|
||||
}
|
||||
if (desc.albumId.isEmpty()) {
|
||||
m_errorList << tr("Unable to fetch cover: Album ID unknown");
|
||||
emit resultsAvailable();
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
// the item belongs to an album which cover has already been fetched
|
||||
desc.cover = m_coverData.at(desc.albumId);
|
||||
} catch (const out_of_range &) {
|
||||
if (desc.coverUrl.isEmpty()) {
|
||||
// request the cover URL
|
||||
auto *const reply = requestAlbumDetails(desc);
|
||||
addReply(reply, bind(&LyricsWikiaResultsModel::handleAlbumDetailsReplyFinished, this, reply, index.row()));
|
||||
setFetchingCover(true);
|
||||
} else {
|
||||
m_errorList << tr("Unable to fetch cover: Album ID unknown");
|
||||
emit resultsAvailable();
|
||||
// request the cover art
|
||||
auto *const reply = networkAccessManager().get(QNetworkRequest(QUrl(desc.coverUrl)));
|
||||
addReply(reply, bind(&LyricsWikiaResultsModel::handleCoverReplyFinished, this, reply, desc.albumId, index.row()));
|
||||
setFetchingCover(true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -90,42 +92,27 @@ void LyricsWikiaResultsModel::parseInitialResults(const QByteArray &data)
|
|||
QXmlStreamReader xmlReader(data);
|
||||
|
||||
// parse XML tree
|
||||
// clang-format off
|
||||
#include <qtutilities/misc/xmlparsermacros.h>
|
||||
children
|
||||
{
|
||||
iftag("getArtistResponse")
|
||||
{
|
||||
children {
|
||||
iftag("getArtistResponse") {
|
||||
QString artist;
|
||||
children
|
||||
{
|
||||
iftag("artist")
|
||||
{
|
||||
children {
|
||||
iftag("artist") {
|
||||
artist = text;
|
||||
}
|
||||
eliftag("albums")
|
||||
{
|
||||
children
|
||||
{
|
||||
iftag("albumResult")
|
||||
{
|
||||
} eliftag("albums") {
|
||||
children {
|
||||
iftag("albumResult") {
|
||||
QString album, year;
|
||||
QList<SongDescription> songs;
|
||||
children
|
||||
{
|
||||
iftag("album")
|
||||
{
|
||||
children {
|
||||
iftag("album") {
|
||||
album = text;
|
||||
}
|
||||
eliftag("year")
|
||||
{
|
||||
} eliftag("year") {
|
||||
year = text;
|
||||
}
|
||||
eliftag("songs")
|
||||
{
|
||||
children
|
||||
{
|
||||
iftag("item")
|
||||
{
|
||||
} eliftag("songs") {
|
||||
children {
|
||||
iftag("item") {
|
||||
songs << SongDescription();
|
||||
songs.back().title = text;
|
||||
songs.back().track = songs.size();
|
||||
|
@ -139,7 +126,7 @@ void LyricsWikiaResultsModel::parseInitialResults(const QByteArray &data)
|
|||
if ((m_initialDescription.album.isEmpty() || m_initialDescription.album == album)
|
||||
&& (m_initialDescription.year.isEmpty() || m_initialDescription.year == year)
|
||||
&& (!m_initialDescription.totalTracks || m_initialDescription.totalTracks == songs.size())) {
|
||||
for (SongDescription &song : songs) {
|
||||
for (auto &song : songs) {
|
||||
if ((m_initialDescription.title.isEmpty() || m_initialDescription.title == song.title)
|
||||
&& (!m_initialDescription.track || m_initialDescription.track == song.track)) {
|
||||
song.album = album;
|
||||
|
@ -166,6 +153,7 @@ void LyricsWikiaResultsModel::parseInitialResults(const QByteArray &data)
|
|||
else_skip
|
||||
}
|
||||
#include <qtutilities/misc/undefxmlparsermacros.h>
|
||||
// clang-format on
|
||||
|
||||
// check for parsing errors
|
||||
switch (xmlReader.error()) {
|
||||
|
@ -230,25 +218,18 @@ void LyricsWikiaResultsModel::parseSongDetails(int row, const QByteArray &data)
|
|||
QUrl parsedUrl;
|
||||
|
||||
// parse XML tree
|
||||
// clang-format off
|
||||
QXmlStreamReader xmlReader(data);
|
||||
#include <qtutilities/misc/xmlparsermacros.h>
|
||||
children
|
||||
{
|
||||
iftag("LyricsResult")
|
||||
{
|
||||
children {
|
||||
iftag("LyricsResult") {
|
||||
SongDescription parsedDesc;
|
||||
children
|
||||
{
|
||||
iftag("artist")
|
||||
{
|
||||
children {
|
||||
iftag("artist") {
|
||||
parsedDesc.artist = text;
|
||||
}
|
||||
eliftag("song")
|
||||
{
|
||||
} eliftag("song") {
|
||||
parsedDesc.title = text;
|
||||
}
|
||||
eliftag("url")
|
||||
{
|
||||
} eliftag("url") {
|
||||
parsedUrl = text;
|
||||
}
|
||||
else_skip
|
||||
|
@ -264,6 +245,7 @@ void LyricsWikiaResultsModel::parseSongDetails(int row, const QByteArray &data)
|
|||
else_skip
|
||||
}
|
||||
#include <qtutilities/misc/undefxmlparsermacros.h>
|
||||
// clang-format on
|
||||
|
||||
// check for parsing errors
|
||||
switch (xmlReader.error()) {
|
||||
|
@ -296,12 +278,12 @@ void LyricsWikiaResultsModel::handleLyricsReplyFinished(QNetworkReply *reply, in
|
|||
QByteArray data;
|
||||
if (auto *newReply = evaluateReplyResults(reply, data, true)) {
|
||||
addReply(newReply, bind(&LyricsWikiaResultsModel::handleLyricsReplyFinished, this, newReply, row));
|
||||
} else {
|
||||
if (!data.isEmpty()) {
|
||||
parseLyricsResults(row, data);
|
||||
}
|
||||
setResultsAvailable(true);
|
||||
return;
|
||||
}
|
||||
if (!data.isEmpty()) {
|
||||
parseLyricsResults(row, data);
|
||||
}
|
||||
setResultsAvailable(true);
|
||||
}
|
||||
|
||||
void LyricsWikiaResultsModel::parseLyricsResults(int row, const QByteArray &data)
|
||||
|
@ -318,13 +300,13 @@ void LyricsWikiaResultsModel::parseLyricsResults(int row, const QByteArray &data
|
|||
const QString html(data);
|
||||
|
||||
// parse lyrics from HTML
|
||||
const int lyricsStart = html.indexOf(QLatin1String("<div class='lyricbox'>"));
|
||||
const auto lyricsStart = html.indexOf(QLatin1String("<div class='lyricbox'>"));
|
||||
if (lyricsStart < 0) {
|
||||
m_errorList << tr("Song details requested for %1/%2 do not contain lyrics").arg(assocDesc.artist, assocDesc.title);
|
||||
setResultsAvailable(true);
|
||||
return;
|
||||
}
|
||||
const int lyricsEnd = html.indexOf(QLatin1String("<div class='lyricsbreak'></div>"), lyricsStart);
|
||||
const auto lyricsEnd = html.indexOf(QLatin1String("<div class='lyricsbreak'></div>"), lyricsStart);
|
||||
QTextDocument textDoc;
|
||||
textDoc.setHtml(html.mid(lyricsStart, (lyricsEnd > lyricsStart) ? (lyricsEnd - lyricsStart) : -1));
|
||||
assocDesc.lyrics = textDoc.toPlainText();
|
||||
|
@ -384,7 +366,7 @@ void LyricsWikiaResultsModel::parseAlbumDetailsAndFetchCover(int row, const QByt
|
|||
}
|
||||
|
||||
// request the cover art
|
||||
auto *reply = networkAccessManager().get(QNetworkRequest(QUrl(assocDesc.coverUrl)));
|
||||
auto *const reply = networkAccessManager().get(QNetworkRequest(QUrl(assocDesc.coverUrl)));
|
||||
addReply(reply, bind(&LyricsWikiaResultsModel::handleCoverReplyFinished, this, reply, assocDesc.albumId, row));
|
||||
}
|
||||
|
||||
|
|
|
@ -25,25 +25,29 @@ MusicBrainzResultsModel::MusicBrainzResultsModel(SongDescription &&initialSongDe
|
|||
|
||||
bool MusicBrainzResultsModel::fetchCover(const QModelIndex &index)
|
||||
{
|
||||
if (!index.parent().isValid() && index.row() < m_results.size()) {
|
||||
SongDescription &desc = m_results[index.row()];
|
||||
if (!desc.cover.isEmpty()) {
|
||||
// cover is already available -> nothing to do
|
||||
} else if (!desc.albumId.isEmpty()) {
|
||||
try {
|
||||
// the item belongs to an album which cover has already been fetched
|
||||
desc.cover = m_coverData.at(desc.albumId);
|
||||
} catch (const out_of_range &) {
|
||||
// request the cover art
|
||||
auto *reply = queryCoverArtArchive(desc.albumId);
|
||||
addReply(reply, bind(&MusicBrainzResultsModel::handleCoverReplyFinished, this, reply, desc.albumId, index.row()));
|
||||
setFetchingCover(true);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
m_errorList << tr("Unable to fetch cover: Album ID unknown");
|
||||
emit resultsAvailable();
|
||||
}
|
||||
if (index.parent().isValid() || index.row() >= m_results.size()) {
|
||||
return true;
|
||||
}
|
||||
SongDescription &desc = m_results[index.row()];
|
||||
if (!desc.cover.isEmpty()) {
|
||||
// cover is already available -> nothing to do
|
||||
return true;
|
||||
}
|
||||
|
||||
if (desc.albumId.isEmpty()) {
|
||||
m_errorList << tr("Unable to fetch cover: Album ID unknown");
|
||||
emit resultsAvailable();
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
// the item belongs to an album which cover has already been fetched
|
||||
desc.cover = m_coverData.at(desc.albumId);
|
||||
} catch (const out_of_range &) {
|
||||
// request the cover art
|
||||
auto *const reply = queryCoverArtArchive(desc.albumId);
|
||||
addReply(reply, bind(&MusicBrainzResultsModel::handleCoverReplyFinished, this, reply, desc.albumId, index.row()));
|
||||
setFetchingCover(true);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -64,90 +68,61 @@ void MusicBrainzResultsModel::parseInitialResults(const QByteArray &data)
|
|||
QXmlStreamReader xmlReader(data);
|
||||
|
||||
// parse XML tree
|
||||
// clang-format off
|
||||
#include <qtutilities/misc/xmlparsermacros.h>
|
||||
children
|
||||
{
|
||||
iftag("metadata")
|
||||
{
|
||||
children
|
||||
{
|
||||
iftag("recording-list")
|
||||
{
|
||||
children
|
||||
{
|
||||
iftag("recording")
|
||||
{
|
||||
children {
|
||||
iftag("metadata") {
|
||||
children {
|
||||
iftag("recording-list") {
|
||||
children {
|
||||
iftag("recording") {
|
||||
SongDescription currentDescription(attribute("id").toString());
|
||||
children{ iftag("title"){ currentDescription.title = text;
|
||||
}
|
||||
eliftag("artist-credit")
|
||||
{
|
||||
children
|
||||
{
|
||||
iftag("name-credit")
|
||||
{
|
||||
children
|
||||
{
|
||||
iftag("artist")
|
||||
{
|
||||
children
|
||||
{
|
||||
iftag("name")
|
||||
{
|
||||
currentDescription.artist = text;
|
||||
children {
|
||||
iftag("title") {
|
||||
currentDescription.title = text;
|
||||
} eliftag("artist-credit") {
|
||||
children {
|
||||
iftag("name-credit") {
|
||||
children {
|
||||
iftag("artist") {
|
||||
children {
|
||||
iftag("name") {
|
||||
currentDescription.artist = text;
|
||||
}
|
||||
else_skip
|
||||
}
|
||||
}
|
||||
else_skip
|
||||
}
|
||||
}
|
||||
else_skip
|
||||
}
|
||||
}
|
||||
else_skip
|
||||
}
|
||||
}
|
||||
eliftag("release-list")
|
||||
{
|
||||
children
|
||||
{
|
||||
iftag("release")
|
||||
{
|
||||
if (currentDescription.albumId.isEmpty()) {
|
||||
currentDescription.albumId = attribute("id").toString();
|
||||
}
|
||||
children
|
||||
{
|
||||
iftag("title")
|
||||
{
|
||||
currentDescription.album = text;
|
||||
}
|
||||
eliftag("date")
|
||||
{
|
||||
currentDescription.year = text;
|
||||
}
|
||||
eliftag("medium-list")
|
||||
{
|
||||
children
|
||||
{
|
||||
iftag("medium")
|
||||
{
|
||||
children
|
||||
{
|
||||
iftag("position")
|
||||
{
|
||||
currentDescription.disk = text.toUInt();
|
||||
}
|
||||
eliftag("track-list")
|
||||
{
|
||||
currentDescription.totalTracks = attribute("count").toUInt();
|
||||
children
|
||||
{
|
||||
iftag("track")
|
||||
{
|
||||
children
|
||||
{
|
||||
iftag("number")
|
||||
{
|
||||
currentDescription.track = text.toUInt();
|
||||
} eliftag("release-list") {
|
||||
children {
|
||||
iftag("release") {
|
||||
if (currentDescription.albumId.isEmpty()) {
|
||||
currentDescription.albumId = attribute("id").toString();
|
||||
}
|
||||
children {
|
||||
iftag("title") {
|
||||
currentDescription.album = text;
|
||||
} eliftag("date") {
|
||||
currentDescription.year = text;
|
||||
} eliftag("medium-list") {
|
||||
children {
|
||||
iftag("medium") {
|
||||
children {
|
||||
iftag("position") {
|
||||
currentDescription.disk = text.toInt();
|
||||
} eliftag("track-list") {
|
||||
currentDescription.totalTracks = attribute("count").toInt();
|
||||
children {
|
||||
iftag("track") {
|
||||
children {
|
||||
iftag("number") {
|
||||
currentDescription.track = text.toInt();
|
||||
} else_skip
|
||||
}
|
||||
}
|
||||
else_skip
|
||||
}
|
||||
|
@ -163,44 +138,36 @@ void MusicBrainzResultsModel::parseInitialResults(const QByteArray &data)
|
|||
}
|
||||
else_skip
|
||||
}
|
||||
}
|
||||
else_skip
|
||||
}
|
||||
}
|
||||
eliftag("tag-list")
|
||||
{
|
||||
children
|
||||
{
|
||||
iftag("tag")
|
||||
{
|
||||
children
|
||||
{
|
||||
iftag("name")
|
||||
{
|
||||
if (!currentDescription.genre.isEmpty()) {
|
||||
currentDescription.genre.append(QLatin1Char(' '));
|
||||
} eliftag("tag-list") {
|
||||
children {
|
||||
iftag("tag") {
|
||||
children {
|
||||
iftag("name") {
|
||||
if (!currentDescription.genre.isEmpty()) {
|
||||
currentDescription.genre.append(QLatin1Char(' '));
|
||||
}
|
||||
currentDescription.genre.append(text);
|
||||
}
|
||||
else_skip
|
||||
}
|
||||
currentDescription.genre.append(text);
|
||||
}
|
||||
else_skip
|
||||
}
|
||||
}
|
||||
else_skip
|
||||
}
|
||||
m_results << currentDescription;
|
||||
}
|
||||
else_skip
|
||||
}
|
||||
m_results << currentDescription;
|
||||
}
|
||||
else_skip
|
||||
}
|
||||
}
|
||||
else_skip
|
||||
}
|
||||
}
|
||||
else_skip
|
||||
} // namespace QtGui
|
||||
#include <qtutilities/misc/undefxmlparsermacros.h>
|
||||
// clang-format on
|
||||
|
||||
// check for parsing errors
|
||||
switch (xmlReader.error()) {
|
||||
|
@ -217,7 +184,7 @@ endResetModel();
|
|||
|
||||
QueryResultsModel *queryMusicBrainz(SongDescription &&songDescription)
|
||||
{
|
||||
static const QString defaultMusicBrainzUrl(QStringLiteral("https://musicbrainz.org/ws/2/recording/"));
|
||||
static const auto defaultMusicBrainzUrl(QStringLiteral("https://musicbrainz.org/ws/2/recording/"));
|
||||
|
||||
// compose parts
|
||||
QStringList parts;
|
||||
|
@ -236,7 +203,7 @@ QueryResultsModel *queryMusicBrainz(SongDescription &&songDescription)
|
|||
}
|
||||
|
||||
// compose URL
|
||||
const QString &musicBrainzUrl = Settings::values().dbQuery.musicBrainzUrl;
|
||||
const auto &musicBrainzUrl = Settings::values().dbQuery.musicBrainzUrl;
|
||||
QUrl url(musicBrainzUrl.isEmpty() ? defaultMusicBrainzUrl : (musicBrainzUrl + QStringLiteral("/recording/")));
|
||||
QUrlQuery query;
|
||||
query.addQueryItem(QStringLiteral("query"), parts.join(QStringLiteral(" AND ")));
|
||||
|
@ -250,8 +217,8 @@ QueryResultsModel *queryMusicBrainz(SongDescription &&songDescription)
|
|||
|
||||
QNetworkReply *queryCoverArtArchive(const QString &albumId)
|
||||
{
|
||||
static const QString defaultArchiveUrl(QStringLiteral("https://coverartarchive.org"));
|
||||
const QString &coverArtArchiveUrl = Settings::values().dbQuery.coverArtArchiveUrl;
|
||||
static const auto defaultArchiveUrl(QStringLiteral("https://coverartarchive.org"));
|
||||
const auto &coverArtArchiveUrl = Settings::values().dbQuery.coverArtArchiveUrl;
|
||||
return networkAccessManager().get(QNetworkRequest(QUrl(
|
||||
(coverArtArchiveUrl.isEmpty() ? defaultArchiveUrl : coverArtArchiveUrl) % QStringLiteral("/release/") % albumId % QStringLiteral("/front"))));
|
||||
}
|
||||
|
|
|
@ -101,33 +101,35 @@ DbQueryWidget::~DbQueryWidget()
|
|||
|
||||
void DbQueryWidget::insertSearchTermsFromTagEdit(TagEdit *tagEdit)
|
||||
{
|
||||
if (tagEdit) {
|
||||
// set title, album and artist
|
||||
m_ui->titleLineEdit->setText(tagValueToQString(tagEdit->value(KnownField::Title)));
|
||||
m_ui->albumLineEdit->setText(tagValueToQString(tagEdit->value(KnownField::Album)));
|
||||
m_ui->artistLineEdit->setText(tagValueToQString(tagEdit->value(KnownField::Artist)));
|
||||
if (!tagEdit) {
|
||||
return;
|
||||
}
|
||||
|
||||
// set track number, or if not available part number
|
||||
bool trackValueOk = false;
|
||||
try {
|
||||
TagValue trackValue = tagEdit->value(KnownField::TrackPosition);
|
||||
if (!trackValue.isEmpty()) {
|
||||
m_ui->trackSpinBox->setValue(trackValue.toPositionInSet().position());
|
||||
trackValueOk = true;
|
||||
}
|
||||
} catch (const ConversionException &) {
|
||||
// set title, album and artist
|
||||
m_ui->titleLineEdit->setText(tagValueToQString(tagEdit->value(KnownField::Title)));
|
||||
m_ui->albumLineEdit->setText(tagValueToQString(tagEdit->value(KnownField::Album)));
|
||||
m_ui->artistLineEdit->setText(tagValueToQString(tagEdit->value(KnownField::Artist)));
|
||||
|
||||
// set track number, or if not available part number
|
||||
bool trackValueOk = false;
|
||||
try {
|
||||
TagValue trackValue = tagEdit->value(KnownField::TrackPosition);
|
||||
if (!trackValue.isEmpty()) {
|
||||
m_ui->trackSpinBox->setValue(trackValue.toPositionInSet().position());
|
||||
trackValueOk = true;
|
||||
}
|
||||
if (!trackValueOk) {
|
||||
TagValue trackValue = tagEdit->value(KnownField::PartNumber);
|
||||
if (!trackValue.isEmpty()) {
|
||||
m_ui->trackSpinBox->setValue(trackValue.toInteger());
|
||||
trackValueOk = true;
|
||||
}
|
||||
}
|
||||
if (!trackValueOk) {
|
||||
m_ui->trackSpinBox->clear();
|
||||
} catch (const ConversionException &) {
|
||||
}
|
||||
if (!trackValueOk) {
|
||||
TagValue trackValue = tagEdit->value(KnownField::PartNumber);
|
||||
if (!trackValue.isEmpty()) {
|
||||
m_ui->trackSpinBox->setValue(trackValue.toInteger());
|
||||
trackValueOk = true;
|
||||
}
|
||||
}
|
||||
if (!trackValueOk) {
|
||||
m_ui->trackSpinBox->clear();
|
||||
}
|
||||
}
|
||||
|
||||
SongDescription DbQueryWidget::currentSongDescription() const
|
||||
|
@ -186,50 +188,52 @@ void DbQueryWidget::searchLyricsWikia()
|
|||
|
||||
void DbQueryWidget::abortSearch()
|
||||
{
|
||||
if (m_model) {
|
||||
if (m_model->isFetchingCover()) {
|
||||
// call abort to abort fetching cover
|
||||
m_model->abort();
|
||||
} else if (!m_model->areResultsAvailable()) {
|
||||
// delete model to abort search
|
||||
m_ui->resultsTreeView->setModel(nullptr);
|
||||
delete m_model;
|
||||
m_model = nullptr;
|
||||
if (!m_model) {
|
||||
return;
|
||||
}
|
||||
if (m_model->isFetchingCover()) {
|
||||
// call abort to abort fetching cover
|
||||
m_model->abort();
|
||||
} else if (!m_model->areResultsAvailable()) {
|
||||
// delete model to abort search
|
||||
m_ui->resultsTreeView->setModel(nullptr);
|
||||
delete m_model;
|
||||
m_model = nullptr;
|
||||
|
||||
// update status
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Information);
|
||||
m_ui->notificationLabel->setText(tr("Aborted"));
|
||||
setStatus(true);
|
||||
}
|
||||
// update status
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Information);
|
||||
m_ui->notificationLabel->setText(tr("Aborted"));
|
||||
setStatus(true);
|
||||
}
|
||||
}
|
||||
|
||||
void DbQueryWidget::showResults()
|
||||
{
|
||||
if (m_model) {
|
||||
if (m_model->errorList().isEmpty()) {
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::TaskComplete);
|
||||
if (m_model->results().isEmpty()) {
|
||||
m_ui->notificationLabel->setText(tr("No results available"));
|
||||
} else {
|
||||
m_ui->notificationLabel->setText(tr("%1 result(s) available", 0, m_model->results().size()).arg(m_model->results().size()));
|
||||
}
|
||||
} else {
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Critical);
|
||||
m_ui->notificationLabel->clearText();
|
||||
for (const QString &error : m_model->errorList()) {
|
||||
m_ui->notificationLabel->appendLine(error);
|
||||
}
|
||||
}
|
||||
if (m_model->results().isEmpty()) {
|
||||
m_ui->applyPushButton->setEnabled(false);
|
||||
} else {
|
||||
m_ui->resultsTreeView->selectionModel()->setCurrentIndex(
|
||||
m_model->index(0, 0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
||||
m_ui->applyPushButton->setEnabled(m_tagEditorWidget->activeTagEdit());
|
||||
}
|
||||
setStatus(true);
|
||||
if (!m_model) {
|
||||
return;
|
||||
}
|
||||
if (m_model->errorList().isEmpty()) {
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::TaskComplete);
|
||||
if (m_model->results().isEmpty()) {
|
||||
m_ui->notificationLabel->setText(tr("No results available"));
|
||||
} else {
|
||||
m_ui->notificationLabel->setText(tr("%1 result(s) available", nullptr, m_model->results().size()).arg(m_model->results().size()));
|
||||
}
|
||||
} else {
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Critical);
|
||||
m_ui->notificationLabel->clearText();
|
||||
for (const QString &error : m_model->errorList()) {
|
||||
m_ui->notificationLabel->appendLine(error);
|
||||
}
|
||||
}
|
||||
if (m_model->results().isEmpty()) {
|
||||
m_ui->applyPushButton->setEnabled(false);
|
||||
} else {
|
||||
m_ui->resultsTreeView->selectionModel()->setCurrentIndex(
|
||||
m_model->index(0, 0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
||||
m_ui->applyPushButton->setEnabled(m_tagEditorWidget->activeTagEdit());
|
||||
}
|
||||
setStatus(true);
|
||||
}
|
||||
|
||||
void DbQueryWidget::setStatus(bool aborted)
|
||||
|
@ -254,9 +258,9 @@ void DbQueryWidget::fileStatusChanged(bool, bool hasTags)
|
|||
void DbQueryWidget::applySelectedResults()
|
||||
{
|
||||
// check whether model, tag edit and current selection exist
|
||||
if (TagEdit *tagEdit = m_tagEditorWidget->activeTagEdit()) {
|
||||
if (const QItemSelectionModel *selectionModel = m_ui->resultsTreeView->selectionModel()) {
|
||||
const QModelIndexList selection = selectionModel->selection().indexes();
|
||||
if (auto *const tagEdit = m_tagEditorWidget->activeTagEdit()) {
|
||||
if (const auto *const selectionModel = m_ui->resultsTreeView->selectionModel()) {
|
||||
const auto selection = selectionModel->selection().indexes();
|
||||
if (!selection.isEmpty()) {
|
||||
applyResults(tagEdit, selection.front());
|
||||
}
|
||||
|
@ -290,9 +294,9 @@ void DbQueryWidget::applyMatchingResults(TagEdit *tagEdit)
|
|||
}
|
||||
|
||||
// determine already present title, album and artist
|
||||
const TagValue givenTitle = tagEdit->value(KnownField::Title);
|
||||
const TagValue givenAlbum = tagEdit->value(KnownField::Album);
|
||||
const TagValue givenArtist = tagEdit->value(KnownField::Artist);
|
||||
const auto givenTitle = tagEdit->value(KnownField::Title);
|
||||
const auto givenAlbum = tagEdit->value(KnownField::Album);
|
||||
const auto givenArtist = tagEdit->value(KnownField::Artist);
|
||||
|
||||
// also determine already present track number (which is a little bit more complex -> TODO: improve backend API)
|
||||
int givenTrack;
|
||||
|
@ -352,71 +356,79 @@ void DbQueryWidget::autoInsertMatchingResults()
|
|||
*/
|
||||
void DbQueryWidget::applyResults(TagEdit *tagEdit, const QModelIndex &resultIndex)
|
||||
{
|
||||
if (m_model) {
|
||||
// determine previous value handling
|
||||
PreviousValueHandling previousValueHandling
|
||||
= m_ui->overrideCheckBox->isChecked() ? PreviousValueHandling::Update : PreviousValueHandling::Keep;
|
||||
if (!m_model) {
|
||||
return;
|
||||
}
|
||||
|
||||
// loop through all fields
|
||||
for (const ChecklistItem &item : values().dbQuery.fields.items()) {
|
||||
if (item.isChecked()) {
|
||||
// field should be used
|
||||
const auto field = static_cast<KnownField>(item.id().toInt());
|
||||
int row = resultIndex.row();
|
||||
TagValue value = m_model->fieldValue(row, field);
|
||||
// determine previous value handling
|
||||
const auto previousValueHandling = m_ui->overrideCheckBox->isChecked() ? PreviousValueHandling::Update : PreviousValueHandling::Keep;
|
||||
|
||||
if (value.isEmpty()) {
|
||||
// cover and lyrics might be fetched belated
|
||||
switch (field) {
|
||||
case KnownField::Cover:
|
||||
if (m_model->fetchCover(resultIndex)) {
|
||||
// cover is available now
|
||||
tagEdit->setValue(KnownField::Cover, m_model->fieldValue(row, KnownField::Cover), previousValueHandling);
|
||||
} else {
|
||||
// cover is fetched asynchronously
|
||||
// -> show status
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Progress);
|
||||
m_ui->notificationLabel->appendLine(tr("Retrieving cover art to be applied ..."));
|
||||
setStatus(false);
|
||||
// -> apply cover when available
|
||||
connect(m_model, &QueryResultsModel::coverAvailable, [this, row, previousValueHandling](const QModelIndex &index) {
|
||||
if (row == index.row()) {
|
||||
if (TagEdit *tagEdit = m_tagEditorWidget->activeTagEdit()) {
|
||||
tagEdit->setValue(KnownField::Cover, m_model->fieldValue(row, KnownField::Cover), previousValueHandling);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
// loop through all fields
|
||||
for (const ChecklistItem &item : values().dbQuery.fields.items()) {
|
||||
if (!item.isChecked()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
case KnownField::Lyrics:
|
||||
if (m_model->fetchLyrics(resultIndex)) {
|
||||
// lyrics are available now
|
||||
tagEdit->setValue(KnownField::Lyrics, m_model->fieldValue(row, KnownField::Lyrics), previousValueHandling);
|
||||
} else {
|
||||
// lyrics are fetched asynchronously
|
||||
// -> show status
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Progress);
|
||||
m_ui->notificationLabel->appendLine(tr("Retrieving lyrics to be applied ..."));
|
||||
setStatus(false);
|
||||
// -> apply cover when available
|
||||
connect(m_model, &QueryResultsModel::lyricsAvailable, [this, row, previousValueHandling](const QModelIndex &index) {
|
||||
if (row == index.row()) {
|
||||
if (TagEdit *tagEdit = m_tagEditorWidget->activeTagEdit()) {
|
||||
tagEdit->setValue(KnownField::Lyrics, m_model->fieldValue(row, KnownField::Lyrics), previousValueHandling);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
// determine the field to be used and its value
|
||||
const auto field = static_cast<KnownField>(item.id().toInt());
|
||||
const auto row = resultIndex.row();
|
||||
const auto value = m_model->fieldValue(row, field);
|
||||
|
||||
default:;
|
||||
}
|
||||
} else {
|
||||
// any other fields are just set
|
||||
tagEdit->setValue(field, value, previousValueHandling);
|
||||
}
|
||||
// set the value if available
|
||||
if (!value.isEmpty()) {
|
||||
tagEdit->setValue(field, value, previousValueHandling);
|
||||
continue;
|
||||
}
|
||||
|
||||
// cover and lyrics might be fetched asynchronously
|
||||
switch (field) {
|
||||
case KnownField::Cover:
|
||||
if (m_model->fetchCover(resultIndex)) {
|
||||
// cover is available now
|
||||
tagEdit->setValue(KnownField::Cover, m_model->fieldValue(row, KnownField::Cover), previousValueHandling);
|
||||
continue;
|
||||
}
|
||||
|
||||
// cover is fetched asynchronously
|
||||
// -> show status
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Progress);
|
||||
m_ui->notificationLabel->appendLine(tr("Retrieving cover art to be applied ..."));
|
||||
setStatus(false);
|
||||
// -> apply cover when available
|
||||
connect(m_model, &QueryResultsModel::coverAvailable, [this, row, previousValueHandling](const QModelIndex &index) {
|
||||
if (row != index.row()) {
|
||||
return;
|
||||
}
|
||||
if (auto *const tagEdit = m_tagEditorWidget->activeTagEdit()) {
|
||||
tagEdit->setValue(KnownField::Cover, m_model->fieldValue(row, KnownField::Cover), previousValueHandling);
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case KnownField::Lyrics:
|
||||
if (m_model->fetchLyrics(resultIndex)) {
|
||||
// lyrics are available now
|
||||
tagEdit->setValue(KnownField::Lyrics, m_model->fieldValue(row, KnownField::Lyrics), previousValueHandling);
|
||||
continue;
|
||||
}
|
||||
|
||||
// lyrics are fetched asynchronously
|
||||
// -> show status
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Progress);
|
||||
m_ui->notificationLabel->appendLine(tr("Retrieving lyrics to be applied ..."));
|
||||
setStatus(false);
|
||||
// -> apply cover when available
|
||||
connect(m_model, &QueryResultsModel::lyricsAvailable, [this, row, previousValueHandling](const QModelIndex &index) {
|
||||
if (row != index.row()) {
|
||||
return;
|
||||
}
|
||||
if (auto *const tagEdit = m_tagEditorWidget->activeTagEdit()) {
|
||||
tagEdit->setValue(KnownField::Lyrics, m_model->fieldValue(row, KnownField::Lyrics), previousValueHandling);
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -428,93 +440,98 @@ void DbQueryWidget::insertSearchTermsFromActiveTagEdit()
|
|||
|
||||
void DbQueryWidget::showResultsContextMenu()
|
||||
{
|
||||
if (const QItemSelectionModel *selectionModel = m_ui->resultsTreeView->selectionModel()) {
|
||||
const QModelIndexList selection = selectionModel->selection().indexes();
|
||||
if (!selection.isEmpty()) {
|
||||
QMenu contextMenu;
|
||||
if (m_ui->applyPushButton->isEnabled()) {
|
||||
contextMenu.addAction(m_ui->applyPushButton->icon(), tr("Use selected row"), this,
|
||||
static_cast<void (DbQueryWidget::*)(void)>(&DbQueryWidget::applySelectedResults));
|
||||
}
|
||||
if (m_model && m_model->areResultsAvailable()) {
|
||||
if (!contextMenu.isEmpty()) {
|
||||
contextMenu.addSeparator();
|
||||
}
|
||||
contextMenu.addAction(
|
||||
QIcon::fromTheme(QStringLiteral("view-preview")), tr("Show cover"), this, &DbQueryWidget::fetchAndShowCoverForSelection);
|
||||
contextMenu.addAction(
|
||||
QIcon::fromTheme(QStringLiteral("view-media-lyrics")), tr("Show lyrics"), this, &DbQueryWidget::fetchAndShowLyricsForSelection);
|
||||
contextMenu.addAction(
|
||||
QIcon::fromTheme(QStringLiteral("internet-web-browser")), tr("Show in browser"), this, &DbQueryWidget::openSelectionInBrowser);
|
||||
}
|
||||
contextMenu.exec(QCursor::pos());
|
||||
}
|
||||
const auto *const selectionModel = m_ui->resultsTreeView->selectionModel();
|
||||
if (!selectionModel) {
|
||||
return;
|
||||
}
|
||||
const auto selection = selectionModel->selection().indexes();
|
||||
if (selection.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QMenu contextMenu;
|
||||
if (m_ui->applyPushButton->isEnabled()) {
|
||||
contextMenu.addAction(m_ui->applyPushButton->icon(), tr("Use selected row"), this,
|
||||
static_cast<void (DbQueryWidget::*)(void)>(&DbQueryWidget::applySelectedResults));
|
||||
}
|
||||
if (m_model && m_model->areResultsAvailable()) {
|
||||
if (!contextMenu.isEmpty()) {
|
||||
contextMenu.addSeparator();
|
||||
}
|
||||
contextMenu.addAction(
|
||||
QIcon::fromTheme(QStringLiteral("view-preview")), tr("Show cover"), this, &DbQueryWidget::fetchAndShowCoverForSelection);
|
||||
contextMenu.addAction(
|
||||
QIcon::fromTheme(QStringLiteral("view-media-lyrics")), tr("Show lyrics"), this, &DbQueryWidget::fetchAndShowLyricsForSelection);
|
||||
contextMenu.addAction(
|
||||
QIcon::fromTheme(QStringLiteral("internet-web-browser")), tr("Show in browser"), this, &DbQueryWidget::openSelectionInBrowser);
|
||||
}
|
||||
contextMenu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void DbQueryWidget::fetchAndShowCoverForSelection()
|
||||
{
|
||||
const QModelIndex selectedIndex = this->selectedIndex();
|
||||
const auto selectedIndex = this->selectedIndex();
|
||||
if (!selectedIndex.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (const QByteArray *cover = m_model->cover(selectedIndex)) {
|
||||
if (const QByteArray *const cover = m_model->cover(selectedIndex)) {
|
||||
showCover(*cover);
|
||||
} else {
|
||||
if (m_model->fetchCover(selectedIndex)) {
|
||||
if (const QByteArray *cover = m_model->cover(selectedIndex)) {
|
||||
showCover(*cover);
|
||||
} else {
|
||||
// cover couldn't be fetched, error tracked via resultsAvailable() signal so nothing to do
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_model->fetchCover(selectedIndex)) {
|
||||
if (const QByteArray *const cover = m_model->cover(selectedIndex)) {
|
||||
showCover(*cover);
|
||||
} else {
|
||||
// cover is fetched asynchronously
|
||||
// -> memorize index to be shown
|
||||
m_coverIndex = selectedIndex.row();
|
||||
// -> show status
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Progress);
|
||||
m_ui->notificationLabel->setText(tr("Retrieving cover art ..."));
|
||||
setStatus(false);
|
||||
// cover couldn't be fetched, error tracked via resultsAvailable() signal so nothing to do
|
||||
}
|
||||
} else {
|
||||
// cover is fetched asynchronously
|
||||
// -> memorize index to be shown
|
||||
m_coverIndex = selectedIndex.row();
|
||||
// -> show status
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Progress);
|
||||
m_ui->notificationLabel->setText(tr("Retrieving cover art ..."));
|
||||
setStatus(false);
|
||||
}
|
||||
}
|
||||
|
||||
void DbQueryWidget::fetchAndShowLyricsForSelection()
|
||||
{
|
||||
const QModelIndex selectedIndex = this->selectedIndex();
|
||||
const auto selectedIndex = this->selectedIndex();
|
||||
if (!selectedIndex.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (const QString *lyrics = m_model->lyrics(selectedIndex)) {
|
||||
if (const QString *const lyrics = m_model->lyrics(selectedIndex)) {
|
||||
showLyrics(*lyrics);
|
||||
} else {
|
||||
if (m_model->fetchLyrics(selectedIndex)) {
|
||||
if (const QByteArray *cover = m_model->cover(selectedIndex)) {
|
||||
showLyrics(*cover);
|
||||
} else {
|
||||
// lyrics couldn't be fetched, error tracked via resultsAvailable() signal so nothing to do
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_model->fetchLyrics(selectedIndex)) {
|
||||
if (const QByteArray *cover = m_model->cover(selectedIndex)) {
|
||||
showLyrics(*cover);
|
||||
} else {
|
||||
// lyrics are fetched asynchronously
|
||||
// -> memorize index to be shown
|
||||
m_lyricsIndex = selectedIndex.row();
|
||||
// -> show status
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Progress);
|
||||
m_ui->notificationLabel->setText(tr("Retrieving lyrics ..."));
|
||||
setStatus(false);
|
||||
// lyrics couldn't be fetched, error tracked via resultsAvailable() signal so nothing to do
|
||||
}
|
||||
} else {
|
||||
// lyrics are fetched asynchronously
|
||||
// -> memorize index to be shown
|
||||
m_lyricsIndex = selectedIndex.row();
|
||||
// -> show status
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Progress);
|
||||
m_ui->notificationLabel->setText(tr("Retrieving lyrics ..."));
|
||||
setStatus(false);
|
||||
}
|
||||
}
|
||||
|
||||
void DbQueryWidget::openSelectionInBrowser()
|
||||
{
|
||||
const QModelIndex selectedIndex = this->selectedIndex();
|
||||
const auto selectedIndex = this->selectedIndex();
|
||||
if (!selectedIndex.isValid()) {
|
||||
return;
|
||||
}
|
||||
const QUrl url(m_model->webUrl(selectedIndex));
|
||||
const auto url = m_model->webUrl(selectedIndex);
|
||||
if (url.isEmpty()) {
|
||||
m_ui->notificationLabel->appendLine(tr("No web URL available."));
|
||||
return;
|
||||
|
@ -611,11 +628,11 @@ QModelIndex DbQueryWidget::selectedIndex() const
|
|||
if (!m_model) {
|
||||
return QModelIndex();
|
||||
}
|
||||
const QItemSelectionModel *selectionModel = m_ui->resultsTreeView->selectionModel();
|
||||
const auto *const selectionModel = m_ui->resultsTreeView->selectionModel();
|
||||
if (!selectionModel) {
|
||||
return QModelIndex();
|
||||
}
|
||||
const QModelIndexList selection = selectionModel->selectedRows();
|
||||
const auto selection = selectionModel->selectedRows();
|
||||
if (selection.size() != 1) {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue