mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Add API to QgsCustomDropHandler to support custom drop handlers which
allow drops onto a QgsMapCanvas
This commit is contained in:
parent
e391b43b55
commit
58975e7cee
@ -8,6 +8,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsCustomDropHandler : QObject
|
||||
{
|
||||
%Docstring
|
||||
@ -123,6 +124,49 @@ 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.
|
||||
%End
|
||||
|
||||
virtual bool canHandleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &uri, QgsMapCanvas *canvas );
|
||||
%Docstring
|
||||
Returns ``True`` if the handler is capable of handling the provided mime ``uri``
|
||||
when dropped onto a map ``canvas``.
|
||||
|
||||
The base class implementation returns ``False`` regardless of mime data.
|
||||
|
||||
This method is called when mime data is dragged over a map canvas, in order
|
||||
to determine whether any handlers are capable of handling the data and to
|
||||
determine whether the drag action should be accepted.
|
||||
|
||||
.. warning::
|
||||
|
||||
Subclasses should be very careful about implementing this. If they
|
||||
incorrectly return ``True`` to a ``uri``, it will prevent the default application
|
||||
drop handling from occurring and will break the ability to drag and drop layers
|
||||
and files onto QGIS.
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
virtual bool handleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &uri, QgsMapCanvas *canvas ) const;
|
||||
%Docstring
|
||||
Called from QGIS after a drop event with custom ``uri`` known by the handler occurs
|
||||
onto a map ``canvas``.
|
||||
|
||||
In order for handleCustomUriCanvasDrop() to be called, subclasses must
|
||||
also implement customUriProviderKey() to indicate the providerKey
|
||||
value which the handler accepts.
|
||||
|
||||
If the function returns ``True``, it means the handler has accepted the drop
|
||||
and it should not be further processed (e.g. by other QgsCustomDropHandlers).
|
||||
|
||||
Subclasses which implement this must also implement corresponding versions of
|
||||
canHandleCustomUriCanvasDrop().
|
||||
|
||||
.. seealso:: :py:func:`customUriProviderKey`
|
||||
|
||||
.. seealso:: :py:func:`canHandleCustomUriCanvasDrop`
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
};
|
||||
|
||||
|
@ -719,6 +719,7 @@ for the canvas.
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
void refresh();
|
||||
@ -983,75 +984,36 @@ The ``layer`` argument indicates the associated map layer, if available.
|
||||
|
||||
virtual bool event( QEvent *e );
|
||||
|
||||
%Docstring
|
||||
Overridden standard event to be gestures aware
|
||||
%End
|
||||
|
||||
virtual void keyPressEvent( QKeyEvent *e );
|
||||
|
||||
%Docstring
|
||||
Overridden key press event
|
||||
%End
|
||||
|
||||
virtual void keyReleaseEvent( QKeyEvent *e );
|
||||
|
||||
%Docstring
|
||||
Overridden key release event
|
||||
%End
|
||||
|
||||
virtual void mouseDoubleClickEvent( QMouseEvent *e );
|
||||
|
||||
%Docstring
|
||||
Overridden mouse double-click event
|
||||
%End
|
||||
|
||||
virtual void mouseMoveEvent( QMouseEvent *e );
|
||||
|
||||
%Docstring
|
||||
Overridden mouse move event
|
||||
%End
|
||||
|
||||
virtual void mousePressEvent( QMouseEvent *e );
|
||||
|
||||
%Docstring
|
||||
Overridden mouse press event
|
||||
%End
|
||||
|
||||
virtual void mouseReleaseEvent( QMouseEvent *e );
|
||||
|
||||
%Docstring
|
||||
Overridden mouse release event
|
||||
%End
|
||||
|
||||
virtual void wheelEvent( QWheelEvent *e );
|
||||
|
||||
%Docstring
|
||||
Overridden mouse wheel event
|
||||
%End
|
||||
|
||||
virtual void resizeEvent( QResizeEvent *e );
|
||||
|
||||
%Docstring
|
||||
Overridden resize event
|
||||
%End
|
||||
|
||||
virtual void paintEvent( QPaintEvent *e );
|
||||
|
||||
%Docstring
|
||||
Overridden paint event
|
||||
%End
|
||||
|
||||
virtual void dragEnterEvent( QDragEnterEvent *e );
|
||||
|
||||
%Docstring
|
||||
Overridden drag enter event
|
||||
%End
|
||||
|
||||
void moveCanvasContents( bool reset = false );
|
||||
%Docstring
|
||||
called when panning is in action, reset indicates end of panning
|
||||
%End
|
||||
|
||||
virtual void dropEvent( QDropEvent *event );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1777,11 +1777,28 @@ void QgisApp::registerCustomDropHandler( QgsCustomDropHandler *handler )
|
||||
{
|
||||
if ( !mCustomDropHandlers.contains( handler ) )
|
||||
mCustomDropHandlers << handler;
|
||||
|
||||
const auto canvases = mapCanvases();
|
||||
for ( QgsMapCanvas *canvas : canvases )
|
||||
{
|
||||
canvas->setCustomDropHandlers( mCustomDropHandlers );
|
||||
}
|
||||
}
|
||||
|
||||
void QgisApp::unregisterCustomDropHandler( QgsCustomDropHandler *handler )
|
||||
{
|
||||
mCustomDropHandlers.removeOne( handler );
|
||||
|
||||
const auto canvases = mapCanvases();
|
||||
for ( QgsMapCanvas *canvas : canvases )
|
||||
{
|
||||
canvas->setCustomDropHandlers( mCustomDropHandlers );
|
||||
}
|
||||
}
|
||||
|
||||
QVector<QPointer<QgsCustomDropHandler> > QgisApp::customDropHandlers() const
|
||||
{
|
||||
return mCustomDropHandlers;
|
||||
}
|
||||
|
||||
void QgisApp::registerCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler )
|
||||
@ -3877,6 +3894,8 @@ QgsMapCanvasDockWidget *QgisApp::createNewMapCanvasDock( const QString &name )
|
||||
Q_UNUSED( canvasItem ) //item is already added automatically to canvas scene
|
||||
}
|
||||
|
||||
mapCanvas->setCustomDropHandlers( mCustomDropHandlers );
|
||||
|
||||
markDirty();
|
||||
connect( mapCanvasWidget, &QgsMapCanvasDockWidget::closed, this, &QgisApp::markDirty );
|
||||
connect( mapCanvasWidget, &QgsMapCanvasDockWidget::renameTriggered, this, &QgisApp::renameView );
|
||||
|
@ -666,6 +666,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
|
||||
//! Unregister a previously registered custom drop handler.
|
||||
void unregisterCustomDropHandler( QgsCustomDropHandler *handler );
|
||||
|
||||
//! Returns a list of registered custom drop handlers.
|
||||
QVector<QPointer<QgsCustomDropHandler >> customDropHandlers() const;
|
||||
|
||||
//! Register a new custom layout drop handler.
|
||||
void registerCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler );
|
||||
|
||||
|
@ -45,3 +45,13 @@ bool QgsCustomDropHandler::handleFileDrop( const QString &file )
|
||||
Q_UNUSED( file )
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsCustomDropHandler::canHandleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &, QgsMapCanvas * )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsCustomDropHandler::handleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &, QgsMapCanvas * ) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "qgsmimedatautils.h"
|
||||
#include "qgis_gui.h"
|
||||
|
||||
class QgsMapCanvas;
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
* Abstract base class that may be implemented to handle new types of data to be dropped in QGIS.
|
||||
@ -135,6 +137,45 @@ class GUI_EXPORT QgsCustomDropHandler : public QObject
|
||||
* quickly do not apply.
|
||||
*/
|
||||
virtual bool handleFileDrop( const QString &file );
|
||||
|
||||
/**
|
||||
* Returns TRUE if the handler is capable of handling the provided mime \a uri
|
||||
* when dropped onto a map \a canvas.
|
||||
*
|
||||
* The base class implementation returns FALSE regardless of mime data.
|
||||
*
|
||||
* This method is called when mime data is dragged over a map canvas, in order
|
||||
* to determine whether any handlers are capable of handling the data and to
|
||||
* determine whether the drag action should be accepted.
|
||||
*
|
||||
* \warning Subclasses should be very careful about implementing this. If they
|
||||
* incorrectly return TRUE to a \a uri, it will prevent the default application
|
||||
* drop handling from occurring and will break the ability to drag and drop layers
|
||||
* and files onto QGIS.
|
||||
*
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
virtual bool canHandleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &uri, QgsMapCanvas *canvas );
|
||||
|
||||
/**
|
||||
* Called from QGIS after a drop event with custom \a uri known by the handler occurs
|
||||
* onto a map \a canvas.
|
||||
*
|
||||
* In order for handleCustomUriCanvasDrop() to be called, subclasses must
|
||||
* also implement customUriProviderKey() to indicate the providerKey
|
||||
* value which the handler accepts.
|
||||
*
|
||||
* If the function returns TRUE, it means the handler has accepted the drop
|
||||
* and it should not be further processed (e.g. by other QgsCustomDropHandlers).
|
||||
*
|
||||
* Subclasses which implement this must also implement corresponding versions of
|
||||
* canHandleCustomUriCanvasDrop().
|
||||
*
|
||||
* \see customUriProviderKey()
|
||||
* \see canHandleCustomUriCanvasDrop()
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
virtual bool handleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &uri, QgsMapCanvas *canvas ) const;
|
||||
};
|
||||
|
||||
#endif // QGSCUSTOMDROPHANDLER_H
|
||||
|
@ -71,6 +71,8 @@ email : sherman at mrcc.com
|
||||
#include "qgssvgcache.h"
|
||||
#include "qgsimagecache.h"
|
||||
#include "qgsexpressioncontextutils.h"
|
||||
#include "qgsmimedatautils.h"
|
||||
#include "qgscustomdrophandler.h"
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
@ -716,6 +718,11 @@ void QgsMapCanvas::setPreviewJobsEnabled( bool enabled )
|
||||
mUsePreviewJobs = enabled;
|
||||
}
|
||||
|
||||
void QgsMapCanvas::setCustomDropHandlers( const QVector<QPointer<QgsCustomDropHandler> > &handlers )
|
||||
{
|
||||
mDropHandlers = handlers;
|
||||
}
|
||||
|
||||
void QgsMapCanvas::mapUpdateTimeout()
|
||||
{
|
||||
if ( mJob )
|
||||
@ -1988,6 +1995,40 @@ void QgsMapCanvas::moveCanvasContents( bool reset )
|
||||
setSceneRect( -pnt.x(), -pnt.y(), viewport()->size().width(), viewport()->size().height() );
|
||||
}
|
||||
|
||||
void QgsMapCanvas::dropEvent( QDropEvent *event )
|
||||
{
|
||||
if ( QgsMimeDataUtils::isUriList( event->mimeData() ) )
|
||||
{
|
||||
const QgsMimeDataUtils::UriList lst = QgsMimeDataUtils::decodeUriList( event->mimeData() );
|
||||
bool allHandled = true;
|
||||
for ( const QgsMimeDataUtils::Uri &uri : lst )
|
||||
{
|
||||
bool handled = false;
|
||||
for ( QgsCustomDropHandler *handler : qgis::as_const( mDropHandlers ) )
|
||||
{
|
||||
if ( handler && handler->customUriProviderKey() == uri.providerKey )
|
||||
{
|
||||
if ( handler->handleCustomUriCanvasDrop( uri, this ) )
|
||||
{
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !handled )
|
||||
allHandled = false;
|
||||
}
|
||||
if ( allHandled )
|
||||
event->accept();
|
||||
else
|
||||
event->ignore();
|
||||
}
|
||||
else
|
||||
{
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
QPoint QgsMapCanvas::mouseLastXY()
|
||||
{
|
||||
return mCanvasProperties->mouseLastXY;
|
||||
@ -2170,12 +2211,42 @@ void QgsMapCanvas::selectionChangedSlot()
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMapCanvas::dragEnterEvent( QDragEnterEvent *e )
|
||||
void QgsMapCanvas::dragEnterEvent( QDragEnterEvent *event )
|
||||
{
|
||||
// By default graphics view delegates the drag events to graphics items.
|
||||
// But we do not want that and by ignoring the drag enter we let the
|
||||
// parent (e.g. QgisApp) to handle drops of map layers etc.
|
||||
e->ignore();
|
||||
|
||||
// so we ONLY accept the event if we know in advance that a custom drop handler
|
||||
// wants it
|
||||
|
||||
if ( QgsMimeDataUtils::isUriList( event->mimeData() ) )
|
||||
{
|
||||
const QgsMimeDataUtils::UriList lst = QgsMimeDataUtils::decodeUriList( event->mimeData() );
|
||||
bool allHandled = true;
|
||||
for ( const QgsMimeDataUtils::Uri &uri : lst )
|
||||
{
|
||||
bool handled = false;
|
||||
for ( QgsCustomDropHandler *handler : qgis::as_const( mDropHandlers ) )
|
||||
{
|
||||
if ( handler->canHandleCustomUriCanvasDrop( uri, this ) )
|
||||
{
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !handled )
|
||||
allHandled = false;
|
||||
}
|
||||
if ( allHandled )
|
||||
event->accept();
|
||||
else
|
||||
event->ignore();
|
||||
}
|
||||
else
|
||||
{
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMapCanvas::mapToolDestroyed()
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "qgsrectangle.h"
|
||||
#include "qgsfeatureid.h"
|
||||
#include "qgsgeometry.h"
|
||||
#include "qgscustomdrophandler.h"
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QGraphicsView>
|
||||
@ -639,6 +640,13 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
|
||||
*/
|
||||
void setPreviewJobsEnabled( bool enabled );
|
||||
|
||||
/**
|
||||
* Sets a list of custom drop \a handlers to use when drop events occur on the canvas.
|
||||
* \note Not available in Python bindings
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
void setCustomDropHandlers( const QVector<QPointer<QgsCustomDropHandler >> &handlers ) SIP_SKIP;
|
||||
|
||||
public slots:
|
||||
|
||||
//! Repaints the canvas map
|
||||
@ -863,42 +871,24 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
|
||||
|
||||
protected:
|
||||
|
||||
//! Overridden standard event to be gestures aware
|
||||
bool event( QEvent *e ) override;
|
||||
|
||||
//! Overridden key press event
|
||||
void keyPressEvent( QKeyEvent *e ) override;
|
||||
|
||||
//! Overridden key release event
|
||||
void keyReleaseEvent( QKeyEvent *e ) override;
|
||||
|
||||
//! Overridden mouse double-click event
|
||||
void mouseDoubleClickEvent( QMouseEvent *e ) override;
|
||||
|
||||
//! Overridden mouse move event
|
||||
void mouseMoveEvent( QMouseEvent *e ) override;
|
||||
|
||||
//! Overridden mouse press event
|
||||
void mousePressEvent( QMouseEvent *e ) override;
|
||||
|
||||
//! Overridden mouse release event
|
||||
void mouseReleaseEvent( QMouseEvent *e ) override;
|
||||
|
||||
//! Overridden mouse wheel event
|
||||
void wheelEvent( QWheelEvent *e ) override;
|
||||
|
||||
//! Overridden resize event
|
||||
void resizeEvent( QResizeEvent *e ) override;
|
||||
|
||||
//! Overridden paint event
|
||||
void paintEvent( QPaintEvent *e ) override;
|
||||
|
||||
//! Overridden drag enter event
|
||||
void dragEnterEvent( QDragEnterEvent *e ) override;
|
||||
|
||||
//! called when panning is in action, reset indicates end of panning
|
||||
void moveCanvasContents( bool reset = false );
|
||||
|
||||
void dropEvent( QDropEvent *event ) override;
|
||||
|
||||
|
||||
/// implementation struct
|
||||
class CanvasProperties;
|
||||
|
||||
@ -1029,6 +1019,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
|
||||
|
||||
QHash< QString, int > mLastLayerRenderTime;
|
||||
|
||||
QVector<QPointer<QgsCustomDropHandler >> mDropHandlers;
|
||||
|
||||
/**
|
||||
* Returns the last cursor position on the canvas in geographical coordinates
|
||||
* \since QGIS 3.4
|
||||
|
@ -15,13 +15,14 @@
|
||||
|
||||
#include "qgstest.h"
|
||||
|
||||
#include <qgsapplication.h>
|
||||
#include <qgsmapcanvas.h>
|
||||
#include <qgsvectorlayer.h>
|
||||
#include <qgsproject.h>
|
||||
#include <qgsrenderchecker.h>
|
||||
#include <qgsvectordataprovider.h>
|
||||
#include <qgsmaptoolpan.h>
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsmapcanvas.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgsrenderchecker.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsmaptoolpan.h"
|
||||
#include "qgscustomdrophandler.h"
|
||||
|
||||
namespace QTest
|
||||
{
|
||||
@ -57,6 +58,7 @@ class TestQgsMapCanvas : public QObject
|
||||
void testScaleLockCanvasResize();
|
||||
void testZoomByWheel();
|
||||
void testShiftZoom();
|
||||
void testDragDrop();
|
||||
|
||||
private:
|
||||
QgsMapCanvas *mCanvas = nullptr;
|
||||
@ -431,5 +433,74 @@ void TestQgsMapCanvas::testShiftZoom()
|
||||
QGSCOMPARENEAR( mCanvas->extent().height(), originalHeight, 0.00001 );
|
||||
}
|
||||
|
||||
class TestNoDropHandler : public QgsCustomDropHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
QString customUriProviderKey() const override { return QStringLiteral( "test" ); }
|
||||
bool canHandleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &, QgsMapCanvas * ) override { return false; }
|
||||
bool handleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &, QgsMapCanvas * ) const override { return false; }
|
||||
};
|
||||
|
||||
class TestYesDropHandler : public QgsCustomDropHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
QString customUriProviderKey() const override { return QStringLiteral( "test" ); }
|
||||
bool canHandleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &, QgsMapCanvas * ) override { return true; }
|
||||
bool handleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &, QgsMapCanvas * ) const override { return true; }
|
||||
};
|
||||
|
||||
void TestQgsMapCanvas::testDragDrop()
|
||||
{
|
||||
// default drag, should not be accepted
|
||||
std::unique_ptr< QMimeData > data = qgis::make_unique< QMimeData >();
|
||||
std::unique_ptr< QDragEnterEvent > event = qgis::make_unique< QDragEnterEvent >( QPoint( 10, 10 ), Qt::CopyAction, data.get(), Qt::LeftButton, Qt::NoModifier );
|
||||
mCanvas->dragEnterEvent( event.get() );
|
||||
QVERIFY( !event->isAccepted() );
|
||||
|
||||
// with mime data
|
||||
QgsMimeDataUtils::UriList list;
|
||||
QgsMimeDataUtils::Uri uri;
|
||||
uri.name = QStringLiteral( "name" );
|
||||
uri.providerKey = QStringLiteral( "test" );
|
||||
list << uri;
|
||||
data.reset( QgsMimeDataUtils::encodeUriList( list ) );
|
||||
event = qgis::make_unique< QDragEnterEvent >( QPoint( 10, 10 ), Qt::CopyAction, data.get(), Qt::LeftButton, Qt::NoModifier );
|
||||
mCanvas->dragEnterEvent( event.get() );
|
||||
// still not accepted by default
|
||||
QVERIFY( !event->isAccepted() );
|
||||
|
||||
// add a custom drop handler to the canvas
|
||||
TestNoDropHandler handler;
|
||||
mCanvas->setCustomDropHandlers( QVector< QPointer< QgsCustomDropHandler > >() << &handler );
|
||||
mCanvas->dragEnterEvent( event.get() );
|
||||
// not accepted by handler
|
||||
QVERIFY( !event->isAccepted() );
|
||||
|
||||
TestYesDropHandler handler2;
|
||||
mCanvas->setCustomDropHandlers( QVector< QPointer< QgsCustomDropHandler > >() << &handler << &handler2 );
|
||||
mCanvas->dragEnterEvent( event.get() );
|
||||
// IS accepted by handler
|
||||
QVERIFY( event->isAccepted() );
|
||||
|
||||
// check drop event logic
|
||||
mCanvas->setCustomDropHandlers( QVector< QPointer< QgsCustomDropHandler > >() );
|
||||
std::unique_ptr< QDropEvent > dropEvent = qgis::make_unique< QDropEvent >( QPoint( 10, 10 ), Qt::CopyAction, data.get(), Qt::LeftButton, Qt::NoModifier );
|
||||
mCanvas->dropEvent( dropEvent.get() );
|
||||
QVERIFY( !dropEvent->isAccepted() );
|
||||
mCanvas->setCustomDropHandlers( QVector< QPointer< QgsCustomDropHandler > >() << &handler );
|
||||
mCanvas->dropEvent( dropEvent.get() );
|
||||
QVERIFY( !dropEvent->isAccepted() );
|
||||
mCanvas->setCustomDropHandlers( QVector< QPointer< QgsCustomDropHandler > >() << &handler << &handler2 );
|
||||
mCanvas->dropEvent( dropEvent.get() );
|
||||
// is accepted!
|
||||
QVERIFY( dropEvent->isAccepted() );
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsMapCanvas )
|
||||
#include "testqgsmapcanvas.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user