Skip to content

Commit 9a747de

Browse files
authored
Merge pull request #4164 from nyalldawson/cache_upgrade
Improvements to attribute table performance
2 parents f0d2f6d + 346bfe4 commit 9a747de

12 files changed

+361
-109
lines changed

python/core/qgsvectorlayercache.sip

+1-10
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,10 @@ class QgsVectorLayerCache : QObject
3333
*/
3434
int cacheSize();
3535

36-
/**
37-
* Enable or disable the caching of geometries
38-
*
39-
* @param cacheGeometry Enable or disable the caching of geometries
40-
*/
4136
void setCacheGeometry( bool cacheGeometry );
4237

38+
bool cacheGeometry() const;
4339

44-
/**
45-
* Set the subset of attributes to be cached
46-
*
47-
* @param attributes The attributes to be cached
48-
*/
4940
void setCacheSubsetOfAttributes( const QgsAttributeList& attributes );
5041

5142
/**

python/gui/attributetable/qgsdualview.sip

+2-10
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,8 @@ class QgsDualView : QStackedWidget
3232
explicit QgsDualView( QWidget* parent /TransferThis/ = 0 );
3333
virtual ~QgsDualView();
3434

35-
/**
36-
* Has to be called to initialize the dual view.
37-
*
38-
* @param layer The layer which should be used to fetch features
39-
* @param mapCanvas The mapCanvas (used for the FilterMode
40-
* {@link QgsAttributeTableFilterModel::ShowVisible}
41-
* @param request Use a modified request to limit the shown features
42-
* @param context The context in which this view is shown
43-
*/
44-
void init( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, const QgsFeatureRequest& request = QgsFeatureRequest(), const QgsAttributeEditorContext& context = QgsAttributeEditorContext() );
35+
void init( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas, const QgsFeatureRequest& request = QgsFeatureRequest(), const QgsAttributeEditorContext& context = QgsAttributeEditorContext(),
36+
bool loadFeatures = true );
4537

