From 40545ade6db2eae9397f74c65d9ce801b1bcdab1 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sat, 17 Oct 2020 19:48:25 +0200 Subject: [PATCH 01/19] Search related tracks in collection --- src/library/autodj/dlgautodj.cpp | 12 +- src/library/dlganalysis.cpp | 2 +- src/library/dlghidden.cpp | 2 +- src/library/dlgmissing.cpp | 2 +- src/library/library.cpp | 11 +- src/library/library.h | 4 + src/library/mixxxlibraryfeature.cpp | 8 ++ src/library/mixxxlibraryfeature.h | 2 + src/library/recording/dlgrecording.cpp | 2 +- src/skin/legacyskinparser.cpp | 6 +- src/widget/wanalysislibrarytableview.cpp | 4 +- src/widget/wanalysislibrarytableview.h | 2 +- src/widget/wtrackmenu.cpp | 143 +++++++++++++++++++---- src/widget/wtrackmenu.h | 14 ++- src/widget/wtrackproperty.cpp | 4 +- src/widget/wtrackproperty.h | 4 +- src/widget/wtracktableview.cpp | 13 ++- src/widget/wtracktableview.h | 6 +- src/widget/wtracktext.cpp | 4 +- src/widget/wtracktext.h | 4 +- src/widget/wtrackwidgetgroup.cpp | 4 +- src/widget/wtrackwidgetgroup.h | 4 +- 22 files changed, 195 insertions(+), 62 deletions(-) diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 785706a7e941..b42620c71ec7 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -16,8 +16,7 @@ const char* kPreferenceGroupName = "[Auto DJ]"; const char* kRepeatPlaylistPreference = "Requeue"; } // anonymous namespace -DlgAutoDJ::DlgAutoDJ( - WLibrary* parent, +DlgAutoDJ::DlgAutoDJ(WLibrary* parent, UserSettingsPointer pConfig, Library* pLibrary, AutoDJProcessor* pProcessor, @@ -26,10 +25,11 @@ DlgAutoDJ::DlgAutoDJ( Ui::DlgAutoDJ(), m_pConfig(pConfig), m_pAutoDJProcessor(pProcessor), - m_pTrackTableView(new WTrackTableView(this, m_pConfig, - pLibrary->trackCollections(), - parent->getTrackTableBackgroundColorOpacity(), - /*no sorting*/ false)), + m_pTrackTableView(new WTrackTableView(this, + m_pConfig, + pLibrary, + parent->getTrackTableBackgroundColorOpacity(), + /*no sorting*/ false)), m_bShowButtonText(parent->getShowButtonText()), m_pAutoDJTableModel(nullptr) { setupUi(this); diff --git a/src/library/dlganalysis.cpp b/src/library/dlganalysis.cpp index a3f9a1bf34ca..50077f30aec8 100644 --- a/src/library/dlganalysis.cpp +++ b/src/library/dlganalysis.cpp @@ -24,7 +24,7 @@ DlgAnalysis::DlgAnalysis(WLibrary* parent, m_pAnalysisLibraryTableView = new WAnalysisLibraryTableView( this, pConfig, - pLibrary->trackCollections(), + pLibrary, parent->getTrackTableBackgroundColorOpacity()); connect(m_pAnalysisLibraryTableView, &WAnalysisLibraryTableView::loadTrack, diff --git a/src/library/dlghidden.cpp b/src/library/dlghidden.cpp index 8b4807f3b497..63cb6deac364 100644 --- a/src/library/dlghidden.cpp +++ b/src/library/dlghidden.cpp @@ -17,7 +17,7 @@ DlgHidden::DlgHidden( new WTrackTableView( this, pConfig, - pLibrary->trackCollections(), + pLibrary, parent->getTrackTableBackgroundColorOpacity(), false)) { setupUi(this); diff --git a/src/library/dlgmissing.cpp b/src/library/dlgmissing.cpp index 30bb96d37998..c73d6e3ec433 100644 --- a/src/library/dlgmissing.cpp +++ b/src/library/dlgmissing.cpp @@ -17,7 +17,7 @@ DlgMissing::DlgMissing( new WTrackTableView( this, pConfig, - pLibrary->trackCollections(), + pLibrary, parent->getTrackTableBackgroundColorOpacity(), false)) { setupUi(this); diff --git a/src/library/library.cpp b/src/library/library.cpp index 66d1420472d6..27ab18ce0a67 100644 --- a/src/library/library.cpp +++ b/src/library/library.cpp @@ -298,7 +298,7 @@ void Library::bindLibraryWidget( WLibrary* pLibraryWidget, KeyboardEventFilter* pKeyboard) { WTrackTableView* pTrackTableView = new WTrackTableView(pLibraryWidget, m_pConfig, - m_pTrackCollectionManager, + this, pLibraryWidget->getTrackTableBackgroundColorOpacity(), true); pTrackTableView->installEventFilter(pKeyboard); @@ -551,3 +551,12 @@ TrackCollection& Library::trackCollection() { DEBUG_ASSERT(m_pTrackCollectionManager->internalCollection()); return *m_pTrackCollectionManager->internalCollection(); } + +void Library::searchTracksInCollection(const QString& query) { + VERIFY_OR_DEBUG_ASSERT(m_pMixxxLibraryFeature) { + return; + } + m_pMixxxLibraryFeature->searchAndActivate(query); + emit switchToView(m_sTrackViewName); + m_pSidebarModel->activateDefaultSelection(); +} diff --git a/src/library/library.h b/src/library/library.h index 8420c37864cb..04ea4d02132a 100644 --- a/src/library/library.h +++ b/src/library/library.h @@ -90,6 +90,10 @@ class Library: public QObject { void setRowHeight(int rowHeight); void setEditMedatataSelectedClick(bool enable); + /// Triggers a new search in the internal track collection + /// and shows the results by switching the view. + void searchTracksInCollection(const QString& query); + public slots: void slotShowTrackModel(QAbstractItemModel* model); void slotSwitchToView(const QString& view); diff --git a/src/library/mixxxlibraryfeature.cpp b/src/library/mixxxlibraryfeature.cpp index 47c6e5d562cd..e1c62c1ca395 100644 --- a/src/library/mixxxlibraryfeature.cpp +++ b/src/library/mixxxlibraryfeature.cpp @@ -152,6 +152,14 @@ void MixxxLibraryFeature::refreshLibraryModels() { } } +void MixxxLibraryFeature::searchAndActivate(const QString& query) { + VERIFY_OR_DEBUG_ASSERT(m_pLibraryTableModel) { + return; + } + m_pLibraryTableModel->search(query); + activate(); +} + void MixxxLibraryFeature::activate() { qDebug() << "MixxxLibraryFeature::activate()"; emit showTrackModel(m_pLibraryTableModel); diff --git a/src/library/mixxxlibraryfeature.h b/src/library/mixxxlibraryfeature.h index 3dd70bbb7bbb..f1aae5ac827b 100644 --- a/src/library/mixxxlibraryfeature.h +++ b/src/library/mixxxlibraryfeature.h @@ -44,6 +44,8 @@ class MixxxLibraryFeature final : public LibraryFeature { return true; } + void searchAndActivate(const QString& query); + public slots: void activate() override; void activateChild(const QModelIndex& index) override; diff --git a/src/library/recording/dlgrecording.cpp b/src/library/recording/dlgrecording.cpp index d986695fffe2..9ca47dfa0d24 100644 --- a/src/library/recording/dlgrecording.cpp +++ b/src/library/recording/dlgrecording.cpp @@ -22,7 +22,7 @@ DlgRecording::DlgRecording( new WTrackTableView( this, pConfig, - pLibrary->trackCollections(), + pLibrary, parent->getTrackTableBackgroundColorOpacity(), true)), m_browseModel(this, pLibrary->trackCollections(), pRecordingManager), diff --git a/src/skin/legacyskinparser.cpp b/src/skin/legacyskinparser.cpp index 896ee0fd3aa2..4ab4f8f445c2 100644 --- a/src/skin/legacyskinparser.cpp +++ b/src/skin/legacyskinparser.cpp @@ -989,7 +989,7 @@ QWidget* LegacySkinParser::parseText(const QDomElement& node) { WTrackText* p = new WTrackText(m_pParent, m_pConfig, - m_pLibrary->trackCollections(), + m_pLibrary, group); setupLabelWidget(node, p); @@ -1021,7 +1021,7 @@ QWidget* LegacySkinParser::parseTrackProperty(const QDomElement& node) { WTrackProperty* p = new WTrackProperty( m_pParent, m_pConfig, - m_pLibrary->trackCollections(), + m_pLibrary, group); setupLabelWidget(node, p); @@ -1053,7 +1053,7 @@ QWidget* LegacySkinParser::parseTrackWidgetGroup(const QDomElement& node) { WTrackWidgetGroup* pGroup = new WTrackWidgetGroup( m_pParent, m_pConfig, - m_pLibrary->trackCollections(), + m_pLibrary, group); commonWidgetSetup(node, pGroup); pGroup->setup(node, *m_pContext); diff --git a/src/widget/wanalysislibrarytableview.cpp b/src/widget/wanalysislibrarytableview.cpp index 08d7af63de4f..b33a8c7a4966 100644 --- a/src/widget/wanalysislibrarytableview.cpp +++ b/src/widget/wanalysislibrarytableview.cpp @@ -4,11 +4,11 @@ WAnalysisLibraryTableView::WAnalysisLibraryTableView( QWidget* parent, UserSettingsPointer pConfig, - TrackCollectionManager* pTrackCollectionManager, + Library* pLibrary, double trackTableBackgroundColorOpacity) : WTrackTableView(parent, pConfig, - pTrackCollectionManager, + pLibrary, trackTableBackgroundColorOpacity, true) { setDragDropMode(QAbstractItemView::DragOnly); diff --git a/src/widget/wanalysislibrarytableview.h b/src/widget/wanalysislibrarytableview.h index c3733b8abbaf..f929520d7bce 100644 --- a/src/widget/wanalysislibrarytableview.h +++ b/src/widget/wanalysislibrarytableview.h @@ -11,7 +11,7 @@ class WAnalysisLibraryTableView : public WTrackTableView { WAnalysisLibraryTableView( QWidget* parent, UserSettingsPointer pConfig, - TrackCollectionManager* pTrackCollectionManager, + Library* pLibrary, double trackTableBackgroundColorOpacity); void onSearch(const QString& text) override; diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 03d0cbaac016..deaa03a62f4f 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -35,15 +35,16 @@ #include "widget/wstarrating.h" #include "widget/wwidget.h" -WTrackMenu::WTrackMenu(QWidget* parent, +WTrackMenu::WTrackMenu( + QWidget* parent, UserSettingsPointer pConfig, - TrackCollectionManager* pTrackCollectionManager, + Library* pLibrary, Features flags, TrackModel* trackModel) : QMenu(parent), m_pTrackModel(trackModel), m_pConfig(pConfig), - m_pTrackCollectionManager(pTrackCollectionManager), + m_pLibrary(pLibrary), m_bPlaylistMenuLoaded(false), m_bCrateMenuLoaded(false), m_eActiveFeatures(flags), @@ -138,6 +139,88 @@ void WTrackMenu::createMenus() { //: Reset metadata in right click track context menu in library m_pClearMetadataMenu->setTitle(tr("Reset")); } + + if (featureIsEnabled(Feature::SearchRelated)) { + // TODO: Create a new subclass of QMenu? + DEBUG_ASSERT(!m_pSearchRelatedMenu); + m_pSearchRelatedMenu = + make_parented(tr("Search related tracks"), this); + connect(m_pSearchRelatedMenu, + &QMenu::aboutToShow, + this, + [this] { + m_pSearchRelatedMenu->clear(); + m_pSearchRelatedMenu->setEnabled(false); + const auto pTrack = getFirstTrackPointer(); + if (!pTrack) { + return; + } + auto primaryArtist = pTrack->getArtist(); + auto secondaryArtist = pTrack->getAlbumArtist(); + if (primaryArtist.isEmpty()) { + primaryArtist = secondaryArtist; + secondaryArtist = QString(); + } else { + if (!secondaryArtist.isEmpty() && + primaryArtist.contains(secondaryArtist)) { + // Use the shorter string as primary artist and the + // longer string as secondary artist + if (primaryArtist == secondaryArtist) { + secondaryArtist = QString(); + } else { + std::swap(primaryArtist, secondaryArtist); + } + } + } + DEBUG_ASSERT(!primaryArtist.isEmpty() || secondaryArtist.isEmpty()); + if (!primaryArtist.isEmpty()) { + const auto primaryArtistText = + mixxx::escapeTextPropertyWithoutShortcuts(primaryArtist); + const auto secondaryArtistText = + mixxx::escapeTextPropertyWithoutShortcuts(secondaryArtist); + // Search tracks with similar artist(s) + m_pSearchRelatedMenu->addAction( + tr("Search artist \"%1\"") + .arg(primaryArtistText), + [this, primaryArtist]() { + m_pLibrary->searchTracksInCollection( + QStringLiteral("artist:\"") + + primaryArtist + QChar('"')); + }); + if (!secondaryArtist.isEmpty()) { + m_pSearchRelatedMenu->addAction( + tr("Search artist \"%1\"") + .arg(secondaryArtistText), + [this, secondaryArtist]() { + m_pLibrary->searchTracksInCollection( + QStringLiteral("artist:\"") + + secondaryArtist + QChar('"')); + }); + } + m_pSearchRelatedMenu->addAction( + tr("Search album artist \"%1\"") + .arg(primaryArtistText), + [this, primaryArtist]() { + m_pLibrary->searchTracksInCollection( + QStringLiteral("album_artist:\"") + + primaryArtist + QChar('"')); + }); + if (!secondaryArtist.isEmpty()) { + m_pSearchRelatedMenu->addAction( + tr("Search album artist \"%1\"") + .arg(secondaryArtistText), + [this, secondaryArtist]() { + m_pLibrary->searchTracksInCollection( + QStringLiteral( + "album_artist:\"") + + secondaryArtist + QChar('"')); + }); + } + } + m_pSearchRelatedMenu->setEnabled( + !m_pSearchRelatedMenu->isEmpty()); + }); + } } void WTrackMenu::createActions() { @@ -213,7 +296,8 @@ void WTrackMenu::createActions() { this, &WTrackMenu::slotExportMetadataIntoFileTags); - for (const auto& externalTrackCollection : m_pTrackCollectionManager->externalCollections()) { + for (const auto& externalTrackCollection : + m_pLibrary->trackCollections()->externalCollections()) { UpdateExternalTrackCollection updateInExternalTrackCollection; updateInExternalTrackCollection.externalTrackCollection = externalTrackCollection; updateInExternalTrackCollection.action = new QAction(externalTrackCollection->name(), m_pMetadataMenu); @@ -336,6 +420,11 @@ void WTrackMenu::setupActions() { addSeparator(); } + if (featureIsEnabled(Feature::SearchRelated)) { + addMenu(m_pSearchRelatedMenu); + addSeparator(); + } + if (featureIsEnabled(Feature::Playlist)) { addMenu(m_pPlaylistMenu); } @@ -822,7 +911,7 @@ int WTrackMenu::applyTrackPointerOperation( operationMode); return modalOperation.processTracks( progressLabelText, - m_pTrackCollectionManager, + m_pLibrary->trackCollections(), pTrackPointerIter.get()); } @@ -920,7 +1009,9 @@ void WTrackMenu::slotPopulatePlaylistMenu() { return; } m_pPlaylistMenu->clear(); - PlaylistDAO& playlistDao = m_pTrackCollectionManager->internalCollection()->getPlaylistDAO(); + PlaylistDAO& playlistDao = m_pLibrary->trackCollections() + ->internalCollection() + ->getPlaylistDAO(); QMap playlists; int numPlaylists = playlistDao.playlistCount(); for (int i = 0; i < numPlaylists; ++i) { @@ -957,7 +1048,9 @@ void WTrackMenu::addSelectionToPlaylist(int iPlaylistId) { return; } - PlaylistDAO& playlistDao = m_pTrackCollectionManager->internalCollection()->getPlaylistDAO(); + PlaylistDAO& playlistDao = m_pLibrary->trackCollections() + ->internalCollection() + ->getPlaylistDAO(); if (iPlaylistId == -1) { // i.e. a new playlist is suppose to be created QString name; @@ -997,7 +1090,7 @@ void WTrackMenu::addSelectionToPlaylist(int iPlaylistId) { } // TODO(XXX): Care whether the append succeeded. - m_pTrackCollectionManager->unhideTracks(trackIds); + m_pLibrary->trackCollections()->unhideTracks(trackIds); playlistDao.appendTracksToPlaylist(trackIds, iPlaylistId); } @@ -1011,7 +1104,11 @@ void WTrackMenu::slotPopulateCrateMenu() { m_pCrateMenu->clear(); const TrackIdList trackIds = getTrackIds(); - CrateSummarySelectResult allCrates(m_pTrackCollectionManager->internalCollection()->crates().selectCratesWithTrackCount(trackIds)); + CrateSummarySelectResult allCrates( + m_pLibrary->trackCollections() + ->internalCollection() + ->crates() + .selectCratesWithTrackCount(trackIds)); CrateSummary crate; while (allCrates.populateNext(&crate)) { @@ -1078,17 +1175,19 @@ void WTrackMenu::updateSelectionCrates(QWidget* pWidget) { pCheckBox->setTristate(false); if (!pCheckBox->isChecked()) { if (crateId.isValid()) { - m_pTrackCollectionManager->internalCollection()->removeCrateTracks(crateId, trackIds); + m_pLibrary->trackCollections() + ->internalCollection() + ->removeCrateTracks(crateId, trackIds); } } else { if (!crateId.isValid()) { // i.e. a new crate is suppose to be created crateId = CrateFeatureHelper( - m_pTrackCollectionManager->internalCollection(), m_pConfig) + m_pLibrary->trackCollections()->internalCollection(), m_pConfig) .createEmptyCrate(); } if (crateId.isValid()) { - m_pTrackCollectionManager->unhideTracks(trackIds); - m_pTrackCollectionManager->internalCollection()->addCrateTracks(crateId, trackIds); + m_pLibrary->trackCollections()->unhideTracks(trackIds); + m_pLibrary->trackCollections()->internalCollection()->addCrateTracks(crateId, trackIds); } } } @@ -1102,12 +1201,12 @@ void WTrackMenu::addSelectionToNewCrate() { } CrateId crateId = CrateFeatureHelper( - m_pTrackCollectionManager->internalCollection(), m_pConfig) + m_pLibrary->trackCollections()->internalCollection(), m_pConfig) .createEmptyCrate(); if (crateId.isValid()) { - m_pTrackCollectionManager->unhideTracks(trackIds); - m_pTrackCollectionManager->internalCollection()->addCrateTracks(crateId, trackIds); + m_pLibrary->trackCollections()->unhideTracks(trackIds); + m_pLibrary->trackCollections()->internalCollection()->addCrateTracks(crateId, trackIds); } } @@ -1478,7 +1577,7 @@ void WTrackMenu::slotClearAllMetadata() { const auto progressLabelText = tr("Resetting all performance metadata of %n track(s)", "", getTrackCount()); AnalysisDao& analysisDao = - m_pTrackCollectionManager->internalCollection()->getAnalysisDAO(); + m_pLibrary->trackCollections()->internalCollection()->getAnalysisDAO(); const auto trackOperator = ClearAllPerformanceMetadataTrackPointerOperation(analysisDao); applyTrackPointerOperation( @@ -1552,10 +1651,12 @@ void WTrackMenu::addToAutoDJ(PlaylistDAO::AutoDJSendLoc loc) { return; } - PlaylistDAO& playlistDao = m_pTrackCollectionManager->internalCollection()->getPlaylistDAO(); + PlaylistDAO& playlistDao = m_pLibrary->trackCollections() + ->internalCollection() + ->getPlaylistDAO(); // TODO(XXX): Care whether the append succeeded. - m_pTrackCollectionManager->unhideTracks(trackIds); + m_pLibrary->trackCollections()->unhideTracks(trackIds); playlistDao.addTracksToAutoDJQueue(trackIds, loc); } @@ -1694,8 +1795,10 @@ bool WTrackMenu::featureIsEnabled(Feature flag) const { return true; case Feature::Properties: return m_pTrackModel->hasCapabilities(TrackModel::Capability::EditMetadata); + case Feature::SearchRelated: + return m_pLibrary != nullptr; default: DEBUG_ASSERT(!"unreachable"); - return true; + return false; } } diff --git a/src/widget/wtrackmenu.h b/src/widget/wtrackmenu.h index cd898fa5c169..1a1673073834 100644 --- a/src/widget/wtrackmenu.h +++ b/src/widget/wtrackmenu.h @@ -11,12 +11,13 @@ #include "preferences/usersettings.h" #include "track/trackref.h" #include "util/color/rgbcolor.h" +#include "util/parented_ptr.h" class ControlProxy; class DlgTagFetcher; class DlgTrackInfo; class ExternalTrackCollection; -class TrackCollectionManager; +class Library; class TrackModel; class WColorPickerAction; class WCoverArtMenu; @@ -43,15 +44,17 @@ class WTrackMenu : public QMenu { HideUnhidePurge = 1 << 9, FileBrowser = 1 << 10, Properties = 1 << 11, + SearchRelated = 1 << 12, TrackModelFeatures = Remove | HideUnhidePurge, All = AutoDJ | LoadTo | Playlist | Crate | Remove | Metadata | Reset | - BPM | Color | HideUnhidePurge | FileBrowser | Properties + BPM | Color | HideUnhidePurge | FileBrowser | Properties | + SearchRelated }; Q_DECLARE_FLAGS(Features, Feature) WTrackMenu(QWidget* parent, UserSettingsPointer pConfig, - TrackCollectionManager* pTrackCollectionManager, + Library* pLibrary, Features flags = Feature::All, TrackModel* trackModel = nullptr); ~WTrackMenu() override; @@ -173,7 +176,7 @@ class WTrackMenu : public QMenu { std::optional> getCommonTrackColor() const; CoverInfo getCoverInfoOfLastTrack() const; - TrackModel* m_pTrackModel{}; + TrackModel* const m_pTrackModel; QModelIndexList m_trackIndexList; // Source of track list when TrackModel is not set. @@ -195,6 +198,7 @@ class WTrackMenu : public QMenu { QMenu* m_pBPMMenu{}; QMenu* m_pColorMenu{}; WCoverArtMenu* m_pCoverMenu{}; + parented_ptr m_pSearchRelatedMenu; // Reload Track Metadata Action: QAction* m_pImportMetadataFromFileAct{}; @@ -253,7 +257,7 @@ class WTrackMenu : public QMenu { QAction* m_pClearAllMetadataAction{}; const UserSettingsPointer m_pConfig; - TrackCollectionManager* const m_pTrackCollectionManager; + Library* const m_pLibrary; std::unique_ptr m_pDlgTrackInfo; std::unique_ptr m_pDlgTagFetcher; diff --git a/src/widget/wtrackproperty.cpp b/src/widget/wtrackproperty.cpp index d540e7b8ef25..9855e144463c 100644 --- a/src/widget/wtrackproperty.cpp +++ b/src/widget/wtrackproperty.cpp @@ -23,13 +23,13 @@ const WTrackMenu::Features kTrackMenuFeatures = WTrackProperty::WTrackProperty( QWidget* pParent, UserSettingsPointer pConfig, - TrackCollectionManager* pTrackCollectionManager, + Library* pLibrary, const QString& group) : WLabel(pParent), m_group(group), m_pConfig(pConfig), m_pTrackMenu(make_parented( - this, pConfig, pTrackCollectionManager, kTrackMenuFeatures)) { + this, pConfig, pLibrary, kTrackMenuFeatures)) { setAcceptDrops(true); } diff --git a/src/widget/wtrackproperty.h b/src/widget/wtrackproperty.h index fe4c5edccb66..250f54ce13d0 100644 --- a/src/widget/wtrackproperty.h +++ b/src/widget/wtrackproperty.h @@ -12,7 +12,7 @@ #include "widget/trackdroptarget.h" #include "widget/wlabel.h" -class TrackCollectionManager; +class Library; class WTrackMenu; class WTrackProperty : public WLabel, public TrackDropTarget { @@ -21,7 +21,7 @@ class WTrackProperty : public WLabel, public TrackDropTarget { WTrackProperty( QWidget* pParent, UserSettingsPointer pConfig, - TrackCollectionManager* pTrackCollectionManager, + Library* pLibrary, const QString& group); ~WTrackProperty() override; diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index 6fe37cbbf622..6ba3cd74b514 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -8,6 +8,7 @@ #include "control/controlobject.h" #include "library/dao/trackschema.h" +#include "library/library.h" #include "library/librarytablemodel.h" #include "library/trackcollection.h" #include "library/trackcollectionmanager.h" @@ -31,7 +32,7 @@ const ConfigKey kConfigKeyAllowTrackLoadToPlayingDeck("[Controls]", "AllowTrackL WTrackTableView::WTrackTableView(QWidget* parent, UserSettingsPointer pConfig, - TrackCollectionManager* pTrackCollectionManager, + Library* pLibrary, double backgroundColorOpacity, bool sorting) : WLibraryTableView(parent, @@ -39,7 +40,7 @@ WTrackTableView::WTrackTableView(QWidget* parent, ConfigKey(LIBRARY_CONFIGVALUE, WTRACKTABLEVIEW_VSCROLLBARPOS_KEY)), m_pConfig(pConfig), - m_pTrackCollectionManager(pTrackCollectionManager), + m_pLibrary(pLibrary), m_backgroundColorOpacity(backgroundColorOpacity), m_sorting(sorting), m_selectionChangedSinceLastGuiTick(true), @@ -321,7 +322,7 @@ void WTrackTableView::initTrackMenu() { m_pTrackMenu = make_parented(this, m_pConfig, - m_pTrackCollectionManager, + m_pLibrary, WTrackMenu::Feature::All, trackModel); connect(m_pTrackMenu.get(), @@ -833,10 +834,12 @@ void WTrackTableView::addToAutoDJ(PlaylistDAO::AutoDJSendLoc loc) { return; } - PlaylistDAO& playlistDao = m_pTrackCollectionManager->internalCollection()->getPlaylistDAO(); + PlaylistDAO& playlistDao = m_pLibrary->trackCollections() + ->internalCollection() + ->getPlaylistDAO(); // TODO(XXX): Care whether the append succeeded. - m_pTrackCollectionManager->unhideTracks(trackIds); + m_pLibrary->trackCollections()->unhideTracks(trackIds); playlistDao.addTracksToAutoDJQueue(trackIds, loc); } diff --git a/src/widget/wtracktableview.h b/src/widget/wtracktableview.h index bd7f7b56b6b2..8fd5ef2bf770 100644 --- a/src/widget/wtracktableview.h +++ b/src/widget/wtracktableview.h @@ -14,8 +14,8 @@ class ControlProxy; class DlgTagFetcher; class DlgTrackInfo; -class TrackCollectionManager; class ExternalTrackCollection; +class Library; class WTrackMenu; const QString WTRACKTABLEVIEW_VSCROLLBARPOS_KEY = "VScrollBarPos"; /** ConfigValue key for QTable vertical scrollbar position */ @@ -27,7 +27,7 @@ class WTrackTableView : public WLibraryTableView { WTrackTableView( QWidget* parent, UserSettingsPointer pConfig, - TrackCollectionManager* pTrackCollectionManager, + Library* pLibrary, double backgroundColorOpacity, bool sorting); ~WTrackTableView() override; @@ -91,7 +91,7 @@ class WTrackTableView : public WLibraryTableView { void initTrackMenu(); const UserSettingsPointer m_pConfig; - TrackCollectionManager* const m_pTrackCollectionManager; + Library* const m_pLibrary; // Context menu container parented_ptr m_pTrackMenu; diff --git a/src/widget/wtracktext.cpp b/src/widget/wtracktext.cpp index 251b7256d2fb..00748f3cdf2d 100644 --- a/src/widget/wtracktext.cpp +++ b/src/widget/wtracktext.cpp @@ -23,13 +23,13 @@ const WTrackMenu::Features trackMenuFeatures = WTrackText::WTrackText(QWidget* pParent, UserSettingsPointer pConfig, - TrackCollectionManager* pTrackCollectionManager, + Library* pLibrary, const QString& group) : WLabel(pParent), m_group(group), m_pConfig(pConfig), m_pTrackMenu(make_parented( - this, pConfig, pTrackCollectionManager, trackMenuFeatures)) { + this, pConfig, pLibrary, trackMenuFeatures)) { setAcceptDrops(true); } diff --git a/src/widget/wtracktext.h b/src/widget/wtracktext.h index 106408da3430..541fca92205b 100644 --- a/src/widget/wtracktext.h +++ b/src/widget/wtracktext.h @@ -11,7 +11,7 @@ #include "widget/trackdroptarget.h" #include "widget/wlabel.h" -class TrackCollectionManager; +class Library; class WTrackMenu; class WTrackText : public WLabel, public TrackDropTarget { @@ -20,7 +20,7 @@ class WTrackText : public WLabel, public TrackDropTarget { WTrackText( QWidget* pParent, UserSettingsPointer pConfig, - TrackCollectionManager* pTrackCollectionManager, + Library* pLibrary, const QString& group); ~WTrackText() override; diff --git a/src/widget/wtrackwidgetgroup.cpp b/src/widget/wtrackwidgetgroup.cpp index 035c8679ce76..2d747e043aaa 100644 --- a/src/widget/wtrackwidgetgroup.cpp +++ b/src/widget/wtrackwidgetgroup.cpp @@ -28,14 +28,14 @@ const WTrackMenu::Features kTrackMenuFeatures = WTrackWidgetGroup::WTrackWidgetGroup(QWidget* pParent, UserSettingsPointer pConfig, - TrackCollectionManager* pTrackCollectionManager, + Library* pLibrary, const QString& group) : WWidgetGroup(pParent), m_group(group), m_pConfig(pConfig), m_trackColorAlpha(kDefaultTrackColorAlpha), m_pTrackMenu(make_parented( - this, pConfig, pTrackCollectionManager, kTrackMenuFeatures)) { + this, pConfig, pLibrary, kTrackMenuFeatures)) { setAcceptDrops(true); } diff --git a/src/widget/wtrackwidgetgroup.h b/src/widget/wtrackwidgetgroup.h index 839e59c349c7..6960a5ee00c8 100644 --- a/src/widget/wtrackwidgetgroup.h +++ b/src/widget/wtrackwidgetgroup.h @@ -7,15 +7,15 @@ #include "widget/trackdroptarget.h" #include "widget/wwidgetgroup.h" +class Library; class WTrackMenu; -class TrackCollectionManager; class WTrackWidgetGroup : public WWidgetGroup, public TrackDropTarget { Q_OBJECT public: WTrackWidgetGroup(QWidget* pParent, UserSettingsPointer pConfig, - TrackCollectionManager* pTrackCollectionManager, + Library* pLibrary, const QString& group); ~WTrackWidgetGroup() override; void setup(const QDomNode& node, const SkinContext& context) override; From b222007dbd356c354074c7a4e3043c38bf369b09 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sun, 18 Oct 2020 12:59:03 +0200 Subject: [PATCH 02/19] Reduce log spam --- src/library/mixxxlibraryfeature.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/library/mixxxlibraryfeature.cpp b/src/library/mixxxlibraryfeature.cpp index e1c62c1ca395..5895fff0a370 100644 --- a/src/library/mixxxlibraryfeature.cpp +++ b/src/library/mixxxlibraryfeature.cpp @@ -161,7 +161,6 @@ void MixxxLibraryFeature::searchAndActivate(const QString& query) { } void MixxxLibraryFeature::activate() { - qDebug() << "MixxxLibraryFeature::activate()"; emit showTrackModel(m_pLibraryTableModel); emit enableCoverArtDisplay(true); } From 8e2ba9e951410aa656d0e0cbd17fd12f897b3dce Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sun, 18 Oct 2020 01:02:04 +0200 Subject: [PATCH 03/19] Add more search options for related tracks --- src/widget/wtrackmenu.cpp | 75 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index deaa03a62f4f..e5a5325000b7 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -144,7 +144,7 @@ void WTrackMenu::createMenus() { // TODO: Create a new subclass of QMenu? DEBUG_ASSERT(!m_pSearchRelatedMenu); m_pSearchRelatedMenu = - make_parented(tr("Search related tracks"), this); + make_parented(tr("Search related Tracks"), this); connect(m_pSearchRelatedMenu, &QMenu::aboutToShow, this, @@ -155,6 +155,32 @@ void WTrackMenu::createMenus() { if (!pTrack) { return; } + const auto musicalKey = pTrack->getKeyText(); + if (!musicalKey.isEmpty()) { + const auto musicalKeyText = + mixxx::escapeTextPropertyWithoutShortcuts(musicalKey); + m_pSearchRelatedMenu->addAction( + tr("Harmonic keys for \"%1\"") + .arg(musicalKeyText), + [this, musicalKey]() { + m_pLibrary->searchTracksInCollection( + QStringLiteral("~key:\"") + + musicalKey + QChar('"')); + }); + } + const auto genre = pTrack->getGenre(); + if (!genre.isEmpty()) { + const auto genreText = + mixxx::escapeTextPropertyWithoutShortcuts(genre); + m_pSearchRelatedMenu->addAction( + tr("Genre \"%1\"") + .arg(genreText), + [this, genre]() { + m_pLibrary->searchTracksInCollection( + QStringLiteral("genre:\"") + + genre + QChar('"')); + }); + } auto primaryArtist = pTrack->getArtist(); auto secondaryArtist = pTrack->getAlbumArtist(); if (primaryArtist.isEmpty()) { @@ -180,7 +206,7 @@ void WTrackMenu::createMenus() { mixxx::escapeTextPropertyWithoutShortcuts(secondaryArtist); // Search tracks with similar artist(s) m_pSearchRelatedMenu->addAction( - tr("Search artist \"%1\"") + tr("Artist \"%1\"") .arg(primaryArtistText), [this, primaryArtist]() { m_pLibrary->searchTracksInCollection( @@ -189,7 +215,7 @@ void WTrackMenu::createMenus() { }); if (!secondaryArtist.isEmpty()) { m_pSearchRelatedMenu->addAction( - tr("Search artist \"%1\"") + tr("Artist \"%1\"") .arg(secondaryArtistText), [this, secondaryArtist]() { m_pLibrary->searchTracksInCollection( @@ -198,7 +224,7 @@ void WTrackMenu::createMenus() { }); } m_pSearchRelatedMenu->addAction( - tr("Search album artist \"%1\"") + tr("Album artist \"%1\"") .arg(primaryArtistText), [this, primaryArtist]() { m_pLibrary->searchTracksInCollection( @@ -207,7 +233,7 @@ void WTrackMenu::createMenus() { }); if (!secondaryArtist.isEmpty()) { m_pSearchRelatedMenu->addAction( - tr("Search album artist \"%1\"") + tr("Album artist \"%1\"") .arg(secondaryArtistText), [this, secondaryArtist]() { m_pLibrary->searchTracksInCollection( @@ -217,6 +243,45 @@ void WTrackMenu::createMenus() { }); } } + const auto albumTitle = pTrack->getAlbum(); + if (!albumTitle.isEmpty()) { + const auto albumTitleText = + mixxx::escapeTextPropertyWithoutShortcuts(albumTitle); + m_pSearchRelatedMenu->addAction( + tr("Album \"%1\"") + .arg(albumTitleText), + [this, albumTitle]() { + m_pLibrary->searchTracksInCollection( + QStringLiteral("album:\"") + + albumTitle + QChar('"')); + }); + } + const auto composer = pTrack->getComposer(); + if (!composer.isEmpty()) { + const auto composerText = + mixxx::escapeTextPropertyWithoutShortcuts(composer); + m_pSearchRelatedMenu->addAction( + tr("Composer \"%1\"") + .arg(composerText), + [this, composer]() { + m_pLibrary->searchTracksInCollection( + QStringLiteral("composer:\"") + + composer + QChar('"')); + }); + } + const auto locationPath = pTrack->getFileInfo().directory(); + if (!locationPath.isEmpty()) { + const auto locationPathText = + mixxx::escapeTextPropertyWithoutShortcuts(locationPath); + m_pSearchRelatedMenu->addAction( + tr("Folder \"%1\"") + .arg(locationPathText), + [this, locationPath]() { + m_pLibrary->searchTracksInCollection( + QStringLiteral("location:\"") + + locationPath + QChar('"')); + }); + } m_pSearchRelatedMenu->setEnabled( !m_pSearchRelatedMenu->isEmpty()); }); From a6e71c5ca51b2865389335e3470123ed3a510352 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sun, 18 Oct 2020 01:36:56 +0200 Subject: [PATCH 04/19] Make "Search related Tracks" the first menu entry --- src/widget/wtrackmenu.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index e5a5325000b7..ac40ca993527 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -465,6 +465,11 @@ void WTrackMenu::createActions() { } void WTrackMenu::setupActions() { + if (featureIsEnabled(Feature::SearchRelated)) { + addMenu(m_pSearchRelatedMenu); + addSeparator(); + } + if (featureIsEnabled(Feature::AutoDJ)) { addAction(m_pAutoDJBottomAct); addAction(m_pAutoDJTopAct); @@ -485,11 +490,6 @@ void WTrackMenu::setupActions() { addSeparator(); } - if (featureIsEnabled(Feature::SearchRelated)) { - addMenu(m_pSearchRelatedMenu); - addSeparator(); - } - if (featureIsEnabled(Feature::Playlist)) { addMenu(m_pPlaylistMenu); } From 234a5910e1f4b92866d663a929b317bc6488efbd Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sun, 18 Oct 2020 02:01:21 +0200 Subject: [PATCH 05/19] WTrackWidgetGroup: Enable searching for related tracks --- src/widget/wtrackwidgetgroup.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/widget/wtrackwidgetgroup.cpp b/src/widget/wtrackwidgetgroup.cpp index 2d747e043aaa..bd6ae5938cd7 100644 --- a/src/widget/wtrackwidgetgroup.cpp +++ b/src/widget/wtrackwidgetgroup.cpp @@ -15,6 +15,7 @@ namespace { constexpr int kDefaultTrackColorAlpha = 255; const WTrackMenu::Features kTrackMenuFeatures = + WTrackMenu::Feature::SearchRelated | WTrackMenu::Feature::Playlist | WTrackMenu::Feature::Crate | WTrackMenu::Feature::Metadata | From a41d28a0e9876e17dc45101bcfc5bc4a1a269acf Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sun, 18 Oct 2020 02:05:32 +0200 Subject: [PATCH 06/19] WTrackText: Enable searching for related tracks --- src/widget/wtracktext.cpp | 5 +++-- src/widget/wtrackwidgetgroup.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/widget/wtracktext.cpp b/src/widget/wtracktext.cpp index 00748f3cdf2d..cd875e433a60 100644 --- a/src/widget/wtracktext.cpp +++ b/src/widget/wtracktext.cpp @@ -10,7 +10,8 @@ #include "widget/wtrackmenu.h" namespace { -const WTrackMenu::Features trackMenuFeatures = +constexpr WTrackMenu::Features kTrackMenuFeatures = + WTrackMenu::Feature::SearchRelated | WTrackMenu::Feature::Playlist | WTrackMenu::Feature::Crate | WTrackMenu::Feature::Metadata | @@ -29,7 +30,7 @@ WTrackText::WTrackText(QWidget* pParent, m_group(group), m_pConfig(pConfig), m_pTrackMenu(make_parented( - this, pConfig, pLibrary, trackMenuFeatures)) { + this, pConfig, pLibrary, kTrackMenuFeatures)) { setAcceptDrops(true); } diff --git a/src/widget/wtrackwidgetgroup.cpp b/src/widget/wtrackwidgetgroup.cpp index bd6ae5938cd7..673f6d8bf3e4 100644 --- a/src/widget/wtrackwidgetgroup.cpp +++ b/src/widget/wtrackwidgetgroup.cpp @@ -14,7 +14,7 @@ namespace { constexpr int kDefaultTrackColorAlpha = 255; -const WTrackMenu::Features kTrackMenuFeatures = +constexpr WTrackMenu::Features kTrackMenuFeatures = WTrackMenu::Feature::SearchRelated | WTrackMenu::Feature::Playlist | WTrackMenu::Feature::Crate | From 8f15c9c58c96a6a975af907f6be7d506397cbc78 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sun, 18 Oct 2020 02:09:36 +0200 Subject: [PATCH 07/19] WTrackProperty: Enable searching for related tracks --- src/widget/wtrackproperty.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/widget/wtrackproperty.cpp b/src/widget/wtrackproperty.cpp index 9855e144463c..217f9ba0cb11 100644 --- a/src/widget/wtrackproperty.cpp +++ b/src/widget/wtrackproperty.cpp @@ -9,7 +9,8 @@ #include "widget/wtrackmenu.h" namespace { -const WTrackMenu::Features kTrackMenuFeatures = +constexpr WTrackMenu::Features kTrackMenuFeatures = + WTrackMenu::Feature::SearchRelated | WTrackMenu::Feature::Playlist | WTrackMenu::Feature::Crate | WTrackMenu::Feature::Metadata | From 653b5559c2efa93b83ed020fb4a5eb1a4cfdf68c Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sun, 18 Oct 2020 02:19:27 +0200 Subject: [PATCH 08/19] Search for related tracks by title --- src/widget/wtrackmenu.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index ac40ca993527..526a235726fd 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -181,6 +181,19 @@ void WTrackMenu::createMenus() { genre + QChar('"')); }); } + const auto title = pTrack->getTitle(); + if (!title.isEmpty()) { + const auto titleText = + mixxx::escapeTextPropertyWithoutShortcuts(title); + m_pSearchRelatedMenu->addAction( + tr("Title \"%1\"") + .arg(titleText), + [this, title]() { + m_pLibrary->searchTracksInCollection( + QStringLiteral("title:\"") + + title + QChar('"')); + }); + } auto primaryArtist = pTrack->getArtist(); auto secondaryArtist = pTrack->getAlbumArtist(); if (primaryArtist.isEmpty()) { From 012d9bcafcbadf455fc7707d20c460acecfc6f31 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sun, 18 Oct 2020 11:59:36 +0200 Subject: [PATCH 09/19] Extract WSearchRelatedTracksMenu from WTrackMenu --- CMakeLists.txt | 1 + build/depends.py | 1 + src/widget/wsearchrelatedtracksmenu.cpp | 179 ++++++++++++++++++++++++ src/widget/wsearchrelatedtracksmenu.h | 30 ++++ src/widget/wtrackmenu.cpp | 153 ++------------------ src/widget/wtrackmenu.h | 3 +- 6 files changed, 222 insertions(+), 145 deletions(-) create mode 100644 src/widget/wsearchrelatedtracksmenu.cpp create mode 100644 src/widget/wsearchrelatedtracksmenu.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ccfbb720727d..c0a44c18e7f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -902,6 +902,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/widget/wpushbutton.cpp src/widget/wrecordingduration.cpp src/widget/wsearchlineedit.cpp + src/widget/wsearchrelatedtracksmenu.cpp src/widget/wsingletoncontainer.cpp src/widget/wsizeawarestack.cpp src/widget/wskincolor.cpp diff --git a/build/depends.py b/build/depends.py index dc8e83e4779f..a735ce93a308 100644 --- a/build/depends.py +++ b/build/depends.py @@ -980,6 +980,7 @@ def sources(self, build): "src/widget/wspinny.cpp", "src/widget/wskincolor.cpp", "src/widget/wsearchlineedit.cpp", + "src/widget/wsearchrelatedtracksmenu.cpp", "src/widget/wpixmapstore.cpp", "src/widget/paintable.cpp", "src/widget/wimagestore.cpp", diff --git a/src/widget/wsearchrelatedtracksmenu.cpp b/src/widget/wsearchrelatedtracksmenu.cpp new file mode 100644 index 000000000000..8286fdf64212 --- /dev/null +++ b/src/widget/wsearchrelatedtracksmenu.cpp @@ -0,0 +1,179 @@ +#include "widget/wsearchrelatedtracksmenu.h" + +#include "track/track.h" +#include "util/qt.h" + +WSearchRelatedTracksMenu::WSearchRelatedTracksMenu( + QWidget* parent) + : QMenu(tr("Search related Tracks"), parent) { +} + +void WSearchRelatedTracksMenu::addActionsForTrack( + const Track& track) { + bool addSeparator = false; + + // Musical property actions + const auto keyText = track.getKeyText(); + if (!keyText.isEmpty()) { + const auto keyTextDisplay = + mixxx::escapeTextPropertyWithoutShortcuts(keyText); + addSeparator = addSeparatorBeforeAction(addSeparator); + addAction( + tr("Harmonic keys for \"%1\"") + .arg(keyTextDisplay), + [this, keyText]() { + emit triggerSearch( + QStringLiteral("~key:\"") + + keyText + QChar('"')); + }); + } + const auto genre = track.getGenre(); + if (!genre.isEmpty()) { + const auto genreDisplay = + mixxx::escapeTextPropertyWithoutShortcuts(genre); + addSeparator = addSeparatorBeforeAction(addSeparator); + addAction( + tr("Genre \"%1\"") + .arg(genreDisplay), + [this, genre]() { + emit triggerSearch( + QStringLiteral("genre:\"") + + genre + QChar('"')); + }); + } + + // Artist actions + addSeparator = true; + auto primaryArtist = track.getArtist(); + auto secondaryArtist = track.getAlbumArtist(); + if (primaryArtist.isEmpty()) { + primaryArtist = secondaryArtist; + secondaryArtist = QString(); + } else { + if (!secondaryArtist.isEmpty() && + primaryArtist.contains(secondaryArtist)) { + // Use the shorter string as primary artist and the + // longer string as secondary artist + if (primaryArtist == secondaryArtist) { + secondaryArtist = QString(); + } else { + std::swap(primaryArtist, secondaryArtist); + } + } + } + DEBUG_ASSERT(!primaryArtist.isEmpty() || secondaryArtist.isEmpty()); + if (!primaryArtist.isEmpty()) { + const auto primaryArtistDisplay = + mixxx::escapeTextPropertyWithoutShortcuts(primaryArtist); + const auto secondaryArtistDisplay = + mixxx::escapeTextPropertyWithoutShortcuts(secondaryArtist); + // Search tracks with similar artist(s) + addSeparator = addSeparatorBeforeAction(addSeparator); + addAction( + tr("Artist \"%1\"") + .arg(primaryArtistDisplay), + [this, primaryArtist]() { + emit triggerSearch( + QStringLiteral("artist:\"") + + primaryArtist + QChar('"')); + }); + if (!secondaryArtist.isEmpty()) { + addSeparator = addSeparatorBeforeAction(addSeparator); + addAction( + tr("Artist \"%1\"") + .arg(secondaryArtistDisplay), + [this, secondaryArtist]() { + emit triggerSearch( + QStringLiteral("artist:\"") + + secondaryArtist + QChar('"')); + }); + } + addSeparator = addSeparatorBeforeAction(addSeparator); + addAction( + tr("Album artist \"%1\"") + .arg(primaryArtistDisplay), + [this, primaryArtist]() { + emit triggerSearch( + QStringLiteral("album_artist:\"") + + primaryArtist + QChar('"')); + }); + if (!secondaryArtist.isEmpty()) { + addSeparator = addSeparatorBeforeAction(addSeparator); + addAction( + tr("Album artist \"%1\"") + .arg(secondaryArtistDisplay), + [this, secondaryArtist]() { + emit triggerSearch( + QStringLiteral( + "album_artist:\"") + + secondaryArtist + QChar('"')); + }); + } + } + const auto composer = track.getComposer(); + if (!composer.isEmpty()) { + const auto composerDisplay = + mixxx::escapeTextPropertyWithoutShortcuts(composer); + addSeparator = addSeparatorBeforeAction(addSeparator); + addAction( + tr("Composer \"%1\"") + .arg(composerDisplay), + [this, composer]() { + emit triggerSearch( + QStringLiteral("composer:\"") + + composer + QChar('"')); + }); + } + + // Title actions + addSeparator = true; + const auto title = track.getTitle(); + if (!title.isEmpty()) { + const auto titleDisplay = + mixxx::escapeTextPropertyWithoutShortcuts(title); + addSeparator = addSeparatorBeforeAction(addSeparator); + addAction( + tr("Title \"%1\"") + .arg(titleDisplay), + [this, title]() { + emit triggerSearch( + QStringLiteral("title:\"") + + title + QChar('"')); + }); + } + const auto album = track.getAlbum(); + if (!album.isEmpty()) { + const auto albumDisplay = + mixxx::escapeTextPropertyWithoutShortcuts(album); + addSeparator = addSeparatorBeforeAction(addSeparator); + addAction( + tr("Album \"%1\"") + .arg(albumDisplay), + [this, album]() { + emit triggerSearch( + QStringLiteral("album:\"") + + album + QChar('"')); + }); + } + + // File system actions + addSeparator = true; + const auto locationPath = track.getFileInfo().directory(); + if (!locationPath.isEmpty()) { + const auto locationPathDisplay = + mixxx::escapeTextPropertyWithoutShortcuts(locationPath); + if (addSeparator) { + this->addSeparator(); + addSeparator = false; + } + addSeparator = addSeparatorBeforeAction(addSeparator); + addAction( + tr("Folder \"%1\"") + .arg(locationPathDisplay), + [this, locationPath]() { + emit triggerSearch( + QStringLiteral("location:\"") + + locationPath + QChar('"')); + }); + } +} diff --git a/src/widget/wsearchrelatedtracksmenu.h b/src/widget/wsearchrelatedtracksmenu.h new file mode 100644 index 000000000000..99c8f1839949 --- /dev/null +++ b/src/widget/wsearchrelatedtracksmenu.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +class Track; + +class WSearchRelatedTracksMenu : public QMenu { + Q_OBJECT + public: + explicit WSearchRelatedTracksMenu( + QWidget* parent = nullptr); + ~WSearchRelatedTracksMenu() override = default; + + void addActionsForTrack( + const Track& track); + + signals: + void triggerSearch( + const QString& searchQuery); + + private: + bool addSeparatorBeforeAction( + bool addSeparator) { + if (addSeparator) { + this->addSeparator(); + } + // Reset flag + return false; + } +}; diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 526a235726fd..5b1f9c320ce0 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -31,6 +31,7 @@ #include "widget/wcolorpickeraction.h" #include "widget/wcoverartlabel.h" #include "widget/wcoverartmenu.h" +#include "widget/wsearchrelatedtracksmenu.h" #include "widget/wskincolor.h" #include "widget/wstarrating.h" #include "widget/wwidget.h" @@ -144,160 +145,24 @@ void WTrackMenu::createMenus() { // TODO: Create a new subclass of QMenu? DEBUG_ASSERT(!m_pSearchRelatedMenu); m_pSearchRelatedMenu = - make_parented(tr("Search related Tracks"), this); + make_parented(this); connect(m_pSearchRelatedMenu, &QMenu::aboutToShow, this, [this] { m_pSearchRelatedMenu->clear(); - m_pSearchRelatedMenu->setEnabled(false); const auto pTrack = getFirstTrackPointer(); - if (!pTrack) { - return; - } - const auto musicalKey = pTrack->getKeyText(); - if (!musicalKey.isEmpty()) { - const auto musicalKeyText = - mixxx::escapeTextPropertyWithoutShortcuts(musicalKey); - m_pSearchRelatedMenu->addAction( - tr("Harmonic keys for \"%1\"") - .arg(musicalKeyText), - [this, musicalKey]() { - m_pLibrary->searchTracksInCollection( - QStringLiteral("~key:\"") + - musicalKey + QChar('"')); - }); - } - const auto genre = pTrack->getGenre(); - if (!genre.isEmpty()) { - const auto genreText = - mixxx::escapeTextPropertyWithoutShortcuts(genre); - m_pSearchRelatedMenu->addAction( - tr("Genre \"%1\"") - .arg(genreText), - [this, genre]() { - m_pLibrary->searchTracksInCollection( - QStringLiteral("genre:\"") + - genre + QChar('"')); - }); - } - const auto title = pTrack->getTitle(); - if (!title.isEmpty()) { - const auto titleText = - mixxx::escapeTextPropertyWithoutShortcuts(title); - m_pSearchRelatedMenu->addAction( - tr("Title \"%1\"") - .arg(titleText), - [this, title]() { - m_pLibrary->searchTracksInCollection( - QStringLiteral("title:\"") + - title + QChar('"')); - }); - } - auto primaryArtist = pTrack->getArtist(); - auto secondaryArtist = pTrack->getAlbumArtist(); - if (primaryArtist.isEmpty()) { - primaryArtist = secondaryArtist; - secondaryArtist = QString(); - } else { - if (!secondaryArtist.isEmpty() && - primaryArtist.contains(secondaryArtist)) { - // Use the shorter string as primary artist and the - // longer string as secondary artist - if (primaryArtist == secondaryArtist) { - secondaryArtist = QString(); - } else { - std::swap(primaryArtist, secondaryArtist); - } - } - } - DEBUG_ASSERT(!primaryArtist.isEmpty() || secondaryArtist.isEmpty()); - if (!primaryArtist.isEmpty()) { - const auto primaryArtistText = - mixxx::escapeTextPropertyWithoutShortcuts(primaryArtist); - const auto secondaryArtistText = - mixxx::escapeTextPropertyWithoutShortcuts(secondaryArtist); - // Search tracks with similar artist(s) - m_pSearchRelatedMenu->addAction( - tr("Artist \"%1\"") - .arg(primaryArtistText), - [this, primaryArtist]() { - m_pLibrary->searchTracksInCollection( - QStringLiteral("artist:\"") + - primaryArtist + QChar('"')); - }); - if (!secondaryArtist.isEmpty()) { - m_pSearchRelatedMenu->addAction( - tr("Artist \"%1\"") - .arg(secondaryArtistText), - [this, secondaryArtist]() { - m_pLibrary->searchTracksInCollection( - QStringLiteral("artist:\"") + - secondaryArtist + QChar('"')); - }); - } - m_pSearchRelatedMenu->addAction( - tr("Album artist \"%1\"") - .arg(primaryArtistText), - [this, primaryArtist]() { - m_pLibrary->searchTracksInCollection( - QStringLiteral("album_artist:\"") + - primaryArtist + QChar('"')); - }); - if (!secondaryArtist.isEmpty()) { - m_pSearchRelatedMenu->addAction( - tr("Album artist \"%1\"") - .arg(secondaryArtistText), - [this, secondaryArtist]() { - m_pLibrary->searchTracksInCollection( - QStringLiteral( - "album_artist:\"") + - secondaryArtist + QChar('"')); - }); - } - } - const auto albumTitle = pTrack->getAlbum(); - if (!albumTitle.isEmpty()) { - const auto albumTitleText = - mixxx::escapeTextPropertyWithoutShortcuts(albumTitle); - m_pSearchRelatedMenu->addAction( - tr("Album \"%1\"") - .arg(albumTitleText), - [this, albumTitle]() { - m_pLibrary->searchTracksInCollection( - QStringLiteral("album:\"") + - albumTitle + QChar('"')); - }); - } - const auto composer = pTrack->getComposer(); - if (!composer.isEmpty()) { - const auto composerText = - mixxx::escapeTextPropertyWithoutShortcuts(composer); - m_pSearchRelatedMenu->addAction( - tr("Composer \"%1\"") - .arg(composerText), - [this, composer]() { - m_pLibrary->searchTracksInCollection( - QStringLiteral("composer:\"") + - composer + QChar('"')); - }); - } - const auto locationPath = pTrack->getFileInfo().directory(); - if (!locationPath.isEmpty()) { - const auto locationPathText = - mixxx::escapeTextPropertyWithoutShortcuts(locationPath); - m_pSearchRelatedMenu->addAction( - tr("Folder \"%1\"") - .arg(locationPathText), - [this, locationPath]() { - m_pLibrary->searchTracksInCollection( - QStringLiteral("location:\"") + - locationPath + QChar('"')); - }); + if (pTrack) { + m_pSearchRelatedMenu->addActionsForTrack(*pTrack); } m_pSearchRelatedMenu->setEnabled( !m_pSearchRelatedMenu->isEmpty()); }); + connect(m_pSearchRelatedMenu, + &WSearchRelatedTracksMenu::triggerSearch, + [this](const QString& searchQuery) { + m_pLibrary->searchTracksInCollection(searchQuery); + }); } } diff --git a/src/widget/wtrackmenu.h b/src/widget/wtrackmenu.h index 1a1673073834..1234627bde71 100644 --- a/src/widget/wtrackmenu.h +++ b/src/widget/wtrackmenu.h @@ -21,6 +21,7 @@ class Library; class TrackModel; class WColorPickerAction; class WCoverArtMenu; +class WSearchRelatedTracksMenu; /// A context menu for track(s). /// Can be used with individual track type widgets based on TrackPointer @@ -198,7 +199,7 @@ class WTrackMenu : public QMenu { QMenu* m_pBPMMenu{}; QMenu* m_pColorMenu{}; WCoverArtMenu* m_pCoverMenu{}; - parented_ptr m_pSearchRelatedMenu; + parented_ptr m_pSearchRelatedMenu; // Reload Track Metadata Action: QAction* m_pImportMetadataFromFileAct{}; From a1e6689e8ee833c946fec56c24a011b0fb3f8408 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sun, 18 Oct 2020 14:26:13 +0200 Subject: [PATCH 10/19] Add missing receiver context for signal connection via functor --- src/widget/wtrackmenu.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 5b1f9c320ce0..20a238c530a9 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -160,6 +160,7 @@ void WTrackMenu::createMenus() { }); connect(m_pSearchRelatedMenu, &WSearchRelatedTracksMenu::triggerSearch, + this, [this](const QString& searchQuery) { m_pLibrary->searchTracksInCollection(searchQuery); }); From b4ea49723c00e7956931e1ccbd3b3ecb37c17abf Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sun, 18 Oct 2020 20:10:05 +0200 Subject: [PATCH 11/19] Delete obsolete TODO comment --- src/widget/wtrackmenu.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 20a238c530a9..318558d2a0a1 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -142,7 +142,6 @@ void WTrackMenu::createMenus() { } if (featureIsEnabled(Feature::SearchRelated)) { - // TODO: Create a new subclass of QMenu? DEBUG_ASSERT(!m_pSearchRelatedMenu); m_pSearchRelatedMenu = make_parented(this); From 15f4eb6b0fa177c62b9d43c6320894f806817a2a Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sun, 18 Oct 2020 20:28:13 +0200 Subject: [PATCH 12/19] Search for tracks with similar bpm +/-6% --- src/widget/wsearchrelatedtracksmenu.cpp | 32 ++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/widget/wsearchrelatedtracksmenu.cpp b/src/widget/wsearchrelatedtracksmenu.cpp index 8286fdf64212..0399229bf037 100644 --- a/src/widget/wsearchrelatedtracksmenu.cpp +++ b/src/widget/wsearchrelatedtracksmenu.cpp @@ -3,6 +3,20 @@ #include "track/track.h" #include "util/qt.h" +namespace { + +constexpr double kRelativeBpmRange = 0.06; // +/-6 % + +inline int bpmLowerBound(double bpm) { + return static_cast(std::floor((1 - kRelativeBpmRange) * bpm)); +} + +inline int bpmUpperBound(double bpm) { + return static_cast(std::ceil((1 + kRelativeBpmRange) * bpm)); +} + +} // namespace + WSearchRelatedTracksMenu::WSearchRelatedTracksMenu( QWidget* parent) : QMenu(tr("Search related Tracks"), parent) { @@ -13,6 +27,22 @@ void WSearchRelatedTracksMenu::addActionsForTrack( bool addSeparator = false; // Musical property actions + const auto bpm = track.getBpm(); + if (bpm > 0) { + auto minBpmNumber = QString::number(bpmLowerBound(bpm)); + auto maxBpmNumber = QString::number(bpmUpperBound(bpm)); + addSeparator = addSeparatorBeforeAction(addSeparator); + addAction( + tr("Tempo between %1 and %2 bpm") + .arg(minBpmNumber, maxBpmNumber), + [this, minBpmNumber, maxBpmNumber]() { + emit triggerSearch( + QStringLiteral("bpm:>=") + + minBpmNumber + + QStringLiteral(" bpm:<=") + + maxBpmNumber); + }); + } const auto keyText = track.getKeyText(); if (!keyText.isEmpty()) { const auto keyTextDisplay = @@ -125,7 +155,7 @@ void WSearchRelatedTracksMenu::addActionsForTrack( }); } - // Title actions + // Release actions addSeparator = true; const auto title = track.getTitle(); if (!title.isEmpty()) { From d4660d2de6d2c47a20fe262f99a05063a457ee52 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Mon, 19 Oct 2020 13:32:23 +0200 Subject: [PATCH 13/19] WSearchRelatedTracksMenu: Add member function for adding actions --- src/widget/wsearchrelatedtracksmenu.cpp | 353 +++++++++++++----------- src/widget/wsearchrelatedtracksmenu.h | 12 +- 2 files changed, 195 insertions(+), 170 deletions(-) diff --git a/src/widget/wsearchrelatedtracksmenu.cpp b/src/widget/wsearchrelatedtracksmenu.cpp index 0399229bf037..da8b05994523 100644 --- a/src/widget/wsearchrelatedtracksmenu.cpp +++ b/src/widget/wsearchrelatedtracksmenu.cpp @@ -22,188 +22,217 @@ WSearchRelatedTracksMenu::WSearchRelatedTracksMenu( : QMenu(tr("Search related Tracks"), parent) { } +bool WSearchRelatedTracksMenu::addTriggerSearchAction( + bool addSeparatorBeforeAction, + const QString& actionText, + QString /*!by-value-because-captured-by-lambda!*/ searchQuery) { + if (addSeparatorBeforeAction) { + addSeparator(); + } + addAction( + mixxx::escapeTextPropertyWithoutShortcuts(actionText), + [this, searchQuery]() { + emit triggerSearch(searchQuery); + }); + return false; +} + void WSearchRelatedTracksMenu::addActionsForTrack( const Track& track) { - bool addSeparator = false; + bool addSeparatorBeforeAction = false; + + // NOTE: We have to explicitly use `QString` instead of `auto` + // when composing search queries using `QStringBuilder`. Otherwise + // string concatenation will fail at runtime! // Musical property actions - const auto bpm = track.getBpm(); - if (bpm > 0) { - auto minBpmNumber = QString::number(bpmLowerBound(bpm)); - auto maxBpmNumber = QString::number(bpmUpperBound(bpm)); - addSeparator = addSeparatorBeforeAction(addSeparator); - addAction( - tr("Tempo between %1 and %2 bpm") - .arg(minBpmNumber, maxBpmNumber), - [this, minBpmNumber, maxBpmNumber]() { - emit triggerSearch( - QStringLiteral("bpm:>=") + - minBpmNumber + - QStringLiteral(" bpm:<=") + - maxBpmNumber); - }); + { + const auto bpm = track.getBpm(); + if (bpm > 0) { + const auto minBpmNumber = QString::number(bpmLowerBound(bpm)); + const auto maxBpmNumber = QString::number(bpmUpperBound(bpm)); + const auto actionText = + tr("Tempo between %1 and %2 bpm").arg(minBpmNumber, maxBpmNumber); + const QString searchQuery = + QStringLiteral("bpm:>=") + + minBpmNumber + + QStringLiteral(" bpm:<=") + + maxBpmNumber; + addSeparatorBeforeAction = addTriggerSearchAction( + addSeparatorBeforeAction, + actionText, + searchQuery); + } } - const auto keyText = track.getKeyText(); - if (!keyText.isEmpty()) { - const auto keyTextDisplay = - mixxx::escapeTextPropertyWithoutShortcuts(keyText); - addSeparator = addSeparatorBeforeAction(addSeparator); - addAction( - tr("Harmonic keys for \"%1\"") - .arg(keyTextDisplay), - [this, keyText]() { - emit triggerSearch( - QStringLiteral("~key:\"") + - keyText + QChar('"')); - }); + { + const auto keyText = track.getKeyText(); + if (!keyText.isEmpty()) { + const auto actionText = + tr("Harmonic keys for \"%1\"").arg(keyText); + const QString searchQuery = + QStringLiteral("~key:\"") + + keyText + + QChar('"'); + addSeparatorBeforeAction = addTriggerSearchAction( + addSeparatorBeforeAction, + actionText, + searchQuery); + } } - const auto genre = track.getGenre(); - if (!genre.isEmpty()) { - const auto genreDisplay = - mixxx::escapeTextPropertyWithoutShortcuts(genre); - addSeparator = addSeparatorBeforeAction(addSeparator); - addAction( - tr("Genre \"%1\"") - .arg(genreDisplay), - [this, genre]() { - emit triggerSearch( - QStringLiteral("genre:\"") + - genre + QChar('"')); - }); + { + const auto genre = track.getGenre(); + if (!genre.isEmpty()) { + const auto actionText = + tr("Genre \"%1\"").arg(genre); + const QString searchQuery = + QStringLiteral("genre:\"") + + genre + + QChar('"'); + addSeparatorBeforeAction = addTriggerSearchAction( + addSeparatorBeforeAction, + actionText, + searchQuery); + } } // Artist actions - addSeparator = true; - auto primaryArtist = track.getArtist(); - auto secondaryArtist = track.getAlbumArtist(); - if (primaryArtist.isEmpty()) { - primaryArtist = secondaryArtist; - secondaryArtist = QString(); - } else { - if (!secondaryArtist.isEmpty() && - primaryArtist.contains(secondaryArtist)) { - // Use the shorter string as primary artist and the - // longer string as secondary artist - if (primaryArtist == secondaryArtist) { - secondaryArtist = QString(); - } else { - std::swap(primaryArtist, secondaryArtist); + addSeparatorBeforeAction = true; + { + auto primaryArtist = track.getArtist(); + auto secondaryArtist = track.getAlbumArtist(); + if (primaryArtist.isEmpty()) { + primaryArtist = secondaryArtist; + secondaryArtist = QString(); + } else { + if (!secondaryArtist.isEmpty() && + primaryArtist.contains(secondaryArtist)) { + // Use the shorter string as primary artist and the + // longer string as secondary artist + if (primaryArtist == secondaryArtist) { + secondaryArtist = QString(); + } else { + std::swap(primaryArtist, secondaryArtist); + } } } - } - DEBUG_ASSERT(!primaryArtist.isEmpty() || secondaryArtist.isEmpty()); - if (!primaryArtist.isEmpty()) { - const auto primaryArtistDisplay = - mixxx::escapeTextPropertyWithoutShortcuts(primaryArtist); - const auto secondaryArtistDisplay = - mixxx::escapeTextPropertyWithoutShortcuts(secondaryArtist); - // Search tracks with similar artist(s) - addSeparator = addSeparatorBeforeAction(addSeparator); - addAction( - tr("Artist \"%1\"") - .arg(primaryArtistDisplay), - [this, primaryArtist]() { - emit triggerSearch( - QStringLiteral("artist:\"") + - primaryArtist + QChar('"')); - }); - if (!secondaryArtist.isEmpty()) { - addSeparator = addSeparatorBeforeAction(addSeparator); - addAction( - tr("Artist \"%1\"") - .arg(secondaryArtistDisplay), - [this, secondaryArtist]() { - emit triggerSearch( - QStringLiteral("artist:\"") + - secondaryArtist + QChar('"')); - }); - } - addSeparator = addSeparatorBeforeAction(addSeparator); - addAction( - tr("Album artist \"%1\"") - .arg(primaryArtistDisplay), - [this, primaryArtist]() { - emit triggerSearch( - QStringLiteral("album_artist:\"") + - primaryArtist + QChar('"')); - }); - if (!secondaryArtist.isEmpty()) { - addSeparator = addSeparatorBeforeAction(addSeparator); - addAction( - tr("Album artist \"%1\"") - .arg(secondaryArtistDisplay), - [this, secondaryArtist]() { - emit triggerSearch( - QStringLiteral( - "album_artist:\"") + - secondaryArtist + QChar('"')); - }); + DEBUG_ASSERT(!primaryArtist.isEmpty() || secondaryArtist.isEmpty()); + if (!primaryArtist.isEmpty()) { + // Search tracks with similar artist(s) + { + const auto actionText = + tr("Artist \"%1\"").arg(primaryArtist); + const QString searchQuery = + QStringLiteral("artist:\"") + + primaryArtist + + QChar('"'); + addSeparatorBeforeAction = addTriggerSearchAction( + addSeparatorBeforeAction, + actionText, + searchQuery); + } + if (!secondaryArtist.isEmpty()) { + const auto actionText = + tr("Artist \"%1\"").arg(secondaryArtist); + const QString searchQuery = + QStringLiteral("artist:\"") + + secondaryArtist + + QChar('"'); + addSeparatorBeforeAction = addTriggerSearchAction( + addSeparatorBeforeAction, + actionText, + searchQuery); + } + { + const auto actionText = + tr("Album artist \"%1\"").arg(primaryArtist); + const QString searchQuery = + QStringLiteral("album_artist:\"") + + primaryArtist + + QChar('"'); + addSeparatorBeforeAction = addTriggerSearchAction( + addSeparatorBeforeAction, + actionText, + searchQuery); + } + if (!secondaryArtist.isEmpty()) { + const auto actionText = + tr("Album artist \"%1\"").arg(secondaryArtist); + const QString searchQuery = + QStringLiteral("album_artist:\"") + + secondaryArtist + + QChar('"'); + addSeparatorBeforeAction = addTriggerSearchAction( + addSeparatorBeforeAction, + actionText, + searchQuery); + } } } - const auto composer = track.getComposer(); - if (!composer.isEmpty()) { - const auto composerDisplay = - mixxx::escapeTextPropertyWithoutShortcuts(composer); - addSeparator = addSeparatorBeforeAction(addSeparator); - addAction( - tr("Composer \"%1\"") - .arg(composerDisplay), - [this, composer]() { - emit triggerSearch( - QStringLiteral("composer:\"") + - composer + QChar('"')); - }); + { + const auto composer = track.getComposer(); + if (!composer.isEmpty()) { + const auto actionText = + tr("Composer \"%1\"").arg(composer); + const QString searchQuery = + QStringLiteral("composer:\"") + + composer + + QChar('"'); + addSeparatorBeforeAction = addTriggerSearchAction( + addSeparatorBeforeAction, + actionText, + searchQuery); + } } // Release actions - addSeparator = true; - const auto title = track.getTitle(); - if (!title.isEmpty()) { - const auto titleDisplay = - mixxx::escapeTextPropertyWithoutShortcuts(title); - addSeparator = addSeparatorBeforeAction(addSeparator); - addAction( - tr("Title \"%1\"") - .arg(titleDisplay), - [this, title]() { - emit triggerSearch( - QStringLiteral("title:\"") + - title + QChar('"')); - }); + addSeparatorBeforeAction = true; + { + const auto title = track.getTitle(); + if (!title.isEmpty()) { + const auto actionText = + tr("Title \"%1\"").arg(title); + const QString searchQuery = + QStringLiteral("title:\"") + + title + + QChar('"'); + addSeparatorBeforeAction = addTriggerSearchAction( + addSeparatorBeforeAction, + actionText, + searchQuery); + } + } + { + const auto album = track.getAlbum(); + if (!album.isEmpty()) { + const auto actionText = + tr("Album \"%1\"").arg(album); + const QString searchQuery = + QStringLiteral("album:\"") + + album + + QChar('"'); + addSeparatorBeforeAction = addTriggerSearchAction( + addSeparatorBeforeAction, + actionText, + searchQuery); + } } - const auto album = track.getAlbum(); - if (!album.isEmpty()) { - const auto albumDisplay = - mixxx::escapeTextPropertyWithoutShortcuts(album); - addSeparator = addSeparatorBeforeAction(addSeparator); - addAction( - tr("Album \"%1\"") - .arg(albumDisplay), - [this, album]() { - emit triggerSearch( - QStringLiteral("album:\"") + - album + QChar('"')); - }); } // File system actions - addSeparator = true; - const auto locationPath = track.getFileInfo().directory(); - if (!locationPath.isEmpty()) { - const auto locationPathDisplay = - mixxx::escapeTextPropertyWithoutShortcuts(locationPath); - if (addSeparator) { - this->addSeparator(); - addSeparator = false; + addSeparatorBeforeAction = true; + { + const auto locationPath = track.getFileInfo().directory(); + if (!locationPath.isEmpty()) { + const auto actionText = + tr("Folder \"%1\"").arg(locationPath); + const QString searchQuery = + QStringLiteral("location:\"") + + locationPath + + QChar('"'); + addSeparatorBeforeAction = addTriggerSearchAction( + addSeparatorBeforeAction, + actionText, + searchQuery); } - addSeparator = addSeparatorBeforeAction(addSeparator); - addAction( - tr("Folder \"%1\"") - .arg(locationPathDisplay), - [this, locationPath]() { - emit triggerSearch( - QStringLiteral("location:\"") + - locationPath + QChar('"')); - }); } } diff --git a/src/widget/wsearchrelatedtracksmenu.h b/src/widget/wsearchrelatedtracksmenu.h index 99c8f1839949..853badbf579a 100644 --- a/src/widget/wsearchrelatedtracksmenu.h +++ b/src/widget/wsearchrelatedtracksmenu.h @@ -19,12 +19,8 @@ class WSearchRelatedTracksMenu : public QMenu { const QString& searchQuery); private: - bool addSeparatorBeforeAction( - bool addSeparator) { - if (addSeparator) { - this->addSeparator(); - } - // Reset flag - return false; - } + bool addTriggerSearchAction( + bool addSeparatorBeforeAction, + const QString& actionText, + QString searchQuery); }; From b3f8eadb68a092e1a556abc64e07f925ca310b64 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Mon, 19 Oct 2020 13:32:46 +0200 Subject: [PATCH 14/19] WSearchRelatedTracksMenu: Search for grouping and (release) year --- src/widget/wsearchrelatedtracksmenu.cpp | 54 +++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/widget/wsearchrelatedtracksmenu.cpp b/src/widget/wsearchrelatedtracksmenu.cpp index da8b05994523..1907573b8954 100644 --- a/src/widget/wsearchrelatedtracksmenu.cpp +++ b/src/widget/wsearchrelatedtracksmenu.cpp @@ -15,6 +15,31 @@ inline int bpmUpperBound(double bpm) { return static_cast(std::ceil((1 + kRelativeBpmRange) * bpm)); } +QString extractCalendarYearNumberFromReleaseDate( + const QString& releaseDate) { + // TODO: Improve this poor calendar year number parser + // and extract the code + int skippedLeadingZeros = 0; + int countedLeadingDigits = 0; + const auto trimmed = releaseDate.trimmed(); + // Count leading digits + for (int i = 0; i < trimmed.size(); ++i) { + if (!trimmed[i].isDigit()) { + break; + } + // Skip leading zeros + if (countedLeadingDigits == 0 && trimmed[i] == QChar('0')) { + ++skippedLeadingZeros; + continue; + } + // Count leading digits + ++countedLeadingDigits; + } + // Interpret the leading digits as the calendar year + // without any further validation + return trimmed.mid(skippedLeadingZeros, countedLeadingDigits); +} + } // namespace WSearchRelatedTracksMenu::WSearchRelatedTracksMenu( @@ -216,6 +241,35 @@ void WSearchRelatedTracksMenu::addActionsForTrack( searchQuery); } } + { + const auto grouping = track.getGrouping(); + if (!grouping.isEmpty()) { + const auto actionText = + tr("Grouping \"%1\"").arg(grouping); + const QString searchQuery = + QStringLiteral("grouping:\"") + + grouping + + QChar('"'); + addSeparatorBeforeAction = addTriggerSearchAction( + addSeparatorBeforeAction, + actionText, + searchQuery); + } + } + { + const auto releaseYearNumber = + extractCalendarYearNumberFromReleaseDate(track.getYear()); + if (!releaseYearNumber.isEmpty()) { + const auto actionText = + tr("Release year %1").arg(releaseYearNumber); + const QString searchQuery = + QStringLiteral("year:") + + releaseYearNumber; + addSeparatorBeforeAction = addTriggerSearchAction( + addSeparatorBeforeAction, + actionText, + searchQuery); + } } // File system actions From 57d80c6c4e0dc72bd678d5635a0f330522e424b0 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Tue, 20 Oct 2020 00:08:04 +0200 Subject: [PATCH 15/19] WSearchRelatedTracksMenu: Reorder and relabel menu entries --- src/widget/wsearchrelatedtracksmenu.cpp | 165 ++++++++++++------------ src/widget/wsearchrelatedtracksmenu.h | 2 +- 2 files changed, 81 insertions(+), 86 deletions(-) diff --git a/src/widget/wsearchrelatedtracksmenu.cpp b/src/widget/wsearchrelatedtracksmenu.cpp index 1907573b8954..8dcc0ea096d3 100644 --- a/src/widget/wsearchrelatedtracksmenu.cpp +++ b/src/widget/wsearchrelatedtracksmenu.cpp @@ -48,10 +48,10 @@ WSearchRelatedTracksMenu::WSearchRelatedTracksMenu( } bool WSearchRelatedTracksMenu::addTriggerSearchAction( - bool addSeparatorBeforeAction, + bool addSeparatorBeforeNextAction, const QString& actionText, QString /*!by-value-because-captured-by-lambda!*/ searchQuery) { - if (addSeparatorBeforeAction) { + if (addSeparatorBeforeNextAction) { addSeparator(); } addAction( @@ -64,64 +64,77 @@ bool WSearchRelatedTracksMenu::addTriggerSearchAction( void WSearchRelatedTracksMenu::addActionsForTrack( const Track& track) { - bool addSeparatorBeforeAction = false; - // NOTE: We have to explicitly use `QString` instead of `auto` // when composing search queries using `QStringBuilder`. Otherwise // string concatenation will fail at runtime! - // Musical property actions + // Mixing actions + bool addSeparatorBeforeNextAction = !isEmpty(); + { + const auto keyText = track.getKeyText(); + if (!keyText.isEmpty()) { + const auto actionText = + tr("Key: Harmonic with %1").arg(keyText); + const QString searchQuery = + QStringLiteral("~key:") + + keyText; + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, + actionText, + searchQuery); + } + } { const auto bpm = track.getBpm(); if (bpm > 0) { const auto minBpmNumber = QString::number(bpmLowerBound(bpm)); const auto maxBpmNumber = QString::number(bpmUpperBound(bpm)); const auto actionText = - tr("Tempo between %1 and %2 bpm").arg(minBpmNumber, maxBpmNumber); + tr("BPM: Between %1 and %2").arg(minBpmNumber, maxBpmNumber); const QString searchQuery = QStringLiteral("bpm:>=") + minBpmNumber + QStringLiteral(" bpm:<=") + maxBpmNumber; - addSeparatorBeforeAction = addTriggerSearchAction( - addSeparatorBeforeAction, + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, actionText, searchQuery); } } + + // Artist/Title actions + addSeparatorBeforeNextAction = !isEmpty(); { - const auto keyText = track.getKeyText(); - if (!keyText.isEmpty()) { + const auto title = track.getTitle(); + if (!title.isEmpty()) { const auto actionText = - tr("Harmonic keys for \"%1\"").arg(keyText); + tr("Title: \"%1\"").arg(title); const QString searchQuery = - QStringLiteral("~key:\"") + - keyText + + QStringLiteral("title:\"") + + title + QChar('"'); - addSeparatorBeforeAction = addTriggerSearchAction( - addSeparatorBeforeAction, + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, actionText, searchQuery); } } { - const auto genre = track.getGenre(); - if (!genre.isEmpty()) { + const auto album = track.getAlbum(); + if (!album.isEmpty()) { const auto actionText = - tr("Genre \"%1\"").arg(genre); + tr("Album: \"%1\"").arg(album); const QString searchQuery = - QStringLiteral("genre:\"") + - genre + + QStringLiteral("album:\"") + + album + QChar('"'); - addSeparatorBeforeAction = addTriggerSearchAction( - addSeparatorBeforeAction, + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, actionText, searchQuery); } } - - // Artist actions - addSeparatorBeforeAction = true; { auto primaryArtist = track.getArtist(); auto secondaryArtist = track.getAlbumArtist(); @@ -145,49 +158,49 @@ void WSearchRelatedTracksMenu::addActionsForTrack( // Search tracks with similar artist(s) { const auto actionText = - tr("Artist \"%1\"").arg(primaryArtist); + tr("Artist: \"%1\"").arg(primaryArtist); const QString searchQuery = QStringLiteral("artist:\"") + primaryArtist + QChar('"'); - addSeparatorBeforeAction = addTriggerSearchAction( - addSeparatorBeforeAction, + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, actionText, searchQuery); } if (!secondaryArtist.isEmpty()) { const auto actionText = - tr("Artist \"%1\"").arg(secondaryArtist); + tr("Artist: \"%1\"").arg(secondaryArtist); const QString searchQuery = QStringLiteral("artist:\"") + secondaryArtist + QChar('"'); - addSeparatorBeforeAction = addTriggerSearchAction( - addSeparatorBeforeAction, + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, actionText, searchQuery); } { const auto actionText = - tr("Album artist \"%1\"").arg(primaryArtist); + tr("Album Artist: \"%1\"").arg(primaryArtist); const QString searchQuery = QStringLiteral("album_artist:\"") + primaryArtist + QChar('"'); - addSeparatorBeforeAction = addTriggerSearchAction( - addSeparatorBeforeAction, + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, actionText, searchQuery); } if (!secondaryArtist.isEmpty()) { const auto actionText = - tr("Album artist \"%1\"").arg(secondaryArtist); + tr("Album Artist: \"%1\"").arg(secondaryArtist); const QString searchQuery = QStringLiteral("album_artist:\"") + secondaryArtist + QChar('"'); - addSeparatorBeforeAction = addTriggerSearchAction( - addSeparatorBeforeAction, + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -197,46 +210,13 @@ void WSearchRelatedTracksMenu::addActionsForTrack( const auto composer = track.getComposer(); if (!composer.isEmpty()) { const auto actionText = - tr("Composer \"%1\"").arg(composer); + tr("Composer: \"%1\"").arg(composer); const QString searchQuery = QStringLiteral("composer:\"") + composer + QChar('"'); - addSeparatorBeforeAction = addTriggerSearchAction( - addSeparatorBeforeAction, - actionText, - searchQuery); - } - } - - // Release actions - addSeparatorBeforeAction = true; - { - const auto title = track.getTitle(); - if (!title.isEmpty()) { - const auto actionText = - tr("Title \"%1\"").arg(title); - const QString searchQuery = - QStringLiteral("title:\"") + - title + - QChar('"'); - addSeparatorBeforeAction = addTriggerSearchAction( - addSeparatorBeforeAction, - actionText, - searchQuery); - } - } - { - const auto album = track.getAlbum(); - if (!album.isEmpty()) { - const auto actionText = - tr("Album \"%1\"").arg(album); - const QString searchQuery = - QStringLiteral("album:\"") + - album + - QChar('"'); - addSeparatorBeforeAction = addTriggerSearchAction( - addSeparatorBeforeAction, + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -245,46 +225,61 @@ void WSearchRelatedTracksMenu::addActionsForTrack( const auto grouping = track.getGrouping(); if (!grouping.isEmpty()) { const auto actionText = - tr("Grouping \"%1\"").arg(grouping); + tr("Grouping: \"%1\"").arg(grouping); const QString searchQuery = QStringLiteral("grouping:\"") + grouping + QChar('"'); - addSeparatorBeforeAction = addTriggerSearchAction( - addSeparatorBeforeAction, + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, actionText, searchQuery); } } + + // Other actions + addSeparatorBeforeNextAction = !isEmpty(); { const auto releaseYearNumber = extractCalendarYearNumberFromReleaseDate(track.getYear()); if (!releaseYearNumber.isEmpty()) { const auto actionText = - tr("Release year %1").arg(releaseYearNumber); + tr("Year: %1").arg(releaseYearNumber); const QString searchQuery = QStringLiteral("year:") + releaseYearNumber; - addSeparatorBeforeAction = addTriggerSearchAction( - addSeparatorBeforeAction, + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, + actionText, + searchQuery); + } + } + { + const auto genre = track.getGenre(); + if (!genre.isEmpty()) { + const auto actionText = + tr("Genre: \"%1\"").arg(genre); + const QString searchQuery = + QStringLiteral("genre:\"") + + genre + + QChar('"'); + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, actionText, searchQuery); } } - - // File system actions - addSeparatorBeforeAction = true; { const auto locationPath = track.getFileInfo().directory(); if (!locationPath.isEmpty()) { const auto actionText = - tr("Folder \"%1\"").arg(locationPath); + tr("Folder: \"%1\"").arg(locationPath); const QString searchQuery = QStringLiteral("location:\"") + locationPath + QChar('"'); - addSeparatorBeforeAction = addTriggerSearchAction( - addSeparatorBeforeAction, + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, actionText, searchQuery); } diff --git a/src/widget/wsearchrelatedtracksmenu.h b/src/widget/wsearchrelatedtracksmenu.h index 853badbf579a..e8a8af469d6c 100644 --- a/src/widget/wsearchrelatedtracksmenu.h +++ b/src/widget/wsearchrelatedtracksmenu.h @@ -20,7 +20,7 @@ class WSearchRelatedTracksMenu : public QMenu { private: bool addTriggerSearchAction( - bool addSeparatorBeforeAction, + bool addSeparatorBeforeNextAction, const QString& actionText, QString searchQuery); }; From 1f0d13a0864ffe3df7d28b8a3809733440b27653 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Tue, 20 Oct 2020 13:16:30 +0200 Subject: [PATCH 16/19] WTrackMenu: Use const reference --- src/widget/wtrackmenu.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index 318558d2a0a1..984923003a4c 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -952,9 +952,9 @@ void WTrackMenu::slotPopulatePlaylistMenu() { return; } m_pPlaylistMenu->clear(); - PlaylistDAO& playlistDao = m_pLibrary->trackCollections() - ->internalCollection() - ->getPlaylistDAO(); + const PlaylistDAO& playlistDao = m_pLibrary->trackCollections() + ->internalCollection() + ->getPlaylistDAO(); QMap playlists; int numPlaylists = playlistDao.playlistCount(); for (int i = 0; i < numPlaylists; ++i) { From 897ed465a4464053645710418cd481d47855911d Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Tue, 20 Oct 2020 16:00:38 +0200 Subject: [PATCH 17/19] WSearchRelatedTracksMenu: Re-add missing quotes for key search --- src/widget/wsearchrelatedtracksmenu.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/widget/wsearchrelatedtracksmenu.cpp b/src/widget/wsearchrelatedtracksmenu.cpp index 8dcc0ea096d3..818706fd5da1 100644 --- a/src/widget/wsearchrelatedtracksmenu.cpp +++ b/src/widget/wsearchrelatedtracksmenu.cpp @@ -74,10 +74,11 @@ void WSearchRelatedTracksMenu::addActionsForTrack( const auto keyText = track.getKeyText(); if (!keyText.isEmpty()) { const auto actionText = - tr("Key: Harmonic with %1").arg(keyText); + tr("Key: Harmonic with \"%1\"").arg(keyText); const QString searchQuery = - QStringLiteral("~key:") + - keyText; + QStringLiteral("~key:\"") + + keyText + + QChar('"'); addSeparatorBeforeNextAction = addTriggerSearchAction( addSeparatorBeforeNextAction, actionText, From c6eae53e5d541fae47af821d4b1b6dad54c3ba0f Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Tue, 20 Oct 2020 16:22:22 +0200 Subject: [PATCH 18/19] WSearchRelatedTracksMenu: Split artists from title/grouping actions --- src/widget/wsearchrelatedtracksmenu.cpp | 65 +++++++++++++------------ 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/src/widget/wsearchrelatedtracksmenu.cpp b/src/widget/wsearchrelatedtracksmenu.cpp index 818706fd5da1..b77f4bf96c57 100644 --- a/src/widget/wsearchrelatedtracksmenu.cpp +++ b/src/widget/wsearchrelatedtracksmenu.cpp @@ -104,38 +104,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( } } - // Artist/Title actions + // Artist actions addSeparatorBeforeNextAction = !isEmpty(); - { - const auto title = track.getTitle(); - if (!title.isEmpty()) { - const auto actionText = - tr("Title: \"%1\"").arg(title); - const QString searchQuery = - QStringLiteral("title:\"") + - title + - QChar('"'); - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, - actionText, - searchQuery); - } - } - { - const auto album = track.getAlbum(); - if (!album.isEmpty()) { - const auto actionText = - tr("Album: \"%1\"").arg(album); - const QString searchQuery = - QStringLiteral("album:\"") + - album + - QChar('"'); - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, - actionText, - searchQuery); - } - } { auto primaryArtist = track.getArtist(); auto secondaryArtist = track.getAlbumArtist(); @@ -222,6 +192,39 @@ void WSearchRelatedTracksMenu::addActionsForTrack( searchQuery); } } + + // Title and grouping actions + addSeparatorBeforeNextAction = !isEmpty(); + { + const auto title = track.getTitle(); + if (!title.isEmpty()) { + const auto actionText = + tr("Title: \"%1\"").arg(title); + const QString searchQuery = + QStringLiteral("title:\"") + + title + + QChar('"'); + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, + actionText, + searchQuery); + } + } + { + const auto album = track.getAlbum(); + if (!album.isEmpty()) { + const auto actionText = + tr("Album: \"%1\"").arg(album); + const QString searchQuery = + QStringLiteral("album:\"") + + album + + QChar('"'); + addSeparatorBeforeNextAction = addTriggerSearchAction( + addSeparatorBeforeNextAction, + actionText, + searchQuery); + } + } { const auto grouping = track.getGrouping(); if (!grouping.isEmpty()) { From da79a1e04c50948b4409cbb3e870e343a91a4697 Mon Sep 17 00:00:00 2001 From: Uwe Klotz Date: Sat, 24 Oct 2020 21:41:19 +0200 Subject: [PATCH 19/19] WSearchRelatedTracksMenu: Use an in/out parameter --- src/widget/wsearchrelatedtracksmenu.cpp | 62 +++++++++++++------------ src/widget/wsearchrelatedtracksmenu.h | 4 +- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/widget/wsearchrelatedtracksmenu.cpp b/src/widget/wsearchrelatedtracksmenu.cpp index b77f4bf96c57..51d3603b574c 100644 --- a/src/widget/wsearchrelatedtracksmenu.cpp +++ b/src/widget/wsearchrelatedtracksmenu.cpp @@ -47,19 +47,21 @@ WSearchRelatedTracksMenu::WSearchRelatedTracksMenu( : QMenu(tr("Search related Tracks"), parent) { } -bool WSearchRelatedTracksMenu::addTriggerSearchAction( - bool addSeparatorBeforeNextAction, +void WSearchRelatedTracksMenu::addTriggerSearchAction( + bool* /*in/out*/ pAddSeparatorBeforeNextAction, const QString& actionText, QString /*!by-value-because-captured-by-lambda!*/ searchQuery) { - if (addSeparatorBeforeNextAction) { + DEBUG_ASSERT(pAddSeparatorBeforeNextAction); + if (*pAddSeparatorBeforeNextAction) { addSeparator(); } + // Reset the flag before adding the next action + *pAddSeparatorBeforeNextAction = false; addAction( mixxx::escapeTextPropertyWithoutShortcuts(actionText), [this, searchQuery]() { emit triggerSearch(searchQuery); }); - return false; } void WSearchRelatedTracksMenu::addActionsForTrack( @@ -79,8 +81,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( QStringLiteral("~key:\"") + keyText + QChar('"'); - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, + addTriggerSearchAction( + &addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -97,8 +99,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( minBpmNumber + QStringLiteral(" bpm:<=") + maxBpmNumber; - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, + addTriggerSearchAction( + &addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -134,8 +136,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( QStringLiteral("artist:\"") + primaryArtist + QChar('"'); - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, + addTriggerSearchAction( + &addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -146,8 +148,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( QStringLiteral("artist:\"") + secondaryArtist + QChar('"'); - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, + addTriggerSearchAction( + &addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -158,8 +160,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( QStringLiteral("album_artist:\"") + primaryArtist + QChar('"'); - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, + addTriggerSearchAction( + &addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -170,8 +172,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( QStringLiteral("album_artist:\"") + secondaryArtist + QChar('"'); - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, + addTriggerSearchAction( + &addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -186,8 +188,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( QStringLiteral("composer:\"") + composer + QChar('"'); - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, + addTriggerSearchAction( + &addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -204,8 +206,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( QStringLiteral("title:\"") + title + QChar('"'); - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, + addTriggerSearchAction( + &addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -219,8 +221,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( QStringLiteral("album:\"") + album + QChar('"'); - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, + addTriggerSearchAction( + &addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -234,8 +236,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( QStringLiteral("grouping:\"") + grouping + QChar('"'); - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, + addTriggerSearchAction( + &addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -252,8 +254,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( const QString searchQuery = QStringLiteral("year:") + releaseYearNumber; - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, + addTriggerSearchAction( + &addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -267,8 +269,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( QStringLiteral("genre:\"") + genre + QChar('"'); - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, + addTriggerSearchAction( + &addSeparatorBeforeNextAction, actionText, searchQuery); } @@ -282,8 +284,8 @@ void WSearchRelatedTracksMenu::addActionsForTrack( QStringLiteral("location:\"") + locationPath + QChar('"'); - addSeparatorBeforeNextAction = addTriggerSearchAction( - addSeparatorBeforeNextAction, + addTriggerSearchAction( + &addSeparatorBeforeNextAction, actionText, searchQuery); } diff --git a/src/widget/wsearchrelatedtracksmenu.h b/src/widget/wsearchrelatedtracksmenu.h index e8a8af469d6c..dcd8fb178666 100644 --- a/src/widget/wsearchrelatedtracksmenu.h +++ b/src/widget/wsearchrelatedtracksmenu.h @@ -19,8 +19,8 @@ class WSearchRelatedTracksMenu : public QMenu { const QString& searchQuery); private: - bool addTriggerSearchAction( - bool addSeparatorBeforeNextAction, + void addTriggerSearchAction( + bool* /*in/out*/ pAddSeparatorBeforeNextAction, const QString& actionText, QString searchQuery); };