Update item change signals

This commit is contained in:
Veronica Berglyd Olsen
2024-11-22 00:15:12 +01:00
parent e0b27317f3
commit ffe6cd0a65
11 changed files with 90 additions and 64 deletions
-4
View File
@@ -297,10 +297,6 @@ class NWIndex:
self._rootChange[tItem.itemRoot] = nowTime
if not blockSignal:
tItem.notifyToRefresh()
SHARED.indexSignalProxy({
"event": "scanText",
"handle": tHandle,
})
return True
+7 -3
View File
@@ -78,6 +78,7 @@ class ProjectNode:
self._row = 0
self._cache: dict[int, T_NodeData] = {}
self._flags = NODE_FLAGS
self._count = 0
self.refresh()
self.updateCount()
return
@@ -193,7 +194,6 @@ class ProjectNode:
else:
child._row = len(self._children)
self._children.append(child)
self.updateCount()
return
def takeChild(self, pos: int) -> ProjectNode | None:
@@ -450,8 +450,12 @@ class ProjectModel(QAbstractItemModel):
for node in pruned:
if node.item.itemParent not in handles:
index = self.indexFromNode(node)
if child := self.removeChild(index.parent(), index.row()):
self.insertChild(child, target, pos)
if temp := self.removeChild(index.parent(), index.row()):
self.insertChild(temp, target, pos)
for child in reversed(node.allChildren()):
node._updateRelationships(child)
child.item.notifyToRefresh()
node.item.notifyToRefresh()
return
##
+18 -10
View File
@@ -36,7 +36,7 @@ from novelwriter import SHARED
from novelwriter.constants import nwFiles, nwLabels, trConst
from novelwriter.core.item import NWItem
from novelwriter.core.itemmodel import ProjectModel, ProjectNode
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
from novelwriter.enum import nwChange, nwItemClass, nwItemLayout, nwItemType
from novelwriter.error import logException
if TYPE_CHECKING: # pragma: no cover
@@ -90,6 +90,8 @@ class NWTree:
@property
def trash(self) -> ProjectNode | None:
"""Return trash node, if it exists."""
if self._trash:
return self._trash
return self._getTrashNode()
@property
@@ -108,8 +110,8 @@ class NWTree:
"""Clear the item tree entirely."""
oldModel = self._model
self._model = ProjectModel(self)
self._items = {}
self._nodes = {}
self._items.clear()
self._nodes.clear()
self._trash = None
oldModel.deleteLater()
del oldModel
@@ -124,7 +126,7 @@ class NWTree:
self._model.insertChild(node, index, pos)
self._nodes[item.itemHandle] = node
self._items[item.itemHandle] = item
self._project.setProjectChanged(True)
self._itemChange(item.itemHandle, nwChange.CREATE)
else:
logger.error("Could not locate parent of '%s'", item.itemHandle)
return False
@@ -133,7 +135,7 @@ class NWTree:
self._model.insertChild(node, QModelIndex(), pos)
self._nodes[item.itemHandle] = node
self._items[item.itemHandle] = item
self._project.setProjectChanged(True)
self._itemChange(item.itemHandle, nwChange.CREATE)
else:
logger.error("Invalid project item '%s'", item.itemHandle)
return False
@@ -144,6 +146,7 @@ class NWTree:
if (node := self._nodes.get(tHandle)) and tHandle in self._items:
index = self._model.indexFromNode(node)
if index.isValid() and self._model.removeChild(index.parent(), index.row()):
self._itemChange(tHandle, nwChange.DELETE)
del self._nodes[tHandle]
del self._items[tHandle]
return True
@@ -234,18 +237,14 @@ class NWTree:
"""Refresh these items on the GUI. If they are an ordered range,
also set the isRange flag to True.
"""
change = False
for tHandle in items:
if node := self._nodes.get(tHandle):
node.refresh()
node.updateCount()
SHARED.projectSignalProxy({"event": "projectItem", "handle": tHandle})
indexS = self._model.indexFromNode(node, 0)
indexE = self._model.indexFromNode(node, 3)
self._model.dataChanged.emit(indexS, indexE)
change = True
if change:
self._project.setProjectChanged(True)
self._itemChange(tHandle, nwChange.UPDATE)
return
def refreshAllItems(self) -> None:
@@ -463,6 +462,13 @@ class NWTree:
# Internal Functions
##
def _itemChange(self, tHandle: str, change: nwChange) -> None:
"""Signal item change and notify project."""
logger.debug("Item change: %s -> %s", tHandle, change.name)
self._project.setProjectChanged(True)
SHARED.projectSignalProxy({"event": "itemChanged", "handle": tHandle, "change": change})
return
def _getTrashNode(self) -> ProjectNode | None:
"""Get the trash node. If it doesn't exist, create it."""
for node in self._model.root.children:
@@ -483,6 +489,7 @@ class NWTree:
if parent := self._nodes.get(pHandle):
node = ProjectNode(item)
parent.addChild(node)
parent.updateCount()
self._items[handle] = item
self._nodes[handle] = node
elif pHandle in items:
@@ -491,6 +498,7 @@ class NWTree:
elif item.isRootType():
node = ProjectNode(item)
self._model.root.addChild(node)
self._model.root.updateCount()
self._items[handle] = item
self._nodes[handle] = node
return remains
+7
View File
@@ -75,6 +75,13 @@ class nwTrinary(Enum):
POSITIVE = 1
class nwChange(Enum):
CREATE = 0
UPDATE = 1
DELETE = 2
class nwDocMode(Enum):
VIEW = 0
+5 -5
View File
@@ -57,8 +57,8 @@ from novelwriter.common import decodeMimeHandles, minmax, qtLambda, transferCase
from novelwriter.constants import nwConst, nwKeyWords, nwShortcode, nwUnicode
from novelwriter.core.document import NWDocument
from novelwriter.enum import (
nwComment, nwDocAction, nwDocInsert, nwDocMode, nwItemClass, nwItemType,
nwTrinary
nwChange, nwComment, nwDocAction, nwDocInsert, nwDocMode, nwItemClass,
nwItemType, nwTrinary
)
from novelwriter.extensions.configlayout import NColourLabel
from novelwriter.extensions.eventfilters import WheelEventFilter
@@ -1064,12 +1064,12 @@ class GuiDocEditor(QPlainTextEdit):
# Public Slots
##
@pyqtSlot(str)
def updateDocInfo(self, tHandle: str) -> None:
@pyqtSlot(str, Enum)
def onProjectItemChanged(self, tHandle: str, change: nwChange) -> None:
"""Called when an item label is changed to check if the document
title bar needs updating,
"""
if tHandle and tHandle == self._docHandle:
if tHandle == self._docHandle and change == nwChange.UPDATE:
self.docHeader.setHandle(tHandle)
self.docFooter.updateInfo()
self.updateDocMargins()
+4 -4
View File
@@ -43,7 +43,7 @@ from PyQt5.QtWidgets import (
from novelwriter import CONFIG, SHARED
from novelwriter.common import decodeMimeHandles, qtLambda
from novelwriter.constants import nwConst, nwStyles, nwUnicode
from novelwriter.enum import nwDocAction, nwDocMode, nwItemType
from novelwriter.enum import nwChange, nwDocAction, nwDocMode, nwItemType
from novelwriter.error import logException
from novelwriter.extensions.configlayout import NColourLabel
from novelwriter.extensions.eventfilters import WheelEventFilter
@@ -346,10 +346,10 @@ class GuiDocViewer(QTextBrowser):
# Public Slots
##
@pyqtSlot(str)
def updateDocInfo(self, tHandle: str) -> None:
@pyqtSlot(str, Enum)
def onProjectItemChanged(self, tHandle: str, change: nwChange) -> None:
"""Update the header title bar if needed."""
if tHandle and tHandle == self._docHandle:
if tHandle == self._docHandle and change == nwChange.UPDATE:
self.docHeader.setHandle(tHandle)
self.updateDocMargins()
return
+3 -3
View File
@@ -37,7 +37,7 @@ from novelwriter import CONFIG, SHARED
from novelwriter.common import checkInt
from novelwriter.constants import nwLabels, nwLists, nwStyles, trConst
from novelwriter.core.index import IndexHeading, IndexItem
from novelwriter.enum import nwDocMode, nwItemClass
from novelwriter.enum import nwChange, nwDocMode, nwItemClass
from novelwriter.extensions.modified import NIconToolButton
from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON
from novelwriter.types import QtDecoration, QtHeaderFixed, QtHeaderToContents, QtUserRole
@@ -151,8 +151,8 @@ class GuiDocViewerPanel(QWidget):
self.updateHandle(self._lastHandle)
return
@pyqtSlot(str)
def projectItemChanged(self, tHandle: str) -> None:
@pyqtSlot(str, Enum)
def onProjectItemChanged(self, tHandle: str, change: nwChange) -> None:
"""Update meta data for project item."""
self.tabBackRefs.refreshDocument(tHandle)
activeOnly = self.aInactive.isChecked()
+18 -6
View File
@@ -25,12 +25,15 @@ from __future__ import annotations
import logging
from enum import Enum
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QGridLayout, QLabel, QWidget
from novelwriter import CONFIG, SHARED
from novelwriter.common import elide
from novelwriter.constants import nwLabels, nwStats, trConst
from novelwriter.enum import nwChange
from novelwriter.types import (
QtAlignLeft, QtAlignLeftBase, QtAlignRight, QtAlignRightBase,
QtAlignRightMiddle
@@ -220,12 +223,7 @@ class GuiItemDetails(QWidget):
self.updateViewBox(self._handle)
return
##
# Public Slots
##
@pyqtSlot(str)
def updateViewBox(self, tHandle: str) -> None:
def updateViewBox(self, tHandle: str | None) -> None:
"""Populate the details box from a given handle."""
if tHandle is None:
self.clearDetails()
@@ -286,6 +284,20 @@ class GuiItemDetails(QWidget):
return
##
# Public Slots
##
@pyqtSlot(str, Enum)
def onProjectItemChanged(self, tHandle: str, change: nwChange) -> None:
"""Process project item change."""
if tHandle == self._handle:
if change == nwChange.UPDATE:
self.updateViewBox(tHandle)
elif change == nwChange.DELETE:
self.updateViewBox(None)
return
@pyqtSlot(str, int, int, int)
def updateCounts(self, tHandle: str, cC: int, wC: int, pC: int) -> None:
"""Update the counts if the handle is the same as the one we're
+14 -13
View File
@@ -48,7 +48,7 @@ from novelwriter.dialogs.docmerge import GuiDocMerge
from novelwriter.dialogs.docsplit import GuiDocSplit
from novelwriter.dialogs.editlabel import GuiEditLabel
from novelwriter.dialogs.projectsettings import GuiProjectSettings
from novelwriter.enum import nwDocMode, nwItemClass, nwItemLayout, nwItemType
from novelwriter.enum import nwChange, nwDocMode, nwItemClass, nwItemLayout, nwItemType
from novelwriter.extensions.modified import NIconToolButton
from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
from novelwriter.types import (
@@ -215,10 +215,10 @@ class GuiProjectView(QWidget):
self.projTree.setActiveHandle(tHandle)
return
@pyqtSlot(str)
def projectItemChanged(self, tHandle: str) -> None:
@pyqtSlot(str, Enum)
def onProjectItemChanged(self, tHandle: str, change: nwChange) -> None:
"""Refresh other content when project item changed."""
self.projBar.processTemplateDocuments(tHandle)
self.projBar.processTemplateDocuments(tHandle, change)
return
@pyqtSlot(str)
@@ -409,16 +409,19 @@ class GuiProjectToolBar(QWidget):
"""Build the templates menu."""
for tHandle, _ in SHARED.project.tree.iterRoots(nwItemClass.TEMPLATE):
for dHandle in SHARED.project.tree.subTree(tHandle):
self.processTemplateDocuments(dHandle)
self.processTemplateDocuments(dHandle, nwChange.CREATE)
return
def processTemplateDocuments(self, tHandle: str) -> None:
def processTemplateDocuments(self, tHandle: str, change: nwChange) -> None:
"""Process change in tree items to update menu content."""
if item := SHARED.project.tree[tHandle]:
if item.isTemplateFile() and item.isActive:
self.mTemplates.addUpdate(tHandle, item.itemName, item.getMainIcon())
elif tHandle in self.mTemplates:
self.mTemplates.remove(tHandle)
if change in (nwChange.CREATE, nwChange.UPDATE):
if item := SHARED.project.tree[tHandle]:
if item.isTemplateFile() and item.isActive:
self.mTemplates.addUpdate(tHandle, item.itemName, item.getMainIcon())
elif tHandle in self.mTemplates:
self.mTemplates.remove(tHandle)
elif change == nwChange.DELETE and tHandle in self.mTemplates:
self.mTemplates.remove(tHandle)
return
##
@@ -916,9 +919,7 @@ class GuiProjectTree(QTreeView):
if node := model.node(index):
for child in reversed(node.allChildren()):
SHARED.project.removeItem(child.item.itemHandle)
self.projView.projBar.processTemplateDocuments(child.item.itemHandle)
SHARED.project.removeItem(node.item.itemHandle)
self.projView.projBar.processTemplateDocuments(node.item.itemHandle)
elif trashNode := SHARED.project.tree.trash:
if askFirst and not SHARED.question(self.tr("Move selected item(s) to Trash?")):
+5 -7
View File
@@ -213,14 +213,12 @@ class GuiMain(QMainWindow):
SHARED.indexChangedTags.connect(self.docEditor.updateChangedTags)
SHARED.indexChangedTags.connect(self.docViewerPanel.updateChangedTags)
SHARED.indexCleared.connect(self.docViewerPanel.indexWasCleared)
SHARED.indexScannedText.connect(self.docViewerPanel.projectItemChanged)
SHARED.indexScannedText.connect(self.itemDetails.updateViewBox)
SHARED.mainClockTick.connect(self._timeTick)
SHARED.projectItemChanged.connect(self.projView.projectItemChanged)
SHARED.projectItemChanged.connect(self.docEditor.updateDocInfo)
SHARED.projectItemChanged.connect(self.docViewer.updateDocInfo)
SHARED.projectItemChanged.connect(self.docViewerPanel.projectItemChanged)
SHARED.projectItemChanged.connect(self.itemDetails.updateViewBox)
SHARED.projectItemChanged.connect(self.docEditor.onProjectItemChanged)
SHARED.projectItemChanged.connect(self.docViewer.onProjectItemChanged)
SHARED.projectItemChanged.connect(self.docViewerPanel.onProjectItemChanged)
SHARED.projectItemChanged.connect(self.itemDetails.onProjectItemChanged)
SHARED.projectItemChanged.connect(self.projView.onProjectItemChanged)
SHARED.projectStatusChanged.connect(self.mainStatus.updateProjectStatus)
SHARED.projectStatusMessage.connect(self.mainStatus.setStatusMessage)
SHARED.spellLanguageChanged.connect(self.mainStatus.setLanguage)
+9 -9
View File
@@ -26,6 +26,7 @@ from __future__ import annotations
import logging
from enum import Enum
from pathlib import Path
from time import time
from typing import TYPE_CHECKING, TypeVar
@@ -37,7 +38,7 @@ from PyQt5.QtWidgets import QFileDialog, QFontDialog, QMessageBox, QWidget
from novelwriter.common import formatFileFilter
from novelwriter.constants import nwFiles
from novelwriter.core.spellcheck import NWSpellEnchant
from novelwriter.enum import nwItemClass
from novelwriter.enum import nwChange, nwItemClass
if TYPE_CHECKING: # pragma: no cover
from novelwriter.core.project import NWProject
@@ -60,9 +61,8 @@ class SharedData(QObject):
indexAvailable = pyqtSignal()
indexChangedTags = pyqtSignal(list, list)
indexCleared = pyqtSignal()
indexScannedText = pyqtSignal(str)
mainClockTick = pyqtSignal()
projectItemChanged = pyqtSignal(str)
projectItemChanged = pyqtSignal(str, Enum)
projectStatusChanged = pyqtSignal(bool)
projectStatusMessage = pyqtSignal(str)
spellLanguageChanged = pyqtSignal(str, str)
@@ -319,11 +319,9 @@ class SharedData(QObject):
def indexSignalProxy(self, data: dict) -> None:
"""Emit signals on behalf of the index."""
event = data.get("event")
logger.debug("Received '%s' event from the index", event)
logger.debug("Signal Proxy: %s", event)
if event == "updateTags":
self.indexChangedTags.emit(data.get("updated", []), data.get("deleted", []))
elif event == "scanText":
self.indexScannedText.emit(data.get("handle", ""))
elif event == "clearIndex":
self.indexCleared.emit()
elif event == "buildIndex":
@@ -333,11 +331,13 @@ class SharedData(QObject):
def projectSignalProxy(self, data: dict) -> None:
"""Emit signals on project data change."""
event = data.get("event")
logger.debug("Received '%s' event from project data", event)
logger.debug("Signal Proxy: %s", event)
if event == "statusLabels":
self.statusLabelsChanged.emit(data.get("kind", ""))
elif event == "projectItem":
self.projectItemChanged.emit(data.get("handle", ""))
elif event == "itemChanged":
self.projectItemChanged.emit(
data.get("handle", ""), data.get("change", nwChange.UPDATE)
)
return
##