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
@@ -28,13 +28,15 @@ import logging
28
28
  from pathlib import Path
29
29
  from typing import TYPE_CHECKING
30
30
 
31
- from PyQt5.QtCore import QUrl, pyqtSignal, pyqtSlot
32
- from PyQt5.QtGui import QDesktopServices
31
+ from PyQt5.QtCore import pyqtSignal, pyqtSlot
33
32
  from PyQt5.QtWidgets import QAction, QMenuBar
34
33
 
35
34
  from novelwriter import CONFIG, SHARED
36
- from novelwriter.common import openExternalPath
37
- from novelwriter.constants import nwConst, nwKeyWords, nwLabels, nwUnicode, trConst
35
+ from novelwriter.common import openExternalPath, qtLambda
36
+ from novelwriter.constants import (
37
+ nwConst, nwKeyWords, nwLabels, nwShortcode, nwStats, nwStyles, nwUnicode,
38
+ trConst
39
+ )
38
40
  from novelwriter.enum import nwDocAction, nwDocInsert, nwFocus, nwView
39
41
  from novelwriter.extensions.eventfilters import StatusTipFilter
40
42
 
@@ -104,12 +106,6 @@ class GuiMainMenu(QMenuBar):
104
106
  self.mainGui.docEditor.toggleSpellCheck(None)
105
107
  return
106
108
 
107
- @pyqtSlot(str)
108
- def _openWebsite(self, url: str) -> None:
109
- """Open a URL in the system's default browser."""
110
- QDesktopServices.openUrl(QUrl(url))
111
- return
112
-
113
109
  @pyqtSlot()
114
110
  def _openUserManualFile(self) -> None:
115
111
  """Open the documentation in PDF format."""
@@ -141,12 +137,13 @@ class GuiMainMenu(QMenuBar):
141
137
  # Project > Save Project
142
138
  self.aSaveProject = self.projMenu.addAction(self.tr("Save Project"))
143
139
  self.aSaveProject.setShortcut("Ctrl+Shift+S")
144
- self.aSaveProject.triggered.connect(lambda: self.mainGui.saveProject())
140
+ self.aSaveProject.triggered.connect(qtLambda(self.mainGui.saveProject))
141
+ self.mainGui.addAction(self.aSaveProject)
145
142
 
146
143
  # Project > Close Project
147
144
  self.aCloseProject = self.projMenu.addAction(self.tr("Close Project"))
148
145
  self.aCloseProject.setShortcut("Ctrl+Shift+W")
149
- self.aCloseProject.triggered.connect(lambda: self.mainGui.closeProject(False))
146
+ self.aCloseProject.triggered.connect(qtLambda(self.mainGui.closeProject, False))
150
147
 
151
148
  # Project > Separator
152
149
  self.projMenu.addSeparator()
@@ -167,16 +164,17 @@ class GuiMainMenu(QMenuBar):
167
164
  # Project > Edit
168
165
  self.aEditItem = self.projMenu.addAction(self.tr("Rename Item"))
169
166
  self.aEditItem.setShortcut("F2")
170
- self.aEditItem.triggered.connect(lambda: self.mainGui.projView.renameTreeItem(None))
167
+ self.aEditItem.triggered.connect(qtLambda(self.mainGui.projView.renameTreeItem, None))
168
+ self.mainGui.addAction(self.aEditItem)
171
169
 
172
170
  # Project > Delete
173
171
  self.aDeleteItem = self.projMenu.addAction(self.tr("Delete Item"))
174
172
  self.aDeleteItem.setShortcut("Ctrl+Shift+Del") # Cannot be Ctrl+Del, see #629
175
- self.aDeleteItem.triggered.connect(lambda: self.mainGui.projView.requestDeleteItem(None))
173
+ self.aDeleteItem.triggered.connect(qtLambda(self.mainGui.projView.requestDeleteItem, None))
176
174
 
177
175
  # Project > Empty Trash
178
176
  self.aEmptyTrash = self.projMenu.addAction(self.tr("Empty Trash"))
179
- self.aEmptyTrash.triggered.connect(lambda: self.mainGui.projView.emptyTrash())
177
+ self.aEmptyTrash.triggered.connect(qtLambda(self.mainGui.projView.emptyTrash))
180
178
 
181
179
  # Project > Separator
182
180
  self.projMenu.addSeparator()
@@ -184,8 +182,9 @@ class GuiMainMenu(QMenuBar):
184
182
  # Project > Exit
185
183
  self.aExitNW = self.projMenu.addAction(self.tr("Exit"))
186
184
  self.aExitNW.setShortcut("Ctrl+Q")
187
- self.aExitNW.setMenuRole(QAction.QuitRole)
188
- self.aExitNW.triggered.connect(lambda: self.mainGui.closeMain())
185
+ self.aExitNW.setMenuRole(QAction.MenuRole.QuitRole)
186
+ self.aExitNW.triggered.connect(qtLambda(self.mainGui.closeMain))
187
+ self.mainGui.addAction(self.aExitNW)
189
188
 
190
189
  return
191
190
 
@@ -203,11 +202,13 @@ class GuiMainMenu(QMenuBar):
203
202
  self.aSaveDoc = self.docuMenu.addAction(self.tr("Save Document"))
204
203
  self.aSaveDoc.setShortcut("Ctrl+S")
205
204
  self.aSaveDoc.triggered.connect(self.mainGui.forceSaveDocument)
205
+ self.mainGui.addAction(self.aSaveDoc)
206
206
 
207
207
  # Document > Close
208
208
  self.aCloseDoc = self.docuMenu.addAction(self.tr("Close Document"))
209
209
  self.aCloseDoc.setShortcut("Ctrl+W")
210
210
  self.aCloseDoc.triggered.connect(self.mainGui.closeDocEditor)
211
+ self.mainGui.addAction(self.aCloseDoc)
211
212
 
212
213
  # Document > Separator
213
214
  self.docuMenu.addSeparator()
@@ -215,7 +216,7 @@ class GuiMainMenu(QMenuBar):
215
216
  # Document > Preview
216
217
  self.aViewDoc = self.docuMenu.addAction(self.tr("View Document"))
217
218
  self.aViewDoc.setShortcut("Ctrl+R")
218
- self.aViewDoc.triggered.connect(lambda: self.mainGui.viewDocument(None))
219
+ self.aViewDoc.triggered.connect(qtLambda(self.mainGui.viewDocument, None))
219
220
 
220
221
  # Document > Close Preview
221
222
  self.aCloseView = self.docuMenu.addAction(self.tr("Close Document View"))
@@ -227,11 +228,11 @@ class GuiMainMenu(QMenuBar):
227
228
 
228
229
  # Document > Show File Details
229
230
  self.aFileDetails = self.docuMenu.addAction(self.tr("Show File Details"))
230
- self.aFileDetails.triggered.connect(lambda: self.mainGui.docEditor.revealLocation())
231
+ self.aFileDetails.triggered.connect(qtLambda(self.mainGui.docEditor.revealLocation))
231
232
 
232
233
  # Document > Import From File
233
234
  self.aImportFile = self.docuMenu.addAction(self.tr("Import Text from File"))
234
- self.aImportFile.triggered.connect(lambda: self.mainGui.importDocument())
235
+ self.aImportFile.triggered.connect(qtLambda(self.mainGui.importDocument))
235
236
 
236
237
  return
237
238
 
@@ -246,6 +247,7 @@ class GuiMainMenu(QMenuBar):
246
247
  self.aEditUndo.triggered.connect(
247
248
  lambda: self.requestDocAction.emit(nwDocAction.UNDO)
248
249
  )
250
+ self.mainGui.addAction(self.aEditUndo)
249
251
 
250
252
  # Edit > Redo
251
253
  self.aEditRedo = self.editMenu.addAction(self.tr("Redo"))
@@ -253,6 +255,7 @@ class GuiMainMenu(QMenuBar):
253
255
  self.aEditRedo.triggered.connect(
254
256
  lambda: self.requestDocAction.emit(nwDocAction.REDO)
255
257
  )
258
+ self.mainGui.addAction(self.aEditRedo)
256
259
 
257
260
  # Edit > Separator
258
261
  self.editMenu.addSeparator()
@@ -263,6 +266,7 @@ class GuiMainMenu(QMenuBar):
263
266
  self.aEditCut.triggered.connect(
264
267
  lambda: self.requestDocAction.emit(nwDocAction.CUT)
265
268
  )
269
+ self.mainGui.addAction(self.aEditCut)
266
270
 
267
271
  # Edit > Copy
268
272
  self.aEditCopy = self.editMenu.addAction(self.tr("Copy"))
@@ -270,6 +274,7 @@ class GuiMainMenu(QMenuBar):
270
274
  self.aEditCopy.triggered.connect(
271
275
  lambda: self.requestDocAction.emit(nwDocAction.COPY)
272
276
  )
277
+ self.mainGui.addAction(self.aEditCopy)
273
278
 
274
279
  # Edit > Paste
275
280
  self.aEditPaste = self.editMenu.addAction(self.tr("Paste"))
@@ -277,6 +282,7 @@ class GuiMainMenu(QMenuBar):
277
282
  self.aEditPaste.triggered.connect(
278
283
  lambda: self.requestDocAction.emit(nwDocAction.PASTE)
279
284
  )
285
+ self.mainGui.addAction(self.aEditPaste)
280
286
 
281
287
  # Edit > Separator
282
288
  self.editMenu.addSeparator()
@@ -287,6 +293,7 @@ class GuiMainMenu(QMenuBar):
287
293
  self.aSelectAll.triggered.connect(
288
294
  lambda: self.requestDocAction.emit(nwDocAction.SEL_ALL)
289
295
  )
296
+ self.mainGui.addAction(self.aSelectAll)
290
297
 
291
298
  # Edit > Select Paragraph
292
299
  self.aSelectPar = self.editMenu.addAction(self.tr("Select Paragraph"))
@@ -294,6 +301,7 @@ class GuiMainMenu(QMenuBar):
294
301
  self.aSelectPar.triggered.connect(
295
302
  lambda: self.requestDocAction.emit(nwDocAction.SEL_PARA)
296
303
  )
304
+ self.mainGui.addAction(self.aSelectPar)
297
305
 
298
306
  return
299
307
 
@@ -343,11 +351,13 @@ class GuiMainMenu(QMenuBar):
343
351
  self.aFocusMode = self.viewMenu.addAction(self.tr("Focus Mode"))
344
352
  self.aFocusMode.setShortcut("F8")
345
353
  self.aFocusMode.triggered.connect(self.mainGui.toggleFocusMode)
354
+ self.mainGui.addAction(self.aFocusMode)
346
355
 
347
356
  # View > Toggle Full Screen
348
357
  self.aFullScreen = self.viewMenu.addAction(self.tr("Full Screen Mode"))
349
358
  self.aFullScreen.setShortcut("F11")
350
- self.aFullScreen.triggered.connect(lambda: self.mainGui.toggleFullScreenMode())
359
+ self.aFullScreen.triggered.connect(self.mainGui.toggleFullScreenMode)
360
+ self.mainGui.addAction(self.aFullScreen)
351
361
 
352
362
  return
353
363
 
@@ -365,6 +375,7 @@ class GuiMainMenu(QMenuBar):
365
375
  self.aInsENDash.triggered.connect(
366
376
  lambda: self.requestDocInsertText.emit(nwUnicode.U_ENDASH)
367
377
  )
378
+ self.mainGui.addAction(self.aInsENDash)
368
379
 
369
380
  # Insert > Long Dash
370
381
  self.aInsEMDash = self.mInsDashes.addAction(self.tr("Long Dash"))
@@ -372,6 +383,7 @@ class GuiMainMenu(QMenuBar):
372
383
  self.aInsEMDash.triggered.connect(
373
384
  lambda: self.requestDocInsertText.emit(nwUnicode.U_EMDASH)
374
385
  )
386
+ self.mainGui.addAction(self.aInsEMDash)
375
387
 
376
388
  # Insert > Long Dash
377
389
  self.aInsHorBar = self.mInsDashes.addAction(self.tr("Horizontal Bar"))
@@ -379,6 +391,7 @@ class GuiMainMenu(QMenuBar):
379
391
  self.aInsHorBar.triggered.connect(
380
392
  lambda: self.requestDocInsertText.emit(nwUnicode.U_HBAR)
381
393
  )
394
+ self.mainGui.addAction(self.aInsHorBar)
382
395
 
383
396
  # Insert > Figure Dash
384
397
  self.aInsFigDash = self.mInsDashes.addAction(self.tr("Figure Dash"))
@@ -386,6 +399,7 @@ class GuiMainMenu(QMenuBar):
386
399
  self.aInsFigDash.triggered.connect(
387
400
  lambda: self.requestDocInsertText.emit(nwUnicode.U_FGDASH)
388
401
  )
402
+ self.mainGui.addAction(self.aInsFigDash)
389
403
 
390
404
  # Insert > Quote Marks
391
405
  self.mInsQuotes = self.insMenu.addMenu(self.tr("Quote Marks"))
@@ -396,6 +410,7 @@ class GuiMainMenu(QMenuBar):
396
410
  self.aInsQuoteLS.triggered.connect(
397
411
  lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_LS)
398
412
  )
413
+ self.mainGui.addAction(self.aInsQuoteLS)
399
414
 
400
415
  # Insert > Right Single Quote
401
416
  self.aInsQuoteRS = self.mInsQuotes.addAction(self.tr("Right Single Quote"))
@@ -403,6 +418,7 @@ class GuiMainMenu(QMenuBar):
403
418
  self.aInsQuoteRS.triggered.connect(
404
419
  lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_RS)
405
420
  )
421
+ self.mainGui.addAction(self.aInsQuoteRS)
406
422
 
407
423
  # Insert > Left Double Quote
408
424
  self.aInsQuoteLD = self.mInsQuotes.addAction(self.tr("Left Double Quote"))
@@ -410,6 +426,7 @@ class GuiMainMenu(QMenuBar):
410
426
  self.aInsQuoteLD.triggered.connect(
411
427
  lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_LD)
412
428
  )
429
+ self.mainGui.addAction(self.aInsQuoteLD)
413
430
 
414
431
  # Insert > Right Double Quote
415
432
  self.aInsQuoteRD = self.mInsQuotes.addAction(self.tr("Right Double Quote"))
@@ -417,6 +434,7 @@ class GuiMainMenu(QMenuBar):
417
434
  self.aInsQuoteRD.triggered.connect(
418
435
  lambda: self.requestDocInsert.emit(nwDocInsert.QUOTE_RD)
419
436
  )
437
+ self.mainGui.addAction(self.aInsQuoteRD)
420
438
 
421
439
  # Insert > Alternative Apostrophe
422
440
  self.aInsMSApos = self.mInsQuotes.addAction(self.tr("Alternative Apostrophe"))
@@ -424,6 +442,7 @@ class GuiMainMenu(QMenuBar):
424
442
  self.aInsMSApos.triggered.connect(
425
443
  lambda: self.requestDocInsertText.emit(nwUnicode.U_MAPOS)
426
444
  )
445
+ self.mainGui.addAction(self.aInsMSApos)
427
446
 
428
447
  # Insert > Symbols
429
448
  self.mInsPunct = self.insMenu.addMenu(self.tr("General Punctuation"))
@@ -434,6 +453,7 @@ class GuiMainMenu(QMenuBar):
434
453
  self.aInsEllipsis.triggered.connect(
435
454
  lambda: self.requestDocInsertText.emit(nwUnicode.U_HELLIP)
436
455
  )
456
+ self.mainGui.addAction(self.aInsEllipsis)
437
457
 
438
458
  # Insert > Prime
439
459
  self.aInsPrime = self.mInsPunct.addAction(self.tr("Prime"))
@@ -441,6 +461,7 @@ class GuiMainMenu(QMenuBar):
441
461
  self.aInsPrime.triggered.connect(
442
462
  lambda: self.requestDocInsertText.emit(nwUnicode.U_PRIME)
443
463
  )
464
+ self.mainGui.addAction(self.aInsPrime)
444
465
 
445
466
  # Insert > Double Prime
446
467
  self.aInsDPrime = self.mInsPunct.addAction(self.tr("Double Prime"))
@@ -448,6 +469,7 @@ class GuiMainMenu(QMenuBar):
448
469
  self.aInsDPrime.triggered.connect(
449
470
  lambda: self.requestDocInsertText.emit(nwUnicode.U_DPRIME)
450
471
  )
472
+ self.mainGui.addAction(self.aInsDPrime)
451
473
 
452
474
  # Insert > White Spaces
453
475
  self.mInsSpace = self.insMenu.addMenu(self.tr("White Spaces"))
@@ -458,6 +480,7 @@ class GuiMainMenu(QMenuBar):
458
480
  self.aInsNBSpace.triggered.connect(
459
481
  lambda: self.requestDocInsertText.emit(nwUnicode.U_NBSP)
460
482
  )
483
+ self.mainGui.addAction(self.aInsNBSpace)
461
484
 
462
485
  # Insert > Thin Space
463
486
  self.aInsThinSpace = self.mInsSpace.addAction(self.tr("Thin Space"))
@@ -465,6 +488,7 @@ class GuiMainMenu(QMenuBar):
465
488
  self.aInsThinSpace.triggered.connect(
466
489
  lambda: self.requestDocInsertText.emit(nwUnicode.U_THSP)
467
490
  )
491
+ self.mainGui.addAction(self.aInsThinSpace)
468
492
 
469
493
  # Insert > Thin Non-Breaking Space
470
494
  self.aInsThinNBSpace = self.mInsSpace.addAction(self.tr("Thin Non-Breaking Space"))
@@ -472,6 +496,7 @@ class GuiMainMenu(QMenuBar):
472
496
  self.aInsThinNBSpace.triggered.connect(
473
497
  lambda: self.requestDocInsertText.emit(nwUnicode.U_THNBSP)
474
498
  )
499
+ self.mainGui.addAction(self.aInsThinNBSpace)
475
500
 
476
501
  # Insert > Symbols
477
502
  self.mInsSymbol = self.insMenu.addMenu(self.tr("Other Symbols"))
@@ -482,6 +507,7 @@ class GuiMainMenu(QMenuBar):
482
507
  self.aInsBullet.triggered.connect(
483
508
  lambda: self.requestDocInsertText.emit(nwUnicode.U_BULL)
484
509
  )
510
+ self.mainGui.addAction(self.aInsBullet)
485
511
 
486
512
  # Insert > Hyphen Bullet
487
513
  self.aInsHyBull = self.mInsSymbol.addAction(self.tr("Hyphen Bullet"))
@@ -489,6 +515,7 @@ class GuiMainMenu(QMenuBar):
489
515
  self.aInsHyBull.triggered.connect(
490
516
  lambda: self.requestDocInsertText.emit(nwUnicode.U_HYBULL)
491
517
  )
518
+ self.mainGui.addAction(self.aInsHyBull)
492
519
 
493
520
  # Insert > Flower Mark
494
521
  self.aInsFlower = self.mInsSymbol.addAction(self.tr("Flower Mark"))
@@ -496,6 +523,7 @@ class GuiMainMenu(QMenuBar):
496
523
  self.aInsFlower.triggered.connect(
497
524
  lambda: self.requestDocInsertText.emit(nwUnicode.U_FLOWER)
498
525
  )
526
+ self.mainGui.addAction(self.aInsFlower)
499
527
 
500
528
  # Insert > Per Mille
501
529
  self.aInsPerMille = self.mInsSymbol.addAction(self.tr("Per Mille"))
@@ -503,6 +531,7 @@ class GuiMainMenu(QMenuBar):
503
531
  self.aInsPerMille.triggered.connect(
504
532
  lambda: self.requestDocInsertText.emit(nwUnicode.U_PERMIL)
505
533
  )
534
+ self.mainGui.addAction(self.aInsPerMille)
506
535
 
507
536
  # Insert > Degree Symbol
508
537
  self.aInsDegree = self.mInsSymbol.addAction(self.tr("Degree Symbol"))
@@ -510,6 +539,7 @@ class GuiMainMenu(QMenuBar):
510
539
  self.aInsDegree.triggered.connect(
511
540
  lambda: self.requestDocInsertText.emit(nwUnicode.U_DEGREE)
512
541
  )
542
+ self.mainGui.addAction(self.aInsDegree)
513
543
 
514
544
  # Insert > Minus Sign
515
545
  self.aInsMinus = self.mInsSymbol.addAction(self.tr("Minus Sign"))
@@ -517,6 +547,7 @@ class GuiMainMenu(QMenuBar):
517
547
  self.aInsMinus.triggered.connect(
518
548
  lambda: self.requestDocInsertText.emit(nwUnicode.U_MINUS)
519
549
  )
550
+ self.mainGui.addAction(self.aInsMinus)
520
551
 
521
552
  # Insert > Times Sign
522
553
  self.aInsTimes = self.mInsSymbol.addAction(self.tr("Times Sign"))
@@ -524,6 +555,7 @@ class GuiMainMenu(QMenuBar):
524
555
  self.aInsTimes.triggered.connect(
525
556
  lambda: self.requestDocInsertText.emit(nwUnicode.U_TIMES)
526
557
  )
558
+ self.mainGui.addAction(self.aInsTimes)
527
559
 
528
560
  # Insert > Division
529
561
  self.aInsDivide = self.mInsSymbol.addAction(self.tr("Division Sign"))
@@ -531,27 +563,15 @@ class GuiMainMenu(QMenuBar):
531
563
  self.aInsDivide.triggered.connect(
532
564
  lambda: self.requestDocInsertText.emit(nwUnicode.U_DIVIDE)
533
565
  )
566
+ self.mainGui.addAction(self.aInsDivide)
534
567
 
535
568
  # Insert > Tags and References
536
569
  self.mInsKeywords = self.insMenu.addMenu(self.tr("Tags and References"))
537
- self.mInsKWItems = {}
538
- self.mInsKWItems[nwKeyWords.TAG_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, G")
539
- self.mInsKWItems[nwKeyWords.POV_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, V")
540
- self.mInsKWItems[nwKeyWords.FOCUS_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, F")
541
- self.mInsKWItems[nwKeyWords.CHAR_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, C")
542
- self.mInsKWItems[nwKeyWords.PLOT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, P")
543
- self.mInsKWItems[nwKeyWords.TIME_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, T")
544
- self.mInsKWItems[nwKeyWords.WORLD_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, L")
545
- self.mInsKWItems[nwKeyWords.OBJECT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, O")
546
- self.mInsKWItems[nwKeyWords.ENTITY_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, E")
547
- self.mInsKWItems[nwKeyWords.CUSTOM_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, X")
548
- for n, keyWord in enumerate(self.mInsKWItems):
549
- self.mInsKWItems[keyWord][0].setText(trConst(nwLabels.KEY_NAME[keyWord]))
550
- self.mInsKWItems[keyWord][0].setShortcut(self.mInsKWItems[keyWord][1])
551
- self.mInsKWItems[keyWord][0].triggered.connect(
552
- lambda n, keyWord=keyWord: self.requestDocKeyWordInsert.emit(keyWord)
553
- )
554
- self.mInsKeywords.addAction(self.mInsKWItems[keyWord][0])
570
+ for key in nwKeyWords.ALL_KEYS:
571
+ action = self.mInsKeywords.addAction(trConst(nwLabels.KEY_NAME[key]))
572
+ action.setShortcut(nwLabels.KEY_SHORTCUT[key])
573
+ action.triggered.connect(qtLambda(self.requestDocKeyWordInsert.emit, key))
574
+ self.mainGui.addAction(action)
555
575
 
556
576
  # Insert > Special Comments
557
577
  self.mInsComments = self.insMenu.addMenu(self.tr("Special Comments"))
@@ -562,6 +582,7 @@ class GuiMainMenu(QMenuBar):
562
582
  self.aInsSynopsis.triggered.connect(
563
583
  lambda: self.requestDocInsert.emit(nwDocInsert.SYNOPSIS)
564
584
  )
585
+ self.mainGui.addAction(self.aInsSynopsis)
565
586
 
566
587
  # Insert > Short Description Comment
567
588
  self.aInsShort = self.mInsComments.addAction(self.tr("Short Description Comment"))
@@ -569,9 +590,17 @@ class GuiMainMenu(QMenuBar):
569
590
  self.aInsShort.triggered.connect(
570
591
  lambda: self.requestDocInsert.emit(nwDocInsert.SHORT)
571
592
  )
593
+ self.mainGui.addAction(self.aInsShort)
572
594
 
573
- # Insert > Symbols
574
- self.mInsBreaks = self.insMenu.addMenu(self.tr("Page Break and Space"))
595
+ # Insert > Word/Character Count
596
+ self.mInsField = self.insMenu.addMenu(self.tr("Word/Character Count"))
597
+ for field in nwStats.ALL_FIELDS:
598
+ value = nwShortcode.FIELD_VALUE.format(field)
599
+ action = self.mInsField.addAction(trConst(nwLabels.STATS_NAME[field]))
600
+ action.triggered.connect(qtLambda(self.requestDocInsertText.emit, value))
601
+
602
+ # Insert > Breaks and Vertical Space
603
+ self.mInsBreaks = self.insMenu.addMenu(self.tr("Breaks and Vertical Space"))
575
604
 
576
605
  # Insert > New Page
577
606
  self.aInsNewPage = self.mInsBreaks.addAction(self.tr("Page Break"))
@@ -579,6 +608,12 @@ class GuiMainMenu(QMenuBar):
579
608
  lambda: self.requestDocInsert.emit(nwDocInsert.NEW_PAGE)
580
609
  )
581
610
 
611
+ # Insert > Forced Line Break
612
+ self.aInsLineBreak = self.mInsBreaks.addAction(self.tr("Forced Line Break"))
613
+ self.aInsLineBreak.triggered.connect(
614
+ lambda: self.requestDocInsert.emit(nwDocInsert.LINE_BRK)
615
+ )
616
+
582
617
  # Insert > Vertical Space (Single)
583
618
  self.aInsVSpaceS = self.mInsBreaks.addAction(self.tr("Vertical Space (Single)"))
584
619
  self.aInsVSpaceS.triggered.connect(
@@ -616,6 +651,7 @@ class GuiMainMenu(QMenuBar):
616
651
  self.aFmtBold.triggered.connect(
617
652
  lambda: self.requestDocAction.emit(nwDocAction.MD_BOLD)
618
653
  )
654
+ self.mainGui.addAction(self.aFmtBold)
619
655
 
620
656
  # Format > Italic
621
657
  self.aFmtItalic = self.fmtMenu.addAction(self.tr("Italic"))
@@ -623,6 +659,7 @@ class GuiMainMenu(QMenuBar):
623
659
  self.aFmtItalic.triggered.connect(
624
660
  lambda: self.requestDocAction.emit(nwDocAction.MD_ITALIC)
625
661
  )
662
+ self.mainGui.addAction(self.aFmtItalic)
626
663
 
627
664
  # Format > Strikethrough
628
665
  self.aFmtStrike = self.fmtMenu.addAction(self.tr("Strikethrough"))
@@ -630,6 +667,7 @@ class GuiMainMenu(QMenuBar):
630
667
  self.aFmtStrike.triggered.connect(
631
668
  lambda: self.requestDocAction.emit(nwDocAction.MD_STRIKE)
632
669
  )
670
+ self.mainGui.addAction(self.aFmtStrike)
633
671
 
634
672
  # Edit > Separator
635
673
  self.fmtMenu.addSeparator()
@@ -640,6 +678,7 @@ class GuiMainMenu(QMenuBar):
640
678
  self.aFmtDQuote.triggered.connect(
641
679
  lambda: self.requestDocAction.emit(nwDocAction.D_QUOTE)
642
680
  )
681
+ self.mainGui.addAction(self.aFmtDQuote)
643
682
 
644
683
  # Format > Single Quotes
645
684
  self.aFmtSQuote = self.fmtMenu.addAction(self.tr("Wrap Single Quotes"))
@@ -647,6 +686,7 @@ class GuiMainMenu(QMenuBar):
647
686
  self.aFmtSQuote.triggered.connect(
648
687
  lambda: self.requestDocAction.emit(nwDocAction.S_QUOTE)
649
688
  )
689
+ self.mainGui.addAction(self.aFmtSQuote)
650
690
 
651
691
  # Format > Separator
652
692
  self.fmtMenu.addSeparator()
@@ -700,32 +740,36 @@ class GuiMainMenu(QMenuBar):
700
740
  self.fmtMenu.addSeparator()
701
741
 
702
742
  # Format > Heading 1 (Partition)
703
- self.aFmtHead1 = self.fmtMenu.addAction(self.tr("Heading 1 (Partition)"))
743
+ self.aFmtHead1 = self.fmtMenu.addAction(trConst(nwStyles.T_LABEL["H1"]))
704
744
  self.aFmtHead1.setShortcut("Ctrl+1")
705
745
  self.aFmtHead1.triggered.connect(
706
746
  lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H1)
707
747
  )
748
+ self.mainGui.addAction(self.aFmtHead1)
708
749
 
709
750
  # Format > Heading 2 (Chapter)
710
- self.aFmtHead2 = self.fmtMenu.addAction(self.tr("Heading 2 (Chapter)"))
751
+ self.aFmtHead2 = self.fmtMenu.addAction(trConst(nwStyles.T_LABEL["H2"]))
711
752
  self.aFmtHead2.setShortcut("Ctrl+2")
712
753
  self.aFmtHead2.triggered.connect(
713
754
  lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H2)
714
755
  )
756
+ self.mainGui.addAction(self.aFmtHead2)
715
757
 
716
758
  # Format > Heading 3 (Scene)
717
- self.aFmtHead3 = self.fmtMenu.addAction(self.tr("Heading 3 (Scene)"))
759
+ self.aFmtHead3 = self.fmtMenu.addAction(trConst(nwStyles.T_LABEL["H3"]))
718
760
  self.aFmtHead3.setShortcut("Ctrl+3")
719
761
  self.aFmtHead3.triggered.connect(
720
762
  lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H3)
721
763
  )
764
+ self.mainGui.addAction(self.aFmtHead3)
722
765
 
723
766
  # Format > Heading 4 (Section)
724
- self.aFmtHead4 = self.fmtMenu.addAction(self.tr("Heading 4 (Section)"))
767
+ self.aFmtHead4 = self.fmtMenu.addAction(trConst(nwStyles.T_LABEL["H4"]))
725
768
  self.aFmtHead4.setShortcut("Ctrl+4")
726
769
  self.aFmtHead4.triggered.connect(
727
770
  lambda: self.requestDocAction.emit(nwDocAction.BLOCK_H4)
728
771
  )
772
+ self.mainGui.addAction(self.aFmtHead4)
729
773
 
730
774
  # Format > Separator
731
775
  self.fmtMenu.addSeparator()
@@ -757,6 +801,7 @@ class GuiMainMenu(QMenuBar):
757
801
  self.aFmtAlignLeft.triggered.connect(
758
802
  lambda: self.requestDocAction.emit(nwDocAction.ALIGN_L)
759
803
  )
804
+ self.mainGui.addAction(self.aFmtAlignLeft)
760
805
 
761
806
  # Format > Align Centre
762
807
  self.aFmtAlignCentre = self.fmtMenu.addAction(self.tr("Align Centre"))
@@ -764,6 +809,7 @@ class GuiMainMenu(QMenuBar):
764
809
  self.aFmtAlignCentre.triggered.connect(
765
810
  lambda: self.requestDocAction.emit(nwDocAction.ALIGN_C)
766
811
  )
812
+ self.mainGui.addAction(self.aFmtAlignCentre)
767
813
 
768
814
  # Format > Align Right
769
815
  self.aFmtAlignRight = self.fmtMenu.addAction(self.tr("Align Right"))
@@ -771,6 +817,7 @@ class GuiMainMenu(QMenuBar):
771
817
  self.aFmtAlignRight.triggered.connect(
772
818
  lambda: self.requestDocAction.emit(nwDocAction.ALIGN_R)
773
819
  )
820
+ self.mainGui.addAction(self.aFmtAlignRight)
774
821
 
775
822
  # Format > Separator
776
823
  self.fmtMenu.addSeparator()
@@ -781,6 +828,7 @@ class GuiMainMenu(QMenuBar):
781
828
  self.aFmtIndentLeft.triggered.connect(
782
829
  lambda: self.requestDocAction.emit(nwDocAction.INDENT_L)
783
830
  )
831
+ self.mainGui.addAction(self.aFmtIndentLeft)
784
832
 
785
833
  # Format > Indent Right
786
834
  self.aFmtIndentRight = self.fmtMenu.addAction(self.tr("Indent Right"))
@@ -788,6 +836,7 @@ class GuiMainMenu(QMenuBar):
788
836
  self.aFmtIndentRight.triggered.connect(
789
837
  lambda: self.requestDocAction.emit(nwDocAction.INDENT_R)
790
838
  )
839
+ self.mainGui.addAction(self.aFmtIndentRight)
791
840
 
792
841
  # Format > Separator
793
842
  self.fmtMenu.addSeparator()
@@ -798,6 +847,7 @@ class GuiMainMenu(QMenuBar):
798
847
  self.aFmtComment.triggered.connect(
799
848
  lambda: self.requestDocAction.emit(nwDocAction.BLOCK_COM)
800
849
  )
850
+ self.mainGui.addAction(self.aFmtComment)
801
851
 
802
852
  # Format > Ignore Text
803
853
  self.aFmtIgnore = self.fmtMenu.addAction(self.tr("Toggle Ignore Text"))
@@ -812,6 +862,7 @@ class GuiMainMenu(QMenuBar):
812
862
  self.aFmtNoFormat.triggered.connect(
813
863
  lambda: self.requestDocAction.emit(nwDocAction.BLOCK_TXT)
814
864
  )
865
+ self.mainGui.addAction(self.aFmtNoFormat)
815
866
 
816
867
  # Format > Separator
817
868
  self.fmtMenu.addSeparator()
@@ -844,29 +895,34 @@ class GuiMainMenu(QMenuBar):
844
895
  # Search > Find
845
896
  self.aFind = self.srcMenu.addAction(self.tr("Find"))
846
897
  self.aFind.setShortcut("Ctrl+F")
847
- self.aFind.triggered.connect(lambda: self.mainGui.docEditor.beginSearch())
898
+ self.aFind.triggered.connect(qtLambda(self.mainGui.docEditor.beginSearch))
899
+ self.mainGui.addAction(self.aFind)
848
900
 
849
901
  # Search > Replace
850
902
  self.aReplace = self.srcMenu.addAction(self.tr("Replace"))
851
903
  self.aReplace.setShortcut("Ctrl+=" if CONFIG.osDarwin else "Ctrl+H")
852
- self.aReplace.triggered.connect(lambda: self.mainGui.docEditor.beginReplace())
904
+ self.aReplace.triggered.connect(qtLambda(self.mainGui.docEditor.beginReplace))
905
+ self.mainGui.addAction(self.aReplace)
853
906
 
854
907
  # Search > Find Next
855
908
  self.aFindNext = self.srcMenu.addAction(self.tr("Find Next"))
856
909
  self.aFindNext.setShortcuts(["Ctrl+G", "F3"] if CONFIG.osDarwin else ["F3", "Ctrl+G"])
857
- self.aFindNext.triggered.connect(lambda: self.mainGui.docEditor.findNext())
910
+ self.aFindNext.triggered.connect(qtLambda(self.mainGui.docEditor.findNext))
911
+ self.mainGui.addAction(self.aFindNext)
858
912
 
859
913
  # Search > Find Prev
860
914
  self.aFindPrev = self.srcMenu.addAction(self.tr("Find Previous"))
861
915
  self.aFindPrev.setShortcuts(
862
916
  ["Ctrl+Shift+G", "Shift+F3"] if CONFIG.osDarwin else ["Shift+F3", "Ctrl+Shift+G"]
863
917
  )
864
- self.aFindPrev.triggered.connect(lambda: self.mainGui.docEditor.findNext(goBack=True))
918
+ self.aFindPrev.triggered.connect(qtLambda(self.mainGui.docEditor.findNext, goBack=True))
919
+ self.mainGui.addAction(self.aFindPrev)
865
920
 
866
921
  # Search > Replace Next
867
922
  self.aReplaceNext = self.srcMenu.addAction(self.tr("Replace Next"))
868
923
  self.aReplaceNext.setShortcut("Ctrl+Shift+1")
869
- self.aReplaceNext.triggered.connect(lambda: self.mainGui.docEditor.replaceNext())
924
+ self.aReplaceNext.triggered.connect(qtLambda(self.mainGui.docEditor.replaceNext))
925
+ self.mainGui.addAction(self.aReplaceNext)
870
926
 
871
927
  # Search > Separator
872
928
  self.srcMenu.addSeparator()
@@ -889,6 +945,7 @@ class GuiMainMenu(QMenuBar):
889
945
  self.aSpellCheck.setChecked(SHARED.project.data.spellCheck)
890
946
  self.aSpellCheck.triggered.connect(self._toggleSpellCheck) # triggered, not toggled!
891
947
  self.aSpellCheck.setShortcut("Ctrl+F7")
948
+ self.mainGui.addAction(self.aSpellCheck)
892
949
 
893
950
  self.mSelectLanguage = self.toolsMenu.addMenu(self.tr("Spell Check Language"))
894
951
  languages = SHARED.spelling.listDictionaries()
@@ -902,7 +959,8 @@ class GuiMainMenu(QMenuBar):
902
959
  # Tools > Re-Run Spell Check
903
960
  self.aReRunSpell = self.toolsMenu.addAction(self.tr("Re-Run Spell Check"))
904
961
  self.aReRunSpell.setShortcut("F7")
905
- self.aReRunSpell.triggered.connect(lambda: self.mainGui.docEditor.spellCheckDocument())
962
+ self.aReRunSpell.triggered.connect(qtLambda(self.mainGui.docEditor.spellCheckDocument))
963
+ self.mainGui.addAction(self.aReRunSpell)
906
964
 
907
965
  # Tools > Project Word List
908
966
  self.aEditWordList = self.toolsMenu.addAction(self.tr("Project Word List"))
@@ -919,14 +977,14 @@ class GuiMainMenu(QMenuBar):
919
977
  # Tools > Rebuild Index
920
978
  self.aRebuildIndex = self.toolsMenu.addAction(self.tr("Rebuild Index"))
921
979
  self.aRebuildIndex.setShortcut("F9")
922
- self.aRebuildIndex.triggered.connect(lambda: self.mainGui.rebuildIndex())
980
+ self.aRebuildIndex.triggered.connect(qtLambda(self.mainGui.rebuildIndex))
923
981
 
924
982
  # Tools > Separator
925
983
  self.toolsMenu.addSeparator()
926
984
 
927
985
  # Tools > Backup Project
928
986
  self.aBackupProject = self.toolsMenu.addAction(self.tr("Backup Project"))
929
- self.aBackupProject.triggered.connect(lambda: SHARED.project.backupProject(True))
987
+ self.aBackupProject.triggered.connect(qtLambda(SHARED.project.backupProject, True))
930
988
 
931
989
  # Tools > Build Manuscript
932
990
  self.aBuildManuscript = self.toolsMenu.addAction(self.tr("Build Manuscript"))
@@ -941,8 +999,9 @@ class GuiMainMenu(QMenuBar):
941
999
  # Tools > Preferences
942
1000
  self.aPreferences = self.toolsMenu.addAction(self.tr("Preferences"))
943
1001
  self.aPreferences.setShortcut("Ctrl+,")
944
- self.aPreferences.setMenuRole(QAction.PreferencesRole)
1002
+ self.aPreferences.setMenuRole(QAction.MenuRole.PreferencesRole)
945
1003
  self.aPreferences.triggered.connect(self.mainGui.showPreferencesDialog)
1004
+ self.mainGui.addAction(self.aPreferences)
946
1005
 
947
1006
  return
948
1007
 
@@ -953,12 +1012,12 @@ class GuiMainMenu(QMenuBar):
953
1012
 
954
1013
  # Help > About
955
1014
  self.aAboutNW = self.helpMenu.addAction(self.tr("About novelWriter"))
956
- self.aAboutNW.setMenuRole(QAction.AboutRole)
1015
+ self.aAboutNW.setMenuRole(QAction.MenuRole.AboutRole)
957
1016
  self.aAboutNW.triggered.connect(self.mainGui.showAboutNWDialog)
958
1017
 
959
1018
  # Help > About Qt5
960
1019
  self.aAboutQt = self.helpMenu.addAction(self.tr("About Qt5"))
961
- self.aAboutQt.setMenuRole(QAction.AboutQtRole)
1020
+ self.aAboutQt.setMenuRole(QAction.MenuRole.AboutQtRole)
962
1021
  self.aAboutQt.triggered.connect(self.mainGui.showAboutQtDialog)
963
1022
 
964
1023
  # Help > Separator
@@ -967,27 +1026,29 @@ class GuiMainMenu(QMenuBar):
967
1026
  # Help > User Manual (Online)
968
1027
  self.aHelpDocs = self.helpMenu.addAction(self.tr("User Manual (Online)"))
969
1028
  self.aHelpDocs.setShortcut("F1")
970
- self.aHelpDocs.triggered.connect(lambda: self._openWebsite(nwConst.URL_DOCS))
1029
+ self.aHelpDocs.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_DOCS))
1030
+ self.mainGui.addAction(self.aHelpDocs)
971
1031
 
972
1032
  # Help > User Manual (PDF)
973
1033
  if isinstance(CONFIG.pdfDocs, Path):
974
1034
  self.aPdfDocs = self.helpMenu.addAction(self.tr("User Manual (PDF)"))
975
1035
  self.aPdfDocs.setShortcut("Shift+F1")
976
1036
  self.aPdfDocs.triggered.connect(self._openUserManualFile)
1037
+ self.mainGui.addAction(self.aPdfDocs)
977
1038
 
978
1039
  # Help > Separator
979
1040
  self.helpMenu.addSeparator()
980
1041
 
981
1042
  # Document > Report an Issue
982
1043
  self.aIssue = self.helpMenu.addAction(self.tr("Report an Issue (GitHub)"))
983
- self.aIssue.triggered.connect(lambda: self._openWebsite(nwConst.URL_REPORT))
1044
+ self.aIssue.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_REPORT))
984
1045
 
985
1046
  # Document > Ask a Question
986
1047
  self.aQuestion = self.helpMenu.addAction(self.tr("Ask a Question (GitHub)"))
987
- self.aQuestion.triggered.connect(lambda: self._openWebsite(nwConst.URL_HELP))
1048
+ self.aQuestion.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_HELP))
988
1049
 
989
1050
  # Document > Main Website
990
1051
  self.aWebsite = self.helpMenu.addAction(self.tr("The novelWriter Website"))
991
- self.aWebsite.triggered.connect(lambda: self._openWebsite(nwConst.URL_WEB))
1052
+ self.aWebsite.triggered.connect(qtLambda(SHARED.openWebsite, nwConst.URL_WEB))
992
1053
 
993
1054
  return