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;
%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
};
/************************************************************************

View File

@ -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
@ -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)

View File

@ -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();
}

View File

@ -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;

View File

@ -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;
@ -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;
}
}
QgsAttributes fa = f.attributes();
QgsAttributes ca = current.attributes();
for ( int attr = 0; attr < fa.count(); ++attr )
{
if ( fa.at( attr ) != ca.at( attr ) )
{
if ( !changeAttributeValue( f.id(), attr, fa.at( attr ), ca.at( attr ) ) )
if ( changeGeometry( updatedFeature.id(), updatedFeature.geometry(), true ) )
{
QgsDebugMsg( QString( "attribute %1 of feature %2 could not be changed." ).arg( attr ).arg( f.id() ) );
return false;
hasChanged = true;
}
else
{
QgsDebugMsg( QString( "geometry of feature %1 could not be changed." ).arg( updatedFeature.id() ) );
}
}
QgsAttributes fa = updatedFeature.attributes();
QgsAttributes ca = currentFeature.attributes();
for ( int attr = 0; attr < fa.count(); ++attr )
{
if ( fa.at( attr ) != ca.at( attr ) )
{
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;
}
@ -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 )
{
@ -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 )
@ -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 )
{
@ -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();

View File

@ -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
@ -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)
@ -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
@ -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
*/
@ -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;