V3 WIP: ESC works in editing

This commit is contained in:
Keith Edmunds 2023-10-21 11:03:03 +01:00
parent b75dc4256a
commit 93d780f75a
4 changed files with 90 additions and 109 deletions

View File

@ -50,8 +50,6 @@ class MyTableWidget(QTableView):
super().__init__(parent)
self.setItemDelegate(EscapeDelegate(self))
self.setModel(MyModel())
self.resizeColumnsToContents()
self.resizeRowsToContents()
class MyModel(QAbstractTableModel):
@ -82,6 +80,8 @@ class MainWindow(QMainWindow):
self.table_widget = MyTableWidget(self)
self.setCentralWidget(self.table_widget)
self.table_widget.resizeColumnsToContents()
self.table_widget.resizeRowsToContents()
if __name__ == "__main__":

View File

@ -67,7 +67,7 @@ import icons_rc # noqa F401
import music
from models import Base, Carts, Playdates, PlaylistRows, Playlists, Settings, Tracks
from config import Config
from playlists import PlaylistTab
from playlists_v3 import PlaylistTab
from ui.dlg_cart_ui import Ui_DialogCartEdit # type: ignore
from ui.dlg_search_database_ui import Ui_Dialog # type: ignore
from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist # type: ignore
@ -245,6 +245,8 @@ class MusicMusterSignals(QObject):
"""
set_next_track_signal = pyqtSignal(int, int)
span_cells_signal = pyqtSignal(int, int, int, int)
enable_escape_signal = pyqtSignal(bool)
class PlaylistTrack:
@ -327,7 +329,7 @@ class PlaylistTrack:
class Window(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
super().__init__(parent)
self.setupUi(self)
self.timer10: QTimer = QTimer()
@ -690,6 +692,8 @@ class Window(QMainWindow, Ui_MainWindow):
self.tabBar.tabMoved.connect(self.move_tab)
self.txtSearch.returnPressed.connect(self.search_playlist_return)
self.signals.enable_escape_signal.connect(self.enable_escape)
self.timer10.timeout.connect(self.tick_10ms)
self.timer500.timeout.connect(self.tick_500ms)
self.timer1000.timeout.connect(self.tick_1000ms)
@ -810,6 +814,16 @@ class Window(QMainWindow, Ui_MainWindow):
else:
self.music.set_volume(Config.VOLUME_VLC_DEFAULT, set_default=False)
def enable_escape(self, enabled: bool) -> None:
"""
Manage signal to enable/disable handling ESC character.
Needed because we want to use ESC when editing playlist in place,
so we need to disable it here while editing.
"""
self.action_Clear_selection.setEnabled(enabled)
def enable_play_next_controls(self) -> None:
"""
Enable "play next" keyboard controls

View File

