Skip to content
Permalink
Browse files

[FEATURE] active layer locator filter field name restriction

the filter can now restrict the search to a specific field by typing @+field_name

auto-completion is provided for the field names
  • Loading branch information
3nids committed Sep 8, 2020
1 parent 002a703 commit ccb87207ae0034b7f89e7484d78f30e5e41f4df4
Showing with 51 additions and 13 deletions.
  1. +43 −11 src/app/locator/qgsinbuiltlocatorfilters.cpp
  2. +8 −2 src/app/locator/qgsinbuiltlocatorfilters.h
@@ -244,35 +244,58 @@ QgsActiveLayerFeaturesLocatorFilter *QgsActiveLayerFeaturesLocatorFilter::clone(
return new QgsActiveLayerFeaturesLocatorFilter();
}

void QgsActiveLayerFeaturesLocatorFilter::prepare( const QString &string, const QgsLocatorContext &context )
QString QgsActiveLayerFeaturesLocatorFilter::fieldRestriction( QString &searchString ) const
{
QString _fieldRestriction;
if ( searchString.startsWith( '@' ) )
{
_fieldRestriction = searchString.left( std::max( searchString.indexOf( ' ' ), 0 ) ).remove( 0, 1 );
searchString = searchString.mid( _fieldRestriction.length() + 2 );
}
return _fieldRestriction;
}

QStringList QgsActiveLayerFeaturesLocatorFilter::prepare( const QString &string, const QgsLocatorContext &context )
{
// Normally skip very short search strings, unless when specifically searching using this filter
if ( string.length() < 3 && !context.usingPrefix )
return;
return QStringList();

QgsSettings settings;
mMaxTotalResults = settings.value( QStringLiteral( "locator_filters/active_layer_features/limit_global" ), 30, QgsSettings::App ).toInt();

bool allowNumeric = false;
double numericalValue = string.toDouble( &allowNumeric );

QgsVectorLayer *layer = qobject_cast< QgsVectorLayer *>( QgisApp::instance()->activeLayer() );
if ( !layer )
return;
return QStringList();

mDispExpression = QgsExpression( layer->displayExpression() );
mContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
mDispExpression.prepare( &mContext );

// determine if search is restricted to a specific field
QString searchString = string;
QString _fieldRestriction = fieldRestriction( searchString );
bool allowNumeric = false;
double numericalValue = searchString.toDouble( &allowNumeric );

// build up request expression
QStringList expressionParts;
QStringList completionList;
const QgsFields fields = layer->fields();
QgsAttributeList subsetOfAttributes;
for ( const QgsField &field : fields )
{
if ( !_fieldRestriction.isEmpty() && !field.name().startsWith( _fieldRestriction ) )
continue;

if ( !_fieldRestriction.isEmpty() )
subsetOfAttributes << layer->fields().indexFromName( field.name() );

completionList.append( QStringLiteral( "@%1 " ).arg( field.name() ) );
if ( field.type() == QVariant::String )
{
expressionParts << QStringLiteral( "%1 ILIKE '%%2%'" ).arg( QgsExpression::quotedColumnRef( field.name() ),
string );
searchString );
}
else if ( allowNumeric && field.isNumeric() )
{
@@ -285,6 +308,9 @@ void QgsActiveLayerFeaturesLocatorFilter::prepare( const QString &string, const
QgsFeatureRequest req;
req.setFlags( QgsFeatureRequest::NoGeometry );
req.setFilterExpression( expression );
if ( !_fieldRestriction.isEmpty() )
req.setSubsetOfAttributes( subsetOfAttributes );

req.setLimit( 30 );
mIterator = layer->getFeatures( req );

@@ -295,12 +321,16 @@ void QgsActiveLayerFeaturesLocatorFilter::prepare( const QString &string, const
{
mAttributeAliases.append( layer->attributeDisplayName( idx ) );
}

return completionList;
}

void QgsActiveLayerFeaturesLocatorFilter::fetchResults( const QString &string, const QgsLocatorContext &, QgsFeedback *feedback )
{
int found = 0;
QgsFeature f;
QString searchString = string;
fieldRestriction( searchString );

while ( mIterator.nextFeature( f ) )
{
@@ -317,7 +347,7 @@ void QgsActiveLayerFeaturesLocatorFilter::fetchResults( const QString &string, c
for ( const QVariant &var : attributes )
{
QString attrString = var.toString();
if ( attrString.contains( string, Qt::CaseInsensitive ) )
if ( attrString.contains( searchString, Qt::CaseInsensitive ) )
{
if ( idx < mAttributeAliases.count() )
result.displayString = QStringLiteral( "%1 (%2)" ).arg( attrString, mAttributeAliases[idx] );
@@ -334,7 +364,7 @@ void QgsActiveLayerFeaturesLocatorFilter::fetchResults( const QString &string, c

result.userData = QVariantList() << f.id() << mLayerId;
result.icon = mLayerIcon;
result.score = static_cast< double >( string.length() ) / result.displayString.size();
result.score = static_cast< double >( searchString.length() ) / result.displayString.size();
emit resultFetched( result );

found++;
@@ -395,11 +425,11 @@ QgsAllLayersFeaturesLocatorFilter *QgsAllLayersFeaturesLocatorFilter::clone() co
return new QgsAllLayersFeaturesLocatorFilter();
}

void QgsAllLayersFeaturesLocatorFilter::prepare( const QString &string, const QgsLocatorContext &context )
QStringList QgsAllLayersFeaturesLocatorFilter::prepare( const QString &string, const QgsLocatorContext &context )
{
// Normally skip very short search strings, unless when specifically searching using this filter
if ( string.length() < 3 && !context.usingPrefix )
return;
return QStringList();

QgsSettings settings;
mMaxTotalResults = settings.value( "locator_filters/all_layers_features/limit_global", 15, QgsSettings::App ).toInt();
@@ -445,6 +475,8 @@ void QgsAllLayersFeaturesLocatorFilter::prepare( const QString &string, const Qg

mPreparedLayers.append( preparedLayer );
}

return QStringList();
}

void QgsAllLayersFeaturesLocatorFilter::fetchResults( const QString &string, const QgsLocatorContext &, QgsFeedback *feedback )
@@ -102,14 +102,20 @@ class APP_EXPORT QgsActiveLayerFeaturesLocatorFilter : public QgsLocatorFilter
Priority priority() const override { return Medium; }
QString prefix() const override { return QStringLiteral( "f" ); }

void prepare( const QString &string, const QgsLocatorContext &context ) override;
QStringList 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;
bool hasConfigWidget() const override {return true;}
void openConfigWidget( QWidget *parent ) override;

private:

/**
* Returns the field restriction if defined (starting with @)
* The \a searchString is modified acccordingly by removing the field restriction
*/
QString fieldRestriction( QString &searchString ) const;

QgsExpression mDispExpression;
QgsExpressionContext mContext;
QgsFeatureIterator mIterator;
@@ -150,7 +156,7 @@ class APP_EXPORT QgsAllLayersFeaturesLocatorFilter : public QgsLocatorFilter
Priority priority() const override { return Medium; }
QString prefix() const override { return QStringLiteral( "af" ); }

void prepare( const QString &string, const QgsLocatorContext &context ) override;
QStringList 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;
void triggerResultFromAction( const QgsLocatorResult &result, const int actionId ) override;

0 comments on commit ccb8720

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