Skip to content

Commit

Permalink
Apply default values on update
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Sep 29, 2017
1 parent 7b36287 commit f2d512a
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 45 deletions.
8 changes: 7 additions & 1 deletion python/core/qgsdefaultvalue.sip
Expand Up @@ -72,11 +72,17 @@ class QgsDefaultValue

bool isValid() const;
%Docstring
Returns if this default value is should be applied.
Returns if this default value should be applied.
:return: false if the expression is a null string.
:rtype: bool
%End

operator bool() const;
%Docstring
Checks if a default value is set. Alias for isValid().
:return: false if the expression is a null string.
%End

};

/************************************************************************
Expand Down
6 changes: 3 additions & 3 deletions python/core/qgsvectorlayer.sip
Expand Up @@ -925,7 +925,7 @@ Return the provider type for this layer
virtual bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 );


bool updateFeature( QgsFeature &f );
bool updateFeature( const QgsFeature &f );
%Docstring
Updates an existing feature. This method needs to query the datasource
on every call. Consider using changeAttributeValue() or
Expand Down Expand Up @@ -1172,13 +1172,13 @@ Returns list of attributes making up the primary key
:rtype: bool
%End

bool changeGeometry( QgsFeatureId fid, const QgsGeometry &geom );
bool changeGeometry( QgsFeatureId fid, const QgsGeometry &geom, bool skipDefaultValue = false );
%Docstring
Change feature's geometry
:rtype: bool
%End

bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant() );
bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant(), bool skipDefaultValues = false );
%Docstring
Changes an attribute value (but does not commit it)

Expand Down
7 changes: 6 additions & 1 deletion src/core/qgsdefaultvalue.cpp
Expand Up @@ -50,5 +50,10 @@ void QgsDefaultValue::setApplyOnUpdate( bool applyOnUpdate )

bool QgsDefaultValue::isValid() const
{
return mExpression.isEmpty();
return !mExpression.isEmpty();
}

QgsDefaultValue::operator bool() const
{
return !mExpression.isEmpty();
}
8 changes: 7 additions & 1 deletion src/core/qgsdefaultvalue.h
Expand Up @@ -84,11 +84,17 @@ class CORE_EXPORT QgsDefaultValue
void setApplyOnUpdate( bool applyOnUpdate );

/**
* Returns if this default value is should be applied.
* Returns if this default value should be applied.
* \returns false if the expression is a null string.
*/
bool isValid() const;

/**
* Checks if a default value is set. Alias for isValid().
* \returns false if the expression is a null string.
*/
operator bool() const;

private:
QString mExpression;
bool mApplyOnUpdate = false;
Expand Down
108 changes: 72 additions & 36 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -766,6 +766,25 @@ void QgsVectorLayer::setExtent( const QgsRectangle &r )
mValidExtent = true;
}

void QgsVectorLayer::updateDefaultValues( QgsFeatureId fid, QgsFeature feature )
{
if ( !mDefaultValueOnUpdateFields.isEmpty() )
{
if ( !feature.isValid() )
feature = getFeature( fid );

const QgsFields fields = mFields;
int size = fields.size();
for ( int idx : qgsAsConst( mDefaultValueOnUpdateFields ) )
{
if ( idx < 0 || idx >= size )
continue;

defaultValue( idx, feature );
}
}
}

QgsRectangle QgsVectorLayer::extent() const
{
QgsRectangle rect;
Expand Down Expand Up @@ -941,47 +960,52 @@ bool QgsVectorLayer::addFeature( QgsFeature &feature, Flags )
return success;
}