@ -168,6 +168,20 @@ class PlaylistModel(QAbstractTableModel):
# Fall through to no-op
return QVariant()
def edit_role(self, row: int, column: int, prd: PlaylistRowData) -> QVariant:
"""
Return text for editing
"""
if column == Col.TITLE.value:
return QVariant(prd.title)
if column == Col.ARTIST.value:
return QVariant(prd.artist)
if column == Col.NOTE.value:
return QVariant(prd.note)
return QVariant()
def display_role(self, row: int, column: int, prd: PlaylistRowData) -> QVariant:
"""
Return text for display

View File

@ -56,7 +56,7 @@ if TYPE_CHECKING:
# section_header_cleanup_re = re.compile(r"(@\d\d:\d\d:\d\d.*)?(\+)?")
# start_time_re = re.compile(r"@\d\d:\d\d:\d\d")
# HEADER_NOTES_COLUMN = 2
HEADER_NOTES_COLUMN = 2
# # Columns
# Column = namedtuple("Column", ["idx", "heading"])
@ -85,131 +85,81 @@ if TYPE_CHECKING:
class EscapeDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
"""
- increases the height of a row when editing to make editing easier
- closes the edit on control-return
- checks with user before abandoning edit on Escape
"""
def __init__(self, parent, signals: "MusicMusterSignals") -> None:
super().__init__(parent)
self.signals = signals
def createEditor(self, parent, option, index):
def createEditor(
self,
parent: Optional[QWidget],
option: QStyleOptionViewItem,
index: QModelIndex,
):
"""
Intercept createEditor call and make row just a little bit taller
"""
self.signals.enable_escape_signal.emit(False)
if isinstance(self.parent(), PlaylistTab):
p = cast(PlaylistTab, self.parent())
if isinstance(index.data(), str):
row = index.row()
row_height = p.rowHeight(row)
p.setRowHeight(row, row_height + Config.MINIMUM_ROW_HEIGHT)
return QPlainTextEdit(parent)
return super().createEditor(parent, option, index)
def eventFilter(self, editor: QObject, event: QEvent):
def destroyEditor(self, editor: Optional[QWidget], index: QModelIndex) -> None:
"""
Intercept editor destroyment
"""
self.signals.enable_escape_signal.emit(True)
return super().destroyEditor(editor, index)
def eventFilter(self, editor: Optional[QObject], event: Optional[QEvent]) -> bool:
"""By default, QPlainTextEdit doesn't handle enter or return"""
if editor is None or event is None:
return False
if event.type() == QEvent.Type.KeyPress:
key_event = cast(QKeyEvent, event)
print(key_event)
print(key_event.key())
if key_event.key() == Qt.Key.Key_Return:
if key_event.modifiers() == (Qt.KeyboardModifier.ControlModifier):
print(">>>save data")
self.commitData.emit(editor)
self.closeEditor.emit(editor)
return True
# elif key_event.key() == Qt.Key.Key_Escape:
# print("discard edits")
# discard_edits = QMessageBox.question(
# self.parent(), "Abandon edit", "Discard changes?"
# )
# if discard_edits == QMessageBox.StandardButton.Yes:
# print("abandon edit")
# self.closeEditor.emit(editor)
# return True
elif key_event.key() == Qt.Key.Key_Escape:
discard_edits = QMessageBox.question(
self.parent(), "Abandon edit", "Discard changes?"
)
if discard_edits == QMessageBox.StandardButton.Yes:
self.closeEditor.emit(editor)
return True
return False
def setEditorData(self, editor, index):
print("setEditorData()")
value = index.model().data(index, Qt.ItemDataRole.EditRole)
editor.setPlainText(value.value())
def setModelData(self, editor, model, index):
print("setModelData called")
print("setModelData")
value = editor.toPlainText()
model.setData(index, value, Qt.ItemDataRole.EditRole)
def updateEditorGeometry(self, editor, option, index):
print("updateEditorGeometry")
editor.setGeometry(option.rect)
# class EscapeDelegate(QStyledItemDelegate):
# """
# - increases the height of a row when editing to make editing easier
# - closes the edit on control-return
# - checks with user before abandoning edit on Escape
# """
# def __init__(self, parent) -> None:
# super().__init__(parent)
# def createEditor(
# self,
# parent: Optional[QWidget],
# option: QStyleOptionViewItem,
# index: QModelIndex,
# ):
# """
# Intercept createEditor call and make row just a little bit taller
# """
# return QPlainTextEdit(parent)
# # kae if isinstance(self.parent(), PlaylistTab):
# # kae p = cast(PlaylistTab, self.parent())
# # kae if isinstance(index.data(), str):
# # kae row = index.row()
# # kae row_height = p.rowHeight(row)
# # kae p.setRowHeight(row, row_height + Config.MINIMUM_ROW_HEIGHT)
# # kae return QPlainTextEdit(parent)
# # kae return super().createEditor(parent, option, index)
# def eventFilter(self, editor: Optional[QObject], event: Optional[QEvent]) -> bool:
# """By default, QPlainTextEdit doesn't handle enter or return"""
# # kae if editor is None or event is None:
# # kae print("event filter returning")
# # kae return False
# # kae print(event.type())
# if event.type() == QEvent.Type.KeyPress:
# key_event = cast(QKeyEvent, event)
# if key_event.key() == Qt.Key.Key_Return:
# if key_event.modifiers() == (Qt.KeyboardModifier.ControlModifier):
# self.commitData.emit(editor)
# self.closeEditor.emit(editor)
# return True
# elif key_event.key() == Qt.Key.Key_Escape:
# print("Escape pressed")
# discard_edits = QMessageBox.question(
# self.parent(), "Abandon edit", "Discard changes?"
# )
# if discard_edits == QMessageBox.StandardButton.Yes:
# self.closeEditor.emit(editor)
# return True
# class EscapeDelegate(QStyledItemDelegate):
# def __init__(self, parent=None):
# super().__init__(parent)
# def createEditor(self, parent, option, index):
# return QPlainTextEdit(parent)
# def eventFilter(self, editor: QObject, event: QEvent):
# """By default, QPlainTextEdit doesn't handle enter or return"""
# print("EscapeDelegate event handler")
# if event.type() == QEvent.Type.KeyPress:
# key_event = cast(QKeyEvent, event)
# if key_event.key() == Qt.Key.Key_Return:
# if key_event.modifiers() == (Qt.KeyboardModifier.ControlModifier):
# print("save data")
# self.commitData.emit(editor)
# self.closeEditor.emit(editor)
# return True
# elif key_event.key() == Qt.Key.Key_Escape:
# discard_edits = QMessageBox.question(
# self.parent(), "Abandon edit", "Discard changes?"
# )
# if discard_edits == QMessageBox.StandardButton.Yes:
# print("abandon edit")
# self.closeEditor.emit(editor)
# return True
# return False
# # return False
class PlaylistTab(QTableView):
def __init__(
@ -226,10 +176,10 @@ class PlaylistTab(QTableView):
self.signals = signals
# Set up widget
self.setItemDelegate(EscapeDelegate(self))
self.setItemDelegate(EscapeDelegate(self, self.signals))
self.setAlternatingRowColors(True)
# self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
# self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
# self.setEditTriggers(QAbstractItemView.EditTrigger.DoubleClicked)
self.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel)
# This dancing is to satisfy mypy
@ -2453,7 +2403,10 @@ class PlaylistTab(QTableView):
# Don't set spanning if already in place because that is seen as
# a change to the view and thus it refreshes the data which
# again calls us here.
if self.rowSpan(row, column) == rowSpan and self.columnSpan(row, column) == columnSpan:
if (
self.rowSpan(row, column) == rowSpan
and self.columnSpan(row, column) == columnSpan
):
return
self.setSpan(row, column, rowSpan, columnSpan)