Skip to content
Permalink
Browse files

Merge pull request #5200 from nyalldawson/drop_handler

[FEATURE][processing] Allow dropping model files onto QGIS window to execute them
  • Loading branch information
nyalldawson committed Sep 15, 2017
2 parents f282a75 + 06ee6f6 commit 5bd164b644e5b96825fb6c38890ceaabd9d4f60f
@@ -1,7 +1,6 @@
// Include auto-generated SIP files
%Include qgsattributeeditorcontext.sip
%Include qgsattributeforminterface.sip
%Include qgscustomdrophandler.sip
%Include qgsdetaileditemdata.sip
%Include qgsexpressionbuilderdialog.sip
%Include qgsgeometryrubberband.sip
@@ -91,6 +90,7 @@
%Include qgsconfigureshortcutsdialog.sip
%Include qgscredentialdialog.sip
%Include qgscurveeditorwidget.sip
%Include qgscustomdrophandler.sip
%Include qgsdetaileditemdelegate.sip
%Include qgsdetaileditemwidget.sip
%Include qgsdial.sip
@@ -8,12 +8,30 @@



class QgsCustomDropHandler
class QgsCustomDropHandler : QObject
{
%Docstring
Abstract base class that may be implemented to handle new types of data to be dropped in QGIS.
Implementations will be used when a QgsMimeDataUtils.Uri has layerType equal to "custom",
and the providerKey is equal to key() returned by the implementation.

Implementations have three approaches they can use to handle drops.

1. The simplest approach is to implement handeFileDrop() when they need to handle
dropped files (i.e. with mime type "text/uri-list").

2. Reimplement handleCustomUriDrop() when they want to handle dropped custom
QgsMimeDataUtils.Uri entries, for instance handling dropping custom entries
from the browser tree (with mime type "application/x-vnd.qgis.qgis.uri"). In
this case the implementation's customUriProviderKey() must match the uri
entry's providerKey.

3. Reimplement handleMimeData() to directly handle dropped QMimeData.
Subclasses should take care when overriding this method. When a drop event
occurs, Qt will lock the source application of the drag for the duration
of the drop event handling via handleMimeData() (e.g. dragging files from
explorer to QGIS will lock the explorer window until the drop handling has
been complete). Accordingly handleMimeData() implementations must return
quickly and defer any intensive or slow processing.

.. versionadded:: 3.0
%End

@@ -23,15 +41,55 @@ class QgsCustomDropHandler
public:
virtual ~QgsCustomDropHandler();

virtual QString key() const = 0;
virtual QString customUriProviderKey() const;
%Docstring
Type of custom URI recognized by the handler
Type of custom URI recognized by the handler. This must match
the URI entry's providerKey in order for handleCustomUriDrop()
to be called.

.. seealso:: handleCustomUriDrop()
:rtype: str
%End

virtual void handleDrop( const QgsMimeDataUtils::Uri &uri ) const = 0;
virtual void handleCustomUriDrop( const QgsMimeDataUtils::Uri &uri ) const;
%Docstring
Method called from QGIS after a drop event with custom URI known by the handler
Called from QGIS after a drop event with custom URI known by the handler.

In order for handleCustomUriDrop() to be called, subclasses must
also implement customUriProviderKey() to indicate the providerKey
value which the handler accepts.

.. seealso:: customUriProviderKey()
%End

virtual void handleMimeData( const QMimeData *data );
%Docstring
Called when the specified mime ``data`` has been dropped onto QGIS.

The base class implementation does nothing.

Subclasses should take care when overriding this method. When a drop event
occurs, Qt will lock the source application of the drag for the duration
of the drop event handling (e.g. dragging files from explorer to QGIS will
lock the explorer window until the drop handling has been complete).

Accordingly, only implementations must be lightweight and return ASAP.
(For instance by copying the relevant parts of ``data`` and then handling
the data after a short timeout).
%End

virtual bool handleFileDrop( const QString &file );
%Docstring
Called when the specified ``file`` has been dropped onto QGIS. If true
is returned, then the handler has accepted this file and it should not
be further processed (e.g. by other QgsCustomDropHandlers).

The base class implementation does nothing.

This method is not called directly while drop handling is occurring,
so the limitations described in handleMimeData() about returning
quickly do not apply.
:rtype: bool
%End
};

@@ -32,13 +32,16 @@
import sys

from qgis.core import (QgsApplication,
QgsProcessingUtils)
from qgis.gui import QgsOptionsWidgetFactory
QgsProcessingUtils,
QgsProcessingModelAlgorithm)
from qgis.gui import (QgsOptionsWidgetFactory,
QgsCustomDropHandler)
from qgis.PyQt.QtCore import Qt, QCoreApplication, QDir
from qgis.PyQt.QtWidgets import QMenu, QAction
from qgis.PyQt.QtGui import QIcon

from processing.core.Processing import Processing
from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.gui.ProcessingToolbox import ProcessingToolbox
from processing.gui.HistoryDialog import HistoryDialog
from processing.gui.ConfigDialog import ConfigOptionsPage
@@ -66,13 +69,32 @@ def createWidget(self, parent):
return ConfigOptionsPage(parent)


class ProcessingDropHandler(QgsCustomDropHandler):

def handleFileDrop(self, file):
if not file.lower().endswith('.model3'):
return False

alg = QgsProcessingModelAlgorithm()
if not alg.fromFile(file):
return False

alg.setProvider(QgsApplication.processingRegistry().providerById('model'))
dlg = AlgorithmDialog(alg)
dlg.setAttribute(Qt.WA_DeleteOnClose)
dlg.show()
return True


class ProcessingPlugin(object):

def __init__(self, iface):
self.iface = iface
self.options_factory = ProcessingOptionsFactory()
self.options_factory.setTitle(self.tr('Processing'))
iface.registerOptionsWidgetFactory(self.options_factory)
self.drop_handler = ProcessingDropHandler()
iface.registerCustomDropHandler(self.drop_handler)
self.locator_filter = AlgorithmLocatorFilter()
iface.registerLocatorFilter(self.locator_filter)
Processing.initialize()
@@ -159,6 +181,7 @@ def unload(self):

self.iface.unregisterOptionsWidgetFactory(self.options_factory)
self.iface.deregisterLocatorFilter(self.locator_filter)
self.iface.unregisterCustomDropHandler(self.drop_handler)

removeMenus()
Processing.deinitialize()
@@ -1333,6 +1333,14 @@ void QgisApp::dropEvent( QDropEvent *event )
timer->setSingleShot( true );
timer->setInterval( 50 );

// first, allow custom handlers to directly operate on the mime data
const QList<QPointer<QgsCustomDropHandler >> handlers = mCustomDropHandlers;
for ( QgsCustomDropHandler *handler : handlers )
{
if ( handler )
handler->handleMimeData( event->mimeData() );
}

// get the file list
QList<QUrl>::iterator i;
QList<QUrl>urls = event->mimeData()->urls();
@@ -1392,40 +1400,49 @@ void QgisApp::dropEvent( QDropEvent *event )
files << fileName;
}
}
timer->setProperty( "files", files );

QgsMimeDataUtils::UriList lst;
if ( QgsMimeDataUtils::isUriList( event->mimeData() ) )
{
lst = QgsMimeDataUtils::decodeUriList( event->mimeData() );
}
timer->setProperty( "uris", QVariant::fromValue( lst ) );

connect( timer, &QTimer::timeout, this, &QgisApp::dropEventTimeout );
connect( timer, &QTimer::timeout, this, [this, timer, files, lst]
{
freezeCanvases();

event->acceptProposedAction();
timer->start();
}
for ( const QString &file : qgsAsConst( files ) )
{
bool handled = false;

void QgisApp::dropEventTimeout()
{
freezeCanvases();
QStringList files = sender()->property( "files" ).toStringList();
sender()->deleteLater();
// give custom drop handlers first priority at handling the file
const QList<QPointer<QgsCustomDropHandler >>handlers = mCustomDropHandlers;
for ( QgsCustomDropHandler *handler : handlers )
{
if ( handler && handler->handleFileDrop( file ) )
{
handled = true;
break;
}
}

Q_FOREACH ( const QString &file, files )
{
openFile( file );
}
if ( !handled )
openFile( file );
}

QgsMimeDataUtils::UriList lst = sender()->property( "uris" ).value<QgsMimeDataUtils::UriList>();
if ( !lst.isEmpty() )
{
handleDropUriList( lst );
}
if ( !lst.isEmpty() )
{
handleDropUriList( lst );
}

freezeCanvases( false );
refreshMapCanvas();
freezeCanvases( false );
refreshMapCanvas();

timer->deleteLater();
} );

event->acceptProposedAction();
timer->start();
}

void QgisApp::annotationCreated( QgsAnnotation *annotation )
@@ -1474,9 +1491,9 @@ void QgisApp::handleDropUriList( const QgsMimeDataUtils::UriList &lst )
{
Q_FOREACH ( QgsCustomDropHandler *handler, mCustomDropHandlers )
{
if ( handler->key() == u.providerKey )
if ( handler && handler->customUriProviderKey() == u.providerKey )
{
handler->handleDrop( u );
handler->handleCustomUriDrop( u );
break;
}
}
@@ -1511,9 +1511,6 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
//! Set the layer for the map style dock. Doesn't show the style dock
void setMapStyleDockLayer( QgsMapLayer *layer );

//! Handles processing of dropped mimedata
void dropEventTimeout();

void annotationCreated( QgsAnnotation *annotation );

void updateCrsStatusBar();
@@ -2056,7 +2053,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QList<QgsMapLayerConfigWidgetFactory *> mMapLayerPanelFactories;
QList<QPointer<QgsOptionsWidgetFactory>> mOptionsWidgetFactories;

QList<QgsCustomDropHandler *> mCustomDropHandlers;
QList<QPointer<QgsCustomDropHandler>> mCustomDropHandlers;

QDateTime mProjectLastModified;

@@ -385,6 +385,7 @@ SET(QGIS_GUI_MOC_HDRS
qgsconfigureshortcutsdialog.h
qgscredentialdialog.h
qgscurveeditorwidget.h
qgscustomdrophandler.h
qgsdatumtransformdialog.h
qgsdetaileditemdelegate.h
qgsdetaileditemwidget.h
@@ -684,7 +685,6 @@ SET(QGIS_GUI_HDRS
qgsattributeforminterface.h
qgsattributeformlegacyinterface.h
qgscursors.h
qgscustomdrophandler.h
qgsdetaileditemdata.h
qgsexpressionbuilderdialog.h
qgsgeometryrubberband.h
@@ -14,3 +14,24 @@
***************************************************************************/

#include "qgscustomdrophandler.h"

QString QgsCustomDropHandler::customUriProviderKey() const
{
return QString();
}

void QgsCustomDropHandler::handleCustomUriDrop( const QgsMimeDataUtils::Uri &uri ) const
{
Q_UNUSED( uri );
}

void QgsCustomDropHandler::handleMimeData( const QMimeData *data )
{
Q_UNUSED( data );
}

bool QgsCustomDropHandler::handleFileDrop( const QString &file )
{
Q_UNUSED( file );
return false;
}

0 comments on commit 5bd164b

Please sign in to comment.
You can’t perform that action at this time.