novelWriter 2.2b1__py3-none-any.whl → 2.2.1__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 (134) hide show
  1. {novelWriter-2.2b1.dist-info → novelWriter-2.2.1.dist-info}/METADATA +3 -3
  2. {novelWriter-2.2b1.dist-info → novelWriter-2.2.1.dist-info}/RECORD +128 -114
  3. {novelWriter-2.2b1.dist-info → novelWriter-2.2.1.dist-info}/WHEEL +1 -1
  4. novelwriter/__init__.py +10 -5
  5. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  6. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  7. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  8. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  9. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  10. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  11. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  12. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  13. novelwriter/assets/i18n/project_de_DE.json +1 -0
  14. novelwriter/assets/i18n/project_en_GB.json +1 -0
  15. novelwriter/assets/i18n/project_en_US.json +1 -0
  16. novelwriter/assets/i18n/project_es_419.json +11 -0
  17. novelwriter/assets/i18n/project_fr_FR.json +11 -0
  18. novelwriter/assets/i18n/project_it_IT.json +11 -0
  19. novelwriter/assets/i18n/project_ja_JP.json +2 -1
  20. novelwriter/assets/i18n/project_nb_NO.json +1 -0
  21. novelwriter/assets/i18n/project_zh_CN.json +11 -0
  22. novelwriter/assets/icons/novelwriter.ico +0 -0
  23. novelwriter/assets/icons/typicons_dark/icons.conf +11 -3
  24. novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +4 -0
  25. novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +4 -0
  26. novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +4 -0
  27. novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +4 -0
  28. novelwriter/assets/icons/typicons_dark/nw_panel.svg +4 -0
  29. novelwriter/assets/icons/typicons_dark/nw_tb-bold-md.svg +4 -0
  30. novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +3 -1
  31. novelwriter/assets/icons/typicons_dark/nw_tb-italic-md.svg +4 -0
  32. novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +3 -1
  33. novelwriter/assets/icons/typicons_dark/nw_tb-strike-md.svg +4 -0
  34. novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +3 -1
  35. novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +4 -2
  36. novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +4 -2
  37. novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +4 -2
  38. novelwriter/assets/icons/typicons_dark/typ_eye.svg +4 -0
  39. novelwriter/assets/icons/typicons_light/icons.conf +11 -3
  40. novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +4 -0
  41. novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +4 -0
  42. novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +4 -0
  43. novelwriter/assets/icons/typicons_light/nw_deco-note.svg +4 -0
  44. novelwriter/assets/icons/typicons_light/nw_panel.svg +4 -0
  45. novelwriter/assets/icons/typicons_light/nw_tb-bold-md.svg +4 -0
  46. novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +3 -1
  47. novelwriter/assets/icons/typicons_light/nw_tb-italic-md.svg +4 -0
  48. novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +3 -1
  49. novelwriter/assets/icons/typicons_light/nw_tb-strike-md.svg +4 -0
  50. novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +3 -1
  51. novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +4 -2
  52. novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +4 -2
  53. novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +4 -2
  54. novelwriter/assets/icons/typicons_light/typ_eye.svg +4 -0
  55. novelwriter/assets/icons/x-novelwriter-project.ico +0 -0
  56. novelwriter/assets/manual.pdf +0 -0
  57. novelwriter/assets/sample.zip +0 -0
  58. novelwriter/assets/text/release_notes.htm +50 -7
  59. novelwriter/common.py +35 -27
  60. novelwriter/config.py +13 -28
  61. novelwriter/constants.py +21 -4
  62. novelwriter/core/buildsettings.py +2 -2
  63. novelwriter/core/coretools.py +8 -2
  64. novelwriter/core/docbuild.py +1 -1
  65. novelwriter/core/document.py +1 -1
  66. novelwriter/core/index.py +102 -36
  67. novelwriter/core/item.py +2 -2
  68. novelwriter/core/options.py +6 -3
  69. novelwriter/core/project.py +5 -5
  70. novelwriter/core/projectdata.py +3 -3
  71. novelwriter/core/projectxml.py +1 -1
  72. novelwriter/core/sessions.py +2 -2
  73. novelwriter/core/spellcheck.py +4 -3
  74. novelwriter/core/status.py +3 -3
  75. novelwriter/core/storage.py +1 -1
  76. novelwriter/core/tohtml.py +11 -5
  77. novelwriter/core/tokenizer.py +28 -21
  78. novelwriter/core/tomd.py +6 -2
  79. novelwriter/core/toodt.py +12 -5
  80. novelwriter/core/tree.py +2 -2
  81. novelwriter/dialogs/about.py +30 -31
  82. novelwriter/dialogs/docmerge.py +24 -15
  83. novelwriter/dialogs/docsplit.py +27 -16
  84. novelwriter/dialogs/editlabel.py +19 -7
  85. novelwriter/dialogs/preferences.py +116 -131
  86. novelwriter/dialogs/projdetails.py +29 -36
  87. novelwriter/dialogs/projload.py +32 -36
  88. novelwriter/dialogs/projsettings.py +20 -15
  89. novelwriter/dialogs/quotes.py +32 -25
  90. novelwriter/dialogs/updates.py +17 -16
  91. novelwriter/dialogs/wordlist.py +34 -21
  92. novelwriter/enum.py +19 -8
  93. novelwriter/error.py +1 -1
  94. novelwriter/extensions/circularprogress.py +1 -1
  95. novelwriter/extensions/configlayout.py +3 -15
  96. novelwriter/extensions/{wheeleventfilter.py → eventfilters.py} +15 -5
  97. novelwriter/extensions/novelselector.py +1 -1
  98. novelwriter/extensions/pageddialog.py +1 -1
  99. novelwriter/extensions/pagedsidebar.py +2 -5
  100. novelwriter/extensions/simpleprogress.py +8 -9
  101. novelwriter/extensions/statusled.py +1 -1
  102. novelwriter/extensions/switch.py +4 -4
  103. novelwriter/extensions/switchbox.py +1 -6
  104. novelwriter/gui/doceditor.py +349 -236
  105. novelwriter/gui/dochighlight.py +10 -11
  106. novelwriter/gui/docviewer.py +158 -360
  107. novelwriter/gui/docviewerpanel.py +502 -0
  108. novelwriter/gui/editordocument.py +4 -4
  109. novelwriter/gui/itemdetails.py +2 -2
  110. novelwriter/gui/mainmenu.py +50 -36
  111. novelwriter/gui/noveltree.py +44 -53
  112. novelwriter/gui/outline.py +12 -7
  113. novelwriter/gui/projtree.py +465 -381
  114. novelwriter/gui/sidebar.py +9 -7
  115. novelwriter/gui/statusbar.py +48 -5
  116. novelwriter/gui/theme.py +26 -8
  117. novelwriter/guimain.py +212 -208
  118. novelwriter/shared.py +76 -30
  119. novelwriter/tools/dictionaries.py +268 -0
  120. novelwriter/tools/lipsum.py +34 -28
  121. novelwriter/tools/manusbuild.py +20 -10
  122. novelwriter/tools/manuscript.py +20 -27
  123. novelwriter/tools/manussettings.py +2 -4
  124. novelwriter/tools/projwizard.py +3 -3
  125. novelwriter/tools/writingstats.py +18 -5
  126. novelwriter/assets/icons/typicons_dark/nw_tb-markdown.svg +0 -8
  127. novelwriter/assets/icons/typicons_dark/nw_tb-shortcode.svg +0 -8
  128. novelwriter/assets/icons/typicons_dark/typ_at.svg +0 -4
  129. novelwriter/assets/icons/typicons_light/nw_tb-markdown.svg +0 -8
  130. novelwriter/assets/icons/typicons_light/nw_tb-shortcode.svg +0 -8
  131. novelwriter/assets/icons/typicons_light/typ_at.svg +0 -4
  132. {novelWriter-2.2b1.dist-info → novelWriter-2.2.1.dist-info}/LICENSE.md +0 -0
  133. {novelWriter-2.2b1.dist-info → novelWriter-2.2.1.dist-info}/entry_points.txt +0 -0
  134. {novelWriter-2.2b1.dist-info → novelWriter-2.2.1.dist-info}/top_level.txt +0 -0
@@ -3,10 +3,10 @@ novelWriter – GUI Preferences
3
3
  =============================
4
4
 
5
5
  File History:
6
- Created: 2019-06-10 [0.1.5]
6
+ Created: 2019-06-10 [0.1.5] GuiPreferences
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2023, Veronica Berglyd Olsen
9
+ Copyright 2018–2024, Veronica Berglyd Olsen
10
10
 
11
11
  This program is free software: you can redistribute it and/or modify
12
12
  it under the terms of the GNU General Public License as published by
@@ -25,11 +25,11 @@ from __future__ import annotations
25
25
 
26
26
  import logging
27
27
 
28
- from PyQt5.QtGui import QFont
29
- from PyQt5.QtCore import Qt
28
+ from PyQt5.QtGui import QCloseEvent, QFont
29
+ from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
30
30
  from PyQt5.QtWidgets import (
31
31
  QDialog, QWidget, QComboBox, QSpinBox, QPushButton, QDialogButtonBox,
32
- QLineEdit, QFileDialog, QFontDialog, QDoubleSpinBox
32
+ QLineEdit, QFileDialog, QFontDialog, QDoubleSpinBox, qApp
33
33
  )
34
34
 
35
35
  from novelwriter import CONFIG, SHARED
@@ -43,12 +43,13 @@ logger = logging.getLogger(__name__)
43
43
 
44
44
  class GuiPreferences(NPagedDialog):
45
45
 
46
- def __init__(self, mainGui):
47
- super().__init__(parent=mainGui)
46
+ newPreferencesReady = pyqtSignal(bool, bool, bool, bool)
47
+
48
+ def __init__(self, parent: QWidget) -> None:
49
+ super().__init__(parent=parent)
48
50
 
49
51
  logger.debug("Create: GuiPreferences")
50
52
  self.setObjectName("GuiPreferences")
51
-
52
53
  self.setWindowTitle(self.tr("Preferences"))
53
54
 
54
55
  self.tabGeneral = GuiPreferencesGeneral(self)
@@ -67,9 +68,10 @@ class GuiPreferences(NPagedDialog):
67
68
  self.addTab(self.tabAuto, self.tr("Automation"))
68
69
  self.addTab(self.tabQuote, self.tr("Quotes"))
69
70
 
70
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
71
+ self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self)
71
72
  self.buttonBox.accepted.connect(self._doSave)
72
- self.buttonBox.rejected.connect(self._doClose)
73
+ self.buttonBox.rejected.connect(self.close)
74
+ self.rejected.connect(self.close)
73
75
  self.addControls(self.buttonBox)
74
76
 
75
77
  self.resize(*CONFIG.preferencesWinSize)
@@ -84,40 +86,29 @@ class GuiPreferences(NPagedDialog):
84
86
 
85
87
  return
86
88
 
87
- def __del__(self): # pragma: no cover
89
+ def __del__(self) -> None: # pragma: no cover
88
90
  logger.debug("Delete: GuiPreferences")
89
91
  return
90
92
 
91
93
  ##
92
- # Properties
94
+ # Events
93
95
  ##
94
96
 
95
- @property
96
- def updateTheme(self):
97
- return self._updateTheme
98
-
99
- @property
100
- def updateSyntax(self):
101
- return self._updateSyntax
102
-
103
- @property
104
- def needsRestart(self):
105
- return self._needsRestart
106
-
107
- @property
108
- def refreshTree(self):
109
- return self._refreshTree
97
+ def closeEvent(self, event: QCloseEvent) -> None:
98
+ """Capture the close event and perform cleanup."""
99
+ logger.debug("Close: GuiPreferences")
100
+ self._saveWindowSize()
101
+ event.accept()
102
+ self.deleteLater()
103
+ return
110
104
 
111
105
  ##
112
- # Slots
106
+ # Private Slots
113
107
  ##
114
108
 
115
- def _doSave(self):
116
- """Trigger all the save functions in the tabs, and collect the
117
- status of the saves.
118
- """
119
- logger.debug("Saving new preferences")
120
-
109
+ @pyqtSlot()
110
+ def _doSave(self) -> None:
111
+ """Trigger save functions in the tabs and emit ready signal."""
121
112
  self.tabGeneral.saveValues()
122
113
  self.tabProjects.saveValues()
123
114
  self.tabDocs.saveValues()
@@ -126,26 +117,21 @@ class GuiPreferences(NPagedDialog):
126
117
  self.tabAuto.saveValues()
127
118
  self.tabQuote.saveValues()
128
119
 
129
- self._saveWindowSize()
130
120
  CONFIG.saveConfig()
131
- self.accept()
132
-
133
- return
121
+ self.newPreferencesReady.emit(
122
+ self._needsRestart, self._refreshTree, self._updateTheme, self._updateSyntax
123
+ )
124
+ qApp.processEvents()
125
+ self.close()
134
126
 
135
- def _doClose(self):
136
- """Close the preferences without saving the changes.
137
- """
138
- self._saveWindowSize()
139
- self.reject()
140
127
  return
141
128
 
142
129
  ##
143
130
  # Internal Functions
144
131
  ##
145
132
 
146
- def _saveWindowSize(self):
147
- """Save the dialog window size.
148
- """
133
+ def _saveWindowSize(self) -> None:
134
+ """Save the dialog window size."""
149
135
  CONFIG.setPreferencesWinSize(self.width(), self.height())
150
136
  return
151
137
 
@@ -154,7 +140,7 @@ class GuiPreferences(NPagedDialog):
154
140
 
155
141
  class GuiPreferencesGeneral(QWidget):
156
142
 
157
- def __init__(self, prefsGui):
143
+ def __init__(self, prefsGui: GuiPreferences) -> None:
158
144
  super().__init__(parent=prefsGui)
159
145
 
160
146
  self.prefsGui = prefsGui
@@ -170,7 +156,7 @@ class GuiPreferencesGeneral(QWidget):
170
156
  minWidth = CONFIG.pxInt(200)
171
157
 
172
158
  # Select Locale
173
- self.guiLocale = QComboBox()
159
+ self.guiLocale = QComboBox(self)
174
160
  self.guiLocale.setMinimumWidth(minWidth)
175
161
  theLangs = CONFIG.listLanguages(CONFIG.LANG_NW)
176
162
  for lang, langName in theLangs:
@@ -188,7 +174,7 @@ class GuiPreferencesGeneral(QWidget):
188
174
  )
189
175
 
190
176
  # Select Theme
191
- self.guiTheme = QComboBox()
177
+ self.guiTheme = QComboBox(self)
192
178
  self.guiTheme.setMinimumWidth(minWidth)
193
179
  self.theThemes = SHARED.theme.listThemes()
194
180
  for themeDir, themeName in self.theThemes:
@@ -204,7 +190,7 @@ class GuiPreferencesGeneral(QWidget):
204
190
  )
205
191
 
206
192
  # Editor Theme
207
- self.guiSyntax = QComboBox()
193
+ self.guiSyntax = QComboBox(self)
208
194
  self.guiSyntax.setMinimumWidth(CONFIG.pxInt(200))
209
195
  self.theSyntaxes = SHARED.theme.listSyntax()
210
196
  for syntaxFile, syntaxName in self.theSyntaxes:
@@ -220,11 +206,11 @@ class GuiPreferencesGeneral(QWidget):
220
206
  )
221
207
 
222
208
  # Font Family
223
- self.guiFont = QLineEdit()
209
+ self.guiFont = QLineEdit(self)
224
210
  self.guiFont.setReadOnly(True)
225
211
  self.guiFont.setFixedWidth(CONFIG.pxInt(162))
226
212
  self.guiFont.setText(CONFIG.guiFont)
227
- self.fontButton = QPushButton("...")
213
+ self.fontButton = QPushButton("...", self)
228
214
  self.fontButton.setMaximumWidth(int(2.5*SHARED.theme.getTextWidth("...")))
229
215
  self.fontButton.clicked.connect(self._selectFont)
230
216
  self.mainForm.addRow(
@@ -285,9 +271,8 @@ class GuiPreferencesGeneral(QWidget):
285
271
 
286
272
  return
287
273
 
288
- def saveValues(self):
289
- """Save the values set for this tab.
290
- """
274
+ def saveValues(self) -> None:
275
+ """Save the values set for this tab."""
291
276
  guiLocale = self.guiLocale.currentData()
292
277
  guiTheme = self.guiTheme.currentData()
293
278
  guiSyntax = self.guiSyntax.currentData()
@@ -316,12 +301,12 @@ class GuiPreferencesGeneral(QWidget):
316
301
  return
317
302
 
318
303
  ##
319
- # Slots
304
+ # Private Slots
320
305
  ##
321
306
 
322
- def _selectFont(self):
323
- """Open the QFontDialog and set a font for the font style.
324
- """
307
+ @pyqtSlot()
308
+ def _selectFont(self) -> None:
309
+ """Open the QFontDialog and set a font for the font style."""
325
310
  currFont = QFont()
326
311
  currFont.setFamily(CONFIG.guiFont)
327
312
  currFont.setPointSize(CONFIG.guiFontSize)
@@ -336,7 +321,7 @@ class GuiPreferencesGeneral(QWidget):
336
321
 
337
322
  class GuiPreferencesProjects(QWidget):
338
323
 
339
- def __init__(self, prefsGui):
324
+ def __init__(self, prefsGui: GuiPreferences) -> None:
340
325
  super().__init__(parent=prefsGui)
341
326
 
342
327
  # The Form
@@ -380,7 +365,7 @@ class GuiPreferencesProjects(QWidget):
380
365
 
381
366
  # Backup Path
382
367
  self.backupPath = CONFIG.backupPath()
383
- self.backupGetPath = QPushButton(self.tr("Browse"))
368
+ self.backupGetPath = QPushButton(self.tr("Browse"), self)
384
369
  self.backupGetPath.clicked.connect(self._backupFolder)
385
370
  self.backupPathRow = self.mainForm.addRow(
386
371
  self.tr("Backup storage location"),
@@ -423,7 +408,7 @@ class GuiPreferencesProjects(QWidget):
423
408
  )
424
409
 
425
410
  # Inactive time for idle
426
- self.userIdleTime = QDoubleSpinBox()
411
+ self.userIdleTime = QDoubleSpinBox(self)
427
412
  self.userIdleTime.setMinimum(0.5)
428
413
  self.userIdleTime.setMaximum(600.0)
429
414
  self.userIdleTime.setSingleStep(0.5)
@@ -438,9 +423,8 @@ class GuiPreferencesProjects(QWidget):
438
423
 
439
424
  return
440
425
 
441
- def saveValues(self):
442
- """Save the values set for this tab.
443
- """
426
+ def saveValues(self) -> None:
427
+ """Save the values set for this tab."""
444
428
  # Automatic Save
445
429
  CONFIG.autoSaveDoc = self.autoSaveDoc.value()
446
430
  CONFIG.autoSaveProj = self.autoSaveProj.value()
@@ -457,12 +441,12 @@ class GuiPreferencesProjects(QWidget):
457
441
  return
458
442
 
459
443
  ##
460
- # Slots
444
+ # Private Slots
461
445
  ##
462
446
 
463
- def _backupFolder(self):
464
- """Open a dialog to select the backup folder.
465
- """
447
+ @pyqtSlot()
448
+ def _backupFolder(self) -> None:
449
+ """Open a dialog to select the backup folder."""
466
450
  currDir = self.backupPath or ""
467
451
  newDir = QFileDialog.getExistingDirectory(
468
452
  self, self.tr("Backup Directory"), str(currDir), options=QFileDialog.ShowDirsOnly
@@ -472,15 +456,13 @@ class GuiPreferencesProjects(QWidget):
472
456
  self.mainForm.setHelpText(
473
457
  self.backupPathRow, self.tr("Path: {0}").format(self.backupPath)
474
458
  )
475
- return True
476
-
477
- return False
459
+ return
460
+ return
478
461
 
479
- def _toggledBackupOnClose(self, theState):
480
- """Enable or disable switch that depends on the backup on close
481
- switch.
482
- """
483
- self.askBeforeBackup.setEnabled(theState)
462
+ @pyqtSlot(bool)
463
+ def _toggledBackupOnClose(self, state: bool) -> None:
464
+ """Toggle switch that depends on the backup on close switch."""
465
+ self.askBeforeBackup.setEnabled(state)
484
466
  return
485
467
 
486
468
  # END Class GuiPreferencesProjects
@@ -488,7 +470,7 @@ class GuiPreferencesProjects(QWidget):
488
470
 
489
471
  class GuiPreferencesDocuments(QWidget):
490
472
 
491
- def __init__(self, prefsGui):
473
+ def __init__(self, prefsGui: GuiPreferences) -> None:
492
474
  super().__init__(parent=prefsGui)
493
475
 
494
476
  # The Form
@@ -501,11 +483,11 @@ class GuiPreferencesDocuments(QWidget):
501
483
  self.mainForm.addGroupLabel(self.tr("Text Style"))
502
484
 
503
485
  # Font Family
504
- self.textFont = QLineEdit()
486
+ self.textFont = QLineEdit(self)
505
487
  self.textFont.setReadOnly(True)
506
488
  self.textFont.setFixedWidth(CONFIG.pxInt(162))
507
489
  self.textFont.setText(CONFIG.textFont)
508
- self.fontButton = QPushButton("...")
490
+ self.fontButton = QPushButton("...", self)
509
491
  self.fontButton.setMaximumWidth(int(2.5*SHARED.theme.getTextWidth("...")))
510
492
  self.fontButton.clicked.connect(self._selectFont)
511
493
  self.mainForm.addRow(
@@ -604,9 +586,8 @@ class GuiPreferencesDocuments(QWidget):
604
586
 
605
587
  return
606
588
 
607
- def saveValues(self):
608
- """Save the values set for this tab.
609
- """
589
+ def saveValues(self) -> None:
590
+ """Save the values set for this tab."""
610
591
  # Text Style
611
592
  CONFIG.setTextFont(self.textFont.text(), self.textSize.value())
612
593
 
@@ -621,12 +602,12 @@ class GuiPreferencesDocuments(QWidget):
621
602
  return
622
603
 
623
604
  ##
624
- # Slots
605
+ # Private Slots
625
606
  ##
626
607
 
608
+ @pyqtSlot()
627
609
  def _selectFont(self):
628
- """Open the QFontDialog and set a font for the font style.
629
- """
610
+ """Open the QFontDialog and set a font for the font style."""
630
611
  currFont = QFont()
631
612
  currFont.setFamily(CONFIG.textFont)
632
613
  currFont.setPointSize(CONFIG.textSize)
@@ -642,7 +623,7 @@ class GuiPreferencesDocuments(QWidget):
642
623
 
643
624
  class GuiPreferencesEditor(QWidget):
644
625
 
645
- def __init__(self, prefsGui):
626
+ def __init__(self, prefsGui: GuiPreferences) -> None:
646
627
  super().__init__(parent=prefsGui)
647
628
 
648
629
  # The Form
@@ -726,6 +707,15 @@ class GuiPreferencesEditor(QWidget):
726
707
  # ================
727
708
  self.mainForm.addGroupLabel(self.tr("Scroll Behaviour"))
728
709
 
710
+ # Scroll Past End
711
+ self.scrollPastEnd = NSwitch()
712
+ self.scrollPastEnd.setChecked(CONFIG.scrollPastEnd)
713
+ self.mainForm.addRow(
714
+ self.tr("Scroll past end of the document"),
715
+ self.scrollPastEnd,
716
+ self.tr("Also centres the cursor when scrolling.")
717
+ )
718
+
729
719
  # Typewriter Scrolling
730
720
  self.autoScroll = NSwitch()
731
721
  self.autoScroll.setChecked(CONFIG.autoScroll)
@@ -750,7 +740,7 @@ class GuiPreferencesEditor(QWidget):
750
740
 
751
741
  return
752
742
 
753
- def saveValues(self):
743
+ def saveValues(self) -> None:
754
744
  """Save the values set for this tab."""
755
745
  # Spell Checking
756
746
  CONFIG.spellLanguage = self.spellLanguage.currentData()
@@ -766,6 +756,7 @@ class GuiPreferencesEditor(QWidget):
766
756
  # Scroll Behaviour
767
757
  CONFIG.autoScroll = self.autoScroll.isChecked()
768
758
  CONFIG.autoScrollPos = self.autoScrollPos.value()
759
+ CONFIG.scrollPastEnd = self.scrollPastEnd.isChecked()
769
760
 
770
761
  return
771
762
 
@@ -774,7 +765,7 @@ class GuiPreferencesEditor(QWidget):
774
765
 
775
766
  class GuiPreferencesSyntax(QWidget):
776
767
 
777
- def __init__(self, prefsGui):
768
+ def __init__(self, prefsGui: GuiPreferences) -> None:
778
769
  super().__init__(parent=prefsGui)
779
770
 
780
771
  self.prefsGui = prefsGui
@@ -840,9 +831,8 @@ class GuiPreferencesSyntax(QWidget):
840
831
 
841
832
  return
842
833
 
843
- def saveValues(self):
844
- """Save the values set for this tab.
845
- """
834
+ def saveValues(self) -> None:
835
+ """Save the values set for this tab."""
846
836
  highlightQuotes = self.highlightQuotes.isChecked()
847
837
  allowOpenSQuote = self.allowOpenSQuote.isChecked()
848
838
  allowOpenDQuote = self.allowOpenDQuote.isChecked()
@@ -862,15 +852,14 @@ class GuiPreferencesSyntax(QWidget):
862
852
  return
863
853
 
864
854
  ##
865
- # Slots
855
+ # Private Slots
866
856
  ##
867
857
 
868
- def _toggleHighlightQuotes(self, theState):
869
- """Enables or disables switches controlled by the highlight
870
- quotes switch.
871
- """
872
- self.allowOpenSQuote.setEnabled(theState)
873
- self.allowOpenDQuote.setEnabled(theState)
858
+ @pyqtSlot(bool)
859
+ def _toggleHighlightQuotes(self, state: bool) -> None:
860
+ """Toggle switches controlled by the highlight quotes switch."""
861
+ self.allowOpenSQuote.setEnabled(state)
862
+ self.allowOpenDQuote.setEnabled(state)
874
863
  return
875
864
 
876
865
  # END Class GuiPreferencesSyntax
@@ -878,7 +867,7 @@ class GuiPreferencesSyntax(QWidget):
878
867
 
879
868
  class GuiPreferencesAutomation(QWidget):
880
869
 
881
- def __init__(self, prefsGui):
870
+ def __init__(self, prefsGui: GuiPreferences) -> None:
882
871
  super().__init__(parent=prefsGui)
883
872
 
884
873
  # The Form
@@ -958,7 +947,7 @@ class GuiPreferencesAutomation(QWidget):
958
947
  self.mainForm.addGroupLabel(self.tr("Automatic Padding"))
959
948
 
960
949
  # Pad Before
961
- self.fmtPadBefore = QLineEdit()
950
+ self.fmtPadBefore = QLineEdit(self)
962
951
  self.fmtPadBefore.setMaxLength(32)
963
952
  self.fmtPadBefore.setText(CONFIG.fmtPadBefore)
964
953
  self.mainForm.addRow(
@@ -968,7 +957,7 @@ class GuiPreferencesAutomation(QWidget):
968
957
  )
969
958
 
970
959
  # Pad After
971
- self.fmtPadAfter = QLineEdit()
960
+ self.fmtPadAfter = QLineEdit(self)
972
961
  self.fmtPadAfter.setMaxLength(32)
973
962
  self.fmtPadAfter.setText(CONFIG.fmtPadAfter)
974
963
  self.mainForm.addRow(
@@ -989,9 +978,8 @@ class GuiPreferencesAutomation(QWidget):
989
978
 
990
979
  return
991
980
 
992
- def saveValues(self):
993
- """Save the values set for this tab.
994
- """
981
+ def saveValues(self) -> None:
982
+ """Save the values set for this tab."""
995
983
  # Automatic Features
996
984
  CONFIG.autoSelect = self.autoSelect.isChecked()
997
985
  CONFIG.doReplace = self.doReplace.isChecked()
@@ -1010,18 +998,17 @@ class GuiPreferencesAutomation(QWidget):
1010
998
  return
1011
999
 
1012
1000
  ##
1013
- # Slots
1001
+ # Private Slots
1014
1002
  ##
1015
1003
 
1016
- def _toggleAutoReplaceMain(self, theState):
1017
- """Enables or disables switches controlled by the main auto
1018
- replace switch.
1019
- """
1020
- self.doReplaceSQuote.setEnabled(theState)
1021
- self.doReplaceDQuote.setEnabled(theState)
1022
- self.doReplaceDash.setEnabled(theState)
1023
- self.doReplaceDots.setEnabled(theState)
1024
- self.fmtPadThin.setEnabled(theState)
1004
+ @pyqtSlot(bool)
1005
+ def _toggleAutoReplaceMain(self, state: bool) -> None:
1006
+ """Toggle switches controlled by the auto replace switch."""
1007
+ self.doReplaceSQuote.setEnabled(state)
1008
+ self.doReplaceDQuote.setEnabled(state)
1009
+ self.doReplaceDash.setEnabled(state)
1010
+ self.doReplaceDots.setEnabled(state)
1011
+ self.fmtPadThin.setEnabled(state)
1025
1012
  return
1026
1013
 
1027
1014
  # END Class GuiPreferencesAutomation
@@ -1029,7 +1016,7 @@ class GuiPreferencesAutomation(QWidget):
1029
1016
 
1030
1017
  class GuiPreferencesQuotes(QWidget):
1031
1018
 
1032
- def __init__(self, prefsGui):
1019
+ def __init__(self, prefsGui: GuiPreferences) -> None:
1033
1020
  super().__init__(parent=prefsGui)
1034
1021
 
1035
1022
  # The Form
@@ -1046,13 +1033,13 @@ class GuiPreferencesQuotes(QWidget):
1046
1033
  self.quoteSym = {}
1047
1034
 
1048
1035
  # Single Quote Style
1049
- self.quoteSym["SO"] = QLineEdit()
1036
+ self.quoteSym["SO"] = QLineEdit(self)
1050
1037
  self.quoteSym["SO"].setMaxLength(1)
1051
1038
  self.quoteSym["SO"].setReadOnly(True)
1052
1039
  self.quoteSym["SO"].setFixedWidth(qWidth)
1053
1040
  self.quoteSym["SO"].setAlignment(Qt.AlignCenter)
1054
1041
  self.quoteSym["SO"].setText(CONFIG.fmtSQuoteOpen)
1055
- self.btnSingleStyleO = QPushButton("...")
1042
+ self.btnSingleStyleO = QPushButton("...", self)
1056
1043
  self.btnSingleStyleO.setMaximumWidth(bWidth)
1057
1044
  self.btnSingleStyleO.clicked.connect(lambda: self._getQuote("SO"))
1058
1045
  self.mainForm.addRow(
@@ -1062,13 +1049,13 @@ class GuiPreferencesQuotes(QWidget):
1062
1049
  button=self.btnSingleStyleO
1063
1050
  )
1064
1051
 
1065
- self.quoteSym["SC"] = QLineEdit()
1052
+ self.quoteSym["SC"] = QLineEdit(self)
1066
1053
  self.quoteSym["SC"].setMaxLength(1)
1067
1054
  self.quoteSym["SC"].setReadOnly(True)
1068
1055
  self.quoteSym["SC"].setFixedWidth(qWidth)
1069
1056
  self.quoteSym["SC"].setAlignment(Qt.AlignCenter)
1070
1057
  self.quoteSym["SC"].setText(CONFIG.fmtSQuoteClose)
1071
- self.btnSingleStyleC = QPushButton("...")
1058
+ self.btnSingleStyleC = QPushButton("...", self)
1072
1059
  self.btnSingleStyleC.setMaximumWidth(bWidth)
1073
1060
  self.btnSingleStyleC.clicked.connect(lambda: self._getQuote("SC"))
1074
1061
  self.mainForm.addRow(
@@ -1079,13 +1066,13 @@ class GuiPreferencesQuotes(QWidget):
1079
1066
  )
1080
1067
 
1081
1068
  # Double Quote Style
1082
- self.quoteSym["DO"] = QLineEdit()
1069
+ self.quoteSym["DO"] = QLineEdit(self)
1083
1070
  self.quoteSym["DO"].setMaxLength(1)
1084
1071
  self.quoteSym["DO"].setReadOnly(True)
1085
1072
  self.quoteSym["DO"].setFixedWidth(qWidth)
1086
1073
  self.quoteSym["DO"].setAlignment(Qt.AlignCenter)
1087
1074
  self.quoteSym["DO"].setText(CONFIG.fmtDQuoteOpen)
1088
- self.btnDoubleStyleO = QPushButton("...")
1075
+ self.btnDoubleStyleO = QPushButton("...", self)
1089
1076
  self.btnDoubleStyleO.setMaximumWidth(bWidth)
1090
1077
  self.btnDoubleStyleO.clicked.connect(lambda: self._getQuote("DO"))
1091
1078
  self.mainForm.addRow(
@@ -1095,13 +1082,13 @@ class GuiPreferencesQuotes(QWidget):
1095
1082
  button=self.btnDoubleStyleO
1096
1083
  )
1097
1084
 
1098
- self.quoteSym["DC"] = QLineEdit()
1085
+ self.quoteSym["DC"] = QLineEdit(self)
1099
1086
  self.quoteSym["DC"].setMaxLength(1)
1100
1087
  self.quoteSym["DC"].setReadOnly(True)
1101
1088
  self.quoteSym["DC"].setFixedWidth(qWidth)
1102
1089
  self.quoteSym["DC"].setAlignment(Qt.AlignCenter)
1103
1090
  self.quoteSym["DC"].setText(CONFIG.fmtDQuoteClose)
1104
- self.btnDoubleStyleC = QPushButton("...")
1091
+ self.btnDoubleStyleC = QPushButton("...", self)
1105
1092
  self.btnDoubleStyleC.setMaximumWidth(bWidth)
1106
1093
  self.btnDoubleStyleC.clicked.connect(lambda: self._getQuote("DC"))
1107
1094
  self.mainForm.addRow(
@@ -1113,9 +1100,8 @@ class GuiPreferencesQuotes(QWidget):
1113
1100
 
1114
1101
  return
1115
1102
 
1116
- def saveValues(self):
1117
- """Save the values set for this tab.
1118
- """
1103
+ def saveValues(self) -> None:
1104
+ """Save the values set for this tab."""
1119
1105
  # Quotation Style
1120
1106
  CONFIG.fmtSQuoteOpen = self.quoteSym["SO"].text()
1121
1107
  CONFIG.fmtSQuoteClose = self.quoteSym["SC"].text()
@@ -1124,12 +1110,11 @@ class GuiPreferencesQuotes(QWidget):
1124
1110
  return
1125
1111
 
1126
1112
  ##
1127
- # Slots
1113
+ # Internal Functions
1128
1114
  ##
1129
1115
 
1130
- def _getQuote(self, qType):
1131
- """Dialog for single quote open.
1132
- """
1116
+ def _getQuote(self, qType: str) -> None:
1117
+ """Dialog for single quote open."""
1133
1118
  qtBox = GuiQuoteSelect(self, currentQuote=self.quoteSym[qType].text())
1134
1119
  if qtBox.exec_() == QDialog.Accepted:
1135
1120
  self.quoteSym[qType].setText(qtBox.selectedQuote)