Skip to content
Permalink
Browse files

Merge pull request #4164 from nyalldawson/cache_upgrade

Improvements to attribute table performance
  • Loading branch information
nyalldawson committed Mar 5, 2017
2 parents f0d2f6d + 346bfe4 commit 9a747de6dbbfd3686b7e8e1c075ee174c05fd323
@@ -33,19 +33,10 @@ class QgsVectorLayerCache : QObject
*/
int cacheSize();

/**
* Enable or disable the caching of geometries
*
* @param cacheGeometry Enable or disable the caching of geometries
*/
void setCacheGeometry( bool cacheGeometry );

bool cacheGeometry() const;

/**
* Set the subset of attributes to be cached
*
* @param attributes The attributes to be cached
*/
void setCacheSubsetOfAttributes( const QgsAttributeList& attributes );

/**
@@ -32,16 +32,8 @@ class QgsDualView : QStackedWidget
explicit QgsDualView( QWidget* parent /TransferThis/ = 0 );
virtual ~QgsDualView();

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

/**
* Change the current view mode.
@@ -83,7 +83,6 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QWidget
: QDialog( parent, flags )
, mDock( nullptr )
, mLayer( layer )
, mRubberBand( nullptr )
, mCurrentSearchWidgetWrapper( nullptr )
{
setObjectName( QStringLiteral( "QgsAttributeTableDialog/" ) + layer->id() );
@@ -133,21 +132,26 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QWidget
mEditorContext.setVectorLayerTools( QgisApp::instance()->vectorLayerTools() );

QgsFeatureRequest r;
bool needsGeom = false;
QgsAttributeTableFilterModel::FilterMode initialMode = static_cast< QgsAttributeTableFilterModel::FilterMode>( settings.value( QStringLiteral( "/qgis/attributeTableBehavior" ), QgsAttributeTableFilterModel::ShowAll ).toInt() );
if ( mLayer->geometryType() != QgsWkbTypes::NullGeometry &&
settings.value( QStringLiteral( "/qgis/attributeTableBehavior" ), QgsAttributeTableFilterModel::ShowAll ).toInt() == QgsAttributeTableFilterModel::ShowVisible )
initialMode == QgsAttributeTableFilterModel::ShowVisible )
{
QgsMapCanvas *mc = QgisApp::instance()->mapCanvas();
QgsRectangle extent( mc->mapSettings().mapToLayerCoordinates( layer, mc->extent() ) );
r.setFilterRect( extent );

mRubberBand = new QgsRubberBand( mc, QgsWkbTypes::PolygonGeometry );
mRubberBand->setToGeometry( QgsGeometry::fromRect( extent ), layer );

mActionShowAllFilter->setText( tr( "Show All Features In Initial Canvas Extent" ) );
needsGeom = true;
}
else if ( initialMode == QgsAttributeTableFilterModel::ShowSelected )
{
if ( layer->selectedFeatureCount() > 0 )
r.setFilterFids( layer->selectedFeatureIds() );
}
if ( !needsGeom )
r.setFlags( QgsFeatureRequest::NoGeometry );

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

QgsAttributeTableConfig config = mLayer->attributeTableConfig();
mMainView->setAttributeTableConfig( config );
@@ -334,18 +338,16 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QWidget
QgsAttributeTableDialog::~QgsAttributeTableDialog()
{
delete myDa;
delete mRubberBand;
}

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

if ( mMainView->filterMode() == QgsAttributeTableFilterModel::ShowAll )
@@ -229,7 +229,6 @@ class APP_EXPORT QgsAttributeTableDialog : public QDialog, private Ui::QgsAttrib
QSignalMapper *mFilterActionMapper = nullptr;

QgsVectorLayer *mLayer = nullptr;
QgsRubberBand *mRubberBand = nullptr;
QgsSearchWidgetWrapper *mCurrentSearchWidgetWrapper = nullptr;
QStringList mVisibleFields;
QgsAttributeEditorContext mEditorContext;
@@ -58,7 +58,9 @@ int QgsVectorLayerCache::cacheSize()

void QgsVectorLayerCache::setCacheGeometry( bool cacheGeometry )
{
mCacheGeometry = cacheGeometry && mLayer->hasGeometryType();
bool shouldCacheGeometry = cacheGeometry && mLayer->hasGeometryType();
bool mustInvalidate = shouldCacheGeometry && !mCacheGeometry; // going from no geometry -> geometry, so have to clear existing cache entries
mCacheGeometry = shouldCacheGeometry;
if ( cacheGeometry )
{
connect( mLayer, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayerCache::geometryChanged );
@@ -67,6 +69,10 @@ void QgsVectorLayerCache::setCacheGeometry( bool cacheGeometry )
{
disconnect( mLayer, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayerCache::geometryChanged );
}
if ( mustInvalidate )
{
invalidate();
}
}

void QgsVectorLayerCache::setCacheSubsetOfAttributes( const QgsAttributeList &attributes )
@@ -231,7 +237,7 @@ void QgsVectorLayerCache::attributeAdded( int field )
{
Q_UNUSED( field )
mCachedAttributes.append( field );
mCache.clear();
invalidate();
}

void QgsVectorLayerCache::attributeDeleted( int field )
@@ -267,6 +273,7 @@ void QgsVectorLayerCache::layerDeleted()
void QgsVectorLayerCache::invalidate()
{
mCache.clear();
mFullCache = false;
emit invalidated();
}

@@ -106,9 +106,16 @@ class CORE_EXPORT QgsVectorLayerCache : public QObject
* Enable or disable the caching of geometries
*
* @param cacheGeometry Enable or disable the caching of geometries
* @see cacheGeometry()
*/
void setCacheGeometry( bool cacheGeometry );

