WIP: Implement move rows to playlist

This commit is contained in:
Keith Edmunds 2022-08-09 20:33:06 +01:00
parent 12541e1ff7
commit c8194fad80
3 changed files with 171 additions and 122 deletions

View File

@ -18,7 +18,7 @@ from sqlalchemy import (
delete, delete,
Float, Float,
ForeignKey, ForeignKey,
# func, func,
Integer, Integer,
select, select,
String, String,
@ -317,15 +317,15 @@ class Playlists(Base):
# self.loaded = False # self.loaded = False
# session.add(self) # session.add(self)
# session.flush() # session.flush()
#
# @classmethod @classmethod
# def get_all(cls, session: Session) -> List["Playlists"]: def get_all(cls, session: Session) -> List["Playlists"]:
# """Returns a list of all playlists ordered by last use""" """Returns a list of all playlists ordered by last use"""
#
# return ( return (
# session.query(cls).order_by( session.query(cls).order_by(
# cls.loaded.desc(), cls.last_used.desc()) cls.loaded.desc(), cls.last_used.desc())
# ).all() ).all()
# #
# @classmethod # @classmethod
# def get_closed(cls, session: Session) -> List["Playlists"]: # def get_closed(cls, session: Session) -> List["Playlists"]:
@ -508,6 +508,31 @@ class PlaylistRows(Base):
# Ensure new row numbers are available to the caller # Ensure new row numbers are available to the caller
session.commit() session.commit()
@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
"""
# Find last row of destination playlist
last_row = session.execute(
select(func.max(PlaylistRows.row_number))
.where(PlaylistRows.playlist_id == destination_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
session.commit()
# @classmethod # @classmethod
# def get_playlist_rows(cls, playlist_id: int) -> \ # def get_playlist_rows(cls, playlist_id: int) -> \
# Optional[List["PlaylistRows"]]: # Optional[List["PlaylistRows"]]:

View File

@ -13,16 +13,17 @@ import sys
# from typing import Callable, Dict, List, Optional, Tuple # from typing import Callable, Dict, List, Optional, Tuple
# #
# from PyQt5.QtCore import QDate, QEvent, QProcess, Qt, QTime, QTimer, QUrl # from PyQt5.QtCore import QDate, QEvent, QProcess, Qt, QTime, QTimer, QUrl
from PyQt5.QtCore import Qt
# from PyQt5.QtGui import QColor # from PyQt5.QtGui import QColor
# from PyQt5.QtWebEngineWidgets import QWebEngineView as QWebView # from PyQt5.QtWebEngineWidgets import QWebEngineView as QWebView
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
QApplication, QApplication,
# QDialog, QDialog,
# QFileDialog, # QFileDialog,
# QInputDialog, # QInputDialog,
QLabel, QLabel,
# QLineEdit, # QLineEdit,
# QListWidgetItem, QListWidgetItem,
QMainWindow, QMainWindow,
# QMessageBox, # QMessageBox,
) )
@ -35,14 +36,15 @@ from dbconfig import engine, Session
from models import ( from models import (
Base, Base,
# Playdates, # Playdates,
PlaylistRows,
Playlists, Playlists,
# Settings, Settings,
Tracks Tracks
) )
from playlists import PlaylistTab from playlists import PlaylistTab
# from sqlalchemy.orm.exc import DetachedInstanceError # from sqlalchemy.orm.exc import DetachedInstanceError
# from ui.dlg_search_database_ui import Ui_Dialog # from ui.dlg_search_database_ui import Ui_Dialog
# from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist
# from ui.downloadcsv_ui import Ui_DateSelect # from ui.downloadcsv_ui import Ui_DateSelect
from config import Config from config import Config
from ui.main_window_ui import Ui_MainWindow from ui.main_window_ui import Ui_MainWindow
@ -503,51 +505,58 @@ class Window(QMainWindow, Ui_MainWindow):
playlist.mark_open(session) playlist.mark_open(session)
def move_selected(self) -> None: def move_selected(self) -> None:
"""Move selected rows to another playlist""" """
Move selected rows to another playlist
# ***KAE Actions required:
pass - identify destination playlist
- update playlist for the rows in the database
- remove them from the display
- update destination playlist display if loaded
"""
# with Session() as session: # Identify destination playlist
# visible_tab = self.visible_playlist_tab() with Session() as session:
# visible_tab_id = visible_tab.playlist_id visible_tab = self.visible_playlist_tab()
# source_playlist = visible_tab.playlist_id
# source_playlist = None playlists = []
# playlists = [] for playlist in Playlists.get_all(session):
# for playlist in Playlists.get_all(session): if playlist.id == source_playlist:
# if playlist.id == visible_tab_id: continue
# source_playlist = playlist else:
# else: playlists.append(playlist)
# playlists.append(playlist)
# # Get destination playlist id
# # Get destination playlist id dlg = SelectPlaylistDialog(self, playlists=playlists,
# dlg = SelectPlaylistDialog(self, playlists=playlists, session=session)
# session=session) dlg.exec()
# dlg.exec() if not dlg.playlist:
# if not dlg.playlist: return
# return destination_playlist = dlg.playlist
# destination_playlist = dlg.playlist
# # Update playlist for the rows in the database
# self.visible_playlist_tab().move_selected_to_playlist( plr_ids = visible_tab.get_selected_playlistrow_ids()
# session, destination_playlist.id) PlaylistRows.move_to_playlist(
# session, plr_ids, destination_playlist.id
# # Update destination playlist_tab if visible (if not visible, it )
# # will be re-populated when it is opened)
# destination_visible_playlist_tab = None # Remove moved rows from display
# for tab in range(self.tabPlaylist.count()): visible_tab.remove_selected_rows()
# # Non-playlist tabs won't have a 'playlist_id' attribute
# if not hasattr(self.tabPlaylist.widget(tab), 'playlist_id'): # Update destination playlist_tab if visible (if not visible, it
# continue # will be re-populated when it is opened)
# if self.tabPlaylist.widget(tab).playlist_id == dlg.playlist.id: destination_visible_playlist_tab = None
# destination_visible_playlist_tab = ( for tab in range(self.tabPlaylist.count()):
# self.tabPlaylist.widget(tab)) # Non-playlist tabs won't have a 'playlist_id' attribute
# break if not hasattr(self.tabPlaylist.widget(tab), 'playlist_id'):
# continue
# if destination_visible_playlist_tab: if self.tabPlaylist.widget(tab).playlist_id == dlg.playlist.id:
# # We need to commit to database for populate to work destination_visible_playlist_tab = (
# session.commit() self.tabPlaylist.widget(tab))
# destination_visible_playlist_tab.populate( break
# session, dlg.playlist.id) if destination_visible_playlist_tab:
destination_visible_playlist_tab.populate(
session, dlg.playlist.id)
# #
# def open_info_tabs(self) -> None: # def open_info_tabs(self) -> None:
# """ # """
@ -1095,57 +1104,57 @@ class Window(QMainWindow, Ui_MainWindow):
# self.ui.dateTimeEdit.setTime(QTime(19, 59, 0)) # self.ui.dateTimeEdit.setTime(QTime(19, 59, 0))
# self.ui.buttonBox.accepted.connect(self.accept) # self.ui.buttonBox.accepted.connect(self.accept)
# self.ui.buttonBox.rejected.connect(self.reject) # self.ui.buttonBox.rejected.connect(self.reject)
#
#
# class SelectPlaylistDialog(QDialog): class SelectPlaylistDialog(QDialog):
# def __init__(self, parent=None, playlists=None, session=None): def __init__(self, parent=None, playlists=None, session=None):
# super().__init__(parent) super().__init__(parent)
#
# if playlists is None: if playlists is None:
# return return
# self.ui = Ui_dlgSelectPlaylist() self.ui = Ui_dlgSelectPlaylist()
# self.ui.setupUi(self) self.ui.setupUi(self)
# self.ui.lstPlaylists.itemDoubleClicked.connect(self.list_doubleclick) self.ui.lstPlaylists.itemDoubleClicked.connect(self.list_doubleclick)
# self.ui.buttonBox.accepted.connect(self.open) self.ui.buttonBox.accepted.connect(self.open)
# self.ui.buttonBox.rejected.connect(self.close) self.ui.buttonBox.rejected.connect(self.close)
# self.session = session self.session = session
# self.playlist = None self.playlist = None
# self.plid = None self.plid = None
#
# record = Settings.get_int_settings( record = Settings.get_int_settings(
# self.session, "select_playlist_dialog_width") self.session, "select_playlist_dialog_width")
# width = record.f_int or 800 width = record.f_int or 800
# record = Settings.get_int_settings( record = Settings.get_int_settings(
# self.session, "select_playlist_dialog_height") self.session, "select_playlist_dialog_height")
# height = record.f_int or 600 height = record.f_int or 600
# self.resize(width, height) self.resize(width, height)
#
# for playlist in playlists: for playlist in playlists:
# p = QListWidgetItem() p = QListWidgetItem()
# p.setText(playlist.name) p.setText(playlist.name)
# p.setData(Qt.UserRole, playlist) p.setData(Qt.UserRole, playlist)
# self.ui.lstPlaylists.addItem(p) self.ui.lstPlaylists.addItem(p)
#
# def __del__(self): # review def __del__(self): # review
# record = Settings.get_int_settings( record = Settings.get_int_settings(
# self.session, "select_playlist_dialog_height") self.session, "select_playlist_dialog_height")
# if record.f_int != self.height(): if record.f_int != self.height():
# record.update(self.session, {'f_int': self.height()}) record.update(self.session, {'f_int': self.height()})
#
# record = Settings.get_int_settings( record = Settings.get_int_settings(
# self.session, "select_playlist_dialog_width") self.session, "select_playlist_dialog_width")
# if record.f_int != self.width(): if record.f_int != self.width():
# record.update(self.session, {'f_int': self.width()}) record.update(self.session, {'f_int': self.width()})
#
# def list_doubleclick(self, entry): # review def list_doubleclick(self, entry): # review
# self.playlist = entry.data(Qt.UserRole) self.playlist = entry.data(Qt.UserRole)
# self.accept() self.accept()
#
# def open(self): # review def open(self): # review
# if self.ui.lstPlaylists.selectedItems(): if self.ui.lstPlaylists.selectedItems():
# item = self.ui.lstPlaylists.currentItem() item = self.ui.lstPlaylists.currentItem()
# self.playlist = item.data(Qt.UserRole) self.playlist = item.data(Qt.UserRole)
# self.accept() self.accept()
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -340,6 +340,13 @@ class PlaylistTab(QTableWidget):
self.clearSelection() self.clearSelection()
self.setDragEnabled(False) self.setDragEnabled(False)
def get_selected_playlistrow_ids(self) -> Optional[List]:
"""
Return a list of PlaylistRow ids of the selected rows
"""
return [self._get_playlistrow_id(a) for a in self._selected_rows()]
# def closeEvent(self, event) -> None: # def closeEvent(self, event) -> None:
# """Save column widths""" # """Save column widths"""
# #
@ -697,6 +704,16 @@ class PlaylistTab(QTableWidget):
# KAE self.save_playlist(session) # KAE self.save_playlist(session)
self.update_display(session) self.update_display(session)
def remove_selected_rows(self) -> None:
"""Remove selected 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):
self.removeRow(row)
# Reset drag mode
self.setDragEnabled(False)
def save_playlist(self, session: Session) -> None: def save_playlist(self, session: Session) -> None:
""" """
Save playlist to database Save playlist to database
@ -1254,22 +1271,14 @@ class PlaylistTab(QTableWidget):
""" """
# Delete rows from database # Delete rows from database
# Each item in a row will be returned from selectedItems(), so plr_ids = self.get_selected_playlistrow_ids()
# make a set to remove duplicate row numbers
selected_rows = sorted(
set(item.row() for item in self.selectedItems())
)
plr_ids = [self._get_playlistrow_id(a) for a in selected_rows]
with Session() as session: with Session() as session:
PlaylistRows.delete_rows(session, plr_ids) PlaylistRows.delete_rows(session, plr_ids)
# Fix up row numbers left in this playlist # Fix up row numbers left in this playlist
PlaylistRows.fixup_rownumbers(session, self.playlist_id) PlaylistRows.fixup_rownumbers(session, self.playlist_id)
#Remove selected rows from display
# Remove rows from display. Do so in reverse order so that self.remove_selected_rows()
# row numbers remain valid.
for row in sorted(selected_rows, reverse=True):
self.removeRow(row)
def _drop_on(self, event): def _drop_on(self, event):
""" """
@ -1736,9 +1745,7 @@ class PlaylistTab(QTableWidget):
if self.selecting_in_progress: if self.selecting_in_progress:
return return
# Get the row number of all selected items and put into a set selected_rows = self._selected_rows()
# to deduplicate
selected_rows = set([item.row() for item in self.selectedItems()])
# If no rows are selected, we have nothing to do # If no rows are selected, we have nothing to do
if len(selected_rows) == 0: if len(selected_rows) == 0:
self.musicmuster.lblSumPlaytime.setText("") self.musicmuster.lblSumPlaytime.setText("")
@ -1754,6 +1761,14 @@ class PlaylistTab(QTableWidget):
f"Selected duration: {helpers.ms_to_mmss(ms)}") f"Selected duration: {helpers.ms_to_mmss(ms)}")
else: else:
self.musicmuster.lblSumPlaytime.setText("") self.musicmuster.lblSumPlaytime.setText("")
def _selected_rows(self) -> Optional[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 _select_tracks(self, played: bool) -> None: # def _select_tracks(self, played: bool) -> None:
# """ # """