From 95d8e3ac98898449617840e1afb130b0589cd7d5 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sun, 23 Mar 2025 16:41:40 +0100 Subject: [PATCH] Add back extra column content --- novelwriter/core/index.py | 13 +- novelwriter/core/indexdata.py | 42 +++- novelwriter/core/novelmodel.py | 26 ++- novelwriter/gui/noveltree.py | 267 ++----------------------- tests/test_core/test_core_indexdata.py | 38 ++-- tests/test_core/test_core_options.py | 8 +- tests/test_gui/test_gui_noveltree.py | 20 +- 7 files changed, 113 insertions(+), 301 deletions(-) diff --git a/novelwriter/core/index.py b/novelwriter/core/index.py index 827d287a..3f75f841 100644 --- a/novelwriter/core/index.py +++ b/novelwriter/core/index.py @@ -87,7 +87,7 @@ class Index: # Storage and State self._tagsIndex = TagsIndex() - self._itemIndex = ItemIndex(project) + self._itemIndex = ItemIndex(project, self._tagsIndex) self._indexBroken = False # Models @@ -906,10 +906,11 @@ class ItemIndex: IndexHeading object for each heading of the text. """ - __slots__ = ("_project", "_items") + __slots__ = ("_project", "_tags", "_items") - def __init__(self, project: NWProject) -> None: + def __init__(self, project: NWProject, tagsIndex: TagsIndex) -> None: self._project = project + self._tags = tagsIndex self._items: dict[str, IndexNode] = {} return @@ -936,7 +937,7 @@ class ItemIndex: """Add a new item to the index. This will overwrite the item if it already exists. """ - self._items[tHandle] = IndexNode(tHandle, nwItem) + self._items[tHandle] = IndexNode(self._tags, tHandle, nwItem) return def allItemTags(self, tHandle: str) -> list[str]: @@ -994,7 +995,7 @@ class ItemIndex: if tHandle in self._items: tItem = self._items[tHandle] sTitle = tItem.nextHeading() - tItem.addHeading(IndexHeading(sTitle, lineNo, level, text)) + tItem.addHeading(IndexHeading(self._tags, sTitle, lineNo, level, text)) return sTitle return TT_NONE @@ -1065,7 +1066,7 @@ class ItemIndex: nwItem = self._project.tree[tHandle] if nwItem is not None: - tItem = IndexNode(tHandle, nwItem) + tItem = IndexNode(self._tags, tHandle, nwItem) tItem.unpackData(tData) self._items[tHandle] = tItem diff --git a/novelwriter/core/indexdata.py b/novelwriter/core/indexdata.py index 1dc6043b..46b444f4 100644 --- a/novelwriter/core/indexdata.py +++ b/novelwriter/core/indexdata.py @@ -36,6 +36,7 @@ from novelwriter.common import checkInt, isListInstance, isTitleTag from novelwriter.constants import nwKeyWords, nwStyles if TYPE_CHECKING: # pragma: no cover + from novelwriter.core.index import TagsIndex from novelwriter.core.item import NWItem logger = logging.getLogger(__name__) @@ -56,12 +57,13 @@ class IndexNode: must be reset each time the item is re-indexed. """ - __slots__ = ("_handle", "_item", "_headings", "_count", "_notes") + __slots__ = ("_tags", "_handle", "_item", "_headings", "_notes", "_count") - def __init__(self, tHandle: str, nwItem: NWItem) -> None: + def __init__(self, tagsIndex: TagsIndex, tHandle: str, nwItem: NWItem) -> None: + self._tags = tagsIndex self._handle = tHandle self._item = nwItem - self._headings: dict[str, IndexHeading] = {TT_NONE: IndexHeading(TT_NONE)} + self._headings: dict[str, IndexHeading] = {TT_NONE: IndexHeading(self._tags, TT_NONE)} self._notes: dict[str, set[str]] = {} self._count = 0 return @@ -179,7 +181,7 @@ class IndexNode: """Unpack an item entry from the data.""" for key, entry in data.items(): if isTitleTag(key): - heading = IndexHeading(key) + heading = IndexHeading(self._tags, key) heading.unpackData(entry) self.addHeading(heading) elif key == "document": @@ -202,9 +204,16 @@ class IndexHeading: of all references made under the heading. """ - __slots__ = ("_key", "_line", "_level", "_title", "_counts", "_tag", "_refs", "_comments") + __slots__ = ( + "_tags", "_key", "_line", "_level", "_title", + "_counts", "_tag", "_refs", "_comments", + ) - def __init__(self, key: str, line: int = 0, level: str = "H0", title: str = "") -> None: + def __init__( + self, tagsIndex: TagsIndex, key: str, line: int = 0, + level: str = "H0", title: str = "", + ) -> None: + self._tags = tagsIndex self._key = key self._line = line self._level = level @@ -314,6 +323,27 @@ class IndexHeading: self._refs[tag].add(keyword) return + ## + # Getters + ## + + def getReferences(self) -> dict[str, list[str]]: + """Extract all references for this heading.""" + refs = {x: [] for x in nwKeyWords.VALID_KEYS} + for tag, types in self._refs.items(): + for keyword in types: + if keyword in refs: + refs[keyword].append(self._tags.tagName(tag)) + return refs + + def getReferencesByKeyword(self, keyword: str) -> list[str]: + """Extract all references for this heading.""" + refs = [] + for tag, types in self._refs.items(): + if keyword in types: + refs.append(self._tags.tagName(tag)) + return refs + ## # Data Methods ## diff --git a/novelwriter/core/novelmodel.py b/novelwriter/core/novelmodel.py index e52b3bc2..5c99d7a5 100644 --- a/novelwriter/core/novelmodel.py +++ b/novelwriter/core/novelmodel.py @@ -30,7 +30,7 @@ from PyQt6.QtCore import QAbstractTableModel, QModelIndex, Qt from PyQt6.QtGui import QIcon, QPixmap from novelwriter import SHARED -from novelwriter.constants import nwKeyWords, nwStyles +from novelwriter.constants import nwKeyWords, nwLabels, nwStyles, trConst from novelwriter.core.indexdata import IndexHeading, IndexNode from novelwriter.enum import nwNovelExtra from novelwriter.error import logException @@ -52,7 +52,7 @@ T_NodeData = str | tuple[str, str] | QIcon | QPixmap | Qt.AlignmentFlag | None class NovelModel(QAbstractTableModel): - __slots__ = ("_rows", "_header", "_more", "_columns", "_extra") + __slots__ = ("_rows", "_header", "_more", "_columns", "_extraKey", "_extraLabel") def __init__(self) -> None: super().__init__() @@ -60,7 +60,8 @@ class NovelModel(QAbstractTableModel): self._header: list[QSize] = [] self._more = SHARED.theme.getIcon("more_arrow") self._columns = 3 - self._extra = "" + self._extraKey = "" + self._extraLabel = "" return def __del__(self) -> None: # pragma: no cover @@ -85,16 +86,20 @@ class NovelModel(QAbstractTableModel): match extra: case nwNovelExtra.HIDDEN: self._columns = 3 - self._extra = "" + self._extraKey = "" + self._extraLabel = "" case nwNovelExtra.POV: self._columns = 4 - self._extra = nwKeyWords.POV_KEY + self._extraKey = nwKeyWords.POV_KEY + self._extraLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY]) case nwNovelExtra.FOCUS: self._columns = 4 - self._extra = nwKeyWords.FOCUS_KEY + self._extraKey = nwKeyWords.FOCUS_KEY + self._extraLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY]) case nwNovelExtra.PLOT: self._columns = 4 - self._extra = nwKeyWords.PLOT_KEY + self._extraKey = nwKeyWords.PLOT_KEY + self._extraLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY]) return ## @@ -209,6 +214,7 @@ class NovelModel(QAbstractTableModel): """Generate a cache entry.""" iLevel = nwStyles.H_LEVEL.get(heading.level, 0) data = {} + data[C_FACTOR*0 | R_TIP] = heading.title 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}" @@ -216,8 +222,10 @@ class NovelModel(QAbstractTableModel): if self._columns == 3: data[C_FACTOR*2 | R_ICON] = self._more else: - data[C_FACTOR*2 | R_TIP] = "Hello World" - data[C_FACTOR*2 | R_TEXT] = "Hello World" + if self._extraKey and (refs := heading.getReferencesByKeyword(self._extraKey)): + text = ", ".join(refs) + data[C_FACTOR*2 | R_TEXT] = text + data[C_FACTOR*2 | R_TIP] = f"{self._extraLabel}: {text}" data[C_FACTOR*3 | R_ICON] = self._more data[R_HANDLE] = handle data[R_KEY] = key diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py index c26d0fdd..6732fb24 100644 --- a/novelwriter/gui/noveltree.py +++ b/novelwriter/gui/noveltree.py @@ -383,14 +383,8 @@ class GuiNovelTree(NTreeView): self._actHandle = None self._lastColType = nwNovelExtra.POV self._lastColSize = 0.25 - # self._lastBuild = 0 - # self._treeMap: dict[str, QTreeWidgetItem] = {} - - # Cached Strings - # self._povLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY]) - # self._focLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY]) - # self._pltLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY]) + # Widget Setup self.setIconSize(SHARED.theme.baseIconSize) self.setFrameStyle(QFrame.Shape.NoFrame) self.setUniformRowHeights(True) @@ -569,25 +563,26 @@ class GuiNovelTree(NTreeView): logger.debug("Generating meta data tooltip for '%s:%s'", tHandle, sTitle) if synopsis := head.synopsis: label = trConst(nwLabels.OUTLINE_COLS[nwOutline.SYNOP]) - synopsis = f"

