novelWriter 2.5.3__py3-none-any.whl → 2.6b2__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 (83) hide show
  1. {novelWriter-2.5.3.dist-info → novelWriter-2.6b2.dist-info}/METADATA +1 -1
  2. {novelWriter-2.5.3.dist-info → novelWriter-2.6b2.dist-info}/RECORD +80 -60
  3. novelwriter/__init__.py +49 -10
  4. novelwriter/assets/i18n/project_en_GB.json +1 -0
  5. novelwriter/assets/icons/typicons_dark/icons.conf +8 -0
  6. novelwriter/assets/icons/typicons_dark/mixed_copy.svg +4 -0
  7. novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +6 -0
  8. novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +6 -0
  9. novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +6 -0
  10. novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +6 -0
  11. novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +6 -0
  12. novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +6 -0
  13. novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +5 -0
  14. novelwriter/assets/icons/typicons_light/icons.conf +8 -0
  15. novelwriter/assets/icons/typicons_light/mixed_copy.svg +4 -0
  16. novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +6 -0
  17. novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +6 -0
  18. novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +6 -0
  19. novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +6 -0
  20. novelwriter/assets/icons/typicons_light/mixed_size-height.svg +6 -0
  21. novelwriter/assets/icons/typicons_light/mixed_size-width.svg +6 -0
  22. novelwriter/assets/icons/typicons_light/nw_toolbar.svg +5 -0
  23. novelwriter/assets/manual.pdf +0 -0
  24. novelwriter/assets/sample.zip +0 -0
  25. novelwriter/common.py +100 -2
  26. novelwriter/config.py +25 -15
  27. novelwriter/constants.py +168 -60
  28. novelwriter/core/buildsettings.py +66 -39
  29. novelwriter/core/coretools.py +145 -147
  30. novelwriter/core/docbuild.py +132 -170
  31. novelwriter/core/index.py +38 -37
  32. novelwriter/core/item.py +41 -8
  33. novelwriter/core/itemmodel.py +518 -0
  34. novelwriter/core/options.py +4 -1
  35. novelwriter/core/project.py +67 -89
  36. novelwriter/core/spellcheck.py +9 -14
  37. novelwriter/core/status.py +7 -5
  38. novelwriter/core/tree.py +268 -287
  39. novelwriter/dialogs/docmerge.py +7 -17
  40. novelwriter/dialogs/preferences.py +46 -33
  41. novelwriter/dialogs/projectsettings.py +5 -5
  42. novelwriter/enum.py +36 -23
  43. novelwriter/extensions/configlayout.py +27 -12
  44. novelwriter/extensions/modified.py +13 -1
  45. novelwriter/extensions/pagedsidebar.py +5 -5
  46. novelwriter/formats/shared.py +155 -0
  47. novelwriter/formats/todocx.py +1191 -0
  48. novelwriter/formats/tohtml.py +451 -0
  49. novelwriter/{core → formats}/tokenizer.py +487 -491
  50. novelwriter/formats/tomarkdown.py +217 -0
  51. novelwriter/{core → formats}/toodt.py +311 -432
  52. novelwriter/formats/toqdoc.py +484 -0
  53. novelwriter/formats/toraw.py +91 -0
  54. novelwriter/gui/doceditor.py +342 -284
  55. novelwriter/gui/dochighlight.py +96 -84
  56. novelwriter/gui/docviewer.py +88 -31
  57. novelwriter/gui/docviewerpanel.py +17 -25
  58. novelwriter/gui/editordocument.py +17 -2
  59. novelwriter/gui/itemdetails.py +25 -28
  60. novelwriter/gui/mainmenu.py +129 -63
  61. novelwriter/gui/noveltree.py +45 -47
  62. novelwriter/gui/outline.py +196 -249
  63. novelwriter/gui/projtree.py +594 -1241
  64. novelwriter/gui/search.py +9 -10
  65. novelwriter/gui/sidebar.py +7 -6
  66. novelwriter/gui/theme.py +10 -5
  67. novelwriter/guimain.py +100 -196
  68. novelwriter/shared.py +66 -27
  69. novelwriter/text/counting.py +2 -0
  70. novelwriter/text/patterns.py +168 -60
  71. novelwriter/tools/manusbuild.py +14 -12
  72. novelwriter/tools/manuscript.py +120 -78
  73. novelwriter/tools/manussettings.py +424 -291
  74. novelwriter/tools/welcome.py +4 -4
  75. novelwriter/tools/writingstats.py +3 -3
  76. novelwriter/types.py +23 -7
  77. novelwriter/core/tohtml.py +0 -530
  78. novelwriter/core/tomarkdown.py +0 -252
  79. novelwriter/core/toqdoc.py +0 -419
  80. {novelWriter-2.5.3.dist-info → novelWriter-2.6b2.dist-info}/LICENSE.md +0 -0
  81. {novelWriter-2.5.3.dist-info → novelWriter-2.6b2.dist-info}/WHEEL +0 -0
  82. {novelWriter-2.5.3.dist-info → novelWriter-2.6b2.dist-info}/entry_points.txt +0 -0
  83. {novelWriter-2.5.3.dist-info → novelWriter-2.6b2.dist-info}/top_level.txt +0 -0
@@ -29,7 +29,10 @@ from time import time
29
29
  from typing import TYPE_CHECKING
30
30
 
31
31
  from PyQt5.QtCore import Qt, QTimer, QUrl, pyqtSignal, pyqtSlot
32
- from PyQt5.QtGui import QCloseEvent, QColor, QCursor, QFont, QPalette, QResizeEvent, QTextDocument
32
+ from PyQt5.QtGui import (
33
+ QCloseEvent, QColor, QCursor, QDesktopServices, QFont, QPalette,
34
+ QResizeEvent, QTextDocument
35
+ )
33
36
  from PyQt5.QtPrintSupport import QPrinter, QPrintPreviewDialog
34
37
  from PyQt5.QtWidgets import (
35
38
  QAbstractItemView, QApplication, QFormLayout, QGridLayout, QHBoxLayout,
@@ -40,12 +43,14 @@ from PyQt5.QtWidgets import (
40
43
 
41
44
  from novelwriter import CONFIG, SHARED
42
45
  from novelwriter.common import fuzzyTime
46
+ from novelwriter.constants import nwLabels, nwStats, trConst
43
47
  from novelwriter.core.buildsettings import BuildCollection, BuildSettings
44
48
  from novelwriter.core.docbuild import NWBuildDocument
45
- from novelwriter.core.tokenizer import HeadingFormatter
46
- from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument
47
49
  from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton, NToolDialog
48
50
  from novelwriter.extensions.progressbars import NProgressCircle
51
+ from novelwriter.extensions.switch import NSwitch
52
+ from novelwriter.formats.tokenizer import HeadingFormatter
53
+ from novelwriter.formats.toqdoc import ToQTextDocument
49
54
  from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON
50
55
  from novelwriter.tools.manusbuild import GuiManuscriptBuild
51
56
  from novelwriter.tools.manussettings import GuiBuildSettings
@@ -83,6 +88,7 @@ class GuiManuscript(NToolDialog):
83
88
  self.setMinimumWidth(CONFIG.pxInt(600))
84
89
  self.setMinimumHeight(CONFIG.pxInt(500))
85
90
 
91
+ iPx = SHARED.theme.baseIconHeight
86
92
  iSz = SHARED.theme.baseIconSize
87
93
  wWin = CONFIG.pxInt(900)
88
94
  hWin = CONFIG.pxInt(600)
@@ -112,6 +118,11 @@ class GuiManuscript(NToolDialog):
112
118
  self.tbDel.setStyleSheet(buttonStyle)
113
119
  self.tbDel.clicked.connect(self._deleteSelectedBuild)
114
120
 
121
+ self.tbCopy = NIconToolButton(self, iSz, "copy")
122
+ self.tbCopy.setToolTip(self.tr("Duplicate Selected Build"))
123
+ self.tbCopy.setStyleSheet(buttonStyle)
124
+ self.tbCopy.clicked.connect(self._copySelectedBuild)
125
+
115
126
  self.tbEdit = NIconToolButton(self, iSz, "edit")
116
127
  self.tbEdit.setToolTip(self.tr("Edit Selected Build"))
117
128
  self.tbEdit.setStyleSheet(buttonStyle)
@@ -124,6 +135,7 @@ class GuiManuscript(NToolDialog):
124
135
  self.listToolBox.addStretch(1)
125
136
  self.listToolBox.addWidget(self.tbAdd)
126
137
  self.listToolBox.addWidget(self.tbDel)
138
+ self.listToolBox.addWidget(self.tbCopy)
127
139
  self.listToolBox.addWidget(self.tbEdit)
128
140
  self.listToolBox.setSpacing(0)
129
141
 
@@ -181,15 +193,31 @@ class GuiManuscript(NToolDialog):
181
193
  self.processBox.addWidget(self.btnBuild, 1, 0)
182
194
  self.processBox.addWidget(self.btnClose, 1, 1)
183
195
 
196
+ # Preview Options
197
+ # ===============
198
+
199
+ self.swtNewPage = NSwitch(self, height=iPx)
200
+ self.swtNewPage.setChecked(pOptions.getBool("GuiManuscript", "showNewPage", True))
201
+ self.swtNewPage.clicked.connect(self._generatePreview)
202
+
203
+ self.lblNewPage = QLabel(self.tr("Show Page Breaks"), self)
204
+ self.lblNewPage.setBuddy(self.swtNewPage)
205
+
184
206
  # Assemble GUI
185
207
  # ============
186
208
 
187
209
  self.docPreview = _PreviewWidget(self)
188
210
  self.docStats = _StatsWidget(self)
189
211
 
212
+ self.docBar = QHBoxLayout()
213
+ self.docBar.addWidget(self.docStats, 1, QtAlignTop)
214
+ self.docBar.addWidget(self.lblNewPage, 0, QtAlignTop)
215
+ self.docBar.addWidget(self.swtNewPage, 0, QtAlignTop)
216
+ self.docBar.setContentsMargins(0, 0, 0, 0)
217
+
190
218
  self.docBox = QVBoxLayout()
191
219
  self.docBox.addWidget(self.docPreview, 1)
192
- self.docBox.addWidget(self.docStats, 0)
220
+ self.docBox.addLayout(self.docBar, 0)
193
221
  self.docBox.setContentsMargins(0, 0, 0, 0)
194
222
 
195
223
  self.docWdiget = QWidget(self)
@@ -287,6 +315,17 @@ class GuiManuscript(NToolDialog):
287
315
  self._openSettingsDialog(build)
288
316
  return
289
317
 
318
+ @pyqtSlot()
319
+ def _copySelectedBuild(self) -> None:
320
+ """Copy the currently selected build settings entry."""
321
+ if build := self._getSelectedBuild():
322
+ new = BuildSettings.duplicate(build)
323
+ self._builds.setBuild(new)
324
+ self._updateBuildsList()
325
+ if item := self._buildMap.get(new.buildID):
326
+ item.setSelected(True)
327
+ return
328
+
290
329
  @pyqtSlot("QListWidgetItem*", "QListWidgetItem*")
291
330
  def _updateBuildDetails(self, current: QListWidgetItem, previous: QListWidgetItem) -> None:
292
331
  """Process change of build selection to update the details."""
@@ -323,6 +362,7 @@ class GuiManuscript(NToolDialog):
323
362
  return
324
363
 
325
364
  start = time()
365
+ showNewPage = self.swtNewPage.isChecked()
326
366
 
327
367
  # Make sure editor content is saved before we start
328
368
  SHARED.saveEditor()
@@ -330,22 +370,8 @@ class GuiManuscript(NToolDialog):
330
370
  docBuild = NWBuildDocument(SHARED.project, build)
331
371
  docBuild.queueAll()
332
372
 
333
- theme = TextDocumentTheme()
334
- theme.text = QColor(0, 0, 0)
335
- theme.highlight = QColor(255, 255, 166)
336
- theme.head = QColor(66, 113, 174)
337
- theme.comment = QColor(100, 100, 100)
338
- theme.note = QColor(129, 55, 9)
339
- theme.code = QColor(66, 113, 174)
340
- theme.modifier = QColor(129, 55, 9)
341
- theme.keyword = QColor(245, 135, 31)
342
- theme.tag = QColor(66, 113, 174)
343
- theme.optional = QColor(66, 113, 174)
344
- theme.dialog = QColor(66, 113, 174)
345
- theme.altdialog = QColor(129, 55, 9)
346
-
347
373
  self.docPreview.beginNewBuild(len(docBuild))
348
- for step, _ in docBuild.iterBuildPreview(theme):
374
+ for step, _ in docBuild.iterBuildPreview(showNewPage):
349
375
  self.docPreview.buildStep(step + 1)
350
376
  QApplication.processEvents()
351
377
 
@@ -427,6 +453,7 @@ class GuiManuscript(NToolDialog):
427
453
  detailsHeight = CONFIG.rpxInt(buildSplit[1])
428
454
  detailsWidth = CONFIG.rpxInt(self.buildDetails.getColumnWidth())
429
455
  detailsExpanded = self.buildDetails.getExpandedState()
456
+ showNewPage = self.swtNewPage.isChecked()
430
457
 
431
458
  logger.debug("Saving State: GuiManuscript")
432
459
  pOptions = SHARED.project.options
@@ -438,6 +465,7 @@ class GuiManuscript(NToolDialog):
438
465
  pOptions.setValue("GuiManuscript", "detailsHeight", detailsHeight)
439
466
  pOptions.setValue("GuiManuscript", "detailsWidth", detailsWidth)
440
467
  pOptions.setValue("GuiManuscript", "detailsExpanded", detailsExpanded)
468
+ pOptions.setValue("GuiManuscript", "showNewPage", showNewPage)
441
469
  pOptions.saveSettings()
442
470
 
443
471
  return
@@ -470,9 +498,8 @@ class GuiManuscript(NToolDialog):
470
498
 
471
499
  def _updateBuildItem(self, build: BuildSettings) -> None:
472
500
  """Update the entry of a specific build item."""
473
- bItem = self._buildMap.get(build.buildID, None)
474
- if isinstance(bItem, QListWidgetItem):
475
- bItem.setText(build.name)
501
+ if item := self._buildMap.get(build.buildID):
502
+ item.setText(build.name)
476
503
  else: # Probably a new item
477
504
  self._updateBuildsList()
478
505
  return
@@ -593,7 +620,7 @@ class _DetailsWidget(QWidget):
593
620
  item.setText(1, "")
594
621
  self.listView.addTopLevelItem(item)
595
622
  for hFormat, hHide in [
596
- ("headings.fmtTitle", "headings.hideTitle"),
623
+ ("headings.fmtPart", "headings.hidePart"),
597
624
  ("headings.fmtChapter", "headings.hideChapter"),
598
625
  ("headings.fmtUnnumbered", "headings.hideUnnumbered"),
599
626
  ("headings.fmtScene", "headings.hideScene"),
@@ -725,6 +752,7 @@ class _PreviewWidget(QTextBrowser):
725
752
  self.setMinimumWidth(40*SHARED.theme.textNWidth)
726
753
  self.setTabStopDistance(CONFIG.getTabWidth())
727
754
  self.setOpenExternalLinks(False)
755
+ self.setOpenLinks(False)
728
756
 
729
757
  self.document().setDocumentMargin(CONFIG.getTextMargin())
730
758
  self.setPlaceholderText(self.tr(
@@ -733,6 +761,9 @@ class _PreviewWidget(QTextBrowser):
733
761
 
734
762
  self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
735
763
 
764
+ # Signals
765
+ self.anchorClicked.connect(self._linkClicked)
766
+
736
767
  # Document Age
737
768
  aPalette = self.palette()
738
769
  aPalette.setColor(QPalette.ColorRole.Window, aPalette.toolTipBase().color())
@@ -869,6 +900,17 @@ class _PreviewWidget(QTextBrowser):
869
900
  # Private Slots
870
901
  ##
871
902
 
903
+ @pyqtSlot("QUrl")
904
+ def _linkClicked(self, url: QUrl) -> None:
905
+ """Process a clicked link in the document."""
906
+ if link := url.url():
907
+ logger.debug("Clicked link: '%s'", link)
908
+ if link.startswith("#"):
909
+ self.navigateTo(link.lstrip("#"))
910
+ elif link.startswith("http"):
911
+ QDesktopServices.openUrl(QUrl(url))
912
+ return
913
+
872
914
  @pyqtSlot()
873
915
  def _updateBuildAge(self) -> None:
874
916
  """Update the build time and the fuzzy age."""
@@ -924,8 +966,7 @@ class _StatsWidget(QWidget):
924
966
  self.toggleButton = NIconToggleButton(self, SHARED.theme.baseIconSize, "unfold")
925
967
  self.toggleButton.toggled.connect(self._toggleView)
926
968
 
927
- self._buildMinimal()
928
- self._buildMaximal()
969
+ self._buildBottomPanel()
929
970
 
930
971
  self.mainStack = QStackedWidget(self)
931
972
  self.mainStack.addWidget(self.minWidget)
@@ -945,23 +986,23 @@ class _StatsWidget(QWidget):
945
986
  def updateStats(self, data: dict[str, int]) -> None:
946
987
  """Update the stats values from a Tokenizer stats dict."""
947
988
  # Minimal
948
- self.minWordCount.setText("{0:n}".format(data.get("allWords", 0)))
949
- self.minCharCount.setText("{0:n}".format(data.get("allChars", 0)))
989
+ self.minWordCount.setText("{0:n}".format(data.get(nwStats.WORDS_ALL, 0)))
990
+ self.minCharCount.setText("{0:n}".format(data.get(nwStats.CHARS_ALL, 0)))
950
991
 
951
992
  # Maximal
952
- self.maxTotalWords.setText("{0:n}".format(data.get("allWords", 0)))
953
- self.maxHeadWords.setText("{0:n}".format(data.get("titleWords", 0)))
954
- self.maxTextWords.setText("{0:n}".format(data.get("textWords", 0)))
955
- self.maxTitleCount.setText("{0:n}".format(data.get("titleCount", 0)))
956
- self.maxParCount.setText("{0:n}".format(data.get("paragraphCount", 0)))
993
+ self.maxTotalWords.setText("{0:n}".format(data.get(nwStats.WORDS_ALL, 0)))
994
+ self.maxHeadWords.setText("{0:n}".format(data.get(nwStats.WORDS_TITLE, 0)))
995
+ self.maxTextWords.setText("{0:n}".format(data.get(nwStats.WORDS_TEXT, 0)))
996
+ self.maxTitleCount.setText("{0:n}".format(data.get(nwStats.TITLES, 0)))
997
+ self.maxParCount.setText("{0:n}".format(data.get(nwStats.PARAGRAPHS, 0)))
957
998
 
958
- self.maxTotalChars.setText("{0:n}".format(data.get("allChars", 0)))
959
- self.maxHeaderChars.setText("{0:n}".format(data.get("titleChars", 0)))
960
- self.maxTextChars.setText("{0:n}".format(data.get("textChars", 0)))
999
+ self.maxTotalChars.setText("{0:n}".format(data.get(nwStats.CHARS_ALL, 0)))
1000
+ self.maxHeaderChars.setText("{0:n}".format(data.get(nwStats.CHARS_TITLE, 0)))
1001
+ self.maxTextChars.setText("{0:n}".format(data.get(nwStats.CHARS_TEXT, 0)))
961
1002
 
962
- self.maxTotalWordChars.setText("{0:n}".format(data.get("allWordChars", 0)))
963
- self.maxHeadWordChars.setText("{0:n}".format(data.get("titleWordChars", 0)))
964
- self.maxTextWordChars.setText("{0:n}".format(data.get("textWordChars", 0)))
1003
+ self.maxTotalWordChars.setText("{0:n}".format(data.get(nwStats.WCHARS_ALL, 0)))
1004
+ self.maxHeadWordChars.setText("{0:n}".format(data.get(nwStats.WCHARS_TITLE, 0)))
1005
+ self.maxTextWordChars.setText("{0:n}".format(data.get(nwStats.WCHARS_TEXT, 0)))
965
1006
 
966
1007
  return
967
1008
 
@@ -990,37 +1031,29 @@ class _StatsWidget(QWidget):
990
1031
  # Internal Functions
991
1032
  ##
992
1033
 
993
- def _buildMinimal(self) -> None:
994
- """Build the minimal stats page."""
1034
+ def _buildBottomPanel(self) -> None:
1035
+ """Build the bottom page."""
995
1036
  mPx = CONFIG.pxInt(8)
1037
+ hPx = CONFIG.pxInt(12)
1038
+ vPx = CONFIG.pxInt(4)
996
1039
 
997
- self.lblWordCount = QLabel(self.tr("Words"), self)
1040
+ trAllChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS_ALL])
1041
+ trTextChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS_TEXT])
1042
+ trTitleChars = trConst(nwLabels.STATS_NAME[nwStats.CHARS_TITLE])
1043
+ trParagraphCount = trConst(nwLabels.STATS_NAME[nwStats.PARAGRAPHS])
1044
+ trTitleCount = trConst(nwLabels.STATS_NAME[nwStats.TITLES])
1045
+ trAllWordChars = trConst(nwLabels.STATS_NAME[nwStats.WCHARS_ALL])
1046
+ trTextWordChars = trConst(nwLabels.STATS_NAME[nwStats.WCHARS_TEXT])
1047
+ trTitleWordChars = trConst(nwLabels.STATS_NAME[nwStats.WCHARS_TITLE])
1048
+ trAllWords = trConst(nwLabels.STATS_NAME[nwStats.WORDS_ALL])
1049
+ trTextWords = trConst(nwLabels.STATS_NAME[nwStats.WORDS_TEXT])
1050
+ trTitleWords = trConst(nwLabels.STATS_NAME[nwStats.WORDS_TITLE])
1051
+
1052
+ # Minimal Form
998
1053
  self.minWordCount = QLabel(self)
999
-
1000
- self.lblCharCount = QLabel(self.tr("Characters"), self)
1001
1054
  self.minCharCount = QLabel(self)
1002
1055
 
1003
- # Assemble
1004
- self.minLayout = QHBoxLayout()
1005
- self.minLayout.addWidget(self.lblWordCount)
1006
- self.minLayout.addWidget(self.minWordCount)
1007
- self.minLayout.addSpacing(mPx)
1008
- self.minLayout.addWidget(self.lblCharCount)
1009
- self.minLayout.addWidget(self.minCharCount)
1010
- self.minLayout.addStretch(1)
1011
- self.minLayout.setSpacing(mPx)
1012
- self.minLayout.setContentsMargins(0, 0, 0, 0)
1013
-
1014
- self.minWidget.setLayout(self.minLayout)
1015
-
1016
- return
1017
-
1018
- def _buildMaximal(self) -> None:
1019
- """Build the maximal stats page."""
1020
- hPx = CONFIG.pxInt(12)
1021
- vPx = CONFIG.pxInt(4)
1022
-
1023
- # Left Column
1056
+ # Maximal Form, Left Column
1024
1057
  self.maxTotalWords = QLabel(self)
1025
1058
  self.maxHeadWords = QLabel(self)
1026
1059
  self.maxTextWords = QLabel(self)
@@ -1034,20 +1067,19 @@ class _StatsWidget(QWidget):
1034
1067
  self.maxParCount.setAlignment(QtAlignRight)
1035
1068
 
1036
1069
  self.leftForm = QFormLayout()
1037
- self.leftForm.addRow(self.tr("Words"), self.maxTotalWords)
1038
- self.leftForm.addRow(self.tr("Words in Headings"), self.maxHeadWords)
1039
- self.leftForm.addRow(self.tr("Words in Text"), self.maxTextWords)
1070
+ self.leftForm.addRow(trAllWords, self.maxTotalWords)
1071
+ self.leftForm.addRow(trTitleWords, self.maxHeadWords)
1072
+ self.leftForm.addRow(trTextWords, self.maxTextWords)
1040
1073
  self.leftForm.addRow("", QLabel(self))
1041
- self.leftForm.addRow(self.tr("Headings"), self.maxTitleCount)
1042
- self.leftForm.addRow(self.tr("Paragraphs"), self.maxParCount)
1074
+ self.leftForm.addRow(trTitleCount, self.maxTitleCount)
1075
+ self.leftForm.addRow(trParagraphCount, self.maxParCount)
1043
1076
  self.leftForm.setHorizontalSpacing(hPx)
1044
1077
  self.leftForm.setVerticalSpacing(vPx)
1045
1078
 
1046
- # Right Column
1079
+ # Maximal Form, Right Column
1047
1080
  self.maxTotalChars = QLabel(self)
1048
1081
  self.maxHeaderChars = QLabel(self)
1049
1082
  self.maxTextChars = QLabel(self)
1050
-
1051
1083
  self.maxTotalWordChars = QLabel(self)
1052
1084
  self.maxHeadWordChars = QLabel(self)
1053
1085
  self.maxTextWordChars = QLabel(self)
@@ -1055,22 +1087,31 @@ class _StatsWidget(QWidget):
1055
1087
  self.maxTotalChars.setAlignment(QtAlignRight)
1056
1088
  self.maxHeaderChars.setAlignment(QtAlignRight)
1057
1089
  self.maxTextChars.setAlignment(QtAlignRight)
1058
-
1059
1090
  self.maxTotalWordChars.setAlignment(QtAlignRight)
1060
1091
  self.maxHeadWordChars.setAlignment(QtAlignRight)
1061
1092
  self.maxTextWordChars.setAlignment(QtAlignRight)
1062
1093
 
1063
1094
  self.rightForm = QFormLayout()
1064
- self.rightForm.addRow(self.tr("Characters"), self.maxTotalChars)
1065
- self.rightForm.addRow(self.tr("Characters in Headings"), self.maxHeaderChars)
1066
- self.rightForm.addRow(self.tr("Characters in Text"), self.maxTextChars)
1067
- self.rightForm.addRow(self.tr("Characters, No Spaces"), self.maxTotalWordChars)
1068
- self.rightForm.addRow(self.tr("Characters in Headings, No Spaces"), self.maxHeadWordChars)
1069
- self.rightForm.addRow(self.tr("Characters in Text, No Spaces"), self.maxTextWordChars)
1095
+ self.rightForm.addRow(trAllChars, self.maxTotalChars)
1096
+ self.rightForm.addRow(trTitleChars, self.maxHeaderChars)
1097
+ self.rightForm.addRow(trTextChars, self.maxTextChars)
1098
+ self.rightForm.addRow(trAllWordChars, self.maxTotalWordChars)
1099
+ self.rightForm.addRow(trTitleWordChars, self.maxHeadWordChars)
1100
+ self.rightForm.addRow(trTextWordChars, self.maxTextWordChars)
1070
1101
  self.rightForm.setHorizontalSpacing(hPx)
1071
1102
  self.rightForm.setVerticalSpacing(vPx)
1072
1103
 
1073
1104
  # Assemble
1105
+ self.minLayout = QHBoxLayout()
1106
+ self.minLayout.addWidget(QLabel(trAllWords, self))
1107
+ self.minLayout.addWidget(self.minWordCount)
1108
+ self.minLayout.addSpacing(mPx)
1109
+ self.minLayout.addWidget(QLabel(trAllChars, self))
1110
+ self.minLayout.addWidget(self.minCharCount)
1111
+ self.minLayout.addStretch(1)
1112
+ self.minLayout.setSpacing(mPx)
1113
+ self.minLayout.setContentsMargins(0, 0, 0, 0)
1114
+
1074
1115
  self.maxLayout = QHBoxLayout()
1075
1116
  self.maxLayout.addLayout(self.leftForm)
1076
1117
  self.maxLayout.addLayout(self.rightForm)
@@ -1078,6 +1119,7 @@ class _StatsWidget(QWidget):
1078
1119
  self.maxLayout.setSpacing(CONFIG.pxInt(32))
1079
1120
  self.maxLayout.setContentsMargins(0, 0, 0, 0)
1080
1121
 
1122
+ self.minWidget.setLayout(self.minLayout)
1081
1123
  self.maxWidget.setLayout(self.maxLayout)
1082
1124
 
1083
1125
  return