novelWriter 2.4.3__py3-none-any.whl → 2.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {novelWriter-2.4.3.dist-info → novelWriter-2.5.dist-info}/METADATA +4 -5
- {novelWriter-2.4.3.dist-info → novelWriter-2.5.dist-info}/RECORD +122 -112
- {novelWriter-2.4.3.dist-info → novelWriter-2.5.dist-info}/WHEEL +1 -1
- novelwriter/__init__.py +33 -39
- novelwriter/assets/i18n/nw_de_DE.qm +0 -0
- novelwriter/assets/i18n/nw_en_US.qm +0 -0
- novelwriter/assets/i18n/nw_es_419.qm +0 -0
- novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
- novelwriter/assets/i18n/nw_it_IT.qm +0 -0
- novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
- novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
- novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
- novelwriter/assets/i18n/nw_pl_PL.qm +0 -0
- novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
- novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
- novelwriter/assets/i18n/project_en_GB.json +1 -0
- novelwriter/assets/i18n/project_pl_PL.json +116 -0
- novelwriter/assets/i18n/project_pt_BR.json +74 -74
- novelwriter/assets/icons/typicons_dark/icons.conf +2 -0
- novelwriter/assets/icons/typicons_dark/nw_font.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_quote.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +2 -0
- novelwriter/assets/icons/typicons_light/nw_font.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_quote.svg +4 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/syntax/cyberpunk_night.conf +5 -3
- novelwriter/assets/syntax/default_dark.conf +32 -18
- novelwriter/assets/syntax/default_light.conf +24 -10
- novelwriter/assets/syntax/dracula.conf +44 -0
- novelwriter/assets/syntax/grey_dark.conf +5 -4
- novelwriter/assets/syntax/grey_light.conf +5 -4
- novelwriter/assets/syntax/light_owl.conf +7 -6
- novelwriter/assets/syntax/night_owl.conf +7 -6
- novelwriter/assets/syntax/snazzy.conf +42 -0
- novelwriter/assets/syntax/solarized_dark.conf +4 -3
- novelwriter/assets/syntax/solarized_light.conf +4 -3
- novelwriter/assets/syntax/tango.conf +27 -11
- novelwriter/assets/syntax/tomorrow.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night.conf +7 -6
- novelwriter/assets/syntax/tomorrow_night_blue.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night_bright.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night_eighties.conf +6 -5
- novelwriter/assets/text/credits_en.htm +52 -41
- novelwriter/assets/themes/cyberpunk_night.conf +3 -0
- novelwriter/assets/themes/default_dark.conf +2 -0
- novelwriter/assets/themes/default_light.conf +2 -0
- novelwriter/assets/themes/dracula.conf +48 -0
- novelwriter/assets/themes/solarized_dark.conf +2 -0
- novelwriter/assets/themes/solarized_light.conf +2 -0
- novelwriter/common.py +33 -12
- novelwriter/config.py +184 -98
- novelwriter/constants.py +47 -35
- novelwriter/core/buildsettings.py +68 -69
- novelwriter/core/coretools.py +5 -23
- novelwriter/core/docbuild.py +52 -40
- novelwriter/core/document.py +3 -5
- novelwriter/core/index.py +115 -45
- novelwriter/core/item.py +8 -19
- novelwriter/core/options.py +2 -4
- novelwriter/core/project.py +37 -61
- novelwriter/core/projectdata.py +1 -3
- novelwriter/core/projectxml.py +12 -15
- novelwriter/core/sessions.py +3 -5
- novelwriter/core/spellcheck.py +4 -9
- novelwriter/core/status.py +211 -164
- novelwriter/core/storage.py +0 -8
- novelwriter/core/tohtml.py +139 -105
- novelwriter/core/tokenizer.py +278 -122
- novelwriter/core/{tomd.py → tomarkdown.py} +97 -78
- novelwriter/core/toodt.py +257 -166
- novelwriter/core/toqdoc.py +419 -0
- novelwriter/core/tree.py +5 -7
- novelwriter/dialogs/about.py +11 -18
- novelwriter/dialogs/docmerge.py +17 -19
- novelwriter/dialogs/docsplit.py +17 -19
- novelwriter/dialogs/editlabel.py +6 -10
- novelwriter/dialogs/preferences.py +200 -164
- novelwriter/dialogs/projectsettings.py +225 -189
- novelwriter/dialogs/quotes.py +12 -9
- novelwriter/dialogs/wordlist.py +9 -15
- novelwriter/enum.py +35 -30
- novelwriter/error.py +8 -15
- novelwriter/extensions/configlayout.py +55 -21
- novelwriter/extensions/eventfilters.py +1 -5
- novelwriter/extensions/modified.py +70 -14
- novelwriter/extensions/novelselector.py +1 -3
- novelwriter/extensions/pagedsidebar.py +9 -12
- novelwriter/extensions/{circularprogress.py → progressbars.py} +30 -8
- novelwriter/extensions/statusled.py +40 -26
- novelwriter/extensions/switch.py +4 -6
- novelwriter/extensions/switchbox.py +7 -6
- novelwriter/extensions/versioninfo.py +3 -9
- novelwriter/gui/doceditor.py +120 -139
- novelwriter/gui/dochighlight.py +231 -186
- novelwriter/gui/docviewer.py +69 -108
- novelwriter/gui/docviewerpanel.py +3 -10
- novelwriter/gui/editordocument.py +1 -3
- novelwriter/gui/itemdetails.py +7 -11
- novelwriter/gui/mainmenu.py +22 -18
- novelwriter/gui/noveltree.py +11 -24
- novelwriter/gui/outline.py +15 -26
- novelwriter/gui/projtree.py +39 -65
- novelwriter/gui/search.py +10 -3
- novelwriter/gui/sidebar.py +2 -6
- novelwriter/gui/statusbar.py +29 -37
- novelwriter/gui/theme.py +26 -48
- novelwriter/guimain.py +162 -160
- novelwriter/shared.py +36 -19
- novelwriter/text/patterns.py +113 -0
- novelwriter/tools/dictionaries.py +10 -20
- novelwriter/tools/lipsum.py +10 -16
- novelwriter/tools/manusbuild.py +9 -11
- novelwriter/tools/manuscript.py +75 -149
- novelwriter/tools/manussettings.py +74 -76
- novelwriter/tools/noveldetails.py +16 -21
- novelwriter/tools/welcome.py +21 -26
- novelwriter/tools/writingstats.py +9 -12
- novelwriter/types.py +49 -4
- novelwriter/extensions/simpleprogress.py +0 -55
- {novelWriter-2.4.3.dist-info → novelWriter-2.5.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.4.3.dist-info → novelWriter-2.5.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.4.3.dist-info → novelWriter-2.5.dist-info}/top_level.txt +0 -0
novelwriter/gui/outline.py
CHANGED
@@ -30,30 +30,28 @@ from __future__ import annotations
|
|
30
30
|
import csv
|
31
31
|
import logging
|
32
32
|
|
33
|
-
from time import time
|
34
33
|
from enum import Enum
|
34
|
+
from time import time
|
35
35
|
|
36
|
-
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
36
|
+
from PyQt5.QtCore import QT_TRANSLATE_NOOP, Qt, pyqtSignal, pyqtSlot
|
37
37
|
from PyQt5.QtWidgets import (
|
38
38
|
QAbstractItemView, QAction, QFileDialog, QFrame, QGridLayout, QGroupBox,
|
39
|
-
QHBoxLayout, QLabel, QMenu, QScrollArea,
|
40
|
-
|
39
|
+
QHBoxLayout, QLabel, QMenu, QScrollArea, QSplitter, QToolBar, QToolButton,
|
40
|
+
QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
|
41
41
|
)
|
42
42
|
|
43
43
|
from novelwriter import CONFIG, SHARED
|
44
|
-
from novelwriter.enum import (
|
45
|
-
nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline
|
46
|
-
)
|
47
|
-
from novelwriter.error import logException
|
48
44
|
from novelwriter.common import checkInt, formatFileFilter, makeFileNameSafe
|
49
|
-
from novelwriter.constants import nwHeaders,
|
45
|
+
from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst
|
46
|
+
from novelwriter.enum import nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline
|
47
|
+
from novelwriter.error import logException
|
50
48
|
from novelwriter.extensions.configlayout import NColourLabel
|
51
49
|
from novelwriter.extensions.novelselector import NovelSelector
|
52
50
|
from novelwriter.types import (
|
53
|
-
QtAlignLeftTop, QtAlignRight, QtAlignRightTop, QtDecoration,
|
51
|
+
QtAlignLeftTop, QtAlignRight, QtAlignRightTop, QtDecoration,
|
52
|
+
QtSizeExpanding, QtUserRole
|
54
53
|
)
|
55
54
|
|
56
|
-
|
57
55
|
logger = logging.getLogger(__name__)
|
58
56
|
|
59
57
|
|
@@ -196,8 +194,6 @@ class GuiOutlineView(QWidget):
|
|
196
194
|
self.outlineTree.refreshTree(rootHandle=(tHandle or None), overRide=True)
|
197
195
|
return
|
198
196
|
|
199
|
-
# END Class GuiOutlineView
|
200
|
-
|
201
197
|
|
202
198
|
class GuiOutlineToolBar(QToolBar):
|
203
199
|
|
@@ -215,11 +211,11 @@ class GuiOutlineToolBar(QToolBar):
|
|
215
211
|
self.setContentsMargins(0, 0, 0, 0)
|
216
212
|
|
217
213
|
stretch = QWidget(self)
|
218
|
-
stretch.setSizePolicy(
|
214
|
+
stretch.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
|
219
215
|
|
220
216
|
# Novel Selector
|
221
217
|
self.novelLabel = NColourLabel(
|
222
|
-
self.tr("Outline of"),
|
218
|
+
self.tr("Outline of"), self, scale=NColourLabel.HEADER_SCALE, bold=True
|
223
219
|
)
|
224
220
|
self.novelLabel.setContentsMargins(0, 0, CONFIG.pxInt(12), 0)
|
225
221
|
|
@@ -272,6 +268,7 @@ class GuiOutlineToolBar(QToolBar):
|
|
272
268
|
self.aExport.setIcon(SHARED.theme.getIcon("export"))
|
273
269
|
self.tbColumns.setIcon(SHARED.theme.getIcon("menu"))
|
274
270
|
self.tbColumns.setStyleSheet("QToolButton::menu-indicator {image: none;}")
|
271
|
+
self.novelLabel.setTextColors(color=self.palette().windowText().color())
|
275
272
|
return
|
276
273
|
|
277
274
|
def populateNovelList(self) -> None:
|
@@ -311,8 +308,6 @@ class GuiOutlineToolBar(QToolBar):
|
|
311
308
|
self.outlineExportRequest.emit()
|
312
309
|
return
|
313
310
|
|
314
|
-
# END Class GuiOutlineToolBar
|
315
|
-
|
316
311
|
|
317
312
|
class GuiOutlineTree(QTreeWidget):
|
318
313
|
|
@@ -529,12 +524,12 @@ class GuiOutlineTree(QTreeWidget):
|
|
529
524
|
@pyqtSlot()
|
530
525
|
def exportOutline(self) -> None:
|
531
526
|
"""Export the outline as a CSV file."""
|
532
|
-
path = CONFIG.lastPath() / f"{makeFileNameSafe(SHARED.project.data.name)}.csv"
|
527
|
+
path = CONFIG.lastPath("outline") / f"{makeFileNameSafe(SHARED.project.data.name)}.csv"
|
533
528
|
path, _ = QFileDialog.getSaveFileName(
|
534
529
|
self, self.tr("Save Outline As"), str(path), formatFileFilter(["*.csv", "*"])
|
535
530
|
)
|
536
531
|
if path:
|
537
|
-
CONFIG.setLastPath(path)
|
532
|
+
CONFIG.setLastPath("outline", path)
|
538
533
|
logger.info("Writing CSV file: %s", path)
|
539
534
|
cols = [col for col in self._treeOrder if not self._colHidden[col]]
|
540
535
|
order = [self._colIdx[col] for col in cols]
|
@@ -728,8 +723,6 @@ class GuiOutlineTree(QTreeWidget):
|
|
728
723
|
|
729
724
|
return
|
730
725
|
|
731
|
-
# END Class GuiOutlineTree
|
732
|
-
|
733
726
|
|
734
727
|
class GuiOutlineHeaderMenu(QMenu):
|
735
728
|
|
@@ -772,8 +765,6 @@ class GuiOutlineHeaderMenu(QMenu):
|
|
772
765
|
|
773
766
|
return
|
774
767
|
|
775
|
-
# END Class GuiOutlineHeaderMenu
|
776
|
-
|
777
768
|
|
778
769
|
class GuiOutlineDetails(QScrollArea):
|
779
770
|
|
@@ -1048,7 +1039,7 @@ class GuiOutlineDetails(QScrollArea):
|
|
1048
1039
|
self.titleLabel.setText(self.tr(self.LVL_MAP.get(novIdx.level, "H1")))
|
1049
1040
|
self.titleValue.setText(novIdx.title)
|
1050
1041
|
|
1051
|
-
itemStatus, _ = nwItem.getImportStatus(
|
1042
|
+
itemStatus, _ = nwItem.getImportStatus()
|
1052
1043
|
|
1053
1044
|
self.fileValue.setText(nwItem.itemName)
|
1054
1045
|
self.itemValue.setText(itemStatus)
|
@@ -1104,5 +1095,3 @@ class GuiOutlineDetails(QScrollArea):
|
|
1104
1095
|
return ", ".join(
|
1105
1096
|
[f"<a href='{tag}'>{tag}</a>" for tag in refs.get(key, [])]
|
1106
1097
|
)
|
1107
|
-
|
1108
|
-
# END Class GuiOutlineDetails
|
novelwriter/gui/projtree.py
CHANGED
@@ -30,34 +30,30 @@ import logging
|
|
30
30
|
|
31
31
|
from enum import Enum
|
32
32
|
from time import time
|
33
|
-
from typing import TYPE_CHECKING
|
34
33
|
|
35
|
-
from PyQt5.QtCore import QPoint,
|
36
|
-
from PyQt5.QtGui import
|
37
|
-
QDragEnterEvent, QDragMoveEvent, QDropEvent, QIcon, QMouseEvent, QPalette
|
38
|
-
)
|
34
|
+
from PyQt5.QtCore import QPoint, Qt, QTimer, pyqtSignal, pyqtSlot
|
35
|
+
from PyQt5.QtGui import QDragEnterEvent, QDragMoveEvent, QDropEvent, QIcon, QMouseEvent, QPalette
|
39
36
|
from PyQt5.QtWidgets import (
|
40
|
-
QAbstractItemView, QAction,
|
41
|
-
|
42
|
-
QVBoxLayout, QWidget
|
37
|
+
QAbstractItemView, QAction, QFrame, QHBoxLayout, QHeaderView, QLabel,
|
38
|
+
QMenu, QShortcut, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
|
43
39
|
)
|
44
40
|
|
45
41
|
from novelwriter import CONFIG, SHARED
|
46
42
|
from novelwriter.common import minmax
|
47
|
-
from novelwriter.constants import nwHeaders, nwUnicode, trConst
|
43
|
+
from novelwriter.constants import nwHeaders, nwLabels, nwUnicode, trConst
|
48
44
|
from novelwriter.core.coretools import DocDuplicator, DocMerger, DocSplitter
|
49
45
|
from novelwriter.core.item import NWItem
|
50
46
|
from novelwriter.dialogs.docmerge import GuiDocMerge
|
51
47
|
from novelwriter.dialogs.docsplit import GuiDocSplit
|
52
48
|
from novelwriter.dialogs.editlabel import GuiEditLabel
|
53
49
|
from novelwriter.dialogs.projectsettings import GuiProjectSettings
|
54
|
-
from novelwriter.enum import nwDocMode,
|
50
|
+
from novelwriter.enum import nwDocMode, nwItemClass, nwItemLayout, nwItemType
|
55
51
|
from novelwriter.extensions.modified import NIconToolButton
|
56
52
|
from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
|
57
|
-
from novelwriter.types import
|
58
|
-
|
59
|
-
|
60
|
-
|
53
|
+
from novelwriter.types import (
|
54
|
+
QtAlignLeft, QtAlignRight, QtMouseLeft, QtMouseMiddle, QtSizeExpanding,
|
55
|
+
QtUserRole
|
56
|
+
)
|
61
57
|
|
62
58
|
logger = logging.getLogger(__name__)
|
63
59
|
|
@@ -80,10 +76,8 @@ class GuiProjectView(QWidget):
|
|
80
76
|
# Requests for the main GUI
|
81
77
|
projectSettingsRequest = pyqtSignal(int)
|
82
78
|
|
83
|
-
def __init__(self,
|
84
|
-
super().__init__(parent=
|
85
|
-
|
86
|
-
self.mainGui = mainGui
|
79
|
+
def __init__(self, parent: QWidget) -> None:
|
80
|
+
super().__init__(parent=parent)
|
87
81
|
|
88
82
|
# Build GUI
|
89
83
|
self.projTree = GuiProjectTree(self)
|
@@ -248,8 +242,6 @@ class GuiProjectView(QWidget):
|
|
248
242
|
self.projTree.createNewNote(tag, itemClass)
|
249
243
|
return
|
250
244
|
|
251
|
-
# END Class GuiProjectView
|
252
|
-
|
253
245
|
|
254
246
|
class GuiProjectToolBar(QWidget):
|
255
247
|
|
@@ -262,7 +254,6 @@ class GuiProjectToolBar(QWidget):
|
|
262
254
|
|
263
255
|
self.projView = projView
|
264
256
|
self.projTree = projView.projTree
|
265
|
-
self.mainGui = projView.mainGui
|
266
257
|
|
267
258
|
iSz = SHARED.theme.baseIconSize
|
268
259
|
mPx = CONFIG.pxInt(2)
|
@@ -274,7 +265,7 @@ class GuiProjectToolBar(QWidget):
|
|
274
265
|
self.viewLabel = QLabel(self.tr("Project Content"), self)
|
275
266
|
self.viewLabel.setFont(SHARED.theme.guiFontB)
|
276
267
|
self.viewLabel.setContentsMargins(0, 0, 0, 0)
|
277
|
-
self.viewLabel.setSizePolicy(
|
268
|
+
self.viewLabel.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
|
278
269
|
|
279
270
|
# Quick Links
|
280
271
|
self.mQuick = QMenu(self)
|
@@ -476,8 +467,6 @@ class GuiProjectToolBar(QWidget):
|
|
476
467
|
|
477
468
|
return
|
478
469
|
|
479
|
-
# END Class GuiProjectToolBar
|
480
|
-
|
481
470
|
|
482
471
|
class GuiProjectTree(QTreeWidget):
|
483
472
|
|
@@ -498,7 +487,6 @@ class GuiProjectTree(QTreeWidget):
|
|
498
487
|
logger.debug("Create: GuiProjectTree")
|
499
488
|
|
500
489
|
self.projView = projView
|
501
|
-
self.mainGui = projView.mainGui
|
502
490
|
|
503
491
|
# Internal Variables
|
504
492
|
self._treeMap: dict[str, QTreeWidgetItem] = {}
|
@@ -1009,8 +997,7 @@ class GuiProjectTree(QTreeWidget):
|
|
1009
997
|
trItemP.takeChild(tIndex)
|
1010
998
|
|
1011
999
|
for dHandle in reversed(self.getTreeFromHandle(tHandle)):
|
1012
|
-
|
1013
|
-
self.mainGui.closeDocument()
|
1000
|
+
SHARED.closeEditor(dHandle)
|
1014
1001
|
SHARED.project.removeItem(dHandle)
|
1015
1002
|
self._treeMap.pop(dHandle, None)
|
1016
1003
|
|
@@ -1033,7 +1020,7 @@ class GuiProjectTree(QTreeWidget):
|
|
1033
1020
|
if trItem is None or nwItem is None:
|
1034
1021
|
return
|
1035
1022
|
|
1036
|
-
itemStatus, statusIcon = nwItem.getImportStatus(
|
1023
|
+
itemStatus, statusIcon = nwItem.getImportStatus()
|
1037
1024
|
hLevel = nwItem.mainHeading
|
1038
1025
|
itemIcon = SHARED.theme.getItemIcon(
|
1039
1026
|
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
|
@@ -1409,19 +1396,15 @@ class GuiProjectTree(QTreeWidget):
|
|
1409
1396
|
if not newFile:
|
1410
1397
|
itemList.remove(tHandle)
|
1411
1398
|
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
mrgData = dlgMerge.getData()
|
1418
|
-
mrgList = mrgData.get("finalItems", [])
|
1419
|
-
if not mrgList:
|
1399
|
+
data, status = GuiDocMerge.getData(SHARED.mainGui, tHandle, itemList)
|
1400
|
+
if status:
|
1401
|
+
items = data.get("finalItems", [])
|
1402
|
+
if not items:
|
1420
1403
|
SHARED.info(self.tr("No documents selected for merging."))
|
1421
1404
|
return False
|
1422
1405
|
|
1423
1406
|
# Save the open document first, in case it's part of merge
|
1424
|
-
|
1407
|
+
SHARED.saveEditor()
|
1425
1408
|
|
1426
1409
|
# Create merge object, and append docs
|
1427
1410
|
docMerger = DocMerger(SHARED.project)
|
@@ -1436,7 +1419,7 @@ class GuiProjectTree(QTreeWidget):
|
|
1436
1419
|
else:
|
1437
1420
|
return False
|
1438
1421
|
|
1439
|
-
for sHandle in
|
1422
|
+
for sHandle in items:
|
1440
1423
|
docMerger.appendText(sHandle, True, mLabel)
|
1441
1424
|
|
1442
1425
|
if not docMerger.writeTargetDoc():
|
@@ -1450,10 +1433,11 @@ class GuiProjectTree(QTreeWidget):
|
|
1450
1433
|
if newFile:
|
1451
1434
|
self.revealNewTreeItem(mHandle, nHandle=tHandle, wordCount=True)
|
1452
1435
|
|
1453
|
-
self.
|
1436
|
+
self.projView.openDocumentRequest.emit(mHandle, nwDocMode.EDIT, "", False)
|
1437
|
+
self.projView.setSelectedHandle(mHandle, doScroll=True)
|
1454
1438
|
|
1455
|
-
if
|
1456
|
-
for sHandle in reversed(
|
1439
|
+
if data.get("moveToTrash", False):
|
1440
|
+
for sHandle in reversed(data.get("finalItems", [])):
|
1457
1441
|
trItem = self._getTreeItem(sHandle)
|
1458
1442
|
if isinstance(trItem, QTreeWidgetItem) and trItem.childCount() == 0:
|
1459
1443
|
self.moveItemToTrash(sHandle, askFirst=False, flush=False)
|
@@ -1479,16 +1463,11 @@ class GuiProjectTree(QTreeWidget):
|
|
1479
1463
|
logger.error("Only valid document items can be split")
|
1480
1464
|
return False
|
1481
1465
|
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
splitData, splitText = dlgSplit.getData()
|
1488
|
-
|
1489
|
-
headerList = splitData.get("headerList", [])
|
1490
|
-
intoFolder = splitData.get("intoFolder", False)
|
1491
|
-
docHierarchy = splitData.get("docHierarchy", False)
|
1466
|
+
data, text, status = GuiDocSplit.getData(SHARED.mainGui, tHandle)
|
1467
|
+
if status:
|
1468
|
+
headerList = data.get("headerList", [])
|
1469
|
+
intoFolder = data.get("intoFolder", False)
|
1470
|
+
docHierarchy = data.get("docHierarchy", False)
|
1492
1471
|
|
1493
1472
|
docSplit = DocSplitter(SHARED.project, tHandle)
|
1494
1473
|
if intoFolder:
|
@@ -1498,7 +1477,7 @@ class GuiProjectTree(QTreeWidget):
|
|
1498
1477
|
else:
|
1499
1478
|
docSplit.setParentItem(tItem.itemParent)
|
1500
1479
|
|
1501
|
-
docSplit.splitDocument(headerList,
|
1480
|
+
docSplit.splitDocument(headerList, text)
|
1502
1481
|
for writeOk, dHandle, nHandle in docSplit.writeDocuments(docHierarchy):
|
1503
1482
|
SHARED.project.index.reIndexHandle(dHandle)
|
1504
1483
|
self.revealNewTreeItem(dHandle, nHandle=nHandle, wordCount=True)
|
@@ -1509,7 +1488,7 @@ class GuiProjectTree(QTreeWidget):
|
|
1509
1488
|
info=docSplit.getError()
|
1510
1489
|
)
|
1511
1490
|
|
1512
|
-
if
|
1491
|
+
if data.get("moveToTrash", False):
|
1513
1492
|
self.moveItemToTrash(tHandle, askFirst=False, flush=True)
|
1514
1493
|
|
1515
1494
|
self.saveTreeOrder()
|
@@ -1658,8 +1637,6 @@ class GuiProjectTree(QTreeWidget):
|
|
1658
1637
|
|
1659
1638
|
return
|
1660
1639
|
|
1661
|
-
# END Class GuiProjectTree
|
1662
|
-
|
1663
1640
|
|
1664
1641
|
class _UpdatableMenu(QMenu):
|
1665
1642
|
|
@@ -1723,8 +1700,6 @@ class _UpdatableMenu(QMenu):
|
|
1723
1700
|
self.menuItemTriggered.emit(str(action.data()))
|
1724
1701
|
return
|
1725
1702
|
|
1726
|
-
# END Class _UpdatableMenu
|
1727
|
-
|
1728
1703
|
|
1729
1704
|
class _TreeContextMenu(QMenu):
|
1730
1705
|
|
@@ -1830,6 +1805,7 @@ class _TreeContextMenu(QMenu):
|
|
1830
1805
|
|
1831
1806
|
def _itemHeader(self) -> None:
|
1832
1807
|
"""Check if there is a header that can be used for rename."""
|
1808
|
+
SHARED.saveEditor()
|
1833
1809
|
if hItem := SHARED.project.index.getItemHeading(self._handle, "T0001"):
|
1834
1810
|
action = self.addAction(self.tr("Rename to Heading"))
|
1835
1811
|
action.triggered.connect(
|
@@ -1855,11 +1831,11 @@ class _TreeContextMenu(QMenu):
|
|
1855
1831
|
if self._item.isNovelLike():
|
1856
1832
|
menu = self.addMenu(self.tr("Set Status to ..."))
|
1857
1833
|
current = self._item.itemStatus
|
1858
|
-
for n, (key, entry) in enumerate(SHARED.project.data.itemStatus.
|
1859
|
-
name = entry
|
1834
|
+
for n, (key, entry) in enumerate(SHARED.project.data.itemStatus.iterItems()):
|
1835
|
+
name = entry.name
|
1860
1836
|
if not multi and current == key:
|
1861
1837
|
name += f" ({nwUnicode.U_CHECK})"
|
1862
|
-
action = menu.addAction(entry
|
1838
|
+
action = menu.addAction(entry.icon, name)
|
1863
1839
|
if multi:
|
1864
1840
|
action.triggered.connect(lambda n, key=key: self._iterSetItemStatus(key))
|
1865
1841
|
else:
|
@@ -1872,11 +1848,11 @@ class _TreeContextMenu(QMenu):
|
|
1872
1848
|
else:
|
1873
1849
|
menu = self.addMenu(self.tr("Set Importance to ..."))
|
1874
1850
|
current = self._item.itemImport
|
1875
|
-
for n, (key, entry) in enumerate(SHARED.project.data.itemImport.
|
1876
|
-
name = entry
|
1851
|
+
for n, (key, entry) in enumerate(SHARED.project.data.itemImport.iterItems()):
|
1852
|
+
name = entry.name
|
1877
1853
|
if not multi and current == key:
|
1878
1854
|
name += f" ({nwUnicode.U_CHECK})"
|
1879
|
-
action = menu.addAction(entry
|
1855
|
+
action = menu.addAction(entry.icon, name)
|
1880
1856
|
if multi:
|
1881
1857
|
action.triggered.connect(lambda n, key=key: self._iterSetItemImport(key))
|
1882
1858
|
else:
|
@@ -2076,5 +2052,3 @@ class _TreeContextMenu(QMenu):
|
|
2076
2052
|
else:
|
2077
2053
|
logger.info("Folder conversion cancelled")
|
2078
2054
|
return
|
2079
|
-
|
2080
|
-
# END Class _TreeContextMenu
|
novelwriter/gui/search.py
CHANGED
@@ -208,6 +208,12 @@ class GuiProjectSearch(QWidget):
|
|
208
208
|
self.searchResult.clear()
|
209
209
|
return
|
210
210
|
|
211
|
+
def refreshCurrentSearch(self) -> None:
|
212
|
+
"""Refresh the search if there is one."""
|
213
|
+
if self.searchResult.topLevelItemCount() > 0:
|
214
|
+
self._processSearch()
|
215
|
+
return
|
216
|
+
|
211
217
|
##
|
212
218
|
# Events
|
213
219
|
##
|
@@ -259,7 +265,7 @@ class GuiProjectSearch(QWidget):
|
|
259
265
|
if not self._blocked:
|
260
266
|
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
|
261
267
|
start = time()
|
262
|
-
SHARED.
|
268
|
+
SHARED.saveEditor()
|
263
269
|
self._blocked = True
|
264
270
|
self._map = {}
|
265
271
|
self.searchResult.clear()
|
@@ -298,18 +304,21 @@ class GuiProjectSearch(QWidget):
|
|
298
304
|
def _toggleCase(self, state: bool) -> None:
|
299
305
|
"""Enable/disable case sensitive mode."""
|
300
306
|
CONFIG.searchProjCase = state
|
307
|
+
self.refreshCurrentSearch()
|
301
308
|
return
|
302
309
|
|
303
310
|
@pyqtSlot(bool)
|
304
311
|
def _toggleWord(self, state: bool) -> None:
|
305
312
|
"""Enable/disable whole word search mode."""
|
306
313
|
CONFIG.searchProjWord = state
|
314
|
+
self.refreshCurrentSearch()
|
307
315
|
return
|
308
316
|
|
309
317
|
@pyqtSlot(bool)
|
310
318
|
def _toggleRegEx(self, state: bool) -> None:
|
311
319
|
"""Enable/disable regular expression search mode."""
|
312
320
|
CONFIG.searchProjRegEx = state
|
321
|
+
self.refreshCurrentSearch()
|
313
322
|
return
|
314
323
|
|
315
324
|
##
|
@@ -358,5 +367,3 @@ class GuiProjectSearch(QWidget):
|
|
358
367
|
QApplication.processEvents()
|
359
368
|
|
360
369
|
return
|
361
|
-
|
362
|
-
# END Class GuiProjectSearch
|
novelwriter/gui/sidebar.py
CHANGED
@@ -27,8 +27,8 @@ import logging
|
|
27
27
|
|
28
28
|
from typing import TYPE_CHECKING
|
29
29
|
|
30
|
-
from PyQt5.QtGui import QPalette
|
31
30
|
from PyQt5.QtCore import QEvent, QPoint, QSize, pyqtSignal
|
31
|
+
from PyQt5.QtGui import QPalette
|
32
32
|
from PyQt5.QtWidgets import QMenu, QVBoxLayout, QWidget
|
33
33
|
|
34
34
|
from novelwriter import CONFIG, SHARED
|
@@ -58,7 +58,7 @@ class GuiSideBar(QWidget):
|
|
58
58
|
iSz = QSize(iPx, iPx)
|
59
59
|
|
60
60
|
self.setContentsMargins(0, 0, 0, 0)
|
61
|
-
self.installEventFilter(StatusTipFilter(mainGui))
|
61
|
+
self.installEventFilter(StatusTipFilter(self.mainGui))
|
62
62
|
|
63
63
|
# Buttons
|
64
64
|
self.tbProject = NIconToolButton(self, iSz)
|
@@ -150,8 +150,6 @@ class GuiSideBar(QWidget):
|
|
150
150
|
|
151
151
|
return
|
152
152
|
|
153
|
-
# END Class GuiSideBar
|
154
|
-
|
155
153
|
|
156
154
|
class _PopRightMenu(QMenu):
|
157
155
|
|
@@ -162,5 +160,3 @@ class _PopRightMenu(QMenu):
|
|
162
160
|
offset = QPoint(parent.width(), parent.height() - self.height())
|
163
161
|
self.move(parent.mapToGlobal(offset))
|
164
162
|
return super(_PopRightMenu, self).event(event)
|
165
|
-
|
166
|
-
# END Class _PopRightMenu
|
novelwriter/gui/statusbar.py
CHANGED
@@ -27,26 +27,23 @@ import logging
|
|
27
27
|
|
28
28
|
from datetime import datetime
|
29
29
|
from time import time
|
30
|
-
from typing import TYPE_CHECKING, Literal
|
31
30
|
|
32
|
-
from PyQt5.QtCore import
|
33
|
-
from PyQt5.QtWidgets import QApplication, QStatusBar,
|
31
|
+
from PyQt5.QtCore import QLocale, pyqtSlot
|
32
|
+
from PyQt5.QtWidgets import QApplication, QLabel, QStatusBar, QWidget
|
34
33
|
|
35
34
|
from novelwriter import CONFIG, SHARED
|
36
35
|
from novelwriter.common import formatTime
|
37
36
|
from novelwriter.constants import nwConst
|
37
|
+
from novelwriter.enum import nwTrinary
|
38
38
|
from novelwriter.extensions.statusled import StatusLED
|
39
39
|
|
40
|
-
if TYPE_CHECKING: # pragma: no cover
|
41
|
-
from novelwriter.guimain import GuiMain
|
42
|
-
|
43
40
|
logger = logging.getLogger(__name__)
|
44
41
|
|
45
42
|
|
46
43
|
class GuiMainStatus(QStatusBar):
|
47
44
|
|
48
|
-
def __init__(self,
|
49
|
-
super().__init__(parent=
|
45
|
+
def __init__(self, parent: QWidget) -> None:
|
46
|
+
super().__init__(parent=parent)
|
50
47
|
|
51
48
|
logger.debug("Create: GuiMainStatus")
|
52
49
|
|
@@ -54,10 +51,6 @@ class GuiMainStatus(QStatusBar):
|
|
54
51
|
self._userIdle = False
|
55
52
|
self._debugInfo = False
|
56
53
|
|
57
|
-
colNone = SHARED.theme.statNone
|
58
|
-
colSaved = SHARED.theme.statSaved
|
59
|
-
colUnsaved = SHARED.theme.statUnsaved
|
60
|
-
|
61
54
|
iPx = SHARED.theme.baseIconHeight
|
62
55
|
|
63
56
|
# Permanent Widgets
|
@@ -74,7 +67,7 @@ class GuiMainStatus(QStatusBar):
|
|
74
67
|
self.addPermanentWidget(self.langText)
|
75
68
|
|
76
69
|
# The Editor Status
|
77
|
-
self.docIcon = StatusLED(
|
70
|
+
self.docIcon = StatusLED(iPx, iPx, self)
|
78
71
|
self.docText = QLabel(self.tr("Editor"), self)
|
79
72
|
self.docIcon.setContentsMargins(0, 0, 0, 0)
|
80
73
|
self.docText.setContentsMargins(0, 0, xM, 0)
|
@@ -82,7 +75,7 @@ class GuiMainStatus(QStatusBar):
|
|
82
75
|
self.addPermanentWidget(self.docText)
|
83
76
|
|
84
77
|
# The Project Status
|
85
|
-
self.projIcon = StatusLED(
|
78
|
+
self.projIcon = StatusLED(iPx, iPx, self)
|
86
79
|
self.projText = QLabel(self.tr("Project"), self)
|
87
80
|
self.projIcon.setContentsMargins(0, 0, 0, 0)
|
88
81
|
self.projText.setContentsMargins(0, 0, xM, 0)
|
@@ -123,8 +116,8 @@ class GuiMainStatus(QStatusBar):
|
|
123
116
|
self.setRefTime(-1.0)
|
124
117
|
self.setLanguage(*SHARED.spelling.describeDict())
|
125
118
|
self.setProjectStats(0, 0)
|
126
|
-
self.setProjectStatus(
|
127
|
-
self.setDocumentStatus(
|
119
|
+
self.setProjectStatus(nwTrinary.NEUTRAL)
|
120
|
+
self.setDocumentStatus(nwTrinary.NEUTRAL)
|
128
121
|
self.updateTime()
|
129
122
|
return
|
130
123
|
|
@@ -136,6 +129,13 @@ class GuiMainStatus(QStatusBar):
|
|
136
129
|
self.timePixmap = SHARED.theme.getPixmap("status_time", (iPx, iPx))
|
137
130
|
self.idlePixmap = SHARED.theme.getPixmap("status_idle", (iPx, iPx))
|
138
131
|
self.timeIcon.setPixmap(self.timePixmap)
|
132
|
+
|
133
|
+
colNone = SHARED.theme.statNone
|
134
|
+
colSaved = SHARED.theme.statSaved
|
135
|
+
colUnsaved = SHARED.theme.statUnsaved
|
136
|
+
self.docIcon.setColors(colNone, colSaved, colUnsaved)
|
137
|
+
self.projIcon.setColors(colNone, colSaved, colUnsaved)
|
138
|
+
|
139
139
|
return
|
140
140
|
|
141
141
|
##
|
@@ -147,12 +147,12 @@ class GuiMainStatus(QStatusBar):
|
|
147
147
|
self._refTime = refTime
|
148
148
|
return
|
149
149
|
|
150
|
-
def setProjectStatus(self, state:
|
150
|
+
def setProjectStatus(self, state: nwTrinary) -> None:
|
151
151
|
"""Set the project status colour icon."""
|
152
152
|
self.projIcon.setState(state)
|
153
153
|
return
|
154
154
|
|
155
|
-
def setDocumentStatus(self, state:
|
155
|
+
def setDocumentStatus(self, state: nwTrinary) -> None:
|
156
156
|
"""Set the document status colour icon."""
|
157
157
|
self.docIcon.setState(state)
|
158
158
|
return
|
@@ -215,13 +215,13 @@ class GuiMainStatus(QStatusBar):
|
|
215
215
|
@pyqtSlot(bool)
|
216
216
|
def updateProjectStatus(self, status: bool) -> None:
|
217
217
|
"""Update the project status."""
|
218
|
-
self.setProjectStatus(
|
218
|
+
self.setProjectStatus(nwTrinary.NEGATIVE if status else nwTrinary.POSITIVE)
|
219
219
|
return
|
220
220
|
|
221
221
|
@pyqtSlot(bool)
|
222
222
|
def updateDocumentStatus(self, status: bool) -> None:
|
223
223
|
"""Update the document status."""
|
224
|
-
self.setDocumentStatus(
|
224
|
+
self.setDocumentStatus(nwTrinary.NEGATIVE if status else nwTrinary.POSITIVE)
|
225
225
|
return
|
226
226
|
|
227
227
|
##
|
@@ -238,9 +238,8 @@ class GuiMainStatus(QStatusBar):
|
|
238
238
|
before starting novelWriter.
|
239
239
|
"""
|
240
240
|
import tracemalloc
|
241
|
-
from collections import Counter
|
242
241
|
|
243
|
-
|
242
|
+
count = len(QApplication.allWidgets())
|
244
243
|
if not self._debugInfo:
|
245
244
|
if tracemalloc.is_tracing():
|
246
245
|
self._traceMallocRef = "Total"
|
@@ -248,21 +247,14 @@ class GuiMainStatus(QStatusBar):
|
|
248
247
|
self._traceMallocRef = "Relative"
|
249
248
|
tracemalloc.start()
|
250
249
|
self._debugInfo = True
|
251
|
-
self._wCounts = Counter([type(x).__name__ for x in widgets])
|
252
|
-
|
253
|
-
if hasattr(self, "_wCounts"):
|
254
|
-
diff = Counter([type(x).__name__ for x in widgets]) - self._wCounts
|
255
|
-
for name, count in diff.items():
|
256
|
-
logger.debug("Widget '%s': +%d", name, count)
|
257
250
|
|
258
|
-
|
251
|
+
current, peak = tracemalloc.get_traced_memory()
|
259
252
|
stamp = datetime.now().strftime("%H:%M:%S")
|
260
|
-
|
261
|
-
f"
|
262
|
-
f"
|
263
|
-
f"
|
264
|
-
|
265
|
-
|
253
|
+
message = (
|
254
|
+
f"Widgets: {count} \u2013 "
|
255
|
+
f"{self._traceMallocRef} Memory: {current/1024:,.2f} kiB \u2013 "
|
256
|
+
f"Peak: {peak/1024:,.2f} kiB"
|
257
|
+
)
|
258
|
+
self.showMessage(f"Debug [{stamp}] {message}", 6000)
|
259
|
+
logger.debug("[MEMINFO] %s", message)
|
266
260
|
return
|
267
|
-
|
268
|
-
# END Class GuiMainStatus
|