Apply default values on update

This commit is contained in:
Matthias Kuhn 2017-09-26 13:35:05 +02:00
parent 7b36287ff3
commit f2d512a73a
No known key found for this signature in database
GPG Key ID: A0E766808764D73F
6 changed files with 107 additions and 49 deletions

View File

@ -72,11 +72,17 @@ class QgsDefaultValue
bool isValid() const; bool isValid() const;
%Docstring %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. :return: false if the expression is a null string.
:rtype: bool :rtype: bool
%End %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
}; };
/************************************************************************ /************************************************************************

View File

@ -925,7 +925,7 @@ Return the provider type for this layer
virtual bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 ); virtual bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 );
bool updateFeature( QgsFeature &f ); bool updateFeature( const QgsFeature &f );
%Docstring %Docstring
Updates an existing feature. This method needs to query the datasource Updates an existing feature. This method needs to query the datasource
on every call. Consider using changeAttributeValue() or on every call. Consider using changeAttributeValue() or
@ -1172,13 +1172,13 @@ Returns list of attributes making up the primary key
:rtype: bool :rtype: bool
%End %End
bool changeGeometry( QgsFeatureId fid, const QgsGeometry &geom ); bool changeGeometry( QgsFeatureId fid, const QgsGeometry &geom, bool skipDefaultValue = false );
%Docstring %Docstring
Change feature's geometry Change feature's geometry
:rtype: bool :rtype: bool
%End %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 %Docstring
Changes an attribute value (but does not commit it) Changes an attribute value (but does not commit it)

View File

@ -50,5 +50,10 @@ void QgsDefaultValue::setApplyOnUpdate( bool applyOnUpdate )
bool QgsDefaultValue::isValid() const bool QgsDefaultValue::isValid() const
{ {
return mExpression.isEmpty(); return !mExpression.isEmpty();
}
QgsDefaultValue::operator bool() const
{
return !mExpression.isEmpty();
} }

View File

@ -84,11 +84,17 @@ class CORE_EXPORT QgsDefaultValue
void setApplyOnUpdate( bool applyOnUpdate ); 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. * \returns false if the expression is a null string.
*/ */
bool isValid() const; 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: private:
QString mExpression; QString mExpression;
bool mApplyOnUpdate = false; bool mApplyOnUpdate = false;

View File