4638
/**
4739
* Change the current view mode.

src/app/qgsattributetabledialog.cpp

+14-12
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QWidget
8383
: QDialog( parent, flags )
8484
, mDock( nullptr )
8585
, mLayer( layer )
86-
, mRubberBand( nullptr )
8786
, mCurrentSearchWidgetWrapper( nullptr )
8887
{
8988
setObjectName( QStringLiteral( "QgsAttributeTableDialog/" ) + layer->id() );
@@ -133,21 +132,26 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QWidget
133132
mEditorContext.setVectorLayerTools( QgisApp::instance()->vectorLayerTools() );
134133

135134
QgsFeatureRequest r;
135+
bool needsGeom = false;
136+
QgsAttributeTableFilterModel::FilterMode initialMode = static_cast< QgsAttributeTableFilterModel::FilterMode>( settings.value( QStringLiteral( "/qgis/attributeTableBehavior" ), QgsAttributeTableFilterModel::ShowAll ).toInt() );
136137
if ( mLayer->geometryType() != QgsWkbTypes::NullGeometry &&
137-
settings.value( QStringLiteral( "/qgis/attributeTableBehavior" ), QgsAttributeTableFilterModel::ShowAll ).toInt() == QgsAttributeTableFilterModel::ShowVisible )
138+
initialMode == QgsAttributeTableFilterModel::ShowVisible )
138139
{
139140
QgsMapCanvas *mc = QgisApp::instance()->mapCanvas();
140141
QgsRectangle extent( mc->mapSettings().mapToLayerCoordinates( layer, mc->extent() ) );
141142
r.setFilterRect( extent );
142-
143-
mRubberBand = new QgsRubberBand( mc, QgsWkbTypes::PolygonGeometry );
144-
mRubberBand->setToGeometry( QgsGeometry::fromRect( extent ), layer );
145-
146-
mActionShowAllFilter->setText( tr( "Show All Features In Initial Canvas Extent" ) );
143+
needsGeom = true;
144+
}
145+
else if ( initialMode == QgsAttributeTableFilterModel::ShowSelected )
146+
{
147+
if ( layer->selectedFeatureCount() > 0 )
148+
r.setFilterFids( layer->selectedFeatureIds() );
147149
}
150+
if ( !needsGeom )
151+
r.setFlags( QgsFeatureRequest::NoGeometry );
148152

149153
// Initialize dual view
150-
mMainView->init( mLayer, QgisApp::instance()->mapCanvas(), r, mEditorContext );
154+
mMainView->init( mLayer, QgisApp::instance()->mapCanvas(), r, mEditorContext, false );
151155

152156
QgsAttributeTableConfig config = mLayer->attributeTableConfig();
153157
mMainView->setAttributeTableConfig( config );
@@ -334,18 +338,16 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QWidget
334338
QgsAttributeTableDialog::~QgsAttributeTableDialog()
335339
{
336340
delete myDa;
337-
delete mRubberBand;
338341
}
339342

340343
void QgsAttributeTableDialog::updateTitle()
341344
{
342345
QWidget *w = mDock ? qobject_cast<QWidget *>( mDock ) : qobject_cast<QWidget *>( this );
343-
w->setWindowTitle( tr( " %1 :: Features total: %2, filtered: %3, selected: %4%5" )
346+
w->setWindowTitle( tr( " %1 :: Features total: %2, filtered: %3, selected: %4" )
344347
.arg( mLayer->name() )
345-
.arg( mMainView->featureCount() )
348+
.arg( qMax( static_cast< long >( mMainView->featureCount() ), mLayer->featureCount() ) ) // layer count may be estimated, so use larger of the two
346349
.arg( mMainView->filteredFeatureCount() )
347350
.arg( mLayer->selectedFeatureCount() )
348-
.arg( mRubberBand ? tr( ", spatially limited" ) : QLatin1String( "" ) )
349351
);
350352

351353
if ( mMainView->filterMode() == QgsAttributeTableFilterModel::ShowAll )

src/app/qgsattributetabledialog.h

-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@ class APP_EXPORT QgsAttributeTableDialog : public QDialog, private Ui::QgsAttrib
229229
QSignalMapper *mFilterActionMapper = nullptr;
230230

231231
QgsVectorLayer *mLayer = nullptr;
232-
QgsRubberBand *mRubberBand = nullptr;
233232
QgsSearchWidgetWrapper *mCurrentSearchWidgetWrapper = nullptr;
234233
QStringList mVisibleFields;
235234
QgsAttributeEditorContext mEditorContext;

src/core/qgsvectorlayercache.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ int QgsVectorLayerCache::cacheSize()
5858

5959
void QgsVectorLayerCache::setCacheGeometry( bool cacheGeometry )
6060
{
61-
mCacheGeometry = cacheGeometry && mLayer->hasGeometryType();
61+
bool shouldCacheGeometry = cacheGeometry && mLayer->hasGeometryType();
62+
bool mustInvalidate = shouldCacheGeometry && !mCacheGeometry; // going from no geometry -> geometry, so have to clear existing cache entries
63+
mCacheGeometry = shouldCacheGeometry;
6264
if ( cacheGeometry )
6365
{
6466
connect( mLayer, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayerCache::geometryChanged );
@@ -67,6 +69,10 @@ void QgsVectorLayerCache::setCacheGeometry( bool cacheGeometry )
6769
{
6870
disconnect( mLayer, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayerCache::geometryChanged );
6971
}
72+
if ( mustInvalidate )
73+
{
74+
invalidate();
75+
}
7076
}
7177

7278
void QgsVectorLayerCache::setCacheSubsetOfAttributes( const QgsAttributeList &attributes )
@@ -231,7 +237,7 @@ void QgsVectorLayerCache::attributeAdded( int field )
231237
{
232238
Q_UNUSED( field )
233239
mCachedAttributes.append( field );
234-
mCache.clear();
240+
invalidate();
235241
}
236242

237243
void QgsVectorLayerCache::attributeDeleted( int field )
@@ -267,6 +273,7 @@ void QgsVectorLayerCache::layerDeleted()
267273
void QgsVectorLayerCache::invalidate()
268274
{
269275
mCache.clear();
276+
mFullCache = false;
270277
emit invalidated();
271278
}
272279

src/core/qgsvectorlayercache.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,16 @@ class CORE_EXPORT QgsVectorLayerCache : public QObject
106106
* Enable or disable the caching of geometries
107107
*
108108
* @param cacheGeometry Enable or disable the caching of geometries
109+
* @see cacheGeometry()
109110
*/
110111
void setCacheGeometry( bool cacheGeometry );
111112

