novelWriter 2.4.4__py3-none-any.whl → 2.5__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.
- {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/METADATA +4 -5
- {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/RECORD +121 -111
- {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/WHEEL +1 -1
- novelwriter/__init__.py +33 -39
- novelwriter/assets/i18n/nw_de_DE.qm +0 -0
- novelwriter/assets/i18n/nw_en_US.qm +0 -0
- novelwriter/assets/i18n/nw_es_419.qm +0 -0
- novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
- novelwriter/assets/i18n/nw_it_IT.qm +0 -0
- novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
- novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
- novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
- novelwriter/assets/i18n/nw_pl_PL.qm +0 -0
- novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
- novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
- novelwriter/assets/i18n/project_en_GB.json +1 -0
- novelwriter/assets/i18n/project_pl_PL.json +116 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +2 -0
- novelwriter/assets/icons/typicons_dark/nw_font.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_quote.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +2 -0
- novelwriter/assets/icons/typicons_light/nw_font.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_quote.svg +4 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/syntax/cyberpunk_night.conf +5 -3
- novelwriter/assets/syntax/default_dark.conf +32 -18
- novelwriter/assets/syntax/default_light.conf +24 -10
- novelwriter/assets/syntax/dracula.conf +44 -0
- novelwriter/assets/syntax/grey_dark.conf +5 -4
- novelwriter/assets/syntax/grey_light.conf +5 -4
- novelwriter/assets/syntax/light_owl.conf +7 -6
- novelwriter/assets/syntax/night_owl.conf +7 -6
- novelwriter/assets/syntax/snazzy.conf +42 -0
- novelwriter/assets/syntax/solarized_dark.conf +4 -3
- novelwriter/assets/syntax/solarized_light.conf +4 -3
- novelwriter/assets/syntax/tango.conf +27 -11
- novelwriter/assets/syntax/tomorrow.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night.conf +7 -6
- novelwriter/assets/syntax/tomorrow_night_blue.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night_bright.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night_eighties.conf +6 -5
- novelwriter/assets/text/credits_en.htm +52 -41
- novelwriter/assets/themes/cyberpunk_night.conf +3 -0
- novelwriter/assets/themes/default_dark.conf +2 -0
- novelwriter/assets/themes/default_light.conf +2 -0
- novelwriter/assets/themes/dracula.conf +48 -0
- novelwriter/assets/themes/solarized_dark.conf +2 -0
- novelwriter/assets/themes/solarized_light.conf +2 -0
- novelwriter/common.py +33 -12
- novelwriter/config.py +184 -98
- novelwriter/constants.py +47 -35
- novelwriter/core/buildsettings.py +68 -69
- novelwriter/core/coretools.py +5 -23
- novelwriter/core/docbuild.py +52 -40
- novelwriter/core/document.py +3 -5
- novelwriter/core/index.py +115 -45
- novelwriter/core/item.py +8 -19
- novelwriter/core/options.py +2 -4
- novelwriter/core/project.py +37 -61
- novelwriter/core/projectdata.py +1 -3
- novelwriter/core/projectxml.py +12 -15
- novelwriter/core/sessions.py +3 -5
- novelwriter/core/spellcheck.py +4 -9
- novelwriter/core/status.py +211 -164
- novelwriter/core/storage.py +0 -8
- novelwriter/core/tohtml.py +139 -105
- novelwriter/core/tokenizer.py +278 -122
- novelwriter/core/{tomd.py → tomarkdown.py} +97 -78
- novelwriter/core/toodt.py +257 -166
- novelwriter/core/toqdoc.py +419 -0
- novelwriter/core/tree.py +5 -7
- novelwriter/dialogs/about.py +11 -18
- novelwriter/dialogs/docmerge.py +17 -19
- novelwriter/dialogs/docsplit.py +17 -19
- novelwriter/dialogs/editlabel.py +6 -10
- novelwriter/dialogs/preferences.py +200 -164
- novelwriter/dialogs/projectsettings.py +225 -189
- novelwriter/dialogs/quotes.py +12 -9
- novelwriter/dialogs/wordlist.py +9 -15
- novelwriter/enum.py +35 -30
- novelwriter/error.py +8 -15
- novelwriter/extensions/configlayout.py +55 -21
- novelwriter/extensions/eventfilters.py +1 -5
- novelwriter/extensions/modified.py +58 -14
- novelwriter/extensions/novelselector.py +1 -3
- novelwriter/extensions/pagedsidebar.py +9 -12
- novelwriter/extensions/{circularprogress.py → progressbars.py} +30 -8
- novelwriter/extensions/statusled.py +40 -26
- novelwriter/extensions/switch.py +4 -6
- novelwriter/extensions/switchbox.py +7 -6
- novelwriter/extensions/versioninfo.py +3 -9
- novelwriter/gui/doceditor.py +120 -139
- novelwriter/gui/dochighlight.py +231 -186
- novelwriter/gui/docviewer.py +69 -108
- novelwriter/gui/docviewerpanel.py +3 -10
- novelwriter/gui/editordocument.py +1 -3
- novelwriter/gui/itemdetails.py +7 -11
- novelwriter/gui/mainmenu.py +22 -18
- novelwriter/gui/noveltree.py +11 -24
- novelwriter/gui/outline.py +15 -26
- novelwriter/gui/projtree.py +35 -60
- novelwriter/gui/search.py +10 -3
- novelwriter/gui/sidebar.py +2 -6
- novelwriter/gui/statusbar.py +29 -37
- novelwriter/gui/theme.py +26 -48
- novelwriter/guimain.py +162 -160
- novelwriter/shared.py +36 -32
- novelwriter/text/patterns.py +113 -0
- novelwriter/tools/dictionaries.py +10 -20
- novelwriter/tools/lipsum.py +10 -16
- novelwriter/tools/manusbuild.py +9 -11
- novelwriter/tools/manuscript.py +71 -145
- novelwriter/tools/manussettings.py +71 -75
- novelwriter/tools/noveldetails.py +16 -21
- novelwriter/tools/welcome.py +21 -26
- novelwriter/tools/writingstats.py +9 -12
- novelwriter/types.py +49 -4
- novelwriter/extensions/simpleprogress.py +0 -55
- {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.4.4.dist-info → novelWriter-2.5.dist-info}/top_level.txt +0 -0
novelwriter/shared.py
CHANGED
@@ -31,7 +31,8 @@ from time import time
|
|
31
31
|
from typing import TYPE_CHECKING, TypeVar
|
32
32
|
|
33
33
|
from PyQt5.QtCore import QObject, QRunnable, QThreadPool, QTimer, pyqtSignal
|
34
|
-
from PyQt5.
|
34
|
+
from PyQt5.QtGui import QFont
|
35
|
+
from PyQt5.QtWidgets import QFileDialog, QFontDialog, QMessageBox, QWidget
|
35
36
|
|
36
37
|
from novelwriter.common import formatFileFilter
|
37
38
|
from novelwriter.constants import nwFiles
|
@@ -171,6 +172,23 @@ class SharedData(QObject):
|
|
171
172
|
logger.debug("Thread Pool Max Count: %d", QThreadPool.globalInstance().maxThreadCount())
|
172
173
|
return
|
173
174
|
|
175
|
+
def closeEditor(self, tHandle: str | None = None) -> None:
|
176
|
+
"""Close the document editor, optionally a specific document."""
|
177
|
+
if tHandle is None or tHandle == self.mainGui.docEditor.docHandle:
|
178
|
+
self.mainGui.closeDocument()
|
179
|
+
return
|
180
|
+
|
181
|
+
def saveEditor(self, tHandle: str | None = None) -> None:
|
182
|
+
"""Save the editor content, optionally a specific document."""
|
183
|
+
docEditor = self.mainGui.docEditor
|
184
|
+
if (
|
185
|
+
self.hasProject and docEditor.docHandle
|
186
|
+
and (tHandle is None or tHandle == docEditor.docHandle)
|
187
|
+
):
|
188
|
+
logger.debug("Saving editor document before action")
|
189
|
+
docEditor.saveText()
|
190
|
+
return
|
191
|
+
|
174
192
|
def openProject(self, path: str | Path, clearLock: bool = False) -> bool:
|
175
193
|
"""Open a project."""
|
176
194
|
if self.project.isValid:
|
@@ -198,25 +216,12 @@ class SharedData(QObject):
|
|
198
216
|
|
199
217
|
def closeProject(self) -> None:
|
200
218
|
"""Close the current project."""
|
201
|
-
self.
|
219
|
+
self._closeToolDialogs()
|
202
220
|
self.project.closeProject(self._idleTime)
|
203
221
|
self._resetProject()
|
204
222
|
self._resetIdleTimer()
|
205
223
|
return
|
206
224
|
|
207
|
-
def ensureEditorSaved(self, tHandle: str | None) -> None:
|
208
|
-
"""Ensure that the editor content is saved. Optionally, only if
|
209
|
-
it is a specific handle.
|
210
|
-
"""
|
211
|
-
docEditor = self.mainGui.docEditor
|
212
|
-
if (
|
213
|
-
self.hasProject and docEditor.docHandle
|
214
|
-
and (tHandle is None or tHandle == docEditor.docHandle)
|
215
|
-
):
|
216
|
-
logger.debug("Saving editor document before action")
|
217
|
-
docEditor.saveText()
|
218
|
-
return
|
219
|
-
|
220
225
|
def updateSpellCheckLanguage(self, reload: bool = False) -> None:
|
221
226
|
"""Update the active spell check language from settings."""
|
222
227
|
from novelwriter import CONFIG
|
@@ -257,8 +262,11 @@ class SharedData(QObject):
|
|
257
262
|
QThreadPool.globalInstance().start(runnable, priority=priority)
|
258
263
|
return
|
259
264
|
|
260
|
-
def getProjectPath(
|
261
|
-
|
265
|
+
def getProjectPath(
|
266
|
+
self, parent: QWidget,
|
267
|
+
path: str | Path | None = None,
|
268
|
+
allowZip: bool = False
|
269
|
+
) -> Path | None:
|
262
270
|
"""Open the file dialog and select a novelWriter project file."""
|
263
271
|
label = (self.tr("novelWriter Project File or Zip File")
|
264
272
|
if allowZip else self.tr("novelWriter Project File"))
|
@@ -269,6 +277,13 @@ class SharedData(QObject):
|
|
269
277
|
)
|
270
278
|
return Path(selected) if selected else None
|
271
279
|
|
280
|
+
def getFont(self, current: QFont, native: bool) -> tuple[QFont, bool]:
|
281
|
+
"""Open the font dialog and select a font."""
|
282
|
+
kwargs = {}
|
283
|
+
if not native:
|
284
|
+
kwargs["options"] = QFontDialog.FontDialogOption.DontUseNativeDialog
|
285
|
+
return QFontDialog.getFont(current, self.mainGui, self.tr("Select Font"), **kwargs)
|
286
|
+
|
272
287
|
def findTopLevelWidget(self, kind: type[NWWidget]) -> NWWidget | None:
|
273
288
|
"""Find a top level widget."""
|
274
289
|
for widget in self.mainGui.children():
|
@@ -307,7 +322,6 @@ class SharedData(QObject):
|
|
307
322
|
if log:
|
308
323
|
logger.info(self._lastAlert, stacklevel=2)
|
309
324
|
alert.exec()
|
310
|
-
alert.deleteLater()
|
311
325
|
return
|
312
326
|
|
313
327
|
def warn(self, text: str, info: str = "", details: str = "", log: bool = True) -> None:
|
@@ -319,7 +333,6 @@ class SharedData(QObject):
|
|
319
333
|
if log:
|
320
334
|
logger.warning(self._lastAlert, stacklevel=2)
|
321
335
|
alert.exec()
|
322
|
-
alert.deleteLater()
|
323
336
|
return
|
324
337
|
|
325
338
|
def error(self, text: str, info: str = "", details: str = "", log: bool = True,
|
@@ -334,7 +347,6 @@ class SharedData(QObject):
|
|
334
347
|
if log:
|
335
348
|
logger.error(self._lastAlert, stacklevel=2)
|
336
349
|
alert.exec()
|
337
|
-
alert.deleteLater()
|
338
350
|
return
|
339
351
|
|
340
352
|
def question(self, text: str, info: str = "", details: str = "", warn: bool = False) -> bool:
|
@@ -345,7 +357,6 @@ class SharedData(QObject):
|
|
345
357
|
self._lastAlert = alert.logMessage
|
346
358
|
alert.exec()
|
347
359
|
isYes = alert.result() == QMessageBox.StandardButton.Yes
|
348
|
-
alert.deleteLater()
|
349
360
|
return isYes
|
350
361
|
|
351
362
|
##
|
@@ -370,19 +381,14 @@ class SharedData(QObject):
|
|
370
381
|
self._idleTime = 0.0
|
371
382
|
return
|
372
383
|
|
373
|
-
def
|
374
|
-
"""Close
|
375
|
-
from novelwriter.
|
376
|
-
from novelwriter.tools.writingstats import GuiWritingStats
|
377
|
-
|
384
|
+
def _closeToolDialogs(self) -> None:
|
385
|
+
"""Close all open tool dialogs."""
|
386
|
+
from novelwriter.extensions.modified import NToolDialog
|
378
387
|
for widget in self.mainGui.children():
|
379
|
-
if isinstance(widget,
|
388
|
+
if isinstance(widget, NToolDialog):
|
380
389
|
widget.close()
|
381
|
-
|
382
390
|
return
|
383
391
|
|
384
|
-
# END Class SharedData
|
385
|
-
|
386
392
|
|
387
393
|
class _GuiAlert(QMessageBox):
|
388
394
|
|
@@ -443,5 +449,3 @@ class _GuiAlert(QMessageBox):
|
|
443
449
|
self.setIconPixmap(self._theme.getPixmap("alert_question", (pSz, pSz)))
|
444
450
|
self.setWindowTitle(self.tr("Question"))
|
445
451
|
return
|
446
|
-
|
447
|
-
# END Class _GuiAlert
|
@@ -0,0 +1,113 @@
|
|
1
|
+
"""
|
2
|
+
novelWriter – Text Pattern Functions
|
3
|
+
====================================
|
4
|
+
|
5
|
+
File History:
|
6
|
+
Created: 2024-06-01 [2.5ec1]
|
7
|
+
|
8
|
+
This file is a part of novelWriter
|
9
|
+
Copyright 2018–2024, Veronica Berglyd Olsen
|
10
|
+
|
11
|
+
This program is free software: you can redistribute it and/or modify
|
12
|
+
it under the terms of the GNU General Public License as published by
|
13
|
+
the Free Software Foundation, either version 3 of the License, or
|
14
|
+
(at your option) any later version.
|
15
|
+
|
16
|
+
This program is distributed in the hope that it will be useful, but
|
17
|
+
WITHOUT ANY WARRANTY; without even the implied warranty of
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
19
|
+
General Public License for more details.
|
20
|
+
|
21
|
+
You should have received a copy of the GNU General Public License
|
22
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
23
|
+
"""
|
24
|
+
from __future__ import annotations
|
25
|
+
|
26
|
+
from PyQt5.QtCore import QRegularExpression
|
27
|
+
|
28
|
+
from novelwriter import CONFIG
|
29
|
+
from novelwriter.constants import nwRegEx
|
30
|
+
from novelwriter.types import QRegExUnicode
|
31
|
+
|
32
|
+
|
33
|
+
class RegExPatterns:
|
34
|
+
|
35
|
+
@property
|
36
|
+
def markdownItalic(self) -> QRegularExpression:
|
37
|
+
"""Markdown italic style."""
|
38
|
+
rxRule = QRegularExpression(nwRegEx.FMT_EI)
|
39
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
40
|
+
return rxRule
|
41
|
+
|
42
|
+
@property
|
43
|
+
def markdownBold(self) -> QRegularExpression:
|
44
|
+
"""Markdown bold style."""
|
45
|
+
rxRule = QRegularExpression(nwRegEx.FMT_EB)
|
46
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
47
|
+
return rxRule
|
48
|
+
|
49
|
+
@property
|
50
|
+
def markdownStrike(self) -> QRegularExpression:
|
51
|
+
"""Markdown strikethrough style."""
|
52
|
+
rxRule = QRegularExpression(nwRegEx.FMT_ST)
|
53
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
54
|
+
return rxRule
|
55
|
+
|
56
|
+
@property
|
57
|
+
def shortcodePlain(self) -> QRegularExpression:
|
58
|
+
"""Plain shortcode style."""
|
59
|
+
rxRule = QRegularExpression(nwRegEx.FMT_SC)
|
60
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
61
|
+
return rxRule
|
62
|
+
|
63
|
+
@property
|
64
|
+
def shortcodeValue(self) -> QRegularExpression:
|
65
|
+
"""Plain shortcode style."""
|
66
|
+
rxRule = QRegularExpression(nwRegEx.FMT_SV)
|
67
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
68
|
+
return rxRule
|
69
|
+
|
70
|
+
@property
|
71
|
+
def dialogStyle(self) -> QRegularExpression:
|
72
|
+
"""Dialogue detection rule based on user settings."""
|
73
|
+
symO = ""
|
74
|
+
symC = ""
|
75
|
+
if CONFIG.dialogStyle in (1, 3):
|
76
|
+
symO += CONFIG.fmtSQuoteOpen
|
77
|
+
symC += CONFIG.fmtSQuoteClose
|
78
|
+
if CONFIG.dialogStyle in (2, 3):
|
79
|
+
symO += CONFIG.fmtDQuoteOpen
|
80
|
+
symC += CONFIG.fmtDQuoteClose
|
81
|
+
|
82
|
+
rxEnd = "|$" if CONFIG.allowOpenDial else ""
|
83
|
+
rxRule = QRegularExpression(f"\\B[{symO}].*?(?:[{symC}]\\B{rxEnd})")
|
84
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
85
|
+
return rxRule
|
86
|
+
|
87
|
+
@property
|
88
|
+
def dialogLine(self) -> QRegularExpression:
|
89
|
+
"""Dialogue line rule based on user settings."""
|
90
|
+
sym = QRegularExpression.escape(CONFIG.dialogLine)
|
91
|
+
rxRule = QRegularExpression(f"^{sym}.*?$")
|
92
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
93
|
+
return rxRule
|
94
|
+
|
95
|
+
@property
|
96
|
+
def narratorBreak(self) -> QRegularExpression:
|
97
|
+
"""Dialogue narrator break rule based on user settings."""
|
98
|
+
sym = QRegularExpression.escape(CONFIG.narratorBreak)
|
99
|
+
rxRule = QRegularExpression(f"\\B{sym}\\S.*?\\S{sym}\\B")
|
100
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
101
|
+
return rxRule
|
102
|
+
|
103
|
+
@property
|
104
|
+
def altDialogStyle(self) -> QRegularExpression:
|
105
|
+
"""Dialogue alternative rule based on user settings."""
|
106
|
+
symO = QRegularExpression.escape(CONFIG.altDialogOpen)
|
107
|
+
symC = QRegularExpression.escape(CONFIG.altDialogClose)
|
108
|
+
rxRule = QRegularExpression(f"\\B{symO}.*?{symC}\\B")
|
109
|
+
rxRule.setPatternOptions(QRegExUnicode)
|
110
|
+
return rxRule
|
111
|
+
|
112
|
+
|
113
|
+
REGEX_PATTERNS = RegExPatterns()
|
@@ -31,20 +31,20 @@ from zipfile import ZipFile
|
|
31
31
|
from PyQt5.QtCore import pyqtSlot
|
32
32
|
from PyQt5.QtGui import QCloseEvent, QTextCursor
|
33
33
|
from PyQt5.QtWidgets import (
|
34
|
-
QApplication,
|
35
|
-
|
34
|
+
QApplication, QDialogButtonBox, QFileDialog, QFrame, QHBoxLayout, QLabel,
|
35
|
+
QLineEdit, QPlainTextEdit, QPushButton, QVBoxLayout, QWidget
|
36
36
|
)
|
37
37
|
|
38
38
|
from novelwriter import CONFIG, SHARED
|
39
|
-
from novelwriter.common import formatFileFilter, formatInt, getFileSize, openExternalPath
|
39
|
+
from novelwriter.common import cssCol, formatFileFilter, formatInt, getFileSize, openExternalPath
|
40
40
|
from novelwriter.error import formatException
|
41
|
-
from novelwriter.extensions.modified import NIconToolButton
|
41
|
+
from novelwriter.extensions.modified import NIconToolButton, NNonBlockingDialog
|
42
42
|
from novelwriter.types import QtDialogClose
|
43
43
|
|
44
44
|
logger = logging.getLogger(__name__)
|
45
45
|
|
46
46
|
|
47
|
-
class GuiDictionaries(
|
47
|
+
class GuiDictionaries(NNonBlockingDialog):
|
48
48
|
|
49
49
|
def __init__(self, parent: QWidget) -> None:
|
50
50
|
super().__init__(parent=parent)
|
@@ -109,7 +109,7 @@ class GuiDictionaries(QDialog):
|
|
109
109
|
|
110
110
|
# Buttons
|
111
111
|
self.buttonBox = QDialogButtonBox(QtDialogClose, self)
|
112
|
-
self.buttonBox.rejected.connect(self.
|
112
|
+
self.buttonBox.rejected.connect(self.reject)
|
113
113
|
|
114
114
|
# Assemble
|
115
115
|
self.innerBox = QVBoxLayout()
|
@@ -172,7 +172,7 @@ class GuiDictionaries(QDialog):
|
|
172
172
|
def closeEvent(self, event: QCloseEvent) -> None:
|
173
173
|
"""Capture the user closing the window."""
|
174
174
|
event.accept()
|
175
|
-
self.
|
175
|
+
self.softDelete()
|
176
176
|
return
|
177
177
|
|
178
178
|
##
|
@@ -186,7 +186,7 @@ class GuiDictionaries(QDialog):
|
|
186
186
|
(self.tr("Free or Libre Office extension"), "*.sox *.oxt"), "*"
|
187
187
|
])
|
188
188
|
soxFile, _ = QFileDialog.getOpenFileName(
|
189
|
-
self, self.tr("Browse Files"),
|
189
|
+
self, self.tr("Browse Files"), str(CONFIG.homePath()), filter=ffilter
|
190
190
|
)
|
191
191
|
if soxFile:
|
192
192
|
path = Path(soxFile).absolute()
|
@@ -220,12 +220,6 @@ class GuiDictionaries(QDialog):
|
|
220
220
|
SHARED.error("Path not found.")
|
221
221
|
return
|
222
222
|
|
223
|
-
@pyqtSlot()
|
224
|
-
def _doClose(self) -> None:
|
225
|
-
"""Close the dialog."""
|
226
|
-
self.close()
|
227
|
-
return
|
228
|
-
|
229
223
|
##
|
230
224
|
# Internal Functions
|
231
225
|
##
|
@@ -257,13 +251,9 @@ class GuiDictionaries(QDialog):
|
|
257
251
|
cursor.movePosition(QTextCursor.MoveOperation.End)
|
258
252
|
if cursor.position() > 0:
|
259
253
|
cursor.insertText("\n")
|
260
|
-
if err
|
261
|
-
|
262
|
-
else:
|
263
|
-
cursor.insertText(text)
|
254
|
+
textCol = cssCol(SHARED.theme.errorText if err else self.palette().text().color())
|
255
|
+
cursor.insertHtml(f"<font style='color: {textCol}'>{text}</font>")
|
264
256
|
cursor.movePosition(QTextCursor.MoveOperation.End)
|
265
257
|
cursor.deleteChar()
|
266
258
|
self.infoBox.setTextCursor(cursor)
|
267
259
|
return
|
268
|
-
|
269
|
-
# END Class GuiDictionaries
|
novelwriter/tools/lipsum.py
CHANGED
@@ -23,37 +23,35 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
23
23
|
"""
|
24
24
|
from __future__ import annotations
|
25
25
|
|
26
|
-
import random
|
27
26
|
import logging
|
27
|
+
import random
|
28
28
|
|
29
|
-
from PyQt5.QtCore import
|
29
|
+
from PyQt5.QtCore import pyqtSlot
|
30
30
|
from PyQt5.QtWidgets import (
|
31
|
-
|
32
|
-
|
31
|
+
QDialogButtonBox, QGridLayout, QHBoxLayout, QLabel, QSpinBox, QVBoxLayout,
|
32
|
+
QWidget
|
33
33
|
)
|
34
34
|
|
35
35
|
from novelwriter import CONFIG, SHARED
|
36
36
|
from novelwriter.common import readTextFile
|
37
|
+
from novelwriter.extensions.modified import NDialog
|
37
38
|
from novelwriter.extensions.switch import NSwitch
|
38
|
-
from novelwriter.types import QtAlignLeft, QtAlignRight,
|
39
|
+
from novelwriter.types import QtAlignLeft, QtAlignRight, QtDialogClose, QtRoleAction
|
39
40
|
|
40
41
|
logger = logging.getLogger(__name__)
|
41
42
|
|
42
43
|
|
43
|
-
class GuiLipsum(
|
44
|
+
class GuiLipsum(NDialog):
|
44
45
|
|
45
46
|
def __init__(self, parent: QWidget) -> None:
|
46
47
|
super().__init__(parent=parent)
|
47
48
|
|
48
49
|
logger.debug("Create: GuiLipsum")
|
49
50
|
self.setObjectName("GuiLipsum")
|
50
|
-
|
51
|
-
self.setWindowFlag(Qt.WindowType.Tool)
|
51
|
+
self.setWindowTitle(self.tr("Insert Placeholder Text"))
|
52
52
|
|
53
53
|
self._lipsumText = ""
|
54
54
|
|
55
|
-
self.setWindowTitle(self.tr("Insert Placeholder Text"))
|
56
|
-
|
57
55
|
vSp = CONFIG.pxInt(4)
|
58
56
|
nPx = CONFIG.pxInt(64)
|
59
57
|
|
@@ -95,7 +93,7 @@ class GuiLipsum(QDialog):
|
|
95
93
|
|
96
94
|
# Buttons
|
97
95
|
self.buttonBox = QDialogButtonBox(self)
|
98
|
-
self.buttonBox.rejected.connect(self.
|
96
|
+
self.buttonBox.rejected.connect(self.reject)
|
99
97
|
|
100
98
|
self.btnClose = self.buttonBox.addButton(QtDialogClose)
|
101
99
|
self.btnClose.setAutoDefault(False)
|
@@ -104,8 +102,6 @@ class GuiLipsum(QDialog):
|
|
104
102
|
self.btnInsert.clicked.connect(self._doInsert)
|
105
103
|
self.btnInsert.setAutoDefault(False)
|
106
104
|
|
107
|
-
self.rejected.connect(self.close)
|
108
|
-
|
109
105
|
# Assemble
|
110
106
|
self.outerBox = QVBoxLayout()
|
111
107
|
self.outerBox.addLayout(self.innerBox)
|
@@ -132,7 +128,7 @@ class GuiLipsum(QDialog):
|
|
132
128
|
cls = GuiLipsum(parent)
|
133
129
|
cls.exec()
|
134
130
|
text = cls.lipsumText
|
135
|
-
cls.
|
131
|
+
cls.softDelete()
|
136
132
|
return text
|
137
133
|
|
138
134
|
##
|
@@ -150,5 +146,3 @@ class GuiLipsum(QDialog):
|
|
150
146
|
self._lipsumText = "\n\n".join(lipsumText[0:pCount]) + "\n\n"
|
151
147
|
self.close()
|
152
148
|
return
|
153
|
-
|
154
|
-
# END Class GuiLipsum
|
novelwriter/tools/manusbuild.py
CHANGED
@@ -30,7 +30,7 @@ from pathlib import Path
|
|
30
30
|
from PyQt5.QtCore import QTimer, pyqtSlot
|
31
31
|
from PyQt5.QtGui import QCloseEvent
|
32
32
|
from PyQt5.QtWidgets import (
|
33
|
-
QAbstractButton, QAbstractItemView,
|
33
|
+
QAbstractButton, QAbstractItemView, QDialogButtonBox, QFileDialog,
|
34
34
|
QGridLayout, QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem,
|
35
35
|
QPushButton, QSplitter, QVBoxLayout, QWidget
|
36
36
|
)
|
@@ -42,14 +42,14 @@ from novelwriter.core.buildsettings import BuildSettings
|
|
42
42
|
from novelwriter.core.docbuild import NWBuildDocument
|
43
43
|
from novelwriter.core.item import NWItem
|
44
44
|
from novelwriter.enum import nwBuildFmt
|
45
|
-
from novelwriter.extensions.modified import NIconToolButton
|
46
|
-
from novelwriter.extensions.
|
45
|
+
from novelwriter.extensions.modified import NDialog, NIconToolButton
|
46
|
+
from novelwriter.extensions.progressbars import NProgressSimple
|
47
47
|
from novelwriter.types import QtAlignCenter, QtDialogClose, QtRoleAction, QtRoleReject, QtUserRole
|
48
48
|
|
49
49
|
logger = logging.getLogger(__name__)
|
50
50
|
|
51
51
|
|
52
|
-
class GuiManuscriptBuild(
|
52
|
+
class GuiManuscriptBuild(NDialog):
|
53
53
|
"""GUI Tools: Manuscript Build Dialog
|
54
54
|
|
55
55
|
This is the tool for running the build itself. It can be accessed
|
@@ -220,7 +220,7 @@ class GuiManuscriptBuild(QDialog):
|
|
220
220
|
|
221
221
|
self.btnBuild.setFocus()
|
222
222
|
self._populateContentList()
|
223
|
-
self.buildPath.setText(str(self._build.
|
223
|
+
self.buildPath.setText(str(self._build.lastBuildPath))
|
224
224
|
if self._build.lastBuildName:
|
225
225
|
self.buildName.setText(self._build.lastBuildName)
|
226
226
|
else:
|
@@ -250,7 +250,7 @@ class GuiManuscriptBuild(QDialog):
|
|
250
250
|
"""
|
251
251
|
self._saveSettings()
|
252
252
|
event.accept()
|
253
|
-
self.
|
253
|
+
self.softDelete()
|
254
254
|
return
|
255
255
|
|
256
256
|
##
|
@@ -274,7 +274,7 @@ class GuiManuscriptBuild(QDialog):
|
|
274
274
|
def _doSelectPath(self) -> None:
|
275
275
|
"""Select a folder for output."""
|
276
276
|
bPath = Path(self.buildPath.text())
|
277
|
-
bPath = bPath if bPath.is_dir() else self._build.
|
277
|
+
bPath = bPath if bPath.is_dir() else self._build.lastBuildPath
|
278
278
|
savePath = QFileDialog.getExistingDirectory(
|
279
279
|
self, self.tr("Select Folder"), str(bPath)
|
280
280
|
)
|
@@ -327,7 +327,7 @@ class GuiManuscriptBuild(QDialog):
|
|
327
327
|
return False
|
328
328
|
|
329
329
|
# Make sure editor content is saved before we start
|
330
|
-
SHARED.
|
330
|
+
SHARED.saveEditor()
|
331
331
|
|
332
332
|
docBuild = NWBuildDocument(SHARED.project, self._build)
|
333
333
|
docBuild.queueAll()
|
@@ -336,7 +336,7 @@ class GuiManuscriptBuild(QDialog):
|
|
336
336
|
for i, _ in docBuild.iterBuild(buildPath, bFormat):
|
337
337
|
self.buildProgress.setValue(i+1)
|
338
338
|
|
339
|
-
self._build.
|
339
|
+
self._build.setLastBuildPath(bPath)
|
340
340
|
self._build.setLastBuildName(bName)
|
341
341
|
self._build.setLastFormat(bFormat)
|
342
342
|
|
@@ -403,5 +403,3 @@ class GuiManuscriptBuild(QDialog):
|
|
403
403
|
"""Open the build folder in the system's file explorer."""
|
404
404
|
openExternalPath(Path(self.buildPath.text()))
|
405
405
|
return
|
406
|
-
|
407
|
-
# END Class GuiManuscriptBuild
|