QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
Loading...
Searching...
No Matches
qgsbasicnumericformat.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsbasicnumericformat.cpp
3 ----------------------------
4 begin : January 2020
5 copyright : (C) 2020 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7
8 ***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
18
19#include <iomanip>
20#include <iostream>
21#include <locale>
22#include <memory>
23
24#include "qgis.h"
25
26#include <QString>
27
28using namespace Qt::StringLiterals;
29
31{
32 struct formatter : std::numpunct<wchar_t>
33 {
34 formatter( QChar thousands, bool showThousands, QChar decimal )
35 : mThousands( thousands.unicode() )
36 , mDecimal( decimal.unicode() )
37 , mShowThousands( showThousands )
38 {}
39 wchar_t do_decimal_point() const override { return mDecimal; }
40 wchar_t do_thousands_sep() const override { return mThousands; }
41 std::string do_grouping() const override { return mShowThousands ? "\3" : "\0"; }
42
43 wchar_t mThousands;
44 wchar_t mDecimal;
45 bool mShowThousands = true;
46 };
47} //namespace QgsBasicNumericFormat_ns
48
51
53{
54 return u"basic"_s;
55}
56
58{
59 return QObject::tr( "Number" );
60}
61
63{
64 return 1;
65}
66
67QString QgsBasicNumericFormat::formatDouble( double value, const QgsNumericFormatContext &context ) const
68{
69 const QChar decimal = mDecimalSeparator.isNull() ? context.decimalSeparator() : mDecimalSeparator;
70 std::basic_stringstream<wchar_t> os;
71 os.imbue( std::locale( os.getloc(), new QgsBasicNumericFormat_ns::formatter( mThousandsSeparator.isNull() ? context.thousandsSeparator() : mThousandsSeparator, mShowThousandsSeparator, decimal ) ) );
72
73 if ( !mUseScientific )
74 {
75 switch ( mRoundingType )
76 {
77 case DecimalPlaces:
78 os << std::fixed << std::setprecision( mNumberDecimalPlaces );
79 if ( qgsDoubleNear( value, 0 ) )
80 os << 0.0;
81 else
82 os << value;
83
84 break;
85
87 {
88 if ( qgsDoubleNear( value, 0 ) )
89 {
90 os << std::fixed << std::setprecision( mNumberDecimalPlaces - 1 ) << 0.0;
91 }
92 else
93 {
94 // digits before decimal point
95 const int d = std::floor( std::log10( value < 0 ? -value : value ) ) + 1;
96 const double order = std::pow( 10.0, mNumberDecimalPlaces - d );
97 os << std::fixed << std::setprecision( std::max( mNumberDecimalPlaces - d, 0 ) ) << std::round( value * order ) / order;
98 }
99 break;
100 }
101 }
102 }
103 else
104 {
105 os << std::scientific << std::setprecision( mNumberDecimalPlaces );
106 if ( qgsDoubleNear( value, 0 ) )
107 os << 0.0;
108 else
109 os << value;
110 }
111
112 QString res = QString::fromStdWString( os.str() );
113
114 if ( mShowPlusSign && value > 0 )
115 res.prepend( context.positiveSign() );
116
117 if ( !mShowTrailingZeros && res.contains( decimal ) )
118 {
119 int trimPoint = res.length() - 1;
120 int ePoint = 0;
121 if ( mUseScientific )
122 {
123 while ( res.at( trimPoint ).toUpper() != context.exponential().toUpper() )
124 trimPoint--;
125 ePoint = trimPoint;
126 trimPoint--;
127 }
128
129 while ( res.at( trimPoint ) == context.zeroDigit() )
130 trimPoint--;
131
132 if ( res.at( trimPoint ) == decimal )
133 trimPoint--;
134
135 const QString original = res;
136 res.truncate( trimPoint + 1 );
137 if ( mUseScientific )
138 res += original.mid( ePoint );
139 }
140
141 return res;
142}
143
145{
146 return new QgsBasicNumericFormat( *this );
147}
148
150{
151 auto res = std::make_unique< QgsBasicNumericFormat >();
152 res->setConfiguration( configuration, context );
153 return res.release();
154}
155
157{
158 QVariantMap res;
159 res.insert( u"decimals"_s, mNumberDecimalPlaces );
160 res.insert( u"show_thousand_separator"_s, mShowThousandsSeparator );
161 res.insert( u"show_plus"_s, mShowPlusSign );
162 res.insert( u"show_trailing_zeros"_s, mShowTrailingZeros );
163 res.insert( u"rounding_type"_s, static_cast< int >( mRoundingType ) );
164 res.insert( u"thousand_separator"_s, mThousandsSeparator.isNull() ? QVariant() : QVariant::fromValue( mThousandsSeparator ) );
165 res.insert( u"decimal_separator"_s, mDecimalSeparator.isNull() ? QVariant() : QVariant::fromValue( mDecimalSeparator ) );
166 return res;
167}
168
170{
171 mNumberDecimalPlaces = configuration.value( u"decimals"_s, 6 ).toInt();
172 mShowThousandsSeparator = configuration.value( u"show_thousand_separator"_s, true ).toBool();
173 mShowPlusSign = configuration.value( u"show_plus"_s, false ).toBool();
174 mShowTrailingZeros = configuration.value( u"show_trailing_zeros"_s, false ).toBool();
175 mRoundingType = static_cast< RoundingType >( configuration.value( u"rounding_type"_s, static_cast< int >( DecimalPlaces ) ).toInt() );
176 mThousandsSeparator = configuration.value( u"thousand_separator"_s, QChar() ).toChar();
177 mDecimalSeparator = configuration.value( u"decimal_separator"_s, QChar() ).toChar();
178}
179
181{
182 return mNumberDecimalPlaces;
183}
184
189
191{
192 return mShowThousandsSeparator;
193}
194
199
201{
202 return mShowPlusSign;
203}
204
206{
207 mShowPlusSign = showPlusSign;
208}
209
211{
212 return mShowTrailingZeros;
213}
214
219
224
229
231{
232 return mThousandsSeparator;
233}
234
236{
237 mThousandsSeparator = character;
238}
239
241{
242 return mDecimalSeparator;
243}
244
246{
247 mDecimalSeparator = character;
248}
QgsNumericFormat * create(const QVariantMap &configuration, const QgsReadWriteContext &context) const override
Creates a new copy of the format, using the supplied configuration.
QChar thousandsSeparator() const
Returns any override for the thousands separator character.
RoundingType
Sets rounding type and behavior of the numberDecimalPlaces() setting.
@ DecimalPlaces
Maximum number of decimal places.
@ SignificantFigures
Maximum number of significant figures.
void setThousandsSeparator(QChar character)
Sets an override character for the thousands separator character.
QgsBasicNumericFormat()
Default constructor.
void setShowTrailingZeros(bool show)
Sets whether trailing zeros will be shown (up to the specified numberDecimalPlaces()).
void setShowThousandsSeparator(bool show)
Sets whether the thousands grouping separator will be shown.
bool showThousandsSeparator() const
Returns true if the thousands grouping separator will be shown.
QString id() const override
Returns a unique id for this numeric format.
virtual void setConfiguration(const QVariantMap &configuration, const QgsReadWriteContext &context)
Sets the format's configuration.
RoundingType roundingType() const
Returns the rounding type, which controls the behavior of the numberDecimalPlaces() setting.
QString visibleName() const override
Returns the translated, user-visible name for this format.
int sortKey() override
Returns a sorting key value, where formats with a lower sort key will be shown earlier in lists.
bool showTrailingZeros() const
Returns true if trailing zeros will be shown (up to the specified numberDecimalPlaces()).
void setRoundingType(RoundingType type)
Sets the rounding type, which controls the behavior of the numberDecimalPlaces() setting.
QgsNumericFormat * clone() const override
Clones the format, returning a new object.
bool showPlusSign() const
Returns true if a leading plus sign will be shown for positive values.
QChar decimalSeparator() const
Returns any override for the decimal separator character.
void setShowPlusSign(bool show)
Sets whether a leading plus sign will be shown for positive values.
QString formatDouble(double value, const QgsNumericFormatContext &context) const override
Returns a formatted string representation of a numeric double value.
virtual void setNumberDecimalPlaces(int places)
Sets the maximum number of decimal places to show.
int numberDecimalPlaces() const
Returns the maximum number of decimal places to show.
QVariantMap configuration(const QgsReadWriteContext &context) const override
Returns the current configuration of the formatter.
void setDecimalSeparator(QChar character)
Sets an override character for the decimal separator character.
A context for numeric formats.
QChar thousandsSeparator() const
Returns the thousands separator character.
QChar zeroDigit() const
Returns the zero digit character.
QChar exponential() const
Returns the exponential character.
QChar decimalSeparator() const
Returns the decimal separator character.
QChar positiveSign() const
Returns the positive sign character.
QgsNumericFormat()=default
A container for the context for various read/write operations on objects.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6975
std::string do_grouping() const override
formatter(QChar thousands, bool showThousands, QChar decimal)