Merge branch 'dev' into project_handling
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="1" timeStamp="2022-11-07 13:00:48">
|
||||
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="2" timeStamp="2022-11-07 13:00:48">
|
||||
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="5" autoCount="10" editTime="1000">
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
<author>Jane Smith</author>
|
||||
</project>
|
||||
<settings>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.0.7" hexVersion="0x020007f0" fileVersion="1.5" fileRevision="1" timeStamp="2023-06-03 18:18:23">
|
||||
<novelWriterXML appVersion="2.3a1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="2" timeStamp="2024-01-26 22:50:57">
|
||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="1" editTime="0">
|
||||
<name>New Project</name>
|
||||
<title>New Novel</title>
|
||||
<author>Jane Doe</author>
|
||||
</project>
|
||||
<settings>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.0.7" hexVersion="0x020007f0" fileVersion="1.5" fileRevision="1" timeStamp="2023-06-03 18:18:23">
|
||||
<novelWriterXML appVersion="2.3a1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="2" timeStamp="2024-01-26 22:50:57">
|
||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="1" editTime="0">
|
||||
<name>New Project</name>
|
||||
<title>New Novel</title>
|
||||
<author>Jane Doe</author>
|
||||
</project>
|
||||
<settings>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.1-beta1" hexVersion="0x020100b1" fileVersion="1.5" fileRevision="1" timeStamp="2023-07-20 20:33:41">
|
||||
<novelWriterXML appVersion="2.3a1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="2" timeStamp="2024-01-26 22:53:40">
|
||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="1" editTime="0">
|
||||
<name>New Project</name>
|
||||
<title>New Novel</title>
|
||||
<author>Jane Doe</author>
|
||||
</project>
|
||||
<settings>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.3-alpha1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="1" timeStamp="2023-12-29 14:34:07">
|
||||
<novelWriterXML appVersion="2.3a1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="2" timeStamp="2024-01-26 22:53:40">
|
||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="0" editTime="0">
|
||||
<name>Test Project A</name>
|
||||
<title>Test Project A</title>
|
||||
<author>Jane Doe</author>
|
||||
</project>
|
||||
<settings>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.3-alpha1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="1" timeStamp="2023-12-29 14:36:07">
|
||||
<novelWriterXML appVersion="2.3a1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="2" timeStamp="2024-01-26 22:53:40">
|
||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="1" autoCount="0" editTime="0">
|
||||
<name>Test Project B</name>
|
||||
<title>Test Project B</title>
|
||||
<author>Jane Doe</author>
|
||||
</project>
|
||||
<settings>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.2-alpha1" hexVersion="0x020200a1" fileVersion="1.5" fileRevision="1" timeStamp="2023-10-17 20:52:34">
|
||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="3" autoCount="2" editTime="4">
|
||||
<novelWriterXML appVersion="2.3a1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="2" timeStamp="2024-01-26 22:48:13">
|
||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="3" autoCount="2" editTime="3">
|
||||
<name>New Project</name>
|
||||
<title>New Novel</title>
|
||||
<author>Jane Doe</author>
|
||||
</project>
|
||||
<settings>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.0.7" hexVersion="0x020007f0" fileVersion="1.5" fileRevision="1" timeStamp="2023-06-03 18:18:30">
|
||||
<novelWriterXML appVersion="2.3a1" hexVersion="0x020300a1" fileVersion="1.5" fileRevision="2" timeStamp="2024-01-26 22:45:36">
|
||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="2" autoCount="1" editTime="0">
|
||||
<name>New Project</name>
|
||||
<title>New Novel</title>
|
||||
<author>Jane Doe</author>
|
||||
</project>
|
||||
<settings>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
{
|
||||
"meta": {
|
||||
"projectName": "Lorem Ipsum",
|
||||
"novelTitle": "Lorem Ipsum",
|
||||
"novelAuthor": "lipsum.com",
|
||||
"buildTime": 1687620769,
|
||||
"buildTimeStr": "2023-06-24 17:32:49"
|
||||
"buildTime": 1706306020,
|
||||
"buildTimeStr": "2024-01-26 22:53:40"
|
||||
},
|
||||
"text": {
|
||||
"css": [
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
{
|
||||
"meta": {
|
||||
"projectName": "Lorem Ipsum",
|
||||
"novelTitle": "Lorem Ipsum",
|
||||
"novelAuthor": "lipsum.com",
|
||||
"buildTime": 1687621222,
|
||||
"buildTimeStr": "2023-06-24 17:40:22"
|
||||
"buildTime": 1706306020,
|
||||
"buildTimeStr": "2024-01-26 22:53:40"
|
||||
},
|
||||
"text": {
|
||||
"nwd": [
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="1" timeStamp="2020-05-28 09:59:15">
|
||||
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="2" timeStamp="2020-05-28 09:59:15">
|
||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="0" autoCount="0" editTime="1000">
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
<author>Jay Doh</author>
|
||||
</project>
|
||||
<settings>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="1" timeStamp="2020-06-26 21:20:24">
|
||||
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="2" timeStamp="2020-06-26 21:20:24">
|
||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="5" autoCount="10" editTime="1000">
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
<author>Jay Doh</author>
|
||||
</project>
|
||||
<settings>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="1" timeStamp="2021-08-30 23:33:44">
|
||||
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="2" timeStamp="2021-08-30 23:33:44">
|
||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="5" autoCount="10" editTime="1000">
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
<author>Jay Doh</author>
|
||||
</project>
|
||||
<settings>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="1" timeStamp="2022-10-25 18:26:15">
|
||||
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="2" timeStamp="2022-10-25 18:26:15">
|
||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="5" autoCount="10" editTime="1000">
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
<author>Jay Doh</author>
|
||||
</project>
|
||||
<settings>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="1" timeStamp="2022-10-15 12:12:59">
|
||||
<novelWriterXML appVersion="2.0-rc1" hexVersion="0x020000c1" fileVersion="1.5" fileRevision="2" timeStamp="2022-10-15 12:12:59">
|
||||
<project id="d0f3fe10-c6e6-4310-8bfd-181eb4224eed" saveCount="5" autoCount="10" editTime="1000">
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
<author>Jay Doh</author>
|
||||
</project>
|
||||
<settings>
|
||||
|
||||
@@ -35,7 +35,7 @@ from PyQt5.QtCore import QUrl
|
||||
from novelwriter.common import (
|
||||
checkBool, checkFloat, checkHandle, checkInt, checkIntTuple, checkPath,
|
||||
checkString, checkStringNone, checkUuid, formatInt, formatTime,
|
||||
formatTimeStamp, fuzzyTime, getFileSize, hexToInt, isHandle, isItemClass,
|
||||
formatTimeStamp, formatVersion, fuzzyTime, getFileSize, hexToInt, isHandle, isItemClass,
|
||||
isItemLayout, isItemType, isTitleTag, jsonEncode, makeFileNameSafe, minmax,
|
||||
numberToRoman, NWConfigParser, openExternalPath, readTextFile, simplified,
|
||||
transferCase, xmlIndent, yesNo
|
||||
@@ -348,6 +348,17 @@ def testBaseCommon_formatTime():
|
||||
# END Test testBaseCommon_formatTime
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseCommon_formatVersion():
|
||||
"""Test the formatVersion function."""
|
||||
assert formatVersion("1.2") == "1.2"
|
||||
assert formatVersion("1.2a1") == "1.2 Alpha 1"
|
||||
assert formatVersion("1.2b2") == "1.2 Beta 2"
|
||||
assert formatVersion("1.2rc3") == "1.2 RC 3"
|
||||
|
||||
# END Test testBaseCommon_formatVersion
|
||||
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseCommon_simplified():
|
||||
"""Test the simplified function."""
|
||||
|
||||
@@ -230,7 +230,7 @@ def testCoreDocBuild_HTML(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
|
||||
assert error == []
|
||||
|
||||
copyfile(docFile, tstFile)
|
||||
assert cmpFiles(tstFile, cmpFile, ignoreLines=[6, 7])
|
||||
assert cmpFiles(tstFile, cmpFile, ignoreLines=[5, 6])
|
||||
|
||||
# Check Error Handling
|
||||
# ====================
|
||||
@@ -370,7 +370,7 @@ def testCoreDocBuild_NWD(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
|
||||
assert error == []
|
||||
|
||||
copyfile(docFile, tstFile)
|
||||
assert cmpFiles(tstFile, cmpFile, ignoreLines=[6, 7])
|
||||
assert cmpFiles(tstFile, cmpFile, ignoreLines=[5, 6])
|
||||
|
||||
# Check Error Handling
|
||||
# ====================
|
||||
|
||||
@@ -695,6 +695,7 @@ def testCoreIndex_ExtractData(mockGUI, fncPath, mockRnd):
|
||||
"This is a story about Jane Smith.\n\n"
|
||||
"Well, not really. She's still awesome though.\n"
|
||||
))
|
||||
|
||||
# Whole document
|
||||
cC, wC, pC = index.getCounts(nHandle)
|
||||
assert cC == 152
|
||||
@@ -798,6 +799,10 @@ def testCoreIndex_ExtractData(mockGUI, fncPath, mockRnd):
|
||||
# Extract stats
|
||||
assert index.getNovelWordCount(activeOnly=False) == 43
|
||||
assert index.getNovelWordCount(activeOnly=True) == 15
|
||||
assert index.getNovelWordCount(rootHandle=C.hNovelRoot, activeOnly=False) == 43
|
||||
assert index.getNovelWordCount(rootHandle=C.hNovelRoot, activeOnly=True) == 15
|
||||
assert index.getNovelWordCount(rootHandle=C.hWorldRoot, activeOnly=False) == 0
|
||||
assert index.getNovelWordCount(rootHandle=C.hWorldRoot, activeOnly=True) == 0
|
||||
assert index.getNovelTitleCounts(activeOnly=False) == [0, 3, 2, 3, 0]
|
||||
assert index.getNovelTitleCounts(activeOnly=True) == [0, 1, 2, 3, 0]
|
||||
|
||||
|
||||
@@ -121,27 +121,27 @@ def testCoreOptions_SetGet(mockGUI):
|
||||
assert options.setValue("GuiProjectSettings", "winWidth", 100) is True
|
||||
|
||||
# Set some values of different types
|
||||
assert options.setValue("GuiProjectDetails", "winWidth", 100) is True
|
||||
assert options.setValue("GuiProjectDetails", "winHeight", 12.34) is True
|
||||
assert options.setValue("GuiProjectDetails", "clearDouble", True) is True
|
||||
assert options.setValue("GuiNovelDetails", "winWidth", 100) is True
|
||||
assert options.setValue("GuiNovelDetails", "winHeight", 12.34) is True
|
||||
assert options.setValue("GuiNovelDetails", "clearDouble", True) is True
|
||||
assert options.setValue("GuiNovelView", "lastCol", nwColHidden) is True
|
||||
|
||||
# Generic get, doesn't check type
|
||||
assert options.getValue("GuiProjectDetails", "winWidth", None) == 100
|
||||
assert options.getValue("GuiProjectDetails", "winHeight", None) == 12.34
|
||||
assert options.getValue("GuiProjectDetails", "clearDouble", None) is True
|
||||
assert options.getValue("GuiProjectDetails", "mockItem", None) is None
|
||||
assert options.getValue("GuiNovelDetails", "winWidth", None) == 100
|
||||
assert options.getValue("GuiNovelDetails", "winHeight", None) == 12.34
|
||||
assert options.getValue("GuiNovelDetails", "clearDouble", None) is True
|
||||
assert options.getValue("GuiNovelDetails", "mockItem", None) is None
|
||||
|
||||
# Get type-specific
|
||||
assert options.getString("GuiProjectDetails", "winWidth", None) is None # type: ignore
|
||||
assert options.getString("GuiProjectDetails", "mockItem", None) is None # type: ignore
|
||||
assert options.getInt("GuiProjectDetails", "winWidth", None) == 100 # type: ignore
|
||||
assert options.getInt("GuiProjectDetails", "textFont", None) is None # type: ignore
|
||||
assert options.getInt("GuiProjectDetails", "mockItem", None) is None # type: ignore
|
||||
assert options.getFloat("GuiProjectDetails", "winWidth", None) == 100.0 # type: ignore
|
||||
assert options.getFloat("GuiProjectDetails", "mockItem", None) is None # type: ignore
|
||||
assert options.getBool("GuiProjectDetails", "clearDouble", None) is True # type: ignore
|
||||
assert options.getBool("GuiProjectDetails", "mockItem", None) is None # type: ignore
|
||||
assert options.getString("GuiNovelDetails", "winWidth", None) is None # type: ignore
|
||||
assert options.getString("GuiNovelDetails", "mockItem", None) is None # type: ignore
|
||||
assert options.getInt("GuiNovelDetails", "winWidth", None) == 100 # type: ignore
|
||||
assert options.getInt("GuiNovelDetails", "textFont", None) is None # type: ignore
|
||||
assert options.getInt("GuiNovelDetails", "mockItem", None) is None # type: ignore
|
||||
assert options.getFloat("GuiNovelDetails", "winWidth", None) == 100.0 # type: ignore
|
||||
assert options.getFloat("GuiNovelDetails", "mockItem", None) is None # type: ignore
|
||||
assert options.getBool("GuiNovelDetails", "clearDouble", None) is True # type: ignore
|
||||
assert options.getBool("GuiNovelDetails", "mockItem", None) is None # type: ignore
|
||||
assert options.getEnum("GuiNovelView", "lastCol", NovelTreeColumn, nwColHidden) == nwColHidden
|
||||
|
||||
# Get from non-existent groups
|
||||
|
||||
@@ -482,10 +482,6 @@ def testCoreProject_Methods(monkeypatch, mockGUI, fncPath, mockRnd):
|
||||
project.data.setName(" A Name ")
|
||||
assert project.data.name == "A Name"
|
||||
|
||||
# Project Title
|
||||
project.data.setTitle(" A Title ")
|
||||
assert project.data.title == "A Title"
|
||||
|
||||
# Project Author
|
||||
project.data.setAuthor(" Jane\tDoe ")
|
||||
assert project.data.author == "Jane Doe"
|
||||
|
||||
@@ -131,13 +131,12 @@ def testCoreProjectXML_ReadCurrent(monkeypatch, tstPaths, fncPath):
|
||||
assert xmlReader.state == XMLReadState.PARSED_OK
|
||||
assert xmlReader.xmlRoot == "novelWriterXML"
|
||||
assert xmlReader.xmlVersion == 0x0105
|
||||
assert xmlReader.xmlRevision == 1
|
||||
assert xmlReader.xmlRevision == 2
|
||||
assert xmlReader.appVersion == "2.0-rc1"
|
||||
assert xmlReader.hexVersion == 0x020000c1
|
||||
|
||||
# Check loaded data
|
||||
assert data.name == "Sample Project"
|
||||
assert data.title == "Sample Project"
|
||||
assert data.author == "Jane Smith"
|
||||
assert data.saveCount == 5
|
||||
assert data.autoCount == 10
|
||||
@@ -256,7 +255,6 @@ def testCoreProjectXML_ReadLegacy10(tstPaths, fncPath, mockRnd):
|
||||
|
||||
# Check loaded data
|
||||
assert data.name == "Sample Project"
|
||||
assert data.title == "Sample Project"
|
||||
assert data.author == "Jay Doh" # Only last author is preserved
|
||||
assert data.saveCount == 0 # Doesn't exist in 1.0
|
||||
assert data.autoCount == 0 # Doesn't exist in 1.0
|
||||
@@ -391,7 +389,6 @@ def testCoreProjectXML_ReadLegacy11(tstPaths, fncPath, mockRnd):
|
||||
|
||||
# Check loaded data
|
||||
assert data.name == "Sample Project"
|
||||
assert data.title == "Sample Project"
|
||||
assert data.author == "Jay Doh" # Only last author is preserved
|
||||
assert data.saveCount == 5
|
||||
assert data.autoCount == 10
|
||||
@@ -526,7 +523,6 @@ def testCoreProjectXML_ReadLegacy12(tstPaths, fncPath, mockRnd):
|
||||
|
||||
# Check loaded data
|
||||
assert data.name == "Sample Project"
|
||||
assert data.title == "Sample Project"
|
||||
assert data.author == "Jay Doh" # Only last author is preserved
|
||||
assert data.saveCount == 5
|
||||
assert data.autoCount == 10
|
||||
@@ -664,7 +660,6 @@ def testCoreProjectXML_ReadLegacy13(tstPaths, fncPath, mockRnd):
|
||||
|
||||
# Check loaded data
|
||||
assert data.name == "Sample Project"
|
||||
assert data.title == "Sample Project"
|
||||
assert data.author == "Jay Doh" # Only last author is preserved
|
||||
assert data.saveCount == 5
|
||||
assert data.autoCount == 10
|
||||
@@ -802,7 +797,6 @@ def testCoreProjectXML_ReadLegacy14(tstPaths, fncPath, mockRnd):
|
||||
|
||||
# Check loaded data
|
||||
assert data.name == "Sample Project"
|
||||
assert data.title == "Sample Project"
|
||||
assert data.author == "Jay Doh" # Only last author is preserved
|
||||
assert data.saveCount == 5
|
||||
assert data.autoCount == 10
|
||||
|
||||
@@ -22,9 +22,11 @@ from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from tools import getGuiItem
|
||||
|
||||
from PyQt5.QtGui import QFontDatabase, QKeyEvent
|
||||
from PyQt5.QtCore import QEvent, Qt
|
||||
from PyQt5.QtWidgets import QDialogButtonBox, QFileDialog, QFontDialog
|
||||
from PyQt5.QtWidgets import QAction, QDialogButtonBox, QFileDialog, QFontDialog
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.constants import nwConst, nwUnicode
|
||||
@@ -38,9 +40,13 @@ KEY_DELAY = 1
|
||||
def testDlgPreferences_Main(qtbot, monkeypatch, nwGUI, tstPaths):
|
||||
"""Test the preferences dialog loading."""
|
||||
monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda: [("en", "English [en]")])
|
||||
monkeypatch.setattr(GuiPreferences, "exec_", lambda *a: None)
|
||||
|
||||
# Load GUI with standard values
|
||||
prefs = GuiPreferences(nwGUI)
|
||||
nwGUI.mainMenu.aPreferences.activate(QAction.ActionEvent.Trigger)
|
||||
qtbot.waitUntil(lambda: getGuiItem("GuiPreferences") is not None, timeout=1000)
|
||||
prefs = getGuiItem("GuiPreferences")
|
||||
assert isinstance(prefs, GuiPreferences)
|
||||
prefs.show()
|
||||
|
||||
# Check Languages
|
||||
@@ -95,10 +101,6 @@ def testDlgPreferences_Actions(qtbot, monkeypatch, nwGUI):
|
||||
# Check Navigation
|
||||
vBar = prefs.mainForm.verticalScrollBar()
|
||||
old = -1
|
||||
with qtbot.waitSignal(vBar.valueChanged) as value:
|
||||
prefs.sidebar.button(0).click()
|
||||
assert value.args[0] > old
|
||||
old = value.args[0]
|
||||
with qtbot.waitSignal(vBar.valueChanged) as value:
|
||||
prefs.sidebar.button(1).click()
|
||||
assert value.args[0] > old
|
||||
@@ -107,6 +109,10 @@ def testDlgPreferences_Actions(qtbot, monkeypatch, nwGUI):
|
||||
prefs.sidebar.button(2).click()
|
||||
assert value.args[0] > old
|
||||
old = value.args[0]
|
||||
with qtbot.waitSignal(vBar.valueChanged) as value:
|
||||
prefs.sidebar.button(3).click()
|
||||
assert value.args[0] > old
|
||||
old = value.args[0]
|
||||
|
||||
# Check Search
|
||||
prefs.searchText.setText("Display language")
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
"""
|
||||
novelWriter – Project Details Dialog Class Tester
|
||||
=================================================
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
|
||||
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/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from tools import getGuiItem
|
||||
|
||||
from PyQt5.QtWidgets import QAction
|
||||
|
||||
from novelwriter import SHARED
|
||||
from novelwriter.dialogs.projdetails import GuiProjectDetails
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testDlgProjDetails_Dialog(qtbot, nwGUI, prjLipsum):
|
||||
"""Test the project details dialog.
|
||||
"""
|
||||
# Create a project to work on
|
||||
assert nwGUI.openProject(prjLipsum)
|
||||
assert nwGUI.rebuildIndex(beQuiet=True)
|
||||
qtbot.wait(100)
|
||||
|
||||
# Open the Writing Stats dialog
|
||||
nwGUI.mainMenu.aProjectDetails.activate(QAction.Trigger)
|
||||
qtbot.waitUntil(lambda: getGuiItem("GuiProjectDetails") is not None, timeout=1000)
|
||||
|
||||
projDet = getGuiItem("GuiProjectDetails")
|
||||
assert isinstance(projDet, GuiProjectDetails)
|
||||
|
||||
# Overview Page
|
||||
# =============
|
||||
|
||||
assert projDet.tabMain.bookTitle.text() == "Lorem Ipsum"
|
||||
assert projDet.tabMain.projName.text()[-11:] == "Lorem Ipsum"
|
||||
assert projDet.tabMain.bookAuthors.text()[-10:] == "lipsum.com"
|
||||
|
||||
assert projDet.tabMain.wordCountVal.text() == f"{3000:n}"
|
||||
assert projDet.tabMain.chapCountVal.text() == f"{3:n}"
|
||||
assert projDet.tabMain.sceneCountVal.text() == f"{5:n}"
|
||||
assert projDet.tabMain.revCountVal.text() == f"{SHARED.project.data.saveCount:n}"
|
||||
|
||||
assert projDet.tabMain.projPathVal.text() == str(prjLipsum)
|
||||
|
||||
# Contents Page
|
||||
# =============
|
||||
|
||||
tocTab = projDet.tabContents
|
||||
tocTree = tocTab.tocTree
|
||||
assert tocTree.topLevelItemCount() == 7
|
||||
assert tocTree.topLevelItem(0).text(tocTab.C_TITLE) == "Lorem Ipsum" # type: ignore
|
||||
assert tocTree.topLevelItem(2).text(tocTab.C_TITLE) == "Prologue" # type: ignore
|
||||
assert tocTree.topLevelItem(3).text(tocTab.C_TITLE) == "Act One" # type: ignore
|
||||
assert tocTree.topLevelItem(4).text(tocTab.C_TITLE) == "Chapter One" # type: ignore
|
||||
assert tocTree.topLevelItem(5).text(tocTab.C_TITLE) == "Chapter Two" # type: ignore
|
||||
assert tocTree.topLevelItem(6).text(tocTab.C_TITLE) == "END" # type: ignore
|
||||
|
||||
# Count Pages
|
||||
tocTab.wpValue.setValue(100)
|
||||
tocTab.poValue.setValue(4)
|
||||
tocTab.dblValue.setChecked(False)
|
||||
tocTab._populateTree()
|
||||
|
||||
thePages = ["1", "2", "1", "1", "11", "17", "0"]
|
||||
thePage = ["i", "ii", "1", "2", "3", "14", "31"]
|
||||
for i in range(7):
|
||||
assert tocTree.topLevelItem(i).text(tocTab.C_PAGES) == thePages[i] # type: ignore
|
||||
assert tocTree.topLevelItem(i).text(tocTab.C_PAGE) == thePage[i] # type: ignore
|
||||
|
||||
tocTab.poValue.setValue(5)
|
||||
tocTab.dblValue.setChecked(True)
|
||||
tocTab._populateTree()
|
||||
|
||||
thePages = ["2", "2", "2", "2", "12", "18", "0"]
|
||||
thePage = ["i", "iii", "1", "3", "5", "17", "35"]
|
||||
for i in range(7):
|
||||
assert tocTree.topLevelItem(i).text(tocTab.C_PAGES) == thePages[i] # type: ignore
|
||||
assert tocTree.topLevelItem(i).text(tocTab.C_PAGE) == thePage[i] # type: ignore
|
||||
|
||||
# Re-populate
|
||||
assert tocTab._currentRoot is None
|
||||
tocTab._novelValueChanged("7a992350f3eb6") # Not a root
|
||||
assert tocTab._currentRoot == "b3643d0f92e32" # The actual novel root
|
||||
|
||||
# qtbot.stop()
|
||||
|
||||
# Clean Up
|
||||
projDet.close()
|
||||
nwGUI.closeMain()
|
||||
|
||||
# END Test testDlgProjDetails_Dialog
|
||||
+135
-150
@@ -31,7 +31,7 @@ from PyQt5.QtWidgets import QDialog, QAction, QColorDialog
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.enum import nwItemType
|
||||
from novelwriter.dialogs.editlabel import GuiEditLabel
|
||||
from novelwriter.dialogs.projsettings import GuiProjectSettings
|
||||
from novelwriter.dialogs.projectsettings import GuiProjectSettings
|
||||
|
||||
KEY_DELAY = 1
|
||||
|
||||
@@ -63,17 +63,17 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI):
|
||||
qtbot.addWidget(projSettings)
|
||||
|
||||
# Switch Tabs
|
||||
projSettings._focusTab(GuiProjectSettings.TAB_REPLACE)
|
||||
assert projSettings._tabBox.currentWidget() == projSettings.tabReplace
|
||||
projSettings.sidebar.button(GuiProjectSettings.PAGE_SETTINGS).click()
|
||||
assert projSettings.mainStack.currentWidget() == projSettings.settingsPage
|
||||
|
||||
projSettings._focusTab(GuiProjectSettings.TAB_IMPORT)
|
||||
assert projSettings._tabBox.currentWidget() == projSettings.tabImport
|
||||
projSettings.sidebar.button(GuiProjectSettings.PAGE_STATUS).click()
|
||||
assert projSettings.mainStack.currentWidget() == projSettings.statusPage
|
||||
|
||||
projSettings._focusTab(GuiProjectSettings.TAB_STATUS)
|
||||
assert projSettings._tabBox.currentWidget() == projSettings.tabStatus
|
||||
projSettings.sidebar.button(GuiProjectSettings.PAGE_IMPORT).click()
|
||||
assert projSettings.mainStack.currentWidget() == projSettings.importPage
|
||||
|
||||
projSettings._focusTab(GuiProjectSettings.TAB_MAIN)
|
||||
assert projSettings._tabBox.currentWidget() == projSettings.tabMain
|
||||
projSettings.sidebar.button(GuiProjectSettings.PAGE_REPLACE).click()
|
||||
assert projSettings.mainStack.currentWidget() == projSettings.replacePage
|
||||
|
||||
# Clean Up
|
||||
projSettings.close()
|
||||
@@ -83,9 +83,11 @@ def testDlgProjSettings_Dialog(qtbot, monkeypatch, nwGUI):
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testDlgProjSettings_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
|
||||
"""Test the main tab of the project settings dialog."""
|
||||
monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda: [("en", "English [en]")])
|
||||
def testDlgProjSettings_SettingsPage(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
|
||||
"""Test the settings page of the dialog."""
|
||||
languages = [("en", "English"), ("de", "German")]
|
||||
monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda *a: languages)
|
||||
monkeypatch.setattr(CONFIG, "listLanguages", lambda *a: languages)
|
||||
|
||||
# Create new project
|
||||
buildTestProject(nwGUI, projPath)
|
||||
@@ -94,72 +96,57 @@ def testDlgProjSettings_Main(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockR
|
||||
|
||||
# Set some values
|
||||
project = SHARED.project
|
||||
project.data.setLanguage("en")
|
||||
project.data.setSpellLang("en")
|
||||
project.data.setAuthor("Jane Smith")
|
||||
project.data.setAutoReplace({"A": "B", "C": "D"})
|
||||
|
||||
# Create Dialog
|
||||
projSettings = GuiProjectSettings(nwGUI, GuiProjectSettings.TAB_MAIN)
|
||||
projSettings = GuiProjectSettings(nwGUI, GuiProjectSettings.PAGE_SETTINGS)
|
||||
projSettings.show()
|
||||
qtbot.addWidget(projSettings)
|
||||
|
||||
# Settings Tab
|
||||
# ============
|
||||
settings = projSettings.settingsPage
|
||||
|
||||
tabMain = projSettings.tabMain
|
||||
assert settings.projName.text() == "New Project"
|
||||
assert settings.projAuthor.text() == "Jane Smith"
|
||||
assert settings.projLang.currentData() == "en"
|
||||
assert settings.spellLang.currentData() == "en"
|
||||
assert settings.doBackup.isChecked() is False
|
||||
|
||||
assert tabMain.editName.text() == "New Project"
|
||||
assert tabMain.editTitle.text() == "New Novel"
|
||||
assert tabMain.editAuthor.text() == "Jane Smith"
|
||||
assert tabMain.spellLang.currentData() == "en"
|
||||
assert tabMain.doBackup.isChecked() is False
|
||||
|
||||
tabMain.editName.setText("")
|
||||
for c in "Project Name":
|
||||
qtbot.keyClick(tabMain.editName, c, delay=KEY_DELAY)
|
||||
tabMain.editTitle.setText("")
|
||||
for c in "Project Title":
|
||||
qtbot.keyClick(tabMain.editTitle, c, delay=KEY_DELAY)
|
||||
|
||||
tabMain.editAuthor.clear()
|
||||
for c in "Jane Doe":
|
||||
qtbot.keyClick(tabMain.editAuthor, c, delay=KEY_DELAY)
|
||||
|
||||
assert tabMain.editName.text() == "Project Name"
|
||||
assert tabMain.editTitle.text() == "Project Title"
|
||||
assert tabMain.editAuthor.text() == "Jane Doe"
|
||||
settings.projName.setText("Project Name")
|
||||
settings.projAuthor.setText("Jane Doe")
|
||||
settings.projLang.setCurrentIndex(settings.projLang.findData("de"))
|
||||
settings.spellLang.setCurrentIndex(settings.spellLang.findData("de"))
|
||||
settings.doBackup.setChecked(True)
|
||||
|
||||
projSettings._doSave()
|
||||
assert project.data.name == "Project Name"
|
||||
assert project.data.title == "Project Title"
|
||||
assert project.data.author == "Jane Doe"
|
||||
assert project.data.language == "de"
|
||||
assert project.data.spellLang == "de"
|
||||
assert project.data.doBackup is False
|
||||
|
||||
nwGUI._processProjectSettingsChanges()
|
||||
nwGUI._processProjectSettingsChanges(False)
|
||||
assert nwGUI.windowTitle() == "novelWriter - Project Name"
|
||||
|
||||
# qtbot.stop()
|
||||
|
||||
# END Test testDlgProjSettings_Main
|
||||
# END Test testDlgProjSettings_SettingsPage
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
|
||||
"""Test the status and importance tabs of the project settings
|
||||
dialog.
|
||||
"""
|
||||
def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
"""Test the status and importance pages of the dialog."""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda: [("en", "English [en]")])
|
||||
|
||||
# Create new project
|
||||
mockRnd.reset()
|
||||
buildTestProject(nwGUI, projPath)
|
||||
CONFIG.setBackupPath(fncPath)
|
||||
|
||||
# Set some values
|
||||
theProject = SHARED.project
|
||||
theProject.tree[C.hTitlePage].setStatus(C.sFinished) # type: ignore
|
||||
theProject.tree[C.hChapterDoc].setStatus(C.sDraft) # type: ignore
|
||||
theProject.tree[C.hSceneDoc].setStatus(C.sDraft) # type: ignore
|
||||
project = SHARED.project
|
||||
project.tree[C.hTitlePage].setStatus(C.sFinished) # type: ignore
|
||||
project.tree[C.hChapterDoc].setStatus(C.sDraft) # type: ignore
|
||||
project.tree[C.hSceneDoc].setStatus(C.sDraft) # type: ignore
|
||||
|
||||
nwGUI.projView.projTree.setSelectedHandle(C.hPlotRoot)
|
||||
nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True)
|
||||
@@ -172,51 +159,54 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncPath, projPat
|
||||
hCharNote = "0000000000011"
|
||||
hWorldNote = "0000000000012"
|
||||
|
||||
theProject.tree[hPlotNote].setImport(C.iMajor) # type: ignore
|
||||
theProject.tree[hCharNote].setImport(C.iMajor) # type: ignore
|
||||
theProject.tree[hWorldNote].setImport(C.iMain) # type: ignore
|
||||
project.tree[hPlotNote].setImport(C.iMajor) # type: ignore
|
||||
project.tree[hCharNote].setImport(C.iMajor) # type: ignore
|
||||
project.tree[hWorldNote].setImport(C.iMain) # type: ignore
|
||||
|
||||
nwGUI.rebuildTrees()
|
||||
project.countStatus()
|
||||
|
||||
assert [e["count"] for _, e in project.data.itemStatus.items()] == [2, 0, 2, 1]
|
||||
assert [e["count"] for _, e in project.data.itemImport.items()] == [3, 0, 2, 1]
|
||||
|
||||
# Create Dialog
|
||||
projSettings = GuiProjectSettings(nwGUI, GuiProjectSettings.TAB_STATUS)
|
||||
projSettings = GuiProjectSettings(nwGUI, GuiProjectSettings.PAGE_STATUS)
|
||||
projSettings.show()
|
||||
qtbot.addWidget(projSettings)
|
||||
|
||||
# Status Tab
|
||||
# ==========
|
||||
|
||||
tabStatus = projSettings.tabStatus
|
||||
status = projSettings.statusPage
|
||||
|
||||
assert tabStatus.colChanged is False
|
||||
assert tabStatus.getNewList() == ([], [])
|
||||
assert tabStatus.listBox.topLevelItemCount() == 4
|
||||
assert status.wasChanged is False
|
||||
assert status.getNewList() == ([], [])
|
||||
assert status.listBox.topLevelItemCount() == 4
|
||||
|
||||
# Can't delete the first item (it's in use)
|
||||
tabStatus.listBox.clearSelection()
|
||||
tabStatus.listBox.setCurrentItem(tabStatus.listBox.topLevelItem(0))
|
||||
qtbot.mouseClick(tabStatus.delButton, Qt.LeftButton)
|
||||
assert tabStatus.listBox.topLevelItemCount() == 4
|
||||
status.listBox.clearSelection()
|
||||
status.listBox.setCurrentItem(status.listBox.topLevelItem(0))
|
||||
qtbot.mouseClick(status.delButton, Qt.LeftButton)
|
||||
assert status.listBox.topLevelItemCount() == 4
|
||||
|
||||
# Can delete the second item
|
||||
tabStatus.listBox.clearSelection()
|
||||
tabStatus.listBox.setCurrentItem(tabStatus.listBox.topLevelItem(1))
|
||||
qtbot.mouseClick(tabStatus.delButton, Qt.LeftButton)
|
||||
assert tabStatus.listBox.topLevelItemCount() == 3
|
||||
status.listBox.clearSelection()
|
||||
status.listBox.setCurrentItem(status.listBox.topLevelItem(1))
|
||||
qtbot.mouseClick(status.delButton, Qt.LeftButton)
|
||||
assert status.listBox.topLevelItemCount() == 3
|
||||
|
||||
# Add a new item
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QColorDialog, "getColor", lambda *a: QColor(20, 30, 40))
|
||||
qtbot.mouseClick(tabStatus.addButton, Qt.LeftButton)
|
||||
tabStatus.listBox.setCurrentItem(tabStatus.listBox.topLevelItem(3))
|
||||
for _ in range(8):
|
||||
qtbot.keyClick(tabStatus.editName, Qt.Key_Backspace, delay=KEY_DELAY)
|
||||
for c in "Final":
|
||||
qtbot.keyClick(tabStatus.editName, c, delay=KEY_DELAY)
|
||||
qtbot.mouseClick(tabStatus.colButton, Qt.LeftButton)
|
||||
qtbot.mouseClick(tabStatus.saveButton, Qt.LeftButton)
|
||||
assert tabStatus.listBox.topLevelItemCount() == 4
|
||||
status.addButton.click()
|
||||
status.listBox.setCurrentItem(status.listBox.topLevelItem(3))
|
||||
status.editName.setText("Final")
|
||||
status.colButton.click()
|
||||
status.saveButton.click()
|
||||
assert status.listBox.topLevelItemCount() == 4
|
||||
|
||||
assert tabStatus.colChanged is True
|
||||
assert tabStatus.getNewList() == (
|
||||
assert status.wasChanged is True
|
||||
assert status.getNewList() == (
|
||||
[
|
||||
{
|
||||
"key": C.sNew,
|
||||
@@ -241,62 +231,62 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncPath, projPat
|
||||
)
|
||||
|
||||
# Move items, none selected -> no change
|
||||
tabStatus.listBox.clearSelection()
|
||||
tabStatus._moveItem(1)
|
||||
assert [x["key"] for x in tabStatus.getNewList()[0]] == [
|
||||
status.listBox.clearSelection()
|
||||
status._moveItem(1)
|
||||
assert [x["key"] for x in status.getNewList()[0]] == [
|
||||
C.sNew, C.sDraft, C.sFinished, None
|
||||
]
|
||||
|
||||
# Move items, first selected, move up -> no change
|
||||
tabStatus.listBox.clearSelection()
|
||||
tabStatus.listBox.setCurrentItem(tabStatus.listBox.topLevelItem(0))
|
||||
tabStatus._moveItem(-1)
|
||||
assert [x["key"] for x in tabStatus.getNewList()[0]] == [
|
||||
status.listBox.clearSelection()
|
||||
status.listBox.setCurrentItem(status.listBox.topLevelItem(0))
|
||||
status._moveItem(-1)
|
||||
assert [x["key"] for x in status.getNewList()[0]] == [
|
||||
C.sNew, C.sDraft, C.sFinished, None
|
||||
]
|
||||
|
||||
# Move items, last selected, move up -> allowed
|
||||
tabStatus.listBox.clearSelection()
|
||||
tabStatus.listBox.setCurrentItem(tabStatus.listBox.topLevelItem(3))
|
||||
tabStatus._moveItem(-1)
|
||||
assert [x["key"] for x in tabStatus.getNewList()[0]] == [
|
||||
status.listBox.clearSelection()
|
||||
status.listBox.setCurrentItem(status.listBox.topLevelItem(3))
|
||||
status._moveItem(-1)
|
||||
assert [x["key"] for x in status.getNewList()[0]] == [
|
||||
C.sNew, C.sDraft, None, C.sFinished
|
||||
]
|
||||
|
||||
# Move items, same selected, move down -> allowed
|
||||
tabStatus._moveItem(1)
|
||||
assert [x["key"] for x in tabStatus.getNewList()[0]] == [
|
||||
status._moveItem(1)
|
||||
assert [x["key"] for x in status.getNewList()[0]] == [
|
||||
C.sNew, C.sDraft, C.sFinished, None
|
||||
]
|
||||
|
||||
# Importance Tab
|
||||
# ==============
|
||||
|
||||
tabImport = projSettings.tabImport
|
||||
projSettings._focusTab(GuiProjectSettings.TAB_IMPORT)
|
||||
importance = projSettings.importPage
|
||||
projSettings._sidebarClicked(GuiProjectSettings.PAGE_IMPORT)
|
||||
|
||||
# Delete unused entry
|
||||
tabImport.listBox.clearSelection()
|
||||
tabImport.listBox.setCurrentItem(tabImport.listBox.topLevelItem(1))
|
||||
qtbot.mouseClick(tabImport.delButton, Qt.LeftButton)
|
||||
assert tabImport.listBox.topLevelItemCount() == 3
|
||||
importance.listBox.clearSelection()
|
||||
importance.listBox.setCurrentItem(importance.listBox.topLevelItem(1))
|
||||
qtbot.mouseClick(importance.delButton, Qt.LeftButton)
|
||||
assert importance.listBox.topLevelItemCount() == 3
|
||||
|
||||
# Add a new entry
|
||||
with monkeypatch.context() as mp:
|
||||
mp.setattr(QColorDialog, "getColor", lambda *a: QColor(20, 30, 40))
|
||||
qtbot.mouseClick(tabImport.addButton, Qt.LeftButton)
|
||||
tabImport.listBox.clearSelection()
|
||||
tabImport.listBox.setCurrentItem(tabImport.listBox.topLevelItem(3))
|
||||
qtbot.mouseClick(importance.addButton, Qt.LeftButton)
|
||||
importance.listBox.clearSelection()
|
||||
importance.listBox.setCurrentItem(importance.listBox.topLevelItem(3))
|
||||
for _ in range(8):
|
||||
qtbot.keyClick(tabImport.editName, Qt.Key_Backspace, delay=KEY_DELAY)
|
||||
qtbot.keyClick(importance.editName, Qt.Key_Backspace, delay=KEY_DELAY)
|
||||
for c in "Final":
|
||||
qtbot.keyClick(tabImport.editName, c, delay=KEY_DELAY)
|
||||
qtbot.mouseClick(tabImport.colButton, Qt.LeftButton)
|
||||
qtbot.mouseClick(tabImport.saveButton, Qt.LeftButton)
|
||||
assert tabImport.listBox.topLevelItemCount() == 4
|
||||
qtbot.keyClick(importance.editName, c, delay=KEY_DELAY)
|
||||
qtbot.mouseClick(importance.colButton, Qt.LeftButton)
|
||||
qtbot.mouseClick(importance.saveButton, Qt.LeftButton)
|
||||
assert importance.listBox.topLevelItemCount() == 4
|
||||
|
||||
assert tabImport.colChanged is True
|
||||
assert tabImport.getNewList() == (
|
||||
assert importance.wasChanged is True
|
||||
assert importance.getNewList() == (
|
||||
[
|
||||
{
|
||||
"key": C.iNew,
|
||||
@@ -323,13 +313,13 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncPath, projPat
|
||||
# Check Project
|
||||
projSettings._doSave()
|
||||
|
||||
statusItems = dict(theProject.data.itemStatus.items())
|
||||
statusItems = dict(project.data.itemStatus.items())
|
||||
assert statusItems[C.sNew]["name"] == "New"
|
||||
assert statusItems[C.sDraft]["name"] == "Draft"
|
||||
assert statusItems[C.sFinished]["name"] == "Finished"
|
||||
assert statusItems["s000013"]["name"] == "Final"
|
||||
|
||||
importItems = dict(theProject.data.itemImport.items())
|
||||
importItems = dict(project.data.itemImport.items())
|
||||
assert importItems[C.iNew]["name"] == "New"
|
||||
assert importItems[C.iMajor]["name"] == "Major"
|
||||
assert importItems[C.iMain]["name"] == "Main"
|
||||
@@ -341,83 +331,78 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncPath, projPat
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
|
||||
"""Test the auto-replace tab of the project settings dialog."""
|
||||
def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||
"""Test the auto-replace page of the dialog."""
|
||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||
monkeypatch.setattr(SHARED._spelling, "listDictionaries", lambda: [("en", "English [en]")])
|
||||
|
||||
# Create new project
|
||||
mockRnd.reset()
|
||||
buildTestProject(nwGUI, projPath)
|
||||
CONFIG.setBackupPath(fncPath)
|
||||
|
||||
# Set some values
|
||||
theProject = SHARED.project
|
||||
theProject.data.setAutoReplace({
|
||||
project = SHARED.project
|
||||
project.data.setAutoReplace({
|
||||
"A": "B", "C": "D"
|
||||
})
|
||||
|
||||
# Create Dialog
|
||||
projSettings = GuiProjectSettings(nwGUI, GuiProjectSettings.TAB_REPLACE)
|
||||
projSettings = GuiProjectSettings(nwGUI, GuiProjectSettings.PAGE_REPLACE)
|
||||
projSettings.show()
|
||||
qtbot.addWidget(projSettings)
|
||||
|
||||
# Auto-Replace Tab
|
||||
# ================
|
||||
|
||||
tabReplace = projSettings.tabReplace
|
||||
replace = projSettings.replacePage
|
||||
|
||||
assert tabReplace.listBox.topLevelItem(0).text(0) == "<A>" # type: ignore
|
||||
assert tabReplace.listBox.topLevelItem(0).text(1) == "B" # type: ignore
|
||||
assert tabReplace.listBox.topLevelItem(1).text(0) == "<C>" # type: ignore
|
||||
assert tabReplace.listBox.topLevelItem(1).text(1) == "D" # type: ignore
|
||||
assert tabReplace.listBox.topLevelItemCount() == 2
|
||||
assert replace.listBox.topLevelItem(0).text(0) == "<A>" # type: ignore
|
||||
assert replace.listBox.topLevelItem(0).text(1) == "B" # type: ignore
|
||||
assert replace.listBox.topLevelItem(1).text(0) == "<C>" # type: ignore
|
||||
assert replace.listBox.topLevelItem(1).text(1) == "D" # type: ignore
|
||||
assert replace.listBox.topLevelItemCount() == 2
|
||||
|
||||
# Nothing to save or delete
|
||||
tabReplace.listBox.clearSelection()
|
||||
tabReplace._saveEntry()
|
||||
tabReplace._delEntry()
|
||||
assert tabReplace.listBox.topLevelItemCount() == 2
|
||||
replace.listBox.clearSelection()
|
||||
replace._saveEntry()
|
||||
replace._delEntry()
|
||||
assert replace.listBox.topLevelItemCount() == 2
|
||||
|
||||
# Create a new entry
|
||||
qtbot.mouseClick(tabReplace.addButton, Qt.LeftButton)
|
||||
assert tabReplace.listBox.topLevelItemCount() == 3
|
||||
assert tabReplace.listBox.topLevelItem(2).text(0) == "<keyword3>" # type: ignore
|
||||
assert tabReplace.listBox.topLevelItem(2).text(1) == "" # type: ignore
|
||||
qtbot.mouseClick(replace.addButton, Qt.LeftButton)
|
||||
assert replace.listBox.topLevelItemCount() == 3
|
||||
assert replace.listBox.topLevelItem(2).text(0) == "<keyword3>" # type: ignore
|
||||
assert replace.listBox.topLevelItem(2).text(1) == "" # type: ignore
|
||||
|
||||
# Edit the entry
|
||||
tabReplace.listBox.setCurrentItem(tabReplace.listBox.topLevelItem(2))
|
||||
tabReplace.editKey.setText("")
|
||||
replace.listBox.setCurrentItem(replace.listBox.topLevelItem(2))
|
||||
replace.editKey.setText("")
|
||||
for c in "Th is ":
|
||||
qtbot.keyClick(tabReplace.editKey, c, delay=KEY_DELAY)
|
||||
tabReplace.editValue.setText("")
|
||||
qtbot.keyClick(replace.editKey, c, delay=KEY_DELAY)
|
||||
replace.editValue.setText("")
|
||||
for c in "With This Stuff ":
|
||||
qtbot.keyClick(tabReplace.editValue, c, delay=KEY_DELAY)
|
||||
qtbot.mouseClick(tabReplace.saveButton, Qt.LeftButton)
|
||||
assert tabReplace.listBox.topLevelItem(2).text(0) == "<This>" # type: ignore
|
||||
assert tabReplace.listBox.topLevelItem(2).text(1) == "With This Stuff " # type: ignore
|
||||
qtbot.keyClick(replace.editValue, c, delay=KEY_DELAY)
|
||||
qtbot.mouseClick(replace.saveButton, Qt.LeftButton)
|
||||
assert replace.listBox.topLevelItem(2).text(0) == "<This>" # type: ignore
|
||||
assert replace.listBox.topLevelItem(2).text(1) == "With This Stuff " # type: ignore
|
||||
|
||||
# Create a new entry again
|
||||
tabReplace.listBox.clearSelection()
|
||||
qtbot.mouseClick(tabReplace.addButton, Qt.LeftButton)
|
||||
assert tabReplace.listBox.topLevelItemCount() == 4
|
||||
replace.listBox.clearSelection()
|
||||
qtbot.mouseClick(replace.addButton, Qt.LeftButton)
|
||||
assert replace.listBox.topLevelItemCount() == 4
|
||||
|
||||
# The list is sorted, so we must find it
|
||||
newIdx = -1
|
||||
for i in range(tabReplace.listBox.topLevelItemCount()):
|
||||
if tabReplace.listBox.topLevelItem(i).text(0) == "<keyword4>": # type: ignore
|
||||
for i in range(replace.listBox.topLevelItemCount()):
|
||||
if replace.listBox.topLevelItem(i).text(0) == "<keyword4>": # type: ignore
|
||||
newIdx = i
|
||||
break
|
||||
assert newIdx >= 0
|
||||
|
||||
# Then delete the new item
|
||||
tabReplace.listBox.setCurrentItem(tabReplace.listBox.topLevelItem(newIdx))
|
||||
qtbot.mouseClick(tabReplace.delButton, Qt.LeftButton)
|
||||
assert tabReplace.listBox.topLevelItemCount() == 3
|
||||
replace.listBox.setCurrentItem(replace.listBox.topLevelItem(newIdx))
|
||||
qtbot.mouseClick(replace.delButton, Qt.LeftButton)
|
||||
assert replace.listBox.topLevelItemCount() == 3
|
||||
|
||||
# Check Project
|
||||
projSettings._doSave()
|
||||
assert theProject.data.autoReplace == {
|
||||
assert project.data.autoReplace == {
|
||||
"A": "B", "C": "D", "This": "With This Stuff"
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ from tools import (
|
||||
C, NWD_IGNORE, cmpFiles, buildTestProject, XML_IGNORE, getGuiItem
|
||||
)
|
||||
|
||||
from PyQt5.QtGui import QColor, QPalette
|
||||
from PyQt5.QtGui import QPalette
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import QMenu, QInputDialog
|
||||
|
||||
@@ -170,7 +170,7 @@ def testGuiMain_UpdateTheme(qtbot, nwGUI):
|
||||
mainTheme.loadSyntax()
|
||||
nwGUI._processConfigChanges(True, True, True, True)
|
||||
|
||||
syntaxBack = QColor(*SHARED.theme.colBack)
|
||||
syntaxBack = SHARED.theme.colBack
|
||||
|
||||
assert nwGUI.docEditor.palette().color(QPalette.ColorRole.Window) == syntaxBack
|
||||
assert nwGUI.docEditor.docHeader.palette().color(QPalette.ColorRole.Window) == syntaxBack
|
||||
@@ -200,7 +200,6 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
|
||||
assert len(SHARED.project.tree._roots) == 0
|
||||
assert SHARED.project.tree.trashRoot is None
|
||||
assert SHARED.project.data.name == ""
|
||||
assert SHARED.project.data.title == ""
|
||||
assert SHARED.project.data.author == ""
|
||||
assert SHARED.project.data.spellCheck is False
|
||||
|
||||
@@ -220,7 +219,6 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, projPath, tstPaths, mockRnd):
|
||||
assert len(SHARED.project.tree._roots) == 4
|
||||
assert SHARED.project.tree.trashRoot is None
|
||||
assert SHARED.project.data.name == "New Project"
|
||||
assert SHARED.project.data.title == "New Novel"
|
||||
assert SHARED.project.data.author == "Jane Doe"
|
||||
assert SHARED.project.data.spellCheck is False
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ from pathlib import Path
|
||||
from mocked import causeOSError
|
||||
from tools import writeFile
|
||||
|
||||
from PyQt5.QtGui import QIcon, QPalette, QPixmap
|
||||
from PyQt5.QtGui import QColor, QIcon, QPalette, QPixmap
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
@@ -89,29 +89,38 @@ def testGuiTheme_Main(qtbot, nwGUI, tstPaths):
|
||||
|
||||
parser = NWConfigParser()
|
||||
parser["Palette"] = {
|
||||
"colour1": "100, 150, 200",
|
||||
"colour2": "100, 150, 200, 250",
|
||||
"colour3": "250, 250",
|
||||
"colour4": "-10, 127, 300",
|
||||
"colour1": "100, 150, 200", # Valid
|
||||
"colour2": "100, 150, 200, 250", # With alpha
|
||||
"colour3": "100, 150, 200, 250, 300", # Too many values
|
||||
"colour4": "250, 250", # Missing blue
|
||||
"colour5": "-10, 127, 300", # Invalid red and blue
|
||||
"colour6": "bob, 127, 255", # Invalid red
|
||||
}
|
||||
|
||||
# Test the parser for several valid and invalid values
|
||||
assert mainTheme._parseColour(parser, "Palette", "colour1") == [100, 150, 200]
|
||||
assert mainTheme._parseColour(parser, "Palette", "colour2") == [100, 150, 200]
|
||||
assert mainTheme._parseColour(parser, "Palette", "colour3") == [0, 0, 0]
|
||||
assert mainTheme._parseColour(parser, "Palette", "colour4") == [0, 127, 255]
|
||||
assert mainTheme._parseColour(parser, "Palette", "colour5") == [0, 0, 0]
|
||||
assert mainTheme._parseColour(parser, "Palette", "colour1").getRgb() == (100, 150, 200, 255)
|
||||
assert mainTheme._parseColour(parser, "Palette", "colour2").getRgb() == (100, 150, 200, 250)
|
||||
assert mainTheme._parseColour(parser, "Palette", "colour3").getRgb() == (100, 150, 200, 250)
|
||||
assert mainTheme._parseColour(parser, "Palette", "colour4").getRgb() == (250, 250, 0, 255)
|
||||
assert mainTheme._parseColour(parser, "Palette", "colour5").getRgb() == (0, 0, 0, 0)
|
||||
assert mainTheme._parseColour(parser, "Palette", "colour6").getRgb() == (0, 127, 255, 255)
|
||||
|
||||
# The palette should load with the parsed values
|
||||
mainTheme._setPalette(parser, "Palette", "colour1", QPalette.Window)
|
||||
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (100, 150, 200, 255)
|
||||
mainTheme._setPalette(parser, "Palette", "colour2", QPalette.Window)
|
||||
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (100, 150, 200, 255)
|
||||
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (100, 150, 200, 250)
|
||||
mainTheme._setPalette(parser, "Palette", "colour3", QPalette.Window)
|
||||
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (0, 0, 0, 255)
|
||||
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (100, 150, 200, 250)
|
||||
mainTheme._setPalette(parser, "Palette", "colour4", QPalette.Window)
|
||||
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (0, 127, 255, 255)
|
||||
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (250, 250, 0, 255)
|
||||
mainTheme._setPalette(parser, "Palette", "colour5", QPalette.Window)
|
||||
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (0, 0, 0, 0)
|
||||
mainTheme._setPalette(parser, "Palette", "colour6", QPalette.Window)
|
||||
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (0, 127, 255, 255)
|
||||
|
||||
# Non-existing value should return default colour
|
||||
mainTheme._setPalette(parser, "Palette", "stuff", QPalette.Window)
|
||||
assert mainTheme._guiPalette.color(QPalette.Window).getRgb() == (0, 0, 0, 255)
|
||||
|
||||
# qtbot.stop()
|
||||
@@ -240,9 +249,9 @@ def testGuiTheme_Syntax(qtbot, monkeypatch, nwGUI):
|
||||
|
||||
# Check some values
|
||||
assert mainTheme.syntaxName == "Default Light"
|
||||
assert mainTheme.colBack == [255, 255, 255]
|
||||
assert mainTheme.colText == [0, 0, 0]
|
||||
assert mainTheme.colLink == [0, 0, 200]
|
||||
assert mainTheme.colBack == QColor(255, 255, 255)
|
||||
assert mainTheme.colText == QColor(0, 0, 0)
|
||||
assert mainTheme.colLink == QColor(0, 0, 200)
|
||||
|
||||
# Load Default Dark Theme
|
||||
# =======================
|
||||
@@ -253,9 +262,9 @@ def testGuiTheme_Syntax(qtbot, monkeypatch, nwGUI):
|
||||
|
||||
# Check some values
|
||||
assert mainTheme.syntaxName == "Default Dark"
|
||||
assert mainTheme.colBack == [54, 54, 54]
|
||||
assert mainTheme.colText == [199, 207, 208]
|
||||
assert mainTheme.colLink == [184, 200, 0]
|
||||
assert mainTheme.colBack == QColor(54, 54, 54)
|
||||
assert mainTheme.colText == QColor(199, 207, 208)
|
||||
assert mainTheme.colLink == QColor(184, 200, 0)
|
||||
|
||||
# qtbot.stop()
|
||||
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
"""
|
||||
novelWriter – Novel Details Tool Tester
|
||||
=======================================
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
|
||||
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/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from tools import getGuiItem
|
||||
|
||||
from PyQt5.QtWidgets import QAction
|
||||
|
||||
from novelwriter import SHARED
|
||||
from novelwriter.enum import nwItemClass
|
||||
from novelwriter.tools.noveldetails import GuiNovelDetails
|
||||
|
||||
|
||||
@pytest.mark.gui
|
||||
def testToolNovelDetails_Main(qtbot, nwGUI, prjLipsum, ipsumText):
|
||||
"""Test the Novel Details main dialog."""
|
||||
nwGUI.openProject(prjLipsum)
|
||||
nHandle = "b3643d0f92e32"
|
||||
|
||||
# Add a second Novel folder
|
||||
project = SHARED.project
|
||||
secondText = "#! Second\n\n" + "\n\n".join(ipsumText)
|
||||
sHandle = project.newRoot(nwItemClass.NOVEL, "Second")
|
||||
dHandle = project.newFile("Document", sHandle)
|
||||
project.storage.getDocument(dHandle).writeDocument(secondText)
|
||||
project.index.reIndexHandle(dHandle)
|
||||
nwGUI.projView.projTree.revealNewTreeItem(sHandle)
|
||||
nwGUI.projView.projTree.revealNewTreeItem(dHandle)
|
||||
|
||||
# Create the dialog
|
||||
nwGUI.mainMenu.aNovelDetails.activate(QAction.ActionEvent.Trigger)
|
||||
qtbot.waitUntil(lambda: getGuiItem("GuiNovelDetails") is not None, timeout=1000)
|
||||
details = getGuiItem("GuiNovelDetails")
|
||||
assert isinstance(details, GuiNovelDetails)
|
||||
|
||||
# Overview Page
|
||||
# =============
|
||||
overview = details.overviewPage
|
||||
|
||||
# The selector should default to the first entry
|
||||
assert details.novelSelector.handle == nHandle
|
||||
|
||||
# Check project data
|
||||
assert overview.projName.text() == "Lorem Ipsum"
|
||||
assert overview.projWords.text() == f"{4376:n}"
|
||||
assert overview.projNovels.text() == f"{3638:n}"
|
||||
assert overview.projNotes.text() == f"{738:n}"
|
||||
assert overview.projRevisions.text() != ""
|
||||
assert overview.projEditTime.text() != ""
|
||||
|
||||
# Check novel data for "Novel"
|
||||
assert overview.novelName.text() == "Novel"
|
||||
assert overview.novelWords.text() == f"{3000:n}"
|
||||
assert overview.novelChapters.text() == f"{3:n}"
|
||||
assert overview.novelScenes.text() == f"{5:n}"
|
||||
|
||||
# Check novel data for "Second"
|
||||
details.novelSelector.setHandle(sHandle, blockSignal=False)
|
||||
assert overview.novelName.text() == "Second"
|
||||
assert overview.novelWords.text() == f"{529:n}"
|
||||
assert overview.novelChapters.text() == f"{0:n}"
|
||||
assert overview.novelScenes.text() == f"{0:n}"
|
||||
|
||||
# Contents Page
|
||||
# =============
|
||||
details.novelSelector.setHandle(nHandle, blockSignal=False)
|
||||
details.sidebar.button(details.PAGE_CONTENTS).click()
|
||||
assert details.mainStack.currentIndex() == 1
|
||||
contents = details.contentsPage
|
||||
|
||||
# Check defaults
|
||||
words = [f"{v:n}" for v in [40, 176, 92, 6, 1071, 1615, 0]]
|
||||
pages = [f"{v:n}" for v in [2, 2, 2, 2, 4, 6, 0]]
|
||||
page = [f"{v:n}" for v in [1, 3, 5, 7, 9, 13, 19]]
|
||||
for i in range(6):
|
||||
item = contents.tocTree.topLevelItem(i)
|
||||
assert item is not None
|
||||
assert item.text(contents.C_WORDS) == words[i]
|
||||
assert item.text(contents.C_PAGES) == pages[i]
|
||||
assert item.text(contents.C_PAGE) == page[i]
|
||||
|
||||
# Change Settings
|
||||
contents.poValue.setValue(7)
|
||||
contents.wpValue.setValue(50)
|
||||
words = [f"{v:n}" for v in [40, 176, 92, 6, 1071, 1615, 0]]
|
||||
pages = [f"{v:n}" for v in [2, 4, 2, 2, 22, 34, 0]]
|
||||
page = ["i", "iii"] + [f"{v:n}" for v in [1, 3, 5, 27, 61]]
|
||||
for i in range(6):
|
||||
item = contents.tocTree.topLevelItem(i)
|
||||
assert item is not None
|
||||
assert item.text(contents.C_WORDS) == words[i]
|
||||
assert item.text(contents.C_PAGES) == pages[i]
|
||||
assert item.text(contents.C_PAGE) == page[i]
|
||||
|
||||
# Turn off use odd pages
|
||||
contents.dblValue.setChecked(False)
|
||||
contents.poValue.setValue(0)
|
||||
contents.wpValue.setValue(100)
|
||||
words = [f"{v:n}" for v in [40, 176, 92, 6, 1071, 1615, 0]]
|
||||
pages = [f"{v:n}" for v in [1, 2, 1, 1, 11, 17, 0]]
|
||||
page = [f"{v:n}" for v in [1, 2, 4, 5, 6, 17, 34]]
|
||||
for i in range(6):
|
||||
item = contents.tocTree.topLevelItem(i)
|
||||
assert item is not None
|
||||
assert item.text(contents.C_WORDS) == words[i]
|
||||
assert item.text(contents.C_PAGES) == pages[i]
|
||||
assert item.text(contents.C_PAGE) == page[i]
|
||||
|
||||
# Revert to Overview page
|
||||
details.sidebar.button(details.PAGE_OVERVIEW).click()
|
||||
assert details.mainStack.currentIndex() == 0
|
||||
|
||||
# qtbot.stop()
|
||||
details.close()
|
||||
|
||||
# END Test testToolNovelDetails_Main
|
||||
+20
-18
@@ -156,52 +156,54 @@ def cleanProject(path: str | Path):
|
||||
return
|
||||
|
||||
|
||||
def buildTestProject(obj, projPath):
|
||||
def buildTestProject(obj: object, projPath: Path) -> None:
|
||||
"""Build a standard test project in projPath using the project
|
||||
object as the parent.
|
||||
"""
|
||||
from novelwriter.enum import nwItemClass
|
||||
from novelwriter.guimain import GuiMain
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
if isinstance(obj, NWProject):
|
||||
nwGUI = None
|
||||
project = obj
|
||||
else:
|
||||
elif isinstance(obj, GuiMain):
|
||||
from novelwriter import SHARED
|
||||
nwGUI = obj
|
||||
project = SHARED.project
|
||||
else:
|
||||
return
|
||||
|
||||
project.storage.createNewProject(projPath)
|
||||
project.setDefaultStatusImport()
|
||||
|
||||
project.data.setUuid("d0f3fe10-c6e6-4310-8bfd-181eb4224eed")
|
||||
project.data.setName("New Project")
|
||||
project.data.setTitle("New Novel")
|
||||
project.data.setAuthor("Jane Doe")
|
||||
|
||||
# Creating a minimal project with a few root folders and a
|
||||
# single chapter folder with a single file.
|
||||
xHandle = {}
|
||||
xHandle[1] = project.newRoot(nwItemClass.NOVEL, "Novel")
|
||||
xHandle[2] = project.newRoot(nwItemClass.PLOT, "Plot")
|
||||
xHandle[3] = project.newRoot(nwItemClass.CHARACTER, "Characters")
|
||||
xHandle[4] = project.newRoot(nwItemClass.WORLD, "World")
|
||||
xHandle[5] = project.newFile("Title Page", xHandle[1])
|
||||
xHandle[6] = project.newFolder("New Chapter", xHandle[1])
|
||||
xHandle[7] = project.newFile("New Chapter", xHandle[6])
|
||||
xHandle[8] = project.newFile("New Scene", xHandle[6])
|
||||
nrHandle = project.newRoot(nwItemClass.NOVEL, "Novel")
|
||||
project.newRoot(nwItemClass.PLOT, "Plot")
|
||||
project.newRoot(nwItemClass.CHARACTER, "Characters")
|
||||
project.newRoot(nwItemClass.WORLD, "World")
|
||||
|
||||
aDoc = project.storage.getDocument(xHandle[5])
|
||||
tdHandle = project.newFile("Title Page", nrHandle)
|
||||
cfHandle = project.newFolder("New Chapter", nrHandle) or ""
|
||||
cdHandle = project.newFile("New Chapter", cfHandle)
|
||||
sdHandle = project.newFile("New Scene", cfHandle)
|
||||
|
||||
aDoc = project.storage.getDocument(tdHandle)
|
||||
aDoc.writeDocument("#! New Novel\n\n>> By Jane Doe <<\n")
|
||||
project.index.reIndexHandle(xHandle[5])
|
||||
project.index.reIndexHandle(tdHandle)
|
||||
|
||||
aDoc = project.storage.getDocument(xHandle[7])
|
||||
aDoc = project.storage.getDocument(cdHandle)
|
||||
aDoc.writeDocument("## %s\n\n" % project.tr("New Chapter"))
|
||||
project.index.reIndexHandle(xHandle[7])
|
||||
project.index.reIndexHandle(cdHandle)
|
||||
|
||||
aDoc = project.storage.getDocument(xHandle[8])
|
||||
aDoc = project.storage.getDocument(sdHandle)
|
||||
aDoc.writeDocument("### %s\n\n" % project.tr("New Scene"))
|
||||
project.index.reIndexHandle(xHandle[8])
|
||||
project.index.reIndexHandle(sdHandle)
|
||||
|
||||
project.session.startSession()
|
||||
project.setProjectChanged(True)
|
||||
|
||||
Reference in New Issue
Block a user