diff --git a/novelwriter/constants.py b/novelwriter/constants.py index bb03cdfb..445f8b71 100644 --- a/novelwriter/constants.py +++ b/novelwriter/constants.py @@ -205,13 +205,13 @@ class nwLabels: class nwHeadingFormats: - TITLE = "{Title}" - CH_NUM = "{Chapter}" + TITLE = "{Title}" + CH_NUM = "{Chapter}" CH_WORD = "{Chapter:Word}" - CH_ROMU = "{Chapter:RomanU}" - CH_ROML = "{Chapter:RomanL}" - SC_NUM = "{Scene}" - SC_ABS = "{Scene:Abs}" + CH_ROMU = "{Chapter:URoman}" + CH_ROML = "{Chapter:LRoman}" + SC_NUM = "{Scene}" + SC_ABS = "{Scene:Abs}" # END Class nwHeadingFormats diff --git a/novelwriter/core/buildsettings.py b/novelwriter/core/buildsettings.py index 583c9cd1..a8d95692 100644 --- a/novelwriter/core/buildsettings.py +++ b/novelwriter/core/buildsettings.py @@ -22,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 uuid import logging @@ -59,7 +60,7 @@ SETTINGS_TEMPLATE = { "text.includeBody": (bool, True), "format.buildLang": (str, "en_GB"), "format.textFont": (str, ""), - "format.textSize": (str, ""), + "format.textSize": (int, 12), "format.lineHeight": (float, 1.15, 0.75, 3.0), "format.justifyText": (bool, False), "format.stripUnicode": (bool, False), @@ -119,7 +120,7 @@ class BuildSettings: def __init__(self): self._name = "" - self._uuid = "" + self._uuid = str(uuid.uuid4()) self._skipRoot = set() self._excluded = set() self._included = set() @@ -132,15 +133,15 @@ class BuildSettings: ## @property - def name(self): + def name(self) -> str: return self._name @property - def buildID(self): + def buildID(self) -> str: return self._uuid @property - def changed(self): + def changed(self) -> bool: return self._changed ## @@ -148,12 +149,12 @@ class BuildSettings: ## @staticmethod - def getLabel(key): + def getLabel(key: str) -> str: """Extract the label for a specific item. """ return SETTINGS_LABELS.get(key, "ERROR") - def getValue(self, key): + def getValue(self, key: str) -> str | int | bool | float: """Get the value for a specific item, or return the default. """ return self._settings.get(key, SETTINGS_TEMPLATE.get(key, (None, None)[1])) @@ -162,13 +163,13 @@ class BuildSettings: # Setters ## - def setName(self, name): + def setName(self, name: str): """Set the build setting display name. """ self._name = str(name) return - def setBuildID(self, value): + def setBuildID(self, value: str | uuid.UUID): """Set a UUID build ID. """ value = checkUuid(value, "") @@ -178,7 +179,7 @@ class BuildSettings: self._uuid = value return - def setFiltered(self, tHandle): + def setFiltered(self, tHandle: str): """Set an item as filtered. """ self._excluded.discard(tHandle) @@ -186,7 +187,7 @@ class BuildSettings: self._changed = True return - def setIncluded(self, tHandle): + def setIncluded(self, tHandle: str): """Set an item as explicitly included. """ self._excluded.discard(tHandle) @@ -194,7 +195,7 @@ class BuildSettings: self._changed = True return - def setExcluded(self, tHandle): + def setExcluded(self, tHandle: str): """Set an item as explicitly excluded. """ self._excluded.add(tHandle) @@ -202,7 +203,7 @@ class BuildSettings: self._changed = True return - def setSkipRoot(self, tHandle, state): + def setSkipRoot(self, tHandle: str, state: bool): """Set a specific root folder as skipped or not. """ if state is True: @@ -213,7 +214,7 @@ class BuildSettings: self._changed = True return - def setValue(self, key, value): + def setValue(self, key: str, value: str | int | bool | float) -> bool: """Set a specific value for a build setting. """ if key not in SETTINGS_TEMPLATE: @@ -232,32 +233,34 @@ class BuildSettings: # Methods ## - def isFiltered(self, tHandle): + def isFiltered(self, tHandle: str) -> bool: return tHandle not in self._included and tHandle not in self._excluded - def isIncluded(self, tHandle): + def isIncluded(self, tHandle: str) -> bool: return tHandle in self._included - def isExcluded(self, tHandle): + def isExcluded(self, tHandle: str) -> bool: return tHandle in self._excluded - def isRootAllowed(self, tHandle): + def isRootAllowed(self, tHandle: str) -> bool: return tHandle not in self._skipRoot - def buildItemFilter(self, project): + def buildItemFilter(self, project: NWProject) -> dict: """Return a dictionary of item handles with filter decissions applied. """ - result = {} + result: dict[str, tuple[bool, FilterMode]] = {} if not isinstance(project, NWProject): return result - incNovel = self.getValue("filter.includeNovel") or False - incNotes = self.getValue("filter.includeNotes") or False - incInactive = self.getValue("filter.includeInactive") or False + incNovel = bool(self.getValue("filter.includeNovel")) + incNotes = bool(self.getValue("filter.includeNotes")) + incInactive = bool(self.getValue("filter.includeInactive")) for item in project.tree: tHandle = item.itemHandle + if not tHandle: + continue if not isinstance(item, NWItem): result[tHandle] = (False, FilterMode.UNKNOWN) continue @@ -294,7 +297,7 @@ class BuildSettings: self._changed = False return - def pack(self): + def pack(self) -> dict: """Pack all content into a JSON compatible dictionary. """ logger.debug("Collecting build setting for '%s'", self._name) @@ -307,7 +310,7 @@ class BuildSettings: "skipRoot": list(self._skipRoot), } - def unpack(self, data): + def unpack(self, data: dict): """Unpack a dictionary and populate the class. """ included = data.get("included", []) diff --git a/novelwriter/tools/manusbuild.py b/novelwriter/tools/manusbuild.py index 53418d90..912532b7 100644 --- a/novelwriter/tools/manusbuild.py +++ b/novelwriter/tools/manusbuild.py @@ -35,6 +35,7 @@ from PyQt5.QtWidgets import ( ) from novelwriter import CONFIG +from novelwriter.core.buildsettings import BuildSettings from novelwriter.tools.manussettings import GuiBuildSettings if TYPE_CHECKING: @@ -121,9 +122,10 @@ class GuiBuildManuscript(QDialog): def _createNewBuild(self): """Open the build settings dialog for a new build. """ - data = {"name": self.tr("My Manuscript")} + build = BuildSettings() + build.setName(self.tr("My Manuscript")) - dlgSettings = GuiBuildSettings(self.mainGui, data) + dlgSettings = GuiBuildSettings(self.mainGui, build) dlgSettings.setModal(False) dlgSettings.show() dlgSettings.raise_() diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index c7cfe5b3..27cfdb0f 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -57,13 +57,11 @@ class GuiBuildSettings(QDialog): OPT_HEADINGS = 2 OPT_FORMAT = 3 OPT_CONTENT = 4 - BLD_HTML = 5 - BLD_MARKDOWN = 6 - BLD_ODT = 7 + OPT_OUTPUT = 5 newSettingsReady = pyqtSignal(dict) - def __init__(self, mainGui: GuiMain, buildData: dict): + def __init__(self, mainGui: GuiMain, build: BuildSettings): super().__init__(parent=mainGui) logger.debug("Initialising GuiBuildSettings ...") @@ -73,8 +71,7 @@ class GuiBuildSettings(QDialog): self.mainTheme = mainGui.mainTheme self.theProject = mainGui.theProject - self._build = BuildSettings() - self._build.unpack(buildData) + self._build = build self.setWindowTitle(self.tr("Manuscript Build Settings")) self.setMinimumWidth(CONFIG.pxInt(700)) @@ -98,17 +95,12 @@ class GuiBuildSettings(QDialog): self.optSideBar.setMaximumWidth(mPx) self.optSideBar.setLabelColor(self.mainTheme.helpText) - self.optSideBar.addLabel(self.tr("Content")) + self.optSideBar.addLabel(self.tr("Options")) self.optSideBar.addButton(self.tr("Filters"), self.OPT_FILTERS) self.optSideBar.addButton(self.tr("Headings"), self.OPT_HEADINGS) self.optSideBar.addButton(self.tr("Format"), self.OPT_FORMAT) self.optSideBar.addButton(self.tr("Content"), self.OPT_CONTENT) - self.optSideBar.addSeparator() - - self.optSideBar.addLabel(self.tr("Output")) - self.optSideBar.addButton(self.tr("HTML"), self.BLD_HTML) - self.optSideBar.addButton(self.tr("Markdown"), self.BLD_MARKDOWN) - self.optSideBar.addButton(self.tr("Open Document"), self.BLD_ODT) + self.optSideBar.addButton(self.tr("Output"), self.OPT_OUTPUT) self.optSideBar.buttonClicked.connect(self._stackPageSelected) @@ -120,9 +112,7 @@ class GuiBuildSettings(QDialog): self.optTabHeadings = GuiBuildHeadingsTab(self, self._build) self.optTabFormat = GuiBuildFormatTab(self, self._build) self.optTabContent = GuiBuildContentTab(self, self._build) - self.buildTabHTML = GuiBuildHTMLTab(self, self._build) - self.buildTabMarkdown = GuiBuildMarkdownTab(self, self._build) - self.buildTabODT = GuiBuildODTTab(self, self._build) + self.optTabOutput = GuiBuildOutputTab(self, self._build) # Add Tabs self.toolStack = QStackedWidget(self) @@ -130,9 +120,7 @@ class GuiBuildSettings(QDialog): self.toolStack.addWidget(self.optTabHeadings) self.toolStack.addWidget(self.optTabFormat) self.toolStack.addWidget(self.optTabContent) - self.toolStack.addWidget(self.buildTabHTML) - self.toolStack.addWidget(self.buildTabMarkdown) - self.toolStack.addWidget(self.buildTabODT) + self.toolStack.addWidget(self.optTabOutput) # Main Settings + Buttons # ======================= @@ -195,12 +183,8 @@ class GuiBuildSettings(QDialog): self.toolStack.setCurrentWidget(self.optTabFormat) elif pageId == self.OPT_CONTENT: self.toolStack.setCurrentWidget(self.optTabContent) - elif pageId == self.BLD_HTML: - self.toolStack.setCurrentWidget(self.buildTabHTML) - elif pageId == self.BLD_MARKDOWN: - self.toolStack.setCurrentWidget(self.buildTabMarkdown) - elif pageId == self.BLD_ODT: - self.toolStack.setCurrentWidget(self.buildTabODT) + elif pageId == self.OPT_OUTPUT: + self.toolStack.setCurrentWidget(self.optTabOutput) return @pyqtSlot("QAbstractButton*") @@ -212,6 +196,7 @@ class GuiBuildSettings(QDialog): self._build.setName(self.editBuildName.text()) self.newSettingsReady.emit(self._build.pack()) + self._saveSettings() if role == QDialogButtonBox.AcceptRole: self.accept() elif role == QDialogButtonBox.RejectRole: @@ -849,7 +834,7 @@ class GuiBuildContentTab(QWidget): # END Class GuiBuildContentTab -class GuiBuildHTMLTab(QWidget): +class GuiBuildOutputTab(QWidget): def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings): super().__init__(parent=buildMain) @@ -858,31 +843,7 @@ class GuiBuildHTMLTab(QWidget): return -# END Class GuiBuildHTMLTab - - -class GuiBuildMarkdownTab(QWidget): - - def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings): - super().__init__(parent=buildMain) - - self._build = build - - return - -# END Class GuiBuildMarkdownTab - - -class GuiBuildODTTab(QWidget): - - def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings): - super().__init__(parent=buildMain) - - self._build = build - - return - -# END Class GuiBuildODTTab +# END Class GuiBuildOutputTab class GuiHeadingSyntax(QSyntaxHighlighter):