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 Main Menu
3
3
  ===========================
4
4
 
5
5
  File History:
6
- Created: 2019-04-27 [0.0.1]
6
+ Created: 2019-04-27 [0.0.1] GuiMainMenu
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,16 +27,16 @@ import logging
27
27
 
28
28
  from typing import TYPE_CHECKING
29
29
  from pathlib import Path
30
- from urllib.parse import urljoin
31
- from urllib.request import pathname2url
32
30
 
33
- from PyQt5.QtCore import QUrl, pyqtSignal, pyqtSlot
34
31
  from PyQt5.QtGui import QDesktopServices
32
+ from PyQt5.QtCore import QUrl, pyqtSignal, pyqtSlot
35
33
  from PyQt5.QtWidgets import QMenuBar, QAction
36
34
 
37
35
  from novelwriter import CONFIG, SHARED
38
36
  from novelwriter.enum import nwDocAction, nwDocInsert, nwWidget
37
+ from novelwriter.common import openExternalPath
39
38
  from novelwriter.constants import nwConst, trConst, nwKeyWords, nwLabels, nwUnicode
39
+ from novelwriter.extensions.eventfilters import StatusTipFilter
40
40
 
41
41
  if TYPE_CHECKING: # pragma: no cover
42
42
  from novelwriter.guimain import GuiMain
@@ -74,6 +74,8 @@ class GuiMainMenu(QMenuBar):
74
74
  self._buildToolsMenu()
75
75
  self._buildHelpMenu()
76
76
 
77
+ self.installEventFilter(StatusTipFilter(mainGui))
78
+
77
79
  logger.debug("Ready: GuiMainMenu")
78
80
 
79
81
  return
@@ -111,9 +113,7 @@ class GuiMainMenu(QMenuBar):
111
113
  def _openUserManualFile(self) -> None:
112
114
  """Open the documentation in PDF format."""
113
115
  if isinstance(CONFIG.pdfDocs, Path):
114
- QDesktopServices.openUrl(
115
- QUrl(urljoin("file:", pathname2url(str(CONFIG.pdfDocs))))
116
- )
116
+ openExternalPath(CONFIG.pdfDocs)
117
117
  return
118
118
 
119
119
  @pyqtSlot(str)
@@ -157,12 +157,12 @@ class GuiMainMenu(QMenuBar):
157
157
  # Project > Project Settings
158
158
  self.aProjectSettings = self.projMenu.addAction(self.tr("Project Settings"))
159
159
  self.aProjectSettings.setShortcut("Ctrl+Shift+,")
160
- self.aProjectSettings.triggered.connect(lambda: self.mainGui.showProjectSettingsDialog())
160
+ self.aProjectSettings.triggered.connect(self.mainGui.showProjectSettingsDialog)
161
161
 
162
162
  # Project > Project Details
163
163
  self.aProjectDetails = self.projMenu.addAction(self.tr("Project Details"))
164
164
  self.aProjectDetails.setShortcut("Shift+F6")
165
- self.aProjectDetails.triggered.connect(lambda: self.mainGui.showProjectDetailsDialog())
165
+ self.aProjectDetails.triggered.connect(self.mainGui.showProjectDetailsDialog)
166
166
 
167
167
  # Project > Separator
168
168
  self.projMenu.addSeparator()
@@ -174,7 +174,7 @@ class GuiMainMenu(QMenuBar):
174
174
 
175
175
  # Project > Delete
176
176
  self.aDeleteItem = self.projMenu.addAction(self.tr("Delete Item"))
177
- self.aDeleteItem.setShortcuts(["Ctrl+Del", "Ctrl+Shift+Del"]) # Latter is deprecated
177
+ self.aDeleteItem.setShortcut("Ctrl+Shift+Del") # Cannot be Ctrl+Del, see #629
178
178
  self.aDeleteItem.triggered.connect(lambda: self.mainGui.projView.requestDeleteItem(None))
179
179
 
180
180
  # Project > Empty Trash
@@ -567,6 +567,13 @@ class GuiMainMenu(QMenuBar):
567
567
  lambda: self.requestDocInsert.emit(nwDocInsert.SYNOPSIS)
568
568
  )
569
569
 
570
+ # Insert > Short Description Comment
571
+ self.aInsShort = self.mInsComments.addAction(self.tr("Short Description Comment"))
572
+ self.aInsShort.setShortcut("Ctrl+K, H")
573
+ self.aInsShort.triggered.connect(
574
+ lambda: self.requestDocInsert.emit(nwDocInsert.SHORT)
575
+ )
576
+
570
577
  # Insert > Symbols
571
578
  self.mInsBreaks = self.insMenu.addMenu(self.tr("Page Break and Space"))
572
579
 
@@ -589,8 +596,10 @@ class GuiMainMenu(QMenuBar):
589
596
  )
590
597
 
591
598
  # Insert > Placeholder Text
592
- self.aLipsumText = self.mInsBreaks.addAction(self.tr("Placeholder Text"))
593
- self.aLipsumText.triggered.connect(lambda: self.mainGui.showLoremIpsumDialog())
599
+ self.aLipsumText = self.insMenu.addAction(self.tr("Placeholder Text"))
600
+ self.aLipsumText.triggered.connect(
601
+ lambda: self.requestDocInsert.emit(nwDocInsert.LIPSUM)
602
+ )
594
603
 
595
604
  return
596
605
 
@@ -599,25 +608,25 @@ class GuiMainMenu(QMenuBar):
599
608
  # Format
600
609
  self.fmtMenu = self.addMenu(self.tr("&Format"))
601
610
 
602
- # Format > Emphasis
603
- self.aFmtEmph = self.fmtMenu.addAction(self.tr("Emphasis"))
604
- self.aFmtEmph.setShortcut("Ctrl+I")
605
- self.aFmtEmph.triggered.connect(
606
- lambda: self.requestDocAction.emit(nwDocAction.EMPH)
611
+ # Format > Bold
612
+ self.aFmtBold = self.fmtMenu.addAction(self.tr("Bold"))
613
+ self.aFmtBold.setShortcut("Ctrl+B")
614
+ self.aFmtBold.triggered.connect(
615
+ lambda: self.requestDocAction.emit(nwDocAction.MD_BOLD)
607
616
  )
608
617
 
609
- # Format > Strong Emphasis
610
- self.aFmtStrong = self.fmtMenu.addAction(self.tr("Strong Emphasis"))
611
- self.aFmtStrong.setShortcut("Ctrl+B")
612
- self.aFmtStrong.triggered.connect(
613
- lambda: self.requestDocAction.emit(nwDocAction.STRONG)
618
+ # Format > Italic
619
+ self.aFmtItalic = self.fmtMenu.addAction(self.tr("Italic"))
620
+ self.aFmtItalic.setShortcut("Ctrl+I")
621
+ self.aFmtItalic.triggered.connect(
622
+ lambda: self.requestDocAction.emit(nwDocAction.MD_ITALIC)
614
623
  )
615
624
 
616
625
  # Format > Strikethrough
617
626
  self.aFmtStrike = self.fmtMenu.addAction(self.tr("Strikethrough"))
618
627
  self.aFmtStrike.setShortcut("Ctrl+D")
619
628
  self.aFmtStrike.triggered.connect(
620
- lambda: self.requestDocAction.emit(nwDocAction.STRIKE)
629
+ lambda: self.requestDocAction.emit(nwDocAction.MD_STRIKE)
621
630
  )
622
631
 
623
632
  # Edit > Separator
@@ -643,18 +652,18 @@ class GuiMainMenu(QMenuBar):
643
652
  # Shortcodes
644
653
  self.mShortcodes = self.fmtMenu.addMenu(self.tr("More Formats ..."))
645
654
 
646
- # Shortcode Italic
647
- self.aScItalic = self.mShortcodes.addAction(self.tr("Italics (Shortcode)"))
648
- self.aScItalic.triggered.connect(
649
- lambda: self.requestDocAction.emit(nwDocAction.SC_ITALIC)
650
- )
651
-
652
655
  # Shortcode Bold
653
656
  self.aScBold = self.mShortcodes.addAction(self.tr("Bold (Shortcode)"))
654
657
  self.aScBold.triggered.connect(
655
658
  lambda: self.requestDocAction.emit(nwDocAction.SC_BOLD)
656
659
  )
657
660
 
661
+ # Shortcode Italic
662
+ self.aScItalic = self.mShortcodes.addAction(self.tr("Italics (Shortcode)"))
663
+ self.aScItalic.triggered.connect(
664
+ lambda: self.requestDocAction.emit(nwDocAction.SC_ITALIC)
665
+ )
666
+
658
667
  # Shortcode Strikethrough
659
668
  self.aScStrike = self.mShortcodes.addAction(self.tr("Strikethrough (Shortcode)"))
660
669
  self.aScStrike.triggered.connect(
@@ -868,7 +877,12 @@ class GuiMainMenu(QMenuBar):
868
877
 
869
878
  # Tools > Project Word List
870
879
  self.aEditWordList = self.toolsMenu.addAction(self.tr("Project Word List"))
871
- self.aEditWordList.triggered.connect(lambda: self.mainGui.showProjectWordListDialog())
880
+ self.aEditWordList.triggered.connect(self.mainGui.showProjectWordListDialog)
881
+
882
+ # Tools > Add Dictionaries
883
+ if CONFIG.osWindows or CONFIG.isDebug:
884
+ self.aAddDicts = self.toolsMenu.addAction(self.tr("Add Dictionaries"))
885
+ self.aAddDicts.triggered.connect(self.mainGui.showDictionariesDialog)
872
886
 
873
887
  # Tools > Separator
874
888
  self.toolsMenu.addSeparator()
@@ -893,13 +907,13 @@ class GuiMainMenu(QMenuBar):
893
907
  # Tools > Writing Statistics
894
908
  self.aWritingStats = self.toolsMenu.addAction(self.tr("Writing Statistics"))
895
909
  self.aWritingStats.setShortcut("F6")
896
- self.aWritingStats.triggered.connect(lambda: self.mainGui.showWritingStatsDialog())
910
+ self.aWritingStats.triggered.connect(self.mainGui.showWritingStatsDialog)
897
911
 
898
912
  # Tools > Preferences
899
913
  self.aPreferences = self.toolsMenu.addAction(self.tr("Preferences"))
900
914
  self.aPreferences.setShortcut("Ctrl+,")
901
915
  self.aPreferences.setMenuRole(QAction.PreferencesRole)
902
- self.aPreferences.triggered.connect(lambda: self.mainGui.showPreferencesDialog())
916
+ self.aPreferences.triggered.connect(self.mainGui.showPreferencesDialog)
903
917
 
904
918
  return
905
919
 
@@ -911,12 +925,12 @@ class GuiMainMenu(QMenuBar):
911
925
  # Help > About
912
926
  self.aAboutNW = self.helpMenu.addAction(self.tr("About novelWriter"))
913
927
  self.aAboutNW.setMenuRole(QAction.AboutRole)
914
- self.aAboutNW.triggered.connect(lambda: self.mainGui.showAboutNWDialog())
928
+ self.aAboutNW.triggered.connect(self.mainGui.showAboutNWDialog)
915
929
 
916
930
  # Help > About Qt5
917
931
  self.aAboutQt = self.helpMenu.addAction(self.tr("About Qt5"))
918
932
  self.aAboutQt.setMenuRole(QAction.AboutQtRole)
919
- self.aAboutQt.triggered.connect(lambda: self.mainGui.showAboutQtDialog())
933
+ self.aAboutQt.triggered.connect(self.mainGui.showAboutQtDialog)
920
934
 
921
935
  # Help > Separator
922
936
  self.helpMenu.addSeparator()
@@ -952,7 +966,7 @@ class GuiMainMenu(QMenuBar):
952
966
 
953
967
  # Document > Check for Updates
954
968
  self.aUpdates = self.helpMenu.addAction(self.tr("Check for New Release"))
955
- self.aUpdates.triggered.connect(lambda: self.mainGui.showUpdatesDialog())
969
+ self.aUpdates.triggered.connect(self.mainGui.showUpdatesDialog)
956
970
 
957
971
  return
958
972
 
@@ -8,7 +8,7 @@ Created: 2022-06-12 [2.0rc1] GuiNovelView
8
8
  Created: 2022-06-12 [2.0rc1] GuiNovelToolBar
9
9
 
10
10
  This file is a part of novelWriter
11
- Copyright 2018–2020, Veronica Berglyd Olsen
11
+ Copyright 2018–2024, Veronica Berglyd Olsen
12
12
 
13
13
  This program is free software: you can redistribute it and/or modify
14
14
  it under the terms of the GNU General Public License as published by
@@ -145,6 +145,7 @@ class GuiNovelView(QWidget):
145
145
  """Run closing project tasks."""
146
146
  lastColType = self.novelTree.lastColType
147
147
  lastColSize = self.novelTree.lastColSize
148
+ logger.debug("Saving State: GuiNovelView")
148
149
  pOptions = SHARED.project.options
149
150
  pOptions.setValue("GuiNovelView", "lastCol", lastColType)
150
151
  pOptions.setValue("GuiNovelView", "lastColSize", lastColSize)
@@ -205,18 +206,18 @@ class GuiNovelToolBar(QWidget):
205
206
 
206
207
  # Novel Selector
207
208
  selFont = self.font()
208
- selFont.setWeight(QFont.Bold)
209
+ selFont.setWeight(QFont.Weight.Bold)
209
210
  self.novelPrefix = self.tr("Outline of {0}")
210
211
  self.novelValue = NovelSelector(self)
211
212
  self.novelValue.setFont(selFont)
212
213
  self.novelValue.setMinimumWidth(CONFIG.pxInt(150))
213
- self.novelValue.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
214
+ self.novelValue.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
214
215
  self.novelValue.novelSelectionChanged.connect(self.setCurrentRoot)
215
216
 
216
217
  self.tbNovel = QToolButton(self)
217
218
  self.tbNovel.setToolTip(self.tr("Novel Root"))
218
219
  self.tbNovel.setIconSize(QSize(iPx, iPx))
219
- self.tbNovel.clicked.connect(self._openNovelSelector)
220
+ self.tbNovel.clicked.connect(self.novelValue.showPopup)
220
221
 
221
222
  # Refresh Button
222
223
  self.tbRefresh = QToolButton(self)
@@ -243,7 +244,7 @@ class GuiNovelToolBar(QWidget):
243
244
  self.tbMore.setToolTip(self.tr("More Options"))
244
245
  self.tbMore.setIconSize(QSize(iPx, iPx))
245
246
  self.tbMore.setMenu(self.mMore)
246
- self.tbMore.setPopupMode(QToolButton.InstantPopup)
247
+ self.tbMore.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
247
248
 
248
249
  # Assemble
249
250
  self.outerBox = QHBoxLayout()
@@ -274,7 +275,7 @@ class GuiNovelToolBar(QWidget):
274
275
  self.tbMore.setIcon(SHARED.theme.getIcon("menu"))
275
276
 
276
277
  qPalette = self.palette()
277
- qPalette.setBrush(QPalette.Window, qPalette.base())
278
+ qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base())
278
279
  self.setPalette(qPalette)
279
280
 
280
281
  # StyleSheets
@@ -326,12 +327,6 @@ class GuiNovelToolBar(QWidget):
326
327
  # Private Slots
327
328
  ##
328
329
 
329
- @pyqtSlot()
330
- def _openNovelSelector(self) -> None:
331
- """Trigger the dropdown list of the novel selector."""
332
- self.novelValue.showPopup()
333
- return
334
-
335
330
  @pyqtSlot()
336
331
  def _refreshNovelTree(self) -> None:
337
332
  """Rebuild the current tree."""
@@ -407,14 +402,14 @@ class GuiNovelTree(QTreeWidget):
407
402
  cMg = CONFIG.pxInt(6)
408
403
 
409
404
  self.setIconSize(QSize(iPx, iPx))
410
- self.setFrameStyle(QFrame.NoFrame)
405
+ self.setFrameStyle(QFrame.Shape.NoFrame)
411
406
  self.setUniformRowHeights(True)
412
407
  self.setAllColumnsShowFocus(True)
413
408
  self.setHeaderHidden(True)
414
409
  self.setIndentation(0)
415
410
  self.setColumnCount(4)
416
- self.setSelectionBehavior(QAbstractItemView.SelectRows)
417
- self.setSelectionMode(QAbstractItemView.SingleSelection)
411
+ self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
412
+ self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
418
413
  self.setExpandsOnDoubleClick(False)
419
414
  self.setDragEnabled(False)
420
415
 
@@ -422,10 +417,10 @@ class GuiNovelTree(QTreeWidget):
422
417
  treeHeader = self.header()
423
418
  treeHeader.setStretchLastSection(False)
424
419
  treeHeader.setMinimumSectionSize(iPx + cMg)
425
- treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.Stretch)
426
- treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeToContents)
427
- treeHeader.setSectionResizeMode(self.C_EXTRA, QHeaderView.ResizeToContents)
428
- treeHeader.setSectionResizeMode(self.C_MORE, QHeaderView.ResizeToContents)
420
+ treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.ResizeMode.Stretch)
421
+ treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeMode.ResizeToContents)
422
+ treeHeader.setSectionResizeMode(self.C_EXTRA, QHeaderView.ResizeMode.ResizeToContents)
423
+ treeHeader.setSectionResizeMode(self.C_MORE, QHeaderView.ResizeMode.ResizeToContents)
429
424
 
430
425
  # Pre-Generate Tree Formatting
431
426
  fH1 = self.font()
@@ -454,14 +449,14 @@ class GuiNovelTree(QTreeWidget):
454
449
  """Set or update tree widget settings."""
455
450
  # Scroll bars
456
451
  if CONFIG.hideVScroll:
457
- self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
452
+ self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
458
453
  else:
459
- self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
454
+ self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
460
455
 
461
456
  if CONFIG.hideHScroll:
462
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
457
+ self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
463
458
  else:
464
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
459
+ self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
465
460
 
466
461
  return
467
462
 
@@ -521,21 +516,16 @@ class GuiNovelTree(QTreeWidget):
521
516
 
522
517
  def refreshHandle(self, tHandle: str) -> None:
523
518
  """Refresh the data for a given handle."""
524
- idxData = SHARED.project.index.getItemData(tHandle)
525
- if idxData is None:
526
- return
527
-
528
- logger.debug("Refreshing meta data for item '%s'", tHandle)
529
- for sTitle, tHeading in idxData.items():
530
- sKey = f"{tHandle}:{sTitle}"
531
- trItem = self._treeMap.get(sKey, None)
532
- if trItem is None:
533
- logger.debug("Heading '%s' not in novel tree", sKey)
534
- self.refreshTree()
535
- return
536
-
537
- self._updateTreeItemValues(trItem, tHeading, tHandle, sTitle)
538
-
519
+ if idxData := SHARED.project.index.getItemData(tHandle):
520
+ logger.debug("Refreshing meta data for item '%s'", tHandle)
521
+ for sTitle, tHeading in idxData.items():
522
+ sKey = f"{tHandle}:{sTitle}"
523
+ if trItem := self._treeMap.get(sKey, None):
524
+ self._updateTreeItemValues(trItem, tHeading, tHandle, sTitle)
525
+ else:
526
+ logger.debug("Heading '%s' not in novel tree", sKey)
527
+ self.refreshTree()
528
+ return
539
529
  return
540
530
 
541
531
  def getSelectedHandle(self) -> tuple[str | None, str | None]:
@@ -566,27 +556,25 @@ class GuiNovelTree(QTreeWidget):
566
556
  self._lastColSize = minmax(colSize, 15, 75)/100.0
567
557
  return
568
558
 
569
- def setActiveHandle(self, tHandle: str | None) -> None:
559
+ def setActiveHandle(self, tHandle: str | None, doScroll: bool = False) -> None:
570
560
  """Highlight the rows associated with a given handle."""
571
- tStart = time()
572
-
561
+ didScroll = False
573
562
  self._actHandle = tHandle
574
563
  for i in range(self.topLevelItemCount()):
575
- tItem = self.topLevelItem(i)
576
- if tItem is not None:
564
+ if tItem := self.topLevelItem(i):
577
565
  if tItem.data(self.C_DATA, self.D_HANDLE) == tHandle:
578
566
  tItem.setBackground(self.C_TITLE, self.palette().alternateBase())
579
567
  tItem.setBackground(self.C_WORDS, self.palette().alternateBase())
580
568
  tItem.setBackground(self.C_EXTRA, self.palette().alternateBase())
581
569
  tItem.setBackground(self.C_MORE, self.palette().alternateBase())
570
+ if doScroll and not didScroll:
571
+ self.scrollToItem(tItem, QAbstractItemView.ScrollHint.PositionAtCenter)
572
+ didScroll = True
582
573
  else:
583
574
  tItem.setBackground(self.C_TITLE, self.palette().base())
584
575
  tItem.setBackground(self.C_WORDS, self.palette().base())
585
576
  tItem.setBackground(self.C_EXTRA, self.palette().base())
586
577
  tItem.setBackground(self.C_MORE, self.palette().base())
587
-
588
- logger.debug("Highlighted Novel Tree in %.3f ms", (time() - tStart)*1000)
589
-
590
578
  return
591
579
 
592
580
  ##
@@ -600,12 +588,12 @@ class GuiNovelTree(QTreeWidget):
600
588
  """
601
589
  super().mousePressEvent(event)
602
590
 
603
- if event.button() == Qt.LeftButton:
591
+ if event.button() == Qt.MouseButton.LeftButton:
604
592
  selItem = self.indexAt(event.pos())
605
593
  if not selItem.isValid():
606
594
  self.clearSelection()
607
595
 
608
- elif event.button() == Qt.MiddleButton:
596
+ elif event.button() == Qt.MouseButton.MiddleButton:
609
597
  selItem = self.itemAt(event.pos())
610
598
  if not isinstance(selItem, QTreeWidgetItem):
611
599
  return
@@ -636,7 +624,10 @@ class GuiNovelTree(QTreeWidget):
636
624
  trItem = self.topLevelItem(i)
637
625
  if isinstance(trItem, QTreeWidgetItem):
638
626
  lastText = trItem.data(self.C_DATA, self.D_EXTRA)
639
- trItem.setText(self.C_EXTRA, fMetric.elidedText(lastText, Qt.ElideRight, eliW))
627
+ trItem.setText(
628
+ self.C_EXTRA,
629
+ fMetric.elidedText(lastText, Qt.TextElideMode.ElideRight, eliW)
630
+ )
640
631
  return
641
632
 
642
633
  ##
@@ -692,7 +683,7 @@ class GuiNovelTree(QTreeWidget):
692
683
  newItem.setData(self.C_DATA, self.D_HANDLE, tHandle)
693
684
  newItem.setData(self.C_DATA, self.D_TITLE, sTitle)
694
685
  newItem.setData(self.C_DATA, self.D_KEY, tKey)
695
- newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
686
+ newItem.setTextAlignment(self.C_WORDS, Qt.AlignmentFlag.AlignRight)
696
687
 
697
688
  self._updateTreeItemValues(newItem, novIdx, tHandle, sTitle)
698
689
  self._treeMap[tKey] = newItem
@@ -711,16 +702,16 @@ class GuiNovelTree(QTreeWidget):
711
702
  iLevel = nwHeaders.H_LEVEL.get(idxItem.level, 0)
712
703
  hDec = SHARED.theme.getHeaderDecoration(iLevel)
713
704
 
714
- trItem.setData(self.C_TITLE, Qt.DecorationRole, hDec)
705
+ trItem.setData(self.C_TITLE, Qt.ItemDataRole.DecorationRole, hDec)
715
706
  trItem.setText(self.C_TITLE, idxItem.title)
716
707
  trItem.setFont(self.C_TITLE, self._hFonts[iLevel])
717
708
  trItem.setText(self.C_WORDS, f"{idxItem.wordCount:n}")
718
- trItem.setData(self.C_MORE, Qt.DecorationRole, self._pMore)
709
+ trItem.setData(self.C_MORE, Qt.ItemDataRole.DecorationRole, self._pMore)
719
710
 
720
711
  # Custom column
721
712
  mW = int(self._lastColSize * self.viewport().width())
722
713
  lastText, toolTip = self._getLastColumnText(tHandle, sTitle)
723
- elideText = self.fontMetrics().elidedText(lastText, Qt.ElideRight, mW)
714
+ elideText = self.fontMetrics().elidedText(lastText, Qt.TextElideMode.ElideRight, mW)
724
715
  trItem.setText(self.C_EXTRA, elideText)
725
716
  trItem.setData(self.C_DATA, self.D_EXTRA, lastText)
726
717
  trItem.setToolTip(self.C_EXTRA, toolTip)
@@ -10,7 +10,7 @@ Created: 2019-11-16 [0.4.1] GuiOutlineHeaderMenu
10
10
  Created: 2020-06-02 [0.7] GuiOutlineDetails
11
11
 
12
12
  This file is a part of novelWriter
13
- Copyright 2018–2023, Veronica Berglyd Olsen
13
+ Copyright 2018–2024, Veronica Berglyd Olsen
14
14
 
15
15
  This program is free software: you can redistribute it and/or modify
16
16
  it under the terms of the GNU General Public License as published by
@@ -377,13 +377,17 @@ class GuiOutlineTree(QTreeWidget):
377
377
  fH2 = self.font()
378
378
  fH2.setBold(True)
379
379
 
380
+ iType = nwItemType.FILE
381
+ iClass = nwItemClass.NO_CLASS
382
+ iLayout = nwItemLayout.DOCUMENT
383
+
380
384
  self._hFonts = [self.font(), fH1, fH2, self.font(), self.font()]
381
385
  self._dIcon = {
382
- "H0": SHARED.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H0"),
383
- "H1": SHARED.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H1"),
384
- "H2": SHARED.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H2"),
385
- "H3": SHARED.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H3"),
386
- "H4": SHARED.theme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, "H4"),
386
+ "H0": SHARED.theme.getItemIcon(iType, iClass, iLayout, "H0"),
387
+ "H1": SHARED.theme.getItemIcon(iType, iClass, iLayout, "H1"),
388
+ "H2": SHARED.theme.getItemIcon(iType, iClass, iLayout, "H2"),
389
+ "H3": SHARED.theme.getItemIcon(iType, iClass, iLayout, "H3"),
390
+ "H4": SHARED.theme.getItemIcon(iType, iClass, iLayout, "H4"),
387
391
  }
388
392
 
389
393
  # Internals
@@ -549,7 +553,7 @@ class GuiOutlineTree(QTreeWidget):
549
553
  """Load the state of the main tree header, that is, column order
550
554
  and column width.
551
555
  """
552
- # Load whatever we saved last time, regardless of wether it
556
+ # Load whatever we saved last time, regardless of whether it
553
557
  # contains the correct names or number of columns.
554
558
  colState = SHARED.project.options.getValue("GuiOutline", "columnState", {})
555
559
 
@@ -602,6 +606,7 @@ class GuiOutlineTree(QTreeWidget):
602
606
  logHidden, orgWidth if logHidden and logWidth == 0 else logWidth
603
607
  ]
604
608
 
609
+ logger.debug("Saving State: GuiOutline")
605
610
  pOptions = SHARED.project.options
606
611
  pOptions.setValue("GuiOutline", "columnState", colState)
607
612
  pOptions.saveSettings()