diff --git a/novelwriter/assets/icons/typicons_dark/icons.conf b/novelwriter/assets/icons/typicons_dark/icons.conf index 2e62c460..8e354654 100644 --- a/novelwriter/assets/icons/typicons_dark/icons.conf +++ b/novelwriter/assets/icons/typicons_dark/icons.conf @@ -21,7 +21,7 @@ backward = typ_chevron-left.svg bookmark = typ_bookmark.svg browse = typ_folder-open.svg build_excluded = typ_cancel.svg -build_filtered = typ_filter.svg +build_filtered = typ_arrow-forward.svg build_included = typ_pin.svg bullet-off = typ_media-record-outline.svg bullet-on = typ_media-record.svg diff --git a/novelwriter/assets/icons/typicons_dark/typ_arrow-forward.svg b/novelwriter/assets/icons/typicons_dark/typ_arrow-forward.svg new file mode 100644 index 00000000..e235e9c2 --- /dev/null +++ b/novelwriter/assets/icons/typicons_dark/typ_arrow-forward.svg @@ -0,0 +1,4 @@ + + + + diff --git a/novelwriter/assets/icons/typicons_dark/typ_filter.svg b/novelwriter/assets/icons/typicons_dark/typ_filter.svg deleted file mode 100644 index fd3f3afc..00000000 --- a/novelwriter/assets/icons/typicons_dark/typ_filter.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/novelwriter/assets/icons/typicons_light/icons.conf b/novelwriter/assets/icons/typicons_light/icons.conf index df1d40ee..a52469ea 100644 --- a/novelwriter/assets/icons/typicons_light/icons.conf +++ b/novelwriter/assets/icons/typicons_light/icons.conf @@ -21,7 +21,7 @@ backward = typ_chevron-left.svg bookmark = typ_bookmark.svg browse = typ_folder-open.svg build_excluded = typ_cancel.svg -build_filtered = typ_filter.svg +build_filtered = typ_arrow-forward.svg build_included = typ_pin.svg bullet-off = typ_media-record-outline.svg bullet-on = typ_media-record.svg diff --git a/novelwriter/assets/icons/typicons_light/typ_arrow-forward.svg b/novelwriter/assets/icons/typicons_light/typ_arrow-forward.svg new file mode 100644 index 00000000..9d488e06 --- /dev/null +++ b/novelwriter/assets/icons/typicons_light/typ_arrow-forward.svg @@ -0,0 +1,4 @@ + + + + diff --git a/novelwriter/assets/icons/typicons_light/typ_filter.svg b/novelwriter/assets/icons/typicons_light/typ_filter.svg deleted file mode 100644 index 40000608..00000000 --- a/novelwriter/assets/icons/typicons_light/typ_filter.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/novelwriter/constants.py b/novelwriter/constants.py index 05242c36..5a306a73 100644 --- a/novelwriter/constants.py +++ b/novelwriter/constants.py @@ -257,6 +257,7 @@ class nwLabels: class nwHeadFmt: + BR = "{BR}" TITLE = "{Title}" CH_NUM = "{Chapter}" CH_WORD = "{Chapter:Word}" diff --git a/novelwriter/core/buildsettings.py b/novelwriter/core/buildsettings.py index a5c5cd56..ff869351 100644 --- a/novelwriter/core/buildsettings.py +++ b/novelwriter/core/buildsettings.py @@ -84,7 +84,7 @@ SETTINGS_TEMPLATE = { } SETTINGS_LABELS = { - "filter": QT_TRANSLATE_NOOP("Builds", "Document Types"), + "filter": QT_TRANSLATE_NOOP("Builds", "Document Filters"), "filter.includeNovel": QT_TRANSLATE_NOOP("Builds", "Novel Documents"), "filter.includeNotes": QT_TRANSLATE_NOOP("Builds", "Project Notes"), "filter.includeInactive": QT_TRANSLATE_NOOP("Builds", "Inactive Documents"), @@ -125,10 +125,10 @@ SETTINGS_LABELS = { "format.leftMargin": QT_TRANSLATE_NOOP("Builds", "Left Margin"), "format.rightMargin": QT_TRANSLATE_NOOP("Builds", "Right Margin"), - "odt": QT_TRANSLATE_NOOP("Builds", "Open Document"), + "odt": QT_TRANSLATE_NOOP("Builds", "Open Document (.odt)"), "odt.addColours": QT_TRANSLATE_NOOP("Builds", "Add Highlight Colours"), - "html": QT_TRANSLATE_NOOP("Builds", "HTML"), + "html": QT_TRANSLATE_NOOP("Builds", "HTML (.html)"), "html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"), } diff --git a/novelwriter/core/tohtml.py b/novelwriter/core/tohtml.py index 6c0fa4aa..20c01701 100644 --- a/novelwriter/core/tohtml.py +++ b/novelwriter/core/tohtml.py @@ -31,7 +31,7 @@ from pathlib import Path from novelwriter import CONFIG from novelwriter.common import formatTimeStamp -from novelwriter.constants import nwKeyWords, nwLabels, nwHtmlUnicode +from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwHtmlUnicode from novelwriter.core.project import NWProject from novelwriter.core.tokenizer import Tokenizer, stripEscape @@ -244,27 +244,27 @@ class ToHtml(Tokenizer): parStyle = None elif tType == self.T_TITLE: - tHead = tText.replace(r"\\", "
") + tHead = tText.replace(nwHeadFmt.BR, "
") tmpResult.append(f"

{aNm}{tHead}

\n") elif tType == self.T_UNNUM: - tHead = tText.replace(r"\\", "
") + tHead = tText.replace(nwHeadFmt.BR, "
") tmpResult.append(f"<{h2}{hStyle}>{aNm}{tHead}\n") elif tType == self.T_HEAD1: - tHead = tText.replace(r"\\", "
") + tHead = tText.replace(nwHeadFmt.BR, "
") tmpResult.append(f"<{h1}{h1Cl}{hStyle}>{aNm}{tHead}\n") elif tType == self.T_HEAD2: - tHead = tText.replace(r"\\", "
") + tHead = tText.replace(nwHeadFmt.BR, "
") tmpResult.append(f"<{h2}{hStyle}>{aNm}{tHead}\n") elif tType == self.T_HEAD3: - tHead = tText.replace(r"\\", "
") + tHead = tText.replace(nwHeadFmt.BR, "
") tmpResult.append(f"<{h3}{hStyle}>{aNm}{tHead}\n") elif tType == self.T_HEAD4: - tHead = tText.replace(r"\\", "
") + tHead = tText.replace(nwHeadFmt.BR, "
") tmpResult.append(f"<{h4}{hStyle}>{aNm}{tHead}\n") elif tType == self.T_SEP: diff --git a/novelwriter/core/tomd.py b/novelwriter/core/tomd.py index 1702bc6d..e634de74 100644 --- a/novelwriter/core/tomd.py +++ b/novelwriter/core/tomd.py @@ -27,7 +27,7 @@ import logging from pathlib import Path -from novelwriter.constants import nwLabels +from novelwriter.constants import nwHeadFmt, nwLabels from novelwriter.core.project import NWProject from novelwriter.core.tokenizer import Tokenizer @@ -122,27 +122,27 @@ class ToMarkdown(Tokenizer): thisPar = [] elif tType == self.T_TITLE: - tHead = tText.replace(r"\\", "\n") + tHead = tText.replace(nwHeadFmt.BR, "\n") tmpResult.append(f"# {tHead}\n\n") elif tType == self.T_UNNUM: - tHead = tText.replace(r"\\", "\n") + tHead = tText.replace(nwHeadFmt.BR, "\n") tmpResult.append(f"## {tHead}\n\n") elif tType == self.T_HEAD1: - tHead = tText.replace(r"\\", "\n") + tHead = tText.replace(nwHeadFmt.BR, "\n") tmpResult.append(f"# {tHead}\n\n") elif tType == self.T_HEAD2: - tHead = tText.replace(r"\\", "\n") + tHead = tText.replace(nwHeadFmt.BR, "\n") tmpResult.append(f"## {tHead}\n\n") elif tType == self.T_HEAD3: - tHead = tText.replace(r"\\", "\n") + tHead = tText.replace(nwHeadFmt.BR, "\n") tmpResult.append(f"### {tHead}\n\n") elif tType == self.T_HEAD4: - tHead = tText.replace(r"\\", "\n") + tHead = tText.replace(nwHeadFmt.BR, "\n") tmpResult.append(f"#### {tHead}\n\n") elif tType == self.T_SEP: diff --git a/novelwriter/core/toodt.py b/novelwriter/core/toodt.py index 87392e52..93b8afac 100644 --- a/novelwriter/core/toodt.py +++ b/novelwriter/core/toodt.py @@ -36,7 +36,7 @@ from datetime import datetime from novelwriter import __version__ from novelwriter.common import xmlIndent -from novelwriter.constants import nwKeyWords, nwLabels +from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels from novelwriter.core.project import NWProject from novelwriter.core.tokenizer import Tokenizer, stripEscape @@ -445,27 +445,27 @@ class ToOdt(Tokenizer): parStyle = None elif tType == self.T_TITLE: - tHead = tText.replace(r"\\", "\n") + tHead = tText.replace(nwHeadFmt.BR, "\n") self._addTextPar("Title", oStyle, tHead, isHead=False) # Title must be text:p elif tType == self.T_UNNUM: - tHead = tText.replace(r"\\", "\n") + tHead = tText.replace(nwHeadFmt.BR, "\n") self._addTextPar("Heading_20_2", oStyle, tHead, isHead=True, oLevel="2") elif tType == self.T_HEAD1: - tHead = tText.replace(r"\\", "\n") + tHead = tText.replace(nwHeadFmt.BR, "\n") self._addTextPar("Heading_20_1", oStyle, tHead, isHead=True, oLevel="1") elif tType == self.T_HEAD2: - tHead = tText.replace(r"\\", "\n") + tHead = tText.replace(nwHeadFmt.BR, "\n") self._addTextPar("Heading_20_2", oStyle, tHead, isHead=True, oLevel="2") elif tType == self.T_HEAD3: - tHead = tText.replace(r"\\", "\n") + tHead = tText.replace(nwHeadFmt.BR, "\n") self._addTextPar("Heading_20_3", oStyle, tHead, isHead=True, oLevel="3") elif tType == self.T_HEAD4: - tHead = tText.replace(r"\\", "\n") + tHead = tText.replace(nwHeadFmt.BR, "\n") self._addTextPar("Heading_20_4", oStyle, tHead, isHead=True, oLevel="4") elif tType == self.T_SEP: diff --git a/novelwriter/extensions/pagedsidebar.py b/novelwriter/extensions/pagedsidebar.py index 7afd727f..6da97974 100644 --- a/novelwriter/extensions/pagedsidebar.py +++ b/novelwriter/extensions/pagedsidebar.py @@ -1,7 +1,6 @@ """ novelWriter – Custom Widget: Paged SideBar ========================================== -A custom widget for making a sidebar for flipping through pages File History: Created: 2023-02-21 [2.1b1] NPagedSideBar @@ -24,20 +23,26 @@ 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 QColor, QPainter -from PyQt5.QtCore import QRectF, Qt, pyqtSignal, pyqtSlot +from PyQt5.QtGui import QColor, QPaintEvent, QPainter, QPolygon +from PyQt5.QtCore import QPoint, QRectF, Qt, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import ( - QButtonGroup, QLabel, QSizePolicy, QStyle, QStyleOptionToolButton, QToolBar, - QToolButton, QWidget + QAbstractButton, QAction, QButtonGroup, QLabel, QSizePolicy, QStyle, + QStyleOptionToolButton, QToolBar, QToolButton, QWidget ) class NPagedSideBar(QToolBar): + """Extensions: Paged Side Bar + + A side bar widget that holds buttons that mimic tabs. It is designed + to be used in combination with a QStackedWidget for options panels. + """ buttonClicked = pyqtSignal(int) - def __init__(self, parent): + def __init__(self, parent: QWidget) -> None: super().__init__(parent=parent) self._buttons = [] @@ -58,7 +63,7 @@ class NPagedSideBar(QToolBar): return - def setLabelColor(self, color): + def setLabelColor(self, color: list | QColor) -> None: """Set the text color for the labels.""" if isinstance(color, list): self._labelCol = QColor(*color) @@ -66,7 +71,7 @@ class NPagedSideBar(QToolBar): self._labelCol = color return - def addSeparator(self): + def addSeparator(self) -> None: """Add a spacer widget.""" spacer = QWidget(self) spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) @@ -74,16 +79,16 @@ class NPagedSideBar(QToolBar): self.insertWidget(self._stretchAction, spacer) return - def addLabel(self, text): + def addLabel(self, text: str) -> None: """Add a new label to the toolbar.""" - label = NPagedToolLabel(self, self._labelCol) + label = _NPagedToolLabel(self, self._labelCol) label.setText(text) self.insertWidget(self._stretchAction, label) return - def addButton(self, text, buttonId=-1): + def addButton(self, text: str, buttonId: int = -1) -> QAction: """Add a new button to the toolbar.""" - button = NPagedToolButton(self) + button = _NPagedToolButton(self) button.setText(text) action = self.insertWidget(self._stretchAction, button) @@ -94,7 +99,7 @@ class NPagedSideBar(QToolBar): return action - def setSelected(self, buttonId): + def setSelected(self, buttonId: int) -> None: """Set the selected button.""" self._group.button(buttonId).setChecked(True) return @@ -104,7 +109,7 @@ class NPagedSideBar(QToolBar): ## @pyqtSlot("QAbstractButton*") - def _buttonClicked(self, button): + def _buttonClicked(self, button: QAbstractButton) -> None: """A button was clicked in the group, emit its id.""" buttonId = self._group.id(button) if buttonId != -1: @@ -114,11 +119,11 @@ class NPagedSideBar(QToolBar): # END Class NPagedSideBar -class NPagedToolButton(QToolButton): +class _NPagedToolButton(QToolButton): - __slots__ = ("_bH", "_tM", "_lM", "_cR") + __slots__ = ("_bH", "_tM", "_lM", "_cR", "_aH") - def __init__(self, parent): + def __init__(self, parent: QWidget) -> None: super().__init__(parent=parent) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) @@ -126,14 +131,15 @@ class NPagedToolButton(QToolButton): fH = self.fontMetrics().height() self._bH = round(fH * 1.7) - self._tM = (self._bH - fH) // 2 - self._lM = self.style().pixelMetric(QStyle.PM_ButtonMargin) - self._cR = self._lM // 2 + self._tM = (self._bH - fH)//2 + self._lM = 3*self.style().pixelMetric(QStyle.PM_ButtonMargin)//2 + self._cR = self._lM//2 + self._aH = 2*fH//7 self.setFixedHeight(self._bH) return - def paintEvent(self, event): + def paintEvent(self, event: QPaintEvent) -> None: """Overload the paint event to draw a simple, left aligned text label, with a highlight when selected and a transparent base colour when hovered. @@ -144,6 +150,7 @@ class NPagedToolButton(QToolButton): paint = QPainter(self) paint.setRenderHint(QPainter.Antialiasing, True) paint.setPen(Qt.NoPen) + paint.setBrush(Qt.NoBrush) width = self.width() height = self.height() @@ -171,31 +178,41 @@ class NPagedToolButton(QToolButton): paint.setOpacity(1.0) paint.drawText(QRectF(self._lM, self._tM, tW, tH), Qt.AlignLeft, self.text()) + tC = self.height()//2 + tW = self.width() - self._aH - self._lM + if self.isChecked(): + paint.setBrush(textCol) + paint.drawPolygon(QPolygon([ + QPoint(tW, tC - self._aH), + QPoint(tW + self._aH, tC), + QPoint(tW, tC + self._aH), + ])) + return -# END Class NPagedToolButton +# END Class _NPagedToolButton -class NPagedToolLabel(QLabel): +class _NPagedToolLabel(QLabel): __slots__ = ("_bH", "_tM", "_lM", "_textCol") - def __init__(self, parent, textColor=None): + def __init__(self, parent: QWidget, textColor: QColor | None = None) -> None: super().__init__(parent=parent) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) fH = self.fontMetrics().height() self._bH = round(fH * 1.7) - self._tM = (self._bH - fH) // 2 - self._lM = self.style().pixelMetric(QStyle.PM_ButtonMargin) + self._tM = (self._bH - fH)//2 + self._lM = self.style().pixelMetric(QStyle.PM_ButtonMargin)//2 self.setFixedHeight(self._bH) self._textCol = textColor or self.palette().text().color() return - def paintEvent(self, event): + def paintEvent(self, event: QPaintEvent) -> None: """Overload the paint event to draw a simple, left aligned text label that matches the button style. """ @@ -215,4 +232,4 @@ class NPagedToolLabel(QLabel): return -# END Class NPagedToolLabel +# END Class _NPagedToolLabel diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py index ab29d4aa..d77797f8 100644 --- a/novelwriter/gui/projtree.py +++ b/novelwriter/gui/projtree.py @@ -1202,6 +1202,7 @@ class GuiProjectTree(QTreeWidget): open a context menu in-place. """ tItem = None + tHandle = None hasChild = False selItem = self.itemAt(clickPos) if isinstance(selItem, QTreeWidgetItem): @@ -1209,7 +1210,7 @@ class GuiProjectTree(QTreeWidget): tItem = self.theProject.tree[tHandle] hasChild = selItem.childCount() > 0 - if tItem is None: + if tItem is None or tHandle is None: logger.debug("No item found") return False diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py index e5ffa5b0..8292ceb3 100644 --- a/novelwriter/tools/manuscript.py +++ b/novelwriter/tools/manuscript.py @@ -30,7 +30,7 @@ from time import time from typing import TYPE_CHECKING from datetime import datetime -from PyQt5.QtGui import QColor, QCursor, QFont, QPalette, QResizeEvent +from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent from PyQt5.QtCore import QSize, QTimer, Qt, pyqtSlot from PyQt5.QtWidgets import ( QDialog, QGridLayout, QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPushButton, @@ -231,13 +231,13 @@ class GuiManuscript(QDialog): # Events ## - def closeEvent(self, event): + def closeEvent(self, event: QCloseEvent): """Capture the user closing the window so we can save GUI settings. We also check that we don't have a build settings dialog open. """ self._saveSettings() - for obj in self.children(): + for obj in self.mainGui.children(): # Make sure we don't have any settings windows open if isinstance(obj, GuiBuildSettings) and obj.isVisible(): obj.close() @@ -330,15 +330,13 @@ class GuiManuscript(QDialog): def _buildManuscript(self): """Open the build dialog and build the manuscript.""" build = self._getSelectedBuild() - if build is None: - return + if isinstance(build, BuildSettings): + dlgBuild = GuiManuscriptBuild(self, self.mainGui, build) + dlgBuild.exec_() - dlgBuild = GuiManuscriptBuild(self, self.mainGui, build) - dlgBuild.exec_() - - # After the build is done, save build settings changes - if build.changed: - self._builds.setBuild(build) + # After the build is done, save build settings changes + if build.changed: + self._builds.setBuild(build) return @@ -376,10 +374,13 @@ class GuiManuscript(QDialog): return def _getSelectedBuild(self) -> BuildSettings | None: - """Get the currently selected build.""" - bItems = self.buildList.selectedItems() - if bItems: - build = self._builds.getBuild(bItems[0].data(self.D_KEY)) + """Get the currently selected build. If none are selected, + automatically select the first one. + """ + items = self.buildList.selectedItems() + item = items[0] if items else self.buildList.item(0) + if item: + build = self._builds.getBuild(item.data(self.D_KEY)) if isinstance(build, BuildSettings): return build return None @@ -406,13 +407,23 @@ class GuiManuscript(QDialog): def _openSettingsDialog(self, build: BuildSettings): """Open the build settings dialog.""" - dlgSettings = GuiBuildSettings(self, self.mainGui, build) + for obj in self.mainGui.children(): + # Don't open a second dialog if one exists + if isinstance(obj, GuiBuildSettings): + if obj.buildID == build.buildID: + logger.debug("Found instance of GuiBuildSettings") + obj.show() + obj.raise_() + return + + dlgSettings = GuiBuildSettings(self.mainGui, build) dlgSettings.setModal(False) dlgSettings.show() dlgSettings.raise_() qApp.processEvents() dlgSettings.loadContent() dlgSettings.newSettingsReady.connect(self._processNewSettings) + return def _updateBuildsList(self): @@ -634,7 +645,7 @@ class _PreviewWidget(QTextBrowser): ) else: strBuildTime = self.tr("Unknown") - text = "{0} {1}".format(self.tr("Built"), strBuildTime) + text = "{0}: {1}".format(self.tr("Built"), strBuildTime) if self._buildName: text = "{0}
{1}".format(self._buildName, text) self.ageLabel.setText(text) diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index d2666e42..a3f22d2f 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -69,8 +69,8 @@ class GuiBuildSettings(QDialog): newSettingsReady = pyqtSignal(BuildSettings) - def __init__(self, parent: QWidget, mainGui: GuiMain, build: BuildSettings): - super().__init__(parent=parent) + def __init__(self, mainGui: GuiMain, build: BuildSettings) -> None: + super().__init__(parent=mainGui) logger.debug("Create: GuiBuildSettings") self.setObjectName("GuiBuildSettings") @@ -106,7 +106,7 @@ class GuiBuildSettings(QDialog): self.optSideBar.setLabelColor(self.mainTheme.helpText) self.optSideBar.addLabel(self.tr("Options")) - self.optSideBar.addButton(self.tr("Filters"), self.OPT_FILTERS) + self.optSideBar.addButton(self.tr("Selection"), self.OPT_FILTERS) self.optSideBar.addButton(self.tr("Headings"), self.OPT_HEADINGS) self.optSideBar.addButton(self.tr("Content"), self.OPT_CONTENT) self.optSideBar.addButton(self.tr("Format"), self.OPT_FORMAT) @@ -169,10 +169,11 @@ class GuiBuildSettings(QDialog): return - def __del__(self): # pragma: no cover + def __del__(self) -> None: # pragma: no cover logger.debug("Delete: GuiBuildSettings") + return - def loadContent(self): + def loadContent(self) -> None: """Populate the child widgets.""" self.editBuildName.setText(self._build.name) self.optTabSelect.loadContent() @@ -182,12 +183,21 @@ class GuiBuildSettings(QDialog): self.optTabOutput.loadContent() return + ## + # Properties + ## + + @property + def buildID(self) -> str: + """The build ID of the build of the dialog.""" + return self._build.buildID + ## # Private Slots ## @pyqtSlot(int) - def _stackPageSelected(self, pageId: int): + def _stackPageSelected(self, pageId: int) -> None: """Process a user request to switch page.""" if pageId == self.OPT_FILTERS: self.toolStack.setCurrentWidget(self.optTabSelect) @@ -202,7 +212,7 @@ class GuiBuildSettings(QDialog): return @pyqtSlot("QAbstractButton*") - def _dialogButtonClicked(self, button: QAbstractButton): + def _dialogButtonClicked(self, button: QAbstractButton) -> None: """Handle button clicks from the dialog button box.""" role = self.dlgButtons.buttonRole(button) if role == QDialogButtonBox.ApplyRole: @@ -218,7 +228,7 @@ class GuiBuildSettings(QDialog): # Events ## - def closeEvent(self, event: QEvent): + def closeEvent(self, event: QEvent) -> None: """Capture the user closing the window so we can save settings. """ @@ -233,7 +243,7 @@ class GuiBuildSettings(QDialog): # Internal Functions ## - def _askToSaveBuild(self): + def _askToSaveBuild(self) -> None: """Check if there are unsaved changes, and if there are, ask if it's ok to reject them. """ @@ -247,7 +257,7 @@ class GuiBuildSettings(QDialog): self._build.resetChangedState() return - def _saveSettings(self): + def _saveSettings(self) -> None: """Save the various user settings.""" logger.debug("Saving GuiBuildSettings settings") @@ -265,7 +275,7 @@ class GuiBuildSettings(QDialog): return - def _emitBuildData(self): + def _emitBuildData(self) -> None: """Assemble the build data and emit the signal.""" self._build.setName(self.editBuildName.text()) self.optTabHeadings.saveContent() @@ -294,23 +304,26 @@ class _FilterTab(QWidget): F_INCLUDED = 2 F_EXCLUDED = 3 - def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings): + def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None: super().__init__(parent=buildMain) self.mainGui = buildMain.mainGui self.mainTheme = buildMain.mainGui.mainTheme self.theProject = buildMain.mainGui.theProject - self._treeMap = {} + self._treeMap: dict[str, QTreeWidgetItem] = {} self._build = build - self._statusFlags = { - self.F_NONE: ("", QIcon()), - self.F_FILTERED: (self.tr("Filtered"), self.mainTheme.getIcon("build_filtered")), - self.F_INCLUDED: (self.tr("Included"), self.mainTheme.getIcon("build_included")), - self.F_EXCLUDED: (self.tr("Excluded"), self.mainTheme.getIcon("build_excluded")), + 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._trIncluded = self.tr("Included in manuscript") + self._trExcluded = self.tr("Excluded from manuscript") + # Project Tree # ============ @@ -341,27 +354,28 @@ class _FilterTab(QWidget): # Filters # ======= - self.filteredButton = QToolButton(self) - self.filteredButton.setToolTip(self._statusFlags[self.F_FILTERED][0]) - self.filteredButton.setIcon(self._statusFlags[self.F_FILTERED][1]) - self.filteredButton.clicked.connect(lambda: self._setSelectedMode(self.F_FILTERED)) - self.includedButton = QToolButton(self) - self.includedButton.setToolTip(self._statusFlags[self.F_INCLUDED][0]) - self.includedButton.setIcon(self._statusFlags[self.F_INCLUDED][1]) + self.includedButton.setToolTip(self.tr("Always included")) + self.includedButton.setIcon(self._statusFlags[self.F_INCLUDED]) self.includedButton.clicked.connect(lambda: self._setSelectedMode(self.F_INCLUDED)) self.excludedButton = QToolButton(self) - self.excludedButton.setToolTip(self._statusFlags[self.F_EXCLUDED][0]) - self.excludedButton.setIcon(self._statusFlags[self.F_EXCLUDED][1]) + self.excludedButton.setToolTip(self.tr("Always excluded")) + self.excludedButton.setIcon(self._statusFlags[self.F_EXCLUDED]) self.excludedButton.clicked.connect(lambda: self._setSelectedMode(self.F_EXCLUDED)) + self.resetButton = QToolButton(self) + self.resetButton.setToolTip(self.tr("Reset to default")) + self.resetButton.setIcon(self.mainTheme.getIcon("revert")) + self.resetButton.clicked.connect(lambda: self._setSelectedMode(self.F_FILTERED)) + self.modeBox = QHBoxLayout() self.modeBox.addWidget(QLabel(self.tr("Mark selection as"))) self.modeBox.addStretch(1) - self.modeBox.addWidget(self.filteredButton) self.modeBox.addWidget(self.includedButton) self.modeBox.addWidget(self.excludedButton) + self.modeBox.addWidget(self.resetButton) + self.modeBox.setSpacing(CONFIG.pxInt(4)) # Filer Options self.filterOpt = NSwitchBox(self, iPx) @@ -401,7 +415,7 @@ class _FilterTab(QWidget): return - def loadContent(self): + def loadContent(self) -> None: """Populate the widgets.""" self._populateTree() self._populateFilters() @@ -418,7 +432,7 @@ class _FilterTab(QWidget): ## @pyqtSlot(str, bool) - def _applyFilterSwitch(self, key: str, state: bool): + def _applyFilterSwitch(self, key: str, state: bool) -> None: """Apply filter switch and update the settings.""" if key.startswith("doc:"): self._build.setValue(key[4:], state) @@ -432,7 +446,7 @@ class _FilterTab(QWidget): # Internal Functions ## - def _populateTree(self): + def _populateTree(self) -> None: """Build the tree of project items.""" logger.debug("Building project tree") self._treeMap = {} @@ -486,7 +500,7 @@ class _FilterTab(QWidget): return - def _populateFilters(self): + def _populateFilters(self) -> None: """Populate the filter options switches.""" self.filterOpt.clear() self.filterOpt.addLabel(self._build.getLabel("filter")) @@ -512,7 +526,7 @@ class _FilterTab(QWidget): self.filterOpt.addSeparator() # Root Classes - self.filterOpt.addLabel(self.tr("Root Folders")) + 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( @@ -525,9 +539,13 @@ class _FilterTab(QWidget): return - def _setSelectedMode(self, mode: int): + def _setSelectedMode(self, mode: int) -> None: """Set the mode for the selected items.""" - for item in self.optTree.selectedItems(): + items = self.optTree.selectedItems() + if len(items) == 1 and isinstance(items[0], QTreeWidgetItem): + items = self._scanChildren(items[0], []) + + for item in items: if isinstance(item, QTreeWidgetItem): tHandle = item.data(self.C_DATA, self.D_HANDLE) isFile = item.data(self.C_DATA, self.D_FILE) @@ -543,21 +561,34 @@ class _FilterTab(QWidget): return - def _setTreeItemMode(self): + def _setTreeItemMode(self) -> None: """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)) if mode == FilterMode.INCLUDED: - item.setIcon(self.C_STATUS, self._statusFlags[self.F_INCLUDED][1]) + item.setIcon(self.C_STATUS, self._statusFlags[self.F_INCLUDED]) + item.setToolTip(self.C_STATUS, self._trIncluded) elif mode == FilterMode.EXCLUDED: - item.setIcon(self.C_STATUS, self._statusFlags[self.F_EXCLUDED][1]) + item.setIcon(self.C_STATUS, self._statusFlags[self.F_EXCLUDED]) + item.setToolTip(self.C_STATUS, self._trExcluded) elif mode == FilterMode.FILTERED and allow: - item.setIcon(self.C_STATUS, self._statusFlags[self.F_FILTERED][1]) + item.setIcon(self.C_STATUS, self._statusFlags[self.F_FILTERED]) + item.setToolTip(self.C_STATUS, self._trIncluded) else: - item.setIcon(self.C_STATUS, self._statusFlags[self.F_NONE][1]) + item.setIcon(self.C_STATUS, self._statusFlags[self.F_NONE]) return + def _scanChildren(self, item: QTreeWidgetItem | None, items: list) -> list[QTreeWidgetItem]: + """This is a recursive function returning all items in a tree + starting at a given QTreeWidgetItem. + """ + if isinstance(item, QTreeWidgetItem): + items.append(item) + for i in range(item.childCount()): + self._scanChildren(item.child(i), items) + return items + # END Class _FilterTab @@ -569,7 +600,7 @@ class _HeadingsTab(QWidget): EDIT_SCENE = 4 EDIT_SECTION = 5 - def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings): + def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None: super().__init__(parent=buildMain) self.mainGui = buildMain.mainGui @@ -747,7 +778,7 @@ class _HeadingsTab(QWidget): return - def loadContent(self): + def loadContent(self) -> None: """Populate the widgets.""" self.fmtTitle.setText(self._build.getStr("headings.fmtTitle")) self.fmtChapter.setText(self._build.getStr("headings.fmtChapter")) @@ -758,7 +789,7 @@ class _HeadingsTab(QWidget): self.swtSection.setChecked(self._build.getBool("headings.hideSection")) return - def saveContent(self): + def saveContent(self) -> None: """Save choices back into build object.""" self._build.setValue("headings.hideScene", self.swtScene.isChecked()) self._build.setValue("headings.hideSection", self.swtSection.isChecked()) @@ -768,7 +799,7 @@ class _HeadingsTab(QWidget): # Internal Functions ## - def _insertIntoForm(self, text: str): + def _insertIntoForm(self, text: str) -> None: """Insert formatting text from the dropdown menu.""" if self._editing > 0: cursor = self.editTextBox.textCursor() @@ -776,7 +807,7 @@ class _HeadingsTab(QWidget): self.editTextBox.setFocus() return - def _editHeading(self, heading: int): + def _editHeading(self, heading: int) -> None: """Populate the form with a specific heading format.""" self._editing = heading self.editTextBox.setEnabled(True) @@ -801,7 +832,7 @@ class _HeadingsTab(QWidget): text = "" label = self.tr("None") - self.editTextBox.setPlainText(text.replace("//", "\n")) + self.editTextBox.setPlainText(text.replace(nwHeadFmt.BR, "\n")) self.lblEditForm.setText(self.tr("Editing: {0}").format(label)) return @@ -810,10 +841,10 @@ class _HeadingsTab(QWidget): # Private Slots ## - def _saveFormat(self): + def _saveFormat(self) -> None: """Save the format from the edit text box.""" heading = self._editing - text = self.editTextBox.toPlainText().strip().replace("\n", "//") + text = self.editTextBox.toPlainText().strip().replace("\n", nwHeadFmt.BR) if heading == self.EDIT_TITLE: self.fmtTitle.setText(text) self._build.setValue("headings.fmtTitle", text) @@ -842,7 +873,7 @@ class _HeadingsTab(QWidget): class _HeadingSyntaxHighlighter(QSyntaxHighlighter): - def __init__(self, document: QTextDocument, mainTheme: GuiTheme): + def __init__(self, document: QTextDocument, mainTheme: GuiTheme) -> None: super().__init__(document) self._fmtSymbol = QTextCharFormat() self._fmtSymbol.setForeground(QColor(*mainTheme.colHead)) @@ -850,7 +881,7 @@ class _HeadingSyntaxHighlighter(QSyntaxHighlighter): self._fmtFormat.setForeground(QColor(*mainTheme.colEmph)) return - def highlightBlock(self, text: str): + def highlightBlock(self, text: str) -> None: """Add syntax highlighting to the text block.""" for heading in nwHeadFmt.ALL: pos = text.find(heading) @@ -868,7 +899,7 @@ class _HeadingSyntaxHighlighter(QSyntaxHighlighter): class _ContentTab(QWidget): - def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings): + def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None: super().__init__(parent=buildMain) self.mainGui = buildMain.mainGui @@ -917,7 +948,7 @@ class _ContentTab(QWidget): return - def loadContent(self): + def loadContent(self) -> None: """Populate the widgets.""" self.incSynopsis.setChecked(self._build.getBool("text.includeSynopsis")) self.incComments.setChecked(self._build.getBool("text.includeComments")) @@ -926,7 +957,7 @@ class _ContentTab(QWidget): self.addNoteHead.setChecked(self._build.getBool("text.addNoteHeadings")) return - def saveContent(self): + def saveContent(self) -> None: """Save choices back into build object.""" self._build.setValue("text.includeSynopsis", self.incSynopsis.isChecked()) self._build.setValue("text.includeComments", self.incComments.isChecked()) @@ -940,7 +971,7 @@ class _ContentTab(QWidget): class _FormatTab(QWidget): - def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings): + def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None: super().__init__(parent=buildMain) self.buildMain = buildMain @@ -1033,10 +1064,12 @@ class _FormatTab(QWidget): self.pageWidth = QDoubleSpinBox(self) self.pageWidth.setFixedWidth(dbW) self.pageWidth.setMaximum(500.0) + self.pageWidth.valueChanged.connect(self._pageSizeValueChanged) self.pageHeight = QDoubleSpinBox(self) self.pageHeight.setFixedWidth(dbW) self.pageHeight.setMaximum(500.0) + self.pageHeight.valueChanged.connect(self._pageSizeValueChanged) self.topMargin = QDoubleSpinBox(self) self.topMargin.setFixedWidth(dbW) @@ -1085,7 +1118,7 @@ class _FormatTab(QWidget): return - def loadContent(self): + def loadContent(self) -> None: """Populate the widgets.""" langIdx = self.buildLang.findData(self._build.getStr("format.buildLang")) if langIdx != -1: @@ -1128,7 +1161,7 @@ class _FormatTab(QWidget): return - def saveContent(self): + def saveContent(self) -> None: """Save choices back into build object.""" self._build.setValue("format.buildLang", str(self.buildLang.currentData())) self._build.setValue("format.textFont", self.textFont.text()) @@ -1154,7 +1187,7 @@ class _FormatTab(QWidget): ## @pyqtSlot() - def _selectFont(self): + def _selectFont(self) -> None: """Open the QFontDialog and set a font for the font style.""" currFont = QFont() currFont.setFamily(self.textFont.text()) @@ -1166,7 +1199,7 @@ class _FormatTab(QWidget): return @pyqtSlot(int) - def _changeUnit(self, index: int): + def _changeUnit(self, index: int) -> None: """The current unit change, so recalculate sizes.""" newUnit = self.pageUnit.itemData(index) newScale = nwLabels.UNIT_SCALE.get(newUnit, 1.0) @@ -1185,15 +1218,19 @@ class _FormatTab(QWidget): pMax = 500.0 if isMM else 50.0 mMax = 150.0 if isMM else 15.0 + self.pageWidth.blockSignals(True) self.pageWidth.setDecimals(nDec) self.pageWidth.setSingleStep(nStep) self.pageWidth.setMaximum(pMax) self.pageWidth.setValue(pageWidth) + self.pageWidth.blockSignals(False) + self.pageHeight.blockSignals(True) self.pageHeight.setDecimals(nDec) self.pageHeight.setSingleStep(nStep) self.pageHeight.setMaximum(pMax) self.pageHeight.setValue(pageHeight) + self.pageHeight.blockSignals(False) self.topMargin.setDecimals(nDec) self.topMargin.setSingleStep(nStep) @@ -1216,22 +1253,31 @@ class _FormatTab(QWidget): self.rightMargin.setValue(rightMargin) self._unitScale = newScale + self._changePageSize(self.pageSize.currentIndex()) return @pyqtSlot(int) - def _changePageSize(self, index: int): + def _changePageSize(self, index: int) -> None: """The page size has changed.""" - self.pageWidth.setEnabled(True) - self.pageHeight.setEnabled(True) - w, h = nwLabels.PAPER_SIZE[self.pageSize.itemData(index)] if index >= 0 else (-1.0, -1.0) if w > 0.0 and h > 0.0: - self.pageWidth.setEnabled(False) - self.pageHeight.setEnabled(False) + self.pageWidth.blockSignals(True) self.pageWidth.setValue(w/self._unitScale) + self.pageWidth.blockSignals(False) + self.pageHeight.blockSignals(True) self.pageHeight.setValue(h/self._unitScale) + self.pageHeight.blockSignals(False) + return + @pyqtSlot() + def _pageSizeValueChanged(self): + """The user has changed the page size spin boxes, so we flip + the page size box to Custom. + """ + index = self.pageSize.findData("Custom") + if index >= 0: + self.pageSize.setCurrentIndex(index) return # END Class _FormatTab @@ -1239,7 +1285,7 @@ class _FormatTab(QWidget): class _OutputTab(QWidget): - def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings): + def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None: super().__init__(parent=buildMain) self.mainGui = buildMain.mainGui @@ -1282,13 +1328,13 @@ class _OutputTab(QWidget): return - def loadContent(self): + def loadContent(self) -> None: """Populate the widgets.""" self.odtAddColours.setChecked(self._build.getBool("odt.addColours")) self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles")) return - def saveContent(self): + def saveContent(self) -> None: """Save choices back into build object.""" self._build.setValue("odt.addColours", self.odtAddColours.isChecked()) self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked()) diff --git a/tests/test_tools/test_tools_manuscript.py b/tests/test_tools/test_tools_manuscript.py index 3f2bcdb6..cb5aedb1 100644 --- a/tests/test_tools/test_tools_manuscript.py +++ b/tests/test_tools/test_tools_manuscript.py @@ -168,11 +168,12 @@ def testManuscript_Features(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath: # ======== # No build selected - manus.buildList.clearSelection() + manus.buildList.clear() manus.btnPreview.click() qtbot.wait(200) # Should be enough to run the build assert manus.docPreview.toPlainText().strip() == "" assert cacheFile.exists() is False + manus._updateBuildsList() # Preview the first, but fail to save cache manus.buildList.setCurrentRow(0) @@ -207,12 +208,6 @@ def testManuscript_Features(monkeypatch, qtbot: QtBot, nwGUI: GuiMain, projPath: with monkeypatch.context() as mp: mp.setattr("novelwriter.tools.manusbuild.GuiManuscriptBuild.exec_", lambda *a: None) - # With no selection, no dialog should be created - manus.btnBuild.click() - for obj in manus.children(): - assert not isinstance(obj, GuiManuscriptBuild) - - # With a selection, there should be one manus.buildList.setCurrentRow(0) manus.btnBuild.click() for obj in manus.children(): diff --git a/tests/test_tools/test_tools_manussettings.py b/tests/test_tools/test_tools_manussettings.py index c455b623..f84b2e3d 100644 --- a/tests/test_tools/test_tools_manussettings.py +++ b/tests/test_tools/test_tools_manussettings.py @@ -47,7 +47,7 @@ def testBuildSettings_Init(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockRnd build = BuildSettings() # Create the dialog and populate it - bSettings = GuiBuildSettings(nwGUI, nwGUI, build) + bSettings = GuiBuildSettings(nwGUI, build) bSettings.show() bSettings.loadContent() @@ -132,10 +132,10 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR hCharDoc = nwGUI.theProject.newFile("Jane Doe", C.hCharRoot) nwGUI.projView.projTree.revealNewTreeItem(hPlotDoc) nwGUI.projView.projTree.revealNewTreeItem(hCharDoc) - nwGUI.theProject.tree[hPlotDoc].setActive(False) + nwGUI.theProject.tree[hPlotDoc].setActive(False) # type: ignore # Create the dialog and populate it - bSettings = GuiBuildSettings(nwGUI, nwGUI, build) + bSettings = GuiBuildSettings(nwGUI, build) bSettings.show() bSettings.loadContent() @@ -147,7 +147,7 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR assert filterTab.optTree.topLevelItemCount() == 4 # The 4 root folders assert filterTab.filterOpt._index == 10 # 2 headers, 1 sep, 3 opt and 4 roots - # Untoggle note folders + # Un-toggle note folders filterTab.filterOpt._widgets[switchMap["worldRoot"]].setChecked(False) # World Root assert filterTab.optTree.topLevelItemCount() == 3 assert C.hWorldRoot in build._skipRoot @@ -229,8 +229,8 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR # Set char and plot docs to excluded filterTab.optTree.clearSelection() - filterTab._treeMap[hPlotDoc].setSelected(True) - filterTab._treeMap[hCharDoc].setSelected(True) + filterTab._treeMap[hPlotDoc].setSelected(True) # type: ignore + filterTab._treeMap[hCharDoc].setSelected(True) # type: ignore filterTab.excludedButton.click() assert build.buildItemFilter(nwGUI.theProject) == { C.hNovelRoot: (False, FilterMode.SKIPPED), @@ -260,13 +260,30 @@ def testBuildSettings_Filter(qtbot: QtBot, nwGUI: GuiMain, projPath: Path, mockR C.hWorldRoot: (False, FilterMode.SKIPPED), } + # Selecting only novel root should iterate through all children + filterTab.optTree.clearSelection() + filterTab._treeMap[C.hNovelRoot].setSelected(True) + filterTab.resetButton.click() + assert build.buildItemFilter(nwGUI.theProject) == { + C.hNovelRoot: (False, FilterMode.SKIPPED), + C.hTitlePage: (True, FilterMode.FILTERED), + C.hChapterDir: (False, FilterMode.SKIPPED), + C.hChapterDoc: (True, FilterMode.FILTERED), + C.hSceneDoc: (True, FilterMode.FILTERED), + C.hPlotRoot: (False, FilterMode.SKIPPED), + hPlotDoc: (False, FilterMode.EXCLUDED), + C.hCharRoot: (False, FilterMode.SKIPPED), + hCharDoc: (False, FilterMode.EXCLUDED), + C.hWorldRoot: (False, FilterMode.SKIPPED), + } + # Set everything back to filtered filterTab.optTree.clearSelection() - filterTab._treeMap[C.hChapterDoc].setSelected(True) + filterTab._treeMap[C.hNovelRoot].setSelected(True) filterTab._treeMap[C.hSceneDoc].setSelected(True) - filterTab._treeMap[hPlotDoc].setSelected(True) - filterTab._treeMap[hCharDoc].setSelected(True) - filterTab.filteredButton.click() + filterTab._treeMap[hPlotDoc].setSelected(True) # type: ignore + filterTab._treeMap[hCharDoc].setSelected(True) # type: ignore + filterTab.resetButton.click() assert build.buildItemFilter(nwGUI.theProject) == { C.hNovelRoot: (False, FilterMode.SKIPPED), C.hTitlePage: (True, FilterMode.FILTERED), @@ -285,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) # Char doc has no root handle - nwGUI.theProject.tree[hPlotDoc].setParent(None) # Plot doc has no parent handle + nwGUI.theProject.tree[hCharDoc].setRoot(None) # type: ignore + nwGUI.theProject.tree[hPlotDoc].setParent(None) # type: ignore filterTab._populateTree() assert list(filterTab._treeMap.keys()) == [ C.hNovelRoot, C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc, @@ -320,7 +337,7 @@ def testBuildSettings_Headings(qtbot: QtBot, nwGUI: GuiMain): build.setValue("headings.hideSection", False) # Create the dialog and populate it - bSettings = GuiBuildSettings(nwGUI, nwGUI, build) + bSettings = GuiBuildSettings(nwGUI, build) bSettings.show() bSettings.loadContent() @@ -412,7 +429,9 @@ def testBuildSettings_Headings(qtbot: QtBot, nwGUI: GuiMain): headTab.btnChapter.click() headTab.editTextBox.setPlainText(f"Chapter {nwHeadFmt.CH_NUM}\n{nwHeadFmt.TITLE}\n") headTab.btnApply.click() - assert build.getStr("headings.fmtChapter") == f"Chapter {nwHeadFmt.CH_NUM}//{nwHeadFmt.TITLE}" + assert build.getStr("headings.fmtChapter") == ( + f"Chapter {nwHeadFmt.CH_NUM}{nwHeadFmt.BR}{nwHeadFmt.TITLE}" + ) # Set all to plain title headTab.btnTitle.click() @@ -467,7 +486,7 @@ def testBuildSettings_Content(qtbot: QtBot, nwGUI: GuiMain): build.setValue("text.addNoteHeadings", False) # Create the dialog and populate it - bSettings = GuiBuildSettings(nwGUI, nwGUI, build) + bSettings = GuiBuildSettings(nwGUI, build) bSettings.show() bSettings.loadContent() @@ -534,7 +553,7 @@ def testBuildSettings_Format(monkeypatch, qtbot: QtBot, nwGUI: GuiMain): build.setValue("format.rightMargin", 15.0) # Create the dialog and populate it - bSettings = GuiBuildSettings(nwGUI, nwGUI, build) + bSettings = GuiBuildSettings(nwGUI, build) bSettings.show() bSettings.loadContent() @@ -622,7 +641,7 @@ def testBuildSettings_Output(qtbot: QtBot, nwGUI: GuiMain): build.setValue("html.addStyles", False) # Create the dialog and populate it - bSettings = GuiBuildSettings(nwGUI, nwGUI, build) + bSettings = GuiBuildSettings(nwGUI, build) bSettings.show() bSettings.loadContent()