diff --git a/src/library/browse/browsetablemodel.cpp b/src/library/browse/browsetablemodel.cpp
index b0c43a86835..368b544f736 100644
--- a/src/library/browse/browsetablemodel.cpp
+++ b/src/library/browse/browsetablemodel.cpp
@@ -367,7 +367,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/library/dlghidden.cpp b/src/library/dlghidden.cpp
index d4f9fd674f5..79f324c0892 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/library/hiddentablemodel.cpp b/src/library/hiddentablemodel.cpp
index db1a488d387..cae49ea940a 100644
--- a/src/library/hiddentablemodel.cpp
+++ b/src/library/hiddentablemodel.cpp
@@ -89,5 +89,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 b3bef3c4f33..b232288a048 100644
--- a/src/library/librarytablemodel.cpp
+++ b/src/library/librarytablemodel.cpp
@@ -96,5 +96,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 d0425601200..5c2d8da523c 100644
--- a/src/library/trackmodel.h
+++ b/src/library/trackmodel.h
@@ -49,6 +49,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 e024fc36156..5740f693f68 100644
--- a/src/library/trackset/crate/cratetablemodel.cpp
+++ b/src/library/trackset/crate/cratetablemodel.cpp
@@ -109,7 +109,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/util/widgethelper.cpp b/src/util/widgethelper.cpp
index d0fda107b17..ccaa6b90dc4 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,33 @@ QWindow* getWindow(
return nullptr;
}
+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
+ 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) {
+ listWidget.setMinimumSize(newW, newH);
+ }
+}
+
} // namespace widgethelper
} // namespace mixxx
diff --git a/src/util/widgethelper.h b/src/util/widgethelper.h
index 7ede58dfb31..4eb1473ee2e 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
+void growListWidget(QListWidget& listWidget, const QWidget& parent);
+
} // namespace widgethelper
} // namespace mixxx
diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp
index 448313c8e2c..1bec5e1fb84 100644
--- a/src/widget/wtrackmenu.cpp
+++ b/src/widget/wtrackmenu.cpp
@@ -1,8 +1,11 @@
#include "widget/wtrackmenu.h"
#include
+#include
#include
+#include
#include
+#include
#include "control/controlobject.h"
#include "control/controlproxy.h"
@@ -30,6 +33,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"
@@ -167,6 +171,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() {
@@ -221,6 +230,14 @@ void WTrackMenu::createActions() {
connect(m_pPurgeAct, &QAction::triggered, this, &WTrackMenu::slotPurge);
}
+ if (featureIsEnabled(Feature::RemoveFromDisk)) {
+ m_pRemoveFromDiskAct = new QAction(tr("Delete Files from Disk"), m_pRemoveFromDiskMenu);
+ connect(m_pRemoveFromDiskAct,
+ &QAction::triggered,
+ this,
+ &WTrackMenu::slotRemoveFromDisk);
+ }
+
if (featureIsEnabled(Feature::Properties)) {
m_pPropertiesAct = new QAction(tr("Properties"), this);
// This is just for having the shortcut displayed next to the action
@@ -518,6 +535,12 @@ void WTrackMenu::setupActions() {
}
}
+ if (featureIsEnabled(Feature::RemoveFromDisk) &&
+ m_pTrackModel->hasCapabilities(TrackModel::Capability::RemoveFromDisk)) {
+ m_pRemoveFromDiskMenu->addAction(m_pRemoveFromDiskAct);
+ addMenu(m_pRemoveFromDiskMenu);
+ }
+
if (featureIsEnabled(Feature::FileBrowser)) {
addAction(m_pFileBrowserAct);
}
@@ -766,6 +789,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);
}
@@ -1627,6 +1657,181 @@ void WTrackMenu::slotClearAllMetadata() {
&trackOperator);
}
+namespace {
+
+class RemoveTrackFilesFromDiskTrackPointerOperation : public mixxx::TrackPointerOperation {
+ public:
+ const QList& getTracksToPurge() const {
+ return mTracksToPurge;
+ }
+ const QList& getTracksToKeep() const {
+ return mTracksToKeep;
+ }
+
+ private:
+ mutable QList mTracksToPurge;
+ mutable QList mTracksToKeep;
+
+ 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";
+ mTracksToKeep.append(location);
+ } else {
+ // File doesn't exist or was deleted.
+ // 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);
+ }
+ }
+};
+
+} // anonymous namespace
+
+void WTrackMenu::slotRemoveFromDisk() {
+ const auto trackRefs = getTrackRefs();
+ QStringList locations;
+ locations.reserve(trackRefs.size());
+ for (const auto& trackRef : trackRefs) {
+ QString location = trackRef.getLocation();
+ locations.append(location);
+ }
+ locations.removeDuplicates();
+
+ {
+ // 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.
+ QListWidget* delListWidget = new QListWidget();
+ delListWidget->setSizePolicy(QSizePolicy(QSizePolicy::Minimum,
+ 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"),
+ QDialogButtonBox::RejectRole);
+ QPushButton* deleteBtn = delButtons->addButton(
+ tr("Delete Files"),
+ QDialogButtonBox::AcceptRole);
+ cancelBtn->setDefault(true);
+
+ // 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) {
+ 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.
+ const QList tracksToPurge(trackOperator.getTracksToPurge());
+ if (!tracksToPurge.isEmpty()) {
+ // Purge only those tracks whose files have actually been deleted.
+ m_pLibrary->trackCollectionManager()->purgeTracks(tracksToPurge);
+
+ // Show purge summary message
+ QMessageBox msgBoxPurgeTracks;
+ 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.")
+ .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."));
+ msgBoxPurgeTracks.setTextFormat(Qt::RichText);
+ msgBoxPurgeTracks.setStandardButtons(QMessageBox::Ok);
+ msgBoxPurgeTracks.exec();
+ }
+
+ const QList tracksToKeep(trackOperator.getTracksToKeep());
+ if (!tracksToKeep.isEmpty()) {
+ return;
+ }
+
+ {
+ // Else show a message with a list of tracks that could not be deleted.
+ QLabel* notDeletedLabel = new QLabel;
+ notDeletedLabel->setText(
+ tr("The following %1 files could not be deleted from disk")
+ .arg(QString::number(
+ tracksToKeep.length())));
+ notDeletedLabel->setTextFormat(Qt::RichText);
+
+ QListWidget* notDeletedListWidget = new QListWidget;
+ notDeletedListWidget->addItems(tracksToKeep);
+ mixxx::widgethelper::growListWidget(*notDeletedListWidget, *this);
+
+ 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();
+ }
+}
+
void WTrackMenu::slotShowDlgTrackInfo() {
if (isEmpty()) {
return;
@@ -1836,6 +2041,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 df627b32f4b..444eb6f5a3e 100644
--- a/src/widget/wtrackmenu.h
+++ b/src/widget/wtrackmenu.h
@@ -17,6 +17,7 @@
class ControlProxy;
class DlgTagFetcher;
class DlgTrackInfo;
+//class DlgDeleteFilesConfirmation;
class ExternalTrackCollection;
class Library;
class TrackModel;
@@ -44,14 +45,15 @@ class WTrackMenu : public QMenu {
BPM = 1 << 7,
Color = 1 << 8,
HideUnhidePurge = 1 << 9,
- FileBrowser = 1 << 10,
- Properties = 1 << 11,
- SearchRelated = 1 << 12,
- UpdateReplayGain = 1 << 13,
+ RemoveFromDisk = 1 << 10,
+ FileBrowser = 1 << 11,
+ Properties = 1 << 12,
+ SearchRelated = 1 << 13,
+ UpdateReplayGain = 1 << 14,
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)
@@ -76,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);
@@ -211,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{};
@@ -237,6 +242,7 @@ class WTrackMenu : public QMenu {
QAction* m_pHideAct{};
QAction* m_pUnhideAct{};
QAction* m_pPurgeAct{};
+ QAction* m_pRemoveFromDiskAct{};
// Show track-editor action
QAction* m_pPropertiesAct{};
diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp
index 1a046d0dd39..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,22 +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::slotUnhide() {
+void WTrackTableView::slotDeleteTracksFromDisk() {
QModelIndexList indices = selectionModel()->selectedRows();
+ if (indices.isEmpty()) {
+ return;
+ }
+ m_pTrackMenu->loadTrackModelIndices(indices);
+ m_pTrackMenu->slotRemoveFromDisk();
+}
- if (indices.size() > 0) {
- TrackModel* trackModel = getTrackModel();
- if (trackModel) {
- trackModel->unhideTracks(indices);
- }
+void WTrackTableView::slotUnhide() {
+ QModelIndexList indices = selectionModel()->selectedRows();
+ if (indices.isEmpty()) {
+ return;
+ }
+ TrackModel* trackModel = getTrackModel();
+ if (trackModel) {
+ trackModel->unhideTracks(indices);
}
}
@@ -817,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 {
diff --git a/src/widget/wtracktableview.h b/src/widget/wtracktableview.h
index 9a240bd13b6..3cb326d6efe 100644
--- a/src/widget/wtracktableview.h
+++ b/src/widget/wtracktableview.h
@@ -62,6 +62,7 @@ class WTrackTableView : public WLibraryTableView {
void slotMouseDoubleClicked(const QModelIndex &);
void slotUnhide();
void slotPurge();
+ void slotDeleteTracksFromDisk();
void slotAddToAutoDJBottom() override;
void slotAddToAutoDJTop() override;