Skip to content
Permalink
Browse files

Allow users to override the default locale thousand separator within

specific numeric format objects

E.g. this allows users to set a specific thousand grouping character
to use for a particular scalebar number labels. Useful in the case of
creating maps for users outside of the current locale. Default is
always to use the QGIS locale character (this is an advanced setting!)
  • Loading branch information
nyalldawson committed Jan 8, 2020
1 parent 16c2254 commit d3afd6d936f36ccd94f2c8ae1a22295509d301fd
@@ -124,6 +124,22 @@ Returns the rounding type, which controls the behavior of the numberDecimalPlace
Sets the rounding ``type``, which controls the behavior of the numberDecimalPlaces() setting.

.. seealso:: :py:func:`roundingType`
%End

QChar thousandsSeparator() const;
%Docstring
Returns any override for the thousands separator character. If an invalid QChar is returned,
then the QGIS locale separator is used instead.

.. seealso:: :py:func:`setThousandsSeparator`
%End

void setThousandsSeparator( QChar character );
%Docstring
Sets an override ``character`` for the thousands separator character. If an invalid QChar is set,
then the QGIS locale separator is used instead.

.. seealso:: :py:func:`thousandsSeparator`
%End

protected:
@@ -59,7 +59,7 @@ int QgsBasicNumericFormat::sortKey()
QString QgsBasicNumericFormat::formatDouble( double value, const QgsNumericFormatContext &context ) const
{
std::basic_stringstream<wchar_t> os;
os.imbue( std::locale( os.getloc(), new formatter( context.thousandsSeparator(), mShowThousandsSeparator, context.decimalSeparator() ) ) );
os.imbue( std::locale( os.getloc(), new formatter( mThousandsSeparator.isNull() ? context.thousandsSeparator() : mThousandsSeparator, mShowThousandsSeparator, context.decimalSeparator() ) ) );

if ( !mUseScientific )
{
@@ -145,6 +145,7 @@ QVariantMap QgsBasicNumericFormat::configuration( const QgsReadWriteContext & )
res.insert( QStringLiteral( "show_plus" ), mShowPlusSign );
res.insert( QStringLiteral( "show_trailing_zeros" ), mShowTrailingZeros );
res.insert( QStringLiteral( "rounding_type" ), static_cast< int >( mRoundingType ) );
res.insert( QStringLiteral( "thousand_separator" ), mThousandsSeparator );
return res;
}

@@ -155,6 +156,7 @@ void QgsBasicNumericFormat::setConfiguration( const QVariantMap &configuration,
mShowPlusSign = configuration.value( QStringLiteral( "show_plus" ), false ).toBool();
mShowTrailingZeros = configuration.value( QStringLiteral( "show_trailing_zeros" ), false ).toBool();
mRoundingType = static_cast< RoundingType >( configuration.value( QStringLiteral( "rounding_type" ), static_cast< int >( DecimalPlaces ) ).toInt() );
mThousandsSeparator = configuration.value( QStringLiteral( "thousand_separator" ), QChar() ).toChar();
}

int QgsBasicNumericFormat::numberDecimalPlaces() const
@@ -206,3 +208,13 @@ void QgsBasicNumericFormat::setRoundingType( QgsBasicNumericFormat::RoundingType
{
mRoundingType = type;
}

QChar QgsBasicNumericFormat::thousandsSeparator() const
{
return mThousandsSeparator;
}

void QgsBasicNumericFormat::setThousandsSeparator( QChar character )
{
mThousandsSeparator = character;
}
@@ -126,6 +126,22 @@ class CORE_EXPORT QgsBasicNumericFormat : public QgsNumericFormat
*/
void setRoundingType( RoundingType type );

/**
* Returns any override for the thousands separator character. If an invalid QChar is returned,
* then the QGIS locale separator is used instead.
*
* \see setThousandsSeparator()
*/
QChar thousandsSeparator() const;

/**
* Sets an override \a character for the thousands separator character. If an invalid QChar is set,
* then the QGIS locale separator is used instead.
*
* \see thousandsSeparator()
*/
void setThousandsSeparator( QChar character );

protected:

/**
@@ -143,6 +159,8 @@ class CORE_EXPORT QgsBasicNumericFormat : public QgsNumericFormat
bool mShowTrailingZeros = false;

RoundingType mRoundingType = DecimalPlaces;

QChar mThousandsSeparator;
};

#endif // QGSBASICNUMERICFORMAT_H
@@ -161,6 +161,7 @@ QDomElement QgsXmlUtils::writeVariant( const QVariant &value, QDomDocument &doc
case QVariant::LongLong:
case QVariant::ULongLong:
case QVariant::String:
case QVariant::Char:
element.setAttribute( QStringLiteral( "type" ), QVariant::typeToName( value.type() ) );
element.setAttribute( QStringLiteral( "value" ), value.toString() );
break;
@@ -236,6 +237,11 @@ QVariant QgsXmlUtils::readVariant( const QDomElement &element )
{
return element.attribute( QStringLiteral( "value" ) );
}
else if ( type == QLatin1String( "QChar" ) )
{
const QString res = element.attribute( QStringLiteral( "value" ) );
return res.isEmpty() ? QChar() : res.at( 0 );
}
else if ( type == QLatin1String( "bool" ) )
{
return element.attribute( QStringLiteral( "value" ) ) == QLatin1String( "true" );
@@ -32,6 +32,8 @@ QgsBasicNumericFormatWidget::QgsBasicNumericFormatWidget( const QgsNumericFormat
setupUi( this );
setFormat( format->clone() );

mThousandsLineEdit->setShowClearButton( true );

connect( mShowPlusCheckBox, &QCheckBox::toggled, this, [ = ]( bool checked )
{
mFormat->setShowPlusSign( checked );
@@ -79,6 +81,13 @@ QgsBasicNumericFormatWidget::QgsBasicNumericFormatWidget( const QgsNumericFormat
if ( !mBlockSignals )
emit changed();
} );

connect( mThousandsLineEdit, &QLineEdit::textChanged, this, [ = ]( const QString & text )
{
mFormat->setThousandsSeparator( text.isEmpty() ? QChar() : text.at( 0 ) );
if ( !mBlockSignals )
emit changed();
} );
}

QgsBasicNumericFormatWidget::~QgsBasicNumericFormatWidget() = default;
@@ -92,6 +101,7 @@ void QgsBasicNumericFormatWidget::setFormat( QgsNumericFormat *format )
mShowPlusCheckBox->setChecked( mFormat->showPlusSign() );
mShowTrailingZerosCheckBox->setChecked( mFormat->showTrailingZeros() );
mShowThousandsCheckBox->setChecked( mFormat->showThousandsSeparator() );
mThousandsLineEdit->setText( mFormat->thousandsSeparator().isNull() ? QString() : mFormat->thousandsSeparator() );
switch ( mFormat->roundingType() )
{
case QgsBasicNumericFormat::DecimalPlaces:
@@ -14,7 +14,38 @@
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
<item row="6" column="0">
<item row="1" column="0" colspan="2">
<widget class="QRadioButton" name="mRadDecimalPlaces">
<property name="text">
<string>Decimal places</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="mShowTrailingZerosCheckBox">
<property name="text">
<string>Show trailing zeros</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QRadioButton" name="mRadSignificantFigures">
<property name="text">
<string>Significant figures</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Round to</string>
</property>
</widget>
</item>
<item row="7" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -27,13 +58,6 @@
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Round to</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="mDecimalsSpinBox">
<property name="value">
@@ -58,27 +82,20 @@
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="mShowTrailingZerosCheckBox">
<property name="text">
<string>Show trailing zeros</string>
<item row="6" column="1">
<widget class="QgsFilterLineEdit" name="mThousandsLineEdit">
<property name="maxLength">
<number>1</number>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QRadioButton" name="mRadDecimalPlaces">
<property name="text">
<string>Decimal places</string>
</property>
<property name="checked">
<bool>true</bool>
<property name="placeholderText">
<string>Default</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QRadioButton" name="mRadSignificantFigures">
<item row="6" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Significant figures</string>
<string>Thousands separator</string>
</property>
</widget>
</item>
@@ -91,6 +108,11 @@
<header>qgspanelwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsFilterLineEdit</class>
<extends>QLineEdit</extends>
<header>qgsfilterlineedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
@@ -22,7 +22,6 @@
QgsNumericFormatRegistry,
QgsNumericFormat,
QgsReadWriteContext)

from qgis.testing import start_app, unittest
from qgis.PyQt.QtXml import QDomDocument

@@ -155,6 +154,11 @@ def testBasicFormat(self):
self.assertEqual(f.formatDouble(-5.5, context), '-5.50')
self.assertEqual(f.formatDouble(-55555555.5, context), '-55600000')

f.setThousandsSeparator('✅')
f.setShowThousandsSeparator(True)
self.assertEqual(f.formatDouble(-55555555.5, context), '-55✅600✅000')
f.setShowThousandsSeparator(False)

f.setShowPlusSign(True)

f2 = f.clone()
@@ -165,6 +169,7 @@ def testBasicFormat(self):
self.assertEqual(f2.numberDecimalPlaces(), f.numberDecimalPlaces())
self.assertEqual(f2.showThousandsSeparator(), f.showThousandsSeparator())
self.assertEqual(f2.roundingType(), f.roundingType())
self.assertEqual(f2.thousandsSeparator(), f.thousandsSeparator())

doc = QDomDocument("testdoc")
elem = doc.createElement("test")
@@ -178,6 +183,7 @@ def testBasicFormat(self):
self.assertEqual(f3.numberDecimalPlaces(), f.numberDecimalPlaces())
self.assertEqual(f3.showThousandsSeparator(), f.showThousandsSeparator())
self.assertEqual(f3.roundingType(), f.roundingType())
self.assertEqual(f3.thousandsSeparator(), f.thousandsSeparator())

def testCurrencyFormat(self):
""" test currency formatter """
@@ -64,7 +64,7 @@ def test_long(self):

def test_string(self):
"""
Test that maps are correctly loaded and written
Test that strings are correctly loaded and written
"""
doc = QDomDocument("properties")

0 comments on commit d3afd6d

Please sign in to comment.
You can’t perform that action at this time.