From 669eabc7e88696a31339d30ea5252a294d96823e Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Mon, 6 Jun 2022 13:46:54 +0200
Subject: [PATCH 01/35] Handle actions in the project tree internally in the
class
---
novelwriter/gui/projtree.py | 98 ++++++++++++++++++++++++-------------
novelwriter/guimain.py | 83 +++++++++++++------------------
2 files changed, 99 insertions(+), 82 deletions(-)
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index e0a8ef62..4a069f42 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -27,6 +27,7 @@ along with this program. If not, see .
import logging
import novelwriter
+from enum import Enum
from time import time
from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
@@ -37,7 +38,7 @@ from PyQt5.QtWidgets import (
)
from novelwriter.core import NWDoc
-from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert
+from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert
from novelwriter.common import minmax
from novelwriter.dialogs.itemeditor import GuiItemEditor
@@ -51,11 +52,16 @@ class GuiProjectTree(QTreeWidget):
C_EXPORT = 2
C_STATUS = 3
+ # Signals triggered when the meta data values of items change
treeItemChanged = pyqtSignal(str)
novelItemChanged = pyqtSignal(str)
rootFolderChanged = pyqtSignal(str)
wordCountsChanged = pyqtSignal()
+ # Signals for user interaction with the project tree
+ selectedItemChanged = pyqtSignal(str)
+ openDocumentRequest = pyqtSignal(str, Enum)
+
def __init__(self, theParent):
QTreeWidget.__init__(self, theParent)
@@ -127,6 +133,10 @@ class GuiProjectTree(QTreeWidget):
# The last column should just auto-scale
self.resizeColumnToContents(self.C_STATUS)
+ # Connect signals
+ self.itemDoubleClicked.connect(self._treeDoubleClick)
+ self.itemSelectionChanged.connect(self._treeSelectionChange)
+
# Set custom settings
self.initTree()
@@ -223,9 +233,9 @@ class GuiProjectTree(QTreeWidget):
if tHandle is None: # pragma: no cover
return True
- # Add the new item to the tree
+ # Add the new item to the tree and open the editor dialog
self.revealNewTreeItem(tHandle, nHandle)
- self.theParent.editItem(tHandle)
+ self.editTreeItem(tHandle)
# Handle new file creation
nwItem = self.theProject.tree[tHandle]
@@ -249,10 +259,7 @@ class GuiProjectTree(QTreeWidget):
pIndex.scanText(tHandle, newText)
# Get Word Counts
- cC, wC, pC = pIndex.getCounts(tHandle)
- nwItem.setCharCount(cC)
- nwItem.setWordCount(wC)
- nwItem.setParaCount(pC)
+ _, wC, _ = pIndex.getCounts(tHandle)
self.propagateCount(tHandle, wC)
self.wordCountsChanged.emit()
@@ -280,8 +287,8 @@ class GuiProjectTree(QTreeWidget):
return True
def moveTreeItem(self, nStep):
- """Move an item up or down in the tree, but only if the treeView
- has focus. This also applies when the menu is used.
+ """Move an item up or down in the tree, but only if the project
+ tree has focus. This also applies when the menu is used.
"""
if not self.theParent.hasProject:
logger.error("No project open")
@@ -321,13 +328,9 @@ class GuiProjectTree(QTreeWidget):
return True
- def editTreeItem(self, tHandle=None):
+ def editTreeItem(self, tHandle):
"""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
@@ -357,8 +360,8 @@ class GuiProjectTree(QTreeWidget):
return True
def getTreeFromHandle(self, tHandle):
- """Recursively return all the children items starting from a
- given item handle.
+ """Recursively return all the child items starting from a given
+ item handle.
"""
theList = []
theItem = self._getTreeItem(tHandle)
@@ -366,14 +369,6 @@ class GuiProjectTree(QTreeWidget):
theList = self._scanChildren(theList, theItem, 0)
return theList
- def toggleExpanded(self, tHandle):
- """Expand an item based on its handle.
- """
- trItem = self._getTreeItem(tHandle)
- if trItem is not None:
- trItem.setExpanded(not trItem.isExpanded())
- return
-
def getColumnSizes(self):
"""Return the column widths for the tree columns.
"""
@@ -719,9 +714,52 @@ class GuiProjectTree(QTreeWidget):
return self._timeChanged > checkTime
##
- # Slots
+ # Public Solts
##
+ @pyqtSlot(str, int, int, int)
+ def doUpdateCounts(self, tHandle, cCount, wCount, pCount):
+ """Slot for updating the word count of a specific item.
+ """
+ self.propagateCount(tHandle, wCount, countChildren=True)
+ self.wordCountsChanged.emit()
+ return
+
+ ##
+ # Private Slots
+ ##
+
+ @pyqtSlot()
+ def _treeSelectionChange(self):
+ """The user changed which item is selected.
+ """
+ tHandle = self.getSelectedHandle()
+ if tHandle is not None:
+ self.selectedItemChanged.emit(tHandle)
+ return
+
+ @pyqtSlot("QTreeWidgetItem*", int)
+ def _treeDoubleClick(self, tItem, colNo):
+ """Capture a double-click event and either request the document
+ for editing if it is a file, or expand/close the node it is not.
+ """
+ tHandle = self.getSelectedHandle()
+ if tHandle is None:
+ return
+
+ tItem = self.theProject.tree[tHandle]
+ if tItem is None:
+ return
+
+ if tItem.itemType == nwItemType.FILE:
+ self.openDocumentRequest.emit(tHandle, nwDocMode.EDIT)
+ else:
+ trItem = self._getTreeItem(tHandle)
+ if trItem is not None:
+ trItem.setExpanded(not trItem.isExpanded())
+
+ return
+
@pyqtSlot("QPoint")
def _rightClickMenu(self, clickPos):
"""The user right clicked an element in the project tree, so we
@@ -739,14 +777,6 @@ class GuiProjectTree(QTreeWidget):
return
- @pyqtSlot(str, int, int, int)
- def doUpdateCounts(self, tHandle, cCount, wCount, pCount):
- """Slot for updating the word count of a specific item.
- """
- self.propagateCount(tHandle, wCount, countChildren=True)
- self.wordCountsChanged.emit()
- return
-
##
# Events
##
@@ -774,7 +804,7 @@ class GuiProjectTree(QTreeWidget):
return
if tItem.itemType == nwItemType.FILE:
- self.theParent.viewDocument(tHandle)
+ self.openDocumentRequest.emit(tHandle, nwDocMode.VIEW)
return
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 6a056dca..354edbf4 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -115,28 +115,6 @@ class GuiMain(QMainWindow):
self.mainMenu = GuiMainMenu(self)
self.viewsBar = GuiViewsBar(self)
- # Connect Signals Between Main Elements
- self.viewsBar.viewChangeRequested.connect(self._changeView)
-
- self.treeView.itemSelectionChanged.connect(self._treeSingleClick)
- self.treeView.itemDoubleClicked.connect(self._treeDoubleClick)
- self.treeView.novelItemChanged.connect(self._treeNovelItemChanged)
- self.treeView.wordCountsChanged.connect(self._updateStatusWordCount)
- self.treeView.treeItemChanged.connect(self.docEditor.updateDocInfo)
- self.treeView.treeItemChanged.connect(self.docViewer.updateDocInfo)
- self.treeView.treeItemChanged.connect(self.treeMeta.updateViewBox)
- self.treeView.rootFolderChanged.connect(self.projView.updateRootItem)
-
- self.docEditor.spellDictionaryChanged.connect(self.statusBar.setLanguage)
- self.docEditor.docEditedStatusChanged.connect(self.statusBar.doUpdateDocumentStatus)
- self.docEditor.docCountsChanged.connect(self.treeMeta.doUpdateCounts)
- self.docEditor.docCountsChanged.connect(self.treeView.doUpdateCounts)
- self.docEditor.loadDocumentTagRequest.connect(self._followTag)
-
- self.docViewer.loadDocumentTagRequest.connect(self._followTag)
-
- self.projView.loadDocumentTagRequest.connect(self._followTag)
-
# Project Tree Stack
self.projStack = QStackedWidget()
self.projStack.addWidget(self.treeView)
@@ -214,6 +192,30 @@ class GuiMain(QMainWindow):
self.setStatusBar(self.statusBar)
self.addToolBar(Qt.LeftToolBarArea, self.viewsBar)
+ # Connect Signals
+ # ===============
+
+ self.viewsBar.viewChangeRequested.connect(self._changeView)
+
+ self.treeView.selectedItemChanged.connect(self.treeMeta.updateViewBox)
+ self.treeView.openDocumentRequest.connect(self._openDocument)
+ self.treeView.novelItemChanged.connect(self._treeNovelItemChanged)
+ self.treeView.wordCountsChanged.connect(self._updateStatusWordCount)
+ self.treeView.treeItemChanged.connect(self.docEditor.updateDocInfo)
+ self.treeView.treeItemChanged.connect(self.docViewer.updateDocInfo)
+ self.treeView.treeItemChanged.connect(self.treeMeta.updateViewBox)
+ self.treeView.rootFolderChanged.connect(self.projView.updateRootItem)
+
+ self.docEditor.spellDictionaryChanged.connect(self.statusBar.setLanguage)
+ self.docEditor.docEditedStatusChanged.connect(self.statusBar.doUpdateDocumentStatus)
+ self.docEditor.docCountsChanged.connect(self.treeMeta.doUpdateCounts)
+ self.docEditor.docCountsChanged.connect(self.treeView.doUpdateCounts)
+ self.docEditor.loadDocumentTagRequest.connect(self._followTag)
+
+ self.docViewer.loadDocumentTagRequest.connect(self._followTag)
+
+ self.projView.loadDocumentTagRequest.connect(self._followTag)
+
# Finalise Initialisation
# =======================
@@ -1468,6 +1470,17 @@ class GuiMain(QMainWindow):
self.viewDocument(tHandle=tHandle, tAnchor=f"#{sTitle}")
return
+ @pyqtSlot(str, Enum)
+ def _openDocument(self, tHandle, tMode):
+ """Handle an open document request.
+ """
+ if tHandle is not None:
+ if tMode == nwDocMode.EDIT:
+ self.openDocument(tHandle, changeFocus=False)
+ elif tMode == nwDocMode.VIEW:
+ self.viewDocument(tHandle=tHandle)
+ return
+
@pyqtSlot(nwView)
def _changeView(self, view):
"""Handle the requested change of view from the GuiViewBar.
@@ -1531,32 +1544,6 @@ class GuiMain(QMainWindow):
return
- @pyqtSlot()
- def _treeSingleClick(self):
- """Single click on a project tree item just updates the details
- panel below the tree.
- """
- tHandle = self.treeView.getSelectedHandle()
- if tHandle is not None:
- self.treeMeta.updateViewBox(tHandle)
- return
-
- @pyqtSlot("QTreeWidgetItem*", int)
- def _treeDoubleClick(self, tItem, colNo):
- """The user double-clicked an item in the tree. If it is a file,
- we open it. Otherwise, we toggle the expanded status.
- """
- tHandle = self.treeView.getSelectedHandle()
- if tHandle is not None:
- tItem = self.theProject.tree[tHandle]
- if tItem is None:
- return
- if tItem.itemType == nwItemType.FILE:
- self.openDocument(tHandle, changeFocus=False, doScroll=False)
- else:
- self.treeView.toggleExpanded(tHandle)
- return
-
@pyqtSlot()
def _treeNovelItemChanged(self):
"""Triggered when there is a change to a novel item in the
From b88cdb767727b6868e9b144920f79bbfc04e4069 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Mon, 6 Jun 2022 14:11:59 +0200
Subject: [PATCH 02/35] Make the project tree columns fixed
---
novelwriter/gui/projtree.py | 47 ++++++++++---------------------------
novelwriter/guimain.py | 1 -
2 files changed, 12 insertions(+), 36 deletions(-)
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index 4a069f42..c6d077b8 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -34,7 +34,7 @@ from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (
QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction, QFrame,
- QDialog
+ QDialog, QHeaderView
)
from novelwriter.core import NWDoc
@@ -88,28 +88,24 @@ class GuiProjectTree(QTreeWidget):
# Tree Settings
iPx = self.theTheme.baseIconSize
+ cMg = self.mainConf.pxInt(6)
self.setIconSize(QSize(iPx, iPx))
self.setFrameStyle(QFrame.NoFrame)
self.setExpandsOnDoubleClick(False)
+ self.setHeaderHidden(True)
self.setIndentation(iPx)
self.setColumnCount(4)
- self.setHeaderLabels([
- self.tr("Project Tree"), self.tr("Words"), "", ""
- ])
- treeHeadItem = self.headerItem()
- treeHeadItem.setTextAlignment(self.C_COUNT, Qt.AlignRight)
- treeHeadItem.setToolTip(self.C_NAME, self.tr("Item label"))
- treeHeadItem.setToolTip(self.C_COUNT, self.tr("Word count"))
- treeHeadItem.setToolTip(self.C_EXPORT, self.tr("Include in build"))
- treeHeadItem.setToolTip(self.C_STATUS, self.tr("Item status"))
-
- # Let the last column stretch, and set the minimum size to the
- # size of the icon as the default Qt font metrics approach fails
- # for some fonts like the Ubuntu font.
+ # Lock the column sizes
treeHeader = self.header()
- treeHeader.setStretchLastSection(True)
- treeHeader.setMinimumSectionSize(iPx + 6)
+ treeHeader.setStretchLastSection(False)
+ treeHeader.setMinimumSectionSize(iPx + cMg)
+ treeHeader.setSectionResizeMode(self.C_NAME, QHeaderView.Stretch)
+ treeHeader.setSectionResizeMode(self.C_COUNT, QHeaderView.ResizeToContents)
+ treeHeader.setSectionResizeMode(self.C_EXPORT, QHeaderView.Fixed)
+ treeHeader.setSectionResizeMode(self.C_STATUS, QHeaderView.Fixed)
+ treeHeader.resizeSection(self.C_EXPORT, iPx + cMg)
+ treeHeader.resizeSection(self.C_STATUS, iPx + cMg)
# Allow Move by Drag & Drop
self.setDragEnabled(True)
@@ -124,15 +120,6 @@ class GuiProjectTree(QTreeWidget):
# self.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
- # Get user's column width preferences for NAME and COUNT
- treeColWidth = self.mainConf.getTreeColWidths()
- if len(treeColWidth) <= 4:
- for colN, colW in enumerate(treeColWidth):
- self.setColumnWidth(colN, colW)
-
- # The last column should just auto-scale
- self.resizeColumnToContents(self.C_STATUS)
-
# Connect signals
self.itemDoubleClicked.connect(self._treeDoubleClick)
self.itemSelectionChanged.connect(self._treeSelectionChange)
@@ -369,16 +356,6 @@ class GuiProjectTree(QTreeWidget):
theList = self._scanChildren(theList, theItem, 0)
return theList
- def getColumnSizes(self):
- """Return the column widths for the tree columns.
- """
- retVals = [
- self.columnWidth(0),
- self.columnWidth(1),
- self.columnWidth(2),
- ]
- return retVals
-
def emptyTrash(self):
"""Permanently delete all documents in the Trash folder. This
function only asks for confirmation once, and calls the regular
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 354edbf4..7afd1675 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -1161,7 +1161,6 @@ class GuiMain(QMainWindow):
self.mainConf.setViewPanePos(self.splitView.sizes())
self.mainConf.setShowRefPanel(self.viewMeta.isVisible())
- self.mainConf.setTreeColWidths(self.treeView.getColumnSizes())
self.mainConf.setNovelColWidths(self.novelView.getColumnSizes())
if not self.mainConf.isFullScreen:
self.mainConf.setWinSize(self.width(), self.height())
From d07f5dc520162c6228de07f726f5041e47665d02 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Mon, 6 Jun 2022 15:50:46 +0200
Subject: [PATCH 03/35] Wrap project tree in an outer widget with a toolbar
---
novelwriter/dialogs/preferences.py | 2 +-
novelwriter/gui/__init__.py | 4 +-
novelwriter/gui/itemdetails.py | 2 +-
novelwriter/gui/outline.py | 3 +
novelwriter/gui/projtree.py | 185 ++++++++++++++++++----
novelwriter/guimain.py | 20 +--
tests/test_dialogs/test_dlg_docmerge.py | 28 ++--
tests/test_dialogs/test_dlg_docsplit.py | 20 +--
tests/test_dialogs/test_dlg_itemeditor.py | 10 +-
tests/test_gui/test_gui_docviewer.py | 6 +-
tests/test_gui/test_gui_guimain.py | 49 +++---
tests/test_gui/test_gui_mainmenu.py | 6 +-
tests/test_gui/test_gui_projtree.py | 20 +--
13 files changed, 238 insertions(+), 117 deletions(-)
diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py
index d38a4ab6..755b9198 100644
--- a/novelwriter/dialogs/preferences.py
+++ b/novelwriter/dialogs/preferences.py
@@ -107,7 +107,7 @@ class GuiPreferences(PagedDialog):
), nwAlert.INFO)
if refreshTree:
- self.theParent.treeView.buildTree()
+ self.theParent.treeView.populateTree()
self._saveWindowSize()
self.accept()
diff --git a/novelwriter/gui/__init__.py b/novelwriter/gui/__init__.py
index e3560a99..0ae23024 100644
--- a/novelwriter/gui/__init__.py
+++ b/novelwriter/gui/__init__.py
@@ -25,7 +25,7 @@ from novelwriter.gui.itemdetails import GuiItemDetails
from novelwriter.gui.mainmenu import GuiMainMenu
from novelwriter.gui.noveltree import GuiNovelTree
from novelwriter.gui.outline import GuiOutline
-from novelwriter.gui.projtree import GuiProjectTree
+from novelwriter.gui.projtree import GuiProjectWiew
from novelwriter.gui.statusbar import GuiMainStatus
from novelwriter.gui.theme import GuiTheme
from novelwriter.gui.viewsbar import GuiViewsBar
@@ -39,7 +39,7 @@ __all__ = [
"GuiMainStatus",
"GuiNovelTree",
"GuiOutline",
- "GuiProjectTree",
+ "GuiProjectWiew",
"GuiTheme",
"GuiViewsBar",
]
diff --git a/novelwriter/gui/itemdetails.py b/novelwriter/gui/itemdetails.py
index 643479a4..cf9e8017 100644
--- a/novelwriter/gui/itemdetails.py
+++ b/novelwriter/gui/itemdetails.py
@@ -296,7 +296,7 @@ class GuiItemDetails(QWidget):
return
@pyqtSlot(str, int, int, int)
- def doUpdateCounts(self, tHandle, cC, wC, pC):
+ def updateCounts(self, tHandle, cC, wC, pC):
"""Update the counts if the handle is the same as the one we're
already showing. Otherwise, do nothing.
"""
diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py
index 34cb35da..65bffdbd 100644
--- a/novelwriter/gui/outline.py
+++ b/novelwriter/gui/outline.py
@@ -62,6 +62,7 @@ class GuiOutline(QWidget):
self.mainConf = novelwriter.CONFIG
self.theParent = theParent
+ # Build GUI
self.outlineBar = GuiOutlineToolBar(self)
self.outlineView = GuiOutlineView(self)
self.outlineData = GuiOutlineDetails(self)
@@ -225,6 +226,8 @@ class GuiOutlineToolBar(QToolBar):
logger.debug("GuiOutlineToolBar initialisation complete")
+ return
+
##
# Methods
##
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index c6d077b8..7286f87f 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -6,6 +6,8 @@ GUI classes for the main window project tree
File History:
Created: 2018-09-29 [0.0.1] GuiProjectTree
Created: 2020-06-04 [0.7] GuiProjectTreeMenu
+Created: 2022-06-06 [1.7b1] GuiProjectWiew
+Created: 2022-06-06 [1.7b1] GuiProjectToolBar
This file is a part of novelWriter
Copyright 2018–2022, Veronica Berglyd Olsen
@@ -34,7 +36,8 @@ from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (
QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction, QFrame,
- QDialog, QHeaderView
+ QDialog, QHeaderView, QWidget, QVBoxLayout, QToolBar, QLabel, QToolButton,
+ QSizePolicy
)
from novelwriter.core import NWDoc
@@ -45,12 +48,11 @@ from novelwriter.dialogs.itemeditor import GuiItemEditor
logger = logging.getLogger(__name__)
-class GuiProjectTree(QTreeWidget):
-
- C_NAME = 0
- C_COUNT = 1
- C_EXPORT = 2
- C_STATUS = 3
+class GuiProjectWiew(QWidget):
+ """This is a wrapper class holding all the elements of the project
+ tree. The core object is the project tree itself. Most methods
+ available are mapped through to the project tree class.
+ """
# Signals triggered when the meta data values of items change
treeItemChanged = pyqtSignal(str)
@@ -63,14 +65,143 @@ class GuiProjectTree(QTreeWidget):
openDocumentRequest = pyqtSignal(str, Enum)
def __init__(self, theParent):
- QTreeWidget.__init__(self, theParent)
+ QWidget.__init__(self, theParent)
+
+ self.theParent = theParent
+
+ # Build GUI
+ self.projBar = GuiProjectToolBar(self)
+ self.projTree = GuiProjectTree(self)
+
+ # Assemble
+ self.outerBox = QVBoxLayout()
+ self.outerBox.addWidget(self.projBar)
+ self.outerBox.addWidget(self.projTree)
+ self.outerBox.setContentsMargins(0, 0, 0, 0)
+ self.outerBox.setSpacing(0)
+
+ self.setLayout(self.outerBox)
+
+ # Function Mappings
+ self.newTreeItem = self.projTree.newTreeItem
+ self.revealNewTreeItem = self.projTree.revealNewTreeItem
+ self.moveTreeItem = self.projTree.moveTreeItem
+ self.editTreeItem = self.projTree.editTreeItem
+ self.getTreeFromHandle = self.projTree.getTreeFromHandle
+ self.emptyTrash = self.projTree.emptyTrash
+ self.deleteItem = self.projTree.deleteItem
+ self.setTreeItemValues = self.projTree.setTreeItemValues
+ self.propagateCount = self.projTree.propagateCount
+ self.undoLastMove = self.projTree.undoLastMove
+ self.getSelectedHandle = self.projTree.getSelectedHandle
+ self.setSelectedHandle = self.projTree.setSelectedHandle
+ self.changedSince = self.projTree.changedSince
+
+ return
+
+ ##
+ # Methods
+ ##
+
+ def initSettings(self):
+ self.projTree.initSettings()
+ return
+
+ def clearProject(self):
+ self.projTree.clearTree()
+ return
+
+ def saveProjectTree(self):
+ self.projTree.saveTreeOrder()
+ return
+
+ def populateTree(self):
+ self.projTree.buildTree()
+ return
+
+ def treeFocus(self):
+ return self.projTree.hasFocus()
+
+ ##
+ # Public Solts
+ ##
+
+ @pyqtSlot(str, int, int, int)
+ def updateCounts(self, tHandle, cCount, wCount, pCount):
+ """Slot for updating the word count of a specific item.
+ """
+ self.projTree.propagateCount(tHandle, wCount, countChildren=True)
+ self.wordCountsChanged.emit()
+ return
+
+# END Class GuiProjectWiew
+
+
+class GuiProjectToolBar(QToolBar):
+
+ def __init__(self, theWidget):
+ QTreeWidget.__init__(self, theWidget)
+
+ logger.debug("Initialising GuiProjectToolBar ...")
+
+ self.mainConf = novelwriter.CONFIG
+ self.theParent = theWidget.theParent
+ self.theProject = theWidget.theParent.theProject
+ self.theTheme = theWidget.theParent.theTheme
+
+ iPx = self.theTheme.baseIconSize
+ mPx = self.mainConf.pxInt(12)
+
+ self.setMovable(False)
+ self.setIconSize(QSize(iPx, iPx))
+ self.setContentsMargins(0, 0, 0, 0)
+ self.setStyleSheet("QToolBar {border: 0px;}")
+
+ # Novel Selector
+ self.projLabel = QLabel(self.tr("Project"))
+ self.projLabel.setContentsMargins(0, 0, mPx, 0)
+ self.projLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+
+ # Itemss Menu
+ self.tbItems = QToolButton(self)
+ self.tbItems.setIcon(self.theTheme.getIcon("add"))
+ self.tbItems.setPopupMode(QToolButton.InstantPopup)
+
+ # Settings Menu
+ self.tbSettings = QToolButton(self)
+ self.tbSettings.setIcon(self.theTheme.getIcon("menu"))
+ self.tbSettings.setPopupMode(QToolButton.InstantPopup)
+
+ # Assemble
+ self.addWidget(self.projLabel)
+ self.addSeparator()
+ self.addWidget(self.tbItems)
+ self.addWidget(self.tbSettings)
+
+ logger.debug("GuiProjectToolBar initialisation complete")
+
+ return
+
+# END Class GuiProjectToolBar
+
+
+class GuiProjectTree(QTreeWidget):
+
+ C_NAME = 0
+ C_COUNT = 1
+ C_EXPORT = 2
+ C_STATUS = 3
+
+ def __init__(self, theWidget):
+ QTreeWidget.__init__(self, theWidget)
logger.debug("Initialising GuiProjectTree ...")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
- self.theProject = theParent.theProject
+ self.theWidget = theWidget
+ self.theParent = theWidget.theParent
+ self.theTheme = theWidget.theParent.theTheme
+ self.theProject = theWidget.theParent.theProject
# Internal Variables
self._treeMap = {}
@@ -125,13 +256,13 @@ class GuiProjectTree(QTreeWidget):
self.itemSelectionChanged.connect(self._treeSelectionChange)
# Set custom settings
- self.initTree()
+ self.initSettings()
logger.debug("GuiProjectTree initialisation complete")
return
- def initTree(self):
+ def initSettings(self):
"""Set or update tree widget settings.
"""
# Scroll bars
@@ -248,7 +379,7 @@ class GuiProjectTree(QTreeWidget):
# Get Word Counts
_, wC, _ = pIndex.getCounts(tHandle)
self.propagateCount(tHandle, wC)
- self.wordCountsChanged.emit()
+ self.theWidget.wordCountsChanged.emit()
return True
@@ -494,7 +625,7 @@ class GuiProjectTree(QTreeWidget):
self._deleteTreeItem(dHandle)
self._alertTreeChange(tHandle=tHandle, flush=autoFlush)
- self.wordCountsChanged.emit()
+ self.theWidget.wordCountsChanged.emit()
else:
# The item is not already in the trash folder, so we
@@ -690,18 +821,6 @@ class GuiProjectTree(QTreeWidget):
"""
return self._timeChanged > checkTime
- ##
- # Public Solts
- ##
-
- @pyqtSlot(str, int, int, int)
- def doUpdateCounts(self, tHandle, cCount, wCount, pCount):
- """Slot for updating the word count of a specific item.
- """
- self.propagateCount(tHandle, wCount, countChildren=True)
- self.wordCountsChanged.emit()
- return
-
##
# Private Slots
##
@@ -712,7 +831,7 @@ class GuiProjectTree(QTreeWidget):
"""
tHandle = self.getSelectedHandle()
if tHandle is not None:
- self.selectedItemChanged.emit(tHandle)
+ self.theWidget.selectedItemChanged.emit(tHandle)
return
@pyqtSlot("QTreeWidgetItem*", int)
@@ -729,7 +848,7 @@ class GuiProjectTree(QTreeWidget):
return
if tItem.itemType == nwItemType.FILE:
- self.openDocumentRequest.emit(tHandle, nwDocMode.EDIT)
+ self.theWidget.openDocumentRequest.emit(tHandle, nwDocMode.EDIT)
else:
trItem = self._getTreeItem(tHandle)
if trItem is not None:
@@ -781,7 +900,7 @@ class GuiProjectTree(QTreeWidget):
return
if tItem.itemType == nwItemType.FILE:
- self.openDocumentRequest.emit(tHandle, nwDocMode.VIEW)
+ self.theWidget.openDocumentRequest.emit(tHandle, nwDocMode.VIEW)
return
@@ -988,11 +1107,11 @@ class GuiProjectTree(QTreeWidget):
itemType = tItem.itemType
if itemType == nwItemType.ROOT:
- self.rootFolderChanged.emit(tHandle)
+ self.theWidget.rootFolderChanged.emit(tHandle)
elif itemType == nwItemType.FILE and tItem.isNovelLike():
- self.novelItemChanged.emit(tHandle)
+ self.theWidget.novelItemChanged.emit(tHandle)
- self.treeItemChanged.emit(tHandle)
+ self.theWidget.treeItemChanged.emit(tHandle)
return
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 7afd1675..d18d4d17 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -40,7 +40,7 @@ from PyQt5.QtWidgets import (
from novelwriter.gui import (
GuiDocEditor, GuiDocViewDetails, GuiDocViewer, GuiItemDetails, GuiMainMenu,
- GuiMainStatus, GuiNovelTree, GuiOutline, GuiProjectTree, GuiTheme,
+ GuiMainStatus, GuiNovelTree, GuiOutline, GuiProjectWiew, GuiTheme,
GuiViewsBar
)
from novelwriter.dialogs import (
@@ -105,7 +105,7 @@ class GuiMain(QMainWindow):
# Main GUI Elements
self.statusBar = GuiMainStatus(self)
- self.treeView = GuiProjectTree(self)
+ self.treeView = GuiProjectWiew(self)
self.novelView = GuiNovelTree(self)
self.docEditor = GuiDocEditor(self)
self.viewMeta = GuiDocViewDetails(self)
@@ -208,8 +208,8 @@ class GuiMain(QMainWindow):
self.docEditor.spellDictionaryChanged.connect(self.statusBar.setLanguage)
self.docEditor.docEditedStatusChanged.connect(self.statusBar.doUpdateDocumentStatus)
- self.docEditor.docCountsChanged.connect(self.treeMeta.doUpdateCounts)
- self.docEditor.docCountsChanged.connect(self.treeView.doUpdateCounts)
+ self.docEditor.docCountsChanged.connect(self.treeMeta.updateCounts)
+ self.docEditor.docCountsChanged.connect(self.treeView.updateCounts)
self.docEditor.loadDocumentTagRequest.connect(self._followTag)
self.docViewer.loadDocumentTagRequest.connect(self._followTag)
@@ -291,7 +291,7 @@ class GuiMain(QMainWindow):
"""Wrapper function to clear all sub-elements of the main GUI.
"""
# Project Area
- self.treeView.clearTree()
+ self.treeView.clearProject()
self.novelView.clearTree()
self.treeMeta.clearDetails()
@@ -541,7 +541,7 @@ class GuiMain(QMainWindow):
logger.error("No project open")
return False
- self.treeView.saveTreeOrder()
+ self.treeView.saveProjectTree()
if self.theProject.saveProject(autoSave=autoSave):
self.theProject.index.saveIndex()
@@ -789,7 +789,7 @@ class GuiMain(QMainWindow):
tHandle = None
tLine = None
- if self.treeView.hasFocus():
+ if self.treeView.treeFocus():
tHandle = self.treeView.getSelectedHandle()
elif self.novelView.hasFocus():
tHandle, tLine = self.novelView.getSelectedHandle()
@@ -824,7 +824,7 @@ class GuiMain(QMainWindow):
def rebuildTrees(self):
"""Rebuild the project tree.
"""
- self.treeView.buildTree()
+ self.treeView.populateTree()
self.novelView.refreshTree()
return
@@ -847,7 +847,7 @@ class GuiMain(QMainWindow):
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
tStart = time()
- self.treeView.saveTreeOrder()
+ self.treeView.saveProjectTree()
self.theProject.index.clearIndex()
for tItem in self.theProject.tree:
@@ -919,7 +919,7 @@ class GuiMain(QMainWindow):
self.saveDocument()
self.docEditor.initEditor()
self.docViewer.initViewer()
- self.treeView.initTree()
+ self.treeView.initSettings()
self.novelView.initTree()
self.projView.initOutline()
self._updateStatusWordCount()
diff --git a/tests/test_dialogs/test_dlg_docmerge.py b/tests/test_dialogs/test_dlg_docmerge.py
index a82c77bd..ce5c68d4 100644
--- a/tests/test_dialogs/test_dlg_docmerge.py
+++ b/tests/test_dialogs/test_dlg_docmerge.py
@@ -56,11 +56,11 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Add Project Content
monkeypatch.setattr(GuiItemEditor, "exec_", lambda *a: QDialog.Accepted)
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True)
- nwGUI.treeView.newTreeItem(nwItemType.FILE)
- nwGUI.treeView.newTreeItem(nwItemType.FILE)
- nwGUI.treeView.newTreeItem(nwItemType.FILE)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem(hChapterDir).setSelected(True)
+ nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE)
+ nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE)
+ nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE)
assert nwGUI.saveProject() is True
assert nwGUI.closeProject() is True
@@ -82,8 +82,8 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Open the Merge tool
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem(hChapterDir).setSelected(True)
monkeypatch.setattr(GuiDocMerge, "exec_", lambda *a: None)
nwGUI.mainMenu.aMergeDocs.activate(QAction.Trigger)
@@ -101,27 +101,27 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
assert nwMerge.listBox.count() == 0
# No item selected
- nwGUI.treeView.clearSelection()
+ nwGUI.treeView.projTree.clearSelection()
assert nwMerge._populateList() is False
assert nwMerge.listBox.count() == 0
# Non-existing item
with monkeypatch.context() as mp:
mp.setattr(NWTree, "__getitem__", lambda *a: None)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem(hChapterDir).setSelected(True)
assert nwMerge._populateList() is False
assert nwMerge.listBox.count() == 0
# Select a non-folder
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem(hChapterOne).setSelected(True)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem(hChapterOne).setSelected(True)
assert nwMerge._populateList() is False
assert nwMerge.listBox.count() == 0
# Select the chapter folder
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem(hChapterDir).setSelected(True)
assert nwMerge._populateList() is True
assert nwMerge.listBox.count() == 5
diff --git a/tests/test_dialogs/test_dlg_docsplit.py b/tests/test_dialogs/test_dlg_docsplit.py
index 90e3375d..0e3174c7 100644
--- a/tests/test_dialogs/test_dlg_docsplit.py
+++ b/tests/test_dialogs/test_dlg_docsplit.py
@@ -60,9 +60,9 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Add Project Content
monkeypatch.setattr(GuiItemEditor, "exec_", lambda *a: QDialog.Accepted)
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem(hNovelRoot).setSelected(True)
- nwGUI.treeView.newTreeItem(nwItemType.FILE)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem(hNovelRoot).setSelected(True)
+ nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE)
assert nwGUI.saveProject() is True
assert nwGUI.closeProject() is True
@@ -89,8 +89,8 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Open the Split tool
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem(hToSplit).setSelected(True)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem(hToSplit).setSelected(True)
monkeypatch.setattr(GuiDocSplit, "exec_", lambda *a: None)
nwGUI.mainMenu.aSplitDoc.activate(QAction.Trigger)
@@ -109,7 +109,7 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# No item selected
nwSplit.sourceItem = None
- nwGUI.treeView.clearSelection()
+ nwGUI.treeView.projTree.clearSelection()
assert nwSplit._populateList() is False
assert nwSplit.listBox.count() == 0
@@ -117,15 +117,15 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
with monkeypatch.context() as mp:
mp.setattr(NWTree, "__getitem__", lambda *a: None)
nwSplit.sourceItem = None
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem(hToSplit).setSelected(True)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem(hToSplit).setSelected(True)
assert nwSplit._populateList() is False
assert nwSplit.listBox.count() == 0
# Select a non-file
nwSplit.sourceItem = None
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem(hChapterDir).setSelected(True)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem(hChapterDir).setSelected(True)
assert nwSplit._populateList() is False
assert nwSplit.listBox.count() == 0
diff --git a/tests/test_dialogs/test_dlg_itemeditor.py b/tests/test_dialogs/test_dlg_itemeditor.py
index 95b1ee71..501d1e3b 100644
--- a/tests/test_dialogs/test_dlg_itemeditor.py
+++ b/tests/test_dialogs/test_dlg_itemeditor.py
@@ -25,10 +25,10 @@ from tools import getGuiItem, buildTestProject
from PyQt5.QtWidgets import QAction, QDialog, QMessageBox
-from novelwriter.gui import GuiProjectTree
from novelwriter.enum import nwItemLayout, nwItemType
from novelwriter.dialogs import GuiItemEditor
from novelwriter.core.tree import NWTree
+from novelwriter.gui.projtree import GuiProjectTree
statusKeys = ["s000000", "s000001", "s000002", "s000003"]
importKeys = ["i000004", "i000005", "i000006", "i000007"]
@@ -52,7 +52,7 @@ def testDlgItemEditor_Dialog(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
tHandle = "000000000000f"
# No Selection
- nwGUI.treeView.clearSelection()
+ nwGUI.treeView.projTree.clearSelection()
assert nwGUI.editItem() is False
# Force opening from editor
@@ -163,9 +163,9 @@ def testDlgItemEditor_Note(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
assert nwGUI.theProject.importItems.name(importKeys[1]) == "Minor"
# Create Note
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem("000000000000a").setSelected(True)
- nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem("000000000000a").setSelected(True)
+ nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None)
# Open Note
assert nwGUI.openDocument("0000000000010")
diff --git a/tests/test_gui/test_gui_docviewer.py b/tests/test_gui/test_gui_docviewer.py
index 1fa6b2c7..d1d8797a 100644
--- a/tests/test_gui/test_gui_docviewer.py
+++ b/tests/test_gui/test_gui_docviewer.py
@@ -54,9 +54,9 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
nwGUI.treeView.setSelectedHandle("88243afbe5ed8")
# Middle-click the selected item
- theItem = nwGUI.treeView._getTreeItem("88243afbe5ed8")
- theRect = nwGUI.treeView.visualItemRect(theItem)
- qtbot.mouseClick(nwGUI.treeView.viewport(), Qt.MidButton, pos=theRect.center())
+ theItem = nwGUI.treeView.projTree._getTreeItem("88243afbe5ed8")
+ theRect = nwGUI.treeView.projTree.visualItemRect(theItem)
+ qtbot.mouseClick(nwGUI.treeView.projTree.viewport(), Qt.MidButton, pos=theRect.center())
assert nwGUI.docViewer.docHandle() == "88243afbe5ed8"
# Reload the text
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index 5f49d51d..78c2af66 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -28,11 +28,10 @@ from tools import cmpFiles, buildTestProject, XML_IGNORE, writeFile
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMessageBox, QDialog
-from novelwriter.gui import (
- GuiDocEditor, GuiProjectTree, GuiNovelTree, GuiOutline
-)
+from novelwriter.gui import GuiDocEditor, GuiNovelTree, GuiOutline
from novelwriter.enum import nwItemType, nwWidget
from novelwriter.tools import GuiProjectWizard
+from novelwriter.gui.projtree import GuiProjectTree
from novelwriter.dialogs.itemeditor import GuiItemEditor
keyDelay = 2
@@ -126,7 +125,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
with monkeypatch.context() as mp:
mp.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
assert nwGUI.docEditor.docHandle() is None
- nwGUI.treeView._getTreeItem(sHandle).setSelected(True)
+ nwGUI.treeView.projTree._getTreeItem(sHandle).setSelected(True)
nwGUI._keyPressReturn()
assert nwGUI.docEditor.docHandle() == sHandle
assert nwGUI.closeDocument() is True
@@ -220,14 +219,14 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
assert nwGUI.theProject.spellCheck is False
# Check that tree items have been created
- assert nwGUI.treeView._getTreeItem("0000000000008") is not None
- assert nwGUI.treeView._getTreeItem("0000000000009") is not None
- assert nwGUI.treeView._getTreeItem("000000000000a") is not None
- assert nwGUI.treeView._getTreeItem("000000000000b") is not None
- assert nwGUI.treeView._getTreeItem("000000000000c") is not None
- assert nwGUI.treeView._getTreeItem("000000000000d") is not None
- assert nwGUI.treeView._getTreeItem("000000000000e") is not None
- assert nwGUI.treeView._getTreeItem("000000000000f") is not None
+ assert nwGUI.treeView.projTree._getTreeItem("0000000000008") is not None
+ assert nwGUI.treeView.projTree._getTreeItem("0000000000009") is not None
+ assert nwGUI.treeView.projTree._getTreeItem("000000000000a") is not None
+ assert nwGUI.treeView.projTree._getTreeItem("000000000000b") is not None
+ assert nwGUI.treeView.projTree._getTreeItem("000000000000c") is not None
+ assert nwGUI.treeView.projTree._getTreeItem("000000000000d") is not None
+ assert nwGUI.treeView.projTree._getTreeItem("000000000000e") is not None
+ assert nwGUI.treeView.projTree._getTreeItem("000000000000f") is not None
nwGUI.mainMenu.aSpellCheck.setChecked(True)
assert nwGUI.mainMenu._toggleSpellCheck()
@@ -240,9 +239,9 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
# Add a Character File
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem("000000000000a").setSelected(True)
- nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem("000000000000a").setSelected(True)
+ nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None)
assert nwGUI.openSelectedItem()
# Type something into the document
@@ -262,9 +261,9 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
# Add a Plot File
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem("0000000000009").setSelected(True)
- nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem("0000000000009").setSelected(True)
+ nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None)
assert nwGUI.openSelectedItem()
# Type something into the document
@@ -284,9 +283,9 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
# Add a World File
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem("000000000000b").setSelected(True)
- nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem("000000000000b").setSelected(True)
+ nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None)
assert nwGUI.openSelectedItem()
# Add Some Text
@@ -315,10 +314,10 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
# Select the 'New Scene' file
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.clearSelection()
- nwGUI.treeView._getTreeItem("0000000000008").setExpanded(True)
- nwGUI.treeView._getTreeItem("000000000000d").setExpanded(True)
- nwGUI.treeView._getTreeItem("000000000000f").setSelected(True)
+ nwGUI.treeView.projTree.clearSelection()
+ nwGUI.treeView.projTree._getTreeItem("0000000000008").setExpanded(True)
+ nwGUI.treeView.projTree._getTreeItem("000000000000d").setExpanded(True)
+ nwGUI.treeView.projTree._getTreeItem("000000000000f").setSelected(True)
assert nwGUI.openSelectedItem()
# Type something into the document
diff --git a/tests/test_gui/test_gui_mainmenu.py b/tests/test_gui/test_gui_mainmenu.py
index 801abd68..274746d7 100644
--- a/tests/test_gui/test_gui_mainmenu.py
+++ b/tests/test_gui/test_gui_mainmenu.py
@@ -467,7 +467,7 @@ def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncDir, fncProj, mockRnd):
buildTestProject(nwGUI, fncProj)
- assert nwGUI.treeView._getTreeItem("000000000000f") is not None
+ assert nwGUI.treeView.projTree._getTreeItem("000000000000f") is not None
assert nwGUI.openDocument("000000000000f") is True
nwGUI.docEditor.clear()
@@ -476,10 +476,10 @@ def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncDir, fncProj, mockRnd):
assert nwGUI.docEditor.getText() == "hello world"
nwGUI.docEditor.clear()
- assert not nwGUI.docEditor.insertText(nwDocInsert.NO_INSERT)
+ assert nwGUI.docEditor.insertText(nwDocInsert.NO_INSERT) is False
assert nwGUI.docEditor.isEmpty()
- assert not nwGUI.docEditor.insertText(None)
+ assert nwGUI.docEditor.insertText(None) is False
assert nwGUI.docEditor.isEmpty()
# qtbot.stopForInteraction()
diff --git a/tests/test_gui/test_gui_projtree.py b/tests/test_gui/test_gui_projtree.py
index 258ad150..7b66f305 100644
--- a/tests/test_gui/test_gui_projtree.py
+++ b/tests/test_gui/test_gui_projtree.py
@@ -52,7 +52,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
buildTestProject(nwGUI, prjDir)
# No itemType set
- nwTree.clearSelection()
+ nwTree.projTree.clearSelection()
assert nwTree.newTreeItem(None) is False
# Root Items
@@ -69,7 +69,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
# =================
# No location selected for new item
- nwTree.clearSelection()
+ nwTree.projTree.clearSelection()
caplog.clear()
assert nwTree.newTreeItem(nwItemType.FILE) is False
assert nwTree.newTreeItem(nwItemType.FOLDER) is False
@@ -116,7 +116,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
nwGUI.theProject.tree["0000000000013"].setParent("0000000000011")
# Get the trash folder
- nwTree._addTrashRoot()
+ nwTree.projTree._addTrashRoot()
trashHandle = nwGUI.theProject.trashFolder()
nwTree.setSelectedHandle(trashHandle)
assert nwTree.newTreeItem(nwItemType.FILE) is False
@@ -182,7 +182,7 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
# Move with no selections
- nwTree.clearSelection()
+ nwTree.projTree.clearSelection()
assert nwTree.moveTreeItem(1) is False
# Move second item up twice (should give same result)
@@ -304,13 +304,13 @@ def testGuiProjTree_DeleteItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
# No selection made
- nwTree.clearSelection()
+ nwTree.projTree.clearSelection()
caplog.clear()
assert nwTree.deleteItem() is False
assert "no item to delete" in caplog.text
# Not a valid handle
- nwTree.clearSelection()
+ nwTree.projTree.clearSelection()
caplog.clear()
assert nwTree.deleteItem("0000000000000") is False
assert "Could not find tree item" in caplog.text
@@ -326,10 +326,10 @@ def testGuiProjTree_DeleteItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
# ===========
# Block adding trash folder
- funcPointer = nwTree._addTrashRoot
- nwTree._addTrashRoot = lambda *a: None
+ funcPointer = nwTree.projTree._addTrashRoot
+ nwTree.projTree._addTrashRoot = lambda *a: None
assert nwTree.deleteItem("0000000000012") is False
- nwTree._addTrashRoot = funcPointer
+ nwTree.projTree._addTrashRoot = funcPointer
# Delete last two documents, which also adds the trash folder
assert nwTree.deleteItem("0000000000012") is True
@@ -441,7 +441,7 @@ def testGuiProjTree_DeleteItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
assert os.path.isfile(os.path.join(fncDir, "project", "content", "000000000000e.nwd"))
# Delete proper
- assert nwTree._deleteTreeItem("000000000000e") is True
+ assert nwTree.projTree._deleteTreeItem("000000000000e") is True
assert not os.path.isfile(os.path.join(fncDir, "project", "content", "000000000000e.nwd"))
# Clean up
From 12a7ec7fe388030c18884e4064edb1b9b14d267c Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Mon, 6 Jun 2022 22:02:44 +0200
Subject: [PATCH 04/35] Allow the project class to create new files
---
novelwriter/core/project.py | 32 ++++++++++++++-
tests/test_core/test_core_project.py | 58 +++++++++++++++++++++++-----
2 files changed, 79 insertions(+), 11 deletions(-)
diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py
index 460fb91f..cce4603d 100644
--- a/novelwriter/core/project.py
+++ b/novelwriter/core/project.py
@@ -45,7 +45,7 @@ from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout, nwAlert
from novelwriter.error import logException
from novelwriter.common import (
checkString, checkBool, checkInt, isHandle, formatTimeStamp,
- makeFileNameSafe, hexToInt, simplified
+ makeFileNameSafe, hexToInt, minmax, simplified
)
from novelwriter.constants import trConst, nwFiles, nwLabels
@@ -154,6 +154,8 @@ class NWProject():
def newFolder(self, label, pHandle):
"""Add a new folder with a given label and parent item.
"""
+ if pHandle not in self._projTree:
+ return None
newItem = NWItem(self)
newItem.setName(label)
newItem.setType(nwItemType.FOLDER)
@@ -164,6 +166,8 @@ class NWProject():
def newFile(self, label, pHandle):
"""Add a new file with a given label and parent item.
"""
+ if pHandle not in self._projTree:
+ return None
newItem = NWItem(self)
newItem.setName(label)
newItem.setType(nwItemType.FILE)
@@ -171,6 +175,32 @@ class NWProject():
self._projTree.updateItemData(newItem.itemHandle)
return newItem.itemHandle
+ def writeNewFile(self, tHandle, hLevel, isDocument):
+ """Write content to a new document after it is created. This
+ will not run if the file exists and is not empty.
+ """
+ tItem = self._projTree[tHandle]
+ if tItem is None:
+ return False
+ if tItem.itemType != nwItemType.FILE:
+ return False
+
+ newDoc = NWDoc(self, tHandle)
+ if newDoc.readDocument().strip():
+ return False
+
+ hshText = "#"*minmax(hLevel, 1, 4)
+ newText = f"{hshText} {tItem.itemName}\n\n"
+ if tItem.isNovelLike() and isDocument:
+ tItem.setLayout(nwItemLayout.DOCUMENT)
+ else:
+ tItem.setLayout(nwItemLayout.NOTE)
+
+ newDoc.writeDocument(newText)
+ self._projIndex.scanText(tHandle, newText)
+
+ return True
+
def trashFolder(self):
"""Add the special trash root folder to the project.
"""
diff --git a/tests/test_core/test_core_project.py b/tests/test_core/test_core_project.py
index 005277c6..9454b0fc 100644
--- a/tests/test_core/test_core_project.py
+++ b/tests/test_core/test_core_project.py
@@ -29,10 +29,14 @@ from lxml import etree
from tools import cmpFiles, writeFile, readFile, buildTestProject, XML_IGNORE
from mock import causeOSError
-from novelwriter.core.project import NWProject
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
from novelwriter.common import formatTimeStamp
from novelwriter.constants import nwFiles
+from novelwriter.core.tree import NWTree
+from novelwriter.core.index import NWIndex
+from novelwriter.core.project import NWProject
+from novelwriter.core.options import OptionState
+from novelwriter.core.document import NWDoc
@pytest.mark.core
@@ -280,12 +284,12 @@ def testCoreProject_NewRoot(fncDir, outDir, refDir, mockGUI, mockRnd):
@pytest.mark.core
-def testCoreProject_NewFile(fncDir, outDir, refDir, mockGUI, mockRnd):
+def testCoreProject_NewFileFolder(fncDir, outDir, refDir, mockGUI, mockRnd):
"""Check that new files can be added to the project.
"""
projFile = os.path.join(fncDir, "nwProject.nwx")
- testFile = os.path.join(outDir, "coreProject_NewFile_nwProject.nwx")
- compFile = os.path.join(refDir, "coreProject_NewFile_nwProject.nwx")
+ testFile = os.path.join(outDir, "coreProject_NewFileFolder_nwProject.nwx")
+ compFile = os.path.join(refDir, "coreProject_NewFileFolder_nwProject.nwx")
theProject = NWProject(mockGUI)
buildTestProject(theProject, fncDir)
@@ -295,9 +299,33 @@ def testCoreProject_NewFile(fncDir, outDir, refDir, mockGUI, mockRnd):
assert theProject.closeProject() is True
assert theProject.openProject(projFile) is True
- assert isinstance(theProject.newFile("Hello", "31489056e0916"), str)
- assert isinstance(theProject.newFile("Jane", "71ee45a3c0db9"), str)
- assert theProject.projChanged
+ # Invalid call
+ assert theProject.newFolder("New Folder", "1234567890abc") is None
+ assert theProject.newFile("New File", "1234567890abc") is None
+
+ # Add files properly
+ assert theProject.newFolder("Stuff", "0000000000015") == "0000000000028"
+ assert theProject.newFile("Hello", "0000000000015") == "0000000000029"
+ assert theProject.newFile("Jane", "0000000000012") == "000000000002a"
+
+ assert "0000000000028" in theProject.tree
+ assert "0000000000029" in theProject.tree
+ assert "000000000002a" in theProject.tree
+
+ # Write to file, failed
+ assert theProject.writeNewFile("blabla", 1, True) is False # Not a handle
+ assert theProject.writeNewFile("0000000000028", 1, True) is False # Not a file
+ assert theProject.writeNewFile("0000000000014", 1, True) is False # Already has content
+
+ # Write to file, success
+ assert theProject.writeNewFile("0000000000029", 2, True) is True
+ assert NWDoc(theProject, "0000000000029").readDocument() == "## Hello\n\n"
+
+ assert theProject.writeNewFile("000000000002a", 1, False) is True
+ assert NWDoc(theProject, "000000000002a").readDocument() == "# Jane\n\n"
+
+ # Save, close and check
+ assert theProject.projChanged is True
assert theProject.saveProject() is True
assert theProject.closeProject() is True
@@ -305,7 +333,7 @@ def testCoreProject_NewFile(fncDir, outDir, refDir, mockGUI, mockRnd):
assert cmpFiles(testFile, compFile, ignoreStart=XML_IGNORE)
assert theProject.projChanged is False
-# END Test testCoreProject_NewFile
+# END Test testCoreProject_NewFileFolder
@pytest.mark.core
@@ -613,6 +641,11 @@ def testCoreProject_AccessItems(nwMinimal, mockGUI):
theProject = NWProject(mockGUI)
theProject.openProject(nwMinimal)
+ # Storage Objects
+ assert isinstance(theProject.index, NWIndex)
+ assert isinstance(theProject.tree, NWTree)
+ assert isinstance(theProject.options, OptionState)
+
# Move Novel ROOT to after its files
oldOrder = [
"a508bb932959c", # ROOT: Novel
@@ -722,7 +755,7 @@ def testCoreProject_StatusImport(mockGUI, fncDir, mockRnd):
# Change Importance
# =================
- fHandle = theProject.newFile("Jane Doe", "8b9d2e465e150")
+ fHandle = theProject.newFile("Jane Doe", "0000000000012")
theProject.tree[fHandle].setImport("Main")
assert theProject.tree[fHandle].itemImport == importKeys[3]
@@ -894,6 +927,10 @@ def testCoreProject_Methods(monkeypatch, mockGUI, tmpDir, fncDir, mockRnd):
assert theProject.setProjectLang("en_GB") is True
assert theProject.projLang == "en_GB"
+ # Language Lookup
+ assert theProject.localLookup(1) == "One"
+ assert theProject.localLookup(10) == "Ten"
+
# Automatic outline update
theProject.projChanged = False
assert theProject.setAutoOutline(True)
@@ -1007,7 +1044,8 @@ def testCoreProject_OrphanedFiles(mockGUI, nwLipsum):
# Add a file with non-existent parent
# This file will be renoved from the project on open
- assert theProject.newFile("Oops", "0000000000000")
+ oHandle = theProject.newFile("Oops", "b3643d0f92e32")
+ theProject.tree[oHandle].setParent("1234567890abc")
# Save and close
assert theProject.saveProject() is True
From 46bb8e5bccf2704f3db3055d609a81b2b1f4827e Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Mon, 6 Jun 2022 22:03:42 +0200
Subject: [PATCH 05/35] Populate the add button menu in the project widget
---
novelwriter/core/index.py | 5 -
novelwriter/gui/projtree.py | 158 +++++++++++++-----
sample/nwProject.nwx | 10 +-
...> coreProject_NewFileFolder_nwProject.nwx} | 30 ++--
tests/test_core/test_core_index.py | 3 -
tests/test_dialogs/test_dlg_docmerge.py | 3 +-
tests/test_dialogs/test_dlg_docsplit.py | 3 +-
tests/test_dialogs/test_dlg_itemeditor.py | 5 +-
tests/test_gui/test_gui_guimain.py | 9 +-
tests/test_gui/test_gui_projtree.py | 40 +++--
10 files changed, 180 insertions(+), 86 deletions(-)
rename tests/reference/{coreProject_NewFile_nwProject.nwx => coreProject_NewFileFolder_nwProject.nwx} (76%)
diff --git a/novelwriter/core/index.py b/novelwriter/core/index.py
index f86de8c2..ee9ea089 100644
--- a/novelwriter/core/index.py
+++ b/novelwriter/core/index.py
@@ -502,11 +502,6 @@ class NWIndex:
"""
return self._itemIndex.mainItemHeader(tHandle)
- def getHandleHeaderIntLevel(self, tHandle):
- """Get the integer header level of the first header of a handle.
- """
- return H_LEVEL.get(self._itemIndex.mainItemHeader(tHandle), 0)
-
def getTableOfContents(self, maxDepth, skipExcl=True):
"""Generate a table of contents up to a maximum depth.
"""
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index 7286f87f..2e58a61d 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -37,13 +37,13 @@ from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (
QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction, QFrame,
QDialog, QHeaderView, QWidget, QVBoxLayout, QToolBar, QLabel, QToolButton,
- QSizePolicy
+ QSizePolicy, QInputDialog
)
from novelwriter.core import NWDoc
from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert
-from novelwriter.common import minmax
from novelwriter.dialogs.itemeditor import GuiItemEditor
+from novelwriter.constants import trConst, nwLabels
logger = logging.getLogger(__name__)
@@ -82,6 +82,8 @@ class GuiProjectWiew(QWidget):
self.setLayout(self.outerBox)
+ # Connect Signals
+
# Function Mappings
self.newTreeItem = self.projTree.newTreeItem
self.revealNewTreeItem = self.projTree.revealNewTreeItem
@@ -139,12 +141,19 @@ class GuiProjectWiew(QWidget):
class GuiProjectToolBar(QToolBar):
+ ADD_PLAIN = 0
+ ADD_CHAP = 1
+ ADD_SCENE = 2
+ ADD_NOTE = 3
+ ADD_FOLDER = 4
+
def __init__(self, theWidget):
QTreeWidget.__init__(self, theWidget)
logger.debug("Initialising GuiProjectToolBar ...")
self.mainConf = novelwriter.CONFIG
+ self.theWidget = theWidget
self.theParent = theWidget.theParent
self.theProject = theWidget.theParent.theProject
self.theTheme = theWidget.theParent.theTheme
@@ -157,14 +166,49 @@ class GuiProjectToolBar(QToolBar):
self.setContentsMargins(0, 0, 0, 0)
self.setStyleSheet("QToolBar {border: 0px;}")
- # Novel Selector
+ # Tree Label
self.projLabel = QLabel(self.tr("Project"))
self.projLabel.setContentsMargins(0, 0, mPx, 0)
self.projLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
- # Itemss Menu
+ # Items Menu
+ self.mItems = QMenu()
+
+ self.aAddEmpty = self.mItems.addAction(self.tr("Plain Document"))
+ self.aAddEmpty.setIcon(self.theTheme.getIcon("proj_document"))
+ self.aAddEmpty.triggered.connect(lambda: self._forwardNewItem(self.ADD_PLAIN))
+
+ self.aAddChap = self.mItems.addAction(self.tr("Chapter Document"))
+ self.aAddChap.setIcon(self.theTheme.getIcon("proj_chapter"))
+ self.aAddChap.triggered.connect(lambda: self._forwardNewItem(self.ADD_CHAP))
+
+ self.aAddScene = self.mItems.addAction(self.tr("Scene Document"))
+ self.aAddScene.setIcon(self.theTheme.getIcon("proj_scene"))
+ self.aAddScene.triggered.connect(lambda: self._forwardNewItem(self.ADD_SCENE))
+
+ self.aAddNote = self.mItems.addAction(self.tr("Project Note"))
+ self.aAddNote.setIcon(self.theTheme.getIcon("proj_note"))
+ self.aAddNote.triggered.connect(lambda: self._forwardNewItem(self.ADD_NOTE))
+
+ self.aAddFolder = self.mItems.addAction(self.tr("Folder"))
+ self.aAddFolder.setIcon(self.theTheme.getIcon("proj_folder"))
+ self.aAddFolder.triggered.connect(lambda: self._forwardNewItem(self.ADD_FOLDER))
+
+ self.mAddRoot = self.mItems.addMenu(self.tr("Root Folder"))
+ self._addRootFolderEntry(nwItemClass.NOVEL)
+ self._addRootFolderEntry(nwItemClass.ARCHIVE)
+ self.mAddRoot.addSeparator()
+ self._addRootFolderEntry(nwItemClass.PLOT)
+ self._addRootFolderEntry(nwItemClass.CHARACTER)
+ self._addRootFolderEntry(nwItemClass.WORLD)
+ self._addRootFolderEntry(nwItemClass.ARCHIVE)
+ self._addRootFolderEntry(nwItemClass.OBJECT)
+ self._addRootFolderEntry(nwItemClass.ENTITY)
+ self._addRootFolderEntry(nwItemClass.CUSTOM)
+
self.tbItems = QToolButton(self)
self.tbItems.setIcon(self.theTheme.getIcon("add"))
+ self.tbItems.setMenu(self.mItems)
self.tbItems.setPopupMode(QToolButton.InstantPopup)
# Settings Menu
@@ -182,6 +226,45 @@ class GuiProjectToolBar(QToolBar):
return
+ ##
+ # Private Slots
+ ##
+
+ @pyqtSlot(Enum)
+ def _forwardNewRootFolder(self, itemClass):
+ """Forward the request for a new root folder to the tree.
+ """
+ self.theWidget.projTree.newTreeItem(nwItemType.ROOT, itemClass)
+ return
+
+ @pyqtSlot(int)
+ def _forwardNewItem(self, type):
+ """Forward the request for a new item of a given type.
+ """
+ if type == self.ADD_PLAIN:
+ self.theWidget.projTree.newTreeItem(nwItemType.FILE, hLevel=0, isNote=False)
+ elif type == self.ADD_CHAP:
+ self.theWidget.projTree.newTreeItem(nwItemType.FILE, hLevel=2, isNote=False)
+ elif type == self.ADD_SCENE:
+ self.theWidget.projTree.newTreeItem(nwItemType.FILE, hLevel=3, isNote=False)
+ elif type == self.ADD_NOTE:
+ self.theWidget.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True)
+ elif type == self.ADD_FOLDER:
+ self.theWidget.projTree.newTreeItem(nwItemType.FOLDER)
+ return
+
+ ##
+ # Internal Functions
+ ##
+
+ def _addRootFolderEntry(self, itemClass):
+ """Add a menu entry for a root folder of a given class.
+ """
+ aNew = self.mAddRoot.addAction(trConst(nwLabels.CLASS_NAME[itemClass]))
+ aNew.setIcon(self.theTheme.getIcon(nwLabels.CLASS_ICON[itemClass]))
+ aNew.triggered.connect(lambda: self._forwardNewRootFolder(itemClass))
+ self.mAddRoot.addAction(aNew)
+
# END Class GuiProjectToolBar
@@ -291,7 +374,7 @@ class GuiProjectTree(QTreeWidget):
self._timeChanged = 0
return
- def newTreeItem(self, itemType, itemClass=None):
+ def newTreeItem(self, itemType, itemClass=None, hLevel=1, isNote=False):
"""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
@@ -334,52 +417,49 @@ class GuiProjectTree(QTreeWidget):
), nwAlert.ERROR)
return False
+ # Ask for label
+ if itemType == nwItemType.FILE:
+ if isNote:
+ newLabel = self.tr("New Note")
+ elif hLevel == 2:
+ newLabel = self.tr("New Chapter")
+ elif hLevel == 3:
+ newLabel = self.tr("New Scene")
+ else:
+ newLabel = self.tr("New Document")
+ else:
+ newLabel = self.tr("New Folder")
+
+ newLabel, dlgOk = QInputDialog.getText(self, "", self.tr("Label:"), text=newLabel)
+ if not dlgOk:
+ logger.info("New item creation cancelled by user")
+ return False
+
# Add the file or folder
if itemType == nwItemType.FILE:
- if pItem.isNovelLike():
- tHandle = self.theProject.newFile(self.tr("New Document"), sHandle)
- else:
- tHandle = self.theProject.newFile(self.tr("New Note"), sHandle)
- elif itemType == nwItemType.FOLDER:
- tHandle = self.theProject.newFolder(self.tr("New Folder"), sHandle)
+ tHandle = self.theProject.newFile(newLabel, sHandle)
+ else:
+ tHandle = self.theProject.newFolder(newLabel, sHandle)
else:
logger.error("Failed to add new item")
return False
- # If there is no handle set, return here. This is a bug
+ # If there is no handle set, return here. This is a bug.
if tHandle is None: # pragma: no cover
+ logger.error("Internal error")
return True
- # Add the new item to the tree and open the editor dialog
- self.revealNewTreeItem(tHandle, nHandle)
- self.editTreeItem(tHandle)
-
# Handle new file creation
- nwItem = self.theProject.tree[tHandle]
- if nwItem.itemType != nwItemType.FILE:
- return True
+ if itemType == nwItemType.FILE and hLevel > 0:
+ if self.theProject.writeNewFile(tHandle, hLevel, not isNote):
+ # If successful, update word count
+ wC = self.theProject.index.getCounts(tHandle)[1]
+ self.propagateCount(tHandle, wC)
+ self.theWidget.wordCountsChanged.emit()
- # This is a new file, so let's add some content
- newDoc = NWDoc(self.theProject, tHandle)
- if not newDoc.readDocument():
- if nwItem.itemLayout == nwItemLayout.DOCUMENT:
- iLvl = self.theProject.index.getHandleHeaderIntLevel(sHandle)
- hLvl = "#"*minmax(iLvl + 1, 2, 4)
- newText = f"{hLvl} {nwItem.itemName}\n\n"
- else:
- newText = f"# {nwItem.itemName}\n\n"
-
- pIndex = self.theProject.index
-
- # Save the text and index it
- newDoc.writeDocument(newText)
- pIndex.scanText(tHandle, newText)
-
- # Get Word Counts
- _, wC, _ = pIndex.getCounts(tHandle)
- self.propagateCount(tHandle, wC)
- self.theWidget.wordCountsChanged.emit()
+ # Add the new item to the project tree
+ self.revealNewTreeItem(tHandle, nHandle)
return True
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index 9f3a6587..4dd6396a 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,13 +1,13 @@
-
+
Sample Project
Sample Project
Jane Smith
Jay Doh
- 1334
- 225
- 67746
+ 1342
+ 227
+ 68090
False
@@ -15,7 +15,7 @@
True
None
True
- a520879ca0b45
+ 636b6aa9b697b
636b6aa9b697b
1363
954
diff --git a/tests/reference/coreProject_NewFile_nwProject.nwx b/tests/reference/coreProject_NewFileFolder_nwProject.nwx
similarity index 76%
rename from tests/reference/coreProject_NewFile_nwProject.nwx
rename to tests/reference/coreProject_NewFileFolder_nwProject.nwx
index 19a2f4bf..4235e9bb 100644
--- a/tests/reference/coreProject_NewFile_nwProject.nwx
+++ b/tests/reference/coreProject_NewFileFolder_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
New Novel
@@ -16,9 +16,9 @@
True
None
None
- 0
- 0
- 0
+ 2
+ 1
+ 1
%title%
@@ -28,19 +28,19 @@
- New
+ New
Note
Draft
Finished
- New
+ New
Minor
Major
Main
-
+
-
Novel
@@ -73,13 +73,17 @@
New Scene
- -
-
- Hello
+
-
+
+ Stuff
- -
-
- Jane
+
-
+
+ Hello
+
+ -
+
+ Jane
diff --git a/tests/test_core/test_core_index.py b/tests/test_core/test_core_index.py
index 3d40a9df..8f126e56 100644
--- a/tests/test_core/test_core_index.py
+++ b/tests/test_core/test_core_index.py
@@ -232,9 +232,6 @@ def testCoreIndex_CheckThese(mockGUI, fncDir, mockRnd):
assert theIndex.getHandleHeaderLevel(cHandle) == "H1"
assert theIndex.getHandleHeaderLevel(nHandle) == "H1"
- assert theIndex.getHandleHeaderIntLevel(cHandle) == 1
- assert theIndex.getHandleHeaderIntLevel(nHandle) == 1
- assert theIndex.getHandleHeaderIntLevel("stuff") == 0
# Zero Items
assert theIndex.checkThese([], cItem) == []
diff --git a/tests/test_dialogs/test_dlg_docmerge.py b/tests/test_dialogs/test_dlg_docmerge.py
index ce5c68d4..f796f864 100644
--- a/tests/test_dialogs/test_dlg_docmerge.py
+++ b/tests/test_dialogs/test_dlg_docmerge.py
@@ -25,7 +25,7 @@ import pytest
from mock import causeOSError
from tools import getGuiItem, readFile, writeFile, buildTestProject
-from PyQt5.QtWidgets import QAction, QMessageBox, QDialog
+from PyQt5.QtWidgets import QAction, QMessageBox, QDialog, QInputDialog
from novelwriter.enum import nwItemType, nwWidget
from novelwriter.dialogs import GuiDocMerge, GuiItemEditor
@@ -39,6 +39,7 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Block message box
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Ok)
+ monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
# Create a new project
buildTestProject(nwGUI, fncProj)
diff --git a/tests/test_dialogs/test_dlg_docsplit.py b/tests/test_dialogs/test_dlg_docsplit.py
index 0e3174c7..080be8ab 100644
--- a/tests/test_dialogs/test_dlg_docsplit.py
+++ b/tests/test_dialogs/test_dlg_docsplit.py
@@ -25,7 +25,7 @@ import pytest
from mock import causeOSError
from tools import getGuiItem, readFile, writeFile, buildTestProject
-from PyQt5.QtWidgets import QAction, QMessageBox, QDialog
+from PyQt5.QtWidgets import QAction, QMessageBox, QDialog, QInputDialog
from novelwriter.enum import nwItemType, nwWidget
from novelwriter.dialogs import GuiDocSplit, GuiItemEditor
@@ -40,6 +40,7 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Block message box
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Ok)
+ monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
# Create a new project
buildTestProject(nwGUI, fncProj)
diff --git a/tests/test_dialogs/test_dlg_itemeditor.py b/tests/test_dialogs/test_dlg_itemeditor.py
index 501d1e3b..53426df7 100644
--- a/tests/test_dialogs/test_dlg_itemeditor.py
+++ b/tests/test_dialogs/test_dlg_itemeditor.py
@@ -23,7 +23,7 @@ import pytest
from tools import getGuiItem, buildTestProject
-from PyQt5.QtWidgets import QAction, QDialog, QMessageBox
+from PyQt5.QtWidgets import QAction, QDialog, QMessageBox, QInputDialog
from novelwriter.enum import nwItemLayout, nwItemType
from novelwriter.dialogs import GuiItemEditor
@@ -154,6 +154,7 @@ def testDlgItemEditor_Note(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Block message box
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
+ monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
# Create Project and Open Document
buildTestProject(nwGUI, fncProj)
@@ -165,7 +166,7 @@ def testDlgItemEditor_Note(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Create Note
nwGUI.treeView.projTree.clearSelection()
nwGUI.treeView.projTree._getTreeItem("000000000000a").setSelected(True)
- nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None)
+ nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
# Open Note
assert nwGUI.openDocument("0000000000010")
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index 78c2af66..6085c59b 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -26,7 +26,7 @@ from shutil import copyfile
from tools import cmpFiles, buildTestProject, XML_IGNORE, writeFile
from PyQt5.QtCore import Qt
-from PyQt5.QtWidgets import QMessageBox, QDialog
+from PyQt5.QtWidgets import QMessageBox, QDialog, QInputDialog
from novelwriter.gui import GuiDocEditor, GuiNovelTree, GuiOutline
from novelwriter.enum import nwItemType, nwWidget
@@ -173,6 +173,7 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
monkeypatch.setattr(GuiItemEditor, "result", lambda *a: QDialog.Accepted)
monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
monkeypatch.setattr(GuiDocEditor, "hasFocus", lambda *a: True)
+ monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
# Create new, save, close project
buildTestProject(nwGUI, fncProj)
@@ -241,7 +242,7 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
nwGUI.switchFocus(nwWidget.TREE)
nwGUI.treeView.projTree.clearSelection()
nwGUI.treeView.projTree._getTreeItem("000000000000a").setSelected(True)
- nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None)
+ nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
assert nwGUI.openSelectedItem()
# Type something into the document
@@ -263,7 +264,7 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
nwGUI.switchFocus(nwWidget.TREE)
nwGUI.treeView.projTree.clearSelection()
nwGUI.treeView.projTree._getTreeItem("0000000000009").setSelected(True)
- nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None)
+ nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
assert nwGUI.openSelectedItem()
# Type something into the document
@@ -285,7 +286,7 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
nwGUI.switchFocus(nwWidget.TREE)
nwGUI.treeView.projTree.clearSelection()
nwGUI.treeView.projTree._getTreeItem("000000000000b").setSelected(True)
- nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None)
+ nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
assert nwGUI.openSelectedItem()
# Add Some Text
diff --git a/tests/test_gui/test_gui_projtree.py b/tests/test_gui/test_gui_projtree.py
index 7b66f305..81c9a801 100644
--- a/tests/test_gui/test_gui_projtree.py
+++ b/tests/test_gui/test_gui_projtree.py
@@ -24,9 +24,8 @@ import os
from tools import buildTestProject
-from PyQt5.QtWidgets import QAction, QMessageBox
+from PyQt5.QtWidgets import QAction, QMessageBox, QInputDialog
-from novelwriter.guimain import GuiMain
from novelwriter.gui.projtree import GuiProjectTree
from novelwriter.enum import nwItemType, nwItemClass
@@ -40,7 +39,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
- monkeypatch.setattr(GuiMain, "editItem", lambda *a: None)
+ monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
nwTree = nwGUI.treeView
@@ -89,22 +88,31 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
assert nwGUI.theProject.tree["0000000000012"].itemRoot == "0000000000008"
assert nwGUI.theProject.tree["0000000000012"].itemClass == nwItemClass.NOVEL
- # Add a new file next to the other new file
+ # Add a new chapter next to the other new file
nwTree.setSelectedHandle("0000000000012")
- assert nwTree.newTreeItem(nwItemType.FILE) is True
+ assert nwTree.newTreeItem(nwItemType.FILE, hLevel=2) is True
assert nwGUI.theProject.tree["0000000000013"].itemParent == "0000000000011"
assert nwGUI.theProject.tree["0000000000013"].itemRoot == "0000000000008"
assert nwGUI.theProject.tree["0000000000013"].itemClass == nwItemClass.NOVEL
assert nwGUI.openDocument("0000000000013")
- assert nwGUI.docEditor.getText() == "## New Document\n\n"
+ assert nwGUI.docEditor.getText() == "## New Chapter\n\n"
+
+ # Add a new scene next to the other new file
+ nwTree.setSelectedHandle("0000000000012")
+ assert nwTree.newTreeItem(nwItemType.FILE, hLevel=3) is True
+ assert nwGUI.theProject.tree["0000000000014"].itemParent == "0000000000011"
+ assert nwGUI.theProject.tree["0000000000014"].itemRoot == "0000000000008"
+ assert nwGUI.theProject.tree["0000000000014"].itemClass == nwItemClass.NOVEL
+ assert nwGUI.openDocument("0000000000014")
+ assert nwGUI.docEditor.getText() == "### New Scene\n\n"
# Add a new file to the characters folder
nwTree.setSelectedHandle("000000000000a")
- assert nwTree.newTreeItem(nwItemType.FILE) is True
- assert nwGUI.theProject.tree["0000000000014"].itemParent == "000000000000a"
- assert nwGUI.theProject.tree["0000000000014"].itemRoot == "000000000000a"
- assert nwGUI.theProject.tree["0000000000014"].itemClass == nwItemClass.CHARACTER
- assert nwGUI.openDocument("0000000000014")
+ assert nwTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True) is True
+ assert nwGUI.theProject.tree["0000000000015"].itemParent == "000000000000a"
+ assert nwGUI.theProject.tree["0000000000015"].itemRoot == "000000000000a"
+ assert nwGUI.theProject.tree["0000000000015"].itemClass == nwItemClass.CHARACTER
+ assert nwGUI.openDocument("0000000000015")
assert nwGUI.docEditor.getText() == "# New Note\n\n"
# Make sure the sibling folder bug trap works
@@ -115,6 +123,12 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
assert "Internal error" in caplog.text
nwGUI.theProject.tree["0000000000013"].setParent("0000000000011")
+ # Cancel during creation
+ with monkeypatch.context() as mp:
+ mp.setattr(QInputDialog, "getText", lambda *a, **k: ("", False))
+ nwTree.setSelectedHandle("0000000000013")
+ assert nwTree.newTreeItem(nwItemType.FILE) is False
+
# Get the trash folder
nwTree.projTree._addTrashRoot()
trashHandle = nwGUI.theProject.trashFolder()
@@ -148,7 +162,7 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
- monkeypatch.setattr(GuiMain, "editItem", lambda *a: None)
+ monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
nwTree = nwGUI.treeView
@@ -272,7 +286,7 @@ def testGuiProjTree_DeleteItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
- monkeypatch.setattr(GuiMain, "editItem", lambda *a: None)
+ monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
nwTree = nwGUI.treeView
From 272e7f6e2461b849abd9bc662b32b4b45a9644de Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Mon, 6 Jun 2022 22:17:24 +0200
Subject: [PATCH 06/35] Remove redundant menu entries
---
novelwriter/gui/mainmenu.py | 29 +----------------------------
novelwriter/gui/projtree.py | 31 +------------------------------
2 files changed, 2 insertions(+), 58 deletions(-)
diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py
index bd8d1edd..1996f151 100644
--- a/novelwriter/gui/mainmenu.py
+++ b/novelwriter/gui/mainmenu.py
@@ -33,7 +33,7 @@ from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWidgets import QMenuBar, QAction
-from novelwriter.enum import nwItemType, nwItemClass, nwDocAction, nwDocInsert, nwWidget
+from novelwriter.enum import nwItemType, nwDocAction, nwDocInsert, nwWidget
from novelwriter.constants import trConst, nwKeyWords, nwLabels, nwUnicode
logger = logging.getLogger(__name__)
@@ -164,33 +164,6 @@ class GuiMainMenu(QMenuBar):
# Project > Separator
self.projMenu.addSeparator()
- # Project > New Root
- self.rootMenu = self.projMenu.addMenu(self.tr("Create Root Folder"))
- self.rootItems = {}
- self.rootItems[nwItemClass.NOVEL] = QAction(self.tr("Novel Root"), self.rootMenu)
- self.rootItems[nwItemClass.PLOT] = QAction(self.tr("Plot Root"), self.rootMenu)
- self.rootItems[nwItemClass.CHARACTER] = QAction(self.tr("Character Root"), self.rootMenu)
- self.rootItems[nwItemClass.WORLD] = QAction(self.tr("Location Root"), self.rootMenu)
- self.rootItems[nwItemClass.TIMELINE] = QAction(self.tr("Timeline Root"), self.rootMenu)
- self.rootItems[nwItemClass.OBJECT] = QAction(self.tr("Object Root"), self.rootMenu)
- self.rootItems[nwItemClass.ENTITY] = QAction(self.tr("Entity Root"), self.rootMenu)
- self.rootItems[nwItemClass.CUSTOM] = QAction(self.tr("Custom Root"), self.rootMenu)
- self.rootItems[nwItemClass.ARCHIVE] = QAction(self.tr("Archive Root"), self.rootMenu)
- for n, itemClass in enumerate(self.rootItems.keys()):
- self.rootItems[itemClass].triggered.connect(
- lambda n, itemClass=itemClass: self._newTreeItem(nwItemType.ROOT, itemClass)
- )
- self.rootMenu.addAction(self.rootItems[itemClass])
-
- # Project > New Folder
- self.aCreateFolder = QAction(self.tr("Create Folder"), self)
- self.aCreateFolder.setShortcut("Ctrl+Shift+N")
- self.aCreateFolder.triggered.connect(lambda: self._newTreeItem(nwItemType.FOLDER))
- self.projMenu.addAction(self.aCreateFolder)
-
- # Project > Separator
- self.projMenu.addSeparator()
-
# Project > Edit
self.aEditItem = QAction(self.tr("Edit Item"), self)
self.aEditItem.setShortcuts(["Ctrl+E", "F2"])
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index 2e58a61d..f519fb96 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -167,7 +167,7 @@ class GuiProjectToolBar(QToolBar):
self.setStyleSheet("QToolBar {border: 0px;}")
# Tree Label
- self.projLabel = QLabel(self.tr("Project"))
+ self.projLabel = QLabel("%s" % self.tr("Project Content"))
self.projLabel.setContentsMargins(0, 0, mPx, 0)
self.projLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
@@ -1235,14 +1235,6 @@ class GuiProjectTreeMenu(QMenu):
self.toggleExp.triggered.connect(self._doToggleExported)
self.addAction(self.toggleExp)
- self.newFile = QAction(self.tr("New File"), self)
- self.newFile.triggered.connect(self._doMakeFile)
- self.addAction(self.newFile)
-
- self.newFolder = QAction(self.tr("New Folder"), self)
- self.newFolder.triggered.connect(self._doMakeFolder)
- self.addAction(self.newFolder)
-
self.deleteItem = QAction(self.tr("Delete Item"), self)
self.deleteItem.triggered.connect(self._doDeleteItem)
self.addAction(self.deleteItem)
@@ -1273,18 +1265,13 @@ class GuiProjectTreeMenu(QMenu):
trashHandle = self.theTree.theProject.tree.trashRoot()
- inTrash = self.theTree.theProject.tree.isTrash(theItem.itemHandle)
isTrash = theItem.itemHandle == trashHandle and trashHandle is not None
isFile = theItem.itemType == nwItemType.FILE
- allowNew = not (isTrash or inTrash)
-
self.editItem.setVisible(not isTrash)
self.openItem.setVisible(isFile)
self.viewItem.setVisible(isFile)
self.toggleExp.setVisible(isFile)
- self.newFile.setVisible(allowNew)
- self.newFolder.setVisible(allowNew)
self.deleteItem.setVisible(not isTrash)
self.emptyTrash.setVisible(isTrash)
@@ -1318,22 +1305,6 @@ class GuiProjectTreeMenu(QMenu):
self.theTree.theParent.editItem()
return
- @pyqtSlot()
- def _doMakeFile(self):
- """Forward the new file call to the project tree.
- """
- if self.theItem is not None:
- self.theTree.newTreeItem(nwItemType.FILE)
- return
-
- @pyqtSlot()
- def _doMakeFolder(self):
- """Forward the new folder call to the project tree.
- """
- if self.theItem is not None:
- self.theTree.newTreeItem(nwItemType.FOLDER)
- return
-
@pyqtSlot()
def _doToggleExported(self):
"""Flip the isExported flag of the current item.
From 5a6ef5efd3804a4778257d43c2afea3879dac836 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 7 Jun 2022 00:11:42 +0200
Subject: [PATCH 07/35] Add move buttons to project tree toolbar
---
docs/source/usage_shortcuts.rst | 3 +-
novelwriter/gui/__init__.py | 4 +-
novelwriter/gui/mainmenu.py | 22 +----------
novelwriter/gui/projtree.py | 58 ++++++++++++++++++++++++-----
novelwriter/guimain.py | 4 +-
tests/test_gui/test_gui_projtree.py | 45 +++++++++++-----------
6 files changed, 78 insertions(+), 58 deletions(-)
diff --git a/docs/source/usage_shortcuts.rst b/docs/source/usage_shortcuts.rst
index 69c2e773..fa761a3e 100644
--- a/docs/source/usage_shortcuts.rst
+++ b/docs/source/usage_shortcuts.rst
@@ -48,7 +48,7 @@ The main shorcuts are as follows:
":kbd:`Ctrl`:kbd:`H`", "Open the search and replace bar and search for the selected word, if any is selected. (On Mac, this is :kbd:`Cmd`:kbd:`=`.)"
":kbd:`Ctrl`:kbd:`I`", "Format selected text, or word under cursor, with emphasis (italic)."
":kbd:`Ctrl`:kbd:`K`", "Activate the insert commands. The commands are listed in :ref:`a_kb_ins`."
- ":kbd:`Ctrl`:kbd:`N`", "Create new document."
+ ":kbd:`Ctrl`:kbd:`N`", "Create new project item."
":kbd:`Ctrl`:kbd:`O`", "Open selected document."
":kbd:`Ctrl`:kbd:`Q`", "Exit novelWriter."
":kbd:`Ctrl`:kbd:`R`", "If in the project tree, open a document for viewing. If the editor has focus, open current document for viewing."
@@ -72,7 +72,6 @@ The main shorcuts are as follows:
":kbd:`Ctrl`:kbd:`Shift`:kbd:`A`", "Select all text in current paragraph."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`G`", "Find previous occurrence of search word in current document."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`I`", "Import text to the current document from a text file."
- ":kbd:`Ctrl`:kbd:`Shift`:kbd:`N`", "Create new folder."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`O`", "Open a project."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`R`", "Close the document viewer."
":kbd:`Ctrl`:kbd:`Shift`:kbd:`S`", "Save the current project."
diff --git a/novelwriter/gui/__init__.py b/novelwriter/gui/__init__.py
index 0ae23024..9560df1b 100644
--- a/novelwriter/gui/__init__.py
+++ b/novelwriter/gui/__init__.py
@@ -25,7 +25,7 @@ from novelwriter.gui.itemdetails import GuiItemDetails
from novelwriter.gui.mainmenu import GuiMainMenu
from novelwriter.gui.noveltree import GuiNovelTree
from novelwriter.gui.outline import GuiOutline
-from novelwriter.gui.projtree import GuiProjectWiew
+from novelwriter.gui.projtree import GuiProjectView
from novelwriter.gui.statusbar import GuiMainStatus
from novelwriter.gui.theme import GuiTheme
from novelwriter.gui.viewsbar import GuiViewsBar
@@ -39,7 +39,7 @@ __all__ = [
"GuiMainStatus",
"GuiNovelTree",
"GuiOutline",
- "GuiProjectWiew",
+ "GuiProjectView",
"GuiTheme",
"GuiViewsBar",
]
diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py
index 1996f151..37f1f75c 100644
--- a/novelwriter/gui/mainmenu.py
+++ b/novelwriter/gui/mainmenu.py
@@ -33,7 +33,7 @@ from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtWidgets import QMenuBar, QAction
-from novelwriter.enum import nwItemType, nwDocAction, nwDocInsert, nwWidget
+from novelwriter.enum import nwDocAction, nwDocInsert, nwWidget
from novelwriter.constants import trConst, nwKeyWords, nwLabels, nwUnicode
logger = logging.getLogger(__name__)
@@ -62,8 +62,6 @@ class GuiMainMenu(QMenuBar):
# Function Pointers
self._docAction = self.theParent.passDocumentAction
- self._moveTreeItem = self.theParent.treeView.moveTreeItem
- self._newTreeItem = self.theParent.treeView.newTreeItem
self._docInsert = self.theParent.docEditor.insertText
self._insertKeyWord = self.theParent.docEditor.insertKeyWord
@@ -176,18 +174,6 @@ class GuiMainMenu(QMenuBar):
self.aDeleteItem.triggered.connect(lambda: self.theParent.treeView.deleteItem(None))
self.projMenu.addAction(self.aDeleteItem)
- # Project > Move Up
- self.aMoveUp = QAction(self.tr("Move Item Up"), self)
- self.aMoveUp.setShortcut("Ctrl+Up")
- self.aMoveUp.triggered.connect(lambda: self._moveTreeItem(-1))
- self.projMenu.addAction(self.aMoveUp)
-
- # Project > Move Down
- self.aMoveDown = QAction(self.tr("Move Item Down"), self)
- self.aMoveDown.setShortcut("Ctrl+Down")
- self.aMoveDown.triggered.connect(lambda: self._moveTreeItem(1))
- self.projMenu.addAction(self.aMoveDown)
-
# Project > Undo Last Action
self.aMoveUndo = QAction(self.tr("Undo Last Move"), self)
self.aMoveUndo.setShortcut("Ctrl+Shift+Z")
@@ -217,12 +203,6 @@ class GuiMainMenu(QMenuBar):
# Document
self.docuMenu = self.addMenu(self.tr("&Document"))
- # Document > New
- self.aNewDoc = QAction(self.tr("New Document"), self)
- self.aNewDoc.setShortcut("Ctrl+N")
- self.aNewDoc.triggered.connect(lambda: self._newTreeItem(nwItemType.FILE))
- self.docuMenu.addAction(self.aNewDoc)
-
# Document > Open
self.aOpenDoc = QAction(self.tr("Open Document"), self)
self.aOpenDoc.setShortcut("Ctrl+O")
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index f519fb96..fcd2cd83 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -6,7 +6,7 @@ GUI classes for the main window project tree
File History:
Created: 2018-09-29 [0.0.1] GuiProjectTree
Created: 2020-06-04 [0.7] GuiProjectTreeMenu
-Created: 2022-06-06 [1.7b1] GuiProjectWiew
+Created: 2022-06-06 [1.7b1] GuiProjectView
Created: 2022-06-06 [1.7b1] GuiProjectToolBar
This file is a part of novelWriter
@@ -35,9 +35,9 @@ 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,
- QDialog, QHeaderView, QWidget, QVBoxLayout, QToolBar, QLabel, QToolButton,
- QSizePolicy, QInputDialog
+ qApp, QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction,
+ QFrame, QDialog, QHeaderView, QWidget, QVBoxLayout, QToolBar, QLabel,
+ QToolButton, QSizePolicy, QInputDialog
)
from novelwriter.core import NWDoc
@@ -48,7 +48,7 @@ from novelwriter.constants import trConst, nwLabels
logger = logging.getLogger(__name__)
-class GuiProjectWiew(QWidget):
+class GuiProjectView(QWidget):
"""This is a wrapper class holding all the elements of the project
tree. The core object is the project tree itself. Most methods
available are mapped through to the project tree class.
@@ -87,7 +87,6 @@ class GuiProjectWiew(QWidget):
# Function Mappings
self.newTreeItem = self.projTree.newTreeItem
self.revealNewTreeItem = self.projTree.revealNewTreeItem
- self.moveTreeItem = self.projTree.moveTreeItem
self.editTreeItem = self.projTree.editTreeItem
self.getTreeFromHandle = self.projTree.getTreeFromHandle
self.emptyTrash = self.projTree.emptyTrash
@@ -121,9 +120,26 @@ class GuiProjectWiew(QWidget):
self.projTree.buildTree()
return
+ def setFocus(self):
+ """Forward the set focus call to the tree widget.
+ """
+ self.projTree.setFocus()
+ return
+
def treeFocus(self):
+ """Check if the project tree has focus.
+ """
return self.projTree.hasFocus()
+ def anyFocus(self):
+ """Check if any widget or child widget has focus.
+ """
+ if self.hasFocus():
+ return True
+ if self.isAncestorOf(qApp.focusWidget()):
+ return True
+ return False
+
##
# Public Solts
##
@@ -136,7 +152,7 @@ class GuiProjectWiew(QWidget):
self.wordCountsChanged.emit()
return
-# END Class GuiProjectWiew
+# END Class GuiProjectView
class GuiProjectToolBar(QToolBar):
@@ -171,6 +187,19 @@ class GuiProjectToolBar(QToolBar):
self.projLabel.setContentsMargins(0, 0, mPx, 0)
self.projLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+ # Move Buttons
+ self.tbMoveU = QToolButton(self)
+ self.tbMoveU.setToolTip("%s [Ctrl+Up]" % self.tr("Move Up"))
+ self.tbMoveU.setShortcut("Ctrl+Up")
+ self.tbMoveU.setIcon(self.theTheme.getIcon("up"))
+ self.tbMoveU.clicked.connect(lambda: self._forwardMoveItem(-1))
+
+ self.tbMoveD = QToolButton(self)
+ self.tbMoveD.setToolTip("%s [Ctrl+Down]" % self.tr("Move Down"))
+ self.tbMoveD.setShortcut("Ctrl+Down")
+ self.tbMoveD.setIcon(self.theTheme.getIcon("down"))
+ self.tbMoveD.clicked.connect(lambda: self._forwardMoveItem(1))
+
# Items Menu
self.mItems = QMenu()
@@ -207,6 +236,8 @@ class GuiProjectToolBar(QToolBar):
self._addRootFolderEntry(nwItemClass.CUSTOM)
self.tbItems = QToolButton(self)
+ self.tbItems.setToolTip("%s [Ctrl+N]" % self.tr("Add Item"))
+ self.tbItems.setShortcut("Ctrl+N")
self.tbItems.setIcon(self.theTheme.getIcon("add"))
self.tbItems.setMenu(self.mItems)
self.tbItems.setPopupMode(QToolButton.InstantPopup)
@@ -219,6 +250,8 @@ class GuiProjectToolBar(QToolBar):
# Assemble
self.addWidget(self.projLabel)
self.addSeparator()
+ self.addWidget(self.tbMoveU)
+ self.addWidget(self.tbMoveD)
self.addWidget(self.tbItems)
self.addWidget(self.tbSettings)
@@ -253,6 +286,13 @@ class GuiProjectToolBar(QToolBar):
self.theWidget.projTree.newTreeItem(nwItemType.FOLDER)
return
+ @pyqtSlot(int)
+ def _forwardMoveItem(self, steps):
+ """Forward the request to move an item up or down.
+ """
+ self.theWidget.projTree.moveTreeItem(steps)
+ return
+
##
# Internal Functions
##
@@ -492,7 +532,7 @@ class GuiProjectTree(QTreeWidget):
logger.error("No project open")
return False
- if not self.hasFocus():
+ if not self.theWidget.anyFocus():
return False
tHandle = self.getSelectedHandle()
@@ -831,7 +871,7 @@ class GuiProjectTree(QTreeWidget):
dstItem = self._lastMove.get("parent", None)
dstIndex = self._lastMove.get("index", None)
- if not self.hasFocus():
+ if not self.theWidget.anyFocus():
return False
if srcItem is None or dstItem is None or dstIndex is None:
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index d18d4d17..2716213e 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -40,7 +40,7 @@ from PyQt5.QtWidgets import (
from novelwriter.gui import (
GuiDocEditor, GuiDocViewDetails, GuiDocViewer, GuiItemDetails, GuiMainMenu,
- GuiMainStatus, GuiNovelTree, GuiOutline, GuiProjectWiew, GuiTheme,
+ GuiMainStatus, GuiNovelTree, GuiOutline, GuiProjectView, GuiTheme,
GuiViewsBar
)
from novelwriter.dialogs import (
@@ -105,7 +105,7 @@ class GuiMain(QMainWindow):
# Main GUI Elements
self.statusBar = GuiMainStatus(self)
- self.treeView = GuiProjectWiew(self)
+ self.treeView = GuiProjectView(self)
self.novelView = GuiNovelTree(self)
self.docEditor = GuiDocEditor(self)
self.viewMeta = GuiDocViewDetails(self)
diff --git a/tests/test_gui/test_gui_projtree.py b/tests/test_gui/test_gui_projtree.py
index 81c9a801..031e7680 100644
--- a/tests/test_gui/test_gui_projtree.py
+++ b/tests/test_gui/test_gui_projtree.py
@@ -26,7 +26,7 @@ from tools import buildTestProject
from PyQt5.QtWidgets import QAction, QMessageBox, QInputDialog
-from novelwriter.gui.projtree import GuiProjectTree
+from novelwriter.gui.projtree import GuiProjectView, GuiProjectTree
from novelwriter.enum import nwItemType, nwItemClass
@@ -163,11 +163,12 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
+ monkeypatch.setattr(GuiProjectView, "anyFocus", lambda *a: True)
nwTree = nwGUI.treeView
# Try to move item with no project
- assert nwTree.moveTreeItem(1) is False
+ assert nwTree.projTree.moveTreeItem(1) is False
# Create a project
prjDir = os.path.join(fncDir, "project")
@@ -187,33 +188,33 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
]
# Move item without focus
- monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: False)
- assert nwTree.moveTreeItem(1) is False
- assert nwTree.getTreeFromHandle("000000000000d") == [
- "000000000000d", "000000000000e", "000000000000f",
- "0000000000010", "0000000000011", "0000000000012",
- ]
- monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
+ with monkeypatch.context() as mp:
+ mp.setattr(GuiProjectView, "anyFocus", lambda *a: False)
+ assert nwTree.projTree.moveTreeItem(1) is False
+ assert nwTree.getTreeFromHandle("000000000000d") == [
+ "000000000000d", "000000000000e", "000000000000f",
+ "0000000000010", "0000000000011", "0000000000012",
+ ]
# Move with no selections
nwTree.projTree.clearSelection()
- assert nwTree.moveTreeItem(1) is False
+ assert nwTree.projTree.moveTreeItem(1) is False
# Move second item up twice (should give same result)
nwTree.setSelectedHandle("000000000000f")
- assert nwTree.moveTreeItem(-1) is True
+ assert nwTree.projTree.moveTreeItem(-1) is True
assert nwTree.getTreeFromHandle("000000000000d") == [
"000000000000d", "000000000000f", "000000000000e",
"0000000000010", "0000000000011", "0000000000012",
]
- assert nwTree.moveTreeItem(-1) is False
+ assert nwTree.projTree.moveTreeItem(-1) is False
assert nwTree.getTreeFromHandle("000000000000d") == [
"000000000000d", "000000000000f", "000000000000e",
"0000000000010", "0000000000011", "0000000000012",
]
- # Restore via menu entry
- nwGUI.mainMenu.aMoveDown.activate(QAction.Trigger)
+ # Restore
+ assert nwTree.projTree.moveTreeItem(1) is True
assert nwTree.getTreeFromHandle("000000000000d") == [
"000000000000d", "000000000000e", "000000000000f",
"0000000000010", "0000000000011", "0000000000012",
@@ -221,19 +222,19 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
# Move fifth item down twice (should give same result)
nwTree.setSelectedHandle("0000000000011")
- assert nwTree.moveTreeItem(1) is True
+ assert nwTree.projTree.moveTreeItem(1) is True
assert nwTree.getTreeFromHandle("000000000000d") == [
"000000000000d", "000000000000e", "000000000000f",
"0000000000010", "0000000000012", "0000000000011",
]
- assert nwTree.moveTreeItem(1) is False
+ assert nwTree.projTree.moveTreeItem(1) is False
assert nwTree.getTreeFromHandle("000000000000d") == [
"000000000000d", "000000000000e", "000000000000f",
"0000000000010", "0000000000012", "0000000000011",
]
- # Restore via menu entry
- nwGUI.mainMenu.aMoveUp.activate(QAction.Trigger)
+ # Restore
+ assert nwTree.projTree.moveTreeItem(-1) is True
assert nwTree.getTreeFromHandle("000000000000d") == [
"000000000000d", "000000000000e", "000000000000f",
"0000000000010", "0000000000011", "0000000000012",
@@ -241,7 +242,7 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
# Move down again, and restore via undo
nwTree.setSelectedHandle("0000000000011")
- assert nwTree.moveTreeItem(1) is True
+ assert nwTree.projTree.moveTreeItem(1) is True
assert nwTree.getTreeFromHandle("000000000000d") == [
"000000000000d", "000000000000e", "000000000000f",
"0000000000010", "0000000000012", "0000000000011",
@@ -259,15 +260,15 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
assert nwGUI.theProject.tree._treeOrder.index("0000000000008") == 0
# Move novel folder up
- assert nwTree.moveTreeItem(-1) is False
+ assert nwTree.projTree.moveTreeItem(-1) is False
assert nwGUI.theProject.tree._treeOrder.index("0000000000008") == 0
# Move novel folder down
- assert nwTree.moveTreeItem(1) is True
+ assert nwTree.projTree.moveTreeItem(1) is True
assert nwGUI.theProject.tree._treeOrder.index("0000000000008") == 1
# Move novel folder up again
- assert nwTree.moveTreeItem(-1) is True
+ assert nwTree.projTree.moveTreeItem(-1) is True
assert nwGUI.theProject.tree._treeOrder.index("0000000000008") == 0
# Clean up
From 0909bf7c362da6aa34bfc0ff07239c20560b17f7 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 7 Jun 2022 10:34:27 +0200
Subject: [PATCH 08/35] Update code of conduct to v2.1
---
CODE_OF_CONDUCT.md | 150 +++++++++++++++++++++++++++++++--------------
1 file changed, 103 insertions(+), 47 deletions(-)
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index f64bc973..28de89d7 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -2,75 +2,131 @@
## Our Pledge
-In the interest of fostering an open and welcoming environment, we as
-contributors and maintainers pledge to making participation in our project and
-our community a harassment-free experience for everyone, regardless of age, body
-size, disability, ethnicity, sex characteristics, gender identity and expression,
-level of experience, education, socio-economic status, nationality, personal
-appearance, race, religion, or sexual identity and orientation.
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, caste, color, religion, or sexual
+identity and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
## Our Standards
-Examples of behavior that contributes to creating a positive environment
-include:
+Examples of behavior that contributes to a positive environment for our
+community include:
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the overall
+ community
-Examples of unacceptable behavior by participants include:
+Examples of unacceptable behavior include:
-* The use of sexualized language or imagery and unwelcome sexual attention or
- advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
+* The use of sexualized language or imagery, and sexual attention or advances of
+ any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
-* Publishing others' private information, such as a physical or electronic
- address, without explicit permission
+* Publishing others' private information, such as a physical or email address,
+ without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
-## Our Responsibilities
+## Enforcement Responsibilities
-Project maintainers are responsible for clarifying the standards of acceptable
-behavior and are expected to take appropriate and fair corrective action in
-response to any instances of unacceptable behavior.
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
-Project maintainers have the right and responsibility to remove, edit, or
-reject comments, commits, code, wiki edits, issues, and other contributions
-that are not aligned to this Code of Conduct, or to ban temporarily or
-permanently any contributor for other behaviors that they deem inappropriate,
-threatening, offensive, or harmful.
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
## Scope
-This Code of Conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community. Examples of
-representing a project or community include using an official project e-mail
-address, posting via an official social media account, or acting as an appointed
-representative at an online or offline event. Representation of a project may be
-further defined and clarified by project maintainers.
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported by contacting the project leader at issues (at) novelwriter.io. All
-complaints will be reviewed and investigated and will result in a response that
-is deemed necessary and appropriate to the circumstances. The project team is
-obligated to maintain confidentiality with regard to the reporter of an incident.
-Further details of specific enforcement policies may be posted separately.
+reported to the community leaders responsible for enforcement at issues (at)
+novelwriter.io. All complaints will be reviewed and investigated promptly and
+fairly.
-Project maintainers who do not follow or enforce the Code of Conduct in good
-faith may face temporary or permanent repercussions as determined by other
-members of the project's leadership.
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series of
+actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or permanent
+ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within the
+community.
## Attribution
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
-available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.1, available at
+[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
+[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
-
-For answers to common questions about this code of conduct, see
-https://www.contributor-covenant.org/faq
+[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
+[Mozilla CoC]: https://github.com/mozilla/diversity
+[FAQ]: https://www.contributor-covenant.org/faq
+[translations]: https://www.contributor-covenant.org/translations
From ef270bc0698f272df542321ff9ddf5549aef0319 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 7 Jun 2022 22:38:02 +0200
Subject: [PATCH 09/35] Tweak project toolbar look, and fix shortcuts
---
novelwriter/gui/projtree.py | 165 +++++++++++++---------------
tests/test_gui/test_gui_projtree.py | 9 --
2 files changed, 79 insertions(+), 95 deletions(-)
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index fcd2cd83..bc5b78b6 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -33,11 +33,11 @@ from enum import Enum
from time import time
from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
-from PyQt5.QtGui import QIcon
+from PyQt5.QtGui import QIcon, QPalette
from PyQt5.QtWidgets import (
qApp, QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction,
- QFrame, QDialog, QHeaderView, QWidget, QVBoxLayout, QToolBar, QLabel,
- QToolButton, QSizePolicy, QInputDialog
+ QFrame, QDialog, QHeaderView, QWidget, QVBoxLayout, QLabel, QToolButton,
+ QSizePolicy, QInputDialog, QHBoxLayout, QShortcut
)
from novelwriter.core import NWDoc
@@ -75,13 +75,24 @@ class GuiProjectView(QWidget):
# Assemble
self.outerBox = QVBoxLayout()
- self.outerBox.addWidget(self.projBar)
- self.outerBox.addWidget(self.projTree)
+ self.outerBox.addWidget(self.projBar, 0)
+ self.outerBox.addWidget(self.projTree, 1)
self.outerBox.setContentsMargins(0, 0, 0, 0)
self.outerBox.setSpacing(0)
self.setLayout(self.outerBox)
+ # Keyboard Shortcuts
+ self.keyCtrlUp = QShortcut(self.projTree)
+ self.keyCtrlUp.setKey("Ctrl+Up")
+ self.keyCtrlUp.setContext(Qt.WidgetShortcut)
+ self.keyCtrlUp.activated.connect(lambda: self.projTree.moveTreeItem(-1))
+
+ self.keyCtrlDown = QShortcut(self.projTree)
+ self.keyCtrlDown.setKey("Ctrl+Down")
+ self.keyCtrlDown.setContext(Qt.WidgetShortcut)
+ self.keyCtrlDown.activated.connect(lambda: self.projTree.moveTreeItem(1))
+
# Connect Signals
# Function Mappings
@@ -155,7 +166,7 @@ class GuiProjectView(QWidget):
# END Class GuiProjectView
-class GuiProjectToolBar(QToolBar):
+class GuiProjectToolBar(QWidget):
ADD_PLAIN = 0
ADD_CHAP = 1
@@ -163,42 +174,52 @@ class GuiProjectToolBar(QToolBar):
ADD_NOTE = 3
ADD_FOLDER = 4
- def __init__(self, theWidget):
- QTreeWidget.__init__(self, theWidget)
+ def __init__(self, projView):
+ QTreeWidget.__init__(self, projView)
logger.debug("Initialising GuiProjectToolBar ...")
self.mainConf = novelwriter.CONFIG
- self.theWidget = theWidget
- self.theParent = theWidget.theParent
- self.theProject = theWidget.theParent.theProject
- self.theTheme = theWidget.theParent.theTheme
+ self.projView = projView
+ self.theParent = projView.theParent
+ self.theProject = projView.theParent.theProject
+ self.theTheme = projView.theParent.theTheme
iPx = self.theTheme.baseIconSize
- mPx = self.mainConf.pxInt(12)
+ mPx = self.mainConf.pxInt(4)
- self.setMovable(False)
- self.setIconSize(QSize(iPx, iPx))
self.setContentsMargins(0, 0, 0, 0)
- self.setStyleSheet("QToolBar {border: 0px;}")
+ self.setAutoFillBackground(True)
+
+ qPalette = self.palette()
+ qPalette.setBrush(QPalette.Window, qPalette.base())
+ self.setPalette(qPalette)
+
+ fadeCol = qPalette.text().color()
+ buttonStyle = (
+ "QToolButton {{border: none; background: transparent;}} "
+ "QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
+ ).format(fadeCol.red(), fadeCol.green(), fadeCol.blue())
# Tree Label
self.projLabel = QLabel("%s" % self.tr("Project Content"))
- self.projLabel.setContentsMargins(0, 0, mPx, 0)
+ self.projLabel.setContentsMargins(0, 0, 0, 0)
self.projLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
# Move Buttons
self.tbMoveU = QToolButton(self)
self.tbMoveU.setToolTip("%s [Ctrl+Up]" % self.tr("Move Up"))
- self.tbMoveU.setShortcut("Ctrl+Up")
self.tbMoveU.setIcon(self.theTheme.getIcon("up"))
- self.tbMoveU.clicked.connect(lambda: self._forwardMoveItem(-1))
+ self.tbMoveU.setIconSize(QSize(iPx, iPx))
+ self.tbMoveU.setStyleSheet(buttonStyle)
+ self.tbMoveU.clicked.connect(lambda: self.projView.projTree.moveTreeItem(-1))
self.tbMoveD = QToolButton(self)
self.tbMoveD.setToolTip("%s [Ctrl+Down]" % self.tr("Move Down"))
- self.tbMoveD.setShortcut("Ctrl+Down")
self.tbMoveD.setIcon(self.theTheme.getIcon("down"))
- self.tbMoveD.clicked.connect(lambda: self._forwardMoveItem(1))
+ self.tbMoveD.setIconSize(QSize(iPx, iPx))
+ self.tbMoveD.setStyleSheet(buttonStyle)
+ self.tbMoveD.clicked.connect(lambda: self.projView.projTree.moveTreeItem(1))
# Items Menu
self.mItems = QMenu()
@@ -239,21 +260,29 @@ class GuiProjectToolBar(QToolBar):
self.tbItems.setToolTip("%s [Ctrl+N]" % self.tr("Add Item"))
self.tbItems.setShortcut("Ctrl+N")
self.tbItems.setIcon(self.theTheme.getIcon("add"))
+ self.tbItems.setIconSize(QSize(iPx, iPx))
+ self.tbItems.setStyleSheet(buttonStyle)
self.tbItems.setMenu(self.mItems)
self.tbItems.setPopupMode(QToolButton.InstantPopup)
# Settings Menu
self.tbSettings = QToolButton(self)
self.tbSettings.setIcon(self.theTheme.getIcon("menu"))
+ self.tbSettings.setIconSize(QSize(iPx, iPx))
+ self.tbSettings.setStyleSheet(buttonStyle)
self.tbSettings.setPopupMode(QToolButton.InstantPopup)
# Assemble
- self.addWidget(self.projLabel)
- self.addSeparator()
- self.addWidget(self.tbMoveU)
- self.addWidget(self.tbMoveD)
- self.addWidget(self.tbItems)
- self.addWidget(self.tbSettings)
+ self.outerBox = QHBoxLayout()
+ self.outerBox.addWidget(self.projLabel)
+ self.outerBox.addWidget(self.tbMoveU)
+ self.outerBox.addWidget(self.tbMoveD)
+ self.outerBox.addWidget(self.tbItems)
+ self.outerBox.addWidget(self.tbSettings)
+ self.outerBox.setContentsMargins(mPx, mPx, 0, mPx)
+ self.outerBox.setSpacing(mPx)
+
+ self.setLayout(self.outerBox)
logger.debug("GuiProjectToolBar initialisation complete")
@@ -267,7 +296,7 @@ class GuiProjectToolBar(QToolBar):
def _forwardNewRootFolder(self, itemClass):
"""Forward the request for a new root folder to the tree.
"""
- self.theWidget.projTree.newTreeItem(nwItemType.ROOT, itemClass)
+ self.projView.projTree.newTreeItem(nwItemType.ROOT, itemClass)
return
@pyqtSlot(int)
@@ -275,22 +304,15 @@ class GuiProjectToolBar(QToolBar):
"""Forward the request for a new item of a given type.
"""
if type == self.ADD_PLAIN:
- self.theWidget.projTree.newTreeItem(nwItemType.FILE, hLevel=0, isNote=False)
+ self.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=0, isNote=False)
elif type == self.ADD_CHAP:
- self.theWidget.projTree.newTreeItem(nwItemType.FILE, hLevel=2, isNote=False)
+ self.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=2, isNote=False)
elif type == self.ADD_SCENE:
- self.theWidget.projTree.newTreeItem(nwItemType.FILE, hLevel=3, isNote=False)
+ self.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=3, isNote=False)
elif type == self.ADD_NOTE:
- self.theWidget.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True)
+ self.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True)
elif type == self.ADD_FOLDER:
- self.theWidget.projTree.newTreeItem(nwItemType.FOLDER)
- return
-
- @pyqtSlot(int)
- def _forwardMoveItem(self, steps):
- """Forward the request to move an item up or down.
- """
- self.theWidget.projTree.moveTreeItem(steps)
+ self.projView.projTree.newTreeItem(nwItemType.FOLDER)
return
##
@@ -315,16 +337,16 @@ class GuiProjectTree(QTreeWidget):
C_EXPORT = 2
C_STATUS = 3
- def __init__(self, theWidget):
- QTreeWidget.__init__(self, theWidget)
+ def __init__(self, projView):
+ QTreeWidget.__init__(self, projView)
logger.debug("Initialising GuiProjectTree ...")
self.mainConf = novelwriter.CONFIG
- self.theWidget = theWidget
- self.theParent = theWidget.theParent
- self.theTheme = theWidget.theParent.theTheme
- self.theProject = theWidget.theParent.theProject
+ self.projView = projView
+ self.theParent = projView.theParent
+ self.theTheme = projView.theParent.theTheme
+ self.theProject = projView.theParent.theProject
# Internal Variables
self._treeMap = {}
@@ -496,7 +518,7 @@ class GuiProjectTree(QTreeWidget):
# If successful, update word count
wC = self.theProject.index.getCounts(tHandle)[1]
self.propagateCount(tHandle, wC)
- self.theWidget.wordCountsChanged.emit()
+ self.projView.wordCountsChanged.emit()
# Add the new item to the project tree
self.revealNewTreeItem(tHandle, nHandle)
@@ -525,19 +547,12 @@ class GuiProjectTree(QTreeWidget):
return True
def moveTreeItem(self, nStep):
- """Move an item up or down in the tree, but only if the project
- tree has focus. This also applies when the menu is used.
+ """Move an item up or down in the tree.
"""
- if not self.theParent.hasProject:
- logger.error("No project open")
- return False
-
- if not self.theWidget.anyFocus():
- return False
-
tHandle = self.getSelectedHandle()
tItem = self._getTreeItem(tHandle)
if tItem is None:
+ logger.verbose("No item selected")
return False
pItem = tItem.parent()
@@ -745,7 +760,7 @@ class GuiProjectTree(QTreeWidget):
self._deleteTreeItem(dHandle)
self._alertTreeChange(tHandle=tHandle, flush=autoFlush)
- self.theWidget.wordCountsChanged.emit()
+ self.projView.wordCountsChanged.emit()
else:
# The item is not already in the trash folder, so we
@@ -871,7 +886,7 @@ class GuiProjectTree(QTreeWidget):
dstItem = self._lastMove.get("parent", None)
dstIndex = self._lastMove.get("index", None)
- if not self.theWidget.anyFocus():
+ if not self.projView.anyFocus():
return False
if srcItem is None or dstItem is None or dstIndex is None:
@@ -951,7 +966,7 @@ class GuiProjectTree(QTreeWidget):
"""
tHandle = self.getSelectedHandle()
if tHandle is not None:
- self.theWidget.selectedItemChanged.emit(tHandle)
+ self.projView.selectedItemChanged.emit(tHandle)
return
@pyqtSlot("QTreeWidgetItem*", int)
@@ -968,7 +983,7 @@ class GuiProjectTree(QTreeWidget):
return
if tItem.itemType == nwItemType.FILE:
- self.theWidget.openDocumentRequest.emit(tHandle, nwDocMode.EDIT)
+ self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT)
else:
trItem = self._getTreeItem(tHandle)
if trItem is not None:
@@ -1020,7 +1035,7 @@ class GuiProjectTree(QTreeWidget):
return
if tItem.itemType == nwItemType.FILE:
- self.theWidget.openDocumentRequest.emit(tHandle, nwDocMode.VIEW)
+ self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW)
return
@@ -1227,11 +1242,11 @@ class GuiProjectTree(QTreeWidget):
itemType = tItem.itemType
if itemType == nwItemType.ROOT:
- self.theWidget.rootFolderChanged.emit(tHandle)
+ self.projView.rootFolderChanged.emit(tHandle)
elif itemType == nwItemType.FILE and tItem.isNovelLike():
- self.theWidget.novelItemChanged.emit(tHandle)
+ self.projView.novelItemChanged.emit(tHandle)
- self.theWidget.treeItemChanged.emit(tHandle)
+ self.projView.treeItemChanged.emit(tHandle)
return
@@ -1283,14 +1298,6 @@ class GuiProjectTreeMenu(QMenu):
self.emptyTrash.triggered.connect(self._doEmptyTrash)
self.addAction(self.emptyTrash)
- self.moveUp = QAction(self.tr("Move Item Up"), self)
- self.moveUp.triggered.connect(self._doMoveUp)
- self.addAction(self.moveUp)
-
- self.moveDown = QAction(self.tr("Move Item Down"), self)
- self.moveDown.triggered.connect(self._doMoveDown)
- self.addAction(self.moveDown)
-
return
def filterActions(self, theItem):
@@ -1369,18 +1376,4 @@ class GuiProjectTreeMenu(QMenu):
self.theTree.emptyTrash()
return
- @pyqtSlot()
- def _doMoveUp(self):
- """Forward the move item call to the project tree.
- """
- self.theTree.moveTreeItem(-1)
- return
-
- @pyqtSlot()
- def _doMoveDown(self):
- """Forward the move item call to the project tree.
- """
- self.theTree.moveTreeItem(1)
- return
-
# END Class GuiProjectTreeMenu
diff --git a/tests/test_gui/test_gui_projtree.py b/tests/test_gui/test_gui_projtree.py
index 031e7680..c0189a66 100644
--- a/tests/test_gui/test_gui_projtree.py
+++ b/tests/test_gui/test_gui_projtree.py
@@ -187,15 +187,6 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
"0000000000010", "0000000000011", "0000000000012",
]
- # Move item without focus
- with monkeypatch.context() as mp:
- mp.setattr(GuiProjectView, "anyFocus", lambda *a: False)
- assert nwTree.projTree.moveTreeItem(1) is False
- assert nwTree.getTreeFromHandle("000000000000d") == [
- "000000000000d", "000000000000e", "000000000000f",
- "0000000000010", "0000000000011", "0000000000012",
- ]
-
# Move with no selections
nwTree.projTree.clearSelection()
assert nwTree.projTree.moveTreeItem(1) is False
From af39fb98a13f0a3a8e09dcc0d3e5bc731f5263ad Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 7 Jun 2022 23:38:17 +0200
Subject: [PATCH 10/35] Clean up project tree code and add undo action to the
menu
---
novelwriter/gui/mainmenu.py | 6 --
novelwriter/gui/projtree.py | 153 +++++++++++++---------------
tests/test_gui/test_gui_guimain.py | 2 +-
tests/test_gui/test_gui_projtree.py | 52 +++++-----
4 files changed, 95 insertions(+), 118 deletions(-)
diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py
index 37f1f75c..33b43cfb 100644
--- a/novelwriter/gui/mainmenu.py
+++ b/novelwriter/gui/mainmenu.py
@@ -174,12 +174,6 @@ class GuiMainMenu(QMenuBar):
self.aDeleteItem.triggered.connect(lambda: self.theParent.treeView.deleteItem(None))
self.projMenu.addAction(self.aDeleteItem)
- # Project > Undo Last Action
- self.aMoveUndo = QAction(self.tr("Undo Last Move"), self)
- self.aMoveUndo.setShortcut("Ctrl+Shift+Z")
- self.aMoveUndo.triggered.connect(lambda: self.theParent.treeView.undoLastMove())
- self.projMenu.addAction(self.aMoveUndo)
-
# Project > Empty Trash
self.aEmptyTrash = QAction(self.tr("Empty Trash"), self)
self.aEmptyTrash.triggered.connect(lambda: self.theParent.treeView.emptyTrash())
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index bc5b78b6..6ad4d501 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -70,8 +70,8 @@ class GuiProjectView(QWidget):
self.theParent = theParent
# Build GUI
- self.projBar = GuiProjectToolBar(self)
self.projTree = GuiProjectTree(self)
+ self.projBar = GuiProjectToolBar(self)
# Assemble
self.outerBox = QVBoxLayout()
@@ -83,20 +83,22 @@ class GuiProjectView(QWidget):
self.setLayout(self.outerBox)
# Keyboard Shortcuts
- self.keyCtrlUp = QShortcut(self.projTree)
- self.keyCtrlUp.setKey("Ctrl+Up")
- self.keyCtrlUp.setContext(Qt.WidgetShortcut)
- self.keyCtrlUp.activated.connect(lambda: self.projTree.moveTreeItem(-1))
+ self.keyMoveUp = QShortcut(self.projTree)
+ self.keyMoveUp.setKey("Ctrl+Up")
+ self.keyMoveUp.setContext(Qt.WidgetShortcut)
+ self.keyMoveUp.activated.connect(lambda: self.projTree.moveTreeItem(-1))
- self.keyCtrlDown = QShortcut(self.projTree)
- self.keyCtrlDown.setKey("Ctrl+Down")
- self.keyCtrlDown.setContext(Qt.WidgetShortcut)
- self.keyCtrlDown.activated.connect(lambda: self.projTree.moveTreeItem(1))
+ self.keyMoveDn = QShortcut(self.projTree)
+ self.keyMoveDn.setKey("Ctrl+Down")
+ self.keyMoveDn.setContext(Qt.WidgetShortcut)
+ self.keyMoveDn.activated.connect(lambda: self.projTree.moveTreeItem(1))
- # Connect Signals
+ self.keyUndoMv = QShortcut(self.projTree)
+ self.keyUndoMv.setKey("Ctrl+Shift+Z")
+ self.keyUndoMv.setContext(Qt.WidgetShortcut)
+ self.keyUndoMv.activated.connect(lambda: self.projTree.undoLastMove())
# Function Mappings
- self.newTreeItem = self.projTree.newTreeItem
self.revealNewTreeItem = self.projTree.revealNewTreeItem
self.editTreeItem = self.projTree.editTreeItem
self.getTreeFromHandle = self.projTree.getTreeFromHandle
@@ -104,7 +106,6 @@ class GuiProjectView(QWidget):
self.deleteItem = self.projTree.deleteItem
self.setTreeItemValues = self.projTree.setTreeItemValues
self.propagateCount = self.projTree.propagateCount
- self.undoLastMove = self.projTree.undoLastMove
self.getSelectedHandle = self.projTree.getSelectedHandle
self.setSelectedHandle = self.projTree.setSelectedHandle
self.changedSince = self.projTree.changedSince
@@ -152,7 +153,7 @@ class GuiProjectView(QWidget):
return False
##
- # Public Solts
+ # Public Slots
##
@pyqtSlot(str, int, int, int)
@@ -168,12 +169,6 @@ class GuiProjectView(QWidget):
class GuiProjectToolBar(QWidget):
- ADD_PLAIN = 0
- ADD_CHAP = 1
- ADD_SCENE = 2
- ADD_NOTE = 3
- ADD_FOLDER = 4
-
def __init__(self, projView):
QTreeWidget.__init__(self, projView)
@@ -181,6 +176,7 @@ class GuiProjectToolBar(QWidget):
self.mainConf = novelwriter.CONFIG
self.projView = projView
+ self.projTree = projView.projTree
self.theParent = projView.theParent
self.theProject = projView.theParent.theProject
self.theTheme = projView.theParent.theTheme
@@ -197,9 +193,9 @@ class GuiProjectToolBar(QWidget):
fadeCol = qPalette.text().color()
buttonStyle = (
- "QToolButton {{border: none; background: transparent;}} "
- "QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
- ).format(fadeCol.red(), fadeCol.green(), fadeCol.blue())
+ "QToolButton {{padding: {0}px; border: none; background: transparent;}} "
+ "QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}"
+ ).format(mPx, fadeCol.red(), fadeCol.green(), fadeCol.blue())
# Tree Label
self.projLabel = QLabel("%s" % self.tr("Project Content"))
@@ -212,39 +208,49 @@ class GuiProjectToolBar(QWidget):
self.tbMoveU.setIcon(self.theTheme.getIcon("up"))
self.tbMoveU.setIconSize(QSize(iPx, iPx))
self.tbMoveU.setStyleSheet(buttonStyle)
- self.tbMoveU.clicked.connect(lambda: self.projView.projTree.moveTreeItem(-1))
+ self.tbMoveU.clicked.connect(lambda: self.projTree.moveTreeItem(-1))
self.tbMoveD = QToolButton(self)
self.tbMoveD.setToolTip("%s [Ctrl+Down]" % self.tr("Move Down"))
self.tbMoveD.setIcon(self.theTheme.getIcon("down"))
self.tbMoveD.setIconSize(QSize(iPx, iPx))
self.tbMoveD.setStyleSheet(buttonStyle)
- self.tbMoveD.clicked.connect(lambda: self.projView.projTree.moveTreeItem(1))
+ self.tbMoveD.clicked.connect(lambda: self.projTree.moveTreeItem(1))
- # Items Menu
- self.mItems = QMenu()
+ # Add Item Menu
+ self.mAdd = QMenu()
- self.aAddEmpty = self.mItems.addAction(self.tr("Plain Document"))
+ self.aAddEmpty = self.mAdd.addAction(self.tr("Plain Document"))
self.aAddEmpty.setIcon(self.theTheme.getIcon("proj_document"))
- self.aAddEmpty.triggered.connect(lambda: self._forwardNewItem(self.ADD_PLAIN))
+ self.aAddEmpty.triggered.connect(
+ lambda: self.projTree.newTreeItem(nwItemType.FILE, hLevel=0, isNote=False)
+ )
- self.aAddChap = self.mItems.addAction(self.tr("Chapter Document"))
+ self.aAddChap = self.mAdd.addAction(self.tr("Chapter Document"))
self.aAddChap.setIcon(self.theTheme.getIcon("proj_chapter"))
- self.aAddChap.triggered.connect(lambda: self._forwardNewItem(self.ADD_CHAP))
+ self.aAddChap.triggered.connect(
+ lambda: self.projTree.newTreeItem(nwItemType.FILE, hLevel=2, isNote=False)
+ )
- self.aAddScene = self.mItems.addAction(self.tr("Scene Document"))
+ self.aAddScene = self.mAdd.addAction(self.tr("Scene Document"))
self.aAddScene.setIcon(self.theTheme.getIcon("proj_scene"))
- self.aAddScene.triggered.connect(lambda: self._forwardNewItem(self.ADD_SCENE))
+ self.aAddScene.triggered.connect(
+ lambda: self.projTree.newTreeItem(nwItemType.FILE, hLevel=3, isNote=False)
+ )
- self.aAddNote = self.mItems.addAction(self.tr("Project Note"))
+ self.aAddNote = self.mAdd.addAction(self.tr("Project Note"))
self.aAddNote.setIcon(self.theTheme.getIcon("proj_note"))
- self.aAddNote.triggered.connect(lambda: self._forwardNewItem(self.ADD_NOTE))
+ self.aAddNote.triggered.connect(
+ lambda: self.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True)
+ )
- self.aAddFolder = self.mItems.addAction(self.tr("Folder"))
+ self.aAddFolder = self.mAdd.addAction(self.tr("Folder"))
self.aAddFolder.setIcon(self.theTheme.getIcon("proj_folder"))
- self.aAddFolder.triggered.connect(lambda: self._forwardNewItem(self.ADD_FOLDER))
+ self.aAddFolder.triggered.connect(
+ lambda: self.projTree.newTreeItem(nwItemType.FOLDER)
+ )
- self.mAddRoot = self.mItems.addMenu(self.tr("Root Folder"))
+ self.mAddRoot = self.mAdd.addMenu(self.tr("Root Folder"))
self._addRootFolderEntry(nwItemClass.NOVEL)
self._addRootFolderEntry(nwItemClass.ARCHIVE)
self.mAddRoot.addSeparator()
@@ -256,31 +262,38 @@ class GuiProjectToolBar(QWidget):
self._addRootFolderEntry(nwItemClass.ENTITY)
self._addRootFolderEntry(nwItemClass.CUSTOM)
- self.tbItems = QToolButton(self)
- self.tbItems.setToolTip("%s [Ctrl+N]" % self.tr("Add Item"))
- self.tbItems.setShortcut("Ctrl+N")
- self.tbItems.setIcon(self.theTheme.getIcon("add"))
- self.tbItems.setIconSize(QSize(iPx, iPx))
- self.tbItems.setStyleSheet(buttonStyle)
- self.tbItems.setMenu(self.mItems)
- self.tbItems.setPopupMode(QToolButton.InstantPopup)
+ self.tbAdd = QToolButton(self)
+ self.tbAdd.setToolTip("%s [Ctrl+N]" % self.tr("Add Item"))
+ self.tbAdd.setShortcut("Ctrl+N")
+ self.tbAdd.setIcon(self.theTheme.getIcon("add"))
+ self.tbAdd.setIconSize(QSize(iPx, iPx))
+ self.tbAdd.setStyleSheet(buttonStyle)
+ self.tbAdd.setMenu(self.mAdd)
+ self.tbAdd.setPopupMode(QToolButton.InstantPopup)
- # Settings Menu
- self.tbSettings = QToolButton(self)
- self.tbSettings.setIcon(self.theTheme.getIcon("menu"))
- self.tbSettings.setIconSize(QSize(iPx, iPx))
- self.tbSettings.setStyleSheet(buttonStyle)
- self.tbSettings.setPopupMode(QToolButton.InstantPopup)
+ # More Options Menu
+ self.mMore = QMenu()
+
+ self.aMoreUndo = self.mMore.addAction(self.tr("Undo Move"))
+ self.aMoreUndo.triggered.connect(lambda: self.projTree.undoLastMove())
+
+ self.tbMore = QToolButton(self)
+ self.tbMore.setToolTip(self.tr("More Options"))
+ self.tbMore.setIcon(self.theTheme.getIcon("menu"))
+ self.tbMore.setIconSize(QSize(iPx, iPx))
+ self.tbMore.setStyleSheet(buttonStyle)
+ self.tbMore.setMenu(self.mMore)
+ self.tbMore.setPopupMode(QToolButton.InstantPopup)
# Assemble
self.outerBox = QHBoxLayout()
self.outerBox.addWidget(self.projLabel)
self.outerBox.addWidget(self.tbMoveU)
self.outerBox.addWidget(self.tbMoveD)
- self.outerBox.addWidget(self.tbItems)
- self.outerBox.addWidget(self.tbSettings)
+ self.outerBox.addWidget(self.tbAdd)
+ self.outerBox.addWidget(self.tbMore)
self.outerBox.setContentsMargins(mPx, mPx, 0, mPx)
- self.outerBox.setSpacing(mPx)
+ self.outerBox.setSpacing(0)
self.setLayout(self.outerBox)
@@ -288,33 +301,6 @@ class GuiProjectToolBar(QWidget):
return
- ##
- # Private Slots
- ##
-
- @pyqtSlot(Enum)
- def _forwardNewRootFolder(self, itemClass):
- """Forward the request for a new root folder to the tree.
- """
- self.projView.projTree.newTreeItem(nwItemType.ROOT, itemClass)
- return
-
- @pyqtSlot(int)
- def _forwardNewItem(self, type):
- """Forward the request for a new item of a given type.
- """
- if type == self.ADD_PLAIN:
- self.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=0, isNote=False)
- elif type == self.ADD_CHAP:
- self.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=2, isNote=False)
- elif type == self.ADD_SCENE:
- self.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=3, isNote=False)
- elif type == self.ADD_NOTE:
- self.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True)
- elif type == self.ADD_FOLDER:
- self.projView.projTree.newTreeItem(nwItemType.FOLDER)
- return
-
##
# Internal Functions
##
@@ -324,7 +310,7 @@ class GuiProjectToolBar(QWidget):
"""
aNew = self.mAddRoot.addAction(trConst(nwLabels.CLASS_NAME[itemClass]))
aNew.setIcon(self.theTheme.getIcon(nwLabels.CLASS_ICON[itemClass]))
- aNew.triggered.connect(lambda: self._forwardNewRootFolder(itemClass))
+ aNew.triggered.connect(lambda: self.projTree.newTreeItem(nwItemType.ROOT, itemClass))
self.mAddRoot.addAction(aNew)
# END Class GuiProjectToolBar
@@ -886,9 +872,6 @@ class GuiProjectTree(QTreeWidget):
dstItem = self._lastMove.get("parent", None)
dstIndex = self._lastMove.get("index", None)
- if not self.projView.anyFocus():
- return False
-
if srcItem is None or dstItem is None or dstIndex is None:
logger.verbose("No tree move to undo")
return False
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index 6085c59b..ab3a1141 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -461,7 +461,7 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
qtbot.wait(stepDelay)
# Check a Quick Create and Delete
- assert nwGUI.treeView.newTreeItem(nwItemType.FILE, None)
+ assert nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None)
newHandle = nwGUI.treeView.getSelectedHandle()
assert nwGUI.theProject.tree["0000000000020"] is not None
assert nwGUI.treeView.deleteItem()
diff --git a/tests/test_gui/test_gui_projtree.py b/tests/test_gui/test_gui_projtree.py
index c0189a66..fa904d34 100644
--- a/tests/test_gui/test_gui_projtree.py
+++ b/tests/test_gui/test_gui_projtree.py
@@ -24,7 +24,7 @@ import os
from tools import buildTestProject
-from PyQt5.QtWidgets import QAction, QMessageBox, QInputDialog
+from PyQt5.QtWidgets import QMessageBox, QInputDialog
from novelwriter.gui.projtree import GuiProjectView, GuiProjectTree
from novelwriter.enum import nwItemType, nwItemClass
@@ -44,7 +44,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
nwTree = nwGUI.treeView
# Try to add item with no project
- assert nwTree.newTreeItem(nwItemType.FILE) is False
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is False
# Create a project
prjDir = os.path.join(fncDir, "project")
@@ -52,16 +52,16 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
# No itemType set
nwTree.projTree.clearSelection()
- assert nwTree.newTreeItem(None) is False
+ assert nwTree.projTree.newTreeItem(None) is False
# Root Items
# ==========
# No class set
- assert nwTree.newTreeItem(nwItemType.ROOT) is False
+ assert nwTree.projTree.newTreeItem(nwItemType.ROOT) is False
# Create root item
- assert nwTree.newTreeItem(nwItemType.ROOT, nwItemClass.WORLD) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.ROOT, nwItemClass.WORLD) is True
assert "0000000000010" in nwGUI.theProject.tree
# File/Folder Items
@@ -70,27 +70,27 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
# No location selected for new item
nwTree.projTree.clearSelection()
caplog.clear()
- assert nwTree.newTreeItem(nwItemType.FILE) is False
- assert nwTree.newTreeItem(nwItemType.FOLDER) is False
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is False
+ assert nwTree.projTree.newTreeItem(nwItemType.FOLDER) is False
assert "Did not find anywhere" in caplog.text
# Create new folder as child of Novel folder
nwTree.setSelectedHandle("0000000000008")
- assert nwTree.newTreeItem(nwItemType.FOLDER) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FOLDER) is True
assert nwGUI.theProject.tree["0000000000011"].itemParent == "0000000000008"
assert nwGUI.theProject.tree["0000000000011"].itemRoot == "0000000000008"
assert nwGUI.theProject.tree["0000000000011"].itemClass == nwItemClass.NOVEL
# Add a new file in the new folder
nwTree.setSelectedHandle("0000000000011")
- assert nwTree.newTreeItem(nwItemType.FILE) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is True
assert nwGUI.theProject.tree["0000000000012"].itemParent == "0000000000011"
assert nwGUI.theProject.tree["0000000000012"].itemRoot == "0000000000008"
assert nwGUI.theProject.tree["0000000000012"].itemClass == nwItemClass.NOVEL
# Add a new chapter next to the other new file
nwTree.setSelectedHandle("0000000000012")
- assert nwTree.newTreeItem(nwItemType.FILE, hLevel=2) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE, hLevel=2) is True
assert nwGUI.theProject.tree["0000000000013"].itemParent == "0000000000011"
assert nwGUI.theProject.tree["0000000000013"].itemRoot == "0000000000008"
assert nwGUI.theProject.tree["0000000000013"].itemClass == nwItemClass.NOVEL
@@ -99,7 +99,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
# Add a new scene next to the other new file
nwTree.setSelectedHandle("0000000000012")
- assert nwTree.newTreeItem(nwItemType.FILE, hLevel=3) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE, hLevel=3) is True
assert nwGUI.theProject.tree["0000000000014"].itemParent == "0000000000011"
assert nwGUI.theProject.tree["0000000000014"].itemRoot == "0000000000008"
assert nwGUI.theProject.tree["0000000000014"].itemClass == nwItemClass.NOVEL
@@ -108,7 +108,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
# Add a new file to the characters folder
nwTree.setSelectedHandle("000000000000a")
- assert nwTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True) is True
assert nwGUI.theProject.tree["0000000000015"].itemParent == "000000000000a"
assert nwGUI.theProject.tree["0000000000015"].itemRoot == "000000000000a"
assert nwGUI.theProject.tree["0000000000015"].itemClass == nwItemClass.CHARACTER
@@ -119,7 +119,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
nwTree.setSelectedHandle("0000000000013")
nwGUI.theProject.tree["0000000000013"].setParent(None) # This should not happen
caplog.clear()
- assert nwTree.newTreeItem(nwItemType.FILE) is False
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is False
assert "Internal error" in caplog.text
nwGUI.theProject.tree["0000000000013"].setParent("0000000000011")
@@ -127,13 +127,13 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
with monkeypatch.context() as mp:
mp.setattr(QInputDialog, "getText", lambda *a, **k: ("", False))
nwTree.setSelectedHandle("0000000000013")
- assert nwTree.newTreeItem(nwItemType.FILE) is False
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is False
# Get the trash folder
nwTree.projTree._addTrashRoot()
trashHandle = nwGUI.theProject.trashFolder()
nwTree.setSelectedHandle(trashHandle)
- assert nwTree.newTreeItem(nwItemType.FILE) is False
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is False
assert "Cannot add new files or folders to the Trash folder" in caplog.text
# Other Checks
@@ -179,9 +179,9 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
# Add some files
nwTree.setSelectedHandle("000000000000d")
- assert nwTree.newTreeItem(nwItemType.FILE) is True
- assert nwTree.newTreeItem(nwItemType.FILE) is True
- assert nwTree.newTreeItem(nwItemType.FILE) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is True
assert nwTree.getTreeFromHandle("000000000000d") == [
"000000000000d", "000000000000e", "000000000000f",
"0000000000010", "0000000000011", "0000000000012",
@@ -238,7 +238,7 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
"000000000000d", "000000000000e", "000000000000f",
"0000000000010", "0000000000012", "0000000000011",
]
- nwGUI.mainMenu.aMoveUndo.activate(QAction.Trigger)
+ assert nwTree.projTree.undoLastMove() is True
assert nwTree.getTreeFromHandle("000000000000d") == [
"000000000000d", "000000000000e", "000000000000f",
"0000000000010", "0000000000011", "0000000000012",
@@ -295,9 +295,9 @@ def testGuiProjTree_DeleteItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
# Add some files
nwTree.setSelectedHandle("000000000000d")
- assert nwTree.newTreeItem(nwItemType.FILE) is True
- assert nwTree.newTreeItem(nwItemType.FILE) is True
- assert nwTree.newTreeItem(nwItemType.FILE) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is True
assert nwTree.getTreeFromHandle("000000000000d") == [
"000000000000d", "000000000000e", "000000000000f",
"0000000000010", "0000000000011", "0000000000012",
@@ -379,10 +379,10 @@ def testGuiProjTree_DeleteItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
# Add a folder with two files
nwTree.setSelectedHandle("0000000000009")
- assert nwTree.newTreeItem(nwItemType.FOLDER) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FOLDER) is True
nwTree.setSelectedHandle("0000000000014")
- assert nwTree.newTreeItem(nwItemType.FILE) is True
- assert nwTree.newTreeItem(nwItemType.FILE) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FILE) is True
assert os.path.isfile(os.path.join(fncDir, "project", "content", "0000000000015.nwd"))
assert os.path.isfile(os.path.join(fncDir, "project", "content", "0000000000016.nwd"))
@@ -405,7 +405,7 @@ def testGuiProjTree_DeleteItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
# Add an empty folder, which can be deleted with no further restrictions
nwTree.setSelectedHandle("0000000000009")
- assert nwTree.newTreeItem(nwItemType.FOLDER) is True
+ assert nwTree.projTree.newTreeItem(nwItemType.FOLDER) is True
assert nwTree.getTreeFromHandle("0000000000009") == ["0000000000009", "0000000000017"]
nwTree.setSelectedHandle("0000000000017")
From 77746f712f4dc35623b572c05062823de6d67dd7 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 11 Jun 2022 12:33:37 +0200
Subject: [PATCH 11/35] Fix inconsistend expand/collapse when tree items are
moved
---
novelwriter/gui/projtree.py | 33 +++++++++++++----------------
tests/test_gui/test_gui_projtree.py | 3 +--
2 files changed, 16 insertions(+), 20 deletions(-)
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index 6ad4d501..dc52ffc2 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -35,9 +35,9 @@ from time import time
from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QIcon, QPalette
from PyQt5.QtWidgets import (
- qApp, QTreeWidget, QTreeWidgetItem, QAbstractItemView, QMenu, QAction,
- QFrame, QDialog, QHeaderView, QWidget, QVBoxLayout, QLabel, QToolButton,
- QSizePolicy, QInputDialog, QHBoxLayout, QShortcut
+ QAbstractItemView, QAction, QDialog, QFrame, QHBoxLayout, QHeaderView,
+ QInputDialog, QLabel, QMenu, QShortcut, QSizePolicy, QToolButton,
+ QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
)
from novelwriter.core import NWDoc
@@ -143,15 +143,6 @@ class GuiProjectView(QWidget):
"""
return self.projTree.hasFocus()
- def anyFocus(self):
- """Check if any widget or child widget has focus.
- """
- if self.hasFocus():
- return True
- if self.isAncestorOf(qApp.focusWidget()):
- return True
- return False
-
##
# Public Slots
##
@@ -536,34 +527,40 @@ class GuiProjectTree(QTreeWidget):
"""Move an item up or down in the tree.
"""
tHandle = self.getSelectedHandle()
- tItem = self._getTreeItem(tHandle)
- if tItem is None:
+ trItem = self._getTreeItem(tHandle)
+ if trItem is None:
logger.verbose("No item selected")
return False
- pItem = tItem.parent()
+ pItem = trItem.parent()
+ isExp = trItem.isExpanded()
if pItem is None:
- tIndex = self.indexOfTopLevelItem(tItem)
+ tIndex = self.indexOfTopLevelItem(trItem)
nChild = self.topLevelItemCount()
+
nIndex = tIndex + nStep
if nIndex < 0 or nIndex >= nChild:
return False
+
cItem = self.takeTopLevelItem(tIndex)
self.insertTopLevelItem(nIndex, cItem)
else:
- tIndex = pItem.indexOfChild(tItem)
+ tIndex = pItem.indexOfChild(trItem)
nChild = pItem.childCount()
+
nIndex = tIndex + nStep
if nIndex < 0 or nIndex >= nChild:
return False
+
cItem = pItem.takeChild(tIndex)
pItem.insertChild(nIndex, cItem)
self._recordLastMove(cItem, pItem, tIndex)
self._alertTreeChange(tHandle=tHandle, flush=True)
self.clearSelection()
- cItem.setSelected(True)
+ trItem.setSelected(True)
+ trItem.setExpanded(isExp)
return True
diff --git a/tests/test_gui/test_gui_projtree.py b/tests/test_gui/test_gui_projtree.py
index fa904d34..ee1a1105 100644
--- a/tests/test_gui/test_gui_projtree.py
+++ b/tests/test_gui/test_gui_projtree.py
@@ -26,7 +26,7 @@ from tools import buildTestProject
from PyQt5.QtWidgets import QMessageBox, QInputDialog
-from novelwriter.gui.projtree import GuiProjectView, GuiProjectTree
+from novelwriter.gui.projtree import GuiProjectTree
from novelwriter.enum import nwItemType, nwItemClass
@@ -163,7 +163,6 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
- monkeypatch.setattr(GuiProjectView, "anyFocus", lambda *a: True)
nwTree = nwGUI.treeView
From f0bef18b63911c6139165aaf1586e9be2ac78b43 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 11 Jun 2022 13:44:45 +0200
Subject: [PATCH 12/35] Re-implement the tree context menu
---
novelwriter/gui/projtree.py | 277 +++++++++++++++++++-----------------
sample/nwProject.nwx | 24 ++--
2 files changed, 158 insertions(+), 143 deletions(-)
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index dc52ffc2..65614e05 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -5,7 +5,6 @@ GUI classes for the main window project tree
File History:
Created: 2018-09-29 [0.0.1] GuiProjectTree
-Created: 2020-06-04 [0.7] GuiProjectTreeMenu
Created: 2022-06-06 [1.7b1] GuiProjectView
Created: 2022-06-06 [1.7b1] GuiProjectToolBar
@@ -35,9 +34,9 @@ from time import time
from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QIcon, QPalette
from PyQt5.QtWidgets import (
- QAbstractItemView, QAction, QDialog, QFrame, QHBoxLayout, QHeaderView,
- QInputDialog, QLabel, QMenu, QShortcut, QSizePolicy, QToolButton,
- QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
+ QAbstractItemView, QDialog, QFrame, QHBoxLayout, QHeaderView, QInputDialog,
+ QLabel, QMenu, QShortcut, QSizePolicy, QToolButton, QTreeWidget,
+ QTreeWidgetItem, QVBoxLayout, QWidget
)
from novelwriter.core import NWDoc
@@ -211,37 +210,37 @@ class GuiProjectToolBar(QWidget):
# Add Item Menu
self.mAdd = QMenu()
- self.aAddEmpty = self.mAdd.addAction(self.tr("Plain Document"))
+ self.aAddEmpty = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["document"]))
self.aAddEmpty.setIcon(self.theTheme.getIcon("proj_document"))
self.aAddEmpty.triggered.connect(
lambda: self.projTree.newTreeItem(nwItemType.FILE, hLevel=0, isNote=False)
)
- self.aAddChap = self.mAdd.addAction(self.tr("Chapter Document"))
+ self.aAddChap = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["doc_h2"]))
self.aAddChap.setIcon(self.theTheme.getIcon("proj_chapter"))
self.aAddChap.triggered.connect(
lambda: self.projTree.newTreeItem(nwItemType.FILE, hLevel=2, isNote=False)
)
- self.aAddScene = self.mAdd.addAction(self.tr("Scene Document"))
+ self.aAddScene = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["doc_h3"]))
self.aAddScene.setIcon(self.theTheme.getIcon("proj_scene"))
self.aAddScene.triggered.connect(
lambda: self.projTree.newTreeItem(nwItemType.FILE, hLevel=3, isNote=False)
)
- self.aAddNote = self.mAdd.addAction(self.tr("Project Note"))
+ self.aAddNote = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["note"]))
self.aAddNote.setIcon(self.theTheme.getIcon("proj_note"))
self.aAddNote.triggered.connect(
lambda: self.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True)
)
- self.aAddFolder = self.mAdd.addAction(self.tr("Folder"))
+ self.aAddFolder = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["folder"]))
self.aAddFolder.setIcon(self.theTheme.getIcon("proj_folder"))
self.aAddFolder.triggered.connect(
lambda: self.projTree.newTreeItem(nwItemType.FOLDER)
)
- self.mAddRoot = self.mAdd.addMenu(self.tr("Root Folder"))
+ self.mAddRoot = self.mAdd.addMenu(trConst(nwLabels.ITEM_DESCRIPTION["root"]))
self._addRootFolderEntry(nwItemClass.NOVEL)
self._addRootFolderEntry(nwItemClass.ARCHIVE)
self.mAddRoot.addSeparator()
@@ -268,6 +267,9 @@ class GuiProjectToolBar(QWidget):
self.aMoreUndo = self.mMore.addAction(self.tr("Undo Move"))
self.aMoreUndo.triggered.connect(lambda: self.projTree.undoLastMove())
+ self.aEmptyTrash = self.mMore.addAction(self.tr("Empty Trash"))
+ self.aEmptyTrash.triggered.connect(lambda: self.projTree.emptyTrash())
+
self.tbMore = QToolButton(self)
self.tbMore.setToolTip(self.tr("More Options"))
self.tbMore.setIcon(self.theTheme.getIcon("menu"))
@@ -335,9 +337,8 @@ class GuiProjectTree(QTreeWidget):
##
# Context Menu
- self.ctxMenu = GuiProjectTreeMenu(self)
self.setContextMenuPolicy(Qt.CustomContextMenu)
- self.customContextMenuRequested.connect(self._rightClickMenu)
+ self.customContextMenuRequested.connect(self._openContextMenu)
# Tree Settings
iPx = self.theTheme.baseIconSize
@@ -972,19 +973,106 @@ class GuiProjectTree(QTreeWidget):
return
@pyqtSlot("QPoint")
- def _rightClickMenu(self, clickPos):
+ def _openContextMenu(self, clickPos):
"""The user right clicked an element in the project tree, so we
open a context menu in-place.
"""
+ tItem = None
selItem = self.itemAt(clickPos)
if isinstance(selItem, QTreeWidgetItem):
tHandle = selItem.data(self.C_NAME, Qt.UserRole)
- self.setSelectedHandle(tHandle) # Just to be safe
tItem = self.theProject.tree[tHandle]
- if tItem is not None:
- if self.ctxMenu.filterActions(tItem):
- # Only open menu if any actions remain after filter
- self.ctxMenu.exec_(self.viewport().mapToGlobal(clickPos))
+
+ if tItem is None:
+ logger.debug("No item found")
+
+ ctxMenu = QMenu()
+
+ # Trash Folder
+ # ============
+
+ trashHandle = self.theProject.tree.trashRoot()
+ if tItem.itemHandle == trashHandle and trashHandle is not None:
+ # The trash folder only has one option
+ ctxMenu.addAction(
+ self.tr("Empty Trash"), lambda: self.emptyTrash()
+ )
+ ctxMenu.exec_(self.viewport().mapToGlobal(clickPos))
+ return
+
+ # Document Actions
+ # ================
+
+ isFile = tItem.itemType == nwItemType.FILE
+ if isFile:
+ ctxMenu.addAction(
+ self.tr("Open Document"),
+ lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT)
+ )
+ ctxMenu.addAction(
+ self.tr("View Document"),
+ lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW)
+ )
+ ctxMenu.addSeparator()
+
+ # Edit Item Settings
+ # ==================
+
+ if isFile:
+ ctxMenu.addAction(
+ self.tr("Toggle Exported"), lambda: self._toggleItemExported(tHandle)
+ )
+
+ if tItem.isNovelLike():
+ mStatus = ctxMenu.addMenu(self.tr("Change Status"))
+ for n, (key, entry) in enumerate(self.theProject.statusItems.items()):
+ aStatus = mStatus.addAction(entry["icon"], entry["name"])
+ aStatus.triggered.connect(
+ lambda n, key=key: self._changeItemStatus(tHandle, key)
+ )
+ else:
+ mImport = ctxMenu.addMenu(self.tr("Change Importance"))
+ for n, (key, entry) in enumerate(self.theProject.importItems.items()):
+ aImport = mImport.addAction(entry["icon"], entry["name"])
+ aImport.triggered.connect(
+ lambda n, key=key: self._changeItemImport(tHandle, key)
+ )
+
+ if isFile and tItem.documentAllowed():
+ if tItem.itemLayout == nwItemLayout.NOTE:
+ ctxMenu.addAction(
+ self.tr("Change to {0}").format(
+ trConst(nwLabels.LAYOUT_NAME[nwItemLayout.DOCUMENT])
+ ),
+ lambda: self._changeItemLayout(tHandle, nwItemLayout.DOCUMENT)
+ )
+ else:
+ ctxMenu.addAction(
+ self.tr("Change to {0}").format(
+ trConst(nwLabels.LAYOUT_NAME[nwItemLayout.NOTE])
+ ),
+ lambda: self._changeItemLayout(tHandle, nwItemLayout.NOTE)
+ )
+
+ ctxMenu.addSeparator()
+
+ # Major Item Actions
+ # ==================
+
+ ctxMenu.addAction(
+ self.tr("Edit Item Settings"), lambda: self.editTreeItem(tHandle)
+ )
+
+ if tItem.itemClass == nwItemClass.TRASH or tItem.itemType == nwItemType.ROOT:
+ ctxMenu.addAction(
+ self.tr("Delete Permanently"), lambda: self.deleteItem(tHandle)
+ )
+ else:
+ ctxMenu.addAction(
+ self.tr("Move to Trash"), lambda: self.deleteItem(tHandle)
+ )
+
+ ctxMenu.exec_(self.viewport().mapToGlobal(clickPos))
return
@@ -1121,6 +1209,46 @@ class GuiProjectTree(QTreeWidget):
return True
+ def _toggleItemExported(self, tHandle):
+ """Toggle the exported status of an item.
+ """
+ tItem = self.theProject.tree[tHandle]
+ if tItem is not None:
+ tItem.setExported(not tItem.isExported)
+ self.setTreeItemValues(tItem.itemHandle)
+ return
+
+ def _changeItemStatus(self, tHandle, tStatus):
+ """Set a new status value of an item.
+ """
+ tItem = self.theProject.tree[tHandle]
+ if tItem is not None:
+ tItem.setStatus(tStatus)
+ self.setTreeItemValues(tItem.itemHandle)
+ return
+
+ def _changeItemImport(self, tHandle, tImport):
+ """Set a new importance value of an item.
+ """
+ tItem = self.theProject.tree[tHandle]
+ if tItem is not None:
+ tItem.setImport(tImport)
+ self.setTreeItemValues(tItem.itemHandle)
+ return
+
+ def _changeItemLayout(self, tHandle, itemLayout):
+ """Set a new item layout value of an item.
+ """
+ tItem = self.theProject.tree[tHandle]
+ if tItem is not None:
+ if itemLayout == nwItemLayout.DOCUMENT and tItem.documentAllowed():
+ tItem.setLayout(nwItemLayout.DOCUMENT)
+ self.setTreeItemValues(tItem.itemHandle)
+ elif itemLayout == nwItemLayout.NOTE:
+ tItem.setLayout(nwItemLayout.NOTE)
+ self.setTreeItemValues(tItem.itemHandle)
+ return
+
def _scanChildren(self, theList, tItem, tIndex):
"""This is a recursive function returning all items in a tree
starting at a given QTreeWidgetItem.
@@ -1244,116 +1372,3 @@ class GuiProjectTree(QTreeWidget):
return
# END Class GuiProjectTree
-
-
-class GuiProjectTreeMenu(QMenu):
-
- def __init__(self, theTree):
- QMenu.__init__(self, theTree)
-
- self.theTree = theTree
- self.theItem = None
-
- self.editItem = QAction(self.tr("Edit Project Item"), self)
- self.editItem.triggered.connect(self._doEditItem)
- self.addAction(self.editItem)
-
- self.openItem = QAction(self.tr("Open Document"), self)
- self.openItem.triggered.connect(self._doOpenItem)
- self.addAction(self.openItem)
-
- self.viewItem = QAction(self.tr("View Document"), self)
- self.viewItem.triggered.connect(self._doViewItem)
- self.addAction(self.viewItem)
-
- self.toggleExp = QAction(self.tr("Toggle Included Flag"), self)
- self.toggleExp.triggered.connect(self._doToggleExported)
- self.addAction(self.toggleExp)
-
- self.deleteItem = QAction(self.tr("Delete Item"), self)
- self.deleteItem.triggered.connect(self._doDeleteItem)
- self.addAction(self.deleteItem)
-
- self.emptyTrash = QAction(self.tr("Empty Trash"), self)
- self.emptyTrash.triggered.connect(self._doEmptyTrash)
- self.addAction(self.emptyTrash)
-
- return
-
- def filterActions(self, theItem):
- """Filter the menu entries available based on the properties of
- the item the menu was activated on.
- """
- self.theItem = theItem
-
- if theItem is None:
- logger.error("Failed to extract information to build tree context menu")
- return False
-
- trashHandle = self.theTree.theProject.tree.trashRoot()
-
- isTrash = theItem.itemHandle == trashHandle and trashHandle is not None
- isFile = theItem.itemType == nwItemType.FILE
-
- self.editItem.setVisible(not isTrash)
- self.openItem.setVisible(isFile)
- self.viewItem.setVisible(isFile)
- self.toggleExp.setVisible(isFile)
- self.deleteItem.setVisible(not isTrash)
- self.emptyTrash.setVisible(isTrash)
-
- return True
-
- ##
- # Slots
- ##
-
- @pyqtSlot()
- def _doOpenItem(self):
- """Forward the open document call to the main GUI window.
- """
- if self.theItem is not None:
- self.theTree.theParent.openDocument(self.theItem.itemHandle, doScroll=False)
- return
-
- @pyqtSlot()
- def _doViewItem(self):
- """Forward the view document call to the main GUI window.
- """
- if self.theItem is not None:
- self.theTree.theParent.viewDocument(self.theItem.itemHandle)
- return
-
- @pyqtSlot()
- def _doEditItem(self):
- """Forward the edit item call to the main GUI window.
- """
- if self.theItem is not None:
- self.theTree.theParent.editItem()
- return
-
- @pyqtSlot()
- def _doToggleExported(self):
- """Flip the isExported flag of the current item.
- """
- if self.theItem is not None:
- self.theItem.setExported(not self.theItem.isExported)
- self.theTree.setTreeItemValues(self.theItem.itemHandle)
- return
-
- @pyqtSlot()
- def _doDeleteItem(self):
- """Forward the delete item call to the project tree.
- """
- if self.theItem is not None:
- self.theTree.deleteItem()
- return
-
- @pyqtSlot()
- def _doEmptyTrash(self):
- """Forward the empty trash call to the project tree.
- """
- self.theTree.emptyTrash()
- return
-
-# END Class GuiProjectTreeMenu
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index 4dd6396a..e8ee5c59 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,13 +1,13 @@
-
+
Sample Project
Sample Project
Jane Smith
Jay Doh
- 1342
- 227
- 68090
+ 1345
+ 229
+ 68286
False
@@ -33,13 +33,13 @@
- New
- Notes
+ New
+ Notes
Started
- 1st Draft
- 2nd Draft
+ 1st Draft
+ 2nd Draft
3rd Draft
- Finished
+ Finished
None
@@ -63,7 +63,7 @@
-
- Part One
+ Part One
-
@@ -79,11 +79,11 @@
-
- Interlude
+ Interlude
-
- A Note on Structure
+ A Note on Structure
-
From 025463a28e0b65404002a9244d0c52f3526e19a3 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 11 Jun 2022 14:40:03 +0200
Subject: [PATCH 13/35] Improve project tree test coverage
---
novelwriter/gui/projtree.py | 5 +-
tests/test_gui/test_gui_projtree.py | 90 ++++++++++++++++++++++++++++-
2 files changed, 91 insertions(+), 4 deletions(-)
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index 65614e05..372a2d84 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -985,6 +985,7 @@ class GuiProjectTree(QTreeWidget):
if tItem is None:
logger.debug("No item found")
+ return False
ctxMenu = QMenu()
@@ -998,7 +999,7 @@ class GuiProjectTree(QTreeWidget):
self.tr("Empty Trash"), lambda: self.emptyTrash()
)
ctxMenu.exec_(self.viewport().mapToGlobal(clickPos))
- return
+ return True
# Document Actions
# ================
@@ -1074,7 +1075,7 @@ class GuiProjectTree(QTreeWidget):
ctxMenu.exec_(self.viewport().mapToGlobal(clickPos))
- return
+ return True
##
# Events
diff --git a/tests/test_gui/test_gui_projtree.py b/tests/test_gui/test_gui_projtree.py
index ee1a1105..7b6d2f42 100644
--- a/tests/test_gui/test_gui_projtree.py
+++ b/tests/test_gui/test_gui_projtree.py
@@ -24,10 +24,10 @@ import os
from tools import buildTestProject
-from PyQt5.QtWidgets import QMessageBox, QInputDialog
+from PyQt5.QtWidgets import QMessageBox, QInputDialog, QMenu
from novelwriter.gui.projtree import GuiProjectTree
-from novelwriter.enum import nwItemType, nwItemClass
+from novelwriter.enum import nwItemLayout, nwItemType, nwItemClass
@pytest.mark.gui
@@ -454,3 +454,89 @@ def testGuiProjTree_DeleteItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
nwGUI.closeProject()
# END Test testGuiProjTree_DeleteItems
+
+
+@pytest.mark.gui
+def testGuiProjTree_ContextMenu(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd):
+ """Test the building of the project tree context menu. All this does
+ is test that the menu builds. It doesn't open the actual menu,
+ """
+ # Block message box
+ monkeypatch.setattr(QMessageBox, "warning", lambda *a: QMessageBox.Yes)
+ monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)
+ monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
+ monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
+ monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
+ monkeypatch.setattr(QMenu, "exec_", lambda *a: None)
+
+ # Create a project
+ prjDir = os.path.join(fncDir, "project")
+ buildTestProject(nwGUI, prjDir)
+
+ # Handles for new objects
+ hNovelRoot = "0000000000008"
+ hTitlePage = "000000000000c"
+ hChapterDir = "000000000000d"
+ hChapterFile = "000000000000e"
+ hCharRoot = "000000000000a"
+ hCharNote = "0000000000011"
+ hNovelNote = "0000000000012"
+
+ projTree = nwGUI.treeView.projTree
+ projTree._getTreeItem(hNovelRoot).setExpanded(True)
+ projTree._getTreeItem(hChapterDir).setExpanded(True)
+
+ projTree._addTrashRoot()
+ hTrashRoot = projTree.theProject.tree.trashRoot()
+
+ projTree.setSelectedHandle(hCharRoot)
+ projTree.newTreeItem(nwItemType.FILE)
+ projTree.setSelectedHandle(hNovelRoot)
+ projTree.newTreeItem(nwItemType.FILE, isNote=True)
+
+ def itemPos(tHandle):
+ return projTree.visualItemRect(projTree._getTreeItem(tHandle)).center()
+
+ # No item under menu
+ assert projTree._openContextMenu(projTree.viewport().rect().bottomRight()) is False
+
+ # Generate the possible menu combinarions
+ assert projTree._openContextMenu(itemPos(hTrashRoot)) is True
+ assert projTree._openContextMenu(itemPos(hNovelRoot)) is True
+ assert projTree._openContextMenu(itemPos(hNovelNote)) is True
+ assert projTree._openContextMenu(itemPos(hTitlePage)) is True
+ assert projTree._openContextMenu(itemPos(hChapterDir)) is True
+ assert projTree._openContextMenu(itemPos(hChapterFile)) is True
+ assert projTree._openContextMenu(itemPos(hCharRoot)) is True
+ assert projTree._openContextMenu(itemPos(hCharNote)) is True
+
+ # Direct Edit Functions
+ # =====================
+ # Trigger the dedicated functions the menu entries connect to
+ nwItem = projTree.theProject.tree[hNovelNote]
+
+ # Toggle exported flag
+ assert nwItem.isExported is True
+ projTree._toggleItemExported(hNovelNote)
+ assert nwItem.isExported is False
+
+ # Change item status
+ assert nwItem.itemStatus == "s000000"
+ projTree._changeItemStatus(hNovelNote, "s000001")
+ assert nwItem.itemStatus == "s000001"
+
+ # Change item importance
+ assert nwItem.itemImport == "i000004"
+ projTree._changeItemImport(hNovelNote, "i000005")
+ assert nwItem.itemImport == "i000005"
+
+ # Change item layout
+ assert nwItem.itemLayout == nwItemLayout.NOTE
+ projTree._changeItemLayout(hNovelNote, nwItemLayout.DOCUMENT)
+ assert nwItem.itemLayout == nwItemLayout.DOCUMENT
+ projTree._changeItemLayout(hNovelNote, nwItemLayout.NOTE)
+ assert nwItem.itemLayout == nwItemLayout.NOTE
+
+ # qtbot.stop()
+
+# END Test testGuiProjTree_ContextMenu
From 0181bebd7085905392184984c8b54f196cfd43c8 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 11 Jun 2022 15:33:32 +0200
Subject: [PATCH 14/35] Rename ambiguous theParent variable to mainGui
---
novelwriter/core/project.py | 78 ++++++++++-----------
novelwriter/core/tokenizer.py | 1 -
novelwriter/dialogs/about.py | 22 +++---
novelwriter/dialogs/docmerge.py | 30 ++++----
novelwriter/dialogs/docsplit.py | 30 ++++----
novelwriter/dialogs/itemeditor.py | 8 +--
novelwriter/dialogs/preferences.py | 98 +++++++++++++-------------
novelwriter/dialogs/projdetails.py | 28 ++++----
novelwriter/dialogs/projload.py | 14 ++--
novelwriter/dialogs/projsettings.py | 48 ++++++-------
novelwriter/dialogs/quotes.py | 4 +-
novelwriter/dialogs/updates.py | 10 +--
novelwriter/dialogs/wordlist.py | 14 ++--
novelwriter/gui/custom.py | 8 +--
novelwriter/gui/doceditor.py | 70 +++++++++----------
novelwriter/gui/dochighlight.py | 10 +--
novelwriter/gui/docviewer.py | 40 +++++------
novelwriter/gui/itemdetails.py | 10 +--
novelwriter/gui/mainmenu.py | 102 ++++++++++++++--------------
novelwriter/gui/noveltree.py | 18 ++---
novelwriter/gui/outline.py | 28 ++++----
novelwriter/gui/projtree.py | 48 ++++++-------
novelwriter/gui/statusbar.py | 8 +--
novelwriter/gui/viewsbar.py | 20 +++---
novelwriter/tools/build.py | 28 ++++----
novelwriter/tools/lipsum.py | 14 ++--
novelwriter/tools/projwizard.py | 10 +--
novelwriter/tools/writingstats.py | 16 ++---
28 files changed, 407 insertions(+), 408 deletions(-)
diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py
index cce4603d..dfb577b1 100644
--- a/novelwriter/core/project.py
+++ b/novelwriter/core/project.py
@@ -56,11 +56,11 @@ class NWProject():
FILE_VERSION = "1.4" # The current project file format version
- def __init__(self, theParent):
+ def __init__(self, mainGui):
# Internal
- self.theParent = theParent
- self.mainConf = novelwriter.CONFIG
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
# Core Elements
self._optState = OptionState(self) # Project-specific GUI options
@@ -414,7 +414,7 @@ class NWProject():
if not os.path.isfile(fileName):
fileName = os.path.join(fileName, nwFiles.PROJ_FILE)
if not os.path.isfile(fileName):
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"File not found: {0}"
).format(fileName), nwAlert.ERROR)
return False
@@ -465,20 +465,20 @@ class NWProject():
try:
nwXML = etree.parse(fileName)
except Exception as exc:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Failed to parse project xml."
), nwAlert.ERROR, exception=exc)
# Trying to open backup file instead
backFile = fileName[:-3]+"bak"
if os.path.isfile(backFile):
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Attempting to open backup project file instead."
), nwAlert.INFO)
try:
nwXML = etree.parse(backFile)
except Exception as exc:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Failed to parse project xml."
), nwAlert.ERROR, exception=exc)
self.clearProject()
@@ -501,7 +501,7 @@ class NWProject():
# ===============
if not nwxRoot == "novelWriterXML":
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Project file does not appear to be a novelWriterXML file."
), nwAlert.ERROR)
self.clearProject()
@@ -527,7 +527,7 @@ class NWProject():
# stored and handled. Introduced in version 1.7.
if fileVersion not in ("1.0", "1.1", "1.2", "1.3", "1.4"):
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Unknown or unsupported novelWriter project file format. "
"The project cannot be opened by this version of novelWriter. "
"The file was saved with novelWriter version {0}."
@@ -536,7 +536,7 @@ class NWProject():
return False
if fileVersion != self.FILE_VERSION:
- msgYes = self.theParent.askQuestion(
+ msgYes = self.mainGui.askQuestion(
self.tr("File Version"),
self.tr(
"The file format of your project is about to be updated. "
@@ -552,7 +552,7 @@ class NWProject():
# =========================
if hexToInt(hexVersion) > hexToInt(novelwriter.__hexversion__):
- msgYes = self.theParent.askQuestion(
+ msgYes = self.mainGui.askQuestion(
self.tr("Version Conflict"),
self.tr(
"This project was saved by a newer version of "
@@ -646,7 +646,7 @@ class NWProject():
for projItem in legacyList:
errList = self._legacyDataFolder(projItem, errList)
if errList:
- self.theParent.makeAlert(errList, nwAlert.ERROR)
+ self.mainGui.makeAlert(errList, nwAlert.ERROR)
# Clean up no longer used files
self._deprecatedFiles()
@@ -672,7 +672,7 @@ class NWProject():
self._writeLockFile()
self.setProjectChanged(False)
- self.theParent.setStatus(self.tr("Opened Project: {0}").format(self.projName))
+ self.mainGui.setStatus(self.tr("Opened Project: {0}").format(self.projName))
return True
@@ -683,7 +683,7 @@ class NWProject():
file.
"""
if self.projPath is None:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Project path not set, cannot save project."
), nwAlert.ERROR)
return False
@@ -763,7 +763,7 @@ class NWProject():
xml_declaration=True
))
except Exception as exc:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Failed to save project."
), nwAlert.ERROR, exception=exc)
return False
@@ -775,7 +775,7 @@ class NWProject():
os.replace(saveFile, backFile)
os.replace(tempFile, saveFile)
except OSError as exc:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Failed to save project."
), nwAlert.ERROR, exception=exc)
return False
@@ -788,7 +788,7 @@ class NWProject():
self.mainConf.saveRecentCache()
self._writeLockFile()
- self.theParent.setStatus(self.tr("Saved Project: {0}").format(self.projName))
+ self.mainGui.setStatus(self.tr("Saved Project: {0}").format(self.projName))
self.setProjectChanged(False)
return True
@@ -836,22 +836,22 @@ class NWProject():
def zipIt(self, doNotify):
"""Create a zip file of the entire project.
"""
- if not self.theParent.hasProject:
+ if not self.mainGui.hasProject:
logger.error("No project open")
return False
logger.info("Backing up project")
- self.theParent.setStatus(self.tr("Backing up project ..."))
+ self.mainGui.setStatus(self.tr("Backing up project ..."))
if not (self.mainConf.backupPath and os.path.isdir(self.mainConf.backupPath)):
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Cannot backup project because no valid backup path is set. "
"Please set a valid backup location in Preferences."
), nwAlert.ERROR)
return False
if not self.projName:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Cannot backup project because no project name is set. "
"Please set a Working Title in Project Settings."
), nwAlert.ERROR)
@@ -864,13 +864,13 @@ class NWProject():
os.mkdir(baseDir)
logger.debug("Created folder: %s", baseDir)
except Exception as exc:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Could not create backup folder."
), nwAlert.ERROR, exception=exc)
return False
if baseDir and baseDir.startswith(self.projPath):
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Cannot backup project because the backup path is within the "
"project folder to be backed up. Please choose a different "
"backup path in Preferences."
@@ -886,17 +886,17 @@ class NWProject():
self._writeLockFile()
logger.info("Backup written to: %s", archName)
if doNotify:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Backup archive file written to: {0}"
).format(f"{os.path.join(cleanName, archName)}.zip"), nwAlert.INFO)
except Exception as exc:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Could not write backup archive."
), nwAlert.ERROR, exception=exc)
return False
- self.theParent.setStatus(self.tr(
+ self.mainGui.setStatus(self.tr(
"Project backed up to '{0}'"
).format(f"{baseName}.zip"))
@@ -924,7 +924,7 @@ class NWProject():
shutil.unpack_archive(pkgSample, projPath)
isSuccess = True
except Exception as exc:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Failed to create a new example project."
), nwAlert.ERROR, exception=exc)
@@ -946,12 +946,12 @@ class NWProject():
isSuccess = True
except Exception as exc:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Failed to create a new example project."
), nwAlert.ERROR, exception=exc)
else:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Failed to create a new example project. "
"Could not find the necessary files. "
"They seem to be missing from this installation."
@@ -959,8 +959,8 @@ class NWProject():
if isSuccess:
self.clearProject()
- self.theParent.openProject(projPath)
- self.theParent.rebuildIndex()
+ self.mainGui.openProject(projPath)
+ self.mainGui.rebuildIndex()
return isSuccess
@@ -985,14 +985,14 @@ class NWProject():
os.mkdir(projPath)
logger.debug("Created folder: %s", projPath)
except Exception as exc:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Could not create new project folder."
), nwAlert.ERROR, exception=exc)
return False
if os.path.isdir(projPath):
if os.listdir(self.projPath):
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"New project folder is not empty. "
"Each project requires a dedicated project folder."
), nwAlert.ERROR)
@@ -1042,14 +1042,14 @@ class NWProject():
self.doBackup = doBackup
if doBackup:
if not os.path.isdir(self.mainConf.backupPath):
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"You must set a valid backup path in Preferences to use "
"the automatic project backup feature."
), nwAlert.WARN)
return False
if self.projName == "":
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"You must set a valid project name in Project Settings to "
"use the automatic project backup feature."
), nwAlert.WARN)
@@ -1154,7 +1154,7 @@ class NWProject():
information to the GUI statusbar.
"""
self.projChanged = bValue
- self.theParent.statusBar.doUpdateProjectStatus(bValue)
+ self.mainGui.statusBar.doUpdateProjectStatus(bValue)
if bValue:
# If we've changed the project at all, this should be True
self.projAltered = True
@@ -1384,7 +1384,7 @@ class NWProject():
os.mkdir(thePath)
logger.debug("Created folder: %s", thePath)
except Exception as exc:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Could not create folder."
), nwAlert.ERROR, exception=exc)
return False
@@ -1447,7 +1447,7 @@ class NWProject():
# Report status
if len(orphanFiles) > 0:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Found {0} orphaned file(s) in project folder."
).format(len(orphanFiles)), nwAlert.WARN)
else:
@@ -1504,7 +1504,7 @@ class NWProject():
self._projTree.updateItemData(orphItem.itemHandle)
if noWhere:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"One or more orphaned files could not be added back into the project. "
"Make sure at least a Novel root folder exists."
), nwAlert.WARN)
diff --git a/novelwriter/core/tokenizer.py b/novelwriter/core/tokenizer.py
index bb5f3d8e..3a3b52f1 100644
--- a/novelwriter/core/tokenizer.py
+++ b/novelwriter/core/tokenizer.py
@@ -82,7 +82,6 @@ class Tokenizer(ABC):
def __init__(self, theProject):
self.theProject = theProject
- self.theParent = theProject.theParent
self.mainConf = novelwriter.CONFIG
# Data Variables
diff --git a/novelwriter/dialogs/about.py b/novelwriter/dialogs/about.py
index f832343a..83e3c347 100644
--- a/novelwriter/dialogs/about.py
+++ b/novelwriter/dialogs/about.py
@@ -43,15 +43,15 @@ logger = logging.getLogger(__name__)
class GuiAbout(QDialog):
- def __init__(self, theParent):
- QDialog.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QDialog.__init__(self, mainGui)
logger.debug("Initialising GuiAbout ...")
self.setObjectName("GuiAbout")
- self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
self.outerBox = QVBoxLayout()
self.innerBox = QHBoxLayout()
@@ -63,7 +63,7 @@ class GuiAbout(QDialog):
nPx = self.mainConf.pxInt(96)
self.nwIcon = QLabel()
- self.nwIcon.setPixmap(self.theParent.theTheme.getPixmap("novelwriter", (nPx, nPx)))
+ self.nwIcon.setPixmap(self.mainGui.theTheme.getPixmap("novelwriter", (nPx, nPx)))
self.lblName = QLabel("novelWriter")
self.lblVers = QLabel(f"v{novelwriter.__version__}")
self.lblDate = QLabel(datetime.strptime(novelwriter.__date__, "%Y-%m-%d").strftime("%x"))
@@ -191,8 +191,8 @@ class GuiAbout(QDialog):
])
)
- theTheme = self.theParent.theTheme
- theIcons = self.theParent.theTheme.theIcons
+ theTheme = self.mainGui.theTheme
+ theIcons = self.mainGui.theTheme.theIcons
if theTheme.themeName and theTheme.themeAuthor != "N/A":
licURL = f"{theTheme.themeLicense}"
aboutMsg += "
{0}
{1}
".format(
@@ -279,9 +279,9 @@ class GuiAbout(QDialog):
" padding-right: 0.8em;"
"}}\n"
).format(
- hColR=self.theParent.theTheme.colHead[0],
- hColG=self.theParent.theTheme.colHead[1],
- hColB=self.theParent.theTheme.colHead[2],
+ hColR=self.mainGui.theTheme.colHead[0],
+ hColG=self.mainGui.theTheme.colHead[1],
+ hColB=self.mainGui.theTheme.colHead[2],
kColR=self.theTheme.colKey[0],
kColG=self.theTheme.colKey[1],
kColB=self.theTheme.colKey[2],
diff --git a/novelwriter/dialogs/docmerge.py b/novelwriter/dialogs/docmerge.py
index 033f3698..23657fb5 100644
--- a/novelwriter/dialogs/docmerge.py
+++ b/novelwriter/dialogs/docmerge.py
@@ -41,15 +41,15 @@ logger = logging.getLogger(__name__)
class GuiDocMerge(QDialog):
- def __init__(self, theParent):
- QDialog.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QDialog.__init__(self, mainGui)
logger.debug("Initialising GuiDocMerge ...")
self.setObjectName("GuiDocMerge")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theProject = mainGui.theProject
self.sourceItem = None
self.outerBox = QVBoxLayout()
@@ -57,7 +57,7 @@ class GuiDocMerge(QDialog):
self.headLabel = QLabel("{0}".format(self.tr("Documents to Merge")))
self.helpLabel = QHelpLabel(
- self.tr("Drag and drop items to change the order."), self.theParent.theTheme.helpText
+ self.tr("Drag and drop items to change the order."), self.mainGui.theTheme.helpText
)
self.listBox = QListWidget()
@@ -102,7 +102,7 @@ class GuiDocMerge(QDialog):
finalOrder.append(self.listBox.item(i).data(Qt.UserRole))
if len(finalOrder) == 0:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"No source documents found. Nothing to do."
), nwAlert.ERROR)
return False
@@ -113,21 +113,21 @@ class GuiDocMerge(QDialog):
docText = inDoc.readDocument()
docErr = inDoc.getError()
if docText is None and docErr:
- self.theParent.makeAlert([
+ self.mainGui.makeAlert([
self.tr("Failed to open document file."), docErr
], nwAlert.ERROR)
if docText:
theText += docText.rstrip("\n")+"\n\n"
if self.sourceItem is None:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"No source folder selected. Nothing to do."
), nwAlert.ERROR)
return False
srcItem = self.theProject.tree[self.sourceItem]
if srcItem is None:
- self.theParent.makeAlert(self.tr("Internal error."), nwAlert.ERROR)
+ self.mainGui.makeAlert(self.tr("Internal error."), nwAlert.ERROR)
return False
nHandle = self.theProject.newFile(srcItem.itemName, srcItem.itemParent)
@@ -137,13 +137,13 @@ class GuiDocMerge(QDialog):
outDoc = NWDoc(self.theProject, nHandle)
if not outDoc.writeDocument(theText):
- self.theParent.makeAlert([
+ self.mainGui.makeAlert([
self.tr("Could not save document."), outDoc.getError()
], nwAlert.ERROR)
return False
- self.theParent.treeView.revealNewTreeItem(nHandle)
- self.theParent.openDocument(nHandle, doScroll=True)
+ self.mainGui.treeView.revealNewTreeItem(nHandle)
+ self.mainGui.openDocument(nHandle, doScroll=True)
self._doClose()
@@ -165,7 +165,7 @@ class GuiDocMerge(QDialog):
are then added to the list view in order. The list itself can be
reordered by the user.
"""
- tHandle = self.theParent.treeView.getSelectedHandle()
+ tHandle = self.mainGui.treeView.getSelectedHandle()
self.sourceItem = tHandle
if tHandle is None:
return False
@@ -175,12 +175,12 @@ class GuiDocMerge(QDialog):
return False
if nwItem.itemType is not nwItemType.FOLDER:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Element selected in the project tree must be a folder."
), nwAlert.ERROR)
return False
- for sHandle in self.theParent.treeView.getTreeFromHandle(tHandle):
+ for sHandle in self.mainGui.treeView.getTreeFromHandle(tHandle):
newItem = QListWidgetItem()
nwItem = self.theProject.tree[sHandle]
if nwItem.itemType is not nwItemType.FILE:
diff --git a/novelwriter/dialogs/docsplit.py b/novelwriter/dialogs/docsplit.py
index 76e64d5f..4d2ecc4a 100644
--- a/novelwriter/dialogs/docsplit.py
+++ b/novelwriter/dialogs/docsplit.py
@@ -41,15 +41,15 @@ logger = logging.getLogger(__name__)
class GuiDocSplit(QDialog):
- def __init__(self, theParent):
- QDialog.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QDialog.__init__(self, mainGui)
logger.debug("Initialising GuiDocSplit ...")
self.setObjectName("GuiDocSplit")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theProject = mainGui.theProject
self.sourceItem = None
self.sourceText = []
@@ -60,7 +60,7 @@ class GuiDocSplit(QDialog):
self.headLabel = QLabel("{0}".format(self.tr("Document Headers")))
self.helpLabel = QHelpLabel(
self.tr("Select the maximum level to split into files."),
- self.theParent.theTheme.helpText
+ self.mainGui.theTheme.helpText
)
self.listBox = QListWidget()
@@ -115,14 +115,14 @@ class GuiDocSplit(QDialog):
logger.verbose("GuiDocSplit split button clicked")
if self.sourceItem is None:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"No source document selected. Nothing to do."
), nwAlert.ERROR)
return False
srcItem = self.theProject.tree[self.sourceItem]
if srcItem is None:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Could not parse source document."
), nwAlert.ERROR)
return False
@@ -132,7 +132,7 @@ class GuiDocSplit(QDialog):
docErr = inDoc.getError()
if theText is None and docErr:
- self.theParent.makeAlert([
+ self.mainGui.makeAlert([
self.tr("Failed to open document file."), docErr
], nwAlert.ERROR)
@@ -153,12 +153,12 @@ class GuiDocSplit(QDialog):
nFiles = len(finalOrder)
if nFiles == 0:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"No headers found. Nothing to do."
), nwAlert.ERROR)
return False
- msgYes = self.theParent.askQuestion(
+ msgYes = self.mainGui.askQuestion(
self.tr("Split Document"),
"{0}
{1}".format(
self.tr(
@@ -175,7 +175,7 @@ class GuiDocSplit(QDialog):
# Create the folder
fHandle = self.theProject.newFolder(srcItem.itemName, srcItem.itemParent)
- self.theParent.treeView.revealNewTreeItem(fHandle)
+ self.mainGui.treeView.revealNewTreeItem(fHandle)
logger.verbose("Creating folder '%s'", fHandle)
# Loop through, and create the files
@@ -196,12 +196,12 @@ class GuiDocSplit(QDialog):
outDoc = NWDoc(self.theProject, nHandle)
if not outDoc.writeDocument(theText):
- self.theParent.makeAlert([
+ self.mainGui.makeAlert([
self.tr("Could not save document."), outDoc.getError()
], nwAlert.ERROR)
return False
- self.theParent.treeView.revealNewTreeItem(nHandle)
+ self.mainGui.treeView.revealNewTreeItem(nHandle)
self._doClose()
@@ -226,7 +226,7 @@ class GuiDocSplit(QDialog):
"""
self.listBox.clear()
if self.sourceItem is None:
- self.sourceItem = self.theParent.treeView.getSelectedHandle()
+ self.sourceItem = self.mainGui.treeView.getSelectedHandle()
if self.sourceItem is None:
return False
@@ -236,7 +236,7 @@ class GuiDocSplit(QDialog):
return False
if nwItem.itemType is not nwItemType.FILE:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Element selected in the project tree must be a file."
), nwAlert.ERROR)
return False
diff --git a/novelwriter/dialogs/itemeditor.py b/novelwriter/dialogs/itemeditor.py
index acf07134..7ad4eed0 100644
--- a/novelwriter/dialogs/itemeditor.py
+++ b/novelwriter/dialogs/itemeditor.py
@@ -41,15 +41,15 @@ logger = logging.getLogger(__name__)
class GuiItemEditor(QDialog):
- def __init__(self, theParent, tHandle):
- QDialog.__init__(self, theParent)
+ def __init__(self, mainGui, tHandle):
+ QDialog.__init__(self, mainGui)
logger.debug("Initialising GuiItemEditor ...")
self.setObjectName("GuiItemEditor")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theProject = mainGui.theProject
##
# Build GUI
diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py
index 755b9198..4b74655f 100644
--- a/novelwriter/dialogs/preferences.py
+++ b/novelwriter/dialogs/preferences.py
@@ -43,25 +43,25 @@ logger = logging.getLogger(__name__)
class GuiPreferences(PagedDialog):
- def __init__(self, theParent):
- PagedDialog.__init__(self, theParent)
+ def __init__(self, mainGui):
+ PagedDialog.__init__(self, mainGui)
logger.debug("Initialising GuiPreferences ...")
self.setObjectName("GuiPreferences")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theProject = mainGui.theProject
self.setWindowTitle(self.tr("Preferences"))
- self.tabGeneral = GuiPreferencesGeneral(self.theParent)
- self.tabProjects = GuiPreferencesProjects(self.theParent)
- self.tabDocs = GuiPreferencesDocuments(self.theParent)
- self.tabEditor = GuiPreferencesEditor(self.theParent)
- self.tabSyntax = GuiPreferencesSyntax(self.theParent)
- self.tabAuto = GuiPreferencesAutomation(self.theParent)
- self.tabQuote = GuiPreferencesQuotes(self.theParent)
+ self.tabGeneral = GuiPreferencesGeneral(self.mainGui)
+ self.tabProjects = GuiPreferencesProjects(self.mainGui)
+ self.tabDocs = GuiPreferencesDocuments(self.mainGui)
+ self.tabEditor = GuiPreferencesEditor(self.mainGui)
+ self.tabSyntax = GuiPreferencesSyntax(self.mainGui)
+ self.tabAuto = GuiPreferencesAutomation(self.mainGui)
+ self.tabQuote = GuiPreferencesQuotes(self.mainGui)
self.addTab(self.tabGeneral, self.tr("General"))
self.addTab(self.tabProjects, self.tr("Projects"))
@@ -102,12 +102,12 @@ class GuiPreferences(PagedDialog):
self.tabQuote.saveValues()
if needsRestart:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Some changes will not be applied until novelWriter has been restarted."
), nwAlert.INFO)
if refreshTree:
- self.theParent.treeView.populateTree()
+ self.mainGui.treeView.populateTree()
self._saveWindowSize()
self.accept()
@@ -138,12 +138,12 @@ class GuiPreferences(PagedDialog):
class GuiPreferencesGeneral(QWidget):
- def __init__(self, theParent):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
# The Form
self.mainForm = QConfigLayout()
@@ -344,12 +344,12 @@ class GuiPreferencesGeneral(QWidget):
class GuiPreferencesProjects(QWidget):
- def __init__(self, theParent):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
# The Form
self.mainForm = QConfigLayout()
@@ -505,12 +505,12 @@ class GuiPreferencesProjects(QWidget):
class GuiPreferencesDocuments(QWidget):
- def __init__(self, theParent):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
# The Form
self.mainForm = QConfigLayout()
@@ -666,12 +666,12 @@ class GuiPreferencesDocuments(QWidget):
class GuiPreferencesEditor(QWidget):
- def __init__(self, theParent):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
# The Form
self.mainForm = QConfigLayout()
@@ -688,7 +688,7 @@ class GuiPreferencesEditor(QWidget):
self.spellLanguage = QComboBox(self)
self.spellLanguage.setMaximumWidth(mW)
- langAvail = self.theParent.docEditor.spEnchant.listDictionaries()
+ langAvail = self.mainGui.docEditor.spEnchant.listDictionaries()
if self.mainConf.hasEnchant:
if langAvail:
for spTag, spProv in langAvail:
@@ -840,12 +840,12 @@ class GuiPreferencesEditor(QWidget):
class GuiPreferencesSyntax(QWidget):
- def __init__(self, theParent):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
# The Form
self.mainForm = QConfigLayout()
@@ -943,12 +943,12 @@ class GuiPreferencesSyntax(QWidget):
class GuiPreferencesAutomation(QWidget):
- def __init__(self, theParent):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
# The Form
self.mainForm = QConfigLayout()
@@ -1100,12 +1100,12 @@ class GuiPreferencesAutomation(QWidget):
class GuiPreferencesQuotes(QWidget):
- def __init__(self, theParent):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
# The Form
self.mainForm = QConfigLayout()
diff --git a/novelwriter/dialogs/projdetails.py b/novelwriter/dialogs/projdetails.py
index 258b82e4..8ab1943f 100644
--- a/novelwriter/dialogs/projdetails.py
+++ b/novelwriter/dialogs/projdetails.py
@@ -43,15 +43,15 @@ logger = logging.getLogger(__name__)
class GuiProjectDetails(PagedDialog):
- def __init__(self, theParent):
- PagedDialog.__init__(self, theParent)
+ def __init__(self, mainGui):
+ PagedDialog.__init__(self, mainGui)
logger.debug("Initialising GuiProjectDetails ...")
self.setObjectName("GuiProjectDetails")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theProject = mainGui.theProject
self.setWindowTitle(self.tr("Project Details"))
@@ -66,8 +66,8 @@ class GuiProjectDetails(PagedDialog):
self.mainConf.pxInt(pOptions.getInt("GuiProjectDetails", "winHeight", wH))
)
- self.tabMain = GuiProjectDetailsMain(self.theParent, self.theProject)
- self.tabContents = GuiProjectDetailsContents(self.theParent, self.theProject)
+ self.tabMain = GuiProjectDetailsMain(self.mainGui, self.theProject)
+ self.tabContents = GuiProjectDetailsContents(self.mainGui, self.theProject)
self.addTab(self.tabMain, self.tr("Overview"))
self.addTab(self.tabContents, self.tr("Contents"))
@@ -139,13 +139,13 @@ class GuiProjectDetails(PagedDialog):
class GuiProjectDetailsMain(QWidget):
- def __init__(self, theParent, theProject):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui, theProject):
+ QWidget.__init__(self, mainGui)
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
self.theProject = theProject
- self.theTheme = theParent.theTheme
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
fPx = self.theTheme.fontPixelSize
fPt = self.theTheme.fontPointSize
@@ -271,13 +271,13 @@ class GuiProjectDetailsContents(QWidget):
C_PAGE = 3
C_PROG = 4
- def __init__(self, theParent, theProject):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui, theProject):
+ QWidget.__init__(self, mainGui)
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
self.theProject = theProject
- self.theTheme = theParent.theTheme
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
# Internal
self._theToC = []
diff --git a/novelwriter/dialogs/projload.py b/novelwriter/dialogs/projload.py
index bbae4920..6d296980 100644
--- a/novelwriter/dialogs/projload.py
+++ b/novelwriter/dialogs/projload.py
@@ -53,15 +53,15 @@ class GuiProjectLoad(QDialog):
C_COUNT = 1
C_TIME = 2
- def __init__(self, theParent):
- QDialog.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QDialog.__init__(self, mainGui)
logger.debug("Initialising GuiProjectLoad ...")
self.setObjectName("GuiProjectLoad")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
self.openState = self.NONE_STATE
self.openPath = None
@@ -80,7 +80,7 @@ class GuiProjectLoad(QDialog):
self.setModal(True)
self.nwIcon = QLabel()
- self.nwIcon.setPixmap(self.theParent.theTheme.getPixmap("novelwriter", (nPx, nPx)))
+ self.nwIcon.setPixmap(self.mainGui.theTheme.getPixmap("novelwriter", (nPx, nPx)))
self.innerBox.addWidget(self.nwIcon, 0, Qt.AlignTop)
self.projectForm = QGridLayout()
@@ -225,7 +225,7 @@ class GuiProjectLoad(QDialog):
selList = self.listBox.selectedItems()
if selList:
projName = selList[0].text(self.C_NAME)
- msgYes = self.theParent.askQuestion(
+ msgYes = self.mainGui.askQuestion(
self.tr("Remove Entry"),
self.tr(
"Remove '{0}' from the recent projects list? "
@@ -280,7 +280,7 @@ class GuiProjectLoad(QDialog):
sortList = sorted(dataList, key=lambda x: x[1], reverse=True)
for theTitle, theTime, theWords, projPath in sortList:
newItem = QTreeWidgetItem([""]*4)
- newItem.setIcon(self.C_NAME, self.theParent.theTheme.getIcon("proj_nwx"))
+ newItem.setIcon(self.C_NAME, self.mainGui.theTheme.getIcon("proj_nwx"))
newItem.setText(self.C_NAME, theTitle)
newItem.setData(self.C_NAME, Qt.UserRole, projPath)
newItem.setText(self.C_COUNT, formatInt(theWords))
diff --git a/novelwriter/dialogs/projsettings.py b/novelwriter/dialogs/projsettings.py
index 8bbdcee3..c7531866 100644
--- a/novelwriter/dialogs/projsettings.py
+++ b/novelwriter/dialogs/projsettings.py
@@ -43,15 +43,15 @@ logger = logging.getLogger(__name__)
class GuiProjectSettings(PagedDialog):
- def __init__(self, theParent):
- PagedDialog.__init__(self, theParent)
+ def __init__(self, mainGui):
+ PagedDialog.__init__(self, mainGui)
logger.debug("Initialising GuiProjectSettings ...")
self.setObjectName("GuiProjectSettings")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theProject = mainGui.theProject
self.theProject.countStatus()
self.setWindowTitle(self.tr("Project Settings"))
@@ -67,10 +67,10 @@ class GuiProjectSettings(PagedDialog):
self.mainConf.pxInt(pOptions.getInt("GuiProjectSettings", "winHeight", wH))
)
- self.tabMain = GuiProjectEditMain(self.theParent, self.theProject)
- self.tabStatus = GuiProjectEditStatus(self.theParent, self.theProject, True)
- self.tabImport = GuiProjectEditStatus(self.theParent, self.theProject, False)
- self.tabReplace = GuiProjectEditReplace(self.theParent, self.theProject)
+ self.tabMain = GuiProjectEditMain(self.mainGui, self.theProject)
+ self.tabStatus = GuiProjectEditStatus(self.mainGui, self.theProject, True)
+ self.tabImport = GuiProjectEditStatus(self.mainGui, self.theProject, False)
+ self.tabReplace = GuiProjectEditReplace(self.mainGui, self.theProject)
self.addTab(self.tabMain, self.tr("Settings"))
self.addTab(self.tabStatus, self.tr("Status"))
@@ -121,7 +121,7 @@ class GuiProjectSettings(PagedDialog):
self.theProject.setImportColours(newList, delList)
if self.tabStatus.colChanged or self.tabImport.colChanged:
- self.theParent.rebuildTrees()
+ self.mainGui.rebuildTrees()
if self.tabReplace.arChanged:
newList = self.tabReplace.getNewList()
@@ -166,22 +166,22 @@ class GuiProjectSettings(PagedDialog):
class GuiProjectEditMain(QWidget):
- def __init__(self, theParent, theProject):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui, theProject):
+ QWidget.__init__(self, mainGui)
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
+ self.mainGui = mainGui
self.theProject = theProject
# The Form
self.mainForm = QConfigLayout()
- self.mainForm.setHelpTextStyle(self.theParent.theTheme.helpText)
+ self.mainForm.setHelpTextStyle(self.mainGui.theTheme.helpText)
self.setLayout(self.mainForm)
self.mainForm.addGroupLabel(self.tr("Project Settings"))
xW = self.mainConf.pxInt(250)
- xH = round(4.8*self.theParent.theTheme.fontPixelSize)
+ xH = round(4.8*self.mainGui.theTheme.fontPixelSize)
self.editName = QLineEdit()
self.editName.setMaxLength(200)
@@ -216,7 +216,7 @@ class GuiProjectEditMain(QWidget):
self.spellLang = QComboBox(self)
self.spellLang.setMaximumWidth(xW)
self.spellLang.addItem(self.tr("Default"), "None")
- langAvail = self.theParent.docEditor.spEnchant.listDictionaries()
+ langAvail = self.mainGui.docEditor.spEnchant.listDictionaries()
for spTag, spProv in langAvail:
qLocal = QLocale(spTag)
spLang = qLocal.nativeLanguageName().title()
@@ -256,13 +256,13 @@ class GuiProjectEditStatus(QWidget):
COL_ROLE = Qt.UserRole + 1
NUM_ROLE = Qt.UserRole + 2
- def __init__(self, theParent, theProject, isStatus):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui, theProject, isStatus):
+ QWidget.__init__(self, mainGui)
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
+ self.mainGui = mainGui
self.theProject = theProject
- self.theTheme = theParent.theTheme
+ self.theTheme = mainGui.theTheme
if isStatus:
self.theStatus = self.theProject.statusItems
@@ -411,7 +411,7 @@ class GuiProjectEditStatus(QWidget):
if selItem is not None:
iRow = self.listBox.indexOfTopLevelItem(selItem)
if selItem.data(self.COL_LABEL, self.NUM_ROLE) > 0:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Cannot delete a status item that is in use."
), nwAlert.ERROR)
else:
@@ -527,12 +527,12 @@ class GuiProjectEditReplace(QWidget):
COL_KEY = 0
COL_REPL = 1
- def __init__(self, theParent, theProject):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui, theProject):
+ QWidget.__init__(self, mainGui)
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
self.theProject = theProject
self.arChanged = False
diff --git a/novelwriter/dialogs/quotes.py b/novelwriter/dialogs/quotes.py
index e8426adf..299386d8 100644
--- a/novelwriter/dialogs/quotes.py
+++ b/novelwriter/dialogs/quotes.py
@@ -42,8 +42,8 @@ class GuiQuoteSelect(QDialog):
selectedQuote = ""
- def __init__(self, theParent=None, currentQuote='"'):
- QDialog.__init__(self, parent=theParent)
+ def __init__(self, parent=None, currentQuote='"'):
+ QDialog.__init__(self, parent=parent)
self.mainConf = novelwriter.CONFIG
diff --git a/novelwriter/dialogs/updates.py b/novelwriter/dialogs/updates.py
index fccc49c2..a8f3c8a9 100644
--- a/novelwriter/dialogs/updates.py
+++ b/novelwriter/dialogs/updates.py
@@ -43,14 +43,14 @@ logger = logging.getLogger(__name__)
class GuiUpdates(QDialog):
- def __init__(self, theParent):
- QDialog.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QDialog.__init__(self, mainGui)
logger.debug("Initialising GuiUpdates ...")
self.setObjectName("GuiUpdates")
- self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
self.setWindowTitle(self.tr("Check for Updates"))
@@ -61,7 +61,7 @@ class GuiUpdates(QDialog):
# Left Box
self.nwIcon = QLabel()
- self.nwIcon.setPixmap(self.theParent.theTheme.getPixmap("novelwriter", (nPx, nPx)))
+ self.nwIcon.setPixmap(self.mainGui.theTheme.getPixmap("novelwriter", (nPx, nPx)))
self.leftBox = QVBoxLayout()
self.leftBox.addWidget(self.nwIcon)
diff --git a/novelwriter/dialogs/wordlist.py b/novelwriter/dialogs/wordlist.py
index 77a4fb5a..172ae846 100644
--- a/novelwriter/dialogs/wordlist.py
+++ b/novelwriter/dialogs/wordlist.py
@@ -42,16 +42,16 @@ logger = logging.getLogger(__name__)
class GuiWordList(QDialog):
- def __init__(self, theParent):
- QDialog.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QDialog.__init__(self, mainGui)
logger.debug("Initialising GuiWordList ...")
self.setObjectName("GuiWordList")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
+ self.theProject = mainGui.theProject
self.setWindowTitle(self.tr("Project Word List"))
@@ -121,13 +121,13 @@ class GuiWordList(QDialog):
"""
newWord = self.newEntry.text().strip()
if newWord == "":
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Cannot add a blank word."
), nwAlert.ERROR)
return False
if self.listBox.findItems(newWord, Qt.MatchExactly):
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"The word '{0}' is already in the word list."
).format(newWord), nwAlert.ERROR)
return False
diff --git a/novelwriter/gui/custom.py b/novelwriter/gui/custom.py
index 62dd3c91..e571a5a1 100644
--- a/novelwriter/gui/custom.py
+++ b/novelwriter/gui/custom.py
@@ -376,8 +376,8 @@ class QSwitch(QAbstractButton):
class PagedDialog(QDialog):
- def __init__(self, theParent=None):
- QDialog.__init__(self, parent=theParent)
+ def __init__(self, parent=None):
+ QDialog.__init__(self, parent=parent)
self._tabBar = VerticalTabBar(self)
self._tabBar.setExpanding(False)
@@ -426,8 +426,8 @@ class PagedDialog(QDialog):
class VerticalTabBar(QTabBar):
- def __init__(self, theParent=None):
- QTabBar.__init__(self, parent=theParent)
+ def __init__(self, parent=None):
+ QTabBar.__init__(self, parent=parent)
self._mW = novelwriter.CONFIG.pxInt(150)
return
diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py
index 5ede17f1..e1b1d948 100644
--- a/novelwriter/gui/doceditor.py
+++ b/novelwriter/gui/doceditor.py
@@ -72,16 +72,16 @@ class GuiDocEditor(QTextEdit):
docCountsChanged = pyqtSignal(str, int, int, int)
loadDocumentTagRequest = pyqtSignal(str, Enum)
- def __init__(self, theParent):
- QTextEdit.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QTextEdit.__init__(self, mainGui)
logger.debug("Initialising GuiDocEditor ...")
# Class Variables
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
+ self.theProject = mainGui.theProject
self._nwDocument = None
self._nwItem = None
@@ -124,7 +124,7 @@ class GuiDocEditor(QTextEdit):
# Syntax
self.spEnchant = NWSpellEnchant()
- self.highLight = GuiDocHighlighter(qDoc, self.theParent, self.spEnchant)
+ self.highLight = GuiDocHighlighter(qDoc, self.mainGui, self.spEnchant)
# Context Menu
self.setContextMenuPolicy(Qt.CustomContextMenu)
@@ -341,7 +341,7 @@ class GuiDocEditor(QTextEdit):
docSize = len(theDoc)
if docSize > nwConst.MAX_DOCSIZE:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"The document you are trying to open is too big. "
"The document size is {0} MB. "
"The maximum size allowed is {1} MB."
@@ -417,7 +417,7 @@ class GuiDocEditor(QTextEdit):
# Update the status bar
if self._nwItem is not None:
- self.theParent.setStatus(
+ self.mainGui.setStatus(
self.tr("Opened Document: {0}").format(self._nwItem.itemName)
)
@@ -442,7 +442,7 @@ class GuiDocEditor(QTextEdit):
"""
docSize = len(theText)
if docSize > nwConst.MAX_DOCSIZE:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"The text you are trying to add is too big. "
"The text size is {0} MB. "
"The maximum size allowed is {1} MB."
@@ -488,7 +488,7 @@ class GuiDocEditor(QTextEdit):
if not self._nwDocument.writeDocument(docText):
saveOk = False
if self._nwDocument._currHash != self._nwDocument._prevHash:
- msgYes = self.theParent.askQuestion(
+ msgYes = self.mainGui.askQuestion(
self.tr("File Changed on Disk"),
self.tr(
"This document has been changed outside of novelWriter "
@@ -499,7 +499,7 @@ class GuiDocEditor(QTextEdit):
saveOk = self._nwDocument.writeDocument(docText, forceWrite=True)
if not saveOk:
- self.theParent.makeAlert([
+ self.mainGui.makeAlert([
self.tr("Could not save document."), self._nwDocument.getError()
], nwAlert.ERROR)
@@ -512,17 +512,17 @@ class GuiDocEditor(QTextEdit):
newHeader = self.theProject.index.getHandleHeaderLevel(tHandle)
if self._updateHeaders(checkLevel=True):
- self.theParent.requestNovelTreeRefresh()
+ self.mainGui.requestNovelTreeRefresh()
else:
- self.theParent.novelView.updateWordCounts(tHandle)
+ self.mainGui.novelView.updateWordCounts(tHandle)
if oldHeader != newHeader:
- self.theParent.treeView.setTreeItemValues(tHandle)
- self.theParent.treeMeta.updateViewBox(tHandle)
+ self.mainGui.treeView.setTreeItemValues(tHandle)
+ self.mainGui.treeMeta.updateViewBox(tHandle)
self.docFooter.updateInfo()
# Update the status bar
- self.theParent.setStatus(
+ self.mainGui.setStatus(
self.tr("Saved Document: {0}").format(self._nwItem.itemName)
)
@@ -544,8 +544,8 @@ class GuiDocEditor(QTextEdit):
sH = hBar.height() if hBar.isVisible() else 0
tM = cM
- if self.mainConf.textWidth > 0 or self.theParent.isFocusMode:
- tW = self.mainConf.getTextWidth(self.theParent.isFocusMode)
+ if self.mainConf.textWidth > 0 or self.mainGui.isFocusMode:
+ tW = self.mainConf.getTextWidth(self.mainGui.isFocusMode)
tM = max((wW - sW - tW)//2, cM)
tB = self.frameWidth()
@@ -704,7 +704,7 @@ class GuiDocEditor(QTextEdit):
if not self.mainConf.hasEnchant:
if theMode:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Spell checking requires the package PyEnchant. "
"It does not appear to be installed."
), nwAlert.INFO)
@@ -714,7 +714,7 @@ class GuiDocEditor(QTextEdit):
theMode = False
self._spellCheck = theMode
- self.theParent.mainMenu.setSpellCheck(theMode)
+ self.mainGui.mainMenu.setSpellCheck(theMode)
self.theProject.setSpellCheck(theMode)
self.highLight.setSpellCheck(theMode)
if not self._bigDoc:
@@ -742,7 +742,7 @@ class GuiDocEditor(QTextEdit):
qApp.restoreOverrideCursor()
afTime = time()
logger.debug("Document highlighted in %.3f ms", 1000*(afTime-bfTime))
- self.theParent.statusBar.setStatus(self.tr("Spell check complete"))
+ self.mainGui.statusBar.setStatus(self.tr("Spell check complete"))
return True
@@ -1085,7 +1085,7 @@ class GuiDocEditor(QTextEdit):
self._lastFind = None
if self.document().characterCount() > nwConst.MAX_DOCSIZE:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"The document has grown too big and you cannot add more text to it. "
"The maximum size of a single novelWriter document is {0} MB."
).format(
@@ -1245,7 +1245,7 @@ class GuiDocEditor(QTextEdit):
if time() - self._lastEdit < 5 * self.wcInterval:
logger.verbose("Running word counter")
- self.theParent.threadPool.start(self.wCounterDoc)
+ self.mainGui.threadPool.start(self.wCounterDoc)
return
@@ -1302,7 +1302,7 @@ class GuiDocEditor(QTextEdit):
logger.verbose("Selection word counter is busy")
return
- self.theParent.threadPool.start(self.wCounterSel)
+ self.mainGui.threadPool.start(self.wCounterSel)
return
@@ -1381,7 +1381,7 @@ class GuiDocEditor(QTextEdit):
self.docSearch.setResultCount(0, 0)
self._lastFind = None
if self.docSearch.doNextFile and not goBack:
- self.theParent.openNextDocument(
+ self.mainGui.openNextDocument(
self._docHandle, wrapAround=self.docSearch.doLoop
)
self.beginSearch()
@@ -1401,7 +1401,7 @@ class GuiDocEditor(QTextEdit):
if resIdx > maxIdx:
if self.docSearch.doNextFile and not goBack:
- self.theParent.openNextDocument(
+ self.mainGui.openNextDocument(
self._docHandle, wrapAround=self.docSearch.doLoop
)
self.beginSearch()
@@ -1645,7 +1645,7 @@ class GuiDocEditor(QTextEdit):
"""
theCursor = self.textCursor()
if not theCursor.hasSelection():
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Please select some text before calling replace quotes."
), nwAlert.ERROR)
return False
@@ -2187,7 +2187,7 @@ class GuiDocEditSearch(QFrame):
self.mainConf = novelwriter.CONFIG
self.docEditor = docEditor
- self.theParent = docEditor.theParent
+ self.mainGui = docEditor.mainGui
self.theProject = docEditor.theProject
self.theTheme = docEditor.theTheme
@@ -2575,7 +2575,7 @@ class GuiDocEditHeader(QWidget):
self.mainConf = novelwriter.CONFIG
self.docEditor = docEditor
- self.theParent = docEditor.theParent
+ self.mainGui = docEditor.mainGui
self.theProject = docEditor.theProject
self.theTheme = docEditor.theTheme
@@ -2733,7 +2733,7 @@ class GuiDocEditHeader(QWidget):
This function is called by the GuiMain class via the
toggleFocusMode function and should not be activated directly.
"""
- if self.theParent.isFocusMode:
+ if self.mainGui.isFocusMode:
self.minmaxButton.setIcon(self.theTheme.getIcon("minimise"))
else:
self.minmaxButton.setIcon(self.theTheme.getIcon("maximise"))
@@ -2746,7 +2746,7 @@ class GuiDocEditHeader(QWidget):
def _editDocument(self):
"""Open the edit item dialog from the main GUI.
"""
- self.theParent.editItem(self._docHandle)
+ self.mainGui.editItem(self._docHandle)
return
def _searchDocument(self):
@@ -2758,7 +2758,7 @@ class GuiDocEditHeader(QWidget):
def _closeDocument(self):
"""Trigger the close editor on the main window.
"""
- self.theParent.closeDocEditor()
+ self.mainGui.closeDocEditor()
self.editButton.setVisible(False)
self.searchButton.setVisible(False)
self.closeButton.setVisible(False)
@@ -2768,7 +2768,7 @@ class GuiDocEditHeader(QWidget):
def _minmaxDocument(self):
"""Switch on or off Focus Mode.
"""
- self.theParent.toggleFocusMode()
+ self.mainGui.toggleFocusMode()
return
##
@@ -2779,7 +2779,7 @@ class GuiDocEditHeader(QWidget):
"""Capture a click on the title and ensure that the item is
selected in the project tree.
"""
- self.theParent.treeView.setSelectedHandle(self._docHandle, doScroll=True)
+ self.mainGui.treeView.setSelectedHandle(self._docHandle, doScroll=True)
return
# END Class GuiDocEditHeader
@@ -2799,7 +2799,7 @@ class GuiDocEditFooter(QWidget):
self.mainConf = novelwriter.CONFIG
self.docEditor = docEditor
- self.theParent = docEditor.theParent
+ self.mainGui = docEditor.mainGui
self.theProject = docEditor.theProject
self.theTheme = docEditor.theTheme
diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py
index bd2d78eb..d811332c 100644
--- a/novelwriter/gui/dochighlight.py
+++ b/novelwriter/gui/dochighlight.py
@@ -46,16 +46,16 @@ class GuiDocHighlighter(QSyntaxHighlighter):
BLOCK_META = 2
BLOCK_TITLE = 4
- def __init__(self, theDoc, theParent, spEnchant):
+ def __init__(self, theDoc, mainGui, spEnchant):
QSyntaxHighlighter.__init__(self, theDoc)
logger.debug("Initialising GuiDocHighlighter ...")
self.mainConf = novelwriter.CONFIG
self.theDoc = theDoc
self.spEnchant = spEnchant
- self.theParent = theParent
- self.theTheme = theParent.theTheme
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
+ self.theProject = mainGui.theProject
self.theHandle = None
self.spellCheck = False
self.spellRx = None
@@ -288,7 +288,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
if theText.startswith("@"): # Keywords and commands
self.setCurrentBlockState(self.BLOCK_META)
pIndex = self.theProject.index
- tItem = self.theParent.theProject.tree[self.theHandle]
+ tItem = self.mainGui.theProject.tree[self.theHandle]
isValid, theBits, thePos = pIndex.scanThis(theText)
isGood = pIndex.checkThese(theBits, tItem)
if isValid:
diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py
index 89ae8ea2..5a9c61cd 100644
--- a/novelwriter/gui/docviewer.py
+++ b/novelwriter/gui/docviewer.py
@@ -53,16 +53,16 @@ class GuiDocViewer(QTextBrowser):
loadDocumentTagRequest = pyqtSignal(str, Enum)
- def __init__(self, theParent):
- QTextBrowser.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QTextBrowser.__init__(self, mainGui)
logger.debug("Initialising GuiDocViewer ...")
# Class Variables
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
+ self.theProject = mainGui.theProject
# Internal Variables
self._docHandle = None
@@ -221,7 +221,7 @@ class GuiDocViewer(QTextBrowser):
self.updateDocMargins()
# Make sure the main GUI knows we changed the content
- self.theParent.viewMeta.refreshReferences(tHandle)
+ self.mainGui.viewMeta.refreshReferences(tHandle)
# Since we change the content while it may still be rendering, we mark
# the document dirty again to make sure it's re-rendered properly.
@@ -714,7 +714,7 @@ class GuiDocViewHeader(QWidget):
self.mainConf = novelwriter.CONFIG
self.docViewer = docViewer
- self.theParent = docViewer.theParent
+ self.mainGui = docViewer.mainGui
self.theProject = docViewer.theProject
self.theTheme = docViewer.theTheme
@@ -882,14 +882,14 @@ class GuiDocViewHeader(QWidget):
def _closeDocument(self):
"""Trigger the close editor/viewer on the main window.
"""
- self.theParent.closeDocViewer()
+ self.mainGui.closeDocViewer()
return
def _refreshDocument(self):
"""Reload the content of the document.
"""
- if self.docViewer.docHandle() == self.theParent.docEditor.docHandle():
- self.theParent.saveDocument()
+ if self.docViewer.docHandle() == self.mainGui.docEditor.docHandle():
+ self.mainGui.saveDocument()
self.docViewer.reloadText()
return
@@ -901,7 +901,7 @@ class GuiDocViewHeader(QWidget):
"""Capture a click on the title and ensure that the item is
selected in the project tree.
"""
- self.theParent.treeView.setSelectedHandle(self._docHandle, doScroll=True)
+ self.mainGui.treeView.setSelectedHandle(self._docHandle, doScroll=True)
return
# END Class GuiDocViewHeader
@@ -921,9 +921,9 @@ class GuiDocViewFooter(QWidget):
self.mainConf = novelwriter.CONFIG
self.docViewer = docViewer
- self.theParent = docViewer.theParent
+ self.mainGui = docViewer.mainGui
self.theTheme = docViewer.theTheme
- self.viewMeta = docViewer.theParent.viewMeta
+ self.viewMeta = docViewer.mainGui.viewMeta
# Internal Variables
self._docHandle = None
@@ -1140,14 +1140,14 @@ class GuiDocViewFooter(QWidget):
class GuiDocViewDetails(QScrollArea):
- def __init__(self, theParent):
- QScrollArea.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QScrollArea.__init__(self, mainGui)
logger.debug("Initialising GuiDocViewDetails ...")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theProject = theParent.theProject
- self.theTheme = theParent.theTheme
+ self.mainGui = mainGui
+ self.theProject = mainGui.theProject
+ self.theTheme = mainGui.theTheme
self.refList = QLabel("")
self.refList.setWordWrap(True)
@@ -1181,7 +1181,7 @@ class GuiDocViewDetails(QScrollArea):
"""Update the current list of document references from the
project index.
"""
- if self.theParent.docViewer.stickyRef:
+ if self.mainGui.docViewer.stickyRef:
return
theRefs = self.theProject.index.getBackReferenceList(tHandle)
@@ -1209,7 +1209,7 @@ class GuiDocViewDetails(QScrollArea):
if len(theLink) == 21:
tHandle = theLink[:13]
tAnchor = theLink[13:]
- self.theParent.viewDocument(tHandle, tAnchor)
+ self.mainGui.viewDocument(tHandle, tAnchor)
return
# END Class GuiDocViewDetails
diff --git a/novelwriter/gui/itemdetails.py b/novelwriter/gui/itemdetails.py
index cf9e8017..97d4ba0e 100644
--- a/novelwriter/gui/itemdetails.py
+++ b/novelwriter/gui/itemdetails.py
@@ -38,14 +38,14 @@ logger = logging.getLogger(__name__)
class GuiItemDetails(QWidget):
- def __init__(self, theParent):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QWidget.__init__(self, mainGui)
logger.debug("Initialising GuiItemDetails ...")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theProject = theParent.theProject
- self.theTheme = theParent.theTheme
+ self.mainGui = mainGui
+ self.theProject = mainGui.theProject
+ self.theTheme = mainGui.theTheme
# Internal Variables
self._itemHandle = None
diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py
index 33b43cfb..f482544f 100644
--- a/novelwriter/gui/mainmenu.py
+++ b/novelwriter/gui/mainmenu.py
@@ -41,13 +41,13 @@ logger = logging.getLogger(__name__)
class GuiMainMenu(QMenuBar):
- def __init__(self, theParent):
- QMenuBar.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QMenuBar.__init__(self, mainGui)
logger.debug("Initialising GuiMainMenu ...")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theProject = mainGui.theProject
# Build Menu
self._buildProjectMenu()
@@ -61,9 +61,9 @@ class GuiMainMenu(QMenuBar):
self._buildHelpMenu()
# Function Pointers
- self._docAction = self.theParent.passDocumentAction
- self._docInsert = self.theParent.docEditor.insertText
- self._insertKeyWord = self.theParent.docEditor.insertKeyWord
+ self._docAction = self.mainGui.passDocumentAction
+ self._docInsert = self.mainGui.docEditor.insertText
+ self._insertKeyWord = self.mainGui.docEditor.insertKeyWord
logger.debug("GuiMainMenu initialisation complete")
@@ -94,7 +94,7 @@ class GuiMainMenu(QMenuBar):
flag is handled by the document editor class, so we make no
decision, just pass a None to the function and let it decide.
"""
- self.theParent.docEditor.toggleSpellCheck(None)
+ self.mainGui.docEditor.toggleSpellCheck(None)
return True
def _openWebsite(self, theUrl):
@@ -123,25 +123,25 @@ class GuiMainMenu(QMenuBar):
# Project > New Project
self.aNewProject = QAction(self.tr("New Project"), self)
- self.aNewProject.triggered.connect(lambda: self.theParent.newProject(None))
+ self.aNewProject.triggered.connect(lambda: self.mainGui.newProject(None))
self.projMenu.addAction(self.aNewProject)
# Project > Open Project
self.aOpenProject = QAction(self.tr("Open Project"), self)
self.aOpenProject.setShortcut("Ctrl+Shift+O")
- self.aOpenProject.triggered.connect(lambda: self.theParent.showProjectLoadDialog())
+ self.aOpenProject.triggered.connect(lambda: self.mainGui.showProjectLoadDialog())
self.projMenu.addAction(self.aOpenProject)
# Project > Save Project
self.aSaveProject = QAction(self.tr("Save Project"), self)
self.aSaveProject.setShortcut("Ctrl+Shift+S")
- self.aSaveProject.triggered.connect(lambda: self.theParent.saveProject())
+ self.aSaveProject.triggered.connect(lambda: self.mainGui.saveProject())
self.projMenu.addAction(self.aSaveProject)
# Project > Close Project
self.aCloseProject = QAction(self.tr("Close Project"), self)
self.aCloseProject.setShortcut("Ctrl+Shift+W")
- self.aCloseProject.triggered.connect(lambda: self.theParent.closeProject(False))
+ self.aCloseProject.triggered.connect(lambda: self.mainGui.closeProject(False))
self.projMenu.addAction(self.aCloseProject)
# Project > Separator
@@ -150,13 +150,13 @@ class GuiMainMenu(QMenuBar):
# Project > Project Settings
self.aProjectSettings = QAction(self.tr("Project Settings"), self)
self.aProjectSettings.setShortcut("Ctrl+Shift+,")
- self.aProjectSettings.triggered.connect(lambda: self.theParent.showProjectSettingsDialog())
+ self.aProjectSettings.triggered.connect(lambda: self.mainGui.showProjectSettingsDialog())
self.projMenu.addAction(self.aProjectSettings)
# Project > Project Details
self.aProjectDetails = QAction(self.tr("Project Details"), self)
self.aProjectDetails.setShortcut("Shift+F6")
- self.aProjectDetails.triggered.connect(lambda: self.theParent.showProjectDetailsDialog())
+ self.aProjectDetails.triggered.connect(lambda: self.mainGui.showProjectDetailsDialog())
self.projMenu.addAction(self.aProjectDetails)
# Project > Separator
@@ -165,18 +165,18 @@ class GuiMainMenu(QMenuBar):
# Project > Edit
self.aEditItem = QAction(self.tr("Edit Item"), self)
self.aEditItem.setShortcuts(["Ctrl+E", "F2"])
- self.aEditItem.triggered.connect(lambda: self.theParent.editItem(None))
+ self.aEditItem.triggered.connect(lambda: self.mainGui.editItem(None))
self.projMenu.addAction(self.aEditItem)
# Project > Delete
self.aDeleteItem = QAction(self.tr("Delete Item"), self)
self.aDeleteItem.setShortcut("Ctrl+Shift+Del")
- self.aDeleteItem.triggered.connect(lambda: self.theParent.treeView.deleteItem(None))
+ self.aDeleteItem.triggered.connect(lambda: self.mainGui.treeView.deleteItem(None))
self.projMenu.addAction(self.aDeleteItem)
# Project > Empty Trash
self.aEmptyTrash = QAction(self.tr("Empty Trash"), self)
- self.aEmptyTrash.triggered.connect(lambda: self.theParent.treeView.emptyTrash())
+ self.aEmptyTrash.triggered.connect(lambda: self.mainGui.treeView.emptyTrash())
self.projMenu.addAction(self.aEmptyTrash)
# Project > Separator
@@ -186,7 +186,7 @@ class GuiMainMenu(QMenuBar):
self.aExitNW = QAction(self.tr("Exit"), self)
self.aExitNW.setShortcut("Ctrl+Q")
self.aExitNW.setMenuRole(QAction.QuitRole)
- self.aExitNW.triggered.connect(lambda: self.theParent.closeMain())
+ self.aExitNW.triggered.connect(lambda: self.mainGui.closeMain())
self.projMenu.addAction(self.aExitNW)
return
@@ -200,19 +200,19 @@ class GuiMainMenu(QMenuBar):
# Document > Open
self.aOpenDoc = QAction(self.tr("Open Document"), self)
self.aOpenDoc.setShortcut("Ctrl+O")
- self.aOpenDoc.triggered.connect(lambda: self.theParent.openSelectedItem())
+ self.aOpenDoc.triggered.connect(lambda: self.mainGui.openSelectedItem())
self.docuMenu.addAction(self.aOpenDoc)
# Document > Save
self.aSaveDoc = QAction(self.tr("Save Document"), self)
self.aSaveDoc.setShortcut("Ctrl+S")
- self.aSaveDoc.triggered.connect(lambda: self.theParent.saveDocument())
+ self.aSaveDoc.triggered.connect(lambda: self.mainGui.saveDocument())
self.docuMenu.addAction(self.aSaveDoc)
# Document > Close
self.aCloseDoc = QAction(self.tr("Close Document"), self)
self.aCloseDoc.setShortcut("Ctrl+W")
- self.aCloseDoc.triggered.connect(lambda: self.theParent.closeDocEditor())
+ self.aCloseDoc.triggered.connect(lambda: self.mainGui.closeDocEditor())
self.docuMenu.addAction(self.aCloseDoc)
# Document > Separator
@@ -221,13 +221,13 @@ class GuiMainMenu(QMenuBar):
# Document > Preview
self.aViewDoc = QAction(self.tr("View Document"), self)
self.aViewDoc.setShortcut("Ctrl+R")
- self.aViewDoc.triggered.connect(lambda: self.theParent.viewDocument(None))
+ self.aViewDoc.triggered.connect(lambda: self.mainGui.viewDocument(None))
self.docuMenu.addAction(self.aViewDoc)
# Document > Close Preview
self.aCloseView = QAction(self.tr("Close Document View"), self)
self.aCloseView.setShortcut("Ctrl+Shift+R")
- self.aCloseView.triggered.connect(lambda: self.theParent.closeDocViewer())
+ self.aCloseView.triggered.connect(lambda: self.mainGui.closeDocViewer())
self.docuMenu.addAction(self.aCloseView)
# Document > Separator
@@ -235,23 +235,23 @@ class GuiMainMenu(QMenuBar):
# Document > Show File Details
self.aFileDetails = QAction(self.tr("Show File Details"), self)
- self.aFileDetails.triggered.connect(lambda: self.theParent.docEditor.revealLocation())
+ self.aFileDetails.triggered.connect(lambda: self.mainGui.docEditor.revealLocation())
self.docuMenu.addAction(self.aFileDetails)
# Document > Import From File
self.aImportFile = QAction(self.tr("Import Text from File"), self)
self.aImportFile.setShortcut("Ctrl+Shift+I")
- self.aImportFile.triggered.connect(lambda: self.theParent.importDocument())
+ self.aImportFile.triggered.connect(lambda: self.mainGui.importDocument())
self.docuMenu.addAction(self.aImportFile)
# Document > Merge Documents
self.aMergeDocs = QAction(self.tr("Merge Folder to Document"), self)
- self.aMergeDocs.triggered.connect(lambda: self.theParent.mergeDocuments())
+ self.aMergeDocs.triggered.connect(lambda: self.mainGui.mergeDocuments())
self.docuMenu.addAction(self.aMergeDocs)
# Document > Split Document
self.aSplitDoc = QAction(self.tr("Split Document to Folder"), self)
- self.aSplitDoc.triggered.connect(lambda: self.theParent.splitDocument())
+ self.aSplitDoc.triggered.connect(lambda: self.mainGui.splitDocument())
self.docuMenu.addAction(self.aSplitDoc)
return
@@ -324,7 +324,7 @@ class GuiMainMenu(QMenuBar):
self.aFocusTree.setShortcut("Ctrl+Alt+1")
else:
self.aFocusTree.setShortcut("Alt+1")
- self.aFocusTree.triggered.connect(lambda: self.theParent.switchFocus(nwWidget.TREE))
+ self.aFocusTree.triggered.connect(lambda: self.mainGui.switchFocus(nwWidget.TREE))
self.viewMenu.addAction(self.aFocusTree)
# View > Document Pane 1
@@ -333,7 +333,7 @@ class GuiMainMenu(QMenuBar):
self.aFocusEditor.setShortcut("Ctrl+Alt+2")
else:
self.aFocusEditor.setShortcut("Alt+2")
- self.aFocusEditor.triggered.connect(lambda: self.theParent.switchFocus(nwWidget.EDITOR))
+ self.aFocusEditor.triggered.connect(lambda: self.mainGui.switchFocus(nwWidget.EDITOR))
self.viewMenu.addAction(self.aFocusEditor)
# View > Document Pane 2
@@ -342,7 +342,7 @@ class GuiMainMenu(QMenuBar):
self.aFocusView.setShortcut("Ctrl+Alt+3")
else:
self.aFocusView.setShortcut("Alt+3")
- self.aFocusView.triggered.connect(lambda: self.theParent.switchFocus(nwWidget.VIEWER))
+ self.aFocusView.triggered.connect(lambda: self.mainGui.switchFocus(nwWidget.VIEWER))
self.viewMenu.addAction(self.aFocusView)
# View > Outline
@@ -351,7 +351,7 @@ class GuiMainMenu(QMenuBar):
self.aFocusOutline.setShortcut("Ctrl+Alt+4")
else:
self.aFocusOutline.setShortcut("Alt+4")
- self.aFocusOutline.triggered.connect(lambda: self.theParent.switchFocus(nwWidget.OUTLINE))
+ self.aFocusOutline.triggered.connect(lambda: self.mainGui.switchFocus(nwWidget.OUTLINE))
self.viewMenu.addAction(self.aFocusOutline)
# View > Separator
@@ -360,13 +360,13 @@ class GuiMainMenu(QMenuBar):
# View > Go Backward
self.aViewPrev = QAction(self.tr("Navigate Backward"), self)
self.aViewPrev.setShortcut("Alt+Left")
- self.aViewPrev.triggered.connect(lambda: self.theParent.docViewer.navBackward())
+ self.aViewPrev.triggered.connect(lambda: self.mainGui.docViewer.navBackward())
self.viewMenu.addAction(self.aViewPrev)
# View > Go Forward
self.aViewNext = QAction(self.tr("Navigate Forward"), self)
self.aViewNext.setShortcut("Alt+Right")
- self.aViewNext.triggered.connect(lambda: self.theParent.docViewer.navForward())
+ self.aViewNext.triggered.connect(lambda: self.mainGui.docViewer.navForward())
self.viewMenu.addAction(self.aViewNext)
# View > Separator
@@ -376,14 +376,14 @@ class GuiMainMenu(QMenuBar):
self.aFocusMode = QAction(self.tr("Focus Mode"), self)
self.aFocusMode.setShortcut("F8")
self.aFocusMode.setCheckable(True)
- self.aFocusMode.setChecked(self.theParent.isFocusMode)
- self.aFocusMode.triggered.connect(lambda: self.theParent.toggleFocusMode())
+ self.aFocusMode.setChecked(self.mainGui.isFocusMode)
+ self.aFocusMode.triggered.connect(lambda: self.mainGui.toggleFocusMode())
self.viewMenu.addAction(self.aFocusMode)
# View > Toggle Full Screen
self.aFullScreen = QAction(self.tr("Full Screen Mode"), self)
self.aFullScreen.setShortcut("F11")
- self.aFullScreen.triggered.connect(lambda: self.theParent.toggleFullScreenMode())
+ self.aFullScreen.triggered.connect(lambda: self.mainGui.toggleFullScreenMode())
self.viewMenu.addAction(self.aFullScreen)
return
@@ -588,7 +588,7 @@ class GuiMainMenu(QMenuBar):
# Insert > Placeholder Text
self.aLipsumText = QAction(self.tr("Placeholder Text"), self)
- self.aLipsumText.triggered.connect(lambda: self.theParent.showLoremIpsumDialog())
+ self.aLipsumText.triggered.connect(lambda: self.mainGui.showLoremIpsumDialog())
self.insertMenu.addAction(self.aLipsumText)
return
@@ -752,7 +752,7 @@ class GuiMainMenu(QMenuBar):
# Search > Find
self.aFind = QAction(self.tr("Find"), self)
self.aFind.setShortcut("Ctrl+F")
- self.aFind.triggered.connect(lambda: self.theParent.docEditor.beginSearch())
+ self.aFind.triggered.connect(lambda: self.mainGui.docEditor.beginSearch())
self.srcMenu.addAction(self.aFind)
# Search > Replace
@@ -761,7 +761,7 @@ class GuiMainMenu(QMenuBar):
self.aReplace.setShortcut("Ctrl+=")
else:
self.aReplace.setShortcut("Ctrl+H")
- self.aReplace.triggered.connect(lambda: self.theParent.docEditor.beginReplace())
+ self.aReplace.triggered.connect(lambda: self.mainGui.docEditor.beginReplace())
self.srcMenu.addAction(self.aReplace)
# Search > Find Next
@@ -770,7 +770,7 @@ class GuiMainMenu(QMenuBar):
self.aFindNext.setShortcuts(["Ctrl+G", "F3"])
else:
self.aFindNext.setShortcuts(["F3", "Ctrl+G"])
- self.aFindNext.triggered.connect(lambda: self.theParent.docEditor.findNext())
+ self.aFindNext.triggered.connect(lambda: self.mainGui.docEditor.findNext())
self.srcMenu.addAction(self.aFindNext)
# Search > Find Prev
@@ -779,13 +779,13 @@ class GuiMainMenu(QMenuBar):
self.aFindPrev.setShortcuts(["Ctrl+Shift+G", "Shift+F3"])
else:
self.aFindPrev.setShortcuts(["Shift+F3", "Ctrl+Shift+G"])
- self.aFindPrev.triggered.connect(lambda: self.theParent.docEditor.findNext(goBack=True))
+ self.aFindPrev.triggered.connect(lambda: self.mainGui.docEditor.findNext(goBack=True))
self.srcMenu.addAction(self.aFindPrev)
# Search > Replace Next
self.aReplaceNext = QAction(self.tr("Replace Next"), self)
self.aReplaceNext.setShortcut("Ctrl+Shift+1")
- self.aReplaceNext.triggered.connect(lambda: self.theParent.docEditor.replaceNext())
+ self.aReplaceNext.triggered.connect(lambda: self.mainGui.docEditor.replaceNext())
self.srcMenu.addAction(self.aReplaceNext)
return
@@ -807,12 +807,12 @@ class GuiMainMenu(QMenuBar):
# Tools > Re-Run Spell Check
self.aReRunSpell = QAction(self.tr("Re-Run Spell Check"), self)
self.aReRunSpell.setShortcut("F7")
- self.aReRunSpell.triggered.connect(lambda: self.theParent.docEditor.spellCheckDocument())
+ self.aReRunSpell.triggered.connect(lambda: self.mainGui.docEditor.spellCheckDocument())
self.toolsMenu.addAction(self.aReRunSpell)
# Tools > Project Word List
self.aEditWordList = QAction(self.tr("Project Word List"), self)
- self.aEditWordList.triggered.connect(lambda: self.theParent.showProjectWordListDialog())
+ self.aEditWordList.triggered.connect(lambda: self.mainGui.showProjectWordListDialog())
self.toolsMenu.addAction(self.aEditWordList)
# Tools > Separator
@@ -821,7 +821,7 @@ class GuiMainMenu(QMenuBar):
# Tools > Rebuild Indices
self.aRebuildIndex = QAction(self.tr("Rebuild Index"), self)
self.aRebuildIndex.setShortcut("F9")
- self.aRebuildIndex.triggered.connect(lambda: self.theParent.rebuildIndex())
+ self.aRebuildIndex.triggered.connect(lambda: self.mainGui.rebuildIndex())
self.toolsMenu.addAction(self.aRebuildIndex)
# Tools > Separator
@@ -835,20 +835,20 @@ class GuiMainMenu(QMenuBar):
# Tools > Export Project
self.aBuildProject = QAction(self.tr("Build Novel Project"), self)
self.aBuildProject.setShortcut("F5")
- self.aBuildProject.triggered.connect(lambda: self.theParent.showBuildProjectDialog())
+ self.aBuildProject.triggered.connect(lambda: self.mainGui.showBuildProjectDialog())
self.toolsMenu.addAction(self.aBuildProject)
# Tools > Writing Stats
self.aWritingStats = QAction(self.tr("Writing Statistics"), self)
self.aWritingStats.setShortcut("F6")
- self.aWritingStats.triggered.connect(lambda: self.theParent.showWritingStatsDialog())
+ self.aWritingStats.triggered.connect(lambda: self.mainGui.showWritingStatsDialog())
self.toolsMenu.addAction(self.aWritingStats)
# Tools > Settings
self.aPreferences = QAction(self.tr("Preferences"), self)
self.aPreferences.setShortcut("Ctrl+,")
self.aPreferences.setMenuRole(QAction.PreferencesRole)
- self.aPreferences.triggered.connect(lambda: self.theParent.showPreferencesDialog())
+ self.aPreferences.triggered.connect(lambda: self.mainGui.showPreferencesDialog())
self.toolsMenu.addAction(self.aPreferences)
return
@@ -862,13 +862,13 @@ class GuiMainMenu(QMenuBar):
# Help > About
self.aAboutNW = QAction(self.tr("About novelWriter"), self)
self.aAboutNW.setMenuRole(QAction.AboutRole)
- self.aAboutNW.triggered.connect(lambda: self.theParent.showAboutNWDialog())
+ self.aAboutNW.triggered.connect(lambda: self.mainGui.showAboutNWDialog())
self.helpMenu.addAction(self.aAboutNW)
# Help > About Qt5
self.aAboutQt = QAction(self.tr("About Qt5"), self)
self.aAboutQt.setMenuRole(QAction.AboutQtRole)
- self.aAboutQt.triggered.connect(lambda: self.theParent.showAboutQtDialog())
+ self.aAboutQt.triggered.connect(lambda: self.mainGui.showAboutQtDialog())
self.helpMenu.addAction(self.aAboutQt)
# Help > Separator
@@ -915,7 +915,7 @@ class GuiMainMenu(QMenuBar):
# Document > Check for Updates
self.aUpdates = QAction(self.tr("Check for New Release"), self)
- self.aUpdates.triggered.connect(lambda: self.theParent.showUpdatesDialog())
+ self.aUpdates.triggered.connect(lambda: self.mainGui.showUpdatesDialog())
self.helpMenu.addAction(self.aUpdates)
return
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index 9ac2ea2b..af79fad5 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -45,15 +45,15 @@ class GuiNovelTree(QTreeWidget):
C_WORDS = 1
C_POV = 2
- def __init__(self, theParent):
- QTreeWidget.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QTreeWidget.__init__(self, mainGui)
logger.debug("Initialising GuiNovelTree ...")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
+ self.theProject = mainGui.theProject
# Internal Variables
self._treeMap = {}
@@ -135,7 +135,7 @@ class GuiNovelTree(QTreeWidget):
"""Called whenever the Novel tab is activated.
"""
logger.verbose("Requesting refresh of the novel tree")
- treeChanged = self.theParent.treeView.changedSince(self._lastBuild)
+ treeChanged = self.mainGui.treeView.changedSince(self._lastBuild)
indexChanged = self.theProject.index.indexChangedSince(self._lastBuild)
if not (treeChanged or indexChanged or overRide):
logger.verbose("No changes have been made to the novel index")
@@ -209,7 +209,7 @@ class GuiNovelTree(QTreeWidget):
if tHandle is None:
return
- self.theParent.viewDocument(tHandle)
+ self.mainGui.viewDocument(tHandle)
return
@@ -223,7 +223,7 @@ class GuiNovelTree(QTreeWidget):
document editor.
"""
tHandle, tLine = self.getSelectedHandle()
- self.theParent.openDocument(tHandle, tLine=tLine-1, doScroll=True)
+ self.mainGui.openDocument(tHandle, tLine=tLine-1, doScroll=True)
return
def _itemSelected(self):
@@ -233,7 +233,7 @@ class GuiNovelTree(QTreeWidget):
selItems = self.selectedItems()
if selItems:
tHandle = selItems[0].data(self.C_TITLE, Qt.UserRole)[0]
- self.theParent.treeMeta.updateViewBox(tHandle)
+ self.mainGui.treeMeta.updateViewBox(tHandle)
return
diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py
index 65bffdbd..d2b2eb04 100644
--- a/novelwriter/gui/outline.py
+++ b/novelwriter/gui/outline.py
@@ -56,11 +56,11 @@ class GuiOutline(QWidget):
loadDocumentTagRequest = pyqtSignal(str, Enum)
- def __init__(self, theParent):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
# Build GUI
self.outlineBar = GuiOutlineToolBar(self)
@@ -177,9 +177,9 @@ class GuiOutlineToolBar(QToolBar):
logger.debug("Initialising GuiOutlineToolBar ...")
self.mainConf = novelwriter.CONFIG
- self.theParent = theOutline.theParent
- self.theProject = theOutline.theParent.theProject
- self.theTheme = theOutline.theParent.theTheme
+ self.mainGui = theOutline.mainGui
+ self.theProject = theOutline.mainGui.theProject
+ self.theTheme = theOutline.mainGui.theTheme
iPx = self.mainConf.pxInt(22)
mPx = self.mainConf.pxInt(12)
@@ -322,9 +322,9 @@ class GuiOutlineView(QTreeWidget):
logger.debug("Initialising GuiOutlineView ...")
self.mainConf = novelwriter.CONFIG
- self.theParent = theOutline.theParent
- self.theProject = theOutline.theParent.theProject
- self.theTheme = theOutline.theParent.theTheme
+ self.mainGui = theOutline.mainGui
+ self.theProject = theOutline.mainGui.theProject
+ self.theTheme = theOutline.mainGui.theTheme
self.setFrameStyle(QFrame.NoFrame)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
@@ -464,7 +464,7 @@ class GuiOutlineView(QTreeWidget):
document editor.
"""
tHandle, tLine = self.getSelectedHandle()
- self.theParent.openDocument(tHandle, tLine=tLine - 1, doScroll=True)
+ self.mainGui.openDocument(tHandle, tLine=tLine - 1, doScroll=True)
return
@pyqtSlot()
@@ -782,9 +782,9 @@ class GuiOutlineDetails(QScrollArea):
self.mainConf = novelwriter.CONFIG
self.theOutline = theOutline
- self.theParent = theOutline.theParent
- self.theProject = theOutline.theParent.theProject
- self.theTheme = theOutline.theParent.theTheme
+ self.mainGui = theOutline.mainGui
+ self.theProject = theOutline.mainGui.theProject
+ self.theTheme = theOutline.mainGui.theTheme
# Sizes
minTitle = 30*self.theTheme.textNWidth
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index 372a2d84..f2a7b2b3 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -63,10 +63,10 @@ class GuiProjectView(QWidget):
selectedItemChanged = pyqtSignal(str)
openDocumentRequest = pyqtSignal(str, Enum)
- def __init__(self, theParent):
- QWidget.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QWidget.__init__(self, mainGui)
- self.theParent = theParent
+ self.mainGui = mainGui
# Build GUI
self.projTree = GuiProjectTree(self)
@@ -167,9 +167,9 @@ class GuiProjectToolBar(QWidget):
self.mainConf = novelwriter.CONFIG
self.projView = projView
self.projTree = projView.projTree
- self.theParent = projView.theParent
- self.theProject = projView.theParent.theProject
- self.theTheme = projView.theParent.theTheme
+ self.mainGui = projView.mainGui
+ self.theProject = projView.mainGui.theProject
+ self.theTheme = projView.mainGui.theTheme
iPx = self.theTheme.baseIconSize
mPx = self.mainConf.pxInt(4)
@@ -323,9 +323,9 @@ class GuiProjectTree(QTreeWidget):
self.mainConf = novelwriter.CONFIG
self.projView = projView
- self.theParent = projView.theParent
- self.theTheme = projView.theParent.theTheme
- self.theProject = projView.theParent.theProject
+ self.mainGui = projView.mainGui
+ self.theTheme = projView.mainGui.theTheme
+ self.theProject = projView.mainGui.theProject
# Internal Variables
self._treeMap = {}
@@ -420,7 +420,7 @@ class GuiProjectTree(QTreeWidget):
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:
+ if not self.mainGui.hasProject:
logger.error("No project open")
return False
@@ -435,7 +435,7 @@ class GuiProjectTree(QTreeWidget):
sHandle = self.getSelectedHandle()
if sHandle is None or sHandle not in self.theProject.tree:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Did not find anywhere to add the file or folder!"
), nwAlert.ERROR)
return False
@@ -452,7 +452,7 @@ class GuiProjectTree(QTreeWidget):
return False
if self.theProject.tree.isTrash(sHandle):
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Cannot add new files or folders to the Trash folder."
), nwAlert.ERROR)
return False
@@ -611,7 +611,7 @@ class GuiProjectTree(QTreeWidget):
function only asks for confirmation once, and calls the regular
deleteItem function for each document in the Trash folder.
"""
- if not self.theParent.hasProject:
+ if not self.mainGui.hasProject:
logger.error("No project open")
return False
@@ -619,7 +619,7 @@ class GuiProjectTree(QTreeWidget):
logger.debug("Emptying Trash folder")
if trashHandle is None:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"There is currently no Trash folder in this project."
), nwAlert.INFO)
return False
@@ -630,12 +630,12 @@ class GuiProjectTree(QTreeWidget):
nTrash = len(theTrash)
if nTrash == 0:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"The Trash folder is already empty."
), nwAlert.INFO)
return False
- msgYes = self.theParent.askQuestion(
+ msgYes = self.mainGui.askQuestion(
self.tr("Empty Trash"),
self.tr("Permanently delete {0} file(s) from Trash?").format(nTrash)
)
@@ -660,7 +660,7 @@ class GuiProjectTree(QTreeWidget):
delete the files on disk. Root folders are deleted if they're empty
only, and the deletion is always permanent.
"""
- if not self.theParent.hasProject:
+ if not self.mainGui.hasProject:
logger.error("No project open")
return False
@@ -693,7 +693,7 @@ class GuiProjectTree(QTreeWidget):
self._deleteTreeItem(tHandle)
self._alertTreeChange(tHandle=tHandle, flush=True)
else:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Cannot delete root folder. It is not empty. "
"Recursive deletion is not supported. "
"Please delete the content first."
@@ -723,7 +723,7 @@ class GuiProjectTree(QTreeWidget):
# user if they want to permanently delete the file.
doPermanent = False
if not alreadyAsked:
- msgYes = self.theParent.askQuestion(
+ msgYes = self.mainGui.askQuestion(
self.tr("Delete"),
self.tr("Permanently delete '{0}'?").format(nwItemS.itemName)
)
@@ -739,8 +739,8 @@ class GuiProjectTree(QTreeWidget):
tIndex = trItemP.indexOfChild(trItemS)
trItemC = trItemP.takeChild(tIndex)
for dHandle in reversed(self.getTreeFromHandle(tHandle)):
- if self.theParent.docEditor.docHandle() == dHandle:
- self.theParent.closeDocument()
+ if self.mainGui.docEditor.docHandle() == dHandle:
+ self.mainGui.closeDocument()
self._deleteTreeItem(dHandle)
self._alertTreeChange(tHandle=tHandle, flush=autoFlush)
@@ -749,7 +749,7 @@ class GuiProjectTree(QTreeWidget):
else:
# The item is not already in the trash folder, so we
# move it there.
- msgYes = self.theParent.askQuestion(
+ msgYes = self.mainGui.askQuestion(
self.tr("Delete"),
self.tr("Move '{0}' to Trash?").format(nwItemS.itemName),
)
@@ -1199,7 +1199,7 @@ class GuiProjectTree(QTreeWidget):
if self.theProject.tree.checkType(tHandle, nwItemType.FILE):
delDoc = NWDoc(self.theProject, tHandle)
if not delDoc.deleteDocument():
- self.theParent.makeAlert([
+ self.mainGui.makeAlert([
self.tr("Could not delete document file."), delDoc.getError()
], nwAlert.ERROR)
return False
@@ -1295,7 +1295,7 @@ class GuiProjectTree(QTreeWidget):
newItem.setFlags(newItem.flags() ^ Qt.ItemIsDragEnabled)
self.addTopLevelItem(newItem)
else:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"There is nowhere to add item with name '{0}'."
).format(nwItem.itemName), nwAlert.ERROR)
del self._treeMap[tHandle]
diff --git a/novelwriter/gui/statusbar.py b/novelwriter/gui/statusbar.py
index e3891e7e..4863f9bc 100644
--- a/novelwriter/gui/statusbar.py
+++ b/novelwriter/gui/statusbar.py
@@ -41,14 +41,14 @@ logger = logging.getLogger(__name__)
class GuiMainStatus(QStatusBar):
- def __init__(self, theParent):
- QStatusBar.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QStatusBar.__init__(self, mainGui)
logger.debug("Initialising GuiMainStatus ...")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
self.refTime = None
self.userIdle = False
diff --git a/novelwriter/gui/viewsbar.py b/novelwriter/gui/viewsbar.py
index e5b627b2..d62b5543 100644
--- a/novelwriter/gui/viewsbar.py
+++ b/novelwriter/gui/viewsbar.py
@@ -40,14 +40,14 @@ class GuiViewsBar(QToolBar):
viewChangeRequested = pyqtSignal(nwView)
- def __init__(self, theParent):
- QToolBar.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QToolBar.__init__(self, mainGui)
logger.debug("Initialising GuiViewsBar ...")
- self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
# Style
iPx = self.mainConf.pxInt(22)
@@ -89,29 +89,29 @@ class GuiViewsBar(QToolBar):
self.aBuild.setFont(lblFont)
self.aBuild.setToolTip(self.tr("Build novel project"))
self.aBuild.setIcon(self.theTheme.getIcon("view_build"))
- self.aBuild.triggered.connect(lambda: self.theParent.showBuildProjectDialog())
+ self.aBuild.triggered.connect(lambda: self.mainGui.showBuildProjectDialog())
self.aDetails = QAction(self.tr("Details"))
self.aDetails.setFont(lblFont)
self.aDetails.setToolTip(self.tr("Show project details"))
self.aDetails.setIcon(self.theTheme.getIcon("proj_details"))
- self.aDetails.triggered.connect(lambda: self.theParent.showProjectDetailsDialog())
+ self.aDetails.triggered.connect(lambda: self.mainGui.showProjectDetailsDialog())
self.aStats = QAction(self.tr("Stats"))
self.aStats.setFont(lblFont)
self.aStats.setToolTip(self.tr("Show project statistics"))
self.aStats.setIcon(self.theTheme.getIcon("proj_stats"))
- self.aStats.triggered.connect(lambda: self.theParent.showWritingStatsDialog())
+ self.aStats.triggered.connect(lambda: self.mainGui.showWritingStatsDialog())
# Settings Menu
self.mSettings = QMenu()
self.aPrjSettings = QAction(self.tr("Project Settings"))
- self.aPrjSettings.triggered.connect(lambda: self.theParent.showProjectSettingsDialog())
+ self.aPrjSettings.triggered.connect(lambda: self.mainGui.showProjectSettingsDialog())
self.mSettings.addAction(self.aPrjSettings)
self.aPreferences = QAction(self.tr("Preferences"))
- self.aPreferences.triggered.connect(lambda: self.theParent.showPreferencesDialog())
+ self.aPreferences.triggered.connect(lambda: self.mainGui.showPreferencesDialog())
self.mSettings.addAction(self.aPreferences)
self.tbSettings = QToolButton(self)
diff --git a/novelwriter/tools/build.py b/novelwriter/tools/build.py
index b27a98a4..4ce9dea1 100644
--- a/novelwriter/tools/build.py
+++ b/novelwriter/tools/build.py
@@ -65,16 +65,16 @@ class GuiBuildNovel(QDialog):
FMT_JSON_H = 8 # HTML5 wrapped in JSON
FMT_JSON_M = 9 # nW Markdown wrapped in JSON
- def __init__(self, theParent):
- QDialog.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QDialog.__init__(self, mainGui)
logger.debug("Initialising GuiBuildNovel ...")
self.setObjectName("GuiBuildNovel")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
+ self.theProject = mainGui.theProject
self.htmlText = [] # List of html documents
self.htmlStyle = [] # List of html styles
@@ -711,7 +711,7 @@ class GuiBuildNovel(QDialog):
bldObj.initDocument()
# Make sure the project and document is up to date
- self.theParent.saveDocument()
+ self.mainGui.saveDocument()
self.buildProgress.setMaximum(len(self.theProject.tree))
self.buildProgress.setValue(0)
@@ -760,7 +760,7 @@ class GuiBuildNovel(QDialog):
logger.debug("Built project in %.3f ms", 1000*(tEnd - tStart))
if bldObj.errData:
- self.theParent.makeAlert([
+ self.mainGui.makeAlert([
self.tr("There were problems when building the project:")
] + bldObj.errData, nwAlert.ERROR)
@@ -1003,11 +1003,11 @@ class GuiBuildNovel(QDialog):
# ==============
if wSuccess:
- self.theParent.makeAlert([
+ self.mainGui.makeAlert([
self.tr("{0} file successfully written to:").format(textFmt), savePath
], nwAlert.INFO)
else:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Failed to write {0} file. {1}"
).format(textFmt, errMsg), nwAlert.ERROR)
@@ -1193,18 +1193,18 @@ class GuiBuildNovel(QDialog):
class GuiBuildNovelDocView(QTextBrowser):
- def __init__(self, theParent, theProject):
- QTextBrowser.__init__(self, theParent)
+ def __init__(self, mainGui, theProject):
+ QTextBrowser.__init__(self, mainGui)
logger.debug("Initialising GuiBuildNovelDocView ...")
self.mainConf = novelwriter.CONFIG
self.theProject = theProject
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
self.buildTime = 0
- self.setMinimumWidth(40*self.theParent.theTheme.textNWidth)
+ self.setMinimumWidth(40*self.mainGui.theTheme.textNWidth)
self.setOpenExternalLinks(False)
self.document().setDocumentMargin(self.mainConf.getTextMargin())
diff --git a/novelwriter/tools/lipsum.py b/novelwriter/tools/lipsum.py
index 4ce21643..d741058c 100644
--- a/novelwriter/tools/lipsum.py
+++ b/novelwriter/tools/lipsum.py
@@ -42,15 +42,15 @@ logger = logging.getLogger(__name__)
class GuiLipsum(QDialog):
- def __init__(self, theParent):
- QDialog.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QDialog.__init__(self, mainGui)
logger.debug("Initialising GuiLipsum ...")
self.setObjectName("GuiLipsum")
- self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
self.setWindowTitle(self.tr("Insert Placeholder Text"))
@@ -61,7 +61,7 @@ class GuiLipsum(QDialog):
nPx = self.mainConf.pxInt(64)
vSp = self.mainConf.pxInt(4)
self.docIcon = QLabel()
- self.docIcon.setPixmap(self.theParent.theTheme.getPixmap("proj_document", (nPx, nPx)))
+ self.docIcon.setPixmap(self.mainGui.theTheme.getPixmap("proj_document", (nPx, nPx)))
self.leftBox = QVBoxLayout()
self.leftBox.setSpacing(vSp)
@@ -129,7 +129,7 @@ class GuiLipsum(QDialog):
pCount = self.paraCount.value()
inText = "\n\n".join(lipsumText[0:pCount]) + "\n\n"
- self.theParent.docEditor.insertText(inText)
+ self.mainGui.docEditor.insertText(inText)
return
diff --git a/novelwriter/tools/projwizard.py b/novelwriter/tools/projwizard.py
index 765445b9..3dac9ed8 100644
--- a/novelwriter/tools/projwizard.py
+++ b/novelwriter/tools/projwizard.py
@@ -48,15 +48,15 @@ PAGE_FINAL = 4
class GuiProjectWizard(QWizard):
- def __init__(self, theParent):
- QWizard.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QWizard.__init__(self, mainGui)
logger.debug("Initialising GuiProjectWizard ...")
self.setObjectName("GuiProjectWizard")
- self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
self.sideImage = self.theTheme.loadDecoration(
"wiz-back", None, self.mainConf.pxInt(370)
diff --git a/novelwriter/tools/writingstats.py b/novelwriter/tools/writingstats.py
index aff7bc3d..d4527612 100644
--- a/novelwriter/tools/writingstats.py
+++ b/novelwriter/tools/writingstats.py
@@ -57,16 +57,16 @@ class GuiWritingStats(QDialog):
FMT_JSON = 0
FMT_CSV = 1
- def __init__(self, theParent):
- QDialog.__init__(self, theParent)
+ def __init__(self, mainGui):
+ QDialog.__init__(self, mainGui)
logger.debug("Initialising GuiWritingStats ...")
self.setObjectName("GuiWritingStats")
self.mainConf = novelwriter.CONFIG
- self.theParent = theParent
- self.theTheme = theParent.theTheme
- self.theProject = theParent.theProject
+ self.mainGui = mainGui
+ self.theTheme = mainGui.theTheme
+ self.theProject = mainGui.theProject
self.logData = []
self.filterData = []
@@ -411,11 +411,11 @@ class GuiWritingStats(QDialog):
# Report to user
if wSuccess:
- self.theParent.makeAlert([
+ self.mainGui.makeAlert([
self.tr("{0} file successfully written to:").format(textFmt), savePath
], nwAlert.INFO)
else:
- self.theParent.makeAlert([
+ self.mainGui.makeAlert([
self.tr("Failed to write {0} file.").format(textFmt), errMsg
], nwAlert.ERROR)
@@ -478,7 +478,7 @@ class GuiWritingStats(QDialog):
self.logData.append((dStart, sDiff, wcNovel, wcNotes, sIdle))
except Exception as exc:
- self.theParent.makeAlert(self.tr(
+ self.mainGui.makeAlert(self.tr(
"Failed to read session log file."
), nwAlert.ERROR, exception=exc)
return False
From 94068e777aebc47fbae41a20b979b30350bf2de7 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 11 Jun 2022 15:49:45 +0200
Subject: [PATCH 15/35] Give main GUI elements more identifiable names
---
novelwriter/dialogs/docmerge.py | 6 +-
novelwriter/dialogs/docsplit.py | 6 +-
novelwriter/dialogs/preferences.py | 2 +-
novelwriter/gui/doceditor.py | 6 +-
novelwriter/gui/docviewer.py | 2 +-
novelwriter/gui/mainmenu.py | 4 +-
novelwriter/gui/noveltree.py | 4 +-
novelwriter/guimain.py | 118 +++++++++++-----------
tests/test_dialogs/test_dlg_docmerge.py | 28 ++---
tests/test_dialogs/test_dlg_docsplit.py | 20 ++--
tests/test_dialogs/test_dlg_itemeditor.py | 8 +-
tests/test_gui/test_gui_doceditor.py | 2 +-
tests/test_gui/test_gui_docviewer.py | 10 +-
tests/test_gui/test_gui_guimain.py | 58 +++++------
tests/test_gui/test_gui_mainmenu.py | 2 +-
tests/test_gui/test_gui_outline.py | 16 +--
tests/test_gui/test_gui_projtree.py | 8 +-
tests/test_gui/test_gui_statusbar.py | 2 +-
18 files changed, 151 insertions(+), 151 deletions(-)
diff --git a/novelwriter/dialogs/docmerge.py b/novelwriter/dialogs/docmerge.py
index 23657fb5..96a357f4 100644
--- a/novelwriter/dialogs/docmerge.py
+++ b/novelwriter/dialogs/docmerge.py
@@ -142,7 +142,7 @@ class GuiDocMerge(QDialog):
], nwAlert.ERROR)
return False
- self.mainGui.treeView.revealNewTreeItem(nHandle)
+ self.mainGui.projView.revealNewTreeItem(nHandle)
self.mainGui.openDocument(nHandle, doScroll=True)
self._doClose()
@@ -165,7 +165,7 @@ class GuiDocMerge(QDialog):
are then added to the list view in order. The list itself can be
reordered by the user.
"""
- tHandle = self.mainGui.treeView.getSelectedHandle()
+ tHandle = self.mainGui.projView.getSelectedHandle()
self.sourceItem = tHandle
if tHandle is None:
return False
@@ -180,7 +180,7 @@ class GuiDocMerge(QDialog):
), nwAlert.ERROR)
return False
- for sHandle in self.mainGui.treeView.getTreeFromHandle(tHandle):
+ for sHandle in self.mainGui.projView.getTreeFromHandle(tHandle):
newItem = QListWidgetItem()
nwItem = self.theProject.tree[sHandle]
if nwItem.itemType is not nwItemType.FILE:
diff --git a/novelwriter/dialogs/docsplit.py b/novelwriter/dialogs/docsplit.py
index 4d2ecc4a..c2d51c8e 100644
--- a/novelwriter/dialogs/docsplit.py
+++ b/novelwriter/dialogs/docsplit.py
@@ -175,7 +175,7 @@ class GuiDocSplit(QDialog):
# Create the folder
fHandle = self.theProject.newFolder(srcItem.itemName, srcItem.itemParent)
- self.mainGui.treeView.revealNewTreeItem(fHandle)
+ self.mainGui.projView.revealNewTreeItem(fHandle)
logger.verbose("Creating folder '%s'", fHandle)
# Loop through, and create the files
@@ -201,7 +201,7 @@ class GuiDocSplit(QDialog):
], nwAlert.ERROR)
return False
- self.mainGui.treeView.revealNewTreeItem(nHandle)
+ self.mainGui.projView.revealNewTreeItem(nHandle)
self._doClose()
@@ -226,7 +226,7 @@ class GuiDocSplit(QDialog):
"""
self.listBox.clear()
if self.sourceItem is None:
- self.sourceItem = self.mainGui.treeView.getSelectedHandle()
+ self.sourceItem = self.mainGui.projView.getSelectedHandle()
if self.sourceItem is None:
return False
diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py
index 4b74655f..e0fd41e8 100644
--- a/novelwriter/dialogs/preferences.py
+++ b/novelwriter/dialogs/preferences.py
@@ -107,7 +107,7 @@ class GuiPreferences(PagedDialog):
), nwAlert.INFO)
if refreshTree:
- self.mainGui.treeView.populateTree()
+ self.mainGui.projView.populateTree()
self._saveWindowSize()
self.accept()
diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py
index e1b1d948..a060f151 100644
--- a/novelwriter/gui/doceditor.py
+++ b/novelwriter/gui/doceditor.py
@@ -517,8 +517,8 @@ class GuiDocEditor(QTextEdit):
self.mainGui.novelView.updateWordCounts(tHandle)
if oldHeader != newHeader:
- self.mainGui.treeView.setTreeItemValues(tHandle)
- self.mainGui.treeMeta.updateViewBox(tHandle)
+ self.mainGui.projView.setTreeItemValues(tHandle)
+ self.mainGui.itemDetails.updateViewBox(tHandle)
self.docFooter.updateInfo()
# Update the status bar
@@ -2779,7 +2779,7 @@ class GuiDocEditHeader(QWidget):
"""Capture a click on the title and ensure that the item is
selected in the project tree.
"""
- self.mainGui.treeView.setSelectedHandle(self._docHandle, doScroll=True)
+ self.mainGui.projView.setSelectedHandle(self._docHandle, doScroll=True)
return
# END Class GuiDocEditHeader
diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py
index 5a9c61cd..f77e02ec 100644
--- a/novelwriter/gui/docviewer.py
+++ b/novelwriter/gui/docviewer.py
@@ -901,7 +901,7 @@ class GuiDocViewHeader(QWidget):
"""Capture a click on the title and ensure that the item is
selected in the project tree.
"""
- self.mainGui.treeView.setSelectedHandle(self._docHandle, doScroll=True)
+ self.mainGui.projView.setSelectedHandle(self._docHandle, doScroll=True)
return
# END Class GuiDocViewHeader
diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py
index f482544f..e7203bb9 100644
--- a/novelwriter/gui/mainmenu.py
+++ b/novelwriter/gui/mainmenu.py
@@ -171,12 +171,12 @@ class GuiMainMenu(QMenuBar):
# Project > Delete
self.aDeleteItem = QAction(self.tr("Delete Item"), self)
self.aDeleteItem.setShortcut("Ctrl+Shift+Del")
- self.aDeleteItem.triggered.connect(lambda: self.mainGui.treeView.deleteItem(None))
+ self.aDeleteItem.triggered.connect(lambda: self.mainGui.projView.deleteItem(None))
self.projMenu.addAction(self.aDeleteItem)
# Project > Empty Trash
self.aEmptyTrash = QAction(self.tr("Empty Trash"), self)
- self.aEmptyTrash.triggered.connect(lambda: self.mainGui.treeView.emptyTrash())
+ self.aEmptyTrash.triggered.connect(lambda: self.mainGui.projView.emptyTrash())
self.projMenu.addAction(self.aEmptyTrash)
# Project > Separator
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index af79fad5..dbdd02c0 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -135,7 +135,7 @@ class GuiNovelTree(QTreeWidget):
"""Called whenever the Novel tab is activated.
"""
logger.verbose("Requesting refresh of the novel tree")
- treeChanged = self.mainGui.treeView.changedSince(self._lastBuild)
+ treeChanged = self.mainGui.projView.changedSince(self._lastBuild)
indexChanged = self.theProject.index.indexChangedSince(self._lastBuild)
if not (treeChanged or indexChanged or overRide):
logger.verbose("No changes have been made to the novel index")
@@ -233,7 +233,7 @@ class GuiNovelTree(QTreeWidget):
selItems = self.selectedItems()
if selItems:
tHandle = selItems[0].data(self.C_TITLE, Qt.UserRole)[0]
- self.mainGui.treeMeta.updateViewBox(tHandle)
+ self.mainGui.itemDetails.updateViewBox(tHandle)
return
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 2716213e..24c2180d 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -104,20 +104,20 @@ class GuiMain(QMainWindow):
hWd = self.mainConf.pxInt(4)
# Main GUI Elements
- self.statusBar = GuiMainStatus(self)
- self.treeView = GuiProjectView(self)
- self.novelView = GuiNovelTree(self)
- self.docEditor = GuiDocEditor(self)
- self.viewMeta = GuiDocViewDetails(self)
- self.docViewer = GuiDocViewer(self)
- self.treeMeta = GuiItemDetails(self)
- self.projView = GuiOutline(self)
- self.mainMenu = GuiMainMenu(self)
- self.viewsBar = GuiViewsBar(self)
+ self.statusBar = GuiMainStatus(self)
+ self.projView = GuiProjectView(self)
+ self.novelView = GuiNovelTree(self)
+ self.docEditor = GuiDocEditor(self)
+ self.viewMeta = GuiDocViewDetails(self)
+ self.docViewer = GuiDocViewer(self)
+ self.itemDetails = GuiItemDetails(self)
+ self.outlineView = GuiOutline(self)
+ self.mainMenu = GuiMainMenu(self)
+ self.viewsBar = GuiViewsBar(self)
# Project Tree Stack
self.projStack = QStackedWidget()
- self.projStack.addWidget(self.treeView)
+ self.projStack.addWidget(self.projView)
self.projStack.addWidget(self.novelView)
self.projStack.currentChanged.connect(self._projStackChanged)
@@ -127,7 +127,7 @@ class GuiMain(QMainWindow):
self.treeBox.setContentsMargins(0, 0, 0, 0)
self.treeBox.setSpacing(mPx)
self.treeBox.addWidget(self.projStack)
- self.treeBox.addWidget(self.treeMeta)
+ self.treeBox.addWidget(self.itemDetails)
self.treePane.setLayout(self.treeBox)
# Splitter : Document Viewer / Document Meta
@@ -154,7 +154,7 @@ class GuiMain(QMainWindow):
# Main Stack : Editor / Outline
self.mainStack = QStackedWidget()
self.mainStack.addWidget(self.splitMain)
- self.mainStack.addWidget(self.projView)
+ self.mainStack.addWidget(self.outlineView)
self.mainStack.currentChanged.connect(self._mainStackChanged)
# Indices of Splitter Widgets
@@ -167,8 +167,8 @@ class GuiMain(QMainWindow):
# Indices of Tab Widgets
self.idxEditorView = self.mainStack.indexOf(self.splitMain)
- self.idxOutlineView = self.mainStack.indexOf(self.projView)
- self.idxTreeView = self.projStack.indexOf(self.treeView)
+ self.idxOutlineView = self.mainStack.indexOf(self.outlineView)
+ self.idxProjView = self.projStack.indexOf(self.projView)
self.idxNovelView = self.projStack.indexOf(self.novelView)
# Splitter Behaviour
@@ -197,24 +197,24 @@ class GuiMain(QMainWindow):
self.viewsBar.viewChangeRequested.connect(self._changeView)
- self.treeView.selectedItemChanged.connect(self.treeMeta.updateViewBox)
- self.treeView.openDocumentRequest.connect(self._openDocument)
- self.treeView.novelItemChanged.connect(self._treeNovelItemChanged)
- self.treeView.wordCountsChanged.connect(self._updateStatusWordCount)
- self.treeView.treeItemChanged.connect(self.docEditor.updateDocInfo)
- self.treeView.treeItemChanged.connect(self.docViewer.updateDocInfo)
- self.treeView.treeItemChanged.connect(self.treeMeta.updateViewBox)
- self.treeView.rootFolderChanged.connect(self.projView.updateRootItem)
+ self.projView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
+ self.projView.openDocumentRequest.connect(self._openDocument)
+ self.projView.novelItemChanged.connect(self._treeNovelItemChanged)
+ self.projView.wordCountsChanged.connect(self._updateStatusWordCount)
+ self.projView.treeItemChanged.connect(self.docEditor.updateDocInfo)
+ self.projView.treeItemChanged.connect(self.docViewer.updateDocInfo)
+ self.projView.treeItemChanged.connect(self.itemDetails.updateViewBox)
+ self.projView.rootFolderChanged.connect(self.outlineView.updateRootItem)
self.docEditor.spellDictionaryChanged.connect(self.statusBar.setLanguage)
self.docEditor.docEditedStatusChanged.connect(self.statusBar.doUpdateDocumentStatus)
- self.docEditor.docCountsChanged.connect(self.treeMeta.updateCounts)
- self.docEditor.docCountsChanged.connect(self.treeView.updateCounts)
+ self.docEditor.docCountsChanged.connect(self.itemDetails.updateCounts)
+ self.docEditor.docCountsChanged.connect(self.projView.updateCounts)
self.docEditor.loadDocumentTagRequest.connect(self._followTag)
self.docViewer.loadDocumentTagRequest.connect(self._followTag)
- self.projView.loadDocumentTagRequest.connect(self._followTag)
+ self.outlineView.loadDocumentTagRequest.connect(self._followTag)
# Finalise Initialisation
# =======================
@@ -291,15 +291,15 @@ class GuiMain(QMainWindow):
"""Wrapper function to clear all sub-elements of the main GUI.
"""
# Project Area
- self.treeView.clearProject()
+ self.projView.clearProject()
self.novelView.clearTree()
- self.treeMeta.clearDetails()
+ self.itemDetails.clearDetails()
# Work Area
self.docEditor.clearEditor()
self.docEditor.setDictionaries()
self.closeDocViewer()
- self.projView.clearOutline()
+ self.outlineView.clearOutline()
# General
self.statusBar.clearStatus()
@@ -361,7 +361,7 @@ class GuiMain(QMainWindow):
self.rebuildTrees()
self.saveProject()
self.docEditor.setDictionaries()
- self.projView.updateRootItem(None)
+ self.outlineView.updateRootItem(None)
self.rebuildIndex(beQuiet=True)
self.statusBar.setRefTime(self.theProject.projOpened)
self.statusBar.setProjectStatus(nwState.GOOD)
@@ -417,7 +417,7 @@ class GuiMain(QMainWindow):
if saveOK:
self.closeDocument()
self.docViewer.clearNavHistory()
- self.projView.closeOutline()
+ self.outlineView.closeOutline()
self.theProject.closeProject(self.idleTime)
self.idleRefTime = time()
@@ -508,7 +508,7 @@ class GuiMain(QMainWindow):
self.docEditor.setDictionaries()
self.docEditor.toggleSpellCheck(self.theProject.spellCheck)
self.statusBar.setRefTime(self.theProject.projOpened)
- self.projView.updateRootItem(None)
+ self.outlineView.updateRootItem(None)
self._updateStatusWordCount()
# Restore previously open documents, if any
@@ -541,7 +541,7 @@ class GuiMain(QMainWindow):
logger.error("No project open")
return False
- self.treeView.saveProjectTree()
+ self.projView.saveProjectTree()
if self.theProject.saveProject(autoSave=autoSave):
self.theProject.index.saveIndex()
@@ -586,7 +586,7 @@ class GuiMain(QMainWindow):
if changeFocus:
self.docEditor.setFocus()
self.theProject.setLastEdited(tHandle)
- self.treeView.setSelectedHandle(tHandle, doScroll=doScroll)
+ self.projView.setSelectedHandle(tHandle, doScroll=doScroll)
else:
return False
@@ -652,7 +652,7 @@ class GuiMain(QMainWindow):
self.saveDocument()
else:
logger.verbose("Trying selected document")
- tHandle = self.treeView.getSelectedHandle()
+ tHandle = self.projView.getSelectedHandle()
if tHandle is None:
logger.verbose("Trying last viewed document")
@@ -789,12 +789,12 @@ class GuiMain(QMainWindow):
tHandle = None
tLine = None
- if self.treeView.treeFocus():
- tHandle = self.treeView.getSelectedHandle()
+ if self.projView.treeFocus():
+ tHandle = self.projView.getSelectedHandle()
elif self.novelView.hasFocus():
tHandle, tLine = self.novelView.getSelectedHandle()
- elif self.projView.treeFocus():
- tHandle, tLine = self.projView.getSelectedHandle()
+ elif self.outlineView.treeFocus():
+ tHandle, tLine = self.outlineView.getSelectedHandle()
else:
logger.warning("No item selected")
return False
@@ -815,16 +815,16 @@ class GuiMain(QMainWindow):
if self.docEditor.anyFocus() or self.isFocusMode:
tHandle = self.docEditor.docHandle()
else:
- tHandle = self.treeView.getSelectedHandle()
+ tHandle = self.projView.getSelectedHandle()
if tHandle:
- return self.treeView.editTreeItem(tHandle)
+ return self.projView.editTreeItem(tHandle)
return False
def rebuildTrees(self):
"""Rebuild the project tree.
"""
- self.treeView.populateTree()
+ self.projView.populateTree()
self.novelView.refreshTree()
return
@@ -847,7 +847,7 @@ class GuiMain(QMainWindow):
qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
tStart = time()
- self.treeView.saveProjectTree()
+ self.projView.saveProjectTree()
self.theProject.index.clearIndex()
for tItem in self.theProject.tree:
@@ -857,8 +857,8 @@ class GuiMain(QMainWindow):
logger.verbose("Indexing '%s'", tItem.itemName)
if self.theProject.index.reIndexHandle(tItem.itemHandle):
# Update Word Counts
- self.treeView.propagateCount(tItem.itemHandle, tItem.wordCount, countChildren=True)
- self.treeView.setTreeItemValues(tItem.itemHandle)
+ self.projView.propagateCount(tItem.itemHandle, tItem.wordCount, countChildren=True)
+ self.projView.setTreeItemValues(tItem.itemHandle)
tEnd = time()
self.setStatus(
@@ -919,9 +919,9 @@ class GuiMain(QMainWindow):
self.saveDocument()
self.docEditor.initEditor()
self.docViewer.initViewer()
- self.treeView.initSettings()
+ self.projView.initSettings()
self.novelView.initTree()
- self.projView.initOutline()
+ self.outlineView.initOutline()
self._updateStatusWordCount()
return
@@ -940,7 +940,7 @@ class GuiMain(QMainWindow):
logger.debug("Applying new project settings")
if dlgProj.spellChanged:
self.docEditor.setDictionaries()
- self.treeMeta.refreshDetails()
+ self.itemDetails.refreshDetails()
self._updateWindowTitle(self.theProject.projName)
return True
@@ -1156,7 +1156,7 @@ class GuiMain(QMainWindow):
if not self.isFocusMode:
self.mainConf.setMainPanePos(self.splitMain.sizes())
self.mainConf.setDocPanePos(self.splitDocs.sizes())
- self.mainConf.setOutlinePanePos(self.projView.splitSizes())
+ self.mainConf.setOutlinePanePos(self.outlineView.splitSizes())
if self.viewMeta.isVisible():
self.mainConf.setViewPanePos(self.splitView.sizes())
@@ -1180,8 +1180,8 @@ class GuiMain(QMainWindow):
"""
if paneNo == nwWidget.TREE:
tabIdx = self.projStack.currentIndex()
- if tabIdx == self.idxTreeView:
- self.treeView.setFocus()
+ if tabIdx == self.idxProjView:
+ self.projView.setFocus()
elif tabIdx == self.idxNovelView:
self.novelView.setFocus()
elif paneNo == nwWidget.EDITOR:
@@ -1192,7 +1192,7 @@ class GuiMain(QMainWindow):
self.docViewer.setFocus()
elif paneNo == nwWidget.OUTLINE:
self._changeView(nwView.OUTLINE)
- self.projView.setTreeFocus()
+ self.outlineView.setTreeFocus()
return
def closeDocEditor(self):
@@ -1490,14 +1490,14 @@ class GuiMain(QMainWindow):
elif view == nwView.PROJECT:
self.mainStack.setCurrentWidget(self.splitMain)
- self.projStack.setCurrentWidget(self.treeView)
+ self.projStack.setCurrentWidget(self.projView)
elif view == nwView.NOVEL:
self.mainStack.setCurrentWidget(self.splitMain)
self.projStack.setCurrentWidget(self.novelView)
elif view == nwView.OUTLINE:
- self.mainStack.setCurrentWidget(self.projView)
+ self.mainStack.setCurrentWidget(self.outlineView)
return
@@ -1551,7 +1551,7 @@ class GuiMain(QMainWindow):
if self.mainStack.currentIndex() == self.idxOutlineView:
logger.verbose("Novel tree changed while Outline tab active")
if self.hasProject:
- self.projView.refreshView(novelChanged=True)
+ self.outlineView.refreshView(novelChanged=True)
return
@@ -1584,7 +1584,7 @@ class GuiMain(QMainWindow):
elif tabIndex == self.idxOutlineView:
logger.verbose("Project outline tab activated")
if self.hasProject:
- self.projView.refreshView()
+ self.outlineView.refreshView()
return
@@ -1594,9 +1594,9 @@ class GuiMain(QMainWindow):
"""
sHandle = None
- if tabIndex == self.idxTreeView:
+ if tabIndex == self.idxProjView:
logger.verbose("Project tree tab activated")
- sHandle = self.treeView.getSelectedHandle()
+ sHandle = self.projView.getSelectedHandle()
elif tabIndex == self.idxNovelView:
logger.verbose("Novel tree tab activated")
@@ -1604,7 +1604,7 @@ class GuiMain(QMainWindow):
self.novelView.refreshTree()
sHandle, _ = self.novelView.getSelectedHandle()
- self.treeMeta.updateViewBox(sHandle)
+ self.itemDetails.updateViewBox(sHandle)
return
diff --git a/tests/test_dialogs/test_dlg_docmerge.py b/tests/test_dialogs/test_dlg_docmerge.py
index f796f864..9d9c9082 100644
--- a/tests/test_dialogs/test_dlg_docmerge.py
+++ b/tests/test_dialogs/test_dlg_docmerge.py
@@ -57,11 +57,11 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Add Project Content
monkeypatch.setattr(GuiItemEditor, "exec_", lambda *a: QDialog.Accepted)
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem(hChapterDir).setSelected(True)
- nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE)
- nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE)
- nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem(hChapterDir).setSelected(True)
+ nwGUI.projView.projTree.newTreeItem(nwItemType.FILE)
+ nwGUI.projView.projTree.newTreeItem(nwItemType.FILE)
+ nwGUI.projView.projTree.newTreeItem(nwItemType.FILE)
assert nwGUI.saveProject() is True
assert nwGUI.closeProject() is True
@@ -83,8 +83,8 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Open the Merge tool
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem(hChapterDir).setSelected(True)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem(hChapterDir).setSelected(True)
monkeypatch.setattr(GuiDocMerge, "exec_", lambda *a: None)
nwGUI.mainMenu.aMergeDocs.activate(QAction.Trigger)
@@ -102,27 +102,27 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
assert nwMerge.listBox.count() == 0
# No item selected
- nwGUI.treeView.projTree.clearSelection()
+ nwGUI.projView.projTree.clearSelection()
assert nwMerge._populateList() is False
assert nwMerge.listBox.count() == 0
# Non-existing item
with monkeypatch.context() as mp:
mp.setattr(NWTree, "__getitem__", lambda *a: None)
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem(hChapterDir).setSelected(True)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem(hChapterDir).setSelected(True)
assert nwMerge._populateList() is False
assert nwMerge.listBox.count() == 0
# Select a non-folder
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem(hChapterOne).setSelected(True)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem(hChapterOne).setSelected(True)
assert nwMerge._populateList() is False
assert nwMerge.listBox.count() == 0
# Select the chapter folder
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem(hChapterDir).setSelected(True)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem(hChapterDir).setSelected(True)
assert nwMerge._populateList() is True
assert nwMerge.listBox.count() == 5
diff --git a/tests/test_dialogs/test_dlg_docsplit.py b/tests/test_dialogs/test_dlg_docsplit.py
index 080be8ab..5b042570 100644
--- a/tests/test_dialogs/test_dlg_docsplit.py
+++ b/tests/test_dialogs/test_dlg_docsplit.py
@@ -61,9 +61,9 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Add Project Content
monkeypatch.setattr(GuiItemEditor, "exec_", lambda *a: QDialog.Accepted)
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem(hNovelRoot).setSelected(True)
- nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem(hNovelRoot).setSelected(True)
+ nwGUI.projView.projTree.newTreeItem(nwItemType.FILE)
assert nwGUI.saveProject() is True
assert nwGUI.closeProject() is True
@@ -90,8 +90,8 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Open the Split tool
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem(hToSplit).setSelected(True)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem(hToSplit).setSelected(True)
monkeypatch.setattr(GuiDocSplit, "exec_", lambda *a: None)
nwGUI.mainMenu.aSplitDoc.activate(QAction.Trigger)
@@ -110,7 +110,7 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# No item selected
nwSplit.sourceItem = None
- nwGUI.treeView.projTree.clearSelection()
+ nwGUI.projView.projTree.clearSelection()
assert nwSplit._populateList() is False
assert nwSplit.listBox.count() == 0
@@ -118,15 +118,15 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
with monkeypatch.context() as mp:
mp.setattr(NWTree, "__getitem__", lambda *a: None)
nwSplit.sourceItem = None
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem(hToSplit).setSelected(True)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem(hToSplit).setSelected(True)
assert nwSplit._populateList() is False
assert nwSplit.listBox.count() == 0
# Select a non-file
nwSplit.sourceItem = None
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem(hChapterDir).setSelected(True)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem(hChapterDir).setSelected(True)
assert nwSplit._populateList() is False
assert nwSplit.listBox.count() == 0
diff --git a/tests/test_dialogs/test_dlg_itemeditor.py b/tests/test_dialogs/test_dlg_itemeditor.py
index 53426df7..360f7641 100644
--- a/tests/test_dialogs/test_dlg_itemeditor.py
+++ b/tests/test_dialogs/test_dlg_itemeditor.py
@@ -52,7 +52,7 @@ def testDlgItemEditor_Dialog(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
tHandle = "000000000000f"
# No Selection
- nwGUI.treeView.projTree.clearSelection()
+ nwGUI.projView.projTree.clearSelection()
assert nwGUI.editItem() is False
# Force opening from editor
@@ -164,9 +164,9 @@ def testDlgItemEditor_Note(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
assert nwGUI.theProject.importItems.name(importKeys[1]) == "Minor"
# Create Note
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem("000000000000a").setSelected(True)
- nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem("000000000000a").setSelected(True)
+ nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
# Open Note
assert nwGUI.openDocument("0000000000010")
diff --git a/tests/test_gui/test_gui_doceditor.py b/tests/test_gui/test_gui_doceditor.py
index 1727b69f..d4a3d749 100644
--- a/tests/test_gui/test_gui_doceditor.py
+++ b/tests/test_gui/test_gui_doceditor.py
@@ -1147,7 +1147,7 @@ def testGuiEditor_Tags(qtbot, monkeypatch, nwGUI, nwMinimal, ipsumText):
assert nwGUI.openDocument(cHandle) is True
assert nwGUI.docEditor.replaceText(theText) is True
assert nwGUI.saveDocument() is True
- assert nwGUI.treeView.revealNewTreeItem(cHandle)
+ assert nwGUI.projView.revealNewTreeItem(cHandle)
nwGUI.docEditor.updateTagHighLighting()
# Follow Tag
diff --git a/tests/test_gui/test_gui_docviewer.py b/tests/test_gui/test_gui_docviewer.py
index d1d8797a..2226a4c3 100644
--- a/tests/test_gui/test_gui_docviewer.py
+++ b/tests/test_gui/test_gui_docviewer.py
@@ -51,12 +51,12 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
assert nwGUI.theProject.index._itemIndex._items != {}
# Select a document in the project tree
- nwGUI.treeView.setSelectedHandle("88243afbe5ed8")
+ nwGUI.projView.setSelectedHandle("88243afbe5ed8")
# Middle-click the selected item
- theItem = nwGUI.treeView.projTree._getTreeItem("88243afbe5ed8")
- theRect = nwGUI.treeView.projTree.visualItemRect(theItem)
- qtbot.mouseClick(nwGUI.treeView.projTree.viewport(), Qt.MidButton, pos=theRect.center())
+ theItem = nwGUI.projView.projTree._getTreeItem("88243afbe5ed8")
+ theRect = nwGUI.projView.projTree.visualItemRect(theItem)
+ qtbot.mouseClick(nwGUI.projView.projTree.viewport(), Qt.MidButton, pos=theRect.center())
assert nwGUI.docViewer.docHandle() == "88243afbe5ed8"
# Reload the text
@@ -117,7 +117,7 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
assert nwGUI.docViewer.docAction(nwDocAction.COPY) is False
# Open again via menu
- assert nwGUI.treeView.setSelectedHandle("88243afbe5ed8")
+ assert nwGUI.projView.setSelectedHandle("88243afbe5ed8")
nwGUI.mainMenu.aViewDoc.activate(QAction.Trigger)
# Select "Bod" link
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index ab3a1141..02c97617 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -125,7 +125,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
with monkeypatch.context() as mp:
mp.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
assert nwGUI.docEditor.docHandle() is None
- nwGUI.treeView.projTree._getTreeItem(sHandle).setSelected(True)
+ nwGUI.projView.projTree._getTreeItem(sHandle).setSelected(True)
nwGUI._keyPressReturn()
assert nwGUI.docEditor.docHandle() == sHandle
assert nwGUI.closeDocument() is True
@@ -149,10 +149,10 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
with monkeypatch.context() as mp:
mp.setattr(GuiOutline, "treeFocus", lambda *a: True)
assert nwGUI.docEditor.docHandle() is None
- actItem = nwGUI.projView.outlineView.topLevelItem(0)
+ actItem = nwGUI.outlineView.outlineView.topLevelItem(0)
chpItem = actItem.child(0)
selItem = chpItem.child(0)
- nwGUI.projView.outlineView.setCurrentItem(selItem)
+ nwGUI.outlineView.outlineView.setCurrentItem(selItem)
nwGUI._keyPressReturn()
assert nwGUI.docEditor.docHandle() == sHandle
assert nwGUI.closeDocument() is True
@@ -220,14 +220,14 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
assert nwGUI.theProject.spellCheck is False
# Check that tree items have been created
- assert nwGUI.treeView.projTree._getTreeItem("0000000000008") is not None
- assert nwGUI.treeView.projTree._getTreeItem("0000000000009") is not None
- assert nwGUI.treeView.projTree._getTreeItem("000000000000a") is not None
- assert nwGUI.treeView.projTree._getTreeItem("000000000000b") is not None
- assert nwGUI.treeView.projTree._getTreeItem("000000000000c") is not None
- assert nwGUI.treeView.projTree._getTreeItem("000000000000d") is not None
- assert nwGUI.treeView.projTree._getTreeItem("000000000000e") is not None
- assert nwGUI.treeView.projTree._getTreeItem("000000000000f") is not None
+ assert nwGUI.projView.projTree._getTreeItem("0000000000008") is not None
+ assert nwGUI.projView.projTree._getTreeItem("0000000000009") is not None
+ assert nwGUI.projView.projTree._getTreeItem("000000000000a") is not None
+ assert nwGUI.projView.projTree._getTreeItem("000000000000b") is not None
+ assert nwGUI.projView.projTree._getTreeItem("000000000000c") is not None
+ assert nwGUI.projView.projTree._getTreeItem("000000000000d") is not None
+ assert nwGUI.projView.projTree._getTreeItem("000000000000e") is not None
+ assert nwGUI.projView.projTree._getTreeItem("000000000000f") is not None
nwGUI.mainMenu.aSpellCheck.setChecked(True)
assert nwGUI.mainMenu._toggleSpellCheck()
@@ -240,9 +240,9 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
# Add a Character File
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem("000000000000a").setSelected(True)
- nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem("000000000000a").setSelected(True)
+ nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
assert nwGUI.openSelectedItem()
# Type something into the document
@@ -262,9 +262,9 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
# Add a Plot File
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem("0000000000009").setSelected(True)
- nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem("0000000000009").setSelected(True)
+ nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
assert nwGUI.openSelectedItem()
# Type something into the document
@@ -284,9 +284,9 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
# Add a World File
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem("000000000000b").setSelected(True)
- nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem("000000000000b").setSelected(True)
+ nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
assert nwGUI.openSelectedItem()
# Add Some Text
@@ -315,10 +315,10 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
# Select the 'New Scene' file
nwGUI.switchFocus(nwWidget.TREE)
- nwGUI.treeView.projTree.clearSelection()
- nwGUI.treeView.projTree._getTreeItem("0000000000008").setExpanded(True)
- nwGUI.treeView.projTree._getTreeItem("000000000000d").setExpanded(True)
- nwGUI.treeView.projTree._getTreeItem("000000000000f").setSelected(True)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem("0000000000008").setExpanded(True)
+ nwGUI.projView.projTree._getTreeItem("000000000000d").setExpanded(True)
+ nwGUI.projView.projTree._getTreeItem("000000000000f").setSelected(True)
assert nwGUI.openSelectedItem()
# Type something into the document
@@ -461,12 +461,12 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
qtbot.wait(stepDelay)
# Check a Quick Create and Delete
- assert nwGUI.treeView.projTree.newTreeItem(nwItemType.FILE, None)
- newHandle = nwGUI.treeView.getSelectedHandle()
+ assert nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None)
+ newHandle = nwGUI.projView.getSelectedHandle()
assert nwGUI.theProject.tree["0000000000020"] is not None
- assert nwGUI.treeView.deleteItem()
- assert nwGUI.treeView.setSelectedHandle(newHandle)
- assert nwGUI.treeView.deleteItem()
+ assert nwGUI.projView.deleteItem()
+ assert nwGUI.projView.setSelectedHandle(newHandle)
+ assert nwGUI.projView.deleteItem()
assert nwGUI.theProject.tree["0000000000024"] is not None # Trash
assert nwGUI.saveProject()
diff --git a/tests/test_gui/test_gui_mainmenu.py b/tests/test_gui/test_gui_mainmenu.py
index 274746d7..f579a1a0 100644
--- a/tests/test_gui/test_gui_mainmenu.py
+++ b/tests/test_gui/test_gui_mainmenu.py
@@ -467,7 +467,7 @@ def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncDir, fncProj, mockRnd):
buildTestProject(nwGUI, fncProj)
- assert nwGUI.treeView.projTree._getTreeItem("000000000000f") is not None
+ assert nwGUI.projView.projTree._getTreeItem("000000000000f") is not None
assert nwGUI.openDocument("000000000000f") is True
nwGUI.docEditor.clear()
diff --git a/tests/test_gui/test_gui_outline.py b/tests/test_gui/test_gui_outline.py
index 49a86b16..c8aa893d 100644
--- a/tests/test_gui/test_gui_outline.py
+++ b/tests/test_gui/test_gui_outline.py
@@ -46,7 +46,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, fncDir):
nwGUI.rebuildIndex()
nwGUI._changeView(nwView.OUTLINE)
- outlineMain = nwGUI.projView
+ outlineMain = nwGUI.outlineView
outlineView = outlineMain.outlineView
outlineData = outlineMain.outlineData
outlineMenu = outlineMain.outlineBar.mColumns
@@ -54,7 +54,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, fncDir):
# Toggle scrollbars
nwGUI.mainConf.hideVScroll = True
nwGUI.mainConf.hideHScroll = True
- nwGUI.projView.initOutline()
+ outlineMain.initOutline()
assert outlineView.verticalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
assert outlineView.horizontalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
assert outlineData.verticalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
@@ -62,7 +62,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, fncDir):
nwGUI.mainConf.hideVScroll = False
nwGUI.mainConf.hideHScroll = False
- nwGUI.projView.initOutline()
+ outlineMain.initOutline()
assert outlineView.verticalScrollBarPolicy() == Qt.ScrollBarAsNeeded
assert outlineView.horizontalScrollBarPolicy() == Qt.ScrollBarAsNeeded
assert outlineData.verticalScrollBarPolicy() == Qt.ScrollBarAsNeeded
@@ -169,8 +169,8 @@ def testGuiOutline_Content(qtbot, monkeypatch, nwGUI, nwLipsum):
nwGUI.rebuildIndex()
nwGUI._changeView(nwView.OUTLINE)
- outlineMain = nwGUI.projView
- outlineBar = outlineMain.outlineBar
+ outlineMain = nwGUI.outlineView
+ outlineBar = outlineMain.outlineBar
outlineView = outlineMain.outlineView
outlineData = outlineMain.outlineData
@@ -183,7 +183,7 @@ def testGuiOutline_Content(qtbot, monkeypatch, nwGUI, nwLipsum):
# Add a second novel folder
newHandle = nwGUI.theProject.newRoot(nwItemClass.NOVEL)
- nwGUI.treeView.revealNewTreeItem(newHandle)
+ nwGUI.projView.revealNewTreeItem(newHandle)
# Check new values in dropdown list
assert outlineBar.novelValue.itemData(0) == lipHandle
@@ -202,7 +202,7 @@ def testGuiOutline_Content(qtbot, monkeypatch, nwGUI, nwLipsum):
aHandle = nwGUI.theProject.newFile(dTitle, newHandle)
hHash = "#"*hLevel
writeFile(os.path.join(nwLipsum, "content", f"{aHandle}.nwd"), f"{hHash} {dTitle}\n\n")
- nwGUI.treeView.revealNewTreeItem(aHandle)
+ nwGUI.projView.revealNewTreeItem(aHandle)
nwGUI.rebuildIndex()
@@ -248,7 +248,7 @@ def testGuiOutline_Content(qtbot, monkeypatch, nwGUI, nwLipsum):
# Click POV Link
assert outlineData.povKeyValue.text() == "Bod"
- nwGUI.projView._tagClicked("Bod")
+ outlineMain._tagClicked("Bod")
assert nwGUI.docViewer.docHandle() == "4c4f28287af27"
# Scene One, Section Two
diff --git a/tests/test_gui/test_gui_projtree.py b/tests/test_gui/test_gui_projtree.py
index 7b6d2f42..b3206aa5 100644
--- a/tests/test_gui/test_gui_projtree.py
+++ b/tests/test_gui/test_gui_projtree.py
@@ -41,7 +41,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
- nwTree = nwGUI.treeView
+ nwTree = nwGUI.projView
# Try to add item with no project
assert nwTree.projTree.newTreeItem(nwItemType.FILE) is False
@@ -164,7 +164,7 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
- nwTree = nwGUI.treeView
+ nwTree = nwGUI.projView
# Try to move item with no project
assert nwTree.projTree.moveTreeItem(1) is False
@@ -279,7 +279,7 @@ def testGuiProjTree_DeleteItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
- nwTree = nwGUI.treeView
+ nwTree = nwGUI.projView
# Try to run with no project
assert nwTree.emptyTrash() is False
@@ -482,7 +482,7 @@ def testGuiProjTree_ContextMenu(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
hCharNote = "0000000000011"
hNovelNote = "0000000000012"
- projTree = nwGUI.treeView.projTree
+ projTree = nwGUI.projView.projTree
projTree._getTreeItem(hNovelRoot).setExpanded(True)
projTree._getTreeItem(hChapterDir).setExpanded(True)
diff --git a/tests/test_gui/test_gui_statusbar.py b/tests/test_gui/test_gui_statusbar.py
index 51e9c70b..0c6b1e81 100644
--- a/tests/test_gui/test_gui_statusbar.py
+++ b/tests/test_gui/test_gui_statusbar.py
@@ -40,7 +40,7 @@ def testGuiStatusBar_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
cHandle = nwGUI.theProject.newFile("A Note", "000000000000a")
newDoc = NWDoc(nwGUI.theProject, cHandle)
newDoc.writeDocument("# A Note\n\n")
- nwGUI.treeView.revealNewTreeItem(cHandle)
+ nwGUI.projView.revealNewTreeItem(cHandle)
nwGUI.rebuildIndex(beQuiet=True)
# Reference Time
From db01d85f2e9d0f39f38468344e20cf3808206a53 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 11 Jun 2022 15:59:08 +0200
Subject: [PATCH 16/35] Rename outline components
---
novelwriter/gui/__init__.py | 4 +-
novelwriter/gui/outline.py | 42 +++++------
novelwriter/guimain.py | 4 +-
tests/test_gui/test_gui_guimain.py | 8 +--
tests/test_gui/test_gui_outline.py | 108 ++++++++++++++---------------
5 files changed, 83 insertions(+), 83 deletions(-)
diff --git a/novelwriter/gui/__init__.py b/novelwriter/gui/__init__.py
index 9560df1b..1892e83d 100644
--- a/novelwriter/gui/__init__.py
+++ b/novelwriter/gui/__init__.py
@@ -24,7 +24,7 @@ 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.outline import GuiOutline
+from novelwriter.gui.outline import GuiOutlineView
from novelwriter.gui.projtree import GuiProjectView
from novelwriter.gui.statusbar import GuiMainStatus
from novelwriter.gui.theme import GuiTheme
@@ -38,7 +38,7 @@ __all__ = [
"GuiMainMenu",
"GuiMainStatus",
"GuiNovelTree",
- "GuiOutline",
+ "GuiOutlineView",
"GuiProjectView",
"GuiTheme",
"GuiViewsBar",
diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py
index d2b2eb04..e3283ead 100644
--- a/novelwriter/gui/outline.py
+++ b/novelwriter/gui/outline.py
@@ -4,9 +4,9 @@ novelWriter – GUI Project Outline
GUI class for the project outline view
File History:
-Created: 2022-05-15 [1.7b1] GuiOutline
+Created: 2022-05-15 [1.7b1] GuiOutlineView
Created: 2022-05-22 [1.7b1] GuiOutlineToolBar
-Created: 2019-11-16 [0.4.1] GuiOutlineView
+Created: 2019-11-16 [0.4.1] GuiOutlineTree
Created: 2019-11-16 [0.4.1] GuiOutlineHeaderMenu
Created: 2020-06-02 [0.7.0] GuiOutlineDetails
@@ -52,7 +52,7 @@ from novelwriter.constants import trConst, nwKeyWords, nwLabels
logger = logging.getLogger(__name__)
-class GuiOutline(QWidget):
+class GuiOutlineView(QWidget):
loadDocumentTagRequest = pyqtSignal(str, Enum)
@@ -64,11 +64,11 @@ class GuiOutline(QWidget):
# Build GUI
self.outlineBar = GuiOutlineToolBar(self)
- self.outlineView = GuiOutlineView(self)
+ self.outlineTree = GuiOutlineTree(self)
self.outlineData = GuiOutlineDetails(self)
self.splitOutline = QSplitter(Qt.Vertical)
- self.splitOutline.addWidget(self.outlineView)
+ self.splitOutline.addWidget(self.outlineTree)
self.splitOutline.addWidget(self.outlineData)
self.splitOutline.setSizes(self.mainConf.getOutlinePanePos())
@@ -81,14 +81,14 @@ class GuiOutline(QWidget):
self.setLayout(self.outerBox)
# Connect Signals
- self.outlineView.hiddenStateChanged.connect(self._updateMenuColumns)
- self.outlineView.activeItemChanged.connect(self.outlineData.showItem)
+ self.outlineTree.hiddenStateChanged.connect(self._updateMenuColumns)
+ self.outlineTree.activeItemChanged.connect(self.outlineData.showItem)
self.outlineData.itemTagClicked.connect(self._tagClicked)
self.outlineBar.loadNovelRootRequest.connect(self._rootItemChanged)
- self.outlineBar.viewColumnToggled.connect(self.outlineView.menuColumnToggled)
+ self.outlineBar.viewColumnToggled.connect(self.outlineTree.menuColumnToggled)
# Function Mappings
- self.getSelectedHandle = self.outlineView.getSelectedHandle
+ self.getSelectedHandle = self.outlineTree.getSelectedHandle
return
@@ -104,24 +104,24 @@ class GuiOutline(QWidget):
return
def initOutline(self):
- self.outlineView.initOutline()
+ self.outlineTree.initOutline()
self.outlineData.initDetails()
return
def closeOutline(self):
- self.outlineView.closeOutline()
+ self.outlineTree.closeOutline()
self.outlineData.updateClasses()
return
def refreshView(self, overRide=False, novelChanged=False):
- self.outlineView.refreshTree(overRide=overRide, novelChanged=novelChanged)
+ self.outlineTree.refreshTree(overRide=overRide, novelChanged=novelChanged)
return
def treeFocus(self):
- return self.outlineView.hasFocus()
+ return self.outlineTree.hasFocus()
def setTreeFocus(self):
- return self.outlineView.setFocus()
+ return self.outlineTree.setFocus()
##
# Public Slots
@@ -145,7 +145,7 @@ class GuiOutline(QWidget):
checkboxes whenever a signal is received that the hidden state
of columns has changed.
"""
- self.outlineBar.setColumnHiddenState(self.outlineView.hiddenColumns)
+ self.outlineBar.setColumnHiddenState(self.outlineTree.hiddenColumns)
return
@pyqtSlot(str)
@@ -160,10 +160,10 @@ class GuiOutline(QWidget):
def _rootItemChanged(self, handle):
"""The root novel handle has changed or needs to be refreshed.
"""
- self.outlineView.refreshTree(rootHandle=(handle or None), overRide=True)
+ self.outlineTree.refreshTree(rootHandle=(handle or None), overRide=True)
return
-# END Class GuiOutline
+# END Class GuiOutlineView
class GuiOutlineToolBar(QToolBar):
@@ -271,7 +271,7 @@ class GuiOutlineToolBar(QToolBar):
# END Class GuiOutlineToolBar
-class GuiOutlineView(QTreeWidget):
+class GuiOutlineTree(QTreeWidget):
DEF_WIDTH = {
nwOutline.TITLE: 200,
@@ -319,7 +319,7 @@ class GuiOutlineView(QTreeWidget):
def __init__(self, theOutline):
QTreeWidget.__init__(self, theOutline)
- logger.debug("Initialising GuiOutlineView ...")
+ logger.debug("Initialising GuiOutlineTree ...")
self.mainConf = novelwriter.CONFIG
self.mainGui = theOutline.mainGui
@@ -355,7 +355,7 @@ class GuiOutlineView(QTreeWidget):
self.hiddenStateChanged.emit()
- logger.debug("GuiOutlineView initialisation complete")
+ logger.debug("GuiOutlineTree initialisation complete")
return
@@ -717,7 +717,7 @@ class GuiOutlineView(QTreeWidget):
return newItem
-# END Class GuiOutlineView
+# END Class GuiOutlineTree
class GuiOutlineHeaderMenu(QMenu):
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 24c2180d..8c0e0e51 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -40,7 +40,7 @@ from PyQt5.QtWidgets import (
from novelwriter.gui import (
GuiDocEditor, GuiDocViewDetails, GuiDocViewer, GuiItemDetails, GuiMainMenu,
- GuiMainStatus, GuiNovelTree, GuiOutline, GuiProjectView, GuiTheme,
+ GuiMainStatus, GuiNovelTree, GuiOutlineView, GuiProjectView, GuiTheme,
GuiViewsBar
)
from novelwriter.dialogs import (
@@ -111,7 +111,7 @@ class GuiMain(QMainWindow):
self.viewMeta = GuiDocViewDetails(self)
self.docViewer = GuiDocViewer(self)
self.itemDetails = GuiItemDetails(self)
- self.outlineView = GuiOutline(self)
+ self.outlineView = GuiOutlineView(self)
self.mainMenu = GuiMainMenu(self)
self.viewsBar = GuiViewsBar(self)
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index 02c97617..cf38c7ea 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -28,7 +28,7 @@ from tools import cmpFiles, buildTestProject, XML_IGNORE, writeFile
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMessageBox, QDialog, QInputDialog
-from novelwriter.gui import GuiDocEditor, GuiNovelTree, GuiOutline
+from novelwriter.gui import GuiDocEditor, GuiNovelTree, GuiOutlineView
from novelwriter.enum import nwItemType, nwWidget
from novelwriter.tools import GuiProjectWizard
from novelwriter.gui.projtree import GuiProjectTree
@@ -147,12 +147,12 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Project Outline has focus
nwGUI.switchFocus(nwWidget.OUTLINE)
with monkeypatch.context() as mp:
- mp.setattr(GuiOutline, "treeFocus", lambda *a: True)
+ mp.setattr(GuiOutlineView, "treeFocus", lambda *a: True)
assert nwGUI.docEditor.docHandle() is None
- actItem = nwGUI.outlineView.outlineView.topLevelItem(0)
+ actItem = nwGUI.outlineView.outlineTree.topLevelItem(0)
chpItem = actItem.child(0)
selItem = chpItem.child(0)
- nwGUI.outlineView.outlineView.setCurrentItem(selItem)
+ nwGUI.outlineView.outlineTree.setCurrentItem(selItem)
nwGUI._keyPressReturn()
assert nwGUI.docEditor.docHandle() == sHandle
assert nwGUI.closeDocument() is True
diff --git a/tests/test_gui/test_gui_outline.py b/tests/test_gui/test_gui_outline.py
index c8aa893d..1038404a 100644
--- a/tests/test_gui/test_gui_outline.py
+++ b/tests/test_gui/test_gui_outline.py
@@ -46,57 +46,57 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, fncDir):
nwGUI.rebuildIndex()
nwGUI._changeView(nwView.OUTLINE)
- outlineMain = nwGUI.outlineView
- outlineView = outlineMain.outlineView
- outlineData = outlineMain.outlineData
- outlineMenu = outlineMain.outlineBar.mColumns
+ outlineView = nwGUI.outlineView
+ outlineTree = outlineView.outlineTree
+ outlineData = outlineView.outlineData
+ outlineMenu = outlineView.outlineBar.mColumns
# Toggle scrollbars
nwGUI.mainConf.hideVScroll = True
nwGUI.mainConf.hideHScroll = True
- outlineMain.initOutline()
- assert outlineView.verticalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
- assert outlineView.horizontalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
+ outlineView.initOutline()
+ assert outlineTree.verticalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
+ assert outlineTree.horizontalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
assert outlineData.verticalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
assert outlineData.horizontalScrollBarPolicy() == Qt.ScrollBarAlwaysOff
nwGUI.mainConf.hideVScroll = False
nwGUI.mainConf.hideHScroll = False
- outlineMain.initOutline()
- assert outlineView.verticalScrollBarPolicy() == Qt.ScrollBarAsNeeded
- assert outlineView.horizontalScrollBarPolicy() == Qt.ScrollBarAsNeeded
+ outlineView.initOutline()
+ assert outlineTree.verticalScrollBarPolicy() == Qt.ScrollBarAsNeeded
+ assert outlineTree.horizontalScrollBarPolicy() == Qt.ScrollBarAsNeeded
assert outlineData.verticalScrollBarPolicy() == Qt.ScrollBarAsNeeded
assert outlineData.horizontalScrollBarPolicy() == Qt.ScrollBarAsNeeded
# Check focus
with monkeypatch.context() as mp:
mp.setattr(QWidget, "hasFocus", lambda *a: True)
- assert outlineMain.treeFocus() is True
+ assert outlineView.treeFocus() is True
- outlineMain.setTreeFocus() # Can't check. just ensures that it doesn't error
+ outlineView.setTreeFocus() # Can't check. just ensures that it doesn't error
# Option State
# ============
pOptions = nwGUI.theProject.options
colNames = [h.name for h in nwOutline]
colItems = [h for h in nwOutline]
- colWidth = {h: outlineView.DEF_WIDTH[h] for h in nwOutline}
- colHidden = {h: outlineView.DEF_HIDDEN[h] for h in nwOutline}
+ colWidth = {h: outlineTree.DEF_WIDTH[h] for h in nwOutline}
+ colHidden = {h: outlineTree.DEF_HIDDEN[h] for h in nwOutline}
- assert outlineView.topLevelItemCount() > 0
+ assert outlineTree.topLevelItemCount() > 0
# Save header state not allowed
- outlineView._lastBuild = 0
- outlineView._saveHeaderState()
+ outlineTree._lastBuild = 0
+ outlineTree._saveHeaderState()
assert pOptions.getValue("GuiOutline", "headerOrder", []) == []
# Allow saving header state
- outlineView._lastBuild = time.time()
- outlineView._saveHeaderState()
+ outlineTree._lastBuild = time.time()
+ outlineTree._saveHeaderState()
assert pOptions.getValue("GuiOutline", "headerOrder", []) == colNames
- assert outlineView._treeOrder == colItems
- assert outlineView._colWidth == colWidth
- assert outlineView._colHidden == colHidden
+ assert outlineTree._treeOrder == colItems
+ assert outlineTree._colWidth == colWidth
+ assert outlineTree._colHidden == colHidden
# Get default values
optItems = pOptions.getValue("GuiOutline", "headerOrder", [])
@@ -105,49 +105,49 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, fncDir):
# Add invalid column name
pOptions.setValue("GuiOutline", "headerOrder", optItems + ["blabla"])
- outlineView._loadHeaderState()
- assert outlineView._treeOrder == colItems
- assert outlineView._colHidden == colHidden
+ outlineTree._loadHeaderState()
+ assert outlineTree._treeOrder == colItems
+ assert outlineTree._colHidden == colHidden
# Add duplicate column name
pOptions.setValue("GuiOutline", "headerOrder", optItems + [optItems[-1]])
- outlineView._loadHeaderState()
- assert outlineView._treeOrder == colItems
- assert outlineView._colHidden == colHidden
+ outlineTree._loadHeaderState()
+ assert outlineTree._treeOrder == colItems
+ assert outlineTree._colHidden == colHidden
# Invalid column width data
pOptions.setValue("GuiOutline", "headerOrder", optItems)
pOptions.setValue("GuiOutline", "columnWidth", {"blabla": None})
- outlineView._loadHeaderState()
- assert outlineView._treeOrder == colItems
- assert outlineView._colHidden == colHidden
+ outlineTree._loadHeaderState()
+ assert outlineTree._treeOrder == colItems
+ assert outlineTree._colHidden == colHidden
# Invalid column width data
pOptions.setValue("GuiOutline", "headerOrder", optItems)
pOptions.setValue("GuiOutline", "columnWidth", optWidth)
pOptions.setValue("GuiOutline", "columnHidden", {"bloabla": None})
- outlineView._loadHeaderState()
- assert outlineView._treeOrder == colItems
- assert outlineView._colHidden == colHidden
+ outlineTree._loadHeaderState()
+ assert outlineTree._treeOrder == colItems
+ assert outlineTree._colHidden == colHidden
# Valid settings
pOptions.setValue("GuiOutline", "headerOrder", optItems)
pOptions.setValue("GuiOutline", "columnWidth", optWidth)
pOptions.setValue("GuiOutline", "columnHidden", optHidden)
- outlineView._loadHeaderState()
- assert outlineView._treeOrder == colItems
- assert outlineView._colHidden == colHidden
+ outlineTree._loadHeaderState()
+ assert outlineTree._treeOrder == colItems
+ assert outlineTree._colHidden == colHidden
# Header Menu
# ===========
# Trigger the menu entry for all hidden columns
for hItem in nwOutline:
- if outlineView.DEF_HIDDEN[hItem]:
+ if outlineTree.DEF_HIDDEN[hItem]:
outlineMenu.actionMap[hItem].activate(QAction.Trigger)
# Now no columns should be hidden
- outlineView._saveHeaderState()
+ outlineTree._saveHeaderState()
assert not any(pOptions.getValue("GuiOutline", "columnHidden", None).values())
# qtbot.stop()
@@ -169,10 +169,10 @@ def testGuiOutline_Content(qtbot, monkeypatch, nwGUI, nwLipsum):
nwGUI.rebuildIndex()
nwGUI._changeView(nwView.OUTLINE)
- outlineMain = nwGUI.outlineView
- outlineBar = outlineMain.outlineBar
- outlineView = outlineMain.outlineView
- outlineData = outlineMain.outlineData
+ outlineView = nwGUI.outlineView
+ outlineBar = outlineView.outlineBar
+ outlineTree = outlineView.outlineTree
+ outlineData = outlineView.outlineData
lipHandle = "b3643d0f92e32"
@@ -218,10 +218,10 @@ def testGuiOutline_Content(qtbot, monkeypatch, nwGUI, nwLipsum):
# =============
# First Item
- outlineView.refreshTree()
- selItem = outlineView.topLevelItem(0)
+ outlineTree.refreshTree()
+ selItem = outlineTree.topLevelItem(0)
- outlineView.setCurrentItem(selItem)
+ outlineTree.setCurrentItem(selItem)
assert outlineData.titleLabel.text() == "Title"
assert outlineData.titleValue.text() == "Lorem Ipsum"
assert outlineData.fileValue.text() == "Lorem Ipsum"
@@ -232,12 +232,12 @@ def testGuiOutline_Content(qtbot, monkeypatch, nwGUI, nwLipsum):
assert outlineData.pCValue.text() == "3"
# Scene One
- actItem = outlineView.topLevelItem(1)
+ actItem = outlineTree.topLevelItem(1)
chpItem = actItem.child(0)
selItem = chpItem.child(0)
- outlineView.setCurrentItem(selItem)
- tHandle, tLine = outlineView.getSelectedHandle()
+ outlineTree.setCurrentItem(selItem)
+ tHandle, tLine = outlineTree.getSelectedHandle()
assert tHandle == "88243afbe5ed8"
assert tLine == 0
@@ -248,17 +248,17 @@ def testGuiOutline_Content(qtbot, monkeypatch, nwGUI, nwLipsum):
# Click POV Link
assert outlineData.povKeyValue.text() == "Bod"
- outlineMain._tagClicked("Bod")
+ outlineView._tagClicked("Bod")
assert nwGUI.docViewer.docHandle() == "4c4f28287af27"
# Scene One, Section Two
- actItem = outlineView.topLevelItem(1)
+ actItem = outlineTree.topLevelItem(1)
chpItem = actItem.child(0)
scnItem = chpItem.child(0)
selItem = scnItem.child(0)
- outlineView.setCurrentItem(selItem)
- tHandle, tLine = outlineView.getSelectedHandle()
+ outlineTree.setCurrentItem(selItem)
+ tHandle, tLine = outlineTree.getSelectedHandle()
assert tHandle == "88243afbe5ed8"
assert tLine == 12
@@ -267,7 +267,7 @@ def testGuiOutline_Content(qtbot, monkeypatch, nwGUI, nwLipsum):
assert outlineData.fileValue.text() == "Scene One"
assert outlineData.itemValue.text() == "Finished"
- outlineView._treeDoubleClick(selItem, 0)
+ outlineTree._treeDoubleClick(selItem, 0)
assert nwGUI.docEditor.docHandle() == "88243afbe5ed8"
# qtbot.stop()
From 985179bbb9c63a7863a77255a2d98bf0e241862f Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 11 Jun 2022 16:29:49 +0200
Subject: [PATCH 17/35] Rename main theme object
---
novelwriter/dialogs/about.py | 54 +++++++-------
novelwriter/dialogs/docmerge.py | 2 +-
novelwriter/dialogs/docsplit.py | 2 +-
novelwriter/dialogs/preferences.py | 70 +++++++++---------
novelwriter/dialogs/projdetails.py | 12 ++--
novelwriter/dialogs/projload.py | 12 ++--
novelwriter/dialogs/projsettings.py | 22 +++---
novelwriter/dialogs/updates.py | 2 +-
novelwriter/dialogs/wordlist.py | 6 +-
novelwriter/gui/doceditor.py | 90 +++++++++++------------
novelwriter/gui/dochighlight.py | 30 ++++----
novelwriter/gui/docviewer.py | 104 +++++++++++++--------------
novelwriter/gui/itemdetails.py | 20 +++---
novelwriter/gui/noveltree.py | 6 +-
novelwriter/gui/outline.py | 24 +++----
novelwriter/gui/projtree.py | 34 ++++-----
novelwriter/gui/statusbar.py | 20 +++---
novelwriter/gui/theme.py | 16 ++---
novelwriter/gui/viewsbar.py | 24 +++----
novelwriter/guimain.py | 4 +-
novelwriter/tools/build.py | 18 ++---
novelwriter/tools/lipsum.py | 8 +--
novelwriter/tools/projwizard.py | 16 ++---
novelwriter/tools/writingstats.py | 28 ++++----
tests/test_dialogs/test_dlg_about.py | 4 +-
tests/test_gui/test_gui_theme.py | 64 ++++++++---------
26 files changed, 346 insertions(+), 346 deletions(-)
diff --git a/novelwriter/dialogs/about.py b/novelwriter/dialogs/about.py
index 83e3c347..9cf43daf 100644
--- a/novelwriter/dialogs/about.py
+++ b/novelwriter/dialogs/about.py
@@ -49,9 +49,9 @@ class GuiAbout(QDialog):
logger.debug("Initialising GuiAbout ...")
self.setObjectName("GuiAbout")
- self.mainConf = novelwriter.CONFIG
- self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.mainTheme = mainGui.mainTheme
self.outerBox = QVBoxLayout()
self.innerBox = QHBoxLayout()
@@ -63,7 +63,7 @@ class GuiAbout(QDialog):
nPx = self.mainConf.pxInt(96)
self.nwIcon = QLabel()
- self.nwIcon.setPixmap(self.mainGui.theTheme.getPixmap("novelwriter", (nPx, nPx)))
+ self.nwIcon.setPixmap(self.mainGui.mainTheme.getPixmap("novelwriter", (nPx, nPx)))
self.lblName = QLabel("novelWriter")
self.lblVers = QLabel(f"v{novelwriter.__version__}")
self.lblDate = QLabel(datetime.strptime(novelwriter.__date__, "%Y-%m-%d").strftime("%x"))
@@ -191,37 +191,37 @@ class GuiAbout(QDialog):
])
)
- theTheme = self.mainGui.theTheme
- theIcons = self.mainGui.theTheme.theIcons
- if theTheme.themeName and theTheme.themeAuthor != "N/A":
- licURL = f"{theTheme.themeLicense}"
+ mainTheme = self.mainGui.mainTheme
+ iconCache = self.mainGui.mainTheme.iconCache
+ if mainTheme.themeName and mainTheme.themeAuthor != "N/A":
+ licURL = f"{mainTheme.themeLicense}"
aboutMsg += "{0}
{1}
".format(
- self.tr("Theme: {0}").format(theTheme.themeName),
+ self.tr("Theme: {0}").format(mainTheme.themeName),
self._wrapTable([
- (self.tr("Author"), theTheme.themeAuthor),
- (self.tr("Credit"), theTheme.themeCredit),
+ (self.tr("Author"), mainTheme.themeAuthor),
+ (self.tr("Credit"), mainTheme.themeCredit),
(self.tr("Licence"), licURL),
])
)
- if theIcons.themeName:
- licURL = f"{theIcons.themeLicense}"
+ if iconCache.themeName:
+ licURL = f"{iconCache.themeLicense}"
aboutMsg += "{0}
{1}
".format(
- self.tr("Icons: {0}").format(theIcons.themeName),
+ self.tr("Icons: {0}").format(iconCache.themeName),
self._wrapTable([
- (self.tr("Author"), theIcons.themeAuthor),
- (self.tr("Credit"), theIcons.themeCredit),
+ (self.tr("Author"), iconCache.themeAuthor),
+ (self.tr("Credit"), iconCache.themeCredit),
(self.tr("Licence"), licURL),
])
)
- if theTheme.syntaxName:
- licURL = f"{theTheme.syntaxLicense}"
+ if mainTheme.syntaxName:
+ licURL = f"{mainTheme.syntaxLicense}"
aboutMsg += "{0}
{1}
".format(
- self.tr("Syntax: {0}").format(theTheme.syntaxName),
+ self.tr("Syntax: {0}").format(mainTheme.syntaxName),
self._wrapTable([
- (self.tr("Author"), theTheme.syntaxAuthor),
- (self.tr("Credit"), theTheme.syntaxCredit),
+ (self.tr("Author"), mainTheme.syntaxAuthor),
+ (self.tr("Credit"), mainTheme.syntaxCredit),
(self.tr("Licence"), licURL),
])
)
@@ -279,12 +279,12 @@ class GuiAbout(QDialog):
" padding-right: 0.8em;"
"}}\n"
).format(
- hColR=self.mainGui.theTheme.colHead[0],
- hColG=self.mainGui.theTheme.colHead[1],
- hColB=self.mainGui.theTheme.colHead[2],
- kColR=self.theTheme.colKey[0],
- kColG=self.theTheme.colKey[1],
- kColB=self.theTheme.colKey[2],
+ hColR=self.mainGui.mainTheme.colHead[0],
+ hColG=self.mainGui.mainTheme.colHead[1],
+ hColB=self.mainGui.mainTheme.colHead[2],
+ kColR=self.mainTheme.colKey[0],
+ kColG=self.mainTheme.colKey[1],
+ kColB=self.mainTheme.colKey[2],
)
self.pageAbout.document().setDefaultStyleSheet(styleSheet)
self.pageNotes.document().setDefaultStyleSheet(styleSheet)
diff --git a/novelwriter/dialogs/docmerge.py b/novelwriter/dialogs/docmerge.py
index 96a357f4..30eb602f 100644
--- a/novelwriter/dialogs/docmerge.py
+++ b/novelwriter/dialogs/docmerge.py
@@ -57,7 +57,7 @@ class GuiDocMerge(QDialog):
self.headLabel = QLabel("{0}".format(self.tr("Documents to Merge")))
self.helpLabel = QHelpLabel(
- self.tr("Drag and drop items to change the order."), self.mainGui.theTheme.helpText
+ self.tr("Drag and drop items to change the order."), self.mainGui.mainTheme.helpText
)
self.listBox = QListWidget()
diff --git a/novelwriter/dialogs/docsplit.py b/novelwriter/dialogs/docsplit.py
index c2d51c8e..b507479e 100644
--- a/novelwriter/dialogs/docsplit.py
+++ b/novelwriter/dialogs/docsplit.py
@@ -60,7 +60,7 @@ class GuiDocSplit(QDialog):
self.headLabel = QLabel("{0}".format(self.tr("Document Headers")))
self.helpLabel = QHelpLabel(
self.tr("Select the maximum level to split into files."),
- self.mainGui.theTheme.helpText
+ self.mainGui.mainTheme.helpText
)
self.listBox = QListWidget()
diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py
index e0fd41e8..f807fde1 100644
--- a/novelwriter/dialogs/preferences.py
+++ b/novelwriter/dialogs/preferences.py
@@ -141,13 +141,13 @@ class GuiPreferencesGeneral(QWidget):
def __init__(self, mainGui):
QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.mainTheme = mainGui.mainTheme
# The Form
self.mainForm = QConfigLayout()
- self.mainForm.setHelpTextStyle(self.theTheme.helpText)
+ self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
self.setLayout(self.mainForm)
# Look and Feel
@@ -174,7 +174,7 @@ class GuiPreferencesGeneral(QWidget):
# Select Theme
self.guiTheme = QComboBox()
self.guiTheme.setMinimumWidth(minWidth)
- self.theThemes = self.theTheme.listThemes()
+ self.theThemes = self.mainTheme.listThemes()
for themeDir, themeName in self.theThemes:
self.guiTheme.addItem(themeName, themeDir)
themeIdx = self.guiTheme.findData(self.mainConf.guiTheme)
@@ -190,8 +190,8 @@ class GuiPreferencesGeneral(QWidget):
# Select Icon Theme
self.guiIcons = QComboBox()
self.guiIcons.setMinimumWidth(minWidth)
- self.theIcons = self.theTheme.theIcons.listThemes()
- for iconDir, iconName in self.theIcons:
+ self.iconCache = self.mainTheme.iconCache.listThemes()
+ for iconDir, iconName in self.iconCache:
self.guiIcons.addItem(iconName, iconDir)
iconIdx = self.guiIcons.findData(self.mainConf.guiIcons)
if iconIdx != -1:
@@ -206,7 +206,7 @@ class GuiPreferencesGeneral(QWidget):
# Editor Theme
self.guiSyntax = QComboBox()
self.guiSyntax.setMinimumWidth(self.mainConf.pxInt(200))
- self.theSyntaxes = self.theTheme.listSyntax()
+ self.theSyntaxes = self.mainTheme.listSyntax()
for syntaxFile, syntaxName in self.theSyntaxes:
self.guiSyntax.addItem(syntaxName, syntaxFile)
syntaxIdx = self.guiSyntax.findData(self.mainConf.guiSyntax)
@@ -225,7 +225,7 @@ class GuiPreferencesGeneral(QWidget):
self.guiFont.setFixedWidth(self.mainConf.pxInt(162))
self.guiFont.setText(self.mainConf.guiFont)
self.fontButton = QPushButton("...")
- self.fontButton.setMaximumWidth(int(2.5*self.theTheme.getTextWidth("...")))
+ self.fontButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
self.fontButton.clicked.connect(self._selectFont)
self.mainForm.addRow(
self.tr("Font family"),
@@ -347,13 +347,13 @@ class GuiPreferencesProjects(QWidget):
def __init__(self, mainGui):
QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.mainTheme = mainGui.mainTheme
# The Form
self.mainForm = QConfigLayout()
- self.mainForm.setHelpTextStyle(self.theTheme.helpText)
+ self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
self.setLayout(self.mainForm)
# Automatic Save
@@ -508,13 +508,13 @@ class GuiPreferencesDocuments(QWidget):
def __init__(self, mainGui):
QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.mainTheme = mainGui.mainTheme
# The Form
self.mainForm = QConfigLayout()
- self.mainForm.setHelpTextStyle(self.theTheme.helpText)
+ self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
self.setLayout(self.mainForm)
# Text Style
@@ -527,7 +527,7 @@ class GuiPreferencesDocuments(QWidget):
self.textFont.setFixedWidth(self.mainConf.pxInt(162))
self.textFont.setText(self.mainConf.textFont)
self.fontButton = QPushButton("...")
- self.fontButton.setMaximumWidth(int(2.5*self.theTheme.getTextWidth("...")))
+ self.fontButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
self.fontButton.clicked.connect(self._selectFont)
self.mainForm.addRow(
self.tr("Font family"),
@@ -669,13 +669,13 @@ class GuiPreferencesEditor(QWidget):
def __init__(self, mainGui):
QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.mainTheme = mainGui.mainTheme
# The Form
self.mainForm = QConfigLayout()
- self.mainForm.setHelpTextStyle(self.theTheme.helpText)
+ self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
self.setLayout(self.mainForm)
mW = self.mainConf.pxInt(250)
@@ -843,13 +843,13 @@ class GuiPreferencesSyntax(QWidget):
def __init__(self, mainGui):
QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.mainTheme = mainGui.mainTheme
# The Form
self.mainForm = QConfigLayout()
- self.mainForm.setHelpTextStyle(self.theTheme.helpText)
+ self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
self.setLayout(self.mainForm)
# Quotes & Dialogue
@@ -946,13 +946,13 @@ class GuiPreferencesAutomation(QWidget):
def __init__(self, mainGui):
QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.mainTheme = mainGui.mainTheme
# The Form
self.mainForm = QConfigLayout()
- self.mainForm.setHelpTextStyle(self.theTheme.helpText)
+ self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
self.setLayout(self.mainForm)
# Automatic Features
@@ -1103,13 +1103,13 @@ class GuiPreferencesQuotes(QWidget):
def __init__(self, mainGui):
QWidget.__init__(self, mainGui)
- self.mainConf = novelwriter.CONFIG
- self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.mainTheme = mainGui.mainTheme
# The Form
self.mainForm = QConfigLayout()
- self.mainForm.setHelpTextStyle(self.theTheme.helpText)
+ self.mainForm.setHelpTextStyle(self.mainTheme.helpText)
self.setLayout(self.mainForm)
# Quotation Style
@@ -1117,7 +1117,7 @@ class GuiPreferencesQuotes(QWidget):
self.mainForm.addGroupLabel(self.tr("Quotation Style"))
qWidth = self.mainConf.pxInt(40)
- bWidth = int(2.5*self.theTheme.getTextWidth("..."))
+ bWidth = int(2.5*self.mainTheme.getTextWidth("..."))
self.quoteSym = {}
# Single Quote Style
diff --git a/novelwriter/dialogs/projdetails.py b/novelwriter/dialogs/projdetails.py
index 8ab1943f..e83fc0a4 100644
--- a/novelwriter/dialogs/projdetails.py
+++ b/novelwriter/dialogs/projdetails.py
@@ -145,10 +145,10 @@ class GuiProjectDetailsMain(QWidget):
self.mainConf = novelwriter.CONFIG
self.theProject = theProject
self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
- fPx = self.theTheme.fontPixelSize
- fPt = self.theTheme.fontPointSize
+ fPx = self.mainTheme.fontPixelSize
+ fPt = self.mainTheme.fontPointSize
vPx = self.mainConf.pxInt(4)
hPx = self.mainConf.pxInt(12)
@@ -277,12 +277,12 @@ class GuiProjectDetailsContents(QWidget):
self.mainConf = novelwriter.CONFIG
self.theProject = theProject
self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
# Internal
self._theToC = []
- iPx = self.theTheme.baseIconSize
+ iPx = self.mainTheme.baseIconSize
hPx = self.mainConf.pxInt(12)
vPx = self.mainConf.pxInt(4)
pOptions = self.theProject.options
@@ -469,7 +469,7 @@ class GuiProjectDetailsContents(QWidget):
if tTitle.strip() == "":
tTitle = self.tr("Untitled")
- newItem.setIcon(self.C_TITLE, self.theTheme.getIcon("doc_h%d" % tLevel))
+ newItem.setIcon(self.C_TITLE, self.mainTheme.getIcon("doc_h%d" % tLevel))
newItem.setText(self.C_TITLE, tTitle)
newItem.setText(self.C_WORDS, f"{wCount:n}")
newItem.setText(self.C_PAGES, f"{pCount:n}")
diff --git a/novelwriter/dialogs/projload.py b/novelwriter/dialogs/projload.py
index 6d296980..c7229f44 100644
--- a/novelwriter/dialogs/projload.py
+++ b/novelwriter/dialogs/projload.py
@@ -61,13 +61,13 @@ class GuiProjectLoad(QDialog):
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
self.openState = self.NONE_STATE
self.openPath = None
sPx = self.mainConf.pxInt(16)
nPx = self.mainConf.pxInt(96)
- iPx = self.theTheme.baseIconSize
+ iPx = self.mainTheme.baseIconSize
self.outerBox = QVBoxLayout()
self.innerBox = QHBoxLayout()
@@ -80,7 +80,7 @@ class GuiProjectLoad(QDialog):
self.setModal(True)
self.nwIcon = QLabel()
- self.nwIcon.setPixmap(self.mainGui.theTheme.getPixmap("novelwriter", (nPx, nPx)))
+ self.nwIcon.setPixmap(self.mainGui.mainTheme.getPixmap("novelwriter", (nPx, nPx)))
self.innerBox.addWidget(self.nwIcon, 0, Qt.AlignTop)
self.projectForm = QGridLayout()
@@ -110,7 +110,7 @@ class GuiProjectLoad(QDialog):
self.selPath.setReadOnly(True)
self.browseButton = QPushButton("...")
- self.browseButton.setMaximumWidth(int(2.5*self.theTheme.getTextWidth("...")))
+ self.browseButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
self.browseButton.clicked.connect(self._doBrowse)
self.projectForm.addWidget(self.lblRecent, 0, 0, 1, 3)
@@ -280,7 +280,7 @@ class GuiProjectLoad(QDialog):
sortList = sorted(dataList, key=lambda x: x[1], reverse=True)
for theTitle, theTime, theWords, projPath in sortList:
newItem = QTreeWidgetItem([""]*4)
- newItem.setIcon(self.C_NAME, self.mainGui.theTheme.getIcon("proj_nwx"))
+ newItem.setIcon(self.C_NAME, self.mainGui.mainTheme.getIcon("proj_nwx"))
newItem.setText(self.C_NAME, theTitle)
newItem.setData(self.C_NAME, Qt.UserRole, projPath)
newItem.setText(self.C_COUNT, formatInt(theWords))
@@ -288,7 +288,7 @@ class GuiProjectLoad(QDialog):
newItem.setTextAlignment(self.C_NAME, Qt.AlignLeft | Qt.AlignVCenter)
newItem.setTextAlignment(self.C_COUNT, Qt.AlignRight | Qt.AlignVCenter)
newItem.setTextAlignment(self.C_TIME, Qt.AlignRight | Qt.AlignVCenter)
- newItem.setFont(self.C_TIME, self.theTheme.guiFontFixed)
+ newItem.setFont(self.C_TIME, self.mainTheme.guiFontFixed)
self.listBox.addTopLevelItem(newItem)
if self.listBox.topLevelItemCount() > 0:
diff --git a/novelwriter/dialogs/projsettings.py b/novelwriter/dialogs/projsettings.py
index c7531866..11a640b1 100644
--- a/novelwriter/dialogs/projsettings.py
+++ b/novelwriter/dialogs/projsettings.py
@@ -175,13 +175,13 @@ class GuiProjectEditMain(QWidget):
# The Form
self.mainForm = QConfigLayout()
- self.mainForm.setHelpTextStyle(self.mainGui.theTheme.helpText)
+ self.mainForm.setHelpTextStyle(self.mainGui.mainTheme.helpText)
self.setLayout(self.mainForm)
self.mainForm.addGroupLabel(self.tr("Project Settings"))
xW = self.mainConf.pxInt(250)
- xH = round(4.8*self.mainGui.theTheme.fontPixelSize)
+ xH = round(4.8*self.mainGui.mainTheme.fontPixelSize)
self.editName = QLineEdit()
self.editName.setMaxLength(200)
@@ -262,7 +262,7 @@ class GuiProjectEditStatus(QWidget):
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
self.theProject = theProject
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
if isStatus:
self.theStatus = self.theProject.statusItems
@@ -281,7 +281,7 @@ class GuiProjectEditStatus(QWidget):
self.colChanged = False
self.selColour = QColor(100, 100, 100)
- self.iPx = self.theTheme.baseIconSize
+ self.iPx = self.mainTheme.baseIconSize
# The List
# ========
@@ -300,16 +300,16 @@ class GuiProjectEditStatus(QWidget):
# List Controls
# =============
- self.addButton = QPushButton(self.theTheme.getIcon("add"), "")
+ self.addButton = QPushButton(self.mainTheme.getIcon("add"), "")
self.addButton.clicked.connect(self._newItem)
- self.delButton = QPushButton(self.theTheme.getIcon("remove"), "")
+ self.delButton = QPushButton(self.mainTheme.getIcon("remove"), "")
self.delButton.clicked.connect(self._delItem)
- self.upButton = QPushButton(self.theTheme.getIcon("up"), "")
+ self.upButton = QPushButton(self.mainTheme.getIcon("up"), "")
self.upButton.clicked.connect(lambda: self._moveItem(-1))
- self.dnButton = QPushButton(self.theTheme.getIcon("down"), "")
+ self.dnButton = QPushButton(self.mainTheme.getIcon("down"), "")
self.dnButton.clicked.connect(lambda: self._moveItem(1))
# Edit Form
@@ -532,7 +532,7 @@ class GuiProjectEditReplace(QWidget):
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
self.theProject = theProject
self.arChanged = False
@@ -563,10 +563,10 @@ class GuiProjectEditReplace(QWidget):
# List Controls
# =============
- self.addButton = QPushButton(self.theTheme.getIcon("add"), "")
+ self.addButton = QPushButton(self.mainTheme.getIcon("add"), "")
self.addButton.clicked.connect(self._addEntry)
- self.delButton = QPushButton(self.theTheme.getIcon("remove"), "")
+ self.delButton = QPushButton(self.mainTheme.getIcon("remove"), "")
self.delButton.clicked.connect(self._delEntry)
# Edit Form
diff --git a/novelwriter/dialogs/updates.py b/novelwriter/dialogs/updates.py
index a8f3c8a9..c4782e6d 100644
--- a/novelwriter/dialogs/updates.py
+++ b/novelwriter/dialogs/updates.py
@@ -61,7 +61,7 @@ class GuiUpdates(QDialog):
# Left Box
self.nwIcon = QLabel()
- self.nwIcon.setPixmap(self.mainGui.theTheme.getPixmap("novelwriter", (nPx, nPx)))
+ self.nwIcon.setPixmap(self.mainGui.mainTheme.getPixmap("novelwriter", (nPx, nPx)))
self.leftBox = QVBoxLayout()
self.leftBox.addWidget(self.nwIcon)
diff --git a/novelwriter/dialogs/wordlist.py b/novelwriter/dialogs/wordlist.py
index 172ae846..9a17eed8 100644
--- a/novelwriter/dialogs/wordlist.py
+++ b/novelwriter/dialogs/wordlist.py
@@ -50,7 +50,7 @@ class GuiWordList(QDialog):
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self.setWindowTitle(self.tr("Project Word List"))
@@ -78,10 +78,10 @@ class GuiWordList(QDialog):
self.newEntry = QLineEdit()
- self.addButton = QPushButton(self.theTheme.getIcon("add"), "")
+ self.addButton = QPushButton(self.mainTheme.getIcon("add"), "")
self.addButton.clicked.connect(self._doAdd)
- self.delButton = QPushButton(self.theTheme.getIcon("remove"), "")
+ self.delButton = QPushButton(self.mainTheme.getIcon("remove"), "")
self.delButton.clicked.connect(self._doDelete)
self.editBox = QHBoxLayout()
diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py
index a060f151..ab2c7f2f 100644
--- a/novelwriter/gui/doceditor.py
+++ b/novelwriter/gui/doceditor.py
@@ -80,7 +80,7 @@ class GuiDocEditor(QTextEdit):
# Class Variables
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self._nwDocument = None
@@ -239,10 +239,10 @@ class GuiDocEditor(QTextEdit):
if self.mainConf.textFont is None:
# If none is defined, set a default font
theFont = QFont()
- if self.mainConf.osWindows and "Arial" in self.theTheme.guiFontDB.families():
+ if self.mainConf.osWindows and "Arial" in self.mainTheme.guiFontDB.families():
theFont.setFamily("Arial")
theFont.setPointSize(12)
- elif self.mainConf.osDarwin and "Courier" in self.theTheme.guiFontDB.families():
+ elif self.mainConf.osDarwin and "Courier" in self.mainTheme.guiFontDB.families():
theFont.setFamily("Courier")
theFont.setPointSize(12)
else:
@@ -257,14 +257,14 @@ class GuiDocEditor(QTextEdit):
# Set the widget colours to match syntax theme
mainPalette = self.palette()
- mainPalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack))
- mainPalette.setColor(QPalette.Base, QColor(*self.theTheme.colBack))
- mainPalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
+ mainPalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
+ mainPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
+ mainPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
self.setPalette(mainPalette)
docPalette = self.viewport().palette()
- docPalette.setColor(QPalette.Base, QColor(*self.theTheme.colBack))
- docPalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
+ docPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
+ docPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
self.viewport().setPalette(docPalette)
self.docHeader.matchColours()
@@ -2189,7 +2189,7 @@ class GuiDocEditSearch(QFrame):
self.docEditor = docEditor
self.mainGui = docEditor.mainGui
self.theProject = docEditor.theProject
- self.theTheme = docEditor.theTheme
+ self.mainTheme = docEditor.mainTheme
self.repVisible = False
self.isCaseSense = self.mainConf.searchCase
@@ -2200,9 +2200,9 @@ class GuiDocEditSearch(QFrame):
self.doMatchCap = self.mainConf.searchMatchCap
mPx = self.mainConf.pxInt(6)
- tPx = int(0.8*self.theTheme.fontPixelSize)
- self.boxFont = self.theTheme.guiFont
- self.boxFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
+ tPx = int(0.8*self.mainTheme.fontPixelSize)
+ self.boxFont = self.mainTheme.guiFont
+ self.boxFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
self.setContentsMargins(0, 0, 0, 0)
self.setAutoFillBackground(True)
@@ -2236,38 +2236,38 @@ class GuiDocEditSearch(QFrame):
self.resultLabel = QLabel("?/?")
self.resultLabel.setFont(self.boxFont)
- self.resultLabel.setMinimumWidth(self.theTheme.getTextWidth("?/?", self.boxFont))
+ self.resultLabel.setMinimumWidth(self.mainTheme.getTextWidth("?/?", self.boxFont))
self.toggleCase = QAction(self.tr("Case Sensitive"), self)
- self.toggleCase.setIcon(self.theTheme.getIcon("search_case"))
+ self.toggleCase.setIcon(self.mainTheme.getIcon("search_case"))
self.toggleCase.setCheckable(True)
self.toggleCase.setChecked(self.isCaseSense)
self.toggleCase.toggled.connect(self._doToggleCase)
self.searchOpt.addAction(self.toggleCase)
self.toggleWord = QAction(self.tr("Whole Words Only"), self)
- self.toggleWord.setIcon(self.theTheme.getIcon("search_word"))
+ self.toggleWord.setIcon(self.mainTheme.getIcon("search_word"))
self.toggleWord.setCheckable(True)
self.toggleWord.setChecked(self.isWholeWord)
self.toggleWord.toggled.connect(self._doToggleWord)
self.searchOpt.addAction(self.toggleWord)
self.toggleRegEx = QAction(self.tr("RegEx Mode"), self)
- self.toggleRegEx.setIcon(self.theTheme.getIcon("search_regex"))
+ self.toggleRegEx.setIcon(self.mainTheme.getIcon("search_regex"))
self.toggleRegEx.setCheckable(True)
self.toggleRegEx.setChecked(self.isRegEx)
self.toggleRegEx.toggled.connect(self._doToggleRegEx)
self.searchOpt.addAction(self.toggleRegEx)
self.toggleLoop = QAction(self.tr("Loop Search"), self)
- self.toggleLoop.setIcon(self.theTheme.getIcon("search_loop"))
+ self.toggleLoop.setIcon(self.mainTheme.getIcon("search_loop"))
self.toggleLoop.setCheckable(True)
self.toggleLoop.setChecked(self.doLoop)
self.toggleLoop.toggled.connect(self._doToggleLoop)
self.searchOpt.addAction(self.toggleLoop)
self.toggleProject = QAction(self.tr("Search Next File"), self)
- self.toggleProject.setIcon(self.theTheme.getIcon("search_project"))
+ self.toggleProject.setIcon(self.mainTheme.getIcon("search_project"))
self.toggleProject.setCheckable(True)
self.toggleProject.setChecked(self.doNextFile)
self.toggleProject.toggled.connect(self._doToggleProject)
@@ -2276,7 +2276,7 @@ class GuiDocEditSearch(QFrame):
self.searchOpt.addSeparator()
self.toggleMatchCap = QAction(self.tr("Preserve Case"), self)
- self.toggleMatchCap.setIcon(self.theTheme.getIcon("search_preserve"))
+ self.toggleMatchCap.setIcon(self.mainTheme.getIcon("search_preserve"))
self.toggleMatchCap.setCheckable(True)
self.toggleMatchCap.setChecked(self.doMatchCap)
self.toggleMatchCap.toggled.connect(self._doToggleMatchCap)
@@ -2285,7 +2285,7 @@ class GuiDocEditSearch(QFrame):
self.searchOpt.addSeparator()
self.cancelSearch = QAction(self.tr("Close Search"), self)
- self.cancelSearch.setIcon(self.theTheme.getIcon("search_cancel"))
+ self.cancelSearch.setIcon(self.mainTheme.getIcon("search_cancel"))
self.cancelSearch.triggered.connect(self._doClose)
self.searchOpt.addAction(self.cancelSearch)
@@ -2300,12 +2300,12 @@ class GuiDocEditSearch(QFrame):
self.showReplace.setStyleSheet("QToolButton {border: none; background: transparent;}")
self.showReplace.toggled.connect(self._doToggleReplace)
- self.searchButton = QPushButton(self.theTheme.getIcon("search"), "")
+ self.searchButton = QPushButton(self.mainTheme.getIcon("search"), "")
self.searchButton.setFixedSize(QSize(bPx, bPx))
self.searchButton.setToolTip(self.tr("Find in current document"))
self.searchButton.clicked.connect(self._doSearch)
- self.replaceButton = QPushButton(self.theTheme.getIcon("search_replace"), "")
+ self.replaceButton = QPushButton(self.mainTheme.getIcon("search_replace"), "")
self.replaceButton.setFixedSize(QSize(bPx, bPx))
self.replaceButton.setToolTip(self.tr("Find and replace in current document"))
self.replaceButton.clicked.connect(self._doReplace)
@@ -2424,7 +2424,7 @@ class GuiDocEditSearch(QFrame):
"""
currRes = "?" if currRes is None else currRes
resCount = "?" if resCount is None else "1000+" if resCount > 1000 else resCount
- minWidth = self.theTheme.getTextWidth(f"{resCount}//{resCount}", self.boxFont)
+ minWidth = self.mainTheme.getTextWidth(f"{resCount}//{resCount}", self.boxFont)
self.resultLabel.setText(f"{currRes}/{resCount}")
self.resultLabel.setMinimumWidth(minWidth)
self.adjustSize()
@@ -2577,11 +2577,11 @@ class GuiDocEditHeader(QWidget):
self.docEditor = docEditor
self.mainGui = docEditor.mainGui
self.theProject = docEditor.theProject
- self.theTheme = docEditor.theTheme
+ self.mainTheme = docEditor.mainTheme
self._docHandle = None
- fPx = int(0.9*self.theTheme.fontPixelSize)
+ fPx = int(0.9*self.mainTheme.fontPixelSize)
hSp = self.mainConf.pxInt(6)
# Main Widget Settings
@@ -2598,17 +2598,17 @@ class GuiDocEditHeader(QWidget):
self.theTitle.setFixedHeight(fPx)
lblFont = self.theTitle.font()
- lblFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
+ lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
self.theTitle.setFont(lblFont)
buttonStyle = (
"QToolButton {{border: none; background: transparent;}} "
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
- ).format(*self.theTheme.colText)
+ ).format(*self.mainTheme.colText)
# Buttons
self.editButton = QToolButton(self)
- self.editButton.setIcon(self.theTheme.getIcon("edit"))
+ self.editButton.setIcon(self.mainTheme.getIcon("edit"))
self.editButton.setContentsMargins(0, 0, 0, 0)
self.editButton.setIconSize(QSize(fPx, fPx))
self.editButton.setFixedSize(fPx, fPx)
@@ -2619,7 +2619,7 @@ class GuiDocEditHeader(QWidget):
self.editButton.clicked.connect(self._editDocument)
self.searchButton = QToolButton(self)
- self.searchButton.setIcon(self.theTheme.getIcon("search"))
+ self.searchButton.setIcon(self.mainTheme.getIcon("search"))
self.searchButton.setContentsMargins(0, 0, 0, 0)
self.searchButton.setIconSize(QSize(fPx, fPx))
self.searchButton.setFixedSize(fPx, fPx)
@@ -2630,7 +2630,7 @@ class GuiDocEditHeader(QWidget):
self.searchButton.clicked.connect(self._searchDocument)
self.minmaxButton = QToolButton(self)
- self.minmaxButton.setIcon(self.theTheme.getIcon("maximise"))
+ self.minmaxButton.setIcon(self.mainTheme.getIcon("maximise"))
self.minmaxButton.setContentsMargins(0, 0, 0, 0)
self.minmaxButton.setIconSize(QSize(fPx, fPx))
self.minmaxButton.setFixedSize(fPx, fPx)
@@ -2641,7 +2641,7 @@ class GuiDocEditHeader(QWidget):
self.minmaxButton.clicked.connect(self._minmaxDocument)
self.closeButton = QToolButton(self)
- self.closeButton.setIcon(self.theTheme.getIcon("close"))
+ self.closeButton.setIcon(self.mainTheme.getIcon("close"))
self.closeButton.setContentsMargins(0, 0, 0, 0)
self.closeButton.setIconSize(QSize(fPx, fPx))
self.closeButton.setFixedSize(fPx, fPx)
@@ -2684,9 +2684,9 @@ class GuiDocEditHeader(QWidget):
theme rather than the main GUI.
"""
thePalette = QPalette()
- thePalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack))
- thePalette.setColor(QPalette.WindowText, QColor(*self.theTheme.colText))
- thePalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
+ thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
+ thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
+ thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
self.setPalette(thePalette)
self.theTitle.setPalette(thePalette)
@@ -2734,9 +2734,9 @@ class GuiDocEditHeader(QWidget):
toggleFocusMode function and should not be activated directly.
"""
if self.mainGui.isFocusMode:
- self.minmaxButton.setIcon(self.theTheme.getIcon("minimise"))
+ self.minmaxButton.setIcon(self.mainTheme.getIcon("minimise"))
else:
- self.minmaxButton.setIcon(self.theTheme.getIcon("maximise"))
+ self.minmaxButton.setIcon(self.mainTheme.getIcon("maximise"))
return
##
@@ -2801,20 +2801,20 @@ class GuiDocEditFooter(QWidget):
self.docEditor = docEditor
self.mainGui = docEditor.mainGui
self.theProject = docEditor.theProject
- self.theTheme = docEditor.theTheme
+ self.mainTheme = docEditor.mainTheme
self._theItem = None
self._docHandle = None
self._docSelection = False
- self.sPx = int(round(0.9*self.theTheme.baseIconSize))
- fPx = int(0.9*self.theTheme.fontPixelSize)
+ self.sPx = int(round(0.9*self.mainTheme.baseIconSize))
+ fPx = int(0.9*self.mainTheme.fontPixelSize)
bSp = self.mainConf.pxInt(4)
hSp = self.mainConf.pxInt(6)
lblFont = self.font()
- lblFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
+ lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
# Main Widget Settings
self.setContentsMargins(0, 0, 0, 0)
@@ -2837,7 +2837,7 @@ class GuiDocEditFooter(QWidget):
# Lines
self.linesIcon = QLabel("")
- self.linesIcon.setPixmap(self.theTheme.getPixmap("status_lines", (self.sPx, self.sPx)))
+ self.linesIcon.setPixmap(self.mainTheme.getPixmap("status_lines", (self.sPx, self.sPx)))
self.linesIcon.setContentsMargins(0, 0, 0, 0)
self.linesIcon.setFixedHeight(self.sPx)
self.linesIcon.setAlignment(Qt.AlignLeft | Qt.AlignTop)
@@ -2853,7 +2853,7 @@ class GuiDocEditFooter(QWidget):
# Words
self.wordsIcon = QLabel("")
- self.wordsIcon.setPixmap(self.theTheme.getPixmap("status_stats", (self.sPx, self.sPx)))
+ self.wordsIcon.setPixmap(self.mainTheme.getPixmap("status_stats", (self.sPx, self.sPx)))
self.wordsIcon.setContentsMargins(0, 0, 0, 0)
self.wordsIcon.setFixedHeight(self.sPx)
self.wordsIcon.setAlignment(Qt.AlignLeft | Qt.AlignTop)
@@ -2905,9 +2905,9 @@ class GuiDocEditFooter(QWidget):
theme rather than the main GUI.
"""
thePalette = QPalette()
- thePalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack))
- thePalette.setColor(QPalette.WindowText, QColor(*self.theTheme.colText))
- thePalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
+ thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
+ thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
+ thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
self.setPalette(thePalette)
self.statusText.setPalette(thePalette)
diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py
index d811332c..8b7ec1a5 100644
--- a/novelwriter/gui/dochighlight.py
+++ b/novelwriter/gui/dochighlight.py
@@ -54,7 +54,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
self.theDoc = theDoc
self.spEnchant = spEnchant
self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self.theHandle = None
self.spellCheck = False
@@ -87,24 +87,24 @@ class GuiDocHighlighter(QSyntaxHighlighter):
"""
logger.debug("Setting up highlighting rules")
- self.colHead = QColor(*self.theTheme.colHead)
- self.colHeadH = QColor(*self.theTheme.colHeadH)
- self.colDialN = QColor(*self.theTheme.colDialN)
- self.colDialD = QColor(*self.theTheme.colDialD)
- self.colDialS = QColor(*self.theTheme.colDialS)
- self.colHidden = QColor(*self.theTheme.colHidden)
- self.colKey = QColor(*self.theTheme.colKey)
- self.colVal = QColor(*self.theTheme.colVal)
- self.colSpell = QColor(*self.theTheme.colSpell)
- self.colError = QColor(*self.theTheme.colError)
- self.colRepTag = QColor(*self.theTheme.colRepTag)
- self.colMod = QColor(*self.theTheme.colMod)
- self.colBreak = QColor(*self.theTheme.colEmph)
+ self.colHead = QColor(*self.mainTheme.colHead)
+ self.colHeadH = QColor(*self.mainTheme.colHeadH)
+ self.colDialN = QColor(*self.mainTheme.colDialN)
+ self.colDialD = QColor(*self.mainTheme.colDialD)
+ self.colDialS = QColor(*self.mainTheme.colDialS)
+ self.colHidden = QColor(*self.mainTheme.colHidden)
+ self.colKey = QColor(*self.mainTheme.colKey)
+ self.colVal = QColor(*self.mainTheme.colVal)
+ self.colSpell = QColor(*self.mainTheme.colSpell)
+ self.colError = QColor(*self.mainTheme.colError)
+ self.colRepTag = QColor(*self.mainTheme.colRepTag)
+ self.colMod = QColor(*self.mainTheme.colMod)
+ self.colBreak = QColor(*self.mainTheme.colEmph)
self.colBreak.setAlpha(64)
self.colEmph = None
if self.mainConf.highlightEmph:
- self.colEmph = QColor(*self.theTheme.colEmph)
+ self.colEmph = QColor(*self.mainTheme.colEmph)
self.hStyles = {
"header1": self._makeFormat(self.colHead, "bold", 1.8),
diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py
index f77e02ec..6ce275a3 100644
--- a/novelwriter/gui/docviewer.py
+++ b/novelwriter/gui/docviewer.py
@@ -61,7 +61,7 @@ class GuiDocViewer(QTextBrowser):
# Class Variables
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
# Internal Variables
@@ -118,14 +118,14 @@ class GuiDocViewer(QTextBrowser):
# Set the widget colours to match syntax theme
mainPalette = self.palette()
- mainPalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack))
- mainPalette.setColor(QPalette.Base, QColor(*self.theTheme.colBack))
- mainPalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
+ mainPalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
+ mainPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
+ mainPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
self.setPalette(mainPalette)
docPalette = self.viewport().palette()
- docPalette.setColor(QPalette.Base, QColor(*self.theTheme.colBack))
- docPalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
+ docPalette.setColor(QPalette.Base, QColor(*self.mainTheme.colBack))
+ docPalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
self.viewport().setPalette(docPalette)
self.docHeader.matchColours()
@@ -539,27 +539,27 @@ class GuiDocViewer(QTextBrowser):
" text-align: center;"
"}}\n"
).format(
- tColR=self.theTheme.colText[0],
- tColG=self.theTheme.colText[1],
- tColB=self.theTheme.colText[2],
- hColR=self.theTheme.colHead[0],
- hColG=self.theTheme.colHead[1],
- hColB=self.theTheme.colHead[2],
- aColR=self.theTheme.colVal[0],
- aColG=self.theTheme.colVal[1],
- aColB=self.theTheme.colVal[2],
- eColR=self.theTheme.colEmph[0],
- eColG=self.theTheme.colEmph[1],
- eColB=self.theTheme.colEmph[2],
- kColR=self.theTheme.colKey[0],
- kColG=self.theTheme.colKey[1],
- kColB=self.theTheme.colKey[2],
- cColR=self.theTheme.colHidden[0],
- cColG=self.theTheme.colHidden[1],
- cColB=self.theTheme.colHidden[2],
- mColR=self.theTheme.colMod[0],
- mColG=self.theTheme.colMod[1],
- mColB=self.theTheme.colMod[2],
+ tColR=self.mainTheme.colText[0],
+ tColG=self.mainTheme.colText[1],
+ tColB=self.mainTheme.colText[2],
+ hColR=self.mainTheme.colHead[0],
+ hColG=self.mainTheme.colHead[1],
+ hColB=self.mainTheme.colHead[2],
+ aColR=self.mainTheme.colVal[0],
+ aColG=self.mainTheme.colVal[1],
+ aColB=self.mainTheme.colVal[2],
+ eColR=self.mainTheme.colEmph[0],
+ eColG=self.mainTheme.colEmph[1],
+ eColB=self.mainTheme.colEmph[2],
+ kColR=self.mainTheme.colKey[0],
+ kColG=self.mainTheme.colKey[1],
+ kColB=self.mainTheme.colKey[2],
+ cColR=self.mainTheme.colHidden[0],
+ cColG=self.mainTheme.colHidden[1],
+ cColB=self.mainTheme.colHidden[2],
+ mColR=self.mainTheme.colMod[0],
+ mColG=self.mainTheme.colMod[1],
+ mColB=self.mainTheme.colMod[2],
)
self.document().setDefaultStyleSheet(styleSheet)
@@ -716,12 +716,12 @@ class GuiDocViewHeader(QWidget):
self.docViewer = docViewer
self.mainGui = docViewer.mainGui
self.theProject = docViewer.theProject
- self.theTheme = docViewer.theTheme
+ self.mainTheme = docViewer.mainTheme
# Internal Variables
self._docHandle = None
- fPx = int(0.9*self.theTheme.fontPixelSize)
+ fPx = int(0.9*self.mainTheme.fontPixelSize)
hSp = self.mainConf.pxInt(6)
# Main Widget Settings
@@ -738,17 +738,17 @@ class GuiDocViewHeader(QWidget):
self.theTitle.setFixedHeight(fPx)
lblFont = self.theTitle.font()
- lblFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
+ lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
self.theTitle.setFont(lblFont)
buttonStyle = (
"QToolButton {{border: none; background: transparent;}} "
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
- ).format(*self.theTheme.colText)
+ ).format(*self.mainTheme.colText)
# Buttons
self.backButton = QToolButton(self)
- self.backButton.setIcon(self.theTheme.getIcon("backward"))
+ self.backButton.setIcon(self.mainTheme.getIcon("backward"))
self.backButton.setContentsMargins(0, 0, 0, 0)
self.backButton.setIconSize(QSize(fPx, fPx))
self.backButton.setFixedSize(fPx, fPx)
@@ -759,7 +759,7 @@ class GuiDocViewHeader(QWidget):
self.backButton.clicked.connect(self.docViewer.navBackward)
self.forwardButton = QToolButton(self)
- self.forwardButton.setIcon(self.theTheme.getIcon("forward"))
+ self.forwardButton.setIcon(self.mainTheme.getIcon("forward"))
self.forwardButton.setContentsMargins(0, 0, 0, 0)
self.forwardButton.setIconSize(QSize(fPx, fPx))
self.forwardButton.setFixedSize(fPx, fPx)
@@ -770,7 +770,7 @@ class GuiDocViewHeader(QWidget):
self.forwardButton.clicked.connect(self.docViewer.navForward)
self.refreshButton = QToolButton(self)
- self.refreshButton.setIcon(self.theTheme.getIcon("refresh"))
+ self.refreshButton.setIcon(self.mainTheme.getIcon("refresh"))
self.refreshButton.setContentsMargins(0, 0, 0, 0)
self.refreshButton.setIconSize(QSize(fPx, fPx))
self.refreshButton.setFixedSize(fPx, fPx)
@@ -781,7 +781,7 @@ class GuiDocViewHeader(QWidget):
self.refreshButton.clicked.connect(self._refreshDocument)
self.closeButton = QToolButton(self)
- self.closeButton.setIcon(self.theTheme.getIcon("close"))
+ self.closeButton.setIcon(self.mainTheme.getIcon("close"))
self.closeButton.setContentsMargins(0, 0, 0, 0)
self.closeButton.setIconSize(QSize(fPx, fPx))
self.closeButton.setFixedSize(fPx, fPx)
@@ -824,9 +824,9 @@ class GuiDocViewHeader(QWidget):
theme rather than the main GUI.
"""
thePalette = QPalette()
- thePalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack))
- thePalette.setColor(QPalette.WindowText, QColor(*self.theTheme.colText))
- thePalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
+ thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
+ thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
+ thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
self.setPalette(thePalette)
self.theTitle.setPalette(thePalette)
@@ -922,25 +922,25 @@ class GuiDocViewFooter(QWidget):
self.mainConf = novelwriter.CONFIG
self.docViewer = docViewer
self.mainGui = docViewer.mainGui
- self.theTheme = docViewer.theTheme
+ self.mainTheme = docViewer.mainTheme
self.viewMeta = docViewer.mainGui.viewMeta
# Internal Variables
self._docHandle = None
- fPx = int(0.9*self.theTheme.fontPixelSize)
+ fPx = int(0.9*self.mainTheme.fontPixelSize)
bSp = self.mainConf.pxInt(2)
hSp = self.mainConf.pxInt(8)
# Icons
- stickyOn = self.theTheme.getPixmap("sticky-on", (fPx, fPx))
- stickyOff = self.theTheme.getPixmap("sticky-off", (fPx, fPx))
+ stickyOn = self.mainTheme.getPixmap("sticky-on", (fPx, fPx))
+ stickyOff = self.mainTheme.getPixmap("sticky-off", (fPx, fPx))
stickyIcon = QIcon()
stickyIcon.addPixmap(stickyOn, QIcon.Normal, QIcon.On)
stickyIcon.addPixmap(stickyOff, QIcon.Normal, QIcon.Off)
- bulletOn = self.theTheme.getPixmap("bullet-on", (fPx, fPx))
- bulletOff = self.theTheme.getPixmap("bullet-off", (fPx, fPx))
+ bulletOn = self.mainTheme.getPixmap("bullet-on", (fPx, fPx))
+ bulletOff = self.mainTheme.getPixmap("bullet-off", (fPx, fPx))
bulletIcon = QIcon()
bulletIcon.addPixmap(bulletOn, QIcon.Normal, QIcon.On)
bulletIcon.addPixmap(bulletOff, QIcon.Normal, QIcon.Off)
@@ -952,13 +952,13 @@ class GuiDocViewFooter(QWidget):
buttonStyle = (
"QToolButton {{border: none; background: transparent;}} "
"QToolButton:hover {{border: none; background: rgba({0},{1},{2},0.2);}}"
- ).format(*self.theTheme.colText)
+ ).format(*self.mainTheme.colText)
# Show/Hide Details
self.showHide = QToolButton(self)
self.showHide.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.showHide.setStyleSheet(buttonStyle)
- self.showHide.setIcon(self.theTheme.getIcon("reference"))
+ self.showHide.setIcon(self.mainTheme.getIcon("reference"))
self.showHide.setIconSize(QSize(fPx, fPx))
self.showHide.setFixedSize(QSize(fPx, fPx))
self.showHide.clicked.connect(self._doShowHide)
@@ -1039,7 +1039,7 @@ class GuiDocViewFooter(QWidget):
self.lblSynopsis.setAlignment(Qt.AlignLeft | Qt.AlignTop)
lblFont = self.font()
- lblFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
+ lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
self.lblRefs.setFont(lblFont)
self.lblSticky.setFont(lblFont)
self.lblComments.setFont(lblFont)
@@ -1084,9 +1084,9 @@ class GuiDocViewFooter(QWidget):
theme rather than the main GUI.
"""
thePalette = QPalette()
- thePalette.setColor(QPalette.Window, QColor(*self.theTheme.colBack))
- thePalette.setColor(QPalette.WindowText, QColor(*self.theTheme.colText))
- thePalette.setColor(QPalette.Text, QColor(*self.theTheme.colText))
+ thePalette.setColor(QPalette.Window, QColor(*self.mainTheme.colBack))
+ thePalette.setColor(QPalette.WindowText, QColor(*self.mainTheme.colText))
+ thePalette.setColor(QPalette.Text, QColor(*self.mainTheme.colText))
self.setPalette(thePalette)
self.lblRefs.setPalette(thePalette)
@@ -1147,7 +1147,7 @@ class GuiDocViewDetails(QScrollArea):
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
self.theProject = mainGui.theProject
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
self.refList = QLabel("")
self.refList.setWordWrap(True)
@@ -1156,7 +1156,7 @@ class GuiDocViewDetails(QScrollArea):
self.refList.linkActivated.connect(self._linkClicked)
self.linkStyle = "style='color: rgb({0},{1},{2})'".format(
- *self.theTheme.colLink
+ *self.mainTheme.colLink
)
# Assemble
diff --git a/novelwriter/gui/itemdetails.py b/novelwriter/gui/itemdetails.py
index 97d4ba0e..859e58f2 100644
--- a/novelwriter/gui/itemdetails.py
+++ b/novelwriter/gui/itemdetails.py
@@ -45,7 +45,7 @@ class GuiItemDetails(QWidget):
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
self.theProject = mainGui.theProject
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
# Internal Variables
self._itemHandle = None
@@ -54,11 +54,11 @@ class GuiItemDetails(QWidget):
hSp = self.mainConf.pxInt(6)
vSp = self.mainConf.pxInt(1)
mPx = self.mainConf.pxInt(6)
- iPx = self.theTheme.baseIconSize
- fPt = self.theTheme.fontPointSize
+ iPx = self.mainTheme.baseIconSize
+ fPt = self.mainTheme.fontPointSize
- self._expCheck = self.theTheme.getPixmap("check", (iPx, iPx))
- self._expCross = self.theTheme.getPixmap("cross", (iPx, iPx))
+ self._expCheck = self.mainTheme.getPixmap("check", (iPx, iPx))
+ self._expCross = self.mainTheme.getPixmap("cross", (iPx, iPx))
fntLabel = QFont()
fntLabel.setBold(True)
@@ -181,8 +181,8 @@ class GuiItemDetails(QWidget):
self.setLayout(self.mainBox)
# Make sure the columns for flags and counts don't resize too often
- flagWidth = self.theTheme.getTextWidth("Mm", fntValue)
- countWidth = self.theTheme.getTextWidth("99,999", fntValue)
+ flagWidth = self.mainTheme.getTextWidth("Mm", fntValue)
+ countWidth = self.mainTheme.getTextWidth("99,999", fntValue)
self.mainBox.setColumnMinimumWidth(1, flagWidth)
self.mainBox.setColumnMinimumWidth(4, countWidth)
@@ -238,7 +238,7 @@ class GuiItemDetails(QWidget):
return
self._itemHandle = tHandle
- iPx = int(round(0.8*self.theTheme.baseIconSize))
+ iPx = int(round(0.8*self.mainTheme.baseIconSize))
# Label
# =====
@@ -267,7 +267,7 @@ class GuiItemDetails(QWidget):
# Class
# =====
- classIcon = self.theTheme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass])
+ classIcon = self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItem.itemClass])
self.classIcon.setPixmap(classIcon.pixmap(iPx, iPx))
self.classData.setText(trConst(nwLabels.CLASS_NAME[nwItem.itemClass]))
@@ -275,7 +275,7 @@ class GuiItemDetails(QWidget):
# ======
hLevel = self.theProject.index.getHandleHeaderLevel(tHandle)
- usageIcon = self.theTheme.getItemIcon(
+ usageIcon = self.mainTheme.getItemIcon(
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
)
self.usageIcon.setPixmap(usageIcon.pixmap(iPx, iPx))
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index dbdd02c0..f634ce23 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -52,7 +52,7 @@ class GuiNovelTree(QTreeWidget):
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
# Internal Variables
@@ -60,7 +60,7 @@ class GuiNovelTree(QTreeWidget):
self._lastBuild = 0
# Build GUI
- iPx = self.theTheme.baseIconSize
+ iPx = self.mainTheme.baseIconSize
self.setFrameStyle(QFrame.NoFrame)
self.setIconSize(QSize(iPx, iPx))
self.setIndentation(iPx)
@@ -309,7 +309,7 @@ class GuiNovelTree(QTreeWidget):
newItem.setText(self.C_TITLE, novIdx.title)
newItem.setData(self.C_TITLE, Qt.UserRole, theData)
- newItem.setIcon(self.C_TITLE, self.theTheme.getIcon(hIcon))
+ newItem.setIcon(self.C_TITLE, self.mainTheme.getIcon(hIcon))
newItem.setText(self.C_WORDS, f"{wC:n}")
newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py
index e3283ead..c858c480 100644
--- a/novelwriter/gui/outline.py
+++ b/novelwriter/gui/outline.py
@@ -179,7 +179,7 @@ class GuiOutlineToolBar(QToolBar):
self.mainConf = novelwriter.CONFIG
self.mainGui = theOutline.mainGui
self.theProject = theOutline.mainGui.theProject
- self.theTheme = theOutline.mainGui.theTheme
+ self.mainTheme = theOutline.mainGui.mainTheme
iPx = self.mainConf.pxInt(22)
mPx = self.mainConf.pxInt(12)
@@ -202,7 +202,7 @@ class GuiOutlineToolBar(QToolBar):
# Actions
self.aRefresh = QAction(self.tr("Refresh"), self)
- self.aRefresh.setIcon(self.theTheme.getIcon("refresh"))
+ self.aRefresh.setIcon(self.mainTheme.getIcon("refresh"))
self.aRefresh.triggered.connect(self._refreshRequested)
# Column Menu
@@ -212,7 +212,7 @@ class GuiOutlineToolBar(QToolBar):
)
self.tbColumns = QToolButton(self)
- self.tbColumns.setIcon(self.theTheme.getIcon("menu"))
+ self.tbColumns.setIcon(self.mainTheme.getIcon("menu"))
self.tbColumns.setMenu(self.mColumns)
self.tbColumns.setPopupMode(QToolButton.InstantPopup)
@@ -236,7 +236,7 @@ class GuiOutlineToolBar(QToolBar):
"""Fill the novel combo box with a list of all novel folders.
"""
self.novelValue.clear()
- tIcon = self.theTheme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL])
+ tIcon = self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL])
for tHandle, nwItem in self.theProject.tree.iterRoots(nwItemClass.NOVEL):
self.novelValue.addItem(tIcon, nwItem.itemName, tHandle)
self.novelValue.insertSeparator(self.novelValue.count())
@@ -324,7 +324,7 @@ class GuiOutlineTree(QTreeWidget):
self.mainConf = novelwriter.CONFIG
self.mainGui = theOutline.mainGui
self.theProject = theOutline.mainGui.theProject
- self.theTheme = theOutline.mainGui.theTheme
+ self.mainTheme = theOutline.mainGui.mainTheme
self.setFrameStyle(QFrame.NoFrame)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
@@ -334,7 +334,7 @@ class GuiOutlineTree(QTreeWidget):
self.itemDoubleClicked.connect(self._treeDoubleClick)
self.itemSelectionChanged.connect(self._itemSelected)
- iPx = self.theTheme.baseIconSize
+ iPx = self.mainTheme.baseIconSize
self.setIconSize(QSize(iPx, iPx))
self.setIndentation(iPx)
@@ -682,7 +682,7 @@ class GuiOutlineTree(QTreeWidget):
hIcon = "doc_%s" % novIdx.level.lower()
hLevel = self.theProject.index.getHandleHeaderLevel(tHandle)
- dIcon = self.theTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, hLevel)
+ dIcon = self.mainTheme.getItemIcon(nwItemType.FILE, None, nwItemLayout.DOCUMENT, hLevel)
cC = int(novIdx.charCount)
wC = int(novIdx.wordCount)
@@ -690,7 +690,7 @@ class GuiOutlineTree(QTreeWidget):
newItem.setText(self._colIdx[nwOutline.TITLE], novIdx.title)
newItem.setData(self._colIdx[nwOutline.TITLE], Qt.UserRole, tHandle)
- newItem.setIcon(self._colIdx[nwOutline.TITLE], self.theTheme.getIcon(hIcon))
+ newItem.setIcon(self._colIdx[nwOutline.TITLE], self.mainTheme.getIcon(hIcon))
newItem.setText(self._colIdx[nwOutline.LEVEL], novIdx.level)
newItem.setText(self._colIdx[nwOutline.LABEL], nwItem.itemName)
newItem.setIcon(self._colIdx[nwOutline.LABEL], dIcon)
@@ -784,12 +784,12 @@ class GuiOutlineDetails(QScrollArea):
self.theOutline = theOutline
self.mainGui = theOutline.mainGui
self.theProject = theOutline.mainGui.theProject
- self.theTheme = theOutline.mainGui.theTheme
+ self.mainTheme = theOutline.mainGui.mainTheme
# Sizes
- minTitle = 30*self.theTheme.textNWidth
- maxTitle = 40*self.theTheme.textNWidth
- wCount = self.theTheme.getTextWidth("999,999")
+ minTitle = 30*self.mainTheme.textNWidth
+ maxTitle = 40*self.mainTheme.textNWidth
+ wCount = self.mainTheme.getTextWidth("999,999")
hSpace = int(self.mainConf.pxInt(10))
vSpace = int(self.mainConf.pxInt(4))
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index f2a7b2b3..4c0ea59b 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -169,9 +169,9 @@ class GuiProjectToolBar(QWidget):
self.projTree = projView.projTree
self.mainGui = projView.mainGui
self.theProject = projView.mainGui.theProject
- self.theTheme = projView.mainGui.theTheme
+ self.mainTheme = projView.mainGui.mainTheme
- iPx = self.theTheme.baseIconSize
+ iPx = self.mainTheme.baseIconSize
mPx = self.mainConf.pxInt(4)
self.setContentsMargins(0, 0, 0, 0)
@@ -195,14 +195,14 @@ class GuiProjectToolBar(QWidget):
# Move Buttons
self.tbMoveU = QToolButton(self)
self.tbMoveU.setToolTip("%s [Ctrl+Up]" % self.tr("Move Up"))
- self.tbMoveU.setIcon(self.theTheme.getIcon("up"))
+ self.tbMoveU.setIcon(self.mainTheme.getIcon("up"))
self.tbMoveU.setIconSize(QSize(iPx, iPx))
self.tbMoveU.setStyleSheet(buttonStyle)
self.tbMoveU.clicked.connect(lambda: self.projTree.moveTreeItem(-1))
self.tbMoveD = QToolButton(self)
self.tbMoveD.setToolTip("%s [Ctrl+Down]" % self.tr("Move Down"))
- self.tbMoveD.setIcon(self.theTheme.getIcon("down"))
+ self.tbMoveD.setIcon(self.mainTheme.getIcon("down"))
self.tbMoveD.setIconSize(QSize(iPx, iPx))
self.tbMoveD.setStyleSheet(buttonStyle)
self.tbMoveD.clicked.connect(lambda: self.projTree.moveTreeItem(1))
@@ -211,31 +211,31 @@ class GuiProjectToolBar(QWidget):
self.mAdd = QMenu()
self.aAddEmpty = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["document"]))
- self.aAddEmpty.setIcon(self.theTheme.getIcon("proj_document"))
+ self.aAddEmpty.setIcon(self.mainTheme.getIcon("proj_document"))
self.aAddEmpty.triggered.connect(
lambda: self.projTree.newTreeItem(nwItemType.FILE, hLevel=0, isNote=False)
)
self.aAddChap = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["doc_h2"]))
- self.aAddChap.setIcon(self.theTheme.getIcon("proj_chapter"))
+ self.aAddChap.setIcon(self.mainTheme.getIcon("proj_chapter"))
self.aAddChap.triggered.connect(
lambda: self.projTree.newTreeItem(nwItemType.FILE, hLevel=2, isNote=False)
)
self.aAddScene = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["doc_h3"]))
- self.aAddScene.setIcon(self.theTheme.getIcon("proj_scene"))
+ self.aAddScene.setIcon(self.mainTheme.getIcon("proj_scene"))
self.aAddScene.triggered.connect(
lambda: self.projTree.newTreeItem(nwItemType.FILE, hLevel=3, isNote=False)
)
self.aAddNote = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["note"]))
- self.aAddNote.setIcon(self.theTheme.getIcon("proj_note"))
+ self.aAddNote.setIcon(self.mainTheme.getIcon("proj_note"))
self.aAddNote.triggered.connect(
lambda: self.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True)
)
self.aAddFolder = self.mAdd.addAction(trConst(nwLabels.ITEM_DESCRIPTION["folder"]))
- self.aAddFolder.setIcon(self.theTheme.getIcon("proj_folder"))
+ self.aAddFolder.setIcon(self.mainTheme.getIcon("proj_folder"))
self.aAddFolder.triggered.connect(
lambda: self.projTree.newTreeItem(nwItemType.FOLDER)
)
@@ -255,7 +255,7 @@ class GuiProjectToolBar(QWidget):
self.tbAdd = QToolButton(self)
self.tbAdd.setToolTip("%s [Ctrl+N]" % self.tr("Add Item"))
self.tbAdd.setShortcut("Ctrl+N")
- self.tbAdd.setIcon(self.theTheme.getIcon("add"))
+ self.tbAdd.setIcon(self.mainTheme.getIcon("add"))
self.tbAdd.setIconSize(QSize(iPx, iPx))
self.tbAdd.setStyleSheet(buttonStyle)
self.tbAdd.setMenu(self.mAdd)
@@ -272,7 +272,7 @@ class GuiProjectToolBar(QWidget):
self.tbMore = QToolButton(self)
self.tbMore.setToolTip(self.tr("More Options"))
- self.tbMore.setIcon(self.theTheme.getIcon("menu"))
+ self.tbMore.setIcon(self.mainTheme.getIcon("menu"))
self.tbMore.setIconSize(QSize(iPx, iPx))
self.tbMore.setStyleSheet(buttonStyle)
self.tbMore.setMenu(self.mMore)
@@ -302,7 +302,7 @@ class GuiProjectToolBar(QWidget):
"""Add a menu entry for a root folder of a given class.
"""
aNew = self.mAddRoot.addAction(trConst(nwLabels.CLASS_NAME[itemClass]))
- aNew.setIcon(self.theTheme.getIcon(nwLabels.CLASS_ICON[itemClass]))
+ aNew.setIcon(self.mainTheme.getIcon(nwLabels.CLASS_ICON[itemClass]))
aNew.triggered.connect(lambda: self.projTree.newTreeItem(nwItemType.ROOT, itemClass))
self.mAddRoot.addAction(aNew)
@@ -324,7 +324,7 @@ class GuiProjectTree(QTreeWidget):
self.mainConf = novelwriter.CONFIG
self.projView = projView
self.mainGui = projView.mainGui
- self.theTheme = projView.mainGui.theTheme
+ self.mainTheme = projView.mainGui.mainTheme
self.theProject = projView.mainGui.theProject
# Internal Variables
@@ -341,7 +341,7 @@ class GuiProjectTree(QTreeWidget):
self.customContextMenuRequested.connect(self._openContextMenu)
# Tree Settings
- iPx = self.theTheme.baseIconSize
+ iPx = self.mainTheme.baseIconSize
cMg = self.mainConf.pxInt(6)
self.setIconSize(QSize(iPx, iPx))
self.setFrameStyle(QFrame.NoFrame)
@@ -779,13 +779,13 @@ class GuiProjectTree(QTreeWidget):
expIcon = QIcon()
if nwItem.itemType == nwItemType.FILE:
if nwItem.isExported:
- expIcon = self.theTheme.getIcon("check")
+ expIcon = self.mainTheme.getIcon("check")
else:
- expIcon = self.theTheme.getIcon("cross")
+ expIcon = self.mainTheme.getIcon("cross")
itemStatus, statusIcon = nwItem.getImportStatus()
hLevel = self.theProject.index.getHandleHeaderLevel(tHandle)
- itemIcon = self.theTheme.getItemIcon(
+ itemIcon = self.mainTheme.getItemIcon(
nwItem.itemType, nwItem.itemClass, nwItem.itemLayout, hLevel
)
diff --git a/novelwriter/gui/statusbar.py b/novelwriter/gui/statusbar.py
index 4863f9bc..a0cf9416 100644
--- a/novelwriter/gui/statusbar.py
+++ b/novelwriter/gui/statusbar.py
@@ -48,15 +48,15 @@ class GuiMainStatus(QStatusBar):
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
self.refTime = None
self.userIdle = False
- colNone = QColor(*self.theTheme.statNone)
- colTrue = QColor(*self.theTheme.statUnsaved)
- colFalse = QColor(*self.theTheme.statSaved)
+ colNone = QColor(*self.mainTheme.statNone)
+ colTrue = QColor(*self.mainTheme.statUnsaved)
+ colFalse = QColor(*self.mainTheme.statSaved)
- iPx = self.theTheme.baseIconSize
+ iPx = self.mainTheme.baseIconSize
# Permanent Widgets
# =================
@@ -66,7 +66,7 @@ class GuiMainStatus(QStatusBar):
# The Spell Checker Language
self.langIcon = QLabel("")
self.langText = QLabel(self.tr("None"))
- self.langIcon.setPixmap(self.theTheme.getPixmap("status_lang", (iPx, iPx)))
+ self.langIcon.setPixmap(self.mainTheme.getPixmap("status_lang", (iPx, iPx)))
self.langIcon.setContentsMargins(0, 0, 0, 0)
self.langText.setContentsMargins(0, 0, xM, 0)
self.addPermanentWidget(self.langIcon)
@@ -91,7 +91,7 @@ class GuiMainStatus(QStatusBar):
# The Project and Session Stats
self.statsIcon = QLabel()
self.statsText = QLabel("")
- self.statsIcon.setPixmap(self.theTheme.getPixmap("status_stats", (iPx, iPx)))
+ self.statsIcon.setPixmap(self.mainTheme.getPixmap("status_stats", (iPx, iPx)))
self.statsIcon.setContentsMargins(0, 0, 0, 0)
self.statsText.setContentsMargins(0, 0, xM, 0)
self.addPermanentWidget(self.statsIcon)
@@ -99,14 +99,14 @@ class GuiMainStatus(QStatusBar):
# The Session Clock
# Set the mimimum width so the label doesn't rescale every second
- self.timePixmap = self.theTheme.getPixmap("status_time", (iPx, iPx))
- self.idlePixmap = self.theTheme.getPixmap("status_idle", (iPx, iPx))
+ self.timePixmap = self.mainTheme.getPixmap("status_time", (iPx, iPx))
+ self.idlePixmap = self.mainTheme.getPixmap("status_idle", (iPx, iPx))
self.timeIcon = QLabel()
self.timeText = QLabel("")
self.timeIcon.setPixmap(self.timePixmap)
self.timeText.setToolTip(self.tr("Session Time"))
- self.timeText.setMinimumWidth(self.theTheme.getTextWidth("00:00:00:"))
+ self.timeText.setMinimumWidth(self.mainTheme.getTextWidth("00:00:00:"))
self.timeIcon.setContentsMargins(0, 0, 0, 0)
self.timeText.setContentsMargins(0, 0, 0, 0)
self.addPermanentWidget(self.timeIcon)
diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py
index bb93e0b8..3a59e7e2 100644
--- a/novelwriter/gui/theme.py
+++ b/novelwriter/gui/theme.py
@@ -54,7 +54,7 @@ class GuiTheme:
def __init__(self):
self.mainConf = novelwriter.CONFIG
- self.theIcons = GuiIcons(self)
+ self.iconCache = GuiIcons(self)
# Loaded Theme Settings
# =====================
@@ -127,13 +127,13 @@ class GuiTheme:
self.updateFont()
self.updateTheme()
- self.theIcons.updateTheme()
+ self.iconCache.updateTheme()
# Icon Functions
- self.getIcon = self.theIcons.getIcon
- self.getPixmap = self.theIcons.getPixmap
- self.getItemIcon = self.theIcons.getItemIcon
- self.loadDecoration = self.theIcons.loadDecoration
+ self.getIcon = self.iconCache.getIcon
+ self.getPixmap = self.iconCache.getPixmap
+ self.getItemIcon = self.iconCache.getItemIcon
+ self.loadDecoration = self.iconCache.loadDecoration
# Extract Other Info
self.guiDPI = qApp.primaryScreen().logicalDotsPerInchX()
@@ -478,10 +478,10 @@ class GuiIcons:
"wiz-back": "wizard-back.jpg",
}
- def __init__(self, theTheme):
+ def __init__(self, mainTheme):
self.mainConf = novelwriter.CONFIG
- self.theTheme = theTheme
+ self.mainTheme = mainTheme
# Storage
self._qIcons = {}
diff --git a/novelwriter/gui/viewsbar.py b/novelwriter/gui/viewsbar.py
index d62b5543..031f4316 100644
--- a/novelwriter/gui/viewsbar.py
+++ b/novelwriter/gui/viewsbar.py
@@ -45,16 +45,16 @@ class GuiViewsBar(QToolBar):
logger.debug("Initialising GuiViewsBar ...")
- self.mainConf = novelwriter.CONFIG
- self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.mainTheme = mainGui.mainTheme
# Style
iPx = self.mainConf.pxInt(22)
mPx = self.mainConf.pxInt(60)
- lblFont = self.theTheme.guiFont
- lblFont.setPointSizeF(0.65*self.theTheme.fontPointSize)
+ lblFont = self.mainTheme.guiFont
+ lblFont.setPointSizeF(0.65*self.mainTheme.fontPointSize)
self.setMovable(False)
self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
@@ -70,37 +70,37 @@ class GuiViewsBar(QToolBar):
self.aProject = QAction(self.tr("Project"))
self.aProject.setFont(lblFont)
self.aProject.setToolTip(self.tr("Show project tree and editor"))
- self.aProject.setIcon(self.theTheme.getIcon("view_editor"))
+ self.aProject.setIcon(self.mainTheme.getIcon("view_editor"))
self.aProject.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.PROJECT))
self.aNovel = QAction(self.tr("Novel"))
self.aNovel.setFont(lblFont)
self.aNovel.setToolTip(self.tr("Show novel tree and editor"))
- self.aNovel.setIcon(self.theTheme.getIcon("view_novel"))
+ self.aNovel.setIcon(self.mainTheme.getIcon("view_novel"))
self.aNovel.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.NOVEL))
self.aOutline = QAction(self.tr("Outline"))
self.aOutline.setFont(lblFont)
self.aOutline.setToolTip(self.tr("Show novel outline"))
- self.aOutline.setIcon(self.theTheme.getIcon("view_outline"))
+ self.aOutline.setIcon(self.mainTheme.getIcon("view_outline"))
self.aOutline.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.OUTLINE))
self.aBuild = QAction(self.tr("Build"))
self.aBuild.setFont(lblFont)
self.aBuild.setToolTip(self.tr("Build novel project"))
- self.aBuild.setIcon(self.theTheme.getIcon("view_build"))
+ self.aBuild.setIcon(self.mainTheme.getIcon("view_build"))
self.aBuild.triggered.connect(lambda: self.mainGui.showBuildProjectDialog())
self.aDetails = QAction(self.tr("Details"))
self.aDetails.setFont(lblFont)
self.aDetails.setToolTip(self.tr("Show project details"))
- self.aDetails.setIcon(self.theTheme.getIcon("proj_details"))
+ self.aDetails.setIcon(self.mainTheme.getIcon("proj_details"))
self.aDetails.triggered.connect(lambda: self.mainGui.showProjectDetailsDialog())
self.aStats = QAction(self.tr("Stats"))
self.aStats.setFont(lblFont)
self.aStats.setToolTip(self.tr("Show project statistics"))
- self.aStats.setIcon(self.theTheme.getIcon("proj_stats"))
+ self.aStats.setIcon(self.mainTheme.getIcon("proj_stats"))
self.aStats.triggered.connect(lambda: self.mainGui.showWritingStatsDialog())
# Settings Menu
@@ -117,7 +117,7 @@ class GuiViewsBar(QToolBar):
self.tbSettings = QToolButton(self)
self.tbSettings.setFont(lblFont)
self.tbSettings.setText(self.tr("Settings"))
- self.tbSettings.setIcon(self.theTheme.getIcon("settings"))
+ self.tbSettings.setIcon(self.mainTheme.getIcon("settings"))
self.tbSettings.setMenu(self.mSettings)
self.tbSettings.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
self.tbSettings.setPopupMode(QToolButton.InstantPopup)
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 8c0e0e51..6b315866 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -84,7 +84,7 @@ class GuiMain(QMainWindow):
# ============
# Core Classes and Settings
- self.theTheme = GuiTheme()
+ self.mainTheme = GuiTheme()
self.theProject = NWProject(self)
self.hasProject = False
self.isFocusMode = False
@@ -915,7 +915,7 @@ class GuiMain(QMainWindow):
if dlgConf.result() == QDialog.Accepted:
logger.debug("Applying new preferences")
self.initMain()
- self.theTheme.updateTheme()
+ self.mainTheme.updateTheme()
self.saveDocument()
self.docEditor.initEditor()
self.docViewer.initViewer()
diff --git a/novelwriter/tools/build.py b/novelwriter/tools/build.py
index 4ce9dea1..efeff928 100644
--- a/novelwriter/tools/build.py
+++ b/novelwriter/tools/build.py
@@ -73,7 +73,7 @@ class GuiBuildNovel(QDialog):
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self.htmlText = [] # List of html documents
@@ -93,7 +93,7 @@ class GuiBuildNovel(QDialog):
self.docView = GuiBuildNovelDocView(self, self.theProject)
- hS = self.theTheme.fontPixelSize
+ hS = self.mainTheme.fontPixelSize
wS = 2*hS
# Title Formats
@@ -238,11 +238,11 @@ class GuiBuildNovel(QDialog):
pOptions.getString("GuiBuildNovel", "textFont", self.mainConf.textFont)
)
self.fontButton = QPushButton("...")
- self.fontButton.setMaximumWidth(int(2.5*self.theTheme.getTextWidth("...")))
+ self.fontButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
self.fontButton.clicked.connect(self._selectFont)
self.textSize = QSpinBox(self)
- self.textSize.setFixedWidth(6*self.theTheme.textNWidth)
+ self.textSize.setFixedWidth(6*self.mainTheme.textNWidth)
self.textSize.setMinimum(6)
self.textSize.setMaximum(72)
self.textSize.setSingleStep(1)
@@ -251,7 +251,7 @@ class GuiBuildNovel(QDialog):
)
self.lineHeight = QDoubleSpinBox(self)
- self.lineHeight.setFixedWidth(6*self.theTheme.textNWidth)
+ self.lineHeight.setFixedWidth(6*self.mainTheme.textNWidth)
self.lineHeight.setMinimum(0.8)
self.lineHeight.setMaximum(3.0)
self.lineHeight.setSingleStep(0.05)
@@ -1201,10 +1201,10 @@ class GuiBuildNovelDocView(QTextBrowser):
self.mainConf = novelwriter.CONFIG
self.theProject = theProject
self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
self.buildTime = 0
- self.setMinimumWidth(40*self.mainGui.theTheme.textNWidth)
+ self.setMinimumWidth(40*self.mainGui.mainTheme.textNWidth)
self.setOpenExternalLinks(False)
self.document().setDocumentMargin(self.mainConf.getTextMargin())
@@ -1238,9 +1238,9 @@ class GuiBuildNovelDocView(QTextBrowser):
lblPalette.setColor(QPalette.Foreground, lblPalette.toolTipText().color())
lblFont = self.font()
- lblFont.setPointSizeF(0.9*self.theTheme.fontPointSize)
+ lblFont.setPointSizeF(0.9*self.mainTheme.fontPointSize)
- fPx = int(1.1*self.theTheme.fontPixelSize)
+ fPx = int(1.1*self.mainTheme.fontPixelSize)
self.theTitle = QLabel("", self)
self.theTitle.setIndent(0)
diff --git a/novelwriter/tools/lipsum.py b/novelwriter/tools/lipsum.py
index d741058c..2086d615 100644
--- a/novelwriter/tools/lipsum.py
+++ b/novelwriter/tools/lipsum.py
@@ -48,9 +48,9 @@ class GuiLipsum(QDialog):
logger.debug("Initialising GuiLipsum ...")
self.setObjectName("GuiLipsum")
- self.mainConf = novelwriter.CONFIG
- self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.mainTheme = mainGui.mainTheme
self.setWindowTitle(self.tr("Insert Placeholder Text"))
@@ -61,7 +61,7 @@ class GuiLipsum(QDialog):
nPx = self.mainConf.pxInt(64)
vSp = self.mainConf.pxInt(4)
self.docIcon = QLabel()
- self.docIcon.setPixmap(self.mainGui.theTheme.getPixmap("proj_document", (nPx, nPx)))
+ self.docIcon.setPixmap(self.mainTheme.getPixmap("proj_document", (nPx, nPx)))
self.leftBox = QVBoxLayout()
self.leftBox.setSpacing(vSp)
diff --git a/novelwriter/tools/projwizard.py b/novelwriter/tools/projwizard.py
index 3dac9ed8..5b21f69a 100644
--- a/novelwriter/tools/projwizard.py
+++ b/novelwriter/tools/projwizard.py
@@ -54,11 +54,11 @@ class GuiProjectWizard(QWizard):
logger.debug("Initialising GuiProjectWizard ...")
self.setObjectName("GuiProjectWizard")
- self.mainConf = novelwriter.CONFIG
- self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainConf = novelwriter.CONFIG
+ self.mainGui = mainGui
+ self.mainTheme = mainGui.mainTheme
- self.sideImage = self.theTheme.loadDecoration(
+ self.sideImage = self.mainTheme.loadDecoration(
"wiz-back", None, self.mainConf.pxInt(370)
)
self.setWizardStyle(QWizard.ModernStyle)
@@ -92,7 +92,7 @@ class ProjWizardIntroPage(QWizardPage):
self.mainConf = novelwriter.CONFIG
self.theWizard = theWizard
- self.theTheme = theWizard.theTheme
+ self.mainTheme = theWizard.mainTheme
self.setTitle(self.tr("Create New Project"))
self.theText = QLabel(self.tr(
@@ -107,7 +107,7 @@ class ProjWizardIntroPage(QWizardPage):
"Peter Mitterhofer", "CC BY-SA 4.0"
))
lblFont = self.imgCredit.font()
- lblFont.setPointSizeF(0.6*self.theTheme.fontPointSize)
+ lblFont.setPointSizeF(0.6*self.mainTheme.fontPointSize)
self.imgCredit.setFont(lblFont)
xW = self.mainConf.pxInt(300)
@@ -162,7 +162,7 @@ class ProjWizardFolderPage(QWizardPage):
self.mainConf = novelwriter.CONFIG
self.theWizard = theWizard
- self.theTheme = theWizard.theTheme
+ self.mainTheme = theWizard.mainTheme
self.setTitle(self.tr("Select Project Folder"))
self.theText = QLabel(self.tr(
@@ -180,7 +180,7 @@ class ProjWizardFolderPage(QWizardPage):
self.projPath.setPlaceholderText(self.tr("Required"))
self.browseButton = QPushButton("...")
- self.browseButton.setMaximumWidth(int(2.5*self.theTheme.getTextWidth("...")))
+ self.browseButton.setMaximumWidth(int(2.5*self.mainTheme.getTextWidth("...")))
self.browseButton.clicked.connect(self._doBrowse)
self.errLabel = QLabel("")
diff --git a/novelwriter/tools/writingstats.py b/novelwriter/tools/writingstats.py
index d4527612..add052ec 100644
--- a/novelwriter/tools/writingstats.py
+++ b/novelwriter/tools/writingstats.py
@@ -65,7 +65,7 @@ class GuiWritingStats(QDialog):
self.mainConf = novelwriter.CONFIG
self.mainGui = mainGui
- self.theTheme = mainGui.theTheme
+ self.mainTheme = mainGui.mainTheme
self.theProject = mainGui.theProject
self.logData = []
@@ -125,7 +125,7 @@ class GuiWritingStats(QDialog):
self.listBox.setSortingEnabled(True)
# Word Bar
- self.barHeight = int(round(0.5*self.theTheme.fontPixelSize))
+ self.barHeight = int(round(0.5*self.mainTheme.fontPixelSize))
self.barWidth = self.mainConf.pxInt(200)
self.barImage = QPixmap(self.barHeight, self.barHeight)
self.barImage.fill(self.palette().highlight().color())
@@ -136,27 +136,27 @@ class GuiWritingStats(QDialog):
self.infoBox.setLayout(self.infoForm)
self.labelTotal = QLabel(formatTime(0))
- self.labelTotal.setFont(self.theTheme.guiFontFixed)
+ self.labelTotal.setFont(self.mainTheme.guiFontFixed)
self.labelTotal.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.labelIdleT = QLabel(formatTime(0))
- self.labelIdleT.setFont(self.theTheme.guiFontFixed)
+ self.labelIdleT.setFont(self.mainTheme.guiFontFixed)
self.labelIdleT.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.labelFilter = QLabel(formatTime(0))
- self.labelFilter.setFont(self.theTheme.guiFontFixed)
+ self.labelFilter.setFont(self.mainTheme.guiFontFixed)
self.labelFilter.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.novelWords = QLabel("0")
- self.novelWords.setFont(self.theTheme.guiFontFixed)
+ self.novelWords.setFont(self.mainTheme.guiFontFixed)
self.novelWords.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.notesWords = QLabel("0")
- self.notesWords.setFont(self.theTheme.guiFontFixed)
+ self.notesWords.setFont(self.mainTheme.guiFontFixed)
self.notesWords.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.totalWords = QLabel("0")
- self.totalWords.setFont(self.theTheme.guiFontFixed)
+ self.totalWords.setFont(self.mainTheme.guiFontFixed)
self.totalWords.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
lblTTime = QLabel(self.tr("Total Time:"))
@@ -183,7 +183,7 @@ class GuiWritingStats(QDialog):
self.infoForm.setRowStretch(6, 1)
# Filter Options
- sPx = self.theTheme.baseIconSize
+ sPx = self.mainTheme.baseIconSize
self.filterBox = QGroupBox(self.tr("Filters"), self)
self.filterForm = QGridLayout(self)
@@ -605,13 +605,13 @@ class GuiWritingStats(QDialog):
newItem.setTextAlignment(self.C_COUNT, Qt.AlignRight)
newItem.setTextAlignment(self.C_BAR, Qt.AlignLeft | Qt.AlignVCenter)
- newItem.setFont(self.C_TIME, self.theTheme.guiFontFixed)
- newItem.setFont(self.C_LENGTH, self.theTheme.guiFontFixed)
- newItem.setFont(self.C_COUNT, self.theTheme.guiFontFixed)
+ newItem.setFont(self.C_TIME, self.mainTheme.guiFontFixed)
+ newItem.setFont(self.C_LENGTH, self.mainTheme.guiFontFixed)
+ newItem.setFont(self.C_COUNT, self.mainTheme.guiFontFixed)
if showIdleTime:
- newItem.setFont(self.C_IDLE, self.theTheme.guiFontFixed)
+ newItem.setFont(self.C_IDLE, self.mainTheme.guiFontFixed)
else:
- newItem.setFont(self.C_IDLE, self.theTheme.guiFont)
+ newItem.setFont(self.C_IDLE, self.mainTheme.guiFont)
self.listBox.addTopLevelItem(newItem)
self.timeFilter += sDiff
diff --git a/tests/test_dialogs/test_dlg_about.py b/tests/test_dialogs/test_dlg_about.py
index c5ccfe7f..a4623c1f 100644
--- a/tests/test_dialogs/test_dlg_about.py
+++ b/tests/test_dialogs/test_dlg_about.py
@@ -36,8 +36,8 @@ def testDlgAbout_NWDialog(qtbot, monkeypatch, nwGUI):
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
# NW About
- nwGUI.theTheme.themeName = "A Theme"
- nwGUI.theTheme.themeAuthor = "An Author"
+ nwGUI.mainTheme.themeName = "A Theme"
+ nwGUI.mainTheme.themeAuthor = "An Author"
assert nwGUI.showAboutNWDialog(showNotes=True) is True
qtbot.waitUntil(lambda: getGuiItem("GuiAbout") is not None, timeout=1000)
diff --git a/tests/test_gui/test_gui_theme.py b/tests/test_gui/test_gui_theme.py
index da7fc414..756b2a81 100644
--- a/tests/test_gui/test_gui_theme.py
+++ b/tests/test_gui/test_gui_theme.py
@@ -93,82 +93,82 @@ def testGuiTheme_Main(qtbot, monkeypatch, nwMinimal, tmpDir):
assert thePalette.link().color() == QColor(44, 152, 247)
assert thePalette.linkVisited().color() == QColor(44, 152, 247)
- assert nwGUI.theTheme.statNone == [150, 152, 150]
- assert nwGUI.theTheme.statSaved == [39, 135, 78]
- assert nwGUI.theTheme.statUnsaved == [138, 32, 32]
+ assert nwGUI.mainTheme.statNone == [150, 152, 150]
+ assert nwGUI.mainTheme.statSaved == [39, 135, 78]
+ assert nwGUI.mainTheme.statUnsaved == [138, 32, 32]
# Check Syntax Colours
- assert nwGUI.theTheme.colBack == [45, 45, 45]
- assert nwGUI.theTheme.colText == [204, 204, 204]
- assert nwGUI.theTheme.colLink == [102, 153, 204]
- assert nwGUI.theTheme.colHead == [102, 153, 204]
- assert nwGUI.theTheme.colHeadH == [102, 153, 204]
- assert nwGUI.theTheme.colEmph == [249, 145, 57]
- assert nwGUI.theTheme.colDialN == [242, 119, 122]
- assert nwGUI.theTheme.colDialD == [153, 204, 153]
- assert nwGUI.theTheme.colDialS == [255, 204, 102]
- assert nwGUI.theTheme.colHidden == [153, 153, 153]
- assert nwGUI.theTheme.colKey == [242, 119, 122]
- assert nwGUI.theTheme.colVal == [204, 153, 204]
- assert nwGUI.theTheme.colSpell == [242, 119, 122]
- assert nwGUI.theTheme.colError == [153, 204, 153]
- assert nwGUI.theTheme.colRepTag == [102, 204, 204]
- assert nwGUI.theTheme.colMod == [249, 145, 57]
+ assert nwGUI.mainTheme.colBack == [45, 45, 45]
+ assert nwGUI.mainTheme.colText == [204, 204, 204]
+ assert nwGUI.mainTheme.colLink == [102, 153, 204]
+ assert nwGUI.mainTheme.colHead == [102, 153, 204]
+ assert nwGUI.mainTheme.colHeadH == [102, 153, 204]
+ assert nwGUI.mainTheme.colEmph == [249, 145, 57]
+ assert nwGUI.mainTheme.colDialN == [242, 119, 122]
+ assert nwGUI.mainTheme.colDialD == [153, 204, 153]
+ assert nwGUI.mainTheme.colDialS == [255, 204, 102]
+ assert nwGUI.mainTheme.colHidden == [153, 153, 153]
+ assert nwGUI.mainTheme.colKey == [242, 119, 122]
+ assert nwGUI.mainTheme.colVal == [204, 153, 204]
+ assert nwGUI.mainTheme.colSpell == [242, 119, 122]
+ assert nwGUI.mainTheme.colError == [153, 204, 153]
+ assert nwGUI.mainTheme.colRepTag == [102, 204, 204]
+ assert nwGUI.mainTheme.colMod == [249, 145, 57]
# Test Icon class
- theIcons = nwGUI.theTheme.theIcons
+ iconCache = nwGUI.mainTheme.iconCache
novelwriter.CONFIG.guiIcons = "invalid"
- assert theIcons.updateTheme() is True
+ assert iconCache.updateTheme() is True
assert novelwriter.CONFIG.guiIcons == "typicons_light"
# Ask for a non-existent key
- anImg = theIcons.loadDecoration("nonsense", 20, 20)
+ anImg = iconCache.loadDecoration("nonsense", 20, 20)
assert isinstance(anImg, QPixmap)
assert anImg.isNull()
# Add a non-existent file and request it
- theIcons.DECO_MAP["nonsense"] = "nofile.jpg"
- anImg = theIcons.loadDecoration("nonsense", 20, 20)
+ iconCache.DECO_MAP["nonsense"] = "nofile.jpg"
+ anImg = iconCache.loadDecoration("nonsense", 20, 20)
assert isinstance(anImg, QPixmap)
assert anImg.isNull()
# Get a real image, with different size parameters
- anImg = theIcons.loadDecoration("wiz-back", 20, None)
+ anImg = iconCache.loadDecoration("wiz-back", 20, None)
assert isinstance(anImg, QPixmap)
assert not anImg.isNull()
assert anImg.width() == 20
assert anImg.height() >= 56
- anImg = theIcons.loadDecoration("wiz-back", None, 70)
+ anImg = iconCache.loadDecoration("wiz-back", None, 70)
assert isinstance(anImg, QPixmap)
assert not anImg.isNull()
assert anImg.height() == 70
assert anImg.width() >= 24
- anImg = theIcons.loadDecoration("wiz-back", 30, 70)
+ anImg = iconCache.loadDecoration("wiz-back", 30, 70)
assert isinstance(anImg, QPixmap)
assert not anImg.isNull()
assert anImg.height() == 70
assert anImg.width() == 30
- anImg = theIcons.loadDecoration("wiz-back", None, None)
+ anImg = iconCache.loadDecoration("wiz-back", None, None)
assert isinstance(anImg, QPixmap)
assert not anImg.isNull()
assert anImg.height() >= 1500
assert anImg.width() >= 500
# Load icons
- anIcon = theIcons.getIcon("nonsense")
+ anIcon = iconCache.getIcon("nonsense")
assert isinstance(anIcon, QIcon)
assert anIcon.isNull()
- anIcon = theIcons.getIcon("novelwriter")
+ anIcon = iconCache.getIcon("novelwriter")
assert isinstance(anIcon, QIcon)
assert not anIcon.isNull()
# Check return empty icon if file not found
- theIcons.ICON_KEYS.add("testicon3")
- anIcon = theIcons.getIcon("testicon3")
+ iconCache.ICON_KEYS.add("testicon3")
+ anIcon = iconCache.getIcon("testicon3")
assert isinstance(anIcon, QIcon)
assert anIcon.isNull()
From 60584239701997ef268e6dae0ce6e1d78b33ce5d Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 11 Jun 2022 18:17:57 +0200
Subject: [PATCH 18/35] Add a new edit label dialog
---
novelwriter/dialogs/editlabel.py | 84 ++++++++++++++++++++++++++++++++
1 file changed, 84 insertions(+)
create mode 100644 novelwriter/dialogs/editlabel.py
diff --git a/novelwriter/dialogs/editlabel.py b/novelwriter/dialogs/editlabel.py
new file mode 100644
index 00000000..03bf9d08
--- /dev/null
+++ b/novelwriter/dialogs/editlabel.py
@@ -0,0 +1,84 @@
+"""
+novelWriter – Edit Label Dialog
+===============================
+A simple dialog for editing a label
+
+File History:
+Created: 2022-06-11 [1.7b1]
+
+This file is a part of novelWriter
+Copyright 2018–2022, Veronica Berglyd Olsen
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+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 .
+"""
+
+import logging
+import novelwriter
+
+from PyQt5.QtWidgets import (
+ QDialog, QVBoxLayout, QLineEdit, QLabel, QDialogButtonBox, QHBoxLayout
+)
+
+logger = logging.getLogger(__name__)
+
+
+class GuiEditLabel(QDialog):
+
+ def __init__(self, parent, text=""):
+ QDialog.__init__(self, parent=parent)
+
+ self.setObjectName("GuiEditLabel")
+ self.setWindowTitle(self.tr("Item Label"))
+
+ mVd = novelwriter.CONFIG.pxInt(220)
+ mSp = novelwriter.CONFIG.pxInt(12)
+
+ # Item Label
+ self.labelValue = QLineEdit()
+ self.labelValue.setMinimumWidth(mVd)
+ self.labelValue.setMaxLength(200)
+ self.labelValue.setText(text)
+ self.labelValue.selectAll()
+
+ # Buttons
+ self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
+ self.buttonBox.accepted.connect(self.accept)
+ self.buttonBox.rejected.connect(self.reject)
+
+ # Assemble
+ self.innerBox = QHBoxLayout()
+ self.innerBox.addWidget(QLabel(self.tr("Label")), 0)
+ self.innerBox.addWidget(self.labelValue, 1)
+ self.innerBox.setSpacing(mSp)
+
+ self.outerBox = QVBoxLayout()
+ self.outerBox.setSpacing(mSp)
+ self.outerBox.addLayout(self.innerBox, 1)
+ self.outerBox.addWidget(self.buttonBox, 0)
+
+ self.setLayout(self.outerBox)
+
+ return
+
+ @property
+ def itemLabel(self):
+ return self.labelValue.text()
+
+ @classmethod
+ def getLabel(cls, parent, text):
+ cls = GuiEditLabel(parent, text=text)
+ cls.exec_()
+ return cls.itemLabel, cls.result() == QDialog.Accepted
+
+# END Class GuiEditLabel
From 37c3bb8cd229ffcea076ee3e9df17bdda5737cc7 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 11 Jun 2022 18:19:21 +0200
Subject: [PATCH 19/35] Replace the item editor with the label editor dialog
---
novelwriter/dialogs/__init__.py | 4 +-
novelwriter/dialogs/itemeditor.py | 203 ------------------
novelwriter/gui/mainmenu.py | 4 +-
novelwriter/gui/projtree.py | 39 ++--
novelwriter/guimain.py | 2 +-
tests/test_dialogs/test_dlg_docmerge.py | 7 +-
tests/test_dialogs/test_dlg_docsplit.py | 7 +-
tests/test_dialogs/test_dlg_itemeditor.py | 246 ----------------------
tests/test_gui/test_gui_guimain.py | 7 +-
tests/test_gui/test_gui_projtree.py | 15 +-
10 files changed, 40 insertions(+), 494 deletions(-)
delete mode 100644 novelwriter/dialogs/itemeditor.py
delete mode 100644 tests/test_dialogs/test_dlg_itemeditor.py
diff --git a/novelwriter/dialogs/__init__.py b/novelwriter/dialogs/__init__.py
index 30bd5d82..03efef5c 100644
--- a/novelwriter/dialogs/__init__.py
+++ b/novelwriter/dialogs/__init__.py
@@ -22,7 +22,7 @@ along with this program. If not, see .
from novelwriter.dialogs.about import GuiAbout
from novelwriter.dialogs.docmerge import GuiDocMerge
from novelwriter.dialogs.docsplit import GuiDocSplit
-from novelwriter.dialogs.itemeditor import GuiItemEditor
+from novelwriter.dialogs.editlabel import GuiEditLabel
from novelwriter.dialogs.preferences import GuiPreferences
from novelwriter.dialogs.projdetails import GuiProjectDetails
from novelwriter.dialogs.projload import GuiProjectLoad
@@ -35,7 +35,7 @@ __all__ = [
"GuiAbout",
"GuiDocMerge",
"GuiDocSplit",
- "GuiItemEditor",
+ "GuiEditLabel",
"GuiPreferences",
"GuiProjectDetails",
"GuiProjectLoad",
diff --git a/novelwriter/dialogs/itemeditor.py b/novelwriter/dialogs/itemeditor.py
deleted file mode 100644
index 7ad4eed0..00000000
--- a/novelwriter/dialogs/itemeditor.py
+++ /dev/null
@@ -1,203 +0,0 @@
-"""
-novelWriter – GUI Item Editor
-=============================
-GUI class for the item editor dialog
-
-File History:
-Created: 2019-04-27 [0.0.1]
-
-This file is a part of novelWriter
-Copyright 2018–2022, Veronica Berglyd Olsen
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-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 .
-"""
-
-import logging
-import novelwriter
-
-from PyQt5.QtCore import pyqtSlot
-from PyQt5.QtWidgets import (
- QDialog, QVBoxLayout, QGridLayout, QLineEdit, QComboBox, QLabel,
- QDialogButtonBox
-)
-
-from novelwriter.enum import nwItemLayout, nwItemType
-from novelwriter.constants import trConst, nwLabels
-from novelwriter.gui.custom import QSwitch
-
-logger = logging.getLogger(__name__)
-
-
-class GuiItemEditor(QDialog):
-
- def __init__(self, mainGui, tHandle):
- QDialog.__init__(self, mainGui)
-
- logger.debug("Initialising GuiItemEditor ...")
- self.setObjectName("GuiItemEditor")
-
- self.mainConf = novelwriter.CONFIG
- self.mainGui = mainGui
- self.theProject = mainGui.theProject
-
- ##
- # Build GUI
- ##
-
- self.theItem = self.theProject.tree[tHandle]
- if self.theItem is None:
- self.close()
- return
-
- self.setWindowTitle(self.tr("Item Settings"))
-
- mVd = self.mainConf.pxInt(220)
- mSp = self.mainConf.pxInt(16)
- vSp = self.mainConf.pxInt(4)
-
- # Item Label
- self.editName = QLineEdit()
- self.editName.setMinimumWidth(mVd)
- self.editName.setMaxLength(200)
-
- # Item Status
- self.editStatus = QComboBox()
- self.editStatus.setMinimumWidth(mVd)
- if self.theItem.isNovelLike():
- for key, entry in self.theProject.statusItems.items():
- self.editStatus.addItem(entry["icon"], entry["name"], key)
-
- index = self.editStatus.findData(self.theItem.itemStatus)
- if index != -1:
- self.editStatus.setCurrentIndex(index)
-
- else:
- for key, entry in self.theProject.importItems.items():
- self.editStatus.addItem(entry["icon"], entry["name"], key)
-
- index = self.editStatus.findData(self.theItem.itemImport)
- if index != -1:
- self.editStatus.setCurrentIndex(index)
-
- # Item Layout
- self.editLayout = QComboBox()
- self.editLayout.setMinimumWidth(mVd)
- validLayouts = []
- if self.theItem.itemType == nwItemType.FILE:
- if self.theItem.documentAllowed():
- validLayouts.append(nwItemLayout.DOCUMENT)
- validLayouts.append(nwItemLayout.NOTE)
- else:
- validLayouts.append(nwItemLayout.NO_LAYOUT)
- self.editLayout.setEnabled(False)
-
- for itemLayout in nwItemLayout:
- if itemLayout in validLayouts:
- self.editLayout.addItem(trConst(nwLabels.LAYOUT_NAME[itemLayout]), itemLayout)
-
- index = self.editLayout.findData(self.theItem.itemLayout)
- if index != -1:
- self.editLayout.setCurrentIndex(index)
-
- # Export Switch
- self.textExport = QLabel(self.tr("Include when building project"))
- self.editExport = QSwitch()
- if self.theItem.itemType == nwItemType.FILE:
- self.editExport.setEnabled(True)
- self.editExport.setChecked(self.theItem.isExported)
- else:
- self.editExport.setEnabled(False)
- self.editExport.setChecked(False)
-
- # Buttons
- self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
- self.buttonBox.accepted.connect(self._doSave)
- self.buttonBox.rejected.connect(self._doClose)
-
- # Set Current Values
- self.editName.setText(self.theItem.itemName)
- self.editName.selectAll()
-
- ##
- # Assemble
- ##
-
- nameLabel = QLabel(self.tr("Label"))
- statusLabel = QLabel(self.tr("Status"))
- layoutLabel = QLabel(self.tr("Layout"))
-
- self.mainForm = QGridLayout()
- self.mainForm.setVerticalSpacing(vSp)
- self.mainForm.setHorizontalSpacing(mSp)
- self.mainForm.addWidget(nameLabel, 0, 0, 1, 1)
- self.mainForm.addWidget(self.editName, 0, 1, 1, 2)
- self.mainForm.addWidget(statusLabel, 1, 0, 1, 1)
- self.mainForm.addWidget(self.editStatus, 1, 1, 1, 2)
- self.mainForm.addWidget(layoutLabel, 2, 0, 1, 1)
- self.mainForm.addWidget(self.editLayout, 2, 1, 1, 2)
- self.mainForm.addWidget(self.textExport, 3, 0, 1, 2)
- self.mainForm.addWidget(self.editExport, 3, 2, 1, 1)
- self.mainForm.setColumnStretch(0, 0)
- self.mainForm.setColumnStretch(1, 1)
- self.mainForm.setColumnStretch(2, 0)
-
- self.outerBox = QVBoxLayout()
- self.outerBox.setSpacing(mSp)
- self.outerBox.addLayout(self.mainForm)
- self.outerBox.addStretch(1)
- self.outerBox.addWidget(self.buttonBox)
- self.setLayout(self.outerBox)
-
- self.rejected.connect(self._doClose)
-
- logger.debug("GuiItemEditor initialisation complete")
-
- return
-
- ##
- # Slots
- ##
-
- @pyqtSlot()
- def _doSave(self):
- """Save the setting to the item.
- """
- logger.verbose("ItemEditor save button clicked")
-
- itemName = self.editName.text()
- itemStatus = self.editStatus.currentData()
- itemLayout = self.editLayout.currentData()
- isExported = self.editExport.isChecked()
-
- self.theItem.setName(itemName)
- self.theItem.setImportStatus(itemStatus)
- self.theItem.setLayout(itemLayout)
- self.theItem.setExported(isExported)
-
- self.theProject.setProjectChanged(True)
-
- self.accept()
- self.close()
-
- return
-
- @pyqtSlot()
- def _doClose(self):
- """Close the dialog without saving the settings.
- """
- logger.verbose("ItemEditor cancel button clicked")
- self.close()
- return
-
-# END Class GuiItemEditor
diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py
index e7203bb9..85920749 100644
--- a/novelwriter/gui/mainmenu.py
+++ b/novelwriter/gui/mainmenu.py
@@ -163,8 +163,8 @@ class GuiMainMenu(QMenuBar):
self.projMenu.addSeparator()
# Project > Edit
- self.aEditItem = QAction(self.tr("Edit Item"), self)
- self.aEditItem.setShortcuts(["Ctrl+E", "F2"])
+ self.aEditItem = QAction(self.tr("Rename Item"), self)
+ self.aEditItem.setShortcuts(["F2"])
self.aEditItem.triggered.connect(lambda: self.mainGui.editItem(None))
self.projMenu.addAction(self.aEditItem)
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index 4c0ea59b..aa1ff9ce 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -34,15 +34,15 @@ from time import time
from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QIcon, QPalette
from PyQt5.QtWidgets import (
- QAbstractItemView, QDialog, QFrame, QHBoxLayout, QHeaderView, QInputDialog,
- QLabel, QMenu, QShortcut, QSizePolicy, QToolButton, QTreeWidget,
- QTreeWidgetItem, QVBoxLayout, QWidget
+ QAbstractItemView, QFrame, QHBoxLayout, QHeaderView, QLabel,
+ QMenu, QShortcut, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem,
+ QVBoxLayout, QWidget
)
from novelwriter.core import NWDoc
from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert
-from novelwriter.dialogs.itemeditor import GuiItemEditor
from novelwriter.constants import trConst, nwLabels
+from novelwriter.dialogs.editlabel import GuiEditLabel
logger = logging.getLogger(__name__)
@@ -99,7 +99,7 @@ class GuiProjectView(QWidget):
# Function Mappings
self.revealNewTreeItem = self.projTree.revealNewTreeItem
- self.editTreeItem = self.projTree.editTreeItem
+ self.renameTreeItem = self.projTree.renameTreeItem
self.getTreeFromHandle = self.projTree.getTreeFromHandle
self.emptyTrash = self.projTree.emptyTrash
self.deleteItem = self.projTree.deleteItem
@@ -470,7 +470,7 @@ class GuiProjectTree(QTreeWidget):
else:
newLabel = self.tr("New Folder")
- newLabel, dlgOk = QInputDialog.getText(self, "", self.tr("Label:"), text=newLabel)
+ newLabel, dlgOk = GuiEditLabel.getLabel(self, text=newLabel)
if not dlgOk:
logger.info("New item creation cancelled by user")
return False
@@ -565,23 +565,20 @@ class GuiProjectTree(QTreeWidget):
return True
- def editTreeItem(self, tHandle):
- """Open the edit item dialog.
+ def renameTreeItem(self, tHandle):
+ """Open a dialog to edit the label of an item.
"""
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:
+ newLabel, dlgOk = GuiEditLabel.getLabel(self, text=tItem.itemName)
+ if dlgOk:
+ tItem.setName(newLabel)
self.setTreeItemValues(tHandle)
self._alertTreeChange(tHandle=tHandle, flush=False)
- return True
+ return
def saveTreeOrder(self):
"""Build a list of the items in the project tree and send them
@@ -1019,6 +1016,10 @@ class GuiProjectTree(QTreeWidget):
# Edit Item Settings
# ==================
+ ctxMenu.addAction(
+ self.tr("Change Label"), lambda: self.renameTreeItem(tHandle)
+ )
+
if isFile:
ctxMenu.addAction(
self.tr("Toggle Exported"), lambda: self._toggleItemExported(tHandle)
@@ -1057,12 +1058,8 @@ class GuiProjectTree(QTreeWidget):
ctxMenu.addSeparator()
- # Major Item Actions
- # ==================
-
- ctxMenu.addAction(
- self.tr("Edit Item Settings"), lambda: self.editTreeItem(tHandle)
- )
+ # Delete Item
+ # ===========
if tItem.itemClass == nwItemClass.TRASH or tItem.itemType == nwItemType.ROOT:
ctxMenu.addAction(
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 6b315866..de80c59c 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -817,7 +817,7 @@ class GuiMain(QMainWindow):
else:
tHandle = self.projView.getSelectedHandle()
if tHandle:
- return self.projView.editTreeItem(tHandle)
+ return self.projView.renameTreeItem(tHandle)
return False
diff --git a/tests/test_dialogs/test_dlg_docmerge.py b/tests/test_dialogs/test_dlg_docmerge.py
index 9d9c9082..4e3138f6 100644
--- a/tests/test_dialogs/test_dlg_docmerge.py
+++ b/tests/test_dialogs/test_dlg_docmerge.py
@@ -25,10 +25,10 @@ import pytest
from mock import causeOSError
from tools import getGuiItem, readFile, writeFile, buildTestProject
-from PyQt5.QtWidgets import QAction, QMessageBox, QDialog, QInputDialog
+from PyQt5.QtWidgets import QAction, QMessageBox
from novelwriter.enum import nwItemType, nwWidget
-from novelwriter.dialogs import GuiDocMerge, GuiItemEditor
+from novelwriter.dialogs import GuiDocMerge, GuiEditLabel
from novelwriter.core.tree import NWTree
@@ -39,7 +39,7 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Block message box
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Ok)
- monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
+ monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
# Create a new project
buildTestProject(nwGUI, fncProj)
@@ -55,7 +55,6 @@ def testDlgMerge_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
hMergedDoc = "0000000000023"
# Add Project Content
- monkeypatch.setattr(GuiItemEditor, "exec_", lambda *a: QDialog.Accepted)
nwGUI.switchFocus(nwWidget.TREE)
nwGUI.projView.projTree.clearSelection()
nwGUI.projView.projTree._getTreeItem(hChapterDir).setSelected(True)
diff --git a/tests/test_dialogs/test_dlg_docsplit.py b/tests/test_dialogs/test_dlg_docsplit.py
index 5b042570..d0201d6a 100644
--- a/tests/test_dialogs/test_dlg_docsplit.py
+++ b/tests/test_dialogs/test_dlg_docsplit.py
@@ -25,10 +25,10 @@ import pytest
from mock import causeOSError
from tools import getGuiItem, readFile, writeFile, buildTestProject
-from PyQt5.QtWidgets import QAction, QMessageBox, QDialog, QInputDialog
+from PyQt5.QtWidgets import QAction, QMessageBox
from novelwriter.enum import nwItemType, nwWidget
-from novelwriter.dialogs import GuiDocSplit, GuiItemEditor
+from novelwriter.dialogs import GuiDocSplit, GuiEditLabel
from novelwriter.core.tree import NWTree
from novelwriter.core.document import NWDoc
@@ -40,7 +40,7 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Block message box
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Ok)
- monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
+ monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
# Create a new project
buildTestProject(nwGUI, fncProj)
@@ -59,7 +59,6 @@ def testDlgSplit_Main(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
hSceneFive = "0000000000028"
# Add Project Content
- monkeypatch.setattr(GuiItemEditor, "exec_", lambda *a: QDialog.Accepted)
nwGUI.switchFocus(nwWidget.TREE)
nwGUI.projView.projTree.clearSelection()
nwGUI.projView.projTree._getTreeItem(hNovelRoot).setSelected(True)
diff --git a/tests/test_dialogs/test_dlg_itemeditor.py b/tests/test_dialogs/test_dlg_itemeditor.py
deleted file mode 100644
index 360f7641..00000000
--- a/tests/test_dialogs/test_dlg_itemeditor.py
+++ /dev/null
@@ -1,246 +0,0 @@
-"""
-novelWriter – Item Editor Dialog Class Tester
-=============================================
-
-This file is a part of novelWriter
-Copyright 2018–2022, Veronica Berglyd Olsen
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-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 .
-"""
-
-import pytest
-
-from tools import getGuiItem, buildTestProject
-
-from PyQt5.QtWidgets import QAction, QDialog, QMessageBox, QInputDialog
-
-from novelwriter.enum import nwItemLayout, nwItemType
-from novelwriter.dialogs import GuiItemEditor
-from novelwriter.core.tree import NWTree
-from novelwriter.gui.projtree import GuiProjectTree
-
-statusKeys = ["s000000", "s000001", "s000002", "s000003"]
-importKeys = ["i000004", "i000005", "i000006", "i000007"]
-
-
-@pytest.mark.gui
-def testDlgItemEditor_Dialog(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
- """Test launching the item editor dialog from GuiMain.
- """
- # Block message box
- monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
-
- # Block Dialog exec_
- monkeypatch.setattr(GuiItemEditor, "exec_", lambda *a: None)
-
- # Open Editor wo/Project
- assert nwGUI.editItem() is False
-
- # Create and Open Project
- buildTestProject(nwGUI, fncProj)
- tHandle = "000000000000f"
-
- # No Selection
- nwGUI.projView.projTree.clearSelection()
- assert nwGUI.editItem() is False
-
- # Force opening from editor
- assert nwGUI.openDocument(tHandle)
- nwGUI.isFocusMode = True
-
- # Block Tree Lookup
- with monkeypatch.context() as mp:
- mp.setattr(NWTree, "__getitem__", lambda *a: None)
- assert nwGUI.editItem() is False
-
- # Invalid Type
- nwGUI.theProject.tree[tHandle]._type = nwItemType.NO_TYPE
- assert nwGUI.editItem() is False
- nwGUI.theProject.tree[tHandle]._type = nwItemType.FILE
-
- # Open Properly
- assert nwGUI.editItem() is True
- qtbot.waitUntil(lambda: getGuiItem("GuiItemEditor") is not None, timeout=1000)
- itemEdit = getGuiItem("GuiItemEditor")
- assert itemEdit is not None
- itemEdit.close()
-
- # Open Via Menu
- with monkeypatch.context() as mp:
- mp.setattr(GuiItemEditor, "result", lambda *a: QDialog.Accepted)
- nwGUI.mainMenu.aEditItem.activate(QAction.Trigger)
- qtbot.waitUntil(lambda: getGuiItem("GuiItemEditor") is not None, timeout=1000)
- itemEdit = getGuiItem("GuiItemEditor")
- assert itemEdit is not None
- itemEdit.close()
-
- nwGUI.isFocusMode = False
-
-# END Test testDlgItemEditor_Dialog
-
-
-@pytest.mark.gui
-def testDlgItemEditor_Novel(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
- """Test the item editor dialog for a novel document.
- """
- # Block message box
- monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
- monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
-
- # Create Project and Open Document
- buildTestProject(nwGUI, fncProj)
- tHandle = "000000000000f"
-
- assert nwGUI.theProject.statusItems.name(statusKeys[0]) == "New"
- assert nwGUI.theProject.statusItems.name(statusKeys[1]) == "Note"
-
- assert nwGUI.openDocument(tHandle) is True
-
- # Check that an invalid handle is managed
- itemEdit = GuiItemEditor(nwGUI, "whatever")
- itemEdit.show()
- itemEdit._doClose()
-
- # Edit a Document
- itemEdit = GuiItemEditor(nwGUI, tHandle)
- itemEdit.show()
-
- # Check Existing Settings
- assert itemEdit.editName.text() == "New Scene"
- assert itemEdit.editStatus.currentData() == statusKeys[0]
- assert itemEdit.editLayout.currentData() == nwItemLayout.DOCUMENT
- assert itemEdit.editExport.isChecked() is True
-
- # Change Settings
- layoutIdx = itemEdit.editLayout.findData(nwItemLayout.NOTE)
- itemEdit.editName.setText("Great Scene")
- itemEdit.editStatus.setCurrentIndex(1)
- itemEdit.editLayout.setCurrentIndex(layoutIdx)
- itemEdit.editExport.setChecked(False)
-
- # Check New Settings
- itemEdit._doSave()
- assert itemEdit.theItem.itemName == "Great Scene"
- assert itemEdit.theItem.itemStatus == statusKeys[1]
- assert itemEdit.theItem.itemLayout == nwItemLayout.NOTE
- assert itemEdit.theItem.isExported is False
-
- # Check that the editor header is updated
- nwGUI.docEditor.updateDocInfo(tHandle)
- assert nwGUI.docEditor.docHeader.theTitle.text() == "Novel › New Chapter › Great Scene"
-
- itemEdit.close()
- del itemEdit
- # qtbot.stopForInteraction()
-
-# END Test testDlgItemEditor_Dialog
-
-
-@pytest.mark.gui
-def testDlgItemEditor_Note(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
- """Test the item editor dialog for a project note.
- """
- # Block message box
- monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
- monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
- monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
-
- # Create Project and Open Document
- buildTestProject(nwGUI, fncProj)
- assert nwGUI.theProject.statusItems.name(statusKeys[0]) == "New"
- assert nwGUI.theProject.statusItems.name(statusKeys[1]) == "Note"
- assert nwGUI.theProject.importItems.name(importKeys[0]) == "New"
- assert nwGUI.theProject.importItems.name(importKeys[1]) == "Minor"
-
- # Create Note
- nwGUI.projView.projTree.clearSelection()
- nwGUI.projView.projTree._getTreeItem("000000000000a").setSelected(True)
- nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, None, isNote=True)
-
- # Open Note
- assert nwGUI.openDocument("0000000000010")
-
- # Edit a Document
- itemEdit = GuiItemEditor(nwGUI, "0000000000010")
- itemEdit.show()
-
- # Check Existing Settings
- assert itemEdit.editName.text() == "New Note"
- assert itemEdit.editStatus.currentData() == importKeys[0]
- assert itemEdit.editLayout.currentData() == nwItemLayout.NOTE
- assert itemEdit.editExport.isChecked() is True
-
- # Change Settings
- itemEdit.editName.setText("New Character")
- itemEdit.editStatus.setCurrentIndex(1)
- itemEdit.editExport.setChecked(False)
- itemEdit._doSave()
-
- # Check New Settings
- assert itemEdit.theItem.itemName == "New Character"
- assert itemEdit.theItem.itemStatus == statusKeys[0]
- assert itemEdit.theItem.itemImport == importKeys[1]
- assert itemEdit.theItem.itemLayout == nwItemLayout.NOTE
- assert itemEdit.theItem.isExported is False
-
- itemEdit.close()
- del itemEdit
- # qtbot.stopForInteraction()
-
-# END Test testDlgItemEditor_Note
-
-
-@pytest.mark.gui
-def testDlgItemEditor_Folder(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
- """Test the item editor dialog for a folder.
- """
- # Block message box
- monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
- monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
-
- # Create Project and Open Document
- buildTestProject(nwGUI, fncProj)
-
- # Edit a Folder
- itemEdit = GuiItemEditor(nwGUI, "000000000000d")
- itemEdit.show()
-
- assert nwGUI.theProject.statusItems.name(statusKeys[0]) == "New"
- assert nwGUI.theProject.statusItems.name(statusKeys[1]) == "Note"
-
- # Check Existing Settings
- assert itemEdit.editName.text() == "New Chapter"
- assert itemEdit.editStatus.currentData() == statusKeys[0]
- assert itemEdit.editLayout.currentData() == nwItemLayout.NO_LAYOUT
- assert itemEdit.editExport.isChecked() is False
-
- assert itemEdit.editLayout.isEnabled() is False
- assert itemEdit.editExport.isEnabled() is False
-
- # Change Settings
- itemEdit.editName.setText("Chapter One")
- itemEdit.editStatus.setCurrentIndex(1)
-
- # Check New Settings
- itemEdit._doSave()
- assert itemEdit.theItem.itemName == "Chapter One"
- assert itemEdit.theItem.itemStatus == statusKeys[1]
- assert itemEdit.theItem.itemLayout == nwItemLayout.NO_LAYOUT
- assert itemEdit.theItem.isExported is False
-
- itemEdit.close()
- del itemEdit
- # qtbot.stopForInteraction()
-
-# END Test testDlgItemEditor_Folder
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index cf38c7ea..039901e8 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -26,13 +26,13 @@ from shutil import copyfile
from tools import cmpFiles, buildTestProject, XML_IGNORE, writeFile
from PyQt5.QtCore import Qt
-from PyQt5.QtWidgets import QMessageBox, QDialog, QInputDialog
+from PyQt5.QtWidgets import QMessageBox, QInputDialog
from novelwriter.gui import GuiDocEditor, GuiNovelTree, GuiOutlineView
from novelwriter.enum import nwItemType, nwWidget
from novelwriter.tools import GuiProjectWizard
from novelwriter.gui.projtree import GuiProjectTree
-from novelwriter.dialogs.itemeditor import GuiItemEditor
+from novelwriter.dialogs import GuiEditLabel
keyDelay = 2
typeDelay = 1
@@ -169,11 +169,10 @@ def testGuiMain_Editing(qtbot, monkeypatch, nwGUI, fncProj, refDir, outDir, mock
# Block message box
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
- monkeypatch.setattr(GuiItemEditor, "exec_", lambda *a: None)
- monkeypatch.setattr(GuiItemEditor, "result", lambda *a: QDialog.Accepted)
monkeypatch.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
monkeypatch.setattr(GuiDocEditor, "hasFocus", lambda *a: True)
monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
+ monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
# Create new, save, close project
buildTestProject(nwGUI, fncProj)
diff --git a/tests/test_gui/test_gui_projtree.py b/tests/test_gui/test_gui_projtree.py
index b3206aa5..d7ed41d0 100644
--- a/tests/test_gui/test_gui_projtree.py
+++ b/tests/test_gui/test_gui_projtree.py
@@ -24,10 +24,11 @@ import os
from tools import buildTestProject
-from PyQt5.QtWidgets import QMessageBox, QInputDialog, QMenu
+from PyQt5.QtWidgets import QMessageBox, QMenu
-from novelwriter.gui.projtree import GuiProjectTree
from novelwriter.enum import nwItemLayout, nwItemType, nwItemClass
+from novelwriter.dialogs import GuiEditLabel
+from novelwriter.gui.projtree import GuiProjectTree
@pytest.mark.gui
@@ -39,7 +40,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
- monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
+ monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
nwTree = nwGUI.projView
@@ -125,7 +126,7 @@ def testGuiProjTree_NewItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockRnd)
# Cancel during creation
with monkeypatch.context() as mp:
- mp.setattr(QInputDialog, "getText", lambda *a, **k: ("", False))
+ mp.setattr(GuiEditLabel, "getLabel", lambda *a, **k: ("", False))
nwTree.setSelectedHandle("0000000000013")
assert nwTree.projTree.newTreeItem(nwItemType.FILE) is False
@@ -162,7 +163,7 @@ def testGuiProjTree_MoveItems(qtbot, monkeypatch, nwGUI, fncDir, mockRnd):
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
- monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
+ monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
nwTree = nwGUI.projView
@@ -277,7 +278,7 @@ def testGuiProjTree_DeleteItems(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
- monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
+ monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
nwTree = nwGUI.projView
@@ -466,7 +467,7 @@ def testGuiProjTree_ContextMenu(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
monkeypatch.setattr(QMessageBox, "critical", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
- monkeypatch.setattr(QInputDialog, "getText", lambda *a, text: (text, True))
+ monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
monkeypatch.setattr(QMenu, "exec_", lambda *a: None)
# Create a project
From 946656f8c5bd65fda8a1a0fb63e1303949557965 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 11 Jun 2022 18:26:41 +0200
Subject: [PATCH 20/35] Add test for edit label dialog
---
tests/test_dialogs/test_dlg_dialogs.py | 27 +++++++++++++++++++++-----
1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/tests/test_dialogs/test_dlg_dialogs.py b/tests/test_dialogs/test_dlg_dialogs.py
index 7ae56d94..3423beb5 100644
--- a/tests/test_dialogs/test_dlg_dialogs.py
+++ b/tests/test_dialogs/test_dlg_dialogs.py
@@ -24,11 +24,7 @@ import pytest
from PyQt5.QtCore import QItemSelectionModel
from PyQt5.QtWidgets import QAction, QListWidgetItem, QDialog, QMessageBox
-from novelwriter.dialogs import GuiQuoteSelect, GuiUpdates
-
-keyDelay = 2
-typeDelay = 1
-stepDelay = 20
+from novelwriter.dialogs import GuiQuoteSelect, GuiUpdates, GuiEditLabel
@pytest.mark.gui
@@ -101,3 +97,24 @@ def testDlgOther_Updates(qtbot, monkeypatch, nwGUI):
nwUpdate._doClose()
# END Test testDlgOther_Updates
+
+
+@pytest.mark.gui
+def testDlgOther_EditLabel(qtbot, monkeypatch):
+ """Test the label editor dialog.
+ """
+ monkeypatch.setattr(GuiEditLabel, "exec_", lambda *a: None)
+
+ with monkeypatch.context() as mp:
+ mp.setattr(GuiEditLabel, "result", lambda *a: QDialog.Accepted)
+ newLabel, dlgOk = GuiEditLabel.getLabel(None, text="Hello World")
+ assert dlgOk is True
+ assert newLabel == "Hello World"
+
+ with monkeypatch.context() as mp:
+ mp.setattr(GuiEditLabel, "result", lambda *a: QDialog.Rejected)
+ newLabel, dlgOk = GuiEditLabel.getLabel(None, text="Hello World")
+ assert dlgOk is False
+ assert newLabel == "Hello World"
+
+# END Test testDlgOther_EditLabel
From 8d427f40c659bb71e591cb91cd8a0959aee98094 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 11 Jun 2022 18:40:21 +0200
Subject: [PATCH 21/35] Add a shortcut to open project tree context menu
---
docs/source/usage_shortcuts.rst | 3 +--
novelwriter/gui/projtree.py | 17 ++++++++++++++---
tests/test_gui/test_gui_projtree.py | 6 ++++++
3 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/docs/source/usage_shortcuts.rst b/docs/source/usage_shortcuts.rst
index fa761a3e..e9e7bb36 100644
--- a/docs/source/usage_shortcuts.rst
+++ b/docs/source/usage_shortcuts.rst
@@ -25,7 +25,7 @@ The main shorcuts are as follows:
":kbd:`Alt`:kbd:`4`", "Switch focus to outline view. On Windows, use :kbd:`Ctrl`:kbd:`Alt`:kbd:`4`."
":kbd:`Alt`:kbd:`Left`", "Move backward in the view history of the document viewer."
":kbd:`Alt`:kbd:`Right`", "Move forward in the view history of the document viewer."
- ":kbd:`Ctrl`:kbd:`.`", "Open menu to correct word under cursor."
+ ":kbd:`Ctrl`:kbd:`.`", "Open the context menu in the project tree or the document editor."
":kbd:`Ctrl`:kbd:`,`", "Open the :guilabel:`Preferences` dialog."
":kbd:`Ctrl`:kbd:`/`", "Toggle block format as comment."
":kbd:`Ctrl`:kbd:`0`", "Remove block formatting for block under cursor."
@@ -42,7 +42,6 @@ The main shorcuts are as follows:
":kbd:`Ctrl`:kbd:`B`", "Format selected text, or word under cursor, with strong emphasis (bold)."
":kbd:`Ctrl`:kbd:`C`", "Copy selected text to clipboard."
":kbd:`Ctrl`:kbd:`D`", "Strikethrough selected text, or word under cursor."
- ":kbd:`Ctrl`:kbd:`E`", "If in the project tree, edit a document or folder settings."
":kbd:`Ctrl`:kbd:`F`", "Open the search bar and search for the selected word, if any is selected."
":kbd:`Ctrl`:kbd:`G`", "Find next occurrence of search word in current document."
":kbd:`Ctrl`:kbd:`H`", "Open the search and replace bar and search for the selected word, if any is selected. (On Mac, this is :kbd:`Cmd`:kbd:`=`.)"
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index aa1ff9ce..b9bfda0d 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -97,6 +97,11 @@ class GuiProjectView(QWidget):
self.keyUndoMv.setContext(Qt.WidgetShortcut)
self.keyUndoMv.activated.connect(lambda: self.projTree.undoLastMove())
+ self.keyContext = QShortcut(self.projTree)
+ self.keyContext.setKey("Ctrl+.")
+ self.keyContext.setContext(Qt.WidgetShortcut)
+ self.keyContext.activated.connect(lambda: self.projTree.openContextOnSelected())
+
# Function Mappings
self.revealNewTreeItem = self.projTree.revealNewTreeItem
self.renameTreeItem = self.projTree.renameTreeItem
@@ -913,9 +918,6 @@ class GuiProjectTree(QTreeWidget):
def setSelectedHandle(self, tHandle, doScroll=False):
"""Set a specific handle as the selected item.
"""
- if tHandle not in self._treeMap:
- return False
-
tItem = self._getTreeItem(tHandle)
if tItem is None:
return False
@@ -929,6 +931,15 @@ class GuiProjectTree(QTreeWidget):
return True
+ def openContextOnSelected(self):
+ """Open the context menu on the current selected item.
+ """
+ selItem = self.selectedItems()
+ if selItem:
+ pos = self.visualItemRect(selItem[0]).center()
+ return self._openContextMenu(pos)
+ return False
+
def changedSince(self, checkTime):
"""Check if the tree has changed since a given time.
"""
diff --git a/tests/test_gui/test_gui_projtree.py b/tests/test_gui/test_gui_projtree.py
index d7ed41d0..feef859d 100644
--- a/tests/test_gui/test_gui_projtree.py
+++ b/tests/test_gui/test_gui_projtree.py
@@ -511,6 +511,12 @@ def testGuiProjTree_ContextMenu(qtbot, caplog, monkeypatch, nwGUI, fncDir, mockR
assert projTree._openContextMenu(itemPos(hCharRoot)) is True
assert projTree._openContextMenu(itemPos(hCharNote)) is True
+ # Check the keyboard shortcut handler as well
+ projTree.setSelectedHandle(hNovelRoot)
+ assert projTree.openContextOnSelected() is True
+ projTree.clearSelection()
+ assert projTree.openContextOnSelected() is False
+
# Direct Edit Functions
# =====================
# Trigger the dedicated functions the menu entries connect to
From 2cc8be577612ed35314d7d0fe0eb05592aa4ca4a Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 11 Jun 2022 18:48:22 +0200
Subject: [PATCH 22/35] Rename the main GUI function for editing an item
---
novelwriter/gui/doceditor.py | 2 +-
novelwriter/gui/mainmenu.py | 2 +-
novelwriter/guimain.py | 2 +-
tests/test_gui/test_gui_guimain.py | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py
index ab2c7f2f..25552037 100644
--- a/novelwriter/gui/doceditor.py
+++ b/novelwriter/gui/doceditor.py
@@ -2746,7 +2746,7 @@ class GuiDocEditHeader(QWidget):
def _editDocument(self):
"""Open the edit item dialog from the main GUI.
"""
- self.mainGui.editItem(self._docHandle)
+ self.mainGui.editItemLabel(self._docHandle)
return
def _searchDocument(self):
diff --git a/novelwriter/gui/mainmenu.py b/novelwriter/gui/mainmenu.py
index 85920749..59af7691 100644
--- a/novelwriter/gui/mainmenu.py
+++ b/novelwriter/gui/mainmenu.py
@@ -165,7 +165,7 @@ class GuiMainMenu(QMenuBar):
# Project > Edit
self.aEditItem = QAction(self.tr("Rename Item"), self)
self.aEditItem.setShortcuts(["F2"])
- self.aEditItem.triggered.connect(lambda: self.mainGui.editItem(None))
+ self.aEditItem.triggered.connect(lambda: self.mainGui.editItemLabel(None))
self.projMenu.addAction(self.aEditItem)
# Project > Delete
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index de80c59c..e15a82b0 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -804,7 +804,7 @@ class GuiMain(QMainWindow):
return True
- def editItem(self, tHandle=None):
+ def editItemLabel(self, tHandle=None):
"""Open the edit item dialog.
"""
if not self.hasProject:
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index 039901e8..5fa6951b 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -57,7 +57,7 @@ def testGuiMain_ProjectBlocker(monkeypatch, nwGUI):
assert nwGUI.mergeDocuments() is False
assert nwGUI.splitDocument() is False
assert nwGUI.openSelectedItem() is False
- assert nwGUI.editItem() is False
+ assert nwGUI.editItemLabel() is False
assert nwGUI.requestNovelTreeRefresh() is False
assert nwGUI.rebuildIndex() is False
assert nwGUI.showProjectSettingsDialog() is False
From c58868ed3952ac06f3ff3870b0e5591ba5ba03b8 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sat, 11 Jun 2022 23:54:20 +0200
Subject: [PATCH 23/35] Simplify the conversion of very old project data
---
novelwriter/core/project.py | 98 ++++++++-----------------
tests/test_core/test_core_project.py | 104 +++++++++------------------
2 files changed, 61 insertions(+), 141 deletions(-)
diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py
index dfb577b1..c2683cc7 100644
--- a/novelwriter/core/project.py
+++ b/novelwriter/core/project.py
@@ -438,7 +438,7 @@ class NWProject():
legacyList = [] # Cleanup is done later
for projItem in os.listdir(self.projPath):
logger.verbose("Project contains: %s", projItem)
- if projItem.startswith("data_"):
+ if projItem.startswith("data_") and len(projItem) == 6:
legacyList.append(projItem)
# Project Lock
@@ -500,7 +500,7 @@ class NWProject():
# Check File Type
# ===============
- if not nwxRoot == "novelWriterXML":
+ if nwxRoot != "novelWriterXML":
self.mainGui.makeAlert(self.tr(
"Project file does not appear to be a novelWriterXML file."
), nwAlert.ERROR)
@@ -642,11 +642,14 @@ class NWProject():
# Sort out old file locations
if legacyList:
- errList = []
- for projItem in legacyList:
- errList = self._legacyDataFolder(projItem, errList)
- if errList:
- self.mainGui.makeAlert(errList, nwAlert.ERROR)
+ try:
+ for projItem in legacyList:
+ self._legacyDataFolder(projItem)
+ except Exception:
+ self.mainGui.makeAlert(self.tr(
+ "There was an error while converting project version 1.0. "
+ "Some data may not have been preserved."
+ ), nwAlert.ERROR)
# Clean up no longer used files
self._deprecatedFiles()
@@ -1558,82 +1561,37 @@ class NWProject():
# Legacy Data Structure Handlers
##
- def _legacyDataFolder(self, theFolder, errList):
+ def _legacyDataFolder(self, dataDir):
"""Clean up legacy data folders.
"""
- theData = os.path.join(self.projPath, theFolder)
- if not os.path.isdir(theData):
- errList.append(self.tr("Not a folder: {0}").format(theData))
- return errList
+ dataPath = os.path.join(self.projPath, dataDir)
+ if not os.path.isdir(dataPath):
+ return False
- logger.info("Old data folder %s found", theFolder)
+ logger.info("Old data folder found: %s", dataDir)
# Move Documents to Content
- for dataItem in os.listdir(theData):
- theFile = os.path.join(theData, dataItem)
- if not os.path.isfile(theFile):
- theErr = self._moveUnknownItem(theData, dataItem)
- if theErr:
- errList.append(theErr)
+ for dataItem in os.listdir(dataPath):
+ dataFile = os.path.join(dataPath, dataItem)
+ if not os.path.isfile(dataFile):
continue
if len(dataItem) == 21 and dataItem.endswith("_main.nwd"):
- tHandle = theFolder[-1]+dataItem[:12]
- newPath = os.path.join(self.projContent, tHandle+".nwd")
- try:
- os.rename(theFile, newPath)
- logger.info("Moved file: %s", theFile)
- logger.info("New location: %s", newPath)
- except Exception:
- errList.append(self.tr("Could not move: {0}").format(theFile))
- logger.error("Could not move: %s", theFile)
- logException()
+ tHandle = dataDir[-1] + dataItem[:12]
+ newPath = os.path.join(self.projContent, f"{tHandle}.nwd")
+ os.rename(dataFile, newPath)
+ logger.info("Moved file: %s", dataFile)
elif len(dataItem) == 21 and dataItem.endswith("_main.bak"):
- try:
- os.unlink(theFile)
- logger.info("Deleted file: %s", theFile)
- except Exception:
- errList.append(self.tr("Could not delete: {0}").format(theFile))
- logger.error("Could not delete: %s", theFile)
- logException()
-
- else:
- theErr = self._moveUnknownItem(theData, dataItem)
- if theErr:
- errList.append(theErr)
+ os.unlink(dataFile)
+ logger.info("Deleted file: %s", dataFile)
# Remove Data Folder
- try:
- os.rmdir(theData)
- logger.info("Deleted folder: %s", theFolder)
- except Exception:
- errList.append(self.tr("Could not delete: {0}").format(theFolder))
- logger.error("Could not delete: %s", theFolder)
- logException()
+ if not os.listdir(dataPath):
+ os.rmdir(dataPath)
+ logger.info("Deleted folder: %s", dataDir)
- return errList
-
- def _moveUnknownItem(self, theDir, theItem):
- """Move an item that doesn't belong in the project folder to
- a junk folder.
- """
- theJunk = os.path.join(self.projPath, "junk")
- if not self._checkFolder(theJunk):
- return self.tr("Could not make folder: {0}").format(theJunk)
-
- theSrc = os.path.join(theDir, theItem)
- theDst = os.path.join(theJunk, theItem)
-
- try:
- os.rename(theSrc, theDst)
- logger.info("Moved to junk: %s", theSrc)
- except Exception:
- logger.error("Could not move item %s to junk", theSrc)
- logException()
- return self.tr("Could not move item {0} to {1}.").format(theSrc, theJunk)
-
- return ""
+ return True
def _deprecatedFiles(self):
"""Delete files that are no longer used by novelWriter.
diff --git a/tests/test_core/test_core_project.py b/tests/test_core/test_core_project.py
index 9454b0fc..bdc27771 100644
--- a/tests/test_core/test_core_project.py
+++ b/tests/test_core/test_core_project.py
@@ -463,12 +463,15 @@ def testCoreProject_Open(monkeypatch, nwMinimal, mockGUI):
os.rename(oName, rName)
# Add some legacy stuff that cannot be removed
- writeFile(os.path.join(nwMinimal, "junk"), "stuff")
- os.mkdir(os.path.join(nwMinimal, "data_0"))
- writeFile(os.path.join(nwMinimal, "data_0", "junk"), "stuff")
- mockGUI.clear()
- assert theProject.openProject(nwMinimal) is True
- assert "data_0" in mockGUI.lastAlert
+ with monkeypatch.context() as mp:
+ mp.setattr(theProject, "_legacyDataFolder", causeOSError)
+ os.mkdir(os.path.join(nwMinimal, "data_0"))
+ writeFile(os.path.join(nwMinimal, "data_0", "123456789abc_main.nwd"), "stuff")
+ writeFile(os.path.join(nwMinimal, "data_0", "123456789abc_main.bak"), "stuff")
+ mockGUI.clear()
+ assert theProject.openProject(nwMinimal) is True
+ assert "version 1.0" in mockGUI.lastAlert
+
assert theProject.closeProject()
# END Test testCoreProject_Open
@@ -1141,14 +1144,6 @@ def testCoreProject_OldFormat(mockGUI, nwOldProj):
os.path.join(nwOldProj, "meta", "sessionLogOptions.json"),
]
- # Add some files that shouldn't be there
- deleteFiles.append(os.path.join(nwOldProj, "data_f", "whatnow.nwd"))
- deleteFiles.append(os.path.join(nwOldProj, "data_f", "whatnow.txt"))
-
- # Add some folders that shouldn't be there
- os.mkdir(os.path.join(nwOldProj, "stuff"))
- os.mkdir(os.path.join(nwOldProj, "data_1", "stuff"))
-
# Create mock files
os.mkdir(os.path.join(nwOldProj, "cache"))
for aFile in deleteFiles:
@@ -1162,7 +1157,6 @@ def testCoreProject_OldFormat(mockGUI, nwOldProj):
for aFile in deleteFiles:
assert not os.path.isfile(aFile)
- assert not os.path.isdir(os.path.join(nwOldProj, "data_1", "stuff"))
assert not os.path.isdir(os.path.join(nwOldProj, "data_1"))
assert not os.path.isdir(os.path.join(nwOldProj, "data_7"))
assert not os.path.isdir(os.path.join(nwOldProj, "data_8"))
@@ -1170,12 +1164,6 @@ def testCoreProject_OldFormat(mockGUI, nwOldProj):
assert not os.path.isdir(os.path.join(nwOldProj, "data_a"))
assert not os.path.isdir(os.path.join(nwOldProj, "data_f"))
- # Check stuff that has been moved
- assert os.path.isdir(os.path.join(nwOldProj, "junk"))
- assert os.path.isdir(os.path.join(nwOldProj, "junk", "stuff"))
- assert os.path.isfile(os.path.join(nwOldProj, "junk", "whatnow.nwd"))
- assert os.path.isfile(os.path.join(nwOldProj, "junk", "whatnow.txt"))
-
# Check that files we want to keep are in the right place
assert os.path.isdir(os.path.join(nwOldProj, "cache"))
assert os.path.isdir(os.path.join(nwOldProj, "content"))
@@ -1217,7 +1205,7 @@ def testCoreProject_LegacyData(monkeypatch, mockGUI, fncDir):
with monkeypatch.context() as mp:
mp.setattr("os.unlink", causeOSError)
- assert not theProject._deprecatedFiles()
+ assert theProject._deprecatedFiles() is False
assert theProject._deprecatedFiles()
assert not os.path.isfile(tstFile)
@@ -1226,63 +1214,36 @@ def testCoreProject_LegacyData(monkeypatch, mockGUI, fncDir):
tstFile = os.path.join(fncDir, "data_0")
writeFile(tstFile, "stuff")
assert os.path.isfile(tstFile)
-
- errList = []
- errList = theProject._legacyDataFolder(tstFile, errList)
- assert len(errList) > 0
-
- # Move folder in data folder, shouldn't be there
- tstData = os.path.join(fncDir, "data_1")
- errItem = os.path.join(fncDir, "data_1", "stuff")
- os.mkdir(tstData)
- os.mkdir(errItem)
- assert os.path.isdir(tstData)
- assert os.path.isdir(errItem)
-
- # This causes a failure to create the 'junk' folder
- with monkeypatch.context() as mp:
- mp.setattr("os.mkdir", causeOSError)
- errList = []
- errList = theProject._legacyDataFolder(tstData, errList)
- assert len(errList) > 0
-
- # This causes a failure to move 'stuff' to 'junk'
- with monkeypatch.context() as mp:
- mp.setattr("os.rename", causeOSError)
- errList = []
- errList = theProject._legacyDataFolder(tstData, errList)
- assert len(errList) > 0
-
- # This should be successful
- errList = []
- errList = theProject._legacyDataFolder(tstData, errList)
- assert len(errList) == 0
- assert os.path.isdir(os.path.join(fncDir, "junk", "stuff"))
+ assert theProject._legacyDataFolder(tstFile) is False
# Check renaming/deleting of old document files
- tstData = os.path.join(fncDir, "data_2")
- tstDoc1m = os.path.join(tstData, "000000000001_main.nwd")
- tstDoc1b = os.path.join(tstData, "000000000001_main.bak")
- tstDoc2m = os.path.join(tstData, "000000000002_main.nwd")
- tstDoc2b = os.path.join(tstData, "000000000002_main.bak")
- tstDoc3m = os.path.join(tstData, "tooshort003_main.nwd")
- tstDoc3b = os.path.join(tstData, "tooshort003_main.bak")
+ tstData2 = os.path.join(fncDir, "data_2")
+ tstData3 = os.path.join(fncDir, "data_3")
+ tstDoc1m = os.path.join(tstData2, "000000000001_main.nwd")
+ tstDoc1b = os.path.join(tstData2, "000000000001_main.bak")
+ tstDoc2m = os.path.join(tstData2, "000000000002_main.nwd")
+ tstDoc2b = os.path.join(tstData2, "000000000002_main.bak")
+ tstDoc3m = os.path.join(tstData3, "tooshort003_main.nwd")
+ tstDoc3b = os.path.join(tstData3, "tooshort003_main.bak")
+ tstDir4a = os.path.join(tstData3, "stuff")
- os.mkdir(tstData)
+ os.mkdir(tstData2)
+ os.mkdir(tstData3)
writeFile(tstDoc1m, "stuff")
writeFile(tstDoc1b, "stuff")
writeFile(tstDoc2m, "stuff")
writeFile(tstDoc2b, "stuff")
writeFile(tstDoc3m, "stuff")
writeFile(tstDoc3b, "stuff")
+ os.mkdir(tstDir4a)
# Make the above fail
with monkeypatch.context() as mp:
mp.setattr("os.rename", causeOSError)
mp.setattr("os.unlink", causeOSError)
- errList = []
- errList = theProject._legacyDataFolder(tstData, errList)
- assert len(errList) > 0
+ with pytest.raises(OSError):
+ theProject._legacyDataFolder(tstData2)
+ theProject._legacyDataFolder(tstData3)
assert os.path.isfile(tstDoc1m)
assert os.path.isfile(tstDoc1b)
assert os.path.isfile(tstDoc2m)
@@ -1291,15 +1252,16 @@ def testCoreProject_LegacyData(monkeypatch, mockGUI, fncDir):
assert os.path.isfile(tstDoc3b)
# And succeed ...
- errList = []
- errList = theProject._legacyDataFolder(tstData, errList)
- assert len(errList) == 0
+ assert theProject._legacyDataFolder(tstData2) is True
+ assert theProject._legacyDataFolder(tstData3) is True
- assert not os.path.isdir(tstData)
+ assert not os.path.isdir(tstData2)
+ assert os.path.isdir(tstData3)
assert os.path.isfile(os.path.join(fncDir, "content", "2000000000001.nwd"))
assert os.path.isfile(os.path.join(fncDir, "content", "2000000000002.nwd"))
- assert os.path.isfile(os.path.join(fncDir, "junk", "tooshort003_main.nwd"))
- assert os.path.isfile(os.path.join(fncDir, "junk", "tooshort003_main.bak"))
+ assert os.path.isfile(os.path.join(fncDir, tstData3, "tooshort003_main.nwd"))
+ assert os.path.isfile(os.path.join(fncDir, tstData3, "tooshort003_main.bak"))
+ assert os.path.isdir(tstDir4a)
# END Test testCoreProject_LegacyData
From b3eb276437dcee8bbac9ec868d42a10283e64ad3 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sun, 12 Jun 2022 15:45:39 +0200
Subject: [PATCH 24/35] Wrap the novel tree in an outer widget
---
novelwriter/gui/__init__.py | 4 +-
novelwriter/gui/noveltree.py | 93 +++++++++++++++++++++++-----
novelwriter/guimain.py | 11 ++--
tests/test_gui/test_gui_guimain.py | 8 +--
tests/test_gui/test_gui_noveltree.py | 77 +++++++++++------------
5 files changed, 126 insertions(+), 67 deletions(-)
diff --git a/novelwriter/gui/__init__.py b/novelwriter/gui/__init__.py
index 1892e83d..17699942 100644
--- a/novelwriter/gui/__init__.py
+++ b/novelwriter/gui/__init__.py
@@ -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",
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index f634ce23..85773478 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -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.
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index e15a82b0..6fa52eb6 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -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())
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index 5fa6951b..9a56af3d 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -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
diff --git a/tests/test_gui/test_gui_noveltree.py b/tests/test_gui/test_gui_noveltree.py
index 2bf2df8a..644839d3 100644
--- a/tests/test_gui/test_gui_noveltree.py
+++ b/tests/test_gui/test_gui_noveltree.py
@@ -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
From 52683d5a21202a6e85a15b029262027afa747889 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sun, 12 Jun 2022 17:47:32 +0200
Subject: [PATCH 25/35] Add novel tree toolbar and connect actions
---
novelwriter/core/project.py | 16 +++
novelwriter/gui/noveltree.py | 224 +++++++++++++++++++++++++++--------
novelwriter/gui/projtree.py | 26 ++--
novelwriter/guimain.py | 18 ++-
sample/nwProject.nwx | 16 +--
5 files changed, 224 insertions(+), 76 deletions(-)
diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py
index c2683cc7..43f3297e 100644
--- a/novelwriter/core/project.py
+++ b/novelwriter/core/project.py
@@ -102,6 +102,8 @@ class NWProject():
self.importItems = None # Note file importance values
self.lastEdited = None # The handle of the last file to be edited
self.lastViewed = None # The handle of the last file to be viewed
+ self.lastNovel = None # The handle of the last novel root viewed
+ self.lastOutline = None # The handle of the last outline root viewed
self.lastWCount = 0 # The project word count from last session
self.lastNovelWC = 0 # The novel files word count from last session
self.lastNotesWC = 0 # The note files word count from last session
@@ -612,6 +614,10 @@ class NWProject():
self.lastEdited = checkString(xItem.text, None, True)
elif xItem.tag == "lastViewed":
self.lastViewed = checkString(xItem.text, None, True)
+ elif xItem.tag == "lastNovel":
+ self.lastNovel = checkString(xItem.text, None, True)
+ elif xItem.tag == "lastOutline":
+ self.lastOutline = checkString(xItem.text, None, True)
elif xItem.tag == "lastWordCount":
self.lastWCount = checkInt(xItem.text, 0, False)
elif xItem.tag == "novelWordCount":
@@ -732,6 +738,8 @@ class NWProject():
self._packProjectValue(xSettings, "autoOutline", self.autoOutline)
self._packProjectValue(xSettings, "lastEdited", self.lastEdited)
self._packProjectValue(xSettings, "lastViewed", self.lastViewed)
+ self._packProjectValue(xSettings, "lastNovel", self.lastNovel)
+ self._packProjectValue(xSettings, "lastOutline", self.lastOutline)
self._packProjectValue(xSettings, "lastWordCount", self.currWCount)
self._packProjectValue(xSettings, "novelWordCount", self.currNovelWC)
self._packProjectValue(xSettings, "notesWordCount", self.currNotesWC)
@@ -1123,6 +1131,14 @@ class NWProject():
self.setProjectChanged(True)
return True
+ def setLastNovelViewed(self, tHandle):
+ """Set last viewed novel root in the novel tree.
+ """
+ if self.lastNovel != tHandle:
+ self.lastNovel = tHandle
+ self.setProjectChanged(True)
+ return True
+
def setStatusColours(self, newCols, delCols):
"""Update the list of novel file status flags.
"""
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index 85773478..8cec9fdb 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -27,25 +27,34 @@ import logging
import novelwriter
from time import time
+from enum import Enum
-from PyQt5.QtCore import Qt, QSize
+from PyQt5.QtCore import Qt, QSize, pyqtSlot, pyqtSignal
+from PyQt5.QtGui import QPalette
from PyQt5.QtWidgets import (
- QAbstractItemView, QFrame, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
+ QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView, QLabel,
+ QMenu, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
QWidget
)
+from novelwriter.enum import nwDocMode, nwItemClass
from novelwriter.common import checkInt
-from novelwriter.constants import nwKeyWords
+from novelwriter.constants import nwKeyWords, nwLabels
logger = logging.getLogger(__name__)
class GuiNovelView(QWidget):
+ # Signals for user interaction with the novel tree
+ selectedItemChanged = pyqtSignal(str)
+ openDocumentRequest = pyqtSignal(str, Enum, int, str)
+
def __init__(self, mainGui):
QWidget.__init__(self, mainGui)
- self.mainGui = mainGui
+ self.mainGui = mainGui
+ self.theProject = mainGui.theProject
# Build GUI
self.novelTree = GuiNovelTree(self)
@@ -60,6 +69,11 @@ class GuiNovelView(QWidget):
self.setLayout(self.outerBox)
+ # Connect Signals
+ self.novelBar.rootFolderSelectionChanged.connect(
+ lambda tHandle: self.novelTree.refreshTree(rootHandle=tHandle, overRide=True)
+ )
+
# Function Mappings
self.refreshTree = self.novelTree.refreshTree
self.updateWordCounts = self.novelTree.updateWordCounts
@@ -79,6 +93,21 @@ class GuiNovelView(QWidget):
self.novelTree.clearTree()
return
+ def openProjectTasks(self):
+ """Run tasks related to opening a project.
+ """
+ lastNovel = self.theProject.lastNovel
+ if lastNovel is None:
+ lastNovel = self.theProject.tree.findRoot(nwItemClass.NOVEL)
+
+ logger.debug("Setting novel tree to root item '%s'", lastNovel)
+
+ self.clearProject()
+ self.novelBar.rebuildNovelRootMenu(selHandle=lastNovel)
+ self.novelTree.refreshTree(rootHandle=lastNovel, overRide=True)
+
+ return
+
def setFocus(self):
"""Forward the set focus call to the tree widget.
"""
@@ -90,16 +119,114 @@ class GuiNovelView(QWidget):
"""
return self.novelTree.hasFocus()
+ ##
+ # Public Slots
+ ##
+
+ @pyqtSlot(str)
+ def updateRootItem(self, tHandle):
+ """Should be called whenever a root folders changes.
+ """
+ self.novelBar.rebuildNovelRootMenu()
+ return
+
# END Class GuiNovelView
class GuiNovelToolBar(QWidget):
+ rootFolderSelectionChanged = pyqtSignal(str)
+
def __init__(self, novelView):
QTreeWidget.__init__(self, novelView)
- self.mainConf = novelwriter.CONFIG
- self.novelView = novelView
+ logger.debug("Initialising GuiNovelToolBar ...")
+
+ self.mainConf = novelwriter.CONFIG
+ self.novelView = novelView
+ self.theProject = novelView.mainGui.theProject
+ self.mainTheme = novelView.mainGui.mainTheme
+
+ iPx = self.mainTheme.baseIconSize
+ mPx = self.mainConf.pxInt(4)
+
+ self.setContentsMargins(0, 0, 0, 0)
+ self.setAutoFillBackground(True)
+
+ qPalette = self.palette()
+ qPalette.setBrush(QPalette.Window, qPalette.base())
+ self.setPalette(qPalette)
+
+ fadeCol = qPalette.text().color()
+ buttonStyle = (
+ "QToolButton {{padding: {0}px; border: none; background: transparent;}} "
+ "QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}"
+ ).format(mPx, fadeCol.red(), fadeCol.green(), fadeCol.blue())
+
+ # Widget Label
+ self.viewLabel = QLabel("%s" % self.tr("Novel Outline"))
+ self.viewLabel.setContentsMargins(0, 0, 0, 0)
+ self.viewLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+
+ # Novel Root Menu
+ self.mRoot = QMenu()
+
+ self.tbRoot = QToolButton(self)
+ self.tbRoot.setToolTip(self.tr("Novel Root"))
+ self.tbRoot.setIcon(self.mainTheme.getIcon(nwLabels.CLASS_ICON[nwItemClass.NOVEL]))
+ self.tbRoot.setIconSize(QSize(iPx, iPx))
+ self.tbRoot.setStyleSheet(buttonStyle)
+ self.tbRoot.setMenu(self.mRoot)
+ self.tbRoot.setPopupMode(QToolButton.InstantPopup)
+
+ # More Options Menu
+ self.mMore = QMenu()
+
+ self.tbMore = QToolButton(self)
+ self.tbMore.setToolTip(self.tr("More Options"))
+ self.tbMore.setIcon(self.mainTheme.getIcon("menu"))
+ self.tbMore.setIconSize(QSize(iPx, iPx))
+ self.tbMore.setStyleSheet(buttonStyle)
+ self.tbMore.setMenu(self.mMore)
+ self.tbMore.setPopupMode(QToolButton.InstantPopup)
+
+ # Assemble
+ self.outerBox = QHBoxLayout()
+ self.outerBox.addWidget(self.viewLabel)
+ self.outerBox.addWidget(self.tbRoot)
+ self.outerBox.addWidget(self.tbMore)
+ self.outerBox.setContentsMargins(mPx, mPx, 0, mPx)
+ self.outerBox.setSpacing(0)
+
+ self.setLayout(self.outerBox)
+
+ logger.debug("GuiNovelToolBar initialisation complete")
+
+ return
+
+ ##
+ # Methods
+ ##
+
+ def rebuildNovelRootMenu(self, selHandle=None):
+ """Build the novel root menu.
+ """
+ self.mRoot.clear()
+
+ agRoot = QActionGroup(self.mRoot)
+ for n, (tHandle, nwItem) in enumerate(self.theProject.tree.iterRoots(nwItemClass.NOVEL)):
+ aRoot = self.mRoot.addAction(nwItem.itemName)
+ aRoot.setData(tHandle)
+ aRoot.setCheckable(True)
+ aRoot.triggered.connect(
+ lambda n, tHandle=tHandle: self.rootFolderSelectionChanged.emit(tHandle)
+ )
+ agRoot.addAction(aRoot)
+
+ if n == 0:
+ aRoot.setChecked(True)
+ if selHandle == tHandle:
+ aRoot.setChecked(True)
return
@@ -128,41 +255,32 @@ class GuiNovelTree(QTreeWidget):
self._lastBuild = 0
# Build GUI
+ # =========
+
iPx = self.mainTheme.baseIconSize
- self.setFrameStyle(QFrame.NoFrame)
+ cMg = self.mainConf.pxInt(6)
+
self.setIconSize(QSize(iPx, iPx))
+ self.setFrameStyle(QFrame.NoFrame)
+ self.setHeaderHidden(True)
self.setIndentation(iPx)
self.setColumnCount(3)
- self.setHeaderLabels([
- self.tr("Novel Outline"),
- self.tr("Words"),
- self.tr("POV")
- ])
- self.itemDoubleClicked.connect(self._treeDoubleClick)
- self.itemSelectionChanged.connect(self._itemSelected)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSelectionMode(QAbstractItemView.SingleSelection)
self.setExpandsOnDoubleClick(False)
self.setDragEnabled(False)
- treeHeadItem = self.headerItem()
- treeHeadItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
- treeHeadItem.setToolTip(self.C_TITLE, self.tr("Section title"))
- treeHeadItem.setToolTip(self.C_WORDS, self.tr("Word count"))
- treeHeadItem.setToolTip(self.C_POV, self.tr("Point-of-view character"))
-
+ # Lock the column sizes
treeHeader = self.header()
- treeHeader.setStretchLastSection(True)
- treeHeader.setMinimumSectionSize(iPx + 6)
+ treeHeader.setStretchLastSection(False)
+ treeHeader.setMinimumSectionSize(iPx + cMg)
+ treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.Stretch)
+ treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeToContents)
+ treeHeader.setSectionResizeMode(self.C_POV, QHeaderView.ResizeToContents)
- # Get user's column width preferences for NAME and COUNT
- treeColWidth = self.mainConf.getNovelColWidths()
- if len(treeColWidth) <= 3:
- for colN, colW in enumerate(treeColWidth):
- self.setColumnWidth(colN, colW)
-
- # The last column should just auto-scale
- self.resizeColumnToContents(self.C_POV)
+ # Connect signals
+ self.itemDoubleClicked.connect(self._treeDoubleClick)
+ self.itemSelectionChanged.connect(self._treeSelectionChange)
# Set custom settings
self.initSettings()
@@ -199,12 +317,15 @@ class GuiNovelTree(QTreeWidget):
self._lastBuild = 0
return
- def refreshTree(self, overRide=False):
+ def refreshTree(self, rootHandle=None, overRide=False):
"""Called whenever the Novel tab is activated.
"""
logger.verbose("Requesting refresh of the novel tree")
+ if rootHandle is None:
+ rootHandle = self.theProject.tree.findRoot(nwItemClass.NOVEL)
+
treeChanged = self.mainGui.projView.changedSince(self._lastBuild)
- indexChanged = self.theProject.index.indexChangedSince(self._lastBuild)
+ indexChanged = self.theProject.index.rootChangedSince(rootHandle, self._lastBuild)
if not (treeChanged or indexChanged or overRide):
logger.verbose("No changes have been made to the novel index")
return
@@ -214,7 +335,8 @@ class GuiNovelTree(QTreeWidget):
if selItem:
titleKey = selItem[0].data(self.C_TITLE, Qt.UserRole)[2]
- self._populateTree()
+ self._populateTree(rootHandle)
+ self.theProject.setLastNovelViewed(rootHandle)
if titleKey is not None and titleKey in self._treeMap:
self._treeMap[titleKey].setSelected(True)
@@ -268,39 +390,39 @@ class GuiNovelTree(QTreeWidget):
if tHandle is None:
return
- self.mainGui.viewDocument(tHandle)
+ self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, -1, "")
return
##
- # Slots
+ # Private Slots
##
- def _treeDoubleClick(self, tItem, tCol):
+ @pyqtSlot()
+ def _treeSelectionChange(self):
+ """Extract the handle and line number of the currently selected
+ title, and send it to the tree meta panel.
+ """
+ tHandle, _ = self.getSelectedHandle()
+ if tHandle is not None:
+ self.novelView.selectedItemChanged.emit(tHandle)
+ return
+
+ @pyqtSlot("QTreeWidgetItem*", int)
+ def _treeDoubleClick(self, tItem, colNo):
"""Extract the handle and line number of the title double-
clicked, and send it to the main gui class for opening in the
document editor.
"""
tHandle, tLine = self.getSelectedHandle()
- self.mainGui.openDocument(tHandle, tLine=tLine-1, doScroll=True)
- return
-
- def _itemSelected(self):
- """Extract the handle and line number of the currently selected
- title, and send it to the tree meta panel.
- """
- selItems = self.selectedItems()
- if selItems:
- tHandle = selItems[0].data(self.C_TITLE, Qt.UserRole)[0]
- self.mainGui.itemDetails.updateViewBox(tHandle)
-
+ self.novelView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, tLine, "")
return
##
# Internal Functions
##
- def _populateTree(self):
+ def _populateTree(self, rootHandle):
"""Build the tree based on the project index.
"""
self.clearTree()
@@ -309,7 +431,9 @@ class GuiNovelTree(QTreeWidget):
currChapter = None
currScene = None
- for tKey, tHandle, sTitle, novIdx in self.theProject.index.novelStructure(skipExcl=True):
+ logger.verbose("Building novel tree for root item '%s'", rootHandle)
+ novStruct = self.theProject.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
+ for tKey, tHandle, sTitle, novIdx in novStruct:
tItem = self._createTreeItem(tHandle, sTitle, tKey, novIdx)
self._treeMap[tKey] = tItem
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index b9bfda0d..4f320bfc 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -61,7 +61,7 @@ class GuiProjectView(QWidget):
# Signals for user interaction with the project tree
selectedItemChanged = pyqtSignal(str)
- openDocumentRequest = pyqtSignal(str, Enum)
+ openDocumentRequest = pyqtSignal(str, Enum, int, str)
def __init__(self, mainGui):
QWidget.__init__(self, mainGui)
@@ -192,10 +192,10 @@ class GuiProjectToolBar(QWidget):
"QToolButton:hover {{border: none; background: rgba({1},{2},{3},0.2);}}"
).format(mPx, fadeCol.red(), fadeCol.green(), fadeCol.blue())
- # Tree Label
- self.projLabel = QLabel("%s" % self.tr("Project Content"))
- self.projLabel.setContentsMargins(0, 0, 0, 0)
- self.projLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+ # Widget Label
+ self.viewLabel = QLabel("%s" % self.tr("Project Content"))
+ self.viewLabel.setContentsMargins(0, 0, 0, 0)
+ self.viewLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
# Move Buttons
self.tbMoveU = QToolButton(self)
@@ -285,7 +285,7 @@ class GuiProjectToolBar(QWidget):
# Assemble
self.outerBox = QHBoxLayout()
- self.outerBox.addWidget(self.projLabel)
+ self.outerBox.addWidget(self.viewLabel)
self.outerBox.addWidget(self.tbMoveU)
self.outerBox.addWidget(self.tbMoveD)
self.outerBox.addWidget(self.tbAdd)
@@ -337,9 +337,8 @@ class GuiProjectTree(QTreeWidget):
self._lastMove = {}
self._timeChanged = 0
- ##
- # Build GUI
- ##
+ # Build GUI
+ # =========
# Context Menu
self.setContextMenuPolicy(Qt.CustomContextMenu)
@@ -348,6 +347,7 @@ class GuiProjectTree(QTreeWidget):
# Tree Settings
iPx = self.mainTheme.baseIconSize
cMg = self.mainConf.pxInt(6)
+
self.setIconSize(QSize(iPx, iPx))
self.setFrameStyle(QFrame.NoFrame)
self.setExpandsOnDoubleClick(False)
@@ -972,7 +972,7 @@ class GuiProjectTree(QTreeWidget):
return
if tItem.itemType == nwItemType.FILE:
- self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT)
+ self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, -1, "")
else:
trItem = self._getTreeItem(tHandle)
if trItem is not None:
@@ -1016,11 +1016,11 @@ class GuiProjectTree(QTreeWidget):
if isFile:
ctxMenu.addAction(
self.tr("Open Document"),
- lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT)
+ lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.EDIT, -1, "")
)
ctxMenu.addAction(
self.tr("View Document"),
- lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW)
+ lambda: self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, -1, "")
)
ctxMenu.addSeparator()
@@ -1112,7 +1112,7 @@ class GuiProjectTree(QTreeWidget):
return
if tItem.itemType == nwItemType.FILE:
- self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW)
+ self.projView.openDocumentRequest.emit(tHandle, nwDocMode.VIEW, -1, "")
return
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 6fa52eb6..e06b9edd 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -205,6 +205,10 @@ class GuiMain(QMainWindow):
self.projView.treeItemChanged.connect(self.docViewer.updateDocInfo)
self.projView.treeItemChanged.connect(self.itemDetails.updateViewBox)
self.projView.rootFolderChanged.connect(self.outlineView.updateRootItem)
+ self.projView.rootFolderChanged.connect(self.novelView.updateRootItem)
+
+ self.novelView.selectedItemChanged.connect(self.itemDetails.updateViewBox)
+ self.novelView.openDocumentRequest.connect(self._openDocument)
self.docEditor.spellDictionaryChanged.connect(self.statusBar.setLanguage)
self.docEditor.docEditedStatusChanged.connect(self.statusBar.doUpdateDocumentStatus)
@@ -362,6 +366,7 @@ class GuiMain(QMainWindow):
self.saveProject()
self.docEditor.setDictionaries()
self.outlineView.updateRootItem(None)
+ self.novelView.openProjectTasks()
self.rebuildIndex(beQuiet=True)
self.statusBar.setRefTime(self.theProject.projOpened)
self.statusBar.setProjectStatus(nwState.GOOD)
@@ -509,6 +514,7 @@ class GuiMain(QMainWindow):
self.docEditor.toggleSpellCheck(self.theProject.spellCheck)
self.statusBar.setRefTime(self.theProject.projOpened)
self.outlineView.updateRootItem(None)
+ self.novelView.openProjectTasks()
self._updateStatusWordCount()
# Restore previously open documents, if any
@@ -825,7 +831,7 @@ class GuiMain(QMainWindow):
"""Rebuild the project tree.
"""
self.projView.populateTree()
- self.novelView.refreshTree()
+ # self.novelView.refreshTree()
return
def requestNovelTreeRefresh(self):
@@ -1468,15 +1474,15 @@ class GuiMain(QMainWindow):
self.viewDocument(tHandle=tHandle, tAnchor=f"#{sTitle}")
return
- @pyqtSlot(str, Enum)
- def _openDocument(self, tHandle, tMode):
- """Handle an open document request.
+ @pyqtSlot(str, Enum, int, str)
+ def _openDocument(self, tHandle, tMode, tLine, tAnchor):
+ """Handle an open document request from one of the tree views.
"""
if tHandle is not None:
if tMode == nwDocMode.EDIT:
- self.openDocument(tHandle, changeFocus=False)
+ self.openDocument(tHandle, tLine=tLine, changeFocus=False)
elif tMode == nwDocMode.VIEW:
- self.viewDocument(tHandle=tHandle)
+ self.viewDocument(tHandle=tHandle, tAnchor=(tAnchor or None))
return
@pyqtSlot(nwView)
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index e8ee5c59..af509400 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,13 +1,13 @@
-
+
Sample Project
Sample Project
Jane Smith
Jay Doh
- 1345
- 229
- 68286
+ 1367
+ 231
+ 68784
False
@@ -17,6 +17,8 @@
True
636b6aa9b697b
636b6aa9b697b
+ 7031beac91f75
+ None
1363
954
409
@@ -70,11 +72,11 @@
Chapter One
-
-
+
Making a Scene
-
-
+
Another Scene
-
@@ -86,7 +88,7 @@
A Note on Structure
-
-
+
Chapter Two
-
From 88b2d61cec978044e77b310f50e95f921e502bfb Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sun, 12 Jun 2022 17:54:37 +0200
Subject: [PATCH 26/35] Update tests
---
tests/lipsum/nwProject.nwx | 2 ++
tests/minimal/nwProject.nwx | 2 ++
tests/reference/coreProject_NewCustomA_nwProject.nwx | 4 +++-
tests/reference/coreProject_NewCustomB_nwProject.nwx | 4 +++-
tests/reference/coreProject_NewFileFolder_nwProject.nwx | 4 +++-
tests/reference/coreProject_NewMinimal_nwProject.nwx | 4 +++-
tests/reference/coreProject_NewRoot_nwProject.nwx | 4 +++-
tests/reference/guiEditor_Main_Final_nwProject.nwx | 4 +++-
tests/reference/guiEditor_Main_Initial_nwProject.nwx | 4 +++-
tests/reference/guiProjSettings_Dialog_nwProject.nwx | 4 +++-
tests/test_gui/test_gui_guimain.py | 2 +-
tests/test_gui/test_gui_noveltree.py | 4 ++--
12 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/tests/lipsum/nwProject.nwx b/tests/lipsum/nwProject.nwx
index 02e3df49..a8cf6393 100644
--- a/tests/lipsum/nwProject.nwx
+++ b/tests/lipsum/nwProject.nwx
@@ -16,6 +16,8 @@
True
7a992350f3eb6
None
+ None
+ None
3847
3109
738
diff --git a/tests/minimal/nwProject.nwx b/tests/minimal/nwProject.nwx
index af7595a4..430ecf17 100644
--- a/tests/minimal/nwProject.nwx
+++ b/tests/minimal/nwProject.nwx
@@ -17,6 +17,8 @@
True
None
None
+ None
+ None
10
10
0
diff --git a/tests/reference/coreProject_NewCustomA_nwProject.nwx b/tests/reference/coreProject_NewCustomA_nwProject.nwx
index be4845bf..f046fceb 100644
--- a/tests/reference/coreProject_NewCustomA_nwProject.nwx
+++ b/tests/reference/coreProject_NewCustomA_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Test Custom
Test Novel
@@ -17,6 +17,8 @@
True
None
None
+ None
+ None
0
0
0
diff --git a/tests/reference/coreProject_NewCustomB_nwProject.nwx b/tests/reference/coreProject_NewCustomB_nwProject.nwx
index 12f911cd..5d02172c 100644
--- a/tests/reference/coreProject_NewCustomB_nwProject.nwx
+++ b/tests/reference/coreProject_NewCustomB_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Test Custom
Test Novel
@@ -17,6 +17,8 @@
True
None
None
+ None
+ None
0
0
0
diff --git a/tests/reference/coreProject_NewFileFolder_nwProject.nwx b/tests/reference/coreProject_NewFileFolder_nwProject.nwx
index 4235e9bb..20aeb027 100644
--- a/tests/reference/coreProject_NewFileFolder_nwProject.nwx
+++ b/tests/reference/coreProject_NewFileFolder_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
New Novel
@@ -16,6 +16,8 @@
True
None
None
+ None
+ None
2
1
1
diff --git a/tests/reference/coreProject_NewMinimal_nwProject.nwx b/tests/reference/coreProject_NewMinimal_nwProject.nwx
index 422bb6b2..ba08600f 100644
--- a/tests/reference/coreProject_NewMinimal_nwProject.nwx
+++ b/tests/reference/coreProject_NewMinimal_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
@@ -15,6 +15,8 @@
True
None
None
+ None
+ None
0
0
0
diff --git a/tests/reference/coreProject_NewRoot_nwProject.nwx b/tests/reference/coreProject_NewRoot_nwProject.nwx
index cd25c1cf..0a606137 100644
--- a/tests/reference/coreProject_NewRoot_nwProject.nwx
+++ b/tests/reference/coreProject_NewRoot_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
New Novel
@@ -16,6 +16,8 @@
True
None
None
+ None
+ None
0
0
0
diff --git a/tests/reference/guiEditor_Main_Final_nwProject.nwx b/tests/reference/guiEditor_Main_Final_nwProject.nwx
index a47d454d..ecc96604 100644
--- a/tests/reference/guiEditor_Main_Final_nwProject.nwx
+++ b/tests/reference/guiEditor_Main_Final_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
New Novel
@@ -16,6 +16,8 @@
True
000000000000f
None
+ 0000000000008
+ None
129
102
27
diff --git a/tests/reference/guiEditor_Main_Initial_nwProject.nwx b/tests/reference/guiEditor_Main_Initial_nwProject.nwx
index 03313570..1a79d2c2 100644
--- a/tests/reference/guiEditor_Main_Initial_nwProject.nwx
+++ b/tests/reference/guiEditor_Main_Initial_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
New Project
New Novel
@@ -16,6 +16,8 @@
True
None
None
+ None
+ None
9
9
0
diff --git a/tests/reference/guiProjSettings_Dialog_nwProject.nwx b/tests/reference/guiProjSettings_Dialog_nwProject.nwx
index f12c1dc2..883cb26d 100644
--- a/tests/reference/guiProjSettings_Dialog_nwProject.nwx
+++ b/tests/reference/guiProjSettings_Dialog_nwProject.nwx
@@ -1,5 +1,5 @@
-
+
Project Name
Project Title
@@ -17,6 +17,8 @@
True
None
None
+ None
+ None
9
9
0
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index 9a56af3d..b197885e 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -132,7 +132,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Novel Tree has focus
nwGUI.projStack.setCurrentIndex(1)
- nwGUI.novelView.refreshTree(True)
+ nwGUI.novelView.refreshTree(rootHandle=None, overRide=True)
with monkeypatch.context() as mp:
mp.setattr(GuiNovelView, "treeFocus", lambda *a: True)
assert nwGUI.docEditor.docHandle() is None
diff --git a/tests/test_gui/test_gui_noveltree.py b/tests/test_gui/test_gui_noveltree.py
index 644839d3..b1e223cf 100644
--- a/tests/test_gui/test_gui_noveltree.py
+++ b/tests/test_gui/test_gui_noveltree.py
@@ -62,7 +62,7 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
nwGUI.projStack.setCurrentIndex(nwGUI.idxNovelView)
nwGUI.rebuildIndex()
- novelTree._populateTree()
+ novelTree._populateTree(rootHandle=None)
assert novelTree.topLevelItemCount() == 1
# Rebuild should preserve selection
@@ -133,7 +133,7 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
"#### Section\n\n"
))
nwGUI.rebuildIndex()
- novelTree._populateTree()
+ novelTree._populateTree(None)
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"
From 80404417574c63dbbf2e74f12163be51394028dc Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sun, 12 Jun 2022 19:59:18 +0200
Subject: [PATCH 27/35] Allow changing content of last column of the novel tree
---
novelwriter/core/options.py | 3 +-
novelwriter/gui/noveltree.py | 117 +++++++++++++++++++++++++++++++++--
novelwriter/guimain.py | 1 +
3 files changed, 114 insertions(+), 7 deletions(-)
diff --git a/novelwriter/core/options.py b/novelwriter/core/options.py
index 144ba4ac..b3724047 100644
--- a/novelwriter/core/options.py
+++ b/novelwriter/core/options.py
@@ -56,7 +56,8 @@ VALID_MAP = {
"winWidth", "winHeight", "widthCol0", "widthCol1", "widthCol2",
"widthCol3", "widthCol4", "wordsPerPage", "countFrom", "clearDouble"
},
- "GuiWordList": {"winWidth", "winHeight"}
+ "GuiWordList": {"winWidth", "winHeight"},
+ "GuiNovelView": {"lastCol"},
}
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index 8cec9fdb..a23e1e9e 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -39,11 +39,20 @@ from PyQt5.QtWidgets import (
from novelwriter.enum import nwDocMode, nwItemClass
from novelwriter.common import checkInt
-from novelwriter.constants import nwKeyWords, nwLabels
+from novelwriter.constants import nwKeyWords, nwLabels, trConst
logger = logging.getLogger(__name__)
+class NovelColumnType(Enum):
+
+ HIDDEN = 0
+ POV = 1
+ FOCUS = 2
+
+# END Enum NovelColumnType
+
+
class GuiNovelView(QWidget):
# Signals for user interaction with the novel tree
@@ -94,7 +103,7 @@ class GuiNovelView(QWidget):
return
def openProjectTasks(self):
- """Run tasks related to opening a project.
+ """Run tasks when opening a project.
"""
lastNovel = self.theProject.lastNovel
if lastNovel is None:
@@ -104,10 +113,17 @@ class GuiNovelView(QWidget):
self.clearProject()
self.novelBar.rebuildNovelRootMenu(selHandle=lastNovel)
+ self.novelTree.loadOptions()
self.novelTree.refreshTree(rootHandle=lastNovel, overRide=True)
return
+ def closeProjectTasks(self):
+ """Run tasks when closing a project.
+ """
+ self.novelTree.saveOptions()
+ return
+
def setFocus(self):
"""Forward the set focus call to the tree widget.
"""
@@ -168,6 +184,14 @@ class GuiNovelToolBar(QWidget):
self.viewLabel.setContentsMargins(0, 0, 0, 0)
self.viewLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+ # Refresh Button
+ self.tbRefresh = QToolButton(self)
+ self.tbRefresh.setToolTip(self.tr("Refresh"))
+ self.tbRefresh.setIcon(self.mainTheme.getIcon("refresh"))
+ self.tbRefresh.setIconSize(QSize(iPx, iPx))
+ self.tbRefresh.setStyleSheet(buttonStyle)
+ self.tbRefresh.clicked.connect(self._refreshNovelTree)
+
# Novel Root Menu
self.mRoot = QMenu()
@@ -182,6 +206,17 @@ class GuiNovelToolBar(QWidget):
# More Options Menu
self.mMore = QMenu()
+ self.mCol3 = self.mMore.addMenu(self.tr("Third Column"))
+ self.mCol3.addAction(self.tr("Hide Column")).triggered.connect(
+ lambda: self.novelView.novelTree.setLastColType(NovelColumnType.HIDDEN)
+ )
+ self.mCol3.addAction(self.tr("Point of View Character")).triggered.connect(
+ lambda: self.novelView.novelTree.setLastColType(NovelColumnType.POV)
+ )
+ self.mCol3.addAction(self.tr("Focus Character")).triggered.connect(
+ lambda: self.novelView.novelTree.setLastColType(NovelColumnType.FOCUS)
+ )
+
self.tbMore = QToolButton(self)
self.tbMore.setToolTip(self.tr("More Options"))
self.tbMore.setIcon(self.mainTheme.getIcon("menu"))
@@ -193,6 +228,7 @@ class GuiNovelToolBar(QWidget):
# Assemble
self.outerBox = QHBoxLayout()
self.outerBox.addWidget(self.viewLabel)
+ self.outerBox.addWidget(self.tbRefresh)
self.outerBox.addWidget(self.tbRoot)
self.outerBox.addWidget(self.tbMore)
self.outerBox.setContentsMargins(mPx, mPx, 0, mPx)
@@ -230,6 +266,18 @@ class GuiNovelToolBar(QWidget):
return
+ ##
+ # Private Slots
+ ##
+
+ @pyqtSlot()
+ def _refreshNovelTree(self):
+ """Rebuild the current tree.
+ """
+ rootHandle = self.theProject.lastNovel
+ self.novelView.novelTree.refreshTree(rootHandle=rootHandle, overRide=True)
+ return
+
# END Class GuiNovelToolBar
@@ -237,7 +285,7 @@ class GuiNovelTree(QTreeWidget):
C_TITLE = 0
C_WORDS = 1
- C_POV = 2
+ C_LAST = 2
def __init__(self, novelView):
QTreeWidget.__init__(self, novelView)
@@ -253,6 +301,11 @@ class GuiNovelTree(QTreeWidget):
# Internal Variables
self._treeMap = {}
self._lastBuild = 0
+ self._lastCol = NovelColumnType.POV
+
+ # Cached i18n Strings
+ self._povLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY])
+ self._focLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY])
# Build GUI
# =========
@@ -276,7 +329,7 @@ class GuiNovelTree(QTreeWidget):
treeHeader.setMinimumSectionSize(iPx + cMg)
treeHeader.setSectionResizeMode(self.C_TITLE, QHeaderView.Stretch)
treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeToContents)
- treeHeader.setSectionResizeMode(self.C_POV, QHeaderView.ResizeToContents)
+ treeHeader.setSectionResizeMode(self.C_LAST, QHeaderView.ResizeToContents)
# Connect signals
self.itemDoubleClicked.connect(self._treeDoubleClick)
@@ -317,6 +370,32 @@ class GuiNovelTree(QTreeWidget):
self._lastBuild = 0
return
+ def loadOptions(self):
+ """Load user options.
+ """
+ try:
+ lastCol = NovelColumnType[self.theProject.options.getString(
+ "GuiNovelView", "lastCol", NovelColumnType.POV.name
+ )]
+ except Exception:
+ logger.error("Failed to load last column type from options")
+ return False
+
+ self._lastCol = lastCol
+ self.setColumnHidden(self.C_LAST, lastCol == NovelColumnType.HIDDEN)
+
+ return True
+
+ def saveOptions(self):
+ """Save user options.
+ """
+ try:
+ self.theProject.options.setValue("GuiNovelView", "lastCol", self._lastCol.name)
+ except Exception:
+ logger.error("Failed to save last column type to options")
+ return False
+ return True
+
def refreshTree(self, rootHandle=None, overRide=False):
"""Called whenever the Novel tab is activated.
"""
@@ -365,6 +444,16 @@ class GuiNovelTree(QTreeWidget):
return tHandle, tLine
+ def setLastColType(self, colType):
+ """Change the content type of the last column and rebuild.
+ """
+ if self._lastCol != colType:
+ logger.debug("Changing last column to %s", colType.name)
+ self._lastCol = colType
+ self.setColumnHidden(self.C_LAST, colType == NovelColumnType.HIDDEN)
+ self.refreshTree(rootHandle=self.theProject.lastNovel, overRide=True)
+ return
+
##
# Events
##
@@ -431,6 +520,8 @@ class GuiNovelTree(QTreeWidget):
currChapter = None
currScene = None
+ tStart = time()
+
logger.verbose("Building novel tree for root item '%s'", rootHandle)
novStruct = self.theProject.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
for tKey, tHandle, sTitle, novIdx in novStruct:
@@ -477,6 +568,8 @@ class GuiNovelTree(QTreeWidget):
tItem.setExpanded(True)
+ logger.verbose("Novel Tree built in %.3f ms", (time() - tStart)*1000)
+
self._lastBuild = time()
return
@@ -496,8 +589,20 @@ class GuiNovelTree(QTreeWidget):
newItem.setText(self.C_WORDS, f"{wC:n}")
newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
- theRefs = self.theProject.index.getReferences(tHandle, sTitle)
- newItem.setText(self.C_POV, ", ".join(theRefs[nwKeyWords.POV_KEY]))
+ if self._lastCol == NovelColumnType.HIDDEN:
+ newItem.setText(self.C_LAST, "")
+ else:
+ theRefs = self.theProject.index.getReferences(tHandle, sTitle)
+ if self._lastCol == NovelColumnType.POV:
+ newText = ", ".join(theRefs[nwKeyWords.POV_KEY])
+ newItem.setText(self.C_LAST, newText)
+ if newText:
+ newItem.setToolTip(self.C_LAST, f"{self._povLabel}: {newText}")
+ elif self._lastCol == NovelColumnType.FOCUS:
+ newText = ", ".join(theRefs[nwKeyWords.FOCUS_KEY])
+ newItem.setText(self.C_LAST, newText)
+ if newText:
+ newItem.setToolTip(self.C_LAST, f"{self._focLabel}: {newText}")
return newItem
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index e06b9edd..d3e36e90 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -423,6 +423,7 @@ class GuiMain(QMainWindow):
self.closeDocument()
self.docViewer.clearNavHistory()
self.outlineView.closeOutline()
+ self.novelView.closeProjectTasks()
self.theProject.closeProject(self.idleTime)
self.idleRefTime = time()
From 49ace054bdb1982c63dfa32a430eff525f771b9f Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Sun, 12 Jun 2022 20:18:24 +0200
Subject: [PATCH 28/35] Make options class handle enums, and add plot column to
novel tree
---
novelwriter/core/options.py | 19 ++++++++++++++++++-
novelwriter/gui/noveltree.py | 33 ++++++++++++++++-----------------
2 files changed, 34 insertions(+), 18 deletions(-)
diff --git a/novelwriter/core/options.py b/novelwriter/core/options.py
index b3724047..d64970ae 100644
--- a/novelwriter/core/options.py
+++ b/novelwriter/core/options.py
@@ -28,6 +28,8 @@ import os
import json
import logging
+from enum import Enum
+
from novelwriter.error import logException
from novelwriter.common import checkBool, checkFloat, checkInt, checkString
from novelwriter.constants import nwFiles
@@ -138,7 +140,10 @@ class OptionState():
if group not in self._theState:
self._theState[group] = {}
- self._theState[group][name] = value
+ if isinstance(value, Enum):
+ self._theState[group][name] = value.name
+ else:
+ self._theState[group][name] = value
return True
@@ -187,4 +192,16 @@ class OptionState():
return checkBool(self._theState[group].get(name, default), default)
return default
+ def getEnum(self, group, name, lookup, default):
+ """Return the value mapped to an enum. Otherwise return the
+ default value
+ """
+ if issubclass(lookup, Enum):
+ if group in self._theState:
+ if name in self._theState[group]:
+ value = self._theState[group][name]
+ if value in lookup.__members__:
+ return lookup[value]
+ return default
+
# END Class OptionState
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index a23e1e9e..8bfd207a 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -49,6 +49,7 @@ class NovelColumnType(Enum):
HIDDEN = 0
POV = 1
FOCUS = 2
+ PLOT = 3
# END Enum NovelColumnType
@@ -216,6 +217,9 @@ class GuiNovelToolBar(QWidget):
self.mCol3.addAction(self.tr("Focus Character")).triggered.connect(
lambda: self.novelView.novelTree.setLastColType(NovelColumnType.FOCUS)
)
+ self.mCol3.addAction(self.tr("Novel Plot")).triggered.connect(
+ lambda: self.novelView.novelTree.setLastColType(NovelColumnType.PLOT)
+ )
self.tbMore = QToolButton(self)
self.tbMore.setToolTip(self.tr("More Options"))
@@ -306,6 +310,7 @@ class GuiNovelTree(QTreeWidget):
# Cached i18n Strings
self._povLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY])
self._focLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY])
+ self._pltLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY])
# Build GUI
# =========
@@ -373,28 +378,17 @@ class GuiNovelTree(QTreeWidget):
def loadOptions(self):
"""Load user options.
"""
- try:
- lastCol = NovelColumnType[self.theProject.options.getString(
- "GuiNovelView", "lastCol", NovelColumnType.POV.name
- )]
- except Exception:
- logger.error("Failed to load last column type from options")
- return False
-
- self._lastCol = lastCol
- self.setColumnHidden(self.C_LAST, lastCol == NovelColumnType.HIDDEN)
-
+ self._lastCol = self.theProject.options.getEnum(
+ "GuiNovelView", "lastCol", NovelColumnType, NovelColumnType.POV
+ )
+ self.setColumnHidden(self.C_LAST, self._lastCol == NovelColumnType.HIDDEN)
return True
def saveOptions(self):
"""Save user options.
"""
- try:
- self.theProject.options.setValue("GuiNovelView", "lastCol", self._lastCol.name)
- except Exception:
- logger.error("Failed to save last column type to options")
- return False
- return True
+ self.theProject.options.setValue("GuiNovelView", "lastCol", self._lastCol)
+ return
def refreshTree(self, rootHandle=None, overRide=False):
"""Called whenever the Novel tab is activated.
@@ -603,6 +597,11 @@ class GuiNovelTree(QTreeWidget):
newItem.setText(self.C_LAST, newText)
if newText:
newItem.setToolTip(self.C_LAST, f"{self._focLabel}: {newText}")
+ elif self._lastCol == NovelColumnType.PLOT:
+ newText = ", ".join(theRefs[nwKeyWords.PLOT_KEY])
+ newItem.setText(self.C_LAST, newText)
+ if newText:
+ newItem.setToolTip(self.C_LAST, f"{self._pltLabel}: {newText}")
return newItem
From ea61db9591316db21774840411e7fd4a021ec608 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 14 Jun 2022 00:14:51 +0200
Subject: [PATCH 29/35] Simplify the novel outline tree
---
novelwriter/constants.py | 9 ++
novelwriter/core/index.py | 20 ++---
novelwriter/core/project.py | 2 +-
novelwriter/gui/noveltree.py | 164 ++++++++++++++++-------------------
novelwriter/guimain.py | 20 ++---
5 files changed, 101 insertions(+), 114 deletions(-)
diff --git a/novelwriter/constants.py b/novelwriter/constants.py
index dc62dbd3..3d1b5c13 100644
--- a/novelwriter/constants.py
+++ b/novelwriter/constants.py
@@ -57,6 +57,15 @@ class nwRegEx:
# END Class nwRegEx
+class nwHeaders:
+
+ H_VALID = ("H0", "H1", "H2", "H3", "H4")
+ H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
+ TT_NONE = "T000000"
+
+# END Class nwHeaders
+
+
class nwFiles:
PROJ_FILE = "nwProject.nwx"
diff --git a/novelwriter/core/index.py b/novelwriter/core/index.py
index ee9ea089..0b3afdc5 100644
--- a/novelwriter/core/index.py
+++ b/novelwriter/core/index.py
@@ -34,7 +34,7 @@ from time import time
from novelwriter.enum import nwItemType, nwItemLayout
from novelwriter.error import logException
-from novelwriter.constants import nwFiles, nwKeyWords, nwUnicode
+from novelwriter.constants import nwFiles, nwKeyWords, nwUnicode, nwHeaders
from novelwriter.core.document import NWDoc
from novelwriter.common import (
checkInt, isHandle, isItemClass, isTitleTag, jsonEncode
@@ -42,10 +42,6 @@ from novelwriter.common import (
logger = logging.getLogger(__name__)
-H_VALID = ("H0", "H1", "H2", "H3", "H4")
-H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
-TT_NONE = "T000000"
-
class NWIndex:
"""This class holds the entire index for a given project. The index
@@ -477,7 +473,7 @@ class NWIndex:
"""
hCount = [0, 0, 0, 0, 0]
for _, _, hItem in self._itemIndex.iterNovelStructure(skipExcl=skipExcl):
- iLevel = H_LEVEL.get(hItem.level, 0)
+ iLevel = nwHeaders.H_LEVEL.get(hItem.level, 0)
hCount[iLevel] += 1
return hCount
@@ -510,7 +506,7 @@ class NWIndex:
pKey = None
for tHandle, sTitle, hItem in self._itemIndex.iterNovelStructure(skipExcl=skipExcl):
tKey = f"{tHandle}:{sTitle}"
- iLevel = H_LEVEL.get(hItem.level, 0)
+ iLevel = nwHeaders.H_LEVEL.get(hItem.level, 0)
if iLevel > maxDepth:
if pKey in tData:
tData[pKey]["words"] += hItem.wordCount
@@ -660,7 +656,7 @@ class TagsIndex:
"""
if tagKey in self._tags:
return self._tags.get(tagKey).get("heading")
- return TT_NONE
+ return nwHeaders.TT_NONE
def tagClass(self, tagKey):
"""Get the class of a given tag.
@@ -906,7 +902,7 @@ class IndexItem:
self._index = 0
# Add a placeholder heading
- self._headings[TT_NONE] = IndexHeading(TT_NONE)
+ self._headings[nwHeaders.TT_NONE] = IndexHeading(nwHeaders.TT_NONE)
return
@@ -940,8 +936,8 @@ class IndexItem:
"""Add a heading to the item. Also remove the placeholder entry
if it exists.
"""
- if TT_NONE in self._headings:
- self._headings.pop(TT_NONE)
+ if nwHeaders.TT_NONE in self._headings:
+ self._headings.pop(nwHeaders.TT_NONE)
self._headings[tHeading.key] = tHeading
return
@@ -1110,7 +1106,7 @@ class IndexHeading:
def setLevel(self, level):
"""Set the level of the header if it's a valid value.
"""
- if level in H_VALID:
+ if level in nwHeaders.H_VALID:
self._level = level
return
diff --git a/novelwriter/core/project.py b/novelwriter/core/project.py
index 43f3297e..fb81f033 100644
--- a/novelwriter/core/project.py
+++ b/novelwriter/core/project.py
@@ -653,7 +653,7 @@ class NWProject():
self._legacyDataFolder(projItem)
except Exception:
self.mainGui.makeAlert(self.tr(
- "There was an error while converting project version 1.0. "
+ "There was an error updating the project. "
"Some data may not have been preserved."
), nwAlert.ERROR)
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index 8bfd207a..33981243 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -4,7 +4,9 @@ novelWriter – GUI Novel Tree
GUI classe for the main window novel tree
File History:
-Created: 2020-12-20 [1.1a0]
+Created: 2020-12-20 [1.1a0] GuiNovelTree
+Created: 2022-06-12 [1.7b1] GuiNovelView
+Created: 2022-06-12 [1.7b1] GuiNovelToolBar
This file is a part of novelWriter
Copyright 2018–2020, Veronica Berglyd Olsen
@@ -30,7 +32,7 @@ from time import time
from enum import Enum
from PyQt5.QtCore import Qt, QSize, pyqtSlot, pyqtSignal
-from PyQt5.QtGui import QPalette
+from PyQt5.QtGui import QPalette, QPixmap, QColor
from PyQt5.QtWidgets import (
QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView, QLabel,
QMenu, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
@@ -39,19 +41,19 @@ from PyQt5.QtWidgets import (
from novelwriter.enum import nwDocMode, nwItemClass
from novelwriter.common import checkInt
-from novelwriter.constants import nwKeyWords, nwLabels, trConst
+from novelwriter.constants import nwHeaders, nwKeyWords, nwLabels, trConst
logger = logging.getLogger(__name__)
-class NovelColumnType(Enum):
+class NovelTreeColumn(Enum):
HIDDEN = 0
POV = 1
FOCUS = 2
PLOT = 3
-# END Enum NovelColumnType
+# END Enum NovelTreeColumn
class GuiNovelView(QWidget):
@@ -209,16 +211,16 @@ class GuiNovelToolBar(QWidget):
self.mCol3 = self.mMore.addMenu(self.tr("Third Column"))
self.mCol3.addAction(self.tr("Hide Column")).triggered.connect(
- lambda: self.novelView.novelTree.setLastColType(NovelColumnType.HIDDEN)
+ lambda: self.novelView.novelTree.setLastColType(NovelTreeColumn.HIDDEN)
)
self.mCol3.addAction(self.tr("Point of View Character")).triggered.connect(
- lambda: self.novelView.novelTree.setLastColType(NovelColumnType.POV)
+ lambda: self.novelView.novelTree.setLastColType(NovelTreeColumn.POV)
)
self.mCol3.addAction(self.tr("Focus Character")).triggered.connect(
- lambda: self.novelView.novelTree.setLastColType(NovelColumnType.FOCUS)
+ lambda: self.novelView.novelTree.setLastColType(NovelTreeColumn.FOCUS)
)
self.mCol3.addAction(self.tr("Novel Plot")).triggered.connect(
- lambda: self.novelView.novelTree.setLastColType(NovelColumnType.PLOT)
+ lambda: self.novelView.novelTree.setLastColType(NovelTreeColumn.PLOT)
)
self.tbMore = QToolButton(self)
@@ -305,9 +307,9 @@ class GuiNovelTree(QTreeWidget):
# Internal Variables
self._treeMap = {}
self._lastBuild = 0
- self._lastCol = NovelColumnType.POV
+ self._lastCol = NovelTreeColumn.POV
- # Cached i18n Strings
+ # Cached Strings
self._povLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.POV_KEY])
self._focLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.FOCUS_KEY])
self._pltLabel = trConst(nwLabels.KEY_NAME[nwKeyWords.PLOT_KEY])
@@ -316,12 +318,15 @@ class GuiNovelTree(QTreeWidget):
# =========
iPx = self.mainTheme.baseIconSize
+ nPx = self.mainTheme.textNWidth
cMg = self.mainConf.pxInt(6)
+ mPx = self.mainConf.pxInt(4)
+ nMg = self.mainConf.pxInt(6)
- self.setIconSize(QSize(iPx, iPx))
+ # self.setIconSize(QSize(iPx, iPx))
self.setFrameStyle(QFrame.NoFrame)
self.setHeaderHidden(True)
- self.setIndentation(iPx)
+ self.setIndentation(mPx)
self.setColumnCount(3)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSelectionMode(QAbstractItemView.SingleSelection)
@@ -336,6 +341,25 @@ class GuiNovelTree(QTreeWidget):
treeHeader.setSectionResizeMode(self.C_WORDS, QHeaderView.ResizeToContents)
treeHeader.setSectionResizeMode(self.C_LAST, QHeaderView.ResizeToContents)
+ # Pre-Generate Tree Formatting
+ fH1 = self.font()
+ fH1.setBold(True)
+ fH1.setUnderline(True)
+
+ fH2 = self.font()
+ fH2.setBold(True)
+
+ self._hFonts = [self.font(), fH1, fH2, self.font(), self.font()]
+ self._hIndent = ["", "", "", "\u2022\u00a0", "\u00bb\u00a0"]
+ self._pIndent = [QPixmap(), QPixmap()]
+
+ hPix = QPixmap(QSize(iPx, iPx))
+ hPix.fill(QColor(0, 0, 0, 0))
+ for m in range(1, 4):
+ self._pIndent.append(hPix.scaled(
+ max(nPx*m - nMg, nMg), 2, Qt.IgnoreAspectRatio, Qt.FastTransformation
+ ))
+
# Connect signals
self.itemDoubleClicked.connect(self._treeDoubleClick)
self.itemSelectionChanged.connect(self._treeSelectionChange)
@@ -379,9 +403,9 @@ class GuiNovelTree(QTreeWidget):
"""Load user options.
"""
self._lastCol = self.theProject.options.getEnum(
- "GuiNovelView", "lastCol", NovelColumnType, NovelColumnType.POV
+ "GuiNovelView", "lastCol", NovelTreeColumn, NovelTreeColumn.POV
)
- self.setColumnHidden(self.C_LAST, self._lastCol == NovelColumnType.HIDDEN)
+ self.setColumnHidden(self.C_LAST, self._lastCol == NovelTreeColumn.HIDDEN)
return True
def saveOptions(self):
@@ -444,7 +468,7 @@ class GuiNovelTree(QTreeWidget):
if self._lastCol != colType:
logger.debug("Changing last column to %s", colType.name)
self._lastCol = colType
- self.setColumnHidden(self.C_LAST, colType == NovelColumnType.HIDDEN)
+ self.setColumnHidden(self.C_LAST, colType == NovelTreeColumn.HIDDEN)
self.refreshTree(rootHandle=self.theProject.lastNovel, overRide=True)
return
@@ -509,100 +533,58 @@ class GuiNovelTree(QTreeWidget):
"""Build the tree based on the project index.
"""
self.clearTree()
-
- currTitle = None
- currChapter = None
- currScene = None
-
tStart = time()
-
logger.verbose("Building novel tree for root item '%s'", rootHandle)
+
novStruct = self.theProject.index.novelStructure(rootHandle=rootHandle, skipExcl=True)
for tKey, tHandle, sTitle, novIdx in novStruct:
- tItem = self._createTreeItem(tHandle, sTitle, tKey, novIdx)
- self._treeMap[tKey] = tItem
+ iLevel = nwHeaders.H_LEVEL.get(novIdx.level, 0)
+ if iLevel == 0:
+ continue
- tLevel = novIdx.level
- if tLevel == "H1":
- self.addTopLevelItem(tItem)
- currTitle = tItem
- currChapter = None
- currScene = None
+ newItem = QTreeWidgetItem()
+ theData = (tHandle, sTitle[1:].lstrip("0"), tKey)
- elif tLevel == "H2":
- if currTitle is None:
- self.addTopLevelItem(tItem)
- else:
- currTitle.addChild(tItem)
- currChapter = tItem
- currScene = None
+ newItem.setData(self.C_TITLE, Qt.DecorationRole, self._pIndent[iLevel])
+ newItem.setText(self.C_TITLE, self._hIndent[iLevel] + novIdx.title)
+ newItem.setData(self.C_TITLE, Qt.UserRole, theData)
+ newItem.setFont(self.C_TITLE, self._hFonts[iLevel])
+ newItem.setText(self.C_WORDS, f"{novIdx.wordCount:n}")
+ newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
- elif tLevel == "H3":
- if currChapter is None:
- if currTitle is None:
- self.addTopLevelItem(tItem)
- else:
- currTitle.addChild(tItem)
- else:
- currChapter.addChild(tItem)
- currScene = tItem
+ lastText, toolTip = self._getLastColumnText(tHandle, sTitle)
+ newItem.setText(self.C_LAST, lastText)
+ if lastText:
+ newItem.setToolTip(self.C_LAST, toolTip)
- elif tLevel == "H4":
- if currScene is None:
- if currChapter is None:
- if currTitle is None:
- self.addTopLevelItem(tItem)
- else:
- currTitle.addChild(tItem)
- else:
- currChapter.addChild(tItem)
- else:
- currScene.addChild(tItem)
-
- tItem.setExpanded(True)
+ self._treeMap[tKey] = newItem
+ self.addTopLevelItem(newItem)
logger.verbose("Novel Tree built in %.3f ms", (time() - tStart)*1000)
-
self._lastBuild = time()
return
- def _createTreeItem(self, tHandle, sTitle, titleKey, novIdx):
- """Populate a tree item with all the column values.
+ def _getLastColumnText(self, tHandle, sTitle):
+ """Generate the text for the last column based on user settings.
"""
- newItem = QTreeWidgetItem()
- hIcon = "doc_%s" % novIdx.level.lower()
- theData = (tHandle, sTitle[1:].lstrip("0"), titleKey)
+ if self._lastCol == NovelTreeColumn.HIDDEN:
+ return "", ""
- wC = int(novIdx.wordCount)
+ theRefs = self.theProject.index.getReferences(tHandle, sTitle)
+ if self._lastCol == NovelTreeColumn.POV:
+ newText = ", ".join(theRefs[nwKeyWords.POV_KEY])
+ return newText, f"{self._povLabel}: {newText}"
- newItem.setText(self.C_TITLE, novIdx.title)
- newItem.setData(self.C_TITLE, Qt.UserRole, theData)
- newItem.setIcon(self.C_TITLE, self.mainTheme.getIcon(hIcon))
- newItem.setText(self.C_WORDS, f"{wC:n}")
- newItem.setTextAlignment(self.C_WORDS, Qt.AlignRight)
+ elif self._lastCol == NovelTreeColumn.FOCUS:
+ newText = ", ".join(theRefs[nwKeyWords.FOCUS_KEY])
+ return newText, f"{self._focLabel}: {newText}"
- if self._lastCol == NovelColumnType.HIDDEN:
- newItem.setText(self.C_LAST, "")
- else:
- theRefs = self.theProject.index.getReferences(tHandle, sTitle)
- if self._lastCol == NovelColumnType.POV:
- newText = ", ".join(theRefs[nwKeyWords.POV_KEY])
- newItem.setText(self.C_LAST, newText)
- if newText:
- newItem.setToolTip(self.C_LAST, f"{self._povLabel}: {newText}")
- elif self._lastCol == NovelColumnType.FOCUS:
- newText = ", ".join(theRefs[nwKeyWords.FOCUS_KEY])
- newItem.setText(self.C_LAST, newText)
- if newText:
- newItem.setToolTip(self.C_LAST, f"{self._focLabel}: {newText}")
- elif self._lastCol == NovelColumnType.PLOT:
- newText = ", ".join(theRefs[nwKeyWords.PLOT_KEY])
- newItem.setText(self.C_LAST, newText)
- if newText:
- newItem.setToolTip(self.C_LAST, f"{self._pltLabel}: {newText}")
+ elif self._lastCol == NovelTreeColumn.PLOT:
+ newText = ", ".join(theRefs[nwKeyWords.PLOT_KEY])
+ return newText, f"{self._pltLabel}: {newText}"
- return newItem
+ return "", ""
# END Class GuiNovelTree
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index d3e36e90..71d99e33 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -1582,30 +1582,30 @@ class GuiMain(QMainWindow):
return
@pyqtSlot(int)
- def _mainStackChanged(self, tabIndex):
+ def _mainStackChanged(self, stIndex):
"""Activated when the main window tab is changed.
"""
- if tabIndex == self.idxEditorView:
- logger.verbose("Editor tab activated")
- elif tabIndex == self.idxOutlineView:
- logger.verbose("Project outline tab activated")
+ if stIndex == self.idxEditorView:
+ logger.verbose("Editor View activated")
+ elif stIndex == self.idxOutlineView:
+ logger.verbose("Outline View activated")
if self.hasProject:
self.outlineView.refreshView()
return
@pyqtSlot(int)
- def _projStackChanged(self, tabIndex):
+ def _projStackChanged(self, stIndex):
"""Activated when the project view tab is changed.
"""
sHandle = None
- if tabIndex == self.idxProjView:
- logger.verbose("Project tree tab activated")
+ if stIndex == self.idxProjView:
+ logger.verbose("Project Tree View activated")
sHandle = self.projView.getSelectedHandle()
- elif tabIndex == self.idxNovelView:
- logger.verbose("Novel tree tab activated")
+ elif stIndex == self.idxNovelView:
+ logger.verbose("Novel Tree View activated")
if self.hasProject:
self.novelView.refreshTree()
sHandle, _ = self.novelView.getSelectedHandle()
From 538b722bdf7750921df9668d2e2ab40ba2c98b09 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Tue, 14 Jun 2022 19:33:12 +0200
Subject: [PATCH 30/35] Fix tests and a few other bits
---
novelwriter/gui/doceditor.py | 2 +
novelwriter/gui/noveltree.py | 1 -
sample/content/a520879ca0b45.nwd | 2 +-
sample/content/edca4be2fcaf8.nwd | 2 +-
tests/test_core/test_core_project.py | 2 +-
tests/test_gui/test_gui_guimain.py | 12 ++---
tests/test_gui/test_gui_noveltree.py | 66 +++++-----------------------
7 files changed, 22 insertions(+), 65 deletions(-)
diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py
index 25552037..0d32689e 100644
--- a/novelwriter/gui/doceditor.py
+++ b/novelwriter/gui/doceditor.py
@@ -511,11 +511,13 @@ class GuiDocEditor(QTextEdit):
self.theProject.index.scanText(tHandle, docText)
newHeader = self.theProject.index.getHandleHeaderLevel(tHandle)
+ # ToDo: This should be a signal
if self._updateHeaders(checkLevel=True):
self.mainGui.requestNovelTreeRefresh()
else:
self.mainGui.novelView.updateWordCounts(tHandle)
+ # ToDo: This should be a signal
if oldHeader != newHeader:
self.mainGui.projView.setTreeItemValues(tHandle)
self.mainGui.itemDetails.updateViewBox(tHandle)
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index 33981243..336058a5 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -254,7 +254,6 @@ class GuiNovelToolBar(QWidget):
"""Build the novel root menu.
"""
self.mRoot.clear()
-
agRoot = QActionGroup(self.mRoot)
for n, (tHandle, nwItem) in enumerate(self.theProject.tree.iterRoots(nwItemClass.NOVEL)):
aRoot = self.mRoot.addAction(nwItem.itemName)
diff --git a/sample/content/a520879ca0b45.nwd b/sample/content/a520879ca0b45.nwd
index 12d7a62a..75ba39c8 100644
--- a/sample/content/a520879ca0b45.nwd
+++ b/sample/content/a520879ca0b45.nwd
@@ -1,7 +1,7 @@
%%~name: Chapter One
%%~path: e5e47ebf63b1c/a520879ca0b45
%%~kind: NOVEL/DOCUMENT
-### Chapter One
+## Chapter One
@pov: Jane
diff --git a/sample/content/edca4be2fcaf8.nwd b/sample/content/edca4be2fcaf8.nwd
index 3028b3fd..8b3efc78 100644
--- a/sample/content/edca4be2fcaf8.nwd
+++ b/sample/content/edca4be2fcaf8.nwd
@@ -3,4 +3,4 @@
%%~kind: NOVEL/DOCUMENT
# Part One
->> In the beginning … <<
\ No newline at end of file
+>> In the beginning … <<
diff --git a/tests/test_core/test_core_project.py b/tests/test_core/test_core_project.py
index bdc27771..a6409b98 100644
--- a/tests/test_core/test_core_project.py
+++ b/tests/test_core/test_core_project.py
@@ -470,7 +470,7 @@ def testCoreProject_Open(monkeypatch, nwMinimal, mockGUI):
writeFile(os.path.join(nwMinimal, "data_0", "123456789abc_main.bak"), "stuff")
mockGUI.clear()
assert theProject.openProject(nwMinimal) is True
- assert "version 1.0" in mockGUI.lastAlert
+ assert "There was an error updating the project." in mockGUI.lastAlert
assert theProject.closeProject()
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index b197885e..c308451b 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -29,7 +29,7 @@ from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMessageBox, QInputDialog
from novelwriter.gui import GuiDocEditor, GuiNovelView, GuiOutlineView
-from novelwriter.enum import nwItemType, nwWidget
+from novelwriter.enum import nwItemType, nwView, nwWidget
from novelwriter.tools import GuiProjectWizard
from novelwriter.gui.projtree import GuiProjectTree
from novelwriter.dialogs import GuiEditLabel
@@ -120,6 +120,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
assert nwGUI.openSelectedItem() is False
# Project Tree has focus
+ nwGUI._changeView(nwView.PROJECT)
nwGUI.switchFocus(nwWidget.TREE)
nwGUI.projStack.setCurrentIndex(0)
with monkeypatch.context() as mp:
@@ -131,20 +132,19 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
assert nwGUI.closeDocument() is True
# Novel Tree has focus
- nwGUI.projStack.setCurrentIndex(1)
+ nwGUI._changeView(nwView.NOVEL)
nwGUI.novelView.refreshTree(rootHandle=None, overRide=True)
with monkeypatch.context() as mp:
mp.setattr(GuiNovelView, "treeFocus", lambda *a: True)
assert nwGUI.docEditor.docHandle() is None
- actItem = nwGUI.novelView.novelTree.topLevelItem(0)
- chpItem = actItem.child(0)
- selItem = chpItem.child(0)
+ selItem = nwGUI.novelView.novelTree.topLevelItem(2)
nwGUI.novelView.novelTree.setCurrentItem(selItem)
nwGUI._keyPressReturn()
assert nwGUI.docEditor.docHandle() == sHandle
assert nwGUI.closeDocument() is True
# Project Outline has focus
+ nwGUI._changeView(nwView.OUTLINE)
nwGUI.switchFocus(nwWidget.OUTLINE)
with monkeypatch.context() as mp:
mp.setattr(GuiOutlineView, "treeFocus", lambda *a: True)
@@ -157,7 +157,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
assert nwGUI.docEditor.docHandle() == sHandle
assert nwGUI.closeDocument() is True
- # qtbot.stopForInteraction()
+ # qtbot.stop()
# END Test testGuiMain_ProjectTreeItems
diff --git a/tests/test_gui/test_gui_noveltree.py b/tests/test_gui/test_gui_noveltree.py
index b1e223cf..ea8b49bc 100644
--- a/tests/test_gui/test_gui_noveltree.py
+++ b/tests/test_gui/test_gui_noveltree.py
@@ -20,9 +20,6 @@ along with this program. If not, see .
"""
import pytest
-import os
-
-from tools import writeFile
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMessageBox
@@ -40,9 +37,8 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
novelView = nwGUI.novelView
novelTree = novelView.novelTree
- ##
- # Show/Hide Scrollbars
- ##
+ # Show/Hide Scrollbars
+ # ====================
nwGUI.mainConf.hideVScroll = True
nwGUI.mainConf.hideHScroll = True
@@ -56,14 +52,13 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
assert novelTree.verticalScrollBar().isEnabled()
assert novelTree.horizontalScrollBar().isEnabled()
- ##
- # Populate Tree
- ##
+ # Populate Tree
+ # =============
nwGUI.projStack.setCurrentIndex(nwGUI.idxNovelView)
nwGUI.rebuildIndex()
novelTree._populateTree(rootHandle=None)
- assert novelTree.topLevelItemCount() == 1
+ assert novelTree.topLevelItemCount() == 3
# Rebuild should preserve selection
topItem = novelTree.topLevelItem(0)
@@ -75,13 +70,12 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
novelView.refreshTree()
assert novelTree.topLevelItem(0).isSelected()
- ##
- # Open Items
- ##
+ # Open Items
+ # ==========
# Clear selection
novelTree.clearSelection()
- scItem = novelTree.topLevelItem(0).child(0).child(0)
+ scItem = novelTree.topLevelItem(2)
scItem.setSelected(True)
assert scItem.isSelected()
@@ -114,48 +108,10 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
qtbot.mouseClick(vPort, Qt.MiddleButton, pos=scRect.center(), delay=10)
assert nwGUI.docViewer.docHandle() == "8c659a11cd429"
- ##
- # Populate Tree
- ##
+ # Close
+ # =====
- # Add weird titles to first file to check hnadling of non-standard
- # order of title levels.
- writeFile(os.path.join(nwMinimal, "content", "a35baf2e93843.nwd"), (
- "#### Section wo/Scene\n\n"
- "### Scene wo/Chapter\n\n"
- "## Chapter wo/Title\n\n"
- "# Title\n\n"
- "#### Section w/Title, wo/Scene\n\n"
- "### Scene w/Title, wo/Chapter\n\n"
- "## Chapter\n\n"
- "#### Section w/Chapter, wo/Scene\n\n"
- "### Scene\n\n"
- "#### Section\n\n"
- ))
- nwGUI.rebuildIndex()
- novelTree._populateTree(None)
- 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 = 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(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(novelTree.C_TITLE) == "Section"
-
- ##
- # Close
- ##
-
- # qtbot.stopForInteraction()
+ # qtbot.stop()
nwGUI.closeProject()
# END Test testGuiNovelTree_TreeItems
From 3a061eec3f43f8c253faf2864c1f365efa65045e Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Wed, 15 Jun 2022 16:14:28 +0200
Subject: [PATCH 31/35] Update novel tree menu processing and fix issue with
reaload of document
---
novelwriter/gui/noveltree.py | 159 +++++++++++++++++------------
novelwriter/gui/outline.py | 2 +-
novelwriter/gui/projtree.py | 29 ++----
novelwriter/guimain.py | 6 +-
tests/test_gui/test_gui_guimain.py | 4 +-
tests/test_gui/test_gui_outline.py | 2 +-
6 files changed, 110 insertions(+), 92 deletions(-)
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index 336058a5..2332bc7c 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -28,11 +28,11 @@ along with this program. If not, see .
import logging
import novelwriter
-from time import time
from enum import Enum
+from time import time
-from PyQt5.QtCore import Qt, QSize, pyqtSlot, pyqtSignal
from PyQt5.QtGui import QPalette, QPixmap, QColor
+from PyQt5.QtCore import Qt, QSize, pyqtSlot, pyqtSignal
from PyQt5.QtWidgets import (
QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView, QLabel,
QMenu, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
@@ -81,13 +81,7 @@ class GuiNovelView(QWidget):
self.setLayout(self.outerBox)
- # Connect Signals
- self.novelBar.rootFolderSelectionChanged.connect(
- lambda tHandle: self.novelTree.refreshTree(rootHandle=tHandle, overRide=True)
- )
-
# Function Mappings
- self.refreshTree = self.novelTree.refreshTree
self.updateWordCounts = self.novelTree.updateWordCounts
self.getSelectedHandle = self.novelTree.getSelectedHandle
@@ -101,30 +95,44 @@ class GuiNovelView(QWidget):
self.novelTree.initSettings()
return
+ def refreshTree(self):
+ """Refresh the current tree.
+ """
+ self.novelTree.refreshTree(rootHandle=self.theProject.lastNovel)
+ return
+
def clearProject(self):
- self.novelTree.clearTree()
+ """Clear project-related GUI content.
+ """
+ self.novelTree.clearContent()
+ self.novelBar.clearContent()
return
def openProjectTasks(self):
- """Run tasks when opening a project.
+ """Run opening project tasks.
"""
lastNovel = self.theProject.lastNovel
- if lastNovel is None:
+ if lastNovel not in self.theProject.tree:
lastNovel = self.theProject.tree.findRoot(nwItemClass.NOVEL)
logger.debug("Setting novel tree to root item '%s'", lastNovel)
+ lastCol = self.theProject.options.getEnum(
+ "GuiNovelView", "lastCol", NovelTreeColumn, NovelTreeColumn.HIDDEN
+ )
+
self.clearProject()
- self.novelBar.rebuildNovelRootMenu(selHandle=lastNovel)
- self.novelTree.loadOptions()
- self.novelTree.refreshTree(rootHandle=lastNovel, overRide=True)
+ self.novelBar.buildNovelRootMenu()
+ self.novelBar.setLastColType(lastCol, doRefresh=False)
+ self.novelBar.setCurrentRoot(lastNovel)
return
def closeProjectTasks(self):
- """Run tasks when closing a project.
+ """Run closing project tasks.
"""
- self.novelTree.saveOptions()
+ lastColType = self.novelTree.lastColType
+ self.theProject.options.setValue("GuiNovelView", "lastCol", lastColType)
return
def setFocus(self):
@@ -133,7 +141,7 @@ class GuiNovelView(QWidget):
self.novelTree.setFocus()
return
- def treeFocus(self):
+ def treeHasFocus(self):
"""Check if the novel tree has focus.
"""
return self.novelTree.hasFocus()
@@ -144,9 +152,9 @@ class GuiNovelView(QWidget):
@pyqtSlot(str)
def updateRootItem(self, tHandle):
- """Should be called whenever a root folders changes.
+ """If any root item changes, rebuild the novel root menu.
"""
- self.novelBar.rebuildNovelRootMenu()
+ self.novelBar.buildNovelRootMenu()
return
# END Class GuiNovelView
@@ -154,8 +162,6 @@ class GuiNovelView(QWidget):
class GuiNovelToolBar(QWidget):
- rootFolderSelectionChanged = pyqtSignal(str)
-
def __init__(self, novelView):
QTreeWidget.__init__(self, novelView)
@@ -167,7 +173,7 @@ class GuiNovelToolBar(QWidget):
self.mainTheme = novelView.mainGui.mainTheme
iPx = self.mainTheme.baseIconSize
- mPx = self.mainConf.pxInt(4)
+ mPx = self.mainConf.pxInt(3)
self.setContentsMargins(0, 0, 0, 0)
self.setAutoFillBackground(True)
@@ -197,6 +203,8 @@ class GuiNovelToolBar(QWidget):
# Novel Root Menu
self.mRoot = QMenu()
+ self.gRoot = QActionGroup(self.mRoot)
+ self.aRoot = {}
self.tbRoot = QToolButton(self)
self.tbRoot.setToolTip(self.tr("Novel Root"))
@@ -209,19 +217,13 @@ class GuiNovelToolBar(QWidget):
# More Options Menu
self.mMore = QMenu()
- self.mCol3 = self.mMore.addMenu(self.tr("Third Column"))
- self.mCol3.addAction(self.tr("Hide Column")).triggered.connect(
- lambda: self.novelView.novelTree.setLastColType(NovelTreeColumn.HIDDEN)
- )
- self.mCol3.addAction(self.tr("Point of View Character")).triggered.connect(
- lambda: self.novelView.novelTree.setLastColType(NovelTreeColumn.POV)
- )
- self.mCol3.addAction(self.tr("Focus Character")).triggered.connect(
- lambda: self.novelView.novelTree.setLastColType(NovelTreeColumn.FOCUS)
- )
- self.mCol3.addAction(self.tr("Novel Plot")).triggered.connect(
- lambda: self.novelView.novelTree.setLastColType(NovelTreeColumn.PLOT)
- )
+ self.mLastCol = self.mMore.addMenu(self.tr("Last Column"))
+ self.gLastCol = QActionGroup(self.mMore)
+ self.aLastCol = {}
+ self._addLastColAction(NovelTreeColumn.HIDDEN, self.tr("Hidden"))
+ self._addLastColAction(NovelTreeColumn.POV, self.tr("Point of View Character"))
+ self._addLastColAction(NovelTreeColumn.FOCUS, self.tr("Focus Character"))
+ self._addLastColAction(NovelTreeColumn.PLOT, self.tr("Novel Plot"))
self.tbMore = QToolButton(self)
self.tbMore.setToolTip(self.tr("More Options"))
@@ -250,25 +252,41 @@ class GuiNovelToolBar(QWidget):
# Methods
##
- def rebuildNovelRootMenu(self, selHandle=None):
+ def clearContent(self):
+ """Run clearing project tasks.
+ """
+ self.mRoot.clear()
+ self.aRoot = {}
+ return
+
+ def buildNovelRootMenu(self):
"""Build the novel root menu.
"""
self.mRoot.clear()
- agRoot = QActionGroup(self.mRoot)
+ self.aRoot = {}
for n, (tHandle, nwItem) in enumerate(self.theProject.tree.iterRoots(nwItemClass.NOVEL)):
aRoot = self.mRoot.addAction(nwItem.itemName)
aRoot.setData(tHandle)
aRoot.setCheckable(True)
- aRoot.triggered.connect(
- lambda n, tHandle=tHandle: self.rootFolderSelectionChanged.emit(tHandle)
- )
- agRoot.addAction(aRoot)
+ aRoot.triggered.connect(lambda n, tHandle=tHandle: self.setCurrentRoot(tHandle))
+ self.gRoot.addAction(aRoot)
+ self.aRoot[tHandle] = aRoot
- if n == 0:
- aRoot.setChecked(True)
- if selHandle == tHandle:
- aRoot.setChecked(True)
+ return
+ def setCurrentRoot(self, rootHandle):
+ """Set the current active root handle.
+ """
+ if rootHandle in self.aRoot:
+ self.aRoot[rootHandle].setChecked(True)
+ self.novelView.novelTree.refreshTree(rootHandle=rootHandle, overRide=True)
+ return
+
+ def setLastColType(self, colType, doRefresh=True):
+ """Set the last column type.
+ """
+ self.aLastCol[colType].setChecked(True)
+ self.novelView.novelTree.setLastColType(colType, doRefresh=doRefresh)
return
##
@@ -283,6 +301,20 @@ class GuiNovelToolBar(QWidget):
self.novelView.novelTree.refreshTree(rootHandle=rootHandle, overRide=True)
return
+ ##
+ # Internal Functions
+ ##
+
+ def _addLastColAction(self, colType, actionLabel):
+ """Add a column selection entry to the last column menu.
+ """
+ aLast = self.mLastCol.addAction(actionLabel)
+ aLast.setCheckable(True)
+ aLast.setActionGroup(self.gLastCol)
+ aLast.triggered.connect(lambda: self.setLastColType(colType))
+ self.aLastCol[colType] = aLast
+ return
+
# END Class GuiNovelToolBar
@@ -319,13 +351,12 @@ class GuiNovelTree(QTreeWidget):
iPx = self.mainTheme.baseIconSize
nPx = self.mainTheme.textNWidth
cMg = self.mainConf.pxInt(6)
- mPx = self.mainConf.pxInt(4)
nMg = self.mainConf.pxInt(6)
# self.setIconSize(QSize(iPx, iPx))
self.setFrameStyle(QFrame.NoFrame)
self.setHeaderHidden(True)
- self.setIndentation(mPx)
+ self.setIndentation(0)
self.setColumnCount(3)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSelectionMode(QAbstractItemView.SingleSelection)
@@ -349,7 +380,7 @@ class GuiNovelTree(QTreeWidget):
fH2.setBold(True)
self._hFonts = [self.font(), fH1, fH2, self.font(), self.font()]
- self._hIndent = ["", "", "", "\u2022\u00a0", "\u00bb\u00a0"]
+ self._hIndent = ["", "", "", "\u203a\u00a0", "\u00bb\u00a0"]
self._pIndent = [QPixmap(), QPixmap()]
hPix = QPixmap(QSize(iPx, iPx))
@@ -386,11 +417,19 @@ class GuiNovelTree(QTreeWidget):
return
+ ##
+ # Properties
+ ##
+
+ @property
+ def lastColType(self):
+ return self._lastCol
+
##
# Class Methods
##
- def clearTree(self):
+ def clearContent(self):
"""Clear the GUI content and the related maps.
"""
self.clear()
@@ -398,21 +437,6 @@ class GuiNovelTree(QTreeWidget):
self._lastBuild = 0
return
- def loadOptions(self):
- """Load user options.
- """
- self._lastCol = self.theProject.options.getEnum(
- "GuiNovelView", "lastCol", NovelTreeColumn, NovelTreeColumn.POV
- )
- self.setColumnHidden(self.C_LAST, self._lastCol == NovelTreeColumn.HIDDEN)
- return True
-
- def saveOptions(self):
- """Save user options.
- """
- self.theProject.options.setValue("GuiNovelView", "lastCol", self._lastCol)
- return
-
def refreshTree(self, rootHandle=None, overRide=False):
"""Called whenever the Novel tab is activated.
"""
@@ -461,14 +485,15 @@ class GuiNovelTree(QTreeWidget):
return tHandle, tLine
- def setLastColType(self, colType):
+ def setLastColType(self, colType, doRefresh=True):
"""Change the content type of the last column and rebuild.
"""
if self._lastCol != colType:
logger.debug("Changing last column to %s", colType.name)
self._lastCol = colType
self.setColumnHidden(self.C_LAST, colType == NovelTreeColumn.HIDDEN)
- self.refreshTree(rootHandle=self.theProject.lastNovel, overRide=True)
+ if doRefresh:
+ self.refreshTree(rootHandle=self.theProject.lastNovel, overRide=True)
return
##
@@ -531,7 +556,7 @@ class GuiNovelTree(QTreeWidget):
def _populateTree(self, rootHandle):
"""Build the tree based on the project index.
"""
- self.clearTree()
+ self.clearContent()
tStart = time()
logger.verbose("Building novel tree for root item '%s'", rootHandle)
diff --git a/novelwriter/gui/outline.py b/novelwriter/gui/outline.py
index c858c480..4b2077f6 100644
--- a/novelwriter/gui/outline.py
+++ b/novelwriter/gui/outline.py
@@ -117,7 +117,7 @@ class GuiOutlineView(QWidget):
self.outlineTree.refreshTree(overRide=overRide, novelChanged=novelChanged)
return
- def treeFocus(self):
+ def treeHasFocus(self):
return self.outlineTree.hasFocus()
def setTreeFocus(self):
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index 4f320bfc..08b24232 100644
--- a/novelwriter/gui/projtree.py
+++ b/novelwriter/gui/projtree.py
@@ -31,8 +31,8 @@ import novelwriter
from enum import Enum
from time import time
+from PyQt5.QtGui import QPalette
from PyQt5.QtCore import Qt, QSize, pyqtSignal, pyqtSlot
-from PyQt5.QtGui import QIcon, QPalette
from PyQt5.QtWidgets import (
QAbstractItemView, QFrame, QHBoxLayout, QHeaderView, QLabel,
QMenu, QShortcut, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem,
@@ -142,7 +142,7 @@ class GuiProjectView(QWidget):
self.projTree.setFocus()
return
- def treeFocus(self):
+ def treeHasFocus(self):
"""Check if the project tree has focus.
"""
return self.projTree.hasFocus()
@@ -177,7 +177,7 @@ class GuiProjectToolBar(QWidget):
self.mainTheme = projView.mainGui.mainTheme
iPx = self.mainTheme.baseIconSize
- mPx = self.mainConf.pxInt(4)
+ mPx = self.mainConf.pxInt(3)
self.setContentsMargins(0, 0, 0, 0)
self.setAutoFillBackground(True)
@@ -252,7 +252,7 @@ class GuiProjectToolBar(QWidget):
self._addRootFolderEntry(nwItemClass.PLOT)
self._addRootFolderEntry(nwItemClass.CHARACTER)
self._addRootFolderEntry(nwItemClass.WORLD)
- self._addRootFolderEntry(nwItemClass.ARCHIVE)
+ self._addRootFolderEntry(nwItemClass.TIMELINE)
self._addRootFolderEntry(nwItemClass.OBJECT)
self._addRootFolderEntry(nwItemClass.ENTITY)
self._addRootFolderEntry(nwItemClass.CUSTOM)
@@ -778,13 +778,6 @@ class GuiProjectTree(QTreeWidget):
if trItem is None or nwItem is None:
return
- expIcon = QIcon()
- if nwItem.itemType == nwItemType.FILE:
- if nwItem.isExported:
- expIcon = self.mainTheme.getIcon("check")
- else:
- expIcon = self.mainTheme.getIcon("cross")
-
itemStatus, statusIcon = nwItem.getImportStatus()
hLevel = self.theProject.index.getHandleHeaderLevel(tHandle)
itemIcon = self.mainTheme.getItemIcon(
@@ -793,18 +786,18 @@ class GuiProjectTree(QTreeWidget):
trItem.setIcon(self.C_NAME, itemIcon)
trItem.setText(self.C_NAME, nwItem.itemName)
- trItem.setIcon(self.C_EXPORT, expIcon)
trItem.setIcon(self.C_STATUS, statusIcon)
trItem.setToolTip(self.C_STATUS, itemStatus)
+ if nwItem.itemType == nwItemType.FILE:
+ trItem.setIcon(
+ self.C_EXPORT, self.mainTheme.getIcon("check" if nwItem.isExported else "cross")
+ )
+
if self.mainConf.emphLabels and nwItem.itemLayout == nwItemLayout.DOCUMENT:
trFont = trItem.font(self.C_NAME)
- if hLevel in ("H1", "H2"):
- trFont.setBold(True)
- trFont.setUnderline(True)
- else:
- trFont.setBold(False)
- trFont.setUnderline(False)
+ trFont.setBold(hLevel == "H1" or hLevel == "H2")
+ trFont.setUnderline(hLevel == "H1")
trItem.setFont(self.C_NAME, trFont)
return
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 71d99e33..5030347b 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -796,11 +796,11 @@ class GuiMain(QMainWindow):
tHandle = None
tLine = None
- if self.projView.treeFocus():
+ if self.projView.treeHasFocus():
tHandle = self.projView.getSelectedHandle()
- elif self.novelView.treeFocus():
+ elif self.novelView.treeHasFocus():
tHandle, tLine = self.novelView.getSelectedHandle()
- elif self.outlineView.treeFocus():
+ elif self.outlineView.treeHasFocus():
tHandle, tLine = self.outlineView.getSelectedHandle()
else:
logger.warning("No item selected")
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index c308451b..5637f5c1 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -135,7 +135,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
nwGUI._changeView(nwView.NOVEL)
nwGUI.novelView.refreshTree(rootHandle=None, overRide=True)
with monkeypatch.context() as mp:
- mp.setattr(GuiNovelView, "treeFocus", lambda *a: True)
+ mp.setattr(GuiNovelView, "treeHasFocus", lambda *a: True)
assert nwGUI.docEditor.docHandle() is None
selItem = nwGUI.novelView.novelTree.topLevelItem(2)
nwGUI.novelView.novelTree.setCurrentItem(selItem)
@@ -147,7 +147,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
nwGUI._changeView(nwView.OUTLINE)
nwGUI.switchFocus(nwWidget.OUTLINE)
with monkeypatch.context() as mp:
- mp.setattr(GuiOutlineView, "treeFocus", lambda *a: True)
+ mp.setattr(GuiOutlineView, "treeHasFocus", lambda *a: True)
assert nwGUI.docEditor.docHandle() is None
actItem = nwGUI.outlineView.outlineTree.topLevelItem(0)
chpItem = actItem.child(0)
diff --git a/tests/test_gui/test_gui_outline.py b/tests/test_gui/test_gui_outline.py
index 1038404a..26ca9803 100644
--- a/tests/test_gui/test_gui_outline.py
+++ b/tests/test_gui/test_gui_outline.py
@@ -71,7 +71,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, fncDir):
# Check focus
with monkeypatch.context() as mp:
mp.setattr(QWidget, "hasFocus", lambda *a: True)
- assert outlineView.treeFocus() is True
+ assert outlineView.treeHasFocus() is True
outlineView.setTreeFocus() # Can't check. just ensures that it doesn't error
From cff464392ae5656eb9fd1d117c161ad781517b25 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Wed, 15 Jun 2022 16:15:29 +0200
Subject: [PATCH 32/35] Use the indenta decorators of the novel tree to
indicate type
---
.../assets/icons/typicons_dark/icons.conf | 5 +++
.../assets/icons/typicons_dark/nw_deco-h0.svg | 35 +++++++++++++++++++
.../assets/icons/typicons_dark/nw_deco-h1.svg | 35 +++++++++++++++++++
.../assets/icons/typicons_dark/nw_deco-h2.svg | 35 +++++++++++++++++++
.../assets/icons/typicons_dark/nw_deco-h3.svg | 35 +++++++++++++++++++
.../assets/icons/typicons_dark/nw_deco-h4.svg | 35 +++++++++++++++++++
.../assets/icons/typicons_light/icons.conf | 5 +++
.../icons/typicons_light/nw_deco-h0.svg | 35 +++++++++++++++++++
.../icons/typicons_light/nw_deco-h1.svg | 35 +++++++++++++++++++
.../icons/typicons_light/nw_deco-h2.svg | 35 +++++++++++++++++++
.../icons/typicons_light/nw_deco-h3.svg | 35 +++++++++++++++++++
.../icons/typicons_light/nw_deco-h4.svg | 35 +++++++++++++++++++
novelwriter/gui/noveltree.py | 24 ++++++-------
novelwriter/gui/theme.py | 22 +++++++-----
sample/nwProject.nwx | 16 ++++-----
tests/test_gui/test_gui_theme.py | 2 +-
16 files changed, 393 insertions(+), 31 deletions(-)
create mode 100644 novelwriter/assets/icons/typicons_dark/nw_deco-h0.svg
create mode 100644 novelwriter/assets/icons/typicons_dark/nw_deco-h1.svg
create mode 100644 novelwriter/assets/icons/typicons_dark/nw_deco-h2.svg
create mode 100644 novelwriter/assets/icons/typicons_dark/nw_deco-h3.svg
create mode 100644 novelwriter/assets/icons/typicons_dark/nw_deco-h4.svg
create mode 100644 novelwriter/assets/icons/typicons_light/nw_deco-h0.svg
create mode 100644 novelwriter/assets/icons/typicons_light/nw_deco-h1.svg
create mode 100644 novelwriter/assets/icons/typicons_light/nw_deco-h2.svg
create mode 100644 novelwriter/assets/icons/typicons_light/nw_deco-h3.svg
create mode 100644 novelwriter/assets/icons/typicons_light/nw_deco-h4.svg
diff --git a/novelwriter/assets/icons/typicons_dark/icons.conf b/novelwriter/assets/icons/typicons_dark/icons.conf
index ae157e2c..d4106803 100644
--- a/novelwriter/assets/icons/typicons_dark/icons.conf
+++ b/novelwriter/assets/icons/typicons_dark/icons.conf
@@ -83,3 +83,8 @@ view_build = typ_export.svg
view_editor = mixed_edit.svg
view_novel = typ_book-grey.svg
view_outline = typ_puzzle-outline.svg
+
+deco_doc_h1 = nw_deco-h1.svg
+deco_doc_h2 = nw_deco-h2.svg
+deco_doc_h3 = nw_deco-h3.svg
+deco_doc_h4 = nw_deco-h4.svg
diff --git a/novelwriter/assets/icons/typicons_dark/nw_deco-h0.svg b/novelwriter/assets/icons/typicons_dark/nw_deco-h0.svg
new file mode 100644
index 00000000..3c1618c9
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_dark/nw_deco-h0.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_dark/nw_deco-h1.svg b/novelwriter/assets/icons/typicons_dark/nw_deco-h1.svg
new file mode 100644
index 00000000..1c0dec9b
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_dark/nw_deco-h1.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_dark/nw_deco-h2.svg b/novelwriter/assets/icons/typicons_dark/nw_deco-h2.svg
new file mode 100644
index 00000000..0f86e5bb
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_dark/nw_deco-h2.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_dark/nw_deco-h3.svg b/novelwriter/assets/icons/typicons_dark/nw_deco-h3.svg
new file mode 100644
index 00000000..f05e46e6
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_dark/nw_deco-h3.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_dark/nw_deco-h4.svg b/novelwriter/assets/icons/typicons_dark/nw_deco-h4.svg
new file mode 100644
index 00000000..aa74e6f3
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_dark/nw_deco-h4.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_light/icons.conf b/novelwriter/assets/icons/typicons_light/icons.conf
index 4683bb19..8d267a47 100644
--- a/novelwriter/assets/icons/typicons_light/icons.conf
+++ b/novelwriter/assets/icons/typicons_light/icons.conf
@@ -83,3 +83,8 @@ view_build = typ_export.svg
view_editor = mixed_edit.svg
view_novel = typ_book-grey.svg
view_outline = typ_puzzle-outline.svg
+
+deco_doc_h1 = nw_deco-h1.svg
+deco_doc_h2 = nw_deco-h2.svg
+deco_doc_h3 = nw_deco-h3.svg
+deco_doc_h4 = nw_deco-h4.svg
diff --git a/novelwriter/assets/icons/typicons_light/nw_deco-h0.svg b/novelwriter/assets/icons/typicons_light/nw_deco-h0.svg
new file mode 100644
index 00000000..3c1618c9
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_light/nw_deco-h0.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_light/nw_deco-h1.svg b/novelwriter/assets/icons/typicons_light/nw_deco-h1.svg
new file mode 100644
index 00000000..e6c8efdc
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_light/nw_deco-h1.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_light/nw_deco-h2.svg b/novelwriter/assets/icons/typicons_light/nw_deco-h2.svg
new file mode 100644
index 00000000..7caa4203
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_light/nw_deco-h2.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_light/nw_deco-h3.svg b/novelwriter/assets/icons/typicons_light/nw_deco-h3.svg
new file mode 100644
index 00000000..61feca1b
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_light/nw_deco-h3.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/novelwriter/assets/icons/typicons_light/nw_deco-h4.svg b/novelwriter/assets/icons/typicons_light/nw_deco-h4.svg
new file mode 100644
index 00000000..b76fd7da
--- /dev/null
+++ b/novelwriter/assets/icons/typicons_light/nw_deco-h4.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/novelwriter/gui/noveltree.py b/novelwriter/gui/noveltree.py
index 2332bc7c..8711dc8d 100644
--- a/novelwriter/gui/noveltree.py
+++ b/novelwriter/gui/noveltree.py
@@ -31,7 +31,7 @@ import novelwriter
from enum import Enum
from time import time
-from PyQt5.QtGui import QPalette, QPixmap, QColor
+from PyQt5.QtGui import QPalette
from PyQt5.QtCore import Qt, QSize, pyqtSlot, pyqtSignal
from PyQt5.QtWidgets import (
QAbstractItemView, QActionGroup, QFrame, QHBoxLayout, QHeaderView, QLabel,
@@ -349,11 +349,9 @@ class GuiNovelTree(QTreeWidget):
# =========
iPx = self.mainTheme.baseIconSize
- nPx = self.mainTheme.textNWidth
cMg = self.mainConf.pxInt(6)
- nMg = self.mainConf.pxInt(6)
- # self.setIconSize(QSize(iPx, iPx))
+ self.setIconSize(QSize(iPx, iPx))
self.setFrameStyle(QFrame.NoFrame)
self.setHeaderHidden(True)
self.setIndentation(0)
@@ -380,15 +378,13 @@ class GuiNovelTree(QTreeWidget):
fH2.setBold(True)
self._hFonts = [self.font(), fH1, fH2, self.font(), self.font()]
- self._hIndent = ["", "", "", "\u203a\u00a0", "\u00bb\u00a0"]
- self._pIndent = [QPixmap(), QPixmap()]
-
- hPix = QPixmap(QSize(iPx, iPx))
- hPix.fill(QColor(0, 0, 0, 0))
- for m in range(1, 4):
- self._pIndent.append(hPix.scaled(
- max(nPx*m - nMg, nMg), 2, Qt.IgnoreAspectRatio, Qt.FastTransformation
- ))
+ self._pIndent = [
+ self.mainTheme.loadDecoration("deco_doc_h0", pxH=iPx),
+ self.mainTheme.loadDecoration("deco_doc_h1", pxH=iPx),
+ self.mainTheme.loadDecoration("deco_doc_h2", pxH=iPx),
+ self.mainTheme.loadDecoration("deco_doc_h3", pxH=iPx),
+ self.mainTheme.loadDecoration("deco_doc_h4", pxH=iPx),
+ ]
# Connect signals
self.itemDoubleClicked.connect(self._treeDoubleClick)
@@ -571,7 +567,7 @@ class GuiNovelTree(QTreeWidget):
theData = (tHandle, sTitle[1:].lstrip("0"), tKey)
newItem.setData(self.C_TITLE, Qt.DecorationRole, self._pIndent[iLevel])
- newItem.setText(self.C_TITLE, self._hIndent[iLevel] + novIdx.title)
+ newItem.setText(self.C_TITLE, novIdx.title)
newItem.setData(self.C_TITLE, Qt.UserRole, theData)
newItem.setFont(self.C_TITLE, self._hFonts[iLevel])
newItem.setText(self.C_WORDS, f"{novIdx.wordCount:n}")
diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py
index 3a59e7e2..6c4ff50e 100644
--- a/novelwriter/gui/theme.py
+++ b/novelwriter/gui/theme.py
@@ -472,9 +472,12 @@ class GuiIcons:
# Switches
"sticky-on", "sticky-off",
"bullet-on", "bullet-off",
+
+ # Decorations
+ "deco_doc_h0", "deco_doc_h1", "deco_doc_h2", "deco_doc_h3", "deco_doc_h4",
}
- DECO_MAP = {
+ IMAGE_MAP = {
"wiz-back": "wizard-back.jpg",
}
@@ -573,19 +576,22 @@ class GuiIcons:
# Access Functions
##
- def loadDecoration(self, decoKey, pxW, pxH):
+ def loadDecoration(self, decoKey, pxW=None, pxH=None):
"""Load graphical decoration element based on the decoration
- map. This function always returns a QSwgWidget.
+ map or the icon map. This function always returns a QPixmap.
"""
- if decoKey not in self.DECO_MAP:
+ if decoKey in self._themeMap:
+ imgPath = self._themeMap[decoKey]
+ elif decoKey in self.IMAGE_MAP:
+ imgPath = os.path.join(
+ self.mainConf.assetPath, "images", self.IMAGE_MAP[decoKey]
+ )
+ else:
logger.error("Decoration with name '%s' does not exist", decoKey)
return QPixmap()
- imgPath = os.path.join(
- self.mainConf.assetPath, "images", self.DECO_MAP[decoKey]
- )
if not os.path.isfile(imgPath):
- logger.error("Decoration file '%s' not in assets folder", self.DECO_MAP[decoKey])
+ logger.error("Asset '%s' not found", self.IMAGE_MAP[decoKey])
return QPixmap()
theDeco = QPixmap(imgPath)
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index af509400..6ba4b5f1 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,13 +1,13 @@
-
+
Sample Project
Sample Project
Jane Smith
Jay Doh
- 1367
- 231
- 68784
+ 1371
+ 236
+ 69222
False
@@ -35,9 +35,9 @@
- New
+ New
Notes
- Started
+ Started
1st Draft
2nd Draft
3rd Draft
@@ -92,7 +92,7 @@
Chapter Two
-
-
+
We Found John!
-
@@ -101,7 +101,7 @@
-
- Title Page
+ Title Page
-
diff --git a/tests/test_gui/test_gui_theme.py b/tests/test_gui/test_gui_theme.py
index 756b2a81..8c7b934a 100644
--- a/tests/test_gui/test_gui_theme.py
+++ b/tests/test_gui/test_gui_theme.py
@@ -127,7 +127,7 @@ def testGuiTheme_Main(qtbot, monkeypatch, nwMinimal, tmpDir):
assert anImg.isNull()
# Add a non-existent file and request it
- iconCache.DECO_MAP["nonsense"] = "nofile.jpg"
+ iconCache.IMAGE_MAP["nonsense"] = "nofile.jpg"
anImg = iconCache.loadDecoration("nonsense", 20, 20)
assert isinstance(anImg, QPixmap)
assert anImg.isNull()
From 6ccbb358b916aedff1c63b6bec92001e218ad8fc Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Wed, 15 Jun 2022 16:46:44 +0200
Subject: [PATCH 33/35] Update tests
---
tests/test_gui/test_gui_guimain.py | 2 +-
tests/test_gui/test_gui_noveltree.py | 69 +++++++++++++++++++++++++---
2 files changed, 64 insertions(+), 7 deletions(-)
diff --git a/tests/test_gui/test_gui_guimain.py b/tests/test_gui/test_gui_guimain.py
index 5637f5c1..6407b84b 100644
--- a/tests/test_gui/test_gui_guimain.py
+++ b/tests/test_gui/test_gui_guimain.py
@@ -133,7 +133,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Novel Tree has focus
nwGUI._changeView(nwView.NOVEL)
- nwGUI.novelView.refreshTree(rootHandle=None, overRide=True)
+ nwGUI.novelView.novelTree.refreshTree(rootHandle=None, overRide=True)
with monkeypatch.context() as mp:
mp.setattr(GuiNovelView, "treeHasFocus", lambda *a: True)
assert nwGUI.docEditor.docHandle() is None
diff --git a/tests/test_gui/test_gui_noveltree.py b/tests/test_gui/test_gui_noveltree.py
index ea8b49bc..102b03d2 100644
--- a/tests/test_gui/test_gui_noveltree.py
+++ b/tests/test_gui/test_gui_noveltree.py
@@ -19,23 +19,47 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
+import os
import pytest
+from tools import buildTestProject, writeFile
+
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMessageBox
+from novelwriter.enum import nwWidget, nwItemType
+from novelwriter.dialogs import GuiEditLabel
+from novelwriter.gui.noveltree import NovelTreeColumn
+
@pytest.mark.gui
-def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
+def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
"""Test navigating the novel tree.
"""
# Block message box
monkeypatch.setattr(QMessageBox, "question", lambda *a: QMessageBox.Yes)
monkeypatch.setattr(QMessageBox, "information", lambda *a: QMessageBox.Yes)
+ monkeypatch.setattr(GuiEditLabel, "getLabel", lambda *a, text: (text, True))
+
+ buildTestProject(nwGUI, fncProj)
+
+ nwGUI.switchFocus(nwWidget.TREE)
+ nwGUI.projView.projTree.clearSelection()
+ nwGUI.projView.projTree._getTreeItem("000000000000a").setSelected(True)
+ nwGUI.projView.projTree.newTreeItem(nwItemType.FILE)
+
+ writeFile(
+ os.path.join(nwGUI.theProject.projContent, "0000000000010.nwd"),
+ "# Jane Doe\n\n@tag: Jane\n\n"
+ )
+ writeFile(
+ os.path.join(nwGUI.theProject.projContent, "000000000000f.nwd"),
+ "### Scene One\n\n@pov: Jane\n@focus: Jane\n\n"
+ )
- nwGUI.openProject(nwMinimal)
novelView = nwGUI.novelView
novelTree = novelView.novelTree
+ novelBar = novelView.novelBar
# Show/Hide Scrollbars
# ====================
@@ -65,9 +89,10 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
assert not topItem.isSelected()
topItem.setSelected(True)
assert novelTree.selectedItems()[0] == topItem
- assert novelView.getSelectedHandle() == ("a35baf2e93843", 0)
+ assert novelView.getSelectedHandle() == ("000000000000c", 0)
- novelView.refreshTree()
+ # Refresh using the slot for the butoom
+ novelBar._refreshNovelTree()
assert novelTree.topLevelItem(0).isSelected()
# Open Items
@@ -89,7 +114,7 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
assert scItem.isSelected()
assert nwGUI.docEditor.docHandle() is None
novelTree._treeDoubleClick(scItem, 0)
- assert nwGUI.docEditor.docHandle() == "8c659a11cd429"
+ assert nwGUI.docEditor.docHandle() == "000000000000f"
# Open item with middle mouse button
scItem.setSelected(True)
@@ -106,7 +131,39 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
scItem.setData(novelTree.C_TITLE, Qt.UserRole, oldData)
qtbot.mouseClick(vPort, Qt.MiddleButton, pos=scRect.center(), delay=10)
- assert nwGUI.docViewer.docHandle() == "8c659a11cd429"
+ assert nwGUI.docViewer.docHandle() == "000000000000f"
+
+ # Last Column
+ # ===========
+
+ novelBar.setLastColType(NovelTreeColumn.HIDDEN)
+ assert novelTree.isColumnHidden(novelTree.C_LAST) is True
+ assert novelTree.lastColType == NovelTreeColumn.HIDDEN
+ assert novelTree._getLastColumnText("000000000000f", "T000001") == ("", "")
+
+ novelBar.setLastColType(NovelTreeColumn.POV)
+ assert novelTree.isColumnHidden(novelTree.C_LAST) is False
+ assert novelTree.lastColType == NovelTreeColumn.POV
+ assert novelTree._getLastColumnText("000000000000f", "T000001") == (
+ "Jane", "Point of View: Jane"
+ )
+
+ novelBar.setLastColType(NovelTreeColumn.FOCUS)
+ assert novelTree.isColumnHidden(novelTree.C_LAST) is False
+ assert novelTree.lastColType == NovelTreeColumn.FOCUS
+ assert novelTree._getLastColumnText("000000000000f", "T000001") == (
+ "Jane", "Focus: Jane"
+ )
+
+ novelBar.setLastColType(NovelTreeColumn.PLOT)
+ assert novelTree.isColumnHidden(novelTree.C_LAST) is False
+ assert novelTree.lastColType == NovelTreeColumn.PLOT
+ assert novelTree._getLastColumnText("000000000000f", "T000001") == (
+ "", "Plot: "
+ )
+
+ novelTree._lastCol = None
+ assert novelTree._getLastColumnText("0000000000000", "T000000") == ("", "")
# Close
# =====
From 7d7c2dba2642279d09981e76f35ccaf7d3b1edc3 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Wed, 15 Jun 2022 17:05:48 +0200
Subject: [PATCH 34/35] Resolve issue #1073
---
novelwriter/tools/build.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/novelwriter/tools/build.py b/novelwriter/tools/build.py
index 7ebed572..d852a33f 100644
--- a/novelwriter/tools/build.py
+++ b/novelwriter/tools/build.py
@@ -659,6 +659,7 @@ class GuiBuildNovel(QDialog):
fmtUnnumbered = self.fmtUnnumbered.text()
fmtScene = self.fmtScene.text()
fmtSection = self.fmtSection.text()
+ buildLang = self.buildLang.currentData()
hideScene = self.hideScene.isChecked()
hideSection = self.hideSection.isChecked()
textFont = self.textFont.text()
@@ -706,6 +707,7 @@ class GuiBuildNovel(QDialog):
if isOdt:
bldObj.setColourHeaders(not noStyling)
+ bldObj.setLanguage(buildLang)
bldObj.initDocument()
# Make sure the project and document is up to date
From ad50ad9b0d42c276babd12fc85f5965d4ea731ca Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Wed, 15 Jun 2022 17:06:18 +0200
Subject: [PATCH 35/35] Resolve issue #1085
---
novelwriter/guimain.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 8674dda1..f0aa7899 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -226,7 +226,7 @@ class GuiMain(QMainWindow):
self.splitMain.setCollapsible(self.idxTree, False)
self.splitMain.setCollapsible(self.idxMain, False)
self.splitDocs.setCollapsible(self.idxEditor, False)
- self.splitDocs.setCollapsible(self.idxViewer, True)
+ self.splitDocs.setCollapsible(self.idxViewer, False)
self.splitView.setCollapsible(self.idxViewDoc, False)
self.splitView.setCollapsible(self.idxViewMeta, False)