novelWriter 2.6.3__py3-none-any.whl → 2.7b1__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 (321) hide show
  1. novelwriter/__init__.py +84 -74
  2. novelwriter/assets/i18n/project_en_GB.json +1 -0
  3. novelwriter/assets/icons/font_awesome.icons +109 -0
  4. novelwriter/assets/icons/material_filled_bold.icons +109 -0
  5. novelwriter/assets/icons/material_filled_normal.icons +109 -0
  6. novelwriter/assets/icons/material_filled_thin.icons +109 -0
  7. novelwriter/assets/icons/material_rounded_bold.icons +109 -0
  8. novelwriter/assets/icons/material_rounded_normal.icons +109 -0
  9. novelwriter/assets/icons/material_rounded_thin.icons +109 -0
  10. novelwriter/assets/icons/remix_filled.icons +108 -0
  11. novelwriter/assets/icons/remix_outline.icons +108 -0
  12. novelwriter/assets/manual.pdf +0 -0
  13. novelwriter/assets/{manual_fr_FR.pdf → manual_fr.pdf} +0 -0
  14. novelwriter/assets/sample.zip +0 -0
  15. novelwriter/assets/syntax/cyberpunk_night.conf +1 -1
  16. novelwriter/assets/text/credits_en.htm +6 -6
  17. novelwriter/assets/themes/cyberpunk_night.conf +23 -7
  18. novelwriter/assets/themes/default_dark.conf +20 -4
  19. novelwriter/assets/themes/default_light.conf +21 -5
  20. novelwriter/assets/themes/dracula.conf +20 -4
  21. novelwriter/assets/themes/solarized_dark.conf +24 -8
  22. novelwriter/assets/themes/solarized_light.conf +22 -6
  23. novelwriter/common.py +33 -26
  24. novelwriter/config.py +118 -127
  25. novelwriter/constants.py +50 -36
  26. novelwriter/core/buildsettings.py +23 -16
  27. novelwriter/core/coretools.py +11 -7
  28. novelwriter/core/docbuild.py +19 -13
  29. novelwriter/core/document.py +2 -2
  30. novelwriter/core/index.py +142 -432
  31. novelwriter/core/indexdata.py +403 -0
  32. novelwriter/core/item.py +35 -28
  33. novelwriter/core/itemmodel.py +27 -26
  34. novelwriter/core/novelmodel.py +223 -0
  35. novelwriter/core/options.py +1 -1
  36. novelwriter/core/project.py +10 -11
  37. novelwriter/core/projectdata.py +5 -5
  38. novelwriter/core/projectxml.py +1 -1
  39. novelwriter/core/sessions.py +3 -2
  40. novelwriter/core/spellcheck.py +4 -3
  41. novelwriter/core/status.py +12 -15
  42. novelwriter/core/storage.py +1 -1
  43. novelwriter/core/tree.py +46 -8
  44. novelwriter/dialogs/about.py +19 -22
  45. novelwriter/dialogs/docmerge.py +21 -23
  46. novelwriter/dialogs/docsplit.py +20 -23
  47. novelwriter/dialogs/editlabel.py +9 -13
  48. novelwriter/dialogs/preferences.py +111 -48
  49. novelwriter/dialogs/projectsettings.py +48 -54
  50. novelwriter/dialogs/quotes.py +14 -19
  51. novelwriter/dialogs/wordlist.py +25 -30
  52. novelwriter/enum.py +8 -0
  53. novelwriter/error.py +16 -16
  54. novelwriter/extensions/configlayout.py +18 -18
  55. novelwriter/extensions/eventfilters.py +9 -5
  56. novelwriter/extensions/modified.py +34 -15
  57. novelwriter/extensions/novelselector.py +18 -5
  58. novelwriter/extensions/pagedsidebar.py +39 -49
  59. novelwriter/extensions/progressbars.py +10 -8
  60. novelwriter/extensions/statusled.py +6 -13
  61. novelwriter/extensions/switch.py +19 -30
  62. novelwriter/extensions/switchbox.py +7 -3
  63. novelwriter/extensions/versioninfo.py +4 -4
  64. novelwriter/formats/shared.py +1 -1
  65. novelwriter/formats/todocx.py +14 -10
  66. novelwriter/formats/tohtml.py +7 -5
  67. novelwriter/formats/tokenizer.py +36 -33
  68. novelwriter/formats/tomarkdown.py +6 -2
  69. novelwriter/formats/toodt.py +27 -22
  70. novelwriter/formats/toqdoc.py +19 -14
  71. novelwriter/formats/toraw.py +6 -2
  72. novelwriter/gui/doceditor.py +216 -265
  73. novelwriter/gui/dochighlight.py +46 -45
  74. novelwriter/gui/docviewer.py +102 -104
  75. novelwriter/gui/docviewerpanel.py +47 -51
  76. novelwriter/gui/editordocument.py +8 -5
  77. novelwriter/gui/itemdetails.py +11 -14
  78. novelwriter/gui/mainmenu.py +146 -145
  79. novelwriter/gui/noveltree.py +239 -405
  80. novelwriter/gui/outline.py +133 -72
  81. novelwriter/gui/projtree.py +138 -132
  82. novelwriter/gui/search.py +33 -31
  83. novelwriter/gui/sidebar.py +13 -18
  84. novelwriter/gui/statusbar.py +13 -15
  85. novelwriter/gui/theme.py +533 -430
  86. novelwriter/guimain.py +27 -29
  87. novelwriter/shared.py +32 -23
  88. novelwriter/text/comments.py +70 -0
  89. novelwriter/text/patterns.py +4 -4
  90. novelwriter/tools/dictionaries.py +20 -29
  91. novelwriter/tools/lipsum.py +16 -17
  92. novelwriter/tools/manusbuild.py +39 -42
  93. novelwriter/tools/manuscript.py +101 -114
  94. novelwriter/tools/manussettings.py +78 -83
  95. novelwriter/tools/noveldetails.py +51 -64
  96. novelwriter/tools/welcome.py +56 -75
  97. novelwriter/tools/writingstats.py +44 -57
  98. novelwriter/types.py +5 -7
  99. {novelWriter-2.6.3.dist-info → novelwriter-2.7b1.dist-info}/METADATA +6 -6
  100. novelwriter-2.7b1.dist-info/RECORD +159 -0
  101. {novelWriter-2.6.3.dist-info → novelwriter-2.7b1.dist-info}/WHEEL +1 -1
  102. novelWriter-2.6.3.dist-info/RECORD +0 -363
  103. novelwriter/assets/icons/typicons_dark/README.md +0 -29
  104. novelwriter/assets/icons/typicons_dark/icons.conf +0 -134
  105. novelwriter/assets/icons/typicons_dark/mixed_copy.svg +0 -4
  106. novelwriter/assets/icons/typicons_dark/mixed_document-chapter.svg +0 -12
  107. novelwriter/assets/icons/typicons_dark/mixed_document-new.svg +0 -6
  108. novelwriter/assets/icons/typicons_dark/mixed_document-note.svg +0 -12
  109. novelwriter/assets/icons/typicons_dark/mixed_document-scene.svg +0 -12
  110. novelwriter/assets/icons/typicons_dark/mixed_document-section.svg +0 -12
  111. novelwriter/assets/icons/typicons_dark/mixed_document-title.svg +0 -12
  112. novelwriter/assets/icons/typicons_dark/mixed_edit.svg +0 -4
  113. novelwriter/assets/icons/typicons_dark/mixed_import.svg +0 -5
  114. novelwriter/assets/icons/typicons_dark/mixed_input-checked.svg +0 -5
  115. novelwriter/assets/icons/typicons_dark/mixed_input-none.svg +0 -5
  116. novelwriter/assets/icons/typicons_dark/mixed_input-unchecked.svg +0 -5
  117. novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +0 -6
  118. novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +0 -6
  119. novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +0 -6
  120. novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +0 -6
  121. novelwriter/assets/icons/typicons_dark/mixed_search-replace.svg +0 -6
  122. novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +0 -6
  123. novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +0 -6
  124. novelwriter/assets/icons/typicons_dark/nw_deco-h0.svg +0 -4
  125. novelwriter/assets/icons/typicons_dark/nw_deco-h1.svg +0 -4
  126. novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +0 -4
  127. novelwriter/assets/icons/typicons_dark/nw_deco-h2.svg +0 -4
  128. novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +0 -4
  129. novelwriter/assets/icons/typicons_dark/nw_deco-h3.svg +0 -4
  130. novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +0 -4
  131. novelwriter/assets/icons/typicons_dark/nw_deco-h4.svg +0 -4
  132. novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +0 -4
  133. novelwriter/assets/icons/typicons_dark/nw_deco-noveltree-more.svg +0 -4
  134. novelwriter/assets/icons/typicons_dark/nw_font.svg +0 -4
  135. novelwriter/assets/icons/typicons_dark/nw_panel.svg +0 -4
  136. novelwriter/assets/icons/typicons_dark/nw_quote.svg +0 -4
  137. novelwriter/assets/icons/typicons_dark/nw_search-case.svg +0 -4
  138. novelwriter/assets/icons/typicons_dark/nw_search-preserve.svg +0 -4
  139. novelwriter/assets/icons/typicons_dark/nw_search-regex.svg +0 -4
  140. novelwriter/assets/icons/typicons_dark/nw_search-word.svg +0 -4
  141. novelwriter/assets/icons/typicons_dark/nw_tb-bold-md.svg +0 -4
  142. novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +0 -6
  143. novelwriter/assets/icons/typicons_dark/nw_tb-italic-md.svg +0 -4
  144. novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +0 -6
  145. novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +0 -7
  146. novelwriter/assets/icons/typicons_dark/nw_tb-strike-md.svg +0 -4
  147. novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +0 -6
  148. novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +0 -7
  149. novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +0 -7
  150. novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +0 -7
  151. novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +0 -5
  152. novelwriter/assets/icons/typicons_dark/typ_arrow-down-thick-grey.svg +0 -4
  153. novelwriter/assets/icons/typicons_dark/typ_arrow-forward.svg +0 -4
  154. novelwriter/assets/icons/typicons_dark/typ_arrow-maximise.svg +0 -4
  155. novelwriter/assets/icons/typicons_dark/typ_arrow-minimise.svg +0 -4
  156. novelwriter/assets/icons/typicons_dark/typ_arrow-repeat-grey.svg +0 -4
  157. novelwriter/assets/icons/typicons_dark/typ_book-grey.svg +0 -4
  158. novelwriter/assets/icons/typicons_dark/typ_book.svg +0 -6
  159. novelwriter/assets/icons/typicons_dark/typ_bookmark.svg +0 -4
  160. novelwriter/assets/icons/typicons_dark/typ_calendar.svg +0 -4
  161. novelwriter/assets/icons/typicons_dark/typ_cancel-grey.svg +0 -4
  162. novelwriter/assets/icons/typicons_dark/typ_cancel.svg +0 -4
  163. novelwriter/assets/icons/typicons_dark/typ_chart-bar-grey.svg +0 -4
  164. novelwriter/assets/icons/typicons_dark/typ_chevron-down.svg +0 -4
  165. novelwriter/assets/icons/typicons_dark/typ_chevron-left.svg +0 -4
  166. novelwriter/assets/icons/typicons_dark/typ_chevron-right.svg +0 -4
  167. novelwriter/assets/icons/typicons_dark/typ_chevron-up.svg +0 -4
  168. novelwriter/assets/icons/typicons_dark/typ_cog.svg +0 -4
  169. novelwriter/assets/icons/typicons_dark/typ_delete-full.svg +0 -4
  170. novelwriter/assets/icons/typicons_dark/typ_delete.svg +0 -4
  171. novelwriter/assets/icons/typicons_dark/typ_directions-full.svg +0 -4
  172. novelwriter/assets/icons/typicons_dark/typ_document-add.svg +0 -4
  173. novelwriter/assets/icons/typicons_dark/typ_document-text.svg +0 -8
  174. novelwriter/assets/icons/typicons_dark/typ_document.svg +0 -4
  175. novelwriter/assets/icons/typicons_dark/typ_export-grey.svg +0 -4
  176. novelwriter/assets/icons/typicons_dark/typ_export.svg +0 -4
  177. novelwriter/assets/icons/typicons_dark/typ_eye.svg +0 -4
  178. novelwriter/assets/icons/typicons_dark/typ_flag.svg +0 -4
  179. novelwriter/assets/icons/typicons_dark/typ_folder-open.svg +0 -4
  180. novelwriter/assets/icons/typicons_dark/typ_folder.svg +0 -5
  181. novelwriter/assets/icons/typicons_dark/typ_globe-grey.svg +0 -4
  182. novelwriter/assets/icons/typicons_dark/typ_key.svg +0 -4
  183. novelwriter/assets/icons/typicons_dark/typ_lightbulb-full.svg +0 -4
  184. novelwriter/assets/icons/typicons_dark/typ_location.svg +0 -4
  185. novelwriter/assets/icons/typicons_dark/typ_media-pause-grey.svg +0 -4
  186. novelwriter/assets/icons/typicons_dark/typ_media-record-outline.svg +0 -4
  187. novelwriter/assets/icons/typicons_dark/typ_media-record.svg +0 -4
  188. novelwriter/assets/icons/typicons_dark/typ_minus.svg +0 -4
  189. novelwriter/assets/icons/typicons_dark/typ_pencil.svg +0 -5
  190. novelwriter/assets/icons/typicons_dark/typ_pin-outline.svg +0 -4
  191. novelwriter/assets/icons/typicons_dark/typ_pin.svg +0 -4
  192. novelwriter/assets/icons/typicons_dark/typ_plus.svg +0 -4
  193. novelwriter/assets/icons/typicons_dark/typ_puzzle-outline.svg +0 -4
  194. novelwriter/assets/icons/typicons_dark/typ_puzzle.svg +0 -4
  195. novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +0 -4
  196. novelwriter/assets/icons/typicons_dark/typ_refresh.svg +0 -4
  197. novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +0 -4
  198. novelwriter/assets/icons/typicons_dark/typ_search.svg +0 -4
  199. novelwriter/assets/icons/typicons_dark/typ_star.svg +0 -4
  200. novelwriter/assets/icons/typicons_dark/typ_stopwatch-grey.svg +0 -4
  201. novelwriter/assets/icons/typicons_dark/typ_th-dot-menu.svg +0 -4
  202. novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +0 -4
  203. novelwriter/assets/icons/typicons_dark/typ_th-list-grey.svg +0 -4
  204. novelwriter/assets/icons/typicons_dark/typ_th-list.svg +0 -9
  205. novelwriter/assets/icons/typicons_dark/typ_times.svg +0 -4
  206. novelwriter/assets/icons/typicons_dark/typ_trash.svg +0 -5
  207. novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +0 -4
  208. novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +0 -4
  209. novelwriter/assets/icons/typicons_dark/typ_user.svg +0 -5
  210. novelwriter/assets/icons/typicons_dark/typ_warning-full.svg +0 -4
  211. novelwriter/assets/icons/typicons_light/README.md +0 -29
  212. novelwriter/assets/icons/typicons_light/icons.conf +0 -134
  213. novelwriter/assets/icons/typicons_light/mixed_copy.svg +0 -4
  214. novelwriter/assets/icons/typicons_light/mixed_document-chapter.svg +0 -12
  215. novelwriter/assets/icons/typicons_light/mixed_document-new.svg +0 -6
  216. novelwriter/assets/icons/typicons_light/mixed_document-note.svg +0 -12
  217. novelwriter/assets/icons/typicons_light/mixed_document-scene.svg +0 -12
  218. novelwriter/assets/icons/typicons_light/mixed_document-section.svg +0 -12
  219. novelwriter/assets/icons/typicons_light/mixed_document-title.svg +0 -12
  220. novelwriter/assets/icons/typicons_light/mixed_edit.svg +0 -4
  221. novelwriter/assets/icons/typicons_light/mixed_import.svg +0 -5
  222. novelwriter/assets/icons/typicons_light/mixed_input-checked.svg +0 -5
  223. novelwriter/assets/icons/typicons_light/mixed_input-none.svg +0 -5
  224. novelwriter/assets/icons/typicons_light/mixed_input-unchecked.svg +0 -5
  225. novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +0 -6
  226. novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +0 -6
  227. novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +0 -6
  228. novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +0 -6
  229. novelwriter/assets/icons/typicons_light/mixed_search-replace.svg +0 -6
  230. novelwriter/assets/icons/typicons_light/mixed_size-height.svg +0 -6
  231. novelwriter/assets/icons/typicons_light/mixed_size-width.svg +0 -6
  232. novelwriter/assets/icons/typicons_light/nw_deco-h0.svg +0 -4
  233. novelwriter/assets/icons/typicons_light/nw_deco-h1.svg +0 -4
  234. novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +0 -4
  235. novelwriter/assets/icons/typicons_light/nw_deco-h2.svg +0 -4
  236. novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +0 -4
  237. novelwriter/assets/icons/typicons_light/nw_deco-h3.svg +0 -4
  238. novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +0 -4
  239. novelwriter/assets/icons/typicons_light/nw_deco-h4.svg +0 -4
  240. novelwriter/assets/icons/typicons_light/nw_deco-note.svg +0 -4
  241. novelwriter/assets/icons/typicons_light/nw_deco-noveltree-more.svg +0 -4
  242. novelwriter/assets/icons/typicons_light/nw_font.svg +0 -4
  243. novelwriter/assets/icons/typicons_light/nw_panel.svg +0 -4
  244. novelwriter/assets/icons/typicons_light/nw_quote.svg +0 -4
  245. novelwriter/assets/icons/typicons_light/nw_search-case.svg +0 -4
  246. novelwriter/assets/icons/typicons_light/nw_search-preserve.svg +0 -4
  247. novelwriter/assets/icons/typicons_light/nw_search-regex.svg +0 -4
  248. novelwriter/assets/icons/typicons_light/nw_search-word.svg +0 -4
  249. novelwriter/assets/icons/typicons_light/nw_tb-bold-md.svg +0 -4
  250. novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +0 -6
  251. novelwriter/assets/icons/typicons_light/nw_tb-italic-md.svg +0 -4
  252. novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +0 -6
  253. novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +0 -7
  254. novelwriter/assets/icons/typicons_light/nw_tb-strike-md.svg +0 -4
  255. novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +0 -6
  256. novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +0 -7
  257. novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +0 -7
  258. novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +0 -7
  259. novelwriter/assets/icons/typicons_light/nw_toolbar.svg +0 -5
  260. novelwriter/assets/icons/typicons_light/typ_arrow-down-thick-grey.svg +0 -4
  261. novelwriter/assets/icons/typicons_light/typ_arrow-forward.svg +0 -4
  262. novelwriter/assets/icons/typicons_light/typ_arrow-maximise.svg +0 -4
  263. novelwriter/assets/icons/typicons_light/typ_arrow-minimise.svg +0 -4
  264. novelwriter/assets/icons/typicons_light/typ_arrow-repeat-grey.svg +0 -4
  265. novelwriter/assets/icons/typicons_light/typ_book-grey.svg +0 -4
  266. novelwriter/assets/icons/typicons_light/typ_book.svg +0 -6
  267. novelwriter/assets/icons/typicons_light/typ_bookmark.svg +0 -4
  268. novelwriter/assets/icons/typicons_light/typ_calendar.svg +0 -4
  269. novelwriter/assets/icons/typicons_light/typ_cancel-grey.svg +0 -4
  270. novelwriter/assets/icons/typicons_light/typ_cancel.svg +0 -4
  271. novelwriter/assets/icons/typicons_light/typ_chart-bar-grey.svg +0 -4
  272. novelwriter/assets/icons/typicons_light/typ_chevron-down.svg +0 -4
  273. novelwriter/assets/icons/typicons_light/typ_chevron-left.svg +0 -4
  274. novelwriter/assets/icons/typicons_light/typ_chevron-right.svg +0 -4
  275. novelwriter/assets/icons/typicons_light/typ_chevron-up.svg +0 -4
  276. novelwriter/assets/icons/typicons_light/typ_cog.svg +0 -4
  277. novelwriter/assets/icons/typicons_light/typ_delete-full.svg +0 -4
  278. novelwriter/assets/icons/typicons_light/typ_delete.svg +0 -4
  279. novelwriter/assets/icons/typicons_light/typ_directions-full.svg +0 -4
  280. novelwriter/assets/icons/typicons_light/typ_document-add.svg +0 -4
  281. novelwriter/assets/icons/typicons_light/typ_document-text.svg +0 -5
  282. novelwriter/assets/icons/typicons_light/typ_document.svg +0 -4
  283. novelwriter/assets/icons/typicons_light/typ_export-grey.svg +0 -4
  284. novelwriter/assets/icons/typicons_light/typ_export.svg +0 -4
  285. novelwriter/assets/icons/typicons_light/typ_eye.svg +0 -4
  286. novelwriter/assets/icons/typicons_light/typ_flag.svg +0 -4
  287. novelwriter/assets/icons/typicons_light/typ_folder-open.svg +0 -4
  288. novelwriter/assets/icons/typicons_light/typ_folder.svg +0 -5
  289. novelwriter/assets/icons/typicons_light/typ_globe-grey.svg +0 -4
  290. novelwriter/assets/icons/typicons_light/typ_key.svg +0 -4
  291. novelwriter/assets/icons/typicons_light/typ_lightbulb-full.svg +0 -4
  292. novelwriter/assets/icons/typicons_light/typ_location.svg +0 -4
  293. novelwriter/assets/icons/typicons_light/typ_media-pause-grey.svg +0 -4
  294. novelwriter/assets/icons/typicons_light/typ_media-record-outline.svg +0 -4
  295. novelwriter/assets/icons/typicons_light/typ_media-record.svg +0 -4
  296. novelwriter/assets/icons/typicons_light/typ_minus.svg +0 -4
  297. novelwriter/assets/icons/typicons_light/typ_pencil.svg +0 -5
  298. novelwriter/assets/icons/typicons_light/typ_pin-outline.svg +0 -4
  299. novelwriter/assets/icons/typicons_light/typ_pin.svg +0 -4
  300. novelwriter/assets/icons/typicons_light/typ_plus.svg +0 -4
  301. novelwriter/assets/icons/typicons_light/typ_puzzle-outline.svg +0 -4
  302. novelwriter/assets/icons/typicons_light/typ_puzzle.svg +0 -4
  303. novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +0 -4
  304. novelwriter/assets/icons/typicons_light/typ_refresh.svg +0 -4
  305. novelwriter/assets/icons/typicons_light/typ_search-grey.svg +0 -4
  306. novelwriter/assets/icons/typicons_light/typ_search.svg +0 -4
  307. novelwriter/assets/icons/typicons_light/typ_star.svg +0 -4
  308. novelwriter/assets/icons/typicons_light/typ_stopwatch-grey.svg +0 -4
  309. novelwriter/assets/icons/typicons_light/typ_th-dot-menu.svg +0 -4
  310. novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +0 -4
  311. novelwriter/assets/icons/typicons_light/typ_th-list-grey.svg +0 -4
  312. novelwriter/assets/icons/typicons_light/typ_th-list.svg +0 -9
  313. novelwriter/assets/icons/typicons_light/typ_times.svg +0 -4
  314. novelwriter/assets/icons/typicons_light/typ_trash.svg +0 -5
  315. novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +0 -4
  316. novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +0 -4
  317. novelwriter/assets/icons/typicons_light/typ_user.svg +0 -5
  318. novelwriter/assets/icons/typicons_light/typ_warning-full.svg +0 -4
  319. {novelWriter-2.6.3.dist-info → novelwriter-2.7b1.dist-info}/entry_points.txt +0 -0
  320. {novelWriter-2.6.3.dist-info → novelwriter-2.7b1.dist-info/licenses}/LICENSE.md +0 -0
  321. {novelWriter-2.6.3.dist-info → novelwriter-2.7b1.dist-info}/top_level.txt +0 -0
