From 94c95d6f678f7e57abd47d27fffb02446bdb56db Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 8 Aug 2023 14:35:55 +0200
Subject: [PATCH 01/10] Move GUI theme instance to the config object (after app
creation)
---
novelwriter/config.py | 22 +++++-
novelwriter/dialogs/about.py | 27 ++++---
novelwriter/dialogs/docmerge.py | 7 +-
novelwriter/dialogs/docsplit.py | 5 +-
novelwriter/dialogs/preferences.py | 47 ++++--------
novelwriter/dialogs/projdetails.py | 10 ++-
novelwriter/dialogs/projload.py | 11 ++-
novelwriter/dialogs/projsettings.py | 18 +++--
novelwriter/dialogs/updates.py | 5 +-
novelwriter/dialogs/wordlist.py | 5 +-
novelwriter/gui/components.py | 4 +-
novelwriter/gui/doceditor.py | 82 ++++++++++-----------
novelwriter/gui/dochighlight.py | 29 ++++----
novelwriter/gui/docviewer.py | 104 +++++++++++++--------------
novelwriter/gui/itemdetails.py | 19 +++--
novelwriter/gui/noveltree.py | 18 +++--
novelwriter/gui/outline.py | 27 ++++---
novelwriter/gui/projtree.py | 34 +++++----
novelwriter/gui/sidebar.py | 21 +++---
novelwriter/gui/statusbar.py | 21 +++---
novelwriter/guimain.py | 16 ++---
novelwriter/tools/lipsum.py | 5 +-
novelwriter/tools/manusbuild.py | 11 ++-
novelwriter/tools/manuscript.py | 18 +++--
novelwriter/tools/manussettings.py | 71 ++++++++----------
novelwriter/tools/projwizard.py | 21 ++----
novelwriter/tools/writingstats.py | 27 ++++---
sample/nwProject.nwx | 4 +-
tests/test_dialogs/test_dlg_about.py | 2 -
tests/test_gui/test_gui_theme.py | 18 ++---
30 files changed, 319 insertions(+), 390 deletions(-)
diff --git a/novelwriter/config.py b/novelwriter/config.py
index 6bb94e52..9c96e1be 100644
--- a/novelwriter/config.py
+++ b/novelwriter/config.py
@@ -28,6 +28,7 @@ import json
import logging
from time import time
+from typing import TYPE_CHECKING
from pathlib import Path
from PyQt5.QtGui import QFontDatabase
@@ -40,6 +41,9 @@ from novelwriter.error import logException, formatException
from novelwriter.common import checkPath, formatTimeStamp, NWConfigParser
from novelwriter.constants import nwFiles, nwUnicode
+if TYPE_CHECKING: # pragma: no cover
+ from novelwriter.gui.theme import GuiTheme
+
logger = logging.getLogger(__name__)
@@ -90,7 +94,8 @@ class Config:
# User Settings
# =============
- self._recentProj = RecentProjects(self)
+ self._theme = None
+ self._recent = RecentProjects(self)
# General GUI Settings
self.guiLocale = self._qLocale.name()
@@ -233,7 +238,13 @@ class Config:
@property
def recentProjects(self):
- return self._recentProj
+ return self._recent
+
+ @property
+ def theme(self) -> GuiTheme:
+ if self._theme is None:
+ raise Exception("Cannot access GUI theme before it is initialised")
+ return self._theme
@property
def mainWinSize(self):
@@ -282,6 +293,11 @@ class Config:
# Setters
##
+ def setThemeInstance(self, theme: GuiTheme) -> None:
+ """Set the applications theme instance."""
+ self._theme = theme
+ return
+
def setMainWinSize(self, newWidth, newHeight):
"""Set the size of the main window, but only if the change is
larger than 5 pixels. The OS window manager will sometimes
@@ -479,7 +495,7 @@ class Config:
else:
self.saveConfig()
- self._recentProj.loadCache()
+ self._recent.loadCache()
self._checkOptionalPackages()
logger.debug("Config initialisation complete")
diff --git a/novelwriter/dialogs/about.py b/novelwriter/dialogs/about.py
index 36b8bc99..7907882f 100644
--- a/novelwriter/dialogs/about.py
+++ b/novelwriter/dialogs/about.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI About Box
===========================
-The about novelWriter dialog box
File History:
Created: 2020-05-21 [0.5.2]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
import novelwriter
@@ -31,8 +31,8 @@ from datetime import datetime
from PyQt5.QtGui import QCursor
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
- qApp, QDialog, QHBoxLayout, QVBoxLayout, QDialogButtonBox, QTabWidget,
- QTextBrowser, QLabel
+ qApp, QDialog, QDialogButtonBox, QHBoxLayout, QLabel, QTabWidget,
+ QTextBrowser, QVBoxLayout, QWidget
)
from novelwriter import CONFIG
@@ -44,15 +44,12 @@ logger = logging.getLogger(__name__)
class GuiAbout(QDialog):
- def __init__(self, mainGui):
- super().__init__(parent=mainGui)
+ def __init__(self, parent: QWidget):
+ super().__init__(parent=parent)
logger.debug("Create: GuiAbout")
self.setObjectName("GuiAbout")
- self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
-
self.outerBox = QVBoxLayout()
self.innerBox = QHBoxLayout()
self.innerBox.setSpacing(CONFIG.pxInt(16))
@@ -63,7 +60,7 @@ class GuiAbout(QDialog):
nPx = CONFIG.pxInt(96)
self.nwIcon = QLabel()
- self.nwIcon.setPixmap(self.mainGui.mainTheme.getPixmap("novelwriter", (nPx, nPx)))
+ self.nwIcon.setPixmap(CONFIG.theme.getPixmap("novelwriter", (nPx, nPx)))
self.lblName = QLabel("novelWriter")
self.lblVers = QLabel(f"v{novelwriter.__version__}")
self.lblDate = QLabel(datetime.strptime(novelwriter.__date__, "%Y-%m-%d").strftime("%x"))
@@ -231,12 +228,12 @@ class GuiAbout(QDialog):
" color: rgb({kColR},{kColG},{kColB});"
"}}\n"
).format(
- hColR=self.mainGui.mainTheme.colHead[0],
- hColG=self.mainGui.mainTheme.colHead[1],
- hColB=self.mainGui.mainTheme.colHead[2],
- kColR=self.mainTheme.colKey[0],
- kColG=self.mainTheme.colKey[1],
- kColB=self.mainTheme.colKey[2],
+ hColR=CONFIG.theme.colHead[0],
+ hColG=CONFIG.theme.colHead[1],
+ hColB=CONFIG.theme.colHead[2],
+ kColR=CONFIG.theme.colKey[0],
+ kColG=CONFIG.theme.colKey[1],
+ kColB=CONFIG.theme.colKey[2],
)
self.pageAbout.document().setDefaultStyleSheet(styleSheet)
self.pageNotes.document().setDefaultStyleSheet(styleSheet)
diff --git a/novelwriter/dialogs/docmerge.py b/novelwriter/dialogs/docmerge.py
index 49e3d5f1..a7b3630b 100644
--- a/novelwriter/dialogs/docmerge.py
+++ b/novelwriter/dialogs/docmerge.py
@@ -50,7 +50,6 @@ class GuiDocMerge(QDialog):
self.setObjectName("GuiDocMerge")
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self._data = {}
@@ -60,9 +59,9 @@ class GuiDocMerge(QDialog):
self.headLabel = QLabel("{0}".format(self.tr("Documents to Merge")))
self.helpLabel = NHelpLabel(self.tr(
"Drag and drop items to change the order, or uncheck to exclude."
- ), self.mainTheme.helpText)
+ ), CONFIG.theme.helpText)
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
hSp = CONFIG.pxInt(12)
vSp = CONFIG.pxInt(8)
bSp = CONFIG.pxInt(12)
@@ -161,7 +160,7 @@ class GuiDocMerge(QDialog):
if nwItem is None or not nwItem.isFileType():
continue
- itemIcon = self.mainTheme.getItemIcon(
+ itemIcon = CONFIG.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, nwItem.mainHeading
)
diff --git a/novelwriter/dialogs/docsplit.py b/novelwriter/dialogs/docsplit.py
index 58396879..a87658d9 100644
--- a/novelwriter/dialogs/docsplit.py
+++ b/novelwriter/dialogs/docsplit.py
@@ -52,7 +52,6 @@ class GuiDocSplit(QDialog):
self.setObjectName("GuiDocSplit")
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self._data = {}
@@ -63,11 +62,11 @@ class GuiDocSplit(QDialog):
self.headLabel = QLabel("{0}".format(self.tr("Document Headers")))
self.helpLabel = NHelpLabel(
self.tr("Select the maximum level to split into files."),
- self.mainGui.mainTheme.helpText
+ CONFIG.theme.helpText
)
# Values
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
hSp = CONFIG.pxInt(12)
vSp = CONFIG.pxInt(8)
bSp = CONFIG.pxInt(12)
diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py
index 9878ad51..d4c9819d 100644
--- a/novelwriter/dialogs/preferences.py
+++ b/novelwriter/dialogs/preferences.py
@@ -160,13 +160,11 @@ class GuiPreferencesGeneral(QWidget):
def __init__(self, prefsGui):
super().__init__(parent=prefsGui)
- self.prefsGui = prefsGui
- self.mainGui = prefsGui.mainGui
- self.mainTheme = prefsGui.mainGui.mainTheme
+ self.prefsGui = prefsGui
# The Form
self.mainForm = NConfigLayout()
- self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
+ self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
self.setLayout(self.mainForm)
# Look and Feel
@@ -193,7 +191,7 @@ class GuiPreferencesGeneral(QWidget):
# Select Theme
self.guiTheme = QComboBox()
self.guiTheme.setMinimumWidth(minWidth)
- self.theThemes = self.mainTheme.listThemes()
+ self.theThemes = CONFIG.theme.listThemes()
for themeDir, themeName in self.theThemes:
self.guiTheme.addItem(themeName, themeDir)
themeIdx = self.guiTheme.findData(CONFIG.guiTheme)
@@ -209,7 +207,7 @@ class GuiPreferencesGeneral(QWidget):
# Editor Theme
self.guiSyntax = QComboBox()
self.guiSyntax.setMinimumWidth(CONFIG.pxInt(200))
- self.theSyntaxes = self.mainTheme.listSyntax()
+ self.theSyntaxes = CONFIG.theme.listSyntax()
for syntaxFile, syntaxName in self.theSyntaxes:
self.guiSyntax.addItem(syntaxName, syntaxFile)
syntaxIdx = self.guiSyntax.findData(CONFIG.guiSyntax)
@@ -228,7 +226,7 @@ class GuiPreferencesGeneral(QWidget):
self.guiFont.setFixedWidth(CONFIG.pxInt(162))
self.guiFont.setText(CONFIG.guiFont)
self.fontButton = QPushButton("...")
- self.fontButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
+ self.fontButton.setMaximumWidth(int(2.5*CONFIG.theme.getTextWidth("...")))
self.fontButton.clicked.connect(self._selectFont)
self.mainForm.addRow(
self.tr("Font family"),
@@ -342,12 +340,9 @@ class GuiPreferencesProjects(QWidget):
def __init__(self, prefsGui):
super().__init__(parent=prefsGui)
- self.mainGui = prefsGui.mainGui
- self.mainTheme = prefsGui.mainGui.mainTheme
-
# The Form
self.mainForm = NConfigLayout()
- self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
+ self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
self.setLayout(self.mainForm)
# Automatic Save
@@ -497,12 +492,9 @@ class GuiPreferencesDocuments(QWidget):
def __init__(self, prefsGui):
super().__init__(parent=prefsGui)
- self.mainGui = prefsGui.mainGui
- self.mainTheme = prefsGui.mainGui.mainTheme
-
# The Form
self.mainForm = NConfigLayout()
- self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
+ self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
self.setLayout(self.mainForm)
# Text Style
@@ -515,7 +507,7 @@ class GuiPreferencesDocuments(QWidget):
self.textFont.setFixedWidth(CONFIG.pxInt(162))
self.textFont.setText(CONFIG.textFont)
self.fontButton = QPushButton("...")
- self.fontButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
+ self.fontButton.setMaximumWidth(int(2.5*CONFIG.theme.getTextWidth("...")))
self.fontButton.clicked.connect(self._selectFont)
self.mainForm.addRow(
self.tr("Font family"),
@@ -654,12 +646,11 @@ class GuiPreferencesEditor(QWidget):
def __init__(self, prefsGui):
super().__init__(parent=prefsGui)
- self.mainGui = prefsGui.mainGui
- self.mainTheme = prefsGui.mainGui.mainTheme
+ self.mainGui = prefsGui.mainGui
# The Form
self.mainForm = NConfigLayout()
- self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
+ self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
self.setLayout(self.mainForm)
mW = CONFIG.pxInt(250)
@@ -825,13 +816,11 @@ class GuiPreferencesSyntax(QWidget):
def __init__(self, prefsGui):
super().__init__(parent=prefsGui)
- self.prefsGui = prefsGui
- self.mainGui = prefsGui.mainGui
- self.mainTheme = prefsGui.mainGui.mainTheme
+ self.prefsGui = prefsGui
# The Form
self.mainForm = NConfigLayout()
- self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
+ self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
self.setLayout(self.mainForm)
# Quotes & Dialogue
@@ -931,12 +920,9 @@ class GuiPreferencesAutomation(QWidget):
def __init__(self, prefsGui):
super().__init__(parent=prefsGui)
- self.mainGui = prefsGui.mainGui
- self.mainTheme = prefsGui.mainGui.mainTheme
-
# The Form
self.mainForm = NConfigLayout()
- self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
+ self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
self.setLayout(self.mainForm)
# Automatic Features
@@ -1085,12 +1071,9 @@ class GuiPreferencesQuotes(QWidget):
def __init__(self, prefsGui):
super().__init__(parent=prefsGui)
- self.mainGui = prefsGui.mainGui
- self.mainTheme = prefsGui.mainGui.mainTheme
-
# The Form
self.mainForm = NConfigLayout()
- self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
+ self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
self.setLayout(self.mainForm)
# Quotation Style
@@ -1098,7 +1081,7 @@ class GuiPreferencesQuotes(QWidget):
self.mainForm.addGroupLabel(self.tr("Quotation Style"))
qWidth = CONFIG.pxInt(40)
- bWidth = int(2.5*self.mainTheme.getTextWidth("..."))
+ bWidth = int(2.5*CONFIG.theme.getTextWidth("..."))
self.quoteSym = {}
# Single Quote Style
diff --git a/novelwriter/dialogs/projdetails.py b/novelwriter/dialogs/projdetails.py
index e4960b57..b28d0d8f 100644
--- a/novelwriter/dialogs/projdetails.py
+++ b/novelwriter/dialogs/projdetails.py
@@ -149,10 +149,9 @@ class GuiProjectDetailsMain(QWidget):
self.theProject = theProject
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
- fPx = self.mainTheme.fontPixelSize
- fPt = self.mainTheme.fontPointSize
+ fPx = CONFIG.theme.fontPixelSize
+ fPt = CONFIG.theme.fontPointSize
vPx = CONFIG.pxInt(4)
hPx = CONFIG.pxInt(12)
@@ -282,13 +281,12 @@ class GuiProjectDetailsContents(QWidget):
self.theProject = theProject
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
# Internal
self._theToC = []
self._currentRoot = None
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
hPx = CONFIG.pxInt(12)
vPx = CONFIG.pxInt(4)
pOptions = self.theProject.options
@@ -500,7 +498,7 @@ class GuiProjectDetailsContents(QWidget):
progPage = f"{cPage:n}"
progText = f"{pgProg:.1f}{nwUnicode.U_THSP}%"
- hDec = self.mainTheme.getHeaderDecoration(tLevel)
+ hDec = CONFIG.theme.getHeaderDecoration(tLevel)
if tTitle.strip() == "":
tTitle = self.tr("Untitled")
diff --git a/novelwriter/dialogs/projload.py b/novelwriter/dialogs/projload.py
index 916ca820..f88e7130 100644
--- a/novelwriter/dialogs/projload.py
+++ b/novelwriter/dialogs/projload.py
@@ -62,13 +62,12 @@ class GuiProjectLoad(QDialog):
self.setObjectName("GuiProjectLoad")
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
self.openState = self.NONE_STATE
self.openPath = None
sPx = CONFIG.pxInt(16)
nPx = CONFIG.pxInt(96)
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
self.outerBox = QVBoxLayout()
self.innerBox = QHBoxLayout()
@@ -80,7 +79,7 @@ class GuiProjectLoad(QDialog):
self.setMinimumHeight(CONFIG.pxInt(400))
self.nwIcon = QLabel()
- self.nwIcon.setPixmap(self.mainGui.mainTheme.getPixmap("novelwriter", (nPx, nPx)))
+ self.nwIcon.setPixmap(CONFIG.theme.getPixmap("novelwriter", (nPx, nPx)))
self.innerBox.addWidget(self.nwIcon, 0, Qt.AlignTop)
self.projectForm = QGridLayout()
@@ -110,7 +109,7 @@ class GuiProjectLoad(QDialog):
self.selPath.setReadOnly(True)
self.browseButton = QPushButton("...")
- self.browseButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
+ self.browseButton.setMaximumWidth(int(2.5*CONFIG.theme.getTextWidth("...")))
self.browseButton.clicked.connect(self._doBrowse)
self.projectForm.addWidget(self.lblRecent, 0, 0, 1, 3)
@@ -268,7 +267,7 @@ class GuiProjectLoad(QDialog):
self.listBox.clear()
dataList = CONFIG.recentProjects.listEntries()
sortList = sorted(dataList, key=lambda x: x[3], reverse=True)
- nwxIcon = self.mainGui.mainTheme.getIcon("proj_nwx")
+ nwxIcon = CONFIG.theme.getIcon("proj_nwx")
for path, title, words, time in sortList:
newItem = QTreeWidgetItem([""]*4)
newItem.setIcon(self.C_NAME, nwxIcon)
@@ -279,7 +278,7 @@ class GuiProjectLoad(QDialog):
newItem.setTextAlignment(self.C_NAME, Qt.AlignLeft | Qt.AlignVCenter)
newItem.setTextAlignment(self.C_COUNT, Qt.AlignRight | Qt.AlignVCenter)
newItem.setTextAlignment(self.C_TIME, Qt.AlignRight | Qt.AlignVCenter)
- newItem.setFont(self.C_TIME, self.mainTheme.guiFontFixed)
+ newItem.setFont(self.C_TIME, CONFIG.theme.guiFontFixed)
self.listBox.addTopLevelItem(newItem)
if self.listBox.topLevelItemCount() > 0:
diff --git a/novelwriter/dialogs/projsettings.py b/novelwriter/dialogs/projsettings.py
index a639f42c..cd9c8e00 100644
--- a/novelwriter/dialogs/projsettings.py
+++ b/novelwriter/dialogs/projsettings.py
@@ -206,7 +206,7 @@ class GuiProjectEditMain(QWidget):
# The Form
self.mainForm = NConfigLayout()
- self.mainForm.setHelpTextStyle(self.mainGui.mainTheme.helpText)
+ self.mainForm.setHelpTextStyle(CONFIG.theme.helpText)
self.setLayout(self.mainForm)
self.mainForm.addGroupLabel(self.tr("Project Settings"))
@@ -291,7 +291,6 @@ class GuiProjectEditStatus(QWidget):
self.mainGui = projGui.mainGui
self.theProject = projGui.theProject
- self.mainTheme = projGui.mainGui.mainTheme
if isStatus:
self.theStatus = self.theProject.data.itemStatus
@@ -310,7 +309,7 @@ class GuiProjectEditStatus(QWidget):
self.colChanged = False
self.selColour = QColor(100, 100, 100)
- self.iPx = self.mainTheme.baseIconSize
+ self.iPx = CONFIG.theme.baseIconSize
# The List
# ========
@@ -329,16 +328,16 @@ class GuiProjectEditStatus(QWidget):
# List Controls
# =============
- self.addButton = QPushButton(self.mainTheme.getIcon("add"), "")
+ self.addButton = QPushButton(CONFIG.theme.getIcon("add"), "")
self.addButton.clicked.connect(self._newItem)
- self.delButton = QPushButton(self.mainTheme.getIcon("remove"), "")
+ self.delButton = QPushButton(CONFIG.theme.getIcon("remove"), "")
self.delButton.clicked.connect(self._delItem)
- self.upButton = QPushButton(self.mainTheme.getIcon("up"), "")
+ self.upButton = QPushButton(CONFIG.theme.getIcon("up"), "")
self.upButton.clicked.connect(lambda: self._moveItem(-1))
- self.dnButton = QPushButton(self.mainTheme.getIcon("down"), "")
+ self.dnButton = QPushButton(CONFIG.theme.getIcon("down"), "")
self.dnButton.clicked.connect(lambda: self._moveItem(1))
# Edit Form
@@ -578,7 +577,6 @@ class GuiProjectEditReplace(QWidget):
super().__init__(parent=projGui)
self.mainGui = projGui.mainGui
- self.mainTheme = projGui.mainGui.mainTheme
self.theProject = projGui.theProject
self.arChanged = False
@@ -609,10 +607,10 @@ class GuiProjectEditReplace(QWidget):
# List Controls
# =============
- self.addButton = QPushButton(self.mainTheme.getIcon("add"), "")
+ self.addButton = QPushButton(CONFIG.theme.getIcon("add"), "")
self.addButton.clicked.connect(self._addEntry)
- self.delButton = QPushButton(self.mainTheme.getIcon("remove"), "")
+ self.delButton = QPushButton(CONFIG.theme.getIcon("remove"), "")
self.delButton.clicked.connect(self._delEntry)
# Edit Form
diff --git a/novelwriter/dialogs/updates.py b/novelwriter/dialogs/updates.py
index 4b8afad1..c40cb5a4 100644
--- a/novelwriter/dialogs/updates.py
+++ b/novelwriter/dialogs/updates.py
@@ -49,9 +49,6 @@ class GuiUpdates(QDialog):
logger.debug("Create: GuiUpdates")
self.setObjectName("GuiUpdates")
-
- self.mainGui = mainGui
-
self.setWindowTitle(self.tr("Check for Updates"))
nPx = CONFIG.pxInt(96)
@@ -61,7 +58,7 @@ class GuiUpdates(QDialog):
# Left Box
self.nwIcon = QLabel()
- self.nwIcon.setPixmap(self.mainGui.mainTheme.getPixmap("novelwriter", (nPx, nPx)))
+ self.nwIcon.setPixmap(CONFIG.theme.getPixmap("novelwriter", (nPx, nPx)))
self.leftBox = QVBoxLayout()
self.leftBox.addWidget(self.nwIcon)
diff --git a/novelwriter/dialogs/wordlist.py b/novelwriter/dialogs/wordlist.py
index 9f807162..faeefb41 100644
--- a/novelwriter/dialogs/wordlist.py
+++ b/novelwriter/dialogs/wordlist.py
@@ -52,7 +52,6 @@ class GuiWordList(QDialog):
self.setObjectName("GuiWordList")
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self.setWindowTitle(self.tr("Project Word List"))
@@ -80,10 +79,10 @@ class GuiWordList(QDialog):
self.newEntry = QLineEdit()
- self.addButton = QPushButton(self.mainTheme.getIcon("add"), "")
+ self.addButton = QPushButton(CONFIG.theme.getIcon("add"), "")
self.addButton.clicked.connect(self._doAdd)
- self.delButton = QPushButton(self.mainTheme.getIcon("remove"), "")
+ self.delButton = QPushButton(CONFIG.theme.getIcon("remove"), "")
self.delButton.clicked.connect(self._doDelete)
self.editBox = QHBoxLayout()
diff --git a/novelwriter/gui/components.py b/novelwriter/gui/components.py
index 3556ae9c..fe73cb5a 100644
--- a/novelwriter/gui/components.py
+++ b/novelwriter/gui/components.py
@@ -30,6 +30,7 @@ from PyQt5.QtGui import QPainter
from PyQt5.QtCore import pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QAbstractButton, QComboBox
+from novelwriter import CONFIG
from novelwriter.enum import nwItemClass
from novelwriter.constants import nwLabels
@@ -45,7 +46,6 @@ class NovelSelector(QComboBox):
self._mainGui = mainGui
self._project = project
- self._theme = mainGui.mainTheme
self._blockSignal = False
self._firstHandle = None
@@ -89,7 +89,7 @@ class NovelSelector(QComboBox):
self._firstHandle = None
self.clear()
- icon = self._theme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL])
+ icon = CONFIG.theme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL])
handle = self.currentData()
for tHandle, nwItem in self._project.tree.iterRoots(nwItemClass.NOVEL):
if prefix:
diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py
index 9734bc45..ac1cc0cf 100644
--- a/novelwriter/gui/doceditor.py
+++ b/novelwriter/gui/doceditor.py
@@ -85,7 +85,6 @@ class GuiDocEditor(QTextEdit):
# Class Variables
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self._nwDocument = None
@@ -229,14 +228,14 @@ class GuiDocEditor(QTextEdit):
"""Update the syntax highlighting theme.
"""
mainPalette = self.palette()
- mainPalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
- mainPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
- mainPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
+ mainPalette.setColor(QPalette.Window, QColor(*CONFIG.theme.colBack))
+ mainPalette.setColor(QPalette.Base, QColor(*CONFIG.theme.colBack))
+ mainPalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
self.setPalette(mainPalette)
docPalette = self.viewport().palette()
- docPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
- docPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
+ docPalette.setColor(QPalette.Base, QColor(*CONFIG.theme.colBack))
+ docPalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
self.viewport().setPalette(docPalette)
self.docHeader.matchColours()
@@ -2226,7 +2225,6 @@ class GuiDocEditSearch(QFrame):
self.docEditor = docEditor
self.mainGui = docEditor.mainGui
self.theProject = docEditor.theProject
- self.mainTheme = docEditor.mainTheme
self.repVisible = False
self.isCaseSense = CONFIG.searchCase
@@ -2237,9 +2235,9 @@ class GuiDocEditSearch(QFrame):
self.doMatchCap = CONFIG.searchMatchCap
mPx = CONFIG.pxInt(6)
- tPx = int(0.8*self.mainTheme.fontPixelSize)
- self.boxFont = self.mainTheme.guiFont
- self.boxFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
+ tPx = int(0.8*CONFIG.theme.fontPixelSize)
+ self.boxFont = CONFIG.theme.guiFont
+ self.boxFont.setPointSizeF(0.9*CONFIG.theme.fontPointSize)
self.setContentsMargins(0, 0, 0, 0)
self.setAutoFillBackground(True)
@@ -2272,7 +2270,7 @@ class GuiDocEditSearch(QFrame):
self.resultLabel = QLabel("?/?")
self.resultLabel.setFont(self.boxFont)
- self.resultLabel.setMinimumWidth(self.mainTheme.getTextWidth("?/?", self.boxFont))
+ self.resultLabel.setMinimumWidth(CONFIG.theme.getTextWidth("?/?", self.boxFont))
self.toggleCase = QAction(self.tr("Case Sensitive"), self)
self.toggleCase.setCheckable(True)
@@ -2378,15 +2376,15 @@ class GuiDocEditSearch(QFrame):
self.replaceBox.setPalette(qPalette)
# Set icons
- self.toggleCase.setIcon(self.mainTheme.getIcon("search_case"))
- self.toggleWord.setIcon(self.mainTheme.getIcon("search_word"))
- self.toggleRegEx.setIcon(self.mainTheme.getIcon("search_regex"))
- self.toggleLoop.setIcon(self.mainTheme.getIcon("search_loop"))
- self.toggleProject.setIcon(self.mainTheme.getIcon("search_project"))
- self.toggleMatchCap.setIcon(self.mainTheme.getIcon("search_preserve"))
- self.cancelSearch.setIcon(self.mainTheme.getIcon("search_cancel"))
- self.searchButton.setIcon(self.mainTheme.getIcon("search"))
- self.replaceButton.setIcon(self.mainTheme.getIcon("search_replace"))
+ self.toggleCase.setIcon(CONFIG.theme.getIcon("search_case"))
+ self.toggleWord.setIcon(CONFIG.theme.getIcon("search_word"))
+ self.toggleRegEx.setIcon(CONFIG.theme.getIcon("search_regex"))
+ self.toggleLoop.setIcon(CONFIG.theme.getIcon("search_loop"))
+ self.toggleProject.setIcon(CONFIG.theme.getIcon("search_project"))
+ self.toggleMatchCap.setIcon(CONFIG.theme.getIcon("search_preserve"))
+ self.cancelSearch.setIcon(CONFIG.theme.getIcon("search_cancel"))
+ self.searchButton.setIcon(CONFIG.theme.getIcon("search"))
+ self.replaceButton.setIcon(CONFIG.theme.getIcon("search_replace"))
# Set stylesheets
self.searchOpt.setStyleSheet("QToolBar {padding: 0;}")
@@ -2478,7 +2476,7 @@ class GuiDocEditSearch(QFrame):
"""
currRes = "?" if currRes is None else currRes
resCount = "?" if resCount is None else "1000+" if resCount > 1000 else resCount
- minWidth = self.mainTheme.getTextWidth(f"{resCount}//{resCount}", self.boxFont)
+ minWidth = CONFIG.theme.getTextWidth(f"{resCount}//{resCount}", self.boxFont)
self.resultLabel.setText(f"{currRes}/{resCount}")
self.resultLabel.setMinimumWidth(minWidth)
self.adjustSize()
@@ -2641,11 +2639,10 @@ class GuiDocEditHeader(QWidget):
self.docEditor = docEditor
self.mainGui = docEditor.mainGui
self.theProject = docEditor.theProject
- self.mainTheme = docEditor.mainTheme
self._docHandle = None
- fPx = int(0.9*self.mainTheme.fontPixelSize)
+ fPx = int(0.9*CONFIG.theme.fontPixelSize)
hSp = CONFIG.pxInt(6)
# Main Widget Settings
@@ -2662,7 +2659,7 @@ class GuiDocEditHeader(QWidget):
self.theTitle.setFixedHeight(fPx)
lblFont = self.theTitle.font()
- lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
+ lblFont.setPointSizeF(0.9*CONFIG.theme.fontPointSize)
self.theTitle.setFont(lblFont)
# Buttons
@@ -2732,15 +2729,15 @@ class GuiDocEditHeader(QWidget):
def updateTheme(self):
"""Update theme elements.
"""
- self.editButton.setIcon(self.mainTheme.getIcon("edit"))
- self.searchButton.setIcon(self.mainTheme.getIcon("search"))
- self.minmaxButton.setIcon(self.mainTheme.getIcon("maximise"))
- self.closeButton.setIcon(self.mainTheme.getIcon("close"))
+ self.editButton.setIcon(CONFIG.theme.getIcon("edit"))
+ self.searchButton.setIcon(CONFIG.theme.getIcon("search"))
+ self.minmaxButton.setIcon(CONFIG.theme.getIcon("maximise"))
+ self.closeButton.setIcon(CONFIG.theme.getIcon("close"))
buttonStyle = (
"QToolButton {{border: none; background: transparent;}} "
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
- ).format(*self.mainTheme.colText)
+ ).format(*CONFIG.theme.colText)
self.editButton.setStyleSheet(buttonStyle)
self.searchButton.setStyleSheet(buttonStyle)
@@ -2756,9 +2753,9 @@ class GuiDocEditHeader(QWidget):
theme rather than the main GUI.
"""
thePalette = QPalette()
- thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
- thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
- thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
+ thePalette.setColor(QPalette.Window, QColor(*CONFIG.theme.colBack))
+ thePalette.setColor(QPalette.WindowText, QColor(*CONFIG.theme.colText))
+ thePalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
self.setPalette(thePalette)
self.theTitle.setPalette(thePalette)
@@ -2806,9 +2803,9 @@ class GuiDocEditHeader(QWidget):
toggleFocusMode function and should not be activated directly.
"""
if self.mainGui.isFocusMode:
- self.minmaxButton.setIcon(self.mainTheme.getIcon("minimise"))
+ self.minmaxButton.setIcon(CONFIG.theme.getIcon("minimise"))
else:
- self.minmaxButton.setIcon(self.mainTheme.getIcon("maximise"))
+ self.minmaxButton.setIcon(CONFIG.theme.getIcon("maximise"))
return
##
@@ -2876,20 +2873,19 @@ class GuiDocEditFooter(QWidget):
self.docEditor = docEditor
self.mainGui = docEditor.mainGui
self.theProject = docEditor.theProject
- self.mainTheme = docEditor.mainTheme
self._theItem = None
self._docHandle = None
self._docSelection = False
- self.sPx = int(round(0.9*self.mainTheme.baseIconSize))
- fPx = int(0.9*self.mainTheme.fontPixelSize)
+ self.sPx = int(round(0.9*CONFIG.theme.baseIconSize))
+ fPx = int(0.9*CONFIG.theme.fontPixelSize)
bSp = CONFIG.pxInt(4)
hSp = CONFIG.pxInt(6)
lblFont = self.font()
- lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
+ lblFont.setPointSizeF(0.9*CONFIG.theme.fontPointSize)
# Main Widget Settings
self.setContentsMargins(0, 0, 0, 0)
@@ -2976,8 +2972,8 @@ class GuiDocEditFooter(QWidget):
def updateTheme(self):
"""Update theme elements.
"""
- self.linesIcon.setPixmap(self.mainTheme.getPixmap("status_lines", (self.sPx, self.sPx)))
- self.wordsIcon.setPixmap(self.mainTheme.getPixmap("status_stats", (self.sPx, self.sPx)))
+ self.linesIcon.setPixmap(CONFIG.theme.getPixmap("status_lines", (self.sPx, self.sPx)))
+ self.wordsIcon.setPixmap(CONFIG.theme.getPixmap("status_stats", (self.sPx, self.sPx)))
self.matchColours()
@@ -2988,9 +2984,9 @@ class GuiDocEditFooter(QWidget):
theme rather than the main GUI.
"""
thePalette = QPalette()
- thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
- thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
- thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
+ thePalette.setColor(QPalette.Window, QColor(*CONFIG.theme.colBack))
+ thePalette.setColor(QPalette.WindowText, QColor(*CONFIG.theme.colText))
+ thePalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
self.setPalette(thePalette)
self.statusText.setPalette(thePalette)
diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py
index 46904842..8fbc307e 100644
--- a/novelwriter/gui/dochighlight.py
+++ b/novelwriter/gui/dochighlight.py
@@ -54,7 +54,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
self.theDoc = theDoc
self.spEnchant = spEnchant
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self.theHandle = None
self.spellCheck = False
@@ -87,24 +86,24 @@ class GuiDocHighlighter(QSyntaxHighlighter):
"""
logger.debug("Setting up highlighting rules")
- self.colHead = QColor(*self.mainTheme.colHead)
- self.colHeadH = QColor(*self.mainTheme.colHeadH)
- self.colDialN = QColor(*self.mainTheme.colDialN)
- self.colDialD = QColor(*self.mainTheme.colDialD)
- self.colDialS = QColor(*self.mainTheme.colDialS)
- self.colHidden = QColor(*self.mainTheme.colHidden)
- self.colKey = QColor(*self.mainTheme.colKey)
- self.colVal = QColor(*self.mainTheme.colVal)
- self.colSpell = QColor(*self.mainTheme.colSpell)
- self.colError = QColor(*self.mainTheme.colError)
- self.colRepTag = QColor(*self.mainTheme.colRepTag)
- self.colMod = QColor(*self.mainTheme.colMod)
- self.colBreak = QColor(*self.mainTheme.colEmph)
+ self.colHead = QColor(*CONFIG.theme.colHead)
+ self.colHeadH = QColor(*CONFIG.theme.colHeadH)
+ self.colDialN = QColor(*CONFIG.theme.colDialN)
+ self.colDialD = QColor(*CONFIG.theme.colDialD)
+ self.colDialS = QColor(*CONFIG.theme.colDialS)
+ self.colHidden = QColor(*CONFIG.theme.colHidden)
+ self.colKey = QColor(*CONFIG.theme.colKey)
+ self.colVal = QColor(*CONFIG.theme.colVal)
+ self.colSpell = QColor(*CONFIG.theme.colSpell)
+ self.colError = QColor(*CONFIG.theme.colError)
+ self.colRepTag = QColor(*CONFIG.theme.colRepTag)
+ self.colMod = QColor(*CONFIG.theme.colMod)
+ self.colBreak = QColor(*CONFIG.theme.colEmph)
self.colBreak.setAlpha(64)
self.colEmph = None
if CONFIG.highlightEmph:
- self.colEmph = QColor(*self.mainTheme.colEmph)
+ self.colEmph = QColor(*CONFIG.theme.colEmph)
self.hStyles = {
"header1": self._makeFormat(self.colHead, "bold", 1.8),
diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py
index 168030b2..8cfd2073 100644
--- a/novelwriter/gui/docviewer.py
+++ b/novelwriter/gui/docviewer.py
@@ -60,7 +60,6 @@ class GuiDocViewer(QTextBrowser):
# Class Variables
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
# Internal Variables
@@ -121,14 +120,14 @@ class GuiDocViewer(QTextBrowser):
# Set the widget colours to match syntax theme
mainPalette = self.palette()
- mainPalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
- mainPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
- mainPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
+ mainPalette.setColor(QPalette.Window, QColor(*CONFIG.theme.colBack))
+ mainPalette.setColor(QPalette.Base, QColor(*CONFIG.theme.colBack))
+ mainPalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
self.setPalette(mainPalette)
docPalette = self.viewport().palette()
- docPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
- docPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
+ docPalette.setColor(QPalette.Base, QColor(*CONFIG.theme.colBack))
+ docPalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
self.viewport().setPalette(docPalette)
self.docHeader.matchColours()
@@ -508,27 +507,27 @@ class GuiDocViewer(QTextBrowser):
" text-align: center;"
"}}\n"
).format(
- tColR=self.mainTheme.colText[0],
- tColG=self.mainTheme.colText[1],
- tColB=self.mainTheme.colText[2],
- hColR=self.mainTheme.colHead[0],
- hColG=self.mainTheme.colHead[1],
- hColB=self.mainTheme.colHead[2],
- aColR=self.mainTheme.colVal[0],
- aColG=self.mainTheme.colVal[1],
- aColB=self.mainTheme.colVal[2],
- eColR=self.mainTheme.colEmph[0],
- eColG=self.mainTheme.colEmph[1],
- eColB=self.mainTheme.colEmph[2],
- kColR=self.mainTheme.colKey[0],
- kColG=self.mainTheme.colKey[1],
- kColB=self.mainTheme.colKey[2],
- cColR=self.mainTheme.colHidden[0],
- cColG=self.mainTheme.colHidden[1],
- cColB=self.mainTheme.colHidden[2],
- mColR=self.mainTheme.colMod[0],
- mColG=self.mainTheme.colMod[1],
- mColB=self.mainTheme.colMod[2],
+ tColR=CONFIG.theme.colText[0],
+ tColG=CONFIG.theme.colText[1],
+ tColB=CONFIG.theme.colText[2],
+ hColR=CONFIG.theme.colHead[0],
+ hColG=CONFIG.theme.colHead[1],
+ hColB=CONFIG.theme.colHead[2],
+ aColR=CONFIG.theme.colVal[0],
+ aColG=CONFIG.theme.colVal[1],
+ aColB=CONFIG.theme.colVal[2],
+ eColR=CONFIG.theme.colEmph[0],
+ eColG=CONFIG.theme.colEmph[1],
+ eColB=CONFIG.theme.colEmph[2],
+ kColR=CONFIG.theme.colKey[0],
+ kColG=CONFIG.theme.colKey[1],
+ kColB=CONFIG.theme.colKey[2],
+ cColR=CONFIG.theme.colHidden[0],
+ cColG=CONFIG.theme.colHidden[1],
+ cColB=CONFIG.theme.colHidden[2],
+ mColR=CONFIG.theme.colMod[0],
+ mColG=CONFIG.theme.colMod[1],
+ mColB=CONFIG.theme.colMod[2],
)
self.document().setDefaultStyleSheet(styleSheet)
@@ -684,12 +683,11 @@ class GuiDocViewHeader(QWidget):
self.docViewer = docViewer
self.mainGui = docViewer.mainGui
self.theProject = docViewer.theProject
- self.mainTheme = docViewer.mainTheme
# Internal Variables
self._docHandle = None
- fPx = int(0.9*self.mainTheme.fontPixelSize)
+ fPx = int(0.9*CONFIG.theme.fontPixelSize)
hSp = CONFIG.pxInt(6)
# Main Widget Settings
@@ -706,7 +704,7 @@ class GuiDocViewHeader(QWidget):
self.theTitle.setFixedHeight(fPx)
lblFont = self.theTitle.font()
- lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
+ lblFont.setPointSizeF(0.9*CONFIG.theme.fontPointSize)
self.theTitle.setFont(lblFont)
# Buttons
@@ -777,15 +775,15 @@ class GuiDocViewHeader(QWidget):
def updateTheme(self):
"""Update theme elements.
"""
- self.backButton.setIcon(self.mainTheme.getIcon("backward"))
- self.forwardButton.setIcon(self.mainTheme.getIcon("forward"))
- self.refreshButton.setIcon(self.mainTheme.getIcon("refresh"))
- self.closeButton.setIcon(self.mainTheme.getIcon("close"))
+ self.backButton.setIcon(CONFIG.theme.getIcon("backward"))
+ self.forwardButton.setIcon(CONFIG.theme.getIcon("forward"))
+ self.refreshButton.setIcon(CONFIG.theme.getIcon("refresh"))
+ self.closeButton.setIcon(CONFIG.theme.getIcon("close"))
buttonStyle = (
"QToolButton {{border: none; background: transparent;}} "
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
- ).format(*self.mainTheme.colText)
+ ).format(*CONFIG.theme.colText)
self.backButton.setStyleSheet(buttonStyle)
self.forwardButton.setStyleSheet(buttonStyle)
@@ -801,9 +799,9 @@ class GuiDocViewHeader(QWidget):
theme rather than the main GUI.
"""
thePalette = QPalette()
- thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
- thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
- thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
+ thePalette.setColor(QPalette.Window, QColor(*CONFIG.theme.colBack))
+ thePalette.setColor(QPalette.WindowText, QColor(*CONFIG.theme.colText))
+ thePalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
self.setPalette(thePalette)
self.theTitle.setPalette(thePalette)
@@ -900,13 +898,12 @@ class GuiDocViewFooter(QWidget):
self.docViewer = docViewer
self.mainGui = docViewer.mainGui
- self.mainTheme = docViewer.mainTheme
self.viewMeta = docViewer.mainGui.viewMeta
# Internal Variables
self._docHandle = None
- fPx = int(0.9*self.mainTheme.fontPixelSize)
+ fPx = int(0.9*CONFIG.theme.fontPixelSize)
bSp = CONFIG.pxInt(2)
hSp = CONFIG.pxInt(8)
@@ -991,7 +988,7 @@ class GuiDocViewFooter(QWidget):
self.lblSynopsis.setAlignment(Qt.AlignLeft | Qt.AlignTop)
lblFont = self.font()
- lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
+ lblFont.setPointSizeF(0.9*CONFIG.theme.fontPointSize)
self.lblRefs.setFont(lblFont)
self.lblSticky.setFont(lblFont)
self.lblComments.setFont(lblFont)
@@ -1036,21 +1033,21 @@ class GuiDocViewFooter(QWidget):
"""
# Icons
- fPx = int(0.9*self.mainTheme.fontPixelSize)
+ fPx = int(0.9*CONFIG.theme.fontPixelSize)
- stickyOn = self.mainTheme.getPixmap("sticky-on", (fPx, fPx))
- stickyOff = self.mainTheme.getPixmap("sticky-off", (fPx, fPx))
+ stickyOn = CONFIG.theme.getPixmap("sticky-on", (fPx, fPx))
+ stickyOff = CONFIG.theme.getPixmap("sticky-off", (fPx, fPx))
stickyIcon = QIcon()
stickyIcon.addPixmap(stickyOn, QIcon.Normal, QIcon.On)
stickyIcon.addPixmap(stickyOff, QIcon.Normal, QIcon.Off)
- bulletOn = self.mainTheme.getPixmap("bullet-on", (fPx, fPx))
- bulletOff = self.mainTheme.getPixmap("bullet-off", (fPx, fPx))
+ bulletOn = CONFIG.theme.getPixmap("bullet-on", (fPx, fPx))
+ bulletOff = CONFIG.theme.getPixmap("bullet-off", (fPx, fPx))
bulletIcon = QIcon()
bulletIcon.addPixmap(bulletOn, QIcon.Normal, QIcon.On)
bulletIcon.addPixmap(bulletOff, QIcon.Normal, QIcon.Off)
- self.showHide.setIcon(self.mainTheme.getIcon("reference"))
+ self.showHide.setIcon(CONFIG.theme.getIcon("reference"))
self.stickyRefs.setIcon(stickyIcon)
self.showComments.setIcon(bulletIcon)
self.showSynopsis.setIcon(bulletIcon)
@@ -1060,7 +1057,7 @@ class GuiDocViewFooter(QWidget):
buttonStyle = (
"QToolButton {{border: none; background: transparent;}} "
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
- ).format(*self.mainTheme.colText)
+ ).format(*CONFIG.theme.colText)
self.showHide.setStyleSheet(buttonStyle)
self.stickyRefs.setStyleSheet(buttonStyle)
@@ -1076,9 +1073,9 @@ class GuiDocViewFooter(QWidget):
theme rather than the main GUI.
"""
thePalette = QPalette()
- thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
- thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
- thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
+ thePalette.setColor(QPalette.Window, QColor(*CONFIG.theme.colBack))
+ thePalette.setColor(QPalette.WindowText, QColor(*CONFIG.theme.colText))
+ thePalette.setColor(QPalette.Text, QColor(*CONFIG.theme.colText))
self.setPalette(thePalette)
self.lblRefs.setPalette(thePalette)
@@ -1143,7 +1140,6 @@ class GuiDocViewDetails(QScrollArea):
self.mainGui = mainGui
self.theProject = mainGui.theProject
- self.mainTheme = mainGui.mainTheme
self.refList = QLabel("")
self.refList.setWordWrap(True)
@@ -1151,9 +1147,7 @@ class GuiDocViewDetails(QScrollArea):
self.refList.setScaledContents(True)
self.refList.linkActivated.connect(self._linkClicked)
- self.linkStyle = "style='color: rgb({0},{1},{2})'".format(
- *self.mainTheme.colLink
- )
+ self.linkStyle = "style='color: rgb({0},{1},{2})'".format(*CONFIG.theme.colLink)
# Assemble
self.outerWidget = QWidget()
diff --git a/novelwriter/gui/itemdetails.py b/novelwriter/gui/itemdetails.py
index 163e0d4d..4c1faf6f 100644
--- a/novelwriter/gui/itemdetails.py
+++ b/novelwriter/gui/itemdetails.py
@@ -44,7 +44,6 @@ class GuiItemDetails(QWidget):
self.mainGui = mainGui
self.theProject = mainGui.theProject
- self.mainTheme = mainGui.mainTheme
# Internal Variables
self._itemHandle = None
@@ -53,7 +52,7 @@ class GuiItemDetails(QWidget):
hSp = CONFIG.pxInt(6)
vSp = CONFIG.pxInt(1)
mPx = CONFIG.pxInt(6)
- fPt = self.mainTheme.fontPointSize
+ fPt = CONFIG.theme.fontPointSize
fntLabel = QFont()
fntLabel.setBold(True)
@@ -178,8 +177,8 @@ class GuiItemDetails(QWidget):
self.updateTheme()
# Make sure the columns for flags and counts don't resize too often
- flagWidth = self.mainTheme.getTextWidth("Mm", fntValue)
- countWidth = self.mainTheme.getTextWidth("99,999", fntValue)
+ flagWidth = CONFIG.theme.getTextWidth("Mm", fntValue)
+ countWidth = CONFIG.theme.getTextWidth("99,999", fntValue)
self.mainBox.setColumnMinimumWidth(1, flagWidth)
self.mainBox.setColumnMinimumWidth(4, countWidth)
@@ -241,7 +240,7 @@ class GuiItemDetails(QWidget):
return
self._itemHandle = tHandle
- iPx = int(round(0.8*self.mainTheme.baseIconSize))
+ iPx = int(round(0.8*CONFIG.theme.baseIconSize))
# Label
# =====
@@ -252,11 +251,11 @@ class GuiItemDetails(QWidget):
if nwItem.isFileType():
if nwItem.isActive:
- self.labelIcon.setPixmap(self.mainTheme.getPixmap("checked", (iPx, iPx)))
+ self.labelIcon.setPixmap(CONFIG.theme.getPixmap("checked", (iPx, iPx)))
else:
- self.labelIcon.setPixmap(self.mainTheme.getPixmap("unchecked", (iPx, iPx)))
+ self.labelIcon.setPixmap(CONFIG.theme.getPixmap("unchecked", (iPx, iPx)))
else:
- self.labelIcon.setPixmap(self.mainTheme.getPixmap("noncheckable", (iPx, iPx)))
+ self.labelIcon.setPixmap(CONFIG.theme.getPixmap("noncheckable", (iPx, iPx)))
self.labelData.setText(theLabel)
@@ -270,14 +269,14 @@ class GuiItemDetails(QWidget):
# Class
# =====
- classIcon = self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass])
+ classIcon = CONFIG.theme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass])
self.classIcon.setPixmap(classIcon.pixmap(iPx, iPx))
self.classData.setText(trConst(nwLabels.CLASS_NAME[nwItem.itemClass]))
# Layout
# ======
- usageIcon = self.mainTheme.getItemIcon(
+ usageIcon = CONFIG.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, nwItem.mainHeading
)
self.usageIcon.setPixmap(usageIcon.pixmap(iPx, iPx))
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index cd0fd593..b04db81f 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -201,9 +201,8 @@ class GuiNovelToolBar(QWidget):
self.novelView = novelView
self.mainGui = novelView.mainGui
self.theProject = novelView.mainGui.theProject
- self.mainTheme = novelView.mainGui.mainTheme
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
mPx = CONFIG.pxInt(2)
self.setContentsMargins(0, 0, 0, 0)
@@ -276,9 +275,9 @@ class GuiNovelToolBar(QWidget):
"""Update theme elements.
"""
# Icons
- self.tbNovel.setIcon(self.mainTheme.getIcon("cls_novel"))
- self.tbRefresh.setIcon(self.mainTheme.getIcon("refresh"))
- self.tbMore.setIcon(self.mainTheme.getIcon("menu"))
+ self.tbNovel.setIcon(CONFIG.theme.getIcon("cls_novel"))
+ self.tbRefresh.setIcon(CONFIG.theme.getIcon("refresh"))
+ self.tbMore.setIcon(CONFIG.theme.getIcon("menu"))
qPalette = self.palette()
qPalette.setBrush(QPalette.Window, qPalette.base())
@@ -401,7 +400,6 @@ class GuiNovelTree(QTreeWidget):
self.novelView = novelView
self.mainGui = novelView.mainGui
- self.mainTheme = novelView.mainGui.mainTheme
self.theProject = novelView.mainGui.theProject
# Internal Variables
@@ -419,7 +417,7 @@ class GuiNovelTree(QTreeWidget):
# Build GUI
# =========
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
cMg = CONFIG.pxInt(6)
self.setIconSize(QSize(iPx, iPx))
@@ -485,8 +483,8 @@ class GuiNovelTree(QTreeWidget):
def updateTheme(self):
"""Update theme elements.
"""
- iPx = self.mainTheme.baseIconSize
- self._pMore = self.mainTheme.loadDecoration("deco_doc_more", pxH=iPx)
+ iPx = CONFIG.theme.baseIconSize
+ self._pMore = CONFIG.theme.loadDecoration("deco_doc_more", pxH=iPx)
return
##
@@ -737,7 +735,7 @@ class GuiNovelTree(QTreeWidget):
"""Set the tree item values from the index entry.
"""
iLevel = nwHeaders.H_LEVEL.get(idxItem.level, 0)
- hDec = self.mainTheme.getHeaderDecoration(iLevel)
+ hDec = CONFIG.theme.getHeaderDecoration(iLevel)
trItem.setData(self.C_TITLE, Qt.DecorationRole, hDec)
trItem.setText(self.C_TITLE, idxItem.title)
diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py
index e19b19a3..bcc3ef24 100644
--- a/novelwriter/gui/outline.py
+++ b/novelwriter/gui/outline.py
@@ -217,7 +217,6 @@ class GuiOutlineToolBar(QToolBar):
self.mainGui = theOutline.mainGui
self.theProject = theOutline.mainGui.theProject
- self.mainTheme = theOutline.mainGui.mainTheme
iPx = CONFIG.pxInt(22)
mPx = CONFIG.pxInt(12)
@@ -275,8 +274,8 @@ class GuiOutlineToolBar(QToolBar):
self.setStyleSheet("QToolBar {border: 0px;}")
self.novelValue.updateList(includeAll=True)
- self.aRefresh.setIcon(self.mainTheme.getIcon("refresh"))
- self.tbColumns.setIcon(self.mainTheme.getIcon("menu"))
+ self.aRefresh.setIcon(CONFIG.theme.getIcon("refresh"))
+ self.tbColumns.setIcon(CONFIG.theme.getIcon("menu"))
return
@@ -375,7 +374,6 @@ class GuiOutlineTree(QTreeWidget):
self.outlineView = outlineView
self.mainGui = outlineView.mainGui
self.theProject = outlineView.mainGui.theProject
- self.mainTheme = outlineView.mainGui.mainTheme
self.setUniformRowHeights(True)
self.setFrameStyle(QFrame.NoFrame)
@@ -386,7 +384,7 @@ class GuiOutlineTree(QTreeWidget):
self.itemDoubleClicked.connect(self._treeDoubleClick)
self.itemSelectionChanged.connect(self._itemSelected)
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
self.setIconSize(QSize(iPx, iPx))
self.setIndentation(0)
@@ -403,11 +401,11 @@ class GuiOutlineTree(QTreeWidget):
self._hFonts = [self.font(), fH1, fH2, self.font(), self.font()]
self._dIcon = {
- "H0": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H0"),
- "H1": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H1"),
- "H2": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H2"),
- "H3": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H3"),
- "H4": self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H4"),
+ "H0": CONFIG.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H0"),
+ "H1": CONFIG.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H1"),
+ "H2": CONFIG.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H2"),
+ "H3": CONFIG.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H3"),
+ "H4": CONFIG.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H4"),
}
# Internals
@@ -675,7 +673,7 @@ class GuiOutlineTree(QTreeWidget):
trItem = QTreeWidgetItem()
nwItem = self.theProject.tree[tHandle]
- hDec = self.mainTheme.getHeaderDecoration(iLevel)
+ hDec = CONFIG.theme.getHeaderDecoration(iLevel)
trItem.setData(self._colIdx[nwOutline.TITLE], Qt.DecorationRole, hDec)
trItem.setText(self._colIdx[nwOutline.TITLE], novIdx.title)
@@ -777,12 +775,11 @@ class GuiOutlineDetails(QScrollArea):
self.theOutline = theOutline
self.mainGui = theOutline.mainGui
self.theProject = theOutline.mainGui.theProject
- self.mainTheme = theOutline.mainGui.mainTheme
# Sizes
- minTitle = 30*self.mainTheme.textNWidth
- maxTitle = 40*self.mainTheme.textNWidth
- wCount = self.mainTheme.getTextWidth("999,999")
+ minTitle = 30*CONFIG.theme.textNWidth
+ maxTitle = 40*CONFIG.theme.textNWidth
+ wCount = CONFIG.theme.getTextWidth("999,999")
hSpace = int(CONFIG.pxInt(10))
vSpace = int(CONFIG.pxInt(4))
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index de547135..22c40d44 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -237,9 +237,8 @@ class GuiProjectToolBar(QWidget):
self.projTree = projView.projTree
self.mainGui = projView.mainGui
self.theProject = projView.mainGui.theProject
- self.mainTheme = projView.mainGui.mainTheme
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
mPx = CONFIG.pxInt(2)
self.setContentsMargins(0, 0, 0, 0)
@@ -370,16 +369,16 @@ class GuiProjectToolBar(QWidget):
self.tbAdd.setStyleSheet(buttonStyle)
self.tbMore.setStyleSheet(buttonStyle)
- self.tbQuick.setIcon(self.mainTheme.getIcon("bookmark"))
- self.tbMoveU.setIcon(self.mainTheme.getIcon("up"))
- self.tbMoveD.setIcon(self.mainTheme.getIcon("down"))
- self.aAddEmpty.setIcon(self.mainTheme.getIcon("proj_document"))
- self.aAddChap.setIcon(self.mainTheme.getIcon("proj_chapter"))
- self.aAddScene.setIcon(self.mainTheme.getIcon("proj_scene"))
- self.aAddNote.setIcon(self.mainTheme.getIcon("proj_note"))
- self.aAddFolder.setIcon(self.mainTheme.getIcon("proj_folder"))
- self.tbAdd.setIcon(self.mainTheme.getIcon("add"))
- self.tbMore.setIcon(self.mainTheme.getIcon("menu"))
+ self.tbQuick.setIcon(CONFIG.theme.getIcon("bookmark"))
+ self.tbMoveU.setIcon(CONFIG.theme.getIcon("up"))
+ self.tbMoveD.setIcon(CONFIG.theme.getIcon("down"))
+ self.aAddEmpty.setIcon(CONFIG.theme.getIcon("proj_document"))
+ self.aAddChap.setIcon(CONFIG.theme.getIcon("proj_chapter"))
+ self.aAddScene.setIcon(CONFIG.theme.getIcon("proj_scene"))
+ self.aAddNote.setIcon(CONFIG.theme.getIcon("proj_note"))
+ self.aAddFolder.setIcon(CONFIG.theme.getIcon("proj_folder"))
+ self.tbAdd.setIcon(CONFIG.theme.getIcon("add"))
+ self.tbMore.setIcon(CONFIG.theme.getIcon("menu"))
self.buildQuickLinkMenu()
self._buildRootMenu()
@@ -398,7 +397,7 @@ class GuiProjectToolBar(QWidget):
for n, (tHandle, nwItem) in enumerate(self.theProject.tree.iterRoots(None)):
aRoot = self.mQuick.addAction(nwItem.itemName)
aRoot.setData(tHandle)
- aRoot.setIcon(self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass]))
+ aRoot.setIcon(CONFIG.theme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass]))
aRoot.triggered.connect(
lambda n, tHandle=tHandle: self.projView.setSelectedHandle(tHandle, doScroll=True)
)
@@ -412,7 +411,7 @@ class GuiProjectToolBar(QWidget):
"""Build the rood folder menu."""
def addClass(itemClass):
aNew = self.mAddRoot.addAction(trConst(nwLabels.CLASS_NAME[itemClass]))
- aNew.setIcon(self.mainTheme.getIcon(nwLabels.CLASS_ICON[itemClass]))
+ aNew.setIcon(CONFIG.theme.getIcon(nwLabels.CLASS_ICON[itemClass]))
aNew.triggered.connect(lambda: self.projTree.newTreeItem(nwItemType.ROOT, itemClass))
self.mAddRoot.addAction(aNew)
return
@@ -469,7 +468,6 @@ class GuiProjectTree(QTreeWidget):
self.projView = projView
self.mainGui = projView.mainGui
- self.mainTheme = projView.mainGui.mainTheme
self.theProject = projView.mainGui.theProject
# Internal Variables
@@ -485,7 +483,7 @@ class GuiProjectTree(QTreeWidget):
self.customContextMenuRequested.connect(self._openContextMenu)
# Tree Settings
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
cMg = CONFIG.pxInt(6)
self.setIconSize(QSize(iPx, iPx))
@@ -995,7 +993,7 @@ class GuiProjectTree(QTreeWidget):
itemStatus, statusIcon = nwItem.getImportStatus(incIcon=True)
hLevel = nwItem.mainHeading
- itemIcon = self.mainTheme.getItemIcon(
+ itemIcon = CONFIG.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
)
@@ -1011,7 +1009,7 @@ class GuiProjectTree(QTreeWidget):
else:
iconName = "noncheckable"
- trItem.setIcon(self.C_ACTIVE, self.mainTheme.getIcon(iconName))
+ trItem.setIcon(self.C_ACTIVE, CONFIG.theme.getIcon(iconName))
if CONFIG.emphLabels and nwItem.isDocumentLayout():
trFont = trItem.font(self.C_NAME)
diff --git a/novelwriter/gui/sidebar.py b/novelwriter/gui/sidebar.py
index 637e11a5..8e8b608d 100644
--- a/novelwriter/gui/sidebar.py
+++ b/novelwriter/gui/sidebar.py
@@ -45,15 +45,14 @@ class GuiSideBar(QToolBar):
logger.debug("Create: GuiSideBar")
- self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
+ self.mainGui = mainGui
# Style
iPx = CONFIG.pxInt(22)
mPx = CONFIG.pxInt(60)
- lblFont = self.mainTheme.guiFont
- lblFont.setPointSizeF(0.65*self.mainTheme.fontPointSize)
+ lblFont = CONFIG.theme.guiFont
+ lblFont.setPointSizeF(0.65*CONFIG.theme.fontPointSize)
self.setMovable(False)
self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
@@ -131,13 +130,13 @@ class GuiSideBar(QToolBar):
"""
self.setStyleSheet("QToolBar {border: 0px;}")
- self.aProject.setIcon(self.mainTheme.getIcon("view_editor"))
- self.aNovel.setIcon(self.mainTheme.getIcon("view_novel"))
- self.aOutline.setIcon(self.mainTheme.getIcon("view_outline"))
- self.aBuild.setIcon(self.mainTheme.getIcon("view_build"))
- self.aDetails.setIcon(self.mainTheme.getIcon("proj_details"))
- self.aStats.setIcon(self.mainTheme.getIcon("proj_stats"))
- self.tbSettings.setIcon(self.mainTheme.getIcon("settings"))
+ self.aProject.setIcon(CONFIG.theme.getIcon("view_editor"))
+ self.aNovel.setIcon(CONFIG.theme.getIcon("view_novel"))
+ self.aOutline.setIcon(CONFIG.theme.getIcon("view_outline"))
+ self.aBuild.setIcon(CONFIG.theme.getIcon("view_build"))
+ self.aDetails.setIcon(CONFIG.theme.getIcon("proj_details"))
+ self.aStats.setIcon(CONFIG.theme.getIcon("proj_stats"))
+ self.tbSettings.setIcon(CONFIG.theme.getIcon("settings"))
return
diff --git a/novelwriter/gui/statusbar.py b/novelwriter/gui/statusbar.py
index 10f16c08..f14affff 100644
--- a/novelwriter/gui/statusbar.py
+++ b/novelwriter/gui/statusbar.py
@@ -47,15 +47,14 @@ class GuiMainStatus(QStatusBar):
logger.debug("Create: GuiMainStatus")
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
self.refTime = None
self.userIdle = False
- colNone = QColor(*self.mainTheme.statNone)
- colSaved = QColor(*self.mainTheme.statSaved)
- colUnsaved = QColor(*self.mainTheme.statUnsaved)
+ colNone = QColor(*CONFIG.theme.statNone)
+ colSaved = QColor(*CONFIG.theme.statSaved)
+ colUnsaved = QColor(*CONFIG.theme.statUnsaved)
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
# Permanent Widgets
# =================
@@ -99,7 +98,7 @@ class GuiMainStatus(QStatusBar):
self.timeIcon = QLabel()
self.timeText = QLabel("")
self.timeText.setToolTip(self.tr("Session Time"))
- self.timeText.setMinimumWidth(self.mainTheme.getTextWidth("00:00:00:"))
+ self.timeText.setMinimumWidth(CONFIG.theme.getTextWidth("00:00:00:"))
self.timeIcon.setContentsMargins(0, 0, 0, 0)
self.timeText.setContentsMargins(0, 0, 0, 0)
self.addPermanentWidget(self.timeIcon)
@@ -129,13 +128,13 @@ class GuiMainStatus(QStatusBar):
def updateTheme(self):
"""Update theme elements.
"""
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
- self.langIcon.setPixmap(self.mainTheme.getPixmap("status_lang", (iPx, iPx)))
- self.statsIcon.setPixmap(self.mainTheme.getPixmap("status_stats", (iPx, iPx)))
+ self.langIcon.setPixmap(CONFIG.theme.getPixmap("status_lang", (iPx, iPx)))
+ self.statsIcon.setPixmap(CONFIG.theme.getPixmap("status_stats", (iPx, iPx)))
- self.timePixmap = self.mainTheme.getPixmap("status_time", (iPx, iPx))
- self.idlePixmap = self.mainTheme.getPixmap("status_idle", (iPx, iPx))
+ self.timePixmap = CONFIG.theme.getPixmap("status_time", (iPx, iPx))
+ self.idlePixmap = CONFIG.theme.getPixmap("status_idle", (iPx, iPx))
self.timeIcon.setPixmap(self.timePixmap)
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 6076d120..ac4025a9 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -113,7 +113,7 @@ class GuiMain(QMainWindow):
# ============
# Core Classes
- self.mainTheme = GuiTheme()
+ CONFIG.setThemeInstance(GuiTheme())
self.theProject = NWProject(self)
# Core Settings
@@ -135,7 +135,7 @@ class GuiMain(QMainWindow):
# =============
# Sizes
- iPx = self.mainTheme.fontPixelSize
+ iPx = CONFIG.theme.fontPixelSize
mPx = CONFIG.pxInt(4)
hWd = CONFIG.pxInt(4)
@@ -307,10 +307,10 @@ class GuiMain(QMainWindow):
# Cache Alert Pixmaps
pxSize = (2*iPx, 2*iPx)
self.alertPix: dict[nwAlert, QPixmap] = {
- nwAlert.INFO: self.mainTheme.getPixmap("alert_info", pxSize),
- nwAlert.WARN: self.mainTheme.getPixmap("alert_warn", pxSize),
- nwAlert.ERROR: self.mainTheme.getPixmap("alert_error", pxSize),
- nwAlert.ASK: self.mainTheme.getPixmap("alert_question", pxSize),
+ nwAlert.INFO: CONFIG.theme.getPixmap("alert_info", pxSize),
+ nwAlert.WARN: CONFIG.theme.getPixmap("alert_warn", pxSize),
+ nwAlert.ERROR: CONFIG.theme.getPixmap("alert_error", pxSize),
+ nwAlert.ASK: CONFIG.theme.getPixmap("alert_question", pxSize),
}
# Check that config loaded fine
@@ -912,7 +912,7 @@ class GuiMain(QMainWindow):
if dlgConf.updateTheme:
# We are doing this manually instead of connecting to
# qApp.paletteChanged since the processing order matters
- self.mainTheme.loadTheme()
+ CONFIG.theme.loadTheme()
self.docEditor.updateTheme()
self.docViewer.updateTheme()
self.viewsBar.updateTheme()
@@ -923,7 +923,7 @@ class GuiMain(QMainWindow):
self.mainStatus.updateTheme()
if dlgConf.updateSyntax:
- self.mainTheme.loadSyntax()
+ CONFIG.theme.loadSyntax()
self.docEditor.updateSyntaxColours()
self.docEditor.initEditor()
diff --git a/novelwriter/tools/lipsum.py b/novelwriter/tools/lipsum.py
index c78e20de..b803caf6 100644
--- a/novelwriter/tools/lipsum.py
+++ b/novelwriter/tools/lipsum.py
@@ -49,8 +49,7 @@ class GuiLipsum(QDialog):
if CONFIG.osDarwin:
self.setWindowFlag(Qt.WindowType.Tool)
- self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
+ self.mainGui = mainGui
self.setWindowTitle(self.tr("Insert Placeholder Text"))
@@ -61,7 +60,7 @@ class GuiLipsum(QDialog):
nPx = CONFIG.pxInt(64)
vSp = CONFIG.pxInt(4)
self.docIcon = QLabel()
- self.docIcon.setPixmap(self.mainTheme.getPixmap("proj_document", (nPx, nPx)))
+ self.docIcon.setPixmap(CONFIG.theme.getPixmap("proj_document", (nPx, nPx)))
self.leftBox = QVBoxLayout()
self.leftBox.setSpacing(vSp)
diff --git a/novelwriter/tools/manusbuild.py b/novelwriter/tools/manusbuild.py
index 81df33c2..0c2d4dda 100644
--- a/novelwriter/tools/manusbuild.py
+++ b/novelwriter/tools/manusbuild.py
@@ -66,7 +66,6 @@ class GuiManuscriptBuild(QDialog):
self.setObjectName("GuiManuscriptBuild")
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self._parent = parent
@@ -76,7 +75,7 @@ class GuiManuscriptBuild(QDialog):
self.setMinimumWidth(CONFIG.pxInt(500))
self.setMinimumHeight(CONFIG.pxInt(300))
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
sp4 = CONFIG.pxInt(4)
sp8 = CONFIG.pxInt(8)
sp16 = CONFIG.pxInt(16)
@@ -148,7 +147,7 @@ class GuiManuscriptBuild(QDialog):
# Build Path
self.lblPath = QLabel(self.tr("Path"))
self.buildPath = QLineEdit(self)
- self.btnBrowse = QPushButton(self.mainTheme.getIcon("browse"), "")
+ self.btnBrowse = QPushButton(CONFIG.theme.getIcon("browse"), "")
self.pathBox = QHBoxLayout()
self.pathBox.addWidget(self.buildPath)
@@ -158,7 +157,7 @@ class GuiManuscriptBuild(QDialog):
# Build Name
self.lblName = QLabel(self.tr("File Name"))
self.buildName = QLineEdit(self)
- self.btnReset = QPushButton(self.mainTheme.getIcon("revert"), "")
+ self.btnReset = QPushButton(CONFIG.theme.getIcon("revert"), "")
self.btnReset.setToolTip(self.tr("Reset file name to default"))
self.nameBox = QHBoxLayout()
@@ -183,7 +182,7 @@ class GuiManuscriptBuild(QDialog):
self.buildBox.setVerticalSpacing(sp4)
# Dialog Buttons
- self.btnBuild = QPushButton(self.mainTheme.getIcon("export"), self.tr("&Build"))
+ self.btnBuild = QPushButton(CONFIG.theme.getIcon("export"), self.tr("&Build"))
self.dlgButtons = QDialogButtonBox(QDialogButtonBox.Close)
self.dlgButtons.addButton(self.btnBuild, QDialogButtonBox.ActionRole)
@@ -382,7 +381,7 @@ class GuiManuscriptBuild(QDialog):
if isinstance(rItem, NWItem):
rootMap[rHandle] = rItem.itemName
- itemIcon = self.mainTheme.getItemIcon(
+ itemIcon = CONFIG.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass,
nwItem.itemLayout, nwItem.mainHeading
)
diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py
index e767dced..1e0205c4 100644
--- a/novelwriter/tools/manuscript.py
+++ b/novelwriter/tools/manuscript.py
@@ -73,7 +73,6 @@ class GuiManuscript(QDialog):
self.setWindowFlag(Qt.WindowType.Tool)
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self._builds = BuildCollection(self.theProject)
@@ -83,7 +82,7 @@ class GuiManuscript(QDialog):
self.setMinimumWidth(CONFIG.pxInt(600))
self.setMinimumHeight(CONFIG.pxInt(500))
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
wWin = CONFIG.pxInt(900)
hWin = CONFIG.pxInt(600)
@@ -107,21 +106,21 @@ class GuiManuscript(QDialog):
).format(CONFIG.pxInt(2), fadeCol.red(), fadeCol.green(), fadeCol.blue())
self.tbAdd = QToolButton(self)
- self.tbAdd.setIcon(self.mainTheme.getIcon("add"))
+ self.tbAdd.setIcon(CONFIG.theme.getIcon("add"))
self.tbAdd.setIconSize(QSize(iPx, iPx))
self.tbAdd.setToolTip(self.tr("Add New Build"))
self.tbAdd.setStyleSheet(buttonStyle)
self.tbAdd.clicked.connect(self._createNewBuild)
self.tbDel = QToolButton(self)
- self.tbDel.setIcon(self.mainTheme.getIcon("remove"))
+ self.tbDel.setIcon(CONFIG.theme.getIcon("remove"))
self.tbDel.setIconSize(QSize(iPx, iPx))
self.tbDel.setToolTip(self.tr("Delete Selected Build"))
self.tbDel.setStyleSheet(buttonStyle)
self.tbDel.clicked.connect(self._deleteSelectedBuild)
self.tbEdit = QToolButton(self)
- self.tbEdit.setIcon(self.mainTheme.getIcon("edit"))
+ self.tbEdit.setIcon(CONFIG.theme.getIcon("edit"))
self.tbEdit.setIconSize(QSize(iPx, iPx))
self.tbEdit.setToolTip(self.tr("Edit Selected Build"))
self.tbEdit.setStyleSheet(buttonStyle)
@@ -428,7 +427,7 @@ class GuiManuscript(QDialog):
for key, name in self._builds.builds():
bItem = QListWidgetItem()
bItem.setText(name)
- bItem.setIcon(self.mainTheme.getIcon("export"))
+ bItem.setIcon(CONFIG.theme.getIcon("export"))
bItem.setData(self.D_KEY, key)
self.buildList.addItem(bItem)
self._buildMap[key] = bItem
@@ -452,7 +451,6 @@ class _PreviewWidget(QTextBrowser):
super().__init__(parent=mainGui)
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self._docTime = 0
@@ -464,7 +462,7 @@ class _PreviewWidget(QTextBrowser):
dPalette.setColor(QPalette.Text, QColor(0, 0, 0))
self.setPalette(dPalette)
- self.setMinimumWidth(40*self.mainGui.mainTheme.textNWidth)
+ self.setMinimumWidth(40*CONFIG.theme.textNWidth)
self.setTextFont(CONFIG.textFont, CONFIG.textSize)
self.setTabStopDistance(CONFIG.getTabWidth())
self.setOpenExternalLinks(False)
@@ -482,7 +480,7 @@ class _PreviewWidget(QTextBrowser):
aPalette.setColor(QPalette.Foreground, aPalette.toolTipText().color())
aFont = self.font()
- aFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
+ aFont.setPointSizeF(0.9*CONFIG.theme.fontPointSize)
self.ageLabel = QLabel("", self)
self.ageLabel.setIndent(0)
@@ -490,7 +488,7 @@ class _PreviewWidget(QTextBrowser):
self.ageLabel.setPalette(aPalette)
self.ageLabel.setAutoFillBackground(True)
self.ageLabel.setAlignment(Qt.AlignCenter)
- self.ageLabel.setFixedHeight(int(2.1*self.mainTheme.fontPixelSize))
+ self.ageLabel.setFixedHeight(int(2.1*CONFIG.theme.fontPixelSize))
# Progress
self.buildProgress = NProgressCircle(self, CONFIG.pxInt(160), CONFIG.pxInt(16))
diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py
index fb5eeba0..f90eeb25 100644
--- a/novelwriter/tools/manussettings.py
+++ b/novelwriter/tools/manussettings.py
@@ -49,7 +49,6 @@ from novelwriter.extensions.pagedsidebar import NPagedSideBar
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
- from novelwriter.gui.theme import GuiTheme
logger = logging.getLogger(__name__)
@@ -78,7 +77,6 @@ class GuiBuildSettings(QDialog):
self.setWindowFlag(Qt.WindowType.Tool)
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self._build = build
@@ -103,7 +101,7 @@ class GuiBuildSettings(QDialog):
self.optSideBar = NPagedSideBar(self)
self.optSideBar.setMinimumWidth(mPx)
self.optSideBar.setMaximumWidth(mPx)
- self.optSideBar.setLabelColor(self.mainTheme.helpText)
+ self.optSideBar.setLabelColor(CONFIG.theme.helpText)
self.optSideBar.addLabel(self.tr("Options"))
self.optSideBar.addButton(self.tr("Selection"), self.OPT_FILTERS)
@@ -307,7 +305,6 @@ class _FilterTab(QWidget):
super().__init__(parent=buildMain)
self.mainGui = buildMain.mainGui
- self.mainTheme = buildMain.mainGui.mainTheme
self.theProject = buildMain.mainGui.theProject
self._treeMap: dict[str, QTreeWidgetItem] = {}
@@ -315,9 +312,9 @@ class _FilterTab(QWidget):
self._statusFlags: dict[int, QIcon] = {
self.F_NONE: QIcon(),
- self.F_FILTERED: self.mainTheme.getIcon("build_filtered"),
- self.F_INCLUDED: self.mainTheme.getIcon("build_included"),
- self.F_EXCLUDED: self.mainTheme.getIcon("build_excluded"),
+ self.F_FILTERED: CONFIG.theme.getIcon("build_filtered"),
+ self.F_INCLUDED: CONFIG.theme.getIcon("build_included"),
+ self.F_EXCLUDED: CONFIG.theme.getIcon("build_excluded"),
}
self._trIncluded = self.tr("Included in manuscript")
@@ -327,7 +324,7 @@ class _FilterTab(QWidget):
# ============
# Tree Settings
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
cMg = CONFIG.pxInt(6)
# Tree Widget
@@ -365,7 +362,7 @@ class _FilterTab(QWidget):
self.resetButton = QToolButton(self)
self.resetButton.setToolTip(self.tr("Reset to default"))
- self.resetButton.setIcon(self.mainTheme.getIcon("revert"))
+ self.resetButton.setIcon(CONFIG.theme.getIcon("revert"))
self.resetButton.clicked.connect(lambda: self._setSelectedMode(self.F_FILTERED))
self.modeBox = QHBoxLayout()
@@ -466,7 +463,7 @@ class _FilterTab(QWidget):
continue
hLevel = nwItem.mainHeading
- itemIcon = self.mainTheme.getItemIcon(
+ itemIcon = CONFIG.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
)
@@ -480,7 +477,7 @@ class _FilterTab(QWidget):
trItem.setText(self.C_NAME, nwItem.itemName)
trItem.setData(self.C_DATA, self.D_HANDLE, tHandle)
trItem.setData(self.C_DATA, self.D_FILE, isFile)
- trItem.setIcon(self.C_ACTIVE, self.mainTheme.getIcon(iconName))
+ trItem.setIcon(self.C_ACTIVE, CONFIG.theme.getIcon(iconName))
trItem.setTextAlignment(self.C_NAME, Qt.AlignLeft)
@@ -504,19 +501,19 @@ class _FilterTab(QWidget):
self.filterOpt.clear()
self.filterOpt.addLabel(self._build.getLabel("filter"))
self.filterOpt.addItem(
- self.mainTheme.getIcon("proj_scene"),
+ CONFIG.theme.getIcon("proj_scene"),
self._build.getLabel("filter.includeNovel"),
"doc:filter.includeNovel",
default=self._build.getBool("filter.includeNovel")
)
self.filterOpt.addItem(
- self.mainTheme.getIcon("proj_note"),
+ CONFIG.theme.getIcon("proj_note"),
self._build.getLabel("filter.includeNotes"),
"doc:filter.includeNotes",
default=self._build.getBool("filter.includeNotes")
)
self.filterOpt.addItem(
- self.mainTheme.getIcon("unchecked"),
+ CONFIG.theme.getIcon("unchecked"),
self._build.getLabel("filter.includeInactive"),
"doc:filter.includeInactive",
default=self._build.getBool("filter.includeInactive")
@@ -528,7 +525,7 @@ class _FilterTab(QWidget):
self.filterOpt.addLabel(self.tr("Select Root Folders"))
for tHandle, nwItem in self.theProject.tree.iterRoots(None):
if not nwItem.isInactiveClass():
- itemIcon = self.mainTheme.getItemIcon(
+ itemIcon = CONFIG.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout
)
self.filterOpt.addItem(
@@ -603,13 +600,12 @@ class _HeadingsTab(QWidget):
super().__init__(parent=buildMain)
self.mainGui = buildMain.mainGui
- self.mainTheme = buildMain.mainGui.mainTheme
self.theProject = buildMain.mainGui.theProject
self._build = build
self._editing = 0
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
vSp = CONFIG.pxInt(12)
bSp = CONFIG.pxInt(6)
@@ -623,7 +619,7 @@ class _HeadingsTab(QWidget):
self.fmtTitle = QLineEdit("")
self.fmtTitle.setReadOnly(True)
self.btnTitle = QToolButton()
- self.btnTitle.setIcon(self.mainTheme.getIcon("edit"))
+ self.btnTitle.setIcon(CONFIG.theme.getIcon("edit"))
self.btnTitle.clicked.connect(lambda: self._editHeading(self.EDIT_TITLE))
wrapTitle = QHBoxLayout()
@@ -639,7 +635,7 @@ class _HeadingsTab(QWidget):
self.fmtChapter = QLineEdit("")
self.fmtChapter.setReadOnly(True)
self.btnChapter = QToolButton()
- self.btnChapter.setIcon(self.mainTheme.getIcon("edit"))
+ self.btnChapter.setIcon(CONFIG.theme.getIcon("edit"))
self.btnChapter.clicked.connect(lambda: self._editHeading(self.EDIT_CHAPTER))
wrapChapter = QHBoxLayout()
@@ -655,7 +651,7 @@ class _HeadingsTab(QWidget):
self.fmtUnnumbered = QLineEdit("")
self.fmtUnnumbered.setReadOnly(True)
self.btnUnnumbered = QToolButton()
- self.btnUnnumbered.setIcon(self.mainTheme.getIcon("edit"))
+ self.btnUnnumbered.setIcon(CONFIG.theme.getIcon("edit"))
self.btnUnnumbered.clicked.connect(lambda: self._editHeading(self.EDIT_UNNUM))
wrapUnnumbered = QHBoxLayout()
@@ -672,7 +668,7 @@ class _HeadingsTab(QWidget):
self.fmtScene = QLineEdit("")
self.fmtScene.setReadOnly(True)
self.btnScene = QToolButton()
- self.btnScene.setIcon(self.mainTheme.getIcon("edit"))
+ self.btnScene.setIcon(CONFIG.theme.getIcon("edit"))
self.btnScene.clicked.connect(lambda: self._editHeading(self.EDIT_SCENE))
self.hdeScene = QLabel(self.tr("Hide"))
self.hdeScene.setToolTip(sceneHideTip)
@@ -699,7 +695,7 @@ class _HeadingsTab(QWidget):
self.fmtSection = QLineEdit("")
self.fmtSection.setReadOnly(True)
self.btnSection = QToolButton()
- self.btnSection.setIcon(self.mainTheme.getIcon("edit"))
+ self.btnSection.setIcon(CONFIG.theme.getIcon("edit"))
self.btnSection.clicked.connect(lambda: self._editHeading(self.EDIT_SECTION))
self.hdeSection = QLabel(self.tr("Hide"))
self.hdeSection.setToolTip(sectionHideTip)
@@ -729,7 +725,7 @@ class _HeadingsTab(QWidget):
self.editTextBox.setFixedHeight(5*iPx)
self.editTextBox.setEnabled(False)
- self.formSyntax = _HeadingSyntaxHighlighter(self.editTextBox.document(), self.mainTheme)
+ self.formSyntax = _HeadingSyntaxHighlighter(self.editTextBox.document())
self.menuInsert = QMenu()
self.aInsTitle = self.menuInsert.addAction(self.tr("Title"))
@@ -872,12 +868,12 @@ class _HeadingsTab(QWidget):
class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
- def __init__(self, document: QTextDocument, mainTheme: GuiTheme) -> None:
+ def __init__(self, document: QTextDocument) -> None:
super().__init__(document)
self._fmtSymbol = QTextCharFormat()
- self._fmtSymbol.setForeground(QColor(*mainTheme.colHead))
+ self._fmtSymbol.setForeground(QColor(*CONFIG.theme.colHead))
self._fmtFormat = QTextCharFormat()
- self._fmtFormat.setForeground(QColor(*mainTheme.colEmph))
+ self._fmtFormat.setForeground(QColor(*CONFIG.theme.colEmph))
return
def highlightBlock(self, text: str) -> None:
@@ -901,12 +897,9 @@ class _ContentTab(QWidget):
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
super().__init__(parent=buildMain)
- self.mainGui = buildMain.mainGui
- self.mainTheme = buildMain.mainGui.mainTheme
-
self._build = build
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
# Left Form
# =========
@@ -973,16 +966,15 @@ class _FormatTab(QWidget):
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
super().__init__(parent=buildMain)
- self.buildMain = buildMain
- self.mainGui = buildMain.mainGui
- self.mainTheme = buildMain.mainGui.mainTheme
+ self.buildMain = buildMain
+ self.mainGui = buildMain.mainGui
self._build = build
self._unitScale = 1.0
- iPx = self.mainTheme.baseIconSize
- spW = 6*self.mainTheme.textNWidth
- dbW = 8*self.mainTheme.textNWidth
+ iPx = CONFIG.theme.baseIconSize
+ spW = 6*CONFIG.theme.textNWidth
+ dbW = 8*CONFIG.theme.textNWidth
# Text Format Form
# ================
@@ -1003,7 +995,7 @@ class _FormatTab(QWidget):
self.textFont = QLineEdit()
self.textFont.setReadOnly(True)
self.btnTextFont = QPushButton("...")
- self.btnTextFont.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
+ self.btnTextFont.setMaximumWidth(int(2.5*CONFIG.theme.getTextWidth("...")))
self.btnTextFont.clicked.connect(self._selectFont)
self.formFormat.addRow(
self._build.getLabel("format.textFont"), self.textFont, button=self.btnTextFont
@@ -1287,12 +1279,9 @@ class _OutputTab(QWidget):
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
super().__init__(parent=buildMain)
- self.mainGui = buildMain.mainGui
- self.mainTheme = buildMain.mainGui.mainTheme
-
self._build = build
- iPx = self.mainTheme.baseIconSize
+ iPx = CONFIG.theme.baseIconSize
# Left Form
# =========
diff --git a/novelwriter/tools/projwizard.py b/novelwriter/tools/projwizard.py
index f147dd0f..c4f61416 100644
--- a/novelwriter/tools/projwizard.py
+++ b/novelwriter/tools/projwizard.py
@@ -53,10 +53,9 @@ class GuiProjectWizard(QWizard):
logger.debug("Create: GuiProjectWizard")
self.setObjectName("GuiProjectWizard")
- self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
+ self.mainGui = mainGui
- self.sideImage = self.mainTheme.loadDecoration(
+ self.sideImage = CONFIG.theme.loadDecoration(
"wiz-back", None, CONFIG.pxInt(370)
)
self.setWizardStyle(QWizard.ModernStyle)
@@ -92,9 +91,6 @@ class ProjWizardIntroPage(QWizardPage):
def __init__(self, theWizard):
super().__init__()
- self.theWizard = theWizard
- self.mainTheme = theWizard.mainTheme
-
self.setTitle(self.tr("Create New Project"))
self.theText = QLabel(self.tr(
"Provide at least a project name. The project name should not "
@@ -108,7 +104,7 @@ class ProjWizardIntroPage(QWizardPage):
"Peter Mitterhofer", "CC BY-SA 4.0"
))
lblFont = self.imgCredit.font()
- lblFont.setPointSizeF(0.6*self.mainTheme.fontPointSize)
+ lblFont.setPointSizeF(0.6*CONFIG.theme.fontPointSize)
self.imgCredit.setFont(lblFont)
xW = CONFIG.pxInt(300)
@@ -160,9 +156,6 @@ class ProjWizardFolderPage(QWizardPage):
def __init__(self, theWizard):
super().__init__()
- self.theWizard = theWizard
- self.mainTheme = theWizard.mainTheme
-
self.setTitle(self.tr("Select Project Folder"))
self.theText = QLabel(self.tr(
"Select a location to store the project. A new project folder "
@@ -179,7 +172,7 @@ class ProjWizardFolderPage(QWizardPage):
self.projPath.setPlaceholderText(self.tr("Required"))
self.browseButton = QPushButton("...")
- self.browseButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
+ self.browseButton.setMaximumWidth(int(2.5*CONFIG.theme.getTextWidth("...")))
self.browseButton.clicked.connect(self._doBrowse)
self.errLabel = QLabel("")
@@ -257,8 +250,6 @@ class ProjWizardPopulatePage(QWizardPage):
def __init__(self, theWizard):
super().__init__()
- self.theWizard = theWizard
-
self.setTitle(self.tr("Populate Project"))
self.theText = QLabel(self.tr(
"Choose how to pre-fill the project. Either with a minimal set of "
@@ -312,8 +303,6 @@ class ProjWizardCustomPage(QWizardPage):
def __init__(self, theWizard):
super().__init__()
- self.theWizard = theWizard
-
self.setTitle(self.tr("Custom Project Options"))
self.theText = QLabel(self.tr(
"Select which additional elements to populate the project with. "
@@ -412,8 +401,6 @@ class ProjWizardFinalPage(QWizardPage):
def __init__(self, theWizard):
super().__init__()
- self.theWizard = theWizard
-
self.setTitle(self.tr("Summary"))
self.theText = QLabel("")
self.theText.setWordWrap(True)
diff --git a/novelwriter/tools/writingstats.py b/novelwriter/tools/writingstats.py
index c3b0b1b1..2a787294 100644
--- a/novelwriter/tools/writingstats.py
+++ b/novelwriter/tools/writingstats.py
@@ -73,7 +73,6 @@ class GuiWritingStats(QDialog):
self.setWindowFlag(Qt.WindowType.Tool)
self.mainGui = mainGui
- self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self.logData = []
@@ -134,7 +133,7 @@ class GuiWritingStats(QDialog):
self.listBox.setSortingEnabled(True)
# Word Bar
- self.barHeight = int(round(0.5*self.mainTheme.fontPixelSize))
+ self.barHeight = int(round(0.5*CONFIG.theme.fontPixelSize))
self.barWidth = CONFIG.pxInt(200)
self.barImage = QPixmap(self.barHeight, self.barHeight)
self.barImage.fill(self.palette().highlight().color())
@@ -145,27 +144,27 @@ class GuiWritingStats(QDialog):
self.infoBox.setLayout(self.infoForm)
self.labelTotal = QLabel(formatTime(0))
- self.labelTotal.setFont(self.mainTheme.guiFontFixed)
+ self.labelTotal.setFont(CONFIG.theme.guiFontFixed)
self.labelTotal.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.labelIdleT = QLabel(formatTime(0))
- self.labelIdleT.setFont(self.mainTheme.guiFontFixed)
+ self.labelIdleT.setFont(CONFIG.theme.guiFontFixed)
self.labelIdleT.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.labelFilter = QLabel(formatTime(0))
- self.labelFilter.setFont(self.mainTheme.guiFontFixed)
+ self.labelFilter.setFont(CONFIG.theme.guiFontFixed)
self.labelFilter.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.novelWords = QLabel("0")
- self.novelWords.setFont(self.mainTheme.guiFontFixed)
+ self.novelWords.setFont(CONFIG.theme.guiFontFixed)
self.novelWords.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.notesWords = QLabel("0")
- self.notesWords.setFont(self.mainTheme.guiFontFixed)
+ self.notesWords.setFont(CONFIG.theme.guiFontFixed)
self.notesWords.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.totalWords = QLabel("0")
- self.totalWords.setFont(self.mainTheme.guiFontFixed)
+ self.totalWords.setFont(CONFIG.theme.guiFontFixed)
self.totalWords.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
lblTTime = QLabel(self.tr("Total Time:"))
@@ -192,7 +191,7 @@ class GuiWritingStats(QDialog):
self.infoForm.setRowStretch(6, 1)
# Filter Options
- sPx = self.mainTheme.baseIconSize
+ sPx = CONFIG.theme.baseIconSize
self.filterBox = QGroupBox(self.tr("Filters"), self)
self.filterForm = QGridLayout(self)
@@ -589,13 +588,13 @@ class GuiWritingStats(QDialog):
newItem.setTextAlignment(self.C_COUNT, Qt.AlignRight)
newItem.setTextAlignment(self.C_BAR, Qt.AlignLeft | Qt.AlignVCenter)
- newItem.setFont(self.C_TIME, self.mainTheme.guiFontFixed)
- newItem.setFont(self.C_LENGTH, self.mainTheme.guiFontFixed)
- newItem.setFont(self.C_COUNT, self.mainTheme.guiFontFixed)
+ newItem.setFont(self.C_TIME, CONFIG.theme.guiFontFixed)
+ newItem.setFont(self.C_LENGTH, CONFIG.theme.guiFontFixed)
+ newItem.setFont(self.C_COUNT, CONFIG.theme.guiFontFixed)
if showIdleTime:
- newItem.setFont(self.C_IDLE, self.mainTheme.guiFontFixed)
+ newItem.setFont(self.C_IDLE, CONFIG.theme.guiFontFixed)
else:
- newItem.setFont(self.C_IDLE, self.mainTheme.guiFont)
+ newItem.setFont(self.C_IDLE, CONFIG.theme.guiFont)
self.listBox.addTopLevelItem(newItem)
self.timeFilter += sDiff
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index c37f48cd..41d8853b 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,6 +1,6 @@
-
-
+
+
Sample Project
Sample Project
Jane Smith
diff --git a/tests/test_dialogs/test_dlg_about.py b/tests/test_dialogs/test_dlg_about.py
index 1ae7e028..d2ab97a6 100644
--- a/tests/test_dialogs/test_dlg_about.py
+++ b/tests/test_dialogs/test_dlg_about.py
@@ -34,8 +34,6 @@ from novelwriter.dialogs.about import GuiAbout
def testDlgAbout_NWDialog(qtbot, monkeypatch, nwGUI):
"""Test the novelWriter about dialogs."""
# NW About
- nwGUI.mainTheme.themeName = "A Theme"
- nwGUI.mainTheme.themeAuthor = "An Author"
assert nwGUI.showAboutNWDialog(showNotes=True) is True
qtbot.waitUntil(lambda: getGuiItem("GuiAbout") is not None, timeout=1000)
diff --git a/tests/test_gui/test_gui_theme.py b/tests/test_gui/test_gui_theme.py
index 9d193480..2f012229 100644
--- a/tests/test_gui/test_gui_theme.py
+++ b/tests/test_gui/test_gui_theme.py
@@ -33,14 +33,12 @@ from PyQt5.QtWidgets import QApplication
from novelwriter import CONFIG
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
from novelwriter.constants import nwLabels
-from novelwriter.gui.theme import GuiIcons, GuiTheme
@pytest.mark.gui
def testGuiTheme_Main(qtbot, nwGUI, tstPaths):
- """Test the theme class init.
- """
- mainTheme: GuiTheme = nwGUI.mainTheme
+ """Test the theme class init."""
+ mainTheme = CONFIG.theme
# Methods
# =======
@@ -123,7 +121,7 @@ def testGuiTheme_Main(qtbot, nwGUI, tstPaths):
@pytest.mark.gui
def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI):
"""Test the theme part of the class."""
- mainTheme: GuiTheme = nwGUI.mainTheme
+ mainTheme = CONFIG.theme
# List Themes
# ===========
@@ -200,9 +198,8 @@ def testGuiTheme_Theme(qtbot, monkeypatch, nwGUI):
@pytest.mark.gui
def testGuiTheme_Syntax(qtbot, monkeypatch, nwGUI):
- """Test the syntax part of the class.
- """
- mainTheme: GuiTheme = nwGUI.mainTheme
+ """Test the syntax part of the class."""
+ mainTheme = CONFIG.theme
# List Themes
# ===========
@@ -266,9 +263,8 @@ def testGuiTheme_Syntax(qtbot, monkeypatch, nwGUI):
@pytest.mark.gui
def testGuiTheme_Icons(qtbot, caplog, monkeypatch, nwGUI, tstPaths):
- """Test the icon cache class.
- """
- iconCache: GuiIcons = nwGUI.mainTheme.iconCache
+ """Test the icon cache class."""
+ iconCache = CONFIG.theme.iconCache
# Load Theme
# ==========
From 12897ff2e15fd7d9c4610d2b33a53f35c82fc74b Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 8 Aug 2023 17:21:00 +0200
Subject: [PATCH 02/10] Make project instance private to main GUI class
---
novelwriter/core/projectdata.py | 36 +++---
novelwriter/dialogs/docmerge.py | 5 +-
novelwriter/dialogs/docsplit.py | 11 +-
novelwriter/dialogs/preferences.py | 3 +-
novelwriter/dialogs/projdetails.py | 42 +++----
novelwriter/dialogs/projsettings.py | 61 +++++-----
novelwriter/dialogs/wordlist.py | 14 +--
novelwriter/gui/components.py | 5 +-
novelwriter/gui/doceditor.py | 45 ++++---
novelwriter/gui/dochighlight.py | 5 +-
novelwriter/gui/docviewer.py | 28 ++---
novelwriter/gui/itemdetails.py | 5 +-
novelwriter/gui/mainmenu.py | 27 ++--
novelwriter/gui/noveltree.py | 50 ++++----
novelwriter/gui/outline.py | 38 +++---
novelwriter/gui/projtree.py | 122 +++++++++----------
novelwriter/guimain.py | 79 ++++++------
novelwriter/tools/manusbuild.py | 17 ++-
novelwriter/tools/manuscript.py | 26 ++--
novelwriter/tools/manussettings.py | 21 ++--
novelwriter/tools/writingstats.py | 9 +-
tests/mocked.py | 7 +-
tests/test_dialogs/test_dlg_docsplit.py | 2 +-
tests/test_dialogs/test_dlg_projdetails.py | 2 +-
tests/test_dialogs/test_dlg_projsettings.py | 8 +-
tests/test_dialogs/test_dlg_wordlist.py | 2 +-
tests/test_gui/test_gui_doceditor.py | 20 +--
tests/test_gui/test_gui_docviewer.py | 6 +-
tests/test_gui/test_gui_guimain.py | 32 ++---
tests/test_gui/test_gui_noveltree.py | 2 +-
tests/test_gui/test_gui_outline.py | 6 +-
tests/test_gui/test_gui_projtree.py | 66 +++++-----
tests/test_gui/test_gui_statusbar.py | 4 +-
tests/test_tools/test_tools_manuscript.py | 4 +-
tests/test_tools/test_tools_manussettings.py | 26 ++--
tests/test_tools/test_tools_writingstats.py | 2 +-
tests/tools.py | 72 +++++------
37 files changed, 445 insertions(+), 465 deletions(-)
diff --git a/novelwriter/core/projectdata.py b/novelwriter/core/projectdata.py
index 7deb8d0f..18927271 100644
--- a/novelwriter/core/projectdata.py
+++ b/novelwriter/core/projectdata.py
@@ -43,9 +43,9 @@ class NWProjectData:
the list of project items.
"""
- def __init__(self, theProject):
+ def __init__(self, project):
- self.theProject = theProject
+ self._project = project
# Project Meta
self._uuid = ""
@@ -187,13 +187,13 @@ class NWProjectData:
def incSaveCount(self):
"""Increment the save count by one."""
self._saveCount += 1
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def incAutoCount(self):
"""Increment the auto save count by one."""
self._autoCount += 1
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
##
@@ -215,74 +215,74 @@ class NWProjectData:
self._uuid = str(uuid.uuid4())
elif value != self._uuid:
self._uuid = value
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def setName(self, value: str | None):
"""Set a new project name."""
if value != self._name:
self._name = simplified(str(value or ""))
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def setTitle(self, value: str | None):
"""Set a new novel title."""
if value != self._title:
self._title = simplified(str(value or ""))
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def setAuthor(self, value: str | None):
"""Set the author value."""
if value != self._title:
self._author = simplified(str(value or ""))
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def setSaveCount(self, value: Any):
"""Set the save count from last session."""
self._saveCount = checkInt(value, 0)
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def setAutoCount(self, value: Any):
"""Set the auto save count from last session."""
self._autoCount = checkInt(value, 0)
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def setEditTime(self, value: Any):
"""Set the edit time from last session."""
self._editTime = checkInt(value, 0)
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def setDoBackup(self, value: Any):
"""Set the do write backup flag."""
if value != self._doBackup:
self._doBackup = checkBool(value, False)
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def setLanguage(self, value: str | None):
"""Set the project language."""
if value != self._language:
self._language = checkStringNone(value, None)
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def setSpellCheck(self, value: Any):
"""Set the spell check flag."""
if value != self._spellCheck:
self._spellCheck = checkBool(value, False)
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def setSpellLang(self, value: str | None):
"""Set the spell check language."""
if value != self._spellLang:
self._spellLang = checkStringNone(value, None)
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def setLastHandle(self, value: str | None, component: str):
@@ -291,7 +291,7 @@ class NWProjectData:
"""
if isinstance(component, str):
self._lastHandle[component] = checkStringNone(value, None)
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def setLastHandles(self, value: dict):
@@ -302,7 +302,7 @@ class NWProjectData:
for key, entry in value.items():
if key in self._lastHandle:
self._lastHandle[key] = str(entry) if isHandle(entry) else None
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
def setInitCounts(self, novel: Any = None, notes: Any = None):
@@ -330,7 +330,7 @@ class NWProjectData:
for key, entry in value.items():
if isinstance(entry, str):
self._autoReplace[key] = simplified(entry)
- self.theProject.setProjectChanged(True)
+ self._project.setProjectChanged(True)
return
# END Class NWProjectData
diff --git a/novelwriter/dialogs/docmerge.py b/novelwriter/dialogs/docmerge.py
index a7b3630b..5ad908a4 100644
--- a/novelwriter/dialogs/docmerge.py
+++ b/novelwriter/dialogs/docmerge.py
@@ -49,8 +49,7 @@ class GuiDocMerge(QDialog):
logger.debug("Create: GuiDocMerge")
self.setObjectName("GuiDocMerge")
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
self._data = {}
@@ -156,7 +155,7 @@ class GuiDocMerge(QDialog):
self.listBox.clear()
for tHandle in itemList:
- nwItem = self.theProject.tree[tHandle]
+ nwItem = self.mainGui.project.tree[tHandle]
if nwItem is None or not nwItem.isFileType():
continue
diff --git a/novelwriter/dialogs/docsplit.py b/novelwriter/dialogs/docsplit.py
index a87658d9..b68613a2 100644
--- a/novelwriter/dialogs/docsplit.py
+++ b/novelwriter/dialogs/docsplit.py
@@ -51,8 +51,7 @@ class GuiDocSplit(QDialog):
logger.debug("Create: GuiDocSplit")
self.setObjectName("GuiDocSplit")
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
self._data = {}
self._text = []
@@ -71,7 +70,7 @@ class GuiDocSplit(QDialog):
vSp = CONFIG.pxInt(8)
bSp = CONFIG.pxInt(12)
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
spLevel = pOptions.getInt("GuiDocSplit", "spLevel", 3)
intoFolder = pOptions.getBool("GuiDocSplit", "intoFolder", True)
docHierarchy = pOptions.getBool("GuiDocSplit", "docHierarchy", True)
@@ -170,7 +169,7 @@ class GuiDocSplit(QDialog):
self._data["docHierarchy"] = docHierarchy
self._data["moveToTrash"] = moveToTrash
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
pOptions.setValue("GuiDocSplit", "spLevel", spLevel)
pOptions.setValue("GuiDocSplit", "intoFolder", intoFolder)
pOptions.setValue("GuiDocSplit", "docHierarchy", docHierarchy)
@@ -200,13 +199,13 @@ class GuiDocSplit(QDialog):
self.listBox.clear()
- nwItem = self.theProject.tree[sHandle]
+ nwItem = self.mainGui.project.tree[sHandle]
if nwItem is None or not nwItem.isFileType():
return
spLevel = self.splitLevel.currentData()
if not self._text:
- inDoc = self.theProject.storage.getDocument(sHandle)
+ inDoc = self.mainGui.project.storage.getDocument(sHandle)
self._text = (inDoc.readDocument() or "").splitlines()
for lineNo, aLine in enumerate(self._text):
diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py
index d4c9819d..08a4d5b9 100644
--- a/novelwriter/dialogs/preferences.py
+++ b/novelwriter/dialogs/preferences.py
@@ -49,8 +49,7 @@ class GuiPreferences(NPagedDialog):
logger.debug("Create: GuiPreferences")
self.setObjectName("GuiPreferences")
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
self.setWindowTitle(self.tr("Preferences"))
diff --git a/novelwriter/dialogs/projdetails.py b/novelwriter/dialogs/projdetails.py
index b28d0d8f..68a6b3b6 100644
--- a/novelwriter/dialogs/projdetails.py
+++ b/novelwriter/dialogs/projdetails.py
@@ -51,14 +51,13 @@ class GuiProjectDetails(NPagedDialog):
logger.debug("Create: GuiProjectDetails")
self.setObjectName("GuiProjectDetails")
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
self.setWindowTitle(self.tr("Project Details"))
wW = CONFIG.pxInt(600)
wH = CONFIG.pxInt(400)
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
self.setMinimumWidth(wW)
self.setMinimumHeight(wH)
@@ -67,8 +66,8 @@ class GuiProjectDetails(NPagedDialog):
CONFIG.pxInt(pOptions.getInt("GuiProjectDetails", "winHeight", wH))
)
- self.tabMain = GuiProjectDetailsMain(self.mainGui, self.theProject)
- self.tabContents = GuiProjectDetailsContents(self.mainGui, self.theProject)
+ self.tabMain = GuiProjectDetailsMain(self.mainGui)
+ self.tabContents = GuiProjectDetailsContents(self.mainGui)
self.addTab(self.tabMain, self.tr("Overview"))
self.addTab(self.tabContents, self.tr("Contents"))
@@ -125,7 +124,7 @@ class GuiProjectDetails(NPagedDialog):
countFrom = self.tabContents.poValue.value()
clearDouble = self.tabContents.dblValue.isChecked()
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
pOptions.setValue("GuiProjectDetails", "winWidth", winWidth)
pOptions.setValue("GuiProjectDetails", "winHeight", winHeight)
pOptions.setValue("GuiProjectDetails", "widthCol0", widthCol0)
@@ -144,11 +143,10 @@ class GuiProjectDetails(NPagedDialog):
class GuiProjectDetailsMain(QWidget):
- def __init__(self, mainGui, theProject):
+ def __init__(self, mainGui):
super().__init__(parent=mainGui)
- self.theProject = theProject
- self.mainGui = mainGui
+ self.mainGui = mainGui
fPx = CONFIG.theme.fontPixelSize
fPt = CONFIG.theme.fontPointSize
@@ -246,22 +244,23 @@ class GuiProjectDetailsMain(QWidget):
def updateValues(self):
"""Set all the values.
"""
- pIndex = self.theProject.index
+ project = self.mainGui.project
+ pIndex = project.index
hCounts = pIndex.getNovelTitleCounts()
nwCount = pIndex.getNovelWordCount()
- edTime = self.theProject.getCurrentEditTime()
+ edTime = project.getCurrentEditTime()
- self.bookTitle.setText(self.theProject.data.title or self.theProject.data.name)
- self.projName.setText(self.tr("Project: {0}").format(self.theProject.data.name))
- self.bookAuthors.setText(self.tr("By {0}").format(self.theProject.data.author))
+ self.bookTitle.setText(project.data.title or project.data.name)
+ self.projName.setText(self.tr("Project: {0}").format(project.data.name))
+ self.bookAuthors.setText(self.tr("By {0}").format(project.data.author))
self.wordCountVal.setText(f"{nwCount:n}")
self.chapCountVal.setText(f"{hCounts[2]:n}")
self.sceneCountVal.setText(f"{hCounts[3]:n}")
- self.revCountVal.setText(f"{self.theProject.data.saveCount:n}")
+ self.revCountVal.setText(f"{project.data.saveCount:n}")
self.editTimeVal.setText(formatTime(edTime))
- self.projPathVal.setText(str(self.theProject.storage.storagePath))
+ self.projPathVal.setText(str(project.storage.storagePath))
return
@@ -276,11 +275,10 @@ class GuiProjectDetailsContents(QWidget):
C_PAGE = 3
C_PROG = 4
- def __init__(self, mainGui, theProject):
+ def __init__(self, mainGui):
super().__init__(parent=mainGui)
- self.theProject = theProject
- self.mainGui = mainGui
+ self.mainGui = mainGui
# Internal
self._theToC = []
@@ -289,14 +287,14 @@ class GuiProjectDetailsContents(QWidget):
iPx = CONFIG.theme.baseIconSize
hPx = CONFIG.pxInt(12)
vPx = CONFIG.pxInt(4)
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
# Header
# ======
self.tocLabel = QLabel("%s" % self.tr("Table of Contents"))
- self.novelValue = NovelSelector(self, self.theProject, self.mainGui)
+ self.novelValue = NovelSelector(self, self.mainGui)
self.novelValue.setMinimumWidth(CONFIG.pxInt(200))
self.novelValue.novelSelectionChanged.connect(self._novelValueChanged)
@@ -445,7 +443,7 @@ class GuiProjectDetailsContents(QWidget):
"""Extract the information from the project index.
"""
logger.debug("Populating ToC from handle '%s'", rootHandle)
- self._theToC = self.theProject.index.getTableOfContents(rootHandle, 2)
+ self._theToC = self.mainGui.project.index.getTableOfContents(rootHandle, 2)
self._theToC.append(("", 0, self.tr("END"), 0))
return
diff --git a/novelwriter/dialogs/projsettings.py b/novelwriter/dialogs/projsettings.py
index cd9c8e00..92b22454 100644
--- a/novelwriter/dialogs/projsettings.py
+++ b/novelwriter/dialogs/projsettings.py
@@ -60,15 +60,13 @@ class GuiProjectSettings(NPagedDialog):
logger.debug("Create: GuiProjectSettings")
self.setObjectName("GuiProjectSettings")
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
-
- self.theProject.countStatus()
+ self.mainGui = mainGui
+ self.mainGui.project.countStatus()
self.setWindowTitle(self.tr("Project Settings"))
wW = CONFIG.pxInt(570)
wH = CONFIG.pxInt(375)
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
self.setMinimumWidth(wW)
self.setMinimumHeight(wH)
@@ -117,34 +115,35 @@ class GuiProjectSettings(NPagedDialog):
def _doSave(self):
"""Save settings and close dialog.
"""
+ project = self.mainGui.project
projName = self.tabMain.editName.text()
bookTitle = self.tabMain.editTitle.text()
bookAuthor = self.tabMain.editAuthor.text()
spellLang = self.tabMain.spellLang.currentData()
doBackup = not self.tabMain.doBackup.isChecked()
- self.theProject.data.setName(projName)
- self.theProject.data.setTitle(bookTitle)
- self.theProject.data.setAuthor(bookAuthor)
- self.theProject.data.setDoBackup(doBackup)
+ project.data.setName(projName)
+ project.data.setTitle(bookTitle)
+ project.data.setAuthor(bookAuthor)
+ project.data.setDoBackup(doBackup)
# Remember this as updating spell dictionary can be expensive
- self._spellChanged = self.theProject.data.setSpellLang(spellLang)
+ self._spellChanged = project.data.setSpellLang(spellLang)
if self.tabStatus.colChanged:
newList, delList = self.tabStatus.getNewList()
- self.theProject.setStatusColours(newList, delList)
+ project.setStatusColours(newList, delList)
if self.tabImport.colChanged:
newList, delList = self.tabImport.getNewList()
- self.theProject.setImportColours(newList, delList)
+ project.setImportColours(newList, delList)
if self.tabStatus.colChanged or self.tabImport.colChanged:
self.mainGui.rebuildTrees()
if self.tabReplace.arChanged:
newList = self.tabReplace.getNewList()
- self.theProject.data.setAutoReplace(newList)
+ project.data.setAutoReplace(newList)
self._saveGuiSettings()
self.accept()
@@ -184,7 +183,7 @@ class GuiProjectSettings(NPagedDialog):
statusColW = CONFIG.rpxInt(self.tabStatus.listBox.columnWidth(0))
importColW = CONFIG.rpxInt(self.tabImport.listBox.columnWidth(0))
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
pOptions.setValue("GuiProjectSettings", "winWidth", winWidth)
pOptions.setValue("GuiProjectSettings", "winHeight", winHeight)
pOptions.setValue("GuiProjectSettings", "replaceColW", replaceColW)
@@ -201,8 +200,7 @@ class GuiProjectEditMain(QWidget):
def __init__(self, projGui):
super().__init__(parent=projGui)
- self.mainGui = projGui.mainGui
- self.theProject = projGui.theProject
+ self.mainGui = projGui.mainGui
# The Form
self.mainForm = NConfigLayout()
@@ -212,11 +210,12 @@ class GuiProjectEditMain(QWidget):
self.mainForm.addGroupLabel(self.tr("Project Settings"))
xW = CONFIG.pxInt(250)
+ pData = self.mainGui.project.data
self.editName = QLineEdit()
self.editName.setMaxLength(200)
self.editName.setMaximumWidth(xW)
- self.editName.setText(self.theProject.data.name)
+ self.editName.setText(pData.name)
self.mainForm.addRow(
self.tr("Project name"),
self.editName,
@@ -226,7 +225,7 @@ class GuiProjectEditMain(QWidget):
self.editTitle = QLineEdit()
self.editTitle.setMaxLength(200)
self.editTitle.setMaximumWidth(xW)
- self.editTitle.setText(self.theProject.data.title)
+ self.editTitle.setText(pData.title)
self.mainForm.addRow(
self.tr("Novel title"),
self.editTitle,
@@ -236,7 +235,7 @@ class GuiProjectEditMain(QWidget):
self.editAuthor = QLineEdit()
self.editAuthor.setMaxLength(200)
self.editAuthor.setMaximumWidth(xW)
- self.editAuthor.setText(self.theProject.data.author)
+ self.editAuthor.setText(pData.author)
self.mainForm.addRow(
self.tr("Author(s)"),
self.editAuthor,
@@ -259,13 +258,13 @@ class GuiProjectEditMain(QWidget):
)
spellIdx = 0
- if self.theProject.data.spellLang is not None:
- spellIdx = self.spellLang.findData(self.theProject.data.spellLang)
+ if pData.spellLang is not None:
+ spellIdx = self.spellLang.findData(pData.spellLang)
if spellIdx != -1:
self.spellLang.setCurrentIndex(spellIdx)
self.doBackup = NSwitch(self)
- self.doBackup.setChecked(not self.theProject.data.doBackup)
+ self.doBackup.setChecked(not pData.doBackup)
self.mainForm.addRow(
self.tr("No backup on close"),
self.doBackup,
@@ -289,20 +288,19 @@ class GuiProjectEditStatus(QWidget):
def __init__(self, projGui, isStatus):
super().__init__(parent=projGui)
- self.mainGui = projGui.mainGui
- self.theProject = projGui.theProject
+ self.mainGui = projGui.mainGui
if isStatus:
- self.theStatus = self.theProject.data.itemStatus
+ self.theStatus = self.mainGui.project.data.itemStatus
pageLabel = self.tr("Novel File Status Levels")
colSetting = "statusColW"
else:
- self.theStatus = self.theProject.data.itemImport
+ self.theStatus = self.mainGui.project.data.itemImport
pageLabel = self.tr("Note File Importance Levels")
colSetting = "importColW"
wCol0 = CONFIG.pxInt(
- self.theProject.options.getInt("GuiProjectSettings", colSetting, 130)
+ self.mainGui.project.options.getInt("GuiProjectSettings", colSetting, 130)
)
self.colDeleted = []
@@ -576,12 +574,11 @@ class GuiProjectEditReplace(QWidget):
def __init__(self, projGui):
super().__init__(parent=projGui)
- self.mainGui = projGui.mainGui
- self.theProject = projGui.theProject
- self.arChanged = False
+ self.mainGui = projGui.mainGui
+ self.arChanged = False
wCol0 = CONFIG.pxInt(
- self.theProject.options.getInt("GuiProjectSettings", "replaceColW", 130)
+ self.mainGui.project.options.getInt("GuiProjectSettings", "replaceColW", 130)
)
pageLabel = self.tr("Text Replace List for Preview and Export")
@@ -597,7 +594,7 @@ class GuiProjectEditReplace(QWidget):
self.listBox.setColumnWidth(self.COL_KEY, wCol0)
self.listBox.setIndentation(0)
- for aKey, aVal in self.theProject.data.autoReplace.items():
+ for aKey, aVal in self.mainGui.project.data.autoReplace.items():
newItem = QTreeWidgetItem(["<%s>" % aKey, aVal])
self.listBox.addTopLevelItem(newItem)
diff --git a/novelwriter/dialogs/wordlist.py b/novelwriter/dialogs/wordlist.py
index faeefb41..ad549298 100644
--- a/novelwriter/dialogs/wordlist.py
+++ b/novelwriter/dialogs/wordlist.py
@@ -50,16 +50,14 @@ class GuiWordList(QDialog):
logger.debug("Create: GuiWordList")
self.setObjectName("GuiWordList")
-
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
-
self.setWindowTitle(self.tr("Project Word List"))
+ self.mainGui = mainGui
+
mS = CONFIG.pxInt(250)
wW = CONFIG.pxInt(320)
wH = CONFIG.pxInt(340)
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
self.setMinimumWidth(mS)
self.setMinimumHeight(mS)
@@ -151,7 +149,7 @@ class GuiWordList(QDialog):
def _doSave(self):
"""Save the new word list and close."""
self._saveGuiSettings()
- userDict = UserDictionary(self.theProject)
+ userDict = UserDictionary(self.mainGui.project)
for i in range(self.listBox.count()):
item = self.listBox.item(i)
if isinstance(item, QListWidgetItem):
@@ -174,7 +172,7 @@ class GuiWordList(QDialog):
def _loadWordList(self):
"""Load the project's word list, if it exists."""
- userDict = UserDictionary(self.theProject)
+ userDict = UserDictionary(self.mainGui.project)
userDict.load()
self.listBox.clear()
for word in userDict:
@@ -187,7 +185,7 @@ class GuiWordList(QDialog):
winWidth = CONFIG.rpxInt(self.width())
winHeight = CONFIG.rpxInt(self.height())
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
pOptions.setValue("GuiWordList", "winWidth", winWidth)
pOptions.setValue("GuiWordList", "winHeight", winHeight)
diff --git a/novelwriter/gui/components.py b/novelwriter/gui/components.py
index fe73cb5a..ffa19af1 100644
--- a/novelwriter/gui/components.py
+++ b/novelwriter/gui/components.py
@@ -41,11 +41,10 @@ class NovelSelector(QComboBox):
novelSelectionChanged = pyqtSignal(str)
- def __init__(self, parent, project, mainGui):
+ def __init__(self, parent, mainGui):
super().__init__(parent=parent)
self._mainGui = mainGui
- self._project = project
self._blockSignal = False
self._firstHandle = None
@@ -91,7 +90,7 @@ class NovelSelector(QComboBox):
icon = CONFIG.theme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL])
handle = self.currentData()
- for tHandle, nwItem in self._project.tree.iterRoots(nwItemClass.NOVEL):
+ for tHandle, nwItem in self._mainGui.project.tree.iterRoots(nwItemClass.NOVEL):
if prefix:
name = prefix.format(nwItem.itemName)
self.addItem(name, tHandle)
diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py
index ac1cc0cf..876172e1 100644
--- a/novelwriter/gui/doceditor.py
+++ b/novelwriter/gui/doceditor.py
@@ -84,8 +84,7 @@ class GuiDocEditor(QTextEdit):
logger.debug("Create: GuiDocEditor")
# Class Variables
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
self._nwDocument = None
self._nwItem = None
@@ -133,7 +132,7 @@ class GuiDocEditor(QTextEdit):
self.docSearch = GuiDocEditSearch(self)
# Syntax
- self.spEnchant = NWSpellEnchant(self.theProject)
+ self.spEnchant = NWSpellEnchant(self.mainGui.project)
self.highLight = GuiDocHighlighter(qDoc, self.mainGui, self.spEnchant)
# Context Menu
@@ -341,7 +340,7 @@ class GuiDocEditor(QTextEdit):
document is new (empty string), we set up the editor for editing
the file.
"""
- self._nwDocument = self.theProject.storage.getDocument(tHandle)
+ self._nwDocument = self.mainGui.project.storage.getDocument(tHandle)
self._nwItem = self._nwDocument.getCurrentItem()
theDoc = self._nwDocument.readDocument()
@@ -517,10 +516,10 @@ class GuiDocEditor(QTextEdit):
self.setDocumentChanged(False)
oldHeader = self._nwItem.mainHeading
- oldCount = self.theProject.index.getHandleHeaderCount(tHandle)
- self.theProject.index.scanText(tHandle, docText)
+ oldCount = self.mainGui.project.index.getHandleHeaderCount(tHandle)
+ self.mainGui.project.index.scanText(tHandle, docText)
newHeader = self._nwItem.mainHeading
- newCount = self.theProject.index.getHandleHeaderCount(tHandle)
+ newCount = self.mainGui.project.index.getHandleHeaderCount(tHandle)
if self._nwItem.itemClass == nwItemClass.NOVEL:
if oldCount == newCount:
@@ -699,10 +698,10 @@ class GuiDocEditor(QTextEdit):
"""Set the spell checker dictionary language, and emit the
dictionary changed signal.
"""
- if self.theProject.data.spellLang is None:
+ if self.mainGui.project.data.spellLang is None:
theLang = CONFIG.spellLanguage
else:
- theLang = self.theProject.data.spellLang
+ theLang = self.mainGui.project.data.spellLang
self.spEnchant.setLanguage(theLang)
_, theProvider = self.spEnchant.describeDict()
@@ -735,7 +734,7 @@ class GuiDocEditor(QTextEdit):
self._spellCheck = theMode
self.mainGui.mainMenu.setSpellCheck(theMode)
- self.theProject.data.setSpellCheck(theMode)
+ self.mainGui.project.data.setSpellCheck(theMode)
self.highLight.setSpellCheck(theMode)
if not self._bigDoc or theMode is False:
# We don't run the spell checker automatically on big docs
@@ -1917,7 +1916,7 @@ class GuiDocEditor(QTextEdit):
if theText.startswith("@"):
- isGood, tBits, tPos = self.theProject.index.scanThis(theText)
+ isGood, tBits, tPos = self.mainGui.project.index.scanThis(theText)
if not isGood:
return False
@@ -2222,9 +2221,8 @@ class GuiDocEditSearch(QFrame):
logger.debug("Create: GuiDocEditSearch")
- self.docEditor = docEditor
- self.mainGui = docEditor.mainGui
- self.theProject = docEditor.theProject
+ self.docEditor = docEditor
+ self.mainGui = docEditor.mainGui
self.repVisible = False
self.isCaseSense = CONFIG.searchCase
@@ -2636,9 +2634,8 @@ class GuiDocEditHeader(QWidget):
logger.debug("Create: GuiDocEditHeader")
- self.docEditor = docEditor
- self.mainGui = docEditor.mainGui
- self.theProject = docEditor.theProject
+ self.docEditor = docEditor
+ self.mainGui = docEditor.mainGui
self._docHandle = None
@@ -2775,17 +2772,18 @@ class GuiDocEditHeader(QWidget):
self.minmaxButton.setVisible(False)
return True
+ pTree = self.mainGui.project.tree
if CONFIG.showFullPath:
tTitle = []
- tTree = self.theProject.tree.getItemPath(tHandle)
+ tTree = pTree.getItemPath(tHandle)
for aHandle in reversed(tTree):
- nwItem = self.theProject.tree[aHandle]
+ nwItem = pTree[aHandle]
if nwItem is not None:
tTitle.append(nwItem.itemName)
sSep = " %s " % nwUnicode.U_RSAQUO
self.theTitle.setText(sSep.join(tTitle))
else:
- nwItem = self.theProject.tree[tHandle]
+ nwItem = pTree[tHandle]
if nwItem is None:
return False
self.theTitle.setText(nwItem.itemName)
@@ -2870,9 +2868,8 @@ class GuiDocEditFooter(QWidget):
logger.debug("Create: GuiDocEditFooter")
- self.docEditor = docEditor
- self.mainGui = docEditor.mainGui
- self.theProject = docEditor.theProject
+ self.docEditor = docEditor
+ self.mainGui = docEditor.mainGui
self._theItem = None
self._docHandle = None
@@ -3003,7 +3000,7 @@ class GuiDocEditFooter(QWidget):
logger.debug("No handle set, so clearing the editor footer")
self._theItem = None
else:
- self._theItem = self.theProject.tree[self._docHandle]
+ self._theItem = self.mainGui.project.tree[self._docHandle]
self.setHasSelection(False)
self.updateInfo()
diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py
index 8fbc307e..355a0b54 100644
--- a/novelwriter/gui/dochighlight.py
+++ b/novelwriter/gui/dochighlight.py
@@ -54,7 +54,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
self.theDoc = theDoc
self.spEnchant = spEnchant
self.mainGui = mainGui
- self.theProject = mainGui.theProject
self.theHandle = None
self.spellCheck = False
self.spellRx = None
@@ -286,8 +285,8 @@ class GuiDocHighlighter(QSyntaxHighlighter):
if theText.startswith("@"): # Keywords and commands
self.setCurrentBlockState(self.BLOCK_META)
- pIndex = self.theProject.index
- tItem = self.mainGui.theProject.tree[self.theHandle]
+ pIndex = self.mainGui.project.index
+ tItem = self.mainGui.project.tree[self.theHandle]
isValid, theBits, thePos = pIndex.scanThis(theText)
isGood = pIndex.checkThese(theBits, tItem)
if isValid:
diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py
index 8cfd2073..c532d430 100644
--- a/novelwriter/gui/docviewer.py
+++ b/novelwriter/gui/docviewer.py
@@ -59,8 +59,7 @@ class GuiDocViewer(QTextBrowser):
logger.debug("Create: GuiDocViewer")
# Class Variables
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
# Internal Variables
self._docHandle = None
@@ -163,7 +162,7 @@ class GuiDocViewer(QTextBrowser):
def loadText(self, tHandle, updateHistory=True):
"""Load text into the viewer from an item handle.
"""
- if not self.theProject.tree.checkType(tHandle, nwItemType.FILE):
+ if not self.mainGui.project.tree.checkType(tHandle, nwItemType.FILE):
logger.warning("Item not found")
return False
@@ -171,7 +170,7 @@ class GuiDocViewer(QTextBrowser):
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
sPos = self.verticalScrollBar().value()
- aDoc = ToHtml(self.theProject)
+ aDoc = ToHtml(self.mainGui.project)
aDoc.setPreview(CONFIG.viewComments, CONFIG.viewSynopsis)
aDoc.setLinkHeaders(True)
@@ -211,7 +210,7 @@ class GuiDocViewer(QTextBrowser):
self.verticalScrollBar().setValue(sPos)
self._docHandle = tHandle
- self.theProject._data.setLastHandle(tHandle, "viewer")
+ self.mainGui.project.data.setLastHandle(tHandle, "viewer")
self.docHeader.setTitleFromHandle(self._docHandle)
self.updateDocMargins()
@@ -680,9 +679,8 @@ class GuiDocViewHeader(QWidget):
logger.debug("Create: GuiDocViewHeader")
- self.docViewer = docViewer
- self.mainGui = docViewer.mainGui
- self.theProject = docViewer.theProject
+ self.docViewer = docViewer
+ self.mainGui = docViewer.mainGui
# Internal Variables
self._docHandle = None
@@ -821,17 +819,18 @@ class GuiDocViewHeader(QWidget):
self.refreshButton.setVisible(False)
return True
+ pTree = self.mainGui.project.tree
if CONFIG.showFullPath:
tTitle = []
- tTree = self.theProject.tree.getItemPath(tHandle)
+ tTree = pTree.getItemPath(tHandle)
for aHandle in reversed(tTree):
- nwItem = self.theProject.tree[aHandle]
+ nwItem = pTree[aHandle]
if nwItem is not None:
tTitle.append(nwItem.itemName)
sSep = " %s " % nwUnicode.U_RSAQUO
self.theTitle.setText(sSep.join(tTitle))
else:
- nwItem = self.theProject.tree[tHandle]
+ nwItem = pTree[tHandle]
if nwItem is None:
return False
self.theTitle.setText(nwItem.itemName)
@@ -1138,8 +1137,7 @@ class GuiDocViewDetails(QScrollArea):
logger.debug("Create: GuiDocViewDetails")
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
self.refList = QLabel("")
self.refList.setWordWrap(True)
@@ -1174,10 +1172,10 @@ class GuiDocViewDetails(QScrollArea):
if self.mainGui.docViewer.stickyRef:
return
- theRefs = self.theProject.index.getBackReferenceList(tHandle)
+ theRefs = self.mainGui.project.index.getBackReferenceList(tHandle)
theList = []
for tHandle in theRefs:
- tItem = self.theProject.tree[tHandle]
+ tItem = self.mainGui.project.tree[tHandle]
if tItem is not None:
theList.append("%s" % (
tHandle, theRefs[tHandle], self.linkStyle, tItem.itemName
diff --git a/novelwriter/gui/itemdetails.py b/novelwriter/gui/itemdetails.py
index 4c1faf6f..6270f2f0 100644
--- a/novelwriter/gui/itemdetails.py
+++ b/novelwriter/gui/itemdetails.py
@@ -42,8 +42,7 @@ class GuiItemDetails(QWidget):
logger.debug("Create: GuiItemDetails")
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
# Internal Variables
self._itemHandle = None
@@ -234,7 +233,7 @@ class GuiItemDetails(QWidget):
self.clearDetails()
return
- nwItem = self.theProject.tree[tHandle]
+ nwItem = self.mainGui.project.tree[tHandle]
if nwItem is None:
self.clearDetails()
return
diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py
index 80b1f8ae..f74f7f18 100644
--- a/novelwriter/gui/mainmenu.py
+++ b/novelwriter/gui/mainmenu.py
@@ -51,8 +51,7 @@ class GuiMainMenu(QMenuBar):
logger.debug("Create: GuiMainMenu")
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
# Build Menu
self._buildProjectMenu()
@@ -380,10 +379,10 @@ class GuiMainMenu(QMenuBar):
"""Assemble the Insert menu.
"""
# Insert
- self.insertMenu = self.addMenu(self.tr("&Insert"))
+ self.insMenu = self.addMenu(self.tr("&Insert"))
# Insert > Dashes and Dots
- self.mInsDashes = self.insertMenu.addMenu(self.tr("Dashes"))
+ self.mInsDashes = self.insMenu.addMenu(self.tr("Dashes"))
# Insert > Short Dash
self.aInsENDash = QAction(self.tr("Short Dash"), self)
@@ -410,7 +409,7 @@ class GuiMainMenu(QMenuBar):
self.mInsDashes.addAction(self.aInsFigDash)
# Insert > Quote Marks
- self.mInsQuotes = self.insertMenu.addMenu(self.tr("Quote Marks"))
+ self.mInsQuotes = self.insMenu.addMenu(self.tr("Quote Marks"))
# Insert > Left Single Quote
self.aInsQuoteLS = QAction(self.tr("Left Single Quote"), self)
@@ -443,7 +442,7 @@ class GuiMainMenu(QMenuBar):
self.mInsQuotes.addAction(self.aInsMSApos)
# Insert > Symbols
- self.mInsPunct = self.insertMenu.addMenu(self.tr("General Punctuation"))
+ self.mInsPunct = self.insMenu.addMenu(self.tr("General Punctuation"))
# Insert > Ellipsis
self.aInsEllipsis = QAction(self.tr("Ellipsis"), self)
@@ -464,7 +463,7 @@ class GuiMainMenu(QMenuBar):
self.mInsPunct.addAction(self.aInsDPrime)
# Insert > White Spaces
- self.mInsSpace = self.insertMenu.addMenu(self.tr("White Spaces"))
+ self.mInsSpace = self.insMenu.addMenu(self.tr("White Spaces"))
# Insert > Non-Breaking Space
self.aInsNBSpace = QAction(self.tr("Non-Breaking Space"), self)
@@ -485,7 +484,7 @@ class GuiMainMenu(QMenuBar):
self.mInsSpace.addAction(self.aInsThinNBSpace)
# Insert > Symbols
- self.mInsSymbol = self.insertMenu.addMenu(self.tr("Other Symbols"))
+ self.mInsSymbol = self.insMenu.addMenu(self.tr("Other Symbols"))
# Insert > List Bullet
self.aInsBullet = QAction(self.tr("List Bullet"), self)
@@ -536,7 +535,7 @@ class GuiMainMenu(QMenuBar):
self.mInsSymbol.addAction(self.aInsDivide)
# Insert > Tags and References
- self.mInsKeywords = self.insertMenu.addMenu(self.tr("Tags and References"))
+ self.mInsKeywords = self.insMenu.addMenu(self.tr("Tags and References"))
self.mInsKWItems = {}
self.mInsKWItems[nwKeyWords.TAG_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, G")
self.mInsKWItems[nwKeyWords.POV_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, V")
@@ -557,7 +556,7 @@ class GuiMainMenu(QMenuBar):
self.mInsKeywords.addAction(self.mInsKWItems[keyWord][0])
# Insert > Special Comments
- self.mInsComments = self.insertMenu.addMenu(self.tr("Special Comments"))
+ self.mInsComments = self.insMenu.addMenu(self.tr("Special Comments"))
# Insert > Synopsis Comment
self.aInsSynopsis = QAction(self.tr("Synopsis Comment"), self)
@@ -566,7 +565,7 @@ class GuiMainMenu(QMenuBar):
self.mInsComments.addAction(self.aInsSynopsis)
# Insert > Symbols
- self.mInsBreaks = self.insertMenu.addMenu(self.tr("Page Break and Space"))
+ self.mInsBreaks = self.insMenu.addMenu(self.tr("Page Break and Space"))
# Insert > New Page
self.aInsNewPage = QAction(self.tr("Page Break"), self)
@@ -586,7 +585,7 @@ class GuiMainMenu(QMenuBar):
# Insert > Placeholder Text
self.aLipsumText = QAction(self.tr("Placeholder Text"), self)
self.aLipsumText.triggered.connect(lambda: self.mainGui.showLoremIpsumDialog())
- self.insertMenu.addAction(self.aLipsumText)
+ self.insMenu.addAction(self.aLipsumText)
return
@@ -796,7 +795,7 @@ class GuiMainMenu(QMenuBar):
# Tools > Check Spelling
self.aSpellCheck = QAction(self.tr("Check Spelling"), self)
self.aSpellCheck.setCheckable(True)
- self.aSpellCheck.setChecked(self.theProject.data.spellCheck)
+ self.aSpellCheck.setChecked(self.mainGui.project.data.spellCheck)
self.aSpellCheck.triggered.connect(self._toggleSpellCheck) # triggered, not toggled!
self.aSpellCheck.setShortcut("Ctrl+F7")
self.toolsMenu.addAction(self.aSpellCheck)
@@ -826,7 +825,7 @@ class GuiMainMenu(QMenuBar):
# Tools > Backup Project
self.aBackupProject = QAction(self.tr("Backup Project"), self)
- self.aBackupProject.triggered.connect(lambda: self.theProject.backupProject(True))
+ self.aBackupProject.triggered.connect(lambda: self.mainGui.project.backupProject(True))
self.toolsMenu.addAction(self.aBackupProject)
# Tools > Build Manuscript
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index b04db81f..fda64471 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -66,8 +66,7 @@ class GuiNovelView(QWidget):
def __init__(self, mainGui):
super().__init__(parent=mainGui)
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
# Build GUI
self.novelTree = GuiNovelTree(self)
@@ -118,16 +117,16 @@ class GuiNovelView(QWidget):
def openProjectTasks(self):
"""Run open project tasks.
"""
- lastNovel = self.theProject.data.getLastHandle("novelTree")
- if lastNovel not in self.theProject.tree:
- lastNovel = self.theProject.tree.findRoot(nwItemClass.NOVEL)
+ lastNovel = self.mainGui.project.data.getLastHandle("novelTree")
+ if lastNovel not in self.mainGui.project.tree:
+ lastNovel = self.mainGui.project.tree.findRoot(nwItemClass.NOVEL)
logger.debug("Setting novel tree to root item '%s'", lastNovel)
- lastCol = self.theProject.options.getEnum(
+ lastCol = self.mainGui.project.options.getEnum(
"GuiNovelView", "lastCol", NovelTreeColumn, NovelTreeColumn.HIDDEN
)
- lastColSize = self.theProject.options.getInt(
+ lastColSize = self.mainGui.project.options.getInt(
"GuiNovelView", "lastColSize", 25
)
@@ -147,8 +146,9 @@ class GuiNovelView(QWidget):
"""
lastColType = self.novelTree.lastColType
lastColSize = self.novelTree.lastColSize
- self.theProject.options.setValue("GuiNovelView", "lastCol", lastColType)
- self.theProject.options.setValue("GuiNovelView", "lastColSize", lastColSize)
+ pOptions = self.mainGui.project.options
+ pOptions.setValue("GuiNovelView", "lastCol", lastColType)
+ pOptions.setValue("GuiNovelView", "lastColSize", lastColSize)
return
def setTreeFocus(self):
@@ -170,7 +170,7 @@ class GuiNovelView(QWidget):
def refreshTree(self):
"""Refresh the current tree.
"""
- self.novelTree.refreshTree(rootHandle=self.theProject.data.getLastHandle("novelTree"))
+ self.novelTree.refreshTree(rootHandle=self.mainGui.project.data.getLastHandle("novelTree"))
return
@pyqtSlot(str)
@@ -198,9 +198,8 @@ class GuiNovelToolBar(QWidget):
logger.debug("Create: GuiNovelToolBar")
- self.novelView = novelView
- self.mainGui = novelView.mainGui
- self.theProject = novelView.mainGui.theProject
+ self.novelView = novelView
+ self.mainGui = novelView.mainGui
iPx = CONFIG.theme.baseIconSize
mPx = CONFIG.pxInt(2)
@@ -212,7 +211,7 @@ class GuiNovelToolBar(QWidget):
selFont = self.font()
selFont.setWeight(QFont.Bold)
self.novelPrefix = self.tr("Outline of {0}")
- self.novelValue = NovelSelector(self, self.theProject, self.mainGui)
+ self.novelValue = NovelSelector(self, self.mainGui)
self.novelValue.setFont(selFont)
self.novelValue.setMinimumWidth(CONFIG.pxInt(150))
self.novelValue.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
@@ -346,7 +345,7 @@ class GuiNovelToolBar(QWidget):
def _refreshNovelTree(self):
"""Rebuild the current tree.
"""
- rootHandle = self.theProject.data.getLastHandle("novelTree")
+ rootHandle = self.mainGui.project.data.getLastHandle("novelTree")
self.novelView.novelTree.refreshTree(rootHandle=rootHandle, overRide=True)
return
@@ -398,9 +397,8 @@ class GuiNovelTree(QTreeWidget):
logger.debug("Create: GuiNovelTree")
- self.novelView = novelView
- self.mainGui = novelView.mainGui
- self.theProject = novelView.mainGui.theProject
+ self.novelView = novelView
+ self.mainGui = novelView.mainGui
# Internal Variables
self._treeMap = {}
@@ -516,10 +514,10 @@ class GuiNovelTree(QTreeWidget):
"""
logger.debug("Requesting refresh of the novel tree")
if rootHandle is None:
- rootHandle = self.theProject.tree.findRoot(nwItemClass.NOVEL)
+ rootHandle = self.mainGui.project.tree.findRoot(nwItemClass.NOVEL)
treeChanged = self.mainGui.projView.changedSince(self._lastBuild)
- indexChanged = self.theProject.index.rootChangedSince(rootHandle, self._lastBuild)
+ indexChanged = self.mainGui.project.index.rootChangedSince(rootHandle, self._lastBuild)
if not (treeChanged or indexChanged or overRide):
logger.debug("No changes have been made to the novel index")
return
@@ -530,7 +528,7 @@ class GuiNovelTree(QTreeWidget):
titleKey = selItem[0].data(self.C_DATA, self.D_KEY)
self._populateTree(rootHandle)
- self.theProject.data.setLastHandle(rootHandle, "novelTree")
+ self.mainGui.project.data.setLastHandle(rootHandle, "novelTree")
if titleKey is not None and titleKey in self._treeMap:
self._treeMap[titleKey].setSelected(True)
@@ -540,7 +538,7 @@ class GuiNovelTree(QTreeWidget):
def refreshHandle(self, tHandle):
"""Refresh the data for a given handle.
"""
- idxData = self.theProject.index.getItemData(tHandle)
+ idxData = self.mainGui.project.index.getItemData(tHandle)
if idxData is None:
return
@@ -577,7 +575,7 @@ class GuiNovelTree(QTreeWidget):
self._lastCol = colType
self.setColumnHidden(self.C_EXTRA, colType == NovelTreeColumn.HIDDEN)
if doRefresh:
- lastNovel = self.theProject.data.getLastHandle("novelTree")
+ lastNovel = self.mainGui.project.data.getLastHandle("novelTree")
self.refreshTree(rootHandle=lastNovel, overRide=True)
return
@@ -709,7 +707,7 @@ class GuiNovelTree(QTreeWidget):
tStart = time()
logger.debug("Building novel tree for root item '%s'", rootHandle)
- novStruct = self.theProject.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
+ novStruct = self.mainGui.project.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
for tKey, tHandle, sTitle, novIdx in novStruct:
if novIdx.level == "H0":
continue
@@ -761,7 +759,7 @@ class GuiNovelTree(QTreeWidget):
refData = []
refName = ""
- theRefs = self.theProject.index.getReferences(tHandle, sTitle)
+ theRefs = self.mainGui.project.index.getReferences(tHandle, sTitle)
if self._lastCol == NovelTreeColumn.POV:
refData = theRefs[nwKeyWords.POV_KEY]
refName = self._povLabel
@@ -785,7 +783,7 @@ class GuiNovelTree(QTreeWidget):
"""
logger.debug("Generating meta data tooltip for '%s:%s'", tHandle, sTitle)
- pIndex = self.theProject.index
+ pIndex = self.mainGui.project.index
novIdx = pIndex.getItemHeader(tHandle, sTitle)
refTags = pIndex.getReferences(tHandle, sTitle)
diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py
index bcc3ef24..93b94ee8 100644
--- a/novelwriter/gui/outline.py
+++ b/novelwriter/gui/outline.py
@@ -62,8 +62,7 @@ class GuiOutlineView(QWidget):
def __init__(self, mainGui):
super().__init__(parent=mainGui)
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
# Build GUI
self.outlineTree = GuiOutlineTree(self)
@@ -118,7 +117,7 @@ class GuiOutlineView(QWidget):
def refreshTree(self):
"""Refresh the current tree.
"""
- self.outlineTree.refreshTree(rootHandle=self.theProject.data.getLastHandle("outline"))
+ self.outlineTree.refreshTree(rootHandle=self.mainGui.project.data.getLastHandle("outline"))
return
def clearProject(self):
@@ -131,9 +130,9 @@ class GuiOutlineView(QWidget):
def openProjectTasks(self):
"""Run open project tasks.
"""
- lastOutline = self.theProject.data.getLastHandle("outline")
- if not (lastOutline in self.theProject.tree or lastOutline is None):
- lastOutline = self.theProject.tree.findRoot(nwItemClass.NOVEL)
+ lastOutline = self.mainGui.project.data.getLastHandle("outline")
+ if not (lastOutline in self.mainGui.project.tree or lastOutline is None):
+ lastOutline = self.mainGui.project.tree.findRoot(nwItemClass.NOVEL)
logger.debug("Setting outline tree to root item '%s'", lastOutline)
@@ -215,8 +214,7 @@ class GuiOutlineToolBar(QToolBar):
logger.debug("Create: GuiOutlineToolBar")
- self.mainGui = theOutline.mainGui
- self.theProject = theOutline.mainGui.theProject
+ self.mainGui = theOutline.mainGui
iPx = CONFIG.pxInt(22)
mPx = CONFIG.pxInt(12)
@@ -232,7 +230,7 @@ class GuiOutlineToolBar(QToolBar):
self.novelLabel = QLabel(self.tr("Outline of"))
self.novelLabel.setContentsMargins(0, 0, mPx, 0)
- self.novelValue = NovelSelector(self, self.theProject, self.mainGui)
+ self.novelValue = NovelSelector(self, self.mainGui)
self.novelValue.setMinimumWidth(CONFIG.pxInt(200))
self.novelValue.novelSelectionChanged.connect(self._novelValueChanged)
@@ -373,7 +371,6 @@ class GuiOutlineTree(QTreeWidget):
self.outlineView = outlineView
self.mainGui = outlineView.mainGui
- self.theProject = outlineView.mainGui.theProject
self.setUniformRowHeights(True)
self.setFrameStyle(QFrame.NoFrame)
@@ -491,13 +488,13 @@ class GuiOutlineTree(QTreeWidget):
# If the novel index or novel tree has changed since the tree
# was last built, we rebuild the tree from the updated index.
- indexChanged = self.theProject.index.rootChangedSince(rootHandle, self._lastBuild)
+ indexChanged = self.mainGui.project.index.rootChangedSince(rootHandle, self._lastBuild)
if not (novelChanged or indexChanged or overRide):
logger.debug("No changes have been made to the novel index")
return
self._populateTree(rootHandle)
- self.theProject.data.setLastHandle(rootHandle or None, "outline")
+ self.mainGui.project.data.setLastHandle(rootHandle or None, "outline")
return
@@ -577,7 +574,7 @@ class GuiOutlineTree(QTreeWidget):
"""
# Load whatever we saved last time, regardless of wether it
# contains the correct names or number of columns.
- colState = self.theProject.options.getValue("GuiOutline", "columnState", {})
+ colState = self.mainGui.project.options.getValue("GuiOutline", "columnState", {})
tmpOrder = []
tmpHidden = {}
@@ -628,7 +625,7 @@ class GuiOutlineTree(QTreeWidget):
logHidden, orgWidth if logHidden and logWidth == 0 else logWidth
]
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
pOptions.setValue("GuiOutline", "columnState", colState)
pOptions.saveSettings()
@@ -664,7 +661,7 @@ class GuiOutlineTree(QTreeWidget):
headItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], Qt.AlignRight)
headItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], Qt.AlignRight)
- novStruct = self.theProject.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
+ novStruct = self.mainGui.project.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
for _, tHandle, sTitle, novIdx in novStruct:
iLevel = nwHeaders.H_LEVEL.get(novIdx.level, 0)
@@ -672,7 +669,7 @@ class GuiOutlineTree(QTreeWidget):
continue
trItem = QTreeWidgetItem()
- nwItem = self.theProject.tree[tHandle]
+ nwItem = self.mainGui.project.tree[tHandle]
hDec = CONFIG.theme.getHeaderDecoration(iLevel)
trItem.setData(self._colIdx[nwOutline.TITLE], Qt.DecorationRole, hDec)
@@ -692,7 +689,7 @@ class GuiOutlineTree(QTreeWidget):
trItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], Qt.AlignRight)
trItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], Qt.AlignRight)
- refs = self.theProject.index.getReferences(tHandle, sTitle)
+ refs = self.mainGui.project.index.getReferences(tHandle, sTitle)
trItem.setText(self._colIdx[nwOutline.POV], ", ".join(refs[nwKeyWords.POV_KEY]))
trItem.setText(self._colIdx[nwOutline.FOCUS], ", ".join(refs[nwKeyWords.FOCUS_KEY]))
trItem.setText(self._colIdx[nwOutline.CHAR], ", ".join(refs[nwKeyWords.CHAR_KEY]))
@@ -774,7 +771,6 @@ class GuiOutlineDetails(QScrollArea):
self.theOutline = theOutline
self.mainGui = theOutline.mainGui
- self.theProject = theOutline.mainGui.theProject
# Sizes
minTitle = 30*CONFIG.theme.textNWidth
@@ -1009,8 +1005,8 @@ class GuiOutlineDetails(QScrollArea):
"""Update the content of the tree with the given handle and line
number pointing to a header.
"""
- pIndex = self.theProject.index
- nwItem = self.theProject.tree[tHandle]
+ pIndex = self.mainGui.project.index
+ nwItem = self.mainGui.project.tree[tHandle]
novIdx = pIndex.getItemHeader(tHandle, sTitle)
theRefs = pIndex.getReferences(tHandle, sTitle)
if nwItem is None or novIdx is None:
@@ -1053,7 +1049,7 @@ class GuiOutlineDetails(QScrollArea):
def updateClasses(self):
"""Update the visibility status of class details.
"""
- usedClasses = self.theProject.tree.rootClasses()
+ usedClasses = self.mainGui.project.tree.rootClasses()
pltVisible = nwItemClass.PLOT in usedClasses
timVisible = nwItemClass.TIMELINE in usedClasses
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index 22c40d44..f45de16f 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -233,10 +233,9 @@ class GuiProjectToolBar(QWidget):
logger.debug("Create: GuiProjectToolBar")
- self.projView = projView
- self.projTree = projView.projTree
- self.mainGui = projView.mainGui
- self.theProject = projView.mainGui.theProject
+ self.projView = projView
+ self.projTree = projView.projTree
+ self.mainGui = projView.mainGui
iPx = CONFIG.theme.baseIconSize
mPx = CONFIG.pxInt(2)
@@ -394,7 +393,7 @@ class GuiProjectToolBar(QWidget):
"""Build the quick link menu."""
logger.debug("Rebuilding quick links menu")
self.mQuick.clear()
- for n, (tHandle, nwItem) in enumerate(self.theProject.tree.iterRoots(None)):
+ for n, (tHandle, nwItem) in enumerate(self.mainGui.project.tree.iterRoots(None)):
aRoot = self.mQuick.addAction(nwItem.itemName)
aRoot.setData(tHandle)
aRoot.setIcon(CONFIG.theme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass]))
@@ -440,7 +439,7 @@ class GuiProjectToolBar(QWidget):
documents. They should only be visible if novel documents can
actually be added.
"""
- nwItem = self.theProject.tree[tHandle]
+ nwItem = self.mainGui.project.tree[tHandle]
allowDoc = isinstance(nwItem, NWItem) and nwItem.documentAllowed()
self.aAddEmpty.setVisible(allowDoc)
self.aAddChap.setVisible(allowDoc)
@@ -466,9 +465,8 @@ class GuiProjectTree(QTreeWidget):
logger.debug("Create: GuiProjectTree")
- self.projView = projView
- self.mainGui = projView.mainGui
- self.theProject = projView.mainGui.theProject
+ self.projView = projView
+ self.mainGui = projView.mainGui
# Internal Variables
self._treeMap = {}
@@ -575,15 +573,15 @@ class GuiProjectTree(QTreeWidget):
if itemType == nwItemType.ROOT and isinstance(itemClass, nwItemClass):
- tHandle = self.theProject.newRoot(itemClass)
+ tHandle = self.mainGui.project.newRoot(itemClass)
sHandle = self.getSelectedHandle()
- pItem = self.theProject.tree[sHandle] if sHandle else None
+ pItem = self.mainGui.project.tree[sHandle] if sHandle else None
nHandle = pItem.itemRoot if pItem else None
elif itemType in (nwItemType.FILE, nwItemType.FOLDER):
sHandle = self.getSelectedHandle()
- pItem = self.theProject.tree[sHandle] if sHandle else None
+ pItem = self.mainGui.project.tree[sHandle] if sHandle else None
if sHandle is None or pItem is None:
self.mainGui.makeAlert(self.tr(
"Did not find anywhere to add the file or folder!"
@@ -595,7 +593,7 @@ class GuiProjectTree(QTreeWidget):
sLevel = nwHeaders.H_LEVEL.get(pItem.mainHeading, 0)
sIsParent = False if qItem is None else qItem.childCount() > 0
- if self.theProject.tree.isTrash(sHandle):
+ if self.mainGui.project.tree.isTrash(sHandle):
self.mainGui.makeAlert(self.tr(
"Cannot add new files or folders to the Trash folder."
), level=nwAlert.ERROR)
@@ -638,9 +636,9 @@ class GuiProjectTree(QTreeWidget):
# Add the file or folder
if itemType == nwItemType.FILE:
- tHandle = self.theProject.newFile(newLabel, sHandle)
+ tHandle = self.mainGui.project.newFile(newLabel, sHandle)
else:
- tHandle = self.theProject.newFolder(newLabel, sHandle)
+ tHandle = self.mainGui.project.newFolder(newLabel, sHandle)
else:
logger.error("Failed to add new item")
@@ -653,7 +651,7 @@ class GuiProjectTree(QTreeWidget):
# Handle new file creation
if itemType == nwItemType.FILE and hLevel > 0:
- self.theProject.writeNewFile(tHandle, hLevel, not isNote)
+ self.mainGui.project.writeNewFile(tHandle, hLevel, not isNote)
# Add the new item to the project tree
self.revealNewTreeItem(tHandle, nHandle=nHandle, wordCount=True)
@@ -664,7 +662,7 @@ class GuiProjectTree(QTreeWidget):
def revealNewTreeItem(self, tHandle: str | None, nHandle: str | None = None,
wordCount: bool = False) -> bool:
"""Reveal a newly added project item in the project tree."""
- nwItem = self.theProject.tree[tHandle] if tHandle else None
+ nwItem = self.mainGui.project.tree[tHandle] if tHandle else None
if tHandle is None or nwItem is None:
return False
@@ -673,7 +671,7 @@ class GuiProjectTree(QTreeWidget):
return False
if nwItem.isFileType() and wordCount:
- wC = self.theProject.index.getCounts(tHandle)[1]
+ wC = self.mainGui.project.index.getCounts(tHandle)[1]
self.propagateCount(tHandle, wC)
self.projView.wordCountsChanged.emit()
@@ -748,7 +746,7 @@ class GuiProjectTree(QTreeWidget):
def renameTreeItem(self, tHandle: str) -> bool:
"""Open a dialog to edit the label of an item."""
- tItem = self.theProject.tree[tHandle]
+ tItem = self.mainGui.project.tree[tHandle]
if tItem is None:
return False
@@ -772,7 +770,7 @@ class GuiProjectTree(QTreeWidget):
if isinstance(item, QTreeWidgetItem):
theList = self._scanChildren(theList, item, i)
logger.debug("Saving project tree item order")
- self.theProject.setTreeOrder(theList)
+ self.mainGui.project.setTreeOrder(theList)
return
def getTreeFromHandle(self, tHandle: str) -> list[str]:
@@ -805,16 +803,16 @@ class GuiProjectTree(QTreeWidget):
logger.error("There is no item to delete")
return False
- trashHandle = self.theProject.tree.trashRoot()
+ trashHandle = self.mainGui.project.tree.trashRoot()
if tHandle == trashHandle:
logger.error("Cannot delete the Trash folder")
return False
- nwItem = self.theProject.tree[tHandle]
+ nwItem = self.mainGui.project.tree[tHandle]
if nwItem is None:
return False
- if self.theProject.tree.isTrash(tHandle) or nwItem.isRootType():
+ if self.mainGui.project.tree.isTrash(tHandle) or nwItem.isRootType():
status = self.permDeleteItem(tHandle)
else:
status = self.moveItemToTrash(tHandle)
@@ -830,7 +828,7 @@ class GuiProjectTree(QTreeWidget):
logger.error("No project open")
return False
- trashHandle = self.theProject.tree.trashRoot()
+ trashHandle = self.mainGui.project.tree.trashRoot()
logger.debug("Emptying Trash folder")
if trashHandle is None:
@@ -873,13 +871,13 @@ class GuiProjectTree(QTreeWidget):
so such a request is cancelled.
"""
trItemS = self._getTreeItem(tHandle)
- nwItemS = self.theProject.tree[tHandle]
+ nwItemS = self.mainGui.project.tree[tHandle]
if trItemS is None or nwItemS is None:
logger.error("Could not find tree item for deletion")
return False
- if self.theProject.tree.isTrash(tHandle):
+ if self.mainGui.project.tree.isTrash(tHandle):
logger.error("Item is already in the Trash folder")
return False
@@ -923,7 +921,7 @@ class GuiProjectTree(QTreeWidget):
Root items are handled a little different than other items.
"""
trItemS = self._getTreeItem(tHandle)
- nwItemS = self.theProject.tree[tHandle]
+ nwItemS = self.mainGui.project.tree[tHandle]
if trItemS is None or nwItemS is None:
logger.error("Could not find tree item for deletion")
return False
@@ -940,7 +938,7 @@ class GuiProjectTree(QTreeWidget):
tIndex = self.indexOfTopLevelItem(trItemS)
self.takeTopLevelItem(tIndex)
- self.theProject.removeItem(tHandle)
+ self.mainGui.project.removeItem(tHandle)
self._treeMap.pop(tHandle, None)
self._alertTreeChange(tHandle, flush=True)
@@ -969,7 +967,7 @@ class GuiProjectTree(QTreeWidget):
for dHandle in reversed(self.getTreeFromHandle(tHandle)):
if self.mainGui.docEditor.docHandle() == dHandle:
self.mainGui.closeDocument()
- self.theProject.removeItem(dHandle)
+ self.mainGui.project.removeItem(dHandle)
self._treeMap.pop(dHandle, None)
self._alertTreeChange(tHandle, flush=flush)
@@ -987,7 +985,7 @@ class GuiProjectTree(QTreeWidget):
already coming from the project tree.
"""
trItem = self._getTreeItem(tHandle)
- nwItem = self.theProject.tree[tHandle]
+ nwItem = self.mainGui.project.tree[tHandle]
if trItem is None or nwItem is None:
return
@@ -1049,10 +1047,10 @@ class GuiProjectTree(QTreeWidget):
pHandle = pItem.data(self.C_DATA, self.D_HANDLE)
if pHandle:
- if self.theProject.tree.checkType(pHandle, nwItemType.FILE):
+ if self.mainGui.project.tree.checkType(pHandle, nwItemType.FILE):
# A file has an internal word count we need to account
# for, but a folder always has 0 words on its own.
- pCount += self.theProject.index.getCounts(pHandle)[1]
+ pCount += self.mainGui.project.index.getCounts(pHandle)[1]
self.propagateCount(pHandle, pCount, countChildren=False)
@@ -1067,7 +1065,7 @@ class GuiProjectTree(QTreeWidget):
logger.debug("Building the project tree ...")
self.clearTree()
count = 0
- for nwItem in self.theProject.getProjectItems():
+ for nwItem in self.mainGui.project.getProjectItems():
count += 1
self._addTreeItem(nwItem)
if count > 0:
@@ -1180,7 +1178,7 @@ class GuiProjectTree(QTreeWidget):
if tHandle is None:
return
- tItem = self.theProject.tree[tHandle]
+ tItem = self.mainGui.project.tree[tHandle]
if tItem is None:
return
@@ -1202,7 +1200,7 @@ class GuiProjectTree(QTreeWidget):
selItem = self.itemAt(clickPos)
if isinstance(selItem, QTreeWidgetItem):
tHandle = selItem.data(self.C_DATA, self.D_HANDLE)
- tItem = self.theProject.tree[tHandle]
+ tItem = self.mainGui.project.tree[tHandle]
hasChild = selItem.childCount() > 0
if tItem is None or tHandle is None:
@@ -1214,7 +1212,7 @@ class GuiProjectTree(QTreeWidget):
# Trash Folder
# ============
- trashHandle = self.theProject.tree.trashRoot()
+ trashHandle = self.mainGui.project.tree.trashRoot()
if tItem.itemHandle == trashHandle and trashHandle is not None:
# The trash folder only has one option
aEmptyTrash = ctxMenu.addAction(self.tr("Empty Trash"))
@@ -1253,7 +1251,7 @@ class GuiProjectTree(QTreeWidget):
checkMark = f" ({nwUnicode.U_CHECK})"
if tItem.isNovelLike():
mStatus = ctxMenu.addMenu(self.tr("Set Status to ..."))
- for n, (key, entry) in enumerate(self.theProject.data.itemStatus.items()):
+ for n, (key, entry) in enumerate(self.mainGui.project.data.itemStatus.items()):
entryName = entry["name"] + (checkMark if tItem.itemStatus == key else "")
aStatus = mStatus.addAction(entry["icon"], entryName)
aStatus.triggered.connect(
@@ -1266,7 +1264,7 @@ class GuiProjectTree(QTreeWidget):
)
else:
mImport = ctxMenu.addMenu(self.tr("Set Importance to ..."))
- for n, (key, entry) in enumerate(self.theProject.data.itemImport.items()):
+ for n, (key, entry) in enumerate(self.mainGui.project.data.itemImport.items()):
entryName = entry["name"] + (checkMark if tItem.itemImport == key else "")
aImport = mImport.addAction(entry["icon"], entryName)
aImport.triggered.connect(
@@ -1378,7 +1376,7 @@ class GuiProjectTree(QTreeWidget):
return
tHandle = selItem.data(self.C_DATA, self.D_HANDLE)
- tItem = self.theProject.tree[tHandle]
+ tItem = self.mainGui.project.tree[tHandle]
if tItem is None:
return
@@ -1422,7 +1420,7 @@ class GuiProjectTree(QTreeWidget):
def _postItemMove(self, tHandle: str, wCount: int) -> bool:
"""Run various maintenance tasks for a moved item."""
trItemS = self._getTreeItem(tHandle)
- nwItemS = self.theProject.tree[tHandle]
+ nwItemS = self.mainGui.project.tree[tHandle]
trItemP = trItemS.parent() if trItemS else None
if trItemP is None or nwItemS is None:
logger.error("Failed to find new parent item of '%s'", tHandle)
@@ -1439,13 +1437,13 @@ class GuiProjectTree(QTreeWidget):
logger.debug("A total of %d item(s) were moved", len(mHandles))
for mHandle in mHandles:
logger.debug("Updating item '%s'", mHandle)
- self.theProject.tree.updateItemData(mHandle)
+ self.mainGui.project.tree.updateItemData(mHandle)
# Update the index
if nwItemS.isInactiveClass():
- self.theProject.index.deleteHandle(mHandle)
+ self.mainGui.project.index.deleteHandle(mHandle)
else:
- self.theProject.index.reIndexHandle(mHandle)
+ self.mainGui.project.index.reIndexHandle(mHandle)
self.setTreeItemValues(mHandle)
@@ -1465,7 +1463,7 @@ class GuiProjectTree(QTreeWidget):
def _toggleItemActive(self, tHandle: str) -> None:
"""Toggle the active status of an item."""
- tItem = self.theProject.tree[tHandle]
+ tItem = self.mainGui.project.tree[tHandle]
if tItem is not None:
tItem.setActive(not tItem.isActive)
self.setTreeItemValues(tItem.itemHandle)
@@ -1486,7 +1484,7 @@ class GuiProjectTree(QTreeWidget):
def _changeItemStatus(self, tHandle: str, tStatus: str) -> None:
"""Set a new status value of an item."""
- tItem = self.theProject.tree[tHandle]
+ tItem = self.mainGui.project.tree[tHandle]
if tItem is not None:
tItem.setStatus(tStatus)
self.setTreeItemValues(tItem.itemHandle)
@@ -1495,7 +1493,7 @@ class GuiProjectTree(QTreeWidget):
def _changeItemImport(self, tHandle: str, tImport: str) -> None:
"""Set a new importance value of an item."""
- tItem = self.theProject.tree[tHandle]
+ tItem = self.mainGui.project.tree[tHandle]
if tItem is not None:
tItem.setImport(tImport)
self.setTreeItemValues(tItem.itemHandle)
@@ -1504,7 +1502,7 @@ class GuiProjectTree(QTreeWidget):
def _changeItemLayout(self, tHandle: str, itemLayout: nwItemLayout) -> None:
"""Set a new item layout value of an item."""
- tItem = self.theProject.tree[tHandle]
+ tItem = self.mainGui.project.tree[tHandle]
if tItem is not None:
if itemLayout == nwItemLayout.DOCUMENT and tItem.documentAllowed():
tItem.setLayout(nwItemLayout.DOCUMENT)
@@ -1518,7 +1516,7 @@ class GuiProjectTree(QTreeWidget):
def _covertFolderToFile(self, tHandle: str, itemLayout: nwItemLayout) -> None:
"""Convert a folder to a note or document."""
- tItem = self.theProject.tree[tHandle]
+ tItem = self.mainGui.project.tree[tHandle]
if tItem is not None and tItem.isFolderType():
msgYes = self.mainGui.askQuestion(self.tr(
"Do you want to convert the folder to a {0}? "
@@ -1543,7 +1541,7 @@ class GuiProjectTree(QTreeWidget):
logger.info("Request to merge items under handle '%s'", tHandle)
itemList = self.getTreeFromHandle(tHandle)
- tItem = self.theProject.tree[tHandle]
+ tItem = self.mainGui.project.tree[tHandle]
if tItem is None:
return False
@@ -1569,7 +1567,7 @@ class GuiProjectTree(QTreeWidget):
self.mainGui.saveDocument()
# Create merge object, and append docs
- docMerger = DocMerger(self.theProject)
+ docMerger = DocMerger(self.mainGui.project)
mLabel = self.tr("Merged")
if newFile:
@@ -1591,7 +1589,7 @@ class GuiProjectTree(QTreeWidget):
)
return False
- self.theProject.index.reIndexHandle(mHandle)
+ self.mainGui.project.index.reIndexHandle(mHandle)
if newFile:
self.revealNewTreeItem(mHandle, nHandle=tHandle, wordCount=True)
@@ -1616,7 +1614,7 @@ class GuiProjectTree(QTreeWidget):
"""Split a document into multiple documents."""
logger.info("Request to split items with handle '%s'", tHandle)
- tItem = self.theProject.tree[tHandle]
+ tItem = self.mainGui.project.tree[tHandle]
if tItem is None:
return False
@@ -1635,7 +1633,7 @@ class GuiProjectTree(QTreeWidget):
intoFolder = splitData.get("intoFolder", False)
docHierarchy = splitData.get("docHierarchy", False)
- docSplit = DocSplitter(self.theProject, tHandle)
+ docSplit = DocSplitter(self.mainGui.project, tHandle)
if intoFolder:
fHandle = docSplit.newParentFolder(tItem.itemParent, tItem.itemName)
self.revealNewTreeItem(fHandle, nHandle=tHandle)
@@ -1645,7 +1643,7 @@ class GuiProjectTree(QTreeWidget):
docSplit.splitDocument(headerList, splitText)
for writeOk, dHandle, nHandle in docSplit.writeDocuments(docHierarchy):
- self.theProject.index.reIndexHandle(dHandle)
+ self.mainGui.project.index.reIndexHandle(dHandle)
self.revealNewTreeItem(dHandle, nHandle=nHandle, wordCount=True)
self._alertTreeChange(dHandle, flush=False)
if not writeOk:
@@ -1679,10 +1677,10 @@ class GuiProjectTree(QTreeWidget):
if not self.mainGui.askQuestion(question):
return False
- docDup = DocDuplicator(self.theProject)
+ docDup = DocDuplicator(self.mainGui.project)
dupCount = 0
for dHandle, nHandle in docDup.duplicate(itemTree):
- self.theProject.index.reIndexHandle(dHandle)
+ self.mainGui.project.index.reIndexHandle(dHandle)
self.revealNewTreeItem(dHandle, nHandle=nHandle, wordCount=True)
self._alertTreeChange(dHandle, flush=False)
dupCount += 1
@@ -1702,7 +1700,7 @@ class GuiProjectTree(QTreeWidget):
cCount = tItem.childCount()
# Update tree-related meta data
- nwItem = self.theProject.tree[tHandle]
+ nwItem = self.mainGui.project.tree[tHandle]
if nwItem is not None:
nwItem.setExpanded(tItem.isExpanded() and cCount > 0)
nwItem.setOrder(tIndex)
@@ -1769,13 +1767,13 @@ class GuiProjectTree(QTreeWidget):
"""Adds the trash root folder if it doesn't already exist in the
project tree.
"""
- trashHandle = self.theProject.trashFolder()
+ trashHandle = self.mainGui.project.trashFolder()
if trashHandle is None:
return None
trItem = self._getTreeItem(trashHandle)
if trItem is None:
- trItem = self._addTreeItem(self.theProject.tree[trashHandle])
+ trItem = self._addTreeItem(self.mainGui.project.tree[trashHandle])
if trItem is not None:
trItem.setExpanded(True)
self._alertTreeChange(trashHandle, flush=True)
@@ -1788,14 +1786,14 @@ class GuiProjectTree(QTreeWidget):
deleted.
"""
self._timeChanged = time()
- self.theProject.setProjectChanged(True)
+ self.mainGui.project.setProjectChanged(True)
if flush:
self.saveTreeOrder()
- if tHandle is None or tHandle not in self.theProject.tree:
+ if tHandle is None or tHandle not in self.mainGui.project.tree:
return
- tItem = self.theProject.tree[tHandle]
+ tItem = self.mainGui.project.tree[tHandle]
if tItem and tItem.isRootType():
self.projView.rootFolderChanged.emit(tHandle)
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index ac4025a9..ab728dfe 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -114,7 +114,7 @@ class GuiMain(QMainWindow):
# Core Classes
CONFIG.setThemeInstance(GuiTheme())
- self.theProject = NWProject(self)
+ self._project = NWProject(self)
# Core Settings
self.hasProject = False
@@ -238,7 +238,7 @@ class GuiMain(QMainWindow):
# Connect Signals
# ===============
- self.theProject.projectStatusChanged.connect(self.mainStatus.doUpdateProjectStatus)
+ self._project.projectStatusChanged.connect(self.mainStatus.doUpdateProjectStatus)
self.viewsBar.viewChangeRequested.connect(self._changeView)
@@ -382,6 +382,15 @@ class GuiMain(QMainWindow):
return
+ ##
+ # Properties
+ ##
+
+ @property
+ def project(self) -> NWProject:
+ """The project instance."""
+ return self._project
+
##
# Project Actions
##
@@ -444,7 +453,7 @@ class GuiMain(QMainWindow):
saveOK = self.saveProject()
doBackup = False
- if self.theProject.data.doBackup and CONFIG.backupOnClose:
+ if self._project.data.doBackup and CONFIG.backupOnClose:
doBackup = True
if CONFIG.askBeforeBackup:
msgYes = self.askQuestion(self.tr("Backup the current project?"))
@@ -452,7 +461,7 @@ class GuiMain(QMainWindow):
doBackup = False
if doBackup:
- self.theProject.backupProject(False)
+ self._project.backupProject(False)
if saveOK:
self.closeDocument()
@@ -460,7 +469,7 @@ class GuiMain(QMainWindow):
self.outlineView.closeProjectTasks()
self.novelView.closeProjectTasks()
- self.theProject.closeProject(self.idleTime)
+ self._project.closeProject(self.idleTime)
self.idleRefTime = time()
self.idleTime = 0.0
@@ -484,9 +493,9 @@ class GuiMain(QMainWindow):
self._changeView(nwView.PROJECT)
# Try to open the project
- if not self.theProject.openProject(projFile):
+ if not self._project.openProject(projFile):
# The project open failed.
- lockStatus = self.theProject.getLockStatus()
+ lockStatus = self._project.getLockStatus()
if lockStatus is None:
# The project is not locked, so failed for some other
# reason handled by the project class.
@@ -516,7 +525,7 @@ class GuiMain(QMainWindow):
lockDetails = ""
if self.askQuestion(lockText, info=lockInfo, details=lockDetails, level=nwAlert.WARN):
- if not self.theProject.openProject(projFile, overrideLock=True):
+ if not self._project.openProject(projFile, overrideLock=True):
return False
else:
return False
@@ -527,11 +536,11 @@ class GuiMain(QMainWindow):
self.idleTime = 0.0
# Update GUI
- self._updateWindowTitle(self.theProject.data.name)
+ self._updateWindowTitle(self._project.data.name)
self.rebuildTrees()
self.docEditor.setDictionaries()
- self.docEditor.toggleSpellCheck(self.theProject.data.spellCheck)
- self.mainStatus.setRefTime(self.theProject.projOpened)
+ self.docEditor.toggleSpellCheck(self._project.data.spellCheck)
+ self.mainStatus.setRefTime(self._project.projOpened)
self.projView.openProjectTasks()
self.novelView.openProjectTasks()
self.outlineView.openProjectTasks()
@@ -539,9 +548,9 @@ class GuiMain(QMainWindow):
# Restore previously open documents, if any
# If none was recorded, open the first document found
- lastEdited = self.theProject.data.getLastHandle("editor")
+ lastEdited = self._project.data.getLastHandle("editor")
if lastEdited is None:
- for nwItem in self.theProject.tree:
+ for nwItem in self._project.tree:
if nwItem and nwItem.isFileType():
lastEdited = nwItem.itemHandle
break
@@ -549,19 +558,19 @@ class GuiMain(QMainWindow):
if lastEdited is not None:
self.openDocument(lastEdited, doScroll=True)
- lastViewed = self.theProject.data.getLastHandle("viewer")
+ lastViewed = self._project.data.getLastHandle("viewer")
if lastViewed is not None:
self.viewDocument(lastViewed)
# Check if we need to rebuild the index
- if self.theProject.index.indexBroken:
+ if self._project.index.indexBroken:
self.makeAlert(self.tr("The project index is outdated or broken. Rebuilding index."))
self.rebuildIndex()
# Make sure the changed status is set to false on things opened
qApp.processEvents()
self.docEditor.setDocumentChanged(False)
- self.theProject.setProjectChanged(False)
+ self._project.setProjectChanged(False)
logger.debug("Project load complete")
@@ -573,7 +582,7 @@ class GuiMain(QMainWindow):
logger.error("No project open")
return False
self.projView.saveProjectTasks()
- self.theProject.saveProject(autoSave=autoSave)
+ self._project.saveProject(autoSave=autoSave)
return True
##
@@ -606,7 +615,7 @@ class GuiMain(QMainWindow):
logger.error("No project open")
return False
- if not tHandle or not self.theProject.tree.checkType(tHandle, nwItemType.FILE):
+ if not tHandle or not self._project.tree.checkType(tHandle, nwItemType.FILE):
logger.debug("Requested item '%s' is not a document", tHandle)
return False
@@ -620,7 +629,7 @@ class GuiMain(QMainWindow):
self.closeDocument(beforeOpen=True)
if self.docEditor.loadText(tHandle, tLine):
- self.theProject.data.setLastHandle(tHandle, "editor")
+ self._project.data.setLastHandle(tHandle, "editor")
self.projView.setSelectedHandle(tHandle, doScroll=doScroll)
self.novelView.setActiveHandle(tHandle)
if changeFocus:
@@ -641,7 +650,7 @@ class GuiMain(QMainWindow):
nHandle = None # The next handle after tHandle
fHandle = None # The first file handle we encounter
foundIt = False # We've found tHandle, pick the next we see
- for tItem in self.theProject.tree:
+ for tItem in self._project.tree:
if not tItem.isFileType():
continue
if fHandle is None:
@@ -687,7 +696,7 @@ class GuiMain(QMainWindow):
tHandle = self.projView.getSelectedHandle()
if tHandle is None:
- tHandle = self.theProject.data.getLastHandle("viewer")
+ tHandle = self._project.data.getLastHandle("viewer")
if tHandle is None:
logger.debug("No document to view, giving up")
@@ -806,7 +815,7 @@ class GuiMain(QMainWindow):
return False
if tHandle is not None and sTitle is not None:
- hItem = self.theProject.index.getItemHeader(tHandle, sTitle)
+ hItem = self._project.index.getItemHeader(tHandle, sTitle)
if hItem is not None:
tLine = hItem.line
@@ -843,7 +852,7 @@ class GuiMain(QMainWindow):
tStart = time()
self.projView.saveProjectTasks()
- self.theProject.index.rebuildIndex()
+ self._project.index.rebuildIndex()
self.projView.populateTree()
self.novelView.refreshTree()
@@ -951,7 +960,7 @@ class GuiMain(QMainWindow):
if dlgProj.spellChanged:
self.docEditor.setDictionaries()
self.itemDetails.refreshDetails()
- self._updateWindowTitle(self.theProject.data.name)
+ self._updateWindowTitle(self._project.data.name)
return True
@@ -1197,7 +1206,7 @@ class GuiMain(QMainWindow):
def closeDocEditor(self) -> None:
"""Close the document editor. This does not hide the editor."""
self.closeDocument()
- self.theProject.data.setLastHandle(None, "editor")
+ self._project.data.setLastHandle(None, "editor")
return
def closeDocViewer(self, byUser: bool = True) -> bool:
@@ -1205,7 +1214,7 @@ class GuiMain(QMainWindow):
self.docViewer.clearViewer()
if byUser:
# Only reset the last handle if the user called this
- self.theProject.data.setLastHandle(None, "viewer")
+ self._project.data.setLastHandle(None, "viewer")
# Hide the panel
bPos = self.splitMain.sizes()
@@ -1391,7 +1400,7 @@ class GuiMain(QMainWindow):
"""Handle the index lookup of a tag and display an alert if the
tag cannot be found.
"""
- tHandle, sTitle = self.theProject.index.getTagSource(tag)
+ tHandle, sTitle = self._project.index.getTagSource(tag)
if tHandle is None:
self.makeAlert(self.tr(
"Could not find the reference for tag '{0}'. It either doesn't "
@@ -1438,7 +1447,7 @@ class GuiMain(QMainWindow):
if tHandle is not None:
if mode == nwDocMode.EDIT:
tLine = None
- hItem = self.theProject.index.getItemHeader(tHandle, sTitle)
+ hItem = self._project.index.getItemHeader(tHandle, sTitle)
if hItem is not None:
tLine = hItem.line
self.openDocument(tHandle, tLine=tLine, changeFocus=setFocus)
@@ -1491,8 +1500,8 @@ class GuiMain(QMainWindow):
def _autoSaveProject(self) -> None:
"""Autosave of the project. This is a timer-activated slot."""
doSave = self.hasProject
- doSave &= self.theProject.projChanged
- doSave &= self.theProject.storage.isOpen()
+ doSave &= self._project.projChanged
+ doSave &= self._project.storage.isOpen()
if doSave:
logger.debug("Autosaving project")
self.saveProject(autoSave=True)
@@ -1512,14 +1521,14 @@ class GuiMain(QMainWindow):
if not self.hasProject:
self.mainStatus.setProjectStats(0, 0)
- self.theProject.updateWordCounts()
+ self._project.updateWordCounts()
if CONFIG.incNotesWCount:
- iTotal = sum(self.theProject.data.initCounts)
- cTotal = sum(self.theProject.data.currCounts)
+ iTotal = sum(self._project.data.initCounts)
+ cTotal = sum(self._project.data.currCounts)
self.mainStatus.setProjectStats(cTotal, cTotal - iTotal)
else:
- iNovel, _ = self.theProject.data.initCounts
- cNovel, _ = self.theProject.data.currCounts
+ iNovel, _ = self._project.data.initCounts
+ cNovel, _ = self._project.data.currCounts
self.mainStatus.setProjectStats(cNovel, cNovel - iNovel)
return
diff --git a/novelwriter/tools/manusbuild.py b/novelwriter/tools/manusbuild.py
index 0c2d4dda..2fb91269 100644
--- a/novelwriter/tools/manusbuild.py
+++ b/novelwriter/tools/manusbuild.py
@@ -65,8 +65,7 @@ class GuiManuscriptBuild(QDialog):
logger.debug("Create: GuiManuscriptBuild")
self.setObjectName("GuiManuscriptBuild")
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
self._parent = parent
self._build = build
@@ -82,7 +81,7 @@ class GuiManuscriptBuild(QDialog):
wWin = CONFIG.pxInt(620)
hWin = CONFIG.pxInt(360)
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
self.resize(
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "winWidth", wWin)),
CONFIG.pxInt(pOptions.getInt("GuiManuscriptBuild", "winHeight", hWin))
@@ -280,7 +279,7 @@ class GuiManuscriptBuild(QDialog):
@pyqtSlot()
def _doResetBuildName(self):
"""Generate a default build name."""
- bName = f"{self.theProject.data.name} - {self._build.name}"
+ bName = f"{self.mainGui.project.data.name} - {self._build.name}"
self.buildName.setText(bName)
self._build.setLastBuildName(bName)
return
@@ -321,7 +320,7 @@ class GuiManuscriptBuild(QDialog):
):
return False
- docBuild = NWBuildDocument(self.theProject, self._build)
+ docBuild = NWBuildDocument(self.mainGui.project, self._build)
docBuild.queueAll()
self.buildProgress.setMaximum(len(docBuild))
@@ -354,7 +353,7 @@ class GuiManuscriptBuild(QDialog):
fmtWidth = CONFIG.rpxInt(mainSplit[0])
sumWidth = CONFIG.rpxInt(mainSplit[1])
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
pOptions.setValue("GuiManuscriptBuild", "winWidth", winWidth)
pOptions.setValue("GuiManuscriptBuild", "winHeight", winHeight)
pOptions.setValue("GuiManuscriptBuild", "fmtWidth", fmtWidth)
@@ -366,9 +365,9 @@ class GuiManuscriptBuild(QDialog):
def _populateContentList(self):
"""Build the content list."""
rootMap = {}
- filtered = self._build.buildItemFilter(self.theProject)
+ filtered = self._build.buildItemFilter(self.mainGui.project)
self.listContent.clear()
- for nwItem in self.theProject.tree:
+ for nwItem in self.mainGui.project.tree:
tHandle = nwItem.itemHandle
rHandle = nwItem.itemRoot
@@ -377,7 +376,7 @@ class GuiManuscriptBuild(QDialog):
if filtered.get(tHandle, (False, 0))[0]:
if rHandle not in rootMap:
- rItem = self.theProject.tree[rHandle]
+ rItem = self.mainGui.project.tree[rHandle]
if isinstance(rItem, NWItem):
rootMap[rHandle] = rItem.itemName
diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py
index 1e0205c4..8666e47d 100644
--- a/novelwriter/tools/manuscript.py
+++ b/novelwriter/tools/manuscript.py
@@ -72,10 +72,9 @@ class GuiManuscript(QDialog):
if CONFIG.osDarwin:
self.setWindowFlag(Qt.WindowType.Tool)
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
- self._builds = BuildCollection(self.theProject)
+ self._builds = BuildCollection(self.mainGui.project)
self._buildMap: dict[str, QListWidgetItem] = {}
self.setWindowTitle(self.tr("Build Manuscript"))
@@ -86,7 +85,7 @@ class GuiManuscript(QDialog):
wWin = CONFIG.pxInt(900)
hWin = CONFIG.pxInt(600)
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
self.resize(
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "winWidth", wWin)),
CONFIG.pxInt(pOptions.getInt("GuiManuscript", "winHeight", hWin))
@@ -211,7 +210,7 @@ class GuiManuscript(QDialog):
self._updateBuildsList()
logger.debug("Loading build cache")
- cache = CONFIG.dataPath("cache") / f"build_{self.theProject.data.uuid}.json"
+ cache = CONFIG.dataPath("cache") / f"build_{self.mainGui.project.data.uuid}.json"
if cache.is_file():
try:
with open(cache, mode="r", encoding="utf-8") as fObj:
@@ -290,7 +289,7 @@ class GuiManuscript(QDialog):
if build is None:
return
- docBuild = NWBuildDocument(self.theProject, build)
+ docBuild = NWBuildDocument(self.mainGui.project, build)
docBuild.queueAll()
self.docPreview.beginNewBuild(len(docBuild))
@@ -310,7 +309,7 @@ class GuiManuscript(QDialog):
self._updatePreview(result, build)
logger.debug("Saving build cache")
- cache = CONFIG.dataPath("cache") / f"build_{self.theProject.data.uuid}.json"
+ cache = CONFIG.dataPath("cache") / f"build_{self.mainGui.project.data.uuid}.json"
try:
with open(cache, mode="w+", encoding="utf-8") as outFile:
outFile.write(json.dumps(result, indent=2))
@@ -391,7 +390,7 @@ class GuiManuscript(QDialog):
optsWidth = CONFIG.rpxInt(mainSplit[0])
viewWidth = CONFIG.rpxInt(mainSplit[1])
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
pOptions.setValue("GuiManuscript", "winWidth", winWidth)
pOptions.setValue("GuiManuscript", "winHeight", winHeight)
pOptions.setValue("GuiManuscript", "optsWidth", optsWidth)
@@ -450,8 +449,7 @@ class _PreviewWidget(QTextBrowser):
def __init__(self, mainGui: GuiMain):
super().__init__(parent=mainGui)
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
self._docTime = 0
self._buildName = ""
@@ -524,12 +522,12 @@ class _PreviewWidget(QTextBrowser):
def setJustify(self, state: bool):
"""Enable/disable the justify text option."""
- options = self.document().defaultTextOption()
+ pOptions = self.document().defaultTextOption()
if state:
- options.setAlignment(Qt.AlignJustify)
+ pOptions.setAlignment(Qt.AlignJustify)
else:
- options.setAlignment(Qt.AlignAbsolute)
- self.document().setDefaultTextOption(options)
+ pOptions.setAlignment(Qt.AlignAbsolute)
+ self.document().setDefaultTextOption(pOptions)
return
def setTextFont(self, family: str, size: int):
diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py
index f90eeb25..62eaba27 100644
--- a/novelwriter/tools/manussettings.py
+++ b/novelwriter/tools/manussettings.py
@@ -76,8 +76,7 @@ class GuiBuildSettings(QDialog):
if CONFIG.osDarwin:
self.setWindowFlag(Qt.WindowType.Tool)
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
self._build = build
@@ -89,7 +88,7 @@ class GuiBuildSettings(QDialog):
wWin = CONFIG.pxInt(750)
hWin = CONFIG.pxInt(550)
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
self.resize(
CONFIG.pxInt(pOptions.getInt("GuiBuildSettings", "winWidth", wWin)),
CONFIG.pxInt(pOptions.getInt("GuiBuildSettings", "winHeight", hWin))
@@ -263,7 +262,7 @@ class GuiBuildSettings(QDialog):
treeWidth, filterWidth = self.optTabSelect.mainSplitSizes()
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
pOptions.setValue("GuiBuildSettings", "winWidth", winWidth)
pOptions.setValue("GuiBuildSettings", "winHeight", winHeight)
pOptions.setValue("GuiBuildSettings", "treeWidth", treeWidth)
@@ -304,8 +303,7 @@ class _FilterTab(QWidget):
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
super().__init__(parent=buildMain)
- self.mainGui = buildMain.mainGui
- self.theProject = buildMain.mainGui.theProject
+ self.mainGui = buildMain.mainGui
self._treeMap: dict[str, QTreeWidgetItem] = {}
self._build = build
@@ -381,7 +379,7 @@ class _FilterTab(QWidget):
# Assemble GUI
# ============
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
self.selectionBox = QVBoxLayout()
self.selectionBox.addWidget(self.optTree)
@@ -447,7 +445,7 @@ class _FilterTab(QWidget):
logger.debug("Building project tree")
self._treeMap = {}
self.optTree.clear()
- for nwItem in self.theProject.getProjectItems():
+ for nwItem in self.mainGui.project.getProjectItems():
tHandle = nwItem.itemHandle
pHandle = nwItem.itemParent
@@ -523,7 +521,7 @@ class _FilterTab(QWidget):
# Root Classes
self.filterOpt.addLabel(self.tr("Select Root Folders"))
- for tHandle, nwItem in self.theProject.tree.iterRoots(None):
+ for tHandle, nwItem in self.mainGui.project.tree.iterRoots(None):
if not nwItem.isInactiveClass():
itemIcon = CONFIG.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout
@@ -559,7 +557,7 @@ class _FilterTab(QWidget):
def _setTreeItemMode(self) -> None:
"""Update the filtered mode icon on all items."""
- filtered = self._build.buildItemFilter(self.theProject)
+ filtered = self._build.buildItemFilter(self.mainGui.project)
for tHandle, item in self._treeMap.items():
allow, mode = filtered.get(tHandle, (False, FilterMode.UNKNOWN))
if mode == FilterMode.INCLUDED:
@@ -599,8 +597,7 @@ class _HeadingsTab(QWidget):
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
super().__init__(parent=buildMain)
- self.mainGui = buildMain.mainGui
- self.theProject = buildMain.mainGui.theProject
+ self.mainGui = buildMain.mainGui
self._build = build
self._editing = 0
diff --git a/novelwriter/tools/writingstats.py b/novelwriter/tools/writingstats.py
index 2a787294..fb995ef2 100644
--- a/novelwriter/tools/writingstats.py
+++ b/novelwriter/tools/writingstats.py
@@ -72,15 +72,14 @@ class GuiWritingStats(QDialog):
if CONFIG.osDarwin:
self.setWindowFlag(Qt.WindowType.Tool)
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
+ self.mainGui = mainGui
self.logData = []
self.filterData = []
self.timeFilter = 0.0
self.wordOffset = 0
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
self.setWindowTitle(self.tr("Writing Statistics"))
self.setMinimumWidth(CONFIG.pxInt(420))
@@ -334,7 +333,7 @@ class GuiWritingStats(QDialog):
showIdleTime = self.showIdleTime.isChecked()
histMax = self.histMax.value()
- pOptions = self.theProject.options
+ pOptions = self.mainGui.project.options
pOptions.setValue("GuiWritingStats", "winWidth", winWidth)
pOptions.setValue("GuiWritingStats", "winHeight", winHeight)
pOptions.setValue("GuiWritingStats", "widthCol0", widthCol0)
@@ -442,7 +441,7 @@ class GuiWritingStats(QDialog):
ttTime = 0
ttIdle = 0
- for record in self.theProject.session.iterRecords():
+ for record in self.mainGui.project.session.iterRecords():
rType = record.get("type")
if rType == "initial":
self.wordOffset = checkInt(record.get("offset"), 0)
diff --git a/tests/mocked.py b/tests/mocked.py
index b9a64fb0..cb25a51b 100644
--- a/tests/mocked.py
+++ b/tests/mocked.py
@@ -31,8 +31,9 @@ class MockGuiMain(QObject):
def __init__(self):
super().__init__()
+ self._project = None
+
self.hasProject = True
- self.theProject = None
self.mainStatus = MockStatusBar()
self.projPath = ""
@@ -43,6 +44,10 @@ class MockGuiMain(QObject):
return
+ @property
+ def project(self):
+ return self._project
+
def postLaunchTasks(self, cmdOpen):
return
diff --git a/tests/test_dialogs/test_dlg_docsplit.py b/tests/test_dialogs/test_dlg_docsplit.py
index 63d21e51..fc6ceccf 100644
--- a/tests/test_dialogs/test_dlg_docsplit.py
+++ b/tests/test_dialogs/test_dlg_docsplit.py
@@ -35,7 +35,7 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
# Create a new project
buildTestProject(nwGUI, projPath)
- theProject = nwGUI.theProject
+ theProject = nwGUI.project
projTree = nwGUI.projView.projTree
docText = (
diff --git a/tests/test_dialogs/test_dlg_projdetails.py b/tests/test_dialogs/test_dlg_projdetails.py
index 8afd668e..af234423 100644
--- a/tests/test_dialogs/test_dlg_projdetails.py
+++ b/tests/test_dialogs/test_dlg_projdetails.py
@@ -54,7 +54,7 @@ def testDlgProjDetails_Dialog(qtbot, nwGUI, prjLipsum):
assert projDet.tabMain.wordCountVal.text() == f"{3000:n}"
assert projDet.tabMain.chapCountVal.text() == f"{3:n}"
assert projDet.tabMain.sceneCountVal.text() == f"{5:n}"
- assert projDet.tabMain.revCountVal.text() == f"{nwGUI.theProject.data.saveCount:n}"
+ assert projDet.tabMain.revCountVal.text() == f"{nwGUI.project.data.saveCount:n}"
assert projDet.tabMain.projPathVal.text() == str(prjLipsum)
diff --git a/tests/test_dialogs/test_dlg_projsettings.py b/tests/test_dialogs/test_dlg_projsettings.py
index a2c36d2f..c3137265 100644
--- a/tests/test_dialogs/test_dlg_projsettings.py
+++ b/tests/test_dialogs/test_dlg_projsettings.py
@@ -51,7 +51,7 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI):
# Pretend we have a project
nwGUI.hasProject = True
- nwGUI.theProject.data.setSpellLang("en")
+ nwGUI.project.data.setSpellLang("en")
# Get the dialog object
nwGUI.mainMenu.aProjectSettings.activate(QAction.Trigger)
@@ -95,7 +95,7 @@ def testDlgProjSettings_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockR
CONFIG.setBackupPath(fncPath)
# Set some values
- theProject = nwGUI.theProject
+ theProject = nwGUI.project
theProject.data.setSpellLang("en")
theProject.data.setAuthor("Jane Smith")
theProject.data.setAutoReplace({"A": "B", "C": "D"})
@@ -160,7 +160,7 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncPath, projPat
CONFIG.setBackupPath(fncPath)
# Set some values
- theProject = nwGUI.theProject
+ theProject = nwGUI.project
theProject.tree[C.hTitlePage].setStatus(C.sFinished)
theProject.tree[C.hChapterDoc].setStatus(C.sDraft)
theProject.tree[C.hSceneDoc].setStatus(C.sDraft)
@@ -361,7 +361,7 @@ def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, fncPath, projPath, mo
CONFIG.setBackupPath(fncPath)
# Set some values
- theProject = nwGUI.theProject
+ theProject = nwGUI.project
theProject.data.setAutoReplace({
"A": "B", "C": "D"
})
diff --git a/tests/test_dialogs/test_dlg_wordlist.py b/tests/test_dialogs/test_dlg_wordlist.py
index 8d698851..35b1b1cf 100644
--- a/tests/test_dialogs/test_dlg_wordlist.py
+++ b/tests/test_dialogs/test_dlg_wordlist.py
@@ -55,7 +55,7 @@ def testDlgWordList_Dialog(qtbot, monkeypatch, nwGUI, projPath):
assert wList.listBox.count() == 0
# Add words
- userDict = UserDictionary(nwGUI.theProject)
+ userDict = UserDictionary(nwGUI.project)
userDict.add("word_a")
userDict.add("word_c")
userDict.add("word_g")
diff --git a/tests/test_gui/test_gui_doceditor.py b/tests/test_gui/test_gui_doceditor.py
index 25769dbf..8452623f 100644
--- a/tests/test_gui/test_gui_doceditor.py
+++ b/tests/test_gui/test_gui_doceditor.py
@@ -163,10 +163,10 @@ def testGuiEditor_SaveText(qtbot, monkeypatch, caplog, nwGUI, projPath, ipsumTex
assert "Could not save document." in caplog.text
# Change header level
- assert nwGUI.theProject.tree[C.hSceneDoc].itemLayout == nwItemLayout.DOCUMENT
+ assert nwGUI.project.tree[C.hSceneDoc].itemLayout == nwItemLayout.DOCUMENT
nwGUI.docEditor.replaceText(longText[1:])
assert nwGUI.docEditor.saveText() is True
- assert nwGUI.theProject.tree[C.hSceneDoc].itemLayout == nwItemLayout.DOCUMENT
+ assert nwGUI.project.tree[C.hSceneDoc].itemLayout == nwItemLayout.DOCUMENT
# Regular save
assert nwGUI.docEditor.saveText() is True
@@ -203,9 +203,9 @@ def testGuiEditor_MetaData(qtbot, nwGUI, projPath, mockRnd):
assert nwGUI.docEditor.setCursorPosition(None) is False
assert nwGUI.docEditor.setCursorPosition(10) is True
assert nwGUI.docEditor.getCursorPosition() == 10
- assert nwGUI.theProject.tree[C.hSceneDoc].cursorPos != 10
+ assert nwGUI.project.tree[C.hSceneDoc].cursorPos != 10
nwGUI.docEditor.saveCursorPosition()
- assert nwGUI.theProject.tree[C.hSceneDoc].cursorPos == 10
+ assert nwGUI.project.tree[C.hSceneDoc].cursorPos == 10
assert nwGUI.docEditor.setCursorLine(None) is False
assert nwGUI.docEditor.setCursorLine(3) is True
@@ -1067,7 +1067,7 @@ def testGuiEditor_Tags(qtbot, nwGUI, projPath, ipsumText, mockRnd):
# Create Character
theText = "### Jane Doe\n\n@tag: Jane\n\n" + ipsumText[1] + "\n\n"
- cHandle = nwGUI.theProject.newFile("Jane Doe", C.hCharRoot)
+ cHandle = nwGUI.project.newFile("Jane Doe", C.hCharRoot)
assert nwGUI.openDocument(cHandle) is True
assert nwGUI.docEditor.replaceText(theText) is True
assert nwGUI.saveDocument() is True
@@ -1145,8 +1145,8 @@ def testGuiEditor_WordCounters(qtbot, monkeypatch, nwGUI, projPath, ipsumText, m
assert nwGUI.docEditor.docFooter.wordsText.text() == "Words: 0 (+0)"
# Open a document and populate it
- nwGUI.theProject.tree[C.hSceneDoc]._initCount = 0 # Clear item's count
- nwGUI.theProject.tree[C.hSceneDoc]._wordCount = 0 # Clear item's count
+ nwGUI.project.tree[C.hSceneDoc]._initCount = 0 # Clear item's count
+ nwGUI.project.tree[C.hSceneDoc]._wordCount = 0 # Clear item's count
assert nwGUI.openDocument(C.hSceneDoc) is True
theText = "\n\n".join(ipsumText)
@@ -1170,9 +1170,9 @@ def testGuiEditor_WordCounters(qtbot, monkeypatch, nwGUI, projPath, ipsumText, m
nwGUI.docEditor.wCounterDoc.run()
# nwGUI.docEditor._updateDocCounts(cC, wC, pC)
- assert nwGUI.theProject.tree[C.hSceneDoc]._charCount == cC
- assert nwGUI.theProject.tree[C.hSceneDoc]._wordCount == wC
- assert nwGUI.theProject.tree[C.hSceneDoc]._paraCount == pC
+ assert nwGUI.project.tree[C.hSceneDoc]._charCount == cC
+ assert nwGUI.project.tree[C.hSceneDoc]._wordCount == wC
+ assert nwGUI.project.tree[C.hSceneDoc]._paraCount == pC
assert nwGUI.docEditor.docFooter.wordsText.text() == f"Words: {wC} (+{wC})"
# Select all text
diff --git a/tests/test_gui/test_gui_docviewer.py b/tests/test_gui/test_gui_docviewer.py
index 45d3caec..69b11039 100644
--- a/tests/test_gui/test_gui_docviewer.py
+++ b/tests/test_gui/test_gui_docviewer.py
@@ -40,8 +40,8 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum):
# Rebuild the index
nwGUI.mainMenu.aRebuildIndex.activate(QAction.Trigger)
- assert nwGUI.theProject.index._tagsIndex._tags != {}
- assert nwGUI.theProject.index._itemIndex._items != {}
+ assert nwGUI.project.index._tagsIndex._tags != {}
+ assert nwGUI.project.index._itemIndex._items != {}
# Select a document in the project tree
nwGUI.projView.setSelectedHandle("88243afbe5ed8")
@@ -128,7 +128,7 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum):
nwGUI.docViewer.reloadText()
# Change document title
- nwItem = nwGUI.theProject.tree["4c4f28287af27"]
+ nwItem = nwGUI.project.tree["4c4f28287af27"]
nwItem.setName("Test Title")
assert nwItem.itemName == "Test Title"
nwGUI.docViewer.updateDocInfo("4c4f28287af27")
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index 5ab8ea25..c46cac96 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -202,14 +202,14 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
assert nwGUI.saveProject()
assert nwGUI.closeProject()
- assert len(nwGUI.theProject.tree) == 0
- assert len(nwGUI.theProject.tree._treeOrder) == 0
- assert len(nwGUI.theProject.tree._treeRoots) == 0
- assert nwGUI.theProject.tree.trashRoot() is None
- assert nwGUI.theProject.data.name == ""
- assert nwGUI.theProject.data.title == ""
- assert nwGUI.theProject.data.author == ""
- assert nwGUI.theProject.data.spellCheck is False
+ assert len(nwGUI.project.tree) == 0
+ assert len(nwGUI.project.tree._treeOrder) == 0
+ assert len(nwGUI.project.tree._treeRoots) == 0
+ assert nwGUI.project.tree.trashRoot() is None
+ assert nwGUI.project.data.name == ""
+ assert nwGUI.project.data.title == ""
+ assert nwGUI.project.data.author == ""
+ assert nwGUI.project.data.spellCheck is False
# Check the files
projFile = projPath / "nwProject.nwx"
@@ -222,14 +222,14 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
assert nwGUI.openProject(projPath)
# Check that we loaded the data
- assert len(nwGUI.theProject.tree) == 8
- assert len(nwGUI.theProject.tree._treeOrder) == 8
- assert len(nwGUI.theProject.tree._treeRoots) == 4
- assert nwGUI.theProject.tree.trashRoot() is None
- assert nwGUI.theProject.data.name == "New Project"
- assert nwGUI.theProject.data.title == "New Novel"
- assert nwGUI.theProject.data.author == "Jane Doe"
- assert nwGUI.theProject.data.spellCheck is False
+ assert len(nwGUI.project.tree) == 8
+ assert len(nwGUI.project.tree._treeOrder) == 8
+ assert len(nwGUI.project.tree._treeRoots) == 4
+ assert nwGUI.project.tree.trashRoot() is None
+ assert nwGUI.project.data.name == "New Project"
+ assert nwGUI.project.data.title == "New Novel"
+ assert nwGUI.project.data.author == "Jane Doe"
+ assert nwGUI.project.data.spellCheck is False
# Check that tree items have been created
assert nwGUI.projView.projTree._getTreeItem(C.hNovelRoot) is not None
diff --git a/tests/test_gui/test_gui_noveltree.py b/tests/test_gui/test_gui_noveltree.py
index 789f6225..86675cf8 100644
--- a/tests/test_gui/test_gui_noveltree.py
+++ b/tests/test_gui/test_gui_noveltree.py
@@ -48,7 +48,7 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
nwGUI.projView.projTree._getTreeItem(C.hCharRoot).setSelected(True)
nwGUI.projView.projTree.newTreeItem(nwItemType.FILE)
- contentPath = nwGUI.theProject.storage.contentPath
+ contentPath = nwGUI.project.storage.contentPath
assert isinstance(contentPath, Path)
(contentPath / "0000000000010.nwd").write_text(
diff --git a/tests/test_gui/test_gui_outline.py b/tests/test_gui/test_gui_outline.py
index 5aaf3117..b1bb74f8 100644
--- a/tests/test_gui/test_gui_outline.py
+++ b/tests/test_gui/test_gui_outline.py
@@ -71,7 +71,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, projPath):
# Option State
# ============
- pOptions = nwGUI.theProject.options
+ pOptions = nwGUI.project.options
colNames = [h.name for h in nwOutline]
colItems = [h for h in nwOutline]
colWidth = {h: outlineTree.DEF_WIDTH[h] for h in nwOutline}
@@ -181,7 +181,7 @@ def testGuiOutline_Content(qtbot, nwGUI, prjLipsum):
assert outlineBar.novelValue.itemData(2) == "" # All novels
# Add a second novel folder
- newHandle = nwGUI.theProject.newRoot(nwItemClass.NOVEL)
+ newHandle = nwGUI.project.newRoot(nwItemClass.NOVEL)
nwGUI.projView.projTree.revealNewTreeItem(newHandle)
# Check new values in dropdown list
@@ -198,7 +198,7 @@ def testGuiOutline_Content(qtbot, nwGUI, prjLipsum):
("Section 4", 4),
]
for dTitle, hLevel in docList:
- aHandle = nwGUI.theProject.newFile(dTitle, newHandle)
+ aHandle = nwGUI.project.newFile(dTitle, newHandle)
hHash = "#"*hLevel
writeFile(prjLipsum / "content" / f"{aHandle}.nwd", f"{hHash} {dTitle}\n\n")
nwGUI.projView.projTree.revealNewTreeItem(aHandle)
diff --git a/tests/test_gui/test_gui_projtree.py b/tests/test_gui/test_gui_projtree.py
index bd645619..c5428506 100644
--- a/tests/test_gui/test_gui_projtree.py
+++ b/tests/test_gui/test_gui_projtree.py
@@ -46,7 +46,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
projView = nwGUI.projView
projTree = nwGUI.projView.projTree
- theProject = nwGUI.theProject
+ theProject = nwGUI.project
# Try to add item with no project
assert projView.projTree.newTreeItem(nwItemType.FILE) is False
@@ -260,19 +260,19 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
# ===========
projView.setSelectedHandle(C.hNovelRoot)
- assert nwGUI.theProject.tree._treeOrder.index(C.hNovelRoot) == 0
+ assert nwGUI.project.tree._treeOrder.index(C.hNovelRoot) == 0
# Move novel folder up
assert projTree.moveTreeItem(-1) is False
- assert nwGUI.theProject.tree._treeOrder.index(C.hNovelRoot) == 0
+ assert nwGUI.project.tree._treeOrder.index(C.hNovelRoot) == 0
# Move novel folder down
assert projTree.moveTreeItem(1) is True
- assert nwGUI.theProject.tree._treeOrder.index(C.hNovelRoot) == 1
+ assert nwGUI.project.tree._treeOrder.index(C.hNovelRoot) == 1
# Move novel folder up again
assert projTree.moveTreeItem(-1) is True
- assert nwGUI.theProject.tree._treeOrder.index(C.hNovelRoot) == 0
+ assert nwGUI.project.tree._treeOrder.index(C.hNovelRoot) == 0
# Clean up
# qtbot.stop()
@@ -348,7 +348,7 @@ def testGuiProjTree_RequestDeleteItem(qtbot, caplog, monkeypatch, nwGUI, projPat
C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
"0000000000010"
]
- trashHandle = nwGUI.theProject.tree.trashRoot()
+ trashHandle = nwGUI.project.tree.trashRoot()
assert projTree.getTreeFromHandle(trashHandle) == [
trashHandle, "0000000000012", "0000000000011"
]
@@ -368,7 +368,7 @@ def testGuiProjTree_MoveItemToTrash(qtbot, caplog, monkeypatch, nwGUI, projPath,
"""Test moving items to Trash."""
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
- theProject = nwGUI.theProject
+ theProject = nwGUI.project
projTree = nwGUI.projView.projTree
# Create a project
@@ -420,7 +420,7 @@ def testGuiProjTree_PermanentlyDeleteItem(qtbot, caplog, monkeypatch, nwGUI, pro
"""Test permanently deleting items."""
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
- theProject = nwGUI.theProject
+ theProject = nwGUI.project
projTree = nwGUI.projView.projTree
# Create a project
@@ -471,7 +471,7 @@ def testGuiProjTree_EmptyTrash(qtbot, caplog, monkeypatch, nwGUI, projPath, mock
"""Test emptying Trash."""
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
- theProject = nwGUI.theProject
+ theProject = nwGUI.project
projTree = nwGUI.projView.projTree
# No project open
@@ -541,16 +541,16 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
projTree.setExpandedFromHandle(None, True)
projTree._addTrashRoot()
- hTrashRoot = projTree.theProject.tree.trashRoot()
+ hTrashRoot = nwGUI.project.tree.trashRoot()
projTree.setSelectedHandle(C.hCharRoot)
projTree.newTreeItem(nwItemType.FILE)
projTree.setSelectedHandle(C.hNovelRoot)
projTree.newTreeItem(nwItemType.FILE, isNote=True)
- nwGUI.theProject.newFile("SubNote", hNovelNote)
+ nwGUI.project.newFile("SubNote", hNovelNote)
projTree.revealNewTreeItem(hSubNote)
- assert nwGUI.theProject.tree[hSubNote].itemParent == hNovelNote
+ assert nwGUI.project.tree[hSubNote].itemParent == hNovelNote
def itemPos(tHandle):
return projTree.visualItemRect(projTree._getTreeItem(tHandle)).center()
@@ -578,7 +578,7 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
# Direct Edit Functions
# =====================
# Trigger the dedicated functions the menu entries connect to
- nwItem = projTree.theProject.tree[hNovelNote]
+ nwItem = nwGUI.project.tree[hNovelNote]
# Toggle active flag
assert nwItem.isActive is True
@@ -619,17 +619,17 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT)
- assert nwGUI.theProject.tree[hNewFolderOne].isFolderType()
+ assert nwGUI.project.tree[hNewFolderOne].isFolderType()
# Convert the first folder to a document
projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT)
- assert nwGUI.theProject.tree[hNewFolderOne].isFileType()
- assert nwGUI.theProject.tree[hNewFolderOne].isDocumentLayout()
+ assert nwGUI.project.tree[hNewFolderOne].isFileType()
+ assert nwGUI.project.tree[hNewFolderOne].isDocumentLayout()
# Convert the second folder to a note
projTree._covertFolderToFile(hNewFolderTwo, nwItemLayout.NOTE)
- assert nwGUI.theProject.tree[hNewFolderTwo].isFileType()
- assert nwGUI.theProject.tree[hNewFolderTwo].isNoteLayout()
+ assert nwGUI.project.tree[hNewFolderTwo].isFileType()
+ assert nwGUI.project.tree[hNewFolderTwo].isNoteLayout()
# qtbot.stop()
@@ -649,7 +649,7 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
# Create a project
buildTestProject(nwGUI, projPath)
- theProject = nwGUI.theProject
+ theProject = nwGUI.project
projTree = nwGUI.projView.projTree
mergedDoc1 = "0000000000014"
@@ -751,7 +751,7 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
# Create a project
buildTestProject(nwGUI, projPath)
- theProject = nwGUI.theProject
+ theProject = nwGUI.project
projTree = nwGUI.projView.projTree
docText = (
@@ -852,7 +852,7 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
"""Test the duplicate items function."""
# Create a project
buildTestProject(nwGUI, projPath)
- assert len(nwGUI.theProject.tree) == 8
+ assert len(nwGUI.project.tree) == 8
projTree = nwGUI.projView.projTree
projTree._getTreeItem(C.hNovelRoot).setExpanded(True) # type: ignore
@@ -860,28 +860,28 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
# Nothing to do
assert projTree._duplicateFromHandle(C.hInvalid) is False
- assert len(nwGUI.theProject.tree) == 8
+ assert len(nwGUI.project.tree) == 8
# Duplicate title page, but select no
with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
assert projTree._duplicateFromHandle(C.hTitlePage) is False
- assert len(nwGUI.theProject.tree) == 8
+ assert len(nwGUI.project.tree) == 8
# Duplicate title page
assert projTree._duplicateFromHandle(C.hTitlePage) is True
- assert len(nwGUI.theProject.tree) == 9
+ assert len(nwGUI.project.tree) == 9
# Duplicate folder
assert projTree._duplicateFromHandle(C.hChapterDir) is True
- assert len(nwGUI.theProject.tree) == 12
+ assert len(nwGUI.project.tree) == 12
# Duplicate novel root
assert projTree._duplicateFromHandle(C.hNovelRoot) is True
- assert len(nwGUI.theProject.tree) == 21
+ assert len(nwGUI.project.tree) == 21
# Check tree order that all items are next to eachother
- assert nwGUI.theProject.tree._treeOrder == [
+ assert nwGUI.project.tree._treeOrder == [
C.hNovelRoot, C.hTitlePage, "0000000000010", C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
"0000000000011", "0000000000012", "0000000000013", "0000000000014", "0000000000015",
"0000000000016", "0000000000017", "0000000000018", "0000000000019", "000000000001a",
@@ -889,7 +889,7 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
]
# Make the duplicator stop early
- content = nwGUI.theProject.storage.contentPath
+ content = nwGUI.project.storage.contentPath
assert isinstance(content, Path)
(content / "000000000001e.nwd").touch()
assert (content / "000000000001e.nwd").exists()
@@ -897,7 +897,7 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
# Should only create the folder, and skip the two files because the
# next handle is already a file
assert projTree._duplicateFromHandle(C.hChapterDir) is True
- assert len(nwGUI.theProject.tree) == 22
+ assert len(nwGUI.project.tree) == 22
# qtbot.stop()
@@ -938,13 +938,13 @@ def testGuiProjTree_Other(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mockRnd)
assert projTree.revealNewTreeItem(C.hInvalid) is False
# Try to add an orphaned file to the tree
- nHandle = nwGUI.theProject.newFile("Test", C.hNovelRoot)
- nwGUI.theProject.tree[nHandle].setParent(None) # type: ignore
+ nHandle = nwGUI.project.newFile("Test", C.hNovelRoot)
+ nwGUI.project.tree[nHandle].setParent(None) # type: ignore
assert projTree.revealNewTreeItem(nHandle) is False
# Try to add an item with unknown parent to the tree
- nHandle = nwGUI.theProject.newFile("Test", C.hNovelRoot)
- nwGUI.theProject.tree[nHandle].setParent(C.hInvalid) # type: ignore
+ nHandle = nwGUI.project.newFile("Test", C.hNovelRoot)
+ nwGUI.project.tree[nHandle].setParent(C.hInvalid) # type: ignore
assert projTree.revealNewTreeItem(nHandle) is False
# Method: undoLastMove
diff --git a/tests/test_gui/test_gui_statusbar.py b/tests/test_gui/test_gui_statusbar.py
index b19afa45..73572160 100644
--- a/tests/test_gui/test_gui_statusbar.py
+++ b/tests/test_gui/test_gui_statusbar.py
@@ -33,8 +33,8 @@ def testGuiStatusBar_Main(qtbot, nwGUI, projPath, mockRnd):
"""Test the the various features of the status bar.
"""
buildTestProject(nwGUI, projPath)
- cHandle = nwGUI.theProject.newFile("A Note", C.hCharRoot)
- newDoc = nwGUI.theProject.storage.getDocument(cHandle)
+ cHandle = nwGUI.project.newFile("A Note", C.hCharRoot)
+ newDoc = nwGUI.project.storage.getDocument(cHandle)
newDoc.writeDocument("# A Note\n\n")
nwGUI.projView.projTree.revealNewTreeItem(cHandle)
nwGUI.rebuildIndex(beQuiet=True)
diff --git a/tests/test_tools/test_tools_manuscript.py b/tests/test_tools/test_tools_manuscript.py
index cb5aedb1..9d58554d 100644
--- a/tests/test_tools/test_tools_manuscript.py
+++ b/tests/test_tools/test_tools_manuscript.py
@@ -45,7 +45,7 @@ def testManuscript_Init(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath: Pat
"""Test the init/main functionality of the GuiManuscript dialog."""
buildTestProject(nwGUI, projPath)
nwGUI.openProject(projPath)
- nwGUI.theProject.storage.getDocument(C.hChapterDoc).writeDocument("## A Chapter\n\n\t\tHi")
+ nwGUI.project.storage.getDocument(C.hChapterDoc).writeDocument("## A Chapter\n\n\t\tHi")
allText = "New Novel\nBy Jane Doe\nA Chapter\n\t\tHi\n* * *"
manus = GuiManuscript(nwGUI)
@@ -159,7 +159,7 @@ def testManuscript_Features(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath:
manus.show()
manus.loadContent()
- cacheFile = CONFIG.dataPath("cache") / f"build_{nwGUI.theProject.data.uuid}.json"
+ cacheFile = CONFIG.dataPath("cache") / f"build_{nwGUI.project.data.uuid}.json"
manus.buildList.setCurrentRow(0)
build = manus._getSelectedBuild()
assert isinstance(build, BuildSettings)
diff --git a/tests/test_tools/test_tools_manussettings.py b/tests/test_tools/test_tools_manussettings.py
index f84b2e3d..deccca1c 100644
--- a/tests/test_tools/test_tools_manussettings.py
+++ b/tests/test_tools/test_tools_manussettings.py
@@ -128,11 +128,11 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
"worldRoot": 9,
}
- hPlotDoc = nwGUI.theProject.newFile("Main Plot", C.hPlotRoot)
- hCharDoc = nwGUI.theProject.newFile("Jane Doe", C.hCharRoot)
+ hPlotDoc = nwGUI.project.newFile("Main Plot", C.hPlotRoot)
+ hCharDoc = nwGUI.project.newFile("Jane Doe", C.hCharRoot)
nwGUI.projView.projTree.revealNewTreeItem(hPlotDoc)
nwGUI.projView.projTree.revealNewTreeItem(hCharDoc)
- nwGUI.theProject.tree[hPlotDoc].setActive(False) # type: ignore
+ nwGUI.project.tree[hPlotDoc].setActive(False) # type: ignore
# Create the dialog and populate it
bSettings = GuiBuildSettings(nwGUI, build)
@@ -167,7 +167,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
# Switch off novel docs
filterTab.filterOpt._widgets[switchMap["incNovel"]].setChecked(False)
- assert build.buildItemFilter(nwGUI.theProject) == {
+ assert build.buildItemFilter(nwGUI.project) == {
C.hNovelRoot: (False, FilterMode.SKIPPED),
C.hTitlePage: (False, FilterMode.FILTERED),
C.hChapterDir: (False, FilterMode.SKIPPED),
@@ -182,7 +182,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
# Switch on note docs
filterTab.filterOpt._widgets[switchMap["incNotes"]].setChecked(True)
- assert build.buildItemFilter(nwGUI.theProject) == {
+ assert build.buildItemFilter(nwGUI.project) == {
C.hNovelRoot: (False, FilterMode.SKIPPED),
C.hTitlePage: (False, FilterMode.FILTERED),
C.hChapterDir: (False, FilterMode.SKIPPED),
@@ -197,7 +197,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
# Switch on inactive docs
filterTab.filterOpt._widgets[switchMap["incInactive"]].setChecked(True)
- assert build.buildItemFilter(nwGUI.theProject) == {
+ assert build.buildItemFilter(nwGUI.project) == {
C.hNovelRoot: (False, FilterMode.SKIPPED),
C.hTitlePage: (False, FilterMode.FILTERED),
C.hChapterDir: (False, FilterMode.SKIPPED),
@@ -214,7 +214,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
filterTab._treeMap[C.hChapterDoc].setSelected(True)
filterTab._treeMap[C.hSceneDoc].setSelected(True)
filterTab.includedButton.click()
- assert build.buildItemFilter(nwGUI.theProject) == {
+ assert build.buildItemFilter(nwGUI.project) == {
C.hNovelRoot: (False, FilterMode.SKIPPED),
C.hTitlePage: (False, FilterMode.FILTERED),
C.hChapterDir: (False, FilterMode.SKIPPED),
@@ -232,7 +232,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
filterTab._treeMap[hPlotDoc].setSelected(True) # type: ignore
filterTab._treeMap[hCharDoc].setSelected(True) # type: ignore
filterTab.excludedButton.click()
- assert build.buildItemFilter(nwGUI.theProject) == {
+ assert build.buildItemFilter(nwGUI.project) == {
C.hNovelRoot: (False, FilterMode.SKIPPED),
C.hTitlePage: (False, FilterMode.FILTERED),
C.hChapterDir: (False, FilterMode.SKIPPED),
@@ -247,7 +247,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
# Switch on novel docs
filterTab.filterOpt._widgets[switchMap["incNovel"]].setChecked(True)
- assert build.buildItemFilter(nwGUI.theProject) == {
+ assert build.buildItemFilter(nwGUI.project) == {
C.hNovelRoot: (False, FilterMode.SKIPPED),
C.hTitlePage: (True, FilterMode.FILTERED), # Now enabled
C.hChapterDir: (False, FilterMode.SKIPPED),
@@ -264,7 +264,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
filterTab.optTree.clearSelection()
filterTab._treeMap[C.hNovelRoot].setSelected(True)
filterTab.resetButton.click()
- assert build.buildItemFilter(nwGUI.theProject) == {
+ assert build.buildItemFilter(nwGUI.project) == {
C.hNovelRoot: (False, FilterMode.SKIPPED),
C.hTitlePage: (True, FilterMode.FILTERED),
C.hChapterDir: (False, FilterMode.SKIPPED),
@@ -284,7 +284,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
filterTab._treeMap[hPlotDoc].setSelected(True) # type: ignore
filterTab._treeMap[hCharDoc].setSelected(True) # type: ignore
filterTab.resetButton.click()
- assert build.buildItemFilter(nwGUI.theProject) == {
+ assert build.buildItemFilter(nwGUI.project) == {
C.hNovelRoot: (False, FilterMode.SKIPPED),
C.hTitlePage: (True, FilterMode.FILTERED),
C.hChapterDir: (False, FilterMode.SKIPPED),
@@ -302,8 +302,8 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR
C.hNovelRoot, C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
C.hPlotRoot, hPlotDoc, C.hCharRoot, hCharDoc,
]
- nwGUI.theProject.tree[hCharDoc].setRoot(None) # type: ignore
- nwGUI.theProject.tree[hPlotDoc].setParent(None) # type: ignore
+ nwGUI.project.tree[hCharDoc].setRoot(None) # type: ignore
+ nwGUI.project.tree[hPlotDoc].setParent(None) # type: ignore
filterTab._populateTree()
assert list(filterTab._treeMap.keys()) == [
C.hNovelRoot, C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
diff --git a/tests/test_tools/test_tools_writingstats.py b/tests/test_tools/test_tools_writingstats.py
index 50ab2e1d..3674004c 100644
--- a/tests/test_tools/test_tools_writingstats.py
+++ b/tests/test_tools/test_tools_writingstats.py
@@ -39,7 +39,7 @@ def testToolWritingStats_Main(qtbot, monkeypatch, nwGUI, projPath, tstPaths):
"""
# Create a project to work on
buildTestProject(nwGUI, projPath)
- project = nwGUI.theProject
+ project = nwGUI.project
qtbot.wait(100)
assert nwGUI.saveProject()
diff --git a/tests/tools.py b/tests/tools.py
index e07912ae..f8f3f03c 100644
--- a/tests/tools.py
+++ b/tests/tools.py
@@ -154,59 +154,59 @@ def cleanProject(path: str | Path):
return
-def buildTestProject(theObject, projPath):
- """Build a standard test project in projPath using theProject
+def buildTestProject(obj, projPath):
+ """Build a standard test project in projPath using the project
object as the parent.
"""
from novelwriter.enum import nwItemClass
from novelwriter.core.project import NWProject
- if isinstance(theObject, NWProject):
- theGUI = None
- theProject = theObject
+ if isinstance(obj, NWProject):
+ nwGUI = None
+ project = obj
else:
- theGUI = theObject
- theProject = theObject.theProject
+ nwGUI = obj
+ project = obj.project
- theProject.clearProject()
- theProject.storage.openProjectInPlace(projPath)
- theProject.setDefaultStatusImport()
+ project.clearProject()
+ project.storage.openProjectInPlace(projPath)
+ project.setDefaultStatusImport()
- theProject.data.setUuid("d0f3fe10-c6e6-4310-8bfd-181eb4224eed")
- theProject.data.setName("New Project")
- theProject.data.setTitle("New Novel")
- theProject.data.setAuthor("Jane Doe")
+ project.data.setUuid("d0f3fe10-c6e6-4310-8bfd-181eb4224eed")
+ project.data.setName("New Project")
+ project.data.setTitle("New Novel")
+ project.data.setAuthor("Jane Doe")
# Creating a minimal project with a few root folders and a
# single chapter folder with a single file.
xHandle = {}
- xHandle[1] = theProject.newRoot(nwItemClass.NOVEL, "Novel")
- xHandle[2] = theProject.newRoot(nwItemClass.PLOT, "Plot")
- xHandle[3] = theProject.newRoot(nwItemClass.CHARACTER, "Characters")
- xHandle[4] = theProject.newRoot(nwItemClass.WORLD, "World")
- xHandle[5] = theProject.newFile("Title Page", xHandle[1])
- xHandle[6] = theProject.newFolder("New Chapter", xHandle[1])
- xHandle[7] = theProject.newFile("New Chapter", xHandle[6])
- xHandle[8] = theProject.newFile("New Scene", xHandle[6])
+ xHandle[1] = project.newRoot(nwItemClass.NOVEL, "Novel")
+ xHandle[2] = project.newRoot(nwItemClass.PLOT, "Plot")
+ xHandle[3] = project.newRoot(nwItemClass.CHARACTER, "Characters")
+ xHandle[4] = project.newRoot(nwItemClass.WORLD, "World")
+ xHandle[5] = project.newFile("Title Page", xHandle[1])
+ xHandle[6] = project.newFolder("New Chapter", xHandle[1])
+ xHandle[7] = project.newFile("New Chapter", xHandle[6])
+ xHandle[8] = project.newFile("New Scene", xHandle[6])
- aDoc = theProject.storage.getDocument(xHandle[5])
+ aDoc = project.storage.getDocument(xHandle[5])
aDoc.writeDocument("#! New Novel\n\n>> By Jane Doe <<\n")
- theProject.index.reIndexHandle(xHandle[5])
+ project.index.reIndexHandle(xHandle[5])
- aDoc = theProject.storage.getDocument(xHandle[7])
- aDoc.writeDocument("## %s\n\n" % theProject.tr("New Chapter"))
- theProject.index.reIndexHandle(xHandle[7])
+ aDoc = project.storage.getDocument(xHandle[7])
+ aDoc.writeDocument("## %s\n\n" % project.tr("New Chapter"))
+ project.index.reIndexHandle(xHandle[7])
- aDoc = theProject.storage.getDocument(xHandle[8])
- aDoc.writeDocument("### %s\n\n" % theProject.tr("New Scene"))
- theProject.index.reIndexHandle(xHandle[8])
+ aDoc = project.storage.getDocument(xHandle[8])
+ aDoc.writeDocument("### %s\n\n" % project.tr("New Scene"))
+ project.index.reIndexHandle(xHandle[8])
- theProject.session.startSession()
- theProject.setProjectChanged(True)
- theProject.saveProject(autoSave=True)
+ project.session.startSession()
+ project.setProjectChanged(True)
+ project.saveProject(autoSave=True)
- if theGUI is not None:
- theGUI.hasProject = True
- theGUI.rebuildTrees()
+ if nwGUI is not None:
+ nwGUI.hasProject = True
+ nwGUI.rebuildTrees()
return
From c40d910b69bdbc9212814d35db793f19c3ac2703 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 8 Aug 2023 19:50:20 +0200
Subject: [PATCH 03/10] Make backup path always set
---
novelwriter/common.py | 3 +-
novelwriter/config.py | 33 ++++++++++-----------
novelwriter/core/project.py | 18 ++++-------
tests/reference/baseConfig_novelwriter.conf | 4 +--
tests/test_base/test_base_config.py | 2 +-
tests/test_core/test_core_project.py | 4 ---
6 files changed, 26 insertions(+), 38 deletions(-)
diff --git a/novelwriter/common.py b/novelwriter/common.py
index a325e604..35db1c9c 100644
--- a/novelwriter/common.py
+++ b/novelwriter/common.py
@@ -121,8 +121,7 @@ def checkUuid(value: Any, default: str) -> str:
def checkPath(value: Any, default: Path) -> Path:
- """Check if a value is a valid path. Non-empty strings are accepted.
- """
+ """Check if a value is a valid path."""
if isinstance(value, Path):
return value
elif isinstance(value, str):
diff --git a/novelwriter/config.py b/novelwriter/config.py
index 9c96e1be..1edffa10 100644
--- a/novelwriter/config.py
+++ b/novelwriter/config.py
@@ -94,8 +94,8 @@ class Config:
# User Settings
# =============
- self._theme = None
- self._recent = RecentProjects(self)
+ self._themeObj = None
+ self._recentObj = RecentProjects(self)
# General GUI Settings
self.guiLocale = self._qLocale.name()
@@ -107,7 +107,6 @@ class Config:
self.hideVScroll = False # Hide vertical scroll bars on main widgets
self.hideHScroll = False # Hide horizontal scroll bars on main widgets
self.lastNotes = "0x0" # The latest release notes that have been shown
- self._lastPath = self._homePath # The user's last used path
# Size Settings
self._mainWinSize = [1200, 650] # Last size of the main GUI window
@@ -121,7 +120,6 @@ class Config:
self.autoSaveProj = 60 # Interval for auto-saving project, in seconds
self.autoSaveDoc = 30 # Interval for auto-saving document, in seconds
self.emphLabels = True # Add emphasis to H1 and H2 item labels
- self._backupPath = None # Backup path to use, can be none
self.backupOnClose = False # Flag for running automatic backups
self.askBeforeBackup = True # Flag for asking before running automatic backup
@@ -174,6 +172,10 @@ class Config:
self.fmtPadAfter = ""
self.fmtPadThin = False
+ # User Paths
+ self._lastPath = self._homePath # The user's last used path
+ self._backupPath = self._homePath # Backup path to use, can be none
+
# Spell Checking Settings
self.spellLanguage = "en"
@@ -238,13 +240,13 @@ class Config:
@property
def recentProjects(self):
- return self._recent
+ return self._recentObj
@property
def theme(self) -> GuiTheme:
- if self._theme is None:
+ if self._themeObj is None:
raise Exception("Cannot access GUI theme before it is initialised")
- return self._theme
+ return self._themeObj
@property
def mainWinSize(self):
@@ -295,7 +297,7 @@ class Config:
def setThemeInstance(self, theme: GuiTheme) -> None:
"""Set the applications theme instance."""
- self._theme = theme
+ self._themeObj = theme
return
def setMainWinSize(self, newWidth, newHeight):
@@ -351,9 +353,9 @@ class Config:
logger.debug("Last path updated: %s" % self._lastPath)
return
- def setBackupPath(self, backupPath: Path | None):
+ def setBackupPath(self, backupPath: Path | str):
"""Set the current backup path."""
- self._backupPath = checkPath(backupPath, None)
+ self._backupPath = checkPath(backupPath, self._homePath)
return
def setTextFont(self, family: str | None, pointSize: int = 12):
@@ -411,12 +413,12 @@ class Config:
return self._lastPath
return self._homePath
- def backupPath(self) -> Path | None:
+ def backupPath(self) -> Path:
"""Return the backup path."""
if isinstance(self._backupPath, Path):
if self._backupPath.is_dir():
return self._backupPath
- return None
+ return self._homePath
def errorText(self) -> str:
"""Compile and return error messages from the initialisation of
@@ -495,7 +497,7 @@ class Config:
else:
self.saveConfig()
- self._recent.loadCache()
+ self._recentObj.loadCache()
self._checkOptionalPackages()
logger.debug("Config initialisation complete")
@@ -647,9 +649,6 @@ class Config:
# Check Values
# ============
- # Check Certain Values for None
- self.spellLanguage = self._checkNone(self.spellLanguage)
-
# If we're using straight quotes, disable auto-replace
if self.fmtSQuoteOpen == self.fmtSQuoteClose == "'" and self.doReplaceSQuote:
logger.info("Using straight single quotes, so disabling auto-replace")
@@ -697,7 +696,7 @@ class Config:
"autosaveproject": str(self.autoSaveProj),
"autosavedoc": str(self.autoSaveDoc),
"emphlabels": str(self.emphLabels),
- "backuppath": str(self._backupPath or ""),
+ "backuppath": str(self._backupPath),
"backuponclose": str(self.backupOnClose),
"askbeforebackup": str(self.askBeforeBackup),
}
diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py
index 88450946..dfe7a737 100644
--- a/novelwriter/core/project.py
+++ b/novelwriter/core/project.py
@@ -416,14 +416,6 @@ class NWProject(QObject):
logger.info("Backing up project")
self.mainGui.setStatus(self.tr("Backing up project ..."))
- backupPath = CONFIG.backupPath()
- if not isinstance(backupPath, Path):
- self.mainGui.makeAlert(self.tr(
- "Cannot backup project because no valid backup path is set. "
- "Please set a valid backup location in Preferences."
- ), level=nwAlert.ERROR)
- return False
-
if not self._data.name:
self.mainGui.makeAlert(self.tr(
"Cannot backup project because no project name is set. "
@@ -432,6 +424,7 @@ class NWProject(QObject):
return False
cleanName = makeFileNameSafe(self._data.name)
+ backupPath = CONFIG.backupPath()
baseDir = backupPath / cleanName
try:
baseDir.mkdir(exist_ok=True)
@@ -444,11 +437,12 @@ class NWProject(QObject):
timeStamp = formatTimeStamp(time(), fileSafe=True)
archName = baseDir / f"{cleanName} {timeStamp}.zip"
if self._storage.zipIt(archName, compression=2):
- size = archName.stat().st_size
+ size = formatInt(archName.stat().st_size)
if doNotify:
- self.mainGui.makeAlert(self.tr(
- "Backup archive file written to: {0} [{1}B]"
- ).format(str(archName), formatInt(size)))
+ self.mainGui.makeAlert(
+ self.tr("Created a backup of your project of size {0}B.").format(size),
+ info=self.tr("Path: {0}").format(str(backupPath))
+ )
else:
self.mainGui.makeAlert(self.tr(
"Could not write backup archive."
diff --git a/tests/reference/baseConfig_novelwriter.conf b/tests/reference/baseConfig_novelwriter.conf
index 50f12524..e1554e94 100644
--- a/tests/reference/baseConfig_novelwriter.conf
+++ b/tests/reference/baseConfig_novelwriter.conf
@@ -1,5 +1,5 @@
[Meta]
-timestamp = 2023-08-02 14:53:36
+timestamp = 2023-08-08 19:01:25
[Main]
theme = default
@@ -10,7 +10,7 @@ localisation = en_GB
hidevscroll = False
hidehscroll = False
lastnotes = 0x0
-lastpath = /home/vkbo
+lastpath =
[Sizes]
mainwindow = 1200, 650
diff --git a/tests/test_base/test_base_config.py b/tests/test_base/test_base_config.py
index 3f0d94c7..524cd8a1 100644
--- a/tests/test_base/test_base_config.py
+++ b/tests/test_base/test_base_config.py
@@ -111,7 +111,7 @@ def testBaseConfig_InitLoadSave(monkeypatch, fncPath, tstPaths):
# Check that we have a default file
copyfile(confFile, testFile)
- ignore = ("timestamp", "lastnotes", "localisation", "lastpath")
+ ignore = ("timestamp", "lastnotes", "localisation", "lastpath", "backuppath")
assert cmpFiles(testFile, compFile, ignoreStart=ignore)
tstConf.errorText() # This clears the error cache
diff --git a/tests/test_core/test_core_project.py b/tests/test_core/test_core_project.py
index 598f861e..b13b75c4 100644
--- a/tests/test_core/test_core_project.py
+++ b/tests/test_core/test_core_project.py
@@ -590,10 +590,6 @@ def testCoreProject_Backup(monkeypatch, mockGUI, fncPath, tstPaths):
# Invalid Settings
# ================
- # Invalid path
- CONFIG._backupPath = None
- assert theProject.backupProject(doNotify=False) is False
-
# Missing project name
CONFIG._backupPath = tstPaths.tmpDir
theProject.data.setName("")
From 348e62cd3e94c75aa65e867197655cb1bb63096e Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 8 Aug 2023 19:59:57 +0200
Subject: [PATCH 04/10] Change default backup folder to HOME/Backups
Signed-off-by: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
---
novelwriter/config.py | 7 ++++---
novelwriter/core/project.py | 2 +-
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/novelwriter/config.py b/novelwriter/config.py
index 1edffa10..c60efee1 100644
--- a/novelwriter/config.py
+++ b/novelwriter/config.py
@@ -68,6 +68,7 @@ class Config:
self._confPath = confRoot.absolute() / self.appHandle # The user config location
self._dataPath = dataRoot.absolute() / self.appHandle # The user data location
self._homePath = Path.home().absolute() # The user's home directory
+ self._backPath = self._homePath / "Backups"
self._appPath = Path(__file__).parent.absolute()
self._appRoot = self._appPath.parent
@@ -174,7 +175,7 @@ class Config:
# User Paths
self._lastPath = self._homePath # The user's last used path
- self._backupPath = self._homePath # Backup path to use, can be none
+ self._backupPath = self._backPath # Backup path to use, can be none
# Spell Checking Settings
self.spellLanguage = "en"
@@ -355,7 +356,7 @@ class Config:
def setBackupPath(self, backupPath: Path | str):
"""Set the current backup path."""
- self._backupPath = checkPath(backupPath, self._homePath)
+ self._backupPath = checkPath(backupPath, self._backPath)
return
def setTextFont(self, family: str | None, pointSize: int = 12):
@@ -418,7 +419,7 @@ class Config:
if isinstance(self._backupPath, Path):
if self._backupPath.is_dir():
return self._backupPath
- return self._homePath
+ return self._backPath
def errorText(self) -> str:
"""Compile and return error messages from the initialisation of
diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py
index dfe7a737..839ab335 100644
--- a/novelwriter/core/project.py
+++ b/novelwriter/core/project.py
@@ -427,7 +427,7 @@ class NWProject(QObject):
backupPath = CONFIG.backupPath()
baseDir = backupPath / cleanName
try:
- baseDir.mkdir(exist_ok=True)
+ baseDir.mkdir(exist_ok=True, parents=True)
except Exception as exc:
self.mainGui.makeAlert(self.tr(
"Could not create backup folder."
From d658a993c0951dd5555aad6293a92d3874e10189 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 8 Aug 2023 21:41:35 +0200
Subject: [PATCH 05/10] Update source file headers
---
novelwriter/core/project.py | 1 -
novelwriter/core/status.py | 2 +-
novelwriter/dialogs/docmerge.py | 2 +-
novelwriter/dialogs/docsplit.py | 2 +-
novelwriter/dialogs/editlabel.py | 2 +-
novelwriter/dialogs/preferences.py | 2 +-
novelwriter/dialogs/projdetails.py | 2 +-
novelwriter/dialogs/projload.py | 2 +-
novelwriter/dialogs/quotes.py | 2 +-
novelwriter/dialogs/updates.py | 2 +-
novelwriter/enum.py | 1 -
novelwriter/extensions/configlayout.py | 1 -
novelwriter/extensions/pageddialog.py | 2 +-
novelwriter/extensions/switch.py | 2 +-
novelwriter/gui/components.py | 2 +-
novelwriter/gui/dochighlight.py | 2 +-
novelwriter/gui/docviewer.py | 2 +-
novelwriter/gui/itemdetails.py | 2 +-
novelwriter/gui/mainmenu.py | 2 +-
novelwriter/gui/noveltree.py | 2 +-
novelwriter/gui/outline.py | 2 +-
novelwriter/gui/projtree.py | 1 -
novelwriter/gui/sidebar.py | 2 +-
novelwriter/gui/statusbar.py | 2 +-
novelwriter/gui/theme.py | 1 -
novelwriter/tools/lipsum.py | 2 +-
novelwriter/tools/projwizard.py | 2 +-
27 files changed, 22 insertions(+), 27 deletions(-)
diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py
index 839ab335..c1b2ea2a 100644
--- a/novelwriter/core/project.py
+++ b/novelwriter/core/project.py
@@ -1,7 +1,6 @@
"""
novelWriter – Project Wrapper
=============================
-The parent class for a novelWriter project
File History:
Created: 2018-09-29 [0.0.1]
diff --git a/novelwriter/core/status.py b/novelwriter/core/status.py
index a1e99899..88b4467a 100644
--- a/novelwriter/core/status.py
+++ b/novelwriter/core/status.py
@@ -1,7 +1,6 @@
"""
novelWriter – Project Item Status Class
=======================================
-Data class for the status/importance settings of a project item
File History:
Created: 2019-05-19 [0.1.3]
@@ -23,6 +22,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import random
import logging
diff --git a/novelwriter/dialogs/docmerge.py b/novelwriter/dialogs/docmerge.py
index 5ad908a4..0faf9dd9 100644
--- a/novelwriter/dialogs/docmerge.py
+++ b/novelwriter/dialogs/docmerge.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Doc Merge Dialog
==================================
-Custom dialog class for merging documents.
File History:
Created: 2020-01-23 [0.4.3]
@@ -23,6 +22,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/dialogs/docsplit.py b/novelwriter/dialogs/docsplit.py
index b68613a2..9542268f 100644
--- a/novelwriter/dialogs/docsplit.py
+++ b/novelwriter/dialogs/docsplit.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Doc Split Dialog
==================================
-Custom dialog class for splitting documents.
File History:
Created: 2020-02-01 [0.4.3]
@@ -23,6 +22,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/dialogs/editlabel.py b/novelwriter/dialogs/editlabel.py
index 58c72890..662c00f6 100644
--- a/novelwriter/dialogs/editlabel.py
+++ b/novelwriter/dialogs/editlabel.py
@@ -1,7 +1,6 @@
"""
novelWriter – Edit Label Dialog
===============================
-A simple dialog for editing a label
File History:
Created: 2022-06-11 [2.0rc1]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py
index 08a4d5b9..47d35b08 100644
--- a/novelwriter/dialogs/preferences.py
+++ b/novelwriter/dialogs/preferences.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Preferences
=============================
-GUI classes for the user preferences dialog
File History:
Created: 2019-06-10 [0.1.5]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/dialogs/projdetails.py b/novelwriter/dialogs/projdetails.py
index 68a6b3b6..b3d942ca 100644
--- a/novelwriter/dialogs/projdetails.py
+++ b/novelwriter/dialogs/projdetails.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Project Details
=================================
-Class holding the project details dialog
File History:
Created: 2021-01-03 [1.1rc1]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import math
import logging
diff --git a/novelwriter/dialogs/projload.py b/novelwriter/dialogs/projload.py
index f88e7130..1ae6fb50 100644
--- a/novelwriter/dialogs/projload.py
+++ b/novelwriter/dialogs/projload.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Open Project
==============================
-GUI class for the load/browse/new project dialog
File History:
Created: 2020-02-26 [0.4.5]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/dialogs/quotes.py b/novelwriter/dialogs/quotes.py
index 4f5ba9eb..6282c6b6 100644
--- a/novelwriter/dialogs/quotes.py
+++ b/novelwriter/dialogs/quotes.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Quotes Dialog
===============================
-GUI class for quotes dialog
File History:
Created: 2020-06-18 [0.9]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/dialogs/updates.py b/novelwriter/dialogs/updates.py
index c40cb5a4..9553fa8d 100644
--- a/novelwriter/dialogs/updates.py
+++ b/novelwriter/dialogs/updates.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Updates
=========================
-A dialog box for checking for latest updates
File History:
Created: 2021-08-21 [1.5b1]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import json
import logging
diff --git a/novelwriter/enum.py b/novelwriter/enum.py
index aeab3f5e..1abc29c7 100644
--- a/novelwriter/enum.py
+++ b/novelwriter/enum.py
@@ -1,7 +1,6 @@
"""
novelWriter – Enums
===================
-Global enum values
File History:
Created: 2018-11-02 [0.0.1]
diff --git a/novelwriter/extensions/configlayout.py b/novelwriter/extensions/configlayout.py
index 93d348be..68ac39e2 100644
--- a/novelwriter/extensions/configlayout.py
+++ b/novelwriter/extensions/configlayout.py
@@ -1,7 +1,6 @@
"""
novelWriter – Custom Widget: Config Layout
==========================================
-A custom grid layout for config pages
File History:
Created: 2020-05-03 [0.4.5]
diff --git a/novelwriter/extensions/pageddialog.py b/novelwriter/extensions/pageddialog.py
index 28bd817c..aa8de6e2 100644
--- a/novelwriter/extensions/pageddialog.py
+++ b/novelwriter/extensions/pageddialog.py
@@ -1,7 +1,6 @@
"""
novelWriter – Custom Widget: Paged Dialog
=========================================
-A custom dialog with tabs and a vertical tab bar
File History:
Created: 2020-05-17 [0.5.1]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
from PyQt5.QtCore import QRect, QPoint
from PyQt5.QtWidgets import (
diff --git a/novelwriter/extensions/switch.py b/novelwriter/extensions/switch.py
index 529db854..be90bec7 100644
--- a/novelwriter/extensions/switch.py
+++ b/novelwriter/extensions/switch.py
@@ -1,7 +1,6 @@
"""
novelWriter – Custom Widget: Switch
===================================
-A custom switch widget
File History:
Created: 2020-05-03 [0.4.5]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
from PyQt5.QtGui import QPainter
from PyQt5.QtCore import Qt, QRectF, QPropertyAnimation, pyqtProperty
diff --git a/novelwriter/gui/components.py b/novelwriter/gui/components.py
index ffa19af1..762f0b0c 100644
--- a/novelwriter/gui/components.py
+++ b/novelwriter/gui/components.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Components Module
===================================
-A module of various small GUI components
File History:
Created: 2020-05-17 [0.5.1] StatusLED
@@ -23,6 +22,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py
index 355a0b54..1032c886 100644
--- a/novelwriter/gui/dochighlight.py
+++ b/novelwriter/gui/dochighlight.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Syntax Highlighter
====================================
-Class for the main document editor syntax highlighter
File History:
Created: 2019-04-06 [0.0.1]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py
index c532d430..fdb5435f 100644
--- a/novelwriter/gui/docviewer.py
+++ b/novelwriter/gui/docviewer.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Document Viewer
=================================
-GUI classes for the main document viewer
File History:
Created: 2019-05-10 [0.0.1] GuiDocViewer
@@ -26,6 +25,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/gui/itemdetails.py b/novelwriter/gui/itemdetails.py
index 6270f2f0..df11ce2c 100644
--- a/novelwriter/gui/itemdetails.py
+++ b/novelwriter/gui/itemdetails.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Item Details Panel
====================================
-GUI class for the project tree item details panel
File History:
Created: 2019-04-24 [0.0.1]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py
index f74f7f18..dce2ca55 100644
--- a/novelwriter/gui/mainmenu.py
+++ b/novelwriter/gui/mainmenu.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Main Menu
===========================
-GUI class for the main window menu
File History:
Created: 2019-04-27 [0.0.1]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index fda64471..877dc1bd 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Novel Tree
============================
-GUI class for the main window novel tree
File History:
Created: 2020-12-20 [1.1rc1] GuiNovelTree
@@ -24,6 +23,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py
index 93b94ee8..0c75a6b1 100644
--- a/novelwriter/gui/outline.py
+++ b/novelwriter/gui/outline.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Project Outline
=================================
-GUI class for the project outline view
File History:
Created: 2022-05-15 [2.0rc1] GuiOutlineView
@@ -26,6 +25,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index f45de16f..a4dedd46 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Project Tree
==============================
-GUI classes for the main window project tree
File History:
Created: 2018-09-29 [0.0.1] GuiProjectTree
diff --git a/novelwriter/gui/sidebar.py b/novelwriter/gui/sidebar.py
index 8e8b608d..6ec9f308 100644
--- a/novelwriter/gui/sidebar.py
+++ b/novelwriter/gui/sidebar.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Main Window SideBar
=====================================
-GUI class for the main window side bar
File History:
Created: 2022-05-10 [2.0rc1]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/gui/statusbar.py b/novelwriter/gui/statusbar.py
index f14affff..e3512270 100644
--- a/novelwriter/gui/statusbar.py
+++ b/novelwriter/gui/statusbar.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI Main Window Status Bar
========================================
-GUI class for the main window status bar
File History:
Created: 2019-04-20 [0.0.1] GuiMainStatus
@@ -23,6 +22,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import logging
diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py
index c65fad5d..a91d9ae1 100644
--- a/novelwriter/gui/theme.py
+++ b/novelwriter/gui/theme.py
@@ -1,7 +1,6 @@
"""
novelWriter – Theme and Icons Classes
=====================================
-Classes managing and caching themes and icons
File History:
Created: 2019-05-18 [0.1.3] GuiTheme
diff --git a/novelwriter/tools/lipsum.py b/novelwriter/tools/lipsum.py
index b803caf6..d7aa9d51 100644
--- a/novelwriter/tools/lipsum.py
+++ b/novelwriter/tools/lipsum.py
@@ -1,7 +1,6 @@
"""
novelWriter – Lorem Ipsum Tool
==============================
-Simple tool for inserting placeholder text in a document
File History:
Created: 2022-04-02 [2.0rc1]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import random
import logging
diff --git a/novelwriter/tools/projwizard.py b/novelwriter/tools/projwizard.py
index c4f61416..6564320a 100644
--- a/novelwriter/tools/projwizard.py
+++ b/novelwriter/tools/projwizard.py
@@ -1,7 +1,6 @@
"""
novelWriter – GUI New Project Wizard
====================================
-GUI classes for the new project wizard dialog
File History:
Created: 2020-07-11 [0.10.1]
@@ -22,6 +21,7 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+from __future__ import annotations
import os
import logging
From eeadfc95e3b7d75c6df63e148e7aed67633f9a56 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 8 Aug 2023 22:37:48 +0200
Subject: [PATCH 06/10] Annotate core modules
---
novelwriter/common.py | 16 ++---
novelwriter/core/buildsettings.py | 32 ++++-----
novelwriter/core/coretools.py | 13 ++--
novelwriter/core/docbuild.py | 6 +-
novelwriter/core/projectdata.py | 43 ++++++------
novelwriter/core/projectxml.py | 26 ++++---
novelwriter/core/sessions.py | 4 +-
novelwriter/core/spellcheck.py | 10 +--
novelwriter/core/status.py | 104 ++++++++++++----------------
novelwriter/core/storage.py | 18 ++---
novelwriter/core/tohtml.py | 24 +++----
novelwriter/core/tokenizer.py | 68 +++++++++---------
novelwriter/core/tomd.py | 18 +++--
novelwriter/core/toodt.py | 90 ++++++++++++------------
sample/nwProject.nwx | 4 +-
tests/test_core/test_core_status.py | 2 +-
16 files changed, 232 insertions(+), 246 deletions(-)
diff --git a/novelwriter/common.py b/novelwriter/common.py
index 35db1c9c..17fb6403 100644
--- a/novelwriter/common.py
+++ b/novelwriter/common.py
@@ -30,7 +30,7 @@ import logging
import unicodedata
import xml.etree.ElementTree as ET
-from typing import Any, Literal
+from typing import Any, Literal, TypeGuard
from pathlib import Path
from datetime import datetime
from configparser import ConfigParser
@@ -134,7 +134,7 @@ def checkPath(value: Any, default: Path) -> Path:
# Validator Functions
# =============================================================================================== #
-def isHandle(value: Any) -> bool:
+def isHandle(value: Any) -> TypeGuard[str]:
"""Check if a string is a valid novelWriter handle.
Note: This is case sensitive. Must be lower case!
"""
@@ -148,7 +148,7 @@ def isHandle(value: Any) -> bool:
return True
-def isTitleTag(value: Any) -> bool:
+def isTitleTag(value: Any) -> TypeGuard[str]:
"""Check if a string is a valid title tag string."""
if not isinstance(value, str):
return False
@@ -288,8 +288,7 @@ def transferCase(source: str, target: str) -> str:
def fuzzyTime(seconds: int) -> str:
- """Converts a time difference in seconds into a fuzzy time string.
- """
+ """Convert a time difference in seconds into a fuzzy time string."""
if seconds < 0:
return QCoreApplication.translate(
"Common", "in the future"
@@ -349,8 +348,7 @@ def fuzzyTime(seconds: int) -> str:
def numberToRoman(value: int, toLower: bool = False) -> str:
- """Convert an integer to a Roman number.
- """
+ """Convert an integer to a Roman number."""
if not isinstance(value, int):
return "NAN"
if value < 1 or value > 4999:
@@ -423,12 +421,14 @@ def jsonEncode(data: dict | list | tuple, n: int = 0, nmax: int = 0) -> str:
return "".join(buffer)
-def xmlIndent(tree: ET.Element | ET.ElementTree):
+def xmlIndent(tree: ET.Element | ET.ElementTree) -> None:
"""A modified version of the XML indent function in the standard
library. It behaves more closely to how the one from lxml does.
"""
if isinstance(tree, ET.ElementTree):
tree = tree.getroot()
+ if not isinstance(tree, ET.Element):
+ return
indentations = ["\n"]
diff --git a/novelwriter/core/buildsettings.py b/novelwriter/core/buildsettings.py
index ff869351..64196ed1 100644
--- a/novelwriter/core/buildsettings.py
+++ b/novelwriter/core/buildsettings.py
@@ -153,7 +153,7 @@ class BuildSettings:
The settings can be packed/unpacked to/from a dictionary for JSON.
"""
- def __init__(self):
+ def __init__(self) -> None:
self._name = ""
self._uuid = str(uuid.uuid4())
self._path = Path.home()
@@ -239,12 +239,12 @@ class BuildSettings:
# Setters
##
- def setName(self, name: str):
+ def setName(self, name: str) -> None:
"""Set the build setting display name."""
self._name = str(name)
return
- def setBuildID(self, value: str | uuid.UUID):
+ def setBuildID(self, value: str | uuid.UUID) -> None:
"""Set a UUID build ID."""
value = checkUuid(value, "")
if not value:
@@ -253,7 +253,7 @@ class BuildSettings:
self._uuid = value
return
- def setLastPath(self, path: Path | str | None):
+ def setLastPath(self, path: Path | str | None) -> None:
"""Set the last used build path."""
if isinstance(path, str):
path = Path(path)
@@ -264,41 +264,41 @@ class BuildSettings:
self._changed = True
return
- def setLastBuildName(self, name: str):
+ def setLastBuildName(self, name: str) -> None:
"""Set the last used build name."""
self._build = str(name).strip()
self._changed = True
return
- def setLastFormat(self, value: nwBuildFmt):
+ def setLastFormat(self, value: nwBuildFmt) -> None:
"""Set the last used build format."""
if isinstance(value, nwBuildFmt):
self._format = value
self._changed = True
return
- def setFiltered(self, tHandle: str):
+ def setFiltered(self, tHandle: str) -> None:
"""Set an item as filtered."""
self._excluded.discard(tHandle)
self._included.discard(tHandle)
self._changed = True
return
- def setIncluded(self, tHandle: str):
+ def setIncluded(self, tHandle: str) -> None:
"""Set an item as explicitly included."""
self._excluded.discard(tHandle)
self._included.add(tHandle)
self._changed = True
return
- def setExcluded(self, tHandle: str):
+ def setExcluded(self, tHandle: str) -> None:
"""Set an item as explicitly excluded."""
self._excluded.add(tHandle)
self._included.discard(tHandle)
self._changed = True
return
- def setAllowRoot(self, tHandle: str, state: bool):
+ def setAllowRoot(self, tHandle: str, state: bool) -> None:
"""Set a specific root folder as allowed or not."""
if state is True:
self._skipRoot.discard(tHandle)
@@ -386,7 +386,7 @@ class BuildSettings:
return result
- def resetChangedState(self):
+ def resetChangedState(self) -> None:
"""Reset the changed status of the settings object. This must be
called when the changes have been safely saved or passed on.
"""
@@ -410,7 +410,7 @@ class BuildSettings:
}
}
- def unpack(self, data: dict):
+ def unpack(self, data: dict) -> None:
"""Unpack a dictionary and populate the class."""
settings = data.get("settings", {})
content = data.get("content", {})
@@ -454,13 +454,13 @@ class BuildCollection:
project folder.
"""
- def __init__(self, project: NWProject):
+ def __init__(self, project: NWProject) -> None:
self._project = project
self._builds = {}
self._loadCollection()
return
- def __len__(self):
+ def __len__(self) -> int:
"""Return the number of builds."""
return len(self._builds)
@@ -476,7 +476,7 @@ class BuildCollection:
build.unpack(self._builds[buildID])
return build
- def setBuild(self, build: BuildSettings):
+ def setBuild(self, build: BuildSettings) -> None:
"""Set build settings data in the collection."""
if isinstance(build, BuildSettings):
buildID = build.buildID
@@ -484,7 +484,7 @@ class BuildCollection:
self._saveCollection()
return
- def removeBuild(self, buildID: str):
+ def removeBuild(self, buildID: str) -> None:
"""Remove the a build from the collection."""
self._builds.pop(buildID, None)
self._saveCollection()
diff --git a/novelwriter/core/coretools.py b/novelwriter/core/coretools.py
index 114c92ff..094c8c55 100644
--- a/novelwriter/core/coretools.py
+++ b/novelwriter/core/coretools.py
@@ -80,7 +80,7 @@ class DocMerger:
and a new doc label. Calling this function resets the class.
"""
srcItem = self._project.tree[srcHandle]
- if srcItem is None:
+ if srcItem is None or srcItem.itemParent is None:
return None
newHandle = self._project.newFile(docLabel, srcItem.itemParent)
@@ -210,7 +210,7 @@ class DocSplitter:
"""An iterator that will write each document in the buffer, and
return its new handle, parent handle, and sibling handle.
"""
- if self._srcHandle is None or self._srcItem is None:
+ if self._srcHandle is None or self._srcItem is None or self._parHandle is None:
return
pHandle = self._parHandle
@@ -385,9 +385,10 @@ class ProjectBuilder:
aDoc = project.storage.getDocument(hChapter)
aDoc.writeDocument(f"## {lblNewChapter}\n\n")
- hScene = project.newFile(lblNewScene, hChapter)
- aDoc = project.storage.getDocument(hScene)
- aDoc.writeDocument(f"### {lblNewScene}\n\n")
+ if hChapter:
+ hScene = project.newFile(lblNewScene, hChapter)
+ aDoc = project.storage.getDocument(hScene)
+ aDoc.writeDocument(f"### {lblNewScene}\n\n")
project.newRoot(nwItemClass.PLOT)
project.newRoot(nwItemClass.CHARACTER)
@@ -418,7 +419,7 @@ class ProjectBuilder:
aDoc.writeDocument(f"## {chTitle}\n\n% Synopsis: {chSynop}\n\n")
# Create chapter scenes
- if numScenes > 0:
+ if numScenes > 0 and cHandle:
for sc in range(numScenes):
scTitle = self.tr("Scene {0}").format(f"{ch+1:d}.{sc+1:d}")
sHandle = project.newFile(scTitle, cHandle)
diff --git a/novelwriter/core/docbuild.py b/novelwriter/core/docbuild.py
index c3301e0f..f5020bba 100644
--- a/novelwriter/core/docbuild.py
+++ b/novelwriter/core/docbuild.py
@@ -54,7 +54,7 @@ class NWBuildDocument:
__slots__ = ("_project", "_build", "_queue", "_error", "_cache")
- def __init__(self, project: NWProject, build: BuildSettings):
+ def __init__(self, project: NWProject, build: BuildSettings) -> None:
self._project = project
self._build = build
self._queue = []
@@ -91,12 +91,12 @@ class NWBuildDocument:
# Methods
##
- def addDocument(self, tHandle: str):
+ def addDocument(self, tHandle: str) -> None:
"""Add a document to the build queue manually."""
self._queue.append(tHandle)
return
- def queueAll(self):
+ def queueAll(self) -> None:
"""Queue all document as defined by the build settings."""
self._queue = []
filtered = self._build.buildItemFilter(self._project)
diff --git a/novelwriter/core/projectdata.py b/novelwriter/core/projectdata.py
index 18927271..9b0cc36c 100644
--- a/novelwriter/core/projectdata.py
+++ b/novelwriter/core/projectdata.py
@@ -26,13 +26,16 @@ from __future__ import annotations
import uuid
import logging
-from typing import Any
+from typing import TYPE_CHECKING, Any
from novelwriter.common import (
checkBool, checkInt, checkStringNone, checkUuid, isHandle, simplified
)
from novelwriter.core.status import NWStatus
+if TYPE_CHECKING: # pragma: no cover
+ from novelwriter.core.project import NWProject
+
logger = logging.getLogger(__name__)
@@ -43,7 +46,7 @@ class NWProjectData:
the list of project items.
"""
- def __init__(self, project):
+ def __init__(self, project: NWProject) -> None:
self._project = project
@@ -184,13 +187,13 @@ class NWProjectData:
# Methods
##
- def incSaveCount(self):
+ def incSaveCount(self) -> None:
"""Increment the save count by one."""
self._saveCount += 1
self._project.setProjectChanged(True)
return
- def incAutoCount(self):
+ def incAutoCount(self) -> None:
"""Increment the auto save count by one."""
self._autoCount += 1
self._project.setProjectChanged(True)
@@ -208,7 +211,7 @@ class NWProjectData:
# Setters
##
- def setUuid(self, value: Any):
+ def setUuid(self, value: Any) -> None:
"""Set the project id."""
value = checkUuid(value, "")
if not value:
@@ -218,74 +221,74 @@ class NWProjectData:
self._project.setProjectChanged(True)
return
- def setName(self, value: str | None):
+ def setName(self, value: str | None) -> None:
"""Set a new project name."""
if value != self._name:
self._name = simplified(str(value or ""))
self._project.setProjectChanged(True)
return
- def setTitle(self, value: str | None):
+ def setTitle(self, value: str | None) -> None:
"""Set a new novel title."""
if value != self._title:
self._title = simplified(str(value or ""))
self._project.setProjectChanged(True)
return
- def setAuthor(self, value: str | None):
+ def setAuthor(self, value: str | None) -> None:
"""Set the author value."""
if value != self._title:
self._author = simplified(str(value or ""))
self._project.setProjectChanged(True)
return
- def setSaveCount(self, value: Any):
+ def setSaveCount(self, value: Any) -> None:
"""Set the save count from last session."""
self._saveCount = checkInt(value, 0)
self._project.setProjectChanged(True)
return
- def setAutoCount(self, value: Any):
+ def setAutoCount(self, value: Any) -> None:
"""Set the auto save count from last session."""
self._autoCount = checkInt(value, 0)
self._project.setProjectChanged(True)
return
- def setEditTime(self, value: Any):
+ def setEditTime(self, value: Any) -> None:
"""Set the edit time from last session."""
self._editTime = checkInt(value, 0)
self._project.setProjectChanged(True)
return
- def setDoBackup(self, value: Any):
+ def setDoBackup(self, value: Any) -> None:
"""Set the do write backup flag."""
if value != self._doBackup:
self._doBackup = checkBool(value, False)
self._project.setProjectChanged(True)
return
- def setLanguage(self, value: str | None):
+ def setLanguage(self, value: str | None) -> None:
"""Set the project language."""
if value != self._language:
self._language = checkStringNone(value, None)
self._project.setProjectChanged(True)
return
- def setSpellCheck(self, value: Any):
+ def setSpellCheck(self, value: Any) -> None:
"""Set the spell check flag."""
if value != self._spellCheck:
self._spellCheck = checkBool(value, False)
self._project.setProjectChanged(True)
return
- def setSpellLang(self, value: str | None):
+ def setSpellLang(self, value: str | None) -> None:
"""Set the spell check language."""
if value != self._spellLang:
self._spellLang = checkStringNone(value, None)
self._project.setProjectChanged(True)
return
- def setLastHandle(self, value: str | None, component: str):
+ def setLastHandle(self, value: str | None, component: str) -> None:
"""Set a last used handle into the handle registry for a given
component.
"""
@@ -294,7 +297,7 @@ class NWProjectData:
self._project.setProjectChanged(True)
return
- def setLastHandles(self, value: dict):
+ def setLastHandles(self, value: dict) -> None:
"""Set the full last handles dictionary to a new set of values.
This is intended to be used at project load.
"""
@@ -305,7 +308,7 @@ class NWProjectData:
self._project.setProjectChanged(True)
return
- def setInitCounts(self, novel: Any = None, notes: Any = None):
+ def setInitCounts(self, novel: Any = None, notes: Any = None) -> None:
"""Set the word count totals for novel and note files."""
if novel is not None:
self._initCounts[0] = checkInt(novel, 0)
@@ -315,7 +318,7 @@ class NWProjectData:
self._currCounts[1] = checkInt(notes, 0)
return
- def setCurrCounts(self, novel: Any = None, notes: Any = None):
+ def setCurrCounts(self, novel: Any = None, notes: Any = None) -> None:
"""Set the word count totals for novel and note files."""
if novel is not None:
self._currCounts[0] = checkInt(novel, 0)
@@ -323,7 +326,7 @@ class NWProjectData:
self._currCounts[1] = checkInt(notes, 0)
return
- def setAutoReplace(self, value: dict):
+ def setAutoReplace(self, value: dict) -> None:
"""Set the auto-replace dictionary."""
if isinstance(value, dict):
self._autoReplace = {}
diff --git a/novelwriter/core/projectxml.py b/novelwriter/core/projectxml.py
index 055fe4ef..c12e0dc0 100644
--- a/novelwriter/core/projectxml.py
+++ b/novelwriter/core/projectxml.py
@@ -110,7 +110,7 @@ class ProjectXMLReader:
Rev 1: Drops the titleFormat section of settings.
"""
- def __init__(self, path):
+ def __init__(self, path: str | Path) -> None:
self._path = Path(path)
self._state = XMLReadState.NO_ACTION
self._root = ""
@@ -236,7 +236,7 @@ class ProjectXMLReader:
# Internal Functions
##
- def _parseProjectMeta(self, xSection: ET.Element, data: NWProjectData):
+ def _parseProjectMeta(self, xSection: ET.Element, data: NWProjectData) -> None:
"""Parse the project section of the XML file."""
logger.debug("Parsing section")
@@ -267,7 +267,7 @@ class ProjectXMLReader:
return
- def _parseProjectSettings(self, xSection: ET.Element, data: NWProjectData):
+ def _parseProjectSettings(self, xSection: ET.Element, data: NWProjectData) -> None:
"""Parse the settings section of the XML file."""
logger.debug("Parsing section")
@@ -307,7 +307,9 @@ class ProjectXMLReader:
return
- def _parseProjectContent(self, xSection: ET.Element, data: NWProjectData, content: list):
+ def _parseProjectContent(
+ self, xSection: ET.Element, data: NWProjectData, content: list
+ ) -> None:
"""Parse the content section of the XML file."""
logger.debug("Parsing section")
@@ -362,7 +364,9 @@ class ProjectXMLReader:
return
- def _parseProjectContentLegacy(self, xSection: ET.Element, data: NWProjectData, content: list):
+ def _parseProjectContentLegacy(
+ self, xSection: ET.Element, data: NWProjectData, content: list
+ ) -> None:
"""Parse the content section of the XML file for older versions."""
logger.debug("Parsing section (legacy format)")
@@ -438,7 +442,7 @@ class ProjectXMLReader:
return
- def _parseStatusImport(self, xItem: ET.Element, sObject: NWStatus):
+ def _parseStatusImport(self, xItem: ET.Element, sObject: NWStatus) -> None:
"""Parse a status or importance entry."""
for xEntry in xItem:
if xEntry.tag == "entry":
@@ -447,7 +451,7 @@ class ProjectXMLReader:
green = checkInt(xEntry.attrib.get("green", 0), 0)
blue = checkInt(xEntry.attrib.get("blue", 0), 0)
count = checkInt(xEntry.attrib.get("count", 0), 0)
- sObject.write(key, xEntry.text, (red, green, blue), count)
+ sObject.write(key, xEntry.text or "", (red, green, blue), count)
return
def _parseDictKeyText(self, xItem: ET.Element) -> dict:
@@ -460,7 +464,7 @@ class ProjectXMLReader:
result[xEntry.attrib["key"]] = checkString(xEntry.text, "")
return result
- def _parseDictTagText(self, xItem):
+ def _parseDictTagText(self, xItem) -> dict:
"""Parse a dictionary stored with key as the tag and the value
as the text property.
"""
@@ -476,7 +480,7 @@ class ProjectXMLWriter:
very latest spec.
"""
- def __init__(self, path):
+ def __init__(self, path: str | Path) -> None:
self._path = Path(path)
self._error = None
return
@@ -585,13 +589,13 @@ class ProjectXMLWriter:
def _packSingleValue(
self, xParent: ET.Element, name: str, value: str | None, attrib: dict | None = None
- ):
+ ) -> None:
"""Pack a single value into an XML element."""
xItem = ET.SubElement(xParent, name, attrib=attrib or {})
xItem.text = str(value) or ""
return
- def _packDictKeyValue(self, xParent: ET.Element, name: str, data: dict):
+ def _packDictKeyValue(self, xParent: ET.Element, name: str, data: dict) -> None:
"""Pack the entries of a dictionary into an XML element."""
xItem = ET.SubElement(xParent, name)
for key, value in data.items():
diff --git a/novelwriter/core/sessions.py b/novelwriter/core/sessions.py
index aa9da7e8..dfbf720e 100644
--- a/novelwriter/core/sessions.py
+++ b/novelwriter/core/sessions.py
@@ -47,7 +47,7 @@ class NWSessionLog:
format. That is, one JSON object per line.
"""
- def __init__(self, project: NWProject):
+ def __init__(self, project: NWProject) -> None:
self._project = project
self._start = 0.0
return
@@ -65,7 +65,7 @@ class NWSessionLog:
# Methods
##
- def startSession(self):
+ def startSession(self) -> None:
"""Start the writing session."""
self._start = time()
return
diff --git a/novelwriter/core/spellcheck.py b/novelwriter/core/spellcheck.py
index b5cac3a2..d7d55d91 100644
--- a/novelwriter/core/spellcheck.py
+++ b/novelwriter/core/spellcheck.py
@@ -45,7 +45,7 @@ class NWSpellEnchant:
between spell check tools.
"""
- def __init__(self, project: NWProject):
+ def __init__(self, project: NWProject) -> None:
self._project = project
self._dictObj = FakeEnchant()
self._userDict = UserDictionary(project)
@@ -165,7 +165,7 @@ class NWSpellEnchant:
class FakeEnchant:
"""Fallback for when Enchant is selected, but not installed."""
- def __init__(self):
+ def __init__(self) -> None:
class FakeProvider:
name = ""
@@ -189,7 +189,7 @@ class FakeEnchant:
class UserDictionary:
- def __init__(self, project: NWProject):
+ def __init__(self, project: NWProject) -> None:
self._project = project
self._words = set()
self._path = None
@@ -210,7 +210,7 @@ class UserDictionary:
self._words.add(word)
return True
- def load(self):
+ def load(self) -> None:
"""Load the user's dictionary."""
self._path = self._project.storage.getMetaFile(nwFiles.DICT_FILE)
if not isinstance(self._path, Path):
@@ -224,7 +224,7 @@ class UserDictionary:
logException()
return
- def save(self):
+ def save(self) -> None:
"""Save the user's dictionary."""
if self._path is None:
self._path = self._project.storage.getMetaFile(nwFiles.DICT_FILE)
diff --git a/novelwriter/core/status.py b/novelwriter/core/status.py
index 88b4467a..ac26641f 100644
--- a/novelwriter/core/status.py
+++ b/novelwriter/core/status.py
@@ -27,6 +27,8 @@ from __future__ import annotations
import random
import logging
+from typing import ItemsView, Iterator, KeysView, Literal, TypeGuard, ValuesView
+
from PyQt5.QtGui import QIcon, QPainter, QPainterPath, QPixmap, QColor
from PyQt5.QtCore import QRectF, Qt
@@ -41,9 +43,9 @@ class NWStatus:
STATUS = 1
IMPORT = 2
- def __init__(self, type):
+ def __init__(self, kind: Literal[1, 2]) -> None:
- self._type = type
+ self._type = kind
self._store = {}
self._default = None
@@ -66,7 +68,7 @@ class NWStatus:
return
- def write(self, key, name, col, count=None):
+ def write(self, key: str | None, name: str, col: tuple, count: int | None = None) -> str:
"""Add or update a status entry. If the key is invalid, a new
key is generated.
"""
@@ -96,10 +98,8 @@ class NWStatus:
return key
- def remove(self, key):
- """Remove an entry in the list, but not if the count is larger
- than 0.
- """
+ def remove(self, key: str) -> bool:
+ """Remove an entry in the list, except if the count > 0."""
if key not in self._store:
return False
if self._store[key]["count"] > 0:
@@ -116,59 +116,49 @@ class NWStatus:
return True
- def check(self, value):
- """Check the key against the stored status names.
- """
+ def check(self, value: str) -> str:
+ """Check the key against the stored status names."""
if self._isKey(value) and value in self._store:
return value
elif self._default is not None:
return self._default
- else:
- return ""
+ return ""
- def name(self, key):
- """Return the name associated with a given key.
- """
+ def name(self, key: str) -> str:
+ """Return the name associated with a given key."""
if key in self._store:
return self._store[key]["name"]
elif self._default is not None:
return self._store[self._default]["name"]
- else:
- return ""
+ return ""
- def cols(self, key):
+ def cols(self, key: str) -> tuple[int, int, int]:
"""Return the colours associated with a given key.
"""
if key in self._store:
return self._store[key]["cols"]
elif self._default is not None:
return self._store[self._default]["cols"]
- else:
- return (100, 100, 100)
+ return 100, 100, 100
- def count(self, key):
- """Return the count associated with a given key.
- """
+ def count(self, key: str) -> int:
+ """Return the count associated with a given key."""
if key in self._store:
return self._store[key]["count"]
elif self._default is not None:
return self._store[self._default]["count"]
- else:
- return 0
+ return 0
- def icon(self, key):
- """Return the icon associated with a given key.
- """
+ def icon(self, key: str) -> QIcon:
+ """Return the icon associated with a given key."""
if key in self._store:
return self._store[key]["icon"]
elif self._default is not None:
return self._store[self._default]["icon"]
- else:
- return self._defaultIcon
+ return self._defaultIcon
- def reorder(self, order):
- """Reorder the items according to list.
- """
+ def reorder(self, order: list[str]) -> bool:
+ """Reorder the items according to list."""
if len(order) != len(self._store):
logger.error("Length mismatch between new and old order")
return False
@@ -188,23 +178,20 @@ class NWStatus:
return True
- def resetCounts(self):
- """Clear the counts of references to the status entries.
- """
+ def resetCounts(self) -> None:
+ """Clear the counts of references to the status entries."""
for key in self._store:
self._store[key]["count"] = 0
return
- def increment(self, key):
- """Increment the counter for a given entry.
- """
+ def increment(self, key: str) -> None:
+ """Increment the counter for a given entry."""
if key in self._store:
self._store[key]["count"] += 1
return
- def pack(self):
- """Pack the status entries into a dictionary.
- """
+ def pack(self) -> Iterator[tuple[str, dict]]:
+ """Pack the status entries into a dictionary."""
for key, data in self._store.items():
yield (data["name"], {
"key": key,
@@ -215,25 +202,22 @@ class NWStatus:
})
return
- def unpack(self, data):
- """Unpack a data dictionary and set the class values.
- """
+ def unpack(self, data: dict) -> None:
+ """Unpack a data dictionary and set the class values."""
self._store = {}
self._default = None
-
for key, entry in data.items():
label = entry.get("label", "")
colour = entry.get("colour", (100, 100, 100))
count = entry.get("count", 0)
self.write(key, label, colour, count)
-
- return True
+ return
##
# Internal Functions
##
- def _newKey(self):
+ def _newKey(self) -> str:
"""Generate a new key for a status flag. This method is
recursive, but should only fail if there is an issue with the
random number generator or the user has added a lot of status
@@ -245,9 +229,8 @@ class NWStatus:
key = self._newKey()
return key
- def _isKey(self, value):
- """Check if a value is a key or not.
- """
+ def _isKey(self, value: str | None) -> TypeGuard[str]:
+ """Check if a value is a key or not."""
if not isinstance(value, str):
return False
if len(value) != 7:
@@ -259,9 +242,8 @@ class NWStatus:
return False
return True
- def _createIcon(self, red, green, blue):
- """Generate an icon for a status label.
- """
+ def _createIcon(self, red: int, green: int, blue: int) -> QIcon:
+ """Generate an icon for a status label."""
pixmap = QPixmap(self._iPX, self._iPX)
pixmap.fill(Qt.transparent)
@@ -276,22 +258,22 @@ class NWStatus:
# Iterator Bits
##
- def __len__(self):
+ def __len__(self) -> int:
return len(self._store)
- def __getitem__(self, key):
+ def __getitem__(self, key: str) -> dict:
return self._store[key]
- def __iter__(self):
+ def __iter__(self) -> Iterator[dict]:
return iter(self._store)
- def keys(self):
+ def keys(self) -> KeysView[str]:
return self._store.keys()
- def items(self):
+ def items(self) -> ItemsView[str, dict]:
return self._store.items()
- def values(self):
+ def values(self) -> ValuesView[dict]:
return self._store.values()
# END Class NWStatus
diff --git a/novelwriter/core/storage.py b/novelwriter/core/storage.py
index 84e4ee35..d8740c0e 100644
--- a/novelwriter/core/storage.py
+++ b/novelwriter/core/storage.py
@@ -55,7 +55,7 @@ class NWStorage:
MODE_INPLACE = 1
MODE_ARCHIVE = 2
- def __init__(self, project: NWProject):
+ def __init__(self, project: NWProject) -> None:
self._project = project
self._storagePath = None
self._runtimePath = None
@@ -63,7 +63,7 @@ class NWStorage:
self._openMode = self.MODE_INACTIVE
return
- def clear(self):
+ def clear(self) -> None:
"""Reset internal variables."""
self._storagePath = None
self._runtimePath = None
@@ -145,7 +145,7 @@ class NWStorage:
return True
return True
- def closeSession(self):
+ def closeSession(self) -> None:
"""Run tasks related to closing the session."""
self.clearLockFile()
self.clear()
@@ -353,11 +353,11 @@ class _LegacyStorage:
file/folder layout to the current project format.
"""
- def __init__(self, project: NWProject):
+ def __init__(self, project: NWProject) -> None:
self._project = project
return
- def legacyDataFolder(self, path: Path, child: Path):
+ def legacyDataFolder(self, path: Path, child: Path) -> None:
"""Handle the content of a legacy data folder from a version 1.0
project.
"""
@@ -396,7 +396,7 @@ class _LegacyStorage:
return
- def deprecatedFiles(self, path: Path):
+ def deprecatedFiles(self, path: Path) -> None:
"""Handle files that are no longer used by novelWriter."""
self._convertOldWordList( # Changed in 2.1 Beta 1
path / "meta" / "wordlist.txt",
@@ -440,7 +440,7 @@ class _LegacyStorage:
# Internal Functions
##
- def _convertOldWordList(self, wordList: Path, wordJson: Path):
+ def _convertOldWordList(self, wordList: Path, wordJson: Path) -> None:
"""Convert the old word list plain text file to new format."""
if wordJson.exists() or not wordList.exists():
# If the new file already exists, we won't overwrite it
@@ -466,7 +466,7 @@ class _LegacyStorage:
return
- def _convertOldLogFile(self, sessLog: Path, sessJson: Path):
+ def _convertOldLogFile(self, sessLog: Path, sessJson: Path) -> None:
"""Convert the old text log file format to the new JSON Lines
format.
"""
@@ -507,7 +507,7 @@ class _LegacyStorage:
return
- def _convertOldOptionsFile(self, optsOld: Path, optsNew: Path):
+ def _convertOldOptionsFile(self, optsOld: Path, optsNew: Path) -> None:
"""Convert the old options state file format to the format."""
if optsNew.exists() or not optsOld.exists():
# If the new file already exists, we won't overwrite it
diff --git a/novelwriter/core/tohtml.py b/novelwriter/core/tohtml.py
index 20c01701..8459ae59 100644
--- a/novelwriter/core/tohtml.py
+++ b/novelwriter/core/tohtml.py
@@ -49,12 +49,12 @@ class ToHtml(Tokenizer):
M_EXPORT = 1 # Tweak output for saving to HTML or printing
M_EBOOK = 2 # Tweak output for converting to epub
- def __init__(self, project: NWProject):
+ def __init__(self, project: NWProject) -> None:
super().__init__(project)
self._genMode = self.M_EXPORT
self._cssStyles = True
- self._fullHTML = []
+ self._fullHTML: list[str] = []
# Internals
self._trMap = {}
@@ -67,14 +67,14 @@ class ToHtml(Tokenizer):
##
@property
- def fullHTML(self):
+ def fullHTML(self) -> list[str]:
return self._fullHTML
##
# Setters
##
- def setPreview(self, doComments: bool, doSynopsis: bool):
+ def setPreview(self, doComments: bool, doSynopsis: bool) -> None:
"""If we're using this class to generate markdown preview, we
need to make a few changes to formatting, which is managed by
these flags.
@@ -85,14 +85,14 @@ class ToHtml(Tokenizer):
self._doSynopsis = doSynopsis
return
- def setStyles(self, cssStyles: bool):
+ def setStyles(self, cssStyles: bool) -> None:
"""Enable or disable CSS styling. Some elements may still have
class tags.
"""
self._cssStyles = cssStyles
return
- def setReplaceUnicode(self, doReplace: bool):
+ def setReplaceUnicode(self, doReplace: bool) -> None:
"""Set the translation map to either minimal or full unicode for
html entities replacement.
"""
@@ -113,7 +113,7 @@ class ToHtml(Tokenizer):
"""Return the size of the full HTML result."""
return sum([len(x) for x in self._fullHTML])
- def doPreProcessing(self):
+ def doPreProcessing(self) -> None:
"""Extend the auto-replace to also properly encode some unicode
characters into their respective HTML entities.
"""
@@ -121,7 +121,7 @@ class ToHtml(Tokenizer):
self._text = self._text.translate(self._trMap)
return
- def doConvert(self):
+ def doConvert(self) -> None:
"""Convert the list of text tokens into a HTML document saved
to _result.
"""
@@ -299,7 +299,7 @@ class ToHtml(Tokenizer):
return
- def saveHtml5(self, path: str | Path):
+ def saveHtml5(self, path: str | Path) -> None:
"""Save the data to an HTML file."""
with open(path, mode="w", encoding="utf-8") as fObj:
fObj.write((
@@ -326,7 +326,7 @@ class ToHtml(Tokenizer):
logger.info("Wrote file: %s", path)
return
- def saveHtmlJson(self, path: str | Path):
+ def saveHtmlJson(self, path: str | Path) -> None:
"""Save the data to a JSON file."""
timeStamp = time()
data = {
@@ -347,7 +347,7 @@ class ToHtml(Tokenizer):
logger.info("Wrote file: %s", path)
return
- def replaceTabs(self, nSpaces: int = 8, spaceChar: str = " "):
+ def replaceTabs(self, nSpaces: int = 8, spaceChar: str = " ") -> None:
"""Replace tabs with spaces in the html."""
htmlText = []
tabSpace = spaceChar*nSpaces
@@ -357,7 +357,7 @@ class ToHtml(Tokenizer):
self._fullHTML = htmlText
return
- def getStyleSheet(self) -> list:
+ def getStyleSheet(self) -> list[str]:
"""Generate a stylesheet for the current settings."""
styles = []
if not self._cssStyles:
diff --git a/novelwriter/core/tokenizer.py b/novelwriter/core/tokenizer.py
index e1a9aea4..f5d54d29 100644
--- a/novelwriter/core/tokenizer.py
+++ b/novelwriter/core/tokenizer.py
@@ -44,7 +44,7 @@ from novelwriter.core.project import NWProject
logger = logging.getLogger(__name__)
-def stripEscape(text):
+def stripEscape(text) -> str:
"""Helper function to strip escaped Markdown characters from
paragraph text.
"""
@@ -100,7 +100,7 @@ class Tokenizer(ABC):
A_IND_L = 0x0100 # Left indentation
A_IND_R = 0x0200 # Right indentation
- def __init__(self, project: NWProject):
+ def __init__(self, project: NWProject) -> None:
self._project = project
@@ -191,116 +191,116 @@ class Tokenizer(ABC):
# Setters
##
- def setTitleFormat(self, hFormat: str):
+ def setTitleFormat(self, hFormat: str) -> None:
"""Set the title format pattern."""
self._fmtTitle = hFormat.strip()
return
- def setChapterFormat(self, hFormat: str):
+ def setChapterFormat(self, hFormat: str) -> None:
"""Set the chapert format pattern."""
self._fmtChapter = hFormat.strip()
return
- def setUnNumberedFormat(self, hFormat: str):
+ def setUnNumberedFormat(self, hFormat: str) -> None:
"""Set the unnumbered format pattern."""
self._fmtUnNum = hFormat.strip()
return
- def setSceneFormat(self, hFormat: str, hide: bool):
+ def setSceneFormat(self, hFormat: str, hide: bool) -> None:
"""Set the scene format pattern and hidden status."""
self._fmtScene = hFormat.strip()
self._hideScene = hide
return
- def setSectionFormat(self, hFormat: str, hide: bool):
+ def setSectionFormat(self, hFormat: str, hide: bool) -> None:
"""Set the section format pattern and hidden status."""
self._fmtSection = hFormat.strip()
self._hideSection = hide
return
- def setFont(self, family: str, size: int, isFixed: bool = False):
+ def setFont(self, family: str, size: int, isFixed: bool = False) -> None:
"""Set the build font."""
self._textFont = family
self._textSize = round(int(size))
self._textFixed = isFixed
return
- def setLineHeight(self, height: float):
+ def setLineHeight(self, height: float) -> None:
"""Set the line height between 0.5 and 5.0."""
self._lineHeight = min(max(float(height), 0.5), 5.0)
return
- def setBlockIndent(self, indent: float):
+ def setBlockIndent(self, indent: float) -> None:
"""Set the block indent between 0.0 and 10.0."""
self._blockIndent = min(max(float(indent), 0.0), 10.0)
return
- def setJustify(self, state: bool):
+ def setJustify(self, state: bool) -> None:
"""Enable or disable text justification."""
self._doJustify = state
return
- def setTitleMargins(self, upper: float, lower: float):
+ def setTitleMargins(self, upper: float, lower: float) -> None:
"""Set the upper and lower title margin."""
self._marginTitle = (float(upper), float(lower))
return
- def setHead1Margins(self, upper: float, lower: float):
+ def setHead1Margins(self, upper: float, lower: float) -> None:
"""Set the upper and lower header 1 margin."""
self._marginHead1 = (float(upper), float(lower))
return
- def setHead2Margins(self, upper: float, lower: float):
+ def setHead2Margins(self, upper: float, lower: float) -> None:
"""Set the upper and lower header 2 margin."""
self._marginHead2 = (float(upper), float(lower))
return
- def setHead3Margins(self, upper: float, lower: float):
+ def setHead3Margins(self, upper: float, lower: float) -> None:
"""Set the upper and lower header 3 margin."""
self._marginHead3 = (float(upper), float(lower))
return
- def setHead4Margins(self, upper: float, lower: float):
+ def setHead4Margins(self, upper: float, lower: float) -> None:
"""Set the upper and lower header 4 margin."""
self._marginHead4 = (float(upper), float(lower))
return
- def setTextMargins(self, upper: float, lower: float):
+ def setTextMargins(self, upper: float, lower: float) -> None:
"""Set the upper and lower text margin."""
self._marginText = (float(upper), float(lower))
return
- def setMetaMargins(self, upper: float, lower: float):
+ def setMetaMargins(self, upper: float, lower: float) -> None:
"""Set the upper and lower meta text margin."""
self._marginMeta = (float(upper), float(lower))
return
- def setLinkHeaders(self, state: bool):
+ def setLinkHeaders(self, state: bool) -> None:
"""Enable or disable adding an anchor before headers."""
self._linkHeaders = state
return
- def setBodyText(self, state: bool):
+ def setBodyText(self, state: bool) -> None:
"""Include body text in build."""
self._doBodyText = state
return
- def setSynopsis(self, state: bool):
+ def setSynopsis(self, state: bool) -> None:
"""Include synopsis comments in build."""
self._doSynopsis = state
return
- def setComments(self, state: bool):
+ def setComments(self, state: bool) -> None:
"""Include comments in build."""
self._doComments = state
return
- def setKeywords(self, state: bool):
+ def setKeywords(self, state: bool) -> None:
"""Include keywords in build."""
self._doKeywords = state
return
- def setKeepMarkdown(self, state: bool):
+ def setKeepMarkdown(self, state: bool) -> None:
"""Keep original markdown during build."""
self._keepMarkdown = state
return
@@ -310,7 +310,7 @@ class Tokenizer(ABC):
##
@abstractmethod
- def doConvert(self):
+ def doConvert(self) -> None:
raise NotImplementedError
def addRootHeading(self, tHandle: str) -> bool:
@@ -365,7 +365,7 @@ class Tokenizer(ABC):
return True
- def doPreProcessing(self):
+ def doPreProcessing(self) -> None:
"""Run trough the various replace dictionaries."""
# Process the user's auto-replace dictionary
autoReplace = self._project.data.autoReplace
@@ -382,7 +382,7 @@ class Tokenizer(ABC):
return
- def tokenizeText(self):
+ def tokenizeText(self) -> None:
"""Scan the text for either lines starting with specific
characters that indicate headers, comments, commands etc, or
just contain plain text. In the case of plain text, apply the
@@ -742,14 +742,14 @@ class Tokenizer(ABC):
return True
- def saveRawMarkdown(self, path: str | Path):
+ def saveRawMarkdown(self, path: str | Path) -> None:
"""Save the raw text to a plain text file."""
with open(path, mode="w", encoding="utf-8") as outFile:
for nwdPage in self._allMarkdown:
outFile.write(nwdPage)
return
- def saveRawMarkdownJSON(self, path: str | Path):
+ def saveRawMarkdownJSON(self, path: str | Path) -> None:
"""Save the raw text to a JSON file."""
timeStamp = time()
data = {
@@ -773,30 +773,30 @@ class Tokenizer(ABC):
class HeadingFormatter:
- def __init__(self, project: NWProject):
+ def __init__(self, project: NWProject) -> None:
self._project = project
self._chCount = 0
self._scChCount = 0
self._scAbsCount = 0
return
- def incChapter(self):
+ def incChapter(self) -> None:
"""Increment the chapter counter."""
self._chCount += 1
return
- def incScene(self):
+ def incScene(self) -> None:
"""Increment the scene counters."""
self._scChCount += 1
self._scAbsCount += 1
return
- def resetScene(self):
+ def resetScene(self) -> None:
"""Reset the chapter scene counter."""
self._scChCount = 0
return
- def apply(self, hFormat: str, text: str):
+ def apply(self, hFormat: str, text: str) -> str:
"""Apply formatting to a specific heading."""
hFormat = hFormat.replace(nwHeadFmt.TITLE, text)
hFormat = hFormat.replace(nwHeadFmt.CH_NUM, str(self._chCount))
diff --git a/novelwriter/core/tomd.py b/novelwriter/core/tomd.py
index e634de74..c9859318 100644
--- a/novelwriter/core/tomd.py
+++ b/novelwriter/core/tomd.py
@@ -45,12 +45,10 @@ class ToMarkdown(Tokenizer):
M_STD = 0 # Standard Markdown
M_GH = 1 # GitHub Markdown
- def __init__(self, project: NWProject):
+ def __init__(self, project: NWProject) -> None:
super().__init__(project)
-
self._genMode = self.M_STD
- self._fullMD = []
-
+ self._fullMD: list[str] = []
return
##
@@ -58,7 +56,7 @@ class ToMarkdown(Tokenizer):
##
@property
- def fullMD(self) -> list:
+ def fullMD(self) -> list[str]:
"""Return the markdown as a list."""
return self._fullMD
@@ -66,11 +64,11 @@ class ToMarkdown(Tokenizer):
# Setters
##
- def setStandardMarkdown(self):
+ def setStandardMarkdown(self) -> None:
self._genMode = self.M_STD
return
- def setGitHubMarkdown(self):
+ def setGitHubMarkdown(self) -> None:
self._genMode = self.M_GH
return
@@ -82,7 +80,7 @@ class ToMarkdown(Tokenizer):
"""Return the size of the full Markdown result."""
return sum([len(x) for x in self._fullMD])
- def doConvert(self):
+ def doConvert(self) -> None:
"""Convert the list of text tokens into a HTML document saved
to theResult.
"""
@@ -175,14 +173,14 @@ class ToMarkdown(Tokenizer):
return
- def saveMarkdown(self, path: str | Path):
+ def saveMarkdown(self, path: str | Path) -> None:
"""Save the data to a plain text file."""
with open(path, mode="w", encoding="utf-8") as outFile:
outFile.write("".join(self._fullMD))
logger.info("Wrote file: %s", path)
return
- def replaceTabs(self, nSpaces: int = 8, spaceChar: str = " "):
+ def replaceTabs(self, nSpaces: int = 8, spaceChar: str = " ") -> None:
"""Replace tabs with spaces."""
spaces = spaceChar*nSpaces
self._fullMD = [p.replace("\t", spaces) for p in self._fullMD]
diff --git a/novelwriter/core/toodt.py b/novelwriter/core/toodt.py
index 93b8afac..b69af17b 100644
--- a/novelwriter/core/toodt.py
+++ b/novelwriter/core/toodt.py
@@ -98,7 +98,7 @@ class ToOdt(Tokenizer):
Test with: https://odfvalidator.org/
"""
- def __init__(self, project: NWProject, isFlat: bool):
+ def __init__(self, project: NWProject, isFlat: bool) -> None:
super().__init__(project)
self._isFlat = isFlat # Flat: .fodt, otherwise .odt
@@ -188,7 +188,7 @@ class ToOdt(Tokenizer):
# Setters
##
- def setLanguage(self, language: str):
+ def setLanguage(self, language: str) -> None:
"""Set language for the document."""
if language:
langBits = language.split("_")
@@ -197,7 +197,7 @@ class ToOdt(Tokenizer):
self._dCountry = langBits[1]
return
- def setColourHeaders(self, state: bool):
+ def setColourHeaders(self, state: bool) -> None:
"""Enable/disable coloured headings and comments."""
self._colourHead = state
return
@@ -205,7 +205,7 @@ class ToOdt(Tokenizer):
def setPageLayout(
self, width: int | float, height: int | float,
top: int | float, bottom: int | float, left: int | float, right: int | float
- ):
+ ) -> None:
"""Set the document page size and margins in millimetres."""
self._mDocWidth = f"{width/10.0:.3f}cm"
self._mDocHeight = f"{height/10.0:.3f}cm"
@@ -219,7 +219,7 @@ class ToOdt(Tokenizer):
# Class Methods
##
- def initDocument(self):
+ def initDocument(self) -> None:
"""Initialises a new open document XML tree."""
# Initialise Variables
# ====================
@@ -381,7 +381,7 @@ class ToOdt(Tokenizer):
return
- def doConvert(self):
+ def doConvert(self) -> None:
"""Convert the list of text tokens into XML elements."""
self._result = "" # Not used, but cleared just in case
@@ -599,7 +599,7 @@ class ToOdt(Tokenizer):
def _addTextPar(
self, styleName: str, oStyle: ODTParagraphStyle, tText: str, tFmt: str = "",
isHead: bool = False, oLevel: str | None = None
- ):
+ ) -> None:
"""Add a text paragraph to the text XML element."""
tAttr = {}
tAttr[_mkTag("text", "style-name")] = self._paraStyle(styleName, oStyle)
@@ -726,7 +726,7 @@ class ToOdt(Tokenizer):
# Style Elements
##
- def _pageStyles(self):
+ def _pageStyles(self) -> None:
"""Set the default page style."""
tAttr = {}
tAttr[_mkTag("style", "name")] = "PM1"
@@ -756,7 +756,7 @@ class ToOdt(Tokenizer):
return
- def _defaultStyles(self):
+ def _defaultStyles(self) -> None:
"""Set the default styles."""
# Add Paragraph Family Style
# ==========================
@@ -829,7 +829,7 @@ class ToOdt(Tokenizer):
return
- def _useableStyles(self):
+ def _useableStyles(self) -> None:
"""Set the usable styles."""
# Add Text Body Style
# ===================
@@ -1002,7 +1002,7 @@ class ToOdt(Tokenizer):
return
- def _writeHeader(self):
+ def _writeHeader(self) -> None:
"""Write the header elements."""
tAttr = {}
tAttr[_mkTag("style", "name")] = "Standard"
@@ -1048,7 +1048,7 @@ class ODTParagraphStyle:
VALID_CLASS = ["text", "chapter"]
VALID_WEIGHT = ["normal", "inherit", "bold"]
- def __init__(self):
+ def __init__(self) -> None:
# Attributes
self._mAttr = {
@@ -1087,26 +1087,26 @@ class ODTParagraphStyle:
# Attribute Setters
##
- def setDisplayName(self, value: str | None):
+ def setDisplayName(self, value: str | None) -> None:
self._mAttr["display-name"][1] = value
return
- def setParentStyleName(self, value: str | None):
+ def setParentStyleName(self, value: str | None) -> None:
self._mAttr["parent-style-name"][1] = value
return
- def setNextStyleName(self, value: str | None):
+ def setNextStyleName(self, value: str | None) -> None:
self._mAttr["next-style-name"][1] = value
return
- def setOutlineLevel(self, value: str | None):
+ def setOutlineLevel(self, value: str | None) -> None:
if value in self.VALID_LEVEL:
self._mAttr["default-outline-level"][1] = value
else:
self._mAttr["default-outline-level"][1] = None
return
- def setClass(self, value: str | None):
+ def setClass(self, value: str | None) -> None:
if value in self.VALID_CLASS:
self._mAttr["class"][1] = value
else:
@@ -1117,41 +1117,41 @@ class ODTParagraphStyle:
# Paragraph Setters
##
- def setMarginTop(self, value: str | None):
+ def setMarginTop(self, value: str | None) -> None:
self._pAttr["margin-top"][1] = value
return
- def setMarginBottom(self, value: str | None):
+ def setMarginBottom(self, value: str | None) -> None:
self._pAttr["margin-bottom"][1] = value
return
- def setMarginLeft(self, value: str | None):
+ def setMarginLeft(self, value: str | None) -> None:
self._pAttr["margin-left"][1] = value
return
- def setMarginRight(self, value: str | None):
+ def setMarginRight(self, value: str | None) -> None:
self._pAttr["margin-right"][1] = value
return
- def setLineHeight(self, value: str | None):
+ def setLineHeight(self, value: str | None) -> None:
self._pAttr["line-height"][1] = value
return
- def setTextAlign(self, value: str | None):
+ def setTextAlign(self, value: str | None) -> None:
if value in self.VALID_ALIGN:
self._pAttr["text-align"][1] = value
else:
self._pAttr["text-align"][1] = None
return
- def setBreakBefore(self, value: str | None):
+ def setBreakBefore(self, value: str | None) -> None:
if value in self.VALID_BREAK:
self._pAttr["break-before"][1] = value
else:
self._pAttr["break-before"][1] = None
return
- def setBreakAfter(self, value: str | None):
+ def setBreakAfter(self, value: str | None) -> None:
if value in self.VALID_BREAK:
self._pAttr["break-after"][1] = value
else:
@@ -1162,30 +1162,30 @@ class ODTParagraphStyle:
# Text Setters
##
- def setFontName(self, value: str | None):
+ def setFontName(self, value: str | None) -> None:
self._tAttr["font-name"][1] = value
return
- def setFontFamily(self, value: str | None):
+ def setFontFamily(self, value: str | None) -> None:
self._tAttr["font-family"][1] = value
return
- def setFontSize(self, value: str | None):
+ def setFontSize(self, value: str | None) -> None:
self._tAttr["font-size"][1] = value
return
- def setFontWeight(self, value: str | None):
+ def setFontWeight(self, value: str | None) -> None:
if value in self.VALID_WEIGHT:
self._tAttr["font-weight"][1] = value
else:
self._tAttr["font-weight"][1] = None
return
- def setColor(self, value: str | None):
+ def setColor(self, value: str | None) -> None:
self._tAttr["color"][1] = value
return
- def setOpacity(self, value: str | None):
+ def setOpacity(self, value: str | None) -> None:
self._tAttr["opacity"][1] = value
return
@@ -1193,7 +1193,7 @@ class ODTParagraphStyle:
# Methods
##
- def checkNew(self, refStyle: ODTParagraphStyle):
+ def checkNew(self, refStyle: ODTParagraphStyle) -> bool:
"""Check if there are new settings in refStyle that differ from
those in the current object.
"""
@@ -1217,7 +1217,7 @@ class ODTParagraphStyle:
)
return sha256(theString.encode()).hexdigest()
- def packXML(self, xParent: ET.Element, name: str):
+ def packXML(self, xParent: ET.Element, name: str) -> None:
"""Pack the content into an xml element."""
theAttr = {}
theAttr[_mkTag("style", "name")] = name
@@ -1259,8 +1259,7 @@ class ODTTextStyle:
VALID_LSTYLE = ["none", "solid"]
VALID_LTYPE = ["none", "single", "double"]
- def __init__(self):
-
+ def __init__(self) -> None:
# Text Attributes
self._tAttr = {
"font-weight": ["fo", None],
@@ -1268,35 +1267,34 @@ class ODTTextStyle:
"text-line-through-style": ["style", None],
"text-line-through-type": ["style", None],
}
-
return
##
# Setters
##
- def setFontWeight(self, value: str | None):
+ def setFontWeight(self, value: str | None) -> None:
if value in self.VALID_WEIGHT:
self._tAttr["font-weight"][1] = value
else:
self._tAttr["font-weight"][1] = None
return
- def setFontStyle(self, value: str | None):
+ def setFontStyle(self, value: str | None) -> None:
if value in self.VALID_STYLE:
self._tAttr["font-style"][1] = value
else:
self._tAttr["font-style"][1] = None
return
- def setStrikeStyle(self, value: str | None):
+ def setStrikeStyle(self, value: str | None) -> None:
if value in self.VALID_LSTYLE:
self._tAttr["text-line-through-style"][1] = value
else:
self._tAttr["text-line-through-style"][1] = None
return
- def setStrikeType(self, value: str | None):
+ def setStrikeType(self, value: str | None) -> None:
if value in self.VALID_LTYPE:
self._tAttr["text-line-through-type"][1] = value
else:
@@ -1307,7 +1305,7 @@ class ODTTextStyle:
# Methods
##
- def packXML(self, xParent: ET.Element, name: str):
+ def packXML(self, xParent: ET.Element, name: str) -> None:
"""Pack the content into an xml element."""
theAttr = {}
theAttr[_mkTag("style", "name")] = name
@@ -1357,7 +1355,7 @@ class XMLParagraph:
object and attribute is written to,
"""
- def __init__(self, xRoot: ET.Element):
+ def __init__(self, xRoot: ET.Element) -> None:
self._xRoot = xRoot
self._xTail = ET.Element("")
@@ -1370,7 +1368,7 @@ class XMLParagraph:
return
- def appendText(self, tText: str):
+ def appendText(self, tText: str) -> None:
"""Append text to the XML element. We do this one character at
the time in order to be able to process line breaks, tabs and
spaces separately. Multiple spaces are concatenated into a
@@ -1435,7 +1433,7 @@ class XMLParagraph:
return
- def appendSpan(self, tText: str, tFmt: str):
+ def appendSpan(self, tText: str, tFmt: str) -> None:
"""Append a text span to the XML element. The span is always
closed since we do not allow nested spans (like Libre Office).
Therefore we return to the root element level when we're done
@@ -1449,7 +1447,7 @@ class XMLParagraph:
self._nState = X_ROOT_TAIL
return
- def checkError(self):
+ def checkError(self) -> tuple[int, str]:
"""Check that the number of characters written matches the
number of characters received.
"""
@@ -1463,7 +1461,7 @@ class XMLParagraph:
# Internal Functions
##
- def _processSpaces(self, nSpaces: int):
+ def _processSpaces(self, nSpaces: int) -> None:
"""Add spaces to paragraph. The first space is always written
as-is (unless it's the first character of the paragraph). The
second space uses the dedicated tag for spaces, and from the
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index 41d8853b..cb3d212e 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,6 +1,6 @@
-
-
+
+
Sample Project
Sample Project
Jane Smith
diff --git a/tests/test_core/test_core_status.py b/tests/test_core/test_core_status.py
index fdfa1588..a42701b9 100644
--- a/tests/test_core/test_core_status.py
+++ b/tests/test_core/test_core_status.py
@@ -344,7 +344,7 @@ def testCoreStatus_PackUnpack(mockRnd):
# Unpack
theStatus = NWStatus(NWStatus.STATUS)
- assert theStatus.unpack({
+ theStatus.unpack({
statusKeys[0]: {"label": "New0", "colour": (100, 100, 100), "count": countTo[0]},
statusKeys[1]: {"label": "New1", "colour": (150, 150, 150), "count": countTo[1]},
statusKeys[2]: {"label": "New2", "colour": (200, 200, 200), "count": countTo[2]},
From 5d817ae51f62e628bae66eb5bb778baa81783747 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 8 Aug 2023 22:47:24 +0200
Subject: [PATCH 07/10] Move GUI components module to extensions subpackage
---
novelwriter/dialogs/projdetails.py | 2 +-
.../novelselector.py} | 95 ++++---------------
novelwriter/extensions/statusled.py | 77 +++++++++++++++
novelwriter/gui/noveltree.py | 2 +-
novelwriter/gui/outline.py | 2 +-
novelwriter/gui/statusbar.py | 2 +-
tests/test_gui/test_gui_statusbar.py | 2 +-
7 files changed, 100 insertions(+), 82 deletions(-)
rename novelwriter/{gui/components.py => extensions/novelselector.py} (59%)
create mode 100644 novelwriter/extensions/statusled.py
diff --git a/novelwriter/dialogs/projdetails.py b/novelwriter/dialogs/projdetails.py
index b3d942ca..5544ec7d 100644
--- a/novelwriter/dialogs/projdetails.py
+++ b/novelwriter/dialogs/projdetails.py
@@ -36,9 +36,9 @@ from PyQt5.QtWidgets import (
from novelwriter import CONFIG
from novelwriter.common import formatTime, numberToRoman
from novelwriter.constants import nwUnicode
-from novelwriter.gui.components import NovelSelector
from novelwriter.extensions.switch import NSwitch
from novelwriter.extensions.pageddialog import NPagedDialog
+from novelwriter.extensions.novelselector import NovelSelector
logger = logging.getLogger(__name__)
diff --git a/novelwriter/gui/components.py b/novelwriter/extensions/novelselector.py
similarity index 59%
rename from novelwriter/gui/components.py
rename to novelwriter/extensions/novelselector.py
index 762f0b0c..8bb2c4c2 100644
--- a/novelwriter/gui/components.py
+++ b/novelwriter/extensions/novelselector.py
@@ -1,10 +1,9 @@
"""
-novelWriter – GUI Components Module
-===================================
+novelWriter – Custom Widget: Novel Selector
+===========================================
File History:
-Created: 2020-05-17 [0.5.1] StatusLED
-Created: 2022-11-17 [2.0] NovelSelector
+Created: 2022-11-17 [2.0]
This file is a part of novelWriter
Copyright 2018–2023, Veronica Berglyd Olsen
@@ -26,14 +25,18 @@ from __future__ import annotations
import logging
-from PyQt5.QtGui import QPainter
+from typing import TYPE_CHECKING
+
from PyQt5.QtCore import pyqtSignal, pyqtSlot
-from PyQt5.QtWidgets import QAbstractButton, QComboBox
+from PyQt5.QtWidgets import QComboBox, QWidget
from novelwriter import CONFIG
from novelwriter.enum import nwItemClass
from novelwriter.constants import nwLabels
+if TYPE_CHECKING: # pragma: no cover
+ from novelwriter.guimain import GuiMain
+
logger = logging.getLogger(__name__)
@@ -41,15 +44,12 @@ class NovelSelector(QComboBox):
novelSelectionChanged = pyqtSignal(str)
- def __init__(self, parent, mainGui):
+ def __init__(self, parent: QWidget, mainGui: GuiMain) -> None:
super().__init__(parent=parent)
-
self._mainGui = mainGui
self._blockSignal = False
self._firstHandle = None
-
self.currentIndexChanged.connect(self._indexChanged)
-
return
##
@@ -57,20 +57,19 @@ class NovelSelector(QComboBox):
##
@property
- def handle(self):
+ def handle(self) -> str:
return self.currentData()
@property
- def firstHandle(self):
+ def firstHandle(self) -> str | None:
return self._firstHandle
##
# Methods
##
- def setHandle(self, tHandle, blockSignal=True):
- """Set the currently selected handle.
- """
+ def setHandle(self, tHandle: str, blockSignal: bool = True) -> None:
+ """Set the currently selected handle."""
self._blockSignal = blockSignal
if tHandle is None:
index = self.count() - 1
@@ -81,9 +80,8 @@ class NovelSelector(QComboBox):
self._blockSignal = False
return
- def updateList(self, includeAll=False, prefix=None):
- """Rebuild the list of novel items.
- """
+ def updateList(self, includeAll: bool = False, prefix: str | None = None) -> None:
+ """Rebuild the list of novel items."""
self._blockSignal = True
self._firstHandle = None
self.clear()
@@ -115,67 +113,10 @@ class NovelSelector(QComboBox):
##
@pyqtSlot(int)
- def _indexChanged(self, index):
- """Re-emit the change of selected novel signal, unless blocked.
- """
+ def _indexChanged(self, index: int) -> None:
+ """Re-emit the change of selection signal, unless blocked."""
if not self._blockSignal:
self.novelSelectionChanged.emit(self.currentData())
return
# END Class NovelSelector
-
-
-class StatusLED(QAbstractButton):
-
- S_NONE = 0
- S_BAD = 1
- S_GOOD = 2
-
- def __init__(self, colNone, colGood, colBad, sW, sH, parent=None):
- super().__init__(parent=parent)
-
- self._colNone = colNone
- self._colGood = colGood
- self._colBad = colBad
- self._theCol = colNone
-
- self.setFixedWidth(sW)
- self.setFixedHeight(sH)
-
- return
-
- ##
- # Setters
- ##
-
- def setState(self, theState):
- """Set the colour state.
- """
- if theState == self.S_GOOD:
- self._theCol = self._colGood
- elif theState == self.S_BAD:
- self._theCol = self._colBad
- else:
- self._theCol = self._colNone
-
- self.update()
-
- return
-
- ##
- # Events
- ##
-
- def paintEvent(self, _):
- """Drawing the LED.
- """
- qPalette = self.palette()
- qPaint = QPainter(self)
- qPaint.setRenderHint(QPainter.Antialiasing, True)
- qPaint.setPen(qPalette.dark().color())
- qPaint.setBrush(self._theCol)
- qPaint.setOpacity(1.0)
- qPaint.drawEllipse(1, 1, self.width() - 2, self.height() - 2)
- return
-
-# END Class StatusLED
diff --git a/novelwriter/extensions/statusled.py b/novelwriter/extensions/statusled.py
new file mode 100644
index 00000000..8a5ba4e6
--- /dev/null
+++ b/novelwriter/extensions/statusled.py
@@ -0,0 +1,77 @@
+"""
+novelWriter – Custom Widget: Status LED
+=======================================
+
+File History:
+Created: 2020-05-17 [0.5.1]
+
+This file is a part of novelWriter
+Copyright 2018–2023, Veronica Berglyd Olsen
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+"""
+from __future__ import annotations
+
+import logging
+from typing import Literal
+
+from PyQt5.QtGui import QColor, QPaintEvent, QPainter
+from PyQt5.QtWidgets import QAbstractButton, QWidget
+
+logger = logging.getLogger(__name__)
+
+
+class StatusLED(QAbstractButton):
+
+ S_NONE = 0
+ S_BAD = 1
+ S_GOOD = 2
+
+ def __init__(self, colNone: QColor, colGood: QColor, colBad: QColor,
+ sW: int, sH: int, parent: QWidget | None = None) -> None:
+ super().__init__(parent=parent)
+
+ self._colNone = colNone
+ self._colGood = colGood
+ self._colBad = colBad
+ self._theCol = colNone
+
+ self.setFixedWidth(sW)
+ self.setFixedHeight(sH)
+
+ return
+
+ def setState(self, state: Literal[0, 1, 2]) -> None:
+ """Set the colour state."""
+ if state == self.S_GOOD:
+ self._theCol = self._colGood
+ elif state == self.S_BAD:
+ self._theCol = self._colBad
+ else:
+ self._theCol = self._colNone
+ self.update()
+ return
+
+ def paintEvent(self, event: QPaintEvent) -> None:
+ """Drawing the LED."""
+ qPalette = self.palette()
+ qPaint = QPainter(self)
+ qPaint.setRenderHint(QPainter.Antialiasing, True)
+ qPaint.setPen(qPalette.dark().color())
+ qPaint.setBrush(self._theCol)
+ qPaint.setOpacity(1.0)
+ qPaint.drawEllipse(1, 1, self.width() - 2, self.height() - 2)
+ return
+
+# END Class StatusLED
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index 877dc1bd..98d36fe9 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -42,7 +42,7 @@ from novelwriter import CONFIG
from novelwriter.enum import nwDocMode, nwItemClass, nwOutline
from novelwriter.common import minmax
from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst
-from novelwriter.gui.components import NovelSelector
+from novelwriter.extensions.novelselector import NovelSelector
logger = logging.getLogger(__name__)
diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py
index 0c75a6b1..73440f1f 100644
--- a/novelwriter/gui/outline.py
+++ b/novelwriter/gui/outline.py
@@ -48,7 +48,7 @@ from novelwriter.enum import (
from novelwriter.error import logException
from novelwriter.common import checkInt
from novelwriter.constants import nwHeaders, trConst, nwKeyWords, nwLabels
-from novelwriter.gui.components import NovelSelector
+from novelwriter.extensions.novelselector import NovelSelector
logger = logging.getLogger(__name__)
diff --git a/novelwriter/gui/statusbar.py b/novelwriter/gui/statusbar.py
index e3512270..138d1cd3 100644
--- a/novelwriter/gui/statusbar.py
+++ b/novelwriter/gui/statusbar.py
@@ -34,7 +34,7 @@ from PyQt5.QtWidgets import qApp, QStatusBar, QLabel
from novelwriter import CONFIG
from novelwriter.common import formatTime
-from novelwriter.gui.components import StatusLED
+from novelwriter.extensions.statusled import StatusLED
logger = logging.getLogger(__name__)
diff --git a/tests/test_gui/test_gui_statusbar.py b/tests/test_gui/test_gui_statusbar.py
index 73572160..b227fb61 100644
--- a/tests/test_gui/test_gui_statusbar.py
+++ b/tests/test_gui/test_gui_statusbar.py
@@ -25,7 +25,7 @@ import pytest
from tools import C, buildTestProject
from novelwriter import CONFIG
-from novelwriter.gui.statusbar import StatusLED
+from novelwriter.extensions.statusled import StatusLED
@pytest.mark.gui
From 6e5d991cfe925275ff67bc56d8c7116186cfd097 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 8 Aug 2023 23:14:35 +0200
Subject: [PATCH 08/10] Move TypeGuard to TYPE_CHECKING condition
---
novelwriter/common.py | 6 +++---
novelwriter/core/status.py | 5 ++++-
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/novelwriter/common.py b/novelwriter/common.py
index 17fb6403..8ccf0bf0 100644
--- a/novelwriter/common.py
+++ b/novelwriter/common.py
@@ -30,7 +30,7 @@ import logging
import unicodedata
import xml.etree.ElementTree as ET
-from typing import Any, Literal, TypeGuard
+from typing import Any, Literal
from pathlib import Path
from datetime import datetime
from configparser import ConfigParser
@@ -134,7 +134,7 @@ def checkPath(value: Any, default: Path) -> Path:
# Validator Functions
# =============================================================================================== #
-def isHandle(value: Any) -> TypeGuard[str]:
+def isHandle(value: Any) -> bool:
"""Check if a string is a valid novelWriter handle.
Note: This is case sensitive. Must be lower case!
"""
@@ -148,7 +148,7 @@ def isHandle(value: Any) -> TypeGuard[str]:
return True
-def isTitleTag(value: Any) -> TypeGuard[str]:
+def isTitleTag(value: Any) -> bool:
"""Check if a string is a valid title tag string."""
if not isinstance(value, str):
return False
diff --git a/novelwriter/core/status.py b/novelwriter/core/status.py
index ac26641f..203ad6bf 100644
--- a/novelwriter/core/status.py
+++ b/novelwriter/core/status.py
@@ -27,7 +27,7 @@ from __future__ import annotations
import random
import logging
-from typing import ItemsView, Iterator, KeysView, Literal, TypeGuard, ValuesView
+from typing import TYPE_CHECKING, ItemsView, Iterator, KeysView, Literal, ValuesView
from PyQt5.QtGui import QIcon, QPainter, QPainterPath, QPixmap, QColor
from PyQt5.QtCore import QRectF, Qt
@@ -35,6 +35,9 @@ from PyQt5.QtCore import QRectF, Qt
from novelwriter import CONFIG
from novelwriter.common import minmax, simplified
+if TYPE_CHECKING: # pragma: no cover
+ from typing import TypeGuard # Requires Python 3.10
+
logger = logging.getLogger(__name__)
From 71e961ba38b3982254b0ad53b244670e657ba9e8 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 8 Aug 2023 23:32:30 +0200
Subject: [PATCH 09/10] Fix annotations in NWStatus class
---
novelwriter/core/status.py | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/novelwriter/core/status.py b/novelwriter/core/status.py
index 203ad6bf..fad14027 100644
--- a/novelwriter/core/status.py
+++ b/novelwriter/core/status.py
@@ -127,7 +127,7 @@ class NWStatus:
return self._default
return ""
- def name(self, key: str) -> str:
+ def name(self, key: str | None) -> str:
"""Return the name associated with a given key."""
if key in self._store:
return self._store[key]["name"]
@@ -135,16 +135,15 @@ class NWStatus:
return self._store[self._default]["name"]
return ""
- def cols(self, key: str) -> tuple[int, int, int]:
- """Return the colours associated with a given key.
- """
+ def cols(self, key: str | None) -> tuple[int, int, int]:
+ """Return the colours associated with a given key."""
if key in self._store:
return self._store[key]["cols"]
elif self._default is not None:
return self._store[self._default]["cols"]
return 100, 100, 100
- def count(self, key: str) -> int:
+ def count(self, key: str | None) -> int:
"""Return the count associated with a given key."""
if key in self._store:
return self._store[key]["count"]
@@ -152,7 +151,7 @@ class NWStatus:
return self._store[self._default]["count"]
return 0
- def icon(self, key: str) -> QIcon:
+ def icon(self, key: str | None) -> QIcon:
"""Return the icon associated with a given key."""
if key in self._store:
return self._store[key]["icon"]
From ddacfc743ef37e2d94c80f70b1abd2cd9d6a0690 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Thu, 10 Aug 2023 00:49:33 +0200
Subject: [PATCH 10/10] Annotate config class and extensions
---
novelwriter/config.py | 361 ++++++++++-----------
novelwriter/dialogs/projload.py | 8 +-
novelwriter/extensions/circularprogress.py | 12 +-
novelwriter/extensions/configlayout.py | 26 +-
novelwriter/extensions/pageddialog.py | 31 +-
novelwriter/extensions/simpleprogress.py | 4 +-
novelwriter/extensions/switch.py | 56 ++--
novelwriter/extensions/switchbox.py | 18 +-
tests/test_base/test_base_config.py | 8 -
9 files changed, 244 insertions(+), 280 deletions(-)
diff --git a/novelwriter/config.py b/novelwriter/config.py
index c60efee1..cafa3e36 100644
--- a/novelwriter/config.py
+++ b/novelwriter/config.py
@@ -33,12 +33,13 @@ from pathlib import Path
from PyQt5.QtGui import QFontDatabase
from PyQt5.QtCore import (
- QT_VERSION, QT_VERSION_STR, PYQT_VERSION, PYQT_VERSION_STR, QStandardPaths,
- QSysInfo, QLocale, QLibraryInfo, QTranslator
+ PYQT_VERSION, PYQT_VERSION_STR, QT_VERSION, QT_VERSION_STR, QLibraryInfo,
+ QLocale, QStandardPaths, QSysInfo, QTranslator
)
+from PyQt5.QtWidgets import QApplication
-from novelwriter.error import logException, formatException
-from novelwriter.common import checkPath, formatTimeStamp, NWConfigParser
+from novelwriter.error import formatException, logException
+from novelwriter.common import NWConfigParser, checkInt, checkPath, formatTimeStamp
from novelwriter.constants import nwFiles, nwUnicode
if TYPE_CHECKING: # pragma: no cover
@@ -52,7 +53,7 @@ class Config:
LANG_NW = 1
LANG_PROJ = 2
- def __init__(self):
+ def __init__(self) -> None:
# Initialisation
# ==============
@@ -236,11 +237,11 @@ class Config:
##
@property
- def hasError(self):
+ def hasError(self) -> bool:
return self._hasError
@property
- def recentProjects(self):
+ def recentProjects(self) -> RecentProjects:
return self._recentObj
@property
@@ -250,45 +251,45 @@ class Config:
return self._themeObj
@property
- def mainWinSize(self):
+ def mainWinSize(self) -> list[int]:
return [int(x*self.guiScale) for x in self._mainWinSize]
@property
- def preferencesWinSize(self):
+ def preferencesWinSize(self) -> list[int]:
return [int(x*self.guiScale) for x in self._prefsWinSize]
@property
- def projLoadColWidths(self):
+ def projLoadColWidths(self) -> list[int]:
return [int(x*self.guiScale) for x in self._projLoadCols]
@property
- def mainPanePos(self):
+ def mainPanePos(self) -> list[int]:
return [int(x*self.guiScale) for x in self._mainPanePos]
@property
- def viewPanePos(self):
+ def viewPanePos(self) -> list[int]:
return [int(x*self.guiScale) for x in self._viewPanePos]
@property
- def outlinePanePos(self):
+ def outlinePanePos(self) -> list[int]:
return [int(x*self.guiScale) for x in self._outlnPanePos]
##
# Getters
##
- def getTextWidth(self, focusMode=False):
+ def getTextWidth(self, focusMode: bool = False) -> int:
"""Get the text with for the correct editor mode."""
if focusMode:
return self.pxInt(max(self.focusWidth, 200))
else:
return self.pxInt(max(self.textWidth, 200))
- def getTextMargin(self):
+ def getTextMargin(self) -> int:
"""Get the scaled text margin."""
return self.pxInt(max(self.textMargin, 0))
- def getTabWidth(self):
+ def getTabWidth(self) -> int:
"""Get the scaled tab width."""
return self.pxInt(max(self.tabWidth, 0))
@@ -301,65 +302,65 @@ class Config:
self._themeObj = theme
return
- def setMainWinSize(self, newWidth, newHeight):
+ def setMainWinSize(self, width: int, height: int) -> None:
"""Set the size of the main window, but only if the change is
larger than 5 pixels. The OS window manager will sometimes
adjust it a bit, and we don't want the main window to shrink or
grow each time the app is opened.
"""
- newWidth = int(newWidth/self.guiScale)
- newHeight = int(newHeight/self.guiScale)
- if abs(self._mainWinSize[0] - newWidth) > 5:
- self._mainWinSize[0] = newWidth
- if abs(self._mainWinSize[1] - newHeight) > 5:
- self._mainWinSize[1] = newHeight
+ width = int(width/self.guiScale)
+ height = int(height/self.guiScale)
+ if abs(self._mainWinSize[0] - width) > 5:
+ self._mainWinSize[0] = width
+ if abs(self._mainWinSize[1] - height) > 5:
+ self._mainWinSize[1] = height
return
- def setPreferencesWinSize(self, newWidth, newHeight):
+ def setPreferencesWinSize(self, width: int, height: int) -> None:
"""Set the size of the Preferences dialog window."""
- self._prefsWinSize[0] = int(newWidth/self.guiScale)
- self._prefsWinSize[1] = int(newHeight/self.guiScale)
+ self._prefsWinSize[0] = int(width/self.guiScale)
+ self._prefsWinSize[1] = int(height/self.guiScale)
return
- def setProjLoadColWidths(self, colWidths):
+ def setProjLoadColWidths(self, widths: list[int]) -> None:
"""Set the column widths of the Load Project dialog."""
- self._projLoadCols = [int(x/self.guiScale) for x in colWidths]
+ self._projLoadCols = [int(x/self.guiScale) for x in widths]
return
- def setMainPanePos(self, panePos):
+ def setMainPanePos(self, pos: list[int]) -> None:
"""Set the position of the main GUI splitter."""
- self._mainPanePos = [int(x/self.guiScale) for x in panePos]
+ self._mainPanePos = [int(x/self.guiScale) for x in pos]
return
- def setViewPanePos(self, panePos):
+ def setViewPanePos(self, pos: list[int]) -> None:
"""Set the position of the viewer meta data splitter."""
- self._viewPanePos = [int(x/self.guiScale) for x in panePos]
+ self._viewPanePos = [int(x/self.guiScale) for x in pos]
return
- def setOutlinePanePos(self, panePos):
+ def setOutlinePanePos(self, pos: list[int]) -> None:
"""Set the position of the outline details splitter."""
- self._outlnPanePos = [int(x/self.guiScale) for x in panePos]
+ self._outlnPanePos = [int(x/self.guiScale) for x in pos]
return
- def setLastPath(self, lastPath):
+ def setLastPath(self, path: str | Path) -> None:
"""Set the last used path. Only the folder is saved, so if the
path is not a folder, the parent of the path is used instead.
"""
- if isinstance(lastPath, (str, Path)):
- lastPath = checkPath(lastPath, self._homePath)
- if not lastPath.is_dir():
- lastPath = lastPath.parent
- if lastPath.is_dir():
- self._lastPath = lastPath
+ if isinstance(path, (str, Path)):
+ path = checkPath(path, self._homePath)
+ if not path.is_dir():
+ path = path.parent
+ if path.is_dir():
+ self._lastPath = path
logger.debug("Last path updated: %s" % self._lastPath)
return
- def setBackupPath(self, backupPath: Path | str):
+ def setBackupPath(self, path: Path | str) -> None:
"""Set the current backup path."""
- self._backupPath = checkPath(backupPath, self._backPath)
+ self._backupPath = checkPath(path, self._backPath)
return
- def setTextFont(self, family: str | None, pointSize: int = 12):
+ def setTextFont(self, family: str | None, pointSize: int = 12) -> None:
"""Set the text font if it exists. If it doesn't, or is None,
set to default font.
"""
@@ -383,15 +384,11 @@ class Config:
##
def pxInt(self, value: int) -> int:
- """Used to scale fixed gui sizes by the screen scale factor.
- This function returns an int, which is always rounded down.
- """
+ """Scale fixed gui sizes by the screen scale factor."""
return int(value*self.guiScale)
def rpxInt(self, value: int) -> int:
- """Used to un-scale fixed gui sizes by the screen scale factor.
- This function returns an int, which is always rounded down.
- """
+ """Un-scale fixed gui sizes by the screen scale factor."""
return int(value/self.guiScale)
def dataPath(self, target: str | None = None) -> Path:
@@ -461,7 +458,8 @@ class Config:
# Config Actions
##
- def initConfig(self, confPath: str | Path | None = None, dataPath: str | Path | None = None):
+ def initConfig(self, confPath: str | Path | None = None,
+ dataPath: str | Path | None = None) -> None:
"""Initialise the config class. The manual setting of confPath
and dataPath is mainly intended for the test suite.
"""
@@ -505,9 +503,8 @@ class Config:
return
- def initLocalisation(self, nwApp):
- """Initialise the localisation of the GUI.
- """
+ def initLocalisation(self, nwApp: QApplication) -> None:
+ """Initialise the localisation of the GUI."""
self._qLocale = QLocale(self.guiLocale)
QLocale.setDefault(self._qLocale)
self._qtTrans = {}
@@ -528,16 +525,15 @@ class Config:
return
- def loadConfig(self):
- """Load preferences from file and replace default settings.
- """
+ def loadConfig(self) -> bool:
+ """Load preferences from file and replace default settings."""
logger.debug("Loading config file")
- theConf = NWConfigParser()
+ conf = NWConfigParser()
cnfPath = self._confPath / nwFiles.CONF_FILE
try:
with open(cnfPath, mode="r", encoding="utf-8") as inFile:
- theConf.read_file(inFile)
+ conf.read_file(inFile)
except Exception as exc:
logger.error("Could not load config file")
logException()
@@ -547,98 +543,98 @@ class Config:
return False
# Main
- cnfSec = "Main"
- self.guiTheme = theConf.rdStr(cnfSec, "theme", self.guiTheme)
- self.guiSyntax = theConf.rdStr(cnfSec, "syntax", self.guiSyntax)
- self.guiFont = theConf.rdStr(cnfSec, "font", self.guiFont)
- self.guiFontSize = theConf.rdInt(cnfSec, "fontsize", self.guiFontSize)
- self.guiLocale = theConf.rdStr(cnfSec, "localisation", self.guiLocale)
- self.hideVScroll = theConf.rdBool(cnfSec, "hidevscroll", self.hideVScroll)
- self.hideHScroll = theConf.rdBool(cnfSec, "hidehscroll", self.hideHScroll)
- self.lastNotes = theConf.rdStr(cnfSec, "lastnotes", self.lastNotes)
- self._lastPath = theConf.rdPath(cnfSec, "lastpath", self._lastPath)
+ sec = "Main"
+ self.guiTheme = conf.rdStr(sec, "theme", self.guiTheme)
+ self.guiSyntax = conf.rdStr(sec, "syntax", self.guiSyntax)
+ self.guiFont = conf.rdStr(sec, "font", self.guiFont)
+ self.guiFontSize = conf.rdInt(sec, "fontsize", self.guiFontSize)
+ self.guiLocale = conf.rdStr(sec, "localisation", self.guiLocale)
+ self.hideVScroll = conf.rdBool(sec, "hidevscroll", self.hideVScroll)
+ self.hideHScroll = conf.rdBool(sec, "hidehscroll", self.hideHScroll)
+ self.lastNotes = conf.rdStr(sec, "lastnotes", self.lastNotes)
+ self._lastPath = conf.rdPath(sec, "lastpath", self._lastPath)
# Sizes
- cnfSec = "Sizes"
- self._mainWinSize = theConf.rdIntList(cnfSec, "mainwindow", self._mainWinSize)
- self._prefsWinSize = theConf.rdIntList(cnfSec, "preferences", self._prefsWinSize)
- self._projLoadCols = theConf.rdIntList(cnfSec, "projloadcols", self._projLoadCols)
- self._mainPanePos = theConf.rdIntList(cnfSec, "mainpane", self._mainPanePos)
- self._viewPanePos = theConf.rdIntList(cnfSec, "viewpane", self._viewPanePos)
- self._outlnPanePos = theConf.rdIntList(cnfSec, "outlinepane", self._outlnPanePos)
+ sec = "Sizes"
+ self._mainWinSize = conf.rdIntList(sec, "mainwindow", self._mainWinSize)
+ self._prefsWinSize = conf.rdIntList(sec, "preferences", self._prefsWinSize)
+ self._projLoadCols = conf.rdIntList(sec, "projloadcols", self._projLoadCols)
+ self._mainPanePos = conf.rdIntList(sec, "mainpane", self._mainPanePos)
+ self._viewPanePos = conf.rdIntList(sec, "viewpane", self._viewPanePos)
+ self._outlnPanePos = conf.rdIntList(sec, "outlinepane", self._outlnPanePos)
# Project
- cnfSec = "Project"
- self.autoSaveProj = theConf.rdInt(cnfSec, "autosaveproject", self.autoSaveProj)
- self.autoSaveDoc = theConf.rdInt(cnfSec, "autosavedoc", self.autoSaveDoc)
- self.emphLabels = theConf.rdBool(cnfSec, "emphlabels", self.emphLabels)
- self._backupPath = theConf.rdPath(cnfSec, "backuppath", self._backupPath)
- self.backupOnClose = theConf.rdBool(cnfSec, "backuponclose", self.backupOnClose)
- self.askBeforeBackup = theConf.rdBool(cnfSec, "askbeforebackup", self.askBeforeBackup)
+ sec = "Project"
+ self.autoSaveProj = conf.rdInt(sec, "autosaveproject", self.autoSaveProj)
+ self.autoSaveDoc = conf.rdInt(sec, "autosavedoc", self.autoSaveDoc)
+ self.emphLabels = conf.rdBool(sec, "emphlabels", self.emphLabels)
+ self._backupPath = conf.rdPath(sec, "backuppath", self._backupPath)
+ self.backupOnClose = conf.rdBool(sec, "backuponclose", self.backupOnClose)
+ self.askBeforeBackup = conf.rdBool(sec, "askbeforebackup", self.askBeforeBackup)
# Editor
- cnfSec = "Editor"
- self.textFont = theConf.rdStr(cnfSec, "textfont", self.textFont)
- self.textSize = theConf.rdInt(cnfSec, "textsize", self.textSize)
- self.textWidth = theConf.rdInt(cnfSec, "width", self.textWidth)
- self.textMargin = theConf.rdInt(cnfSec, "margin", self.textMargin)
- self.tabWidth = theConf.rdInt(cnfSec, "tabwidth", self.tabWidth)
- self.focusWidth = theConf.rdInt(cnfSec, "focuswidth", self.focusWidth)
- self.hideFocusFooter = theConf.rdBool(cnfSec, "hidefocusfooter", self.hideFocusFooter)
- self.doJustify = theConf.rdBool(cnfSec, "justify", self.doJustify)
- self.autoSelect = theConf.rdBool(cnfSec, "autoselect", self.autoSelect)
- self.doReplace = theConf.rdBool(cnfSec, "autoreplace", self.doReplace)
- self.doReplaceSQuote = theConf.rdBool(cnfSec, "repsquotes", self.doReplaceSQuote)
- self.doReplaceDQuote = theConf.rdBool(cnfSec, "repdquotes", self.doReplaceDQuote)
- self.doReplaceDash = theConf.rdBool(cnfSec, "repdash", self.doReplaceDash)
- self.doReplaceDots = theConf.rdBool(cnfSec, "repdots", self.doReplaceDots)
- self.scrollPastEnd = theConf.rdInt(cnfSec, "scrollpastend", self.scrollPastEnd)
- self.autoScroll = theConf.rdBool(cnfSec, "autoscroll", self.autoScroll)
- self.autoScrollPos = theConf.rdInt(cnfSec, "autoscrollpos", self.autoScrollPos)
- self.fmtSQuoteOpen = theConf.rdStr(cnfSec, "fmtsquoteopen", self.fmtSQuoteOpen)
- self.fmtSQuoteClose = theConf.rdStr(cnfSec, "fmtsquoteclose", self.fmtSQuoteClose)
- self.fmtDQuoteOpen = theConf.rdStr(cnfSec, "fmtdquoteopen", self.fmtDQuoteOpen)
- self.fmtDQuoteClose = theConf.rdStr(cnfSec, "fmtdquoteclose", self.fmtDQuoteClose)
- self.fmtPadBefore = theConf.rdStr(cnfSec, "fmtpadbefore", self.fmtPadBefore)
- self.fmtPadAfter = theConf.rdStr(cnfSec, "fmtpadafter", self.fmtPadAfter)
- self.fmtPadThin = theConf.rdBool(cnfSec, "fmtpadthin", self.fmtPadThin)
- self.spellLanguage = theConf.rdStr(cnfSec, "spellcheck", self.spellLanguage)
- self.showTabsNSpaces = theConf.rdBool(cnfSec, "showtabsnspaces", self.showTabsNSpaces)
- self.showLineEndings = theConf.rdBool(cnfSec, "showlineendings", self.showLineEndings)
- self.showMultiSpaces = theConf.rdBool(cnfSec, "showmultispaces", self.showMultiSpaces)
- self.wordCountTimer = theConf.rdFlt(cnfSec, "wordcounttimer", self.wordCountTimer)
- self.bigDocLimit = theConf.rdInt(cnfSec, "bigdoclimit", self.bigDocLimit)
- self.incNotesWCount = theConf.rdBool(cnfSec, "incnoteswcount", self.incNotesWCount)
- self.showFullPath = theConf.rdBool(cnfSec, "showfullpath", self.showFullPath)
- self.highlightQuotes = theConf.rdBool(cnfSec, "highlightquotes", self.highlightQuotes)
- self.allowOpenSQuote = theConf.rdBool(cnfSec, "allowopensquote", self.allowOpenSQuote)
- self.allowOpenDQuote = theConf.rdBool(cnfSec, "allowopendquote", self.allowOpenDQuote)
- self.highlightEmph = theConf.rdBool(cnfSec, "highlightemph", self.highlightEmph)
- self.stopWhenIdle = theConf.rdBool(cnfSec, "stopwhenidle", self.stopWhenIdle)
- self.userIdleTime = theConf.rdInt(cnfSec, "useridletime", self.userIdleTime)
+ sec = "Editor"
+ self.textFont = conf.rdStr(sec, "textfont", self.textFont)
+ self.textSize = conf.rdInt(sec, "textsize", self.textSize)
+ self.textWidth = conf.rdInt(sec, "width", self.textWidth)
+ self.textMargin = conf.rdInt(sec, "margin", self.textMargin)
+ self.tabWidth = conf.rdInt(sec, "tabwidth", self.tabWidth)
+ self.focusWidth = conf.rdInt(sec, "focuswidth", self.focusWidth)
+ self.hideFocusFooter = conf.rdBool(sec, "hidefocusfooter", self.hideFocusFooter)
+ self.doJustify = conf.rdBool(sec, "justify", self.doJustify)
+ self.autoSelect = conf.rdBool(sec, "autoselect", self.autoSelect)
+ self.doReplace = conf.rdBool(sec, "autoreplace", self.doReplace)
+ self.doReplaceSQuote = conf.rdBool(sec, "repsquotes", self.doReplaceSQuote)
+ self.doReplaceDQuote = conf.rdBool(sec, "repdquotes", self.doReplaceDQuote)
+ self.doReplaceDash = conf.rdBool(sec, "repdash", self.doReplaceDash)
+ self.doReplaceDots = conf.rdBool(sec, "repdots", self.doReplaceDots)
+ self.scrollPastEnd = conf.rdInt(sec, "scrollpastend", self.scrollPastEnd)
+ self.autoScroll = conf.rdBool(sec, "autoscroll", self.autoScroll)
+ self.autoScrollPos = conf.rdInt(sec, "autoscrollpos", self.autoScrollPos)
+ self.fmtSQuoteOpen = conf.rdStr(sec, "fmtsquoteopen", self.fmtSQuoteOpen)
+ self.fmtSQuoteClose = conf.rdStr(sec, "fmtsquoteclose", self.fmtSQuoteClose)
+ self.fmtDQuoteOpen = conf.rdStr(sec, "fmtdquoteopen", self.fmtDQuoteOpen)
+ self.fmtDQuoteClose = conf.rdStr(sec, "fmtdquoteclose", self.fmtDQuoteClose)
+ self.fmtPadBefore = conf.rdStr(sec, "fmtpadbefore", self.fmtPadBefore)
+ self.fmtPadAfter = conf.rdStr(sec, "fmtpadafter", self.fmtPadAfter)
+ self.fmtPadThin = conf.rdBool(sec, "fmtpadthin", self.fmtPadThin)
+ self.spellLanguage = conf.rdStr(sec, "spellcheck", self.spellLanguage)
+ self.showTabsNSpaces = conf.rdBool(sec, "showtabsnspaces", self.showTabsNSpaces)
+ self.showLineEndings = conf.rdBool(sec, "showlineendings", self.showLineEndings)
+ self.showMultiSpaces = conf.rdBool(sec, "showmultispaces", self.showMultiSpaces)
+ self.wordCountTimer = conf.rdFlt(sec, "wordcounttimer", self.wordCountTimer)
+ self.bigDocLimit = conf.rdInt(sec, "bigdoclimit", self.bigDocLimit)
+ self.incNotesWCount = conf.rdBool(sec, "incnoteswcount", self.incNotesWCount)
+ self.showFullPath = conf.rdBool(sec, "showfullpath", self.showFullPath)
+ self.highlightQuotes = conf.rdBool(sec, "highlightquotes", self.highlightQuotes)
+ self.allowOpenSQuote = conf.rdBool(sec, "allowopensquote", self.allowOpenSQuote)
+ self.allowOpenDQuote = conf.rdBool(sec, "allowopendquote", self.allowOpenDQuote)
+ self.highlightEmph = conf.rdBool(sec, "highlightemph", self.highlightEmph)
+ self.stopWhenIdle = conf.rdBool(sec, "stopwhenidle", self.stopWhenIdle)
+ self.userIdleTime = conf.rdInt(sec, "useridletime", self.userIdleTime)
# State
- cnfSec = "State"
- self.showRefPanel = theConf.rdBool(cnfSec, "showrefpanel", self.showRefPanel)
- self.viewComments = theConf.rdBool(cnfSec, "viewcomments", self.viewComments)
- self.viewSynopsis = theConf.rdBool(cnfSec, "viewsynopsis", self.viewSynopsis)
- self.searchCase = theConf.rdBool(cnfSec, "searchcase", self.searchCase)
- self.searchWord = theConf.rdBool(cnfSec, "searchword", self.searchWord)
- self.searchRegEx = theConf.rdBool(cnfSec, "searchregex", self.searchRegEx)
- self.searchLoop = theConf.rdBool(cnfSec, "searchloop", self.searchLoop)
- self.searchNextFile = theConf.rdBool(cnfSec, "searchnextfile", self.searchNextFile)
- self.searchMatchCap = theConf.rdBool(cnfSec, "searchmatchcap", self.searchMatchCap)
+ sec = "State"
+ self.showRefPanel = conf.rdBool(sec, "showrefpanel", self.showRefPanel)
+ self.viewComments = conf.rdBool(sec, "viewcomments", self.viewComments)
+ self.viewSynopsis = conf.rdBool(sec, "viewsynopsis", self.viewSynopsis)
+ self.searchCase = conf.rdBool(sec, "searchcase", self.searchCase)
+ self.searchWord = conf.rdBool(sec, "searchword", self.searchWord)
+ self.searchRegEx = conf.rdBool(sec, "searchregex", self.searchRegEx)
+ self.searchLoop = conf.rdBool(sec, "searchloop", self.searchLoop)
+ self.searchNextFile = conf.rdBool(sec, "searchnextfile", self.searchNextFile)
+ self.searchMatchCap = conf.rdBool(sec, "searchmatchcap", self.searchMatchCap)
# Deprecated Settings or Locations as of 2.0
# ToDo: These will be loaded for a few minor releases until the users have converted them
- self.guiFont = theConf.rdStr("Main", "guifont", self.guiFont)
- self.guiFontSize = theConf.rdInt("Main", "guifontsize", self.guiFontSize)
- self.guiLocale = theConf.rdStr("Main", "guilang", self.guiLocale)
- self._backupPath = theConf.rdPath("Backup", "backuppath", self._backupPath)
- self.backupOnClose = theConf.rdBool("Backup", "backuponclose", self.backupOnClose)
- self.askBeforeBackup = theConf.rdBool("Backup", "askbeforebackup", self.askBeforeBackup)
- fmtSingleQuotes = theConf.rdStrList(cnfSec, "fmtsinglequote", [])
- fmtDoubleQuotes = theConf.rdStrList(cnfSec, "fmtdoublequote", [])
+ self.guiFont = conf.rdStr("Main", "guifont", self.guiFont)
+ self.guiFontSize = conf.rdInt("Main", "guifontsize", self.guiFontSize)
+ self.guiLocale = conf.rdStr("Main", "guilang", self.guiLocale)
+ self._backupPath = conf.rdPath("Backup", "backuppath", self._backupPath)
+ self.backupOnClose = conf.rdBool("Backup", "backuponclose", self.backupOnClose)
+ self.askBeforeBackup = conf.rdBool("Backup", "askbeforebackup", self.askBeforeBackup)
+ fmtSingleQuotes = conf.rdStrList(sec, "fmtsinglequote", [])
+ fmtDoubleQuotes = conf.rdStrList(sec, "fmtdoublequote", [])
if isinstance(fmtSingleQuotes, list) and len(fmtSingleQuotes) == 2:
self.fmtSQuoteOpen = fmtSingleQuotes[0]
@@ -661,18 +657,17 @@ class Config:
return True
- def saveConfig(self):
- """Save the current preferences to file.
- """
+ def saveConfig(self) -> bool:
+ """Save the current preferences to file."""
logger.debug("Saving config file")
- theConf = NWConfigParser()
+ conf = NWConfigParser()
- theConf["Meta"] = {
+ conf["Meta"] = {
"timestamp": formatTimeStamp(time()),
}
- theConf["Main"] = {
+ conf["Main"] = {
"theme": str(self.guiTheme),
"syntax": str(self.guiSyntax),
"font": str(self.guiFont),
@@ -684,7 +679,7 @@ class Config:
"lastpath": str(self._lastPath),
}
- theConf["Sizes"] = {
+ conf["Sizes"] = {
"mainwindow": self._packList(self._mainWinSize),
"preferences": self._packList(self._prefsWinSize),
"projloadcols": self._packList(self._projLoadCols),
@@ -693,7 +688,7 @@ class Config:
"outlinepane": self._packList(self._outlnPanePos),
}
- theConf["Project"] = {
+ conf["Project"] = {
"autosaveproject": str(self.autoSaveProj),
"autosavedoc": str(self.autoSaveDoc),
"emphlabels": str(self.emphLabels),
@@ -702,7 +697,7 @@ class Config:
"askbeforebackup": str(self.askBeforeBackup),
}
- theConf["Editor"] = {
+ conf["Editor"] = {
"textfont": str(self.textFont),
"textsize": str(self.textSize),
"width": str(self.textWidth),
@@ -743,7 +738,7 @@ class Config:
"useridletime": str(self.userIdleTime),
}
- theConf["State"] = {
+ conf["State"] = {
"showrefpanel": str(self.showRefPanel),
"viewcomments": str(self.viewComments),
"viewsynopsis": str(self.viewSynopsis),
@@ -759,7 +754,7 @@ class Config:
cnfPath = self._confPath / nwFiles.CONF_FILE
try:
with open(cnfPath, mode="w", encoding="utf-8") as outFile:
- theConf.write(outFile)
+ conf.write(outFile)
except Exception as exc:
logger.error("Could not save config file")
logException()
@@ -774,26 +769,14 @@ class Config:
# Internal Functions
##
- def _packList(self, inData):
+ def _packList(self, data: list) -> str:
"""Pack a list of items into a comma-separated string for saving
to the config file.
"""
- return ", ".join([str(inVal) for inVal in inData])
+ return ", ".join([str(inVal) for inVal in data])
- def _checkNone(self, checkVal):
- """Return a NoneType if the value corresponds to None, otherwise
- return the value unchanged.
- """
- if checkVal is None:
- return None
- if isinstance(checkVal, str):
- if checkVal.lower() == "none":
- return None
- return checkVal
-
- def _checkOptionalPackages(self):
- """Check if we have the optional packages used by some features.
- """
+ def _checkOptionalPackages(self) -> None:
+ """Check optional packages used by some features."""
try:
import enchant # noqa: F401
except ImportError:
@@ -809,14 +792,13 @@ class Config:
class RecentProjects:
- def __init__(self, config):
+ def __init__(self, config: Config) -> None:
self._conf = config
self._data = {}
return
- def loadCache(self):
- """Load the cache file for recent projects.
- """
+ def loadCache(self) -> bool:
+ """Load the cache file for recent projects."""
self._data = {}
cacheFile = self._conf.dataPath(nwFiles.RECENT_FILE)
@@ -839,9 +821,8 @@ class RecentProjects:
return True
- def saveCache(self):
- """Save the cache dictionary of recent projects.
- """
+ def saveCache(self) -> bool:
+ """Save the cache dictionary of recent projects."""
cacheFile = self._conf.dataPath(nwFiles.RECENT_FILE)
cacheTemp = cacheFile.with_suffix(".tmp")
try:
@@ -855,27 +836,27 @@ class RecentProjects:
return True
- def listEntries(self):
- """List all items in the cache.
- """
- return [(k, e["title"], e["words"], e["time"]) for k, e in self._data.items()]
+ def listEntries(self) -> list[tuple[str, str, int, int]]:
+ """List all items in the cache."""
+ return [
+ (str(k), str(e["title"]), checkInt(e["words"], 0), checkInt(e["time"], 0))
+ for k, e in self._data.items()
+ ]
- def update(self, projPath, projTitle, wordCount, saveTime):
- """Add or update recent cache information on a given project.
- """
- self._data[str(projPath)] = {
- "title": projTitle,
- "words": int(wordCount),
- "time": int(saveTime),
+ def update(self, path: str | Path, title: str, words: int, saved: float | int) -> None:
+ """Add or update recent cache information on a given project."""
+ self._data[str(path)] = {
+ "title": title,
+ "words": int(words),
+ "time": int(saved),
}
self.saveCache()
return
- def remove(self, projPath):
- """Try to remove a path from the recent projects cache.
- """
- if self._data.pop(str(projPath), None) is not None:
- logger.debug("Removed recent: %s", projPath)
+ def remove(self, path: str | Path) -> None:
+ """Try to remove a path from the recent projects cache."""
+ if self._data.pop(str(path), None) is not None:
+ logger.debug("Removed recent: %s", path)
self.saveCache()
return
diff --git a/novelwriter/dialogs/projload.py b/novelwriter/dialogs/projload.py
index 1ae6fb50..09fabd4d 100644
--- a/novelwriter/dialogs/projload.py
+++ b/novelwriter/dialogs/projload.py
@@ -100,8 +100,9 @@ class GuiProjectLoad(QDialog):
self.listBox.setIconSize(QSize(iPx, iPx))
treeHead = self.listBox.headerItem()
- treeHead.setTextAlignment(self.C_COUNT, Qt.AlignRight)
- treeHead.setTextAlignment(self.C_TIME, Qt.AlignRight)
+ if treeHead:
+ treeHead.setTextAlignment(self.C_COUNT, Qt.AlignRight)
+ treeHead.setTextAlignment(self.C_TIME, Qt.AlignRight)
self.lblRecent = QLabel("%s" % self.tr("Recently Opened Projects"))
self.lblPath = QLabel("%s" % self.tr("Path"))
@@ -281,8 +282,7 @@ class GuiProjectLoad(QDialog):
newItem.setFont(self.C_TIME, CONFIG.theme.guiFontFixed)
self.listBox.addTopLevelItem(newItem)
- if self.listBox.topLevelItemCount() > 0:
- self.listBox.topLevelItem(0).setSelected(True)
+ self.listBox.setCurrentItem(self.listBox.topLevelItem(0))
projColWidth = CONFIG.projLoadColWidths
if len(projColWidth) == 3:
diff --git a/novelwriter/extensions/circularprogress.py b/novelwriter/extensions/circularprogress.py
index 79dacfd1..b53bf6bd 100644
--- a/novelwriter/extensions/circularprogress.py
+++ b/novelwriter/extensions/circularprogress.py
@@ -42,7 +42,7 @@ class NProgressCircle(QProgressBar):
"_cPen", "_bPen", "_tColor"
)
- def __init__(self, parent: QWidget, size: int, point: int):
+ def __init__(self, parent: QWidget, size: int, point: int) -> None:
super().__init__(parent=parent)
self._text = None
self._point = point
@@ -60,10 +60,8 @@ class NProgressCircle(QProgressBar):
self.setFixedHeight(size)
return
- def setColours(
- self, back: QColor | None = None, track: QColor | None = None,
- bar: QColor | None = None, text: QColor | None = None
- ):
+ def setColours(self, back: QColor | None = None, track: QColor | None = None,
+ bar: QColor | None = None, text: QColor | None = None) -> None:
"""Set the colours of the widget."""
if isinstance(back, QColor):
self._dPen = QPen(back)
@@ -76,13 +74,13 @@ class NProgressCircle(QProgressBar):
self._tColor = text
return
- def setCentreText(self, text: str | None):
+ def setCentreText(self, text: str | None) -> None:
"""Replace the progress text with a custom string."""
self._text = text
self.setValue(self.value()) # Triggers a redraw
return
- def paintEvent(self, event: QPaintEvent):
+ def paintEvent(self, event: QPaintEvent) -> None:
"""Custom painter for the progress bar."""
progress = 100.0*self.value()/self.maximum()
angle = ceil(16*3.6*progress)
diff --git a/novelwriter/extensions/configlayout.py b/novelwriter/extensions/configlayout.py
index 68ac39e2..3ab6b87b 100644
--- a/novelwriter/extensions/configlayout.py
+++ b/novelwriter/extensions/configlayout.py
@@ -37,7 +37,7 @@ FONT_SCALE = 0.9
class NConfigLayout(QGridLayout):
- def __init__(self):
+ def __init__(self) -> None:
super().__init__()
self._nextRow = 0
@@ -56,7 +56,8 @@ class NConfigLayout(QGridLayout):
# Getters and Setters
##
- def setHelpTextStyle(self, color: QColor | list | tuple, fontScale: float = FONT_SCALE):
+ def setHelpTextStyle(self, color: QColor | list | tuple,
+ fontScale: float = FONT_SCALE) -> None:
"""Set the text color for the help text."""
if isinstance(color, QColor):
self._helpCol = color
@@ -65,7 +66,7 @@ class NConfigLayout(QGridLayout):
self._fontScale = fontScale
return
- def setHelpText(self, row: int, text: str):
+ def setHelpText(self, row: int, text: str) -> None:
"""Set the text for the help label."""
if row in self._itemMap:
qHelp = self._itemMap[row][1]
@@ -73,7 +74,7 @@ class NConfigLayout(QGridLayout):
qHelp.setText(text)
return
- def setLabelText(self, row: int, text: str):
+ def setLabelText(self, row: int, text: str) -> None:
"""Set the text for the main label."""
if row in self._itemMap:
self._itemMap[row](0).setText(text)
@@ -83,7 +84,7 @@ class NConfigLayout(QGridLayout):
# Class Methods
##
- def addGroupLabel(self, label: str):
+ def addGroupLabel(self, label: str) -> None:
"""Add a text label to separate groups of settings."""
hM = CONFIG.pxInt(4)
qLabel = QLabel("%s" % label)
@@ -94,10 +95,8 @@ class NConfigLayout(QGridLayout):
self._nextRow += 1
return
- def addRow(
- self, label: str, widget: QWidget, helpText: str | None = None,
- unit: str | None = None, button: QWidget | None = None
- ) -> int:
+ def addRow(self, label: str, widget: QWidget, helpText: str | None = None,
+ unit: str | None = None, button: QWidget | None = None) -> int:
"""Add a label and a widget as a new row of the grid."""
wSp = CONFIG.pxInt(8)
qLabel = QLabel(label)
@@ -155,7 +154,7 @@ class NSimpleLayout(QGridLayout):
column layout.
"""
- def __init__(self):
+ def __init__(self) -> None:
super().__init__()
self._nextRow = 0
@@ -170,7 +169,7 @@ class NSimpleLayout(QGridLayout):
# Methods
##
- def addGroupLabel(self, label: str):
+ def addGroupLabel(self, label: str) -> None:
"""Add a text label to separate groups of settings."""
hM = CONFIG.pxInt(4)
qLabel = QLabel("%s" % label)
@@ -181,7 +180,7 @@ class NSimpleLayout(QGridLayout):
self._nextRow += 1
return
- def addRow(self, label: str, widget: QWidget):
+ def addRow(self, label: str, widget: QWidget) -> None:
"""Add a label and a widget as a new row of the grid."""
wSp = CONFIG.pxInt(8)
qLabel = QLabel(label)
@@ -208,7 +207,8 @@ class NSimpleLayout(QGridLayout):
class NHelpLabel(QLabel):
- def __init__(self, text: str, color: QColor | list | tuple, fontSize: float = FONT_SCALE):
+ def __init__(self, text: str, color: QColor | list | tuple,
+ fontSize: float = FONT_SCALE) -> None:
super().__init__(text)
if isinstance(color, QColor):
diff --git a/novelwriter/extensions/pageddialog.py b/novelwriter/extensions/pageddialog.py
index aa8de6e2..a4170a2a 100644
--- a/novelwriter/extensions/pageddialog.py
+++ b/novelwriter/extensions/pageddialog.py
@@ -23,10 +23,11 @@ along with this program. If not, see .
"""
from __future__ import annotations
-from PyQt5.QtCore import QRect, QPoint
+from PyQt5.QtGui import QPaintEvent
+from PyQt5.QtCore import QRect, QPoint, QSize
from PyQt5.QtWidgets import (
QDialog, QHBoxLayout, QStyle, QStyleOptionTab, QStylePainter, QTabBar,
- QTabWidget, QVBoxLayout
+ QTabWidget, QVBoxLayout, QWidget
)
from novelwriter import CONFIG
@@ -34,7 +35,7 @@ from novelwriter import CONFIG
class NPagedDialog(QDialog):
- def __init__(self, parent=None):
+ def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
self._tabBar = NVerticalTabBar(self)
@@ -67,21 +68,18 @@ class NPagedDialog(QDialog):
return
- def addTab(self, widget, label):
- """Forward the adding of tabs to the QTabWidget.
- """
+ def addTab(self, widget: QWidget, label: str) -> None:
+ """Forward the adding of tabs to the QTabWidget."""
self._tabBox.addTab(widget, label)
return
- def addControls(self, buttonBar):
- """Add a button bar to the dialog.
- """
+ def addControls(self, buttonBar: QWidget) -> None:
+ """Add a button bar to the dialog."""
self._buttonBox.addWidget(buttonBar)
return
- def setCurrentWidget(self, widget):
- """Forward the changing of tab to the QTabWidget.
- """
+ def setCurrentWidget(self, widget: QWidget) -> None:
+ """Forward the changing of tab to the QTabWidget."""
self._tabBox.setCurrentWidget(widget)
return
@@ -90,20 +88,19 @@ class NPagedDialog(QDialog):
class NVerticalTabBar(QTabBar):
- def __init__(self, parent=None):
+ def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
self._mW = CONFIG.pxInt(150)
return
- def tabSizeHint(self, index):
- """Return a transposed size hint for the rotated bar.
- """
+ def tabSizeHint(self, index: int) -> QSize:
+ """Return a transposed size hint for the rotated bar."""
tSize = super().tabSizeHint(index)
tSize.transpose()
tSize.setWidth(min(tSize.width(), self._mW))
return tSize
- def paintEvent(self, event):
+ def paintEvent(self, event: QPaintEvent) -> None:
"""Custom implementation of the label painter that rotates the
label 90 degrees.
"""
diff --git a/novelwriter/extensions/simpleprogress.py b/novelwriter/extensions/simpleprogress.py
index 2dbf4e43..30a11168 100644
--- a/novelwriter/extensions/simpleprogress.py
+++ b/novelwriter/extensions/simpleprogress.py
@@ -35,11 +35,11 @@ class NProgressSimple(QProgressBar):
A custom widget that paints a plain bar with no other styling.
"""
- def __init__(self, parent: QWidget):
+ def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
return
- def paintEvent(self, event: QPaintEvent):
+ def paintEvent(self, event: QPaintEvent) -> None:
"""Custom painter for the progress bar."""
if self.value() == 0:
return
diff --git a/novelwriter/extensions/switch.py b/novelwriter/extensions/switch.py
index be90bec7..e702a6b6 100644
--- a/novelwriter/extensions/switch.py
+++ b/novelwriter/extensions/switch.py
@@ -23,9 +23,9 @@ along with this program. If not, see .
"""
from __future__ import annotations
-from PyQt5.QtGui import QPainter
-from PyQt5.QtCore import Qt, QRectF, QPropertyAnimation, pyqtProperty
-from PyQt5.QtWidgets import QSizePolicy, QAbstractButton
+from PyQt5.QtGui import QMouseEvent, QPainter, QPaintEvent, QResizeEvent
+from PyQt5.QtCore import QEvent, QPropertyAnimation, QRectF, Qt, pyqtProperty
+from PyQt5.QtWidgets import QAbstractButton, QSizePolicy, QWidget
from novelwriter import CONFIG
from novelwriter.constants import nwUnicode
@@ -33,7 +33,8 @@ from novelwriter.constants import nwUnicode
class NSwitch(QAbstractButton):
- def __init__(self, parent=None, width=None, height=None):
+ def __init__(self, parent: QWidget | None = None,
+ width: int | None = None, height: int | None = None) -> None:
super().__init__(parent=parent)
if width is None:
@@ -64,12 +65,12 @@ class NSwitch(QAbstractButton):
# Properties
##
- @pyqtProperty(int)
- def offset(self):
+ @pyqtProperty(int) # type: ignore
+ def offset(self) -> int: # type: ignore
return self._offset
- @offset.setter
- def offset(self, offset):
+ @offset.setter # type: ignore
+ def offset(self, offset: int):
self._offset = offset
self.update()
return
@@ -78,33 +79,30 @@ class NSwitch(QAbstractButton):
# Getters and Setters
##
- def setChecked(self, checked):
- """Overload setChecked to also alter the offset.
- """
+ def setChecked(self, checked: bool) -> None:
+ """Overload setChecked to also alter the offset."""
super().setChecked(checked)
if checked:
- self.offset = self._xW - self._xR
+ self._offset = self._xW - self._xR
else:
- self.offset = self._xR
+ self._offset = self._xR
return
##
# Events
##
- def resizeEvent(self, event):
- """Overload resize to ensure correct offset.
- """
+ def resizeEvent(self, event: QResizeEvent) -> None:
+ """Overload resize to ensure correct offset."""
super().resizeEvent(event)
if self.isChecked():
- self.offset = self._xW - self._xR
+ self._offset = self._xW - self._xR
else:
- self.offset = self._xR
+ self._offset = self._xR
return
- def paintEvent(self, event):
- """Drawing the switch itself.
- """
+ def paintEvent(self, event: QPaintEvent) -> None:
+ """Drawing the switch itself."""
qPaint = QPainter(self)
qPaint.setRenderHint(QPainter.Antialiasing, True)
qPaint.setPen(Qt.NoPen)
@@ -134,27 +132,26 @@ class NSwitch(QAbstractButton):
qPaint.drawRoundedRect(0, 0, self._xW, self._xH, self._xR, self._xR)
qPaint.setBrush(thumbBrush)
- qPaint.drawEllipse(self.offset - self._rR, self._rB, self._rH, self._rH)
+ qPaint.drawEllipse(self._offset - self._rR, self._rB, self._rH, self._rH)
theFont = qPaint.font()
theFont.setPixelSize(self._xT)
qPaint.setPen(textColor)
qPaint.setFont(theFont)
qPaint.drawText(
- QRectF(self.offset - self._rR, self._rB, self._rH, self._rH),
+ QRectF(self._offset - self._rR, self._rB, self._rH, self._rH),
Qt.AlignCenter, thumbText
)
return
- def mouseReleaseEvent(self, event):
- """Animate the switch on mouse release.
- """
+ def mouseReleaseEvent(self, event: QMouseEvent) -> None:
+ """Animate the switch on mouse release."""
super().mouseReleaseEvent(event)
if event.button() == Qt.LeftButton:
doAnim = QPropertyAnimation(self, b"offset", self)
doAnim.setDuration(120)
- doAnim.setStartValue(self.offset)
+ doAnim.setStartValue(self._offset)
if self.isChecked():
doAnim.setEndValue(self._xW - self._xR)
else:
@@ -162,9 +159,8 @@ class NSwitch(QAbstractButton):
doAnim.start()
return
- def enterEvent(self, event):
- """Change the cursor when hovering the button.
- """
+ def enterEvent(self, event: QEvent) -> None:
+ """Change the cursor when hovering the button."""
self.setCursor(Qt.PointingHandCursor)
super().enterEvent(event)
return
diff --git a/novelwriter/extensions/switchbox.py b/novelwriter/extensions/switchbox.py
index f7385058..98db295a 100644
--- a/novelwriter/extensions/switchbox.py
+++ b/novelwriter/extensions/switchbox.py
@@ -23,8 +23,8 @@ along with this program. If not, see .
"""
from __future__ import annotations
-from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QIcon
+from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtWidgets import QGridLayout, QLabel, QScrollArea, QSizePolicy, QWidget
from novelwriter.extensions.switch import NSwitch
@@ -39,7 +39,7 @@ class NSwitchBox(QScrollArea):
switchToggled = pyqtSignal(str, bool)
- def __init__(self, parent: QWidget, baseSize: int):
+ def __init__(self, parent: QWidget, baseSize: int) -> None:
super().__init__(parent=parent)
self._index = 0
self._hSwitch = baseSize
@@ -49,7 +49,7 @@ class NSwitchBox(QScrollArea):
self.clear()
return
- def clear(self):
+ def clear(self) -> None:
"""Rebuild the content of the core widget."""
self._index = 0
self._widgets = []
@@ -66,7 +66,7 @@ class NSwitchBox(QScrollArea):
return
- def addLabel(self, text: str):
+ def addLabel(self, text: str) -> None:
"""Add a header label to the content box."""
label = QLabel(text)
font = label.font()
@@ -77,7 +77,7 @@ class NSwitchBox(QScrollArea):
self._bumpIndex()
return
- def addItem(self, qIcon: QIcon, text: str, identifier: str, default: bool = False):
+ def addItem(self, qIcon: QIcon, text: str, identifier: str, default: bool = False) -> None:
"""Add an item to the content box."""
icon = QLabel("")
icon.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
@@ -97,7 +97,7 @@ class NSwitchBox(QScrollArea):
return
- def addSeparator(self):
+ def addSeparator(self) -> None:
"""Add a blank entry in the content box."""
spacer = QWidget()
spacer.setFixedHeight(int(0.5*self._sIcon))
@@ -106,7 +106,7 @@ class NSwitchBox(QScrollArea):
self._bumpIndex()
return
- def setInnerContentsMargins(self, left: int, top: int, right: int, bottom: int):
+ def setInnerContentsMargins(self, left: int, top: int, right: int, bottom: int) -> None:
"""Set the contents margins of the inner layout."""
self._content.setContentsMargins(left, top, right, bottom)
return
@@ -115,12 +115,12 @@ class NSwitchBox(QScrollArea):
# Internal Functions
##
- def _emitSwitchSignal(self, identifier: str, state: bool):
+ def _emitSwitchSignal(self, identifier: str, state: bool) -> None:
"""Emit a signal for a switch toggle."""
self.switchToggled.emit(identifier, state)
return
- def _bumpIndex(self):
+ def _bumpIndex(self) -> None:
"""Increase the index counter and make sure only the last
columns is stretching.
"""
diff --git a/tests/test_base/test_base_config.py b/tests/test_base/test_base_config.py
index 524cd8a1..0f953f81 100644
--- a/tests/test_base/test_base_config.py
+++ b/tests/test_base/test_base_config.py
@@ -366,14 +366,6 @@ def testBaseConfig_Internal(monkeypatch, fncPath):
# Function _packList
assert tstConf._packList(["A", 1, 2.0, None, False]) == "A, 1, 2.0, None, False"
- # Function _checkNone
- assert tstConf._checkNone(None) is None
- assert tstConf._checkNone("None") is None
- assert tstConf._checkNone("none") is None
- assert tstConf._checkNone("NONE") is None
- assert tstConf._checkNone("NoNe") is None
- assert tstConf._checkNone(123456) == 123456
-
# Function _checkOptionalPackages
# (Assumes enchant package exists and is importable)
tstConf._checkOptionalPackages()