novelWriter 2.2.1__py3-none-any.whl → 2.3b1__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 (110) hide show
  1. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/METADATA +1 -1
  2. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/RECORD +102 -92
  3. novelwriter/__init__.py +4 -4
  4. novelwriter/assets/icons/typicons_dark/icons.conf +6 -0
  5. novelwriter/assets/icons/typicons_dark/mixed_import.svg +5 -0
  6. novelwriter/assets/icons/typicons_dark/typ_document-add-col.svg +8 -0
  7. novelwriter/assets/icons/typicons_dark/typ_document-add.svg +4 -0
  8. novelwriter/assets/icons/typicons_dark/typ_document.svg +4 -0
  9. novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +4 -0
  10. novelwriter/assets/icons/typicons_light/icons.conf +6 -0
  11. novelwriter/assets/icons/typicons_light/mixed_import.svg +5 -0
  12. novelwriter/assets/icons/typicons_light/typ_document-add-col.svg +8 -0
  13. novelwriter/assets/icons/typicons_light/typ_document-add.svg +4 -0
  14. novelwriter/assets/icons/typicons_light/typ_document.svg +4 -0
  15. novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +4 -0
  16. novelwriter/assets/images/novelwriter-text-dark.svg +4 -0
  17. novelwriter/assets/images/novelwriter-text-light.svg +4 -0
  18. novelwriter/assets/images/welcome-dark.jpg +0 -0
  19. novelwriter/assets/images/welcome-light.jpg +0 -0
  20. novelwriter/assets/manual.pdf +0 -0
  21. novelwriter/assets/sample.zip +0 -0
  22. novelwriter/assets/syntax/default_dark.conf +1 -0
  23. novelwriter/assets/syntax/default_light.conf +1 -0
  24. novelwriter/assets/syntax/grey_dark.conf +1 -0
  25. novelwriter/assets/syntax/grey_light.conf +1 -0
  26. novelwriter/assets/syntax/light_owl.conf +1 -0
  27. novelwriter/assets/syntax/night_owl.conf +1 -0
  28. novelwriter/assets/syntax/solarized_dark.conf +1 -0
  29. novelwriter/assets/syntax/solarized_light.conf +1 -0
  30. novelwriter/assets/syntax/tomorrow.conf +1 -0
  31. novelwriter/assets/syntax/tomorrow_night.conf +1 -0
  32. novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
  33. novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
  34. novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
  35. novelwriter/assets/text/credits_en.htm +4 -2
  36. novelwriter/assets/themes/default_dark.conf +2 -2
  37. novelwriter/assets/themes/default_light.conf +2 -2
  38. novelwriter/common.py +48 -37
  39. novelwriter/config.py +36 -41
  40. novelwriter/constants.py +38 -16
  41. novelwriter/core/buildsettings.py +7 -7
  42. novelwriter/core/coretools.py +192 -154
  43. novelwriter/core/docbuild.py +6 -3
  44. novelwriter/core/document.py +6 -6
  45. novelwriter/core/index.py +89 -56
  46. novelwriter/core/item.py +21 -3
  47. novelwriter/core/options.py +8 -7
  48. novelwriter/core/project.py +69 -44
  49. novelwriter/core/projectdata.py +1 -14
  50. novelwriter/core/projectxml.py +13 -41
  51. novelwriter/core/sessions.py +2 -1
  52. novelwriter/core/spellcheck.py +2 -1
  53. novelwriter/core/status.py +2 -1
  54. novelwriter/core/storage.py +178 -140
  55. novelwriter/core/tohtml.py +4 -2
  56. novelwriter/core/tokenizer.py +73 -45
  57. novelwriter/core/toodt.py +40 -30
  58. novelwriter/core/tree.py +3 -2
  59. novelwriter/dialogs/about.py +70 -160
  60. novelwriter/dialogs/docmerge.py +6 -5
  61. novelwriter/dialogs/docsplit.py +6 -6
  62. novelwriter/dialogs/editlabel.py +1 -1
  63. novelwriter/dialogs/preferences.py +553 -703
  64. novelwriter/dialogs/{projsettings.py → projectsettings.py} +288 -262
  65. novelwriter/dialogs/quotes.py +27 -23
  66. novelwriter/dialogs/wordlist.py +96 -40
  67. novelwriter/enum.py +20 -18
  68. novelwriter/error.py +1 -1
  69. novelwriter/extensions/circularprogress.py +11 -11
  70. novelwriter/extensions/configlayout.py +185 -134
  71. novelwriter/extensions/modified.py +81 -0
  72. novelwriter/extensions/novelselector.py +26 -12
  73. novelwriter/extensions/pagedsidebar.py +14 -16
  74. novelwriter/extensions/simpleprogress.py +5 -5
  75. novelwriter/extensions/statusled.py +8 -8
  76. novelwriter/extensions/switch.py +31 -63
  77. novelwriter/extensions/switchbox.py +1 -1
  78. novelwriter/extensions/versioninfo.py +153 -0
  79. novelwriter/gui/doceditor.py +178 -150
  80. novelwriter/gui/dochighlight.py +63 -92
  81. novelwriter/gui/docviewer.py +49 -51
  82. novelwriter/gui/docviewerpanel.py +72 -24
  83. novelwriter/gui/itemdetails.py +7 -7
  84. novelwriter/gui/mainmenu.py +14 -18
  85. novelwriter/gui/noveltree.py +9 -8
  86. novelwriter/gui/outline.py +98 -75
  87. novelwriter/gui/projtree.py +188 -61
  88. novelwriter/gui/sidebar.py +3 -4
  89. novelwriter/gui/statusbar.py +3 -4
  90. novelwriter/gui/theme.py +60 -68
  91. novelwriter/guimain.py +49 -156
  92. novelwriter/shared.py +15 -1
  93. novelwriter/tools/dictionaries.py +5 -6
  94. novelwriter/tools/manuscript.py +6 -6
  95. novelwriter/tools/manussettings.py +192 -221
  96. novelwriter/tools/noveldetails.py +525 -0
  97. novelwriter/tools/welcome.py +802 -0
  98. novelwriter/tools/writingstats.py +9 -9
  99. novelwriter/assets/images/wizard-back.jpg +0 -0
  100. novelwriter/assets/text/gplv3_en.htm +0 -641
  101. novelwriter/assets/text/release_notes.htm +0 -60
  102. novelwriter/dialogs/projdetails.py +0 -518
  103. novelwriter/dialogs/projload.py +0 -294
  104. novelwriter/dialogs/updates.py +0 -172
  105. novelwriter/extensions/pageddialog.py +0 -130
  106. novelwriter/tools/projwizard.py +0 -478
  107. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/LICENSE.md +0 -0
  108. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/WHEEL +0 -0
  109. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/entry_points.txt +0 -0
  110. {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/top_level.txt +0 -0
@@ -24,20 +24,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
24
24
  from __future__ import annotations
25
25
 
26
26
  import logging
27
- import novelwriter
28
27
 
29
- from datetime import datetime
30
-
31
- from PyQt5.QtGui import QCloseEvent, QCursor
28
+ from PyQt5.QtGui import QCloseEvent, QColor
32
29
  from PyQt5.QtCore import Qt
33
30
  from PyQt5.QtWidgets import (
34
- qApp, QDialog, QDialogButtonBox, QHBoxLayout, QLabel, QTabWidget,
35
- QTextBrowser, QVBoxLayout, QWidget
31
+ QDialog, QDialogButtonBox, QHBoxLayout, QLabel, QTextBrowser, QVBoxLayout,
32
+ QWidget
36
33
  )
37
34
 
38
35
  from novelwriter import CONFIG, SHARED
39
36
  from novelwriter.common import readTextFile
40
- from novelwriter.constants import nwConst
37
+ from novelwriter.extensions.configlayout import NColourLabel
38
+ from novelwriter.extensions.versioninfo import VersionInfoWidget
41
39
 
42
40
  logger = logging.getLogger(__name__)
43
41
 
@@ -50,62 +48,67 @@ class GuiAbout(QDialog):
50
48
  logger.debug("Create: GuiAbout")
51
49
  self.setObjectName("GuiAbout")
52
50
 
53
- self.outerBox = QVBoxLayout()
54
- self.innerBox = QHBoxLayout()
55
- self.innerBox.setSpacing(CONFIG.pxInt(16))
56
-
57
51
  self.setWindowTitle(self.tr("About novelWriter"))
58
- self.setMinimumWidth(CONFIG.pxInt(650))
59
- self.setMinimumHeight(CONFIG.pxInt(600))
60
-
61
- nPx = CONFIG.pxInt(96)
62
- self.nwIcon = QLabel()
63
- self.nwIcon.setPixmap(SHARED.theme.getPixmap("novelwriter", (nPx, nPx)))
64
- self.lblName = QLabel("<b>novelWriter</b>")
65
- self.lblVers = QLabel(f"v{novelwriter.__version__}")
66
- self.lblDate = QLabel(datetime.strptime(novelwriter.__date__, "%Y-%m-%d").strftime("%x"))
67
-
68
- self.leftBox = QVBoxLayout()
69
- self.leftBox.setSpacing(CONFIG.pxInt(4))
70
- self.leftBox.addWidget(self.nwIcon, 0, Qt.AlignCenter)
71
- self.leftBox.addWidget(self.lblName, 0, Qt.AlignCenter)
72
- self.leftBox.addWidget(self.lblVers, 0, Qt.AlignCenter)
73
- self.leftBox.addWidget(self.lblDate, 0, Qt.AlignCenter)
74
- self.leftBox.addStretch(1)
75
- self.innerBox.addLayout(self.leftBox)
76
-
77
- # Pages
78
- self.pageAbout = QTextBrowser()
79
- self.pageAbout.setOpenExternalLinks(True)
80
- self.pageAbout.document().setDocumentMargin(CONFIG.pxInt(16))
81
-
82
- self.pageNotes = QTextBrowser()
83
- self.pageNotes.setOpenExternalLinks(True)
84
- self.pageNotes.document().setDocumentMargin(CONFIG.pxInt(16))
85
-
86
- self.pageCredits = QTextBrowser()
87
- self.pageCredits.setOpenExternalLinks(True)
88
- self.pageCredits.document().setDocumentMargin(CONFIG.pxInt(16))
89
-
90
- self.pageLicense = QTextBrowser()
91
- self.pageLicense.setOpenExternalLinks(True)
92
- self.pageLicense.document().setDocumentMargin(CONFIG.pxInt(16))
93
-
94
- # Main Tab Area
95
- self.tabBox = QTabWidget()
96
- self.tabBox.addTab(self.pageAbout, self.tr("About"))
97
- self.tabBox.addTab(self.pageNotes, self.tr("Release"))
98
- self.tabBox.addTab(self.pageCredits, self.tr("Credits"))
99
- self.tabBox.addTab(self.pageLicense, self.tr("Licence"))
100
- self.innerBox.addWidget(self.tabBox)
101
-
102
- # OK Button
103
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok)
104
- self.buttonBox.accepted.connect(self.close)
105
-
106
- self.outerBox.addLayout(self.innerBox)
107
- self.outerBox.addWidget(self.buttonBox)
52
+ self.resize(CONFIG.pxInt(700), CONFIG.pxInt(500))
53
+
54
+ hA = CONFIG.pxInt(8)
55
+ hB = CONFIG.pxInt(16)
56
+ nwH = CONFIG.pxInt(36)
57
+ nwPx = CONFIG.pxInt(128)
58
+
59
+ # Logo and Banner
60
+ self.nwImage = SHARED.theme.loadDecoration("nw-text", h=nwH)
61
+ self.bgColor = QColor(255, 255, 255) if SHARED.theme.isLightTheme else QColor(54, 54, 54)
62
+
63
+ self.nwLogo = QLabel(self)
64
+ self.nwLogo.setPixmap(SHARED.theme.getPixmap("novelwriter", (nwPx, nwPx)))
65
+
66
+ self.nwLabel = QLabel(self)
67
+ self.nwLabel.setPixmap(self.nwImage)
68
+
69
+ self.nwInfo = VersionInfoWidget(self)
70
+
71
+ self.nwLicence = QLabel(self.tr("This application is licenced under {0}".format(
72
+ "<a href='https://www.gnu.org/licenses/gpl-3.0.html'>GPL v3.0</a>"
73
+ )))
74
+ self.nwLicence.setOpenExternalLinks(True)
75
+
76
+ # Credits
77
+ self.lblCredits = NColourLabel(
78
+ self.tr("Credits"), scale=1.6, parent=self, bold=True
79
+ )
80
+
81
+ self.txtCredits = QTextBrowser(self)
82
+ self.txtCredits.setOpenExternalLinks(True)
83
+ self.txtCredits.document().setDocumentMargin(0)
84
+ self.txtCredits.setViewportMargins(0, hA, hA, 0)
85
+
86
+ # Buttons
87
+ self.btnBox = QDialogButtonBox(QDialogButtonBox.Close, self)
88
+ self.btnBox.rejected.connect(self.close)
89
+
90
+ # Assemble
91
+ self.innerBox = QVBoxLayout()
92
+ self.innerBox.addSpacing(hB)
93
+ self.innerBox.addWidget(self.nwLabel)
94
+ self.innerBox.addWidget(self.nwInfo)
95
+ self.innerBox.addSpacing(hA)
96
+ self.innerBox.addWidget(self.nwLicence)
97
+ self.innerBox.addSpacing(hA)
98
+ self.innerBox.addWidget(self.lblCredits)
99
+ self.innerBox.addWidget(self.txtCredits)
100
+ self.innerBox.addSpacing(hB)
101
+ self.innerBox.addWidget(self.btnBox)
102
+
103
+ topRight = Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignRight
104
+
105
+ self.outerBox = QHBoxLayout()
106
+ self.outerBox.addWidget(self.nwLogo, 0, topRight)
107
+ self.outerBox.addLayout(self.innerBox, 1)
108
+
108
109
  self.setLayout(self.outerBox)
110
+ self.setSizeGripEnabled(True)
111
+ self._setStyleSheet()
109
112
 
110
113
  logger.debug("Ready: GuiAbout")
111
114
 
@@ -117,18 +120,7 @@ class GuiAbout(QDialog):
117
120
 
118
121
  def populateGUI(self) -> None:
119
122
  """Populate tabs with text."""
120
- qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
121
- self._setStyleSheet()
122
- self._fillAboutPage()
123
- self._fillNotesPage()
124
123
  self._fillCreditsPage()
125
- self._fillLicensePage()
126
- qApp.restoreOverrideCursor()
127
- return
128
-
129
- def showReleaseNotes(self) -> None:
130
- """Show the release notes."""
131
- self.tabBox.setCurrentWidget(self.pageNotes)
132
124
  return
133
125
 
134
126
  ##
@@ -145,104 +137,22 @@ class GuiAbout(QDialog):
145
137
  # Internal Functions
146
138
  ##
147
139
 
148
- def _fillAboutPage(self) -> None:
149
- """Generate the content for the About page."""
150
- aboutMsg = (
151
- "<h2>{title1}</h2>"
152
- "<p>{copy}</p>"
153
- "<p>{link}</p>"
154
- "<p>{intro}</p>"
155
- "<p>{license1}</p>"
156
- "<p>{license2}</p>"
157
- "<p>{license3}</p>"
158
- ).format(
159
- title1=self.tr("About novelWriter"),
160
- copy=novelwriter.__copyright__,
161
- link=self.tr("Website: {0}").format(
162
- f"<a href='{nwConst.URL_WEB}'>{novelwriter.__domain__}</a>"
163
- ),
164
- intro=self.tr(
165
- "novelWriter is a markdown-like text editor designed for organising and "
166
- "writing novels. It is written in Python 3 with a Qt5 GUI, using PyQt5."
167
- ),
168
- license1=self.tr(
169
- "novelWriter is free software: you can redistribute it and/or modify it "
170
- "under the terms of the GNU General Public License as published by the "
171
- "Free Software Foundation, either version 3 of the License, or (at your "
172
- "option) any later version."
173
- ),
174
- license2=self.tr(
175
- "novelWriter is distributed in the hope that it will be useful, but "
176
- "WITHOUT ANY WARRANTY; without even the implied warranty of "
177
- "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
178
- ),
179
- license3=self.tr(
180
- "See the Licence tab for the full licence text, or visit the "
181
- "GNU website at {0} for more details."
182
- ).format(
183
- "<a href='https://www.gnu.org/licenses/gpl-3.0.html'>GPL v3.0</a>"
184
- ),
185
- )
186
-
187
- self.pageAbout.setHtml(aboutMsg)
188
-
189
- return
190
-
191
- def _fillNotesPage(self) -> None:
192
- """Load the content for the Release Notes page."""
193
- docPath = CONFIG.assetPath("text") / "release_notes.htm"
194
- docText = readTextFile(docPath)
195
- if docText:
196
- self.pageNotes.setHtml(docText)
197
- else:
198
- self.pageNotes.setHtml("Error loading release notes text ...")
199
- return
200
-
201
140
  def _fillCreditsPage(self) -> None:
202
141
  """Load the content for the Credits page."""
203
142
  docPath = CONFIG.assetPath("text") / "credits_en.htm"
204
143
  docText = readTextFile(docPath)
205
144
  if docText:
206
- self.pageCredits.setHtml(docText)
207
- else:
208
- self.pageCredits.setHtml("Error loading credits text ...")
209
- return
210
-
211
- def _fillLicensePage(self) -> None:
212
- """Load the content for the Licence page."""
213
- docPath = CONFIG.assetPath("text") / "gplv3_en.htm"
214
- docText = readTextFile(docPath)
215
- if docText:
216
- self.pageLicense.setHtml(docText)
145
+ self.txtCredits.setHtml(docText)
217
146
  else:
218
- self.pageLicense.setHtml("Error loading licence text ...")
147
+ self.txtCredits.setHtml("Error loading credits text ...")
219
148
  return
220
149
 
221
150
  def _setStyleSheet(self) -> None:
222
151
  """Set stylesheet for all browser tabs."""
223
- styleSheet = (
224
- "h1, h2, h3, h4 {{"
225
- " color: rgb({hColR},{hColG},{hColB});"
226
- "}}\n"
227
- "a {{"
228
- " color: rgb({hColR},{hColG},{hColB});"
229
- "}}\n"
230
- ".alt {{"
231
- " color: rgb({kColR},{kColG},{kColB});"
232
- "}}\n"
233
- ).format(
234
- hColR=SHARED.theme.colHead[0],
235
- hColG=SHARED.theme.colHead[1],
236
- hColB=SHARED.theme.colHead[2],
237
- kColR=SHARED.theme.colKey[0],
238
- kColG=SHARED.theme.colKey[1],
239
- kColB=SHARED.theme.colKey[2],
240
- )
241
- self.pageAbout.document().setDefaultStyleSheet(styleSheet)
242
- self.pageNotes.document().setDefaultStyleSheet(styleSheet)
243
- self.pageCredits.document().setDefaultStyleSheet(styleSheet)
244
- self.pageLicense.document().setDefaultStyleSheet(styleSheet)
245
-
152
+ baseCol = self.palette().window().color()
153
+ self.txtCredits.setStyleSheet((
154
+ "QTextBrowser {{border: none; background: rgb({r},{g},{b});}} "
155
+ ).format(r=baseCol.red(), g=baseCol.green(), b=baseCol.blue()))
246
156
  return
247
157
 
248
158
  # END Class GuiAbout
@@ -35,7 +35,7 @@ from PyQt5.QtWidgets import (
35
35
 
36
36
  from novelwriter import CONFIG, SHARED
37
37
  from novelwriter.extensions.switch import NSwitch
38
- from novelwriter.extensions.configlayout import NHelpLabel
38
+ from novelwriter.extensions.configlayout import NColourLabel
39
39
 
40
40
  logger = logging.getLogger(__name__)
41
41
 
@@ -54,9 +54,10 @@ class GuiDocMerge(QDialog):
54
54
  self._data = {}
55
55
 
56
56
  self.headLabel = QLabel("<b>{0}</b>".format(self.tr("Documents to Merge")))
57
- self.helpLabel = NHelpLabel(self.tr(
58
- "Drag and drop items to change the order, or uncheck to exclude."
59
- ), SHARED.theme.helpText)
57
+ self.helpLabel = NColourLabel(
58
+ self.tr("Drag and drop items to change the order, or uncheck to exclude."),
59
+ SHARED.theme.helpText, parent=self, wrap=True
60
+ )
60
61
 
61
62
  iPx = SHARED.theme.baseIconSize
62
63
  hSp = CONFIG.pxInt(12)
@@ -73,7 +74,7 @@ class GuiDocMerge(QDialog):
73
74
 
74
75
  # Merge Options
75
76
  self.trashLabel = QLabel(self.tr("Move merged items to Trash"))
76
- self.trashSwitch = NSwitch(width=2*iPx, height=iPx)
77
+ self.trashSwitch = NSwitch(self, height=iPx)
77
78
 
78
79
  self.optBox = QGridLayout()
79
80
  self.optBox.addWidget(self.trashLabel, 0, 0)
@@ -35,7 +35,7 @@ from PyQt5.QtWidgets import (
35
35
 
36
36
  from novelwriter import CONFIG, SHARED
37
37
  from novelwriter.extensions.switch import NSwitch
38
- from novelwriter.extensions.configlayout import NHelpLabel
38
+ from novelwriter.extensions.configlayout import NColourLabel
39
39
 
40
40
  logger = logging.getLogger(__name__)
41
41
 
@@ -58,9 +58,9 @@ class GuiDocSplit(QDialog):
58
58
  self.setWindowTitle(self.tr("Split Document"))
59
59
 
60
60
  self.headLabel = QLabel("<b>{0}</b>".format(self.tr("Document Headers")))
61
- self.helpLabel = NHelpLabel(
61
+ self.helpLabel = NColourLabel(
62
62
  self.tr("Select the maximum level to split into files."),
63
- SHARED.theme.helpText
63
+ SHARED.theme.helpText, parent=self, wrap=True
64
64
  )
65
65
 
66
66
  # Values
@@ -92,15 +92,15 @@ class GuiDocSplit(QDialog):
92
92
 
93
93
  # Split Options
94
94
  self.folderLabel = QLabel(self.tr("Split into a new folder"))
95
- self.folderSwitch = NSwitch(width=2*iPx, height=iPx)
95
+ self.folderSwitch = NSwitch(self, height=iPx)
96
96
  self.folderSwitch.setChecked(intoFolder)
97
97
 
98
98
  self.hierarchyLabel = QLabel(self.tr("Create document hierarchy"))
99
- self.hierarchySwitch = NSwitch(width=2*iPx, height=iPx)
99
+ self.hierarchySwitch = NSwitch(self, height=iPx)
100
100
  self.hierarchySwitch.setChecked(docHierarchy)
101
101
 
102
102
  self.trashLabel = QLabel(self.tr("Move split document to Trash"))
103
- self.trashSwitch = NSwitch(width=2*iPx, height=iPx)
103
+ self.trashSwitch = NSwitch(self, height=iPx)
104
104
 
105
105
  self.optBox = QGridLayout()
106
106
  self.optBox.addWidget(self.folderLabel, 0, 0)
@@ -48,7 +48,7 @@ class GuiEditLabel(QDialog):
48
48
  mSp = CONFIG.pxInt(12)
49
49
 
50
50
  # Item Label
51
- self.labelValue = QLineEdit()
51
+ self.labelValue = QLineEdit(self)
52
52
  self.labelValue.setMinimumWidth(mVd)
53
53
  self.labelValue.setMaxLength(200)
54
54
  self.labelValue.setText(text)