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.
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/METADATA +1 -1
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/RECORD +102 -92
- novelwriter/__init__.py +4 -4
- novelwriter/assets/icons/typicons_dark/icons.conf +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_import.svg +5 -0
- novelwriter/assets/icons/typicons_dark/typ_document-add-col.svg +8 -0
- novelwriter/assets/icons/typicons_dark/typ_document-add.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_document.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_th-dot-more.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +6 -0
- novelwriter/assets/icons/typicons_light/mixed_import.svg +5 -0
- novelwriter/assets/icons/typicons_light/typ_document-add-col.svg +8 -0
- novelwriter/assets/icons/typicons_light/typ_document-add.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_document.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_th-dot-more.svg +4 -0
- novelwriter/assets/images/novelwriter-text-dark.svg +4 -0
- novelwriter/assets/images/novelwriter-text-light.svg +4 -0
- novelwriter/assets/images/welcome-dark.jpg +0 -0
- novelwriter/assets/images/welcome-light.jpg +0 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/syntax/default_dark.conf +1 -0
- novelwriter/assets/syntax/default_light.conf +1 -0
- novelwriter/assets/syntax/grey_dark.conf +1 -0
- novelwriter/assets/syntax/grey_light.conf +1 -0
- novelwriter/assets/syntax/light_owl.conf +1 -0
- novelwriter/assets/syntax/night_owl.conf +1 -0
- novelwriter/assets/syntax/solarized_dark.conf +1 -0
- novelwriter/assets/syntax/solarized_light.conf +1 -0
- novelwriter/assets/syntax/tomorrow.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
- novelwriter/assets/text/credits_en.htm +4 -2
- novelwriter/assets/themes/default_dark.conf +2 -2
- novelwriter/assets/themes/default_light.conf +2 -2
- novelwriter/common.py +48 -37
- novelwriter/config.py +36 -41
- novelwriter/constants.py +38 -16
- novelwriter/core/buildsettings.py +7 -7
- novelwriter/core/coretools.py +192 -154
- novelwriter/core/docbuild.py +6 -3
- novelwriter/core/document.py +6 -6
- novelwriter/core/index.py +89 -56
- novelwriter/core/item.py +21 -3
- novelwriter/core/options.py +8 -7
- novelwriter/core/project.py +69 -44
- novelwriter/core/projectdata.py +1 -14
- novelwriter/core/projectxml.py +13 -41
- novelwriter/core/sessions.py +2 -1
- novelwriter/core/spellcheck.py +2 -1
- novelwriter/core/status.py +2 -1
- novelwriter/core/storage.py +178 -140
- novelwriter/core/tohtml.py +4 -2
- novelwriter/core/tokenizer.py +73 -45
- novelwriter/core/toodt.py +40 -30
- novelwriter/core/tree.py +3 -2
- novelwriter/dialogs/about.py +70 -160
- novelwriter/dialogs/docmerge.py +6 -5
- novelwriter/dialogs/docsplit.py +6 -6
- novelwriter/dialogs/editlabel.py +1 -1
- novelwriter/dialogs/preferences.py +553 -703
- novelwriter/dialogs/{projsettings.py → projectsettings.py} +288 -262
- novelwriter/dialogs/quotes.py +27 -23
- novelwriter/dialogs/wordlist.py +96 -40
- novelwriter/enum.py +20 -18
- novelwriter/error.py +1 -1
- novelwriter/extensions/circularprogress.py +11 -11
- novelwriter/extensions/configlayout.py +185 -134
- novelwriter/extensions/modified.py +81 -0
- novelwriter/extensions/novelselector.py +26 -12
- novelwriter/extensions/pagedsidebar.py +14 -16
- novelwriter/extensions/simpleprogress.py +5 -5
- novelwriter/extensions/statusled.py +8 -8
- novelwriter/extensions/switch.py +31 -63
- novelwriter/extensions/switchbox.py +1 -1
- novelwriter/extensions/versioninfo.py +153 -0
- novelwriter/gui/doceditor.py +178 -150
- novelwriter/gui/dochighlight.py +63 -92
- novelwriter/gui/docviewer.py +49 -51
- novelwriter/gui/docviewerpanel.py +72 -24
- novelwriter/gui/itemdetails.py +7 -7
- novelwriter/gui/mainmenu.py +14 -18
- novelwriter/gui/noveltree.py +9 -8
- novelwriter/gui/outline.py +98 -75
- novelwriter/gui/projtree.py +188 -61
- novelwriter/gui/sidebar.py +3 -4
- novelwriter/gui/statusbar.py +3 -4
- novelwriter/gui/theme.py +60 -68
- novelwriter/guimain.py +49 -156
- novelwriter/shared.py +15 -1
- novelwriter/tools/dictionaries.py +5 -6
- novelwriter/tools/manuscript.py +6 -6
- novelwriter/tools/manussettings.py +192 -221
- novelwriter/tools/noveldetails.py +525 -0
- novelwriter/tools/welcome.py +802 -0
- novelwriter/tools/writingstats.py +9 -9
- novelwriter/assets/images/wizard-back.jpg +0 -0
- novelwriter/assets/text/gplv3_en.htm +0 -641
- novelwriter/assets/text/release_notes.htm +0 -60
- novelwriter/dialogs/projdetails.py +0 -518
- novelwriter/dialogs/projload.py +0 -294
- novelwriter/dialogs/updates.py +0 -172
- novelwriter/extensions/pageddialog.py +0 -130
- novelwriter/tools/projwizard.py +0 -478
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/WHEEL +0 -0
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.2.1.dist-info → novelWriter-2.3b1.dist-info}/top_level.txt +0 -0
novelwriter/dialogs/quotes.py
CHANGED
@@ -25,7 +25,7 @@ from __future__ import annotations
|
|
25
25
|
|
26
26
|
import logging
|
27
27
|
|
28
|
-
from PyQt5.QtGui import
|
28
|
+
from PyQt5.QtGui import QFontMetrics
|
29
29
|
from PyQt5.QtCore import QSize, Qt, pyqtSlot
|
30
30
|
from PyQt5.QtWidgets import (
|
31
31
|
QDialog, QDialogButtonBox, QFrame, QHBoxLayout, QLabel, QListWidget,
|
@@ -40,11 +40,11 @@ logger = logging.getLogger(__name__)
|
|
40
40
|
|
41
41
|
class GuiQuoteSelect(QDialog):
|
42
42
|
|
43
|
-
|
43
|
+
_selected = ""
|
44
44
|
|
45
45
|
D_KEY = Qt.ItemDataRole.UserRole
|
46
46
|
|
47
|
-
def __init__(self, parent: QWidget,
|
47
|
+
def __init__(self, parent: QWidget, current: str = '"') -> None:
|
48
48
|
super().__init__(parent=parent)
|
49
49
|
|
50
50
|
logger.debug("Create: GuiQuoteSelect")
|
@@ -54,7 +54,7 @@ class GuiQuoteSelect(QDialog):
|
|
54
54
|
self.innerBox = QHBoxLayout()
|
55
55
|
self.labelBox = QVBoxLayout()
|
56
56
|
|
57
|
-
self.
|
57
|
+
self._selected = current
|
58
58
|
|
59
59
|
qMetrics = QFontMetrics(self.font())
|
60
60
|
pxW = 7*qMetrics.boundingRectChar("M").width()
|
@@ -65,7 +65,7 @@ class GuiQuoteSelect(QDialog):
|
|
65
65
|
lblFont.setPointSizeF(4*lblFont.pointSizeF())
|
66
66
|
|
67
67
|
# Preview Label
|
68
|
-
self.previewLabel = QLabel(
|
68
|
+
self.previewLabel = QLabel(current)
|
69
69
|
self.previewLabel.setFont(lblFont)
|
70
70
|
self.previewLabel.setFixedSize(QSize(pxW, pxH))
|
71
71
|
self.previewLabel.setAlignment(Qt.AlignCenter)
|
@@ -77,12 +77,12 @@ class GuiQuoteSelect(QDialog):
|
|
77
77
|
|
78
78
|
minSize = 100
|
79
79
|
for sKey, sLabel in nwQuotes.SYMBOLS.items():
|
80
|
-
|
81
|
-
minSize = max(minSize, qMetrics.boundingRect(
|
82
|
-
qtItem = QListWidgetItem(
|
80
|
+
text = "[ %s ] %s" % (sKey, trConst(sLabel))
|
81
|
+
minSize = max(minSize, qMetrics.boundingRect(text).width())
|
82
|
+
qtItem = QListWidgetItem(text)
|
83
83
|
qtItem.setData(self.D_KEY, sKey)
|
84
84
|
self.listBox.addItem(qtItem)
|
85
|
-
if sKey ==
|
85
|
+
if sKey == current:
|
86
86
|
self.listBox.setCurrentItem(qtItem)
|
87
87
|
|
88
88
|
self.listBox.setMinimumWidth(minSize + CONFIG.pxInt(40))
|
@@ -113,15 +113,20 @@ class GuiQuoteSelect(QDialog):
|
|
113
113
|
logger.debug("Delete: GuiQuoteSelect")
|
114
114
|
return
|
115
115
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
116
|
+
@property
|
117
|
+
def selectedQuote(self) -> str:
|
118
|
+
"""Return the selected quote symbol."""
|
119
|
+
return self._selected
|
120
|
+
|
121
|
+
@classmethod
|
122
|
+
def getQuote(cls, parent: QWidget, current: str = "") -> tuple[str, bool]:
|
123
|
+
"""Pop the dialog and return the result."""
|
124
|
+
cls = GuiQuoteSelect(parent, current=current)
|
125
|
+
cls.exec_()
|
126
|
+
quote = cls._selected
|
127
|
+
accepted = cls.result() == QDialog.DialogCode.Accepted
|
128
|
+
cls.deleteLater()
|
129
|
+
return quote, accepted
|
125
130
|
|
126
131
|
##
|
127
132
|
# Private Slots
|
@@ -130,11 +135,10 @@ class GuiQuoteSelect(QDialog):
|
|
130
135
|
@pyqtSlot()
|
131
136
|
def _selectedSymbol(self) -> None:
|
132
137
|
"""Update the preview label and the selected quote style."""
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
self.
|
137
|
-
self.selectedQuote = theSymbol
|
138
|
+
if items := self.listBox.selectedItems():
|
139
|
+
quote = items[0].data(self.D_KEY)
|
140
|
+
self.previewLabel.setText(quote)
|
141
|
+
self._selected = quote
|
138
142
|
return
|
139
143
|
|
140
144
|
# END Class GuiQuoteSelect
|
novelwriter/dialogs/wordlist.py
CHANGED
@@ -26,16 +26,19 @@ from __future__ import annotations
|
|
26
26
|
import logging
|
27
27
|
|
28
28
|
from typing import TYPE_CHECKING
|
29
|
+
from pathlib import Path
|
29
30
|
|
30
31
|
from PyQt5.QtGui import QCloseEvent
|
31
32
|
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
32
33
|
from PyQt5.QtWidgets import (
|
33
|
-
QAbstractItemView, QDialog, QDialogButtonBox,
|
34
|
-
QLineEdit, QListWidget,
|
34
|
+
QAbstractItemView, QDialog, QDialogButtonBox, QFileDialog, QHBoxLayout,
|
35
|
+
QLineEdit, QListWidget, QPushButton, QVBoxLayout, qApp
|
35
36
|
)
|
36
37
|
|
37
38
|
from novelwriter import CONFIG, SHARED
|
39
|
+
from novelwriter.common import formatFileFilter
|
38
40
|
from novelwriter.core.spellcheck import UserDictionary
|
41
|
+
from novelwriter.extensions.configlayout import NColourLabel
|
39
42
|
|
40
43
|
if TYPE_CHECKING: # pragma: no cover
|
41
44
|
from novelwriter.guimain import GuiMain
|
@@ -57,30 +60,46 @@ class GuiWordList(QDialog):
|
|
57
60
|
mS = CONFIG.pxInt(250)
|
58
61
|
wW = CONFIG.pxInt(320)
|
59
62
|
wH = CONFIG.pxInt(340)
|
60
|
-
pOptions = SHARED.project.options
|
61
63
|
|
62
64
|
self.setMinimumWidth(mS)
|
63
65
|
self.setMinimumHeight(mS)
|
64
66
|
self.resize(
|
65
|
-
CONFIG.pxInt(
|
66
|
-
CONFIG.pxInt(
|
67
|
+
CONFIG.pxInt(SHARED.project.options.getInt("GuiWordList", "winWidth", wW)),
|
68
|
+
CONFIG.pxInt(SHARED.project.options.getInt("GuiWordList", "winHeight", wH))
|
69
|
+
)
|
70
|
+
|
71
|
+
# Header
|
72
|
+
self.headLabel = NColourLabel(
|
73
|
+
"Project Word List", SHARED.theme.helpText, parent=self,
|
74
|
+
scale=NColourLabel.HEADER_SCALE
|
67
75
|
)
|
68
76
|
|
69
|
-
|
70
|
-
|
77
|
+
self.importButton = QPushButton(SHARED.theme.getIcon("import"), "", self)
|
78
|
+
self.importButton.setToolTip(self.tr("Import words from text file"))
|
79
|
+
self.importButton.clicked.connect(self._importWords)
|
71
80
|
|
72
|
-
self.
|
81
|
+
self.exportButton = QPushButton(SHARED.theme.getIcon("export"), "", self)
|
82
|
+
self.exportButton.setToolTip(self.tr("Export words to text file"))
|
83
|
+
self.exportButton.clicked.connect(self._exportWords)
|
73
84
|
|
74
|
-
self.
|
85
|
+
self.headerBox = QHBoxLayout()
|
86
|
+
self.headerBox.addWidget(self.headLabel, 1)
|
87
|
+
self.headerBox.addWidget(self.importButton, 0)
|
88
|
+
self.headerBox.addWidget(self.exportButton, 0)
|
89
|
+
|
90
|
+
# List Box
|
91
|
+
self.listBox = QListWidget(self)
|
75
92
|
self.listBox.setDragDropMode(QAbstractItemView.NoDragDrop)
|
93
|
+
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
76
94
|
self.listBox.setSortingEnabled(True)
|
77
95
|
|
78
|
-
|
96
|
+
# Add/Remove Form
|
97
|
+
self.newEntry = QLineEdit(self)
|
79
98
|
|
80
|
-
self.addButton = QPushButton(SHARED.theme.getIcon("add"), "")
|
99
|
+
self.addButton = QPushButton(SHARED.theme.getIcon("add"), "", self)
|
81
100
|
self.addButton.clicked.connect(self._doAdd)
|
82
101
|
|
83
|
-
self.delButton = QPushButton(SHARED.theme.getIcon("remove"), "")
|
102
|
+
self.delButton = QPushButton(SHARED.theme.getIcon("remove"), "", self)
|
84
103
|
self.delButton.clicked.connect(self._doDelete)
|
85
104
|
|
86
105
|
self.editBox = QHBoxLayout()
|
@@ -88,20 +107,19 @@ class GuiWordList(QDialog):
|
|
88
107
|
self.editBox.addWidget(self.addButton, 0)
|
89
108
|
self.editBox.addWidget(self.delButton, 0)
|
90
109
|
|
110
|
+
# Buttons
|
91
111
|
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Close)
|
92
112
|
self.buttonBox.accepted.connect(self._doSave)
|
93
113
|
self.buttonBox.rejected.connect(self.close)
|
94
114
|
|
95
115
|
# Assemble
|
96
|
-
# ========
|
97
|
-
|
98
116
|
self.outerBox = QVBoxLayout()
|
99
|
-
self.outerBox.
|
100
|
-
self.outerBox.addSpacing(CONFIG.pxInt(8))
|
117
|
+
self.outerBox.addLayout(self.headerBox, 0)
|
101
118
|
self.outerBox.addWidget(self.listBox, 1)
|
102
119
|
self.outerBox.addLayout(self.editBox, 0)
|
103
120
|
self.outerBox.addSpacing(CONFIG.pxInt(12))
|
104
121
|
self.outerBox.addWidget(self.buttonBox, 0)
|
122
|
+
self.outerBox.setSpacing(CONFIG.pxInt(4))
|
105
123
|
|
106
124
|
self.setLayout(self.outerBox)
|
107
125
|
|
@@ -134,45 +152,69 @@ class GuiWordList(QDialog):
|
|
134
152
|
def _doAdd(self) -> None:
|
135
153
|
"""Add a new word to the word list."""
|
136
154
|
word = self.newEntry.text().strip()
|
137
|
-
if word == "":
|
138
|
-
SHARED.error(self.tr("Cannot add a blank word."))
|
139
|
-
return
|
140
|
-
|
141
|
-
if self.listBox.findItems(word, Qt.MatchExactly):
|
142
|
-
SHARED.error(self.tr(
|
143
|
-
"The word '{0}' is already in the word list."
|
144
|
-
).format(word))
|
145
|
-
return
|
146
|
-
|
147
|
-
self.listBox.addItem(word)
|
148
155
|
self.newEntry.setText("")
|
149
|
-
|
156
|
+
self.listBox.clearSelection()
|
157
|
+
self._addWord(word)
|
158
|
+
if items := self.listBox.findItems(word, Qt.MatchExactly):
|
159
|
+
self.listBox.setCurrentItem(items[0])
|
160
|
+
self.listBox.scrollToItem(items[0], QAbstractItemView.ScrollHint.PositionAtCenter)
|
150
161
|
return
|
151
162
|
|
152
163
|
@pyqtSlot()
|
153
164
|
def _doDelete(self) -> None:
|
154
|
-
"""Delete the selected
|
155
|
-
|
156
|
-
|
157
|
-
self.listBox.takeItem(self.listBox.row(selItem[0]))
|
165
|
+
"""Delete the selected items."""
|
166
|
+
for item in self.listBox.selectedItems():
|
167
|
+
self.listBox.takeItem(self.listBox.row(item))
|
158
168
|
return
|
159
169
|
|
160
170
|
@pyqtSlot()
|
161
171
|
def _doSave(self) -> None:
|
162
172
|
"""Save the new word list and close."""
|
163
173
|
userDict = UserDictionary(SHARED.project)
|
164
|
-
for
|
165
|
-
|
166
|
-
if isinstance(item, QListWidgetItem):
|
167
|
-
word = item.text().strip()
|
168
|
-
if word:
|
169
|
-
userDict.add(word)
|
174
|
+
for word in self._listWords():
|
175
|
+
userDict.add(word)
|
170
176
|
userDict.save()
|
171
177
|
self.newWordListReady.emit()
|
172
178
|
qApp.processEvents()
|
173
179
|
self.close()
|
174
180
|
return
|
175
181
|
|
182
|
+
@pyqtSlot()
|
183
|
+
def _importWords(self) -> None:
|
184
|
+
"""Import words from file."""
|
185
|
+
SHARED.info(self.tr(
|
186
|
+
"Note: The import file must be a plain text file with UTF-8 or ASCII encoding."
|
187
|
+
))
|
188
|
+
ffilter = formatFileFilter(["*.txt", "*"])
|
189
|
+
path, _ = QFileDialog.getOpenFileName(
|
190
|
+
self, self.tr("Import File"), str(Path.home()), filter=ffilter
|
191
|
+
)
|
192
|
+
if path:
|
193
|
+
try:
|
194
|
+
with open(path, mode="r", encoding="utf-8") as fo:
|
195
|
+
words = set(w.strip() for w in fo.read().split())
|
196
|
+
except Exception as exc:
|
197
|
+
SHARED.error("Could not read file.", exc=exc)
|
198
|
+
return
|
199
|
+
for word in words:
|
200
|
+
self._addWord(word)
|
201
|
+
return
|
202
|
+
|
203
|
+
@pyqtSlot()
|
204
|
+
def _exportWords(self) -> None:
|
205
|
+
"""Export words to file."""
|
206
|
+
path, _ = QFileDialog.getSaveFileName(
|
207
|
+
self, self.tr("Export File"), str(Path.home())
|
208
|
+
)
|
209
|
+
if path:
|
210
|
+
try:
|
211
|
+
path = Path(path).with_suffix(".txt")
|
212
|
+
with open(path, mode="w", encoding="utf-8") as fo:
|
213
|
+
fo.write("\n".join(self._listWords()))
|
214
|
+
except Exception as exc:
|
215
|
+
SHARED.error("Could not write file.", exc=exc)
|
216
|
+
return
|
217
|
+
|
176
218
|
##
|
177
219
|
# Internal Functions
|
178
220
|
##
|
@@ -183,8 +225,7 @@ class GuiWordList(QDialog):
|
|
183
225
|
userDict.load()
|
184
226
|
self.listBox.clear()
|
185
227
|
for word in userDict:
|
186
|
-
|
187
|
-
self.listBox.addItem(word)
|
228
|
+
self.listBox.addItem(word)
|
188
229
|
return
|
189
230
|
|
190
231
|
def _saveGuiSettings(self) -> None:
|
@@ -199,4 +240,19 @@ class GuiWordList(QDialog):
|
|
199
240
|
|
200
241
|
return
|
201
242
|
|
243
|
+
def _addWord(self, word: str) -> None:
|
244
|
+
"""Add a single word to the list."""
|
245
|
+
if word and not self.listBox.findItems(word, Qt.MatchExactly):
|
246
|
+
self.listBox.addItem(word)
|
247
|
+
self._changed = True
|
248
|
+
return
|
249
|
+
|
250
|
+
def _listWords(self) -> list[str]:
|
251
|
+
"""List all words in the list box."""
|
252
|
+
result = []
|
253
|
+
for i in range(self.listBox.count()):
|
254
|
+
if (item := self.listBox.item(i)) and (word := item.text().strip()):
|
255
|
+
result.append(word)
|
256
|
+
return result
|
257
|
+
|
202
258
|
# END Class GuiWordList
|
novelwriter/enum.py
CHANGED
@@ -47,7 +47,8 @@ class nwItemClass(Enum):
|
|
47
47
|
ENTITY = 7
|
48
48
|
CUSTOM = 8
|
49
49
|
ARCHIVE = 9
|
50
|
-
|
50
|
+
TEMPLATE = 10
|
51
|
+
TRASH = 11
|
51
52
|
|
52
53
|
# END Enum nwItemClass
|
53
54
|
|
@@ -107,23 +108,24 @@ class nwDocAction(Enum):
|
|
107
108
|
BLOCK_H3 = 15
|
108
109
|
BLOCK_H4 = 16
|
109
110
|
BLOCK_COM = 17
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
111
|
+
BLOCK_IGN = 18
|
112
|
+
BLOCK_TXT = 19
|
113
|
+
BLOCK_TTL = 20
|
114
|
+
BLOCK_UNN = 21
|
115
|
+
REPL_SNG = 22
|
116
|
+
REPL_DBL = 23
|
117
|
+
RM_BREAKS = 24
|
118
|
+
ALIGN_L = 25
|
119
|
+
ALIGN_C = 26
|
120
|
+
ALIGN_R = 27
|
121
|
+
INDENT_L = 28
|
122
|
+
INDENT_R = 29
|
123
|
+
SC_ITALIC = 30
|
124
|
+
SC_BOLD = 31
|
125
|
+
SC_STRIKE = 32
|
126
|
+
SC_ULINE = 33
|
127
|
+
SC_SUP = 34
|
128
|
+
SC_SUB = 35
|
127
129
|
|
128
130
|
# END Enum nwDocAction
|
129
131
|
|
novelwriter/error.py
CHANGED
@@ -50,7 +50,7 @@ def logException() -> None:
|
|
50
50
|
"""Log the content of an exception message."""
|
51
51
|
exType, exValue, _ = sys.exc_info()
|
52
52
|
if exType is not None:
|
53
|
-
logger.error("
|
53
|
+
logger.error(f"{exType.__name__}: {str(exValue)}", stacklevel=2)
|
54
54
|
return
|
55
55
|
|
56
56
|
|
@@ -84,17 +84,17 @@ class NProgressCircle(QProgressBar):
|
|
84
84
|
"""Custom painter for the progress bar."""
|
85
85
|
progress = 100.0*self.value()/self.maximum()
|
86
86
|
angle = ceil(16*3.6*progress)
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
87
|
+
painter = QPainter(self)
|
88
|
+
painter.setRenderHint(QPainter.Antialiasing, True)
|
89
|
+
painter.setPen(self._dPen)
|
90
|
+
painter.setBrush(self._dBrush)
|
91
|
+
painter.drawEllipse(self._dRect)
|
92
|
+
painter.setPen(self._bPen)
|
93
|
+
painter.drawArc(self._cRect, 0, 360*16)
|
94
|
+
painter.setPen(self._cPen)
|
95
|
+
painter.drawArc(self._cRect, 90*16, -angle)
|
96
|
+
painter.setPen(self._tColor)
|
97
|
+
painter.drawText(self._cRect, Qt.AlignCenter, self._text or f"{progress:.1f} %")
|
98
98
|
return
|
99
99
|
|
100
100
|
# END Class NProgressCircle
|