Add project variables for character counts

This commit is contained in:
Veronica Berglyd Olsen
2025-04-29 22:00:53 +02:00
parent 8de6fd25e2
commit bd4a658bd9
8 changed files with 104 additions and 57 deletions
+20 -4
View File
@@ -897,9 +897,10 @@ class RecentProjects:
puuid = str(entry.get("uuid", "")) puuid = str(entry.get("uuid", ""))
title = str(entry.get("title", "")) title = str(entry.get("title", ""))
words = checkInt(entry.get("words", 0), 0) words = checkInt(entry.get("words", 0), 0)
chars = checkInt(entry.get("chars", 0), 0)
saved = checkInt(entry.get("time", 0), 0) saved = checkInt(entry.get("time", 0), 0)
if path and title: if path and title:
self._setEntry(puuid, path, title, words, saved) self._setEntry(puuid, path, title, words, chars, saved)
except Exception: except Exception:
logger.error("Could not load recent project cache") logger.error("Could not load recent project cache")
logException() logException()
@@ -932,7 +933,14 @@ class RecentProjects:
try: try:
if (remove := self._map.get(data.uuid)) and (remove != str(path)): if (remove := self._map.get(data.uuid)) and (remove != str(path)):
self.remove(remove) self.remove(remove)
self._setEntry(data.uuid, str(path), data.name, sum(data.currCounts), int(saved)) self._setEntry(
data.uuid,
str(path),
data.name,
sum(data.currCounts[:2]),
sum(data.currCounts[2:]),
int(saved),
)
self.saveCache() self.saveCache()
except Exception: except Exception:
pass pass
@@ -945,9 +953,17 @@ class RecentProjects:
self.saveCache() self.saveCache()
return return
def _setEntry(self, puuid: str, path: str, title: str, words: int, saved: int) -> None: def _setEntry(
self, puuid: str, path: str, title: str, words: int, chars: int, saved: int
) -> None:
"""Set an entry in the recent projects record.""" """Set an entry in the recent projects record."""
self._data[path] = {"uuid": puuid, "title": title, "words": words, "time": saved} self._data[path] = {
"uuid": puuid,
"title": title,
"words": words,
"chars": chars,
"time": saved,
}
if puuid: if puuid:
self._map[puuid] = path self._map[puuid] = path
return return
+6 -6
View File
@@ -367,7 +367,7 @@ class NWProject:
# Often, the index needs to be rebuilt when updating format # Often, the index needs to be rebuilt when updating format
self._index.rebuild() self._index.rebuild()
self.updateWordCounts() self.updateCounts()
self._session.startSession() self._session.startSession()
self.setProjectChanged(False) self.setProjectChanged(False)
self._valid = True self._valid = True
@@ -397,7 +397,7 @@ class NWProject:
else: else:
self._data.incSaveCount() self._data.incSaveCount()
self.updateWordCounts() self.updateCounts()
self.countStatus() self.countStatus()
xmlWriter = self._storage.getXmlWriter() xmlWriter = self._storage.getXmlWriter()
@@ -515,10 +515,10 @@ class NWProject:
# Class Methods # Class Methods
## ##
def updateWordCounts(self) -> None: def updateCounts(self) -> None:
"""Update the total word count values.""" """Update the total word and character count values."""
novel, notes = self._tree.sumWords() wNovel, wNotes, cNovel, cNotes = self._tree.sumWords()
self._data.setCurrCounts(novel=novel, notes=notes) self._data.setCurrCounts(wNovel=wNovel, wNotes=wNotes, cNovel=cNovel, cNotes=cNotes)
return return
def countStatus(self) -> None: def countStatus(self) -> None:
+42 -24
View File
@@ -66,8 +66,8 @@ class NWProjectData:
self._spellLang = None self._spellLang = None
# Project Dictionaries # Project Dictionaries
self._initCounts = [0, 0] self._initCounts = [0, 0, 0, 0]
self._currCounts = [0, 0] self._currCounts = [0, 0, 0, 0]
self._lastHandle: dict[str, str | None] = { self._lastHandle: dict[str, str | None] = {
"editor": None, "editor": None,
"viewer": None, "viewer": None,
@@ -148,18 +148,18 @@ class NWProjectData:
return self._spellLang return self._spellLang
@property @property
def initCounts(self) -> tuple[int, int]: def initCounts(self) -> tuple[int, int, int, int]:
"""Return the initial count of words for novel and note """Return the initial count of words and characters for novel
documents. and note documents.
""" """
return self._initCounts[0], self._initCounts[1] return self._initCounts[0], self._initCounts[1], self._initCounts[2], self._initCounts[3]
@property @property
def currCounts(self) -> tuple[int, int]: def currCounts(self) -> tuple[int, int, int, int]:
"""Return the current count of words for novel and note """Return the current count of words and characters for novel
documents. and note documents.
""" """
return self._currCounts[0], self._currCounts[1] return self._currCounts[0], self._currCounts[1], self._currCounts[2], self._currCounts[3]
@property @property
def lastHandle(self) -> dict[str, str | None]: def lastHandle(self) -> dict[str, str | None]:
@@ -301,22 +301,40 @@ class NWProjectData:
self._project.setProjectChanged(True) self._project.setProjectChanged(True)
return return
def setInitCounts(self, novel: Any = None, notes: Any = None) -> None: def setInitCounts(
"""Set the word count totals for novel and note files.""" self, wNovel: Any = None, wNotes: Any = None, cNovel: Any = None, cNotes: Any = None
if novel is not None: ) -> None:
self._initCounts[0] = checkInt(novel, 0) """Set the count totals for novel and note files."""
self._currCounts[0] = checkInt(novel, 0) if wNovel is not None:
if notes is not None: count = checkInt(wNovel, 0)
self._initCounts[1] = checkInt(notes, 0) self._initCounts[0] = count
self._currCounts[1] = checkInt(notes, 0) self._currCounts[0] = count
if wNotes is not None:
count = checkInt(wNotes, 0)
self._initCounts[1] = count
self._currCounts[1] = count
if cNovel is not None:
count = checkInt(cNovel, 0)
self._initCounts[2] = count
self._currCounts[2] = count
if cNotes is not None:
count = checkInt(cNotes, 0)
self._initCounts[3] = count
self._currCounts[3] = count
return return
def setCurrCounts(self, novel: Any = None, notes: Any = None) -> None: def setCurrCounts(
"""Set the word count totals for novel and note files.""" self, wNovel: Any = None, wNotes: Any = None, cNovel: Any = None, cNotes: Any = None
if novel is not None: ) -> None:
self._currCounts[0] = checkInt(novel, 0) """Set the count totals for novel and note files."""
if notes is not None: if wNovel is not None:
self._currCounts[1] = checkInt(notes, 0) self._currCounts[0] = checkInt(wNovel, 0)
if wNotes is not None:
self._currCounts[1] = checkInt(wNotes, 0)
if cNovel is not None:
self._currCounts[2] = checkInt(cNovel, 0)
if cNotes is not None:
self._currCounts[3] = checkInt(cNotes, 0)
return return
def setAutoReplace(self, value: dict) -> None: def setAutoReplace(self, value: dict) -> None:
+17 -7
View File
@@ -46,7 +46,7 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
FILE_VERSION = "1.5" # The current project file format version FILE_VERSION = "1.5" # The current project file format version
FILE_REVISION = "4" # The current project file format revision FILE_REVISION = "5" # The current project file format revision
HEX_VERSION = 0x0105 HEX_VERSION = 0x0105
NUM_VERSION = { NUM_VERSION = {
@@ -109,6 +109,8 @@ class ProjectXMLReader:
Rev 3: Added TEMPLATE class. 2.3. Rev 3: Added TEMPLATE class. 2.3.
Rev 4: Added shape attribute to status and importance entry Rev 4: Added shape attribute to status and importance entry
nodes. 2.5. nodes. 2.5.
Rev 5: Added novelChars and notesChars attributes to content
node. 2.7 RC 1.
""" """
def __init__(self, path: str | Path) -> None: def __init__(self, path: str | Path) -> None:
@@ -286,9 +288,9 @@ class ProjectXMLReader:
elif xItem.tag == "spellLang": # Changed to spellChecking in 1.5 elif xItem.tag == "spellLang": # Changed to spellChecking in 1.5
data.setSpellLang(xItem.text) data.setSpellLang(xItem.text)
elif xItem.tag == "novelWordCount": # Moved to content attribute in 1.5 elif xItem.tag == "novelWordCount": # Moved to content attribute in 1.5
data.setInitCounts(novel=xItem.text) data.setInitCounts(wNovel=xItem.text)
elif xItem.tag == "notesWordCount": # Moved to content attribute in 1.5 elif xItem.tag == "notesWordCount": # Moved to content attribute in 1.5
data.setInitCounts(notes=xItem.text) data.setInitCounts(wNotes=xItem.text)
return return
@@ -298,8 +300,13 @@ class ProjectXMLReader:
"""Parse the content section of the XML file.""" """Parse the content section of the XML file."""
logger.debug("Parsing <content> section") logger.debug("Parsing <content> section")
data.setInitCounts(novel=xSection.attrib.get("novelWords", None)) # Moved in 1.5 # Moved in 1.5
data.setInitCounts(notes=xSection.attrib.get("notesWords", None)) # Moved in 1.5 data.setInitCounts(
wNovel=xSection.attrib.get("novelWords", None),
wNotes=xSection.attrib.get("notesWords", None),
cNovel=xSection.attrib.get("novelChars", None),
cNotes=xSection.attrib.get("notesChars", None),
)
for xItem in xSection: for xItem in xSection:
if xItem.tag != "item": if xItem.tag != "item":
@@ -527,10 +534,13 @@ class ProjectXMLWriter:
self._packSingleValue(xImport, "entry", label, attrib=attrib) self._packSingleValue(xImport, "entry", label, attrib=attrib)
# Save Tree Content # Save Tree Content
counts = data.currCounts
contAttr = { contAttr = {
"items": str(len(content)), "items": str(len(content)),
"novelWords": str(data.currCounts[0]), "novelWords": str(counts[0]),
"notesWords": str(data.currCounts[1]), "notesWords": str(counts[1]),
"novelChars": str(counts[2]),
"notesChars": str(counts[3]),
} }
xContent = ET.SubElement(xRoot, "content", attrib=contAttr) xContent = ET.SubElement(xRoot, "content", attrib=contAttr)
+2 -2
View File
@@ -79,8 +79,8 @@ class NWSessionLog:
return False return False
now = time() now = time()
iNovel, iNotes = self._project.data.initCounts iNovel, iNotes, _, _ = self._project.data.initCounts
cNovel, cNotes = self._project.data.currCounts cNovel, cNotes, _, _ = self._project.data.currCounts
iTotal = iNovel + iNotes iTotal = iNovel + iNotes
wDiff = cNovel + cNotes - iTotal wDiff = cNovel + cNotes - iTotal
sTime = now - self._start sTime = now - self._start
+9 -5
View File
@@ -410,16 +410,20 @@ class NWTree:
return True return True
def sumWords(self) -> tuple[int, int]: def sumWords(self) -> tuple[int, int, int, int]:
"""Loop over all entries and add up the word counts.""" """Loop over all entries and add up the word and char counts."""
noteWords = 0
novelWords = 0 novelWords = 0
notesWords = 0
novelChars = 0
notesChars = 0
for item in self._items.values(): for item in self._items.values():
if item.itemLayout == nwItemLayout.NOTE: if item.itemLayout == nwItemLayout.NOTE:
noteWords += item.wordCount notesWords += item.wordCount
notesChars += item.charCount
elif item.itemLayout == nwItemLayout.DOCUMENT: elif item.itemLayout == nwItemLayout.DOCUMENT:
novelWords += item.wordCount novelWords += item.wordCount
return novelWords, noteWords novelChars += item.charCount
return novelWords, notesWords, novelChars, notesChars
## ##
# Tree Item Methods # Tree Item Methods
+6 -7
View File
@@ -1261,15 +1261,14 @@ class GuiMain(QMainWindow):
if self._lastTotalCount != currentTotalCount: if self._lastTotalCount != currentTotalCount:
self._lastTotalCount = currentTotalCount self._lastTotalCount = currentTotalCount
SHARED.project.updateWordCounts() SHARED.project.updateCounts()
if CONFIG.incNotesWCount: if CONFIG.incNotesWCount:
iTotal = sum(SHARED.project.data.initCounts) iTotal = sum(SHARED.project.data.initCounts[:2])
cTotal = sum(SHARED.project.data.currCounts) cTotal = sum(SHARED.project.data.currCounts[:2])
self.mainStatus.setProjectStats(cTotal, cTotal - iTotal)
else: else:
iNovel, _ = SHARED.project.data.initCounts iTotal = SHARED.project.data.initCounts[0]
cNovel, _ = SHARED.project.data.currCounts cTotal = SHARED.project.data.currCounts[0]
self.mainStatus.setProjectStats(cNovel, cNovel - iNovel) self.mainStatus.setProjectStats(cTotal, cTotal - iTotal)
return return
+2 -2
View File
@@ -256,8 +256,8 @@ class _OverviewPage(NScrollablePage):
def updateProjectData(self) -> None: def updateProjectData(self) -> None:
"""Load information about the project.""" """Load information about the project."""
project = SHARED.project project = SHARED.project
project.updateWordCounts() project.updateCounts()
wcNovel, wcNotes = project.data.currCounts wcNovel, wcNotes, _, _ = project.data.currCounts
self.projName.setText(project.data.name) self.projName.setText(project.data.name)
self.projRevisions.setText(f"{project.data.saveCount:n}") self.projRevisions.setText(f"{project.data.saveCount:n}")