[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...
This commit is contained in:
Nyall Dawson 2019-06-12 13:01:40 +10:00
parent d56ddc25fb
commit cf63a7af97
3 changed files with 101 additions and 1 deletions

View File

@ -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();

View File

@ -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 );
}
}

View File

@ -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