novelWriter 2.4b1__py3-none-any.whl → 2.4.1__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 (89) hide show
  1. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/METADATA +5 -6
  2. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/RECORD +79 -83
  3. novelwriter/__init__.py +15 -8
  4. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  5. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  6. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  7. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  8. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  9. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  10. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  11. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  12. novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
  13. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  14. novelwriter/assets/icons/none.svg +4 -0
  15. novelwriter/assets/icons/typicons_dark/icons.conf +2 -2
  16. novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +4 -0
  17. novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +4 -0
  18. novelwriter/assets/icons/typicons_light/icons.conf +2 -2
  19. novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +4 -0
  20. novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +4 -0
  21. novelwriter/assets/manual.pdf +0 -0
  22. novelwriter/assets/sample.zip +0 -0
  23. novelwriter/common.py +11 -3
  24. novelwriter/config.py +12 -4
  25. novelwriter/core/buildsettings.py +7 -7
  26. novelwriter/core/coretools.py +21 -22
  27. novelwriter/core/docbuild.py +2 -2
  28. novelwriter/core/projectxml.py +1 -1
  29. novelwriter/core/spellcheck.py +3 -3
  30. novelwriter/core/status.py +3 -2
  31. novelwriter/core/tokenizer.py +3 -3
  32. novelwriter/core/toodt.py +333 -356
  33. novelwriter/dialogs/about.py +9 -11
  34. novelwriter/dialogs/docmerge.py +17 -14
  35. novelwriter/dialogs/docsplit.py +14 -12
  36. novelwriter/dialogs/editlabel.py +5 -4
  37. novelwriter/dialogs/preferences.py +29 -34
  38. novelwriter/dialogs/projectsettings.py +31 -28
  39. novelwriter/dialogs/quotes.py +10 -9
  40. novelwriter/dialogs/wordlist.py +17 -14
  41. novelwriter/error.py +14 -12
  42. novelwriter/extensions/circularprogress.py +12 -8
  43. novelwriter/extensions/configlayout.py +1 -3
  44. novelwriter/extensions/modified.py +33 -2
  45. novelwriter/extensions/pagedsidebar.py +16 -14
  46. novelwriter/extensions/simpleprogress.py +3 -1
  47. novelwriter/extensions/statusled.py +3 -1
  48. novelwriter/extensions/switch.py +10 -9
  49. novelwriter/extensions/switchbox.py +14 -13
  50. novelwriter/gui/doceditor.py +205 -246
  51. novelwriter/gui/dochighlight.py +26 -9
  52. novelwriter/gui/docviewer.py +55 -59
  53. novelwriter/gui/docviewerpanel.py +16 -13
  54. novelwriter/gui/editordocument.py +4 -4
  55. novelwriter/gui/itemdetails.py +45 -48
  56. novelwriter/gui/mainmenu.py +2 -2
  57. novelwriter/gui/noveltree.py +23 -21
  58. novelwriter/gui/outline.py +93 -94
  59. novelwriter/gui/projtree.py +32 -30
  60. novelwriter/gui/search.py +75 -29
  61. novelwriter/gui/sidebar.py +24 -28
  62. novelwriter/gui/statusbar.py +14 -14
  63. novelwriter/gui/theme.py +61 -39
  64. novelwriter/guimain.py +37 -33
  65. novelwriter/shared.py +21 -9
  66. novelwriter/text/counting.py +1 -0
  67. novelwriter/tools/dictionaries.py +15 -14
  68. novelwriter/tools/lipsum.py +20 -17
  69. novelwriter/tools/manusbuild.py +44 -35
  70. novelwriter/tools/manuscript.py +112 -112
  71. novelwriter/tools/manussettings.py +91 -98
  72. novelwriter/tools/noveldetails.py +20 -18
  73. novelwriter/tools/welcome.py +51 -48
  74. novelwriter/tools/writingstats.py +61 -55
  75. novelwriter/types.py +90 -0
  76. novelwriter/assets/icons/typicons_dark/typ_arrow-down.svg +0 -4
  77. novelwriter/assets/icons/typicons_dark/typ_arrow-right.svg +0 -4
  78. novelwriter/assets/icons/typicons_light/typ_arrow-down.svg +0 -4
  79. novelwriter/assets/icons/typicons_light/typ_arrow-right.svg +0 -4
  80. novelwriter/core/__init__.py +0 -3
  81. novelwriter/dialogs/__init__.py +0 -3
  82. novelwriter/extensions/__init__.py +0 -3
  83. novelwriter/gui/__init__.py +0 -3
  84. novelwriter/text/__init__.py +0 -3
  85. novelwriter/tools/__init__.py +0 -3
  86. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/LICENSE.md +0 -0
  87. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/WHEEL +0 -0
  88. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/entry_points.txt +0 -0
  89. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/top_level.txt +0 -0
@@ -26,19 +26,19 @@ from __future__ import annotations
26
26
  import json
27
27
  import logging
28
28
 
29
+ from datetime import datetime
29
30
  from time import time
30
31
  from typing import TYPE_CHECKING
31
- from datetime import datetime
32
32
 
33
+ from PyQt5.QtCore import Qt, QTimer, QUrl, pyqtSignal, pyqtSlot
33
34
  from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent
34
- from PyQt5.QtCore import QSize, QTimer, QUrl, Qt, pyqtSignal, pyqtSlot
35
+ from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
35
36
  from PyQt5.QtWidgets import (
36
- QAbstractItemView, QDialog, QFormLayout, QGridLayout, QHBoxLayout, QLabel,
37
- QListWidget, QListWidgetItem, QPushButton, QSizePolicy, QSplitter,
38
- QStackedWidget, QTabWidget, QTextBrowser, QTreeWidget, QTreeWidgetItem,
39
- QVBoxLayout, QWidget, qApp
37
+ QAbstractItemView, QApplication, QDialog, QFormLayout, QGridLayout,
38
+ QHBoxLayout, QLabel, QListWidget, QListWidgetItem, QPushButton,
39
+ QSizePolicy, QSplitter, QStackedWidget, QTabWidget, QTextBrowser,
40
+ QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
40
41
  )
41
- from PyQt5.QtPrintSupport import QPrintPreviewDialog, QPrinter
42
42
 
43
43
  from novelwriter import CONFIG, SHARED
44
44
  from novelwriter.common import checkInt, fuzzyTime
@@ -48,10 +48,14 @@ from novelwriter.core.tohtml import ToHtml
48
48
  from novelwriter.core.tokenizer import HeadingFormatter
49
49
  from novelwriter.error import logException
50
50
  from novelwriter.extensions.circularprogress import NProgressCircle
51
- from novelwriter.extensions.modified import NIconToolButton
51
+ from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton
52
52
  from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON
53
53
  from novelwriter.tools.manusbuild import GuiManuscriptBuild
54
54
  from novelwriter.tools.manussettings import GuiBuildSettings
55
+ from novelwriter.types import (
56
+ QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignRight, QtAlignTop,
57
+ QtUserRole
58
+ )
55
59
 
56
60
  if TYPE_CHECKING: # pragma: no cover
57
61
  from novelwriter.guimain import GuiMain
@@ -67,7 +71,7 @@ class GuiManuscript(QDialog):
67
71
  a document directly to disk.
68
72
  """
69
73
 
70
- D_KEY = Qt.ItemDataRole.UserRole
74
+ D_KEY = QtUserRole
71
75
 
72
76
  def __init__(self, mainGui: GuiMain) -> None:
73
77
  super().__init__(parent=mainGui)
@@ -86,7 +90,7 @@ class GuiManuscript(QDialog):
86
90
  self.setMinimumWidth(CONFIG.pxInt(600))
87
91
  self.setMinimumHeight(CONFIG.pxInt(500))
88
92
 
89
- iPx = SHARED.theme.baseIconSize
93
+ iSz = SHARED.theme.baseIconSize
90
94
  wWin = CONFIG.pxInt(900)
91
95
  hWin = CONFIG.pxInt(600)
92
96
 
@@ -100,30 +104,27 @@ class GuiManuscript(QDialog):
100
104
  # ==============
101
105
 
102
106
  qPalette = self.palette()
103
- qPalette.setBrush(QPalette.Window, qPalette.base())
107
+ qPalette.setBrush(QPalette.ColorRole.Window, qPalette.base())
104
108
  self.setPalette(qPalette)
105
109
 
106
110
  buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON)
107
111
 
108
- self.tbAdd = NIconToolButton(self, iPx)
109
- self.tbAdd.setIcon(SHARED.theme.getIcon("add"))
112
+ self.tbAdd = NIconToolButton(self, iSz, "add")
110
113
  self.tbAdd.setToolTip(self.tr("Add New Build"))
111
114
  self.tbAdd.setStyleSheet(buttonStyle)
112
115
  self.tbAdd.clicked.connect(self._createNewBuild)
113
116
 
114
- self.tbDel = NIconToolButton(self, iPx)
115
- self.tbDel.setIcon(SHARED.theme.getIcon("remove"))
117
+ self.tbDel = NIconToolButton(self, iSz, "remove")
116
118
  self.tbDel.setToolTip(self.tr("Delete Selected Build"))
117
119
  self.tbDel.setStyleSheet(buttonStyle)
118
120
  self.tbDel.clicked.connect(self._deleteSelectedBuild)
119
121
 
120
- self.tbEdit = NIconToolButton(self, iPx)
121
- self.tbEdit.setIcon(SHARED.theme.getIcon("edit"))
122
+ self.tbEdit = NIconToolButton(self, iSz, "edit")
122
123
  self.tbEdit.setToolTip(self.tr("Edit Selected Build"))
123
124
  self.tbEdit.setStyleSheet(buttonStyle)
124
125
  self.tbEdit.clicked.connect(self._editSelectedBuild)
125
126
 
126
- self.lblBuilds = QLabel("<b>{0}</b>".format(self.tr("Builds")))
127
+ self.lblBuilds = QLabel("<b>{0}</b>".format(self.tr("Builds")), self)
127
128
 
128
129
  self.listToolBox = QHBoxLayout()
129
130
  self.listToolBox.addWidget(self.lblBuilds)
@@ -137,11 +138,11 @@ class GuiManuscript(QDialog):
137
138
  # ======
138
139
 
139
140
  self.buildList = QListWidget(self)
140
- self.buildList.setIconSize(QSize(iPx, iPx))
141
+ self.buildList.setIconSize(iSz)
141
142
  self.buildList.doubleClicked.connect(self._editSelectedBuild)
142
143
  self.buildList.currentItemChanged.connect(self._updateBuildDetails)
143
- self.buildList.setSelectionMode(QAbstractItemView.SingleSelection)
144
- self.buildList.setDragDropMode(QAbstractItemView.InternalMove)
144
+ self.buildList.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
145
+ self.buildList.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
145
146
 
146
147
  # Details Tabs
147
148
  # ============
@@ -154,7 +155,7 @@ class GuiManuscript(QDialog):
154
155
  self.buildOutline = _OutlineWidget(self)
155
156
 
156
157
  self.detailsTabs = QTabWidget(self)
157
- self.detailsTabs.addTab(self.buildDetails, self.tr("Build"))
158
+ self.detailsTabs.addTab(self.buildDetails, self.tr("Details"))
158
159
  self.detailsTabs.addTab(self.buildOutline, self.tr("Outline"))
159
160
  self.detailsTabs.setStyleSheet(SHARED.theme.getStyleSheet(STYLES_FLAT_TABS))
160
161
 
@@ -169,16 +170,16 @@ class GuiManuscript(QDialog):
169
170
  # Process Controls
170
171
  # ================
171
172
 
172
- self.btnPreview = QPushButton(self.tr("Preview"))
173
+ self.btnPreview = QPushButton(self.tr("Preview"), self)
173
174
  self.btnPreview.clicked.connect(self._generatePreview)
174
175
 
175
- self.btnPrint = QPushButton(self.tr("Print"))
176
+ self.btnPrint = QPushButton(self.tr("Print"), self)
176
177
  self.btnPrint.clicked.connect(self._printDocument)
177
178
 
178
- self.btnBuild = QPushButton(self.tr("Build"))
179
+ self.btnBuild = QPushButton(self.tr("Build"), self)
179
180
  self.btnBuild.clicked.connect(self._buildManuscript)
180
181
 
181
- self.btnClose = QPushButton(self.tr("Close"))
182
+ self.btnClose = QPushButton(self.tr("Close"), self)
182
183
  self.btnClose.clicked.connect(self.close)
183
184
 
184
185
  self.processBox = QGridLayout()
@@ -210,7 +211,7 @@ class GuiManuscript(QDialog):
210
211
  self.optsWidget = QWidget(self)
211
212
  self.optsWidget.setLayout(self.controlBox)
212
213
 
213
- self.mainSplit = QSplitter()
214
+ self.mainSplit = QSplitter(self)
214
215
  self.mainSplit.addWidget(self.optsWidget)
215
216
  self.mainSplit.addWidget(self.docWdiget)
216
217
  self.mainSplit.setCollapsible(0, False)
@@ -302,26 +303,24 @@ class GuiManuscript(QDialog):
302
303
  @pyqtSlot()
303
304
  def _editSelectedBuild(self) -> None:
304
305
  """Edit the currently selected build settings entry."""
305
- build = self._getSelectedBuild()
306
- if build is not None:
306
+ if build := self._getSelectedBuild():
307
307
  self._openSettingsDialog(build)
308
308
  return
309
309
 
310
310
  @pyqtSlot("QListWidgetItem*", "QListWidgetItem*")
311
311
  def _updateBuildDetails(self, current: QListWidgetItem, previous: QListWidgetItem) -> None:
312
312
  """Process change of build selection to update the details."""
313
- if isinstance(current, QListWidgetItem):
314
- build = self._builds.getBuild(current.data(self.D_KEY))
315
- if build is not None:
316
- self.buildDetails.updateInfo(build)
313
+ if current and (build := self._builds.getBuild(current.data(self.D_KEY))):
314
+ self.buildDetails.updateInfo(build)
317
315
  return
318
316
 
319
317
  @pyqtSlot()
320
318
  def _deleteSelectedBuild(self) -> None:
321
319
  """Delete the currently selected build settings entry."""
322
- build = self._getSelectedBuild()
323
- if build is not None:
320
+ if build := self._getSelectedBuild():
324
321
  if SHARED.question(self.tr("Delete build '{0}'?".format(build.name))):
322
+ if dialog := self._findSettingsDialog(build.buildID):
323
+ dialog.close()
325
324
  self._builds.removeBuild(build.buildID)
326
325
  self._updateBuildsList()
327
326
  return
@@ -331,8 +330,7 @@ class GuiManuscript(QDialog):
331
330
  """Process new build settings from the settings dialog."""
332
331
  self._builds.setBuild(build)
333
332
  self._updateBuildItem(build)
334
- current = self.buildList.currentItem()
335
- if isinstance(current, QListWidgetItem) and current.data(self.D_KEY) == build.buildID:
333
+ if (current := self.buildList.currentItem()) and current.data(self.D_KEY) == build.buildID:
336
334
  self._updateBuildDetails(current, current)
337
335
  return
338
336
 
@@ -341,10 +339,12 @@ class GuiManuscript(QDialog):
341
339
  """Run the document builder on the current build settings for
342
340
  the preview widget.
343
341
  """
344
- build = self._getSelectedBuild()
345
- if build is None:
342
+ if not (build := self._getSelectedBuild()):
346
343
  return
347
344
 
345
+ # Make sure editor content is saved before we start
346
+ SHARED.mainGui.saveDocument()
347
+
348
348
  docBuild = NWBuildDocument(SHARED.project, build)
349
349
  docBuild.setPreviewMode(True)
350
350
  docBuild.queueAll()
@@ -352,7 +352,7 @@ class GuiManuscript(QDialog):
352
352
  self.docPreview.beginNewBuild(len(docBuild))
353
353
  for step, _ in docBuild.iterBuildHTML(None):
354
354
  self.docPreview.buildStep(step + 1)
355
- qApp.processEvents()
355
+ QApplication.processEvents()
356
356
 
357
357
  buildObj = docBuild.lastBuild
358
358
  assert isinstance(buildObj, ToHtml)
@@ -382,10 +382,9 @@ class GuiManuscript(QDialog):
382
382
  @pyqtSlot()
383
383
  def _buildManuscript(self) -> None:
384
384
  """Open the build dialog and build the manuscript."""
385
- build = self._getSelectedBuild()
386
- if isinstance(build, BuildSettings):
385
+ if build := self._getSelectedBuild():
387
386
  dlgBuild = GuiManuscriptBuild(self, build)
388
- dlgBuild.exec_()
387
+ dlgBuild.exec()
389
388
 
390
389
  # After the build is done, save build settings changes
391
390
  if build.changed:
@@ -398,7 +397,7 @@ class GuiManuscript(QDialog):
398
397
  """Open the print preview dialog."""
399
398
  preview = QPrintPreviewDialog(self)
400
399
  preview.paintRequested.connect(self.docPreview.printPreview)
401
- preview.exec_()
400
+ preview.exec()
402
401
  return
403
402
 
404
403
  ##
@@ -473,20 +472,16 @@ class GuiManuscript(QDialog):
473
472
 
474
473
  def _openSettingsDialog(self, build: BuildSettings) -> None:
475
474
  """Open the build settings dialog."""
476
- for obj in self.mainGui.children():
477
- # Don't open a second dialog if one exists
478
- if isinstance(obj, GuiBuildSettings):
479
- if obj.buildID == build.buildID:
480
- logger.debug("Found instance of GuiBuildSettings")
481
- obj.show()
482
- obj.raise_()
483
- return
475
+ if dialog := self._findSettingsDialog(build.buildID):
476
+ dialog.show()
477
+ dialog.raise_()
478
+ return
484
479
 
485
480
  dlgSettings = GuiBuildSettings(self.mainGui, build)
486
481
  dlgSettings.setModal(False)
487
482
  dlgSettings.show()
488
483
  dlgSettings.raise_()
489
- qApp.processEvents()
484
+ QApplication.processEvents()
490
485
  dlgSettings.loadContent()
491
486
  dlgSettings.newSettingsReady.connect(self._processNewSettings)
492
487
 
@@ -495,6 +490,7 @@ class GuiManuscript(QDialog):
495
490
  def _updateBuildsList(self) -> None:
496
491
  """Update the list of available builds."""
497
492
  self.buildList.clear()
493
+ self._buildMap.clear()
498
494
  for key, name in self._builds.builds():
499
495
  bItem = QListWidgetItem()
500
496
  bItem.setText(name)
@@ -513,6 +509,15 @@ class GuiManuscript(QDialog):
513
509
  self._updateBuildsList()
514
510
  return
515
511
 
512
+ def _findSettingsDialog(self, buildID: str) -> GuiBuildSettings | None:
513
+ """Return an open build settings dialog for a given build, if
514
+ one exists.
515
+ """
516
+ for obj in SHARED.mainGui.children():
517
+ if isinstance(obj, GuiBuildSettings) and obj.buildID == buildID:
518
+ return obj
519
+ return None
520
+
516
521
  # END Class GuiManuscript
517
522
 
518
523
 
@@ -526,7 +531,7 @@ class _DetailsWidget(QWidget):
526
531
  # Tree Widget
527
532
  self.listView = QTreeWidget(self)
528
533
  self.listView.setHeaderLabels([self.tr("Setting"), self.tr("Value")])
529
- self.listView.setIndentation(SHARED.theme.baseIconSize)
534
+ self.listView.setIndentation(SHARED.theme.baseIconHeight)
530
535
  self.listView.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
531
536
 
532
537
  # Assemble
@@ -626,7 +631,7 @@ class _DetailsWidget(QWidget):
626
631
  ("headings.fmtChapter", "headings.hideChapter"),
627
632
  ("headings.fmtUnnumbered", "headings.hideUnnumbered"),
628
633
  ("headings.fmtScene", "headings.hideScene"),
629
- ("headings.fmtHardScene", "headings.hideHardScene"),
634
+ ("headings.fmtAltScene", "headings.hideAltScene"),
630
635
  ("headings.fmtSection", "headings.hideSection"),
631
636
  ]:
632
637
  sub = QTreeWidgetItem()
@@ -661,7 +666,7 @@ class _DetailsWidget(QWidget):
661
666
 
662
667
  class _OutlineWidget(QWidget):
663
668
 
664
- D_LINE = Qt.ItemDataRole.UserRole
669
+ D_LINE = QtUserRole
665
670
 
666
671
  outlineEntryClicked = pyqtSignal(str)
667
672
 
@@ -721,7 +726,9 @@ class _OutlineWidget(QWidget):
721
726
  parent.addChild(item)
722
727
  indent = True
723
728
 
724
- self.listView.setIndentation(SHARED.theme.baseIconSize if indent else CONFIG.pxInt(4))
729
+ self.listView.setIndentation(
730
+ SHARED.theme.baseIconHeight if indent else CONFIG.pxInt(4)
731
+ )
725
732
  self._outline = data
726
733
 
727
734
  return
@@ -745,11 +752,12 @@ class _PreviewWidget(QTextBrowser):
745
752
 
746
753
  self._docTime = 0
747
754
  self._buildName = ""
755
+ self._scrollPos = 0
748
756
 
749
757
  # Document Setup
750
758
  dPalette = self.palette()
751
- dPalette.setColor(QPalette.Base, QColor(255, 255, 255))
752
- dPalette.setColor(QPalette.Text, QColor(0, 0, 0))
759
+ dPalette.setColor(QPalette.ColorRole.Base, QColor(255, 255, 255))
760
+ dPalette.setColor(QPalette.ColorRole.Text, QColor(0, 0, 0))
753
761
  self.setPalette(dPalette)
754
762
 
755
763
  self.setMinimumWidth(40*SHARED.theme.textNWidth)
@@ -766,8 +774,8 @@ class _PreviewWidget(QTextBrowser):
766
774
 
767
775
  # Document Age
768
776
  aPalette = self.palette()
769
- aPalette.setColor(QPalette.Background, aPalette.toolTipBase().color())
770
- aPalette.setColor(QPalette.Foreground, aPalette.toolTipText().color())
777
+ aPalette.setColor(QPalette.ColorRole.Window, aPalette.toolTipBase().color())
778
+ aPalette.setColor(QPalette.ColorRole.WindowText, aPalette.toolTipText().color())
771
779
 
772
780
  aFont = self.font()
773
781
  aFont.setPointSizeF(0.9*SHARED.theme.fontPointSize)
@@ -777,7 +785,7 @@ class _PreviewWidget(QTextBrowser):
777
785
  self.ageLabel.setFont(aFont)
778
786
  self.ageLabel.setPalette(aPalette)
779
787
  self.ageLabel.setAutoFillBackground(True)
780
- self.ageLabel.setAlignment(Qt.AlignmentFlag.AlignCenter)
788
+ self.ageLabel.setAlignment(QtAlignCenter)
781
789
  self.ageLabel.setFixedHeight(int(2.1*SHARED.theme.fontPixelSize))
782
790
 
783
791
  # Progress
@@ -816,9 +824,9 @@ class _PreviewWidget(QTextBrowser):
816
824
  """Enable/disable the justify text option."""
817
825
  pOptions = self.document().defaultTextOption()
818
826
  if state:
819
- pOptions.setAlignment(Qt.AlignmentFlag.AlignJustify)
827
+ pOptions.setAlignment(QtAlignJustify)
820
828
  else:
821
- pOptions.setAlignment(Qt.AlignmentFlag.AlignAbsolute)
829
+ pOptions.setAlignment(QtAlignAbsolute)
822
830
  self.document().setDefaultTextOption(pOptions)
823
831
  return
824
832
 
@@ -841,6 +849,7 @@ class _PreviewWidget(QTextBrowser):
841
849
  self.buildProgress.setValue(0)
842
850
  self.buildProgress.setCentreText(None)
843
851
  self.buildProgress.setVisible(True)
852
+ self._scrollPos = self.verticalScrollBar().value()
844
853
  self.setPlaceholderText("")
845
854
  self.clear()
846
855
  return
@@ -848,16 +857,15 @@ class _PreviewWidget(QTextBrowser):
848
857
  def buildStep(self, value: int) -> None:
849
858
  """Update the progress bar value."""
850
859
  self.buildProgress.setValue(value)
851
- qApp.processEvents()
860
+ QApplication.processEvents()
852
861
  return
853
862
 
854
863
  def setContent(self, data: dict) -> None:
855
864
  """Set the content of the preview widget."""
856
- sPos = self.verticalScrollBar().value()
857
- qApp.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
865
+ QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
858
866
 
859
867
  self.buildProgress.setCentreText(self.tr("Processing ..."))
860
- qApp.processEvents()
868
+ QApplication.processEvents()
861
869
 
862
870
  styles = "\n".join(data.get("styles", []))
863
871
  self.document().setDefaultStyleSheet(styles)
@@ -865,12 +873,11 @@ class _PreviewWidget(QTextBrowser):
865
873
  html = "".join(data.get("html", []))
866
874
  html = html.replace("\t", "!!tab!!")
867
875
  self.setHtml(html)
868
- qApp.processEvents()
876
+ QApplication.processEvents()
869
877
  while self.find("!!tab!!"):
870
878
  cursor = self.textCursor()
871
879
  cursor.insertText("\t")
872
880
 
873
- self.verticalScrollBar().setValue(sPos)
874
881
  self._docTime = checkInt(data.get("time"), 0)
875
882
  self._updateBuildAge()
876
883
 
@@ -879,9 +886,9 @@ class _PreviewWidget(QTextBrowser):
879
886
  self.document().markContentsDirty(0, self.document().characterCount())
880
887
 
881
888
  self.buildProgress.setCentreText(self.tr("Done"))
882
- qApp.restoreOverrideCursor()
883
- qApp.processEvents()
884
- QTimer.singleShot(300, self._hideProgress)
889
+ QApplication.restoreOverrideCursor()
890
+ QApplication.processEvents()
891
+ QTimer.singleShot(300, self._postUpdate)
885
892
 
886
893
  return
887
894
 
@@ -902,10 +909,10 @@ class _PreviewWidget(QTextBrowser):
902
909
  @pyqtSlot("QPrinter*")
903
910
  def printPreview(self, printer: QPrinter) -> None:
904
911
  """Connect the print preview painter to the document viewer."""
905
- qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
906
- printer.setOrientation(QPrinter.Portrait)
912
+ QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
913
+ printer.setOrientation(QPrinter.Orientation.Portrait)
907
914
  self.document().print(printer)
908
- qApp.restoreOverrideCursor()
915
+ QApplication.restoreOverrideCursor()
909
916
  return
910
917
 
911
918
  @pyqtSlot(str)
@@ -936,9 +943,10 @@ class _PreviewWidget(QTextBrowser):
936
943
  return
937
944
 
938
945
  @pyqtSlot()
939
- def _hideProgress(self) -> None:
940
- """Clean up the build progress bar."""
946
+ def _postUpdate(self) -> None:
947
+ """Run tasks after content update."""
941
948
  self.buildProgress.setVisible(False)
949
+ self.verticalScrollBar().setValue(self._scrollPos)
942
950
  return
943
951
 
944
952
  ##
@@ -976,13 +984,7 @@ class _StatsWidget(QWidget):
976
984
  self.minWidget = QWidget(self)
977
985
  self.maxWidget = QWidget(self)
978
986
 
979
- iPx = int(0.6*SHARED.theme.baseIconSize)
980
- toggleIcon = SHARED.theme.getToggleIcon("unfold", (iPx, iPx))
981
-
982
- self.toggleButton = NIconToolButton(self, iPx)
983
- self.toggleButton.setCheckable(True)
984
- self.toggleButton.setIcon(toggleIcon)
985
- self.toggleButton.setStyleSheet(SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON))
987
+ self.toggleButton = NIconToggleButton(self, SHARED.theme.baseIconSize, "unfold")
986
988
  self.toggleButton.toggled.connect(self._toggleView)
987
989
 
988
990
  self._buildMinimal()
@@ -993,8 +995,8 @@ class _StatsWidget(QWidget):
993
995
  self.mainStack.addWidget(self.maxWidget)
994
996
 
995
997
  self.outerBox = QHBoxLayout()
996
- self.outerBox.addWidget(self.toggleButton, 0, Qt.AlignmentFlag.AlignTop)
997
- self.outerBox.addWidget(self.mainStack, 1, Qt.AlignmentFlag.AlignTop)
998
+ self.outerBox.addWidget(self.toggleButton, 0, QtAlignTop)
999
+ self.outerBox.addWidget(self.mainStack, 1, QtAlignTop)
998
1000
  self.outerBox.setContentsMargins(0, 0, 0, 0)
999
1001
 
1000
1002
  self.setLayout(self.outerBox)
@@ -1011,7 +1013,7 @@ class _StatsWidget(QWidget):
1011
1013
 
1012
1014
  # Maximal
1013
1015
  self.maxTotalWords.setText("{0:n}".format(data.get("allWords", 0)))
1014
- self.maxHeaderWords.setText("{0:n}".format(data.get("titleWords", 0)))
1016
+ self.maxHeadWords.setText("{0:n}".format(data.get("titleWords", 0)))
1015
1017
  self.maxTextWords.setText("{0:n}".format(data.get("textWords", 0)))
1016
1018
  self.maxTitleCount.setText("{0:n}".format(data.get("titleCount", 0)))
1017
1019
  self.maxParCount.setText("{0:n}".format(data.get("paragraphCount", 0)))
@@ -1021,7 +1023,7 @@ class _StatsWidget(QWidget):
1021
1023
  self.maxTextChars.setText("{0:n}".format(data.get("textChars", 0)))
1022
1024
 
1023
1025
  self.maxTotalWordChars.setText("{0:n}".format(data.get("allWordChars", 0)))
1024
- self.maxHeaderWordChars.setText("{0:n}".format(data.get("titleWordChars", 0)))
1026
+ self.maxHeadWordChars.setText("{0:n}".format(data.get("titleWordChars", 0)))
1025
1027
  self.maxTextWordChars.setText("{0:n}".format(data.get("textWordChars", 0)))
1026
1028
 
1027
1029
  return
@@ -1057,10 +1059,10 @@ class _StatsWidget(QWidget):
1057
1059
  """Build the minimal stats page."""
1058
1060
  mPx = CONFIG.pxInt(8)
1059
1061
 
1060
- self.lblWordCount = QLabel(self.tr("Words"))
1062
+ self.lblWordCount = QLabel(self.tr("Words"), self)
1061
1063
  self.minWordCount = QLabel(self)
1062
1064
 
1063
- self.lblCharCount = QLabel(self.tr("Characters"))
1065
+ self.lblCharCount = QLabel(self.tr("Characters"), self)
1064
1066
  self.minCharCount = QLabel(self)
1065
1067
 
1066
1068
  # Assemble
@@ -1083,25 +1085,23 @@ class _StatsWidget(QWidget):
1083
1085
  hPx = CONFIG.pxInt(12)
1084
1086
  vPx = CONFIG.pxInt(4)
1085
1087
 
1086
- alignRight = Qt.AlignmentFlag.AlignRight
1087
-
1088
1088
  # Left Column
1089
1089
  self.maxTotalWords = QLabel(self)
1090
- self.maxHeaderWords = QLabel(self)
1090
+ self.maxHeadWords = QLabel(self)
1091
1091
  self.maxTextWords = QLabel(self)
1092
1092
  self.maxTitleCount = QLabel(self)
1093
1093
  self.maxParCount = QLabel(self)
1094
1094
 
1095
- self.maxTotalWords.setAlignment(alignRight)
1096
- self.maxHeaderWords.setAlignment(alignRight)
1097
- self.maxTextWords.setAlignment(alignRight)
1098
- self.maxTitleCount.setAlignment(alignRight)
1099
- self.maxParCount.setAlignment(alignRight)
1095
+ self.maxTotalWords.setAlignment(QtAlignRight)
1096
+ self.maxHeadWords.setAlignment(QtAlignRight)
1097
+ self.maxTextWords.setAlignment(QtAlignRight)
1098
+ self.maxTitleCount.setAlignment(QtAlignRight)
1099
+ self.maxParCount.setAlignment(QtAlignRight)
1100
1100
 
1101
1101
  self.leftForm = QFormLayout()
1102
1102
  self.leftForm.addRow(self.tr("Words"), self.maxTotalWords)
1103
- self.leftForm.addRow(self.tr("Heading Words"), self.maxHeaderWords)
1104
- self.leftForm.addRow(self.tr("Body Text Words"), self.maxTextWords)
1103
+ self.leftForm.addRow(self.tr("Words in Headings"), self.maxHeadWords)
1104
+ self.leftForm.addRow(self.tr("Words in Text"), self.maxTextWords)
1105
1105
  self.leftForm.addRow("", QLabel(self))
1106
1106
  self.leftForm.addRow(self.tr("Headings"), self.maxTitleCount)
1107
1107
  self.leftForm.addRow(self.tr("Paragraphs"), self.maxParCount)
@@ -1114,24 +1114,24 @@ class _StatsWidget(QWidget):
1114
1114
  self.maxTextChars = QLabel(self)
1115
1115
 
1116
1116
  self.maxTotalWordChars = QLabel(self)
1117
- self.maxHeaderWordChars = QLabel(self)
1117
+ self.maxHeadWordChars = QLabel(self)
1118
1118
  self.maxTextWordChars = QLabel(self)
1119
1119
 
1120
- self.maxTotalChars.setAlignment(alignRight)
1121
- self.maxHeaderChars.setAlignment(alignRight)
1122
- self.maxTextChars.setAlignment(alignRight)
1120
+ self.maxTotalChars.setAlignment(QtAlignRight)
1121
+ self.maxHeaderChars.setAlignment(QtAlignRight)
1122
+ self.maxTextChars.setAlignment(QtAlignRight)
1123
1123
 
1124
- self.maxTotalWordChars.setAlignment(alignRight)
1125
- self.maxHeaderWordChars.setAlignment(alignRight)
1126
- self.maxTextWordChars.setAlignment(alignRight)
1124
+ self.maxTotalWordChars.setAlignment(QtAlignRight)
1125
+ self.maxHeadWordChars.setAlignment(QtAlignRight)
1126
+ self.maxTextWordChars.setAlignment(QtAlignRight)
1127
1127
 
1128
1128
  self.rightForm = QFormLayout()
1129
1129
  self.rightForm.addRow(self.tr("Characters"), self.maxTotalChars)
1130
- self.rightForm.addRow(self.tr("Heading Characters"), self.maxHeaderChars)
1131
- self.rightForm.addRow(self.tr("Body Text Characters"), self.maxTextChars)
1130
+ self.rightForm.addRow(self.tr("Characters in Headings"), self.maxHeaderChars)
1131
+ self.rightForm.addRow(self.tr("Characters in Text"), self.maxTextChars)
1132
1132
  self.rightForm.addRow(self.tr("Characters, No Spaces"), self.maxTotalWordChars)
1133
- self.rightForm.addRow(self.tr("Heading Characters, No Spaces"), self.maxHeaderWordChars)
1134
- self.rightForm.addRow(self.tr("Body Text Characters, No Spaces"), self.maxTextWordChars)
1133
+ self.rightForm.addRow(self.tr("Characters in Headings, No Spaces"), self.maxHeadWordChars)
1134
+ self.rightForm.addRow(self.tr("Characters in Text, No Spaces"), self.maxTextWordChars)
1135
1135
  self.rightForm.setHorizontalSpacing(hPx)
1136
1136
  self.rightForm.setVerticalSpacing(vPx)
1137
1137