diff --git a/python/PyQt6/core/auto_generated/qgsfieldconstraints.sip.in b/python/PyQt6/core/auto_generated/qgsfieldconstraints.sip.in index e96ba5a1d631..adf14b5af385 100644 --- a/python/PyQt6/core/auto_generated/qgsfieldconstraints.sip.in +++ b/python/PyQt6/core/auto_generated/qgsfieldconstraints.sip.in @@ -72,7 +72,8 @@ is not present on this field. ConstraintStrength constraintStrength( Constraint constraint ) const; %Docstring Returns the strength of a field constraint, or ConstraintStrengthNotSet if the constraint -is not present on this field. +is not present on this field. If the strength is not set returns ConstraintStrengthNotSet +for anything but ConstraintExpression which returns ConstraintStrengthHard. .. seealso:: :py:func:`constraints` diff --git a/python/core/auto_generated/qgsfieldconstraints.sip.in b/python/core/auto_generated/qgsfieldconstraints.sip.in index 51ef4a9b8ba8..c9530a1a482c 100644 --- a/python/core/auto_generated/qgsfieldconstraints.sip.in +++ b/python/core/auto_generated/qgsfieldconstraints.sip.in @@ -72,7 +72,8 @@ is not present on this field. ConstraintStrength constraintStrength( Constraint constraint ) const; %Docstring Returns the strength of a field constraint, or ConstraintStrengthNotSet if the constraint -is not present on this field. +is not present on this field. If the strength is not set returns ConstraintStrengthNotSet +for anything but ConstraintExpression which returns ConstraintStrengthHard. .. seealso:: :py:func:`constraints` diff --git a/src/core/qgsfieldconstraints.cpp b/src/core/qgsfieldconstraints.cpp index c9007529145f..4954916497a3 100644 --- a/src/core/qgsfieldconstraints.cpp +++ b/src/core/qgsfieldconstraints.cpp @@ -29,8 +29,8 @@ QgsFieldConstraints::ConstraintStrength QgsFieldConstraints::constraintStrength( if ( !( mConstraints & constraint ) ) return ConstraintStrengthNotSet; - // defaults to hard strength unless explicitly set - return mConstraintStrengths.value( constraint, ConstraintStrengthHard ); + // defaults to not set for all but expressions (which does not use strength) + return mConstraintStrengths.value( constraint, constraint == ConstraintExpression ? ConstraintStrengthHard : ConstraintStrengthNotSet ); } void QgsFieldConstraints::setConstraintStrength( QgsFieldConstraints::Constraint constraint, QgsFieldConstraints::ConstraintStrength strength ) diff --git a/src/core/qgsfieldconstraints.h b/src/core/qgsfieldconstraints.h index a5e0ee5752a8..8bd87ac260ae 100644 --- a/src/core/qgsfieldconstraints.h +++ b/src/core/qgsfieldconstraints.h @@ -89,7 +89,8 @@ class CORE_EXPORT QgsFieldConstraints /** * Returns the strength of a field constraint, or ConstraintStrengthNotSet if the constraint - * is not present on this field. + * is not present on this field. If the strength is not set returns ConstraintStrengthNotSet + * for anything but ConstraintExpression which returns ConstraintStrengthHard. * \see constraints() * \see setConstraintStrength() */ diff --git a/src/core/vector/qgsvectorlayer.cpp b/src/core/vector/qgsvectorlayer.cpp index 7810f5273e64..e41fcc853292 100644 --- a/src/core/vector/qgsvectorlayer.cpp +++ b/src/core/vector/qgsvectorlayer.cpp @@ -3145,6 +3145,7 @@ bool QgsVectorLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString constraintElem.setAttribute( QStringLiteral( "unique_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) ); constraintElem.setAttribute( QStringLiteral( "notnull_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) ); constraintElem.setAttribute( QStringLiteral( "exp_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) ); + constraintsElem.appendChild( constraintElem ); } node.appendChild( constraintsElem ); diff --git a/tests/src/python/test_qgsvectorlayer.py b/tests/src/python/test_qgsvectorlayer.py index 881578a0bb0f..c6b4918d00a1 100644 --- a/tests/src/python/test_qgsvectorlayer.py +++ b/tests/src/python/test_qgsvectorlayer.py @@ -4675,6 +4675,47 @@ def test_selection_properties(self): self.assertEqual(vl2.selectionProperties().selectionColor(), QColor(255, 0, 0)) + def testConstraintsotSet(self): + """Test that a NotSet constraint does not become a Hard constraint + when saving and loading a layer style, see issue GH #58431""" + + # Create a memory layer with unique constraints + layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", "test_unique", "memory") + self.assertTrue(layer.isValid()) + + # Se not constraints on fldtxt + layer.setFieldConstraint(0, QgsFieldConstraints.Constraint.ConstraintNotNull, QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) + layer.setFieldConstraint(0, QgsFieldConstraints.Constraint.ConstraintUnique, QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet) + + # Check constraints at the field level + field = layer.fields().at(0) + constraints = field.constraints() + self.assertEqual(constraints.constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) + self.assertEqual(constraints.constraintStrength(QgsFieldConstraints.Constraint.ConstraintUnique), QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet) + + # Check constraints at the layer level + constraints = layer.fieldConstraintsAndStrength(0) + self.assertEqual(constraints[QgsFieldConstraints.Constraint.ConstraintNotNull], QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) + self.assertEqual(constraints[QgsFieldConstraints.Constraint.ConstraintUnique], QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet) + + # Export the style to QML and reload it + style = QgsMapLayerStyle() + temp_file = tempfile.mktemp(suffix='.qml') + layer.saveNamedStyle(temp_file) + layer.loadNamedStyle(temp_file) + + # Check constraints at the field level + field = layer.fields().at(0) + constraints = field.constraints() + self.assertEqual(constraints.constraintStrength(QgsFieldConstraints.Constraint.ConstraintNotNull), QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) + self.assertEqual(constraints.constraintStrength(QgsFieldConstraints.Constraint.ConstraintUnique), QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet) + + # Check constraints at the layer level + constraints = layer.fieldConstraintsAndStrength(0) + self.assertEqual(constraints[QgsFieldConstraints.Constraint.ConstraintNotNull], QgsFieldConstraints.ConstraintStrength.ConstraintStrengthSoft) + self.assertEqual(constraints[QgsFieldConstraints.Constraint.ConstraintUnique], QgsFieldConstraints.ConstraintStrength.ConstraintStrengthNotSet) + + # TODO: # - fetch rect: feat with changed geometry: 1. in rect, 2. out of rect # - more join tests