Skip to content

Commit 096b4ce

Browse files
authored
Merge pull request #8177 from elpaso/bugfix-20094-field-calculator-slowness
Fixes slow update in field calculator
2 parents 87e0f69 + c8ea3a7 commit 096b4ce

11 files changed

+73
-6
lines changed

python/core/auto_generated/qgsapplication.sip.in

+2
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,7 @@ Emits the signal to collect all the strings of .qgs to be included in ts file
824824
.. versionadded:: 3.4
825825
%End
826826

827+
827828
%If (ANDROID)
828829
//dummy method to workaround sip generation issue
829830
bool x11EventFilter( XEvent *event );
@@ -852,6 +853,7 @@ In order to register translatable strings, connect to this signal and register t
852853
.. versionadded:: 3.4
853854
%End
854855

856+
855857
};
856858

857859

python/core/auto_generated/qgsvectorlayer.sip.in

+7
Original file line numberDiff line numberDiff line change
@@ -2371,6 +2371,13 @@ Is emitted, before changes are committed to the data provider
23712371
void beforeRollBack();
23722372
%Docstring
23732373
Is emitted, before changes are rolled back
2374+
%End
2375+
2376+
void afterRollBack();
2377+
%Docstring
2378+
Is emitted, after changes are rolled back
2379+
2380+
.. versionadded:: 3.4
23742381
%End
23752382

23762383
void attributeAdded( int idx );

src/app/qgisapp.cpp

+10-3
Original file line numberDiff line numberDiff line change
@@ -7093,13 +7093,14 @@ void QgisApp::fieldCalculator()
70937093

70947094
void QgisApp::attributeTable( QgsAttributeTableFilterModel::FilterMode filter )
70957095
{
7096-
QgsVectorLayer *myLayer = qobject_cast<QgsVectorLayer *>( activeLayer() );
7097-
if ( !myLayer )
7096+
QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( activeLayer() );
7097+
if ( !vectorLayer )
70987098
{
70997099
return;
71007100
}
71017101

7102-
QgsAttributeTableDialog *mDialog = new QgsAttributeTableDialog( myLayer, filter );
7102+
QgsAttributeTableDialog *mDialog = new QgsAttributeTableDialog( vectorLayer, filter );
7103+
71037104
mDialog->show();
71047105
// the dialog will be deleted by itself on close
71057106
}
@@ -9191,6 +9192,7 @@ bool QgisApp::toggleEditing( QgsMapLayer *layer, bool allowCancel )
91919192
return res;
91929193
}
91939194

9195+
91949196
void QgisApp::saveActiveLayerEdits()
91959197
{
91969198
saveEdits( activeLayer(), true, true );
@@ -14153,3 +14155,8 @@ void QgisApp::triggerCrashHandler()
1415314155
RaiseException( 0x12345678, 0, 0, nullptr );
1415414156
#endif
1415514157
}
14158+
14159+
void QgisApp::blockAttributeTableUpdates( const QgsVectorLayer *layer, const bool blocked )
14160+
{
14161+
emit attributeTableUpdateBlocked( layer, blocked );
14162+
}

src/app/qgisapp.h

+14
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,13 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
10081008
*/
10091009
void triggerCrashHandler();
10101010

1011+
/**
1012+
* Emits the signal to set the \a blocked state of attribute tables connected a particular \a layer
1013+
*
1014+
* \since QGIS 3.4
1015+
*/
1016+
void blockAttributeTableUpdates( const QgsVectorLayer *layer, const bool blocked );
1017+
10111018
protected:
10121019

10131020
//! Handle state changes (WindowTitleChange)
@@ -1741,6 +1748,13 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
17411748
*/
17421749
void activeLayerChanged( QgsMapLayer *layer );
17431750

1751+
/**
1752+
* Emitted when \a blocked status of attribute table updates for a particular \a layer must change
1753+
*
1754+
* \since QGIS 3.4
1755+
*/
1756+
void attributeTableUpdateBlocked( const QgsVectorLayer *layer, const bool blocked );
1757+
17441758
private:
17451759
void startProfile( const QString &name );
17461760
void endProfile();

src/app/qgsattributetabledialog.cpp

+19-1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QgsAttr
111111
connect( mActionExpressionSelect, &QAction::triggered, this, &QgsAttributeTableDialog::mActionExpressionSelect_triggered );
112112
connect( mMainView, &QgsDualView::showContextMenuExternally, this, &QgsAttributeTableDialog::showContextMenu );
113113

