From c865dbd59bbc5e6873ac8eff6442f99febb0251b Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 24 May 2020 16:42:28 +0200 Subject: [PATCH] Added a lot of comments to functions in the source code --- nw/core/document.py | 4 +- nw/core/index.py | 1 - nw/core/project.py | 87 +++++++++++++++++++++++++------ nw/core/spellcheck.py | 38 +++++++++++++- nw/core/tools.py | 3 -- nw/gui/additions/pageddialog.py | 10 +++- nw/gui/additions/qconfiglayout.py | 6 ++- nw/gui/additions/qswitch.py | 1 - nw/gui/elements/docdetails.py | 39 +++++++------- nw/gui/elements/doceditor.py | 40 +++++++++----- nw/gui/elements/doctitlebar.py | 1 - nw/gui/elements/doctree.py | 47 +++++++++++++++-- nw/gui/elements/docviewer.py | 22 ++++++-- nw/gui/elements/noticebar.py | 4 ++ nw/gui/elements/outline.py | 4 -- nw/gui/elements/searchbar.py | 17 ++++++ nw/gui/elements/viewdetails.py | 11 +++- nw/gui/tools/dochighlight.py | 12 ++++- nw/gui/tools/optionstate.py | 2 - nw/gui/tools/wordcounter.py | 4 +- nw/guimain.py | 2 +- 21 files changed, 273 insertions(+), 82 deletions(-) diff --git a/nw/core/document.py b/nw/core/document.py index 6bcba588..4c502bea 100644 --- a/nw/core/document.py +++ b/nw/core/document.py @@ -136,7 +136,6 @@ class NWDoc(): """Save the document via temp file in case of save failure, and in any case keep a backup of the file. """ - if self.docHandle is None or not self.docEditable: return False @@ -202,7 +201,6 @@ class NWDoc(): """Parses the document meta tag and returns the path and name as a list and a string. """ - if len(self.docMeta) < 14: # Not enough information return "", [] @@ -232,6 +230,8 @@ class NWDoc(): @staticmethod def _assemblePath(tHandle, docExt): + """Assemble the file path for a given handle. + """ if tHandle is None: return None, None docDir = "data_"+tHandle[0] diff --git a/nw/core/index.py b/nw/core/index.py index 346fdb36..3633c841 100644 --- a/nw/core/index.py +++ b/nw/core/index.py @@ -244,7 +244,6 @@ class NWIndex(): and text as separate inputs as we want to primarily scan the files before we save them, unless we're rebuilding the index. """ - theItem = self.theProject.projTree[tHandle] if theItem is None: return False diff --git a/nw/core/project.py b/nw/core/project.py index 7838d5fd..4516d1aa 100644 --- a/nw/core/project.py +++ b/nw/core/project.py @@ -181,7 +181,6 @@ class NWProject(): """Clear the data for the current project, and set them to default values. """ - # Project Status self.projOpened = 0 self.projChanged = False @@ -236,7 +235,6 @@ class NWProject(): parse the XML of the file and populate the project variables and build the tree of project items. """ - if not path.isfile(fileName): fileName = path.join(fileName, nwFiles.PROJ_FILE) if not path.isfile(fileName): @@ -404,7 +402,6 @@ class NWProject(): make sure if the save fails, we're not left with a truncated file. """ - if self.projPath is None: self.makeAlert("Project path not set, cannot save.", nwAlert.ERROR) return False @@ -522,7 +519,6 @@ class NWProject(): def zipIt(self, doNotify): """Create a zip file of the entire project. """ - logger.info("Backing up project") self.theParent.statusBar.setStatus("Backing up project ...") @@ -836,7 +832,6 @@ class NWProject(): def _readLockFile(self): """Reads the lock file in the project folder. """ - if self.projPath is None: return ["ERROR"] @@ -863,7 +858,6 @@ class NWProject(): def _writeLockFile(self): """Writes a lock file to the project folder. """ - if self.projPath is None: return False @@ -901,6 +895,8 @@ class NWProject(): return None def _checkFolder(self, thePath): + """Check if a folder exists, and if it doesn't, create it. + """ if not path.isdir(thePath): try: mkdir(thePath) @@ -911,6 +907,8 @@ class NWProject(): return True def _packProjectValue(self, xParent, theName, theValue, allowNone=True): + """Pack a list of values into an xml element. + """ if not isinstance(theValue, list): theValue = [theValue] for aValue in theValue: @@ -927,7 +925,6 @@ class NWProject(): orphaned files so the user can either delete them, or put them back into the project tree. """ - if self.projPath is None: return @@ -992,7 +989,6 @@ class NWProject(): def _appendSessionStats(self): """Append session statistics to the sessions log file. """ - if self.projMeta is None: return False @@ -1234,9 +1230,13 @@ class NWTree(): ## def __len__(self): + """Return the length counter. Does not check that it is correct! + """ return self._theLength def __bool__(self): + """Returns True if the tree has any entries. + """ return self._theLength > 0 ## @@ -1382,7 +1382,6 @@ class NWItem(): def unpackXML(self, xItem): """Sets the values from an XML entry of type 'item'. """ - if xItem.tag != "item": logger.error("XML entry is not an NWItem") return False @@ -1420,9 +1419,11 @@ class NWItem(): @staticmethod def _subPack(xParent, name, attrib=None, text=None, none=True): + """Packs the values into an xml element. + """ if not none and (text == None or text == "None"): return None - xSub = etree.SubElement(xParent,name,attrib=attrib) + xSub = etree.SubElement(xParent, name, attrib=attrib) if text is not None: xSub.text = text return xSub @@ -1432,10 +1433,14 @@ class NWItem(): ## def setName(self, theName): + """Set the item name. + """ self.itemName = theName.strip() return def setHandle(self, theHandle): + """Set the item handle, and ensure it is valid. + """ if isinstance(theHandle, str): if len(theHandle) == 13: self.itemHandle = theHandle @@ -1446,6 +1451,8 @@ class NWItem(): return def setParent(self, theParent): + """Set the parent handle, and ensure that it is valid. + """ if theParent is None: self.parHandle = None elif isinstance(theParent, str): @@ -1458,10 +1465,16 @@ class NWItem(): return def setOrder(self, theOrder): + """Set the item order, and ensure that it is valid. This value + is purely a meta value, not actually used by novelWriter. + """ self.itemOrder = checkInt(theOrder, 0) return def setType(self, theType): + """Set the item type from either a proper nwItemType, or set it + from a string representing a nwItemType. + """ if isinstance(theType, nwItemType): self.itemType = theType elif theType in nwItemType.__members__: @@ -1472,6 +1485,9 @@ class NWItem(): return def setClass(self, theClass): + """Set the item class from either a proper nwItemClass, or set + it from a string representing a nwItemClass. + """ if isinstance(theClass, nwItemClass): self.itemClass = theClass elif theClass in nwItemClass.__members__: @@ -1482,6 +1498,9 @@ class NWItem(): return def setLayout(self, theLayout): + """Set the item layout from either a proper nwItemLayout, or set + it from a string representing a nwItemLayout. + """ if isinstance(theLayout, nwItemLayout): self.itemLayout = theLayout elif theLayout in nwItemLayout.__members__: @@ -1492,6 +1511,9 @@ class NWItem(): return def setStatus(self, theStatus): + """Set the item status by looking it up in the valid status + items of the current project. + """ if self.itemClass == nwItemClass.NOVEL: self.itemStatus = self.theProject.statusItems.checkEntry(theStatus) else: @@ -1499,6 +1521,8 @@ class NWItem(): return def setExpanded(self, expState): + """Save the expanded status of an item in the project tree. + """ if isinstance(expState, str): self.isExpanded = expState == str(True) else: @@ -1506,6 +1530,8 @@ class NWItem(): return def setExported(self, expState): + """Save the export flag. + """ if isinstance(expState, str): self.isExported = expState == str(True) else: @@ -1517,19 +1543,27 @@ class NWItem(): ## def setCharCount(self, theCount): - self.charCount = checkInt(theCount,0) + """Set the character count, and ensure that it is an integer. + """ + self.charCount = checkInt(theCount, 0) return def setWordCount(self, theCount): - self.wordCount = checkInt(theCount,0) + """Set the word count, and ensure that it is an integer. + """ + self.wordCount = checkInt(theCount, 0) return def setParaCount(self, theCount): - self.paraCount = checkInt(theCount,0) + """Set the paragraph count, and ensure that it is an integer. + """ + self.paraCount = checkInt(theCount, 0) return def setCursorPos(self, thePosition): - self.cursorPos = checkInt(thePosition,0) + """Set the cursor position, and ensure that it is an integer. + """ + self.cursorPos = checkInt(thePosition, 0) return # END Class NWItem @@ -1551,6 +1585,9 @@ class NWStatus(): return def addEntry(self, theLabel, theColours): + """Add a status entry to the status object, but ensure it isn't + a duplicate. + """ theLabel = theLabel.strip() if self.lookupEntry(theLabel) is None: self.theLabels.append(theLabel) @@ -1561,6 +1598,9 @@ class NWStatus(): return True def lookupEntry(self, theLabel): + """Look up a status entry in the object lists, and return it if + it exists. + """ if theLabel is None: return None theLabel = theLabel.strip() @@ -1569,6 +1609,9 @@ class NWStatus(): return None def checkEntry(self, theStatus): + """Check if a status value is valid, and returns the safe + reference to be used internally. + """ if isinstance(theStatus, str): theStatus = theStatus.strip() if self.lookupEntry(theStatus) is not None: @@ -1578,11 +1621,12 @@ class NWStatus(): return self.theLabels[theStatus] def setNewEntries(self, newList): - + """Update the list of entries after they have been modified by + the GUI tool. + """ replaceMap = {} if newList is not None: - self.theLabels = [] self.theColours = [] self.theCounts = [] @@ -1598,10 +1642,14 @@ class NWStatus(): return replaceMap def resetCounts(self): + """Clear the counts of references to the status entries. + """ self.theCounts = [0]*self.theLength return def countEntry(self, theLabel): + """Lookup the usage count of a given entry. + """ theIndex = self.lookupEntry(theLabel) if theIndex is not None: self.theCounts[theIndex] += 1 @@ -1623,7 +1671,6 @@ class NWStatus(): def unpackEntries(self, xParent): """Unpack an XML tree and set the class values. """ - theLabels = [] theColours = [] @@ -1661,15 +1708,21 @@ class NWStatus(): ## def __getitem__(self, n): + """Return an entry by its index. + """ if n >= 0 and n < self.theLength: return self.theLabels[n], self.theColours[n], self.theCounts[n] return None, None, None def __iter__(self): + """Initialise the iterator. + """ self.theIndex = 0 return self def __next__(self): + """Return the next entry for the iterator. + """ if self.theIndex < self.theLength: theLabel, theColour, theCount = self.__getitem__(self.theIndex) self.theIndex += 1 diff --git a/nw/core/spellcheck.py b/nw/core/spellcheck.py index fda4022d..2af06f42 100644 --- a/nw/core/spellcheck.py +++ b/nw/core/spellcheck.py @@ -55,15 +55,23 @@ class NWSpellCheck(): return def setLanguage(self, theLang, projectDict=None): + """Dummy function. + """ return def checkWord(self, theWord): + """Dummy function. + """ return True def suggestWords(self, theWord): + """Dummy function. + """ return [] def addWord(self, newWord): + """Add a word to the project dictionary. + """ if self.projectDict is not None and newWord not in self.PROJW: newWord = newWord.strip() self.PROJW.append(newWord) @@ -76,10 +84,14 @@ class NWSpellCheck(): return def listDictionaries(self): + """Dummy function. + """ return [] @staticmethod def expandLanguage(spTag): + """Translate a language tag to something more suer friendly. + """ spBits = spTag.split("_") if spBits[0] in isoLanguage.ISO_639_1: spLang = isoLanguage.ISO_639_1[spBits[0]] @@ -94,6 +106,9 @@ class NWSpellCheck(): ## def _readProjectDictionary(self, projectDict): + """Read the content of the project dictionary, and add it to the + lookup lists. + """ self.PROJW = [] if projectDict is not None: self.projectDict = projectDict @@ -147,17 +162,25 @@ class NWSpellEnchant(NWSpellCheck): return def checkWord(self, theWord): + """Wrapper function for pyenchant. + """ return self.theDict.check(theWord) def suggestWords(self, theWord): + """Wrapper function for pyenchant. + """ return self.theDict.suggest(theWord) def addWord(self, newWord): + """Wrapper function for pyenchant. + """ self.theDict.add_to_session(newWord) NWSpellCheck.addWord(self, newWord) return def listDictionaries(self): + """Wrapper function for pyenchant. + """ retList = [] try: import enchant @@ -171,6 +194,8 @@ class NWSpellEnchant(NWSpellCheck): # END Class NWSpellEnchant class NWSpellEnchantDummy: + """Fallback for when Enchant is selected, but not installed. + """ def __init__(self): return @@ -191,6 +216,11 @@ class NWSpellEnchantDummy: # ================================================================================================ # class NWSpellSimple(NWSpellCheck): + """Internal spell check tool that uses standard Python packages with + no other external dependencies. This is the fallback spell checker + when no other is available. This method is fairly slow compared to + other implementations. + """ WORDS = [] @@ -200,7 +230,8 @@ class NWSpellSimple(NWSpellCheck): return def setLanguage(self, theLang, projectDict=None): - + """Load a dictionary as a list from the app assets folder. + """ self.WORDS = [] dictFile = path.join(self.mainConf.dictPath,theLang+".dict") try: @@ -259,6 +290,8 @@ class NWSpellSimple(NWSpellCheck): return theOptions def addWord(self, newWord): + """Wrapper for the internal project dictionary feature. + """ newWord = newWord.strip().lower() if newWord not in self.WORDS: self.WORDS.append(newWord) @@ -266,7 +299,8 @@ class NWSpellSimple(NWSpellCheck): return def listDictionaries(self): - + """Lists the dictionary files in the app assets folder. + """ retList = [] for dictFile in listdir(self.mainConf.dictPath): diff --git a/nw/core/tools.py b/nw/core/tools.py index 2c96cee6..a6eb244b 100644 --- a/nw/core/tools.py +++ b/nw/core/tools.py @@ -39,7 +39,6 @@ def countWords(theText): """Count words in a piece of text, skipping special syntax and comments. """ - charCount = 0 wordCount = 0 paraCount = 0 @@ -86,7 +85,6 @@ def projectMaintenance(theProject): """Wrapper class for handling various tasks related to managing old projects with content from older versions of novelWriter. """ - # Remove no longer used project cache folder if path.isdir(theProject.projPath): cacheDir = path.join(theProject.projPath, "cache") @@ -141,7 +139,6 @@ def numberToWord(numVal, theLanguage): def _numberToWordEN(numVal): """Convert numbers to English words. """ - numWord = "" oneWord = "" tenWord = "" diff --git a/nw/gui/additions/pageddialog.py b/nw/gui/additions/pageddialog.py index 6e5c2e23..2b65cbb9 100644 --- a/nw/gui/additions/pageddialog.py +++ b/nw/gui/additions/pageddialog.py @@ -69,10 +69,14 @@ class PagedDialog(QDialog): return def addTab(self, tabWidget, tabLabel): + """Forwards the adding of tabs to the QTabWidget. + """ self._tabBox.addTab(tabWidget, tabLabel) return def addControls(self, buttonBar): + """Adds a button bar to the dialog. + """ self._buttonBox.addWidget(buttonBar) return @@ -85,12 +89,16 @@ class VerticalTabBar(QTabBar): return def tabSizeHint(self, theIndex): + """Returns a transposed size hint for the rotated bar. + """ tSize = QTabBar.tabSizeHint(self, theIndex) tSize.transpose() return tSize def paintEvent(self, theEvent): - + """Custom implementation of the label painter that rotates the + label 90 degrees. + """ pObj = QStylePainter(self) oObj = QStyleOptionTab() diff --git a/nw/gui/additions/qconfiglayout.py b/nw/gui/additions/qconfiglayout.py index 032d0e6b..f4eb1ca7 100644 --- a/nw/gui/additions/qconfiglayout.py +++ b/nw/gui/additions/qconfiglayout.py @@ -69,11 +69,15 @@ class QConfigLayout(QGridLayout): return def setHelpText(self, intRow, theText): + """Set the text for the help label. + """ if intRow in self._itemMap: self._itemMap[intRow]["help"].setText(theText) return def setLabelText(self, intRow, theText): + """Set the text for the main label. + """ if intRow in self._itemMap: self._itemMap[intRow]["label"].setText(theText) return @@ -85,7 +89,6 @@ class QConfigLayout(QGridLayout): def addGroupLabel(self, theLabel): """Adds a text label to separate groups of settings. """ - if isinstance(theLabel, QLabel): qLabel = theLabel elif isinstance(theLabel, str): @@ -107,7 +110,6 @@ class QConfigLayout(QGridLayout): def addRow(self, theLabel, theWidget, helpText=None, theUnit=None): """Add a label and a widget as a new row of the grid. """ - thisEntry = { "label" : None, "help" : None, diff --git a/nw/gui/additions/qswitch.py b/nw/gui/additions/qswitch.py index 39fc5b8a..7eb32830 100644 --- a/nw/gui/additions/qswitch.py +++ b/nw/gui/additions/qswitch.py @@ -97,7 +97,6 @@ class QSwitch(QAbstractButton): def paintEvent(self, event): """Drawing the switch itself. """ - qPaint = QPainter(self) qPaint.setRenderHint(QPainter.Antialiasing, True) qPaint.setPen(Qt.NoPen) diff --git a/nw/gui/elements/docdetails.py b/nw/gui/elements/docdetails.py index 12eb6030..6a12f0b3 100644 --- a/nw/gui/elements/docdetails.py +++ b/nw/gui/elements/docdetails.py @@ -143,31 +143,33 @@ class GuiDocDetails(QFrame): self.pCountData.setAlignment(Qt.AlignRight) # Assemble - self.mainBox.addWidget(self.labelName, 0, 0, 1, 1) - self.mainBox.addWidget(self.labelFlag, 0, 1, 1, 1) - self.mainBox.addWidget(self.labelData, 0, 2, 1, 3) + self.mainBox.addWidget(self.labelName, 0, 0, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.labelFlag, 0, 1, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.labelData, 0, 2, 1, 3, Qt.AlignTop) - self.mainBox.addWidget(self.statusName, 1, 0, 1, 1) - self.mainBox.addWidget(self.statusFlag, 1, 1, 1, 1) - self.mainBox.addWidget(self.statusData, 1, 2, 1, 1) - self.mainBox.addWidget(self.cCountName, 1, 3, 1, 1) - self.mainBox.addWidget(self.cCountData, 1, 4, 1, 1) + self.mainBox.addWidget(self.statusName, 1, 0, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.statusFlag, 1, 1, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.statusData, 1, 2, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.cCountName, 1, 3, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.cCountData, 1, 4, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.className, 2, 0, 1, 1) - self.mainBox.addWidget(self.classFlag, 2, 1, 1, 1) - self.mainBox.addWidget(self.classData, 2, 2, 1, 1) - self.mainBox.addWidget(self.wCountName, 2, 3, 1, 1) - self.mainBox.addWidget(self.wCountData, 2, 4, 1, 1) + self.mainBox.addWidget(self.className, 2, 0, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.classFlag, 2, 1, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.classData, 2, 2, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.wCountName, 2, 3, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.wCountData, 2, 4, 1, 1, Qt.AlignTop) - self.mainBox.addWidget(self.layoutName, 3, 0, 1, 1) - self.mainBox.addWidget(self.layoutFlag, 3, 1, 1, 1) - self.mainBox.addWidget(self.layoutData, 3, 2, 1, 1) - self.mainBox.addWidget(self.pCountName, 3, 3, 1, 1) - self.mainBox.addWidget(self.pCountData, 3, 4, 1, 1) + self.mainBox.addWidget(self.layoutName, 3, 0, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.layoutFlag, 3, 1, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.layoutData, 3, 2, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.pCountName, 3, 3, 1, 1, Qt.AlignTop) + self.mainBox.addWidget(self.pCountData, 3, 4, 1, 1, Qt.AlignTop) self.mainBox.setColumnStretch(0,0) self.mainBox.setColumnStretch(1,0) self.mainBox.setColumnStretch(2,1) + self.mainBox.setColumnStretch(3,0) + self.mainBox.setColumnStretch(4,0) logger.debug("DocDetails initialisation complete") @@ -180,7 +182,6 @@ class GuiDocDetails(QFrame): def updateViewBox(self, tHandle): """Populate the details box from a given handle. """ - nwItem = self.theProject.projTree[tHandle] if nwItem is None: diff --git a/nw/gui/elements/doceditor.py b/nw/gui/elements/doceditor.py index 5e5e6228..906d4c65 100644 --- a/nw/gui/elements/doceditor.py +++ b/nw/gui/elements/doceditor.py @@ -141,7 +141,6 @@ class GuiDocEditor(QTextEdit): """Clear the current document and reset all document related flags and counters. """ - self.nwDocument.clearDocument() self.setReadOnly(True) self.clear() @@ -167,7 +166,6 @@ class GuiDocEditor(QTextEdit): settings. This function is both called when the editor is created, and when the user changes the main editor preferences. """ - # Some Constants self.nonWord = "\"'" self.nonWord += "".join(self.mainConf.fmtDoubleQuotes) @@ -241,7 +239,6 @@ class GuiDocEditor(QTextEdit): document is new (empty string), we set up the editor for editing the file. """ - theDoc = self.nwDocument.openDocument(tHandle, showStatus=showStatus) if theDoc is None: # There was an io error @@ -319,7 +316,6 @@ class GuiDocEditor(QTextEdit): Config.textFixedW is enabled or we're in Zen mode. Otherwise, just ensure the margins are set correctly. """ - if self.mainConf.textFixedW or self.theParent.isZenMode: vBar = self.verticalScrollBar() if vBar.isVisible(): @@ -376,6 +372,10 @@ class GuiDocEditor(QTextEdit): ## def setDocumentChanged(self, bValue): + """Keeps track of the document changed variable, and ensures + that the corresponding icon on the status bar shows the same + status. + """ self.docChanged = bValue self.theParent.statusBar.setDocumentStatus(self.docChanged) return self.docChanged @@ -437,7 +437,6 @@ class GuiDocEditor(QTextEdit): If the spell check mode (theMode) is not defined (None), then toggle the current status saved in this class. """ - if theMode is None: theMode = not self.spellCheck @@ -460,7 +459,6 @@ class GuiDocEditor(QTextEdit): currently loaded text. The fastest way to do this, at least as of Qt 5.13, is to clear the text and put it back. """ - logger.verbose("Running spell checker") if self.spellCheck: bfTime = time() @@ -481,6 +479,12 @@ class GuiDocEditor(QTextEdit): ## def docAction(self, theAction): + """Perform an action on the current document based on an action + flag. This is just a single entry point wrapper function to + ensure all the feature functions get the correct information + passed to it without having to consider the internal logic of + this class when calling these actions from other classes. + """ logger.verbose("Requesting action: %s" % theAction.name) if not self.theParent.hasProject: logger.error("No project open") @@ -537,9 +541,14 @@ class GuiDocEditor(QTextEdit): return True def isEmpty(self): + """Wrapper function to check if the current document is empty. + """ return self.qDocument.isEmpty() def revealLocation(self): + """Tell the user where on the file system the file in the editor + is saved. + """ if self.theHandle is not None: msgBox = QMessageBox() msgBox.information(self, "File Location", ( @@ -568,7 +577,6 @@ class GuiDocEditor(QTextEdit): However, we don't want to spend a lot of time in this function as it is triggered on every keypress when typing. """ - self.hasSelection = self.textCursor().hasSelection() if keyEvent.modifiers() == Qt.ShiftModifier: @@ -628,7 +636,6 @@ class GuiDocEditor(QTextEdit): """Triggered by right click to open the context menu. Also triggered by the Ctrl+. shortcut. """ - if not self.spellCheck: return @@ -667,7 +674,11 @@ class GuiDocEditor(QTextEdit): return + @pyqtSlot("QTextCursor", str) def _correctWord(self, theCursor, theWord): + """Slot for the spell check context menu triggering the + replacement of a word with the word from the dictionary. + """ xPos = theCursor.selectionStart() theCursor.beginEditBlock() theCursor.removeSelectedText() @@ -677,7 +688,11 @@ class GuiDocEditor(QTextEdit): self.setTextCursor(theCursor) return + @pyqtSlot("QTextCursor") def _addWord(self, theCursor): + """Slot for the spell check context menu triggered when the user + wants to add a word to the project dictionary. + """ theWord = theCursor.selectedText().strip().strip(self.nonWord) logger.debug("Added '%s' to project dictionary" % theWord) self.theDict.addWord(theWord) @@ -729,7 +744,6 @@ class GuiDocEditor(QTextEdit): tag and can tell the document viewer to try and find and load the file where the tag is defined. """ - if theCursor is None: theCursor = self.textCursor() @@ -772,13 +786,15 @@ class GuiDocEditor(QTextEdit): return def _openSpellContext(self): + """Opens the spell check context menu at the current point of + the cursor. + """ self._openContextMenu(self.cursorRect().center()) return def _docAutoReplace(self, theBlock): """Autoreplace text elements based on main configuration. """ - if not theBlock.isValid(): return @@ -870,7 +886,6 @@ class GuiDocEditor(QTextEdit): def _formatBlock(self, docAction): """Changes the block format of the block under the cursor. """ - theCursor = self.textCursor() theBlock = theCursor.block() if not theBlock.isValid(): @@ -949,6 +964,8 @@ class GuiDocEditor(QTextEdit): return def _makeSelection(self, selMode): + """Wrapper function to select a word based on a selection mode. + """ theCursor = self.textCursor() theCursor.clearSelection() theCursor.select(selMode) @@ -1025,7 +1042,6 @@ class GuiDocEditor(QTextEdit): """Create the spell checking object based on the spellTool setting in config. """ - if self.mainConf.spellTool == "enchant": from nw.core.spellcheck import NWSpellEnchant self.theDict = NWSpellEnchant() diff --git a/nw/gui/elements/doctitlebar.py b/nw/gui/elements/doctitlebar.py index 9e05f479..38425961 100644 --- a/nw/gui/elements/doctitlebar.py +++ b/nw/gui/elements/doctitlebar.py @@ -79,7 +79,6 @@ class GuiDocTitleBar(QLabel): """Sets the document title from the handle, or alternatively, set the whole document path. """ - self.setText("") self.theHandle = tHandle if tHandle is None: diff --git a/nw/gui/elements/doctree.py b/nw/gui/elements/doctree.py index a91ee10e..2c81cf91 100644 --- a/nw/gui/elements/doctree.py +++ b/nw/gui/elements/doctree.py @@ -105,13 +105,19 @@ class GuiDocTree(QTreeWidget): ## def clearTree(self): + """Clear the GUI content and the related maps. + """ self.clear() self.theMap = {} self.orphRoot = None return def newTreeItem(self, itemType, itemClass): - + """Add new item to the tree, with a given itemType and + itemClass, and attach it to the selected handle. Also make sure + the item is added in a place it can be added, and that other + meta data is set correctly to ensure a valid project tree. + """ pHandle = self.getSelectedHandle() if not self.theParent.hasProject: @@ -274,7 +280,6 @@ class GuiDocTree(QTreeWidget): function only asks for confirmation once, and calls the regular deleteItem function for each document in the Trash folder. """ - trashHandle = self.theProject.projTree.trashRoot() logger.debug("Emptying Trash folder") @@ -315,7 +320,6 @@ class GuiDocTree(QTreeWidget): that to save memory. Items not in the tree are not saved to the project file, so a loaded project will be clean anyway. """ - if tHandle is None: tHandle = self.getSelectedHandle() @@ -446,6 +450,13 @@ class GuiDocTree(QTreeWidget): return def propagateCount(self, tHandle, theCount, nDepth=0): + """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 not None: tItem.setText(self.C_COUNT,str(theCount)) @@ -460,6 +471,12 @@ class GuiDocTree(QTreeWidget): return def projectWordCount(self): + """Sum up the word counts for all root items and set the + relevant values in the project and on the status bar. This call + is a fast way of getting this number, and depends on the + propagateCount function being called when it should to maintain + the correct count. + """ nWords = 0 for n in range(self.topLevelItemCount()): tItem = self.topLevelItem(n) @@ -472,6 +489,11 @@ class GuiDocTree(QTreeWidget): return def buildTree(self): + """Build the entire project tree from scratch. This depends on + the save project item iterator in the project class which will + always make sure items with a parent have had their parent item + sent first. + """ self.clear() for nwItem in self.theProject.getProjectItems(): self._addTreeItem(nwItem) @@ -517,11 +539,16 @@ class GuiDocTree(QTreeWidget): ## def _getTreeItem(self, tHandle): + """Returns the QTreeWidgetItem of a given item handle. + """ if tHandle in self.theMap.keys(): return self.theMap[tHandle] return None def _scanChildren(self, theList, theItem, theIndex): + """This is a recursive function returning all items in a tree + starting at a given QTreeWidgetItem. + """ tHandle = theItem.text(self.C_HANDLE) nwItem = self.theProject.projTree[tHandle] nwItem.setExpanded(theItem.isExpanded()) @@ -532,7 +559,9 @@ class GuiDocTree(QTreeWidget): return theList def _addTreeItem(self, nwItem): - + """Create a QTreeWidgetItem from an NWItem and add it to the + project tree. + """ tHandle = nwItem.itemHandle pHandle = nwItem.parHandle tClass = nwItem.itemClass @@ -591,6 +620,9 @@ class GuiDocTree(QTreeWidget): return trItem def _addOrphanedRoot(self): + """Add the special Orphaned Files root item to hold non-root + items with no parent set. + """ if self.orphRoot is None: newItem = QTreeWidgetItem([""]*4) newItem.setText(self.C_NAME, "Orphaned Files") @@ -604,6 +636,8 @@ class GuiDocTree(QTreeWidget): return def _cleanOrphanedRoot(self): + """Remove the special Orphaned Files root folder if it is empty. + """ if self.orphRoot is not None: if self.orphRoot.childCount() == 0: self.takeTopLevelItem(self.indexOfTopLevelItem(self.orphRoot)) @@ -615,7 +649,6 @@ class GuiDocTree(QTreeWidget): in the project is consistent with the treeView. Also move the word count over to the new parent tree. """ - trItemS = self._getTreeItem(tHandle) nwItemS = self.theProject.projTree[tHandle] trItemP = trItemS.parent() @@ -636,6 +669,10 @@ class GuiDocTree(QTreeWidget): return True def _moveOrphanedItem(self, tHandle, dHandle): + """Move an Orphaned Item to a new dHandle parent item. This + function will set all the missing meta data based on the meta + data of the destination item. + """ trItemS = self._getTreeItem(tHandle) nwItemS = self.theProject.projTree[tHandle] nwItemD = self.theProject.projTree[dHandle] diff --git a/nw/gui/elements/docviewer.py b/nw/gui/elements/docviewer.py index c99b1de1..7fdf22e4 100644 --- a/nw/gui/elements/docviewer.py +++ b/nw/gui/elements/docviewer.py @@ -88,7 +88,6 @@ class GuiDocViewer(QTextBrowser): def initViewer(self): """Set editor settings from main config. """ - self._makeStyleSheet() # Set Font @@ -122,7 +121,6 @@ class GuiDocViewer(QTextBrowser): def loadText(self, tHandle): """Load text into the viewer from an item handle. """ - tItem = self.theProject.projTree[tHandle] if tItem is None: logger.warning("Item not found") @@ -153,11 +151,16 @@ class GuiDocViewer(QTextBrowser): return True def reloadText(self): + """Reload the text in the current document. + """ self.loadText(self.theHandle) return def loadFromTag(self, theTag): - + """Load text in the document from a reference given by a meta + tag rather than a known handle. This function depends on the + index being up to date. + """ logger.debug("Loading document from tag '%s'" % theTag) if theTag in self.theParent.theIndex.tagIndex.keys(): @@ -175,6 +178,9 @@ class GuiDocViewer(QTextBrowser): return True def docAction(self, theAction): + """Wrapper function for various document actions on the current + document. + """ logger.verbose("Requesting action: %s" % theAction.name) if self.theHandle is None: logger.error("No document open") @@ -225,6 +231,9 @@ class GuiDocViewer(QTextBrowser): ## def _makeSelection(self, selMode): + """Wrapper function for making a selection based on a specific + selection mode. + """ theCursor = self.textCursor() theCursor.clearSelection() theCursor.select(selMode) @@ -232,7 +241,8 @@ class GuiDocViewer(QTextBrowser): return def _linkClicked(self, theURL): - + """Slot for a link in the document being clicked. + """ theLink = theURL.url() tHandle = None onLine = 0 @@ -256,7 +266,9 @@ class GuiDocViewer(QTextBrowser): return def _makeStyleSheet(self): - + """Generate an appropriate style sheet for the document viewer, + based on the current syntax highlighter theme, + """ styleSheet = ( "body {{" " color: rgb({tColR},{tColG},{tColB});" diff --git a/nw/gui/elements/noticebar.py b/nw/gui/elements/noticebar.py index b5580984..4b6d57aa 100644 --- a/nw/gui/elements/noticebar.py +++ b/nw/gui/elements/noticebar.py @@ -67,11 +67,15 @@ class GuiNoticeBar(QFrame): return def showNote(self, theNote): + """Show the note on the noticebar. + """ self.noteLabel.setText("Note: %s" % theNote) self.setVisible(True) return def hideNote(self): + """Clear the noticebar and hide it. + """ self.noteLabel.setText("") self.setVisible(False) return diff --git a/nw/gui/elements/outline.py b/nw/gui/elements/outline.py index 408dc126..f09a38b6 100644 --- a/nw/gui/elements/outline.py +++ b/nw/gui/elements/outline.py @@ -125,7 +125,6 @@ class GuiProjectOutline(QTreeWidget): """Clear the tree and header and set the default values for the columns arrays. """ - self.clear() self.setColumnCount(1) self.setHeaderLabel(nwLabels.OUTLINE_COLS[nwOutline.TITLE]) @@ -150,7 +149,6 @@ class GuiProjectOutline(QTreeWidget): what data to load, and if necessary, force a rebuild of the tree. """ - # If it's the first time, we always build if self.firstView or self.firstView and overRide: self._loadHeaderState() @@ -229,7 +227,6 @@ class GuiProjectOutline(QTreeWidget): """Load the state of the main tree header, that is, column order and column width. """ - # Load whatever we saved last time, regardless of wether it # contains the correct names or number of columns. The names # must be valid though. @@ -280,7 +277,6 @@ class GuiProjectOutline(QTreeWidget): save the current width of hidden columns though. This preserves the last known width in case they're unhidden again. """ - # If we haven't built the tree, there is nothing to save. if self.lastBuild == 0: return diff --git a/nw/gui/elements/searchbar.py b/nw/gui/elements/searchbar.py index 431bddad..590d8d0a 100644 --- a/nw/gui/elements/searchbar.py +++ b/nw/gui/elements/searchbar.py @@ -98,6 +98,9 @@ class GuiSearchBar(QFrame): ## def setSearchText(self, theText): + """Open the search bar and set the search text to the text + provided, if any. + """ if not self.isVisible(): self.setVisible(True) self.searchBox.setText(theText) @@ -106,15 +109,21 @@ class GuiSearchBar(QFrame): return True def setReplaceText(self, theText): + """Set the replace text. + """ self._replaceVisible(True) self.replaceBox.setFocus() self.replaceBox.setText(theText) return True def getSearchText(self): + """Return the current search text. + """ return self.searchBox.text() def getReplaceText(self): + """Return the current replace text. + """ return self.replaceBox.text() ## @@ -122,11 +131,15 @@ class GuiSearchBar(QFrame): ## def _doClose(self): + """Hide the search/replace bar. + """ self._replaceVisible(False) self.setVisible(False) return def _doSearch(self): + """Call the search action function for the document editor. + """ modKey = qApp.keyboardModifiers() if modKey == Qt.ShiftModifier: self.theParent.docEditor.docAction(nwDocAction.GO_PREV) @@ -135,10 +148,14 @@ class GuiSearchBar(QFrame): return def _doReplace(self): + """Call the replace action function for the document editor. + """ self.theParent.docEditor.docAction(nwDocAction.REPL_NEXT) return def _replaceVisible(self, isVisible): + """Set the visibility of all the replace widgets. + """ self.replaceLabel.setVisible(isVisible) self.replaceBox.setVisible(isVisible) self.replaceButton.setVisible(isVisible) diff --git a/nw/gui/elements/viewdetails.py b/nw/gui/elements/viewdetails.py index cb0d6af3..589ffee5 100644 --- a/nw/gui/elements/viewdetails.py +++ b/nw/gui/elements/viewdetails.py @@ -94,7 +94,9 @@ class GuiDocViewDetails(QWidget): return def refreshReferences(self, tHandle): - + """Update the current list of document references from the + project index. + """ self.currHandle = tHandle if self.isSticky.isChecked(): @@ -117,12 +119,17 @@ class GuiDocViewDetails(QWidget): ## def _linkClicked(self, theLink): + """Capture the link-click and forward it to the document viewer + class for handling. + """ if len(theLink) == 18: tHandle = theLink[-13:] self.theParent.viewDocument(tHandle) return def _doShowHide(self, chState): + """Toggle the expand/collapse of the panel. + """ self.scrollBox.setVisible(chState) self.mainConf.setShowRefPanel(chState) if chState: @@ -132,6 +139,8 @@ class GuiDocViewDetails(QWidget): return def _doSticky(self, chState): + """Toggle the sticky feature of the references. + """ if not chState and self.currHandle is not None: self.refreshReferences(self.currHandle) return diff --git a/nw/gui/tools/dochighlight.py b/nw/gui/tools/dochighlight.py index 9d57b612..cda6ac03 100644 --- a/nw/gui/tools/dochighlight.py +++ b/nw/gui/tools/dochighlight.py @@ -75,6 +75,9 @@ class GuiDocHighlighter(QSyntaxHighlighter): return def initHighlighter(self): + """Initialise the syntax highlighter, setting all the colour + rules and building the regexes. + """ logger.debug("Setting up highlighting rules") @@ -205,14 +208,21 @@ class GuiDocHighlighter(QSyntaxHighlighter): ## def setDict(self, theDict): + """Set the dictionary object for spell check underlines lookup. + """ self.theDict = theDict return True def setSpellCheck(self, theMode): + """Enable/disable the real time spell checker. + """ self.spellCheck = theMode return True def setHandle(self, theHandle): + """Set the handle of the currently highlighted document. This is + needed for the index lookup for validating tags and references. + """ self.theHandle = theHandle return True @@ -226,7 +236,6 @@ class GuiDocHighlighter(QSyntaxHighlighter): is significantly faster than running the regex checks we use for text paragraphs. """ - if self.theHandle is None or not theText: return @@ -317,7 +326,6 @@ class GuiDocHighlighter(QSyntaxHighlighter): """Generate a valid character format to be applied to the text that is to be highlighted. """ - theFormat = QTextCharFormat() if fmtCol is not None: diff --git a/nw/gui/tools/optionstate.py b/nw/gui/tools/optionstate.py index ed45e7cf..5f265622 100644 --- a/nw/gui/tools/optionstate.py +++ b/nw/gui/tools/optionstate.py @@ -51,7 +51,6 @@ class OptionState(): def loadSettings(self): """Load the options dictionary from the project settings file. """ - if self.theProject.projMeta is None: return False @@ -76,7 +75,6 @@ class OptionState(): def saveSettings(self): """Save the options dictionary to the project settings file. """ - if self.theProject.projMeta is None: return False diff --git a/nw/gui/tools/wordcounter.py b/nw/gui/tools/wordcounter.py index 24a0b9ca..49255040 100644 --- a/nw/gui/tools/wordcounter.py +++ b/nw/gui/tools/wordcounter.py @@ -45,7 +45,9 @@ class WordCounter(QThread): return def run(self): - + """Overloaded run function for the word counter, forwarding the + call to the function that does the actual counting. + """ theText = self.theParent.getText() cC, wC, pC = countWords(theText) diff --git a/nw/guimain.py b/nw/guimain.py index 558712ed..b15edbe9 100644 --- a/nw/guimain.py +++ b/nw/guimain.py @@ -57,7 +57,7 @@ class GuiMain(QMainWindow): logger.info("Starting %s" % nw.__package__) logger.debug("Initialising GUI ...") - self.mainConf = nw.CONFIG + self.mainConf = nw.CONFIG # Some runtime info useful for debugging logger.info("OS: %s" % self.mainConf.osType)