Skip to content
Permalink
Browse files

[FEATURE] add new locator filter searching across all layers in displ…

…ay expression
  • Loading branch information
3nids committed Sep 7, 2018
1 parent d6b2537 commit d54b7b1d4deac9d4fb86ed7c2e4585f8d5e44330
@@ -191,6 +191,10 @@ void QgsActionLocatorFilter::searchActions( const QString &string, QWidget *pare
}
}

//
// QgsActiveLayerFeaturesLocatorFilter
//

QgsActiveLayerFeaturesLocatorFilter::QgsActiveLayerFeaturesLocatorFilter( QObject *parent )
: QgsLocatorFilter( parent )
{
@@ -298,6 +302,106 @@ void QgsActiveLayerFeaturesLocatorFilter::triggerResult( const QgsLocatorResult
QgisApp::instance()->mapCanvas()->zoomToFeatureIds( layer, QgsFeatureIds() << id );
}

//
// QgsAllLayersFeaturesLocatorFilter
//

QgsAllLayersFeaturesLocatorFilter::QgsAllLayersFeaturesLocatorFilter( QObject *parent )
: QgsLocatorFilter( parent )
{
setUseWithoutPrefix( false );
}

QgsAllLayersFeaturesLocatorFilter *QgsAllLayersFeaturesLocatorFilter::clone() const
{
return new QgsAllLayersFeaturesLocatorFilter();
}

void QgsAllLayersFeaturesLocatorFilter::prepare( const QString &string, const QgsLocatorContext & )
{
if ( string.length() < 3 )
return;

const QMap<QString, QgsMapLayer *> layers = QgsProject::instance()->mapLayers();
for ( auto it = layers.constBegin(); it != layers.constEnd(); ++it )
{
QgsVectorLayer *layer = qobject_cast< QgsVectorLayer *>( it.value() );
if ( !layer )
continue;

QgsExpression expression( layer->displayExpression() );
QgsExpressionContext context;
context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
expression.prepare( &context );

QgsFeatureRequest req;
req.setFlags( QgsFeatureRequest::NoGeometry );
req.setFilterExpression( QStringLiteral( "%1 ILIKE '%%2%'" )
.arg( layer->displayExpression() )
.arg( 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 );

mPreparedLayers.append( preparedLayer );
}
}

void QgsAllLayersFeaturesLocatorFilter::fetchResults( const QString &string, const QgsLocatorContext &, QgsFeedback *feedback )
{
int foundInCurrentLayer;
int foundInTotal = 0;
QgsFeature f;

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

QgsLocatorResult result;
result.group = preparedLayer.layerName;

preparedLayer.context.setFeature( f );

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

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

foundInCurrentLayer++;
foundInTotal++;
if ( foundInCurrentLayer >= mMaxResultsPerLayer )
break;
}
if ( foundInTotal >= mMaxTotalResults )
break;
}
}

void QgsAllLayersFeaturesLocatorFilter::triggerResult( const QgsLocatorResult &result )
{
QVariantList dataList = result.userData.toList();
QgsFeatureId id = dataList.at( 0 ).toLongLong();
QString layerId = dataList.at( 1 ).toString();
QgsVectorLayer *layer = qobject_cast< QgsVectorLayer *>( QgsProject::instance()->mapLayer( layerId ) );
if ( !layer )
return;

QgisApp::instance()->mapCanvas()->zoomToFeatureIds( layer, QgsFeatureIds() << id );
}

//
// QgsExpressionCalculatorLocatorFilter
//
@@ -113,6 +113,41 @@ class QgsActiveLayerFeaturesLocatorFilter : public QgsLocatorFilter
QIcon mLayerIcon;
};

class QgsAllLayersFeaturesLocatorFilter : public QgsLocatorFilter
{
Q_OBJECT

public:
struct PreparedLayer
{
public:
QgsExpression expression;
QgsExpressionContext context;
QgsFeatureIterator iterator;
QString layerName;
QString layerId;
QIcon layerIcon;
} ;

QgsAllLayersFeaturesLocatorFilter( QObject *parent = nullptr );
QgsAllLayersFeaturesLocatorFilter *clone() const override;
QString name() const override { return QStringLiteral( "allfeatures" ); }
QString displayName() const override { return tr( "Features In All Layers" ); }
Priority priority() const override { return Medium; }
QString prefix() const override { return QStringLiteral( "a" ); }

void prepare( const QString &string, const QgsLocatorContext &context ) override;
void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
void triggerResult( const QgsLocatorResult &result ) override;

private:
int mMaxResultsPerLayer = 6;
int mMaxTotalResults = 12;
QList<PreparedLayer> mPreparedLayers;


};

class APP_EXPORT QgsExpressionCalculatorLocatorFilter : public QgsLocatorFilter
{
Q_OBJECT
@@ -3121,6 +3121,7 @@ void QgisApp::createStatusBar()

mLocatorWidget->locator()->registerFilter( new QgsActionLocatorFilter( actionObjects ) );
mLocatorWidget->locator()->registerFilter( new QgsActiveLayerFeaturesLocatorFilter() );
mLocatorWidget->locator()->registerFilter( new QgsAllLayersFeaturesLocatorFilter() );
mLocatorWidget->locator()->registerFilter( new QgsExpressionCalculatorLocatorFilter() );
mLocatorWidget->locator()->registerFilter( new QgsBookmarkLocatorFilter() );
mLocatorWidget->locator()->registerFilter( new QgsSettingsLocatorFilter() );
@@ -25,6 +25,7 @@ const QList<QString> QgsLocator::CORE_FILTERS = QList<QString>() << QStringLiter
<< QStringLiteral( "layertree" )
<< QStringLiteral( "layouts" )
<< QStringLiteral( "features" )
<< QStringLiteral( "allfeatures" )
<< QStringLiteral( "calculator" )
<< QStringLiteral( "bookmarks" )
<< QStringLiteral( "optionpages" );

0 comments on commit d54b7b1

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