Handle novel model refresh scenarios

This commit is contained in:
Veronica Berglyd Olsen
2025-03-22 20:25:34 +01:00
parent edf765f91f
commit 9990ebf193
8 changed files with 62 additions and 8 deletions
+3
View File
@@ -123,6 +123,7 @@ class Index:
def refreshNovelModel(self, tHandle: str) -> None: def refreshNovelModel(self, tHandle: str) -> None:
"""Refresh a novel model.""" """Refresh a novel model."""
if model := self.getNovelModel(tHandle): if model := self.getNovelModel(tHandle):
logger.debug("Refreshing novel model '%s'", tHandle)
model.beginResetModel() model.beginResetModel()
model.clear() model.clear()
self._appendSubTreeToModel(tHandle, model) self._appendSubTreeToModel(tHandle, model)
@@ -170,6 +171,8 @@ class Index:
self.scanText(nwItem.itemHandle, text, blockSignal=True) self.scanText(nwItem.itemHandle, text, blockSignal=True)
self._indexBroken = False self._indexBroken = False
SHARED.emitIndexAvailable(self._project) SHARED.emitIndexAvailable(self._project)
for tHandle in self._novelModels:
self.refreshNovelModel(tHandle)
return return
def deleteHandle(self, tHandle: str) -> None: def deleteHandle(self, tHandle: str) -> None:
+6
View File
@@ -293,6 +293,12 @@ class NWItem:
self._project.tree.refreshItems([self._handle]) self._project.tree.refreshItems([self._handle])
return 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 # Lookup Methods
## ##
+4 -1
View File
@@ -193,7 +193,7 @@ class ProjectNode:
return self._parent return self._parent
def child(self, row: int) -> ProjectNode | None: 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): if 0 <= row < len(self._children):
return self._children[row] return self._children[row]
return None return None
@@ -218,6 +218,7 @@ class ProjectNode:
child._row = len(self._children) child._row = len(self._children)
self._children.append(child) self._children.append(child)
self._refreshChildrenPos() self._refreshChildrenPos()
self._item.notifyNovelStructureChange()
return return
def takeChild(self, pos: int) -> ProjectNode | None: def takeChild(self, pos: int) -> ProjectNode | None:
@@ -226,6 +227,7 @@ class ProjectNode:
node = self._children.pop(pos) node = self._children.pop(pos)
self._refreshChildrenPos() self._refreshChildrenPos()
self.updateCount() self.updateCount()
self._item.notifyNovelStructureChange()
return node return node
return None return None
@@ -236,6 +238,7 @@ class ProjectNode:
node = self._children.pop(source) node = self._children.pop(source)
self._children.insert(target, node) self._children.insert(target, node)
self._refreshChildrenPos() self._refreshChildrenPos()
self._item.notifyNovelStructureChange()
return return
def setExpanded(self, state: bool) -> None: def setExpanded(self, state: bool) -> None:
+9 -1
View File
@@ -60,7 +60,7 @@ class NWTree:
also used for file names. also used for file names.
""" """
__slots__ = ("_project", "_model", "_items", "_nodes", "_trash") __slots__ = ("_project", "_model", "_items", "_nodes", "_trash", "_ready")
def __init__(self, project: NWProject) -> None: def __init__(self, project: NWProject) -> None:
self._project = project self._project = project
@@ -68,6 +68,7 @@ class NWTree:
self._items: dict[str, NWItem] = {} self._items: dict[str, NWItem] = {}
self._nodes: dict[str, ProjectNode] = {} self._nodes: dict[str, ProjectNode] = {}
self._trash = None self._trash = None
self._ready = False
logger.debug("Ready: NWTree") logger.debug("Ready: NWTree")
return return
@@ -249,6 +250,7 @@ class NWTree:
logger.error("Not all items could be added to project tree") logger.error("Not all items could be added to project tree")
self._trash = self._getTrashNode() self._trash = self._getTrashNode()
self._ready = True
self._model.endInsertRows() self._model.endInsertRows()
self._model.layoutChanged.emit() self._model.layoutChanged.emit()
@@ -278,6 +280,12 @@ class NWTree:
self._model.layoutChanged.emit() self._model.layoutChanged.emit()
return 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]: def checkConsistency(self, prefix: str) -> tuple[int, int]:
"""Check the project tree consistency. Also check the content """Check the project tree consistency. Also check the content
folder and add back files that were discovered but were not folder and add back files that were discovered but were not
+33 -5
View File
@@ -84,6 +84,7 @@ class GuiNovelView(QWidget):
self.setLayout(self.outerBox) self.setLayout(self.outerBox)
# Function Mappings # Function Mappings
self.setActive = self.novelBar.setActive
self.getSelectedHandle = self.novelTree.getSelectedHandle self.getSelectedHandle = self.novelTree.getSelectedHandle
return return
@@ -203,6 +204,9 @@ class GuiNovelToolBar(QWidget):
self.novelView = novelView self.novelView = novelView
self._active = False
self._refresh: dict[str, bool] = {}
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
self.setContentsMargins(0, 0, 0, 0) self.setContentsMargins(0, 0, 0, 0)
@@ -227,7 +231,7 @@ class GuiNovelToolBar(QWidget):
# Refresh Button # Refresh Button
self.tbRefresh = NIconToolButton(self, iSz) self.tbRefresh = NIconToolButton(self, iSz)
self.tbRefresh.setToolTip(self.tr("Refresh")) self.tbRefresh.setToolTip(self.tr("Refresh"))
self.tbRefresh.clicked.connect(self._refreshNovelTree) self.tbRefresh.clicked.connect(self._forceRefreshNovelTree)
# More Options Menu # More Options Menu
self.mMore = QMenu(self) self.mMore = QMenu(self)
@@ -261,6 +265,9 @@ class GuiNovelToolBar(QWidget):
self.updateTheme() self.updateTheme()
# Connect Signals
SHARED.novelStructureChanged.connect(self._refreshNovelTree)
logger.debug("Ready: GuiNovelToolBar") logger.debug("Ready: GuiNovelToolBar")
return return
@@ -316,16 +323,37 @@ class GuiNovelToolBar(QWidget):
# self.novelView.novelTree.setLastColType(colType, doRefresh=doRefresh) # self.novelView.novelTree.setLastColType(colType, doRefresh=doRefresh)
return 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 # Private Slots
## ##
@pyqtSlot() @pyqtSlot()
def _refreshNovelTree(self) -> None: def _forceRefreshNovelTree(self) -> None:
"""Rebuild the current tree.""" """Rebuild the current tree."""
if rootHandle := self.novelValue.handle: self._refresh[self.novelValue.handle] = True
SHARED.project.index.refreshNovelModel(rootHandle) self._refreshNovelTree(self.novelValue.handle)
# self.novelView.setCurrentNovel(SHARED.project.data.getLastHandle("novelTree")) 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 return
@pyqtSlot() @pyqtSlot()
+2
View File
@@ -1399,6 +1399,7 @@ class _TreeContextMenu(QMenu):
if itemLayout == nwItemLayout.DOCUMENT and self._item.documentAllowed(): if itemLayout == nwItemLayout.DOCUMENT and self._item.documentAllowed():
self._item.setLayout(nwItemLayout.DOCUMENT) self._item.setLayout(nwItemLayout.DOCUMENT)
self._item.notifyToRefresh() self._item.notifyToRefresh()
self._item.notifyNovelStructureChange()
elif itemLayout == nwItemLayout.NOTE: elif itemLayout == nwItemLayout.NOTE:
self._item.setLayout(nwItemLayout.NOTE) self._item.setLayout(nwItemLayout.NOTE)
self._item.notifyToRefresh() self._item.notifyToRefresh()
@@ -1415,6 +1416,7 @@ class _TreeContextMenu(QMenu):
self._item.setType(nwItemType.FILE) self._item.setType(nwItemType.FILE)
self._item.setLayout(nwItemLayout.DOCUMENT) self._item.setLayout(nwItemLayout.DOCUMENT)
self._item.notifyToRefresh() self._item.notifyToRefresh()
self._item.notifyNovelStructureChange()
elif msgYes and itemLayout == nwItemLayout.NOTE: elif msgYes and itemLayout == nwItemLayout.NOTE:
self._item.setType(nwItemType.FILE) self._item.setType(nwItemType.FILE)
self._item.setLayout(nwItemLayout.NOTE) self._item.setLayout(nwItemLayout.NOTE)
+3
View File
@@ -1163,15 +1163,18 @@ class GuiMain(QMainWindow):
elif view == nwView.PROJECT: elif view == nwView.PROJECT:
self.mainStack.setCurrentWidget(self.splitMain) self.mainStack.setCurrentWidget(self.splitMain)
self.projStack.setCurrentWidget(self.projView) self.projStack.setCurrentWidget(self.projView)
self.novelView.setActive(False)
elif view == nwView.NOVEL: elif view == nwView.NOVEL:
self.mainStack.setCurrentWidget(self.splitMain) self.mainStack.setCurrentWidget(self.splitMain)
self.projStack.setCurrentWidget(self.novelView) self.projStack.setCurrentWidget(self.novelView)
self.novelView.setActive(True)
elif view == nwView.SEARCH: elif view == nwView.SEARCH:
self.mainStack.setCurrentWidget(self.splitMain) self.mainStack.setCurrentWidget(self.splitMain)
self.projStack.setCurrentWidget(self.projSearch) self.projStack.setCurrentWidget(self.projSearch)
self.projSearch.beginSearch( self.projSearch.beginSearch(
self.docEditor.getSelectedText() if self.docEditor.anyFocus() else "" self.docEditor.getSelectedText() if self.docEditor.anyFocus() else ""
) )
self.novelView.setActive(False)
elif view == nwView.OUTLINE: elif view == nwView.OUTLINE:
self.mainStack.setCurrentWidget(self.outlineView) self.mainStack.setCurrentWidget(self.outlineView)
return return
+2 -1
View File
@@ -63,10 +63,11 @@ class SharedData(QObject):
indexChangedTags = pyqtSignal(list, list) indexChangedTags = pyqtSignal(list, list)
indexCleared = pyqtSignal() indexCleared = pyqtSignal()
mainClockTick = pyqtSignal() mainClockTick = pyqtSignal()
novelStructureChanged = pyqtSignal(str)
projectItemChanged = pyqtSignal(str, Enum) projectItemChanged = pyqtSignal(str, Enum)
rootFolderChanged = pyqtSignal(str, Enum)
projectStatusChanged = pyqtSignal(bool) projectStatusChanged = pyqtSignal(bool)
projectStatusMessage = pyqtSignal(str) projectStatusMessage = pyqtSignal(str)
rootFolderChanged = pyqtSignal(str, Enum)
spellLanguageChanged = pyqtSignal(str, str) spellLanguageChanged = pyqtSignal(str, str)
statusLabelsChanged = pyqtSignal(str) statusLabelsChanged = pyqtSignal(str)