Merge pull request #637 from vkbo/issue636_noveltab_wcount

Issue #636: Novel Tab Word Count
This commit is contained in:
Veronica K. Berglyd Olsen
2021-02-01 21:59:06 +00:00
committed by GitHub
8 changed files with 179 additions and 36 deletions
-1
View File
@@ -49,7 +49,6 @@ class nwConst():
class nwLists(): class nwLists():
"""Lists used for grouping various other constants. """Lists used for grouping various other constants.
""" """
# Regular user-accessible item types # Regular user-accessible item types
REG_TYPES = {nwItemType.ROOT, nwItemType.FOLDER, nwItemType.FILE} REG_TYPES = {nwItemType.ROOT, nwItemType.FOLDER, nwItemType.FILE}
+30
View File
@@ -608,6 +608,36 @@ class NWIndex():
return hCount 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): def getTableOfContents(self, maxDepth, skipExcluded=True):
"""Generate a table of contents up to a maxiumum depth. """Generate a table of contents up to a maxiumum depth.
""" """
+33 -1
View File
@@ -75,12 +75,14 @@ class GuiDocEditor(QTextEdit):
self.mainConf = nw.CONFIG self.mainConf = nw.CONFIG
self.theParent = theParent self.theParent = theParent
self.theTheme = theParent.theTheme self.theTheme = theParent.theTheme
self.theIndex = theParent.theIndex
self.theProject = theParent.theProject self.theProject = theParent.theProject
self.nwDocument = NWDoc(self.theProject, self.theParent) self.nwDocument = NWDoc(self.theProject, self.theParent)
self.docChanged = False # Flag for changed status of document self.docChanged = False # Flag for changed status of document
self.spellCheck = False # Flag for spell checking enabled self.spellCheck = False # Flag for spell checking enabled
self.theHandle = None # The handle of the open file 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.theDict = None # The current spell check dictionary
self.nonWord = "\"'" # Characters to not include in spell checking self.nonWord = "\"'" # Characters to not include in spell checking
@@ -342,6 +344,7 @@ class GuiDocEditor(QTextEdit):
self.docFooter.updateLineCount() self.docFooter.updateLineCount()
self.lengthLast = self.qDocument.characterCount() self.lengthLast = self.qDocument.characterCount()
self.theHeaders = self.theIndex.getHandleHeaders(self.theHandle)
qApp.processEvents() qApp.processEvents()
self.setDocumentChanged(False) self.setDocumentChanged(False)
@@ -398,6 +401,7 @@ class GuiDocEditor(QTextEdit):
return False return False
docText = self.getText() docText = self.getText()
tHandle = theItem.itemHandle
cC, wC, pC = countWords(docText) cC, wC, pC = countWords(docText)
self._updateCounts(cC, wC, pC) self._updateCounts(cC, wC, pC)
@@ -410,7 +414,11 @@ class GuiDocEditor(QTextEdit):
self.nwDocument.saveDocument(docText) self.nwDocument.saveDocument(docText)
self.setDocumentChanged(False) 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 return True
@@ -1219,6 +1227,30 @@ class GuiDocEditor(QTextEdit):
return 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): def _replaceQuotes(self, sQuote, oQuote, cQuote):
"""Replace all straight quotes in the selected text. """Replace all straight quotes in the selected text.
""" """
+27 -19
View File
@@ -1,28 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""novelWriter GUI Novel Tree """
novelWriter GUI Novel Tree
============================
GUI classe for the main window novel tree
novelWriter GUI Novel Tree File History:
============================== Created: 2020-12-20 [1.1a0]
Class holding the project's novel files tree view
File History: This file is a part of novelWriter
Created: 2020-12-20 [1.1a0] Copyright 20182020, Veronica Berglyd Olsen
This file is a part of novelWriter This program is free software: you can redistribute it and/or modify
Copyright 20182020, Veronica Berglyd Olsen 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 This program is distributed in the hope that it will be useful, but
it under the terms of the GNU General Public License as published by WITHOUT ANY WARRANTY; without even the implied warranty of
the Free Software Foundation, either version 3 of the License, or MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
(at your option) any later version. General Public License for more details.
This program is distributed in the hope that it will be useful, but You should have received a copy of the GNU General Public License
WITHOUT ANY WARRANTY; without even the implied warranty of along with this program. If not, see <https://www.gnu.org/licenses/>.
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 <https://www.gnu.org/licenses/>.
""" """
import nw import nw
@@ -151,6 +150,15 @@ class GuiNovelTree(QTreeWidget):
return 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): def getColumnSizes(self):
"""Return the column widths for the tree columns. """Return the column widths for the tree columns.
""" """
+19 -1
View File
@@ -1,5 +1,23 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""novelWriter Test Config """
novelWriter Test Suite Configuration
======================================
This file is a part of novelWriter
Copyright 20182021, 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 <https://www.gnu.org/licenses/>.
""" """
import sys import sys
+19 -1
View File
@@ -1,5 +1,23 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""novelWriter Test Dummy GUI Classes """
novelWriter Test Suite Dummy Classes
======================================
This file is a part of novelWriter
Copyright 20182021, 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 <https://www.gnu.org/licenses/>.
""" """
# =========================================================================== # # =========================================================================== #
+32 -12
View File
@@ -572,12 +572,12 @@ def testCoreIndex_ExtractData(nwMinimal, dummyGUI):
"@char: Jane\n\n" "@char: Jane\n\n"
"% this is a comment\n\n" "% this is a comment\n\n"
"This is a story about Jane Smith.\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 # Whole document
cC, wC, pC = theIndex.getCounts(nHandle) cC, wC, pC = theIndex.getCounts(nHandle)
assert cC == 124 assert cC == 152
assert wC == 24 assert wC == 28
assert pC == 4 assert pC == 4
# First part # First part
@@ -588,8 +588,8 @@ def testCoreIndex_ExtractData(nwMinimal, dummyGUI):
# First part # First part
cC, wC, pC = theIndex.getCounts(nHandle, "T000011") cC, wC, pC = theIndex.getCounts(nHandle, "T000011")
assert cC == 62 assert cC == 90
assert wC == 12 assert wC == 16
assert pC == 2 assert pC == 2
# Get section counts for a note file # Get section counts for a note file
@@ -605,12 +605,12 @@ def testCoreIndex_ExtractData(nwMinimal, dummyGUI):
"@char: Jane\n\n" "@char: Jane\n\n"
"% this is a comment\n\n" "% this is a comment\n\n"
"This is a story about Jane Smith.\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 # Whole document
cC, wC, pC = theIndex.getCounts(cHandle) cC, wC, pC = theIndex.getCounts(cHandle)
assert cC == 124 assert cC == 152
assert wC == 24 assert wC == 28
assert pC == 4 assert pC == 4
# First part # First part
@@ -621,8 +621,8 @@ def testCoreIndex_ExtractData(nwMinimal, dummyGUI):
# First part # First part
cC, wC, pC = theIndex.getCounts(cHandle, "T000011") cC, wC, pC = theIndex.getCounts(cHandle, "T000011")
assert cC == 62 assert cC == 90
assert wC == 12 assert wC == 16
assert pC == 2 assert pC == 2
## ##
@@ -650,7 +650,7 @@ def testCoreIndex_ExtractData(nwMinimal, dummyGUI):
theProject.projTree._treeOrder.remove("0000000000000") theProject.projTree._treeOrder.remove("0000000000000")
# Extract stats # Extract stats
assert theIndex.getNovelWordCount(False) == 30 assert theIndex.getNovelWordCount(False) == 34
assert theIndex.getNovelWordCount(True) == 6 assert theIndex.getNovelWordCount(True) == 6
assert theIndex.getNovelTitleCounts(False) == [0, 2, 1, 2, 0] assert theIndex.getNovelTitleCounts(False) == [0, 2, 1, 2, 0]
assert theIndex.getNovelTitleCounts(True) == [0, 0, 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(0, False) == []
assert theIndex.getTableOfContents(1, False) == [ assert theIndex.getTableOfContents(1, False) == [
("%s:T000001" % nHandle, 1, "Hello World!", 12), ("%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() 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 # END Test testCoreIndex_ExtractData
+19 -1
View File
@@ -1,5 +1,23 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""novelWriter Test Tools """
novelWriter Test Suite Tools
==============================
This file is a part of novelWriter
Copyright 20182021, 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 <https://www.gnu.org/licenses/>.
""" """
import os import os