Keep project tree and outline tree in sync

This commit is contained in:
Veronica K. B. Olsen
2021-01-02 17:33:53 +01:00
parent 4d7f925c5a
commit 21d91193a2
3 changed files with 59 additions and 9 deletions
+5 -5
View File
@@ -165,7 +165,7 @@ class GuiOutline(QTreeWidget):
return return
def refreshTree(self, overRide=False): def refreshTree(self, overRide=False, novelChanged=False):
"""Called whenever the Outline tab is activated and controls """Called whenever the Outline tab is activated and controls
what data to load, and if necessary, force a rebuild of the what data to load, and if necessary, force a rebuild of the
tree. tree.
@@ -177,10 +177,10 @@ class GuiOutline(QTreeWidget):
self.firstView = False self.firstView = False
return return
# If the novel index has changed since the tree was last built, # If the novel index or novel tree has changed since the tree
# we rebuild the tree from the updated index. # was last built, we rebuild the tree from the updated index.
idxChanged = self.theParent.theIndex.novelChangedSince(self.lastBuild) indexChanged = self.theIndex.novelChangedSince(self.lastBuild)
doBuild = idxChanged and self.theProject.autoOutline doBuild = (novelChanged or indexChanged) and self.theProject.autoOutline
if doBuild or overRide: if doBuild or overRide:
logger.debug("Rebuilding Project Outline") logger.debug("Rebuilding Project Outline")
self._populateTree() self._populateTree()
+27 -2
View File
@@ -31,7 +31,7 @@ import logging
from time import time from time import time
from PyQt5.QtCore import Qt, QSize from PyQt5.QtCore import Qt, QSize, pyqtSignal
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
qApp, QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction qApp, QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction
@@ -51,6 +51,9 @@ class GuiProjectTree(QTreeWidget):
C_EXPORT = 2 C_EXPORT = 2
C_FLAGS = 3 C_FLAGS = 3
novelItemChanged = pyqtSignal()
noteItemChanged = pyqtSignal()
def __init__(self, theParent): def __init__(self, theParent):
QTreeWidget.__init__(self, theParent) QTreeWidget.__init__(self, theParent)
@@ -285,8 +288,11 @@ class GuiProjectTree(QTreeWidget):
pHandle = nwItem.itemParent pHandle = nwItem.itemParent
if pHandle is not None and pHandle in self._treeMap: if pHandle is not None and pHandle in self._treeMap:
self._treeMap[pHandle].setExpanded(True) self._treeMap[pHandle].setExpanded(True)
self._emitItemChange(tHandle)
self.clearSelection() self.clearSelection()
trItem.setSelected(True) trItem.setSelected(True)
return True return True
def moveTreeItem(self, nStep): def moveTreeItem(self, nStep):
@@ -327,6 +333,7 @@ class GuiProjectTree(QTreeWidget):
self.clearSelection() self.clearSelection()
cItem.setSelected(True) cItem.setSelected(True)
self._setTreeChanged(True) self._setTreeChanged(True)
self._emitItemChange(tHandle)
return True return True
@@ -788,6 +795,10 @@ class GuiProjectTree(QTreeWidget):
else: else:
self.theIndex.reIndexHandle(sHandle) self.theIndex.reIndexHandle(sHandle)
# Trigger dependent updates
self._setTreeChanged(True)
self._emitItemChange(sHandle)
else: else:
theEvent.ignore() theEvent.ignore()
logger.debug("Drag'n'drop of item %s not accepted" % sHandle) logger.debug("Drag'n'drop of item %s not accepted" % sHandle)
@@ -915,7 +926,6 @@ class GuiProjectTree(QTreeWidget):
pHandle = trItemP.data(self.C_NAME, Qt.UserRole) pHandle = trItemP.data(self.C_NAME, Qt.UserRole)
nwItemS.setParent(pHandle) nwItemS.setParent(pHandle)
self.setTreeItemValues(tHandle) self.setTreeItemValues(tHandle)
self._setTreeChanged(True)
logger.debug("The parent of item %s has been changed to %s" % (tHandle, pHandle)) logger.debug("The parent of item %s has been changed to %s" % (tHandle, pHandle))
@@ -930,6 +940,21 @@ class GuiProjectTree(QTreeWidget):
self.theProject.setProjectChanged(True) self.theProject.setProjectChanged(True)
return return
def _emitItemChange(self, tHandle):
"""Emit an item change signal for a given handle.
"""
nwItem = self.theProject.projTree[tHandle]
if nwItem is None:
return
if nwItem.itemType == nwItemType.FILE:
if nwItem.itemClass == nwItemClass.NOVEL:
self.novelItemChanged.emit()
else:
self.noteItemChanged.emit()
return
# END Class GuiProjectTree # END Class GuiProjectTree
class GuiProjectTreeMenu(QMenu): class GuiProjectTreeMenu(QMenu):
+27 -2
View File
@@ -32,7 +32,7 @@ import os
from datetime import datetime from datetime import datetime
from time import time from time import time
from PyQt5.QtCore import Qt, QTimer, QThreadPool from PyQt5.QtCore import Qt, QTimer, QThreadPool, pyqtSlot
from PyQt5.QtGui import QIcon, QPixmap, QColor, QKeySequence, QCursor from PyQt5.QtGui import QIcon, QPixmap, QColor, QKeySequence, QCursor
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
qApp, QMainWindow, QVBoxLayout, QWidget, QSplitter, QFileDialog, QShortcut, qApp, QMainWindow, QVBoxLayout, QWidget, QSplitter, QFileDialog, QShortcut,
@@ -193,6 +193,7 @@ class GuiMain(QMainWindow):
# Initialise the Project Tree # Initialise the Project Tree
self.treeView.itemSelectionChanged.connect(self._treeSingleClick) self.treeView.itemSelectionChanged.connect(self._treeSingleClick)
self.treeView.itemDoubleClicked.connect(self._treeDoubleClick) self.treeView.itemDoubleClicked.connect(self._treeDoubleClick)
self.treeView.novelItemChanged.connect(self._treeNovelItemChanged)
self.rebuildTrees() self.rebuildTrees()
# Set Main Window Elements # Set Main Window Elements
@@ -1319,9 +1320,10 @@ class GuiMain(QMainWindow):
return return
## ##
# Signal Handlers # Slots
## ##
@pyqtSlot()
def _treeSingleClick(self): def _treeSingleClick(self):
"""Single click on a project tree item just updates the details """Single click on a project tree item just updates the details
panel below the tree. panel below the tree.
@@ -1331,12 +1333,14 @@ class GuiMain(QMainWindow):
self.treeMeta.updateViewBox(sHandle) self.treeMeta.updateViewBox(sHandle)
return return
@pyqtSlot("QTreeWidgetItem*", int)
def _treeDoubleClick(self, tItem, colNo): def _treeDoubleClick(self, tItem, colNo):
"""The user double-clicked an item in the tree. If it is a file, """The user double-clicked an item in the tree. If it is a file,
we open it. Otherwise, we do nothing. we open it. Otherwise, we do nothing.
""" """
tHandle = tItem.data(self.treeView.C_NAME, Qt.UserRole) tHandle = tItem.data(self.treeView.C_NAME, Qt.UserRole)
logger.verbose("User double clicked tree item with handle %s" % tHandle) logger.verbose("User double clicked tree item with handle %s" % tHandle)
nwItem = self.theProject.projTree[tHandle] nwItem = self.theProject.projTree[tHandle]
if nwItem is not None: if nwItem is not None:
if nwItem.itemType == nwItemType.FILE: if nwItem.itemType == nwItemType.FILE:
@@ -1347,6 +1351,20 @@ class GuiMain(QMainWindow):
return return
@pyqtSlot()
def _treeNovelItemChanged(self):
"""Triggered when there is a change to a novel item in the
project tree.
"""
if self.mainTabs.currentIndex() == self.idxTabProj:
logger.verbose("Novel tree changed while Outline tab active")
if self.hasProject:
self.treeView.flushTreeOrder()
self.projView.refreshTree(novelChanged=True)
return
@pyqtSlot()
def _treeKeyPressReturn(self): def _treeKeyPressReturn(self):
"""The user pressed return on an item in the tree. If it is a """The user pressed return on an item in the tree. If it is a
file, we open it. Otherwise, we do nothing. Pressing return does file, we open it. Otherwise, we do nothing. Pressing return does
@@ -1354,6 +1372,7 @@ class GuiMain(QMainWindow):
""" """
tHandle = self.treeView.getSelectedHandle() tHandle = self.treeView.getSelectedHandle()
logger.verbose("User pressed return on tree item with handle %s" % tHandle) logger.verbose("User pressed return on tree item with handle %s" % tHandle)
nwItem = self.theProject.projTree[tHandle] nwItem = self.theProject.projTree[tHandle]
if nwItem is not None: if nwItem is not None:
if nwItem.itemType == nwItemType.FILE: if nwItem.itemType == nwItemType.FILE:
@@ -1361,8 +1380,10 @@ class GuiMain(QMainWindow):
self.openDocument(tHandle, changeFocus=False, doScroll=False) self.openDocument(tHandle, changeFocus=False, doScroll=False)
else: else:
logger.verbose("Requested item %s is a folder" % tHandle) logger.verbose("Requested item %s is a folder" % tHandle)
return return
@pyqtSlot()
def _keyPressEscape(self): def _keyPressEscape(self):
"""When the escape key is pressed somewhere in the main window, """When the escape key is pressed somewhere in the main window,
do the following, in order: do the following, in order:
@@ -1371,8 +1392,10 @@ class GuiMain(QMainWindow):
self.docEditor.closeSearch() self.docEditor.closeSearch()
elif self.isFocusMode: elif self.isFocusMode:
self.toggleFocusMode() self.toggleFocusMode()
return return
@pyqtSlot(int)
def _mainTabChanged(self, tabIndex): def _mainTabChanged(self, tabIndex):
"""Activated when the main window tab is changed. """Activated when the main window tab is changed.
""" """
@@ -1382,8 +1405,10 @@ class GuiMain(QMainWindow):
logger.verbose("Project outline tab activated") logger.verbose("Project outline tab activated")
if self.hasProject: if self.hasProject:
self.projView.refreshTree() self.projView.refreshTree()
return return
@pyqtSlot(int)
def _projTabsChanged(self, tabIndex): def _projTabsChanged(self, tabIndex):
"""Activated when the project view tab is changed. """Activated when the project view tab is changed.
""" """