diff --git a/novelwriter/core/tree.py b/novelwriter/core/tree.py index 9ee92eb9..a3c93745 100644 --- a/novelwriter/core/tree.py +++ b/novelwriter/core/tree.py @@ -270,16 +270,18 @@ class NWTree: pNode = sNode.parent() pLevel = nwStyles.H_LEVEL.get(pNode.item.mainHeading, 0) if pNode else 0 - sLevel = 0 if isNote else nwStyles.H_LEVEL.get(sNode.item.mainHeading, 0) - if pNode and pNode.item.isFileType() and pLevel == hLevel and sLevel > hLevel: - # If the selected item is deeper level, but the parent is a document - # of the same level, we make it a sibling of the parent (See #2260) + # 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 (sLevel < hLevel or isNote): - # If the item already has child nodes and is of a lower level - # or is a note, we make the new item a child + 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 diff --git a/tests/test_core/test_core_tree.py b/tests/test_core/test_core_tree.py index b33d6dd7..1c96f580 100644 --- a/tests/test_core/test_core_tree.py +++ b/tests/test_core/test_core_tree.py @@ -252,7 +252,7 @@ def testCoreTree_PickParent(mockGUI, mockItems): # =============================== # Add a chapter under Part One - hChapterOne = tree.create("Chapter One", hPartOne, nwItemType.FILE, pos=sPos) + hChapterOne = tree.create("Chapter One", hPartOne, nwItemType.FILE) assert hChapterOne is not None nChapterOne = tree.nodes[hChapterOne] assert nChapterOne.item.itemParent == hPartOne @@ -273,6 +273,18 @@ def testCoreTree_PickParent(mockGUI, mockItems): 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 # ================================= @@ -286,6 +298,25 @@ def testCoreTree_PickParent(mockGUI, mockItems): 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 # ============= @@ -293,7 +324,7 @@ def testCoreTree_PickParent(mockGUI, mockItems): nCharRoot = tree.nodes[hCharRoot] # Add a note at root level - hNoteOne = tree.create("Note One", hCharRoot, nwItemType.FILE, pos=sPos) + hNoteOne = tree.create("Note One", hCharRoot, nwItemType.FILE) assert hNoteOne is not None nNoteOne = tree.nodes[hNoteOne] assert nNoteOne.item.itemClass == nwItemClass.CHARACTER @@ -306,7 +337,7 @@ def testCoreTree_PickParent(mockGUI, mockItems): assert sPos == 1 # Add a child note to Note One - hNoteTwo = tree.create("Note Two", hNoteOne, nwItemType.FILE, pos=sPos) + hNoteTwo = tree.create("Note Two", hNoteOne, nwItemType.FILE) assert hNoteTwo is not None nNoteTwo = tree.nodes[hNoteTwo] assert nNoteTwo.item.itemClass == nwItemClass.CHARACTER