Skip to content

Commit 0a01725

Browse files
authored
avoid freeze with multiple layers locator search (#8650) (#8659)
* 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 2f7d634 commit 0a01725

File tree

2 files changed

+27
-20
lines changed

2 files changed

+27
-20
lines changed

src/app/locator/qgsinbuiltlocatorfilters.cpp

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* *
1616
***************************************************************************/
1717

18+
#include <QToolButton>
19+
#include <QClipboard>
1820

1921
#include "qgsinbuiltlocatorfilters.h"
2022
#include "qgsproject.h"
@@ -25,8 +27,8 @@
2527
#include "qgsmaplayermodel.h"
2628
#include "qgslayoutmanager.h"
2729
#include "qgsmapcanvas.h"
28-
#include <QToolButton>
29-
#include <QClipboard>
30+
#include "qgsvectorlayerfeatureiterator.h"
31+
3032

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

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

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

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

384387
// we cannot used const loop since iterator::nextFeature is not const
385-
for ( PreparedLayer preparedLayer : mPreparedLayers )
388+
for ( auto preparedLayer : qgis::as_const( mPreparedLayers ) )
386389
{
387390
foundInCurrentLayer = 0;
388-
while ( preparedLayer.iterator.nextFeature( f ) )
391+
QgsFeatureIterator it = preparedLayer->featureSource->getFeatures( preparedLayer->request );
392+
while ( it.nextFeature( f ) )
389393
{
390394
if ( feedback->isCanceled() )
391395
return;
392396

393397
QgsLocatorResult result;
394-
result.group = preparedLayer.layerName;
398+
result.group = preparedLayer->layerName;
395399

396-
preparedLayer.context.setFeature( f );
400+
preparedLayer->context.setFeature( f );
397401

398-
result.displayString = preparedLayer.expression.evaluate( &( preparedLayer.context ) ).toString();
402+
result.displayString = preparedLayer->expression.evaluate( &( preparedLayer->context ) ).toString();
399403

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

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

@@ -124,7 +126,8 @@ class APP_EXPORT QgsAllLayersFeaturesLocatorFilter : public QgsLocatorFilter
124126
public:
125127
QgsExpression expression;
126128
QgsExpressionContext context;
127-
QgsFeatureIterator iterator;
129+
std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
130+
QgsFeatureRequest request;
128131
QString layerName;
129132
QString layerId;
130133
QIcon layerIcon;
@@ -144,7 +147,7 @@ class APP_EXPORT QgsAllLayersFeaturesLocatorFilter : public QgsLocatorFilter
144147
private:
145148
int mMaxResultsPerLayer = 6;
146149
int mMaxTotalResults = 12;
147-
QList<PreparedLayer> mPreparedLayers;
150+
QList<std::shared_ptr<PreparedLayer>> mPreparedLayers;
148151

149152

150153
};

0 commit comments

Comments
 (0)