Add handlers for document label change
This commit is contained in:
+18
-18
@@ -36,7 +36,7 @@ from typing import TYPE_CHECKING, ItemsView, Iterable, Iterator
|
||||
from pathlib import Path
|
||||
from novelwriter import SHARED
|
||||
|
||||
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout, nwTrinary
|
||||
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.common import checkInt, isHandle, isItemClass, isTitleTag, jsonEncode
|
||||
from novelwriter.constants import nwFiles, nwKeyWords, nwRegEx, nwUnicode, nwHeaders
|
||||
@@ -255,7 +255,7 @@ class NWIndex:
|
||||
return False
|
||||
|
||||
# Keep a record of existing tags, and create a new item entry
|
||||
itemTags = dict.fromkeys(self._itemIndex.allItemTags(tHandle), nwTrinary.NEGATIVE)
|
||||
itemTags = dict.fromkeys(self._itemIndex.allItemTags(tHandle), False)
|
||||
self._itemIndex.add(tHandle, tItem)
|
||||
|
||||
# Run word counter for the whole text
|
||||
@@ -290,8 +290,7 @@ class NWIndex:
|
||||
# Internal Indexer Helpers
|
||||
##
|
||||
|
||||
def _scanActive(self, tHandle: str, nwItem: NWItem, text: str,
|
||||
tags: dict[str, nwTrinary]) -> None:
|
||||
def _scanActive(self, tHandle: str, nwItem: NWItem, text: str, tags: dict[str, bool]) -> None:
|
||||
"""Scan an active document for meta data."""
|
||||
nTitle = 0 # Line Number of the previous title
|
||||
cTitle = TT_NONE # Tag of the current title
|
||||
@@ -347,20 +346,18 @@ class NWIndex:
|
||||
self._indexWordCounts(tHandle, text, cTitle)
|
||||
|
||||
# Prune no longer used tags
|
||||
for tTag, tStatus in tags.items():
|
||||
added = []
|
||||
for tTag, isActive in tags.items():
|
||||
updated = []
|
||||
deleted = []
|
||||
if tStatus == nwTrinary.NEGATIVE:
|
||||
if isActive:
|
||||
logger.debug("Added/updated tag '%s'", tTag)
|
||||
updated.append(tTag)
|
||||
else:
|
||||
logger.debug("Removed tag '%s'", tTag)
|
||||
del self._tagsIndex[tTag]
|
||||
deleted.append(tTag)
|
||||
elif tStatus == nwTrinary.POSITIVE:
|
||||
logger.debug("Added new tag '%s'", tTag)
|
||||
added.append(tTag)
|
||||
else:
|
||||
logger.debug("Unchanged tag '%s'", tTag)
|
||||
if added or deleted:
|
||||
SHARED.indexUpdatedTags(added, deleted)
|
||||
if updated or deleted:
|
||||
SHARED.indexUpdatedTags(updated, deleted)
|
||||
|
||||
return
|
||||
|
||||
@@ -397,7 +394,7 @@ class NWIndex:
|
||||
return
|
||||
|
||||
def _indexKeyword(self, tHandle: str, line: str, sTitle: str,
|
||||
itemClass: nwItemClass, tags: dict[str, nwTrinary]) -> None:
|
||||
itemClass: nwItemClass, tags: dict[str, bool]) -> None:
|
||||
"""Validate and save the information about a reference to a tag
|
||||
in another file, or the setting of a tag in the file. A record
|
||||
of active tags is updated so that no longer used tags can be
|
||||
@@ -414,10 +411,9 @@ class NWIndex:
|
||||
|
||||
if tBits[0] == nwKeyWords.TAG_KEY:
|
||||
tagName = tBits[1]
|
||||
tagKey = tagName.lower()
|
||||
self._tagsIndex.add(tagName, tHandle, sTitle, itemClass)
|
||||
self._itemIndex.setHeadingTag(tHandle, sTitle, tagName)
|
||||
tags[tagKey] = nwTrinary.NEUTRAL if tagKey in tags else nwTrinary.POSITIVE
|
||||
tags[tagName.lower()] = True
|
||||
else:
|
||||
self._itemIndex.addHeadingRef(tHandle, sTitle, tBits[1:], tBits[0])
|
||||
|
||||
@@ -634,7 +630,11 @@ class NWIndex:
|
||||
sTitle = self._tagsIndex.tagHeading(tagKey)
|
||||
return tHandle, sTitle
|
||||
|
||||
def getTags(self, itemClass: nwItemClass) -> list[str]:
|
||||
def getDocumentTags(self, tHandle: str | None) -> list[str]:
|
||||
"""Return all tags used by a specific document."""
|
||||
return self._itemIndex.allItemTags(tHandle) if tHandle else []
|
||||
|
||||
def getClassTags(self, itemClass: nwItemClass) -> list[str]:
|
||||
"""Return all tags based on itemClass."""
|
||||
return self._tagsIndex.filterTagNames(itemClass.name)
|
||||
|
||||
|
||||
@@ -2054,7 +2054,7 @@ class MetaCompleter(QMenu):
|
||||
length = len(lookup)
|
||||
suffix = ""
|
||||
options = list(filter(
|
||||
lambda x: lookup in x.lower(), SHARED.project.index.getTags(
|
||||
lambda x: lookup in x.lower(), SHARED.project.index.getClassTags(
|
||||
nwKeyWords.KEY_CLASS.get(kw.strip(), nwItemClass.NO_CLASS)
|
||||
)
|
||||
))[:15]
|
||||
|
||||
@@ -102,8 +102,8 @@ class GuiDocViewerPanel(QWidget):
|
||||
"""Run open project tasks."""
|
||||
self.clearClassTabs()
|
||||
for key, name, tClass, iItem, hItem in SHARED.project.index.getTagsData():
|
||||
if tClass in self.kwTabs:
|
||||
self.kwTabs[tClass].addEntry(key, name, iItem, hItem)
|
||||
if tClass in self.kwTabs and iItem and hItem:
|
||||
self.kwTabs[tClass].addUpdateEntry(key, name, iItem, hItem)
|
||||
self._updateTabVisibility()
|
||||
return
|
||||
|
||||
@@ -123,6 +123,16 @@ class GuiDocViewerPanel(QWidget):
|
||||
# Public Slots
|
||||
##
|
||||
|
||||
@pyqtSlot(str)
|
||||
def projectItemChanged(self, tHandle: str) -> None:
|
||||
"""Update meta data for project item."""
|
||||
self.tabBackRefs.refreshDocument(tHandle)
|
||||
for key in SHARED.project.index.getDocumentTags(tHandle):
|
||||
name, tClass, iItem, hItem = SHARED.project.index.getSingleTag(key)
|
||||
if tClass in self.kwTabs and iItem and hItem:
|
||||
self.kwTabs[tClass].addUpdateEntry(key, name, iItem, hItem)
|
||||
return
|
||||
|
||||
@pyqtSlot(str)
|
||||
def updateHandle(self, tHandle: str | None) -> None:
|
||||
"""Update the document handle."""
|
||||
@@ -131,22 +141,19 @@ class GuiDocViewerPanel(QWidget):
|
||||
return
|
||||
|
||||
@pyqtSlot(list, list)
|
||||
def updateChangedTags(self, added: list[str], deleted: list[str]) -> None:
|
||||
def updateChangedTags(self, updated: list[str], deleted: list[str]) -> None:
|
||||
"""Forward tags changes to the lists."""
|
||||
for key in added:
|
||||
for key in updated:
|
||||
name, tClass, iItem, hItem = SHARED.project.index.getSingleTag(key)
|
||||
if tClass in self.kwTabs:
|
||||
self.kwTabs[tClass].addEntry(key, name, iItem, hItem)
|
||||
|
||||
if tClass in self.kwTabs and iItem and hItem:
|
||||
self.kwTabs[tClass].addUpdateEntry(key, name, iItem, hItem)
|
||||
for key in deleted:
|
||||
for cTab in self.kwTabs.values():
|
||||
if cTab.removeEntry(key):
|
||||
break
|
||||
else:
|
||||
logger.warning("Could not remove tag '%s' from view panel", key)
|
||||
|
||||
self._updateTabVisibility()
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
@@ -180,9 +187,7 @@ class _ViewPanelBackRefs(QTreeWidget):
|
||||
cMg = CONFIG.pxInt(6)
|
||||
|
||||
# Content
|
||||
self.setHeaderLabels([
|
||||
self.tr("Heading"), "", "", self.tr("Document")
|
||||
])
|
||||
self.setHeaderLabels([self.tr("Heading"), "", "", self.tr("Document")])
|
||||
self.setIndentation(0)
|
||||
self.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
|
||||
self.setIconSize(QSize(iPx, iPx))
|
||||
@@ -233,6 +238,21 @@ class _ViewPanelBackRefs(QTreeWidget):
|
||||
self.addTopLevelItem(trItem)
|
||||
return
|
||||
|
||||
def refreshDocument(self, tHandle: str) -> None:
|
||||
"""Refresh document meta data."""
|
||||
nwItem = SHARED.project.tree[tHandle]
|
||||
if nwItem:
|
||||
docIcon = SHARED.theme.getItemIcon(
|
||||
nwItem.itemType, nwItem.itemClass,
|
||||
nwItem.itemLayout, nwItem.mainHeading
|
||||
)
|
||||
for i in range(self.topLevelItemCount()):
|
||||
trItem = self.topLevelItem(i)
|
||||
if trItem and trItem.data(self.C_DATA, self.D_HANDLE) == tHandle:
|
||||
trItem.setIcon(self.C_DOCUMENT, docIcon)
|
||||
trItem.setText(self.C_DOCUMENT, nwItem.itemName)
|
||||
return
|
||||
|
||||
# END Class _ViewPanelBackRefs
|
||||
|
||||
|
||||
@@ -250,15 +270,13 @@ class _ViewPanelKeyWords(QTreeWidget):
|
||||
|
||||
def __init__(self, parent: QWidget, itemClass: nwItemClass) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self._itemClass = nwItemClass
|
||||
|
||||
self._tagMap: dict[str, QTreeWidgetItem] = {}
|
||||
|
||||
iPx = SHARED.theme.baseIconSize
|
||||
cMg = CONFIG.pxInt(6)
|
||||
|
||||
self.setHeaderLabels([
|
||||
self.tr("Tag"), "", "", self.tr("Heading"), self.tr("Document")
|
||||
])
|
||||
self.setHeaderLabels([self.tr("Tag"), "", "", self.tr("Heading"), self.tr("Document")])
|
||||
self.setIndentation(0)
|
||||
self.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
|
||||
self.setIconSize(QSize(iPx, iPx))
|
||||
@@ -266,6 +284,7 @@ class _ViewPanelKeyWords(QTreeWidget):
|
||||
self.setSortingEnabled(True)
|
||||
self.sortByColumn(self.C_NAME, Qt.SortOrder.AscendingOrder)
|
||||
|
||||
# Set Header Sizes
|
||||
treeHeader = self.header()
|
||||
treeHeader.setStretchLastSection(True)
|
||||
treeHeader.setSectionResizeMode(self.C_NAME, QHeaderView.ResizeMode.ResizeToContents)
|
||||
@@ -274,6 +293,7 @@ class _ViewPanelKeyWords(QTreeWidget):
|
||||
treeHeader.resizeSection(self.C_EDIT, iPx + cMg)
|
||||
treeHeader.resizeSection(self.C_VIEW, iPx + cMg)
|
||||
|
||||
# Cache Icons Locally
|
||||
self._classIcon = SHARED.theme.getIcon(nwLabels.CLASS_ICON[itemClass])
|
||||
self._editIcon = SHARED.theme.getIcon("edit")
|
||||
self._viewIcon = SHARED.theme.getIcon("view")
|
||||
@@ -281,14 +301,11 @@ class _ViewPanelKeyWords(QTreeWidget):
|
||||
return
|
||||
|
||||
def count(self) -> int:
|
||||
"""Return the number of items in the list."""
|
||||
return self.topLevelItemCount()
|
||||
|
||||
def addEntry(self, tag: str, name: str, iItem: IndexItem | None,
|
||||
hItem: IndexHeading | None) -> None:
|
||||
"""Add a tag entry to the list."""
|
||||
if not iItem or not hItem:
|
||||
return
|
||||
|
||||
def addUpdateEntry(self, tag: str, name: str, iItem: IndexItem, hItem: IndexHeading) -> None:
|
||||
"""Add a new entry, or update an existing one."""
|
||||
nwItem = iItem.item
|
||||
docIcon = SHARED.theme.getItemIcon(
|
||||
nwItem.itemType, nwItem.itemClass,
|
||||
@@ -297,7 +314,13 @@ class _ViewPanelKeyWords(QTreeWidget):
|
||||
iLevel = nwHeaders.H_LEVEL.get(hItem.level, 0) if nwItem.isDocumentLayout() else 5
|
||||
hDec = SHARED.theme.getHeaderDecorationNarrow(iLevel)
|
||||
|
||||
trItem = QTreeWidgetItem()
|
||||
# This can not use a get call to the dictionary as that creates
|
||||
# some weird issue with Qt, so we need to do this with an if
|
||||
if tag in self._tagMap:
|
||||
trItem = self._tagMap[tag]
|
||||
else:
|
||||
trItem = QTreeWidgetItem()
|
||||
|
||||
trItem.setText(self.C_NAME, name)
|
||||
trItem.setIcon(self.C_NAME, self._classIcon)
|
||||
trItem.setIcon(self.C_EDIT, self._editIcon)
|
||||
@@ -308,8 +331,10 @@ class _ViewPanelKeyWords(QTreeWidget):
|
||||
trItem.setText(self.C_DOCUMENT, nwItem.itemName)
|
||||
trItem.setData(self.C_DATA, self.D_TAG, tag)
|
||||
trItem.setData(self.C_DATA, self.D_HANDLE, iItem.handle)
|
||||
self.addTopLevelItem(trItem)
|
||||
self._tagMap[tag] = trItem
|
||||
|
||||
if tag not in self._tagMap:
|
||||
self.addTopLevelItem(trItem)
|
||||
self._tagMap[tag] = trItem
|
||||
|
||||
return
|
||||
|
||||
|
||||
@@ -259,6 +259,7 @@ class GuiMain(QMainWindow):
|
||||
self.projView.treeItemChanged.connect(self.docEditor.updateDocInfo)
|
||||
self.projView.treeItemChanged.connect(self.docViewer.updateDocInfo)
|
||||
self.projView.treeItemChanged.connect(self.itemDetails.updateViewBox)
|
||||
self.projView.treeItemChanged.connect(self.docViewerPanel.projectItemChanged)
|
||||
self.projView.rootFolderChanged.connect(self.outlineView.updateRootItem)
|
||||
self.projView.rootFolderChanged.connect(self.novelView.updateRootItem)
|
||||
self.projView.rootFolderChanged.connect(self.projView.updateRootItem)
|
||||
@@ -788,11 +789,9 @@ class GuiMain(QMainWindow):
|
||||
if not SHARED.hasProject:
|
||||
logger.error("No project open")
|
||||
return False
|
||||
|
||||
if tHandle is None and (self.docEditor.anyFocus() or self.isFocusMode):
|
||||
tHandle = self.docEditor.docHandle
|
||||
self.projView.renameTreeItem(tHandle)
|
||||
|
||||
return True
|
||||
|
||||
def rebuildTrees(self) -> None:
|
||||
|
||||
@@ -215,9 +215,9 @@ class SharedData(QObject):
|
||||
# Call-Back Functions
|
||||
##
|
||||
|
||||
def indexUpdatedTags(self, added: list[str], deleted: list[str]) -> None:
|
||||
def indexUpdatedTags(self, updated: list[str], deleted: list[str]) -> None:
|
||||
"""Emit the index changed tags signal."""
|
||||
self.indexChangedTags.emit(added, deleted)
|
||||
self.indexChangedTags.emit(updated, deleted)
|
||||
return
|
||||
|
||||
##
|
||||
|
||||
Reference in New Issue
Block a user