WIP: template management: edit and delete working

This commit is contained in:
Keith Edmunds 2025-02-22 11:34:36 +00:00
parent b0f6e4e819
commit e10c2adafe

View File

@ -1,9 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Standard library imports # Standard library imports
from __future__ import annotations
from slugify import slugify # type: ignore from slugify import slugify # type: ignore
from typing import Callable, Optional from typing import Callable, Optional
import argparse import argparse
from dataclasses import dataclass
import datetime as dt import datetime as dt
import os import os
import subprocess import subprocess
@ -23,6 +25,7 @@ from PyQt6.QtGui import (
QAction, QAction,
QCloseEvent, QCloseEvent,
QColor, QColor,
QFont,
QIcon, QIcon,
QKeySequence, QKeySequence,
QPalette, QPalette,
@ -30,6 +33,7 @@ from PyQt6.QtGui import (
) )
from PyQt6.QtWidgets import ( from PyQt6.QtWidgets import (
QApplication, QApplication,
QCheckBox,
QComboBox, QComboBox,
QDialog, QDialog,
QFileDialog, QFileDialog,
@ -42,6 +46,8 @@ from PyQt6.QtWidgets import (
QMenu, QMenu,
QMessageBox, QMessageBox,
QPushButton, QPushButton,
QTableWidget,
QTableWidgetItem,
QVBoxLayout, QVBoxLayout,
QWidget, QWidget,
) )
@ -102,6 +108,18 @@ class Current:
) )
class DownloadCSV(QDialog):
def __init__(self, parent=None):
super().__init__()
self.ui = Ui_DateSelect()
self.ui.setupUi(self)
self.ui.dateTimeEdit.setDate(QDate.currentDate())
self.ui.dateTimeEdit.setTime(QTime(19, 59, 0))
self.ui.buttonBox.accepted.connect(self.accept)
self.ui.buttonBox.rejected.connect(self.reject)
class EditDeleteDialog(QDialog): class EditDeleteDialog(QDialog):
def __init__(self, templates: list[tuple[str, int]]) -> None: def __init__(self, templates: list[tuple[str, int]]) -> None:
super().__init__() super().__init__()
@ -160,6 +178,125 @@ class EditDeleteDialog(QDialog):
self.reject() self.reject()
@dataclass
class ItemlistItem:
id: int
name: str
favourite: bool = False
class ItemlistManager(QDialog):
def __init__(
self, items: list[ItemlistItem], callbacks: ItemlistManagerCallbacks
) -> None:
super().__init__()
self.setWindowTitle("Item Manager")
self.setMinimumSize(600, 400)
self.items = items
self.callbacks = callbacks
layout = QVBoxLayout(self)
self.table = QTableWidget(len(items), 2, self)
self.table.setHorizontalHeaderLabels(["Item", "Actions"])
hh = self.table.horizontalHeader()
if not hh:
raise ApplicationError("ItemlistManager failed to create horizontalHeader")
hh.setStretchLastSection(True)
self.table.setColumnWidth(0, 200)
self.table.setColumnWidth(1, 300)
self.populate_table()
layout.addWidget(self.table)
button_layout = QHBoxLayout()
self.new_button = QPushButton("New")
self.new_button.clicked.connect(self.new_item)
button_layout.addWidget(self.new_button)
self.close_button = QPushButton("Close")
self.close_button.clicked.connect(self.close)
button_layout.addWidget(self.close_button)
layout.addLayout(button_layout)
def populate_table(self) -> None:
"""Populates the table with items and action buttons."""
self.table.setRowCount(len(self.items))
for row, item in enumerate(self.items):
item_text = QTableWidgetItem(item.name)
if item.favourite:
item_text.setFont(QFont("Arial", weight=QFont.Weight.Bold))
self.table.setItem(row, 0, item_text)
# Action Buttons and Checkbox in a widget
widget = QWidget()
h_layout = QHBoxLayout(widget)
h_layout.setContentsMargins(0, 0, 0, 0)
h_layout.setSpacing(5)
rename_button = QPushButton("Rename")
rename_button.clicked.connect(lambda _, i=item.id: self.rename_item(i))
h_layout.addWidget(rename_button)
edit_button = QPushButton("Edit")
edit_button.clicked.connect(lambda _, i=item.id: self.edit_item(i))
h_layout.addWidget(edit_button)
delete_button = QPushButton("Delete")
delete_button.clicked.connect(lambda _, i=item.id: self.delete_item(i))
h_layout.addWidget(delete_button)
fav_checkbox = QCheckBox()
fav_checkbox.setChecked(item.favourite)
fav_checkbox.stateChanged.connect(
lambda state, cb=fav_checkbox, i=item.id: self.toggle_favourite(
i, cb.isChecked()
)
)
h_layout.addWidget(fav_checkbox)
self.table.setCellWidget(row, 1, widget)
def delete_item(self, item_id: int) -> None:
self.callbacks.delete(item_id)
def edit_item(self, item_id: int) -> None:
self.callbacks.edit(item_id)
def rename_item(self, item_id: int) -> None:
print(f"Rename item {item_id}")
def toggle_favourite(self, item_id: int, checked: bool) -> None:
print(f"Toggle favourite for item {item_id}: {checked}")
self.callbacks.favourite(item_id, checked)
for row in range(self.table.rowCount()):
item = self.table.item(row, 0)
if item and self.items[row].id == item_id:
font = QFont(
"Arial",
weight=QFont.Weight.Bold if checked else QFont.Weight.Normal,
)
item.setFont(font)
self.items[row].favourite = checked
break
def new_item(self) -> None:
self.callbacks.new_item()
@dataclass
class ItemlistManagerCallbacks:
delete: Callable[[int], None]
edit: Callable[[int], None]
favourite: Callable[[int, bool], None]
new_item: Callable[[], None]
rename: Callable[[int], None]
class PreviewManager: class PreviewManager:
""" """
Manage track preview player Manage track preview player
@ -1041,42 +1178,81 @@ class Window(QMainWindow):
Delete / edit templates Delete / edit templates
""" """
# Build a list of (template-name, playlist-id) tuples def delete(template_id: int) -> None:
template_list: list[tuple[str, int]] = [] """delete template"""
template = session.get(Playlists, template_id)
if not template:
raise ApplicationError(
f"manage_templeate.delete({template_id=}) can't load template"
)
if helpers.ask_yes_no(
"Delete template",
f"Delete template '{template.name}': " "Are you sure?",
):
# If template is currently open, re-check
for idx in range(self.playlist_section.tabPlaylist.count()):
if (
self.playlist_section.tabPlaylist.widget(idx).playlist_id
== template_id
):
if not helpers.ask_yes_no(
"Delete open template",
f"Template '{template.name}' is currently open. Really delete?"
):
return
else:
self.playlist_section.tabPlaylist.removeTab(idx)
break
log.info(f"manage_templates: delete {template=}")
template.delete(session)
session.commit()
def edit(template_id: int) -> None:
"""Edit template"""
template = session.get(Playlists, template_id)
if not template:
raise ApplicationError(
f"manage_templeate.edit({template_id=}) can't load template"
)
# Simply load the template as a playlist. Any changes
# made will persist
idx = self.create_playlist_tab(template)
self.playlist_section.tabPlaylist.setCurrentIndex(idx)
def favourite(template_id: int, favourite: bool) -> None:
"""favourite template"""
print(f"manage_templates.favourite({template_id=}")
print(f"{session=}")
def new_item() -> None:
"""new item"""
print("manage_templates.new()")
print(f"{session=}")
def rename(template_id: int) -> None:
"""rename template"""
print(f"manage_templates.rename({template_id=}")
print(f"{session=}")
callbacks = ItemlistManagerCallbacks(
delete=delete, edit=edit, favourite=favourite, new_item=new_item, rename=rename
)
# Build a list of templates
template_list: list[ItemlistItem] = []
with db.Session() as session: with db.Session() as session:
for template in Playlists.get_all_templates(session): for template in Playlists.get_all_templates(session):
template_list.append((template.name, template.id)) # TODO: need to add in favourites
template_list.append(ItemlistItem(name=template.name, id=template.id))
# Get user's selection x = ItemlistManager(template_list, callbacks)
dlg = EditDeleteDialog(template_list) x.show()
if not dlg.exec():
return # User cancelled
action, template_id = dlg.selection
playlist = session.get(Playlists, template_id)
if not playlist:
log.error(f"Error opening {template_id=}")
if action == "Edit":
# Simply load the template as a playlist. Any changes
# made will persist
idx = self.create_playlist_tab(playlist)
self.playlist_section.tabPlaylist.setCurrentIndex(idx)
elif action == "Delete":
if helpers.ask_yes_no(
"Delete template",
f"Delete template '{playlist.name}': " "Are you sure?",
):
if self.close_playlist_tab():
playlist.delete(session)
session.commit()
else:
raise ApplicationError(
f"Unrecognised action from EditDeleteDialog: {action=}"
)
def mark_rows_for_moving(self) -> None: def mark_rows_for_moving(self) -> None:
""" """