@@ -31,9 +31,9 @@ from time import sleep
31
31
  from urllib.error import HTTPError
32
32
  from urllib.request import Request, urlopen
33
33
 
34
- from PyQt5.QtCore import QObject, QRunnable, QUrl, pyqtSignal, pyqtSlot
35
- from PyQt5.QtGui import QDesktopServices
36
- from PyQt5.QtWidgets import QLabel, QVBoxLayout, QWidget
34
+ from PyQt6.QtCore import QObject, QRunnable, QUrl, pyqtSignal, pyqtSlot
35
+ from PyQt6.QtGui import QDesktopServices
36
+ from PyQt6.QtWidgets import QLabel, QVBoxLayout, QWidget
37
37
 
38
38
  from novelwriter import CONFIG, SHARED, __date__, __domain__, __version__
39
39
  from novelwriter.common import formatVersion
@@ -70,7 +70,7 @@ class VersionInfoWidget(QWidget):
70
70
  self._layout = QVBoxLayout()
71
71
  self._layout.addWidget(self._lblInfo)
72
72
  self._layout.addWidget(self._lblRelease)
73
- self._layout.setSpacing(CONFIG.pxInt(2))
73
+ self._layout.setSpacing(2)
74
74
  self._layout.setContentsMargins(0, 0, 0, 0)
75
75
 
76
76
  self.setLayout(self._layout)
@@ -27,7 +27,7 @@ import re
27
27
 
28
28
  from enum import Flag, IntEnum
29
29
 
30
- from PyQt5.QtGui import QColor
30
+ from PyQt6.QtGui import QColor
31
31
 
32
32
  ESCAPES = {r"\*": "*", r"\~": "~", r"\_": "_", r"\[": "[", r"\]": "]", r"\ ": ""}
33
33
  RX_ESC = re.compile("|".join([re.escape(k) for k in ESCAPES.keys()]), flags=re.DOTALL)
@@ -29,21 +29,25 @@ import re
29
29
  import xml.etree.ElementTree as ET
30
30
 
31
31
  from datetime import datetime
32
- from pathlib import Path
33
- from typing import NamedTuple
32
+ from typing import TYPE_CHECKING, NamedTuple
34
33
  from zipfile import ZIP_DEFLATED, ZipFile
35
34
 
36
- from PyQt5.QtCore import QMargins, QSize
37
- from PyQt5.QtGui import QColor
35
+ from PyQt6.QtCore import QMargins, QSize
38
36
 
39
37
  from novelwriter import __version__
40
38
  from novelwriter.common import firstFloat, xmlElement, xmlSubElem
41
39
  from novelwriter.constants import nwHeadFmt, nwStyles
