novelWriter 2.5.2__py3-none-any.whl → 2.6__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.5.2.dist-info → novelWriter-2.6.dist-info}/METADATA +5 -4
- {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/RECORD +126 -105
- {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/WHEEL +1 -1
- novelwriter/__init__.py +50 -11
- 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_ru_RU.qm +0 -0
- novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
- novelwriter/assets/i18n/project_de_DE.json +4 -2
- novelwriter/assets/i18n/project_en_GB.json +1 -0
- novelwriter/assets/i18n/project_en_US.json +2 -0
- novelwriter/assets/i18n/project_it_IT.json +2 -0
- novelwriter/assets/i18n/project_ja_JP.json +2 -0
- novelwriter/assets/i18n/project_nb_NO.json +2 -0
- novelwriter/assets/i18n/project_nl_NL.json +2 -0
- novelwriter/assets/i18n/project_pl_PL.json +2 -0
- novelwriter/assets/i18n/project_pt_BR.json +2 -0
- novelwriter/assets/i18n/project_ru_RU.json +11 -0
- novelwriter/assets/i18n/project_zh_CN.json +2 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +8 -0
- novelwriter/assets/icons/typicons_dark/mixed_copy.svg +4 -0
- novelwriter/assets/icons/typicons_dark/mixed_margin-bottom.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_margin-left.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_margin-right.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_margin-top.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_size-height.svg +6 -0
- novelwriter/assets/icons/typicons_dark/mixed_size-width.svg +6 -0
- novelwriter/assets/icons/typicons_dark/nw_toolbar.svg +5 -0
- novelwriter/assets/icons/typicons_light/icons.conf +8 -0
- novelwriter/assets/icons/typicons_light/mixed_copy.svg +4 -0
- novelwriter/assets/icons/typicons_light/mixed_margin-bottom.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_margin-left.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_margin-right.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_margin-top.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_size-height.svg +6 -0
- novelwriter/assets/icons/typicons_light/mixed_size-width.svg +6 -0
- novelwriter/assets/icons/typicons_light/nw_toolbar.svg +5 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/text/credits_en.htm +1 -0
- novelwriter/assets/themes/default_light.conf +2 -2
- novelwriter/common.py +101 -3
- novelwriter/config.py +30 -17
- novelwriter/constants.py +189 -81
- novelwriter/core/buildsettings.py +74 -40
- novelwriter/core/coretools.py +146 -148
- novelwriter/core/docbuild.py +133 -171
- novelwriter/core/document.py +1 -1
- novelwriter/core/index.py +39 -38
- novelwriter/core/item.py +42 -9
- novelwriter/core/itemmodel.py +518 -0
- novelwriter/core/options.py +5 -2
- novelwriter/core/project.py +68 -90
- novelwriter/core/projectdata.py +8 -2
- novelwriter/core/projectxml.py +1 -1
- novelwriter/core/sessions.py +1 -1
- novelwriter/core/spellcheck.py +10 -15
- novelwriter/core/status.py +24 -8
- novelwriter/core/storage.py +1 -1
- novelwriter/core/tree.py +269 -288
- novelwriter/dialogs/about.py +1 -1
- novelwriter/dialogs/docmerge.py +8 -18
- novelwriter/dialogs/docsplit.py +1 -1
- novelwriter/dialogs/editlabel.py +1 -1
- novelwriter/dialogs/preferences.py +47 -34
- novelwriter/dialogs/projectsettings.py +149 -99
- novelwriter/dialogs/quotes.py +1 -1
- novelwriter/dialogs/wordlist.py +11 -10
- novelwriter/enum.py +37 -24
- novelwriter/error.py +2 -2
- novelwriter/extensions/configlayout.py +28 -13
- novelwriter/extensions/eventfilters.py +1 -1
- novelwriter/extensions/modified.py +30 -6
- novelwriter/extensions/novelselector.py +4 -3
- novelwriter/extensions/pagedsidebar.py +9 -9
- novelwriter/extensions/progressbars.py +4 -4
- novelwriter/extensions/statusled.py +3 -3
- novelwriter/extensions/switch.py +3 -3
- novelwriter/extensions/switchbox.py +1 -1
- novelwriter/extensions/versioninfo.py +1 -1
- novelwriter/formats/shared.py +156 -0
- novelwriter/formats/todocx.py +1191 -0
- novelwriter/formats/tohtml.py +454 -0
- novelwriter/{core → formats}/tokenizer.py +497 -495
- novelwriter/formats/tomarkdown.py +218 -0
- novelwriter/{core → formats}/toodt.py +312 -433
- novelwriter/formats/toqdoc.py +486 -0
- novelwriter/formats/toraw.py +91 -0
- novelwriter/gui/doceditor.py +347 -287
- novelwriter/gui/dochighlight.py +97 -85
- novelwriter/gui/docviewer.py +90 -33
- novelwriter/gui/docviewerpanel.py +18 -26
- novelwriter/gui/editordocument.py +18 -3
- novelwriter/gui/itemdetails.py +27 -29
- novelwriter/gui/mainmenu.py +130 -64
- novelwriter/gui/noveltree.py +46 -48
- novelwriter/gui/outline.py +202 -256
- novelwriter/gui/projtree.py +590 -1238
- novelwriter/gui/search.py +11 -19
- novelwriter/gui/sidebar.py +8 -7
- novelwriter/gui/statusbar.py +20 -3
- novelwriter/gui/theme.py +11 -6
- novelwriter/guimain.py +101 -201
- novelwriter/shared.py +67 -28
- novelwriter/text/counting.py +3 -1
- novelwriter/text/patterns.py +169 -61
- novelwriter/tools/dictionaries.py +3 -3
- novelwriter/tools/lipsum.py +1 -1
- novelwriter/tools/manusbuild.py +15 -13
- novelwriter/tools/manuscript.py +121 -79
- novelwriter/tools/manussettings.py +424 -291
- novelwriter/tools/noveldetails.py +1 -1
- novelwriter/tools/welcome.py +6 -6
- novelwriter/tools/writingstats.py +4 -4
- novelwriter/types.py +25 -9
- novelwriter/core/tohtml.py +0 -530
- novelwriter/core/tomarkdown.py +0 -252
- novelwriter/core/toqdoc.py +0 -419
- {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.5.2.dist-info → novelWriter-2.6.dist-info}/top_level.txt +0 -0
novelwriter/gui/outline.py
CHANGED
@@ -10,7 +10,7 @@ Created: 2019-11-16 [0.4.1] GuiOutlineHeaderMenu
|
|
10
10
|
Created: 2020-06-02 [0.7] GuiOutlineDetails
|
11
11
|
|
12
12
|
This file is a part of novelWriter
|
13
|
-
Copyright
|
13
|
+
Copyright (C) 2019 Veronica Berglyd Olsen and novelWriter contributors
|
14
14
|
|
15
15
|
This program is free software: you can redistribute it and/or modify
|
16
16
|
it under the terms of the GNU General Public License as published by
|
@@ -41,15 +41,15 @@ from PyQt5.QtWidgets import (
|
|
41
41
|
)
|
42
42
|
|
43
43
|
from novelwriter import CONFIG, SHARED
|
44
|
-
from novelwriter.common import checkInt, formatFileFilter
|
45
|
-
from novelwriter.constants import
|
46
|
-
from novelwriter.enum import nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline
|
44
|
+
from novelwriter.common import checkInt, formatFileFilter
|
45
|
+
from novelwriter.constants import nwKeyWords, nwLabels, nwStats, nwStyles, trConst
|
46
|
+
from novelwriter.enum import nwChange, nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline
|
47
47
|
from novelwriter.error import logException
|
48
48
|
from novelwriter.extensions.configlayout import NColourLabel
|
49
49
|
from novelwriter.extensions.novelselector import NovelSelector
|
50
50
|
from novelwriter.types import (
|
51
51
|
QtAlignLeftTop, QtAlignRight, QtAlignRightTop, QtDecoration,
|
52
|
-
QtSizeExpanding, QtUserRole
|
52
|
+
QtScrollAlwaysOff, QtScrollAsNeeded, QtSizeExpanding, QtUserRole
|
53
53
|
)
|
54
54
|
|
55
55
|
logger = logging.getLogger(__name__)
|
@@ -135,11 +135,15 @@ class GuiOutlineView(QWidget):
|
|
135
135
|
self.outlineBar.populateNovelList()
|
136
136
|
self.outlineBar.setCurrentRoot(lastOutline)
|
137
137
|
self.outlineBar.setEnabled(True)
|
138
|
+
self.outlineData.loadGuiSettings()
|
138
139
|
|
139
140
|
return
|
140
141
|
|
141
142
|
def closeProjectTasks(self) -> None:
|
142
143
|
"""Run closing project tasks."""
|
144
|
+
if self.outlineTree.wasRendered:
|
145
|
+
# If the panel hasn't been drawn yet, those values are incorrect
|
146
|
+
self.outlineData.saveGuiSettings()
|
143
147
|
self.outlineTree.closeProjectTasks()
|
144
148
|
self.outlineData.updateClasses()
|
145
149
|
self.clearOutline()
|
@@ -161,8 +165,8 @@ class GuiOutlineView(QWidget):
|
|
161
165
|
# Public Slots
|
162
166
|
##
|
163
167
|
|
164
|
-
@pyqtSlot(str)
|
165
|
-
def updateRootItem(self, tHandle: str) -> None:
|
168
|
+
@pyqtSlot(str, Enum)
|
169
|
+
def updateRootItem(self, tHandle: str, change: nwChange) -> None:
|
166
170
|
"""Handle tasks whenever a root folders changes."""
|
167
171
|
self.outlineBar.populateNovelList()
|
168
172
|
self.outlineData.updateClasses()
|
@@ -312,43 +316,49 @@ class GuiOutlineToolBar(QToolBar):
|
|
312
316
|
class GuiOutlineTree(QTreeWidget):
|
313
317
|
|
314
318
|
DEF_WIDTH = {
|
315
|
-
nwOutline.TITLE:
|
316
|
-
nwOutline.LEVEL:
|
317
|
-
nwOutline.LABEL:
|
318
|
-
nwOutline.LINE:
|
319
|
-
nwOutline.
|
320
|
-
nwOutline.
|
321
|
-
nwOutline.
|
322
|
-
nwOutline.
|
323
|
-
nwOutline.
|
324
|
-
nwOutline.
|
325
|
-
nwOutline.
|
326
|
-
nwOutline.
|
327
|
-
nwOutline.
|
328
|
-
nwOutline.
|
329
|
-
nwOutline.
|
330
|
-
nwOutline.
|
331
|
-
nwOutline.
|
319
|
+
nwOutline.TITLE: 200,
|
320
|
+
nwOutline.LEVEL: 40,
|
321
|
+
nwOutline.LABEL: 150,
|
322
|
+
nwOutline.LINE: 40,
|
323
|
+
nwOutline.STATUS: 100,
|
324
|
+
nwOutline.CCOUNT: 50,
|
325
|
+
nwOutline.WCOUNT: 50,
|
326
|
+
nwOutline.PCOUNT: 50,
|
327
|
+
nwOutline.POV: 100,
|
328
|
+
nwOutline.FOCUS: 100,
|
329
|
+
nwOutline.CHAR: 100,
|
330
|
+
nwOutline.PLOT: 100,
|
331
|
+
nwOutline.TIME: 100,
|
332
|
+
nwOutline.WORLD: 100,
|
333
|
+
nwOutline.OBJECT: 100,
|
334
|
+
nwOutline.ENTITY: 100,
|
335
|
+
nwOutline.CUSTOM: 100,
|
336
|
+
nwOutline.STORY: 100,
|
337
|
+
nwOutline.MENTION: 100,
|
338
|
+
nwOutline.SYNOP: 200,
|
332
339
|
}
|
333
340
|
|
334
341
|
DEF_HIDDEN = {
|
335
|
-
nwOutline.TITLE:
|
336
|
-
nwOutline.LEVEL:
|
337
|
-
nwOutline.LABEL:
|
338
|
-
nwOutline.LINE:
|
339
|
-
nwOutline.
|
340
|
-
nwOutline.
|
341
|
-
nwOutline.
|
342
|
-
nwOutline.
|
343
|
-
nwOutline.
|
344
|
-
nwOutline.
|
345
|
-
nwOutline.
|
346
|
-
nwOutline.
|
347
|
-
nwOutline.
|
348
|
-
nwOutline.
|
349
|
-
nwOutline.
|
350
|
-
nwOutline.
|
351
|
-
nwOutline.
|
342
|
+
nwOutline.TITLE: False,
|
343
|
+
nwOutline.LEVEL: True,
|
344
|
+
nwOutline.LABEL: False,
|
345
|
+
nwOutline.LINE: True,
|
346
|
+
nwOutline.STATUS: True,
|
347
|
+
nwOutline.CCOUNT: True,
|
348
|
+
nwOutline.WCOUNT: False,
|
349
|
+
nwOutline.PCOUNT: False,
|
350
|
+
nwOutline.POV: False,
|
351
|
+
nwOutline.FOCUS: True,
|
352
|
+
nwOutline.CHAR: False,
|
353
|
+
nwOutline.PLOT: False,
|
354
|
+
nwOutline.TIME: True,
|
355
|
+
nwOutline.WORLD: False,
|
356
|
+
nwOutline.OBJECT: True,
|
357
|
+
nwOutline.ENTITY: True,
|
358
|
+
nwOutline.CUSTOM: True,
|
359
|
+
nwOutline.STORY: True,
|
360
|
+
nwOutline.MENTION: True,
|
361
|
+
nwOutline.SYNOP: False,
|
352
362
|
}
|
353
363
|
|
354
364
|
D_HANDLE = QtUserRole
|
@@ -370,8 +380,8 @@ class GuiOutlineTree(QTreeWidget):
|
|
370
380
|
self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
371
381
|
self.setExpandsOnDoubleClick(False)
|
372
382
|
self.setDragEnabled(False)
|
373
|
-
self.itemDoubleClicked.connect(self.
|
374
|
-
self.itemSelectionChanged.connect(self.
|
383
|
+
self.itemDoubleClicked.connect(self._onItemDoubleClicked)
|
384
|
+
self.itemSelectionChanged.connect(self._onItemSelectionChanged)
|
375
385
|
|
376
386
|
self.setIconSize(SHARED.theme.baseIconSize)
|
377
387
|
self.setIndentation(0)
|
@@ -426,6 +436,11 @@ class GuiOutlineTree(QTreeWidget):
|
|
426
436
|
def hiddenColumns(self) -> dict[nwOutline, bool]:
|
427
437
|
return self._colHidden
|
428
438
|
|
439
|
+
@property
|
440
|
+
def wasRendered(self) -> bool:
|
441
|
+
"""Returns True after the Outline has been rendered once."""
|
442
|
+
return not self._firstView
|
443
|
+
|
429
444
|
##
|
430
445
|
# Methods
|
431
446
|
##
|
@@ -433,13 +448,13 @@ class GuiOutlineTree(QTreeWidget):
|
|
433
448
|
def initSettings(self) -> None:
|
434
449
|
"""Set or update outline settings."""
|
435
450
|
if CONFIG.hideVScroll:
|
436
|
-
self.setVerticalScrollBarPolicy(
|
451
|
+
self.setVerticalScrollBarPolicy(QtScrollAlwaysOff)
|
437
452
|
else:
|
438
|
-
self.setVerticalScrollBarPolicy(
|
453
|
+
self.setVerticalScrollBarPolicy(QtScrollAsNeeded)
|
439
454
|
if CONFIG.hideHScroll:
|
440
|
-
self.setHorizontalScrollBarPolicy(
|
455
|
+
self.setHorizontalScrollBarPolicy(QtScrollAlwaysOff)
|
441
456
|
else:
|
442
|
-
self.setHorizontalScrollBarPolicy(
|
457
|
+
self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
|
443
458
|
return
|
444
459
|
|
445
460
|
def clearContent(self) -> None:
|
@@ -465,8 +480,10 @@ class GuiOutlineTree(QTreeWidget):
|
|
465
480
|
|
466
481
|
return
|
467
482
|
|
468
|
-
def refreshTree(
|
469
|
-
|
483
|
+
def refreshTree(
|
484
|
+
self, rootHandle: str | None = None,
|
485
|
+
overRide: bool = False, novelChanged: bool = False
|
486
|
+
) -> None:
|
470
487
|
"""Called whenever the Outline tab is activated and controls
|
471
488
|
what data to load, and if necessary, force a rebuild of the
|
472
489
|
tree.
|
@@ -524,11 +541,10 @@ class GuiOutlineTree(QTreeWidget):
|
|
524
541
|
@pyqtSlot()
|
525
542
|
def exportOutline(self) -> None:
|
526
543
|
"""Export the outline as a CSV file."""
|
527
|
-
|
528
|
-
path
|
529
|
-
self, self.tr("Save Outline As"), str(
|
530
|
-
)
|
531
|
-
if path:
|
544
|
+
name = CONFIG.lastPath("outline") / f"{SHARED.project.data.fileSafeName}.csv"
|
545
|
+
if path := QFileDialog.getSaveFileName(
|
546
|
+
self, self.tr("Save Outline As"), str(name), formatFileFilter(["*.csv", "*"])
|
547
|
+
)[0]:
|
532
548
|
CONFIG.setLastPath("outline", path)
|
533
549
|
logger.info("Writing CSV file: %s", path)
|
534
550
|
cols = [col for col in self._treeOrder if not self._colHidden[col]]
|
@@ -546,7 +562,7 @@ class GuiOutlineTree(QTreeWidget):
|
|
546
562
|
##
|
547
563
|
|
548
564
|
@pyqtSlot("QTreeWidgetItem*", int)
|
549
|
-
def
|
565
|
+
def _onItemDoubleClicked(self, tItem: QTreeWidgetItem, tCol: int) -> None:
|
550
566
|
"""Extract the handle and line number of the title double-
|
551
567
|
clicked, and send it to the main gui class for opening in the
|
552
568
|
document editor.
|
@@ -557,14 +573,13 @@ class GuiOutlineTree(QTreeWidget):
|
|
557
573
|
return
|
558
574
|
|
559
575
|
@pyqtSlot()
|
560
|
-
def
|
576
|
+
def _onItemSelectionChanged(self) -> None:
|
561
577
|
"""Extract the handle and line number of the currently selected
|
562
578
|
title, and send it to the details panel.
|
563
579
|
"""
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
sTitle = selItems[0].data(self._colIdx[nwOutline.TITLE], self.D_TITLE)
|
580
|
+
if items := self.selectedItems():
|
581
|
+
tHandle = items[0].data(self._colIdx[nwOutline.TITLE], self.D_HANDLE)
|
582
|
+
sTitle = items[0].data(self._colIdx[nwOutline.TITLE], self.D_TITLE)
|
568
583
|
self.activeItemChanged.emit(tHandle, sTitle)
|
569
584
|
return
|
570
585
|
|
@@ -653,6 +668,7 @@ class GuiOutlineTree(QTreeWidget):
|
|
653
668
|
is fast and doesn't require a rebuild of the tree.
|
654
669
|
"""
|
655
670
|
logger.debug("Rebuilding Outline tree")
|
671
|
+
tStart = time()
|
656
672
|
self.clear()
|
657
673
|
|
658
674
|
if self._firstView:
|
@@ -681,45 +697,51 @@ class GuiOutlineTree(QTreeWidget):
|
|
681
697
|
novStruct = SHARED.project.index.novelStructure(rootHandle=rootHandle, activeOnly=True)
|
682
698
|
for _, tHandle, sTitle, novIdx in novStruct:
|
683
699
|
|
684
|
-
iLevel =
|
700
|
+
iLevel = nwStyles.H_LEVEL.get(novIdx.level, 0)
|
685
701
|
nwItem = SHARED.project.tree[tHandle]
|
686
702
|
if iLevel == 0 or nwItem is None:
|
687
703
|
continue
|
704
|
+
sLabel, sIcon = nwItem.getImportStatus()
|
688
705
|
|
689
|
-
|
706
|
+
item = QTreeWidgetItem()
|
690
707
|
hDec = SHARED.theme.getHeaderDecoration(iLevel)
|
691
708
|
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
709
|
+
item.setData(self._colIdx[nwOutline.TITLE], QtDecoration, hDec)
|
710
|
+
item.setText(self._colIdx[nwOutline.TITLE], novIdx.title)
|
711
|
+
item.setData(self._colIdx[nwOutline.TITLE], self.D_HANDLE, tHandle)
|
712
|
+
item.setData(self._colIdx[nwOutline.TITLE], self.D_TITLE, sTitle)
|
713
|
+
item.setFont(self._colIdx[nwOutline.TITLE], self._hFonts[iLevel])
|
714
|
+
item.setText(self._colIdx[nwOutline.LEVEL], novIdx.level)
|
715
|
+
item.setIcon(self._colIdx[nwOutline.LABEL], self._dIcon[nwItem.mainHeading])
|
716
|
+
item.setText(self._colIdx[nwOutline.LABEL], nwItem.itemName)
|
717
|
+
item.setText(self._colIdx[nwOutline.LINE], f"{novIdx.line:n}")
|
718
|
+
item.setText(self._colIdx[nwOutline.STATUS], sLabel)
|
719
|
+
item.setIcon(self._colIdx[nwOutline.STATUS], sIcon)
|
720
|
+
item.setText(self._colIdx[nwOutline.SYNOP], novIdx.synopsis)
|
721
|
+
item.setText(self._colIdx[nwOutline.CCOUNT], f"{novIdx.charCount:n}")
|
722
|
+
item.setText(self._colIdx[nwOutline.WCOUNT], f"{novIdx.wordCount:n}")
|
723
|
+
item.setText(self._colIdx[nwOutline.PCOUNT], f"{novIdx.paraCount:n}")
|
724
|
+
item.setTextAlignment(self._colIdx[nwOutline.CCOUNT], QtAlignRight)
|
725
|
+
item.setTextAlignment(self._colIdx[nwOutline.WCOUNT], QtAlignRight)
|
726
|
+
item.setTextAlignment(self._colIdx[nwOutline.PCOUNT], QtAlignRight)
|
708
727
|
|
709
728
|
refs = SHARED.project.index.getReferences(tHandle, sTitle)
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
self.
|
729
|
+
item.setText(self._colIdx[nwOutline.POV], ", ".join(refs[nwKeyWords.POV_KEY]))
|
730
|
+
item.setText(self._colIdx[nwOutline.FOCUS], ", ".join(refs[nwKeyWords.FOCUS_KEY]))
|
731
|
+
item.setText(self._colIdx[nwOutline.CHAR], ", ".join(refs[nwKeyWords.CHAR_KEY]))
|
732
|
+
item.setText(self._colIdx[nwOutline.PLOT], ", ".join(refs[nwKeyWords.PLOT_KEY]))
|
733
|
+
item.setText(self._colIdx[nwOutline.TIME], ", ".join(refs[nwKeyWords.TIME_KEY]))
|
734
|
+
item.setText(self._colIdx[nwOutline.WORLD], ", ".join(refs[nwKeyWords.WORLD_KEY]))
|
735
|
+
item.setText(self._colIdx[nwOutline.OBJECT], ", ".join(refs[nwKeyWords.OBJECT_KEY]))
|
736
|
+
item.setText(self._colIdx[nwOutline.ENTITY], ", ".join(refs[nwKeyWords.ENTITY_KEY]))
|
737
|
+
item.setText(self._colIdx[nwOutline.CUSTOM], ", ".join(refs[nwKeyWords.CUSTOM_KEY]))
|
738
|
+
item.setText(self._colIdx[nwOutline.STORY], ", ".join(refs[nwKeyWords.STORY_KEY]))
|
739
|
+
item.setText(self._colIdx[nwOutline.MENTION], ", ".join(refs[nwKeyWords.MENTION_KEY]))
|
740
|
+
|
741
|
+
self.addTopLevelItem(item)
|
721
742
|
|
722
743
|
self._lastBuild = time()
|
744
|
+
logger.debug("Project outline built in %.3f ms", 1000.0*(time() - tStart))
|
723
745
|
|
724
746
|
return
|
725
747
|
|
@@ -793,6 +815,10 @@ class GuiOutlineDetails(QScrollArea):
|
|
793
815
|
|
794
816
|
bFont = SHARED.theme.guiFontB
|
795
817
|
|
818
|
+
trStats1 = trConst(nwLabels.STATS_NAME[nwStats.CHARS])
|
819
|
+
trStats2 = trConst(nwLabels.STATS_NAME[nwStats.WORDS])
|
820
|
+
trStats3 = trConst(nwLabels.STATS_NAME[nwStats.PARAGRAPHS])
|
821
|
+
|
796
822
|
# Details Area
|
797
823
|
self.titleLabel = QLabel(self.tr("Title"), self)
|
798
824
|
self.fileLabel = QLabel(self.tr("Document"), self)
|
@@ -813,9 +839,9 @@ class GuiOutlineDetails(QScrollArea):
|
|
813
839
|
self.itemValue.setMaximumWidth(maxTitle)
|
814
840
|
|
815
841
|
# Stats Area
|
816
|
-
self.cCLabel = QLabel(
|
817
|
-
self.wCLabel = QLabel(
|
818
|
-
self.pCLabel = QLabel(
|
842
|
+
self.cCLabel = QLabel(trStats1, self)
|
843
|
+
self.wCLabel = QLabel(trStats2, self)
|
844
|
+
self.pCLabel = QLabel(trStats3, self)
|
819
845
|
self.cCValue = QLabel("", self)
|
820
846
|
self.wCValue = QLabel("", self)
|
821
847
|
self.pCValue = QLabel("", self)
|
@@ -842,96 +868,25 @@ class GuiOutlineDetails(QScrollArea):
|
|
842
868
|
self.synopLWrap = QHBoxLayout()
|
843
869
|
self.synopLWrap.addWidget(self.synopValue, 1)
|
844
870
|
|
845
|
-
# Tags
|
846
|
-
self.povKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY]), self)
|
847
|
-
self.focKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY]), self)
|
848
|
-
self.chrKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.CHAR_KEY]), self)
|
849
|
-
self.pltKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY]), self)
|
850
|
-
self.timKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.TIME_KEY]), self)
|
851
|
-
self.wldKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.WORLD_KEY]), self)
|
852
|
-
self.objKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.OBJECT_KEY]), self)
|
853
|
-
self.entKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.ENTITY_KEY]), self)
|
854
|
-
self.cstKeyLabel = QLabel(trConst(nwLabels.KEY_NAME[nwKeyWords.CUSTOM_KEY]), self)
|
855
|
-
|
856
|
-
self.povKeyLabel.setFont(bFont)
|
857
|
-
self.focKeyLabel.setFont(bFont)
|
858
|
-
self.chrKeyLabel.setFont(bFont)
|
859
|
-
self.pltKeyLabel.setFont(bFont)
|
860
|
-
self.timKeyLabel.setFont(bFont)
|
861
|
-
self.wldKeyLabel.setFont(bFont)
|
862
|
-
self.objKeyLabel.setFont(bFont)
|
863
|
-
self.entKeyLabel.setFont(bFont)
|
864
|
-
self.cstKeyLabel.setFont(bFont)
|
865
|
-
|
866
|
-
self.povKeyLWrap = QHBoxLayout()
|
867
|
-
self.focKeyLWrap = QHBoxLayout()
|
868
|
-
self.chrKeyLWrap = QHBoxLayout()
|
869
|
-
self.pltKeyLWrap = QHBoxLayout()
|
870
|
-
self.timKeyLWrap = QHBoxLayout()
|
871
|
-
self.wldKeyLWrap = QHBoxLayout()
|
872
|
-
self.objKeyLWrap = QHBoxLayout()
|
873
|
-
self.entKeyLWrap = QHBoxLayout()
|
874
|
-
self.cstKeyLWrap = QHBoxLayout()
|
875
|
-
|
876
|
-
self.povKeyValue = QLabel("", self)
|
877
|
-
self.focKeyValue = QLabel("", self)
|
878
|
-
self.chrKeyValue = QLabel("", self)
|
879
|
-
self.pltKeyValue = QLabel("", self)
|
880
|
-
self.timKeyValue = QLabel("", self)
|
881
|
-
self.wldKeyValue = QLabel("", self)
|
882
|
-
self.objKeyValue = QLabel("", self)
|
883
|
-
self.entKeyValue = QLabel("", self)
|
884
|
-
self.cstKeyValue = QLabel("", self)
|
885
|
-
|
886
|
-
self.povKeyValue.setWordWrap(True)
|
887
|
-
self.focKeyValue.setWordWrap(True)
|
888
|
-
self.chrKeyValue.setWordWrap(True)
|
889
|
-
self.pltKeyValue.setWordWrap(True)
|
890
|
-
self.timKeyValue.setWordWrap(True)
|
891
|
-
self.wldKeyValue.setWordWrap(True)
|
892
|
-
self.objKeyValue.setWordWrap(True)
|
893
|
-
self.entKeyValue.setWordWrap(True)
|
894
|
-
self.cstKeyValue.setWordWrap(True)
|
895
|
-
|
896
|
-
self.povKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
|
897
|
-
self.focKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
|
898
|
-
self.chrKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
|
899
|
-
self.pltKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
|
900
|
-
self.timKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
|
901
|
-
self.wldKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
|
902
|
-
self.objKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
|
903
|
-
self.entKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
|
904
|
-
self.cstKeyValue.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
|
905
|
-
|
906
|
-
self.povKeyLWrap.addWidget(self.povKeyValue, 1)
|
907
|
-
self.focKeyLWrap.addWidget(self.focKeyValue, 1)
|
908
|
-
self.chrKeyLWrap.addWidget(self.chrKeyValue, 1)
|
909
|
-
self.pltKeyLWrap.addWidget(self.pltKeyValue, 1)
|
910
|
-
self.timKeyLWrap.addWidget(self.timKeyValue, 1)
|
911
|
-
self.wldKeyLWrap.addWidget(self.wldKeyValue, 1)
|
912
|
-
self.objKeyLWrap.addWidget(self.objKeyValue, 1)
|
913
|
-
self.entKeyLWrap.addWidget(self.entKeyValue, 1)
|
914
|
-
self.cstKeyLWrap.addWidget(self.cstKeyValue, 1)
|
915
|
-
|
916
871
|
# Selected Item Details
|
917
|
-
self.mainGroup = QGroupBox(self.tr("Title Details"), self)
|
918
872
|
self.mainForm = QGridLayout()
|
873
|
+
self.mainGroup = QGroupBox(self.tr("Title Details"), self)
|
919
874
|
self.mainGroup.setLayout(self.mainForm)
|
920
875
|
|
921
|
-
self.mainForm.addWidget(self.titleLabel,
|
922
|
-
self.mainForm.addWidget(self.titleValue,
|
923
|
-
self.mainForm.addWidget(self.cCLabel,
|
924
|
-
self.mainForm.addWidget(self.cCValue,
|
925
|
-
self.mainForm.addWidget(self.fileLabel,
|
926
|
-
self.mainForm.addWidget(self.fileValue,
|
927
|
-
self.mainForm.addWidget(self.wCLabel,
|
928
|
-
self.mainForm.addWidget(self.wCValue,
|
929
|
-
self.mainForm.addWidget(self.itemLabel,
|
930
|
-
self.mainForm.addWidget(self.itemValue,
|
931
|
-
self.mainForm.addWidget(self.pCLabel,
|
932
|
-
self.mainForm.addWidget(self.pCValue,
|
933
|
-
self.mainForm.addWidget(self.synopLabel,
|
934
|
-
self.mainForm.addLayout(self.synopLWrap,
|
876
|
+
self.mainForm.addWidget(self.titleLabel, 0, 0, 1, 1, QtAlignLeftTop)
|
877
|
+
self.mainForm.addWidget(self.titleValue, 0, 1, 1, 1, QtAlignLeftTop)
|
878
|
+
self.mainForm.addWidget(self.cCLabel, 0, 2, 1, 1, QtAlignLeftTop)
|
879
|
+
self.mainForm.addWidget(self.cCValue, 0, 3, 1, 1, QtAlignRightTop)
|
880
|
+
self.mainForm.addWidget(self.fileLabel, 1, 0, 1, 1, QtAlignLeftTop)
|
881
|
+
self.mainForm.addWidget(self.fileValue, 1, 1, 1, 1, QtAlignLeftTop)
|
882
|
+
self.mainForm.addWidget(self.wCLabel, 1, 2, 1, 1, QtAlignLeftTop)
|
883
|
+
self.mainForm.addWidget(self.wCValue, 1, 3, 1, 1, QtAlignRightTop)
|
884
|
+
self.mainForm.addWidget(self.itemLabel, 2, 0, 1, 1, QtAlignLeftTop)
|
885
|
+
self.mainForm.addWidget(self.itemValue, 2, 1, 1, 1, QtAlignLeftTop)
|
886
|
+
self.mainForm.addWidget(self.pCLabel, 2, 2, 1, 1, QtAlignLeftTop)
|
887
|
+
self.mainForm.addWidget(self.pCValue, 2, 3, 1, 1, QtAlignRightTop)
|
888
|
+
self.mainForm.addWidget(self.synopLabel, 3, 0, 1, 4, QtAlignLeftTop)
|
889
|
+
self.mainForm.addLayout(self.synopLWrap, 4, 0, 1, 4, QtAlignLeftTop)
|
935
890
|
|
936
891
|
self.mainForm.setColumnStretch(1, 1)
|
937
892
|
self.mainForm.setRowStretch(4, 1)
|
@@ -939,45 +894,40 @@ class GuiOutlineDetails(QScrollArea):
|
|
939
894
|
self.mainForm.setVerticalSpacing(vSpace)
|
940
895
|
|
941
896
|
# Selected Item Tags
|
942
|
-
self.tagsGroup = QGroupBox(self.tr("Reference Tags"), self)
|
943
897
|
self.tagsForm = QGridLayout()
|
898
|
+
self.tagsGroup = QGroupBox(self.tr("Reference Tags"), self)
|
944
899
|
self.tagsGroup.setLayout(self.tagsForm)
|
945
900
|
|
946
|
-
self.
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
self.tagsForm.addLayout(self.objKeyLWrap, 6, 1, 1, 1, QtAlignLeftTop)
|
960
|
-
self.tagsForm.addWidget(self.entKeyLabel, 7, 0, 1, 1, QtAlignLeftTop)
|
961
|
-
self.tagsForm.addLayout(self.entKeyLWrap, 7, 1, 1, 1, QtAlignLeftTop)
|
962
|
-
self.tagsForm.addWidget(self.cstKeyLabel, 8, 0, 1, 1, QtAlignLeftTop)
|
963
|
-
self.tagsForm.addLayout(self.cstKeyLWrap, 8, 1, 1, 1, QtAlignLeftTop)
|
901
|
+
self.tagValues: dict[str, tuple[QLabel, QLabel]] = {}
|
902
|
+
for key in nwKeyWords.ALL_KEYS:
|
903
|
+
label = QLabel(trConst(nwLabels.KEY_NAME[key]), self)
|
904
|
+
label.setFont(bFont)
|
905
|
+
value = QLabel("", self)
|
906
|
+
value.setWordWrap(True)
|
907
|
+
value.linkActivated.connect(lambda x: self.itemTagClicked.emit(x))
|
908
|
+
layout = QHBoxLayout()
|
909
|
+
layout.addWidget(value, 1)
|
910
|
+
n = len(self.tagValues)
|
911
|
+
self.tagsForm.addWidget(label, n, 0, QtAlignLeftTop)
|
912
|
+
self.tagsForm.addLayout(layout, n, 1, QtAlignLeftTop)
|
913
|
+
self.tagValues[key] = (label, value)
|
964
914
|
|
965
915
|
self.tagsForm.setColumnStretch(1, 1)
|
966
|
-
self.tagsForm.setRowStretch(
|
916
|
+
self.tagsForm.setRowStretch(len(self.tagValues), 1)
|
967
917
|
self.tagsForm.setHorizontalSpacing(hSpace)
|
968
918
|
self.tagsForm.setVerticalSpacing(vSpace)
|
969
919
|
|
970
920
|
# Assemble
|
971
|
-
self.
|
972
|
-
self.
|
973
|
-
self.
|
974
|
-
self.
|
921
|
+
self.mainSplit = QSplitter(Qt.Orientation.Horizontal)
|
922
|
+
self.mainSplit.addWidget(self.mainGroup)
|
923
|
+
self.mainSplit.addWidget(self.tagsGroup)
|
924
|
+
self.mainSplit.setCollapsible(0, False)
|
925
|
+
self.mainSplit.setCollapsible(1, False)
|
975
926
|
|
976
|
-
self.
|
977
|
-
self.setWidget(self.outerWidget)
|
927
|
+
self.setWidget(self.mainSplit)
|
978
928
|
|
979
|
-
self.setHorizontalScrollBarPolicy(
|
980
|
-
self.setVerticalScrollBarPolicy(
|
929
|
+
self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
|
930
|
+
self.setVerticalScrollBarPolicy(QtScrollAsNeeded)
|
981
931
|
self.setWidgetResizable(True)
|
982
932
|
self.setFrameStyle(QFrame.Shape.NoFrame)
|
983
933
|
|
@@ -990,35 +940,53 @@ class GuiOutlineDetails(QScrollArea):
|
|
990
940
|
def initSettings(self) -> None:
|
991
941
|
"""Set or update outline settings."""
|
992
942
|
if CONFIG.hideVScroll:
|
993
|
-
self.setVerticalScrollBarPolicy(
|
943
|
+
self.setVerticalScrollBarPolicy(QtScrollAlwaysOff)
|
994
944
|
else:
|
995
|
-
self.setVerticalScrollBarPolicy(
|
945
|
+
self.setVerticalScrollBarPolicy(QtScrollAsNeeded)
|
996
946
|
if CONFIG.hideHScroll:
|
997
|
-
self.setHorizontalScrollBarPolicy(
|
947
|
+
self.setHorizontalScrollBarPolicy(QtScrollAlwaysOff)
|
998
948
|
else:
|
999
|
-
self.setHorizontalScrollBarPolicy(
|
949
|
+
self.setHorizontalScrollBarPolicy(QtScrollAsNeeded)
|
1000
950
|
self.updateClasses()
|
1001
951
|
return
|
1002
952
|
|
953
|
+
def loadGuiSettings(self) -> None:
|
954
|
+
"""Run open project tasks."""
|
955
|
+
parent = self.outlineView.parent() # This widget is rendered already
|
956
|
+
width = parent.width() if isinstance(parent, QWidget) else 1000
|
957
|
+
pOptions = SHARED.project.options
|
958
|
+
self.mainSplit.setSizes([
|
959
|
+
CONFIG.pxInt(pOptions.getInt("GuiOutlineDetails", "detailsWidth", width//3)),
|
960
|
+
CONFIG.pxInt(pOptions.getInt("GuiOutlineDetails", "tagsWidth", 2*width//3))
|
961
|
+
])
|
962
|
+
return
|
963
|
+
|
964
|
+
def saveGuiSettings(self) -> None:
|
965
|
+
"""Run close project tasks."""
|
966
|
+
mainSplit = self.mainSplit.sizes()
|
967
|
+
detailsWidth = CONFIG.rpxInt(mainSplit[0])
|
968
|
+
tagsWidth = CONFIG.rpxInt(mainSplit[1])
|
969
|
+
|
970
|
+
logger.debug("Saving State: GuiOutlineDetails")
|
971
|
+
pOptions = SHARED.project.options
|
972
|
+
pOptions.setValue("GuiOutlineDetails", "detailsWidth", detailsWidth)
|
973
|
+
pOptions.setValue("GuiOutlineDetails", "tagsWidth", tagsWidth)
|
974
|
+
return
|
975
|
+
|
1003
976
|
def clearDetails(self) -> None:
|
1004
977
|
"""Clear all the data labels."""
|
1005
978
|
self.titleLabel.setText(self.tr("Title"))
|
1006
|
-
self.titleValue.
|
1007
|
-
self.fileValue.
|
1008
|
-
self.itemValue.
|
1009
|
-
self.cCValue.
|
1010
|
-
self.wCValue.
|
1011
|
-
self.pCValue.
|
1012
|
-
self.synopValue.
|
1013
|
-
|
1014
|
-
self.
|
1015
|
-
|
1016
|
-
|
1017
|
-
self.timKeyValue.setText("")
|
1018
|
-
self.wldKeyValue.setText("")
|
1019
|
-
self.objKeyValue.setText("")
|
1020
|
-
self.entKeyValue.setText("")
|
1021
|
-
self.cstKeyValue.setText("")
|
979
|
+
self.titleValue.clear()
|
980
|
+
self.fileValue.clear()
|
981
|
+
self.itemValue.clear()
|
982
|
+
self.cCValue.clear()
|
983
|
+
self.wCValue.clear()
|
984
|
+
self.pCValue.clear()
|
985
|
+
self.synopValue.clear()
|
986
|
+
|
987
|
+
for _, value in self.tagValues.values():
|
988
|
+
value.clear()
|
989
|
+
|
1022
990
|
self.updateClasses()
|
1023
991
|
return
|
1024
992
|
|
@@ -1050,15 +1018,8 @@ class GuiOutlineDetails(QScrollArea):
|
|
1050
1018
|
|
1051
1019
|
self.synopValue.setText(novIdx.synopsis)
|
1052
1020
|
|
1053
|
-
self.
|
1054
|
-
|
1055
|
-
self.chrKeyValue.setText(self._formatTags(novRefs, nwKeyWords.CHAR_KEY))
|
1056
|
-
self.pltKeyValue.setText(self._formatTags(novRefs, nwKeyWords.PLOT_KEY))
|
1057
|
-
self.timKeyValue.setText(self._formatTags(novRefs, nwKeyWords.TIME_KEY))
|
1058
|
-
self.wldKeyValue.setText(self._formatTags(novRefs, nwKeyWords.WORLD_KEY))
|
1059
|
-
self.objKeyValue.setText(self._formatTags(novRefs, nwKeyWords.OBJECT_KEY))
|
1060
|
-
self.entKeyValue.setText(self._formatTags(novRefs, nwKeyWords.ENTITY_KEY))
|
1061
|
-
self.cstKeyValue.setText(self._formatTags(novRefs, nwKeyWords.CUSTOM_KEY))
|
1021
|
+
for key, (_, value) in self.tagValues.items():
|
1022
|
+
value.setText(self._formatTags(novRefs, key))
|
1062
1023
|
|
1063
1024
|
return
|
1064
1025
|
|
@@ -1066,27 +1027,12 @@ class GuiOutlineDetails(QScrollArea):
|
|
1066
1027
|
def updateClasses(self) -> None:
|
1067
1028
|
"""Update the visibility status of class details."""
|
1068
1029
|
usedClasses = SHARED.project.tree.rootClasses()
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
cstVisible = nwItemClass.CUSTOM in usedClasses
|
1076
|
-
|
1077
|
-
self.pltKeyLabel.setVisible(pltVisible)
|
1078
|
-
self.pltKeyValue.setVisible(pltVisible)
|
1079
|
-
self.timKeyLabel.setVisible(timVisible)
|
1080
|
-
self.timKeyValue.setVisible(timVisible)
|
1081
|
-
self.wldKeyLabel.setVisible(wldVisible)
|
1082
|
-
self.wldKeyValue.setVisible(wldVisible)
|
1083
|
-
self.objKeyLabel.setVisible(objVisible)
|
1084
|
-
self.objKeyValue.setVisible(objVisible)
|
1085
|
-
self.entKeyLabel.setVisible(entVisible)
|
1086
|
-
self.entKeyValue.setVisible(entVisible)
|
1087
|
-
self.cstKeyLabel.setVisible(cstVisible)
|
1088
|
-
self.cstKeyValue.setVisible(cstVisible)
|
1089
|
-
|
1030
|
+
for key, itemClass in nwKeyWords.KEY_CLASS.items():
|
1031
|
+
visible = itemClass in usedClasses
|
1032
|
+
if key in self.tagValues:
|
1033
|
+
label, value = self.tagValues[key]
|
1034
|
+
label.setVisible(visible)
|
1035
|
+
value.setVisible(visible)
|
1090
1036
|
return
|
1091
1037
|
|
1092
1038
|
@staticmethod
|