Add move buttons to project tree toolbar
This commit is contained in:
@@ -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."
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user