/**
* Returns true if the cache will fetch and cache feature geometries.
* @note added in QGIS 3.0
* @see setCacheGeometry()
*/
bool cacheGeometry() const { return mCacheGeometry; }

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

/**
* The cache has been invalidated and cleared.
* The cache has been invalidated and cleared. Note that when a cache is invalidated
* the fullCache() setting will be cleared, and a full cache rebuild via setFullCache( true )
* will need to be performed.
*/
void invalidated();

@@ -60,13 +60,13 @@ QgsAttributeTableModel::QgsAttributeTableModel( QgsVectorLayerCache *layerCache,

loadAttributes();

connect( mLayerCache, SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant & ) ), this, SLOT( attributeValueChanged( QgsFeatureId, int, const QVariant & ) ) );
connect( layer(), SIGNAL( featuresDeleted( QgsFeatureIds ) ), this, SLOT( featuresDeleted( QgsFeatureIds ) ) );
connect( layer(), SIGNAL( attributeDeleted( int ) ), this, SLOT( attributeDeleted( int ) ) );
connect( layer(), SIGNAL( updatedFields() ), this, SLOT( updatedFields() ) );
connect( layer(), SIGNAL( editCommandEnded() ), this, SLOT( editCommandEnded() ) );
connect( mLayerCache, SIGNAL( featureAdded( QgsFeatureId ) ), this, SLOT( featureAdded( QgsFeatureId ) ) );
connect( mLayerCache, SIGNAL( cachedLayerDeleted() ), this, SLOT( layerDeleted() ) );
connect( mLayerCache, &QgsVectorLayerCache::attributeValueChanged, this, &QgsAttributeTableModel::attributeValueChanged );
connect( layer(), &QgsVectorLayer::featuresDeleted, this, &QgsAttributeTableModel::featuresDeleted );
connect( layer(), &QgsVectorLayer::attributeDeleted, this, &QgsAttributeTableModel::attributeDeleted );
connect( layer(), &QgsVectorLayer::updatedFields, this, &QgsAttributeTableModel::updatedFields );
connect( layer(), &QgsVectorLayer::editCommandEnded, this, &QgsAttributeTableModel::editCommandEnded );
connect( mLayerCache, &QgsVectorLayerCache::featureAdded, this, &QgsAttributeTableModel::featureAdded );
connect( mLayerCache, &QgsVectorLayerCache::cachedLayerDeleted, this, &QgsAttributeTableModel::layerDeleted );
}

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

emit finished();

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

endResetModel();
}

0 comments on commit 9a747de

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