novelWriter 2.5b1__py3-none-any.whl → 2.5.1__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.5b1.dist-info → novelWriter-2.5.1.dist-info}/METADATA +1 -1
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/RECORD +77 -75
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/WHEEL +1 -1
- novelwriter/__init__.py +3 -3
- 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_pl_PL.json +116 -0
- novelwriter/assets/i18n/project_pt_BR.json +74 -74
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/text/credits_en.htm +52 -44
- novelwriter/assets/themes/cyberpunk_night.conf +1 -0
- novelwriter/assets/themes/default_dark.conf +1 -0
- novelwriter/assets/themes/default_light.conf +1 -0
- novelwriter/assets/themes/dracula.conf +1 -0
- novelwriter/assets/themes/solarized_dark.conf +1 -0
- novelwriter/assets/themes/solarized_light.conf +1 -0
- novelwriter/common.py +12 -3
- novelwriter/config.py +67 -15
- novelwriter/constants.py +8 -10
- novelwriter/core/buildsettings.py +5 -3
- novelwriter/core/coretools.py +3 -1
- novelwriter/core/docbuild.py +1 -0
- novelwriter/core/project.py +15 -4
- novelwriter/core/status.py +4 -1
- novelwriter/core/storage.py +6 -1
- novelwriter/core/tohtml.py +69 -29
- novelwriter/core/tokenizer.py +83 -14
- novelwriter/core/toodt.py +48 -21
- novelwriter/core/toqdoc.py +37 -21
- novelwriter/dialogs/about.py +10 -15
- novelwriter/dialogs/docmerge.py +16 -16
- novelwriter/dialogs/docsplit.py +16 -16
- novelwriter/dialogs/editlabel.py +6 -8
- novelwriter/dialogs/preferences.py +106 -93
- novelwriter/dialogs/projectsettings.py +16 -20
- novelwriter/dialogs/quotes.py +9 -5
- novelwriter/dialogs/wordlist.py +6 -6
- novelwriter/enum.py +4 -5
- novelwriter/extensions/configlayout.py +38 -4
- novelwriter/extensions/modified.py +22 -3
- novelwriter/extensions/{circularprogress.py → progressbars.py} +26 -3
- novelwriter/extensions/statusled.py +39 -23
- novelwriter/gui/doceditor.py +22 -13
- novelwriter/gui/dochighlight.py +30 -39
- novelwriter/gui/docviewer.py +24 -15
- novelwriter/gui/docviewerpanel.py +7 -0
- novelwriter/gui/mainmenu.py +11 -11
- novelwriter/gui/outline.py +4 -3
- novelwriter/gui/projtree.py +85 -77
- novelwriter/gui/search.py +10 -1
- novelwriter/gui/statusbar.py +25 -29
- novelwriter/gui/theme.py +3 -0
- novelwriter/guimain.py +139 -124
- novelwriter/shared.py +19 -8
- novelwriter/text/patterns.py +113 -0
- novelwriter/tools/dictionaries.py +2 -8
- novelwriter/tools/lipsum.py +8 -12
- novelwriter/tools/manusbuild.py +9 -9
- novelwriter/tools/manuscript.py +10 -5
- novelwriter/tools/manussettings.py +7 -3
- novelwriter/tools/noveldetails.py +10 -10
- novelwriter/tools/welcome.py +19 -10
- novelwriter/tools/writingstats.py +3 -3
- novelwriter/types.py +5 -2
- novelwriter/extensions/simpleprogress.py +0 -53
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.5b1.dist-info → novelWriter-2.5.1.dist-info}/top_level.txt +0 -0
novelwriter/gui/projtree.py
CHANGED
@@ -34,9 +34,8 @@ from time import time
|
|
34
34
|
from PyQt5.QtCore import QPoint, Qt, QTimer, pyqtSignal, pyqtSlot
|
35
35
|
from PyQt5.QtGui import QDragEnterEvent, QDragMoveEvent, QDropEvent, QIcon, QMouseEvent, QPalette
|
36
36
|
from PyQt5.QtWidgets import (
|
37
|
-
QAbstractItemView, QAction,
|
38
|
-
|
39
|
-
QWidget
|
37
|
+
QAbstractItemView, QAction, QFrame, QHBoxLayout, QHeaderView, QLabel,
|
38
|
+
QMenu, QShortcut, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
|
40
39
|
)
|
41
40
|
|
42
41
|
from novelwriter import CONFIG, SHARED
|
@@ -167,6 +166,7 @@ class GuiProjectView(QWidget):
|
|
167
166
|
|
168
167
|
def openProjectTasks(self) -> None:
|
169
168
|
"""Run open project tasks."""
|
169
|
+
self.populateTree()
|
170
170
|
self.projBar.buildQuickLinksMenu()
|
171
171
|
self.projBar.setEnabled(True)
|
172
172
|
return
|
@@ -214,7 +214,8 @@ class GuiProjectView(QWidget):
|
|
214
214
|
@pyqtSlot(str)
|
215
215
|
def updateItemValues(self, tHandle: str) -> None:
|
216
216
|
"""Update tree item."""
|
217
|
-
|
217
|
+
if nwItem := SHARED.project.tree[tHandle]:
|
218
|
+
self.projTree.setTreeItemValues(nwItem)
|
218
219
|
return
|
219
220
|
|
220
221
|
@pyqtSlot(str)
|
@@ -243,6 +244,12 @@ class GuiProjectView(QWidget):
|
|
243
244
|
self.projTree.createNewNote(tag, itemClass)
|
244
245
|
return
|
245
246
|
|
247
|
+
@pyqtSlot(str)
|
248
|
+
def refreshUserLabels(self, kind: str) -> None:
|
249
|
+
"""Refresh status or importance labels."""
|
250
|
+
self.projTree.refreshUserLabels(kind)
|
251
|
+
return
|
252
|
+
|
246
253
|
|
247
254
|
class GuiProjectToolBar(QWidget):
|
248
255
|
|
@@ -793,11 +800,11 @@ class GuiProjectTree(QTreeWidget):
|
|
793
800
|
|
794
801
|
def renameTreeItem(self, tHandle: str, name: str = "") -> None:
|
795
802
|
"""Open a dialog to edit the label of an item."""
|
796
|
-
if
|
797
|
-
newLabel, dlgOk = GuiEditLabel.getLabel(self, text=name or
|
803
|
+
if nwItem := SHARED.project.tree[tHandle]:
|
804
|
+
newLabel, dlgOk = GuiEditLabel.getLabel(self, text=name or nwItem.itemName)
|
798
805
|
if dlgOk:
|
799
|
-
|
800
|
-
self.setTreeItemValues(
|
806
|
+
nwItem.setName(newLabel)
|
807
|
+
self.setTreeItemValues(nwItem)
|
801
808
|
self._alertTreeChange(tHandle, flush=False)
|
802
809
|
return
|
803
810
|
|
@@ -998,7 +1005,7 @@ class GuiProjectTree(QTreeWidget):
|
|
998
1005
|
trItemP.takeChild(tIndex)
|
999
1006
|
|
1000
1007
|
for dHandle in reversed(self.getTreeFromHandle(tHandle)):
|
1001
|
-
SHARED.
|
1008
|
+
SHARED.closeEditor(dHandle)
|
1002
1009
|
SHARED.project.removeItem(dHandle)
|
1003
1010
|
self._treeMap.pop(dHandle, None)
|
1004
1011
|
|
@@ -1011,44 +1018,52 @@ class GuiProjectTree(QTreeWidget):
|
|
1011
1018
|
|
1012
1019
|
return True
|
1013
1020
|
|
1014
|
-
def
|
1015
|
-
"""
|
1016
|
-
|
1017
|
-
|
1021
|
+
def refreshUserLabels(self, kind: str) -> None:
|
1022
|
+
"""Refresh status or importance labels."""
|
1023
|
+
if kind == "s":
|
1024
|
+
for nwItem in SHARED.project.tree:
|
1025
|
+
if nwItem.isNovelLike():
|
1026
|
+
self.setTreeItemValues(nwItem)
|
1027
|
+
elif kind == "i":
|
1028
|
+
for nwItem in SHARED.project.tree:
|
1029
|
+
if not nwItem.isNovelLike():
|
1030
|
+
self.setTreeItemValues(nwItem)
|
1031
|
+
return
|
1032
|
+
|
1033
|
+
def setTreeItemValues(self, nwItem: NWItem | None) -> None:
|
1034
|
+
"""Set the name and flag values for a tree item in the project
|
1035
|
+
tree. Does not trigger a tree change as the data is already
|
1036
|
+
coming from project data.
|
1018
1037
|
"""
|
1019
|
-
trItem
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
hLevel = nwItem.mainHeading
|
1026
|
-
itemIcon = SHARED.theme.getItemIcon(
|
1027
|
-
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
|
1028
|
-
)
|
1038
|
+
if isinstance(nwItem, NWItem) and (trItem := self._getTreeItem(nwItem.itemHandle)):
|
1039
|
+
itemStatus, statusIcon = nwItem.getImportStatus()
|
1040
|
+
hLevel = nwItem.mainHeading
|
1041
|
+
itemIcon = SHARED.theme.getItemIcon(
|
1042
|
+
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
|
1043
|
+
)
|
1029
1044
|
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1045
|
+
trItem.setIcon(self.C_NAME, itemIcon)
|
1046
|
+
trItem.setText(self.C_NAME, nwItem.itemName)
|
1047
|
+
trItem.setIcon(self.C_STATUS, statusIcon)
|
1048
|
+
trItem.setToolTip(self.C_STATUS, itemStatus)
|
1034
1049
|
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1050
|
+
if nwItem.isFileType():
|
1051
|
+
iconName = "checked" if nwItem.isActive else "unchecked"
|
1052
|
+
toolTip = self.trActive if nwItem.isActive else self.trInactive
|
1053
|
+
trItem.setToolTip(self.C_ACTIVE, toolTip)
|
1054
|
+
else:
|
1055
|
+
iconName = "noncheckable"
|
1041
1056
|
|
1042
|
-
|
1057
|
+
trItem.setIcon(self.C_ACTIVE, SHARED.theme.getIcon(iconName))
|
1043
1058
|
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1059
|
+
if CONFIG.emphLabels and nwItem.isDocumentLayout():
|
1060
|
+
trFont = trItem.font(self.C_NAME)
|
1061
|
+
trFont.setBold(hLevel == "H1" or hLevel == "H2")
|
1062
|
+
trFont.setUnderline(hLevel == "H1")
|
1063
|
+
trItem.setFont(self.C_NAME, trFont)
|
1049
1064
|
|
1050
|
-
|
1051
|
-
|
1065
|
+
# Emit Refresh Signal
|
1066
|
+
self.itemRefreshed.emit(nwItem.itemHandle, nwItem, itemIcon)
|
1052
1067
|
|
1053
1068
|
return
|
1054
1069
|
|
@@ -1354,7 +1369,8 @@ class GuiProjectTree(QTreeWidget):
|
|
1354
1369
|
SHARED.project.index.deleteHandle(mHandle)
|
1355
1370
|
else:
|
1356
1371
|
SHARED.project.index.reIndexHandle(mHandle)
|
1357
|
-
|
1372
|
+
if mItem := SHARED.project.tree[mHandle]:
|
1373
|
+
self.setTreeItemValues(mItem)
|
1358
1374
|
|
1359
1375
|
# Update word count
|
1360
1376
|
self.propagateCount(tHandle, nwItemS.wordCount, countChildren=True)
|
@@ -1397,19 +1413,15 @@ class GuiProjectTree(QTreeWidget):
|
|
1397
1413
|
if not newFile:
|
1398
1414
|
itemList.remove(tHandle)
|
1399
1415
|
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
mrgData = dlgMerge.getData()
|
1406
|
-
mrgList = mrgData.get("finalItems", [])
|
1407
|
-
if not mrgList:
|
1416
|
+
data, status = GuiDocMerge.getData(SHARED.mainGui, tHandle, itemList)
|
1417
|
+
if status:
|
1418
|
+
items = data.get("finalItems", [])
|
1419
|
+
if not items:
|
1408
1420
|
SHARED.info(self.tr("No documents selected for merging."))
|
1409
1421
|
return False
|
1410
1422
|
|
1411
1423
|
# Save the open document first, in case it's part of merge
|
1412
|
-
SHARED.
|
1424
|
+
SHARED.saveEditor()
|
1413
1425
|
|
1414
1426
|
# Create merge object, and append docs
|
1415
1427
|
docMerger = DocMerger(SHARED.project)
|
@@ -1424,7 +1436,7 @@ class GuiProjectTree(QTreeWidget):
|
|
1424
1436
|
else:
|
1425
1437
|
return False
|
1426
1438
|
|
1427
|
-
for sHandle in
|
1439
|
+
for sHandle in items:
|
1428
1440
|
docMerger.appendText(sHandle, True, mLabel)
|
1429
1441
|
|
1430
1442
|
if not docMerger.writeTargetDoc():
|
@@ -1441,8 +1453,8 @@ class GuiProjectTree(QTreeWidget):
|
|
1441
1453
|
self.projView.openDocumentRequest.emit(mHandle, nwDocMode.EDIT, "", False)
|
1442
1454
|
self.projView.setSelectedHandle(mHandle, doScroll=True)
|
1443
1455
|
|
1444
|
-
if
|
1445
|
-
for sHandle in reversed(
|
1456
|
+
if data.get("moveToTrash", False):
|
1457
|
+
for sHandle in reversed(data.get("finalItems", [])):
|
1446
1458
|
trItem = self._getTreeItem(sHandle)
|
1447
1459
|
if isinstance(trItem, QTreeWidgetItem) and trItem.childCount() == 0:
|
1448
1460
|
self.moveItemToTrash(sHandle, askFirst=False, flush=False)
|
@@ -1468,16 +1480,11 @@ class GuiProjectTree(QTreeWidget):
|
|
1468
1480
|
logger.error("Only valid document items can be split")
|
1469
1481
|
return False
|
1470
1482
|
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
splitData, splitText = dlgSplit.getData()
|
1477
|
-
|
1478
|
-
headerList = splitData.get("headerList", [])
|
1479
|
-
intoFolder = splitData.get("intoFolder", False)
|
1480
|
-
docHierarchy = splitData.get("docHierarchy", False)
|
1483
|
+
data, text, status = GuiDocSplit.getData(SHARED.mainGui, tHandle)
|
1484
|
+
if status:
|
1485
|
+
headerList = data.get("headerList", [])
|
1486
|
+
intoFolder = data.get("intoFolder", False)
|
1487
|
+
docHierarchy = data.get("docHierarchy", False)
|
1481
1488
|
|
1482
1489
|
docSplit = DocSplitter(SHARED.project, tHandle)
|
1483
1490
|
if intoFolder:
|
@@ -1487,7 +1494,7 @@ class GuiProjectTree(QTreeWidget):
|
|
1487
1494
|
else:
|
1488
1495
|
docSplit.setParentItem(tItem.itemParent)
|
1489
1496
|
|
1490
|
-
docSplit.splitDocument(headerList,
|
1497
|
+
docSplit.splitDocument(headerList, text)
|
1491
1498
|
for writeOk, dHandle, nHandle in docSplit.writeDocuments(docHierarchy):
|
1492
1499
|
SHARED.project.index.reIndexHandle(dHandle)
|
1493
1500
|
self.revealNewTreeItem(dHandle, nHandle=nHandle, wordCount=True)
|
@@ -1498,7 +1505,7 @@ class GuiProjectTree(QTreeWidget):
|
|
1498
1505
|
info=docSplit.getError()
|
1499
1506
|
)
|
1500
1507
|
|
1501
|
-
if
|
1508
|
+
if data.get("moveToTrash", False):
|
1502
1509
|
self.moveItemToTrash(tHandle, askFirst=False, flush=True)
|
1503
1510
|
|
1504
1511
|
self.saveTreeOrder()
|
@@ -1604,7 +1611,7 @@ class GuiProjectTree(QTreeWidget):
|
|
1604
1611
|
|
1605
1612
|
self._treeMap[tHandle] = newItem
|
1606
1613
|
self.propagateCount(tHandle, nwItem.wordCount, countChildren=True)
|
1607
|
-
self.setTreeItemValues(
|
1614
|
+
self.setTreeItemValues(nwItem)
|
1608
1615
|
newItem.setExpanded(nwItem.isExpanded)
|
1609
1616
|
|
1610
1617
|
return newItem
|
@@ -1815,6 +1822,7 @@ class _TreeContextMenu(QMenu):
|
|
1815
1822
|
|
1816
1823
|
def _itemHeader(self) -> None:
|
1817
1824
|
"""Check if there is a header that can be used for rename."""
|
1825
|
+
SHARED.saveEditor()
|
1818
1826
|
if hItem := SHARED.project.index.getItemHeading(self._handle, "T0001"):
|
1819
1827
|
action = self.addAction(self.tr("Rename to Heading"))
|
1820
1828
|
action.triggered.connect(
|
@@ -1980,7 +1988,7 @@ class _TreeContextMenu(QMenu):
|
|
1980
1988
|
def _toggleItemActive(self) -> None:
|
1981
1989
|
"""Toggle the active status of an item."""
|
1982
1990
|
self._item.setActive(not self._item.isActive)
|
1983
|
-
self.projTree.setTreeItemValues(self.
|
1991
|
+
self.projTree.setTreeItemValues(self._item)
|
1984
1992
|
self.projTree._alertTreeChange(self._handle, flush=False)
|
1985
1993
|
return
|
1986
1994
|
|
@@ -1993,14 +2001,14 @@ class _TreeContextMenu(QMenu):
|
|
1993
2001
|
for tItem in self._items:
|
1994
2002
|
if tItem and tItem.isFileType():
|
1995
2003
|
tItem.setActive(isActive)
|
1996
|
-
self.projTree.setTreeItemValues(tItem
|
2004
|
+
self.projTree.setTreeItemValues(tItem)
|
1997
2005
|
self.projTree._alertTreeChange(tItem.itemHandle, flush=False)
|
1998
2006
|
return
|
1999
2007
|
|
2000
2008
|
def _changeItemStatus(self, key: str) -> None:
|
2001
2009
|
"""Set a new status value of an item."""
|
2002
2010
|
self._item.setStatus(key)
|
2003
|
-
self.projTree.setTreeItemValues(self.
|
2011
|
+
self.projTree.setTreeItemValues(self._item)
|
2004
2012
|
self.projTree._alertTreeChange(self._handle, flush=False)
|
2005
2013
|
return
|
2006
2014
|
|
@@ -2009,14 +2017,14 @@ class _TreeContextMenu(QMenu):
|
|
2009
2017
|
for tItem in self._items:
|
2010
2018
|
if tItem and tItem.isNovelLike():
|
2011
2019
|
tItem.setStatus(key)
|
2012
|
-
self.projTree.setTreeItemValues(tItem
|
2020
|
+
self.projTree.setTreeItemValues(tItem)
|
2013
2021
|
self.projTree._alertTreeChange(tItem.itemHandle, flush=False)
|
2014
2022
|
return
|
2015
2023
|
|
2016
2024
|
def _changeItemImport(self, key: str) -> None:
|
2017
2025
|
"""Set a new importance value of an item."""
|
2018
2026
|
self._item.setImport(key)
|
2019
|
-
self.projTree.setTreeItemValues(self.
|
2027
|
+
self.projTree.setTreeItemValues(self._item)
|
2020
2028
|
self.projTree._alertTreeChange(self._handle, flush=False)
|
2021
2029
|
return
|
2022
2030
|
|
@@ -2025,7 +2033,7 @@ class _TreeContextMenu(QMenu):
|
|
2025
2033
|
for tItem in self._items:
|
2026
2034
|
if tItem and not tItem.isNovelLike():
|
2027
2035
|
tItem.setImport(key)
|
2028
|
-
self.projTree.setTreeItemValues(tItem
|
2036
|
+
self.projTree.setTreeItemValues(tItem)
|
2029
2037
|
self.projTree._alertTreeChange(tItem.itemHandle, flush=False)
|
2030
2038
|
return
|
2031
2039
|
|
@@ -2033,11 +2041,11 @@ class _TreeContextMenu(QMenu):
|
|
2033
2041
|
"""Set a new item layout value of an item."""
|
2034
2042
|
if itemLayout == nwItemLayout.DOCUMENT and self._item.documentAllowed():
|
2035
2043
|
self._item.setLayout(nwItemLayout.DOCUMENT)
|
2036
|
-
self.projTree.setTreeItemValues(self.
|
2044
|
+
self.projTree.setTreeItemValues(self._item)
|
2037
2045
|
self.projTree._alertTreeChange(self._handle, flush=False)
|
2038
2046
|
elif itemLayout == nwItemLayout.NOTE:
|
2039
2047
|
self._item.setLayout(nwItemLayout.NOTE)
|
2040
|
-
self.projTree.setTreeItemValues(self.
|
2048
|
+
self.projTree.setTreeItemValues(self._item)
|
2041
2049
|
self.projTree._alertTreeChange(self._handle, flush=False)
|
2042
2050
|
return
|
2043
2051
|
|
@@ -2051,12 +2059,12 @@ class _TreeContextMenu(QMenu):
|
|
2051
2059
|
if msgYes and itemLayout == nwItemLayout.DOCUMENT and self._item.documentAllowed():
|
2052
2060
|
self._item.setType(nwItemType.FILE)
|
2053
2061
|
self._item.setLayout(nwItemLayout.DOCUMENT)
|
2054
|
-
self.projTree.setTreeItemValues(self.
|
2062
|
+
self.projTree.setTreeItemValues(self._item)
|
2055
2063
|
self.projTree._alertTreeChange(self._handle, flush=False)
|
2056
2064
|
elif msgYes and itemLayout == nwItemLayout.NOTE:
|
2057
2065
|
self._item.setType(nwItemType.FILE)
|
2058
2066
|
self._item.setLayout(nwItemLayout.NOTE)
|
2059
|
-
self.projTree.setTreeItemValues(self.
|
2067
|
+
self.projTree.setTreeItemValues(self._item)
|
2060
2068
|
self.projTree._alertTreeChange(self._handle, flush=False)
|
2061
2069
|
else:
|
2062
2070
|
logger.info("Folder conversion cancelled")
|
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
|
##
|
novelwriter/gui/statusbar.py
CHANGED
@@ -27,7 +27,6 @@ import logging
|
|
27
27
|
|
28
28
|
from datetime import datetime
|
29
29
|
from time import time
|
30
|
-
from typing import Literal
|
31
30
|
|
32
31
|
from PyQt5.QtCore import QLocale, pyqtSlot
|
33
32
|
from PyQt5.QtWidgets import QApplication, QLabel, QStatusBar, QWidget
|
@@ -35,6 +34,7 @@ from PyQt5.QtWidgets import QApplication, QLabel, QStatusBar, QWidget
|
|
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
40
|
logger = logging.getLogger(__name__)
|
@@ -51,10 +51,6 @@ class GuiMainStatus(QStatusBar):
|
|
51
51
|
self._userIdle = False
|
52
52
|
self._debugInfo = False
|
53
53
|
|
54
|
-
colNone = SHARED.theme.statNone
|
55
|
-
colSaved = SHARED.theme.statSaved
|
56
|
-
colUnsaved = SHARED.theme.statUnsaved
|
57
|
-
|
58
54
|
iPx = SHARED.theme.baseIconHeight
|
59
55
|
|
60
56
|
# Permanent Widgets
|
@@ -71,7 +67,7 @@ class GuiMainStatus(QStatusBar):
|
|
71
67
|
self.addPermanentWidget(self.langText)
|
72
68
|
|
73
69
|
# The Editor Status
|
74
|
-
self.docIcon = StatusLED(
|
70
|
+
self.docIcon = StatusLED(iPx, iPx, self)
|
75
71
|
self.docText = QLabel(self.tr("Editor"), self)
|
76
72
|
self.docIcon.setContentsMargins(0, 0, 0, 0)
|
77
73
|
self.docText.setContentsMargins(0, 0, xM, 0)
|
@@ -79,7 +75,7 @@ class GuiMainStatus(QStatusBar):
|
|
79
75
|
self.addPermanentWidget(self.docText)
|
80
76
|
|
81
77
|
# The Project Status
|
82
|
-
self.projIcon = StatusLED(
|
78
|
+
self.projIcon = StatusLED(iPx, iPx, self)
|
83
79
|
self.projText = QLabel(self.tr("Project"), self)
|
84
80
|
self.projIcon.setContentsMargins(0, 0, 0, 0)
|
85
81
|
self.projText.setContentsMargins(0, 0, xM, 0)
|
@@ -120,8 +116,8 @@ class GuiMainStatus(QStatusBar):
|
|
120
116
|
self.setRefTime(-1.0)
|
121
117
|
self.setLanguage(*SHARED.spelling.describeDict())
|
122
118
|
self.setProjectStats(0, 0)
|
123
|
-
self.setProjectStatus(
|
124
|
-
self.setDocumentStatus(
|
119
|
+
self.setProjectStatus(nwTrinary.NEUTRAL)
|
120
|
+
self.setDocumentStatus(nwTrinary.NEUTRAL)
|
125
121
|
self.updateTime()
|
126
122
|
return
|
127
123
|
|
@@ -133,6 +129,13 @@ class GuiMainStatus(QStatusBar):
|
|
133
129
|
self.timePixmap = SHARED.theme.getPixmap("status_time", (iPx, iPx))
|
134
130
|
self.idlePixmap = SHARED.theme.getPixmap("status_idle", (iPx, iPx))
|
135
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
|
+
|
136
139
|
return
|
137
140
|
|
138
141
|
##
|
@@ -144,12 +147,12 @@ class GuiMainStatus(QStatusBar):
|
|
144
147
|
self._refTime = refTime
|
145
148
|
return
|
146
149
|
|
147
|
-
def setProjectStatus(self, state:
|
150
|
+
def setProjectStatus(self, state: nwTrinary) -> None:
|
148
151
|
"""Set the project status colour icon."""
|
149
152
|
self.projIcon.setState(state)
|
150
153
|
return
|
151
154
|
|
152
|
-
def setDocumentStatus(self, state:
|
155
|
+
def setDocumentStatus(self, state: nwTrinary) -> None:
|
153
156
|
"""Set the document status colour icon."""
|
154
157
|
self.docIcon.setState(state)
|
155
158
|
return
|
@@ -212,13 +215,13 @@ class GuiMainStatus(QStatusBar):
|
|
212
215
|
@pyqtSlot(bool)
|
213
216
|
def updateProjectStatus(self, status: bool) -> None:
|
214
217
|
"""Update the project status."""
|
215
|
-
self.setProjectStatus(
|
218
|
+
self.setProjectStatus(nwTrinary.NEGATIVE if status else nwTrinary.POSITIVE)
|
216
219
|
return
|
217
220
|
|
218
221
|
@pyqtSlot(bool)
|
219
222
|
def updateDocumentStatus(self, status: bool) -> None:
|
220
223
|
"""Update the document status."""
|
221
|
-
self.setDocumentStatus(
|
224
|
+
self.setDocumentStatus(nwTrinary.NEGATIVE if status else nwTrinary.POSITIVE)
|
222
225
|
return
|
223
226
|
|
224
227
|
##
|
@@ -236,9 +239,7 @@ class GuiMainStatus(QStatusBar):
|
|
236
239
|
"""
|
237
240
|
import tracemalloc
|
238
241
|
|
239
|
-
|
240
|
-
|
241
|
-
widgets = QApplication.allWidgets()
|
242
|
+
count = len(QApplication.allWidgets())
|
242
243
|
if not self._debugInfo:
|
243
244
|
if tracemalloc.is_tracing():
|
244
245
|
self._traceMallocRef = "Total"
|
@@ -246,19 +247,14 @@ class GuiMainStatus(QStatusBar):
|
|
246
247
|
self._traceMallocRef = "Relative"
|
247
248
|
tracemalloc.start()
|
248
249
|
self._debugInfo = True
|
249
|
-
self._wCounts = Counter([type(x).__name__ for x in widgets])
|
250
|
-
|
251
|
-
if hasattr(self, "_wCounts"):
|
252
|
-
diff = Counter([type(x).__name__ for x in widgets]) - self._wCounts
|
253
|
-
for name, count in diff.items():
|
254
|
-
logger.debug("Widget '%s': +%d", name, count)
|
255
250
|
|
256
|
-
|
251
|
+
current, peak = tracemalloc.get_traced_memory()
|
257
252
|
stamp = datetime.now().strftime("%H:%M:%S")
|
258
|
-
|
259
|
-
f"
|
260
|
-
f"
|
261
|
-
f"
|
262
|
-
|
263
|
-
|
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)
|
264
260
|
return
|
novelwriter/gui/theme.py
CHANGED
@@ -75,6 +75,7 @@ class GuiTheme:
|
|
75
75
|
self.statUnsaved = QColor(0, 0, 0)
|
76
76
|
self.statSaved = QColor(0, 0, 0)
|
77
77
|
self.helpText = QColor(0, 0, 0)
|
78
|
+
self.fadedText = QColor(0, 0, 0)
|
78
79
|
self.errorText = QColor(255, 0, 0)
|
79
80
|
|
80
81
|
# Loaded Syntax Settings
|
@@ -263,6 +264,7 @@ class GuiTheme:
|
|
263
264
|
sec = "GUI"
|
264
265
|
if parser.has_section(sec):
|
265
266
|
self.helpText = self._parseColour(parser, sec, "helptext")
|
267
|
+
self.fadedText = self._parseColour(parser, sec, "fadedtext")
|
266
268
|
self.errorText = self._parseColour(parser, sec, "errortext")
|
267
269
|
self.statNone = self._parseColour(parser, sec, "statusnone")
|
268
270
|
self.statUnsaved = self._parseColour(parser, sec, "statusunsaved")
|
@@ -405,6 +407,7 @@ class GuiTheme:
|
|
405
407
|
self.statUnsaved = QColor(200, 15, 39)
|
406
408
|
self.statSaved = QColor(2, 133, 37)
|
407
409
|
self.helpText = QColor(0, 0, 0)
|
410
|
+
self.fadedText = QColor(128, 128, 128)
|
408
411
|
self.errorText = QColor(255, 0, 0)
|
409
412
|
return
|
410
413
|
|