2016-03-03 22:21:15 +01:00
|
|
|
#include "./dbquerywidget.h"
|
|
|
|
#include "./tageditorwidget.h"
|
|
|
|
#include "./tagedit.h"
|
|
|
|
|
|
|
|
#include "../application/knownfieldmodel.h"
|
|
|
|
#include "../application/settings.h"
|
|
|
|
#include "../dbquery/dbquery.h"
|
|
|
|
#include "../misc/utility.h"
|
|
|
|
|
|
|
|
#include "ui_dbquerywidget.h"
|
|
|
|
|
|
|
|
#include <tagparser/tag.h>
|
|
|
|
|
|
|
|
#include <qtutilities/misc/dialogutils.h>
|
|
|
|
|
|
|
|
#include <c++utilities/conversion/conversionexception.h>
|
|
|
|
|
|
|
|
#include <QKeyEvent>
|
2016-03-06 17:52:33 +01:00
|
|
|
#include <QMenu>
|
|
|
|
#include <QDialog>
|
|
|
|
#include <QGraphicsView>
|
|
|
|
#include <QGraphicsItem>
|
2016-10-09 22:41:34 +02:00
|
|
|
#include <QTextBrowser>
|
2016-03-03 22:21:15 +01:00
|
|
|
|
2016-10-24 20:15:10 +02:00
|
|
|
#include <functional>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace std::placeholders;
|
2016-03-03 22:21:15 +01:00
|
|
|
using namespace ConversionUtilities;
|
|
|
|
using namespace Dialogs;
|
|
|
|
using namespace Models;
|
|
|
|
using namespace Settings;
|
|
|
|
using namespace Utility;
|
|
|
|
using namespace Media;
|
|
|
|
|
|
|
|
namespace QtGui {
|
|
|
|
|
|
|
|
DbQueryWidget::DbQueryWidget(TagEditorWidget *tagEditorWidget, QWidget *parent) :
|
|
|
|
QWidget(parent),
|
|
|
|
m_ui(new Ui::DbQueryWidget),
|
|
|
|
m_tagEditorWidget(tagEditorWidget),
|
2016-03-06 17:52:33 +01:00
|
|
|
m_model(nullptr),
|
2016-06-02 22:41:01 +02:00
|
|
|
m_coverIndex(-1),
|
2016-10-09 22:41:34 +02:00
|
|
|
m_lyricsIndex(-1),
|
2016-06-02 22:41:01 +02:00
|
|
|
m_menu(new QMenu(parent))
|
2016-03-03 22:21:15 +01:00
|
|
|
{
|
|
|
|
m_ui->setupUi(this);
|
|
|
|
#ifdef Q_OS_WIN32
|
|
|
|
setStyleSheet(dialogStyle());
|
2016-03-05 16:50:23 +01:00
|
|
|
#else
|
|
|
|
setStyleSheet(QStringLiteral("QGroupBox { color: palette(text); background-color: palette(base); }"));
|
2016-03-03 22:21:15 +01:00
|
|
|
#endif
|
|
|
|
|
2016-10-09 19:44:06 +02:00
|
|
|
m_ui->notificationLabel->setText(tr("Search hasn't been started"));
|
2016-03-03 22:21:15 +01:00
|
|
|
m_ui->searchGroupBox->installEventFilter(this);
|
|
|
|
|
|
|
|
// initialize buttons
|
|
|
|
m_ui->abortPushButton->setIcon(style()->standardIcon(QStyle::SP_DialogCancelButton, nullptr, m_ui->abortPushButton));
|
|
|
|
m_ui->abortPushButton->setVisible(false);
|
|
|
|
m_ui->applyPushButton->setIcon(style()->standardIcon(QStyle::SP_DialogApplyButton, nullptr, m_ui->applyPushButton));
|
|
|
|
|
|
|
|
// initialize fields model
|
2016-10-24 20:15:10 +02:00
|
|
|
m_ui->fieldsListView->setModel(&values().dbQuery.fields);
|
2016-03-03 22:21:15 +01:00
|
|
|
|
|
|
|
// initialize search terms form
|
|
|
|
insertSearchTermsFromTagEdit(m_tagEditorWidget->activeTagEdit());
|
|
|
|
|
|
|
|
// restore settings
|
2016-10-24 20:15:10 +02:00
|
|
|
m_ui->overrideCheckBox->setChecked(values().dbQuery.override);
|
2016-03-03 22:21:15 +01:00
|
|
|
|
2016-06-02 22:41:01 +02:00
|
|
|
// setup menu
|
|
|
|
m_insertPresentDataAction = m_menu->addAction(tr("Insert present data"));
|
|
|
|
m_insertPresentDataAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
|
|
|
|
m_insertPresentDataAction->setEnabled(m_tagEditorWidget->activeTagEdit());
|
|
|
|
connect(m_insertPresentDataAction, &QAction::triggered, this, &DbQueryWidget::insertSearchTermsFromActiveTagEdit);
|
|
|
|
QAction *clearSearchCriteria = m_menu->addAction(tr("Clear search criteria"));
|
|
|
|
clearSearchCriteria->setIcon(QIcon::fromTheme(QStringLiteral("edit-clear")));
|
|
|
|
connect(clearSearchCriteria, &QAction::triggered, this, &DbQueryWidget::clearSearchCriteria);
|
|
|
|
m_ui->menuPushButton->setMenu(m_menu);
|
|
|
|
|
2016-03-03 22:21:15 +01:00
|
|
|
// connect signals and slots
|
|
|
|
connect(m_ui->abortPushButton, &QPushButton::clicked, this, &DbQueryWidget::abortSearch);
|
2016-10-09 19:44:06 +02:00
|
|
|
connect(m_ui->searchMusicBrainzPushButton, &QPushButton::clicked, this, &DbQueryWidget::searchMusicBrainz);
|
|
|
|
connect(m_ui->searchLyricsWikiaPushButton, &QPushButton::clicked, this, &DbQueryWidget::searchLyricsWikia);
|
2016-10-24 20:15:10 +02:00
|
|
|
connect(m_ui->applyPushButton, &QPushButton::clicked, this, static_cast<void(DbQueryWidget::*)(void)>(&DbQueryWidget::applySelectedResults));
|
2016-08-07 19:59:33 +02:00
|
|
|
connect(m_tagEditorWidget, &TagEditorWidget::fileStatusChanged, this, &DbQueryWidget::fileStatusChanged);
|
2016-03-06 17:52:33 +01:00
|
|
|
connect(m_ui->resultsTreeView, &QTreeView::customContextMenuRequested, this, &DbQueryWidget::showResultsContextMenu);
|
2016-03-03 22:21:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
DbQueryWidget::~DbQueryWidget()
|
|
|
|
{
|
2016-10-24 20:15:10 +02:00
|
|
|
values().dbQuery.override = m_ui->overrideCheckBox->isChecked();
|
2016-03-03 22:21:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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)));
|
|
|
|
|
|
|
|
// set track number, or if not available part number
|
|
|
|
bool trackValueOk = false;
|
|
|
|
try {
|
|
|
|
TagValue trackValue = tagEdit->value(KnownField::TrackPosition);
|
|
|
|
if(!trackValue.isEmpty()) {
|
2016-03-19 18:34:10 +01:00
|
|
|
m_ui->trackSpinBox->setValue(trackValue.toPositionInSet().position());
|
2016-03-03 22:21:15 +01:00
|
|
|
trackValueOk = true;
|
|
|
|
}
|
|
|
|
} 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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-09 22:41:34 +02:00
|
|
|
SongDescription DbQueryWidget::currentSongDescription() const
|
|
|
|
{
|
|
|
|
SongDescription desc;
|
|
|
|
desc.title = m_ui->titleLineEdit->text();
|
|
|
|
desc.album = m_ui->albumLineEdit->text();
|
|
|
|
desc.artist = m_ui->artistLineEdit->text();
|
|
|
|
desc.track = static_cast<unsigned int>(m_ui->trackSpinBox->value());
|
|
|
|
return desc;
|
|
|
|
}
|
|
|
|
|
2016-10-09 19:44:06 +02:00
|
|
|
void DbQueryWidget::searchMusicBrainz()
|
2016-03-03 22:21:15 +01:00
|
|
|
{
|
2016-10-09 19:44:06 +02:00
|
|
|
// check whether enough search terms are supplied
|
2016-07-27 19:43:07 +02:00
|
|
|
if(m_ui->titleLineEdit->text().isEmpty() && m_ui->albumLineEdit->text().isEmpty() && m_ui->artistLineEdit->text().isEmpty()) {
|
2016-03-03 22:21:15 +01:00
|
|
|
m_ui->notificationLabel->setNotificationType(NotificationType::Critical);
|
2016-10-09 22:41:34 +02:00
|
|
|
m_ui->notificationLabel->setText(tr("Insufficient search criteria supplied - at least title, album or artist must be specified"));
|
2016-03-03 22:21:15 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// delete current model
|
|
|
|
m_ui->resultsTreeView->setModel(nullptr);
|
|
|
|
delete m_model;
|
|
|
|
|
|
|
|
// show status
|
|
|
|
m_ui->notificationLabel->setNotificationType(NotificationType::Progress);
|
2016-10-09 22:41:34 +02:00
|
|
|
m_ui->notificationLabel->setText(tr("Retrieving meta data from MusicBrainz ..."));
|
2016-03-03 22:21:15 +01:00
|
|
|
setStatus(false);
|
|
|
|
|
|
|
|
// do actual query
|
2016-10-09 22:41:34 +02:00
|
|
|
m_ui->resultsTreeView->setModel(m_model = queryMusicBrainz(currentSongDescription()));
|
2016-10-09 19:44:06 +02:00
|
|
|
connect(m_model, &QueryResultsModel::resultsAvailable, this, &DbQueryWidget::showResults);
|
|
|
|
connect(m_model, &QueryResultsModel::coverAvailable, this, &DbQueryWidget::showCoverFromIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DbQueryWidget::searchLyricsWikia()
|
|
|
|
{
|
|
|
|
// check whether enough search terms are supplied
|
|
|
|
if(m_ui->artistLineEdit->text().isEmpty()) {
|
|
|
|
m_ui->notificationLabel->setNotificationType(NotificationType::Critical);
|
2016-10-09 22:41:34 +02:00
|
|
|
m_ui->notificationLabel->setText(tr("Insufficient search criteria supplied - artist is mandatory"));
|
2016-10-09 19:44:06 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// delete current model
|
|
|
|
m_ui->resultsTreeView->setModel(nullptr);
|
|
|
|
delete m_model;
|
|
|
|
|
|
|
|
// show status
|
|
|
|
m_ui->notificationLabel->setNotificationType(NotificationType::Progress);
|
2016-10-09 22:41:34 +02:00
|
|
|
m_ui->notificationLabel->setText(tr("Retrieving meta data from LyricsWikia ..."));
|
2016-10-09 19:44:06 +02:00
|
|
|
setStatus(false);
|
|
|
|
|
|
|
|
// do actual query
|
2016-10-09 22:41:34 +02:00
|
|
|
m_ui->resultsTreeView->setModel(m_model = queryLyricsWikia(currentSongDescription()));
|
2016-03-03 22:21:15 +01:00
|
|
|
connect(m_model, &QueryResultsModel::resultsAvailable, this, &DbQueryWidget::showResults);
|
2016-10-09 22:41:34 +02:00
|
|
|
connect(m_model, &QueryResultsModel::lyricsAvailable, this, &DbQueryWidget::showLyricsFromIndex);
|
2016-03-03 22:21:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void DbQueryWidget::abortSearch()
|
|
|
|
{
|
2016-03-06 17:52:33 +01:00
|
|
|
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;
|
|
|
|
|
|
|
|
// update status
|
|
|
|
m_ui->notificationLabel->setNotificationType(NotificationType::Information);
|
|
|
|
m_ui->notificationLabel->setText(tr("Aborted"));
|
|
|
|
setStatus(true);
|
|
|
|
}
|
2016-03-03 22:21:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2016-03-05 16:50:23 +01:00
|
|
|
m_ui->resultsTreeView->selectionModel()->setCurrentIndex(m_model->index(0, 0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
2016-03-03 22:21:15 +01:00
|
|
|
m_ui->applyPushButton->setEnabled(m_tagEditorWidget->activeTagEdit());
|
|
|
|
}
|
|
|
|
setStatus(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DbQueryWidget::setStatus(bool aborted)
|
|
|
|
{
|
|
|
|
m_ui->abortPushButton->setVisible(!aborted);
|
2016-10-09 19:44:06 +02:00
|
|
|
m_ui->searchMusicBrainzPushButton->setVisible(aborted);
|
|
|
|
m_ui->searchLyricsWikiaPushButton->setVisible(aborted);
|
2016-03-03 22:21:15 +01:00
|
|
|
m_ui->applyPushButton->setVisible(aborted);
|
|
|
|
}
|
|
|
|
|
2016-03-06 17:52:33 +01:00
|
|
|
void DbQueryWidget::fileStatusChanged(bool, bool hasTags)
|
2016-03-03 22:21:15 +01:00
|
|
|
{
|
|
|
|
m_ui->applyPushButton->setEnabled(hasTags && m_ui->resultsTreeView->selectionModel() && m_ui->resultsTreeView->selectionModel()->hasSelection());
|
2016-06-02 22:41:01 +02:00
|
|
|
insertSearchTermsFromActiveTagEdit();
|
|
|
|
m_insertPresentDataAction->setEnabled(hasTags);
|
2016-03-03 22:21:15 +01:00
|
|
|
}
|
|
|
|
|
2016-10-24 20:15:10 +02:00
|
|
|
/*!
|
|
|
|
* \brief Applies the selected results for the selected fields to the active tag edit.
|
|
|
|
* \sa applyResults()
|
|
|
|
*/
|
|
|
|
void DbQueryWidget::applySelectedResults()
|
2016-03-03 22:21:15 +01:00
|
|
|
{
|
2016-03-06 17:52:33 +01:00
|
|
|
// check whether model, tag edit and current selection exist
|
2016-10-24 20:15:10 +02:00
|
|
|
if(TagEdit *tagEdit = m_tagEditorWidget->activeTagEdit()) {
|
|
|
|
if(const QItemSelectionModel *selectionModel = m_ui->resultsTreeView->selectionModel()) {
|
|
|
|
const QModelIndexList selection = selectionModel->selection().indexes();
|
|
|
|
if(!selection.isEmpty()) {
|
|
|
|
applyResults(tagEdit, selection.front());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Completes all present tag edits with the best matching result row.
|
|
|
|
* \remarks
|
|
|
|
* - Does nothing if no result row matches.
|
|
|
|
* - Only the selected fields are applied.
|
|
|
|
* \sa applyResults()
|
|
|
|
*/
|
|
|
|
void DbQueryWidget::applyMatchingResults()
|
|
|
|
{
|
|
|
|
m_tagEditorWidget->foreachTagEdit(bind(static_cast<void(DbQueryWidget::*)(TagEdit *)>(&DbQueryWidget::applyMatchingResults), this, _1));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Completes the specified \a tagEdit with the best matching result row.
|
|
|
|
* \remarks
|
|
|
|
* - Does nothing if no result row matches.
|
|
|
|
* - Only the selected fields are applied.
|
|
|
|
* \sa applyResults()
|
|
|
|
*/
|
|
|
|
void DbQueryWidget::applyMatchingResults(TagEdit *tagEdit)
|
|
|
|
{
|
2016-12-01 22:23:01 +01:00
|
|
|
if(!m_model) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-24 20:15:10 +02:00
|
|
|
// 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);
|
|
|
|
|
|
|
|
// also determine already present track number (which is a little bit more complex -> TODO: improve backend API)
|
|
|
|
int givenTrack;
|
|
|
|
try {
|
|
|
|
givenTrack = tagEdit->value(KnownField::TrackPosition).toPositionInSet().position();
|
|
|
|
} catch (const ConversionException &) {
|
2016-12-01 22:23:01 +01:00
|
|
|
givenTrack = 0;
|
2016-10-24 20:15:10 +02:00
|
|
|
}
|
|
|
|
if(!givenTrack) {
|
|
|
|
for(const Tag *tag : tagEdit->tags()) {
|
|
|
|
if(!tag->supportsTarget() || tag->targetLevel() == TagTargetLevel::Track) {
|
|
|
|
try {
|
|
|
|
givenTrack = tagEdit->value(KnownField::PartNumber).toInteger();
|
|
|
|
} catch (const ConversionException &) {
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-01 22:23:01 +01:00
|
|
|
if(givenTitle.isEmpty() || !givenTrack) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-24 20:15:10 +02:00
|
|
|
// find row matching already present data
|
|
|
|
for(int row = 0, rowCount = m_model->rowCount(); row != rowCount; ++row) {
|
|
|
|
if((!givenTitle.isEmpty() && givenTitle != m_model->fieldValue(row, KnownField::Title))
|
|
|
|
|| (!givenAlbum.isEmpty() && givenAlbum != m_model->fieldValue(row, KnownField::Album))
|
|
|
|
|| (!givenArtist.isEmpty() && givenArtist != m_model->fieldValue(row, KnownField::Artist))
|
2016-12-01 22:23:01 +01:00
|
|
|
|| (givenTrack && givenTrack != m_model->fieldValue(row, KnownField::PartNumber).toInteger())) {
|
2016-10-24 20:15:10 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// apply results for matching row
|
|
|
|
applyResults(tagEdit, m_model->index(row, 0));
|
|
|
|
|
|
|
|
// just take the first matching row for now
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-01 22:23:01 +01:00
|
|
|
/*!
|
|
|
|
* \brief The same as applyMatchingResults() but checks whether auto-insert is enabled before (and does nothing if not).
|
|
|
|
*/
|
|
|
|
void DbQueryWidget::autoInsertMatchingResults()
|
|
|
|
{
|
|
|
|
if(m_ui->autoInsertCheckBox->isChecked()) {
|
|
|
|
applyMatchingResults();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-24 20:15:10 +02:00
|
|
|
/*!
|
|
|
|
* \brief Applies the results at the specified \a resultIndex for the selected fields to the specified \a tagEdit.
|
|
|
|
* \remarks
|
|
|
|
* - Returns instantly. If cover/lyrics need to be retrieved, this is done asynchronously.
|
|
|
|
* - Does nothing if no results are available.
|
|
|
|
*/
|
|
|
|
void DbQueryWidget::applyResults(TagEdit *tagEdit, const QModelIndex &resultIndex)
|
|
|
|
{
|
2016-03-03 22:21:15 +01:00
|
|
|
if(m_model) {
|
2016-10-24 20:15:10 +02:00
|
|
|
// determine previous value handling
|
|
|
|
PreviousValueHandling previousValueHandling = m_ui->overrideCheckBox->isChecked()
|
|
|
|
? PreviousValueHandling::Update : PreviousValueHandling::Keep;
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
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()) {
|
2016-10-09 22:41:34 +02:00
|
|
|
tagEdit->setValue(KnownField::Cover, m_model->fieldValue(row, KnownField::Cover), previousValueHandling);
|
|
|
|
}
|
2016-10-24 20:15:10 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
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()) {
|
2016-10-09 22:41:34 +02:00
|
|
|
tagEdit->setValue(KnownField::Lyrics, m_model->fieldValue(row, KnownField::Lyrics), previousValueHandling);
|
|
|
|
}
|
2016-03-06 17:52:33 +01:00
|
|
|
}
|
2016-10-24 20:15:10 +02:00
|
|
|
});
|
2016-03-06 17:52:33 +01:00
|
|
|
}
|
2016-10-24 20:15:10 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
;
|
2016-03-06 17:52:33 +01:00
|
|
|
}
|
2016-10-24 20:15:10 +02:00
|
|
|
} else {
|
|
|
|
// any other fields are just set
|
|
|
|
tagEdit->setValue(field, value, previousValueHandling);
|
2016-03-06 17:52:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-02 22:41:01 +02:00
|
|
|
void DbQueryWidget::insertSearchTermsFromActiveTagEdit()
|
|
|
|
{
|
|
|
|
insertSearchTermsFromTagEdit(m_tagEditorWidget->activeTagEdit());
|
|
|
|
}
|
|
|
|
|
2016-03-06 17:52:33 +01:00
|
|
|
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()) {
|
2016-10-09 19:44:06 +02:00
|
|
|
contextMenu.addAction(m_ui->applyPushButton->icon(), tr("Use selected row"), this, SLOT(applyResults()));
|
2016-03-06 17:52:33 +01:00
|
|
|
}
|
|
|
|
if(m_model && m_model->areResultsAvailable()) {
|
|
|
|
contextMenu.addAction(QIcon::fromTheme(QStringLiteral("view-preview")), tr("Show cover"), this, SLOT(fetchAndShowCoverForSelection()));
|
2016-10-09 22:41:34 +02:00
|
|
|
contextMenu.addAction(QIcon::fromTheme(QStringLiteral("view-media-lyrics")), tr("Show lyrics"), this, SLOT(fetchAndShowLyricsForSelection()));
|
2016-03-06 17:52:33 +01:00
|
|
|
}
|
|
|
|
contextMenu.exec(QCursor::pos());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DbQueryWidget::fetchAndShowCoverForSelection()
|
|
|
|
{
|
|
|
|
if(m_model) {
|
|
|
|
if(const QItemSelectionModel *selectionModel = m_ui->resultsTreeView->selectionModel()) {
|
|
|
|
const QModelIndexList selection = selectionModel->selection().indexes();
|
|
|
|
if(!selection.isEmpty()) {
|
|
|
|
const QModelIndex &selectedIndex = selection.at(0);
|
|
|
|
if(const QByteArray *cover = m_model->cover(selectedIndex)) {
|
|
|
|
showCover(*cover);
|
|
|
|
} else {
|
|
|
|
if(m_model->fetchCover(selectedIndex)) {
|
|
|
|
if(const QByteArray *cover = m_model->cover(selectedIndex)) {
|
|
|
|
showCover(*cover);
|
|
|
|
} else {
|
2016-10-09 22:41:34 +02:00
|
|
|
// cover couldn't be fetched, error tracks via resultsAvailable() signal so nothing to do
|
2016-03-03 22:21:15 +01:00
|
|
|
}
|
2016-03-06 17:52:33 +01:00
|
|
|
} 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);
|
2016-03-03 22:21:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-09 22:41:34 +02:00
|
|
|
void DbQueryWidget::fetchAndShowLyricsForSelection()
|
|
|
|
{
|
|
|
|
if(m_model) {
|
|
|
|
if(const QItemSelectionModel *selectionModel = m_ui->resultsTreeView->selectionModel()) {
|
|
|
|
const QModelIndexList selection = selectionModel->selection().indexes();
|
|
|
|
if(!selection.isEmpty()) {
|
|
|
|
const QModelIndex &selectedIndex = selection.at(0);
|
|
|
|
if(const QString *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 tracks 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-06 17:52:33 +01:00
|
|
|
void DbQueryWidget::showCover(const QByteArray &data)
|
|
|
|
{
|
|
|
|
QDialog dlg;
|
|
|
|
dlg.setWindowFlags(Qt::Tool);
|
|
|
|
dlg.setWindowTitle(tr("Cover - %1").arg(QApplication::applicationName()));
|
|
|
|
QBoxLayout layout(QBoxLayout::Up);
|
|
|
|
layout.setMargin(0);
|
|
|
|
QGraphicsView view(&dlg);
|
|
|
|
QGraphicsScene scene;
|
|
|
|
layout.addWidget(&view);
|
|
|
|
scene.addItem(new QGraphicsPixmapItem(QPixmap::fromImage(QImage::fromData(data))));
|
|
|
|
view.setScene(&scene);
|
|
|
|
view.show();
|
|
|
|
dlg.setLayout(&layout);
|
|
|
|
dlg.exec();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DbQueryWidget::showCoverFromIndex(const QModelIndex &index)
|
|
|
|
{
|
|
|
|
if(m_coverIndex == index.row()) {
|
|
|
|
m_coverIndex = -1;
|
|
|
|
showCover(*m_model->cover(index));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-09 22:41:34 +02:00
|
|
|
void DbQueryWidget::showLyrics(const QString &data)
|
|
|
|
{
|
|
|
|
QDialog dlg;
|
|
|
|
dlg.setWindowFlags(Qt::Tool);
|
|
|
|
dlg.setWindowTitle(tr("Lyrics - %1").arg(QApplication::applicationName()));
|
|
|
|
QBoxLayout layout(QBoxLayout::Up);
|
|
|
|
layout.setMargin(0);
|
|
|
|
QTextBrowser textBrowser;
|
|
|
|
layout.addWidget(&textBrowser);
|
|
|
|
textBrowser.setText(data);
|
|
|
|
dlg.setLayout(&layout);
|
|
|
|
dlg.resize(400, 400);
|
|
|
|
dlg.exec();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DbQueryWidget::showLyricsFromIndex(const QModelIndex &index)
|
|
|
|
{
|
|
|
|
if(m_lyricsIndex == index.row()) {
|
|
|
|
m_lyricsIndex = -1;
|
|
|
|
showLyrics(*m_model->lyrics(index));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-02 22:41:01 +02:00
|
|
|
void DbQueryWidget::clearSearchCriteria()
|
|
|
|
{
|
|
|
|
m_ui->titleLineEdit->clear();
|
|
|
|
m_ui->albumLineEdit->clear();
|
|
|
|
m_ui->artistLineEdit->clear();
|
|
|
|
m_ui->trackSpinBox->setValue(0);
|
|
|
|
}
|
|
|
|
|
2016-03-03 22:21:15 +01:00
|
|
|
bool DbQueryWidget::eventFilter(QObject *obj, QEvent *event)
|
|
|
|
{
|
2016-03-28 20:28:59 +02:00
|
|
|
if(obj == m_ui->searchGroupBox) {
|
2016-03-03 22:21:15 +01:00
|
|
|
switch(event->type()) {
|
2016-03-28 20:28:59 +02:00
|
|
|
case QEvent::KeyRelease:
|
|
|
|
switch(static_cast<QKeyEvent *>(event)->key()) {
|
2016-03-03 22:21:15 +01:00
|
|
|
case Qt::Key_Return:
|
2016-10-09 19:44:06 +02:00
|
|
|
searchMusicBrainz();
|
2016-03-03 22:21:15 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
break;
|
2016-03-28 20:28:59 +02:00
|
|
|
default:
|
2016-03-03 22:21:15 +01:00
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
2016-03-28 20:28:59 +02:00
|
|
|
return QWidget::eventFilter(obj, event);
|
2016-03-03 22:21:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|