Add item duplication functionality to project tree

This commit is contained in:
Veronica Berglyd Olsen
2023-07-20 18:51:50 +02:00
parent 567045e4ff
commit 1559e3299a
+53 -13
View File
@@ -24,11 +24,13 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
import logging
from enum import Enum
from time import time
from typing import TYPE_CHECKING
from PyQt5.QtGui import QPalette
from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
@@ -42,12 +44,15 @@ from novelwriter import CONFIG
from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert, nwWidget
from novelwriter.constants import nwHeaders, nwUnicode, trConst, nwLabels
from novelwriter.core.item import NWItem
from novelwriter.core.coretools import DocMerger, DocSplitter
from novelwriter.core.coretools import DocDuplicator, DocMerger, DocSplitter
from novelwriter.dialogs.docmerge import GuiDocMerge
from novelwriter.dialogs.docsplit import GuiDocSplit
from novelwriter.dialogs.editlabel import GuiEditLabel
from novelwriter.dialogs.projsettings import GuiProjectSettings
if TYPE_CHECKING: # pragma: no cover
from novelwriter.guimain import GuiMain
logger = logging.getLogger(__name__)
@@ -69,7 +74,7 @@ class GuiProjectView(QWidget):
# Requests for the main GUI
projectSettingsRequest = pyqtSignal(int)
def __init__(self, mainGui):
def __init__(self, mainGui: GuiMain):
super().__init__(parent=mainGui)
self.mainGui = mainGui
@@ -452,7 +457,7 @@ class GuiProjectTree(QTreeWidget):
D_HANDLE = Qt.ItemDataRole.UserRole
D_WORDS = Qt.ItemDataRole.UserRole + 1
def __init__(self, projView):
def __init__(self, projView: GuiProjectView):
super().__init__(parent=projView)
logger.debug("Create: GuiProjectTree")
@@ -1308,8 +1313,8 @@ class GuiProjectTree(QTreeWidget):
aSplit1 = mTrans.addAction(self.tr("Split Document by Headers"))
aSplit1.triggered.connect(lambda: self._splitDocument(tHandle))
# Expand/Collapse/Delete
# ======================
# Expand/Collapse/Delete/Duplicate
# ================================
ctxMenu.addSeparator()
@@ -1318,6 +1323,11 @@ class GuiProjectTree(QTreeWidget):
aExpand.triggered.connect(lambda: self.setExpandedFromHandle(tHandle, True))
aCollapse = ctxMenu.addAction(self.tr("Collapse All"))
aCollapse.triggered.connect(lambda: self.setExpandedFromHandle(tHandle, False))
aDuplicate = ctxMenu.addAction(self.tr("Duplicate from Here"))
aDuplicate.triggered.connect(lambda: self._duplicateFromHandle(tHandle))
elif isFile:
aDuplicate = ctxMenu.addAction(self.tr("Duplicate Document"))
aDuplicate.triggered.connect(lambda: self._duplicateFromHandle(tHandle))
if tItem.itemClass == nwItemClass.TRASH or isRoot or (isFolder and not hasChild):
aDelete = ctxMenu.addAction(self.tr("Delete Permanently"))
@@ -1532,8 +1542,7 @@ class GuiProjectTree(QTreeWidget):
return
def _mergeDocuments(self, tHandle, newFile):
"""Merge an item's child documents into a single document.
"""
"""Merge an item's child documents into a single document."""
logger.info("Request to merge items under handle '%s'", tHandle)
itemList = self.getTreeFromHandle(tHandle)
@@ -1608,8 +1617,7 @@ class GuiProjectTree(QTreeWidget):
return True
def _splitDocument(self, tHandle):
"""Split a document into multiple documents.
"""
"""Split a document into multiple documents."""
logger.info("Request to split items with handle '%s'", tHandle)
tItem = self.theProject.tree[tHandle]
@@ -1660,7 +1668,39 @@ class GuiProjectTree(QTreeWidget):
return True
def _scanChildren(self, theList, tItem, tIndex):
def _duplicateFromHandle(self, tHandle: str) -> bool:
"""Duplicate the item hierarchy from a given item."""
itemTree = self.getTreeFromHandle(tHandle)
nItems = len(itemTree)
if nItems == 0:
return False
elif nItems == 1:
qTitle = self.tr("Duplicate Document")
qText = self.tr("Do you want to duplicate this document?")
else:
qTitle = self.tr("Duplicate from Here")
qText = self.tr("Do you want to duplicate this item and all child items?")
if not self.mainGui.askQuestion(qTitle, qText):
return False
docDup = DocDuplicator(self.theProject)
dupCount = 0
for dHandle, nHandle in docDup.duplicate(itemTree):
print(dHandle, nHandle)
self.theProject.index.reIndexHandle(dHandle)
self.revealNewTreeItem(dHandle, nHandle=nHandle, wordCount=True)
self._alertTreeChange(dHandle, flush=False)
dupCount += 1
if dupCount != nItems:
self.mainGui.makeAlert(self.tr("Could not duplicate all items."), nwAlert.ERROR)
self.saveTreeOrder()
return True
def _scanChildren(self, itemList: list, tItem: QTreeWidgetItem, tIndex: int):
"""This is a recursive function returning all items in a tree
starting at a given QTreeWidgetItem.
"""
@@ -1673,11 +1713,11 @@ class GuiProjectTree(QTreeWidget):
nwItem.setExpanded(tItem.isExpanded() and cCount > 0)
nwItem.setOrder(tIndex)
theList.append(tHandle)
itemList.append(tHandle)
for i in range(cCount):
self._scanChildren(theList, tItem.child(i), i)
self._scanChildren(itemList, tItem.child(i), i)
return theList
return itemList
def _addTreeItem(self, nwItem, nHandle=None):
"""Create a QTreeWidgetItem from an NWItem and add it to the