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.
Files changed (129) hide show
  1. {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/METADATA +5 -4
  2. {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/RECORD +126 -105
  3. {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/WHEEL +1 -1
  4. novelwriter/__init__.py +50 -11
  5. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  6. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  7. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  8. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  9. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  10. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  11. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  12. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  13. novelwriter/assets/i18n/nw_pl_PL.qm +0 -0
  14. novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
  15. novelwriter/assets/i18n/nw_ru_RU.qm +0 -0
  16. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  17. novelwriter/assets/i18n/project_de_DE.json +4 -2
  18. novelwriter/assets/i18n/project_en_GB.json +1 -0
  19. novelwriter/assets/i18n/project_en_US.json +2 -0
  20. novelwriter/assets/i18n/project_it_IT.json +2 -0
  21. novelwriter/assets/i18n/project_ja_JP.json +2 -0
  22. novelwriter/assets/i18n/project_nb_NO.json +2 -0
  23. novelwriter/assets/i18n/project_nl_NL.json +2 -0
  24. novelwriter/assets/i18n/project_pl_PL.json +2 -0
  25. novelwriter/assets/i18n/project_pt_BR.json +2 -0
  26. novelwriter/assets/i18n/project_ru_RU.json +11 -0
  27. novelwriter/assets/i18n/project_zh_CN.json +2 -0
  28. novelwriter/assets/icons/typicons_dark/icons.conf +8 -0
  29. novelwriter/assets/icons/typicons_dark/mixed_copy.svg +4 -0
  30. novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +6 -0
  31. novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +6 -0
  32. novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +6 -0
  33. novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +6 -0
  34. novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +6 -0
  35. novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +6 -0
  36. novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +5 -0
  37. novelwriter/assets/icons/typicons_light/icons.conf +8 -0
  38. novelwriter/assets/icons/typicons_light/mixed_copy.svg +4 -0
  39. novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +6 -0
  40. novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +6 -0
  41. novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +6 -0
  42. novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +6 -0
  43. novelwriter/assets/icons/typicons_light/mixed_size-height.svg +6 -0
  44. novelwriter/assets/icons/typicons_light/mixed_size-width.svg +6 -0
  45. novelwriter/assets/icons/typicons_light/nw_toolbar.svg +5 -0
  46. novelwriter/assets/manual.pdf +0 -0
  47. novelwriter/assets/sample.zip +0 -0
  48. novelwriter/assets/text/credits_en.htm +1 -0
  49. novelwriter/assets/themes/default_light.conf +2 -2
  50. novelwriter/common.py +101 -3
  51. novelwriter/config.py +30 -17
  52. novelwriter/constants.py +189 -81
  53. novelwriter/core/buildsettings.py +74 -40
  54. novelwriter/core/coretools.py +146 -148
  55. novelwriter/core/docbuild.py +133 -171
  56. novelwriter/core/document.py +1 -1
  57. novelwriter/core/index.py +39 -38
  58. novelwriter/core/item.py +42 -9
  59. novelwriter/core/itemmodel.py +518 -0
  60. novelwriter/core/options.py +5 -2
  61. novelwriter/core/project.py +68 -90
  62. novelwriter/core/projectdata.py +8 -2
  63. novelwriter/core/projectxml.py +1 -1
  64. novelwriter/core/sessions.py +1 -1
  65. novelwriter/core/spellcheck.py +10 -15
  66. novelwriter/core/status.py +24 -8
  67. novelwriter/core/storage.py +1 -1
  68. novelwriter/core/tree.py +269 -288
  69. novelwriter/dialogs/about.py +1 -1
  70. novelwriter/dialogs/docmerge.py +8 -18
  71. novelwriter/dialogs/docsplit.py +1 -1
  72. novelwriter/dialogs/editlabel.py +1 -1
  73. novelwriter/dialogs/preferences.py +47 -34
  74. novelwriter/dialogs/projectsettings.py +149 -99
  75. novelwriter/dialogs/quotes.py +1 -1
  76. novelwriter/dialogs/wordlist.py +11 -10
  77. novelwriter/enum.py +37 -24
  78. novelwriter/error.py +2 -2
  79. novelwriter/extensions/configlayout.py +28 -13
  80. novelwriter/extensions/eventfilters.py +1 -1
  81. novelwriter/extensions/modified.py +30 -6
  82. novelwriter/extensions/novelselector.py +4 -3
  83. novelwriter/extensions/pagedsidebar.py +9 -9
  84. novelwriter/extensions/progressbars.py +4 -4
  85. novelwriter/extensions/statusled.py +3 -3
  86. novelwriter/extensions/switch.py +3 -3
  87. novelwriter/extensions/switchbox.py +1 -1
  88. novelwriter/extensions/versioninfo.py +1 -1
  89. novelwriter/formats/shared.py +156 -0
  90. novelwriter/formats/todocx.py +1191 -0
  91. novelwriter/formats/tohtml.py +454 -0
  92. novelwriter/{core → formats}/tokenizer.py +497 -495
  93. novelwriter/formats/tomarkdown.py +218 -0
  94. novelwriter/{core → formats}/toodt.py +312 -433
  95. novelwriter/formats/toqdoc.py +486 -0
  96. novelwriter/formats/toraw.py +91 -0
  97. novelwriter/gui/doceditor.py +347 -287
  98. novelwriter/gui/dochighlight.py +97 -85
  99. novelwriter/gui/docviewer.py +90 -33
  100. novelwriter/gui/docviewerpanel.py +18 -26
  101. novelwriter/gui/editordocument.py +18 -3
  102. novelwriter/gui/itemdetails.py +27 -29
  103. novelwriter/gui/mainmenu.py +130 -64
  104. novelwriter/gui/noveltree.py +46 -48
  105. novelwriter/gui/outline.py +202 -256
  106. novelwriter/gui/projtree.py +590 -1238
  107. novelwriter/gui/search.py +11 -19
  108. novelwriter/gui/sidebar.py +8 -7
  109. novelwriter/gui/statusbar.py +20 -3
  110. novelwriter/gui/theme.py +11 -6
  111. novelwriter/guimain.py +101 -201
  112. novelwriter/shared.py +67 -28
  113. novelwriter/text/counting.py +3 -1
  114. novelwriter/text/patterns.py +169 -61
  115. novelwriter/tools/dictionaries.py +3 -3
  116. novelwriter/tools/lipsum.py +1 -1
  117. novelwriter/tools/manusbuild.py +15 -13
  118. novelwriter/tools/manuscript.py +121 -79
  119. novelwriter/tools/manussettings.py +424 -291
  120. novelwriter/tools/noveldetails.py +1 -1
  121. novelwriter/tools/welcome.py +6 -6
  122. novelwriter/tools/writingstats.py +4 -4
  123. novelwriter/types.py +25 -9
  124. novelwriter/core/tohtml.py +0 -530
  125. novelwriter/core/tomarkdown.py +0 -252
  126. novelwriter/core/toqdoc.py +0 -419
  127. {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/LICENSE.md +0 -0
  128. {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/entry_points.txt +0 -0
  129. {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/top_level.txt +0 -0
@@ -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 2018–2024, Veronica Berglyd Olsen
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)
@@ -3,10 +3,11 @@ novelWriter – Text Pattern Functions
3
3
  ====================================
4
4
 
5
5
  File History:
6
- Created: 2024-06-01 [2.5ec1]
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 2018–2024, Veronica Berglyd Olsen
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
- from PyQt5.QtCore import QRegularExpression
27
+ import re
27
28
 
28
29
  from novelwriter import CONFIG
29
- from novelwriter.constants import nwRegEx
30
- from novelwriter.types import QRegExUnicode
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 markdownItalic(self) -> QRegularExpression:
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
- rxRule = QRegularExpression(nwRegEx.FMT_EI)
39
- rxRule.setPatternOptions(QRegExUnicode)
40
- return rxRule
66
+ return self._rxItalic
41
67
 
42
68
  @property
43
- def markdownBold(self) -> QRegularExpression:
69
+ def markdownBold(self) -> re.Pattern:
44
70
  """Markdown bold style."""
45
- rxRule = QRegularExpression(nwRegEx.FMT_EB)
46
- rxRule.setPatternOptions(QRegExUnicode)
47
- return rxRule
71
+ return self._rxBold
48
72
 
49
73
  @property
50
- def markdownStrike(self) -> QRegularExpression:
74
+ def markdownStrike(self) -> re.Pattern:
51
75
  """Markdown strikethrough style."""
52
- rxRule = QRegularExpression(nwRegEx.FMT_ST)
53
- rxRule.setPatternOptions(QRegExUnicode)
54
- return rxRule
76
+ return self._rxStrike
55
77
 
56
78
  @property
57
- def shortcodePlain(self) -> QRegularExpression:
79
+ def shortcodePlain(self) -> re.Pattern:
58
80
  """Plain shortcode style."""
59
- rxRule = QRegularExpression(nwRegEx.FMT_SC)
60
- rxRule.setPatternOptions(QRegExUnicode)
61
- return rxRule
81
+ return self._rxSCPlain
62
82
 
63
83
  @property
64
- def shortcodeValue(self) -> QRegularExpression:
84
+ def shortcodeValue(self) -> re.Pattern:
65
85
  """Plain shortcode style."""
66
- rxRule = QRegularExpression(nwRegEx.FMT_SV)
67
- rxRule.setPatternOptions(QRegExUnicode)
68
- return rxRule
86
+ return self._rxSCValue
69
87
 
70
88
  @property
71
- def dialogStyle(self) -> QRegularExpression:
89
+ def dialogStyle(self) -> re.Pattern | None:
72
90
  """Dialogue detection rule based on user settings."""
73
- symO = ""
74
- symC = ""
75
- if CONFIG.dialogStyle in (1, 3):
76
- symO += CONFIG.fmtSQuoteOpen
77
- symC += CONFIG.fmtSQuoteClose
78
- if CONFIG.dialogStyle in (2, 3):
79
- symO += CONFIG.fmtDQuoteOpen
80
- symC += CONFIG.fmtDQuoteClose
81
-
82
- rxEnd = "|$" if CONFIG.allowOpenDial else ""
83
- rxRule = QRegularExpression(f"\\B[{symO}].*?(?:[{symC}]\\B{rxEnd})")
84
- rxRule.setPatternOptions(QRegExUnicode)
85
- return rxRule
86
-
87
- @property
88
- def dialogLine(self) -> QRegularExpression:
89
- """Dialogue line rule based on user settings."""
90
- sym = QRegularExpression.escape(CONFIG.dialogLine)
91
- rxRule = QRegularExpression(f"^{sym}.*?$")
92
- rxRule.setPatternOptions(QRegExUnicode)
93
- return rxRule
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) -> QRegularExpression:
115
+ def altDialogStyle(self) -> re.Pattern | None:
105
116
  """Dialogue alternative rule based on user settings."""
106
- symO = QRegularExpression.escape(CONFIG.altDialogOpen)
107
- symC = QRegularExpression.escape(CONFIG.altDialogClose)
108
- rxRule = QRegularExpression(f"\\B{symO}.*?{symC}\\B")
109
- rxRule.setPatternOptions(QRegExUnicode)
110
- return rxRule
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 2018–2024, Veronica Berglyd Olsen
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"&nbsp;\u203a <a href='{foUrl}'>{foUrl}</a>",
73
72
  f"&nbsp;\u203a <a href='{loUrl}'>{loUrl}</a>",
73
+ f"&nbsp;\u203a <a href='{ooUrl}'>{ooUrl}</a>",
74
74
  ]), self)
75
75
  self.huInfo.setOpenExternalLinks(True)
76
76
  self.huInfo.setWordWrap(True)
@@ -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 2018–2024, Veronica Berglyd Olsen
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
@@ -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 2018–2024, Veronica Berglyd Olsen
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.dlgButtons = QDialogButtonBox(QtDialogClose, self)
188
- self.dlgButtons.addButton(self.btnOpen, QtRoleAction)
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.dlgButtons, 0)
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.dlgButtons.clicked.connect(self._dialogButtonClicked)
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.dlgButtons.buttonRole(button)
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.iterBuild(buildPath, bFormat):
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(itemIcon)
399
+ item.setIcon(nwItem.getMainIcon())
398
400
  self.listContent.addItem(item)
399
401
 
400
402
  return