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.

(cherry picked from commit eba9ffa)
  • Loading branch information
nyalldawson committed Feb 19, 2021
1 parent 7521861 commit 6404e58bc9691fa3df8087d1a9de821793455675
@@ -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">
@@ -401,17 +401,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 6404e58

Please sign in to comment.