diff --git a/python/core/auto_generated/fieldformatter/qgscheckboxfieldformatter.sip.in b/python/core/auto_generated/fieldformatter/qgscheckboxfieldformatter.sip.in new file mode 100644 index 00000000000..f549d2f8547 --- /dev/null +++ b/python/core/auto_generated/fieldformatter/qgscheckboxfieldformatter.sip.in @@ -0,0 +1,43 @@ +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/fieldformatter/qgscheckboxfieldformatter.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.pl again * + ************************************************************************/ + + + +class QgsCheckBoxFieldFormatter : QgsFieldFormatter +{ +%Docstring +Field formatter for a checkbox field. + +.. versionadded:: 3.10 +%End + +%TypeHeaderCode +#include "qgscheckboxfieldformatter.h" +%End + public: + + QgsCheckBoxFieldFormatter(); +%Docstring +Constructor for QgsCheckBoxFieldFormatter. +%End + + virtual QString id() const; + + + virtual QString representValue( QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value ) const; + +}; + + +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/fieldformatter/qgscheckboxfieldformatter.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.pl again * + ************************************************************************/ diff --git a/python/core/auto_generated/qgsfieldformatter.sip.in b/python/core/auto_generated/qgsfieldformatter.sip.in index a3ac2eed27e..f15911ad268 100644 --- a/python/core/auto_generated/qgsfieldformatter.sip.in +++ b/python/core/auto_generated/qgsfieldformatter.sip.in @@ -29,7 +29,11 @@ This is an abstract base class and will always need to be subclassed. #include "qgsfieldformatter.h" %End public: + QgsFieldFormatter(); +%Docstring +Default constructor +%End virtual ~QgsFieldFormatter(); diff --git a/python/core/core_auto.sip b/python/core/core_auto.sip index c105a432fb2..031ef17b652 100644 --- a/python/core/core_auto.sip +++ b/python/core/core_auto.sip @@ -321,6 +321,7 @@ %Include auto_generated/geometry/qgswkbptr.sip %Include auto_generated/./3d/qgs3drendererregistry.sip %Include auto_generated/./3d/qgsabstract3drenderer.sip +%Include auto_generated/fieldformatter/qgscheckboxfieldformatter.sip %Include auto_generated/fieldformatter/qgsrangefieldformatter.sip %Include auto_generated/fieldformatter/qgsdatetimefieldformatter.sip %Include auto_generated/fieldformatter/qgsfallbackfieldformatter.sip diff --git a/scripts/astyle.options b/scripts/astyle.options index 2552a8a06dc..02c64a1dece 100644 --- a/scripts/astyle.options +++ b/scripts/astyle.options @@ -7,7 +7,7 @@ --indent-labels --indent-namespaces --indent-switches ---max-instatement-indent=40 +--max-instatement-indent=80 --min-conditional-indent=-1 --suffix=none --break-after-logical diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 0ce641ffe71..751c86c2f75 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -569,6 +569,7 @@ SET(QGIS_CORE_SRCS 3d/qgs3drendererregistry.cpp 3d/qgsabstract3drenderer.cpp + fieldformatter/qgscheckboxfieldformatter.cpp fieldformatter/qgsrangefieldformatter.cpp fieldformatter/qgsdatetimefieldformatter.cpp fieldformatter/qgsfallbackfieldformatter.cpp @@ -1290,6 +1291,7 @@ SET(QGIS_CORE_HDRS 3d/qgs3drendererregistry.h 3d/qgsabstract3drenderer.h + fieldformatter/qgscheckboxfieldformatter.h fieldformatter/qgsrangefieldformatter.h fieldformatter/qgsdatetimefieldformatter.h fieldformatter/qgsfallbackfieldformatter.h diff --git a/src/core/fieldformatter/qgscheckboxfieldformatter.cpp b/src/core/fieldformatter/qgscheckboxfieldformatter.cpp new file mode 100644 index 00000000000..9179212c50a --- /dev/null +++ b/src/core/fieldformatter/qgscheckboxfieldformatter.cpp @@ -0,0 +1,89 @@ +/*************************************************************************** + qgscheckboxfieldformatter.cpp - QgsCheckBoxFieldFormatter + + --------------------- + begin : 23.09.2019 + copyright : (C) 2019 by Denis Rouzaud + email : denis@opengis.ch + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include + +#include "qgscheckboxfieldformatter.h" +#include "qgsvectorlayer.h" +#include "qgsapplication.h" + + +QString QgsCheckBoxFieldFormatter::id() const +{ + return QStringLiteral( "CheckBox" ); +} + +QString QgsCheckBoxFieldFormatter::representValue( QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value ) const +{ + Q_UNUSED( cache ) + + /* + This follows this logic: + + if field type is bool: + NULL => nullRepresentation + true => tr("true") + false => tr("false") + else + if cannot convert to string (like json integer list) => (invalid) + if == checkedstate => tr("true") + if == uncheckedstate => tr("false") + else (value.toString) + */ + + bool isNull = value.isNull(); + bool boolValue = false; + QString textValue = QgsApplication::nullRepresentation(); + + const QVariant::Type fieldType = layer->fields().at( fieldIndex ).type(); + if ( fieldType == QVariant::Bool ) + { + boolValue = value.toBool(); + } + else + { + if ( !value.canConvert() ) + { + isNull = true; + textValue = QObject::tr( "(invalid)" ); + } + else + { + if ( config.contains( QStringLiteral( "CheckedState" ) ) && value.toString() == config[ QStringLiteral( "CheckedState" ) ].toString() ) + { + boolValue = true; + } + else if ( config.contains( QStringLiteral( "UncheckedState" ) ) && value.toString() == config[ QStringLiteral( "UncheckedState" ) ].toString() ) + { + boolValue = false; + } + else + { + isNull = true; + textValue = QStringLiteral( "(%1)" ).arg( value.toString() ); + } + } + } + + if ( isNull ) + { + return textValue; + } + if ( boolValue ) + return QObject::tr( "true" ); + else + return QObject::tr( "false" ); +} diff --git a/src/core/fieldformatter/qgscheckboxfieldformatter.h b/src/core/fieldformatter/qgscheckboxfieldformatter.h new file mode 100644 index 00000000000..38c4b4cee96 --- /dev/null +++ b/src/core/fieldformatter/qgscheckboxfieldformatter.h @@ -0,0 +1,44 @@ +/*************************************************************************** + qgscheckboxfieldformatter.h - QgsCheckBoxFieldFormatter + + --------------------- + begin : 23.09.2019 + copyright : (C) 2019 by Denis Rouzaud + email : denis@opengis.ch + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifndef QGSCHECKBOXFIELDFORMATTER_H +#define QGSCHECKBOXFIELDFORMATTER_H + +#include "qgis_core.h" +#include "qgsfieldformatter.h" + + +/** + * \ingroup core + * Field formatter for a checkbox field. + * + * \since QGIS 3.10 + */ +class CORE_EXPORT QgsCheckBoxFieldFormatter : public QgsFieldFormatter +{ + public: + + /** + * Constructor for QgsCheckBoxFieldFormatter. + */ + QgsCheckBoxFieldFormatter() = default; + + QString id() const override; + + QString representValue( QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value ) const override; +}; + + +#endif // QGSCHECKBOXFIELDFORMATTER_H diff --git a/src/core/qgsfieldformatter.cpp b/src/core/qgsfieldformatter.cpp index 4acbb2fbc05..383656f6216 100644 --- a/src/core/qgsfieldformatter.cpp +++ b/src/core/qgsfieldformatter.cpp @@ -20,9 +20,6 @@ #include "qgsvectorlayer.h" #include "qgsvectordataprovider.h" -QgsFieldFormatter::QgsFieldFormatter() //NOLINT -{ -} QString QgsFieldFormatter::representValue( QgsVectorLayer *layer, int fieldIndex, const QVariantMap &config, const QVariant &cache, const QVariant &value ) const { diff --git a/src/core/qgsfieldformatter.h b/src/core/qgsfieldformatter.h index a8386502622..b37185cb5b2 100644 --- a/src/core/qgsfieldformatter.h +++ b/src/core/qgsfieldformatter.h @@ -40,7 +40,11 @@ class QgsVectorLayer; class CORE_EXPORT QgsFieldFormatter { public: - QgsFieldFormatter(); + + /** + * Default constructor + */ + QgsFieldFormatter() = default; virtual ~QgsFieldFormatter() = default; diff --git a/src/core/qgsfieldformatterregistry.cpp b/src/core/qgsfieldformatterregistry.cpp index 97956835616..0c595752f35 100644 --- a/src/core/qgsfieldformatterregistry.cpp +++ b/src/core/qgsfieldformatterregistry.cpp @@ -23,6 +23,7 @@ #include "qgskeyvaluefieldformatter.h" #include "qgslistfieldformatter.h" #include "qgsrangefieldformatter.h" +#include "qgscheckboxfieldformatter.h" #include "qgsfallbackfieldformatter.h" @@ -36,6 +37,7 @@ QgsFieldFormatterRegistry::QgsFieldFormatterRegistry( QObject *parent ) addFieldFormatter( new QgsListFieldFormatter() ); addFieldFormatter( new QgsDateTimeFieldFormatter() ); addFieldFormatter( new QgsRangeFieldFormatter() ); + addFieldFormatter( new QgsCheckBoxFieldFormatter() ); mFallbackFieldFormatter = new QgsFallbackFieldFormatter(); } diff --git a/src/gui/attributetable/qgsattributetablemodel.cpp b/src/gui/attributetable/qgsattributetablemodel.cpp index 08381d788c2..0b30c970f82 100644 --- a/src/gui/attributetable/qgsattributetablemodel.cpp +++ b/src/gui/attributetable/qgsattributetablemodel.cpp @@ -689,8 +689,11 @@ QVariant QgsAttributeTableModel::data( const QModelIndex &index, int role ) cons { case Qt::DisplayRole: case Qt::ToolTipRole: - return mFieldFormatters.at( index.column() )->representValue( layer(), fieldId, mWidgetConfigs.at( index.column() ), - mAttributeWidgetCaches.at( index.column() ), val ); + return mFieldFormatters.at( index.column() )->representValue( layer(), + fieldId, + mWidgetConfigs.at( index.column() ), + mAttributeWidgetCaches.at( index.column() ), + val ); case Qt::EditRole: return val; diff --git a/tests/src/python/test_qgsfieldformatters.py b/tests/src/python/test_qgsfieldformatters.py index 9b2e31668d8..c28fabbb2d8 100644 --- a/tests/src/python/test_qgsfieldformatters.py +++ b/tests/src/python/test_qgsfieldformatters.py @@ -15,7 +15,7 @@ import qgis # NOQA from qgis.core import (QgsFeature, QgsProject, QgsRelation, QgsVectorLayer, QgsValueMapFieldFormatter, QgsValueRelationFieldFormatter, QgsRelationReferenceFieldFormatter, QgsRangeFieldFormatter, - QgsSettings, QgsGeometry, QgsPointXY) + QgsCheckBoxFieldFormatter, QgsSettings, QgsGeometry, QgsPointXY) from qgis.PyQt.QtCore import QCoreApplication, QLocale from qgis.testing import start_app, unittest @@ -357,5 +357,39 @@ class TestQgsRangeFieldFormatter(unittest.TestCase): QgsProject.instance().removeAllMapLayers() +class TestQgsCheckBoxFieldFormatter(unittest.TestCase): + + @classmethod + def setUpClass(cls): + """Run before all tests""" + QCoreApplication.setOrganizationName("QGIS_Test") + QCoreApplication.setOrganizationDomain("QGIS_TestPyQgsCheckBoxFieldFormatter.com") + QCoreApplication.setApplicationName("QGIS_TestPyQgsCheckBoxFieldFormatter") + QgsSettings().clear() + start_app() + + def test_representValue(self): + null_value = "NULL" + QgsSettings().setValue("qgis/nullValue", null_value) + layer = QgsVectorLayer("point?field=int:integer&field=str:string", "layer", "memory") + self.assertTrue(layer.isValid()) + + field_formatter = QgsCheckBoxFieldFormatter() + + # test with integer + # normal case + self.assertEqual(field_formatter.representValue(layer, 0, {'UncheckedState': 0, 'CheckedState': 1}, None, 1), 'true') + self.assertEqual(field_formatter.representValue(layer, 0, {'UncheckedState': 0, 'CheckedState': 1}, None, 0), 'false') + self.assertEqual(field_formatter.representValue(layer, 0, {'UncheckedState': 0, 'CheckedState': 1}, None, 10), "(10)") + # invert true/false + self.assertEqual(field_formatter.representValue(layer, 0, {'UncheckedState': 1, 'CheckedState': 0}, None, 0), 'true') + self.assertEqual(field_formatter.representValue(layer, 0, {'UncheckedState': 1, 'CheckedState': 0}, None, 1), 'false') + + # test with string + self.assertEqual(field_formatter.representValue(layer, 1, {'UncheckedState': 'nooh', 'CheckedState': 'yeah'}, None, 'yeah'), 'true') + self.assertEqual(field_formatter.representValue(layer, 1, {'UncheckedState': 'nooh', 'CheckedState': 'yeah'}, None, 'nooh'), 'false') + self.assertEqual(field_formatter.representValue(layer, 1, {'UncheckedState': 'nooh', 'CheckedState': 'yeah'}, None, 'oops'), "(oops)") + + if __name__ == '__main__': unittest.main()