diff --git a/dbquery/dbquery.cpp b/dbquery/dbquery.cpp index bb8e009..f99e82a 100644 --- a/dbquery/dbquery.cpp +++ b/dbquery/dbquery.cpp @@ -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(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(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(sender()); + auto *const reply = static_cast(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("

Do you want to redirect form %1 to %2?

").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("

Do you want to redirect form %1 to %2?

").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); } diff --git a/dbquery/lyricswikia.cpp b/dbquery/lyricswikia.cpp index a4bb23e..ada5280 100644 --- a/dbquery/lyricswikia.cpp +++ b/dbquery/lyricswikia.cpp @@ -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 - 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 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 + // 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 - 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 + // 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("
")); + const auto lyricsStart = html.indexOf(QLatin1String("
")); 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("
"), lyricsStart); + const auto lyricsEnd = html.indexOf(QLatin1String("
"), 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)); } diff --git a/dbquery/musicbrainz.cpp b/dbquery/musicbrainz.cpp index bb0901e..38f5e51 100644 --- a/dbquery/musicbrainz.cpp +++ b/dbquery/musicbrainz.cpp @@ -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 - 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 +// 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")))); } diff --git a/gui/dbquerywidget.cpp b/gui/dbquerywidget.cpp index dcdeec5..3887944 100644 --- a/gui/dbquerywidget.cpp +++ b/gui/dbquerywidget.cpp @@ -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(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(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(&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(&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(); }