Skip to content

Commit 6d34089

Browse files
authoredDec 12, 2018
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
1 parent 969b789 commit 6d34089

File tree

2 files changed

+25
-18
lines changed

2 files changed

+25
-18
lines changed
 

‎src/app/locator/qgsinbuiltlocatorfilters.cpp

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "qgslayoutmanager.h"
2929
#include "qgsmapcanvas.h"
3030
#include "qgsfeatureaction.h"
31+
#include "qgsvectorlayerfeatureiterator.h"
32+
3133

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

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

367-
PreparedLayer preparedLayer;
368-
preparedLayer.expression = expression;
369-
preparedLayer.context = context;
370-
preparedLayer.layerId = layer->id();
371-
preparedLayer.layerName = layer->name();
372-
preparedLayer.iterator = layer->getFeatures( req );
373-
preparedLayer.layerIcon = QgsMapLayerModel::iconForLayer( layer );
369+
std::shared_ptr<PreparedLayer> preparedLayer( new PreparedLayer() );
370+
preparedLayer->expression = expression;
371+
preparedLayer->context = context;
372+
preparedLayer->layerId = layer->id();
373+
preparedLayer->layerName = layer->name();
374+
preparedLayer->featureSource.reset( new QgsVectorLayerFeatureSource( layer ) );
375+
preparedLayer->request = req;
376+
preparedLayer->layerIcon = QgsMapLayerModel::iconForLayer( layer );
374377

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

385388
// we cannot used const loop since iterator::nextFeature is not const
386-
for ( PreparedLayer preparedLayer : mPreparedLayers )
389+
for ( auto preparedLayer : qgis::as_const( mPreparedLayers ) )
387390
{
388391
foundInCurrentLayer = 0;
389-
while ( preparedLayer.iterator.nextFeature( f ) )
392+
QgsFeatureIterator it = preparedLayer->featureSource->getFeatures( preparedLayer->request );
393+
while ( it.nextFeature( f ) )
390394
{
391395
if ( feedback->isCanceled() )
392396
return;
393397

394398
QgsLocatorResult result;
395-
result.group = preparedLayer.layerName;
399+
result.group = preparedLayer->layerName;
396400

397-
preparedLayer.context.setFeature( f );
401+
preparedLayer->context.setFeature( f );
398402

399-
result.displayString = preparedLayer.expression.evaluate( &( preparedLayer.context ) ).toString();
403+
result.displayString = preparedLayer->expression.evaluate( &( preparedLayer->context ) ).toString();
400404

401-
result.userData = QVariantList() << f.id() << preparedLayer.layerId;
402-
result.icon = preparedLayer.layerIcon;
405+
result.userData = QVariantList() << f.id() << preparedLayer->layerId;
406+
result.icon = preparedLayer->layerIcon;
403407
result.score = static_cast< double >( string.length() ) / result.displayString.size();
404408

405409
result.actions << QgsLocatorResult::ResultAction( OpenForm, tr( "Open form…" ) );

‎src/app/locator/qgsinbuiltlocatorfilters.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include "qgslocatorfilter.h"
2323
#include "qgsexpressioncontext.h"
2424
#include "qgsfeatureiterator.h"
25+
#include "qgsvectorlayerfeatureiterator.h"
26+
2527

2628
class QAction;
2729

@@ -130,7 +132,8 @@ class APP_EXPORT QgsAllLayersFeaturesLocatorFilter : public QgsLocatorFilter
130132
public:
131133
QgsExpression expression;
132134
QgsExpressionContext context;
133-
QgsFeatureIterator iterator;
135+
std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
136+
QgsFeatureRequest request;
134137
QString layerName;
135138
QString layerId;
136139
QIcon layerIcon;
@@ -151,7 +154,7 @@ class APP_EXPORT QgsAllLayersFeaturesLocatorFilter : public QgsLocatorFilter
151154
private:
152155
int mMaxResultsPerLayer = 6;
153156
int mMaxTotalResults = 12;
154-
QList<PreparedLayer> mPreparedLayers;
157+
QList<std::shared_ptr<PreparedLayer>> mPreparedLayers;
155158

156159

157160
};

0 commit comments

Comments
 (0)
Please sign in to comment.