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
novelwriter/gui/noveltree.py
CHANGED
@@ -29,9 +29,10 @@ import logging
|
|
29
29
|
|
30
30
|
from enum import Enum
|
31
31
|
from time import time
|
32
|
+
from typing import TYPE_CHECKING
|
32
33
|
|
33
|
-
from PyQt5.QtGui import QFont, QPalette
|
34
|
-
from PyQt5.QtCore import Qt, QSize, pyqtSlot, pyqtSignal
|
34
|
+
from PyQt5.QtGui import QFocusEvent, QFont, QMouseEvent, QPalette, QResizeEvent
|
35
|
+
from PyQt5.QtCore import QModelIndex, QPoint, Qt, QSize, pyqtSlot, pyqtSignal
|
35
36
|
from PyQt5.QtWidgets import (
|
36
37
|
QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView,
|
37
38
|
QInputDialog, QMenu, QSizePolicy, QToolButton, QToolTip, QTreeWidget,
|
@@ -42,8 +43,12 @@ from novelwriter import CONFIG, SHARED
|
|
42
43
|
from novelwriter.enum import nwDocMode, nwItemClass, nwOutline
|
43
44
|
from novelwriter.common import minmax
|
44
45
|
from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst
|
46
|
+
from novelwriter.core.index import IndexHeading
|
45
47
|
from novelwriter.extensions.novelselector import NovelSelector
|
46
48
|
|
49
|
+
if TYPE_CHECKING: # pragma: no cover
|
50
|
+
from novelwriter.guimain import GuiMain
|
51
|
+
|
47
52
|
logger = logging.getLogger(__name__)
|
48
53
|
|
49
54
|
|
@@ -63,7 +68,7 @@ class GuiNovelView(QWidget):
|
|
63
68
|
selectedItemChanged = pyqtSignal(str)
|
64
69
|
openDocumentRequest = pyqtSignal(str, Enum, str, bool)
|
65
70
|
|
66
|
-
def __init__(self, mainGui):
|
71
|
+
def __init__(self, mainGui: GuiMain) -> None:
|
67
72
|
super().__init__(parent=mainGui)
|
68
73
|
|
69
74
|
self.mainGui = mainGui
|
@@ -92,33 +97,29 @@ class GuiNovelView(QWidget):
|
|
92
97
|
# Methods
|
93
98
|
##
|
94
99
|
|
95
|
-
def updateTheme(self):
|
96
|
-
"""Update theme elements.
|
97
|
-
"""
|
100
|
+
def updateTheme(self) -> None:
|
101
|
+
"""Update theme elements."""
|
98
102
|
self.novelBar.updateTheme()
|
99
103
|
self.novelTree.updateTheme()
|
100
104
|
self.refreshTree()
|
101
105
|
return
|
102
106
|
|
103
|
-
def initSettings(self):
|
104
|
-
"""Initialise GUI elements that depend on specific settings.
|
105
|
-
"""
|
107
|
+
def initSettings(self) -> None:
|
108
|
+
"""Initialise GUI elements that depend on specific settings."""
|
106
109
|
self.novelTree.initSettings()
|
107
110
|
return
|
108
111
|
|
109
|
-
def clearNovelView(self):
|
110
|
-
"""Clear project-related GUI content.
|
111
|
-
"""
|
112
|
+
def clearNovelView(self) -> None:
|
113
|
+
"""Clear project-related GUI content."""
|
112
114
|
self.novelTree.clearContent()
|
113
115
|
self.novelBar.clearContent()
|
114
116
|
self.novelBar.setEnabled(False)
|
115
117
|
return
|
116
118
|
|
117
|
-
def openProjectTasks(self):
|
118
|
-
"""Run open project tasks.
|
119
|
-
"""
|
119
|
+
def openProjectTasks(self) -> None:
|
120
|
+
"""Run open project tasks."""
|
120
121
|
lastNovel = SHARED.project.data.getLastHandle("novelTree")
|
121
|
-
if lastNovel not in SHARED.project.tree:
|
122
|
+
if lastNovel and lastNovel not in SHARED.project.tree:
|
122
123
|
lastNovel = SHARED.project.tree.findRoot(nwItemClass.NOVEL)
|
123
124
|
|
124
125
|
logger.debug("Setting novel tree to root item '%s'", lastNovel)
|
@@ -140,7 +141,7 @@ class GuiNovelView(QWidget):
|
|
140
141
|
|
141
142
|
return
|
142
143
|
|
143
|
-
def closeProjectTasks(self):
|
144
|
+
def closeProjectTasks(self) -> None:
|
144
145
|
"""Run closing project tasks."""
|
145
146
|
lastColType = self.novelTree.lastColType
|
146
147
|
lastColSize = self.novelTree.lastColSize
|
@@ -150,15 +151,13 @@ class GuiNovelView(QWidget):
|
|
150
151
|
self.clearNovelView()
|
151
152
|
return
|
152
153
|
|
153
|
-
def setTreeFocus(self):
|
154
|
-
"""Set the focus to the tree widget.
|
155
|
-
"""
|
154
|
+
def setTreeFocus(self) -> None:
|
155
|
+
"""Set the focus to the tree widget."""
|
156
156
|
self.novelTree.setFocus()
|
157
157
|
return
|
158
158
|
|
159
|
-
def treeHasFocus(self):
|
160
|
-
"""Check if the novel tree has focus.
|
161
|
-
"""
|
159
|
+
def treeHasFocus(self) -> bool:
|
160
|
+
"""Check if the novel tree has focus."""
|
162
161
|
return self.novelTree.hasFocus()
|
163
162
|
|
164
163
|
##
|
@@ -166,21 +165,19 @@ class GuiNovelView(QWidget):
|
|
166
165
|
##
|
167
166
|
|
168
167
|
@pyqtSlot()
|
169
|
-
def refreshTree(self):
|
170
|
-
"""Refresh the current tree.
|
171
|
-
"""
|
168
|
+
def refreshTree(self) -> None:
|
169
|
+
"""Refresh the current tree."""
|
172
170
|
self.novelTree.refreshTree(rootHandle=SHARED.project.data.getLastHandle("novelTree"))
|
173
171
|
return
|
174
172
|
|
175
173
|
@pyqtSlot(str)
|
176
|
-
def updateRootItem(self, tHandle):
|
177
|
-
"""If any root item changes, rebuild the novel root menu.
|
178
|
-
"""
|
174
|
+
def updateRootItem(self, tHandle: str) -> None:
|
175
|
+
"""If any root item changes, rebuild the novel root menu."""
|
179
176
|
self.novelBar.buildNovelRootMenu()
|
180
177
|
return
|
181
178
|
|
182
179
|
@pyqtSlot(str)
|
183
|
-
def updateNovelItemMeta(self, tHandle):
|
180
|
+
def updateNovelItemMeta(self, tHandle: str) -> None:
|
184
181
|
"""The meta data of a novel item has changed, and the tree item
|
185
182
|
needs to be refreshed.
|
186
183
|
"""
|
@@ -192,7 +189,7 @@ class GuiNovelView(QWidget):
|
|
192
189
|
|
193
190
|
class GuiNovelToolBar(QWidget):
|
194
191
|
|
195
|
-
def __init__(self, novelView):
|
192
|
+
def __init__(self, novelView: GuiNovelView) -> None:
|
196
193
|
super().__init__(parent=novelView)
|
197
194
|
|
198
195
|
logger.debug("Create: GuiNovelToolBar")
|
@@ -269,9 +266,8 @@ class GuiNovelToolBar(QWidget):
|
|
269
266
|
# Methods
|
270
267
|
##
|
271
268
|
|
272
|
-
def updateTheme(self):
|
273
|
-
"""Update theme elements.
|
274
|
-
"""
|
269
|
+
def updateTheme(self) -> None:
|
270
|
+
"""Update theme elements."""
|
275
271
|
# Icons
|
276
272
|
self.tbNovel.setIcon(SHARED.theme.getIcon("cls_novel"))
|
277
273
|
self.tbRefresh.setIcon(SHARED.theme.getIcon("refresh"))
|
@@ -287,10 +283,11 @@ class GuiNovelToolBar(QWidget):
|
|
287
283
|
"QToolButton {{padding: {0}px; border: none; background: transparent;}} "
|
288
284
|
"QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}"
|
289
285
|
).format(CONFIG.pxInt(2), fadeCol.red(), fadeCol.green(), fadeCol.blue())
|
286
|
+
buttonStyleMenu = f"{buttonStyle} QToolButton::menu-indicator {{image: none;}}"
|
290
287
|
|
291
288
|
self.tbNovel.setStyleSheet(buttonStyle)
|
292
289
|
self.tbRefresh.setStyleSheet(buttonStyle)
|
293
|
-
self.tbMore.setStyleSheet(
|
290
|
+
self.tbMore.setStyleSheet(buttonStyleMenu)
|
294
291
|
|
295
292
|
self.novelValue.setStyleSheet(
|
296
293
|
"QComboBox {border-style: none; padding-left: 0;} "
|
@@ -301,30 +298,26 @@ class GuiNovelToolBar(QWidget):
|
|
301
298
|
|
302
299
|
return
|
303
300
|
|
304
|
-
def clearContent(self):
|
305
|
-
"""Run clearing project tasks.
|
306
|
-
"""
|
301
|
+
def clearContent(self) -> None:
|
302
|
+
"""Run clearing project tasks."""
|
307
303
|
self.novelValue.clear()
|
308
304
|
self.novelValue.setToolTip("")
|
309
305
|
return
|
310
306
|
|
311
|
-
def buildNovelRootMenu(self):
|
312
|
-
"""Build the novel root menu.
|
313
|
-
"""
|
307
|
+
def buildNovelRootMenu(self) -> None:
|
308
|
+
"""Build the novel root menu."""
|
314
309
|
self.novelValue.updateList(prefix=self.novelPrefix)
|
315
310
|
self.tbNovel.setVisible(self.novelValue.count() > 1)
|
316
311
|
return
|
317
312
|
|
318
|
-
def setCurrentRoot(self, rootHandle):
|
319
|
-
"""Set the current active root handle.
|
320
|
-
"""
|
313
|
+
def setCurrentRoot(self, rootHandle: str | None) -> None:
|
314
|
+
"""Set the current active root handle."""
|
321
315
|
self.novelValue.setHandle(rootHandle)
|
322
316
|
self.novelView.novelTree.refreshTree(rootHandle=rootHandle, overRide=True)
|
323
317
|
return
|
324
318
|
|
325
|
-
def setLastColType(self, colType, doRefresh=True):
|
326
|
-
"""Set the last column type.
|
327
|
-
"""
|
319
|
+
def setLastColType(self, colType: NovelTreeColumn, doRefresh: bool = True) -> None:
|
320
|
+
"""Set the last column type."""
|
328
321
|
self.aLastCol[colType].setChecked(True)
|
329
322
|
self.novelView.novelTree.setLastColType(colType, doRefresh=doRefresh)
|
330
323
|
return
|
@@ -334,24 +327,21 @@ class GuiNovelToolBar(QWidget):
|
|
334
327
|
##
|
335
328
|
|
336
329
|
@pyqtSlot()
|
337
|
-
def _openNovelSelector(self):
|
338
|
-
"""Trigger the dropdown list of the novel selector.
|
339
|
-
"""
|
330
|
+
def _openNovelSelector(self) -> None:
|
331
|
+
"""Trigger the dropdown list of the novel selector."""
|
340
332
|
self.novelValue.showPopup()
|
341
333
|
return
|
342
334
|
|
343
335
|
@pyqtSlot()
|
344
|
-
def _refreshNovelTree(self):
|
345
|
-
"""Rebuild the current tree.
|
346
|
-
"""
|
336
|
+
def _refreshNovelTree(self) -> None:
|
337
|
+
"""Rebuild the current tree."""
|
347
338
|
rootHandle = SHARED.project.data.getLastHandle("novelTree")
|
348
339
|
self.novelView.novelTree.refreshTree(rootHandle=rootHandle, overRide=True)
|
349
340
|
return
|
350
341
|
|
351
342
|
@pyqtSlot()
|
352
|
-
def _selectLastColumnSize(self):
|
353
|
-
"""Set the maximum width for the last column.
|
354
|
-
"""
|
343
|
+
def _selectLastColumnSize(self) -> None:
|
344
|
+
"""Set the maximum width for the last column."""
|
355
345
|
oldSize = self.novelView.novelTree.lastColSize
|
356
346
|
newSize, isOk = QInputDialog.getInt(
|
357
347
|
self, self.tr("Column Size"), self.tr("Maximum column size in %"), oldSize, 15, 75, 5
|
@@ -365,9 +355,8 @@ class GuiNovelToolBar(QWidget):
|
|
365
355
|
# Internal Functions
|
366
356
|
##
|
367
357
|
|
368
|
-
def _addLastColAction(self, colType, actionLabel):
|
369
|
-
"""Add a column selection entry to the last column menu.
|
370
|
-
"""
|
358
|
+
def _addLastColAction(self, colType, actionLabel) -> None:
|
359
|
+
"""Add a column selection entry to the last column menu."""
|
371
360
|
aLast = self.mLastCol.addAction(actionLabel)
|
372
361
|
aLast.setCheckable(True)
|
373
362
|
aLast.setActionGroup(self.gLastCol)
|
@@ -391,7 +380,7 @@ class GuiNovelTree(QTreeWidget):
|
|
391
380
|
D_KEY = Qt.ItemDataRole.UserRole + 2
|
392
381
|
D_EXTRA = Qt.ItemDataRole.UserRole + 3
|
393
382
|
|
394
|
-
def __init__(self, novelView):
|
383
|
+
def __init__(self, novelView: GuiNovelView) -> None:
|
395
384
|
super().__init__(parent=novelView)
|
396
385
|
|
397
386
|
logger.debug("Create: GuiNovelTree")
|
@@ -461,9 +450,8 @@ class GuiNovelTree(QTreeWidget):
|
|
461
450
|
|
462
451
|
return
|
463
452
|
|
464
|
-
def initSettings(self):
|
465
|
-
"""Set or update tree widget settings.
|
466
|
-
"""
|
453
|
+
def initSettings(self) -> None:
|
454
|
+
"""Set or update tree widget settings."""
|
467
455
|
# Scroll bars
|
468
456
|
if CONFIG.hideVScroll:
|
469
457
|
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
@@ -477,11 +465,10 @@ class GuiNovelTree(QTreeWidget):
|
|
477
465
|
|
478
466
|
return
|
479
467
|
|
480
|
-
def updateTheme(self):
|
481
|
-
"""Update theme elements.
|
482
|
-
"""
|
468
|
+
def updateTheme(self) -> None:
|
469
|
+
"""Update theme elements."""
|
483
470
|
iPx = SHARED.theme.baseIconSize
|
484
|
-
self._pMore = SHARED.theme.loadDecoration("deco_doc_more",
|
471
|
+
self._pMore = SHARED.theme.loadDecoration("deco_doc_more", h=iPx)
|
485
472
|
return
|
486
473
|
|
487
474
|
##
|
@@ -489,28 +476,26 @@ class GuiNovelTree(QTreeWidget):
|
|
489
476
|
##
|
490
477
|
|
491
478
|
@property
|
492
|
-
def lastColType(self):
|
479
|
+
def lastColType(self) -> NovelTreeColumn:
|
493
480
|
return self._lastCol
|
494
481
|
|
495
482
|
@property
|
496
|
-
def lastColSize(self):
|
483
|
+
def lastColSize(self) -> int:
|
497
484
|
return int(self._lastColSize * 100)
|
498
485
|
|
499
486
|
##
|
500
487
|
# Class Methods
|
501
488
|
##
|
502
489
|
|
503
|
-
def clearContent(self):
|
504
|
-
"""Clear the GUI content and the related maps.
|
505
|
-
"""
|
490
|
+
def clearContent(self) -> None:
|
491
|
+
"""Clear the GUI content and the related maps."""
|
506
492
|
self.clear()
|
507
493
|
self._treeMap = {}
|
508
494
|
self._lastBuild = 0
|
509
495
|
return
|
510
496
|
|
511
|
-
def refreshTree(self, rootHandle=None, overRide=False):
|
512
|
-
"""Refresh the tree if it has been changed.
|
513
|
-
"""
|
497
|
+
def refreshTree(self, rootHandle: str | None = None, overRide: bool = False) -> None:
|
498
|
+
"""Refresh the tree if it has been changed."""
|
514
499
|
logger.debug("Requesting refresh of the novel tree")
|
515
500
|
if rootHandle is None:
|
516
501
|
rootHandle = SHARED.project.tree.findRoot(nwItemClass.NOVEL)
|
@@ -534,9 +519,8 @@ class GuiNovelTree(QTreeWidget):
|
|
534
519
|
|
535
520
|
return
|
536
521
|
|
537
|
-
def refreshHandle(self, tHandle):
|
538
|
-
"""Refresh the data for a given handle.
|
539
|
-
"""
|
522
|
+
def refreshHandle(self, tHandle: str) -> None:
|
523
|
+
"""Refresh the data for a given handle."""
|
540
524
|
idxData = SHARED.project.index.getItemData(tHandle)
|
541
525
|
if idxData is None:
|
542
526
|
return
|
@@ -554,7 +538,7 @@ class GuiNovelTree(QTreeWidget):
|
|
554
538
|
|
555
539
|
return
|
556
540
|
|
557
|
-
def getSelectedHandle(self):
|
541
|
+
def getSelectedHandle(self) -> tuple[str | None, str | None]:
|
558
542
|
"""Get the currently selected or active handle. If multiple
|
559
543
|
items are selected, return the first.
|
560
544
|
"""
|
@@ -566,9 +550,8 @@ class GuiNovelTree(QTreeWidget):
|
|
566
550
|
return tHandle, sTitle
|
567
551
|
return None, None
|
568
552
|
|
569
|
-
def setLastColType(self, colType, doRefresh=True):
|
570
|
-
"""Change the content type of the last column and rebuild.
|
571
|
-
"""
|
553
|
+
def setLastColType(self, colType: NovelTreeColumn, doRefresh: bool = True) -> None:
|
554
|
+
"""Change the content type of the last column and rebuild."""
|
572
555
|
if self._lastCol != colType:
|
573
556
|
logger.debug("Changing last column to %s", colType.name)
|
574
557
|
self._lastCol = colType
|
@@ -578,15 +561,13 @@ class GuiNovelTree(QTreeWidget):
|
|
578
561
|
self.refreshTree(rootHandle=lastNovel, overRide=True)
|
579
562
|
return
|
580
563
|
|
581
|
-
def setLastColSize(self, colSize):
|
582
|
-
"""Set the column size in integer values between 15 and 75.
|
583
|
-
"""
|
564
|
+
def setLastColSize(self, colSize: int) -> None:
|
565
|
+
"""Set the column size in integer values between 15 and 75."""
|
584
566
|
self._lastColSize = minmax(colSize, 15, 75)/100.0
|
585
567
|
return
|
586
568
|
|
587
|
-
def setActiveHandle(self, tHandle):
|
588
|
-
"""Highlight the rows associated with a given handle.
|
589
|
-
"""
|
569
|
+
def setActiveHandle(self, tHandle: str | None) -> None:
|
570
|
+
"""Highlight the rows associated with a given handle."""
|
590
571
|
tStart = time()
|
591
572
|
|
592
573
|
self._actHandle = tHandle
|
@@ -612,20 +593,20 @@ class GuiNovelTree(QTreeWidget):
|
|
612
593
|
# Events
|
613
594
|
##
|
614
595
|
|
615
|
-
def mousePressEvent(self,
|
596
|
+
def mousePressEvent(self, event: QMouseEvent) -> None:
|
616
597
|
"""Overload mousePressEvent to clear selection if clicking the
|
617
598
|
mouse in a blank area of the tree view, and to load a document
|
618
599
|
for viewing if the user middle-clicked.
|
619
600
|
"""
|
620
|
-
super().mousePressEvent(
|
601
|
+
super().mousePressEvent(event)
|
621
602
|
|
622
|
-
if
|
623
|
-
selItem = self.indexAt(
|
603
|
+
if event.button() == Qt.LeftButton:
|
604
|
+
selItem = self.indexAt(event.pos())
|
624
605
|
if not selItem.isValid():
|
625
606
|
self.clearSelection()
|
626
607
|
|
627
|
-
elif
|
628
|
-
selItem = self.itemAt(
|
608
|
+
elif event.button() == Qt.MiddleButton:
|
609
|
+
selItem = self.itemAt(event.pos())
|
629
610
|
if not isinstance(selItem, QTreeWidgetItem):
|
630
611
|
return
|
631
612
|
|
@@ -637,16 +618,14 @@ class GuiNovelTree(QTreeWidget):
|
|
637
618
|
|
638
619
|
return
|
639
620
|
|
640
|
-
def focusOutEvent(self,
|
641
|
-
"""Clear the selection when the tree no longer has focus.
|
642
|
-
|
643
|
-
super().focusOutEvent(theEvent)
|
621
|
+
def focusOutEvent(self, event: QFocusEvent) -> None:
|
622
|
+
"""Clear the selection when the tree no longer has focus."""
|
623
|
+
super().focusOutEvent(event)
|
644
624
|
self.clearSelection()
|
645
625
|
return
|
646
626
|
|
647
|
-
def resizeEvent(self, event):
|
648
|
-
"""Elide labels in the extra column.
|
649
|
-
"""
|
627
|
+
def resizeEvent(self, event: QResizeEvent) -> None:
|
628
|
+
"""Elide labels in the extra column."""
|
650
629
|
super().resizeEvent(event)
|
651
630
|
newW = event.size().width()
|
652
631
|
oldW = event.oldSize().width()
|
@@ -665,18 +644,17 @@ class GuiNovelTree(QTreeWidget):
|
|
665
644
|
##
|
666
645
|
|
667
646
|
@pyqtSlot("QModelIndex")
|
668
|
-
def _treeItemClicked(self,
|
669
|
-
"""The user clicked on an item in the tree.
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
tipPos = self.mapToGlobal(self.visualRect(mIndex).topRight())
|
647
|
+
def _treeItemClicked(self, index: QModelIndex) -> None:
|
648
|
+
"""The user clicked on an item in the tree."""
|
649
|
+
if index.column() == self.C_MORE:
|
650
|
+
tHandle = index.siblingAtColumn(self.C_DATA).data(self.D_HANDLE)
|
651
|
+
sTitle = index.siblingAtColumn(self.C_DATA).data(self.D_TITLE)
|
652
|
+
tipPos = self.mapToGlobal(self.visualRect(index).topRight())
|
675
653
|
self._popMetaBox(tipPos, tHandle, sTitle)
|
676
654
|
return
|
677
655
|
|
678
656
|
@pyqtSlot()
|
679
|
-
def _treeSelectionChange(self):
|
657
|
+
def _treeSelectionChange(self) -> None:
|
680
658
|
"""Extract the handle and line number of the currently selected
|
681
659
|
title, and send it to the tree meta panel.
|
682
660
|
"""
|
@@ -686,7 +664,7 @@ class GuiNovelTree(QTreeWidget):
|
|
686
664
|
return
|
687
665
|
|
688
666
|
@pyqtSlot("QTreeWidgetItem*", int)
|
689
|
-
def _treeDoubleClick(self,
|
667
|
+
def _treeDoubleClick(self, item: QTreeWidgetItem, column: int) -> None:
|
690
668
|
"""Extract the handle and line number of the title double-
|
691
669
|
clicked, and send it to the main gui class for opening in the
|
692
670
|
document editor.
|
@@ -699,9 +677,8 @@ class GuiNovelTree(QTreeWidget):
|
|
699
677
|
# Internal Functions
|
700
678
|
##
|
701
679
|
|
702
|
-
def _populateTree(self, rootHandle):
|
703
|
-
"""Build the tree based on the project index.
|
704
|
-
"""
|
680
|
+
def _populateTree(self, rootHandle: str | None) -> None:
|
681
|
+
"""Build the tree based on the project index."""
|
705
682
|
self.clearContent()
|
706
683
|
tStart = time()
|
707
684
|
logger.debug("Building novel tree for root item '%s'", rootHandle)
|
@@ -728,9 +705,9 @@ class GuiNovelTree(QTreeWidget):
|
|
728
705
|
|
729
706
|
return
|
730
707
|
|
731
|
-
def _updateTreeItemValues(self, trItem, idxItem
|
732
|
-
|
733
|
-
"""
|
708
|
+
def _updateTreeItemValues(self, trItem: QTreeWidgetItem, idxItem: IndexHeading,
|
709
|
+
tHandle: str, sTitle: str) -> None:
|
710
|
+
"""Set the tree item values from the index entry."""
|
734
711
|
iLevel = nwHeaders.H_LEVEL.get(idxItem.level, 0)
|
735
712
|
hDec = SHARED.theme.getHeaderDecoration(iLevel)
|
736
713
|
|
@@ -750,9 +727,8 @@ class GuiNovelTree(QTreeWidget):
|
|
750
727
|
|
751
728
|
return
|
752
729
|
|
753
|
-
def _getLastColumnText(self, tHandle, sTitle):
|
754
|
-
"""Generate
|
755
|
-
"""
|
730
|
+
def _getLastColumnText(self, tHandle: str, sTitle: str) -> tuple[str, str]:
|
731
|
+
"""Generate text for the last column based on user settings."""
|
756
732
|
if self._lastCol == NovelTreeColumn.HIDDEN:
|
757
733
|
return "", ""
|
758
734
|
|
@@ -777,14 +753,15 @@ class GuiNovelTree(QTreeWidget):
|
|
777
753
|
|
778
754
|
return "", ""
|
779
755
|
|
780
|
-
def _popMetaBox(self, qPos, tHandle, sTitle):
|
781
|
-
"""Show the novel meta data box.
|
782
|
-
"""
|
756
|
+
def _popMetaBox(self, qPos: QPoint, tHandle: str, sTitle: str) -> None:
|
757
|
+
"""Show the novel meta data box."""
|
783
758
|
logger.debug("Generating meta data tooltip for '%s:%s'", tHandle, sTitle)
|
784
759
|
|
785
760
|
pIndex = SHARED.project.index
|
786
761
|
novIdx = pIndex.getItemHeader(tHandle, sTitle)
|
787
762
|
refTags = pIndex.getReferences(tHandle, sTitle)
|
763
|
+
if not novIdx:
|
764
|
+
return
|
788
765
|
|
789
766
|
synopText = novIdx.synopsis
|
790
767
|
if synopText:
|
@@ -814,9 +791,8 @@ class GuiNovelTree(QTreeWidget):
|
|
814
791
|
return
|
815
792
|
|
816
793
|
@staticmethod
|
817
|
-
def _appendMetaTag(refs, key, lines):
|
818
|
-
"""Generate a reference list for a given reference key.
|
819
|
-
"""
|
794
|
+
def _appendMetaTag(refs: dict, key: str, lines: list[str]) -> list[str]:
|
795
|
+
"""Generate a reference list for a given reference key."""
|
820
796
|
tags = ", ".join(refs.get(key, []))
|
821
797
|
if tags:
|
822
798
|
lines.append(f"<b>{trConst(nwLabels.KEY_NAME[key])}</b>: {tags}")
|