From dc1583bd7c8ba98ce338beb197ae84598d42a9a5 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 24 Sep 2024 21:12:43 +0200 Subject: [PATCH] QgsJsonUtils: add a way to disable use of field formatters Fixes #58861 --- .../core/auto_generated/qgsjsonutils.sip.in | 18 ++++++++++ .../core/auto_generated/qgsjsonutils.sip.in | 18 ++++++++++ src/core/qgsjsonutils.cpp | 8 ++--- src/core/qgsjsonutils.h | 21 +++++++++++- tests/src/python/test_qgsjsonutils.py | 33 ++++++++++++++++++- 5 files changed, 92 insertions(+), 6 deletions(-) diff --git a/python/PyQt6/core/auto_generated/qgsjsonutils.sip.in b/python/PyQt6/core/auto_generated/qgsjsonutils.sip.in index 427105b74e59..4e459e5b45e0 100644 --- a/python/PyQt6/core/auto_generated/qgsjsonutils.sip.in +++ b/python/PyQt6/core/auto_generated/qgsjsonutils.sip.in @@ -220,6 +220,24 @@ take precedence over attributes included via :py:func:`~QgsJsonExporter.attribut .. seealso:: :py:func:`setExcludedAttributes` .. seealso:: :py:func:`attributes` +%End + + void setUseFieldFormatters( bool useFieldFormatters ); +%Docstring +Sets whether field formatters (of type KeyValue, List, ValueRelation, +ValueMap) are used to export raw values as displayed +values. The default is true. + +.. versionadded:: 3.40 +%End + + bool useFieldFormatters() const; +%Docstring +Returned whether field formatters (of type KeyValue, List, ValueRelation, +ValueMap) are used to export raw values as displayed +values. + +.. versionadded:: 3.40 %End QString exportFeature( const QgsFeature &feature, diff --git a/python/core/auto_generated/qgsjsonutils.sip.in b/python/core/auto_generated/qgsjsonutils.sip.in index 3d167e6de110..1a7c5c77ca6f 100644 --- a/python/core/auto_generated/qgsjsonutils.sip.in +++ b/python/core/auto_generated/qgsjsonutils.sip.in @@ -220,6 +220,24 @@ take precedence over attributes included via :py:func:`~QgsJsonExporter.attribut .. seealso:: :py:func:`setExcludedAttributes` .. seealso:: :py:func:`attributes` +%End + + void setUseFieldFormatters( bool useFieldFormatters ); +%Docstring +Sets whether field formatters (of type KeyValue, List, ValueRelation, +ValueMap) are used to export raw values as displayed +values. The default is true. + +.. versionadded:: 3.40 +%End + + bool useFieldFormatters() const; +%Docstring +Returned whether field formatters (of type KeyValue, List, ValueRelation, +ValueMap) are used to export raw values as displayed +values. + +.. versionadded:: 3.40 %End QString exportFeature( const QgsFeature &feature, diff --git a/src/core/qgsjsonutils.cpp b/src/core/qgsjsonutils.cpp index 8bd89997d0c8..674c68d7613f 100644 --- a/src/core/qgsjsonutils.cpp +++ b/src/core/qgsjsonutils.cpp @@ -170,7 +170,7 @@ json QgsJsonExporter::exportFeatureToJsonObject( const QgsFeature &feature, cons QVariant val = feature.attributes().at( i ); - if ( mLayer ) + if ( mUseFieldFormatters && mLayer ) { const QgsEditorWidgetSetup setup = fields.at( i ).editorWidgetSetup(); const QgsFieldFormatter *fieldFormatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() ); @@ -222,7 +222,7 @@ json QgsJsonExporter::exportFeatureToJsonObject( const QgsFeature &feature, cons QgsFeature relatedFet; while ( it.nextFeature( relatedFet ) ) { - relatedFeatureAttributes += QgsJsonUtils::exportAttributesToJsonObject( relatedFet, childLayer, attributeWidgetCaches ); + relatedFeatureAttributes += QgsJsonUtils::exportAttributesToJsonObject( relatedFet, childLayer, attributeWidgetCaches, mUseFieldFormatters ); } } properties[ relation.name().toStdString() ] = relatedFeatureAttributes; @@ -901,7 +901,7 @@ QVariant QgsJsonUtils::parseJson( const QString &jsonString ) return parseJson( jsonString.toStdString() ); } -json QgsJsonUtils::exportAttributesToJsonObject( const QgsFeature &feature, QgsVectorLayer *layer, const QVector &attributeWidgetCaches ) +json QgsJsonUtils::exportAttributesToJsonObject( const QgsFeature &feature, QgsVectorLayer *layer, const QVector &attributeWidgetCaches, bool useFieldFormatters ) { QgsFields fields = feature.fields(); json attrs; @@ -909,7 +909,7 @@ json QgsJsonUtils::exportAttributesToJsonObject( const QgsFeature &feature, QgsV { QVariant val = feature.attributes().at( i ); - if ( layer ) + if ( layer && useFieldFormatters ) { QgsEditorWidgetSetup setup = layer->fields().at( i ).editorWidgetSetup(); QgsFieldFormatter *fieldFormatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() ); diff --git a/src/core/qgsjsonutils.h b/src/core/qgsjsonutils.h index b7278740a756..12064c6399e2 100644 --- a/src/core/qgsjsonutils.h +++ b/src/core/qgsjsonutils.h @@ -197,6 +197,22 @@ class CORE_EXPORT QgsJsonExporter */ QgsAttributeList excludedAttributes() const { return mExcludedAttributeIndexes; } + /** + * Sets whether field formatters (of type KeyValue, List, ValueRelation, + * ValueMap) are used to export raw values as displayed + * values. The default is true. + * \since QGIS 3.40 + */ + void setUseFieldFormatters( bool useFieldFormatters ) { mUseFieldFormatters = useFieldFormatters; } + + /** + * Returned whether field formatters (of type KeyValue, List, ValueRelation, + * ValueMap) are used to export raw values as displayed + * values. + * \since QGIS 3.40 + */ + bool useFieldFormatters() const { return mUseFieldFormatters; } + /** * Returns a GeoJSON string representation of a feature. * \param feature feature to convert @@ -291,6 +307,8 @@ class CORE_EXPORT QgsJsonExporter bool mTransformGeometries = true; QgsCoordinateReferenceSystem mDestinationCrs; + + bool mUseFieldFormatters = true; }; /** @@ -350,11 +368,12 @@ class CORE_EXPORT QgsJsonUtils * richer export utilising settings like the layer's fields widget configuration. * \param attributeWidgetCaches optional widget configuration cache. Can be used * to speed up exporting the attributes for multiple features from the same layer. + * \param useFieldFormatters Whether field formatters should be used (since QGIS 3.40) * \note Not available in Python bindings * \since QGIS 3.8 */ static json exportAttributesToJsonObject( const QgsFeature &feature, QgsVectorLayer *layer = nullptr, - const QVector &attributeWidgetCaches = QVector() ) SIP_SKIP; + const QVector &attributeWidgetCaches = QVector(), bool useFieldFormatters = true ) SIP_SKIP; /** * Parse a simple array (depth=1) diff --git a/tests/src/python/test_qgsjsonutils.py b/tests/src/python/test_qgsjsonutils.py index 30915b0c3a6b..2ef5b4555bb6 100644 --- a/tests/src/python/test_qgsjsonutils.py +++ b/tests/src/python/test_qgsjsonutils.py @@ -726,11 +726,12 @@ def testExportFeatureRelations(self): # with field formatter setup = QgsEditorWidgetSetup('ValueMap', {"map": {"apples": 123, "bananas": 124}}) child.setEditorWidgetSetup(1, setup) + parent.setEditorWidgetSetup(1, QgsEditorWidgetSetup('ValueMap', {"map": {"sixty-seven": 67}})) expected = """{ "geometry": null, "id": 432, "properties": { - "fldint": 67, + "fldint": "sixty-seven", "fldtxt": "test1", "foreignkey": 123, "relation one": [ @@ -750,6 +751,36 @@ def testExportFeatureRelations(self): }""" self.assertEqual(exporter.exportFeature(pf1, indent=2), expected) + # Use raw values + self.assertTrue(exporter.useFieldFormatters()) + exporter.setUseFieldFormatters(False) + self.assertFalse(exporter.useFieldFormatters()) + expected = """{ + "geometry": null, + "id": 432, + "properties": { + "fldint": 67, + "fldtxt": "test1", + "foreignkey": 123, + "relation one": [ + { + "x": "foo", + "y": 123, + "z": 321 + }, + { + "x": "bar", + "y": 123, + "z": 654 + } + ] + }, + "type": "Feature" +}""" + self.assertEqual(exporter.exportFeature(pf1, indent=2), expected) + exporter.setUseFieldFormatters(True) + parent.setEditorWidgetSetup(1, QgsEditorWidgetSetup()) + # test excluding related attributes exporter.setIncludeRelated(False) self.assertEqual(exporter.includeRelated(), False)