From 9990ebf193b9fc67eed7e9029f3089ab1aebf847 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 22 Mar 2025 20:25:34 +0100 Subject: [PATCH] Handle novel model refresh scenarios --- novelwriter/core/index.py | 3 +++ novelwriter/core/item.py | 6 ++++++ novelwriter/core/itemmodel.py | 5 ++++- novelwriter/core/tree.py | 10 ++++++++- novelwriter/gui/noveltree.py | 38 ++++++++++++++++++++++++++++++----- novelwriter/gui/projtree.py | 2 ++ novelwriter/guimain.py | 3 +++ novelwriter/shared.py | 3 ++- 8 files changed, 62 insertions(+), 8 deletions(-) diff --git a/novelwriter/core/index.py b/novelwriter/core/index.py index be8df2ed..398a49b2 100644 --- a/novelwriter/core/index.py +++ b/novelwriter/core/index.py @@ -123,6 +123,7 @@ class Index: def refreshNovelModel(self, tHandle: str) -> None: """Refresh a novel model.""" if model := self.getNovelModel(tHandle): + logger.debug("Refreshing novel model '%s'", tHandle) model.beginResetModel() model.clear() self._appendSubTreeToModel(tHandle, model) @@ -170,6 +171,8 @@ class Index: self.scanText(nwItem.itemHandle, text, blockSignal=True) self._indexBroken = False SHARED.emitIndexAvailable(self._project) + for tHandle in self._novelModels: + self.refreshNovelModel(tHandle) return def deleteHandle(self, tHandle: str) -> None: diff --git a/novelwriter/core/item.py b/novelwriter/core/item.py index 38a2dbcc..3bbb8cec 100644 --- a/novelwriter/core/item.py +++ b/novelwriter/core/item.py @@ -293,6 +293,12 @@ class NWItem: self._project.tree.refreshItems([self._handle]) return + def notifyNovelStructureChange(self) -> None: + """Notify that the structure of a novel has changed.""" + if self._root and self._class == nwItemClass.NOVEL: + self._project.tree.novelStructureChanged(self._root) + return + ## # Lookup Methods ## diff --git a/novelwriter/core/itemmodel.py b/novelwriter/core/itemmodel.py index a14b8cc0..4d52aabd 100644 --- a/novelwriter/core/itemmodel.py +++ b/novelwriter/core/itemmodel.py @@ -193,7 +193,7 @@ class ProjectNode: return self._parent def child(self, row: int) -> ProjectNode | None: - """Return a child ofg the node.""" + """Return a child of the node.""" if 0 <= row < len(self._children): return self._children[row] return None @@ -218,6 +218,7 @@ class ProjectNode: child._row = len(self._children) self._children.append(child) self._refreshChildrenPos() + self._item.notifyNovelStructureChange() return def takeChild(self, pos: int) -> ProjectNode | None: @@ -226,6 +227,7 @@ class ProjectNode: node = self._children.pop(pos) self._refreshChildrenPos() self.updateCount() + self._item.notifyNovelStructureChange() return node return None @@ -236,6 +238,7 @@ class ProjectNode: node = self._children.pop(source) self._children.insert(target, node) self._refreshChildrenPos() + self._item.notifyNovelStructureChange() return def setExpanded(self, state: bool) -> None: diff --git a/novelwriter/core/tree.py b/novelwriter/core/tree.py index 002ff811..be582526 100644 --- a/novelwriter/core/tree.py +++ b/novelwriter/core/tree.py @@ -60,7 +60,7 @@ class NWTree: also used for file names. """ - __slots__ = ("_project", "_model", "_items", "_nodes", "_trash") + __slots__ = ("_project", "_model", "_items", "_nodes", "_trash", "_ready") def __init__(self, project: NWProject) -> None: self._project = project @@ -68,6 +68,7 @@ class NWTree: self._items: dict[str, NWItem] = {} self._nodes: dict[str, ProjectNode] = {} self._trash = None + self._ready = False logger.debug("Ready: NWTree") return @@ -249,6 +250,7 @@ class NWTree: logger.error("Not all items could be added to project tree") self._trash = self._getTrashNode() + self._ready = True self._model.endInsertRows() self._model.layoutChanged.emit() @@ -278,6 +280,12 @@ class NWTree: self._model.layoutChanged.emit() return + def novelStructureChanged(self, tHandle: str) -> None: + """Emit a novel structure change signal.""" + if self._ready: + SHARED.novelStructureChanged.emit(tHandle) + return + def checkConsistency(self, prefix: str) -> tuple[int, int]: """Check the project tree consistency. Also check the content folder and add back files that were discovered but were not diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py index b512ab51..3e02d750 100644 --- a/novelwriter/gui/noveltree.py +++ b/novelwriter/gui/noveltree.py @@ -84,6 +84,7 @@ class GuiNovelView(QWidget): self.setLayout(self.outerBox) # Function Mappings + self.setActive = self.novelBar.setActive self.getSelectedHandle = self.novelTree.getSelectedHandle return @@ -203,6 +204,9 @@ class GuiNovelToolBar(QWidget): self.novelView = novelView + self._active = False + self._refresh: dict[str, bool] = {} + iSz = SHARED.theme.baseIconSize self.setContentsMargins(0, 0, 0, 0) @@ -227,7 +231,7 @@ class GuiNovelToolBar(QWidget): # Refresh Button self.tbRefresh = NIconToolButton(self, iSz) self.tbRefresh.setToolTip(self.tr("Refresh")) - self.tbRefresh.clicked.connect(self._refreshNovelTree) + self.tbRefresh.clicked.connect(self._forceRefreshNovelTree) # More Options Menu self.mMore = QMenu(self) @@ -261,6 +265,9 @@ class GuiNovelToolBar(QWidget): self.updateTheme() + # Connect Signals + SHARED.novelStructureChanged.connect(self._refreshNovelTree) + logger.debug("Ready: GuiNovelToolBar") return @@ -316,16 +323,37 @@ class GuiNovelToolBar(QWidget): # self.novelView.novelTree.setLastColType(colType, doRefresh=doRefresh) return + def setActive(self, state: bool) -> None: + """Set the widget active state, which enables automatic tree + refresh when content structure changes. + """ + self._active = state + if self._active: + self._refreshNovelTree(self.novelValue.handle) + return + ## # Private Slots ## @pyqtSlot() - def _refreshNovelTree(self) -> None: + def _forceRefreshNovelTree(self) -> None: """Rebuild the current tree.""" - if rootHandle := self.novelValue.handle: - SHARED.project.index.refreshNovelModel(rootHandle) - # self.novelView.setCurrentNovel(SHARED.project.data.getLastHandle("novelTree")) + self._refresh[self.novelValue.handle] = True + self._refreshNovelTree(self.novelValue.handle) + return + + @pyqtSlot(str) + def _refreshNovelTree(self, tHandle: str) -> None: + """Refresh or schedule refresh of a novel tree.""" + if tHandle: + if self._active: + if self._refresh.get(tHandle, False): + SHARED.project.index.refreshNovelModel(tHandle) + self._refresh[tHandle] = False + else: + self._refresh[tHandle] = True + print(self._refresh) return @pyqtSlot() diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index 0d8575a2..7e15c2fa 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -1399,6 +1399,7 @@ class _TreeContextMenu(QMenu): if itemLayout == nwItemLayout.DOCUMENT and self._item.documentAllowed(): self._item.setLayout(nwItemLayout.DOCUMENT) self._item.notifyToRefresh() + self._item.notifyNovelStructureChange() elif itemLayout == nwItemLayout.NOTE: self._item.setLayout(nwItemLayout.NOTE) self._item.notifyToRefresh() @@ -1415,6 +1416,7 @@ class _TreeContextMenu(QMenu): self._item.setType(nwItemType.FILE) self._item.setLayout(nwItemLayout.DOCUMENT) self._item.notifyToRefresh() + self._item.notifyNovelStructureChange() elif msgYes and itemLayout == nwItemLayout.NOTE: self._item.setType(nwItemType.FILE) self._item.setLayout(nwItemLayout.NOTE) diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index 30467411..98b2c7ef 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -1163,15 +1163,18 @@ class GuiMain(QMainWindow): elif view == nwView.PROJECT: self.mainStack.setCurrentWidget(self.splitMain) self.projStack.setCurrentWidget(self.projView) + self.novelView.setActive(False) elif view == nwView.NOVEL: self.mainStack.setCurrentWidget(self.splitMain) self.projStack.setCurrentWidget(self.novelView) + self.novelView.setActive(True) elif view == nwView.SEARCH: self.mainStack.setCurrentWidget(self.splitMain) self.projStack.setCurrentWidget(self.projSearch) self.projSearch.beginSearch( self.docEditor.getSelectedText() if self.docEditor.anyFocus() else "" ) + self.novelView.setActive(False) elif view == nwView.OUTLINE: self.mainStack.setCurrentWidget(self.outlineView) return diff --git a/novelwriter/shared.py b/novelwriter/shared.py index 588252d9..17b0a58f 100644 --- a/novelwriter/shared.py +++ b/novelwriter/shared.py @@ -63,10 +63,11 @@ class SharedData(QObject): indexChangedTags = pyqtSignal(list, list) indexCleared = pyqtSignal() mainClockTick = pyqtSignal() + novelStructureChanged = pyqtSignal(str) projectItemChanged = pyqtSignal(str, Enum) - rootFolderChanged = pyqtSignal(str, Enum) projectStatusChanged = pyqtSignal(bool) projectStatusMessage = pyqtSignal(str) + rootFolderChanged = pyqtSignal(str, Enum) spellLanguageChanged = pyqtSignal(str, str) statusLabelsChanged = pyqtSignal(str)