diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 04e9cf94..9f9beeea 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -90,20 +90,21 @@ class GuiDocEditor(QPlainTextEdit): ) # Custom Signals - statusMessage = pyqtSignal(str) + closeEditorRequest = pyqtSignal() docCountsChanged = pyqtSignal(str, int, int, int) docTextChanged = pyqtSignal(str, float) editedStatusChanged = pyqtSignal(bool) + itemHandleChanged = pyqtSignal(str) loadDocumentTagRequest = pyqtSignal(str, Enum) - novelStructureChanged = pyqtSignal() novelItemMetaChanged = pyqtSignal(str) - spellCheckStateChanged = pyqtSignal(bool) - closeDocumentRequest = pyqtSignal() - toggleFocusModeRequest = pyqtSignal() - requestProjectItemSelected = pyqtSignal(str, bool) - requestProjectItemRenamed = pyqtSignal(str, str) + novelStructureChanged = pyqtSignal() requestNewNoteCreation = pyqtSignal(str, nwItemClass) requestNextDocument = pyqtSignal(str, bool) + requestProjectItemRenamed = pyqtSignal(str, str) + requestProjectItemSelected = pyqtSignal(str, bool) + spellCheckStateChanged = pyqtSignal(bool) + toggleFocusModeRequest = pyqtSignal() + updateStatusMessage = pyqtSignal(str) def __init__(self, parent: QWidget) -> None: super().__init__(parent=parent) @@ -271,6 +272,8 @@ class GuiDocEditor(QPlainTextEdit): self.docFooter.setHandle(self._docHandle) self.docToolBar.setVisible(False) + self.itemHandleChanged.emit("") + return def updateTheme(self) -> None: @@ -430,12 +433,15 @@ class GuiDocEditor(QPlainTextEdit): self.setDocumentChanged(False) self._qDocument.clearUndoRedoStacks() self.docToolBar.setVisible(CONFIG.showEditToolBar) + self.itemHandleChanged.emit(tHandle) QApplication.restoreOverrideCursor() # Update the status bar if self._nwItem is not None: - self.statusMessage.emit(self.tr("Opened Document: {0}").format(self._nwItem.itemName)) + self.updateStatusMessage.emit( + self.tr("Opened Document: {0}").format(self._nwItem.itemName) + ) return True @@ -506,7 +512,7 @@ class GuiDocEditor(QPlainTextEdit): self.docFooter.updateInfo() # Update the status bar - self.statusMessage.emit(self.tr("Saved Document: {0}").format(self._nwItem.itemName)) + self.updateStatusMessage.emit(self.tr("Saved Document: {0}").format(self._nwItem.itemName)) return True @@ -701,7 +707,7 @@ class GuiDocEditor(QPlainTextEdit): self._qDocument.syntaxHighlighter.rehighlight() QApplication.restoreOverrideCursor() logger.debug("Document highlighted in %.3f ms", 1000*(time() - start)) - self.statusMessage.emit(self.tr("Spell check complete")) + self.updateStatusMessage.emit(self.tr("Spell check complete")) return ## @@ -1274,7 +1280,7 @@ class GuiDocEditor(QPlainTextEdit): @pyqtSlot() def _closeCurrentDocument(self) -> None: """Close the document. Forwarded to the main Gui.""" - self.closeDocumentRequest.emit() + self.closeEditorRequest.emit() self.docToolBar.setVisible(False) return diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py index 5b33a5fb..c2a28c2b 100644 --- a/novelwriter/gui/noveltree.py +++ b/novelwriter/gui/noveltree.py @@ -87,7 +87,6 @@ class GuiNovelView(QWidget): # Function Mappings self.getSelectedHandle = self.novelTree.getSelectedHandle - self.setActiveHandle = self.novelTree.setActiveHandle return @@ -163,6 +162,12 @@ class GuiNovelView(QWidget): # Public Slots ## + @pyqtSlot(str) + def setActiveHandle(self, tHandle: str) -> None: + """Highlight the rows associated with a given handle.""" + self.novelTree.setActiveHandle(tHandle) + return + @pyqtSlot() def refreshTree(self) -> None: """Refresh the current tree.""" @@ -367,11 +372,11 @@ class GuiNovelTree(QTreeWidget): self.novelView = novelView # Internal Variables - self._treeMap = {} self._lastBuild = 0 self._lastCol = NovelTreeColumn.POV self._lastColSize = 0.25 self._actHandle = None + self._treeMap: dict[str, QTreeWidgetItem] = {} # Cached Strings self._povLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY]) @@ -540,25 +545,29 @@ class GuiNovelTree(QTreeWidget): self._lastColSize = minmax(colSize, 15, 75)/100.0 return - def setActiveHandle(self, tHandle: str | None, doScroll: bool = False) -> None: + def setActiveHandle(self, tHandle: str | None) -> None: """Highlight the rows associated with a given handle.""" didScroll = False - self._actHandle = tHandle - for i in range(self.topLevelItemCount()): - if tItem := self.topLevelItem(i): - if tItem.data(self.C_DATA, self.D_HANDLE) == tHandle: - tItem.setBackground(self.C_TITLE, self.palette().alternateBase()) - tItem.setBackground(self.C_WORDS, self.palette().alternateBase()) - tItem.setBackground(self.C_EXTRA, self.palette().alternateBase()) - tItem.setBackground(self.C_MORE, self.palette().alternateBase()) - if doScroll and not didScroll: - self.scrollToItem(tItem, QAbstractItemView.ScrollHint.PositionAtCenter) + brushOn = self.palette().alternateBase() + brushOff = self.palette().base() + if pHandle := self._actHandle: + for key, item in self._treeMap.items(): + if key.startswith(pHandle): + item.setBackground(self.C_TITLE, brushOff) + item.setBackground(self.C_WORDS, brushOff) + item.setBackground(self.C_EXTRA, brushOff) + item.setBackground(self.C_MORE, brushOff) + if tHandle: + for key, item in self._treeMap.items(): + if key.startswith(tHandle): + item.setBackground(self.C_TITLE, brushOn) + item.setBackground(self.C_WORDS, brushOn) + item.setBackground(self.C_EXTRA, brushOn) + item.setBackground(self.C_MORE, brushOn) + if not didScroll: + self.scrollToItem(item, QAbstractItemView.ScrollHint.PositionAtCenter) didScroll = True - else: - tItem.setBackground(self.C_TITLE, self.palette().base()) - tItem.setBackground(self.C_WORDS, self.palette().base()) - tItem.setBackground(self.C_EXTRA, self.palette().base()) - tItem.setBackground(self.C_MORE, self.palette().base()) + self._actHandle = tHandle or None return ## diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index 9863fb83..6bcae09d 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -211,6 +211,12 @@ class GuiProjectView(QWidget): self.projTree.setSelectedHandle(tHandle, doScroll=doScroll) return + @pyqtSlot(str) + def setActiveHandle(self, tHandle: str | None) -> None: + """Highlight the active handle.""" + self.projTree.setActiveHandle(tHandle) + return + @pyqtSlot(str) def updateItemValues(self, tHandle: str) -> None: """Update tree item.""" @@ -500,6 +506,7 @@ class GuiProjectTree(QTreeWidget): self._treeMap: dict[str, QTreeWidgetItem] = {} self._timeChanged = 0.0 self._popAlert = None + self._actHandle = None # Cached Translations self.trActive = self.tr("Active") @@ -1144,6 +1151,19 @@ class GuiProjectTree(QTreeWidget): return True + def setActiveHandle(self, tHandle: str | None) -> None: + """Highlight the rows associated with a given handle.""" + brushOn = self.palette().alternateBase() + brushOff = self.palette().base() + if (pHandle := self._actHandle) and (item := self._treeMap.get(pHandle)): + for i in range(self.columnCount()): + item.setBackground(i, brushOff) + if tHandle and (item := self._treeMap.get(tHandle)): + for i in range(self.columnCount()): + item.setBackground(i, brushOn) + self._actHandle = tHandle or None + return + def setExpandedFromHandle(self, tHandle: str | None, isExpanded: bool) -> None: """Iterate through items below tHandle and change expanded status for all child items. If tHandle is None, it affects the diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index e29d491d..dbdc2b26 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -249,11 +249,13 @@ class GuiMain(QMainWindow): self.projSearch.openDocumentSelectRequest.connect(self._openDocumentSelection) self.projSearch.selectedItemChanged.connect(self.itemDetails.updateViewBox) - self.docEditor.closeDocumentRequest.connect(self.closeDocEditor) + self.docEditor.closeEditorRequest.connect(self.closeDocEditor) self.docEditor.docCountsChanged.connect(self.itemDetails.updateCounts) self.docEditor.docCountsChanged.connect(self.projView.updateCounts) self.docEditor.docTextChanged.connect(self.projSearch.textChanged) self.docEditor.editedStatusChanged.connect(self.mainStatus.updateDocumentStatus) + self.docEditor.itemHandleChanged.connect(self.novelView.setActiveHandle) + self.docEditor.itemHandleChanged.connect(self.projView.setActiveHandle) self.docEditor.loadDocumentTagRequest.connect(self._followTag) self.docEditor.novelItemMetaChanged.connect(self.novelView.updateNovelItemMeta) self.docEditor.novelStructureChanged.connect(self.novelView.refreshTree) @@ -262,8 +264,8 @@ class GuiMain(QMainWindow): self.docEditor.requestProjectItemRenamed.connect(self.projView.renameTreeItem) self.docEditor.requestProjectItemSelected.connect(self.projView.setSelectedHandle) self.docEditor.spellCheckStateChanged.connect(self.mainMenu.setSpellCheckState) - self.docEditor.statusMessage.connect(self.mainStatus.setStatusMessage) self.docEditor.toggleFocusModeRequest.connect(self.toggleFocusMode) + self.docEditor.updateStatusMessage.connect(self.mainStatus.setStatusMessage) self.docViewer.closeDocumentRequest.connect(self.closeDocViewer) self.docViewer.documentLoaded.connect(self.docViewerPanel.updateHandle) @@ -518,8 +520,6 @@ class GuiMain(QMainWindow): SHARED.setFocusMode(False) self.saveDocument() self.docEditor.clearEditor() - if not beforeOpen: - self.novelView.setActiveHandle(None) return def openDocument( @@ -554,7 +554,6 @@ class GuiMain(QMainWindow): if self.docEditor.loadText(tHandle, tLine): SHARED.project.data.setLastHandle(tHandle, "editor") self.projView.setSelectedHandle(tHandle, doScroll=doScroll) - self.novelView.setActiveHandle(tHandle, doScroll=doScroll) if changeFocus: self.docEditor.setFocus() else: