From 55b0e1d81769d92907e46b266e03acd89cc5a706 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 3 Nov 2019 15:06:51 +0100 Subject: [PATCH 1/8] The two executables generated for pip should be novelWriter-cli and novelWriter --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 5929fe21..2f7b7e6c 100755 --- a/setup.py +++ b/setup.py @@ -15,8 +15,8 @@ setuptools.setup( license = "GNU General Public License v3", url = "https://github.com/vkbo/novelWriter", entry_points = { - "console_scripts" : ["novelWriter=nw:main"], - "gui_scripts" : ["novelWriter-gui=nw:main"], + "console_scripts" : ["novelWriter-cli=nw:main"], + "gui_scripts" : ["novelWriter=nw:main"], }, packages = setuptools.find_packages(exclude=["docs","tests","sample"]), include_package_data = True, From 5e79ec40f2465b863e205d2fb7896cfb139fcd86 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 3 Nov 2019 15:09:29 +0100 Subject: [PATCH 2/8] Remove milliseconds from debug verbose logging --- nw/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nw/__init__.py b/nw/__init__.py index e7889366..96aeadf8 100644 --- a/nw/__init__.py +++ b/nw/__init__.py @@ -102,7 +102,7 @@ def main(sysArgs=None): " --verbose Increase verbosity of debug output.\n" " -D, --debuggui Shows additional debug GUI elements. Includes -d.\n" " -q, --quiet Disable output to command line. Does not affect log file.\n" - " -t, --time Shows time stamp in logging output. Adds milliseconds when --verbose.\n" + " -t, --time Shows time stamp in logging output.\n" " -l, --logfile= Specify log file.\n" " --style= Set Qt5 style flag. Defaults to Fusion.\n" " --config= Alternative config file.\n" @@ -152,7 +152,6 @@ def main(sysArgs=None): toStd = False elif inOpt in ("--verbose"): debugLevel = VERBOSE - timeStr = "[{asctime:}.{msecs:03.0f}] " elif inOpt in ("-t","--time"): showTime = True elif inOpt in ("--style"): @@ -165,7 +164,7 @@ def main(sysArgs=None): spellTool = inArg elif inOpt in ("-D","--debuggui"): debugLevel = logging.DEBUG - debugStr = "{name:>20}:{lineno:<4d} {levelname:8} {message:}" + debugStr = "{name:>30}:{lineno:<4d} {levelname:8} {message:}" debugGUI = True # Set Config Options From f6bc1f32e5cc5049c67245031b509817e0661bcb Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 3 Nov 2019 15:14:34 +0100 Subject: [PATCH 3/8] Also remove the debuggui feature, as the functionality os handled otherwise if still needed --- nw/__init__.py | 8 -------- nw/config.py | 1 - nw/gui/elements/docdetails.py | 1 - nw/gui/elements/doctree.py | 4 +--- nw/gui/elements/viewdetails.py | 1 - nw/gui/statusbar.py | 13 ------------- nw/project/document.py | 1 - 7 files changed, 1 insertion(+), 28 deletions(-) diff --git a/nw/__init__.py b/nw/__init__.py index 96aeadf8..6be830af 100644 --- a/nw/__init__.py +++ b/nw/__init__.py @@ -80,7 +80,6 @@ def main(sysArgs=None): "help", "debug", "verbose", - "debuggui", "quiet", "time", "logfile=", @@ -100,7 +99,6 @@ def main(sysArgs=None): " -v, --version Print program version and exit.\n" " -d, --debug Print debug output.\n" " --verbose Increase verbosity of debug output.\n" - " -D, --debuggui Shows additional debug GUI elements. Includes -d.\n" " -q, --quiet Disable output to command line. Does not affect log file.\n" " -t, --time Shows time stamp in logging output.\n" " -l, --logfile= Specify log file.\n" @@ -124,7 +122,6 @@ def main(sysArgs=None): showTime = False confPath = None testMode = False - debugGUI = False spellTool = None qtStyle = "Fusion" @@ -162,14 +159,9 @@ def main(sysArgs=None): testMode = True elif inOpt in ("--spell"): spellTool = inArg - elif inOpt in ("-D","--debuggui"): - debugLevel = logging.DEBUG - debugStr = "{name:>30}:{lineno:<4d} {levelname:8} {message:}" - debugGUI = True # Set Config Options CONFIG.showGUI = not testMode - CONFIG.debugGUI = debugGUI CONFIG.debugInfo = debugLevel < logging.INFO CONFIG.spellTool = spellTool diff --git a/nw/config.py b/nw/config.py index 2e0baacb..30d65cdf 100644 --- a/nw/config.py +++ b/nw/config.py @@ -40,7 +40,6 @@ class Config: self.appName = nw.__package__ self.appHandle = nw.__package__.lower() self.showGUI = True - self.debugGUI = False self.debugInfo = False self.spellTool = None diff --git a/nw/gui/elements/docdetails.py b/nw/gui/elements/docdetails.py index 888e295e..a38f9ac6 100644 --- a/nw/gui/elements/docdetails.py +++ b/nw/gui/elements/docdetails.py @@ -32,7 +32,6 @@ class GuiDocDetails(QFrame): logger.debug("Initialising DocDetails ...") self.mainConf = nw.CONFIG - self.debugGUI = self.mainConf.debugGUI self.theParent = theParent self.theProject = theProject diff --git a/nw/gui/elements/doctree.py b/nw/gui/elements/doctree.py index bc53ab59..9b4bc750 100644 --- a/nw/gui/elements/doctree.py +++ b/nw/gui/elements/doctree.py @@ -35,7 +35,6 @@ class GuiDocTree(QTreeWidget): logger.debug("Initialising DocTree ...") self.mainConf = nw.CONFIG - self.debugGUI = self.mainConf.debugGUI self.theParent = theParent self.theTheme = theParent.theTheme self.theProject = theProject @@ -52,8 +51,7 @@ class GuiDocTree(QTreeWidget): self.setIndentation(13) self.setColumnCount(4) self.setHeaderLabels(["Label","Words","Flags","Handle"]) - if not self.debugGUI: - self.hideColumn(self.C_HANDLE) + self.hideColumn(self.C_HANDLE) treeHead = self.headerItem() treeHead.setTextAlignment(self.C_COUNT,Qt.AlignRight) diff --git a/nw/gui/elements/viewdetails.py b/nw/gui/elements/viewdetails.py index d283cd20..5880d008 100644 --- a/nw/gui/elements/viewdetails.py +++ b/nw/gui/elements/viewdetails.py @@ -31,7 +31,6 @@ class GuiDocViewDetails(QWidget): logger.debug("Initialising DocViewDetails ...") self.mainConf = nw.CONFIG - self.debugGUI = self.mainConf.debugGUI self.theParent = theParent self.theProject = theProject self.currHandle = None diff --git a/nw/gui/statusbar.py b/nw/gui/statusbar.py index cbd02b70..00170b8c 100644 --- a/nw/gui/statusbar.py +++ b/nw/gui/statusbar.py @@ -60,9 +60,6 @@ class GuiMainStatus(QStatusBar): self.docChanged.setFixedWidth(16) self.docChanged.setToolTip("Document Changes Saved") - self.boxDocHandle = QLabel() - self.boxDocHandle.setFrameStyle(QFrame.Panel | QFrame.Sunken); - # Add Them self.addPermanentWidget(self.docChanged) self.addPermanentWidget(self.boxCounts) @@ -70,8 +67,6 @@ class GuiMainStatus(QStatusBar): self.addPermanentWidget(self.projChanged) self.addPermanentWidget(self.boxStats) self.addPermanentWidget(self.boxTime) - if self.mainConf.debugGUI: - self.addPermanentWidget(self.boxDocHandle) self.setSizeGripEnabled(True) @@ -90,7 +85,6 @@ class GuiMainStatus(QStatusBar): self.setRefTime(None) self.setStats(0,0) self.setCounts(0,0,0) - self.setDocHandle(None) self.setProjectStatus(None) self.setDocumentStatus(None) self._updateTime() @@ -134,13 +128,6 @@ class GuiMainStatus(QStatusBar): self.boxCounts.setText("Document: {:d} : {:d} : {:d}".format(cC,wC,pC)) return - def setDocHandle(self, theHandle): - if theHandle is None: - self.boxDocHandle.setText("0000000000000") - else: - self.boxDocHandle.setText("%13s" % theHandle) - return - ## # Internal Functions ## diff --git a/nw/project/document.py b/nw/project/document.py index ad531fb3..e54a72f0 100644 --- a/nw/project/document.py +++ b/nw/project/document.py @@ -82,7 +82,6 @@ class NWDoc(): if showStatus: self.theParent.statusBar.setStatus("Opened Document: %s" % self.theItem.itemName) - self.theParent.statusBar.setDocHandle(tHandle) return theDoc From 33e3b67ba575cdf3a81aefcc5ac02e4efd613991 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 3 Nov 2019 15:36:34 +0100 Subject: [PATCH 4/8] Make sure all code lines are within a 100 characters --- nw/config.py | 136 ++++++++++++++++++++++++-------- nw/convert/text/tomarkdown.py | 4 +- nw/convert/tokenizer.py | 3 +- nw/gui/dialogs/configeditor.py | 4 +- nw/gui/dialogs/export.py | 4 +- nw/gui/dialogs/itemeditor.py | 14 ++-- nw/gui/dialogs/projecteditor.py | 4 +- nw/gui/dialogs/sessionlog.py | 8 +- nw/gui/dialogs/timelineview.py | 25 +++--- nw/gui/elements/doceditor.py | 25 +++++- nw/gui/elements/doctree.py | 14 ++-- nw/gui/elements/docviewer.py | 36 ++++----- nw/gui/elements/searchbar.py | 2 +- nw/gui/mainmenu.py | 4 +- nw/gui/winmain.py | 56 +++++++++---- nw/project/backup.py | 13 ++- nw/project/project.py | 26 +++--- 17 files changed, 263 insertions(+), 115 deletions(-) diff --git a/nw/config.py b/nw/config.py index 30d65cdf..a47e7c24 100644 --- a/nw/config.py +++ b/nw/config.py @@ -200,65 +200,133 @@ class Config: logger.debug("Loading config file") cnfParse = configparser.ConfigParser() try: - cnfParse.read_file(open(path.join(self.confPath,self.confFile),mode="r",encoding="utf8")) + cnfParse.read_file( + open(path.join(self.confPath,self.confFile),mode="r",encoding="utf8") + ) except Exception as e: logger.error("Could not load config file") return False ## Main cnfSec = "Main" - self.guiTheme = self._parseLine(cnfParse, cnfSec, "theme", self.CNF_STR, self.guiTheme) - self.guiSyntax = self._parseLine(cnfParse, cnfSec, "syntax", self.CNF_STR, self.guiSyntax) + self.guiTheme = self._parseLine( + cnfParse, cnfSec, "theme", self.CNF_STR, self.guiTheme + ) + self.guiSyntax = self._parseLine( + cnfParse, cnfSec, "syntax", self.CNF_STR, self.guiSyntax + ) ## Sizes cnfSec = "Sizes" - self.winGeometry = self._parseLine(cnfParse, cnfSec, "geometry", self.CNF_LIST, self.winGeometry) - self.treeColWidth = self._parseLine(cnfParse, cnfSec, "treecols", self.CNF_LIST, self.treeColWidth) - self.mainPanePos = self._parseLine(cnfParse, cnfSec, "mainpane", self.CNF_LIST, self.mainPanePos) - self.docPanePos = self._parseLine(cnfParse, cnfSec, "docpane", self.CNF_LIST, self.docPanePos) + self.winGeometry = self._parseLine( + cnfParse, cnfSec, "geometry", self.CNF_LIST, self.winGeometry + ) + self.treeColWidth = self._parseLine( + cnfParse, cnfSec, "treecols", self.CNF_LIST, self.treeColWidth + ) + self.mainPanePos = self._parseLine( + cnfParse, cnfSec, "mainpane", self.CNF_LIST, self.mainPanePos + ) + self.docPanePos = self._parseLine( + cnfParse, cnfSec, "docpane", self.CNF_LIST, self.docPanePos + ) ## Project cnfSec = "Project" - self.autoSaveProj = self._parseLine(cnfParse, cnfSec, "autosaveproject", self.CNF_INT, self.autoSaveProj) - self.autoSaveDoc = self._parseLine(cnfParse, cnfSec, "autosavedoc", self.CNF_INT, self.autoSaveDoc) + self.autoSaveProj = self._parseLine( + cnfParse, cnfSec, "autosaveproject", self.CNF_INT, self.autoSaveProj + ) + self.autoSaveDoc = self._parseLine( + cnfParse, cnfSec, "autosavedoc", self.CNF_INT, self.autoSaveDoc + ) ## Editor cnfSec = "Editor" - self.textFont = self._parseLine(cnfParse, cnfSec, "textfont", self.CNF_STR, self.textFont) - self.textSize = self._parseLine(cnfParse, cnfSec, "textsize", self.CNF_INT, self.textSize) - self.textFixedW = self._parseLine(cnfParse, cnfSec, "fixedwidth", self.CNF_BOOL, self.textFixedW) - self.textWidth = self._parseLine(cnfParse, cnfSec, "width", self.CNF_INT, self.textWidth) - self.textMargin = self._parseLine(cnfParse, cnfSec, "margin", self.CNF_INT, self.textMargin) - self.tabWidth = self._parseLine(cnfParse, cnfSec, "tabwidth", self.CNF_INT, self.tabWidth) - self.doJustify = self._parseLine(cnfParse, cnfSec, "justify", self.CNF_BOOL, self.doJustify) - self.autoSelect = self._parseLine(cnfParse, cnfSec, "autoselect", self.CNF_BOOL, self.autoSelect) - self.doReplace = self._parseLine(cnfParse, cnfSec, "autoreplace", self.CNF_BOOL, self.doReplace) - self.doReplaceSQuote = self._parseLine(cnfParse, cnfSec, "repsquotes", self.CNF_BOOL, self.doReplaceSQuote) - self.doReplaceDQuote = self._parseLine(cnfParse, cnfSec, "repdquotes", self.CNF_BOOL, self.doReplaceDQuote) - self.doReplaceDash = self._parseLine(cnfParse, cnfSec, "repdash", self.CNF_BOOL, self.doReplaceDash) - self.doReplaceDots = self._parseLine(cnfParse, cnfSec, "repdots", self.CNF_BOOL, self.doReplaceDots) - self.fmtSingleQuotes = self._parseLine(cnfParse, cnfSec, "fmtsinglequote", self.CNF_LIST, self.fmtSingleQuotes) - self.fmtDoubleQuotes = self._parseLine(cnfParse, cnfSec, "fmtdoublequote", self.CNF_LIST, self.fmtDoubleQuotes) - self.spellLanguage = self._parseLine(cnfParse, cnfSec, "spellcheck", self.CNF_STR, self.spellLanguage) - self.showTabsNSpaces = self._parseLine(cnfParse, cnfSec, "showtabsnspaces", self.CNF_BOOL, self.showTabsNSpaces) - self.showLineEndings = self._parseLine(cnfParse, cnfSec, "showlineendings", self.CNF_BOOL, self.showLineEndings) + self.textFont = self._parseLine( + cnfParse, cnfSec, "textfont", self.CNF_STR, self.textFont + ) + self.textSize = self._parseLine( + cnfParse, cnfSec, "textsize", self.CNF_INT, self.textSize + ) + self.textFixedW = self._parseLine( + cnfParse, cnfSec, "fixedwidth", self.CNF_BOOL, self.textFixedW + ) + self.textWidth = self._parseLine( + cnfParse, cnfSec, "width", self.CNF_INT, self.textWidth + ) + self.textMargin = self._parseLine( + cnfParse, cnfSec, "margin", self.CNF_INT, self.textMargin + ) + self.tabWidth = self._parseLine( + cnfParse, cnfSec, "tabwidth", self.CNF_INT, self.tabWidth + ) + self.doJustify = self._parseLine( + cnfParse, cnfSec, "justify", self.CNF_BOOL, self.doJustify + ) + self.autoSelect = self._parseLine( + cnfParse, cnfSec, "autoselect", self.CNF_BOOL, self.autoSelect + ) + self.doReplace = self._parseLine( + cnfParse, cnfSec, "autoreplace", self.CNF_BOOL, self.doReplace + ) + self.doReplaceSQuote = self._parseLine( + cnfParse, cnfSec, "repsquotes", self.CNF_BOOL, self.doReplaceSQuote + ) + self.doReplaceDQuote = self._parseLine( + cnfParse, cnfSec, "repdquotes", self.CNF_BOOL, self.doReplaceDQuote + ) + self.doReplaceDash = self._parseLine( + cnfParse, cnfSec, "repdash", self.CNF_BOOL, self.doReplaceDash + ) + self.doReplaceDots = self._parseLine( + cnfParse, cnfSec, "repdots", self.CNF_BOOL, self.doReplaceDots + ) + self.fmtSingleQuotes = self._parseLine( + cnfParse, cnfSec, "fmtsinglequote", self.CNF_LIST, self.fmtSingleQuotes + ) + self.fmtDoubleQuotes = self._parseLine( + cnfParse, cnfSec, "fmtdoublequote", self.CNF_LIST, self.fmtDoubleQuotes + ) + self.spellLanguage = self._parseLine( + cnfParse, cnfSec, "spellcheck", self.CNF_STR, self.spellLanguage + ) + self.showTabsNSpaces = self._parseLine( + cnfParse, cnfSec, "showtabsnspaces", self.CNF_BOOL, self.showTabsNSpaces + ) + self.showLineEndings = self._parseLine( + cnfParse, cnfSec, "showlineendings", self.CNF_BOOL, self.showLineEndings + ) ## Backup cnfSec = "Backup" - self.backupPath = self._parseLine(cnfParse, cnfSec, "backuppath", self.CNF_STR, self.backupPath) - self.backupOnClose = self._parseLine(cnfParse, cnfSec, "backuponclose", self.CNF_BOOL, self.backupOnClose) - self.askBeforeBackup = self._parseLine(cnfParse, cnfSec, "askbeforebackup", self.CNF_BOOL, self.askBeforeBackup) + self.backupPath = self._parseLine( + cnfParse, cnfSec, "backuppath", self.CNF_STR, self.backupPath + ) + self.backupOnClose = self._parseLine( + cnfParse, cnfSec, "backuponclose", self.CNF_BOOL, self.backupOnClose + ) + self.askBeforeBackup = self._parseLine( + cnfParse, cnfSec, "askbeforebackup", self.CNF_BOOL, self.askBeforeBackup + ) ## State cnfSec = "State" - self.showRefPanel = self._parseLine(cnfParse, cnfSec, "showrefpanel", self.CNF_BOOL, self.showRefPanel) - self.viewComments = self._parseLine(cnfParse, cnfSec, "viewcomments", self.CNF_BOOL, self.viewComments) + self.showRefPanel = self._parseLine( + cnfParse, cnfSec, "showrefpanel", self.CNF_BOOL, self.showRefPanel + ) + self.viewComments = self._parseLine( + cnfParse, cnfSec, "viewcomments", self.CNF_BOOL, self.viewComments + ) ## Path cnfSec = "Path" - self.lastPath = self._parseLine(cnfParse, cnfSec, "lastpath", self.CNF_STR, self.lastPath) + self.lastPath = self._parseLine( + cnfParse, cnfSec, "lastpath", self.CNF_STR, self.lastPath + ) for i in range(10): - self.recentList[i] = self._parseLine(cnfParse, cnfSec, "recent%d" % i,self.CNF_STR, self.recentList[i]) + self.recentList[i] = self._parseLine( + cnfParse, cnfSec, "recent%d" % i,self.CNF_STR, self.recentList[i] + ) # Check Certain Values for None self.spellLanguage = self._checkNone(self.spellLanguage) diff --git a/nw/convert/text/tomarkdown.py b/nw/convert/text/tomarkdown.py index bd422836..78098c5e 100644 --- a/nw/convert/text/tomarkdown.py +++ b/nw/convert/text/tomarkdown.py @@ -71,7 +71,9 @@ class ToMarkdown(Tokenizer): # 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(tText.strip(),initial_indent=" ",subsequent_indent=" ") + tText = textwrap.fill( + tText.strip(),initial_indent=" ",subsequent_indent=" " + ) else: tText = tWrap.fill(tText) diff --git a/nw/convert/tokenizer.py b/nw/convert/tokenizer.py index 55452915..acc90b91 100644 --- a/nw/convert/tokenizer.py +++ b/nw/convert/tokenizer.py @@ -203,7 +203,8 @@ class Tokenizer(): xLen = rxMatch.capturedLength(n) fmtPos.append([xPos,xLen,theKeys[n]]) - # Save the line as is, but append the array of formatting locations sorted by position + # Save the line as is, but append the array of formatting locations + # sorted by position fmtPos = sorted(fmtPos,key=itemgetter(0)) self.theTokens.append((self.T_TEXT,aLine,fmtPos,self.A_LEFT)) diff --git a/nw/gui/dialogs/configeditor.py b/nw/gui/dialogs/configeditor.py index a77dcfc8..fd90ec9a 100644 --- a/nw/gui/dialogs/configeditor.py +++ b/nw/gui/dialogs/configeditor.py @@ -407,7 +407,9 @@ class GuiConfigEditEditor(QWidget): self.autoReplaceDQ.setCheckState(Qt.Unchecked) self.autoReplaceDash = QCheckBox(self) - self.autoReplaceDash.setToolTip("Auto-replace double and triple hyphens with short and long dash.") + self.autoReplaceDash.setToolTip( + "Auto-replace double and triple hyphens with short and long dash." + ) if self.mainConf.doReplaceDash: self.autoReplaceDash.setCheckState(Qt.Checked) else: diff --git a/nw/gui/dialogs/export.py b/nw/gui/dialogs/export.py index d9f3b7e9..d3be1260 100644 --- a/nw/gui/dialogs/export.py +++ b/nw/gui/dialogs/export.py @@ -510,7 +510,9 @@ class GuiExportMain(QWidget): self.fixedWidth.setMaximum(999) self.fixedWidth.setSingleStep(1) self.fixedWidth.setValue(self.optState.getSetting("fixWidth")) - self.fixedWidth.setToolTip("Applies to .txt and .md files. A value of '0' disables the feature.") + self.fixedWidth.setToolTip( + "Applies to .txt and .md files. A value of '0' disables the feature." + ) self.addSettingsForm.addWidget(QLabel("Fixed width"), 0, 0) self.addSettingsForm.addWidget(self.fixedWidth, 0, 1) diff --git a/nw/gui/dialogs/itemeditor.py b/nw/gui/dialogs/itemeditor.py index d5ae459d..a5bc5fe1 100644 --- a/nw/gui/dialogs/itemeditor.py +++ b/nw/gui/dialogs/itemeditor.py @@ -13,14 +13,16 @@ import logging import nw -from os import path +from os import path from PyQt5.QtCore import Qt, QSize -from PyQt5.QtWidgets import QDialog, QHBoxLayout, QVBoxLayout, QGroupBox, QFormLayout, QLineEdit, QPushButton, QComboBox from PyQt5.QtSvg import QSvgWidget +from PyQt5.QtWidgets import ( + QDialog, QHBoxLayout, QVBoxLayout, QGroupBox, QFormLayout, QLineEdit, QPushButton, QComboBox +) -from nw.enum import nwItemLayout, nwItemClass, nwItemType -from nw.constants import nwLabels +from nw.enum import nwItemLayout, nwItemClass, nwItemType +from nw.constants import nwLabels logger = logging.getLogger(__name__) @@ -36,8 +38,8 @@ class GuiItemEditor(QDialog): self.theParent = theParent self.theItem = self.theProject.getItem(tHandle) - self.outerBox = QHBoxLayout() - self.innerBox = QVBoxLayout() + self.outerBox = QHBoxLayout() + self.innerBox = QVBoxLayout() self.setWindowTitle("Item Settings") diff --git a/nw/gui/dialogs/projecteditor.py b/nw/gui/dialogs/projecteditor.py index bd42cdb5..4909d835 100644 --- a/nw/gui/dialogs/projecteditor.py +++ b/nw/gui/dialogs/projecteditor.py @@ -221,7 +221,9 @@ class GuiProjectEditStatus(QWidget): def _selectColour(self): logger.verbose("Item colour button clicked") if self.selColour is not None: - newCol = QColorDialog.getColor(self.selColour, self, "Select Colour", QColorDialog.DontUseNativeDialog) + newCol = QColorDialog.getColor( + self.selColour, self, "Select Colour", QColorDialog.DontUseNativeDialog + ) if newCol: self.selColour = newCol colPixmap = QPixmap(16,16) diff --git a/nw/gui/dialogs/sessionlog.py b/nw/gui/dialogs/sessionlog.py index 3c400acf..be2a1f94 100644 --- a/nw/gui/dialogs/sessionlog.py +++ b/nw/gui/dialogs/sessionlog.py @@ -70,8 +70,12 @@ class GuiSessionLogView(QDialog): self.monoFont = QFont("Monospace",10) sortValid = (Qt.AscendingOrder, Qt.DescendingOrder) - sortCol = self.optState.validIntRange(self.optState.getSetting("sortCol"), 0, 2, 0) - sortOrder = self.optState.validIntTuple(self.optState.getSetting("sortOrder"), sortValid, Qt.DescendingOrder) + sortCol = self.optState.validIntRange( + self.optState.getSetting("sortCol"), 0, 2, 0 + ) + sortOrder = self.optState.validIntTuple( + self.optState.getSetting("sortOrder"), sortValid, Qt.DescendingOrder + ) self.listBox.sortByColumn(sortCol, sortOrder) self.listBox.setSortingEnabled(True) diff --git a/nw/gui/dialogs/timelineview.py b/nw/gui/dialogs/timelineview.py index fba390ea..fb0a00d5 100644 --- a/nw/gui/dialogs/timelineview.py +++ b/nw/gui/dialogs/timelineview.py @@ -13,7 +13,8 @@ import logging import nw -from os import path +from os import path + from PyQt5.QtCore import Qt from PyQt5.QtGui import QIcon, QColor, QPixmap from PyQt5.QtWidgets import ( @@ -41,21 +42,25 @@ class GuiTimeLineView(QDialog): self.optState = TimeLineLastState(self.theProject,nwFiles.TLINE_OPT) self.optState.loadSettings() - self.theMatrix = {} - self.numRows = 0 - self.numCols = 0 + self.theMatrix = {} + self.numRows = 0 + self.numCols = 0 - self.outerBox = QVBoxLayout() - self.filterBox = QVBoxLayout() - self.centreBox = QHBoxLayout() - self.bottomBox = QHBoxLayout() + self.outerBox = QVBoxLayout() + self.filterBox = QVBoxLayout() + self.centreBox = QHBoxLayout() + self.bottomBox = QHBoxLayout() self.setWindowTitle("Timeline View") self.setMinimumWidth(700) self.setMinimumHeight(400) - winWidth = self.optState.validIntRange(self.optState.getSetting("winWidth"), 700, 10000, 700) - winHeight = self.optState.validIntRange(self.optState.getSetting("winHeight"), 400, 10000, 400) + winWidth = self.optState.validIntRange( + self.optState.getSetting("winWidth"), 700, 10000, 700 + ) + winHeight = self.optState.validIntRange( + self.optState.getSetting("winHeight"), 400, 10000, 400 + ) self.resize(winWidth,winHeight) # TimeLine Table diff --git a/nw/gui/elements/doceditor.py b/nw/gui/elements/doceditor.py index 852d3272..e2214b03 100644 --- a/nw/gui/elements/doceditor.py +++ b/nw/gui/elements/doceditor.py @@ -82,9 +82,24 @@ class GuiDocEditor(QTextEdit): self.setAcceptRichText(False) # Custom Shortcuts - QShortcut(QKeySequence("Ctrl+."), self, context=Qt.WidgetShortcut, activated=self._openSpellContext) - QShortcut(Qt.Key_Return | Qt.ControlModifier, self, context=Qt.WidgetShortcut, activated=self._followTag) - QShortcut(Qt.Key_Enter | Qt.ControlModifier, self, context=Qt.WidgetShortcut, activated=self._followTag) + QShortcut( + QKeySequence("Ctrl+."), + self, + context = Qt.WidgetShortcut, + activated = self._openSpellContext + ) + QShortcut( + Qt.Key_Return | Qt.ControlModifier, + self, + context = Qt.WidgetShortcut, + activated = self._followTag + ) + QShortcut( + Qt.Key_Enter | Qt.ControlModifier, + self, + context = Qt.WidgetShortcut, + activated = self._followTag + ) # Set Up Word Count Thread and Timer self.wcInterval = self.mainConf.wordCountTimer @@ -459,7 +474,9 @@ class GuiDocEditor(QTextEdit): if len(theSuggest) > 0: for aWord in theSuggest: mnuWord = QAction(aWord, mnuSuggest) - mnuWord.triggered.connect(lambda thePos, aWord=aWord : self._correctWord(theCursor, aWord)) + mnuWord.triggered.connect( + lambda thePos, aWord=aWord : self._correctWord(theCursor, aWord) + ) mnuSuggest.addAction(mnuWord) mnuSuggest.addSeparator() mnuAdd = QAction("Add Word to Dictionary", mnuSuggest) diff --git a/nw/gui/elements/doctree.py b/nw/gui/elements/doctree.py index 9b4bc750..854ceac4 100644 --- a/nw/gui/elements/doctree.py +++ b/nw/gui/elements/doctree.py @@ -18,8 +18,8 @@ from PyQt5.QtGui import QIcon, QFont, QColor from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAbstractItemView, QApplication from nw.project.item import NWItem -from nw.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert from nw.constants import nwLabels +from nw.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert logger = logging.getLogger(__name__) @@ -145,11 +145,15 @@ class GuiDocTree(QTreeWidget): # If we again has no home, give up if pHandle is None: - self.makeAlert("Did not find anywhere to add the file or folder!", nwAlert.ERROR) + self.makeAlert( + "Did not find anywhere to add the file or folder!", nwAlert.ERROR + ) return False if pHandle == self.theProject.trashRoot: - self.makeAlert("Cannot add new files or folders to the trash folder.", nwAlert.ERROR) + self.makeAlert( + "Cannot add new files or folders to the trash folder.", nwAlert.ERROR + ) return False # If we're still here, add the file or folder @@ -295,10 +299,10 @@ class GuiDocTree(QTreeWidget): tStatus += "."+nwLabels.LAYOUT_FLAG[nwItem.itemLayout] iStatus = nwItem.itemStatus if tClass == nwItemClass.NOVEL: - iStatus = self.theProject.statusItems.checkEntry(iStatus) # Make sure it's a valid index + iStatus = self.theProject.statusItems.checkEntry(iStatus) # Make sure it's valid flagIcon = self.theParent.statusIcons[iStatus] else: - iStatus = self.theProject.importItems.checkEntry(iStatus) # Make sure it's a valid index + iStatus = self.theProject.importItems.checkEntry(iStatus) # Make sure it's valid flagIcon = self.theParent.importIcons[iStatus] trItem.setText(self.C_NAME, tName) diff --git a/nw/gui/elements/docviewer.py b/nw/gui/elements/docviewer.py index 468f4f2b..9edd1838 100644 --- a/nw/gui/elements/docviewer.py +++ b/nw/gui/elements/docviewer.py @@ -205,24 +205,24 @@ class GuiDocViewer(QTextBrowser): ).format( textSize = self.mainConf.textSize, preSize = self.mainConf.textSize*0.9, - tColR = self.theTheme.colText[0], - tColG = self.theTheme.colText[1], - tColB = self.theTheme.colText[2], - hColR = self.theTheme.colHead[0], - hColG = self.theTheme.colHead[1], - hColB = self.theTheme.colHead[2], - cColR = self.theTheme.colComm[0], - cColG = self.theTheme.colComm[1], - cColB = self.theTheme.colComm[2], - eColR = self.theTheme.colEmph[0], - eColG = self.theTheme.colEmph[1], - eColB = self.theTheme.colEmph[2], - aColR = self.theTheme.colVal[0], - aColG = self.theTheme.colVal[1], - aColB = self.theTheme.colVal[2], - kColR = self.theTheme.colKey[0], - kColG = self.theTheme.colKey[1], - kColB = self.theTheme.colKey[2], + tColR = self.theTheme.colText[0], + tColG = self.theTheme.colText[1], + tColB = self.theTheme.colText[2], + hColR = self.theTheme.colHead[0], + hColG = self.theTheme.colHead[1], + hColB = self.theTheme.colHead[2], + cColR = self.theTheme.colComm[0], + cColG = self.theTheme.colComm[1], + cColB = self.theTheme.colComm[2], + eColR = self.theTheme.colEmph[0], + eColG = self.theTheme.colEmph[1], + eColB = self.theTheme.colEmph[2], + aColR = self.theTheme.colVal[0], + aColG = self.theTheme.colVal[1], + aColB = self.theTheme.colVal[2], + kColR = self.theTheme.colKey[0], + kColG = self.theTheme.colKey[1], + kColB = self.theTheme.colKey[2], ) self.qDocument.setDefaultStyleSheet(styleSheet) diff --git a/nw/gui/elements/searchbar.py b/nw/gui/elements/searchbar.py index e5da35ee..8fab6e93 100644 --- a/nw/gui/elements/searchbar.py +++ b/nw/gui/elements/searchbar.py @@ -17,7 +17,7 @@ from PyQt5.QtCore import Qt from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import QFrame, QGridLayout, QLabel, QLineEdit, QPushButton, QApplication -from nw.enum import nwDocAction +from nw.enum import nwDocAction logger = logging.getLogger(__name__) diff --git a/nw/gui/mainmenu.py b/nw/gui/mainmenu.py index e40975ae..49551b9b 100644 --- a/nw/gui/mainmenu.py +++ b/nw/gui/mainmenu.py @@ -353,7 +353,9 @@ class GuiMainMenu(QMenuBar): # Document > Show File Details menuItem = QAction("Show File Details", self) - menuItem.setStatusTip("Shows a message box with the document location in the project folder") + menuItem.setStatusTip( + "Shows a message box with the document location in the project folder" + ) menuItem.triggered.connect(self._showDocumentLocation) self.docuMenu.addAction(menuItem) diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py index c64c095d..a6bf6f01 100644 --- a/nw/gui/winmain.py +++ b/nw/gui/winmain.py @@ -63,10 +63,18 @@ class GuiMain(QMainWindow): self.theIndex = NWIndex(self.theProject, self) self.hasProject = False - logger.info("OS: %s" % (self.mainConf.osType)) - logger.info("Qt5 Version: %s (%d)" % (self.mainConf.verQtString, self.mainConf.verQtValue)) - logger.info("PyQt5 Version: %s (%d)" % (self.mainConf.verPyQtString, self.mainConf.verPyQtValue)) - logger.info("Python Version: %s (0x%x)" % (self.mainConf.verPyString, self.mainConf.verPyHexVal)) + logger.info("OS: %s" % ( + self.mainConf.osType) + ) + logger.info("Qt5 Version: %s (%d)" % ( + self.mainConf.verQtString, self.mainConf.verQtValue) + ) + logger.info("PyQt5 Version: %s (%d)" % ( + self.mainConf.verPyQtString, self.mainConf.verPyQtValue) + ) + logger.info("Python Version: %s (0x%x)" % ( + self.mainConf.verPyString, self.mainConf.verPyHexVal) + ) self.resize(*self.mainConf.winGeometry) self._setWindowTitle() @@ -157,8 +165,17 @@ class GuiMain(QMainWindow): self.asDocTimer.timeout.connect(self._autoSaveDocument) # Keyboard Shortcuts - QShortcut(Qt.Key_Return, self.treeView, context=Qt.WidgetShortcut, activated=self._treeKeyPressReturn) - QShortcut(Qt.Key_Escape, self, activated=self._keyPressEscape) + QShortcut( + Qt.Key_Return, + self.treeView, + context = Qt.WidgetShortcut, + activated = self._treeKeyPressReturn + ) + QShortcut( + Qt.Key_Escape, + self, + activated = self._keyPressEscape + ) # Forward Functions self.setStatus = self.statusBar.setStatus @@ -271,8 +288,8 @@ class GuiMain(QMainWindow): return saveOK def openProject(self, projFile=None): - """Open a project. - 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() @@ -415,20 +432,26 @@ class GuiMain(QMainWindow): with open(loadFile,mode="rt",encoding="utf8") as inFile: theText = inFile.read() except Exception as e: - self.makeAlert(["Could not read file. The file cannot be a binary file.",str(e)], nwAlert.ERROR) + self.makeAlert( + ["Could not read file. The file cannot be a binary file.",str(e)], + nwAlert.ERROR + ) return False if self.docEditor.theHandle is None: - self.makeAlert(["Please open a document to import the text file into."], nwAlert.ERROR) + self.makeAlert( + ["Please open a document to import the text file into."], + nwAlert.ERROR + ) return False if not self.docEditor.isEmpty(): if self.mainConf.showGUI: msgBox = QMessageBox() - msgRes = msgBox.question( - self, "Import Document", - "Importing the file will overwrite the current content of the document. Do you want to proceed?" - ) + msgRes = msgBox.question(self, "Import Document",( + "Importing the file will overwrite the current content of the document. " + "Do you want to proceed?" + )) if msgRes != QMessageBox.Yes: return False else: @@ -733,7 +756,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() @@ -779,7 +803,7 @@ 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) diff --git a/nw/project/backup.py b/nw/project/backup.py index bb69309a..993c4406 100644 --- a/nw/project/backup.py +++ b/nw/project/backup.py @@ -32,11 +32,15 @@ class NWBackup(): def zipIt(self): if self.mainConf.backupPath is None: - self.theParent.makeAlert("Cannot backup project because no backup path is set.",nwAlert.WARN) + self.theParent.makeAlert( + "Cannot backup project because no backup path is set.",nwAlert.WARN + ) return False if self.theProject.projName is None: - self.theParent.makeAlert("Cannot backup project because no project name is set.",nwAlert.WARN) + self.theParent.makeAlert( + "Cannot backup project because no project name is set.",nwAlert.WARN + ) return False logger.info("Backing up project") @@ -55,7 +59,10 @@ class NWBackup(): try: make_archive(baseName, "zip", self.theProject.projPath, ".") except Exception as e: - self.theParent.makeAlert(["Could not write backup archive.",str(e)],nwAlert.ERROR) + self.theParent.makeAlert( + ["Could not write backup archive.",str(e)], + nwAlert.ERROR + ) return False self.theParent.statusBar.setStatus("Project backup complete") diff --git a/nw/project/project.py b/nw/project/project.py index aa9bc9d2..9a0bfd03 100644 --- a/nw/project/project.py +++ b/nw/project/project.py @@ -214,7 +214,10 @@ class NWProject(): logger.verbose("File version is %s" % fileVersion) if not nwxRoot == "novelWriterXML" or not fileVersion == "1.0": - self.makeAlert("Project file does not appear to be a novelWriterXML file version 1.0", nwAlert.ERROR) + self.makeAlert( + "Project file does not appear to be a novelWriterXML file version 1.0", + nwAlert.ERROR + ) return False for xChild in xRoot: @@ -399,16 +402,16 @@ class NWProject(): self.doBackup = False if doBackup: if not path.isdir(self.mainConf.backupPath): - self.theParent.makeAlert( - "You must set a valid backup path in preferences
to use the automatic project backup feature.", - nwAlert.ERROR - ) + self.theParent.makeAlert(( + "You must set a valid backup path in preferences to use " + "the automatic project backup feature." + ), nwAlert.ERROR) return False if self.projName == "": - self.theParent.makeAlert( - "You must set a valid project name in project settings
to use the automatic project backup feature.", - nwAlert.ERROR - ) + self.theParent.makeAlert(( + "You must set a valid project name in project settings to use " + "the automatic project backup feature." + ), nwAlert.ERROR) return False self.doBackup = True return True @@ -634,7 +637,10 @@ class NWProject(): # Report status if len(orphanFiles) > 0: - self.makeAlert("Found %d orphaned file(s) in project folder!" % len(orphanFiles), nwAlert.WARN) + self.makeAlert( + "Found %d orphaned file(s) in project folder!" % len(orphanFiles), + nwAlert.WARN + ) else: logger.debug("File check OK") return From be78fd201ed0c23dbea3f8171d4debc65ec7ab17 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 3 Nov 2019 15:55:37 +0100 Subject: [PATCH 5/8] Added a coding style guide --- README.md | 5 +++++ docs/markdown/style.md | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 docs/markdown/style.md diff --git a/README.md b/README.md index dcb2ca69..cc01bd40 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,11 @@ The different notes can be assigned tags, which the novel files can refer back t Currently, this information can be used to display a Timeline View of the story, showing where each scene connects to the plot, and which characters, etc. occur in them. Further features using this meta data will be added in the future. +## Contribution + +If you ant to contribute to novelWriter, please follow the coding convention laid out in the [Style Guide](docs/markdown/style.md). +They broadly follow Python PEP8, but there are a few modifications. + ## Screenshot ![Screenshot 1](docs/source/images/screenshot.png) diff --git a/docs/markdown/style.md b/docs/markdown/style.md new file mode 100644 index 00000000..3ae03093 --- /dev/null +++ b/docs/markdown/style.md @@ -0,0 +1,22 @@ +# Code Style Guide + +The source code of novelWriter broadly follows the style guide [PEP8](https://www.python.org/dev/peps/pep-0008/), but with a few modifications and exceptions. + +### Source Code Exceptions + +* Methods are camelCase, not underscore based. + The reason is partially because of the maintainers personal preference, and partially because that is what Qt5 and PyQt5 uses. + The maintainer generally, across multiple programming languages, uses underscores for defining namespaces. +* The maximum length of a code line is 100 characters, not 79. + The reason for this is that novelWriter is almost entirely made up of classes, meaning nearly all lines of code already have 8 leading spaces. + A 79 character limitation is too strict, and causes too many wrapped lines. + 100 characters is suitable for GitHub diff readability, and therefore the preferred limit. +* Aligning code with additional spaces is acceptable in those cases where it improves readability. + Otherwise, the PEP8 standard should be applied. + +### Documentation + +The documentation does not adhere to the 80 character limit either. +The standard used in documentation is one line break after each sentence. +This is an alternative style that greatly improves readability of diffs as re-wrapping text is not needed when inserting new text in paragraphs. +Instead, the diff will show changes to each sentence. From 7c95af951ae0da5d67300f35f52df76ef96a302f Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 3 Nov 2019 17:23:39 +0100 Subject: [PATCH 6/8] Make comments and docstrings comply with PEP8 --- nw/common.py | 4 +- nw/convert/file/text.py | 26 ++++--- nw/convert/text/tohtml.py | 5 +- nw/convert/text/tolatex.py | 13 ++-- nw/convert/text/tomarkdown.py | 13 ++-- nw/convert/text/totext.py | 13 ++-- nw/convert/tokenizer.py | 9 ++- nw/gui/dialogs/export.py | 7 +- nw/gui/dialogs/sessionlog.py | 12 ++- nw/gui/elements/doceditor.py | 141 +++++++++++++++++++++------------- nw/gui/elements/doctree.py | 32 ++++---- nw/gui/mainmenu.py | 7 +- nw/gui/winmain.py | 32 +++++--- nw/project/document.py | 12 +-- nw/project/index.py | 37 +++++---- nw/project/item.py | 33 +++++--- nw/project/project.py | 47 +++++++----- nw/project/status.py | 2 +- nw/tools/analyse.py | 21 ++--- nw/tools/spellenchant.py | 5 +- 20 files changed, 287 insertions(+), 184 deletions(-) diff --git a/nw/common.py b/nw/common.py index b148e7df..ada29987 100644 --- a/nw/common.py +++ b/nw/common.py @@ -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 diff --git a/nw/convert/file/text.py b/nw/convert/file/text.py index 4d3cd346..0925515b 100644 --- a/nw/convert/file/text.py +++ b/nw/convert/file/text.py @@ -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.
Do you want to overwrite it?" % self.fileName) - ) + msgRes = msgBox.question(self.theParent, "Overwrite", ( + "File '%s' already exists.
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() diff --git a/nw/convert/text/tohtml.py b/nw/convert/text/tohtml.py index fae40df4..4abdeeb3 100644 --- a/nw/convert/text/tohtml.py +++ b/nw/convert/text/tohtml.py @@ -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 diff --git a/nw/convert/text/tolatex.py b/nw/convert/text/tolatex.py index 435fee84..e68cd3b2 100644 --- a/nw/convert/text/tolatex.py +++ b/nw/convert/text/tolatex.py @@ -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: diff --git a/nw/convert/text/tomarkdown.py b/nw/convert/text/tomarkdown.py index 78098c5e..c9ea57b7 100644 --- a/nw/convert/text/tomarkdown.py +++ b/nw/convert/text/tomarkdown.py @@ -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: diff --git a/nw/convert/text/totext.py b/nw/convert/text/totext.py index e6073012..e7fdb9d2 100644 --- a/nw/convert/text/totext.py +++ b/nw/convert/text/totext.py @@ -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: diff --git a/nw/convert/tokenizer.py b/nw/convert/tokenizer.py index acc90b91..e391aab7 100644 --- a/nw/convert/tokenizer.py +++ b/nw/convert/tokenizer.py @@ -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 diff --git a/nw/gui/dialogs/export.py b/nw/gui/dialogs/export.py index d3be1260..ea2eb0bf 100644 --- a/nw/gui/dialogs/export.py +++ b/nw/gui/dialogs/export.py @@ -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("") diff --git a/nw/gui/dialogs/sessionlog.py b/nw/gui/dialogs/sessionlog.py index be2a1f94..0afd21c5 100644 --- a/nw/gui/dialogs/sessionlog.py +++ b/nw/gui/dialogs/sessionlog.py @@ -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",""]) diff --git a/nw/gui/elements/doceditor.py b/nw/gui/elements/doceditor.py index e2214b03..4a21ddac 100644 --- a/nw/gui/elements/doceditor.py +++ b/nw/gui/elements/doceditor.py @@ -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() diff --git a/nw/gui/elements/doctree.py b/nw/gui/elements/doctree.py index 854ceac4..bafa5b48 100644 --- a/nw/gui/elements/doctree.py +++ b/nw/gui/elements/doctree.py @@ -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: diff --git a/nw/gui/mainmenu.py b/nw/gui/mainmenu.py index 49551b9b..ffa876c5 100644 --- a/nw/gui/mainmenu.py +++ b/nw/gui/mainmenu.py @@ -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 = ( "

About {name:s}

" "

Version: {version:s}
Release Date: {date:s}

" - "

{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

" + "

{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

" "

{name:s} is licensed under GPL v3.0

" "

{copyright:s}

" "

Website: {website:s}

" diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py index a6bf6f01..8eedb626 100644 --- a/nw/gui/winmain.py +++ b/nw/gui/winmain.py @@ -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 diff --git a/nw/project/document.py b/nw/project/document.py index e54a72f0..3e807a2b 100644 --- a/nw/project/document.py +++ b/nw/project/document.py @@ -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 "" diff --git a/nw/project/index.py b/nw/project/index.py index db7d21e1..d3b62613 100644 --- a/nw/project/index.py +++ b/nw/project/index.py @@ -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 = {} diff --git a/nw/project/item.py b/nw/project/item.py index 55d532a1..9640265b 100644 --- a/nw/project/item.py +++ b/nw/project/item.py @@ -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 diff --git a/nw/project/project.py b/nw/project/project.py index 9a0bfd03..a0208885 100644 --- a/nw/project/project.py +++ b/nw/project/project.py @@ -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) diff --git a/nw/project/status.py b/nw/project/status.py index ea1a045a..d3bbb560 100644 --- a/nw/project/status.py +++ b/nw/project/status.py @@ -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 diff --git a/nw/tools/analyse.py b/nw/tools/analyse.py index 37076063..bb847d74 100644 --- a/nw/tools/analyse.py +++ b/nw/tools/analyse.py @@ -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) diff --git a/nw/tools/spellenchant.py b/nw/tools/spellenchant.py index b2faa472..cf4f1574 100644 --- a/nw/tools/spellenchant.py +++ b/nw/tools/spellenchant.py @@ -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: From b303eb6539e8b76b42cea344a6c6fd10fe09bbfd Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 3 Nov 2019 18:02:47 +0100 Subject: [PATCH 7/8] Further PEP8 compliance changes --- nw/common.py | 22 ++-- nw/config.py | 18 ++-- nw/convert/file/concat.py | 7 +- nw/convert/file/html.py | 6 +- nw/convert/file/latex.py | 9 +- nw/convert/file/markdown.py | 6 +- nw/convert/file/text.py | 19 ++-- nw/convert/text/tohtml.py | 4 +- nw/convert/text/tolatex.py | 2 +- nw/convert/text/totext.py | 2 +- nw/convert/tokenizer.py | 11 +- nw/gui/dialogs/configeditor.py | 28 ++++-- nw/gui/dialogs/export.py | 69 +++++++------ nw/gui/dialogs/itemeditor.py | 9 +- nw/gui/dialogs/projecteditor.py | 15 +-- nw/gui/dialogs/sessionlog.py | 36 +++---- nw/gui/dialogs/timelineview.py | 13 +-- nw/gui/elements/docdetails.py | 4 +- nw/gui/elements/doceditor.py | 35 ++++--- nw/gui/elements/doctree.py | 12 ++- nw/gui/elements/docviewer.py | 8 +- nw/gui/elements/noticebar.py | 7 +- nw/gui/elements/searchbar.py | 8 +- nw/gui/elements/viewdetails.py | 8 +- nw/gui/mainmenu.py | 8 +- nw/gui/statusbar.py | 7 +- nw/gui/tools/dochighlight.py | 30 +++--- nw/gui/winmain.py | 62 ++++++------ nw/project/backup.py | 4 +- nw/project/document.py | 9 +- nw/project/index.py | 16 ++- nw/project/item.py | 36 +++---- nw/project/project.py | 78 ++++++++------- nw/project/status.py | 2 +- nw/theme.py | 172 ++++++++++++++++---------------- nw/tools/analyse.py | 4 +- nw/tools/wordcount.py | 2 +- 37 files changed, 408 insertions(+), 380 deletions(-) diff --git a/nw/common.py b/nw/common.py index ada29987..8aa0a0f0 100644 --- a/nw/common.py +++ b/nw/common.py @@ -17,16 +17,20 @@ logger = logging.getLogger(__name__) def checkString(checkValue, defaultValue, allowNone=False): if allowNone: - if checkValue == None: return None - if checkValue == "None": return None + if checkValue == None: + return None + if checkValue == "None": + return None if isinstance(checkValue,str): return str(checkValue) return defaultValue def checkInt(checkValue, defaultValue, allowNone=False): if allowNone: - if checkValue == None: return None - if checkValue == "None": return None + if checkValue == None: + return None + if checkValue == "None": + return None try: return int(checkValue) except: @@ -34,8 +38,10 @@ def checkInt(checkValue, defaultValue, allowNone=False): def checkBool(checkValue, defaultValue, allowNone=False): if allowNone: - if checkValue == None: return None - if checkValue == "None": return None + if checkValue == None: + return None + if checkValue == "None": + return None if isinstance(checkValue, str): if checkValue == "True": return True @@ -92,8 +98,8 @@ def splitVersionNumber(vString): vPatch = 0 vInt = 0 - vBits = vString.split(".") - nBits = len(vBits) + vBits = vString.split(".") + nBits = len(vBits) if nBits > 0: vMajor = checkInt(vBits[0],0) diff --git a/nw/config.py b/nw/config.py index a47e7c24..5a50395e 100644 --- a/nw/config.py +++ b/nw/config.py @@ -15,15 +15,15 @@ import configparser import sys import nw -from os import path, mkdir, makedirs, getcwd -from appdirs import user_config_dir -from datetime import datetime +from os import path, mkdir, makedirs, getcwd +from appdirs import user_config_dir +from datetime import datetime + +from PyQt5.Qt import PYQT_VERSION_STR +from PyQt5.QtCore import QT_VERSION_STR from nw.constants import nwFiles, nwUnicode -from nw.common import splitVersionNumber - -from PyQt5.Qt import PYQT_VERSION_STR -from PyQt5.QtCore import QT_VERSION_STR +from nw.common import splitVersionNumber logger = logging.getLogger(__name__) @@ -59,8 +59,8 @@ class Config: self.confChanged = False ## General - self.guiTheme = "default" - self.guiSyntax = "default_light" + self.guiTheme = "default" + self.guiSyntax = "default_light" ## Sizes self.winGeometry = [1100, 650] diff --git a/nw/convert/file/concat.py b/nw/convert/file/concat.py index 392e86f9..6aedb857 100644 --- a/nw/convert/file/concat.py +++ b/nw/convert/file/concat.py @@ -13,12 +13,13 @@ import logging import nw -from os import path +from os import path + from PyQt5.QtWidgets import QMessageBox from nw.convert.file.text import TextFile from nw.convert.tokenizer import Tokenizer -from nw.enum import nwAlert, nwItemLayout +from nw.enum import nwAlert, nwItemLayout logger = logging.getLogger(__name__) @@ -26,9 +27,7 @@ class ConcatFile(TextFile): def __init__(self, theProject, theParent): TextFile.__init__(self, theProject, theParent) - self.theConv = Tokenizer(self.theProject, self.theParent) - return def addText(self, tHandle): diff --git a/nw/convert/file/html.py b/nw/convert/file/html.py index 1dc89b39..084789d6 100644 --- a/nw/convert/file/html.py +++ b/nw/convert/file/html.py @@ -13,9 +13,9 @@ import logging import nw -from nw.convert.file.text import TextFile +from nw.convert.file.text import TextFile from nw.convert.text.tohtml import ToHtml -from nw.enum import nwAlert +from nw.enum import nwAlert logger = logging.getLogger(__name__) @@ -23,9 +23,7 @@ class HtmlFile(TextFile): def __init__(self, theProject, theParent): TextFile.__init__(self, theProject, theParent) - self.theConv = ToHtml(self.theProject, self.theParent) - return ## diff --git a/nw/convert/file/latex.py b/nw/convert/file/latex.py index a61d3a68..6a8617fd 100644 --- a/nw/convert/file/latex.py +++ b/nw/convert/file/latex.py @@ -13,9 +13,9 @@ import logging import nw -from nw.convert.file.text import TextFile +from nw.convert.file.text import TextFile from nw.convert.text.tolatex import ToLaTeX -from nw.enum import nwAlert +from nw.enum import nwAlert logger = logging.getLogger(__name__) @@ -32,7 +32,6 @@ class LaTeXFile(TextFile): ## def _doOpenFile(self, filePath): - try: self.outFile = open(filePath,mode="wt+",encoding="utf8") self.outFile.write("\\documentclass[12pt]{report}\n") @@ -43,17 +42,13 @@ class LaTeXFile(TextFile): except Exception as e: self.makeAlert(["Failed to open file.",str(e)], nwAlert.ERROR) return False - return True def _doCloseFile(self): - if self.outFile is not None: self.outFile.write("\\end{document}\n") self.outFile.close() - self.texCodecFail = self.theConv.texCodecFail - return True # END Class LaTeXFile diff --git a/nw/convert/file/markdown.py b/nw/convert/file/markdown.py index 360f1a64..fc96ac4f 100644 --- a/nw/convert/file/markdown.py +++ b/nw/convert/file/markdown.py @@ -13,9 +13,9 @@ import logging import nw -from nw.convert.file.text import TextFile +from nw.convert.file.text import TextFile from nw.convert.text.tomarkdown import ToMarkdown -from nw.enum import nwAlert +from nw.enum import nwAlert logger = logging.getLogger(__name__) @@ -23,9 +23,7 @@ class MarkdownFile(TextFile): def __init__(self, theProject, theParent): TextFile.__init__(self, theProject, theParent) - self.theConv = ToMarkdown(self.theProject, self.theParent) - return ## diff --git a/nw/convert/file/text.py b/nw/convert/file/text.py index 0925515b..cc842422 100644 --- a/nw/convert/file/text.py +++ b/nw/convert/file/text.py @@ -13,11 +13,12 @@ import logging import nw -from os import path +from os import path + from PyQt5.QtWidgets import QMessageBox from nw.convert.text.totext import ToText -from nw.enum import nwAlert, nwItemType, nwItemLayout, nwItemClass +from nw.enum import nwAlert, nwItemType, nwItemLayout, nwItemClass logger = logging.getLogger(__name__) @@ -29,14 +30,14 @@ class TextFile(): self.theProject = theProject self.theParent = theParent - self.outFile = None - self.fileName = "" - self.theText = "" - self.expNovel = True - self.expNotes = False + self.outFile = None + self.fileName = "" + self.theText = "" + self.expNovel = True + self.expNotes = False - self.theConv = ToText(self.theProject, self.theParent) - self.makeAlert = self.theParent.makeAlert + self.theConv = ToText(self.theProject, self.theParent) + self.makeAlert = self.theParent.makeAlert self.setComments(False) self.setKeywords(False) diff --git a/nw/convert/text/tohtml.py b/nw/convert/text/tohtml.py index 4abdeeb3..ca56c87a 100644 --- a/nw/convert/text/tohtml.py +++ b/nw/convert/text/tohtml.py @@ -15,7 +15,7 @@ import re import nw from nw.convert.tokenizer import Tokenizer -from nw.constants import nwUnicode, nwLabels +from nw.constants import nwUnicode, nwLabels logger = logging.getLogger(__name__) @@ -31,12 +31,10 @@ class ToHtml(Tokenizer): need to make a few changes to formatting, which is selected by this flag. """ - self.forPreview = forPreview if forPreview: self.doKeywords = True self.doComments = doComments - return def doAutoReplace(self): diff --git a/nw/convert/text/tolatex.py b/nw/convert/text/tolatex.py index e68cd3b2..630fd405 100644 --- a/nw/convert/text/tolatex.py +++ b/nw/convert/text/tolatex.py @@ -16,7 +16,7 @@ import re import nw from nw.convert.tokenizer import Tokenizer -from nw.constants import nwUnicode +from nw.constants import nwUnicode logger = logging.getLogger(__name__) diff --git a/nw/convert/text/totext.py b/nw/convert/text/totext.py index e7fdb9d2..fa528199 100644 --- a/nw/convert/text/totext.py +++ b/nw/convert/text/totext.py @@ -16,7 +16,7 @@ import re import nw from nw.convert.tokenizer import Tokenizer -from nw.constants import nwUnicode +from nw.constants import nwUnicode logger = logging.getLogger(__name__) diff --git a/nw/convert/tokenizer.py b/nw/convert/tokenizer.py index e391aab7..44bcc6c7 100644 --- a/nw/convert/tokenizer.py +++ b/nw/convert/tokenizer.py @@ -15,12 +15,12 @@ import logging import re import nw -from operator import itemgetter -from PyQt5.QtCore import QRegularExpression +from operator import itemgetter +from PyQt5.QtCore import QRegularExpression from nw.project.document import NWDoc -from nw.tools.translate import numberToWord -from nw.enum import nwItemLayout +from nw.tools.translate import numberToWord +from nw.enum import nwItemLayout logger = logging.getLogger(__name__) @@ -230,7 +230,8 @@ class Tokenizer(): if isNone: return if isNote: return - # For novel files, we need to handle chapter numbering and scene breaks + # For novel files, we need to handle chapter numbering and scene + # breaks if isBook or isUnNum or isChap or isScene: for n in range(len(self.theTokens)): diff --git a/nw/gui/dialogs/configeditor.py b/nw/gui/dialogs/configeditor.py index fd90ec9a..28f44c80 100644 --- a/nw/gui/dialogs/configeditor.py +++ b/nw/gui/dialogs/configeditor.py @@ -15,15 +15,15 @@ import nw from os import path -from PyQt5.QtCore import Qt, QSize -from PyQt5.QtGui import QIcon, QPixmap, QColor, QBrush, QStandardItemModel, QFont -from PyQt5.QtSvg import QSvgWidget +from PyQt5.QtCore import Qt, QSize +from PyQt5.QtGui import QIcon, QPixmap, QColor, QBrush, QStandardItemModel, QFont +from PyQt5.QtSvg import QSvgWidget from PyQt5.QtWidgets import ( QDialog, QHBoxLayout, QVBoxLayout, QFormLayout, QLineEdit, QPlainTextEdit, QLabel, QWidget, QTabWidget, QDialogButtonBox, QSpinBox, QGroupBox, QComboBox, QMessageBox, QCheckBox, QGridLayout, QFontComboBox, QPushButton, QFileDialog ) -from nw.enum import nwAlert +from nw.enum import nwAlert from nw.constants import nwQuotes logger = logging.getLogger(__name__) @@ -80,8 +80,8 @@ class GuiConfigEditor(QDialog): logger.verbose("ConfigEditor save button clicked") - validEntries = True - needsRestart = False + validEntries = True + needsRestart = False retA, retB = self.tabMain.saveValues() validEntries &= retA @@ -557,25 +557,33 @@ class GuiConfigEditEditor(QWidget): if self._checkQuoteSymbol(fmtSingleQuotesO): self.mainConf.fmtSingleQuotes[0] = fmtSingleQuotesO else: - self.theParent.makeAlert("Invalid quote symbol: %s" % fmtSingleQuotesO, nwAlert.ERROR) + self.theParent.makeAlert( + "Invalid quote symbol: %s" % fmtSingleQuotesO, nwAlert.ERROR + ) validEntries = False if self._checkQuoteSymbol(fmtSingleQuotesC): self.mainConf.fmtSingleQuotes[1] = fmtSingleQuotesC else: - self.theParent.makeAlert("Invalid quote symbol: %s" % fmtSingleQuotesC, nwAlert.ERROR) + self.theParent.makeAlert( + "Invalid quote symbol: %s" % fmtSingleQuotesC, nwAlert.ERROR + ) validEntries = False if self._checkQuoteSymbol(fmtDoubleQuotesO): self.mainConf.fmtDoubleQuotes[0] = fmtDoubleQuotesO else: - self.theParent.makeAlert("Invalid quote symbol: %s" % fmtDoubleQuotesO, nwAlert.ERROR) + self.theParent.makeAlert( + "Invalid quote symbol: %s" % fmtDoubleQuotesO, nwAlert.ERROR + ) validEntries = False if self._checkQuoteSymbol(fmtDoubleQuotesC): self.mainConf.fmtDoubleQuotes[1] = fmtDoubleQuotesC else: - self.theParent.makeAlert("Invalid quote symbol: %s" % fmtDoubleQuotesC, nwAlert.ERROR) + self.theParent.makeAlert( + "Invalid quote symbol: %s" % fmtDoubleQuotesC, nwAlert.ERROR + ) validEntries = False showTabsNSpaces = self.showTabsNSpaces.isChecked() diff --git a/nw/gui/dialogs/export.py b/nw/gui/dialogs/export.py index ea2eb0bf..cb4bd113 100644 --- a/nw/gui/dialogs/export.py +++ b/nw/gui/dialogs/export.py @@ -16,24 +16,25 @@ import nw from os import path -from PyQt5.QtCore import Qt, QSize -from PyQt5.QtSvg import QSvgWidget +from PyQt5.QtCore import Qt, QSize +from PyQt5.QtSvg import QSvgWidget from PyQt5.QtWidgets import ( - QDialog, QHBoxLayout, QVBoxLayout, QWidget, QTabWidget, QGridLayout, QGroupBox, QCheckBox, - QLabel, QComboBox, QLineEdit, QPushButton, QFileDialog, QProgressBar, QSpinBox, QMessageBox + QDialog, QHBoxLayout, QVBoxLayout, QWidget, QTabWidget, QGridLayout, + QGroupBox, QCheckBox, QLabel, QComboBox, QLineEdit, QPushButton, + QFileDialog, QProgressBar, QSpinBox, QMessageBox ) -from nw.project.document import NWDoc -from nw.tools.translate import numberToWord -from nw.tools.optlaststate import OptLastState -from nw.convert.file.text import TextFile -from nw.convert.file.html import HtmlFile +from nw.project.document import NWDoc +from nw.tools.translate import numberToWord +from nw.tools.optlaststate import OptLastState +from nw.convert.file.text import TextFile +from nw.convert.file.html import HtmlFile from nw.convert.file.markdown import MarkdownFile -from nw.convert.file.latex import LaTeXFile -from nw.convert.file.concat import ConcatFile -from nw.common import packageRefURL -from nw.constants import nwFiles -from nw.enum import nwItemType, nwAlert +from nw.convert.file.latex import LaTeXFile +from nw.convert.file.concat import ConcatFile +from nw.common import packageRefURL +from nw.constants import nwFiles +from nw.enum import nwItemType, nwAlert logger = logging.getLogger(__name__) @@ -201,9 +202,10 @@ class GuiExport(QDialog): # Check that encoding was successful if outFile.texCodecFail: self.theParent.makeAlert(( - "Failed to escape unicode characters while writing LaTeX file. The generated " - ".tex file may not build properly. Make sure the python package '{package:s}' " - "is installed and working." + "Failed to escape unicode characters while writing LaTeX " + "file. The generated .tex file may not build properly. " + "Make sure the python package '{package:s}' is installed " + "and working." ).format( package = packageRefURL("latexcodec") ), nwAlert.WARN) @@ -343,27 +345,31 @@ class GuiExportMain(QWidget): } FMT_HELP = { FMT_NWD : ( - "Exports a document using the novelWriter markdown format. The files selected by the " - "filters are appended as-is, including comments and other settings." + "Exports a document using the novelWriter markdown format. " + "The files selected by the filters are appended as-is, " + "including comments and other settings." ), FMT_TXT : ( - "Exports a plain text file. All formatting is stripped and comments are in square " - "brackets." + "Exports a plain text file. All formatting is stripped and " + "comments are in square brackets." ), FMT_MD : ( - "Exports a standard markdown file. Comments are converted to preformatted text blocks." + "Exports a standard markdown file. Comments are converted " + "to preformatted text blocks." ), FMT_HTML : ( - "Exports a plain html5 file. Comments are wrapped in blocks with a yellow background " - "colour." + "Exports a plain html5 file. Comments are wrapped in " + "blocks with a yellow background colour." ), FMT_TEX : ( - "Exports a LaTeX file that can be compiled to PDF using for instance PDFLaTeX. " - "Comments are exported as LaTeX comments." + "Exports a LaTeX file that can be compiled to PDF using " + "for instance PDFLaTeX. 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." ), } @@ -566,7 +572,8 @@ class GuiExportMain(QWidget): dlgOpt = QFileDialog.Options() dlgOpt |= QFileDialog.DontUseNativeDialog saveTo = QFileDialog.getSaveFileName( - self,"Export File",self.exportPath.text(),options=dlgOpt,filter=";;".join(extFilter) + self, "Export File", self.exportPath.text(), + options=dlgOpt, filter=";;".join(extFilter) ) if saveTo: self.exportPath.setText(saveTo[0]) @@ -658,7 +665,6 @@ class GuiExportPandoc(QWidget): self.outputFormat.addItem("ePUB eBook v2 (.epub2)", self.FMT_EPUB2) self.outputFormat.addItem("ePUB eBook v3 (.epub3)", self.FMT_EPUB3) self.outputFormat.addItem("Zim Wiki (.txt)", self.FMT_ZIM) - # self.outputFormat.currentIndexChanged.connect(self._updateFormat) optIdx = self.outputFormat.findData(self.optState.getSetting("pFormat")) if optIdx == -1: @@ -674,9 +680,6 @@ class GuiExportPandoc(QWidget): self.outerBox.addWidget(self.guiInfo, 0, 0) self.outerBox.addWidget(self.guiOutput, 1, 0) self.outerBox.setRowStretch(2, 1) - # self.outerBox.setColumnStretch(0, 1) - # self.outerBox.setColumnStretch(1, 1) - # self.outerBox.setColumnStretch(2, 1) self.setLayout(self.outerBox) return diff --git a/nw/gui/dialogs/itemeditor.py b/nw/gui/dialogs/itemeditor.py index a5bc5fe1..3e771b63 100644 --- a/nw/gui/dialogs/itemeditor.py +++ b/nw/gui/dialogs/itemeditor.py @@ -15,13 +15,14 @@ import nw from os import path -from PyQt5.QtCore import Qt, QSize -from PyQt5.QtSvg import QSvgWidget +from PyQt5.QtCore import Qt, QSize +from PyQt5.QtSvg import QSvgWidget from PyQt5.QtWidgets import ( - QDialog, QHBoxLayout, QVBoxLayout, QGroupBox, QFormLayout, QLineEdit, QPushButton, QComboBox + QDialog, QHBoxLayout, QVBoxLayout, QGroupBox, QFormLayout, + QLineEdit, QPushButton, QComboBox ) -from nw.enum import nwItemLayout, nwItemClass, nwItemType +from nw.enum import nwItemLayout, nwItemClass, nwItemType from nw.constants import nwLabels logger = logging.getLogger(__name__) diff --git a/nw/gui/dialogs/projecteditor.py b/nw/gui/dialogs/projecteditor.py index 4909d835..6daecddc 100644 --- a/nw/gui/dialogs/projecteditor.py +++ b/nw/gui/dialogs/projecteditor.py @@ -15,13 +15,14 @@ import nw from os import path -from PyQt5.QtCore import Qt, QSize -from PyQt5.QtGui import QIcon, QPixmap, QColor, QBrush, QStandardItemModel -from PyQt5.QtSvg import QSvgWidget +from PyQt5.QtCore import Qt, QSize +from PyQt5.QtGui import QIcon, QPixmap, QColor, QBrush, QStandardItemModel +from PyQt5.QtSvg import QSvgWidget from PyQt5.QtWidgets import ( - QDialog, QHBoxLayout, QVBoxLayout, QFormLayout, QLineEdit, QPlainTextEdit, QLabel, - QWidget, QTabWidget, QDialogButtonBox, QListWidget, QListWidgetItem, QPushButton, - QColorDialog, QAbstractItemView, QTreeWidget, QTreeWidgetItem, QCheckBox + QDialog, QHBoxLayout, QVBoxLayout, QFormLayout, QLineEdit, QPlainTextEdit, + QLabel, QWidget, QTabWidget, QDialogButtonBox, QListWidget, + QListWidgetItem, QPushButton, QColorDialog, QAbstractItemView, QTreeWidget, + QTreeWidgetItem, QCheckBox ) from nw.enum import nwAlert @@ -173,7 +174,7 @@ class GuiProjectEditStatus(QWidget): for iName, iCol, nUse in self.theStatus: self._addItem(iName, iCol, iName, nUse) - self.editName = QLineEdit() + self.editName = QLineEdit() self.editName.setEnabled(False) self.newButton = QPushButton("New") self.delButton = QPushButton("Delete") diff --git a/nw/gui/dialogs/sessionlog.py b/nw/gui/dialogs/sessionlog.py index 0afd21c5..a897039a 100644 --- a/nw/gui/dialogs/sessionlog.py +++ b/nw/gui/dialogs/sessionlog.py @@ -13,18 +13,20 @@ import logging import nw -from os import path -from datetime import datetime -from PyQt5.QtCore import Qt -from PyQt5.QtGui import QIcon, QColor, QPixmap, QFont +from os import path +from datetime import datetime + +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QIcon, QColor, QPixmap, QFont from PyQt5.QtWidgets import ( - QDialog, QVBoxLayout, QHBoxLayout, QTreeWidget, QTreeWidgetItem, QDialogButtonBox, QHeaderView, - QGridLayout, QLabel, QGroupBox, QCheckBox + QDialog, QVBoxLayout, QHBoxLayout, QTreeWidget, QTreeWidgetItem, + QDialogButtonBox, QHeaderView, QGridLayout, QLabel, QGroupBox, + QCheckBox ) from nw.tools.optlaststate import OptLastState -from nw.constants import nwConst, nwFiles -from nw.enum import nwAlert +from nw.constants import nwConst, nwFiles +from nw.enum import nwAlert logger = logging.getLogger(__name__) @@ -44,8 +46,8 @@ class GuiSessionLogView(QDialog): self.timeFilter = 0.0 self.timeTotal = 0.0 - self.outerBox = QGridLayout() - self.bottomBox = QHBoxLayout() + self.outerBox = QGridLayout() + self.bottomBox = QHBoxLayout() self.setWindowTitle("Session Log") self.setMinimumWidth(420) @@ -76,7 +78,7 @@ class GuiSessionLogView(QDialog): self.monoFont = QFont("Monospace",10) sortValid = (Qt.AscendingOrder, Qt.DescendingOrder) - sortCol = self.optState.validIntRange( + sortCol = self.optState.validIntRange( self.optState.getSetting("sortCol"), 0, 2, 0 ) sortOrder = self.optState.validIntTuple( @@ -91,7 +93,7 @@ class GuiSessionLogView(QDialog): self.infoBoxForm = QGridLayout(self) self.infoBox.setLayout(self.infoBoxForm) - self.labelTotal = QLabel(self._formatTime(0)) + self.labelTotal = QLabel(self._formatTime(0)) self.labelTotal.setFont(self.monoFont) self.labelTotal.setAlignment(Qt.AlignVCenter | Qt.AlignRight) @@ -162,11 +164,11 @@ class GuiSessionLogView(QDialog): inData = inLine.split() if len(inData) != 8: continue - dStart = datetime.strptime("%s %s" % (inData[1],inData[2]),nwConst.tStampFmt) - dEnd = datetime.strptime("%s %s" % (inData[4],inData[5]),nwConst.tStampFmt) - nWords = int(inData[7]) - tDiff = dEnd - dStart - sDiff = tDiff.total_seconds() + dStart = datetime.strptime("%s %s" % (inData[1],inData[2]),nwConst.tStampFmt) + dEnd = datetime.strptime("%s %s" % (inData[4],inData[5]),nwConst.tStampFmt) + nWords = int(inData[7]) + tDiff = dEnd - dStart + sDiff = tDiff.total_seconds() self.timeTotal += sDiff if abs(nWords) > 0: diff --git a/nw/gui/dialogs/timelineview.py b/nw/gui/dialogs/timelineview.py index fb0a00d5..6d78e12a 100644 --- a/nw/gui/dialogs/timelineview.py +++ b/nw/gui/dialogs/timelineview.py @@ -15,16 +15,17 @@ import nw from os import path -from PyQt5.QtCore import Qt -from PyQt5.QtGui import QIcon, QColor, QPixmap +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QIcon, QColor, QPixmap from PyQt5.QtWidgets import ( - QDialog, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem, QDialogButtonBox, QLabel, - QPushButton, QHeaderView, QGridLayout, QGroupBox, QCheckBox + QDialog, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem, + QDialogButtonBox, QLabel, QPushButton, QHeaderView, QGridLayout, + QGroupBox, QCheckBox ) from nw.tools.optlaststate import OptLastState -from nw.constants import nwFiles -from nw.enum import nwItemClass +from nw.constants import nwFiles +from nw.enum import nwItemClass logger = logging.getLogger(__name__) diff --git a/nw/gui/elements/docdetails.py b/nw/gui/elements/docdetails.py index a38f9ac6..7df20457 100644 --- a/nw/gui/elements/docdetails.py +++ b/nw/gui/elements/docdetails.py @@ -13,10 +13,10 @@ import logging import nw -from PyQt5.QtGui import QFont +from PyQt5.QtGui import QFont from PyQt5.QtWidgets import QFrame, QGridLayout, QLabel -from nw.constants import nwLabels +from nw.constants import nwLabels logger = logging.getLogger(__name__) diff --git a/nw/gui/elements/doceditor.py b/nw/gui/elements/doceditor.py index 4a21ddac..cb1cd2ef 100644 --- a/nw/gui/elements/doceditor.py +++ b/nw/gui/elements/doceditor.py @@ -15,18 +15,21 @@ import nw from time import time -from PyQt5.QtCore import Qt, QTimer, QSizeF -from PyQt5.QtWidgets import qApp, QTextEdit, QAction, QMenu, QShortcut, QMessageBox -from PyQt5.QtGui import ( - QTextCursor, QTextOption, QIcon, QKeySequence, QFont, QColor, QPalette, QTextDocument, +from PyQt5.QtCore import Qt, QTimer, QSizeF +from PyQt5.QtWidgets import ( + qApp, QTextEdit, QAction, QMenu, QShortcut, QMessageBox +) +from PyQt5.QtGui import ( + QTextCursor, QTextOption, QIcon, QKeySequence, QFont, QColor, + QPalette, QTextDocument, ) -from nw.project.document import NWDoc +from nw.project.document import NWDoc from nw.gui.tools.dochighlight import GuiDocHighlighter -from nw.gui.tools.wordcounter import WordCounter -from nw.tools.spellcheck import NWSpellCheck -from nw.constants import nwFiles, nwUnicode -from nw.enum import nwDocAction, nwAlert +from nw.gui.tools.wordcounter import WordCounter +from nw.tools.spellcheck import NWSpellCheck +from nw.constants import nwFiles, nwUnicode +from nw.enum import nwDocAction, nwAlert logger = logging.getLogger(__name__) @@ -85,20 +88,20 @@ class GuiDocEditor(QTextEdit): QShortcut( QKeySequence("Ctrl+."), self, - context = Qt.WidgetShortcut, - activated = self._openSpellContext + context=Qt.WidgetShortcut, + activated=self._openSpellContext ) QShortcut( Qt.Key_Return | Qt.ControlModifier, self, - context = Qt.WidgetShortcut, - activated = self._followTag + context=Qt.WidgetShortcut, + activated=self._followTag ) QShortcut( Qt.Key_Enter | Qt.ControlModifier, self, - context = Qt.WidgetShortcut, - activated = self._followTag + context=Qt.WidgetShortcut, + activated=self._followTag ) # Set Up Word Count Thread and Timer @@ -684,7 +687,7 @@ class GuiDocEditor(QTextEdit): the document. Wraps back to the top if not found. """ searchFor = self.theParent.searchBar.getSearchText() - wasFound = self.find(searchFor) + wasFound = self.find(searchFor) if not wasFound: theCursor = self.textCursor() theCursor.movePosition(QTextCursor.Start) diff --git a/nw/gui/elements/doctree.py b/nw/gui/elements/doctree.py index bafa5b48..0f93405a 100644 --- a/nw/gui/elements/doctree.py +++ b/nw/gui/elements/doctree.py @@ -13,13 +13,15 @@ import logging import nw -from PyQt5.QtCore import Qt, QSize -from PyQt5.QtGui import QIcon, QFont, QColor -from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAbstractItemView, QApplication +from PyQt5.QtCore import Qt, QSize +from PyQt5.QtGui import QIcon, QFont, QColor +from PyQt5.QtWidgets import ( + QTreeWidget, QTreeWidgetItem, QAbstractItemView, QApplication +) from nw.project.item import NWItem -from nw.constants import nwLabels -from nw.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert +from nw.constants import nwLabels +from nw.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert logger = logging.getLogger(__name__) diff --git a/nw/gui/elements/docviewer.py b/nw/gui/elements/docviewer.py index 9edd1838..6c6634f0 100644 --- a/nw/gui/elements/docviewer.py +++ b/nw/gui/elements/docviewer.py @@ -13,13 +13,13 @@ import logging import nw -from PyQt5.QtCore import Qt +from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QTextBrowser -from PyQt5.QtGui import QTextOption, QFont, QPalette, QColor +from PyQt5.QtGui import QTextOption, QFont, QPalette, QColor -from nw.convert.tokenizer import Tokenizer +from nw.convert.tokenizer import Tokenizer from nw.convert.text.tohtml import ToHtml -from nw.enum import nwAlert, nwItemType +from nw.enum import nwAlert, nwItemType logger = logging.getLogger(__name__) diff --git a/nw/gui/elements/noticebar.py b/nw/gui/elements/noticebar.py index 17bd512e..37b7f963 100644 --- a/nw/gui/elements/noticebar.py +++ b/nw/gui/elements/noticebar.py @@ -13,8 +13,8 @@ import logging import nw -from PyQt5.QtCore import Qt -from PyQt5.QtGui import QPalette, QColor +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QPalette, QColor from PyQt5.QtWidgets import QFrame, QHBoxLayout, QLabel, QPushButton logger = logging.getLogger(__name__) @@ -36,7 +36,8 @@ class GuiNoticeBar(QFrame): self.mainBox = QHBoxLayout(self) self.mainBox.setContentsMargins(8,2,2,2) - self.noteLabel = QLabel("Hi there!") + self.noteLabel = QLabel("Hi there!") + self.closeButton = QPushButton(self.theTheme.getIcon("close"),"") self.closeButton.clicked.connect(self.hideNote) diff --git a/nw/gui/elements/searchbar.py b/nw/gui/elements/searchbar.py index 8fab6e93..32a520ec 100644 --- a/nw/gui/elements/searchbar.py +++ b/nw/gui/elements/searchbar.py @@ -13,9 +13,11 @@ import logging import nw -from PyQt5.QtCore import Qt -from PyQt5.QtGui import QIcon -from PyQt5.QtWidgets import QFrame, QGridLayout, QLabel, QLineEdit, QPushButton, QApplication +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QIcon +from PyQt5.QtWidgets import ( + QFrame, QGridLayout, QLabel, QLineEdit, QPushButton, QApplication +) from nw.enum import nwDocAction diff --git a/nw/gui/elements/viewdetails.py b/nw/gui/elements/viewdetails.py index 5880d008..05c4be25 100644 --- a/nw/gui/elements/viewdetails.py +++ b/nw/gui/elements/viewdetails.py @@ -13,11 +13,11 @@ import logging import nw -from PyQt5.QtCore import Qt, QSize -from PyQt5.QtGui import QFont +from PyQt5.QtCore import Qt, QSize +from PyQt5.QtGui import QFont from PyQt5.QtWidgets import ( - QWidget, QHBoxLayout, QVBoxLayout, QLabel, QGroupBox, QScrollArea, QFrame, QToolButton, - QSizePolicy, QCheckBox, QGridLayout + QWidget, QHBoxLayout, QVBoxLayout, QLabel, QGroupBox, QScrollArea, QFrame, + QToolButton, QSizePolicy, QCheckBox, QGridLayout ) from nw.constants import nwLabels diff --git a/nw/gui/mainmenu.py b/nw/gui/mainmenu.py index ffa876c5..e46dfd4e 100644 --- a/nw/gui/mainmenu.py +++ b/nw/gui/mainmenu.py @@ -13,8 +13,8 @@ import logging import nw -from PyQt5.QtCore import QUrl -from PyQt5.QtGui import QIcon, QDesktopServices +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 @@ -78,7 +78,9 @@ class GuiMainMenu(QMenuBar): recentProject = self.mainConf.recentList[n] if recentProject == "": continue menuItem = QAction("%s" % recentProject, self.projMenu) - menuItem.triggered.connect(lambda menuItem, n=n : self.openRecentProject(menuItem, n)) + menuItem.triggered.connect( + lambda menuItem, n=n : self.openRecentProject(menuItem, n) + ) self.recentMenu.addAction(menuItem) self.recentMenu.addSeparator() diff --git a/nw/gui/statusbar.py b/nw/gui/statusbar.py index 00170b8c..ef082e2f 100644 --- a/nw/gui/statusbar.py +++ b/nw/gui/statusbar.py @@ -13,9 +13,10 @@ import logging import nw -from time import time -from PyQt5.QtCore import Qt, QTimer -from PyQt5.QtGui import QIcon, QColor, QPixmap +from time import time + +from PyQt5.QtCore import Qt, QTimer +from PyQt5.QtGui import QIcon, QColor, QPixmap from PyQt5.QtWidgets import QStatusBar, QLabel, QFrame logger = logging.getLogger(__name__) diff --git a/nw/gui/tools/dochighlight.py b/nw/gui/tools/dochighlight.py index e356dbf7..02090d94 100644 --- a/nw/gui/tools/dochighlight.py +++ b/nw/gui/tools/dochighlight.py @@ -14,7 +14,9 @@ import logging import nw from PyQt5.QtCore import Qt, QRegularExpression -from PyQt5.QtGui import QColor, QTextCharFormat, QFont, QSyntaxHighlighter, QBrush +from PyQt5.QtGui import ( + QColor, QTextCharFormat, QFont, QSyntaxHighlighter, QBrush +) from nw.constants import nwUnicode @@ -38,18 +40,18 @@ class GuiDocHighlighter(QSyntaxHighlighter): self.hRules = [] self.hStyles = {} - self.colHead = QColor(0,0,0) - self.colHeadH = QColor(0,0,0) - self.colEmph = QColor(0,0,0) - self.colDialN = QColor(0,0,0) - self.colDialD = QColor(0,0,0) - self.colDialS = QColor(0,0,0) - self.colComm = QColor(0,0,0) - self.colKey = QColor(0,0,0) - self.colVal = QColor(0,0,0) - self.colSpell = QColor(0,0,0) - self.colTagErr = QColor(0,0,0) - self.colRepTag = QColor(0,0,0) + self.colHead = QColor(0,0,0) + self.colHeadH = QColor(0,0,0) + self.colEmph = QColor(0,0,0) + self.colDialN = QColor(0,0,0) + self.colDialD = QColor(0,0,0) + self.colDialS = QColor(0,0,0) + self.colComm = QColor(0,0,0) + self.colKey = QColor(0,0,0) + self.colVal = QColor(0,0,0) + self.colSpell = QColor(0,0,0) + self.colTagErr = QColor(0,0,0) + self.colRepTag = QColor(0,0,0) self.initHighlighter() @@ -196,7 +198,7 @@ class GuiDocHighlighter(QSyntaxHighlighter): )) self.hRules.append(( - "<(\S+?)>", { + r"<(\S+?)>", { 0 : self.hStyles["replace"], } )) diff --git a/nw/gui/winmain.py b/nw/gui/winmain.py index 8eedb626..047ccdeb 100644 --- a/nw/gui/winmain.py +++ b/nw/gui/winmain.py @@ -16,37 +16,37 @@ import nw from os import path -from PyQt5.QtCore import Qt, QTimer -from PyQt5.QtGui import QIcon, QPixmap, QColor +from PyQt5.QtCore import Qt, QTimer +from PyQt5.QtGui import QIcon, QPixmap, QColor from PyQt5.QtWidgets import ( qApp, QWidget, QMainWindow, QVBoxLayout, QFrame, QSplitter, QFileDialog, QShortcut, QMessageBox, QProgressDialog, QDialog ) -from nw.gui.mainmenu import GuiMainMenu -from nw.gui.statusbar import GuiMainStatus -from nw.gui.elements.doctree import GuiDocTree -from nw.gui.elements.doceditor import GuiDocEditor -from nw.gui.elements.docviewer import GuiDocViewer -from nw.gui.elements.docdetails import GuiDocDetails -from nw.gui.elements.searchbar import GuiSearchBar -from nw.gui.elements.noticebar import GuiNoticeBar -from nw.gui.elements.viewdetails import GuiDocViewDetails -from nw.gui.dialogs.configeditor import GuiConfigEditor +from nw.gui.mainmenu import GuiMainMenu +from nw.gui.statusbar import GuiMainStatus +from nw.gui.elements.doctree import GuiDocTree +from nw.gui.elements.doceditor import GuiDocEditor +from nw.gui.elements.docviewer import GuiDocViewer +from nw.gui.elements.docdetails import GuiDocDetails +from nw.gui.elements.searchbar import GuiSearchBar +from nw.gui.elements.noticebar import GuiNoticeBar +from nw.gui.elements.viewdetails import GuiDocViewDetails +from nw.gui.dialogs.configeditor import GuiConfigEditor from nw.gui.dialogs.projecteditor import GuiProjectEditor -from nw.gui.dialogs.export import GuiExport -from nw.gui.dialogs.itemeditor import GuiItemEditor -from nw.gui.dialogs.timelineview import GuiTimeLineView -from nw.gui.dialogs.sessionlog import GuiSessionLogView -from nw.project.project import NWProject -from nw.project.document import NWDoc -from nw.project.item import NWItem -from nw.project.index import NWIndex -from nw.project.backup import NWBackup -from nw.tools.wordcount import countWords -from nw.theme import Theme -from nw.enum import nwItemType, nwAlert -from nw.constants import nwFiles +from nw.gui.dialogs.export import GuiExport +from nw.gui.dialogs.itemeditor import GuiItemEditor +from nw.gui.dialogs.timelineview import GuiTimeLineView +from nw.gui.dialogs.sessionlog import GuiSessionLogView +from nw.project.project import NWProject +from nw.project.document import NWDoc +from nw.project.item import NWItem +from nw.project.index import NWIndex +from nw.project.backup import NWBackup +from nw.tools.wordcount import countWords +from nw.theme import Theme +from nw.enum import nwItemType, nwAlert +from nw.constants import nwFiles logger = logging.getLogger(__name__) @@ -168,17 +168,17 @@ class GuiMain(QMainWindow): QShortcut( Qt.Key_Return, self.treeView, - context = Qt.WidgetShortcut, - activated = self._treeKeyPressReturn + context=Qt.WidgetShortcut, + activated=self._treeKeyPressReturn ) QShortcut( Qt.Key_Escape, self, - activated = self._keyPressEscape + activated=self._keyPressEscape ) # Forward Functions - self.setStatus = self.statusBar.setStatus + self.setStatus = self.statusBar.setStatus self.setProjectStatus = self.statusBar.setProjectStatus if self.mainConf.showGUI: @@ -578,7 +578,7 @@ class GuiMain(QMainWindow): dlgOpt |= QFileDialog.ShowDirsOnly dlgOpt |= QFileDialog.DontUseNativeDialog projPath = QFileDialog.getExistingDirectory( - self,"Save novelWriter Project","",options=dlgOpt + self, "Save novelWriter Project", "", options=dlgOpt ) if projPath: return projPath @@ -589,7 +589,7 @@ class GuiMain(QMainWindow): dlgOpt |= QFileDialog.ShowDirsOnly dlgOpt |= QFileDialog.DontUseNativeDialog projPath = QFileDialog.getExistingDirectory( - self,"Select Location for New novelWriter Project","",options=dlgOpt + self, "Select Location for New novelWriter Project", "", options=dlgOpt ) if projPath: return projPath diff --git a/nw/project/backup.py b/nw/project/backup.py index 993c4406..2fdb4112 100644 --- a/nw/project/backup.py +++ b/nw/project/backup.py @@ -13,8 +13,8 @@ import logging import nw -from os import path, mkdir, listdir -from shutil import make_archive +from os import path, mkdir, listdir +from shutil import make_archive from datetime import datetime from nw.enum import nwAlert diff --git a/nw/project/document.py b/nw/project/document.py index 3e807a2b..c6a5e49c 100644 --- a/nw/project/document.py +++ b/nw/project/document.py @@ -103,9 +103,12 @@ class NWDoc(): docTemp = path.join(dataPath,docFile[:-3]+"tmp") docBack = path.join(dataPath,docFile[:-3]+"bak") - if path.isfile(docTemp): unlink(docTemp) - if path.isfile(docBack): rename(docBack,docTemp) - if path.isfile(docPath): rename(docPath,docBack) + if path.isfile(docTemp): + unlink(docTemp) + if path.isfile(docBack): + rename(docBack,docTemp) + if path.isfile(docPath): + rename(docPath,docBack) try: with open(docPath,mode="w",encoding="utf8") as outFile: diff --git a/nw/project/index.py b/nw/project/index.py index d3b62613..59893dc5 100644 --- a/nw/project/index.py +++ b/nw/project/index.py @@ -17,9 +17,9 @@ import nw from os import path from nw.project.document import NWDoc -from nw.enum import nwItemType, nwItemClass, nwItemLayout -from nw.constants import nwFiles, nwKeyWords -from nw.enum import nwAlert +from nw.enum import nwItemType, nwItemClass, nwItemLayout +from nw.constants import nwFiles, nwKeyWords +from nw.enum import nwAlert logger = logging.getLogger(__name__) @@ -62,7 +62,7 @@ class NWIndex(): self.noteIndex = {} # Lists - self.novelList = [] + self.novelList = [] return @@ -101,7 +101,7 @@ class NWIndex(): """Load index from last session from the project meta folder. """ - theData = {} + theData = {} indexFile = path.join(self.theProject.projMeta, nwFiles.INDEX_FILE) if path.isfile(indexFile): logger.debug("Loading index file") @@ -213,11 +213,11 @@ class NWIndex(): # Check file type, and reset its old index if itemClass == nwItemClass.NOVEL: self.novelIndex[tHandle] = [] - self.refIndex[tHandle] = [] + self.refIndex[tHandle] = [] isNovel = True else: self.noteIndex[tHandle] = [] - self.refIndex[tHandle] = [] + self.refIndex[tHandle] = [] isNovel = False # Also clear references to file in tag index @@ -390,7 +390,6 @@ class NWIndex(): def buildNovelList(self): """Build a list of the content of the novel. """ - self.novelList = [] self.novelOrder = [] for tHandle in self.theProject.treeOrder: @@ -399,7 +398,6 @@ class NWIndex(): for tEntry in self.novelIndex[tHandle]: self.novelList.append(tEntry) self.novelOrder.append("%s:%d" % (tHandle,tEntry[0])) - return True def buildReferenceList(self, tHandle): diff --git a/nw/project/item.py b/nw/project/item.py index 9640265b..cae1777b 100644 --- a/nw/project/item.py +++ b/nw/project/item.py @@ -13,11 +13,11 @@ import logging import nw -from os import path, mkdir -from lxml import etree -from datetime import datetime +from os import path, mkdir +from lxml import etree +from datetime import datetime -from nw.enum import nwItemType, nwItemClass, nwItemLayout +from nw.enum import nwItemType, nwItemClass, nwItemLayout from nw.common import checkInt logger = logging.getLogger(__name__) @@ -28,23 +28,23 @@ class NWItem(): def __init__(self, theProject): - self.theProject = theProject + self.theProject = theProject - self.itemName = "" - self.itemHandle = None - self.parHandle = None - self.itemOrder = None - self.itemType = nwItemType.NO_TYPE - self.itemClass = nwItemClass.NO_CLASS - self.itemLayout = nwItemLayout.NO_LAYOUT - self.itemStatus = None - self.isExpanded = False + self.itemName = "" + self.itemHandle = None + self.parHandle = None + self.itemOrder = None + self.itemType = nwItemType.NO_TYPE + self.itemClass = nwItemClass.NO_CLASS + self.itemLayout = nwItemLayout.NO_LAYOUT + self.itemStatus = None + self.isExpanded = False # Document Meta Data - self.charCount = 0 - self.wordCount = 0 - self.paraCount = 0 - self.cursorPos = 0 + self.charCount = 0 + self.wordCount = 0 + self.paraCount = 0 + self.cursorPos = 0 return diff --git a/nw/project/project.py b/nw/project/project.py index a0208885..46c70de8 100644 --- a/nw/project/project.py +++ b/nw/project/project.py @@ -13,18 +13,18 @@ import logging import nw -from os import path, mkdir, listdir -from shutil import copyfile -from lxml import etree -from hashlib import sha256 +from os import path, mkdir, listdir +from shutil import copyfile +from lxml import etree +from hashlib import sha256 from datetime import datetime -from time import time +from time import time -from nw.project.item import NWItem +from nw.project.item import NWItem from nw.project.status import NWStatus -from nw.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert -from nw.common import checkString, checkBool, checkInt -from nw.constants import nwFiles, nwConst +from nw.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert +from nw.common import checkString, checkBool, checkInt +from nw.constants import nwFiles, nwConst logger = logging.getLogger(__name__) @@ -40,18 +40,18 @@ class NWProject(): self.projAltered = None # The project has been altered this session # Debug - self.handleSeed = None + self.handleSeed = None # Class Settings - self.projTree = None # Holds all the items of the project - self.treeOrder = None # The order of the tree items on the tree view - self.treeRoots = None # The root items of the tree - self.trashRoot = None # The handle of the trash root folder - self.projPath = None # The full path to where the currently open project is saved - self.projMeta = None # The full path to the project's meta data folder - self.projCache = None # The full path to the project's cache folder - self.projDict = None # The spell check dictionary - self.projFile = None # The file name of the project main xml file + self.projTree = None # Holds all the items of the project + self.treeOrder = None # The order of the tree items on the tree view + self.treeRoots = None # The root items of the tree + self.trashRoot = None # The handle of the trash root folder + self.projPath = None # The full path to where the currently open project is saved + self.projMeta = None # The full path to the project's meta data folder + self.projCache = None # The full path to the project's cache folder + self.projDict = None # The spell check dictionary + self.projFile = None # The file name of the project main xml file # Project Meta self.projName = None @@ -194,8 +194,10 @@ class NWProject(): self.projCache = path.join(self.projPath,"cache") self.projDict = path.join(self.projMeta, nwFiles.PROJ_DICT) - if not self._checkFolder(self.projMeta): return - if not self._checkFolder(self.projCache): return + if not self._checkFolder(self.projMeta): + return + if not self._checkFolder(self.projCache): + return try: nwXML = etree.parse(fileName) @@ -313,19 +315,19 @@ class NWProject(): }) # Save Project Meta - xProject = etree.SubElement(nwXML,"project") - self._saveProjectValue(xProject,"name", self.projName, True) - self._saveProjectValue(xProject,"title", self.bookTitle, True) - self._saveProjectValue(xProject,"author",self.bookAuthors) - self._saveProjectValue(xProject,"backup",self.doBackup) + xProject = etree.SubElement(nwXML, "project") + self._saveProjectValue(xProject, "name", self.projName, True) + self._saveProjectValue(xProject, "title", self.bookTitle, True) + self._saveProjectValue(xProject, "author", self.bookAuthors) + self._saveProjectValue(xProject, "backup", self.doBackup) # Save Project Settings - xSettings = etree.SubElement(nwXML,"settings") - self._saveProjectValue(xSettings,"spellCheck", self.spellCheck) - self._saveProjectValue(xSettings,"lastEdited", self.lastEdited) - self._saveProjectValue(xSettings,"lastViewed", self.lastViewed) - self._saveProjectValue(xSettings,"lastWordCount",self.currWCount) - xAutoRep = etree.SubElement(xSettings,"autoReplace") + xSettings = etree.SubElement(nwXML, "settings") + self._saveProjectValue(xSettings, "spellCheck", self.spellCheck) + self._saveProjectValue(xSettings, "lastEdited", self.lastEdited) + self._saveProjectValue(xSettings, "lastViewed", self.lastViewed) + self._saveProjectValue(xSettings, "lastWordCount", self.currWCount) + xAutoRep = etree.SubElement(xSettings, "autoReplace") for aKey, aValue in self.autoReplace.items(): if len(aKey) > 0: self._saveProjectValue(xAutoRep,aKey,aValue) @@ -337,7 +339,7 @@ class NWProject(): # Save Tree Content logger.debug("Writing project content") - xContent = etree.SubElement(nwXML,"content",attrib={"count":str(len(self.treeOrder))}) + xContent = etree.SubElement(nwXML, "content", attrib={"count":str(len(self.treeOrder))}) for tHandle in self.treeOrder: self.projTree[tHandle].packXML(xContent) @@ -411,8 +413,8 @@ class NWProject(): return False if self.projName == "": self.theParent.makeAlert(( - "You must set a valid project name in project settings to use " - "the automatic project backup feature." + "You must set a valid project name in project settings to " + "use the automatic project backup feature." ), nwAlert.ERROR) return False self.doBackup = True @@ -699,7 +701,7 @@ class NWProject(): sessionFile = path.join(self.projMeta, nwFiles.SESS_INFO) - with open(sessionFile,mode="a+",encoding="utf8") as outFile: + with open(sessionFile, mode="a+", encoding="utf8") as outFile: print(( "Start: {opened:s} " "End: {closed:s} " @@ -750,8 +752,8 @@ class NWProject(): try: copyfile( - path.join(self.projPath,self.projFile), - path.join(self.projCache,projBackup) + path.join(self.projPath, self.projFile), + path.join(self.projCache, projBackup) ) except: logger.error("Failed to write to file %s" % projBackup) diff --git a/nw/project/status.py b/nw/project/status.py index d3bbb560..de49a03c 100644 --- a/nw/project/status.py +++ b/nw/project/status.py @@ -15,7 +15,7 @@ import nw from lxml import etree -from nw.enum import nwItemClass +from nw.enum import nwItemClass from nw.common import checkInt logger = logging.getLogger(__name__) diff --git a/nw/theme.py b/nw/theme.py index 70d101c6..0b687b17 100644 --- a/nw/theme.py +++ b/nw/theme.py @@ -17,7 +17,7 @@ import nw from os import path, listdir from PyQt5.QtWidgets import qApp -from PyQt5.QtGui import QPalette, QColor, QIcon +from PyQt5.QtGui import QPalette, QColor, QIcon from nw.enum import nwAlert @@ -41,30 +41,30 @@ class Theme: def __init__(self, theParent): - self.mainConf = nw.CONFIG - self.theParent = theParent - self.guiPalette = QPalette() - self.guiPath = "gui" - self.iconPath = "icons" - self.syntaxPath = "syntax" - self.cssName = "style.qss" - self.confName = "theme.conf" - self.themeList = [] - self.syntaxList = [] + self.mainConf = nw.CONFIG + self.theParent = theParent + self.guiPalette = QPalette() + self.guiPath = "gui" + self.iconPath = "icons" + self.syntaxPath = "syntax" + self.cssName = "style.qss" + self.confName = "theme.conf" + self.themeList = [] + self.syntaxList = [] # Loaded Theme Settings ## Theme - self.themeName = "" - self.themeAuthor = "" - self.themeCredit = "" - self.themeUrl = "" + self.themeName = "" + self.themeAuthor = "" + self.themeCredit = "" + self.themeUrl = "" ## GUI - self.treeWCount = [ 0, 0, 0] - self.statNone = [120,120,120] - self.statUnsaved = [120,120, 40] - self.statSaved = [ 40,120, 0] + self.treeWCount = [ 0, 0, 0] + self.statNone = [120,120,120] + self.statUnsaved = [120,120, 40] + self.statSaved = [ 40,120, 0] # Loaded Syntax Settings @@ -75,33 +75,33 @@ class Theme: self.syntaxUrl = "" ## Colours - self.colBack = [255,255,255] - self.colText = [ 0, 0, 0] - self.colLink = [ 0, 0, 0] - self.colHead = [ 0, 0, 0] - self.colHeadH = [ 0, 0, 0] - self.colEmph = [ 0, 0, 0] - self.colDialN = [ 0, 0, 0] - self.colDialD = [ 0, 0, 0] - self.colDialS = [ 0, 0, 0] - self.colComm = [ 0, 0, 0] - self.colKey = [ 0, 0, 0] - self.colVal = [ 0, 0, 0] - self.colSpell = [ 0, 0, 0] - self.colTagErr = [ 0, 0, 0] - self.colRepTag = [ 0, 0, 0] + self.colBack = [255,255,255] + self.colText = [ 0, 0, 0] + self.colLink = [ 0, 0, 0] + self.colHead = [ 0, 0, 0] + self.colHeadH = [ 0, 0, 0] + self.colEmph = [ 0, 0, 0] + self.colDialN = [ 0, 0, 0] + self.colDialD = [ 0, 0, 0] + self.colDialS = [ 0, 0, 0] + self.colComm = [ 0, 0, 0] + self.colKey = [ 0, 0, 0] + self.colVal = [ 0, 0, 0] + self.colSpell = [ 0, 0, 0] + self.colTagErr = [ 0, 0, 0] + self.colRepTag = [ 0, 0, 0] ## Icons - self.themeIcons = {} + self.themeIcons = {} # Changeable Settings - self.guiTheme = None - self.guiSyntax = None - self.themeRoot = None - self.themePath = None - self.syntaxFile = None - self.confFile = None - self.cssFile = None + self.guiTheme = None + self.guiSyntax = None + self.themeRoot = None + self.themePath = None + self.syntaxFile = None + self.confFile = None + self.cssFile = None self.updateTheme() @@ -162,36 +162,36 @@ class Theme: ## Main cnfSec = "Main" if confParser.has_section(cnfSec): - self.themeName = self._parseLine(confParser,cnfSec,"name", "") - self.themeAuthor = self._parseLine(confParser,cnfSec,"author","") - self.themeCredit = self._parseLine(confParser,cnfSec,"credit","") - self.themeUrl = self._parseLine(confParser,cnfSec,"url", "") + self.themeName = self._parseLine( confParser, cnfSec, "name", "") + self.themeAuthor = self._parseLine( confParser, cnfSec, "author", "") + self.themeCredit = self._parseLine( confParser, cnfSec, "credit", "") + self.themeUrl = self._parseLine( confParser, cnfSec, "url", "") ## Palette cnfSec = "Palette" if confParser.has_section(cnfSec): - self._setPalette(confParser,cnfSec,"window", QPalette.Window) - self._setPalette(confParser,cnfSec,"windowtext", QPalette.WindowText) - self._setPalette(confParser,cnfSec,"base", QPalette.Base) - self._setPalette(confParser,cnfSec,"alternatebase", QPalette.AlternateBase) - self._setPalette(confParser,cnfSec,"text", QPalette.Text) - self._setPalette(confParser,cnfSec,"tooltipbase", QPalette.ToolTipBase) - self._setPalette(confParser,cnfSec,"tooltiptext", QPalette.ToolTipText) - self._setPalette(confParser,cnfSec,"button", QPalette.Button) - self._setPalette(confParser,cnfSec,"buttontext", QPalette.ButtonText) - self._setPalette(confParser,cnfSec,"brighttext", QPalette.BrightText) - self._setPalette(confParser,cnfSec,"highlight", QPalette.Highlight) - self._setPalette(confParser,cnfSec,"highlightedtext",QPalette.HighlightedText) - self._setPalette(confParser,cnfSec,"link", QPalette.Link) - self._setPalette(confParser,cnfSec,"linkvisited", QPalette.LinkVisited) + self._setPalette(confParser, cnfSec, "window", QPalette.Window) + self._setPalette(confParser, cnfSec, "windowtext", QPalette.WindowText) + self._setPalette(confParser, cnfSec, "base", QPalette.Base) + self._setPalette(confParser, cnfSec, "alternatebase", QPalette.AlternateBase) + self._setPalette(confParser, cnfSec, "text", QPalette.Text) + self._setPalette(confParser, cnfSec, "tooltipbase", QPalette.ToolTipBase) + self._setPalette(confParser, cnfSec, "tooltiptext", QPalette.ToolTipText) + self._setPalette(confParser, cnfSec, "button", QPalette.Button) + self._setPalette(confParser, cnfSec, "buttontext", QPalette.ButtonText) + self._setPalette(confParser, cnfSec, "brighttext", QPalette.BrightText) + self._setPalette(confParser, cnfSec, "highlight", QPalette.Highlight) + self._setPalette(confParser, cnfSec, "highlightedtext", QPalette.HighlightedText) + self._setPalette(confParser, cnfSec, "link", QPalette.Link) + self._setPalette(confParser, cnfSec, "linkvisited", QPalette.LinkVisited) ## GUI cnfSec = "GUI" if confParser.has_section(cnfSec): - self.treeWCount = self._loadColour(confParser,cnfSec,"treewordcount") - self.statNone = self._loadColour(confParser,cnfSec,"statusnone") - self.statUnsaved = self._loadColour(confParser,cnfSec,"statusunsaved") - self.statSaved = self._loadColour(confParser,cnfSec,"statussaved") + self.treeWCount = self._loadColour(confParser, cnfSec, "treewordcount") + self.statNone = self._loadColour(confParser, cnfSec, "statusnone") + self.statUnsaved = self._loadColour(confParser, cnfSec, "statusunsaved") + self.statSaved = self._loadColour(confParser, cnfSec, "statussaved") # Apply Styles qApp.setStyleSheet(cssData) @@ -205,7 +205,7 @@ class Theme: confParser = configparser.ConfigParser() try: - confParser.read_file(open(self.syntaxFile,mode="r",encoding="utf8")) + confParser.read_file(open(self.syntaxFile, mode="r", encoding="utf8")) except Exception as e: logger.error("Could not load syntax colours from: %s" % self.syntaxFile) return False @@ -213,29 +213,29 @@ class Theme: ## Main cnfSec = "Main" if confParser.has_section(cnfSec): - self.syntaxName = self._parseLine(confParser,cnfSec,"name","") - self.syntaxAuthor = self._parseLine(confParser,cnfSec,"author","") - self.syntaxCredit = self._parseLine(confParser,cnfSec,"credit","") - self.syntaxUrl = self._parseLine(confParser,cnfSec,"url", "") + self.syntaxName = self._parseLine(confParser, cnfSec, "name", "") + self.syntaxAuthor = self._parseLine(confParser, cnfSec, "author", "") + self.syntaxCredit = self._parseLine(confParser, cnfSec, "credit", "") + self.syntaxUrl = self._parseLine(confParser, cnfSec, "url", "") ## Syntax cnfSec = "Syntax" if confParser.has_section(cnfSec): - self.colBack = self._loadColour(confParser,cnfSec,"background") - self.colText = self._loadColour(confParser,cnfSec,"text") - self.colLink = self._loadColour(confParser,cnfSec,"link") - self.colHead = self._loadColour(confParser,cnfSec,"headertext") - self.colHeadH = self._loadColour(confParser,cnfSec,"headertag") - self.colEmph = self._loadColour(confParser,cnfSec,"emphasis") - self.colDialN = self._loadColour(confParser,cnfSec,"straightquotes") - self.colDialD = self._loadColour(confParser,cnfSec,"doublequotes") - self.colDialS = self._loadColour(confParser,cnfSec,"singlequotes") - self.colComm = self._loadColour(confParser,cnfSec,"hidden") - self.colKey = self._loadColour(confParser,cnfSec,"keyword") - self.colVal = self._loadColour(confParser,cnfSec,"value") - self.colSpell = self._loadColour(confParser,cnfSec,"spellcheckline") - self.colTagErr = self._loadColour(confParser,cnfSec,"tagerror") - self.colRepTag = self._loadColour(confParser,cnfSec,"replacetag") + self.colBack = self._loadColour(confParser, cnfSec, "background") + self.colText = self._loadColour(confParser, cnfSec, "text") + self.colLink = self._loadColour(confParser, cnfSec, "link") + self.colHead = self._loadColour(confParser, cnfSec, "headertext") + self.colHeadH = self._loadColour(confParser, cnfSec, "headertag") + self.colEmph = self._loadColour(confParser, cnfSec, "emphasis") + self.colDialN = self._loadColour(confParser, cnfSec, "straightquotes") + self.colDialD = self._loadColour(confParser, cnfSec, "doublequotes") + self.colDialS = self._loadColour(confParser, cnfSec, "singlequotes") + self.colComm = self._loadColour(confParser, cnfSec, "hidden") + self.colKey = self._loadColour(confParser, cnfSec, "keyword") + self.colVal = self._loadColour(confParser, cnfSec, "value") + self.colSpell = self._loadColour(confParser, cnfSec, "spellcheckline") + self.colTagErr = self._loadColour(confParser, cnfSec, "tagerror") + self.colRepTag = self._loadColour(confParser, cnfSec, "replacetag") logger.info("Loaded syntax theme '%s'" % self.guiSyntax) @@ -251,7 +251,7 @@ class Theme: themeConf = path.join(self.mainConf.themeRoot, self.guiPath, themeDir, self.confName) logger.verbose("Checking theme config for '%s'" % themeDir) try: - confParser.read_file(open(themeConf,mode="r",encoding="utf8")) + confParser.read_file(open(themeConf, mode="r", encoding="utf8")) except Exception as e: self.theParent.makeAlert(["Could not load theme config file",str(e)],nwAlert.ERROR) continue @@ -279,7 +279,7 @@ class Theme: continue logger.verbose("Checking theme syntax for '%s'" % syntaxFile) try: - confParser.read_file(open(syntaxPath,mode="r",encoding="utf8")) + confParser.read_file(open(syntaxPath, mode="r", encoding="utf8")) except Exception as e: self.theParent.makeAlert(["Could not load syntax file",str(e)],nwAlert.ERROR) return [] diff --git a/nw/tools/analyse.py b/nw/tools/analyse.py index bb847d74..e0866526 100644 --- a/nw/tools/analyse.py +++ b/nw/tools/analyse.py @@ -130,8 +130,8 @@ class TextAnalysis(): else: cleanText += " " - asVow = "aeiouy'’" - dExept = ("ei","ie","ua","ia","eo") + asVow = "aeiouy'’" + dExept = ("ei","ie","ua","ia","eo") theWords = cleanText.lower().split() allSylls = 0 for inWord in theWords: diff --git a/nw/tools/wordcount.py b/nw/tools/wordcount.py index d6fad51a..4ce7cc1e 100644 --- a/nw/tools/wordcount.py +++ b/nw/tools/wordcount.py @@ -34,7 +34,7 @@ def countWords(theText): if aLine[0] == "@" or aLine[0] == "%": continue - if aLine[0:5] == "#### ": + if aLine[0:5] == "#### ": wordCount -= 1 charCount -= 5 countPara = False From be7b69dc9ab51e06864746ad7c34c4f9e7073382 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 3 Nov 2019 18:06:24 +0100 Subject: [PATCH 8/8] Updated style file --- docs/markdown/style.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/markdown/style.md b/docs/markdown/style.md index 3ae03093..fd1a2d7b 100644 --- a/docs/markdown/style.md +++ b/docs/markdown/style.md @@ -7,10 +7,12 @@ The source code of novelWriter broadly follows the style guide [PEP8](https://ww * Methods are camelCase, not underscore based. The reason is partially because of the maintainers personal preference, and partially because that is what Qt5 and PyQt5 uses. The maintainer generally, across multiple programming languages, uses underscores for defining namespaces. -* The maximum length of a code line is 100 characters, not 79. +* The maximum length of a code line is 99 characters, not 79. The reason for this is that novelWriter is almost entirely made up of classes, meaning nearly all lines of code already have 8 leading spaces. A 79 character limitation is too strict, and causes too many wrapped lines. - 100 characters is suitable for GitHub diff readability, and therefore the preferred limit. + 99 characters is suitable for GitHub diff readability, and therefore the preferred limit. + It is also permitted under PEP8 as the maximum. + Comments and docstrings should comply with the 72 character limit. * Aligning code with additional spaces is acceptable in those cases where it improves readability. Otherwise, the PEP8 standard should be applied.