42
- from novelwriter.core.project import NWProject
43
40
  from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt
44
41
  from novelwriter.formats.tokenizer import Tokenizer
45
42
  from novelwriter.types import QtHexRgb
46
43
 
44
+ if TYPE_CHECKING:
45
+ from pathlib import Path
46
+
47
+ from PyQt6.QtGui import QColor
48
+
49
+ from novelwriter.core.project import NWProject
50
+
47
51
  logger = logging.getLogger(__name__)
48
52
 
49
53
  # RegEx
@@ -212,9 +216,9 @@ class ToDocX(Tokenizer):
212
216
  self._pageMargins = QMargins(_mmToSz(left), _mmToSz(top), _mmToSz(right), _mmToSz(bottom))
213
217
  return
214
218
 
215
- def setHeaderFormat(self, format: str, offset: int) -> None:
219
+ def setHeaderFormat(self, value: str, offset: int) -> None:
216
220
  """Set the document header format."""
217
- self._headerFormat = format.strip()
221
+ self._headerFormat = value.strip()
218
222
  self._pageOffset = offset
219
223
  return
220
224
 
@@ -1052,9 +1056,9 @@ class ToDocX(Tokenizer):
1052
1056
  class DocXParagraph:
1053
1057
 
1054
1058
  __slots__ = (
1055
- "_content", "_style", "_textAlign",
1056
- "_topMargin", "_bottomMargin", "_leftMargin", "_rightMargin",
1057
- "_indentFirst", "_breakBefore", "_breakAfter", "_footnoteRef",
1059
+ "_bottomMargin", "_breakAfter", "_breakBefore", "_content",
1060
+ "_footnoteRef", "_indentFirst", "_leftMargin", "_rightMargin",
1061
+ "_style", "_textAlign", "_topMargin",
1058
1062
  )
