From 0e16a27effb4633ae5e238bf3acc75a7bb847ca6 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Wed, 28 Oct 2020 18:33:14 +0100 Subject: [PATCH 01/23] WTrackMenu: add capabilty RemoveFromDisk, add to Tracks, Hidden, Crates --- src/library/hiddentablemodel.cpp | 4 +++- src/library/librarytablemodel.cpp | 3 ++- src/library/trackmodel.h | 1 + src/library/trackset/crate/cratetablemodel.cpp | 3 ++- src/widget/wtrackmenu.cpp | 2 ++ src/widget/wtrackmenu.h | 11 ++++++----- 6 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/library/hiddentablemodel.cpp b/src/library/hiddentablemodel.cpp index 99d902ab961..6768ce7456c 100644 --- a/src/library/hiddentablemodel.cpp +++ b/src/library/hiddentablemodel.cpp @@ -88,5 +88,7 @@ Qt::ItemFlags HiddenTableModel::flags(const QModelIndex& index) const { } TrackModel::Capabilities HiddenTableModel::getCapabilities() const { - return Capability::Purge | Capability::Unhide; + return Capability::Purge | + Capability::Unhide | + Capability::RemoveFromDisk; } diff --git a/src/library/librarytablemodel.cpp b/src/library/librarytablemodel.cpp index 57ebf573038..4514bc9876e 100644 --- a/src/library/librarytablemodel.cpp +++ b/src/library/librarytablemodel.cpp @@ -95,5 +95,6 @@ TrackModel::Capabilities LibraryTableModel::getCapabilities() const { Capability::LoadToSampler | Capability::LoadToPreviewDeck | Capability::Hide | - Capability::ResetPlayed; + Capability::ResetPlayed | + Capability::RemoveFromDisk; } diff --git a/src/library/trackmodel.h b/src/library/trackmodel.h index f3abf13115a..1bbba584055 100644 --- a/src/library/trackmodel.h +++ b/src/library/trackmodel.h @@ -45,6 +45,7 @@ class TrackModel { Purge = 1u << 13u, RemovePlaylist = 1u << 14u, RemoveCrate = 1u << 15u, + RemoveFromDisk = 1u << 16u, }; Q_DECLARE_FLAGS(Capabilities, Capability) diff --git a/src/library/trackset/crate/cratetablemodel.cpp b/src/library/trackset/crate/cratetablemodel.cpp index c586f6a5f15..85a73d4ceba 100644 --- a/src/library/trackset/crate/cratetablemodel.cpp +++ b/src/library/trackset/crate/cratetablemodel.cpp @@ -108,7 +108,8 @@ TrackModel::Capabilities CrateTableModel::getCapabilities() const { Capability::LoadToSampler | Capability::LoadToPreviewDeck | Capability::RemoveCrate | - Capability::ResetPlayed; + Capability::ResetPlayed | + Capability::RemoveFromDisk; if (m_selectedCrate.isValid()) { Crate crate; diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 99e0b0e2645..a96bc75f977 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1736,6 +1736,8 @@ bool WTrackMenu::featureIsEnabled(Feature flag) const { return m_pTrackModel->hasCapabilities(TrackModel::Capability::Hide) || m_pTrackModel->hasCapabilities(TrackModel::Capability::Unhide) || m_pTrackModel->hasCapabilities(TrackModel::Capability::Purge); + case Feature::RemoveFromDisk: + return m_pTrackModel->hasCapabilities(TrackModel::Capability::RemoveFromDisk); case Feature::FileBrowser: return true; case Feature::Properties: diff --git a/src/widget/wtrackmenu.h b/src/widget/wtrackmenu.h index 1234627bde7..bca46ce4743 100644 --- a/src/widget/wtrackmenu.h +++ b/src/widget/wtrackmenu.h @@ -43,13 +43,14 @@ class WTrackMenu : public QMenu { BPM = 1 << 7, Color = 1 << 8, HideUnhidePurge = 1 << 9, - FileBrowser = 1 << 10, - Properties = 1 << 11, - SearchRelated = 1 << 12, + RemoveFromDisk = 1 << 10, + FileBrowser = 1 << 11, + Properties = 1 << 12, + SearchRelated = 1 << 13, TrackModelFeatures = Remove | HideUnhidePurge, All = AutoDJ | LoadTo | Playlist | Crate | Remove | Metadata | Reset | - BPM | Color | HideUnhidePurge | FileBrowser | Properties | - SearchRelated + BPM | Color | HideUnhidePurge | RemoveFromDisk | FileBrowser | + Properties | SearchRelated }; Q_DECLARE_FLAGS(Features, Feature) From 00b64fba116e7f7b7bc44ba250d62c88a111ccd9 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Wed, 28 Oct 2020 18:43:19 +0100 Subject: [PATCH 02/23] WTrackMenu > Remove from disk: add action, slot and TrackPointerOperation --- src/widget/wtrackmenu.cpp | 155 ++++++++++++++++++++++++++++++++++++++ src/widget/wtrackmenu.h | 2 + 2 files changed, 157 insertions(+) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index a96bc75f977..703d2e213b7 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -207,6 +207,14 @@ void WTrackMenu::createActions() { connect(m_pPurgeAct, &QAction::triggered, this, &WTrackMenu::slotPurge); } + if (featureIsEnabled(Feature::RemoveFromDisk)) { + m_pRemoveFromDiskAct = new QAction(tr("Remove from disk"), this); + connect(m_pRemoveFromDiskAct, + &QAction::triggered, + this, + &WTrackMenu::slotRemoveFromDisk); + } + if (featureIsEnabled(Feature::Properties)) { m_pPropertiesAct = new QAction(tr("Properties"), this); connect(m_pPropertiesAct, &QAction::triggered, this, &WTrackMenu::slotShowDlgTrackInfo); @@ -465,6 +473,11 @@ void WTrackMenu::setupActions() { } } + if (featureIsEnabled(Feature::RemoveFromDisk) && + m_pTrackModel->hasCapabilities(TrackModel::Capability::RemoveFromDisk)) { + addAction(m_pRemoveFromDiskAct); + } + if (featureIsEnabled(Feature::FileBrowser)) { addAction(m_pFileBrowserAct); } @@ -714,6 +727,13 @@ void WTrackMenu::updateMenus() { } } + if (featureIsEnabled(Feature::RemoveFromDisk)) { + bool locked = m_pTrackModel->hasCapabilities(TrackModel::Capability::Locked); + if (m_pTrackModel->hasCapabilities(TrackModel::Capability::RemoveFromDisk)) { + m_pRemoveFromDiskAct->setEnabled(!locked); + } + } + if (featureIsEnabled(Feature::Properties)) { m_pPropertiesAct->setEnabled(singleTrackSelected); } @@ -1528,6 +1548,141 @@ void WTrackMenu::slotClearAllMetadata() { &trackOperator); } +namespace { + +class RemoveTrackFilesFromDiskTrackPointerOperation : public mixxx::TrackPointerOperation { + public: + mutable QList tr_tracksToPurge; + mutable QList tr_tracksToKeep; + + private: + void doApply( + const TrackPointer& pTrack) const override { + auto trackRef = TrackRef::fromFileInfo( + pTrack->getFileInfo(), + pTrack->getId()); + VERIFY_OR_DEBUG_ASSERT(trackRef.isValid()) { + return; + } + QString location = pTrack->getLocation(); + QFile file(location); + if (file.exists() && !file.remove()) { + // Deletion failed, log warning and queue location for the + // Failed Deletions warning. + qWarning() + << "Queued file" + << location + << "could not be deleted. Track is not purged"; + tr_tracksToKeep.append(location); + return; + } else { + // File doesn't exist or was deleted. Queue for purging. + tr_tracksToPurge.append(trackRef); + } + } +}; + +} // anonymous namespace + +void WTrackMenu::slotRemoveFromDisk() { + // Collect & de-duplicate file locations for the Delete warning. + QList trackLocations; + trackLocations.reserve(getTrackCount()); + for (const auto& trackRef : getTrackRefs()) { + DEBUG_ASSERT(trackRef.hasLocation()); + QString location = trackRef.getLocation(); + if (!trackLocations.contains(location)) { + trackLocations.append(location); + } + } + + // TODO Use a dialog with a QListView that can be scrolled horizontally? + // Or improve linebreaks and formatting in the current plain textview. + // TODO Should each item may have a checkbox to allow removing it from the delete list + // or is it okay for the user to Cancel and adjust the selection in the tracks table? + // TODO Allow to keep all selected tracks' references + + // Show Delete warning. + QMessageBox msgBoxDelete(QMessageBox::Critical, + QObject::tr("Delete Files"), + nullptr); + msgBoxDelete.setInformativeText( + QObject::tr("Permanently delete these %1 files from disk?" + " " + "
" + "%2
" + "
" + "This can not be undone!
") + .arg(QString::number(trackLocations.length()), + // Primitive hack to create a pseudo list. + QString(QStringLiteral("• ")) + + trackLocations.join( + QStringLiteral("
• ")))); + msgBoxDelete.setTextFormat(Qt::RichText); + QAbstractButton* deleteBtn = msgBoxDelete.addButton( + tr("Delete Files!"), QMessageBox::AcceptRole); + msgBoxDelete.addButton(QMessageBox::Cancel); + msgBoxDelete.setDefaultButton(QMessageBox::Cancel); + msgBoxDelete.exec(); + if (msgBoxDelete.clickedButton() != deleteBtn) { + return; + } + + // Set up and initiate the track batch operation + const auto progressLabelText = + tr("Removing %1 track file(s) from disk...", + "", + getTrackCount()); + const auto trackOperator = + RemoveTrackFilesFromDiskTrackPointerOperation(); + applyTrackPointerOperation( + progressLabelText, + &trackOperator); + + // Purge deleted tracks and show deletion summary message. + if (trackOperator.tr_tracksToPurge.length() > 0) { + // Purge only those tracks whose files were actually deleted. + m_pLibrary->trackCollections()->purgeTracks(trackOperator.tr_tracksToPurge); + // Optional message box: + QMessageBox msgBoxPurgeTracks(QMessageBox::Information, + QObject::tr("Yeaiij!"), + nullptr); + msgBoxPurgeTracks.setInformativeText( + QObject::tr( + "
" + "%1 annoying tracks were deleted from disk and " + "purged from the Mixxx database." + "

") + .arg(QString::number(trackOperator.tr_tracksToPurge.length()))); + msgBoxPurgeTracks.setTextFormat(Qt::RichText); + msgBoxPurgeTracks.exec(); + } + + // Show list of tracks that could not be deleted and are thus not going to be purged. + if (trackOperator.tr_tracksToKeep.length() >= 0) { + return; + } + QMessageBox msgBoxKeepTracks(QMessageBox::Warning, + QObject::tr("Some Files Were Not Deleted"), + nullptr); + msgBoxKeepTracks.setInformativeText( + QObject::tr("

" + "The following %1 files could not be deleted from disk." + "Make sure you have write access to those files and " + "try again later." + "
" + "%2" + "
") + .arg(QString::number( + trackOperator.tr_tracksToKeep.length()), + // Primitive hack to create a pseudo list. + QString(QStringLiteral("• ")) + + trackOperator.tr_tracksToKeep.join( + QStringLiteral("
• ")))); + msgBoxKeepTracks.setTextFormat(Qt::RichText); + msgBoxKeepTracks.exec(); +} + void WTrackMenu::slotShowDlgTrackInfo() { if (isEmpty()) { return; diff --git a/src/widget/wtrackmenu.h b/src/widget/wtrackmenu.h index bca46ce4743..cd23ca36863 100644 --- a/src/widget/wtrackmenu.h +++ b/src/widget/wtrackmenu.h @@ -129,6 +129,7 @@ class WTrackMenu : public QMenu { void slotHide(); void slotUnhide(); void slotPurge(); + void slotRemoveFromDisk(); private: // This getter verifies that m_pTrackModel is set when @@ -224,6 +225,7 @@ class WTrackMenu : public QMenu { QAction* m_pHideAct{}; QAction* m_pUnhideAct{}; QAction* m_pPurgeAct{}; + QAction* m_pRemoveFromDiskAct{}; // Show track-editor action QAction* m_pPropertiesAct{}; From 7688b29a43c16f3fbfeefcb478f77acafecfd81b Mon Sep 17 00:00:00 2001 From: ronso0 Date: Mon, 23 Nov 2020 18:23:06 +0100 Subject: [PATCH 03/23] WTrackMenu: use QListWidget for track file deletion dialogs --- src/widget/wtrackmenu.cpp | 140 +++++++++++++++++++++----------------- src/widget/wtrackmenu.h | 1 + 2 files changed, 77 insertions(+), 64 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 79e552553fc..03950b27034 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1,8 +1,12 @@ #include "widget/wtrackmenu.h" #include +#include #include +#include +#include #include +#include #include "control/controlobject.h" #include "control/controlproxy.h" @@ -1587,47 +1591,53 @@ class RemoveTrackFilesFromDiskTrackPointerOperation : public mixxx::TrackPointer } // anonymous namespace void WTrackMenu::slotRemoveFromDisk() { - // Collect & de-duplicate file locations for the Delete warning. - QList trackLocations; - trackLocations.reserve(getTrackCount()); - for (const auto& trackRef : getTrackRefs()) { - DEBUG_ASSERT(trackRef.hasLocation()); + const auto trackRefs = getTrackRefs(); + QStringList locations; + locations.reserve(trackRefs.size()); + for (const auto& trackRef : trackRefs) { QString location = trackRef.getLocation(); - if (!trackLocations.contains(location)) { - trackLocations.append(location); - } + // TODO de-duplicate when extending this feature to Playlists + locations.append(location); } - // TODO Use a dialog with a QListView that can be scrolled horizontally? - // Or improve linebreaks and formatting in the current plain textview. + // TODO Resize the dialog appropriately. // TODO Should each item may have a checkbox to allow removing it from the delete list // or is it okay for the user to Cancel and adjust the selection in the tracks table? - // TODO Allow to keep all selected tracks' references - - // Show Delete warning. - QMessageBox msgBoxDelete(QMessageBox::Critical, - QObject::tr("Delete Files"), - nullptr); - msgBoxDelete.setInformativeText( - QObject::tr("Permanently delete these %1 files from disk?" - " " - "
" - "%2
" - "
" - "This can not be undone!
") - .arg(QString::number(trackLocations.length()), - // Primitive hack to create a pseudo list. - QString(QStringLiteral("• ")) + - trackLocations.join( - QStringLiteral("
• ")))); - msgBoxDelete.setTextFormat(Qt::RichText); - QAbstractButton* deleteBtn = msgBoxDelete.addButton( - tr("Delete Files!"), QMessageBox::AcceptRole); - msgBoxDelete.addButton(QMessageBox::Cancel); - msgBoxDelete.setDefaultButton(QMessageBox::Cancel); - msgBoxDelete.exec(); - if (msgBoxDelete.clickedButton() != deleteBtn) { - return; + { + QDialog* delConfirmDlg = new QDialog(nullptr); + delConfirmDlg->setModal(true); // just to be sure + delConfirmDlg->setWindowTitle(tr("Delete Track Files")); + + QVBoxLayout* delConfirmDlgLayout = new QVBoxLayout; + QLabel* delWarning = new QLabel; + delWarning->setText(tr("Permanently delete these files from disk?") + QString("
") + + QString("") + tr("This can not be undone!") + QString("")); + delWarning->setTextFormat(Qt::RichText); + + QListWidget* fileListWidget = new QListWidget; + fileListWidget->addItems(locations); + + QDialogButtonBox* delConfirmDlgButtons = new QDialogButtonBox(); + QPushButton* cancelBtn = delConfirmDlgButtons->addButton( + tr("Cancel"), + QDialogButtonBox::RejectRole); + QPushButton* deleteBtn = delConfirmDlgButtons->addButton( + tr("Delete Files"), + QDialogButtonBox::AcceptRole); + cancelBtn->setDefault(true); + // This is required after customizing the buttons, otherwise neither button + // would close the dialog. + connect(cancelBtn, &QPushButton::clicked, delConfirmDlg, &QDialog::reject); + connect(deleteBtn, &QPushButton::clicked, delConfirmDlg, &QDialog::accept); + + delConfirmDlgLayout->addWidget(fileListWidget); + delConfirmDlgLayout->addWidget(delWarning); + delConfirmDlgLayout->addWidget(delConfirmDlgButtons); + delConfirmDlg->setLayout(delConfirmDlgLayout); + + if (delConfirmDlg->exec() == QDialog::Rejected) { + return; + } } // Set up and initiate the track batch operation @@ -1647,42 +1657,44 @@ void WTrackMenu::slotRemoveFromDisk() { m_pLibrary->trackCollections()->purgeTracks(trackOperator.tr_tracksToPurge); // Optional message box: QMessageBox msgBoxPurgeTracks(QMessageBox::Information, - QObject::tr("Yeaiij!"), + QObject::tr("Track files deleted"), nullptr); - msgBoxPurgeTracks.setInformativeText( - QObject::tr( - "
" - "%1 annoying tracks were deleted from disk and " - "purged from the Mixxx database." - "

") - .arg(QString::number(trackOperator.tr_tracksToPurge.length()))); + msgBoxPurgeTracks.setText( + QObject::tr("%1 track files were deleted from disk and purged " + "from the Mixxx database.") + .arg(QString::number( + trackOperator.tr_tracksToPurge.length()))); msgBoxPurgeTracks.setTextFormat(Qt::RichText); msgBoxPurgeTracks.exec(); } - // Show list of tracks that could not be deleted and are thus not going to be purged. if (trackOperator.tr_tracksToKeep.length() >= 0) { return; } - QMessageBox msgBoxKeepTracks(QMessageBox::Warning, - QObject::tr("Some Files Were Not Deleted"), - nullptr); - msgBoxKeepTracks.setInformativeText( - QObject::tr("

" - "The following %1 files could not be deleted from disk." - "Make sure you have write access to those files and " - "try again later." - "
" - "%2" - "
") - .arg(QString::number( - trackOperator.tr_tracksToKeep.length()), - // Primitive hack to create a pseudo list. - QString(QStringLiteral("• ")) + - trackOperator.tr_tracksToKeep.join( - QStringLiteral("
• ")))); - msgBoxKeepTracks.setTextFormat(Qt::RichText); - msgBoxKeepTracks.exec(); + + { + // If there are tracks that could not be deleted show a message with those listed. + QDialog* notDeletedDlg = new QDialog(nullptr); + notDeletedDlg->setWindowTitle(tr("Delete Track Files")); + QVBoxLayout* notDeletedLayout = new QVBoxLayout; + QLabel* notDeletedLabel = new QLabel; + notDeletedLabel->setText( + tr("The following %1 files could not be deleted from disk") + .arg(QString::number( + trackOperator.tr_tracksToKeep.length()))); + notDeletedLabel->setTextFormat(Qt::RichText); + + QListWidget* notDeletedList = new QListWidget; + notDeletedList->addItems(trackOperator.tr_tracksToKeep); + + QDialogButtonBox* deletedDlgButtons = new QDialogButtonBox(QDialogButtonBox::Ok); + + notDeletedLayout->addWidget(notDeletedLabel); + notDeletedLayout->addWidget(notDeletedList); + notDeletedLayout->addWidget(deletedDlgButtons); + notDeletedDlg->setLayout(notDeletedLayout); + notDeletedDlg->exec(); + } } void WTrackMenu::slotShowDlgTrackInfo() { diff --git a/src/widget/wtrackmenu.h b/src/widget/wtrackmenu.h index fe915af8448..cbf200cb7f9 100644 --- a/src/widget/wtrackmenu.h +++ b/src/widget/wtrackmenu.h @@ -16,6 +16,7 @@ class ControlProxy; class DlgTagFetcher; class DlgTrackInfo; +//class DlgDeleteFilesConfirmation; class ExternalTrackCollection; class Library; class TrackModel; From a5b509d90b2aaf8ff3a2dcd3972dab4ebe834b84 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Sun, 21 Feb 2021 00:33:46 +0100 Subject: [PATCH 04/23] WTrackMenu: allow Remove From Disk in Browse & Recording --- src/library/browse/browsetablemodel.cpp | 3 ++- src/widget/wtrackmenu.cpp | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/library/browse/browsetablemodel.cpp b/src/library/browse/browsetablemodel.cpp index a61914b4f49..7115f1e1d78 100644 --- a/src/library/browse/browsetablemodel.cpp +++ b/src/library/browse/browsetablemodel.cpp @@ -335,7 +335,8 @@ TrackModel::Capabilities BrowseTableModel::getCapabilities() const { Capability::AddToAutoDJ | Capability::LoadToDeck | Capability::LoadToPreviewDeck | - Capability::LoadToSampler; + Capability::LoadToSampler | + Capability::RemoveFromDisk; } Qt::ItemFlags BrowseTableModel::flags(const QModelIndex& index) const { diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 0e0d51f4051..39976fd6f6f 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1705,10 +1705,13 @@ void WTrackMenu::slotRemoveFromDisk() { QObject::tr("Track files deleted"), nullptr); msgBoxPurgeTracks.setText( - QObject::tr("%1 track files were deleted from disk and purged " - "from the Mixxx database.") + tr("%1 track files were deleted from disk and purged " + "from the Mixxx database.") .arg(QString::number( - trackOperator.tr_tracksToPurge.length()))); + trackOperator.tr_tracksToPurge.length())) + + QString("

") + + tr("Note: if you are in Browse or Recording you need to " + "click the current view again to see changes.")); msgBoxPurgeTracks.setTextFormat(Qt::RichText); msgBoxPurgeTracks.exec(); } From a4e9f7149fbd71e00c639f7a2438bebeb83de037 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Sun, 21 Feb 2021 00:55:06 +0100 Subject: [PATCH 05/23] WTrackMenu: improve format of Delete warning --- src/widget/wtrackmenu.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 39976fd6f6f..02e986fbfbb 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1655,9 +1655,12 @@ void WTrackMenu::slotRemoveFromDisk() { QVBoxLayout* delConfirmDlgLayout = new QVBoxLayout; QLabel* delWarning = new QLabel; - delWarning->setText(tr("Permanently delete these files from disk?") + QString("
") + - QString("") + tr("This can not be undone!") + QString("")); + delWarning->setText(tr("Permanently delete these files from disk?") + + QString("

") + + tr("This can not be undone!") + QString("")); delWarning->setTextFormat(Qt::RichText); + delWarning->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, + QSizePolicy::Minimum)); QListWidget* fileListWidget = new QListWidget; fileListWidget->addItems(locations); From 73001045887c161ca73272a95ff4ee945b506b36 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Mon, 14 Jun 2021 16:34:43 +0200 Subject: [PATCH 06/23] Remove from disk: rename variables --- src/widget/wtrackmenu.cpp | 50 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 02e986fbfbb..54783f69861 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1649,11 +1649,11 @@ void WTrackMenu::slotRemoveFromDisk() { // TODO Should each item may have a checkbox to allow removing it from the delete list // or is it okay for the user to Cancel and adjust the selection in the tracks table? { - QDialog* delConfirmDlg = new QDialog(nullptr); - delConfirmDlg->setModal(true); // just to be sure - delConfirmDlg->setWindowTitle(tr("Delete Track Files")); + QDialog* dlgDelConfirm = new QDialog(nullptr); + dlgDelConfirm->setModal(true); // just to be sure + dlgDelConfirm->setWindowTitle(tr("Delete Track Files")); - QVBoxLayout* delConfirmDlgLayout = new QVBoxLayout; + QVBoxLayout* delLayout = new QVBoxLayout; QLabel* delWarning = new QLabel; delWarning->setText(tr("Permanently delete these files from disk?") + QString("

") + @@ -1662,28 +1662,28 @@ void WTrackMenu::slotRemoveFromDisk() { delWarning->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); - QListWidget* fileListWidget = new QListWidget; - fileListWidget->addItems(locations); + QListWidget* delListWidget = new QListWidget; + delListWidget->addItems(locations); - QDialogButtonBox* delConfirmDlgButtons = new QDialogButtonBox(); - QPushButton* cancelBtn = delConfirmDlgButtons->addButton( + QDialogButtonBox* delButtons = new QDialogButtonBox(); + QPushButton* cancelBtn = delButtons->addButton( tr("Cancel"), QDialogButtonBox::RejectRole); - QPushButton* deleteBtn = delConfirmDlgButtons->addButton( + QPushButton* deleteBtn = delButtons->addButton( tr("Delete Files"), QDialogButtonBox::AcceptRole); cancelBtn->setDefault(true); // This is required after customizing the buttons, otherwise neither button // would close the dialog. - connect(cancelBtn, &QPushButton::clicked, delConfirmDlg, &QDialog::reject); - connect(deleteBtn, &QPushButton::clicked, delConfirmDlg, &QDialog::accept); + connect(cancelBtn, &QPushButton::clicked, dlgDelConfirm, &QDialog::reject); + connect(deleteBtn, &QPushButton::clicked, dlgDelConfirm, &QDialog::accept); - delConfirmDlgLayout->addWidget(fileListWidget); - delConfirmDlgLayout->addWidget(delWarning); - delConfirmDlgLayout->addWidget(delConfirmDlgButtons); - delConfirmDlg->setLayout(delConfirmDlgLayout); + delLayout->addWidget(delListWidget); + delLayout->addWidget(delWarning); + delLayout->addWidget(delButtons); + dlgDelConfirm->setLayout(delLayout); - if (delConfirmDlg->exec() == QDialog::Rejected) { + if (dlgDelConfirm->exec() == QDialog::Rejected) { return; } } @@ -1725,8 +1725,8 @@ void WTrackMenu::slotRemoveFromDisk() { { // If there are tracks that could not be deleted show a message with those listed. - QDialog* notDeletedDlg = new QDialog(nullptr); - notDeletedDlg->setWindowTitle(tr("Delete Track Files")); + QDialog* dlgNotDeleted = new QDialog(nullptr); + dlgNotDeleted->setWindowTitle(tr("Delete Track Files")); QVBoxLayout* notDeletedLayout = new QVBoxLayout; QLabel* notDeletedLabel = new QLabel; notDeletedLabel->setText( @@ -1735,16 +1735,16 @@ void WTrackMenu::slotRemoveFromDisk() { trackOperator.tr_tracksToKeep.length()))); notDeletedLabel->setTextFormat(Qt::RichText); - QListWidget* notDeletedList = new QListWidget; - notDeletedList->addItems(trackOperator.tr_tracksToKeep); + QListWidget* notDeletedListWidget = new QListWidget; + notDeletedListWidget->addItems(trackOperator.tr_tracksToKeep); - QDialogButtonBox* deletedDlgButtons = new QDialogButtonBox(QDialogButtonBox::Ok); + QDialogButtonBox* notDeletedButtons = new QDialogButtonBox(QDialogButtonBox::Ok); notDeletedLayout->addWidget(notDeletedLabel); - notDeletedLayout->addWidget(notDeletedList); - notDeletedLayout->addWidget(deletedDlgButtons); - notDeletedDlg->setLayout(notDeletedLayout); - notDeletedDlg->exec(); + notDeletedLayout->addWidget(notDeletedListWidget); + notDeletedLayout->addWidget(notDeletedButtons); + dlgNotDeleted->setLayout(notDeletedLayout); + dlgNotDeleted->exec(); } } From 4769018eb2565c8a6226be6b65ea886c90cf3f78 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Mon, 14 Jun 2021 16:58:44 +0200 Subject: [PATCH 07/23] widgethelper: add method to stretch QListWidget to show all content --- src/util/widgethelper.cpp | 29 +++++++++++++++++++++++++++++ src/util/widgethelper.h | 4 ++++ 2 files changed, 33 insertions(+) diff --git a/src/util/widgethelper.cpp b/src/util/widgethelper.cpp index d0fda107b17..6ab2caa2cc9 100644 --- a/src/util/widgethelper.cpp +++ b/src/util/widgethelper.cpp @@ -1,6 +1,7 @@ #include "util/widgethelper.h" #include +#include #include "util/math.h" @@ -47,6 +48,34 @@ QWindow* getWindow( return nullptr; } +QSize adjustedListWidgetSize(const QListWidget& listWidget, const QWidget& parent) { + // Try to display all files and the complete file locations to avoid + // horizontal scrolling. + // Get the screen dimensions + QScreen* const pScreen = getScreen(parent); + QSize screenSpace; + VERIFY_OR_DEBUG_ASSERT(pScreen) { + qWarning() << "Screen not detected. Assuming screen size of 800x600px."; + screenSpace = QSize(800, 600); + } + else { + screenSpace = pScreen->size(); + } + // Calculate the dimensions of the file list to show all. + int margin = 2 * listWidget.frameWidth() + + listWidget.style()->pixelMetric(QStyle::PM_ScrollBarExtent); + int minW = listWidget.sizeHintForColumn(0) + margin; + int minH = listWidget.sizeHintForRow(0) * listWidget.count() + margin; + // The file list should fit into the window, but clamp to 90% of screen size. + int newW = std::min(minW, static_cast(screenSpace.width() * 0.9)); + int newH = std::min(minH, static_cast(screenSpace.height() * 0.9)); + // Apply new size + if (newW > 0 && newH > 0) { + return QSize(newW, newH); + } + return QSize(); +} + } // namespace widgethelper } // namespace mixxx diff --git a/src/util/widgethelper.h b/src/util/widgethelper.h index 7ede58dfb31..0c0d3fac3e5 100644 --- a/src/util/widgethelper.h +++ b/src/util/widgethelper.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -49,6 +50,9 @@ inline QScreen* getScreen( #endif } +/// QSize for stretching a list widget attempting to show entire column +QSize adjustedListWidgetSize(const QListWidget& listWidget, const QWidget& parent); + } // namespace widgethelper } // namespace mixxx From ac6c35f3514f39ccc9b300ce4b14d762e56a52f3 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Mon, 14 Jun 2021 17:17:27 +0200 Subject: [PATCH 08/23] Remove from disk: stretch dialog to show all files --- src/widget/wtrackmenu.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 54783f69861..b6905b07795 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -33,6 +32,7 @@ #include "util/desktophelper.h" #include "util/parented_ptr.h" #include "util/qt.h" +#include "util/widgethelper.h" #include "widget/wcolorpickeraction.h" #include "widget/wcoverartlabel.h" #include "widget/wcoverartmenu.h" @@ -1645,7 +1645,6 @@ void WTrackMenu::slotRemoveFromDisk() { locations.append(location); } - // TODO Resize the dialog appropriately. // TODO Should each item may have a checkbox to allow removing it from the delete list // or is it okay for the user to Cancel and adjust the selection in the tracks table? { @@ -1662,8 +1661,14 @@ void WTrackMenu::slotRemoveFromDisk() { delWarning->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); + // TODO (ronso0) We could also make this a table to allow showing + // artist and title if file names don't suffice to identify tracks. QListWidget* delListWidget = new QListWidget; + delListWidget->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, + QSizePolicy::MinimumExpanding)); delListWidget->addItems(locations); + delListWidget->setMinimumSize( + mixxx::widgethelper::adjustedListWidgetSize(*delListWidget, *this)); QDialogButtonBox* delButtons = new QDialogButtonBox(); QPushButton* cancelBtn = delButtons->addButton( @@ -1737,6 +1742,8 @@ void WTrackMenu::slotRemoveFromDisk() { QListWidget* notDeletedListWidget = new QListWidget; notDeletedListWidget->addItems(trackOperator.tr_tracksToKeep); + notDeletedListWidget->setMinimumSize( + mixxx::widgethelper::adjustedListWidgetSize(*notDeletedListWidget, *this)); QDialogButtonBox* notDeletedButtons = new QDialogButtonBox(QDialogButtonBox::Ok); From 42952adb3576e0050e0597edce76ff02dd980722 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 31 Aug 2021 04:07:16 +0200 Subject: [PATCH 09/23] Remove from disk: clean up comments --- src/widget/wtrackmenu.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 780233f09f2..f231b98080f 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1649,9 +1649,8 @@ void WTrackMenu::slotRemoveFromDisk() { locations.append(location); } - // TODO Should each item may have a checkbox to allow removing it from the delete list - // or is it okay for the user to Cancel and adjust the selection in the tracks table? { + // Set up and run the confirmation dalog QDialog* dlgDelConfirm = new QDialog(nullptr); dlgDelConfirm->setModal(true); // just to be sure dlgDelConfirm->setWindowTitle(tr("Delete Track Files")); @@ -1665,7 +1664,7 @@ void WTrackMenu::slotRemoveFromDisk() { delWarning->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); - // TODO (ronso0) We could also make this a table to allow showing + // NOTE(ronso0) We could also make this a table to allow showing // artist and title if file names don't suffice to identify tracks. QListWidget* delListWidget = new QListWidget; delListWidget->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, From 7fb77837c19fdad875dcd8d2b1d5877a4665f0a4 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 31 Aug 2021 19:23:35 +0200 Subject: [PATCH 10/23] WTrackMenu: move Delete Files into own submenu, rename Remove > Delete --- src/widget/wtrackmenu.cpp | 10 ++++++++-- src/widget/wtrackmenu.h | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 8f945333fae..a8c534a9c9b 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -170,6 +170,11 @@ void WTrackMenu::createMenus() { m_pLibrary->searchTracksInCollection(searchQuery); }); } + + if (featureIsEnabled(Feature::RemoveFromDisk)) { + m_pRemoveFromDiskMenu = new QMenu(this); + m_pRemoveFromDiskMenu->setTitle(tr("Delete Track Files")); + } } void WTrackMenu::createActions() { @@ -214,7 +219,7 @@ void WTrackMenu::createActions() { } if (featureIsEnabled(Feature::RemoveFromDisk)) { - m_pRemoveFromDiskAct = new QAction(tr("Remove from disk"), this); + m_pRemoveFromDiskAct = new QAction(tr("Delete Files From disk"), m_pRemoveFromDiskMenu); connect(m_pRemoveFromDiskAct, &QAction::triggered, this, @@ -513,7 +518,8 @@ void WTrackMenu::setupActions() { if (featureIsEnabled(Feature::RemoveFromDisk) && m_pTrackModel->hasCapabilities(TrackModel::Capability::RemoveFromDisk)) { - addAction(m_pRemoveFromDiskAct); + m_pRemoveFromDiskMenu->addAction(m_pRemoveFromDiskAct); + addMenu(m_pRemoveFromDiskMenu); } if (featureIsEnabled(Feature::FileBrowser)) { diff --git a/src/widget/wtrackmenu.h b/src/widget/wtrackmenu.h index caabfc45f5b..444eb6f5a3e 100644 --- a/src/widget/wtrackmenu.h +++ b/src/widget/wtrackmenu.h @@ -78,6 +78,8 @@ class WTrackMenu : public QMenu { // This has been done on purpose to ensure menu doesn't popup without loaded track(s). void popup(const QPoint& pos, QAction* at = nullptr); void slotShowDlgTrackInfo(); + // Library management + void slotRemoveFromDisk(); signals: void loadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play = false); @@ -134,7 +136,6 @@ class WTrackMenu : public QMenu { void slotHide(); void slotUnhide(); void slotPurge(); - void slotRemoveFromDisk(); private: // This getter verifies that m_pTrackModel is set when @@ -214,6 +215,7 @@ class WTrackMenu : public QMenu { QMenu* m_pColorMenu{}; WCoverArtMenu* m_pCoverMenu{}; parented_ptr m_pSearchRelatedMenu; + QMenu* m_pRemoveFromDiskMenu{}; // Update ReplayGain from Track QAction* m_pUpdateReplayGain{}; From 5227e9ec19c0f3c72143012ae59757f4b63b838a Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 31 Aug 2021 19:24:28 +0200 Subject: [PATCH 11/23] Hidden Tracks: add 'Delete & Purge' button --- src/library/dlghidden.cpp | 13 ++++++++++++- src/library/dlghidden.ui | 16 ++++++++++++++++ src/widget/wtracktableview.cpp | 9 +++++++++ src/widget/wtracktableview.h | 1 + 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/library/dlghidden.cpp b/src/library/dlghidden.cpp index 266c2c01444..8eeea57bb4a 100644 --- a/src/library/dlghidden.cpp +++ b/src/library/dlghidden.cpp @@ -36,6 +36,7 @@ DlgHidden::DlgHidden( m_pHiddenTableModel = new HiddenTableModel(this, pLibrary->trackCollectionManager()); m_pTrackTableView->loadTrackModel(m_pHiddenTableModel); + // set up button connections connect(btnUnhide, &QPushButton::clicked, m_pTrackTableView, @@ -52,10 +53,19 @@ DlgHidden::DlgHidden( &QPushButton::clicked, this, &DlgHidden::clicked); + connect(btnDelete, + &QPushButton::clicked, + m_pTrackTableView, + &WTrackTableView::slotDeleteTracksFromDisk); + connect(btnDelete, + &QPushButton::clicked, + this, + &DlgHidden::clicked); connect(btnSelect, &QPushButton::clicked, this, &DlgHidden::selectAll); + // set up common track table view connections connect(m_pTrackTableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, @@ -110,8 +120,9 @@ void DlgHidden::selectAll() { } void DlgHidden::activateButtons(bool enable) { - btnPurge->setEnabled(enable); btnUnhide->setEnabled(enable); + btnPurge->setEnabled(enable); + btnDelete->setEnabled(enable); } void DlgHidden::selectionChanged(const QItemSelection &selected, diff --git a/src/library/dlghidden.ui b/src/library/dlghidden.ui index 3cbea274e82..18bab2a20b6 100644 --- a/src/library/dlghidden.ui +++ b/src/library/dlghidden.ui @@ -95,6 +95,22 @@ + + + + Qt::NoFocus + + + Purge selected tracks from the library and delete files from disk. + + + Purge And Delete Files + + + false + + + diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index 0b1dced9457..c02443f7861 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -447,6 +447,15 @@ void WTrackTableView::slotPurge() { } } +void WTrackTableView::slotDeleteTracksFromDisk() { + QModelIndexList indices = selectionModel()->selectedRows(); + + if (indices.size() > 0) { + m_pTrackMenu->loadTrackModelIndices(indices); + m_pTrackMenu->slotRemoveFromDisk(); + } +} + void WTrackTableView::slotUnhide() { QModelIndexList indices = selectionModel()->selectedRows(); diff --git a/src/widget/wtracktableview.h b/src/widget/wtracktableview.h index 9db21a36d23..ad07d2d7758 100644 --- a/src/widget/wtracktableview.h +++ b/src/widget/wtracktableview.h @@ -57,6 +57,7 @@ class WTrackTableView : public WLibraryTableView { void slotMouseDoubleClicked(const QModelIndex &); void slotUnhide(); void slotPurge(); + void slotDeleteTracksFromDisk(); void slotAddToAutoDJBottom() override; void slotAddToAutoDJTop() override; From 8a59dbfb4536ce1f5da16294eaa82b53090c7674 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Fri, 1 Oct 2021 23:59:33 +0200 Subject: [PATCH 12/23] reword track delete dialogs --- src/widget/wtrackmenu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index a8c534a9c9b..d7d82b7b0ae 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -219,7 +219,7 @@ void WTrackMenu::createActions() { } if (featureIsEnabled(Feature::RemoveFromDisk)) { - m_pRemoveFromDiskAct = new QAction(tr("Delete Files From disk"), m_pRemoveFromDiskMenu); + m_pRemoveFromDiskAct = new QAction(tr("Delete Files from Disk"), m_pRemoveFromDiskMenu); connect(m_pRemoveFromDiskAct, &QAction::triggered, this, @@ -1735,7 +1735,7 @@ void WTrackMenu::slotRemoveFromDisk() { m_pLibrary->trackCollectionManager()->purgeTracks(trackOperator.tr_tracksToPurge); // Optional message box: QMessageBox msgBoxPurgeTracks(QMessageBox::Information, - QObject::tr("Track files deleted"), + QObject::tr("Track Files Deleted"), nullptr); msgBoxPurgeTracks.setText( tr("%1 track files were deleted from disk and purged " From 225052254dfaead57aedcbb98aa4a2ca9000665f Mon Sep 17 00:00:00 2001 From: ronso0 Date: Sat, 2 Oct 2021 00:02:35 +0200 Subject: [PATCH 13/23] move setMinimumSize() to widgethelper --- src/util/widgethelper.cpp | 5 ++--- src/util/widgethelper.h | 2 +- src/widget/wtrackmenu.cpp | 6 ++---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/util/widgethelper.cpp b/src/util/widgethelper.cpp index 6ab2caa2cc9..ccaa6b90dc4 100644 --- a/src/util/widgethelper.cpp +++ b/src/util/widgethelper.cpp @@ -48,7 +48,7 @@ QWindow* getWindow( return nullptr; } -QSize adjustedListWidgetSize(const QListWidget& listWidget, const QWidget& parent) { +void growListWidget(QListWidget& listWidget, const QWidget& parent) { // Try to display all files and the complete file locations to avoid // horizontal scrolling. // Get the screen dimensions @@ -71,9 +71,8 @@ QSize adjustedListWidgetSize(const QListWidget& listWidget, const QWidget& paren int newH = std::min(minH, static_cast(screenSpace.height() * 0.9)); // Apply new size if (newW > 0 && newH > 0) { - return QSize(newW, newH); + listWidget.setMinimumSize(newW, newH); } - return QSize(); } } // namespace widgethelper diff --git a/src/util/widgethelper.h b/src/util/widgethelper.h index 0c0d3fac3e5..4eb1473ee2e 100644 --- a/src/util/widgethelper.h +++ b/src/util/widgethelper.h @@ -51,7 +51,7 @@ inline QScreen* getScreen( } /// QSize for stretching a list widget attempting to show entire column -QSize adjustedListWidgetSize(const QListWidget& listWidget, const QWidget& parent); +void growListWidget(QListWidget& listWidget, const QWidget& parent); } // namespace widgethelper diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index d7d82b7b0ae..c4c1139ce90 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1692,8 +1692,7 @@ void WTrackMenu::slotRemoveFromDisk() { delListWidget->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding)); delListWidget->addItems(locations); - delListWidget->setMinimumSize( - mixxx::widgethelper::adjustedListWidgetSize(*delListWidget, *this)); + mixxx::widgethelper::growListWidget(*delListWidget, *this); QDialogButtonBox* delButtons = new QDialogButtonBox(); QPushButton* cancelBtn = delButtons->addButton( @@ -1767,8 +1766,7 @@ void WTrackMenu::slotRemoveFromDisk() { QListWidget* notDeletedListWidget = new QListWidget; notDeletedListWidget->addItems(trackOperator.tr_tracksToKeep); - notDeletedListWidget->setMinimumSize( - mixxx::widgethelper::adjustedListWidgetSize(*notDeletedListWidget, *this)); + mixxx::widgethelper::growListWidget(*notDeletedListWidget, *this); QDialogButtonBox* notDeletedButtons = new QDialogButtonBox(QDialogButtonBox::Ok); From 0f59bd88edb6059c0af11cc8cff94bd8b2c66b30 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Sat, 2 Oct 2021 00:06:14 +0200 Subject: [PATCH 14/23] make purged/keep list members of TrackPointerOperation --- src/widget/wtrackmenu.cpp | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index c4c1139ce90..347c9e01b40 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1629,10 +1629,17 @@ namespace { class RemoveTrackFilesFromDiskTrackPointerOperation : public mixxx::TrackPointerOperation { public: - mutable QList tr_tracksToPurge; - mutable QList tr_tracksToKeep; + QList getTracksToPurge() const { + return mTracksToPurge; + } + QList getTracksToKeep() const { + return mTracksToKeep; + } private: + mutable QList mTracksToPurge; + mutable QList mTracksToKeep; + void doApply( const TrackPointer& pTrack) const override { auto trackRef = TrackRef::fromFileInfo( @@ -1650,11 +1657,10 @@ class RemoveTrackFilesFromDiskTrackPointerOperation : public mixxx::TrackPointer << "Queued file" << location << "could not be deleted. Track is not purged"; - tr_tracksToKeep.append(location); - return; + mTracksToKeep.append(location); } else { // File doesn't exist or was deleted. Queue for purging. - tr_tracksToPurge.append(trackRef); + mTracksToPurge.append(trackRef); } } }; @@ -1729,9 +1735,10 @@ void WTrackMenu::slotRemoveFromDisk() { &trackOperator); // Purge deleted tracks and show deletion summary message. - if (trackOperator.tr_tracksToPurge.length() > 0) { + QList tracksToPurge(trackOperator.getTracksToPurge()); + if (tracksToPurge.length() > 0) { // Purge only those tracks whose files were actually deleted. - m_pLibrary->trackCollectionManager()->purgeTracks(trackOperator.tr_tracksToPurge); + m_pLibrary->trackCollectionManager()->purgeTracks(tracksToPurge); // Optional message box: QMessageBox msgBoxPurgeTracks(QMessageBox::Information, QObject::tr("Track Files Deleted"), @@ -1739,8 +1746,7 @@ void WTrackMenu::slotRemoveFromDisk() { msgBoxPurgeTracks.setText( tr("%1 track files were deleted from disk and purged " "from the Mixxx database.") - .arg(QString::number( - trackOperator.tr_tracksToPurge.length())) + + .arg(QString::number(tracksToPurge.length())) + QString("

") + tr("Note: if you are in Browse or Recording you need to " "click the current view again to see changes.")); @@ -1748,7 +1754,8 @@ void WTrackMenu::slotRemoveFromDisk() { msgBoxPurgeTracks.exec(); } - if (trackOperator.tr_tracksToKeep.length() >= 0) { + QList tracksToKeep(trackOperator.getTracksToKeep()); + if (tracksToKeep.length() == 0) { return; } @@ -1761,11 +1768,11 @@ void WTrackMenu::slotRemoveFromDisk() { notDeletedLabel->setText( tr("The following %1 files could not be deleted from disk") .arg(QString::number( - trackOperator.tr_tracksToKeep.length()))); + tracksToKeep.length()))); notDeletedLabel->setTextFormat(Qt::RichText); QListWidget* notDeletedListWidget = new QListWidget; - notDeletedListWidget->addItems(trackOperator.tr_tracksToKeep); + notDeletedListWidget->addItems(tracksToKeep); mixxx::widgethelper::growListWidget(*notDeletedListWidget, *this); QDialogButtonBox* notDeletedButtons = new QDialogButtonBox(QDialogButtonBox::Ok); From 394e338aa1d43c181928dfef508997d1a1f3793e Mon Sep 17 00:00:00 2001 From: ronso0 Date: Sat, 2 Oct 2021 00:33:12 +0200 Subject: [PATCH 15/23] explain why we must purge tracks AFTER the batch operation --- src/widget/wtrackmenu.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 347c9e01b40..992af070006 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1659,7 +1659,11 @@ class RemoveTrackFilesFromDiskTrackPointerOperation : public mixxx::TrackPointer << "could not be deleted. Track is not purged"; mTracksToKeep.append(location); } else { - // File doesn't exist or was deleted. Queue for purging. + // File doesn't exist or was deleted. + // Note: we must not purge every single track since TrackDAO::afterPurgingTracks + // would enforce a track model update (select()) + // So we add it to the purge queue and purge all tracks at once + // in slotRemoveFromDisk() afterwards. mTracksToPurge.append(trackRef); } } From d84c8a3c8c3a247bfe676554a68559f9e5326375 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Sun, 14 Nov 2021 16:58:25 +0100 Subject: [PATCH 16/23] create QDialogs on the stack --- src/widget/wtrackmenu.cpp | 41 ++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index ce92255217b..f423b20c270 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1714,13 +1714,13 @@ void WTrackMenu::slotRemoveFromDisk() { } { - // Set up and run the confirmation dalog - QDialog* dlgDelConfirm = new QDialog(nullptr); - dlgDelConfirm->setModal(true); // just to be sure - dlgDelConfirm->setWindowTitle(tr("Delete Track Files")); + // Set up and run the delete confirmation dalog + QDialog dlgDelConfirm(this); + dlgDelConfirm.setModal(true); // just to be sure + dlgDelConfirm.setWindowTitle(tr("Delete Track Files")); - QVBoxLayout* delLayout = new QVBoxLayout; - QLabel* delWarning = new QLabel; + QVBoxLayout* delLayout = new QVBoxLayout(); + QLabel* delWarning = new QLabel(); delWarning->setText(tr("Permanently delete these files from disk?") + QString("

") + tr("This can not be undone!") + QString("")); @@ -1730,7 +1730,7 @@ void WTrackMenu::slotRemoveFromDisk() { // NOTE(ronso0) We could also make this a table to allow showing // artist and title if file names don't suffice to identify tracks. - QListWidget* delListWidget = new QListWidget; + QListWidget* delListWidget = new QListWidget(); delListWidget->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding)); delListWidget->addItems(locations); @@ -1746,15 +1746,15 @@ void WTrackMenu::slotRemoveFromDisk() { cancelBtn->setDefault(true); // This is required after customizing the buttons, otherwise neither button // would close the dialog. - connect(cancelBtn, &QPushButton::clicked, dlgDelConfirm, &QDialog::reject); - connect(deleteBtn, &QPushButton::clicked, dlgDelConfirm, &QDialog::accept); + connect(cancelBtn, &QPushButton::clicked, &dlgDelConfirm, &QDialog::reject); + connect(deleteBtn, &QPushButton::clicked, &dlgDelConfirm, &QDialog::accept); delLayout->addWidget(delListWidget); delLayout->addWidget(delWarning); delLayout->addWidget(delButtons); - dlgDelConfirm->setLayout(delLayout); + dlgDelConfirm.setLayout(delLayout); - if (dlgDelConfirm->exec() == QDialog::Rejected) { + if (dlgDelConfirm.exec() == QDialog::Rejected) { return; } } @@ -1775,10 +1775,10 @@ void WTrackMenu::slotRemoveFromDisk() { if (tracksToPurge.length() > 0) { // Purge only those tracks whose files were actually deleted. m_pLibrary->trackCollectionManager()->purgeTracks(tracksToPurge); - // Optional message box: - QMessageBox msgBoxPurgeTracks(QMessageBox::Information, - QObject::tr("Track Files Deleted"), - nullptr); + // Purge summary + QMessageBox msgBoxPurgeTracks(this); + msgBoxPurgeTracks.setIcon(QMessageBox::Information); + msgBoxPurgeTracks.setWindowTitle(tr("Track Files Deleted")); msgBoxPurgeTracks.setText( tr("%1 track files were deleted from disk and purged " "from the Mixxx database.") @@ -1787,6 +1787,7 @@ void WTrackMenu::slotRemoveFromDisk() { tr("Note: if you are in Browse or Recording you need to " "click the current view again to see changes.")); msgBoxPurgeTracks.setTextFormat(Qt::RichText); + msgBoxPurgeTracks.setStandardButtons(QMessageBox::Ok); msgBoxPurgeTracks.exec(); } @@ -1796,9 +1797,9 @@ void WTrackMenu::slotRemoveFromDisk() { } { - // If there are tracks that could not be deleted show a message with those listed. - QDialog* dlgNotDeleted = new QDialog(nullptr); - dlgNotDeleted->setWindowTitle(tr("Delete Track Files")); + // Else show a message with a list of tracks that could not be deleted. + QDialog dlgNotDeleted(this); + dlgNotDeleted.setWindowTitle(tr("Delete Track Files")); QVBoxLayout* notDeletedLayout = new QVBoxLayout; QLabel* notDeletedLabel = new QLabel; notDeletedLabel->setText( @@ -1816,8 +1817,8 @@ void WTrackMenu::slotRemoveFromDisk() { notDeletedLayout->addWidget(notDeletedLabel); notDeletedLayout->addWidget(notDeletedListWidget); notDeletedLayout->addWidget(notDeletedButtons); - dlgNotDeleted->setLayout(notDeletedLayout); - dlgNotDeleted->exec(); + dlgNotDeleted.setLayout(notDeletedLayout); + dlgNotDeleted.exec(); } } From 3a06d9cd55ccd89bd2d856f7f2dc7123f178ae5e Mon Sep 17 00:00:00 2001 From: ronso0 Date: Sun, 14 Nov 2021 21:10:10 +0100 Subject: [PATCH 17/23] refine comment in RemoveTrackFilesFromDiskTrackPointerOperation --- src/widget/wtrackmenu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index f423b20c270..5d0969c28b3 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1692,8 +1692,8 @@ class RemoveTrackFilesFromDiskTrackPointerOperation : public mixxx::TrackPointer mTracksToKeep.append(location); } else { // File doesn't exist or was deleted. - // Note: we must not purge every single track since TrackDAO::afterPurgingTracks - // would enforce a track model update (select()) + // Note: we must NOT purge every single track here since + // TrackDAO::afterPurgingTracks would enforce a track model update (select()) // So we add it to the purge queue and purge all tracks at once // in slotRemoveFromDisk() afterwards. mTracksToPurge.append(trackRef); From 8a2130f81e8d4c9303bc42ae4d091bb32ddef4f2 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Sun, 14 Nov 2021 21:11:46 +0100 Subject: [PATCH 18/23] instantiate dialog ingredients just before they're needed --- src/widget/wtrackmenu.cpp | 62 +++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 5d0969c28b3..4b72a82d378 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1714,20 +1714,8 @@ void WTrackMenu::slotRemoveFromDisk() { } { - // Set up and run the delete confirmation dalog - QDialog dlgDelConfirm(this); - dlgDelConfirm.setModal(true); // just to be sure - dlgDelConfirm.setWindowTitle(tr("Delete Track Files")); - - QVBoxLayout* delLayout = new QVBoxLayout(); - QLabel* delWarning = new QLabel(); - delWarning->setText(tr("Permanently delete these files from disk?") + - QString("

") + - tr("This can not be undone!") + QString("")); - delWarning->setTextFormat(Qt::RichText); - delWarning->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, - QSizePolicy::Minimum)); - + // Prepare the delete confirmation dalog + // List view for the files to be deleted // NOTE(ronso0) We could also make this a table to allow showing // artist and title if file names don't suffice to identify tracks. QListWidget* delListWidget = new QListWidget(); @@ -1735,7 +1723,15 @@ void WTrackMenu::slotRemoveFromDisk() { QSizePolicy::MinimumExpanding)); delListWidget->addItems(locations); mixxx::widgethelper::growListWidget(*delListWidget, *this); - + // Warning text + QLabel* delWarning = new QLabel(); + delWarning->setText(tr("Permanently delete these files from disk?") + + QString("

") + + tr("This can not be undone!") + QString("")); + delWarning->setTextFormat(Qt::RichText); + delWarning->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, + QSizePolicy::Minimum)); + // Buttons QDialogButtonBox* delButtons = new QDialogButtonBox(); QPushButton* cancelBtn = delButtons->addButton( tr("Cancel"), @@ -1744,14 +1740,20 @@ void WTrackMenu::slotRemoveFromDisk() { tr("Delete Files"), QDialogButtonBox::AcceptRole); cancelBtn->setDefault(true); - // This is required after customizing the buttons, otherwise neither button - // would close the dialog. - connect(cancelBtn, &QPushButton::clicked, &dlgDelConfirm, &QDialog::reject); - connect(deleteBtn, &QPushButton::clicked, &dlgDelConfirm, &QDialog::accept); + // Populate the main layout + QVBoxLayout* delLayout = new QVBoxLayout(); delLayout->addWidget(delListWidget); delLayout->addWidget(delWarning); delLayout->addWidget(delButtons); + + QDialog dlgDelConfirm; + dlgDelConfirm.setModal(true); // just to be sure + dlgDelConfirm.setWindowTitle(tr("Delete Track Files")); + // This is required after customizing the buttons, otherwise neither button + // would close the dialog. + connect(cancelBtn, &QPushButton::clicked, &dlgDelConfirm, &QDialog::reject); + connect(deleteBtn, &QPushButton::clicked, &dlgDelConfirm, &QDialog::accept); dlgDelConfirm.setLayout(delLayout); if (dlgDelConfirm.exec() == QDialog::Rejected) { @@ -1773,10 +1775,11 @@ void WTrackMenu::slotRemoveFromDisk() { // Purge deleted tracks and show deletion summary message. QList tracksToPurge(trackOperator.getTracksToPurge()); if (tracksToPurge.length() > 0) { - // Purge only those tracks whose files were actually deleted. + // Purge only those tracks whose files have actually been deleted. m_pLibrary->trackCollectionManager()->purgeTracks(tracksToPurge); - // Purge summary - QMessageBox msgBoxPurgeTracks(this); + + // Show purge summary message + QMessageBox msgBoxPurgeTracks; msgBoxPurgeTracks.setIcon(QMessageBox::Information); msgBoxPurgeTracks.setWindowTitle(tr("Track Files Deleted")); msgBoxPurgeTracks.setText( @@ -1798,9 +1801,6 @@ void WTrackMenu::slotRemoveFromDisk() { { // Else show a message with a list of tracks that could not be deleted. - QDialog dlgNotDeleted(this); - dlgNotDeleted.setWindowTitle(tr("Delete Track Files")); - QVBoxLayout* notDeletedLayout = new QVBoxLayout; QLabel* notDeletedLabel = new QLabel; notDeletedLabel->setText( tr("The following %1 files could not be deleted from disk") @@ -1812,12 +1812,22 @@ void WTrackMenu::slotRemoveFromDisk() { notDeletedListWidget->addItems(tracksToKeep); mixxx::widgethelper::growListWidget(*notDeletedListWidget, *this); - QDialogButtonBox* notDeletedButtons = new QDialogButtonBox(QDialogButtonBox::Ok); + QDialogButtonBox* notDeletedButtons = new QDialogButtonBox(); + QPushButton* closeBtn = notDeletedButtons->addButton( + tr("Close"), + QDialogButtonBox::AcceptRole); + QVBoxLayout* notDeletedLayout = new QVBoxLayout; notDeletedLayout->addWidget(notDeletedLabel); notDeletedLayout->addWidget(notDeletedListWidget); notDeletedLayout->addWidget(notDeletedButtons); + + QDialog dlgNotDeleted; + dlgNotDeleted.setModal(true); + dlgNotDeleted.setWindowTitle(tr("Remaining Track Files")); dlgNotDeleted.setLayout(notDeletedLayout); + // Required for being able to close the dialog + connect(closeBtn, &QPushButton::clicked, &dlgNotDeleted, &QDialog::close); dlgNotDeleted.exec(); } } From 9187e38caa08c1b3edb90d84c5ffa0d06cfa1b71 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 23 Nov 2021 10:53:04 +0100 Subject: [PATCH 19/23] remove files from disk: de-duplicate file list --- src/widget/wtrackmenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 4b72a82d378..a460603d8ca 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1709,9 +1709,9 @@ void WTrackMenu::slotRemoveFromDisk() { locations.reserve(trackRefs.size()); for (const auto& trackRef : trackRefs) { QString location = trackRef.getLocation(); - // TODO de-duplicate when extending this feature to Playlists locations.append(location); } + locations.removeDuplicates(); { // Prepare the delete confirmation dalog From f1b20afca403e95c1aa9e22a3b696d73968bb42a Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 23 Nov 2021 10:56:13 +0100 Subject: [PATCH 20/23] remove files from disk: fix comment typo --- src/widget/wtrackmenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index a460603d8ca..35d66b274ed 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1714,7 +1714,7 @@ void WTrackMenu::slotRemoveFromDisk() { locations.removeDuplicates(); { - // Prepare the delete confirmation dalog + // Prepare the delete confirmation dialog // List view for the files to be deleted // NOTE(ronso0) We could also make this a table to allow showing // artist and title if file names don't suffice to identify tracks. From e9b70a673ccd0bebfb4c06a0b0a6447d146f0de0 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 23 Nov 2021 10:56:52 +0100 Subject: [PATCH 21/23] remove files from disk: replace length() > 0 with isEmpty() --- src/widget/wtrackmenu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 35d66b274ed..2fecf8d7b17 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1774,7 +1774,7 @@ void WTrackMenu::slotRemoveFromDisk() { // Purge deleted tracks and show deletion summary message. QList tracksToPurge(trackOperator.getTracksToPurge()); - if (tracksToPurge.length() > 0) { + if (!tracksToPurge.isEmpty()) { // Purge only those tracks whose files have actually been deleted. m_pLibrary->trackCollectionManager()->purgeTracks(tracksToPurge); @@ -1795,7 +1795,7 @@ void WTrackMenu::slotRemoveFromDisk() { } QList tracksToKeep(trackOperator.getTracksToKeep()); - if (tracksToKeep.length() == 0) { + if (!tracksToKeep.isEmpty()) { return; } From ed79726df7075e8240981b88aaaf6f7d914140dc Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 23 Nov 2021 11:02:34 +0100 Subject: [PATCH 22/23] WTrackTableView: use QModelIndexList::isEmpty(), return early --- src/widget/wtracktableview.cpp | 77 ++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index a0758d35fe5..0d37756668a 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -399,7 +399,7 @@ TrackModel::SortColumnId WTrackTableView::getColumnIdFromCurrentIndex() { void WTrackTableView::assignPreviousTrackColor() { QModelIndexList indices = selectionModel()->selectedRows(); - if (indices.size() <= 0) { + if (indices.isEmpty()) { return; } @@ -420,7 +420,7 @@ void WTrackTableView::assignPreviousTrackColor() { void WTrackTableView::assignNextTrackColor() { QModelIndexList indices = selectionModel()->selectedRows(); - if (indices.size() <= 0) { + if (indices.isEmpty()) { return; } @@ -441,31 +441,32 @@ void WTrackTableView::assignNextTrackColor() { void WTrackTableView::slotPurge() { QModelIndexList indices = selectionModel()->selectedRows(); - if (indices.size() > 0) { - TrackModel* trackModel = getTrackModel(); - if (trackModel) { - trackModel->purgeTracks(indices); - } + if (indices.isEmpty()) { + return; + } + TrackModel* trackModel = getTrackModel(); + if (trackModel) { + trackModel->purgeTracks(indices); } } void WTrackTableView::slotDeleteTracksFromDisk() { QModelIndexList indices = selectionModel()->selectedRows(); - - if (indices.size() > 0) { - m_pTrackMenu->loadTrackModelIndices(indices); - m_pTrackMenu->slotRemoveFromDisk(); + if (indices.isEmpty()) { + return; } + m_pTrackMenu->loadTrackModelIndices(indices); + m_pTrackMenu->slotRemoveFromDisk(); } void WTrackTableView::slotUnhide() { QModelIndexList indices = selectionModel()->selectedRows(); - - if (indices.size() > 0) { - TrackModel* trackModel = getTrackModel(); - if (trackModel) { - trackModel->unhideTracks(indices); - } + if (indices.isEmpty()) { + return; + } + TrackModel* trackModel = getTrackModel(); + if (trackModel) { + trackModel->unhideTracks(indices); } } @@ -826,33 +827,35 @@ void WTrackTableView::hideOrRemoveSelectedTracks() { void WTrackTableView::loadSelectedTrack() { auto indices = selectionModel()->selectedRows(); - if (indices.size() > 0) { - slotMouseDoubleClicked(indices.at(0)); + if (indices.isEmpty()) { + return; } + slotMouseDoubleClicked(indices.at(0)); } void WTrackTableView::loadSelectedTrackToGroup(const QString& group, bool play) { auto indices = selectionModel()->selectedRows(); - if (indices.size() > 0) { - // If the track load override is disabled, check to see if a track is - // playing before trying to load it - if (!(m_pConfig->getValueString( - ConfigKey("[Controls]", "AllowTrackLoadToPlayingDeck")) - .toInt())) { - // TODO(XXX): Check for other than just the first preview deck. - if (group != "[PreviewDeck1]" && - ControlObject::get(ConfigKey(group, "play")) > 0.0) { - return; - } - } - auto index = indices.at(0); - auto* trackModel = getTrackModel(); - TrackPointer pTrack; - if (trackModel && - (pTrack = trackModel->getTrack(index))) { - emit loadTrackToPlayer(pTrack, group, play); + if (indices.isEmpty()) { + return; + } + // If the track load override is disabled, check to see if a track is + // playing before trying to load it + if (!(m_pConfig->getValueString( + ConfigKey("[Controls]", "AllowTrackLoadToPlayingDeck")) + .toInt())) { + // TODO(XXX): Check for other than just the first preview deck. + if (group != "[PreviewDeck1]" && + ControlObject::get(ConfigKey(group, "play")) > 0.0) { + return; } } + auto index = indices.at(0); + auto* trackModel = getTrackModel(); + TrackPointer pTrack; + if (trackModel && + (pTrack = trackModel->getTrack(index))) { + emit loadTrackToPlayer(pTrack, group, play); + } } QList WTrackTableView::getSelectedTrackIds() const { From ab31361ed823dc887e53d2276bafbffee109ce01 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 23 Nov 2021 17:57:51 +0100 Subject: [PATCH 23/23] const ref purge/keep track lists, more const --- src/widget/wtrackmenu.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 2fecf8d7b17..1bec5e1fb84 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -1661,10 +1661,10 @@ namespace { class RemoveTrackFilesFromDiskTrackPointerOperation : public mixxx::TrackPointerOperation { public: - QList getTracksToPurge() const { + const QList& getTracksToPurge() const { return mTracksToPurge; } - QList getTracksToKeep() const { + const QList& getTracksToKeep() const { return mTracksToKeep; } @@ -1773,7 +1773,7 @@ void WTrackMenu::slotRemoveFromDisk() { &trackOperator); // Purge deleted tracks and show deletion summary message. - QList tracksToPurge(trackOperator.getTracksToPurge()); + const QList tracksToPurge(trackOperator.getTracksToPurge()); if (!tracksToPurge.isEmpty()) { // Purge only those tracks whose files have actually been deleted. m_pLibrary->trackCollectionManager()->purgeTracks(tracksToPurge); @@ -1794,7 +1794,7 @@ void WTrackMenu::slotRemoveFromDisk() { msgBoxPurgeTracks.exec(); } - QList tracksToKeep(trackOperator.getTracksToKeep()); + const QList tracksToKeep(trackOperator.getTracksToKeep()); if (!tracksToKeep.isEmpty()) { return; }