novelWriter 2.3rc1__py3-none-any.whl → 2.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/METADATA +5 -6
- {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/RECORD +119 -109
- {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/WHEEL +1 -1
- novelWriter-2.4.dist-info/entry_points.txt +2 -0
- novelwriter/__init__.py +17 -10
- novelwriter/assets/i18n/nw_de_DE.qm +0 -0
- novelwriter/assets/i18n/nw_en_US.qm +0 -0
- novelwriter/assets/i18n/nw_es_419.qm +0 -0
- novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
- novelwriter/assets/i18n/nw_it_IT.qm +0 -0
- novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
- novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
- novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
- novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
- novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
- novelwriter/assets/i18n/project_nl_NL.json +11 -0
- novelwriter/assets/i18n/project_pt_BR.json +11 -0
- novelwriter/assets/icons/none.svg +4 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +7 -0
- novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +1 -1
- novelwriter/assets/icons/typicons_dark/typ_refresh.svg +1 -1
- novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_times.svg +1 -1
- novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +7 -0
- novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +1 -1
- novelwriter/assets/icons/typicons_light/typ_refresh.svg +1 -1
- novelwriter/assets/icons/typicons_light/typ_search-grey.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_times.svg +1 -1
- novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +4 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/syntax/cyberpunk_night.conf +26 -0
- novelwriter/assets/syntax/default_dark.conf +1 -0
- novelwriter/assets/syntax/default_light.conf +1 -0
- novelwriter/assets/syntax/grey_dark.conf +1 -0
- novelwriter/assets/syntax/grey_light.conf +1 -0
- novelwriter/assets/syntax/light_owl.conf +1 -0
- novelwriter/assets/syntax/night_owl.conf +1 -0
- novelwriter/assets/syntax/solarized_dark.conf +1 -0
- novelwriter/assets/syntax/solarized_light.conf +1 -0
- novelwriter/assets/syntax/tango.conf +23 -0
- novelwriter/assets/syntax/tomorrow.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
- novelwriter/assets/text/credits_en.htm +25 -23
- novelwriter/assets/themes/cyberpunk_night.conf +29 -0
- novelwriter/common.py +12 -4
- novelwriter/config.py +47 -16
- novelwriter/constants.py +5 -6
- novelwriter/core/buildsettings.py +64 -44
- novelwriter/core/coretools.py +97 -13
- novelwriter/core/docbuild.py +74 -7
- novelwriter/core/document.py +24 -3
- novelwriter/core/index.py +31 -112
- novelwriter/core/project.py +11 -15
- novelwriter/core/projectxml.py +3 -2
- novelwriter/core/sessions.py +2 -2
- novelwriter/core/spellcheck.py +3 -3
- novelwriter/core/status.py +6 -5
- novelwriter/core/storage.py +16 -6
- novelwriter/core/tohtml.py +22 -25
- novelwriter/core/tokenizer.py +417 -237
- novelwriter/core/tomd.py +17 -8
- novelwriter/core/toodt.py +386 -351
- novelwriter/core/tree.py +8 -8
- novelwriter/dialogs/about.py +10 -12
- novelwriter/dialogs/docmerge.py +17 -14
- novelwriter/dialogs/docsplit.py +20 -19
- novelwriter/dialogs/editlabel.py +5 -4
- novelwriter/dialogs/preferences.py +32 -40
- novelwriter/dialogs/projectsettings.py +31 -28
- novelwriter/dialogs/quotes.py +10 -9
- novelwriter/dialogs/wordlist.py +18 -15
- novelwriter/enum.py +17 -14
- novelwriter/error.py +14 -12
- novelwriter/extensions/circularprogress.py +12 -8
- novelwriter/extensions/configlayout.py +23 -3
- novelwriter/extensions/modified.py +51 -2
- novelwriter/extensions/pagedsidebar.py +16 -14
- novelwriter/extensions/simpleprogress.py +3 -1
- novelwriter/extensions/statusled.py +3 -1
- novelwriter/extensions/switch.py +10 -9
- novelwriter/extensions/switchbox.py +14 -13
- novelwriter/extensions/versioninfo.py +1 -1
- novelwriter/gui/doceditor.py +433 -496
- novelwriter/gui/dochighlight.py +54 -33
- novelwriter/gui/docviewer.py +162 -175
- novelwriter/gui/docviewerpanel.py +20 -37
- novelwriter/gui/editordocument.py +15 -4
- novelwriter/gui/itemdetails.py +51 -54
- novelwriter/gui/mainmenu.py +37 -17
- novelwriter/gui/noveltree.py +31 -37
- novelwriter/gui/outline.py +120 -98
- novelwriter/gui/projtree.py +114 -112
- novelwriter/gui/search.py +362 -0
- novelwriter/gui/sidebar.py +36 -45
- novelwriter/gui/statusbar.py +14 -14
- novelwriter/gui/theme.py +116 -34
- novelwriter/guimain.py +216 -207
- novelwriter/shared.py +31 -6
- novelwriter/text/counting.py +138 -0
- novelwriter/tools/dictionaries.py +15 -14
- novelwriter/tools/lipsum.py +20 -17
- novelwriter/tools/manusbuild.py +43 -35
- novelwriter/tools/manuscript.py +381 -104
- novelwriter/tools/manussettings.py +263 -125
- novelwriter/tools/noveldetails.py +21 -19
- novelwriter/tools/welcome.py +59 -57
- novelwriter/tools/writingstats.py +61 -55
- novelwriter/types.py +90 -0
- novelWriter-2.3rc1.dist-info/entry_points.txt +0 -5
- novelwriter/core/__init__.py +0 -3
- novelwriter/dialogs/__init__.py +0 -3
- novelwriter/extensions/__init__.py +0 -3
- novelwriter/gui/__init__.py +0 -3
- novelwriter/tools/__init__.py +0 -3
- {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/top_level.txt +0 -0
novelwriter/core/tree.py
CHANGED
@@ -28,7 +28,7 @@ import logging
|
|
28
28
|
|
29
29
|
from typing import TYPE_CHECKING, Literal, overload
|
30
30
|
from pathlib import Path
|
31
|
-
from collections.abc import Iterator
|
31
|
+
from collections.abc import Iterable, Iterator
|
32
32
|
|
33
33
|
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
34
34
|
from novelwriter.error import logException
|
@@ -351,16 +351,16 @@ class NWTree:
|
|
351
351
|
return False
|
352
352
|
return tItem.itemType == itemType
|
353
353
|
|
354
|
-
def getItemPath(self, tHandle: str) -> list[str]:
|
354
|
+
def getItemPath(self, tHandle: str, asName: bool = False) -> list[str]:
|
355
355
|
"""Iterate upwards in the tree until we find the item with
|
356
|
-
parent None, the root item, and return the list of handles
|
357
|
-
We do this with a for loop with a
|
358
|
-
infinite loops impossible.
|
356
|
+
parent None, the root item, and return the list of handles, or
|
357
|
+
alternatively item names. We do this with a for loop with a
|
358
|
+
maximum depth to make infinite loops impossible.
|
359
359
|
"""
|
360
360
|
tTree = []
|
361
361
|
tItem = self.__getitem__(tHandle)
|
362
362
|
if tItem is not None:
|
363
|
-
tTree.append(tHandle)
|
363
|
+
tTree.append(tItem.itemName if asName else tHandle)
|
364
364
|
for _ in range(MAX_DEPTH):
|
365
365
|
if tItem.itemParent is None:
|
366
366
|
return tTree
|
@@ -370,7 +370,7 @@ class NWTree:
|
|
370
370
|
if tItem is None:
|
371
371
|
return tTree
|
372
372
|
else:
|
373
|
-
tTree.append(tHandle)
|
373
|
+
tTree.append(tItem.itemName if asName else tHandle)
|
374
374
|
else:
|
375
375
|
raise RecursionError("Critical internal error")
|
376
376
|
|
@@ -387,7 +387,7 @@ class NWTree:
|
|
387
387
|
rootClasses.add(nwItem.itemClass)
|
388
388
|
return rootClasses
|
389
389
|
|
390
|
-
def iterRoots(self, itemClass: nwItemClass | None) ->
|
390
|
+
def iterRoots(self, itemClass: nwItemClass | None) -> Iterable[tuple[str, NWItem]]:
|
391
391
|
"""Iterate over all root items of a given class in order."""
|
392
392
|
for tHandle in self._order:
|
393
393
|
nwItem = self.__getitem__(tHandle)
|
novelwriter/dialogs/about.py
CHANGED
@@ -26,16 +26,16 @@ from __future__ import annotations
|
|
26
26
|
import logging
|
27
27
|
|
28
28
|
from PyQt5.QtGui import QCloseEvent, QColor
|
29
|
-
from PyQt5.QtCore import Qt
|
30
29
|
from PyQt5.QtWidgets import (
|
31
30
|
QDialog, QDialogButtonBox, QHBoxLayout, QLabel, QTextBrowser, QVBoxLayout,
|
32
31
|
QWidget
|
33
32
|
)
|
34
33
|
|
35
34
|
from novelwriter import CONFIG, SHARED
|
36
|
-
from novelwriter.common import readTextFile
|
35
|
+
from novelwriter.common import cssCol, readTextFile
|
37
36
|
from novelwriter.extensions.configlayout import NColourLabel
|
38
37
|
from novelwriter.extensions.versioninfo import VersionInfoWidget
|
38
|
+
from novelwriter.types import QtAlignRightTop, QtDialogClose
|
39
39
|
|
40
40
|
logger = logging.getLogger(__name__)
|
41
41
|
|
@@ -68,9 +68,9 @@ class GuiAbout(QDialog):
|
|
68
68
|
|
69
69
|
self.nwInfo = VersionInfoWidget(self)
|
70
70
|
|
71
|
-
self.nwLicence = QLabel(self.tr("This application is licenced under {0}".format(
|
71
|
+
self.nwLicence = QLabel(self.tr("This application is licenced under {0}").format(
|
72
72
|
"<a href='https://www.gnu.org/licenses/gpl-3.0.html'>GPL v3.0</a>"
|
73
|
-
))
|
73
|
+
), self)
|
74
74
|
self.nwLicence.setOpenExternalLinks(True)
|
75
75
|
|
76
76
|
# Credits
|
@@ -84,7 +84,7 @@ class GuiAbout(QDialog):
|
|
84
84
|
self.txtCredits.setViewportMargins(0, hA, hA, 0)
|
85
85
|
|
86
86
|
# Buttons
|
87
|
-
self.btnBox = QDialogButtonBox(
|
87
|
+
self.btnBox = QDialogButtonBox(QtDialogClose, self)
|
88
88
|
self.btnBox.rejected.connect(self.close)
|
89
89
|
|
90
90
|
# Assemble
|
@@ -100,10 +100,8 @@ class GuiAbout(QDialog):
|
|
100
100
|
self.innerBox.addSpacing(hB)
|
101
101
|
self.innerBox.addWidget(self.btnBox)
|
102
102
|
|
103
|
-
topRight = Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignRight
|
104
|
-
|
105
103
|
self.outerBox = QHBoxLayout()
|
106
|
-
self.outerBox.addWidget(self.nwLogo, 0,
|
104
|
+
self.outerBox.addWidget(self.nwLogo, 0, QtAlignRightTop)
|
107
105
|
self.outerBox.addLayout(self.innerBox, 1)
|
108
106
|
|
109
107
|
self.setLayout(self.outerBox)
|
@@ -149,10 +147,10 @@ class GuiAbout(QDialog):
|
|
149
147
|
|
150
148
|
def _setStyleSheet(self) -> None:
|
151
149
|
"""Set stylesheet for all browser tabs."""
|
152
|
-
baseCol = self.palette().window().color()
|
153
|
-
self.txtCredits.setStyleSheet(
|
154
|
-
"QTextBrowser {{border: none; background:
|
155
|
-
)
|
150
|
+
baseCol = cssCol(self.palette().window().color())
|
151
|
+
self.txtCredits.setStyleSheet(
|
152
|
+
f"QTextBrowser {{border: none; background: {baseCol};}} "
|
153
|
+
)
|
156
154
|
return
|
157
155
|
|
158
156
|
# END Class GuiAbout
|
novelwriter/dialogs/docmerge.py
CHANGED
@@ -26,8 +26,8 @@ from __future__ import annotations
|
|
26
26
|
|
27
27
|
import logging
|
28
28
|
|
29
|
+
from PyQt5.QtCore import Qt, pyqtSlot
|
29
30
|
from PyQt5.QtGui import QCloseEvent
|
30
|
-
from PyQt5.QtCore import Qt, QSize, pyqtSlot
|
31
31
|
from PyQt5.QtWidgets import (
|
32
32
|
QAbstractItemView, QDialog, QDialogButtonBox, QGridLayout, QLabel,
|
33
33
|
QListWidget, QListWidgetItem, QVBoxLayout, QWidget
|
@@ -36,13 +36,14 @@ from PyQt5.QtWidgets import (
|
|
36
36
|
from novelwriter import CONFIG, SHARED
|
37
37
|
from novelwriter.extensions.switch import NSwitch
|
38
38
|
from novelwriter.extensions.configlayout import NColourLabel
|
39
|
+
from novelwriter.types import QtDialogCancel, QtDialogOk, QtDialogReset, QtUserRole
|
39
40
|
|
40
41
|
logger = logging.getLogger(__name__)
|
41
42
|
|
42
43
|
|
43
44
|
class GuiDocMerge(QDialog):
|
44
45
|
|
45
|
-
D_HANDLE =
|
46
|
+
D_HANDLE = QtUserRole
|
46
47
|
|
47
48
|
def __init__(self, parent: QWidget, sHandle: str, itemList: list[str]) -> None:
|
48
49
|
super().__init__(parent=parent)
|
@@ -53,27 +54,29 @@ class GuiDocMerge(QDialog):
|
|
53
54
|
|
54
55
|
self._data = {}
|
55
56
|
|
56
|
-
self.headLabel = QLabel(
|
57
|
+
self.headLabel = QLabel(self.tr("Documents to Merge"), self)
|
58
|
+
self.headLabel.setFont(SHARED.theme.guiFontB)
|
57
59
|
self.helpLabel = NColourLabel(
|
58
60
|
self.tr("Drag and drop items to change the order, or uncheck to exclude."),
|
59
61
|
SHARED.theme.helpText, parent=self, wrap=True
|
60
62
|
)
|
61
63
|
|
62
|
-
iPx = SHARED.theme.
|
64
|
+
iPx = SHARED.theme.baseIconHeight
|
65
|
+
iSz = SHARED.theme.baseIconSize
|
63
66
|
hSp = CONFIG.pxInt(12)
|
64
67
|
vSp = CONFIG.pxInt(8)
|
65
68
|
bSp = CONFIG.pxInt(12)
|
66
69
|
|
67
|
-
self.listBox = QListWidget()
|
68
|
-
self.listBox.setIconSize(
|
70
|
+
self.listBox = QListWidget(self)
|
71
|
+
self.listBox.setIconSize(iSz)
|
69
72
|
self.listBox.setMinimumWidth(CONFIG.pxInt(400))
|
70
73
|
self.listBox.setMinimumHeight(CONFIG.pxInt(180))
|
71
|
-
self.listBox.setSelectionBehavior(QAbstractItemView.SelectRows)
|
72
|
-
self.listBox.setSelectionMode(QAbstractItemView.SingleSelection)
|
73
|
-
self.listBox.setDragDropMode(QAbstractItemView.InternalMove)
|
74
|
+
self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
75
|
+
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
76
|
+
self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
|
74
77
|
|
75
78
|
# Merge Options
|
76
|
-
self.trashLabel = QLabel(self.tr("Move merged items to Trash"))
|
79
|
+
self.trashLabel = QLabel(self.tr("Move merged items to Trash"), self)
|
77
80
|
self.trashSwitch = NSwitch(self, height=iPx)
|
78
81
|
|
79
82
|
self.optBox = QGridLayout()
|
@@ -83,11 +86,11 @@ class GuiDocMerge(QDialog):
|
|
83
86
|
self.optBox.setColumnStretch(2, 1)
|
84
87
|
|
85
88
|
# Buttons
|
86
|
-
self.buttonBox = QDialogButtonBox(
|
89
|
+
self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
|
87
90
|
self.buttonBox.accepted.connect(self.accept)
|
88
91
|
self.buttonBox.rejected.connect(self.reject)
|
89
92
|
|
90
|
-
self.resetButton = self.buttonBox.addButton(
|
93
|
+
self.resetButton = self.buttonBox.addButton(QtDialogReset)
|
91
94
|
self.resetButton.clicked.connect(self._resetList)
|
92
95
|
|
93
96
|
# Assemble
|
@@ -119,7 +122,7 @@ class GuiDocMerge(QDialog):
|
|
119
122
|
finalItems = []
|
120
123
|
for i in range(self.listBox.count()):
|
121
124
|
item = self.listBox.item(i)
|
122
|
-
if item is not None and item.checkState() == Qt.Checked:
|
125
|
+
if item is not None and item.checkState() == Qt.CheckState.Checked:
|
123
126
|
finalItems.append(item.data(self.D_HANDLE))
|
124
127
|
|
125
128
|
self._data["moveToTrash"] = self.trashSwitch.isChecked()
|
@@ -174,7 +177,7 @@ class GuiDocMerge(QDialog):
|
|
174
177
|
newItem.setIcon(itemIcon)
|
175
178
|
newItem.setText(nwItem.itemName)
|
176
179
|
newItem.setData(self.D_HANDLE, tHandle)
|
177
|
-
newItem.setCheckState(Qt.Checked)
|
180
|
+
newItem.setCheckState(Qt.CheckState.Checked)
|
178
181
|
|
179
182
|
self.listBox.addItem(newItem)
|
180
183
|
|
novelwriter/dialogs/docsplit.py
CHANGED
@@ -26,8 +26,8 @@ from __future__ import annotations
|
|
26
26
|
|
27
27
|
import logging
|
28
28
|
|
29
|
+
from PyQt5.QtCore import pyqtSlot
|
29
30
|
from PyQt5.QtGui import QCloseEvent
|
30
|
-
from PyQt5.QtCore import Qt, pyqtSlot
|
31
31
|
from PyQt5.QtWidgets import (
|
32
32
|
QAbstractItemView, QComboBox, QDialog, QDialogButtonBox, QGridLayout,
|
33
33
|
QLabel, QListWidget, QListWidgetItem, QVBoxLayout, QWidget
|
@@ -36,15 +36,16 @@ from PyQt5.QtWidgets import (
|
|
36
36
|
from novelwriter import CONFIG, SHARED
|
37
37
|
from novelwriter.extensions.switch import NSwitch
|
38
38
|
from novelwriter.extensions.configlayout import NColourLabel
|
39
|
+
from novelwriter.types import QtDialogCancel, QtDialogOk, QtUserRole
|
39
40
|
|
40
41
|
logger = logging.getLogger(__name__)
|
41
42
|
|
42
43
|
|
43
44
|
class GuiDocSplit(QDialog):
|
44
45
|
|
45
|
-
LINE_ROLE =
|
46
|
-
LEVEL_ROLE =
|
47
|
-
LABEL_ROLE =
|
46
|
+
LINE_ROLE = QtUserRole
|
47
|
+
LEVEL_ROLE = QtUserRole + 1
|
48
|
+
LABEL_ROLE = QtUserRole + 2
|
48
49
|
|
49
50
|
def __init__(self, parent: QWidget, sHandle: str) -> None:
|
50
51
|
super().__init__(parent=parent)
|
@@ -57,14 +58,15 @@ class GuiDocSplit(QDialog):
|
|
57
58
|
|
58
59
|
self.setWindowTitle(self.tr("Split Document"))
|
59
60
|
|
60
|
-
self.headLabel = QLabel(
|
61
|
+
self.headLabel = QLabel(self.tr("Document Headings"), self)
|
62
|
+
self.headLabel.setFont(SHARED.theme.guiFontB)
|
61
63
|
self.helpLabel = NColourLabel(
|
62
64
|
self.tr("Select the maximum level to split into files."),
|
63
65
|
SHARED.theme.helpText, parent=self, wrap=True
|
64
66
|
)
|
65
67
|
|
66
68
|
# Values
|
67
|
-
iPx = SHARED.theme.
|
69
|
+
iPx = SHARED.theme.baseIconHeight
|
68
70
|
hSp = CONFIG.pxInt(12)
|
69
71
|
vSp = CONFIG.pxInt(8)
|
70
72
|
bSp = CONFIG.pxInt(12)
|
@@ -74,32 +76,32 @@ class GuiDocSplit(QDialog):
|
|
74
76
|
intoFolder = pOptions.getBool("GuiDocSplit", "intoFolder", True)
|
75
77
|
docHierarchy = pOptions.getBool("GuiDocSplit", "docHierarchy", True)
|
76
78
|
|
77
|
-
#
|
78
|
-
self.listBox = QListWidget()
|
79
|
-
self.listBox.setDragDropMode(QAbstractItemView.NoDragDrop)
|
79
|
+
# Heading Selection
|
80
|
+
self.listBox = QListWidget(self)
|
81
|
+
self.listBox.setDragDropMode(QAbstractItemView.DragDropMode.NoDragDrop)
|
80
82
|
self.listBox.setMinimumWidth(CONFIG.pxInt(400))
|
81
83
|
self.listBox.setMinimumHeight(CONFIG.pxInt(180))
|
82
84
|
|
83
85
|
self.splitLevel = QComboBox(self)
|
84
|
-
self.splitLevel.addItem(self.tr("Split on
|
85
|
-
self.splitLevel.addItem(self.tr("Split up to
|
86
|
-
self.splitLevel.addItem(self.tr("Split up to
|
87
|
-
self.splitLevel.addItem(self.tr("Split up to
|
86
|
+
self.splitLevel.addItem(self.tr("Split on Heading Level 1 (Partition)"), 1)
|
87
|
+
self.splitLevel.addItem(self.tr("Split up to Heading Level 2 (Chapter)"), 2)
|
88
|
+
self.splitLevel.addItem(self.tr("Split up to Heading Level 3 (Scene)"), 3)
|
89
|
+
self.splitLevel.addItem(self.tr("Split up to Heading Level 4 (Section)"), 4)
|
88
90
|
spIndex = self.splitLevel.findData(spLevel)
|
89
91
|
if spIndex != -1:
|
90
92
|
self.splitLevel.setCurrentIndex(spIndex)
|
91
93
|
self.splitLevel.currentIndexChanged.connect(self._reloadList)
|
92
94
|
|
93
95
|
# Split Options
|
94
|
-
self.folderLabel = QLabel(self.tr("Split into a new folder"))
|
96
|
+
self.folderLabel = QLabel(self.tr("Split into a new folder"), self)
|
95
97
|
self.folderSwitch = NSwitch(self, height=iPx)
|
96
98
|
self.folderSwitch.setChecked(intoFolder)
|
97
99
|
|
98
|
-
self.hierarchyLabel = QLabel(self.tr("Create document hierarchy"))
|
100
|
+
self.hierarchyLabel = QLabel(self.tr("Create document hierarchy"), self)
|
99
101
|
self.hierarchySwitch = NSwitch(self, height=iPx)
|
100
102
|
self.hierarchySwitch.setChecked(docHierarchy)
|
101
103
|
|
102
|
-
self.trashLabel = QLabel(self.tr("Move split document to Trash"))
|
104
|
+
self.trashLabel = QLabel(self.tr("Move split document to Trash"), self)
|
103
105
|
self.trashSwitch = NSwitch(self, height=iPx)
|
104
106
|
|
105
107
|
self.optBox = QGridLayout()
|
@@ -114,7 +116,7 @@ class GuiDocSplit(QDialog):
|
|
114
116
|
self.optBox.setColumnStretch(3, 1)
|
115
117
|
|
116
118
|
# Buttons
|
117
|
-
self.buttonBox = QDialogButtonBox(
|
119
|
+
self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
|
118
120
|
self.buttonBox.accepted.connect(self.accept)
|
119
121
|
self.buttonBox.rejected.connect(self.reject)
|
120
122
|
|
@@ -214,8 +216,7 @@ class GuiDocSplit(QDialog):
|
|
214
216
|
|
215
217
|
spLevel = self.splitLevel.currentData()
|
216
218
|
if not self._text:
|
217
|
-
|
218
|
-
self._text = (inDoc.readDocument() or "").splitlines()
|
219
|
+
self._text = SHARED.project.storage.getDocumentText(sHandle).splitlines()
|
219
220
|
|
220
221
|
for lineNo, aLine in enumerate(self._text):
|
221
222
|
|
novelwriter/dialogs/editlabel.py
CHANGED
@@ -31,6 +31,7 @@ from PyQt5.QtWidgets import (
|
|
31
31
|
)
|
32
32
|
|
33
33
|
from novelwriter import CONFIG
|
34
|
+
from novelwriter.types import QtDialogCancel, QtDialogOk
|
34
35
|
|
35
36
|
logger = logging.getLogger(__name__)
|
36
37
|
|
@@ -55,13 +56,13 @@ class GuiEditLabel(QDialog):
|
|
55
56
|
self.labelValue.selectAll()
|
56
57
|
|
57
58
|
# Buttons
|
58
|
-
self.buttonBox = QDialogButtonBox(
|
59
|
+
self.buttonBox = QDialogButtonBox(QtDialogOk | QtDialogCancel, self)
|
59
60
|
self.buttonBox.accepted.connect(self.accept)
|
60
61
|
self.buttonBox.rejected.connect(self.reject)
|
61
62
|
|
62
63
|
# Assemble
|
63
64
|
self.innerBox = QHBoxLayout()
|
64
|
-
self.innerBox.addWidget(QLabel(self.tr("Label")), 0)
|
65
|
+
self.innerBox.addWidget(QLabel(self.tr("Label"), self), 0)
|
65
66
|
self.innerBox.addWidget(self.labelValue, 1)
|
66
67
|
self.innerBox.setSpacing(mSp)
|
67
68
|
|
@@ -88,9 +89,9 @@ class GuiEditLabel(QDialog):
|
|
88
89
|
def getLabel(cls, parent: QWidget, text: str) -> tuple[str, bool]:
|
89
90
|
"""Pop the dialog and return the result."""
|
90
91
|
cls = GuiEditLabel(parent, text=text)
|
91
|
-
cls.
|
92
|
+
cls.exec()
|
92
93
|
label = cls.itemLabel
|
93
|
-
accepted = cls.result() == QDialog.Accepted
|
94
|
+
accepted = cls.result() == QDialog.DialogCode.Accepted
|
94
95
|
cls.deleteLater()
|
95
96
|
return label, accepted
|
96
97
|
|
@@ -26,21 +26,25 @@ from __future__ import annotations
|
|
26
26
|
|
27
27
|
import logging
|
28
28
|
|
29
|
-
from PyQt5.QtGui import QCloseEvent, QFont, QKeyEvent, QKeySequence
|
30
29
|
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
30
|
+
from PyQt5.QtGui import QCloseEvent, QFont, QKeyEvent, QKeySequence
|
31
31
|
from PyQt5.QtWidgets import (
|
32
|
-
QAbstractButton, QCompleter, QDialog, QDialogButtonBox,
|
33
|
-
QFontDialog, QHBoxLayout, QLineEdit, QPushButton,
|
34
|
-
QWidget
|
32
|
+
QAbstractButton, QApplication, QCompleter, QDialog, QDialogButtonBox,
|
33
|
+
QFileDialog, QFontDialog, QHBoxLayout, QLineEdit, QPushButton, QVBoxLayout,
|
34
|
+
QWidget
|
35
35
|
)
|
36
36
|
|
37
37
|
from novelwriter import CONFIG, SHARED
|
38
38
|
from novelwriter.constants import nwConst, nwUnicode
|
39
39
|
from novelwriter.dialogs.quotes import GuiQuoteSelect
|
40
|
-
from novelwriter.extensions.switch import NSwitch
|
41
|
-
from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NSpinBox
|
42
40
|
from novelwriter.extensions.configlayout import NColourLabel, NScrollableForm
|
41
|
+
from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NIconToolButton, NSpinBox
|
43
42
|
from novelwriter.extensions.pagedsidebar import NPagedSideBar
|
43
|
+
from novelwriter.extensions.switch import NSwitch
|
44
|
+
from novelwriter.types import (
|
45
|
+
QtAlignCenter, QtDialogApply, QtDialogClose, QtDialogSave, QtRoleAccept,
|
46
|
+
QtRoleApply, QtRoleReject
|
47
|
+
)
|
44
48
|
|
45
49
|
logger = logging.getLogger(__name__)
|
46
50
|
|
@@ -83,11 +87,7 @@ class GuiPreferences(QDialog):
|
|
83
87
|
self.mainForm.setHelpTextStyle(SHARED.theme.helpText)
|
84
88
|
|
85
89
|
# Buttons
|
86
|
-
self.buttonBox = QDialogButtonBox(
|
87
|
-
QDialogButtonBox.StandardButton.Apply
|
88
|
-
| QDialogButtonBox.StandardButton.Save
|
89
|
-
| QDialogButtonBox.StandardButton.Close
|
90
|
-
)
|
90
|
+
self.buttonBox = QDialogButtonBox(QtDialogApply | QtDialogSave | QtDialogClose, self)
|
91
91
|
self.buttonBox.clicked.connect(self._dialogButtonClicked)
|
92
92
|
|
93
93
|
# Assemble
|
@@ -132,8 +132,8 @@ class GuiPreferences(QDialog):
|
|
132
132
|
def buildForm(self) -> None:
|
133
133
|
"""Build the settings form."""
|
134
134
|
section = 0
|
135
|
+
iSz = SHARED.theme.baseIconSize
|
135
136
|
minWidth = CONFIG.pxInt(200)
|
136
|
-
mIcon = SHARED.theme.getIcon("more")
|
137
137
|
|
138
138
|
# Label
|
139
139
|
self.sidebar.addLabel(self.tr("General"))
|
@@ -151,8 +151,7 @@ class GuiPreferences(QDialog):
|
|
151
151
|
self.guiLocale.setMinimumWidth(minWidth)
|
152
152
|
for lang, name in CONFIG.listLanguages(CONFIG.LANG_NW):
|
153
153
|
self.guiLocale.addItem(name, lang)
|
154
|
-
|
155
|
-
self.guiLocale.setCurrentIndex(idx)
|
154
|
+
self.guiLocale.setCurrentData(CONFIG.guiLocale, "en_GB")
|
156
155
|
|
157
156
|
self.mainForm.addRow(
|
158
157
|
self.tr("Display language"), self.guiLocale,
|
@@ -164,8 +163,7 @@ class GuiPreferences(QDialog):
|
|
164
163
|
self.guiTheme.setMinimumWidth(minWidth)
|
165
164
|
for theme, name in SHARED.theme.listThemes():
|
166
165
|
self.guiTheme.addItem(name, theme)
|
167
|
-
|
168
|
-
self.guiTheme.setCurrentIndex(idx)
|
166
|
+
self.guiTheme.setCurrentData(CONFIG.guiTheme, "default")
|
169
167
|
|
170
168
|
self.mainForm.addRow(
|
171
169
|
self.tr("Colour theme"), self.guiTheme,
|
@@ -177,8 +175,7 @@ class GuiPreferences(QDialog):
|
|
177
175
|
self.guiFont.setReadOnly(True)
|
178
176
|
self.guiFont.setMinimumWidth(CONFIG.pxInt(162))
|
179
177
|
self.guiFont.setText(CONFIG.guiFont)
|
180
|
-
self.guiFontButton =
|
181
|
-
self.guiFontButton.setIcon(mIcon)
|
178
|
+
self.guiFontButton = NIconToolButton(self, iSz, "more")
|
182
179
|
self.guiFontButton.clicked.connect(self._selectGuiFont)
|
183
180
|
self.mainForm.addRow(
|
184
181
|
self.tr("Application font family"), self.guiFont,
|
@@ -226,8 +223,7 @@ class GuiPreferences(QDialog):
|
|
226
223
|
self.guiSyntax.setMinimumWidth(CONFIG.pxInt(200))
|
227
224
|
for syntax, name in SHARED.theme.listSyntax():
|
228
225
|
self.guiSyntax.addItem(name, syntax)
|
229
|
-
|
230
|
-
self.guiSyntax.setCurrentIndex(idx)
|
226
|
+
self.guiSyntax.setCurrentData(CONFIG.guiSyntax, "default_light")
|
231
227
|
|
232
228
|
self.mainForm.addRow(
|
233
229
|
self.tr("Document colour theme"), self.guiSyntax,
|
@@ -239,8 +235,7 @@ class GuiPreferences(QDialog):
|
|
239
235
|
self.textFont.setReadOnly(True)
|
240
236
|
self.textFont.setMinimumWidth(CONFIG.pxInt(162))
|
241
237
|
self.textFont.setText(CONFIG.textFont)
|
242
|
-
self.textFontButton =
|
243
|
-
self.textFontButton.setIcon(mIcon)
|
238
|
+
self.textFontButton = NIconToolButton(self, iSz, "more")
|
244
239
|
self.textFontButton.clicked.connect(self._selectTextFont)
|
245
240
|
self.mainForm.addRow(
|
246
241
|
self.tr("Document font family"), self.textFont,
|
@@ -323,6 +318,7 @@ class GuiPreferences(QDialog):
|
|
323
318
|
# Backup Path
|
324
319
|
self.backupPath = CONFIG.backupPath()
|
325
320
|
self.backupGetPath = QPushButton(SHARED.theme.getIcon("browse"), self.tr("Browse"), self)
|
321
|
+
self.backupGetPath.setIconSize(iSz)
|
326
322
|
self.backupGetPath.clicked.connect(self._backupFolder)
|
327
323
|
self.mainForm.addRow(
|
328
324
|
self.tr("Backup storage location"), self.backupGetPath,
|
@@ -678,10 +674,9 @@ class GuiPreferences(QDialog):
|
|
678
674
|
self.quoteSym["SO"].setMaxLength(1)
|
679
675
|
self.quoteSym["SO"].setReadOnly(True)
|
680
676
|
self.quoteSym["SO"].setFixedWidth(qWidth)
|
681
|
-
self.quoteSym["SO"].setAlignment(
|
677
|
+
self.quoteSym["SO"].setAlignment(QtAlignCenter)
|
682
678
|
self.quoteSym["SO"].setText(CONFIG.fmtSQuoteOpen)
|
683
|
-
self.btnSingleStyleO =
|
684
|
-
self.btnSingleStyleO.setIcon(mIcon)
|
679
|
+
self.btnSingleStyleO = NIconToolButton(self, iSz, "more")
|
685
680
|
self.btnSingleStyleO.clicked.connect(lambda: self._getQuote("SO"))
|
686
681
|
self.mainForm.addRow(
|
687
682
|
self.tr("Single quote open style"), self.quoteSym["SO"],
|
@@ -693,10 +688,9 @@ class GuiPreferences(QDialog):
|
|
693
688
|
self.quoteSym["SC"].setMaxLength(1)
|
694
689
|
self.quoteSym["SC"].setReadOnly(True)
|
695
690
|
self.quoteSym["SC"].setFixedWidth(qWidth)
|
696
|
-
self.quoteSym["SC"].setAlignment(
|
691
|
+
self.quoteSym["SC"].setAlignment(QtAlignCenter)
|
697
692
|
self.quoteSym["SC"].setText(CONFIG.fmtSQuoteClose)
|
698
|
-
self.btnSingleStyleC =
|
699
|
-
self.btnSingleStyleC.setIcon(mIcon)
|
693
|
+
self.btnSingleStyleC = NIconToolButton(self, iSz, "more")
|
700
694
|
self.btnSingleStyleC.clicked.connect(lambda: self._getQuote("SC"))
|
701
695
|
self.mainForm.addRow(
|
702
696
|
self.tr("Single quote close style"), self.quoteSym["SC"],
|
@@ -709,10 +703,9 @@ class GuiPreferences(QDialog):
|
|
709
703
|
self.quoteSym["DO"].setMaxLength(1)
|
710
704
|
self.quoteSym["DO"].setReadOnly(True)
|
711
705
|
self.quoteSym["DO"].setFixedWidth(qWidth)
|
712
|
-
self.quoteSym["DO"].setAlignment(
|
706
|
+
self.quoteSym["DO"].setAlignment(QtAlignCenter)
|
713
707
|
self.quoteSym["DO"].setText(CONFIG.fmtDQuoteOpen)
|
714
|
-
self.btnDoubleStyleO =
|
715
|
-
self.btnDoubleStyleO.setIcon(mIcon)
|
708
|
+
self.btnDoubleStyleO = NIconToolButton(self, iSz, "more")
|
716
709
|
self.btnDoubleStyleO.clicked.connect(lambda: self._getQuote("DO"))
|
717
710
|
self.mainForm.addRow(
|
718
711
|
self.tr("Double quote open style"), self.quoteSym["DO"],
|
@@ -724,10 +717,9 @@ class GuiPreferences(QDialog):
|
|
724
717
|
self.quoteSym["DC"].setMaxLength(1)
|
725
718
|
self.quoteSym["DC"].setReadOnly(True)
|
726
719
|
self.quoteSym["DC"].setFixedWidth(qWidth)
|
727
|
-
self.quoteSym["DC"].setAlignment(
|
720
|
+
self.quoteSym["DC"].setAlignment(QtAlignCenter)
|
728
721
|
self.quoteSym["DC"].setText(CONFIG.fmtDQuoteClose)
|
729
|
-
self.btnDoubleStyleC =
|
730
|
-
self.btnDoubleStyleC.setIcon(mIcon)
|
722
|
+
self.btnDoubleStyleC = NIconToolButton(self, iSz, "more")
|
731
723
|
self.btnDoubleStyleC.clicked.connect(lambda: self._getQuote("DC"))
|
732
724
|
self.mainForm.addRow(
|
733
725
|
self.tr("Double quote close style"), self.quoteSym["DC"],
|
@@ -749,7 +741,7 @@ class GuiPreferences(QDialog):
|
|
749
741
|
logger.debug("Close: GuiPreferences")
|
750
742
|
self._saveWindowSize()
|
751
743
|
event.accept()
|
752
|
-
|
744
|
+
QApplication.processEvents()
|
753
745
|
self.done(nwConst.DLG_FINISHED)
|
754
746
|
self.deleteLater()
|
755
747
|
return
|
@@ -769,12 +761,12 @@ class GuiPreferences(QDialog):
|
|
769
761
|
def _dialogButtonClicked(self, button: QAbstractButton) -> None:
|
770
762
|
"""Handle button clicks from the dialog button box."""
|
771
763
|
role = self.buttonBox.buttonRole(button)
|
772
|
-
if role ==
|
764
|
+
if role == QtRoleApply:
|
773
765
|
self._saveValues()
|
774
|
-
elif role ==
|
766
|
+
elif role == QtRoleAccept:
|
775
767
|
self._saveValues()
|
776
768
|
self.close()
|
777
|
-
elif role ==
|
769
|
+
elif role == QtRoleReject:
|
778
770
|
self.close()
|
779
771
|
return
|
780
772
|
|
@@ -803,7 +795,7 @@ class GuiPreferences(QDialog):
|
|
803
795
|
return
|
804
796
|
|
805
797
|
@pyqtSlot()
|
806
|
-
def _selectTextFont(self):
|
798
|
+
def _selectTextFont(self) -> None:
|
807
799
|
"""Open the QFontDialog and set a font for the font style."""
|
808
800
|
current = QFont()
|
809
801
|
current.setFamily(CONFIG.textFont)
|
@@ -819,7 +811,7 @@ class GuiPreferences(QDialog):
|
|
819
811
|
"""Open a dialog to select the backup folder."""
|
820
812
|
if path := QFileDialog.getExistingDirectory(
|
821
813
|
self, self.tr("Backup Directory"), str(self.backupPath) or "",
|
822
|
-
options=QFileDialog.ShowDirsOnly
|
814
|
+
options=QFileDialog.Option.ShowDirsOnly
|
823
815
|
):
|
824
816
|
self.backupPath = path
|
825
817
|
self.mainForm.setHelpText("backupPath", self.tr("Path: {0}").format(path))
|