Skip to content

Commit

Permalink
Fix "zoom" and "flash" features buttons have no effect when opening
Browse files Browse the repository at this point in the history
filter mode in attribute form

(For reference: not a regression -- these buttons were originally
added for the "select by form" dialog only, and they've just never
been hooked up for use inside the attribute form itself!)

Fixes qgis#34506
  • Loading branch information
nyalldawson committed Jun 4, 2020
1 parent 2f36e18 commit fafae5e
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 46 deletions.
47 changes: 47 additions & 0 deletions python/gui/auto_generated/qgsmapcanvasutils.sip.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgsmapcanvasutils.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/




class QgsMapCanvasUtils
{
%Docstring
Utility functions for working with QgsMapCanvas widgets.

.. versionadded:: 3.14
%End

%TypeHeaderCode
#include "qgsmapcanvasutils.h"
%End
public:

static long zoomToMatchingFeatures( QgsMapCanvas *canvas, QgsVectorLayer *layer, const QString &filter );
%Docstring
Zooms a map ``canvas`` to features from the specified ``layer`` which match the given ``filter`` expression string.

The total count of matching features will be returned.
%End

static long flashMatchingFeatures( QgsMapCanvas *canvas, QgsVectorLayer *layer, const QString &filter );
%Docstring
Flashes features from the specified ``layer`` which match the given ``filter`` expression string with a map ``canvas``.

The total count of matching features will be returned.
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgsmapcanvasutils.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
1 change: 1 addition & 0 deletions python/gui/gui_auto.sip
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
%Include auto_generated/qgsmapcanvasitem.sip
%Include auto_generated/qgsmapcanvassnappingutils.sip
%Include auto_generated/qgsmapcanvastracer.sip
%Include auto_generated/qgsmapcanvasutils.sip
%Include auto_generated/qgsmaplayeractionregistry.sip
%Include auto_generated/qgsmaplayercombobox.sip
%Include auto_generated/qgsmaplayerconfigwidget.sip
Expand Down
50 changes: 4 additions & 46 deletions src/app/qgsselectbyformdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include "qgsmessagebar.h"
#include "qgsexpressioncontextutils.h"
#include "qgsgui.h"

#include "qgsmapcanvasutils.h"

QgsSelectByFormDialog::QgsSelectByFormDialog( QgsVectorLayer *layer, const QgsAttributeEditorContext &context, QWidget *parent, Qt::WindowFlags fl )
: QDialog( parent, fl )
Expand Down Expand Up @@ -65,35 +65,11 @@ void QgsSelectByFormDialog::setMapCanvas( QgsMapCanvas *canvas )

void QgsSelectByFormDialog::zoomToFeatures( const QString &filter )
{
QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( mLayer ) );

QgsFeatureRequest request = QgsFeatureRequest().setFilterExpression( filter )
.setExpressionContext( context )
.setNoAttributes();

QgsFeatureIterator features = mLayer->getFeatures( request );

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

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

const long featureCount = QgsMapCanvasUtils::zoomToMatchingFeatures( mMapCanvas, mLayer, filter );
QgsSettings settings;
int timeout = settings.value( QStringLiteral( "qgis/messageTimeout" ), 5 ).toInt();
if ( featureCount > 0 )
{
mMapCanvas->zoomToFeatureExtent( bbox );
if ( mMessageBar )
{
mMessageBar->pushMessage( QString(),
Expand All @@ -113,28 +89,10 @@ void QgsSelectByFormDialog::zoomToFeatures( const QString &filter )

void QgsSelectByFormDialog::flashFeatures( const QString &filter )
{
QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( mLayer ) );

QgsFeatureRequest request = QgsFeatureRequest().setFilterExpression( filter )
.setExpressionContext( context )
.setNoAttributes();

QgsFeatureIterator features = mLayer->getFeatures( request );
QgsFeature feat;
QList< QgsGeometry > geoms;
while ( features.nextFeature( feat ) )
{
if ( feat.hasGeometry() )
geoms << feat.geometry();
}

const long featureCount = QgsMapCanvasUtils::flashMatchingFeatures( mMapCanvas, mLayer, filter );
QgsSettings settings;
int timeout = settings.value( QStringLiteral( "qgis/messageTimeout" ), 5 ).toInt();
if ( !geoms.empty() )
{
mMapCanvas->flashGeometries( geoms, mLayer->crs() );
}
else if ( mMessageBar )
if ( featureCount == 0 && mMessageBar )
{
mMessageBar->pushMessage( QString(),
tr( "No matching features found" ),
Expand Down
2 changes: 2 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ SET(QGIS_GUI_SRCS
qgsmapcanvasmap.cpp
qgsmapcanvassnappingutils.cpp
qgsmapcanvastracer.cpp
qgsmapcanvasutils.cpp
qgsmaplayeractionregistry.cpp
qgsmaplayercombobox.cpp
qgsmaplayerconfigwidgetfactory.cpp
Expand Down Expand Up @@ -681,6 +682,7 @@ SET(QGIS_GUI_HDRS
qgsmapcanvasmap.h
qgsmapcanvassnappingutils.h
qgsmapcanvastracer.h
qgsmapcanvasutils.h
qgsmaplayeractionregistry.h
qgsmaplayercombobox.h
qgsmaplayerconfigwidget.h
Expand Down
16 changes: 16 additions & 0 deletions src/gui/attributetable/qgsdualview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "qgsexpressioncontextutils.h"
#include "qgsshortcutsmanager.h"
#include "qgsfieldconditionalformatwidget.h"
#include "qgsmapcanvasutils.h"


QgsDualView::QgsDualView( QWidget *parent )
Expand Down Expand Up @@ -149,6 +150,21 @@ void QgsDualView::init( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas, const Qg
connect( mAttributeForm, &QgsAttributeForm::widgetValueChanged, this, &QgsDualView::featureFormAttributeChanged );
connect( mAttributeForm, &QgsAttributeForm::modeChanged, this, &QgsDualView::formModeChanged );
connect( mAttributeForm, &QgsAttributeForm::filterExpressionSet, this, &QgsDualView::filterExpressionSet );
connect( mAttributeForm, &QgsAttributeForm::flashFeatures, this, [ = ]( const QString & filter )
{
if ( QgsMapCanvas *canvas = mFilterModel->mapCanvas() )
{
QgsMapCanvasUtils::flashMatchingFeatures( canvas, mLayer, filter );
}
} );
connect( mAttributeForm, &QgsAttributeForm::zoomToFeatures, this, [ = ]( const QString & filter )
{
if ( QgsMapCanvas *canvas = mFilterModel->mapCanvas() )
{
QgsMapCanvasUtils::zoomToMatchingFeatures( canvas, mLayer, filter );
}
} );

connect( mMasterModel, &QgsAttributeTableModel::modelChanged, mAttributeForm, &QgsAttributeForm::refreshFeature );
connect( mFilterModel, &QgsAttributeTableFilterModel::sortColumnChanged, this, &QgsDualView::onSortColumnChanged );

Expand Down
76 changes: 76 additions & 0 deletions src/gui/qgsmapcanvasutils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/***************************************************************************
qgsmapcanvasutils.cpp
-------------------
begin : June 2020
copyright : (C) 2020 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 "qgsmapcanvasutils.h"
#include "qgsmapcanvas.h"
#include "qgsvectorlayer.h"
#include "qgsexpressioncontextutils.h"

long QgsMapCanvasUtils::zoomToMatchingFeatures( QgsMapCanvas *canvas, QgsVectorLayer *layer, const QString &filter )
{
QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );

QgsFeatureRequest request = QgsFeatureRequest().setFilterExpression( filter )
.setExpressionContext( context )
.setNoAttributes();

QgsFeatureIterator features = layer->getFeatures( request );

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

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

if ( featureCount > 0 )
{
canvas->zoomToFeatureExtent( bbox );
}
return featureCount;
}

long QgsMapCanvasUtils::flashMatchingFeatures( QgsMapCanvas *canvas, QgsVectorLayer *layer, const QString &filter )
{
QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );

QgsFeatureRequest request = QgsFeatureRequest().setFilterExpression( filter )
.setExpressionContext( context )
.setNoAttributes();

QgsFeatureIterator features = layer->getFeatures( request );
QgsFeature feat;
QList< QgsGeometry > geoms;
while ( features.nextFeature( feat ) )
{
if ( feat.hasGeometry() )
geoms << feat.geometry();
}

if ( !geoms.empty() )
{
canvas->flashGeometries( geoms, layer->crs() );
}
return geoms.size();
}
52 changes: 52 additions & 0 deletions src/gui/qgsmapcanvasutils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/***************************************************************************
qgsmapcanvasutils.h
-------------------
begin : June 2020
copyright : (C) 2020 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 QGSMAPCANVASUTILS_H
#define QGSMAPCANVASUTILS_H

#include "qgis_gui.h"

class QgsMapCanvas;
class QgsVectorLayer;
class QString;

/**
* \ingroup gui
* \class QgsMapCanvasUtils
* Utility functions for working with QgsMapCanvas widgets.
* \since QGIS 3.14
*/
class GUI_EXPORT QgsMapCanvasUtils
{

public:

/**
* Zooms a map \a canvas to features from the specified \a layer which match the given \a filter expression string.
*
* The total count of matching features will be returned.
*/
static long zoomToMatchingFeatures( QgsMapCanvas *canvas, QgsVectorLayer *layer, const QString &filter );

/**
* Flashes features from the specified \a layer which match the given \a filter expression string with a map \a canvas.
*
* The total count of matching features will be returned.
*/
static long flashMatchingFeatures( QgsMapCanvas *canvas, QgsVectorLayer *layer, const QString &filter );

};

#endif //QGSMAPCANVASUTILS_H

0 comments on commit fafae5e

Please sign in to comment.