Skip to content

Commit

Permalink
Use widget value when validating attrs in form
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
elpaso committed Dec 13, 2021
1 parent 048003a commit d93bab9
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 6 deletions.
14 changes: 13 additions & 1 deletion python/core/auto_generated/vector/qgsvectorlayerutils.sip.in
Expand Up @@ -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(),
Expand Down
7 changes: 6 additions & 1 deletion src/core/vector/qgsvectorlayerutils.cpp
Expand Up @@ -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;
Expand All @@ -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();

Expand Down
13 changes: 12 additions & 1 deletion src/core/vector/qgsvectorlayerutils.h
Expand Up @@ -169,14 +169,25 @@ 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.
*/
static bool validateAttribute( const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors SIP_OUT,
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
Expand Down
4 changes: 2 additions & 2 deletions src/gui/editorwidgets/core/qgseditorwidgetwrapper.cpp
Expand Up @@ -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
Expand Down
23 changes: 22 additions & 1 deletion src/gui/qgsattributeform.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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 )
{
Expand Down
1 change: 1 addition & 0 deletions src/gui/qgsattributeform.h
Expand Up @@ -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;
Expand Down

0 comments on commit d93bab9

Please sign in to comment.