113+
/**
114+
* Returns true if the cache will fetch and cache feature geometries.
115+
* @note added in QGIS 3.0
116+
* @see setCacheGeometry()
117+
*/
118+
bool cacheGeometry() const { return mCacheGeometry; }
112119

113120
/**
114121
* Set the subset of attributes to be cached
@@ -134,6 +141,8 @@ class CORE_EXPORT QgsVectorLayerCache : public QObject
134141
* be used for slow data sources, be aware, that the call to this method might take a long time.
135142
*
136143
* @param fullCache True: enable full caching, False: disable full caching
144+
* @note when a cache is invalidated() (e.g. by adding an attribute to a layer) this setting
145+
* is reset. A full cache rebuild must be performed by calling setFullCache( true ) again.
137146
* @see hasFullCache()
138147
*/
139148
void setFullCache( bool fullCache );
@@ -312,7 +321,9 @@ class CORE_EXPORT QgsVectorLayerCache : public QObject
312321
void featureAdded( QgsFeatureId fid );
313322

314323
/**
315-
* The cache has been invalidated and cleared.
324+
* The cache has been invalidated and cleared. Note that when a cache is invalidated
325+
* the fullCache() setting will be cleared, and a full cache rebuild via setFullCache( true )
326+
* will need to be performed.
316327
*/
317328
void invalidated();
318329

src/gui/attributetable/qgsattributetablemodel.cpp

+8-8
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@ QgsAttributeTableModel::QgsAttributeTableModel( QgsVectorLayerCache *layerCache,
6060

6161
loadAttributes();
6262

63-
connect( mLayerCache, SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant & ) ), this, SLOT( attributeValueChanged( QgsFeatureId, int, const QVariant & ) ) );
64-
connect( layer(), SIGNAL( featuresDeleted( QgsFeatureIds ) ), this, SLOT( featuresDeleted( QgsFeatureIds ) ) );
65-
connect( layer(), SIGNAL( attributeDeleted( int ) ), this, SLOT( attributeDeleted( int ) ) );
66-
connect( layer(), SIGNAL( updatedFields() ), this, SLOT( updatedFields() ) );
67-
connect( layer(), SIGNAL( editCommandEnded() ), this, SLOT( editCommandEnded() ) );
68-
connect( mLayerCache, SIGNAL( featureAdded( QgsFeatureId ) ), this, SLOT( featureAdded( QgsFeatureId ) ) );
69-
connect( mLayerCache, SIGNAL( cachedLayerDeleted() ), this, SLOT( layerDeleted() ) );
63+
connect( mLayerCache, &QgsVectorLayerCache::attributeValueChanged, this, &QgsAttributeTableModel::attributeValueChanged );
64+
connect( layer(), &QgsVectorLayer::featuresDeleted, this, &QgsAttributeTableModel::featuresDeleted );
65+
connect( layer(), &QgsVectorLayer::attributeDeleted, this, &QgsAttributeTableModel::attributeDeleted );
66+
connect( layer(), &QgsVectorLayer::updatedFields, this, &QgsAttributeTableModel::updatedFields );
67+
connect( layer(), &QgsVectorLayer::editCommandEnded, this, &QgsAttributeTableModel::editCommandEnded );
68+
connect( mLayerCache, &QgsVectorLayerCache::featureAdded, this, &QgsAttributeTableModel::featureAdded );
69+
connect( mLayerCache, &QgsVectorLayerCache::cachedLayerDeleted, this, &QgsAttributeTableModel::layerDeleted );
7070
}
7171

7272
bool QgsAttributeTableModel::loadFeatureAtId( QgsFeatureId fid ) const
@@ -430,7 +430,7 @@ void QgsAttributeTableModel::loadLayer()
430430

431431
emit finished();
432432

433-
connect( mLayerCache, SIGNAL( invalidated() ), this, SLOT( loadLayer() ), Qt::UniqueConnection );
433+
connect( mLayerCache, &QgsVectorLayerCache::invalidated, this, &QgsAttributeTableModel::loadLayer, Qt::UniqueConnection );
434434

435435
endResetModel();
436436
}

0 commit comments

Comments
 (0)