novelWriter 2.6.3__py3-none-any.whl → 2.7rc1__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 (325) hide show
  1. novelwriter/__init__.py +98 -75
  2. novelwriter/assets/i18n/project_en_GB.json +2 -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 +109 -0
  11. novelwriter/assets/icons/remix_outline.icons +109 -0
  12. novelwriter/assets/images/splash.png +0 -0
  13. novelwriter/assets/manual.pdf +0 -0
  14. novelwriter/assets/{manual_fr_FR.pdf → manual_fr.pdf} +0 -0
  15. novelwriter/assets/sample.zip +0 -0
  16. novelwriter/assets/syntax/cyberpunk_night.conf +1 -1
  17. novelwriter/assets/syntax/snazzy.conf +3 -3
  18. novelwriter/assets/text/credits_en.htm +6 -6
  19. novelwriter/assets/themes/cyberpunk_night.conf +23 -7
  20. novelwriter/assets/themes/default_dark.conf +20 -4
  21. novelwriter/assets/themes/default_light.conf +21 -5
  22. novelwriter/assets/themes/dracula.conf +20 -4
  23. novelwriter/assets/themes/snazzy.conf +48 -0
  24. novelwriter/assets/themes/solarized_dark.conf +24 -8
  25. novelwriter/assets/themes/solarized_light.conf +22 -6
  26. novelwriter/common.py +43 -27
  27. novelwriter/config.py +201 -139
  28. novelwriter/constants.py +67 -36
  29. novelwriter/core/buildsettings.py +25 -16
  30. novelwriter/core/coretools.py +52 -41
  31. novelwriter/core/docbuild.py +20 -13
  32. novelwriter/core/document.py +2 -2
  33. novelwriter/core/index.py +166 -432
  34. novelwriter/core/indexdata.py +406 -0
  35. novelwriter/core/item.py +50 -32
  36. novelwriter/core/itemmodel.py +43 -38
  37. novelwriter/core/novelmodel.py +225 -0
  38. novelwriter/core/options.py +1 -1
  39. novelwriter/core/project.py +24 -25
  40. novelwriter/core/projectdata.py +47 -29
  41. novelwriter/core/projectxml.py +18 -8
  42. novelwriter/core/sessions.py +32 -15
  43. novelwriter/core/spellcheck.py +4 -3
  44. novelwriter/core/status.py +12 -15
  45. novelwriter/core/storage.py +1 -1
  46. novelwriter/core/tree.py +55 -13
  47. novelwriter/dialogs/about.py +19 -22
  48. novelwriter/dialogs/docmerge.py +23 -24
  49. novelwriter/dialogs/docsplit.py +26 -26
  50. novelwriter/dialogs/editlabel.py +19 -20
  51. novelwriter/dialogs/preferences.py +143 -69
  52. novelwriter/dialogs/projectsettings.py +51 -54
  53. novelwriter/dialogs/quotes.py +14 -19
  54. novelwriter/dialogs/wordlist.py +25 -30
  55. novelwriter/enum.py +8 -0
  56. novelwriter/error.py +16 -16
  57. novelwriter/extensions/configlayout.py +24 -20
  58. novelwriter/extensions/eventfilters.py +9 -5
  59. novelwriter/extensions/modified.py +34 -15
  60. novelwriter/extensions/novelselector.py +18 -5
  61. novelwriter/extensions/pagedsidebar.py +39 -49
  62. novelwriter/extensions/progressbars.py +10 -8
  63. novelwriter/extensions/statusled.py +6 -13
  64. novelwriter/extensions/switch.py +31 -41
  65. novelwriter/extensions/switchbox.py +8 -3
  66. novelwriter/extensions/versioninfo.py +4 -4
  67. novelwriter/formats/shared.py +1 -1
  68. novelwriter/formats/todocx.py +14 -10
  69. novelwriter/formats/tohtml.py +7 -5
  70. novelwriter/formats/tokenizer.py +37 -33
  71. novelwriter/formats/tomarkdown.py +6 -2
  72. novelwriter/formats/toodt.py +27 -22
  73. novelwriter/formats/toqdoc.py +19 -14
  74. novelwriter/formats/toraw.py +6 -2
  75. novelwriter/gui/doceditor.py +314 -305
  76. novelwriter/gui/dochighlight.py +46 -45
  77. novelwriter/gui/docviewer.py +102 -104
  78. novelwriter/gui/docviewerpanel.py +47 -51
  79. novelwriter/gui/editordocument.py +8 -5
  80. novelwriter/gui/itemdetails.py +11 -14
  81. novelwriter/gui/mainmenu.py +146 -145
  82. novelwriter/gui/noveltree.py +246 -406
  83. novelwriter/gui/outline.py +141 -72
  84. novelwriter/gui/projtree.py +139 -132
  85. novelwriter/gui/search.py +34 -31
  86. novelwriter/gui/sidebar.py +13 -18
  87. novelwriter/gui/statusbar.py +27 -21
  88. novelwriter/gui/theme.py +554 -436
  89. novelwriter/guimain.py +56 -38
  90. novelwriter/shared.py +32 -23
  91. novelwriter/splash.py +74 -0
  92. novelwriter/text/comments.py +70 -0
  93. novelwriter/text/patterns.py +4 -4
  94. novelwriter/tools/dictionaries.py +20 -29
  95. novelwriter/tools/lipsum.py +18 -18
  96. novelwriter/tools/manusbuild.py +39 -42
  97. novelwriter/tools/manuscript.py +102 -115
  98. novelwriter/tools/manussettings.py +116 -96
  99. novelwriter/tools/noveldetails.py +60 -72
  100. novelwriter/tools/welcome.py +57 -75
  101. novelwriter/tools/writingstats.py +112 -102
  102. novelwriter/types.py +5 -7
  103. {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info}/METADATA +6 -6
  104. novelwriter-2.7rc1.dist-info/RECORD +162 -0
  105. {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info}/WHEEL +1 -1
  106. novelWriter-2.6.3.dist-info/RECORD +0 -363
  107. novelwriter/assets/icons/typicons_dark/README.md +0 -29
  108. novelwriter/assets/icons/typicons_dark/icons.conf +0 -134
  109. novelwriter/assets/icons/typicons_dark/mixed_copy.svg +0 -4
  110. novelwriter/assets/icons/typicons_dark/mixed_document-chapter.svg +0 -12
  111. novelwriter/assets/icons/typicons_dark/mixed_document-new.svg +0 -6
  112. novelwriter/assets/icons/typicons_dark/mixed_document-note.svg +0 -12
  113. novelwriter/assets/icons/typicons_dark/mixed_document-scene.svg +0 -12
  114. novelwriter/assets/icons/typicons_dark/mixed_document-section.svg +0 -12
  115. novelwriter/assets/icons/typicons_dark/mixed_document-title.svg +0 -12
  116. novelwriter/assets/icons/typicons_dark/mixed_edit.svg +0 -4
  117. novelwriter/assets/icons/typicons_dark/mixed_import.svg +0 -5
  118. novelwriter/assets/icons/typicons_dark/mixed_input-checked.svg +0 -5
  119. novelwriter/assets/icons/typicons_dark/mixed_input-none.svg +0 -5
  120. novelwriter/assets/icons/typicons_dark/mixed_input-unchecked.svg +0 -5
  121. novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +0 -6
  122. novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +0 -6
  123. novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +0 -6
  124. novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +0 -6
  125. novelwriter/assets/icons/typicons_dark/mixed_search-replace.svg +0 -6
  126. novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +0 -6
  127. novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +0 -6
  128. novelwriter/assets/icons/typicons_dark/nw_deco-h0.svg +0 -4
  129. novelwriter/assets/icons/typicons_dark/nw_deco-h1.svg +0 -4
  130. novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +0 -4
  131. novelwriter/assets/icons/typicons_dark/nw_deco-h2.svg +0 -4
  132. novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +0 -4
  133. novelwriter/assets/icons/typicons_dark/nw_deco-h3.svg +0 -4
  134. novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +0 -4
  135. novelwriter/assets/icons/typicons_dark/nw_deco-h4.svg +0 -4
  136. novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +0 -4
  137. novelwriter/assets/icons/typicons_dark/nw_deco-noveltree-more.svg +0 -4
  138. novelwriter/assets/icons/typicons_dark/nw_font.svg +0 -4
  139. novelwriter/assets/icons/typicons_dark/nw_panel.svg +0 -4
  140. novelwriter/assets/icons/typicons_dark/nw_quote.svg +0 -4
  141. novelwriter/assets/icons/typicons_dark/nw_search-case.svg +0 -4
  142. novelwriter/assets/icons/typicons_dark/nw_search-preserve.svg +0 -4
  143. novelwriter/assets/icons/typicons_dark/nw_search-regex.svg +0 -4
  144. novelwriter/assets/icons/typicons_dark/nw_search-word.svg +0 -4
  145. novelwriter/assets/icons/typicons_dark/nw_tb-bold-md.svg +0 -4
  146. novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +0 -6
  147. novelwriter/assets/icons/typicons_dark/nw_tb-italic-md.svg +0 -4
  148. novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +0 -6
  149. novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +0 -7
  150. novelwriter/assets/icons/typicons_dark/nw_tb-strike-md.svg +0 -4
  151. novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +0 -6
  152. novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +0 -7
  153. novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +0 -7
  154. novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +0 -7
  155. novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +0 -5
  156. novelwriter/assets/icons/typicons_dark/typ_arrow-down-thick-grey.svg +0 -4
  157. novelwriter/assets/icons/typicons_dark/typ_arrow-forward.svg +0 -4
  158. novelwriter/assets/icons/typicons_dark/typ_arrow-maximise.svg +0 -4
  159. novelwriter/assets/icons/typicons_dark/typ_arrow-minimise.svg +0 -4
  160. novelwriter/assets/icons/typicons_dark/typ_arrow-repeat-grey.svg +0 -4
  161. novelwriter/assets/icons/typicons_dark/typ_book-grey.svg +0 -4
  162. novelwriter/assets/icons/typicons_dark/typ_book.svg +0 -6
  163. novelwriter/assets/icons/typicons_dark/typ_bookmark.svg +0 -4
  164. novelwriter/assets/icons/typicons_dark/typ_calendar.svg +0 -4
  165. novelwriter/assets/icons/typicons_dark/typ_cancel-grey.svg +0 -4
  166. novelwriter/assets/icons/typicons_dark/typ_cancel.svg +0 -4
  167. novelwriter/assets/icons/typicons_dark/typ_chart-bar-grey.svg +0 -4
  168. novelwriter/assets/icons/typicons_dark/typ_chevron-down.svg +0 -4
  169. novelwriter/assets/icons/typicons_dark/typ_chevron-left.svg +0 -4
  170. novelwriter/assets/icons/typicons_dark/typ_chevron-right.svg +0 -4
  171. novelwriter/assets/icons/typicons_dark/typ_chevron-up.svg +0 -4
  172. novelwriter/assets/icons/typicons_dark/typ_cog.svg +0 -4
  173. novelwriter/assets/icons/typicons_dark/typ_delete-full.svg +0 -4
  174. novelwriter/assets/icons/typicons_dark/typ_delete.svg +0 -4
  175. novelwriter/assets/icons/typicons_dark/typ_directions-full.svg +0 -4
  176. novelwriter/assets/icons/typicons_dark/typ_document-add.svg +0 -4
  177. novelwriter/assets/icons/typicons_dark/typ_document-text.svg +0 -8
  178. novelwriter/assets/icons/typicons_dark/typ_document.svg +0 -4
  179. novelwriter/assets/icons/typicons_dark/typ_export-grey.svg +0 -4
  180. novelwriter/assets/icons/typicons_dark/typ_export.svg +0 -4
  181. novelwriter/assets/icons/typicons_dark/typ_eye.svg +0 -4
  182. novelwriter/assets/icons/typicons_dark/typ_flag.svg +0 -4
  183. novelwriter/assets/icons/typicons_dark/typ_folder-open.svg +0 -4
  184. novelwriter/assets/icons/typicons_dark/typ_folder.svg +0 -5
  185. novelwriter/assets/icons/typicons_dark/typ_globe-grey.svg +0 -4
  186. novelwriter/assets/icons/typicons_dark/typ_key.svg +0 -4
  187. novelwriter/assets/icons/typicons_dark/typ_lightbulb-full.svg +0 -4
  188. novelwriter/assets/icons/typicons_dark/typ_location.svg +0 -4
  189. novelwriter/assets/icons/typicons_dark/typ_media-pause-grey.svg +0 -4
  190. novelwriter/assets/icons/typicons_dark/typ_media-record-outline.svg +0 -4
  191. novelwriter/assets/icons/typicons_dark/typ_media-record.svg +0 -4
  192. novelwriter/assets/icons/typicons_dark/typ_minus.svg +0 -4
  193. novelwriter/assets/icons/typicons_dark/typ_pencil.svg +0 -5
  194. novelwriter/assets/icons/typicons_dark/typ_pin-outline.svg +0 -4
  195. novelwriter/assets/icons/typicons_dark/typ_pin.svg +0 -4
  196. novelwriter/assets/icons/typicons_dark/typ_plus.svg +0 -4
  197. novelwriter/assets/icons/typicons_dark/typ_puzzle-outline.svg +0 -4
  198. novelwriter/assets/icons/typicons_dark/typ_puzzle.svg +0 -4
  199. novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +0 -4
  200. novelwriter/assets/icons/typicons_dark/typ_refresh.svg +0 -4
  201. novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +0 -4
  202. novelwriter/assets/icons/typicons_dark/typ_search.svg +0 -4
  203. novelwriter/assets/icons/typicons_dark/typ_star.svg +0 -4
  204. novelwriter/assets/icons/typicons_dark/typ_stopwatch-grey.svg +0 -4
  205. novelwriter/assets/icons/typicons_dark/typ_th-dot-menu.svg +0 -4
  206. novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +0 -4
  207. novelwriter/assets/icons/typicons_dark/typ_th-list-grey.svg +0 -4
  208. novelwriter/assets/icons/typicons_dark/typ_th-list.svg +0 -9
  209. novelwriter/assets/icons/typicons_dark/typ_times.svg +0 -4
  210. novelwriter/assets/icons/typicons_dark/typ_trash.svg +0 -5
  211. novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +0 -4
  212. novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +0 -4
  213. novelwriter/assets/icons/typicons_dark/typ_user.svg +0 -5
  214. novelwriter/assets/icons/typicons_dark/typ_warning-full.svg +0 -4
  215. novelwriter/assets/icons/typicons_light/README.md +0 -29
  216. novelwriter/assets/icons/typicons_light/icons.conf +0 -134
  217. novelwriter/assets/icons/typicons_light/mixed_copy.svg +0 -4
  218. novelwriter/assets/icons/typicons_light/mixed_document-chapter.svg +0 -12
  219. novelwriter/assets/icons/typicons_light/mixed_document-new.svg +0 -6
  220. novelwriter/assets/icons/typicons_light/mixed_document-note.svg +0 -12
  221. novelwriter/assets/icons/typicons_light/mixed_document-scene.svg +0 -12
  222. novelwriter/assets/icons/typicons_light/mixed_document-section.svg +0 -12
  223. novelwriter/assets/icons/typicons_light/mixed_document-title.svg +0 -12
  224. novelwriter/assets/icons/typicons_light/mixed_edit.svg +0 -4
  225. novelwriter/assets/icons/typicons_light/mixed_import.svg +0 -5
  226. novelwriter/assets/icons/typicons_light/mixed_input-checked.svg +0 -5
  227. novelwriter/assets/icons/typicons_light/mixed_input-none.svg +0 -5
  228. novelwriter/assets/icons/typicons_light/mixed_input-unchecked.svg +0 -5
  229. novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +0 -6
  230. novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +0 -6
  231. novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +0 -6
  232. novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +0 -6
  233. novelwriter/assets/icons/typicons_light/mixed_search-replace.svg +0 -6
  234. novelwriter/assets/icons/typicons_light/mixed_size-height.svg +0 -6
  235. novelwriter/assets/icons/typicons_light/mixed_size-width.svg +0 -6
  236. novelwriter/assets/icons/typicons_light/nw_deco-h0.svg +0 -4
  237. novelwriter/assets/icons/typicons_light/nw_deco-h1.svg +0 -4
  238. novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +0 -4
  239. novelwriter/assets/icons/typicons_light/nw_deco-h2.svg +0 -4
  240. novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +0 -4
  241. novelwriter/assets/icons/typicons_light/nw_deco-h3.svg +0 -4
  242. novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +0 -4
  243. novelwriter/assets/icons/typicons_light/nw_deco-h4.svg +0 -4
  244. novelwriter/assets/icons/typicons_light/nw_deco-note.svg +0 -4
  245. novelwriter/assets/icons/typicons_light/nw_deco-noveltree-more.svg +0 -4
  246. novelwriter/assets/icons/typicons_light/nw_font.svg +0 -4
  247. novelwriter/assets/icons/typicons_light/nw_panel.svg +0 -4
  248. novelwriter/assets/icons/typicons_light/nw_quote.svg +0 -4
  249. novelwriter/assets/icons/typicons_light/nw_search-case.svg +0 -4
  250. novelwriter/assets/icons/typicons_light/nw_search-preserve.svg +0 -4
  251. novelwriter/assets/icons/typicons_light/nw_search-regex.svg +0 -4
  252. novelwriter/assets/icons/typicons_light/nw_search-word.svg +0 -4
  253. novelwriter/assets/icons/typicons_light/nw_tb-bold-md.svg +0 -4
  254. novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +0 -6
  255. novelwriter/assets/icons/typicons_light/nw_tb-italic-md.svg +0 -4
  256. novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +0 -6
  257. novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +0 -7
  258. novelwriter/assets/icons/typicons_light/nw_tb-strike-md.svg +0 -4
  259. novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +0 -6
  260. novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +0 -7
  261. novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +0 -7
  262. novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +0 -7
  263. novelwriter/assets/icons/typicons_light/nw_toolbar.svg +0 -5
  264. novelwriter/assets/icons/typicons_light/typ_arrow-down-thick-grey.svg +0 -4
  265. novelwriter/assets/icons/typicons_light/typ_arrow-forward.svg +0 -4
  266. novelwriter/assets/icons/typicons_light/typ_arrow-maximise.svg +0 -4
  267. novelwriter/assets/icons/typicons_light/typ_arrow-minimise.svg +0 -4
  268. novelwriter/assets/icons/typicons_light/typ_arrow-repeat-grey.svg +0 -4
  269. novelwriter/assets/icons/typicons_light/typ_book-grey.svg +0 -4
  270. novelwriter/assets/icons/typicons_light/typ_book.svg +0 -6
  271. novelwriter/assets/icons/typicons_light/typ_bookmark.svg +0 -4
  272. novelwriter/assets/icons/typicons_light/typ_calendar.svg +0 -4
  273. novelwriter/assets/icons/typicons_light/typ_cancel-grey.svg +0 -4
  274. novelwriter/assets/icons/typicons_light/typ_cancel.svg +0 -4
  275. novelwriter/assets/icons/typicons_light/typ_chart-bar-grey.svg +0 -4
  276. novelwriter/assets/icons/typicons_light/typ_chevron-down.svg +0 -4
  277. novelwriter/assets/icons/typicons_light/typ_chevron-left.svg +0 -4
  278. novelwriter/assets/icons/typicons_light/typ_chevron-right.svg +0 -4
  279. novelwriter/assets/icons/typicons_light/typ_chevron-up.svg +0 -4
  280. novelwriter/assets/icons/typicons_light/typ_cog.svg +0 -4
  281. novelwriter/assets/icons/typicons_light/typ_delete-full.svg +0 -4
  282. novelwriter/assets/icons/typicons_light/typ_delete.svg +0 -4
  283. novelwriter/assets/icons/typicons_light/typ_directions-full.svg +0 -4
  284. novelwriter/assets/icons/typicons_light/typ_document-add.svg +0 -4
  285. novelwriter/assets/icons/typicons_light/typ_document-text.svg +0 -5
  286. novelwriter/assets/icons/typicons_light/typ_document.svg +0 -4
  287. novelwriter/assets/icons/typicons_light/typ_export-grey.svg +0 -4
  288. novelwriter/assets/icons/typicons_light/typ_export.svg +0 -4
  289. novelwriter/assets/icons/typicons_light/typ_eye.svg +0 -4
  290. novelwriter/assets/icons/typicons_light/typ_flag.svg +0 -4
  291. novelwriter/assets/icons/typicons_light/typ_folder-open.svg +0 -4
  292. novelwriter/assets/icons/typicons_light/typ_folder.svg +0 -5
  293. novelwriter/assets/icons/typicons_light/typ_globe-grey.svg +0 -4
  294. novelwriter/assets/icons/typicons_light/typ_key.svg +0 -4
  295. novelwriter/assets/icons/typicons_light/typ_lightbulb-full.svg +0 -4
  296. novelwriter/assets/icons/typicons_light/typ_location.svg +0 -4
  297. novelwriter/assets/icons/typicons_light/typ_media-pause-grey.svg +0 -4
  298. novelwriter/assets/icons/typicons_light/typ_media-record-outline.svg +0 -4
  299. novelwriter/assets/icons/typicons_light/typ_media-record.svg +0 -4
  300. novelwriter/assets/icons/typicons_light/typ_minus.svg +0 -4
  301. novelwriter/assets/icons/typicons_light/typ_pencil.svg +0 -5
  302. novelwriter/assets/icons/typicons_light/typ_pin-outline.svg +0 -4
  303. novelwriter/assets/icons/typicons_light/typ_pin.svg +0 -4
  304. novelwriter/assets/icons/typicons_light/typ_plus.svg +0 -4
  305. novelwriter/assets/icons/typicons_light/typ_puzzle-outline.svg +0 -4
  306. novelwriter/assets/icons/typicons_light/typ_puzzle.svg +0 -4
  307. novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +0 -4
  308. novelwriter/assets/icons/typicons_light/typ_refresh.svg +0 -4
  309. novelwriter/assets/icons/typicons_light/typ_search-grey.svg +0 -4
  310. novelwriter/assets/icons/typicons_light/typ_search.svg +0 -4
  311. novelwriter/assets/icons/typicons_light/typ_star.svg +0 -4
  312. novelwriter/assets/icons/typicons_light/typ_stopwatch-grey.svg +0 -4
  313. novelwriter/assets/icons/typicons_light/typ_th-dot-menu.svg +0 -4
  314. novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +0 -4
  315. novelwriter/assets/icons/typicons_light/typ_th-list-grey.svg +0 -4
  316. novelwriter/assets/icons/typicons_light/typ_th-list.svg +0 -9
  317. novelwriter/assets/icons/typicons_light/typ_times.svg +0 -4
  318. novelwriter/assets/icons/typicons_light/typ_trash.svg +0 -5
  319. novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +0 -4
  320. novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +0 -4
  321. novelwriter/assets/icons/typicons_light/typ_user.svg +0 -5
  322. novelwriter/assets/icons/typicons_light/typ_warning-full.svg +0 -4
  323. {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info}/entry_points.txt +0 -0
  324. {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info/licenses}/LICENSE.md +0 -0
  325. {novelWriter-2.6.3.dist-info → novelwriter-2.7rc1.dist-info}/top_level.txt +0 -0
@@ -28,8 +28,8 @@ import logging
28
28
 
29
29
  from typing import TYPE_CHECKING
30
30
 
31
- from PyQt5.QtCore import QAbstractItemModel, QMimeData, QModelIndex, Qt
32
- from PyQt5.QtGui import QFont, QIcon
31
+ from PyQt6.QtCore import QAbstractItemModel, QMimeData, QModelIndex, Qt
32
+ from PyQt6.QtGui import QFont, QIcon
33
33
 
34
34
  from novelwriter.common import decodeMimeHandles, encodeMimeHandles, minmax
35
35
  from novelwriter.constants import nwConst
@@ -37,7 +37,7 @@ from novelwriter.core.item import NWItem
37
37
  from novelwriter.enum import nwItemClass
38
38
  from novelwriter.types import QtAlignRight
39
39
 
40
- if TYPE_CHECKING: # pragma: no cover
40
+ if TYPE_CHECKING:
41
41
  from novelwriter.core.tree import NWTree
42
42
 
43
43
  logger = logging.getLogger(__name__)
@@ -45,24 +45,24 @@ logger = logging.getLogger(__name__)
45
45
  INV_ROOT = "invisibleRoot"
46
46
  C_FACTOR = 0x0100
47
47
 
48
- C_LABEL_TEXT = 0x0000 | Qt.ItemDataRole.DisplayRole
49
- C_LABEL_ICON = 0x0000 | Qt.ItemDataRole.DecorationRole
50
- C_LABEL_FONT = 0x0000 | Qt.ItemDataRole.FontRole
51
- C_COUNT_TEXT = 0x0100 | Qt.ItemDataRole.DisplayRole
52
- C_COUNT_ICON = 0x0100 | Qt.ItemDataRole.DecorationRole
53
- C_COUNT_ALIGN = 0x0100 | Qt.ItemDataRole.TextAlignmentRole
54
- C_ACTIVE_ICON = 0x0200 | Qt.ItemDataRole.DecorationRole
55
- C_ACTIVE_TIP = 0x0200 | Qt.ItemDataRole.ToolTipRole
56
- C_STATUS_ICON = 0x0300 | Qt.ItemDataRole.DecorationRole
57
- C_STATUS_TIP = 0x0300 | Qt.ItemDataRole.ToolTipRole
48
+ C_LABEL_TEXT = 0x0000 | Qt.ItemDataRole.DisplayRole
49
+ C_LABEL_ICON = 0x0000 | Qt.ItemDataRole.DecorationRole
50
+ C_LABEL_FONT = 0x0000 | Qt.ItemDataRole.FontRole
51
+ C_COUNT_TEXT = 0x0100 | Qt.ItemDataRole.DisplayRole
52
+ C_COUNT_ICON = 0x0100 | Qt.ItemDataRole.DecorationRole
53
+ C_COUNT_ALIGN = 0x0100 | Qt.ItemDataRole.TextAlignmentRole
54
+ C_ACTIVE_ICON = 0x0200 | Qt.ItemDataRole.DecorationRole
55
+ C_ACTIVE_TIP = 0x0200 | Qt.ItemDataRole.ToolTipRole
56
+ C_ACTIVE_ACCESS = 0x0200 | Qt.ItemDataRole.AccessibleTextRole
57
+ C_STATUS_ICON = 0x0300 | Qt.ItemDataRole.DecorationRole
58
+ C_STATUS_TIP = 0x0300 | Qt.ItemDataRole.ToolTipRole
59
+ C_STATUS_ACCESS = 0x0300 | Qt.ItemDataRole.AccessibleTextRole
58
60
 
59
61
  NODE_FLAGS = Qt.ItemFlag.ItemIsEnabled
60
62
  NODE_FLAGS |= Qt.ItemFlag.ItemIsSelectable
61
63
  NODE_FLAGS |= Qt.ItemFlag.ItemIsDropEnabled
62
64
 
63
- if TYPE_CHECKING: # pragma: no cover
64
- # Requires Python 3.10
65
- T_NodeData = str | QIcon | QFont | Qt.AlignmentFlag | None
65
+ T_NodeData = str | QIcon | QFont | Qt.AlignmentFlag | None
66
66
 
67
67
 
68
68
  class ProjectNode:
@@ -91,7 +91,7 @@ class ProjectNode:
91
91
  C_ACTIVE = 2
92
92
  C_STATUS = 3
93
93
 
94
- __slots__ = ("_item", "_children", "_parent", "_row", "_cache", "_flags", "_count")
94
+ __slots__ = ("_cache", "_children", "_count", "_flags", "_item", "_parent", "_row")
95
95
 
96
96
  def __init__(self, item: NWItem) -> None:
97
97
  self._item = item
@@ -152,19 +152,21 @@ class ProjectNode:
152
152
 
153
153
  # Active
154
154
  aText, aIcon = self._item.getActiveStatus()
155
- self._cache[C_ACTIVE_TIP] = aText
156
155
  self._cache[C_ACTIVE_ICON] = aIcon
156
+ self._cache[C_ACTIVE_TIP] = aText
157
+ self._cache[C_ACTIVE_ACCESS] = aText
157
158
 
158
159
  # Status
159
160
  sText, sIcon = self._item.getImportStatus()
160
- self._cache[C_STATUS_TIP] = sText
161
161
  self._cache[C_STATUS_ICON] = sIcon
162
+ self._cache[C_STATUS_TIP] = sText
163
+ self._cache[C_STATUS_ACCESS] = sText
162
164
 
163
165
  return
164
166
 
165
167
  def updateCount(self, propagate: bool = True) -> None:
166
168
  """Update counts, and propagate upwards in the tree."""
167
- self._count = self._item.wordCount + sum(c._count for c in self._children)
169
+ self._count = self._item.mainCount + sum(c._count for c in self._children) # noqa: SLF001
168
170
  self._cache[C_COUNT_TEXT] = f"{self._count:n}"
169
171
  if propagate and (parent := self._parent):
170
172
  parent.updateCount()
@@ -195,7 +197,7 @@ class ProjectNode:
195
197
  return self._parent
196
198
 
197
199
  def child(self, row: int) -> ProjectNode | None:
198
- """Return a child ofg the node."""
200
+ """Return a child of the node."""
199
201
  if 0 <= row < len(self._children):
200
202
  return self._children[row]
201
203
  return None
@@ -220,6 +222,7 @@ class ProjectNode:
220
222
  child._row = len(self._children)
221
223
  self._children.append(child)
222
224
  self._refreshChildrenPos()
225
+ self._item.notifyNovelStructureChange()
223
226
  return
224
227
 
225
228
  def takeChild(self, pos: int) -> ProjectNode | None:
@@ -228,6 +231,7 @@ class ProjectNode:
228
231
  node = self._children.pop(pos)
229
232
  self._refreshChildrenPos()
230
233
  self.updateCount()
234
+ self._item.notifyNovelStructureChange()
231
235
  return node
232
236
  return None
233
237
 
@@ -238,6 +242,7 @@ class ProjectNode:
238
242
  node = self._children.pop(source)
239
243
  self._children.insert(target, node)
240
244
  self._refreshChildrenPos()
245
+ self._item.notifyNovelStructureChange()
241
246
  return
242
247
 
243
248
  def setExpanded(self, state: bool) -> None:
@@ -256,13 +261,13 @@ class ProjectNode:
256
261
  """Recursively add all nodes to a list."""
257
262
  for node in self._children:
258
263
  children.append(node)
259
- node._recursiveAppendChildren(children)
264
+ node._recursiveAppendChildren(children) # noqa: SLF001
260
265
  return
261
266
 
262
267
  def _refreshChildrenPos(self) -> None:
263
268
  """Update the row value on all children."""
264
269
  for n, child in enumerate(self._children):
265
- child._row = n
270
+ child._row = n # noqa: SLF001
266
271
  child.item.setOrder(n)
267
272
  return
268
273
 
@@ -289,12 +294,12 @@ class ProjectModel(QAbstractItemModel):
289
294
  methods needed primarily by the project tree GUI component.
290
295
  """
291
296
 
292
- __slots__ = ("_tree", "_root")
297
+ __slots__ = ("_root", "_tree")
293
298
 
294
299
  def __init__(self, tree: NWTree) -> None:
295
300
  super().__init__()
296
301
  self._tree = tree
297
- self._root = ProjectNode(NWItem(tree._project, INV_ROOT))
302
+ self._root = ProjectNode(NWItem(tree.project, INV_ROOT))
298
303
  self._root.item.setName("Invisible Root")
299
304
  logger.debug("Ready: ProjectModel")
300
305
  return
@@ -332,8 +337,9 @@ class ProjectModel(QAbstractItemModel):
332
337
  return self.createIndex(parent.row(), 0, parent)
333
338
  return QModelIndex()
334
339
 
335
- def index(self, row: int, column: int, parent: QModelIndex = QModelIndex()) -> QModelIndex:
336
- """get the index of a child item of a parent."""
340
+ def index(self, row: int, column: int, parent: QModelIndex | None = None) -> QModelIndex:
341
+ """Get the index of a child item of a parent."""
342
+ parent = parent or QModelIndex()
337
343
  if self.hasIndex(row, column, parent):
338
344
  node: ProjectNode = parent.internalPointer() if parent.isValid() else self._root
339
345
  if child := node.child(row):
@@ -389,10 +395,10 @@ class ProjectModel(QAbstractItemModel):
389
395
  ) -> bool:
390
396
  """Process mime data drop."""
391
397
  if self.canDropMimeData(data, action, row, column, parent):
392
- items = []
393
- for handle in decodeMimeHandles(data):
394
- if (index := self.indexFromHandle(handle)).isValid():
395
- items.append(index)
398
+ items = [
399
+ index for handle in decodeMimeHandles(data)
400
+ if (index := self.indexFromHandle(handle)).isValid()
401
+ ]
396
402
  self.multiMove(items, parent, row)
397
403
  return True
398
404
  return False
@@ -488,7 +494,7 @@ class ProjectModel(QAbstractItemModel):
488
494
  if temp := self.removeChild(index.parent(), index.row()):
489
495
  self.insertChild(temp, target, pos)
490
496
  for child in reversed(node.allChildren()):
491
- node._updateRelationships(child)
497
+ node._updateRelationships(child) # noqa: SLF001
492
498
  child.item.notifyToRefresh()
493
499
  node.item.notifyToRefresh()
494
500
  return
@@ -499,16 +505,15 @@ class ProjectModel(QAbstractItemModel):
499
505
 
500
506
  def clear(self) -> None:
501
507
  """Clear the project model."""
502
- self._root._children.clear()
508
+ self._root.children.clear()
503
509
  return
504
510
 
505
511
  def allExpanded(self) -> list[QModelIndex]:
506
512
  """Return a list of all expanded items."""
507
- expanded = []
508
- for node in self._root.allChildren():
509
- if node._item.isExpanded:
510
- expanded.append(self.createIndex(node.row(), 0, node))
511
- return expanded
513
+ return [
514
+ self.createIndex(node.row(), 0, node) for node in self._root.allChildren()
515
+ if node.item.isExpanded
516
+ ]
512
517
 
513
518
  def trashSelection(self, indices: list[QModelIndex]) -> bool:
514
519
  """Check if a selection of indices are all in trash or not."""
@@ -0,0 +1,225 @@
1
+ """
2
+ novelWriter – Novel Model
3
+ =========================
4
+
5
+ File History:
6
+ Created: 2025-02-22 [2.7b1] NovelModel
7
+
8
+ This file is a part of novelWriter
9
+ Copyright (C) 2025 Veronica Berglyd Olsen and novelWriter contributors
10
+
11
+ This program is free software: you can redistribute it and/or modify
12
+ it under the terms of the GNU General Public License as published by
13
+ the Free Software Foundation, either version 3 of the License, or
14
+ (at your option) any later version.
15
+
16
+ This program is distributed in the hope that it will be useful, but
17
+ WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19
+ General Public License for more details.
20
+
21
+ You should have received a copy of the GNU General Public License
22
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
23
+ """
24
+ from __future__ import annotations
25
+
26
+ import logging
27
+
28
+ from typing import TYPE_CHECKING
29
+
30
+ from PyQt6.QtCore import QAbstractTableModel, QModelIndex, Qt
31
+ from PyQt6.QtGui import QIcon, QPixmap
32
+
33
+ from novelwriter import SHARED
34
+ from novelwriter.constants import nwKeyWords, nwLabels, nwStyles, trConst
35
+ from novelwriter.enum import nwNovelExtra
36
+ from novelwriter.types import QtAlignRight
37
+
38
+ if TYPE_CHECKING:
39
+ from novelwriter.core.indexdata import IndexHeading, IndexNode
40
+
41
+ logger = logging.getLogger(__name__)
42
+
43
+ C_FACTOR = 0x0100
44
+
45
+ R_TEXT = Qt.ItemDataRole.DisplayRole
46
+ R_ICON = Qt.ItemDataRole.DecorationRole
47
+ R_ALIGN = Qt.ItemDataRole.TextAlignmentRole
48
+ R_TIP = Qt.ItemDataRole.ToolTipRole
49
+ R_ACCESS = Qt.ItemDataRole.AccessibleTextRole
50
+ R_HANDLE = 0xff01
51
+ R_KEY = 0xff02
52
+
53
+ T_NodeData = str | QIcon | QPixmap | Qt.AlignmentFlag | None
54
+
55
+
56
+ class NovelModel(QAbstractTableModel):
57
+
58
+ __slots__ = ("_columns", "_extraKey", "_extraLabel", "_more", "_rows")
59
+
60
+ def __init__(self) -> None:
61
+ super().__init__()
62
+ self._rows: list[dict[int, T_NodeData]] = []
63
+ self._more = SHARED.theme.getIcon("more_arrow")
64
+ self._columns = 3
65
+ self._extraKey = ""
66
+ self._extraLabel = ""
67
+ return
68
+
69
+ def __del__(self) -> None: # pragma: no cover
70
+ logger.debug("Delete: NovelModel")
71
+ return
72
+
73
+ ##
74
+ # Properties
75
+ ##
76
+
77
+ @property
78
+ def columns(self) -> int:
79
+ """Return the number of columns."""
80
+ return self._columns
81
+
82
+ ##
83
+ # Setters
84
+ ##
85
+
86
+ def setExtraColumn(self, extra: nwNovelExtra) -> None:
87
+ """Set extra data column settings."""
88
+ match extra:
89
+ case nwNovelExtra.HIDDEN:
90
+ self._columns = 3
91
+ self._extraKey = ""
92
+ self._extraLabel = ""
93
+ case nwNovelExtra.POV:
94
+ self._columns = 4
95
+ self._extraKey = nwKeyWords.POV_KEY
96
+ self._extraLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY])
97
+ case nwNovelExtra.FOCUS:
98
+ self._columns = 4
99
+ self._extraKey = nwKeyWords.FOCUS_KEY
100
+ self._extraLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY])
101
+ case nwNovelExtra.PLOT:
102
+ self._columns = 4
103
+ self._extraKey = nwKeyWords.PLOT_KEY
104
+ self._extraLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY])
105
+ return
106
+
107
+ ##
108
+ # Model Interface
109
+ ##
110
+
111
+ def rowCount(self, index: QModelIndex) -> int:
112
+ """Return the number of rows."""
113
+ return len(self._rows)
114
+
115
+ def columnCount(self, index: QModelIndex) -> int:
116
+ """Return the number of columns."""
117
+ return self._columns
118
+
119
+ def data(self, index: QModelIndex, role: Qt.ItemDataRole) -> T_NodeData:
120
+ """Return display data for a node."""
121
+ try:
122
+ return self._rows[index.row()].get(C_FACTOR*index.column() | role)
123
+ except Exception:
124
+ logger.error("Novel model index is inconsistent")
125
+ return None
126
+
127
+ def handle(self, index: QModelIndex) -> str | None:
128
+ """Return item handle for the row."""
129
+ try:
130
+ return self._rows[index.row()].get(R_HANDLE) # type: ignore
131
+ except Exception:
132
+ logger.error("Novel model index is inconsistent")
133
+ return None
134
+
135
+ def key(self, index: QModelIndex) -> str | None:
136
+ """Return item handle for the row."""
137
+ try:
138
+ return self._rows[index.row()].get(R_KEY) # type: ignore
139
+ except Exception:
140
+ logger.error("Novel model index is inconsistent")
141
+ return None
142
+
143
+ ##
144
+ # Data Methods
145
+ ##
146
+
147
+ def clear(self) -> None:
148
+ """Clear the model."""
149
+ self._rows.clear()
150
+ return
151
+
152
+ def append(self, node: IndexNode) -> None:
153
+ """Append a node to the model."""
154
+ handle = node.handle
155
+ for key, head in node.items():
156
+ if key != "T0000":
157
+ self._rows.append(self._generateEntry(handle, key, head))
158
+ return
159
+
160
+ def refresh(self, node: IndexNode) -> bool:
161
+ """Refresh an index node."""
162
+ handle = node.handle
163
+ current = []
164
+ for i, row in enumerate(self._rows):
165
+ if row.get(R_HANDLE) == handle:
166
+ current.append(i)
167
+
168
+ if current == []:
169
+ logger.warning("No novel model entries for '%s'", handle)
170
+ return False
171
+
172
+ cols = self._columns - 1
173
+ first = current[0]
174
+ last = current[-1]
175
+
176
+ remains = []
177
+ for key, head in node.items():
178
+ if key != "T0000":
179
+ if current:
180
+ j = current.pop(0)
181
+ self._rows[j] = self._generateEntry(handle, key, head)
182
+ else:
183
+ remains.append((key, head))
184
+
185
+ self.dataChanged.emit(self.createIndex(first, 0), self.createIndex(last, cols))
186
+
187
+ if remains:
188
+ # Inserting is safe for out of bounds indices
189
+ self.beginInsertRows(QModelIndex(), last, last + len(remains) - 1)
190
+ for k, (key, head) in enumerate(remains, last + 1):
191
+ self._rows.insert(k, self._generateEntry(handle, key, head))
192
+ self.endInsertRows()
193
+ elif current:
194
+ # Deleting ranges are safe for out of bounds indices
195
+ self.beginRemoveRows(QModelIndex(), current[0], current[-1])
196
+ del self._rows[current[0]:current[-1] + 1]
197
+ self.endRemoveRows()
198
+
199
+ return True
200
+
201
+ ##
202
+ # Internal Functions
203
+ ##
204
+
205
+ def _generateEntry(self, handle: str, key: str, head: IndexHeading) -> dict[int, T_NodeData]:
206
+ """Generate a cache entry."""
207
+ iLevel = nwStyles.H_LEVEL.get(head.level, 0)
208
+ data = {}
209
+ data[C_FACTOR*0 | R_TIP] = head.title
210
+ data[C_FACTOR*0 | R_TEXT] = head.title
211
+ data[C_FACTOR*0 | R_ICON] = SHARED.theme.getHeaderDecoration(iLevel)
212
+ data[C_FACTOR*1 | R_TEXT] = f"{head.mainCount:n}"
213
+ data[C_FACTOR*1 | R_ALIGN] = QtAlignRight
214
+ if self._columns == 3:
215
+ data[C_FACTOR*2 | R_ICON] = self._more
216
+ else:
217
+ if self._extraKey and (refs := head.getReferencesByKeyword(self._extraKey)):
218
+ text = ", ".join(refs)
219
+ data[C_FACTOR*2 | R_TEXT] = text
220
+ data[C_FACTOR*2 | R_TIP] = f"<b>{self._extraLabel}:</b> {text}"
221
+ data[C_FACTOR*2 | R_ACCESS] = f"{self._extraLabel}: {text}"
222
+ data[C_FACTOR*3 | R_ICON] = self._more
223
+ data[R_HANDLE] = handle
224
+ data[R_KEY] = key
225
+ return data
@@ -35,7 +35,7 @@ from novelwriter.common import checkBool, checkFloat, checkInt, checkString, jso
35
35
  from novelwriter.constants import nwFiles
36
36
  from novelwriter.error import logException
37
37
 
38
- if TYPE_CHECKING: # pragma: no cover
38
+ if TYPE_CHECKING:
39
39
  from novelwriter.core.project import NWProject
40
40
 
41
41
  logger = logging.getLogger(__name__)
@@ -32,7 +32,7 @@ from pathlib import Path
32
32
  from time import time
33
33
  from typing import TYPE_CHECKING
34
34
 
35
- from PyQt5.QtCore import QCoreApplication
35
+ from PyQt6.QtCore import QCoreApplication
36
36
 
37
37
  from novelwriter import CONFIG, SHARED, __hexversion__, __version__
38
38
  from novelwriter.common import (
@@ -40,7 +40,7 @@ from novelwriter.common import (
40
40
  makeFileNameSafe, minmax
41
41
  )
42
42
  from novelwriter.constants import nwLabels, trConst
43
- from novelwriter.core.index import NWIndex
43
+ from novelwriter.core.index import Index
44
44
  from novelwriter.core.options import OptionState
45
45
  from novelwriter.core.projectdata import NWProjectData
46
46
  from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLReadState
@@ -50,8 +50,7 @@ from novelwriter.core.tree import NWTree
50
50
  from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
51
51
  from novelwriter.error import logException
52
52
 
53
- if TYPE_CHECKING: # pragma: no cover
54
- # Requires Python 3.10
53
+ if TYPE_CHECKING:
55
54
  from novelwriter.core.status import T_StatusKind, T_UpdateEntry
56
55
 
57
56
  logger = logging.getLogger(__name__)
@@ -68,8 +67,8 @@ class NWProjectState(Enum):
68
67
  class NWProject:
69
68
 
70
69
  __slots__ = (
71
- "_options", "_storage", "_data", "_tree", "_index", "_session",
72
- "_langData", "_changed", "_valid", "_state", "tr",
70
+ "_changed", "_data", "_index", "_langData", "_options", "_session",
71
+ "_state", "_storage", "_tree", "_valid", "tr",
73
72
  )
74
73
 
75
74
  def __init__(self) -> None:
@@ -79,7 +78,7 @@ class NWProject:
79
78
  self._storage = NWStorage(self) # The project storage handler
80
79
  self._data = NWProjectData(self) # The project settings
81
80
  self._tree = NWTree(self) # The project tree
82
- self._index = NWIndex(self) # The project index
81
+ self._index = Index(self) # The project index
83
82
  self._session = NWSessionLog(self) # The session record
84
83
 
85
84
  # Project Status
@@ -126,7 +125,7 @@ class NWProject:
126
125
  return self._tree
127
126
 
128
127
  @property
129
- def index(self) -> NWIndex:
128
+ def index(self) -> Index:
130
129
  return self._index
131
130
 
132
131
  @property
@@ -368,7 +367,7 @@ class NWProject:
368
367
  # Often, the index needs to be rebuilt when updating format
369
368
  self._index.rebuild()
370
369
 
371
- self.updateWordCounts()
370
+ self.updateCounts()
372
371
  self._session.startSession()
373
372
  self.setProjectChanged(False)
374
373
  self._valid = True
@@ -398,7 +397,7 @@ class NWProject:
398
397
  else:
399
398
  self._data.incSaveCount()
400
399
 
401
- self.updateWordCounts()
400
+ self.updateCounts()
402
401
  self.countStatus()
403
402
 
404
403
  xmlWriter = self._storage.getXmlWriter()
@@ -484,14 +483,14 @@ class NWProject:
484
483
 
485
484
  def setDefaultStatusImport(self) -> None:
486
485
  """Set the default status and importance values."""
487
- self._data.itemStatus.add(None, self.tr("New"), (100, 100, 100), "SQUARE", 0)
488
- self._data.itemStatus.add(None, self.tr("Note"), (200, 50, 0), "SQUARE", 0)
489
- self._data.itemStatus.add(None, self.tr("Draft"), (200, 150, 0), "SQUARE", 0)
490
- self._data.itemStatus.add(None, self.tr("Finished"), (50, 200, 0), "SQUARE", 0)
491
- self._data.itemImport.add(None, self.tr("New"), (100, 100, 100), "SQUARE", 0)
492
- self._data.itemImport.add(None, self.tr("Minor"), (200, 50, 0), "SQUARE", 0)
493
- self._data.itemImport.add(None, self.tr("Major"), (200, 150, 0), "SQUARE", 0)
494
- self._data.itemImport.add(None, self.tr("Main"), (50, 200, 0), "SQUARE", 0)
486
+ self._data.itemStatus.add(None, self.tr("New"), (120, 120, 120), "STAR", 0)
487
+ self._data.itemStatus.add(None, self.tr("Note"), (205, 171, 143), "TRIANGLE", 0)
488
+ self._data.itemStatus.add(None, self.tr("Draft"), (143, 240, 164), "CIRCLE_T", 0)
489
+ self._data.itemStatus.add(None, self.tr("Finished"), (249, 240, 107), "STAR", 0)
490
+ self._data.itemImport.add(None, self.tr("New"), (120, 120, 120), "SQUARE", 0)
491
+ self._data.itemImport.add(None, self.tr("Minor"), (220, 138, 221), "BLOCK_2", 0)
492
+ self._data.itemImport.add(None, self.tr("Major"), (220, 138, 221), "BLOCK_3", 0)
493
+ self._data.itemImport.add(None, self.tr("Main"), (220, 138, 221), "BLOCK_4", 0)
495
494
  return
496
495
 
497
496
  def setProjectLang(self, language: str | None) -> None:
@@ -516,10 +515,10 @@ class NWProject:
516
515
  # Class Methods
517
516
  ##
518
517
 
519
- def updateWordCounts(self) -> None:
520
- """Update the total word count values."""
521
- novel, notes = self._tree.sumWords()
522
- self._data.setCurrCounts(novel=novel, notes=notes)
518
+ def updateCounts(self) -> None:
519
+ """Update the total word and character count values."""
520
+ wNovel, wNotes, cNovel, cNotes = self._tree.sumCounts()
521
+ self._data.setCurrCounts(wNovel=wNovel, wNotes=wNotes, cNovel=cNovel, cNotes=cNotes)
523
522
  return
524
523
 
525
524
  def countStatus(self) -> None:
@@ -561,13 +560,13 @@ class NWProject:
561
560
 
562
561
  def _loadProjectLocalisation(self) -> bool:
563
562
  """Load the language data for the current project language."""
564
- if self._data.language is None or CONFIG._nwLangPath is None:
563
+ if self._data.language is None or CONFIG.nwLangPath is None:
565
564
  self._langData = {}
566
565
  return False
567
566
 
568
- langFile = Path(CONFIG._nwLangPath) / f"project_{self._data.language}.json"
567
+ langFile = Path(CONFIG.nwLangPath) / f"project_{self._data.language}.json"
569
568
  if not langFile.is_file():
570
- langFile = Path(CONFIG._nwLangPath) / "project_en_GB.json"
569
+ langFile = Path(CONFIG.nwLangPath) / "project_en_GB.json"
571
570
 
572
571
  try:
573
572
  with open(langFile, mode="r", encoding="utf-8") as inFile: