Skip to content

Commit

Permalink
Also expose setting for optionally overridding the decimal character
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jan 9, 2020
1 parent 1e82bbc commit 1cd2e16
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 68 deletions.
Expand Up @@ -140,6 +140,22 @@ Sets an override ``character`` for the thousands separator character. If an inva
then the QGIS locale separator is used instead.

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

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

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

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

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

protected:
Expand Down
21 changes: 18 additions & 3 deletions src/core/numericformats/qgsbasicnumericformat.cpp
Expand Up @@ -58,8 +58,11 @@ int QgsBasicNumericFormat::sortKey()

QString QgsBasicNumericFormat::formatDouble( double value, const QgsNumericFormatContext &context ) const
{
QChar decimal = mDecimalSeparator.isNull() ? context.decimalSeparator() : mDecimalSeparator;
std::basic_stringstream<wchar_t> os;
os.imbue( std::locale( os.getloc(), new formatter( mThousandsSeparator.isNull() ? context.thousandsSeparator() : mThousandsSeparator, mShowThousandsSeparator, context.decimalSeparator() ) ) );
os.imbue( std::locale( os.getloc(), new formatter( mThousandsSeparator.isNull() ? context.thousandsSeparator() : mThousandsSeparator,
mShowThousandsSeparator,
decimal ) ) );

if ( !mUseScientific )
{
Expand Down Expand Up @@ -98,7 +101,7 @@ QString QgsBasicNumericFormat::formatDouble( double value, const QgsNumericForma
if ( mShowPlusSign && value > 0 )
res.prepend( context.positiveSign() );

if ( !mShowTrailingZeros && res.contains( context.decimalSeparator() ) )
if ( !mShowTrailingZeros && res.contains( decimal ) )
{
int trimPoint = res.length() - 1;
int ePoint = 0;
Expand All @@ -113,7 +116,7 @@ QString QgsBasicNumericFormat::formatDouble( double value, const QgsNumericForma
while ( res.at( trimPoint ) == context.zeroDigit() )
trimPoint--;

if ( res.at( trimPoint ) == context.decimalSeparator() )
if ( res.at( trimPoint ) == decimal )
trimPoint--;

QString original = res;
Expand Down Expand Up @@ -146,6 +149,7 @@ QVariantMap QgsBasicNumericFormat::configuration( const QgsReadWriteContext & )
res.insert( QStringLiteral( "show_trailing_zeros" ), mShowTrailingZeros );
res.insert( QStringLiteral( "rounding_type" ), static_cast< int >( mRoundingType ) );
res.insert( QStringLiteral( "thousand_separator" ), mThousandsSeparator );
res.insert( QStringLiteral( "decimal_separator" ), mDecimalSeparator );
return res;
}

Expand All @@ -157,6 +161,7 @@ void QgsBasicNumericFormat::setConfiguration( const QVariantMap &configuration,
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();
mDecimalSeparator = configuration.value( QStringLiteral( "decimal_separator" ), QChar() ).toChar();
}

int QgsBasicNumericFormat::numberDecimalPlaces() const
Expand Down Expand Up @@ -218,3 +223,13 @@ void QgsBasicNumericFormat::setThousandsSeparator( QChar character )
{
mThousandsSeparator = character;
}

QChar QgsBasicNumericFormat::decimalSeparator() const
{
return mDecimalSeparator;
}

void QgsBasicNumericFormat::setDecimalSeparator( QChar character )
{
mDecimalSeparator = character;
}
17 changes: 17 additions & 0 deletions src/core/numericformats/qgsbasicnumericformat.h
Expand Up @@ -142,6 +142,22 @@ class CORE_EXPORT QgsBasicNumericFormat : public QgsNumericFormat
*/
void setThousandsSeparator( QChar character );

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

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

protected:

/**
Expand All @@ -161,6 +177,7 @@ class CORE_EXPORT QgsBasicNumericFormat : public QgsNumericFormat
RoundingType mRoundingType = DecimalPlaces;

QChar mThousandsSeparator;
QChar mDecimalSeparator;
};

#endif // QGSBASICNUMERICFORMAT_H
1 change: 1 addition & 0 deletions src/core/numericformats/qgsbearingnumericformat.cpp
Expand Up @@ -93,6 +93,7 @@ QgsNumericFormat *QgsBearingNumericFormat::create( const QVariantMap &configurat
{
std::unique_ptr< QgsBearingNumericFormat > res = qgis::make_unique< QgsBearingNumericFormat >();
res->setConfiguration( configuration, context );
res->mDirectionFormat = static_cast< FormatDirectionOption >( configuration.value( QStringLiteral( "direction_format" ), 0 ).toInt() );
return res.release();
}

Expand Down
9 changes: 9 additions & 0 deletions src/gui/numericformats/qgsnumericformatwidget.cpp
Expand Up @@ -33,6 +33,7 @@ QgsBasicNumericFormatWidget::QgsBasicNumericFormatWidget( const QgsNumericFormat
setFormat( format->clone() );

mThousandsLineEdit->setShowClearButton( true );
mDecimalLineEdit->setShowClearButton( true );

connect( mShowPlusCheckBox, &QCheckBox::toggled, this, [ = ]( bool checked )
{
Expand Down Expand Up @@ -88,6 +89,13 @@ QgsBasicNumericFormatWidget::QgsBasicNumericFormatWidget( const QgsNumericFormat
if ( !mBlockSignals )
emit changed();
} );

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

QgsBasicNumericFormatWidget::~QgsBasicNumericFormatWidget() = default;
Expand All @@ -102,6 +110,7 @@ void QgsBasicNumericFormatWidget::setFormat( QgsNumericFormat *format )
mShowTrailingZerosCheckBox->setChecked( mFormat->showTrailingZeros() );
mShowThousandsCheckBox->setChecked( mFormat->showThousandsSeparator() );
mThousandsLineEdit->setText( mFormat->thousandsSeparator().isNull() ? QString() : mFormat->thousandsSeparator() );
mDecimalLineEdit->setText( mFormat->decimalSeparator().isNull() ? QString() : mFormat->decimalSeparator() );
switch ( mFormat->roundingType() )
{
case QgsBasicNumericFormat::DecimalPlaces:
Expand Down
75 changes: 46 additions & 29 deletions src/ui/numericformats/qgsbasicnumericformatwidgetbase.ui
Expand Up @@ -13,7 +13,14 @@
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Round to</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QRadioButton" name="mRadDecimalPlaces">
<property name="text">
Expand All @@ -24,39 +31,39 @@
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="mShowTrailingZerosCheckBox">
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="mShowPlusCheckBox">
<property name="text">
<string>Show trailing zeros</string>
<string>Show plus sign</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QRadioButton" name="mRadSignificantFigures">
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="mShowThousandsCheckBox">
<property name="text">
<string>Significant figures</string>
<string>Show thousands separator</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<item row="7" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Round to</string>
<string>Decimal separator</string>
</property>
</widget>
</item>
<item row="7" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<item row="7" column="1">
<widget class="QgsFilterLineEdit" name="mDecimalLineEdit">
<property name="maxLength">
<number>1</number>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
<property name="placeholderText">
<string>Default</string>
</property>
</spacer>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="mDecimalsSpinBox">
Expand All @@ -65,23 +72,33 @@
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="mShowThousandsCheckBox">
<item row="2" column="0" colspan="2">
<widget class="QRadioButton" name="mRadSignificantFigures">
<property name="text">
<string>Show thousands separator</string>
</property>
<property name="checked">
<bool>true</bool>
<string>Significant figures</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="mShowPlusCheckBox">
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="mShowTrailingZerosCheckBox">
<property name="text">
<string>Show plus sign</string>
<string>Show trailing zeros</string>
</property>
</widget>
</item>
<item row="8" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="1">
<widget class="QgsFilterLineEdit" name="mThousandsLineEdit">
<property name="maxLength">
Expand Down
77 changes: 41 additions & 36 deletions tests/src/python/test_qgsnumericformat.py
Expand Up @@ -91,6 +91,9 @@ def testBasicFormat(self):
self.assertEqual(f.formatDouble(-5.5, context), '-5☕5')
self.assertEqual(f.formatDouble(-55555555.5, context), '-55555555☕5')
context.setDecimalSeparator('.')
f.setDecimalSeparator('⛹')
self.assertEqual(f.formatDouble(-5.5, context), '-5⛹5')
self.assertEqual(f.formatDouble(-55555555.5, context), '-55555555⛹5')
f.setNumberDecimalPlaces(0)
self.assertEqual(f.formatDouble(0, context), '0')
self.assertEqual(f.formatDouble(5.5, context), '6')
Expand All @@ -100,58 +103,58 @@ def testBasicFormat(self):
self.assertEqual(f.formatDouble(-55555555.5, context), '-55555556')
f.setNumberDecimalPlaces(3)
self.assertEqual(f.formatDouble(0, context), '0')
self.assertEqual(f.formatDouble(5.5, context), '5.5')
self.assertEqual(f.formatDouble(55555555.5, context), '55555555.5')
self.assertEqual(f.formatDouble(55555555.123456, context), '55555555.123')
self.assertEqual(f.formatDouble(-5.5, context), '-5.5')
self.assertEqual(f.formatDouble(-55555555.5, context), '-55555555.5')
self.assertEqual(f.formatDouble(5.5, context), '55')
self.assertEqual(f.formatDouble(55555555.5, context), '555555555')
self.assertEqual(f.formatDouble(55555555.123456, context), '55555555123')
self.assertEqual(f.formatDouble(-5.5, context), '-55')
self.assertEqual(f.formatDouble(-55555555.5, context), '-555555555')
f.setShowTrailingZeros(True)
self.assertEqual(f.formatDouble(0, context), '0.000')
self.assertEqual(f.formatDouble(5, context), '5.000')
self.assertEqual(f.formatDouble(-5, context), '-5.000')
self.assertEqual(f.formatDouble(5.5, context), '5.500')
self.assertEqual(f.formatDouble(55555555.5, context), '55555555.500')
self.assertEqual(f.formatDouble(55555555.123456, context), '55555555.123')
self.assertEqual(f.formatDouble(-5.5, context), '-5.500')
self.assertEqual(f.formatDouble(-55555555.5, context), '-55555555.500')
self.assertEqual(f.formatDouble(0, context), '0000')
self.assertEqual(f.formatDouble(5, context), '5000')
self.assertEqual(f.formatDouble(-5, context), '-5000')
self.assertEqual(f.formatDouble(5.5, context), '5500')
self.assertEqual(f.formatDouble(55555555.5, context), '55555555500')
self.assertEqual(f.formatDouble(55555555.123456, context), '55555555123')
self.assertEqual(f.formatDouble(-5.5, context), '-5500')
self.assertEqual(f.formatDouble(-55555555.5, context), '-55555555500')
f.setShowPlusSign(True)
self.assertEqual(f.formatDouble(0, context), '0.000')
self.assertEqual(f.formatDouble(5, context), '+5.000')
self.assertEqual(f.formatDouble(-5, context), '-5.000')
self.assertEqual(f.formatDouble(5.5, context), '+5.500')
self.assertEqual(f.formatDouble(55555555.5, context), '+55555555.500')
self.assertEqual(f.formatDouble(55555555.123456, context), '+55555555.123')
self.assertEqual(f.formatDouble(-5.5, context), '-5.500')
self.assertEqual(f.formatDouble(-55555555.5, context), '-55555555.500')
self.assertEqual(f.formatDouble(0, context), '0000')
self.assertEqual(f.formatDouble(5, context), '+5000')
self.assertEqual(f.formatDouble(-5, context), '-5000')
self.assertEqual(f.formatDouble(5.5, context), '+5500')
self.assertEqual(f.formatDouble(55555555.5, context), '+55555555500')
self.assertEqual(f.formatDouble(55555555.123456, context), '+55555555123')
self.assertEqual(f.formatDouble(-5.5, context), '-5500')
self.assertEqual(f.formatDouble(-55555555.5, context), '-55555555500')
context.setPositiveSign('w')
self.assertEqual(f.formatDouble(5, context), 'w5.000')
self.assertEqual(f.formatDouble(-5, context), '-5.000')
self.assertEqual(f.formatDouble(5.5, context), 'w5.500')
self.assertEqual(f.formatDouble(5, context), 'w5000')
self.assertEqual(f.formatDouble(-5, context), '-5000')
self.assertEqual(f.formatDouble(5.5, context), 'w5500')

f.setShowPlusSign(False)
f.setRoundingType(QgsBasicNumericFormat.SignificantFigures)
self.assertEqual(f.formatDouble(0, context), '0.00')
self.assertEqual(f.formatDouble(5, context), '5.00')
self.assertEqual(f.formatDouble(-5, context), '-5.00')
self.assertEqual(f.formatDouble(5.5, context), '5.50')
self.assertEqual(f.formatDouble(0, context), '000')
self.assertEqual(f.formatDouble(5, context), '500')
self.assertEqual(f.formatDouble(-5, context), '-500')
self.assertEqual(f.formatDouble(5.5, context), '550')
self.assertEqual(f.formatDouble(1231.23123123123123, context), '1230')
self.assertEqual(f.formatDouble(123.123123123123123, context), '123')
self.assertEqual(f.formatDouble(12.3123123123123123, context), '12.3')
self.assertEqual(f.formatDouble(1.23123123123123123, context), '1.23')
self.assertEqual(f.formatDouble(12.3123123123123123, context), '123')
self.assertEqual(f.formatDouble(1.23123123123123123, context), '123')
self.assertEqual(f.formatDouble(-1231.23123123123123, context), '-1230')
self.assertEqual(f.formatDouble(-123.123123123123123, context), '-123')
self.assertEqual(f.formatDouble(-12.3123123123123123, context), '-12.3')
self.assertEqual(f.formatDouble(-1.23123123123123123, context), '-1.23')
self.assertEqual(f.formatDouble(-12.3123123123123123, context), '-123')
self.assertEqual(f.formatDouble(-1.23123123123123123, context), '-123')
self.assertEqual(f.formatDouble(100, context), '100')
self.assertEqual(f.formatDouble(1000, context), '1000')
self.assertEqual(f.formatDouble(1001, context), '1000')
self.assertEqual(f.formatDouble(9999, context), '10000')
self.assertEqual(f.formatDouble(10, context), '10.0')
self.assertEqual(f.formatDouble(1, context), '1.00')
self.assertEqual(f.formatDouble(0.00000123456, context), '0.00000123')
self.assertEqual(f.formatDouble(10, context), '100')
self.assertEqual(f.formatDouble(1, context), '100')
self.assertEqual(f.formatDouble(0.00000123456, context), '000000123')
self.assertEqual(f.formatDouble(55555555.5, context), '55600000')
self.assertEqual(f.formatDouble(55555555.123456, context), '55600000')
self.assertEqual(f.formatDouble(-5.5, context), '-5.50')
self.assertEqual(f.formatDouble(-5.5, context), '-550')
self.assertEqual(f.formatDouble(-55555555.5, context), '-55600000')

f.setThousandsSeparator('✅')
Expand All @@ -170,6 +173,7 @@ def testBasicFormat(self):
self.assertEqual(f2.showThousandsSeparator(), f.showThousandsSeparator())
self.assertEqual(f2.roundingType(), f.roundingType())
self.assertEqual(f2.thousandsSeparator(), f.thousandsSeparator())
self.assertEqual(f2.decimalSeparator(), f.decimalSeparator())

doc = QDomDocument("testdoc")
elem = doc.createElement("test")
Expand All @@ -184,6 +188,7 @@ def testBasicFormat(self):
self.assertEqual(f3.showThousandsSeparator(), f.showThousandsSeparator())
self.assertEqual(f3.roundingType(), f.roundingType())
self.assertEqual(f3.thousandsSeparator(), f.thousandsSeparator())
self.assertEqual(f3.decimalSeparator(), f.decimalSeparator())

def testCurrencyFormat(self):
""" test currency formatter """
Expand Down

0 comments on commit 1cd2e16

Please sign in to comment.