Skip to content

Commit

Permalink
filterFeatures functionality in attributetable filter model instead o…
Browse files Browse the repository at this point in the history
…f the widget for re-filtering on main model data changed (e.g. add feature)
  • Loading branch information
signedav committed Mar 16, 2020
1 parent 18dddff commit 00492ca
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 53 deletions.
Expand Up @@ -196,6 +196,12 @@ Returns -1 if none is defined.
Set the attribute table configuration to control which fields are shown,
in which order they are shown as well as if and where an action column
is shown.
%End

void setFilterExpression( const QgsExpression &expression, const QgsExpressionContext &context );
%Docstring
Set the ``expression`` to be stored in case of the features need to be
filtered (like on filter or on main model data change).
%End

signals:
Expand Down Expand Up @@ -241,6 +247,8 @@ the master table model changes.
When a change is signalled, the filter is updated and invalidated if needed.
%End

void filterFeatures();

};

/************************************************************************
Expand Down
7 changes: 6 additions & 1 deletion python/gui/auto_generated/attributetable/qgsdualview.sip.in
Expand Up @@ -122,13 +122,18 @@ filter restrictions
:return: Number of features
%End

void setFilteredFeatures( const QgsFeatureIds &filteredFeatures );
void setFilteredFeatures( const QgsFeatureIds &filteredFeatures );
%Docstring
Set a list of currently visible features

:param filteredFeatures: A list of feature ids

.. deprecated::
since filterFeatures is handled in the attribute filter model itself
%End

void filterFeatures( const QgsExpression &filterExpression, const QgsExpressionContext &context );

QgsFeatureIds filteredFeatures();
%Docstring
Gets a list of currently visible feature ids.
Expand Down
62 changes: 62 additions & 0 deletions src/gui/attributetable/qgsattributetablefiltermodel.cpp
Expand Up @@ -26,6 +26,7 @@
#include "qgsrenderer.h"
#include "qgsvectorlayereditbuffer.h"
#include "qgsexpressioncontextutils.h"
#include "qgsapplication.h"

//////////////////
// Filter Model //
Expand Down Expand Up @@ -323,6 +324,15 @@ void QgsAttributeTableFilterModel::setFilterMode( FilterMode filterMode )
disconnect( mTableModel, &QgsAttributeTableModel::dataChanged, this, &QgsAttributeTableFilterModel::reloadVisible );
}

if ( filterMode == ShowFilteredList )
{
connect( mTableModel, &QgsAttributeTableModel::dataChanged, this, &QgsAttributeTableFilterModel::filterFeatures );
}
else
{
disconnect( mTableModel, &QgsAttributeTableModel::dataChanged, this, &QgsAttributeTableFilterModel::filterFeatures );
}

mFilterMode = filterMode;
invalidateFilter();
}
Expand Down Expand Up @@ -379,6 +389,58 @@ void QgsAttributeTableFilterModel::reloadVisible()
invalidateFilter();
}

void QgsAttributeTableFilterModel::filterFeatures()
{
if ( !mFilterExpression.isValid() )
return;

QgsFeatureIds filteredFeatures;
QgsDistanceArea myDa;

myDa.setSourceCrs( mTableModel->layer()->crs(), QgsProject::instance()->transformContext() );
myDa.setEllipsoid( QgsProject::instance()->ellipsoid() );

bool fetchGeom = mFilterExpression.needsGeometry();

QApplication::setOverrideCursor( Qt::WaitCursor );

mFilterExpression.setGeomCalculator( &myDa );
mFilterExpression.setDistanceUnits( QgsProject::instance()->distanceUnits() );
mFilterExpression.setAreaUnits( QgsProject::instance()->areaUnits() );
QgsFeatureRequest request( mTableModel->request() );
request.setSubsetOfAttributes( mFilterExpression.referencedColumns(), mTableModel->layer()->fields() );
if ( !fetchGeom )
{
request.setFlags( QgsFeatureRequest::NoGeometry );
}
else
{
// force geometry extraction if the filter requests it
request.setFlags( request.flags() & ~QgsFeatureRequest::NoGeometry );
}
QgsFeatureIterator featIt = mTableModel->layer()->getFeatures( request );

QgsFeature f;

while ( featIt.nextFeature( f ) )
{
mFilterExpressionContext.setFeature( f );
if ( mFilterExpression.evaluate( &mFilterExpressionContext ).toInt() != 0 )
filteredFeatures << f.id();

// check if there were errors during evaluating
if ( mFilterExpression.hasEvalError() )
break;
}

featIt.close();

setFilteredFeatures( filteredFeatures );

QApplication::restoreOverrideCursor();
}


void QgsAttributeTableFilterModel::selectionChanged()
{
if ( ShowSelected == mFilterMode )
Expand Down
11 changes: 11 additions & 0 deletions src/gui/attributetable/qgsattributetablefiltermodel.h
Expand Up @@ -221,6 +221,12 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub
*/
void setAttributeTableConfig( const QgsAttributeTableConfig &config );

/**
* Set the \a expression to be stored in case of the features need to be
* filtered (like on filter or on main model data change).
*/
void setFilterExpression( const QgsExpression &expression, const QgsExpressionContext &context ) { mFilterExpression = expression; mFilterExpressionContext = context; }

signals:

/**
Expand Down Expand Up @@ -261,6 +267,8 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub
*/
void reloadVisible();

void filterFeatures();

private slots:
void selectionChanged();
void onColumnsChanged();
Expand All @@ -274,6 +282,9 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub

QgsAttributeTableConfig mConfig;
QVector<int> mColumnMapping;
QgsExpression mFilterExpression;
QgsExpressionContext mFilterExpressionContext;

int mapColumnToSource( int column ) const;
int mapColumnFromSource( int column ) const;

Expand Down
7 changes: 7 additions & 0 deletions src/gui/attributetable/qgsdualview.cpp
Expand Up @@ -1076,6 +1076,13 @@ void QgsDualView::setFilteredFeatures( const QgsFeatureIds &filteredFeatures )
mFilterModel->setFilteredFeatures( filteredFeatures );
}

void QgsDualView::filterFeatures( const QgsExpression &filterExpression, const QgsExpressionContext &context )
{
mFilterModel->setFilterExpression( filterExpression, context );
mFilterModel->filterFeatures();
}


void QgsDualView::setRequest( const QgsFeatureRequest &request )
{
mMasterModel->setRequest( request );
Expand Down
7 changes: 5 additions & 2 deletions src/gui/attributetable/qgsdualview.h
Expand Up @@ -157,8 +157,11 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
*
* \param filteredFeatures A list of feature ids
*
*/
void setFilteredFeatures( const QgsFeatureIds &filteredFeatures );
* \deprecated since filterFeatures is handled in the attribute filter model itself
*/
Q_DECL_DEPRECATED void setFilteredFeatures( const QgsFeatureIds &filteredFeatures );

void filterFeatures( const QgsExpression &filterExpression, const QgsExpressionContext &context );

/**
* Gets a list of currently visible feature ids.
Expand Down
51 changes: 1 addition & 50 deletions src/gui/attributetable/qgsfeaturefilterwidget.cpp
Expand Up @@ -89,7 +89,6 @@ void QgsFeatureFilterWidget::init( QgsVectorLayer *layer, const QgsAttributeEdit

connect( mLayer, &QgsVectorLayer::attributeAdded, this, &QgsFeatureFilterWidget::columnBoxInit );
connect( mLayer, &QgsVectorLayer::attributeDeleted, this, &QgsFeatureFilterWidget::columnBoxInit );
connect( mMainView->masterModel(), &QgsAttributeTableModel::dataChanged, this, &QgsFeatureFilterWidget::filterQueryAccepted );

//set delay on entering text
mFilterQueryTimer.setSingleShot( true );
Expand Down Expand Up @@ -447,12 +446,6 @@ void QgsFeatureFilterWidget::setFilterExpression( const QString &filterString, Q
}
}

QgsFeatureIds filteredFeatures;
QgsDistanceArea myDa;

myDa.setSourceCrs( mLayer->crs(), QgsProject::instance()->transformContext() );
myDa.setEllipsoid( QgsProject::instance()->ellipsoid() );

// parse search string and build parsed tree
QgsExpression filterExpression( filter );
if ( filterExpression.hasParserError() )
Expand All @@ -468,50 +461,8 @@ void QgsFeatureFilterWidget::setFilterExpression( const QString &filterString, Q
mMessageBar->pushMessage( tr( "Evaluation error" ), filterExpression.evalErrorString(), Qgis::Warning, mMessageBarTimeout );
}

bool fetchGeom = filterExpression.needsGeometry();

QApplication::setOverrideCursor( Qt::WaitCursor );

filterExpression.setGeomCalculator( &myDa );
filterExpression.setDistanceUnits( QgsProject::instance()->distanceUnits() );
filterExpression.setAreaUnits( QgsProject::instance()->areaUnits() );
QgsFeatureRequest request( mMainView->masterModel()->request() );
request.setSubsetOfAttributes( filterExpression.referencedColumns(), mLayer->fields() );
if ( !fetchGeom )
{
request.setFlags( QgsFeatureRequest::NoGeometry );
}
else
{
// force geometry extraction if the filter requests it
request.setFlags( request.flags() & ~QgsFeatureRequest::NoGeometry );
}
QgsFeatureIterator featIt = mLayer->getFeatures( request );
mMainView->filterFeatures( filterExpression, context );

QgsFeature f;

while ( featIt.nextFeature( f ) )
{
context.setFeature( f );
if ( filterExpression.evaluate( &context ).toInt() != 0 )
filteredFeatures << f.id();

// check if there were errors during evaluating
if ( filterExpression.hasEvalError() )
break;
}

featIt.close();

mMainView->setFilteredFeatures( filteredFeatures );

QApplication::restoreOverrideCursor();

if ( filterExpression.hasEvalError() )
{
mMessageBar->pushMessage( tr( "Error filtering" ), filterExpression.evalErrorString(), Qgis::Warning, mMessageBarTimeout );
return;
}
mMainView->setFilterMode( QgsAttributeTableFilterModel::ShowFilteredList );
}

Expand Down

0 comments on commit 00492ca

Please sign in to comment.