"""
Drag/Drop handlers for handling drop events on the canvas.
This is used to create a widget node when a file is dragged onto the canvas.
To define a handler subclass a :class:`OWNodeFromMimeDataDropHandler` or one
of its subclasses (e.g :class:`SingleUrlDropHandler`,
:class:`SingleFileDropHandler`, ...) and register it with the target
application's entry point (the default is
'orangecanvas.document.interactions.DropHandler') in the project's meta data,
e.g.::
entry_points = {
...
"orange.canvas.drophandler": [
"The widget = fully.qualified.module:class_name",
...
],
...
"""
import abc
from typing import Type, Dict, Any, Sequence
from AnyQt.QtCore import QMimeData, QUrl
from orangecanvas.document.interactions import NodeFromMimeDataDropHandler
from orangecanvas.document.schemeedit import SchemeEditWidget
from orangecanvas.utils import qualified_name
from orangewidget.widget import OWBaseWidget
__all__ = [
"OWNodeFromMimeDataDropHandler",
"SingleUrlDropHandler",
"UrlsDropHandler",
"SingleFileDropHandler",
"FilesDropHandler",
]
[docs]class OWNodeFromMimeDataDropHandler(NodeFromMimeDataDropHandler, abc.ABC):
"""
Canvas drop handler creating a OWBaseWidget nodes.
This implements a default :meth:`.qualifiedName`
that is based on :attr:`.WIDGET` class attribute.
"""
#: Class attribute declaring which OWBaseWidget (sub)class this drop
#: handler creates. Concrete subclasses **must** assign this attribute.
WIDGET: Type[OWBaseWidget] = None
[docs] def qualifiedName(self) -> str:
"""Reimplemented."""
return qualified_name(self.WIDGET)
[docs]class SingleUrlDropHandler(OWNodeFromMimeDataDropHandler):
"""
Canvas drop handler accepting a single url drop.
Subclasses must define :meth:`canDropUrl` and :meth:`parametersFromUrl`
Note
----
Use :class:`SingleFileDropHandler` if you only care about local
filesystem paths.
"""
[docs] def canDropMimeData(self, document: 'SchemeEditWidget', data: 'QMimeData') -> bool:
"""
Reimplemented.
Delegate to `canDropFile` method if the `data` has a single local file
system path.
"""
urls = data.urls()
if len(urls) != 1:
return False
return self.canDropUrl(urls[0])
[docs] def parametersFromMimeData(self, document: 'SchemeEditWidget', data: 'QMimeData') -> 'Dict[str, Any]':
"""
Reimplemented.
Delegate to :meth:`parametersFromUrl` method.
"""
return self.parametersFromUrl(data.urls()[0])
[docs] @abc.abstractmethod
def canDropUrl(self, url: QUrl) -> bool:
"""
Can the handler create a node from the `url`.
Subclasses must redefine this method.
"""
raise NotImplementedError
[docs] @abc.abstractmethod
def parametersFromUrl(self, url: QUrl) -> 'Dict[str, Any]':
"""
Return the node parameters from `url`.
Subclasses must redefine this method.
"""
raise NotImplementedError
[docs]class UrlsDropHandler(OWNodeFromMimeDataDropHandler):
"""
Canvas drop handler accepting url drops.
Subclasses must define :meth:`canDropUrls` and :meth:`parametersFromUrls`
Note
----
Use :class:`FilesDropHandler` if you only care about local filesystem paths.
"""
[docs] def canDropMimeData(self, document: 'SchemeEditWidget', data: 'QMimeData') -> bool:
"""
Reimplemented.
Delegate to :meth:`canDropUrls` method.
"""
urls = data.urls()
if not bool(urls):
return False
return self.canDropUrls(urls)
[docs] def parametersFromMimeData(self, document: 'SchemeEditWidget', data: 'QMimeData') -> 'Dict[str, Any]':
"""
Reimplemented.
Delegate to :meth:`parametersFromUrls` method.
"""
return self.parametersFromUrls(data.urls())
[docs] @abc.abstractmethod
def canDropUrls(self, urls: Sequence[QUrl]) -> bool:
"""
Can the handler create a node from the `urls` list.
Subclasses must redefine this method.
"""
raise NotImplementedError
[docs] @abc.abstractmethod
def parametersFromUrls(self, urls: Sequence[QUrl]) -> 'Dict[str, Any]':
"""
Return the node parameters from `urls`.
Subclasses must redefine this method.
"""
raise NotImplementedError
[docs]class SingleFileDropHandler(OWNodeFromMimeDataDropHandler):
"""
Canvas drop handler accepting single local file path.
Subclasses must define :meth:`canDropFile` and :meth:`parametersFromFile`
"""
[docs] def canDropMimeData(self, document: 'SchemeEditWidget', data: 'QMimeData') -> bool:
"""
Reimplemented.
Delegate to :meth:`canDropFile` method if the `data` has a single
local file system path.
"""
urls = data.urls()
if len(urls) != 1 or not urls[0].isLocalFile():
return False
path = urls[0].toLocalFile()
return self.canDropFile(path)
[docs] def parametersFromMimeData(self, document: 'SchemeEditWidget', data: 'QMimeData') -> 'Dict[str, Any]':
"""
Reimplemented.
Delegate to :meth:`parametersFromFile` method.
"""
path = data.urls()[0].toLocalFile()
return self.parametersFromFile(path)
[docs] @abc.abstractmethod
def canDropFile(self, path: str) -> bool:
"""
Can the handler create a node from the file `path`.
Subclasses must redefine this method.
"""
raise NotImplementedError
[docs] @abc.abstractmethod
def parametersFromFile(self, path: str) -> 'Dict[str, Any]':
"""
Return the node parameters based on file `path`.
Subclasses must redefine this method.
"""
raise NotImplementedError
[docs]class FilesDropHandler(OWNodeFromMimeDataDropHandler):
"""
Canvas drop handler accepting local file paths.
Subclasses must define :meth:`canDropFiles` and :meth:`parametersFromFiles`
"""
[docs] def canDropMimeData(self, document: 'SchemeEditWidget', data: 'QMimeData') -> bool:
"""
Reimplemented.
Delegate to :meth:`canDropFiles` method if the `data` has only local
filesystem paths.
"""
urls = data.urls()
if not urls or not all(url.isLocalFile() for url in urls):
return False
paths = [url.toLocalFile() for url in urls]
return self.canDropFiles(paths)
[docs] def parametersFromMimeData(self, document: 'SchemeEditWidget', data: 'QMimeData') -> 'Dict[str, Any]':
"""
Reimplemented.
Delegate to :meth:`parametersFromFile` method.
"""
urls = data.urls()
paths = [url.toLocalFile() for url in urls]
return self.parametersFromFiles(paths)
[docs] @abc.abstractmethod
def canDropFiles(self, paths: Sequence[str]) -> bool:
"""
Can the handler create a node from the `paths`.
Subclasses must redefine this method.
"""
raise NotImplementedError
[docs] @abc.abstractmethod
def parametersFromFiles(self, paths: Sequence[str]) -> 'Dict[str, Any]':
"""
Return the node parameters based on `paths`.
Subclasses must redefine this method.
"""
raise NotImplementedError