Simple text editor for basic notes
This commit is contained in:
parent
bd4d571c95
commit
160de4c526
5 changed files with 96 additions and 15 deletions
|
|
@ -1,7 +1,6 @@
|
||||||
from PySide6.QtCore import Qt
|
from PySide6.QtCore import Qt
|
||||||
from PySide6.QtGui import QAction, QKeySequence
|
from PySide6.QtGui import QAction, QKeySequence
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QLabel,
|
|
||||||
QMainWindow,
|
QMainWindow,
|
||||||
QSplitter,
|
QSplitter,
|
||||||
QStatusBar,
|
QStatusBar,
|
||||||
|
|
@ -13,7 +12,9 @@ from PySide6.QtWidgets import (
|
||||||
from .settings import get_settings
|
from .settings import get_settings
|
||||||
|
|
||||||
from trovedb import trove as tr
|
from trovedb import trove as tr
|
||||||
|
|
||||||
from .note_browser import NoteBrowser
|
from .note_browser import NoteBrowser
|
||||||
|
from .note_tool_stack import NoteToolStack
|
||||||
|
|
||||||
class TroveMainWindow(QMainWindow):
|
class TroveMainWindow(QMainWindow):
|
||||||
def __init__(self, trove: tr.Trove):
|
def __init__(self, trove: tr.Trove):
|
||||||
|
|
@ -44,15 +45,17 @@ class TroveMainWindow(QMainWindow):
|
||||||
layout.setSpacing(0)
|
layout.setSpacing(0)
|
||||||
|
|
||||||
# Horizontal splitter: tree | editor
|
# Horizontal splitter: tree | editor
|
||||||
splitter = QSplitter(Qt.Orientation.Horizontal)
|
self._splitter = QSplitter(Qt.Orientation.Horizontal)
|
||||||
|
|
||||||
self._note_browser = NoteBrowser(trove)
|
self._note_browser = NoteBrowser(trove)
|
||||||
splitter.addWidget(self._note_browser)
|
self._splitter.addWidget(self._note_browser)
|
||||||
|
|
||||||
self._tool = QLabel("View/Edit Tool")
|
self._tool_stack = NoteToolStack()
|
||||||
splitter.addWidget(self._tool)
|
self._splitter.addWidget(self._tool_stack)
|
||||||
|
|
||||||
layout.addWidget(splitter, stretch=1)
|
layout.addWidget(self._splitter, stretch=1)
|
||||||
|
|
||||||
|
self._note_browser.activeNoteChanged.connect(self._tool_stack.onNoteSelected)
|
||||||
|
|
||||||
# ── Status bar ──
|
# ── Status bar ──
|
||||||
self.setStatusBar(QStatusBar())
|
self.setStatusBar(QStatusBar())
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,7 @@ class NoteBrowser(QWidget):
|
||||||
tree_selected(TreeNote) -- emitted when a tree note is activated
|
tree_selected(TreeNote) -- emitted when a tree note is activated
|
||||||
"""
|
"""
|
||||||
|
|
||||||
note_selected = Signal(object) # Note
|
activeNoteChanged = Signal(object) # Note
|
||||||
tree_selected = Signal(object) # TreeNote
|
|
||||||
|
|
||||||
def __init__(self, trove: Trove, parent: Optional[QWidget] = None):
|
def __init__(self, trove: Trove, parent: Optional[QWidget] = None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
@ -38,6 +37,8 @@ class NoteBrowser(QWidget):
|
||||||
layout.setContentsMargins(0, 0, 0, 0)
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
layout.setSpacing(2)
|
layout.setSpacing(2)
|
||||||
|
|
||||||
|
self._activeNote: Optional[Note] = None
|
||||||
|
|
||||||
self._tree = QTreeView()
|
self._tree = QTreeView()
|
||||||
self._tree.setModel(self._model)
|
self._tree.setModel(self._model)
|
||||||
self._tree.setHeaderHidden(True)
|
self._tree.setHeaderHidden(True)
|
||||||
|
|
@ -67,12 +68,7 @@ class NoteBrowser(QWidget):
|
||||||
|
|
||||||
def _on_activated(self, index: QModelIndex) -> None:
|
def _on_activated(self, index: QModelIndex) -> None:
|
||||||
note = index.data(Qt.ItemDataRole.UserRole)
|
note = index.data(Qt.ItemDataRole.UserRole)
|
||||||
if note is None:
|
self._handle_set_active_note(note)
|
||||||
return
|
|
||||||
if isinstance(note, TreeNote):
|
|
||||||
self.tree_selected.emit(note)
|
|
||||||
else:
|
|
||||||
self.note_selected.emit(note)
|
|
||||||
|
|
||||||
def _on_context_menu(self, pos) -> None:
|
def _on_context_menu(self, pos) -> None:
|
||||||
index = self._tree.indexAt(pos)
|
index = self._tree.indexAt(pos)
|
||||||
|
|
@ -105,6 +101,14 @@ class NoteBrowser(QWidget):
|
||||||
# Public API
|
# Public API
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _handle_set_active_note(self, note: Note | None) -> None:
|
||||||
|
"""Called by the controller to update the active note."""
|
||||||
|
if not isinstance(note, Note):
|
||||||
|
note = None
|
||||||
|
if self._activeNote != note:
|
||||||
|
self._activeNote = note
|
||||||
|
self.activeNoteChanged.emit(note)
|
||||||
|
|
||||||
def select_note(self, note: Note) -> None:
|
def select_note(self, note: Note) -> None:
|
||||||
"""Programmatically select the node matching the given note object."""
|
"""Programmatically select the node matching the given note object."""
|
||||||
match = self._find_index(self._model.index(0, 0, QModelIndex()), note)
|
match = self._find_index(self._model.index(0, 0, QModelIndex()), note)
|
||||||
|
|
|
||||||
32
trovedb/qgui/note_tool_stack.py
Normal file
32
trovedb/qgui/note_tool_stack.py
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
from typing import Generator
|
||||||
|
|
||||||
|
from PySide6.QtCore import Property, Slot
|
||||||
|
from PySide6.QtWidgets import QStackedWidget, QWidget, QLabel
|
||||||
|
|
||||||
|
import trovedb.trove as tr
|
||||||
|
|
||||||
|
from .tool import Tool
|
||||||
|
from .tool_basic_editor import ToolBasicEditor
|
||||||
|
|
||||||
|
|
||||||
|
class NoteToolStack(QStackedWidget):
|
||||||
|
def __init__(self, parent: QWidget | None = None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.addWidget(QLabel("No note selected"))
|
||||||
|
|
||||||
|
@Slot(object)
|
||||||
|
def onNoteSelected(self, note: tr.Note):
|
||||||
|
for tool in self._iter_tools():
|
||||||
|
if tool.note == note:
|
||||||
|
self.setCurrentWidget(tool)
|
||||||
|
return
|
||||||
|
tool = ToolBasicEditor(note)
|
||||||
|
self.addWidget(tool)
|
||||||
|
self.setCurrentWidget(tool)
|
||||||
|
|
||||||
|
def _iter_tools(self) -> Generator[Tool, None, None]:
|
||||||
|
for i in range(self.count()):
|
||||||
|
widget = self.widget(i)
|
||||||
|
if isinstance(widget, Tool):
|
||||||
|
yield widget
|
||||||
14
trovedb/qgui/tool.py
Normal file
14
trovedb/qgui/tool.py
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
"""Tool Base Class"""
|
||||||
|
|
||||||
|
from PySide6.QtWidgets import QWidget
|
||||||
|
|
||||||
|
import trovedb.trove as tr
|
||||||
|
|
||||||
|
class Tool(QWidget):
|
||||||
|
def __init__(self, note: tr.Note, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self._note = note
|
||||||
|
|
||||||
|
@property
|
||||||
|
def note(self) -> tr.Note:
|
||||||
|
return self._note
|
||||||
28
trovedb/qgui/tool_basic_editor.py
Normal file
28
trovedb/qgui/tool_basic_editor.py
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
"""Tool Supporting Basic Editor Functions"""
|
||||||
|
from typing import cast, Protocol
|
||||||
|
from PySide6.QtWidgets import QTextEdit, QVBoxLayout
|
||||||
|
|
||||||
|
import trovedb.trove as tr
|
||||||
|
from .tool import Tool
|
||||||
|
|
||||||
|
|
||||||
|
class ToolBasicEditor(Tool):
|
||||||
|
def __init__(self, note, parent=None):
|
||||||
|
super().__init__(note, parent)
|
||||||
|
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
layout.setSpacing(0)
|
||||||
|
|
||||||
|
self._text_edit = QTextEdit()
|
||||||
|
layout.addWidget(self._text_edit)
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def _refresh_blob(self, note: tr.Blob):
|
||||||
|
self._text_edit.setPlainText(note.read().decode("utf-8"))
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
if isinstance(self.note, tr.Blob):
|
||||||
|
self._refresh_blob(cast(tr.Blob, self.note))
|
||||||
|
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue