novelWriter 2.2.1__py3-none-any.whl → 2.3b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/METADATA +1 -1
  2. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/RECORD +102 -92
  3. novelwriter/__init__.py +4 -4
  4. novelwriter/assets/icons/typicons_dark/icons.conf +6 -0
  5. novelwriter/assets/icons/typicons_dark/mixed_import.svg +5 -0
  6. novelwriter/assets/icons/typicons_dark/typ_document-add-col.svg +8 -0
  7. novelwriter/assets/icons/typicons_dark/typ_document-add.svg +4 -0
  8. novelwriter/assets/icons/typicons_dark/typ_document.svg +4 -0
  9. novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +4 -0
  10. novelwriter/assets/icons/typicons_light/icons.conf +6 -0
  11. novelwriter/assets/icons/typicons_light/mixed_import.svg +5 -0
  12. novelwriter/assets/icons/typicons_light/typ_document-add-col.svg +8 -0
  13. novelwriter/assets/icons/typicons_light/typ_document-add.svg +4 -0
  14. novelwriter/assets/icons/typicons_light/typ_document.svg +4 -0
  15. novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +4 -0
  16. novelwriter/assets/images/novelwriter-text-dark.svg +4 -0
  17. novelwriter/assets/images/novelwriter-text-light.svg +4 -0
  18. novelwriter/assets/images/welcome-dark.jpg +0 -0
  19. novelwriter/assets/images/welcome-light.jpg +0 -0
  20. novelwriter/assets/manual.pdf +0 -0
  21. novelwriter/assets/sample.zip +0 -0
  22. novelwriter/assets/syntax/default_dark.conf +1 -0
  23. novelwriter/assets/syntax/default_light.conf +1 -0
  24. novelwriter/assets/syntax/grey_dark.conf +1 -0
  25. novelwriter/assets/syntax/grey_light.conf +1 -0
  26. novelwriter/assets/syntax/light_owl.conf +1 -0
  27. novelwriter/assets/syntax/night_owl.conf +1 -0
  28. novelwriter/assets/syntax/solarized_dark.conf +1 -0
  29. novelwriter/assets/syntax/solarized_light.conf +1 -0
  30. novelwriter/assets/syntax/tomorrow.conf +1 -0
  31. novelwriter/assets/syntax/tomorrow_night.conf +1 -0
  32. novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
  33. novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
  34. novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
  35. novelwriter/assets/text/credits_en.htm +4 -2
  36. novelwriter/assets/themes/default_dark.conf +2 -2
  37. novelwriter/assets/themes/default_light.conf +2 -2
  38. novelwriter/common.py +48 -37
  39. novelwriter/config.py +36 -41
  40. novelwriter/constants.py +38 -16
  41. novelwriter/core/buildsettings.py +7 -7
  42. novelwriter/core/coretools.py +192 -154
  43. novelwriter/core/docbuild.py +6 -3
  44. novelwriter/core/document.py +6 -6
  45. novelwriter/core/index.py +89 -56
  46. novelwriter/core/item.py +21 -3
  47. novelwriter/core/options.py +8 -7
  48. novelwriter/core/project.py +69 -44
  49. novelwriter/core/projectdata.py +1 -14
  50. novelwriter/core/projectxml.py +13 -41
  51. novelwriter/core/sessions.py +2 -1
  52. novelwriter/core/spellcheck.py +2 -1
  53. novelwriter/core/status.py +2 -1
  54. novelwriter/core/storage.py +178 -140
  55. novelwriter/core/tohtml.py +4 -2
  56. novelwriter/core/tokenizer.py +73 -45
  57. novelwriter/core/toodt.py +40 -30
  58. novelwriter/core/tree.py +3 -2
  59. novelwriter/dialogs/about.py +70 -160
  60. novelwriter/dialogs/docmerge.py +6 -5
  61. novelwriter/dialogs/docsplit.py +6 -6
  62. novelwriter/dialogs/editlabel.py +1 -1
  63. novelwriter/dialogs/preferences.py +553 -703
  64. novelwriter/dialogs/{projsettings.py → projectsettings.py} +288 -262
  65. novelwriter/dialogs/quotes.py +27 -23
  66. novelwriter/dialogs/wordlist.py +96 -40
  67. novelwriter/enum.py +20 -18
  68. novelwriter/error.py +1 -1
  69. novelwriter/extensions/circularprogress.py +11 -11
  70. novelwriter/extensions/configlayout.py +185 -134
  71. novelwriter/extensions/modified.py +81 -0
  72. novelwriter/extensions/novelselector.py +26 -12
  73. novelwriter/extensions/pagedsidebar.py +14 -16
  74. novelwriter/extensions/simpleprogress.py +5 -5
  75. novelwriter/extensions/statusled.py +8 -8
  76. novelwriter/extensions/switch.py +31 -63
  77. novelwriter/extensions/switchbox.py +1 -1
  78. novelwriter/extensions/versioninfo.py +153 -0
  79. novelwriter/gui/doceditor.py +178 -150
  80. novelwriter/gui/dochighlight.py +63 -92
  81. novelwriter/gui/docviewer.py +49 -51
  82. novelwriter/gui/docviewerpanel.py +72 -24
  83. novelwriter/gui/itemdetails.py +7 -7
  84. novelwriter/gui/mainmenu.py +14 -18
  85. novelwriter/gui/noveltree.py +9 -8
  86. novelwriter/gui/outline.py +98 -75
  87. novelwriter/gui/projtree.py +188 -61
  88. novelwriter/gui/sidebar.py +3 -4
  89. novelwriter/gui/statusbar.py +3 -4
  90. novelwriter/gui/theme.py +60 -68
  91. novelwriter/guimain.py +49 -156
  92. novelwriter/shared.py +15 -1
  93. novelwriter/tools/dictionaries.py +5 -6
  94. novelwriter/tools/manuscript.py +6 -6
  95. novelwriter/tools/manussettings.py +192 -221
  96. novelwriter/tools/noveldetails.py +525 -0
  97. novelwriter/tools/welcome.py +802 -0
  98. novelwriter/tools/writingstats.py +9 -9
  99. novelwriter/assets/images/wizard-back.jpg +0 -0
  100. novelwriter/assets/text/gplv3_en.htm +0 -641
  101. novelwriter/assets/text/release_notes.htm +0 -60
  102. novelwriter/dialogs/projdetails.py +0 -518
  103. novelwriter/dialogs/projload.py +0 -294
  104. novelwriter/dialogs/updates.py +0 -172
  105. novelwriter/extensions/pageddialog.py +0 -130
  106. novelwriter/tools/projwizard.py +0 -478
  107. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/LICENSE.md +0 -0
  108. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/WHEEL +0 -0
  109. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/entry_points.txt +0 -0
  110. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/top_level.txt +0 -0
