Skip to content
Permalink
Browse files

Merge pull request #35034 from signedav/attradd

Refresh features in Attribute Table on data change
  • Loading branch information
signedav committed Mar 26, 2020
2 parents 14d0abc + 7c54194 commit 7248c433b39a86c2dba411c03a45197112fb2914
@@ -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:
@@ -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

};
@@ -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();
@@ -26,6 +26,7 @@
#include "qgsrenderer.h"
#include "qgsvectorlayereditbuffer.h"
#include "qgsexpressioncontextutils.h"
#include "qgsapplication.h"

//////////////////
// Filter Model //
@@ -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 )
@@ -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;
@@ -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 )
@@ -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:

/**
@@ -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;
@@ -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;

@@ -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 );
@@ -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.
@@ -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() )
@@ -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 );
}

@@ -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 )
{
@@ -463,6 +467,7 @@ void QgsFeatureListView::ensureEditSelection( bool inSelection )
}
mUpdateEditSelectionTimer.start();
}
updateEditSelectionDependencies();
}

void QgsFeatureListView::setFeatureSelectionManager( QgsIFeatureSelectionManager *featureSelectionManager )
@@ -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

0 comments on commit 7248c43

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