Refactor build settings (#2031)

This commit is contained in:
Veronica Berglyd Olsen
2024-09-28 11:58:58 +02:00
committed by GitHub
5 changed files with 333 additions and 294 deletions
+2 -4
View File
@@ -121,13 +121,11 @@ SETTINGS_LABELS = {
"text.includeKeywords": QT_TRANSLATE_NOOP("Builds", "Include Keywords"), "text.includeKeywords": QT_TRANSLATE_NOOP("Builds", "Include Keywords"),
"text.includeBodyText": QT_TRANSLATE_NOOP("Builds", "Include Body Text"), "text.includeBodyText": QT_TRANSLATE_NOOP("Builds", "Include Body Text"),
"text.ignoredKeywords": QT_TRANSLATE_NOOP("Builds", "Ignore These Keywords"), "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"), "text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"),
"format.grpFormat": QT_TRANSLATE_NOOP("Builds", "Text Format"), "format.grpFormat": QT_TRANSLATE_NOOP("Builds", "Text Format"),
"format.textFont": QT_TRANSLATE_NOOP("Builds", "Text Font"), "format.textFont": QT_TRANSLATE_NOOP("Builds", "Text Font"),
"format.lineHeight": QT_TRANSLATE_NOOP("Builds", "Line Height"), "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.justifyText": QT_TRANSLATE_NOOP("Builds", "Justify Text Margins"),
"format.stripUnicode": QT_TRANSLATE_NOOP("Builds", "Replace Unicode Characters"), "format.stripUnicode": QT_TRANSLATE_NOOP("Builds", "Replace Unicode Characters"),
"format.replaceTabs": QT_TRANSLATE_NOOP("Builds", "Replace Tabs with Spaces"), "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.leftMargin": QT_TRANSLATE_NOOP("Builds", "Left Margin"),
"format.rightMargin": QT_TRANSLATE_NOOP("Builds", "Right 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.addColours": QT_TRANSLATE_NOOP("Builds", "Add Highlight Colours"),
"odt.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"), "odt.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"),
"odt.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"), "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.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"),
"html.preserveTabs": QT_TRANSLATE_NOOP("Builds", "Preserve Tab Characters"), "html.preserveTabs": QT_TRANSLATE_NOOP("Builds", "Preserve Tab Characters"),
} }
+6 -5
View File
@@ -1095,6 +1095,12 @@ class GuiDocEditor(QPlainTextEdit):
self._completer.hide() self._completer.hide()
return return
@pyqtSlot()
def _openContextFromCursor(self) -> None:
"""Open the spell check context menu at the cursor."""
self._openContextMenu(self.cursorRect().center())
return
@pyqtSlot("QPoint") @pyqtSlot("QPoint")
def _openContextMenu(self, pos: QPoint) -> None: def _openContextMenu(self, pos: QPoint) -> None:
"""Open the editor context menu at a given coordinate.""" """Open the editor context menu at a given coordinate."""
@@ -1938,11 +1944,6 @@ class GuiDocEditor(QPlainTextEdit):
self.requestProjectItemRenamed.emit(self._docHandle, text) self.requestProjectItemRenamed.emit(self._docHandle, text)
return 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: def _docAutoReplace(self, text: str) -> None:
"""Auto-replace text elements based on main configuration.""" """Auto-replace text elements based on main configuration."""
cursor = self.textCursor() cursor = self.textCursor()
+1 -1
View File
@@ -491,7 +491,7 @@ class TextBlockData(QTextBlockUserData):
self._spellErrors = [] self._spellErrors = []
checker = SHARED.spelling checker = SHARED.spelling
for match in RX_WORDS.finditer(text.replace("_", " ")): for match in RX_WORDS.finditer(text.replace("_", " "), offset):
if ( if (
(word := match.group(0)) (word := match.group(0))
and not (word.isnumeric() or word.isupper() or checker.checkWord(word)) and not (word.isnumeric() or word.isupper() or checker.checkWord(word))
+167 -174
View File
@@ -67,11 +67,9 @@ class GuiBuildSettings(NToolDialog):
editing JSON build definitions, wrapped as a BuildSettings object. editing JSON build definitions, wrapped as a BuildSettings object.
""" """
OPT_FILTERS = 1 OPT_FILTERS = 1
OPT_HEADINGS = 2 OPT_HEADINGS = 2
OPT_CONTENT = 3 OPT_FORMATTING = 10
OPT_FORMAT = 4
OPT_OUTPUT = 5
newSettingsReady = pyqtSignal(BuildSettings) newSettingsReady = pyqtSignal(BuildSettings)
@@ -86,7 +84,6 @@ class GuiBuildSettings(NToolDialog):
self.setWindowTitle(self.tr("Manuscript Build Settings")) self.setWindowTitle(self.tr("Manuscript Build Settings"))
self.setMinimumSize(CONFIG.pxInt(700), CONFIG.pxInt(400)) self.setMinimumSize(CONFIG.pxInt(700), CONFIG.pxInt(400))
mPx = CONFIG.pxInt(150)
wWin = CONFIG.pxInt(750) wWin = CONFIG.pxInt(750)
hWin = CONFIG.pxInt(550) hWin = CONFIG.pxInt(550)
@@ -108,31 +105,24 @@ class GuiBuildSettings(NToolDialog):
# SideBar # SideBar
self.sidebar = NPagedSideBar(self) self.sidebar = NPagedSideBar(self)
self.sidebar.setMinimumWidth(mPx)
self.sidebar.setMaximumWidth(mPx)
self.sidebar.setLabelColor(SHARED.theme.helpText) 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("Selection"), self.OPT_FILTERS)
self.sidebar.addButton(self.tr("Headings"), self.OPT_HEADINGS) self.sidebar.addButton(self.tr("Headings"), self.OPT_HEADINGS)
self.sidebar.addButton(self.tr("Content"), self.OPT_CONTENT) self.sidebar.addLabel(self.tr("Formatting"))
self.sidebar.addButton(self.tr("Format"), self.OPT_FORMAT)
self.sidebar.addButton(self.tr("Output"), self.OPT_OUTPUT)
self.sidebar.buttonClicked.connect(self._stackPageSelected) self.sidebar.buttonClicked.connect(self._stackPageSelected)
# Content # Content
self.optTabSelect = _FilterTab(self, self._build) self.optTabSelect = _FilterTab(self, self._build)
self.optTabHeadings = _HeadingsTab(self, self._build) self.optTabHeadings = _HeadingsTab(self, self._build)
self.optTabContent = _ContentTab(self, self._build) self.optTabFormatting = _FormattingTab(self, self._build, self.sidebar)
self.optTabFormat = _FormatTab(self, self._build)
self.optTabOutput = _OutputTab(self, self._build)
self.toolStack = QStackedWidget(self) self.toolStack = QStackedWidget(self)
self.toolStack.addWidget(self.optTabSelect) self.toolStack.addWidget(self.optTabSelect)
self.toolStack.addWidget(self.optTabHeadings) self.toolStack.addWidget(self.optTabHeadings)
self.toolStack.addWidget(self.optTabFormat) self.toolStack.addWidget(self.optTabFormatting)
self.toolStack.addWidget(self.optTabContent)
self.toolStack.addWidget(self.optTabOutput)
# Buttons # Buttons
self.buttonBox = QDialogButtonBox(QtDialogApply | QtDialogSave | QtDialogClose, self) self.buttonBox = QDialogButtonBox(QtDialogApply | QtDialogSave | QtDialogClose, self)
@@ -174,9 +164,7 @@ class GuiBuildSettings(NToolDialog):
self.editBuildName.setText(self._build.name) self.editBuildName.setText(self._build.name)
self.optTabSelect.loadContent() self.optTabSelect.loadContent()
self.optTabHeadings.loadContent() self.optTabHeadings.loadContent()
self.optTabContent.loadContent() self.optTabFormatting.loadContent()
self.optTabFormat.loadContent()
self.optTabOutput.loadContent()
return return
## ##
@@ -214,12 +202,9 @@ class GuiBuildSettings(NToolDialog):
self.toolStack.setCurrentWidget(self.optTabSelect) self.toolStack.setCurrentWidget(self.optTabSelect)
elif pageId == self.OPT_HEADINGS: elif pageId == self.OPT_HEADINGS:
self.toolStack.setCurrentWidget(self.optTabHeadings) self.toolStack.setCurrentWidget(self.optTabHeadings)
elif pageId == self.OPT_CONTENT: elif pageId >= self.OPT_FORMATTING:
self.toolStack.setCurrentWidget(self.optTabContent) self.toolStack.setCurrentWidget(self.optTabFormatting)
elif pageId == self.OPT_FORMAT: self.optTabFormatting.scrollToSection(pageId)
self.toolStack.setCurrentWidget(self.optTabFormat)
elif pageId == self.OPT_OUTPUT:
self.toolStack.setCurrentWidget(self.optTabOutput)
return return
@pyqtSlot("QAbstractButton*") @pyqtSlot("QAbstractButton*")
@@ -272,9 +257,7 @@ class GuiBuildSettings(NToolDialog):
"""Assemble the build data and emit the signal.""" """Assemble the build data and emit the signal."""
self._build.setName(self.editBuildName.text()) self._build.setName(self.editBuildName.text())
self.optTabHeadings.saveContent() self.optTabHeadings.saveContent()
self.optTabContent.saveContent() self.optTabFormatting.saveContent()
self.optTabFormat.saveContent()
self.optTabOutput.saveContent()
self.newSettingsReady.emit(self._build) self.newSettingsReady.emit(self._build)
self._build.resetChangedState() self._build.resetChangedState()
return return
@@ -963,22 +946,48 @@ class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
return 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) super().__init__(parent=parent)
self._build = build 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 iPx = SHARED.theme.baseIconHeight
iSz = SHARED.theme.baseIconSize iSz = SHARED.theme.baseIconSize
spW = 6*SHARED.theme.textNWidth
dbW = 8*SHARED.theme.textNWidth
# Text Content # 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.incBodyText = NSwitch(self, height=iPx)
self.incSynopsis = NSwitch(self, height=iPx) self.incSynopsis = NSwitch(self, height=iPx)
self.incComments = NSwitch(self, height=iPx) self.incComments = NSwitch(self, height=iPx)
self.incKeywords = 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.ignoredKeywords = QLineEdit(self)
self.mnKeywords = QMenu(self) self.mnKeywords = QMenu(self)
@@ -990,80 +999,23 @@ class _ContentTab(NScrollableForm):
self.ignoredKeywordsButton = NIconToolButton(self, iSz, "add") self.ignoredKeywordsButton = NIconToolButton(self, iSz, "add")
self.ignoredKeywordsButton.setMenu(self.mnKeywords) 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")) # Note Headings
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
self.addNoteHead = NSwitch(self, height=iPx) self.addNoteHead = NSwitch(self, height=iPx)
self.addGroupLabel(self._build.getLabel("text.grpInsert"))
self.addRow(self._build.getLabel("text.addNoteHeadings"), self.addNoteHead) 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 # 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 # Text Font
self.textFont = QLineEdit(self) self.textFont = QLineEdit(self)
@@ -1085,10 +1037,6 @@ class _FormatTab(NScrollableForm):
self.addRow(self._build.getLabel("format.lineHeight"), self.lineHeight, unit="em") self.addRow(self._build.getLabel("format.lineHeight"), self.lineHeight, unit="em")
# Text Options # Text Options
# ============
self.addGroupLabel(self._build.getLabel("format.grpOptions"))
self.justifyText = NSwitch(self, height=iPx) self.justifyText = NSwitch(self, height=iPx)
self.stripUnicode = NSwitch(self, height=iPx) self.stripUnicode = NSwitch(self, height=iPx)
self.replaceTabs = NSwitch(self, height=iPx) self.replaceTabs = NSwitch(self, height=iPx)
@@ -1104,7 +1052,10 @@ class _FormatTab(NScrollableForm):
# First Line Indent # 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.firstIndent = NSwitch(self, height=iPx)
self.indentFirstPar = NSwitch(self, height=iPx) self.indentFirstPar = NSwitch(self, height=iPx)
@@ -1123,7 +1074,10 @@ class _FormatTab(NScrollableForm):
# Page Layout # 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) self.pageUnit = NComboBox(self)
for key, name in nwLabels.UNIT_NAME.items(): 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.leftMargin"), self.leftMargin)
self.addRow(self._build.getLabel("format.rightMargin"), self.rightMargin) 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 # Finalise
self.finalise() self.finalise()
@@ -1171,6 +1166,20 @@ class _FormatTab(NScrollableForm):
def loadContent(self) -> None: def loadContent(self) -> None:
"""Populate the widgets.""" """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 = QFont()
self._textFont.fromString(self._build.getStr("format.textFont")) self._textFont.fromString(self._build.getStr("format.textFont"))
@@ -1184,10 +1193,16 @@ class _FormatTab(NScrollableForm):
self.keepBreaks.setChecked(self._build.getBool("format.keepBreaks")) self.keepBreaks.setChecked(self._build.getBool("format.keepBreaks"))
self.showDialogue.setChecked(self._build.getBool("format.showDialogue")) self.showDialogue.setChecked(self._build.getBool("format.showDialogue"))
# First Line Indent
# =================
self.firstIndent.setChecked(self._build.getBool("format.firstLineIndent")) self.firstIndent.setChecked(self._build.getBool("format.firstLineIndent"))
self.indentWidth.setValue(self._build.getFloat("format.firstIndentWidth")) self.indentWidth.setValue(self._build.getFloat("format.firstIndentWidth"))
self.indentFirstPar.setChecked(self._build.getBool("format.indentFirstPar")) self.indentFirstPar.setChecked(self._build.getBool("format.indentFirstPar"))
# Page Layout
# ===========
pageUnit = self._build.getStr("format.pageUnit") pageUnit = self._build.getStr("format.pageUnit")
index = self.pageUnit.findData(pageUnit) index = self.pageUnit.findData(pageUnit)
if index >= 0: if index >= 0:
@@ -1211,10 +1226,34 @@ class _FormatTab(NScrollableForm):
self.pageUnit.currentIndexChanged.connect(self._changeUnit) self.pageUnit.currentIndexChanged.connect(self._changeUnit)
self.pageSize.currentIndexChanged.connect(self._changePageSize) 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 return
def saveContent(self) -> None: def saveContent(self) -> None:
"""Save choices back into build object.""" """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.textFont", self._textFont.toString())
self._build.setValue("format.lineHeight", self.lineHeight.value()) 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.keepBreaks", self.keepBreaks.isChecked())
self._build.setValue("format.showDialogue", self.showDialogue.isChecked()) self._build.setValue("format.showDialogue", self.showDialogue.isChecked())
# First Line Indent
self._build.setValue("format.firstLineIndent", self.firstIndent.isChecked()) self._build.setValue("format.firstLineIndent", self.firstIndent.isChecked())
self._build.setValue("format.firstIndentWidth", self.indentWidth.value()) self._build.setValue("format.firstIndentWidth", self.indentWidth.value())
self._build.setValue("format.indentFirstPar", self.indentFirstPar.isChecked()) self._build.setValue("format.indentFirstPar", self.indentFirstPar.isChecked())
# Page Layout
self._build.setValue("format.pageUnit", str(self.pageUnit.currentData())) self._build.setValue("format.pageUnit", str(self.pageUnit.currentData()))
self._build.setValue("format.pageSize", str(self.pageSize.currentData())) self._build.setValue("format.pageSize", str(self.pageSize.currentData()))
self._build.setValue("format.pageWidth", self.pageWidth.value()) 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.bottomMargin", self.bottomMargin.value())
self._build.setValue("format.leftMargin", self.leftMargin.value()) self._build.setValue("format.leftMargin", self.leftMargin.value())
self._build.setValue("format.rightMargin", self.rightMargin.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 return
## ##
@@ -1334,79 +1385,21 @@ class _FormatTab(NScrollableForm):
self.pageSize.setCurrentIndex(index) self.pageSize.setCurrentIndex(index)
return 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: def _resetPageHeader(self) -> None:
"""Reset the ODT header format to default.""" """Reset the ODT header format to default."""
self.odtPageHeader.setText(nwHeadFmt.ODT_AUTO) self.odtPageHeader.setText(nwHeadFmt.ODT_AUTO)
self.odtPageHeader.setCursorPosition(0) self.odtPageHeader.setCursorPosition(0)
return 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
+157 -110
View File
@@ -31,8 +31,7 @@ from novelwriter.common import describeFont
from novelwriter.constants import nwHeadFmt from novelwriter.constants import nwHeadFmt
from novelwriter.core.buildsettings import BuildSettings, FilterMode from novelwriter.core.buildsettings import BuildSettings, FilterMode
from novelwriter.tools.manussettings import ( from novelwriter.tools.manussettings import (
GuiBuildSettings, _ContentTab, _FilterTab, _FormatTab, _HeadingsTab, GuiBuildSettings, _FilterTab, _FormattingTab, _HeadingsTab
_OutputTab
) )
from novelwriter.types import QtDialogApply, QtDialogClose, QtDialogSave from novelwriter.types import QtDialogApply, QtDialogClose, QtDialogSave
@@ -52,14 +51,8 @@ def testToolBuildSettings_Init(qtbot, nwGUI, projPath, mockRnd):
bSettings.loadContent() bSettings.loadContent()
# Flip through pages # Flip through pages
bSettings.sidebar._group.button(bSettings.OPT_OUTPUT).click() bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 1).click()
assert isinstance(bSettings.toolStack.currentWidget(), _OutputTab) assert isinstance(bSettings.toolStack.currentWidget(), _FormattingTab)
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_HEADINGS).click() bSettings.sidebar._group.button(bSettings.OPT_HEADINGS).click()
assert isinstance(bSettings.toolStack.currentWidget(), _HeadingsTab) assert isinstance(bSettings.toolStack.currentWidget(), _HeadingsTab)
@@ -484,8 +477,8 @@ def testToolBuildSettings_Headings(qtbot, nwGUI):
@pytest.mark.gui @pytest.mark.gui
def testToolBuildSettings_Content(qtbot, nwGUI): def testToolBuildSettings_FormatTextContent(qtbot, nwGUI):
"""Test the Content Tab of the GuiBuildSettings dialog.""" """Test the Text Content settings."""
build = BuildSettings() build = BuildSettings()
build.setValue("text.includeBodyText", False) build.setValue("text.includeBodyText", False)
@@ -501,34 +494,34 @@ def testToolBuildSettings_Content(qtbot, nwGUI):
bSettings.show() bSettings.show()
bSettings.loadContent() bSettings.loadContent()
contTab = bSettings.optTabContent fmtTab = bSettings.optTabFormatting
bSettings.sidebar._group.button(bSettings.OPT_CONTENT).click() bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 1).click()
assert bSettings.toolStack.currentWidget() is contTab assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values # Check initial values
assert contTab.incBodyText.isChecked() is False assert fmtTab.incBodyText.isChecked() is False
assert contTab.incSynopsis.isChecked() is False assert fmtTab.incSynopsis.isChecked() is False
assert contTab.incComments.isChecked() is False assert fmtTab.incComments.isChecked() is False
assert contTab.incKeywords.isChecked() is False assert fmtTab.incKeywords.isChecked() is False
assert contTab.ignoredKeywords.text() == "" assert fmtTab.ignoredKeywords.text() == ""
assert contTab.addNoteHead.isChecked() is False assert fmtTab.addNoteHead.isChecked() is False
# Toggle switches # Toggle switches
contTab.incBodyText.setChecked(True) fmtTab.incBodyText.setChecked(True)
contTab.incSynopsis.setChecked(True) fmtTab.incSynopsis.setChecked(True)
contTab.incComments.setChecked(True) fmtTab.incComments.setChecked(True)
contTab.incKeywords.setChecked(True) fmtTab.incKeywords.setChecked(True)
contTab.addNoteHead.setChecked(True) fmtTab.addNoteHead.setChecked(True)
# Test cleanup of ignored keywords # Test cleanup of ignored keywords
contTab.ignoredKeywords.setText("@stuff, @pizza, @object") # First two are invalid fmtTab.ignoredKeywords.setText("@stuff, @pizza, @object") # First two are invalid
contTab._updateIgnoredKeywords("@custom") # Adding a new should trigger cleanup fmtTab._updateIgnoredKeywords("@custom") # Adding a new should trigger cleanup
assert contTab.ignoredKeywords.text() in ("@custom, @object", "@object, @custom") assert fmtTab.ignoredKeywords.text() in ("@custom, @object", "@object, @custom")
# Save values # Save values
contTab.saveContent() fmtTab.saveContent()
assert build.getBool("text.includeBodyText") is True assert build.getBool("text.includeBodyText") is True
assert build.getBool("text.includeSynopsis") is True assert build.getBool("text.includeSynopsis") is True
@@ -544,8 +537,8 @@ def testToolBuildSettings_Content(qtbot, nwGUI):
@pytest.mark.gui @pytest.mark.gui
def testToolBuildSettings_Format(monkeypatch, qtbot, nwGUI): def testToolBuildSettings_FormatTextFormat(monkeypatch, qtbot, nwGUI):
"""Test the Format Tab of the GuiBuildSettings dialog.""" """Test the Text Format settings."""
build = BuildSettings() build = BuildSettings()
build.setValue("format.buildLang", "en_US") build.setValue("format.buildLang", "en_US")
@@ -558,26 +551,13 @@ def testToolBuildSettings_Format(monkeypatch, qtbot, nwGUI):
build.setValue("format.keepBreaks", True) build.setValue("format.keepBreaks", True)
build.setValue("format.showDialogue", False) 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 # Create the dialog and populate it
bSettings = GuiBuildSettings(nwGUI, build) bSettings = GuiBuildSettings(nwGUI, build)
bSettings.show() bSettings.show()
bSettings.loadContent() bSettings.loadContent()
fmtTab = bSettings.optTabFormat fmtTab = bSettings.optTabFormatting
bSettings.sidebar._group.button(bSettings.OPT_FORMAT).click() bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 2).click()
assert bSettings.toolStack.currentWidget() is fmtTab assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values # Check initial values
@@ -589,19 +569,6 @@ def testToolBuildSettings_Format(monkeypatch, qtbot, nwGUI):
assert fmtTab.keepBreaks.isChecked() is True assert fmtTab.keepBreaks.isChecked() is True
assert fmtTab.showDialogue.isChecked() is False 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 # Change values
testFont = QFont("Arial", 11) testFont = QFont("Arial", 11)
fmtTab._textFont = testFont fmtTab._textFont = testFont
@@ -614,13 +581,6 @@ def testToolBuildSettings_Format(monkeypatch, qtbot, nwGUI):
fmtTab.keepBreaks.setChecked(False) fmtTab.keepBreaks.setChecked(False)
fmtTab.showDialogue.setChecked(True) 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 # Save values
fmtTab.saveContent() fmtTab.saveContent()
@@ -633,19 +593,6 @@ def testToolBuildSettings_Format(monkeypatch, qtbot, nwGUI):
assert build.getBool("format.keepBreaks") is False assert build.getBool("format.keepBreaks") is False
assert build.getBool("format.showDialogue") is True 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 # Check that the font dialog doesn't fail
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
font = QFont() font = QFont()
@@ -662,50 +609,150 @@ def testToolBuildSettings_Format(monkeypatch, qtbot, nwGUI):
@pytest.mark.gui @pytest.mark.gui
def testToolBuildSettings_Output(qtbot, nwGUI): def testToolBuildSettings_FormatFirstLineIndent(monkeypatch, qtbot, nwGUI):
"""Test the Output Tab of the GuiBuildSettings dialog.""" """Test the First Line Indent settings."""
build = BuildSettings() build = BuildSettings()
build.setValue("odt.addColours", False) build.setValue("format.firstLineIndent", False)
build.setValue("html.addStyles", False) build.setValue("format.firstIndentWidth", 1.4)
build.setValue("format.indentFirstPar", False)
# Create the dialog and populate it # Create the dialog and populate it
bSettings = GuiBuildSettings(nwGUI, build) bSettings = GuiBuildSettings(nwGUI, build)
bSettings.show() bSettings.show()
bSettings.loadContent() bSettings.loadContent()
outTab = bSettings.optTabOutput fmtTab = bSettings.optTabFormatting
bSettings.sidebar._group.button(bSettings.OPT_OUTPUT).click() bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 3).click()
assert bSettings.toolStack.currentWidget() is outTab assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values # Check initial values
assert outTab.odtAddColours.isChecked() is False assert fmtTab.firstIndent.isChecked() is False
assert outTab.odtPageHeader.text() == nwHeadFmt.ODT_AUTO assert fmtTab.indentWidth.value() == 1.4
assert outTab.odtPageCountOffset.value() == 0 assert fmtTab.indentFirstPar.isChecked() is False
assert outTab.htmlAddStyles.isChecked() is False
assert outTab.htmlPreserveTabs.isChecked() is False
# Toggle all # Change values
outTab.odtAddColours.setChecked(True) fmtTab.firstIndent.setChecked(True)
outTab.htmlAddStyles.setChecked(True) fmtTab.indentWidth.setValue(2.0)
outTab.htmlPreserveTabs.setChecked(True) fmtTab.indentFirstPar.setChecked(True)
# Change Values
outTab.odtPageCountOffset.setValue(1)
outTab.odtPageHeader.setText("Stuff")
# Save values # Save values
outTab.saveContent() fmtTab.saveContent()
assert build.getBool("odt.addColours") is True assert build.getBool("format.firstLineIndent") is True
assert build.getStr("odt.pageHeader") == "Stuff" assert build.getFloat("format.firstIndentWidth") == 2.0
assert build.getInt("odt.pageCountOffset") == 1 assert build.getBool("format.indentFirstPar") is True
assert build.getBool("html.addStyles") is True
assert build.getBool("html.preserveTabs") is True # Finish
bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose))
# Reset header format # qtbot.stop()
outTab.btnPageHeader.click()
assert outTab.odtPageHeader.text() == nwHeadFmt.ODT_AUTO
@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 # Finish
bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose)) bSettings._dialogButtonClicked(bSettings.buttonBox.button(QtDialogClose))