Skip to content

Commit

Permalink
Update all attributes in a single transaction
Browse files Browse the repository at this point in the history
Fixes #17869
  • Loading branch information
pblottiere committed Mar 30, 2018
1 parent 0eb3cd4 commit 140b40b
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 2 deletions.
42 changes: 42 additions & 0 deletions src/core/qgsvectorlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2384,6 +2384,48 @@ bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QV
return mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
}

bool QgsVectorLayer::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues )
{
bool result = true;

QgsAttributeMap newValidValues;
QgsAttributeMap oldValidValues;

QgsAttributeMap::const_iterator it;
for ( it = newValues.constBegin(); it != newValues.constEnd(); ++it )
{
const int field = it.key();
const QVariant newValue = it.value();
QVariant oldValue;

if ( oldValues.contains( field ) )
oldValue = oldValues[field];

switch ( fields().fieldOrigin( field ) )
{
case QgsFields::OriginProvider:
case QgsFields::OriginEdit:
case QgsFields::OriginExpression:
{
newValidValues[field] = newValue;
oldValidValues[field] = oldValue;
break;
}

case QgsFields::OriginJoin:
case QgsFields::OriginUnknown:
break;
}
}

if ( ! newValidValues.isEmpty() && mEditBuffer && mDataProvider )
{
result &= mEditBuffer->changeAttributeValues( fid, newValidValues, oldValidValues );
}

return result;
}

bool QgsVectorLayer::addAttribute( const QgsField &field )
{
if ( !mEditBuffer || !mDataProvider )
Expand Down
33 changes: 33 additions & 0 deletions src/core/qgsvectorlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -1347,6 +1347,39 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant() );

/**
* Changes attributes' values for a feature (but does not immediately
* commit the changes).
* The \a fid argument specifies the ID of the feature to be changed.
*
* The new values to be assigned to the fields are given by \a newValues.
*
* If a valid QVariant is specified for a field in \a oldValues, it will be
* used as the field value in the case of an undo operation corresponding
* to this attribute value change. If an invalid QVariant is used (the
* default behavior), then the feature's current value will be
* automatically retrieved and used. Note that this involves a feature
* request to the underlying data provider, so it is more efficient to
* explicitly pass an oldValue if it is already available.
*
* Returns true if feature's attributes was successfully changed.
*
* \note Calls to changeAttributeValues() are only valid for layers in
* which edits have been enabled by a call to startEditing(). Changes made
* to features using this method are not committed to the underlying data
* provider until a commitChanges() call is made. Any uncommitted changes
* can be discarded by calling rollBack().
*
* \see startEditing()
* \see commitChanges()
* \see changeGeometry()
* \see updateFeature()
* \see changeAttributeValue()
*
* \since QGIS 2.18
*/
bool changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues );

/** Add an attribute field (but does not commit it)
* returns true if the field was added
*/
Expand Down
19 changes: 19 additions & 0 deletions src/core/qgsvectorlayereditbuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -776,3 +776,22 @@ void QgsVectorLayerEditBuffer::updateLayerFields()
{
L->updateFields();
}

bool QgsVectorLayerEditBuffer::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues )
{
bool success = true;
QgsAttributeMap::const_iterator it;
for ( it = newValues.constBegin() ; it != newValues.constEnd(); ++it )
{
const int field = it.key();
const QVariant newValue = it.value();
QVariant oldValue;

if ( oldValues.contains( field ) )
oldValue = oldValues[field];

success &= changeAttributeValue( fid, field, newValue, oldValue );
}

return success;
}
7 changes: 6 additions & 1 deletion src/core/qgsvectorlayereditbuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,12 @@ class CORE_EXPORT QgsVectorLayerEditBuffer : public QObject
/** Stop editing and discard the edits */
virtual void rollBack();


/**
* Changes values of attributes (but does not commit it).
* \returns true if attributes are well updated, false otherwise
* \since QGIS 2.18
*/
virtual bool changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues );

/** New features which are not commited. */
inline const QgsFeatureMap& addedFeatures() { return mAddedFeatures; }
Expand Down
21 changes: 21 additions & 0 deletions src/core/qgsvectorlayereditpassthrough.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,27 @@ bool QgsVectorLayerEditPassthrough::changeAttributeValue( QgsFeatureId fid, int
return false;
}

bool QgsVectorLayerEditPassthrough::changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues )
{
Q_UNUSED( oldValues );
bool result = false;

QgsChangedAttributesMap attribMap;
attribMap.insert( fid, newValues );

if ( L->dataProvider()->changeAttributeValues( attribMap ) )
{
result = true;
QgsAttributeMap::const_iterator it;
for ( it = newValues.constBegin(); it != newValues.constEnd(); ++it )
{
emit attributeValueChanged( fid, it.key(), it.value() );
}
}

return result;
}

bool QgsVectorLayerEditPassthrough::addAttribute( const QgsField &field )
{
if ( L->dataProvider()->addAttributes( QList<QgsField>() << field ) )
Expand Down
1 change: 1 addition & 0 deletions src/core/qgsvectorlayereditpassthrough.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class CORE_EXPORT QgsVectorLayerEditPassthrough : public QgsVectorLayerEditBuffe
bool deleteFeatures( const QgsFeatureIds& fids ) override;
bool changeGeometry( QgsFeatureId fid, QgsGeometry* geom ) override;
bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant() ) override;
bool changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues ) override;
bool addAttribute( const QgsField &field ) override;
bool deleteAttribute( int attr ) override;
bool renameAttribute( int attr, const QString& newName ) override;
Expand Down
9 changes: 8 additions & 1 deletion src/gui/qgsattributeform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,9 @@ bool QgsAttributeForm::saveEdits()
{
mLayer->beginEditCommand( mEditCommandMessage );

QgsAttributeMap newValues;
QgsAttributeMap oldValues;

int n = 0;
for ( int i = 0; i < dst.count(); ++i )
{
Expand All @@ -353,10 +356,14 @@ bool QgsAttributeForm::saveEdits()
QgsDebugMsg( QString( "src:'%1' (type:%2, isNull:%3, isValid:%4)" )
.arg( src.at( i ).toString(), src.at( i ).typeName() ).arg( src.at( i ).isNull() ).arg( src.at( i ).isValid() ) );

success &= mLayer->changeAttributeValue( mFeature.id(), i, dst.at( i ), src.at( i ) );
newValues[i] = dst.at( i );
oldValues[i] = src.at( i );

n++;
}

success = mLayer->changeAttributeValues( mFeature.id(), newValues, oldValues );

if ( success && n > 0 )
{
mLayer->endEditCommand();
Expand Down

0 comments on commit 140b40b

Please sign in to comment.