novelWriter 2.4.3__py3-none-any.whl → 2.5__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 (123) hide show
  1. {novelWriter-2.4.3.dist-info → novelWriter-2.5.dist-info}/METADATA +4 -5
  2. {novelWriter-2.4.3.dist-info → novelWriter-2.5.dist-info}/RECORD +122 -112
  3. {novelWriter-2.4.3.dist-info → novelWriter-2.5.dist-info}/WHEEL +1 -1
  4. novelwriter/__init__.py +33 -39
  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_zh_CN.qm +0 -0
  16. novelwriter/assets/i18n/project_en_GB.json +1 -0
  17. novelwriter/assets/i18n/project_pl_PL.json +116 -0
  18. novelwriter/assets/i18n/project_pt_BR.json +74 -74
  19. novelwriter/assets/icons/typicons_dark/icons.conf +2 -0
  20. novelwriter/assets/icons/typicons_dark/nw_font.svg +4 -0
  21. novelwriter/assets/icons/typicons_dark/nw_quote.svg +4 -0
  22. novelwriter/assets/icons/typicons_light/icons.conf +2 -0
  23. novelwriter/assets/icons/typicons_light/nw_font.svg +4 -0
  24. novelwriter/assets/icons/typicons_light/nw_quote.svg +4 -0
  25. novelwriter/assets/manual.pdf +0 -0
  26. novelwriter/assets/sample.zip +0 -0
  27. novelwriter/assets/syntax/cyberpunk_night.conf +5 -3
  28. novelwriter/assets/syntax/default_dark.conf +32 -18
  29. novelwriter/assets/syntax/default_light.conf +24 -10
  30. novelwriter/assets/syntax/dracula.conf +44 -0
  31. novelwriter/assets/syntax/grey_dark.conf +5 -4
  32. novelwriter/assets/syntax/grey_light.conf +5 -4
  33. novelwriter/assets/syntax/light_owl.conf +7 -6
  34. novelwriter/assets/syntax/night_owl.conf +7 -6
  35. novelwriter/assets/syntax/snazzy.conf +42 -0
  36. novelwriter/assets/syntax/solarized_dark.conf +4 -3
  37. novelwriter/assets/syntax/solarized_light.conf +4 -3
  38. novelwriter/assets/syntax/tango.conf +27 -11
  39. novelwriter/assets/syntax/tomorrow.conf +6 -5
  40. novelwriter/assets/syntax/tomorrow_night.conf +7 -6
  41. novelwriter/assets/syntax/tomorrow_night_blue.conf +6 -5
  42. novelwriter/assets/syntax/tomorrow_night_bright.conf +6 -5
  43. novelwriter/assets/syntax/tomorrow_night_eighties.conf +6 -5
  44. novelwriter/assets/text/credits_en.htm +52 -41
  45. novelwriter/assets/themes/cyberpunk_night.conf +3 -0
  46. novelwriter/assets/themes/default_dark.conf +2 -0
  47. novelwriter/assets/themes/default_light.conf +2 -0
  48. novelwriter/assets/themes/dracula.conf +48 -0
  49. novelwriter/assets/themes/solarized_dark.conf +2 -0
  50. novelwriter/assets/themes/solarized_light.conf +2 -0
  51. novelwriter/common.py +33 -12
  52. novelwriter/config.py +184 -98
  53. novelwriter/constants.py +47 -35
  54. novelwriter/core/buildsettings.py +68 -69
  55. novelwriter/core/coretools.py +5 -23
  56. novelwriter/core/docbuild.py +52 -40
  57. novelwriter/core/document.py +3 -5
  58. novelwriter/core/index.py +115 -45
  59. novelwriter/core/item.py +8 -19
  60. novelwriter/core/options.py +2 -4
  61. novelwriter/core/project.py +37 -61
  62. novelwriter/core/projectdata.py +1 -3
  63. novelwriter/core/projectxml.py +12 -15
  64. novelwriter/core/sessions.py +3 -5
  65. novelwriter/core/spellcheck.py +4 -9
  66. novelwriter/core/status.py +211 -164
  67. novelwriter/core/storage.py +0 -8
  68. novelwriter/core/tohtml.py +139 -105
  69. novelwriter/core/tokenizer.py +278 -122
  70. novelwriter/core/{tomd.py → tomarkdown.py} +97 -78
  71. novelwriter/core/toodt.py +257 -166
  72. novelwriter/core/toqdoc.py +419 -0
  73. novelwriter/core/tree.py +5 -7
  74. novelwriter/dialogs/about.py +11 -18
  75. novelwriter/dialogs/docmerge.py +17 -19
  76. novelwriter/dialogs/docsplit.py +17 -19
  77. novelwriter/dialogs/editlabel.py +6 -10
  78. novelwriter/dialogs/preferences.py +200 -164
  79. novelwriter/dialogs/projectsettings.py +225 -189
  80. novelwriter/dialogs/quotes.py +12 -9
  81. novelwriter/dialogs/wordlist.py +9 -15
  82. novelwriter/enum.py +35 -30
  83. novelwriter/error.py +8 -15
  84. novelwriter/extensions/configlayout.py +55 -21
  85. novelwriter/extensions/eventfilters.py +1 -5
  86. novelwriter/extensions/modified.py +70 -14
  87. novelwriter/extensions/novelselector.py +1 -3
  88. novelwriter/extensions/pagedsidebar.py +9 -12
  89. novelwriter/extensions/{circularprogress.py → progressbars.py} +30 -8
  90. novelwriter/extensions/statusled.py +40 -26
  91. novelwriter/extensions/switch.py +4 -6
  92. novelwriter/extensions/switchbox.py +7 -6
  93. novelwriter/extensions/versioninfo.py +3 -9
  94. novelwriter/gui/doceditor.py +120 -139
  95. novelwriter/gui/dochighlight.py +231 -186
  96. novelwriter/gui/docviewer.py +69 -108
  97. novelwriter/gui/docviewerpanel.py +3 -10
  98. novelwriter/gui/editordocument.py +1 -3
  99. novelwriter/gui/itemdetails.py +7 -11
  100. novelwriter/gui/mainmenu.py +22 -18
  101. novelwriter/gui/noveltree.py +11 -24
  102. novelwriter/gui/outline.py +15 -26
  103. novelwriter/gui/projtree.py +39 -65
  104. novelwriter/gui/search.py +10 -3
  105. novelwriter/gui/sidebar.py +2 -6
  106. novelwriter/gui/statusbar.py +29 -37
  107. novelwriter/gui/theme.py +26 -48
  108. novelwriter/guimain.py +162 -160
  109. novelwriter/shared.py +36 -19
  110. novelwriter/text/patterns.py +113 -0
  111. novelwriter/tools/dictionaries.py +10 -20
  112. novelwriter/tools/lipsum.py +10 -16
  113. novelwriter/tools/manusbuild.py +9 -11
  114. novelwriter/tools/manuscript.py +75 -149
  115. novelwriter/tools/manussettings.py +74 -76
  116. novelwriter/tools/noveldetails.py +16 -21
  117. novelwriter/tools/welcome.py +21 -26
  118. novelwriter/tools/writingstats.py +9 -12
  119. novelwriter/types.py +49 -4
  120. novelwriter/extensions/simpleprogress.py +0 -55
  121. {novelWriter-2.4.3.dist-info → novelWriter-2.5.dist-info}/LICENSE.md +0 -0
  122. {novelWriter-2.4.3.dist-info → novelWriter-2.5.dist-info}/entry_points.txt +0 -0
  123. {novelWriter-2.4.3.dist-info → novelWriter-2.5.dist-info}/top_level.txt +0 -0
