From d57ffbdb09c5eadbae311ec2fbeb31a020337023 Mon Sep 17 00:00:00 2001 From: Keith Edmunds Date: Mon, 16 Oct 2023 23:16:56 +0100 Subject: [PATCH] Implement select duplicate rows Fixes #157 --- app/musicmuster.py | 28 ++++++++++++++++++++++++++++ app/playlists.py | 15 +++++++++++++++ app/ui/main_window.ui | 7 +++++++ app/ui/main_window_ui.py | 7 ++++++- 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/app/musicmuster.py b/app/musicmuster.py index 19bfabd..49bee91 100755 --- a/app/musicmuster.py +++ b/app/musicmuster.py @@ -22,6 +22,8 @@ from typing import ( Sequence, ) +from sqlalchemy import text + from PyQt6.QtCore import ( pyqtSignal, QDate, @@ -668,6 +670,7 @@ class Window(QMainWindow, Ui_MainWindow): lambda: self.tabPlaylist.currentWidget().lookup_row_in_wikipedia() ) self.actionSearch.triggered.connect(self.search_playlist) + self.actionSelect_duplicate_rows.triggered.connect(self.select_duplicate_rows) self.actionSelect_next_track.triggered.connect(self.select_next_row) self.actionSelect_previous_track.triggered.connect(self.select_previous_row) self.actionMoveUnplayed.triggered.connect(self.move_unplayed) @@ -1487,6 +1490,31 @@ class Window(QMainWindow, Ui_MainWindow): self.visible_playlist_tab().set_search(self.txtSearch.text()) self.enable_play_next_controls() + def select_duplicate_rows(self) -> None: + """ + Select the last of any rows with duplicate tracks in current playlist. + This allows the selection to typically come towards the end of the playlist away + from any show specific sections. + If there a track is selected on three or more rows, only the last one is selected. + """ + + visible_playlist_id = self.visible_playlist_tab().playlist_id + # Get row number of duplicate rows + sql = text(f""" + SELECT max(plr_rownum) + FROM playlist_rows + WHERE playlist_id = {visible_playlist_id} + AND track_id != 0 + GROUP BY track_id + HAVING count(id) > 1 + """) + + with Session() as session: + row_numbers = [int(a) for a in session.execute(sql).scalars().all()] + if row_numbers: + self.visible_playlist_tab().select_rows(row_numbers) + self.statusbar.showMessage(f"{len(row_numbers)} duplicate rows selected", 10000) + def select_next_row(self) -> None: """Select next or first row in playlist""" diff --git a/app/playlists.py b/app/playlists.py index c75039f..a3aff53 100644 --- a/app/playlists.py +++ b/app/playlists.py @@ -979,6 +979,21 @@ class PlaylistTab(QTableWidget): self.selectRow(row_number) + def select_rows(self, rows: List[int]) -> None: + """ + Select rows that are passed + """ + + # Clear any selected rows to avoid confustion + self.clear_selection() + # We need to be in MultiSelection mode + self.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection) + # Select the rows + for row in rows: + self.selectRow(row) + # Reset selection mode + self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) + def tab_visible(self) -> None: """Called when tab becomes visible""" diff --git a/app/ui/main_window.ui b/app/ui/main_window.ui index 538a6d6..14a028a 100644 --- a/app/ui/main_window.ui +++ b/app/ui/main_window.ui @@ -746,6 +746,8 @@ padding-left: 8px; + + @@ -1132,6 +1134,11 @@ padding-left: 8px; Ctrl+S + + + Select duplicate rows... + + diff --git a/app/ui/main_window_ui.py b/app/ui/main_window_ui.py index 40adf63..4488a3e 100644 --- a/app/ui/main_window_ui.py +++ b/app/ui/main_window_ui.py @@ -1,6 +1,6 @@ # Form implementation generated from reading ui file 'app/ui/main_window.ui' # -# Created by: PyQt6 UI code generator 6.5.2 +# Created by: PyQt6 UI code generator 6.5.3 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -453,6 +453,8 @@ class Ui_MainWindow(object): self.actionSearch_title_in_Wikipedia.setObjectName("actionSearch_title_in_Wikipedia") self.actionSearch_title_in_Songfacts = QtGui.QAction(parent=MainWindow) self.actionSearch_title_in_Songfacts.setObjectName("actionSearch_title_in_Songfacts") + self.actionSelect_duplicate_rows = QtGui.QAction(parent=MainWindow) + self.actionSelect_duplicate_rows.setObjectName("actionSelect_duplicate_rows") self.menuFile.addAction(self.actionNewPlaylist) self.menuFile.addAction(self.actionNew_from_template) self.menuFile.addAction(self.actionOpenPlaylist) @@ -461,6 +463,8 @@ class Ui_MainWindow(object): self.menuFile.addAction(self.actionDeletePlaylist) self.menuFile.addAction(self.actionExport_playlist) self.menuFile.addSeparator() + self.menuFile.addAction(self.actionSelect_duplicate_rows) + self.menuFile.addSeparator() self.menuFile.addAction(self.actionMoveSelected) self.menuFile.addAction(self.actionMoveUnplayed) self.menuFile.addAction(self.actionDownload_CSV_of_played_tracks) @@ -595,5 +599,6 @@ class Ui_MainWindow(object): self.actionSearch_title_in_Wikipedia.setShortcut(_translate("MainWindow", "Ctrl+W")) self.actionSearch_title_in_Songfacts.setText(_translate("MainWindow", "Search title in Songfacts")) self.actionSearch_title_in_Songfacts.setShortcut(_translate("MainWindow", "Ctrl+S")) + self.actionSelect_duplicate_rows.setText(_translate("MainWindow", "Select duplicate rows...")) from infotabs import InfoTabs from pyqtgraph import PlotWidget