Re-implement word counters

This commit is contained in:
Veronica Berglyd Olsen
2024-11-21 00:14:54 +01:00
parent 2f71ec68d8
commit 55eed706fb
6 changed files with 50 additions and 76 deletions
+15 -4
View File
@@ -79,6 +79,7 @@ class ProjectNode:
self._cache: dict[int, str | QIcon | Qt.AlignmentFlag] = {}
self._flags = NODE_FLAGS
self.refresh()
self.updateCount()
return
def __repr__(self) -> str:
@@ -95,12 +96,19 @@ class ProjectNode:
@property
def item(self) -> NWItem:
"""The project item of the node."""
return self._item
@property
def children(self) -> list[ProjectNode]:
"""All children of the node."""
return self._children
@property
def count(self) -> int:
"""The count of the node."""
return self._count
##
# Data Maintenance
##
@@ -127,11 +135,10 @@ class ProjectNode:
self._cache[C_STATUS_TIP] = sText
self._cache[C_STATUS_ICON] = sIcon
self.updateCount()
return
def updateCount(self, propagate: bool = True) -> None:
"""Update counts, and propagate upwards in the tree."""
self._count = self._item.wordCount + sum(c._count for c in self._children)
self._cache[C_COUNT_TEXT] = f"{self._count:n}"
if propagate and (parent := self._parent):
@@ -143,9 +150,11 @@ class ProjectNode:
##
def row(self) -> int:
"""Return the node's row number."""
return self._row
def childCount(self) -> int:
"""Return the number of children of the node."""
return len(self._children)
def data(self, column: int, role: Qt.ItemDataRole) -> T_NodeData:
@@ -157,9 +166,11 @@ class ProjectNode:
return self._flags
def parent(self) -> ProjectNode | None:
"""Return the parent of the node."""
return self._parent
def child(self, row: int) -> ProjectNode | None:
"""Return a child ofg the node."""
if 0 <= row < len(self._children):
return self._children[row]
return None
@@ -366,9 +377,9 @@ class ProjectModel(QAbstractItemModel):
return self.createIndex(node.row(), 0, node)
return QModelIndex()
def indexFromNode(self, node: ProjectNode) -> QModelIndex:
def indexFromNode(self, node: ProjectNode, column: int = 0) -> QModelIndex:
"""Get the index representing a node in the model."""
return self.createIndex(node.row(), 0, node)
return self.createIndex(node.row(), column, node)
def rootIndex(self) -> QModelIndex:
"""Get the index representing the root."""
+5
View File
@@ -145,6 +145,11 @@ class NWProject:
"""Return total edit time, including the current session."""
return self._data.editTime + round(time() - self._session.start)
@property
def currentTotalCount(self) -> int:
"""Return the current total word count from the tree."""
return self._tree.model.root.count
##
# Item Methods
##
+9 -9
View File
@@ -230,22 +230,22 @@ class NWTree:
return
def refreshItems(self, items: list[str], isRange: bool = False) -> None:
def refreshItems(self, items: list[str]) -> None:
"""Refresh these items on the GUI. If they are an ordered range,
also set the isRange flag to True.
"""
indices = []
change = False
for tHandle in items:
if node := self._nodes.get(tHandle):
node.refresh()
node.updateCount()
SHARED.projectSignalProxy({"event": "projectItem", "handle": tHandle})
indices.append(self._model.indexFromNode(node))
if isRange and len(indices) >= 2:
self._model.dataChanged.emit(indices[0], indices[-1])
else:
for index in indices:
self._model.dataChanged.emit(index, index)
self._project.setProjectChanged(len(indices) > 0)
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)
return
def checkConsistency(self, prefix: str) -> tuple[int, int]:
+1 -2
View File
@@ -110,7 +110,6 @@ class GuiDocEditor(QPlainTextEdit):
# Custom Signals
closeEditorRequest = pyqtSignal()
docCountsChanged = pyqtSignal(str, int, int, int)
docTextChanged = pyqtSignal(str, float)
editedStatusChanged = pyqtSignal(bool)
itemHandleChanged = pyqtSignal(str)
@@ -1281,7 +1280,7 @@ class GuiDocEditor(QPlainTextEdit):
self._nwItem.setCharCount(cCount)
self._nwItem.setWordCount(wCount)
self._nwItem.setParaCount(pCount)
self.docCountsChanged.emit(self._docHandle, cCount, wCount, pCount)
self._nwItem.notifyToRefresh()
self.docFooter.updateWordCount(wCount, False)
return
-47
View File
@@ -67,7 +67,6 @@ class GuiProjectView(QWidget):
# Signals triggered when the meta data values of items change
rootFolderChanged = pyqtSignal(str)
wordCountsChanged = pyqtSignal()
# Signals for user interaction with the project tree
selectedItemChanged = pyqtSignal(str)
@@ -241,13 +240,6 @@ class GuiProjectView(QWidget):
self.projTree.newTreeItem(nwItemType.FILE, copyDoc=tHandle)
return
@pyqtSlot(str, int, int, int)
def updateCounts(self, tHandle: str, cCount: int, wCount: int, pCount: int) -> None:
"""Slot for updating the word count of a specific item."""
self.projTree.propagateCount(tHandle, wCount, countChildren=True)
self.wordCountsChanged.emit()
return
@pyqtSlot(str)
def updateRootItem(self, tHandle: str) -> None:
"""Process root item changes."""
@@ -1067,45 +1059,6 @@ class GuiProjectTree(QTreeView):
# self.setTreeItemValues(nwItem)
return
def propagateCount(self, tHandle: str, newCount: int, countChildren: bool = False) -> None:
"""Recursive function setting the word count for a given item,
and propagating that count upwards in the tree until reaching a
root item. This function is more efficient than recalculating
everything each time the word count is updated, but is also
prone to diverging from the true values if the counts are not
properly reported to the function.
"""
# tItem = self._getTreeItem(tHandle)
# if tItem is None:
# return
# if countChildren:
# for i in range(tItem.childCount()):
# newCount += int(tItem.child(i).data(self.C_DATA, self.D_WORDS))
# tItem.setText(self.C_COUNT, f"{newCount:n}")
# tItem.setData(self.C_DATA, self.D_WORDS, int(newCount))
# pItem = tItem.parent()
# if pItem is None:
# return
# pCount = 0
# pHandle = None
# for i in range(pItem.childCount()):
# pCount += int(pItem.child(i).data(self.C_DATA, self.D_WORDS))
# pHandle = pItem.data(self.C_DATA, self.D_HANDLE)
# if pHandle:
# if SHARED.project.tree.checkType(pHandle, nwItemType.FILE):
# # A file has an internal word count we need to account
# # for, but a folder always has 0 words on its own.
# pCount += SHARED.project.index.getCounts(pHandle)[1]
# self.propagateCount(pHandle, pCount, countChildren=False)
return
class _UpdatableMenu(QMenu):
+20 -14
View File
@@ -242,7 +242,6 @@ class GuiMain(QMainWindow):
self.projView.rootFolderChanged.connect(self.outlineView.updateRootItem)
self.projView.rootFolderChanged.connect(self.projView.updateRootItem)
self.projView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
self.projView.wordCountsChanged.connect(self._updateStatusWordCount)
self.novelView.openDocumentRequest.connect(self._openDocument)
self.novelView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
@@ -251,8 +250,6 @@ class GuiMain(QMainWindow):
self.projSearch.selectedItemChanged.connect(self.itemDetails.updateViewBox)
self.docEditor.closeEditorRequest.connect(self.closeDocEditor)
self.docEditor.docCountsChanged.connect(self.itemDetails.updateCounts)
self.docEditor.docCountsChanged.connect(self.projView.updateCounts)
self.docEditor.docTextChanged.connect(self.projSearch.textChanged)
self.docEditor.editedStatusChanged.connect(self.mainStatus.updateDocumentStatus)
self.docEditor.itemHandleChanged.connect(self.novelView.setActiveHandle)
@@ -315,6 +312,9 @@ class GuiMain(QMainWindow):
self.keyEscape.setKey("Esc")
self.keyEscape.activated.connect(self._keyPressEscape)
# Internal Variables
self._lastTotalCount = 0
# Initialise Main GUI
self.initMain()
self.asProjTimer.start()
@@ -1226,8 +1226,10 @@ class GuiMain(QMainWindow):
self.mainStatus.setUserIdle(editIdle or userIdle)
SHARED.updateIdleTime(currTime, editIdle or userIdle)
self.mainStatus.updateTime(idleTime=SHARED.projectIdleTime)
if CONFIG.memInfo and int(currTime) % 5 == 0: # pragma: no cover
self.mainStatus.memInfo()
if int(currTime) % 5 == 0:
self._updateStatusWordCount()
if CONFIG.memInfo: # pragma: no cover
self.mainStatus.memInfo()
return
@pyqtSlot()
@@ -1255,15 +1257,19 @@ class GuiMain(QMainWindow):
if not SHARED.hasProject:
self.mainStatus.setProjectStats(0, 0)
SHARED.project.updateWordCounts()
if CONFIG.incNotesWCount:
iTotal = sum(SHARED.project.data.initCounts)
cTotal = sum(SHARED.project.data.currCounts)
self.mainStatus.setProjectStats(cTotal, cTotal - iTotal)
else:
iNovel, _ = SHARED.project.data.initCounts
cNovel, _ = SHARED.project.data.currCounts
self.mainStatus.setProjectStats(cNovel, cNovel - iNovel)
currentTotalCount = SHARED.project.currentTotalCount
if self._lastTotalCount != currentTotalCount:
self._lastTotalCount = currentTotalCount
SHARED.project.updateWordCounts()
if CONFIG.incNotesWCount:
iTotal = sum(SHARED.project.data.initCounts)
cTotal = sum(SHARED.project.data.currCounts)
self.mainStatus.setProjectStats(cTotal, cTotal - iTotal)
else:
iNovel, _ = SHARED.project.data.initCounts
cNovel, _ = SHARED.project.data.currCounts
self.mainStatus.setProjectStats(cNovel, cNovel - iNovel)
return