@@ -25,21 +25,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
25
25
  from __future__ import annotations
26
26
 
27
27
  import json
28
- import uuid
29
28
  import logging
29
+ import uuid
30
30
 
31
+ from collections.abc import Iterable
31
32
  from enum import Enum
32
33
  from pathlib import Path
33
- from collections.abc import Iterable
34
34
 
35
35
  from PyQt5.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
36
36
 
37
37
  from novelwriter import CONFIG
38
- from novelwriter.enum import nwBuildFmt
39
- from novelwriter.error import logException
40
38
  from novelwriter.common import checkUuid, isHandle, jsonEncode
41
39
  from novelwriter.constants import nwFiles, nwHeadFmt
42
40
  from novelwriter.core.project import NWProject
41
+ from novelwriter.enum import nwBuildFmt
42
+ from novelwriter.error import logException
43
43
 
44
44
  logger = logging.getLogger(__name__)
45
45
 
@@ -76,12 +76,16 @@ SETTINGS_TEMPLATE = {
76
76
  "text.includeBodyText": (bool, True),
77
77
  "text.ignoredKeywords": (str, ""),
78
78
  "text.addNoteHeadings": (bool, True),
79
- "format.textFont": (str, CONFIG.textFont),
80
- "format.textSize": (int, 12),
79
+ "format.textFont": (str, CONFIG.textFont.toString()),
81
80
  "format.lineHeight": (float, 1.15, 0.75, 3.0),
82
81
  "format.justifyText": (bool, False),
83
82
  "format.stripUnicode": (bool, False),
84
83
  "format.replaceTabs": (bool, False),
84
+ "format.keepBreaks": (bool, True),
85
+ "format.showDialogue": (bool, False),
86
+ "format.firstLineIndent": (bool, False),
87
+ "format.firstIndentWidth": (float, 1.4),
88
+ "format.indentFirstPar": (bool, False),
85
89
  "format.pageUnit": (str, "cm"),
86
90
  "format.pageSize": (str, "A4"),
87
91
  "format.pageWidth": (float, 21.0),
@@ -93,65 +97,66 @@ SETTINGS_TEMPLATE = {
93
97
  "odt.addColours": (bool, True),
94
98
  "odt.pageHeader": (str, nwHeadFmt.ODT_AUTO),
95
99
  "odt.pageCountOffset": (int, 0),
96
- "odt.firstLineIndent": (bool, False),
97
- "md.preserveBreaks": (bool, True),
98
100
  "html.addStyles": (bool, True),
99
101
  "html.preserveTabs": (bool, False),
100
102
  }
101
103
 
102
104
  SETTINGS_LABELS = {
103
- "filter": QT_TRANSLATE_NOOP("Builds", "Document Filters"),
104
- "filter.includeNovel": QT_TRANSLATE_NOOP("Builds", "Novel Documents"),
105
- "filter.includeNotes": QT_TRANSLATE_NOOP("Builds", "Project Notes"),
106
- "filter.includeInactive": QT_TRANSLATE_NOOP("Builds", "Inactive Documents"),
107
-
108
- "headings": QT_TRANSLATE_NOOP("Builds", "Headings"),
109
- "headings.fmtTitle": QT_TRANSLATE_NOOP("Builds", "Partition Format"),
110
- "headings.fmtChapter": QT_TRANSLATE_NOOP("Builds", "Chapter Format"),
111
- "headings.fmtUnnumbered": QT_TRANSLATE_NOOP("Builds", "Unnumbered Format"),
112
- "headings.fmtScene": QT_TRANSLATE_NOOP("Builds", "Scene Format"),
113
- "headings.fmtAltScene": QT_TRANSLATE_NOOP("Builds", "Alt. Scene Format"),
114
- "headings.fmtSection": QT_TRANSLATE_NOOP("Builds", "Section Format"),
115
-
116
- "text.grpContent": QT_TRANSLATE_NOOP("Builds", "Text Content"),
117
- "text.includeSynopsis": QT_TRANSLATE_NOOP("Builds", "Include Synopsis"),
118
- "text.includeComments": QT_TRANSLATE_NOOP("Builds", "Include Comments"),
119
- "text.includeKeywords": QT_TRANSLATE_NOOP("Builds", "Include Keywords"),
120
- "text.includeBodyText": QT_TRANSLATE_NOOP("Builds", "Include Body Text"),
121
- "text.ignoredKeywords": QT_TRANSLATE_NOOP("Builds", "Ignore These Keywords"),
122
- "text.grpInsert": QT_TRANSLATE_NOOP("Builds", "Insert Content"),
123
- "text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"),
124
-
125
- "format.grpFormat": QT_TRANSLATE_NOOP("Builds", "Text Format"),
126
- "format.textFont": QT_TRANSLATE_NOOP("Builds", "Font Family"),
127
- "format.textSize": QT_TRANSLATE_NOOP("Builds", "Font Size"),
128
- "format.lineHeight": QT_TRANSLATE_NOOP("Builds", "Line Height"),
129
- "format.grpOptions": QT_TRANSLATE_NOOP("Builds", "Text Options"),
130
- "format.justifyText": QT_TRANSLATE_NOOP("Builds", "Justify Text Margins"),
131
- "format.stripUnicode": QT_TRANSLATE_NOOP("Builds", "Replace Unicode Characters"),
132
- "format.replaceTabs": QT_TRANSLATE_NOOP("Builds", "Replace Tabs with Spaces"),
133
- "format.grpPage": QT_TRANSLATE_NOOP("Builds", "Page Layout"),
134
- "format.pageUnit": QT_TRANSLATE_NOOP("Builds", "Unit"),
135
- "format.pageSize": QT_TRANSLATE_NOOP("Builds", "Page Size"),
136
- "format.pageWidth": QT_TRANSLATE_NOOP("Builds", "Page Width"),
137
- "format.pageHeight": QT_TRANSLATE_NOOP("Builds", "Page Height"),
138
- "format.topMargin": QT_TRANSLATE_NOOP("Builds", "Top Margin"),
139
- "format.bottomMargin": QT_TRANSLATE_NOOP("Builds", "Bottom Margin"),
140
- "format.leftMargin": QT_TRANSLATE_NOOP("Builds", "Left Margin"),
141
- "format.rightMargin": QT_TRANSLATE_NOOP("Builds", "Right Margin"),
142
-
143
- "odt": QT_TRANSLATE_NOOP("Builds", "Open Document (.odt)"),
144
- "odt.addColours": QT_TRANSLATE_NOOP("Builds", "Add Highlight Colours"),
145
- "odt.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"),
146
- "odt.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"),
147
- "odt.firstLineIndent": QT_TRANSLATE_NOOP("Builds", "First Line Indent"),
148
-
149
- "md": QT_TRANSLATE_NOOP("Builds", "Markdown (.md)"),
150
- "md.preserveBreaks": QT_TRANSLATE_NOOP("Builds", "Preserve Hard Line Breaks"),
151
-
152
- "html": QT_TRANSLATE_NOOP("Builds", "HTML (.html)"),
153
- "html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"),
154
- "html.preserveTabs": QT_TRANSLATE_NOOP("Builds", "Preserve Tab Characters"),
105
+ "filter": QT_TRANSLATE_NOOP("Builds", "Document Filters"),
106
+ "filter.includeNovel": QT_TRANSLATE_NOOP("Builds", "Novel Documents"),
107
+ "filter.includeNotes": QT_TRANSLATE_NOOP("Builds", "Project Notes"),
108
+ "filter.includeInactive": QT_TRANSLATE_NOOP("Builds", "Inactive Documents"),
109
+
110
+ "headings": QT_TRANSLATE_NOOP("Builds", "Headings"),
111
+ "headings.fmtTitle": QT_TRANSLATE_NOOP("Builds", "Partition Format"),
112
+ "headings.fmtChapter": QT_TRANSLATE_NOOP("Builds", "Chapter Format"),
113
+ "headings.fmtUnnumbered": QT_TRANSLATE_NOOP("Builds", "Unnumbered Format"),
114
+ "headings.fmtScene": QT_TRANSLATE_NOOP("Builds", "Scene Format"),
115
+ "headings.fmtAltScene": QT_TRANSLATE_NOOP("Builds", "Alt. Scene Format"),
116
+ "headings.fmtSection": QT_TRANSLATE_NOOP("Builds", "Section Format"),
117
+
118
+ "text.grpContent": QT_TRANSLATE_NOOP("Builds", "Text Content"),
119
+ "text.includeSynopsis": QT_TRANSLATE_NOOP("Builds", "Include Synopsis"),
120
+ "text.includeComments": QT_TRANSLATE_NOOP("Builds", "Include Comments"),
121
+ "text.includeKeywords": QT_TRANSLATE_NOOP("Builds", "Include Keywords"),
122
+ "text.includeBodyText": QT_TRANSLATE_NOOP("Builds", "Include Body Text"),
123
+ "text.ignoredKeywords": QT_TRANSLATE_NOOP("Builds", "Ignore These Keywords"),
124
+ "text.grpInsert": QT_TRANSLATE_NOOP("Builds", "Insert Content"),
125
+ "text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"),
126
+
127
+ "format.grpFormat": QT_TRANSLATE_NOOP("Builds", "Text Format"),
128
+ "format.textFont": QT_TRANSLATE_NOOP("Builds", "Text Font"),
129
+ "format.lineHeight": QT_TRANSLATE_NOOP("Builds", "Line Height"),
130
+ "format.grpOptions": QT_TRANSLATE_NOOP("Builds", "Text Options"),
131
+ "format.justifyText": QT_TRANSLATE_NOOP("Builds", "Justify Text Margins"),
132
+ "format.stripUnicode": QT_TRANSLATE_NOOP("Builds", "Replace Unicode Characters"),
133
+ "format.replaceTabs": QT_TRANSLATE_NOOP("Builds", "Replace Tabs with Spaces"),
134
+ "format.keepBreaks": QT_TRANSLATE_NOOP("Builds", "Preserve Hard Line Breaks"),
135
+ "format.showDialogue": QT_TRANSLATE_NOOP("Builds", "Apply Dialogue Highlighting"),
136
+
137
+ "format.grpParIndent": QT_TRANSLATE_NOOP("Builds", "First Line Indent"),
138
+ "format.firstLineIndent": QT_TRANSLATE_NOOP("Builds", "Enable Indent"),
139
+ "format.firstIndentWidth": QT_TRANSLATE_NOOP("Builds", "Indent Width"),
140
+ "format.indentFirstPar": QT_TRANSLATE_NOOP("Builds", "Indent First Paragraph"),
141
+
142
+ "format.grpPage": QT_TRANSLATE_NOOP("Builds", "Page Layout"),
143
+ "format.pageUnit": QT_TRANSLATE_NOOP("Builds", "Unit"),
144
+ "format.pageSize": QT_TRANSLATE_NOOP("Builds", "Page Size"),
145
+ "format.pageWidth": QT_TRANSLATE_NOOP("Builds", "Page Width"),
146
+ "format.pageHeight": QT_TRANSLATE_NOOP("Builds", "Page Height"),
147
+ "format.topMargin": QT_TRANSLATE_NOOP("Builds", "Top Margin"),
148
+ "format.bottomMargin": QT_TRANSLATE_NOOP("Builds", "Bottom Margin"),
149
+ "format.leftMargin": QT_TRANSLATE_NOOP("Builds", "Left Margin"),
150
+ "format.rightMargin": QT_TRANSLATE_NOOP("Builds", "Right Margin"),
151
+
152
+ "odt": QT_TRANSLATE_NOOP("Builds", "Open Document (.odt)"),
153
+ "odt.addColours": QT_TRANSLATE_NOOP("Builds", "Add Highlight Colours"),
154
+ "odt.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"),
155
+ "odt.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"),
156
+
157
+ "html": QT_TRANSLATE_NOOP("Builds", "HTML (.html)"),
158
+ "html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"),
159
+ "html.preserveTabs": QT_TRANSLATE_NOOP("Builds", "Preserve Tab Characters"),
155
160
  }