1059
1063
 
1060
1064
  def __init__(self) -> None:
@@ -26,16 +26,20 @@ from __future__ import annotations
26
26
  import json
27
27
  import logging
28
28
 
29
- from pathlib import Path
30
29
  from time import time
30
+ from typing import TYPE_CHECKING
31
31
 
32
32
  from novelwriter.common import formatTimeStamp
33
33
  from novelwriter.constants import nwHtmlUnicode, nwStyles
34
- from novelwriter.core.project import NWProject
35
34
  from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt, stripEscape
36
35
  from novelwriter.formats.tokenizer import Tokenizer
37
36
  from novelwriter.types import FONT_STYLE, FONT_WEIGHTS, QtHexRgb
38
37
 
38
+ if TYPE_CHECKING:
39
+ from pathlib import Path
40
+
41
+ from novelwriter.core.project import NWProject
42
+
39
43
  logger = logging.getLogger(__name__)
40
44
 
41
45
  # Each opener tag, with the id of its corresponding closer and tag format
@@ -311,10 +315,8 @@ class ToHtml(Tokenizer):
311
315
 
312
316
  def replaceTabs(self, nSpaces: int = 8, spaceChar: str = " ") -> None:
313
317
  """Replace tabs with spaces in the html."""
314
- pages = []
315
318
  tabSpace = spaceChar*nSpaces
316
- for aLine in self._pages:
317
- pages.append(aLine.replace("\t", tabSpace))
319
+ pages = [aLine.replace("\t", tabSpace) for aLine in self._pages]
318
320
  self._pages = pages
319
321
  return
320
322
 
@@ -28,11 +28,10 @@ import logging
28
28
  import re
29
29
 
30
30
  from abc import ABC, abstractmethod
31
- from pathlib import Path
32
- from typing import NamedTuple
31
+ from typing import TYPE_CHECKING, NamedTuple
33
32
 
34
- from PyQt5.QtCore import QLocale
35
- from PyQt5.QtGui import QColor, QFont
33
+ from PyQt6.QtCore import QLocale
34
+ from PyQt6.QtGui import QColor, QFont
36
35
 
37
36
  from novelwriter import CONFIG
38
37
  from novelwriter.common import checkInt, fontMatcher, numberToRoman
@@ -40,14 +39,18 @@ from novelwriter.constants import (
40
39
  nwHeadFmt, nwKeyWords, nwLabels, nwShortcode, nwStats, nwStyles, nwUnicode,
41
40
  trConst
42
41
  )
43
- from novelwriter.core.index import processComment
44
- from novelwriter.core.project import NWProject
45
42
  from novelwriter.enum import nwComment, nwItemLayout
46
43
  from novelwriter.formats.shared import (
47
44
  BlockFmt, BlockTyp, T_Block, T_Formats, T_Note, TextDocumentTheme, TextFmt
48
45
  )
46
+ from novelwriter.text.comments import processComment
49
47
  from novelwriter.text.patterns import REGEX_PATTERNS, DialogParser
50
48
 
49
+ if TYPE_CHECKING:
50
+ from pathlib import Path
51
+
52
+ from novelwriter.core.project import NWProject
53
+
51
54
  logger = logging.getLogger(__name__)
52
55
 
53
56
 
