Skip to content

Commit 41d5f30

Browse files
committed
[needs-docs] Attribute table "show selected features" shows no features
when none are selected This change is being driven by performance - the "show selected" mode can be used to speed up the attribute table loading for large layers. The current behaviour (showing ALL features when none are selected) breaks this performance benefit, because if users accidently open the table with no selection then they are forced to wait for the entire table to load (sometimes takes hours on large tables/slow connections).
1 parent 95040c1 commit 41d5f30

File tree

5 files changed

+73
-9
lines changed

5 files changed

+73
-9
lines changed

src/app/qgsattributetabledialog.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,7 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QWidget
144144
}
145145
else if ( initialMode == QgsAttributeTableFilterModel::ShowSelected )
146146
{
147-
if ( layer->selectedFeatureCount() > 0 )
148-
r.setFilterFids( layer->selectedFeatureIds() );
147+
r.setFilterFids( layer->selectedFeatureIds() );
149148
}
150149
if ( !needsGeom )
151150
r.setFlags( QgsFeatureRequest::NoGeometry );

src/gui/attributetable/qgsattributetablefiltermodel.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ bool QgsAttributeTableFilterModel::filterAcceptsRow( int sourceRow, const QModel
311311
return mFilteredFeatures.contains( masterModel()->rowToId( sourceRow ) );
312312

313313
case ShowSelected:
314-
return layer()->selectedFeatureIds().isEmpty() || layer()->selectedFeatureIds().contains( masterModel()->rowToId( sourceRow ) );
314+
return layer()->selectedFeatureIds().contains( masterModel()->rowToId( sourceRow ) );
315315

316316
case ShowVisible:
317317
return mFilteredFeatures.contains( masterModel()->rowToId( sourceRow ) );

src/gui/attributetable/qgsdualview.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,7 @@ void QgsDualView::setFilterMode( QgsAttributeTableFilterModel::FilterMode filter
245245

246246
case QgsAttributeTableFilterModel::ShowSelected:
247247
connect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures );
248-
if ( masterModel()->layer()->selectedFeatureCount() > 0 )
249-
r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
248+
r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
250249
break;
251250
}
252251

@@ -718,10 +717,7 @@ void QgsDualView::updateSelectedFeatures()
718717
if ( r.filterType() == QgsFeatureRequest::FilterNone && r.filterRect().isNull() )
719718
return; // already requested all features
720719

721-
if ( masterModel()->layer()->selectedFeatureCount() > 0 )
722-
r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
723-
else
724-
r.disableFilter();
720+
r.setFilterFids( masterModel()->layer()->selectedFeatureIds() );
725721
mMasterModel->setRequest( r );
726722
mMasterModel->loadLayer();
727723
emit filterChanged();

tests/src/app/testqgsattributetable.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class TestQgsAttributeTable : public QObject
4545
void testFieldCalculation();
4646
void testFieldCalculationArea();
4747
void testNoGeom();
48+
void testSelected();
4849

4950
private:
5051
QgisApp *mQgisApp = nullptr;
@@ -209,6 +210,43 @@ void TestQgsAttributeTable::testNoGeom()
209210

210211
}
211212

213+
void TestQgsAttributeTable::testSelected()
214+
{
215+
// test attribute table opening in show selected mode
216+
QgsSettings s;
217+
218+
std::unique_ptr< QgsVectorLayer> tempLayer( new QgsVectorLayer( QStringLiteral( "LineString?crs=epsg:3111&field=pk:int&field=col1:double" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
219+
QVERIFY( tempLayer->isValid() );
220+
221+
QgsFeature f1( tempLayer->dataProvider()->fields(), 1 );
222+
QgsFeature f2( tempLayer->dataProvider()->fields(), 2 );
223+
QgsFeature f3( tempLayer->dataProvider()->fields(), 3 );
224+
QVERIFY( tempLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 << f3 ) );
225+
226+
s.setValue( QStringLiteral( "/qgis/attributeTableBehavior" ), QgsAttributeTableFilterModel::ShowSelected );
227+
std::unique_ptr< QgsAttributeTableDialog > dlg( new QgsAttributeTableDialog( tempLayer.get() ) );
228+
229+
QVERIFY( !dlg->mMainView->masterModel()->layerCache()->cacheGeometry() );
230+
//should be nothing - because no selection!
231+
QCOMPARE( dlg->mMainView->masterModel()->request().filterType(), QgsFeatureRequest::FilterFids );
232+
QVERIFY( dlg->mMainView->masterModel()->request().filterFids().isEmpty() );
233+
234+
// make a selection
235+
tempLayer->selectByIds( QgsFeatureIds() << 1 << 3 );
236+
QCOMPARE( dlg->mMainView->masterModel()->request().filterType(), QgsFeatureRequest::FilterFids );
237+
QCOMPARE( dlg->mMainView->masterModel()->request().filterFids(), QgsFeatureIds() << 1 << 3 );
238+
239+
// another test - start with selection when dialog created
240+
dlg.reset( new QgsAttributeTableDialog( tempLayer.get() ) );
241+
QVERIFY( !dlg->mMainView->masterModel()->layerCache()->cacheGeometry() );
242+
QCOMPARE( dlg->mMainView->masterModel()->request().filterType(), QgsFeatureRequest::FilterFids );
243+
QCOMPARE( dlg->mMainView->masterModel()->request().filterFids(), QgsFeatureIds() << 1 << 3 );
244+
// remove selection
245+
tempLayer->removeSelection();
246+
QCOMPARE( dlg->mMainView->masterModel()->request().filterType(), QgsFeatureRequest::FilterFids );
247+
QVERIFY( dlg->mMainView->masterModel()->request().filterFids().isEmpty() );
248+
}
249+
212250

213251
QGSTEST_MAIN( TestQgsAttributeTable )
214252
#include "testqgsattributetable.moc"

tests/src/gui/testqgsdualview.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class TestQgsDualView : public QObject
5050
void testColumnHeaders();
5151

5252
void testData();
53+
void testFilterSelected();
5354

5455
void testSelectAll();
5556

@@ -134,6 +135,36 @@ void TestQgsDualView::testData()
134135
}
135136
}
136137

138+
void TestQgsDualView::testFilterSelected()
139+
{
140+
QgsFeature feature;
141+
QList< QgsFeatureId > ids;
142+
QgsFeatureIterator it = mPointsLayer->getFeatures( QgsFeatureRequest().setOrderBy( QgsFeatureRequest::OrderBy() << QgsFeatureRequest::OrderByClause( "Heading" ) ) );
143+
while ( it.nextFeature( feature ) )
144+
ids << feature.id();
145+
146+
// select some features
147+
QList< QgsFeatureId > selected;
148+
selected << ids.at( 1 ) << ids.at( 3 );
149+
mPointsLayer->selectByIds( selected.toSet() );
150+
151+
mDualView->setFilterMode( QgsAttributeTableFilterModel::ShowSelected );
152+
QCOMPARE( mDualView->tableView()->model()->rowCount(), 2 );
153+
154+
int headingIdx = mPointsLayer->fields().lookupField( "Heading" );
155+
QgsField fld = mPointsLayer->fields().at( headingIdx );
156+
for ( int i = 0; i < selected.count(); ++i )
157+
{
158+
mPointsLayer->getFeatures( QgsFeatureRequest().setFilterFid( selected.at( i ) ) ).nextFeature( feature );
159+
QModelIndex index = mDualView->tableView()->model()->index( i, headingIdx );
160+
QCOMPARE( mDualView->tableView()->model()->data( index ).toString(), fld.displayString( feature.attribute( headingIdx ) ) );
161+
}
162+
163+
// select none
164+
mPointsLayer->removeSelection();
165+
QCOMPARE( mDualView->tableView()->model()->rowCount(), 0 );
166+
}
167+
137168
void TestQgsDualView::testSelectAll()
138169
{
139170
mDualView->setFilterMode( QgsAttributeTableFilterModel::ShowVisible );

0 commit comments

Comments
 (0)