156
161
 
157
162
 
@@ -165,8 +170,6 @@ class FilterMode(Enum):
165
170
  SKIPPED = 4
166
171
  ROOT = 5
167
172
 
168
- # END Enum FilterMode
169
-
170
173
 
171
174
  class BuildSettings:
172
175
  """Core: Build Settings Class
@@ -216,7 +219,7 @@ class BuildSettings:
216
219
  return self._order
217
220
 
218
221
  @property
219
- def lastPath(self) -> Path:
222
+ def lastBuildPath(self) -> Path:
220
223
  """The last used build path."""
221
224
  if self._path.is_dir():
222
225
  return self._path
@@ -290,7 +293,7 @@ class BuildSettings:
290
293
  self._order = value
291
294
  return
292
295
 
293
- def setLastPath(self, path: Path | str | None) -> None:
296
+ def setLastBuildPath(self, path: Path | str | None) -> None:
294
297
  """Set the last used build path."""
295
298
  if isinstance(path, str):
296
299
  path = Path(path)
@@ -458,7 +461,7 @@ class BuildSettings:
458
461
  self.setName(data.get("name", ""))
459
462
  self.setBuildID(data.get("uuid", ""))
460
463
  self.setOrder(data.get("order", 0))
461
- self.setLastPath(data.get("path", None))
464
+ self.setLastBuildPath(data.get("path", None))
462
465
  self.setLastBuildName(data.get("build", ""))
463
466
 
464
467
  buildFmt = str(data.get("format", ""))
@@ -481,8 +484,6 @@ class BuildSettings:
481
484
 
482
485
  return
483
486
 
484
- # END Class BuildSettings
485
-
486
487
 
487
488
  class BuildCollection:
488
489
  """Core: Build Collection Class
