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 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)
@@ -3,10 +3,10 @@ novelWriter – GUI Project Settings
3
3
  ==================================
4
4
 
5
5
  File History:
6
- Created: 2018-09-29 [0.0.1]
6
+ Created: 2018-09-29 [0.0.1] GuiProjectSettings
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
@@ -27,11 +27,11 @@ import logging
27
27
 
28
28
  from typing import TYPE_CHECKING
29
29
 
30
- from PyQt5.QtGui import QIcon, QPixmap, QColor
31
- from PyQt5.QtCore import Qt, pyqtSlot
30
+ from PyQt5.QtGui import QCloseEvent, QIcon, QPixmap, QColor
31
+ from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
32
32
  from PyQt5.QtWidgets import (
33
33
  QColorDialog, QComboBox, QDialogButtonBox, QHBoxLayout, QLabel, QLineEdit,
34
- QPushButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
34
+ QPushButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget, qApp
35
35
  )
36
36
 
37
37
  from novelwriter import CONFIG, SHARED
@@ -53,6 +53,8 @@ class GuiProjectSettings(NPagedDialog):
53
53
  TAB_IMPORT = 2
54
54
  TAB_REPLACE = 3
55
55
 
56
+ newProjectSettingsReady = pyqtSignal()
57
+
56
58
  def __init__(self, mainGui: GuiMain, focusTab: int = TAB_MAIN) -> None:
57
59
  super().__init__(parent=mainGui)
58
60
 
@@ -86,7 +88,8 @@ class GuiProjectSettings(NPagedDialog):
86
88
 
87
89
  self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
88
90
  self.buttonBox.accepted.connect(self._doSave)
89
- self.buttonBox.rejected.connect(self._doClose)
91
+ self.buttonBox.rejected.connect(self.close)
92
+ self.rejected.connect(self.close)
90
93
  self.addControls(self.buttonBox)
91
94
 
92
95
  # Focus Tab
@@ -100,6 +103,13 @@ class GuiProjectSettings(NPagedDialog):
100
103
  logger.debug("Delete: GuiProjectSettings")
101
104
  return
102
105
 
106
+ def closeEvent(self, event: QCloseEvent) -> None:
107
+ """Capture the close event and perform cleanup."""
108
+ self._saveGuiSettings()
109
+ event.accept()
110
+ self.deleteLater()
111
+ return
112
+
103
113
  ##
104
114
  # Private Slots
105
115
  ##
@@ -137,18 +147,12 @@ class GuiProjectSettings(NPagedDialog):
137
147
  newList = self.tabReplace.getNewList()
138
148
  project.data.setAutoReplace(newList)
139
149
 
140
- self._saveGuiSettings()
141
- self.accept()
150
+ self.newProjectSettingsReady.emit()
151
+ qApp.processEvents()
152
+ self.close()
142
153
 
143
154
  return
144
155
 
145
- @pyqtSlot()
146
- def _doClose(self) -> None:
147
- """Save settings and close the dialog."""
148
- self._saveGuiSettings()
149
- self.reject()
150
- return
151
-
152
156
  ##
153
157
  # Internal Functions
154
158
  ##
@@ -173,6 +177,7 @@ class GuiProjectSettings(NPagedDialog):
173
177
  statusColW = CONFIG.rpxInt(self.tabStatus.listBox.columnWidth(0))
174
178
  importColW = CONFIG.rpxInt(self.tabImport.listBox.columnWidth(0))
175
179
 
180
+ logger.debug("Saving State: GuiProjectSettings")
176
181
  pOptions = SHARED.project.options
177
182
  pOptions.setValue("GuiProjectSettings", "winWidth", winWidth)
178
183
  pOptions.setValue("GuiProjectSettings", "winHeight", winHeight)
@@ -3,10 +3,10 @@ novelWriter – GUI Quotes Dialog
3
3
  ===============================
4
4
 
5
5
  File History:
6
- Created: 2020-06-18 [0.9]
6
+ Created: 2020-06-18 [0.9.0] GuiQuoteSelect
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 QFontMetrics
29
- from PyQt5.QtCore import Qt, QSize
28
+ from PyQt5.QtGui import QCloseEvent, QFontMetrics
29
+ from PyQt5.QtCore import QSize, Qt, pyqtSlot
30
30
  from PyQt5.QtWidgets import (
31
- QLabel, QVBoxLayout, QHBoxLayout, QDialog, QDialogButtonBox,
32
- QListWidget, QListWidgetItem, QFrame
31
+ QDialog, QDialogButtonBox, QFrame, QHBoxLayout, QLabel, QListWidget,
32
+ QListWidgetItem, QVBoxLayout, QWidget
33
33
  )
34
34
 
35
35
  from novelwriter import CONFIG
@@ -44,9 +44,12 @@ class GuiQuoteSelect(QDialog):
44
44
 
45
45
  D_KEY = Qt.ItemDataRole.UserRole
46
46
 
47
- def __init__(self, parent=None, currentQuote='"'):
47
+ def __init__(self, parent: QWidget, currentQuote: str = '"') -> None:
48
48
  super().__init__(parent=parent)
49
49
 
50
+ logger.debug("Create: GuiQuoteSelect")
51
+ self.setObjectName("GuiQuoteSelect")
52
+
50
53
  self.outerBox = QVBoxLayout()
51
54
  self.innerBox = QHBoxLayout()
52
55
  self.labelBox = QVBoxLayout()
@@ -87,8 +90,8 @@ class GuiQuoteSelect(QDialog):
87
90
 
88
91
  # Buttons
89
92
  self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
90
- self.buttonBox.accepted.connect(self._doAccept)
91
- self.buttonBox.rejected.connect(self._doReject)
93
+ self.buttonBox.accepted.connect(self.accept)
94
+ self.buttonBox.rejected.connect(self.reject)
92
95
 
93
96
  # Assemble
94
97
  self.labelBox.addWidget(self.previewLabel, 0, Qt.AlignTop)
@@ -102,15 +105,31 @@ class GuiQuoteSelect(QDialog):
102
105
 
103
106
  self.setLayout(self.outerBox)
104
107
 
108
+ logger.debug("Ready: GuiQuoteSelect")
109
+
110
+ return
111
+
112
+ def __del__(self) -> None: # pragma: no cover
113
+ logger.debug("Delete: GuiQuoteSelect")
105
114
  return
106
115
 
107
116
  ##
108
- # Slots
117
+ # Events
109
118
  ##
110
119
 
111
- def _selectedSymbol(self):
112
- """Update the preview label and the selected quote style.
113
- """
120
+ def closeEvent(self, event: QCloseEvent) -> None:
121
+ """Capture the close event and perform cleanup."""
122
+ event.accept()
123
+ self.deleteLater()
124
+ return
125
+
126
+ ##
127
+ # Private Slots
128
+ ##
129
+
130
+ @pyqtSlot()
131
+ def _selectedSymbol(self) -> None:
132
+ """Update the preview label and the selected quote style."""
114
133
  selItems = self.listBox.selectedItems()
115
134
  if selItems:
116
135
  theSymbol = selItems[0].data(self.D_KEY)
@@ -118,16 +137,4 @@ class GuiQuoteSelect(QDialog):
118
137
  self.selectedQuote = theSymbol
119
138
  return
120
139
 
121
- def _doAccept(self):
122
- """Ok button clicked.
123
- """
124
- self.accept()
125
- return
126
-
127
- def _doReject(self):
128
- """Cancel button clicked.
129
- """
130
- self.reject()
131
- return
132
-
133
140
  # END Class GuiQuoteSelect
@@ -3,10 +3,10 @@ novelWriter – GUI Updates
3
3
  =========================
4
4
 
5
5
  File History:
6
- Created: 2021-08-21 [1.5b1]
6
+ Created: 2021-08-21 [1.5b1] GuiUpdates
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,10 +29,10 @@ import logging
29
29
  from datetime import datetime
30
30
  from urllib.request import Request, urlopen
31
31
 
32
- from PyQt5.QtGui import QCursor
32
+ from PyQt5.QtGui import QCloseEvent, QCursor
33
33
  from PyQt5.QtCore import Qt
34
34
  from PyQt5.QtWidgets import (
35
- qApp, QDialog, QHBoxLayout, QVBoxLayout, QDialogButtonBox, QLabel
35
+ QWidget, qApp, QDialog, QHBoxLayout, QVBoxLayout, QDialogButtonBox, QLabel
36
36
  )
37
37
 
38
38
  from novelwriter import CONFIG, SHARED, __version__, __date__
@@ -44,8 +44,8 @@ logger = logging.getLogger(__name__)
44
44
 
45
45
  class GuiUpdates(QDialog):
46
46
 
47
- def __init__(self, mainGui):
48
- super().__init__(parent=mainGui)
47
+ def __init__(self, parent: QWidget) -> None:
48
+ super().__init__(parent=parent)
49
49
 
50
50
  logger.debug("Create: GuiUpdates")
51
51
  self.setObjectName("GuiUpdates")
@@ -94,8 +94,8 @@ class GuiUpdates(QDialog):
94
94
  self.latestLabel.setFont(hFont)
95
95
 
96
96
  # Buttons
97
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok)
98
- self.buttonBox.accepted.connect(self._doClose)
97
+ self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
98
+ self.buttonBox.rejected.connect(self.close)
99
99
 
100
100
  # Assemble
101
101
  self.innerBox = QHBoxLayout()
@@ -114,17 +114,16 @@ class GuiUpdates(QDialog):
114
114
 
115
115
  return
116
116
 
117
- def __del__(self): # pragma: no cover
117
+ def __del__(self) -> None: # pragma: no cover
118
118
  logger.debug("Delete: GuiUpdates")
119
119
  return
120
120
 
121
- def checkLatest(self):
122
- """Check for latest release.
123
- """
121
+ def checkLatest(self) -> None:
122
+ """Check for latest release."""
124
123
  qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
125
124
 
126
125
  urlReq = Request("https://api.github.com/repos/vkbo/novelwriter/releases/latest")
127
- urlReq.add_header("User-Agent", "Mozilla/5.0 (compatible; novelWriter (Python))")
126
+ urlReq.add_header("User-Agent", nwConst.USER_AGENT)
128
127
  urlReq.add_header("Accept", "application/vnd.github.v3+json")
129
128
 
130
129
  rawData = {}
@@ -161,11 +160,13 @@ class GuiUpdates(QDialog):
161
160
  return
162
161
 
163
162
  ##
164
- # Internal Functions
163
+ # Events
165
164
  ##
166
165
 
167
- def _doClose(self):
168
- self.close()
166
+ def closeEvent(self, event: QCloseEvent) -> None:
167
+ """Capture the user closing the window."""
168
+ event.accept()
169
+ self.deleteLater()
169
170
  return
170
171
 
171
172
  # END Class GuiUpdates