Skip to content
Permalink
Browse files
Fix performance issue when using attribute table with "edited or new
features" filter in place

Instead of loading the entire layer into table and then hiding rows,
use similar shortcuts as we do for the "selected features" or
"visible features" filters so that we only actually load edited
features into the table.
  • Loading branch information
nyalldawson committed Jun 8, 2021
1 parent 5bac4c2 commit af021f10fb73d4850a0486527775e7fdc101ef47
@@ -56,6 +56,7 @@
#include "qgsproxyprogresstask.h"
#include "qgisapp.h"
#include "qgsorganizetablecolumnsdialog.h"
#include "qgsvectorlayereditbuffer.h"

QgsExpressionContext QgsAttributeTableDialog::createExpressionContext() const
{
@@ -193,6 +194,10 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QgsAttr
{
r.setFilterFids( layer->selectedFeatureIds() );
}
else if ( initialMode == QgsAttributeTableFilterModel::ShowEdited )
{
r.setFilterFids( layer->editBuffer() ? layer->editBuffer()->allAddedOrEditedFeatures() : QgsFeatureIds() );
}
if ( !needsGeom )
r.setFlags( QgsFeatureRequest::NoGeometry );

@@ -45,6 +45,7 @@
#include "qgsfieldconditionalformatwidget.h"
#include "qgsmapcanvasutils.h"
#include "qgsmessagebar.h"
#include "qgsvectorlayereditbuffer.h"


QgsDualView::QgsDualView( QWidget *parent )
@@ -301,12 +302,17 @@ void QgsDualView::setFilterMode( QgsAttributeTableFilterModel::FilterMode filter
break;

case QgsAttributeTableFilterModel::ShowAll:
case QgsAttributeTableFilterModel::ShowEdited:
case QgsAttributeTableFilterModel::ShowFilteredList:
disconnect( mFilterModel, &QgsAttributeTableFilterModel::featuresFiltered, this, &QgsDualView::filterChanged );
disconnect( mFilterModel, &QgsAttributeTableFilterModel::filterError, this, &QgsDualView::filterError );
break;

case QgsAttributeTableFilterModel::ShowEdited:
disconnect( mFilterModel, &QgsAttributeTableFilterModel::featuresFiltered, this, &QgsDualView::filterChanged );
disconnect( mFilterModel, &QgsAttributeTableFilterModel::filterError, this, &QgsDualView::filterError );
disconnect( masterModel()->layer(), &QgsVectorLayer::layerModified, this, &QgsDualView::updateEditedAddedFeatures );
break;

case QgsAttributeTableFilterModel::ShowSelected:
disconnect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures );
break;
@@ -340,8 +346,14 @@ void QgsDualView::setFilterMode( QgsAttributeTableFilterModel::FilterMode filter
connect( mFilterModel, &QgsAttributeTableFilterModel::visibleReloaded, this, &QgsDualView::filterChanged );
break;

case QgsAttributeTableFilterModel::ShowAll:
case QgsAttributeTableFilterModel::ShowEdited:
r.setFilterFids( masterModel()->layer()->editBuffer() ? masterModel()->layer()->editBuffer()->allAddedOrEditedFeatures() : QgsFeatureIds() );
connect( mFilterModel, &QgsAttributeTableFilterModel::featuresFiltered, this, &QgsDualView::filterChanged );
connect( mFilterModel, &QgsAttributeTableFilterModel::filterError, this, &QgsDualView::filterError );
connect( masterModel()->layer(), &QgsVectorLayer::layerModified, this, &QgsDualView::updateEditedAddedFeatures );
break;

case QgsAttributeTableFilterModel::ShowAll:
case QgsAttributeTableFilterModel::ShowFilteredList:
connect( mFilterModel, &QgsAttributeTableFilterModel::featuresFiltered, this, &QgsDualView::filterChanged );
connect( mFilterModel, &QgsAttributeTableFilterModel::filterError, this, &QgsDualView::filterError );
@@ -1173,6 +1185,18 @@ void QgsDualView::updateSelectedFeatures()
emit filterChanged();
}

void QgsDualView::updateEditedAddedFeatures()
{
QgsFeatureRequest r = mMasterModel->request();
if ( r.filterType() == QgsFeatureRequest::FilterNone && r.filterRect().isNull() )
return; // already requested all features

r.setFilterFids( masterModel()->layer()->editBuffer() ? masterModel()->layer()->editBuffer()->allAddedOrEditedFeatures() : QgsFeatureIds() );
mMasterModel->setRequest( r );
mMasterModel->loadLayer();
emit filterChanged();
}

void QgsDualView::extentChanged()
{
QgsFeatureRequest r = mMasterModel->request();
@@ -358,6 +358,7 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
void onSortColumnChanged();

void updateSelectedFeatures();
void updateEditedAddedFeatures();

void extentChanged();

@@ -51,6 +51,7 @@ class TestQgsAttributeTable : public QObject
void testFieldCalculationArea();
void testNoGeom();
void testSelected();
void testEdited();
void testSelectedOnTop();
void testSortByDisplayExpression();
void testOrderColumn();
@@ -289,6 +290,45 @@ void TestQgsAttributeTable::testSelected()
QVERIFY( dlg->mMainView->masterModel()->request().filterFids().isEmpty() );
}

void TestQgsAttributeTable::testEdited()
{
// test attribute table opening in edited features mode
std::unique_ptr< QgsVectorLayer> tempLayer( new QgsVectorLayer( QStringLiteral( "LineString?crs=epsg:3111&field=pk:int&field=col1:double" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
QVERIFY( tempLayer->isValid() );

QgsFeature f1( tempLayer->dataProvider()->fields(), 1 );
QgsFeature f2( tempLayer->dataProvider()->fields(), 2 );
QgsFeature f3( tempLayer->dataProvider()->fields(), 3 );
QVERIFY( tempLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 << f3 ) );

std::unique_ptr< QgsAttributeTableDialog > dlg( new QgsAttributeTableDialog( tempLayer.get(), QgsAttributeTableFilterModel::ShowEdited ) );

QVERIFY( !dlg->mMainView->masterModel()->layerCache()->cacheGeometry() );
//should be nothing - because no edited features!
QCOMPARE( dlg->mMainView->masterModel()->request().filterType(), QgsFeatureRequest::FilterFids );
QVERIFY( dlg->mMainView->masterModel()->request().filterFids().isEmpty() );

// make some edits
tempLayer->startEditing();
QVERIFY( tempLayer->changeAttributeValue( 1, 1, 5.5 ) );
QCOMPARE( dlg->mMainView->masterModel()->request().filterType(), QgsFeatureRequest::FilterFids );
QCOMPARE( dlg->mMainView->masterModel()->request().filterFids(), QgsFeatureIds() << 1 );
QgsGeometry geom = QgsGeometry::fromWkt( QStringLiteral( "LineString(0 0, 1 1)" ) );
QVERIFY( tempLayer->changeGeometry( 3, geom ) );
QCOMPARE( dlg->mMainView->masterModel()->request().filterType(), QgsFeatureRequest::FilterFids );
QCOMPARE( dlg->mMainView->masterModel()->request().filterFids(), QgsFeatureIds() << 1 << 3 );

// another test - start with edited features when dialog created
dlg.reset( new QgsAttributeTableDialog( tempLayer.get(), QgsAttributeTableFilterModel::ShowEdited ) );
QVERIFY( !dlg->mMainView->masterModel()->layerCache()->cacheGeometry() );
QCOMPARE( dlg->mMainView->masterModel()->request().filterType(), QgsFeatureRequest::FilterFids );
QCOMPARE( dlg->mMainView->masterModel()->request().filterFids(), QgsFeatureIds() << 1 << 3 );
// remove edits
tempLayer->rollBack();
QCOMPARE( dlg->mMainView->masterModel()->request().filterType(), QgsFeatureRequest::FilterFids );
QVERIFY( dlg->mMainView->masterModel()->request().filterFids().isEmpty() );
}

void TestQgsAttributeTable::testSelectedOnTop()
{
std::unique_ptr< QgsVectorLayer> tempLayer( new QgsVectorLayer( QStringLiteral( "LineString?crs=epsg:3111&field=pk:int&field=col1:double" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );

0 comments on commit af021f1

Please sign in to comment.