novelWriter 2.6.2__py3-none-any.whl → 2.7__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 (348) hide show
  1. novelwriter/__init__.py +98 -75
  2. novelwriter/assets/i18n/nw_cs_CZ.qm +0 -0
  3. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  4. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  5. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  6. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  7. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  8. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  9. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  10. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  11. novelwriter/assets/i18n/nw_pl_PL.qm +0 -0
  12. novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
  13. novelwriter/assets/i18n/nw_ru_RU.qm +0 -0
  14. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  15. novelwriter/assets/i18n/project_de_DE.json +3 -1
  16. novelwriter/assets/i18n/project_en_GB.json +2 -0
  17. novelwriter/assets/i18n/project_en_US.json +2 -0
  18. novelwriter/assets/i18n/project_it_IT.json +2 -0
  19. novelwriter/assets/i18n/project_ja_JP.json +2 -0
  20. novelwriter/assets/i18n/project_nb_NO.json +2 -0
  21. novelwriter/assets/i18n/project_nn_NO.json +5 -0
  22. novelwriter/assets/i18n/project_pl_PL.json +2 -0
  23. novelwriter/assets/i18n/project_pt_BR.json +2 -0
  24. novelwriter/assets/i18n/project_ru_RU.json +2 -0
  25. novelwriter/assets/i18n/project_zh_CN.json +2 -0
  26. novelwriter/assets/icons/font_awesome.icons +109 -0
  27. novelwriter/assets/icons/material_filled_bold.icons +109 -0
  28. novelwriter/assets/icons/material_filled_normal.icons +109 -0
  29. novelwriter/assets/icons/material_filled_thin.icons +109 -0
  30. novelwriter/assets/icons/material_rounded_bold.icons +109 -0
  31. novelwriter/assets/icons/material_rounded_normal.icons +109 -0
  32. novelwriter/assets/icons/material_rounded_thin.icons +109 -0
  33. novelwriter/assets/icons/remix_filled.icons +109 -0
  34. novelwriter/assets/icons/remix_outline.icons +109 -0
  35. novelwriter/assets/images/splash.png +0 -0
  36. novelwriter/assets/manual.pdf +0 -0
  37. novelwriter/assets/{manual_fr_FR.pdf → manual_fr.pdf} +0 -0
  38. novelwriter/assets/sample.zip +0 -0
  39. novelwriter/assets/syntax/cyberpunk_night.conf +1 -1
  40. novelwriter/assets/syntax/snazzy.conf +3 -3
  41. novelwriter/assets/text/credits_en.htm +12 -6
  42. novelwriter/assets/themes/cyberpunk_night.conf +23 -7
  43. novelwriter/assets/themes/default_dark.conf +20 -4
  44. novelwriter/assets/themes/default_light.conf +21 -5
  45. novelwriter/assets/themes/dracula.conf +20 -4
  46. novelwriter/assets/themes/snazzy.conf +48 -0
  47. novelwriter/assets/themes/solarized_dark.conf +24 -8
  48. novelwriter/assets/themes/solarized_light.conf +22 -6
  49. novelwriter/common.py +43 -27
  50. novelwriter/config.py +201 -139
  51. novelwriter/constants.py +92 -56
  52. novelwriter/core/buildsettings.py +26 -17
  53. novelwriter/core/coretools.py +52 -41
  54. novelwriter/core/docbuild.py +20 -13
  55. novelwriter/core/document.py +2 -2
  56. novelwriter/core/index.py +166 -432
  57. novelwriter/core/indexdata.py +406 -0
  58. novelwriter/core/item.py +50 -32
  59. novelwriter/core/itemmodel.py +43 -38
  60. novelwriter/core/novelmodel.py +225 -0
  61. novelwriter/core/options.py +1 -1
  62. novelwriter/core/project.py +24 -25
  63. novelwriter/core/projectdata.py +47 -29
  64. novelwriter/core/projectxml.py +18 -8
  65. novelwriter/core/sessions.py +32 -15
  66. novelwriter/core/spellcheck.py +4 -3
  67. novelwriter/core/status.py +12 -15
  68. novelwriter/core/storage.py +1 -1
  69. novelwriter/core/tree.py +55 -13
  70. novelwriter/dialogs/about.py +19 -22
  71. novelwriter/dialogs/docmerge.py +23 -24
  72. novelwriter/dialogs/docsplit.py +26 -26
  73. novelwriter/dialogs/editlabel.py +19 -20
  74. novelwriter/dialogs/preferences.py +143 -69
  75. novelwriter/dialogs/projectsettings.py +51 -54
  76. novelwriter/dialogs/quotes.py +14 -19
  77. novelwriter/dialogs/wordlist.py +25 -30
  78. novelwriter/enum.py +8 -0
  79. novelwriter/error.py +16 -16
  80. novelwriter/extensions/configlayout.py +24 -20
  81. novelwriter/extensions/eventfilters.py +9 -5
  82. novelwriter/extensions/modified.py +34 -15
  83. novelwriter/extensions/novelselector.py +18 -5
  84. novelwriter/extensions/pagedsidebar.py +39 -49
  85. novelwriter/extensions/progressbars.py +10 -8
  86. novelwriter/extensions/statusled.py +6 -13
  87. novelwriter/extensions/switch.py +31 -41
  88. novelwriter/extensions/switchbox.py +8 -3
  89. novelwriter/extensions/versioninfo.py +4 -4
  90. novelwriter/formats/shared.py +1 -1
  91. novelwriter/formats/todocx.py +14 -10
  92. novelwriter/formats/tohtml.py +7 -5
  93. novelwriter/formats/tokenizer.py +37 -33
  94. novelwriter/formats/tomarkdown.py +6 -2
  95. novelwriter/formats/toodt.py +27 -22
  96. novelwriter/formats/toqdoc.py +19 -14
  97. novelwriter/formats/toraw.py +6 -2
  98. novelwriter/gui/doceditor.py +314 -305
  99. novelwriter/gui/dochighlight.py +46 -45
  100. novelwriter/gui/docviewer.py +102 -104
  101. novelwriter/gui/docviewerpanel.py +47 -51
  102. novelwriter/gui/editordocument.py +8 -5
  103. novelwriter/gui/itemdetails.py +15 -18
  104. novelwriter/gui/mainmenu.py +147 -146
  105. novelwriter/gui/noveltree.py +246 -406
  106. novelwriter/gui/outline.py +145 -76
  107. novelwriter/gui/projtree.py +139 -132
  108. novelwriter/gui/search.py +34 -31
  109. novelwriter/gui/sidebar.py +13 -18
  110. novelwriter/gui/statusbar.py +27 -21
  111. novelwriter/gui/theme.py +554 -436
  112. novelwriter/guimain.py +56 -38
  113. novelwriter/shared.py +32 -23
  114. novelwriter/splash.py +74 -0
  115. novelwriter/text/comments.py +70 -0
  116. novelwriter/text/patterns.py +4 -4
  117. novelwriter/tools/dictionaries.py +20 -29
  118. novelwriter/tools/lipsum.py +18 -18
  119. novelwriter/tools/manusbuild.py +39 -42
  120. novelwriter/tools/manuscript.py +114 -127
  121. novelwriter/tools/manussettings.py +129 -102
  122. novelwriter/tools/noveldetails.py +60 -72
  123. novelwriter/tools/welcome.py +57 -75
  124. novelwriter/tools/writingstats.py +112 -102
  125. novelwriter/types.py +5 -7
  126. {novelWriter-2.6.2.dist-info → novelwriter-2.7.dist-info}/METADATA +6 -6
  127. novelwriter-2.7.dist-info/RECORD +162 -0
  128. {novelWriter-2.6.2.dist-info → novelwriter-2.7.dist-info}/WHEEL +1 -1
  129. novelWriter-2.6.2.dist-info/RECORD +0 -363
  130. novelwriter/assets/icons/typicons_dark/README.md +0 -29
  131. novelwriter/assets/icons/typicons_dark/icons.conf +0 -134
  132. novelwriter/assets/icons/typicons_dark/mixed_copy.svg +0 -4
  133. novelwriter/assets/icons/typicons_dark/mixed_document-chapter.svg +0 -12
  134. novelwriter/assets/icons/typicons_dark/mixed_document-new.svg +0 -6
  135. novelwriter/assets/icons/typicons_dark/mixed_document-note.svg +0 -12
  136. novelwriter/assets/icons/typicons_dark/mixed_document-scene.svg +0 -12
  137. novelwriter/assets/icons/typicons_dark/mixed_document-section.svg +0 -12
  138. novelwriter/assets/icons/typicons_dark/mixed_document-title.svg +0 -12
  139. novelwriter/assets/icons/typicons_dark/mixed_edit.svg +0 -4
  140. novelwriter/assets/icons/typicons_dark/mixed_import.svg +0 -5
  141. novelwriter/assets/icons/typicons_dark/mixed_input-checked.svg +0 -5
  142. novelwriter/assets/icons/typicons_dark/mixed_input-none.svg +0 -5
  143. novelwriter/assets/icons/typicons_dark/mixed_input-unchecked.svg +0 -5
  144. novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +0 -6
  145. novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +0 -6
  146. novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +0 -6
  147. novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +0 -6
  148. novelwriter/assets/icons/typicons_dark/mixed_search-replace.svg +0 -6
  149. novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +0 -6
  150. novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +0 -6
  151. novelwriter/assets/icons/typicons_dark/nw_deco-h0.svg +0 -4
  152. novelwriter/assets/icons/typicons_dark/nw_deco-h1.svg +0 -4
  153. novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +0 -4
  154. novelwriter/assets/icons/typicons_dark/nw_deco-h2.svg +0 -4
  155. novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +0 -4
  156. novelwriter/assets/icons/typicons_dark/nw_deco-h3.svg +0 -4
  157. novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +0 -4
  158. novelwriter/assets/icons/typicons_dark/nw_deco-h4.svg +0 -4
  159. novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +0 -4
  160. novelwriter/assets/icons/typicons_dark/nw_deco-noveltree-more.svg +0 -4
  161. novelwriter/assets/icons/typicons_dark/nw_font.svg +0 -4
  162. novelwriter/assets/icons/typicons_dark/nw_panel.svg +0 -4
  163. novelwriter/assets/icons/typicons_dark/nw_quote.svg +0 -4
  164. novelwriter/assets/icons/typicons_dark/nw_search-case.svg +0 -4
  165. novelwriter/assets/icons/typicons_dark/nw_search-preserve.svg +0 -4
  166. novelwriter/assets/icons/typicons_dark/nw_search-regex.svg +0 -4
  167. novelwriter/assets/icons/typicons_dark/nw_search-word.svg +0 -4
  168. novelwriter/assets/icons/typicons_dark/nw_tb-bold-md.svg +0 -4
  169. novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +0 -6
  170. novelwriter/assets/icons/typicons_dark/nw_tb-italic-md.svg +0 -4
  171. novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +0 -6
  172. novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +0 -7
  173. novelwriter/assets/icons/typicons_dark/nw_tb-strike-md.svg +0 -4
  174. novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +0 -6
  175. novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +0 -7
  176. novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +0 -7
  177. novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +0 -7
  178. novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +0 -5
  179. novelwriter/assets/icons/typicons_dark/typ_arrow-down-thick-grey.svg +0 -4
  180. novelwriter/assets/icons/typicons_dark/typ_arrow-forward.svg +0 -4
  181. novelwriter/assets/icons/typicons_dark/typ_arrow-maximise.svg +0 -4
  182. novelwriter/assets/icons/typicons_dark/typ_arrow-minimise.svg +0 -4
  183. novelwriter/assets/icons/typicons_dark/typ_arrow-repeat-grey.svg +0 -4
  184. novelwriter/assets/icons/typicons_dark/typ_book-grey.svg +0 -4
  185. novelwriter/assets/icons/typicons_dark/typ_book.svg +0 -6
  186. novelwriter/assets/icons/typicons_dark/typ_bookmark.svg +0 -4
  187. novelwriter/assets/icons/typicons_dark/typ_calendar.svg +0 -4
  188. novelwriter/assets/icons/typicons_dark/typ_cancel-grey.svg +0 -4
  189. novelwriter/assets/icons/typicons_dark/typ_cancel.svg +0 -4
  190. novelwriter/assets/icons/typicons_dark/typ_chart-bar-grey.svg +0 -4
  191. novelwriter/assets/icons/typicons_dark/typ_chevron-down.svg +0 -4
  192. novelwriter/assets/icons/typicons_dark/typ_chevron-left.svg +0 -4
  193. novelwriter/assets/icons/typicons_dark/typ_chevron-right.svg +0 -4
  194. novelwriter/assets/icons/typicons_dark/typ_chevron-up.svg +0 -4
  195. novelwriter/assets/icons/typicons_dark/typ_cog.svg +0 -4
  196. novelwriter/assets/icons/typicons_dark/typ_delete-full.svg +0 -4
  197. novelwriter/assets/icons/typicons_dark/typ_delete.svg +0 -4
  198. novelwriter/assets/icons/typicons_dark/typ_directions-full.svg +0 -4
  199. novelwriter/assets/icons/typicons_dark/typ_document-add.svg +0 -4
  200. novelwriter/assets/icons/typicons_dark/typ_document-text.svg +0 -8
  201. novelwriter/assets/icons/typicons_dark/typ_document.svg +0 -4
  202. novelwriter/assets/icons/typicons_dark/typ_export-grey.svg +0 -4
  203. novelwriter/assets/icons/typicons_dark/typ_export.svg +0 -4
  204. novelwriter/assets/icons/typicons_dark/typ_eye.svg +0 -4
  205. novelwriter/assets/icons/typicons_dark/typ_flag.svg +0 -4
  206. novelwriter/assets/icons/typicons_dark/typ_folder-open.svg +0 -4
  207. novelwriter/assets/icons/typicons_dark/typ_folder.svg +0 -5
  208. novelwriter/assets/icons/typicons_dark/typ_globe-grey.svg +0 -4
  209. novelwriter/assets/icons/typicons_dark/typ_key.svg +0 -4
  210. novelwriter/assets/icons/typicons_dark/typ_lightbulb-full.svg +0 -4
  211. novelwriter/assets/icons/typicons_dark/typ_location.svg +0 -4
  212. novelwriter/assets/icons/typicons_dark/typ_media-pause-grey.svg +0 -4
  213. novelwriter/assets/icons/typicons_dark/typ_media-record-outline.svg +0 -4
  214. novelwriter/assets/icons/typicons_dark/typ_media-record.svg +0 -4
  215. novelwriter/assets/icons/typicons_dark/typ_minus.svg +0 -4
  216. novelwriter/assets/icons/typicons_dark/typ_pencil.svg +0 -5
  217. novelwriter/assets/icons/typicons_dark/typ_pin-outline.svg +0 -4
  218. novelwriter/assets/icons/typicons_dark/typ_pin.svg +0 -4
  219. novelwriter/assets/icons/typicons_dark/typ_plus.svg +0 -4
  220. novelwriter/assets/icons/typicons_dark/typ_puzzle-outline.svg +0 -4
  221. novelwriter/assets/icons/typicons_dark/typ_puzzle.svg +0 -4
  222. novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +0 -4
  223. novelwriter/assets/icons/typicons_dark/typ_refresh.svg +0 -4
  224. novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +0 -4
  225. novelwriter/assets/icons/typicons_dark/typ_search.svg +0 -4
  226. novelwriter/assets/icons/typicons_dark/typ_star.svg +0 -4
  227. novelwriter/assets/icons/typicons_dark/typ_stopwatch-grey.svg +0 -4
  228. novelwriter/assets/icons/typicons_dark/typ_th-dot-menu.svg +0 -4
  229. novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +0 -4
  230. novelwriter/assets/icons/typicons_dark/typ_th-list-grey.svg +0 -4
  231. novelwriter/assets/icons/typicons_dark/typ_th-list.svg +0 -9
  232. novelwriter/assets/icons/typicons_dark/typ_times.svg +0 -4
  233. novelwriter/assets/icons/typicons_dark/typ_trash.svg +0 -5
  234. novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +0 -4
  235. novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +0 -4
  236. novelwriter/assets/icons/typicons_dark/typ_user.svg +0 -5
  237. novelwriter/assets/icons/typicons_dark/typ_warning-full.svg +0 -4
  238. novelwriter/assets/icons/typicons_light/README.md +0 -29
  239. novelwriter/assets/icons/typicons_light/icons.conf +0 -134
  240. novelwriter/assets/icons/typicons_light/mixed_copy.svg +0 -4
  241. novelwriter/assets/icons/typicons_light/mixed_document-chapter.svg +0 -12
  242. novelwriter/assets/icons/typicons_light/mixed_document-new.svg +0 -6
  243. novelwriter/assets/icons/typicons_light/mixed_document-note.svg +0 -12
  244. novelwriter/assets/icons/typicons_light/mixed_document-scene.svg +0 -12
  245. novelwriter/assets/icons/typicons_light/mixed_document-section.svg +0 -12
  246. novelwriter/assets/icons/typicons_light/mixed_document-title.svg +0 -12
  247. novelwriter/assets/icons/typicons_light/mixed_edit.svg +0 -4
  248. novelwriter/assets/icons/typicons_light/mixed_import.svg +0 -5
  249. novelwriter/assets/icons/typicons_light/mixed_input-checked.svg +0 -5
  250. novelwriter/assets/icons/typicons_light/mixed_input-none.svg +0 -5
  251. novelwriter/assets/icons/typicons_light/mixed_input-unchecked.svg +0 -5
  252. novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +0 -6
  253. novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +0 -6
  254. novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +0 -6
  255. novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +0 -6
  256. novelwriter/assets/icons/typicons_light/mixed_search-replace.svg +0 -6
  257. novelwriter/assets/icons/typicons_light/mixed_size-height.svg +0 -6
  258. novelwriter/assets/icons/typicons_light/mixed_size-width.svg +0 -6
  259. novelwriter/assets/icons/typicons_light/nw_deco-h0.svg +0 -4
  260. novelwriter/assets/icons/typicons_light/nw_deco-h1.svg +0 -4
  261. novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +0 -4
  262. novelwriter/assets/icons/typicons_light/nw_deco-h2.svg +0 -4
  263. novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +0 -4
  264. novelwriter/assets/icons/typicons_light/nw_deco-h3.svg +0 -4
  265. novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +0 -4
  266. novelwriter/assets/icons/typicons_light/nw_deco-h4.svg +0 -4
  267. novelwriter/assets/icons/typicons_light/nw_deco-note.svg +0 -4
  268. novelwriter/assets/icons/typicons_light/nw_deco-noveltree-more.svg +0 -4
  269. novelwriter/assets/icons/typicons_light/nw_font.svg +0 -4
  270. novelwriter/assets/icons/typicons_light/nw_panel.svg +0 -4
  271. novelwriter/assets/icons/typicons_light/nw_quote.svg +0 -4
  272. novelwriter/assets/icons/typicons_light/nw_search-case.svg +0 -4
  273. novelwriter/assets/icons/typicons_light/nw_search-preserve.svg +0 -4
  274. novelwriter/assets/icons/typicons_light/nw_search-regex.svg +0 -4
  275. novelwriter/assets/icons/typicons_light/nw_search-word.svg +0 -4
  276. novelwriter/assets/icons/typicons_light/nw_tb-bold-md.svg +0 -4
  277. novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +0 -6
  278. novelwriter/assets/icons/typicons_light/nw_tb-italic-md.svg +0 -4
  279. novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +0 -6
  280. novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +0 -7
  281. novelwriter/assets/icons/typicons_light/nw_tb-strike-md.svg +0 -4
  282. novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +0 -6
  283. novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +0 -7
  284. novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +0 -7
  285. novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +0 -7
  286. novelwriter/assets/icons/typicons_light/nw_toolbar.svg +0 -5
  287. novelwriter/assets/icons/typicons_light/typ_arrow-down-thick-grey.svg +0 -4
  288. novelwriter/assets/icons/typicons_light/typ_arrow-forward.svg +0 -4
  289. novelwriter/assets/icons/typicons_light/typ_arrow-maximise.svg +0 -4
  290. novelwriter/assets/icons/typicons_light/typ_arrow-minimise.svg +0 -4
  291. novelwriter/assets/icons/typicons_light/typ_arrow-repeat-grey.svg +0 -4
  292. novelwriter/assets/icons/typicons_light/typ_book-grey.svg +0 -4
  293. novelwriter/assets/icons/typicons_light/typ_book.svg +0 -6
  294. novelwriter/assets/icons/typicons_light/typ_bookmark.svg +0 -4
  295. novelwriter/assets/icons/typicons_light/typ_calendar.svg +0 -4
  296. novelwriter/assets/icons/typicons_light/typ_cancel-grey.svg +0 -4
  297. novelwriter/assets/icons/typicons_light/typ_cancel.svg +0 -4
  298. novelwriter/assets/icons/typicons_light/typ_chart-bar-grey.svg +0 -4
  299. novelwriter/assets/icons/typicons_light/typ_chevron-down.svg +0 -4
  300. novelwriter/assets/icons/typicons_light/typ_chevron-left.svg +0 -4
  301. novelwriter/assets/icons/typicons_light/typ_chevron-right.svg +0 -4
  302. novelwriter/assets/icons/typicons_light/typ_chevron-up.svg +0 -4
  303. novelwriter/assets/icons/typicons_light/typ_cog.svg +0 -4
  304. novelwriter/assets/icons/typicons_light/typ_delete-full.svg +0 -4
  305. novelwriter/assets/icons/typicons_light/typ_delete.svg +0 -4
  306. novelwriter/assets/icons/typicons_light/typ_directions-full.svg +0 -4
  307. novelwriter/assets/icons/typicons_light/typ_document-add.svg +0 -4
  308. novelwriter/assets/icons/typicons_light/typ_document-text.svg +0 -5
  309. novelwriter/assets/icons/typicons_light/typ_document.svg +0 -4
  310. novelwriter/assets/icons/typicons_light/typ_export-grey.svg +0 -4
  311. novelwriter/assets/icons/typicons_light/typ_export.svg +0 -4
  312. novelwriter/assets/icons/typicons_light/typ_eye.svg +0 -4
  313. novelwriter/assets/icons/typicons_light/typ_flag.svg +0 -4
  314. novelwriter/assets/icons/typicons_light/typ_folder-open.svg +0 -4
  315. novelwriter/assets/icons/typicons_light/typ_folder.svg +0 -5
  316. novelwriter/assets/icons/typicons_light/typ_globe-grey.svg +0 -4
  317. novelwriter/assets/icons/typicons_light/typ_key.svg +0 -4
  318. novelwriter/assets/icons/typicons_light/typ_lightbulb-full.svg +0 -4
  319. novelwriter/assets/icons/typicons_light/typ_location.svg +0 -4
  320. novelwriter/assets/icons/typicons_light/typ_media-pause-grey.svg +0 -4
  321. novelwriter/assets/icons/typicons_light/typ_media-record-outline.svg +0 -4
  322. novelwriter/assets/icons/typicons_light/typ_media-record.svg +0 -4
  323. novelwriter/assets/icons/typicons_light/typ_minus.svg +0 -4
  324. novelwriter/assets/icons/typicons_light/typ_pencil.svg +0 -5
  325. novelwriter/assets/icons/typicons_light/typ_pin-outline.svg +0 -4
  326. novelwriter/assets/icons/typicons_light/typ_pin.svg +0 -4
  327. novelwriter/assets/icons/typicons_light/typ_plus.svg +0 -4
  328. novelwriter/assets/icons/typicons_light/typ_puzzle-outline.svg +0 -4
  329. novelwriter/assets/icons/typicons_light/typ_puzzle.svg +0 -4
  330. novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +0 -4
  331. novelwriter/assets/icons/typicons_light/typ_refresh.svg +0 -4
  332. novelwriter/assets/icons/typicons_light/typ_search-grey.svg +0 -4
  333. novelwriter/assets/icons/typicons_light/typ_search.svg +0 -4
  334. novelwriter/assets/icons/typicons_light/typ_star.svg +0 -4
  335. novelwriter/assets/icons/typicons_light/typ_stopwatch-grey.svg +0 -4
  336. novelwriter/assets/icons/typicons_light/typ_th-dot-menu.svg +0 -4
  337. novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +0 -4
  338. novelwriter/assets/icons/typicons_light/typ_th-list-grey.svg +0 -4
  339. novelwriter/assets/icons/typicons_light/typ_th-list.svg +0 -9
  340. novelwriter/assets/icons/typicons_light/typ_times.svg +0 -4
  341. novelwriter/assets/icons/typicons_light/typ_trash.svg +0 -5
  342. novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +0 -4
  343. novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +0 -4
  344. novelwriter/assets/icons/typicons_light/typ_user.svg +0 -5
  345. novelwriter/assets/icons/typicons_light/typ_warning-full.svg +0 -4
  346. {novelWriter-2.6.2.dist-info → novelwriter-2.7.dist-info}/entry_points.txt +0 -0
  347. {novelWriter-2.6.2.dist-info → novelwriter-2.7.dist-info/licenses}/LICENSE.md +0 -0
  348. {novelWriter-2.6.2.dist-info → novelwriter-2.7.dist-info}/top_level.txt +0 -0
