Skip to content

Commit

Permalink
Update tests other than tree-related
Browse files Browse the repository at this point in the history
  • Loading branch information
vkbo committed Nov 23, 2024
1 parent ca8bd8d commit 1bf42ce
Show file tree
Hide file tree
Showing 29 changed files with 229 additions and 205 deletions.
7 changes: 6 additions & 1 deletion novelwriter/core/itemmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ def __repr__(self) -> str:
f"children={len(self._children)}>"
)

def __bool__(self) -> bool:
"""A node should always evaluate to True."""
return True

##
# Properties
##
Expand Down Expand Up @@ -190,10 +194,10 @@ def addChild(self, child: ProjectNode, pos: int = -1) -> None:
self._updateRelationships(child)
if 0 <= pos < len(self._children):
self._children.insert(pos, child)
self._refreshChildrenPos()
else:
child._row = len(self._children)
self._children.append(child)
self._refreshChildrenPos()
return

def takeChild(self, pos: int) -> ProjectNode | None:
Expand Down Expand Up @@ -229,6 +233,7 @@ def _refreshChildrenPos(self) -> None:
"""Update the row value on all children."""
for n, child in enumerate(self._children):
child._row = n
child.item.setOrder(n)
return

def _updateRelationships(self, child: ProjectNode) -> None:
Expand Down
13 changes: 13 additions & 0 deletions novelwriter/core/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
from novelwriter.core.projectdata import NWProjectData
from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLReadState
from novelwriter.core.sessions import NWSessionLog
from novelwriter.core.status import T_StatusKinds, T_UpdateEntry
from novelwriter.core.storage import NWStorage, NWStorageOpen
from novelwriter.core.tree import NWTree
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
Expand Down Expand Up @@ -531,6 +532,18 @@ def countStatus(self) -> None:
self._data.itemImport.increment(nwItem.itemImport)
return

def updateStatus(self, kind: T_StatusKinds, update: T_UpdateEntry) -> None:
"""Update status or import entries."""
if kind == "s":
self._data.itemStatus.update(update)
SHARED.projectSignalProxy({"event": "statusLabels", "kind": kind})
self._tree.refreshAllItems()
elif kind == "i":
self._data.itemImport.update(update)
SHARED.projectSignalProxy({"event": "statusLabels", "kind": kind})
self._tree.refreshAllItems()
return

