novelWriter 2.4.4__py3-none-any.whl → 2.5rc1__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 (110) hide show
  1. {novelWriter-2.4.4.dist-info → novelWriter-2.5rc1.dist-info}/METADATA +4 -5
  2. {novelWriter-2.4.4.dist-info → novelWriter-2.5rc1.dist-info}/RECORD +109 -101
  3. {novelWriter-2.4.4.dist-info → novelWriter-2.5rc1.dist-info}/WHEEL +1 -1
  4. novelwriter/__init__.py +33 -39
  5. novelwriter/assets/i18n/project_en_GB.json +1 -0
  6. novelwriter/assets/icons/typicons_dark/icons.conf +2 -0
  7. novelwriter/assets/icons/typicons_dark/nw_font.svg +4 -0
  8. novelwriter/assets/icons/typicons_dark/nw_quote.svg +4 -0
  9. novelwriter/assets/icons/typicons_light/icons.conf +2 -0
  10. novelwriter/assets/icons/typicons_light/nw_font.svg +4 -0
  11. novelwriter/assets/icons/typicons_light/nw_quote.svg +4 -0
  12. novelwriter/assets/manual.pdf +0 -0
  13. novelwriter/assets/sample.zip +0 -0
  14. novelwriter/assets/syntax/cyberpunk_night.conf +5 -3
  15. novelwriter/assets/syntax/default_dark.conf +32 -18
  16. novelwriter/assets/syntax/default_light.conf +24 -10
  17. novelwriter/assets/syntax/dracula.conf +44 -0
  18. novelwriter/assets/syntax/grey_dark.conf +5 -4
  19. novelwriter/assets/syntax/grey_light.conf +5 -4
  20. novelwriter/assets/syntax/light_owl.conf +7 -6
  21. novelwriter/assets/syntax/night_owl.conf +7 -6
  22. novelwriter/assets/syntax/snazzy.conf +42 -0
  23. novelwriter/assets/syntax/solarized_dark.conf +4 -3
  24. novelwriter/assets/syntax/solarized_light.conf +4 -3
  25. novelwriter/assets/syntax/tango.conf +27 -11
  26. novelwriter/assets/syntax/tomorrow.conf +6 -5
  27. novelwriter/assets/syntax/tomorrow_night.conf +7 -6
  28. novelwriter/assets/syntax/tomorrow_night_blue.conf +6 -5
  29. novelwriter/assets/syntax/tomorrow_night_bright.conf +6 -5
  30. novelwriter/assets/syntax/tomorrow_night_eighties.conf +6 -5
  31. novelwriter/assets/text/credits_en.htm +4 -1
  32. novelwriter/assets/themes/cyberpunk_night.conf +3 -0
  33. novelwriter/assets/themes/default_dark.conf +2 -0
  34. novelwriter/assets/themes/default_light.conf +2 -0
  35. novelwriter/assets/themes/dracula.conf +48 -0
  36. novelwriter/assets/themes/solarized_dark.conf +2 -0
  37. novelwriter/assets/themes/solarized_light.conf +2 -0
  38. novelwriter/common.py +33 -12
  39. novelwriter/config.py +184 -98
  40. novelwriter/constants.py +47 -35
  41. novelwriter/core/buildsettings.py +68 -69
  42. novelwriter/core/coretools.py +5 -23
  43. novelwriter/core/docbuild.py +52 -40
  44. novelwriter/core/document.py +3 -5
  45. novelwriter/core/index.py +115 -45
  46. novelwriter/core/item.py +8 -19
  47. novelwriter/core/options.py +2 -4
  48. novelwriter/core/project.py +23 -57
  49. novelwriter/core/projectdata.py +1 -3
  50. novelwriter/core/projectxml.py +12 -15
  51. novelwriter/core/sessions.py +3 -5
  52. novelwriter/core/spellcheck.py +4 -9
  53. novelwriter/core/status.py +211 -164
  54. novelwriter/core/storage.py +0 -8
  55. novelwriter/core/tohtml.py +139 -105
  56. novelwriter/core/tokenizer.py +278 -122
  57. novelwriter/core/{tomd.py → tomarkdown.py} +97 -78
  58. novelwriter/core/toodt.py +257 -166
  59. novelwriter/core/toqdoc.py +419 -0
  60. novelwriter/core/tree.py +5 -7
  61. novelwriter/dialogs/about.py +11 -18
  62. novelwriter/dialogs/docmerge.py +17 -19
  63. novelwriter/dialogs/docsplit.py +17 -19
  64. novelwriter/dialogs/editlabel.py +6 -10
  65. novelwriter/dialogs/preferences.py +193 -144
  66. novelwriter/dialogs/projectsettings.py +225 -189
  67. novelwriter/dialogs/quotes.py +12 -9
  68. novelwriter/dialogs/wordlist.py +9 -15
  69. novelwriter/enum.py +35 -30
  70. novelwriter/error.py +8 -15
  71. novelwriter/extensions/configlayout.py +40 -21
  72. novelwriter/extensions/eventfilters.py +1 -5
  73. novelwriter/extensions/modified.py +58 -14
  74. novelwriter/extensions/novelselector.py +1 -3
  75. novelwriter/extensions/pagedsidebar.py +9 -12
  76. novelwriter/extensions/{circularprogress.py → progressbars.py} +30 -8
  77. novelwriter/extensions/statusled.py +29 -25
  78. novelwriter/extensions/switch.py +4 -6
  79. novelwriter/extensions/switchbox.py +7 -6
  80. novelwriter/extensions/versioninfo.py +3 -9
  81. novelwriter/gui/doceditor.py +118 -137
  82. novelwriter/gui/dochighlight.py +231 -186
  83. novelwriter/gui/docviewer.py +66 -107
  84. novelwriter/gui/docviewerpanel.py +3 -10
  85. novelwriter/gui/editordocument.py +1 -3
  86. novelwriter/gui/itemdetails.py +7 -11
  87. novelwriter/gui/mainmenu.py +22 -18
  88. novelwriter/gui/noveltree.py +11 -24
  89. novelwriter/gui/outline.py +14 -26
  90. novelwriter/gui/projtree.py +35 -60
  91. novelwriter/gui/search.py +10 -3
  92. novelwriter/gui/sidebar.py +2 -6
  93. novelwriter/gui/statusbar.py +29 -37
  94. novelwriter/gui/theme.py +26 -48
  95. novelwriter/guimain.py +134 -148
  96. novelwriter/shared.py +36 -32
  97. novelwriter/text/patterns.py +113 -0
  98. novelwriter/tools/dictionaries.py +10 -20
  99. novelwriter/tools/lipsum.py +10 -16
  100. novelwriter/tools/manusbuild.py +9 -11
  101. novelwriter/tools/manuscript.py +71 -145
  102. novelwriter/tools/manussettings.py +71 -75
  103. novelwriter/tools/noveldetails.py +16 -21
  104. novelwriter/tools/welcome.py +12 -26
  105. novelwriter/tools/writingstats.py +9 -12
  106. novelwriter/types.py +49 -4
  107. novelwriter/extensions/simpleprogress.py +0 -55
  108. {novelWriter-2.4.4.dist-info → novelWriter-2.5rc1.dist-info}/LICENSE.md +0 -0
  109. {novelWriter-2.4.4.dist-info → novelWriter-2.5rc1.dist-info}/entry_points.txt +0 -0
  110. {novelWriter-2.4.4.dist-info → novelWriter-2.5rc1.dist-info}/top_level.txt +0 -0
@@ -27,23 +27,24 @@ import logging
27
27
 
28
28
  from typing import TYPE_CHECKING
29
29
 
30
- from PyQt5.QtCore import QEvent, Qt, pyqtSignal, pyqtSlot
30
+ from PyQt5.QtCore import QEvent, pyqtSignal, pyqtSlot
31
31
  from PyQt5.QtGui import QFont, QIcon, QSyntaxHighlighter, QTextCharFormat, QTextDocument
32
32
  from PyQt5.QtWidgets import (
33
- QAbstractButton, QAbstractItemView, QDialogButtonBox, QFontDialog, QFrame,
34
- QGridLayout, QHBoxLayout, QHeaderView, QLabel, QLineEdit, QMenu,
35
- QPlainTextEdit, QPushButton, QSplitter, QStackedWidget, QTreeWidget,
36
- QTreeWidgetItem, QVBoxLayout, QWidget
33
+ QAbstractButton, QAbstractItemView, QDialogButtonBox, QFrame, QGridLayout,
34
+ QHBoxLayout, QHeaderView, QLabel, QLineEdit, QMenu, QPlainTextEdit,
35
+ QPushButton, QSplitter, QStackedWidget, QTreeWidget, QTreeWidgetItem,
36
+ QVBoxLayout, QWidget
37
37
  )
38
38
 
39
39
  from novelwriter import CONFIG, SHARED
40
+ from novelwriter.common import describeFont
40
41
  from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, trConst
41
42
  from novelwriter.core.buildsettings import BuildSettings, FilterMode
42
43
  from novelwriter.extensions.configlayout import (
43
44
  NColourLabel, NFixedPage, NScrollableForm, NScrollablePage
44
45
  )
45
46
  from novelwriter.extensions.modified import (
46
- NComboBox, NDialog, NDoubleSpinBox, NIconToolButton, NSpinBox
47
+ NComboBox, NDoubleSpinBox, NIconToolButton, NSpinBox, NToolDialog
47
48
  )
48
49
  from novelwriter.extensions.pagedsidebar import NPagedSideBar
49
50
  from novelwriter.extensions.switch import NSwitch
@@ -59,7 +60,7 @@ if TYPE_CHECKING: # pragma: no cover
59
60
  logger = logging.getLogger(__name__)
60
61
 
61
62
 
62
- class GuiBuildSettings(NDialog):
63
+ class GuiBuildSettings(NToolDialog):
63
64
  """GUI Tools: Manuscript Build Settings Dialog
64
65
 
65
66
  The main tool for configuring manuscript builds. It's a GUI tool for
@@ -74,13 +75,11 @@ class GuiBuildSettings(NDialog):
74
75
 
75
76
  newSettingsReady = pyqtSignal(BuildSettings)
76
77
 
77
- def __init__(self, mainGui: GuiMain, build: BuildSettings) -> None:
78
- super().__init__(parent=mainGui)
78
+ def __init__(self, parent: GuiMain, build: BuildSettings) -> None:
79
+ super().__init__(parent=parent)
79
80
 
80
81
  logger.debug("Create: GuiBuildSettings")
81
82
  self.setObjectName("GuiBuildSettings")
82
- if CONFIG.osDarwin:
83
- self.setWindowFlag(Qt.WindowType.Tool)
84
83
 
85
84
  self._build = build
86
85
 
@@ -99,8 +98,8 @@ class GuiBuildSettings(NDialog):
99
98
 
100
99
  # Title
101
100
  self.titleLabel = NColourLabel(
102
- self.tr("Manuscript Build Settings"), SHARED.theme.helpText,
103
- parent=self, scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
101
+ self.tr("Manuscript Build Settings"), self, color=SHARED.theme.helpText,
102
+ scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
104
103
  )
105
104
 
106
105
  # Settings Name
@@ -280,8 +279,6 @@ class GuiBuildSettings(NDialog):
280
279
  self._build.resetChangedState()
281
280
  return
282
281
 
283
- # END Class GuiBuildSettings
284
-
285
282
 
286
283
  class _FilterTab(NFixedPage):
287
284
 
@@ -298,8 +295,8 @@ class _FilterTab(NFixedPage):
298
295
  F_INCLUDED = 2
299
296
  F_EXCLUDED = 3
300
297
 
301
- def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
302
- super().__init__(parent=buildMain)
298
+ def __init__(self, parent: QWidget, build: BuildSettings) -> None:
299
+ super().__init__(parent=parent)
303
300
 
304
301
  self._treeMap: dict[str, QTreeWidgetItem] = {}
305
302
  self._build = build
@@ -576,8 +573,6 @@ class _FilterTab(NFixedPage):
576
573
  self._scanChildren(item.child(i), items)
577
574
  return items
578
575
 
579
- # END Class _FilterTab
580
-
581
576
 
582
577
  class _HeadingsTab(NScrollablePage):
583
578
 
@@ -588,8 +583,8 @@ class _HeadingsTab(NScrollablePage):
588
583
  EDIT_HSCENE = 5
589
584
  EDIT_SECTION = 6
590
585
 
591
- def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
592
- super().__init__(parent=buildMain)
586
+ def __init__(self, parent: QWidget, build: BuildSettings) -> None:
587
+ super().__init__(parent=parent)
593
588
 
594
589
  self._build = build
595
590
  self._editing = 0
@@ -943,8 +938,6 @@ class _HeadingsTab(NScrollablePage):
943
938
 
944
939
  return
945
940
 
946
- # END Class _HeadingsTab
947
-
948
941
 
949
942
  class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
950
943
 
@@ -969,13 +962,11 @@ class _HeadingSyntaxHighlighter(QSyntaxHighlighter):
969
962
  self.setFormat(pos + ddots, 1, self._fmtSymbol)
970
963
  return
971
964
 
972
- # END Class _HeadingSyntaxHighlighter
973
-
974
965
 
975
966
  class _ContentTab(NScrollableForm):
976
967
 
977
- def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
978
- super().__init__(parent=buildMain)
968
+ def __init__(self, parent: QWidget, build: BuildSettings) -> None:
969
+ super().__init__(parent=parent)
979
970
 
980
971
  self._build = build
981
972
 
@@ -1054,16 +1045,15 @@ class _ContentTab(NScrollableForm):
1054
1045
  self.ignoredKeywords.setText(", ".join(verified))
1055
1046
  return
1056
1047
 
1057
- # END Class _ContentTab
1058
-
1059
1048
 
1060
1049
  class _FormatTab(NScrollableForm):
1061
1050
 
1062
- def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
1063
- super().__init__(parent=buildMain)
1051
+ def __init__(self, parent: QWidget, build: BuildSettings) -> None:
1052
+ super().__init__(parent=parent)
1064
1053
 
1065
1054
  self._build = build
1066
1055
  self._unitScale = 1.0
1056
+ self._textFont = QFont(CONFIG.textFont)
1067
1057
 
1068
1058
  iPx = SHARED.theme.baseIconHeight
1069
1059
  iSz = SHARED.theme.baseIconSize
@@ -1075,24 +1065,16 @@ class _FormatTab(NScrollableForm):
1075
1065
 
1076
1066
  self.addGroupLabel(self._build.getLabel("format.grpFormat"))
1077
1067
 
1078
- # Font Family
1068
+ # Text Font
1079
1069
  self.textFont = QLineEdit(self)
1080
1070
  self.textFont.setReadOnly(True)
1081
- self.btnTextFont = NIconToolButton(self, iSz, "more")
1071
+ self.btnTextFont = NIconToolButton(self, iSz, "font")
1082
1072
  self.btnTextFont.clicked.connect(self._selectFont)
1083
1073
  self.addRow(
1084
1074
  self._build.getLabel("format.textFont"), self.textFont,
1085
- button=self.btnTextFont, stretch=(3, 2)
1075
+ button=self.btnTextFont, stretch=(1, 1)
1086
1076
  )
1087
1077
 
1088
- # Font Size
1089
- self.textSize = NSpinBox(self)
1090
- self.textSize.setMinimum(8)
1091
- self.textSize.setMaximum(60)
1092
- self.textSize.setSingleStep(1)
1093
- self.textSize.setMinimumWidth(spW)
1094
- self.addRow(self._build.getLabel("format.textSize"), self.textSize, unit="pt")
1095
-
1096
1078
  # Line Height
1097
1079
  self.lineHeight = NDoubleSpinBox(self)
1098
1080
  self.lineHeight.setFixedWidth(spW)
@@ -1110,10 +1092,33 @@ class _FormatTab(NScrollableForm):
1110
1092
  self.justifyText = NSwitch(self, height=iPx)
1111
1093
  self.stripUnicode = NSwitch(self, height=iPx)
1112
1094
  self.replaceTabs = NSwitch(self, height=iPx)
1095
+ self.keepBreaks = NSwitch(self, height=iPx)
1096
+ self.showDialogue = NSwitch(self, height=iPx)
1113
1097
 
1114
1098
  self.addRow(self._build.getLabel("format.justifyText"), self.justifyText)
1115
1099
  self.addRow(self._build.getLabel("format.stripUnicode"), self.stripUnicode)
1116
1100
  self.addRow(self._build.getLabel("format.replaceTabs"), self.replaceTabs)
1101
+ self.addRow(self._build.getLabel("format.keepBreaks"), self.keepBreaks)
1102
+ self.addRow(self._build.getLabel("format.showDialogue"), self.showDialogue)
1103
+
1104
+ # First Line Indent
1105
+ # =================
1106
+
1107
+ self.addGroupLabel(self._build.getLabel("format.grpParIndent"))
1108
+
1109
+ self.firstIndent = NSwitch(self, height=iPx)
1110
+ self.indentFirstPar = NSwitch(self, height=iPx)
1111
+
1112
+ self.indentWidth = NDoubleSpinBox(self)
1113
+ self.indentWidth.setFixedWidth(spW)
1114
+ self.indentWidth.setMinimum(0.1)
1115
+ self.indentWidth.setMaximum(9.9)
1116
+ self.indentWidth.setSingleStep(0.1)
1117
+ self.indentWidth.setDecimals(1)
1118
+
1119
+ self.addRow(self._build.getLabel("format.firstLineIndent"), self.firstIndent)
1120
+ self.addRow(self._build.getLabel("format.firstIndentWidth"), self.indentWidth, unit="em")
1121
+ self.addRow(self._build.getLabel("format.indentFirstPar"), self.indentFirstPar)
1117
1122
 
1118
1123
  # Page Layout
1119
1124
  # ===========
@@ -1166,17 +1171,22 @@ class _FormatTab(NScrollableForm):
1166
1171
 
1167
1172
  def loadContent(self) -> None:
1168
1173
  """Populate the widgets."""
1169
- textFont = self._build.getStr("format.textFont")
1170
- if not textFont:
1171
- textFont = str(CONFIG.textFont)
1174
+ self._textFont = QFont()
1175
+ self._textFont.fromString(self._build.getStr("format.textFont"))
1172
1176
 
1173
- self.textFont.setText(textFont)
1174
- self.textSize.setValue(self._build.getInt("format.textSize"))
1175
- self.lineHeight.setValue(self._build.getFloat("format.lineHeight"))
1177
+ self.textFont.setText(describeFont(self._textFont))
1178
+ self.textFont.setCursorPosition(0)
1176
1179
 
1180
+ self.lineHeight.setValue(self._build.getFloat("format.lineHeight"))
1177
1181
  self.justifyText.setChecked(self._build.getBool("format.justifyText"))
1178
1182
  self.stripUnicode.setChecked(self._build.getBool("format.stripUnicode"))
1179
1183
  self.replaceTabs.setChecked(self._build.getBool("format.replaceTabs"))
1184
+ self.keepBreaks.setChecked(self._build.getBool("format.keepBreaks"))
1185
+ self.showDialogue.setChecked(self._build.getBool("format.showDialogue"))
1186
+
1187
+ self.firstIndent.setChecked(self._build.getBool("format.firstLineIndent"))
1188
+ self.indentWidth.setValue(self._build.getFloat("format.firstIndentWidth"))
1189
+ self.indentFirstPar.setChecked(self._build.getBool("format.indentFirstPar"))
1180
1190
 
1181
1191
  pageUnit = self._build.getStr("format.pageUnit")
1182
1192
  index = self.pageUnit.findData(pageUnit)
@@ -1205,13 +1215,18 @@ class _FormatTab(NScrollableForm):
1205
1215
 
1206
1216
  def saveContent(self) -> None:
1207
1217
  """Save choices back into build object."""
1208
- self._build.setValue("format.textFont", self.textFont.text())
1209
- self._build.setValue("format.textSize", self.textSize.value())
1218
+ self._build.setValue("format.textFont", self._textFont.toString())
1210
1219
  self._build.setValue("format.lineHeight", self.lineHeight.value())
1211
1220
 
1212
1221
  self._build.setValue("format.justifyText", self.justifyText.isChecked())
1213
1222
  self._build.setValue("format.stripUnicode", self.stripUnicode.isChecked())
1214
1223
  self._build.setValue("format.replaceTabs", self.replaceTabs.isChecked())
1224
+ self._build.setValue("format.keepBreaks", self.keepBreaks.isChecked())
1225
+ self._build.setValue("format.showDialogue", self.showDialogue.isChecked())
1226
+
1227
+ self._build.setValue("format.firstLineIndent", self.firstIndent.isChecked())
1228
+ self._build.setValue("format.firstIndentWidth", self.indentWidth.value())
1229
+ self._build.setValue("format.indentFirstPar", self.indentFirstPar.isChecked())
1215
1230
 
1216
1231
  self._build.setValue("format.pageUnit", str(self.pageUnit.currentData()))
1217
1232
  self._build.setValue("format.pageSize", str(self.pageSize.currentData()))
@@ -1230,13 +1245,11 @@ class _FormatTab(NScrollableForm):
1230
1245
  @pyqtSlot()
1231
1246
  def _selectFont(self) -> None:
1232
1247
  """Open the QFontDialog and set a font for the font style."""
1233
- currFont = QFont()
1234
- currFont.setFamily(self.textFont.text())
1235
- currFont.setPointSize(self.textSize.value())
1236
- newFont, status = QFontDialog.getFont(currFont, self)
1248
+ font, status = SHARED.getFont(self._textFont, CONFIG.nativeFont)
1237
1249
  if status:
1238
- self.textFont.setText(newFont.family())
1239
- self.textSize.setValue(newFont.pointSize())
1250
+ self.textFont.setText(describeFont(font))
1251
+ self.textFont.setCursorPosition(0)
1252
+ self._textFont = font
1240
1253
  return
1241
1254
 
1242
1255
  @pyqtSlot(int)
@@ -1321,13 +1334,11 @@ class _FormatTab(NScrollableForm):
1321
1334
  self.pageSize.setCurrentIndex(index)
1322
1335
  return
1323
1336
 
1324
- # END Class _FormatTab
1325
-
1326
1337
 
1327
1338
  class _OutputTab(NScrollableForm):
1328
1339
 
1329
- def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
1330
- super().__init__(parent=buildMain)
1340
+ def __init__(self, parent: QWidget, build: BuildSettings) -> None:
1341
+ super().__init__(parent=parent)
1331
1342
 
1332
1343
  self._build = build
1333
1344
 
@@ -1357,9 +1368,6 @@ class _OutputTab(NScrollableForm):
1357
1368
  self.odtPageCountOffset.setMinimumWidth(spW)
1358
1369
  self.addRow(self._build.getLabel("odt.pageCountOffset"), self.odtPageCountOffset)
1359
1370
 
1360
- self.odtFirstLineIndent = NSwitch(self, height=iPx)
1361
- self.addRow(self._build.getLabel("odt.firstLineIndent"), self.odtFirstLineIndent)
1362
-
1363
1371
  # HTML Document
1364
1372
  self.addGroupLabel(self._build.getLabel("html"))
1365
1373
 
@@ -1369,12 +1377,6 @@ class _OutputTab(NScrollableForm):
1369
1377
  self.htmlPreserveTabs = NSwitch(self, height=iPx)
1370
1378
  self.addRow(self._build.getLabel("html.preserveTabs"), self.htmlPreserveTabs)
1371
1379
 
1372
- # Markdown Document
1373
- self.addGroupLabel(self._build.getLabel("md"))
1374
-
1375
- self.mdPreserveBreaks = NSwitch(self, height=iPx)
1376
- self.addRow(self._build.getLabel("md.preserveBreaks"), self.mdPreserveBreaks)
1377
-
1378
1380
  # Finalise
1379
1381
  self.finalise()
1380
1382
 
@@ -1385,10 +1387,8 @@ class _OutputTab(NScrollableForm):
1385
1387
  self.odtAddColours.setChecked(self._build.getBool("odt.addColours"))
1386
1388
  self.odtPageHeader.setText(self._build.getStr("odt.pageHeader"))
1387
1389
  self.odtPageCountOffset.setValue(self._build.getInt("odt.pageCountOffset"))
1388
- self.odtFirstLineIndent.setChecked(self._build.getBool("odt.firstLineIndent"))
1389
1390
  self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles"))
1390
1391
  self.htmlPreserveTabs.setChecked(self._build.getBool("html.preserveTabs"))
1391
- self.mdPreserveBreaks.setChecked(self._build.getBool("md.preserveBreaks"))
1392
1392
  self.odtPageHeader.setCursorPosition(0)
1393
1393
  return
1394
1394
 
@@ -1397,10 +1397,8 @@ class _OutputTab(NScrollableForm):
1397
1397
  self._build.setValue("odt.addColours", self.odtAddColours.isChecked())
1398
1398
  self._build.setValue("odt.pageHeader", self.odtPageHeader.text())
1399
1399
  self._build.setValue("odt.pageCountOffset", self.odtPageCountOffset.value())
1400
- self._build.setValue("odt.firstLineIndent", self.odtFirstLineIndent.isChecked())
1401
1400
  self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked())
1402
1401
  self._build.setValue("html.preserveTabs", self.htmlPreserveTabs.isChecked())
1403
- self._build.setValue("md.preserveBreaks", self.mdPreserveBreaks.isChecked())
1404
1402
  return
1405
1403
 
1406
1404
  ##
@@ -1412,5 +1410,3 @@ class _OutputTab(NScrollableForm):
1412
1410
  self.odtPageHeader.setText(nwHeadFmt.ODT_AUTO)
1413
1411
  self.odtPageHeader.setCursorPosition(0)
1414
1412
  return
1415
-
1416
- # END Class _OutputTab
@@ -23,21 +23,22 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
23
23
  """
24
24
  from __future__ import annotations
25
25
 
26
- import math
27
26
  import logging
27
+ import math
28
28
 
29
29
  from PyQt5.QtCore import pyqtSlot
30
30
  from PyQt5.QtGui import QCloseEvent
31
31
  from PyQt5.QtWidgets import (
32
- QAbstractItemView, QDialog, QDialogButtonBox, QFormLayout, QGridLayout,
33
- QHBoxLayout, QLabel, QSpinBox, QStackedWidget, QTreeWidget,
34
- QTreeWidgetItem, QVBoxLayout, QWidget
32
+ QAbstractItemView, QDialogButtonBox, QFormLayout, QGridLayout, QHBoxLayout,
33
+ QLabel, QSpinBox, QStackedWidget, QTreeWidget, QTreeWidgetItem,
34
+ QVBoxLayout, QWidget
35
35
  )
36
36
 
37
37
  from novelwriter import CONFIG, SHARED
38
38
  from novelwriter.common import formatTime, numberToRoman
39
39
  from novelwriter.constants import nwUnicode
40
40
  from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrollablePage
41
+ from novelwriter.extensions.modified import NNonBlockingDialog
41
42
  from novelwriter.extensions.novelselector import NovelSelector
42
43
  from novelwriter.extensions.pagedsidebar import NPagedSideBar
43
44
  from novelwriter.extensions.switch import NSwitch
@@ -46,7 +47,7 @@ from novelwriter.types import QtAlignRight, QtDecoration, QtDialogClose
46
47
  logger = logging.getLogger(__name__)
47
48
 
48
49
 
49
- class GuiNovelDetails(QDialog):
50
+ class GuiNovelDetails(NNonBlockingDialog):
50
51
 
51
52
  PAGE_OVERVIEW = 1
52
53
  PAGE_CONTENTS = 2
@@ -67,8 +68,8 @@ class GuiNovelDetails(QDialog):
67
68
 
68
69
  # Title
69
70
  self.titleLabel = NColourLabel(
70
- self.tr("Novel Details"), SHARED.theme.helpText,
71
- parent=self, scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
71
+ self.tr("Novel Details"), self, color=SHARED.theme.helpText,
72
+ scale=NColourLabel.HEADER_SCALE, indent=CONFIG.pxInt(4)
72
73
  )
73
74
 
74
75
  # Novel Selector
@@ -96,7 +97,7 @@ class GuiNovelDetails(QDialog):
96
97
 
97
98
  # Buttons
98
99
  self.buttonBox = QDialogButtonBox(QtDialogClose, self)
99
- self.buttonBox.rejected.connect(self.close)
100
+ self.buttonBox.rejected.connect(self.reject)
100
101
 
101
102
  # Assemble
102
103
  self.topBox = QHBoxLayout()
@@ -149,7 +150,7 @@ class GuiNovelDetails(QDialog):
149
150
  """Capture the user closing the window and save settings."""
150
151
  self._saveSettings()
151
152
  event.accept()
152
- self.deleteLater()
153
+ self.softDelete()
153
154
  return
154
155
 
155
156
  ##
@@ -185,8 +186,6 @@ class GuiNovelDetails(QDialog):
185
186
 
186
187
  return
187
188
 
188
- # END Class GuiNovelDetails
189
-
190
189
 
191
190
  class _OverviewPage(NScrollablePage):
192
191
 
@@ -200,8 +199,8 @@ class _OverviewPage(NScrollablePage):
200
199
 
201
200
  # Project Info
202
201
  self.projLabel = NColourLabel(
203
- self.tr("Project"), SHARED.theme.helpText,
204
- parent=self, scale=NColourLabel.HEADER_SCALE
202
+ self.tr("Project"), self, color=SHARED.theme.helpText,
203
+ scale=NColourLabel.HEADER_SCALE
205
204
  )
206
205
 
207
206
  self.projName = QLabel("", self)
@@ -224,8 +223,8 @@ class _OverviewPage(NScrollablePage):
224
223
 
225
224
  # Novel Info
226
225
  self.novelLabel = NColourLabel(
227
- self.tr("Selected Novel"), SHARED.theme.helpText,
228
- parent=self, scale=NColourLabel.HEADER_SCALE
226
+ self.tr("Selected Novel"), self, color=SHARED.theme.helpText,
227
+ scale=NColourLabel.HEADER_SCALE
229
228
  )
230
229
 
231
230
  self.novelName = QLabel("", self)
@@ -293,8 +292,6 @@ class _OverviewPage(NScrollablePage):
293
292
 
294
293
  return
295
294
 
296
- # END Class _OverviewPage
297
-
298
295
 
299
296
  class _ContentsPage(NFixedPage):
300
297
 
@@ -318,8 +315,8 @@ class _ContentsPage(NFixedPage):
318
315
 
319
316
  # Title
320
317
  self.contentLabel = NColourLabel(
321
- self.tr("Table of Contents"), SHARED.theme.helpText,
322
- parent=self, scale=NColourLabel.HEADER_SCALE
318
+ self.tr("Table of Contents"), self, color=SHARED.theme.helpText,
319
+ scale=NColourLabel.HEADER_SCALE
323
320
  )
324
321
 
325
322
  # Contents Tree
@@ -523,5 +520,3 @@ class _ContentsPage(NFixedPage):
523
520
  self._data = SHARED.project.index.getTableOfContents(rootHandle, 2)
524
521
  self._data.append(("", 0, self.tr("END"), 0))
525
522
  return
526
-
527
- # END Class _ContentsPage
@@ -32,11 +32,11 @@ from PyQt5.QtCore import (
32
32
  QAbstractListModel, QEvent, QModelIndex, QObject, QPoint, QSize, Qt,
33
33
  pyqtSignal, pyqtSlot
34
34
  )
35
- from PyQt5.QtGui import QCloseEvent, QColor, QFont, QPaintEvent, QPainter, QPen
35
+ from PyQt5.QtGui import QCloseEvent, QColor, QFont, QPainter, QPaintEvent, QPen
36
36
  from PyQt5.QtWidgets import (
37
- QAction, QApplication, QDialog, QFileDialog, QFormLayout, QHBoxLayout,
38
- QLabel, QLineEdit, QListView, QMenu, QPushButton, QScrollArea, QShortcut,
39
- QStackedWidget, QStyleOptionViewItem, QStyledItemDelegate, QVBoxLayout,
37
+ QAction, QApplication, QFileDialog, QFormLayout, QHBoxLayout, QLabel,
38
+ QLineEdit, QListView, QMenu, QPushButton, QScrollArea, QShortcut,
39
+ QStackedWidget, QStyledItemDelegate, QStyleOptionViewItem, QVBoxLayout,
40
40
  QWidget
41
41
  )
42
42
 
@@ -46,7 +46,7 @@ from novelwriter.constants import nwFiles
46
46
  from novelwriter.core.coretools import ProjectBuilder
47
47
  from novelwriter.enum import nwItemClass
48
48
  from novelwriter.extensions.configlayout import NWrappedWidgetBox
49
- from novelwriter.extensions.modified import NIconToolButton, NSpinBox
49
+ from novelwriter.extensions.modified import NDialog, NIconToolButton, NSpinBox
50
50
  from novelwriter.extensions.switch import NSwitch
51
51
  from novelwriter.extensions.versioninfo import VersionInfoWidget
52
52
  from novelwriter.types import QtAlignLeft, QtAlignRightTop, QtSelected
@@ -56,7 +56,7 @@ logger = logging.getLogger(__name__)
56
56
  PANEL_ALPHA = 178
57
57
 
58
58
 
59
- class GuiWelcome(QDialog):
59
+ class GuiWelcome(NDialog):
60
60
 
61
61
  openProjectRequest = pyqtSignal(Path)
62
62
 
@@ -196,7 +196,7 @@ class GuiWelcome(QDialog):
196
196
  """Capture the user closing the window and save settings."""
197
197
  self._saveSettings()
198
198
  event.accept()
199
- self.deleteLater()
199
+ self.softDelete()
200
200
  return
201
201
 
202
202
  ##
@@ -220,8 +220,7 @@ class GuiWelcome(QDialog):
220
220
  @pyqtSlot()
221
221
  def _browseForProject(self) -> None:
222
222
  """Browse for a project to open."""
223
- if path := SHARED.getProjectPath(self, path=CONFIG.lastPath(), allowZip=False):
224
- CONFIG.setLastPath(path)
223
+ if path := SHARED.getProjectPath(self, path=CONFIG.homePath(), allowZip=False):
225
224
  self._openProjectPath(path)
226
225
  return
227
226
 
@@ -267,8 +266,6 @@ class GuiWelcome(QDialog):
267
266
  self.btnCreate.setFocus()
268
267
  return
269
268
 
270
- # END Class GuiWelcome
271
-
272
269
 
273
270
  class _OpenProjectPage(QWidget):
274
271
 
@@ -392,8 +389,6 @@ class _OpenProjectPage(QWidget):
392
389
  self._projectClicked(index)
393
390
  return
394
391
 
395
- # END Class _OpenProjectPage
396
-
397
392
 
398
393
  class _ProjectListItem(QStyledItemDelegate):
399
394
 
@@ -450,8 +445,6 @@ class _ProjectListItem(QStyledItemDelegate):
450
445
  """Set the size hint to fixed height."""
451
446
  return QSize(opt.rect.width(), self._hPx)
452
447
 
453
- # END Class _ProjectListItem
454
-
455
448
 
456
449
  class _ProjectListModel(QAbstractListModel):
457
450
 
@@ -491,8 +484,6 @@ class _ProjectListModel(QAbstractListModel):
491
484
  return True
492
485
  return False
493
486
 
494
- # END Class _ProjectListModel
495
-
496
487
 
497
488
  class _NewProjectPage(QWidget):
498
489
 
@@ -548,8 +539,6 @@ class _NewProjectPage(QWidget):
548
539
  self.openProjectRequest.emit(path)
549
540
  return
550
541
 
551
- # END Class _NewProjectPage
552
-
553
542
 
554
543
  class _NewProjectForm(QWidget):
555
544
 
@@ -560,7 +549,7 @@ class _NewProjectForm(QWidget):
560
549
  def __init__(self, parent: QWidget) -> None:
561
550
  super().__init__(parent=parent)
562
551
 
563
- self._basePath = CONFIG.homePath()
552
+ self._basePath = CONFIG.lastPath("project")
564
553
  self._fillMode = self.FILL_BLANK
565
554
  self._copyPath = None
566
555
 
@@ -736,12 +725,13 @@ class _NewProjectForm(QWidget):
736
725
  @pyqtSlot()
737
726
  def _doBrowse(self) -> None:
738
727
  """Select a project folder."""
739
- if projDir := QFileDialog.getExistingDirectory(
728
+ if path := QFileDialog.getExistingDirectory(
740
729
  self, self.tr("Select Project Folder"),
741
730
  str(self._basePath), options=QFileDialog.Option.ShowDirsOnly
742
731
  ):
743
- self._basePath = Path(projDir)
732
+ self._basePath = Path(path)
744
733
  self._updateProjPath()
734
+ CONFIG.setLastPath("project", path)
745
735
  return
746
736
 
747
737
  @pyqtSlot()
@@ -805,8 +795,6 @@ class _NewProjectForm(QWidget):
805
795
 
806
796
  return
807
797
 
808
- # END Class _NewProjectForm
809
-
810
798
 
811
799
  class _PopLeftDirectionMenu(QMenu):
812
800
 
@@ -817,5 +805,3 @@ class _PopLeftDirectionMenu(QMenu):
817
805
  offset = QPoint(parent.width() - self.width(), parent.height())
818
806
  self.move(parent.mapToGlobal(offset))
819
807
  return super(_PopLeftDirectionMenu, self).event(event)
820
-
821
- # END Class _PopLeftDirectionMenu
@@ -32,15 +32,16 @@ from typing import TYPE_CHECKING
32
32
  from PyQt5.QtCore import Qt, pyqtSlot
33
33
  from PyQt5.QtGui import QCloseEvent, QCursor, QPixmap
34
34
  from PyQt5.QtWidgets import (
35
- QAction, QApplication, QDialog, QDialogButtonBox, QFileDialog, QGridLayout,
35
+ QAction, QApplication, QDialogButtonBox, QFileDialog, QGridLayout,
36
36
  QGroupBox, QHBoxLayout, QLabel, QMenu, QSpinBox, QTreeWidget,
37
37
  QTreeWidgetItem
38
38
  )
39
39
 
40
40
  from novelwriter import CONFIG, SHARED
41
- from novelwriter.common import formatTime, checkInt, checkIntTuple, minmax
41
+ from novelwriter.common import checkInt, checkIntTuple, formatTime, minmax
42
42
  from novelwriter.constants import nwConst
43
43
  from novelwriter.error import formatException
44
+ from novelwriter.extensions.modified import NToolDialog
44
45
  from novelwriter.extensions.switch import NSwitch
45
46
  from novelwriter.types import (
46
47
  QtAlignLeftMiddle, QtAlignRight, QtAlignRightMiddle, QtDecoration,
@@ -53,7 +54,7 @@ if TYPE_CHECKING: # pragma: no cover
53
54
  logger = logging.getLogger(__name__)
54
55
 
55
56
 
56
- class GuiWritingStats(QDialog):
57
+ class GuiWritingStats(NToolDialog):
57
58
  """GUI Tools: Writing Statistics
58
59
 
59
60
  Displays data from the NWSessionLog object.
@@ -68,13 +69,11 @@ class GuiWritingStats(QDialog):
68
69
  FMT_JSON = 0
69
70
  FMT_CSV = 1
70
71
 
71
- def __init__(self, mainGui: GuiMain) -> None:
72
- super().__init__(parent=mainGui)
72
+ def __init__(self, parent: GuiMain) -> None:
73
+ super().__init__(parent=parent)
73
74
 
74
75
  logger.debug("Create: GuiWritingStats")
75
76
  self.setObjectName("GuiWritingStats")
76
- if CONFIG.osDarwin:
77
- self.setWindowFlag(Qt.WindowType.Tool)
78
77
 
79
78
  self.logData = []
80
79
  self.filterData = []
@@ -319,7 +318,7 @@ class GuiWritingStats(QDialog):
319
318
  def closeEvent(self, event: QCloseEvent) -> None:
320
319
  """Capture the user closing the window."""
321
320
  event.accept()
322
- self.deleteLater()
321
+ self.softDelete()
323
322
  return
324
323
 
325
324
  ##
@@ -385,14 +384,14 @@ class GuiWritingStats(QDialog):
385
384
  return False
386
385
 
387
386
  # Generate the file name
388
- savePath = CONFIG.lastPath() / f"sessionStats.{fileExt}"
387
+ savePath = CONFIG.lastPath("stats") / f"sessionStats.{fileExt}"
389
388
  savePath, _ = QFileDialog.getSaveFileName(
390
389
  self, self.tr("Save Data As"), str(savePath), f"{textFmt} (*.{fileExt})"
391
390
  )
392
391
  if not savePath:
393
392
  return False
394
393
 
395
- CONFIG.setLastPath(savePath)
394
+ CONFIG.setLastPath("stats", savePath)
396
395
 
397
396
  # Do the actual writing
398
397
  wSuccess = False
@@ -615,5 +614,3 @@ class GuiWritingStats(QDialog):
615
614
  self.labelFilter.setText(formatTime(round(self.timeFilter)))
616
615
 
617
616
  return
618
-
619
- # END Class GuiWritingStats