Use widget value when validating attrs in form

Also, make sure that non enforced constraints
do not block commits and do not report as violated
constraints (Fix #46364).

Followup #46439 because the constraints were
not checked agains the widget value but against
the attribute value.
This commit is contained in:
Alessandro Pasotti 2021-12-13 10:48:37 +01:00
parent 048003aa8a
commit d93bab9dac
6 changed files with 56 additions and 6 deletions

View File

@ -172,11 +172,23 @@ The optional seed value can be used as a basis for generated values.
QgsFieldConstraints::ConstraintStrength strength = QgsFieldConstraints::ConstraintStrengthNotSet,
QgsFieldConstraints::ConstraintOrigin origin = QgsFieldConstraints::ConstraintOriginNotSet );
%Docstring
Tests an attribute value to check whether it passes all constraints which are present on the corresponding field.
Tests a feature attribute value to check whether it passes all constraints which are present on the corresponding field.
Returns ``True`` if the attribute value is valid for the field. Any constraint failures will be reported in the errors argument.
If the strength or origin parameter is set then only constraints with a matching strength/origin will be checked.
%End
static bool validateAttributeValue( const QVariant &value, const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors /Out/,
QgsFieldConstraints::ConstraintStrength strength = QgsFieldConstraints::ConstraintStrengthNotSet,
QgsFieldConstraints::ConstraintOrigin origin = QgsFieldConstraints::ConstraintOriginNotSet );
%Docstring
Tests a value to check whether it passes all constraints which are present on the corresponding field.
Returns ``True`` if the attribute value is valid for the field. Any constraint failures will be reported in the errors argument.
If the strength or origin parameter is set then only constraints with a matching strength/origin will be checked.
.. versionadded:: 3.24
%End
static QgsFeature createFeature( const QgsVectorLayer *layer,
const QgsGeometry &geometry = QgsGeometry(),
const QgsAttributeMap &attributes = QgsAttributeMap(),

View File

@ -375,6 +375,12 @@ QVariant QgsVectorLayerUtils::createUniqueValueFromCache( const QgsVectorLayer *
bool QgsVectorLayerUtils::validateAttribute( const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors,
QgsFieldConstraints::ConstraintStrength strength, QgsFieldConstraints::ConstraintOrigin origin )
{
const QVariant value = feature.attribute( attributeIndex );
return QgsVectorLayerUtils::validateAttributeValue( value, layer, feature, attributeIndex, errors, strength, origin );
}
bool QgsVectorLayerUtils::validateAttributeValue( const QVariant &value, const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors, QgsFieldConstraints::ConstraintStrength strength, QgsFieldConstraints::ConstraintOrigin origin )
{
if ( !layer )
return false;
@ -384,7 +390,6 @@ bool QgsVectorLayerUtils::validateAttribute( const QgsVectorLayer *layer, const
QgsFields fields = layer->fields();
QgsField field = fields.at( attributeIndex );
QVariant value = feature.attribute( attributeIndex );
bool valid = true;
errors.clear();

View File

@ -169,7 +169,7 @@ class CORE_EXPORT QgsVectorLayerUtils
static QVariant createUniqueValueFromCache( const QgsVectorLayer *layer, int fieldIndex, const QSet<QVariant> &existingValues, const QVariant &seed = QVariant() );
/**
* Tests an attribute value to check whether it passes all constraints which are present on the corresponding field.
* Tests a feature attribute value to check whether it passes all constraints which are present on the corresponding field.
* Returns TRUE if the attribute value is valid for the field. Any constraint failures will be reported in the errors argument.
* If the strength or origin parameter is set then only constraints with a matching strength/origin will be checked.
*/
@ -177,6 +177,17 @@ class CORE_EXPORT QgsVectorLayerUtils
QgsFieldConstraints::ConstraintStrength strength = QgsFieldConstraints::ConstraintStrengthNotSet,
QgsFieldConstraints::ConstraintOrigin origin = QgsFieldConstraints::ConstraintOriginNotSet );
/**
* Tests a value to check whether it passes all constraints which are present on the corresponding field.
* Returns TRUE if the attribute value is valid for the field. Any constraint failures will be reported in the errors argument.
* If the strength or origin parameter is set then only constraints with a matching strength/origin will be checked.
* \since QGIS 3.24
*/
static bool validateAttributeValue( const QVariant &value, const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors SIP_OUT,
QgsFieldConstraints::ConstraintStrength strength = QgsFieldConstraints::ConstraintStrengthNotSet,
QgsFieldConstraints::ConstraintOrigin origin = QgsFieldConstraints::ConstraintOriginNotSet );
/**
* Creates a new feature ready for insertion into a layer. Default values and constraints
* (e.g., unique constraints) will automatically be handled. An optional attribute map can be

View File

@ -220,9 +220,9 @@ void QgsEditorWidgetWrapper::updateConstraint( const QgsVectorLayer *layer, int
toEmit = true;
}
hardConstraintsOk = QgsVectorLayerUtils::validateAttribute( layer, ft, index, errors, QgsFieldConstraints::ConstraintStrengthHard, constraintOrigin );
hardConstraintsOk = QgsVectorLayerUtils::validateAttributeValue( value(), layer, ft, index, errors, QgsFieldConstraints::ConstraintStrengthHard, constraintOrigin );
softConstraintsOk = QgsVectorLayerUtils::validateAttribute( layer, ft, index, softErrors, QgsFieldConstraints::ConstraintStrengthSoft, constraintOrigin );
softConstraintsOk = QgsVectorLayerUtils::validateAttributeValue( value(), layer, ft, index, softErrors, QgsFieldConstraints::ConstraintStrengthSoft, constraintOrigin );
errors << softErrors;
}
else // invalid feature

View File

@ -1258,6 +1258,27 @@ bool QgsAttributeForm::currentFormValidConstraints( QStringList &invalidFields,
return valid;
}
bool QgsAttributeForm::currentFormValidHardConstraints( QStringList &invalidFields, QStringList &descriptions )
{
bool valid( true );
for ( QgsWidgetWrapper *ww : std::as_const( mWidgets ) )
{
QgsEditorWidgetWrapper *eww = qobject_cast<QgsEditorWidgetWrapper *>( ww );
if ( eww )
{
if ( eww->isBlockingCommit() )
{
invalidFields.append( eww->field().displayName() );
descriptions.append( eww->constraintFailureReason() );
valid = false; // continue to get all invalid fields
}
}
}
return valid;
}
void QgsAttributeForm::onAttributeAdded( int idx )
{
mPreventFeatureRefresh = false;
@ -1454,7 +1475,7 @@ void QgsAttributeForm::synchronizeState()
if ( mMode != QgsAttributeEditorContext::SearchMode )
{
QStringList invalidFields, descriptions;
mValidConstraints = currentFormValidConstraints( invalidFields, descriptions );
mValidConstraints = currentFormValidHardConstraints( invalidFields, descriptions );
if ( isEditable && mContext.formMode() == QgsAttributeEditorContext::Embed )
{

View File

@ -443,6 +443,7 @@ class GUI_EXPORT QgsAttributeForm : public QWidget
void updateLabels();
bool currentFormValuesFeature( QgsFeature &feature );
bool currentFormValidConstraints( QStringList &invalidFields, QStringList &descriptions );
bool currentFormValidHardConstraints( QStringList &invalidFields, QStringList &descriptions );
QList<QgsEditorWidgetWrapper *> constraintDependencies( QgsEditorWidgetWrapper *w );
Q_DECL_DEPRECATED QgsRelationWidgetWrapper *setupRelationWidgetWrapper( const QgsRelation &rel, const QgsAttributeEditorContext &context ) SIP_DEPRECATED;