114+
// Block/unblock table updates (feature cache signals)
115+
connect( QgisApp::instance(), &QgisApp::attributeTableUpdateBlocked, [ = ]( const QgsVectorLayer * layer, const bool blocked )
116+
{
117+
if ( layer == mLayer )
118+
this->blockCacheUpdateSignals( blocked );
119+
} );
120+
// Massive rollbacks can also freeze the GUI due to the feature cache signals
121+
connect( mLayer, &QgsVectorLayer::beforeRollBack, [ = ] { this->blockCacheUpdateSignals( true ); } );
122+
connect( mLayer, &QgsVectorLayer::afterRollBack, [ = ] { this->blockCacheUpdateSignals( false ); } );
123+
114124
const QgsFields fields = mLayer->fields();
115125
for ( const QgsField &field : fields )
116126
{
@@ -718,7 +728,6 @@ void QgsAttributeTableDialog::mActionOpenFieldCalculator_triggered()
718728
if ( calc.exec() == QDialog::Accepted )
719729
{
720730
int col = masterModel->fieldCol( calc.changedAttributeId() );
721-
722731
if ( col >= 0 )
723732
{
724733
masterModel->reload( masterModel->index( 0, col ), masterModel->index( masterModel->rowCount() - 1, col ) );
@@ -1130,6 +1139,15 @@ void QgsAttributeTableDialog::setFilterExpression( const QString &filterString,
11301139
mMainView->setFilterMode( QgsAttributeTableFilterModel::ShowFilteredList );
11311140
}
11321141

1142+
void QgsAttributeTableDialog::blockCacheUpdateSignals( const bool block )
1143+
{
1144+
QgsAttributeTableModel *masterModel = mMainView->masterModel();
1145+
1146+
if ( ! masterModel )
1147+
return;
1148+
1149+
masterModel->layerCache()->blockSignals( block );
1150+
}
11331151

11341152
void QgsAttributeTableDialog::deleteFeature( const QgsFeatureId fid )
11351153
{

src/app/qgsattributetabledialog.h

+1
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ class APP_EXPORT QgsAttributeTableDialog : public QDialog, private Ui::QgsAttrib
242242

243243
void updateMultiEditButtonState();
244244
void deleteFeature( QgsFeatureId fid );
245+
void blockCacheUpdateSignals( const bool block );
245246

246247
friend class TestQgsAttributeTable;
247248
};

src/app/qgsfieldcalculator.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,10 @@ void QgsFieldCalculator::accept()
163163
{
164164
builder->saveToRecent( QStringLiteral( "fieldcalc" ) );
165165

166-
if ( !mVectorLayer )
166+
if ( ! mVectorLayer )
167+
{
167168
return;
169+
}
168170

169171
// Set up QgsDistanceArea each time we (re-)calculate
170172
QgsDistanceArea myDa;
@@ -265,6 +267,10 @@ void QgsFieldCalculator::accept()
265267
return;
266268
}
267269

270+
// Begin feature modifications, block updates for attr tables
271+
// connected to this layer
272+
QgisApp::instance()->blockAttributeTableUpdates( mVectorLayer, true );
273+
268274
//go through all the features and change the new attribute
269275
QgsFeature feature;
270276
bool calculationSuccess = true;
@@ -315,6 +321,8 @@ void QgsFieldCalculator::accept()
315321
rownum++;
316322
}
317323

324+
QgisApp::instance()->blockAttributeTableUpdates( mVectorLayer, false );
325+
318326
QApplication::restoreOverrideCursor();
319327

320328
if ( !calculationSuccess )
@@ -323,7 +331,6 @@ void QgsFieldCalculator::accept()
323331
mVectorLayer->destroyEditCommand();
324332
return;
325333
}
326-
327334
mVectorLayer->endEditCommand();
328335
}
329336
QDialog::accept();

src/core/qgsapplication.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1535,6 +1535,7 @@ void QgsApplication::collectTranslatableObjects( QgsTranslationContext *translat
15351535
emit requestForTranslatableObjects( translationContext );
15361536
}
15371537

1538+
15381539
QString QgsApplication::nullRepresentation()
15391540
{
15401541
ApplicationMembers *appMembers = members();

src/core/qgsapplication.h

+2
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,7 @@ class CORE_EXPORT QgsApplication : public QApplication
757757
*/
758758
void collectTranslatableObjects( QgsTranslationContext *translationContext );
759759

760+
760761
#ifdef SIP_RUN
761762
SIP_IF_FEATURE( ANDROID )
762763
//dummy method to workaround sip generation issue
@@ -788,6 +789,7 @@ class CORE_EXPORT QgsApplication : public QApplication
788789
*/
789790
void requestForTranslatableObjects( QgsTranslationContext *translationContext );
790791

792+
791793
private:
792794

793795
static void copyPath( const QString &src, const QString &dst );

src/core/qgsvectorlayer.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -2973,6 +2973,8 @@ bool QgsVectorLayer::rollBack( bool deleteBuffer )
29732973

29742974
mEditBuffer->rollBack();
29752975

2976+
emit afterRollBack();
2977+
29762978
if ( isModified() )
29772979
{
29782980
// new undo stack roll back method

src/core/qgsvectorlayer.h

+6
Original file line numberDiff line numberDiff line change
@@ -2167,6 +2167,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
21672167
//! Is emitted, before changes are rolled back
21682168
void beforeRollBack();
21692169

2170+
/**
2171+
* Is emitted, after changes are rolled back
2172+
* \since QGIS 3.4
2173+
*/
2174+
void afterRollBack();
2175+
21702176
/**
21712177
* Will be emitted, when a new attribute has been added to this vector layer.
21722178
* Applies only to types QgsFields::OriginEdit, QgsFields::OriginProvider and QgsFields::OriginExpression

0 commit comments

Comments
 (0)