Allow refreshing a novel model node

This commit is contained in:
Veronica Berglyd Olsen
2025-03-22 22:37:03 +01:00
parent ef652355bf
commit 848027856d
2 changed files with 84 additions and 25 deletions
+18 -13
View File
@@ -178,9 +178,9 @@ class Index:
return self._rootChange.get(rootHandle, self._indexChange) > float(checkTime)
return False
def refreshNovelModel(self, tHandle: str) -> None:
def refreshNovelModel(self, tHandle: str | None) -> None:
"""Refresh a novel model."""
if model := self.getNovelModel(tHandle):
if tHandle and (model := self.getNovelModel(tHandle)):
logger.info("Refreshing novel model '%s'", tHandle)
model.beginResetModel()
model.clear()
@@ -188,6 +188,19 @@ class Index:
model.endResetModel()
return
def updateNovelModelData(self, nwItem: NWItem) -> bool:
"""Refresh a novel model."""
if (
(rHandle := nwItem.itemRoot)
and (model := self._novelModels.get(rHandle))
and (node := self._itemIndex[nwItem.itemHandle])
and node.item.isDocumentLayout()
and node.item.isActive
):
logger.info("Updating novel model data '%s'", nwItem.itemHandle)
return model.refresh(node)
return False
##
# Load and Save Index to/from File
##
@@ -285,7 +298,6 @@ class Index:
# Keep a record of existing tags, and create a new item entry
itemTags = dict.fromkeys(self._itemIndex.allItemTags(tHandle), False)
itemHeadings = self._itemIndex.headingCount(tHandle)
self._itemIndex.add(tHandle, tItem)
# Run word counter for the whole text
@@ -309,10 +321,9 @@ class Index:
else:
self._scanActive(tHandle, tItem, text, itemTags)
if itemHeadings == self._itemIndex.headingCount(tHandle):
pass
else:
tItem.notifyNovelStructureChange()
if tItem.itemClass == nwItemClass.NOVEL and not blockSignal:
if not self.updateNovelModelData(tItem):
self.refreshNovelModel(tItem.itemRoot)
# Update timestamps for index changes
nowTime = time()
@@ -915,12 +926,6 @@ class ItemIndex:
self._items[tHandle] = IndexNode(tHandle, nwItem)
return
def headingCount(self, tHandle: str) -> int:
"""Return the number of headings in this item."""
if tHandle in self._items:
return len(self._items[tHandle])
return 0
def allItemTags(self, tHandle: str) -> list[str]:
"""Get all tags set for headings of an item."""
if tHandle in self._items:
+66 -12
View File
@@ -30,7 +30,8 @@ from PyQt6.QtGui import QIcon, QPixmap
from novelwriter import SHARED
from novelwriter.constants import nwStyles
from novelwriter.core.indexdata import IndexNode
from novelwriter.core.indexdata import IndexHeading, IndexNode
from novelwriter.error import logException
from novelwriter.types import QtAlignRight
logger = logging.getLogger(__name__)
@@ -121,15 +122,68 @@ class NovelModel(QAbstractTableModel):
handle = node.handle
for key, head in node.items():
if key != "T0000":
iLevel = nwStyles.H_LEVEL.get(head.level, 0)
more = self._columns - 1
data = {}
data[C_FACTOR*0 | R_TEXT] = head.title
data[C_FACTOR*0 | R_ICON] = SHARED.theme.getHeaderDecoration(iLevel)
data[C_FACTOR*1 | R_TEXT] = f"{head.mainCount:n}"
data[C_FACTOR*1 | R_ALIGN] = QtAlignRight
data[C_FACTOR*more | R_ICON] = self._more
data[R_HANDLE] = handle
data[R_KEY] = key
self._rows.append(data)
self._rows.append(self._generateEntry(handle, key, head))
return
def refresh(self, node: IndexNode) -> bool:
"""Refresh an index node."""
handle = node.handle
current = []
for i, row in enumerate(self._rows):
if row.get(R_HANDLE) == handle:
current.append(i)
if current == []:
return False
cols = self._columns - 1
first = current[0]
last = current[-1]
remains = []
try:
for key, head in node.items():
if key != "T0000":
if current:
j = current.pop(0)
self._rows[j] = self._generateEntry(handle, key, head)
else:
remains.append((key, head))
self.dataChanged.emit(self.createIndex(first, 0), self.createIndex(last, cols))
if remains:
self.beginInsertRows(QModelIndex(), last, last + len(remains) - 1)
for k, (key, head) in enumerate(remains, last + 1):
self._rows.insert(k, self._generateEntry(handle, key, head))
self.endInsertRows()
elif current:
self.beginRemoveRows(QModelIndex(), current[0], current[-1])
del self._rows[current[0]:current[-1] + 1]
self.endRemoveRows()
except Exception:
# This is faster than to check for index boundaries.
# We definitely don't want to cause a crash.
logException()
return False
return True
##
# Internal Functions
##
def _generateEntry(self, handle: str, key: str, heading: IndexHeading) -> dict:
"""Generate a cache entry."""
iLevel = nwStyles.H_LEVEL.get(heading.level, 0)
more = self._columns - 1
data = {}
data[C_FACTOR*0 | R_TEXT] = heading.title
data[C_FACTOR*0 | R_ICON] = SHARED.theme.getHeaderDecoration(iLevel)
data[C_FACTOR*1 | R_TEXT] = f"{heading.mainCount:n}"
data[C_FACTOR*1 | R_ALIGN] = QtAlignRight
data[C_FACTOR*more | R_ICON] = self._more
data[R_HANDLE] = handle
data[R_KEY] = key
return data