Skip to content
Permalink
Browse files

avoid freeze with multiple layers locator search (#8650)

* 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 969b789 commit 6d34089a82c50bb454b0fccf23f78fa18f7befc5
Showing with 25 additions and 18 deletions.
  1. +20 −16 src/app/locator/qgsinbuiltlocatorfilters.cpp
  2. +5 −2 src/app/locator/qgsinbuiltlocatorfilters.h
@@ -28,6 +28,8 @@
#include "qgslayoutmanager.h"
#include "qgsmapcanvas.h"
#include "qgsfeatureaction.h"
#include "qgsvectorlayerfeatureiterator.h"


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

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

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

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

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

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.icon = preparedLayer.layerIcon;
result.userData = QVariantList() << f.id() << preparedLayer->layerId;
result.icon = preparedLayer->layerIcon;
result.score = static_cast< double >( string.length() ) / result.displayString.size();

result.actions << QgsLocatorResult::ResultAction( OpenForm, tr( "Open form…" ) );
@@ -22,6 +22,8 @@
#include "qgslocatorfilter.h"
#include "qgsexpressioncontext.h"
#include "qgsfeatureiterator.h"
#include "qgsvectorlayerfeatureiterator.h"


class QAction;

@@ -130,7 +132,8 @@ class APP_EXPORT QgsAllLayersFeaturesLocatorFilter : public QgsLocatorFilter
public:
QgsExpression expression;
QgsExpressionContext context;
QgsFeatureIterator iterator;
std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
QgsFeatureRequest request;
QString layerName;
QString layerId;
QIcon layerIcon;
@@ -151,7 +154,7 @@ class APP_EXPORT QgsAllLayersFeaturesLocatorFilter : public QgsLocatorFilter
private:
int mMaxResultsPerLayer = 6;
int mMaxTotalResults = 12;
QList<PreparedLayer> mPreparedLayers;
QList<std::shared_ptr<PreparedLayer>> mPreparedLayers;


};

0 comments on commit 6d34089

Please sign in to comment.
You can’t perform that action at this time.