Improve placement of new documents (#2302)

This commit is contained in:
Veronica Berglyd Olsen
2025-04-19 15:05:38 +02:00
committed by GitHub
4 changed files with 272 additions and 83 deletions
+26 -1
View File
@@ -33,7 +33,7 @@ from typing import TYPE_CHECKING, Literal, overload
from PyQt6.QtCore import QModelIndex
from novelwriter import SHARED
from novelwriter.constants import nwFiles, nwLabels, trConst
from novelwriter.constants import nwFiles, nwLabels, nwStyles, trConst
from novelwriter.core.item import NWItem
from novelwriter.core.itemmodel import ProjectModel, ProjectNode
from novelwriter.enum import nwChange, nwItemClass, nwItemLayout, nwItemType
@@ -262,6 +262,31 @@ class NWTree:
return
def pickParent(self, sNode: ProjectNode, hLevel: int, isNote: bool) -> tuple[str | None, int]:
"""Pick an appropriate parent handle for adding a new item."""
if sNode.item.isFolderType() or sNode.item.isRootType():
# Always add as a direct child of folders
return sNode.item.itemHandle, sNode.childCount()
pNode = sNode.parent()
pLevel = nwStyles.H_LEVEL.get(pNode.item.mainHeading, 0) if pNode else 0
# Notes are treated as H0, and scenes and sections both as H3
sLevel = min(0 if isNote else nwStyles.H_LEVEL.get(sNode.item.mainHeading, 0), 3)
if pNode and pNode.item.isFileType() and pLevel >= hLevel and sLevel > hLevel:
# If the selected item is a smaller heading and the parent heading
# is equal or larger, we make it a sibling of the parent (See #2260)
return pNode.item.itemParent, pNode.row() + 1
if sNode.childCount() > 0 and (0 < sLevel < hLevel or isNote):
# If the selected item already has child nodes and has a larger
# heading or is a note, we make the new item a child
return sNode.item.itemHandle, sNode.childCount()
# The default behaviour is to make the new item a sibling
return sNode.item.itemParent, sNode.row() + 1
def refreshItems(self, items: list[str]) -> None:
"""Refresh these items on the GUI. If they are an ordered range,
also set the isRange flag to True.
+55 -51
View File
@@ -275,9 +275,9 @@ class GuiProjectToolBar(QWidget):
# Add Item Menu
self.mAdd = QMenu(self)
self.aAddEmpty = qtAddAction(self.mAdd, trConst(nwLabels.ITEM_DESCRIPTION["document"]))
self.aAddEmpty.triggered.connect(
qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=0, isNote=False)
self.aAddScene = qtAddAction(self.mAdd, trConst(nwLabels.ITEM_DESCRIPTION["doc_h3"]))
self.aAddScene.triggered.connect(
qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=3, isNote=False)
)
self.aAddChap = qtAddAction(self.mAdd, trConst(nwLabels.ITEM_DESCRIPTION["doc_h2"]))
@@ -285,9 +285,14 @@ class GuiProjectToolBar(QWidget):
qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=2, isNote=False)
)
self.aAddScene = qtAddAction(self.mAdd, trConst(nwLabels.ITEM_DESCRIPTION["doc_h3"]))
self.aAddScene.triggered.connect(
qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=3, isNote=False)
self.aAddPart = qtAddAction(self.mAdd, trConst(nwLabels.ITEM_DESCRIPTION["doc_h1"]))
self.aAddPart.triggered.connect(
qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=1, isNote=False)
)
self.aAddEmpty = qtAddAction(self.mAdd, trConst(nwLabels.ITEM_DESCRIPTION["document"]))
self.aAddEmpty.triggered.connect(
qtLambda(self.projTree.newTreeItem, nwItemType.FILE, hLevel=0, isNote=False)
)
self.aAddNote = qtAddAction(self.mAdd, trConst(nwLabels.ITEM_DESCRIPTION["note"]))
@@ -366,9 +371,10 @@ class GuiProjectToolBar(QWidget):
self.tbAdd.setThemeIcon("add", "green")
self.tbMore.setThemeIcon("more_vertical")
self.aAddEmpty.setIcon(SHARED.theme.getIcon("prj_document", "file"))
self.aAddChap.setIcon(SHARED.theme.getIcon("prj_chapter", "chapter"))
self.aAddScene.setIcon(SHARED.theme.getIcon("prj_scene", "scene"))
self.aAddChap.setIcon(SHARED.theme.getIcon("prj_chapter", "chapter"))
self.aAddPart.setIcon(SHARED.theme.getIcon("prj_title", "title"))
self.aAddEmpty.setIcon(SHARED.theme.getIcon("prj_document", "file"))
self.aAddNote.setIcon(SHARED.theme.getIcon("prj_note", "note"))
self.aAddFolder.setIcon(SHARED.theme.getIcon("prj_folder", "folder"))
@@ -425,9 +431,10 @@ class GuiProjectToolBar(QWidget):
"""
nwItem = SHARED.project.tree[tHandle]
allowDoc = isinstance(nwItem, NWItem) and nwItem.documentAllowed()
self.aAddEmpty.setVisible(allowDoc)
self.aAddChap.setVisible(allowDoc)
self.aAddScene.setVisible(allowDoc)
self.aAddChap.setVisible(allowDoc)
self.aAddPart.setVisible(allowDoc)
self.aAddEmpty.setVisible(allowDoc)
return
##
@@ -503,7 +510,6 @@ class GuiProjectTree(QTreeView):
self.customContextMenuRequested.connect(self.openContextMenu)
# Connect signals
self.clicked.connect(self._onSingleClick)
self.doubleClicked.connect(self._onDoubleClick)
self.collapsed.connect(self._onNodeCollapsed)
self.expanded.connect(self._onNodeExpanded)
@@ -553,6 +559,9 @@ class GuiProjectTree(QTreeView):
def loadModel(self) -> None:
"""Load and prepare a new project model."""
if selectModelOld := self.selectionModel():
selectModelOld.disconnect()
self.setModel(SHARED.project.tree.model)
# Lock the column sizes
@@ -568,6 +577,9 @@ class GuiProjectTree(QTreeView):
header.resizeSection(ProjectNode.C_ACTIVE, iPx + 6)
header.resizeSection(ProjectNode.C_STATUS, iPx + 6)
if selectModelNew := self.selectionModel():
selectModelNew.currentChanged.connect(self._onSelectionChange)
self.restoreExpandedState()
return
@@ -606,12 +618,12 @@ class GuiProjectTree(QTreeView):
tHandle = None
if itemType == nwItemType.ROOT and isinstance(itemClass, nwItemClass):
pos = -1
sPos = -1
if (node := self._getNode(self.currentIndex())) and (itemRoot := node.item.itemRoot):
if root := SHARED.project.tree.nodes.get(itemRoot):
pos = root.row() + 1
sPos = root.row() + 1
tHandle = SHARED.project.newRoot(itemClass, pos)
tHandle = SHARED.project.newRoot(itemClass, sPos)
self.restoreExpandedState()
elif itemType in (nwItemType.FILE, nwItemType.FOLDER):
@@ -624,52 +636,43 @@ class GuiProjectTree(QTreeView):
SHARED.error(self.tr("Cannot add new files or folders to the Trash folder."))
return
# Collect some information about the selected item
sLevel = nwStyles.H_LEVEL.get(node.item.mainHeading, 0)
sIsParent = node.childCount() > 0
# Set default label and determine if new item is to be added
# as child or sibling to the selected item
# Set default label and determine where to put the new item
nNote = isNote
nLevel = hLevel
if itemType == nwItemType.FILE:
if copyDoc and (cItem := SHARED.project.tree[copyDoc]):
nNote = cItem.isNoteLayout()
nLevel = nwStyles.H_LEVEL.get(cItem.mainHeading, 0)
newLabel = cItem.itemName
asChild = sIsParent and node.item.isDocumentLayout()
elif isNote:
newLabel = self.tr("New Note")
asChild = sIsParent
elif hLevel == 1:
newLabel = self.tr("New Part")
elif hLevel == 2:
newLabel = self.tr("New Chapter")
asChild = sIsParent and node.item.isDocumentLayout() and sLevel < 2
elif hLevel == 3:
newLabel = self.tr("New Scene")
asChild = sIsParent and node.item.isDocumentLayout() and sLevel < 3
else:
newLabel = self.tr("New Document")
asChild = sIsParent and node.item.isDocumentLayout()
else:
newLabel = self.tr("New Folder")
asChild = False
nLevel = 0
pos = -1
sHandle = None
if not (asChild or node.item.isFolderType() or node.item.isRootType()):
pos = node.row() + 1
sHandle = node.item.itemParent
sHandle = sHandle or node.item.itemHandle
newLabel, dlgOk = GuiEditLabel.getLabel(self, text=newLabel)
if dlgOk:
# Add the file or folder
if itemType == nwItemType.FILE:
if tHandle := SHARED.project.newFile(newLabel, sHandle, pos):
if copyDoc:
SHARED.project.copyFileContent(tHandle, copyDoc)
elif hLevel > 0:
SHARED.project.writeNewFile(tHandle, hLevel, not isNote)
SHARED.project.index.reIndexHandle(tHandle)
SHARED.project.tree.refreshItems([tHandle])
else:
tHandle = SHARED.project.newFolder(newLabel, sHandle, pos)
sHandle, sPos = SHARED.project.tree.pickParent(node, nLevel, nNote)
if sHandle:
newLabel, dlgOk = GuiEditLabel.getLabel(self, text=newLabel)
if dlgOk:
# Add the file or folder
if itemType == nwItemType.FILE:
if tHandle := SHARED.project.newFile(newLabel, sHandle, sPos):
if copyDoc:
SHARED.project.copyFileContent(tHandle, copyDoc)
elif hLevel > 0:
SHARED.project.writeNewFile(tHandle, hLevel, not nNote)
SHARED.project.index.reIndexHandle(tHandle)
SHARED.project.tree.refreshItems([tHandle])
else:
tHandle = SHARED.project.newFolder(newLabel, sHandle, sPos)
# Select the new item automatically
if tHandle:
@@ -969,10 +972,10 @@ class GuiProjectTree(QTreeView):
# Private Slots
##
@pyqtSlot(QModelIndex)
def _onSingleClick(self, index: QModelIndex) -> None:
@pyqtSlot(QModelIndex, QModelIndex)
def _onSelectionChange(self, current: QModelIndex, previous: QModelIndex) -> None:
"""The user changed which item is selected."""
if node := self._getNode(index):
if node := self._getNode(current):
self.projView.selectedItemChanged.emit(node.item.itemHandle)
return
@@ -1198,9 +1201,10 @@ class _TreeContextMenu(QMenu):
def _itemCreation(self) -> None:
"""Add create item actions."""
menu = qtAddMenu(self, self.tr("Create New ..."))
menu.addAction(self._view.projBar.aAddEmpty)
menu.addAction(self._view.projBar.aAddChap)
menu.addAction(self._view.projBar.aAddScene)
menu.addAction(self._view.projBar.aAddChap)
menu.addAction(self._view.projBar.aAddPart)
menu.addAction(self._view.projBar.aAddEmpty)
menu.addAction(self._view.projBar.aAddNote)
menu.addAction(self._view.projBar.aAddFolder)
return
+139
View File
@@ -211,6 +211,145 @@ def testCoreTree_ManipulateTree(mockGUI, mockItems):
]
@pytest.mark.core
def testCoreTree_PickParent(mockGUI, mockItems):
"""Check the parent item picker."""
project = NWProject()
tree = NWTree(project)
assert len(tree) == 0
# Case 1: Root and Folder
# =======================
hNovelRoot = tree.create("Novel", None, nwItemType.ROOT, nwItemClass.NOVEL)
nNovelRoot = tree.nodes[hNovelRoot]
# Add a folder
sHandle, sPos = tree.pickParent(nNovelRoot, 0, False)
assert sHandle == hNovelRoot
assert sPos == 0
hNovelFolder = tree.create("Folder", sHandle, nwItemType.FOLDER, pos=sPos)
assert hNovelFolder is not None
nNovelFolder = tree.nodes[hNovelFolder]
assert nNovelFolder.item.itemClass == nwItemClass.NOVEL
# Add a partition
sHandle, sPos = tree.pickParent(nNovelRoot, 1, False)
assert sHandle == hNovelRoot
assert sPos == 1
hPartOne = tree.create("Part One", sHandle, nwItemType.FILE, pos=sPos)
assert hPartOne is not None
nPartOne = tree.nodes[hPartOne]
assert nPartOne.item.itemClass == nwItemClass.NOVEL
nPartOne.item.setMainHeading("H1")
# Folders behave identical to root
sHandle, sPos = tree.pickParent(nNovelFolder, 0, False)
assert sHandle == hNovelFolder
assert sPos == 0
# Case 2: Documents of Same Level
# ===============================
# Add a chapter under Part One
hChapterOne = tree.create("Chapter One", hPartOne, nwItemType.FILE)
assert hChapterOne is not None
nChapterOne = tree.nodes[hChapterOne]
assert nChapterOne.item.itemParent == hPartOne
nChapterOne.item.setMainHeading("H2")
# Add a chapter next to Chapter One -> Sibling (default behaviour)
sHandle, sPos = tree.pickParent(nChapterOne, 2, False)
assert sHandle == hPartOne
assert sPos == 1
hChapterTwo = tree.create("Chapter Two", sHandle, nwItemType.FILE, pos=sPos)
assert hChapterTwo is not None
nChapterTwo = tree.nodes[hChapterTwo]
assert nChapterTwo.item.itemClass == nwItemClass.NOVEL
nChapterTwo.item.setMainHeading("H2")
# Add a new part next to Chapter Two -> Sibling to parent (second if condition)
sHandle, sPos = tree.pickParent(nChapterTwo, 1, False)
assert sHandle == hNovelRoot
assert sPos == 2
# Add a scene under Chapter Two
hSceneOne = tree.create("Scene One", hChapterOne, nwItemType.FILE)
assert hSceneOne is not None
nSceneOne = tree.nodes[hSceneOne]
assert nSceneOne.item.itemParent == hChapterOne
nSceneOne.item.setMainHeading("H3")
# Adding a part next to the scene should also jump a level up
sHandle, sPos = tree.pickParent(nSceneOne, 1, False)
assert sHandle == hPartOne
assert sPos == 1
# Case 3: Documents of Deeper Level
# =================================
# Add chapter directly to Part One with existing chapters -> Added as child (third if)
sHandle, sPos = tree.pickParent(nPartOne, 2, False)
assert sHandle == hPartOne
assert sPos == 2
# But adding a new part becomes a sibling
sHandle, sPos = tree.pickParent(nPartOne, 1, False)
assert sHandle == hNovelRoot
assert sPos == 2
# Add a page without a heading
hPage = tree.create("Page", hNovelRoot, nwItemType.FILE)
assert hPage is not None
nPage = tree.nodes[hPage]
assert nPage.item.itemParent == hNovelRoot
nPage.item.setMainHeading("H0")
# Add a scene below the page
hSceneTwo = tree.create("Scene Two", hPage, nwItemType.FILE)
assert hSceneTwo is not None
nSceneTwo = tree.nodes[hSceneTwo]
assert nSceneTwo.item.itemParent == hPage
nSceneTwo.item.setMainHeading("H3")
# A page without a heading should not add anything as a child
sHandle, sPos = tree.pickParent(nPage, 3, False)
assert sHandle == hNovelRoot
assert sPos == 3
# Case 4: Notes
# =============
hCharRoot = tree.create("Characters", None, nwItemType.ROOT, nwItemClass.CHARACTER)
nCharRoot = tree.nodes[hCharRoot]
# Add a note at root level
hNoteOne = tree.create("Note One", hCharRoot, nwItemType.FILE)
assert hNoteOne is not None
nNoteOne = tree.nodes[hNoteOne]
assert nNoteOne.item.itemClass == nwItemClass.CHARACTER
nNoteOne.item.setMainHeading("H1")
assert nCharRoot.childCount() == 1
# Adding a new note is a sibling
sHandle, sPos = tree.pickParent(nNoteOne, 1, True)
assert sHandle == hCharRoot
assert sPos == 1
# Add a child note to Note One
hNoteTwo = tree.create("Note Two", hNoteOne, nwItemType.FILE)
assert hNoteTwo is not None
nNoteTwo = tree.nodes[hNoteTwo]
assert nNoteTwo.item.itemClass == nwItemClass.CHARACTER
nNoteTwo.item.setMainHeading("H1")
assert nNoteOne.childCount() == 1
# Adding a new note now is a child
sHandle, sPos = tree.pickParent(nNoteOne, 1, True)
assert sHandle == hNoteOne
assert sPos == 1
@pytest.mark.core
def testCoreTree_ItemMethods(monkeypatch, mockGUI, mockItems):
"""Check the item methods of the tree."""
+52 -31
View File
@@ -134,7 +134,7 @@ def testGuiProjTree_NewTreeItem(qtbot, caplog, monkeypatch, nwGUI, projPath, moc
# Add a new file in the new folder
hNewFile = "0000000000013"
projView.setSelectedHandle(hNewFolder, doScroll=True)
projTree.newTreeItem(nwItemType.FILE)
projTree.newTreeItem(nwItemType.FILE, hLevel=0)
assert hNewFile in tree
item = tree[hNewFile]
assert item is not None
@@ -148,9 +148,28 @@ def testGuiProjTree_NewTreeItem(qtbot, caplog, monkeypatch, nwGUI, projPath, moc
"Objects", "Trash",
]
# Add a new chapter next to the other new file
hNewChapter = "0000000000014"
# Add a new partition next to the other new file
hNewPart = "0000000000014"
projView.setSelectedHandle(hNewFile, doScroll=True)
projTree.newTreeItem(nwItemType.FILE, hLevel=1)
assert hNewPart in tree
item = tree[hNewPart]
assert item is not None
assert item.itemName == "New Part"
assert item.itemParent == hNewFolder
assert item.itemRoot == C.hNovelRoot
assert item.itemClass == nwItemClass.NOVEL
assert nwGUI.openDocument(hNewPart)
assert nwGUI.docEditor.getText() == "# New Part\n\n"
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
"Novel", "Title Page", "New Folder", "New Chapter", "New Scene",
"New Folder", "New Document", "New Part", "Plot", "Characters",
"Locations", "Objects", "Trash",
]
# Add a new chapter next to the other new file
hNewChapter = "0000000000015"
projView.setSelectedHandle(hNewPart, doScroll=True)
projTree.newTreeItem(nwItemType.FILE, hLevel=2)
assert hNewChapter in tree
item = tree[hNewChapter]
@@ -163,12 +182,12 @@ def testGuiProjTree_NewTreeItem(qtbot, caplog, monkeypatch, nwGUI, projPath, moc
assert nwGUI.docEditor.getText() == "## New Chapter\n\n"
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
"Novel", "Title Page", "New Folder", "New Chapter", "New Scene",
"New Folder", "New Document", "New Chapter", "Plot", "Characters",
"Locations", "Objects", "Trash",
"New Folder", "New Document", "New Part", "New Chapter", "Plot",
"Characters", "Locations", "Objects", "Trash",
]
# Add a new scene next to the other new file
hNewScene = "0000000000015"
hNewScene = "0000000000016"
projView.setSelectedHandle(hNewChapter, doScroll=True)
projTree.newTreeItem(nwItemType.FILE, hLevel=3)
assert hNewScene in tree
@@ -182,8 +201,8 @@ def testGuiProjTree_NewTreeItem(qtbot, caplog, monkeypatch, nwGUI, projPath, moc
assert nwGUI.docEditor.getText() == "### New Scene\n\n"
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
"Novel", "Title Page", "New Folder", "New Chapter", "New Scene",
"New Folder", "New Document", "New Chapter", "New Scene", "Plot",
"Characters", "Locations", "Objects", "Trash",
"New Folder", "New Document", "New Part", "New Chapter", "New Scene",
"Plot", "Characters", "Locations", "Objects", "Trash",
]
# Add a new scene with the content copied from the previous
@@ -191,7 +210,7 @@ def testGuiProjTree_NewTreeItem(qtbot, caplog, monkeypatch, nwGUI, projPath, moc
nwGUI.docEditor.setPlainText("### New Scene\n\nWith Stuff\n\n")
nwGUI.saveDocument()
hNewSceneCopy = "0000000000016"
hNewSceneCopy = "0000000000017"
projView.setSelectedHandle(hNewScene, doScroll=True)
projTree.newTreeItem(nwItemType.FILE, copyDoc=hNewScene)
assert hNewSceneCopy in tree
@@ -205,12 +224,12 @@ def testGuiProjTree_NewTreeItem(qtbot, caplog, monkeypatch, nwGUI, projPath, moc
assert nwGUI.docEditor.getText() == "### New Scene\n\nWith Stuff\n\n"
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
"Novel", "Title Page", "New Folder", "New Chapter", "New Scene",
"New Folder", "New Document", "New Chapter", "New Scene", "New Scene",
"Plot", "Characters", "Locations", "Objects", "Trash",
"New Folder", "New Document", "New Part", "New Chapter", "New Scene",
"New Scene", "Plot", "Characters", "Locations", "Objects", "Trash",
]
# Add a new file to the characters folder
hNewCharacter = "0000000000017"
hNewCharacter = "0000000000018"
projView.setSelectedHandle(C.hCharRoot, doScroll=True)
projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True)
assert hNewCharacter in tree
@@ -224,8 +243,9 @@ def testGuiProjTree_NewTreeItem(qtbot, caplog, monkeypatch, nwGUI, projPath, moc
assert nwGUI.docEditor.getText() == "# New Note\n\n"
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
"Novel", "Title Page", "New Folder", "New Chapter", "New Scene",
"New Folder", "New Document", "New Chapter", "New Scene", "New Scene",
"Plot", "Characters", "New Note", "Locations", "Objects", "Trash",
"New Folder", "New Document", "New Part", "New Chapter", "New Scene",
"New Scene", "Plot", "Characters", "New Note", "Locations",
"Objects", "Trash",
]
# Cancel during creation
@@ -235,15 +255,16 @@ def testGuiProjTree_NewTreeItem(qtbot, caplog, monkeypatch, nwGUI, projPath, moc
projTree.newTreeItem(nwItemType.FILE)
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
"Novel", "Title Page", "New Folder", "New Chapter", "New Scene",
"New Folder", "New Document", "New Chapter", "New Scene", "New Scene",
"Plot", "Characters", "New Note", "Locations", "Objects", "Trash",
"New Folder", "New Document", "New Part", "New Chapter", "New Scene",
"New Scene", "Plot", "Characters", "New Note", "Locations",
"Objects", "Trash",
]
# From Template
# =============
# Create template folder
hTemplateRoot = "0000000000018"
hTemplateRoot = "0000000000019"
projView.setSelectedHandle(hObjectRoot)
projTree.newTreeItem(nwItemType.ROOT, nwItemClass.TEMPLATE)
assert hTemplateRoot in tree
@@ -255,13 +276,13 @@ def testGuiProjTree_NewTreeItem(qtbot, caplog, monkeypatch, nwGUI, projPath, moc
assert item.itemClass == nwItemClass.TEMPLATE
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
"Novel", "Title Page", "New Folder", "New Chapter", "New Scene",
"New Folder", "New Document", "New Chapter", "New Scene", "New Scene",
"Plot", "Characters", "New Note", "Locations", "Objects", "Templates",
"Trash",
"New Folder", "New Document", "New Part", "New Chapter", "New Scene",
"New Scene", "Plot", "Characters", "New Note", "Locations",
"Objects", "Templates", "Trash",
]
# Create scene template
hSceneTemplate = "0000000000019"
hSceneTemplate = "000000000001a"
projView.setSelectedHandle(hTemplateRoot, doScroll=True)
projTree.newTreeItem(nwItemType.FILE, hLevel=3)
assert hSceneTemplate in tree
@@ -278,13 +299,13 @@ def testGuiProjTree_NewTreeItem(qtbot, caplog, monkeypatch, nwGUI, projPath, moc
nwGUI.saveDocument()
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
"Novel", "Title Page", "New Folder", "New Chapter", "New Scene",
"New Folder", "New Document", "New Chapter", "New Scene", "New Scene",
"Plot", "Characters", "New Note", "Locations", "Objects", "Templates",
"New Scene Template", "Trash",
"New Folder", "New Document", "New Part", "New Chapter", "New Scene",
"New Scene", "Plot", "Characters", "New Note", "Locations",
"Objects", "Templates", "New Scene Template", "Trash",
]
# Create from template
hNewFromTemplate = "000000000001a"
hNewFromTemplate = "000000000001b"
projView.setSelectedHandle(hNewSceneCopy, doScroll=True)
projView.createFileFromTemplate(hSceneTemplate)
assert hNewFromTemplate in tree
@@ -298,9 +319,9 @@ def testGuiProjTree_NewTreeItem(qtbot, caplog, monkeypatch, nwGUI, projPath, moc
assert nwGUI.docEditor.getText() == "### New Scene Template\n\nWith Stuff\n\n"
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
"Novel", "Title Page", "New Folder", "New Chapter", "New Scene",
"New Folder", "New Document", "New Chapter", "New Scene", "New Scene",
"New Scene Template", "Plot", "Characters", "New Note", "Locations",
"Objects", "Templates", "New Scene Template", "Trash",
"New Folder", "New Document", "New Part", "New Chapter", "New Scene",
"New Scene", "New Scene Template", "Plot", "Characters", "New Note",
"Locations", "Objects", "Templates", "New Scene Template", "Trash",
]
# Rename Item
@@ -489,7 +510,7 @@ def testGuiProjTree_MouseClicks(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
# Single click emits a signal
with qtbot.waitSignal(projView.selectedItemChanged) as signal:
projTree._onSingleClick(model.indexFromHandle(C.hNovelRoot))
projTree._onSelectionChange(model.indexFromHandle(C.hNovelRoot), QModelIndex())
assert signal.args[0] == C.hNovelRoot
# Double click on folder expands/collapses it
@@ -1065,7 +1086,7 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
# Handles for new objects
hCharNote = "0000000000011"
hNovelNote = "0000000000012"
hTrashDoc = "0000000000013"
hTrashDoc = "0000000000013"
hSubNote = "0000000000014"
hNewFolderOne = "0000000000015"
hNewFolderTwo = "0000000000017"
@@ -1090,7 +1111,7 @@ def testGuiProjTree_ContextMenu(qtbot, monkeypatch, nwGUI, projPath, mockRnd):
assert [n.item.itemName for n in tree.model.root.allChildren()] == [
"Novel", "Title Page", "New Folder", "New Chapter", "New Scene",
"New Note", "SubNote", "Plot", "Characters", "New Note", "Locations",
"Trash", "New Document",
"Trash", "New Part",
]
# Pop the menu in various positions and check for success