novelWriter 2.6b2__py3-none-any.whl → 2.6.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 (107) hide show
  1. {novelWriter-2.6b2.dist-info → novelWriter-2.6.1.dist-info}/METADATA +2 -2
  2. {novelWriter-2.6b2.dist-info → novelWriter-2.6.1.dist-info}/RECORD +107 -106
  3. {novelWriter-2.6b2.dist-info → novelWriter-2.6.1.dist-info}/WHEEL +1 -1
  4. novelwriter/__init__.py +4 -4
  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_nl_NL.qm +0 -0
  13. novelwriter/assets/i18n/nw_pl_PL.qm +0 -0
  14. novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
  15. novelwriter/assets/i18n/nw_ru_RU.qm +0 -0
  16. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  17. novelwriter/assets/i18n/project_de_DE.json +2 -0
  18. novelwriter/assets/i18n/project_en_US.json +2 -0
  19. novelwriter/assets/i18n/project_es_419.json +2 -0
  20. novelwriter/assets/i18n/project_fr_FR.json +3 -1
  21. novelwriter/assets/i18n/project_it_IT.json +2 -0
  22. novelwriter/assets/i18n/project_ja_JP.json +2 -0
  23. novelwriter/assets/i18n/project_nb_NO.json +2 -0
  24. novelwriter/assets/i18n/project_nl_NL.json +2 -0
  25. novelwriter/assets/i18n/project_pl_PL.json +2 -0
  26. novelwriter/assets/i18n/project_pt_BR.json +2 -0
  27. novelwriter/assets/i18n/project_zh_CN.json +2 -0
  28. novelwriter/assets/manual.pdf +0 -0
  29. novelwriter/assets/manual_fr_FR.pdf +0 -0
  30. novelwriter/assets/sample.zip +0 -0
  31. novelwriter/common.py +1 -1
  32. novelwriter/config.py +45 -20
  33. novelwriter/constants.py +40 -36
  34. novelwriter/core/buildsettings.py +8 -1
  35. novelwriter/core/coretools.py +1 -1
  36. novelwriter/core/docbuild.py +1 -1
  37. novelwriter/core/document.py +1 -1
  38. novelwriter/core/index.py +1 -1
  39. novelwriter/core/item.py +1 -1
  40. novelwriter/core/itemmodel.py +1 -1
  41. novelwriter/core/options.py +1 -1
  42. novelwriter/core/project.py +3 -7
  43. novelwriter/core/projectdata.py +8 -2
  44. novelwriter/core/projectxml.py +1 -1
  45. novelwriter/core/sessions.py +1 -1
  46. novelwriter/core/spellcheck.py +1 -1
  47. novelwriter/core/status.py +17 -3
  48. novelwriter/core/storage.py +1 -1
  49. novelwriter/core/tree.py +1 -1
  50. novelwriter/dialogs/about.py +1 -1
  51. novelwriter/dialogs/docmerge.py +1 -1
  52. novelwriter/dialogs/docsplit.py +1 -1
  53. novelwriter/dialogs/editlabel.py +1 -1
  54. novelwriter/dialogs/preferences.py +16 -7
  55. novelwriter/dialogs/projectsettings.py +146 -96
  56. novelwriter/dialogs/quotes.py +1 -1
  57. novelwriter/dialogs/wordlist.py +11 -10
  58. novelwriter/enum.py +1 -8
  59. novelwriter/error.py +2 -2
  60. novelwriter/extensions/configlayout.py +1 -1
  61. novelwriter/extensions/eventfilters.py +1 -1
  62. novelwriter/extensions/modified.py +17 -5
  63. novelwriter/extensions/novelselector.py +4 -3
  64. novelwriter/extensions/pagedsidebar.py +4 -4
  65. novelwriter/extensions/progressbars.py +4 -4
  66. novelwriter/extensions/statusled.py +8 -9
  67. novelwriter/extensions/switch.py +3 -3
  68. novelwriter/extensions/switchbox.py +1 -1
  69. novelwriter/extensions/versioninfo.py +1 -1
  70. novelwriter/formats/shared.py +13 -12
  71. novelwriter/formats/todocx.py +2 -2
  72. novelwriter/formats/tohtml.py +31 -28
  73. novelwriter/formats/tokenizer.py +19 -13
  74. novelwriter/formats/tomarkdown.py +4 -3
  75. novelwriter/formats/toodt.py +2 -2
  76. novelwriter/formats/toqdoc.py +3 -1
  77. novelwriter/formats/toraw.py +1 -1
  78. novelwriter/gui/doceditor.py +39 -21
  79. novelwriter/gui/dochighlight.py +1 -1
  80. novelwriter/gui/docviewer.py +2 -2
  81. novelwriter/gui/docviewerpanel.py +1 -1
  82. novelwriter/gui/editordocument.py +1 -1
  83. novelwriter/gui/itemdetails.py +4 -3
  84. novelwriter/gui/mainmenu.py +1 -1
  85. novelwriter/gui/noveltree.py +1 -1
  86. novelwriter/gui/outline.py +8 -9
  87. novelwriter/gui/projtree.py +20 -25
  88. novelwriter/gui/search.py +2 -9
  89. novelwriter/gui/sidebar.py +1 -1
  90. novelwriter/gui/statusbar.py +26 -10
  91. novelwriter/gui/theme.py +1 -1
  92. novelwriter/guimain.py +2 -6
  93. novelwriter/shared.py +1 -1
  94. novelwriter/text/counting.py +1 -1
  95. novelwriter/text/patterns.py +1 -1
  96. novelwriter/tools/dictionaries.py +3 -3
  97. novelwriter/tools/lipsum.py +1 -1
  98. novelwriter/tools/manusbuild.py +1 -1
  99. novelwriter/tools/manuscript.py +7 -7
  100. novelwriter/tools/manussettings.py +9 -9
  101. novelwriter/tools/noveldetails.py +1 -1
  102. novelwriter/tools/welcome.py +2 -2
  103. novelwriter/tools/writingstats.py +1 -1
  104. novelwriter/types.py +2 -2
  105. {novelWriter-2.6b2.dist-info → novelWriter-2.6.1.dist-info}/LICENSE.md +0 -0
  106. {novelWriter-2.6b2.dist-info → novelWriter-2.6.1.dist-info}/entry_points.txt +0 -0
  107. {novelWriter-2.6b2.dist-info → novelWriter-2.6.1.dist-info}/top_level.txt +0 -0
@@ -14,7 +14,7 @@ Created: 2023-11-06 [2.2b1] MetaCompleter
14
14
  Created: 2023-11-07 [2.2b1] GuiDocToolBar
15
15
 
16
16
  This file is a part of novelWriter
17
- Copyright 2018–2024, Veronica Berglyd Olsen
17
+ Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
18
18
 
19
19
  This program is free software: you can redistribute it and/or modify
20
20
  it under the terms of the GNU General Public License as published by
@@ -34,7 +34,7 @@ from __future__ import annotations
34
34
  import bisect
35
35
  import logging
36
36
 
37
- from enum import Enum
37
+ from enum import Enum, IntFlag
38
38
  from time import time
39
39
 
40
40
  from PyQt5.QtCore import (
@@ -57,7 +57,7 @@ from novelwriter.constants import nwConst, nwKeyWords, nwShortcode, nwUnicode
57
57
  from novelwriter.core.document import NWDocument
58
58
  from novelwriter.enum import (
59
59
  nwChange, nwComment, nwDocAction, nwDocInsert, nwDocMode, nwItemClass,
60
- nwItemType, nwTrinary
60
+ nwItemType
61
61
  )
62
62
  from novelwriter.extensions.configlayout import NColourLabel
63
63
  from novelwriter.extensions.eventfilters import WheelEventFilter
@@ -84,6 +84,13 @@ class _SelectAction(Enum):
84
84
  MOVE_AFTER = 3
85
85
 
86
86
 
87
+ class _TagAction(IntFlag):
88
+
89
+ NONE = 0b00
90
+ FOLLOW = 0b01
91
+ CREATE = 0b10
92
+
93
+
87
94
  class GuiDocEditor(QPlainTextEdit):
88
95
  """Gui Widget: Main Document Editor"""
89
96
 
@@ -1104,10 +1111,10 @@ class GuiDocEditor(QPlainTextEdit):
1104
1111
  else:
1105
1112
  self._completer.setVisible(False)
1106
1113
 
1107
- if self._doReplace and added == 1:
1108
- cursor = self.textCursor()
1109
- if self._autoReplace.process(text, cursor):
1110
- self._qDocument.syntaxHighlighter.rehighlightBlock(cursor.block())
1114
+ if self._doReplace and added == 1:
1115
+ cursor = self.textCursor()
1116
+ if self._autoReplace.process(text, cursor):
1117
+ self._qDocument.syntaxHighlighter.rehighlightBlock(cursor.block())
1111
1118
 
1112
1119
  return
1113
1120
 
@@ -1158,11 +1165,11 @@ class GuiDocEditor(QPlainTextEdit):
1158
1165
 
1159
1166
  # Follow
1160
1167
  status = self._processTag(cursor=pCursor, follow=False)
1161
- if status == nwTrinary.POSITIVE:
1168
+ if status & _TagAction.FOLLOW:
1162
1169
  action = ctxMenu.addAction(self.tr("Follow Tag"))
1163
1170
  action.triggered.connect(qtLambda(self._processTag, cursor=pCursor, follow=True))
1164
1171
  ctxMenu.addSeparator()
1165
- elif status == nwTrinary.NEGATIVE:
1172
+ elif status & _TagAction.CREATE:
1166
1173
  action = ctxMenu.addAction(self.tr("Create Note for Tag"))
1167
1174
  action.triggered.connect(qtLambda(self._processTag, cursor=pCursor, create=True))
1168
1175
  ctxMenu.addSeparator()
@@ -1217,7 +1224,7 @@ class GuiDocEditor(QPlainTextEdit):
1217
1224
 
1218
1225
  # Execute the context menu
1219
1226
  ctxMenu.exec(self.viewport().mapToGlobal(pos))
1220
- ctxMenu.deleteLater()
1227
+ ctxMenu.setParent(None)
1221
1228
 
1222
1229
  return
1223
1230
 
@@ -1253,7 +1260,9 @@ class GuiDocEditor(QPlainTextEdit):
1253
1260
  self._nwItem.setParaCount(pCount)
1254
1261
  if needsRefresh:
1255
1262
  self._nwItem.notifyToRefresh()
1256
- self.docFooter.updateWordCount(wCount, False)
1263
+ if not self.textCursor().hasSelection():
1264
+ # Selection counter should take precedence (#2155)
1265
+ self.docFooter.updateWordCount(wCount, False)
1257
1266
  return
1258
1267
 
1259
1268
  @pyqtSlot()
@@ -1923,8 +1932,9 @@ class GuiDocEditor(QPlainTextEdit):
1923
1932
  self._qDocument.syntaxHighlighter.rehighlightBlock(block)
1924
1933
  return
1925
1934
 
1926
- def _processTag(self, cursor: QTextCursor | None = None,
1927
- follow: bool = True, create: bool = False) -> nwTrinary:
1935
+ def _processTag(
1936
+ self, cursor: QTextCursor | None = None, follow: bool = True, create: bool = False
1937
+ ) -> _TagAction:
1928
1938
  """Activated by Ctrl+Enter. Checks that we're in a block
1929
1939
  starting with '@'. We then find the tag under the cursor and
1930
1940
  check that it is not the tag itself. If all this is fine, we
@@ -1934,19 +1944,22 @@ class GuiDocEditor(QPlainTextEdit):
1934
1944
  if cursor is None:
1935
1945
  cursor = self.textCursor()
1936
1946
 
1947
+ status = _TagAction.NONE
1937
1948
  block = cursor.block()
1938
1949
  text = block.text()
1939
1950
  if len(text) == 0:
1940
- return nwTrinary.NEUTRAL
1951
+ return status
1941
1952
 
1942
1953
  if text.startswith("@") and self._docHandle:
1943
1954
 
1944
1955
  isGood, tBits, tPos = SHARED.project.index.scanThis(text)
1945
1956
  if (
1946
- not isGood or not tBits or tBits[0] == nwKeyWords.TAG_KEY
1947
- or tBits[0] not in nwKeyWords.VALID_KEYS
1957
+ not isGood
1958
+ or not tBits
1959
+ or (key := tBits[0]) == nwKeyWords.TAG_KEY
1960
+ or key not in nwKeyWords.VALID_KEYS
1948
1961
  ):
1949
- return nwTrinary.NEUTRAL
1962
+ return status
1950
1963
 
1951
1964
  tag = ""
1952
1965
  exist = False
@@ -1963,7 +1976,14 @@ class GuiDocEditor(QPlainTextEdit):
1963
1976
 
1964
1977
  if not tag or tag.startswith("@"):
1965
1978
  # The keyword cannot be looked up, so we ignore that
1966
- return nwTrinary.NEUTRAL
1979
+ return status
1980
+
1981
+ if not exist and key in nwKeyWords.CAN_CREATE:
1982
+ # Must only be set if we have a tag selected
1983
+ status |= _TagAction.CREATE
1984
+
1985
+ if exist:
1986
+ status |= _TagAction.FOLLOW
1967
1987
 
1968
1988
  if follow and exist:
1969
1989
  logger.debug("Attempting to follow tag '%s'", tag)
@@ -1975,9 +1995,7 @@ class GuiDocEditor(QPlainTextEdit):
1975
1995
  itemClass = nwKeyWords.KEY_CLASS.get(tBits[0], nwItemClass.NO_CLASS)
1976
1996
  self.requestNewNoteCreation.emit(tag, itemClass)
1977
1997
 
1978
- return nwTrinary.POSITIVE if exist else nwTrinary.NEGATIVE
1979
-
1980
- return nwTrinary.NEUTRAL
1998
+ return status
1981
1999
 
1982
2000
  def _emitRenameItem(self, block: QTextBlock) -> None:
1983
2001
  """Emit a signal to request an item be renamed."""
@@ -7,7 +7,7 @@ Created: 2019-04-06 [0.0.1] GuiDocHighlighter
7
7
  Created: 2023-09-10 [2.2b1] TextBlockData
8
8
 
9
9
  This file is a part of novelWriter
10
- Copyright 2018–2024, Veronica Berglyd Olsen
10
+ Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
11
11
 
12
12
  This program is free software: you can redistribute it and/or modify
13
13
  it under the terms of the GNU General Public License as published by
@@ -9,7 +9,7 @@ Created: 2020-06-09 [0.8] GuiDocViewFooter
9
9
  Created: 2020-09-08 [1.0b1] GuiDocViewHistory
10
10
 
11
11
  This file is a part of novelWriter
12
- Copyright 2018–2024, Veronica Berglyd Olsen
12
+ Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
13
13
 
14
14
  This program is free software: you can redistribute it and/or modify
15
15
  it under the terms of the GNU General Public License as published by
@@ -424,7 +424,7 @@ class GuiDocViewer(QTextBrowser):
424
424
 
425
425
  # Open the context menu
426
426
  ctxMenu.exec(self.viewport().mapToGlobal(point))
427
- ctxMenu.deleteLater()
427
+ ctxMenu.setParent(None)
428
428
 
429
429
  return
430
430
 
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2023-11-14 [2.2rc1] GuiDocViewerPanel
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
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
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2023-09-07 [2.2b1] GuiTextDocument
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
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
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2019-04-24 [0.0.1] GuiItemDetails
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
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
@@ -65,8 +65,8 @@ class GuiItemDetails(QWidget):
65
65
  fntValue = self.font()
66
66
  fntValue.setPointSizeF(0.9*fPt)
67
67
 
68
- trStats1 = trConst(nwLabels.STATS_NAME[nwStats.CHARS_ALL])
69
- trStats2 = trConst(nwLabels.STATS_NAME[nwStats.WORDS_ALL])
68
+ trStats1 = trConst(nwLabels.STATS_NAME[nwStats.CHARS])
69
+ trStats2 = trConst(nwLabels.STATS_NAME[nwStats.WORDS])
70
70
  trStats3 = trConst(nwLabels.STATS_NAME[nwStats.PARAGRAPHS])
71
71
 
72
72
  # Label
@@ -93,6 +93,7 @@ class GuiItemDetails(QWidget):
93
93
  self.statusData = QLabel("", self)
94
94
  self.statusData.setFont(fntValue)
95
95
  self.statusData.setAlignment(QtAlignLeft)
96
+ self.statusData.setWordWrap(True)
96
97
 
97
98
  # Class
98
99
  self.className = QLabel(self.tr("Class"), self)
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2019-04-27 [0.0.1] GuiMainMenu
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
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
@@ -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–2024, Veronica Berglyd Olsen
11
+ Copyright (C) 2020 Veronica Berglyd Olsen and novelWriter contributors
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
@@ -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–2024, Veronica Berglyd Olsen
13
+ Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
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
@@ -41,7 +41,7 @@ from PyQt5.QtWidgets import (
41
41
  )
42
42
 
43
43
  from novelwriter import CONFIG, SHARED
44
- from novelwriter.common import checkInt, formatFileFilter, makeFileNameSafe
44
+ from novelwriter.common import checkInt, formatFileFilter
45
45
  from novelwriter.constants import nwKeyWords, nwLabels, nwStats, nwStyles, trConst
46
46
  from novelwriter.enum import nwChange, nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline
47
47
  from novelwriter.error import logException
@@ -541,11 +541,10 @@ class GuiOutlineTree(QTreeWidget):
541
541
  @pyqtSlot()
542
542
  def exportOutline(self) -> None:
543
543
  """Export the outline as a CSV file."""
544
- path = CONFIG.lastPath("outline") / f"{makeFileNameSafe(SHARED.project.data.name)}.csv"
545
- path, _ = QFileDialog.getSaveFileName(
546
- self, self.tr("Save Outline As"), str(path), formatFileFilter(["*.csv", "*"])
547
- )
548
- if path:
544
+ name = CONFIG.lastPath("outline") / f"{SHARED.project.data.fileSafeName}.csv"
545
+ if path := QFileDialog.getSaveFileName(
546
+ self, self.tr("Save Outline As"), str(name), formatFileFilter(["*.csv", "*"])
547
+ )[0]:
549
548
  CONFIG.setLastPath("outline", path)
550
549
  logger.info("Writing CSV file: %s", path)
551
550
  cols = [col for col in self._treeOrder if not self._colHidden[col]]
@@ -816,8 +815,8 @@ class GuiOutlineDetails(QScrollArea):
816
815
 
817
816
  bFont = SHARED.theme.guiFontB
818
817
 
819
- trStats1 = trConst(nwLabels.STATS_NAME[nwStats.CHARS_ALL])
820
- trStats2 = trConst(nwLabels.STATS_NAME[nwStats.WORDS_ALL])
818
+ trStats1 = trConst(nwLabels.STATS_NAME[nwStats.CHARS])
819
+ trStats2 = trConst(nwLabels.STATS_NAME[nwStats.WORDS])
821
820
  trStats3 = trConst(nwLabels.STATS_NAME[nwStats.PARAGRAPHS])
822
821
 
823
822
  # Details Area
@@ -11,7 +11,7 @@ Rewritten: 2024-11-17 [2.6b2] GuiProjectTree
11
11
  Rewritten: 2024-11-20 [2.6b2] _TreeContextMenu
12
12
 
13
13
  This file is a part of novelWriter
14
- Copyright 2018–2024, Veronica Berglyd Olsen
14
+ Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
15
15
 
16
16
  This program is free software: you can redistribute it and/or modify
17
17
  it under the terms of the GNU General Public License as published by
@@ -955,23 +955,18 @@ class GuiProjectTree(QTreeView):
955
955
  if model := self._getModel():
956
956
  if point is None:
957
957
  point = self.visualRect(self.currentIndex()).center()
958
-
959
- if (
960
- point is not None
961
- and (node := self._getNode(self.currentIndex()))
962
- and (indices := self._selectedRows())
963
- ):
964
- ctxMenu = _TreeContextMenu(self, model, node, indices)
965
- if node is SHARED.project.tree.trash:
966
- ctxMenu.buildTrashMenu()
967
- elif len(indices) > 1:
968
- ctxMenu.buildMultiSelectMenu()
969
- else:
970
- ctxMenu.buildSingleSelectMenu()
971
-
972
- ctxMenu.exec(self.viewport().mapToGlobal(point))
973
- ctxMenu.deleteLater()
974
-
958
+ if point is not None:
959
+ index = self.indexAt(point)
960
+ if (node := self._getNode(index)) and (indices := self._selectedRows()):
961
+ ctxMenu = _TreeContextMenu(self, model, node, indices)
962
+ if node is SHARED.project.tree.trash:
963
+ ctxMenu.buildTrashMenu()
964
+ elif len(indices) > 1:
965
+ ctxMenu.buildMultiSelectMenu()
966
+ else:
967
+ ctxMenu.buildSingleSelectMenu()
968
+ ctxMenu.exec(self.viewport().mapToGlobal(point))
969
+ ctxMenu.setParent(None)
975
970
  return
976
971
 
977
972
  ##
@@ -1020,7 +1015,9 @@ class GuiProjectTree(QTreeView):
1020
1015
  def _clearSelection(self) -> None:
1021
1016
  """Clear the currently selected items."""
1022
1017
  self.clearSelection()
1023
- self.selectionModel().clearCurrentIndex()
1018
+ if model := self.selectionModel():
1019
+ # Selection model can be None (#2173)
1020
+ model.clearCurrentIndex()
1024
1021
  return
1025
1022
 
1026
1023
  def _selectedRows(self) -> list[QModelIndex]:
@@ -1366,9 +1363,8 @@ class _TreeContextMenu(QMenu):
1366
1363
 
1367
1364
  def _changeItemStatus(self, key: str) -> None:
1368
1365
  """Set a new status value of an item."""
1369
- if self._item.isFileType():
1370
- self._item.setStatus(key)
1371
- self._item.notifyToRefresh()
1366
+ self._item.setStatus(key)
1367
+ self._item.notifyToRefresh()
1372
1368
  return
1373
1369
 
1374
1370
  def _iterSetItemStatus(self, key: str) -> None:
@@ -1383,9 +1379,8 @@ class _TreeContextMenu(QMenu):
1383
1379
 
1384
1380
  def _changeItemImport(self, key: str) -> None:
1385
1381
  """Set a new importance value of an item."""
1386
- if self._item.isFileType():
1387
- self._item.setImport(key)
1388
- self._item.notifyToRefresh()
1382
+ self._item.setImport(key)
1383
+ self._item.notifyToRefresh()
1389
1384
  return
1390
1385
 
1391
1386
  def _iterSetItemImport(self, key: str) -> None:
novelwriter/gui/search.py CHANGED
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2024-03-21 [2.4b1] GuiProjectSearch
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
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
@@ -133,12 +133,8 @@ class GuiProjectSearch(QWidget):
133
133
  self.headerBox.setContentsMargins(0, 0, 0, 0)
134
134
  self.headerBox.setSpacing(0)
135
135
 
136
- self.headerWidget = QWidget(self)
137
- self.headerWidget.setLayout(self.headerBox)
138
- self.headerWidget.setContentsMargins(0, 0, 0, 0)
139
-
140
136
  self.outerBox = QVBoxLayout()
141
- self.outerBox.addWidget(self.headerWidget, 0)
137
+ self.outerBox.addLayout(self.headerBox, 0)
142
138
  self.outerBox.addWidget(self.searchText, 0)
143
139
  self.outerBox.addWidget(self.searchResult, 1)
144
140
  self.outerBox.setContentsMargins(0, 0, 0, 0)
@@ -164,9 +160,6 @@ class GuiProjectSearch(QWidget):
164
160
  colBase = cssCol(qPalette.base().color())
165
161
  colFocus = cssCol(qPalette.highlight().color())
166
162
 
167
- self.headerWidget.setStyleSheet(f"QWidget {{background: {colBase};}}")
168
- self.headerWidget.setAutoFillBackground(True)
169
-
170
163
  self.setStyleSheet(
171
164
  "QToolBar {padding: 0; background: none;} "
172
165
  f"QLineEdit {{border: {bPx}px solid {colBase}; padding: {mPx}px;}} "
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2022-05-10 [2.0rc1] GuiSideBar
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
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
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2019-04-20 [0.0.1] GuiMainStatus
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
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
@@ -34,7 +34,7 @@ from PyQt5.QtWidgets import QApplication, QLabel, QStatusBar, QWidget
34
34
  from novelwriter import CONFIG, SHARED
35
35
  from novelwriter.common import formatTime
36
36
  from novelwriter.constants import nwConst
37
- from novelwriter.enum import nwTrinary
37
+ from novelwriter.extensions.modified import NClickableLabel
38
38
  from novelwriter.extensions.statusled import StatusLED
39
39
 
40
40
  logger = logging.getLogger(__name__)
@@ -92,12 +92,16 @@ class GuiMainStatus(QStatusBar):
92
92
 
93
93
  # The Session Clock
94
94
  # Set the minimum width so the label doesn't rescale every second
95
- self.timeIcon = QLabel(self)
96
- self.timeText = QLabel("", self)
95
+ self.timeIcon = NClickableLabel(self)
96
+ self.timeIcon.mouseClicked.connect(self._onClickTimerLabel)
97
+
98
+ self.timeText = NClickableLabel("", self)
97
99
  self.timeText.setToolTip(self.tr("Session Time"))
98
100
  self.timeText.setMinimumWidth(SHARED.theme.getTextWidth("00:00:00:"))
99
101
  self.timeIcon.setContentsMargins(0, 0, 0, 0)
100
102
  self.timeText.setContentsMargins(0, 0, 0, 0)
103
+ self.timeText.setVisible(CONFIG.showSessionTime)
104
+ self.timeText.mouseClicked.connect(self._onClickTimerLabel)
101
105
  self.addPermanentWidget(self.timeIcon)
102
106
  self.addPermanentWidget(self.timeText)
103
107
 
@@ -116,8 +120,8 @@ class GuiMainStatus(QStatusBar):
116
120
  self.setRefTime(-1.0)
117
121
  self.setLanguage(*SHARED.spelling.describeDict())
118
122
  self.setProjectStats(0, 0)
119
- self.setProjectStatus(nwTrinary.NEUTRAL)
120
- self.setDocumentStatus(nwTrinary.NEUTRAL)
123
+ self.setProjectStatus(None)
124
+ self.setDocumentStatus(None)
121
125
  self.updateTime()
122
126
  return
123
127
 
@@ -147,12 +151,12 @@ class GuiMainStatus(QStatusBar):
147
151
  self._refTime = refTime
148
152
  return
149
153
 
150
- def setProjectStatus(self, state: nwTrinary) -> None:
154
+ def setProjectStatus(self, state: bool | None) -> None:
151
155
  """Set the project status colour icon."""
152
156
  self.projIcon.setState(state)
153
157
  return
154
158
 
155
- def setDocumentStatus(self, state: nwTrinary) -> None:
159
+ def setDocumentStatus(self, state: bool | None) -> None:
156
160
  """Set the document status colour icon."""
157
161
  self.docIcon.setState(state)
158
162
  return
@@ -215,13 +219,25 @@ class GuiMainStatus(QStatusBar):
215
219
  @pyqtSlot(bool)
216
220
  def updateProjectStatus(self, status: bool) -> None:
217
221
  """Update the project status."""
218
- self.setProjectStatus(nwTrinary.NEGATIVE if status else nwTrinary.POSITIVE)
222
+ self.setProjectStatus(not status)
219
223
  return
220
224
 
221
225
  @pyqtSlot(bool)
222
226
  def updateDocumentStatus(self, status: bool) -> None:
223
227
  """Update the document status."""
224
- self.setDocumentStatus(nwTrinary.NEGATIVE if status else nwTrinary.POSITIVE)
228
+ self.setDocumentStatus(not status)
229
+ return
230
+
231
+ ##
232
+ # Private Slots
233
+ ##
234
+
235
+ @pyqtSlot()
236
+ def _onClickTimerLabel(self) -> None:
237
+ """Process mouse click on timer label."""
238
+ state = not CONFIG.showSessionTime
239
+ self.timeText.setVisible(state)
240
+ CONFIG.showSessionTime = state
225
241
  return
226
242
 
227
243
  ##
novelwriter/gui/theme.py CHANGED
@@ -7,7 +7,7 @@ Created: 2019-05-18 [0.1.3] GuiTheme
7
7
  Created: 2019-11-08 [0.4] GuiIcons
8
8
 
9
9
  This file is a part of novelWriter
10
- Copyright 2018–2024, Veronica Berglyd Olsen
10
+ Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
11
11
 
12
12
  This program is free software: you can redistribute it and/or modify
13
13
  it under the terms of the GNU General Public License as published by
novelwriter/guimain.py CHANGED
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2018-09-22 [0.0.1] GuiMain
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2018 Veronica Berglyd Olsen and novelWriter contributors
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
@@ -852,7 +852,7 @@ class GuiMain(QMainWindow):
852
852
 
853
853
  def closeMain(self) -> bool:
854
854
  """Save everything, and close novelWriter."""
855
- if SHARED.hasProject and not SHARED.question("%s<br>%s" % (
855
+ if SHARED.hasProject and CONFIG.askBeforeExit and not SHARED.question("%s<br>%s" % (
856
856
  self.tr("Do you want to exit novelWriter?"),
857
857
  self.tr("Changes are saved automatically.")
858
858
  )):
@@ -957,12 +957,8 @@ class GuiMain(QMainWindow):
957
957
  docEditor = True
958
958
  elif self.docViewer.isAncestorOf(new):
959
959
  docViewer = True
960
-
961
960
  self.docEditor.changeFocusState(docEditor)
962
961
  self.docViewer.changeFocusState(docViewer)
963
-
964
- logger.debug("Main focus switched to: %s", type(new).__name__)
965
-
966
962
  return
967
963
 
968
964
  @pyqtSlot(bool)
novelwriter/shared.py CHANGED
@@ -7,7 +7,7 @@ Created: 2023-08-10 [2.1rc1] SharedData
7
7
  Created: 2023-08-14 [2.1rc1] _GuiAlert
8
8
 
9
9
  This file is a part of novelWriter
10
- Copyright 2018–2024, Veronica Berglyd Olsen
10
+ Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
11
11
 
12
12
  This program is free software: you can redistribute it and/or modify
13
13
  it under the terms of the GNU General Public License as published by
@@ -8,7 +8,7 @@ Rewritten: 2024-02-27 [2.4b1] preProcessText, standardCounter
8
8
  Created: 2024-02-27 [2.4b1] bodyTextCounter
9
9
 
10
10
  This file is a part of novelWriter
11
- Copyright 2018–2024, Veronica Berglyd Olsen
11
+ Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
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
@@ -7,7 +7,7 @@ Created: 2024-06-01 [2.5rc1] RegExPatterns
7
7
  Created: 2024-11-04 [2.6b1] DialogParser
8
8
 
9
9
  This file is a part of novelWriter
10
- Copyright 2018–2024, Veronica Berglyd Olsen
10
+ Copyright (C) 2024 Veronica Berglyd Olsen and novelWriter contributors
11
11
 
12
12
  This program is free software: you can redistribute it and/or modify
13
13
  it under the terms of the GNU General Public License as published by
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2023-11-19 [2.2rc1] GuiDictionaries
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
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
@@ -65,12 +65,12 @@ class GuiDictionaries(NNonBlockingDialog):
65
65
  self.setMinimumHeight(CONFIG.pxInt(300))
66
66
 
67
67
  # Hunspell Dictionaries
68
- foUrl = "https://www.freeoffice.com/en/download/dictionaries"
69
68
  loUrl = "https://extensions.libreoffice.org"
69
+ ooUrl = "https://extensions.openoffice.org"
70
70
  self.huInfo = QLabel("<br>".join([
71
71
  self.tr("Download a dictionary from one of the links, and add it below."),
72
- f"&nbsp;\u203a <a href='{foUrl}'>{foUrl}</a>",
73
72
  f"&nbsp;\u203a <a href='{loUrl}'>{loUrl}</a>",
73
+ f"&nbsp;\u203a <a href='{ooUrl}'>{ooUrl}</a>",
74
74
  ]), self)
75
75
  self.huInfo.setOpenExternalLinks(True)
76
76
  self.huInfo.setWordWrap(True)
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2022-04-02 [2.0rc1] GuiLipsum
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2022 Veronica Berglyd Olsen and novelWriter contributors
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
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2023-05-24 [2.1b1] GuiManuscriptBuild
7
7
 
8
8
  This file is a part of novelWriter
9
- Copyright 2018–2024, Veronica Berglyd Olsen
9
+ Copyright (C) 2023 Veronica Berglyd Olsen and novelWriter contributors
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