novelWriter 2.2rc1__py3-none-any.whl → 2.3__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 (162) hide show
  1. {novelWriter-2.2rc1.dist-info → novelWriter-2.3.dist-info}/METADATA +1 -1
  2. {novelWriter-2.2rc1.dist-info → novelWriter-2.3.dist-info}/RECORD +149 -132
  3. {novelWriter-2.2rc1.dist-info → novelWriter-2.3.dist-info}/WHEEL +1 -1
  4. novelWriter-2.3.dist-info/entry_points.txt +2 -0
  5. novelwriter/__init__.py +11 -6
  6. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  7. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  8. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  9. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  10. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  11. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  12. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  13. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  14. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  15. novelwriter/assets/i18n/project_de_DE.json +1 -0
  16. novelwriter/assets/i18n/project_en_US.json +1 -0
  17. novelwriter/assets/i18n/project_es_419.json +11 -0
  18. novelwriter/assets/i18n/project_fr_FR.json +11 -0
  19. novelwriter/assets/i18n/project_it_IT.json +11 -0
  20. novelwriter/assets/i18n/project_ja_JP.json +2 -1
  21. novelwriter/assets/i18n/project_nb_NO.json +1 -0
  22. novelwriter/assets/i18n/project_nl_NL.json +11 -0
  23. novelwriter/assets/i18n/project_pt_BR.json +11 -0
  24. novelwriter/assets/i18n/project_zh_CN.json +11 -0
  25. novelwriter/assets/icons/typicons_dark/icons.conf +11 -2
  26. novelwriter/assets/icons/typicons_dark/mixed_document-new.svg +6 -0
  27. novelwriter/assets/icons/typicons_dark/mixed_import.svg +5 -0
  28. novelwriter/assets/icons/typicons_dark/nw_tb-bold-md.svg +4 -0
  29. novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +3 -1
  30. novelwriter/assets/icons/typicons_dark/nw_tb-italic-md.svg +4 -0
  31. novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +3 -1
  32. novelwriter/assets/icons/typicons_dark/nw_tb-strike-md.svg +4 -0
  33. novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +3 -1
  34. novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +4 -2
  35. novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +4 -2
  36. novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +4 -2
  37. novelwriter/assets/icons/typicons_dark/typ_document-add.svg +4 -0
  38. novelwriter/assets/icons/typicons_dark/typ_document.svg +4 -0
  39. novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +4 -0
  40. novelwriter/assets/icons/typicons_dark/typ_th-list.svg +9 -0
  41. novelwriter/assets/icons/typicons_light/icons.conf +11 -2
  42. novelwriter/assets/icons/typicons_light/mixed_document-new.svg +6 -0
  43. novelwriter/assets/icons/typicons_light/mixed_import.svg +5 -0
  44. novelwriter/assets/icons/typicons_light/nw_tb-bold-md.svg +4 -0
  45. novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +3 -1
  46. novelwriter/assets/icons/typicons_light/nw_tb-italic-md.svg +4 -0
  47. novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +3 -1
  48. novelwriter/assets/icons/typicons_light/nw_tb-strike-md.svg +4 -0
  49. novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +3 -1
  50. novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +4 -2
  51. novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +4 -2
  52. novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +4 -2
  53. novelwriter/assets/icons/typicons_light/typ_document-add.svg +4 -0
  54. novelwriter/assets/icons/typicons_light/typ_document.svg +4 -0
  55. novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +4 -0
  56. novelwriter/assets/icons/typicons_light/typ_th-list.svg +9 -0
  57. novelwriter/assets/images/novelwriter-text-dark.svg +4 -0
  58. novelwriter/assets/images/novelwriter-text-light.svg +4 -0
  59. novelwriter/assets/images/welcome-dark.jpg +0 -0
  60. novelwriter/assets/images/welcome-light.jpg +0 -0
  61. novelwriter/assets/manual.pdf +0 -0
  62. novelwriter/assets/sample.zip +0 -0
  63. novelwriter/assets/syntax/cyberpunk_night.conf +26 -0
  64. novelwriter/assets/syntax/default_dark.conf +1 -0
  65. novelwriter/assets/syntax/default_light.conf +1 -0
  66. novelwriter/assets/syntax/grey_dark.conf +1 -0
  67. novelwriter/assets/syntax/grey_light.conf +1 -0
  68. novelwriter/assets/syntax/light_owl.conf +1 -0
  69. novelwriter/assets/syntax/night_owl.conf +1 -0
  70. novelwriter/assets/syntax/solarized_dark.conf +1 -0
  71. novelwriter/assets/syntax/solarized_light.conf +1 -0
  72. novelwriter/assets/syntax/tango.conf +23 -0
  73. novelwriter/assets/syntax/tomorrow.conf +1 -0
  74. novelwriter/assets/syntax/tomorrow_night.conf +1 -0
  75. novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
  76. novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
  77. novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
  78. novelwriter/assets/text/credits_en.htm +4 -2
  79. novelwriter/assets/themes/cyberpunk_night.conf +29 -0
  80. novelwriter/assets/themes/default_dark.conf +2 -2
  81. novelwriter/assets/themes/default_light.conf +2 -2
  82. novelwriter/common.py +64 -66
  83. novelwriter/config.py +39 -44
  84. novelwriter/constants.py +39 -17
  85. novelwriter/core/buildsettings.py +8 -8
  86. novelwriter/core/coretools.py +198 -157
  87. novelwriter/core/docbuild.py +7 -4
  88. novelwriter/core/document.py +7 -7
  89. novelwriter/core/index.py +90 -57
  90. novelwriter/core/item.py +23 -5
  91. novelwriter/core/options.py +11 -10
  92. novelwriter/core/project.py +73 -47
  93. novelwriter/core/projectdata.py +3 -16
  94. novelwriter/core/projectxml.py +14 -42
  95. novelwriter/core/sessions.py +4 -3
  96. novelwriter/core/spellcheck.py +6 -4
  97. novelwriter/core/status.py +5 -4
  98. novelwriter/core/storage.py +183 -141
  99. novelwriter/core/tohtml.py +6 -4
  100. novelwriter/core/tokenizer.py +110 -83
  101. novelwriter/core/tomd.py +2 -2
  102. novelwriter/core/toodt.py +41 -31
  103. novelwriter/core/tree.py +5 -4
  104. novelwriter/dialogs/about.py +88 -179
  105. novelwriter/dialogs/docmerge.py +30 -20
  106. novelwriter/dialogs/docsplit.py +33 -22
  107. novelwriter/dialogs/editlabel.py +20 -8
  108. novelwriter/dialogs/preferences.py +562 -725
  109. novelwriter/dialogs/{projsettings.py → projectsettings.py} +301 -270
  110. novelwriter/dialogs/quotes.py +47 -36
  111. novelwriter/dialogs/wordlist.py +128 -59
  112. novelwriter/enum.py +25 -22
  113. novelwriter/error.py +2 -2
  114. novelwriter/extensions/circularprogress.py +12 -12
  115. novelwriter/extensions/configlayout.py +185 -146
  116. novelwriter/extensions/{wheeleventfilter.py → eventfilters.py} +15 -5
  117. novelwriter/extensions/modified.py +81 -0
  118. novelwriter/extensions/novelselector.py +27 -13
  119. novelwriter/extensions/pagedsidebar.py +15 -20
  120. novelwriter/extensions/simpleprogress.py +8 -9
  121. novelwriter/extensions/statusled.py +9 -9
  122. novelwriter/extensions/switch.py +32 -64
  123. novelwriter/extensions/switchbox.py +2 -7
  124. novelwriter/extensions/versioninfo.py +153 -0
  125. novelwriter/gui/doceditor.py +250 -214
  126. novelwriter/gui/dochighlight.py +66 -94
  127. novelwriter/gui/docviewer.py +71 -98
  128. novelwriter/gui/docviewerpanel.py +140 -47
  129. novelwriter/gui/editordocument.py +3 -3
  130. novelwriter/gui/itemdetails.py +9 -9
  131. novelwriter/gui/mainmenu.py +47 -47
  132. novelwriter/gui/noveltree.py +53 -61
  133. novelwriter/gui/outline.py +100 -76
  134. novelwriter/gui/projtree.py +246 -112
  135. novelwriter/gui/sidebar.py +9 -8
  136. novelwriter/gui/statusbar.py +49 -7
  137. novelwriter/gui/theme.py +74 -76
  138. novelwriter/guimain.py +175 -330
  139. novelwriter/shared.py +68 -30
  140. novelwriter/tools/dictionaries.py +7 -8
  141. novelwriter/tools/lipsum.py +34 -28
  142. novelwriter/tools/manusbuild.py +3 -4
  143. novelwriter/tools/manuscript.py +25 -32
  144. novelwriter/tools/manussettings.py +194 -225
  145. novelwriter/tools/noveldetails.py +525 -0
  146. novelwriter/tools/welcome.py +819 -0
  147. novelwriter/tools/writingstats.py +26 -13
  148. novelWriter-2.2rc1.dist-info/entry_points.txt +0 -5
  149. novelwriter/assets/icons/typicons_dark/nw_tb-markdown.svg +0 -8
  150. novelwriter/assets/icons/typicons_dark/nw_tb-shortcode.svg +0 -8
  151. novelwriter/assets/icons/typicons_light/nw_tb-markdown.svg +0 -8
  152. novelwriter/assets/icons/typicons_light/nw_tb-shortcode.svg +0 -8
  153. novelwriter/assets/images/wizard-back.jpg +0 -0
  154. novelwriter/assets/text/gplv3_en.htm +0 -641
  155. novelwriter/assets/text/release_notes.htm +0 -17
  156. novelwriter/dialogs/projdetails.py +0 -525
  157. novelwriter/dialogs/projload.py +0 -298
  158. novelwriter/dialogs/updates.py +0 -182
  159. novelwriter/extensions/pageddialog.py +0 -130
  160. novelwriter/tools/projwizard.py +0 -478
  161. {novelWriter-2.2rc1.dist-info → novelWriter-2.3.dist-info}/LICENSE.md +0 -0
  162. {novelWriter-2.2rc1.dist-info → novelWriter-2.3.dist-info}/top_level.txt +0 -0
