Streamline how project item changes are reported

This commit is contained in:
Veronica Berglyd Olsen
2022-06-05 17:25:39 +02:00
parent 2873336dce
commit 88976d6800
9 changed files with 122 additions and 123 deletions
+67 -57
View File
@@ -32,11 +32,13 @@ from time import time
from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (
QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction, QFrame
QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction, QFrame,
QDialog
)
from novelwriter.core import NWDoc
from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert
from novelwriter.dialogs.itemeditor import GuiItemEditor
logger = logging.getLogger(__name__)
@@ -48,10 +50,10 @@ class GuiProjectTree(QTreeWidget):
C_EXPORT = 2
C_STATUS = 3
novelItemChanged = pyqtSignal()
noteItemChanged = pyqtSignal()
treeItemChanged = pyqtSignal(str)
novelItemChanged = pyqtSignal(str)
rootFolderChanged = pyqtSignal(str)
wordCountsChanged = pyqtSignal()
rootFoldersChanged = pyqtSignal()
def __init__(self, theParent):
QTreeWidget.__init__(self, theParent)
@@ -64,10 +66,9 @@ class GuiProjectTree(QTreeWidget):
self.theProject = theParent.theProject
# Internal Variables
self._treeMap = {}
self._treeChanged = False
self._treeMap = {}
self._lastMove = {}
self._timeChanged = 0
self._lastMove = {}
##
# Build GUI
@@ -157,15 +158,15 @@ class GuiProjectTree(QTreeWidget):
"""
self.clear()
self._treeMap = {}
self._treeChanged = False
self._lastMove = {}
self._timeChanged = 0
return
def newTreeItem(self, itemType, itemClass=None):
"""Add new item to the tree, with a given itemType (and
itemClass if Root), and attach it to the selected handle. Also make
sure the item is added in a place it can be added, and that other
meta data is set correctly to ensure a valid project tree.
itemClass if Root), and attach it to the selected handle. Also
make sure the item is added in a place it can be added, and that
other meta data is set correctly to ensure a valid project tree.
"""
if not self.theParent.hasProject:
logger.error("No project open")
@@ -177,7 +178,6 @@ class GuiProjectTree(QTreeWidget):
if itemType == nwItemType.ROOT and isinstance(itemClass, nwItemClass):
tHandle = self.theProject.newRoot(itemClass)
self.rootFoldersChanged.emit()
elif itemType in (nwItemType.FILE, nwItemType.FOLDER):
@@ -223,9 +223,9 @@ class GuiProjectTree(QTreeWidget):
# Add the new item to the tree
self.revealNewTreeItem(tHandle, nHandle)
self.theParent.editItem(tHandle)
nwItem = self.theProject.tree[tHandle]
# If this is a folder, return here
# Handle new file creation
nwItem = self.theProject.tree[tHandle]
if nwItem.itemType != nwItemType.FILE:
return True
@@ -268,7 +268,7 @@ class GuiProjectTree(QTreeWidget):
if pHandle is not None and pHandle in self._treeMap:
self._treeMap[pHandle].setExpanded(True)
self._emitItemChange(tHandle)
self._alertTreeChange(tHandle=tHandle, flush=True)
self.clearSelection()
trItem.setSelected(True)
@@ -310,10 +310,31 @@ class GuiProjectTree(QTreeWidget):
pItem.insertChild(nIndex, cItem)
self._recordLastMove(cItem, pItem, tIndex)
self._alertTreeChange(tHandle=tHandle, flush=True)
self.clearSelection()
cItem.setSelected(True)
self._setTreeChanged(True)
self._emitItemChange(tHandle)
return True
def editTreeItem(self, tHandle=None):
"""Open the edit item dialog.
"""
if tHandle is None:
logger.warning("No item selected")
return False
tItem = self.theProject.tree[tHandle]
if tItem is None:
return False
if tItem.itemType == nwItemType.NO_TYPE:
return False
logger.verbose("Requesting change to item '%s'", tHandle)
dlgProj = GuiItemEditor(self, tHandle)
dlgProj.exec_()
if dlgProj.result() == QDialog.Accepted:
self.setTreeItemValues(tHandle)
self._alertTreeChange(tHandle=tHandle, flush=False)
return True
@@ -330,16 +351,6 @@ class GuiProjectTree(QTreeWidget):
self.theProject.setTreeOrder(theList)
return True
def flushTreeOrder(self):
"""Calls saveTreeOrder if there are unsaved changes, otherwise
does nothing.
"""
if self._treeChanged:
logger.verbose("Flushing project tree to project class")
self.saveTreeOrder()
self._setTreeChanged(False)
return
def getTreeFromHandle(self, tHandle):
"""Recursively return all the children items starting from a
given item handle.
@@ -411,7 +422,7 @@ class GuiProjectTree(QTreeWidget):
self.deleteItem(tHandle, alreadyAsked=True, bulkAction=True)
if nTrash > 0:
self._setTreeChanged(True)
self._alertTreeChange(tHandle=trashHandle, flush=True)
return True
@@ -445,6 +456,7 @@ class GuiProjectTree(QTreeWidget):
return False
wCount = self._getItemWordCount(tHandle)
autoFlush = not bulkAction
if nwItemS.itemType == nwItemType.ROOT:
# Only an empty ROOT folder can be deleted
logger.debug("User requested a root folder '%s' deleted", tHandle)
@@ -452,8 +464,7 @@ class GuiProjectTree(QTreeWidget):
if trItemS.childCount() == 0:
self.takeTopLevelItem(tIndex)
self._deleteTreeItem(tHandle)
self._setTreeChanged(True)
self.rootFoldersChanged.emit()
self._alertTreeChange(tHandle=tHandle, flush=True)
else:
self.theParent.makeAlert(self.tr(
"Cannot delete root folder. It is not empty. "
@@ -469,7 +480,7 @@ class GuiProjectTree(QTreeWidget):
tIndex = trItemP.indexOfChild(trItemS)
trItemP.takeChild(tIndex)
self._deleteTreeItem(tHandle)
self._setTreeChanged(True)
self._alertTreeChange(tHandle=tHandle, flush=autoFlush)
else:
# A populated FOLDER or a FILE requires confirmtation
@@ -505,7 +516,7 @@ class GuiProjectTree(QTreeWidget):
self.theParent.closeDocument()
self._deleteTreeItem(dHandle)
self._setTreeChanged(True)
self._alertTreeChange(tHandle=tHandle, flush=autoFlush)
self.wordCountsChanged.emit()
else:
@@ -524,7 +535,7 @@ class GuiProjectTree(QTreeWidget):
trItemT.addChild(trItemC)
self._postItemMove(tHandle, wCount)
self._recordLastMove(trItemS, trItemP, tIndex)
self._setTreeChanged(True)
self._alertTreeChange(tHandle=tHandle, flush=autoFlush)
return True
@@ -660,6 +671,7 @@ class GuiProjectTree(QTreeWidget):
dstItem.insertChild(dstIndex, movItem)
self._postItemMove(sHandle, wCount)
self._alertTreeChange(tHandle=sHandle, flush=True)
self.clearSelection()
movItem.setSelected(True)
@@ -788,6 +800,7 @@ class GuiProjectTree(QTreeWidget):
QTreeWidget.dropEvent(self, theEvent)
self._postItemMove(sHandle, wCount)
self._recordLastMove(sItem, pItem, pIndex)
self._alertTreeChange(tHandle=sHandle, flush=True)
sItem.setExpanded(isExpanded)
return
@@ -829,8 +842,6 @@ class GuiProjectTree(QTreeWidget):
# Trigger dependent updates
self.propagateCount(tHandle, wCount)
self._setTreeChanged(True)
self._emitItemChange(tHandle)
return True
@@ -931,8 +942,6 @@ class GuiProjectTree(QTreeWidget):
self.setTreeItemValues(tHandle)
newItem.setExpanded(nwItem.isExpanded)
self._setTreeChanged(True)
return newItem
def _addTrashRoot(self):
@@ -945,33 +954,34 @@ class GuiProjectTree(QTreeWidget):
trItem = self._getTreeItem(trashHandle)
if trItem is None:
trItem = self._addTreeItem(
self.theProject.tree[trashHandle]
)
trItem = self._addTreeItem(self.theProject.tree[trashHandle])
if trItem is not None:
trItem.setExpanded(True)
self._setTreeChanged(True)
self._alertTreeChange(tHandle=trashHandle, flush=True)
return trItem
def _setTreeChanged(self, theState):
"""Set the tree change flag, and propagate to the project.
def _alertTreeChange(self, tHandle=None, flush=True):
"""Update information on tree change state, and emit necessary
signals.
"""
self._treeChanged = theState
if theState:
self._timeChanged = time()
self.theProject.setProjectChanged(True)
return
self._timeChanged = time()
self.theProject.setProjectChanged(True)
if flush:
self.saveTreeOrder()
tItem = self.theProject.tree[tHandle]
if tItem is None:
return
itemType = tItem.itemType
if itemType == nwItemType.ROOT:
self.rootFolderChanged.emit(tHandle)
elif itemType == nwItemType.FILE and tItem.isNovelLike():
self.novelItemChanged.emit(tHandle)
self.treeItemChanged.emit(tHandle)
def _emitItemChange(self, tHandle):
"""Emit an item change signal for a given handle.
"""
if self.theProject.tree.checkType(tHandle, nwItemType.FILE):
nwItem = self.theProject.tree[tHandle]
if nwItem.isNovelLike():
self.novelItemChanged.emit()
else:
self.noteItemChanged.emit()
return
def _recordLastMove(self, srcItem, parItem, parIndex):