Skip to content
Permalink
Browse files

Add option to control the plain text display method for fields using

the checkbox form widget

In QGIS 2.x we always displayed the underlying raw value of a field
using the checkbox widget in the attribute table or in identify results
(i.e. the text display of the field would always match the value
the user had set for the checked or unchecked representation status,
e.g. "yes"/"no", "present"/"absent", etc)

This was changed in 3.0 so that the representation status ONLY affected
how the underlying stored values are mapped to a boolean true or false
value, and accordingly the attribute table/identify results started
only showing "true" or "false" strings.

This new setting allows users to control whether they want plain text
displays of the field to use the 3.x "true"/"false" behavior (the
default), or if they want to see the 2.x style actual field value.
  • Loading branch information
nyalldawson committed Feb 16, 2021
1 parent 1772c94 commit eba9ffa46e6d3f00e276583e3c38e29ccb1841b9
@@ -21,6 +21,12 @@ Field formatter for a checkbox field.
%End
public:

enum TextDisplayMethod
{
ShowTrueFalse,
ShowStoredValues,
};

QgsCheckBoxFieldFormatter();
%Docstring
Constructor for QgsCheckBoxFieldFormatter.
@@ -52,6 +52,7 @@ QString QgsCheckBoxFieldFormatter::representValue( QgsVectorLayer *layer, int fi
if ( fieldType == QVariant::Bool )
{
boolValue = value.toBool();
textValue = boolValue ? QObject::tr( "true" ) : QObject::tr( "false" );
}
else
{
@@ -62,18 +63,19 @@ QString QgsCheckBoxFieldFormatter::representValue( QgsVectorLayer *layer, int fi
}
else
{
if ( config.contains( QStringLiteral( "CheckedState" ) ) && value.toString() == config[ QStringLiteral( "CheckedState" ) ].toString() )
textValue = value.toString();
if ( config.contains( QStringLiteral( "CheckedState" ) ) && textValue == config[ QStringLiteral( "CheckedState" ) ].toString() )
{
boolValue = true;
}
else if ( config.contains( QStringLiteral( "UncheckedState" ) ) && value.toString() == config[ QStringLiteral( "UncheckedState" ) ].toString() )
else if ( config.contains( QStringLiteral( "UncheckedState" ) ) && textValue == config[ QStringLiteral( "UncheckedState" ) ].toString() )
{
boolValue = false;
}
else
{
isNull = true;
textValue = QStringLiteral( "(%1)" ).arg( value.toString() );
textValue = QStringLiteral( "(%1)" ).arg( textValue );
}
}
}
@@ -82,8 +84,18 @@ QString QgsCheckBoxFieldFormatter::representValue( QgsVectorLayer *layer, int fi
{
return textValue;
}
if ( boolValue )
return QObject::tr( "true" );
else
return QObject::tr( "false" );

const TextDisplayMethod displayMethod = static_cast< TextDisplayMethod >( config.value( QStringLiteral( "TextDisplayMethod" ), QStringLiteral( "0" ) ).toInt() );
switch ( displayMethod )
{
case QgsCheckBoxFieldFormatter::ShowTrueFalse:
if ( boolValue )
return QObject::tr( "true" );
else
return QObject::tr( "false" );

case QgsCheckBoxFieldFormatter::ShowStoredValues:
return textValue;
}
return QString();
}
@@ -30,6 +30,17 @@ class CORE_EXPORT QgsCheckBoxFieldFormatter : public QgsFieldFormatter
{
public:

/**
* Method to use when displaying the checkbox values as plain text.
*
* \since QGIS 3.18
*/
enum TextDisplayMethod
{
ShowTrueFalse, //!< Shows "True" or "False" strings
ShowStoredValues, //!< Shows actual stored field value
};

/**
* Constructor for QgsCheckBoxFieldFormatter.
*/
@@ -14,14 +14,21 @@
***************************************************************************/

#include "qgscheckboxconfigdlg.h"
#include "qgscheckboxwidgetwrapper.h"
#include "qgscheckboxfieldformatter.h"

QgsCheckBoxConfigDlg::QgsCheckBoxConfigDlg( QgsVectorLayer *vl, int fieldIdx, QWidget *parent )
: QgsEditorConfigWidget( vl, fieldIdx, parent )
{
setupUi( this );

mDisplayAsTextComboBox->addItem( tr( "\"True\" or \"False\"" ), QgsCheckBoxFieldFormatter::ShowTrueFalse );
mDisplayAsTextComboBox->addItem( tr( "Stored Values" ), QgsCheckBoxFieldFormatter::ShowStoredValues );
mDisplayAsTextComboBox->setCurrentIndex( 0 );

connect( leCheckedState, &QLineEdit::textEdited, this, &QgsEditorConfigWidget::changed );
connect( leUncheckedState, &QLineEdit::textEdited, this, &QgsEditorConfigWidget::changed );
connect( mDisplayAsTextComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsEditorConfigWidget::changed );

if ( vl->fields().at( fieldIdx ).type() == QVariant::Bool )
{
@@ -39,6 +46,7 @@ QVariantMap QgsCheckBoxConfigDlg::config()

cfg.insert( QStringLiteral( "CheckedState" ), leCheckedState->text() );
cfg.insert( QStringLiteral( "UncheckedState" ), leUncheckedState->text() );
cfg.insert( QStringLiteral( "TextDisplayMethod" ), mDisplayAsTextComboBox->currentData().toInt() );

return cfg;
}
@@ -50,4 +58,5 @@ void QgsCheckBoxConfigDlg::setConfig( const QVariantMap &config )
leCheckedState->setText( config.value( QStringLiteral( "CheckedState" ) ).toString() );
leUncheckedState->setText( config.value( QStringLiteral( "UncheckedState" ) ).toString() );
}
mDisplayAsTextComboBox->setCurrentIndex( mDisplayAsTextComboBox->findData( config.value( QStringLiteral( "TextDisplayMethod" ), QString::number( static_cast< int >( QgsCheckBoxFieldFormatter::ShowTrueFalse ) ) ).toInt() ) );
}
@@ -6,34 +6,87 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<width>395</width>
<height>351</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Representation for checked state</string>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Display Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Display the checkbox state as a plain text value (e.g. in an attribute table) using</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QComboBox" name="mDisplayAsTextComboBox"/>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="leCheckedState"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Representation for unchecked state</string>
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Representation</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Unchecked state</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="leUncheckedState"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Checked state</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="leCheckedState"/>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>The checked and unchecked representation state are the raw values stored in the layer when the checkbox is checked or unchecked.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="leUncheckedState"/>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
@@ -402,17 +402,40 @@ def test_representValue(self):

# 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)")

config = {'UncheckedState': 0, 'CheckedState': 1}
self.assertEqual(field_formatter.representValue(layer, 0, config, None, 1), 'true')
self.assertEqual(field_formatter.representValue(layer, 0, config, None, 0), 'false')
self.assertEqual(field_formatter.representValue(layer, 0, config, None, 10), "(10)")

# displaying stored values
config['TextDisplayMethod'] = QgsCheckBoxFieldFormatter.ShowStoredValues
self.assertEqual(field_formatter.representValue(layer, 0, config, None, 1), '1')
self.assertEqual(field_formatter.representValue(layer, 0, config, None, 0), '0')
self.assertEqual(field_formatter.representValue(layer, 0, config, 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')
config = {'UncheckedState': 1, 'CheckedState': 0}
self.assertEqual(field_formatter.representValue(layer, 0, config, None, 0), 'true')
self.assertEqual(field_formatter.representValue(layer, 0, config, None, 1), 'false')

# displaying stored values
config['TextDisplayMethod'] = QgsCheckBoxFieldFormatter.ShowStoredValues
self.assertEqual(field_formatter.representValue(layer, 0, config, None, 1), '1')
self.assertEqual(field_formatter.representValue(layer, 0, config, None, 0), '0')
self.assertEqual(field_formatter.representValue(layer, 0, config, None, 10), "(10)")

# 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)")
config = {'UncheckedState': 'nooh', 'CheckedState': 'yeah'}
self.assertEqual(field_formatter.representValue(layer, 1, config, None, 'yeah'), 'true')
self.assertEqual(field_formatter.representValue(layer, 1, config, None, 'nooh'), 'false')
self.assertEqual(field_formatter.representValue(layer, 1, config, None, 'oops'), "(oops)")

# displaying stored values
config['TextDisplayMethod'] = QgsCheckBoxFieldFormatter.ShowStoredValues
self.assertEqual(field_formatter.representValue(layer, 0, config, None, 'yeah'), 'yeah')
self.assertEqual(field_formatter.representValue(layer, 0, config, None, 'nooh'), 'nooh')
self.assertEqual(field_formatter.representValue(layer, 0, config, None, 'oops'), "(oops)")


class TestQgsFallbackFieldFormatter(unittest.TestCase):

0 comments on commit eba9ffa

Please sign in to comment.