@@ -630,5 +631,3 @@ class BuildCollection:
630
631
  return False
631
632
 
632
633
  return True
633
-
634
- # END Class BuildCollection
@@ -104,7 +104,7 @@ class DocMerger:
104
104
  docText = self._project.storage.getDocumentText(srcHandle).rstrip("\n")
105
105
  if addComment:
106
106
  docInfo = srcItem.describeMe()
107
- docSt, _ = srcItem.getImportStatus(incIcon=False)
107
+ docSt, _ = srcItem.getImportStatus()
108
108
  cmtLine = f"% {cmtPrefix} {docInfo}: {srcItem.itemName} [{docSt}]\n\n"
109
109
  docText = cmtLine + docText
110
110
 
@@ -129,8 +129,6 @@ class DocMerger:
129
129
 
130
130
  return status
131
131
 
132
- # END Class DocMerger
133
-
134
132
 
135
133
  class DocSplitter:
136
134
  """Document tool for splitting a document into a set of new
@@ -257,8 +255,6 @@ class DocSplitter:
257
255
 
258
256
  return
259
257
 
260
- # END Class DocSplitter
261
-
262
258
 
263
259
  class DocDuplicator:
264
260
  """A class that will duplicate all documents and folders starting
@@ -297,8 +293,6 @@ class DocDuplicator:
297
293
  nHandle = None
