V3 WIP: ESC works in editing
This commit is contained in:
parent
b75dc4256a
commit
93d780f75a
@ -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__":
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user