Skip to content

Commit

Permalink
[FEATURE] Active layer feature locator filter
Browse files Browse the repository at this point in the history
Searches for matching attributes in any field from the current
active layer.
  • Loading branch information
nyalldawson committed Jun 1, 2017
1 parent 5077e12 commit 55ed6f9
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 4 deletions.
78 changes: 78 additions & 0 deletions src/app/locator/qgsinbuiltlocatorfilters.cpp
Expand Up @@ -25,6 +25,7 @@
#include "qgsmaplayermodel.h"
#include "qgscomposition.h"
#include "qgslayoutmanager.h"
#include "qgsmapcanvas.h"
#include <QToolButton>

QgsLayerTreeLocatorFilter::QgsLayerTreeLocatorFilter( QObject *parent )
Expand Down Expand Up @@ -163,3 +164,80 @@ void QgsActionLocatorFilter::searchActions( const QString &string, QWidget *pare
}
}
}

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

void QgsActiveLayerFeaturesLocatorFilter::fetchResults( const QString &string, const QgsLocatorContext &, QgsFeedback *feedback )
{
if ( string.length() < 3 )
return;

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

int i = 0;
int found = 0;
QgsExpression dispExpression( layer->displayExpression() );
QgsExpressionContext context;
context.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( layer ) );
dispExpression.prepare( &context );

Q_FOREACH ( const QgsField &field, layer->fields() )
{
if ( feedback->isCanceled() )
return;

QString exp = QStringLiteral( "%1 ILIKE '%%2%'" ).arg( QgsExpression::quotedColumnRef( field.name() ),
string );
QgsFeatureRequest req;
req.setFlags( QgsFeatureRequest::NoGeometry );
QStringList attrs;
attrs << field.name();
attrs.append( dispExpression.referencedColumns().toList() );
req.setSubsetOfAttributes( attrs, layer->fields() );
req.setFilterExpression( exp );
req.setLimit( 30 );
QgsFeature f;
QgsFeatureIterator it = layer->getFeatures( req );
while ( it.nextFeature( f ) )
{
if ( feedback->isCanceled() )
return;

QgsLocatorResult result;
result.filter = this;

context.setFeature( f );
result.displayString = dispExpression.evaluate( &context ).toString();
if ( result.displayString.isEmpty() )
result.displayString = f.attribute( i ).toString();
else
result.description = f.attribute( i ).toString();

result.userData = f.id();
result.icon = QgsMapLayerModel::iconForLayer( layer );
result.score = static_cast< double >( string.length() ) / f.attribute( i ).toString().size();
emit resultFetched( result );

found++;
if ( found >= 30 )
return;
}
i++;
}
}

void QgsActiveLayerFeaturesLocatorFilter::triggerResult( const QgsLocatorResult &result )
{
QgsFeatureId id = result.userData.toLongLong();
QgsVectorLayer *layer = qobject_cast< QgsVectorLayer *>( QgisApp::instance()->activeLayer() );
if ( !layer )
return;

QgisApp::instance()->mapCanvas()->zoomToFeatureIds( layer, QgsFeatureIds() << id );
}
17 changes: 17 additions & 0 deletions src/app/locator/qgsinbuiltlocatorfilters.h
Expand Up @@ -77,6 +77,23 @@ class QgsActionLocatorFilter : public QgsLocatorFilter

};

class QgsActiveLayerFeaturesLocatorFilter : public QgsLocatorFilter
{
Q_OBJECT

public:

QgsActiveLayerFeaturesLocatorFilter( QObject *parent = nullptr );
virtual QString name() const override { return QStringLiteral( "features" ); }
virtual QString displayName() const override { return tr( "Active Layer Features" ); }
virtual Priority priority() const override { return Medium; }
QString prefix() const override { return QStringLiteral( "f" ); }

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


#endif // QGSINBUILTLOCATORFILTERS_H


2 changes: 1 addition & 1 deletion src/app/qgisapp.cpp
Expand Up @@ -2672,7 +2672,7 @@ void QgisApp::createStatusBar()
<< mSnappingToolBar;

mLocatorWidget->locator()->registerFilter( new QgsActionLocatorFilter( actionObjects ) );

mLocatorWidget->locator()->registerFilter( new QgsActiveLayerFeaturesLocatorFilter() );
}

void QgisApp::setIconSizes( int size )
Expand Down
6 changes: 4 additions & 2 deletions src/app/qgisapp.h
Expand Up @@ -621,6 +621,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
//! Process the list of URIs that have been dropped in QGIS
void handleDropUriList( const QgsMimeDataUtils::UriList &lst );

//! Returns the active map layer.
QgsMapLayer *activeLayer();

public slots:
void layerTreeViewDoubleClicked( const QModelIndex &index );
//! Make sure the insertion point for new layers is up-to-date with the current item in layer tree view
Expand Down Expand Up @@ -1139,8 +1142,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void hideDeselectedLayers();
//reimplements method from base (gui) class
void showSelectedLayers();
//! Return pointer to the active layer
QgsMapLayer *activeLayer();

//! Open the help contents in a browser
void helpContents();
//! Open the API documentation in a browser
Expand Down
3 changes: 2 additions & 1 deletion src/gui/locator/qgslocator.cpp
Expand Up @@ -63,7 +63,8 @@ void QgsLocator::registerFilter( QgsLocatorFilter *filter )
if ( !filter->prefix().isEmpty() )
{
if ( filter->name() == QStringLiteral( "actions" ) || filter->name() == QStringLiteral( "processing_alg" )
|| filter->name() == QStringLiteral( "layertree" ) || filter->name() == QStringLiteral( "layouts" ) )
|| filter->name() == QStringLiteral( "layertree" ) || filter->name() == QStringLiteral( "layouts" )
|| filter->name() == QStringLiteral( "features" ) )
{
//inbuilt filter, no prefix check
mPrefixedFilters.insert( filter->prefix(), filter );
Expand Down

0 comments on commit 55ed6f9

Please sign in to comment.