novelWriter 2.2rc1__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 (117) hide show
  1. {novelWriter-2.2rc1.dist-info → novelWriter-2.2.1.dist-info}/METADATA +1 -1
  2. {novelWriter-2.2rc1.dist-info → novelWriter-2.2.1.dist-info}/RECORD +113 -111
  3. {novelWriter-2.2rc1.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_US.json +1 -0
  15. novelwriter/assets/i18n/project_es_419.json +11 -0
  16. novelwriter/assets/i18n/project_fr_FR.json +11 -0
  17. novelwriter/assets/i18n/project_it_IT.json +11 -0
  18. novelwriter/assets/i18n/project_ja_JP.json +2 -1
  19. novelwriter/assets/i18n/project_nb_NO.json +1 -0
  20. novelwriter/assets/i18n/project_zh_CN.json +11 -0
  21. novelwriter/assets/icons/typicons_dark/icons.conf +3 -2
  22. novelwriter/assets/icons/typicons_dark/nw_tb-bold-md.svg +4 -0
  23. novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +3 -1
  24. novelwriter/assets/icons/typicons_dark/nw_tb-italic-md.svg +4 -0
  25. novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +3 -1
  26. novelwriter/assets/icons/typicons_dark/nw_tb-strike-md.svg +4 -0
  27. novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +3 -1
  28. novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +4 -2
  29. novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +4 -2
  30. novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +4 -2
  31. novelwriter/assets/icons/typicons_light/icons.conf +3 -2
  32. novelwriter/assets/icons/typicons_light/nw_tb-bold-md.svg +4 -0
  33. novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +3 -1
  34. novelwriter/assets/icons/typicons_light/nw_tb-italic-md.svg +4 -0
  35. novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +3 -1
  36. novelwriter/assets/icons/typicons_light/nw_tb-strike-md.svg +4 -0
  37. novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +3 -1
  38. novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +4 -2
  39. novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +4 -2
  40. novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +4 -2
  41. novelwriter/assets/manual.pdf +0 -0
  42. novelwriter/assets/sample.zip +0 -0
  43. novelwriter/assets/text/release_notes.htm +50 -7
  44. novelwriter/common.py +16 -29
  45. novelwriter/config.py +3 -3
  46. novelwriter/constants.py +1 -1
  47. novelwriter/core/buildsettings.py +1 -1
  48. novelwriter/core/coretools.py +2 -1
  49. novelwriter/core/docbuild.py +1 -1
  50. novelwriter/core/document.py +1 -1
  51. novelwriter/core/index.py +2 -2
  52. novelwriter/core/item.py +2 -2
  53. novelwriter/core/options.py +3 -3
  54. novelwriter/core/project.py +3 -3
  55. novelwriter/core/projectdata.py +2 -2
  56. novelwriter/core/projectxml.py +1 -1
  57. novelwriter/core/sessions.py +2 -2
  58. novelwriter/core/spellcheck.py +4 -3
  59. novelwriter/core/status.py +3 -3
  60. novelwriter/core/storage.py +1 -1
  61. novelwriter/core/tohtml.py +2 -2
  62. novelwriter/core/tokenizer.py +1 -1
  63. novelwriter/core/tomd.py +2 -2
  64. novelwriter/core/toodt.py +1 -1
  65. novelwriter/core/tree.py +2 -2
  66. novelwriter/dialogs/about.py +30 -31
  67. novelwriter/dialogs/docmerge.py +24 -15
  68. novelwriter/dialogs/docsplit.py +27 -16
  69. novelwriter/dialogs/editlabel.py +19 -7
  70. novelwriter/dialogs/preferences.py +44 -57
  71. novelwriter/dialogs/projdetails.py +29 -36
  72. novelwriter/dialogs/projload.py +32 -36
  73. novelwriter/dialogs/projsettings.py +20 -15
  74. novelwriter/dialogs/quotes.py +32 -25
  75. novelwriter/dialogs/updates.py +4 -14
  76. novelwriter/dialogs/wordlist.py +34 -21
  77. novelwriter/enum.py +5 -4
  78. novelwriter/error.py +1 -1
  79. novelwriter/extensions/circularprogress.py +1 -1
  80. novelwriter/extensions/configlayout.py +3 -15
  81. novelwriter/extensions/{wheeleventfilter.py → eventfilters.py} +15 -5
  82. novelwriter/extensions/novelselector.py +1 -1
  83. novelwriter/extensions/pageddialog.py +1 -1
  84. novelwriter/extensions/pagedsidebar.py +2 -5
  85. novelwriter/extensions/simpleprogress.py +8 -9
  86. novelwriter/extensions/statusled.py +1 -1
  87. novelwriter/extensions/switch.py +4 -4
  88. novelwriter/extensions/switchbox.py +1 -6
  89. novelwriter/gui/doceditor.py +72 -64
  90. novelwriter/gui/dochighlight.py +3 -2
  91. novelwriter/gui/docviewer.py +22 -47
  92. novelwriter/gui/docviewerpanel.py +68 -23
  93. novelwriter/gui/editordocument.py +3 -3
  94. novelwriter/gui/itemdetails.py +2 -2
  95. novelwriter/gui/mainmenu.py +35 -30
  96. novelwriter/gui/noveltree.py +44 -53
  97. novelwriter/gui/outline.py +2 -1
  98. novelwriter/gui/projtree.py +5 -6
  99. novelwriter/gui/sidebar.py +6 -4
  100. novelwriter/gui/statusbar.py +47 -4
  101. novelwriter/gui/theme.py +5 -6
  102. novelwriter/guimain.py +139 -189
  103. novelwriter/shared.py +53 -29
  104. novelwriter/tools/dictionaries.py +2 -2
  105. novelwriter/tools/lipsum.py +34 -28
  106. novelwriter/tools/manusbuild.py +3 -4
  107. novelwriter/tools/manuscript.py +19 -26
  108. novelwriter/tools/manussettings.py +2 -4
  109. novelwriter/tools/projwizard.py +3 -3
  110. novelwriter/tools/writingstats.py +17 -4
  111. novelwriter/assets/icons/typicons_dark/nw_tb-markdown.svg +0 -8
  112. novelwriter/assets/icons/typicons_dark/nw_tb-shortcode.svg +0 -8
  113. novelwriter/assets/icons/typicons_light/nw_tb-markdown.svg +0 -8
  114. novelwriter/assets/icons/typicons_light/nw_tb-shortcode.svg +0 -8
  115. {novelWriter-2.2rc1.dist-info → novelWriter-2.2.1.dist-info}/LICENSE.md +0 -0
  116. {novelWriter-2.2rc1.dist-info → novelWriter-2.2.1.dist-info}/entry_points.txt +0 -0
  117. {novelWriter-2.2rc1.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, pyqtSlot
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,6 +43,8 @@ logger = logging.getLogger(__name__)
43
43
 
44
44
  class GuiPreferences(NPagedDialog):
45
45
 
46
+ newPreferencesReady = pyqtSignal(bool, bool, bool, bool)
47
+
46
48
  def __init__(self, parent: QWidget) -> None:
47
49
  super().__init__(parent=parent)
48
50
 
@@ -66,9 +68,10 @@ class GuiPreferences(NPagedDialog):
66
68
  self.addTab(self.tabAuto, self.tr("Automation"))
67
69
  self.addTab(self.tabQuote, self.tr("Quotes"))
68
70
 
69
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
71
+ self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self)
70
72
  self.buttonBox.accepted.connect(self._doSave)
71
- self.buttonBox.rejected.connect(self._doClose)
73
+ self.buttonBox.rejected.connect(self.close)
74
+ self.rejected.connect(self.close)
72
75
  self.addControls(self.buttonBox)
73
76
 
74
77
  self.resize(*CONFIG.preferencesWinSize)
@@ -83,29 +86,21 @@ class GuiPreferences(NPagedDialog):
83
86
 
84
87
  return
85
88
 
86
- def __del__(self): # pragma: no cover
89
+ def __del__(self) -> None: # pragma: no cover
87
90
  logger.debug("Delete: GuiPreferences")
88
91
  return
89
92
 
90
93
  ##
91
- # Properties
94
+ # Events
92
95
  ##
93
96
 
94
- @property
95
- def updateTheme(self) -> bool:
96
- return self._updateTheme
97
-
98
- @property
99
- def updateSyntax(self) -> bool:
100
- return self._updateSyntax
101
-
102
- @property
103
- def needsRestart(self) -> bool:
104
- return self._needsRestart
105
-
106
- @property
107
- def refreshTree(self) -> bool:
108
- 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
109
104
 
110
105
  ##
111
106
  # Private Slots
@@ -113,11 +108,7 @@ class GuiPreferences(NPagedDialog):
113
108
 
114
109
  @pyqtSlot()
115
110
  def _doSave(self) -> None:
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
-
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,17 +117,13 @@ 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
- @pyqtSlot()
136
- def _doClose(self) -> None:
137
- """Close the preferences without saving the changes."""
138
- self._saveWindowSize()
139
- self.reject()
140
127
  return
141
128
 
142
129
  ##
@@ -169,7 +156,7 @@ class GuiPreferencesGeneral(QWidget):
169
156
  minWidth = CONFIG.pxInt(200)
170
157
 
171
158
  # Select Locale
172
- self.guiLocale = QComboBox()
159
+ self.guiLocale = QComboBox(self)
173
160
  self.guiLocale.setMinimumWidth(minWidth)
174
161
  theLangs = CONFIG.listLanguages(CONFIG.LANG_NW)
175
162
  for lang, langName in theLangs:
@@ -187,7 +174,7 @@ class GuiPreferencesGeneral(QWidget):
187
174
  )
188
175
 
189
176
  # Select Theme
190
- self.guiTheme = QComboBox()
177
+ self.guiTheme = QComboBox(self)
191
178
  self.guiTheme.setMinimumWidth(minWidth)
192
179
  self.theThemes = SHARED.theme.listThemes()
193
180
  for themeDir, themeName in self.theThemes:
@@ -203,7 +190,7 @@ class GuiPreferencesGeneral(QWidget):
203
190
  )
204
191
 
205
192
  # Editor Theme
206
- self.guiSyntax = QComboBox()
193
+ self.guiSyntax = QComboBox(self)
207
194
  self.guiSyntax.setMinimumWidth(CONFIG.pxInt(200))
208
195
  self.theSyntaxes = SHARED.theme.listSyntax()
209
196
  for syntaxFile, syntaxName in self.theSyntaxes:
@@ -219,11 +206,11 @@ class GuiPreferencesGeneral(QWidget):
219
206
  )
220
207
 
221
208
  # Font Family
222
- self.guiFont = QLineEdit()
209
+ self.guiFont = QLineEdit(self)
223
210
  self.guiFont.setReadOnly(True)
224
211
  self.guiFont.setFixedWidth(CONFIG.pxInt(162))
225
212
  self.guiFont.setText(CONFIG.guiFont)
226
- self.fontButton = QPushButton("...")
213
+ self.fontButton = QPushButton("...", self)
227
214
  self.fontButton.setMaximumWidth(int(2.5*SHARED.theme.getTextWidth("...")))
228
215
  self.fontButton.clicked.connect(self._selectFont)
229
216
  self.mainForm.addRow(
@@ -378,7 +365,7 @@ class GuiPreferencesProjects(QWidget):
378
365
 
379
366
  # Backup Path
380
367
  self.backupPath = CONFIG.backupPath()
381
- self.backupGetPath = QPushButton(self.tr("Browse"))
368
+ self.backupGetPath = QPushButton(self.tr("Browse"), self)
382
369
  self.backupGetPath.clicked.connect(self._backupFolder)
383
370
  self.backupPathRow = self.mainForm.addRow(
384
371
  self.tr("Backup storage location"),
@@ -421,7 +408,7 @@ class GuiPreferencesProjects(QWidget):
421
408
  )
422
409
 
423
410
  # Inactive time for idle
424
- self.userIdleTime = QDoubleSpinBox()
411
+ self.userIdleTime = QDoubleSpinBox(self)
425
412
  self.userIdleTime.setMinimum(0.5)
426
413
  self.userIdleTime.setMaximum(600.0)
427
414
  self.userIdleTime.setSingleStep(0.5)
@@ -496,11 +483,11 @@ class GuiPreferencesDocuments(QWidget):
496
483
  self.mainForm.addGroupLabel(self.tr("Text Style"))
497
484
 
498
485
  # Font Family
499
- self.textFont = QLineEdit()
486
+ self.textFont = QLineEdit(self)
500
487
  self.textFont.setReadOnly(True)
501
488
  self.textFont.setFixedWidth(CONFIG.pxInt(162))
502
489
  self.textFont.setText(CONFIG.textFont)
503
- self.fontButton = QPushButton("...")
490
+ self.fontButton = QPushButton("...", self)
504
491
  self.fontButton.setMaximumWidth(int(2.5*SHARED.theme.getTextWidth("...")))
505
492
  self.fontButton.clicked.connect(self._selectFont)
506
493
  self.mainForm.addRow(
@@ -960,7 +947,7 @@ class GuiPreferencesAutomation(QWidget):
960
947
  self.mainForm.addGroupLabel(self.tr("Automatic Padding"))
961
948
 
962
949
  # Pad Before
963
- self.fmtPadBefore = QLineEdit()
950
+ self.fmtPadBefore = QLineEdit(self)
964
951
  self.fmtPadBefore.setMaxLength(32)
965
952
  self.fmtPadBefore.setText(CONFIG.fmtPadBefore)
966
953
  self.mainForm.addRow(
@@ -970,7 +957,7 @@ class GuiPreferencesAutomation(QWidget):
970
957
  )
971
958
 
972
959
  # Pad After
973
- self.fmtPadAfter = QLineEdit()
960
+ self.fmtPadAfter = QLineEdit(self)
974
961
  self.fmtPadAfter.setMaxLength(32)
975
962
  self.fmtPadAfter.setText(CONFIG.fmtPadAfter)
976
963
  self.mainForm.addRow(
@@ -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(
@@ -3,10 +3,10 @@ novelWriter – GUI Project Details
3
3
  =================================
4
4
 
5
5
  File History:
6
- Created: 2021-01-03 [1.1rc1]
6
+ Created: 2021-01-03 [1.1rc1] GuiProjectDetails
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
@@ -26,8 +26,8 @@ from __future__ import annotations
26
26
  import math
27
27
  import logging
28
28
 
29
+ from PyQt5.QtGui import QCloseEvent, QFont
29
30
  from PyQt5.QtCore import Qt, QSize, pyqtSlot
30
- from PyQt5.QtGui import QFont
31
31
  from PyQt5.QtWidgets import (
32
32
  QAbstractItemView, QDialogButtonBox, QGridLayout, QHBoxLayout, QLabel,
33
33
  QLineEdit, QSpinBox, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
@@ -45,7 +45,7 @@ logger = logging.getLogger(__name__)
45
45
 
46
46
  class GuiProjectDetails(NPagedDialog):
47
47
 
48
- def __init__(self, parent):
48
+ def __init__(self, parent: QWidget) -> None:
49
49
  super().__init__(parent=parent)
50
50
 
51
51
  logger.debug("Create: GuiProjectDetails")
@@ -71,43 +71,41 @@ class GuiProjectDetails(NPagedDialog):
71
71
  self.addTab(self.tabContents, self.tr("Contents"))
72
72
 
73
73
  self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
74
- self.buttonBox.button(QDialogButtonBox.Close)
75
- self.buttonBox.rejected.connect(self._doClose)
74
+ self.buttonBox.rejected.connect(self.close)
75
+ self.rejected.connect(self.close)
76
76
  self.addControls(self.buttonBox)
77
77
 
78
78
  logger.debug("Ready: GuiProjectDetails")
79
79
 
80
80
  return
81
81
 
82
- def __del__(self): # pragma: no cover
82
+ def __del__(self) -> None: # pragma: no cover
83
83
  logger.debug("Delete: GuiProjectDetails")
84
84
  return
85
85
 
86
- def updateValues(self):
87
- """Set all the values of the pages.
88
- """
86
+ def updateValues(self) -> None:
87
+ """Set all the values of the pages."""
89
88
  self.tabMain.updateValues()
90
89
  self.tabContents.updateValues()
91
90
  return
92
91
 
93
92
  ##
94
- # Slots
93
+ # Events
95
94
  ##
96
95
 
97
- def _doClose(self):
98
- """Save settings and close the dialog.
99
- """
96
+ def closeEvent(self, event: QCloseEvent) -> None:
97
+ """Capture the close event and perform cleanup."""
100
98
  self._saveGuiSettings()
101
- self.close()
99
+ event.accept()
100
+ self.deleteLater()
102
101
  return
103
102
 
104
103
  ##
105
104
  # Internal Functions
106
105
  ##
107
106
 
108
- def _saveGuiSettings(self):
109
- """Save GUI settings.
110
- """
107
+ def _saveGuiSettings(self) -> None:
108
+ """Save GUI settings."""
111
109
  winWidth = CONFIG.rpxInt(self.width())
112
110
  winHeight = CONFIG.rpxInt(self.height())
113
111
 
@@ -122,6 +120,7 @@ class GuiProjectDetails(NPagedDialog):
122
120
  countFrom = self.tabContents.poValue.value()
123
121
  clearDouble = self.tabContents.dblValue.isChecked()
124
122
 
123
+ logger.debug("Saving State: GuiProjectDetails")
125
124
  pOptions = SHARED.project.options
126
125
  pOptions.setValue("GuiProjectDetails", "winWidth", winWidth)
127
126
  pOptions.setValue("GuiProjectDetails", "winHeight", winHeight)
@@ -141,7 +140,7 @@ class GuiProjectDetails(NPagedDialog):
141
140
 
142
141
  class GuiProjectDetailsMain(QWidget):
143
142
 
144
- def __init__(self, parent):
143
+ def __init__(self, parent: QWidget) -> None:
145
144
  super().__init__(parent=parent)
146
145
 
147
146
  fPx = SHARED.theme.fontPixelSize
@@ -270,7 +269,7 @@ class GuiProjectDetailsContents(QWidget):
270
269
  C_PAGE = 3
271
270
  C_PROG = 4
272
271
 
273
- def __init__(self, parent):
272
+ def __init__(self, parent: QWidget) -> None:
274
273
  super().__init__(parent=parent)
275
274
 
276
275
  # Internal
@@ -406,9 +405,8 @@ class GuiProjectDetailsContents(QWidget):
406
405
 
407
406
  return
408
407
 
409
- def getColumnSizes(self):
410
- """Return the column widths for the tree columns.
411
- """
408
+ def getColumnSizes(self) -> list[int]:
409
+ """Return the column widths for the tree columns."""
412
410
  retVals = [
413
411
  self.tocTree.columnWidth(0),
414
412
  self.tocTree.columnWidth(1),
@@ -418,24 +416,21 @@ class GuiProjectDetailsContents(QWidget):
418
416
  ]
419
417
  return retVals
420
418
 
421
- def updateValues(self):
422
- """Populate the tree.
423
- """
419
+ def updateValues(self) -> None:
420
+ """Populate the tree."""
424
421
  self._currentRoot = None
425
422
  self.novelValue.updateList()
426
423
  self.novelValue.setHandle(self.novelValue.firstHandle)
427
424
  self._prepareData(self.novelValue.firstHandle)
428
425
  self._populateTree()
429
-
430
426
  return
431
427
 
432
428
  ##
433
429
  # Internal Functions
434
430
  ##
435
431
 
436
- def _prepareData(self, rootHandle):
437
- """Extract the information from the project index.
438
- """
432
+ def _prepareData(self, rootHandle: str | None) -> None:
433
+ """Extract the information from the project index."""
439
434
  logger.debug("Populating ToC from handle '%s'", rootHandle)
440
435
  self._theToC = SHARED.project.index.getTableOfContents(rootHandle, 2)
441
436
  self._theToC.append(("", 0, self.tr("END"), 0))
@@ -446,9 +441,8 @@ class GuiProjectDetailsContents(QWidget):
446
441
  ##
447
442
 
448
443
  @pyqtSlot(str)
449
- def _novelValueChanged(self, tHandle):
450
- """Refresh the tree with another root item.
451
- """
444
+ def _novelValueChanged(self, tHandle: str) -> None:
445
+ """Refresh the tree with another root item."""
452
446
  if tHandle != self._currentRoot:
453
447
  self._prepareData(tHandle)
454
448
  self._populateTree()
@@ -456,9 +450,8 @@ class GuiProjectDetailsContents(QWidget):
456
450
  return
457
451
 
458
452
  @pyqtSlot()
459
- def _populateTree(self):
460
- """Set the content of the chapter/page tree.
461
- """
453
+ def _populateTree(self) -> None:
454
+ """Set the content of the chapter/page tree."""
462
455
  dblPages = self.dblValue.isChecked()
463
456
  wpPage = self.wpValue.value()
464
457
  fstPage = self.poValue.value() - 1
@@ -3,10 +3,10 @@ novelWriter – GUI Open Project
3
3
  ==============================
4
4
 
5
5
  File History:
6
- Created: 2020-02-26 [0.4.5]
6
+ Created: 2020-02-26 [0.4.5] GuiProjectLoad
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
@@ -29,8 +29,8 @@ from typing import TYPE_CHECKING
29
29
  from pathlib import Path
30
30
  from datetime import datetime
31
31
 
32
- from PyQt5.QtGui import QKeySequence
33
- from PyQt5.QtCore import Qt, QSize
32
+ from PyQt5.QtGui import QCloseEvent, QKeySequence
33
+ from PyQt5.QtCore import Qt, QSize, pyqtSlot
34
34
  from PyQt5.QtWidgets import (
35
35
  QDialog, QHBoxLayout, QVBoxLayout, QGridLayout, QPushButton, QTreeWidget,
36
36
  QAbstractItemView, QTreeWidgetItem, QDialogButtonBox, QLabel, QShortcut,
@@ -112,8 +112,7 @@ class GuiProjectLoad(QDialog):
112
112
  self.selPath = QLineEdit("")
113
113
  self.selPath.setReadOnly(True)
114
114
 
115
- self.browseButton = QPushButton("...")
116
- self.browseButton.setMaximumWidth(int(2.5*SHARED.theme.getTextWidth("...")))
115
+ self.browseButton = QPushButton(SHARED.theme.getIcon("browse"), "", self)
117
116
  self.browseButton.clicked.connect(self._doBrowse)
118
117
 
119
118
  self.projectForm.addWidget(self.lblRecent, 0, 0, 1, 3)
@@ -154,17 +153,17 @@ class GuiProjectLoad(QDialog):
154
153
 
155
154
  return
156
155
 
157
- def __del__(self): # pragma: no cover
156
+ def __del__(self) -> None: # pragma: no cover
158
157
  logger.debug("Delete: GuiProjectLoad")
159
158
  return
160
159
 
161
160
  ##
162
- # Buttons
161
+ # Private Slots
163
162
  ##
164
163
 
165
- def _doOpenRecent(self):
166
- """Close the dialog window with a recent project selected.
167
- """
164
+ @pyqtSlot()
165
+ def _doOpenRecent(self) -> None:
166
+ """Close the dialog window with a recent project selected."""
168
167
  self._saveSettings()
169
168
 
170
169
  self.openPath = None
@@ -178,17 +177,17 @@ class GuiProjectLoad(QDialog):
178
177
 
179
178
  return
180
179
 
181
- def _doSelectRecent(self):
182
- """A recent item has been selected.
183
- """
180
+ @pyqtSlot()
181
+ def _doSelectRecent(self) -> None:
182
+ """Update path when a recent item has been selected."""
184
183
  selList = self.listBox.selectedItems()
185
184
  if selList:
186
185
  self.selPath.setText(selList[0].data(self.C_NAME, self.D_PATH))
187
186
  return
188
187
 
189
- def _doBrowse(self):
190
- """Browse for a folder path.
191
- """
188
+ @pyqtSlot()
189
+ def _doBrowse(self) -> None:
190
+ """Browse for a folder path."""
192
191
  extFilter = [
193
192
  self.tr("novelWriter Project File ({0})").format(nwFiles.PROJ_FILE),
194
193
  self.tr("All files ({0})").format("*"),
@@ -205,26 +204,26 @@ class GuiProjectLoad(QDialog):
205
204
 
206
205
  return
207
206
 
208
- def _doCancel(self):
209
- """Close the dialog window without doing anything.
210
- """
207
+ @pyqtSlot()
208
+ def _doCancel(self) -> None:
209
+ """Close the dialog window without doing anything."""
211
210
  self.openPath = None
212
211
  self.openState = self.NONE_STATE
213
212
  self.close()
214
213
  return
215
214
 
216
- def _doNewProject(self):
217
- """Create a new project.
218
- """
215
+ @pyqtSlot()
216
+ def _doNewProject(self) -> None:
217
+ """Create a new project."""
219
218
  self._saveSettings()
220
219
  self.openPath = None
221
220
  self.openState = self.NEW_STATE
222
221
  self.accept()
223
222
  return
224
223
 
225
- def _doDeleteRecent(self):
226
- """Remove an entry from the recent projects list.
227
- """
224
+ @pyqtSlot()
225
+ def _doDeleteRecent(self) -> None:
226
+ """Remove an entry from the recent projects list."""
228
227
  selList = self.listBox.selectedItems()
229
228
  if selList:
230
229
  projName = selList[0].text(self.C_NAME)
@@ -244,20 +243,18 @@ class GuiProjectLoad(QDialog):
244
243
  # Events
245
244
  ##
246
245
 
247
- def closeEvent(self, theEvent):
248
- """Capture the user closing the dialog so we can save settings.
249
- """
246
+ def closeEvent(self, event: QCloseEvent) -> None:
247
+ """Capture the user closing the dialog and save settings."""
250
248
  self._saveSettings()
251
- theEvent.accept()
249
+ event.accept()
252
250
  return
253
251
 
254
252
  ##
255
253
  # Internal Functions
256
254
  ##
257
255
 
258
- def _saveSettings(self):
259
- """Save the changes made to the dialog.
260
- """
256
+ def _saveSettings(self) -> None:
257
+ """Save the changes made to the dialog."""
261
258
  colWidths = [0, 0, 0]
262
259
  colWidths[self.C_NAME] = self.listBox.columnWidth(self.C_NAME)
263
260
  colWidths[self.C_COUNT] = self.listBox.columnWidth(self.C_COUNT)
@@ -265,9 +262,8 @@ class GuiProjectLoad(QDialog):
265
262
  CONFIG.setProjLoadColWidths(colWidths)
266
263
  return
267
264
 
268
- def _populateList(self):
269
- """Populate the list box with recent project data.
270
- """
265
+ def _populateList(self) -> None:
266
+ """Populate the list box with recent project data."""
271
267
  self.listBox.clear()
272
268
  dataList = CONFIG.recentProjects.listEntries()
273
269
  sortList = sorted(dataList, key=lambda x: x[3], reverse=True)