Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Refresh features in Attribute Table on data change
  • Loading branch information
github-actions[bot] committed Mar 26, 2020
1 parent 08532a5 commit 3151d64
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 55 deletions.
Expand Up @@ -196,6 +196,14 @@ 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`` and the ``context`` to be stored in case of the features
need to be filtered again (like on filter or on main model data change).

.. versionadded:: 3.10.3
%End

signals:
Expand Down Expand Up @@ -234,10 +242,21 @@ selection state of the feature in case selected features are to be shown on top.

public slots:

void extentsChanged();
void extentsChanged();
%Docstring
Is called upon every change of the visible extents on the map canvas.
When a change is signalled, the filter is updated and invalidated if needed.

.. deprecated:: QGIS 3.10.3
- made private as reloadVisible()
%End

void filterFeatures();
%Docstring
Updates the filtered features in the filter model. It is called when the data of the
main table or the filter expression changed.

.. versionadded:: 3.10.3
%End

};
Expand Down
13 changes: 12 additions & 1 deletion python/gui/auto_generated/attributetable/qgsdualview.sip.in
Expand Up @@ -122,11 +122,22 @@ 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 );
%Docstring
Sets the expression and Updates the filtered features in the filter model.
It is called when the filter expression changed.

.. versionadded:: 3.10.3
%End

QgsFeatureIds filteredFeatures();
Expand Down
79 changes: 77 additions & 2 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 @@ -226,6 +227,12 @@ void QgsAttributeTableFilterModel::setAttributeTableConfig( const QgsAttributeTa
sort( config.sortExpression(), config.sortOrder() );
}

void QgsAttributeTableFilterModel::setFilterExpression( const QgsExpression &expression, const QgsExpressionContext &context )
{
mFilterExpression = expression;
mFilterExpressionContext = context;
}

void QgsAttributeTableFilterModel::sort( const QString &expression, Qt::SortOrder order )
{
if ( order != Qt::AscendingOrder && order != Qt::DescendingOrder )
Expand Down Expand Up @@ -313,12 +320,23 @@ void QgsAttributeTableFilterModel::setFilterMode( FilterMode filterMode )
{
if ( filterMode == ShowVisible )
{
connect( mCanvas, &QgsMapCanvas::extentsChanged, this, &QgsAttributeTableFilterModel::extentsChanged );
connect( mCanvas, &QgsMapCanvas::extentsChanged, this, &QgsAttributeTableFilterModel::reloadVisible );
connect( mTableModel, &QgsAttributeTableModel::dataChanged, this, &QgsAttributeTableFilterModel::reloadVisible );
generateListOfVisibleFeatures();
}
else
{
disconnect( mCanvas, &QgsMapCanvas::extentsChanged, this, &QgsAttributeTableFilterModel::extentsChanged );
disconnect( mCanvas, &QgsMapCanvas::extentsChanged, this, &QgsAttributeTableFilterModel::reloadVisible );
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;
Expand Down Expand Up @@ -372,11 +390,68 @@ bool QgsAttributeTableFilterModel::filterAcceptsRow( int sourceRow, const QModel
}

void QgsAttributeTableFilterModel::extentsChanged()
{
reloadVisible();
}

void QgsAttributeTableFilterModel::reloadVisible()
{
generateListOfVisibleFeatures();
invalidateFilter();
}

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

QgsFeatureIds filteredFeatures;
QgsDistanceArea distanceArea;

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

const bool fetchGeom = mFilterExpression.needsGeometry();

QApplication::setOverrideCursor( Qt::WaitCursor );

mFilterExpression.setGeomCalculator( &distanceArea );
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
24 changes: 23 additions & 1 deletion src/gui/attributetable/qgsattributetablefiltermodel.h
Expand Up @@ -221,6 +221,14 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub
*/
void setAttributeTableConfig( const QgsAttributeTableConfig &config );

/**
* Set the \a expression and the \a context to be stored in case of the features
* need to be filtered again (like on filter or on main model data change).
*
* \since QGIS 3.10.3
*/
void setFilterExpression( const QgsExpression &expression, const QgsExpressionContext &context );

signals:

/**
Expand Down Expand Up @@ -257,12 +265,23 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub
/**
* Is called upon every change of the visible extents on the map canvas.
* When a change is signalled, the filter is updated and invalidated if needed.
*
* \deprecated since QGIS 3.10.3 - made private as reloadVisible()
*/
void extentsChanged();
Q_DECL_DEPRECATED void extentsChanged();

/**
* Updates the filtered features in the filter model. It is called when the data of the
* main table or the filter expression changed.
*
* \since QGIS 3.10.3
*/
void filterFeatures();

private slots:
void selectionChanged();
void onColumnsChanged();
void reloadVisible();

private:
QgsFeatureIds mFilteredFeatures;
Expand All @@ -273,6 +292,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 @@ -1063,6 +1063,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
11 changes: 10 additions & 1 deletion src/gui/attributetable/qgsdualview.h
Expand Up @@ -157,8 +157,17 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
*
* \param filteredFeatures A list of feature ids
*
* \deprecated since filterFeatures is handled in the attribute filter model itself
*/
Q_DECL_DEPRECATED void setFilteredFeatures( const QgsFeatureIds &filteredFeatures );

/**
* Sets the expression and Updates the filtered features in the filter model.
* It is called when the filter expression changed.
*
* \since QGIS 3.10.3
*/
void setFilteredFeatures( const QgsFeatureIds &filteredFeatures );
void filterFeatures( const QgsExpression &filterExpression, const QgsExpressionContext &context );

/**
* Gets a list of currently visible feature ids.
Expand Down
50 changes: 1 addition & 49 deletions src/gui/attributetable/qgsfeaturefilterwidget.cpp
Expand Up @@ -446,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 @@ -467,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
5 changes: 5 additions & 0 deletions src/gui/attributetable/qgsfeaturelistview.cpp
Expand Up @@ -162,7 +162,11 @@ void QgsFeatureListView::editSelectionChanged( const QItemSelection &deselected,
QItemSelection localSelected = mModel->mapSelectionFromMaster( selected );
viewport()->update( visualRegionForSelection( localDeselected ) | visualRegionForSelection( localSelected ) );
}
updateEditSelectionDependencies();
}

void QgsFeatureListView::updateEditSelectionDependencies()
{
QItemSelection currentSelection = mCurrentEditSelectionModel->selection();
if ( currentSelection.size() == 1 )
{
Expand Down Expand Up @@ -458,6 +462,7 @@ void QgsFeatureListView::ensureEditSelection( bool inSelection )
}
mUpdateEditSelectionTimer.start();
}
updateEditSelectionDependencies();
}

void QgsFeatureListView::setFeatureSelectionManager( QgsIFeatureSelectionManager *featureSelectionManager )
Expand Down
5 changes: 5 additions & 0 deletions src/gui/attributetable/qgsfeaturelistview.h
Expand Up @@ -214,6 +214,11 @@ class GUI_EXPORT QgsFeatureListView : public QListView
private slots:
void editSelectionChanged( const QItemSelection &deselected, const QItemSelection &selected );

/**
* Emits the signal for the feature and the selection information
*/
void updateEditSelectionDependencies();

/**
* Make sure, there is an edit selection. If there is none, choose the first item.
* If \a inSelection is set to TRUE, the edit selection is done in selected entries if
Expand Down

0 comments on commit 3151d64

Please sign in to comment.