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)
|
super().__init__(parent)
|
||||||
self.setItemDelegate(EscapeDelegate(self))
|
self.setItemDelegate(EscapeDelegate(self))
|
||||||
self.setModel(MyModel())
|
self.setModel(MyModel())
|
||||||
self.resizeColumnsToContents()
|
|
||||||
self.resizeRowsToContents()
|
|
||||||
|
|
||||||
|
|
||||||
class MyModel(QAbstractTableModel):
|
class MyModel(QAbstractTableModel):
|
||||||
@ -82,6 +80,8 @@ class MainWindow(QMainWindow):
|
|||||||
self.table_widget = MyTableWidget(self)
|
self.table_widget = MyTableWidget(self)
|
||||||
self.setCentralWidget(self.table_widget)
|
self.setCentralWidget(self.table_widget)
|
||||||
|
|
||||||
|
self.table_widget.resizeColumnsToContents()
|
||||||
|
self.table_widget.resizeRowsToContents()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@ -67,7 +67,7 @@ import icons_rc # noqa F401
|
|||||||
import music
|
import music
|
||||||
from models import Base, Carts, Playdates, PlaylistRows, Playlists, Settings, Tracks
|
from models import Base, Carts, Playdates, PlaylistRows, Playlists, Settings, Tracks
|
||||||
from config import Config
|
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_cart_ui import Ui_DialogCartEdit # type: ignore
|
||||||
from ui.dlg_search_database_ui import Ui_Dialog # type: ignore
|
from ui.dlg_search_database_ui import Ui_Dialog # type: ignore
|
||||||
from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist # 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)
|
set_next_track_signal = pyqtSignal(int, int)
|
||||||
|
span_cells_signal = pyqtSignal(int, int, int, int)
|
||||||
|
enable_escape_signal = pyqtSignal(bool)
|
||||||
|
|
||||||
|
|
||||||
class PlaylistTrack:
|
class PlaylistTrack:
|
||||||
@ -327,7 +329,7 @@ class PlaylistTrack:
|
|||||||
|
|
||||||
class Window(QMainWindow, Ui_MainWindow):
|
class Window(QMainWindow, Ui_MainWindow):
|
||||||
def __init__(self, parent=None, *args, **kwargs) -> None:
|
def __init__(self, parent=None, *args, **kwargs) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
|
||||||
self.timer10: QTimer = QTimer()
|
self.timer10: QTimer = QTimer()
|
||||||
@ -690,6 +692,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.tabBar.tabMoved.connect(self.move_tab)
|
self.tabBar.tabMoved.connect(self.move_tab)
|
||||||
self.txtSearch.returnPressed.connect(self.search_playlist_return)
|
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.timer10.timeout.connect(self.tick_10ms)
|
||||||
self.timer500.timeout.connect(self.tick_500ms)
|
self.timer500.timeout.connect(self.tick_500ms)
|
||||||
self.timer1000.timeout.connect(self.tick_1000ms)
|
self.timer1000.timeout.connect(self.tick_1000ms)
|
||||||
@ -810,6 +814,16 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
else:
|
else:
|
||||||
self.music.set_volume(Config.VOLUME_VLC_DEFAULT, set_default=False)
|
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:
|
def enable_play_next_controls(self) -> None:
|
||||||
"""
|
"""
|
||||||
Enable "play next" keyboard controls
|
Enable "play next" keyboard controls
|
||||||
|
|||||||
@ -168,6 +168,20 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
# Fall through to no-op
|
# Fall through to no-op
|
||||||
return QVariant()
|
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:
|
def display_role(self, row: int, column: int, prd: PlaylistRowData) -> QVariant:
|
||||||
"""
|
"""
|
||||||
Return text for display
|
Return text for display
|
||||||
|
|||||||
@ -56,7 +56,7 @@ if TYPE_CHECKING:
|
|||||||
# section_header_cleanup_re = re.compile(r"(@\d\d:\d\d:\d\d.*)?(\+)?")
|
# 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")
|
# start_time_re = re.compile(r"@\d\d:\d\d:\d\d")
|
||||||
|
|
||||||
# HEADER_NOTES_COLUMN = 2
|
HEADER_NOTES_COLUMN = 2
|
||||||
|
|
||||||
# # Columns
|
# # Columns
|
||||||
# Column = namedtuple("Column", ["idx", "heading"])
|
# Column = namedtuple("Column", ["idx", "heading"])
|
||||||
@ -85,131 +85,81 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
|
|
||||||
class EscapeDelegate(QStyledItemDelegate):
|
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)
|
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 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"""
|
"""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:
|
if event.type() == QEvent.Type.KeyPress:
|
||||||
key_event = cast(QKeyEvent, event)
|
key_event = cast(QKeyEvent, event)
|
||||||
print(key_event)
|
print(key_event.key())
|
||||||
if key_event.key() == Qt.Key.Key_Return:
|
if key_event.key() == Qt.Key.Key_Return:
|
||||||
if key_event.modifiers() == (Qt.KeyboardModifier.ControlModifier):
|
if key_event.modifiers() == (Qt.KeyboardModifier.ControlModifier):
|
||||||
print(">>>save data")
|
|
||||||
self.commitData.emit(editor)
|
self.commitData.emit(editor)
|
||||||
self.closeEditor.emit(editor)
|
self.closeEditor.emit(editor)
|
||||||
return True
|
return True
|
||||||
# elif key_event.key() == Qt.Key.Key_Escape:
|
elif key_event.key() == Qt.Key.Key_Escape:
|
||||||
# print("discard edits")
|
discard_edits = QMessageBox.question(
|
||||||
# discard_edits = QMessageBox.question(
|
self.parent(), "Abandon edit", "Discard changes?"
|
||||||
# self.parent(), "Abandon edit", "Discard changes?"
|
)
|
||||||
# )
|
if discard_edits == QMessageBox.StandardButton.Yes:
|
||||||
# if discard_edits == QMessageBox.StandardButton.Yes:
|
self.closeEditor.emit(editor)
|
||||||
# print("abandon edit")
|
return True
|
||||||
# self.closeEditor.emit(editor)
|
|
||||||
# return True
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def setEditorData(self, editor, index):
|
def setEditorData(self, editor, index):
|
||||||
|
print("setEditorData()")
|
||||||
value = index.model().data(index, Qt.ItemDataRole.EditRole)
|
value = index.model().data(index, Qt.ItemDataRole.EditRole)
|
||||||
editor.setPlainText(value.value())
|
editor.setPlainText(value.value())
|
||||||
|
|
||||||
def setModelData(self, editor, model, index):
|
def setModelData(self, editor, model, index):
|
||||||
print("setModelData called")
|
print("setModelData")
|
||||||
value = editor.toPlainText()
|
value = editor.toPlainText()
|
||||||
model.setData(index, value, Qt.ItemDataRole.EditRole)
|
model.setData(index, value, Qt.ItemDataRole.EditRole)
|
||||||
|
|
||||||
def updateEditorGeometry(self, editor, option, index):
|
def updateEditorGeometry(self, editor, option, index):
|
||||||
|
print("updateEditorGeometry")
|
||||||
editor.setGeometry(option.rect)
|
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):
|
class PlaylistTab(QTableView):
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -226,10 +176,10 @@ class PlaylistTab(QTableView):
|
|||||||
self.signals = signals
|
self.signals = signals
|
||||||
|
|
||||||
# Set up widget
|
# Set up widget
|
||||||
self.setItemDelegate(EscapeDelegate(self))
|
self.setItemDelegate(EscapeDelegate(self, self.signals))
|
||||||
self.setAlternatingRowColors(True)
|
self.setAlternatingRowColors(True)
|
||||||
# self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
||||||
# self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||||
# self.setEditTriggers(QAbstractItemView.EditTrigger.DoubleClicked)
|
# self.setEditTriggers(QAbstractItemView.EditTrigger.DoubleClicked)
|
||||||
self.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel)
|
self.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel)
|
||||||
# This dancing is to satisfy mypy
|
# 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
|
# 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
|
# a change to the view and thus it refreshes the data which
|
||||||
# again calls us here.
|
# 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
|
return
|
||||||
|
|
||||||
self.setSpan(row, column, rowSpan, columnSpan)
|
self.setSpan(row, column, rowSpan, columnSpan)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user