novelWriter 2.1.1__py3-none-any.whl → 2.2rc1__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 (109) hide show
  1. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/METADATA +3 -3
  2. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/RECORD +105 -76
  3. novelwriter/__init__.py +6 -24
  4. novelwriter/assets/i18n/project_de_DE.json +10 -0
  5. novelwriter/assets/i18n/project_en_GB.json +11 -0
  6. novelwriter/assets/i18n/project_en_US.json +10 -0
  7. novelwriter/assets/i18n/project_ja_JP.json +11 -1
  8. novelwriter/assets/i18n/project_nb_NO.json +10 -0
  9. novelwriter/assets/i18n/project_nn_NO.json +10 -0
  10. novelwriter/assets/icons/novelwriter.ico +0 -0
  11. novelwriter/assets/icons/novelwriter.svg +8 -183
  12. novelwriter/assets/icons/typicons_dark/icons.conf +17 -2
  13. novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +4 -0
  14. novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +4 -0
  15. novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +4 -0
  16. novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +4 -0
  17. novelwriter/assets/icons/typicons_dark/nw_panel.svg +4 -0
  18. novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +4 -0
  19. novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +4 -0
  20. novelwriter/assets/icons/typicons_dark/nw_tb-markdown.svg +8 -0
  21. novelwriter/assets/icons/typicons_dark/nw_tb-shortcode.svg +8 -0
  22. novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +4 -0
  23. novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +5 -0
  24. novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +5 -0
  25. novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +5 -0
  26. novelwriter/assets/icons/typicons_dark/typ_eye.svg +4 -0
  27. novelwriter/assets/icons/typicons_dark/typ_th-dot-menu.svg +4 -0
  28. novelwriter/assets/icons/typicons_light/icons.conf +17 -2
  29. novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +4 -0
  30. novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +4 -0
  31. novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +4 -0
  32. novelwriter/assets/icons/typicons_light/nw_deco-note.svg +4 -0
  33. novelwriter/assets/icons/typicons_light/nw_panel.svg +4 -0
  34. novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +4 -0
  35. novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +4 -0
  36. novelwriter/assets/icons/typicons_light/nw_tb-markdown.svg +8 -0
  37. novelwriter/assets/icons/typicons_light/nw_tb-shortcode.svg +8 -0
  38. novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +4 -0
  39. novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +5 -0
  40. novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +5 -0
  41. novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +5 -0
  42. novelwriter/assets/icons/typicons_light/typ_eye.svg +4 -0
  43. novelwriter/assets/icons/typicons_light/typ_th-dot-menu.svg +4 -0
  44. novelwriter/assets/icons/x-novelwriter-project.ico +0 -0
  45. novelwriter/assets/icons/x-novelwriter-project.svg +7 -206
  46. novelwriter/assets/manual.pdf +0 -0
  47. novelwriter/assets/sample.zip +0 -0
  48. novelwriter/assets/syntax/default_dark.conf +1 -0
  49. novelwriter/assets/syntax/default_light.conf +1 -0
  50. novelwriter/assets/syntax/grey_dark.conf +1 -0
  51. novelwriter/assets/syntax/grey_light.conf +1 -0
  52. novelwriter/assets/syntax/light_owl.conf +1 -0
  53. novelwriter/assets/syntax/night_owl.conf +1 -0
  54. novelwriter/assets/syntax/solarized_dark.conf +1 -0
  55. novelwriter/assets/syntax/solarized_light.conf +1 -0
  56. novelwriter/assets/syntax/tomorrow.conf +1 -0
  57. novelwriter/assets/syntax/tomorrow_night.conf +1 -0
  58. novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
  59. novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
  60. novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
  61. novelwriter/assets/text/credits_en.htm +7 -0
  62. novelwriter/assets/text/release_notes.htm +7 -37
  63. novelwriter/common.py +22 -1
  64. novelwriter/config.py +27 -42
  65. novelwriter/constants.py +45 -7
  66. novelwriter/core/buildsettings.py +40 -24
  67. novelwriter/core/coretools.py +8 -1
  68. novelwriter/core/docbuild.py +2 -6
  69. novelwriter/core/index.py +264 -175
  70. novelwriter/core/options.py +8 -3
  71. novelwriter/core/project.py +2 -2
  72. novelwriter/core/projectdata.py +3 -3
  73. novelwriter/core/tohtml.py +60 -59
  74. novelwriter/core/tokenizer.py +110 -70
  75. novelwriter/core/tomd.py +51 -38
  76. novelwriter/core/toodt.py +184 -147
  77. novelwriter/dialogs/preferences.py +75 -106
  78. novelwriter/dialogs/projsettings.py +101 -110
  79. novelwriter/dialogs/updates.py +25 -14
  80. novelwriter/enum.py +28 -3
  81. novelwriter/extensions/novelselector.py +1 -1
  82. novelwriter/gui/doceditor.py +1345 -1235
  83. novelwriter/gui/dochighlight.py +98 -62
  84. novelwriter/gui/docviewer.py +151 -340
  85. novelwriter/gui/docviewerpanel.py +457 -0
  86. novelwriter/gui/editordocument.py +126 -0
  87. novelwriter/gui/mainmenu.py +350 -300
  88. novelwriter/gui/noveltree.py +101 -125
  89. novelwriter/gui/outline.py +154 -171
  90. novelwriter/gui/projtree.py +480 -380
  91. novelwriter/gui/sidebar.py +106 -75
  92. novelwriter/gui/statusbar.py +1 -1
  93. novelwriter/gui/theme.py +114 -75
  94. novelwriter/guimain.py +353 -254
  95. novelwriter/shared.py +36 -3
  96. novelwriter/tools/dictionaries.py +268 -0
  97. novelwriter/tools/manusbuild.py +17 -6
  98. novelwriter/tools/manuscript.py +11 -3
  99. novelwriter/tools/manussettings.py +0 -14
  100. novelwriter/tools/projwizard.py +16 -2
  101. novelwriter/tools/writingstats.py +1 -1
  102. novelwriter/assets/icons/typicons_dark/typ_at.svg +0 -4
  103. novelwriter/assets/icons/typicons_dark/typ_th-menu.svg +0 -4
  104. novelwriter/assets/icons/typicons_light/typ_at.svg +0 -4
  105. novelwriter/assets/icons/typicons_light/typ_th-menu.svg +0 -4
  106. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/LICENSE.md +0 -0
  107. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/WHEEL +0 -0
  108. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/entry_points.txt +0 -0
  109. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/top_level.txt +0 -0
