Update item change signals
This commit is contained in:
@@ -297,10 +297,6 @@ class NWIndex:
|
||||
self._rootChange[tItem.itemRoot] = nowTime
|
||||
if not blockSignal:
|
||||
tItem.notifyToRefresh()
|
||||
SHARED.indexSignalProxy({
|
||||
"event": "scanText",
|
||||
"handle": tHandle,
|
||||
})
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -75,6 +75,13 @@ class nwTrinary(Enum):
|
||||
POSITIVE = 1
|
||||
|
||||
|
||||
class nwChange(Enum):
|
||||
|
||||
CREATE = 0
|
||||
UPDATE = 1
|
||||
DELETE = 2
|
||||
|
||||
|
||||
class nwDocMode(Enum):
|
||||
|
||||
VIEW = 0
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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?")):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
##
|
||||
|
||||
Reference in New Issue
Block a user