diff --git a/python/gui/auto_generated/qgsmaplayercombobox.sip.in b/python/gui/auto_generated/qgsmaplayercombobox.sip.in index 5545518e350..07dfca545d7 100644 --- a/python/gui/auto_generated/qgsmaplayercombobox.sip.in +++ b/python/gui/auto_generated/qgsmaplayercombobox.sip.in @@ -154,6 +154,17 @@ setLayer set the current layer selected in the combo Emitted whenever the currently selected layer changes. %End + protected: + + virtual void dragEnterEvent( QDragEnterEvent *event ); + + virtual void dragLeaveEvent( QDragLeaveEvent *event ); + + virtual void dropEvent( QDropEvent *event ); + + virtual void paintEvent( QPaintEvent *e ); + + protected slots: void indexChanged( int i ); void rowsChanged(); diff --git a/src/gui/qgsmaplayercombobox.cpp b/src/gui/qgsmaplayercombobox.cpp index 2995c0aa25f..cfae40c560e 100644 --- a/src/gui/qgsmaplayercombobox.cpp +++ b/src/gui/qgsmaplayercombobox.cpp @@ -15,7 +15,9 @@ #include "qgsmaplayercombobox.h" #include "qgsmaplayermodel.h" - +#include "qgsmimedatautils.h" +#include +#include QgsMapLayerComboBox::QgsMapLayerComboBox( QWidget *parent ) : QComboBox( parent ) @@ -26,6 +28,8 @@ QgsMapLayerComboBox::QgsMapLayerComboBox( QWidget *parent ) connect( this, static_cast < void ( QComboBox::* )( int ) > ( &QComboBox::activated ), this, &QgsMapLayerComboBox::indexChanged ); connect( mProxyModel, &QAbstractItemModel::rowsInserted, this, &QgsMapLayerComboBox::rowsChanged ); connect( mProxyModel, &QAbstractItemModel::rowsRemoved, this, &QgsMapLayerComboBox::rowsChanged ); + + setAcceptDrops( true ); } void QgsMapLayerComboBox::setExcludedProviders( const QStringList &providers ) @@ -138,3 +142,74 @@ void QgsMapLayerComboBox::rowsChanged() } } +QgsMapLayer *QgsMapLayerComboBox::compatibleMapLayerFromMimeData( const QMimeData *data ) const +{ + const QgsMimeDataUtils::UriList uriList = QgsMimeDataUtils::decodeUriList( data ); + for ( const QgsMimeDataUtils::Uri &u : uriList ) + { + // is this uri from the current project? + if ( QgsMapLayer *layer = u.mapLayer() ) + { + if ( mProxyModel->acceptsLayer( layer ) ) + return layer; + } + } + return nullptr; +} + +void QgsMapLayerComboBox::dragEnterEvent( QDragEnterEvent *event ) +{ + if ( !( event->possibleActions() & Qt::CopyAction ) ) + return; + + if ( compatibleMapLayerFromMimeData( event->mimeData() ) ) + { + // dragged an acceptable layer, phew + event->setDropAction( Qt::CopyAction ); + event->accept(); + mDragActive = true; + update(); + } +} + +void QgsMapLayerComboBox::dragLeaveEvent( QDragLeaveEvent *event ) +{ + QComboBox::dragLeaveEvent( event ); + if ( mDragActive ) + { + event->accept(); + mDragActive = false; + update(); + } +} + +void QgsMapLayerComboBox::dropEvent( QDropEvent *event ) +{ + if ( !( event->possibleActions() & Qt::CopyAction ) ) + return; + + if ( QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData() ) ) + { + // dropped an acceptable layer, phew + setFocus( Qt::MouseFocusReason ); + event->setDropAction( Qt::CopyAction ); + event->accept(); + + setLayer( layer ); + } + mDragActive = false; + update(); +} + +void QgsMapLayerComboBox::paintEvent( QPaintEvent *e ) +{ + QComboBox::paintEvent( e ); + if ( mDragActive ) + { + QPainter p( this ); + int width = 2; // width of highlight rectangle inside frame + p.setPen( QPen( palette().highlight(), width ) ); + QRect r = rect().adjusted( width, width, -width, -width ); + p.drawRect( r ); + } +} diff --git a/src/gui/qgsmaplayercombobox.h b/src/gui/qgsmaplayercombobox.h index c72959cf49c..3067be524c7 100644 --- a/src/gui/qgsmaplayercombobox.h +++ b/src/gui/qgsmaplayercombobox.h @@ -139,12 +139,26 @@ class GUI_EXPORT QgsMapLayerComboBox : public QComboBox //! Emitted whenever the currently selected layer changes. void layerChanged( QgsMapLayer *layer ); + protected: + + void dragEnterEvent( QDragEnterEvent *event ) override; + void dragLeaveEvent( QDragLeaveEvent *event ) override; + void dropEvent( QDropEvent *event ) override; + void paintEvent( QPaintEvent *e ) override; + protected slots: void indexChanged( int i ); void rowsChanged(); private: QgsMapLayerProxyModel *mProxyModel = nullptr; + bool mDragActive = false; + + /** + * Returns a map layer, compatible with the filters set for the combo box, from + * the specified mime \a data (if possible!). + */ + QgsMapLayer *compatibleMapLayerFromMimeData( const QMimeData *data ) const; }; #endif // QGSMAPLAYERCOMBOBOX_H