@@ -59,8 +59,8 @@ class GuiOutlineView(QWidget):
59
59
  loadDocumentTagRequest = pyqtSignal(str, Enum)
60
60
  openDocumentRequest = pyqtSignal(str, Enum, str, bool)
61
61
 
62
- def __init__(self, mainGui):
63
- super().__init__(parent=mainGui)
62
+ def __init__(self, parent: QWidget) -> None:
63
+ super().__init__(parent=parent)
64
64
 
65
65
  # Build GUI
66
66
  self.outlineTree = GuiOutlineTree(self)
@@ -98,38 +98,33 @@ class GuiOutlineView(QWidget):
98
98
  # Methods
99
99
  ##
100
100
 
101
- def updateTheme(self):
102
- """Update theme elements.
103
- """
101
+ def updateTheme(self) -> None:
102
+ """Update theme elements."""
104
103
  self.outlineBar.updateTheme()
105
104
  self.refreshTree()
106
105
  return
107
106
 
108
- def initSettings(self):
109
- """Initialise GUI elements that depend on specific settings.
110
- """
107
+ def initSettings(self) -> None:
108
+ """Initialise GUI elements that depend on specific settings."""
111
109
  self.outlineTree.initSettings()
112
110
  self.outlineData.initSettings()
113
111
  return
114
112
 
115
- def refreshTree(self):
116
- """Refresh the current tree.
117
- """
113
+ def refreshTree(self) -> None:
114
+ """Refresh the current tree."""
118
115
  self.outlineTree.refreshTree(rootHandle=SHARED.project.data.getLastHandle("outline"))
119
116
  return
120
117
 
121
- def clearOutline(self):
122
- """Clear project-related GUI content.
123
- """
118
+ def clearOutline(self) -> None:
119
+ """Clear project-related GUI content."""
124
120
  self.outlineData.clearDetails()
125
121
  self.outlineBar.setEnabled(False)
126
122
  return
127
123
 
128
- def openProjectTasks(self):
129
- """Run open project tasks.
130
- """
124
+ def openProjectTasks(self) -> None:
125
+ """Run open project tasks."""
131
126
  lastOutline = SHARED.project.data.getLastHandle("outline")
132
- if not (lastOutline in SHARED.project.tree or lastOutline is None):
127
+ if not (lastOutline is None or lastOutline in SHARED.project.tree):
133
128
  lastOutline = SHARED.project.tree.findRoot(nwItemClass.NOVEL)
134
129
 
135
130
  logger.debug("Setting outline tree to root item '%s'", lastOutline)
@@ -141,23 +136,23 @@ class GuiOutlineView(QWidget):
141
136
 
142
137
  return
143
138
 
144
- def closeProjectTasks(self):
139
+ def closeProjectTasks(self) -> None:
140
+ """Run closing project tasks."""
145
141
  self.outlineTree.closeProjectTasks()
146
142
  self.outlineData.updateClasses()
147
143
  self.clearOutline()
148
144
  return
149
145
 
150
- def splitSizes(self):
146
+ def splitSizes(self) -> list[int]:
147
+ """Get the sizes of the splitter widget."""
151
148
  return self.splitOutline.sizes()
152
149
 
153
- def setTreeFocus(self):
154
- """Set the focus to the tree widget.
155
- """
150
+ def setTreeFocus(self) -> None:
151
+ """Set the focus to the tree widget."""
156
152
  return self.outlineTree.setFocus()
157
153
 
158
- def treeHasFocus(self):
159
- """Check if the outline tree has focus.
160
- """
154
+ def treeHasFocus(self) -> bool:
155
+ """Check if the outline tree has focus."""
161
156
  return self.outlineTree.hasFocus()
