WIP: template management: edit and delete working
This commit is contained in:
parent
b0f6e4e819
commit
e10c2adafe
@ -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:
|
||||
"""
|
||||
|
||||
Loading…
Reference in New Issue
Block a user