{label}: {synopsis}

" + synopsis = f"

{label}: {synopsis}

" - def appendTags(refs: dict, key: str, lines: list[str]) -> list[str]: + def appendTags(refs: dict, key: str, lines: list[str]) -> None: """Generate a reference list for a given reference key.""" if tags := ", ".join(refs.get(key, [])): - lines.append(f"{trConst(nwLabels.KEY_NAME[key])}: {tags}") - return lines + lines.append(f"{trConst(nwLabels.KEY_NAME[key])}: {tags}") + return - tags = SHARED.project.index.getReferences(tHandle, sTitle) lines = [] - lines = appendTags(tags, nwKeyWords.POV_KEY, lines) - lines = appendTags(tags, nwKeyWords.FOCUS_KEY, lines) - lines = appendTags(tags, nwKeyWords.CHAR_KEY, lines) - lines = appendTags(tags, nwKeyWords.PLOT_KEY, lines) - lines = appendTags(tags, nwKeyWords.TIME_KEY, lines) - lines = appendTags(tags, nwKeyWords.WORLD_KEY, lines) - lines = appendTags(tags, nwKeyWords.OBJECT_KEY, lines) - lines = appendTags(tags, nwKeyWords.ENTITY_KEY, lines) - lines = appendTags(tags, nwKeyWords.CUSTOM_KEY, lines) + if head := SHARED.project.index.getItemHeading(tHandle, sTitle): + tags = head.getReferences() + appendTags(tags, nwKeyWords.POV_KEY, lines) + appendTags(tags, nwKeyWords.FOCUS_KEY, lines) + appendTags(tags, nwKeyWords.CHAR_KEY, lines) + appendTags(tags, nwKeyWords.PLOT_KEY, lines) + appendTags(tags, nwKeyWords.TIME_KEY, lines) + appendTags(tags, nwKeyWords.WORLD_KEY, lines) + appendTags(tags, nwKeyWords.OBJECT_KEY, lines) + appendTags(tags, nwKeyWords.ENTITY_KEY, lines) + appendTags(tags, nwKeyWords.CUSTOM_KEY, lines) text = "" if lines: @@ -596,233 +591,3 @@ class GuiNovelTree(NTreeView): if tooltip := (text + synopsis or self.tr("No meta data")): QToolTip.showText(qPos, tooltip) return - - ## - # Old Code - ## - - ## - # Class Methods - ## - - # def clearContent(self) -> None: - # """Clear the GUI content and the related maps.""" - # self.clear() - # self._treeMap = {} - # self._lastBuild = 0 - # return - - # def refreshTree(self, rootHandle: str | None = None, overRide: bool = False) -> None: - # """Refresh the tree if it has been changed.""" - # logger.debug("Requesting refresh of the novel tree") - # if rootHandle is None: - # rootHandle = SHARED.project.tree.findRoot(nwItemClass.NOVEL) - - # titleKey = None - # if selItems := self.selectedItems(): - # titleKey = selItems[0].data(self.C_DATA, self.D_KEY) - - # self._populateTree(rootHandle) - # SHARED.project.data.setLastHandle(rootHandle, "novelTree") - - # if titleKey is not None and titleKey in self._treeMap: - # self._treeMap[titleKey].setSelected(True) - - # return - - # def refreshHandle(self, tHandle: str) -> None: - # """Refresh the data for a given handle.""" - # if idxData := SHARED.project.index.getItemData(tHandle): - # logger.debug("Refreshing meta data for item '%s'", tHandle) - # for sTitle, tHeading in idxData.items(): - # sKey = f"{tHandle}:{sTitle}" - # if trItem := self._treeMap.get(sKey, None): - # self._updateTreeItemValues(trItem, tHeading, tHandle, sTitle) - # else: - # logger.debug("Heading '%s' not in novel tree", sKey) - # self.refreshTree() - # return - # return - - # def setLastColType(self, colType: NovelTreeColumn, doRefresh: bool = True) -> None: - # """Change the content type of the last column and rebuild.""" - # if self._lastCol != colType: - # logger.debug("Changing last column to %s", colType.name) - # self._lastCol = colType - # self.setColumnHidden(self.C_EXTRA, colType == NovelTreeColumn.HIDDEN) - # if doRefresh: - # lastNovel = SHARED.project.data.getLastHandle("novelTree") - # self.refreshTree(rootHandle=lastNovel, overRide=True) - # return - - # def setActiveHandle(self, tHandle: str | None) -> None: - # """Highlight the rows associated with a given handle.""" - # didScroll = False - # brushOn = self.palette().alternateBase() - # brushOff = self.palette().base() - # if pHandle := self._actHandle: - # for key, item in self._treeMap.items(): - # if key.startswith(pHandle): - # for i in range(self.columnCount()): - # item.setBackground(i, brushOff) - # if tHandle: - # for key, item in self._treeMap.items(): - # if key.startswith(tHandle): - # for i in range(self.columnCount()): - # item.setBackground(i, brushOn) - # if not didScroll: - # self.scrollToItem(item, QAbstractItemView.ScrollHint.PositionAtCenter) - # didScroll = True - # self._actHandle = tHandle or None - # return - - ## - # Events - ## - - # def mousePressEvent(self, event: QMouseEvent) -> None: - # """Overload mousePressEvent to clear selection if clicking the - # mouse in a blank area of the tree view, and to load a document - # for viewing if the user middle-clicked. - # """ - # super().mousePressEvent(event) - - # if event.button() == QtMouseLeft: - # selItem = self.indexAt(event.pos()) - # if not selItem.isValid(): - # self.clearSelection() - - # elif event.button() == QtMouseMiddle: - # selItem = self.itemAt(event.pos()) - # if not isinstance(selItem, QTreeWidgetItem): - # return - - # tHandle, sTitle = self.getSelectedHandle() - # if tHandle is None: - # return - - # self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, sTitle or "", False) - - # return - - # def focusOutEvent(self, event: QFocusEvent) -> None: - # """Clear the selection when the tree no longer has focus.""" - # super().focusOutEvent(event) - # self.clearSelection() - # return - - ## - # Private Slots - ## - - # @pyqtSlot("QModelIndex") - # def _treeItemClicked(self, index: QModelIndex) -> None: - # """The user clicked on an item in the tree.""" - # if index.column() == self.C_MORE: - # tHandle = index.siblingAtColumn(self.C_DATA).data(self.D_HANDLE) - # sTitle = index.siblingAtColumn(self.C_DATA).data(self.D_TITLE) - # tipPos = self.mapToGlobal(self.visualRect(index).topRight()) - # self._popMetaBox(tipPos, tHandle, sTitle) - # return - - # @pyqtSlot() - # def _treeSelectionChange(self) -> None: - # """Extract the handle and line number of the currently selected - # title, and send it to the tree meta panel. - # """ - # tHandle, _ = self.getSelectedHandle() - # if tHandle is not None: - # self.novelView.selectedItemChanged.emit(tHandle) - # return - - # @pyqtSlot("QTreeWidgetItem*", int) - # def _treeDoubleClick(self, item: QTreeWidgetItem, column: int) -> None: - # """Extract the handle and line number of the title double- - # clicked, and send it to the main gui class for opening in the - # document editor. - # """ - # tHandle, sTitle = self.getSelectedHandle() - # self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, sTitle or "", True) - # return - - ## - # Internal Functions - ## - - # def _populateTree(self, rootHandle: str | None) -> None: - # """Build the tree based on the project index.""" - # self.clearContent() - # tStart = time() - # logger.debug("Building novel tree for root item '%s'", rootHandle) - - # novStruct = SHARED.project.index.novelStructure(rootHandle=rootHandle, activeOnly=True) - # for tKey, tHandle, sTitle, novIdx in novStruct: - # if novIdx.level == "H0": - # continue - - # newItem = QTreeWidgetItem() - # newItem.setData(self.C_DATA, self.D_HANDLE, tHandle) - # newItem.setData(self.C_DATA, self.D_TITLE, sTitle) - # newItem.setData(self.C_DATA, self.D_KEY, tKey) - # newItem.setTextAlignment(self.C_WORDS, QtAlignRight) - - # self._updateTreeItemValues(newItem, novIdx, tHandle, sTitle) - # self._treeMap[tKey] = newItem - # self.addTopLevelItem(newItem) - - # self.setActiveHandle(self._actHandle) - - # logger.debug("Novel Tree built in %.3f ms", (time() - tStart)*1000) - # self._lastBuild = time() - - # return - - # def _updateTreeItemValues( - # self, trItem: QTreeWidgetItem, idxItem: IndexHeading, tHandle: str, sTitle: str - # ) -> None: - # """Set the tree item values from the index entry.""" - # iLevel = nwStyles.H_LEVEL.get(idxItem.level, 0) - # hDec = SHARED.theme.getHeaderDecoration(iLevel) - - # trItem.setData(self.C_TITLE, QtDecoration, hDec) - # trItem.setText(self.C_TITLE, idxItem.title) - # trItem.setFont(self.C_TITLE, self._hFonts[iLevel]) - # trItem.setText(self.C_WORDS, f"{idxItem.wordCount:n}") - # trItem.setData(self.C_MORE, QtDecoration, self._pMore) - - # # Custom column - # viewport = self.viewport() - # mW = int(self._lastColSize * (viewport.width() if viewport else 100)) - # lastText, toolTip = self._getLastColumnText(tHandle, sTitle) - # elideText = self.fontMetrics().elidedText(lastText, Qt.TextElideMode.ElideRight, mW) - # trItem.setText(self.C_EXTRA, elideText) - # trItem.setData(self.C_DATA, self.D_EXTRA, lastText) - # trItem.setToolTip(self.C_EXTRA, toolTip) - - # return - - # def _getLastColumnText(self, tHandle: str, sTitle: str) -> tuple[str, str]: - # """Generate text for the last column based on user settings.""" - # if self._lastCol == NovelTreeColumn.HIDDEN: - # return "", "" - - # refData = [] - # refName = "" - # refs = SHARED.project.index.getReferences(tHandle, sTitle) - # if self._lastCol == NovelTreeColumn.POV: - # refData = refs[nwKeyWords.POV_KEY] - # refName = self._povLabel - - # elif self._lastCol == NovelTreeColumn.FOCUS: - # refData = refs[nwKeyWords.FOCUS_KEY] - # refName = self._focLabel - - # elif self._lastCol == NovelTreeColumn.PLOT: - # refData = refs[nwKeyWords.PLOT_KEY] - # refName = self._pltLabel - - # if refData: - # toolText = ", ".join(refData) - # return toolText, f"{refName}: {toolText}" - - # return "", "" diff --git a/tests/test_core/test_core_indexdata.py b/tests/test_core/test_core_indexdata.py index e8436825..5767a669 100644 --- a/tests/test_core/test_core_indexdata.py +++ b/tests/test_core/test_core_indexdata.py @@ -22,6 +22,7 @@ from __future__ import annotations import pytest +from novelwriter.core.index import TagsIndex from novelwriter.core.indexdata import IndexHeading, IndexNode from novelwriter.core.item import NWItem from novelwriter.core.project import NWProject @@ -33,9 +34,10 @@ def testCoreIndexData_IndexNode(mockGUI): handle = "0123456789abc" project = NWProject() item = NWItem(project, handle) + tags = TagsIndex() # Defaults - node = IndexNode(handle, item) + node = IndexNode(tags, handle, item) assert node.handle == handle assert node.item is item assert str(node) == f"" @@ -44,8 +46,8 @@ def testCoreIndexData_IndexNode(mockGUI): assert "T0000" in node # Placeholder heading # Add a heading - head1 = IndexHeading(node.nextHeading(), line=1, level="H1", title="Heading 1") - head2 = IndexHeading(node.nextHeading(), line=10, level="H2", title="Heading 2") + head1 = IndexHeading(tags, node.nextHeading(), line=1, level="H1", title="Heading 1") + head2 = IndexHeading(tags, node.nextHeading(), line=10, level="H2", title="Heading 2") node.addHeading(head1) node.addHeading(head2) assert len(node) == 2 @@ -105,11 +107,12 @@ def testCoreIndexData_IndexNodePackUnpack(mockGUI): handle = "0123456789abc" project = NWProject() item = NWItem(project, handle) - node = IndexNode(handle, item) + tags = TagsIndex() + node = IndexNode(tags, handle, item) # Add some headings and notes - head1 = IndexHeading(node.nextHeading(), line=1, level="H1", title="Heading 1") - head2 = IndexHeading(node.nextHeading(), line=10, level="H2", title="Heading 2") + head1 = IndexHeading(tags, node.nextHeading(), line=1, level="H1", title="Heading 1") + head2 = IndexHeading(tags, node.nextHeading(), line=10, level="H2", title="Heading 2") node.addHeading(head1) node.addHeading(head2) node.setHeadingCounts("T0001", 42, 13, 3) @@ -128,7 +131,7 @@ def testCoreIndexData_IndexNodePackUnpack(mockGUI): assert set(data["document"]["footnotes"]) == {"key1", "key2"} # Create a new node - new = IndexNode(handle, item) + new = IndexNode(tags, handle, item) # Unpack heading one data = {"T0001": {"meta": { @@ -165,7 +168,8 @@ def testCoreIndexData_IndexNodePackUnpack(mockGUI): def testCoreIndexData_IndexHeading(): """Test the IndexHeading class.""" # Defaults - head = IndexHeading("T0001") + tags = TagsIndex() + head = IndexHeading(tags, "T0001") assert str(head) == "" assert repr(head) == "" assert head.key == "T0001" @@ -234,11 +238,13 @@ def testCoreIndexData_IndexHeading(): @pytest.mark.core def testCoreIndexData_IndexHeadingUnpackMeta(): """Test IndexHeading class meta unpacking.""" + tags = TagsIndex() + # Valid data = {"meta": { "level": "H1", "title": "So it Begins", "line": 1, "tag": "begins", "counts": [95, 18, 1] }} - head = IndexHeading("T0001") + head = IndexHeading(tags, "T0001") head.unpackData(data) assert head.level == "H1" assert head.title == "So it Begins" @@ -252,7 +258,7 @@ def testCoreIndexData_IndexHeadingUnpackMeta(): data = {"meta": { "level": "H9", "title": None, "line": None, "tag": None, "counts": [42] }} - head = IndexHeading("T0001") + head = IndexHeading(tags, "T0001") head.unpackData(data) assert head.level == "H0" assert head.title == "None" @@ -264,7 +270,7 @@ def testCoreIndexData_IndexHeadingUnpackMeta(): # Empty data = {"meta": {}} - head = IndexHeading("T0001") + head = IndexHeading(tags, "T0001") head.unpackData(data) assert head.level == "H0" assert head.title == "" @@ -278,11 +284,13 @@ def testCoreIndexData_IndexHeadingUnpackMeta(): @pytest.mark.core def testCoreIndexData_IndexHeadingUnpackRefs(): """Test IndexHeading class refs unpacking.""" + tags = TagsIndex() + # Valid data = {"refs": { "jane": "@char,@pov", "john": "@char", "earth": "@location", "space": "@mention,@location" }} - head = IndexHeading("T0001") + head = IndexHeading(tags, "T0001") head.unpackData(data) assert head.references["jane"] == {"@char", "@pov"} assert head.references["john"] == {"@char"} @@ -291,18 +299,18 @@ def testCoreIndexData_IndexHeadingUnpackRefs(): # Invalid key data = {"refs": {0: "@char,@pov"}} - head = IndexHeading("T0001") + head = IndexHeading(tags, "T0001") with pytest.raises(ValueError, match="Heading reference key must be a string"): head.unpackData(data) # Invalid value data = {"refs": {"jane": None}} - head = IndexHeading("T0001") + head = IndexHeading(tags, "T0001") with pytest.raises(ValueError, match="Heading reference value must be a string"): head.unpackData(data) # Invalid keyword data = {"refs": {"jane": "@char,@pov,@stuff"}} - head = IndexHeading("T0001") + head = IndexHeading(tags, "T0001") with pytest.raises(ValueError, match="Heading reference contains an invalid keyword"): head.unpackData(data) diff --git a/tests/test_core/test_core_options.py b/tests/test_core/test_core_options.py index 1db14e13..51a45c8c 100644 --- a/tests/test_core/test_core_options.py +++ b/tests/test_core/test_core_options.py @@ -27,7 +27,7 @@ import pytest from novelwriter.constants import nwFiles from novelwriter.core.options import OptionState from novelwriter.core.project import NWProject -from novelwriter.gui.noveltree import NovelTreeColumn +from novelwriter.enum import nwNovelExtra from tests.mocked import causeOSError @@ -110,7 +110,7 @@ def testCoreOptions_SetGet(mockGUI): project = NWProject() options = OptionState(project) - nwColHidden = NovelTreeColumn.HIDDEN + nwColHidden = nwNovelExtra.HIDDEN # Set invalid values assert options.setValue("MockGroup", "mockItem", None) is False @@ -141,7 +141,7 @@ def testCoreOptions_SetGet(mockGUI): assert options.getFloat("GuiNovelDetails", "mockItem", None) is None # type: ignore assert options.getBool("GuiNovelDetails", "clearDouble", None) is True # type: ignore assert options.getBool("GuiNovelDetails", "mockItem", None) is None # type: ignore - assert options.getEnum("GuiNovelView", "lastCol", NovelTreeColumn, nwColHidden) == nwColHidden + assert options.getEnum("GuiNovelView", "lastCol", nwNovelExtra, nwColHidden) == nwColHidden # Get from non-existent groups assert options.getValue("SomeGroup", "mockItem", None) is None @@ -149,4 +149,4 @@ def testCoreOptions_SetGet(mockGUI): assert options.getInt("SomeGroup", "mockItem", None) is None # type: ignore assert options.getFloat("SomeGroup", "mockItem", None) is None # type: ignore assert options.getBool("SomeGroup", "mockItem", None) is None # type: ignore - assert options.getEnum("SomeGroup", "mockItem", NovelTreeColumn, None) is None # type: ignore + assert options.getEnum("SomeGroup", "mockItem", nwNovelExtra, None) is None # type: ignore diff --git a/tests/test_gui/test_gui_noveltree.py b/tests/test_gui/test_gui_noveltree.py index 9ec5f352..ee70b216 100644 --- a/tests/test_gui/test_gui_noveltree.py +++ b/tests/test_gui/test_gui_noveltree.py @@ -30,8 +30,8 @@ from PyQt6.QtWidgets import QInputDialog, QToolTip from novelwriter import CONFIG, SHARED from novelwriter.dialogs.editlabel import GuiEditLabel -from novelwriter.enum import nwFocus, nwItemType -from novelwriter.gui.noveltree import GuiNovelTree, NovelTreeColumn +from novelwriter.enum import nwFocus, nwItemType, nwNovelExtra +from novelwriter.gui.noveltree import GuiNovelTree from novelwriter.types import QtMouseLeft, QtMouseMiddle from tests.tools import C, buildTestProject @@ -143,28 +143,28 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd): # Last Column # =========== - novelBar.setLastColType(NovelTreeColumn.HIDDEN) + novelBar.setLastColType(nwNovelExtra.HIDDEN) assert novelTree.isColumnHidden(novelTree.C_EXTRA) is True - assert novelTree.lastColType == NovelTreeColumn.HIDDEN + assert novelTree.lastColType == nwNovelExtra.HIDDEN assert novelTree._getLastColumnText(C.hSceneDoc, "T0001") == ("", "") - novelBar.setLastColType(NovelTreeColumn.PLOT) + novelBar.setLastColType(nwNovelExtra.PLOT) assert novelTree.isColumnHidden(novelTree.C_EXTRA) is False - assert novelTree.lastColType == NovelTreeColumn.PLOT + assert novelTree.lastColType == nwNovelExtra.PLOT assert novelTree._getLastColumnText(C.hSceneDoc, "T0001") == ( "", "" ) - novelBar.setLastColType(NovelTreeColumn.FOCUS) + novelBar.setLastColType(nwNovelExtra.FOCUS) assert novelTree.isColumnHidden(novelTree.C_EXTRA) is False - assert novelTree.lastColType == NovelTreeColumn.FOCUS + assert novelTree.lastColType == nwNovelExtra.FOCUS assert novelTree._getLastColumnText(C.hSceneDoc, "T0001") == ( "Jane", "Focus: Jane" ) - novelBar.setLastColType(NovelTreeColumn.POV) + novelBar.setLastColType(nwNovelExtra.POV) assert novelTree.isColumnHidden(novelTree.C_EXTRA) is False - assert novelTree.lastColType == NovelTreeColumn.POV + assert novelTree.lastColType == nwNovelExtra.POV assert novelTree._getLastColumnText(C.hSceneDoc, "T0001") == ( "Jane", "Point of View: Jane" )