From ec20a52805dcbffef652b7658e7dbbdb7bcf0041 Mon Sep 17 00:00:00 2001 From: David Signer Date: Tue, 6 Aug 2019 16:45:10 +0200 Subject: [PATCH 1/9] Update widget content when field contains default value that referencing to the currently changed widgets field. On init the dependencies are stored into mDefaultValueDependencies. On attribute change the default values are written into the other widgets according to the dependency map. To avoid recursions the widgets fields index is stored into mAlreadyUpdatedFields. --- src/gui/qgsattributeform.cpp | 92 ++++++++++++++++++++++++++++++++++++ src/gui/qgsattributeform.h | 12 +++++ 2 files changed, 104 insertions(+) diff --git a/src/gui/qgsattributeform.cpp b/src/gui/qgsattributeform.cpp index da425fe980be..de340cafe044 100644 --- a/src/gui/qgsattributeform.cpp +++ b/src/gui/qgsattributeform.cpp @@ -41,6 +41,7 @@ #include "qgshtmlwidgetwrapper.h" #include "qgsapplication.h" #include "qgsexpressioncontextutils.h" +#include "qgsfeaturerequest.h" #include #include @@ -418,6 +419,66 @@ bool QgsAttributeForm::saveEdits() return success; } +bool QgsAttributeForm::updateDefaultValues( const int originIdx ) +{ + if ( !mDefaultValueDependencies.contains( originIdx ) ) + return false; + + // create updated Feature + QgsFeature updatedFeature = QgsFeature( mFeature ); + if ( mFeature.isValid() || mMode == QgsAttributeEditorContext::AddFeatureMode ) + { + QgsAttributes dst = mFeature.attributes(); + for ( QgsWidgetWrapper *ww : qgis::as_const( mWidgets ) ) + { + QgsEditorWidgetWrapper *eww = qobject_cast( ww ); + if ( eww ) + { + QVariant dstVar = dst.at( eww->fieldIdx() ); + QVariant srcVar = eww->value(); + + // need to check dstVar.isNull() != srcVar.isNull() + // otherwise if dstVar=NULL and scrVar=0, then dstVar = srcVar + // be careful- sometimes two null qvariants will be reported as not equal!! (e.g., different types) + bool changed = ( dstVar != srcVar && !dstVar.isNull() && !srcVar.isNull() ) + || ( dstVar.isNull() != srcVar.isNull() ); + if ( changed && srcVar.isValid() && fieldIsEditable( eww->fieldIdx() ) ) + { + dst[eww->fieldIdx()] = srcVar; + } + } + } + updatedFeature.setAttributes( dst ); + + // go through depending fields and update the fields with defaultexpression + QList relevantWidgets = mDefaultValueDependencies.values( originIdx ); + for ( QgsWidgetWrapper *ww : qgis::as_const( relevantWidgets ) ) + { + QgsEditorWidgetWrapper *eww = qobject_cast( ww ); + if ( eww ) + { + //do not update when when mMode is not AddFeatureMode and it's not applyOnUpdate + if ( mMode != QgsAttributeEditorContext::AddFeatureMode && !eww->field().defaultValueDefinition().applyOnUpdate() ) + { + continue; + } + + //do not update when this widget is already updating (avoid recursions) + if ( mAlreadyUpdatedFields.contains( eww->fieldIdx() ) ) + { + qDebug() << "we don't update field [" << eww->fieldIdx() << "] " << eww->field().name() << " because it's already 'updating'"; + continue; + } + + qDebug() << "update field [" << eww->fieldIdx() << "] " << eww->field().name() << " with field of id " << originIdx << " because " << eww->layer()->fields().at( originIdx ).name() << " is in " << eww->field().defaultValueDefinition().expression(); + QString value = mLayer->defaultValue( eww->fieldIdx(), updatedFeature ).toString(); + eww->setValue( value ); + } + } + } + return true; +} + void QgsAttributeForm::resetMultiEdit( bool promptToSave ) { if ( promptToSave ) @@ -772,6 +833,11 @@ void QgsAttributeForm::onAttributeChanged( const QVariant &value ) updateConstraints( eww ); + //append field index here, so it's not updated recursive + mAlreadyUpdatedFields.append( eww->fieldIdx() ); + updateDefaultValues( eww->fieldIdx() ); + mAlreadyUpdatedFields.removeAll( eww->fieldIdx() ); + if ( !signalEmitted ) { Q_NOWARN_DEPRECATED_PUSH @@ -1417,6 +1483,32 @@ void QgsAttributeForm::init() } } + //create defaultValueDependencies + for ( QgsWidgetWrapper *ww : qgis::as_const( mWidgets ) ) + { + QgsEditorWidgetWrapper *eww = qobject_cast( ww ); + if ( eww ) + { + QgsExpression exp( eww->field().defaultValueDefinition().expression() ); + for ( const QString &referencedColumn : exp.referencedColumns().toList() ) + { + if ( referencedColumn == QgsFeatureRequest::ALL_ATTRIBUTES ) + { + const QList allAttributeIds( mLayer->fields().allAttributesList() ); + + for ( const int id : allAttributeIds ) + { + mDefaultValueDependencies.insertMulti( id, eww ); + } + } + else + { + mDefaultValueDependencies.insertMulti( mLayer->fields().lookupField( referencedColumn ), eww ); + } + } + } + } + if ( !mButtonBox ) { mButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel ); diff --git a/src/gui/qgsattributeform.h b/src/gui/qgsattributeform.h index e36126f648b1..9e42a8443807 100644 --- a/src/gui/qgsattributeform.h +++ b/src/gui/qgsattributeform.h @@ -352,6 +352,12 @@ class GUI_EXPORT QgsAttributeForm : public QWidget //! Save single feature or add feature edits bool saveEdits(); + //! fill up dependency map for default values + void createDefaultValueDependencies(); + + //! update the default values in the fields after a referenced field changed + bool updateDefaultValues( const int originIdx ); + int messageTimeout(); void clearMultiEditMessages(); void pushSelectedFeaturesMessage(); @@ -444,6 +450,12 @@ class GUI_EXPORT QgsAttributeForm : public QWidget QMap mIconMap; + //! dependency map for default values + QMap mDefaultValueDependencies; + + //! list of updated fields to avoid recursion on the setting of defaultValues + QList mAlreadyUpdatedFields; + friend class TestQgsDualView; friend class TestQgsAttributeForm; }; From a1bb8062dfbba74c7b19c8a9c05e9aeb2ee36f69 Mon Sep 17 00:00:00 2001 From: David Signer Date: Thu, 8 Aug 2019 17:20:34 +0200 Subject: [PATCH 2/9] updating default values --- tests/src/gui/testqgsattributeform.cpp | 102 +++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/tests/src/gui/testqgsattributeform.cpp b/tests/src/gui/testqgsattributeform.cpp index fce0a044ada7..16c0dd95eda3 100644 --- a/tests/src/gui/testqgsattributeform.cpp +++ b/tests/src/gui/testqgsattributeform.cpp @@ -50,6 +50,7 @@ class TestQgsAttributeForm : public QObject void testEditableJoin(); void testUpsertOnEdit(); void testAttributeFormInterface(); + void testDefaultValueUpdate(); private: QLabel *constraintsLabel( QgsAttributeForm *form, QgsEditorWidgetWrapper *ww ) @@ -906,6 +907,107 @@ void TestQgsAttributeForm::testAttributeFormInterface() } +void TestQgsAttributeForm::testDefaultValueUpdate() +{ + // make a temporary layer to check through + QString def = QStringLiteral( "Point?field=col0:integer&field=col1:integer&field=col2:integer&field=col3:integer" ); + QgsVectorLayer *layer = new QgsVectorLayer( def, QStringLiteral( "test" ), QStringLiteral( "memory" ) ); + + //set defaultValueDefinitions + //col0 - no default value + //col1 - "col0"+1 + //col2 - "col0"+"col1" + //col3 - "col2" + + // set constraints for each field + layer->setDefaultValueDefinition( 1, QgsDefaultValue( QStringLiteral( "\"col0\"+1" ) ) ); + layer->setDefaultValueDefinition( 2, QgsDefaultValue( QStringLiteral( "\"col0\"+\"col1\"" ) ) ); + layer->setDefaultValueDefinition( 3, QgsDefaultValue( QStringLiteral( "\"col2\"" ) ) ); + + // build a form for this feature + QgsFeature ft( layer->dataProvider()->fields(), 1 ); + ft.setAttribute( QStringLiteral( "col0" ), 0 ); + QgsAttributeForm form( layer ); + form.setMode( QgsAttributeEditorContext::AddFeatureMode ); + form.setFeature( ft ); + + // get wrappers for each widget + QgsEditorWidgetWrapper *ww0, *ww1, *ww2, *ww3; + ww0 = qobject_cast( form.mWidgets[0] ); + ww1 = qobject_cast( form.mWidgets[1] ); + ww2 = qobject_cast( form.mWidgets[2] ); + ww3 = qobject_cast( form.mWidgets[3] ); + + //set value in col0: + ww0->setValue( 5 ); + + //we expect + //col0 - 5 + //col1 - 6 + //col2 - 11 + //col3 - 11 + + QCOMPARE( ww0->value().toInt(), 5 ); + QCOMPARE( ww1->value().toInt(), 6 ); + QCOMPARE( ww2->value().toInt(), 11 ); + QCOMPARE( ww3->value().toInt(), 11 ); + + //set value in col1: + ww1->setValue( 10 ); + + //we expect + //col0 - 5 + //col1 - 10 + //col2 - 15 + //col3 - 15 + + QCOMPARE( ww0->value().toInt(), 5 ); + QCOMPARE( ww1->value().toInt(), 10 ); + QCOMPARE( ww2->value().toInt(), 15 ); + QCOMPARE( ww3->value().toInt(), 15 ); + + /* + //let's make a recursion + //col0 - COALESCE( 0, "col3"+1) + //col1 - COALESCE( 0, "col0"+1) + //col2 - COALESCE( 0, "col1"+1) + //col3 - COALESCE( 0, "col2"+1) + + // set constraints for each field + layer->setDefaultValueDefinition( 0, QgsDefaultValue( QStringLiteral("\"col3\"+1") ) ); + layer->setDefaultValueDefinition( 1, QgsDefaultValue( QStringLiteral("\"col0\"+1") ) ); + layer->setDefaultValueDefinition( 2, QgsDefaultValue( QStringLiteral("\"col1\"+1") ) ); + layer->setDefaultValueDefinition( 3, QgsDefaultValue( QStringLiteral("\"col2\"+1") ) ); + + //set value in col0: + ww0->setValue( 20 ); + + //we expect + //col0 - 20 + //col1 - 21 + //col2 - 22 + //col3 - 23 + + QCOMPARE( ww0->value().toInt(), 20 ); + QCOMPARE( ww1->value().toInt(), 21 ); + QCOMPARE( ww2->value().toInt(), 22 ); + QCOMPARE( ww3->value().toInt(), 23 ); + + //set value in col2: + ww2->setValue( 30 ); + + //we expect + //col0 - 32 + //col1 - 33 + //col2 - 30 + //col3 - 31 + + QCOMPARE( ww0->value().toInt(), 32 ); + QCOMPARE( ww1->value().toInt(), 33 ); + QCOMPARE( ww2->value().toInt(), 30 ); + QCOMPARE( ww3->value().toInt(), 31 ); + */ +} QGSTEST_MAIN( TestQgsAttributeForm ) #include "testqgsattributeform.moc" From 1352b7e897fdf631f4324417a46797ba651d3617 Mon Sep 17 00:00:00 2001 From: David Signer Date: Sun, 11 Aug 2019 18:47:30 +0200 Subject: [PATCH 3/9] test for recursion in default values --- tests/src/gui/testqgsattributeform.cpp | 46 ++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/tests/src/gui/testqgsattributeform.cpp b/tests/src/gui/testqgsattributeform.cpp index 16c0dd95eda3..7f30f913e20b 100644 --- a/tests/src/gui/testqgsattributeform.cpp +++ b/tests/src/gui/testqgsattributeform.cpp @@ -51,6 +51,7 @@ class TestQgsAttributeForm : public QObject void testUpsertOnEdit(); void testAttributeFormInterface(); void testDefaultValueUpdate(); + void testDefaultValueUpdateRecursion(); private: QLabel *constraintsLabel( QgsAttributeForm *form, QgsEditorWidgetWrapper *ww ) @@ -965,8 +966,14 @@ void TestQgsAttributeForm::testDefaultValueUpdate() QCOMPARE( ww1->value().toInt(), 10 ); QCOMPARE( ww2->value().toInt(), 15 ); QCOMPARE( ww3->value().toInt(), 15 ); +} + +void TestQgsAttributeForm::testDefaultValueUpdateRecursion() +{ + // make a temporary layer to check through + QString def = QStringLiteral( "Point?field=col0:integer&field=col1:integer&field=col2:integer&field=col3:integer" ); + QgsVectorLayer *layer = new QgsVectorLayer( def, QStringLiteral( "test" ), QStringLiteral( "memory" ) ); - /* //let's make a recursion //col0 - COALESCE( 0, "col3"+1) //col1 - COALESCE( 0, "col0"+1) @@ -974,10 +981,24 @@ void TestQgsAttributeForm::testDefaultValueUpdate() //col3 - COALESCE( 0, "col2"+1) // set constraints for each field - layer->setDefaultValueDefinition( 0, QgsDefaultValue( QStringLiteral("\"col3\"+1") ) ); - layer->setDefaultValueDefinition( 1, QgsDefaultValue( QStringLiteral("\"col0\"+1") ) ); - layer->setDefaultValueDefinition( 2, QgsDefaultValue( QStringLiteral("\"col1\"+1") ) ); - layer->setDefaultValueDefinition( 3, QgsDefaultValue( QStringLiteral("\"col2\"+1") ) ); + layer->setDefaultValueDefinition( 0, QgsDefaultValue( QStringLiteral( "\"col3\"+1" ) ) ); + layer->setDefaultValueDefinition( 1, QgsDefaultValue( QStringLiteral( "\"col0\"+1" ) ) ); + layer->setDefaultValueDefinition( 2, QgsDefaultValue( QStringLiteral( "\"col1\"+1" ) ) ); + layer->setDefaultValueDefinition( 3, QgsDefaultValue( QStringLiteral( "\"col2\"+1" ) ) ); + + // build a form for this feature + QgsFeature ft( layer->dataProvider()->fields(), 1 ); + ft.setAttribute( QStringLiteral( "col0" ), 0 ); + QgsAttributeForm form( layer ); + form.setMode( QgsAttributeEditorContext::AddFeatureMode ); + form.setFeature( ft ); + + // get wrappers for each widget + QgsEditorWidgetWrapper *ww0, *ww1, *ww2, *ww3; + ww0 = qobject_cast( form.mWidgets[0] ); + ww1 = qobject_cast( form.mWidgets[1] ); + ww2 = qobject_cast( form.mWidgets[2] ); + ww3 = qobject_cast( form.mWidgets[3] ); //set value in col0: ww0->setValue( 20 ); @@ -1006,7 +1027,20 @@ void TestQgsAttributeForm::testDefaultValueUpdate() QCOMPARE( ww1->value().toInt(), 33 ); QCOMPARE( ww2->value().toInt(), 30 ); QCOMPARE( ww3->value().toInt(), 31 ); - */ + + //set value in col0 again: + ww0->setValue( 40 ); + + //we expect + //col0 - 40 + //col1 - 41 + //col2 - 42 + //col3 - 43 + + QCOMPARE( ww0->value().toInt(), 40 ); + QCOMPARE( ww1->value().toInt(), 41 ); + QCOMPARE( ww2->value().toInt(), 42 ); + QCOMPARE( ww3->value().toInt(), 43 ); } QGSTEST_MAIN( TestQgsAttributeForm ) From 82ae686ee160282d0e2dea8ebe217467fb5d343a Mon Sep 17 00:00:00 2001 From: David Signer Date: Sun, 11 Aug 2019 19:51:48 +0200 Subject: [PATCH 4/9] beautifications --- src/gui/qgsattributeform.cpp | 3 ++- src/gui/qgsattributeform.h | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gui/qgsattributeform.cpp b/src/gui/qgsattributeform.cpp index de340cafe044..98d3d3cffeab 100644 --- a/src/gui/qgsattributeform.cpp +++ b/src/gui/qgsattributeform.cpp @@ -1490,7 +1490,8 @@ void QgsAttributeForm::init() if ( eww ) { QgsExpression exp( eww->field().defaultValueDefinition().expression() ); - for ( const QString &referencedColumn : exp.referencedColumns().toList() ) + const QSet referencedColumns = exp.referencedColumns(); + for ( const QString &referencedColumn : referencedColumns ) { if ( referencedColumn == QgsFeatureRequest::ALL_ATTRIBUTES ) { diff --git a/src/gui/qgsattributeform.h b/src/gui/qgsattributeform.h index 9e42a8443807..0ee6f4e0de63 100644 --- a/src/gui/qgsattributeform.h +++ b/src/gui/qgsattributeform.h @@ -450,10 +450,13 @@ class GUI_EXPORT QgsAttributeForm : public QWidget QMap mIconMap; - //! dependency map for default values + /** + * Dependency map for default values. Attribute index -> widget wrapper. + * Attribute indexes will be added multiple times if more than one widget depends on them. + */ QMap mDefaultValueDependencies; - //! list of updated fields to avoid recursion on the setting of defaultValues + //! List of updated fields to avoid recursion on the setting of defaultValues QList mAlreadyUpdatedFields; friend class TestQgsDualView; From 9b236a07fe79d18cb5e55827b949e3fa2da1635a Mon Sep 17 00:00:00 2001 From: David Signer Date: Thu, 15 Aug 2019 11:02:37 +0200 Subject: [PATCH 5/9] handles two null values as equal, since they can be handled as not equal by == comparison. --- src/core/qgis.cpp | 2 +- src/core/qgis.h | 3 ++- tests/src/core/testqgis.cpp | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/core/qgis.cpp b/src/core/qgis.cpp index 02b5dbe2c5c3..9815e2afb2a9 100644 --- a/src/core/qgis.cpp +++ b/src/core/qgis.cpp @@ -297,5 +297,5 @@ uint qHash( const QVariant &variant ) bool qgsVariantEqual( const QVariant &lhs, const QVariant &rhs ) { - return lhs.isNull() == rhs.isNull() && lhs == rhs; + return ( lhs.isNull() == rhs.isNull() && lhs == rhs ) || ( lhs.isNull() && rhs.isNull() ); } diff --git a/src/core/qgis.h b/src/core/qgis.h index 4772589b8e74..f8ef5c8030a3 100644 --- a/src/core/qgis.h +++ b/src/core/qgis.h @@ -503,7 +503,8 @@ CORE_EXPORT qlonglong qgsPermissiveToLongLong( QString string, bool &ok ); CORE_EXPORT bool qgsVariantLessThan( const QVariant &lhs, const QVariant &rhs ); /** - * Compares two QVariant values and returns whether they are equal, NULL values are treated as equal. + * Compares two QVariant values and returns whether they are equal, two NULL values are + * always treated as equal and 0 is not treated as equal with NULL * * \param lhs first value * \param rhs second value diff --git a/tests/src/core/testqgis.cpp b/tests/src/core/testqgis.cpp index 992349bbb78b..330c946e1b7f 100644 --- a/tests/src/core/testqgis.cpp +++ b/tests/src/core/testqgis.cpp @@ -393,6 +393,8 @@ void TestQgis::testQgsVariantEqual() // NULL identities QVERIFY( qgsVariantEqual( QVariant( QVariant::Int ), QVariant( QVariant::Int ) ) ); QVERIFY( qgsVariantEqual( QVariant( QVariant::Double ), QVariant( QVariant::Double ) ) ); + QVERIFY( qgsVariantEqual( QVariant( QVariant::Int ), QVariant( QVariant::Double ) ) ); + QVERIFY( qgsVariantEqual( QVariant( QVariant::Int ), QVariant( QVariant::String ) ) ); } void TestQgis::testQgsEnumValueToKey() From 38e4bacb7d85db07da659d0e82f20e04c6989bf6 Mon Sep 17 00:00:00 2001 From: David Signer Date: Thu, 15 Aug 2019 11:03:19 +0200 Subject: [PATCH 6/9] missing sip --- python/core/auto_generated/qgis.sip.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/core/auto_generated/qgis.sip.in b/python/core/auto_generated/qgis.sip.in index 254e8afabb38..d94ac4b8fc26 100644 --- a/python/core/auto_generated/qgis.sip.in +++ b/python/core/auto_generated/qgis.sip.in @@ -194,7 +194,8 @@ Invalid < NULL < Values bool qgsVariantEqual( const QVariant &lhs, const QVariant &rhs ); %Docstring -Compares two QVariant values and returns whether they are equal, NULL values are treated as equal. +Compares two QVariant values and returns whether they are equal, two NULL values are +always treated as equal and 0 is not treated as equal with NULL :param lhs: first value :param rhs: second value From 6bbf5da33b365f3c7105360d53b4abbe5f6c1655 Mon Sep 17 00:00:00 2001 From: David Signer Date: Thu, 15 Aug 2019 11:03:45 +0200 Subject: [PATCH 7/9] using qgsVariantEqual --- src/gui/qgsattributeform.cpp | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/gui/qgsattributeform.cpp b/src/gui/qgsattributeform.cpp index 98d3d3cffeab..9cf81fd7879d 100644 --- a/src/gui/qgsattributeform.cpp +++ b/src/gui/qgsattributeform.cpp @@ -319,12 +319,7 @@ bool QgsAttributeForm::saveEdits() QVariant dstVar = dst.at( eww->fieldIdx() ); QVariant srcVar = eww->value(); - // need to check dstVar.isNull() != srcVar.isNull() - // otherwise if dstVar=NULL and scrVar=0, then dstVar = srcVar - // be careful- sometimes two null qvariants will be reported as not equal!! (e.g., different types) - bool changed = ( dstVar != srcVar && !dstVar.isNull() && !srcVar.isNull() ) - || ( dstVar.isNull() != srcVar.isNull() ); - if ( changed && srcVar.isValid() && fieldIsEditable( eww->fieldIdx() ) ) + if ( !qgsVariantEqual( dstVar, srcVar ) && srcVar.isValid() && fieldIsEditable( eww->fieldIdx() ) ) { dst[eww->fieldIdx()] = srcVar; @@ -437,12 +432,7 @@ bool QgsAttributeForm::updateDefaultValues( const int originIdx ) QVariant dstVar = dst.at( eww->fieldIdx() ); QVariant srcVar = eww->value(); - // need to check dstVar.isNull() != srcVar.isNull() - // otherwise if dstVar=NULL and scrVar=0, then dstVar = srcVar - // be careful- sometimes two null qvariants will be reported as not equal!! (e.g., different types) - bool changed = ( dstVar != srcVar && !dstVar.isNull() && !srcVar.isNull() ) - || ( dstVar.isNull() != srcVar.isNull() ); - if ( changed && srcVar.isValid() && fieldIsEditable( eww->fieldIdx() ) ) + if ( !qgsVariantEqual( dstVar, srcVar ) && srcVar.isValid() && fieldIsEditable( eww->fieldIdx() ) ) { dst[eww->fieldIdx()] = srcVar; } @@ -465,12 +455,8 @@ bool QgsAttributeForm::updateDefaultValues( const int originIdx ) //do not update when this widget is already updating (avoid recursions) if ( mAlreadyUpdatedFields.contains( eww->fieldIdx() ) ) - { - qDebug() << "we don't update field [" << eww->fieldIdx() << "] " << eww->field().name() << " because it's already 'updating'"; continue; - } - qDebug() << "update field [" << eww->fieldIdx() << "] " << eww->field().name() << " with field of id " << originIdx << " because " << eww->layer()->fields().at( originIdx ).name() << " is in " << eww->field().defaultValueDefinition().expression(); QString value = mLayer->defaultValue( eww->fieldIdx(), updatedFeature ).toString(); eww->setValue( value ); } From f2073bd3b11c3cc82165e742b6f45543aeb6ba91 Mon Sep 17 00:00:00 2001 From: David Signer Date: Thu, 15 Aug 2019 22:22:11 +0200 Subject: [PATCH 8/9] do only return true if both values are null and none of them is invalid --- src/core/qgis.cpp | 3 ++- tests/src/core/testqgis.cpp | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/qgis.cpp b/src/core/qgis.cpp index 9815e2afb2a9..6ceda13042dc 100644 --- a/src/core/qgis.cpp +++ b/src/core/qgis.cpp @@ -28,6 +28,7 @@ #include "qgsconfig.h" #include "qgslogger.h" #include "qgswkbtypes.h" +#include #include #include @@ -297,5 +298,5 @@ uint qHash( const QVariant &variant ) bool qgsVariantEqual( const QVariant &lhs, const QVariant &rhs ) { - return ( lhs.isNull() == rhs.isNull() && lhs == rhs ) || ( lhs.isNull() && rhs.isNull() ); + return ( lhs.isNull() == rhs.isNull() && lhs == rhs ) || ( lhs.isNull() && rhs.isNull() && lhs.isValid() && rhs.isValid() ); } diff --git a/tests/src/core/testqgis.cpp b/tests/src/core/testqgis.cpp index 330c946e1b7f..2c0fe9f7a379 100644 --- a/tests/src/core/testqgis.cpp +++ b/tests/src/core/testqgis.cpp @@ -395,6 +395,9 @@ void TestQgis::testQgsVariantEqual() QVERIFY( qgsVariantEqual( QVariant( QVariant::Double ), QVariant( QVariant::Double ) ) ); QVERIFY( qgsVariantEqual( QVariant( QVariant::Int ), QVariant( QVariant::Double ) ) ); QVERIFY( qgsVariantEqual( QVariant( QVariant::Int ), QVariant( QVariant::String ) ) ); + + // NULL should not be equal to invalid + QVERIFY( !qgsVariantEqual( QVariant(), QVariant( QVariant::Int ) ) ); } void TestQgis::testQgsEnumValueToKey() From 556551be32f95b1962291b0ee5b192fbd68f245d Mon Sep 17 00:00:00 2001 From: signedav Date: Fri, 16 Aug 2019 12:32:14 +0200 Subject: [PATCH 9/9] Update src/core/qgis.cpp Co-Authored-By: Matthias Kuhn --- src/core/qgis.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/qgis.cpp b/src/core/qgis.cpp index 6ceda13042dc..7e528e439d38 100644 --- a/src/core/qgis.cpp +++ b/src/core/qgis.cpp @@ -28,7 +28,6 @@ #include "qgsconfig.h" #include "qgslogger.h" #include "qgswkbtypes.h" -#include #include #include