novelwriter/constants.py CHANGED
@@ -23,7 +23,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
23
23
  """
24
24
  from __future__ import annotations
25
25
 
26
- from PyQt5.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
26
+ from typing import Final
27
+
28
+ from PyQt6.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
27
29
 
28
30
  from novelwriter.enum import (
29
31
  nwBuildFmt, nwComment, nwItemClass, nwItemLayout, nwOutline, nwStatusShape
@@ -35,6 +37,11 @@ def trConst(text: str) -> str:
35
37
  return QCoreApplication.translate("Constant", text)
36
38
 
37
39
 
40
+ def trStats(text: str) -> str:
41
+ """Wrapper function for locally translating stats constants."""
42
+ return QCoreApplication.translate("Stats", text)
43
+
44
+
38
45
  class nwConst:
39
46
 
40
47
  # Date and Time Formats
@@ -94,7 +101,7 @@ class nwShortcode:
94
101
  FOOTNOTE_B = "[footnote:"
95
102
  FIELD_B = "[field:"
96
103
 
97
- COMMENT_STYLES = {
104
+ COMMENT_STYLES: Final[dict[nwComment, str]] = {
98
105
  nwComment.FOOTNOTE: "[footnote:{0}]",
99
106
  nwComment.COMMENT: "[comment:{0}]",
100
107
  }
@@ -105,13 +112,13 @@ class nwShortcode:
105
112
  class nwStyles:
106
113
 
107
114
  H_VALID = ("H0", "H1", "H2", "H3", "H4")
108
- H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
109
- H_SIZES = {0: 2.50, 1: 2.00, 2: 1.75, 3: 1.50, 4: 1.25}
115
+ H_LEVEL: Final[dict[str, int]] = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
116
+ H_SIZES: Final[dict[int, float]] = {0: 2.50, 1: 2.00, 2: 1.75, 3: 1.50, 4: 1.25}
110
117
 
111
118
  T_NORMAL = 1.0
112
119
  T_SMALL = 0.8
113
120
 
114
- T_LABEL = {
121
+ T_LABEL: Final[dict[str, str]] = {
115
122
  "H0": QT_TRANSLATE_NOOP("Constant", "Title"),
116
123
  "H1": QT_TRANSLATE_NOOP("Constant", "Heading 1 (Partition)"),
117
124
  "H2": QT_TRANSLATE_NOOP("Constant", "Heading 2 (Chapter)"),
@@ -120,7 +127,7 @@ class nwStyles:
120
127
  "TT": QT_TRANSLATE_NOOP("Constant", "Text Paragraph"),
121
128
  "SP": QT_TRANSLATE_NOOP("Constant", "Scene Separator"),
122
129
  }
123
- T_MARGIN = {
130
+ T_MARGIN: Final[dict[str, tuple[float, float]]] = {
124
131
  "H0": (1.50, 0.60), # Title margins (top, bottom)
125
132
  "H1": (1.50, 0.60), # Heading 1 margins (top, bottom)
126
133
  "H2": (1.50, 0.60), # Heading 2 margins (top, bottom)
@@ -169,20 +176,20 @@ class nwKeyWords:
169
176
  MENTION_KEY = "@mention"
170
177
 
171
178
  # Note: The order here affects the order of menu entries
172
- ALL_KEYS = [
179
+ ALL_KEYS: Final[list[str]] = [
173
180
  TAG_KEY, POV_KEY, FOCUS_KEY, CHAR_KEY, PLOT_KEY, TIME_KEY, WORLD_KEY,
174
181
  OBJECT_KEY, ENTITY_KEY, CUSTOM_KEY, STORY_KEY, MENTION_KEY,
175
182
  ]
176
- CAN_CREATE = [
183
+ CAN_CREATE: Final[list[str]] = [
177
184
  POV_KEY, FOCUS_KEY, CHAR_KEY, PLOT_KEY, TIME_KEY, WORLD_KEY,
178
185
  OBJECT_KEY, ENTITY_KEY, CUSTOM_KEY,
179
186
  ]
180
187
 
181
188
  # Set of Valid Keys
182
- VALID_KEYS = set(ALL_KEYS)
189
+ VALID_KEYS: Final[set[str]] = set(ALL_KEYS)
183
190
 
184
191
  # Map from Keys to Item Class
185
- KEY_CLASS = {
192
+ KEY_CLASS: Final[dict[str, nwItemClass]] = {
186
193
  POV_KEY: nwItemClass.CHARACTER,
187
194
  FOCUS_KEY: nwItemClass.CHARACTER,
188
195
  CHAR_KEY: nwItemClass.CHARACTER,
@@ -198,7 +205,7 @@ class nwKeyWords:
198
205
 
199
206
  class nwLists:
200
207
 
201
- USER_CLASSES = [
208
+ USER_CLASSES: Final[list[nwItemClass]] = [
202
209
  nwItemClass.CHARACTER,
203
210
  nwItemClass.PLOT,
204
211
  nwItemClass.WORLD,
@@ -224,7 +231,7 @@ class nwStats:
224
231
  WORDS_TITLE = "titleWords"
225
232
 
226
233
  # Note: The order here affects the order of menu entries
227
- ALL_FIELDS = [
234
+ ALL_FIELDS: Final[list[str]] = [
228
235
  WORDS, WORDS_TEXT, WORDS_TITLE,
229
236
  CHARS, CHARS_TEXT, CHARS_TITLE,
230
237
  WCHARS_ALL, WCHARS_TEXT, WCHARS_TITLE,
@@ -234,7 +241,7 @@ class nwStats:
234
241
 
235
242
  class nwLabels:
236
243
 
237
- CLASS_NAME = {
244
+ CLASS_NAME: Final[dict[nwItemClass, str]] = {
238
245
  nwItemClass.NO_CLASS: QT_TRANSLATE_NOOP("Constant", "None"),
239
246
  nwItemClass.NOVEL: QT_TRANSLATE_NOOP("Constant", "Novel"),
240
247
  nwItemClass.PLOT: QT_TRANSLATE_NOOP("Constant", "Plot"),
@@ -248,7 +255,7 @@ class nwLabels:
248
255
  nwItemClass.TEMPLATE: QT_TRANSLATE_NOOP("Constant", "Templates"),
249
256
  nwItemClass.TRASH: QT_TRANSLATE_NOOP("Constant", "Trash"),
250
257
  }
251
- CLASS_ICON = {
258
+ CLASS_ICON: Final[dict[nwItemClass, str]] = {
252
259
  nwItemClass.NO_CLASS: "cls_none",
253
260
  nwItemClass.NOVEL: "cls_novel",
254
261
  nwItemClass.PLOT: "cls_plot",
@@ -262,12 +269,12 @@ class nwLabels:
262
269
  nwItemClass.TEMPLATE: "cls_template",
263
270
  nwItemClass.TRASH: "cls_trash",
264
271
  }
265
- LAYOUT_NAME = {
272
+ LAYOUT_NAME: Final[dict[nwItemLayout, str]] = {
266
273
  nwItemLayout.NO_LAYOUT: QT_TRANSLATE_NOOP("Constant", "None"),
267
274
  nwItemLayout.DOCUMENT: QT_TRANSLATE_NOOP("Constant", "Novel Document"),
268
275
  nwItemLayout.NOTE: QT_TRANSLATE_NOOP("Constant", "Project Note"),
269
276
  }
270
- ITEM_DESCRIPTION = {
277
+ ITEM_DESCRIPTION: Final[dict[str, str]] = {
271
278
  "none": QT_TRANSLATE_NOOP("Constant", "None"),
272
279
  "root": QT_TRANSLATE_NOOP("Constant", "Root Folder"),
273
280
  "folder": QT_TRANSLATE_NOOP("Constant", "Folder"),
@@ -278,11 +285,11 @@ class nwLabels:
278
285
  "doc_h4": QT_TRANSLATE_NOOP("Constant", "Novel Section"),
279
286
  "note": QT_TRANSLATE_NOOP("Constant", "Project Note"),
280
287
  }
281
- ACTIVE_NAME = {
288
+ ACTIVE_NAME: Final[dict[str, str]] = {
282
289
  "checked": QT_TRANSLATE_NOOP("Constant", "Active"),
283
290
  "unchecked": QT_TRANSLATE_NOOP("Constant", "Inactive"),
284
291
  }
285
- KEY_NAME = {
292
+ KEY_NAME: Final[dict[str, str]] = {
286
293
  nwKeyWords.TAG_KEY: QT_TRANSLATE_NOOP("Constant", "Tag"),
287
294
  nwKeyWords.POV_KEY: QT_TRANSLATE_NOOP("Constant", "Point of View"),
288
295
  nwKeyWords.FOCUS_KEY: QT_TRANSLATE_NOOP("Constant", "Focus"),
@@ -296,7 +303,7 @@ class nwLabels:
296
303
  nwKeyWords.STORY_KEY: QT_TRANSLATE_NOOP("Constant", "Story"),
297
304
  nwKeyWords.MENTION_KEY: QT_TRANSLATE_NOOP("Constant", "Mentions"),
298
305
  }
299
- KEY_SHORTCUT = {
306
+ KEY_SHORTCUT: Final[dict[str, str]] = {
300
307
  nwKeyWords.TAG_KEY: "Ctrl+K, G",
301
308
  nwKeyWords.POV_KEY: "Ctrl+K, V",
302
309
  nwKeyWords.FOCUS_KEY: "Ctrl+K, F",
@@ -310,7 +317,7 @@ class nwLabels:
310
317
  nwKeyWords.STORY_KEY: "Ctrl+K, N",
311
318
  nwKeyWords.MENTION_KEY: "Ctrl+K, M",
312
319
  }
313
- OUTLINE_COLS = {
320
+ OUTLINE_COLS: Final[dict[nwOutline, str]] = {
314
321
  nwOutline.TITLE: QT_TRANSLATE_NOOP("Constant", "Title"),
315
322
  nwOutline.LEVEL: QT_TRANSLATE_NOOP("Constant", "Level"),
316
323
  nwOutline.LABEL: QT_TRANSLATE_NOOP("Constant", "Document"),
@@ -332,7 +339,7 @@ class nwLabels:
332
339
  nwOutline.MENTION: KEY_NAME[nwKeyWords.MENTION_KEY],
333
340
  nwOutline.SYNOP: QT_TRANSLATE_NOOP("Constant", "Synopsis"),
334
341
  }
335
- STATS_NAME = {
342
+ STATS_NAME: Final[dict[str, str]] = {
336
343
  nwStats.CHARS: QT_TRANSLATE_NOOP("Stats", "Characters"),
337
344
  nwStats.CHARS_TEXT: QT_TRANSLATE_NOOP("Stats", "Characters in Text"),
338
345
  nwStats.CHARS_TITLE: QT_TRANSLATE_NOOP("Stats", "Characters in Headings"),
@@ -345,7 +352,11 @@ class nwLabels:
345
352
  nwStats.WORDS_TEXT: QT_TRANSLATE_NOOP("Stats", "Words in Text"),
346
353
  nwStats.WORDS_TITLE: QT_TRANSLATE_NOOP("Stats", "Words in Headings"),
347
354
  }
348
- BUILD_FMT = {
355
+ STATS_DISPLAY: Final[dict[str, str]] = {
356
+ nwStats.CHARS: QT_TRANSLATE_NOOP("Stats", "Characters: {0} ({1})"),
357
+ nwStats.WORDS: QT_TRANSLATE_NOOP("Stats", "Words: {0} ({1})"),
358
+ }
359
+ BUILD_FMT: Final[dict[nwBuildFmt, str]] = {
349
360
  nwBuildFmt.ODT: QT_TRANSLATE_NOOP("Constant", "Open Document (.odt)"),
350
361
  nwBuildFmt.FODT: QT_TRANSLATE_NOOP("Constant", "Flat Open Document (.fodt)"),
351
362
  nwBuildFmt.DOCX: QT_TRANSLATE_NOOP("Constant", "Microsoft Word Document (.docx)"),
@@ -357,7 +368,7 @@ class nwLabels:
357
368
  nwBuildFmt.J_HTML: QT_TRANSLATE_NOOP("Constant", "JSON + HTML 5 (.json)"),
358
369
  nwBuildFmt.J_NWD: QT_TRANSLATE_NOOP("Constant", "JSON + novelWriter Markup (.json)"),
359
370
  }
360
- BUILD_EXT = {
371
+ BUILD_EXT: Final[dict[nwBuildFmt, str]] = {
361
372
  nwBuildFmt.ODT: ".odt",
362
373
  nwBuildFmt.FODT: ".fodt",
363
374
  nwBuildFmt.DOCX: ".docx",
@@ -369,52 +380,52 @@ class nwLabels:
369
380
  nwBuildFmt.J_HTML: ".json",
370
381
  nwBuildFmt.J_NWD: ".json",
371
382
  }
372
- SHAPES_PLAIN = {
373
- nwStatusShape.SQUARE: QT_TRANSLATE_NOOP("Shape", "Square"),
374
- nwStatusShape.TRIANGLE: QT_TRANSLATE_NOOP("Shape", "Triangle"),
375
- nwStatusShape.NABLA: QT_TRANSLATE_NOOP("Shape", "Nabla"),
376
- nwStatusShape.DIAMOND: QT_TRANSLATE_NOOP("Shape", "Diamond"),
377
- nwStatusShape.PENTAGON: QT_TRANSLATE_NOOP("Shape", "Pentagon"),
378
- nwStatusShape.HEXAGON: QT_TRANSLATE_NOOP("Shape", "Hexagon"),
379
- nwStatusShape.STAR: QT_TRANSLATE_NOOP("Shape", "Star"),
380
- nwStatusShape.PACMAN: QT_TRANSLATE_NOOP("Shape", "Pacman"),
383
+ SHAPES_PLAIN: Final[dict[nwStatusShape, str]] = {
384
+ nwStatusShape.SQUARE: QT_TRANSLATE_NOOP("Constant", "Square"),
385
+ nwStatusShape.TRIANGLE: QT_TRANSLATE_NOOP("Constant", "Triangle"),
386
+ nwStatusShape.NABLA: QT_TRANSLATE_NOOP("Constant", "Nabla"),
387
+ nwStatusShape.DIAMOND: QT_TRANSLATE_NOOP("Constant", "Diamond"),
388
+ nwStatusShape.PENTAGON: QT_TRANSLATE_NOOP("Constant", "Pentagon"),
389
+ nwStatusShape.HEXAGON: QT_TRANSLATE_NOOP("Constant", "Hexagon"),
390
+ nwStatusShape.STAR: QT_TRANSLATE_NOOP("Constant", "Star"),
391
+ nwStatusShape.PACMAN: QT_TRANSLATE_NOOP("Constant", "Pacman"),
381
392
  }
382
- SHAPES_CIRCLE = {
383
- nwStatusShape.CIRCLE_Q: QT_TRANSLATE_NOOP("Shape", "1/4 Circle"),
384
- nwStatusShape.CIRCLE_H: QT_TRANSLATE_NOOP("Shape", "Half Circle"),
385
- nwStatusShape.CIRCLE_T: QT_TRANSLATE_NOOP("Shape", "3/4 Circle"),
386
- nwStatusShape.CIRCLE: QT_TRANSLATE_NOOP("Shape", "Full Circle"),
393
+ SHAPES_CIRCLE: Final[dict[nwStatusShape, str]] = {
394
+ nwStatusShape.CIRCLE_Q: QT_TRANSLATE_NOOP("Constant", "1/4 Circle"),
395
+ nwStatusShape.CIRCLE_H: QT_TRANSLATE_NOOP("Constant", "Half Circle"),
396
+ nwStatusShape.CIRCLE_T: QT_TRANSLATE_NOOP("Constant", "3/4 Circle"),
397
+ nwStatusShape.CIRCLE: QT_TRANSLATE_NOOP("Constant", "Full Circle"),
387
398
  }
388
- SHAPES_BARS = {
389
- nwStatusShape.BARS_1: QT_TRANSLATE_NOOP("Shape", "1 Bar"),
390
- nwStatusShape.BARS_2: QT_TRANSLATE_NOOP("Shape", "2 Bars"),
391
- nwStatusShape.BARS_3: QT_TRANSLATE_NOOP("Shape", "3 Bars"),
392
- nwStatusShape.BARS_4: QT_TRANSLATE_NOOP("Shape", "4 Bars"),
399
+ SHAPES_BARS: Final[dict[nwStatusShape, str]] = {
400
+ nwStatusShape.BARS_1: QT_TRANSLATE_NOOP("Constant", "1 Bar"),
401
+ nwStatusShape.BARS_2: QT_TRANSLATE_NOOP("Constant", "2 Bars"),
402
+ nwStatusShape.BARS_3: QT_TRANSLATE_NOOP("Constant", "3 Bars"),
403
+ nwStatusShape.BARS_4: QT_TRANSLATE_NOOP("Constant", "4 Bars"),
393
404
  }
394
- SHAPES_BLOCKS = {
395
- nwStatusShape.BLOCK_1: QT_TRANSLATE_NOOP("Shape", "1 Block"),
396
- nwStatusShape.BLOCK_2: QT_TRANSLATE_NOOP("Shape", "2 Blocks"),
397
- nwStatusShape.BLOCK_3: QT_TRANSLATE_NOOP("Shape", "3 Blocks"),
398
- nwStatusShape.BLOCK_4: QT_TRANSLATE_NOOP("Shape", "4 Blocks"),
405
+ SHAPES_BLOCKS: Final[dict[nwStatusShape, str]] = {
406
+ nwStatusShape.BLOCK_1: QT_TRANSLATE_NOOP("Constant", "1 Block"),
407
+ nwStatusShape.BLOCK_2: QT_TRANSLATE_NOOP("Constant", "2 Blocks"),
408
+ nwStatusShape.BLOCK_3: QT_TRANSLATE_NOOP("Constant", "3 Blocks"),
409
+ nwStatusShape.BLOCK_4: QT_TRANSLATE_NOOP("Constant", "4 Blocks"),
399
410
  }
400
- FILE_FILTERS = {
411
+ FILE_FILTERS: Final[dict[str, str]] = {
401
412
  "*.txt": QT_TRANSLATE_NOOP("Constant", "Text files"),
402
413
  "*.md": QT_TRANSLATE_NOOP("Constant", "Markdown files"),
403
414
  "*.nwd": QT_TRANSLATE_NOOP("Constant", "novelWriter files"),
404
415
  "*.csv": QT_TRANSLATE_NOOP("Constant", "CSV files"),
405
416
  "*": QT_TRANSLATE_NOOP("Constant", "All files"),
406
417
  }
407
- UNIT_NAME = {
418
+ UNIT_NAME: Final[dict[str, str]] = {
408
419
  "mm": QT_TRANSLATE_NOOP("Constant", "Millimetres"),
409
420
  "cm": QT_TRANSLATE_NOOP("Constant", "Centimetres"),
410
421
  "in": QT_TRANSLATE_NOOP("Constant", "Inches"),
411
422
  }
412
- UNIT_SCALE = {
423
+ UNIT_SCALE: Final[dict[str, float]] = {
413
424
  "mm": 1.0,
414
425
  "cm": 10.0,
415
426
  "in": 25.4,
416
427
  }
417
- PAPER_NAME = {
428
+ PAPER_NAME: Final[dict[str, str]] = {
418
429
  "A4": QT_TRANSLATE_NOOP("Constant", "A4"),
419
430
  "A5": QT_TRANSLATE_NOOP("Constant", "A5"),
420
431
  "A6": QT_TRANSLATE_NOOP("Constant", "A6"),
@@ -422,7 +433,7 @@ class nwLabels:
422
433
  "Letter": QT_TRANSLATE_NOOP("Constant", "US Letter"),
423
434
  "Custom": QT_TRANSLATE_NOOP("Constant", "Custom"),
424
435
  }
425
- PAPER_SIZE = {
436
+ PAPER_SIZE: Final[dict[str, tuple[float, float]]] = {
426
437
  "A4": (210.0, 297.0),
427
438
  "A5": (148.0, 210.0),
428
439
  "A6": (105.0, 148.0),
@@ -430,6 +441,18 @@ class nwLabels:
430
441
  "Letter": (215.9, 279.4),
431
442
  "Custom": (-1.0, -1.0),
432
443
  }
444
+ THEME_COLORS: Final[dict[str, str]] = {
445
+ "theme": QT_TRANSLATE_NOOP("Constant", "Theme Colours"),
446
+ "default": QT_TRANSLATE_NOOP("Constant", "Foreground Colour"),
447
+ "faded": QT_TRANSLATE_NOOP("Constant", "Faded Colour"),
448
+ "red": QT_TRANSLATE_NOOP("Constant", "Red"),
449
+ "orange": QT_TRANSLATE_NOOP("Constant", "Orange"),
450
+ "yellow": QT_TRANSLATE_NOOP("Constant", "Yellow"),
451
+ "green": QT_TRANSLATE_NOOP("Constant", "Green"),
452
+ "aqua": QT_TRANSLATE_NOOP("Constant", "Aqua"),
453
+ "blue": QT_TRANSLATE_NOOP("Constant", "Blue"),
454
+ "purple": QT_TRANSLATE_NOOP("Constant", "Purple"),
455
+ }
433
456
 
434
457
 
435
458
  class nwHeadFmt:
@@ -445,7 +468,7 @@ class nwHeadFmt:
445
468
  CHAR_POV = "{Char:POV}"
446
469
  CHAR_FOCUS = "{Char:Focus}"
447
470
 
448
- PAGE_HEADERS = [
471
+ PAGE_HEADERS: Final[list[str]] = [
449
472
  TITLE, CH_NUM, CH_WORD, CH_ROMU, CH_ROML, SC_NUM, SC_ABS,
450
473
  CHAR_POV, CHAR_FOCUS
451
474
  ]
@@ -461,7 +484,7 @@ class nwQuotes:
461
484
  """Allowed quotation marks.
