From dd180402325a232c580d0068caad694f0b9929f1 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Mon, 1 Feb 2021 21:52:51 +0100 Subject: [PATCH 1/3] Fix some source file headers --- nw/constants/constants.py | 1 - nw/gui/noveltree.py | 37 ++++++++++++++++++------------------- tests/conftest.py | 20 +++++++++++++++++++- tests/dummy.py | 20 +++++++++++++++++++- tests/tools.py | 20 +++++++++++++++++++- 5 files changed, 75 insertions(+), 23 deletions(-) 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/gui/noveltree.py b/nw/gui/noveltree.py index 1174bbfe..d8c23b04 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 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/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 From af21f3c5d8e86f7087b214a3e548ea810f028070 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Mon, 1 Feb 2021 22:48:07 +0100 Subject: [PATCH 2/3] Add index functions to extract headers and word counts for a given handle --- nw/core/index.py | 30 ++++++++++++++++++++ tests/test_core/test_core_index.py | 44 ++++++++++++++++++++++-------- 2 files changed, 62 insertions(+), 12 deletions(-) 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/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 From d0940708b04e605abad8d5d05b0fed6ff745e740 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Mon, 1 Feb 2021 22:49:11 +0100 Subject: [PATCH 3/3] Add a header structure record to the editor, and force an update of te novel tree if header levels change --- nw/gui/doceditor.py | 34 +++++++++++++++++++++++++++++++++- nw/gui/noveltree.py | 9 +++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) 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 d8c23b04..7a7990f8 100644 --- a/nw/gui/noveltree.py +++ b/nw/gui/noveltree.py @@ -150,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. """