def localLookup(self, word: str | int) -> str:
"""Look up a word or number in the translation map for the
project and return it. The variable is cast to a string before
Expand Down
11 changes: 5 additions & 6 deletions novelwriter/core/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ def duplicate(cls, source: StatusEntry) -> StatusEntry:

NO_ENTRY = StatusEntry("", QColor(0, 0, 0), nwStatusShape.SQUARE, QIcon(), 0)

T_UpdateEntry = list[tuple[str | None, StatusEntry]]
T_StatusKinds = Literal["s", "i"]


class NWStatus:

Expand All @@ -73,7 +76,7 @@ class NWStatus:

__slots__ = ("_store", "_default", "_prefix", "_height")

def __init__(self, prefix: Literal["s", "i"]) -> None:
def __init__(self, prefix: T_StatusKinds) -> None:
self._store: dict[str, StatusEntry] = {}
self._default = None
self._prefix = prefix[:1]
Expand Down Expand Up @@ -120,7 +123,7 @@ def add(self, key: str | None, name: str, color: tuple[int, int, int],

return key

def update(self, update: list[tuple[str | None, StatusEntry]]) -> None:
def update(self, update: T_UpdateEntry) -> None:
"""Update the list of statuses."""
self._store.clear()
for key, entry in update:
Expand All @@ -130,10 +133,6 @@ def update(self, update: list[tuple[str | None, StatusEntry]]) -> None:
if self._default not in self._store:
self._default = next(iter(self._store)) if self._store else None

# Emit the change signal and refresh tree
SHARED.projectSignalProxy({"event": "statusLabels", "kind": self._prefix})
SHARED.project.tree.refreshAllItems()

return

def check(self, value: str) -> str:
Expand Down
19 changes: 13 additions & 6 deletions novelwriter/core/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def add(self, item: NWItem, pos: int = -1) -> bool:
self._model.insertChild(node, index, pos)
self._nodes[item.itemHandle] = node
self._items[item.itemHandle] = item
self._itemChange(item.itemHandle, nwChange.CREATE)
self._itemChange(item, nwChange.CREATE)
else:
logger.error("Could not locate parent of '%s'", item.itemHandle)
return False
Expand All @@ -137,7 +137,7 @@ def add(self, item: NWItem, pos: int = -1) -> bool:
self._model.insertChild(node, QModelIndex(), pos)
self._nodes[item.itemHandle] = node
self._items[item.itemHandle] = item
self._itemChange(item.itemHandle, nwChange.CREATE)
self._itemChange(item, nwChange.CREATE)
else:
logger.error("Invalid project item '%s'", item.itemHandle)
return False
Expand All @@ -148,7 +148,7 @@ def remove(self, tHandle: str) -> bool:
if (node := self._nodes.get(tHandle)) and tHandle in self._items:
index = self._model.indexFromNode(node)
if index.isValid() and self._model.removeChild(index.parent(), index.row()):
self._itemChange(tHandle, nwChange.DELETE)
self._itemChange(node.item, nwChange.DELETE)
del self._nodes[tHandle]
del self._items[tHandle]
return True
Expand Down Expand Up @@ -246,7 +246,7 @@ def refreshItems(self, items: list[str]) -> None:
indexS = self._model.indexFromNode(node, 0)
indexE = self._model.indexFromNode(node, 3)
self._model.dataChanged.emit(indexS, indexE)
self._itemChange(tHandle, nwChange.UPDATE)
self._itemChange(node.item, nwChange.UPDATE)
return

def refreshAllItems(self) -> None:
Expand Down Expand Up @@ -464,11 +464,18 @@ def __iter__(self) -> Iterator[NWItem]:
# Internal Functions
##

def _itemChange(self, tHandle: str, change: nwChange) -> None:
def _itemChange(self, item: NWItem, change: nwChange) -> None:
"""Signal item change and notify project."""
tHandle = item.itemHandle
logger.debug("Item change: %s -> %s", tHandle, change.name)
self._project.setProjectChanged(True)
SHARED.projectSignalProxy({"event": "itemChanged", "handle": tHandle, "change": change})
SHARED.projectSignalProxy(
{"event": "itemChanged", "handle": tHandle, "change": change}
)
if item.isRootType():
SHARED.projectSignalProxy(
{"event": "rootChanged", "handle": tHandle, "change": change}
)
return

def _getTrashNode(self) -> ProjectNode | None:
Expand Down
4 changes: 2 additions & 2 deletions novelwriter/dialogs/projectsettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,11 @@ def _doSave(self) -> None:

if self.statusPage.changed:
logger.debug("Updating status labels")
project.data.itemStatus.update(self.statusPage.getNewList())
project.updateStatus("s", self.statusPage.getNewList())

if self.importPage.changed:
logger.debug("Updating importance labels")
project.data.itemImport.update(self.importPage.getNewList())
project.updateStatus("i", self.importPage.getNewList())

if self.replacePage.changed:
logger.debug("Updating auto-replace settings")
Expand Down
6 changes: 3 additions & 3 deletions novelwriter/gui/noveltree.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
from novelwriter.common import minmax, qtLambda
from novelwriter.constants import nwKeyWords, nwLabels, nwStyles, trConst
from novelwriter.core.index import IndexHeading
from novelwriter.enum import nwDocMode, nwItemClass, nwOutline
from novelwriter.enum import nwChange, nwDocMode, nwItemClass, nwOutline
from novelwriter.extensions.modified import NIconToolButton
from novelwriter.extensions.novelselector import NovelSelector
from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
Expand Down Expand Up @@ -174,8 +174,8 @@ def refreshTree(self) -> None:
self.novelTree.refreshTree(rootHandle=SHARED.project.data.getLastHandle("novelTree"))
return

@pyqtSlot(str)
def updateRootItem(self, tHandle: str) -> None:
@pyqtSlot(str, Enum)
def updateRootItem(self, tHandle: str, change: nwChange) -> None:
"""If any root item changes, rebuild the novel root menu."""
self.novelBar.buildNovelRootMenu()
return
Expand Down
21 changes: 10 additions & 11 deletions novelwriter/gui/outline.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
from novelwriter import CONFIG, SHARED
from novelwriter.common import checkInt, formatFileFilter, makeFileNameSafe
from novelwriter.constants import nwKeyWords, nwLabels, nwStats, nwStyles, trConst
from novelwriter.enum import nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline
from novelwriter.enum import nwChange, nwDocMode, nwItemClass, nwItemLayout, nwItemType, nwOutline
from novelwriter.error import logException
from novelwriter.extensions.configlayout import NColourLabel
from novelwriter.extensions.novelselector import NovelSelector
Expand Down Expand Up @@ -165,8 +165,8 @@ def treeHasFocus(self) -> bool:
# Public Slots
##

@pyqtSlot(str)
def updateRootItem(self, tHandle: str) -> None:
@pyqtSlot(str, Enum)
def updateRootItem(self, tHandle: str, change: nwChange) -> None:
"""Handle tasks whenever a root folders changes."""
self.outlineBar.populateNovelList()
self.outlineData.updateClasses()
Expand Down Expand Up @@ -380,8 +380,8 @@ def __init__(self, outlineView: GuiOutlineView) -> None:
self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
self.setExpandsOnDoubleClick(False)
self.setDragEnabled(False)
self.itemDoubleClicked.connect(self._treeDoubleClick)
self.itemSelectionChanged.connect(self._itemSelected)
self.itemDoubleClicked.connect(self._onItemDoubleClicked)
self.itemSelectionChanged.connect(self._onItemSelectionChanged)

self.setIconSize(SHARED.theme.baseIconSize)
self.setIndentation(0)
Expand Down Expand Up @@ -563,7 +563,7 @@ def exportOutline(self) -> None:
##

@pyqtSlot("QTreeWidgetItem*", int)
def _treeDoubleClick(self, tItem: QTreeWidgetItem, tCol: int) -> None:
def _onItemDoubleClicked(self, tItem: QTreeWidgetItem, tCol: 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.
Expand All @@ -574,14 +574,13 @@ def _treeDoubleClick(self, tItem: QTreeWidgetItem, tCol: int) -> None:
return

@pyqtSlot()
def _itemSelected(self) -> None:
def _onItemSelectionChanged(self) -> None:
"""Extract the handle and line number of the currently selected
title, and send it to the details panel.
"""
selItems = self.selectedItems()
if selItems:
tHandle = selItems[0].data(self._colIdx[nwOutline.TITLE], self.D_HANDLE)
sTitle = selItems[0].data(self._colIdx[nwOutline.TITLE], self.D_TITLE)
if items := self.selectedItems():
tHandle = items[0].data(self._colIdx[nwOutline.TITLE], self.D_HANDLE)
sTitle = items[0].data(self._colIdx[nwOutline.TITLE], self.D_TITLE)
self.activeItemChanged.emit(tHandle, sTitle)
return

Expand Down
20 changes: 8 additions & 12 deletions novelwriter/gui/projtree.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,9 @@ class GuiProjectView(QWidget):
available are mapped through to the project tree class.
"""

