novelWriter 2.2rc1__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 (117) hide show
  1. {novelWriter-2.2rc1.dist-info → novelWriter-2.2.1.dist-info}/METADATA +1 -1
  2. {novelWriter-2.2rc1.dist-info → novelWriter-2.2.1.dist-info}/RECORD +113 -111
  3. {novelWriter-2.2rc1.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_US.json +1 -0
  15. novelwriter/assets/i18n/project_es_419.json +11 -0
  16. novelwriter/assets/i18n/project_fr_FR.json +11 -0
  17. novelwriter/assets/i18n/project_it_IT.json +11 -0
  18. novelwriter/assets/i18n/project_ja_JP.json +2 -1
  19. novelwriter/assets/i18n/project_nb_NO.json +1 -0
  20. novelwriter/assets/i18n/project_zh_CN.json +11 -0
  21. novelwriter/assets/icons/typicons_dark/icons.conf +3 -2
  22. novelwriter/assets/icons/typicons_dark/nw_tb-bold-md.svg +4 -0
  23. novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +3 -1
  24. novelwriter/assets/icons/typicons_dark/nw_tb-italic-md.svg +4 -0
  25. novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +3 -1
  26. novelwriter/assets/icons/typicons_dark/nw_tb-strike-md.svg +4 -0
  27. novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +3 -1
  28. novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +4 -2
  29. novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +4 -2
  30. novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +4 -2
  31. novelwriter/assets/icons/typicons_light/icons.conf +3 -2
  32. novelwriter/assets/icons/typicons_light/nw_tb-bold-md.svg +4 -0
  33. novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +3 -1
  34. novelwriter/assets/icons/typicons_light/nw_tb-italic-md.svg +4 -0
  35. novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +3 -1
  36. novelwriter/assets/icons/typicons_light/nw_tb-strike-md.svg +4 -0
  37. novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +3 -1
  38. novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +4 -2
  39. novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +4 -2
  40. novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +4 -2
  41. novelwriter/assets/manual.pdf +0 -0
  42. novelwriter/assets/sample.zip +0 -0
  43. novelwriter/assets/text/release_notes.htm +50 -7
  44. novelwriter/common.py +16 -29
  45. novelwriter/config.py +3 -3
  46. novelwriter/constants.py +1 -1
  47. novelwriter/core/buildsettings.py +1 -1
  48. novelwriter/core/coretools.py +2 -1
  49. novelwriter/core/docbuild.py +1 -1
  50. novelwriter/core/document.py +1 -1
  51. novelwriter/core/index.py +2 -2
  52. novelwriter/core/item.py +2 -2
  53. novelwriter/core/options.py +3 -3
  54. novelwriter/core/project.py +3 -3
  55. novelwriter/core/projectdata.py +2 -2
  56. novelwriter/core/projectxml.py +1 -1
  57. novelwriter/core/sessions.py +2 -2
  58. novelwriter/core/spellcheck.py +4 -3
  59. novelwriter/core/status.py +3 -3
  60. novelwriter/core/storage.py +1 -1
  61. novelwriter/core/tohtml.py +2 -2
  62. novelwriter/core/tokenizer.py +1 -1
  63. novelwriter/core/tomd.py +2 -2
  64. novelwriter/core/toodt.py +1 -1
  65. novelwriter/core/tree.py +2 -2
  66. novelwriter/dialogs/about.py +30 -31
  67. novelwriter/dialogs/docmerge.py +24 -15
  68. novelwriter/dialogs/docsplit.py +27 -16
  69. novelwriter/dialogs/editlabel.py +19 -7
  70. novelwriter/dialogs/preferences.py +44 -57
  71. novelwriter/dialogs/projdetails.py +29 -36
  72. novelwriter/dialogs/projload.py +32 -36
  73. novelwriter/dialogs/projsettings.py +20 -15
  74. novelwriter/dialogs/quotes.py +32 -25
  75. novelwriter/dialogs/updates.py +4 -14
  76. novelwriter/dialogs/wordlist.py +34 -21
  77. novelwriter/enum.py +5 -4
  78. novelwriter/error.py +1 -1
  79. novelwriter/extensions/circularprogress.py +1 -1
  80. novelwriter/extensions/configlayout.py +3 -15
  81. novelwriter/extensions/{wheeleventfilter.py → eventfilters.py} +15 -5
  82. novelwriter/extensions/novelselector.py +1 -1
  83. novelwriter/extensions/pageddialog.py +1 -1
  84. novelwriter/extensions/pagedsidebar.py +2 -5
  85. novelwriter/extensions/simpleprogress.py +8 -9
  86. novelwriter/extensions/statusled.py +1 -1
  87. novelwriter/extensions/switch.py +4 -4
  88. novelwriter/extensions/switchbox.py +1 -6
  89. novelwriter/gui/doceditor.py +72 -64
  90. novelwriter/gui/dochighlight.py +3 -2
  91. novelwriter/gui/docviewer.py +22 -47
  92. novelwriter/gui/docviewerpanel.py +68 -23
  93. novelwriter/gui/editordocument.py +3 -3
  94. novelwriter/gui/itemdetails.py +2 -2
  95. novelwriter/gui/mainmenu.py +35 -30
  96. novelwriter/gui/noveltree.py +44 -53
  97. novelwriter/gui/outline.py +2 -1
  98. novelwriter/gui/projtree.py +5 -6
  99. novelwriter/gui/sidebar.py +6 -4
  100. novelwriter/gui/statusbar.py +47 -4
  101. novelwriter/gui/theme.py +5 -6
  102. novelwriter/guimain.py +139 -189
  103. novelwriter/shared.py +53 -29
  104. novelwriter/tools/dictionaries.py +2 -2
  105. novelwriter/tools/lipsum.py +34 -28
  106. novelwriter/tools/manusbuild.py +3 -4
  107. novelwriter/tools/manuscript.py +19 -26
  108. novelwriter/tools/manussettings.py +2 -4
  109. novelwriter/tools/projwizard.py +3 -3
  110. novelwriter/tools/writingstats.py +17 -4
  111. novelwriter/assets/icons/typicons_dark/nw_tb-markdown.svg +0 -8
  112. novelwriter/assets/icons/typicons_dark/nw_tb-shortcode.svg +0 -8
  113. novelwriter/assets/icons/typicons_light/nw_tb-markdown.svg +0 -8
  114. novelwriter/assets/icons/typicons_light/nw_tb-shortcode.svg +0 -8
  115. {novelWriter-2.2rc1.dist-info → novelWriter-2.2.1.dist-info}/LICENSE.md +0 -0
  116. {novelWriter-2.2rc1.dist-info → novelWriter-2.2.1.dist-info}/entry_points.txt +0 -0
  117. {novelWriter-2.2rc1.dist-info → novelWriter-2.2.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–2023, Veronica Berglyd Olsen
17
+ Copyright 2018–2024, Veronica Berglyd Olsen
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
@@ -58,10 +58,11 @@ from novelwriter.common import minmax, transferCase
58
58
  from novelwriter.constants import nwKeyWords, nwLabels, nwShortcode, nwUnicode, trConst
59
59
  from novelwriter.core.item import NWItem
60
60
  from novelwriter.core.index import countWords
61
+ from novelwriter.tools.lipsum import GuiLipsum
61
62
  from novelwriter.core.document import NWDocument
62
63
  from novelwriter.gui.dochighlight import GuiDocHighlighter
63
64
  from novelwriter.gui.editordocument import GuiTextDocument
64
- from novelwriter.extensions.wheeleventfilter import WheelEventFilter
65
+ from novelwriter.extensions.eventfilters import WheelEventFilter
65
66
 
66
67
  if TYPE_CHECKING: # pragma: no cover
67
68
  from novelwriter.guimain import GuiMain
@@ -717,11 +718,11 @@ class GuiDocEditor(QPlainTextEdit):
717
718
  self.copy()
718
719
  elif action == nwDocAction.PASTE:
719
720
  self.paste()
720
- elif action == nwDocAction.EMPH:
721
+ elif action == nwDocAction.MD_ITALIC:
721
722
  self._toggleFormat(1, "_")
722
- elif action == nwDocAction.STRONG:
723
+ elif action == nwDocAction.MD_BOLD:
723
724
  self._toggleFormat(2, "*")
724
- elif action == nwDocAction.STRIKE:
725
+ elif action == nwDocAction.MD_STRIKE:
725
726
  self._toggleFormat(2, "~")
726
727
  elif action == nwDocAction.S_QUOTE:
727
728
  self._wrapSelection(self._typSQuoteO, self._typSQuoteC)
@@ -831,11 +832,11 @@ class GuiDocEditor(QPlainTextEdit):
831
832
  elif insert == nwDocInsert.QUOTE_RD:
832
833
  text = self._typDQuoteC
833
834
  elif insert == nwDocInsert.SYNOPSIS:
834
- text = "% Synopsis: "
835
+ text = "%Synopsis: "
835
836
  newBlock = True
836
837
  goAfter = True
837
838
  elif insert == nwDocInsert.SHORT:
838
- text = "% Short: "
839
+ text = "%Short: "
839
840
  newBlock = True
840
841
  goAfter = True
841
842
  elif insert == nwDocInsert.NEW_PAGE:
@@ -850,18 +851,23 @@ class GuiDocEditor(QPlainTextEdit):
850
851
  text = "[vspace:2]"
851
852
  newBlock = True
852
853
  goAfter = False
854
+ elif insert == nwDocInsert.LIPSUM:
855
+ text = GuiLipsum.getLipsum(self)
856
+ newBlock = True
857
+ goAfter = False
853
858
  else:
854
859
  return False
855
860
  else:
856
861
  return False
857
862
 
858
- if newBlock:
859
- self.insertNewBlock(text, defaultAfter=goAfter)
860
- else:
861
- cursor = self.textCursor()
862
- cursor.beginEditBlock()
863
- cursor.insertText(text)
864
- cursor.endEditBlock()
863
+ if text:
864
+ if newBlock:
865
+ self.insertNewBlock(text, defaultAfter=goAfter)
866
+ else:
867
+ cursor = self.textCursor()
868
+ cursor.beginEditBlock()
869
+ cursor.insertText(text)
870
+ cursor.endEditBlock()
865
871
 
866
872
  return True
867
873
 
@@ -1144,6 +1150,7 @@ class GuiDocEditor(QPlainTextEdit):
1144
1150
 
1145
1151
  # Execute the context menu
1146
1152
  ctxMenu.exec_(self.viewport().mapToGlobal(pos))
1153
+ ctxMenu.deleteLater()
1147
1154
 
1148
1155
  return
1149
1156
 
@@ -2005,20 +2012,25 @@ class GuiDocEditor(QPlainTextEdit):
2005
2012
  cPos = cursor.position()
2006
2013
  bPos = cursor.block().position()
2007
2014
  bLen = cursor.block().length()
2015
+ apos = nwUnicode.U_APOS + nwUnicode.U_RSQUO
2008
2016
 
2009
- # Scan backwards
2017
+ # Scan backward
2010
2018
  sPos = cPos
2011
2019
  for i in range(cPos - bPos):
2012
2020
  sPos = cPos - i - 1
2013
- if not self._qDocument.characterAt(sPos).isalnum():
2021
+ cOne = self._qDocument.characterAt(sPos)
2022
+ cTwo = self._qDocument.characterAt(sPos - 1)
2023
+ if not (cOne.isalnum() or cOne in apos and cTwo.isalnum()):
2014
2024
  sPos += 1
2015
2025
  break
2016
2026
 
2017
- # Scan forwards
2027
+ # Scan forward
2018
2028
  ePos = cPos
2019
2029
  for i in range(bPos + bLen - cPos):
2020
2030
  ePos = cPos + i
2021
- if not self._qDocument.characterAt(ePos).isalnum():
2031
+ cOne = self._qDocument.characterAt(ePos)
2032
+ cTwo = self._qDocument.characterAt(ePos + 1)
2033
+ if not (cOne.isalnum() or cOne in apos and cTwo.isalnum()):
2022
2034
  break
2023
2035
 
2024
2036
  if ePos - sPos <= 0:
@@ -2225,39 +2237,65 @@ class GuiDocToolBar(QWidget):
2225
2237
  # General Buttons
2226
2238
  # ===============
2227
2239
 
2228
- self.tbMode = QToolButton(self)
2229
- self.tbMode.setToolTip(self.tr("Toggle Markdown or Shortcodes Mode"))
2230
- self.tbMode.setIconSize(iconSize)
2231
- self.tbMode.setCheckable(True)
2232
- self.tbMode.setChecked(CONFIG.useShortcodes)
2233
- self.tbMode.toggled.connect(self._toggleFormatMode)
2240
+ self.tbBoldMD = QToolButton(self)
2241
+ self.tbBoldMD.setIconSize(iconSize)
2242
+ self.tbBoldMD.setToolTip(self.tr("Markdown Bold"))
2243
+ self.tbBoldMD.clicked.connect(
2244
+ lambda: self.requestDocAction.emit(nwDocAction.MD_BOLD)
2245
+ )
2246
+
2247
+ self.tbItalicMD = QToolButton(self)
2248
+ self.tbItalicMD.setIconSize(iconSize)
2249
+ self.tbItalicMD.setToolTip(self.tr("Markdown Italic"))
2250
+ self.tbItalicMD.clicked.connect(
2251
+ lambda: self.requestDocAction.emit(nwDocAction.MD_ITALIC)
2252
+ )
2253
+
2254
+ self.tbStrikeMD = QToolButton(self)
2255
+ self.tbStrikeMD.setIconSize(iconSize)
2256
+ self.tbStrikeMD.setToolTip(self.tr("Markdown Strikethrough"))
2257
+ self.tbStrikeMD.clicked.connect(
2258
+ lambda: self.requestDocAction.emit(nwDocAction.MD_STRIKE)
2259
+ )
2234
2260
 
2235
2261
  self.tbBold = QToolButton(self)
2236
2262
  self.tbBold.setIconSize(iconSize)
2237
- self.tbBold.clicked.connect(self._formatBold)
2263
+ self.tbBold.setToolTip(self.tr("Shortcode Bold"))
2264
+ self.tbBold.clicked.connect(
2265
+ lambda: self.requestDocAction.emit(nwDocAction.SC_BOLD)
2266
+ )
2238
2267
 
2239
2268
  self.tbItalic = QToolButton(self)
2240
2269
  self.tbItalic.setIconSize(iconSize)
2241
- self.tbItalic.clicked.connect(self._formatItalic)
2270
+ self.tbItalic.setToolTip(self.tr("Shortcode Italic"))
2271
+ self.tbItalic.clicked.connect(
2272
+ lambda: self.requestDocAction.emit(nwDocAction.SC_ITALIC)
2273
+ )
2242
2274
 
2243
2275
  self.tbStrike = QToolButton(self)
2244
2276
  self.tbStrike.setIconSize(iconSize)
2245
- self.tbStrike.clicked.connect(self._formatStrike)
2277
+ self.tbStrike.setToolTip(self.tr("Shortcode Strikethrough"))
2278
+ self.tbStrike.clicked.connect(
2279
+ lambda: self.requestDocAction.emit(nwDocAction.SC_STRIKE)
2280
+ )
2246
2281
 
2247
2282
  self.tbUnderline = QToolButton(self)
2248
2283
  self.tbUnderline.setIconSize(iconSize)
2284
+ self.tbUnderline.setToolTip(self.tr("Shortcode Underline"))
2249
2285
  self.tbUnderline.clicked.connect(
2250
2286
  lambda: self.requestDocAction.emit(nwDocAction.SC_ULINE)
2251
2287
  )
2252
2288
 
2253
2289
  self.tbSuperscript = QToolButton(self)
2254
2290
  self.tbSuperscript.setIconSize(iconSize)
2291
+ self.tbSuperscript.setToolTip(self.tr("Shortcode Superscript"))
2255
2292
  self.tbSuperscript.clicked.connect(
2256
2293
  lambda: self.requestDocAction.emit(nwDocAction.SC_SUP)
2257
2294
  )
2258
2295
 
2259
2296
  self.tbSubscript = QToolButton(self)
2260
2297
  self.tbSubscript.setIconSize(iconSize)
2298
+ self.tbSubscript.setToolTip(self.tr("Shortcode Subscript"))
2261
2299
  self.tbSubscript.clicked.connect(
2262
2300
  lambda: self.requestDocAction.emit(nwDocAction.SC_SUB)
2263
2301
  )
@@ -2266,7 +2304,10 @@ class GuiDocToolBar(QWidget):
2266
2304
  # ========
2267
2305
 
2268
2306
  self.outerBox = QVBoxLayout()
2269
- self.outerBox.addWidget(self.tbMode)
2307
+ self.outerBox.addWidget(self.tbBoldMD)
2308
+ self.outerBox.addWidget(self.tbItalicMD)
2309
+ self.outerBox.addWidget(self.tbStrikeMD)
2310
+ self.outerBox.addSpacing(cM)
2270
2311
  self.outerBox.addWidget(self.tbBold)
2271
2312
  self.outerBox.addWidget(self.tbItalic)
2272
2313
  self.outerBox.addWidget(self.tbStrike)
@@ -2294,8 +2335,9 @@ class GuiDocToolBar(QWidget):
2294
2335
  palette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
2295
2336
  self.setPalette(palette)
2296
2337
 
2297
- tPx = int(0.8*SHARED.theme.fontPixelSize)
2298
- self.tbMode.setIcon(SHARED.theme.getToggleIcon("fmt_mode", (tPx, tPx)))
2338
+ self.tbBoldMD.setIcon(SHARED.theme.getIcon("fmt_bold-md"))
2339
+ self.tbItalicMD.setIcon(SHARED.theme.getIcon("fmt_italic-md"))
2340
+ self.tbStrikeMD.setIcon(SHARED.theme.getIcon("fmt_strike-md"))
2299
2341
  self.tbBold.setIcon(SHARED.theme.getIcon("fmt_bold"))
2300
2342
  self.tbItalic.setIcon(SHARED.theme.getIcon("fmt_italic"))
2301
2343
  self.tbStrike.setIcon(SHARED.theme.getIcon("fmt_strike"))
@@ -2305,40 +2347,6 @@ class GuiDocToolBar(QWidget):
2305
2347
 
2306
2348
  return
2307
2349
 
2308
- ##
2309
- # Private Slots
2310
- ##
2311
-
2312
- @pyqtSlot(bool)
2313
- def _toggleFormatMode(self, checked: bool) -> None:
2314
- """Toggle the formatting mode."""
2315
- CONFIG.useShortcodes = checked
2316
- return
2317
-
2318
- @pyqtSlot()
2319
- def _formatBold(self):
2320
- """Call the bold format action."""
2321
- self.requestDocAction.emit(
2322
- nwDocAction.SC_BOLD if self.tbMode.isChecked() else nwDocAction.STRONG
2323
- )
2324
- return
2325
-
2326
- @pyqtSlot()
2327
- def _formatItalic(self):
2328
- """Call the italic format action."""
2329
- self.requestDocAction.emit(
2330
- nwDocAction.SC_ITALIC if self.tbMode.isChecked() else nwDocAction.EMPH
2331
- )
2332
- return
2333
-
2334
- @pyqtSlot()
2335
- def _formatStrike(self):
2336
- """Call the strikethrough format action."""
2337
- self.requestDocAction.emit(
2338
- nwDocAction.SC_STRIKE if self.tbMode.isChecked() else nwDocAction.STRIKE
2339
- )
2340
- return
2341
-
2342
2350
  # END Class GuiDocToolBar
2343
2351
 
2344
2352
 
@@ -3,10 +3,11 @@ novelWriter – GUI Syntax Highlighter
3
3
  ====================================
4
4
 
5
5
  File History:
6
- Created: 2019-04-06 [0.0.1]
6
+ Created: 2019-04-06 [0.0.1] GuiDocHighlighter
7
+ Created: 2023-09-10 [2.2b1] TextBlockData
7
8
 
8
9
  This file is a part of novelWriter
9
- Copyright 2018–2023, Veronica Berglyd Olsen
10
+ Copyright 2018–2024, Veronica Berglyd Olsen
10
11
 
11
12
  This program is free software: you can redistribute it and/or modify
12
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–2023, Veronica Berglyd Olsen
12
+ Copyright 2018–2024, Veronica Berglyd Olsen
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
@@ -46,7 +46,7 @@ from novelwriter.enum import nwItemType, nwDocAction, nwDocMode
46
46
  from novelwriter.error import logException
47
47
  from novelwriter.constants import nwUnicode
48
48
  from novelwriter.core.tohtml import ToHtml
49
- from novelwriter.extensions.wheeleventfilter import WheelEventFilter
49
+ from novelwriter.extensions.eventfilters import WheelEventFilter
50
50
 
51
51
  if TYPE_CHECKING: # pragma: no cover
52
52
  from novelwriter.guimain import GuiMain
@@ -378,33 +378,34 @@ class GuiDocViewer(QTextBrowser):
378
378
  userCursor = self.textCursor()
379
379
  userSelection = userCursor.hasSelection()
380
380
 
381
- mnuContext = QMenu(self)
381
+ ctxMenu = QMenu(self)
382
382
 
383
383
  if userSelection:
384
- mnuCopy = QAction(self.tr("Copy"), mnuContext)
384
+ mnuCopy = QAction(self.tr("Copy"), ctxMenu)
385
385
  mnuCopy.triggered.connect(lambda: self.docAction(nwDocAction.COPY))
386
- mnuContext.addAction(mnuCopy)
386
+ ctxMenu.addAction(mnuCopy)
387
387
 
388
- mnuContext.addSeparator()
388
+ ctxMenu.addSeparator()
389
389
 
390
- mnuSelAll = QAction(self.tr("Select All"), mnuContext)
390
+ mnuSelAll = QAction(self.tr("Select All"), ctxMenu)
391
391
  mnuSelAll.triggered.connect(lambda: self.docAction(nwDocAction.SEL_ALL))
392
- mnuContext.addAction(mnuSelAll)
392
+ ctxMenu.addAction(mnuSelAll)
393
393
 
394
- mnuSelWord = QAction(self.tr("Select Word"), mnuContext)
394
+ mnuSelWord = QAction(self.tr("Select Word"), ctxMenu)
395
395
  mnuSelWord.triggered.connect(
396
396
  lambda: self._makePosSelection(QTextCursor.SelectionType.WordUnderCursor, point)
397
397
  )
398
- mnuContext.addAction(mnuSelWord)
398
+ ctxMenu.addAction(mnuSelWord)
399
399
 
400
- mnuSelPara = QAction(self.tr("Select Paragraph"), mnuContext)
400
+ mnuSelPara = QAction(self.tr("Select Paragraph"), ctxMenu)
401
401
  mnuSelPara.triggered.connect(
402
402
  lambda: self._makePosSelection(QTextCursor.SelectionType.BlockUnderCursor, point)
403
403
  )
404
- mnuContext.addAction(mnuSelPara)
404
+ ctxMenu.addAction(mnuSelPara)
405
405
 
406
406
  # Open the context menu
407
- mnuContext.exec_(self.viewport().mapToGlobal(point))
407
+ ctxMenu.exec_(self.viewport().mapToGlobal(point))
408
+ ctxMenu.deleteLater()
408
409
 
409
410
  return
410
411
 
@@ -861,8 +862,7 @@ class GuiDocViewFooter(QWidget):
861
862
  self._docHandle = None
862
863
 
863
864
  fPx = int(0.9*SHARED.theme.fontPixelSize)
864
- bSp = CONFIG.pxInt(2)
865
- hSp = CONFIG.pxInt(8)
865
+ hSp = CONFIG.pxInt(4)
866
866
 
867
867
  # Main Widget Settings
868
868
  self.setContentsMargins(0, 0, 0, 0)
@@ -872,64 +872,41 @@ class GuiDocViewFooter(QWidget):
872
872
  self.showHide = QToolButton(self)
873
873
  self.showHide.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
874
874
  self.showHide.setIconSize(QSize(fPx, fPx))
875
- self.showHide.setFixedSize(QSize(fPx, fPx))
876
875
  self.showHide.clicked.connect(lambda: self.docViewer.togglePanelVisibility.emit())
877
876
  self.showHide.setToolTip(self.tr("Show/Hide Viewer Panel"))
878
877
 
879
878
  # Show Comments
880
879
  self.showComments = QToolButton(self)
880
+ self.showComments.setText(self.tr("Comments"))
881
881
  self.showComments.setCheckable(True)
882
882
  self.showComments.setChecked(CONFIG.viewComments)
883
- self.showComments.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
883
+ self.showComments.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
884
884
  self.showComments.setIconSize(QSize(fPx, fPx))
885
- self.showComments.setFixedSize(QSize(fPx, fPx))
886
885
  self.showComments.toggled.connect(self._doToggleComments)
887
886
  self.showComments.setToolTip(self.tr("Show Comments"))
888
887
 
889
888
  # Show Synopsis
890
889
  self.showSynopsis = QToolButton(self)
890
+ self.showSynopsis.setText(self.tr("Synopsis"))
891
891
  self.showSynopsis.setCheckable(True)
892
892
  self.showSynopsis.setChecked(CONFIG.viewSynopsis)
893
- self.showSynopsis.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
893
+ self.showSynopsis.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
894
894
  self.showSynopsis.setIconSize(QSize(fPx, fPx))
895
- self.showSynopsis.setFixedSize(QSize(fPx, fPx))
896
895
  self.showSynopsis.toggled.connect(self._doToggleSynopsis)
897
896
  self.showSynopsis.setToolTip(self.tr("Show Synopsis Comments"))
898
897
 
899
- # Labels
900
- self.lblComments = QLabel(self.tr("Comments"))
901
- self.lblComments.setBuddy(self.showComments)
902
- self.lblComments.setIndent(0)
903
- self.lblComments.setMargin(0)
904
- self.lblComments.setContentsMargins(0, 0, 0, 0)
905
- self.lblComments.setAutoFillBackground(True)
906
- self.lblComments.setFixedHeight(fPx)
907
- self.lblComments.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop)
908
-
909
- self.lblSynopsis = QLabel(self.tr("Synopsis"))
910
- self.lblSynopsis.setBuddy(self.showSynopsis)
911
- self.lblSynopsis.setIndent(0)
912
- self.lblSynopsis.setMargin(0)
913
- self.lblSynopsis.setContentsMargins(0, 0, 0, 0)
914
- self.lblSynopsis.setAutoFillBackground(True)
915
- self.lblSynopsis.setFixedHeight(fPx)
916
- self.lblSynopsis.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop)
917
-
918
898
  lblFont = self.font()
919
899
  lblFont.setPointSizeF(0.9*SHARED.theme.fontPointSize)
920
- self.lblComments.setFont(lblFont)
921
- self.lblSynopsis.setFont(lblFont)
900
+ self.showComments.setFont(lblFont)
901
+ self.showSynopsis.setFont(lblFont)
922
902
 
923
903
  # Assemble Layout
924
904
  self.outerBox = QHBoxLayout()
925
- self.outerBox.setSpacing(bSp)
926
905
  self.outerBox.addWidget(self.showHide, 0)
927
906
  self.outerBox.addStretch(1)
928
907
  self.outerBox.addWidget(self.showComments, 0)
929
- self.outerBox.addWidget(self.lblComments, 0)
930
- self.outerBox.addSpacing(hSp)
931
908
  self.outerBox.addWidget(self.showSynopsis, 0)
932
- self.outerBox.addWidget(self.lblSynopsis, 0)
909
+ self.outerBox.setSpacing(hSp)
933
910
  self.setLayout(self.outerBox)
934
911
 
935
912
  # Fix Margins and Size
@@ -983,8 +960,6 @@ class GuiDocViewFooter(QWidget):
983
960
  palette.setColor(QPalette.ColorRole.WindowText, QColor(*SHARED.theme.colText))
984
961
  palette.setColor(QPalette.ColorRole.Text, QColor(*SHARED.theme.colText))
985
962
  self.setPalette(palette)
986
- self.lblComments.setPalette(palette)
987
- self.lblSynopsis.setPalette(palette)
988
963
  return
989
964
 
990
965
  ##
@@ -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–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
@@ -57,7 +57,7 @@ class GuiDocViewerPanel(QWidget):
57
57
  self.tabBackRefs = _ViewPanelBackRefs(self)
58
58
 
59
59
  self.mainTabs = QTabWidget(self)
60
- self.mainTabs.addTab(self.tabBackRefs, self.tr("Backreferences"))
60
+ self.mainTabs.addTab(self.tabBackRefs, self.tr("References"))
61
61
 
62
62
  self.kwTabs: dict[str, _ViewPanelKeyWords] = {}
63
63
  self.idTabs: dict[str, int] = {}
@@ -73,7 +73,7 @@ class GuiDocViewerPanel(QWidget):
73
73
  self.outerBox.setContentsMargins(0, 0, 0, 0)
74
74
 
75
75
  self.setLayout(self.outerBox)
76
- self.updateTheme()
76
+ self.updateTheme(updateTabs=False)
77
77
 
78
78
  logger.debug("Ready: GuiDocViewerPanel")
79
79
 
@@ -83,7 +83,7 @@ class GuiDocViewerPanel(QWidget):
83
83
  # Methods
84
84
  ##
85
85
 
86
- def updateTheme(self) -> None:
86
+ def updateTheme(self, updateTabs: bool = True) -> None:
87
87
  """Update theme elements."""
88
88
  vPx = CONFIG.pxInt(4)
89
89
  lPx = CONFIG.pxInt(2)
@@ -102,6 +102,11 @@ class GuiDocViewerPanel(QWidget):
102
102
  self.mainTabs.setStyleSheet(styleSheet)
103
103
  self.updateHandle(self._lastHandle)
104
104
 
105
+ if updateTabs:
106
+ self.tabBackRefs.updateTheme()
107
+ for tab in self.kwTabs.values():
108
+ tab.updateTheme()
109
+
105
110
  return
106
111
 
107
112
  def openProjectTasks(self) -> None:
@@ -118,6 +123,7 @@ class GuiDocViewerPanel(QWidget):
118
123
  widths = {}
119
124
  for key, tab in self.kwTabs.items():
120
125
  widths[key] = tab.getColumnWidths()
126
+ logger.debug("Saving State: GuiDocViewerPanel")
121
127
  SHARED.project.options.setValue("GuiDocViewerPanel", "colWidths", widths)
122
128
  return
123
129
 
@@ -218,12 +224,14 @@ class _ViewPanelBackRefs(QTreeWidget):
218
224
  # Set Header Sizes
219
225
  treeHeader = self.header()
220
226
  treeHeader.setStretchLastSection(True)
227
+ treeHeader.setMinimumSectionSize(iPx + cMg) # See Issue #1627
221
228
  treeHeader.setSectionResizeMode(self.C_DOC, QHeaderView.ResizeMode.ResizeToContents)
222
229
  treeHeader.setSectionResizeMode(self.C_EDIT, QHeaderView.ResizeMode.Fixed)
223
230
  treeHeader.setSectionResizeMode(self.C_VIEW, QHeaderView.ResizeMode.Fixed)
224
231
  treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.ResizeMode.ResizeToContents)
225
232
  treeHeader.resizeSection(self.C_EDIT, iPx + cMg)
226
233
  treeHeader.resizeSection(self.C_VIEW, iPx + cMg)
234
+ treeHeader.setSectionsMovable(False)
227
235
 
228
236
  # Cache Icons Locally
229
237
  self._editIcon = SHARED.theme.getIcon("edit")
@@ -235,6 +243,16 @@ class _ViewPanelBackRefs(QTreeWidget):
235
243
 
236
244
  return
237
245
 
246
+ def updateTheme(self) -> None:
247
+ """Update theme elements."""
248
+ self._editIcon = SHARED.theme.getIcon("edit")
249
+ self._viewIcon = SHARED.theme.getIcon("view")
250
+ for i in range(self.topLevelItemCount()):
251
+ if item := self.topLevelItem(i):
252
+ item.setIcon(self.C_EDIT, self._editIcon)
253
+ item.setIcon(self.C_VIEW, self._viewIcon)
254
+ return
255
+
238
256
  def clearContent(self) -> None:
239
257
  """Clear the widget."""
240
258
  self.clear()
@@ -276,7 +294,7 @@ class _ViewPanelBackRefs(QTreeWidget):
276
294
  def _treeItemDoubleClicked(self, index: QModelIndex) -> None:
277
295
  """Emit follow tag signal on user double click."""
278
296
  tHandle = index.siblingAtColumn(self.C_DATA).data(self.D_HANDLE)
279
- if index.column() == self.C_DOC:
297
+ if index.column() not in (self.C_EDIT, self.C_VIEW):
280
298
  self._parent.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, "", True)
281
299
  return
282
300
 
@@ -299,10 +317,12 @@ class _ViewPanelBackRefs(QTreeWidget):
299
317
 
300
318
  trItem.setIcon(self.C_DOC, docIcon)
301
319
  trItem.setText(self.C_DOC, nwItem.itemName)
320
+ trItem.setToolTip(self.C_DOC, nwItem.itemName)
302
321
  trItem.setIcon(self.C_EDIT, self._editIcon)
303
322
  trItem.setIcon(self.C_VIEW, self._viewIcon)
304
- trItem.setText(self.C_TITLE, hItem.title)
305
323
  trItem.setData(self.C_TITLE, Qt.ItemDataRole.DecorationRole, hDec)
324
+ trItem.setText(self.C_TITLE, hItem.title)
325
+ trItem.setToolTip(self.C_TITLE, hItem.title)
306
326
  trItem.setData(self.C_DATA, self.D_HANDLE, tHandle)
307
327
 
308
328
  if tKey not in self._treeMap:
@@ -316,13 +336,14 @@ class _ViewPanelBackRefs(QTreeWidget):
316
336
 
317
337
  class _ViewPanelKeyWords(QTreeWidget):
318
338
 
319
- C_DATA = 0
320
- C_NAME = 0
321
- C_EDIT = 1
322
- C_VIEW = 2
323
- C_DOC = 3
324
- C_TITLE = 4
325
- C_SHORT = 5
339
+ C_DATA = 0
340
+ C_NAME = 0
341
+ C_EDIT = 1
342
+ C_VIEW = 2
343
+ C_IMPORT = 3
344
+ C_DOC = 4
345
+ C_TITLE = 5
346
+ C_SHORT = 6
326
347
 
327
348
  D_TAG = Qt.ItemDataRole.UserRole
328
349
 
@@ -330,13 +351,14 @@ class _ViewPanelKeyWords(QTreeWidget):
330
351
  super().__init__(parent=parent)
331
352
 
332
353
  self._parent = parent
354
+ self._class = itemClass
333
355
  self._treeMap: dict[str, QTreeWidgetItem] = {}
334
356
 
335
357
  iPx = SHARED.theme.baseIconSize
336
358
  cMg = CONFIG.pxInt(6)
337
359
 
338
360
  self.setHeaderLabels([
339
- self.tr("Tag"), "", "", self.tr("Document"),
361
+ self.tr("Tag"), "", "", self.tr("Importance"), self.tr("Document"),
340
362
  self.tr("Heading"), self.tr("Short Description")
341
363
  ])
342
364
  self.setIndentation(0)
@@ -351,7 +373,7 @@ class _ViewPanelKeyWords(QTreeWidget):
351
373
  # Set Header Sizes
352
374
  treeHeader = self.header()
353
375
  treeHeader.setStretchLastSection(True)
354
- treeHeader.setSectionResizeMode(self.C_NAME, QHeaderView.ResizeMode.ResizeToContents)
376
+ treeHeader.setMinimumSectionSize(iPx + cMg) # See Issue #1627
355
377
  treeHeader.setSectionResizeMode(self.C_EDIT, QHeaderView.ResizeMode.Fixed)
356
378
  treeHeader.setSectionResizeMode(self.C_VIEW, QHeaderView.ResizeMode.Fixed)
357
379
  treeHeader.resizeSection(self.C_EDIT, iPx + cMg)
@@ -369,6 +391,17 @@ class _ViewPanelKeyWords(QTreeWidget):
369
391
 
370
392
  return
371
393
 
394
+ def updateTheme(self) -> None:
395
+ """Update theme elements."""
396
+ self._classIcon = SHARED.theme.getIcon(nwLabels.CLASS_ICON[self._class])
397
+ self._editIcon = SHARED.theme.getIcon("edit")
398
+ self._viewIcon = SHARED.theme.getIcon("view")
399
+ for i in range(self.topLevelItemCount()):
400
+ if item := self.topLevelItem(i):
401
+ item.setIcon(self.C_EDIT, self._editIcon)
402
+ item.setIcon(self.C_VIEW, self._viewIcon)
403
+ return
404
+
372
405
  def countEntries(self) -> int:
373
406
  """Return the number of items in the list."""
374
407
  return self.topLevelItemCount()
@@ -386,22 +419,30 @@ class _ViewPanelKeyWords(QTreeWidget):
386
419
  nwItem.itemType, nwItem.itemClass,
387
420
  nwItem.itemLayout, nwItem.mainHeading
388
421
  )
422
+ impLabel, impIcon = nwItem.getImportStatus(incIcon=True)
389
423
  iLevel = nwHeaders.H_LEVEL.get(hItem.level, 0) if nwItem.isDocumentLayout() else 5
390
424
  hDec = SHARED.theme.getHeaderDecorationNarrow(iLevel)
391
425
 
392
- # This can not use a get call to the dictionary as that creates
393
- # some weird issue with Qt, so we need to do this with an if
426
+ # This can not use a get call to the dictionary as that would create an
427
+ # instance of the QTreeWidgetItem, which has some weird side effects
394
428
  trItem = self._treeMap[tag] if tag in self._treeMap else QTreeWidgetItem()
395
429
 
396
- trItem.setText(self.C_NAME, name)
397
430
  trItem.setIcon(self.C_NAME, self._classIcon)
431
+ trItem.setText(self.C_NAME, name)
432
+ trItem.setToolTip(self.C_NAME, name)
398
433
  trItem.setIcon(self.C_EDIT, self._editIcon)
399
434
  trItem.setIcon(self.C_VIEW, self._viewIcon)
435
+ trItem.setIcon(self.C_IMPORT, impIcon)
436
+ trItem.setText(self.C_IMPORT, impLabel)
437
+ trItem.setToolTip(self.C_IMPORT, impLabel)
400
438
  trItem.setIcon(self.C_DOC, docIcon)
401
439
  trItem.setText(self.C_DOC, nwItem.itemName)
402
- trItem.setText(self.C_TITLE, hItem.title)
440
+ trItem.setToolTip(self.C_DOC, nwItem.itemName)
403
441
  trItem.setData(self.C_TITLE, Qt.ItemDataRole.DecorationRole, hDec)
442
+ trItem.setText(self.C_TITLE, hItem.title)
443
+ trItem.setToolTip(self.C_TITLE, hItem.title)
404
444
  trItem.setText(self.C_SHORT, hItem.synopsis)
445
+ trItem.setToolTip(self.C_SHORT, hItem.synopsis)
405
446
  trItem.setData(self.C_DATA, self.D_TAG, tag)
406
447
 
407
448
  if tag not in self._treeMap:
@@ -420,14 +461,18 @@ class _ViewPanelKeyWords(QTreeWidget):
420
461
 
421
462
  def setColumnWidths(self, widths: list[int]) -> None:
422
463
  """Set the column widths."""
423
- if isinstance(widths, list) and len(widths) >= 2:
424
- self.setColumnWidth(self.C_DOC, CONFIG.pxInt(checkInt(widths[0], 100)))
425
- self.setColumnWidth(self.C_TITLE, CONFIG.pxInt(checkInt(widths[1], 100)))
464
+ if isinstance(widths, list) and len(widths) >= 4:
465
+ self.setColumnWidth(self.C_NAME, CONFIG.pxInt(checkInt(widths[0], 100)))
466
+ self.setColumnWidth(self.C_IMPORT, CONFIG.pxInt(checkInt(widths[1], 100)))
467
+ self.setColumnWidth(self.C_DOC, CONFIG.pxInt(checkInt(widths[2], 100)))
468
+ self.setColumnWidth(self.C_TITLE, CONFIG.pxInt(checkInt(widths[3], 100)))
426
469
  return
427
470
 
428
471
  def getColumnWidths(self) -> list[int]:
429
472
  """Get the widths of the user-adjustable columns."""
430
473
  return [
474
+ CONFIG.rpxInt(self.columnWidth(self.C_NAME)),
475
+ CONFIG.rpxInt(self.columnWidth(self.C_IMPORT)),
431
476
  CONFIG.rpxInt(self.columnWidth(self.C_DOC)),
432
477
  CONFIG.rpxInt(self.columnWidth(self.C_TITLE)),
433
478
  ]
@@ -450,7 +495,7 @@ class _ViewPanelKeyWords(QTreeWidget):
450
495
  def _treeItemDoubleClicked(self, index: QModelIndex) -> None:
451
496
  """Emit follow tag signal on user double click."""
452
497
  tag = index.siblingAtColumn(self.C_DATA).data(self.D_TAG)
453
- if index.column() == self.C_NAME:
498
+ if index.column() not in (self.C_EDIT, self.C_VIEW):
454
499
  self._parent.loadDocumentTagRequest.emit(tag, nwDocMode.VIEW)
455
500
  return
456
501