Skip to content

Commit

Permalink
avoid freeze with multiple layers locator search (#8650) (#8659)
Browse files Browse the repository at this point in the history
* avoid freeze with multiple layers locator search

if the project had many searchable layers, a freeze occured when running the all features locator filter
the feature iterator was created in prepare (main thread) and the maximum number of connection was reached

* fix leak + clear former prepared layers

* avoid copy in loop

* declare ptr earlier
  • Loading branch information
3nids committed Dec 12, 2018
1 parent 2f7d634 commit 0a01725
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 20 deletions.
40 changes: 22 additions & 18 deletions src/app/locator/qgsinbuiltlocatorfilters.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* * * *
***************************************************************************/ ***************************************************************************/


#include <QToolButton>
#include <QClipboard>


#include "qgsinbuiltlocatorfilters.h" #include "qgsinbuiltlocatorfilters.h"
#include "qgsproject.h" #include "qgsproject.h"
Expand All @@ -25,8 +27,8 @@
#include "qgsmaplayermodel.h" #include "qgsmaplayermodel.h"
#include "qgslayoutmanager.h" #include "qgslayoutmanager.h"
#include "qgsmapcanvas.h" #include "qgsmapcanvas.h"
#include <QToolButton> #include "qgsvectorlayerfeatureiterator.h"
#include <QClipboard>


QgsLayerTreeLocatorFilter::QgsLayerTreeLocatorFilter( QObject *parent ) QgsLayerTreeLocatorFilter::QgsLayerTreeLocatorFilter( QObject *parent )
: QgsLocatorFilter( parent ) : QgsLocatorFilter( parent )
Expand Down Expand Up @@ -342,6 +344,7 @@ void QgsAllLayersFeaturesLocatorFilter::prepare( const QString &string, const Qg
if ( string.length() < 3 && !context.usingPrefix ) if ( string.length() < 3 && !context.usingPrefix )
return; return;


mPreparedLayers.clear();
const QMap<QString, QgsMapLayer *> layers = QgsProject::instance()->mapLayers(); const QMap<QString, QgsMapLayer *> layers = QgsProject::instance()->mapLayers();
for ( auto it = layers.constBegin(); it != layers.constEnd(); ++it ) for ( auto it = layers.constBegin(); it != layers.constEnd(); ++it )
{ {
Expand All @@ -359,17 +362,17 @@ void QgsAllLayersFeaturesLocatorFilter::prepare( const QString &string, const Qg
if ( !expression.needsGeometry() ) if ( !expression.needsGeometry() )
req.setFlags( QgsFeatureRequest::NoGeometry ); req.setFlags( QgsFeatureRequest::NoGeometry );
req.setFilterExpression( QStringLiteral( "%1 ILIKE '%%2%'" ) req.setFilterExpression( QStringLiteral( "%1 ILIKE '%%2%'" )
.arg( layer->displayExpression(), .arg( layer->displayExpression(), string ) );
string ) );
req.setLimit( 30 ); req.setLimit( 30 );


PreparedLayer preparedLayer; std::shared_ptr<PreparedLayer> preparedLayer( new PreparedLayer() );
preparedLayer.expression = expression; preparedLayer->expression = expression;
preparedLayer.context = context; preparedLayer->context = context;
preparedLayer.layerId = layer->id(); preparedLayer->layerId = layer->id();
preparedLayer.layerName = layer->name(); preparedLayer->layerName = layer->name();
preparedLayer.iterator = layer->getFeatures( req ); preparedLayer->featureSource.reset( new QgsVectorLayerFeatureSource( layer ) );
preparedLayer.layerIcon = QgsMapLayerModel::iconForLayer( layer ); preparedLayer->request = req;
preparedLayer->layerIcon = QgsMapLayerModel::iconForLayer( layer );


mPreparedLayers.append( preparedLayer ); mPreparedLayers.append( preparedLayer );
} }
Expand All @@ -382,23 +385,24 @@ void QgsAllLayersFeaturesLocatorFilter::fetchResults( const QString &string, con
QgsFeature f; QgsFeature f;


// we cannot used const loop since iterator::nextFeature is not const // we cannot used const loop since iterator::nextFeature is not const
for ( PreparedLayer preparedLayer : mPreparedLayers ) for ( auto preparedLayer : qgis::as_const( mPreparedLayers ) )
{ {
foundInCurrentLayer = 0; foundInCurrentLayer = 0;
while ( preparedLayer.iterator.nextFeature( f ) ) QgsFeatureIterator it = preparedLayer->featureSource->getFeatures( preparedLayer->request );
while ( it.nextFeature( f ) )
{ {
if ( feedback->isCanceled() ) if ( feedback->isCanceled() )
return; return;


QgsLocatorResult result; QgsLocatorResult result;
result.group = preparedLayer.layerName; result.group = preparedLayer->layerName;


preparedLayer.context.setFeature( f ); preparedLayer->context.setFeature( f );


result.displayString = preparedLayer.expression.evaluate( &( preparedLayer.context ) ).toString(); result.displayString = preparedLayer->expression.evaluate( &( preparedLayer->context ) ).toString();


result.userData = QVariantList() << f.id() << preparedLayer.layerId; result.userData = QVariantList() << f.id() << preparedLayer->layerId;
result.icon = preparedLayer.layerIcon; result.icon = preparedLayer->layerIcon;
result.score = static_cast< double >( string.length() ) / result.displayString.size(); result.score = static_cast< double >( string.length() ) / result.displayString.size();
emit resultFetched( result ); emit resultFetched( result );


Expand Down
7 changes: 5 additions & 2 deletions src/app/locator/qgsinbuiltlocatorfilters.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include "qgslocatorfilter.h" #include "qgslocatorfilter.h"
#include "qgsexpressioncontext.h" #include "qgsexpressioncontext.h"
#include "qgsfeatureiterator.h" #include "qgsfeatureiterator.h"
#include "qgsvectorlayerfeatureiterator.h"



class QAction; class QAction;


Expand Down Expand Up @@ -124,7 +126,8 @@ class APP_EXPORT QgsAllLayersFeaturesLocatorFilter : public QgsLocatorFilter
public: public:
QgsExpression expression; QgsExpression expression;
QgsExpressionContext context; QgsExpressionContext context;
QgsFeatureIterator iterator; std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
QgsFeatureRequest request;
QString layerName; QString layerName;
QString layerId; QString layerId;
QIcon layerIcon; QIcon layerIcon;
Expand All @@ -144,7 +147,7 @@ class APP_EXPORT QgsAllLayersFeaturesLocatorFilter : public QgsLocatorFilter
private: private:
int mMaxResultsPerLayer = 6; int mMaxResultsPerLayer = 6;
int mMaxTotalResults = 12; int mMaxTotalResults = 12;
QList<PreparedLayer> mPreparedLayers; QList<std::shared_ptr<PreparedLayer>> mPreparedLayers;




}; };
Expand Down

0 comments on commit 0a01725

Please sign in to comment.