Handle novel model refresh scenarios
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
##
|
##
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user