162
157
 
163
158
  ##
@@ -165,9 +160,8 @@ class GuiOutlineView(QWidget):
165
160
  ##
166
161
 
167
162
  @pyqtSlot(str)
168
- def updateRootItem(self, tHandle):
169
- """Should be called whenever a root folders changes.
170
- """
163
+ def updateRootItem(self, tHandle: str) -> None:
164
+ """Handle tasks whenever a root folders changes."""
171
165
  self.outlineBar.populateNovelList()
172
166
  self.outlineData.updateClasses()
173
167
  return
@@ -177,7 +171,7 @@ class GuiOutlineView(QWidget):
177
171
  ##
178
172
 
179
173
  @pyqtSlot()
180
- def _updateMenuColumns(self):
174
+ def _updateMenuColumns(self) -> None:
181
175
  """Trigger an update of the toggled state of the column menu
182
176
  checkboxes whenever a signal is received that the hidden state
183
177
  of columns has changed.
@@ -186,18 +180,16 @@ class GuiOutlineView(QWidget):
186
180
  return
187
181
 
188
182
  @pyqtSlot(str)
189
- def _tagClicked(self, link):
190
- """Capture the click of a tag in the details panel.
191
- """
183
+ def _tagClicked(self, link: str) -> None:
184
+ """Capture the click of a tag in the details panel."""
192
185
  if link:
193
186
  self.loadDocumentTagRequest.emit(link, nwDocMode.VIEW)
194
187
  return
195
188
 
196
189
  @pyqtSlot(str)
197
- def _rootItemChanged(self, handle):
198
- """The root novel handle has changed or needs to be refreshed.
199
- """
200
- self.outlineTree.refreshTree(rootHandle=(handle or None), overRide=True)
190
+ def _rootItemChanged(self, tHandle) -> None:
191
+ """Handle root novel changed or needs to be refreshed."""
192
+ self.outlineTree.refreshTree(rootHandle=(tHandle or None), overRide=True)
201
193
  return
202
194
 
203
195
  # END Class GuiOutlineView
@@ -208,8 +200,8 @@ class GuiOutlineToolBar(QToolBar):
208
200
  loadNovelRootRequest = pyqtSignal(str)
209
201
  viewColumnToggled = pyqtSignal(bool, Enum)
210
202
 
211
- def __init__(self, theOutline):
212
- super().__init__(parent=theOutline)
203
+ def __init__(self, outlineView: GuiOutlineView) -> None:
204
+ super().__init__(parent=outlineView)
213
205
 
214
206
  logger.debug("Create: GuiOutlineToolBar")
215
207
 
@@ -221,7 +213,7 @@ class GuiOutlineToolBar(QToolBar):
221
213
  self.setContentsMargins(0, 0, 0, 0)
222
214
 
223
215
  stretch = QWidget(self)
224
- stretch.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
216
+ stretch.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
225
217
 
226
218
  # Novel Selector
227
219
  self.novelLabel = QLabel(self.tr("Outline of"))
@@ -243,7 +235,7 @@ class GuiOutlineToolBar(QToolBar):
243
235
 
244
236
  self.tbColumns = QToolButton(self)
245
237
  self.tbColumns.setMenu(self.mColumns)
246
- self.tbColumns.setPopupMode(QToolButton.InstantPopup)
238
+ self.tbColumns.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
247
239
 
248
240
  # Assemble
249
241
  self.addWidget(self.novelLabel)
@@ -263,32 +255,27 @@ class GuiOutlineToolBar(QToolBar):
263
255
  # Methods
264
256
  ##
265
257
 
266
- def updateTheme(self):
267
- """Update theme elements.
268
- """
258
+ def updateTheme(self) -> None:
259
+ """Update theme elements."""
269
260
  self.setStyleSheet("QToolBar {border: 0px;}")
270
-
271
261
  self.novelValue.updateList(includeAll=True)
272
262
  self.aRefresh.setIcon(SHARED.theme.getIcon("refresh"))
273
263
  self.tbColumns.setIcon(SHARED.theme.getIcon("menu"))
274
-
264
+ self.tbColumns.setStyleSheet("QToolButton::menu-indicator {image: none;}")
275
265
  return
276
266
 
277
- def populateNovelList(self):
278
- """Reload the content of the novel list.
279
- """
267
+ def populateNovelList(self) -> None:
268
+ """Reload the content of the novel list."""
280
269
  self.novelValue.updateList(includeAll=True)
281
270
  return
282
271
 
283
- def setCurrentRoot(self, rootHandle):
284
- """Set the current active root handle.
285
- """
272
+ def setCurrentRoot(self, rootHandle: str | None) -> None:
273
+ """Set the current active root handle."""
286
274
  self.novelValue.setHandle(rootHandle)
287
275
  return
288
276
 
289
- def setColumnHiddenState(self, hiddenState):
290
- """Forward the change of column hidden states to the menu.
291
- """
277
+ def setColumnHiddenState(self, hiddenState: dict[nwOutline, bool]) -> None:
278
+ """Forward the change of column hidden states to the menu."""
292
279
  self.mColumns.setHiddenState(hiddenState)
293
280
  return
294
281
 
@@ -297,16 +284,14 @@ class GuiOutlineToolBar(QToolBar):
297
284
  ##
298
285
 
299
286
  @pyqtSlot(str)
300
- def _novelValueChanged(self, tHandle):
301
- """Emit a signal containing the handle of the selected item.
302
- """
287
+ def _novelValueChanged(self, tHandle: str) -> None:
288
+ """Emit a signal containing the handle of the selected item."""
303
289
  self.loadNovelRootRequest.emit(tHandle)
304
290
  return
305
291
 
306
292
  @pyqtSlot()
307
- def _refreshRequested(self):
308
- """Emit a signal containing the handle of the selected item.
309
- """
293
+ def _refreshRequested(self) -> None:
294
+ """Emit a signal containing the handle of the selected item."""
310
295
  self.loadNovelRootRequest.emit(self.novelValue.handle)
311
296
  return
312
297
 
@@ -361,7 +346,7 @@ class GuiOutlineTree(QTreeWidget):
361
346
  hiddenStateChanged = pyqtSignal()
362
347
  activeItemChanged = pyqtSignal(str, str)
363
348
 
364
- def __init__(self, outlineView):
349
+ def __init__(self, outlineView: GuiOutlineView) -> None:
365
350
  super().__init__(parent=outlineView)
366
351
 
367
352
  logger.debug("Create: GuiOutlineTree")
@@ -369,9 +354,9 @@ class GuiOutlineTree(QTreeWidget):
369
354
  self.outlineView = outlineView
370
355
 
371
356
  self.setUniformRowHeights(True)
372
- self.setFrameStyle(QFrame.NoFrame)
373
- self.setSelectionBehavior(QAbstractItemView.SelectRows)
374
- self.setSelectionMode(QAbstractItemView.SingleSelection)
357
+ self.setFrameStyle(QFrame.Shape.NoFrame)
358
+ self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
359
+ self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
375
360
  self.setExpandsOnDoubleClick(False)
376
361
  self.setDragEnabled(False)
377
362
  self.itemDoubleClicked.connect(self._treeDoubleClick)
@@ -392,13 +377,17 @@ class GuiOutlineTree(QTreeWidget):
392
377
  fH2 = self.font()
393
378
  fH2.setBold(True)
394
379
 
380
+ iType = nwItemType.FILE
381
+ iClass = nwItemClass.NO_CLASS
382
+ iLayout = nwItemLayout.DOCUMENT
383
+
395
384
  self._hFonts = [self.font(), fH1, fH2, self.font(), self.font()]
396
385
  self._dIcon = {
397
- "H0": SHARED.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H0"),
398
- "H1": SHARED.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H1"),
399
- "H2": SHARED.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H2"),
400
- "H3": SHARED.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H3"),
401
- "H4": SHARED.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H4"),
386
+ "H0": SHARED.theme.getItemIcon(iType, iClass, iLayout, "H0"),
387
+ "H1": SHARED.theme.getItemIcon(iType, iClass, iLayout, "H1"),
388
+ "H2": SHARED.theme.getItemIcon(iType, iClass, iLayout, "H2"),
389
+ "H3": SHARED.theme.getItemIcon(iType, iClass, iLayout, "H3"),
390
+ "H4": SHARED.theme.getItemIcon(iType, iClass, iLayout, "H4"),
402
391
  }
403
392
 
404
393
  # Internals
@@ -431,23 +420,19 @@ class GuiOutlineTree(QTreeWidget):
431
420
  # Methods
432
421
  ##
433
422
 
434
- def initSettings(self):
435
- """Set or update outline settings.
436
- """
437
- # Scroll bars
423
+ def initSettings(self) -> None:
424
+ """Set or update outline settings."""
438
425
  if CONFIG.hideVScroll:
439
- self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
426
+ self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
440
427
  else:
441
- self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
442
-
428
+ self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
443
429
  if CONFIG.hideHScroll:
444
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
430
+ self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
445
431
  else:
446
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
447
-
432
+ self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
448
433
  return
449
434
 
450
- def clearContent(self):
435
+ def clearContent(self) -> None:
451
436
  """Clear the tree and header and set the default values for the
452
437
  columns arrays.
453
438
  """
@@ -455,10 +440,10 @@ class GuiOutlineTree(QTreeWidget):
455
440
  self.setColumnCount(1)
456
441
  self.setHeaderLabel(trConst(nwLabels.OUTLINE_COLS[nwOutline.TITLE]))
457
442
 
458
- self._treeOrder = []
459
- self._colWidth = {}
460
- self._colHidden = {}
461
- self._colIdx = {}
443
+ self._treeOrder: list[nwOutline] = []
444
+ self._colWidth: dict[nwOutline, int] = {}
445
+ self._colHidden: dict[nwOutline, bool] = {}
446
+ self._colIdx: dict[nwOutline, int] = {}
462
447
  self._treeNCols = 0
463
448
 
464
449
  for hItem in nwOutline:
@@ -470,7 +455,8 @@ class GuiOutlineTree(QTreeWidget):
470
455
 
471
456
  return
472
457
 
473
- def refreshTree(self, rootHandle=None, overRide=False, novelChanged=False):
458
+ def refreshTree(self, rootHandle: str | None = None,
459
+ overRide: bool = False, novelChanged: bool = False) -> None:
474
460
  """Called whenever the Outline tab is activated and controls
475
461
  what data to load, and if necessary, force a rebuild of the
476
462
  tree.
@@ -494,15 +480,14 @@ class GuiOutlineTree(QTreeWidget):
494
480
 
495
481
  return
496
482
 
497
- def closeProjectTasks(self):
498
- """Called before a project is closed.
499
- """
483
+ def closeProjectTasks(self) -> None:
484
+ """Called before a project is closed."""
500
485
  self._saveHeaderState()
501
486
  self.clearContent()
502
487
  self._firstView = True
503
488
  return
504
489
 
505
- def getSelectedHandle(self):
490
+ def getSelectedHandle(self) -> tuple[str | None, str | None]:
506
491
  """Get the currently selected handle. If multiple items are
507
492
  selected, return the first.
508
493
  """
@@ -518,7 +503,7 @@ class GuiOutlineTree(QTreeWidget):
518
503
  ##
519
504
 
520
505
  @pyqtSlot("QTreeWidgetItem*", int)
521
- def _treeDoubleClick(self, tItem, tCol):
506
+ def _treeDoubleClick(self, tItem: QTreeWidgetItem, tCol: int) -> None:
522
507
  """Extract the handle and line number of the title double-
523
508
  clicked, and send it to the main gui class for opening in the
524
509
  document editor.
@@ -530,7 +515,7 @@ class GuiOutlineTree(QTreeWidget):
530
515
  return
531
516
 
532
517
  @pyqtSlot()
533
- def _itemSelected(self):
518
+ def _itemSelected(self) -> None:
534
519
  """Extract the handle and line number of the currently selected
535
520
  title, and send it to the details panel.
536
521
  """
@@ -542,7 +527,7 @@ class GuiOutlineTree(QTreeWidget):
542
527
  return
543
528
 
544
529
  @pyqtSlot(int, int, int)
545
- def _columnMoved(self, logIdx, oldVisualIdx, newVisualIdx):
530
+ def _columnMoved(self, logIdx: int, oldVisualIdx: int, newVisualIdx: int) -> None:
546
531
  """Make sure the order array is up to date with the actual order
547
532
  of the columns.
548
533
  """
@@ -551,12 +536,12 @@ class GuiOutlineTree(QTreeWidget):
551
536
  return
552
537
 
553
538
  @pyqtSlot(bool, Enum)
554
- def menuColumnToggled(self, isChecked, theItem):
539
+ def menuColumnToggled(self, isChecked: bool, hItem: nwOutline) -> None:
555
540
  """Receive the changes to column visibility forwarded by the
556
541
  column selection menu.
557
542
  """
558
- if theItem in self._colIdx:
559
- self.setColumnHidden(self._colIdx[theItem], not isChecked)
543
+ if hItem in self._colIdx:
544
+ self.setColumnHidden(self._colIdx[hItem], not isChecked)
560
545
  self._saveHeaderState()
561
546
  return
562
547
 
@@ -568,7 +553,7 @@ class GuiOutlineTree(QTreeWidget):
568
553
  """Load the state of the main tree header, that is, column order
569
554
  and column width.
570
555
  """
571
- # Load whatever we saved last time, regardless of wether it
556
+ # Load whatever we saved last time, regardless of whether it
572
557
  # contains the correct names or number of columns.
573
558
  colState = SHARED.project.options.getValue("GuiOutline", "columnState", {})
574
559
 
@@ -600,7 +585,7 @@ class GuiOutlineTree(QTreeWidget):
600
585
 
601
586
  return
602
587
 
603
- def _saveHeaderState(self):
588
+ def _saveHeaderState(self) -> None:
604
589
  """Save the state of the main tree header, that is, column
605
590
  order, column width and column hidden state. We don't want to
606
591
  save the current width of hidden columns though. This preserves
@@ -627,7 +612,7 @@ class GuiOutlineTree(QTreeWidget):
627
612
 
628
613
  return
629
614
 
630
- def _populateTree(self, rootHandle):
615
+ def _populateTree(self, rootHandle: str | None) -> None:
631
616
  """Build the tree based on the project index, and the header
632
617
  based on the defined constants, default values and user selected
633
618
  width, order and hidden state. All columns are populated, even
@@ -653,22 +638,25 @@ class GuiOutlineTree(QTreeWidget):
653
638
 
654
639
  headItem = self.headerItem()
655
640
  if isinstance(headItem, QTreeWidgetItem):
656
- headItem.setTextAlignment(self._colIdx[nwOutline.CCOUNT], Qt.AlignRight)
657
- headItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], Qt.AlignRight)
658
- headItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], Qt.AlignRight)
641
+ headItem.setTextAlignment(
642
+ self._colIdx[nwOutline.CCOUNT], Qt.AlignmentFlag.AlignRight)
643
+ headItem.setTextAlignment(
644
+ self._colIdx[nwOutline.WCOUNT], Qt.AlignmentFlag.AlignRight)
645
+ headItem.setTextAlignment(
646
+ self._colIdx[nwOutline.PCOUNT], Qt.AlignmentFlag.AlignRight)
659
647
 
660
648
  novStruct = SHARED.project.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
661
649
  for _, tHandle, sTitle, novIdx in novStruct:
662
650
 
663
651
  iLevel = nwHeaders.H_LEVEL.get(novIdx.level, 0)
664
- if iLevel == 0:
652
+ nwItem = SHARED.project.tree[tHandle]
653
+ if iLevel == 0 or nwItem is None:
665
654
  continue
666
655
 
667
656
  trItem = QTreeWidgetItem()
668
- nwItem = SHARED.project.tree[tHandle]
669
657
  hDec = SHARED.theme.getHeaderDecoration(iLevel)
670
658
 
671
- trItem.setData(self._colIdx[nwOutline.TITLE], Qt.DecorationRole, hDec)
659
+ trItem.setData(self._colIdx[nwOutline.TITLE], Qt.ItemDataRole.DecorationRole, hDec)
672
660
  trItem.setText(self._colIdx[nwOutline.TITLE], novIdx.title)
673
661
  trItem.setData(self._colIdx[nwOutline.TITLE], self.D_HANDLE, tHandle)
674
662
  trItem.setData(self._colIdx[nwOutline.TITLE], self.D_TITLE, sTitle)
@@ -681,9 +669,9 @@ class GuiOutlineTree(QTreeWidget):
681
669
  trItem.setText(self._colIdx[nwOutline.CCOUNT], f"{novIdx.charCount:n}")
682
670
  trItem.setText(self._colIdx[nwOutline.WCOUNT], f"{novIdx.wordCount:n}")
683
671
  trItem.setText(self._colIdx[nwOutline.PCOUNT], f"{novIdx.paraCount:n}")
684
- trItem.setTextAlignment(self._colIdx[nwOutline.CCOUNT], Qt.AlignRight)
685
- trItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], Qt.AlignRight)
686
- trItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], Qt.AlignRight)
672
+ trItem.setTextAlignment(self._colIdx[nwOutline.CCOUNT], Qt.AlignmentFlag.AlignRight)
673
+ trItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], Qt.AlignmentFlag.AlignRight)
674
+ trItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], Qt.AlignmentFlag.AlignRight)
687
675
 
688
676
  refs = SHARED.project.index.getReferences(tHandle, sTitle)
689
677
  trItem.setText(self._colIdx[nwOutline.POV], ", ".join(refs[nwKeyWords.POV_KEY]))
@@ -709,8 +697,8 @@ class GuiOutlineHeaderMenu(QMenu):
709
697
 
710
698
  columnToggled = pyqtSignal(bool, Enum)
711
699
 
712
- def __init__(self, theOutline):
713
- super().__init__(parent=theOutline)
700
+ def __init__(self, outlineToolBar: GuiOutlineToolBar) -> None:
701
+ super().__init__(parent=outlineToolBar)
714
702
 
715
703
  self.acceptToggle = True
716
704
 
@@ -731,7 +719,7 @@ class GuiOutlineHeaderMenu(QMenu):
731
719
 
732
720
  return
733
721
 
734
- def setHiddenState(self, hiddenState):
722
+ def setHiddenState(self, hiddenState: dict[nwOutline, bool]) -> None:
735
723
  """Overwrite the checked state of the columns as the inverse of
736
724
  the hidden state. Skip the TITLE column as it cannot be hidden.
737
725
  """
@@ -760,12 +748,12 @@ class GuiOutlineDetails(QScrollArea):
760
748
 
761
749
  itemTagClicked = pyqtSignal(str)
762
750
 
763
- def __init__(self, theOutline):
764
- super().__init__(parent=theOutline)
751
+ def __init__(self, outlineView: GuiOutlineView) -> None:
752
+ super().__init__(parent=outlineView)
765
753
 
766
754
  logger.debug("Create: GuiOutlineDetails")
767
755
 
768
- self.theOutline = theOutline
756
+ self.outlineView = outlineView
769
757
 
770
758
  # Sizes
771
759
  minTitle = 30*SHARED.theme.textNWidth
@@ -878,23 +866,26 @@ class GuiOutlineDetails(QScrollArea):
878
866
 
879
867
  # Selected Item Details
880
868
  self.mainGroup = QGroupBox(self.tr("Title Details"), self)
881
- self.mainForm = QGridLayout()
869
+ self.mainForm = QGridLayout()
882
870
  self.mainGroup.setLayout(self.mainForm)
883
871
 
884
- self.mainForm.addWidget(self.titleLabel, 0, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
885
- self.mainForm.addWidget(self.titleValue, 0, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
886
- self.mainForm.addWidget(self.cCLabel, 0, 2, 1, 1, Qt.AlignTop | Qt.AlignLeft)
887
- self.mainForm.addWidget(self.cCValue, 0, 3, 1, 1, Qt.AlignTop | Qt.AlignRight)
888
- self.mainForm.addWidget(self.fileLabel, 1, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
889
- self.mainForm.addWidget(self.fileValue, 1, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
890
- self.mainForm.addWidget(self.wCLabel, 1, 2, 1, 1, Qt.AlignTop | Qt.AlignLeft)
891
- self.mainForm.addWidget(self.wCValue, 1, 3, 1, 1, Qt.AlignTop | Qt.AlignRight)
892
- self.mainForm.addWidget(self.itemLabel, 2, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
893
- self.mainForm.addWidget(self.itemValue, 2, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
894
- self.mainForm.addWidget(self.pCLabel, 2, 2, 1, 1, Qt.AlignTop | Qt.AlignLeft)
895
- self.mainForm.addWidget(self.pCValue, 2, 3, 1, 1, Qt.AlignTop | Qt.AlignRight)
896
- self.mainForm.addWidget(self.synopLabel, 3, 0, 1, 4, Qt.AlignTop | Qt.AlignLeft)
897
- self.mainForm.addLayout(self.synopLWrap, 4, 0, 1, 4, Qt.AlignTop | Qt.AlignLeft)
872
+ topLeft = Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignLeft
873
+ topRight = Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignRight
874
+
875
+ self.mainForm.addWidget(self.titleLabel, 0, 0, 1, 1, topLeft)
876
+ self.mainForm.addWidget(self.titleValue, 0, 1, 1, 1, topLeft)
877
+ self.mainForm.addWidget(self.cCLabel, 0, 2, 1, 1, topLeft)
878
+ self.mainForm.addWidget(self.cCValue, 0, 3, 1, 1, topRight)
879
+ self.mainForm.addWidget(self.fileLabel, 1, 0, 1, 1, topLeft)
880
+ self.mainForm.addWidget(self.fileValue, 1, 1, 1, 1, topLeft)
881
+ self.mainForm.addWidget(self.wCLabel, 1, 2, 1, 1, topLeft)
882
+ self.mainForm.addWidget(self.wCValue, 1, 3, 1, 1, topRight)
883
+ self.mainForm.addWidget(self.itemLabel, 2, 0, 1, 1, topLeft)
884
+ self.mainForm.addWidget(self.itemValue, 2, 1, 1, 1, topLeft)
885
+ self.mainForm.addWidget(self.pCLabel, 2, 2, 1, 1, topLeft)
886
+ self.mainForm.addWidget(self.pCValue, 2, 3, 1, 1, topRight)
887
+ self.mainForm.addWidget(self.synopLabel, 3, 0, 1, 4, topLeft)
888
+ self.mainForm.addLayout(self.synopLWrap, 4, 0, 1, 4, topLeft)
898
889
 
899
890
  self.mainForm.setColumnStretch(1, 1)
900
891
  self.mainForm.setRowStretch(4, 1)
@@ -906,24 +897,24 @@ class GuiOutlineDetails(QScrollArea):
906
897
  self.tagsForm = QGridLayout()
907
898
  self.tagsGroup.setLayout(self.tagsForm)
908
899
 
909
- self.tagsForm.addWidget(self.povKeyLabel, 0, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
910
- self.tagsForm.addLayout(self.povKeyLWrap, 0, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
911
- self.tagsForm.addWidget(self.focKeyLabel, 1, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
912
- self.tagsForm.addLayout(self.focKeyLWrap, 1, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
913
- self.tagsForm.addWidget(self.chrKeyLabel, 2, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
914
- self.tagsForm.addLayout(self.chrKeyLWrap, 2, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
915
- self.tagsForm.addWidget(self.pltKeyLabel, 3, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
916
- self.tagsForm.addLayout(self.pltKeyLWrap, 3, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
917
- self.tagsForm.addWidget(self.timKeyLabel, 4, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
918
- self.tagsForm.addLayout(self.timKeyLWrap, 4, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
919
- self.tagsForm.addWidget(self.wldKeyLabel, 5, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
920
- self.tagsForm.addLayout(self.wldKeyLWrap, 5, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
921
- self.tagsForm.addWidget(self.objKeyLabel, 6, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
922
- self.tagsForm.addLayout(self.objKeyLWrap, 6, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
923
- self.tagsForm.addWidget(self.entKeyLabel, 7, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
924
- self.tagsForm.addLayout(self.entKeyLWrap, 7, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
925
- self.tagsForm.addWidget(self.cstKeyLabel, 8, 0, 1, 1, Qt.AlignTop | Qt.AlignLeft)
926
- self.tagsForm.addLayout(self.cstKeyLWrap, 8, 1, 1, 1, Qt.AlignTop | Qt.AlignLeft)
900
+ self.tagsForm.addWidget(self.povKeyLabel, 0, 0, 1, 1, topLeft)
901
+ self.tagsForm.addLayout(self.povKeyLWrap, 0, 1, 1, 1, topLeft)
902
+ self.tagsForm.addWidget(self.focKeyLabel, 1, 0, 1, 1, topLeft)
903
+ self.tagsForm.addLayout(self.focKeyLWrap, 1, 1, 1, 1, topLeft)
904
+ self.tagsForm.addWidget(self.chrKeyLabel, 2, 0, 1, 1, topLeft)
905
+ self.tagsForm.addLayout(self.chrKeyLWrap, 2, 1, 1, 1, topLeft)
906
+ self.tagsForm.addWidget(self.pltKeyLabel, 3, 0, 1, 1, topLeft)
907
+ self.tagsForm.addLayout(self.pltKeyLWrap, 3, 1, 1, 1, topLeft)
908
+ self.tagsForm.addWidget(self.timKeyLabel, 4, 0, 1, 1, topLeft)
909
+ self.tagsForm.addLayout(self.timKeyLWrap, 4, 1, 1, 1, topLeft)
910
+ self.tagsForm.addWidget(self.wldKeyLabel, 5, 0, 1, 1, topLeft)
911
+ self.tagsForm.addLayout(self.wldKeyLWrap, 5, 1, 1, 1, topLeft)
912
+ self.tagsForm.addWidget(self.objKeyLabel, 6, 0, 1, 1, topLeft)
913
+ self.tagsForm.addLayout(self.objKeyLWrap, 6, 1, 1, 1, topLeft)
914
+ self.tagsForm.addWidget(self.entKeyLabel, 7, 0, 1, 1, topLeft)
915
+ self.tagsForm.addLayout(self.entKeyLWrap, 7, 1, 1, 1, topLeft)
916
+ self.tagsForm.addWidget(self.cstKeyLabel, 8, 0, 1, 1, topLeft)
917
+ self.tagsForm.addLayout(self.cstKeyLWrap, 8, 1, 1, 1, topLeft)
927
918
 
928
919
  self.tagsForm.setColumnStretch(1, 1)
929
920
  self.tagsForm.setRowStretch(8, 1)
@@ -939,10 +930,10 @@ class GuiOutlineDetails(QScrollArea):
939
930
  self.outerWidget.setLayout(self.outerBox)
940
931
  self.setWidget(self.outerWidget)
941
932
 
942
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
943
- self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
933
+ self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
934
+ self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
944
935
  self.setWidgetResizable(True)
945
- self.setFrameStyle(QFrame.NoFrame)
936
+ self.setFrameStyle(QFrame.Shape.NoFrame)
946
937
 
947
938
  self.initSettings()
948
939
 
@@ -950,27 +941,21 @@ class GuiOutlineDetails(QScrollArea):
950
941
 
951
942
  return
952
943
 
953
- def initSettings(self):
954
- """Set or update outline settings.
955
- """
956
- # Scroll bars
944
+ def initSettings(self) -> None:
945
+ """Set or update outline settings."""
957
946
  if CONFIG.hideVScroll:
958
- self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
947
+ self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
959
948
  else:
960
- self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
961
-
949
+ self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
962
950
  if CONFIG.hideHScroll:
963
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
951
+ self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
964
952
  else:
965
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
966
-
953
+ self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
967
954
  self.updateClasses()
968
-
969
955
  return
970
956
 
971
- def clearDetails(self):
972
- """Clear all the data labels.
973
- """
957
+ def clearDetails(self) -> None:
958
+ """Clear all the data labels."""
974
959
  self.titleLabel.setText("<b>%s</b>" % self.tr("Title"))
975
960
  self.titleValue.setText("")
976
961
  self.fileValue.setText("")
@@ -996,7 +981,7 @@ class GuiOutlineDetails(QScrollArea):
996
981
  ##
997
982
 
998
983
  @pyqtSlot(str, str)
999
- def showItem(self, tHandle, sTitle):
984
+ def showItem(self, tHandle: str, sTitle: str) -> bool:
1000
985
  """Update the content of the tree with the given handle and line
1001
986
  number pointing to a header.
1002
987
  """
@@ -1041,9 +1026,8 @@ class GuiOutlineDetails(QScrollArea):
1041
1026
  return True
1042
1027
 
1043
1028
  @pyqtSlot()
1044
- def updateClasses(self):
1045
- """Update the visibility status of class details.
1046
- """
1029
+ def updateClasses(self) -> None:
1030
+ """Update the visibility status of class details."""
1047
1031
  usedClasses = SHARED.project.tree.rootClasses()
1048
1032
 
1049
1033
  pltVisible = nwItemClass.PLOT in usedClasses
@@ -1069,9 +1053,8 @@ class GuiOutlineDetails(QScrollArea):
1069
1053
  return
1070
1054
 
1071
1055
  @staticmethod
1072
- def _formatTags(refs, key):
1073
- """Convert a list of tags into a list of clickable tag links.
1074
- """
1056
+ def _formatTags(refs: dict[str, list[str]], key: str) -> str:
1057
+ """Convert a list of tags into a list of clickable tag links."""
1075
1058
  return ", ".join(
1076
1059
  [f"<a href='{tag}'>{tag}</a>" for tag in refs.get(key, [])]
1077
1060
  )