@@ -132,14 +132,10 @@ class GuiMainMenu(QMenuBar):
132
132
  # Project
133
133
  self.projMenu = self.addMenu(self.tr("&Project"))
134
134
 
135
- # Project > New Project
136
- self.aNewProject = self.projMenu.addAction(self.tr("New Project"))
137
- self.aNewProject.triggered.connect(lambda: self.mainGui.newProject(None))
138
-
139
- # Project > Open Project
140
- self.aOpenProject = self.projMenu.addAction(self.tr("Open Project"))
135
+ # Project > Create or Open Project
136
+ self.aOpenProject = self.projMenu.addAction(self.tr("Create or Open Project"))
141
137
  self.aOpenProject.setShortcut("Ctrl+Shift+O")
142
- self.aOpenProject.triggered.connect(lambda: self.mainGui.showProjectLoadDialog())
138
+ self.aOpenProject.triggered.connect(self.mainGui.showWelcomeDialog)
143
139
 
144
140
  # Project > Save Project
145
141
  self.aSaveProject = self.projMenu.addAction(self.tr("Save Project"))
@@ -159,10 +155,10 @@ class GuiMainMenu(QMenuBar):
159
155
  self.aProjectSettings.setShortcut("Ctrl+Shift+,")
160
156
  self.aProjectSettings.triggered.connect(self.mainGui.showProjectSettingsDialog)