@@ -61,18 +64,18 @@ class ComStyle(NamedTuple):
61
64
  COMMENT_STYLE = {
62
65
  nwComment.PLAIN: ComStyle("Comment", "comment", "comment"),
63
66
  nwComment.IGNORE: ComStyle(),
64
- nwComment.SYNOPSIS: ComStyle("Synopsis", "modifier", "synopsis"),
65
- nwComment.SHORT: ComStyle("Short Description", "modifier", "synopsis"),
67
+ nwComment.SYNOPSIS: ComStyle("Synopsis", "modifier", "note"),
68
+ nwComment.SHORT: ComStyle("Short Description", "modifier", "note"),
66
69
  nwComment.NOTE: ComStyle("Note", "modifier", "note"),
67
70
  nwComment.FOOTNOTE: ComStyle("", "modifier", "note"),
68
71
  nwComment.COMMENT: ComStyle(),
69
- nwComment.STORY: ComStyle("", "modifier", "note"),
72
+ nwComment.STORY: ComStyle("Story Structure", "modifier", "note"),
70
73
  }
71
74
  HEADINGS = [
72
75
  BlockTyp.TITLE, BlockTyp.PART, BlockTyp.HEAD1,
73
76
  BlockTyp.HEAD2, BlockTyp.HEAD3, BlockTyp.HEAD4,
74
77
  ]
75
- SKIP_INDENT = HEADINGS + [BlockTyp.SEP, BlockTyp.SKIP]
78
+ SKIP_INDENT = [*HEADINGS, BlockTyp.SEP, BlockTyp.SKIP]
76
79
  B_EMPTY: T_Block = (BlockTyp.EMPTY, "", "", [], BlockFmt.NONE)
77
80
 
78
81
 
@@ -118,14 +121,16 @@ class Tokenizer(ABC):
118
121
  self._indentFirst = False # Indent first paragraph
119
122
  self._doJustify = False # Justify text
120
123
  self._doBodyText = True # Include body text
121
- self._doSynopsis = False # Also process synopsis comments
122
- self._doComments = False # Also process comments
124
+ self._doComments = set() # Comment styles to allow
123
125
  self._doKeywords = False # Also process keywords like tags and references
124
126
  self._keepBreaks = True # Keep line breaks in paragraphs
125
127
  self._defaultAlign = "left" # The default text alignment
126
128
 
127
129
  self._skipKeywords: set[str] = set() # Keywords to ignore
128
130
 
131
+ # Defaults
132
+ self._doComments.add(nwComment.FOOTNOTE)
133
+
129
134
  # Other Setting
130
135
  self._theme = TextDocumentTheme()
131
136
  self._classes: dict[str, QColor] = {}
@@ -393,14 +398,12 @@ class Tokenizer(ABC):
393
398
  self._doBodyText = state
394
399
  return
395
400
 
396
- def setSynopsis(self, state: bool) -> None:
397
- """Include synopsis comments in build."""
398
- self._doSynopsis = state
399
- return
400
-
401
- def setComments(self, state: bool) -> None:
402
- """Include comments in build."""
403
- self._doComments = state
401
+ def setCommentType(self, comment: nwComment, state: bool) -> None:
402
+ """Toggle the inclusion og certain comment types."""
403
+ if state:
404
+ self._doComments.add(comment)
405
+ else:
406
+ self._doComments.discard(comment)
404
407
  return
405
408
 
406
409
  def setKeywords(self, state: bool) -> None:
@@ -437,7 +440,7 @@ class Tokenizer(ABC):
437
440
  def initDocument(self) -> None:
438
441
  """Initialise data after settings."""
439
442
  self._classes["modifier"] = self._theme.modifier
440
- self._classes["synopsis"] = self._theme.note
443
+ self._classes["note"] = self._theme.note
441
444
  self._classes["comment"] = self._theme.comment
442
445
  self._classes["dialog"] = self._theme.dialog
443
446
  self._classes["altdialog"] = self._theme.altdialog
@@ -604,15 +607,15 @@ class Tokenizer(ABC):
604
607
  continue
605
608
 
606
609
  cStyle, cKey, cText, _, _ = processComment(aLine)
607
- if cStyle in (nwComment.SYNOPSIS, nwComment.SHORT) and not self._doSynopsis:
608
- continue
609
- if cStyle == nwComment.PLAIN and not self._doComments:
610
+ if cStyle not in self._doComments:
610
611
  continue
611
612
 
612
613
  if doJustify and not tStyle & BlockFmt.ALIGNED:
613
614
  tStyle |= BlockFmt.JUSTIFY
614
615
 
615
- if cStyle in (nwComment.SYNOPSIS, nwComment.SHORT, nwComment.PLAIN):
616
+ if cStyle in (
617
+ nwComment.SYNOPSIS, nwComment.SHORT, nwComment.PLAIN, nwComment.STORY
618
+ ):
616
619
  bStyle = COMMENT_STYLE[cStyle]
617
620
  tLine, tFmt = self._formatComment(bStyle, cKey, cText)
