Clean up item notification and item main icon

This commit is contained in:
Veronica Berglyd Olsen
2024-11-21 01:18:28 +01:00
parent 55eed706fb
commit d55f53be0a
13 changed files with 63 additions and 117 deletions
+1
View File
@@ -296,6 +296,7 @@ class NWIndex:
self._indexChange = nowTime self._indexChange = nowTime
self._rootChange[tItem.itemRoot] = nowTime self._rootChange[tItem.itemRoot] = nowTime
if not blockSignal: if not blockSignal:
tItem.notifyToRefresh()
SHARED.indexSignalProxy({ SHARED.indexSignalProxy({
"event": "scanText", "event": "scanText",
"handle": tHandle, "handle": tHandle,
+4
View File
@@ -321,6 +321,10 @@ class NWItem:
return trConst(nwLabels.ITEM_DESCRIPTION.get(descKey, "")) return trConst(nwLabels.ITEM_DESCRIPTION.get(descKey, ""))
def getMainIcon(self) -> QIcon:
"""Get the main item icon."""
return SHARED.theme.getItemIcon(self._type, self._class, self._layout, self._heading)
def getImportStatus(self) -> tuple[str, QIcon]: def getImportStatus(self) -> tuple[str, QIcon]:
"""Return the relevant importance or status label and icon for """Return the relevant importance or status label and icon for
the current item based on its class. the current item based on its class.
+1 -5
View File
@@ -31,7 +31,6 @@ from typing import TYPE_CHECKING
from PyQt5.QtCore import QAbstractItemModel, QMimeData, QModelIndex, Qt from PyQt5.QtCore import QAbstractItemModel, QMimeData, QModelIndex, Qt
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon
from novelwriter import SHARED
from novelwriter.common import decodeMimeHandles, minmax from novelwriter.common import decodeMimeHandles, minmax
from novelwriter.constants import nwConst from novelwriter.constants import nwConst
from novelwriter.core.item import NWItem from novelwriter.core.item import NWItem
@@ -116,10 +115,7 @@ class ProjectNode:
def refresh(self) -> None: def refresh(self) -> None:
"""Refresh data values.""" """Refresh data values."""
# Label # Label
self._cache[C_LABEL_ICON] = SHARED.theme.getItemIcon( self._cache[C_LABEL_ICON] = self._item.getMainIcon()
self._item.itemType, self._item.itemClass,
self._item.itemLayout, self._item.mainHeading
)
self._cache[C_LABEL_TEXT] = self._item.itemName self._cache[C_LABEL_TEXT] = self._item.itemName
# Count # Count
+2 -1
View File
@@ -130,8 +130,9 @@ class NWStatus:
if self._default not in self._store: if self._default not in self._store:
self._default = next(iter(self._store)) if self._store else None self._default = next(iter(self._store)) if self._store else None
# Emit the change signal # Emit the change signal and refresh tree
SHARED.projectSignalProxy({"event": "statusLabels", "kind": self._prefix}) SHARED.projectSignalProxy({"event": "statusLabels", "kind": self._prefix})
SHARED.project.tree.refreshAllItems()
return return
+8
View File
@@ -248,6 +248,14 @@ class NWTree:
self._project.setProjectChanged(True) self._project.setProjectChanged(True)
return return
def refreshAllItems(self) -> None:
"""Refresh all items in the tree."""
for node in reversed(self._model.root.allChildren()):
node.refresh()
node.updateCount(propagate=False)
self._model.layoutChanged.emit()
return
def checkConsistency(self, prefix: str) -> tuple[int, int]: def checkConsistency(self, prefix: str) -> tuple[int, int]:
"""Check the project tree consistency. Also check the content """Check the project tree consistency. Also check the content
folder and add back files that were discovered but were not folder and add back files that were discovered but were not
+7 -17
View File
@@ -162,23 +162,13 @@ class GuiDocMerge(NDialog):
self._data = {} self._data = {}
self._data["sHandle"] = sHandle self._data["sHandle"] = sHandle
self._data["origItems"] = itemList self._data["origItems"] = itemList
self.listBox.clear() self.listBox.clear()
for tHandle in itemList: for tHandle in itemList:
nwItem = SHARED.project.tree[tHandle] if (nwItem := SHARED.project.tree[tHandle]) and nwItem.isFileType():
if nwItem is None or not nwItem.isFileType(): item = QListWidgetItem()
continue item.setIcon(nwItem.getMainIcon())
item.setText(nwItem.itemName)
itemIcon = SHARED.theme.getItemIcon( item.setData(self.D_HANDLE, tHandle)
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, nwItem.mainHeading item.setCheckState(Qt.CheckState.Checked)
) self.listBox.addItem(item)
newItem = QListWidgetItem()
newItem.setIcon(itemIcon)
newItem.setText(nwItem.itemName)
newItem.setData(self.D_HANDLE, tHandle)
newItem.setCheckState(Qt.CheckState.Checked)
self.listBox.addItem(newItem)
return return
+2 -10
View File
@@ -339,17 +339,13 @@ class _ViewPanelBackRefs(QTreeWidget):
def _setTreeItemValues(self, tHandle: str, sTitle: str, hItem: IndexHeading) -> None: def _setTreeItemValues(self, tHandle: str, sTitle: str, hItem: IndexHeading) -> None:
"""Add or update a tree item.""" """Add or update a tree item."""
if nwItem := SHARED.project.tree[tHandle]: if nwItem := SHARED.project.tree[tHandle]:
docIcon = SHARED.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass,
nwItem.itemLayout, nwItem.mainHeading
)
iLevel = nwStyles.H_LEVEL.get(hItem.level, 0) if nwItem.isDocumentLayout() else 5 iLevel = nwStyles.H_LEVEL.get(hItem.level, 0) if nwItem.isDocumentLayout() else 5
hDec = SHARED.theme.getHeaderDecorationNarrow(iLevel) hDec = SHARED.theme.getHeaderDecorationNarrow(iLevel)
tKey = f"{tHandle}:{sTitle}" tKey = f"{tHandle}:{sTitle}"
trItem = self._treeMap[tKey] if tKey in self._treeMap else QTreeWidgetItem() trItem = self._treeMap[tKey] if tKey in self._treeMap else QTreeWidgetItem()
trItem.setIcon(self.C_DOC, docIcon) trItem.setIcon(self.C_DOC, nwItem.getMainIcon())
trItem.setText(self.C_DOC, nwItem.itemName) trItem.setText(self.C_DOC, nwItem.itemName)
trItem.setToolTip(self.C_DOC, nwItem.itemName) trItem.setToolTip(self.C_DOC, nwItem.itemName)
trItem.setIcon(self.C_EDIT, self._editIcon) trItem.setIcon(self.C_EDIT, self._editIcon)
@@ -448,10 +444,6 @@ class _ViewPanelKeyWords(QTreeWidget):
def addUpdateEntry(self, tag: str, name: str, iItem: IndexItem, hItem: IndexHeading) -> None: def addUpdateEntry(self, tag: str, name: str, iItem: IndexItem, hItem: IndexHeading) -> None:
"""Add a new entry, or update an existing one.""" """Add a new entry, or update an existing one."""
nwItem = iItem.item nwItem = iItem.item
docIcon = SHARED.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass,
nwItem.itemLayout, nwItem.mainHeading
)
impLabel, impIcon = nwItem.getImportStatus() impLabel, impIcon = nwItem.getImportStatus()
iLevel = nwStyles.H_LEVEL.get(hItem.level, 0) if nwItem.isDocumentLayout() else 5 iLevel = nwStyles.H_LEVEL.get(hItem.level, 0) if nwItem.isDocumentLayout() else 5
hDec = SHARED.theme.getHeaderDecorationNarrow(iLevel) hDec = SHARED.theme.getHeaderDecorationNarrow(iLevel)
@@ -468,7 +460,7 @@ class _ViewPanelKeyWords(QTreeWidget):
trItem.setIcon(self.C_IMPORT, impIcon) trItem.setIcon(self.C_IMPORT, impIcon)
trItem.setText(self.C_IMPORT, impLabel) trItem.setText(self.C_IMPORT, impLabel)
trItem.setToolTip(self.C_IMPORT, impLabel) trItem.setToolTip(self.C_IMPORT, impLabel)
trItem.setIcon(self.C_DOC, docIcon) trItem.setIcon(self.C_DOC, nwItem.getMainIcon())
trItem.setText(self.C_DOC, nwItem.itemName) trItem.setText(self.C_DOC, nwItem.itemName)
trItem.setToolTip(self.C_DOC, nwItem.itemName) trItem.setToolTip(self.C_DOC, nwItem.itemName)
trItem.setData(self.C_TITLE, QtDecoration, hDec) trItem.setData(self.C_TITLE, QtDecoration, hDec)
+1 -4
View File
@@ -269,10 +269,7 @@ class GuiItemDetails(QWidget):
# Layout # Layout
# ====== # ======
usageIcon = SHARED.theme.getItemIcon( self.usageIcon.setPixmap(nwItem.getMainIcon().pixmap(iPx, iPx))
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, nwItem.mainHeading
)
self.usageIcon.setPixmap(usageIcon.pixmap(iPx, iPx))
self.usageData.setText(nwItem.describeMe()) self.usageData.setText(nwItem.describeMe())
# Counts # Counts
+27 -50
View File
@@ -130,7 +130,6 @@ class GuiProjectView(QWidget):
# Signals # Signals
self.selectedItemChanged.connect(self.projBar.treeSelectionChanged) self.selectedItemChanged.connect(self.projBar.treeSelectionChanged)
self.projTree.itemRefreshed.connect(self.projBar.treeItemRefreshed)
self.projBar.newDocumentFromTemplate.connect(self.createFileFromTemplate) self.projBar.newDocumentFromTemplate.connect(self.createFileFromTemplate)
# Function Mappings # Function Mappings
@@ -145,7 +144,6 @@ class GuiProjectView(QWidget):
def updateTheme(self) -> None: def updateTheme(self) -> None:
"""Update theme elements.""" """Update theme elements."""
self.projBar.updateTheme() self.projBar.updateTheme()
self.populateTree()
return return
def initSettings(self) -> None: def initSettings(self) -> None:
@@ -162,21 +160,12 @@ class GuiProjectView(QWidget):
def openProjectTasks(self) -> None: def openProjectTasks(self) -> None:
"""Run open project tasks.""" """Run open project tasks."""
self.populateTree() self.projTree.loadModel()
self.projBar.buildTemplatesMenu()
self.projBar.buildQuickLinksMenu() self.projBar.buildQuickLinksMenu()
self.projBar.setEnabled(True) self.projBar.setEnabled(True)
return return
def saveProjectTasks(self) -> None:
"""Run save project tasks."""
# self.projTree.saveTreeOrder()
return
def populateTree(self) -> None:
"""Build the tree structure from project data."""
self.projTree.loadModel()
return
def setTreeFocus(self) -> None: def setTreeFocus(self) -> None:
"""Forward the set focus call to the tree widget.""" """Forward the set focus call to the tree widget."""
self.projTree.setFocus() self.projTree.setFocus()
@@ -227,10 +216,9 @@ class GuiProjectView(QWidget):
return return
@pyqtSlot(str) @pyqtSlot(str)
def updateItemValues(self, tHandle: str) -> None: def projectItemChanged(self, tHandle: str) -> None:
"""Update tree item.""" """Refresh other content when project item changed."""
# if nwItem := SHARED.project.tree[tHandle]: self.projBar.processTemplateDocuments(tHandle)
# self.projTree.setTreeItemValues(nwItem)
return return
@pyqtSlot(str) @pyqtSlot(str)
@@ -246,12 +234,6 @@ class GuiProjectView(QWidget):
self.projBar.buildQuickLinksMenu() self.projBar.buildQuickLinksMenu()
return return
@pyqtSlot(str)
def refreshUserLabels(self, kind: str) -> None:
"""Refresh status or importance labels."""
self.projTree.refreshUserLabels(kind)
return
class GuiProjectToolBar(QWidget): class GuiProjectToolBar(QWidget):
@@ -398,6 +380,7 @@ class GuiProjectToolBar(QWidget):
self.aAddNote.setIcon(SHARED.theme.getIcon("proj_note")) self.aAddNote.setIcon(SHARED.theme.getIcon("proj_note"))
self.aAddFolder.setIcon(SHARED.theme.getIcon("proj_folder")) self.aAddFolder.setIcon(SHARED.theme.getIcon("proj_folder"))
self.buildTemplatesMenu()
self.buildQuickLinksMenu() self.buildQuickLinksMenu()
self._buildRootMenu() self._buildRootMenu()
@@ -422,19 +405,26 @@ class GuiProjectToolBar(QWidget):
) )
return return
def buildTemplatesMenu(self) -> None:
"""Build the templates menu."""
for tHandle, _ in SHARED.project.tree.iterRoots(nwItemClass.TEMPLATE):
for dHandle in SHARED.project.tree.subTree(tHandle):
self.processTemplateDocuments(dHandle)
return
def processTemplateDocuments(self, tHandle: str) -> None:
"""Process change in tree items to update menu content."""
if item := SHARED.project.tree[tHandle]:
if item.isTemplateFile() and item.isActive:
self.mTemplates.addUpdate(tHandle, item.itemName, item.getMainIcon())
elif tHandle in self.mTemplates:
self.mTemplates.remove(tHandle)
return
## ##
# Public Slots # Public Slots
## ##
@pyqtSlot(str, NWItem, QIcon)
def treeItemRefreshed(self, tHandle: str, nwItem: NWItem, icon: QIcon) -> None:
"""Process change in tree items to update menu content."""
if nwItem.isTemplateFile() and nwItem.isActive:
self.mTemplates.addUpdate(tHandle, nwItem.itemName, icon)
elif tHandle in self.mTemplates:
self.mTemplates.remove(tHandle)
return
@pyqtSlot(str) @pyqtSlot(str)
def treeSelectionChanged(self, tHandle: str) -> None: def treeSelectionChanged(self, tHandle: str) -> None:
"""Toggle the visibility of the new item entries for novel """Toggle the visibility of the new item entries for novel
@@ -482,8 +472,6 @@ class GuiProjectToolBar(QWidget):
class GuiProjectTree(QTreeView): class GuiProjectTree(QTreeView):
itemRefreshed = pyqtSignal(str, NWItem, QIcon)
def __init__(self, projView: GuiProjectView) -> None: def __init__(self, projView: GuiProjectView) -> None:
super().__init__(parent=projView) super().__init__(parent=projView)
@@ -635,6 +623,7 @@ class GuiProjectTree(QTreeView):
SHARED.project.newRoot(itemClass, pos) SHARED.project.newRoot(itemClass, pos)
self.restoreExpandedState() self.restoreExpandedState()
self.projView.rootFolderChanged.emit(tHandle)
elif itemType in (nwItemType.FILE, nwItemType.FOLDER): elif itemType in (nwItemType.FILE, nwItemType.FOLDER):
@@ -927,7 +916,9 @@ class GuiProjectTree(QTreeView):
if node := model.node(index): if node := model.node(index):
for child in reversed(node.allChildren()): for child in reversed(node.allChildren()):
SHARED.project.removeItem(child.item.itemHandle) SHARED.project.removeItem(child.item.itemHandle)
self.projView.projBar.processTemplateDocuments(child.item.itemHandle)
SHARED.project.removeItem(node.item.itemHandle) SHARED.project.removeItem(node.item.itemHandle)
self.projView.projBar.processTemplateDocuments(node.item.itemHandle)
elif trashNode := SHARED.project.tree.trash: elif trashNode := SHARED.project.tree.trash:
if askFirst and not SHARED.question(self.tr("Move selected item(s) to Trash?")): if askFirst and not SHARED.question(self.tr("Move selected item(s) to Trash?")):
@@ -1043,22 +1034,6 @@ class GuiProjectTree(QTreeView):
return node return node
return None return None
# =========================================================================================== #
# Old Code
# =========================================================================================== #
def refreshUserLabels(self, kind: str) -> None:
"""Refresh status or importance labels."""
# if kind == "s":
# for nwItem in SHARED.project.tree:
# if nwItem.isNovelLike():
# self.setTreeItemValues(nwItem)
# elif kind == "i":
# for nwItem in SHARED.project.tree:
# if not nwItem.isNovelLike():
# self.setTreeItemValues(nwItem)
return
class _UpdatableMenu(QMenu): class _UpdatableMenu(QMenu):
@@ -1350,6 +1325,8 @@ class _TreeContextMenu(QMenu):
"""Add move to Trash action.""" """Add move to Trash action."""
if self._model.trashSelection(self._indices): if self._model.trashSelection(self._indices):
text = self.tr("Delete Permanently") text = self.tr("Delete Permanently")
elif len(self._indices) == 1 and self._item.isRootType():
text = self.tr("Delete Permanently")
else: else:
text = self.tr("Move to Trash") text = self.tr("Move to Trash")
action = self.addAction(text) action = self.addAction(text)
+1 -5
View File
@@ -334,15 +334,11 @@ class GuiProjectSearch(QWidget):
"""Populate the result tree.""" """Populate the result tree."""
if results and nwItem: if results and nwItem:
tHandle = nwItem.itemHandle tHandle = nwItem.itemHandle
docIcon = SHARED.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass,
nwItem.itemLayout, nwItem.mainHeading
)
ext = "+" if capped else "" ext = "+" if capped else ""
tItem = QTreeWidgetItem() tItem = QTreeWidgetItem()
tItem.setText(self.C_NAME, nwItem.itemName) tItem.setText(self.C_NAME, nwItem.itemName)
tItem.setIcon(self.C_NAME, docIcon) tItem.setIcon(self.C_NAME, nwItem.getMainIcon())
tItem.setData(self.C_NAME, self.D_HANDLE, tHandle) tItem.setData(self.C_NAME, self.D_HANDLE, tHandle)
tItem.setText(self.C_COUNT, f"({len(results):n}{ext})") tItem.setText(self.C_COUNT, f"({len(results):n}{ext})")
tItem.setTextAlignment(self.C_COUNT, QtAlignRight) tItem.setTextAlignment(self.C_COUNT, QtAlignRight)
+6 -10
View File
@@ -215,8 +215,8 @@ class GuiMain(QMainWindow):
SHARED.indexCleared.connect(self.docViewerPanel.indexWasCleared) SHARED.indexCleared.connect(self.docViewerPanel.indexWasCleared)
SHARED.indexScannedText.connect(self.docViewerPanel.projectItemChanged) SHARED.indexScannedText.connect(self.docViewerPanel.projectItemChanged)
SHARED.indexScannedText.connect(self.itemDetails.updateViewBox) SHARED.indexScannedText.connect(self.itemDetails.updateViewBox)
SHARED.indexScannedText.connect(self.projView.updateItemValues)
SHARED.mainClockTick.connect(self._timeTick) SHARED.mainClockTick.connect(self._timeTick)
SHARED.projectItemChanged.connect(self.projView.projectItemChanged)
SHARED.projectItemChanged.connect(self.docEditor.updateDocInfo) SHARED.projectItemChanged.connect(self.docEditor.updateDocInfo)
SHARED.projectItemChanged.connect(self.docViewer.updateDocInfo) SHARED.projectItemChanged.connect(self.docViewer.updateDocInfo)
SHARED.projectItemChanged.connect(self.docViewerPanel.projectItemChanged) SHARED.projectItemChanged.connect(self.docViewerPanel.projectItemChanged)
@@ -225,7 +225,6 @@ class GuiMain(QMainWindow):
SHARED.projectStatusMessage.connect(self.mainStatus.setStatusMessage) SHARED.projectStatusMessage.connect(self.mainStatus.setStatusMessage)
SHARED.spellLanguageChanged.connect(self.mainStatus.setLanguage) SHARED.spellLanguageChanged.connect(self.mainStatus.setLanguage)
SHARED.statusLabelsChanged.connect(self.docViewerPanel.updateStatusLabels) SHARED.statusLabelsChanged.connect(self.docViewerPanel.updateStatusLabels)
SHARED.statusLabelsChanged.connect(self.projView.refreshUserLabels)
self.mainMenu.requestDocAction.connect(self._passDocumentAction) self.mainMenu.requestDocAction.connect(self._passDocumentAction)
self.mainMenu.requestDocInsert.connect(self._passDocumentInsert) self.mainMenu.requestDocInsert.connect(self._passDocumentInsert)
@@ -512,11 +511,9 @@ class GuiMain(QMainWindow):
def saveProject(self, autoSave: bool = False) -> bool: def saveProject(self, autoSave: bool = False) -> bool:
"""Save the current project.""" """Save the current project."""
if not SHARED.hasProject: if SHARED.hasProject:
logger.error("No project open") return SHARED.saveProject(autoSave=autoSave)
return False return False
self.projView.saveProjectTasks()
return SHARED.saveProject(autoSave=autoSave)
## ##
# Document Actions # Document Actions
@@ -743,9 +740,8 @@ class GuiMain(QMainWindow):
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
tStart = time() tStart = time()
self.projView.saveProjectTasks()
SHARED.project.index.rebuildIndex() SHARED.project.index.rebuildIndex()
self.projView.populateTree() SHARED.project.tree.refreshAllItems()
self.novelView.refreshTree() self.novelView.refreshTree()
tEnd = time() tEnd = time()
@@ -1063,7 +1059,7 @@ class GuiMain(QMainWindow):
)) ))
if tree: if tree:
self.projView.populateTree() SHARED.project.tree.refreshAllItems()
if theme: if theme:
# We are doing this manually instead of connecting to # We are doing this manually instead of connecting to
+1 -5
View File
@@ -394,13 +394,9 @@ class GuiManuscriptBuild(NDialog):
if isinstance(rItem, NWItem): if isinstance(rItem, NWItem):
rootMap[rHandle] = rItem.itemName rootMap[rHandle] = rItem.itemName
itemIcon = SHARED.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass,
nwItem.itemLayout, nwItem.mainHeading
)
rootName = rootMap.get(rHandle, "??????") rootName = rootMap.get(rHandle, "??????")
item = QListWidgetItem(f"{rootName}: {nwItem.itemName}") item = QListWidgetItem(f"{rootName}: {nwItem.itemName}")
item.setIcon(itemIcon) item.setIcon(nwItem.getMainIcon())
self.listContent.addItem(item) self.listContent.addItem(item)
return return
+2 -10
View File
@@ -432,13 +432,8 @@ class _FilterTab(NFixedPage):
if nwItem.isInactiveClass() or not self._build.isRootAllowed(rHandle): if nwItem.isInactiveClass() or not self._build.isRootAllowed(rHandle):
continue continue
hLevel = nwItem.mainHeading
itemIcon = SHARED.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
)
trItem = QTreeWidgetItem() trItem = QTreeWidgetItem()
trItem.setIcon(self.C_NAME, itemIcon) trItem.setIcon(self.C_NAME, nwItem.getMainIcon())
trItem.setText(self.C_NAME, nwItem.itemName) trItem.setText(self.C_NAME, nwItem.itemName)
trItem.setData(self.C_DATA, self.D_HANDLE, tHandle) trItem.setData(self.C_DATA, self.D_HANDLE, tHandle)
trItem.setData(self.C_DATA, self.D_FILE, isFile) trItem.setData(self.C_DATA, self.D_FILE, isFile)
@@ -489,11 +484,8 @@ class _FilterTab(NFixedPage):
self.filterOpt.addLabel(self.tr("Select Root Folders")) self.filterOpt.addLabel(self.tr("Select Root Folders"))
for tHandle, nwItem in SHARED.project.tree.iterRoots(None): for tHandle, nwItem in SHARED.project.tree.iterRoots(None):
if not nwItem.isInactiveClass(): if not nwItem.isInactiveClass():
itemIcon = SHARED.theme.getItemIcon(
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout
)
self.filterOpt.addItem( self.filterOpt.addItem(
itemIcon, nwItem.itemName, f"root:{tHandle}", nwItem.getMainIcon(), nwItem.itemName, f"root:{tHandle}",
default=self._build.isRootAllowed(tHandle) default=self._build.isRootAllowed(tHandle)
) )