novelWriter 2.5.2__py3-none-any.whl → 2.6__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 (129) hide show
  1. {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/METADATA +5 -4
  2. {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/RECORD +126 -105
  3. {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/WHEEL +1 -1
  4. novelwriter/__init__.py +50 -11
  5. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  6. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  7. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  8. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  9. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  10. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  11. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  12. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  13. novelwriter/assets/i18n/nw_pl_PL.qm +0 -0
  14. novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
  15. novelwriter/assets/i18n/nw_ru_RU.qm +0 -0
  16. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  17. novelwriter/assets/i18n/project_de_DE.json +4 -2
  18. novelwriter/assets/i18n/project_en_GB.json +1 -0
  19. novelwriter/assets/i18n/project_en_US.json +2 -0
  20. novelwriter/assets/i18n/project_it_IT.json +2 -0
  21. novelwriter/assets/i18n/project_ja_JP.json +2 -0
  22. novelwriter/assets/i18n/project_nb_NO.json +2 -0
  23. novelwriter/assets/i18n/project_nl_NL.json +2 -0
  24. novelwriter/assets/i18n/project_pl_PL.json +2 -0
  25. novelwriter/assets/i18n/project_pt_BR.json +2 -0
  26. novelwriter/assets/i18n/project_ru_RU.json +11 -0
  27. novelwriter/assets/i18n/project_zh_CN.json +2 -0
  28. novelwriter/assets/icons/typicons_dark/icons.conf +8 -0
  29. novelwriter/assets/icons/typicons_dark/mixed_copy.svg +4 -0
  30. novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +6 -0
  31. novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +6 -0
  32. novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +6 -0
  33. novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +6 -0
  34. novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +6 -0
  35. novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +6 -0
  36. novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +5 -0
  37. novelwriter/assets/icons/typicons_light/icons.conf +8 -0
  38. novelwriter/assets/icons/typicons_light/mixed_copy.svg +4 -0
  39. novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +6 -0
  40. novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +6 -0
  41. novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +6 -0
  42. novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +6 -0
  43. novelwriter/assets/icons/typicons_light/mixed_size-height.svg +6 -0
  44. novelwriter/assets/icons/typicons_light/mixed_size-width.svg +6 -0
  45. novelwriter/assets/icons/typicons_light/nw_toolbar.svg +5 -0
  46. novelwriter/assets/manual.pdf +0 -0
  47. novelwriter/assets/sample.zip +0 -0
  48. novelwriter/assets/text/credits_en.htm +1 -0
  49. novelwriter/assets/themes/default_light.conf +2 -2
  50. novelwriter/common.py +101 -3
  51. novelwriter/config.py +30 -17
  52. novelwriter/constants.py +189 -81
  53. novelwriter/core/buildsettings.py +74 -40
  54. novelwriter/core/coretools.py +146 -148
  55. novelwriter/core/docbuild.py +133 -171
  56. novelwriter/core/document.py +1 -1
  57. novelwriter/core/index.py +39 -38
  58. novelwriter/core/item.py +42 -9
  59. novelwriter/core/itemmodel.py +518 -0
  60. novelwriter/core/options.py +5 -2
  61. novelwriter/core/project.py +68 -90
  62. novelwriter/core/projectdata.py +8 -2
  63. novelwriter/core/projectxml.py +1 -1
  64. novelwriter/core/sessions.py +1 -1
  65. novelwriter/core/spellcheck.py +10 -15
  66. novelwriter/core/status.py +24 -8
  67. novelwriter/core/storage.py +1 -1
  68. novelwriter/core/tree.py +269 -288
  69. novelwriter/dialogs/about.py +1 -1
  70. novelwriter/dialogs/docmerge.py +8 -18
  71. novelwriter/dialogs/docsplit.py +1 -1
  72. novelwriter/dialogs/editlabel.py +1 -1
  73. novelwriter/dialogs/preferences.py +47 -34
  74. novelwriter/dialogs/projectsettings.py +149 -99
  75. novelwriter/dialogs/quotes.py +1 -1
  76. novelwriter/dialogs/wordlist.py +11 -10
  77. novelwriter/enum.py +37 -24
  78. novelwriter/error.py +2 -2
  79. novelwriter/extensions/configlayout.py +28 -13
  80. novelwriter/extensions/eventfilters.py +1 -1
  81. novelwriter/extensions/modified.py +30 -6
  82. novelwriter/extensions/novelselector.py +4 -3
  83. novelwriter/extensions/pagedsidebar.py +9 -9
  84. novelwriter/extensions/progressbars.py +4 -4
  85. novelwriter/extensions/statusled.py +3 -3
  86. novelwriter/extensions/switch.py +3 -3
  87. novelwriter/extensions/switchbox.py +1 -1
  88. novelwriter/extensions/versioninfo.py +1 -1
  89. novelwriter/formats/shared.py +156 -0
  90. novelwriter/formats/todocx.py +1191 -0
  91. novelwriter/formats/tohtml.py +454 -0
  92. novelwriter/{core → formats}/tokenizer.py +497 -495
  93. novelwriter/formats/tomarkdown.py +218 -0
  94. novelwriter/{core → formats}/toodt.py +312 -433
  95. novelwriter/formats/toqdoc.py +486 -0
  96. novelwriter/formats/toraw.py +91 -0
  97. novelwriter/gui/doceditor.py +347 -287
  98. novelwriter/gui/dochighlight.py +97 -85
  99. novelwriter/gui/docviewer.py +90 -33
  100. novelwriter/gui/docviewerpanel.py +18 -26
  101. novelwriter/gui/editordocument.py +18 -3
  102. novelwriter/gui/itemdetails.py +27 -29
  103. novelwriter/gui/mainmenu.py +130 -64
  104. novelwriter/gui/noveltree.py +46 -48
  105. novelwriter/gui/outline.py +202 -256
  106. novelwriter/gui/projtree.py +590 -1238
  107. novelwriter/gui/search.py +11 -19
  108. novelwriter/gui/sidebar.py +8 -7
  109. novelwriter/gui/statusbar.py +20 -3
  110. novelwriter/gui/theme.py +11 -6
  111. novelwriter/guimain.py +101 -201
  112. novelwriter/shared.py +67 -28
  113. novelwriter/text/counting.py +3 -1
  114. novelwriter/text/patterns.py +169 -61
  115. novelwriter/tools/dictionaries.py +3 -3
  116. novelwriter/tools/lipsum.py +1 -1
  117. novelwriter/tools/manusbuild.py +15 -13
  118. novelwriter/tools/manuscript.py +121 -79
  119. novelwriter/tools/manussettings.py +424 -291
  120. novelwriter/tools/noveldetails.py +1 -1
  121. novelwriter/tools/welcome.py +6 -6
  122. novelwriter/tools/writingstats.py +4 -4
  123. novelwriter/types.py +25 -9
  124. novelwriter/core/tohtml.py +0 -530
  125. novelwriter/core/tomarkdown.py +0 -252
  126. novelwriter/core/toqdoc.py +0 -419
  127. {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/LICENSE.md +0 -0
  128. {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/entry_points.txt +0 -0
  129. {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/top_level.txt +0 -0
@@ -8,7 +8,7 @@ Created: 2022-06-12 [2.0rc1] GuiNovelView
8
8
  Created: 2022-06-12 [2.0rc1] GuiNovelToolBar
9
9
 
10
10
  This file is a part of novelWriter
11
- Copyright 2018–2024, Veronica Berglyd Olsen
11
+ Copyright (C) 2020 Veronica Berglyd Olsen and novelWriter contributors
12
12
 
13
13
  This program is free software: you can redistribute it and/or modify
14
14
  it under the terms of the GNU General Public License as published by
@@ -33,22 +33,22 @@ from time import time
33
33
  from PyQt5.QtCore import QModelIndex, QPoint, Qt, pyqtSignal, pyqtSlot
34
34
  from PyQt5.QtGui import QFocusEvent, QFont, QMouseEvent, QPalette, QResizeEvent
35
35
  from PyQt5.QtWidgets import (
36
- QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView,
37
- QInputDialog, QMenu, QToolTip, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
38
- QWidget
36
+ QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QInputDialog, QMenu,
37
+ QToolTip, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
39
38
  )
40
39
 
41
40
  from novelwriter import CONFIG, SHARED
42
- from novelwriter.common import minmax
43
- from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst
41
+ from novelwriter.common import minmax, qtLambda
42
+ from novelwriter.constants import nwKeyWords, nwLabels, nwStyles, trConst
44
43
  from novelwriter.core.index import IndexHeading
45
- from novelwriter.enum import nwDocMode, nwItemClass, nwOutline
44
+ from novelwriter.enum import nwChange, nwDocMode, nwItemClass, nwOutline
46
45
  from novelwriter.extensions.modified import NIconToolButton
47
46
  from novelwriter.extensions.novelselector import NovelSelector
48
47
  from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
49
48
  from novelwriter.types import (
50
- QtAlignRight, QtDecoration, QtMouseLeft, QtMouseMiddle, QtSizeExpanding,
51
- QtUserRole
49
+ QtAlignRight, QtDecoration, QtHeaderStretch, QtHeaderToContents,
50
+ QtMouseLeft, QtMouseMiddle, QtScrollAlwaysOff, QtScrollAsNeeded,
51
+ QtSizeExpanding, QtUserRole
52
52
  )
53
53
 
54
54
  logger = logging.getLogger(__name__)
@@ -87,7 +87,6 @@ class GuiNovelView(QWidget):
87
87
 
88
88
  # Function Mappings
89
89
  self.getSelectedHandle = self.novelTree.getSelectedHandle
90
- self.setActiveHandle = self.novelTree.setActiveHandle
91
90
 
92
91
  return
93
92
 
@@ -163,14 +162,20 @@ class GuiNovelView(QWidget):
163
162
  # Public Slots
164
163
  ##
165
164
 
165
+ @pyqtSlot(str)
166
+ def setActiveHandle(self, tHandle: str) -> None:
167
+ """Highlight the rows associated with a given handle."""
168
+ self.novelTree.setActiveHandle(tHandle)
169
+ return
170
+
166
171
  @pyqtSlot()
167
172
  def refreshTree(self) -> None:
168
173
  """Refresh the current tree."""
169
174
  self.novelTree.refreshTree(rootHandle=SHARED.project.data.getLastHandle("novelTree"))
170
175
  return
171
176
 
172
- @pyqtSlot(str)
173
- def updateRootItem(self, tHandle: str) -> None:
177
+ @pyqtSlot(str, Enum)
178
+ def updateRootItem(self, tHandle: str, change: nwChange) -> None:
174
179
  """If any root item changes, rebuild the novel root menu."""
175
180
  self.novelBar.buildNovelRootMenu()
176
181
  return
@@ -341,7 +346,7 @@ class GuiNovelToolBar(QWidget):
341
346
  aLast = self.mLastCol.addAction(actionLabel)
342
347
  aLast.setCheckable(True)
343
348
  aLast.setActionGroup(self.gLastCol)
344
- aLast.triggered.connect(lambda: self.setLastColType(colType))
349
+ aLast.triggered.connect(qtLambda(self.setLastColType, colType))
345
350
  self.aLastCol[colType] = aLast
346
351
  return
347
352
 
@@ -367,11 +372,11 @@ class GuiNovelTree(QTreeWidget):
367
372
  self.novelView = novelView
368
373
 
369
374
  # Internal Variables
370
- self._treeMap = {}
371
375
  self._lastBuild = 0
372
376
  self._lastCol = NovelTreeColumn.POV
373
377
  self._lastColSize = 0.25
374
378
  self._actHandle = None
379
+ self._treeMap: dict[str, QTreeWidgetItem] = {}
375
380
 
376
381
  # Cached Strings
377
382
  self._povLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY])
@@ -401,10 +406,10 @@ class GuiNovelTree(QTreeWidget):
401
406
  treeHeader = self.header()
402
407
  treeHeader.setStretchLastSection(False)
403
408
  treeHeader.setMinimumSectionSize(iPx + cMg)
404
- treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.ResizeMode.Stretch)
405
- treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeMode.ResizeToContents)
406
- treeHeader.setSectionResizeMode(self.C_EXTRA, QHeaderView.ResizeMode.ResizeToContents)
407
- treeHeader.setSectionResizeMode(self.C_MORE, QHeaderView.ResizeMode.ResizeToContents)
409
+ treeHeader.setSectionResizeMode(self.C_TITLE, QtHeaderStretch)
410
+ treeHeader.setSectionResizeMode(self.C_WORDS, QtHeaderToContents)
411
+ treeHeader.setSectionResizeMode(self.C_EXTRA, QtHeaderToContents)
412
+ treeHeader.setSectionResizeMode(self.C_MORE, QtHeaderToContents)
408
413
 
409
414
  # Pre-Generate Tree Formatting
410
415
  fH1 = self.font()
@@ -433,14 +438,14 @@ class GuiNovelTree(QTreeWidget):
433
438
  """Set or update tree widget settings."""
434
439
  # Scroll bars
435
440
  if CONFIG.hideVScroll:
436
- self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
441
+ self.setVerticalScrollBarPolicy(QtScrollAlwaysOff)
437
442
  else:
438
- self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
443
+ self.setVerticalScrollBarPolicy(QtScrollAsNeeded)
439
444
 
440
445
  if CONFIG.hideHScroll:
441
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
446
+ self.setHorizontalScrollBarPolicy(QtScrollAlwaysOff)
442
447
  else:
443
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
448
+ self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
444
449
 
445
450
  return
446
451
 
@@ -479,16 +484,9 @@ class GuiNovelTree(QTreeWidget):
479
484
  if rootHandle is None:
480
485
  rootHandle = SHARED.project.tree.findRoot(nwItemClass.NOVEL)
481
486
 
482
- treeChanged = SHARED.mainGui.projView.changedSince(self._lastBuild)
483
- indexChanged = SHARED.project.index.rootChangedSince(rootHandle, self._lastBuild)
484
- if not (treeChanged or indexChanged or overRide):
485
- logger.debug("No changes have been made to the novel index")
486
- return
487
-
488
- selItem = self.selectedItems()
489
487
  titleKey = None
490
- if selItem:
491
- titleKey = selItem[0].data(self.C_DATA, self.D_KEY)
488
+ if selItems := self.selectedItems():
489
+ titleKey = selItems[0].data(self.C_DATA, self.D_KEY)
492
490
 
493
491
  self._populateTree(rootHandle)
494
492
  SHARED.project.data.setLastHandle(rootHandle, "novelTree")
@@ -540,25 +538,25 @@ class GuiNovelTree(QTreeWidget):
540
538
  self._lastColSize = minmax(colSize, 15, 75)/100.0
541
539
  return
542
540
 
543
- def setActiveHandle(self, tHandle: str | None, doScroll: bool = False) -> None:
541
+ def setActiveHandle(self, tHandle: str | None) -> None:
544
542
  """Highlight the rows associated with a given handle."""
545
543
  didScroll = False
546
- self._actHandle = tHandle
547
- for i in range(self.topLevelItemCount()):
548
- if tItem := self.topLevelItem(i):
549
- if tItem.data(self.C_DATA, self.D_HANDLE) == tHandle:
550
- tItem.setBackground(self.C_TITLE, self.palette().alternateBase())
551
- tItem.setBackground(self.C_WORDS, self.palette().alternateBase())
552
- tItem.setBackground(self.C_EXTRA, self.palette().alternateBase())
553
- tItem.setBackground(self.C_MORE, self.palette().alternateBase())
554
- if doScroll and not didScroll:
555
- self.scrollToItem(tItem, QAbstractItemView.ScrollHint.PositionAtCenter)
544
+ brushOn = self.palette().alternateBase()
545
+ brushOff = self.palette().base()
546
+ if pHandle := self._actHandle:
547
+ for key, item in self._treeMap.items():
548
+ if key.startswith(pHandle):
549
+ for i in range(self.columnCount()):
550
+ item.setBackground(i, brushOff)
551
+ if tHandle:
552
+ for key, item in self._treeMap.items():
553
+ if key.startswith(tHandle):
554
+ for i in range(self.columnCount()):
555
+ item.setBackground(i, brushOn)
556
+ if not didScroll:
557
+ self.scrollToItem(item, QAbstractItemView.ScrollHint.PositionAtCenter)
556
558
  didScroll = True
557
- else:
558
- tItem.setBackground(self.C_TITLE, self.palette().base())
559
- tItem.setBackground(self.C_WORDS, self.palette().base())
560
- tItem.setBackground(self.C_EXTRA, self.palette().base())
561
- tItem.setBackground(self.C_MORE, self.palette().base())
559
+ self._actHandle = tHandle or None
562
560
  return
563
561
 
564
562
  ##
@@ -683,7 +681,7 @@ class GuiNovelTree(QTreeWidget):
683
681
  def _updateTreeItemValues(self, trItem: QTreeWidgetItem, idxItem: IndexHeading,
684
682
  tHandle: str, sTitle: str) -> None:
685
683
  """Set the tree item values from the index entry."""
686
- iLevel = nwHeaders.H_LEVEL.get(idxItem.level, 0)
684
+ iLevel = nwStyles.H_LEVEL.get(idxItem.level, 0)
687
685
  hDec = SHARED.theme.getHeaderDecoration(iLevel)
688
686
 
689
687
  trItem.setData(self.C_TITLE, QtDecoration, hDec)