diff --git a/nw/constants/constants.py b/nw/constants/constants.py
index 5b961e10..10c44bac 100644
--- a/nw/constants/constants.py
+++ b/nw/constants/constants.py
@@ -49,7 +49,6 @@ class nwConst():
class nwLists():
"""Lists used for grouping various other constants.
"""
-
# Regular user-accessible item types
REG_TYPES = {nwItemType.ROOT, nwItemType.FOLDER, nwItemType.FILE}
diff --git a/nw/core/index.py b/nw/core/index.py
index ba2e06f3..2299ab0d 100644
--- a/nw/core/index.py
+++ b/nw/core/index.py
@@ -608,6 +608,36 @@ class NWIndex():
return hCount
+ def getHandleWordCounts(self, tHandle):
+ """Get all header word counts for a specific handle.
+ """
+ theCounts = []
+ hRecord = self._novelIndex.get(tHandle, None)
+ if hRecord is None:
+ hRecord = self._noteIndex.get(tHandle, None)
+ if hRecord is None:
+ return theCounts
+
+ for sTitle, sData in hRecord.items():
+ theCounts.append(("%s:%s" % (tHandle, sTitle), sData["wCount"]))
+
+ return theCounts
+
+ def getHandleHeaders(self, tHandle):
+ """Get all headers for a specific handle.
+ """
+ theHeaders = []
+ hRecord = self._novelIndex.get(tHandle, None)
+ if hRecord is None:
+ hRecord = self._noteIndex.get(tHandle, None)
+ if hRecord is None:
+ return theHeaders
+
+ for sTitle, sData in hRecord.items():
+ theHeaders.append((sTitle, sData["level"], sData["title"]))
+
+ return theHeaders
+
def getTableOfContents(self, maxDepth, skipExcluded=True):
"""Generate a table of contents up to a maxiumum depth.
"""
diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py
index 627b4ff9..03f6b622 100644
--- a/nw/gui/doceditor.py
+++ b/nw/gui/doceditor.py
@@ -75,12 +75,14 @@ class GuiDocEditor(QTextEdit):
self.mainConf = nw.CONFIG
self.theParent = theParent
self.theTheme = theParent.theTheme
+ self.theIndex = theParent.theIndex
self.theProject = theParent.theProject
self.nwDocument = NWDoc(self.theProject, self.theParent)
self.docChanged = False # Flag for changed status of document
self.spellCheck = False # Flag for spell checking enabled
self.theHandle = None # The handle of the open file
+ self.theHeaders = [] # Record of headers in the file
self.theDict = None # The current spell check dictionary
self.nonWord = "\"'" # Characters to not include in spell checking
@@ -342,6 +344,7 @@ class GuiDocEditor(QTextEdit):
self.docFooter.updateLineCount()
self.lengthLast = self.qDocument.characterCount()
+ self.theHeaders = self.theIndex.getHandleHeaders(self.theHandle)
qApp.processEvents()
self.setDocumentChanged(False)
@@ -398,6 +401,7 @@ class GuiDocEditor(QTextEdit):
return False
docText = self.getText()
+ tHandle = theItem.itemHandle
cC, wC, pC = countWords(docText)
self._updateCounts(cC, wC, pC)
@@ -410,7 +414,11 @@ class GuiDocEditor(QTextEdit):
self.nwDocument.saveDocument(docText)
self.setDocumentChanged(False)
- self.theParent.theIndex.scanText(theItem.itemHandle, docText)
+ self.theIndex.scanText(tHandle, docText)
+ if self._updateHeaders(checkLevel=True):
+ self.theParent.novelView.refreshTree()
+ else:
+ self.theParent.novelView.updateWordCounts(tHandle)
return True
@@ -1219,6 +1227,30 @@ class GuiDocEditor(QTextEdit):
return
+ def _updateHeaders(self, checkPos=False, checkLevel=False):
+ """Update the headers record and return True if anything
+ changed, if a check flag was provided.
+ """
+ if self.theHandle is None:
+ return False
+
+ newHeaders = self.theIndex.getHandleHeaders(self.theHandle)
+ if checkPos:
+ newPos = [x[0] for x in newHeaders]
+ oldPos = [x[0] for x in self.theHeaders]
+ if checkLevel:
+ newLev = [x[1] for x in newHeaders]
+ oldLev = [x[1] for x in self.theHeaders]
+
+ self.theHeaders = newHeaders
+
+ if checkPos:
+ return newPos != oldPos
+ if checkLevel:
+ return newLev != oldLev
+
+ return False
+
def _replaceQuotes(self, sQuote, oQuote, cQuote):
"""Replace all straight quotes in the selected text.
"""
diff --git a/nw/gui/noveltree.py b/nw/gui/noveltree.py
index 1174bbfe..7a7990f8 100644
--- a/nw/gui/noveltree.py
+++ b/nw/gui/noveltree.py
@@ -1,28 +1,27 @@
# -*- coding: utf-8 -*-
-"""novelWriter GUI Novel Tree
+"""
+novelWriter – GUI Novel Tree
+============================
+GUI classe for the main window novel tree
- novelWriter – GUI Novel Tree
-==============================
- Class holding the project's novel files tree view
+File History:
+Created: 2020-12-20 [1.1a0]
- File History:
- Created: 2020-12-20 [1.1a0]
+This file is a part of novelWriter
+Copyright 2018–2020, Veronica Berglyd Olsen
- This file is a part of novelWriter
- Copyright 2018–2020, Veronica Berglyd Olsen
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
"""
import nw
@@ -151,6 +150,15 @@ class GuiNovelTree(QTreeWidget):
return
+ def updateWordCounts(self, tHandle):
+ """Update the word count for a given handle.
+ """
+ tHeaders = self.theIndex.getHandleWordCounts(tHandle)
+ for titleKey, wCount in tHeaders:
+ if titleKey in self._treeMap:
+ self._treeMap[titleKey].setText(self.C_WORDS, f"{wCount:n}")
+ return
+
def getColumnSizes(self):
"""Return the column widths for the tree columns.
"""
diff --git a/tests/conftest.py b/tests/conftest.py
index 670085d5..57956aff 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,5 +1,23 @@
# -*- coding: utf-8 -*-
-"""novelWriter Test Config
+"""
+novelWriter – Test Suite Configuration
+======================================
+
+This file is a part of novelWriter
+Copyright 2018–2021, Veronica Berglyd Olsen
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
"""
import sys
diff --git a/tests/dummy.py b/tests/dummy.py
index 9a74bb61..72ac5e21 100644
--- a/tests/dummy.py
+++ b/tests/dummy.py
@@ -1,5 +1,23 @@
# -*- coding: utf-8 -*-
-"""novelWriter Test Dummy GUI Classes
+"""
+novelWriter – Test Suite Dummy Classes
+======================================
+
+This file is a part of novelWriter
+Copyright 2018–2021, Veronica Berglyd Olsen
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
"""
# =========================================================================== #
diff --git a/tests/test_core/test_core_index.py b/tests/test_core/test_core_index.py
index e10000d6..eeee2be9 100644
--- a/tests/test_core/test_core_index.py
+++ b/tests/test_core/test_core_index.py
@@ -572,12 +572,12 @@ def testCoreIndex_ExtractData(nwMinimal, dummyGUI):
"@char: Jane\n\n"
"% this is a comment\n\n"
"This is a story about Jane Smith.\n\n"
- "Well, not really.\n"
+ "Well, not really. She's still awesome though.\n"
))
# Whole document
cC, wC, pC = theIndex.getCounts(nHandle)
- assert cC == 124
- assert wC == 24
+ assert cC == 152
+ assert wC == 28
assert pC == 4
# First part
@@ -588,8 +588,8 @@ def testCoreIndex_ExtractData(nwMinimal, dummyGUI):
# First part
cC, wC, pC = theIndex.getCounts(nHandle, "T000011")
- assert cC == 62
- assert wC == 12
+ assert cC == 90
+ assert wC == 16
assert pC == 2
# Get section counts for a note file
@@ -605,12 +605,12 @@ def testCoreIndex_ExtractData(nwMinimal, dummyGUI):
"@char: Jane\n\n"
"% this is a comment\n\n"
"This is a story about Jane Smith.\n\n"
- "Well, not really.\n"
+ "Well, not really. She's still awesome though.\n"
))
# Whole document
cC, wC, pC = theIndex.getCounts(cHandle)
- assert cC == 124
- assert wC == 24
+ assert cC == 152
+ assert wC == 28
assert pC == 4
# First part
@@ -621,8 +621,8 @@ def testCoreIndex_ExtractData(nwMinimal, dummyGUI):
# First part
cC, wC, pC = theIndex.getCounts(cHandle, "T000011")
- assert cC == 62
- assert wC == 12
+ assert cC == 90
+ assert wC == 16
assert pC == 2
##
@@ -650,7 +650,7 @@ def testCoreIndex_ExtractData(nwMinimal, dummyGUI):
theProject.projTree._treeOrder.remove("0000000000000")
# Extract stats
- assert theIndex.getNovelWordCount(False) == 30
+ assert theIndex.getNovelWordCount(False) == 34
assert theIndex.getNovelWordCount(True) == 6
assert theIndex.getNovelTitleCounts(False) == [0, 2, 1, 2, 0]
assert theIndex.getNovelTitleCounts(True) == [0, 0, 1, 2, 0]
@@ -670,9 +670,29 @@ def testCoreIndex_ExtractData(nwMinimal, dummyGUI):
assert theIndex.getTableOfContents(0, False) == []
assert theIndex.getTableOfContents(1, False) == [
("%s:T000001" % nHandle, 1, "Hello World!", 12),
- ("%s:T000011" % nHandle, 1, "Hello World!", 18),
+ ("%s:T000011" % nHandle, 1, "Hello World!", 22),
+ ]
+
+ # Header Word Counts
+ bHandle = "0000000000000"
+ assert theIndex.getHandleWordCounts(bHandle) == []
+ assert theIndex.getHandleWordCounts(hHandle) == [("%s:T000001" % hHandle, 2)]
+ assert theIndex.getHandleWordCounts(sHandle) == [("%s:T000001" % sHandle, 2)]
+ assert theIndex.getHandleWordCounts(tHandle) == [("%s:T000001" % tHandle, 2)]
+ assert theIndex.getHandleWordCounts(nHandle) == [
+ ("%s:T000001" % nHandle, 12), ("%s:T000011" % nHandle, 16)
]
assert theProject.closeProject()
+ # Header Record
+ bHandle = "0000000000000"
+ assert theIndex.getHandleHeaders(bHandle) == []
+ assert theIndex.getHandleHeaders(hHandle) == [("T000001", "H2", "Chapter One")]
+ assert theIndex.getHandleHeaders(sHandle) == [("T000001", "H3", "Scene One")]
+ assert theIndex.getHandleHeaders(tHandle) == [("T000001", "H3", "Scene Two")]
+ assert theIndex.getHandleHeaders(nHandle) == [
+ ("T000001", "H1", "Hello World!"), ("T000011", "H1", "Hello World!")
+ ]
+
# END Test testCoreIndex_ExtractData
diff --git a/tests/tools.py b/tests/tools.py
index d55a1e4e..1b688f1e 100644
--- a/tests/tools.py
+++ b/tests/tools.py
@@ -1,5 +1,23 @@
# -*- coding: utf-8 -*-
-"""novelWriter Test Tools
+"""
+novelWriter – Test Suite Tools
+==============================
+
+This file is a part of novelWriter
+Copyright 2018–2021, Veronica Berglyd Olsen
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
"""
import os