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/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/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
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/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 e7203bb9..59af7691 100644
--- a/novelwriter/gui/mainmenu.py
+++ b/novelwriter/gui/mainmenu.py
@@ -163,9 +163,9 @@ class GuiMainMenu(QMenuBar):
self.projMenu.addSeparator()
# Project > Edit
- self.aEditItem = QAction(self.tr("Edit Item"), self)
- self.aEditItem.setShortcuts(["Ctrl+E", "F2"])
- self.aEditItem.triggered.connect(lambda: self.mainGui.editItem(None))
+ self.aEditItem = QAction(self.tr("Rename Item"), self)
+ self.aEditItem.setShortcuts(["F2"])
+ self.aEditItem.triggered.connect(lambda: self.mainGui.editItemLabel(None))
self.projMenu.addAction(self.aEditItem)
# Project > Delete
diff --git a/novelwriter/gui/projtree.py b/novelwriter/gui/projtree.py
index 4c0ea59b..b9bfda0d 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__)
@@ -97,9 +97,14 @@ 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.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 +475,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 +570,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
@@ -916,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
@@ -932,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.
"""
@@ -1019,6 +1027,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 +1069,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..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:
@@ -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_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
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..5fa6951b 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
@@ -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
@@ -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..feef859d 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
@@ -510,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