novelWriter 2.5.1__py3-none-any.whl → 2.6b1__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 (64) hide show
  1. {novelWriter-2.5.1.dist-info → novelWriter-2.6b1.dist-info}/METADATA +2 -1
  2. {novelWriter-2.5.1.dist-info → novelWriter-2.6b1.dist-info}/RECORD +61 -56
  3. {novelWriter-2.5.1.dist-info → novelWriter-2.6b1.dist-info}/WHEEL +1 -1
  4. novelwriter/__init__.py +3 -3
  5. novelwriter/assets/i18n/project_en_GB.json +1 -0
  6. novelwriter/assets/icons/typicons_dark/icons.conf +1 -0
  7. novelwriter/assets/icons/typicons_dark/mixed_copy.svg +4 -0
  8. novelwriter/assets/icons/typicons_light/icons.conf +1 -0
  9. novelwriter/assets/icons/typicons_light/mixed_copy.svg +4 -0
  10. novelwriter/assets/manual.pdf +0 -0
  11. novelwriter/assets/sample.zip +0 -0
  12. novelwriter/assets/themes/default_light.conf +2 -2
  13. novelwriter/common.py +63 -0
  14. novelwriter/config.py +10 -3
  15. novelwriter/constants.py +153 -60
  16. novelwriter/core/buildsettings.py +66 -39
  17. novelwriter/core/coretools.py +34 -22
  18. novelwriter/core/docbuild.py +130 -169
  19. novelwriter/core/index.py +29 -18
  20. novelwriter/core/item.py +2 -2
  21. novelwriter/core/options.py +4 -1
  22. novelwriter/core/spellcheck.py +9 -14
  23. novelwriter/dialogs/preferences.py +45 -32
  24. novelwriter/dialogs/projectsettings.py +3 -3
  25. novelwriter/enum.py +29 -23
  26. novelwriter/extensions/configlayout.py +24 -11
  27. novelwriter/extensions/modified.py +13 -1
  28. novelwriter/extensions/pagedsidebar.py +5 -5
  29. novelwriter/formats/shared.py +155 -0
  30. novelwriter/formats/todocx.py +1195 -0
  31. novelwriter/formats/tohtml.py +452 -0
  32. novelwriter/{core → formats}/tokenizer.py +483 -485
  33. novelwriter/formats/tomarkdown.py +217 -0
  34. novelwriter/{core → formats}/toodt.py +270 -320
  35. novelwriter/formats/toqdoc.py +436 -0
  36. novelwriter/formats/toraw.py +91 -0
  37. novelwriter/gui/doceditor.py +240 -193
  38. novelwriter/gui/dochighlight.py +96 -84
  39. novelwriter/gui/docviewer.py +56 -30
  40. novelwriter/gui/docviewerpanel.py +3 -3
  41. novelwriter/gui/editordocument.py +17 -2
  42. novelwriter/gui/itemdetails.py +8 -4
  43. novelwriter/gui/mainmenu.py +121 -60
  44. novelwriter/gui/noveltree.py +35 -37
  45. novelwriter/gui/outline.py +186 -238
  46. novelwriter/gui/projtree.py +142 -131
  47. novelwriter/gui/sidebar.py +7 -6
  48. novelwriter/gui/theme.py +5 -4
  49. novelwriter/guimain.py +43 -155
  50. novelwriter/shared.py +14 -4
  51. novelwriter/text/counting.py +2 -0
  52. novelwriter/text/patterns.py +155 -59
  53. novelwriter/tools/manusbuild.py +1 -1
  54. novelwriter/tools/manuscript.py +121 -78
  55. novelwriter/tools/manussettings.py +403 -260
  56. novelwriter/tools/welcome.py +4 -4
  57. novelwriter/tools/writingstats.py +3 -3
  58. novelwriter/types.py +16 -6
  59. novelwriter/core/tohtml.py +0 -530
  60. novelwriter/core/tomarkdown.py +0 -252
  61. novelwriter/core/toqdoc.py +0 -419
  62. {novelWriter-2.5.1.dist-info → novelWriter-2.6b1.dist-info}/LICENSE.md +0 -0
  63. {novelWriter-2.5.1.dist-info → novelWriter-2.6b1.dist-info}/entry_points.txt +0 -0
  64. {novelWriter-2.5.1.dist-info → novelWriter-2.6b1.dist-info}/top_level.txt +0 -0
@@ -42,14 +42,14 @@ from PyQt5.QtWidgets import (
42
42
 
43
43
  from novelwriter import CONFIG, SHARED
44
44
  from novelwriter.common import checkInt, formatFileFilter, makeFileNameSafe
45
- from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst
45
+ from novelwriter.constants import nwKeyWords, nwLabels, nwStats, nwStyles, trConst
46
46
  from novelwriter.enum import nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline
47
47
  from novelwriter.error import logException
48
48
  from novelwriter.extensions.configlayout import NColourLabel
49
49
  from novelwriter.extensions.novelselector import NovelSelector
50
50
  from novelwriter.types import (
51
51
  QtAlignLeftTop, QtAlignRight, QtAlignRightTop, QtDecoration,
52
- QtSizeExpanding, QtUserRole
52
+ QtScrollAlwaysOff, QtScrollAsNeeded, QtSizeExpanding, QtUserRole
53
53
  )
54
54
 
55
55
  logger = logging.getLogger(__name__)
@@ -135,11 +135,15 @@ class GuiOutlineView(QWidget):
135
135
  self.outlineBar.populateNovelList()
136
136
  self.outlineBar.setCurrentRoot(lastOutline)
137
137
  self.outlineBar.setEnabled(True)
138
+ self.outlineData.loadGuiSettings()
138
139
 
139
140
  return
140
141
 
141
142
  def closeProjectTasks(self) -> None:
142
143
  """Run closing project tasks."""
144
+ if self.outlineTree.wasRendered:
145
+ # If the panel hasn't been drawn yet, those values are incorrect
146
+ self.outlineData.saveGuiSettings()
143
147
  self.outlineTree.closeProjectTasks()
144
148
  self.outlineData.updateClasses()
145
149
  self.clearOutline()
@@ -312,43 +316,49 @@ class GuiOutlineToolBar(QToolBar):
312
316
  class GuiOutlineTree(QTreeWidget):
313
317
 
314
318
  DEF_WIDTH = {
315
- nwOutline.TITLE: 200,
316
- nwOutline.LEVEL: 40,
317
- nwOutline.LABEL: 150,
318
- nwOutline.LINE: 40,
319
- nwOutline.CCOUNT: 50,
320
- nwOutline.WCOUNT: 50,
321
- nwOutline.PCOUNT: 50,
322
- nwOutline.POV: 100,
323
- nwOutline.FOCUS: 100,
324
- nwOutline.CHAR: 100,
325
- nwOutline.PLOT: 100,
326
- nwOutline.TIME: 100,
327
- nwOutline.WORLD: 100,
328
- nwOutline.OBJECT: 100,
329
- nwOutline.ENTITY: 100,
330
- nwOutline.CUSTOM: 100,
331
- nwOutline.SYNOP: 200,
319
+ nwOutline.TITLE: 200,
320
+ nwOutline.LEVEL: 40,
321
+ nwOutline.LABEL: 150,
322
+ nwOutline.LINE: 40,
323
+ nwOutline.STATUS: 100,
324
+ nwOutline.CCOUNT: 50,
325
+ nwOutline.WCOUNT: 50,
326
+ nwOutline.PCOUNT: 50,
327
+ nwOutline.POV: 100,
328
+ nwOutline.FOCUS: 100,
329
+ nwOutline.CHAR: 100,
330
+ nwOutline.PLOT: 100,
331
+ nwOutline.TIME: 100,
332
+ nwOutline.WORLD: 100,
333
+ nwOutline.OBJECT: 100,
334
+ nwOutline.ENTITY: 100,
335
+ nwOutline.CUSTOM: 100,
336
+ nwOutline.STORY: 100,
337
+ nwOutline.MENTION: 100,
338
+ nwOutline.SYNOP: 200,
332
339
  }
333
340
 
334
341
  DEF_HIDDEN = {
335
- nwOutline.TITLE: False,
336
- nwOutline.LEVEL: True,
337
- nwOutline.LABEL: False,
338
- nwOutline.LINE: True,
339
- nwOutline.CCOUNT: True,
340
- nwOutline.WCOUNT: False,
341
- nwOutline.PCOUNT: False,
342
- nwOutline.POV: False,
343
- nwOutline.FOCUS: True,
344
- nwOutline.CHAR: False,
345
- nwOutline.PLOT: False,
346
- nwOutline.TIME: True,
347
- nwOutline.WORLD: False,
348
- nwOutline.OBJECT: True,
349
- nwOutline.ENTITY: True,
350
- nwOutline.CUSTOM: True,
351
- nwOutline.SYNOP: False,
342
+ nwOutline.TITLE: False,
343
+ nwOutline.LEVEL: True,
344
+ nwOutline.LABEL: False,
345
+ nwOutline.LINE: True,
346
+ nwOutline.STATUS: True,
347
+ nwOutline.CCOUNT: True,
348
+ nwOutline.WCOUNT: False,
349
+ nwOutline.PCOUNT: False,
350
+ nwOutline.POV: False,
351
+ nwOutline.FOCUS: True,
352
+ nwOutline.CHAR: False,
353
+ nwOutline.PLOT: False,
354
+ nwOutline.TIME: True,
355
+ nwOutline.WORLD: False,
356
+ nwOutline.OBJECT: True,
357
+ nwOutline.ENTITY: True,
358
+ nwOutline.CUSTOM: True,
359
+ nwOutline.STORY: True,
360
+ nwOutline.MENTION: True,
361
+ nwOutline.SYNOP: False,
352
362
  }
353
363
 
354
364
  D_HANDLE = QtUserRole
@@ -426,6 +436,11 @@ class GuiOutlineTree(QTreeWidget):
426
436
  def hiddenColumns(self) -> dict[nwOutline, bool]:
427
437
  return self._colHidden
428
438
 
439
+ @property
440
+ def wasRendered(self) -> bool:
441
+ """Returns True after the Outline has been rendered once."""
442
+ return not self._firstView
443
+
429
444
  ##
430
445
  # Methods
431
446
  ##
@@ -433,13 +448,13 @@ class GuiOutlineTree(QTreeWidget):
433
448
  def initSettings(self) -> None:
434
449
  """Set or update outline settings."""
435
450
  if CONFIG.hideVScroll:
436
- self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
451
+ self.setVerticalScrollBarPolicy(QtScrollAlwaysOff)
437
452
  else:
438
- self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
453
+ self.setVerticalScrollBarPolicy(QtScrollAsNeeded)
439
454
  if CONFIG.hideHScroll:
440
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
455
+ self.setHorizontalScrollBarPolicy(QtScrollAlwaysOff)
441
456
  else:
442
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
457
+ self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
443
458
  return
444
459
 
445
460
  def clearContent(self) -> None:
@@ -465,8 +480,10 @@ class GuiOutlineTree(QTreeWidget):
465
480
 
466
481
  return
467
482
 
468
- def refreshTree(self, rootHandle: str | None = None,
469
- overRide: bool = False, novelChanged: bool = False) -> None:
483
+ def refreshTree(
484
+ self, rootHandle: str | None = None,
485
+ overRide: bool = False, novelChanged: bool = False
486
+ ) -> None:
470
487
  """Called whenever the Outline tab is activated and controls
471
488
  what data to load, and if necessary, force a rebuild of the
472
489
  tree.
@@ -653,6 +670,7 @@ class GuiOutlineTree(QTreeWidget):
653
670
  is fast and doesn't require a rebuild of the tree.
654
671
  """
655
672
  logger.debug("Rebuilding Outline tree")
673
+ tStart = time()
656
674
  self.clear()
657
675
 
658
676
  if self._firstView:
@@ -681,45 +699,51 @@ class GuiOutlineTree(QTreeWidget):
681
699
  novStruct = SHARED.project.index.novelStructure(rootHandle=rootHandle, activeOnly=True)
682
700
  for _, tHandle, sTitle, novIdx in novStruct:
683
701
 
684
- iLevel = nwHeaders.H_LEVEL.get(novIdx.level, 0)
702
+ iLevel = nwStyles.H_LEVEL.get(novIdx.level, 0)
685
703
  nwItem = SHARED.project.tree[tHandle]
686
704
  if iLevel == 0 or nwItem is None:
687
705
  continue
706
+ sLabel, sIcon = nwItem.getImportStatus()
688
707
 
689
- trItem = QTreeWidgetItem()
708
+ item = QTreeWidgetItem()
690
709
  hDec = SHARED.theme.getHeaderDecoration(iLevel)
691
710
 
692
- trItem.setData(self._colIdx[nwOutline.TITLE], QtDecoration, hDec)
693
- trItem.setText(self._colIdx[nwOutline.TITLE], novIdx.title)
694
- trItem.setData(self._colIdx[nwOutline.TITLE], self.D_HANDLE, tHandle)
695
- trItem.setData(self._colIdx[nwOutline.TITLE], self.D_TITLE, sTitle)
696
- trItem.setFont(self._colIdx[nwOutline.TITLE], self._hFonts[iLevel])
697
- trItem.setText(self._colIdx[nwOutline.LEVEL], novIdx.level)
698
- trItem.setIcon(self._colIdx[nwOutline.LABEL], self._dIcon[nwItem.mainHeading])
699
- trItem.setText(self._colIdx[nwOutline.LABEL], nwItem.itemName)
700
- trItem.setText(self._colIdx[nwOutline.LINE], f"{novIdx.line:n}")
701
- trItem.setText(self._colIdx[nwOutline.SYNOP], novIdx.synopsis)
702
- trItem.setText(self._colIdx[nwOutline.CCOUNT], f"{novIdx.charCount:n}")
703
- trItem.setText(self._colIdx[nwOutline.WCOUNT], f"{novIdx.wordCount:n}")
704
- trItem.setText(self._colIdx[nwOutline.PCOUNT], f"{novIdx.paraCount:n}")
705
- trItem.setTextAlignment(self._colIdx[nwOutline.CCOUNT], QtAlignRight)
706
- trItem.setTextAlignment(self._colIdx[nwOutline.WCOUNT], QtAlignRight)
707
- trItem.setTextAlignment(self._colIdx[nwOutline.PCOUNT], QtAlignRight)
711
+ item.setData(self._colIdx[nwOutline.TITLE], QtDecoration, hDec)
712
+ item.setText(self._colIdx[nwOutline.TITLE], novIdx.title)
713
+ item.setData(self._colIdx[nwOutline.TITLE], self.D_HANDLE, tHandle)
714
+ item.setData(self._colIdx[nwOutline.TITLE], self.D_TITLE, sTitle)
715
+ item.setFont(self._colIdx[nwOutline.TITLE], self._hFonts[iLevel])
716
+ item.setText(self._colIdx[nwOutline.LEVEL], novIdx.level)
717
+ item.setIcon(self._colIdx[nwOutline.LABEL], self._dIcon[nwItem.mainHeading])
718
+ item.setText(self._colIdx[nwOutline.LABEL], nwItem.itemName)
719
+ item.setText(self._colIdx[nwOutline.LINE], f"{novIdx.line:n}")
720
+ item.setText(self._colIdx[nwOutline.STATUS], sLabel)
721
+ item.setIcon(self._colIdx[nwOutline.STATUS], sIcon)
722
+ item.setText(self._colIdx[nwOutline.SYNOP], novIdx.synopsis)
723
+ item.setText(self._colIdx[nwOutline.CCOUNT], f"{novIdx.charCount:n}")
724
+ item.setText(self._colIdx[nwOutline.WCOUNT], f"{novIdx.wordCount:n}")
725
+ item.setText(self._colIdx[nwOutline.PCOUNT], f"{novIdx.paraCount:n}")
726
+ item.setTextAlignment(self._colIdx[nwOutline.CCOUNT], QtAlignRight)
727
+ item.setTextAlignment(self._colIdx[nwOutline.WCOUNT], QtAlignRight)
728
+ item.setTextAlignment(self._colIdx[nwOutline.PCOUNT], QtAlignRight)
708
729
 
709
730
  refs = SHARED.project.index.getReferences(tHandle, sTitle)
710
- trItem.setText(self._colIdx[nwOutline.POV], ", ".join(refs[nwKeyWords.POV_KEY]))
711
- trItem.setText(self._colIdx[nwOutline.FOCUS], ", ".join(refs[nwKeyWords.FOCUS_KEY]))
712
- trItem.setText(self._colIdx[nwOutline.CHAR], ", ".join(refs[nwKeyWords.CHAR_KEY]))
713
- trItem.setText(self._colIdx[nwOutline.PLOT], ", ".join(refs[nwKeyWords.PLOT_KEY]))
714
- trItem.setText(self._colIdx[nwOutline.TIME], ", ".join(refs[nwKeyWords.TIME_KEY]))
715
- trItem.setText(self._colIdx[nwOutline.WORLD], ", ".join(refs[nwKeyWords.WORLD_KEY]))
716
- trItem.setText(self._colIdx[nwOutline.OBJECT], ", ".join(refs[nwKeyWords.OBJECT_KEY]))
717
- trItem.setText(self._colIdx[nwOutline.ENTITY], ", ".join(refs[nwKeyWords.ENTITY_KEY]))
718
- trItem.setText(self._colIdx[nwOutline.CUSTOM], ", ".join(refs[nwKeyWords.CUSTOM_KEY]))
719
-
720
- self.addTopLevelItem(trItem)
731
+ item.setText(self._colIdx[nwOutline.POV], ", ".join(refs[nwKeyWords.POV_KEY]))
732
+ item.setText(self._colIdx[nwOutline.FOCUS], ", ".join(refs[nwKeyWords.FOCUS_KEY]))
733
+ item.setText(self._colIdx[nwOutline.CHAR], ", ".join(refs[nwKeyWords.CHAR_KEY]))
734
+ item.setText(self._colIdx[nwOutline.PLOT], ", ".join(refs[nwKeyWords.PLOT_KEY]))
735
+ item.setText(self._colIdx[nwOutline.TIME], ", ".join(refs[nwKeyWords.TIME_KEY]))
736
+ item.setText(self._colIdx[nwOutline.WORLD], ", ".join(refs[nwKeyWords.WORLD_KEY]))
737
+ item.setText(self._colIdx[nwOutline.OBJECT], ", ".join(refs[nwKeyWords.OBJECT_KEY]))
738
+ item.setText(self._colIdx[nwOutline.ENTITY], ", ".join(refs[nwKeyWords.ENTITY_KEY]))
739
+ item.setText(self._colIdx[nwOutline.CUSTOM], ", ".join(refs[nwKeyWords.CUSTOM_KEY]))
740
+ item.setText(self._colIdx[nwOutline.STORY], ", ".join(refs[nwKeyWords.STORY_KEY]))
741
+ item.setText(self._colIdx[nwOutline.MENTION], ", ".join(refs[nwKeyWords.MENTION_KEY]))
742
+
743
+ self.addTopLevelItem(item)
721
744
 
722
745
  self._lastBuild = time()
746
+ logger.debug("Project outline built in %.3f ms", 1000.0*(time() - tStart))
723
747
 
724
748
  return
725
749
 
@@ -793,6 +817,10 @@ class GuiOutlineDetails(QScrollArea):
793
817
 
794
818
  bFont = SHARED.theme.guiFontB
795
819
 
820
+ trStats1 = trConst(nwLabels.STATS_NAME[nwStats.CHARS_ALL])
821
+ trStats2 = trConst(nwLabels.STATS_NAME[nwStats.WORDS_ALL])
822
+ trStats3 = trConst(nwLabels.STATS_NAME[nwStats.PARAGRAPHS])
823
+
796
824
  # Details Area
797
825
  self.titleLabel = QLabel(self.tr("Title"), self)
798
826
  self.fileLabel = QLabel(self.tr("Document"), self)
@@ -813,9 +841,9 @@ class GuiOutlineDetails(QScrollArea):
813
841
  self.itemValue.setMaximumWidth(maxTitle)
814
842
 
815
843
  # Stats Area
816
- self.cCLabel = QLabel(self.tr("Characters"), self)
817
- self.wCLabel = QLabel(self.tr("Words"), self)
818
- self.pCLabel = QLabel(self.tr("Paragraphs"), self)
844
+ self.cCLabel = QLabel(trStats1, self)
845
+ self.wCLabel = QLabel(trStats2, self)
846
+ self.pCLabel = QLabel(trStats3, self)
819
847
  self.cCValue = QLabel("", self)
820
848
  self.wCValue = QLabel("", self)
821
849
  self.pCValue = QLabel("", self)
@@ -842,96 +870,25 @@ class GuiOutlineDetails(QScrollArea):
842
870
  self.synopLWrap = QHBoxLayout()
843
871
  self.synopLWrap.addWidget(self.synopValue, 1)
844
872
 
845
- # Tags
846
- self.povKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY]), self)
847
- self.focKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY]), self)
848
- self.chrKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.CHAR_KEY]), self)
849
- self.pltKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY]), self)
850
- self.timKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.TIME_KEY]), self)
851
- self.wldKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.WORLD_KEY]), self)
852
- self.objKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.OBJECT_KEY]), self)
853
- self.entKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.ENTITY_KEY]), self)
854
- self.cstKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.CUSTOM_KEY]), self)
855
-
856
- self.povKeyLabel.setFont(bFont)
857
- self.focKeyLabel.setFont(bFont)
858
- self.chrKeyLabel.setFont(bFont)
859
- self.pltKeyLabel.setFont(bFont)
860
- self.timKeyLabel.setFont(bFont)
861
- self.wldKeyLabel.setFont(bFont)
862
- self.objKeyLabel.setFont(bFont)
863
- self.entKeyLabel.setFont(bFont)
864
- self.cstKeyLabel.setFont(bFont)
865
-
866
- self.povKeyLWrap = QHBoxLayout()
867
- self.focKeyLWrap = QHBoxLayout()
868
- self.chrKeyLWrap = QHBoxLayout()
869
- self.pltKeyLWrap = QHBoxLayout()
870
- self.timKeyLWrap = QHBoxLayout()
871
- self.wldKeyLWrap = QHBoxLayout()
872
- self.objKeyLWrap = QHBoxLayout()
873
- self.entKeyLWrap = QHBoxLayout()
874
- self.cstKeyLWrap = QHBoxLayout()
875
-
876
- self.povKeyValue = QLabel("", self)
877
- self.focKeyValue = QLabel("", self)
878
- self.chrKeyValue = QLabel("", self)
879
- self.pltKeyValue = QLabel("", self)
880
- self.timKeyValue = QLabel("", self)
881
- self.wldKeyValue = QLabel("", self)
882
- self.objKeyValue = QLabel("", self)
883
- self.entKeyValue = QLabel("", self)
884
- self.cstKeyValue = QLabel("", self)
885
-
886
- self.povKeyValue.setWordWrap(True)
887
- self.focKeyValue.setWordWrap(True)
888
- self.chrKeyValue.setWordWrap(True)
889
- self.pltKeyValue.setWordWrap(True)
890
- self.timKeyValue.setWordWrap(True)
891
- self.wldKeyValue.setWordWrap(True)
892
- self.objKeyValue.setWordWrap(True)
893
- self.entKeyValue.setWordWrap(True)
894
- self.cstKeyValue.setWordWrap(True)
895
-
896
- self.povKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
897
- self.focKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
898
- self.chrKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
899
- self.pltKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
900
- self.timKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
901
- self.wldKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
902
- self.objKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
903
- self.entKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
904
- self.cstKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
905
-
906
- self.povKeyLWrap.addWidget(self.povKeyValue, 1)
907
- self.focKeyLWrap.addWidget(self.focKeyValue, 1)
908
- self.chrKeyLWrap.addWidget(self.chrKeyValue, 1)
909
- self.pltKeyLWrap.addWidget(self.pltKeyValue, 1)
910
- self.timKeyLWrap.addWidget(self.timKeyValue, 1)
911
- self.wldKeyLWrap.addWidget(self.wldKeyValue, 1)
912
- self.objKeyLWrap.addWidget(self.objKeyValue, 1)
913
- self.entKeyLWrap.addWidget(self.entKeyValue, 1)
914
- self.cstKeyLWrap.addWidget(self.cstKeyValue, 1)
915
-
916
873
  # Selected Item Details
917
- self.mainGroup = QGroupBox(self.tr("Title Details"), self)
918
874
  self.mainForm = QGridLayout()
875
+ self.mainGroup = QGroupBox(self.tr("Title Details"), self)
919
876
  self.mainGroup.setLayout(self.mainForm)
920
877
 
921
- self.mainForm.addWidget(self.titleLabel, 0, 0, 1, 1, QtAlignLeftTop)
922
- self.mainForm.addWidget(self.titleValue, 0, 1, 1, 1, QtAlignLeftTop)
923
- self.mainForm.addWidget(self.cCLabel, 0, 2, 1, 1, QtAlignLeftTop)
924
- self.mainForm.addWidget(self.cCValue, 0, 3, 1, 1, QtAlignRightTop)
925
- self.mainForm.addWidget(self.fileLabel, 1, 0, 1, 1, QtAlignLeftTop)
926
- self.mainForm.addWidget(self.fileValue, 1, 1, 1, 1, QtAlignLeftTop)
927
- self.mainForm.addWidget(self.wCLabel, 1, 2, 1, 1, QtAlignLeftTop)
928
- self.mainForm.addWidget(self.wCValue, 1, 3, 1, 1, QtAlignRightTop)
929
- self.mainForm.addWidget(self.itemLabel, 2, 0, 1, 1, QtAlignLeftTop)
930
- self.mainForm.addWidget(self.itemValue, 2, 1, 1, 1, QtAlignLeftTop)
931
- self.mainForm.addWidget(self.pCLabel, 2, 2, 1, 1, QtAlignLeftTop)
932
- self.mainForm.addWidget(self.pCValue, 2, 3, 1, 1, QtAlignRightTop)
933
- self.mainForm.addWidget(self.synopLabel, 3, 0, 1, 4, QtAlignLeftTop)
934
- self.mainForm.addLayout(self.synopLWrap, 4, 0, 1, 4, QtAlignLeftTop)
878
+ self.mainForm.addWidget(self.titleLabel, 0, 0, 1, 1, QtAlignLeftTop)
879
+ self.mainForm.addWidget(self.titleValue, 0, 1, 1, 1, QtAlignLeftTop)
880
+ self.mainForm.addWidget(self.cCLabel, 0, 2, 1, 1, QtAlignLeftTop)
881
+ self.mainForm.addWidget(self.cCValue, 0, 3, 1, 1, QtAlignRightTop)
882
+ self.mainForm.addWidget(self.fileLabel, 1, 0, 1, 1, QtAlignLeftTop)
883
+ self.mainForm.addWidget(self.fileValue, 1, 1, 1, 1, QtAlignLeftTop)
884
+ self.mainForm.addWidget(self.wCLabel, 1, 2, 1, 1, QtAlignLeftTop)
885
+ self.mainForm.addWidget(self.wCValue, 1, 3, 1, 1, QtAlignRightTop)
886
+ self.mainForm.addWidget(self.itemLabel, 2, 0, 1, 1, QtAlignLeftTop)
887
+ self.mainForm.addWidget(self.itemValue, 2, 1, 1, 1, QtAlignLeftTop)
888
+ self.mainForm.addWidget(self.pCLabel, 2, 2, 1, 1, QtAlignLeftTop)
889
+ self.mainForm.addWidget(self.pCValue, 2, 3, 1, 1, QtAlignRightTop)
890
+ self.mainForm.addWidget(self.synopLabel, 3, 0, 1, 4, QtAlignLeftTop)
891
+ self.mainForm.addLayout(self.synopLWrap, 4, 0, 1, 4, QtAlignLeftTop)
935
892
 
936
893
  self.mainForm.setColumnStretch(1, 1)
937
894
  self.mainForm.setRowStretch(4, 1)
@@ -939,45 +896,40 @@ class GuiOutlineDetails(QScrollArea):
939
896
  self.mainForm.setVerticalSpacing(vSpace)
940
897
 
941
898
  # Selected Item Tags
942
- self.tagsGroup = QGroupBox(self.tr("Reference Tags"), self)
943
899
  self.tagsForm = QGridLayout()
900
+ self.tagsGroup = QGroupBox(self.tr("Reference Tags"), self)
944
901
  self.tagsGroup.setLayout(self.tagsForm)
945
902
 
946
- self.tagsForm.addWidget(self.povKeyLabel, 0, 0, 1, 1, QtAlignLeftTop)
947
- self.tagsForm.addLayout(self.povKeyLWrap, 0, 1, 1, 1, QtAlignLeftTop)
948
- self.tagsForm.addWidget(self.focKeyLabel, 1, 0, 1, 1, QtAlignLeftTop)
949
- self.tagsForm.addLayout(self.focKeyLWrap, 1, 1, 1, 1, QtAlignLeftTop)
950
- self.tagsForm.addWidget(self.chrKeyLabel, 2, 0, 1, 1, QtAlignLeftTop)
951
- self.tagsForm.addLayout(self.chrKeyLWrap, 2, 1, 1, 1, QtAlignLeftTop)
952
- self.tagsForm.addWidget(self.pltKeyLabel, 3, 0, 1, 1, QtAlignLeftTop)
953
- self.tagsForm.addLayout(self.pltKeyLWrap, 3, 1, 1, 1, QtAlignLeftTop)
954
- self.tagsForm.addWidget(self.timKeyLabel, 4, 0, 1, 1, QtAlignLeftTop)
955
- self.tagsForm.addLayout(self.timKeyLWrap, 4, 1, 1, 1, QtAlignLeftTop)
956
- self.tagsForm.addWidget(self.wldKeyLabel, 5, 0, 1, 1, QtAlignLeftTop)
957
- self.tagsForm.addLayout(self.wldKeyLWrap, 5, 1, 1, 1, QtAlignLeftTop)
958
- self.tagsForm.addWidget(self.objKeyLabel, 6, 0, 1, 1, QtAlignLeftTop)
959
- self.tagsForm.addLayout(self.objKeyLWrap, 6, 1, 1, 1, QtAlignLeftTop)
960
- self.tagsForm.addWidget(self.entKeyLabel, 7, 0, 1, 1, QtAlignLeftTop)
961
- self.tagsForm.addLayout(self.entKeyLWrap, 7, 1, 1, 1, QtAlignLeftTop)
962
- self.tagsForm.addWidget(self.cstKeyLabel, 8, 0, 1, 1, QtAlignLeftTop)
963
- self.tagsForm.addLayout(self.cstKeyLWrap, 8, 1, 1, 1, QtAlignLeftTop)
903
+ self.tagValues: dict[str, tuple[QLabel, QLabel]] = {}
904
+ for key in nwKeyWords.ALL_KEYS:
905
+ label = QLabel(trConst(nwLabels.KEY_NAME[key]), self)
906
+ label.setFont(bFont)
907
+ value = QLabel("", self)
908
+ value.setWordWrap(True)
909
+ value.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
910
+ layout = QHBoxLayout()
911
+ layout.addWidget(value, 1)
912
+ n = len(self.tagValues)
913
+ self.tagsForm.addWidget(label, n, 0, QtAlignLeftTop)
914
+ self.tagsForm.addLayout(layout, n, 1, QtAlignLeftTop)
915
+ self.tagValues[key] = (label, value)
964
916
 
965
917
  self.tagsForm.setColumnStretch(1, 1)
966
- self.tagsForm.setRowStretch(8, 1)
918
+ self.tagsForm.setRowStretch(len(self.tagValues), 1)
967
919
  self.tagsForm.setHorizontalSpacing(hSpace)
968
920
  self.tagsForm.setVerticalSpacing(vSpace)
969
921
 
970
922
  # Assemble
971
- self.outerWidget = QWidget(self)
972
- self.outerBox = QHBoxLayout()
973
- self.outerBox.addWidget(self.mainGroup, 0)
974
- self.outerBox.addWidget(self.tagsGroup, 1)
923
+ self.mainSplit = QSplitter(Qt.Orientation.Horizontal)
924
+ self.mainSplit.addWidget(self.mainGroup)
925
+ self.mainSplit.addWidget(self.tagsGroup)
926
+ self.mainSplit.setCollapsible(0, False)
927
+ self.mainSplit.setCollapsible(1, False)
975
928
 
976
- self.outerWidget.setLayout(self.outerBox)
977
- self.setWidget(self.outerWidget)
929
+ self.setWidget(self.mainSplit)
978
930
 
979
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
980
- self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
931
+ self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
932
+ self.setVerticalScrollBarPolicy(QtScrollAsNeeded)
981
933
  self.setWidgetResizable(True)
982
934
  self.setFrameStyle(QFrame.Shape.NoFrame)
983
935
 
@@ -990,35 +942,53 @@ class GuiOutlineDetails(QScrollArea):
990
942
  def initSettings(self) -> None:
991
943
  """Set or update outline settings."""
992
944
  if CONFIG.hideVScroll:
993
- self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
945
+ self.setVerticalScrollBarPolicy(QtScrollAlwaysOff)
994
946
  else:
995
- self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
947
+ self.setVerticalScrollBarPolicy(QtScrollAsNeeded)
996
948
  if CONFIG.hideHScroll:
997
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
949
+ self.setHorizontalScrollBarPolicy(QtScrollAlwaysOff)
998
950
  else:
999
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
951
+ self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
1000
952
  self.updateClasses()
1001
953
  return
1002
954
 
955
+ def loadGuiSettings(self) -> None:
956
+ """Run open project tasks."""
957
+ parent = self.outlineView.parent() # This widget is rendered already
958
+ width = parent.width() if isinstance(parent, QWidget) else 1000
959
+ pOptions = SHARED.project.options
960
+ self.mainSplit.setSizes([
961
+ CONFIG.pxInt(pOptions.getInt("GuiOutlineDetails", "detailsWidth", width//3)),
962
+ CONFIG.pxInt(pOptions.getInt("GuiOutlineDetails", "tagsWidth", 2*width//3))
963
+ ])
964
+ return
965
+
966
+ def saveGuiSettings(self) -> None:
967
+ """Run close project tasks."""
968
+ mainSplit = self.mainSplit.sizes()
969
+ detailsWidth = CONFIG.rpxInt(mainSplit[0])
970
+ tagsWidth = CONFIG.rpxInt(mainSplit[1])
971
+
972
+ logger.debug("Saving State: GuiOutlineDetails")
973
+ pOptions = SHARED.project.options
974
+ pOptions.setValue("GuiOutlineDetails", "detailsWidth", detailsWidth)
975
+ pOptions.setValue("GuiOutlineDetails", "tagsWidth", tagsWidth)
976
+ return
977
+
1003
978
  def clearDetails(self) -> None:
1004
979
  """Clear all the data labels."""
1005
980
  self.titleLabel.setText(self.tr("Title"))
1006
- self.titleValue.setText("")
1007
- self.fileValue.setText("")
1008
- self.itemValue.setText("")
1009
- self.cCValue.setText("")
1010
- self.wCValue.setText("")
1011
- self.pCValue.setText("")
1012
- self.synopValue.setText("")
1013
- self.povKeyValue.setText("")
1014
- self.focKeyValue.setText("")
1015
- self.chrKeyValue.setText("")
1016
- self.pltKeyValue.setText("")
1017
- self.timKeyValue.setText("")
1018
- self.wldKeyValue.setText("")
1019
- self.objKeyValue.setText("")
1020
- self.entKeyValue.setText("")
1021
- self.cstKeyValue.setText("")
981
+ self.titleValue.clear()
982
+ self.fileValue.clear()
983
+ self.itemValue.clear()
984
+ self.cCValue.clear()
985
+ self.wCValue.clear()
986
+ self.pCValue.clear()
987
+ self.synopValue.clear()
988
+
989
+ for _, value in self.tagValues.values():
990
+ value.clear()
991
+
1022
992
  self.updateClasses()
1023
993
  return
1024
994
 
@@ -1050,15 +1020,8 @@ class GuiOutlineDetails(QScrollArea):
1050
1020
 
1051
1021
  self.synopValue.setText(novIdx.synopsis)
1052
1022
 
1053
- self.povKeyValue.setText(self._formatTags(novRefs, nwKeyWords.POV_KEY))
1054
- self.focKeyValue.setText(self._formatTags(novRefs, nwKeyWords.FOCUS_KEY))
1055
- self.chrKeyValue.setText(self._formatTags(novRefs, nwKeyWords.CHAR_KEY))
1056
- self.pltKeyValue.setText(self._formatTags(novRefs, nwKeyWords.PLOT_KEY))
1057
- self.timKeyValue.setText(self._formatTags(novRefs, nwKeyWords.TIME_KEY))
1058
- self.wldKeyValue.setText(self._formatTags(novRefs, nwKeyWords.WORLD_KEY))
1059
- self.objKeyValue.setText(self._formatTags(novRefs, nwKeyWords.OBJECT_KEY))
1060
- self.entKeyValue.setText(self._formatTags(novRefs, nwKeyWords.ENTITY_KEY))
1061
- self.cstKeyValue.setText(self._formatTags(novRefs, nwKeyWords.CUSTOM_KEY))
1023
+ for key, (_, value) in self.tagValues.items():
1024
+ value.setText(self._formatTags(novRefs, key))
1062
1025
 
1063
1026
  return
1064
1027
 
@@ -1066,27 +1029,12 @@ class GuiOutlineDetails(QScrollArea):
1066
1029
  def updateClasses(self) -> None:
1067
1030
  """Update the visibility status of class details."""
1068
1031
  usedClasses = SHARED.project.tree.rootClasses()
1069
-
1070
- pltVisible = nwItemClass.PLOT in usedClasses
1071
- timVisible = nwItemClass.TIMELINE in usedClasses
1072
- wldVisible = nwItemClass.WORLD in usedClasses
1073
- objVisible = nwItemClass.OBJECT in usedClasses
1074
- entVisible = nwItemClass.ENTITY in usedClasses
1075
- cstVisible = nwItemClass.CUSTOM in usedClasses
1076
-
1077
- self.pltKeyLabel.setVisible(pltVisible)
1078
- self.pltKeyValue.setVisible(pltVisible)
1079
- self.timKeyLabel.setVisible(timVisible)
1080
- self.timKeyValue.setVisible(timVisible)
1081
- self.wldKeyLabel.setVisible(wldVisible)
1082
- self.wldKeyValue.setVisible(wldVisible)
1083
- self.objKeyLabel.setVisible(objVisible)
1084
- self.objKeyValue.setVisible(objVisible)
1085
- self.entKeyLabel.setVisible(entVisible)
1086
- self.entKeyValue.setVisible(entVisible)
1087
- self.cstKeyLabel.setVisible(cstVisible)
1088
- self.cstKeyValue.setVisible(cstVisible)
1089
-
1032
+ for key, itemClass in nwKeyWords.KEY_CLASS.items():
1033
+ visible = itemClass in usedClasses
1034
+ if key in self.tagValues:
1035
+ label, value = self.tagValues[key]
1036
+ label.setVisible(visible)
1037
+ value.setVisible(visible)
1090
1038
  return
1091
1039
 
1092
1040
  @staticmethod