Move the decision logic of where to put new items to the NWTree class and improve (#2260)
This commit is contained in:
@@ -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,29 @@ 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
|
||||
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)
|
||||
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
|
||||
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.
|
||||
|
||||
+38
-36
@@ -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
|
||||
|
||||
##
|
||||
@@ -606,12 +613,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 +631,46 @@ 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, sPos = SHARED.project.tree.pickParent(node, nLevel, nNote)
|
||||
if not sHandle:
|
||||
SHARED.error(self.tr("Did not find anywhere to add the file or folder!"))
|
||||
return
|
||||
|
||||
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 tHandle := SHARED.project.newFile(newLabel, sHandle, sPos):
|
||||
if copyDoc:
|
||||
SHARED.project.copyFileContent(tHandle, copyDoc)
|
||||
elif hLevel > 0:
|
||||
SHARED.project.writeNewFile(tHandle, hLevel, not isNote)
|
||||
SHARED.project.writeNewFile(tHandle, hLevel, not nNote)
|
||||
SHARED.project.index.reIndexHandle(tHandle)
|
||||
SHARED.project.tree.refreshItems([tHandle])
|
||||
else:
|
||||
tHandle = SHARED.project.newFolder(newLabel, sHandle, pos)
|
||||
tHandle = SHARED.project.newFolder(newLabel, sHandle, sPos)
|
||||
|
||||
# Select the new item automatically
|
||||
if tHandle:
|
||||
@@ -1198,9 +1199,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
|
||||
|
||||
Reference in New Issue
Block a user