Add multi selection to project tree (#1612)
This commit is contained in:
+427
-352
File diff suppressed because it is too large
Load Diff
+410
-185
@@ -23,18 +23,20 @@ from __future__ import annotations
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from novelwriter.core.project import NWProject
|
||||||
|
|
||||||
from tools import C, buildTestProject
|
from tools import C, buildTestProject
|
||||||
from mocked import causeOSError
|
from mocked import causeOSError
|
||||||
|
|
||||||
from PyQt5.QtGui import QDragMoveEvent, QDropEvent
|
from PyQt5.QtGui import QDragEnterEvent, QDragMoveEvent, QDropEvent, QMouseEvent
|
||||||
from PyQt5.QtCore import QMimeData, QPoint, QTimer, Qt
|
from PyQt5.QtCore import QEvent, QMimeData, QPoint, QTimer, Qt
|
||||||
from PyQt5.QtWidgets import QMessageBox, QMenu, QTreeWidget, QTreeWidgetItem, QDialog
|
from PyQt5.QtWidgets import QMessageBox, QMenu, QTreeWidget, QTreeWidgetItem, QDialog
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
from novelwriter.enum import nwItemLayout, nwItemType, nwItemClass
|
from novelwriter.enum import nwItemLayout, nwItemType, nwItemClass, nwWidget
|
||||||
from novelwriter.guimain import GuiMain
|
from novelwriter.guimain import GuiMain
|
||||||
from novelwriter.gui.projtree import GuiProjectTree, GuiProjectView
|
from novelwriter.core.item import NWItem
|
||||||
|
from novelwriter.gui.projtree import GuiProjectTree, GuiProjectView, _TreeContextMenu
|
||||||
from novelwriter.dialogs.docmerge import GuiDocMerge
|
from novelwriter.dialogs.docmerge import GuiDocMerge
|
||||||
from novelwriter.dialogs.docsplit import GuiDocSplit
|
from novelwriter.dialogs.docsplit import GuiDocSplit
|
||||||
from novelwriter.dialogs.editlabel import GuiEditLabel
|
from novelwriter.dialogs.editlabel import GuiEditLabel
|
||||||
@@ -50,81 +52,84 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
|
|||||||
project = SHARED.project
|
project = SHARED.project
|
||||||
|
|
||||||
# Try to add item with no project
|
# Try to add item with no project
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FILE) is False
|
assert projTree.newTreeItem(nwItemType.FILE) is False
|
||||||
|
|
||||||
# Create a project
|
# Create a project
|
||||||
buildTestProject(nwGUI, projPath)
|
buildTestProject(nwGUI, projPath)
|
||||||
|
|
||||||
# No itemType set
|
# No itemType set
|
||||||
projView.projTree.clearSelection()
|
projTree.clearSelection()
|
||||||
assert projView.projTree.newTreeItem(None) is False
|
assert projTree.newTreeItem(None) is False
|
||||||
|
|
||||||
# Root Items
|
# Root Items
|
||||||
# ==========
|
# ==========
|
||||||
|
|
||||||
# No class set
|
# No class set
|
||||||
assert projView.projTree.newTreeItem(nwItemType.ROOT) is False
|
assert projTree.newTreeItem(nwItemType.ROOT) is False
|
||||||
|
|
||||||
# Create root item
|
# Create root item
|
||||||
assert projView.projTree.newTreeItem(nwItemType.ROOT, nwItemClass.WORLD) is True
|
assert projTree.newTreeItem(nwItemType.ROOT, nwItemClass.WORLD) is True
|
||||||
assert "0000000000010" in project.tree
|
assert "0000000000010" in project.tree
|
||||||
|
|
||||||
# File/Folder Items
|
# File/Folder Items
|
||||||
# =================
|
# =================
|
||||||
|
|
||||||
# No location selected for new item
|
# No location selected for new item
|
||||||
projView.projTree.clearSelection()
|
projTree.clearSelection()
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FILE) is False
|
assert projTree.newTreeItem(nwItemType.FILE) is False
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FOLDER) is False
|
assert projTree.newTreeItem(nwItemType.FOLDER) is False
|
||||||
assert "Did not find anywhere" in caplog.text
|
assert "Did not find anywhere" in caplog.text
|
||||||
|
|
||||||
# Create new folder as child of Novel folder
|
# Create new folder as child of Novel folder
|
||||||
projView.setSelectedHandle(C.hNovelRoot)
|
projView.setSelectedHandle(C.hNovelRoot)
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FOLDER) is True
|
assert projTree.newTreeItem(nwItemType.FOLDER) is True
|
||||||
assert project.tree["0000000000011"].itemParent == C.hNovelRoot # type: ignore
|
assert project.tree["0000000000011"].itemParent == C.hNovelRoot # type: ignore
|
||||||
assert project.tree["0000000000011"].itemRoot == C.hNovelRoot # type: ignore
|
assert project.tree["0000000000011"].itemRoot == C.hNovelRoot # type: ignore
|
||||||
assert project.tree["0000000000011"].itemClass == nwItemClass.NOVEL # type: ignore
|
assert project.tree["0000000000011"].itemClass == nwItemClass.NOVEL # type: ignore
|
||||||
|
|
||||||
# Add a new file in the new folder
|
# Add a new file in the new folder
|
||||||
projView.setSelectedHandle("0000000000011")
|
projView.setSelectedHandle("0000000000011")
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FILE) is True
|
assert projTree.newTreeItem(nwItemType.FILE) is True
|
||||||
assert project.tree["0000000000012"].itemParent == "0000000000011" # type: ignore
|
assert project.tree["0000000000012"].itemParent == "0000000000011" # type: ignore
|
||||||
assert project.tree["0000000000012"].itemRoot == C.hNovelRoot # type: ignore
|
assert project.tree["0000000000012"].itemRoot == C.hNovelRoot # type: ignore
|
||||||
assert project.tree["0000000000012"].itemClass == nwItemClass.NOVEL # type: ignore
|
assert project.tree["0000000000012"].itemClass == nwItemClass.NOVEL # type: ignore
|
||||||
|
|
||||||
# Add a new chapter next to the other new file
|
# Add a new chapter next to the other new file
|
||||||
projView.setSelectedHandle("0000000000012")
|
projView.setSelectedHandle("0000000000012")
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FILE, hLevel=2) is True
|
assert projTree.newTreeItem(nwItemType.FILE, hLevel=2) is True
|
||||||
assert project.tree["0000000000013"].itemParent == "0000000000011" # type: ignore
|
assert project.tree["0000000000013"].itemParent == "0000000000011" # type: ignore
|
||||||
assert project.tree["0000000000013"].itemRoot == C.hNovelRoot # type: ignore
|
assert project.tree["0000000000013"].itemRoot == C.hNovelRoot # type: ignore
|
||||||
assert project.tree["0000000000013"].itemClass == nwItemClass.NOVEL # type: ignore
|
assert project.tree["0000000000013"].itemClass == nwItemClass.NOVEL # type: ignore
|
||||||
assert nwGUI.openDocument("0000000000013")
|
assert nwGUI.openDocument("0000000000013")
|
||||||
assert nwGUI.docEditor.getText() == "## New Chapter\n\n"
|
assert nwGUI.docEditor.getText() == "## New Chapter\n\n"
|
||||||
|
assert projTree._getItemWordCount("0000000000013") == 2
|
||||||
|
|
||||||
# Add a new scene next to the other new file
|
# Add a new scene next to the other new file
|
||||||
projView.setSelectedHandle("0000000000012")
|
projView.setSelectedHandle("0000000000012")
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FILE, hLevel=3) is True
|
assert projTree.newTreeItem(nwItemType.FILE, hLevel=3) is True
|
||||||
assert project.tree["0000000000014"].itemParent == "0000000000011" # type: ignore
|
assert project.tree["0000000000014"].itemParent == "0000000000011" # type: ignore
|
||||||
assert project.tree["0000000000014"].itemRoot == C.hNovelRoot # type: ignore
|
assert project.tree["0000000000014"].itemRoot == C.hNovelRoot # type: ignore
|
||||||
assert project.tree["0000000000014"].itemClass == nwItemClass.NOVEL # type: ignore
|
assert project.tree["0000000000014"].itemClass == nwItemClass.NOVEL # type: ignore
|
||||||
assert nwGUI.openDocument("0000000000014")
|
assert nwGUI.openDocument("0000000000014")
|
||||||
assert nwGUI.docEditor.getText() == "### New Scene\n\n"
|
assert nwGUI.docEditor.getText() == "### New Scene\n\n"
|
||||||
|
assert projTree._getItemWordCount("0000000000014") == 2
|
||||||
|
|
||||||
# Add a new file to the characters folder
|
# Add a new file to the characters folder
|
||||||
projView.setSelectedHandle(C.hCharRoot)
|
projView.setSelectedHandle(C.hCharRoot)
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True) is True
|
assert projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True) is True
|
||||||
assert project.tree["0000000000015"].itemParent == C.hCharRoot # type: ignore
|
assert project.tree["0000000000015"].itemParent == C.hCharRoot # type: ignore
|
||||||
assert project.tree["0000000000015"].itemRoot == C.hCharRoot # type: ignore
|
assert project.tree["0000000000015"].itemRoot == C.hCharRoot # type: ignore
|
||||||
assert project.tree["0000000000015"].itemClass == nwItemClass.CHARACTER # type: ignore
|
assert project.tree["0000000000015"].itemClass == nwItemClass.CHARACTER # type: ignore
|
||||||
assert nwGUI.openDocument("0000000000015")
|
assert nwGUI.openDocument("0000000000015")
|
||||||
assert nwGUI.docEditor.getText() == "# New Note\n\n"
|
assert nwGUI.docEditor.getText() == "# New Note\n\n"
|
||||||
|
assert projTree._getItemWordCount("0000000000015") == 2
|
||||||
|
|
||||||
# Make sure the sibling folder bug trap works
|
# Make sure the sibling folder bug trap works
|
||||||
projView.setSelectedHandle("0000000000013")
|
projView.setSelectedHandle("0000000000013")
|
||||||
project.tree["0000000000013"].setParent(None) # This should not happen # type: ignore
|
project.tree["0000000000013"].setParent(None) # This should not happen # type: ignore
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FILE) is False
|
assert projTree.newTreeItem(nwItemType.FILE) is False
|
||||||
assert "Internal error" in caplog.text
|
assert "Internal error" in caplog.text
|
||||||
project.tree["0000000000013"].setParent("0000000000011") # type: ignore
|
project.tree["0000000000013"].setParent("0000000000011") # type: ignore
|
||||||
|
|
||||||
@@ -132,13 +137,17 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
|
|||||||
with monkeypatch.context() as mp:
|
with monkeypatch.context() as mp:
|
||||||
mp.setattr(GuiEditLabel, "getLabel", lambda *a, **k: ("", False))
|
mp.setattr(GuiEditLabel, "getLabel", lambda *a, **k: ("", False))
|
||||||
projView.setSelectedHandle("0000000000013")
|
projView.setSelectedHandle("0000000000013")
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FILE) is False
|
assert projTree.newTreeItem(nwItemType.FILE) is False
|
||||||
|
|
||||||
# Get the trash folder
|
# Get the trash folder
|
||||||
projView.projTree._addTrashRoot()
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(NWProject, "trashFolder", lambda *a: None)
|
||||||
|
assert projTree._addTrashRoot() is None
|
||||||
|
|
||||||
|
assert isinstance(projTree._addTrashRoot(), QTreeWidgetItem)
|
||||||
trashHandle = project.trashFolder()
|
trashHandle = project.trashFolder()
|
||||||
projView.setSelectedHandle(trashHandle)
|
projView.setSelectedHandle(trashHandle)
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FILE) is False
|
assert projTree.newTreeItem(nwItemType.FILE) is False
|
||||||
assert "Cannot add new files or folders to the Trash folder" in caplog.text
|
assert "Cannot add new files or folders to the Trash folder" in caplog.text
|
||||||
|
|
||||||
# Rename Item
|
# Rename Item
|
||||||
@@ -157,14 +166,14 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, projPath, mockRn
|
|||||||
# ============
|
# ============
|
||||||
|
|
||||||
# Also check error handling in reveal function
|
# Also check error handling in reveal function
|
||||||
assert projView.projTree.revealNewTreeItem("abc") is False
|
assert projTree.revealNewTreeItem("abc") is False
|
||||||
|
|
||||||
# Add an item that cannot be displayed in the tree
|
# Add an item that cannot be displayed in the tree
|
||||||
nHandle = project.newFile("Test", None) # type: ignore
|
nHandle = project.newFile("Test", None) # type: ignore
|
||||||
assert projView.projTree.revealNewTreeItem(nHandle) is False
|
assert projTree.revealNewTreeItem(nHandle) is False
|
||||||
|
|
||||||
# Adding an invalid item directly to the tree should also fail
|
# Adding an invalid item directly to the tree should also fail
|
||||||
assert projView.projTree._addTreeItem(None) is None
|
assert projTree._addTreeItem(None) is None
|
||||||
|
|
||||||
# Clean up
|
# Clean up
|
||||||
# qtbot.stop()
|
# qtbot.stop()
|
||||||
@@ -182,7 +191,7 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
|||||||
projTree = nwGUI.projView.projTree
|
projTree = nwGUI.projView.projTree
|
||||||
|
|
||||||
# Try to move item with no project
|
# Try to move item with no project
|
||||||
assert projView.projTree.moveTreeItem(1) is False
|
assert projTree.moveTreeItem(1) is False
|
||||||
|
|
||||||
# Create a project
|
# Create a project
|
||||||
buildTestProject(nwGUI, projPath)
|
buildTestProject(nwGUI, projPath)
|
||||||
@@ -244,18 +253,13 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
|||||||
"0000000000010", "0000000000011", "0000000000012",
|
"0000000000010", "0000000000011", "0000000000012",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Move down again, and restore via undo
|
# Move down again
|
||||||
projView.setSelectedHandle("0000000000011")
|
projView.setSelectedHandle("0000000000011")
|
||||||
assert projTree.moveTreeItem(1) is True
|
assert projTree.moveTreeItem(1) is True
|
||||||
assert projTree.getTreeFromHandle(C.hChapterDir) == [
|
assert projTree.getTreeFromHandle(C.hChapterDir) == [
|
||||||
C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
||||||
"0000000000010", "0000000000012", "0000000000011",
|
"0000000000010", "0000000000012", "0000000000011",
|
||||||
]
|
]
|
||||||
assert projTree.undoLastMove() is True
|
|
||||||
assert projTree.getTreeFromHandle(C.hChapterDir) == [
|
|
||||||
C.hChapterDir, C.hChapterDoc, C.hSceneDoc,
|
|
||||||
"0000000000010", "0000000000011", "0000000000012",
|
|
||||||
]
|
|
||||||
|
|
||||||
# Root Folder
|
# Root Folder
|
||||||
# ===========
|
# ===========
|
||||||
@@ -519,125 +523,6 @@ def testGuiProjTree_EmptyTrash(qtbot, caplog, monkeypatch, nwGUI, projPath, mock
|
|||||||
# END Test testGuiProjTree_EmptyTrash
|
# END Test testGuiProjTree_EmptyTrash
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.gui
|
|
||||||
def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
|
||||||
"""Test the building of the project tree context menu. All this does
|
|
||||||
is test that the menu builds. It doesn't open the actual menu,
|
|
||||||
"""
|
|
||||||
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
|
||||||
monkeypatch.setattr(QMenu, "exec_", lambda *a: None)
|
|
||||||
|
|
||||||
# Create a project
|
|
||||||
buildTestProject(nwGUI, projPath)
|
|
||||||
|
|
||||||
# Handles for new objects
|
|
||||||
hCharNote = "0000000000011"
|
|
||||||
hNovelNote = "0000000000012"
|
|
||||||
hSubNote = "0000000000013"
|
|
||||||
hNewFolderOne = "0000000000014"
|
|
||||||
hNewFolderTwo = "0000000000016"
|
|
||||||
|
|
||||||
projView = nwGUI.projView
|
|
||||||
projTree = nwGUI.projView.projTree
|
|
||||||
projTree.setExpandedFromHandle(None, True)
|
|
||||||
|
|
||||||
projTree._addTrashRoot()
|
|
||||||
hTrashRoot = SHARED.project.tree.trashRoot
|
|
||||||
|
|
||||||
projTree.setSelectedHandle(C.hCharRoot)
|
|
||||||
projTree.newTreeItem(nwItemType.FILE)
|
|
||||||
projTree.setSelectedHandle(C.hNovelRoot)
|
|
||||||
projTree.newTreeItem(nwItemType.FILE, isNote=True)
|
|
||||||
|
|
||||||
SHARED.project.newFile("SubNote", hNovelNote)
|
|
||||||
projTree.revealNewTreeItem(hSubNote)
|
|
||||||
assert SHARED.project.tree[hSubNote].itemParent == hNovelNote # type: ignore
|
|
||||||
|
|
||||||
def itemPos(tHandle):
|
|
||||||
return projTree.visualItemRect(projTree._getTreeItem(tHandle)).center()
|
|
||||||
|
|
||||||
# No item under menu
|
|
||||||
assert projTree._openContextMenu(projTree.viewport().rect().bottomRight()) is False
|
|
||||||
|
|
||||||
# Generate the possible menu combinations
|
|
||||||
assert projTree._openContextMenu(itemPos(hTrashRoot)) is True
|
|
||||||
assert projTree._openContextMenu(itemPos(C.hNovelRoot)) is True
|
|
||||||
assert projTree._openContextMenu(itemPos(hNovelNote)) is True
|
|
||||||
assert projTree._openContextMenu(itemPos(C.hTitlePage)) is True
|
|
||||||
assert projTree._openContextMenu(itemPos(C.hChapterDir)) is True
|
|
||||||
assert projTree._openContextMenu(itemPos(C.hChapterDoc)) is True
|
|
||||||
assert projTree._openContextMenu(itemPos(C.hCharRoot)) is True
|
|
||||||
assert projTree._openContextMenu(itemPos(hCharNote)) is True
|
|
||||||
assert projTree._openContextMenu(itemPos(hNovelNote)) is True
|
|
||||||
|
|
||||||
# Check the keyboard shortcut handler as well
|
|
||||||
projTree.setSelectedHandle(C.hNovelRoot)
|
|
||||||
assert projTree.openContextOnSelected() is True
|
|
||||||
projTree.clearSelection()
|
|
||||||
assert projTree.openContextOnSelected() is False
|
|
||||||
|
|
||||||
# Direct Edit Functions
|
|
||||||
# =====================
|
|
||||||
# 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
|
|
||||||
projTree._toggleItemActive(hNovelNote)
|
|
||||||
assert nwItem.isActive is False
|
|
||||||
|
|
||||||
# Change item status
|
|
||||||
assert nwItem.itemStatus == "s000000"
|
|
||||||
projTree._changeItemStatus(hNovelNote, "s000001")
|
|
||||||
assert nwItem.itemStatus == "s000001"
|
|
||||||
|
|
||||||
# Change item importance
|
|
||||||
assert nwItem.itemImport == "i000004"
|
|
||||||
projTree._changeItemImport(hNovelNote, "i000005")
|
|
||||||
assert nwItem.itemImport == "i000005"
|
|
||||||
|
|
||||||
# Change item layout
|
|
||||||
assert nwItem.itemLayout == nwItemLayout.NOTE
|
|
||||||
projTree._changeItemLayout(hNovelNote, nwItemLayout.DOCUMENT)
|
|
||||||
assert nwItem.itemLayout == nwItemLayout.DOCUMENT
|
|
||||||
projTree._changeItemLayout(hNovelNote, nwItemLayout.NOTE)
|
|
||||||
assert nwItem.itemLayout == nwItemLayout.NOTE
|
|
||||||
|
|
||||||
# Convert Folders to Documents
|
|
||||||
# ============================
|
|
||||||
|
|
||||||
projView.setSelectedHandle(hNovelNote)
|
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FOLDER) is True
|
|
||||||
projView.setSelectedHandle(hNewFolderOne)
|
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FILE) is True
|
|
||||||
|
|
||||||
projView.setSelectedHandle(hNovelNote)
|
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FOLDER) is True
|
|
||||||
projView.setSelectedHandle(hNewFolderTwo)
|
|
||||||
assert projView.projTree.newTreeItem(nwItemType.FILE, isNote=True) is True
|
|
||||||
|
|
||||||
# Click no on the dialog
|
|
||||||
with monkeypatch.context() as mp:
|
|
||||||
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
|
|
||||||
projTree._covertFolderToFile(hNewFolderOne, nwItemLayout.DOCUMENT)
|
|
||||||
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() # 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() # type: ignore
|
|
||||||
assert SHARED.project.tree[hNewFolderTwo].isNoteLayout() # type: ignore
|
|
||||||
|
|
||||||
# qtbot.stop()
|
|
||||||
|
|
||||||
# END Test testGuiProjTree_ContextMenu
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.gui
|
@pytest.mark.gui
|
||||||
def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd, ipsumText):
|
def testGuiProjTree_MergeDocuments(qtbot, monkeypatch, nwGUI, projPath, mockRnd, ipsumText):
|
||||||
"""Test the merge document function."""
|
"""Test the merge document function."""
|
||||||
@@ -988,17 +873,14 @@ def testGuiProjTree_DragAndDrop(qtbot, monkeypatch, caplog, nwGUI: GuiMain, proj
|
|||||||
mouse = Qt.MouseButton.LeftButton
|
mouse = Qt.MouseButton.LeftButton
|
||||||
modifier = Qt.KeyboardModifier.NoModifier
|
modifier = Qt.KeyboardModifier.NoModifier
|
||||||
|
|
||||||
# Move an item
|
projTree.saveTreeOrder()
|
||||||
# The actual move is blocked, but the undo history should record
|
treeOrder = SHARED.project.tree._order
|
||||||
# the event, although without an actual move implied
|
|
||||||
assert projTree._lastMove == {}
|
# Move an item, but no selection
|
||||||
event = QDropEvent(nPos, action, mime, mouse, modifier)
|
event = QDropEvent(nPos, action, mime, mouse, modifier)
|
||||||
projTree.dropEvent(event)
|
projTree.dropEvent(event)
|
||||||
assert projTree._lastMove == {
|
projTree.saveTreeOrder()
|
||||||
"item": projTree._getTreeItem(C.hSceneDoc),
|
assert SHARED.project.tree._order == treeOrder
|
||||||
"parent": projTree._getTreeItem(C.hChapterDir),
|
|
||||||
"index": 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Invalid location
|
# Invalid location
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
@@ -1006,23 +888,58 @@ def testGuiProjTree_DragAndDrop(qtbot, monkeypatch, caplog, nwGUI: GuiMain, proj
|
|||||||
projTree.dropEvent(event)
|
projTree.dropEvent(event)
|
||||||
assert event.isAccepted() is False
|
assert event.isAccepted() is False
|
||||||
assert "Invalid drop location" in caplog.text
|
assert "Invalid drop location" in caplog.text
|
||||||
|
projTree.saveTreeOrder()
|
||||||
# No item selected
|
assert SHARED.project.tree._order == treeOrder
|
||||||
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
|
# Root item selected
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
event = QDropEvent(nPos, action, mime, mouse, modifier)
|
event = QDropEvent(nPos, action, mime, mouse, modifier)
|
||||||
projTree.clearSelection()
|
projTree.clearSelection()
|
||||||
projTree.setSelectedHandle(C.hNovelRoot, True)
|
projTree._getTreeItem(C.hTitlePage).setSelected(True) # type: ignore
|
||||||
|
projTree._getTreeItem(C.hNovelRoot).setSelected(True) # type: ignore
|
||||||
projTree.dropEvent(event)
|
projTree.dropEvent(event)
|
||||||
assert event.isAccepted() is False
|
assert event.isAccepted() is False
|
||||||
assert "Invalid drag and drop event" in caplog.text
|
projTree.saveTreeOrder()
|
||||||
|
assert SHARED.project.tree._order == treeOrder
|
||||||
|
|
||||||
|
# Make sure illegal drag events are cancelled
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(QTreeWidget, "dragEnterEvent", lambda *a: None)
|
||||||
|
mime = QMimeData()
|
||||||
|
mime.setText("foobar")
|
||||||
|
event = QDragEnterEvent(nPos, action, mime, mouse, modifier)
|
||||||
|
projTree.clearSelection()
|
||||||
|
projTree._getTreeItem(C.hNovelRoot).setSelected(True) # type: ignore
|
||||||
|
projTree._getTreeItem(C.hTitlePage).setSelected(True) # type: ignore
|
||||||
|
projTree._getTreeItem(C.hChapterDoc).setSelected(True) # type: ignore
|
||||||
|
assert projTree.selectedItems() == [ # Novel Root selection is cancelled automatically
|
||||||
|
projTree._getTreeItem(C.hTitlePage), projTree._getTreeItem(C.hChapterDoc)
|
||||||
|
]
|
||||||
|
projTree.dragEnterEvent(event)
|
||||||
|
assert mime.text() == ""
|
||||||
|
assert projTree._popAlert is not None
|
||||||
|
|
||||||
|
# Pop the alert
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(QTreeWidget, "startDrag", lambda *a: None)
|
||||||
|
projTree.startDrag(None) # type: ignore
|
||||||
|
assert projTree._popAlert is None
|
||||||
|
|
||||||
|
# Valid drag events are processed
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(QTreeWidget, "dragEnterEvent", lambda *a: None)
|
||||||
|
mime = QMimeData()
|
||||||
|
mime.setText("foobar")
|
||||||
|
event = QDragEnterEvent(nPos, action, mime, mouse, modifier)
|
||||||
|
projTree.clearSelection()
|
||||||
|
projTree._getTreeItem(C.hChapterDoc).setSelected(True) # type: ignore
|
||||||
|
projTree._getTreeItem(C.hSceneDoc).setSelected(True) # type: ignore
|
||||||
|
assert projTree.selectedItems() == [ # Novel Root selection is cancelled automatically
|
||||||
|
projTree._getTreeItem(C.hChapterDoc), projTree._getTreeItem(C.hSceneDoc)
|
||||||
|
]
|
||||||
|
projTree.dragEnterEvent(event)
|
||||||
|
assert mime.text() == "foobar"
|
||||||
|
assert projTree._popAlert is None
|
||||||
|
|
||||||
# qtbot.stop()
|
# qtbot.stop()
|
||||||
|
|
||||||
@@ -1070,22 +987,6 @@ def testGuiProjTree_Other(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mockRnd)
|
|||||||
SHARED.project.tree[nHandle].setParent(C.hInvalid) # type: ignore
|
SHARED.project.tree[nHandle].setParent(C.hInvalid) # type: ignore
|
||||||
assert projTree.revealNewTreeItem(nHandle) is False
|
assert projTree.revealNewTreeItem(nHandle) is False
|
||||||
|
|
||||||
# Method: undoLastMove
|
|
||||||
# ====================
|
|
||||||
|
|
||||||
# Nothing to move
|
|
||||||
assert projTree.undoLastMove() is False
|
|
||||||
|
|
||||||
projTree._lastMove["item"] = QTreeWidgetItem()
|
|
||||||
projTree._lastMove["parent"] = QTreeWidgetItem()
|
|
||||||
projTree._lastMove["index"] = 0
|
|
||||||
assert projTree.undoLastMove() is False
|
|
||||||
|
|
||||||
projTree._lastMove["item"] = projTree._treeMap[C.hTitlePage]
|
|
||||||
projTree._lastMove["parent"] = QTreeWidgetItem()
|
|
||||||
projTree._lastMove["index"] = 0
|
|
||||||
assert projTree.undoLastMove() is False
|
|
||||||
|
|
||||||
# Slot: _treeDoubleClick
|
# Slot: _treeDoubleClick
|
||||||
# ======================
|
# ======================
|
||||||
|
|
||||||
@@ -1166,6 +1067,330 @@ def testGuiProjTree_Other(qtbot, monkeypatch, nwGUI: GuiMain, projPath, mockRnd)
|
|||||||
projTree.moveToLevel(1)
|
projTree.moveToLevel(1)
|
||||||
assert projTree.getSelectedHandle() is None
|
assert projTree.getSelectedHandle() is None
|
||||||
|
|
||||||
|
# Mouse Button Clicks
|
||||||
|
# ===================
|
||||||
|
|
||||||
|
eType = QEvent.Type.MouseButtonPress
|
||||||
|
pos = projTree.visualItemRect(projTree._getTreeItem(C.hChapterDoc)).center()
|
||||||
|
button = Qt.MouseButton.MiddleButton
|
||||||
|
modifier = Qt.KeyboardModifier.NoModifier
|
||||||
|
|
||||||
|
# Trigger the viewer
|
||||||
|
event = QMouseEvent(eType, pos, button, button, modifier)
|
||||||
|
projTree.mousePressEvent(event)
|
||||||
|
assert nwGUI.docViewer.docHandle == C.hChapterDoc
|
||||||
|
|
||||||
|
# Trigger the left click clear
|
||||||
|
pos = QPoint(5000, 5000)
|
||||||
|
button = Qt.MouseButton.LeftButton
|
||||||
|
event = QMouseEvent(eType, pos, button, button, modifier)
|
||||||
|
projTree.setSelectedHandle(C.hChapterDoc)
|
||||||
|
projTree.mousePressEvent(event)
|
||||||
|
assert projTree.selectedItems() == []
|
||||||
|
|
||||||
|
# Rename Item
|
||||||
|
# ===========
|
||||||
|
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(GuiEditLabel, "getLabel", lambda *a, **k: ("FooBar", True))
|
||||||
|
projTree.clearSelection()
|
||||||
|
assert SHARED.project.tree[C.hChapterDoc].itemName == "New Chapter" # type: ignore
|
||||||
|
assert projView.renameTreeItem(C.hChapterDoc) is True
|
||||||
|
assert SHARED.project.tree[C.hChapterDoc].itemName == "FooBar" # type: ignore
|
||||||
|
|
||||||
|
projTree.setSelectedHandle(C.hSceneDoc)
|
||||||
|
assert SHARED.project.tree[C.hSceneDoc].itemName == "New Scene" # type: ignore
|
||||||
|
assert projView.renameTreeItem() is True
|
||||||
|
assert SHARED.project.tree[C.hSceneDoc].itemName == "FooBar" # type: ignore
|
||||||
|
|
||||||
|
# Check Crash Resistance
|
||||||
|
# ======================
|
||||||
|
projTree._postItemMove("dfghj") # This should exit cleanly
|
||||||
|
|
||||||
# qtbot.stop()
|
# qtbot.stop()
|
||||||
|
|
||||||
# END Test testGuiProjTree_Other
|
# END Test testGuiProjTree_Other
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.gui
|
||||||
|
def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
|
||||||
|
"""Test the building of the project tree context menu. All this does
|
||||||
|
is test that the menu builds. It doesn't open the actual menu,
|
||||||
|
"""
|
||||||
|
monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
|
||||||
|
|
||||||
|
# Create a project
|
||||||
|
buildTestProject(nwGUI, projPath)
|
||||||
|
nwGUI.openProject(projPath)
|
||||||
|
nwGUI.switchFocus(nwWidget.TREE)
|
||||||
|
|
||||||
|
# Handles for new objects
|
||||||
|
hCharNote = "0000000000011"
|
||||||
|
hNovelNote = "0000000000012"
|
||||||
|
hSubNote = "0000000000013"
|
||||||
|
hNewFolderOne = "0000000000014"
|
||||||
|
hNewFolderTwo = "0000000000016"
|
||||||
|
|
||||||
|
projView = nwGUI.projView
|
||||||
|
projTree = nwGUI.projView.projTree
|
||||||
|
projTree.setExpandedFromHandle(None, True)
|
||||||
|
|
||||||
|
projTree._addTrashRoot()
|
||||||
|
hTrashRoot = SHARED.project.tree.trashRoot
|
||||||
|
|
||||||
|
projTree.setSelectedHandle(C.hCharRoot)
|
||||||
|
projTree.newTreeItem(nwItemType.FILE)
|
||||||
|
projTree.setSelectedHandle(C.hNovelRoot)
|
||||||
|
projTree.newTreeItem(nwItemType.FILE, isNote=True)
|
||||||
|
|
||||||
|
SHARED.project.newFile("SubNote", hNovelNote)
|
||||||
|
projTree.revealNewTreeItem(hSubNote)
|
||||||
|
assert SHARED.project.tree[hSubNote].itemParent == hNovelNote # type: ignore
|
||||||
|
|
||||||
|
def itemPos(tHandle):
|
||||||
|
return projTree.visualItemRect(projTree._getTreeItem(tHandle)).center()
|
||||||
|
|
||||||
|
# Pop the menu
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(QMenu, "exec_", lambda *a: None)
|
||||||
|
projTree.clearSelection()
|
||||||
|
|
||||||
|
# No item under menu
|
||||||
|
assert projTree._openContextMenu(projTree.viewport().rect().bottomRight()) is False
|
||||||
|
|
||||||
|
# Open Trash Menu
|
||||||
|
assert projTree._openContextMenu(itemPos(hTrashRoot)) is True
|
||||||
|
|
||||||
|
# Open Single Select Menu
|
||||||
|
assert projTree._openContextMenu(itemPos(C.hNovelRoot)) is True
|
||||||
|
|
||||||
|
# Open Multi-Select Menu
|
||||||
|
projTree._getTreeItem(hNovelNote).setSelected(True)
|
||||||
|
projTree._getTreeItem(hSubNote).setSelected(True)
|
||||||
|
assert projTree._openContextMenu(itemPos(hCharNote)) is True
|
||||||
|
|
||||||
|
# Check the keyboard shortcut handler as well
|
||||||
|
projTree.setSelectedHandle(C.hNovelRoot)
|
||||||
|
assert projTree.openContextOnSelected() is True
|
||||||
|
projTree.clearSelection()
|
||||||
|
assert projTree.openContextOnSelected() is False
|
||||||
|
|
||||||
|
# Menu Builders
|
||||||
|
# =============
|
||||||
|
|
||||||
|
# Context Menu on Root Item
|
||||||
|
nwItem = SHARED.project.tree[C.hNovelRoot]
|
||||||
|
assert isinstance(nwItem, NWItem)
|
||||||
|
ctxMenu = _TreeContextMenu(projTree, nwItem)
|
||||||
|
ctxMenu.buildSingleSelectMenu(True)
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Rename", "Set Status to ...", "Expand All", "Collapse All",
|
||||||
|
"Duplicate from Here", "Delete Permanently",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Context Menu on Folder Item
|
||||||
|
nwItem = SHARED.project.tree[C.hChapterDir]
|
||||||
|
assert isinstance(nwItem, NWItem)
|
||||||
|
ctxMenu = _TreeContextMenu(projTree, nwItem)
|
||||||
|
ctxMenu.buildSingleSelectMenu(True)
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Rename", "Set Status to ...", "Transform", "Expand All", "Collapse All",
|
||||||
|
"Duplicate from Here", "Move to Trash",
|
||||||
|
]
|
||||||
|
|
||||||
|
def getTransformSubMenu(menu: QMenu) -> list[str]:
|
||||||
|
for action in menu.actions():
|
||||||
|
if action.text() == "Transform":
|
||||||
|
return [x.text() for x in action.menu().actions() if x.text()]
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Context Menu on Document File Item
|
||||||
|
nwItem = SHARED.project.tree[C.hChapterDoc]
|
||||||
|
assert isinstance(nwItem, NWItem)
|
||||||
|
ctxMenu = _TreeContextMenu(projTree, nwItem)
|
||||||
|
ctxMenu.buildSingleSelectMenu(True)
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Open Document", "View Document", "Rename", "Toggle Active", "Set Status to ...",
|
||||||
|
"Transform", "Expand All", "Collapse All", "Duplicate from Here", "Move to Trash",
|
||||||
|
]
|
||||||
|
assert getTransformSubMenu(ctxMenu) == [
|
||||||
|
"Convert to Project Note", "Merge Child Items into Self",
|
||||||
|
"Merge Child Items into New", "Split Document by Headers"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Context Menu on Note File Item in Character Folder
|
||||||
|
nwItem = SHARED.project.tree[hCharNote]
|
||||||
|
assert isinstance(nwItem, NWItem)
|
||||||
|
ctxMenu = _TreeContextMenu(projTree, nwItem)
|
||||||
|
ctxMenu.buildSingleSelectMenu(False)
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Open Document", "View Document", "Rename", "Toggle Active", "Set Importance to ...",
|
||||||
|
"Transform", "Duplicate Document", "Move to Trash",
|
||||||
|
]
|
||||||
|
assert getTransformSubMenu(ctxMenu) == [
|
||||||
|
"Split Document by Headers",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Context Menu on Note File Item in Novel Tree
|
||||||
|
nwItem = SHARED.project.tree[hNovelNote]
|
||||||
|
assert isinstance(nwItem, NWItem)
|
||||||
|
ctxMenu = _TreeContextMenu(projTree, nwItem)
|
||||||
|
ctxMenu.buildSingleSelectMenu(False)
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Open Document", "View Document", "Rename", "Toggle Active", "Set Status to ...",
|
||||||
|
"Transform", "Duplicate Document", "Move to Trash",
|
||||||
|
]
|
||||||
|
assert getTransformSubMenu(ctxMenu) == [
|
||||||
|
"Convert to Novel Document", "Split Document by Headers",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Context Menu on Multiple Items, Clicked on Document
|
||||||
|
nwItem = SHARED.project.tree[hNovelNote]
|
||||||
|
assert isinstance(nwItem, NWItem)
|
||||||
|
ctxMenu = _TreeContextMenu(projTree, nwItem)
|
||||||
|
ctxMenu.buildMultiSelectMenu([hCharNote, hNovelNote, hSubNote])
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Set Active to ...", "Set Status to ...", "Move to Trash",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Context Menu on Multiple Items, Clicked on Note
|
||||||
|
nwItem = SHARED.project.tree[hCharNote]
|
||||||
|
assert isinstance(nwItem, NWItem)
|
||||||
|
ctxMenu = _TreeContextMenu(projTree, nwItem)
|
||||||
|
ctxMenu.buildMultiSelectMenu([hCharNote, hNovelNote, hSubNote])
|
||||||
|
actions = [x.text() for x in ctxMenu.actions() if x.text()]
|
||||||
|
assert actions == [
|
||||||
|
"Set Active to ...", "Set Importance to ...", "Move to Trash",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Direct Edit Functions, Single
|
||||||
|
# =============================
|
||||||
|
|
||||||
|
nwItem = SHARED.project.tree[hNovelNote]
|
||||||
|
assert isinstance(nwItem, NWItem)
|
||||||
|
|
||||||
|
# # Toggle active flag
|
||||||
|
ctxMenu = _TreeContextMenu(projTree, nwItem)
|
||||||
|
ctxMenu.buildSingleSelectMenu(False)
|
||||||
|
assert nwItem.isActive is True
|
||||||
|
ctxMenu._toggleItemActive()
|
||||||
|
assert nwItem.isActive is False
|
||||||
|
|
||||||
|
# Change item status
|
||||||
|
assert nwItem.itemStatus == "s000000"
|
||||||
|
ctxMenu._changeItemStatus("s000001")
|
||||||
|
assert nwItem.itemStatus == "s000001"
|
||||||
|
|
||||||
|
# Change item importance
|
||||||
|
assert nwItem.itemImport == "i000004"
|
||||||
|
ctxMenu._changeItemImport("i000005")
|
||||||
|
assert nwItem.itemImport == "i000005"
|
||||||
|
|
||||||
|
# Change item layout
|
||||||
|
assert nwItem.itemLayout == nwItemLayout.NOTE
|
||||||
|
ctxMenu._changeItemLayout(nwItemLayout.DOCUMENT)
|
||||||
|
assert nwItem.itemLayout == nwItemLayout.DOCUMENT
|
||||||
|
ctxMenu._changeItemLayout(nwItemLayout.NOTE)
|
||||||
|
assert nwItem.itemLayout == nwItemLayout.NOTE
|
||||||
|
|
||||||
|
# Convert Folders to Documents
|
||||||
|
# ============================
|
||||||
|
|
||||||
|
projView.setSelectedHandle(hNovelNote)
|
||||||
|
assert projTree.newTreeItem(nwItemType.FOLDER) is True
|
||||||
|
projView.setSelectedHandle(hNewFolderOne)
|
||||||
|
assert projTree.newTreeItem(nwItemType.FILE) is True
|
||||||
|
|
||||||
|
projView.setSelectedHandle(hNovelNote)
|
||||||
|
assert projTree.newTreeItem(nwItemType.FOLDER) is True
|
||||||
|
projView.setSelectedHandle(hNewFolderTwo)
|
||||||
|
assert projTree.newTreeItem(nwItemType.FILE, isNote=True) is True
|
||||||
|
|
||||||
|
nwItem = SHARED.project.tree[hNewFolderOne]
|
||||||
|
assert isinstance(nwItem, NWItem)
|
||||||
|
ctxMenu = _TreeContextMenu(projTree, nwItem)
|
||||||
|
ctxMenu.buildSingleSelectMenu(False)
|
||||||
|
|
||||||
|
# Click no on the dialog
|
||||||
|
with monkeypatch.context() as mp:
|
||||||
|
mp.setattr(QMessageBox, "result", lambda *a: QMessageBox.No)
|
||||||
|
ctxMenu._covertFolderToFile(nwItemLayout.DOCUMENT)
|
||||||
|
assert SHARED.project.tree[hNewFolderOne].isFolderType() # type: ignore
|
||||||
|
|
||||||
|
# Convert the first folder to a document
|
||||||
|
ctxMenu._covertFolderToFile(nwItemLayout.DOCUMENT)
|
||||||
|
assert SHARED.project.tree[hNewFolderOne].isFileType() # type: ignore
|
||||||
|
assert SHARED.project.tree[hNewFolderOne].isDocumentLayout() # type: ignore
|
||||||
|
|
||||||
|
nwItem = SHARED.project.tree[hNewFolderTwo]
|
||||||
|
assert isinstance(nwItem, NWItem)
|
||||||
|
ctxMenu = _TreeContextMenu(projTree, nwItem)
|
||||||
|
ctxMenu.buildSingleSelectMenu(False)
|
||||||
|
|
||||||
|
# Convert the second folder to a note
|
||||||
|
ctxMenu._covertFolderToFile(nwItemLayout.NOTE)
|
||||||
|
assert SHARED.project.tree[hNewFolderTwo].isFileType() # type: ignore
|
||||||
|
assert SHARED.project.tree[hNewFolderTwo].isNoteLayout() # type: ignore
|
||||||
|
|
||||||
|
# Direct Edit Functions, Multi
|
||||||
|
# ============================
|
||||||
|
|
||||||
|
nwItem = SHARED.project.tree[hCharNote]
|
||||||
|
assert isinstance(nwItem, NWItem)
|
||||||
|
ctxMenu = _TreeContextMenu(projTree, nwItem)
|
||||||
|
ctxMenu.buildMultiSelectMenu([hCharNote, hNovelNote, hSubNote])
|
||||||
|
|
||||||
|
projTree.clearSelection()
|
||||||
|
projTree._getTreeItem(hCharNote).setSelected(True)
|
||||||
|
projTree._getTreeItem(hNovelNote).setSelected(True)
|
||||||
|
projTree._getTreeItem(hSubNote).setSelected(True)
|
||||||
|
|
||||||
|
# Item Active
|
||||||
|
assert SHARED.project.tree[hCharNote].isActive is True # type: ignore
|
||||||
|
assert SHARED.project.tree[hNovelNote].isActive is False # type: ignore
|
||||||
|
assert SHARED.project.tree[hSubNote].isActive is True # type: ignore
|
||||||
|
ctxMenu._iterItemActive(False)
|
||||||
|
assert SHARED.project.tree[hCharNote].isActive is False # type: ignore
|
||||||
|
assert SHARED.project.tree[hNovelNote].isActive is False # type: ignore
|
||||||
|
assert SHARED.project.tree[hSubNote].isActive is False # type: ignore
|
||||||
|
ctxMenu._iterItemActive(True)
|
||||||
|
assert SHARED.project.tree[hCharNote].isActive is True # type: ignore
|
||||||
|
assert SHARED.project.tree[hNovelNote].isActive is True # type: ignore
|
||||||
|
assert SHARED.project.tree[hSubNote].isActive is True # type: ignore
|
||||||
|
|
||||||
|
# Item Status
|
||||||
|
assert SHARED.project.tree[hCharNote].itemStatus == "s000000" # type: ignore
|
||||||
|
assert SHARED.project.tree[hNovelNote].itemStatus == "s000001" # type: ignore
|
||||||
|
assert SHARED.project.tree[hSubNote].itemStatus == "s000000" # type: ignore
|
||||||
|
ctxMenu._iterSetItemStatus("s000003")
|
||||||
|
assert SHARED.project.tree[hCharNote].itemStatus == "s000000" # type: ignore
|
||||||
|
assert SHARED.project.tree[hNovelNote].itemStatus == "s000003" # type: ignore
|
||||||
|
assert SHARED.project.tree[hSubNote].itemStatus == "s000003" # type: ignore
|
||||||
|
|
||||||
|
# Item Importance
|
||||||
|
assert SHARED.project.tree[hCharNote].itemImport == "i000004" # type: ignore
|
||||||
|
assert SHARED.project.tree[hNovelNote].itemImport == "i000005" # type: ignore
|
||||||
|
assert SHARED.project.tree[hSubNote].itemImport == "i000004" # type: ignore
|
||||||
|
ctxMenu._iterSetItemImport("i000007")
|
||||||
|
assert SHARED.project.tree[hCharNote].itemImport == "i000007" # type: ignore
|
||||||
|
assert SHARED.project.tree[hNovelNote].itemImport == "i000005" # type: ignore
|
||||||
|
assert SHARED.project.tree[hSubNote].itemImport == "i000004" # type: ignore
|
||||||
|
|
||||||
|
# Move to Trash
|
||||||
|
assert SHARED.project.tree[hCharNote].itemRoot == C.hCharRoot # type: ignore
|
||||||
|
assert SHARED.project.tree[hNovelNote].itemRoot == C.hNovelRoot # type: ignore
|
||||||
|
assert SHARED.project.tree[hSubNote].itemRoot == C.hNovelRoot # type: ignore
|
||||||
|
ctxMenu._iterMoveToTrash()
|
||||||
|
assert SHARED.project.tree[hCharNote].itemRoot == hTrashRoot # type: ignore
|
||||||
|
assert SHARED.project.tree[hNovelNote].itemRoot == hTrashRoot # type: ignore
|
||||||
|
assert SHARED.project.tree[hSubNote].itemRoot == hTrashRoot # type: ignore
|
||||||
|
|
||||||
|
# qtbot.stop()
|
||||||
|
|
||||||
|
# END Test testGuiProjTree_ContextMenu
|
||||||
|
|||||||
Reference in New Issue
Block a user