Make new code pass docstring linting
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
novelWriter – Build Settings Class
|
||||
==================================
|
||||
A class to hold build settings for the build tool
|
||||
novelWriter – Build Settings
|
||||
============================
|
||||
|
||||
File History:
|
||||
Created: 2023-02-14 [2.1b1] BuildSettings
|
||||
@@ -117,6 +116,7 @@ SETTINGS_LABELS = {
|
||||
|
||||
|
||||
class FilterMode(Enum):
|
||||
"""The decision reason for an item in a filtered project."""
|
||||
|
||||
UNKNOWN = 0
|
||||
FILTERED = 1
|
||||
@@ -128,6 +128,11 @@ class FilterMode(Enum):
|
||||
|
||||
|
||||
class BuildSettings:
|
||||
"""Core: Build Settings Class
|
||||
|
||||
This class manages the build settings for a Manuscript build job.
|
||||
The settings can be packed/unpacked to/from a dictionary for JSON.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._name = ""
|
||||
@@ -145,14 +150,17 @@ class BuildSettings:
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the build name."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def buildID(self) -> str:
|
||||
"""Return the build ID."""
|
||||
return self._uuid
|
||||
|
||||
@property
|
||||
def changed(self) -> bool:
|
||||
"""Return the changed status of the build."""
|
||||
return self._changed
|
||||
|
||||
##
|
||||
@@ -161,33 +169,28 @@ class BuildSettings:
|
||||
|
||||
@staticmethod
|
||||
def getLabel(key: str) -> str:
|
||||
"""Extract the label for a specific item.
|
||||
"""
|
||||
"""Extract the GUI label for a specific setting."""
|
||||
return SETTINGS_LABELS.get(key, "ERROR")
|
||||
|
||||
def getStr(self, key: str) -> str:
|
||||
"""Type safe value access for strings.
|
||||
"""
|
||||
"""Type safe value access for strings."""
|
||||
value = self._settings.get(key, SETTINGS_TEMPLATE.get(key, (None, None)[1]))
|
||||
return str(value)
|
||||
|
||||
def getBool(self, key: str) -> bool:
|
||||
"""Type safe value access for bools.
|
||||
"""
|
||||
"""Type safe value access for bools."""
|
||||
value = self._settings.get(key, SETTINGS_TEMPLATE.get(key, (None, None)[1]))
|
||||
return bool(value)
|
||||
|
||||
def getInt(self, key: str) -> int:
|
||||
"""Type safe value access for integers.
|
||||
"""
|
||||
"""Type safe value access for integers."""
|
||||
value = self._settings.get(key, SETTINGS_TEMPLATE.get(key, (None, None)[1]))
|
||||
if isinstance(value, int):
|
||||
return value
|
||||
return 0
|
||||
|
||||
def getFloat(self, key: str) -> float:
|
||||
"""Type safe value access for float.
|
||||
"""
|
||||
"""Type safe value access for float."""
|
||||
value = self._settings.get(key, SETTINGS_TEMPLATE.get(key, (None, None)[1]))
|
||||
if isinstance(value, float):
|
||||
return value
|
||||
@@ -198,14 +201,12 @@ class BuildSettings:
|
||||
##
|
||||
|
||||
def setName(self, name: str):
|
||||
"""Set the build setting display name.
|
||||
"""
|
||||
"""Set the build setting display name."""
|
||||
self._name = str(name)
|
||||
return
|
||||
|
||||
def setBuildID(self, value: str | uuid.UUID):
|
||||
"""Set a UUID build ID.
|
||||
"""
|
||||
"""Set a UUID build ID."""
|
||||
value = checkUuid(value, "")
|
||||
if not value:
|
||||
self._uuid = str(uuid.uuid4())
|
||||
@@ -214,32 +215,28 @@ class BuildSettings:
|
||||
return
|
||||
|
||||
def setFiltered(self, tHandle: str):
|
||||
"""Set an item as filtered.
|
||||
"""
|
||||
"""Set an item as filtered."""
|
||||
self._excluded.discard(tHandle)
|
||||
self._included.discard(tHandle)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def setIncluded(self, tHandle: str):
|
||||
"""Set an item as explicitly included.
|
||||
"""
|
||||
"""Set an item as explicitly included."""
|
||||
self._excluded.discard(tHandle)
|
||||
self._included.add(tHandle)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def setExcluded(self, tHandle: str):
|
||||
"""Set an item as explicitly excluded.
|
||||
"""
|
||||
"""Set an item as explicitly excluded."""
|
||||
self._excluded.add(tHandle)
|
||||
self._included.discard(tHandle)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def setSkipRoot(self, tHandle: str, state: bool):
|
||||
"""Set a specific root folder as skipped or not.
|
||||
"""
|
||||
"""Set a specific root folder as skipped or not."""
|
||||
if state is True:
|
||||
self._skipRoot.discard(tHandle)
|
||||
self._changed = True
|
||||
@@ -249,8 +246,7 @@ class BuildSettings:
|
||||
return
|
||||
|
||||
def setValue(self, key: str, value: str | int | bool | float) -> bool:
|
||||
"""Set a specific value for a build setting.
|
||||
"""
|
||||
"""Set a specific value for a build setting."""
|
||||
if key not in SETTINGS_TEMPLATE:
|
||||
return False
|
||||
definition = SETTINGS_TEMPLATE[key]
|
||||
@@ -267,19 +263,11 @@ class BuildSettings:
|
||||
# Methods
|
||||
##
|
||||
|
||||
def isFiltered(self, tHandle: str) -> bool:
|
||||
return tHandle not in self._included and tHandle not in self._excluded
|
||||
|
||||
def isIncluded(self, tHandle: str) -> bool:
|
||||
return tHandle in self._included
|
||||
|
||||
def isExcluded(self, tHandle: str) -> bool:
|
||||
return tHandle in self._excluded
|
||||
|
||||
def isRootAllowed(self, tHandle: str) -> bool:
|
||||
"""Check if a root handle is allowed in the build."""
|
||||
return tHandle not in self._skipRoot
|
||||
|
||||
def buildItemFilter(self, project: NWProject) -> dict:
|
||||
def buildItemFilter(self, project: NWProject) -> dict[str, tuple[bool, FilterMode]]:
|
||||
"""Return a dictionary of item handles with filter decissions
|
||||
applied.
|
||||
"""
|
||||
@@ -325,15 +313,14 @@ class BuildSettings:
|
||||
return result
|
||||
|
||||
def resetChangedState(self):
|
||||
"""This must be called when the changes to this class has been
|
||||
safely saved to file or passed on.
|
||||
"""Reset the changed status of the settings object. This must be
|
||||
called when the changes have been safely saved or passed on.
|
||||
"""
|
||||
self._changed = False
|
||||
return
|
||||
|
||||
def pack(self) -> dict:
|
||||
"""Pack all content into a JSON compatible dictionary.
|
||||
"""
|
||||
"""Pack all content into a JSON compatible dictionary."""
|
||||
logger.debug("Collecting build setting for '%s'", self._name)
|
||||
return {
|
||||
"name": self._name,
|
||||
@@ -347,8 +334,7 @@ class BuildSettings:
|
||||
}
|
||||
|
||||
def unpack(self, data: dict):
|
||||
"""Unpack a dictionary and populate the class.
|
||||
"""
|
||||
"""Unpack a dictionary and populate the class."""
|
||||
settings = data.get("settings", {})
|
||||
content = data.get("content", {})
|
||||
included = content.get("included", [])
|
||||
@@ -377,6 +363,12 @@ class BuildSettings:
|
||||
|
||||
|
||||
class BuildCollection:
|
||||
"""Core: Build Collection Class
|
||||
|
||||
This object holds all the build setting objects defined by the given
|
||||
project. The build settings are saved as a single JSON file in the
|
||||
project folder.
|
||||
"""
|
||||
|
||||
def __init__(self, project: NWProject):
|
||||
self._project = project
|
||||
@@ -384,8 +376,7 @@ class BuildCollection:
|
||||
return
|
||||
|
||||
def getBuild(self, buildID: str) -> BuildSettings | None:
|
||||
"""Get a specific build settings object.
|
||||
"""
|
||||
"""Get a specific build settings object."""
|
||||
if buildID not in self._builds:
|
||||
return None
|
||||
build = BuildSettings()
|
||||
@@ -393,8 +384,7 @@ class BuildCollection:
|
||||
return build
|
||||
|
||||
def setBuild(self, build: BuildSettings) -> bool:
|
||||
"""Set build settings data in the collection.
|
||||
"""
|
||||
"""Set build settings data in the collection."""
|
||||
if not isinstance(build, BuildSettings):
|
||||
return False
|
||||
buildID = build.buildID
|
||||
@@ -402,15 +392,13 @@ class BuildCollection:
|
||||
return True
|
||||
|
||||
def builds(self) -> Iterable[tuple[str, str]]:
|
||||
"""Iterate over all avaiable builds.
|
||||
"""
|
||||
"""Iterate over all avaiable builds."""
|
||||
for buildID in self._builds:
|
||||
yield buildID, self._builds[buildID].get("name", "")
|
||||
return
|
||||
|
||||
def loadCollection(self) -> bool:
|
||||
"""Load build collections file.
|
||||
"""
|
||||
"""Load build collections file."""
|
||||
buildsFile = self._project.storage.getMetaFile(nwFiles.BUILDS_FILE)
|
||||
if not isinstance(buildsFile, Path):
|
||||
return False
|
||||
@@ -442,8 +430,7 @@ class BuildCollection:
|
||||
return True
|
||||
|
||||
def saveCollection(self) -> bool:
|
||||
"""Save build collections file.
|
||||
"""
|
||||
"""Save build collections file."""
|
||||
buildsFile = self._project.storage.getMetaFile(nwFiles.BUILDS_FILE)
|
||||
if not isinstance(buildsFile, Path):
|
||||
return False
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"""
|
||||
novelWriter – Build Document Tool
|
||||
=================================
|
||||
A class to build one or more novelWriter files to a single document
|
||||
novelWriter – Manuscript Document Builder
|
||||
=========================================
|
||||
|
||||
File History:
|
||||
Created: 2022-12-01 [2.1b1]
|
||||
Created: 2022-12-01 [2.1b1] NWBuildDocument
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2023, Veronica Berglyd Olsen
|
||||
@@ -44,6 +43,11 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NWBuildDocument:
|
||||
"""Core: Manuscript Document Build Class
|
||||
|
||||
This is the core tool that assembles a project and outputs a
|
||||
manuscript, based on a build definition object (BuildSettings).
|
||||
"""
|
||||
|
||||
__slots__ = ("_project", "_build", "_queue", "_error", "_cache")
|
||||
|
||||
@@ -61,10 +65,15 @@ class NWBuildDocument:
|
||||
|
||||
@property
|
||||
def error(self) -> str | None:
|
||||
"""Return the last error, if any."""
|
||||
return self._error
|
||||
|
||||
@property
|
||||
def lastBuild(self) -> Tokenizer | None:
|
||||
"""Return the build object of the last build process, if any.
|
||||
This is useful for accessing build details and data after the
|
||||
build job is completed.
|
||||
"""
|
||||
return self._cache
|
||||
|
||||
##
|
||||
@@ -72,6 +81,7 @@ class NWBuildDocument:
|
||||
##
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""Return the length of the build queue."""
|
||||
return len(self._queue)
|
||||
|
||||
##
|
||||
@@ -79,17 +89,17 @@ class NWBuildDocument:
|
||||
##
|
||||
|
||||
def addDocument(self, tHandle: str):
|
||||
"""Add a document to the build queue manually.
|
||||
"""
|
||||
"""Add a document to the build queue manually."""
|
||||
self._queue.append(tHandle)
|
||||
return
|
||||
|
||||
def queueAll(self):
|
||||
"""Queue all document as defined by the build setup.
|
||||
"""
|
||||
"""Queue all document as defined by the build settings."""
|
||||
filtered = self._build.buildItemFilter(self._project)
|
||||
noteTitles = self._build.getBool("text.addNoteHeadings")
|
||||
for item in self._project.tree:
|
||||
if not item.itemHandle:
|
||||
continue
|
||||
if filtered.get(item.itemHandle, False):
|
||||
self._queue.append(item.itemHandle)
|
||||
elif item.isRootType() and noteTitles:
|
||||
@@ -97,8 +107,7 @@ class NWBuildDocument:
|
||||
return
|
||||
|
||||
def iterBuildOpenDocument(self, path: Path, isFlat: bool) -> Iterable[tuple[int, bool]]:
|
||||
"""Build an Open Document file.
|
||||
"""
|
||||
"""Build an Open Document file."""
|
||||
makeOdt = ToOdt(self._project, isFlat=isFlat)
|
||||
self._setupBuild(makeOdt)
|
||||
makeOdt.initDocument()
|
||||
@@ -146,8 +155,7 @@ class NWBuildDocument:
|
||||
return
|
||||
|
||||
def iterBuildMarkdown(self, path: Path, extendedMd: bool) -> Iterable[tuple[int, bool]]:
|
||||
"""Build a Markdown file.
|
||||
"""
|
||||
"""Build a Markdown file."""
|
||||
makeMd = ToMarkdown(self._project)
|
||||
self._setupBuild(makeMd)
|
||||
|
||||
@@ -177,8 +185,7 @@ class NWBuildDocument:
|
||||
##
|
||||
|
||||
def _setupBuild(self, bldObj: Tokenizer):
|
||||
"""Configure the build object.
|
||||
"""
|
||||
"""Configure the build object."""
|
||||
# Get Settings
|
||||
fmtTitle = self._build.getStr("headings.fmtTitle")
|
||||
fmtChapter = self._build.getStr("headings.fmtChapter")
|
||||
@@ -240,8 +247,7 @@ class NWBuildDocument:
|
||||
return
|
||||
|
||||
def _doBuild(self, bldObj: Tokenizer, tHandle: str) -> bool:
|
||||
"""Build a single document and add it to the build object.
|
||||
"""
|
||||
"""Build a single document and add it to the build object."""
|
||||
self._error = None
|
||||
tItem = self._project.tree[tHandle]
|
||||
if tItem is None:
|
||||
|
||||
+19
-2
@@ -1,10 +1,9 @@
|
||||
"""
|
||||
novelWriter – GUI Main Window
|
||||
=============================
|
||||
The main application window
|
||||
|
||||
File History:
|
||||
Created: 2018-09-22 [0.0.1]
|
||||
Created: 2018-09-22 [0.0.1] GuiMain
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2023, Veronica Berglyd Olsen
|
||||
@@ -74,6 +73,24 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiMain(QMainWindow):
|
||||
"""Main GUI Window
|
||||
|
||||
The Main GUI window class. It is the entry point of the
|
||||
application, and holds all runtime objects aside from the main
|
||||
Config instance, which is created before the Main GUI.
|
||||
|
||||
The Main GUI is split up into GUI components, assembled in the init
|
||||
function. Also, the project instance and theme instance are created
|
||||
here. These should be passed around to all other objects who need
|
||||
them and new instances of them should generally not be created.
|
||||
|
||||
* All other GUI classes that depend on any components from the
|
||||
main GUI should be passed a reference to the instance of this
|
||||
class.
|
||||
* All non-GUI classes can be passed a reference to the NWProject
|
||||
instance if the Main GUI is not needed (which it generally
|
||||
shouldn't need).
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"""
|
||||
novelWriter – GUI Build Manuscript
|
||||
==================================
|
||||
GUI classes for the Manuscript Build Tool
|
||||
|
||||
File History:
|
||||
Created: 2023-05-24 [2.1b1]
|
||||
Created: 2023-05-24 [2.1b1] GuiManuscriptBuild
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2023, Veronica Berglyd Olsen
|
||||
@@ -32,6 +31,11 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiManuscriptBuild(QDialog):
|
||||
"""GUI Tools: Manucript Builder Dialog
|
||||
|
||||
This is the tool for running the build itself. It can be accessed
|
||||
independently of the Manuscript Build Tool.
|
||||
"""
|
||||
|
||||
def __init__(self, parent: QWidget):
|
||||
super().__init__(parent=parent)
|
||||
@@ -46,6 +50,7 @@ class GuiManuscriptBuild(QDialog):
|
||||
return
|
||||
|
||||
def __del__(self):
|
||||
"""For debug use only."""
|
||||
logger.debug("Delete: GuiManuscriptBuild")
|
||||
return
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
"""
|
||||
novelWriter – GUI Build Manuscript
|
||||
==================================
|
||||
GUI classes for the Manuscript Build Tool
|
||||
novelWriter – GUI Manuscript Tool
|
||||
=================================
|
||||
|
||||
File History:
|
||||
Created: 2023-05-13 [2.1b1] GuiManuscript
|
||||
Created: 2023-05-13 [2.1b1] GuiManuscriptPreview
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2023, Veronica Berglyd Olsen
|
||||
@@ -52,6 +50,12 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiManuscript(QDialog):
|
||||
"""GUI Tools: Manuscript Tool
|
||||
|
||||
The dialog displays all the users build definitions, a preview panel
|
||||
for the manuscript, and can trigger the actual build dialog to build
|
||||
a document directly to disk.
|
||||
"""
|
||||
|
||||
def __init__(self, mainGui: GuiMain):
|
||||
super().__init__(parent=mainGui)
|
||||
@@ -98,7 +102,7 @@ class GuiManuscript(QDialog):
|
||||
self.buildProgress = QProgressBar()
|
||||
self.btnPreview = QPushButton(self.tr("Build Preview"))
|
||||
self.btnPreview.clicked.connect(self._generatePreview)
|
||||
self.manPreview = GuiManuscriptPreview(self.mainGui)
|
||||
self.manPreview = _PreviewWidget(self.mainGui)
|
||||
|
||||
self.menuPrint = QMenu(self)
|
||||
self.aPrintSend = self.menuPrint.addAction(self.tr("Print Preview"))
|
||||
@@ -166,12 +170,12 @@ class GuiManuscript(QDialog):
|
||||
return
|
||||
|
||||
def __del__(self):
|
||||
"""For debug use only."""
|
||||
logger.debug("Delete: GuiManuscript")
|
||||
return
|
||||
|
||||
def loadContent(self):
|
||||
"""Load dialog content from project data.
|
||||
"""
|
||||
"""Load dialog content from project data."""
|
||||
self._builds.loadCollection()
|
||||
self._updateBuildsList()
|
||||
return
|
||||
@@ -181,7 +185,9 @@ class GuiManuscript(QDialog):
|
||||
##
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""Capture the user closing the window so we can save settings.
|
||||
"""Capture the user closing the window so we can save GUI
|
||||
settings. We also check that we don't have a build settings
|
||||
diralog open.
|
||||
"""
|
||||
self._saveSettings()
|
||||
for obj in self.children():
|
||||
@@ -198,8 +204,7 @@ class GuiManuscript(QDialog):
|
||||
|
||||
@pyqtSlot()
|
||||
def _createNewBuild(self):
|
||||
"""Open the build settings dialog for a new build.
|
||||
"""
|
||||
"""Open the build settings dialog for a new build."""
|
||||
build = BuildSettings()
|
||||
build.setName(self.tr("My Manuscript"))
|
||||
self._openSettingsDialog(build)
|
||||
@@ -207,8 +212,7 @@ class GuiManuscript(QDialog):
|
||||
|
||||
@pyqtSlot()
|
||||
def _editSelectedBuild(self):
|
||||
"""Edit the currently selected build settings entry.
|
||||
"""
|
||||
"""Edit the currently selected build settings entry."""
|
||||
build = self._getSelectedBuild()
|
||||
if build is not None:
|
||||
self._openSettingsDialog(build)
|
||||
@@ -216,8 +220,7 @@ class GuiManuscript(QDialog):
|
||||
|
||||
@pyqtSlot(BuildSettings)
|
||||
def _processNewSettings(self, build: BuildSettings):
|
||||
"""Process new build settings from the settings dialog.
|
||||
"""
|
||||
"""Process new build settings from the settings dialog."""
|
||||
self._builds.setBuild(build)
|
||||
self._builds.saveCollection()
|
||||
self._updateBuildItem(build)
|
||||
@@ -263,8 +266,7 @@ class GuiManuscript(QDialog):
|
||||
|
||||
@pyqtSlot()
|
||||
def _doClose(self):
|
||||
"""The close button has been clicked.
|
||||
"""
|
||||
"""Forward the close button to the default close method."""
|
||||
self.close()
|
||||
return
|
||||
|
||||
@@ -273,8 +275,7 @@ class GuiManuscript(QDialog):
|
||||
##
|
||||
|
||||
def _getSelectedBuild(self) -> BuildSettings | None:
|
||||
"""Get the currently selected build.
|
||||
"""
|
||||
"""Get the currently selected build."""
|
||||
bItems = self.buildList.selectedItems()
|
||||
if bItems:
|
||||
build = self._builds.getBuild(bItems[0].data(Qt.UserRole))
|
||||
@@ -283,13 +284,11 @@ class GuiManuscript(QDialog):
|
||||
return None
|
||||
|
||||
def _saveManuscript(self, outFormat: int):
|
||||
"""Save the manuscript file or files.
|
||||
"""
|
||||
"""Save the manuscript file or files."""
|
||||
return
|
||||
|
||||
def _saveSettings(self):
|
||||
"""Save the various user settings.
|
||||
"""
|
||||
"""Save the user GUI settings."""
|
||||
logger.debug("Saving GuiManuscript settings")
|
||||
|
||||
winWidth = CONFIG.rpxInt(self.width())
|
||||
@@ -309,8 +308,7 @@ class GuiManuscript(QDialog):
|
||||
return
|
||||
|
||||
def _openSettingsDialog(self, build: BuildSettings):
|
||||
"""Open the build settings dialog.
|
||||
"""
|
||||
"""Open the build settings dialog."""
|
||||
dlgSettings = GuiBuildSettings(self, self.mainGui, build)
|
||||
dlgSettings.setModal(False)
|
||||
dlgSettings.show()
|
||||
@@ -321,8 +319,7 @@ class GuiManuscript(QDialog):
|
||||
return
|
||||
|
||||
def _updateBuildsList(self):
|
||||
"""Update the list of available builds.
|
||||
"""
|
||||
"""Update the list of available builds."""
|
||||
self.buildList.clear()
|
||||
for key, name in self._builds.builds():
|
||||
bItem = QListWidgetItem()
|
||||
@@ -333,8 +330,7 @@ class GuiManuscript(QDialog):
|
||||
return
|
||||
|
||||
def _updateBuildItem(self, build: BuildSettings):
|
||||
"""Update the entry of a specific build item.
|
||||
"""
|
||||
"""Update the entry of a specific build item."""
|
||||
bItem = self._buildMap.get(build.buildID, None)
|
||||
if isinstance(bItem, QListWidgetItem):
|
||||
bItem.setText(build.name)
|
||||
@@ -345,7 +341,7 @@ class GuiManuscript(QDialog):
|
||||
# END Class GuiManuscript
|
||||
|
||||
|
||||
class GuiManuscriptPreview(QTextBrowser):
|
||||
class _PreviewWidget(QTextBrowser):
|
||||
|
||||
def __init__(self, mainGui: GuiMain):
|
||||
super().__init__(parent=mainGui)
|
||||
@@ -357,8 +353,7 @@ class GuiManuscriptPreview(QTextBrowser):
|
||||
return
|
||||
|
||||
def setContent(self, data: dict):
|
||||
"""
|
||||
"""
|
||||
"""Set the content of the preview widget."""
|
||||
sPos = self.verticalScrollBar().value()
|
||||
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||
|
||||
@@ -377,4 +372,4 @@ class GuiManuscriptPreview(QTextBrowser):
|
||||
|
||||
return
|
||||
|
||||
# END Class GuiManuscriptPreview
|
||||
# END Class _PreviewWidget
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"""
|
||||
novelWriter – GUI Build Settings
|
||||
================================
|
||||
GUI classes for editing Manuscript Build Settings
|
||||
|
||||
File History:
|
||||
Created: 2023-02-13 [2.1b1]
|
||||
Created: 2023-02-13 [2.1b1] GuiBuildSettings
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2023, Veronica Berglyd Olsen
|
||||
@@ -34,8 +33,8 @@ from PyQt5.QtGui import (
|
||||
from PyQt5.QtCore import QEvent, QSize, Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtWidgets import (
|
||||
QAbstractButton, QAbstractItemView, QComboBox, QDialog, QDialogButtonBox,
|
||||
QDoubleSpinBox, QFontDialog, QFrame, QGridLayout, QHBoxLayout, QHeaderView, QLabel,
|
||||
QLineEdit, QMenu, QPlainTextEdit, QPushButton, QSpinBox, QSplitter,
|
||||
QDoubleSpinBox, QFontDialog, QFrame, QGridLayout, QHBoxLayout, QHeaderView,
|
||||
QLabel, QLineEdit, QMenu, QPlainTextEdit, QPushButton, QSpinBox, QSplitter,
|
||||
QStackedWidget, QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
|
||||
QWidget
|
||||
)
|
||||
@@ -56,6 +55,11 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiBuildSettings(QDialog):
|
||||
"""GUI Tools: Manuscript Build Settings Dialog
|
||||
|
||||
The main tool for configuring manuscript builds. It's a GUI tool for
|
||||
editing JSON build definitions, wrapped as a BuildSettings object.
|
||||
"""
|
||||
|
||||
OPT_FILTERS = 1
|
||||
OPT_HEADINGS = 2
|
||||
@@ -112,11 +116,11 @@ class GuiBuildSettings(QDialog):
|
||||
# ============
|
||||
|
||||
# Create Tabs
|
||||
self.optTabSelect = GuiBuildFilterTab(self, self._build)
|
||||
self.optTabHeadings = GuiBuildHeadingsTab(self, self._build)
|
||||
self.optTabFormat = GuiBuildFormatTab(self, self._build)
|
||||
self.optTabContent = GuiBuildContentTab(self, self._build)
|
||||
self.optTabOutput = GuiBuildOutputTab(self, self._build)
|
||||
self.optTabSelect = _FilterTab(self, self._build)
|
||||
self.optTabHeadings = _HeadingsTab(self, self._build)
|
||||
self.optTabFormat = _FormatTab(self, self._build)
|
||||
self.optTabContent = _ContentTab(self, self._build)
|
||||
self.optTabOutput = _OutputTab(self, self._build)
|
||||
|
||||
# Add Tabs
|
||||
self.toolStack = QStackedWidget(self)
|
||||
@@ -164,11 +168,11 @@ class GuiBuildSettings(QDialog):
|
||||
return
|
||||
|
||||
def __del__(self):
|
||||
"""For debug use only."""
|
||||
logger.debug("Delete: GuiBuildSettings")
|
||||
|
||||
def loadContent(self):
|
||||
"""Populate the child widgets.
|
||||
"""
|
||||
"""Populate the child widgets."""
|
||||
self.editBuildName.setText(self._build.name)
|
||||
self.optTabSelect.loadContent()
|
||||
self.optTabHeadings.loadContent()
|
||||
@@ -183,8 +187,7 @@ class GuiBuildSettings(QDialog):
|
||||
|
||||
@pyqtSlot(int)
|
||||
def _stackPageSelected(self, pageId: int):
|
||||
"""Process a user request to switch page.
|
||||
"""
|
||||
"""Process a user request to switch page."""
|
||||
if pageId == self.OPT_FILTERS:
|
||||
self.toolStack.setCurrentWidget(self.optTabSelect)
|
||||
elif pageId == self.OPT_HEADINGS:
|
||||
@@ -199,8 +202,7 @@ class GuiBuildSettings(QDialog):
|
||||
|
||||
@pyqtSlot("QAbstractButton*")
|
||||
def _dialogButtonClicked(self, button: QAbstractButton):
|
||||
"""Handle button clicks from the dialog button box.
|
||||
"""
|
||||
"""Handle button clicks from the dialog button box."""
|
||||
role = self.dlgButtons.buttonRole(button)
|
||||
if role == QDialogButtonBox.ApplyRole:
|
||||
self._emitBuildData()
|
||||
@@ -216,7 +218,8 @@ class GuiBuildSettings(QDialog):
|
||||
##
|
||||
|
||||
def closeEvent(self, event: QEvent):
|
||||
"""Capture the user closing the window so we can save settings.
|
||||
"""Capture the user closing the window so we can save
|
||||
settings.
|
||||
"""
|
||||
logger.debug("Closing: GuiBuildSettings")
|
||||
self._askToSaveBuild()
|
||||
@@ -244,8 +247,7 @@ class GuiBuildSettings(QDialog):
|
||||
return
|
||||
|
||||
def _saveSettings(self):
|
||||
"""Save the various user settings.
|
||||
"""
|
||||
"""Save the various user settings."""
|
||||
logger.debug("Saving GuiBuildSettings settings")
|
||||
|
||||
winWidth = CONFIG.rpxInt(self.width())
|
||||
@@ -263,8 +265,7 @@ class GuiBuildSettings(QDialog):
|
||||
return
|
||||
|
||||
def _emitBuildData(self):
|
||||
"""Assemble the build data and emit the signal.
|
||||
"""
|
||||
"""Assemble the build data and emit the signal."""
|
||||
self._build.setName(self.editBuildName.text())
|
||||
self.optTabHeadings.saveContent()
|
||||
self.optTabContent.saveContent()
|
||||
@@ -277,7 +278,7 @@ class GuiBuildSettings(QDialog):
|
||||
# END Class GuiBuildSettings
|
||||
|
||||
|
||||
class GuiBuildFilterTab(QWidget):
|
||||
class _FilterTab(QWidget):
|
||||
|
||||
C_DATA = 0
|
||||
C_NAME = 0
|
||||
@@ -398,15 +399,13 @@ class GuiBuildFilterTab(QWidget):
|
||||
return
|
||||
|
||||
def loadContent(self):
|
||||
"""Populate the widgets.
|
||||
"""
|
||||
"""Populate the widgets."""
|
||||
self._populateTree()
|
||||
self._populateFilters()
|
||||
return
|
||||
|
||||
def mainSplitSizes(self) -> tuple[int, int]:
|
||||
"""Extract the sizes of the main splitter.
|
||||
"""
|
||||
"""Extract the sizes of the main splitter."""
|
||||
sizes = self.mainSplit.sizes()
|
||||
if len(sizes) < 2:
|
||||
return 0, 0
|
||||
@@ -418,8 +417,7 @@ class GuiBuildFilterTab(QWidget):
|
||||
|
||||
@pyqtSlot(str, bool)
|
||||
def _applyFilterSwitch(self, key: str, state: bool):
|
||||
"""A filter switch has been toggled, so update the settings.
|
||||
"""
|
||||
"""Apply filter switch and update the settings."""
|
||||
if key.startswith("doc:"):
|
||||
self._build.setValue(key[4:], state)
|
||||
self._setTreeItemMode()
|
||||
@@ -433,8 +431,7 @@ class GuiBuildFilterTab(QWidget):
|
||||
##
|
||||
|
||||
def _populateTree(self):
|
||||
"""Build the tree of project items.
|
||||
"""
|
||||
"""Build the tree of project items."""
|
||||
logger.debug("Building project tree")
|
||||
self._treeMap = {}
|
||||
self.optTree.clear()
|
||||
@@ -490,8 +487,7 @@ class GuiBuildFilterTab(QWidget):
|
||||
return
|
||||
|
||||
def _populateFilters(self):
|
||||
"""Populate the filter options switches.
|
||||
"""
|
||||
"""Populate the filter options switches."""
|
||||
self.filterOpt.clear()
|
||||
self.filterOpt.addLabel(self._build.getLabel("filter"))
|
||||
self.filterOpt.addItem(
|
||||
@@ -530,8 +526,7 @@ class GuiBuildFilterTab(QWidget):
|
||||
return
|
||||
|
||||
def _setSelectedMode(self, mode: int):
|
||||
"""Set the mode for the selected items.
|
||||
"""
|
||||
"""Set the mode for the selected items."""
|
||||
for item in self.optTree.selectedItems():
|
||||
if not isinstance(item, QTreeWidgetItem):
|
||||
continue
|
||||
@@ -551,8 +546,7 @@ class GuiBuildFilterTab(QWidget):
|
||||
return
|
||||
|
||||
def _setTreeItemMode(self):
|
||||
"""Update the filtered mode icon on all items.
|
||||
"""
|
||||
"""Update the filtered mode icon on all items."""
|
||||
filtered = self._build.buildItemFilter(self.theProject)
|
||||
for tHandle, item in self._treeMap.items():
|
||||
allow, mode = filtered.get(tHandle, (False, FilterMode.UNKNOWN))
|
||||
@@ -566,10 +560,10 @@ class GuiBuildFilterTab(QWidget):
|
||||
item.setIcon(self.C_STATUS, self._statusFlags[self.F_NONE][1])
|
||||
return
|
||||
|
||||
# END Class GuiBuildFilterTab
|
||||
# END Class _FilterTab
|
||||
|
||||
|
||||
class GuiBuildHeadingsTab(QWidget):
|
||||
class _HeadingsTab(QWidget):
|
||||
|
||||
EDIT_TITLE = 1
|
||||
EDIT_CHAPTER = 2
|
||||
@@ -707,7 +701,7 @@ class GuiBuildHeadingsTab(QWidget):
|
||||
self.editTextBox.setFixedHeight(5*iPx)
|
||||
self.editTextBox.setEnabled(False)
|
||||
|
||||
self.formSyntax = GuiHeadingSyntax(self.editTextBox.document(), self.mainTheme)
|
||||
self.formSyntax = _HeadingSyntaxHighlighter(self.editTextBox.document(), self.mainTheme)
|
||||
|
||||
self.menuInsert = QMenu()
|
||||
self.aInsTitle = self.menuInsert.addAction(self.tr("Title"))
|
||||
@@ -756,8 +750,7 @@ class GuiBuildHeadingsTab(QWidget):
|
||||
return
|
||||
|
||||
def loadContent(self):
|
||||
"""Populate the widgets.
|
||||
"""
|
||||
"""Populate the widgets."""
|
||||
self.fmtTitle.setText(self._build.getStr("headings.fmtTitle"))
|
||||
self.fmtChapter.setText(self._build.getStr("headings.fmtChapter"))
|
||||
self.fmtUnnumbered.setText(self._build.getStr("headings.fmtUnnumbered"))
|
||||
@@ -768,8 +761,7 @@ class GuiBuildHeadingsTab(QWidget):
|
||||
return
|
||||
|
||||
def saveContent(self):
|
||||
"""Save choices back into build object.
|
||||
"""
|
||||
"""Save choices back into build object."""
|
||||
self._build.setValue("headings.hideScene", self.swtScene.isChecked())
|
||||
self._build.setValue("headings.hideSection", self.swtSection.isChecked())
|
||||
return
|
||||
@@ -779,8 +771,7 @@ class GuiBuildHeadingsTab(QWidget):
|
||||
##
|
||||
|
||||
def _insertIntoForm(self, text: str):
|
||||
"""Insert formatting text from the dropdown menu.
|
||||
"""
|
||||
"""Insert formatting text from the dropdown menu."""
|
||||
if self._editing > 0:
|
||||
cursor = self.editTextBox.textCursor()
|
||||
cursor.insertText(text)
|
||||
@@ -788,8 +779,7 @@ class GuiBuildHeadingsTab(QWidget):
|
||||
return
|
||||
|
||||
def _editHeading(self, heading: int):
|
||||
"""Populate the form with a specific heading format.
|
||||
"""
|
||||
"""Populate the form with a specific heading format."""
|
||||
self._editing = heading
|
||||
self.editTextBox.setEnabled(True)
|
||||
if heading == self.EDIT_TITLE:
|
||||
@@ -823,8 +813,7 @@ class GuiBuildHeadingsTab(QWidget):
|
||||
##
|
||||
|
||||
def _saveFormat(self):
|
||||
"""Save the format from the edit text box.
|
||||
"""
|
||||
"""Save the format from the edit text box."""
|
||||
heading = self._editing
|
||||
text = self.editTextBox.toPlainText().replace("\n", "//")
|
||||
if heading == self.EDIT_TITLE:
|
||||
@@ -850,10 +839,10 @@ class GuiBuildHeadingsTab(QWidget):
|
||||
|
||||
return
|
||||
|
||||
# END Class GuiBuildHeadingsTab
|
||||
# END Class _HeadingsTab
|
||||
|
||||
|
||||
class GuiHeadingSyntax(QSyntaxHighlighter):
|
||||
class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
|
||||
|
||||
def __init__(self, document: QTextDocument, mainTheme: GuiTheme):
|
||||
super().__init__(document)
|
||||
@@ -864,8 +853,7 @@ class GuiHeadingSyntax(QSyntaxHighlighter):
|
||||
return
|
||||
|
||||
def highlightBlock(self, text: str):
|
||||
"""Add syntax highlighting to the text block.
|
||||
"""
|
||||
"""Add syntax highlighting to the text block."""
|
||||
for heading in nwHeadFmt.ALL:
|
||||
pos = text.find(heading)
|
||||
if pos >= 0:
|
||||
@@ -877,10 +865,10 @@ class GuiHeadingSyntax(QSyntaxHighlighter):
|
||||
self.setFormat(pos + ddots, 1, self._fmtSymbol)
|
||||
return
|
||||
|
||||
# END Class GuiHeadingSyntax
|
||||
# END Class _HeadingSyntaxHighlighter
|
||||
|
||||
|
||||
class GuiBuildContentTab(QWidget):
|
||||
class _ContentTab(QWidget):
|
||||
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings):
|
||||
super().__init__(parent=buildMain)
|
||||
@@ -932,8 +920,7 @@ class GuiBuildContentTab(QWidget):
|
||||
return
|
||||
|
||||
def loadContent(self):
|
||||
"""Populate the widgets.
|
||||
"""
|
||||
"""Populate the widgets."""
|
||||
self.incSynopsis.setChecked(self._build.getBool("text.includeSynopsis"))
|
||||
self.incComments.setChecked(self._build.getBool("text.includeComments"))
|
||||
self.incKeywords.setChecked(self._build.getBool("text.includeKeywords"))
|
||||
@@ -942,8 +929,7 @@ class GuiBuildContentTab(QWidget):
|
||||
return
|
||||
|
||||
def saveContent(self):
|
||||
"""Save choices back into build object.
|
||||
"""
|
||||
"""Save choices back into build object."""
|
||||
self._build.setValue("text.includeSynopsis", self.incSynopsis.isChecked())
|
||||
self._build.setValue("text.includeComments", self.incComments.isChecked())
|
||||
self._build.setValue("text.includeKeywords", self.incKeywords.isChecked())
|
||||
@@ -951,10 +937,10 @@ class GuiBuildContentTab(QWidget):
|
||||
self._build.setValue("text.addNoteHeadings", self.addNoteHead.isChecked())
|
||||
return
|
||||
|
||||
# END Class GuiBuildContentTab
|
||||
# END Class _ContentTab
|
||||
|
||||
|
||||
class GuiBuildFormatTab(QWidget):
|
||||
class _FormatTab(QWidget):
|
||||
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings):
|
||||
super().__init__(parent=buildMain)
|
||||
@@ -1035,8 +1021,7 @@ class GuiBuildFormatTab(QWidget):
|
||||
return
|
||||
|
||||
def loadContent(self):
|
||||
"""Populate the widgets.
|
||||
"""
|
||||
"""Populate the widgets."""
|
||||
langIdx = self.buildLang.findData(self._build.getStr("format.buildLang"))
|
||||
if langIdx != -1:
|
||||
self.buildLang.setCurrentIndex(langIdx)
|
||||
@@ -1056,8 +1041,7 @@ class GuiBuildFormatTab(QWidget):
|
||||
return
|
||||
|
||||
def saveContent(self):
|
||||
"""Save choices back into build object.
|
||||
"""
|
||||
"""Save choices back into build object."""
|
||||
self._build.setValue("format.buildLang", str(self.buildLang.currentData()))
|
||||
self._build.setValue("format.textFont", self.textFont.text())
|
||||
self._build.setValue("format.textSize", self.textSize.value())
|
||||
@@ -1073,8 +1057,7 @@ class GuiBuildFormatTab(QWidget):
|
||||
|
||||
@pyqtSlot()
|
||||
def _selectFont(self):
|
||||
"""Open the QFontDialog and set a font for the font style.
|
||||
"""
|
||||
"""Open the QFontDialog and set a font for the font style."""
|
||||
currFont = QFont()
|
||||
currFont.setFamily(self.textFont.text())
|
||||
currFont.setPointSize(self.textSize.value())
|
||||
@@ -1084,10 +1067,10 @@ class GuiBuildFormatTab(QWidget):
|
||||
self.textSize.setValue(theFont.pointSize())
|
||||
return
|
||||
|
||||
# END Class GuiBuildFormatTab
|
||||
# END Class _FormatTab
|
||||
|
||||
|
||||
class GuiBuildOutputTab(QWidget):
|
||||
class _OutputTab(QWidget):
|
||||
|
||||
def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings):
|
||||
super().__init__(parent=buildMain)
|
||||
@@ -1133,17 +1116,15 @@ class GuiBuildOutputTab(QWidget):
|
||||
return
|
||||
|
||||
def loadContent(self):
|
||||
"""Populate the widgets.
|
||||
"""
|
||||
"""Populate the widgets."""
|
||||
self.odtAddColours.setChecked(self._build.getBool("odt.addColours"))
|
||||
self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles"))
|
||||
return
|
||||
|
||||
def saveContent(self):
|
||||
"""Save choices back into build object.
|
||||
"""
|
||||
"""Save choices back into build object."""
|
||||
self._build.setValue("odt.addColours", self.odtAddColours.isChecked())
|
||||
self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked())
|
||||
return
|
||||
|
||||
# END Class GuiBuildOutputTab
|
||||
# END Class _OutputTab
|
||||
|
||||
Reference in New Issue
Block a user