From cf63a7af973b667a0bc1b51dea21cf6d9b55cba7 Mon Sep 17 00:00:00 2001 From: Nyall Dawson <nyall.dawson@gmail.com> Date: Wed, 12 Jun 2019 13:01:40 +1000 Subject: [PATCH] [needs-docs] Allow dragging project layers from legend over map layer comboboxes to select Greatly assists with usability of the combobox with large projects, especially those with multiple copies of layers with the same name... --- .../auto_generated/qgsmaplayercombobox.sip.in | 11 +++ src/gui/qgsmaplayercombobox.cpp | 77 ++++++++++++++++++- src/gui/qgsmaplayercombobox.h | 14 ++++ 3 files changed, 101 insertions(+), 1 deletion(-) 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 <QDragEnterEvent> +#include <QPainter> 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