From ea4d9ce64b2f516479763fef6650ccdb41b847cc Mon Sep 17 00:00:00 2001 From: signedav Date: Fri, 19 Apr 2024 13:54:42 +0200 Subject: [PATCH 1/5] DuplicatePolicy like default value / dupicate / remove value to define what has to be done on duplicating a feature. --- python/PyQt6/core/auto_additions/qgis.py | 7 +++ python/PyQt6/core/auto_generated/qgis.sip.in | 7 +++ .../PyQt6/core/auto_generated/qgsfield.sip.in | 20 +++++++ .../vector/qgsvectorlayer.sip.in | 21 +++++++ python/core/auto_additions/qgis.py | 7 +++ python/core/auto_generated/qgis.sip.in | 7 +++ python/core/auto_generated/qgsfield.sip.in | 20 +++++++ .../vector/qgsvectorlayer.sip.in | 21 +++++++ src/core/qgis.h | 16 ++++++ src/core/qgsfield.cpp | 19 ++++++- src/core/qgsfield.h | 25 ++++++-- src/core/qgsfield_p.h | 5 ++ src/core/vector/qgsvectorlayer.cpp | 57 +++++++++++++++++++ src/core/vector/qgsvectorlayer.h | 30 ++++++++++ src/core/vector/qgsvectorlayereditutils.cpp | 3 +- src/core/vector/qgsvectorlayerutils.cpp | 25 +++++++- .../qgsattributetypedialog.cpp | 37 ++++++++++++ .../qgsattributetypedialog.h | 20 +++++++ .../vector/qgsattributesformproperties.cpp | 4 ++ src/gui/vector/qgsattributesformproperties.h | 1 + .../qgsattributetypeedit.ui | 28 +++++++-- 21 files changed, 368 insertions(+), 12 deletions(-) diff --git a/python/PyQt6/core/auto_additions/qgis.py b/python/PyQt6/core/auto_additions/qgis.py index 02cb7d44a228..805449190def 100644 --- a/python/PyQt6/core/auto_additions/qgis.py +++ b/python/PyQt6/core/auto_additions/qgis.py @@ -3204,6 +3204,13 @@ # -- Qgis.FieldDomainMergePolicy.baseClass = Qgis # monkey patching scoped based enum +Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ = "Use default field value" +Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ = "Duplicate original value" +Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ = "Clears the field value so that the data provider backend will populate using any backend triggers or similar logic (since QGIS 3.30)" +Qgis.FieldDomainDuplicatePolicy.__doc__ = "Duplicate policy for field domains.\n\nWhen a feature is duplicated, defines how the value of attributes\nfollowing the domain are computed.\n\n.. versionadded:: 3.38\n\n" + '* ``DefaultValue``: ' + Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ + '\n' + '* ``Duplicate``: ' + Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ + '\n' + '* ``UnsetField``: ' + Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ +# -- +Qgis.FieldDomainDuplicatePolicy.baseClass = Qgis +# monkey patching scoped based enum Qgis.FieldDomainType.Coded.__doc__ = "Coded field domain" Qgis.FieldDomainType.Range.__doc__ = "Numeric range field domain (min/max)" Qgis.FieldDomainType.Glob.__doc__ = "Glob string pattern field domain" diff --git a/python/PyQt6/core/auto_generated/qgis.sip.in b/python/PyQt6/core/auto_generated/qgis.sip.in index 38b07fa1399c..38ccaed15742 100644 --- a/python/PyQt6/core/auto_generated/qgis.sip.in +++ b/python/PyQt6/core/auto_generated/qgis.sip.in @@ -1817,6 +1817,13 @@ The development version GeometryWeighted, }; + enum class FieldDomainDuplicatePolicy /BaseType=IntEnum/ + { + DefaultValue, + Duplicate, + UnsetField, + }; + enum class FieldDomainType /BaseType=IntEnum/ { Coded, diff --git a/python/PyQt6/core/auto_generated/qgsfield.sip.in b/python/PyQt6/core/auto_generated/qgsfield.sip.in index 655275c4790e..65130f8ccf9b 100644 --- a/python/PyQt6/core/auto_generated/qgsfield.sip.in +++ b/python/PyQt6/core/auto_generated/qgsfield.sip.in @@ -466,6 +466,26 @@ be handled during a split operation. .. seealso:: :py:func:`splitPolicy` .. versionadded:: 3.30 +%End + + Qgis::FieldDomainDuplicatePolicy duplicatePolicy() const; +%Docstring +Returns the field's duplicate policy, which indicates how field values should +be handled during a duplicate operation. + +.. seealso:: :py:func:`setDuplicatePolicy` + +.. versionadded:: 3.38 +%End + + void setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy policy ); +%Docstring +Sets the field's duplicate ``policy``, which indicates how field values should +be handled during a duplicate operation. + +.. seealso:: :py:func:`duplicatePolicy` + +.. versionadded:: 3.38 %End SIP_PYOBJECT __repr__(); diff --git a/python/PyQt6/core/auto_generated/vector/qgsvectorlayer.sip.in b/python/PyQt6/core/auto_generated/vector/qgsvectorlayer.sip.in index 9aa67e3bd4af..3c8e2e5fd9af 100644 --- a/python/PyQt6/core/auto_generated/vector/qgsvectorlayer.sip.in +++ b/python/PyQt6/core/auto_generated/vector/qgsvectorlayer.sip.in @@ -1935,6 +1935,27 @@ Sets a split ``policy`` for the field with the specified index. } %End + void setFieldDuplicatePolicy( int index, Qgis::FieldDomainDuplicatePolicy policy ); +%Docstring +Sets a duplicate ``policy`` for the field with the specified index. + +:raises KeyError: if no field with the specified index exists + +.. versionadded:: 3.38 +%End + +%MethodCode + if ( a0 < 0 || a0 >= sipCpp->fields().count() ) + { + PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) ); + sipIsErr = 1; + } + else + { + sipCpp->setFieldDuplicatePolicy( a0, a1 ); + } +%End + QSet excludeAttributesWms() const /Deprecated/; %Docstring A set of attributes that are not advertised in WMS requests with QGIS server. diff --git a/python/core/auto_additions/qgis.py b/python/core/auto_additions/qgis.py index 4918dd1f3f26..05794066b236 100644 --- a/python/core/auto_additions/qgis.py +++ b/python/core/auto_additions/qgis.py @@ -3149,6 +3149,13 @@ # -- Qgis.FieldDomainMergePolicy.baseClass = Qgis # monkey patching scoped based enum +Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ = "Use default field value" +Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ = "Duplicate original value" +Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ = "Clears the field value so that the data provider backend will populate using any backend triggers or similar logic (since QGIS 3.30)" +Qgis.FieldDomainDuplicatePolicy.__doc__ = "Duplicate policy for field domains.\n\nWhen a feature is duplicated, defines how the value of attributes\nfollowing the domain are computed.\n\n.. versionadded:: 3.38\n\n" + '* ``DefaultValue``: ' + Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ + '\n' + '* ``Duplicate``: ' + Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ + '\n' + '* ``UnsetField``: ' + Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ +# -- +Qgis.FieldDomainDuplicatePolicy.baseClass = Qgis +# monkey patching scoped based enum Qgis.FieldDomainType.Coded.__doc__ = "Coded field domain" Qgis.FieldDomainType.Range.__doc__ = "Numeric range field domain (min/max)" Qgis.FieldDomainType.Glob.__doc__ = "Glob string pattern field domain" diff --git a/python/core/auto_generated/qgis.sip.in b/python/core/auto_generated/qgis.sip.in index 965636863fe2..31c60298831b 100644 --- a/python/core/auto_generated/qgis.sip.in +++ b/python/core/auto_generated/qgis.sip.in @@ -1817,6 +1817,13 @@ The development version GeometryWeighted, }; + enum class FieldDomainDuplicatePolicy + { + DefaultValue, + Duplicate, + UnsetField, + }; + enum class FieldDomainType { Coded, diff --git a/python/core/auto_generated/qgsfield.sip.in b/python/core/auto_generated/qgsfield.sip.in index 655275c4790e..65130f8ccf9b 100644 --- a/python/core/auto_generated/qgsfield.sip.in +++ b/python/core/auto_generated/qgsfield.sip.in @@ -466,6 +466,26 @@ be handled during a split operation. .. seealso:: :py:func:`splitPolicy` .. versionadded:: 3.30 +%End + + Qgis::FieldDomainDuplicatePolicy duplicatePolicy() const; +%Docstring +Returns the field's duplicate policy, which indicates how field values should +be handled during a duplicate operation. + +.. seealso:: :py:func:`setDuplicatePolicy` + +.. versionadded:: 3.38 +%End + + void setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy policy ); +%Docstring +Sets the field's duplicate ``policy``, which indicates how field values should +be handled during a duplicate operation. + +.. seealso:: :py:func:`duplicatePolicy` + +.. versionadded:: 3.38 %End SIP_PYOBJECT __repr__(); diff --git a/python/core/auto_generated/vector/qgsvectorlayer.sip.in b/python/core/auto_generated/vector/qgsvectorlayer.sip.in index 9aa67e3bd4af..3c8e2e5fd9af 100644 --- a/python/core/auto_generated/vector/qgsvectorlayer.sip.in +++ b/python/core/auto_generated/vector/qgsvectorlayer.sip.in @@ -1935,6 +1935,27 @@ Sets a split ``policy`` for the field with the specified index. } %End + void setFieldDuplicatePolicy( int index, Qgis::FieldDomainDuplicatePolicy policy ); +%Docstring +Sets a duplicate ``policy`` for the field with the specified index. + +:raises KeyError: if no field with the specified index exists + +.. versionadded:: 3.38 +%End + +%MethodCode + if ( a0 < 0 || a0 >= sipCpp->fields().count() ) + { + PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) ); + sipIsErr = 1; + } + else + { + sipCpp->setFieldDuplicatePolicy( a0, a1 ); + } +%End + QSet excludeAttributesWms() const /Deprecated/; %Docstring A set of attributes that are not advertised in WMS requests with QGIS server. diff --git a/src/core/qgis.h b/src/core/qgis.h index 56a599e59dcb..acc15d84df6c 100644 --- a/src/core/qgis.h +++ b/src/core/qgis.h @@ -3203,6 +3203,22 @@ class CORE_EXPORT Qgis }; Q_ENUM( FieldDomainMergePolicy ) + /** + * Duplicate policy for field domains. + * + * When a feature is duplicated, defines how the value of attributes + * following the domain are computed. + * + * \since QGIS 3.38 + */ + enum class FieldDomainDuplicatePolicy : int + { + DefaultValue, //!< Use default field value + Duplicate, //!< Duplicate original value + UnsetField, //!< Clears the field value so that the data provider backend will populate using any backend triggers or similar logic (since QGIS 3.30) + }; + Q_ENUM( FieldDomainDuplicatePolicy ) + /** * Types of field domain * diff --git a/src/core/qgsfield.cpp b/src/core/qgsfield.cpp index 0db53d8faa0b..0fa86ff52709 100644 --- a/src/core/qgsfield.cpp +++ b/src/core/qgsfield.cpp @@ -706,6 +706,11 @@ bool QgsField::convertCompatible( QVariant &v, QString *errorMessage ) const return true; } +QgsField::operator QVariant() const +{ + return QVariant::fromValue( *this ); +} + void QgsField::setEditorWidgetSetup( const QgsEditorWidgetSetup &v ) { d->editorWidgetSetup = v; @@ -736,6 +741,16 @@ void QgsField::setSplitPolicy( Qgis::FieldDomainSplitPolicy policy ) d->splitPolicy = policy; } +Qgis::FieldDomainDuplicatePolicy QgsField::duplicatePolicy() const +{ + return d->duplicatePolicy; +} + +void QgsField::setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy policy ) +{ + d->duplicatePolicy = policy; +} + /*************************************************************************** * This class is considered CRITICAL and any change MUST be accompanied with * full unit tests in testqgsfield.cpp. @@ -782,6 +797,7 @@ QDataStream &operator>>( QDataStream &in, QgsField &field ) quint32 strengthUnique; quint32 strengthExpression; int splitPolicy; + int duplicatePolicy; bool applyOnUpdate; @@ -796,7 +812,7 @@ QDataStream &operator>>( QDataStream &in, QgsField &field ) in >> name >> type >> typeName >> length >> precision >> comment >> alias >> defaultValueExpression >> applyOnUpdate >> constraints >> originNotNull >> originUnique >> originExpression >> strengthNotNull >> strengthUnique >> strengthExpression >> - constraintExpression >> constraintDescription >> subType >> splitPolicy >> metadata; + constraintExpression >> constraintDescription >> subType >> splitPolicy >> duplicatePolicy >> metadata; field.setName( name ); field.setType( static_cast< QVariant::Type >( type ) ); field.setTypeName( typeName ); @@ -806,6 +822,7 @@ QDataStream &operator>>( QDataStream &in, QgsField &field ) field.setAlias( alias ); field.setDefaultValueDefinition( QgsDefaultValue( defaultValueExpression, applyOnUpdate ) ); field.setSplitPolicy( static_cast< Qgis::FieldDomainSplitPolicy >( splitPolicy ) ); + field.setDuplicatePolicy( static_cast< Qgis::FieldDomainDuplicatePolicy >( duplicatePolicy ) ); QgsFieldConstraints fieldConstraints; if ( constraints & QgsFieldConstraints::ConstraintNotNull ) { diff --git a/src/core/qgsfield.h b/src/core/qgsfield.h index 090b40a86913..03c44be9d57e 100644 --- a/src/core/qgsfield.h +++ b/src/core/qgsfield.h @@ -441,10 +441,7 @@ class CORE_EXPORT QgsField #endif //! Allows direct construction of QVariants from fields. - operator QVariant() const - { - return QVariant::fromValue( *this ); - } + operator QVariant() const; /** * Set the editor widget setup for the field. @@ -497,6 +494,26 @@ class CORE_EXPORT QgsField */ void setSplitPolicy( Qgis::FieldDomainSplitPolicy policy ); + /** + * Returns the field's duplicate policy, which indicates how field values should + * be handled during a duplicate operation. + * + * \see setDuplicatePolicy() + * + * \since QGIS 3.38 + */ + Qgis::FieldDomainDuplicatePolicy duplicatePolicy() const; + + /** + * Sets the field's duplicate \a policy, which indicates how field values should + * be handled during a duplicate operation. + * + * \see duplicatePolicy() + * + * \since QGIS 3.38 + */ + void setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy policy ); + #ifdef SIP_RUN SIP_PYOBJECT __repr__(); % MethodCode diff --git a/src/core/qgsfield_p.h b/src/core/qgsfield_p.h index 982e6d513533..beab53710a6f 100644 --- a/src/core/qgsfield_p.h +++ b/src/core/qgsfield_p.h @@ -84,6 +84,7 @@ class QgsFieldPrivate : public QSharedData , constraints( other.constraints ) , editorWidgetSetup( other.editorWidgetSetup ) , splitPolicy( other.splitPolicy ) + , duplicatePolicy( other.duplicatePolicy ) , isReadOnly( other.isReadOnly ) { } @@ -99,6 +100,7 @@ class QgsFieldPrivate : public QSharedData && ( alias == other.alias ) && ( defaultValueDefinition == other.defaultValueDefinition ) && ( constraints == other.constraints ) && ( flags == other.flags ) && ( splitPolicy == other.splitPolicy ) + && ( duplicatePolicy == other.duplicatePolicy ) && ( isReadOnly == other.isReadOnly ) && ( editorWidgetSetup == other.editorWidgetSetup ) ); } @@ -144,6 +146,9 @@ class QgsFieldPrivate : public QSharedData //! Split policy Qgis::FieldDomainSplitPolicy splitPolicy = Qgis::FieldDomainSplitPolicy::Duplicate; + //! Duplicate policy + Qgis::FieldDomainDuplicatePolicy duplicatePolicy = Qgis::FieldDomainDuplicatePolicy::Duplicate; + //! Read-only bool isReadOnly = false; diff --git a/src/core/vector/qgsvectorlayer.cpp b/src/core/vector/qgsvectorlayer.cpp index eac50e31e0ef..722b6aebf699 100644 --- a/src/core/vector/qgsvectorlayer.cpp +++ b/src/core/vector/qgsvectorlayer.cpp @@ -2243,6 +2243,10 @@ bool QgsVectorLayer::setDataProvider( QString const &provider, const QgsDataProv { mAttributeSplitPolicy[ field.name() ] = field.splitPolicy(); } + if ( !mAttributeDuplicatePolicy.contains( field.name() ) ) + { + mAttributeDuplicatePolicy[ field.name() ] = field.duplicatePolicy(); + } } if ( profile ) @@ -2573,6 +2577,21 @@ bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMes } } + // The duplicate policy is - unlike alias and split policy - never defined by the data provider, so we clear the map + mAttributeDuplicatePolicy.clear(); + const QDomNode duplicatePoliciesNode = layerNode.namedItem( QStringLiteral( "duplicatePolicies" ) ); + if ( !duplicatePoliciesNode.isNull() ) + { + const QDomNodeList duplicatePolicyNodeList = duplicatePoliciesNode.toElement().elementsByTagName( QStringLiteral( "policy" ) ); + for ( int i = 0; i < duplicatePolicyNodeList.size(); ++i ) + { + const QDomElement duplicatePolicyElem = duplicatePolicyNodeList.at( i ).toElement(); + const QString field = duplicatePolicyElem.attribute( QStringLiteral( "field" ) ); + const Qgis::FieldDomainDuplicatePolicy policy = qgsEnumKeyToValue( duplicatePolicyElem.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDomainDuplicatePolicy::Duplicate ); + mAttributeDuplicatePolicy.insert( field, policy ); + } + } + // default expressions mDefaultExpressionMap.clear(); QDomNode defaultsNode = layerNode.namedItem( QStringLiteral( "defaults" ) ); @@ -3085,6 +3104,19 @@ bool QgsVectorLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString node.appendChild( splitPoliciesElement ); } + //duplicate policies + { + QDomElement duplicatePoliciesElement = doc.createElement( QStringLiteral( "duplicatePolicies" ) ); + for ( const QgsField &field : std::as_const( mFields ) ) + { + QDomElement duplicatePolicyElem = doc.createElement( QStringLiteral( "policy" ) ); + duplicatePolicyElem.setAttribute( QStringLiteral( "field" ), field.name() ); + duplicatePolicyElem.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.duplicatePolicy() ) ); + duplicatePoliciesElement.appendChild( duplicatePolicyElem ); + } + node.appendChild( duplicatePoliciesElement ); + } + //default expressions QDomElement defaultsElem = doc.createElement( QStringLiteral( "defaults" ) ); for ( const QgsField &field : std::as_const( mFields ) ) @@ -3588,6 +3620,22 @@ void QgsVectorLayer::setFieldSplitPolicy( int index, Qgis::FieldDomainSplitPolic emit layerModified(); // TODO[MD]: should have a different signal? } +void QgsVectorLayer::setFieldDuplicatePolicy( int index, Qgis::FieldDomainDuplicatePolicy policy ) +{ + QGIS_PROTECT_QOBJECT_THREAD_ACCESS + + if ( index < 0 || index >= fields().count() ) + return; + + const QString name = fields().at( index ).name(); + + mAttributeDuplicatePolicy.insert( name, policy ); + mFields[ index ].setDuplicatePolicy( policy ); + mEditFormConfig.setFields( mFields ); + emit layerModified(); // TODO[MD]: should have a different signal? +} + + QSet QgsVectorLayer::excludeAttributesWms() const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS @@ -4463,6 +4511,15 @@ void QgsVectorLayer::updateFields() mFields[ index ].setSplitPolicy( splitPolicyIt.value() ); } + for ( auto duplicatePolicyIt = mAttributeDuplicatePolicy.constBegin(); duplicatePolicyIt != mAttributeDuplicatePolicy.constEnd(); ++duplicatePolicyIt ) + { + int index = mFields.lookupField( duplicatePolicyIt.key() ); + if ( index < 0 ) + continue; + + mFields[ index ].setDuplicatePolicy( duplicatePolicyIt.value() ); + } + // Update configuration flags QMap< QString, Qgis::FieldConfigurationFlags >::const_iterator flagsIt = mFieldConfigurationFlags.constBegin(); for ( ; flagsIt != mFieldConfigurationFlags.constEnd(); ++flagsIt ) diff --git a/src/core/vector/qgsvectorlayer.h b/src/core/vector/qgsvectorlayer.h index 00af40a4e895..1053bef0c189 100644 --- a/src/core/vector/qgsvectorlayer.h +++ b/src/core/vector/qgsvectorlayer.h @@ -1840,6 +1840,13 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte * \since QGIS 3.30 */ void setFieldSplitPolicy( int index, Qgis::FieldDomainSplitPolicy policy ); + + /** + * Sets a duplicate \a policy for the field with the specified index. + * + * \since QGIS 3.38 + */ + void setFieldDuplicatePolicy( int index, Qgis::FieldDomainDuplicatePolicy policy ); #else /** @@ -1861,6 +1868,26 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte sipCpp->setFieldSplitPolicy( a0, a1 ); } % End + + /** + * Sets a duplicate \a policy for the field with the specified index. + * + * \throws KeyError if no field with the specified index exists + * \since QGIS 3.38 + */ + void setFieldDuplicatePolicy( int index, Qgis::FieldDomainDuplicatePolicy policy ); + + % MethodCode + if ( a0 < 0 || a0 >= sipCpp->fields().count() ) + { + PyErr_SetString( PyExc_KeyError, QByteArray::number( a0 ) ); + sipIsErr = 1; + } + else + { + sipCpp->setFieldDuplicatePolicy( a0, a1 ); + } + % End #endif /** @@ -2867,6 +2894,9 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte //! Map that stores the split policy for attributes QMap< QString, Qgis::FieldDomainSplitPolicy > mAttributeSplitPolicy; + //! Map that stores the duplicate policy for attributes + QMap< QString, Qgis::FieldDomainDuplicatePolicy > mAttributeDuplicatePolicy; + //! An internal structure to keep track of fields that have a defaultValueOnUpdate QSet mDefaultValueOnUpdateFields; diff --git a/src/core/vector/qgsvectorlayereditutils.cpp b/src/core/vector/qgsvectorlayereditutils.cpp index bd1a45a1e26b..5605476df707 100644 --- a/src/core/vector/qgsvectorlayereditutils.cpp +++ b/src/core/vector/qgsvectorlayereditutils.cpp @@ -521,8 +521,7 @@ Qgis::GeometryOperationResult QgsVectorLayerEditUtils::splitFeatures( const QgsC switch ( field.splitPolicy() ) { case Qgis::FieldDomainSplitPolicy::DefaultValue: - // TODO!!! - + //do nothing - default values ​​are determined break; case Qgis::FieldDomainSplitPolicy::Duplicate: diff --git a/src/core/vector/qgsvectorlayerutils.cpp b/src/core/vector/qgsvectorlayerutils.cpp index 06c5471977c5..af84e28cbdef 100644 --- a/src/core/vector/qgsvectorlayerutils.cpp +++ b/src/core/vector/qgsvectorlayerutils.cpp @@ -36,6 +36,7 @@ #include "qgsauxiliarystorage.h" #include "qgssymbollayerreference.h" #include "qgspainteffect.h" +#include "qgsunsetattributevalue.h" QgsFeatureIterator QgsVectorLayerUtils::getValuesIterator( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly ) { @@ -643,7 +644,29 @@ QgsFeature QgsVectorLayerUtils::duplicateFeature( QgsVectorLayer *layer, const Q QgsExpressionContext context = layer->createExpressionContext(); context.setFeature( feature ); - QgsFeature newFeature = createFeature( layer, feature.geometry(), feature.attributes().toMap(), &context ); + //respect field duplicate policy + QgsAttributeMap attributeMap; + const int fieldCount = layer->fields().count(); + for ( int fieldIdx = 0; fieldIdx < fieldCount; ++fieldIdx ) + { + const QgsField field = layer->fields().at( fieldIdx ); + switch ( field.duplicatePolicy() ) + { + case Qgis::FieldDomainDuplicatePolicy::DefaultValue: + //do nothing - default values ​​are determined + break; + + case Qgis::FieldDomainDuplicatePolicy::Duplicate: + attributeMap.insert( fieldIdx, feature.attribute( fieldIdx ) ); + break; + + case Qgis::FieldDomainDuplicatePolicy::UnsetField: + attributeMap.insert( fieldIdx, QgsUnsetAttributeValue() ); + break; + } + } + + QgsFeature newFeature = createFeature( layer, feature.geometry(), attributeMap, &context ); layer->addFeature( newFeature ); const QList relations = project->relationManager()->referencedRelations( layer ); diff --git a/src/gui/attributeformconfig/qgsattributetypedialog.cpp b/src/gui/attributeformconfig/qgsattributetypedialog.cpp index 3b1e7605935a..0e717e15a861 100644 --- a/src/gui/attributeformconfig/qgsattributetypedialog.cpp +++ b/src/gui/attributeformconfig/qgsattributetypedialog.cpp @@ -124,6 +124,12 @@ QgsAttributeTypeDialog::QgsAttributeTypeDialog( QgsVectorLayer *vl, int fieldIdx connect( mSplitPolicyComboBox, qOverload( &QComboBox::currentIndexChanged ), this, &QgsAttributeTypeDialog::updateSplitPolicyLabel ); updateSplitPolicyLabel(); + + mDuplicatePolicyComboBox->addItem( tr( "Duplicate Value" ), QVariant::fromValue( Qgis::FieldDomainDuplicatePolicy::Duplicate ) ); + mDuplicatePolicyComboBox->addItem( tr( "Use Default Value" ), QVariant::fromValue( Qgis::FieldDomainDuplicatePolicy::DefaultValue ) ); + mDuplicatePolicyComboBox->addItem( tr( "Remove Value" ), QVariant::fromValue( Qgis::FieldDomainDuplicatePolicy::UnsetField ) ); + connect( mDuplicatePolicyComboBox, qOverload( &QComboBox::currentIndexChanged ), this, &QgsAttributeTypeDialog::updateDuplicatePolicyLabel ); + updateDuplicatePolicyLabel(); } QgsAttributeTypeDialog::~QgsAttributeTypeDialog() @@ -381,6 +387,17 @@ void QgsAttributeTypeDialog::setSplitPolicy( Qgis::FieldDomainSplitPolicy policy updateSplitPolicyLabel(); } +Qgis::FieldDomainDuplicatePolicy QgsAttributeTypeDialog::duplicatePolicy() const +{ + return mDuplicatePolicyComboBox->currentData().value< Qgis::FieldDomainDuplicatePolicy >(); +} + +void QgsAttributeTypeDialog::setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy policy ) +{ + mDuplicatePolicyComboBox->setCurrentIndex( mDuplicatePolicyComboBox->findData( QVariant::fromValue( policy ) ) ); + updateSplitPolicyLabel(); +} + QString QgsAttributeTypeDialog::constraintExpression() const { return constraintExpressionWidget->asExpression(); @@ -498,6 +515,26 @@ void QgsAttributeTypeDialog::updateSplitPolicyLabel() mSplitPolicyDescriptionLabel->setText( QStringLiteral( "%1" ).arg( helperText ) ); } +void QgsAttributeTypeDialog::updateDuplicatePolicyLabel() +{ + QString helperText; + switch ( mDuplicatePolicyComboBox->currentData().value< Qgis::FieldDomainDuplicatePolicy >() ) + { + case Qgis::FieldDomainDuplicatePolicy::DefaultValue: + helperText = tr( "Resets the field by recalculating its default value." ); + break; + + case Qgis::FieldDomainDuplicatePolicy::Duplicate: + helperText = tr( "Copies the current field value without change." ); + break; + + case Qgis::FieldDomainDuplicatePolicy::UnsetField: + helperText = tr( "Clears the field to an unset state." ); + break; + } + mDuplicatePolicyDescriptionLabel->setText( QStringLiteral( "%1" ).arg( helperText ) ); +} + QStandardItem *QgsAttributeTypeDialog::currentItem() const { QStandardItemModel *widgetTypeModel = qobject_cast( mWidgetTypeComboBox->model() ); diff --git a/src/gui/attributeformconfig/qgsattributetypedialog.h b/src/gui/attributeformconfig/qgsattributetypedialog.h index 40305a0d9e32..8b9eb28c2eb3 100644 --- a/src/gui/attributeformconfig/qgsattributetypedialog.h +++ b/src/gui/attributeformconfig/qgsattributetypedialog.h @@ -245,6 +245,24 @@ class GUI_EXPORT QgsAttributeTypeDialog: public QWidget, private Ui::QgsAttribut */ void setSplitPolicy( Qgis::FieldDomainSplitPolicy policy ); + /** + * Returns the field's duplicate policy. + * + * \see setDuplicatePolicy() + * + * \since QGIS 3.38 + */ + Qgis::FieldDomainDuplicatePolicy duplicatePolicy() const; + + /** + * Sets the field's duplicate policy. + * + * \see duplicatePolicy() + * + * \since QGIS 3.38 + */ + void setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy policy ); + private slots: /** @@ -257,6 +275,8 @@ class GUI_EXPORT QgsAttributeTypeDialog: public QWidget, private Ui::QgsAttribut void updateSplitPolicyLabel(); + void updateDuplicatePolicyLabel(); + private: QgsVectorLayer *mLayer = nullptr; int mFieldIdx; diff --git a/src/gui/vector/qgsattributesformproperties.cpp b/src/gui/vector/qgsattributesformproperties.cpp index 905eaed0e0c1..c50c40eeeffa 100644 --- a/src/gui/vector/qgsattributesformproperties.cpp +++ b/src/gui/vector/qgsattributesformproperties.cpp @@ -302,6 +302,7 @@ void QgsAttributesFormProperties::loadAttributeTypeDialog() mAttributeTypeDialog->setUnique( constraints.constraints() & QgsFieldConstraints::ConstraintUnique ); mAttributeTypeDialog->setUniqueEnforced( constraints.constraintStrength( QgsFieldConstraints::ConstraintUnique ) == QgsFieldConstraints::ConstraintStrengthHard ); mAttributeTypeDialog->setSplitPolicy( cfg.mSplitPolicy ); + mAttributeTypeDialog->setDuplicatePolicy( cfg.mDuplicatePolicy ); QgsFieldConstraints::Constraints providerConstraints = QgsFieldConstraints::Constraints(); if ( constraints.constraintOrigin( QgsFieldConstraints::ConstraintNotNull ) == QgsFieldConstraints::ConstraintOriginProvider ) @@ -386,6 +387,7 @@ void QgsAttributesFormProperties::storeAttributeTypeDialog() cfg.mEditorWidgetConfig = mAttributeTypeDialog->editorWidgetConfig(); cfg.mSplitPolicy = mAttributeTypeDialog->splitPolicy(); + cfg.mDuplicatePolicy = mAttributeTypeDialog->duplicatePolicy(); const QString fieldName = mLayer->fields().at( mAttributeTypeDialog->fieldIdx() ).name(); @@ -1013,6 +1015,7 @@ void QgsAttributesFormProperties::apply() mLayer->setFieldAlias( idx, cfg.mAlias ); mLayer->setFieldSplitPolicy( idx, cfg.mSplitPolicy ); + mLayer->setFieldDuplicatePolicy( idx, cfg.mDuplicatePolicy ); } // tabs and groups @@ -1085,6 +1088,7 @@ QgsAttributesFormProperties::FieldConfig::FieldConfig( QgsVectorLayer *layer, in mEditorWidgetType = setup.type(); mEditorWidgetConfig = setup.config(); mSplitPolicy = layer->fields().at( idx ).splitPolicy(); + mDuplicatePolicy = layer->fields().at( idx ).duplicatePolicy(); } QgsAttributesFormProperties::FieldConfig::operator QVariant() diff --git a/src/gui/vector/qgsattributesformproperties.h b/src/gui/vector/qgsattributesformproperties.h index bcf7bde2e148..505aca6f120f 100644 --- a/src/gui/vector/qgsattributesformproperties.h +++ b/src/gui/vector/qgsattributesformproperties.h @@ -338,6 +338,7 @@ class GUI_EXPORT QgsAttributesFormProperties : public QWidget, public QgsExpress QgsPropertyCollection mDataDefinedProperties; QString mComment; Qgis::FieldDomainSplitPolicy mSplitPolicy = Qgis::FieldDomainSplitPolicy::Duplicate; + Qgis::FieldDomainDuplicatePolicy mDuplicatePolicy = Qgis::FieldDomainDuplicatePolicy::Duplicate; operator QVariant(); }; diff --git a/src/ui/attributeformconfig/qgsattributetypeedit.ui b/src/ui/attributeformconfig/qgsattributetypeedit.ui index 31bdb54180b4..7c46ca9b4f3a 100644 --- a/src/ui/attributeformconfig/qgsattributetypeedit.ui +++ b/src/ui/attributeformconfig/qgsattributetypeedit.ui @@ -149,7 +149,7 @@ - + Qt::StrongFocus @@ -283,10 +283,20 @@ Policies - - + + + + + + When duplicating features + + + + + + @@ -294,7 +304,17 @@ - + + + + TextLabel + + + true + + + + TextLabel From 17c6584976afc6219defa3b64e1fa3fabe74a92f Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 22 Apr 2024 11:34:50 +0200 Subject: [PATCH 2/5] DuplicatePolicy set/get etc. tests --- tests/src/core/testqgsfield.cpp | 11 +++++++ tests/src/python/test_qgsvectorlayer.py | 40 +++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/tests/src/core/testqgsfield.cpp b/tests/src/core/testqgsfield.cpp index 73c54163542e..7183897eb1cf 100644 --- a/tests/src/core/testqgsfield.cpp +++ b/tests/src/core/testqgsfield.cpp @@ -103,6 +103,7 @@ void TestQgsField::copy() original.setConstraints( constraints ); original.setReadOnly( true ); original.setSplitPolicy( Qgis::FieldDomainSplitPolicy::GeometryRatio ); + original.setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy::UnsetField ); original.setMetadata( {{ 1, QStringLiteral( "abc" )}, {2, 5 }} ); QVariantMap config; @@ -130,6 +131,7 @@ void TestQgsField::assignment() original.setConstraints( constraints ); original.setReadOnly( true ); original.setSplitPolicy( Qgis::FieldDomainSplitPolicy::GeometryRatio ); + original.setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy::UnsetField ); original.setMetadata( {{ 1, QStringLiteral( "abc" )}, {2, 5 }} ); QgsField copy; copy = original; @@ -204,6 +206,9 @@ void TestQgsField::gettersSetters() field.setSplitPolicy( Qgis::FieldDomainSplitPolicy::GeometryRatio ); QCOMPARE( field.splitPolicy(), Qgis::FieldDomainSplitPolicy::GeometryRatio ); + field.setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy::UnsetField ); + QCOMPARE( field.duplicatePolicy(), Qgis::FieldDomainDuplicatePolicy::UnsetField ); + field.setMetadata( {{ static_cast< int >( Qgis::FieldMetadataProperty::GeometryCrs ), QStringLiteral( "abc" )}, {2, 5 }} ); QMap< int, QVariant> expected {{ static_cast< int >( Qgis::FieldMetadataProperty::GeometryCrs ), QStringLiteral( "abc" )}, {2, 5 }}; QCOMPARE( field.metadata(), expected ); @@ -359,6 +364,12 @@ void TestQgsField::equality() field2.setSplitPolicy( Qgis::FieldDomainSplitPolicy::GeometryRatio ); QVERIFY( field1 == field2 ); + field1.setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy::UnsetField ); + QVERIFY( !( field1 == field2 ) ); + QVERIFY( field1 != field2 ); + field2.setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy::UnsetField ); + QVERIFY( field1 == field2 ); + field1.setMetadata( {{ static_cast< int >( Qgis::FieldMetadataProperty::GeometryCrs ), QStringLiteral( "abc" )}, {2, 5 }} ); QVERIFY( !( field1 == field2 ) ); QVERIFY( field1 != field2 ); diff --git a/tests/src/python/test_qgsvectorlayer.py b/tests/src/python/test_qgsvectorlayer.py index 44db1a908b84..2935554c8bfa 100644 --- a/tests/src/python/test_qgsvectorlayer.py +++ b/tests/src/python/test_qgsvectorlayer.py @@ -4547,6 +4547,46 @@ def test_split_policies(self): self.assertEqual(vl2.fields()[3].splitPolicy(), Qgis.FieldDomainSplitPolicy.GeometryRatio) + def test_duplicate_policies(self): + vl = QgsVectorLayer('Point?crs=epsg:3111&field=field_default:integer&field=field_dupe:integer&field=field_unset:integer', 'test', 'memory') + self.assertTrue(vl.isValid()) + + with self.assertRaises(KeyError): + vl.setFieldDuplicatePolicy(-1, Qgis.FieldDomainDuplicatePolicy.DefaultValue) + with self.assertRaises(KeyError): + vl.setFieldDuplicatePolicy(4, Qgis.FieldDomainDuplicatePolicy.DefaultValue) + + vl.setFieldDuplicatePolicy(0, Qgis.FieldDomainDuplicatePolicy.DefaultValue) + vl.setFieldDuplicatePolicy(1, Qgis.FieldDomainDuplicatePolicy.Duplicate) + vl.setFieldDuplicatePolicy(2, Qgis.FieldDomainDuplicatePolicy.UnsetField) + + self.assertEqual(vl.fields()[0].duplicatePolicy(), + Qgis.FieldDomainDuplicatePolicy.DefaultValue) + self.assertEqual(vl.fields()[1].duplicatePolicy(), + Qgis.FieldDomainDuplicatePolicy.Duplicate) + self.assertEqual(vl.fields()[2].duplicatePolicy(), + Qgis.FieldDomainDuplicatePolicy.UnsetField) + + p = QgsProject() + p.addMapLayer(vl) + + # test saving and restoring split policies + with tempfile.TemporaryDirectory() as temp: + self.assertTrue(p.write(temp + '/test.qgs')) + + p2 = QgsProject() + self.assertTrue(p2.read(temp + '/test.qgs')) + + vl2 = list(p2.mapLayers().values())[0] + self.assertEqual(vl2.name(), vl.name()) + + self.assertEqual(vl2.fields()[0].duplicatePolicy(), + Qgis.FieldDomainDuplicatePolicy.DefaultValue) + self.assertEqual(vl2.fields()[1].duplicatePolicy(), + Qgis.FieldDomainDuplicatePolicy.Duplicate) + self.assertEqual(vl2.fields()[2].duplicatePolicy(), + Qgis.FieldDomainDuplicatePolicy.UnsetField) + def test_selection_properties(self): vl = QgsVectorLayer( 'Point?crs=epsg:3111&field=field_default:integer&field=field_dupe:integer&field=field_unset:integer&field=field_ratio:integer', From a9747ae21c0eec802cfa86256806fd3dcee16535 Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 22 Apr 2024 11:35:20 +0200 Subject: [PATCH 3/5] DuplicatePolicy functionality test --- tests/src/python/test_qgsvectorlayerutils.py | 69 +++++++++++++++----- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/tests/src/python/test_qgsvectorlayerutils.py b/tests/src/python/test_qgsvectorlayerutils.py index 5e5e9bece97a..3b8b6732efff 100644 --- a/tests/src/python/test_qgsvectorlayerutils.py +++ b/tests/src/python/test_qgsvectorlayerutils.py @@ -15,6 +15,7 @@ from qgis.PyQt.QtCore import QVariant from qgis.core import ( NULL, + Qgis, QgsDefaultValue, QgsFeature, QgsField, @@ -478,29 +479,53 @@ def testCreateFeature(self): self.assertEqual(f.attributes(), ['test_5', 132, NULL]) def testDuplicateFeature(self): - """ test duplicating a feature """ + """ test duplicating a feature with relations """ project = QgsProject().instance() # LAYERS # - add first layer (parent) - layer1 = QgsVectorLayer("Point?field=fldtxt:string&field=pkid:integer", + layer1 = QgsVectorLayer("Point?field=fldtxt:string&field=pkid:integer&field=policycheck1value:text&field=policycheck2value:text&field=policycheck3value:text", "parentlayer", "memory") # > check first layer (parent) self.assertTrue(layer1.isValid()) - # - set the value for the copy + # - set the default values for pk and policy check and the field policy layer1.setDefaultValueDefinition(1, QgsDefaultValue("rand(1000,2000)")) + layer1.setDefaultValueDefinition(2, QgsDefaultValue("'Def Blabla L1'")) + layer1.setDefaultValueDefinition(3, QgsDefaultValue("'Def Blabla L1'")) + layer1.setDefaultValueDefinition(4, QgsDefaultValue("'Def Blabla L1'")) + layer1.setFieldDuplicatePolicy(2, Qgis.FieldDomainDuplicatePolicy.Duplicate) + layer1.setFieldDuplicatePolicy(3, Qgis.FieldDomainDuplicatePolicy.DefaultValue) + layer1.setFieldDuplicatePolicy(4, Qgis.FieldDomainDuplicatePolicy.UnsetField) # > check first layer (parent) self.assertTrue(layer1.isValid()) # - add second layer (child) - layer2 = QgsVectorLayer("Point?field=fldtxt:string&field=id:integer&field=foreign_key:integer", + layer2 = QgsVectorLayer("Point?field=fldtxt:string&field=id:integer&field=foreign_key:integer&field=policycheck1value:text&field=policycheck2value:text&field=policycheck3value:text", "childlayer1", "memory") # > check second layer (child) self.assertTrue(layer2.isValid()) - # - add second layer (child) - layer3 = QgsVectorLayer("Point?field=fldtxt:string&field=id:integer&field=foreign_key:integer", - "childlayer2", "memory") + # - set the default values for pk and policy check and the field policy + layer2.setDefaultValueDefinition(3, QgsDefaultValue("'Def Blabla L2'")) + layer2.setDefaultValueDefinition(4, QgsDefaultValue("'Def Blabla L2'")) + layer2.setDefaultValueDefinition(5, QgsDefaultValue("'Def Blabla L2'")) + layer2.setFieldDuplicatePolicy(3, Qgis.FieldDomainDuplicatePolicy.Duplicate) + layer2.setFieldDuplicatePolicy(4, Qgis.FieldDomainDuplicatePolicy.DefaultValue) + layer2.setFieldDuplicatePolicy(5, Qgis.FieldDomainDuplicatePolicy.UnsetField) # > check second layer (child) + self.assertTrue(layer2.isValid()) + # - add third layer (child) + layer3 = QgsVectorLayer("Point?field=fldtxt:string&field=id:integer&field=foreign_key:integer&field=policycheck1value:text&field=policycheck2value:text&field=policycheck3value:text", + "childlayer2", "memory") + # > check third layer (child) + self.assertTrue(layer3.isValid()) + # - set the default values for pk and policy check and the field policy + layer3.setDefaultValueDefinition(3, QgsDefaultValue("'Def Blabla L3'")) + layer3.setDefaultValueDefinition(4, QgsDefaultValue("'Def Blabla L3'")) + layer3.setDefaultValueDefinition(5, QgsDefaultValue("'Def Blabla L3'")) + layer3.setFieldDuplicatePolicy(3, Qgis.FieldDomainDuplicatePolicy.Duplicate) + layer3.setFieldDuplicatePolicy(4, Qgis.FieldDomainDuplicatePolicy.DefaultValue) + layer3.setFieldDuplicatePolicy(5, Qgis.FieldDomainDuplicatePolicy.UnsetField) + # > check third layer (child) self.assertTrue(layer3.isValid()) # - add layers project.addMapLayers([layer1, layer2, layer3]) @@ -509,34 +534,34 @@ def testDuplicateFeature(self): # - add 2 features on layer1 (parent) l1f1orig = QgsFeature() l1f1orig.setFields(layer1.fields()) - l1f1orig.setAttributes(["F_l1f1", 100]) + l1f1orig.setAttributes(["F_l1f1", 100, 'Orig Blabla L1', 'Orig Blabla L1', 'Orig Blabla L1']) l1f2orig = QgsFeature() l1f2orig.setFields(layer1.fields()) - l1f2orig.setAttributes(["F_l1f2", 101]) + l1f2orig.setAttributes(["F_l1f2", 101, 'Orig Blabla L1', 'Orig Blabla L1', 'Orig Blabla L1']) # > check by adding features self.assertTrue(layer1.dataProvider().addFeatures([l1f1orig, l1f2orig])) # add 4 features on layer2 (child) l2f1orig = QgsFeature() l2f1orig.setFields(layer2.fields()) - l2f1orig.setAttributes(["F_l2f1", 201, 100]) + l2f1orig.setAttributes(["F_l2f1", 201, 100, 'Orig Blabla L2', 'Orig Blabla L2', 'Orig Blabla L2']) l2f2orig = QgsFeature() l2f2orig.setFields(layer2.fields()) - l2f2orig.setAttributes(["F_l2f2", 202, 100]) + l2f2orig.setAttributes(["F_l2f2", 202, 100, 'Orig Blabla L2', 'Orig Blabla L2', 'Orig Blabla L2']) l2f3orig = QgsFeature() l2f3orig.setFields(layer2.fields()) - l2f3orig.setAttributes(["F_l2f3", 203, 100]) + l2f3orig.setAttributes(["F_l2f3", 203, 100, 'Orig Blabla L2', 'Orig Blabla L2', 'Orig Blabla L2']) l2f4orig = QgsFeature() l2f4orig.setFields(layer2.fields()) - l2f4orig.setAttributes(["F_l2f4", 204, 101]) + l2f4orig.setAttributes(["F_l2f4", 204, 101, 'Orig Blabla L2', 'Orig Blabla L2', 'Orig Blabla L2']) # > check by adding features self.assertTrue(layer2.dataProvider().addFeatures([l2f1orig, l2f2orig, l2f3orig, l2f4orig])) # add 2 features on layer3 (child) l3f1orig = QgsFeature() l3f1orig.setFields(layer3.fields()) - l3f1orig.setAttributes(["F_l3f1", 201, 100]) + l3f1orig.setAttributes(["F_l3f1", 301, 100, 'Orig Blabla L3', 'Orig Blabla L3', 'Orig Blabla L3']) l3f2orig = QgsFeature() l3f2orig.setFields(layer2.fields()) - l3f2orig.setAttributes(["F_l3f2", 202, 100]) + l3f2orig.setAttributes(["F_l3f2", 302, 100, 'Orig Blabla L3', 'Orig Blabla L3', 'Orig Blabla L3']) # > check by adding features self.assertTrue(layer3.dataProvider().addFeatures([l3f1orig, l3f2orig])) @@ -618,16 +643,30 @@ def testDuplicateFeature(self): results = QgsVectorLayerUtils.duplicateFeature(layer1, l1f1orig, project, 0) # > check if name is name of duplicated (pk is different) + # > and duplicate policy is concerned result_feature = results[0] self.assertEqual(result_feature.attribute('fldtxt'), l1f1orig.attribute('fldtxt')) + self.assertEqual(result_feature.attribute('policycheck1value'), 'Orig Blabla L1') # duplicated + self.assertEqual(result_feature.attribute('policycheck2value'), 'Def Blabla L1') # default Value + self.assertEqual(result_feature.attribute('policycheck3value'), None) # unset # > check duplicated children occurred on both layers self.assertEqual(len(results[1].layers()), 2) idx = results[1].layers().index(layer2) self.assertEqual(results[1].layers()[idx], layer2) self.assertTrue(results[1].duplicatedFeatures(layer2)) + for child_fid in results[1].duplicatedFeatures(layer2): + child_feature = layer2.getFeature(child_fid) + self.assertEqual(child_feature.attribute('policycheck1value'), 'Orig Blabla L2') # duplicated + self.assertEqual(child_feature.attribute('policycheck2value'), 'Def Blabla L2') # default Value + self.assertEqual(child_feature.attribute('policycheck3value'), None) # unset idx = results[1].layers().index(layer3) self.assertEqual(results[1].layers()[idx], layer3) self.assertTrue(results[1].duplicatedFeatures(layer3)) + for child_fid in results[1].duplicatedFeatures(layer3): + child_feature = layer3.getFeature(child_fid) + self.assertEqual(child_feature.attribute('policycheck1value'), 'Orig Blabla L3') # duplicated + self.assertEqual(child_feature.attribute('policycheck2value'), 'Def Blabla L3') # default Value + self.assertEqual(child_feature.attribute('policycheck3value'), None) # unset ''' # testoutput 2 From 39e6dbd0c1c50db1ac462dd4fe41df439fc4c7f5 Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 22 Apr 2024 13:20:08 +0200 Subject: [PATCH 4/5] fix datastream and comments --- python/PyQt6/core/auto_additions/qgis.py | 2 +- python/core/auto_additions/qgis.py | 2 +- src/core/qgis.h | 2 +- src/core/qgsfield.cpp | 1 + tests/src/core/testqgsfield.cpp | 1 + tests/src/python/test_qgsvectorlayerutils.py | 18 +++++++++--------- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/python/PyQt6/core/auto_additions/qgis.py b/python/PyQt6/core/auto_additions/qgis.py index e7670ddf8522..ef8d8971abe0 100644 --- a/python/PyQt6/core/auto_additions/qgis.py +++ b/python/PyQt6/core/auto_additions/qgis.py @@ -3218,7 +3218,7 @@ Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ = "Use default field value" Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ = "Duplicate original value" Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ = "Clears the field value so that the data provider backend will populate using any backend triggers or similar logic (since QGIS 3.30)" -Qgis.FieldDomainDuplicatePolicy.__doc__ = "Duplicate policy for field domains.\n\nWhen a feature is duplicated, defines how the value of attributes\nfollowing the domain are computed.\n\n.. versionadded:: 3.38\n\n" + '* ``DefaultValue``: ' + Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ + '\n' + '* ``Duplicate``: ' + Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ + '\n' + '* ``UnsetField``: ' + Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ +Qgis.FieldDomainDuplicatePolicy.__doc__ = "Duplicate policy for fields.\n\nWhen a feature is duplicated, defines how the value of attributes\nfollowing the domain are computed.\n\n.. versionadded:: 3.38\n\n" + '* ``DefaultValue``: ' + Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ + '\n' + '* ``Duplicate``: ' + Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ + '\n' + '* ``UnsetField``: ' + Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ # -- Qgis.FieldDomainDuplicatePolicy.baseClass = Qgis # monkey patching scoped based enum diff --git a/python/core/auto_additions/qgis.py b/python/core/auto_additions/qgis.py index 4fed270ba807..f885d9a5d822 100644 --- a/python/core/auto_additions/qgis.py +++ b/python/core/auto_additions/qgis.py @@ -3163,7 +3163,7 @@ Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ = "Use default field value" Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ = "Duplicate original value" Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ = "Clears the field value so that the data provider backend will populate using any backend triggers or similar logic (since QGIS 3.30)" -Qgis.FieldDomainDuplicatePolicy.__doc__ = "Duplicate policy for field domains.\n\nWhen a feature is duplicated, defines how the value of attributes\nfollowing the domain are computed.\n\n.. versionadded:: 3.38\n\n" + '* ``DefaultValue``: ' + Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ + '\n' + '* ``Duplicate``: ' + Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ + '\n' + '* ``UnsetField``: ' + Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ +Qgis.FieldDomainDuplicatePolicy.__doc__ = "Duplicate policy for fields.\n\nWhen a feature is duplicated, defines how the value of attributes\nfollowing the domain are computed.\n\n.. versionadded:: 3.38\n\n" + '* ``DefaultValue``: ' + Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ + '\n' + '* ``Duplicate``: ' + Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ + '\n' + '* ``UnsetField``: ' + Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ # -- Qgis.FieldDomainDuplicatePolicy.baseClass = Qgis # monkey patching scoped based enum diff --git a/src/core/qgis.h b/src/core/qgis.h index a3862cf2be7f..610718daf04a 100644 --- a/src/core/qgis.h +++ b/src/core/qgis.h @@ -3219,7 +3219,7 @@ class CORE_EXPORT Qgis Q_ENUM( FieldDomainMergePolicy ) /** - * Duplicate policy for field domains. + * Duplicate policy for fields. * * When a feature is duplicated, defines how the value of attributes * following the domain are computed. diff --git a/src/core/qgsfield.cpp b/src/core/qgsfield.cpp index 0fa86ff52709..1c3cc54e76eb 100644 --- a/src/core/qgsfield.cpp +++ b/src/core/qgsfield.cpp @@ -779,6 +779,7 @@ QDataStream &operator<<( QDataStream &out, const QgsField &field ) out << field.constraints().constraintDescription(); out << static_cast< quint32 >( field.subType() ); out << static_cast< int >( field.splitPolicy() ); + out << static_cast< int >( field.duplicatePolicy() ); out << field.metadata(); return out; } diff --git a/tests/src/core/testqgsfield.cpp b/tests/src/core/testqgsfield.cpp index 7183897eb1cf..81ecc7f94574 100644 --- a/tests/src/core/testqgsfield.cpp +++ b/tests/src/core/testqgsfield.cpp @@ -934,6 +934,7 @@ void TestQgsField::dataStream() original.setAlias( QStringLiteral( "alias" ) ); original.setDefaultValueDefinition( QgsDefaultValue( QStringLiteral( "default" ) ) ); original.setSplitPolicy( Qgis::FieldDomainSplitPolicy::GeometryRatio ); + original.setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy::DefaultValue ); QgsFieldConstraints constraints; constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginProvider ); constraints.setConstraint( QgsFieldConstraints::ConstraintUnique, QgsFieldConstraints::ConstraintOriginLayer ); diff --git a/tests/src/python/test_qgsvectorlayerutils.py b/tests/src/python/test_qgsvectorlayerutils.py index 3b8b6732efff..c2fa6f2d3716 100644 --- a/tests/src/python/test_qgsvectorlayerutils.py +++ b/tests/src/python/test_qgsvectorlayerutils.py @@ -646,9 +646,9 @@ def testDuplicateFeature(self): # > and duplicate policy is concerned result_feature = results[0] self.assertEqual(result_feature.attribute('fldtxt'), l1f1orig.attribute('fldtxt')) - self.assertEqual(result_feature.attribute('policycheck1value'), 'Orig Blabla L1') # duplicated - self.assertEqual(result_feature.attribute('policycheck2value'), 'Def Blabla L1') # default Value - self.assertEqual(result_feature.attribute('policycheck3value'), None) # unset + self.assertEqual(result_feature.attribute('policycheck1value'), 'Orig Blabla L1') # duplicated + self.assertEqual(result_feature.attribute('policycheck2value'), 'Def Blabla L1') # default Value + self.assertEqual(result_feature.attribute('policycheck3value'), None) # unset # > check duplicated children occurred on both layers self.assertEqual(len(results[1].layers()), 2) idx = results[1].layers().index(layer2) @@ -656,17 +656,17 @@ def testDuplicateFeature(self): self.assertTrue(results[1].duplicatedFeatures(layer2)) for child_fid in results[1].duplicatedFeatures(layer2): child_feature = layer2.getFeature(child_fid) - self.assertEqual(child_feature.attribute('policycheck1value'), 'Orig Blabla L2') # duplicated - self.assertEqual(child_feature.attribute('policycheck2value'), 'Def Blabla L2') # default Value - self.assertEqual(child_feature.attribute('policycheck3value'), None) # unset + self.assertEqual(child_feature.attribute('policycheck1value'), 'Orig Blabla L2') # duplicated + self.assertEqual(child_feature.attribute('policycheck2value'), 'Def Blabla L2') # default Value + self.assertEqual(child_feature.attribute('policycheck3value'), None) # unset idx = results[1].layers().index(layer3) self.assertEqual(results[1].layers()[idx], layer3) self.assertTrue(results[1].duplicatedFeatures(layer3)) for child_fid in results[1].duplicatedFeatures(layer3): child_feature = layer3.getFeature(child_fid) - self.assertEqual(child_feature.attribute('policycheck1value'), 'Orig Blabla L3') # duplicated - self.assertEqual(child_feature.attribute('policycheck2value'), 'Def Blabla L3') # default Value - self.assertEqual(child_feature.attribute('policycheck3value'), None) # unset + self.assertEqual(child_feature.attribute('policycheck1value'), 'Orig Blabla L3') # duplicated + self.assertEqual(child_feature.attribute('policycheck2value'), 'Def Blabla L3') # default Value + self.assertEqual(child_feature.attribute('policycheck3value'), None) # unset ''' # testoutput 2 From cfe71973c2f7496d08d38f2545199f03841d1869 Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 6 May 2024 19:45:41 +0200 Subject: [PATCH 5/5] rename FieldDomainDuplicatePolicy to FieldDuplicatePolicy because - not like the Merge or Split Policy it does not affect the FieldDomains but only the Fields instead --- python/PyQt6/core/auto_additions/qgis.py | 10 ++++----- python/PyQt6/core/auto_generated/qgis.sip.in | 2 +- .../PyQt6/core/auto_generated/qgsfield.sip.in | 4 ++-- .../vector/qgsvectorlayer.sip.in | 2 +- python/core/auto_additions/qgis.py | 10 ++++----- python/core/auto_generated/qgis.sip.in | 2 +- python/core/auto_generated/qgsfield.sip.in | 4 ++-- .../vector/qgsvectorlayer.sip.in | 2 +- src/core/qgis.h | 7 +++--- src/core/qgsfield.cpp | 6 ++--- src/core/qgsfield.h | 4 ++-- src/core/qgsfield_p.h | 2 +- src/core/vector/qgsvectorlayer.cpp | 4 ++-- src/core/vector/qgsvectorlayer.h | 6 ++--- src/core/vector/qgsvectorlayerutils.cpp | 6 ++--- .../qgsattributetypedialog.cpp | 20 ++++++++--------- .../qgsattributetypedialog.h | 4 ++-- src/gui/vector/qgsattributesformproperties.h | 2 +- tests/src/core/testqgsfield.cpp | 14 ++++++------ tests/src/python/test_qgsvectorlayer.py | 22 +++++++++---------- tests/src/python/test_qgsvectorlayerutils.py | 18 +++++++-------- 21 files changed, 75 insertions(+), 76 deletions(-) diff --git a/python/PyQt6/core/auto_additions/qgis.py b/python/PyQt6/core/auto_additions/qgis.py index ef8d8971abe0..361389af6f2d 100644 --- a/python/PyQt6/core/auto_additions/qgis.py +++ b/python/PyQt6/core/auto_additions/qgis.py @@ -3215,12 +3215,12 @@ # -- Qgis.FieldDomainMergePolicy.baseClass = Qgis # monkey patching scoped based enum -Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ = "Use default field value" -Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ = "Duplicate original value" -Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ = "Clears the field value so that the data provider backend will populate using any backend triggers or similar logic (since QGIS 3.30)" -Qgis.FieldDomainDuplicatePolicy.__doc__ = "Duplicate policy for fields.\n\nWhen a feature is duplicated, defines how the value of attributes\nfollowing the domain are computed.\n\n.. versionadded:: 3.38\n\n" + '* ``DefaultValue``: ' + Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ + '\n' + '* ``Duplicate``: ' + Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ + '\n' + '* ``UnsetField``: ' + Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ +Qgis.FieldDuplicatePolicy.DefaultValue.__doc__ = "Use default field value" +Qgis.FieldDuplicatePolicy.Duplicate.__doc__ = "Duplicate original value" +Qgis.FieldDuplicatePolicy.UnsetField.__doc__ = "Clears the field value so that the data provider backend will populate using any backend triggers or similar logic (since QGIS 3.30)" +Qgis.FieldDuplicatePolicy.__doc__ = "Duplicate policy for fields.\n\nWhen a feature is duplicated, defines how the value of attributes are computed.\n\n.. versionadded:: 3.38\n\n" + '* ``DefaultValue``: ' + Qgis.FieldDuplicatePolicy.DefaultValue.__doc__ + '\n' + '* ``Duplicate``: ' + Qgis.FieldDuplicatePolicy.Duplicate.__doc__ + '\n' + '* ``UnsetField``: ' + Qgis.FieldDuplicatePolicy.UnsetField.__doc__ # -- -Qgis.FieldDomainDuplicatePolicy.baseClass = Qgis +Qgis.FieldDuplicatePolicy.baseClass = Qgis # monkey patching scoped based enum Qgis.FieldDomainType.Coded.__doc__ = "Coded field domain" Qgis.FieldDomainType.Range.__doc__ = "Numeric range field domain (min/max)" diff --git a/python/PyQt6/core/auto_generated/qgis.sip.in b/python/PyQt6/core/auto_generated/qgis.sip.in index 1376e9118e23..82e79b2a6769 100644 --- a/python/PyQt6/core/auto_generated/qgis.sip.in +++ b/python/PyQt6/core/auto_generated/qgis.sip.in @@ -1826,7 +1826,7 @@ The development version GeometryWeighted, }; - enum class FieldDomainDuplicatePolicy /BaseType=IntEnum/ + enum class FieldDuplicatePolicy /BaseType=IntEnum/ { DefaultValue, Duplicate, diff --git a/python/PyQt6/core/auto_generated/qgsfield.sip.in b/python/PyQt6/core/auto_generated/qgsfield.sip.in index 65130f8ccf9b..0193040936b6 100644 --- a/python/PyQt6/core/auto_generated/qgsfield.sip.in +++ b/python/PyQt6/core/auto_generated/qgsfield.sip.in @@ -468,7 +468,7 @@ be handled during a split operation. .. versionadded:: 3.30 %End - Qgis::FieldDomainDuplicatePolicy duplicatePolicy() const; + Qgis::FieldDuplicatePolicy duplicatePolicy() const; %Docstring Returns the field's duplicate policy, which indicates how field values should be handled during a duplicate operation. @@ -478,7 +478,7 @@ be handled during a duplicate operation. .. versionadded:: 3.38 %End - void setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy policy ); + void setDuplicatePolicy( Qgis::FieldDuplicatePolicy policy ); %Docstring Sets the field's duplicate ``policy``, which indicates how field values should be handled during a duplicate operation. diff --git a/python/PyQt6/core/auto_generated/vector/qgsvectorlayer.sip.in b/python/PyQt6/core/auto_generated/vector/qgsvectorlayer.sip.in index bb1bd4e01ff5..b54fb80e6f10 100644 --- a/python/PyQt6/core/auto_generated/vector/qgsvectorlayer.sip.in +++ b/python/PyQt6/core/auto_generated/vector/qgsvectorlayer.sip.in @@ -1935,7 +1935,7 @@ Sets a split ``policy`` for the field with the specified index. } %End - void setFieldDuplicatePolicy( int index, Qgis::FieldDomainDuplicatePolicy policy ); + void setFieldDuplicatePolicy( int index, Qgis::FieldDuplicatePolicy policy ); %Docstring Sets a duplicate ``policy`` for the field with the specified index. diff --git a/python/core/auto_additions/qgis.py b/python/core/auto_additions/qgis.py index f885d9a5d822..15f42e5c2d9a 100644 --- a/python/core/auto_additions/qgis.py +++ b/python/core/auto_additions/qgis.py @@ -3160,12 +3160,12 @@ # -- Qgis.FieldDomainMergePolicy.baseClass = Qgis # monkey patching scoped based enum -Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ = "Use default field value" -Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ = "Duplicate original value" -Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ = "Clears the field value so that the data provider backend will populate using any backend triggers or similar logic (since QGIS 3.30)" -Qgis.FieldDomainDuplicatePolicy.__doc__ = "Duplicate policy for fields.\n\nWhen a feature is duplicated, defines how the value of attributes\nfollowing the domain are computed.\n\n.. versionadded:: 3.38\n\n" + '* ``DefaultValue``: ' + Qgis.FieldDomainDuplicatePolicy.DefaultValue.__doc__ + '\n' + '* ``Duplicate``: ' + Qgis.FieldDomainDuplicatePolicy.Duplicate.__doc__ + '\n' + '* ``UnsetField``: ' + Qgis.FieldDomainDuplicatePolicy.UnsetField.__doc__ +Qgis.FieldDuplicatePolicy.DefaultValue.__doc__ = "Use default field value" +Qgis.FieldDuplicatePolicy.Duplicate.__doc__ = "Duplicate original value" +Qgis.FieldDuplicatePolicy.UnsetField.__doc__ = "Clears the field value so that the data provider backend will populate using any backend triggers or similar logic (since QGIS 3.30)" +Qgis.FieldDuplicatePolicy.__doc__ = "Duplicate policy for fields.\n\nWhen a feature is duplicated, defines how the value of attributes are computed.\n\n.. versionadded:: 3.38\n\n" + '* ``DefaultValue``: ' + Qgis.FieldDuplicatePolicy.DefaultValue.__doc__ + '\n' + '* ``Duplicate``: ' + Qgis.FieldDuplicatePolicy.Duplicate.__doc__ + '\n' + '* ``UnsetField``: ' + Qgis.FieldDuplicatePolicy.UnsetField.__doc__ # -- -Qgis.FieldDomainDuplicatePolicy.baseClass = Qgis +Qgis.FieldDuplicatePolicy.baseClass = Qgis # monkey patching scoped based enum Qgis.FieldDomainType.Coded.__doc__ = "Coded field domain" Qgis.FieldDomainType.Range.__doc__ = "Numeric range field domain (min/max)" diff --git a/python/core/auto_generated/qgis.sip.in b/python/core/auto_generated/qgis.sip.in index 0a65844c0e3c..b1493a20cbdd 100644 --- a/python/core/auto_generated/qgis.sip.in +++ b/python/core/auto_generated/qgis.sip.in @@ -1826,7 +1826,7 @@ The development version GeometryWeighted, }; - enum class FieldDomainDuplicatePolicy + enum class FieldDuplicatePolicy { DefaultValue, Duplicate, diff --git a/python/core/auto_generated/qgsfield.sip.in b/python/core/auto_generated/qgsfield.sip.in index 65130f8ccf9b..0193040936b6 100644 --- a/python/core/auto_generated/qgsfield.sip.in +++ b/python/core/auto_generated/qgsfield.sip.in @@ -468,7 +468,7 @@ be handled during a split operation. .. versionadded:: 3.30 %End - Qgis::FieldDomainDuplicatePolicy duplicatePolicy() const; + Qgis::FieldDuplicatePolicy duplicatePolicy() const; %Docstring Returns the field's duplicate policy, which indicates how field values should be handled during a duplicate operation. @@ -478,7 +478,7 @@ be handled during a duplicate operation. .. versionadded:: 3.38 %End - void setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy policy ); + void setDuplicatePolicy( Qgis::FieldDuplicatePolicy policy ); %Docstring Sets the field's duplicate ``policy``, which indicates how field values should be handled during a duplicate operation. diff --git a/python/core/auto_generated/vector/qgsvectorlayer.sip.in b/python/core/auto_generated/vector/qgsvectorlayer.sip.in index bb1bd4e01ff5..b54fb80e6f10 100644 --- a/python/core/auto_generated/vector/qgsvectorlayer.sip.in +++ b/python/core/auto_generated/vector/qgsvectorlayer.sip.in @@ -1935,7 +1935,7 @@ Sets a split ``policy`` for the field with the specified index. } %End - void setFieldDuplicatePolicy( int index, Qgis::FieldDomainDuplicatePolicy policy ); + void setFieldDuplicatePolicy( int index, Qgis::FieldDuplicatePolicy policy ); %Docstring Sets a duplicate ``policy`` for the field with the specified index. diff --git a/src/core/qgis.h b/src/core/qgis.h index 610718daf04a..475c0baad10c 100644 --- a/src/core/qgis.h +++ b/src/core/qgis.h @@ -3221,18 +3221,17 @@ class CORE_EXPORT Qgis /** * Duplicate policy for fields. * - * When a feature is duplicated, defines how the value of attributes - * following the domain are computed. + * When a feature is duplicated, defines how the value of attributes are computed. * * \since QGIS 3.38 */ - enum class FieldDomainDuplicatePolicy : int + enum class FieldDuplicatePolicy : int { DefaultValue, //!< Use default field value Duplicate, //!< Duplicate original value UnsetField, //!< Clears the field value so that the data provider backend will populate using any backend triggers or similar logic (since QGIS 3.30) }; - Q_ENUM( FieldDomainDuplicatePolicy ) + Q_ENUM( FieldDuplicatePolicy ) /** * Types of field domain diff --git a/src/core/qgsfield.cpp b/src/core/qgsfield.cpp index 1c3cc54e76eb..14107b82885f 100644 --- a/src/core/qgsfield.cpp +++ b/src/core/qgsfield.cpp @@ -741,12 +741,12 @@ void QgsField::setSplitPolicy( Qgis::FieldDomainSplitPolicy policy ) d->splitPolicy = policy; } -Qgis::FieldDomainDuplicatePolicy QgsField::duplicatePolicy() const +Qgis::FieldDuplicatePolicy QgsField::duplicatePolicy() const { return d->duplicatePolicy; } -void QgsField::setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy policy ) +void QgsField::setDuplicatePolicy( Qgis::FieldDuplicatePolicy policy ) { d->duplicatePolicy = policy; } @@ -823,7 +823,7 @@ QDataStream &operator>>( QDataStream &in, QgsField &field ) field.setAlias( alias ); field.setDefaultValueDefinition( QgsDefaultValue( defaultValueExpression, applyOnUpdate ) ); field.setSplitPolicy( static_cast< Qgis::FieldDomainSplitPolicy >( splitPolicy ) ); - field.setDuplicatePolicy( static_cast< Qgis::FieldDomainDuplicatePolicy >( duplicatePolicy ) ); + field.setDuplicatePolicy( static_cast< Qgis::FieldDuplicatePolicy >( duplicatePolicy ) ); QgsFieldConstraints fieldConstraints; if ( constraints & QgsFieldConstraints::ConstraintNotNull ) { diff --git a/src/core/qgsfield.h b/src/core/qgsfield.h index 03c44be9d57e..0c67ca03cfbb 100644 --- a/src/core/qgsfield.h +++ b/src/core/qgsfield.h @@ -502,7 +502,7 @@ class CORE_EXPORT QgsField * * \since QGIS 3.38 */ - Qgis::FieldDomainDuplicatePolicy duplicatePolicy() const; + Qgis::FieldDuplicatePolicy duplicatePolicy() const; /** * Sets the field's duplicate \a policy, which indicates how field values should @@ -512,7 +512,7 @@ class CORE_EXPORT QgsField * * \since QGIS 3.38 */ - void setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy policy ); + void setDuplicatePolicy( Qgis::FieldDuplicatePolicy policy ); #ifdef SIP_RUN SIP_PYOBJECT __repr__(); diff --git a/src/core/qgsfield_p.h b/src/core/qgsfield_p.h index beab53710a6f..3889bbef810f 100644 --- a/src/core/qgsfield_p.h +++ b/src/core/qgsfield_p.h @@ -147,7 +147,7 @@ class QgsFieldPrivate : public QSharedData Qgis::FieldDomainSplitPolicy splitPolicy = Qgis::FieldDomainSplitPolicy::Duplicate; //! Duplicate policy - Qgis::FieldDomainDuplicatePolicy duplicatePolicy = Qgis::FieldDomainDuplicatePolicy::Duplicate; + Qgis::FieldDuplicatePolicy duplicatePolicy = Qgis::FieldDuplicatePolicy::Duplicate; //! Read-only bool isReadOnly = false; diff --git a/src/core/vector/qgsvectorlayer.cpp b/src/core/vector/qgsvectorlayer.cpp index 722b6aebf699..308bea7a1d69 100644 --- a/src/core/vector/qgsvectorlayer.cpp +++ b/src/core/vector/qgsvectorlayer.cpp @@ -2587,7 +2587,7 @@ bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMes { const QDomElement duplicatePolicyElem = duplicatePolicyNodeList.at( i ).toElement(); const QString field = duplicatePolicyElem.attribute( QStringLiteral( "field" ) ); - const Qgis::FieldDomainDuplicatePolicy policy = qgsEnumKeyToValue( duplicatePolicyElem.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDomainDuplicatePolicy::Duplicate ); + const Qgis::FieldDuplicatePolicy policy = qgsEnumKeyToValue( duplicatePolicyElem.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDuplicatePolicy::Duplicate ); mAttributeDuplicatePolicy.insert( field, policy ); } } @@ -3620,7 +3620,7 @@ void QgsVectorLayer::setFieldSplitPolicy( int index, Qgis::FieldDomainSplitPolic emit layerModified(); // TODO[MD]: should have a different signal? } -void QgsVectorLayer::setFieldDuplicatePolicy( int index, Qgis::FieldDomainDuplicatePolicy policy ) +void QgsVectorLayer::setFieldDuplicatePolicy( int index, Qgis::FieldDuplicatePolicy policy ) { QGIS_PROTECT_QOBJECT_THREAD_ACCESS diff --git a/src/core/vector/qgsvectorlayer.h b/src/core/vector/qgsvectorlayer.h index 7f9fe77342c2..07a184243aae 100644 --- a/src/core/vector/qgsvectorlayer.h +++ b/src/core/vector/qgsvectorlayer.h @@ -1847,7 +1847,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte * * \since QGIS 3.38 */ - void setFieldDuplicatePolicy( int index, Qgis::FieldDomainDuplicatePolicy policy ); + void setFieldDuplicatePolicy( int index, Qgis::FieldDuplicatePolicy policy ); #else /** @@ -1876,7 +1876,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte * \throws KeyError if no field with the specified index exists * \since QGIS 3.38 */ - void setFieldDuplicatePolicy( int index, Qgis::FieldDomainDuplicatePolicy policy ); + void setFieldDuplicatePolicy( int index, Qgis::FieldDuplicatePolicy policy ); % MethodCode if ( a0 < 0 || a0 >= sipCpp->fields().count() ) @@ -2896,7 +2896,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte QMap< QString, Qgis::FieldDomainSplitPolicy > mAttributeSplitPolicy; //! Map that stores the duplicate policy for attributes - QMap< QString, Qgis::FieldDomainDuplicatePolicy > mAttributeDuplicatePolicy; + QMap< QString, Qgis::FieldDuplicatePolicy > mAttributeDuplicatePolicy; //! An internal structure to keep track of fields that have a defaultValueOnUpdate QSet mDefaultValueOnUpdateFields; diff --git a/src/core/vector/qgsvectorlayerutils.cpp b/src/core/vector/qgsvectorlayerutils.cpp index af84e28cbdef..6ea707ab2756 100644 --- a/src/core/vector/qgsvectorlayerutils.cpp +++ b/src/core/vector/qgsvectorlayerutils.cpp @@ -652,15 +652,15 @@ QgsFeature QgsVectorLayerUtils::duplicateFeature( QgsVectorLayer *layer, const Q const QgsField field = layer->fields().at( fieldIdx ); switch ( field.duplicatePolicy() ) { - case Qgis::FieldDomainDuplicatePolicy::DefaultValue: + case Qgis::FieldDuplicatePolicy::DefaultValue: //do nothing - default values ​​are determined break; - case Qgis::FieldDomainDuplicatePolicy::Duplicate: + case Qgis::FieldDuplicatePolicy::Duplicate: attributeMap.insert( fieldIdx, feature.attribute( fieldIdx ) ); break; - case Qgis::FieldDomainDuplicatePolicy::UnsetField: + case Qgis::FieldDuplicatePolicy::UnsetField: attributeMap.insert( fieldIdx, QgsUnsetAttributeValue() ); break; } diff --git a/src/gui/attributeformconfig/qgsattributetypedialog.cpp b/src/gui/attributeformconfig/qgsattributetypedialog.cpp index 0e717e15a861..71135f4e904a 100644 --- a/src/gui/attributeformconfig/qgsattributetypedialog.cpp +++ b/src/gui/attributeformconfig/qgsattributetypedialog.cpp @@ -125,9 +125,9 @@ QgsAttributeTypeDialog::QgsAttributeTypeDialog( QgsVectorLayer *vl, int fieldIdx connect( mSplitPolicyComboBox, qOverload( &QComboBox::currentIndexChanged ), this, &QgsAttributeTypeDialog::updateSplitPolicyLabel ); updateSplitPolicyLabel(); - mDuplicatePolicyComboBox->addItem( tr( "Duplicate Value" ), QVariant::fromValue( Qgis::FieldDomainDuplicatePolicy::Duplicate ) ); - mDuplicatePolicyComboBox->addItem( tr( "Use Default Value" ), QVariant::fromValue( Qgis::FieldDomainDuplicatePolicy::DefaultValue ) ); - mDuplicatePolicyComboBox->addItem( tr( "Remove Value" ), QVariant::fromValue( Qgis::FieldDomainDuplicatePolicy::UnsetField ) ); + mDuplicatePolicyComboBox->addItem( tr( "Duplicate Value" ), QVariant::fromValue( Qgis::FieldDuplicatePolicy::Duplicate ) ); + mDuplicatePolicyComboBox->addItem( tr( "Use Default Value" ), QVariant::fromValue( Qgis::FieldDuplicatePolicy::DefaultValue ) ); + mDuplicatePolicyComboBox->addItem( tr( "Remove Value" ), QVariant::fromValue( Qgis::FieldDuplicatePolicy::UnsetField ) ); connect( mDuplicatePolicyComboBox, qOverload( &QComboBox::currentIndexChanged ), this, &QgsAttributeTypeDialog::updateDuplicatePolicyLabel ); updateDuplicatePolicyLabel(); } @@ -387,12 +387,12 @@ void QgsAttributeTypeDialog::setSplitPolicy( Qgis::FieldDomainSplitPolicy policy updateSplitPolicyLabel(); } -Qgis::FieldDomainDuplicatePolicy QgsAttributeTypeDialog::duplicatePolicy() const +Qgis::FieldDuplicatePolicy QgsAttributeTypeDialog::duplicatePolicy() const { - return mDuplicatePolicyComboBox->currentData().value< Qgis::FieldDomainDuplicatePolicy >(); + return mDuplicatePolicyComboBox->currentData().value< Qgis::FieldDuplicatePolicy >(); } -void QgsAttributeTypeDialog::setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy policy ) +void QgsAttributeTypeDialog::setDuplicatePolicy( Qgis::FieldDuplicatePolicy policy ) { mDuplicatePolicyComboBox->setCurrentIndex( mDuplicatePolicyComboBox->findData( QVariant::fromValue( policy ) ) ); updateSplitPolicyLabel(); @@ -518,17 +518,17 @@ void QgsAttributeTypeDialog::updateSplitPolicyLabel() void QgsAttributeTypeDialog::updateDuplicatePolicyLabel() { QString helperText; - switch ( mDuplicatePolicyComboBox->currentData().value< Qgis::FieldDomainDuplicatePolicy >() ) + switch ( mDuplicatePolicyComboBox->currentData().value< Qgis::FieldDuplicatePolicy >() ) { - case Qgis::FieldDomainDuplicatePolicy::DefaultValue: + case Qgis::FieldDuplicatePolicy::DefaultValue: helperText = tr( "Resets the field by recalculating its default value." ); break; - case Qgis::FieldDomainDuplicatePolicy::Duplicate: + case Qgis::FieldDuplicatePolicy::Duplicate: helperText = tr( "Copies the current field value without change." ); break; - case Qgis::FieldDomainDuplicatePolicy::UnsetField: + case Qgis::FieldDuplicatePolicy::UnsetField: helperText = tr( "Clears the field to an unset state." ); break; } diff --git a/src/gui/attributeformconfig/qgsattributetypedialog.h b/src/gui/attributeformconfig/qgsattributetypedialog.h index 8b9eb28c2eb3..4f65c771679c 100644 --- a/src/gui/attributeformconfig/qgsattributetypedialog.h +++ b/src/gui/attributeformconfig/qgsattributetypedialog.h @@ -252,7 +252,7 @@ class GUI_EXPORT QgsAttributeTypeDialog: public QWidget, private Ui::QgsAttribut * * \since QGIS 3.38 */ - Qgis::FieldDomainDuplicatePolicy duplicatePolicy() const; + Qgis::FieldDuplicatePolicy duplicatePolicy() const; /** * Sets the field's duplicate policy. @@ -261,7 +261,7 @@ class GUI_EXPORT QgsAttributeTypeDialog: public QWidget, private Ui::QgsAttribut * * \since QGIS 3.38 */ - void setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy policy ); + void setDuplicatePolicy( Qgis::FieldDuplicatePolicy policy ); private slots: diff --git a/src/gui/vector/qgsattributesformproperties.h b/src/gui/vector/qgsattributesformproperties.h index 505aca6f120f..4eef017a9905 100644 --- a/src/gui/vector/qgsattributesformproperties.h +++ b/src/gui/vector/qgsattributesformproperties.h @@ -338,7 +338,7 @@ class GUI_EXPORT QgsAttributesFormProperties : public QWidget, public QgsExpress QgsPropertyCollection mDataDefinedProperties; QString mComment; Qgis::FieldDomainSplitPolicy mSplitPolicy = Qgis::FieldDomainSplitPolicy::Duplicate; - Qgis::FieldDomainDuplicatePolicy mDuplicatePolicy = Qgis::FieldDomainDuplicatePolicy::Duplicate; + Qgis::FieldDuplicatePolicy mDuplicatePolicy = Qgis::FieldDuplicatePolicy::Duplicate; operator QVariant(); }; diff --git a/tests/src/core/testqgsfield.cpp b/tests/src/core/testqgsfield.cpp index 81ecc7f94574..d596e7f30576 100644 --- a/tests/src/core/testqgsfield.cpp +++ b/tests/src/core/testqgsfield.cpp @@ -103,7 +103,7 @@ void TestQgsField::copy() original.setConstraints( constraints ); original.setReadOnly( true ); original.setSplitPolicy( Qgis::FieldDomainSplitPolicy::GeometryRatio ); - original.setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy::UnsetField ); + original.setDuplicatePolicy( Qgis::FieldDuplicatePolicy::UnsetField ); original.setMetadata( {{ 1, QStringLiteral( "abc" )}, {2, 5 }} ); QVariantMap config; @@ -131,7 +131,7 @@ void TestQgsField::assignment() original.setConstraints( constraints ); original.setReadOnly( true ); original.setSplitPolicy( Qgis::FieldDomainSplitPolicy::GeometryRatio ); - original.setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy::UnsetField ); + original.setDuplicatePolicy( Qgis::FieldDuplicatePolicy::UnsetField ); original.setMetadata( {{ 1, QStringLiteral( "abc" )}, {2, 5 }} ); QgsField copy; copy = original; @@ -206,8 +206,8 @@ void TestQgsField::gettersSetters() field.setSplitPolicy( Qgis::FieldDomainSplitPolicy::GeometryRatio ); QCOMPARE( field.splitPolicy(), Qgis::FieldDomainSplitPolicy::GeometryRatio ); - field.setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy::UnsetField ); - QCOMPARE( field.duplicatePolicy(), Qgis::FieldDomainDuplicatePolicy::UnsetField ); + field.setDuplicatePolicy( Qgis::FieldDuplicatePolicy::UnsetField ); + QCOMPARE( field.duplicatePolicy(), Qgis::FieldDuplicatePolicy::UnsetField ); field.setMetadata( {{ static_cast< int >( Qgis::FieldMetadataProperty::GeometryCrs ), QStringLiteral( "abc" )}, {2, 5 }} ); QMap< int, QVariant> expected {{ static_cast< int >( Qgis::FieldMetadataProperty::GeometryCrs ), QStringLiteral( "abc" )}, {2, 5 }}; @@ -364,10 +364,10 @@ void TestQgsField::equality() field2.setSplitPolicy( Qgis::FieldDomainSplitPolicy::GeometryRatio ); QVERIFY( field1 == field2 ); - field1.setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy::UnsetField ); + field1.setDuplicatePolicy( Qgis::FieldDuplicatePolicy::UnsetField ); QVERIFY( !( field1 == field2 ) ); QVERIFY( field1 != field2 ); - field2.setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy::UnsetField ); + field2.setDuplicatePolicy( Qgis::FieldDuplicatePolicy::UnsetField ); QVERIFY( field1 == field2 ); field1.setMetadata( {{ static_cast< int >( Qgis::FieldMetadataProperty::GeometryCrs ), QStringLiteral( "abc" )}, {2, 5 }} ); @@ -934,7 +934,7 @@ void TestQgsField::dataStream() original.setAlias( QStringLiteral( "alias" ) ); original.setDefaultValueDefinition( QgsDefaultValue( QStringLiteral( "default" ) ) ); original.setSplitPolicy( Qgis::FieldDomainSplitPolicy::GeometryRatio ); - original.setDuplicatePolicy( Qgis::FieldDomainDuplicatePolicy::DefaultValue ); + original.setDuplicatePolicy( Qgis::FieldDuplicatePolicy::DefaultValue ); QgsFieldConstraints constraints; constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginProvider ); constraints.setConstraint( QgsFieldConstraints::ConstraintUnique, QgsFieldConstraints::ConstraintOriginLayer ); diff --git a/tests/src/python/test_qgsvectorlayer.py b/tests/src/python/test_qgsvectorlayer.py index 2935554c8bfa..7513d1bd1c1a 100644 --- a/tests/src/python/test_qgsvectorlayer.py +++ b/tests/src/python/test_qgsvectorlayer.py @@ -4552,20 +4552,20 @@ def test_duplicate_policies(self): self.assertTrue(vl.isValid()) with self.assertRaises(KeyError): - vl.setFieldDuplicatePolicy(-1, Qgis.FieldDomainDuplicatePolicy.DefaultValue) + vl.setFieldDuplicatePolicy(-1, Qgis.FieldDuplicatePolicy.DefaultValue) with self.assertRaises(KeyError): - vl.setFieldDuplicatePolicy(4, Qgis.FieldDomainDuplicatePolicy.DefaultValue) + vl.setFieldDuplicatePolicy(4, Qgis.FieldDuplicatePolicy.DefaultValue) - vl.setFieldDuplicatePolicy(0, Qgis.FieldDomainDuplicatePolicy.DefaultValue) - vl.setFieldDuplicatePolicy(1, Qgis.FieldDomainDuplicatePolicy.Duplicate) - vl.setFieldDuplicatePolicy(2, Qgis.FieldDomainDuplicatePolicy.UnsetField) + vl.setFieldDuplicatePolicy(0, Qgis.FieldDuplicatePolicy.DefaultValue) + vl.setFieldDuplicatePolicy(1, Qgis.FieldDuplicatePolicy.Duplicate) + vl.setFieldDuplicatePolicy(2, Qgis.FieldDuplicatePolicy.UnsetField) self.assertEqual(vl.fields()[0].duplicatePolicy(), - Qgis.FieldDomainDuplicatePolicy.DefaultValue) + Qgis.FieldDuplicatePolicy.DefaultValue) self.assertEqual(vl.fields()[1].duplicatePolicy(), - Qgis.FieldDomainDuplicatePolicy.Duplicate) + Qgis.FieldDuplicatePolicy.Duplicate) self.assertEqual(vl.fields()[2].duplicatePolicy(), - Qgis.FieldDomainDuplicatePolicy.UnsetField) + Qgis.FieldDuplicatePolicy.UnsetField) p = QgsProject() p.addMapLayer(vl) @@ -4581,11 +4581,11 @@ def test_duplicate_policies(self): self.assertEqual(vl2.name(), vl.name()) self.assertEqual(vl2.fields()[0].duplicatePolicy(), - Qgis.FieldDomainDuplicatePolicy.DefaultValue) + Qgis.FieldDuplicatePolicy.DefaultValue) self.assertEqual(vl2.fields()[1].duplicatePolicy(), - Qgis.FieldDomainDuplicatePolicy.Duplicate) + Qgis.FieldDuplicatePolicy.Duplicate) self.assertEqual(vl2.fields()[2].duplicatePolicy(), - Qgis.FieldDomainDuplicatePolicy.UnsetField) + Qgis.FieldDuplicatePolicy.UnsetField) def test_selection_properties(self): vl = QgsVectorLayer( diff --git a/tests/src/python/test_qgsvectorlayerutils.py b/tests/src/python/test_qgsvectorlayerutils.py index c2fa6f2d3716..a995a0da48aa 100644 --- a/tests/src/python/test_qgsvectorlayerutils.py +++ b/tests/src/python/test_qgsvectorlayerutils.py @@ -494,9 +494,9 @@ def testDuplicateFeature(self): layer1.setDefaultValueDefinition(2, QgsDefaultValue("'Def Blabla L1'")) layer1.setDefaultValueDefinition(3, QgsDefaultValue("'Def Blabla L1'")) layer1.setDefaultValueDefinition(4, QgsDefaultValue("'Def Blabla L1'")) - layer1.setFieldDuplicatePolicy(2, Qgis.FieldDomainDuplicatePolicy.Duplicate) - layer1.setFieldDuplicatePolicy(3, Qgis.FieldDomainDuplicatePolicy.DefaultValue) - layer1.setFieldDuplicatePolicy(4, Qgis.FieldDomainDuplicatePolicy.UnsetField) + layer1.setFieldDuplicatePolicy(2, Qgis.FieldDuplicatePolicy.Duplicate) + layer1.setFieldDuplicatePolicy(3, Qgis.FieldDuplicatePolicy.DefaultValue) + layer1.setFieldDuplicatePolicy(4, Qgis.FieldDuplicatePolicy.UnsetField) # > check first layer (parent) self.assertTrue(layer1.isValid()) # - add second layer (child) @@ -508,9 +508,9 @@ def testDuplicateFeature(self): layer2.setDefaultValueDefinition(3, QgsDefaultValue("'Def Blabla L2'")) layer2.setDefaultValueDefinition(4, QgsDefaultValue("'Def Blabla L2'")) layer2.setDefaultValueDefinition(5, QgsDefaultValue("'Def Blabla L2'")) - layer2.setFieldDuplicatePolicy(3, Qgis.FieldDomainDuplicatePolicy.Duplicate) - layer2.setFieldDuplicatePolicy(4, Qgis.FieldDomainDuplicatePolicy.DefaultValue) - layer2.setFieldDuplicatePolicy(5, Qgis.FieldDomainDuplicatePolicy.UnsetField) + layer2.setFieldDuplicatePolicy(3, Qgis.FieldDuplicatePolicy.Duplicate) + layer2.setFieldDuplicatePolicy(4, Qgis.FieldDuplicatePolicy.DefaultValue) + layer2.setFieldDuplicatePolicy(5, Qgis.FieldDuplicatePolicy.UnsetField) # > check second layer (child) self.assertTrue(layer2.isValid()) # - add third layer (child) @@ -522,9 +522,9 @@ def testDuplicateFeature(self): layer3.setDefaultValueDefinition(3, QgsDefaultValue("'Def Blabla L3'")) layer3.setDefaultValueDefinition(4, QgsDefaultValue("'Def Blabla L3'")) layer3.setDefaultValueDefinition(5, QgsDefaultValue("'Def Blabla L3'")) - layer3.setFieldDuplicatePolicy(3, Qgis.FieldDomainDuplicatePolicy.Duplicate) - layer3.setFieldDuplicatePolicy(4, Qgis.FieldDomainDuplicatePolicy.DefaultValue) - layer3.setFieldDuplicatePolicy(5, Qgis.FieldDomainDuplicatePolicy.UnsetField) + layer3.setFieldDuplicatePolicy(3, Qgis.FieldDuplicatePolicy.Duplicate) + layer3.setFieldDuplicatePolicy(4, Qgis.FieldDuplicatePolicy.DefaultValue) + layer3.setFieldDuplicatePolicy(5, Qgis.FieldDuplicatePolicy.UnsetField) # > check third layer (child) self.assertTrue(layer3.isValid()) # - add layers