618
621
  tBlocks.append((
@@ -651,7 +654,7 @@ class Tokenizer(ABC):
651
654
  tText = aLine[2:].strip()
652
655
  tType = BlockTyp.HEAD1 if isPlain else BlockTyp.TITLE
653
656
  sHide = self._hidePart if isPlain else False
654
- if not (isPlain or isNovel and sHide):
657
+ if not (isPlain or (isNovel and sHide)):
655
658
  tStyle |= self._titleStyle
656
659
  if isNovel:
657
660
  tType = BlockTyp.PART if isPlain else BlockTyp.TITLE
@@ -1034,10 +1037,12 @@ class Tokenizer(ABC):
1034
1037
 
1035
1038
  def _formatComment(self, style: ComStyle, key: str, text: str) -> tuple[str, T_Formats]:
1036
1039
  """Apply formatting to comments and notes."""
1040
+ rFmt = []
1037
1041
  tTxt, tFmt = self._extractFormats(text)
1038
1042
  tFmt.insert(0, (0, TextFmt.COL_B, style.textClass))
1039
1043
  tFmt.append((len(tTxt), TextFmt.COL_E, ""))
1040
- if label := (self._localLookup(style.label) + (f" ({key})" if key else "")).strip():
1044
+ term = f" ({key.title()})" if key else ""
1045
+ if label := f"{self._localLookup(style.label)}{term}".strip():
1041
1046
  shift = len(label) + 2
1042
1047
  tTxt = f"{label}: {tTxt}"
1043
1048
  rFmt = [(0, TextFmt.B_B, ""), (shift - 1, TextFmt.B_E, "")]
@@ -1123,12 +1128,10 @@ class Tokenizer(ABC):
1123
1128
  temp.append((res.end(0), 0, TextFmt.HRF_E, ""))
1124
1129
 
1125
1130
  # Match Shortcodes
1126
- for res in REGEX_PATTERNS.shortcodePlain.finditer(text):
1127
- temp.append((
1128
- res.start(1), res.end(1),
1129
- self._shortCodeFmt.get(res.group(1).lower(), 0),
1130
- "",
1131
- ))
1131
+ temp.extend(
1132
+ (res.start(1), res.end(1), self._shortCodeFmt.get(res.group(1).lower(), 0), "")
1133
+ for res in REGEX_PATTERNS.shortcodePlain.finditer(text)
1134
+ )
1132
1135
 
1133
1136
  # Match Shortcode w/Values
1134
1137
  tHandle = self._handle or ""
@@ -25,13 +25,17 @@ from __future__ import annotations
25
25
 
26
26
  import logging
27
27
 
28
- from pathlib import Path
28
+ from typing import TYPE_CHECKING
29
29
 
30
30
  from novelwriter.constants import nwUnicode
31
- from novelwriter.core.project import NWProject
32
31
  from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt
33
32
  from novelwriter.formats.tokenizer import Tokenizer
34
33
 
34
+ if TYPE_CHECKING:
35
+ from pathlib import Path
36
+
37
+ from novelwriter.core.project import NWProject
38
+
35
39
  logger = logging.getLogger(__name__)
36
40
 
37
41
 
@@ -29,22 +29,26 @@ from __future__ import annotations
29
29
  import logging
30
30
  import xml.etree.ElementTree as ET
31
31
 
32
- from collections.abc import Sequence
33
32
  from datetime import datetime
34
33
  from hashlib import sha256
35
- from pathlib import Path
34
+ from typing import TYPE_CHECKING, Final
36
35
  from zipfile import ZIP_DEFLATED, ZipFile
37
36
 
38
- from PyQt5.QtGui import QColor, QFont
37
+ from PyQt6.QtGui import QColor, QFont
39
38
 
40
39
  from novelwriter import __version__
41
40
  from novelwriter.common import xmlElement, xmlIndent, xmlSubElem
42
41
  from novelwriter.constants import nwHeadFmt, nwStyles
43
- from novelwriter.core.project import NWProject
44
42
  from novelwriter.formats.shared import BlockFmt, BlockTyp, TextFmt, stripEscape
45
43
  from novelwriter.formats.tokenizer import Tokenizer
46
44
  from novelwriter.types import FONT_STYLE, QtHexRgb
47
45
 
46
+ if TYPE_CHECKING:
47
+ from collections.abc import Sequence
48
+ from pathlib import Path
49
+
50
+ from novelwriter.core.project import NWProject
51
+
48
52
  logger = logging.getLogger(__name__)
49
53
 
50
54
  # Main XML NameSpaces
@@ -203,9 +207,9 @@ class ToOdt(Tokenizer):
203
207
  self._mDocRight = f"{right/10.0:.3f}cm"
204
208
  return
205
209
 
206
- def setHeaderFormat(self, format: str, offset: int) -> None:
210
+ def setHeaderFormat(self, value: str, offset: int) -> None:
207
211
  """Set the document header format."""
208
- self._headerFormat = format.strip()
212
+ self._headerFormat = value.strip()
209
213
  self._pageOffset = offset
210
214
  return
211
215
 
@@ -598,6 +602,7 @@ class ToOdt(Tokenizer):
598
602
  def _textStyle(self, hFmt: int, fClass: str = "") -> str:
599
603
  """Return a text style for a given style code."""
600
604
  tKey = str(hFmt)
605
+ color = None
601
606
  if fClass and (color := self._classes.get(fClass)):
602
607
  tKey = f"{tKey}:{fClass}"
603
608
  if tKey in self._autoText:
@@ -999,11 +1004,11 @@ class ODTParagraphStyle:
999
1004
  exporter. Only the used settings are exposed here to keep the class
1000
1005
  minimal and fast.
1001
1006
  """
1002
- VALID_ALIGN = ["start", "center", "end", "justify", "inside", "outside", "left", "right"]
1003
- VALID_BREAK = ["auto", "column", "page", "even-page", "odd-page", "inherit"]
1004
- VALID_LEVEL = ["1", "2", "3", "4"]
1005
- VALID_CLASS = ["text", "chapter", "extra"]
1006
- VALID_WEIGHT = ["normal", "bold"] + FONT_WEIGHT_NUM
1007
+ VALID_ALIGN: Final[list[str]] = ["start", "center", "end", "justify", "left", "right"]
1008
+ VALID_BREAK: Final[list[str]] = ["auto", "page", "even-page", "odd-page", "inherit"]
1009
+ VALID_LEVEL: Final[list[str]] = ["1", "2", "3", "4"]
1010
+ VALID_CLASS: Final[list[str]] = ["text", "chapter", "extra"]
1011
+ VALID_WEIGHT: Final[list[str]] = ["normal", "bold", *FONT_WEIGHT_NUM]
1007
1012
 
1008
1013
  def __init__(self, name: str) -> None:
1009
1014
 
@@ -1206,9 +1211,9 @@ class ODTParagraphStyle:
1206
1211
  def getID(self) -> str:
1207
1212
  """Generate a unique ID from the settings."""
1208
1213
  return sha256((
1209
- f"Paragraph:Main:{str(self._mAttr)}:"
1210
- f"Paragraph:Para:{str(self._pAttr)}:"
1211
- f"Paragraph:Text:{str(self._tAttr)}:"
1214
+ f"Paragraph:Main:{self._mAttr!s}:"
1215
+ f"Paragraph:Para:{self._pAttr!s}:"
1216
+ f"Paragraph:Text:{self._tAttr!s}:"
1212
1217
  ).encode()).hexdigest()
1213
1218
 
1214
1219
  def packXML(self, xParent: ET.Element) -> None:
@@ -1236,13 +1241,13 @@ class ODTTextStyle:
1236
1241
  Only the used settings are exposed here to keep the class minimal
1237
1242
  and fast.
1238
1243
  """
1239
- VALID_WEIGHT = ["normal", "bold"] + FONT_WEIGHT_NUM
1240
- VALID_STYLE = ["normal", "italic", "oblique"]
1241
- VALID_POS = ["super", "sub"]
1242
- VALID_LSTYLE = ["none", "solid"]
1243
- VALID_LTYPE = ["single", "double"]
1244
- VALID_LWIDTH = ["auto"]
1245
- VALID_LCOL = ["font-color"]
1244
+ VALID_WEIGHT: Final[list[str]] = ["normal", "bold", *FONT_WEIGHT_NUM]
1245
+ VALID_STYLE: Final[list[str]] = ["normal", "italic", "oblique"]
1246
+ VALID_POS: Final[list[str]] = ["super", "sub"]
1247
+ VALID_LSTYLE: Final[list[str]] = ["none", "solid"]
1248
+ VALID_LTYPE: Final[list[str]] = ["single", "double"]
1249
+ VALID_LWIDTH: Final[list[str]] = ["auto"]
1250
+ VALID_LCOL: Final[list[str]] = ["font-color"]
1246
1251
 
1247
1252
  def __init__(self, name: str) -> None:
1248
1253
  self._name = name
@@ -1508,7 +1513,7 @@ class XMLParagraph:
1508
1513
  errMsg = ""
1509
1514
  nMissed = len(self._rawTxt) - self._chrPos
1510
1515
  if nMissed != 0:
1511
- errMsg = "%d char(s) were not written: '%s'" % (nMissed, self._rawTxt)
1516
+ errMsg = f"{nMissed} char(s) were not written: '{self._rawTxt}'"
1512
1517
  return nMissed, errMsg
1513
1518
 
1514
1519
  ##
@@ -25,18 +25,17 @@ from __future__ import annotations
25
25
 
26
26
  import logging
27
27
 
28
- from pathlib import Path
28
+ from typing import TYPE_CHECKING
29
29
 
30
- from PyQt5.QtCore import QMarginsF, QSizeF
31
- from PyQt5.QtGui import (
32
- QColor, QFont, QFontDatabase, QPageSize, QTextBlockFormat, QTextCharFormat,
33
- QTextCursor, QTextDocument, QTextFrameFormat
30
+ from PyQt6.QtCore import QMarginsF, QSizeF
31
+ from PyQt6.QtGui import (
32
+ QColor, QFont, QFontDatabase, QPageLayout, QPageSize, QTextBlockFormat,
33
+ QTextCharFormat, QTextCursor, QTextDocument, QTextFrameFormat
34
34
  )
35
- from PyQt5.QtPrintSupport import QPrinter
35
+ from PyQt6.QtPrintSupport import QPrinter
36
36
 
37
37
  from novelwriter import __version__
38
38
  from novelwriter.constants import nwStyles, nwUnicode
39
- from novelwriter.core.project import NWProject
40
39
  from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt
41
40
  from novelwriter.formats.tokenizer import HEADINGS, Tokenizer
42
41
  from novelwriter.types import (
@@ -45,6 +44,11 @@ from novelwriter.types import (
45
44
  QtPropLineHeight, QtTransparent, QtVAlignNormal, QtVAlignSub, QtVAlignSuper
46
45
  )
47
46
 
47
+ if TYPE_CHECKING:
48
+ from pathlib import Path
49
+
50
+ from novelwriter.core.project import NWProject
51
+
48
52
  logger = logging.getLogger(__name__)
49
53
 
50
54
  T_TextStyle = tuple[QTextBlockFormat, QTextCharFormat]
@@ -129,10 +133,9 @@ class ToQTextDocument(Tokenizer):
129
133
  super().initDocument()
130
134
 
131
135
  if pdf:
132
- fontDB = QFontDatabase()
133
136
  family = self._textFont.family()
134
137
  style = self._textFont.styleName()
135
- self._dpi = 1200 if fontDB.isScalable(family, style) else 72
138
+ self._dpi = 1200 if QFontDatabase.isScalable(family, style) else 72
136
139
 
137
140
  self._document.setUndoRedoEnabled(False)
138
141
  self._document.blockSignals(True)
@@ -270,7 +273,6 @@ class ToQTextDocument(Tokenizer):
270
273
 
271
274
  def saveDocument(self, path: Path) -> None:
272
275
  """Save the document as a PDF file."""
273
- m = self._pageMargins
274
276
  logger.info("Writing PDF at %d DPI", self._dpi)
275
277
 
276
278
  printer = QPrinter(QPrinter.PrinterMode.HighResolution)
@@ -279,11 +281,13 @@ class ToQTextDocument(Tokenizer):
279
281
  printer.setResolution(self._dpi)
280
282
  printer.setOutputFormat(QPrinter.OutputFormat.PdfFormat)
281
283
  printer.setPageSize(self._pageSize)
282
- printer.setPageMargins(m.left(), m.top(), m.right(), m.bottom(), QPrinter.Unit.Millimeter)
284
+ printer.setPageMargins(self._pageMargins, QPageLayout.Unit.Millimeter)
283
285
  printer.setOutputFileName(str(path))
284
286
 
285
- self._document.documentLayout().setPaintDevice(printer)
286
- self._document.setPageSize(QSizeF(printer.pageRect().size()))
287
+ if layout := self._document.documentLayout():
288
+ layout.setPaintDevice(printer)
289
+
290
+ self._document.setPageSize(printer.pageRect(QPrinter.Unit.DevicePixel).size())
287
291
  self._document.print(printer)
288
292
 
289
293
  return
@@ -462,7 +466,8 @@ class ToQTextDocument(Tokenizer):
462
466
  cursor.insertFrame(fFmt)
463
467
  cursor.setBlockFormat(bFmt)
464
468
  cursor.insertText(self._project.localLookup("New Page"), cFmt)
465
- cursor.swap(self._document.rootFrame().lastCursorPosition())
469
+ if root := self._document.rootFrame():
470
+ cursor.swap(root.lastCursorPosition())
466
471
 
467
472
  return
468
473
 
@@ -26,13 +26,17 @@ from __future__ import annotations
26
26
  import json
27
27
  import logging
28
28
 
29
- from pathlib import Path
30
29
  from time import time
30
+ from typing import TYPE_CHECKING
31
31
 
32
32
  from novelwriter.common import formatTimeStamp
33
- from novelwriter.core.project import NWProject
34
33
  from novelwriter.formats.tokenizer import Tokenizer
35
34
 
35
+ if TYPE_CHECKING:
36
+ from pathlib import Path
37
+
38
+ from novelwriter.core.project import NWProject
39
+
36
40
  logger = logging.getLogger(__name__)
37
41
 
38
42