Wrap the novel tree in an outer widget

This commit is contained in:
Veronica Berglyd Olsen
2022-06-12 15:45:39 +02:00
parent ed5c52859d
commit b3eb276437
5 changed files with 126 additions and 67 deletions
+2 -2
View File
@@ -23,7 +23,7 @@ from novelwriter.gui.doceditor import GuiDocEditor
from novelwriter.gui.docviewer import GuiDocViewer, GuiDocViewDetails
from novelwriter.gui.itemdetails import GuiItemDetails
from novelwriter.gui.mainmenu import GuiMainMenu
from novelwriter.gui.noveltree import GuiNovelTree
from novelwriter.gui.noveltree import GuiNovelView
from novelwriter.gui.outline import GuiOutlineView
from novelwriter.gui.projtree import GuiProjectView
from novelwriter.gui.statusbar import GuiMainStatus
@@ -37,7 +37,7 @@ __all__ = [
"GuiItemDetails",
"GuiMainMenu",
"GuiMainStatus",
"GuiNovelTree",
"GuiNovelView",
"GuiOutlineView",
"GuiProjectView",
"GuiTheme",
+76 -17
View File
@@ -30,7 +30,8 @@ from time import time
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import (
QTreeWidget, QTreeWidgetItem, QAbstractItemView, QFrame
QAbstractItemView, QFrame, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
QWidget
)
from novelwriter.common import checkInt
@@ -39,21 +40,88 @@ from novelwriter.constants import nwKeyWords
logger = logging.getLogger(__name__)
class GuiNovelView(QWidget):
def __init__(self, mainGui):
QWidget.__init__(self, mainGui)
self.mainGui = mainGui
# Build GUI
self.novelTree = GuiNovelTree(self)
self.novelBar = GuiNovelToolBar(self)
# Assemble
self.outerBox = QVBoxLayout()
self.outerBox.addWidget(self.novelBar, 0)
self.outerBox.addWidget(self.novelTree, 1)
self.outerBox.setContentsMargins(0, 0, 0, 0)
self.outerBox.setSpacing(0)
self.setLayout(self.outerBox)
# Function Mappings
self.refreshTree = self.novelTree.refreshTree
self.updateWordCounts = self.novelTree.updateWordCounts
self.getSelectedHandle = self.novelTree.getSelectedHandle
return
##
# Methods
##
def initSettings(self):
self.novelTree.initSettings()
return
def clearProject(self):
self.novelTree.clearTree()
return
def setFocus(self):
"""Forward the set focus call to the tree widget.
"""
self.novelTree.setFocus()
return
def treeFocus(self):
"""Check if the novel tree has focus.
"""
return self.novelTree.hasFocus()
# END Class GuiNovelView
class GuiNovelToolBar(QWidget):
def __init__(self, novelView):
QTreeWidget.__init__(self, novelView)
self.mainConf = novelwriter.CONFIG
self.novelView = novelView
return
# END Class GuiNovelToolBar
class GuiNovelTree(QTreeWidget):
C_TITLE = 0
C_WORDS = 1
C_POV = 2
def __init__(self, mainGui):
QTreeWidget.__init__(self, mainGui)
def __init__(self, novelView):
QTreeWidget.__init__(self, novelView)
logger.debug("Initialising GuiNovelTree ...")
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self.novelView = novelView
self.mainGui = novelView.mainGui
self.mainTheme = novelView.mainGui.mainTheme
self.theProject = novelView.mainGui.theProject
# Internal Variables
self._treeMap = {}
@@ -97,13 +165,13 @@ class GuiNovelTree(QTreeWidget):
self.resizeColumnToContents(self.C_POV)
# Set custom settings
self.initTree()
self.initSettings()
logger.debug("GuiNovelTree initialisation complete")
return
def initTree(self):
def initSettings(self):
"""Set or update tree widget settings.
"""
# Scroll bars
@@ -162,15 +230,6 @@ class GuiNovelTree(QTreeWidget):
self._treeMap[titleKey].setText(self.C_WORDS, f"{wCount:n}")
return
def getColumnSizes(self):
"""Return the column widths for the tree columns.
"""
retVals = [
self.columnWidth(0),
self.columnWidth(1),
]
return retVals
def getSelectedHandle(self):
"""Get the currently selected handle. If multiple items are
selected, return the first.
+5 -6
View File
@@ -40,7 +40,7 @@ from PyQt5.QtWidgets import (
from novelwriter.gui import (
GuiDocEditor, GuiDocViewDetails, GuiDocViewer, GuiItemDetails, GuiMainMenu,
GuiMainStatus, GuiNovelTree, GuiOutlineView, GuiProjectView, GuiTheme,
GuiMainStatus, GuiNovelView, GuiOutlineView, GuiProjectView, GuiTheme,
GuiViewsBar
)
from novelwriter.dialogs import (
@@ -106,7 +106,7 @@ class GuiMain(QMainWindow):
# Main GUI Elements
self.statusBar = GuiMainStatus(self)
self.projView = GuiProjectView(self)
self.novelView = GuiNovelTree(self)
self.novelView = GuiNovelView(self)
self.docEditor = GuiDocEditor(self)
self.viewMeta = GuiDocViewDetails(self)
self.docViewer = GuiDocViewer(self)
@@ -292,7 +292,7 @@ class GuiMain(QMainWindow):
"""
# Project Area
self.projView.clearProject()
self.novelView.clearTree()
self.novelView.clearProject()
self.itemDetails.clearDetails()
# Work Area
@@ -791,7 +791,7 @@ class GuiMain(QMainWindow):
tLine = None
if self.projView.treeFocus():
tHandle = self.projView.getSelectedHandle()
elif self.novelView.hasFocus():
elif self.novelView.treeFocus():
tHandle, tLine = self.novelView.getSelectedHandle()
elif self.outlineView.treeFocus():
tHandle, tLine = self.outlineView.getSelectedHandle()
@@ -920,7 +920,7 @@ class GuiMain(QMainWindow):
self.docEditor.initEditor()
self.docViewer.initViewer()
self.projView.initSettings()
self.novelView.initTree()
self.novelView.initSettings()
self.outlineView.initOutline()
self._updateStatusWordCount()
@@ -1161,7 +1161,6 @@ class GuiMain(QMainWindow):
self.mainConf.setViewPanePos(self.splitView.sizes())
self.mainConf.setShowRefPanel(self.viewMeta.isVisible())
self.mainConf.setNovelColWidths(self.novelView.getColumnSizes())
if not self.mainConf.isFullScreen:
self.mainConf.setWinSize(self.width(), self.height())
+4 -4
View File
@@ -28,7 +28,7 @@ from tools import cmpFiles, buildTestProject, XML_IGNORE, writeFile
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMessageBox, QInputDialog
from novelwriter.gui import GuiDocEditor, GuiNovelTree, GuiOutlineView
from novelwriter.gui import GuiDocEditor, GuiNovelView, GuiOutlineView
from novelwriter.enum import nwItemType, nwWidget
from novelwriter.tools import GuiProjectWizard
from novelwriter.gui.projtree import GuiProjectTree
@@ -134,12 +134,12 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
nwGUI.projStack.setCurrentIndex(1)
nwGUI.novelView.refreshTree(True)
with monkeypatch.context() as mp:
mp.setattr(GuiNovelTree, "hasFocus", lambda *a: True)
mp.setattr(GuiNovelView, "treeFocus", lambda *a: True)
assert nwGUI.docEditor.docHandle() is None
actItem = nwGUI.novelView.topLevelItem(0)
actItem = nwGUI.novelView.novelTree.topLevelItem(0)
chpItem = actItem.child(0)
selItem = chpItem.child(0)
nwGUI.novelView.setCurrentItem(selItem)
nwGUI.novelView.novelTree.setCurrentItem(selItem)
nwGUI._keyPressReturn()
assert nwGUI.docEditor.docHandle() == sHandle
assert nwGUI.closeDocument() is True
+39 -38
View File
@@ -37,23 +37,24 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
nwGUI.openProject(nwMinimal)
nwTree = nwGUI.novelView
novelView = nwGUI.novelView
novelTree = novelView.novelTree
##
# Show/Hide Scrollbars
##
nwTree.mainConf.hideVScroll = True
nwTree.mainConf.hideHScroll = True
nwTree.initTree()
assert not nwTree.verticalScrollBar().isVisible()
assert not nwTree.horizontalScrollBar().isVisible()
nwGUI.mainConf.hideVScroll = True
nwGUI.mainConf.hideHScroll = True
novelView.initSettings()
assert not novelTree.verticalScrollBar().isVisible()
assert not novelTree.horizontalScrollBar().isVisible()
nwTree.mainConf.hideVScroll = False
nwTree.mainConf.hideHScroll = False
nwTree.initTree()
assert nwTree.verticalScrollBar().isEnabled()
assert nwTree.horizontalScrollBar().isEnabled()
nwGUI.mainConf.hideVScroll = False
nwGUI.mainConf.hideHScroll = False
novelView.initSettings()
assert novelTree.verticalScrollBar().isEnabled()
assert novelTree.horizontalScrollBar().isEnabled()
##
# Populate Tree
@@ -61,31 +62,31 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
nwGUI.projStack.setCurrentIndex(nwGUI.idxNovelView)
nwGUI.rebuildIndex()
nwTree._populateTree()
assert nwTree.topLevelItemCount() == 1
novelTree._populateTree()
assert novelTree.topLevelItemCount() == 1
# Rebuild should preserve selection
topItem = nwTree.topLevelItem(0)
topItem = novelTree.topLevelItem(0)
assert not topItem.isSelected()
topItem.setSelected(True)
assert nwTree.selectedItems()[0] == topItem
assert nwTree.getSelectedHandle() == ("a35baf2e93843", 0)
assert novelTree.selectedItems()[0] == topItem
assert novelView.getSelectedHandle() == ("a35baf2e93843", 0)
nwTree.refreshTree()
assert nwTree.topLevelItem(0).isSelected()
novelView.refreshTree()
assert novelTree.topLevelItem(0).isSelected()
##
# Open Items
##
# Clear selection
nwTree.clearSelection()
scItem = nwTree.topLevelItem(0).child(0).child(0)
novelTree.clearSelection()
scItem = novelTree.topLevelItem(0).child(0).child(0)
scItem.setSelected(True)
assert scItem.isSelected()
# Clear selection with mouse
vPort = nwTree.viewport()
vPort = novelTree.viewport()
qtbot.mouseClick(vPort, Qt.LeftButton, pos=vPort.rect().center(), delay=10)
assert not scItem.isSelected()
@@ -93,7 +94,7 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
scItem.setSelected(True)
assert scItem.isSelected()
assert nwGUI.docEditor.docHandle() is None
nwTree._treeDoubleClick(scItem, 0)
novelTree._treeDoubleClick(scItem, 0)
assert nwGUI.docEditor.docHandle() == "8c659a11cd429"
# Open item with middle mouse button
@@ -103,13 +104,13 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
qtbot.mouseClick(vPort, Qt.MiddleButton, pos=vPort.rect().center(), delay=10)
assert nwGUI.docViewer.docHandle() is None
scRect = nwTree.visualItemRect(scItem)
oldData = scItem.data(nwTree.C_TITLE, Qt.UserRole)
scItem.setData(nwTree.C_TITLE, Qt.UserRole, (None, "", ""))
scRect = novelTree.visualItemRect(scItem)
oldData = scItem.data(novelTree.C_TITLE, Qt.UserRole)
scItem.setData(novelTree.C_TITLE, Qt.UserRole, (None, "", ""))
qtbot.mouseClick(vPort, Qt.MiddleButton, pos=scRect.center(), delay=10)
assert nwGUI.docViewer.docHandle() is None
scItem.setData(nwTree.C_TITLE, Qt.UserRole, oldData)
scItem.setData(novelTree.C_TITLE, Qt.UserRole, oldData)
qtbot.mouseClick(vPort, Qt.MiddleButton, pos=scRect.center(), delay=10)
assert nwGUI.docViewer.docHandle() == "8c659a11cd429"
@@ -132,23 +133,23 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
"#### Section\n\n"
))
nwGUI.rebuildIndex()
nwTree._populateTree()
assert nwTree.topLevelItem(0).text(nwTree.C_TITLE) == "Section wo/Scene"
assert nwTree.topLevelItem(1).text(nwTree.C_TITLE) == "Scene wo/Chapter"
assert nwTree.topLevelItem(2).text(nwTree.C_TITLE) == "Chapter wo/Title"
assert nwTree.topLevelItem(3).text(nwTree.C_TITLE) == "Title"
novelTree._populateTree()
assert novelTree.topLevelItem(0).text(novelTree.C_TITLE) == "Section wo/Scene"
assert novelTree.topLevelItem(1).text(novelTree.C_TITLE) == "Scene wo/Chapter"
assert novelTree.topLevelItem(2).text(novelTree.C_TITLE) == "Chapter wo/Title"
assert novelTree.topLevelItem(3).text(novelTree.C_TITLE) == "Title"
tTitle = nwTree.topLevelItem(3)
assert tTitle.child(0).text(nwTree.C_TITLE) == "Section w/Title, wo/Scene"
assert tTitle.child(1).text(nwTree.C_TITLE) == "Scene w/Title, wo/Chapter"
assert tTitle.child(2).text(nwTree.C_TITLE) == "Chapter"
tTitle = novelTree.topLevelItem(3)
assert tTitle.child(0).text(novelTree.C_TITLE) == "Section w/Title, wo/Scene"
assert tTitle.child(1).text(novelTree.C_TITLE) == "Scene w/Title, wo/Chapter"
assert tTitle.child(2).text(novelTree.C_TITLE) == "Chapter"
tChap = tTitle.child(2)
assert tChap.child(0).text(nwTree.C_TITLE) == "Section w/Chapter, wo/Scene"
assert tChap.child(1).text(nwTree.C_TITLE) == "Scene"
assert tChap.child(0).text(novelTree.C_TITLE) == "Section w/Chapter, wo/Scene"
assert tChap.child(1).text(novelTree.C_TITLE) == "Scene"
tScene = tChap.child(1)
assert tScene.child(0).text(nwTree.C_TITLE) == "Section"
assert tScene.child(0).text(novelTree.C_TITLE) == "Section"
##
# Close