Move selected / move unplayed working
This commit is contained in:
parent
eff80d684e
commit
d5950ab29a
@ -556,29 +556,33 @@ class PlaylistRows(Base):
|
||||
return plrs
|
||||
|
||||
@staticmethod
|
||||
def move_to_playlist(session: Session,
|
||||
playlistrow_ids: List[int],
|
||||
destination_playlist_id: int) -> None:
|
||||
"""
|
||||
Move the list of playlistrow_ids to the end of destination_playlist
|
||||
"""
|
||||
def get_last_used_row(session: Session, playlist_id: int) -> Optional[int]:
|
||||
"""Return the last used row for playlist, or None if no rows"""
|
||||
|
||||
# Find last row of destination playlist
|
||||
last_row = session.execute(
|
||||
return session.execute(
|
||||
select(func.max(PlaylistRows.row_number))
|
||||
.where(PlaylistRows.playlist_id == destination_playlist_id)
|
||||
.where(PlaylistRows.playlist_id == playlist_id)
|
||||
).scalar_one()
|
||||
if last_row is None:
|
||||
last_row = 0
|
||||
|
||||
# Update the PlaylistRows entries
|
||||
for plr_id in playlistrow_ids:
|
||||
last_row += 1
|
||||
plr = session.get(PlaylistRows, plr_id)
|
||||
plr.row_number = last_row
|
||||
plr.playlist_id = destination_playlist_id
|
||||
@classmethod
|
||||
def get_unplayed_rows(cls, session: Session,
|
||||
playlist_id: int) -> List[int]:
|
||||
"""
|
||||
For passed playlist, return a list of track rows that
|
||||
have not been played.
|
||||
"""
|
||||
|
||||
session.commit()
|
||||
plrs = session.execute(
|
||||
select(cls)
|
||||
.where(
|
||||
cls.playlist_id == playlist_id,
|
||||
cls.track_id.is_not(None),
|
||||
cls.played.is_(False)
|
||||
)
|
||||
.order_by(cls.row_number)
|
||||
).scalars().all()
|
||||
|
||||
return plrs
|
||||
|
||||
# @classmethod
|
||||
# def get_playlist_rows(cls, playlist_id: int) -> \
|
||||
|
||||
@ -7,6 +7,7 @@ import sys
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
# from typing import Callable, Dict, List, Optional, Tuple
|
||||
from typing import List
|
||||
|
||||
from PyQt5.QtCore import QDate, QEvent, Qt, QTime, QTimer
|
||||
from PyQt5.QtGui import QColor
|
||||
@ -175,8 +176,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
# self.actionSelect_played_tracks.triggered.connect(self.select_played)
|
||||
self.actionSelect_previous_track.triggered.connect(
|
||||
self.select_previous_row)
|
||||
# self.actionSelect_unplayed_tracks.triggered.connect(
|
||||
# self.select_unplayed)
|
||||
self.actionMoveUnplayed.triggered.connect(self.move_unplayed)
|
||||
self.actionSetNext.triggered.connect(
|
||||
lambda: self.tabPlaylist.currentWidget().set_selected_as_next())
|
||||
self.actionSkipToNext.triggered.connect(self.play_next)
|
||||
@ -485,9 +485,10 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
self.create_playlist_tab(session, playlist)
|
||||
playlist.mark_open(session)
|
||||
|
||||
def move_selected(self) -> None:
|
||||
def move_playlist_rows(self, session: Session,
|
||||
playlistrows: List[PlaylistRows]) -> None:
|
||||
"""
|
||||
Move selected rows to another playlist
|
||||
Move passed playlist rows to another playlist
|
||||
|
||||
Actions required:
|
||||
- identify destination playlist
|
||||
@ -496,43 +497,74 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
- update destination playlist display if loaded
|
||||
"""
|
||||
|
||||
if not playlistrows:
|
||||
log.debug(f"musicmuster.move_playlist_rows({playlistrows=}")
|
||||
|
||||
# Identify destination playlist
|
||||
visible_tab = self.visible_playlist_tab()
|
||||
source_playlist = visible_tab.playlist_id
|
||||
playlists = []
|
||||
for playlist in Playlists.get_all(session):
|
||||
if playlist.id == source_playlist:
|
||||
continue
|
||||
else:
|
||||
playlists.append(playlist)
|
||||
|
||||
# Get destination playlist id
|
||||
dlg = SelectPlaylistDialog(self, playlists=playlists, session=session)
|
||||
dlg.exec()
|
||||
if not dlg.playlist:
|
||||
return
|
||||
destination_playlist_id = dlg.playlist.id
|
||||
|
||||
# Remove moved rows from display
|
||||
visible_tab.remove_rows([plr.row_number for plr in playlistrows])
|
||||
|
||||
# Update playlist for the rows in the database
|
||||
last_row = PlaylistRows.get_last_used_row(session,
|
||||
destination_playlist_id)
|
||||
if last_row is not None:
|
||||
next_row = last_row + 1
|
||||
else:
|
||||
next_row = 0
|
||||
|
||||
for plr in playlistrows:
|
||||
plr.row_number = next_row
|
||||
plr.playlist_id = destination_playlist_id
|
||||
# Reset played as it's not been played on this playlist
|
||||
plr.played = False
|
||||
|
||||
# Update destination playlist_tab if visible (if not visible, it
|
||||
# will be re-populated when it is opened)
|
||||
destionation_playlist_tab = None
|
||||
for tab in range(self.tabPlaylist.count()):
|
||||
if self.tabPlaylist.widget(tab).playlist_id == dlg.playlist.id:
|
||||
destionation_playlist_tab = self.tabPlaylist.widget(tab)
|
||||
break
|
||||
if destionation_playlist_tab:
|
||||
destionation_playlist_tab.populate(session, dlg.playlist.id)
|
||||
|
||||
def move_selected(self) -> None:
|
||||
"""
|
||||
Move selected rows to another playlist
|
||||
"""
|
||||
|
||||
with Session() as session:
|
||||
visible_tab = self.visible_playlist_tab()
|
||||
source_playlist = visible_tab.playlist_id
|
||||
playlists = []
|
||||
for playlist in Playlists.get_all(session):
|
||||
if playlist.id == source_playlist:
|
||||
continue
|
||||
else:
|
||||
playlists.append(playlist)
|
||||
|
||||
# Get destination playlist id
|
||||
dlg = SelectPlaylistDialog(self, playlists=playlists,
|
||||
session=session)
|
||||
dlg.exec()
|
||||
if not dlg.playlist:
|
||||
return
|
||||
destination_playlist = dlg.playlist
|
||||
|
||||
# Update playlist for the rows in the database
|
||||
plr_ids = visible_tab.get_selected_playlistrow_ids()
|
||||
PlaylistRows.move_to_playlist(
|
||||
session, plr_ids, destination_playlist.id
|
||||
self.move_playlist_rows(
|
||||
session,
|
||||
self.visible_playlist_tab().get_selected_playlistrows(session)
|
||||
)
|
||||
|
||||
# Remove moved rows from display
|
||||
visible_tab.remove_selected_rows()
|
||||
def move_unplayed(self) -> None:
|
||||
"""
|
||||
Move unplayed rows to another playlist
|
||||
"""
|
||||
|
||||
# Update destination playlist_tab if visible (if not visible, it
|
||||
# will be re-populated when it is opened)
|
||||
destionation_playlist_tab = None
|
||||
for tab in range(self.tabPlaylist.count()):
|
||||
if self.tabPlaylist.widget(tab).playlist_id == dlg.playlist.id:
|
||||
destionation_playlist_tab = self.tabPlaylist.widget(tab)
|
||||
break
|
||||
if destionation_playlist_tab:
|
||||
destionation_playlist_tab.populate(session, dlg.playlist.id)
|
||||
playlist_id = self.visible_playlist_tab().playlist_id
|
||||
with Session() as session:
|
||||
unplayed_playlist_rows = PlaylistRows.get_unplayed_rows(
|
||||
session, playlist_id)
|
||||
self.move_playlist_rows(session, unplayed_playlist_rows)
|
||||
|
||||
def play_next(self) -> None:
|
||||
"""
|
||||
@ -640,7 +672,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
"""Tidy up and reset search bar"""
|
||||
|
||||
# Clear the search text
|
||||
self.visible_playlist_tab().search("")
|
||||
self.visible_playlist_tab().set_search("")
|
||||
# Clean up search bar
|
||||
self.txtSearch.setText("")
|
||||
self.txtSearch.setHidden(True)
|
||||
@ -681,11 +713,6 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
"""Select previous or first row in playlist"""
|
||||
|
||||
self.visible_playlist_tab().select_previous_row()
|
||||
#
|
||||
# def select_unplayed(self) -> None:
|
||||
# """Select all unplayed tracks in playlist"""
|
||||
#
|
||||
# self.visible_playlist_tab().select_unplayed_tracks()
|
||||
|
||||
def set_main_window_size(self) -> None:
|
||||
"""Set size of window from database"""
|
||||
|
||||
@ -156,7 +156,7 @@ class PlaylistTab(QTableWidget):
|
||||
self.populate(session, self.playlist_id)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<PlaylistTab(id={self.playlist_id}"
|
||||
return f"<PlaylistTab(id={self.playlist_id}>"
|
||||
|
||||
# ########## Events other than cell editing ##########
|
||||
|
||||
@ -472,7 +472,15 @@ class PlaylistTab(QTableWidget):
|
||||
Return a list of PlaylistRow ids of the selected rows
|
||||
"""
|
||||
|
||||
return [self._get_playlistrow_id(a) for a in self._selected_rows()]
|
||||
return [self._get_playlistrow_id(a) for a in self._get_selected_rows()]
|
||||
|
||||
def get_selected_playlistrows(self, session: Session) -> Optional[List]:
|
||||
"""
|
||||
Return a list of PlaylistRows of the selected rows
|
||||
"""
|
||||
|
||||
plr_ids = self.get_selected_playlistrow_ids()
|
||||
return [session.get(PlaylistRows, a) for a in plr_ids]
|
||||
|
||||
def insert_header(self, session: Session, note: str,
|
||||
repaint: bool = True) -> None:
|
||||
@ -497,12 +505,6 @@ class PlaylistTab(QTableWidget):
|
||||
if repaint:
|
||||
self.update_display(session)
|
||||
#
|
||||
# def _get_selected_rows(self) -> List[int]:
|
||||
# """Return a sorted list of selected row numbers"""
|
||||
#
|
||||
# rows = self.selectionModel().selectedRows()
|
||||
# return sorted([row.row() for row in rows])
|
||||
#
|
||||
# def get_selected_title(self) -> Optional[str]:
|
||||
# """Return title of selected row or None"""
|
||||
#
|
||||
@ -747,13 +749,18 @@ class PlaylistTab(QTableWidget):
|
||||
# self.save_playlist(session)
|
||||
self.update_display(session)
|
||||
|
||||
def remove_selected_rows(self) -> None:
|
||||
"""Remove selected rows from display"""
|
||||
def remove_rows(self, row_numbers: List[int]) -> None:
|
||||
"""Remove passed rows from display"""
|
||||
|
||||
# Remove rows from display. Do so in reverse order so that
|
||||
# row numbers remain valid.
|
||||
for row in sorted(self._selected_rows(), reverse=True):
|
||||
for row in sorted(row_numbers, reverse=True):
|
||||
self.removeRow(row)
|
||||
|
||||
def remove_selected_rows(self) -> None:
|
||||
"""Remove selected rows from display"""
|
||||
|
||||
self.remove_rows(self._get_selected_rows())
|
||||
# Reset drag mode
|
||||
self.setDragEnabled(False)
|
||||
|
||||
@ -868,7 +875,7 @@ class PlaylistTab(QTableWidget):
|
||||
row: int
|
||||
selected_rows: List[int]
|
||||
|
||||
selected_rows = self._selected_rows()
|
||||
selected_rows = self._get_selected_rows()
|
||||
# we will only handle zero or one selected rows
|
||||
if len(selected_rows) > 1:
|
||||
return
|
||||
@ -915,7 +922,7 @@ class PlaylistTab(QTableWidget):
|
||||
row: int
|
||||
selected_rows: List[int]
|
||||
|
||||
selected_rows = self._selected_rows()
|
||||
selected_rows = self._get_selected_rows()
|
||||
# we will only handle zero or one selected rows
|
||||
if len(selected_rows) > 1:
|
||||
return
|
||||
@ -943,16 +950,6 @@ class PlaylistTab(QTableWidget):
|
||||
track_id = self._get_row_track_id(row)
|
||||
|
||||
self.selectRow(row)
|
||||
#
|
||||
# def select_unplayed_tracks(self) -> None:
|
||||
# """Select all unplayed tracks in playlist"""
|
||||
#
|
||||
# try:
|
||||
# self.selecting_in_progress = True
|
||||
# self._select_tracks(played=False)
|
||||
# finally:
|
||||
# self.selecting_in_progress = False
|
||||
# self._select_event()
|
||||
|
||||
def set_searchtext(self, text: Optional[str]) -> None:
|
||||
"""Set the search text and find first match"""
|
||||
@ -1393,14 +1390,6 @@ class PlaylistTab(QTableWidget):
|
||||
|
||||
return track_id
|
||||
|
||||
# def _get_unplayed_track_rows(self) -> Optional[List[int]]:
|
||||
# """Return rows marked as unplayed, or None"""
|
||||
#
|
||||
# unplayed_rows: Set[int] = set(self._meta_notset(RowMeta.PLAYED))
|
||||
# notes_rows: Set[int] = set(self._get_notes_rows())
|
||||
#
|
||||
# return list(unplayed_rows - notes_rows)
|
||||
|
||||
def _get_selected_row(self) -> Optional[int]:
|
||||
"""Return row number of first selected row, or None if none selected"""
|
||||
|
||||
@ -1409,6 +1398,13 @@ class PlaylistTab(QTableWidget):
|
||||
else:
|
||||
return self.selectionModel().selectedRows()[0].row()
|
||||
|
||||
def _get_selected_rows(self) -> List[int]:
|
||||
"""Return a list of selected row numbers"""
|
||||
|
||||
# Use a set to deduplicate result (a selected row will have all
|
||||
# items in that row selected)
|
||||
return [row for row in set([a.row() for a in self.selectedItems()])]
|
||||
|
||||
def _get_unreadable_track_rows(self) -> List[int]:
|
||||
"""Return rows marked as unreadable, or None"""
|
||||
|
||||
@ -1680,7 +1676,7 @@ class PlaylistTab(QTableWidget):
|
||||
if self.selecting_in_progress:
|
||||
return
|
||||
|
||||
selected_rows = self._selected_rows()
|
||||
selected_rows = self._get_selected_rows()
|
||||
# If no rows are selected, we have nothing to do
|
||||
if len(selected_rows) == 0:
|
||||
self.musicmuster.lblSumPlaytime.setText("")
|
||||
@ -1697,13 +1693,6 @@ class PlaylistTab(QTableWidget):
|
||||
else:
|
||||
self.musicmuster.lblSumPlaytime.setText("")
|
||||
|
||||
def _selected_rows(self) -> List[int]:
|
||||
"""Return a list of selected row numbers"""
|
||||
|
||||
# Use a set to deduplicate result (a selected row will have all
|
||||
# items in that row selected)
|
||||
return [row for row in set([a.row() for a in self.selectedItems()])]
|
||||
|
||||
def _set_column_widths(self, session: Session) -> None:
|
||||
"""Column widths from settings"""
|
||||
|
||||
|
||||
@ -763,7 +763,7 @@ border: 1px solid rgb(85, 87, 83);</string>
|
||||
<addaction name="actionDeletePlaylist"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionMoveSelected"/>
|
||||
<addaction name="actionMove_unplayed"/>
|
||||
<addaction name="actionMoveUnplayed"/>
|
||||
<addaction name="actionDownload_CSV_of_played_tracks"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionE_xit"/>
|
||||
@ -1000,7 +1000,7 @@ border: 1px solid rgb(85, 87, 83);</string>
|
||||
<string>Select played tracks</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMove_unplayed">
|
||||
<action name="actionMoveUnplayed">
|
||||
<property name="text">
|
||||
<string>Move &unplayed tracks to...</string>
|
||||
</property>
|
||||
|
||||
@ -430,8 +430,8 @@ class Ui_MainWindow(object):
|
||||
self.actionSelect_previous_track.setObjectName("actionSelect_previous_track")
|
||||
self.actionSelect_played_tracks = QtWidgets.QAction(MainWindow)
|
||||
self.actionSelect_played_tracks.setObjectName("actionSelect_played_tracks")
|
||||
self.actionMove_unplayed = QtWidgets.QAction(MainWindow)
|
||||
self.actionMove_unplayed.setObjectName("actionMove_unplayed")
|
||||
self.actionMoveUnplayed = QtWidgets.QAction(MainWindow)
|
||||
self.actionMoveUnplayed.setObjectName("actionMoveUnplayed")
|
||||
self.actionAdd_note = QtWidgets.QAction(MainWindow)
|
||||
self.actionAdd_note.setObjectName("actionAdd_note")
|
||||
self.actionEnable_controls = QtWidgets.QAction(MainWindow)
|
||||
@ -458,7 +458,7 @@ class Ui_MainWindow(object):
|
||||
self.menuFile.addAction(self.actionDeletePlaylist)
|
||||
self.menuFile.addSeparator()
|
||||
self.menuFile.addAction(self.actionMoveSelected)
|
||||
self.menuFile.addAction(self.actionMove_unplayed)
|
||||
self.menuFile.addAction(self.actionMoveUnplayed)
|
||||
self.menuFile.addAction(self.actionDownload_CSV_of_played_tracks)
|
||||
self.menuFile.addSeparator()
|
||||
self.menuFile.addAction(self.actionE_xit)
|
||||
@ -559,7 +559,7 @@ class Ui_MainWindow(object):
|
||||
self.actionSelect_previous_track.setText(_translate("MainWindow", "Select previous track"))
|
||||
self.actionSelect_previous_track.setShortcut(_translate("MainWindow", "K"))
|
||||
self.actionSelect_played_tracks.setText(_translate("MainWindow", "Select played tracks"))
|
||||
self.actionMove_unplayed.setText(_translate("MainWindow", "Move &unplayed tracks to..."))
|
||||
self.actionMoveUnplayed.setText(_translate("MainWindow", "Move &unplayed tracks to..."))
|
||||
self.actionAdd_note.setText(_translate("MainWindow", "Add note..."))
|
||||
self.actionAdd_note.setShortcut(_translate("MainWindow", "Ctrl+T"))
|
||||
self.actionEnable_controls.setText(_translate("MainWindow", "Enable controls"))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user