bool QgsVectorLayer::updateFeature( QgsFeature &f )
bool QgsVectorLayer::updateFeature( const QgsFeature &updatedFeature )
{
QgsFeatureRequest req;
req.setFilterFid( f.id() );
if ( !f.hasGeometry() )
req.setFlags( QgsFeatureRequest::NoGeometry );
if ( f.attributes().isEmpty() )
req.setSubsetOfAttributes( QgsAttributeList() );
bool hasChanged = false;
bool hasError = false;

QgsFeature current;
if ( !getFeatures( req ).nextFeature( current ) )
QgsFeature currentFeature = getFeature( updatedFeature.id() );
if ( currentFeature.isValid() )
{
QgsDebugMsg( QString( "feature %1 could not be retrieved" ).arg( f.id() ) );
return false;
}
QgsDebugMsg( QString( "feature %1 could not be retrieved" ).arg( updatedFeature.id() ) );

if ( f.hasGeometry() && current.hasGeometry() && !f.geometry().isGeosEqual( current.geometry() ) )
{
if ( !changeGeometry( f.id(), f.geometry() ) )
if ( updatedFeature.hasGeometry() && currentFeature.hasGeometry() && !updatedFeature.geometry().isGeosEqual( currentFeature.geometry() ) )
{
QgsDebugMsg( QString( "geometry of feature %1 could not be changed." ).arg( f.id() ) );
return false;
if ( changeGeometry( updatedFeature.id(), updatedFeature.geometry(), true ) )
{
hasChanged = true;
}
else
{
QgsDebugMsg( QString( "geometry of feature %1 could not be changed." ).arg( updatedFeature.id() ) );
}
}
}

QgsAttributes fa = f.attributes();
QgsAttributes ca = current.attributes();
QgsAttributes fa = updatedFeature.attributes();
QgsAttributes ca = currentFeature.attributes();

for ( int attr = 0; attr < fa.count(); ++attr )
{
if ( fa.at( attr ) != ca.at( attr ) )
for ( int attr = 0; attr < fa.count(); ++attr )
{
if ( !changeAttributeValue( f.id(), attr, fa.at( attr ), ca.at( attr ) ) )
if ( fa.at( attr ) != ca.at( attr ) )
{
QgsDebugMsg( QString( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( f.id() ) );
return false;
if ( changeAttributeValue( updatedFeature.id(), attr, fa.at( attr ), ca.at( attr ), true ) )
{
hasChanged = true;
}
else
{
QgsDebugMsg( QString( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( updatedFeature.id() ) );
hasError = true;
}
}
}
}

return true;
if ( hasChanged && !mDefaultValueOnUpdateFields.isEmpty() )
updateDefaultValues( updatedFeature.id(), updatedFeature );

return !hasError;
}


Expand Down Expand Up @@ -2260,7 +2284,7 @@ bool QgsVectorLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &error
}


bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, const QgsGeometry &geom )
bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, const QgsGeometry &geom, bool skipDefaultValue )
{
if ( !mEditBuffer || !mDataProvider )
{
Expand All @@ -2272,33 +2296,40 @@ bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, const QgsGeometry &geom )
bool result = mEditBuffer->changeGeometry( fid, geom );

if ( result )
{
updateExtents();
if ( !skipDefaultValue && !mDefaultValueOnUpdateFields.isEmpty() )
updateDefaultValues( fid );
}
return result;
}


bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue )
bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue, bool skipDefaultValues )
{
bool result = false;

switch ( fields().fieldOrigin( field ) )
{
case QgsFields::OriginJoin:
return mJoinBuffer->changeAttributeValue( fid, field, newValue, oldValue );
result = mJoinBuffer->changeAttributeValue( fid, field, newValue, oldValue );

case QgsFields::OriginProvider:
case QgsFields::OriginEdit:
case QgsFields::OriginExpression:
{
if ( !mEditBuffer || !mDataProvider )
return false;
else
return mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
if ( mEditBuffer && mDataProvider )
result = mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
}

case QgsFields::OriginUnknown:
return false;
break;
}

return false;
if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
updateDefaultValues( fid );

return result;
}

bool QgsVectorLayer::addAttribute( const QgsField &field )
Expand Down Expand Up @@ -2920,6 +2951,9 @@ void QgsVectorLayer::updateFields()

mFields[ index ].setAlias( aliasIt.value() );
}

// Update default values
mDefaultValueOnUpdateFields.clear();
QMap< QString, QgsDefaultValue >::const_iterator defaultIt = mDefaultExpressionMap.constBegin();
for ( ; defaultIt != mDefaultExpressionMap.constEnd(); ++defaultIt )
{
Expand All @@ -2928,6 +2962,8 @@ void QgsVectorLayer::updateFields()
continue;

mFields[ index ].setDefaultValue( defaultIt.value() );
if ( defaultIt.value().applyOnUpdate() )
mDefaultValueOnUpdateFields.insert( index );
}

QMap< QString, QgsFieldConstraints::Constraints >::const_iterator constraintIt = mFieldConstraints.constBegin();
Expand Down
11 changes: 8 additions & 3 deletions src/core/qgsvectorlayer.h
Expand Up @@ -913,7 +913,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
\param f Feature to update
\returns True in case of success and False in case of error
*/
bool updateFeature( QgsFeature &f );
bool updateFeature( const QgsFeature &f );

/** Insert a new vertex before the given vertex number,
* in the given ring, item (first number is index 0), and feature
Expand Down Expand Up @@ -1142,7 +1142,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
bool setReadOnly( bool readonly = true );

//! Change feature's geometry
bool changeGeometry( QgsFeatureId fid, const QgsGeometry &geom );
bool changeGeometry( QgsFeatureId fid, const QgsGeometry &geom, bool skipDefaultValue = false );

/**
* Changes an attribute value (but does not commit it)
Expand All @@ -1154,7 +1154,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
*
* \returns true in case of success
*/
bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant() );
bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant(), bool skipDefaultValues = false );

/** Add an attribute field (but does not commit it)
* returns true if the field was added
Expand Down Expand Up @@ -1958,6 +1958,8 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte

private: // Private methods

void updateDefaultValues( QgsFeatureId fid, QgsFeature feature = QgsFeature() );

/**
* Returns true if the provider is in read-only mode
*/
Expand Down Expand Up @@ -2014,6 +2016,9 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
//! Map which stores default value expressions for fields
QMap<QString, QgsDefaultValue> mDefaultExpressionMap;

//! An internal structure to keep track of fields that have a defaultValueOnUpdate
QSet<int> mDefaultValueOnUpdateFields;

//! Map which stores constraints for fields
QMap< QString, QgsFieldConstraints::Constraints > mFieldConstraints;

Expand Down

0 comments on commit f2d512a

Please sign in to comment.