@ -766,6 +766,25 @@ void QgsVectorLayer::setExtent( const QgsRectangle &r )
mValidExtent = true; 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 QgsVectorLayer::extent() const
{ {
QgsRectangle rect; QgsRectangle rect;
@ -941,47 +960,52 @@ bool QgsVectorLayer::addFeature( QgsFeature &feature, Flags )
return success; return success;
} }
bool QgsVectorLayer::updateFeature( QgsFeature &f ) bool QgsVectorLayer::updateFeature( const QgsFeature &updatedFeature )
{ {
QgsFeatureRequest req; bool hasChanged = false;
req.setFilterFid( f.id() ); bool hasError = false;
if ( !f.hasGeometry() )
req.setFlags( QgsFeatureRequest::NoGeometry );
if ( f.attributes().isEmpty() )
req.setSubsetOfAttributes( QgsAttributeList() );
QgsFeature current; QgsFeature currentFeature = getFeature( updatedFeature.id() );
if ( !getFeatures( req ).nextFeature( current ) ) if ( currentFeature.isValid() )
{ {
QgsDebugMsg( QString( "feature %1 could not be retrieved" ).arg( f.id() ) ); QgsDebugMsg( QString( "feature %1 could not be retrieved" ).arg( updatedFeature.id() ) );
return false;
if ( updatedFeature.hasGeometry() && currentFeature.hasGeometry() && !updatedFeature.geometry().isGeosEqual( currentFeature.geometry() ) )
{
if ( changeGeometry( updatedFeature.id(), updatedFeature.geometry(), true ) )
{
hasChanged = true;
} }
else
if ( f.hasGeometry() && current.hasGeometry() && !f.geometry().isGeosEqual( current.geometry() ) )
{ {
if ( !changeGeometry( f.id(), f.geometry() ) ) QgsDebugMsg( QString( "geometry of feature %1 could not be changed." ).arg( updatedFeature.id() ) );
{
QgsDebugMsg( QString( "geometry of feature %1 could not be changed." ).arg( f.id() ) );
return false;
} }
} }
QgsAttributes fa = f.attributes(); QgsAttributes fa = updatedFeature.attributes();
QgsAttributes ca = current.attributes(); QgsAttributes ca = currentFeature.attributes();
for ( int attr = 0; attr < fa.count(); ++attr ) for ( int attr = 0; attr < fa.count(); ++attr )
{ {
if ( fa.at( attr ) != ca.at( attr ) ) if ( fa.at( attr ) != ca.at( attr ) )
{ {
if ( !changeAttributeValue( f.id(), attr, fa.at( attr ), ca.at( attr ) ) ) if ( changeAttributeValue( updatedFeature.id(), attr, fa.at( attr ), ca.at( attr ), true ) )
{ {
QgsDebugMsg( QString( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( f.id() ) ); hasChanged = true;
return false; }
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;
} }
@ -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 ) if ( !mEditBuffer || !mDataProvider )
{ {
@ -2272,33 +2296,40 @@ bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, const QgsGeometry &geom )
bool result = mEditBuffer->changeGeometry( fid, geom ); bool result = mEditBuffer->changeGeometry( fid, geom );
if ( result ) if ( result )
{
updateExtents(); updateExtents();
if ( !skipDefaultValue && !mDefaultValueOnUpdateFields.isEmpty() )
updateDefaultValues( fid );
}
return result; 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 ) ) switch ( fields().fieldOrigin( field ) )
{ {
case QgsFields::OriginJoin: case QgsFields::OriginJoin:
return mJoinBuffer->changeAttributeValue( fid, field, newValue, oldValue ); result = mJoinBuffer->changeAttributeValue( fid, field, newValue, oldValue );
case QgsFields::OriginProvider: case QgsFields::OriginProvider:
case QgsFields::OriginEdit: case QgsFields::OriginEdit:
case QgsFields::OriginExpression: case QgsFields::OriginExpression:
{ {
if ( !mEditBuffer || !mDataProvider ) if ( mEditBuffer && mDataProvider )
return false; result = mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
else
return mEditBuffer->changeAttributeValue( fid, field, newValue, oldValue );
} }
case QgsFields::OriginUnknown: case QgsFields::OriginUnknown:
return false; break;
} }
return false; if ( result && !skipDefaultValues && !mDefaultValueOnUpdateFields.isEmpty() )
updateDefaultValues( fid );
return result;
} }
bool QgsVectorLayer::addAttribute( const QgsField &field ) bool QgsVectorLayer::addAttribute( const QgsField &field )
@ -2920,6 +2951,9 @@ void QgsVectorLayer::updateFields()
mFields[ index ].setAlias( aliasIt.value() ); mFields[ index ].setAlias( aliasIt.value() );
} }
// Update default values
mDefaultValueOnUpdateFields.clear();
QMap< QString, QgsDefaultValue >::const_iterator defaultIt = mDefaultExpressionMap.constBegin(); QMap< QString, QgsDefaultValue >::const_iterator defaultIt = mDefaultExpressionMap.constBegin();
for ( ; defaultIt != mDefaultExpressionMap.constEnd(); ++defaultIt ) for ( ; defaultIt != mDefaultExpressionMap.constEnd(); ++defaultIt )
{ {
@ -2928,6 +2962,8 @@ void QgsVectorLayer::updateFields()
continue; continue;
mFields[ index ].setDefaultValue( defaultIt.value() ); mFields[ index ].setDefaultValue( defaultIt.value() );
if ( defaultIt.value().applyOnUpdate() )
mDefaultValueOnUpdateFields.insert( index );
} }
QMap< QString, QgsFieldConstraints::Constraints >::const_iterator constraintIt = mFieldConstraints.constBegin(); QMap< QString, QgsFieldConstraints::Constraints >::const_iterator constraintIt = mFieldConstraints.constBegin();

View File

@ -913,7 +913,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
\param f Feature to update \param f Feature to update
\returns True in case of success and False in case of error \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, /** Insert a new vertex before the given vertex number,
* in the given ring, item (first number is index 0), and feature * in the given ring, item (first number is index 0), and feature
@ -1142,7 +1142,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
bool setReadOnly( bool readonly = true ); bool setReadOnly( bool readonly = true );
//! Change feature's geometry //! 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) * Changes an attribute value (but does not commit it)
@ -1154,7 +1154,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
* *
* \returns true in case of success * \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) /** Add an attribute field (but does not commit it)
* returns true if the field was added * returns true if the field was added
@ -1958,6 +1958,8 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
private: // Private methods private: // Private methods
void updateDefaultValues( QgsFeatureId fid, QgsFeature feature = QgsFeature() );
/** /**
* Returns true if the provider is in read-only mode * Returns true if the provider is in read-only mode
*/ */
@ -2014,6 +2016,9 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
//! Map which stores default value expressions for fields //! Map which stores default value expressions for fields
QMap<QString, QgsDefaultValue> mDefaultExpressionMap; 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 //! Map which stores constraints for fields
QMap< QString, QgsFieldConstraints::Constraints > mFieldConstraints; QMap< QString, QgsFieldConstraints::Constraints > mFieldConstraints;