Allow drag and drop to open documents
This commit is contained in:
@@ -43,8 +43,9 @@ from PyQt5.QtCore import (
|
||||
pyqtSlot
|
||||
)
|
||||
from PyQt5.QtGui import (
|
||||
QColor, QCursor, QKeyEvent, QKeySequence, QMouseEvent, QPalette, QPixmap,
|
||||
QResizeEvent, QTextBlock, QTextCursor, QTextDocument, QTextOption
|
||||
QColor, QCursor, QDragEnterEvent, QDragMoveEvent, QDropEvent, QKeyEvent,
|
||||
QKeySequence, QMouseEvent, QPalette, QPixmap, QResizeEvent, QTextBlock,
|
||||
QTextCursor, QTextDocument, QTextOption
|
||||
)
|
||||
from PyQt5.QtWidgets import (
|
||||
QAction, QApplication, QFrame, QGridLayout, QHBoxLayout, QLabel, QLineEdit,
|
||||
@@ -52,7 +53,7 @@ from PyQt5.QtWidgets import (
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.common import minmax, qtLambda, transferCase
|
||||
from novelwriter.common import decodeMimeHandles, minmax, qtLambda, transferCase
|
||||
from novelwriter.constants import nwConst, nwKeyWords, nwShortcode, nwUnicode
|
||||
from novelwriter.core.document import NWDocument
|
||||
from novelwriter.enum import (
|
||||
@@ -116,6 +117,7 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
loadDocumentTagRequest = pyqtSignal(str, Enum)
|
||||
novelItemMetaChanged = pyqtSignal(str)
|
||||
novelStructureChanged = pyqtSignal()
|
||||
openDocumentRequest = pyqtSignal(str, Enum, str, bool)
|
||||
requestNewNoteCreation = pyqtSignal(str, nwItemClass)
|
||||
requestNextDocument = pyqtSignal(str, bool)
|
||||
requestProjectItemRenamed = pyqtSignal(str, str)
|
||||
@@ -191,6 +193,7 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
self.setMinimumWidth(CONFIG.pxInt(300))
|
||||
self.setAutoFillBackground(True)
|
||||
self.setFrameStyle(QFrame.Shape.NoFrame)
|
||||
self.setAcceptDrops(True)
|
||||
|
||||
# Custom Shortcuts
|
||||
self.keyContext = QShortcut(self)
|
||||
@@ -997,6 +1000,32 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
|
||||
return
|
||||
|
||||
def dragEnterEvent(self, event: QDragEnterEvent) -> None:
|
||||
"""Overload drag enter event to handle dragged items."""
|
||||
if event.mimeData().hasFormat(nwConst.MIME_HANDLE):
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
super().dragEnterEvent(event)
|
||||
return
|
||||
|
||||
def dragMoveEvent(self, event: QDragMoveEvent) -> None:
|
||||
"""Overload drag move event to handle dragged items."""
|
||||
if event.mimeData().hasFormat(nwConst.MIME_HANDLE):
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
super().dragMoveEvent(event)
|
||||
return
|
||||
|
||||
def dropEvent(self, event: QDropEvent) -> None:
|
||||
"""Overload drop event to handle dragged items."""
|
||||
if event.mimeData().hasFormat(nwConst.MIME_HANDLE):
|
||||
if handles := decodeMimeHandles(event.mimeData()):
|
||||
if SHARED.project.tree.checkType(handles[0], nwItemType.FILE):
|
||||
self.openDocumentRequest.emit(handles[0], nwDocMode.EDIT, "", True)
|
||||
else:
|
||||
super().dropEvent(event)
|
||||
return
|
||||
|
||||
def focusNextPrevChild(self, next: bool) -> bool:
|
||||
"""Capture the focus request from the tab key on the text
|
||||
editor. If the editor has focus, we do not change focus and
|
||||
|
||||
@@ -31,15 +31,18 @@ import logging
|
||||
from enum import Enum
|
||||
|
||||
from PyQt5.QtCore import QPoint, Qt, QUrl, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtGui import QCursor, QDesktopServices, QMouseEvent, QPalette, QResizeEvent, QTextCursor
|
||||
from PyQt5.QtGui import (
|
||||
QCursor, QDesktopServices, QDragEnterEvent, QDragMoveEvent, QDropEvent,
|
||||
QMouseEvent, QPalette, QResizeEvent, QTextCursor
|
||||
)
|
||||
from PyQt5.QtWidgets import (
|
||||
QAction, QApplication, QFrame, QHBoxLayout, QMenu, QTextBrowser,
|
||||
QToolButton, QWidget
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.common import qtLambda
|
||||
from novelwriter.constants import nwStyles, nwUnicode
|
||||
from novelwriter.common import decodeMimeHandles, qtLambda
|
||||
from novelwriter.constants import nwConst, nwStyles, nwUnicode
|
||||
from novelwriter.enum import nwDocAction, nwDocMode, nwItemType
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.extensions.configlayout import NColourLabel
|
||||
@@ -445,6 +448,32 @@ class GuiDocViewer(QTextBrowser):
|
||||
super().mouseReleaseEvent(event)
|
||||
return
|
||||
|
||||
def dragEnterEvent(self, event: QDragEnterEvent) -> None:
|
||||
"""Overload drag enter event to handle dragged items."""
|
||||
if event.mimeData().hasFormat(nwConst.MIME_HANDLE):
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
super().dragEnterEvent(event)
|
||||
return
|
||||
|
||||
def dragMoveEvent(self, event: QDragMoveEvent) -> None:
|
||||
"""Overload drag move event to handle dragged items."""
|
||||
if event.mimeData().hasFormat(nwConst.MIME_HANDLE):
|
||||
event.acceptProposedAction()
|
||||
else:
|
||||
super().dragMoveEvent(event)
|
||||
return
|
||||
|
||||
def dropEvent(self, event: QDropEvent) -> None:
|
||||
"""Overload drop event to handle dragged items."""
|
||||
if event.mimeData().hasFormat(nwConst.MIME_HANDLE):
|
||||
if handles := decodeMimeHandles(event.mimeData()):
|
||||
if SHARED.project.tree.checkType(handles[0], nwItemType.FILE):
|
||||
self.openDocumentRequest.emit(handles[0], nwDocMode.VIEW, "", True)
|
||||
else:
|
||||
super().dropEvent(event)
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
@@ -1111,82 +1111,6 @@ class GuiProjectTree(QTreeView):
|
||||
# self._scrollTimer.stop()
|
||||
return
|
||||
|
||||
##
|
||||
# Events
|
||||
##
|
||||
|
||||
# def startDrag(self, dropAction: Qt.DropAction) -> None:
|
||||
# """Capture the drag and drop handling to pop alerts."""
|
||||
# super().startDrag(dropAction)
|
||||
# if self._popAlert:
|
||||
# SHARED.error(self._popAlert)
|
||||
# self._popAlert = None
|
||||
# return
|
||||
|
||||
# def dragEnterEvent(self, event: QDragEnterEvent) -> None:
|
||||
# """Check that we're only dragging items that are siblings, and
|
||||
# not a root level item.
|
||||
# """
|
||||
# items = self.selectedItems()
|
||||
# if items and (parent := items[0].parent()) and all(x.parent() is parent for x in items):
|
||||
# super().dragEnterEvent(event)
|
||||
# else:
|
||||
# logger.warning("Drag action is not allowed and has been cancelled")
|
||||
# self._popAlert = self.tr(
|
||||
# "Drag and drop is only allowed for single items, non-root "
|
||||
# "items, or multiple items with the same parent."
|
||||
# )
|
||||
# event.mimeData().clear()
|
||||
# event.ignore()
|
||||
# return
|
||||
|
||||
# def dragMoveEvent(self, event: QDragMoveEvent) -> None:
|
||||
# """Capture the drag move event to enable edge auto scroll."""
|
||||
# y = event.pos().y()
|
||||
# if y < self._scrollMargin:
|
||||
# if not self._scrollTimer.isActive():
|
||||
# self._scrollDirection = -1
|
||||
# self._scrollTimer.start()
|
||||
# elif y > self.height() - self._scrollMargin:
|
||||
# if not self._scrollTimer.isActive():
|
||||
# self._scrollDirection = 1
|
||||
# self._scrollTimer.start()
|
||||
# super().dragMoveEvent(event)
|
||||
# return
|
||||
|
||||
# def dropEvent(self, event: QDropEvent) -> None:
|
||||
# """Overload the drop item event to ensure the drag and drop
|
||||
# action is allowed, and update relevant data.
|
||||
# """
|
||||
# tItem = self.itemAt(event.pos())
|
||||
# onItem = self.dropIndicatorPosition() == QAbstractItemView.DropIndicatorPosition.OnItem
|
||||
# onView = self.dropIndicatorPosition() == QAbstractItemView.DropIndicatorPosition.OnViewport
|
||||
# # Make sure nothing can be dropped on invisible root (see #1569)
|
||||
# # Make sure nothing can be dropped on the viewport (see #2108)
|
||||
# if tItem is None or (tItem.parent() is None and not onItem) or onView:
|
||||
# logger.error("Invalid drop location")
|
||||
# event.ignore()
|
||||
# return
|
||||
|
||||
# mItems: dict[str, tuple[QTreeWidgetItem, bool]] = {}
|
||||
# sItems = self.selectedItems()
|
||||
# if sItems and (parent := sItems[0].parent()) and all(x.parent() is parent for x in sItems):
|
||||
# for sItem in sItems:
|
||||
# mHandle = str(sItem.data(self.C_DATA, self.D_HANDLE))
|
||||
# mItems[mHandle] = (sItem, sItem.isExpanded())
|
||||
# self.propagateCount(mHandle, 0)
|
||||
|
||||
# super().dropEvent(event)
|
||||
|
||||
# for mHandle, (sItem, isExpanded) in mItems.items():
|
||||
# self._postItemMove(mHandle)
|
||||
# sItem.setExpanded(isExpanded)
|
||||
# self._alertTreeChange(mHandle, flush=False)
|
||||
|
||||
# self.saveTreeOrder()
|
||||
|
||||
# return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
Reference in New Issue
Block a user