Skip to content

Commit

Permalink
[FEATURE] Add zoom to features shortcut in select by form dialog
Browse files Browse the repository at this point in the history
Allows very quick navigation to features which match the criteria
in the form
  • Loading branch information
nyalldawson committed Dec 22, 2016
1 parent 0bfc9bb commit 80b757b
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 8 deletions.
6 changes: 6 additions & 0 deletions python/gui/qgsattributeform.sip
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,12 @@ class QgsAttributeForm : QWidget
*/
void closed();

/**
* Emitted when the user chooses to zoom to a filtered set of features.
* @note added in QGIS 3.0
*/
void zoomToFeatures( const QString& filter );

public slots:
/**
* Call this to change the content of a given attribute. Will update the editor(s) related to this field.
Expand Down
8 changes: 4 additions & 4 deletions python/gui/qgsmapcanvas.sip
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ class QgsMapCanvas : QGraphicsView
//! Zooms in/out with a given center
void zoomWithCenter( int x, int y, bool zoomIn );

//! Zooms to feature extent. Adds a small margin around the extent
//! and does a pan if rect is empty (point extent)
void zoomToFeatureExtent( QgsRectangle& rect );

//! Returns whether the scale is locked, so zooming can be performed using magnication.
//! @note added in 2.16
//! @see setScaleLocked()
Expand Down Expand Up @@ -518,10 +522,6 @@ class QgsMapCanvas : QGraphicsView
//! called when panning is in action, reset indicates end of panning
void moveCanvasContents( bool reset = false );

//! Zooms to feature extent. Adds a small margin around the extent
//! and does a pan if rect is empty (point extent)
void zoomToFeatureExtent( QgsRectangle& rect );

//! called on resize or changed extent to notify canvas items to change their rectangle
void updateCanvasItemPositions();

Expand Down
1 change: 1 addition & 0 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7520,6 +7520,7 @@ void QgisApp::selectByForm()

QgsSelectByFormDialog* dlg = new QgsSelectByFormDialog( vlayer, context, this );
dlg->setMessageBar( messageBar() );
dlg->setMapCanvas( mapCanvas() );
dlg->setAttribute( Qt::WA_DeleteOnClose );
dlg->show();
}
Expand Down
64 changes: 64 additions & 0 deletions src/app/qgsselectbyformdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@

#include "qgsselectbyformdialog.h"
#include "qgsattributeform.h"
#include "qgsmapcanvas.h"
#include <QLayout>
#include <QSettings>

QgsSelectByFormDialog::QgsSelectByFormDialog( QgsVectorLayer* layer, const QgsAttributeEditorContext& context, QWidget* parent, Qt::WindowFlags fl )
: QDialog( parent, fl )
, mLayer( layer )
, mMessageBar( nullptr )
{
QgsAttributeEditorContext dlgContext = context;
dlgContext.setFormMode( QgsAttributeEditorContext::StandaloneDialog );
Expand Down Expand Up @@ -51,5 +54,66 @@ QgsSelectByFormDialog::~QgsSelectByFormDialog()

void QgsSelectByFormDialog::setMessageBar( QgsMessageBar* messageBar )
{
mMessageBar = messageBar;
mForm->setMessageBar( messageBar );
}

void QgsSelectByFormDialog::setMapCanvas( QgsMapCanvas* canvas )
{
mMapCanvas = canvas;
connect( mForm, &QgsAttributeForm::zoomToFeatures, this, &QgsSelectByFormDialog::zoomToFeatures );
}

void QgsSelectByFormDialog::zoomToFeatures( const QString& filter )
{
QgsFeatureIds ids;

QgsExpressionContext context;
context << QgsExpressionContextUtils::globalScope()
<< QgsExpressionContextUtils::projectScope()
<< QgsExpressionContextUtils::layerScope( mLayer );

QgsFeatureRequest request = QgsFeatureRequest().setFilterExpression( filter )
.setExpressionContext( context )
.setSubsetOfAttributes( QgsAttributeList() );

QgsFeatureIterator features = mLayer->getFeatures( request );

QgsRectangle bbox;
bbox.setMinimal();
QgsFeature feat;
int featureCount = 0;
while ( features.nextFeature( feat ) )
{
QgsGeometry geom = feat.geometry();
if ( geom.isEmpty() || geom.geometry()->isEmpty() )
continue;

QgsRectangle r = mMapCanvas->mapSettings().layerExtentToOutputExtent( mLayer, geom.boundingBox() );
bbox.combineExtentWith( r );
featureCount++;
}
features.close();

QSettings settings;
int timeout = settings.value( QStringLiteral( "/qgis/messageTimeout" ), 5 ).toInt();
if ( featureCount > 0 )
{
mMapCanvas->zoomToFeatureExtent( bbox );
if ( mMessageBar )
{
mMessageBar->pushMessage( QString(),
tr( "Zoomed to %1 matching %2" ).arg( featureCount )
.arg( featureCount == 1 ? tr( "feature" ) : tr( "features" ) ),
QgsMessageBar::INFO,
timeout );
}
}
else if ( mMessageBar )
{
mMessageBar->pushMessage( QString(),
tr( "No matching features found" ),
QgsMessageBar::INFO,
timeout );
}
}
13 changes: 13 additions & 0 deletions src/app/qgsselectbyformdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
class QgsAttributeForm;
class QgsMessageBar;
class QgsVectorLayer;
class QgsMapCanvas;

/** \ingroup app
* \class QgsSelectByFormDialog
Expand Down Expand Up @@ -54,9 +55,21 @@ class APP_EXPORT QgsSelectByFormDialog : public QDialog
*/
void setMessageBar( QgsMessageBar* messageBar );

/**
* Sets a map canvas associated with the dialog.
*/
void setMapCanvas( QgsMapCanvas* canvas );

private slots:

void zoomToFeatures( const QString& filter );

private:

QgsAttributeForm* mForm;
QgsVectorLayer* mLayer;
QgsMessageBar* mMessageBar;
QgsMapCanvas* mMapCanvas;

};

Expand Down
15 changes: 15 additions & 0 deletions src/gui/qgsattributeform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,15 @@ void QgsAttributeForm::filterTriggered()
setMode( SingleEditMode );
}

void QgsAttributeForm::searchZoomTo()
{
QString filter = createFilterExpression();
if ( filter.isEmpty() )
return;

emit zoomToFeatures( filter );
}

void QgsAttributeForm::filterAndTriggered()
{
QString filter = createFilterExpression();
Expand Down Expand Up @@ -1310,6 +1319,12 @@ void QgsAttributeForm::init()
boxLayout->addWidget( clearButton );
boxLayout->addStretch( 1 );

QPushButton* zoomButton = new QPushButton();
zoomButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
zoomButton->setText( tr( "&Zoom to features" ) );
connect( zoomButton, &QToolButton::clicked, this, &QgsAttributeForm::searchZoomTo );
boxLayout->addWidget( zoomButton );

QToolButton* selectButton = new QToolButton();
selectButton->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
selectButton->setText( tr( "&Select features" ) );
Expand Down
7 changes: 7 additions & 0 deletions src/gui/qgsattributeform.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
*/
void closed();

/**
* Emitted when the user chooses to zoom to a filtered set of features.
* @note added in QGIS 3.0
*/
void zoomToFeatures( const QString& filter );

public slots:

/**
Expand Down Expand Up @@ -250,6 +256,7 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
void filterOrTriggered();
void filterTriggered();

void searchZoomTo();
void searchSetSelection();
void searchAddToSelection();
void searchRemoveFromSelection();
Expand Down
8 changes: 4 additions & 4 deletions src/gui/qgsmapcanvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,10 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! Zooms in/out with a given center
void zoomWithCenter( int x, int y, bool zoomIn );

//! Zooms to feature extent. Adds a small margin around the extent
//! and does a pan if rect is empty (point extent)
void zoomToFeatureExtent( QgsRectangle& rect );

//! Returns whether the scale is locked, so zooming can be performed using magnication.
//! @note added in 2.16
//! @see setScaleLocked()
Expand Down Expand Up @@ -589,10 +593,6 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! called when panning is in action, reset indicates end of panning
void moveCanvasContents( bool reset = false );

//! Zooms to feature extent. Adds a small margin around the extent
//! and does a pan if rect is empty (point extent)
void zoomToFeatureExtent( QgsRectangle& rect );

//! called on resize or changed extent to notify canvas items to change their rectangle
void updateCanvasItemPositions();

Expand Down

0 comments on commit 80b757b

Please sign in to comment.