Skip to content

Commit 3c3c00a

Browse files
authored
Merge pull request #6719 from pblottiere/bugfix_transaction_constraints_218
[backport][bugfix] Update all attributes in a single transaction
2 parents b1c6a87 + 032e082 commit 3c3c00a

12 files changed

+237
-5
lines changed

python/core/qgsvectorlayer.sip

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,39 @@ class QgsVectorLayer : QgsMapLayer
954954
*/
955955
bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant() );
956956

957+
/**
958+
* Changes attributes' values for a feature (but does not immediately
959+
* commit the changes).
960+
* The \a fid argument specifies the ID of the feature to be changed.
961+
*
962+
* The new values to be assigned to the fields are given by \a newValues.
963+
*
964+
* If a valid QVariant is specified for a field in \a oldValues, it will be
965+
* used as the field value in the case of an undo operation corresponding
966+
* to this attribute value change. If an invalid QVariant is used (the
967+
* default behavior), then the feature's current value will be
968+
* automatically retrieved and used. Note that this involves a feature
969+
* request to the underlying data provider, so it is more efficient to
970+
* explicitly pass an oldValue if it is already available.
971+
*
972+
* Returns true if feature's attributes was successfully changed.
973+
*
974+
* @note Calls to changeAttributeValues() are only valid for layers in
975+
* which edits have been enabled by a call to startEditing(). Changes made
976+
* to features using this method are not committed to the underlying data
977+
* provider until a commitChanges() call is made. Any uncommitted changes
978+
* can be discarded by calling rollBack().
979+
*
980+
* @see startEditing()
981+
* @see commitChanges()
982+
* @see changeGeometry()
983+
* @see updateFeature()
984+
* @see changeAttributeValue()
985+
*
986+
* @note added in QGIS 2.18
987+
*/
988+
bool changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues );
989+
957990
/** Add an attribute field (but does not commit it)
958991
* returns true if the field was added
959992
*/

python/core/qgsvectorlayereditbuffer.sip

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,12 @@ class QgsVectorLayerEditBuffer : QObject
7070
/** Stop editing and discard the edits */
7171
virtual void rollBack();
7272

73-
73+
/**
74+
* Changes values of attributes (but does not commit it).
75+
* @return true if attributes are well updated, false otherwise
76+
* @note added in QGIS 2.18
77+
*/
78+
virtual bool changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues );
7479

7580
/** New features which are not commited. */
7681
const QgsFeatureMap& addedFeatures();

python/core/qgsvectorlayereditpassthrough.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class QgsVectorLayerEditPassthrough : QgsVectorLayerEditBuffer
1212
bool deleteFeatures( const QgsFeatureIds& fids );
1313
bool changeGeometry( QgsFeatureId fid, QgsGeometry* geom );
1414
bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant() );
15+
bool changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues );
1516
bool addAttribute( const QgsField &field );
1617
bool deleteAttribute( int attr );
1718
bool renameAttribute( int attr, const QString& newName );

src/core/qgsvectorlayer.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2384,6 +2384,48 @@ bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QV
23842384
return mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
23852385
}
23862386

2387+
bool QgsVectorLayer::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues )
2388+
{
2389+
bool result = true;
2390+
2391+
QgsAttributeMap newValidValues;
2392+
QgsAttributeMap oldValidValues;
2393+
2394+
QgsAttributeMap::const_iterator it;
2395+
for ( it = newValues.constBegin(); it != newValues.constEnd(); ++it )
2396+
{
2397+
const int field = it.key();
2398+
const QVariant newValue = it.value();
2399+
QVariant oldValue;
2400+
2401+
if ( oldValues.contains( field ) )
2402+
oldValue = oldValues[field];
2403+
2404+
switch ( fields().fieldOrigin( field ) )
2405+
{
2406+
case QgsFields::OriginProvider:
2407+
case QgsFields::OriginEdit:
2408+
case QgsFields::OriginExpression:
2409+
{
2410+
newValidValues[field] = newValue;
2411+
oldValidValues[field] = oldValue;
2412+
break;
2413+
}
2414+
2415+
case QgsFields::OriginJoin:
2416+
case QgsFields::OriginUnknown:
2417+
break;
2418+
}
2419+
}
2420+
2421+
if ( ! newValidValues.isEmpty() && mEditBuffer && mDataProvider )
2422+
{
2423+
result &= mEditBuffer->changeAttributeValues( fid, newValidValues, oldValidValues );
2424+
}
2425+
2426+
return result;
2427+
}
2428+
23872429
bool QgsVectorLayer::addAttribute( const QgsField &field )
23882430
{
23892431
if ( !mEditBuffer || !mDataProvider )

src/core/qgsvectorlayer.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,39 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
13471347
*/
13481348
bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant() );
13491349

