diff --git a/novelwriter/core/buildsettings.py b/novelwriter/core/buildsettings.py index 3ceee536..f5173bee 100644 --- a/novelwriter/core/buildsettings.py +++ b/novelwriter/core/buildsettings.py @@ -121,13 +121,11 @@ SETTINGS_LABELS = { "text.includeKeywords": QT_TRANSLATE_NOOP("Builds", "Include Keywords"), "text.includeBodyText": QT_TRANSLATE_NOOP("Builds", "Include Body Text"), "text.ignoredKeywords": QT_TRANSLATE_NOOP("Builds", "Ignore These Keywords"), - "text.grpInsert": QT_TRANSLATE_NOOP("Builds", "Insert Content"), "text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"), "format.grpFormat": QT_TRANSLATE_NOOP("Builds", "Text Format"), "format.textFont": QT_TRANSLATE_NOOP("Builds", "Text Font"), "format.lineHeight": QT_TRANSLATE_NOOP("Builds", "Line Height"), - "format.grpOptions": QT_TRANSLATE_NOOP("Builds", "Text Options"), "format.justifyText": QT_TRANSLATE_NOOP("Builds", "Justify Text Margins"), "format.stripUnicode": QT_TRANSLATE_NOOP("Builds", "Replace Unicode Characters"), "format.replaceTabs": QT_TRANSLATE_NOOP("Builds", "Replace Tabs with Spaces"), @@ -149,12 +147,12 @@ 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)"), + "odt": QT_TRANSLATE_NOOP("Builds", "ODT Documents"), "odt.addColours": QT_TRANSLATE_NOOP("Builds", "Add Highlight Colours"), "odt.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"), "odt.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"), - "html": QT_TRANSLATE_NOOP("Builds", "HTML (.html)"), + "html": QT_TRANSLATE_NOOP("Builds", "HTML Document"), "html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"), "html.preserveTabs": QT_TRANSLATE_NOOP("Builds", "Preserve Tab Characters"), } diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 56b42ec7..a29fe34b 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -1095,6 +1095,12 @@ class GuiDocEditor(QPlainTextEdit): self._completer.hide() return + @pyqtSlot() + def _openContextFromCursor(self) -> None: + """Open the spell check context menu at the cursor.""" + self._openContextMenu(self.cursorRect().center()) + return + @pyqtSlot("QPoint") def _openContextMenu(self, pos: QPoint) -> None: """Open the editor context menu at a given coordinate.""" @@ -1938,11 +1944,6 @@ class GuiDocEditor(QPlainTextEdit): self.requestProjectItemRenamed.emit(self._docHandle, text) return - def _openContextFromCursor(self) -> None: - """Open the spell check context menu at the cursor.""" - self._openContextMenu(self.cursorRect().center()) - return - def _docAutoReplace(self, text: str) -> None: """Auto-replace text elements based on main configuration.""" cursor = self.textCursor() diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py index a19e0945..d0b95451 100644 --- a/novelwriter/gui/dochighlight.py +++ b/novelwriter/gui/dochighlight.py @@ -491,7 +491,7 @@ class TextBlockData(QTextBlockUserData): self._spellErrors = [] checker = SHARED.spelling - for match in RX_WORDS.finditer(text.replace("_", " ")): + for match in RX_WORDS.finditer(text.replace("_", " "), offset): if ( (word := match.group(0)) and not (word.isnumeric() or word.isupper() or checker.checkWord(word)) diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py index 8964dcf4..15b6d918 100644 --- a/novelwriter/tools/manussettings.py +++ b/novelwriter/tools/manussettings.py @@ -67,11 +67,9 @@ class GuiBuildSettings(NToolDialog): editing JSON build definitions, wrapped as a BuildSettings object. """ - OPT_FILTERS = 1 - OPT_HEADINGS = 2 - OPT_CONTENT = 3 - OPT_FORMAT = 4 - OPT_OUTPUT = 5 + OPT_FILTERS = 1 + OPT_HEADINGS = 2 + OPT_FORMATTING = 10 newSettingsReady = pyqtSignal(BuildSettings) @@ -86,7 +84,6 @@ class GuiBuildSettings(NToolDialog): self.setWindowTitle(self.tr("Manuscript Build Settings")) self.setMinimumSize(CONFIG.pxInt(700), CONFIG.pxInt(400)) - mPx = CONFIG.pxInt(150) wWin = CONFIG.pxInt(750) hWin = CONFIG.pxInt(550) @@ -108,31 +105,24 @@ class GuiBuildSettings(NToolDialog): # SideBar self.sidebar = NPagedSideBar(self) - self.sidebar.setMinimumWidth(mPx) - self.sidebar.setMaximumWidth(mPx) self.sidebar.setLabelColor(SHARED.theme.helpText) + self.sidebar.addLabel(self.tr("General")) self.sidebar.addButton(self.tr("Selection"), self.OPT_FILTERS) self.sidebar.addButton(self.tr("Headings"), self.OPT_HEADINGS) - self.sidebar.addButton(self.tr("Content"), self.OPT_CONTENT) - self.sidebar.addButton(self.tr("Format"), self.OPT_FORMAT) - self.sidebar.addButton(self.tr("Output"), self.OPT_OUTPUT) + self.sidebar.addLabel(self.tr("Formatting")) self.sidebar.buttonClicked.connect(self._stackPageSelected) # Content self.optTabSelect = _FilterTab(self, self._build) self.optTabHeadings = _HeadingsTab(self, self._build) - self.optTabContent = _ContentTab(self, self._build) - self.optTabFormat = _FormatTab(self, self._build) - self.optTabOutput = _OutputTab(self, self._build) + self.optTabFormatting = _FormattingTab(self, self._build, self.sidebar) self.toolStack = QStackedWidget(self) self.toolStack.addWidget(self.optTabSelect) self.toolStack.addWidget(self.optTabHeadings) - self.toolStack.addWidget(self.optTabFormat) - self.toolStack.addWidget(self.optTabContent) - self.toolStack.addWidget(self.optTabOutput) + self.toolStack.addWidget(self.optTabFormatting) # Buttons self.buttonBox = QDialogButtonBox(QtDialogApply | QtDialogSave | QtDialogClose, self) @@ -174,9 +164,7 @@ class GuiBuildSettings(NToolDialog): self.editBuildName.setText(self._build.name) self.optTabSelect.loadContent() self.optTabHeadings.loadContent() - self.optTabContent.loadContent() - self.optTabFormat.loadContent() - self.optTabOutput.loadContent() + self.optTabFormatting.loadContent() return ## @@ -214,12 +202,9 @@ class GuiBuildSettings(NToolDialog): self.toolStack.setCurrentWidget(self.optTabSelect) elif pageId == self.OPT_HEADINGS: self.toolStack.setCurrentWidget(self.optTabHeadings) - elif pageId == self.OPT_CONTENT: - self.toolStack.setCurrentWidget(self.optTabContent) - elif pageId == self.OPT_FORMAT: - self.toolStack.setCurrentWidget(self.optTabFormat) - elif pageId == self.OPT_OUTPUT: - self.toolStack.setCurrentWidget(self.optTabOutput) + elif pageId >= self.OPT_FORMATTING: + self.toolStack.setCurrentWidget(self.optTabFormatting) + self.optTabFormatting.scrollToSection(pageId) return @pyqtSlot("QAbstractButton*") @@ -272,9 +257,7 @@ class GuiBuildSettings(NToolDialog): """Assemble the build data and emit the signal.""" self._build.setName(self.editBuildName.text()) self.optTabHeadings.saveContent() - self.optTabContent.saveContent() - self.optTabFormat.saveContent() - self.optTabOutput.saveContent() + self.optTabFormatting.saveContent() self.newSettingsReady.emit(self._build) self._build.resetChangedState() return @@ -963,22 +946,48 @@ class _HeadingSyntaxHighlighter(QSyntaxHighlighter): return -class _ContentTab(NScrollableForm): +class _FormattingTab(NScrollableForm): - def __init__(self, parent: QWidget, build: BuildSettings) -> None: + def __init__(self, parent: QWidget, build: BuildSettings, sidebar: NPagedSideBar) -> None: super().__init__(parent=parent) self._build = build + self._sidebar = sidebar + + self.setHelpTextStyle(SHARED.theme.helpText) + self.buildForm() + + return + + def buildForm(self) -> None: + """Build the formatting form.""" + section = 10 iPx = SHARED.theme.baseIconHeight iSz = SHARED.theme.baseIconSize + spW = 6*SHARED.theme.textNWidth + dbW = 8*SHARED.theme.textNWidth # Text Content + # ============ + + title = self._build.getLabel("text.grpContent") + section += 1 + self._sidebar.addButton(title, section) + self.addGroupLabel(title, section) + + # Text Inclusion self.incBodyText = NSwitch(self, height=iPx) self.incSynopsis = NSwitch(self, height=iPx) self.incComments = NSwitch(self, height=iPx) self.incKeywords = NSwitch(self, height=iPx) + self.addRow(self._build.getLabel("text.includeBodyText"), self.incBodyText) + self.addRow(self._build.getLabel("text.includeSynopsis"), self.incSynopsis) + self.addRow(self._build.getLabel("text.includeComments"), self.incComments) + self.addRow(self._build.getLabel("text.includeKeywords"), self.incKeywords) + + # Ignored Keywords self.ignoredKeywords = QLineEdit(self) self.mnKeywords = QMenu(self) @@ -990,80 +999,23 @@ class _ContentTab(NScrollableForm): self.ignoredKeywordsButton = NIconToolButton(self, iSz, "add") self.ignoredKeywordsButton.setMenu(self.mnKeywords) + self.addRow( + self._build.getLabel("text.ignoredKeywords"), self.ignoredKeywords, + button=self.ignoredKeywordsButton, stretch=(1, 1) + ) - self.addGroupLabel(self._build.getLabel("text.grpContent")) - self.addRow(self._build.getLabel("text.includeBodyText"), self.incBodyText) - self.addRow(self._build.getLabel("text.includeSynopsis"), self.incSynopsis) - self.addRow(self._build.getLabel("text.includeComments"), self.incComments) - self.addRow(self._build.getLabel("text.includeKeywords"), self.incKeywords) - self.addRow(self._build.getLabel("text.ignoredKeywords"), self.ignoredKeywords, - button=self.ignoredKeywordsButton, stretch=(1, 1)) - - # Insert Content + # Note Headings self.addNoteHead = NSwitch(self, height=iPx) - self.addGroupLabel(self._build.getLabel("text.grpInsert")) self.addRow(self._build.getLabel("text.addNoteHeadings"), self.addNoteHead) - # Finalise - self.finalise() - - return - - def loadContent(self) -> None: - """Populate the widgets.""" - self.incBodyText.setChecked(self._build.getBool("text.includeBodyText")) - self.incSynopsis.setChecked(self._build.getBool("text.includeSynopsis")) - self.incComments.setChecked(self._build.getBool("text.includeComments")) - self.incKeywords.setChecked(self._build.getBool("text.includeKeywords")) - self.ignoredKeywords.setText(self._build.getStr("text.ignoredKeywords")) - self.addNoteHead.setChecked(self._build.getBool("text.addNoteHeadings")) - self._updateIgnoredKeywords() - return - - def saveContent(self) -> None: - """Save choices back into build object.""" - self._updateIgnoredKeywords() - self._build.setValue("text.includeBodyText", self.incBodyText.isChecked()) - self._build.setValue("text.includeSynopsis", self.incSynopsis.isChecked()) - self._build.setValue("text.includeComments", self.incComments.isChecked()) - self._build.setValue("text.includeKeywords", self.incKeywords.isChecked()) - self._build.setValue("text.ignoredKeywords", self.ignoredKeywords.text()) - self._build.setValue("text.addNoteHeadings", self.addNoteHead.isChecked()) - return - - ## - # Internal Functions - ## - - def _updateIgnoredKeywords(self, keyword: str | None = None) -> None: - """Update the ignored keywords list.""" - current = [x.lower().strip() for x in self.ignoredKeywords.text().split(",")] - if keyword: - current.append(keyword) - verified = set(x for x in current if x in nwKeyWords.VALID_KEYS) - self.ignoredKeywords.setText(", ".join(verified)) - return - - -class _FormatTab(NScrollableForm): - - def __init__(self, parent: QWidget, build: BuildSettings) -> None: - super().__init__(parent=parent) - - self._build = build - self._unitScale = 1.0 - self._textFont = QFont(CONFIG.textFont) - - iPx = SHARED.theme.baseIconHeight - iSz = SHARED.theme.baseIconSize - spW = 6*SHARED.theme.textNWidth - dbW = 8*SHARED.theme.textNWidth - # Text Format # =========== - self.addGroupLabel(self._build.getLabel("format.grpFormat")) + title = self._build.getLabel("format.grpFormat") + section += 1 + self._sidebar.addButton(title, section) + self.addGroupLabel(title, section) # Text Font self.textFont = QLineEdit(self) @@ -1085,10 +1037,6 @@ class _FormatTab(NScrollableForm): self.addRow(self._build.getLabel("format.lineHeight"), self.lineHeight, unit="em") # Text Options - # ============ - - self.addGroupLabel(self._build.getLabel("format.grpOptions")) - self.justifyText = NSwitch(self, height=iPx) self.stripUnicode = NSwitch(self, height=iPx) self.replaceTabs = NSwitch(self, height=iPx) @@ -1104,7 +1052,10 @@ class _FormatTab(NScrollableForm): # First Line Indent # ================= - self.addGroupLabel(self._build.getLabel("format.grpParIndent")) + title = self._build.getLabel("format.grpParIndent") + section += 1 + self._sidebar.addButton(title, section) + self.addGroupLabel(title, section) self.firstIndent = NSwitch(self, height=iPx) self.indentFirstPar = NSwitch(self, height=iPx) @@ -1123,7 +1074,10 @@ class _FormatTab(NScrollableForm): # Page Layout # =========== - self.addGroupLabel(self._build.getLabel("format.grpPage")) + title = self._build.getLabel("format.grpPage") + section += 1 + self._sidebar.addButton(title, section) + self.addGroupLabel(title, section) self.pageUnit = NComboBox(self) for key, name in nwLabels.UNIT_NAME.items(): @@ -1164,6 +1118,47 @@ class _FormatTab(NScrollableForm): self.addRow(self._build.getLabel("format.leftMargin"), self.leftMargin) self.addRow(self._build.getLabel("format.rightMargin"), self.rightMargin) + # Open Document + # ============= + + title = self._build.getLabel("odt") + section += 1 + self._sidebar.addButton(title, section) + self.addGroupLabel(title, section) + + self.odtAddColours = NSwitch(self, height=iPx) + self.addRow(self._build.getLabel("odt.addColours"), self.odtAddColours) + + self.odtPageHeader = QLineEdit(self) + self.odtPageHeader.setMinimumWidth(CONFIG.pxInt(200)) + self.btnPageHeader = NIconToolButton(self, iSz, "revert") + self.btnPageHeader.clicked.connect(self._resetPageHeader) + self.addRow( + self._build.getLabel("odt.pageHeader"), self.odtPageHeader, + button=self.btnPageHeader, stretch=(1, 1) + ) + + self.odtPageCountOffset = NSpinBox(self) + self.odtPageCountOffset.setMinimum(0) + self.odtPageCountOffset.setMaximum(999) + self.odtPageCountOffset.setSingleStep(1) + self.odtPageCountOffset.setMinimumWidth(spW) + self.addRow(self._build.getLabel("odt.pageCountOffset"), self.odtPageCountOffset) + + # HTML Document + # ============= + + title = self._build.getLabel("html") + section += 1 + self._sidebar.addButton(title, section) + self.addGroupLabel(title, section) + + self.htmlAddStyles = NSwitch(self, height=iPx) + self.addRow(self._build.getLabel("html.addStyles"), self.htmlAddStyles) + + self.htmlPreserveTabs = NSwitch(self, height=iPx) + self.addRow(self._build.getLabel("html.preserveTabs"), self.htmlPreserveTabs) + # Finalise self.finalise() @@ -1171,6 +1166,20 @@ class _FormatTab(NScrollableForm): def loadContent(self) -> None: """Populate the widgets.""" + # Text Content + # ============ + + self.incBodyText.setChecked(self._build.getBool("text.includeBodyText")) + self.incSynopsis.setChecked(self._build.getBool("text.includeSynopsis")) + self.incComments.setChecked(self._build.getBool("text.includeComments")) + self.incKeywords.setChecked(self._build.getBool("text.includeKeywords")) + self.ignoredKeywords.setText(self._build.getStr("text.ignoredKeywords")) + self.addNoteHead.setChecked(self._build.getBool("text.addNoteHeadings")) + self._updateIgnoredKeywords() + + # Text Format + # =========== + self._textFont = QFont() self._textFont.fromString(self._build.getStr("format.textFont")) @@ -1184,10 +1193,16 @@ class _FormatTab(NScrollableForm): self.keepBreaks.setChecked(self._build.getBool("format.keepBreaks")) self.showDialogue.setChecked(self._build.getBool("format.showDialogue")) + # First Line Indent + # ================= + self.firstIndent.setChecked(self._build.getBool("format.firstLineIndent")) self.indentWidth.setValue(self._build.getFloat("format.firstIndentWidth")) self.indentFirstPar.setChecked(self._build.getBool("format.indentFirstPar")) + # Page Layout + # =========== + pageUnit = self._build.getStr("format.pageUnit") index = self.pageUnit.findData(pageUnit) if index >= 0: @@ -1211,10 +1226,34 @@ class _FormatTab(NScrollableForm): self.pageUnit.currentIndexChanged.connect(self._changeUnit) self.pageSize.currentIndexChanged.connect(self._changePageSize) + # ODT Document + # ============ + + self.odtAddColours.setChecked(self._build.getBool("odt.addColours")) + self.odtPageHeader.setText(self._build.getStr("odt.pageHeader")) + self.odtPageCountOffset.setValue(self._build.getInt("odt.pageCountOffset")) + self.odtPageHeader.setCursorPosition(0) + + # HTML Document + # ============= + + self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles")) + self.htmlPreserveTabs.setChecked(self._build.getBool("html.preserveTabs")) + return def saveContent(self) -> None: """Save choices back into build object.""" + # Text Content + self._updateIgnoredKeywords() + self._build.setValue("text.includeBodyText", self.incBodyText.isChecked()) + self._build.setValue("text.includeSynopsis", self.incSynopsis.isChecked()) + self._build.setValue("text.includeComments", self.incComments.isChecked()) + self._build.setValue("text.includeKeywords", self.incKeywords.isChecked()) + self._build.setValue("text.ignoredKeywords", self.ignoredKeywords.text()) + self._build.setValue("text.addNoteHeadings", self.addNoteHead.isChecked()) + + # Text Format self._build.setValue("format.textFont", self._textFont.toString()) self._build.setValue("format.lineHeight", self.lineHeight.value()) @@ -1224,10 +1263,12 @@ class _FormatTab(NScrollableForm): self._build.setValue("format.keepBreaks", self.keepBreaks.isChecked()) self._build.setValue("format.showDialogue", self.showDialogue.isChecked()) + # First Line Indent self._build.setValue("format.firstLineIndent", self.firstIndent.isChecked()) self._build.setValue("format.firstIndentWidth", self.indentWidth.value()) self._build.setValue("format.indentFirstPar", self.indentFirstPar.isChecked()) + # Page Layout self._build.setValue("format.pageUnit", str(self.pageUnit.currentData())) self._build.setValue("format.pageSize", str(self.pageSize.currentData())) self._build.setValue("format.pageWidth", self.pageWidth.value()) @@ -1236,6 +1277,16 @@ class _FormatTab(NScrollableForm): self._build.setValue("format.bottomMargin", self.bottomMargin.value()) self._build.setValue("format.leftMargin", self.leftMargin.value()) self._build.setValue("format.rightMargin", self.rightMargin.value()) + + # ODT Document + self._build.setValue("odt.addColours", self.odtAddColours.isChecked()) + self._build.setValue("odt.pageHeader", self.odtPageHeader.text()) + self._build.setValue("odt.pageCountOffset", self.odtPageCountOffset.value()) + + # HTML Document + self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked()) + self._build.setValue("html.preserveTabs", self.htmlPreserveTabs.isChecked()) + return ## @@ -1334,79 +1385,21 @@ class _FormatTab(NScrollableForm): self.pageSize.setCurrentIndex(index) return - -class _OutputTab(NScrollableForm): - - def __init__(self, parent: QWidget, build: BuildSettings) -> None: - super().__init__(parent=parent) - - self._build = build - - iPx = SHARED.theme.baseIconHeight - iSz = SHARED.theme.baseIconSize - spW = 6*SHARED.theme.textNWidth - - # Open Document - self.addGroupLabel(self._build.getLabel("odt")) - - self.odtAddColours = NSwitch(self, height=iPx) - self.addRow(self._build.getLabel("odt.addColours"), self.odtAddColours) - - self.odtPageHeader = QLineEdit(self) - self.odtPageHeader.setMinimumWidth(CONFIG.pxInt(200)) - self.btnPageHeader = NIconToolButton(self, iSz, "revert") - self.btnPageHeader.clicked.connect(self._resetPageHeader) - self.addRow( - self._build.getLabel("odt.pageHeader"), self.odtPageHeader, - button=self.btnPageHeader, stretch=(1, 1) - ) - - self.odtPageCountOffset = NSpinBox(self) - self.odtPageCountOffset.setMinimum(0) - self.odtPageCountOffset.setMaximum(999) - self.odtPageCountOffset.setSingleStep(1) - self.odtPageCountOffset.setMinimumWidth(spW) - self.addRow(self._build.getLabel("odt.pageCountOffset"), self.odtPageCountOffset) - - # HTML Document - self.addGroupLabel(self._build.getLabel("html")) - - self.htmlAddStyles = NSwitch(self, height=iPx) - self.addRow(self._build.getLabel("html.addStyles"), self.htmlAddStyles) - - self.htmlPreserveTabs = NSwitch(self, height=iPx) - self.addRow(self._build.getLabel("html.preserveTabs"), self.htmlPreserveTabs) - - # Finalise - self.finalise() - - return - - def loadContent(self) -> None: - """Populate the widgets.""" - self.odtAddColours.setChecked(self._build.getBool("odt.addColours")) - self.odtPageHeader.setText(self._build.getStr("odt.pageHeader")) - self.odtPageCountOffset.setValue(self._build.getInt("odt.pageCountOffset")) - self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles")) - self.htmlPreserveTabs.setChecked(self._build.getBool("html.preserveTabs")) - self.odtPageHeader.setCursorPosition(0) - return - - def saveContent(self) -> None: - """Save choices back into build object.""" - self._build.setValue("odt.addColours", self.odtAddColours.isChecked()) - self._build.setValue("odt.pageHeader", self.odtPageHeader.text()) - self._build.setValue("odt.pageCountOffset", self.odtPageCountOffset.value()) - self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked()) - self._build.setValue("html.preserveTabs", self.htmlPreserveTabs.isChecked()) - return - - ## - # Private Slots - ## - def _resetPageHeader(self) -> None: """Reset the ODT header format to default.""" self.odtPageHeader.setText(nwHeadFmt.ODT_AUTO) self.odtPageHeader.setCursorPosition(0) return + + ## + # Internal Functions + ## + + def _updateIgnoredKeywords(self, keyword: str | None = None) -> None: + """Update the ignored keywords list.""" + current = [x.lower().strip() for x in self.ignoredKeywords.text().split(",")] + if keyword: + current.append(keyword) + verified = set(x for x in current if x in nwKeyWords.VALID_KEYS) + self.ignoredKeywords.setText(", ".join(verified)) + return diff --git a/tests/test_tools/test_tools_manussettings.py b/tests/test_tools/test_tools_manussettings.py index cc39745e..026b27ee 100644 --- a/tests/test_tools/test_tools_manussettings.py +++ b/tests/test_tools/test_tools_manussettings.py @@ -31,8 +31,7 @@ from novelwriter.common import describeFont from novelwriter.constants import nwHeadFmt from novelwriter.core.buildsettings import BuildSettings, FilterMode from novelwriter.tools.manussettings import ( - GuiBuildSettings, _ContentTab, _FilterTab, _FormatTab, _HeadingsTab, - _OutputTab + GuiBuildSettings, _FilterTab, _FormattingTab, _HeadingsTab ) from novelwriter.types import QtDialogApply, QtDialogClose, QtDialogSave @@ -52,14 +51,8 @@ def testToolBuildSettings_Init(qtbot, nwGUI, projPath, mockRnd): bSettings.loadContent() # Flip through pages - bSettings.sidebar._group.button(bSettings.OPT_OUTPUT).click() - assert isinstance(bSettings.toolStack.currentWidget(), _OutputTab) - - bSettings.sidebar._group.button(bSettings.OPT_FORMAT).click() - assert isinstance(bSettings.toolStack.currentWidget(), _FormatTab) - - bSettings.sidebar._group.button(bSettings.OPT_CONTENT).click() - assert isinstance(bSettings.toolStack.currentWidget(), _ContentTab) + bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 1).click() + assert isinstance(bSettings.toolStack.currentWidget(), _FormattingTab) bSettings.sidebar._group.button(bSettings.OPT_HEADINGS).click() assert isinstance(bSettings.toolStack.currentWidget(), _HeadingsTab) @@ -484,8 +477,8 @@ def testToolBuildSettings_Headings(qtbot, nwGUI): @pytest.mark.gui -def testToolBuildSettings_Content(qtbot, nwGUI): - """Test the Content Tab of the GuiBuildSettings dialog.""" +def testToolBuildSettings_FormatTextContent(qtbot, nwGUI): + """Test the Text Content settings.""" build = BuildSettings() build.setValue("text.includeBodyText", False) @@ -501,34 +494,34 @@ def testToolBuildSettings_Content(qtbot, nwGUI): bSettings.show() bSettings.loadContent() - contTab = bSettings.optTabContent - bSettings.sidebar._group.button(bSettings.OPT_CONTENT).click() - assert bSettings.toolStack.currentWidget() is contTab + fmtTab = bSettings.optTabFormatting + bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 1).click() + assert bSettings.toolStack.currentWidget() is fmtTab # Check initial values - assert contTab.incBodyText.isChecked() is False - assert contTab.incSynopsis.isChecked() is False - assert contTab.incComments.isChecked() is False - assert contTab.incKeywords.isChecked() is False - assert contTab.ignoredKeywords.text() == "" + assert fmtTab.incBodyText.isChecked() is False + assert fmtTab.incSynopsis.isChecked() is False + assert fmtTab.incComments.isChecked() is False + assert fmtTab.incKeywords.isChecked() is False + assert fmtTab.ignoredKeywords.text() == "" - assert contTab.addNoteHead.isChecked() is False + assert fmtTab.addNoteHead.isChecked() is False # Toggle switches - contTab.incBodyText.setChecked(True) - contTab.incSynopsis.setChecked(True) - contTab.incComments.setChecked(True) - contTab.incKeywords.setChecked(True) + fmtTab.incBodyText.setChecked(True) + fmtTab.incSynopsis.setChecked(True) + fmtTab.incComments.setChecked(True) + fmtTab.incKeywords.setChecked(True) - contTab.addNoteHead.setChecked(True) + fmtTab.addNoteHead.setChecked(True) # Test cleanup of ignored keywords - contTab.ignoredKeywords.setText("@stuff, @pizza, @object") # First two are invalid - contTab._updateIgnoredKeywords("@custom") # Adding a new should trigger cleanup - assert contTab.ignoredKeywords.text() in ("@custom, @object", "@object, @custom") + fmtTab.ignoredKeywords.setText("@stuff, @pizza, @object") # First two are invalid + fmtTab._updateIgnoredKeywords("@custom") # Adding a new should trigger cleanup + assert fmtTab.ignoredKeywords.text() in ("@custom, @object", "@object, @custom") # Save values - contTab.saveContent() + fmtTab.saveContent() assert build.getBool("text.includeBodyText") is True assert build.getBool("text.includeSynopsis") is True @@ -544,8 +537,8 @@ def testToolBuildSettings_Content(qtbot, nwGUI): @pytest.mark.gui -def testToolBuildSettings_Format(monkeypatch, qtbot, nwGUI): - """Test the Format Tab of the GuiBuildSettings dialog.""" +def testToolBuildSettings_FormatTextFormat(monkeypatch, qtbot, nwGUI): + """Test the Text Format settings.""" build = BuildSettings() build.setValue("format.buildLang", "en_US") @@ -558,26 +551,13 @@ def testToolBuildSettings_Format(monkeypatch, qtbot, nwGUI): build.setValue("format.keepBreaks", True) build.setValue("format.showDialogue", False) - build.setValue("format.firstLineIndent", False) - build.setValue("format.firstIndentWidth", 1.4) - build.setValue("format.indentFirstPar", False) - - build.setValue("format.pageUnit", "mm") - build.setValue("format.pageSize", "Custom") - build.setValue("format.pageWidth", 180.0) - build.setValue("format.pageHeight", 250.0) - build.setValue("format.topMargin", 25.0) - build.setValue("format.bottomMargin", 25.0) - build.setValue("format.leftMargin", 15.0) - build.setValue("format.rightMargin", 15.0) - # Create the dialog and populate it bSettings = GuiBuildSettings(nwGUI, build) bSettings.show() bSettings.loadContent() - fmtTab = bSettings.optTabFormat - bSettings.sidebar._group.button(bSettings.OPT_FORMAT).click() + fmtTab = bSettings.optTabFormatting + bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 2).click() assert bSettings.toolStack.currentWidget() is fmtTab # Check initial values @@ -589,19 +569,6 @@ def testToolBuildSettings_Format(monkeypatch, qtbot, nwGUI): assert fmtTab.keepBreaks.isChecked() is True assert fmtTab.showDialogue.isChecked() is False - assert fmtTab.firstIndent.isChecked() is False - assert fmtTab.indentWidth.value() == 1.4 - assert fmtTab.indentFirstPar.isChecked() is False - - assert fmtTab.pageUnit.currentData() == "mm" - assert fmtTab.pageSize.currentData() == "Custom" - assert fmtTab.pageWidth.value() == 180.0 - assert fmtTab.pageHeight.value() == 250.0 - assert fmtTab.topMargin.value() == 25.0 - assert fmtTab.bottomMargin.value() == 25.0 - assert fmtTab.leftMargin.value() == 15.0 - assert fmtTab.rightMargin.value() == 15.0 - # Change values testFont = QFont("Arial", 11) fmtTab._textFont = testFont @@ -614,13 +581,6 @@ def testToolBuildSettings_Format(monkeypatch, qtbot, nwGUI): fmtTab.keepBreaks.setChecked(False) fmtTab.showDialogue.setChecked(True) - fmtTab.firstIndent.setChecked(True) - fmtTab.indentWidth.setValue(2.0) - fmtTab.indentFirstPar.setChecked(True) - - fmtTab.pageUnit.setCurrentIndex(fmtTab.pageUnit.findData("cm")) - fmtTab.pageSize.setCurrentIndex(fmtTab.pageSize.findData("A4")) - # Save values fmtTab.saveContent() @@ -633,19 +593,6 @@ def testToolBuildSettings_Format(monkeypatch, qtbot, nwGUI): assert build.getBool("format.keepBreaks") is False assert build.getBool("format.showDialogue") is True - assert build.getBool("format.firstLineIndent") is True - assert build.getFloat("format.firstIndentWidth") == 2.0 - assert build.getBool("format.indentFirstPar") is True - - assert fmtTab.pageUnit.currentData() == "cm" - assert fmtTab.pageSize.currentData() == "A4" - assert fmtTab.pageWidth.value() == 21.0 - assert fmtTab.pageHeight.value() == 29.7 - assert fmtTab.topMargin.value() == 2.5 - assert fmtTab.bottomMargin.value() == 2.5 - assert fmtTab.leftMargin.value() == 1.5 - assert fmtTab.rightMargin.value() == 1.5 - # Check that the font dialog doesn't fail with monkeypatch.context() as mp: font = QFont() @@ -662,50 +609,150 @@ def testToolBuildSettings_Format(monkeypatch, qtbot, nwGUI): @pytest.mark.gui -def testToolBuildSettings_Output(qtbot, nwGUI): - """Test the Output Tab of the GuiBuildSettings dialog.""" +def testToolBuildSettings_FormatFirstLineIndent(monkeypatch, qtbot, nwGUI): + """Test the First Line Indent settings.""" build = BuildSettings() - build.setValue("odt.addColours", False) - build.setValue("html.addStyles", False) + build.setValue("format.firstLineIndent", False) + build.setValue("format.firstIndentWidth", 1.4) + build.setValue("format.indentFirstPar", False) # Create the dialog and populate it bSettings = GuiBuildSettings(nwGUI, build) bSettings.show() bSettings.loadContent() - outTab = bSettings.optTabOutput - bSettings.sidebar._group.button(bSettings.OPT_OUTPUT).click() - assert bSettings.toolStack.currentWidget() is outTab + fmtTab = bSettings.optTabFormatting + bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 3).click() + assert bSettings.toolStack.currentWidget() is fmtTab # Check initial values - assert outTab.odtAddColours.isChecked() is False - assert outTab.odtPageHeader.text() == nwHeadFmt.ODT_AUTO - assert outTab.odtPageCountOffset.value() == 0 - assert outTab.htmlAddStyles.isChecked() is False - assert outTab.htmlPreserveTabs.isChecked() is False + assert fmtTab.firstIndent.isChecked() is False + assert fmtTab.indentWidth.value() == 1.4 + assert fmtTab.indentFirstPar.isChecked() is False - # Toggle all - outTab.odtAddColours.setChecked(True) - outTab.htmlAddStyles.setChecked(True) - outTab.htmlPreserveTabs.setChecked(True) - - # Change Values - outTab.odtPageCountOffset.setValue(1) - outTab.odtPageHeader.setText("Stuff") + # Change values + fmtTab.firstIndent.setChecked(True) + fmtTab.indentWidth.setValue(2.0) + fmtTab.indentFirstPar.setChecked(True) # Save values - outTab.saveContent() + fmtTab.saveContent() - assert build.getBool("odt.addColours") is True - assert build.getStr("odt.pageHeader") == "Stuff" - assert build.getInt("odt.pageCountOffset") == 1 - assert build.getBool("html.addStyles") is True - assert build.getBool("html.preserveTabs") is True - - # Reset header format - outTab.btnPageHeader.click() - assert outTab.odtPageHeader.text() == nwHeadFmt.ODT_AUTO + assert build.getBool("format.firstLineIndent") is True + assert build.getFloat("format.firstIndentWidth") == 2.0 + assert build.getBool("format.indentFirstPar") is True + + # Finish + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) + # qtbot.stop() + + +@pytest.mark.gui +def testToolBuildSettings_FormatPageLayout(monkeypatch, qtbot, nwGUI): + """Test the First Line Indent settings.""" + build = BuildSettings() + + build.setValue("format.pageUnit", "mm") + build.setValue("format.pageSize", "Custom") + build.setValue("format.pageWidth", 180.0) + build.setValue("format.pageHeight", 250.0) + build.setValue("format.topMargin", 25.0) + build.setValue("format.bottomMargin", 25.0) + build.setValue("format.leftMargin", 15.0) + build.setValue("format.rightMargin", 15.0) + + # Create the dialog and populate it + bSettings = GuiBuildSettings(nwGUI, build) + bSettings.show() + bSettings.loadContent() + + fmtTab = bSettings.optTabFormatting + bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 4).click() + assert bSettings.toolStack.currentWidget() is fmtTab + + # Check initial values + assert fmtTab.pageUnit.currentData() == "mm" + assert fmtTab.pageSize.currentData() == "Custom" + assert fmtTab.pageWidth.value() == 180.0 + assert fmtTab.pageHeight.value() == 250.0 + assert fmtTab.topMargin.value() == 25.0 + assert fmtTab.bottomMargin.value() == 25.0 + assert fmtTab.leftMargin.value() == 15.0 + assert fmtTab.rightMargin.value() == 15.0 + + # Change values + fmtTab.pageUnit.setCurrentIndex(fmtTab.pageUnit.findData("cm")) + fmtTab.pageSize.setCurrentIndex(fmtTab.pageSize.findData("A4")) + + # Save values + fmtTab.saveContent() + + assert fmtTab.pageUnit.currentData() == "cm" + assert fmtTab.pageSize.currentData() == "A4" + assert fmtTab.pageWidth.value() == 21.0 + assert fmtTab.pageHeight.value() == 29.7 + assert fmtTab.topMargin.value() == 2.5 + assert fmtTab.bottomMargin.value() == 2.5 + assert fmtTab.leftMargin.value() == 1.5 + assert fmtTab.rightMargin.value() == 1.5 + + # Finish + bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) + # qtbot.stop() + + +@pytest.mark.gui +def testToolBuildSettings_FormatOutput(qtbot, nwGUI): + """Test the format-specific settings.""" + build = BuildSettings() + + build.setValue("odt.addColours", False) + build.setValue("odt.pageHeader", nwHeadFmt.ODT_AUTO) + build.setValue("odt.pageCountOffset", 0) + + build.setValue("html.addStyles", False) + build.setValue("html.preserveTabs", False) + + # Create the dialog and populate it + bSettings = GuiBuildSettings(nwGUI, build) + bSettings.show() + bSettings.loadContent() + + fmtTab = bSettings.optTabFormatting + bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 5).click() + assert bSettings.toolStack.currentWidget() is fmtTab + + # Check initial values + assert fmtTab.odtAddColours.isChecked() is False + assert fmtTab.odtPageHeader.text() == nwHeadFmt.ODT_AUTO + assert fmtTab.odtPageCountOffset.value() == 0 + + assert fmtTab.htmlAddStyles.isChecked() is False + assert fmtTab.htmlPreserveTabs.isChecked() is False + + # Toggle all + fmtTab.odtAddColours.setChecked(True) + fmtTab.htmlAddStyles.setChecked(True) + fmtTab.htmlPreserveTabs.setChecked(True) + + # Change Values + fmtTab.odtPageCountOffset.setValue(1) + fmtTab.odtPageHeader.setText("Stuff") + + # Save values + fmtTab.saveContent() + + assert build.getBool("odt.addColours") is True + assert build.getStr("odt.pageHeader") == "Stuff" + assert build.getInt("odt.pageCountOffset") == 1 + + assert build.getBool("html.addStyles") is True + assert build.getBool("html.preserveTabs") is True + + # Reset header format + fmtTab.btnPageHeader.click() + assert fmtTab.odtPageHeader.text() == nwHeadFmt.ODT_AUTO # Finish bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose))