novelWriter 2.1.1__py3-none-any.whl → 2.2rc1__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.1.1.dist-info → novelWriter-2.2rc1.dist-info}/METADATA +3 -3
- {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/RECORD +105 -76
- novelwriter/__init__.py +6 -24
- novelwriter/assets/i18n/project_de_DE.json +10 -0
- novelwriter/assets/i18n/project_en_GB.json +11 -0
- novelwriter/assets/i18n/project_en_US.json +10 -0
- novelwriter/assets/i18n/project_ja_JP.json +11 -1
- novelwriter/assets/i18n/project_nb_NO.json +10 -0
- novelwriter/assets/i18n/project_nn_NO.json +10 -0
- novelwriter/assets/icons/novelwriter.ico +0 -0
- novelwriter/assets/icons/novelwriter.svg +8 -183
- novelwriter/assets/icons/typicons_dark/icons.conf +17 -2
- novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_panel.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-markdown.svg +8 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-shortcode.svg +8 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +5 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +5 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +5 -0
- novelwriter/assets/icons/typicons_dark/typ_eye.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_th-dot-menu.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +17 -2
- novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_deco-note.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_panel.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-markdown.svg +8 -0
- novelwriter/assets/icons/typicons_light/nw_tb-shortcode.svg +8 -0
- novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +5 -0
- novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +5 -0
- novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +5 -0
- novelwriter/assets/icons/typicons_light/typ_eye.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_th-dot-menu.svg +4 -0
- novelwriter/assets/icons/x-novelwriter-project.ico +0 -0
- novelwriter/assets/icons/x-novelwriter-project.svg +7 -206
- 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 +7 -0
- novelwriter/assets/text/release_notes.htm +7 -37
- novelwriter/common.py +22 -1
- novelwriter/config.py +27 -42
- novelwriter/constants.py +45 -7
- novelwriter/core/buildsettings.py +40 -24
- novelwriter/core/coretools.py +8 -1
- novelwriter/core/docbuild.py +2 -6
- novelwriter/core/index.py +264 -175
- novelwriter/core/options.py +8 -3
- novelwriter/core/project.py +2 -2
- novelwriter/core/projectdata.py +3 -3
- novelwriter/core/tohtml.py +60 -59
- novelwriter/core/tokenizer.py +110 -70
- novelwriter/core/tomd.py +51 -38
- novelwriter/core/toodt.py +184 -147
- novelwriter/dialogs/preferences.py +75 -106
- novelwriter/dialogs/projsettings.py +101 -110
- novelwriter/dialogs/updates.py +25 -14
- novelwriter/enum.py +28 -3
- novelwriter/extensions/novelselector.py +1 -1
- novelwriter/gui/doceditor.py +1345 -1235
- novelwriter/gui/dochighlight.py +98 -62
- novelwriter/gui/docviewer.py +151 -340
- novelwriter/gui/docviewerpanel.py +457 -0
- novelwriter/gui/editordocument.py +126 -0
- novelwriter/gui/mainmenu.py +350 -300
- novelwriter/gui/noveltree.py +101 -125
- novelwriter/gui/outline.py +154 -171
- novelwriter/gui/projtree.py +480 -380
- novelwriter/gui/sidebar.py +106 -75
- novelwriter/gui/statusbar.py +1 -1
- novelwriter/gui/theme.py +114 -75
- novelwriter/guimain.py +353 -254
- novelwriter/shared.py +36 -3
- novelwriter/tools/dictionaries.py +268 -0
- novelwriter/tools/manusbuild.py +17 -6
- novelwriter/tools/manuscript.py +11 -3
- novelwriter/tools/manussettings.py +0 -14
- novelwriter/tools/projwizard.py +16 -2
- novelwriter/tools/writingstats.py +1 -1
- novelwriter/assets/icons/typicons_dark/typ_at.svg +0 -4
- novelwriter/assets/icons/typicons_dark/typ_th-menu.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_at.svg +0 -4
- novelwriter/assets/icons/typicons_light/typ_th-menu.svg +0 -4
- {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/WHEEL +0 -0
- {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/top_level.txt +0 -0
@@ -96,21 +96,22 @@ class GuiProjectSettings(NPagedDialog):
|
|
96
96
|
|
97
97
|
return
|
98
98
|
|
99
|
-
def __del__(self): # pragma: no cover
|
99
|
+
def __del__(self) -> None: # pragma: no cover
|
100
100
|
logger.debug("Delete: GuiProjectSettings")
|
101
101
|
return
|
102
102
|
|
103
103
|
##
|
104
|
-
# Slots
|
104
|
+
# Private Slots
|
105
105
|
##
|
106
106
|
|
107
|
-
|
108
|
-
|
109
|
-
"""
|
110
|
-
project
|
107
|
+
@pyqtSlot()
|
108
|
+
def _doSave(self) -> None:
|
109
|
+
"""Save settings and close dialog."""
|
110
|
+
project = SHARED.project
|
111
111
|
projName = self.tabMain.editName.text()
|
112
112
|
bookTitle = self.tabMain.editTitle.text()
|
113
113
|
bookAuthor = self.tabMain.editAuthor.text()
|
114
|
+
projLang = self.tabMain.projLang.currentData()
|
114
115
|
spellLang = self.tabMain.spellLang.currentData()
|
115
116
|
doBackup = not self.tabMain.doBackup.isChecked()
|
116
117
|
|
@@ -119,6 +120,7 @@ class GuiProjectSettings(NPagedDialog):
|
|
119
120
|
project.data.setAuthor(bookAuthor)
|
120
121
|
project.data.setDoBackup(doBackup)
|
121
122
|
project.data.setSpellLang(spellLang)
|
123
|
+
project.setProjectLang(projLang)
|
122
124
|
|
123
125
|
if self.tabStatus.colChanged:
|
124
126
|
newList, delList = self.tabStatus.getNewList()
|
@@ -140,9 +142,9 @@ class GuiProjectSettings(NPagedDialog):
|
|
140
142
|
|
141
143
|
return
|
142
144
|
|
143
|
-
|
144
|
-
|
145
|
-
"""
|
145
|
+
@pyqtSlot()
|
146
|
+
def _doClose(self) -> None:
|
147
|
+
"""Save settings and close the dialog."""
|
146
148
|
self._saveGuiSettings()
|
147
149
|
self.reject()
|
148
150
|
return
|
@@ -151,9 +153,8 @@ class GuiProjectSettings(NPagedDialog):
|
|
151
153
|
# Internal Functions
|
152
154
|
##
|
153
155
|
|
154
|
-
def _focusTab(self, tab):
|
155
|
-
"""Change which is the focused tab.
|
156
|
-
"""
|
156
|
+
def _focusTab(self, tab: int) -> None:
|
157
|
+
"""Change which is the focused tab."""
|
157
158
|
if tab == self.TAB_MAIN:
|
158
159
|
self.setCurrentWidget(self.tabMain)
|
159
160
|
elif tab == self.TAB_STATUS:
|
@@ -164,9 +165,8 @@ class GuiProjectSettings(NPagedDialog):
|
|
164
165
|
self.setCurrentWidget(self.tabReplace)
|
165
166
|
return
|
166
167
|
|
167
|
-
def _saveGuiSettings(self):
|
168
|
-
"""Save GUI settings.
|
169
|
-
"""
|
168
|
+
def _saveGuiSettings(self) -> None:
|
169
|
+
"""Save GUI settings."""
|
170
170
|
winWidth = CONFIG.rpxInt(self.width())
|
171
171
|
winHeight = CONFIG.rpxInt(self.height())
|
172
172
|
replaceColW = CONFIG.rpxInt(self.tabReplace.listBox.columnWidth(0))
|
@@ -187,8 +187,8 @@ class GuiProjectSettings(NPagedDialog):
|
|
187
187
|
|
188
188
|
class GuiProjectEditMain(QWidget):
|
189
189
|
|
190
|
-
def __init__(self,
|
191
|
-
super().__init__(parent=
|
190
|
+
def __init__(self, parent: QWidget) -> None:
|
191
|
+
super().__init__(parent=parent)
|
192
192
|
|
193
193
|
# The Form
|
194
194
|
self.mainForm = NConfigLayout()
|
@@ -230,24 +230,41 @@ class GuiProjectEditMain(QWidget):
|
|
230
230
|
self.tr("Change whenever you want!")
|
231
231
|
)
|
232
232
|
|
233
|
+
self.projLang = QComboBox(self)
|
234
|
+
self.projLang.setMaximumWidth(xW)
|
235
|
+
for tag, language in CONFIG.listLanguages(CONFIG.LANG_PROJ):
|
236
|
+
self.projLang.addItem(language, tag)
|
237
|
+
self.mainForm.addRow(
|
238
|
+
self.tr("Project language"),
|
239
|
+
self.projLang,
|
240
|
+
self.tr("Used when building the manuscript.")
|
241
|
+
)
|
242
|
+
|
243
|
+
langIdx = 0
|
244
|
+
if pData.language is not None:
|
245
|
+
langIdx = self.projLang.findData(pData.language)
|
246
|
+
if langIdx == -1:
|
247
|
+
langIdx = self.projLang.findData("en_GB")
|
248
|
+
if langIdx != -1:
|
249
|
+
self.projLang.setCurrentIndex(langIdx)
|
250
|
+
|
233
251
|
self.spellLang = QComboBox(self)
|
234
252
|
self.spellLang.setMaximumWidth(xW)
|
235
253
|
self.spellLang.addItem(self.tr("Default"), "None")
|
236
254
|
if CONFIG.hasEnchant:
|
237
255
|
for tag, language in SHARED.spelling.listDictionaries():
|
238
256
|
self.spellLang.addItem(language, tag)
|
239
|
-
|
240
257
|
self.mainForm.addRow(
|
241
258
|
self.tr("Spell check language"),
|
242
259
|
self.spellLang,
|
243
260
|
self.tr("Overrides main preferences.")
|
244
261
|
)
|
245
262
|
|
246
|
-
|
263
|
+
langIdx = 0
|
247
264
|
if pData.spellLang is not None:
|
248
|
-
|
249
|
-
if
|
250
|
-
self.spellLang.setCurrentIndex(
|
265
|
+
langIdx = self.spellLang.findData(pData.spellLang)
|
266
|
+
if langIdx != -1:
|
267
|
+
self.spellLang.setCurrentIndex(langIdx)
|
251
268
|
|
252
269
|
self.doBackup = NSwitch(self)
|
253
270
|
self.doBackup.setChecked(not pData.doBackup)
|
@@ -271,8 +288,8 @@ class GuiProjectEditStatus(QWidget):
|
|
271
288
|
COL_ROLE = Qt.ItemDataRole.UserRole + 1
|
272
289
|
NUM_ROLE = Qt.ItemDataRole.UserRole + 2
|
273
290
|
|
274
|
-
def __init__(self,
|
275
|
-
super().__init__(parent=
|
291
|
+
def __init__(self, parent: QWidget, isStatus: bool) -> None:
|
292
|
+
super().__init__(parent=parent)
|
276
293
|
|
277
294
|
if isStatus:
|
278
295
|
self.theStatus = SHARED.project.data.itemStatus
|
@@ -372,9 +389,8 @@ class GuiProjectEditStatus(QWidget):
|
|
372
389
|
|
373
390
|
return
|
374
391
|
|
375
|
-
def getNewList(self):
|
376
|
-
"""Return list of entries.
|
377
|
-
"""
|
392
|
+
def getNewList(self) -> tuple[list, list]:
|
393
|
+
"""Return list of entries."""
|
378
394
|
if self.colChanged:
|
379
395
|
newList = []
|
380
396
|
for n in range(self.listBox.topLevelItemCount()):
|
@@ -394,9 +410,8 @@ class GuiProjectEditStatus(QWidget):
|
|
394
410
|
##
|
395
411
|
|
396
412
|
@pyqtSlot()
|
397
|
-
def _selectColour(self):
|
398
|
-
"""Open a dialog to select the status icon colour.
|
399
|
-
"""
|
413
|
+
def _selectColour(self) -> None:
|
414
|
+
"""Open a dialog to select the status icon colour."""
|
400
415
|
if self.selColour is not None:
|
401
416
|
newCol = QColorDialog.getColor(
|
402
417
|
self.selColour, self, self.tr("Select Colour")
|
@@ -410,17 +425,15 @@ class GuiProjectEditStatus(QWidget):
|
|
410
425
|
return
|
411
426
|
|
412
427
|
@pyqtSlot()
|
413
|
-
def _newItem(self):
|
414
|
-
"""Create a new status item.
|
415
|
-
"""
|
428
|
+
def _newItem(self) -> None:
|
429
|
+
"""Create a new status item."""
|
416
430
|
self._addItem(None, self.tr("New Item"), (100, 100, 100), 0)
|
417
431
|
self.colChanged = True
|
418
432
|
return
|
419
433
|
|
420
434
|
@pyqtSlot()
|
421
|
-
def _delItem(self):
|
422
|
-
"""Delete a status item.
|
423
|
-
"""
|
435
|
+
def _delItem(self) -> None:
|
436
|
+
"""Delete a status item."""
|
424
437
|
selItem = self._getSelectedItem()
|
425
438
|
if isinstance(selItem, QTreeWidgetItem):
|
426
439
|
iRow = self.listBox.indexOfTopLevelItem(selItem)
|
@@ -433,9 +446,8 @@ class GuiProjectEditStatus(QWidget):
|
|
433
446
|
return
|
434
447
|
|
435
448
|
@pyqtSlot()
|
436
|
-
def _saveItem(self):
|
437
|
-
"""Save changes made to a status item.
|
438
|
-
"""
|
449
|
+
def _saveItem(self) -> None:
|
450
|
+
"""Save changes made to a status item."""
|
439
451
|
selItem = self._getSelectedItem()
|
440
452
|
if isinstance(selItem, QTreeWidgetItem):
|
441
453
|
selItem.setText(self.COL_LABEL, simplified(self.editName.text()))
|
@@ -444,11 +456,10 @@ class GuiProjectEditStatus(QWidget):
|
|
444
456
|
self.selColour.red(), self.selColour.green(), self.selColour.blue()
|
445
457
|
))
|
446
458
|
self.colChanged = True
|
447
|
-
|
448
459
|
return
|
449
460
|
|
450
461
|
@pyqtSlot()
|
451
|
-
def _selectedItem(self):
|
462
|
+
def _selectedItem(self) -> None:
|
452
463
|
"""Extract the info of a selected item and populate the settings
|
453
464
|
boxes and button. If no item is selected, clear the form.
|
454
465
|
"""
|
@@ -456,7 +467,6 @@ class GuiProjectEditStatus(QWidget):
|
|
456
467
|
if isinstance(selItem, QTreeWidgetItem):
|
457
468
|
cols = selItem.data(self.COL_LABEL, self.COL_ROLE)
|
458
469
|
name = selItem.text(self.COL_LABEL)
|
459
|
-
|
460
470
|
pixmap = QPixmap(self.iPx, self.iPx)
|
461
471
|
pixmap.fill(QColor(*cols))
|
462
472
|
self.selColour = QColor(*cols)
|
@@ -464,31 +474,27 @@ class GuiProjectEditStatus(QWidget):
|
|
464
474
|
self.colButton.setIcon(QIcon(pixmap))
|
465
475
|
self.editName.selectAll()
|
466
476
|
self.editName.setFocus()
|
467
|
-
|
468
477
|
self.editName.setEnabled(True)
|
469
478
|
self.colButton.setEnabled(True)
|
470
479
|
self.saveButton.setEnabled(True)
|
471
|
-
|
472
480
|
else:
|
473
481
|
pixmap = QPixmap(self.iPx, self.iPx)
|
474
482
|
pixmap.fill(QColor(100, 100, 100))
|
475
483
|
self.selColour = QColor(100, 100, 100)
|
476
484
|
self.editName.setText("")
|
477
485
|
self.colButton.setIcon(QIcon(pixmap))
|
478
|
-
|
479
486
|
self.editName.setEnabled(False)
|
480
487
|
self.colButton.setEnabled(False)
|
481
488
|
self.saveButton.setEnabled(False)
|
482
|
-
|
483
489
|
return
|
484
490
|
|
485
491
|
##
|
486
492
|
# Internal Functions
|
487
493
|
##
|
488
494
|
|
489
|
-
def _addItem(self, key, name
|
490
|
-
|
491
|
-
"""
|
495
|
+
def _addItem(self, key: str | None, name: str,
|
496
|
+
cols: tuple[int, int, int], count: int) -> None:
|
497
|
+
"""Add a status item to the list."""
|
492
498
|
pixmap = QPixmap(self.iPx, self.iPx)
|
493
499
|
pixmap.fill(QColor(*cols))
|
494
500
|
|
@@ -504,9 +510,8 @@ class GuiProjectEditStatus(QWidget):
|
|
504
510
|
|
505
511
|
return
|
506
512
|
|
507
|
-
def _moveItem(self, step):
|
508
|
-
"""Move and item up or down step.
|
509
|
-
"""
|
513
|
+
def _moveItem(self, step: int) -> None:
|
514
|
+
"""Move and item up or down step."""
|
510
515
|
selItem = self._getSelectedItem()
|
511
516
|
if selItem is None:
|
512
517
|
return
|
@@ -527,17 +532,15 @@ class GuiProjectEditStatus(QWidget):
|
|
527
532
|
|
528
533
|
return
|
529
534
|
|
530
|
-
def _getSelectedItem(self):
|
531
|
-
"""Get the currently selected item.
|
532
|
-
"""
|
535
|
+
def _getSelectedItem(self) -> QTreeWidgetItem | None:
|
536
|
+
"""Get the currently selected item."""
|
533
537
|
selItem = self.listBox.selectedItems()
|
534
538
|
if len(selItem) > 0:
|
535
539
|
return selItem[0]
|
536
540
|
return None
|
537
541
|
|
538
|
-
def _usageString(self, nUse):
|
539
|
-
"""Generate usage string.
|
540
|
-
"""
|
542
|
+
def _usageString(self, nUse: int) -> str:
|
543
|
+
"""Generate usage string."""
|
541
544
|
if nUse == 0:
|
542
545
|
return self.tr("Not in use")
|
543
546
|
elif nUse == 1:
|
@@ -553,8 +556,8 @@ class GuiProjectEditReplace(QWidget):
|
|
553
556
|
COL_KEY = 0
|
554
557
|
COL_REPL = 1
|
555
558
|
|
556
|
-
def __init__(self,
|
557
|
-
super().__init__(parent=
|
559
|
+
def __init__(self, parent: QWidget) -> None:
|
560
|
+
super().__init__(parent=parent)
|
558
561
|
|
559
562
|
self.arChanged = False
|
560
563
|
|
@@ -635,25 +638,23 @@ class GuiProjectEditReplace(QWidget):
|
|
635
638
|
|
636
639
|
return
|
637
640
|
|
638
|
-
def getNewList(self):
|
639
|
-
"""Extract the list from the widget.
|
640
|
-
|
641
|
-
newList = {}
|
641
|
+
def getNewList(self) -> dict:
|
642
|
+
"""Extract the list from the widget."""
|
643
|
+
new = {}
|
642
644
|
for n in range(self.listBox.topLevelItemCount()):
|
643
645
|
tItem = self.listBox.topLevelItem(n)
|
644
646
|
if tItem is not None:
|
645
647
|
aKey = self._stripNotAllowed(tItem.text(0))
|
646
648
|
aVal = tItem.text(1)
|
647
649
|
if len(aKey) > 0:
|
648
|
-
|
649
|
-
|
650
|
-
return newList
|
650
|
+
new[aKey] = aVal
|
651
|
+
return new
|
651
652
|
|
652
653
|
##
|
653
654
|
# Internal Functions
|
654
655
|
##
|
655
656
|
|
656
|
-
def _selectedItem(self):
|
657
|
+
def _selectedItem(self) -> bool:
|
657
658
|
"""Extract the details from the selected item and populate the
|
658
659
|
edit form.
|
659
660
|
"""
|
@@ -670,63 +671,53 @@ class GuiProjectEditReplace(QWidget):
|
|
670
671
|
self.editKey.setFocus()
|
671
672
|
return True
|
672
673
|
|
673
|
-
def _saveEntry(self):
|
674
|
-
"""Save the form data into the list widget.
|
675
|
-
"""
|
674
|
+
def _saveEntry(self) -> None:
|
675
|
+
"""Save the form data into the list widget."""
|
676
676
|
selItem = self._getSelectedItem()
|
677
|
-
if selItem
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
self.editValue.setEnabled(False)
|
691
|
-
self.listBox.clearSelection()
|
692
|
-
self.arChanged = True
|
693
|
-
|
677
|
+
if selItem:
|
678
|
+
newKey = self.editKey.text()
|
679
|
+
newVal = self.editValue.text()
|
680
|
+
saveKey = self._stripNotAllowed(newKey)
|
681
|
+
if len(saveKey) > 0 and len(newVal) > 0:
|
682
|
+
selItem.setText(self.COL_KEY, "<%s>" % saveKey)
|
683
|
+
selItem.setText(self.COL_REPL, newVal)
|
684
|
+
self.editKey.clear()
|
685
|
+
self.editValue.clear()
|
686
|
+
self.editKey.setEnabled(False)
|
687
|
+
self.editValue.setEnabled(False)
|
688
|
+
self.listBox.clearSelection()
|
689
|
+
self.arChanged = True
|
694
690
|
return
|
695
691
|
|
696
|
-
def _addEntry(self):
|
697
|
-
"""Add a new list entry.
|
698
|
-
"""
|
692
|
+
def _addEntry(self) -> None:
|
693
|
+
"""Add a new list entry."""
|
699
694
|
saveKey = "<keyword%d>" % (self.listBox.topLevelItemCount() + 1)
|
700
695
|
newVal = ""
|
701
696
|
newItem = QTreeWidgetItem([saveKey, newVal])
|
702
697
|
self.listBox.addTopLevelItem(newItem)
|
703
|
-
return
|
698
|
+
return
|
704
699
|
|
705
|
-
def _delEntry(self):
|
706
|
-
"""Delete the selected entry.
|
707
|
-
"""
|
700
|
+
def _delEntry(self) -> None:
|
701
|
+
"""Delete the selected entry."""
|
708
702
|
selItem = self._getSelectedItem()
|
709
|
-
if selItem
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
return True
|
703
|
+
if selItem:
|
704
|
+
self.listBox.takeTopLevelItem(self.listBox.indexOfTopLevelItem(selItem))
|
705
|
+
self.arChanged = True
|
706
|
+
return
|
714
707
|
|
715
|
-
def _getSelectedItem(self):
|
716
|
-
"""Extract the currently selected item.
|
717
|
-
"""
|
708
|
+
def _getSelectedItem(self) -> QTreeWidgetItem | None:
|
709
|
+
"""Extract the currently selected item."""
|
718
710
|
selItem = self.listBox.selectedItems()
|
719
711
|
if len(selItem) == 0:
|
720
712
|
return None
|
721
713
|
return selItem[0]
|
722
714
|
|
723
|
-
def _stripNotAllowed(self,
|
724
|
-
"""Clean up the replace key string.
|
725
|
-
""
|
726
|
-
|
727
|
-
for c in theKey:
|
715
|
+
def _stripNotAllowed(self, key: str) -> str:
|
716
|
+
"""Clean up the replace key string."""
|
717
|
+
result = ""
|
718
|
+
for c in key:
|
728
719
|
if c.isalnum():
|
729
|
-
|
730
|
-
return
|
720
|
+
result += c
|
721
|
+
return result
|
731
722
|
|
732
723
|
# END Class GuiProjectEditReplace
|
novelwriter/dialogs/updates.py
CHANGED
@@ -29,10 +29,10 @@ import logging
|
|
29
29
|
from datetime import datetime
|
30
30
|
from urllib.request import Request, urlopen
|
31
31
|
|
32
|
-
from PyQt5.QtGui import QCursor
|
33
|
-
from PyQt5.QtCore import Qt
|
32
|
+
from PyQt5.QtGui import QCloseEvent, QCursor
|
33
|
+
from PyQt5.QtCore import Qt, pyqtSlot
|
34
34
|
from PyQt5.QtWidgets import (
|
35
|
-
qApp, QDialog, QHBoxLayout, QVBoxLayout, QDialogButtonBox, QLabel
|
35
|
+
QWidget, qApp, QDialog, QHBoxLayout, QVBoxLayout, QDialogButtonBox, QLabel
|
36
36
|
)
|
37
37
|
|
38
38
|
from novelwriter import CONFIG, SHARED, __version__, __date__
|
@@ -44,8 +44,8 @@ logger = logging.getLogger(__name__)
|
|
44
44
|
|
45
45
|
class GuiUpdates(QDialog):
|
46
46
|
|
47
|
-
def __init__(self,
|
48
|
-
super().__init__(parent=
|
47
|
+
def __init__(self, parent: QWidget) -> None:
|
48
|
+
super().__init__(parent=parent)
|
49
49
|
|
50
50
|
logger.debug("Create: GuiUpdates")
|
51
51
|
self.setObjectName("GuiUpdates")
|
@@ -94,8 +94,8 @@ class GuiUpdates(QDialog):
|
|
94
94
|
self.latestLabel.setFont(hFont)
|
95
95
|
|
96
96
|
# Buttons
|
97
|
-
self.buttonBox = QDialogButtonBox(QDialogButtonBox.
|
98
|
-
self.buttonBox.
|
97
|
+
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Close)
|
98
|
+
self.buttonBox.rejected.connect(self._doClose)
|
99
99
|
|
100
100
|
# Assemble
|
101
101
|
self.innerBox = QHBoxLayout()
|
@@ -114,17 +114,16 @@ class GuiUpdates(QDialog):
|
|
114
114
|
|
115
115
|
return
|
116
116
|
|
117
|
-
def __del__(self): # pragma: no cover
|
117
|
+
def __del__(self) -> None: # pragma: no cover
|
118
118
|
logger.debug("Delete: GuiUpdates")
|
119
119
|
return
|
120
120
|
|
121
|
-
def checkLatest(self):
|
122
|
-
"""Check for latest release.
|
123
|
-
"""
|
121
|
+
def checkLatest(self) -> None:
|
122
|
+
"""Check for latest release."""
|
124
123
|
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
|
125
124
|
|
126
125
|
urlReq = Request("https://api.github.com/repos/vkbo/novelwriter/releases/latest")
|
127
|
-
urlReq.add_header("User-Agent",
|
126
|
+
urlReq.add_header("User-Agent", nwConst.USER_AGENT)
|
128
127
|
urlReq.add_header("Accept", "application/vnd.github.v3+json")
|
129
128
|
|
130
129
|
rawData = {}
|
@@ -161,10 +160,22 @@ class GuiUpdates(QDialog):
|
|
161
160
|
return
|
162
161
|
|
163
162
|
##
|
164
|
-
#
|
163
|
+
# Events
|
165
164
|
##
|
166
165
|
|
167
|
-
def
|
166
|
+
def closeEvent(self, event: QCloseEvent) -> None:
|
167
|
+
"""Capture the user closing the window."""
|
168
|
+
event.accept()
|
169
|
+
self.deleteLater()
|
170
|
+
return
|
171
|
+
|
172
|
+
##
|
173
|
+
# Private Slots
|
174
|
+
##
|
175
|
+
|
176
|
+
@pyqtSlot()
|
177
|
+
def _doClose(self) -> None:
|
178
|
+
"""Close the dialog."""
|
168
179
|
self.close()
|
169
180
|
return
|
170
181
|
|
novelwriter/enum.py
CHANGED
@@ -61,6 +61,24 @@ class nwItemLayout(Enum):
|
|
61
61
|
# END Enum nwItemLayout
|
62
62
|
|
63
63
|
|
64
|
+
class nwComment(Enum):
|
65
|
+
|
66
|
+
PLAIN = 0
|
67
|
+
SYNOPSIS = 1
|
68
|
+
SHORT = 2
|
69
|
+
|
70
|
+
# END Enum nwComment
|
71
|
+
|
72
|
+
|
73
|
+
class nwTrinary(Enum):
|
74
|
+
|
75
|
+
NEGATIVE = -1
|
76
|
+
NEUTRAL = 0
|
77
|
+
POSITIVE = 1
|
78
|
+
|
79
|
+
# END Enum nwTrinary
|
80
|
+
|
81
|
+
|
64
82
|
class nwDocMode(Enum):
|
65
83
|
|
66
84
|
VIEW = 0
|
@@ -100,6 +118,12 @@ class nwDocAction(Enum):
|
|
100
118
|
ALIGN_R = 26
|
101
119
|
INDENT_L = 27
|
102
120
|
INDENT_R = 28
|
121
|
+
SC_ITALIC = 29
|
122
|
+
SC_BOLD = 30
|
123
|
+
SC_STRIKE = 31
|
124
|
+
SC_ULINE = 32
|
125
|
+
SC_SUP = 33
|
126
|
+
SC_SUB = 34
|
103
127
|
|
104
128
|
# END Enum nwDocAction
|
105
129
|
|
@@ -112,9 +136,10 @@ class nwDocInsert(Enum):
|
|
112
136
|
QUOTE_LD = 3
|
113
137
|
QUOTE_RD = 4
|
114
138
|
SYNOPSIS = 5
|
115
|
-
|
116
|
-
|
117
|
-
|
139
|
+
SHORT = 6
|
140
|
+
NEW_PAGE = 7
|
141
|
+
VSPACE_S = 8
|
142
|
+
VSPACE_M = 9
|
118
143
|
|
119
144
|
# END Enum nwDocInsert
|
120
145
|
|
@@ -62,7 +62,7 @@ class NovelSelector(QComboBox):
|
|
62
62
|
# Methods
|
63
63
|
##
|
64
64
|
|
65
|
-
def setHandle(self, tHandle: str, blockSignal: bool = True) -> None:
|
65
|
+
def setHandle(self, tHandle: str | None, blockSignal: bool = True) -> None:
|
66
66
|
"""Set the currently selected handle."""
|
67
67
|
self._blockSignal = blockSignal
|
68
68
|
if tHandle is None:
|