Clean up config and improve project tree test coverage (#1607)

This commit is contained in:
Veronica Berglyd Olsen
2023-11-17 21:38:42 +01:00
committed by GitHub
4 changed files with 192 additions and 87 deletions
+4 -24
View File
@@ -181,7 +181,7 @@ class Config:
# State
self.showRefPanel = True # The reference panel for the viewer is visible
self.showEditToolBar = False # The document editor toolbar visibility
self.useShortcodes = False # Use shorcodes for basic formatting
self.useShortcodes = False # Use shortcodes for basic formatting
self.viewComments = True # Comments are shown in the viewer
self.viewSynopsis = True # Synopsis is shown in the viewer
@@ -392,8 +392,7 @@ class Config:
return self._appPath / "assets"
def lastPath(self) -> Path:
"""Return the last path used by the user, but ensure it exists.
"""
"""Return the last path used by the user, if it exists."""
if isinstance(self._lastPath, Path):
if self._lastPath.is_dir():
return self._lastPath
@@ -401,9 +400,8 @@ class Config:
def backupPath(self) -> Path:
"""Return the backup path."""
if isinstance(self._backupPath, Path):
if self._backupPath.is_dir():
return self._backupPath
if isinstance(self._backupPath, Path) and self._backupPath.is_dir():
return self._backupPath
return self._backPath
def errorText(self) -> str:
@@ -614,24 +612,6 @@ class Config:
self.searchNextFile = conf.rdBool(sec, "searchnextfile", self.searchNextFile)
self.searchMatchCap = conf.rdBool(sec, "searchmatchcap", self.searchMatchCap)
# Deprecated Settings or Locations as of 2.0
# ToDo: These will be loaded for a few minor releases until the users have converted them
self.guiFont = conf.rdStr("Main", "guifont", self.guiFont)
self.guiFontSize = conf.rdInt("Main", "guifontsize", self.guiFontSize)
self.guiLocale = conf.rdStr("Main", "guilang", self.guiLocale)
self._backupPath = conf.rdPath("Backup", "backuppath", self._backupPath)
self.backupOnClose = conf.rdBool("Backup", "backuponclose", self.backupOnClose)
self.askBeforeBackup = conf.rdBool("Backup", "askbeforebackup", self.askBeforeBackup)
fmtSingleQuotes = conf.rdStrList(sec, "fmtsinglequote", [])
fmtDoubleQuotes = conf.rdStrList(sec, "fmtdoublequote", [])
if isinstance(fmtSingleQuotes, list) and len(fmtSingleQuotes) == 2:
self.fmtSQuoteOpen = fmtSingleQuotes[0]
self.fmtSQuoteClose = fmtSingleQuotes[1]
if isinstance(fmtDoubleQuotes, list) and len(fmtDoubleQuotes) == 2:
self.fmtDQuoteOpen = fmtDoubleQuotes[0]
self.fmtDQuoteClose = fmtDoubleQuotes[1]
# Check Values
# ============
+5 -5
View File
@@ -511,7 +511,7 @@ class GuiProjectTree(QTreeWidget):
self.setDragDropMode(QAbstractItemView.InternalMove)
self.setDropIndicatorShown(True)
# Disable built-in autoscroll as it isn't working in some Qt
# Disable built-in auto scroll as it isn't working in some Qt
# releases (see #1561) and instead use our own implementation
self.setAutoScroll(False)
@@ -533,7 +533,7 @@ class GuiProjectTree(QTreeWidget):
self.itemDoubleClicked.connect(self._treeDoubleClick)
self.itemSelectionChanged.connect(self._treeSelectionChange)
# Autoscroll
# Auto Scroll
self._scrollMargin = SHARED.theme.baseIconSize
self._scrollDirection = 0
self._scrollTimer = QTimer()
@@ -1415,7 +1415,7 @@ class GuiProjectTree(QTreeWidget):
return
def dragMoveEvent(self, event: QDragMoveEvent) -> None:
"""Capture the drag move event to enable edge autoscroll."""
"""Capture the drag move event to enable edge auto scroll."""
y = event.pos().y()
if y < self._scrollMargin:
if not self._scrollTimer.isActive():
@@ -1429,8 +1429,8 @@ class GuiProjectTree(QTreeWidget):
return
def dropEvent(self, event: QDropEvent) -> None:
"""Overload the drop item event to ensure relevant data has been
updated.
"""Overload the drop item event to ensure the drag and drop
action is allowed, and update relevant data.
"""
sHandle = self.getSelectedHandle()
sItem = self._getTreeItem(sHandle) if sHandle else None
+9 -7
View File
@@ -45,7 +45,7 @@ def testBaseConfig_Constructor(monkeypatch):
assert tstConf.osWindows is False
assert tstConf.osUnknown is False
# macOS
# MacOS
with monkeypatch.context() as mp:
mp.setattr("sys.platform", "darwin")
tstConf = Config()
@@ -225,6 +225,11 @@ def testBaseConfig_Methods(fncPath):
tmpStuff.rmdir()
assert tstConf.lastPath() == Path.home().absolute()
# Backup Path
assert tstConf.backupPath() == tstConf._backPath
tstConf.setBackupPath(fncPath)
assert tstConf.backupPath() == fncPath
# Recent Projects
assert isinstance(tstConf.recentProjects, RecentProjects)
@@ -233,8 +238,7 @@ def testBaseConfig_Methods(fncPath):
@pytest.mark.base
def testBaseConfig_SettersGetters(fncPath):
"""Set various sizes and positions
"""
"""Set various sizes and positions."""
tstConf = Config()
tstConf.initConfig(confPath=fncPath, dataPath=fncPath)
@@ -358,8 +362,7 @@ def testBaseConfig_SettersGetters(fncPath):
@pytest.mark.base
def testBaseConfig_Internal(monkeypatch, fncPath):
"""Check internal functions.
"""
"""Check internal functions."""
tstConf = Config()
tstConf.initConfig(confPath=fncPath, dataPath=fncPath)
@@ -381,8 +384,7 @@ def testBaseConfig_Internal(monkeypatch, fncPath):
@pytest.mark.base
def testBaseConfig_RecentCache(monkeypatch, tstPaths):
"""Test recent cache file.
"""
"""Test recent cache file."""
cacheFile = tstPaths.cnfDir / nwFiles.RECENT_FILE
recent = RecentProjects(CONFIG)
+174 -51
View File
@@ -27,8 +27,9 @@ from pathlib import Path
from tools import C, buildTestProject
from mocked import causeOSError
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMessageBox, QMenu, QTreeWidgetItem, QDialog
from PyQt5.QtGui import QDragMoveEvent, QDropEvent
from PyQt5.QtCore import QMimeData, QPoint, QTimer, Qt
from PyQt5.QtWidgets import QMessageBox, QMenu, QTreeWidget, QTreeWidgetItem, QDialog
from novelwriter import CONFIG, SHARED
from novelwriter.enum import nwItemLayout, nwItemType, nwItemClass
@@ -46,7 +47,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
projView = nwGUI.projView
projTree = nwGUI.projView.projTree
theProject = SHARED.project
project = SHARED.project
# Try to add item with no project
assert projView.projTree.newTreeItem(nwItemType.FILE) is False
@@ -66,7 +67,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
# Create root item
assert projView.projTree.newTreeItem(nwItemType.ROOT, nwItemClass.WORLD) is True
assert "0000000000010" in theProject.tree
assert "0000000000010" in project.tree
# File/Folder Items
# =================
@@ -81,51 +82,51 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
# Create new folder as child of Novel folder
projView.setSelectedHandle(C.hNovelRoot)
assert projView.projTree.newTreeItem(nwItemType.FOLDER) is True
assert theProject.tree["0000000000011"].itemParent == C.hNovelRoot
assert theProject.tree["0000000000011"].itemRoot == C.hNovelRoot
assert theProject.tree["0000000000011"].itemClass == nwItemClass.NOVEL
assert project.tree["0000000000011"].itemParent == C.hNovelRoot # type: ignore
assert project.tree["0000000000011"].itemRoot == C.hNovelRoot # type: ignore
assert project.tree["0000000000011"].itemClass == nwItemClass.NOVEL # type: ignore
# Add a new file in the new folder
projView.setSelectedHandle("0000000000011")
assert projView.projTree.newTreeItem(nwItemType.FILE) is True
assert theProject.tree["0000000000012"].itemParent == "0000000000011"
assert theProject.tree["0000000000012"].itemRoot == C.hNovelRoot
assert theProject.tree["0000000000012"].itemClass == nwItemClass.NOVEL
assert project.tree["0000000000012"].itemParent == "0000000000011" # type: ignore
assert project.tree["0000000000012"].itemRoot == C.hNovelRoot # type: ignore
assert project.tree["0000000000012"].itemClass == nwItemClass.NOVEL # type: ignore
# Add a new chapter next to the other new file
projView.setSelectedHandle("0000000000012")
assert projView.projTree.newTreeItem(nwItemType.FILE, hLevel=2) is True
assert theProject.tree["0000000000013"].itemParent == "0000000000011"
assert theProject.tree["0000000000013"].itemRoot == C.hNovelRoot
assert theProject.tree["0000000000013"].itemClass == nwItemClass.NOVEL
assert project.tree["0000000000013"].itemParent == "0000000000011" # type: ignore
assert project.tree["0000000000013"].itemRoot == C.hNovelRoot # type: ignore
assert project.tree["0000000000013"].itemClass == nwItemClass.NOVEL # type: ignore
assert nwGUI.openDocument("0000000000013")
assert nwGUI.docEditor.getText() == "## New Chapter\n\n"
# Add a new scene next to the other new file
projView.setSelectedHandle("0000000000012")
assert projView.projTree.newTreeItem(nwItemType.FILE, hLevel=3) is True
assert theProject.tree["0000000000014"].itemParent == "0000000000011"
assert theProject.tree["0000000000014"].itemRoot == C.hNovelRoot
assert theProject.tree["0000000000014"].itemClass == nwItemClass.NOVEL
assert project.tree["0000000000014"].itemParent == "0000000000011" # type: ignore
assert project.tree["0000000000014"].itemRoot == C.hNovelRoot # type: ignore
assert project.tree["0000000000014"].itemClass == nwItemClass.NOVEL # type: ignore
assert nwGUI.openDocument("0000000000014")
assert nwGUI.docEditor.getText() == "### New Scene\n\n"
# Add a new file to the characters folder
projView.setSelectedHandle(C.hCharRoot)
assert projView.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True) is True
assert theProject.tree["0000000000015"].itemParent == C.hCharRoot
assert theProject.tree["0000000000015"].itemRoot == C.hCharRoot
assert theProject.tree["0000000000015"].itemClass == nwItemClass.CHARACTER
assert project.tree["0000000000015"].itemParent == C.hCharRoot # type: ignore
assert project.tree["0000000000015"].itemRoot == C.hCharRoot # type: ignore
assert project.tree["0000000000015"].itemClass == nwItemClass.CHARACTER # type: ignore
assert nwGUI.openDocument("0000000000015")
assert nwGUI.docEditor.getText() == "# New Note\n\n"
# Make sure the sibling folder bug trap works
projView.setSelectedHandle("0000000000013")
theProject.tree["0000000000013"].setParent(None) # This should not happen
project.tree["0000000000013"].setParent(None) # This should not happen # type: ignore
caplog.clear()
assert projView.projTree.newTreeItem(nwItemType.FILE) is False
assert "Internal error" in caplog.text
theProject.tree["0000000000013"].setParent("0000000000011")
project.tree["0000000000013"].setParent("0000000000011") # type: ignore
# Cancel during creation
with monkeypatch.context() as mp:
@@ -135,7 +136,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
# Get the trash folder
projView.projTree._addTrashRoot()
trashHandle = theProject.trashFolder()
trashHandle = project.trashFolder()
projView.setSelectedHandle(trashHandle)
assert projView.projTree.newTreeItem(nwItemType.FILE) is False
assert "Cannot add new files or folders to the Trash folder" in caplog.text
@@ -147,7 +148,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
with monkeypatch.context() as mp:
mp.setattr(GuiEditLabel, "getLabel", lambda *a, **k: ("Stuff", True))
projTree.renameTreeItem(C.hPlotRoot) is True
assert theProject.tree[C.hPlotRoot].itemName == "Stuff"
assert project.tree[C.hPlotRoot].itemName == "Stuff" # type: ignore
# Rename invalid folder
projTree.renameTreeItem("0000000000000") is False
@@ -159,7 +160,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
assert projView.projTree.revealNewTreeItem("abc") is False
# Add an item that cannot be displayed in the tree
nHandle = theProject.newFile("Test", None)
nHandle = project.newFile("Test", None) # type: ignore
assert projView.projTree.revealNewTreeItem(nHandle) is False
# Adding an invalid item directly to the tree should also fail
@@ -550,7 +551,7 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
SHARED.project.newFile("SubNote", hNovelNote)
projTree.revealNewTreeItem(hSubNote)
assert SHARED.project.tree[hSubNote].itemParent == hNovelNote
assert SHARED.project.tree[hSubNote].itemParent == hNovelNote # type: ignore
def itemPos(tHandle):
return projTree.visualItemRect(projTree._getTreeItem(tHandle)).center()
@@ -579,6 +580,7 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
# =====================
# Trigger the dedicated functions the menu entries connect to
nwItem = SHARED.project.tree[hNovelNote]
assert nwItem is not None
# Toggle active flag
assert nwItem.isActive is True
@@ -619,17 +621,17 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
with monkeypatch.context() as mp:
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT)
assert SHARED.project.tree[hNewFolderOne].isFolderType()
assert SHARED.project.tree[hNewFolderOne].isFolderType() # type: ignore
# Convert the first folder to a document
projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT)
assert SHARED.project.tree[hNewFolderOne].isFileType()
assert SHARED.project.tree[hNewFolderOne].isDocumentLayout()
assert SHARED.project.tree[hNewFolderOne].isFileType() # type: ignore
assert SHARED.project.tree[hNewFolderOne].isDocumentLayout() # type: ignore
# Convert the second folder to a note
projTree._covertFolderToFile(hNewFolderTwo, nwItemLayout.NOTE)
assert SHARED.project.tree[hNewFolderTwo].isFileType()
assert SHARED.project.tree[hNewFolderTwo].isNoteLayout()
assert SHARED.project.tree[hNewFolderTwo].isFileType() # type: ignore
assert SHARED.project.tree[hNewFolderTwo].isNoteLayout() # type: ignore
# qtbot.stop()
@@ -646,19 +648,18 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
monkeypatch.setattr(GuiDocMerge, "result", lambda *a: QDialog.Accepted)
monkeypatch.setattr(GuiDocMerge, "getData", lambda *a: mergeData)
# Create a project
buildTestProject(nwGUI, projPath)
theProject = SHARED.project
project = SHARED.project
projTree = nwGUI.projView.projTree
mergedDoc1 = "0000000000014"
# Create File to Merge
hChapter1 = theProject.newFile("Chapter 1", C.hNovelRoot)
hSceneOne11 = theProject.newFile("Scene 1.1", hChapter1)
hSceneOne12 = theProject.newFile("Scene 1.2", hChapter1)
hSceneOne13 = theProject.newFile("Scene 1.3", hChapter1)
hChapter1 = project.newFile("Chapter 1", C.hNovelRoot)
hSceneOne11 = project.newFile("Scene 1.1", hChapter1) # type: ignore
hSceneOne12 = project.newFile("Scene 1.2", hChapter1) # type: ignore
hSceneOne13 = project.newFile("Scene 1.3", hChapter1) # type: ignore
docText1 = "\n\n".join(ipsumText[0:2]) + "\n\n"
docText2 = "\n\n".join(ipsumText[1:3]) + "\n\n"
@@ -671,10 +672,10 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
lenText4 = len(docText4)
lenAll = lenText1 + lenText2 + lenText3 + lenText4
theProject.writeNewFile(hChapter1, 2, True, docText1)
theProject.writeNewFile(hSceneOne11, 3, True, docText2)
theProject.writeNewFile(hSceneOne12, 3, True, docText3)
theProject.writeNewFile(hSceneOne13, 3, True, docText4)
project.writeNewFile(hChapter1, 2, True, docText1) # type: ignore
project.writeNewFile(hSceneOne11, 3, True, docText2) # type: ignore
project.writeNewFile(hSceneOne12, 3, True, docText3) # type: ignore
project.writeNewFile(hSceneOne13, 3, True, docText4) # type: ignore
projTree.revealNewTreeItem(hChapter1)
projTree.revealNewTreeItem(hSceneOne11)
@@ -705,7 +706,7 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
# The merge goes through
assert projTree._mergeDocuments(hChapter1, True) is True
assert len(theProject.storage.getDocument(mergedDoc1).readDocument()) > lenAll
assert len(project.storage.getDocument(mergedDoc1).readDocument()) > lenAll # type: ignore
# Merge to Existing Doc
# =====================
@@ -724,13 +725,13 @@ def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
# Successful merge, and move to trash
mergeData["moveToTrash"] = True
assert len(theProject.storage.getDocument(hChapter1).readDocument()) < lenAll
assert len(project.storage.getDocument(hChapter1).readDocument()) < lenAll # type: ignore
assert projTree._mergeDocuments(hChapter1, False) is True
assert len(theProject.storage.getDocument(hChapter1).readDocument()) > lenAll
assert len(project.storage.getDocument(hChapter1).readDocument()) > lenAll # type: ignore
assert theProject.tree.isTrash(hSceneOne11)
assert theProject.tree.isTrash(hSceneOne12)
assert theProject.tree.isTrash(hSceneOne13)
assert project.tree.isTrash(hSceneOne11) # type: ignore
assert project.tree.isTrash(hSceneOne12) # type: ignore
assert project.tree.isTrash(hSceneOne13) # type: ignore
# qtbot.stop()
@@ -770,7 +771,7 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
)
hSplitDoc = theProject.newFile("Split Doc", C.hNovelRoot)
theProject.writeNewFile(hSplitDoc, 1, True, docText)
theProject.writeNewFile(hSplitDoc, 1, True, docText) # type: ignore
projTree.revealNewTreeItem(hSplitDoc, nHandle=C.hNovelRoot, wordCount=True)
docText = f"# Split Doc\n\n{docText}"
@@ -835,7 +836,7 @@ def testGuiProjTree_SplitDocument(qtbot, monkeypatch, nwGUI, projPath, mockRnd,
assert tHandle in theProject.tree
assert (projPath / "content" / f"{tHandle}.nwd").is_file()
assert theProject.tree.isTrash(hSplitDoc) is True
assert theProject.tree.isTrash(hSplitDoc) is True # type: ignore
# Cancelled by user
with monkeypatch.context() as mp:
@@ -880,7 +881,7 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
assert projTree._duplicateFromHandle(C.hNovelRoot) is True
assert len(SHARED.project.tree) == 21
# Check tree order that all items are next to eachother
# Check tree order that all items are next to each other
assert SHARED.project.tree._order == [
C.hNovelRoot, C.hTitlePage, "0000000000010", C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
"0000000000011", "0000000000012", "0000000000013", "0000000000014", "0000000000015",
@@ -904,14 +905,136 @@ def testGuiProjTree_Duplicate(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mock
# END Test testGuiProjTree_Duplicate
@pytest.mark.gui
def testGuiProjTree_AutoScroll(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mockRnd):
"""Test the auto scroll feature."""
buildTestProject(nwGUI, projPath)
projTree: GuiProjectTree = nwGUI.projView.projTree
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda parent, text: (text, True))
monkeypatch.setattr(QTreeWidget, "dragMoveEvent", lambda *a, **k: None)
monkeypatch.setattr(QTimer, "isActive", lambda *a: False)
monkeypatch.setattr(QTimer, "start", lambda *a: None)
projTree.setSelectedHandle(C.hChapterDir, True)
projTree._getTreeItem(C.hChapterDir).setExpanded(True) # type: ignore
for i in range(100):
projTree.newTreeItem(nwItemType.FILE, None, 3, False)
projTree.setSelectedHandle("0000000000015", True)
nwGUI.resize(500, 500)
action = Qt.DropAction.MoveAction
mime = QMimeData()
mouse = Qt.MouseButton.LeftButton
modifier = Qt.KeyboardModifier.NoModifier
# Scroll Down
h = projTree.height()
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, h-1), action, mime, mouse, modifier))
assert projTree._scrollDirection == 1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, h-2), action, mime, mouse, modifier))
assert projTree._scrollDirection == 1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, h-3), action, mime, mouse, modifier))
assert projTree._scrollDirection == 1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, h-4), action, mime, mouse, modifier))
assert projTree._scrollDirection == 1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
# Scroll Up
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, 1), action, mime, mouse, modifier))
assert projTree._scrollDirection == -1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, 2), action, mime, mouse, modifier))
assert projTree._scrollDirection == -1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, 3), action, mime, mouse, modifier))
assert projTree._scrollDirection == -1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
projTree.dragMoveEvent(QDragMoveEvent(QPoint(1, 4), action, mime, mouse, modifier))
assert projTree._scrollDirection == -1
projTree._doAutoScroll()
assert projTree._scrollDirection == 0
# qtbot.stop()
# END Test testGuiProjTree_AutoScroll
@pytest.mark.gui
def testGuiProjTree_DragAndDrop(qtbot, monkeypatch, caplog, nwGUI: GuiMain, projPath, mockRnd):
"""Test the auto scroll feature."""
buildTestProject(nwGUI, projPath)
projTree: GuiProjectTree = nwGUI.projView.projTree
monkeypatch.setattr(QTreeWidget, "dropEvent", lambda *a, **k: None)
projTree.setSelectedHandle(C.hSceneDoc, True)
projTree._getTreeItem(C.hChapterDir).setExpanded(True) # type: ignore
nPos = projTree.visualItemRect(projTree._getTreeItem(C.hNovelRoot)).bottomLeft()
action = Qt.DropAction.MoveAction
mime = QMimeData()
mouse = Qt.MouseButton.LeftButton
modifier = Qt.KeyboardModifier.NoModifier
# Move an item
# The actual move is blocked, but the undo history should record
# the event, although without an actual move implied
assert projTree._lastMove == {}
event = QDropEvent(nPos, action, mime, mouse, modifier)
projTree.dropEvent(event)
assert projTree._lastMove == {
"item": projTree._getTreeItem(C.hSceneDoc),
"parent": projTree._getTreeItem(C.hChapterDir),
"index": 1,
}
# Invalid location
caplog.clear()
event = QDropEvent(QPoint(1000, 1000), action, mime, mouse, modifier)
projTree.dropEvent(event)
assert event.isAccepted() is False
assert "Invalid drop location" in caplog.text
# No item selected
caplog.clear()
event = QDropEvent(nPos, action, mime, mouse, modifier)
projTree.clearSelection()
projTree.dropEvent(event)
assert event.isAccepted() is False
assert "Invalid drag and drop event" in caplog.text
# Root item selected
caplog.clear()
event = QDropEvent(nPos, action, mime, mouse, modifier)
projTree.clearSelection()
projTree.setSelectedHandle(C.hNovelRoot, True)
projTree.dropEvent(event)
assert event.isAccepted() is False
assert "Invalid drag and drop event" in caplog.text
# qtbot.stop()
# END Test testGuiProjTree_DragAndDrop
@pytest.mark.gui
def testGuiProjTree_Other(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mockRnd):
"""Test various parts of the project tree class not covered by
other tests.
"""
# Create a project
buildTestProject(nwGUI, projPath)
projView: GuiProjectView = nwGUI.projView
projTree: GuiProjectTree = nwGUI.projView.projTree