Skip to content

Commit

Permalink
[FEATURE] Allow dropping a map layer from the layer tree onto
Browse files Browse the repository at this point in the history
a projection selection widget to set the projection to match that layer

Just a little timesaving shortcut!
  • Loading branch information
nyalldawson committed Dec 22, 2019
1 parent 1db193e commit fb5b440
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 7 deletions.
9 changes: 9 additions & 0 deletions python/gui/auto_generated/qgsprojectionselectionwidget.sip.in
Expand Up @@ -119,6 +119,15 @@ to the preset CRSes shown in the widget.
Opens the dialog for selecting a new CRS
%End

protected:

virtual void dragEnterEvent( QDragEnterEvent *event );

virtual void dragLeaveEvent( QDragLeaveEvent *event );

virtual void dropEvent( QDropEvent *event );


};

/************************************************************************
Expand Down
2 changes: 2 additions & 0 deletions src/gui/CMakeLists.txt
Expand Up @@ -317,6 +317,7 @@ SET(QGIS_GUI_SRCS
qgsgui.cpp
qgsguiutils.cpp
qgshighlight.cpp
qgshighlightablecombobox.cpp
qgshistogramwidget.cpp
qgshelp.cpp
qgsidentifymenu.cpp
Expand Down Expand Up @@ -520,6 +521,7 @@ SET(QGIS_GUI_HDRS
qgsguiutils.h
qgshelp.h
qgshighlight.h
qgshighlightablecombobox.h
qgshistogramwidget.h
qgsidentifymenu.h
qgskeyvaluewidget.h
Expand Down
40 changes: 40 additions & 0 deletions src/gui/qgshighlightablecombobox.cpp
@@ -0,0 +1,40 @@
/***************************************************************************
qgshighlightablecombobox.cpp
---------------------------
Date : 20/12/2019
Copyright : (C) 2019 by Nyall Dawson
Email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgshighlightablecombobox.h"
#include <QPainter>

QgsHighlightableComboBox::QgsHighlightableComboBox( QWidget *parent )
: QComboBox( parent )
{}

void QgsHighlightableComboBox::paintEvent( QPaintEvent *e )
{
QComboBox::paintEvent( e );
if ( mHighlight )
{
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 );
}
}

void QgsHighlightableComboBox::setHighlighted( bool highlighted )
{
mHighlight = highlighted;
update();
}
65 changes: 65 additions & 0 deletions src/gui/qgshighlightablecombobox.h
@@ -0,0 +1,65 @@
/***************************************************************************
qgshighlightablecombobox.h
-------------------------
Date : 20/12/2019
Copyright : (C) 2019 by Nyall Dawson
Email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSHIGHLIGHTABLECOMBOBOX_H
#define QGSHIGHLIGHTABLECOMBOBOX_H

#include <QComboBox>

#include "qgscoordinatereferencesystem.h"
#include "qgis_gui.h"

#define SIP_NO_FILE

/**
* \class QgsHighlightableComboBox
* \ingroup gui
*
* A QComboBox subclass with the ability to "highlight" the edges of the widget.
*
* \since QGIS 3.12
*/
class GUI_EXPORT QgsHighlightableComboBox : public QComboBox
{
Q_OBJECT
public:

/**
* Constructor for QgsHighlightableComboBox with the specified parent widget.
*/
QgsHighlightableComboBox( QWidget *parent = nullptr );

/**
* Returns TRUE if the combo box is currently highlighted.
* \see setHighlighted()
*/
bool isHighlighted() const { return mHighlight; }

/**
* Sets whether the combo box is currently \a highlighted.
* \see isHighlighted()
*/
void setHighlighted( bool highlighted );

protected:
void paintEvent( QPaintEvent *e ) override;

private:

bool mHighlight = false;

};

#endif // QGSHIGHLIGHTABLECOMBOBOX_H
88 changes: 82 additions & 6 deletions src/gui/qgsprojectionselectionwidget.cpp
Expand Up @@ -20,18 +20,17 @@
#include "qgsprojectionselectiondialog.h"
#include "qgsproject.h"
#include "qgssettings.h"
#include "qgshighlightablecombobox.h"

QgsProjectionSelectionWidget::QgsProjectionSelectionWidget( QWidget *parent )
: QWidget( parent )
{


QHBoxLayout *layout = new QHBoxLayout();
layout->setContentsMargins( 0, 0, 0, 0 );
layout->setSpacing( 6 );
setLayout( layout );

mCrsComboBox = new QComboBox( this );
mCrsComboBox = new QgsHighlightableComboBox( this );
mCrsComboBox->addItem( tr( "invalid projection" ), QgsProjectionSelectionWidget::CurrentCrs );
mCrsComboBox->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred );

Expand All @@ -58,14 +57,15 @@ QgsProjectionSelectionWidget::QgsProjectionSelectionWidget( QWidget *parent )

setFocusPolicy( Qt::StrongFocus );
setFocusProxy( mButton );
setAcceptDrops( true );

connect( mButton, &QToolButton::clicked, this, &QgsProjectionSelectionWidget::selectCrs );
connect( mCrsComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsProjectionSelectionWidget::comboIndexChanged );
}

QgsCoordinateReferenceSystem QgsProjectionSelectionWidget::crs() const
{
switch ( ( CrsOption )mCrsComboBox->currentData().toInt() )
switch ( static_cast< CrsOption >( mCrsComboBox->currentData().toInt() ) )
{
case QgsProjectionSelectionWidget::LayerCrs:
return mLayerCrs;
Expand Down Expand Up @@ -194,6 +194,68 @@ void QgsProjectionSelectionWidget::selectCrs()
}
}

void QgsProjectionSelectionWidget::dragEnterEvent( QDragEnterEvent *event )
{
if ( !( event->possibleActions() & Qt::CopyAction ) )
{
event->ignore();
return;
}

if ( mapLayerFromMimeData( event->mimeData() ) )
{
// dragged an acceptable layer, phew
event->setDropAction( Qt::CopyAction );
event->accept();
mCrsComboBox->setHighlighted( true );
update();
}
else
{
event->ignore();
}
}

void QgsProjectionSelectionWidget::dragLeaveEvent( QDragLeaveEvent *event )
{
if ( mCrsComboBox->isHighlighted() )
{
event->accept();
mCrsComboBox->setHighlighted( false );
update();
}
else
{
event->ignore();
}
}

void QgsProjectionSelectionWidget::dropEvent( QDropEvent *event )
{
if ( !( event->possibleActions() & Qt::CopyAction ) )
{
event->ignore();
return;
}

if ( QgsMapLayer *layer = mapLayerFromMimeData( event->mimeData() ) )
{
// dropped a map layer
setFocus( Qt::MouseFocusReason );
event->setDropAction( Qt::CopyAction );
event->accept();

if ( layer->crs().isValid() )
setCrs( layer->crs() );
}
else
{
event->ignore();
}
mCrsComboBox->setHighlighted( false );
update();
}

void QgsProjectionSelectionWidget::addNotSetOption()
{
mCrsComboBox->insertItem( 0, mNotSetText, QgsProjectionSelectionWidget::CrsNotSet );
Expand All @@ -203,7 +265,7 @@ void QgsProjectionSelectionWidget::addNotSetOption()

void QgsProjectionSelectionWidget::comboIndexChanged( int idx )
{
switch ( ( CrsOption )mCrsComboBox->itemData( idx ).toInt() )
switch ( static_cast< CrsOption >( mCrsComboBox->itemData( idx ).toInt() ) )
{
case QgsProjectionSelectionWidget::LayerCrs:
emit crsChanged( mLayerCrs );
Expand Down Expand Up @@ -349,7 +411,7 @@ int QgsProjectionSelectionWidget::firstRecentCrsIndex() const
{
for ( int i = 0; i < mCrsComboBox->count(); ++i )
{
if ( ( CrsOption )mCrsComboBox->itemData( i ).toInt() == RecentCrs )
if ( static_cast< CrsOption >( mCrsComboBox->itemData( i ).toInt() ) == RecentCrs )
{
return i;
}
Expand All @@ -365,3 +427,17 @@ void QgsProjectionSelectionWidget::updateTooltip()
else
setToolTip( QString() );
}

QgsMapLayer *QgsProjectionSelectionWidget::mapLayerFromMimeData( 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() )
{
return layer;
}
}
return nullptr;
}
11 changes: 10 additions & 1 deletion src/gui/qgsprojectionselectionwidget.h
Expand Up @@ -27,6 +27,7 @@
#include "qgis_gui.h"

class QgsProjectionSelectionDialog;
class QgsHighlightableComboBox;

/**
* \class QgsProjectionSelectionWidget
Expand Down Expand Up @@ -132,13 +133,19 @@ class GUI_EXPORT QgsProjectionSelectionWidget : public QWidget
*/
void selectCrs();

protected:

void dragEnterEvent( QDragEnterEvent *event ) override;
void dragLeaveEvent( QDragLeaveEvent *event ) override;
void dropEvent( QDropEvent *event ) override;

private:

QgsCoordinateReferenceSystem mCrs;
QgsCoordinateReferenceSystem mLayerCrs;
QgsCoordinateReferenceSystem mProjectCrs;
QgsCoordinateReferenceSystem mDefaultCrs;
QComboBox *mCrsComboBox = nullptr;
QgsHighlightableComboBox *mCrsComboBox = nullptr;
QToolButton *mButton = nullptr;
QgsProjectionSelectionDialog *mDialog = nullptr;
QString mNotSetText;
Expand All @@ -155,6 +162,8 @@ class GUI_EXPORT QgsProjectionSelectionWidget : public QWidget
int firstRecentCrsIndex() const;
void updateTooltip();

QgsMapLayer *mapLayerFromMimeData( const QMimeData *data ) const;

private slots:

void comboIndexChanged( int idx );
Expand Down

0 comments on commit fb5b440

Please sign in to comment.