novelWriter 2.5.2__py3-none-any.whl → 2.6__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.5.2.dist-info → novelWriter-2.6.dist-info}/METADATA +5 -4
- {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/RECORD +126 -105
- {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/WHEEL +1 -1
- novelwriter/__init__.py +50 -11
- 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_pl_PL.qm +0 -0
- novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
- novelwriter/assets/i18n/nw_ru_RU.qm +0 -0
- novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
- novelwriter/assets/i18n/project_de_DE.json +4 -2
- novelwriter/assets/i18n/project_en_GB.json +1 -0
- novelwriter/assets/i18n/project_en_US.json +2 -0
- novelwriter/assets/i18n/project_it_IT.json +2 -0
- novelwriter/assets/i18n/project_ja_JP.json +2 -0
- novelwriter/assets/i18n/project_nb_NO.json +2 -0
- novelwriter/assets/i18n/project_nl_NL.json +2 -0
- novelwriter/assets/i18n/project_pl_PL.json +2 -0
- novelwriter/assets/i18n/project_pt_BR.json +2 -0
- novelwriter/assets/i18n/project_ru_RU.json +11 -0
- novelwriter/assets/i18n/project_zh_CN.json +2 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +8 -0
- novelwriter/assets/icons/typicons_dark/mixed_copy.svg +4 -0
- novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +6 -0
- novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +5 -0
- novelwriter/assets/icons/typicons_light/icons.conf +8 -0
- novelwriter/assets/icons/typicons_light/mixed_copy.svg +4 -0
- novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_size-height.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_size-width.svg +6 -0
- novelwriter/assets/icons/typicons_light/nw_toolbar.svg +5 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/text/credits_en.htm +1 -0
- novelwriter/assets/themes/default_light.conf +2 -2
- novelwriter/common.py +101 -3
- novelwriter/config.py +30 -17
- novelwriter/constants.py +189 -81
- novelwriter/core/buildsettings.py +74 -40
- novelwriter/core/coretools.py +146 -148
- novelwriter/core/docbuild.py +133 -171
- novelwriter/core/document.py +1 -1
- novelwriter/core/index.py +39 -38
- novelwriter/core/item.py +42 -9
- novelwriter/core/itemmodel.py +518 -0
- novelwriter/core/options.py +5 -2
- novelwriter/core/project.py +68 -90
- novelwriter/core/projectdata.py +8 -2
- novelwriter/core/projectxml.py +1 -1
- novelwriter/core/sessions.py +1 -1
- novelwriter/core/spellcheck.py +10 -15
- novelwriter/core/status.py +24 -8
- novelwriter/core/storage.py +1 -1
- novelwriter/core/tree.py +269 -288
- novelwriter/dialogs/about.py +1 -1
- novelwriter/dialogs/docmerge.py +8 -18
- novelwriter/dialogs/docsplit.py +1 -1
- novelwriter/dialogs/editlabel.py +1 -1
- novelwriter/dialogs/preferences.py +47 -34
- novelwriter/dialogs/projectsettings.py +149 -99
- novelwriter/dialogs/quotes.py +1 -1
- novelwriter/dialogs/wordlist.py +11 -10
- novelwriter/enum.py +37 -24
- novelwriter/error.py +2 -2
- novelwriter/extensions/configlayout.py +28 -13
- novelwriter/extensions/eventfilters.py +1 -1
- novelwriter/extensions/modified.py +30 -6
- novelwriter/extensions/novelselector.py +4 -3
- novelwriter/extensions/pagedsidebar.py +9 -9
- novelwriter/extensions/progressbars.py +4 -4
- novelwriter/extensions/statusled.py +3 -3
- novelwriter/extensions/switch.py +3 -3
- novelwriter/extensions/switchbox.py +1 -1
- novelwriter/extensions/versioninfo.py +1 -1
- novelwriter/formats/shared.py +156 -0
- novelwriter/formats/todocx.py +1191 -0
- novelwriter/formats/tohtml.py +454 -0
- novelwriter/{core → formats}/tokenizer.py +497 -495
- novelwriter/formats/tomarkdown.py +218 -0
- novelwriter/{core → formats}/toodt.py +312 -433
- novelwriter/formats/toqdoc.py +486 -0
- novelwriter/formats/toraw.py +91 -0
- novelwriter/gui/doceditor.py +347 -287
- novelwriter/gui/dochighlight.py +97 -85
- novelwriter/gui/docviewer.py +90 -33
- novelwriter/gui/docviewerpanel.py +18 -26
- novelwriter/gui/editordocument.py +18 -3
- novelwriter/gui/itemdetails.py +27 -29
- novelwriter/gui/mainmenu.py +130 -64
- novelwriter/gui/noveltree.py +46 -48
- novelwriter/gui/outline.py +202 -256
- novelwriter/gui/projtree.py +590 -1238
- novelwriter/gui/search.py +11 -19
- novelwriter/gui/sidebar.py +8 -7
- novelwriter/gui/statusbar.py +20 -3
- novelwriter/gui/theme.py +11 -6
- novelwriter/guimain.py +101 -201
- novelwriter/shared.py +67 -28
- novelwriter/text/counting.py +3 -1
- novelwriter/text/patterns.py +169 -61
- novelwriter/tools/dictionaries.py +3 -3
- novelwriter/tools/lipsum.py +1 -1
- novelwriter/tools/manusbuild.py +15 -13
- novelwriter/tools/manuscript.py +121 -79
- novelwriter/tools/manussettings.py +424 -291
- novelwriter/tools/noveldetails.py +1 -1
- novelwriter/tools/welcome.py +6 -6
- novelwriter/tools/writingstats.py +4 -4
- novelwriter/types.py +25 -9
- novelwriter/core/tohtml.py +0 -530
- novelwriter/core/tomarkdown.py +0 -252
- novelwriter/core/toqdoc.py +0 -419
- {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/top_level.txt +0 -0
novelwriter/text/counting.py
CHANGED
@@ -8,7 +8,7 @@ Rewritten: 2024-02-27 [2.4b1] preProcessText, standardCounter
|
|
8
8
|
Created: 2024-02-27 [2.4b1] bodyTextCounter
|
9
9
|
|
10
10
|
This file is a part of novelWriter
|
11
|
-
Copyright
|
11
|
+
Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
|
12
12
|
|
13
13
|
This program is free software: you can redistribute it and/or modify
|
14
14
|
it under the terms of the GNU General Public License as published by
|
@@ -30,6 +30,7 @@ import re
|
|
30
30
|
from novelwriter.constants import nwRegEx, nwUnicode
|
31
31
|
|
32
32
|
RX_SC = re.compile(nwRegEx.FMT_SC)
|
33
|
+
RX_SV = re.compile(nwRegEx.FMT_SV)
|
33
34
|
RX_LO = re.compile(r"(?i)(?<!\\)(\[(?:vspace|newpage|new page)(:\d+)?)(?<!\\)(\])")
|
34
35
|
|
35
36
|
|
@@ -64,6 +65,7 @@ def preProcessText(text: str, keepHeaders: bool = True) -> list[str]:
|
|
64
65
|
# Strip shortcodes and special formatting
|
65
66
|
# RegEx is slow, so we do this only when necessary
|
66
67
|
line = RX_SC.sub("", line)
|
68
|
+
line = RX_SV.sub("", line)
|
67
69
|
line = RX_LO.sub("", line)
|
68
70
|
|
69
71
|
result.append(line)
|
novelwriter/text/patterns.py
CHANGED
@@ -3,10 +3,11 @@ novelWriter – Text Pattern Functions
|
|
3
3
|
====================================
|
4
4
|
|
5
5
|
File History:
|
6
|
-
Created: 2024-06-01 [2.
|
6
|
+
Created: 2024-06-01 [2.5rc1] RegExPatterns
|
7
|
+
Created: 2024-11-04 [2.6b1] DialogParser
|
7
8
|
|
8
9
|
This file is a part of novelWriter
|
9
|
-
Copyright
|
10
|
+
Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
|
10
11
|
|
11
12
|
This program is free software: you can redistribute it and/or modify
|
12
13
|
it under the terms of the GNU General Public License as published by
|
@@ -23,91 +24,198 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
23
24
|
"""
|
24
25
|
from __future__ import annotations
|
25
26
|
|
26
|
-
|
27
|
+
import re
|
27
28
|
|
28
29
|
from novelwriter import CONFIG
|
29
|
-
from novelwriter.
|
30
|
-
from novelwriter.
|
30
|
+
from novelwriter.common import compact, uniqueCompact
|
31
|
+
from novelwriter.constants import nwRegEx, nwUnicode
|
31
32
|
|
32
33
|
|
33
34
|
class RegExPatterns:
|
34
35
|
|
36
|
+
AMBIGUOUS = (nwUnicode.U_APOS, nwUnicode.U_RSQUO)
|
37
|
+
|
38
|
+
# Static RegExes
|
39
|
+
_rxUrl = re.compile(nwRegEx.URL, re.ASCII)
|
40
|
+
_rxWords = re.compile(nwRegEx.WORDS, re.UNICODE)
|
41
|
+
_rxBreak = re.compile(nwRegEx.BREAK, re.UNICODE)
|
42
|
+
_rxItalic = re.compile(nwRegEx.FMT_EI, re.UNICODE)
|
43
|
+
_rxBold = re.compile(nwRegEx.FMT_EB, re.UNICODE)
|
44
|
+
_rxStrike = re.compile(nwRegEx.FMT_ST, re.UNICODE)
|
45
|
+
_rxSCPlain = re.compile(nwRegEx.FMT_SC, re.UNICODE)
|
46
|
+
_rxSCValue = re.compile(nwRegEx.FMT_SV, re.UNICODE)
|
47
|
+
|
35
48
|
@property
|
36
|
-
def
|
49
|
+
def url(self) -> re.Pattern:
|
50
|
+
"""Find URLs."""
|
51
|
+
return self._rxUrl
|
52
|
+
|
53
|
+
@property
|
54
|
+
def wordSplit(self) -> re.Pattern:
|
55
|
+
"""Split text into words."""
|
56
|
+
return self._rxWords
|
57
|
+
|
58
|
+
@property
|
59
|
+
def lineBreak(self) -> re.Pattern:
|
60
|
+
"""Find forced line break."""
|
61
|
+
return self._rxBreak
|
62
|
+
|
63
|
+
@property
|
64
|
+
def markdownItalic(self) -> re.Pattern:
|
37
65
|
"""Markdown italic style."""
|
38
|
-
|
39
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
40
|
-
return rxRule
|
66
|
+
return self._rxItalic
|
41
67
|
|
42
68
|
@property
|
43
|
-
def markdownBold(self) ->
|
69
|
+
def markdownBold(self) -> re.Pattern:
|
44
70
|
"""Markdown bold style."""
|
45
|
-
|
46
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
47
|
-
return rxRule
|
71
|
+
return self._rxBold
|
48
72
|
|
49
73
|
@property
|
50
|
-
def markdownStrike(self) ->
|
74
|
+
def markdownStrike(self) -> re.Pattern:
|
51
75
|
"""Markdown strikethrough style."""
|
52
|
-
|
53
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
54
|
-
return rxRule
|
76
|
+
return self._rxStrike
|
55
77
|
|
56
78
|
@property
|
57
|
-
def shortcodePlain(self) ->
|
79
|
+
def shortcodePlain(self) -> re.Pattern:
|
58
80
|
"""Plain shortcode style."""
|
59
|
-
|
60
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
61
|
-
return rxRule
|
81
|
+
return self._rxSCPlain
|
62
82
|
|
63
83
|
@property
|
64
|
-
def shortcodeValue(self) ->
|
84
|
+
def shortcodeValue(self) -> re.Pattern:
|
65
85
|
"""Plain shortcode style."""
|
66
|
-
|
67
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
68
|
-
return rxRule
|
86
|
+
return self._rxSCValue
|
69
87
|
|
70
88
|
@property
|
71
|
-
def dialogStyle(self) ->
|
89
|
+
def dialogStyle(self) -> re.Pattern | None:
|
72
90
|
"""Dialogue detection rule based on user settings."""
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
@property
|
96
|
-
def narratorBreak(self) -> QRegularExpression:
|
97
|
-
"""Dialogue narrator break rule based on user settings."""
|
98
|
-
sym = QRegularExpression.escape(CONFIG.narratorBreak)
|
99
|
-
rxRule = QRegularExpression(f"\\B{sym}\\S.*?\\S{sym}\\B")
|
100
|
-
rxRule.setPatternOptions(QRegExUnicode)
|
101
|
-
return rxRule
|
91
|
+
if CONFIG.dialogStyle > 0:
|
92
|
+
rx = []
|
93
|
+
if CONFIG.dialogStyle in (1, 3):
|
94
|
+
qO = CONFIG.fmtSQuoteOpen.strip()[:1]
|
95
|
+
qC = CONFIG.fmtSQuoteClose.strip()[:1]
|
96
|
+
if qO == qC:
|
97
|
+
rx.append(f"(?:\\B{qO}.+?{qC}\\B)")
|
98
|
+
else:
|
99
|
+
rx.append(f"(?:{qO}[^{qO}]+{qC})")
|
100
|
+
if CONFIG.allowOpenDial:
|
101
|
+
rx.append(f"(?:{qO}.+?$)")
|
102
|
+
if CONFIG.dialogStyle in (2, 3):
|
103
|
+
qO = CONFIG.fmtDQuoteOpen.strip()[:1]
|
104
|
+
qC = CONFIG.fmtDQuoteClose.strip()[:1]
|
105
|
+
if qO == qC:
|
106
|
+
rx.append(f"(?:\\B{qO}.+?{qC}\\B)")
|
107
|
+
else:
|
108
|
+
rx.append(f"(?:{qO}[^{qO}]+{qC})")
|
109
|
+
if CONFIG.allowOpenDial:
|
110
|
+
rx.append(f"(?:{qO}.+?$)")
|
111
|
+
return re.compile("|".join(rx), re.UNICODE)
|
112
|
+
return None
|
102
113
|
|
103
114
|
@property
|
104
|
-
def altDialogStyle(self) ->
|
115
|
+
def altDialogStyle(self) -> re.Pattern | None:
|
105
116
|
"""Dialogue alternative rule based on user settings."""
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
117
|
+
if CONFIG.altDialogOpen and CONFIG.altDialogClose:
|
118
|
+
qO = re.escape(compact(CONFIG.altDialogOpen))
|
119
|
+
qC = re.escape(compact(CONFIG.altDialogClose))
|
120
|
+
qB = r"\B" if (qO == qC or qC in self.AMBIGUOUS) else ""
|
121
|
+
return re.compile(f"{qO}.*?{qC}{qB}", re.UNICODE)
|
122
|
+
return None
|
111
123
|
|
112
124
|
|
113
125
|
REGEX_PATTERNS = RegExPatterns()
|
126
|
+
|
127
|
+
|
128
|
+
class DialogParser:
|
129
|
+
|
130
|
+
__slots__ = (
|
131
|
+
"_quotes", "_dialog", "_alternate", "_enabled",
|
132
|
+
"_narrator", "_breakD", "_breakQ", "_mode",
|
133
|
+
)
|
134
|
+
|
135
|
+
def __init__(self) -> None:
|
136
|
+
self._quotes = None
|
137
|
+
self._dialog = ""
|
138
|
+
self._alternate = ""
|
139
|
+
self._enabled = False
|
140
|
+
self._narrator = ""
|
141
|
+
self._breakD = None
|
142
|
+
self._breakQ = None
|
143
|
+
self._mode = ""
|
144
|
+
return
|
145
|
+
|
146
|
+
@property
|
147
|
+
def enabled(self) -> bool:
|
148
|
+
"""Return True if there are any settings to parse."""
|
149
|
+
return self._enabled
|
150
|
+
|
151
|
+
def initParser(self) -> None:
|
152
|
+
"""Init parser settings. This method must also be called when
|
153
|
+
the config changes.
|
154
|
+
"""
|
155
|
+
self._quotes = REGEX_PATTERNS.dialogStyle
|
156
|
+
self._dialog = uniqueCompact(CONFIG.dialogLine)
|
157
|
+
self._alternate = CONFIG.narratorDialog.strip()[:1]
|
158
|
+
|
159
|
+
# One of the three modes are needed for the class to have
|
160
|
+
# anything to do
|
161
|
+
self._enabled = bool(self._quotes or self._dialog or self._alternate)
|
162
|
+
|
163
|
+
# Build narrator break RegExes
|
164
|
+
if narrator := CONFIG.narratorBreak.strip()[:1]:
|
165
|
+
punct = re.escape(".,:;!?")
|
166
|
+
self._breakD = re.compile(f"{narrator}.*?(?:{narrator}[{punct}]?|$)", re.UNICODE)
|
167
|
+
self._breakQ = re.compile(f"{narrator}.*?(?:{narrator}[{punct}]?)", re.UNICODE)
|
168
|
+
self._narrator = narrator
|
169
|
+
self._mode = f" {narrator}"
|
170
|
+
|
171
|
+
return
|
172
|
+
|
173
|
+
def __call__(self, text: str) -> list[tuple[int, int]]:
|
174
|
+
"""Caller wrapper for dialogue processing."""
|
175
|
+
temp: list[int] = []
|
176
|
+
result: list[tuple[int, int]] = []
|
177
|
+
if text:
|
178
|
+
plain = True
|
179
|
+
if self._dialog and text[0] in self._dialog:
|
180
|
+
# The whole line is dialogue
|
181
|
+
plain = False
|
182
|
+
temp.append(0)
|
183
|
+
temp.append(len(text))
|
184
|
+
if self._breakD:
|
185
|
+
# Process narrator breaks in the dialogue
|
186
|
+
for res in self._breakD.finditer(text, 1):
|
187
|
+
temp.append(res.start(0))
|
188
|
+
temp.append(res.end(0))
|
189
|
+
elif self._quotes:
|
190
|
+
# Quoted dialogue is enabled, so we look for them
|
191
|
+
for res in self._quotes.finditer(text):
|
192
|
+
plain = False
|
193
|
+
temp.append(res.start(0))
|
194
|
+
temp.append(res.end(0))
|
195
|
+
if self._breakQ:
|
196
|
+
for sub in self._breakQ.finditer(text, res.start(0), res.end(0)):
|
197
|
+
temp.append(sub.start(0))
|
198
|
+
temp.append(sub.end(0))
|
199
|
+
|
200
|
+
if plain and self._alternate:
|
201
|
+
# The main rules found no dialogue, so we check for
|
202
|
+
# alternating dialogue sections, if enabled
|
203
|
+
pos = 0
|
204
|
+
for num, bit in enumerate(text.split(self._alternate)):
|
205
|
+
length = len(bit) + (1 if num > 0 else 0)
|
206
|
+
if num%2:
|
207
|
+
temp.append(pos)
|
208
|
+
temp.append(pos + length)
|
209
|
+
pos += length
|
210
|
+
|
211
|
+
if temp:
|
212
|
+
# Sort unique edges in increasing order, and add them in pairs
|
213
|
+
start = None
|
214
|
+
for pos in sorted(set(temp)):
|
215
|
+
if start is None:
|
216
|
+
start = pos
|
217
|
+
else:
|
218
|
+
result.append((start, pos))
|
219
|
+
start = None
|
220
|
+
|
221
|
+
return result
|
@@ -6,7 +6,7 @@ File History:
|
|
6
6
|
Created: 2023-11-19 [2.2rc1] GuiDictionaries
|
7
7
|
|
8
8
|
This file is a part of novelWriter
|
9
|
-
Copyright
|
9
|
+
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
10
10
|
|
11
11
|
This program is free software: you can redistribute it and/or modify
|
12
12
|
it under the terms of the GNU General Public License as published by
|
@@ -65,12 +65,12 @@ class GuiDictionaries(NNonBlockingDialog):
|
|
65
65
|
self.setMinimumHeight(CONFIG.pxInt(300))
|
66
66
|
|
67
67
|
# Hunspell Dictionaries
|
68
|
-
foUrl = "https://www.freeoffice.com/en/download/dictionaries"
|
69
68
|
loUrl = "https://extensions.libreoffice.org"
|
69
|
+
ooUrl = "https://extensions.openoffice.org"
|
70
70
|
self.huInfo = QLabel("<br>".join([
|
71
71
|
self.tr("Download a dictionary from one of the links, and add it below."),
|
72
|
-
f" \u203a <a href='{foUrl}'>{foUrl}</a>",
|
73
72
|
f" \u203a <a href='{loUrl}'>{loUrl}</a>",
|
73
|
+
f" \u203a <a href='{ooUrl}'>{ooUrl}</a>",
|
74
74
|
]), self)
|
75
75
|
self.huInfo.setOpenExternalLinks(True)
|
76
76
|
self.huInfo.setWordWrap(True)
|
novelwriter/tools/lipsum.py
CHANGED
@@ -6,7 +6,7 @@ File History:
|
|
6
6
|
Created: 2022-04-02 [2.0rc1] GuiLipsum
|
7
7
|
|
8
8
|
This file is a part of novelWriter
|
9
|
-
Copyright
|
9
|
+
Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
|
10
10
|
|
11
11
|
This program is free software: you can redistribute it and/or modify
|
12
12
|
it under the terms of the GNU General Public License as published by
|
novelwriter/tools/manusbuild.py
CHANGED
@@ -6,7 +6,7 @@ File History:
|
|
6
6
|
Created: 2023-05-24 [2.1b1] GuiManuscriptBuild
|
7
7
|
|
8
8
|
This file is a part of novelWriter
|
9
|
-
Copyright
|
9
|
+
Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
|
10
10
|
|
11
11
|
This program is free software: you can redistribute it and/or modify
|
12
12
|
it under the terms of the GNU General Public License as published by
|
@@ -179,14 +179,20 @@ class GuiManuscriptBuild(NDialog):
|
|
179
179
|
self.buildBox.setVerticalSpacing(sp4)
|
180
180
|
|
181
181
|
# Dialog Buttons
|
182
|
+
self.buttonBox = QDialogButtonBox(self)
|
183
|
+
|
182
184
|
self.btnOpen = QPushButton(SHARED.theme.getIcon("browse"), self.tr("Open Folder"), self)
|
183
185
|
self.btnOpen.setIconSize(bSz)
|
186
|
+
self.btnOpen.setAutoDefault(False)
|
187
|
+
self.buttonBox.addButton(self.btnOpen, QtRoleAction)
|
188
|
+
|
184
189
|
self.btnBuild = QPushButton(SHARED.theme.getIcon("export"), self.tr("&Build"), self)
|
185
190
|
self.btnBuild.setIconSize(bSz)
|
191
|
+
self.btnBuild.setAutoDefault(True)
|
192
|
+
self.buttonBox.addButton(self.btnBuild, QtRoleAction)
|
186
193
|
|
187
|
-
self.
|
188
|
-
self.
|
189
|
-
self.dlgButtons.addButton(self.btnBuild, QtRoleAction)
|
194
|
+
self.btnClose = self.buttonBox.addButton(QtDialogClose)
|
195
|
+
self.btnClose.setAutoDefault(False)
|
190
196
|
|
191
197
|
# Assemble GUI
|
192
198
|
# ============
|
@@ -213,7 +219,7 @@ class GuiManuscriptBuild(NDialog):
|
|
213
219
|
self.outerBox.addSpacing(sp4)
|
214
220
|
self.outerBox.addLayout(self.buildBox, 0)
|
215
221
|
self.outerBox.addSpacing(sp16)
|
216
|
-
self.outerBox.addWidget(self.
|
222
|
+
self.outerBox.addWidget(self.buttonBox, 0)
|
217
223
|
self.outerBox.setSpacing(0)
|
218
224
|
|
219
225
|
self.setLayout(self.outerBox)
|
@@ -229,7 +235,7 @@ class GuiManuscriptBuild(NDialog):
|
|
229
235
|
# Signals
|
230
236
|
self.btnReset.clicked.connect(self._doResetBuildName)
|
231
237
|
self.btnBrowse.clicked.connect(self._doSelectPath)
|
232
|
-
self.
|
238
|
+
self.buttonBox.clicked.connect(self._dialogButtonClicked)
|
233
239
|
self.listFormats.itemSelectionChanged.connect(self._resetProgress)
|
234
240
|
|
235
241
|
logger.debug("Ready: GuiManuscriptBuild")
|
@@ -260,7 +266,7 @@ class GuiManuscriptBuild(NDialog):
|
|
260
266
|
@pyqtSlot("QAbstractButton*")
|
261
267
|
def _dialogButtonClicked(self, button: QAbstractButton) -> None:
|
262
268
|
"""Handle button clicks from the dialog button box."""
|
263
|
-
role = self.
|
269
|
+
role = self.buttonBox.buttonRole(button)
|
264
270
|
if role == QtRoleAction:
|
265
271
|
if button == self.btnBuild:
|
266
272
|
self._runBuild()
|
@@ -333,7 +339,7 @@ class GuiManuscriptBuild(NDialog):
|
|
333
339
|
docBuild.queueAll()
|
334
340
|
|
335
341
|
self.buildProgress.setMaximum(len(docBuild))
|
336
|
-
for i, _ in docBuild.
|
342
|
+
for i, _ in docBuild.iterBuildDocument(buildPath, bFormat):
|
337
343
|
self.buildProgress.setValue(i+1)
|
338
344
|
|
339
345
|
self._build.setLastBuildPath(bPath)
|
@@ -388,13 +394,9 @@ class GuiManuscriptBuild(NDialog):
|
|
388
394
|
if isinstance(rItem, NWItem):
|
389
395
|
rootMap[rHandle] = rItem.itemName
|
390
396
|
|
391
|
-
itemIcon = SHARED.theme.getItemIcon(
|
392
|
-
nwItem.itemType, nwItem.itemClass,
|
393
|
-
nwItem.itemLayout, nwItem.mainHeading
|
394
|
-
)
|
395
397
|
rootName = rootMap.get(rHandle, "??????")
|
396
398
|
item = QListWidgetItem(f"{rootName}: {nwItem.itemName}")
|
397
|
-
item.setIcon(
|
399
|
+
item.setIcon(nwItem.getMainIcon())
|
398
400
|
self.listContent.addItem(item)
|
399
401
|
|
400
402
|
return
|