839 lines
30 KiB
Python
839 lines
30 KiB
Python
"""
|
||
novelWriter – Manuscript Build Settings Dialog Tester
|
||
=====================================================
|
||
|
||
This file is a part of novelWriter
|
||
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
||
|
||
This program is free software: you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation, either version 3 of the License, or
|
||
(at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful, but
|
||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
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 <https://www.gnu.org/licenses/>.
|
||
""" # noqa
|
||
from __future__ import annotations
|
||
|
||
import pytest
|
||
|
||
from PyQt6.QtCore import pyqtSlot
|
||
from PyQt6.QtGui import QFont
|
||
from PyQt6.QtWidgets import QFontDialog
|
||
|
||
from novelwriter import SHARED
|
||
from novelwriter.common import describeFont
|
||
from novelwriter.constants import nwHeadFmt
|
||
from novelwriter.core.buildsettings import BuildSettings, FilterMode
|
||
from novelwriter.tools.manussettings import (
|
||
GuiBuildSettings, _FilterTab, _FormattingTab, _HeadingsTab
|
||
)
|
||
from novelwriter.types import QtDialogApply, QtDialogClose, QtDialogSave
|
||
|
||
from tests.tools import C, buildTestProject
|
||
|
||
|
||
@pytest.mark.gui
|
||
def testToolBuildSettings_Init(qtbot, nwGUI, projPath, mockRnd):
|
||
"""Test the initialisation of the GuiBuildSettings dialog."""
|
||
buildTestProject(nwGUI, projPath)
|
||
nwGUI.openProject(projPath)
|
||
build = BuildSettings()
|
||
|
||
# Create the dialog and populate it
|
||
bSettings = GuiBuildSettings(nwGUI, build)
|
||
bSettings.show()
|
||
bSettings.loadContent()
|
||
|
||
# Flip through pages
|
||
button = bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 1)
|
||
assert button is not None
|
||
button.click()
|
||
assert isinstance(bSettings.toolStack.currentWidget(), _FormattingTab)
|
||
|
||
button = bSettings.sidebar._group.button(bSettings.OPT_HEADINGS)
|
||
assert button is not None
|
||
button.click()
|
||
assert isinstance(bSettings.toolStack.currentWidget(), _HeadingsTab)
|
||
|
||
button = bSettings.sidebar._group.button(bSettings.OPT_FILTERS)
|
||
assert button is not None
|
||
button.click()
|
||
assert isinstance(bSettings.toolStack.currentWidget(), _FilterTab)
|
||
|
||
# Check dialog buttons
|
||
triggered = False
|
||
|
||
@pyqtSlot(BuildSettings)
|
||
def _testNewSettingsReady(new: BuildSettings):
|
||
nonlocal triggered
|
||
assert new.buildID == build.buildID
|
||
triggered = True
|
||
|
||
# Capture Apply button
|
||
with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000):
|
||
bSettings.newSettingsReady.connect(_testNewSettingsReady)
|
||
button = bSettings.buttonBox.button(QtDialogApply)
|
||
assert button is not None
|
||
bSettings._dialogButtonClicked(button)
|
||
|
||
assert triggered
|
||
|
||
# Capture Save button
|
||
triggered = False
|
||
|
||
with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000):
|
||
bSettings.newSettingsReady.connect(_testNewSettingsReady)
|
||
button = bSettings.buttonBox.button(QtDialogSave)
|
||
assert button is not None
|
||
bSettings._dialogButtonClicked(button)
|
||
|
||
assert triggered
|
||
|
||
# Close manually
|
||
# This pops the ask to save dialog, which is automatically handled
|
||
triggered = False
|
||
build._changed = True
|
||
bSettings.show()
|
||
|
||
with qtbot.waitSignal(bSettings.newSettingsReady, timeout=5000):
|
||
bSettings.newSettingsReady.connect(_testNewSettingsReady)
|
||
bSettings._build._changed = True
|
||
bSettings.close()
|
||
|
||
assert triggered
|
||
|
||
# Finish
|
||
button = bSettings.buttonBox.button(QtDialogClose)
|
||
assert button is not None
|
||
bSettings._dialogButtonClicked(button)
|
||
# qtbot.stop()
|
||
|
||
|
||
@pytest.mark.gui
|
||
def testToolBuildSettings_Filter(qtbot, nwGUI, projPath, mockRnd):
|
||
"""Test the Filter Tab of the GuiBuildSettings dialog."""
|
||
buildTestProject(nwGUI, projPath)
|
||
nwGUI.openProject(projPath)
|
||
build = BuildSettings()
|
||
|
||
switchMap = {
|
||
"incNovel": 1,
|
||
"incNotes": 2,
|
||
"incInactive": 3,
|
||
"novelRoot": 6,
|
||
"plotRoot": 7,
|
||
"charRoot": 8,
|
||
"worldRoot": 9,
|
||
}
|
||
|
||
hPlotDoc = SHARED.project.newFile("Main Plot", C.hPlotRoot)
|
||
hCharDoc = SHARED.project.newFile("Jane Doe", C.hCharRoot)
|
||
SHARED.project.tree[hPlotDoc].setActive(False) # type: ignore
|
||
|
||
# Create the dialog and populate it
|
||
bSettings = GuiBuildSettings(nwGUI, build)
|
||
bSettings.show()
|
||
bSettings.loadContent()
|
||
|
||
sBuild = bSettings._build
|
||
assert sBuild.buildID == build.buildID
|
||
|
||
filterTab = bSettings.optTabSelect
|
||
button = bSettings.sidebar._group.button(bSettings.OPT_FILTERS)
|
||
assert button is not None
|
||
button.click()
|
||
assert bSettings.toolStack.currentWidget() is filterTab
|
||
|
||
# Check content
|
||
assert filterTab.optTree.topLevelItemCount() == 4 # The 4 root folders
|
||
assert filterTab.filterOpt._index == 10 # 2 headers, 1 sep, 3 opt and 4 roots
|
||
|
||
# Un-toggle note folders
|
||
filterTab.filterOpt._widgets[switchMap["worldRoot"]].setChecked(False) # World Root
|
||
assert filterTab.optTree.topLevelItemCount() == 3
|
||
assert C.hWorldRoot in sBuild._skipRoot
|
||
|
||
filterTab.filterOpt._widgets[switchMap["charRoot"]].setChecked(False) # Char Root
|
||
assert filterTab.optTree.topLevelItemCount() == 2
|
||
assert C.hCharRoot in sBuild._skipRoot
|
||
|
||
filterTab.filterOpt._widgets[switchMap["plotRoot"]].setChecked(False) # Plot Root
|
||
assert filterTab.optTree.topLevelItemCount() == 1
|
||
assert C.hPlotRoot in sBuild._skipRoot
|
||
|
||
# Reset Plot and Char
|
||
filterTab.filterOpt._widgets[switchMap["plotRoot"]].setChecked(True)
|
||
filterTab.filterOpt._widgets[switchMap["charRoot"]].setChecked(True)
|
||
assert filterTab.optTree.topLevelItemCount() == 3
|
||
|
||
# Switch off novel docs
|
||
filterTab.filterOpt._widgets[switchMap["incNovel"]].setChecked(False)
|
||
assert sBuild.buildItemFilter(SHARED.project) == {
|
||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||
C.hTitlePage: (False, FilterMode.FILTERED),
|
||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||
C.hChapterDoc: (False, FilterMode.FILTERED),
|
||
C.hSceneDoc: (False, FilterMode.FILTERED),
|
||
C.hPlotRoot: (False, FilterMode.SKIPPED),
|
||
hPlotDoc: (False, FilterMode.FILTERED),
|
||
C.hCharRoot: (False, FilterMode.SKIPPED),
|
||
hCharDoc: (False, FilterMode.FILTERED),
|
||
C.hWorldRoot: (False, FilterMode.SKIPPED),
|
||
C.hTrashRoot: (False, FilterMode.SKIPPED),
|
||
}
|
||
|
||
# Switch on note docs
|
||
filterTab.filterOpt._widgets[switchMap["incNotes"]].setChecked(True)
|
||
assert sBuild.buildItemFilter(SHARED.project) == {
|
||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||
C.hTitlePage: (False, FilterMode.FILTERED),
|
||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||
C.hChapterDoc: (False, FilterMode.FILTERED),
|
||
C.hSceneDoc: (False, FilterMode.FILTERED),
|
||
C.hPlotRoot: (False, FilterMode.SKIPPED),
|
||
hPlotDoc: (False, FilterMode.FILTERED), # Set to inactive
|
||
C.hCharRoot: (False, FilterMode.SKIPPED),
|
||
hCharDoc: (True, FilterMode.FILTERED), # Now enabled
|
||
C.hWorldRoot: (False, FilterMode.SKIPPED),
|
||
C.hTrashRoot: (False, FilterMode.SKIPPED),
|
||
}
|
||
|
||
# Switch on inactive docs
|
||
filterTab.filterOpt._widgets[switchMap["incInactive"]].setChecked(True)
|
||
assert sBuild.buildItemFilter(SHARED.project) == {
|
||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||
C.hTitlePage: (False, FilterMode.FILTERED),
|
||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||
C.hChapterDoc: (False, FilterMode.FILTERED),
|
||
C.hSceneDoc: (False, FilterMode.FILTERED),
|
||
C.hPlotRoot: (False, FilterMode.SKIPPED),
|
||
hPlotDoc: (True, FilterMode.FILTERED), # Now enabled
|
||
C.hCharRoot: (False, FilterMode.SKIPPED),
|
||
hCharDoc: (True, FilterMode.FILTERED),
|
||
C.hWorldRoot: (False, FilterMode.SKIPPED),
|
||
C.hTrashRoot: (False, FilterMode.SKIPPED),
|
||
}
|
||
|
||
# Set chapter and scene docs to included
|
||
filterTab._treeMap[C.hChapterDoc].setSelected(True)
|
||
filterTab._treeMap[C.hSceneDoc].setSelected(True)
|
||
filterTab.includedButton.click()
|
||
assert sBuild.buildItemFilter(SHARED.project) == {
|
||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||
C.hTitlePage: (False, FilterMode.FILTERED),
|
||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||
C.hChapterDoc: (True, FilterMode.INCLUDED), # Now included
|
||
C.hSceneDoc: (True, FilterMode.INCLUDED), # Now included
|
||
C.hPlotRoot: (False, FilterMode.SKIPPED),
|
||
hPlotDoc: (True, FilterMode.FILTERED),
|
||
C.hCharRoot: (False, FilterMode.SKIPPED),
|
||
hCharDoc: (True, FilterMode.FILTERED),
|
||
C.hWorldRoot: (False, FilterMode.SKIPPED),
|
||
C.hTrashRoot: (False, FilterMode.SKIPPED),
|
||
}
|
||
|
||
# Set char and plot docs to excluded
|
||
filterTab.optTree.clearSelection()
|
||
filterTab._treeMap[hPlotDoc].setSelected(True) # type: ignore
|
||
filterTab._treeMap[hCharDoc].setSelected(True) # type: ignore
|
||
filterTab.excludedButton.click()
|
||
assert sBuild.buildItemFilter(SHARED.project) == {
|
||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||
C.hTitlePage: (False, FilterMode.FILTERED),
|
||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||
C.hChapterDoc: (True, FilterMode.INCLUDED),
|
||
C.hSceneDoc: (True, FilterMode.INCLUDED),
|
||
C.hPlotRoot: (False, FilterMode.SKIPPED),
|
||
hPlotDoc: (False, FilterMode.EXCLUDED), # Now excluded
|
||
C.hCharRoot: (False, FilterMode.SKIPPED),
|
||
hCharDoc: (False, FilterMode.EXCLUDED), # Now excluded
|
||
C.hWorldRoot: (False, FilterMode.SKIPPED),
|
||
C.hTrashRoot: (False, FilterMode.SKIPPED),
|
||
}
|
||
|
||
# Switch on novel docs
|
||
filterTab.filterOpt._widgets[switchMap["incNovel"]].setChecked(True)
|
||
assert sBuild.buildItemFilter(SHARED.project) == {
|
||
C.hNovelRoot: (False, FilterMode.SKIPPED),
|
||
C.hTitlePage: (True, FilterMode.FILTERED), # Now enabled
|
||
C.hChapterDir: (False, FilterMode.SKIPPED),
|
||
C.hChapterDoc: (True, FilterMode.INCLUDED),
|
||
C.hSceneDoc: (True, FilterMode.INCLUDED),
|
||
C.hPlotRoot: (False, FilterMode.SKIPPED),
|
||
hPlotDoc: (False, FilterMode.EXCLUDED),
|
||
C.hCharRoot: (False, FilterMode.SKIPPED),
|
||
hCharDoc: (False, FilterMode.EXCLUDED),
|
||
C.hWorldRoot: (False, FilterMode.SKIPPED),
|
||
C.hTrashRoot: (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 sBuild.buildItemFilter(SHARED.project) == {
|
||
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),
|
||
C.hTrashRoot: (False, FilterMode.SKIPPED),
|
||
}
|
||
|
||
# Set everything back to filtered
|
||
filterTab.optTree.clearSelection()
|
||
filterTab._treeMap[C.hNovelRoot].setSelected(True)
|
||
filterTab._treeMap[C.hSceneDoc].setSelected(True)
|
||
filterTab._treeMap[hPlotDoc].setSelected(True) # type: ignore
|
||
filterTab._treeMap[hCharDoc].setSelected(True) # type: ignore
|
||
filterTab.resetButton.click()
|
||
assert sBuild.buildItemFilter(SHARED.project) == {
|
||
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: (True, FilterMode.FILTERED),
|
||
C.hCharRoot: (False, FilterMode.SKIPPED),
|
||
hCharDoc: (True, FilterMode.FILTERED),
|
||
C.hWorldRoot: (False, FilterMode.SKIPPED),
|
||
C.hTrashRoot: (False, FilterMode.SKIPPED),
|
||
}
|
||
|
||
# Check handling of invalid project items
|
||
assert list(filterTab._treeMap.keys()) == [
|
||
C.hNovelRoot, C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
||
C.hPlotRoot, hPlotDoc, C.hCharRoot, hCharDoc,
|
||
]
|
||
SHARED.project.tree[hCharDoc].setRoot(None) # type: ignore
|
||
SHARED.project.tree[hPlotDoc].setParent(None) # type: ignore
|
||
filterTab._populateTree()
|
||
assert list(filterTab._treeMap.keys()) == [
|
||
C.hNovelRoot, C.hTitlePage, C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
||
C.hPlotRoot, C.hCharRoot
|
||
]
|
||
|
||
# Finish
|
||
button = bSettings.buttonBox.button(QtDialogClose)
|
||
assert button is not None
|
||
bSettings._dialogButtonClicked(button)
|
||
# qtbot.stop()
|
||
|
||
|
||
@pytest.mark.gui
|
||
def testToolBuildSettings_Headings(qtbot, nwGUI):
|
||
"""Test the Headings Tab of the GuiBuildSettings dialog."""
|
||
build = BuildSettings()
|
||
|
||
ttTitle = f"Part: {nwHeadFmt.TITLE}"
|
||
chTitle = f"Chapter: {nwHeadFmt.TITLE}"
|
||
unTitle = f"Interlude: {nwHeadFmt.TITLE}"
|
||
scTitle = f"Scene: {nwHeadFmt.TITLE}"
|
||
shTitle = f"Hard Scene: {nwHeadFmt.TITLE}"
|
||
sxTitle = f"Section: {nwHeadFmt.TITLE}"
|
||
|
||
build.setValue("headings.fmtPart", ttTitle)
|
||
build.setValue("headings.fmtChapter", chTitle)
|
||
build.setValue("headings.fmtUnnumbered", unTitle)
|
||
build.setValue("headings.fmtScene", scTitle)
|
||
build.setValue("headings.fmtAltScene", shTitle)
|
||
build.setValue("headings.fmtSection", sxTitle)
|
||
build.setValue("headings.hideScene", False)
|
||
build.setValue("headings.hideSection", False)
|
||
|
||
# Create the dialog and populate it
|
||
bSettings = GuiBuildSettings(nwGUI, build)
|
||
bSettings.show()
|
||
bSettings.loadContent()
|
||
|
||
headTab = bSettings.optTabHeadings
|
||
button = bSettings.sidebar._group.button(bSettings.OPT_HEADINGS)
|
||
assert button is not None
|
||
button.click()
|
||
assert bSettings.toolStack.currentWidget() is headTab
|
||
|
||
# Check initial values
|
||
assert headTab.fmtPart.text() == ttTitle
|
||
assert headTab.fmtChapter.text() == chTitle
|
||
assert headTab.fmtUnnumbered.text() == unTitle
|
||
assert headTab.fmtScene.text() == scTitle
|
||
assert headTab.fmtAScene.text() == shTitle
|
||
assert headTab.fmtSection.text() == sxTitle
|
||
assert headTab.swtScene.isChecked() is False
|
||
assert headTab.swtSection.isChecked() is False
|
||
|
||
# Edit in Turn
|
||
# ============
|
||
|
||
# Nothing to apply
|
||
assert headTab._editing == 0
|
||
assert headTab.editTextBox.isEnabled() is False
|
||
headTab.btnApply.click()
|
||
assert headTab.editTextBox.isEnabled() is False
|
||
|
||
# Title
|
||
headTab.btnPart.click()
|
||
assert headTab._editing == headTab.EDIT_TITLE
|
||
assert headTab.editTextBox.isEnabled() is True
|
||
assert headTab.editTextBox.toPlainText() == ttTitle
|
||
headTab.btnApply.click()
|
||
assert headTab.editTextBox.isEnabled() is False
|
||
|
||
# Chapter
|
||
headTab.btnChapter.click()
|
||
assert headTab._editing == headTab.EDIT_CHAPTER
|
||
assert headTab.editTextBox.isEnabled() is True
|
||
assert headTab.editTextBox.toPlainText() == chTitle
|
||
headTab.btnApply.click()
|
||
assert headTab.editTextBox.isEnabled() is False
|
||
|
||
# Unnumbered
|
||
headTab.btnUnnumbered.click()
|
||
assert headTab._editing == headTab.EDIT_UNNUM
|
||
assert headTab.editTextBox.isEnabled() is True
|
||
assert headTab.editTextBox.toPlainText() == unTitle
|
||
headTab.btnApply.click()
|
||
assert headTab.editTextBox.isEnabled() is False
|
||
|
||
# Scene
|
||
headTab.btnScene.click()
|
||
assert headTab._editing == headTab.EDIT_SCENE
|
||
assert headTab.editTextBox.isEnabled() is True
|
||
assert headTab.editTextBox.toPlainText() == scTitle
|
||
headTab.btnApply.click()
|
||
assert headTab.editTextBox.isEnabled() is False
|
||
|
||
# Hard Scene
|
||
headTab.btnAScene.click()
|
||
assert headTab._editing == headTab.EDIT_HSCENE
|
||
assert headTab.editTextBox.isEnabled() is True
|
||
assert headTab.editTextBox.toPlainText() == shTitle
|
||
headTab.btnApply.click()
|
||
assert headTab.editTextBox.isEnabled() is False
|
||
|
||
# Section
|
||
headTab.btnSection.click()
|
||
assert headTab._editing == headTab.EDIT_SECTION
|
||
assert headTab.editTextBox.isEnabled() is True
|
||
assert headTab.editTextBox.toPlainText() == sxTitle
|
||
headTab.btnApply.click()
|
||
assert headTab.editTextBox.isEnabled() is False
|
||
|
||
# Edit a Heading
|
||
# ==============
|
||
sBuild = bSettings._build
|
||
assert sBuild.buildID == build.buildID
|
||
|
||
# Create new format of all bits
|
||
headTab.btnChapter.click()
|
||
allFmt = (
|
||
f"{nwHeadFmt.TITLE}{nwHeadFmt.CH_NUM}{nwHeadFmt.CH_WORD}{nwHeadFmt.CH_ROMU}"
|
||
f"{nwHeadFmt.CH_ROML}{nwHeadFmt.SC_NUM}{nwHeadFmt.SC_ABS}"
|
||
)
|
||
headTab.editTextBox.clear()
|
||
assert headTab.editTextBox.toPlainText() == ""
|
||
headTab.aInsTitle.trigger()
|
||
headTab.aInsChNum.trigger()
|
||
headTab.aInsChWord.trigger()
|
||
headTab.aInsChRomU.trigger()
|
||
headTab.aInsChRomL.trigger()
|
||
headTab.aInsScNum.trigger()
|
||
headTab.aInsScAbs.trigger()
|
||
assert headTab.editTextBox.toPlainText() == allFmt
|
||
headTab.btnApply.click()
|
||
assert sBuild.getStr("headings.fmtChapter") == allFmt
|
||
|
||
# Check complex format
|
||
headTab.btnChapter.click()
|
||
headTab.editTextBox.setPlainText(f"Chapter {nwHeadFmt.CH_NUM}\n{nwHeadFmt.TITLE}\n")
|
||
headTab.btnApply.click()
|
||
assert sBuild.getStr("headings.fmtChapter") == (
|
||
f"Chapter {nwHeadFmt.CH_NUM}{nwHeadFmt.BR}{nwHeadFmt.TITLE}"
|
||
)
|
||
|
||
# Set all to plain title
|
||
headTab.btnPart.click()
|
||
headTab.editTextBox.setPlainText(nwHeadFmt.TITLE)
|
||
headTab.btnApply.click()
|
||
assert sBuild.getStr("headings.fmtPart") == nwHeadFmt.TITLE
|
||
|
||
headTab.btnChapter.click()
|
||
headTab.editTextBox.setPlainText(nwHeadFmt.TITLE)
|
||
headTab.btnApply.click()
|
||
assert sBuild.getStr("headings.fmtChapter") == nwHeadFmt.TITLE
|
||
|
||
headTab.btnUnnumbered.click()
|
||
headTab.editTextBox.setPlainText(nwHeadFmt.TITLE)
|
||
headTab.btnApply.click()
|
||
assert sBuild.getStr("headings.fmtUnnumbered") == nwHeadFmt.TITLE
|
||
|
||
headTab.btnScene.click()
|
||
headTab.editTextBox.setPlainText(nwHeadFmt.TITLE)
|
||
headTab.btnApply.click()
|
||
assert sBuild.getStr("headings.fmtScene") == nwHeadFmt.TITLE
|
||
|
||
headTab.btnAScene.click()
|
||
headTab.editTextBox.setPlainText(nwHeadFmt.TITLE)
|
||
headTab.btnApply.click()
|
||
assert sBuild.getStr("headings.fmtAltScene") == nwHeadFmt.TITLE
|
||
|
||
headTab.btnSection.click()
|
||
headTab.editTextBox.setPlainText(nwHeadFmt.TITLE)
|
||
headTab.btnApply.click()
|
||
assert sBuild.getStr("headings.fmtSection") == nwHeadFmt.TITLE
|
||
|
||
# Check hide switches
|
||
headTab.swtScene.setChecked(True)
|
||
headTab.swtSection.setChecked(True)
|
||
headTab.saveContent()
|
||
sBuild = bSettings._build
|
||
assert sBuild.buildID == build.buildID
|
||
|
||
assert sBuild.getBool("headings.hideScene") is True
|
||
assert sBuild.getBool("headings.hideSection") is True
|
||
|
||
# Finish
|
||
button = bSettings.buttonBox.button(QtDialogClose)
|
||
assert button is not None
|
||
bSettings._dialogButtonClicked(button)
|
||
# qtbot.stop()
|
||
|
||
|
||
@pytest.mark.gui
|
||
def testToolBuildSettings_FormatTextContent(qtbot, nwGUI):
|
||
"""Test the Text Content settings."""
|
||
build = BuildSettings()
|
||
|
||
build.setValue("text.includeBodyText", False)
|
||
build.setValue("text.includeSynopsis", False)
|
||
build.setValue("text.includeComments", False)
|
||
build.setValue("text.includeStory", False)
|
||
build.setValue("text.includeNotes", False)
|
||
build.setValue("text.includeKeywords", False)
|
||
build.setValue("text.ignoredKeywords", "")
|
||
|
||
build.setValue("text.addNoteHeadings", False)
|
||
|
||
# Create the dialog and populate it
|
||
bSettings = GuiBuildSettings(nwGUI, build)
|
||
bSettings.show()
|
||
bSettings.loadContent()
|
||
|
||
fmtTab = bSettings.optTabFormatting
|
||
button = bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 1)
|
||
assert button is not None
|
||
button.click()
|
||
assert bSettings.toolStack.currentWidget() is fmtTab
|
||
|
||
# Check initial values
|
||
assert fmtTab.incBodyText.isChecked() is False
|
||
assert fmtTab.incSynopsis.isChecked() is False
|
||
assert fmtTab.incComments.isChecked() is False
|
||
assert fmtTab.incStory.isChecked() is False
|
||
assert fmtTab.incNotes.isChecked() is False
|
||
assert fmtTab.incKeywords.isChecked() is False
|
||
assert fmtTab.ignoredKeywords.text() == ""
|
||
|
||
assert fmtTab.addNoteHead.isChecked() is False
|
||
|
||
# Toggle switches
|
||
fmtTab.incBodyText.setChecked(True)
|
||
fmtTab.incSynopsis.setChecked(True)
|
||
fmtTab.incComments.setChecked(True)
|
||
fmtTab.incStory.setChecked(True)
|
||
fmtTab.incNotes.setChecked(True)
|
||
fmtTab.incKeywords.setChecked(True)
|
||
|
||
fmtTab.addNoteHead.setChecked(True)
|
||
|
||
# Test cleanup of ignored keywords
|
||
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
|
||
fmtTab.saveContent()
|
||
sBuild = bSettings._build
|
||
assert sBuild.buildID == build.buildID
|
||
|
||
assert sBuild.getBool("text.includeBodyText") is True
|
||
assert sBuild.getBool("text.includeSynopsis") is True
|
||
assert sBuild.getBool("text.includeComments") is True
|
||
assert sBuild.getBool("text.includeStory") is True
|
||
assert sBuild.getBool("text.includeNotes") is True
|
||
assert sBuild.getBool("text.includeKeywords") is True
|
||
assert sBuild.getStr("text.ignoredKeywords") in ("@custom, @object", "@object, @custom")
|
||
|
||
assert sBuild.getBool("text.addNoteHeadings") is True
|
||
|
||
# Finish
|
||
button = bSettings.buttonBox.button(QtDialogClose)
|
||
assert button is not None
|
||
bSettings._dialogButtonClicked(button)
|
||
# qtbot.stop()
|
||
|
||
|
||
@pytest.mark.gui
|
||
def testToolBuildSettings_FormatTextFormat(monkeypatch, qtbot, nwGUI):
|
||
"""Test the Text Format settings."""
|
||
build = BuildSettings()
|
||
|
||
build.setValue("format.buildLang", "en_US")
|
||
build.setValue("format.textFont", "") # Will fall back to config value
|
||
build.setValue("format.lineHeight", 1.2)
|
||
|
||
build.setValue("format.justifyText", False)
|
||
build.setValue("format.stripUnicode", False)
|
||
build.setValue("format.replaceTabs", False)
|
||
build.setValue("format.keepBreaks", True)
|
||
build.setValue("format.showDialogue", False)
|
||
|
||
# Create the dialog and populate it
|
||
bSettings = GuiBuildSettings(nwGUI, build)
|
||
bSettings.show()
|
||
bSettings.loadContent()
|
||
|
||
fmtTab = bSettings.optTabFormatting
|
||
button = bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 2)
|
||
assert button is not None
|
||
button.click()
|
||
assert bSettings.toolStack.currentWidget() is fmtTab
|
||
|
||
# Check initial values
|
||
assert fmtTab.lineHeight.value() == 1.2
|
||
|
||
assert fmtTab.justifyText.isChecked() is False
|
||
assert fmtTab.stripUnicode.isChecked() is False
|
||
assert fmtTab.replaceTabs.isChecked() is False
|
||
assert fmtTab.keepBreaks.isChecked() is True
|
||
assert fmtTab.showDialogue.isChecked() is False
|
||
|
||
# Change values
|
||
testFont = QFont("Arial", 11)
|
||
fmtTab._textFont = testFont
|
||
fmtTab.textFont.setText(describeFont(testFont))
|
||
fmtTab.lineHeight.setValue(1.15)
|
||
|
||
fmtTab.justifyText.setChecked(True)
|
||
fmtTab.stripUnicode.setChecked(True)
|
||
fmtTab.replaceTabs.setChecked(True)
|
||
fmtTab.keepBreaks.setChecked(False)
|
||
fmtTab.showDialogue.setChecked(True)
|
||
|
||
# Save values
|
||
fmtTab.saveContent()
|
||
sBuild = bSettings._build
|
||
assert sBuild.buildID == build.buildID
|
||
|
||
assert sBuild.getStr("format.textFont") == testFont.toString()
|
||
assert sBuild.getFloat("format.lineHeight") == 1.15
|
||
|
||
assert sBuild.getBool("format.justifyText") is True
|
||
assert sBuild.getBool("format.stripUnicode") is True
|
||
assert sBuild.getBool("format.replaceTabs") is True
|
||
assert sBuild.getBool("format.keepBreaks") is False
|
||
assert sBuild.getBool("format.showDialogue") is True
|
||
|
||
# Check that the font dialog doesn't fail
|
||
with monkeypatch.context() as mp:
|
||
font = QFont()
|
||
font.setFamily("Times")
|
||
font.setPointSize(10)
|
||
mp.setattr(QFontDialog, "getFont", lambda *a, **k: (font, True))
|
||
|
||
fmtTab.btnTextFont.click()
|
||
assert fmtTab._textFont == font
|
||
|
||
# Finish
|
||
button = bSettings.buttonBox.button(QtDialogClose)
|
||
assert button is not None
|
||
bSettings._dialogButtonClicked(button)
|
||
# qtbot.stop()
|
||
|
||
|
||
@pytest.mark.gui
|
||
def testToolBuildSettings_FormatFirstLineIndent(monkeypatch, qtbot, nwGUI):
|
||
"""Test the First Line Indent settings."""
|
||
build = BuildSettings()
|
||
|
||
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()
|
||
|
||
fmtTab = bSettings.optTabFormatting
|
||
button = bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 3)
|
||
assert button is not None
|
||
button.click()
|
||
assert bSettings.toolStack.currentWidget() is fmtTab
|
||
|
||
# Check initial values
|
||
assert fmtTab.firstIndent.isChecked() is False
|
||
assert fmtTab.indentWidth.value() == 1.4
|
||
assert fmtTab.indentFirstPar.isChecked() is False
|
||
|
||
# Change values
|
||
fmtTab.firstIndent.setChecked(True)
|
||
fmtTab.indentWidth.setValue(2.0)
|
||
fmtTab.indentFirstPar.setChecked(True)
|
||
|
||
# Save values
|
||
fmtTab.saveContent()
|
||
sBuild = bSettings._build
|
||
assert sBuild.buildID == build.buildID
|
||
|
||
assert sBuild.getBool("format.firstLineIndent") is True
|
||
assert sBuild.getFloat("format.firstIndentWidth") == 2.0
|
||
assert sBuild.getBool("format.indentFirstPar") is True
|
||
|
||
# Finish
|
||
button = bSettings.buttonBox.button(QtDialogClose)
|
||
assert button is not None
|
||
bSettings._dialogButtonClicked(button)
|
||
# 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
|
||
button = bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 4)
|
||
assert button is not None
|
||
button.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
|
||
button = bSettings.buttonBox.button(QtDialogClose)
|
||
assert button is not None
|
||
bSettings._dialogButtonClicked(button)
|
||
# qtbot.stop()
|
||
|
||
|
||
@pytest.mark.gui
|
||
def testToolBuildSettings_FormatOutput(qtbot, nwGUI):
|
||
"""Test the format-specific settings."""
|
||
build = BuildSettings()
|
||
|
||
build.setValue("doc.pageHeader", nwHeadFmt.DOC_AUTO)
|
||
build.setValue("doc.pageCountOffset", 0)
|
||
build.setValue("doc.colorHeadings", True)
|
||
build.setValue("doc.scaleHeadings", True)
|
||
build.setValue("doc.boldHeadings", True)
|
||
|
||
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
|
||
button = bSettings.sidebar._group.button(bSettings.OPT_FORMATTING + 5)
|
||
assert button is not None
|
||
button.click()
|
||
assert bSettings.toolStack.currentWidget() is fmtTab
|
||
|
||
# Check initial values
|
||
assert fmtTab.odtPageHeader.text() == nwHeadFmt.DOC_AUTO
|
||
assert fmtTab.odtPageCountOffset.value() == 0
|
||
assert fmtTab.colorHeadings.isChecked() is True
|
||
assert fmtTab.scaleHeadings.isChecked() is True
|
||
assert fmtTab.boldHeadings.isChecked() is True
|
||
|
||
assert fmtTab.htmlAddStyles.isChecked() is False
|
||
assert fmtTab.htmlPreserveTabs.isChecked() is False
|
||
|
||
# Change Values
|
||
fmtTab.odtPageCountOffset.setValue(1)
|
||
fmtTab.odtPageHeader.setText("Stuff")
|
||
|
||
# Toggle all
|
||
fmtTab.colorHeadings.setChecked(False)
|
||
fmtTab.scaleHeadings.setChecked(False)
|
||
fmtTab.boldHeadings.setChecked(False)
|
||
fmtTab.htmlAddStyles.setChecked(True)
|
||
fmtTab.htmlPreserveTabs.setChecked(True)
|
||
|
||
# Save values
|
||
fmtTab.saveContent()
|
||
sBuild = bSettings._build
|
||
assert sBuild.buildID == build.buildID
|
||
|
||
assert sBuild.getStr("doc.pageHeader") == "Stuff"
|
||
assert sBuild.getInt("doc.pageCountOffset") == 1
|
||
assert sBuild.getBool("doc.colorHeadings") is False
|
||
assert sBuild.getBool("doc.scaleHeadings") is False
|
||
assert sBuild.getBool("doc.boldHeadings") is False
|
||
|
||
assert sBuild.getBool("html.addStyles") is True
|
||
assert sBuild.getBool("html.preserveTabs") is True
|
||
|
||
# Reset header format
|
||
fmtTab.btnPageHeader.click()
|
||
assert fmtTab.odtPageHeader.text() == nwHeadFmt.DOC_AUTO
|
||
|
||
# Finish
|
||
button = bSettings.buttonBox.button(QtDialogClose)
|
||
assert button is not None
|
||
bSettings._dialogButtonClicked(button)
|
||
# qtbot.stop()
|