462
485
  Source: https://en.wikipedia.org/wiki/Quotation_mark
463
486
  """
464
- SYMBOLS = {
487
+ SYMBOLS: Final[dict[str, str]] = {
465
488
  "\u0027": QT_TRANSLATE_NOOP("Constant", "Straight single quotation mark"),
466
489
  "\u0022": QT_TRANSLATE_NOOP("Constant", "Straight double quotation mark"),
467
490
 
@@ -486,6 +509,19 @@ class nwQuotes:
486
509
  "\u300f": QT_TRANSLATE_NOOP("Constant", "Right white corner bracket"),
487
510
  }
488
511
 
512
+ DASHES: Final[dict[str, str]] = {
513
+ "": QT_TRANSLATE_NOOP("Constant", "None"),
514
+ "\u2013": QT_TRANSLATE_NOOP("Constant", "Short dash"),
515
+ "\u2014": QT_TRANSLATE_NOOP("Constant", "Long dash"),
516
+ "\u2015": QT_TRANSLATE_NOOP("Constant", "Horizontal bar"),
517
+ }
518
+
519
+ ALLOWED: Final[list[str]] = [
520
+ "\u0027", "\u0022", "\u2018", "\u2019", "\u201a", "\u201b", "\u201c", "\u201d", "\u201e",
521
+ "\u201f", "\u2e42", "\u2039", "\u203a", "\u00ab", "\u00bb", "\u300c", "\u300d", "\u300e",
522
+ "\u300f", "\u2013", "\u2014", "\u2015",
523
+ ]
524
+
489
525
 
490
526
  class nwUnicode:
491
527
  """Supported unicode character constants and their HTML equivalents."""
@@ -626,9 +662,9 @@ class nwUnicode:
626
662
  H_LTRIS = "&#9666;"
627
663
 
628
664
 
629
- class nwHtmlUnicode():
665
+ class nwHtmlUnicode:
630
666
 
631
- U_TO_H = {
667
+ U_TO_H: Final[dict[str, str]] = {
632
668
  # Quotes
633
669
  nwUnicode.U_QUOT: nwUnicode.H_QUOT,
634
670
  nwUnicode.U_APOS: nwUnicode.H_APOS,
@@ -28,11 +28,11 @@ import json
28
28
  import logging
29
29
  import uuid
30
30
 
31
- from collections.abc import Iterable
32
31
  from enum import Enum
33
32
  from pathlib import Path
33
+ from typing import TYPE_CHECKING
34
34
 
35
- from PyQt5.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
35
+ from PyQt6.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
36
36
 
37
37
  from novelwriter import CONFIG
38
38
  from novelwriter.common import checkUuid, isHandle, jsonEncode
@@ -41,13 +41,18 @@ from novelwriter.core.project import NWProject
41
41
  from novelwriter.enum import nwBuildFmt
42
42
  from novelwriter.error import logException
43
43
 
44
+ if TYPE_CHECKING:
45
+ from collections.abc import Iterable
46
+
44
47
  logger = logging.getLogger(__name__)
45
48
 
49
+ T_BuildValue = str | int | float | bool
50
+
46
51
  # The Settings Template
47
52
  # =====================
48
53
  # Each entry contains a tuple on the form: (type, default)
49
54
 
50
- SETTINGS_TEMPLATE: dict[str, tuple[type, str | int | float | bool]] = {
55
+ SETTINGS_TEMPLATE: dict[str, tuple[type, T_BuildValue]] = {
51
56
  "filter.includeNovel": (bool, True),
52
57
  "filter.includeNotes": (bool, False),
53
58
  "filter.includeInactive": (bool, False),
@@ -73,6 +78,8 @@ SETTINGS_TEMPLATE: dict[str, tuple[type, str | int | float | bool]] = {
73
78
  "headings.breakScene": (bool, False),
74
79
  "text.includeSynopsis": (bool, False),
75
80
  "text.includeComments": (bool, False),
81
+ "text.includeStory": (bool, False),
82
+ "text.includeNotes": (bool, False),
76
83
  "text.includeKeywords": (bool, False),
77
84
  "text.includeBodyText": (bool, True),
78
85
  "text.ignoredKeywords": (str, ""),
@@ -139,6 +146,8 @@ SETTINGS_LABELS = {
139
146
  "text.grpContent": QT_TRANSLATE_NOOP("Builds", "Text Content"),
140
147
  "text.includeSynopsis": QT_TRANSLATE_NOOP("Builds", "Include Synopsis"),
141
148
  "text.includeComments": QT_TRANSLATE_NOOP("Builds", "Include Comments"),
149
+ "text.includeStory": QT_TRANSLATE_NOOP("Builds", "Include Story Structure"),
150
+ "text.includeNotes": QT_TRANSLATE_NOOP("Builds", "Include Manuscript Notes"),
142
151
  "text.includeKeywords": QT_TRANSLATE_NOOP("Builds", "Include Keywords"),
143
152
  "text.includeBodyText": QT_TRANSLATE_NOOP("Builds", "Include Body Text"),
144
153
  "text.ignoredKeywords": QT_TRANSLATE_NOOP("Builds", "Ignore These Keywords"),
@@ -185,7 +194,6 @@ SETTINGS_LABELS = {
185
194
  }
186
195
 
187
196
  RENAMED = {
188
- "odt.addColours": "doc.addColours",
189
197
  "odt.pageHeader": "doc.pageHeader",
190
198
  "odt.pageCountOffset": "doc.pageCountOffset",
191
199
  }
@@ -226,9 +234,9 @@ class BuildSettings:
226
234
  @classmethod
227
235
  def fromDict(cls, data: dict) -> BuildSettings:
228
236
  """Create a build settings object from a dict."""
229
- cls = BuildSettings()
230
- cls.unpack(data)
231
- return cls
237
+ new = cls()
238
+ new.unpack(data)
239
+ return new
232
240
 
233
241
  ##
234
242
  # Properties
@@ -293,12 +301,12 @@ class BuildSettings:
293
301
  def getInt(self, key: str) -> int:
294
302
  """Type safe value access for integers."""
295
303
  value = self._settings.get(key, SETTINGS_TEMPLATE.get(key, (None, None))[1])
296
- return int(value) if isinstance(value, (int, float)) else 0
304
+ return int(value) if isinstance(value, int | float) else 0
297
305
 
298
306
  def getFloat(self, key: str) -> float:
299
307
  """Type safe value access for floats."""
300
308
  value = self._settings.get(key, SETTINGS_TEMPLATE.get(key, (None, None))[1])
301
- return float(value) if isinstance(value, (int, float)) else 0.0
309
+ return float(value) if isinstance(value, int | float) else 0.0
302
310
 
303
311
  ##
304
312
  # Setters
@@ -379,10 +387,10 @@ class BuildSettings:
379
387
  self._changed = True
380
388
  return
381
389
 
382
- def setValue(self, key: str, value: str | int | float | bool) -> None:
390
+ def setValue(self, key: str, value: T_BuildValue) -> None:
383
391
  """Set a specific value for a build setting."""
384
392
  if (d := SETTINGS_TEMPLATE.get(key)) and len(d) == 2 and isinstance(value, d[0]):
385
- self._changed = value != self._settings[key]
393
+ self._changed |= (value != self._settings[key])
386
394
  self._settings[key] = value
387
395
  return
388
396
 
@@ -503,7 +511,8 @@ class BuildSettings:
503
511
  self._settings = {k: v[1] for k, v in SETTINGS_TEMPLATE.items()}
504
512
  if isinstance(settings, dict):
505
513
  for key, value in settings.items():
506
- self.setValue(RENAMED.get(key, key), value)
514
+ if isinstance(key, str) and isinstance(value, T_BuildValue):
515
+ self.setValue(RENAMED.get(key, key), value)
507
516
 
508
517
  self._changed = False
509
518
 
@@ -512,11 +521,11 @@ class BuildSettings:
512
521
  @classmethod
513
522
  def duplicate(cls, source: BuildSettings) -> BuildSettings:
514
523
  """Make a copy of another build."""
515
- cls = BuildSettings()
516
- cls.unpack(source.pack())
517
- cls._uuid = str(uuid.uuid4())
518
- cls._name = f"{source.name} 2"
519
- return cls
524
+ new = cls()
525
+ new.unpack(source.pack())
526
+ new._uuid = str(uuid.uuid4())
527
+ new._name = f"{source.name} 2"
528
+ return new
520
529
 
521
530
 
522
531
  class BuildCollection: