novelWriter 2.7.5__py3-none-any.whl → 2.8b1__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 (196) hide show
  1. novelwriter/__init__.py +8 -7
  2. novelwriter/assets/icons/font_awesome.icons +22 -4
  3. novelwriter/assets/icons/material_filled_normal.icons +20 -2
  4. novelwriter/assets/icons/material_filled_thin.icons +20 -2
  5. novelwriter/assets/icons/material_rounded_normal.icons +20 -2
  6. novelwriter/assets/icons/material_rounded_thin.icons +20 -2
  7. novelwriter/assets/icons/material_sharp_normal.icons +20 -2
  8. novelwriter/assets/icons/material_sharp_thin.icons +20 -2
  9. novelwriter/assets/icons/remix_filled.icons +20 -2
  10. novelwriter/assets/icons/remix_outline.icons +20 -2
  11. novelwriter/assets/images/welcome.webp +0 -0
  12. novelwriter/assets/manual.pdf +0 -0
  13. novelwriter/assets/manual_fr.pdf +0 -0
  14. novelwriter/assets/sample.zip +0 -0
  15. novelwriter/assets/text/credits_en.htm +61 -11
  16. novelwriter/assets/themes/aura.conf +97 -0
  17. novelwriter/assets/themes/aura_bright.conf +95 -0
  18. novelwriter/assets/themes/aura_soft.conf +97 -0
  19. novelwriter/assets/themes/b2t_garden_dark.conf +97 -0
  20. novelwriter/assets/themes/b2t_garden_light.conf +97 -0
  21. novelwriter/assets/themes/b2t_suburb_dark.conf +97 -0
  22. novelwriter/assets/themes/b2t_suburb_light.conf +97 -0
  23. novelwriter/assets/themes/b4t_classic_o_dark.conf +97 -0
  24. novelwriter/assets/themes/b4t_classic_o_light.conf +97 -0
  25. novelwriter/assets/themes/b4t_modern_c_dark.conf +97 -0
  26. novelwriter/assets/themes/b4t_modern_c_light.conf +97 -0
  27. novelwriter/assets/themes/blue_streak_dark.conf +97 -0
  28. novelwriter/assets/themes/blue_streak_light.conf +97 -0
  29. novelwriter/assets/themes/castle_day.conf +95 -0
  30. novelwriter/assets/themes/castle_night.conf +95 -0
  31. novelwriter/assets/themes/catppuccin_latte.conf +97 -0
  32. novelwriter/assets/themes/catppuccin_mocha.conf +97 -0
  33. novelwriter/assets/themes/chalky_soil.conf +95 -0
  34. novelwriter/assets/themes/chernozem.conf +95 -0
  35. novelwriter/assets/themes/cyberpunk_night.conf +88 -40
  36. novelwriter/assets/themes/default_dark.conf +89 -41
  37. novelwriter/assets/themes/default_light.conf +89 -41
  38. novelwriter/assets/themes/dracula.conf +91 -42
  39. novelwriter/assets/themes/espresso.conf +97 -0
  40. novelwriter/assets/themes/everforest_dark.conf +97 -0
  41. novelwriter/assets/themes/everforest_light.conf +97 -0
  42. novelwriter/assets/themes/floral_daydream.conf +95 -0
  43. novelwriter/assets/themes/floral_midnight.conf +95 -0
  44. novelwriter/assets/themes/full_moon.conf +95 -0
  45. novelwriter/assets/themes/grey_dark.conf +97 -0
  46. novelwriter/assets/themes/grey_light.conf +97 -0
  47. novelwriter/assets/themes/horizon_dark.conf +97 -0
  48. novelwriter/assets/themes/horizon_light.conf +97 -0
  49. novelwriter/assets/themes/jewel_case_dark.conf +95 -0
  50. novelwriter/assets/themes/jewel_case_light.conf +95 -0
  51. novelwriter/assets/themes/lcars.conf +97 -0
  52. novelwriter/assets/themes/light_owl.conf +117 -0
  53. novelwriter/assets/themes/new_moon.conf +97 -0
  54. novelwriter/assets/themes/night_owl.conf +117 -0
  55. novelwriter/assets/themes/noctis.conf +129 -0
  56. novelwriter/assets/themes/noctis_lux.conf +129 -0
  57. novelwriter/assets/themes/nord.conf +97 -0
  58. novelwriter/assets/themes/nordlicht.conf +95 -0
  59. novelwriter/assets/themes/otium_dark.conf +95 -0
  60. novelwriter/assets/themes/otium_light.conf +95 -0
  61. novelwriter/assets/themes/paragon.conf +96 -0
  62. novelwriter/assets/themes/primer_light.conf +97 -0
  63. novelwriter/assets/themes/primer_night.conf +97 -0
  64. novelwriter/assets/themes/rose_pine.conf +97 -0
  65. novelwriter/assets/themes/rose_pine_dawn.conf +97 -0
  66. novelwriter/assets/themes/ruby_day.conf +95 -0
  67. novelwriter/assets/themes/ruby_night.conf +95 -0
  68. novelwriter/assets/themes/selenium_dark.conf +95 -0
  69. novelwriter/assets/themes/selenium_light.conf +95 -0
  70. novelwriter/assets/themes/sepia_dark.conf +95 -0
  71. novelwriter/assets/themes/sepia_light.conf +95 -0
  72. novelwriter/assets/themes/snazzy.conf +102 -40
  73. novelwriter/assets/themes/solarized_dark.conf +108 -40
  74. novelwriter/assets/themes/solarized_light.conf +108 -40
  75. novelwriter/assets/themes/sultana_light.conf +95 -0
  76. novelwriter/assets/themes/sultana_night.conf +95 -0
  77. novelwriter/assets/themes/tango_dark.conf +111 -0
  78. novelwriter/assets/themes/tango_light.conf +111 -0
  79. novelwriter/assets/themes/tomorrow.conf +117 -0
  80. novelwriter/assets/themes/tomorrow_night.conf +117 -0
  81. novelwriter/assets/themes/tomorrow_night_blue.conf +117 -0
  82. novelwriter/assets/themes/tomorrow_night_bright.conf +117 -0
  83. novelwriter/assets/themes/tomorrow_night_eighties.conf +117 -0
  84. novelwriter/assets/themes/vivid_black_green.conf +97 -0
  85. novelwriter/assets/themes/vivid_black_red.conf +97 -0
  86. novelwriter/assets/themes/vivid_white_green.conf +97 -0
  87. novelwriter/assets/themes/vivid_white_red.conf +97 -0
  88. novelwriter/assets/themes/warpgate.conf +96 -0
  89. novelwriter/assets/themes/waterlily_dark.conf +95 -0
  90. novelwriter/assets/themes/waterlily_light.conf +95 -0
  91. novelwriter/common.py +47 -17
  92. novelwriter/config.py +57 -62
  93. novelwriter/constants.py +32 -6
  94. novelwriter/core/buildsettings.py +3 -23
  95. novelwriter/core/coretools.py +21 -25
  96. novelwriter/core/docbuild.py +4 -9
  97. novelwriter/core/document.py +2 -6
  98. novelwriter/core/index.py +33 -53
  99. novelwriter/core/indexdata.py +17 -22
  100. novelwriter/core/item.py +11 -35
  101. novelwriter/core/itemmodel.py +5 -21
  102. novelwriter/core/novelmodel.py +3 -7
  103. novelwriter/core/options.py +3 -4
  104. novelwriter/core/project.py +31 -21
  105. novelwriter/core/projectdata.py +2 -21
  106. novelwriter/core/projectxml.py +13 -21
  107. novelwriter/core/sessions.py +2 -4
  108. novelwriter/core/spellcheck.py +12 -13
  109. novelwriter/core/status.py +27 -20
  110. novelwriter/core/storage.py +5 -10
  111. novelwriter/core/tree.py +6 -15
  112. novelwriter/dialogs/about.py +9 -10
  113. novelwriter/dialogs/docmerge.py +17 -14
  114. novelwriter/dialogs/docsplit.py +18 -14
  115. novelwriter/dialogs/editlabel.py +15 -9
  116. novelwriter/dialogs/preferences.py +69 -68
  117. novelwriter/dialogs/projectsettings.py +88 -67
  118. novelwriter/dialogs/quotes.py +15 -10
  119. novelwriter/dialogs/wordlist.py +18 -21
  120. novelwriter/enum.py +75 -30
  121. novelwriter/error.py +6 -11
  122. novelwriter/extensions/configlayout.py +8 -34
  123. novelwriter/extensions/eventfilters.py +3 -3
  124. novelwriter/extensions/modified.py +87 -32
  125. novelwriter/extensions/novelselector.py +13 -12
  126. novelwriter/extensions/pagedsidebar.py +10 -18
  127. novelwriter/extensions/progressbars.py +5 -11
  128. novelwriter/extensions/statusled.py +3 -6
  129. novelwriter/extensions/switch.py +8 -11
  130. novelwriter/extensions/switchbox.py +2 -11
  131. novelwriter/extensions/versioninfo.py +6 -7
  132. novelwriter/formats/shared.py +10 -2
  133. novelwriter/formats/todocx.py +15 -37
  134. novelwriter/formats/tohtml.py +52 -61
  135. novelwriter/formats/tokenizer.py +33 -64
  136. novelwriter/formats/tomarkdown.py +4 -11
  137. novelwriter/formats/toodt.py +12 -71
  138. novelwriter/formats/toqdoc.py +11 -21
  139. novelwriter/formats/toraw.py +2 -6
  140. novelwriter/gui/doceditor.py +160 -225
  141. novelwriter/gui/dochighlight.py +142 -101
  142. novelwriter/gui/docviewer.py +53 -84
  143. novelwriter/gui/docviewerpanel.py +18 -41
  144. novelwriter/gui/editordocument.py +12 -17
  145. novelwriter/gui/itemdetails.py +5 -14
  146. novelwriter/gui/mainmenu.py +24 -32
  147. novelwriter/gui/noveltree.py +13 -51
  148. novelwriter/gui/outline.py +20 -61
  149. novelwriter/gui/projtree.py +40 -96
  150. novelwriter/gui/search.py +9 -24
  151. novelwriter/gui/sidebar.py +54 -22
  152. novelwriter/gui/statusbar.py +7 -22
  153. novelwriter/gui/theme.py +482 -368
  154. novelwriter/guimain.py +87 -101
  155. novelwriter/shared.py +79 -48
  156. novelwriter/splash.py +9 -5
  157. novelwriter/text/comments.py +1 -1
  158. novelwriter/text/counting.py +9 -5
  159. novelwriter/text/patterns.py +20 -15
  160. novelwriter/tools/dictionaries.py +18 -16
  161. novelwriter/tools/lipsum.py +15 -17
  162. novelwriter/tools/manusbuild.py +25 -45
  163. novelwriter/tools/manuscript.py +94 -95
  164. novelwriter/tools/manussettings.py +149 -104
  165. novelwriter/tools/noveldetails.py +10 -24
  166. novelwriter/tools/welcome.py +24 -72
  167. novelwriter/tools/writingstats.py +17 -26
  168. novelwriter/types.py +23 -13
  169. {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/METADATA +7 -7
  170. novelwriter-2.8b1.dist-info/RECORD +212 -0
  171. novelwriter/assets/images/welcome-dark.jpg +0 -0
  172. novelwriter/assets/images/welcome-light.jpg +0 -0
  173. novelwriter/assets/syntax/cyberpunk_night.conf +0 -28
  174. novelwriter/assets/syntax/default_dark.conf +0 -42
  175. novelwriter/assets/syntax/default_light.conf +0 -42
  176. novelwriter/assets/syntax/dracula.conf +0 -44
  177. novelwriter/assets/syntax/grey_dark.conf +0 -29
  178. novelwriter/assets/syntax/grey_light.conf +0 -29
  179. novelwriter/assets/syntax/light_owl.conf +0 -49
  180. novelwriter/assets/syntax/night_owl.conf +0 -49
  181. novelwriter/assets/syntax/snazzy.conf +0 -42
  182. novelwriter/assets/syntax/solarized_dark.conf +0 -29
  183. novelwriter/assets/syntax/solarized_light.conf +0 -29
  184. novelwriter/assets/syntax/tango.conf +0 -39
  185. novelwriter/assets/syntax/tomorrow.conf +0 -49
  186. novelwriter/assets/syntax/tomorrow_night.conf +0 -49
  187. novelwriter/assets/syntax/tomorrow_night_blue.conf +0 -49
  188. novelwriter/assets/syntax/tomorrow_night_bright.conf +0 -49
  189. novelwriter/assets/syntax/tomorrow_night_eighties.conf +0 -49
  190. novelwriter/assets/themes/default.conf +0 -3
  191. novelwriter-2.7.5.dist-info/RECORD +0 -163
  192. {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/WHEEL +0 -0
  193. {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/entry_points.txt +0 -0
  194. {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/licenses/LICENSE.md +0 -0
  195. {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/licenses/setup/LICENSE-Apache-2.0.txt +0 -0
  196. {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/top_level.txt +0 -0
@@ -25,7 +25,7 @@ General Public License for more details.
25
25
 
26
26
  You should have received a copy of the GNU General Public License
27
27
  along with this program. If not, see <https://www.gnu.org/licenses/>.
28
- """
28
+ """ # noqa
29
29
  from __future__ import annotations
30
30
 
31
31
  import logging
@@ -61,7 +61,9 @@ logger = logging.getLogger(__name__)
61
61
 
62
62
 
63
63
  class GuiProjectView(QWidget):
64
- """This is a wrapper class holding all the elements of the project
64
+ """GUI: Project View.
65
+
66
+ This is a wrapper class holding all the elements of the project
65
67
  tree. The core object is the project tree itself. Most methods
66
68
  available are mapped through to the project tree class.
67
69
  """
@@ -130,28 +132,24 @@ class GuiProjectView(QWidget):
130
132
  # Function Mappings
131
133
  self.getSelectedHandle = self.projTree.getSelectedHandle
132
134
 
133
- return
134
-
135
135
  ##
136
136
  # Methods
137
137
  ##
138
138
 
139
139
  def updateTheme(self) -> None:
140
140
  """Update theme elements."""
141
+ logger.debug("Theme Update: GuiProjectView")
141
142
  self.projBar.updateTheme()
142
- return
143
143
 
144
144
  def initSettings(self) -> None:
145
145
  """Initialise GUI elements that depend on specific settings."""
146
146
  self.projTree.initSettings()
147
- return
148
147
 
149
148
  def closeProjectTasks(self) -> None:
150
149
  """Clear project-related GUI content."""
151
150
  self.projBar.clearContent()
152
151
  self.projBar.setEnabled(False)
153
152
  self.projTree.clearTree()
154
- return
155
153
 
156
154
  def openProjectTasks(self) -> None:
157
155
  """Run open project tasks."""
@@ -159,26 +157,23 @@ class GuiProjectView(QWidget):
159
157
  self.projBar.buildTemplatesMenu()
160
158
  self.projBar.buildQuickLinksMenu()
161
159
  self.projBar.setEnabled(True)
162
- return
163
160
 
164
161
  def setTreeFocus(self) -> None:
165
162
  """Forward the set focus call to the tree widget."""
166
163
  self.projTree.setFocus()
167
- return
168
164
 
169
165
  def treeHasFocus(self) -> bool:
170
166
  """Check if the project tree has focus."""
171
167
  return self.projTree.hasFocus()
172
168
 
173
169
  def connectMenuActions(self, rename: QAction, delete: QAction, trash: QAction) -> None:
174
- """Main menu actions passed to the project tree."""
170
+ """Connect main menu actions passed to the project tree."""
175
171
  self.projTree.addAction(rename)
176
172
  self.projTree.addAction(delete)
177
173
  self.projTree.addAction(trash)
178
174
  rename.triggered.connect(self.renameTreeItem)
179
175
  delete.triggered.connect(self.projTree.processDeleteRequest)
180
176
  trash.triggered.connect(self.projTree.emptyTrash)
181
- return
182
177
 
183
178
  ##
184
179
  # Public Slots
@@ -197,41 +192,36 @@ class GuiProjectView(QWidget):
197
192
  if dlgOk:
198
193
  nwItem.setName(newLabel)
199
194
  nwItem.notifyToRefresh()
200
- return
201
195
 
202
196
  @pyqtSlot(str, bool)
203
197
  def setSelectedHandle(self, tHandle: str, doScroll: bool = False) -> None:
204
198
  """Select an item and optionally scroll it into view."""
205
199
  self.projTree.setSelectedHandle(tHandle, doScroll=doScroll)
206
- return
207
200
 
208
201
  @pyqtSlot(str)
209
202
  def setActiveHandle(self, tHandle: str | None) -> None:
210
203
  """Highlight the active handle."""
211
204
  self.projTree.setActiveHandle(tHandle)
212
- return
213
205
 
214
206
  @pyqtSlot(str, Enum)
215
207
  def onProjectItemChanged(self, tHandle: str, change: nwChange) -> None:
216
208
  """Refresh other content when project item changed."""
217
209
  self.projBar.processTemplateDocuments(tHandle)
218
- return
219
210
 
220
211
  @pyqtSlot(str)
221
212
  def createFileFromTemplate(self, tHandle: str) -> None:
222
213
  """Create a new document from a template."""
223
214
  logger.debug("Template selected: '%s'", tHandle)
224
215
  self.projTree.newTreeItem(nwItemType.FILE, copyDoc=tHandle)
225
- return
226
216
 
227
217
  @pyqtSlot(str, Enum)
228
218
  def updateRootItem(self, tHandle: str, change: nwChange) -> None:
229
219
  """Process root item changes."""
230
220
  self.projBar.buildQuickLinksMenu()
231
- return
232
221
 
233
222
 
234
223
  class GuiProjectToolBar(QWidget):
224
+ """GUI> Project View ToolBar."""
235
225
 
236
226
  newDocumentFromTemplate = pyqtSignal(str)
237
227
 
@@ -351,14 +341,14 @@ class GuiProjectToolBar(QWidget):
351
341
 
352
342
  logger.debug("Ready: GuiProjectToolBar")
353
343
 
354
- return
355
-
356
344
  ##
357
345
  # Methods
358
346
  ##
359
347
 
360
348
  def updateTheme(self) -> None:
361
349
  """Update theme elements."""
350
+ logger.debug("Theme Update: GuiProjectToolBar")
351
+
362
352
  buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON)
363
353
  self.tbQuick.setStyleSheet(buttonStyle)
364
354
  self.tbMoveU.setStyleSheet(buttonStyle)
@@ -366,11 +356,11 @@ class GuiProjectToolBar(QWidget):
366
356
  self.tbAdd.setStyleSheet(buttonStyle)
367
357
  self.tbMore.setStyleSheet(buttonStyle)
368
358
 
369
- self.tbQuick.setThemeIcon("bookmarks", "blue")
370
- self.tbMoveU.setThemeIcon("chevron_up", "blue")
371
- self.tbMoveD.setThemeIcon("chevron_down", "blue")
372
- self.tbAdd.setThemeIcon("add", "green")
373
- self.tbMore.setThemeIcon("more_vertical")
359
+ self.tbQuick.setThemeIcon("bookmarks", "action")
360
+ self.tbMoveU.setThemeIcon("chevron_up", "action")
361
+ self.tbMoveD.setThemeIcon("chevron_down", "action")
362
+ self.tbAdd.setThemeIcon("add", "add")
363
+ self.tbMore.setThemeIcon("more_vertical", "default")
374
364
 
375
365
  self.aAddScene.setIcon(SHARED.theme.getIcon("prj_scene", "scene"))
376
366
  self.aAddChap.setIcon(SHARED.theme.getIcon("prj_chapter", "chapter"))
@@ -383,13 +373,10 @@ class GuiProjectToolBar(QWidget):
383
373
  self.buildQuickLinksMenu()
384
374
  self._buildRootMenu()
385
375
 
386
- return
387
-
388
376
  def clearContent(self) -> None:
389
377
  """Clear dynamic content on the tool bar."""
390
378
  self.mQuick.clear()
391
379
  self.mTemplates.clearMenu()
392
- return
393
380
 
394
381
  def buildQuickLinksMenu(self) -> None:
395
382
  """Build the quick link menu."""
@@ -402,14 +389,12 @@ class GuiProjectToolBar(QWidget):
402
389
  action.triggered.connect(
403
390
  qtLambda(self.projView.setSelectedHandle, tHandle, doScroll=True)
404
391
  )
405
- return
406
392
 
407
393
  def buildTemplatesMenu(self) -> None:
408
394
  """Build the templates menu."""
409
395
  for tHandle, _ in SHARED.project.tree.iterRoots(nwItemClass.TEMPLATE):
410
396
  for dHandle in SHARED.project.tree.subTree(tHandle):
411
397
  self.processTemplateDocuments(dHandle)
412
- return
413
398
 
414
399
  def processTemplateDocuments(self, tHandle: str) -> None:
415
400
  """Process change in tree items to update menu content."""
@@ -418,7 +403,6 @@ class GuiProjectToolBar(QWidget):
418
403
  self.mTemplates.addUpdate(tHandle, item.itemName, item.getMainIcon())
419
404
  elif tHandle in self.mTemplates:
420
405
  self.mTemplates.remove(tHandle)
421
- return
422
406
 
423
407
  ##
424
408
  # Public Slots
@@ -436,7 +420,6 @@ class GuiProjectToolBar(QWidget):
436
420
  self.aAddChap.setVisible(allowDoc)
437
421
  self.aAddPart.setVisible(allowDoc)
438
422
  self.aAddEmpty.setVisible(allowDoc)
439
- return
440
423
 
441
424
  ##
442
425
  # Internal Functions
@@ -451,7 +434,6 @@ class GuiProjectToolBar(QWidget):
451
434
  qtLambda(self.projTree.newTreeItem, nwItemType.ROOT, itemClass)
452
435
  )
453
436
  self.mAddRoot.addAction(aNew)
454
- return
455
437
 
456
438
  self.mAddRoot.clear()
457
439
  addClass(nwItemClass.NOVEL)
@@ -467,10 +449,9 @@ class GuiProjectToolBar(QWidget):
467
449
  addClass(nwItemClass.ARCHIVE)
468
450
  addClass(nwItemClass.TEMPLATE)
469
451
 
470
- return
471
-
472
452
 
473
453
  class GuiProjectTree(QTreeView):
454
+ """GUI: Project View Tree."""
474
455
 
475
456
  def __init__(self, projView: GuiProjectView) -> None:
476
457
  super().__init__(parent=projView)
@@ -520,8 +501,6 @@ class GuiProjectTree(QTreeView):
520
501
 
521
502
  logger.debug("Ready: GuiProjectTree")
522
503
 
523
- return
524
-
525
504
  def initSettings(self) -> None:
526
505
  """Set or update tree widget settings."""
527
506
  if CONFIG.hideVScroll:
@@ -532,7 +511,6 @@ class GuiProjectTree(QTreeView):
532
511
  self.setHorizontalScrollBarPolicy(QtScrollAlwaysOff)
533
512
  else:
534
513
  self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
535
- return
536
514
 
537
515
  ##
538
516
  # External Methods
@@ -541,7 +519,6 @@ class GuiProjectTree(QTreeView):
541
519
  def setActiveHandle(self, tHandle: str | None) -> None:
542
520
  """Set the handle to be highlighted."""
543
521
  self._actHandle = tHandle
544
- return
545
522
 
546
523
  def getSelectedHandle(self) -> str | None:
547
524
  """Get the currently selected handle."""
@@ -556,7 +533,6 @@ class GuiProjectTree(QTreeView):
556
533
  def clearTree(self) -> None:
557
534
  """Clear the tree view."""
558
535
  self.setModel(None)
559
- return
560
536
 
561
537
  def loadModel(self) -> None:
562
538
  """Load and prepare a new project model."""
@@ -583,8 +559,6 @@ class GuiProjectTree(QTreeView):
583
559
 
584
560
  self.restoreExpandedState()
585
561
 
586
- return
587
-
588
562
  def restoreExpandedState(self) -> None:
589
563
  """Expand all nodes that were previously expanded."""
590
564
  if model := self._getModel():
@@ -592,7 +566,6 @@ class GuiProjectTree(QTreeView):
592
566
  for index in model.allExpanded():
593
567
  self.setExpanded(index, True)
594
568
  self.blockSignals(False)
595
- return
596
569
 
597
570
  def setSelectedHandle(self, tHandle: str | None, doScroll: bool = False) -> None:
598
571
  """Set a specific handle as the selected item."""
@@ -601,7 +574,6 @@ class GuiProjectTree(QTreeView):
601
574
  if doScroll:
602
575
  self.scrollTo(index, QAbstractItemView.ScrollHint.PositionAtCenter)
603
576
  self.projView.selectedItemChanged.emit(tHandle)
604
- return
605
577
 
606
578
  def newTreeItem(
607
579
  self, itemType: nwItemType, itemClass: nwItemClass | None = None,
@@ -667,7 +639,7 @@ class GuiProjectTree(QTreeView):
667
639
  if itemType == nwItemType.FILE:
668
640
  if tHandle := SHARED.project.newFile(newLabel, sHandle, sPos):
669
641
  if copyDoc:
670
- SHARED.project.copyFileContent(tHandle, copyDoc)
642
+ SHARED.project.copyFileContent(tHandle, copyDoc, newLabel)
671
643
  elif hLevel > 0:
672
644
  SHARED.project.writeNewFile(tHandle, hLevel, not nNote)
673
645
  SHARED.project.index.reIndexHandle(tHandle)
@@ -718,9 +690,15 @@ class GuiProjectTree(QTreeView):
718
690
  else:
719
691
  return False
720
692
 
693
+ SHARED.initMainProgress(len(items))
694
+ self.setEnabled(False)
721
695
  for sHandle in items:
696
+ SHARED.incMainProgress()
722
697
  docMerger.appendText(sHandle, True, mLabel)
723
698
 
699
+ self.setEnabled(True)
700
+ SHARED.clearMainProgress()
701
+
724
702
  if not docMerger.writeTargetDoc():
725
703
  SHARED.error(
726
704
  self.tr("Could not write document content."),
@@ -764,7 +742,10 @@ class GuiProjectTree(QTreeView):
764
742
  docSplit.setParentItem(tItem.itemParent)
765
743
 
766
744
  docSplit.splitDocument(headerList, text)
745
+ SHARED.initMainProgress(len(docSplit))
746
+ self.setEnabled(False)
767
747
  for writeOk in docSplit.writeDocuments(docHierarchy):
748
+ SHARED.incMainProgress()
768
749
  if not writeOk:
769
750
  SHARED.error(
770
751
  self.tr("Could not write document content."),
@@ -774,6 +755,9 @@ class GuiProjectTree(QTreeView):
774
755
  if data.get("moveToTrash", False):
775
756
  self.processDeleteRequest([tHandle], False)
776
757
 
758
+ self.setEnabled(True)
759
+ SHARED.clearMainProgress()
760
+
777
761
  return True
778
762
 
779
763
  def duplicateFromHandle(self, tHandle: str) -> None:
@@ -786,12 +770,13 @@ class GuiProjectTree(QTreeView):
786
770
  else:
787
771
  question = self.tr("Do you want to duplicate this item and all child items?")
788
772
  if SHARED.question(question):
773
+ self.setEnabled(False)
789
774
  docDup = DocDuplicator(SHARED.project)
790
775
  dHandles = docDup.duplicate(itemTree)
791
776
  if len(dHandles) != len(itemTree):
792
777
  SHARED.warn(self.tr("Could not duplicate all items."))
778
+ self.setEnabled(True)
793
779
  self.restoreExpandedState()
794
- return
795
780
 
796
781
  ##
797
782
  # Events and Overloads
@@ -811,14 +796,12 @@ class GuiProjectTree(QTreeView):
811
796
  self.projView.openDocumentRequest.emit(
812
797
  node.item.itemHandle, nwDocMode.VIEW, "", False
813
798
  )
814
- return
815
799
 
816
800
  def drawRow(self, painter: QPainter, opt: QStyleOptionViewItem, index: QModelIndex) -> None:
817
801
  """Draw a box on the active row."""
818
802
  if (node := self._getNode(index)) and node.item.itemHandle == self._actHandle:
819
803
  painter.fillRect(opt.rect, self.palette().alternateBase())
820
804
  super().drawRow(painter, opt, index)
821
- return
822
805
 
823
806
  ##
824
807
  # Public Slots
@@ -829,14 +812,12 @@ class GuiProjectTree(QTreeView):
829
812
  """Move an item up in the tree."""
830
813
  if model := self._getModel():
831
814
  model.internalMove(self.currentIndex(), -1)
832
- return
833
815
 
834
816
  @pyqtSlot()
835
817
  def moveItemDown(self) -> None:
836
818
  """Move an item down in the tree."""
837
819
  if model := self._getModel():
838
820
  model.internalMove(self.currentIndex(), 1)
839
- return
840
821
 
841
822
  @pyqtSlot()
842
823
  def goToSiblingUp(self) -> None:
@@ -844,7 +825,6 @@ class GuiProjectTree(QTreeView):
844
825
  if (node := self._getNode(self.currentIndex())) and (parent := node.parent()):
845
826
  if (move := parent.child(node.row() - 1)) and (model := self._getModel()):
846
827
  self.setCurrentIndex(model.indexFromNode(move))
847
- return
848
828
 
849
829
  @pyqtSlot()
850
830
  def goToSiblingDown(self) -> None:
@@ -852,7 +832,6 @@ class GuiProjectTree(QTreeView):
852
832
  if (node := self._getNode(self.currentIndex())) and (parent := node.parent()):
853
833
  if (move := parent.child(node.row() + 1)) and (model := self._getModel()):
854
834
  self.setCurrentIndex(model.indexFromNode(move))
855
- return
856
835
 
857
836
  @pyqtSlot()
858
837
  def goToParent(self) -> None:
@@ -863,7 +842,6 @@ class GuiProjectTree(QTreeView):
863
842
  and (parent := node.parent())
864
843
  ):
865
844
  self.setCurrentIndex(model.indexFromNode(parent))
866
- return
867
845
 
868
846
  @pyqtSlot()
869
847
  def goToFirstChild(self) -> None:
@@ -874,13 +852,11 @@ class GuiProjectTree(QTreeView):
874
852
  and (child := node.child(0))
875
853
  ):
876
854
  self.setCurrentIndex(model.indexFromNode(child))
877
- return
878
855
 
879
856
  @pyqtSlot(QModelIndex)
880
857
  def expandFromIndex(self, index: QModelIndex) -> None:
881
858
  """Expand all nodes from index."""
882
859
  self.expandRecursively(index)
883
- return
884
860
 
885
861
  @pyqtSlot(QModelIndex)
886
862
  def collapseFromIndex(self, index: QModelIndex) -> None:
@@ -888,7 +864,6 @@ class GuiProjectTree(QTreeView):
888
864
  if (model := self._getModel()) and (node := model.node(index)):
889
865
  for child in node.allChildren():
890
866
  self.setExpanded(model.indexFromNode(child), False)
891
- return
892
867
 
893
868
  @pyqtSlot()
894
869
  def processDeleteRequest(
@@ -912,17 +887,23 @@ class GuiProjectTree(QTreeView):
912
887
  if not SHARED.question(self.tr("Permanently delete selected item(s)?")):
913
888
  logger.info("Action cancelled by user")
914
889
  return
890
+
891
+ self.setEnabled(False)
915
892
  for index in indices:
916
893
  if node := model.node(index):
917
894
  for child in reversed(node.allChildren()):
918
895
  SHARED.project.removeItem(child.item.itemHandle)
919
896
  SHARED.project.removeItem(node.item.itemHandle)
897
+ self.setEnabled(True)
920
898
 
921
899
  elif trashNode := SHARED.project.tree.trash:
922
900
  if askFirst and not SHARED.question(self.tr("Move selected item(s) to Trash?")):
923
901
  logger.info("Action cancelled by user")
924
902
  return
903
+
904
+ self.setEnabled(False)
925
905
  model.multiMove(indices, model.indexFromNode(trashNode))
906
+ self.setEnabled(True)
926
907
 
927
908
  return
928
909
 
@@ -948,9 +929,7 @@ class GuiProjectTree(QTreeView):
948
929
  @pyqtSlot()
949
930
  @pyqtSlot("QPoint")
950
931
  def openContextMenu(self, point: QPoint | None = None) -> None:
951
- """The user right clicked an element in the project tree, so we
952
- open a context menu in-place.
953
- """
932
+ """Open a context menu in-place where the user clicked."""
954
933
  if model := self._getModel():
955
934
  if point is None:
956
935
  point = self.visualRect(self.currentIndex()).center()
@@ -967,7 +946,6 @@ class GuiProjectTree(QTreeView):
967
946
  if viewport := self.viewport():
968
947
  ctxMenu.exec(viewport.mapToGlobal(point))
969
948
  ctxMenu.setParent(None)
970
- return
971
949
 
972
950
  ##
973
951
  # Private Slots
@@ -975,10 +953,9 @@ class GuiProjectTree(QTreeView):
975
953
 
976
954
  @pyqtSlot(QModelIndex, QModelIndex)
977
955
  def _onSelectionChange(self, current: QModelIndex, previous: QModelIndex) -> None:
978
- """The user changed which item is selected."""
956
+ """Process user changing which item is selected."""
979
957
  if node := self._getNode(current):
980
958
  self.projView.selectedItemChanged.emit(node.item.itemHandle)
981
- return
982
959
 
983
960
  @pyqtSlot(QModelIndex)
984
961
  def _onDoubleClick(self, index: QModelIndex) -> None:
@@ -992,21 +969,18 @@ class GuiProjectTree(QTreeView):
992
969
  )
993
970
  else:
994
971
  self.setExpanded(index, not self.isExpanded(index))
995
- return
996
972
 
997
973
  @pyqtSlot(QModelIndex)
998
974
  def _onNodeCollapsed(self, index: QModelIndex) -> None:
999
975
  """Capture a node collapse, and pass it to the model."""
1000
976
  if node := self._getNode(index):
1001
977
  node.setExpanded(False)
1002
- return
1003
978
 
1004
979
  @pyqtSlot(QModelIndex)
1005
980
  def _onNodeExpanded(self, index: QModelIndex) -> None:
1006
981
  """Capture a node expand, and pass it to the model."""
1007
982
  if node := self._getNode(index):
1008
983
  node.setExpanded(True)
1009
- return
1010
984
 
1011
985
  ##
1012
986
  # Internal Functions
@@ -1018,7 +992,6 @@ class GuiProjectTree(QTreeView):
1018
992
  if model := self.selectionModel():
1019
993
  # Selection model can be None (#2173)
1020
994
  model.clearCurrentIndex()
1021
- return
1022
995
 
1023
996
  def _selectedRows(self) -> list[QModelIndex]:
1024
997
  """Return all column 0 indexes."""
@@ -1046,7 +1019,6 @@ class _UpdatableMenu(QMenu):
1046
1019
  self._map: dict[str, QAction] = {}
1047
1020
  self.setTitle(self.tr("From Template"))
1048
1021
  self.triggered.connect(self._actionTriggered)
1049
- return
1050
1022
 
1051
1023
  def __contains__(self, tHandle: str) -> bool:
1052
1024
  """Look up a handle in the menu."""
@@ -1068,7 +1040,6 @@ class _UpdatableMenu(QMenu):
1068
1040
  self.addAction(action)
1069
1041
  self._map[tHandle] = action
1070
1042
  self.setActionsVisible(True)
1071
- return
1072
1043
 
1073
1044
  def remove(self, tHandle: str) -> None:
1074
1045
  """Remove a template item."""
@@ -1076,19 +1047,16 @@ class _UpdatableMenu(QMenu):
1076
1047
  self.removeAction(action)
1077
1048
  if not self._map:
1078
1049
  self.setActionsVisible(False)
1079
- return
1080
1050
 
1081
1051
  def clearMenu(self) -> None:
1082
1052
  """Clear all menu content."""
1083
1053
  self._map.clear()
1084
1054
  self.clear()
1085
- return
1086
1055
 
1087
1056
  def setActionsVisible(self, value: bool) -> None:
1088
1057
  """Set the visibility of root action."""
1089
1058
  if action := self.menuAction():
1090
1059
  action.setVisible(value)
1091
- return
1092
1060
 
1093
1061
  ##
1094
1062
  # Private Slots
@@ -1098,7 +1066,6 @@ class _UpdatableMenu(QMenu):
1098
1066
  def _actionTriggered(self, action: QAction) -> None:
1099
1067
  """Translate the menu trigger into an item trigger."""
1100
1068
  self.menuItemTriggered.emit(str(action.data()))
1101
- return
1102
1069
 
1103
1070
 
1104
1071
  class _TreeContextMenu(QMenu):
@@ -1119,11 +1086,9 @@ class _TreeContextMenu(QMenu):
1119
1086
  self._indices = indices
1120
1087
  self._children = node.childCount() > 0
1121
1088
  logger.debug("Ready: _TreeContextMenu")
1122
- return
1123
1089
 
1124
1090
  def __del__(self) -> None: # pragma: no cover
1125
1091
  logger.debug("Delete: _TreeContextMenu")
1126
- return
1127
1092
 
1128
1093
  ##
1129
1094
  # Methods
@@ -1135,7 +1100,6 @@ class _TreeContextMenu(QMenu):
1135
1100
  action.triggered.connect(self._tree.emptyTrash)
1136
1101
  if self._children:
1137
1102
  self._expandCollapse()
1138
- return
1139
1103
 
1140
1104
  def buildSingleSelectMenu(self) -> None:
1141
1105
  """Build the single-select menu."""
@@ -1171,15 +1135,12 @@ class _TreeContextMenu(QMenu):
1171
1135
  action.triggered.connect(qtLambda(self._tree.duplicateFromHandle, self._handle))
1172
1136
  self._deleteOrTrash()
1173
1137
 
1174
- return
1175
-
1176
1138
  def buildMultiSelectMenu(self) -> None:
1177
1139
  """Build the multi-select menu."""
1178
1140
  self._itemActive()
1179
1141
  self._itemStatusImport(True)
1180
1142
  self.addSeparator()
1181
1143
  self._deleteOrTrash()
1182
- return
1183
1144
 
1184
1145
  ##
1185
1146
  # Menu Builders
@@ -1197,7 +1158,6 @@ class _TreeContextMenu(QMenu):
1197
1158
  self._view.openDocumentRequest.emit,
1198
1159
  self._handle, nwDocMode.VIEW, "", False
1199
1160
  ))
1200
- return
1201
1161
 
1202
1162
  def _itemCreation(self) -> None:
1203
1163
  """Add create item actions."""
@@ -1208,7 +1168,6 @@ class _TreeContextMenu(QMenu):
1208
1168
  menu.addAction(self._view.projBar.aAddEmpty)
1209
1169
  menu.addAction(self._view.projBar.aAddNote)
1210
1170
  menu.addAction(self._view.projBar.aAddFolder)
1211
- return
1212
1171
 
1213
1172
  def _itemHeader(self) -> None:
1214
1173
  """Check if there is a header that can be used for rename."""
@@ -1218,22 +1177,20 @@ class _TreeContextMenu(QMenu):
1218
1177
  action.triggered.connect(
1219
1178
  qtLambda(self._view.renameTreeItem, self._handle, hItem.title)
1220
1179
  )
1221
- return
1222
1180
 
1223
1181
  def _itemActive(self) -> None:
1224
1182
  """Add Active/Inactive actions."""
1225
1183
  if len(self._indices) > 1:
1226
1184
  mSub = qtAddMenu(self, self.tr("Set Active to ..."))
1227
1185
  aOne = qtAddAction(mSub, self._tree.trActive)
1228
- aOne.setIcon(SHARED.theme.getIcon("checked", "green"))
1186
+ aOne.setIcon(SHARED.theme.getIcon("checked", "accept"))
1229
1187
  aOne.triggered.connect(qtLambda(self._iterItemActive, True))
1230
1188
  aTwo = qtAddAction(mSub, self._tree.trInactive)
1231
- aTwo.setIcon(SHARED.theme.getIcon("unchecked", "red"))
1189
+ aTwo.setIcon(SHARED.theme.getIcon("unchecked", "reject"))
1232
1190
  aTwo.triggered.connect(qtLambda(self._iterItemActive, False))
1233
1191
  else:
1234
1192
  action = qtAddAction(self, self.tr("Toggle Active"))
1235
1193
  action.triggered.connect(self._toggleItemActive)
1236
- return
1237
1194
 
1238
1195
  def _itemStatusImport(self, multi: bool) -> None:
1239
1196
  """Add actions for changing status or importance."""
@@ -1275,7 +1232,6 @@ class _TreeContextMenu(QMenu):
1275
1232
  self._view.projectSettingsRequest.emit,
1276
1233
  GuiProjectSettings.PAGE_IMPORT
1277
1234
  ))
1278
- return
1279
1235
 
1280
1236
  def _itemTransform(self, isFile: bool, isFolder: bool) -> None:
1281
1237
  """Add actions for the Transform menu."""
@@ -1318,15 +1274,12 @@ class _TreeContextMenu(QMenu):
1318
1274
  action = qtAddAction(menu, self.tr("Split Document by Headings"))
1319
1275
  action.triggered.connect(qtLambda(self._tree.splitDocument, self._handle))
1320
1276
 
1321
- return
1322
-
1323
1277
  def _expandCollapse(self) -> None:
1324
1278
  """Add actions for expand and collapse."""
1325
1279
  action = qtAddAction(self, self.tr("Expand All"))
1326
1280
  action.triggered.connect(qtLambda(self._tree.expandFromIndex, self._indices[0]))
1327
1281
  action = qtAddAction(self, self.tr("Collapse All"))
1328
1282
  action.triggered.connect(qtLambda(self._tree.collapseFromIndex, self._indices[0]))
1329
- return
1330
1283
 
1331
1284
  def _deleteOrTrash(self) -> None:
1332
1285
  """Add move to Trash action."""
@@ -1339,7 +1292,6 @@ class _TreeContextMenu(QMenu):
1339
1292
  text = self.tr("Move to Trash")
1340
1293
  action = qtAddAction(self, text)
1341
1294
  action.triggered.connect(self._tree.processDeleteRequest)
1342
- return
1343
1295
 
1344
1296
  ##
1345
1297
  # Private Slots
@@ -1351,7 +1303,6 @@ class _TreeContextMenu(QMenu):
1351
1303
  if self._item.isFileType():
1352
1304
  self._item.setActive(not self._item.isActive)
1353
1305
  self._item.notifyToRefresh()
1354
- return
1355
1306
 
1356
1307
  ##
1357
1308
  # Internal Functions
@@ -1365,13 +1316,11 @@ class _TreeContextMenu(QMenu):
1365
1316
  node.item.setActive(state)
1366
1317
  refresh.append(node.item.itemHandle)
1367
1318
  SHARED.project.tree.refreshItems(refresh)
1368
- return
1369
1319
 
1370
1320
  def _changeItemStatus(self, key: str) -> None:
1371
1321
  """Set a new status value of an item."""
1372
1322
  self._item.setStatus(key)
1373
1323
  self._item.notifyToRefresh()
1374
- return
1375
1324
 
1376
1325
  def _iterSetItemStatus(self, key: str) -> None:
1377
1326
  """Change the status value for multiple items."""
@@ -1381,13 +1330,11 @@ class _TreeContextMenu(QMenu):
1381
1330
  node.item.setStatus(key)
1382
1331
  refresh.append(node.item.itemHandle)
1383
1332
  SHARED.project.tree.refreshItems(refresh)
1384
- return
1385
1333
 
1386
1334
  def _changeItemImport(self, key: str) -> None:
1387
1335
  """Set a new importance value of an item."""
1388
1336
  self._item.setImport(key)
1389
1337
  self._item.notifyToRefresh()
1390
- return
1391
1338
 
1392
1339
  def _iterSetItemImport(self, key: str) -> None:
1393
1340
  """Change the status value for multiple items."""
@@ -1397,7 +1344,6 @@ class _TreeContextMenu(QMenu):
1397
1344
  node.item.setImport(key)
1398
1345
  refresh.append(node.item.itemHandle)
1399
1346
  SHARED.project.tree.refreshItems(refresh)
1400
- return
1401
1347
 
1402
1348
  def _changeItemLayout(self, itemLayout: nwItemLayout) -> None:
1403
1349
  """Set a new item layout value of an item."""
@@ -1408,7 +1354,6 @@ class _TreeContextMenu(QMenu):
1408
1354
  elif itemLayout == nwItemLayout.NOTE:
1409
1355
  self._item.setLayout(nwItemLayout.NOTE)
1410
1356
  self._item.notifyToRefresh()
1411
- return
1412
1357
 
1413
1358
  def _convertFolderToFile(self, itemLayout: nwItemLayout) -> None:
1414
1359
  """Convert a folder to a note or document."""
@@ -1428,4 +1373,3 @@ class _TreeContextMenu(QMenu):
1428
1373
  self._item.notifyToRefresh()
1429
1374
  else:
1430
1375
  logger.info("Folder conversion cancelled")
1431
- return