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
# Standard library imports
from __future__ import annotations
from slugify import slugify # type: ignore
from typing import Callable, Optional
import argparse
from dataclasses import dataclass
import datetime as dt
import os
import subprocess
@ -23,6 +25,7 @@ from PyQt6.QtGui import (
QAction,
QCloseEvent,
QColor,
QFont,
QIcon,
QKeySequence,
QPalette,
@ -30,6 +33,7 @@ from PyQt6.QtGui import (
)
from PyQt6.QtWidgets import (
QApplication,
QCheckBox,
QComboBox,
QDialog,
QFileDialog,
@ -42,6 +46,8 @@ from PyQt6.QtWidgets import (
QMenu,
QMessageBox,
QPushButton,
QTableWidget,
QTableWidgetItem,
QVBoxLayout,
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):
def __init__(self, templates: list[tuple[str, int]]) -> None:
super().__init__()
@ -160,6 +178,125 @@ class EditDeleteDialog(QDialog):
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:
"""
Manage track preview player
@ -1041,42 +1178,81 @@ class Window(QMainWindow):
Delete / edit templates
"""
# Build a list of (template-name, playlist-id) tuples
template_list: list[tuple[str, int]] = []
def delete(template_id: int) -> None:
"""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:
for template in Playlists.get_all_templates(session):
template_list.append((template.name, template.id))
# Get user's selection
dlg = EditDeleteDialog(template_list)
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=}"
)
# TODO: need to add in favourites
template_list.append(ItemlistItem(name=template.name, id=template.id))
x = ItemlistManager(template_list, callbacks)
x.show()
def mark_rows_for_moving(self) -> None:
"""