# Signals triggered when the meta data values of items change
rootFolderChanged = pyqtSignal(str)

# Signals for user interaction with the project tree
selectedItemChanged = pyqtSignal(str)
openDocumentRequest = pyqtSignal(str, Enum, str, bool)

# Requests for the main GUI
projectSettingsRequest = pyqtSignal(int)
selectedItemChanged = pyqtSignal(str)

def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
Expand Down Expand Up @@ -229,8 +223,8 @@ def createFileFromTemplate(self, tHandle: str) -> None:
self.projTree.newTreeItem(nwItemType.FILE, copyDoc=tHandle)
return

@pyqtSlot(str)
def updateRootItem(self, tHandle: str) -> None:
@pyqtSlot(str, Enum)
def updateRootItem(self, tHandle: str, change: nwChange) -> None:
"""Process root item changes."""
self.projBar.buildQuickLinksMenu()
return
Expand Down Expand Up @@ -625,9 +619,8 @@ def newTreeItem(
if root := SHARED.project.tree.nodes.get(itemRoot):
pos = root.row() + 1

SHARED.project.newRoot(itemClass, pos)
tHandle = SHARED.project.newRoot(itemClass, pos)
self.restoreExpandedState()
self.projView.rootFolderChanged.emit(tHandle)

elif itemType in (nwItemType.FILE, nwItemType.FOLDER):

Expand Down Expand Up @@ -684,7 +677,10 @@ def newTreeItem(
SHARED.project.index.reIndexHandle(tHandle)
SHARED.project.tree.refreshItems([tHandle])
else:
SHARED.project.newFolder(newLabel, sHandle, pos)
tHandle = SHARED.project.newFolder(newLabel, sHandle, pos)

# Select the new item automatically
self.setSelectedHandle(tHandle)

return

Expand Down
9 changes: 6 additions & 3 deletions novelwriter/guimain.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ def __init__(self) -> None:
SHARED.projectItemChanged.connect(self.projView.onProjectItemChanged)
SHARED.projectStatusChanged.connect(self.mainStatus.updateProjectStatus)
SHARED.projectStatusMessage.connect(self.mainStatus.setStatusMessage)
SHARED.rootFolderChanged.connect(self.novelView.updateRootItem)
SHARED.rootFolderChanged.connect(self.outlineView.updateRootItem)
SHARED.rootFolderChanged.connect(self.projView.updateRootItem)
SHARED.spellLanguageChanged.connect(self.mainStatus.setLanguage)
SHARED.statusLabelsChanged.connect(self.docViewerPanel.updateStatusLabels)

Expand All @@ -235,9 +238,6 @@ def __init__(self) -> None:

self.projView.openDocumentRequest.connect(self._openDocument)
self.projView.projectSettingsRequest.connect(self.showProjectSettingsDialog)
self.projView.rootFolderChanged.connect(self.novelView.updateRootItem)
self.projView.rootFolderChanged.connect(self.outlineView.updateRootItem)
self.projView.rootFolderChanged.connect(self.projView.updateRootItem)
self.projView.selectedItemChanged.connect(self.itemDetails.updateViewBox)

self.novelView.openDocumentRequest.connect(self._openDocument)
Expand Down Expand Up @@ -1083,6 +1083,9 @@ def _processConfigChanges(self, restart: bool, tree: bool, theme: bool, syntax:
self.projView.initSettings()
self.novelView.initSettings()
self.outlineView.initSettings()

# Force update of word count
self._lastTotalCount = 0
self._updateStatusWordCount()

return
Expand Down
5 changes: 5 additions & 0 deletions novelwriter/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class SharedData(QObject):
indexCleared = pyqtSignal()
mainClockTick = pyqtSignal()
projectItemChanged = pyqtSignal(str, Enum)
rootFolderChanged = pyqtSignal(str, Enum)
projectStatusChanged = pyqtSignal(bool)
projectStatusMessage = pyqtSignal(str)
spellLanguageChanged = pyqtSignal(str, str)
Expand Down Expand Up @@ -338,6 +339,10 @@ def projectSignalProxy(self, data: dict) -> None:
self.projectItemChanged.emit(
data.get("handle", ""), data.get("change", nwChange.UPDATE)
)
elif event == "rootChanged":
self.rootFolderChanged.emit(
data.get("handle", ""), data.get("change", nwChange.UPDATE)
)
return

##
Expand Down
18 changes: 5 additions & 13 deletions tests/mocked.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"""
from __future__ import annotations

from unittest.mock import MagicMock

from PyQt5.QtGui import QFont, QIcon, QPixmap
from PyQt5.QtWidgets import QWidget

Expand All @@ -28,7 +30,9 @@ class MockGuiMain(QWidget):

def __init__(self):
super().__init__()
self.mainStatus = MockStatusBar()
self.mainStatus = MagicMock()
self.docEditor = MagicMock()
self.docViewer = MagicMock()
self.projPath = ""
return

Expand All @@ -52,18 +56,6 @@ def close(self):
return "close"


class MockStatusBar:

def __init__(self):
return

def setStatus(self, text):
return

def updateProjectStatus(self, status):
return


class MockTheme:

def __init__(self):
Expand Down
Loading

0 comments on commit 1bf42ce

Please sign in to comment.