161
157
 
162
- # Project > Project Details
163
- self.aProjectDetails = self.projMenu.addAction(self.tr("Project Details"))
164
- self.aProjectDetails.setShortcut("Shift+F6")
165
- self.aProjectDetails.triggered.connect(self.mainGui.showProjectDetailsDialog)
158
+ # Project > Novel Details
159
+ self.aNovelDetails = self.projMenu.addAction(self.tr("Novel Details"))
160
+ self.aNovelDetails.setShortcut("Shift+F6")
161
+ self.aNovelDetails.triggered.connect(self.mainGui.showNovelDetailsDialog)
166
162
 
167
163
  # Project > Separator
168
164
  self.projMenu.addSeparator()
@@ -785,6 +781,13 @@ class GuiMainMenu(QMenuBar):
785
781
  lambda: self.requestDocAction.emit(nwDocAction.BLOCK_COM)
786
782
  )
787
783
 
784
+ # Format > Ignore Text
785
+ self.aFmtIgnore = self.fmtMenu.addAction(self.tr("Toggle Ignore Text"))
786
+ self.aFmtIgnore.setShortcut("Ctrl+Shift+D")
787
+ self.aFmtIgnore.triggered.connect(
788
+ lambda: self.requestDocAction.emit(nwDocAction.BLOCK_IGN)
789
+ )
790
+
788
791
  # Format > Remove Block Format
789
792
  self.aFmtNoFormat = self.fmtMenu.addAction(self.tr("Remove Block Format"))
790
793
  self.aFmtNoFormat.setShortcuts(["Ctrl+0", "Ctrl+Shift+/"])
@@ -961,13 +964,6 @@ class GuiMainMenu(QMenuBar):
961
964
  self.aWebsite = self.helpMenu.addAction(self.tr("The novelWriter Website"))
962
965
  self.aWebsite.triggered.connect(lambda: self._openWebsite(nwConst.URL_WEB))
963
966
 
964
- # Help > Separator
965
- self.helpMenu.addSeparator()
966
-
967
- # Document > Check for Updates
968
- self.aUpdates = self.helpMenu.addAction(self.tr("Check for New Release"))
969
- self.aUpdates.triggered.connect(self.mainGui.showUpdatesDialog)
970
-
971
967
  return
972
968
 
973
969
  # END Class GuiMainMenu
@@ -207,9 +207,10 @@ class GuiNovelToolBar(QWidget):
207
207
  # Novel Selector
208
208
  selFont = self.font()
209
209
  selFont.setWeight(QFont.Weight.Bold)
210
- self.novelPrefix = self.tr("Outline of {0}")
210
+
211
211
  self.novelValue = NovelSelector(self)
212
212
  self.novelValue.setFont(selFont)
213
+ self.novelValue.setListFormat(self.tr("Outline of {0}"))
213
214
  self.novelValue.setMinimumWidth(CONFIG.pxInt(150))
214
215
  self.novelValue.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
215
216
  self.novelValue.novelSelectionChanged.connect(self.setCurrentRoot)
@@ -294,7 +295,7 @@ class GuiNovelToolBar(QWidget):
294
295
  "QComboBox {border-style: none; padding-left: 0;} "
295
296
  "QComboBox::drop-down {border-style: none}"
296
297
  )
297
- self.novelValue.updateList(prefix=self.novelPrefix)
298
+ self.novelValue.refreshNovelList()
298
299
  self.tbNovel.setVisible(self.novelValue.count() > 1)
299
300
 
300
301
  return
@@ -307,7 +308,7 @@ class GuiNovelToolBar(QWidget):
307
308
 
308
309
  def buildNovelRootMenu(self) -> None:
309
310
  """Build the novel root menu."""
