Make comments and docstrings comply with PEP8

This commit is contained in:
Veronica K. B. Olsen
2019-11-03 17:23:39 +01:00
parent be78fd201e
commit 7c95af951a
20 changed files with 287 additions and 184 deletions
+2 -2
View File
@@ -83,8 +83,8 @@ def colRange(rgbStart, rgbEnd, nStep):
return retCol
def splitVersionNumber(vString):
""" Splits a version string on the form aa.bb.cc into major, minor and patch, and computes an
integer value aabbcc.
""" Splits a version string on the form aa.bb.cc into major, minor
and patch, and computes an integer value aabbcc.
"""
vMajor = 0
+15 -11
View File
@@ -100,9 +100,9 @@ class TextFile():
self.fileName = path.basename(filePath)
if path.isfile(filePath) and self.mainConf.showGUI:
msgBox = QMessageBox()
msgRes = msgBox.question(
self.theParent, "Overwrite", ("File '%s' already exists.<br>Do you want to overwrite it?" % self.fileName)
)
msgRes = msgBox.question(self.theParent, "Overwrite", (
"File '%s' already exists.<br>Do you want to overwrite it?" % self.fileName
))
if msgRes != QMessageBox.Yes:
return False
@@ -137,11 +137,14 @@ class TextFile():
return True
def checkInclude(self, tHandle):
"""This function checks whether a file should be included in the export or not. For standard
note and novel files, this is controlled by the options selected by the user. For other
files classified as non-exportable, a few checks must be made, and the following are not:
"""This function checks whether a file should be included in the
export or not. For standard note and novel files, this is
controlled by the options selected by the user. For other files
classified as non-exportable, a few checks must be made, and the
following are not:
* Items that are not actual files.
* Items that have been orphaned which are tagged as NO_LAYOUT and NO_CLASS.
* Items that have been orphaned which are tagged as NO_LAYOUT
and NO_CLASS.
* Items that appear in the TRASH folder
"""
@@ -168,8 +171,9 @@ class TextFile():
##
def _doOpenFile(self, filePath):
"""This function does the actual opening of the file, and can be overloaded by a subclass
that uses a different file format that requires a different approach.
"""This function does the actual opening of the file, and can be
overloaded by a subclass that uses a different file format that
requires a different approach.
"""
try:
self.outFile = open(filePath,mode="wt+",encoding="utf8")
@@ -180,8 +184,8 @@ class TextFile():
return True
def _doCloseFile(self):
"""This function closes the file, and is meant to be overloaded by the subclass for other
file formats.
"""This function closes the file, and is meant to be overloaded
by the subclass for other file formats.
"""
if self.outFile is not None:
self.outFile.close()
+3 -2
View File
@@ -27,8 +27,9 @@ class ToHtml(Tokenizer):
return
def setPreview(self, forPreview, doComments):
"""If we're using this class to generate markdown preview, we need to make a few changes to
formatting, which is selected by this flag.
"""If we're using this class to generate markdown preview, we
need to make a few changes to formatting, which is selected by
this flag.
"""
self.forPreview = forPreview
+8 -5
View File
@@ -28,7 +28,8 @@ class ToLaTeX(Tokenizer):
return
def doPostProcessing(self):
"""The latexcodec misses dashes and non-breaking spaces, so we do those here.
"""The latexcodec misses dashes and non-breaking spaces, so we
do those here.
"""
repDict = {
@@ -62,8 +63,9 @@ class ToLaTeX(Tokenizer):
begText = "\\begin{center}\n"
endText = "\\end{center}\n\n"
# First check if we have a comment or plain text, as they need some
# extra replacing before we proceed to wrapping and final formatting.
# First check if we have a comment or plain text, as they
# need some extra replacing before we proceed to wrapping
# and final formatting.
if tType == self.T_COMMENT:
tText = "%% %s" % tText
@@ -75,8 +77,9 @@ class ToLaTeX(Tokenizer):
tLen = len(tText)
# Then the text can receive final formatting before we append it to the results.
# We also store text lines in a buffer and merge them only when we find an empty line
# Then the text can receive final formatting before we
# append it to the results. We also store text lines in a
# buffer and merge them only when we find an empty line
# indicating a new paragraph.
if tType == self.T_EMPTY:
if len(thisPar) > 0:
+8 -5
View File
@@ -55,8 +55,9 @@ class ToMarkdown(Tokenizer):
thisPar = []
for tType, tText, tFormat, tAlign in self.theTokens:
# First check if we have a comment or plain text, as they need some
# extra replacing before we proceed to wrapping and final formatting.
# First check if we have a comment or plain text, as they
# need some extra replacing before we proceed to wrapping
# and final formatting.
if tType == self.T_COMMENT:
tText = " %s" % tText
@@ -68,7 +69,8 @@ class ToMarkdown(Tokenizer):
tLen = len(tText)
# The text can now be word wrapped, if we have requested this and it's needed.
# The text can now be word wrapped, if we have requested
# this and it's needed.
if self.wordWrap > 0 and tLen > self.wordWrap:
if tType == self.T_COMMENT:
tText = textwrap.fill(
@@ -77,8 +79,9 @@ class ToMarkdown(Tokenizer):
else:
tText = tWrap.fill(tText)
# Then the text can receive final formatting before we append it to the results.
# We also store text lines in a buffer and merge them only when we find an empty line,
# Then the text can receive final formatting before we
# append it to the results. We also store text lines in a
# buffer and merge them only when we find an empty line,
# indicating a new paragraph.
if tType == self.T_EMPTY:
if len(thisPar) > 0:
+8 -5
View File
@@ -61,8 +61,9 @@ class ToText(Tokenizer):
thisPar = []
for tType, tText, tFormat, tAlign in self.theTokens:
# First check if we have a comment or plain text, as they need some
# extra replacing before we proceed to wrapping and final formatting.
# First check if we have a comment or plain text, as they
# need some extra replacing before we proceed to wrapping
# and final formatting.
if tType == self.T_COMMENT:
tText = "[%s]" % tText
@@ -74,7 +75,8 @@ class ToText(Tokenizer):
tLen = len(tText)
# The text can now be word wrapped, if we have requested this and it's needed.
# The text can now be word wrapped, if we have requested
# this and it's needed.
if tAlign == self.A_CENTRE:
if self.wordWrap > 0:
if tLen > self.wordWrap:
@@ -88,8 +90,9 @@ class ToText(Tokenizer):
if self.wordWrap > 0 and tLen > self.wordWrap:
tText = tWrap.fill(tText)
# Then the text can receive final formatting before we append it to the results.
# We also store text lines in a buffer and merge them only when we find an empty line,
# Then the text can receive final formatting before we
# append it to the results. We also store text lines in a
# buffer and merge them only when we find an empty line,
# indicating a new paragraph.
if tType == self.T_EMPTY:
if len(thisPar) > 0:
+5 -4
View File
@@ -153,10 +153,11 @@ class Tokenizer():
return
def tokenizeText(self):
"""Scan the text for either lines starting with specific characters that indicate headers,
comments, commands etc, or just contains plain text. in the case of plain text, apply the
same RegExes that the syntax highlighter uses and save the locations of these formatting
tags into the token array.
"""Scan the text for either lines starting with specific
characters that indicate headers, comments, commands etc, or
just contains plain text. in the case of plain text, apply the
same RegExes that the syntax highlighter uses and save the
locations of these formatting tags into the token array.
"""
# RegExes for adding formatting tags within text lines
+4 -3
View File
@@ -362,8 +362,8 @@ class GuiExportMain(QWidget):
"Comments are exported as LaTeX comments."
),
FMT_PDOC : (
"Exports first to markdown or html5. The file is then passed on to Pandoc for a second "
"stage. Use the Pandoc tab for settings up the conversion."
"Exports first to markdown or html5. The file is then passed on to Pandoc for a "
"second stage. Use the Pandoc tab for settings up the conversion."
),
}
@@ -537,7 +537,8 @@ class GuiExportMain(QWidget):
##
def _updateFormat(self, currIdx):
"""Update help text under output format selection and file extension in file box
"""Update help text under output format selection and file
extension in file box
"""
if currIdx == -1:
self.outputHelp.setText("")
+9 -3
View File
@@ -51,9 +51,15 @@ class GuiSessionLogView(QDialog):
self.setMinimumWidth(420)
self.setMinimumHeight(400)
widthCol0 = self.optState.validIntRange(self.optState.getSetting("widthCol0"), 30, 999, 180)
widthCol1 = self.optState.validIntRange(self.optState.getSetting("widthCol1"), 30, 999, 80)
widthCol2 = self.optState.validIntRange(self.optState.getSetting("widthCol2"), 30, 999, 80)
widthCol0 = self.optState.validIntRange(
self.optState.getSetting("widthCol0"), 30, 999, 180
)
widthCol1 = self.optState.validIntRange(
self.optState.getSetting("widthCol1"), 30, 999, 80
)
widthCol2 = self.optState.validIntRange(
self.optState.getSetting("widthCol2"), 30, 999, 80
)
self.listBox = QTreeWidget()
self.listBox.setHeaderLabels(["Session Start","Length","Words",""])
+86 -55
View File
@@ -136,9 +136,9 @@ class GuiDocEditor(QTextEdit):
return True
def initEditor(self):
"""Initialise or re-initialise the editor with the user's settings.
This function is both called when the editor is created, and when the user changes the
main editor preferences.
"""Initialise or re-initialise the editor with the user's
settings. This function is both called when the editor is
created, and when the user changes the main editor preferences.
"""
# Reload dictionaries
@@ -179,10 +179,12 @@ class GuiDocEditor(QTextEdit):
# Initialise the syntax highlighter
self.hLight.initHighlighter()
# If we have a document open, we should reload it in case the font changed, otherwise
# we just clear the editor entirely, which makes it read only.
# If we have a document open, we should reload it in case the
# font changed, otherwise we just clear the editor entirely,
# which makes it read only.
if self.theHandle is not None:
# We must save the current handle as clearEditor() sets it to None
# We must save the current handle as clearEditor() sets it
# to None
tHandle = self.theHandle
self.clearEditor()
self.loadText(tHandle)
@@ -193,11 +195,13 @@ class GuiDocEditor(QTextEdit):
return True
def loadText(self, tHandle):
"""Load text from a document into the editor. If we have an io error, we must handle this
and clear the editor so that we don't risk overwriting the file if it exists. This can for
instance happen of the file contains binary elements or an encoding that novelWriter does
not support. If load is successful, ot the document is new (empty string) we set up the
editor for editing the file.
"""Load text from a document into the editor. If we have an io
error, we must handle this and clear the editor so that we don't
risk overwriting the file if it exists. This can for instance
happen of the file contains binary elements or an encoding that
novelWriter does not support. If load is successful, or the
document is new (empty string) we set up the editor for editing
the file.
"""
theDoc = self.nwDocument.openDocument(tHandle)
@@ -251,8 +255,9 @@ class GuiDocEditor(QTextEdit):
return self.docChanged
def getText(self):
"""Get the text content of the current document. This method uses QTextEdit->toPlainText for
Qt versions lower than 5.9, and the QDocument->toRawText for higher version. The latter
"""Get the text content of the current document. This method
uses QTextEdit->toPlainText for Qt versions lower than 5.9, and
the QDocument->toRawText for higher version. The latter
preserves non-breaking spaces, which the former does not.
"""
if self.mainConf.verQtValue >= 50900:
@@ -296,8 +301,8 @@ class GuiDocEditor(QTextEdit):
##
def changeWidth(self):
"""Automatically adjust the margins so the text is centred, but only if Config.textFixedW is
set to True.
"""Automatically adjust the margins so the text is centred, but
only if Config.textFixedW is set to True.
"""
if self.mainConf.textFixedW:
vBar = self.verticalScrollBar()
@@ -322,23 +327,40 @@ class GuiDocEditor(QTextEdit):
if not self.theParent.hasProject:
logger.error("No project open")
return False
if theAction == nwDocAction.UNDO: self.undo()
elif theAction == nwDocAction.REDO: self.redo()
elif theAction == nwDocAction.CUT: self.cut()
elif theAction == nwDocAction.COPY: self.copy()
elif theAction == nwDocAction.PASTE: self.paste()
elif theAction == nwDocAction.BOLD: self._wrapSelection("**","**")
elif theAction == nwDocAction.ITALIC: self._wrapSelection("_","_")
elif theAction == nwDocAction.U_LINE: self._wrapSelection("__","__")
elif theAction == nwDocAction.S_QUOTE: self._wrapSelection(self.typSQOpen,self.typSQClose)
elif theAction == nwDocAction.D_QUOTE: self._wrapSelection(self.typDQOpen,self.typDQClose)
elif theAction == nwDocAction.SEL_ALL: self._makeSelection(QTextCursor.Document)
elif theAction == nwDocAction.SEL_PARA: self._makeSelection(QTextCursor.BlockUnderCursor)
elif theAction == nwDocAction.FIND: self._beginSearch()
elif theAction == nwDocAction.REPLACE: self._beginReplace()
elif theAction == nwDocAction.GO_NEXT: self._findNext()
elif theAction == nwDocAction.GO_PREV: self._findPrev()
elif theAction == nwDocAction.REPL_NEXT: self._replaceNext()
if theAction == nwDocAction.UNDO:
self.undo()
elif theAction == nwDocAction.REDO:
self.redo()
elif theAction == nwDocAction.CUT:
self.cut()
elif theAction == nwDocAction.COPY:
self.copy()
elif theAction == nwDocAction.PASTE:
self.paste()
elif theAction == nwDocAction.BOLD:
self._wrapSelection("**","**")
elif theAction == nwDocAction.ITALIC:
self._wrapSelection("_","_")
elif theAction == nwDocAction.U_LINE:
self._wrapSelection("__","__")
elif theAction == nwDocAction.S_QUOTE:
self._wrapSelection(self.typSQOpen,self.typSQClose)
elif theAction == nwDocAction.D_QUOTE:
self._wrapSelection(self.typDQOpen,self.typDQClose)
elif theAction == nwDocAction.SEL_ALL:
self._makeSelection(QTextCursor.Document)
elif theAction == nwDocAction.SEL_PARA:
self._makeSelection(QTextCursor.BlockUnderCursor)
elif theAction == nwDocAction.FIND:
self._beginSearch()
elif theAction == nwDocAction.REPLACE:
self._beginReplace()
elif theAction == nwDocAction.GO_NEXT:
self._findNext()
elif theAction == nwDocAction.GO_PREV:
self._findPrev()
elif theAction == nwDocAction.REPL_NEXT:
self._replaceNext()
else:
logger.error("Unknown or unsupported document action %s" % str(theAction))
return False
@@ -366,13 +388,15 @@ class GuiDocEditor(QTextEdit):
def keyPressEvent(self, keyEvent):
"""Intercept key press events.
We need to intercept key presses briefly to record the state of selection. This is in order
to know whether we had a selection prior to triggering the _docChange slot, as we do not
want to trigger autoreplace on selections. Autoreplace on selections messes with undo/redo
history.
We also need to intercept the Shift key modifier for certain key combinations that modifies
standard keys like enter and space. However, we don't want to spend a lot of time in this
function as it is triggered on every keypress when typing.
We need to intercept key presses briefly to record the state of
selection. This is in order to know whether we had a selection
prior to triggering the _docChange slot, as we do not want to
trigger autoreplace on selections. Autoreplace on selections
messes with undo/redo history.
We also need to intercept the Shift key modifier for certain key
combinations that modifies standard keys like enter and space.
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()
@@ -393,8 +417,9 @@ class GuiDocEditor(QTextEdit):
return
def mouseReleaseEvent(self, mEvent):
"""If the mouse button is released and the control key is pressed, check if we're clicking
on a tag, and trigger the follow tag function.
"""If the mouse button is released and the control key is
pressed, check if we're clicking on a tag, and trigger the
follow tag function.
"""
if qApp.keyboardModifiers() == Qt.ControlModifier:
theCursor = self.cursorForPosition(mEvent.pos())
@@ -407,9 +432,11 @@ class GuiDocEditor(QTextEdit):
##
def _followTag(self, theCursor=None):
"""Activated by Ctrl+Enter. Checks that we're in a block starting with '@'. We then find the
word under the cursor and check that it is after the ':'. If all this is fine, we have a tag
and can tell the document viewer to try and find and load the file where the tag is defined.
"""Activated by Ctrl+Enter. Checks that we're in a block
starting with '@'. We then find the word under the cursor and
check that it is after the ':'. If all this is fine, we have a
tag and can tell the document viewer to try and find and load
the file where the tag is defined.
"""
if theCursor is None:
@@ -574,7 +601,8 @@ class GuiDocEditor(QTextEdit):
return
def _runCounter(self):
"""Decide whether to run the word counter, or stop the timer due to inactivity.
"""Decide whether to run the word counter, or stop the timer due
to inactivity.
"""
sinceActive = time()-self.lastEdit
if sinceActive > 5*self.wcInterval:
@@ -603,9 +631,10 @@ class GuiDocEditor(QTextEdit):
return
def _wrapSelection(self, tBefore, tAfter):
"""Wraps the selected text in whatever is in tBefore and tAfter. If there is no selection,
the autoSelect setting decides the action. AutoSelect will select the word under the cursor
before wrapping it. If this feature is disabled, nothing is done.
"""Wraps the selected text in whatever is in tBefore and tAfter.
If there is no selection, the autoSelect setting decides the
action. AutoSelect will select the word under the cursor before
wrapping it. If this feature is disabled, nothing is done.
"""
theCursor = self.textCursor()
if self.mainConf.autoSelect and not theCursor.hasSelection():
@@ -643,15 +672,16 @@ class GuiDocEditor(QTextEdit):
return
def _beginReplace(self):
"""Opens the replace line of the search bar and sets the replace text.
"""Opens the replace line of the search bar and sets the replace
text.
"""
self._beginSearch()
self.theParent.searchBar.setReplaceText("")
return
def _findNext(self):
"""Searches for the next occurrence of the search bar text in the document.
Wraps back to the top if not found.
"""Searches for the next occurrence of the search bar text in
the document. Wraps back to the top if not found.
"""
searchFor = self.theParent.searchBar.getSearchText()
wasFound = self.find(searchFor)
@@ -662,8 +692,8 @@ class GuiDocEditor(QTextEdit):
return
def _findPrev(self):
"""Searches for the previous occurrence of the search bar text in the document.
Wraps back to the end if not found.
"""Searches for the previous occurrence of the search bar text
in the document. Wraps back to the end if not found.
"""
searchFor = self.theParent.searchBar.getSearchText()
wasFound = self.find(searchFor, QTextDocument.FindBackward)
@@ -674,8 +704,9 @@ class GuiDocEditor(QTextEdit):
return
def _replaceNext(self):
"""Searches for the next occurrence of the search bar text in the document and replaces it
with the replace text. Wraps back to the top if not found.
"""Searches for the next occurrence of the search bar text in
the document and replaces it with the replace text. Wraps back
to the top if not found.
"""
theCursor = self.textCursor()
searchFor = self.theParent.searchBar.getSearchText()
+18 -14
View File
@@ -129,7 +129,8 @@ class GuiDocTree(QTreeWidget):
tHandle = self.theProject.newRoot(nwLabels.CLASS_NAME[itemClass], itemClass)
else:
# If no parent has been selected, make the new file under the root NOVEL item.
# If no parent has been selected, make the new file under
# the root NOVEL item.
if pHandle is None:
pHandle = self.theProject.findRootItem(nwItemClass.NOVEL)
@@ -138,7 +139,8 @@ class GuiDocTree(QTreeWidget):
logger.error("Did not find anywhere to add the item!")
return False
# Now check if the selected item is a file, in which case the new file will be a sibling
# Now check if the selected item is a file, in which case
# the new file will be a sibling
pItem = self.theProject.getItem(pHandle)
if pItem.itemType == nwItemType.FILE:
pHandle = pItem.parHandle
@@ -177,8 +179,8 @@ class GuiDocTree(QTreeWidget):
return True
def moveTreeItem(self, nStep):
"""Move an item up or down in the tree, but only if the treeView has focus. This also
applies when the menu is used.
"""Move an item up or down in the tree, but only if the treeView
has focus. This also applies when the menu is used.
"""
if QApplication.focusWidget() == self and self.theParent.hasProject:
tHandle = self.getSelectedHandle()
@@ -225,10 +227,11 @@ class GuiDocTree(QTreeWidget):
return retVals
def deleteItem(self, tHandle=None):
"""Delete items from the tree. Note that this does not delete the item from the item tree in
the project object. However, since this is only meta data, there isn't really a need to do
that to save memory. Items not in the tree are not saved to the project file, so a loaded
project will be clean anyway.
"""Delete items from the tree. Note that this does not delete
the item from the item tree in the project object. However,
since this is only meta data, there isn't really a need to do
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:
@@ -453,8 +456,9 @@ class GuiDocTree(QTreeWidget):
return
def _updateItemParent(self, tHandle):
"""Update the parent handle of an item so that the information in the project is consistent
with the treeView. Also move the word count over to the new parent tree.
"""Update the parent handle of an item so that the information
in the project is consistent with the treeView. Also move the
word count over to the new parent tree.
"""
trItemS = self._getTreeItem(tHandle)
@@ -496,8 +500,8 @@ class GuiDocTree(QTreeWidget):
##
def mousePressEvent(self, theEvent):
"""Overload mousePressEvent to clear selection if clicking the mouse in a blank
area of the tree view.
"""Overload mousePressEvent to clear selection if clicking the
mouse in a blank area of the tree view.
"""
QTreeWidget.mousePressEvent(self, theEvent)
selItem = self.indexAt(theEvent.pos())
@@ -506,8 +510,8 @@ class GuiDocTree(QTreeWidget):
return
def dropEvent(self, theEvent):
"""Overload the drop of dragged item event to check whether the drop is allowed
or not. Disallowed drops are cancelled.
"""Overload the drop of dragged item event to check whether the
drop is allowed or not. Disallowed drops are cancelled.
"""
sHandle = self.getSelectedHandle()
if sHandle is None:
+4 -3
View File
@@ -17,7 +17,7 @@ from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QIcon, QDesktopServices
from PyQt5.QtWidgets import QMenuBar, QAction, QMessageBox
from nw.enum import nwItemType, nwItemClass, nwDocAction
from nw.enum import nwItemType, nwItemClass, nwDocAction
logger = logging.getLogger(__name__)
@@ -122,8 +122,9 @@ class GuiMainMenu(QMenuBar):
aboutMsg = (
"<h3>About {name:s}</h3>"
"<p>Version: {version:s}<br>Release Date: {date:s}</p>"
"<p>{name:s} is a markdown-like text editor designed for organising and writing novels. "
"It is written in Python 3 with a Qt5 GUI, using PyQt5</p>"
"<p>{name:s} is a markdown-like text editor designed for organising "
"and writing novels. It is written in Python 3 with a Qt5 GUI, "
"using PyQt5</p>"
"<p>{name:s} is licensed under GPL v3.0</p>"
"<p>{copyright:s}</p>"
"<p>Website: <a href='{website:s}'>{website:s}</a></p>"
+20 -12
View File
@@ -244,7 +244,8 @@ class GuiMain(QMainWindow):
def closeProject(self, isYes=False):
"""Closes the project if one is open.
isYes is passed on from the close application event so the user doesn't get prompted twice.
isYes is passed on from the close application event so the user
doesn't get prompted twice.
"""
if not self.hasProject:
# There is no project loaded, everything OK
@@ -288,15 +289,17 @@ class GuiMain(QMainWindow):
return saveOK
def openProject(self, projFile=None):
"""Open a project. The parameter projFile is passed from the open recent projects menu, so
can be set. If not, we pop the dialog.
"""Open a project. The parameter projFile is passed from the
open recent projects menu, so can be set. If not, we pop the
dialog.
"""
if projFile is None:
projFile = self.openProjectDialog()
if projFile is None:
return False
# Make sure any open project is cleared out first before we load another one
# Make sure any open project is cleared out first before we load
# another one
if not self.closeProject():
return False
@@ -629,8 +632,9 @@ class GuiMain(QMainWindow):
return True
def makeAlert(self, theMessage, theLevel=nwAlert.INFO):
"""Alert both the user and the logger at the same time. Message can be either a string or an
array of strings. Severity level is 0 = info, 1 = warning, and 2 = error.
"""Alert both the user and the logger at the same time. Message
can be either a string or an array of strings. Severity level is
0 = info, 1 = warning, and 2 = error.
"""
if isinstance(theMessage, list):
@@ -724,7 +728,8 @@ class GuiMain(QMainWindow):
return True
def _autoSaveProject(self):
if self.hasProject and self.theProject.projChanged and self.theProject.projPath is not None:
if (self.hasProject and self.theProject.projChanged and
self.theProject.projPath is not None):
logger.debug("Autosaving project")
self.saveProject(isAuto=True)
return
@@ -756,8 +761,8 @@ class GuiMain(QMainWindow):
##
def resizeEvent(self, theEvent):
"""Extend QMainWindow.resizeEvent to signal dependent GUI elements that its pane may have
changed size.
"""Extend QMainWindow.resizeEvent to signal dependent GUI
elements that its pane may have changed size.
"""
QMainWindow.resizeEvent(self,theEvent)
self.docEditor.changeWidth()
@@ -803,7 +808,8 @@ class GuiMain(QMainWindow):
return
def _keyPressEscape(self):
"""When the escape key is pressed somewhere in the main window, do the following, in order.
"""When the escape key is pressed somewhere in the main window,
do the following, in order.
"""
if self.searchBar.isVisible():
self.searchBar.setVisible(False)
@@ -811,13 +817,15 @@ class GuiMain(QMainWindow):
return
def _splitMainMove(self, pWidth, pHeight):
"""Alert dependent GUI elements that the main pane splitter has been moved.
"""Alert dependent GUI elements that the main pane splitter has
been moved.
"""
self.docEditor.changeWidth()
return
def _splitViewMove(self, pWidth, pHeight):
"""Alert dependent GUI elements that the main pane splitter has been moved.
"""Alert dependent GUI elements that the main pane splitter has
been moved.
"""
self.docEditor.changeWidth()
return
+7 -5
View File
@@ -53,7 +53,8 @@ class NWDoc():
self.clearDocument()
return None
# By default, the document is editable. Except for files in the trash folder.
# By default, the document is editable.
# Except for files in the trash folder.
self.docEditable = True
if self.theItem.parHandle == self.theProject.trashRoot:
self.docEditable = False
@@ -70,13 +71,14 @@ class NWDoc():
theDoc = inFile.read()
except Exception as e:
self.makeAlert(["Failed to open document file.",str(e)], nwAlert.ERROR)
# Note: Document must be cleared in case of an io error, or else the auto-save or
# save will try to overwrite it with an empty file. Return None to alert the caller.
# Note: Document must be cleared in case of an io error,
# or else the auto-save or save will try to overwrite it
# with an empty file. Return None to alert the caller.
self.clearDocument()
return None
else:
# The document file does not exist, so we assume it's a new document and initialise an
# empty text string.
# The document file does not exist, so we assume it's a new
# document and initialise an empty text string.
logger.debug("The requested document does not exist.")
return ""
+23 -14
View File
@@ -130,7 +130,8 @@ class NWIndex():
return False
def saveIndex(self):
"""Save the current index as a json file in the project meta folder.
"""Save the current index as a json file in the project meta
folder.
"""
indexFile = path.join(self.theProject.projMeta, nwFiles.INDEX_FILE)
@@ -155,7 +156,8 @@ class NWIndex():
return True
def checkIndex(self):
"""Check that the entries in the index are valid and contain the elements it should.
"""Check that the entries in the index are valid and contain the
elements it should.
"""
self.indexBroken = False
@@ -193,8 +195,9 @@ class NWIndex():
##
def scanText(self, tHandle, theText):
"""Scan a piece of text associated with a handle. This will update the indices accordingly.
This function takes the handle and text as separate inputs as we want to primarily scan the
"""Scan a piece of text associated with a handle. This will
update the indices accordingly. This function takes the handle
and text as separate inputs as we want to primarily scan the
files before we save them, unless we're rebuilding the index.
"""
@@ -243,7 +246,8 @@ class NWIndex():
return True
def indexTitle(self, tHandle, isNovel, aLine, nLine, itemLayout):
"""Save information about the title and its location in the file.
"""Save information about the title and its location in the
file.
"""
if aLine.startswith("# "):
@@ -272,7 +276,8 @@ class NWIndex():
return True
def indexNoteRef(self, tHandle, aLine, nLine, nTitle):
"""Validate and save the information about a reference to a tag in another file.
"""Validate and save the information about a reference to a tag
in another file.
"""
isValid, theBits, thePos = self.scanThis(aLine)
@@ -303,8 +308,9 @@ class NWIndex():
##
def scanThis(self, aLine):
"""Scan a line starting with @ to check that it's valid and to split up its elements into
an array and an array of positions. The latter is needed for the syntax highlighter.
"""Scan a line starting with @ to check that it's valid and to
split up its elements into an array and an array of positions.
The latter is needed for the syntax highlighter.
"""
theBits = []
@@ -343,8 +349,8 @@ class NWIndex():
return True, theBits, thePos
def checkThese(self, theBits, tItem):
"""Check the tags against the index to see if they are valid tags. This is needed for syntax
highlighting.
"""Check the tags against the index to see if they are valid
tags. This is needed for syntax highlighting.
"""
nBits = len(theBits)
@@ -357,7 +363,8 @@ class NWIndex():
if not isGood[0] or nBits == 1:
return isGood
# If we have a tag, only the first value is accepted, the rest is ignored
# If we have a tag, only the first value is accepted, the rest
# is ignored
if theBits[0] == nwKeyWords.TAG_KEY and nBits > 1:
isGood[0] = True
if theBits[1] in self.tagIndex.keys():
@@ -396,7 +403,8 @@ class NWIndex():
return True
def buildReferenceList(self, tHandle):
"""Build a list of files referring back to our file, specified by tHandle.
"""Build a list of files referring back to our file, specified
by tHandle.
"""
theRefs = {}
@@ -429,8 +437,9 @@ class NWIndex():
return None, 0
def buildTagNovelMap(self, theTags, theFilters=None):
"""Build a two-dimensional map of all titles of the novel and which tags they link to from
the various meta tags. This map is used to display the timeline view.
"""Build a two-dimensional map of all titles of the novel and
which tags they link to from the various meta tags. This map is
used to display the timeline view.
"""
tagMap = {}
+22 -11
View File
@@ -85,17 +85,28 @@ class NWItem():
def setFromTag(self, tagName, tagValue):
logger.verbose("Setting tag '%s' to value '%s'" % (tagName, str(tagValue)))
if tagName == "name": self.setName(tagValue)
elif tagName == "order": self.setOrder(tagValue)
elif tagName == "type": self.setType(tagValue)
elif tagName == "class": self.setClass(tagValue)
elif tagName == "layout": self.setLayout(tagValue)
elif tagName == "status": self.setStatus(tagValue)
elif tagName == "expanded": self.setExpanded(tagValue)
elif tagName == "charCount": self.setCharCount(tagValue)
elif tagName == "wordCount": self.setWordCount(tagValue)
elif tagName == "paraCount": self.setParaCount(tagValue)
elif tagName == "cursorPos": self.setCursorPos(tagValue)
if tagName == "name":
self.setName(tagValue)
elif tagName == "order":
self.setOrder(tagValue)
elif tagName == "type":
self.setType(tagValue)
elif tagName == "class":
self.setClass(tagValue)
elif tagName == "layout":
self.setLayout(tagValue)
elif tagName == "status":
self.setStatus(tagValue)
elif tagName == "expanded":
self.setExpanded(tagValue)
elif tagName == "charCount":
self.setCharCount(tagValue)
elif tagName == "wordCount":
self.setWordCount(tagValue)
elif tagName == "paraCount":
self.setParaCount(tagValue)
elif tagName == "cursorPos":
self.setCursorPos(tagValue)
else:
logger.error("Unknown tag '%s'" % tagName)
return
+29 -18
View File
@@ -37,7 +37,7 @@ class NWProject():
self.mainConf = self.theParent.mainConf
self.projOpened = None # The time stamp of when the project file was opened
self.projChanged = None # The project has unsaved changes
self.projAltered = None # The project has been altered this session (used to trigger backup)
self.projAltered = None # The project has been altered this session
# Debug
self.handleSeed = None
@@ -224,7 +224,8 @@ class NWProject():
if xChild.tag == "project":
logger.debug("Found project meta")
for xItem in xChild:
if xItem.text is None: continue
if xItem.text is None:
continue
if xItem.tag == "name":
logger.verbose("Working Title: '%s'" % xItem.text)
self.projName = xItem.text
@@ -239,7 +240,8 @@ class NWProject():
elif xChild.tag == "settings":
logger.debug("Found project settings")
for xItem in xChild:
if xItem.text is None: continue
if xItem.text is None:
continue
if xItem.tag == "spellCheck":
self.spellCheck = checkBool(xItem.text,False)
elif xItem.tag == "lastEdited":
@@ -493,8 +495,9 @@ class NWProject():
return None
def getRootItem(self, tHandle):
"""Iterate upwards in the tree until we find the item with parent None, the root item.
We do this with a for loop with a maximum depth of 200 to make infinite loops impossible.
"""Iterate upwards in the tree until we find the item with
parent None, the root item. We do this with a for loop with a
maximum depth of 200 to make infinite loops impossible.
"""
tItem = self.getItem(tHandle)
if tItem is not None:
@@ -506,9 +509,10 @@ class NWProject():
return None
def getProjectItems(self):
"""This function is called from the tree view when building the tree. Each item in the
project is returned in the order saved in the project file, but first it checks that it has
a parent item already sent to the tree.
"""This function is called from the tree view when building the
tree. Each item in the project is returned in the order saved in
the project file, but first it checks that it has a parent item
already sent to the tree.
"""
sentItems = []
iterItems = self.treeOrder.copy()
@@ -521,10 +525,12 @@ class NWProject():
if n > 10000:
return # Just in case
if tItem is None:
# Technically a bug since treeOrder is built from the same data as projTree
# Technically a bug since treeOrder is built from the
# same data as projTree
continue
elif tItem.parHandle is None:
# Item is a root, or already been identified as an orphaned item
# Item is a root, or already been identified as an
# orphaned item
sentItems.append(tHandle)
yield tItem
elif tItem.parHandle in sentItems:
@@ -532,7 +538,8 @@ class NWProject():
sentItems.append(tHandle)
yield tItem
elif tItem.parHandle in iterItems:
# Item's parent exists, but hasn't been sent yet, so add it again to the end
# Item's parent exists, but hasn't been sent yet, so add
# it again to the end
logger.warning("Item %s found before its parent" % tHandle)
iterItems.append(tHandle)
nMax = len(iterItems)
@@ -547,7 +554,8 @@ class NWProject():
##
def deleteItem(self, tHandle):
"""This only removes the item from the order list, but not from the project tree.
"""This only removes the item from the order list, but not from
the project tree.
"""
self.treeOrder.remove(tHandle)
self.setProjectChanged(True)
@@ -560,8 +568,8 @@ class NWProject():
return None
def checkRootUnique(self, theClass):
"""Checks if there already is a root entry of class 'theClass' in the
root of the project tree.
"""Checks if there already is a root entry of class 'theClass'
in the root of the project tree.
"""
if theClass == nwItemClass.CUSTOM:
return True
@@ -689,7 +697,9 @@ class NWProject():
if self.projMeta is None:
return False
with open(path.join(self.projMeta, nwFiles.SESS_INFO),mode="a+",encoding="utf8") as outFile:
sessionFile = path.join(self.projMeta, nwFiles.SESS_INFO)
with open(sessionFile,mode="a+",encoding="utf8") as outFile:
print((
"Start: {opened:s} "
"End: {closed:s} "
@@ -717,9 +727,10 @@ class NWProject():
return itemHandle
def _maintainPrevious(self):
"""This function will take the current project file and copy it into the project cache
folder with an incremental file extension added. These serve as a backup in case the xml
file gets corrupted.
"""This function will take the current project file and copy it
into the project cache folder with an incremental file extension
added. These serve as a backup in case the xml file gets
corrupted.
"""
countFile = path.join(self.projCache, nwFiles.PROJ_COUNT)
+1 -1
View File
@@ -13,7 +13,7 @@
import logging
import nw
from lxml import etree
from lxml import etree
from nw.enum import nwItemClass
from nw.common import checkInt
+12 -9
View File
@@ -58,7 +58,7 @@ class TextAnalysis():
return rScore, gLevel
def getReadabilityText(self, rScore):
if rScore >= 90.0:
if rScore >= 90.0:
return "Very Easy"
elif rScore >= 80.0:
return "Easy"
@@ -78,13 +78,15 @@ class TextAnalysis():
#
def _countWords(self):
"""Counts the number of words in a text by simply splitting on all white spaces.
"""Counts the number of words in a text by simply splitting on
all white spaces.
"""
return len(self.theText.strip().split())
def _countSentences(self):
"""Counts the number of non-repeated sentence endings seen in the text.
Note: This will count filenames and urls as multiple sentences.
"""Counts the number of non-repeated sentence endings seen in
the text. Note: This will count filenames and urls as multiple
sentences.
"""
nSent = 0
sawEnd = False
@@ -98,7 +100,8 @@ class TextAnalysis():
return nSent
def _countParagraphs(self, pThreshold=2):
"""Counts the number of paragraphs by counting repeated line breaks.
"""Counts the number of paragraphs by counting repeated line
breaks.
"""
nPara = 1
sawEnd = 0
@@ -114,9 +117,10 @@ class TextAnalysis():
return nPara
def _countSyllablesEN(self):
"""Attempt to count the syllables in a piece of English language text.
This function tends to slightly over-estimate the number of syllables as it doesn't handle
the complexity of silent vowels in endings very well. It will count them all.
"""Attempt to count the syllables in a piece of English language
text. This function tends to slightly over-estimate the number
of syllables as it doesn't handle the complexity of silent
vowels in endings very well. It will count them all.
"""
cleanText = ""
@@ -160,7 +164,6 @@ class TextAnalysis():
nSyll += 1
if nSyll < 1:
nSyll = 1
# print("%-15s: %d" % (inWord,nSyll))
allSylls += nSyll
return allSylls/len(theWords)
+3 -2
View File
@@ -32,8 +32,9 @@ class NWSpellEnchant(NWSpellCheck):
return
def setLanguage(self, theLang, projectDict=None):
"""Load a dictionary for the language specified in the config. If that fails, we load a
dummy dictionary so that lookups don't crash.
"""Load a dictionary for the language specified in the config.
If that fails, we load a dummy dictionary so that lookups don't
crash.
"""
try:
if projectDict is None: