novelWriter 2.6rc1__py3-none-any.whl → 2.6.2__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 (62) hide show
  1. {novelWriter-2.6rc1.dist-info → novelWriter-2.6.2.dist-info}/METADATA +1 -1
  2. {novelWriter-2.6rc1.dist-info → novelWriter-2.6.2.dist-info}/RECORD +62 -59
  3. novelwriter/__init__.py +3 -3
  4. novelwriter/assets/i18n/nw_cs_CZ.qm +0 -0
  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_cs_CZ.json +118 -0
  18. novelwriter/assets/i18n/project_de_DE.json +2 -0
  19. novelwriter/assets/i18n/project_en_US.json +2 -0
  20. novelwriter/assets/i18n/project_es_419.json +2 -0
  21. novelwriter/assets/i18n/project_fr_FR.json +3 -1
  22. novelwriter/assets/i18n/project_it_IT.json +2 -0
  23. novelwriter/assets/i18n/project_ja_JP.json +2 -0
  24. novelwriter/assets/i18n/project_nb_NO.json +2 -0
  25. novelwriter/assets/i18n/project_nl_NL.json +2 -0
  26. novelwriter/assets/i18n/project_pl_PL.json +2 -0
  27. novelwriter/assets/i18n/project_pt_BR.json +2 -0
  28. novelwriter/assets/i18n/project_zh_CN.json +2 -0
  29. novelwriter/assets/manual.pdf +0 -0
  30. novelwriter/assets/manual_fr_FR.pdf +0 -0
  31. novelwriter/assets/sample.zip +0 -0
  32. novelwriter/assets/text/credits_en.htm +1 -0
  33. novelwriter/config.py +41 -19
  34. novelwriter/constants.py +4 -0
  35. novelwriter/core/buildsettings.py +7 -0
  36. novelwriter/core/itemmodel.py +4 -2
  37. novelwriter/core/project.py +2 -6
  38. novelwriter/dialogs/docsplit.py +49 -45
  39. novelwriter/dialogs/preferences.py +14 -5
  40. novelwriter/enum.py +0 -7
  41. novelwriter/extensions/novelselector.py +3 -2
  42. novelwriter/extensions/statusled.py +5 -6
  43. novelwriter/formats/shared.py +12 -11
  44. novelwriter/formats/todocx.py +1 -1
  45. novelwriter/formats/tohtml.py +30 -27
  46. novelwriter/formats/tokenizer.py +14 -8
  47. novelwriter/formats/tomarkdown.py +3 -2
  48. novelwriter/formats/toodt.py +1 -1
  49. novelwriter/formats/toqdoc.py +2 -0
  50. novelwriter/gui/doceditor.py +35 -19
  51. novelwriter/gui/docviewer.py +1 -1
  52. novelwriter/gui/itemdetails.py +1 -0
  53. novelwriter/gui/projtree.py +16 -18
  54. novelwriter/gui/statusbar.py +6 -7
  55. novelwriter/guimain.py +1 -1
  56. novelwriter/tools/dictionaries.py +2 -2
  57. novelwriter/tools/manussettings.py +8 -8
  58. novelwriter/tools/welcome.py +1 -1
  59. {novelWriter-2.6rc1.dist-info → novelWriter-2.6.2.dist-info}/LICENSE.md +0 -0
  60. {novelWriter-2.6rc1.dist-info → novelWriter-2.6.2.dist-info}/WHEEL +0 -0
  61. {novelWriter-2.6rc1.dist-info → novelWriter-2.6.2.dist-info}/entry_points.txt +0 -0
  62. {novelWriter-2.6rc1.dist-info → novelWriter-2.6.2.dist-info}/top_level.txt +0 -0
@@ -68,11 +68,11 @@ COMMENT_STYLE = {
68
68
  nwComment.COMMENT: ComStyle(),
69
69
  nwComment.STORY: ComStyle("", "modifier", "note"),
70
70
  }
71
- HEADINGS = [BlockTyp.TITLE, BlockTyp.HEAD1, BlockTyp.HEAD2, BlockTyp.HEAD3, BlockTyp.HEAD4]
72
- SKIP_INDENT = [
73
- BlockTyp.TITLE, BlockTyp.HEAD1, BlockTyp.HEAD2, BlockTyp.HEAD2, BlockTyp.HEAD3,
74
- BlockTyp.HEAD4, BlockTyp.SEP, BlockTyp.SKIP,
71
+ HEADINGS = [
72
+ BlockTyp.TITLE, BlockTyp.PART, BlockTyp.HEAD1,
73
+ BlockTyp.HEAD2, BlockTyp.HEAD3, BlockTyp.HEAD4,
75
74
  ]
75
+ SKIP_INDENT = HEADINGS + [BlockTyp.SEP, BlockTyp.SKIP]
76
76
  B_EMPTY: T_Block = (BlockTyp.EMPTY, "", "", [], BlockFmt.NONE)
77
77
 
78
78
 
@@ -654,6 +654,7 @@ class Tokenizer(ABC):
654
654
  if not (isPlain or isNovel and sHide):
655
655
  tStyle |= self._titleStyle
656
656
  if isNovel:
657
+ tType = BlockTyp.PART if isPlain else BlockTyp.TITLE
657
658
  if sHide:
658
659
  tText = ""
659
660
  tType = BlockTyp.EMPTY
@@ -687,6 +688,7 @@ class Tokenizer(ABC):
687
688
  sHide = self._hideChapter if isPlain else self._hideUnNum
688
689
  tFormat = self._fmtChapter if isPlain else self._fmtUnNum
689
690
  if isNovel:
691
+ tType = BlockTyp.HEAD1 # Promote
690
692
  if isPlain:
691
693
  self._hFormatter.incChapter()
692
694
  if sHide:
@@ -721,6 +723,7 @@ class Tokenizer(ABC):
721
723
  sHide = self._hideScene if isPlain else self._hideHScene
722
724
  tFormat = self._fmtScene if isPlain else self._fmtHScene
723
725
  if isNovel:
726
+ tType = BlockTyp.HEAD2 # Promote
724
727
  self._hFormatter.incScene()
725
728
  if sHide:
726
729
  tText = ""
@@ -752,6 +755,7 @@ class Tokenizer(ABC):
752
755
  tText = aLine[5:].strip()
753
756
  tType = BlockTyp.HEAD4
754
757
  if isNovel:
758
+ tType = BlockTyp.HEAD3 # Promote
755
759
  if self._hideSection:
756
760
  tText = ""
757
761
  tType = BlockTyp.EMPTY
@@ -927,12 +931,14 @@ class Tokenizer(ABC):
927
931
  for tType, tKey, tText, _, _ in self._blocks:
928
932
  if tType == BlockTyp.TITLE:
929
933
  prefix = "TT"
934
+ elif tType == BlockTyp.PART:
935
+ prefix = "PT"
930
936
  elif tType == BlockTyp.HEAD1:
931
- prefix = "PT" if isNovel else "H1"
937
+ prefix = "CH" if isNovel else "H1"
932
938
  elif tType == BlockTyp.HEAD2:
933
- prefix = "CH" if isNovel else "H2"
934
- elif tType == BlockTyp.HEAD3:
935
- prefix = "SC" if isNovel else "H3"
939
+ prefix = "SC" if isNovel else "H2"
940
+ elif tType == BlockTyp.HEAD3 and not isNovel:
941
+ prefix = "H3"
936
942
  else:
937
943
  continue
938
944
 
@@ -113,9 +113,10 @@ class ToMarkdown(Tokenizer):
113
113
  tTemp = self._formatText(tText, tFormat, mTags).replace("\n", " \n")
114
114
  lines.append(f"{tTemp}\n\n")
115
115
 
116
- elif tType == BlockTyp.TITLE:
116
+ elif tType in (BlockTyp.TITLE, BlockTyp.PART):
117
117
  tHead = tText.replace("\n", " - ")
118
- lines.append(f"# {tHead}\n\n")
118
+ lines.append(f"{tHead}\n")
119
+ lines.append("="*len(tHead) + "\n\n")
119
120
 
120
121
  elif tType == BlockTyp.HEAD1:
121
122
  tHead = tText.replace("\n", " - ")
@@ -363,7 +363,7 @@ class ToOdt(Tokenizer):
363
363
  else:
364
364
  self._addTextPar(xText, S_TEXT, oStyle, tText, tFmt=tFormat)
365
365
 
366
- elif tType == BlockTyp.TITLE:
366
+ elif tType in (BlockTyp.TITLE, BlockTyp.PART):
367
367
  # Title must be text:p
368
368
  self._addTextPar(xText, S_TITLE, oStyle, tText, isHead=False)
369
369
 
@@ -157,6 +157,7 @@ class ToQTextDocument(Tokenizer):
157
157
 
158
158
  self._mHead = {
159
159
  BlockTyp.TITLE: (fPx * self._marginTitle[0], fPx * self._marginTitle[1]),
160
+ BlockTyp.PART: (fPx * self._marginTitle[0], fPx * self._marginTitle[1]),
160
161
  BlockTyp.HEAD1: (fPx * self._marginHead1[0], fPx * self._marginHead1[1]),
161
162
  BlockTyp.HEAD2: (fPx * self._marginHead2[0], fPx * self._marginHead2[1]),
162
163
  BlockTyp.HEAD3: (fPx * self._marginHead3[0], fPx * self._marginHead3[1]),
@@ -166,6 +167,7 @@ class ToQTextDocument(Tokenizer):
166
167
  hScale = self._scaleHeads
167
168
  self._sHead = {
168
169
  BlockTyp.TITLE: (nwStyles.H_SIZES.get(0, 1.0) * fPt) if hScale else fPt,
170
+ BlockTyp.PART: (nwStyles.H_SIZES.get(0, 1.0) * fPt) if hScale else fPt,
169
171
  BlockTyp.HEAD1: (nwStyles.H_SIZES.get(1, 1.0) * fPt) if hScale else fPt,
170
172
  BlockTyp.HEAD2: (nwStyles.H_SIZES.get(2, 1.0) * fPt) if hScale else fPt,
171
173
  BlockTyp.HEAD3: (nwStyles.H_SIZES.get(3, 1.0) * fPt) if hScale else fPt,
@@ -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
 
@@ -1925,8 +1932,9 @@ class GuiDocEditor(QPlainTextEdit):
1925
1932
  self._qDocument.syntaxHighlighter.rehighlightBlock(block)
1926
1933
  return
1927
1934
 
1928
- def _processTag(self, cursor: QTextCursor | None = None,
1929
- follow: bool = True, create: bool = False) -> nwTrinary:
1935
+ def _processTag(
1936
+ self, cursor: QTextCursor | None = None, follow: bool = True, create: bool = False
1937
+ ) -> _TagAction:
1930
1938
  """Activated by Ctrl+Enter. Checks that we're in a block
1931
1939
  starting with '@'. We then find the tag under the cursor and
1932
1940
  check that it is not the tag itself. If all this is fine, we
@@ -1936,19 +1944,22 @@ class GuiDocEditor(QPlainTextEdit):
1936
1944
  if cursor is None:
1937
1945
  cursor = self.textCursor()
1938
1946
 
1947
+ status = _TagAction.NONE
1939
1948
  block = cursor.block()
1940
1949
  text = block.text()
1941
1950
  if len(text) == 0:
1942
- return nwTrinary.NEUTRAL
1951
+ return status
1943
1952
 
1944
1953
  if text.startswith("@") and self._docHandle:
1945
1954
 
1946
1955
  isGood, tBits, tPos = SHARED.project.index.scanThis(text)
1947
1956
  if (
1948
- not isGood or not tBits or tBits[0] == nwKeyWords.TAG_KEY
1949
- 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
1950
1961
  ):
1951
- return nwTrinary.NEUTRAL
1962
+ return status
1952
1963
 
1953
1964
  tag = ""
1954
1965
  exist = False
@@ -1965,7 +1976,14 @@ class GuiDocEditor(QPlainTextEdit):
1965
1976
 
1966
1977
  if not tag or tag.startswith("@"):
1967
1978
  # The keyword cannot be looked up, so we ignore that
1968
- 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
1969
1987
 
1970
1988
  if follow and exist:
1971
1989
  logger.debug("Attempting to follow tag '%s'", tag)
@@ -1977,9 +1995,7 @@ class GuiDocEditor(QPlainTextEdit):
1977
1995
  itemClass = nwKeyWords.KEY_CLASS.get(tBits[0], nwItemClass.NO_CLASS)
1978
1996
  self.requestNewNoteCreation.emit(tag, itemClass)
1979
1997
 
1980
- return nwTrinary.POSITIVE if exist else nwTrinary.NEGATIVE
1981
-
1982
- return nwTrinary.NEUTRAL
1998
+ return status
1983
1999
 
1984
2000
  def _emitRenameItem(self, block: QTextBlock) -> None:
1985
2001
  """Emit a signal to request an item be renamed."""
@@ -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
 
@@ -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)
@@ -177,6 +177,7 @@ class GuiProjectView(QWidget):
177
177
  self.projTree.addAction(trash)
178
178
  rename.triggered.connect(self.renameTreeItem)
179
179
  delete.triggered.connect(self.projTree.processDeleteRequest)
180
+ trash.triggered.connect(self.projTree.emptyTrash)
180
181
  return
181
182
 
182
183
  ##
@@ -955,23 +956,18 @@ class GuiProjectTree(QTreeView):
955
956
  if model := self._getModel():
956
957
  if point is None:
957
958
  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
-
959
+ if point is not None:
960
+ index = self.indexAt(point)
961
+ if (node := self._getNode(index)) and (indices := self._selectedRows()):
962
+ ctxMenu = _TreeContextMenu(self, model, node, indices)
963
+ if node is SHARED.project.tree.trash:
964
+ ctxMenu.buildTrashMenu()
965
+ elif len(indices) > 1:
966
+ ctxMenu.buildMultiSelectMenu()
967
+ else:
968
+ ctxMenu.buildSingleSelectMenu()
969
+ ctxMenu.exec(self.viewport().mapToGlobal(point))
970
+ ctxMenu.setParent(None)
975
971
  return
976
972
 
977
973
  ##
@@ -1020,7 +1016,9 @@ class GuiProjectTree(QTreeView):
1020
1016
  def _clearSelection(self) -> None:
1021
1017
  """Clear the currently selected items."""
1022
1018
  self.clearSelection()
1023
- self.selectionModel().clearCurrentIndex()
1019
+ if model := self.selectionModel():
1020
+ # Selection model can be None (#2173)
1021
+ model.clearCurrentIndex()
1024
1022
  return
1025
1023
 
1026
1024
  def _selectedRows(self) -> list[QModelIndex]:
@@ -34,7 +34,6 @@ 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
38
37
  from novelwriter.extensions.modified import NClickableLabel
39
38
  from novelwriter.extensions.statusled import StatusLED
40
39
 
@@ -121,8 +120,8 @@ class GuiMainStatus(QStatusBar):
121
120
  self.setRefTime(-1.0)
122
121
  self.setLanguage(*SHARED.spelling.describeDict())
123
122
  self.setProjectStats(0, 0)
124
- self.setProjectStatus(nwTrinary.NEUTRAL)
125
- self.setDocumentStatus(nwTrinary.NEUTRAL)
123
+ self.setProjectStatus(None)
124
+ self.setDocumentStatus(None)
126
125
  self.updateTime()
127
126
  return
128
127
 
@@ -152,12 +151,12 @@ class GuiMainStatus(QStatusBar):
152
151
  self._refTime = refTime
153
152
  return
154
153
 
155
- def setProjectStatus(self, state: nwTrinary) -> None:
154
+ def setProjectStatus(self, state: bool | None) -> None:
156
155
  """Set the project status colour icon."""
157
156
  self.projIcon.setState(state)
158
157
  return
159
158
 
160
- def setDocumentStatus(self, state: nwTrinary) -> None:
159
+ def setDocumentStatus(self, state: bool | None) -> None:
161
160
  """Set the document status colour icon."""
162
161
  self.docIcon.setState(state)
163
162
  return
@@ -220,13 +219,13 @@ class GuiMainStatus(QStatusBar):
220
219
  @pyqtSlot(bool)
221
220
  def updateProjectStatus(self, status: bool) -> None:
222
221
  """Update the project status."""
223
- self.setProjectStatus(nwTrinary.NEGATIVE if status else nwTrinary.POSITIVE)
222
+ self.setProjectStatus(not status)
224
223
  return
225
224
 
226
225
  @pyqtSlot(bool)
227
226
  def updateDocumentStatus(self, status: bool) -> None:
228
227
  """Update the document status."""
229
- self.setDocumentStatus(nwTrinary.NEGATIVE if status else nwTrinary.POSITIVE)
228
+ self.setDocumentStatus(not status)
230
229
  return
231
230
 
232
231
  ##
novelwriter/guimain.py CHANGED
@@ -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
  )):
@@ -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)
@@ -38,7 +38,7 @@ from PyQt5.QtWidgets import (
38
38
 
39
39
  from novelwriter import CONFIG, SHARED
40
40
  from novelwriter.common import describeFont, fontMatcher, qtLambda
41
- from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwStyles, trConst
41
+ from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, trConst
42
42
  from novelwriter.core.buildsettings import BuildSettings, FilterMode
43
43
  from novelwriter.extensions.configlayout import (
44
44
  NColourLabel, NFixedPage, NScrollableForm, NScrollablePage
@@ -1074,7 +1074,7 @@ class _FormattingTab(NScrollableForm):
1074
1074
  self.titleMarginB.setFixedWidth(dbW)
1075
1075
 
1076
1076
  self.addRow(
1077
- trConst(nwStyles.T_LABEL["H0"]),
1077
+ self._build.getLabel("format.titleMargin"),
1078
1078
  [pixT, self.titleMarginT, 6, pixB, self.titleMarginB],
1079
1079
  unit="em",
1080
1080
  )
@@ -1087,7 +1087,7 @@ class _FormattingTab(NScrollableForm):
1087
1087
  self.h1MarginB.setFixedWidth(dbW)
1088
1088
 
1089
1089
  self.addRow(
1090
- trConst(nwStyles.T_LABEL["H1"]),
1090
+ self._build.getLabel("format.h1Margin"),
1091
1091
  [pixT, self.h1MarginT, 6, pixB, self.h1MarginB],
1092
1092
  unit="em",
1093
1093
  )
@@ -1100,7 +1100,7 @@ class _FormattingTab(NScrollableForm):
1100
1100
  self.h2MarginB.setFixedWidth(dbW)
1101
1101
 
1102
1102
  self.addRow(
1103
- trConst(nwStyles.T_LABEL["H2"]),
1103
+ self._build.getLabel("format.h2Margin"),
1104
1104
  [pixT, self.h2MarginT, 6, pixB, self.h2MarginB],
1105
1105
  unit="em",
1106
1106
  )
@@ -1113,7 +1113,7 @@ class _FormattingTab(NScrollableForm):
1113
1113
  self.h3MarginB.setFixedWidth(dbW)
1114
1114
 
1115
1115
  self.addRow(
1116
- trConst(nwStyles.T_LABEL["H3"]),
1116
+ self._build.getLabel("format.h3Margin"),
1117
1117
  [pixT, self.h3MarginT, 6, pixB, self.h3MarginB],
1118
1118
  unit="em",
1119
1119
  )
@@ -1126,7 +1126,7 @@ class _FormattingTab(NScrollableForm):
1126
1126
  self.h4MarginB.setFixedWidth(dbW)
1127
1127
 
1128
1128
  self.addRow(
1129
- trConst(nwStyles.T_LABEL["H4"]),
1129
+ self._build.getLabel("format.h4Margin"),
1130
1130
  [pixT, self.h4MarginT, 6, pixB, self.h4MarginB],
1131
1131
  unit="em",
1132
1132
  )
@@ -1139,7 +1139,7 @@ class _FormattingTab(NScrollableForm):
1139
1139
  self.textMarginB.setFixedWidth(dbW)
1140
1140
 
1141
1141
  self.addRow(
1142
- trConst(nwStyles.T_LABEL["TT"]),
1142
+ self._build.getLabel("format.textMargin"),
1143
1143
  [pixT, self.textMarginT, 6, pixB, self.textMarginB],
1144
1144
  unit="em",
1145
1145
  )
@@ -1152,7 +1152,7 @@ class _FormattingTab(NScrollableForm):
1152
1152
  self.sepMarginB.setFixedWidth(dbW)
1153
1153
 
1154
1154
  self.addRow(
1155
- trConst(nwStyles.T_LABEL["SP"]),
1155
+ self._build.getLabel("format.sepMargin"),
1156
1156
  [pixT, self.sepMarginT, 6, pixB, self.sepMarginB],
1157
1157
  unit="em",
1158
1158
  )
@@ -376,7 +376,7 @@ class _OpenProjectPage(QWidget):
376
376
  action = ctxMenu.addAction(self.tr("Remove Project"))
377
377
  action.triggered.connect(self._deleteSelectedItem)
378
378
  ctxMenu.exec(self.mapToGlobal(pos))
379
- ctxMenu.deleteLater()
379
+ ctxMenu.setParent(None)
380
380
  return
381
381
 
382
382
  ##