1350+
/**
1351+
* Changes attributes' values for a feature (but does not immediately
1352+
* commit the changes).
1353+
* The \a fid argument specifies the ID of the feature to be changed.
1354+
*
1355+
* The new values to be assigned to the fields are given by \a newValues.
1356+
*
1357+
* If a valid QVariant is specified for a field in \a oldValues, it will be
1358+
* used as the field value in the case of an undo operation corresponding
1359+
* to this attribute value change. If an invalid QVariant is used (the
1360+
* default behavior), then the feature's current value will be
1361+
* automatically retrieved and used. Note that this involves a feature
1362+
* request to the underlying data provider, so it is more efficient to
1363+
* explicitly pass an oldValue if it is already available.
1364+
*
1365+
* Returns true if feature's attributes was successfully changed.
1366+
*
1367+
* @note Calls to changeAttributeValues() are only valid for layers in
1368+
* which edits have been enabled by a call to startEditing(). Changes made
1369+
* to features using this method are not committed to the underlying data
1370+
* provider until a commitChanges() call is made. Any uncommitted changes
1371+
* can be discarded by calling rollBack().
1372+
*
1373+
* @see startEditing()
1374+
* @see commitChanges()
1375+
* @see changeGeometry()
1376+
* @see updateFeature()
1377+
* @see changeAttributeValue()
1378+
*
1379+
* @note added in QGIS 2.18
1380+
*/
1381+
bool changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues );
1382+
13501383
/** Add an attribute field (but does not commit it)
13511384
* returns true if the field was added
13521385
*/

src/core/qgsvectorlayereditbuffer.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,3 +776,22 @@ void QgsVectorLayerEditBuffer::updateLayerFields()
776776
{
777777
L->updateFields();
778778
}
779+
780+
bool QgsVectorLayerEditBuffer::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues )
781+
{
782+
bool success = true;
783+
QgsAttributeMap::const_iterator it;
784+
for ( it = newValues.constBegin() ; it != newValues.constEnd(); ++it )
785+
{
786+
const int field = it.key();
787+
const QVariant newValue = it.value();
788+
QVariant oldValue;
789+
790+
if ( oldValues.contains( field ) )
791+
oldValue = oldValues[field];
792+
793+
success &= changeAttributeValue( fid, field, newValue, oldValue );
794+
}
795+
796+
return success;
797+
}

src/core/qgsvectorlayereditbuffer.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,12 @@ class CORE_EXPORT QgsVectorLayerEditBuffer : public QObject
9999
/** Stop editing and discard the edits */
100100
virtual void rollBack();
101101

102-
102+
/**
103+
* Changes values of attributes (but does not commit it).
104+
* @return true if attributes are well updated, false otherwise
105+
* @note added in QGIS 2.18
106+
*/
107+
virtual bool changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues );
103108

104109
/** New features which are not commited. */
105110
inline const QgsFeatureMap& addedFeatures() { return mAddedFeatures; }

src/core/qgsvectorlayereditpassthrough.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,27 @@ bool QgsVectorLayerEditPassthrough::changeAttributeValue( QgsFeatureId fid, int
109109
return false;
110110
}
111111

112+
bool QgsVectorLayerEditPassthrough::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues )
113+
{
114+
Q_UNUSED( oldValues );
115+
bool result = false;
116+
117+
QgsChangedAttributesMap attribMap;
118+
attribMap.insert( fid, newValues );
119+
120+
if ( L->dataProvider()->changeAttributeValues( attribMap ) )
121+
{
122+
result = true;
123+
QgsAttributeMap::const_iterator it;
124+
for ( it = newValues.constBegin(); it != newValues.constEnd(); ++it )
125+
{
126+
emit attributeValueChanged( fid, it.key(), it.value() );
127+
}
128+
}
129+
130+
return result;
131+
}
132+
112133
bool QgsVectorLayerEditPassthrough::addAttribute( const QgsField &field )
113134
{
114135
if ( L->dataProvider()->addAttributes( QList<QgsField>() << field ) )

src/core/qgsvectorlayereditpassthrough.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class CORE_EXPORT QgsVectorLayerEditPassthrough : public QgsVectorLayerEditBuffe
3434
bool deleteFeatures( const QgsFeatureIds& fids ) override;
3535
bool changeGeometry( QgsFeatureId fid, QgsGeometry* geom ) override;
3636
bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant() ) override;
37+
bool changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues ) override;
3738
bool addAttribute( const QgsField &field ) override;
3839
bool deleteAttribute( int attr ) override;
3940
bool renameAttribute( int attr, const QString& newName ) override;

src/gui/qgsattributeform.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,9 @@ bool QgsAttributeForm::saveEdits()
337337
{
338338
mLayer->beginEditCommand( mEditCommandMessage );
339339

340+
QgsAttributeMap newValues;
341+
QgsAttributeMap oldValues;
342+
340343
int n = 0;
341344
for ( int i = 0; i < dst.count(); ++i )
342345
{
@@ -353,10 +356,14 @@ bool QgsAttributeForm::saveEdits()
353356
QgsDebugMsg( QString( "src:'%1' (type:%2, isNull:%3, isValid:%4)" )
354357
.arg( src.at( i ).toString(), src.at( i ).typeName() ).arg( src.at( i ).isNull() ).arg( src.at( i ).isValid() ) );
355358

356-
success &= mLayer->changeAttributeValue( mFeature.id(), i, dst.at( i ), src.at( i ) );
359+
newValues[i] = dst.at( i );
360+
oldValues[i] = src.at( i );
361+
357362
n++;
358363
}
359364

365+
success = mLayer->changeAttributeValues( mFeature.id(), newValues, oldValues );
366+
360367
if ( success && n > 0 )
361368
{
362369
mLayer->endEditCommand();

0 commit comments

Comments
 (0)