novelWriter 2.3.1__py3-none-any.whl → 2.4b1__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 (81) hide show
  1. {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/METADATA +1 -1
  2. {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/RECORD +81 -70
  3. novelwriter/__init__.py +5 -5
  4. novelwriter/assets/icons/typicons_dark/icons.conf +4 -0
  5. novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +7 -0
  6. novelwriter/assets/icons/typicons_dark/typ_arrow-down.svg +4 -0
  7. novelwriter/assets/icons/typicons_dark/typ_arrow-right.svg +4 -0
  8. novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +1 -1
  9. novelwriter/assets/icons/typicons_dark/typ_refresh.svg +1 -1
  10. novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +4 -0
  11. novelwriter/assets/icons/typicons_dark/typ_times.svg +1 -1
  12. novelwriter/assets/icons/typicons_light/icons.conf +4 -0
  13. novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +7 -0
  14. novelwriter/assets/icons/typicons_light/typ_arrow-down.svg +4 -0
  15. novelwriter/assets/icons/typicons_light/typ_arrow-right.svg +4 -0
  16. novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +1 -1
  17. novelwriter/assets/icons/typicons_light/typ_refresh.svg +1 -1
  18. novelwriter/assets/icons/typicons_light/typ_search-grey.svg +4 -0
  19. novelwriter/assets/icons/typicons_light/typ_times.svg +1 -1
  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 +25 -23
  36. novelwriter/common.py +1 -1
  37. novelwriter/config.py +35 -12
  38. novelwriter/constants.py +5 -6
  39. novelwriter/core/buildsettings.py +60 -40
  40. novelwriter/core/coretools.py +98 -13
  41. novelwriter/core/docbuild.py +74 -7
  42. novelwriter/core/document.py +24 -3
  43. novelwriter/core/index.py +31 -112
  44. novelwriter/core/project.py +10 -15
  45. novelwriter/core/sessions.py +2 -2
  46. novelwriter/core/status.py +4 -4
  47. novelwriter/core/storage.py +8 -2
  48. novelwriter/core/tohtml.py +22 -25
  49. novelwriter/core/tokenizer.py +416 -232
  50. novelwriter/core/tomd.py +17 -8
  51. novelwriter/core/toodt.py +65 -7
  52. novelwriter/core/tree.py +8 -8
  53. novelwriter/dialogs/docsplit.py +7 -8
  54. novelwriter/dialogs/preferences.py +3 -6
  55. novelwriter/enum.py +17 -14
  56. novelwriter/extensions/modified.py +20 -2
  57. novelwriter/extensions/versioninfo.py +1 -1
  58. novelwriter/gui/doceditor.py +257 -279
  59. novelwriter/gui/dochighlight.py +29 -25
  60. novelwriter/gui/docviewer.py +139 -148
  61. novelwriter/gui/docviewerpanel.py +4 -24
  62. novelwriter/gui/editordocument.py +12 -1
  63. novelwriter/gui/itemdetails.py +6 -6
  64. novelwriter/gui/mainmenu.py +37 -16
  65. novelwriter/gui/noveltree.py +11 -19
  66. novelwriter/gui/outline.py +43 -20
  67. novelwriter/gui/projtree.py +35 -43
  68. novelwriter/gui/search.py +316 -0
  69. novelwriter/gui/sidebar.py +25 -30
  70. novelwriter/gui/theme.py +59 -6
  71. novelwriter/guimain.py +176 -173
  72. novelwriter/shared.py +26 -1
  73. novelwriter/text/__init__.py +3 -0
  74. novelwriter/text/counting.py +137 -0
  75. novelwriter/tools/manuscript.py +344 -55
  76. novelwriter/tools/manussettings.py +213 -71
  77. novelwriter/tools/welcome.py +1 -1
  78. {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/LICENSE.md +0 -0
  79. {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/WHEEL +0 -0
  80. {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/entry_points.txt +0 -0
  81. {novelWriter-2.3.1.dist-info → novelWriter-2.4b1.dist-info}/top_level.txt +0 -0
@@ -37,7 +37,7 @@ from PyQt5.QtWidgets import (
37
37
  )
38
38
 
39
39
  from novelwriter import CONFIG, SHARED
40
- from novelwriter.constants import nwHeadFmt, nwLabels, trConst
40
+ from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, trConst
41
41
  from novelwriter.core.buildsettings import BuildSettings, FilterMode
42
42
  from novelwriter.extensions.switch import NSwitch
43
43
  from novelwriter.extensions.modified import NComboBox, NDoubleSpinBox, NSpinBox
@@ -584,7 +584,8 @@ class _HeadingsTab(NScrollablePage):
584
584
  EDIT_CHAPTER = 2
585
585
  EDIT_UNNUM = 3
586
586
  EDIT_SCENE = 4
587
- EDIT_SECTION = 5
587
+ EDIT_HSCENE = 5
588
+ EDIT_SECTION = 6
588
589
 
589
590
  def __init__(self, buildMain: GuiBuildSettings, build: BuildSettings) -> None:
590
591
  super().__init__(parent=buildMain)
@@ -593,122 +594,123 @@ class _HeadingsTab(NScrollablePage):
593
594
  self._editing = 0
594
595
 
595
596
  iPx = SHARED.theme.baseIconSize
597
+ sSp = CONFIG.pxInt(16)
596
598
  vSp = CONFIG.pxInt(12)
597
599
  bSp = CONFIG.pxInt(6)
598
600
 
599
601
  # Format Boxes
600
602
  # ============
601
603
  self.formatBox = QGridLayout()
602
- self.formatBox.setHorizontalSpacing(vSp)
604
+ self.formatBox.setHorizontalSpacing(bSp)
603
605
 
604
606
  # Title Heading
605
- self.lblTitle = QLabel(self._build.getLabel("headings.fmtTitle"))
607
+ self.lblTitle = QLabel(self._build.getLabel("headings.fmtTitle"), self)
606
608
  self.fmtTitle = QLineEdit("", self)
607
609
  self.fmtTitle.setReadOnly(True)
608
610
  self.btnTitle = QToolButton(self)
609
611
  self.btnTitle.setIcon(SHARED.theme.getIcon("edit"))
610
612
  self.btnTitle.clicked.connect(lambda: self._editHeading(self.EDIT_TITLE))
613
+ self.hdeTitle = QLabel(self.tr("Hide"), self)
614
+ self.hdeTitle.setIndent(bSp)
615
+ self.swtTitle = NSwitch(self, height=iPx)
611
616
 
612
- wrapTitle = QHBoxLayout()
613
- wrapTitle.addWidget(self.fmtTitle)
614
- wrapTitle.addWidget(self.btnTitle)
615
- wrapTitle.setSpacing(bSp)
616
-
617
- self.formatBox.addWidget(self.lblTitle, 0, 0, Qt.AlignLeft)
618
- self.formatBox.addLayout(wrapTitle, 0, 1, Qt.AlignLeft)
617
+ self.formatBox.addWidget(self.lblTitle, 0, 0)
618
+ self.formatBox.addWidget(self.fmtTitle, 0, 1)
619
+ self.formatBox.addWidget(self.btnTitle, 0, 2)
620
+ self.formatBox.addWidget(self.hdeTitle, 0, 3)
621
+ self.formatBox.addWidget(self.swtTitle, 0, 4)
619
622
 
620
623
  # Chapter Heading
621
- self.lblChapter = QLabel(self._build.getLabel("headings.fmtChapter"))
624
+ self.lblChapter = QLabel(self._build.getLabel("headings.fmtChapter"), self)
622
625
  self.fmtChapter = QLineEdit("", self)
623
626
  self.fmtChapter.setReadOnly(True)
624
627
  self.btnChapter = QToolButton(self)
625
628
  self.btnChapter.setIcon(SHARED.theme.getIcon("edit"))
626
629
  self.btnChapter.clicked.connect(lambda: self._editHeading(self.EDIT_CHAPTER))
630
+ self.hdeChapter = QLabel(self.tr("Hide"), self)
631
+ self.hdeChapter.setIndent(bSp)
632
+ self.swtChapter = NSwitch(self, height=iPx)
627
633
 
628
- wrapChapter = QHBoxLayout()
629
- wrapChapter.addWidget(self.fmtChapter)
630
- wrapChapter.addWidget(self.btnChapter)
631
- wrapChapter.setSpacing(bSp)
632
-
633
- self.formatBox.addWidget(self.lblChapter, 1, 0, Qt.AlignLeft)
634
- self.formatBox.addLayout(wrapChapter, 1, 1, Qt.AlignLeft)
634
+ self.formatBox.addWidget(self.lblChapter, 1, 0)
635
+ self.formatBox.addWidget(self.fmtChapter, 1, 1)
636
+ self.formatBox.addWidget(self.btnChapter, 1, 2)
637
+ self.formatBox.addWidget(self.hdeChapter, 1, 3)
638
+ self.formatBox.addWidget(self.swtChapter, 1, 4)
635
639
 
636
640
  # Unnumbered Chapter Heading
637
- self.lblUnnumbered = QLabel(self._build.getLabel("headings.fmtUnnumbered"))
641
+ self.lblUnnumbered = QLabel(self._build.getLabel("headings.fmtUnnumbered"), self)
638
642
  self.fmtUnnumbered = QLineEdit("", self)
639
643
  self.fmtUnnumbered.setReadOnly(True)
640
644
  self.btnUnnumbered = QToolButton(self)
641
645
  self.btnUnnumbered.setIcon(SHARED.theme.getIcon("edit"))
642
646
  self.btnUnnumbered.clicked.connect(lambda: self._editHeading(self.EDIT_UNNUM))
647
+ self.hdeUnnumbered = QLabel(self.tr("Hide"), self)
648
+ self.hdeUnnumbered.setIndent(bSp)
649
+ self.swtUnnumbered = NSwitch(self, height=iPx)
643
650
 
644
- wrapUnnumbered = QHBoxLayout()
645
- wrapUnnumbered.addWidget(self.fmtUnnumbered)
646
- wrapUnnumbered.addWidget(self.btnUnnumbered)
647
- wrapUnnumbered.setSpacing(bSp)
648
-
649
- self.formatBox.addWidget(self.lblUnnumbered, 2, 0, Qt.AlignLeft)
650
- self.formatBox.addLayout(wrapUnnumbered, 2, 1, Qt.AlignLeft)
651
+ self.formatBox.addWidget(self.lblUnnumbered, 2, 0)
652
+ self.formatBox.addWidget(self.fmtUnnumbered, 2, 1)
653
+ self.formatBox.addWidget(self.btnUnnumbered, 2, 2)
654
+ self.formatBox.addWidget(self.hdeUnnumbered, 2, 3)
655
+ self.formatBox.addWidget(self.swtUnnumbered, 2, 4)
651
656
 
652
657
  # Scene Heading
653
- sceneHideTip = self._build.getLabel("headings.hideScene")
654
- self.lblScene = QLabel(self._build.getLabel("headings.fmtScene"))
658
+ self.lblScene = QLabel(self._build.getLabel("headings.fmtScene"), self)
655
659
  self.fmtScene = QLineEdit("", self)
656
660
  self.fmtScene.setReadOnly(True)
657
661
  self.btnScene = QToolButton(self)
658
662
  self.btnScene.setIcon(SHARED.theme.getIcon("edit"))
659
663
  self.btnScene.clicked.connect(lambda: self._editHeading(self.EDIT_SCENE))
660
- self.hdeScene = QLabel(self.tr("Hide"))
661
- self.hdeScene.setToolTip(sceneHideTip)
664
+ self.hdeScene = QLabel(self.tr("Hide"), self)
665
+ self.hdeScene.setIndent(bSp)
662
666
  self.swtScene = NSwitch(self, height=iPx)
663
- self.swtScene.setToolTip(sceneHideTip)
664
-
665
- wrapScene = QHBoxLayout()
666
- wrapScene.addWidget(self.fmtScene)
667
- wrapScene.addWidget(self.btnScene)
668
- wrapScene.setSpacing(bSp)
669
-
670
- wrapSceneHide = QHBoxLayout()
671
- wrapSceneHide.addWidget(self.hdeScene)
672
- wrapSceneHide.addWidget(self.swtScene)
673
- wrapSceneHide.setSpacing(bSp)
674
667
 
675
- self.formatBox.addWidget(self.lblScene, 3, 0, Qt.AlignLeft)
676
- self.formatBox.addLayout(wrapScene, 3, 1, Qt.AlignLeft)
677
- self.formatBox.addLayout(wrapSceneHide, 3, 2, Qt.AlignLeft)
668
+ self.formatBox.addWidget(self.lblScene, 3, 0)
669
+ self.formatBox.addWidget(self.fmtScene, 3, 1)
670
+ self.formatBox.addWidget(self.btnScene, 3, 2)
671
+ self.formatBox.addWidget(self.hdeScene, 3, 3)
672
+ self.formatBox.addWidget(self.swtScene, 3, 4)
673
+
674
+ # Alt Scene Heading
675
+ self.lblHScene = QLabel(self._build.getLabel("headings.fmtHardScene"), self)
676
+ self.fmtHScene = QLineEdit("", self)
677
+ self.fmtHScene.setReadOnly(True)
678
+ self.btnHScene = QToolButton(self)
679
+ self.btnHScene.setIcon(SHARED.theme.getIcon("edit"))
680
+ self.btnHScene.clicked.connect(lambda: self._editHeading(self.EDIT_HSCENE))
681
+ self.hdeHScene = QLabel(self.tr("Hide"), self)
682
+ self.hdeHScene.setIndent(bSp)
683
+ self.swtHScene = NSwitch(self, height=iPx)
684
+
685
+ self.formatBox.addWidget(self.lblHScene, 4, 0)
686
+ self.formatBox.addWidget(self.fmtHScene, 4, 1)
687
+ self.formatBox.addWidget(self.btnHScene, 4, 2)
688
+ self.formatBox.addWidget(self.hdeHScene, 4, 3)
689
+ self.formatBox.addWidget(self.swtHScene, 4, 4)
678
690
 
679
691
  # Section Heading
680
- sectionHideTip = self._build.getLabel("headings.hideSection")
681
- self.lblSection = QLabel(self._build.getLabel("headings.fmtSection"))
692
+ self.lblSection = QLabel(self._build.getLabel("headings.fmtSection"), self)
682
693
  self.fmtSection = QLineEdit("", self)
683
694
  self.fmtSection.setReadOnly(True)
684
695
  self.btnSection = QToolButton(self)
685
696
  self.btnSection.setIcon(SHARED.theme.getIcon("edit"))
686
697
  self.btnSection.clicked.connect(lambda: self._editHeading(self.EDIT_SECTION))
687
- self.hdeSection = QLabel(self.tr("Hide"))
688
- self.hdeSection.setToolTip(sectionHideTip)
698
+ self.hdeSection = QLabel(self.tr("Hide"), self)
699
+ self.hdeSection.setIndent(bSp)
689
700
  self.swtSection = NSwitch(self, height=iPx)
690
- self.swtSection.setToolTip(sectionHideTip)
691
701
 
692
- wrapSection = QHBoxLayout()
693
- wrapSection.addWidget(self.fmtSection)
694
- wrapSection.addWidget(self.btnSection)
695
- wrapSection.setSpacing(bSp)
696
-
697
- wrapSectionHide = QHBoxLayout()
698
- wrapSectionHide.addWidget(self.hdeSection)
699
- wrapSectionHide.addWidget(self.swtSection)
700
- wrapSectionHide.setSpacing(bSp)
701
-
702
- self.formatBox.addWidget(self.lblSection, 4, 0, Qt.AlignLeft)
703
- self.formatBox.addLayout(wrapSection, 4, 1, Qt.AlignLeft)
704
- self.formatBox.addLayout(wrapSectionHide, 4, 2, Qt.AlignLeft)
702
+ self.formatBox.addWidget(self.lblSection, 5, 0)
703
+ self.formatBox.addWidget(self.fmtSection, 5, 1)
704
+ self.formatBox.addWidget(self.btnSection, 5, 2)
705
+ self.formatBox.addWidget(self.hdeSection, 5, 3)
706
+ self.formatBox.addWidget(self.swtSection, 5, 4)
705
707
 
706
708
  # Edit Form
707
709
  # =========
708
710
 
709
711
  self.lblEditForm = QLabel(self.tr("Editing: {0}").format(self.tr("None")))
710
712
 
711
- self.editTextBox = QPlainTextEdit()
713
+ self.editTextBox = QPlainTextEdit(self)
712
714
  self.editTextBox.setFixedHeight(5*iPx)
713
715
  self.editTextBox.setEnabled(False)
714
716
 
@@ -735,10 +737,10 @@ class _HeadingsTab(NScrollablePage):
735
737
  self.aInsCharPOV.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CHAR_POV))
736
738
  self.aInsCharFocus.triggered.connect(lambda: self._insertIntoForm(nwHeadFmt.CHAR_FOCUS))
737
739
 
738
- self.btnInsert = QPushButton(self.tr("Insert"))
740
+ self.btnInsert = QPushButton(self.tr("Insert"), self)
739
741
  self.btnInsert.setMenu(self.menuInsert)
740
742
 
741
- self.btnApply = QPushButton(self.tr("Apply"))
743
+ self.btnApply = QPushButton(self.tr("Apply"), self)
742
744
  self.btnApply.clicked.connect(self._saveFormat)
743
745
 
744
746
  self.formButtonBox = QHBoxLayout()
@@ -751,13 +753,72 @@ class _HeadingsTab(NScrollablePage):
751
753
  self.editFormBox.addWidget(self.editTextBox)
752
754
  self.editFormBox.addLayout(self.formButtonBox)
753
755
 
756
+ # Layout Matrix
757
+ # =============
758
+ self.layoutMatrix = QGridLayout()
759
+ self.layoutMatrix.setVerticalSpacing(vSp)
760
+ self.layoutMatrix.setHorizontalSpacing(vSp)
761
+
762
+ # Heading
763
+ self.layoutHeading = QLabel("<b>{0}</b>".format(self.tr("Additional Styling")), self)
764
+ self.layoutMatrix.addWidget(self.layoutHeading, 0, 0, 1, 5)
765
+
766
+ # Title Layout
767
+ self.mtxTitle = QLabel(self._build.getLabel("headings.fmtTitle"))
768
+ self.centerTitle = NSwitch(self, height=iPx)
769
+ self.breakTitle = NSwitch(self, height=iPx)
770
+ lblCenterT = QLabel(self.tr("Centre"))
771
+ lblCenterT.setIndent(sSp)
772
+ lblBreakT = QLabel(self.tr("Page Break"))
773
+ lblBreakT.setIndent(sSp)
774
+
775
+ self.layoutMatrix.addWidget(self.mtxTitle, 1, 0)
776
+ self.layoutMatrix.addWidget(lblCenterT, 1, 1)
777
+ self.layoutMatrix.addWidget(self.centerTitle, 1, 2)
778
+ self.layoutMatrix.addWidget(lblBreakT, 1, 3)
779
+ self.layoutMatrix.addWidget(self.breakTitle, 1, 4)
780
+
781
+ # Chapter Layout
782
+ self.mtxChapter = QLabel(self._build.getLabel("headings.fmtChapter"))
783
+ self.centerChapter = NSwitch(self, height=iPx)
784
+ self.breakChapter = NSwitch(self, height=iPx)
785
+ lblCenterC = QLabel(self.tr("Centre"))
786
+ lblCenterC.setIndent(sSp)
787
+ lblBreakC = QLabel(self.tr("Page Break"))
788
+ lblBreakC.setIndent(sSp)
789
+
790
+ self.layoutMatrix.addWidget(self.mtxChapter, 2, 0)
791
+ self.layoutMatrix.addWidget(lblCenterC, 2, 1)
792
+ self.layoutMatrix.addWidget(self.centerChapter, 2, 2)
793
+ self.layoutMatrix.addWidget(lblBreakC, 2, 3)
794
+ self.layoutMatrix.addWidget(self.breakChapter, 2, 4)
795
+
796
+ # Scene Layout
797
+ self.mtxScene = QLabel(self._build.getLabel("headings.fmtScene"))
798
+ self.centerScene = NSwitch(self, height=iPx)
799
+ self.breakScene = NSwitch(self, height=iPx)
800
+ lblCenterS = QLabel(self.tr("Centre"))
801
+ lblCenterS.setIndent(sSp)
802
+ lblBreakS = QLabel(self.tr("Page Break"))
803
+ lblBreakS.setIndent(sSp)
804
+
805
+ self.layoutMatrix.addWidget(self.mtxScene, 3, 0)
806
+ self.layoutMatrix.addWidget(lblCenterS, 3, 1)
807
+ self.layoutMatrix.addWidget(self.centerScene, 3, 2)
808
+ self.layoutMatrix.addWidget(lblBreakS, 3, 3)
809
+ self.layoutMatrix.addWidget(self.breakScene, 3, 4)
810
+
811
+ self.layoutMatrix.setColumnStretch(5, 1)
812
+
754
813
  # Assemble
755
814
  # ========
756
815
 
757
816
  self.outerBox = QVBoxLayout()
758
817
  self.outerBox.addLayout(self.formatBox)
759
- self.outerBox.addSpacing(CONFIG.pxInt(16))
818
+ self.outerBox.addSpacing(sSp)
760
819
  self.outerBox.addLayout(self.editFormBox)
820
+ self.outerBox.addSpacing(sSp)
821
+ self.outerBox.addLayout(self.layoutMatrix)
761
822
  self.outerBox.addStretch(1)
762
823
 
763
824
  self.setCentralLayout(self.outerBox)
@@ -770,15 +831,39 @@ class _HeadingsTab(NScrollablePage):
770
831
  self.fmtChapter.setText(self._build.getStr("headings.fmtChapter"))
771
832
  self.fmtUnnumbered.setText(self._build.getStr("headings.fmtUnnumbered"))
772
833
  self.fmtScene.setText(self._build.getStr("headings.fmtScene"))
834
+ self.fmtHScene.setText(self._build.getStr("headings.fmtHardScene"))
773
835
  self.fmtSection.setText(self._build.getStr("headings.fmtSection"))
836
+
837
+ self.swtTitle.setChecked(self._build.getBool("headings.hideTitle"))
838
+ self.swtChapter.setChecked(self._build.getBool("headings.hideChapter"))
839
+ self.swtUnnumbered.setChecked(self._build.getBool("headings.hideUnnumbered"))
774
840
  self.swtScene.setChecked(self._build.getBool("headings.hideScene"))
841
+ self.swtHScene.setChecked(self._build.getBool("headings.hideHardScene"))
775
842
  self.swtSection.setChecked(self._build.getBool("headings.hideSection"))
843
+
844
+ self.centerTitle.setChecked(self._build.getBool("headings.centerTitle"))
845
+ self.centerChapter.setChecked(self._build.getBool("headings.centerChapter"))
846
+ self.centerScene.setChecked(self._build.getBool("headings.centerScene"))
847
+ self.breakTitle.setChecked(self._build.getBool("headings.breakTitle"))
848
+ self.breakChapter.setChecked(self._build.getBool("headings.breakChapter"))
849
+ self.breakScene.setChecked(self._build.getBool("headings.breakScene"))
776
850
  return
777
851
 
778
852
  def saveContent(self) -> None:
779
853
  """Save choices back into build object."""
854
+ self._build.setValue("headings.hideTitle", self.swtTitle.isChecked())
855
+ self._build.setValue("headings.hideChapter", self.swtChapter.isChecked())
856
+ self._build.setValue("headings.hideUnnumbered", self.swtUnnumbered.isChecked())
780
857
  self._build.setValue("headings.hideScene", self.swtScene.isChecked())
858
+ self._build.setValue("headings.hideHardScene", self.swtHScene.isChecked())
781
859
  self._build.setValue("headings.hideSection", self.swtSection.isChecked())
860
+
861
+ self._build.setValue("headings.centerTitle", self.centerTitle.isChecked())
862
+ self._build.setValue("headings.centerChapter", self.centerChapter.isChecked())
863
+ self._build.setValue("headings.centerScene", self.centerScene.isChecked())
864
+ self._build.setValue("headings.breakTitle", self.breakTitle.isChecked())
865
+ self._build.setValue("headings.breakChapter", self.breakChapter.isChecked())
866
+ self._build.setValue("headings.breakScene", self.breakScene.isChecked())
782
867
  return
783
868
 
784
869
  ##
@@ -809,6 +894,9 @@ class _HeadingsTab(NScrollablePage):
809
894
  elif heading == self.EDIT_SCENE:
810
895
  text = self.fmtScene.text()
811
896
  label = self._build.getLabel("headings.fmtScene")
897
+ elif heading == self.EDIT_HSCENE:
898
+ text = self.fmtHScene.text()
899
+ label = self._build.getLabel("headings.fmtHardScene")
812
900
  elif heading == self.EDIT_SECTION:
813
901
  text = self.fmtSection.text()
814
902
  label = self._build.getLabel("headings.fmtSection")
@@ -844,6 +932,9 @@ class _HeadingsTab(NScrollablePage):
844
932
  elif heading == self.EDIT_SCENE:
845
933
  self.fmtScene.setText(text)
846
934
  self._build.setValue("headings.fmtScene", text)
935
+ elif heading == self.EDIT_HSCENE:
936
+ self.fmtHScene.setText(text)
937
+ self._build.setValue("headings.fmtHardScene", text)
847
938
  elif heading == self.EDIT_SECTION:
848
939
  self.fmtSection.setText(text)
849
940
  self._build.setValue("headings.fmtSection", text)
@@ -894,16 +985,32 @@ class _ContentTab(NScrollableForm):
894
985
  iPx = SHARED.theme.baseIconSize
895
986
 
896
987
  # Text Content
988
+ self.incBodyText = NSwitch(self, height=iPx)
897
989
  self.incSynopsis = NSwitch(self, height=iPx)
898
990
  self.incComments = NSwitch(self, height=iPx)
899
991
  self.incKeywords = NSwitch(self, height=iPx)
900
- self.incBodyText = NSwitch(self, height=iPx)
992
+
993
+ self.ignoredKeywords = QLineEdit(self)
994
+
995
+ self.mnKeywords = QMenu(self)
996
+ for keyword in nwKeyWords.VALID_KEYS:
997
+ self.mnKeywords.addAction(
998
+ trConst(nwLabels.KEY_NAME[keyword]),
999
+ lambda keyword=keyword: self._updateIgnoredKeywords(keyword)
1000
+ )
1001
+
1002
+ self.ignoredKeywordsButton = QToolButton(self)
1003
+ self.ignoredKeywordsButton.setIcon(SHARED.theme.getIcon("add"))
1004
+ self.ignoredKeywordsButton.setMenu(self.mnKeywords)
1005
+ self.ignoredKeywordsButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
901
1006
 
902
1007
  self.addGroupLabel(self._build.getLabel("text.grpContent"))
1008
+ self.addRow(self._build.getLabel("text.includeBodyText"), self.incBodyText)
903
1009
  self.addRow(self._build.getLabel("text.includeSynopsis"), self.incSynopsis)
904
1010
  self.addRow(self._build.getLabel("text.includeComments"), self.incComments)
905
1011
  self.addRow(self._build.getLabel("text.includeKeywords"), self.incKeywords)
906
- self.addRow(self._build.getLabel("text.includeBodyText"), self.incBodyText)
1012
+ self.addRow(self._build.getLabel("text.ignoredKeywords"), self.ignoredKeywords,
1013
+ button=self.ignoredKeywordsButton, stretch=(1, 1))
907
1014
 
908
1015
  # Insert Content
909
1016
  self.addNoteHead = NSwitch(self, height=iPx)
@@ -918,22 +1025,39 @@ class _ContentTab(NScrollableForm):
918
1025
 
919
1026
  def loadContent(self) -> None:
920
1027
  """Populate the widgets."""
1028
+ self.incBodyText.setChecked(self._build.getBool("text.includeBodyText"))
921
1029
  self.incSynopsis.setChecked(self._build.getBool("text.includeSynopsis"))
922
1030
  self.incComments.setChecked(self._build.getBool("text.includeComments"))
923
1031
  self.incKeywords.setChecked(self._build.getBool("text.includeKeywords"))
924
- self.incBodyText.setChecked(self._build.getBool("text.includeBodyText"))
1032
+ self.ignoredKeywords.setText(self._build.getStr("text.ignoredKeywords"))
925
1033
  self.addNoteHead.setChecked(self._build.getBool("text.addNoteHeadings"))
1034
+ self._updateIgnoredKeywords()
926
1035
  return
927
1036
 
928
1037
  def saveContent(self) -> None:
929
1038
  """Save choices back into build object."""
1039
+ self._updateIgnoredKeywords()
1040
+ self._build.setValue("text.includeBodyText", self.incBodyText.isChecked())
930
1041
  self._build.setValue("text.includeSynopsis", self.incSynopsis.isChecked())
931
1042
  self._build.setValue("text.includeComments", self.incComments.isChecked())
932
1043
  self._build.setValue("text.includeKeywords", self.incKeywords.isChecked())
933
- self._build.setValue("text.includeBodyText", self.incBodyText.isChecked())
1044
+ self._build.setValue("text.ignoredKeywords", self.ignoredKeywords.text())
934
1045
  self._build.setValue("text.addNoteHeadings", self.addNoteHead.isChecked())
935
1046
  return
936
1047
 
1048
+ ##
1049
+ # Internal Functions
1050
+ ##
1051
+
1052
+ def _updateIgnoredKeywords(self, keyword: str | None = None) -> None:
1053
+ """Update the ignored keywords list."""
1054
+ current = [x.lower().strip() for x in self.ignoredKeywords.text().split(",")]
1055
+ if keyword:
1056
+ current.append(keyword)
1057
+ verified = set(x for x in current if x in nwKeyWords.VALID_KEYS)
1058
+ self.ignoredKeywords.setText(", ".join(verified))
1059
+ return
1060
+
937
1061
  # END Class _ContentTab
938
1062
 
939
1063
 
@@ -1239,12 +1363,24 @@ class _OutputTab(NScrollableForm):
1239
1363
  self.odtPageCountOffset.setMinimumWidth(spW)
1240
1364
  self.addRow(self._build.getLabel("odt.pageCountOffset"), self.odtPageCountOffset)
1241
1365
 
1366
+ self.odtFirstLineIndent = NSwitch(self, height=iPx)
1367
+ self.addRow(self._build.getLabel("odt.firstLineIndent"), self.odtFirstLineIndent)
1368
+
1242
1369
  # HTML Document
1243
1370
  self.addGroupLabel(self._build.getLabel("html"))
1244
1371
 
1245
1372
  self.htmlAddStyles = NSwitch(self, height=iPx)
1246
1373
  self.addRow(self._build.getLabel("html.addStyles"), self.htmlAddStyles)
1247
1374
 
1375
+ self.htmlPreserveTabs = NSwitch(self, height=iPx)
1376
+ self.addRow(self._build.getLabel("html.preserveTabs"), self.htmlPreserveTabs)
1377
+
1378
+ # Markdown Document
1379
+ self.addGroupLabel(self._build.getLabel("md"))
1380
+
1381
+ self.mdPreserveBreaks = NSwitch(self, height=iPx)
1382
+ self.addRow(self._build.getLabel("md.preserveBreaks"), self.mdPreserveBreaks)
1383
+
1248
1384
  # Finalise
1249
1385
  self.finalise()
1250
1386
 
@@ -1255,7 +1391,10 @@ class _OutputTab(NScrollableForm):
1255
1391
  self.odtAddColours.setChecked(self._build.getBool("odt.addColours"))
1256
1392
  self.odtPageHeader.setText(self._build.getStr("odt.pageHeader"))
1257
1393
  self.odtPageCountOffset.setValue(self._build.getInt("odt.pageCountOffset"))
1394
+ self.odtFirstLineIndent.setChecked(self._build.getBool("odt.firstLineIndent"))
1258
1395
  self.htmlAddStyles.setChecked(self._build.getBool("html.addStyles"))
1396
+ self.htmlPreserveTabs.setChecked(self._build.getBool("html.preserveTabs"))
1397
+ self.mdPreserveBreaks.setChecked(self._build.getBool("md.preserveBreaks"))
1259
1398
  return
1260
1399
 
1261
1400
  def saveContent(self) -> None:
@@ -1263,7 +1402,10 @@ class _OutputTab(NScrollableForm):
1263
1402
  self._build.setValue("odt.addColours", self.odtAddColours.isChecked())
1264
1403
  self._build.setValue("odt.pageHeader", self.odtPageHeader.text())
1265
1404
  self._build.setValue("odt.pageCountOffset", self.odtPageCountOffset.value())
1405
+ self._build.setValue("odt.firstLineIndent", self.odtFirstLineIndent.isChecked())
1266
1406
  self._build.setValue("html.addStyles", self.htmlAddStyles.isChecked())
1407
+ self._build.setValue("html.preserveTabs", self.htmlPreserveTabs.isChecked())
1408
+ self._build.setValue("md.preserveBreaks", self.mdPreserveBreaks.isChecked())
1267
1409
  return
1268
1410
 
1269
1411
  ##
@@ -456,7 +456,7 @@ class _ProjectListModel(QAbstractListModel):
456
456
  opened = self.tr("Last Opened")
457
457
  records = sorted(CONFIG.recentProjects.listEntries(), key=lambda x: x[3], reverse=True)
458
458
  for path, title, count, time in records:
459
- when = datetime.fromtimestamp(time).strftime("%x")
459
+ when = CONFIG.localDate(datetime.fromtimestamp(time))
460
460
  data.append((title, path, f"{opened}: {when}, {words}: {formatInt(count)}"))
461
461
  self._data = data
462
462
  return