Shift all view changing functionality to the new Views bar

This commit is contained in:
Veronica Berglyd Olsen
2022-05-10 22:14:35 +02:00
parent ea09a53496
commit 864b06a0e7
6 changed files with 102 additions and 74 deletions
+13
View File
@@ -130,6 +130,19 @@ class nwState(Enum):
# END Enum nwState # END Enum nwState
class nwView(Enum):
PROJECT = 0
NOVEL = 1
OUTLINE = 2
DETAILS = 3
STATS = 4
SET_PROJ = 5
SET_MAIN = 6
# END Enum nwView
class nwWidget(Enum): class nwWidget(Enum):
TREE = 1 TREE = 1
+25 -3
View File
@@ -26,14 +26,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
import logging import logging
import novelwriter import novelwriter
from PyQt5.QtCore import Qt, QSize from PyQt5.QtCore import Qt, QSize, pyqtSignal
from PyQt5.QtWidgets import QToolBar, QWidget, QSizePolicy, QAction from PyQt5.QtWidgets import QToolBar, QWidget, QSizePolicy, QAction
from novelwriter.enum import nwView
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class GuiViewsBar(QToolBar): class GuiViewsBar(QToolBar):
viewChangeRequested = pyqtSignal(nwView)
def __init__(self, theParent): def __init__(self, theParent):
QToolBar.__init__(self, theParent) QToolBar.__init__(self, theParent)
@@ -60,17 +64,35 @@ class GuiViewsBar(QToolBar):
# Actions # Actions
self.aProject = QAction(self.tr("Project")) self.aProject = QAction(self.tr("Project"))
self.aProject.setIcon(self.theTheme.getIcon("status_lines")) self.aProject.setIcon(self.theTheme.getIcon("proj_folder"))
self.aProject.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.PROJECT))
self.aNovel = QAction(self.tr("Novel"))
self.aNovel.setIcon(self.theTheme.getIcon("cls_novel"))
self.aNovel.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.NOVEL))
self.aOutline = QAction(self.tr("Outline"))
self.aOutline.setIcon(self.theTheme.getIcon("cls_plot"))
self.aOutline.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.OUTLINE))
self.aDetails = QAction(self.tr("Details"))
self.aDetails.setIcon(self.theTheme.getIcon("status_lines"))
self.aDetails.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.DETAILS))
self.aStats = QAction(self.tr("Stats")) self.aStats = QAction(self.tr("Stats"))
self.aStats.setIcon(self.theTheme.getIcon("status_stats")) self.aStats.setIcon(self.theTheme.getIcon("status_stats"))
self.aStats.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.STATS))
self.aSettings = QAction(self.tr("Settings")) self.aSettings = QAction(self.tr("Settings"))
self.aSettings.setIcon(self.theTheme.getIcon("settings")) self.aSettings.setIcon(self.theTheme.getIcon("settings"))
self.aSettings.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.SET_PROJ))
# Assemble # Assemble
self.addWidget(stretch)
self.addAction(self.aProject) self.addAction(self.aProject)
self.addAction(self.aNovel)
self.addAction(self.aOutline)
self.addWidget(stretch)
self.addAction(self.aDetails)
self.addAction(self.aStats) self.addAction(self.aStats)
self.addAction(self.aSettings) self.addAction(self.aSettings)
+60 -67
View File
@@ -30,11 +30,11 @@ import novelwriter
from time import time from time import time
from datetime import datetime from datetime import datetime
from PyQt5.QtCore import Qt, QTimer, QSize, QThreadPool, pyqtSlot from PyQt5.QtCore import Qt, QTimer, QThreadPool, pyqtSlot
from PyQt5.QtGui import QIcon, QKeySequence, QCursor from PyQt5.QtGui import QIcon, QKeySequence, QCursor
from PyQt5.QtWidgets import ( from PyQt5.QtWidgets import (
qApp, QMainWindow, QVBoxLayout, QWidget, QSplitter, QFileDialog, QShortcut, qApp, QMainWindow, QVBoxLayout, QWidget, QSplitter, QFileDialog, QShortcut,
QMessageBox, QDialog, QTabWidget, QToolBar, QAction QMessageBox, QDialog, QStackedWidget
) )
from novelwriter.gui import ( from novelwriter.gui import (
@@ -52,7 +52,7 @@ from novelwriter.tools import (
) )
from novelwriter.core import NWProject, NWIndex from novelwriter.core import NWProject, NWIndex
from novelwriter.enum import ( from novelwriter.enum import (
nwItemType, nwItemClass, nwAlert, nwWidget, nwState nwItemType, nwItemClass, nwAlert, nwWidget, nwState, nwView
) )
from novelwriter.common import getGuiItem, hexToInt from novelwriter.common import getGuiItem, hexToInt
@@ -102,8 +102,6 @@ class GuiMain(QMainWindow):
# Sizes # Sizes
mPx = self.mainConf.pxInt(4) mPx = self.mainConf.pxInt(4)
fPx = self.theTheme.fontPixelSize
fPt = self.theTheme.fontPointSize
# Main GUI Elements # Main GUI Elements
self.statusBar = GuiMainStatus(self) self.statusBar = GuiMainStatus(self)
@@ -129,48 +127,20 @@ class GuiMain(QMainWindow):
self.treeView.novelItemChanged.connect(self._treeNovelItemChanged) self.treeView.novelItemChanged.connect(self._treeNovelItemChanged)
self.treeView.wordCountsChanged.connect(self._updateStatusWordCount) self.treeView.wordCountsChanged.connect(self._updateStatusWordCount)
# Project Tree Tabs self.viewsBar.viewChangeRequested.connect(self._changeView)
self.projTabs = QTabWidget()
self.projTabs.setTabPosition(QTabWidget.South)
self.projTabs.setStyleSheet("QTabWidget::pane {border: 0;};")
self.projTabs.addTab(self.treeView, self.tr("Project"))
self.projTabs.addTab(self.novelView, self.tr("Novel"))
self.projTabs.currentChanged.connect(self._projTabsChanged)
tabFont = self.projTabs.tabBar().font() # Project Tree Stack
tabFont.setPointSizeF(0.9*fPt) self.projStack = QStackedWidget()
self.projTabs.tabBar().setFont(tabFont) self.projStack.addWidget(self.treeView)
self.projStack.addWidget(self.novelView)
# Project Tree Action Buttons self.projStack.currentChanged.connect(self._projStackChanged)
btnSize = int(round(0.7*fPx))
self.treeButtons = QToolBar()
self.treeButtons.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.treeButtons.setIconSize(QSize(btnSize, btnSize))
self.treeButtons.setContentsMargins(0, 0, 0, 0)
self.treeButtons.setStyleSheet("QToolBar {padding: 0;}")
self.projTabs.setCornerWidget(self.treeButtons, Qt.BottomRightCorner)
self.projDetailsBtn = QAction(self.tr("Project Details"))
self.projDetailsBtn.setIcon(self.theTheme.getIcon("status_lines"))
self.projDetailsBtn.triggered.connect(lambda: self.showProjectDetailsDialog())
self.treeButtons.addAction(self.projDetailsBtn)
self.projStatsBtn = QAction(self.tr("Writing Statistics"))
self.projStatsBtn.setIcon(self.theTheme.getIcon("status_stats"))
self.projStatsBtn.triggered.connect(lambda: self.showWritingStatsDialog())
self.treeButtons.addAction(self.projStatsBtn)
self.projSettingsBtn = QAction(self.tr("Project Settings"))
self.projSettingsBtn.setIcon(self.theTheme.getIcon("settings"))
self.projSettingsBtn.triggered.connect(lambda: self.showProjectSettingsDialog())
self.treeButtons.addAction(self.projSettingsBtn)
# Project Tree View # Project Tree View
self.treePane = QWidget() self.treePane = QWidget()
self.treeBox = QVBoxLayout() self.treeBox = QVBoxLayout()
self.treeBox.setContentsMargins(0, 0, 0, 0) self.treeBox.setContentsMargins(0, 0, 0, 0)
self.treeBox.setSpacing(mPx) self.treeBox.setSpacing(mPx)
self.treeBox.addWidget(self.projTabs) self.treeBox.addWidget(self.projStack)
self.treeBox.addWidget(self.treeMeta) self.treeBox.addWidget(self.treeMeta)
self.treePane.setLayout(self.treeBox) self.treePane.setLayout(self.treeBox)
@@ -192,33 +162,31 @@ class GuiMain(QMainWindow):
self.splitOutline.setSizes(self.mainConf.getOutlinePanePos()) self.splitOutline.setSizes(self.mainConf.getOutlinePanePos())
# Main Tabs : Editor / Outline # Main Tabs : Editor / Outline
self.mainTabs = QTabWidget() self.mainStack = QStackedWidget()
self.mainTabs.setTabPosition(QTabWidget.East) self.mainStack.addWidget(self.splitDocs)
self.mainTabs.setStyleSheet("QTabWidget::pane {border: 0;}") self.mainStack.addWidget(self.splitOutline)
self.mainTabs.addTab(self.splitDocs, self.tr("Editor")) self.mainStack.currentChanged.connect(self._mainStackChanged)
self.mainTabs.addTab(self.splitOutline, self.tr("Outline"))
self.mainTabs.currentChanged.connect(self._mainTabChanged)
# Splitter : Project Tree / Main Tabs # Splitter : Project Tree / Main Tabs
self.splitMain = QSplitter(Qt.Horizontal) self.splitMain = QSplitter(Qt.Horizontal)
self.splitMain.setContentsMargins(mPx, mPx, mPx, mPx) self.splitMain.setContentsMargins(mPx, mPx, mPx, mPx)
self.splitMain.addWidget(self.treePane) self.splitMain.addWidget(self.treePane)
self.splitMain.addWidget(self.mainTabs) self.splitMain.addWidget(self.mainStack)
self.splitMain.setSizes(self.mainConf.getMainPanePos()) self.splitMain.setSizes(self.mainConf.getMainPanePos())
# Indices of Splitter Widgets # Indices of Splitter Widgets
self.idxTree = self.splitMain.indexOf(self.treePane) self.idxTree = self.splitMain.indexOf(self.treePane)
self.idxMain = self.splitMain.indexOf(self.mainTabs) self.idxMain = self.splitMain.indexOf(self.mainStack)
self.idxEditor = self.splitDocs.indexOf(self.docEditor) self.idxEditor = self.splitDocs.indexOf(self.docEditor)
self.idxViewer = self.splitDocs.indexOf(self.splitView) self.idxViewer = self.splitDocs.indexOf(self.splitView)
self.idxViewDoc = self.splitView.indexOf(self.docViewer) self.idxViewDoc = self.splitView.indexOf(self.docViewer)
self.idxViewMeta = self.splitView.indexOf(self.viewMeta) self.idxViewMeta = self.splitView.indexOf(self.viewMeta)
# Indices of Tab Widgets # Indices of Tab Widgets
self.idxTabEdit = self.mainTabs.indexOf(self.splitDocs) self.idxTabEdit = self.mainStack.indexOf(self.splitDocs)
self.idxTabProj = self.mainTabs.indexOf(self.splitOutline) self.idxTabProj = self.mainStack.indexOf(self.splitOutline)
self.idxTreeView = self.projTabs.indexOf(self.treeView) self.idxTreeView = self.projStack.indexOf(self.treeView)
self.idxNovelView = self.projTabs.indexOf(self.novelView) self.idxNovelView = self.projStack.indexOf(self.novelView)
# Splitter Behaviour # Splitter Behaviour
self.splitMain.setCollapsible(self.idxTree, False) self.splitMain.setCollapsible(self.idxTree, False)
@@ -450,7 +418,7 @@ class GuiMain(QMainWindow):
self.theIndex.clearIndex() self.theIndex.clearIndex()
self.clearGUI() self.clearGUI()
self.hasProject = False self.hasProject = False
self.mainTabs.setCurrentWidget(self.splitDocs) self.mainStack.setCurrentWidget(self.splitDocs)
return saveOK return saveOK
@@ -466,7 +434,7 @@ class GuiMain(QMainWindow):
return False return False
# Switch main tab to editor view # Switch main tab to editor view
self.mainTabs.setCurrentWidget(self.splitDocs) self.mainStack.setCurrentWidget(self.splitDocs)
# Try to open the project # Try to open the project
if not self.theProject.openProject(projFile): if not self.theProject.openProject(projFile):
@@ -605,7 +573,7 @@ class GuiMain(QMainWindow):
return False return False
self.closeDocument() self.closeDocument()
self.mainTabs.setCurrentWidget(self.splitDocs) self.mainStack.setCurrentWidget(self.splitDocs)
if self.docEditor.loadText(tHandle, tLine): if self.docEditor.loadText(tHandle, tLine):
if changeFocus: if changeFocus:
self.docEditor.setFocus() self.docEditor.setFocus()
@@ -688,7 +656,7 @@ class GuiMain(QMainWindow):
return False return False
# Make sure main tab is in Editor view # Make sure main tab is in Editor view
self.mainTabs.setCurrentWidget(self.splitDocs) self.mainStack.setCurrentWidget(self.splitDocs)
logger.debug("Viewing document with handle '%s'", tHandle) logger.debug("Viewing document with handle '%s'", tHandle)
if self.docViewer.loadText(tHandle): if self.docViewer.loadText(tHandle):
@@ -873,7 +841,7 @@ class GuiMain(QMainWindow):
def requestNovelTreeRefresh(self): def requestNovelTreeRefresh(self):
"""Update the novel tree, but only if it is visible. """Update the novel tree, but only if it is visible.
""" """
if self.projTabs.currentIndex() == self.idxNovelView and self.hasProject: if self.projStack.currentIndex() == self.idxNovelView and self.hasProject:
self.novelView.refreshTree() self.novelView.refreshTree()
return True return True
return False return False
@@ -934,7 +902,7 @@ class GuiMain(QMainWindow):
return False return False
logger.verbose("Forcing a rebuild of the Project Outline") logger.verbose("Forcing a rebuild of the Project Outline")
self.mainTabs.setCurrentWidget(self.splitOutline) self.mainStack.setCurrentWidget(self.splitOutline)
self.projView.refreshTree(overRide=True) self.projView.refreshTree(overRide=True)
return True return True
@@ -1247,19 +1215,19 @@ class GuiMain(QMainWindow):
"""Switch focus between main GUI views. """Switch focus between main GUI views.
""" """
if paneNo == nwWidget.TREE: if paneNo == nwWidget.TREE:
tabIdx = self.projTabs.currentIndex() tabIdx = self.projStack.currentIndex()
if tabIdx == self.idxTreeView: if tabIdx == self.idxTreeView:
self.treeView.setFocus() self.treeView.setFocus()
elif tabIdx == self.idxNovelView: elif tabIdx == self.idxNovelView:
self.novelView.setFocus() self.novelView.setFocus()
elif paneNo == nwWidget.EDITOR: elif paneNo == nwWidget.EDITOR:
self.mainTabs.setCurrentWidget(self.splitDocs) self.mainStack.setCurrentWidget(self.splitDocs)
self.docEditor.setFocus() self.docEditor.setFocus()
elif paneNo == nwWidget.VIEWER: elif paneNo == nwWidget.VIEWER:
self.mainTabs.setCurrentWidget(self.splitDocs) self.mainStack.setCurrentWidget(self.splitDocs)
self.docViewer.setFocus() self.docViewer.setFocus()
elif paneNo == nwWidget.OUTLINE: elif paneNo == nwWidget.OUTLINE:
self.mainTabs.setCurrentWidget(self.splitOutline) self.mainStack.setCurrentWidget(self.splitOutline)
self.projView.setFocus() self.projView.setFocus()
return return
@@ -1292,7 +1260,7 @@ class GuiMain(QMainWindow):
self.mainMenu.setFocusMode(self.isFocusMode) self.mainMenu.setFocusMode(self.isFocusMode)
if self.isFocusMode: if self.isFocusMode:
logger.debug("Activating Focus Mode") logger.debug("Activating Focus Mode")
self.mainTabs.setCurrentWidget(self.splitDocs) self.mainStack.setCurrentWidget(self.splitDocs)
self.switchFocus(nwWidget.EDITOR) self.switchFocus(nwWidget.EDITOR)
else: else:
logger.debug("Deactivating Focus Mode") logger.debug("Deactivating Focus Mode")
@@ -1302,7 +1270,6 @@ class GuiMain(QMainWindow):
self.statusBar.setVisible(isVisible) self.statusBar.setVisible(isVisible)
self.mainMenu.setVisible(isVisible) self.mainMenu.setVisible(isVisible)
self.viewsBar.setVisible(isVisible) self.viewsBar.setVisible(isVisible)
self.mainTabs.tabBar().setVisible(isVisible)
hideDocFooter = self.isFocusMode and self.mainConf.hideFocusFooter hideDocFooter = self.isFocusMode and self.mainConf.hideFocusFooter
self.docEditor.docFooter.setVisible(not hideDocFooter) self.docEditor.docFooter.setVisible(not hideDocFooter)
@@ -1516,6 +1483,32 @@ class GuiMain(QMainWindow):
# Slots # Slots
## ##
@pyqtSlot(nwView)
def _changeView(self, view):
"""Handle the requested change of view from the GuiViewBar.
"""
if view == nwView.PROJECT:
self.mainStack.setCurrentWidget(self.splitDocs)
self.projStack.setCurrentWidget(self.treeView)
elif view == nwView.NOVEL:
self.mainStack.setCurrentWidget(self.splitDocs)
self.projStack.setCurrentWidget(self.novelView)
elif view == nwView.OUTLINE:
self.mainStack.setCurrentWidget(self.splitOutline)
elif view == nwView.DETAILS:
self.showProjectDetailsDialog()
elif view == nwView.STATS:
self.showWritingStatsDialog()
elif view == nwView.SET_PROJ:
self.showProjectSettingsDialog()
return
@pyqtSlot() @pyqtSlot()
def _timeTick(self): def _timeTick(self):
"""Triggered on every tick of the main timer. """Triggered on every tick of the main timer.
@@ -1589,7 +1582,7 @@ class GuiMain(QMainWindow):
"""Triggered when there is a change to a novel item in the """Triggered when there is a change to a novel item in the
project tree. project tree.
""" """
if self.mainTabs.currentIndex() == self.idxTabProj: if self.mainStack.currentIndex() == self.idxTabProj:
logger.verbose("Novel tree changed while Outline tab active") logger.verbose("Novel tree changed while Outline tab active")
if self.hasProject: if self.hasProject:
self.treeView.flushTreeOrder() self.treeView.flushTreeOrder()
@@ -1618,7 +1611,7 @@ class GuiMain(QMainWindow):
return return
@pyqtSlot(int) @pyqtSlot(int)
def _mainTabChanged(self, tabIndex): def _mainStackChanged(self, tabIndex):
"""Activated when the main window tab is changed. """Activated when the main window tab is changed.
""" """
if tabIndex == self.idxTabEdit: if tabIndex == self.idxTabEdit:
@@ -1631,7 +1624,7 @@ class GuiMain(QMainWindow):
return return
@pyqtSlot(int) @pyqtSlot(int)
def _projTabsChanged(self, tabIndex): def _projStackChanged(self, tabIndex):
"""Activated when the project view tab is changed. """Activated when the project view tab is changed.
""" """
sHandle = None sHandle = None
+2 -2
View File
@@ -85,7 +85,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Project Tree has focus # Project Tree has focus
nwGUI.switchFocus(nwWidget.TREE) nwGUI.switchFocus(nwWidget.TREE)
nwGUI.projTabs.setCurrentIndex(0) nwGUI.projStack.setCurrentIndex(0)
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(GuiProjectTree, "hasFocus", lambda *a: True) mp.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
assert nwGUI.docEditor.docHandle() is None assert nwGUI.docEditor.docHandle() is None
@@ -95,7 +95,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
assert nwGUI.closeDocument() is True assert nwGUI.closeDocument() is True
# Novel Tree has focus # Novel Tree has focus
nwGUI.projTabs.setCurrentIndex(1) nwGUI.projStack.setCurrentIndex(1)
nwGUI.novelView.refreshTree(True) nwGUI.novelView.refreshTree(True)
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(GuiNovelTree, "hasFocus", lambda *a: True) mp.setattr(GuiNovelTree, "hasFocus", lambda *a: True)
+1 -1
View File
@@ -59,7 +59,7 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
# Populate Tree # Populate Tree
## ##
nwGUI.projTabs.setCurrentIndex(nwGUI.idxNovelView) nwGUI.projStack.setCurrentIndex(nwGUI.idxNovelView)
nwGUI.rebuildIndex() nwGUI.rebuildIndex()
nwTree._populateTree() nwTree._populateTree()
assert nwTree.topLevelItemCount() == 1 assert nwTree.topLevelItemCount() == 1
+1 -1
View File
@@ -43,7 +43,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
nwGUI.mainConf.lastPath = nwLipsum nwGUI.mainConf.lastPath = nwLipsum
nwGUI.rebuildIndex() nwGUI.rebuildIndex()
nwGUI.mainTabs.setCurrentIndex(nwGUI.idxTabProj) nwGUI.mainStack.setCurrentIndex(nwGUI.idxTabProj)
assert nwGUI.projView.topLevelItemCount() > 0 assert nwGUI.projView.topLevelItemCount() > 0