298
294
  return
299
295
 
300
- # END Class DocDuplicator
301
-
302
296
 
303
297
  class DocSearch:
304
298
 
@@ -354,7 +348,9 @@ class DocSearch:
354
348
  rxMatch = rxItt.next()
355
349
  pos = rxMatch.capturedStart()
356
350
  num = rxMatch.capturedLength()
357
- context = text[pos:pos+100].partition("\n")[0]
351
+ lim = text[:pos].rfind("\n") + 1
352
+ cut = text[lim:pos].rfind(" ") + lim + 1
353
+ context = text[cut:cut+100].partition("\n")[0]
358
354
  if context:
359
355
  results.append((pos, num, context))
360
356
  count += 1
@@ -370,23 +366,11 @@ class DocSearch:
370
366
  def _buildPattern(self, search: str) -> str:
371
367
  """Build the search pattern string."""
372
368
  if self._escape:
373
- if CONFIG.verQtValue >= 0x050f00:
374
- search = QRegularExpression.escape(search)
375
- else:
376
- # For older Qt versions, we escape manually
377
- escaped = ""
378
- for c in search:
379
- if c.isalnum() or c == "_":
380
- escaped += c
381
- else:
382
- escaped += f"\\{c}"
383
- search = escaped
369
+ search = QRegularExpression.escape(search)
384
370
  if self._words:
385
371
  search = f"(?:^|\\b){search}(?:$|\\b)"
386
372
  return search
387
373
 
388
- # END Class DocSearch
389
-
390
374
 
391
375
  class ProjectBuilder:
392
376
  """A class to build a new project from a set of user-defined
@@ -619,5 +603,3 @@ class ProjectBuilder:
619
603
  return False
620
604
 
621
605
  return True
622
-
623
- # END Class ProjectBuilder
@@ -25,22 +25,23 @@ from __future__ import annotations
25
25
 
26
26
  import logging
27
27
 
28
- from pathlib import Path
29
28
  from collections.abc import Iterable
29
+ from pathlib import Path
30
30
 
31
- from PyQt5.QtGui import QFont, QFontInfo
31
+ from PyQt5.QtGui import QFont
32
32
 
33
33
  from novelwriter import CONFIG
34
- from novelwriter.enum import nwBuildFmt
35
- from novelwriter.error import formatException, logException
36
34
  from novelwriter.constants import nwLabels
35
+ from novelwriter.core.buildsettings import BuildSettings
37
36
  from novelwriter.core.item import NWItem
38
- from novelwriter.core.tomd import ToMarkdown
39
- from novelwriter.core.toodt import ToOdt
40
- from novelwriter.core.tohtml import ToHtml
41
37
  from novelwriter.core.project import NWProject
38
+ from novelwriter.core.tohtml import ToHtml
42
39
  from novelwriter.core.tokenizer import Tokenizer
43
- from novelwriter.core.buildsettings import BuildSettings
40
+ from novelwriter.core.tomarkdown import ToMarkdown
41
+ from novelwriter.core.toodt import ToOdt
42
+ from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument
43
+ from novelwriter.enum import nwBuildFmt
44
+ from novelwriter.error import formatException, logException
44
45
 
45
46
  logger = logging.getLogger(__name__)
46
47
 
@@ -54,7 +55,7 @@ class NWBuildDocument:
54
55
 
55
56
  __slots__ = (
56
57
  "_project", "_build", "_queue", "_error", "_cache", "_count",
57
- "_outline", "_preview"
58
+ "_outline",
58
59
  )
59
60
 
60
61
  def __init__(self, project: NWProject, build: BuildSettings) -> None:
@@ -65,7 +66,6 @@ class NWBuildDocument:
65
66
  self._cache = None
66
67
  self._count = False
67
68
  self._outline = False
68
- self._preview = False
69
69
  return
70
70
 
71
71
  ##
@@ -99,15 +99,6 @@ class NWBuildDocument:
99
99
  self._outline = state
100
100
  return
101
101
 
102
- def setPreviewMode(self, state: bool) -> None:
103
- """Set the preview mode of the build. This also enables stats
104
- count and outline mode.
105
- """
106
- self._preview = state
107
- self._outline = state
108
- self._count = state
109
- return
110
-
111
102
  ##
112
103
  # Special Methods
113
104
  ##
@@ -134,6 +125,32 @@ class NWBuildDocument:
134
125
  self._queue.append(item.itemHandle)
135
126
  return
136
127
 
128
+ def iterBuildPreview(self, theme: TextDocumentTheme) -> Iterable[tuple[int, bool]]:
129
+ """Build a preview QTextDocument."""
130
+ makeObj = ToQTextDocument(self._project)
131
+ filtered = self._setupBuild(makeObj)
132
+
133
+ self._outline = True
134
+ self._count = True
135
+
136
+ font = QFont()
137
+ font.fromString(self._build.getStr("format.textFont"))
138
+
139
+ makeObj.initDocument(font, theme)
140
+ for i, tHandle in enumerate(self._queue):
141
+ self._error = None
142
+ if filtered.get(tHandle, (False, 0))[0]:
143
+ yield i, self._doBuild(makeObj, tHandle)
144
+ else:
145
+ yield i, False
146
+
147
+ makeObj.appendFootnotes()
148
+
149
+ self._error = None
150
+ self._cache = makeObj
151
+
152
+ return
153
+
137
154
  def iterBuild(self, path: Path, bFormat: nwBuildFmt) -> Iterable[tuple[int, bool]]:
138
155
  """Wrapper for builders based on format."""
139
156
  if bFormat in (nwBuildFmt.ODT, nwBuildFmt.FODT):
@@ -182,8 +199,6 @@ class NWBuildDocument:
182
199
  makeObj = ToHtml(self._project)
183
200
  filtered = self._setupBuild(makeObj)
184
201
 
185
- makeObj.setPreview(self._preview)
186
- makeObj.setLinkHeadings(self._preview)
187
202
  for i, tHandle in enumerate(self._queue):
188
203
  self._error = None
189
204
  if filtered.get(tHandle, (False, 0))[0]:
@@ -191,7 +206,9 @@ class NWBuildDocument:
191
206
  else:
192
207
  yield i, False
193
208
 
194
- if not (self._build.getBool("html.preserveTabs") or self._preview):
209
+ makeObj.appendFootnotes()
210
+
211
+ if not self._build.getBool("html.preserveTabs"):
195
212
  makeObj.replaceTabs()
196
213
 
197
214
  self._error = None
@@ -214,16 +231,10 @@ class NWBuildDocument:
214
231
  makeObj = ToMarkdown(self._project)
215
232
  filtered = self._setupBuild(makeObj)
216
233
 
217
- if extendedMd:
218
- makeObj.setExtendedMarkdown()
219
- else:
220
- makeObj.setStandardMarkdown()
221
-
234
+ makeObj.setExtendedMarkdown(extendedMd)
222
235
  if self._build.getBool("format.replaceTabs"):
223
236
  makeObj.replaceTabs(nSpaces=4, spaceChar=" ")
224
237
 
225
- makeObj.setPreserveBreaks(self._build.getBool("md.preserveBreaks"))
226
-
227
238
  for i, tHandle in enumerate(self._queue):
228
239
  self._error = None
229
240
  if filtered.get(tHandle, (False, 0))[0]:
@@ -231,6 +242,8 @@ class NWBuildDocument:
231
242
  else:
232
243
  yield i, False
233
244
 
245
+ makeObj.appendFootnotes()
246
+
234
247
  self._error = None
235
248
  self._cache = makeObj
236
249
 
@@ -281,13 +294,9 @@ class NWBuildDocument:
281
294
  def _setupBuild(self, bldObj: Tokenizer) -> dict:
282
295
  """Configure the build object."""
283
296
  # Get Settings
284
- textFont = self._build.getStr("format.textFont")
285
- textSize = self._build.getInt("format.textSize")
286
-
287
- fontFamily = textFont or CONFIG.textFont
288
- bldFont = QFont(fontFamily, textSize)
289
- fontInfo = QFontInfo(bldFont)
290
- textFixed = fontInfo.fixedPitch()
297
+ textFont = QFont(CONFIG.textFont)
298
+ textFont.fromString(self._build.getStr("format.textFont"))
299
+ bldObj.setFont(textFont)
291
300
 
292
301
  bldObj.setTitleFormat(
293
302
  self._build.getStr("headings.fmtTitle"),
@@ -326,9 +335,15 @@ class NWBuildDocument:
326
335
  self._build.getBool("headings.breakScene")
327
336
  )
328
337
 
329
- bldObj.setFont(fontFamily, textSize, textFixed)
330
338
  bldObj.setJustify(self._build.getBool("format.justifyText"))
331
339
  bldObj.setLineHeight(self._build.getFloat("format.lineHeight"))
340
+ bldObj.setKeepLineBreaks(self._build.getBool("format.keepBreaks"))
341
+ bldObj.setDialogueHighlight(self._build.getBool("format.showDialogue"))
342
+ bldObj.setFirstLineIndent(
343
+ self._build.getBool("format.firstLineIndent"),
344
+ self._build.getFloat("format.firstIndentWidth"),
345
+ self._build.getBool("format.indentFirstPar"),
346
+ )
332
347
 
333
348
  bldObj.setBodyText(self._build.getBool("text.includeBodyText"))
334
349
  bldObj.setSynopsis(self._build.getBool("text.includeSynopsis"))
@@ -346,7 +361,6 @@ class NWBuildDocument:
346
361
  bldObj.setHeaderFormat(
347
362
  self._build.getStr("odt.pageHeader"), self._build.getInt("odt.pageCountOffset")
348
363
  )
349
- bldObj.setFirstLineIndent(self._build.getBool("odt.firstLineIndent"))
350
364
 
351
365
  scale = nwLabels.UNIT_SCALE.get(self._build.getStr("format.pageUnit"), 1.0)
352
366
  pW, pH = nwLabels.PAPER_SIZE.get(self._build.getStr("format.pageSize"), (-1.0, -1.0))
@@ -397,5 +411,3 @@ class NWBuildDocument:
397
411
  return False
398
412
 
399
413
  return True
400
-
401
- # END Class NWBuildDocument
@@ -26,14 +26,14 @@ from __future__ import annotations
26
26
  import hashlib
27
27
  import logging
28
28
 
29
+ from pathlib import Path
29
30
  from time import time
30
31
  from typing import TYPE_CHECKING
31
- from pathlib import Path
32
32
 
33
- from novelwriter.enum import nwItemLayout, nwItemClass
34
- from novelwriter.error import formatException, logException
35
33
  from novelwriter.common import formatTimeStamp, isHandle
36
34
  from novelwriter.core.item import NWItem
35
+ from novelwriter.enum import nwItemClass, nwItemLayout
36
+ from novelwriter.error import formatException, logException
37
37
 
38
38
  if TYPE_CHECKING: # pragma: no cover
39
39
  from novelwriter.core.project import NWProject
@@ -359,5 +359,3 @@ class NWDocument:
359
359
  logger.debug("Unknown meta data: '%s'", metaLine.strip())
360
360
 
361
361
  return
362
-
363
- # END Class NWDocument