310
- self.novelValue.updateList(prefix=self.novelPrefix)
311
+ self.novelValue.refreshNovelList()
311
312
  self.tbNovel.setVisible(self.novelValue.count() > 1)
312
313
  return
313
314
 
@@ -674,7 +675,7 @@ class GuiNovelTree(QTreeWidget):
674
675
  tStart = time()
675
676
  logger.debug("Building novel tree for root item '%s'", rootHandle)
676
677
 
677
- novStruct = SHARED.project.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
678
+ novStruct = SHARED.project.index.novelStructure(rootHandle=rootHandle, activeOnly=True)
678
679
  for tKey, tHandle, sTitle, novIdx in novStruct:
679
680
  if novIdx.level == "H0":
680
681
  continue
@@ -725,17 +726,17 @@ class GuiNovelTree(QTreeWidget):
725
726
 
726
727
  refData = []
727
728
  refName = ""
728
- theRefs = SHARED.project.index.getReferences(tHandle, sTitle)
729
+ refs = SHARED.project.index.getReferences(tHandle, sTitle)
729
730
  if self._lastCol == NovelTreeColumn.POV:
730
- refData = theRefs[nwKeyWords.POV_KEY]
731
+ refData = refs[nwKeyWords.POV_KEY]
731
732
  refName = self._povLabel
732
733
 
733
734
  elif self._lastCol == NovelTreeColumn.FOCUS:
734
- refData = theRefs[nwKeyWords.FOCUS_KEY]
735
+ refData = refs[nwKeyWords.FOCUS_KEY]
735
736
  refName = self._focLabel
736
737
 
737
738
  elif self._lastCol == NovelTreeColumn.PLOT:
738
- refData = theRefs[nwKeyWords.PLOT_KEY]
739
+ refData = refs[nwKeyWords.PLOT_KEY]
739
740
  refName = self._pltLabel
740
741
 
741
742
  if refData:
@@ -27,18 +27,17 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
27
27
  """
28
28
  from __future__ import annotations
29
29
 
30
+ import csv
30
31
  import logging
31
32
 
32
33
  from time import time
33
34
  from enum import Enum
34
35
 
35
- from PyQt5.QtCore import (
36
- Qt, pyqtSignal, pyqtSlot, QSize, QT_TRANSLATE_NOOP
37
- )
36
+ from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot, QSize, QT_TRANSLATE_NOOP
38
37
  from PyQt5.QtWidgets import (
39
- QAbstractItemView, QAction, QFrame, QGridLayout, QGroupBox, QHBoxLayout,
40
- QLabel, QMenu, QScrollArea, QSizePolicy, QSplitter, QToolBar, QToolButton,
41
- QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
38
+ QAbstractItemView, QAction, QFileDialog, QFrame, QGridLayout, QGroupBox,
39
+ QHBoxLayout, QLabel, QMenu, QScrollArea, QSizePolicy, QSplitter, QToolBar,
40
+ QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
42
41
  )
43
42
 
44
43
  from novelwriter import CONFIG, SHARED
@@ -46,7 +45,7 @@ from novelwriter.enum import (
46
45
  nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline
47
46
  )
48
47
  from novelwriter.error import logException
49
- from novelwriter.common import checkInt
48
+ from novelwriter.common import checkInt, formatFileFilter, makeFileNameSafe
50
49
  from novelwriter.constants import nwHeaders, trConst, nwKeyWords, nwLabels
51
50
  from novelwriter.extensions.novelselector import NovelSelector
52
51
 
@@ -88,6 +87,7 @@ class GuiOutlineView(QWidget):
88
87
  self.outlineData.itemTagClicked.connect(self._tagClicked)
89
88
  self.outlineBar.loadNovelRootRequest.connect(self._rootItemChanged)
90
89
  self.outlineBar.viewColumnToggled.connect(self.outlineTree.menuColumnToggled)
90
+ self.outlineBar.outlineExportRequest.connect(self.outlineTree.exportOutline)
91
91
 
92
92
  # Function Mappings
93
93
  self.getSelectedHandle = self.outlineTree.getSelectedHandle
@@ -124,7 +124,7 @@ class GuiOutlineView(QWidget):
124
124
  def openProjectTasks(self) -> None:
125
125
  """Run open project tasks."""
126
126
  lastOutline = SHARED.project.data.getLastHandle("outline")
127
- if not (lastOutline is None or lastOutline in SHARED.project.tree):
127
+ if not lastOutline or lastOutline not in SHARED.project.tree:
128
128
  lastOutline = SHARED.project.tree.findRoot(nwItemClass.NOVEL)
129
129
 
130
130
  logger.debug("Setting outline tree to root item '%s'", lastOutline)
@@ -198,6 +198,7 @@ class GuiOutlineView(QWidget):
198
198
  class GuiOutlineToolBar(QToolBar):
199
199
 
200
200
  loadNovelRootRequest = pyqtSignal(str)
201
+ outlineExportRequest = pyqtSignal()
201
202
  viewColumnToggled = pyqtSignal(bool, Enum)
202
203
 
203
204
  def __init__(self, outlineView: GuiOutlineView) -> None:
@@ -220,6 +221,7 @@ class GuiOutlineToolBar(QToolBar):
220
221
  self.novelLabel.setContentsMargins(0, 0, mPx, 0)
221
222
 
222
223
  self.novelValue = NovelSelector(self)
224
+ self.novelValue.setIncludeAll(True)
223
225
  self.novelValue.setMinimumWidth(CONFIG.pxInt(200))
224
226
  self.novelValue.novelSelectionChanged.connect(self._novelValueChanged)
225
227
 
@@ -227,6 +229,9 @@ class GuiOutlineToolBar(QToolBar):
227
229
  self.aRefresh = QAction(self.tr("Refresh"), self)
228
230
  self.aRefresh.triggered.connect(self._refreshRequested)
229
231
 
232
+ self.aExport = QAction(self.tr("Export CSV"), self)
233
+ self.aExport.triggered.connect(self._exportRequested)
234
+
230
235
  # Column Menu
231
236
  self.mColumns = GuiOutlineHeaderMenu(self)
232
237
  self.mColumns.columnToggled.connect(
@@ -242,6 +247,7 @@ class GuiOutlineToolBar(QToolBar):
242
247
  self.addWidget(self.novelValue)
243
248
  self.addSeparator()
244
249
  self.addAction(self.aRefresh)
250
+ self.addAction(self.aExport)
245
251
  self.addWidget(self.tbColumns)
246
252
  self.addWidget(stretch)
247
253
 
@@ -258,15 +264,16 @@ class GuiOutlineToolBar(QToolBar):
258
264
  def updateTheme(self) -> None:
259
265
  """Update theme elements."""
260
266
  self.setStyleSheet("QToolBar {border: 0px;}")
261
- self.novelValue.updateList(includeAll=True)
267
+ self.novelValue.refreshNovelList()
262
268
  self.aRefresh.setIcon(SHARED.theme.getIcon("refresh"))
269
+ self.aExport.setIcon(SHARED.theme.getIcon("export"))
263
270
  self.tbColumns.setIcon(SHARED.theme.getIcon("menu"))
264
271
  self.tbColumns.setStyleSheet("QToolButton::menu-indicator {image: none;}")
265
272
  return
266
273
 
267
274
  def populateNovelList(self) -> None:
268
275
  """Reload the content of the novel list."""
269
- self.novelValue.updateList(includeAll=True)
276
+ self.novelValue.refreshNovelList()
270
277
  return
271
278
 
272
279
  def setCurrentRoot(self, rootHandle: str | None) -> None:
@@ -295,6 +302,12 @@ class GuiOutlineToolBar(QToolBar):
295
302
  self.loadNovelRootRequest.emit(self.novelValue.handle)
296
303
  return
297
304
 
305
+ @pyqtSlot()
306
+ def _exportRequested(self) -> None:
307
+ """Emit a signal that an export of the outline was requested."""
308
+ self.outlineExportRequest.emit()
309
+ return
310
+
298
311
  # END Class GuiOutlineToolBar
299
312
 
300
313
 
@@ -491,15 +504,48 @@ class GuiOutlineTree(QTreeWidget):
491
504
  """Get the currently selected handle. If multiple items are
492
505
  selected, return the first.
493
506
  """
494
- selItem = self.selectedItems()
495
- if selItem:
496
- tHandle = selItem[0].data(self._colIdx[nwOutline.TITLE], self.D_HANDLE)
497
- sTitle = selItem[0].data(self._colIdx[nwOutline.TITLE], self.D_TITLE)
507
+ if item := self.selectedItems():
508
+ tHandle = item[0].data(self._colIdx[nwOutline.TITLE], self.D_HANDLE)
509
+ sTitle = item[0].data(self._colIdx[nwOutline.TITLE], self.D_TITLE)
498
510
  return tHandle, sTitle
499
511
  return None, None
500
512
 
501
513
  ##
502
- # Slots
514
+ # Public Slots
515
+ ##
516
+
517
+ @pyqtSlot(bool, Enum)
518
+ def menuColumnToggled(self, isChecked: bool, hItem: nwOutline) -> None:
519
+ """Receive the changes to column visibility forwarded by the
520
+ column selection menu.
521
+ """
522
+ if hItem in self._colIdx:
523
+ self.setColumnHidden(self._colIdx[hItem], not isChecked)
524
+ self._saveHeaderState()
525
+ return
526
+
527
+ @pyqtSlot()
528
+ def exportOutline(self) -> None:
529
+ """Export the outline as a CSV file."""
530
+ path = CONFIG.lastPath() / f"{makeFileNameSafe(SHARED.project.data.name)}.csv"
531
+ path, _ = QFileDialog.getSaveFileName(
532
+ self, self.tr("Save Outline As"), str(path), formatFileFilter(["*.csv", "*"])
533
+ )
534
+ if path:
535
+ CONFIG.setLastPath(path)
536
+ logger.info("Writing CSV file: %s", path)
537
+ cols = [col for col in self._treeOrder if not self._colHidden[col]]
538
+ order = [self._colIdx[col] for col in cols]
539
+ with open(path, mode="w", newline="") as csvFile:
540
+ writer = csv.writer(csvFile, dialect="excel", quoting=csv.QUOTE_ALL)
541
+ writer.writerow([trConst(nwLabels.OUTLINE_COLS[col]) for col in cols])
542
+ for i in range(self.topLevelItemCount()):
543
+ if item := self.topLevelItem(i):
544
+ writer.writerow(item.text(i) for i in order)
545
+ return
546
+
547
+ ##
548
+ # Private Slots
503
549
  ##
504
550
 
505
551
  @pyqtSlot("QTreeWidgetItem*", int)
@@ -509,9 +555,8 @@ class GuiOutlineTree(QTreeWidget):
509
555
  document editor.
510
556
  """
511
557
  tHandle, sTitle = self.getSelectedHandle()
512
- if tHandle is None:
513
- return
514
- self.outlineView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, sTitle or "", True)
558
+ if tHandle:
559
+ self.outlineView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, sTitle or "", True)
515
560
  return
516
561
 
517
562
  @pyqtSlot()
@@ -535,16 +580,6 @@ class GuiOutlineTree(QTreeWidget):
535
580
  self._saveHeaderState()
536
581
  return
537
582
 
538
- @pyqtSlot(bool, Enum)
539
- def menuColumnToggled(self, isChecked: bool, hItem: nwOutline) -> None:
540
- """Receive the changes to column visibility forwarded by the
541
- column selection menu.
542
- """
543
- if hItem in self._colIdx:
544
- self.setColumnHidden(self._colIdx[hItem], not isChecked)
545
- self._saveHeaderState()
546
- return
547
-
548
583
  ##
549
584
  # Internal Functions
550
585
  ##
@@ -624,12 +659,12 @@ class GuiOutlineTree(QTreeWidget):
624
659
  self.clear()
625
660
 
626
661
  if self._firstView:
627
- theLabels = []
662
+ labels = []
628
663
  for i, hItem in enumerate(self._treeOrder):
629
- theLabels.append(trConst(nwLabels.OUTLINE_COLS[hItem]))
664
+ labels.append(trConst(nwLabels.OUTLINE_COLS[hItem]))
630
665
  self._colIdx[hItem] = i
631
666
 
632
- self.setHeaderLabels(theLabels)
667
+ self.setHeaderLabels(labels)
633
668
  for hItem in self._treeOrder:
634
669
  self.setColumnWidth(self._colIdx[hItem], self._colWidth[hItem])
635
670
  self.setColumnHidden(self._colIdx[hItem], self._colHidden[hItem])
@@ -646,7 +681,7 @@ class GuiOutlineTree(QTreeWidget):
646
681
  headItem.setTextAlignment(
647
682
  self._colIdx[nwOutline.PCOUNT], Qt.AlignmentFlag.AlignRight)
648
683
 
649
- novStruct = SHARED.project.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
684
+ novStruct = SHARED.project.index.novelStructure(rootHandle=rootHandle, activeOnly=True)
650
685
  for _, tHandle, sTitle, novIdx in novStruct:
651
686
 
652
687
  iLevel = nwHeaders.H_LEVEL.get(novIdx.level, 0)
@@ -842,18 +877,15 @@ class GuiOutlineDetails(QScrollArea):
842
877
  self.entKeyValue.setWordWrap(True)
843
878
  self.cstKeyValue.setWordWrap(True)
844
879
 
845
- def tagClicked(link):
846
- self.itemTagClicked.emit(link)
847
-
848
- self.povKeyValue.linkActivated.connect(tagClicked)
849
- self.focKeyValue.linkActivated.connect(tagClicked)
850
- self.chrKeyValue.linkActivated.connect(tagClicked)
851
- self.pltKeyValue.linkActivated.connect(tagClicked)
852
- self.timKeyValue.linkActivated.connect(tagClicked)
853
- self.wldKeyValue.linkActivated.connect(tagClicked)
854
- self.objKeyValue.linkActivated.connect(tagClicked)
855
- self.entKeyValue.linkActivated.connect(tagClicked)
856
- self.cstKeyValue.linkActivated.connect(tagClicked)
880
+ self.povKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
881
+ self.focKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
882
+ self.chrKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
883
+ self.pltKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
884
+ self.timKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
885
+ self.wldKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
886
+ self.objKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
887
+ self.entKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
888
+ self.cstKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
857
889
 
858
890
  self.povKeyLWrap.addWidget(self.povKeyValue, 1)
859
891
  self.focKeyLWrap.addWidget(self.focKeyValue, 1)
@@ -982,49 +1014,40 @@ class GuiOutlineDetails(QScrollArea):
982
1014
  ##
983
1015
 
984
1016
  @pyqtSlot(str, str)
985
- def showItem(self, tHandle: str, sTitle: str) -> bool:
1017
+ def showItem(self, tHandle: str, sTitle: str) -> None:
986
1018
  """Update the content of the tree with the given handle and line
987
1019
  number pointing to a header.
988
1020
  """
989
1021
  pIndex = SHARED.project.index
990
1022
  nwItem = SHARED.project.tree[tHandle]
991
1023
  novIdx = pIndex.getItemHeader(tHandle, sTitle)
992
- theRefs = pIndex.getReferences(tHandle, sTitle)
993
- if nwItem is None or novIdx is None:
994
- return False
995
-
996
- if novIdx.level in self.LVL_MAP:
997
- self.titleLabel.setText("<b>%s</b>" % self.tr(self.LVL_MAP[novIdx.level]))
998
- else:
999
- self.titleLabel.setText("<b>%s</b>" % self.tr("Title"))
1000
- self.titleValue.setText(novIdx.title)
1024
+ novRefs = pIndex.getReferences(tHandle, sTitle)
1025
+ if nwItem and novIdx:
1026
+ self.titleLabel.setText("<b>%s</b>" % self.tr(self.LVL_MAP.get(novIdx.level, "H1")))
1027
+ self.titleValue.setText(novIdx.title)
1001
1028
 
1002
- itemStatus, _ = nwItem.getImportStatus(incIcon=False)
1029
+ itemStatus, _ = nwItem.getImportStatus(incIcon=False)
1003
1030
 
1004
- self.fileValue.setText(nwItem.itemName)
1005
- self.itemValue.setText(itemStatus)
1031
+ self.fileValue.setText(nwItem.itemName)
1032
+ self.itemValue.setText(itemStatus)
1006
1033
 
1007
- cC = checkInt(novIdx.charCount, 0)
1008
- wC = checkInt(novIdx.wordCount, 0)
1009
- pC = checkInt(novIdx.paraCount, 0)
1034
+ self.cCValue.setText(f"{checkInt(novIdx.charCount, 0):n}")
1035
+ self.wCValue.setText(f"{checkInt(novIdx.wordCount, 0):n}")
1036
+ self.pCValue.setText(f"{checkInt(novIdx.paraCount, 0):n}")
1010
1037
 
1011
- self.cCValue.setText(f"{cC:n}")
1012
- self.wCValue.setText(f"{wC:n}")
1013
- self.pCValue.setText(f"{pC:n}")
1038
+ self.synopValue.setText(novIdx.synopsis)
1014
1039
 
1015
- self.synopValue.setText(novIdx.synopsis)
1040
+ self.povKeyValue.setText(self._formatTags(novRefs, nwKeyWords.POV_KEY))
1041
+ self.focKeyValue.setText(self._formatTags(novRefs, nwKeyWords.FOCUS_KEY))
1042
+ self.chrKeyValue.setText(self._formatTags(novRefs, nwKeyWords.CHAR_KEY))
1043
+ self.pltKeyValue.setText(self._formatTags(novRefs, nwKeyWords.PLOT_KEY))
1044
+ self.timKeyValue.setText(self._formatTags(novRefs, nwKeyWords.TIME_KEY))
1045
+ self.wldKeyValue.setText(self._formatTags(novRefs, nwKeyWords.WORLD_KEY))
1046
+ self.objKeyValue.setText(self._formatTags(novRefs, nwKeyWords.OBJECT_KEY))
1047
+ self.entKeyValue.setText(self._formatTags(novRefs, nwKeyWords.ENTITY_KEY))
1048
+ self.cstKeyValue.setText(self._formatTags(novRefs, nwKeyWords.CUSTOM_KEY))
1016
1049
 
1017
- self.povKeyValue.setText(self._formatTags(theRefs, nwKeyWords.POV_KEY))
1018
- self.focKeyValue.setText(self._formatTags(theRefs, nwKeyWords.FOCUS_KEY))
1019
- self.chrKeyValue.setText(self._formatTags(theRefs, nwKeyWords.CHAR_KEY))
1020
- self.pltKeyValue.setText(self._formatTags(theRefs, nwKeyWords.PLOT_KEY))
1021
- self.timKeyValue.setText(self._formatTags(theRefs, nwKeyWords.TIME_KEY))
1022
- self.wldKeyValue.setText(self._formatTags(theRefs, nwKeyWords.WORLD_KEY))
1023
- self.objKeyValue.setText(self._formatTags(theRefs, nwKeyWords.OBJECT_KEY))
1024
- self.entKeyValue.setText(self._formatTags(theRefs, nwKeyWords.ENTITY_KEY))
1025
- self.cstKeyValue.setText(self._formatTags(theRefs, nwKeyWords.CUSTOM_KEY))
1026
-
1027
- return True
1050
+ return
1028
1051
 
1029
1052
  @pyqtSlot()
1030
1053
  def updateClasses(self) -> None: