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