novelwriter/config.py CHANGED
@@ -7,7 +7,7 @@ Created: 2018-09-22 [0.0.1] Config
7
7
  Created: 2022-11-09 [2.0rc2] RecentProjects
8
8
 
9
9
  This file is a part of novelWriter
10
- Copyright 2018–2023, Veronica Berglyd Olsen
10
+ Copyright 2018–2024, Veronica Berglyd Olsen
11
11
 
12
12
  This program is free software: you can redistribute it and/or modify
13
13
  it under the terms of the GNU General Public License as published by
@@ -110,8 +110,8 @@ class Config:
110
110
 
111
111
  # Size Settings
112
112
  self._mainWinSize = [1200, 650] # Last size of the main GUI window
113
+ self._welcomeSize = [800, 550] # Last size of the welcome window
113
114
  self._prefsWinSize = [700, 615] # Last size of the Preferences dialog
114
- self._projLoadCols = [280, 60, 160] # Last columns widths of the Project Load dialog
115
115
  self._mainPanePos = [300, 800] # Last position of the main window splitter
116
116
  self._viewPanePos = [500, 150] # Last position of the document viewer splitter
117
117
  self._outlnPanePos = [500, 150] # Last position of the outline panel splitter
@@ -150,9 +150,6 @@ class Config:
150
150
  self.autoScrollPos = 30 # Start point for typewriter-like scrolling
151
151
  self.scrollPastEnd = True # Scroll past end of document, and centre cursor
152
152
 
153
- self.wordCountTimer = 5.0 # Interval for word count update in seconds
154
- self.incNotesWCount = True # The status bar word count includes notes
155
-
156
153
  self.highlightQuotes = True # Highlight text in quotes
157
154
  self.allowOpenSQuote = False # Allow open-ended single quotes
158
155
  self.allowOpenDQuote = True # Allow open-ended double quotes
@@ -160,6 +157,7 @@ class Config:
160
157
 
161
158
  self.stopWhenIdle = True # Stop the status bar clock when the user is idle
162
159
  self.userIdleTime = 300 # Time of inactivity to consider user idle
160
+ self.incNotesWCount = True # The status bar word count includes notes
163
161
 
164
162
  # User-Selected Symbol Settings
165
163
  self.fmtApostrophe = nwUnicode.U_RSQUO
@@ -225,7 +223,8 @@ class Config:
225
223
  # Other System Info
226
224
  self.hostName = QSysInfo.machineHostName()
227
225
  self.kernelVer = QSysInfo.kernelVersion()
228
- self.isDebug = False
226
+ self.isDebug = False # True if running in debug mode
227
+ self.memInfo = False # True if displaying mem info in status bar
229
228
 
230
229
  # Packages
231
230
  self.hasEnchant = False # The pyenchant package
@@ -249,12 +248,12 @@ class Config:
249
248
  return [int(x*self.guiScale) for x in self._mainWinSize]
250
249
 
251
250
  @property
252
- def preferencesWinSize(self) -> list[int]:
253
- return [int(x*self.guiScale) for x in self._prefsWinSize]
251
+ def welcomeWinSize(self) -> list[int]:
252
+ return [int(x*self.guiScale) for x in self._welcomeSize]
254
253
 
255
254
  @property
256
- def projLoadColWidths(self) -> list[int]:
257
- return [int(x*self.guiScale) for x in self._projLoadCols]
255
+ def preferencesWinSize(self) -> list[int]:
256
+ return [int(x*self.guiScale) for x in self._prefsWinSize]
258
257
 
259
258
  @property
260
259
  def mainPanePos(self) -> list[int]:
@@ -305,17 +304,18 @@ class Config:
305
304
  self._mainWinSize[1] = height
306
305
  return
307
306
 
307
+ def setWelcomeWinSize(self, width: int, height: int) -> None:
308
+ """Set the size of the Preferences dialog window."""
309
+ self._welcomeSize[0] = int(width/self.guiScale)
310
+ self._welcomeSize[1] = int(height/self.guiScale)
311
+ return
312
+
308
313
  def setPreferencesWinSize(self, width: int, height: int) -> None:
309
314
  """Set the size of the Preferences dialog window."""
310
315
  self._prefsWinSize[0] = int(width/self.guiScale)
311
316
  self._prefsWinSize[1] = int(height/self.guiScale)
312
317
  return
313
318
 
314
- def setProjLoadColWidths(self, widths: list[int]) -> None:
315
- """Set the column widths of the Load Project dialog."""
316
- self._projLoadCols = [int(x/self.guiScale) for x in widths]
317
- return
318
-
319
319
  def setMainPanePos(self, pos: list[int]) -> None:
320
320
  """Set the position of the main GUI splitter."""
321
321
  self._mainPanePos = [int(x/self.guiScale) for x in pos]
@@ -409,10 +409,10 @@ class Config:
409
409
  """Compile and return error messages from the initialisation of
410
410
  the Config class, and clear the error buffer.
411
411
  """
412
- errMessage = "<br>".join(self._errData)
412
+ message = "<br>".join(self._errData)
413
413
  self._hasError = False
414
414
  self._errData = []
415
- return errMessage
415
+ return message
416
416
 
417
417
  def listLanguages(self, lngSet: int) -> list[tuple[str, str]]:
418
418
  """List localisation files in the i18n folder. The default GUI
@@ -485,7 +485,6 @@ class Config:
485
485
 
486
486
  self._recentObj.loadCache()
487
487
  self._checkOptionalPackages()
488
- self.isDebug = logger.getEffectiveLevel() == logging.DEBUG
489
488
 
490
489
  logger.debug("Config instance initialised")
491
490
 
@@ -545,8 +544,8 @@ class Config:
545
544
  # Sizes
546
545
  sec = "Sizes"
547
546
  self._mainWinSize = conf.rdIntList(sec, "mainwindow", self._mainWinSize)
547
+ self._welcomeSize = conf.rdIntList(sec, "welcome", self._welcomeSize)
548
548
  self._prefsWinSize = conf.rdIntList(sec, "preferences", self._prefsWinSize)
549
- self._projLoadCols = conf.rdIntList(sec, "projloadcols", self._projLoadCols)
550
549
  self._mainPanePos = conf.rdIntList(sec, "mainpane", self._mainPanePos)
551
550
  self._viewPanePos = conf.rdIntList(sec, "viewpane", self._viewPanePos)
552
551
  self._outlnPanePos = conf.rdIntList(sec, "outlinepane", self._outlnPanePos)
@@ -590,7 +589,6 @@ class Config:
590
589
  self.showTabsNSpaces = conf.rdBool(sec, "showtabsnspaces", self.showTabsNSpaces)
591
590
  self.showLineEndings = conf.rdBool(sec, "showlineendings", self.showLineEndings)
592
591
  self.showMultiSpaces = conf.rdBool(sec, "showmultispaces", self.showMultiSpaces)
593
- self.wordCountTimer = conf.rdFlt(sec, "wordcounttimer", self.wordCountTimer)
594
592
  self.incNotesWCount = conf.rdBool(sec, "incnoteswcount", self.incNotesWCount)
595
593
  self.showFullPath = conf.rdBool(sec, "showfullpath", self.showFullPath)
596
594
  self.highlightQuotes = conf.rdBool(sec, "highlightquotes", self.highlightQuotes)
@@ -635,7 +633,7 @@ class Config:
635
633
  conf = NWConfigParser()
636
634
 
637
635
  conf["Meta"] = {
638
- "timestamp": formatTimeStamp(time()),
636
+ "timestamp": formatTimeStamp(time()),
639
637
  }
640
638
 
641
639
  conf["Main"] = {
@@ -651,12 +649,12 @@ class Config:
651
649
  }
652
650
 
653
651
  conf["Sizes"] = {
654
- "mainwindow": self._packList(self._mainWinSize),
655
- "preferences": self._packList(self._prefsWinSize),
656
- "projloadcols": self._packList(self._projLoadCols),
657
- "mainpane": self._packList(self._mainPanePos),
658
- "viewpane": self._packList(self._viewPanePos),
659
- "outlinepane": self._packList(self._outlnPanePos),
652
+ "mainwindow": self._packList(self._mainWinSize),
653
+ "welcome": self._packList(self._welcomeSize),
654
+ "preferences": self._packList(self._prefsWinSize),
655
+ "mainpane": self._packList(self._mainPanePos),
656
+ "viewpane": self._packList(self._viewPanePos),
657
+ "outlinepane": self._packList(self._outlnPanePos),
660
658
  }
661
659
 
662
660
  conf["Project"] = {
@@ -697,7 +695,6 @@ class Config:
697
695
  "showtabsnspaces": str(self.showTabsNSpaces),
698
696
  "showlineendings": str(self.showLineEndings),
699
697
  "showmultispaces": str(self.showMultiSpaces),
700
- "wordcounttimer": str(self.wordCountTimer),
701
698
  "incnoteswcount": str(self.incNotesWCount),
702
699
  "showfullpath": str(self.showFullPath),
703
700
  "highlightquotes": str(self.highlightQuotes),
@@ -774,22 +771,20 @@ class RecentProjects:
774
771
  self._data = {}
775
772
 
776
773
  cacheFile = self._conf.dataPath(nwFiles.RECENT_FILE)
777
- if not cacheFile.is_file():
778
- return True
779
-
780
- try:
781
- with open(cacheFile, mode="r", encoding="utf-8") as inFile:
782
- theData = json.load(inFile)
783
- for projPath, theEntry in theData.items():
784
- self._data[projPath] = {
785
- "title": theEntry.get("title", ""),
786
- "words": theEntry.get("words", 0),
787
- "time": theEntry.get("time", 0),
788
- }
789
- except Exception:
790
- logger.error("Could not load recent project cache")
791
- logException()
792
- return False
774
+ if cacheFile.is_file():
775
+ try:
776
+ with open(cacheFile, mode="r", encoding="utf-8") as inFile:
777
+ data = json.load(inFile)
778
+ for path, entry in data.items():
779
+ self._data[path] = {
780
+ "title": entry.get("title", ""),
781
+ "words": entry.get("words", 0),
782
+ "time": entry.get("time", 0),
783
+ }
784
+ except Exception:
785
+ logger.error("Could not load recent project cache")
786
+ logException()
787
+ return False
793
788
 
794
789
  return True
795
790
 
novelwriter/constants.py CHANGED
@@ -6,7 +6,7 @@ File History:
6
6
  Created: 2019-04-28 [0.0.1]
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
@@ -43,12 +43,12 @@ class nwConst:
43
43
  FMT_DSTAMP = "%Y-%m-%d" # Date only format
44
44
 
45
45
  # URLs
46
- URL_WEB = "https://novelwriter.io"
47
- URL_DOCS = "https://docs.novelwriter.io"
48
- URL_CODE = "https://github.com/vkbo/novelWriter"
49
- URL_REPORT = "https://github.com/vkbo/novelWriter/issues"
50
- URL_HELP = "https://github.com/vkbo/novelWriter/discussions"
51
- URL_RELEASE = "https://github.com/vkbo/novelWriter/releases/latest"
46
+ URL_WEB = "https://novelwriter.io"
47
+ URL_DOCS = "https://docs.novelwriter.io"
48
+ URL_RELEASES = "https://releases.novelwriter.io"
49
+ URL_CODE = "https://github.com/vkbo/novelWriter"
50
+ URL_REPORT = "https://github.com/vkbo/novelWriter/issues"
51
+ URL_HELP = "https://github.com/vkbo/novelWriter/discussions"
52
52
 
53
53
  # Requests
54
54
  USER_AGENT = "Mozilla/5.0 (compatible; novelWriter (Python))"
@@ -56,6 +56,9 @@ class nwConst:
56
56
  # Gui Settings
57
57
  STATUS_MSG_TIMEOUT = 15000 # milliseconds
58
58
 
59
+ # Dialogs
60
+ DLG_FINISHED = 2
61
+
59
62
  # END Class nwConst
60
63
 
61
64
 
@@ -107,7 +110,6 @@ class nwFiles:
107
110
 
108
111
  # Project Root Files
109
112
  PROJ_FILE = "nwProject.nwx"
110
- PROJ_BACKUP = "nwProject.bak"
111
113
  PROJ_LOCK = "nwProject.lock"
112
114
  TOC_TXT = "ToC.txt"
113
115
 
@@ -184,6 +186,7 @@ class nwLabels:
184
186
  nwItemClass.ENTITY: QT_TRANSLATE_NOOP("Constant", "Entities"),
185
187
  nwItemClass.CUSTOM: QT_TRANSLATE_NOOP("Constant", "Custom"),
186
188
  nwItemClass.ARCHIVE: QT_TRANSLATE_NOOP("Constant", "Archive"),
189
+ nwItemClass.TEMPLATE: QT_TRANSLATE_NOOP("Constant", "Templates"),
187
190
  nwItemClass.TRASH: QT_TRANSLATE_NOOP("Constant", "Trash"),
188
191
  }
189
192
  CLASS_ICON = {
@@ -197,6 +200,7 @@ class nwLabels:
197
200
  nwItemClass.ENTITY: "cls_entity",
198
201
  nwItemClass.CUSTOM: "cls_custom",
199
202
  nwItemClass.ARCHIVE: "cls_archive",
203
+ nwItemClass.TEMPLATE: "cls_template",
200
204
  nwItemClass.TRASH: "cls_trash",
201
205
  }
202
206
  LAYOUT_NAME = {
@@ -266,6 +270,13 @@ class nwLabels:
266
270
  nwBuildFmt.J_HTML: ".json",
267
271
  nwBuildFmt.J_NWD: ".json",
268
272
  }
273
+ FILE_FILTERS = {
274
+ "*.txt": QT_TRANSLATE_NOOP("Constant", "Text files"),
275
+ "*.md": QT_TRANSLATE_NOOP("Constant", "Markdown files"),
276
+ "*.nwd": QT_TRANSLATE_NOOP("Constant", "novelWriter files"),
277
+ "*.csv": QT_TRANSLATE_NOOP("Constant", "CSV files"),
278
+ "*": QT_TRANSLATE_NOOP("Constant", "All files"),
279
+ }
269
280
  UNIT_NAME = {
270
281
  "mm": QT_TRANSLATE_NOOP("Constant", "Millimetres"),
271
282
  "cm": QT_TRANSLATE_NOOP("Constant", "Centimetres"),
@@ -298,16 +309,27 @@ class nwLabels:
298
309
 
299
310
  class nwHeadFmt:
300
311
 
301
- BR = "{BR}"
302
- TITLE = "{Title}"
303
- CH_NUM = "{Chapter}"
304
- CH_WORD = "{Chapter:Word}"
305
- CH_ROMU = "{Chapter:URoman}"
306
- CH_ROML = "{Chapter:LRoman}"
307
- SC_NUM = "{Scene}"
308
- SC_ABS = "{Scene:Abs}"
312
+ BR = "{BR}"
313
+ TITLE = "{Title}"
314
+ CH_NUM = "{Chapter}"
315
+ CH_WORD = "{Chapter:Word}"
316
+ CH_ROMU = "{Chapter:URoman}"
317
+ CH_ROML = "{Chapter:LRoman}"
318
+ SC_NUM = "{Scene}"
319
+ SC_ABS = "{Scene:Abs}"
320
+ CHAR_POV = "{Char:POV}"
321
+ CHAR_FOCUS = "{Char:Focus}"
322
+
323
+ PAGE_HEADERS = [
324
+ TITLE, CH_NUM, CH_WORD, CH_ROMU, CH_ROML, SC_NUM, SC_ABS,
325
+ CHAR_POV, CHAR_FOCUS
326
+ ]
309
327
 
310
- ALL = [TITLE, CH_NUM, CH_WORD, CH_ROMU, CH_ROML, SC_NUM, SC_ABS]
328
+ # ODT Document Page Header
329
+ ODT_PROJECT = "{Project}"
330
+ ODT_AUTHOR = "{Author}"
331
+ ODT_PAGE = "{Page}"
332
+ ODT_AUTO = "{Project} / {Author} / {Page}"
311
333
 
312
334
  # END Class nwHeadFmt
313
335
 
@@ -7,7 +7,7 @@ Created: 2023-02-14 [2.1b1] BuildSettings
7
7
  Created: 2023-05-22 [2.1b1] BuildCollection
8
8
 
9
9
  This file is a part of novelWriter
10
- Copyright 2018–2023, Veronica Berglyd Olsen
10
+ Copyright 2018–2024, Veronica Berglyd Olsen
11
11
 
12
12
  This program is free software: you can redistribute it and/or modify
13
13
  it under the terms of the GNU General Public License as published by
@@ -29,8 +29,8 @@ import uuid
29
29
  import logging
30
30
 
31
31
  from enum import Enum
32
- from typing import Iterable
33
32
  from pathlib import Path
33
+ from collections.abc import Iterable
34
34
 
35
35
  from PyQt5.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
36
36
 
@@ -79,6 +79,8 @@ SETTINGS_TEMPLATE = {
79
79
  "format.leftMargin": (float, 2.0),
80
80
  "format.rightMargin": (float, 2.0),
81
81
  "odt.addColours": (bool, True),
82
+ "odt.pageHeader": (str, nwHeadFmt.ODT_AUTO),
83
+ "odt.pageCountOffset": (int, 0),
82
84
  "html.addStyles": (bool, True),
83
85
  }
84
86
 
@@ -125,6 +127,8 @@ SETTINGS_LABELS = {
125
127
 
126
128
  "odt": QT_TRANSLATE_NOOP("Builds", "Open Document (.odt)"),
127
129
  "odt.addColours": QT_TRANSLATE_NOOP("Builds", "Add Highlight Colours"),
130
+ "odt.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"),
131
+ "odt.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"),
128
132
 
129
133
  "html": QT_TRANSLATE_NOOP("Builds", "HTML (.html)"),
130
134
  "html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"),
@@ -235,16 +239,12 @@ class BuildSettings:
235
239
  def getInt(self, key: str) -> int:
236
240
  """Type safe value access for integers."""
237
241
  value = self._settings.get(key, SETTINGS_TEMPLATE.get(key, (None, None))[1])
238
- if isinstance(value, (int, float)):
239
- return int(value)
240
- return 0
242
+ return int(value) if isinstance(value, (int, float)) else 0
241
243
 
242
244
  def getFloat(self, key: str) -> float:
243
245
  """Type safe value access for floats."""
244
246
  value = self._settings.get(key, SETTINGS_TEMPLATE.get(key, (None, None))[1])
245
- if isinstance(value, (int, float)):
246
- return float(value)
247
- return 0.0
247
+ return float(value) if isinstance(value, (int, float)) else 0.0
248
248
 
249
249
  ##
250
250
  # Setters