QGIS API Documentation 3.99.0-Master (d270888f95f)
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}
48
52
54{
55 return u"basic"_s;
56}
57
59{
60 return QObject::tr( "Number" );
61}
62
64{
65 return 1;
66}
67
68QString QgsBasicNumericFormat::formatDouble( double value, const QgsNumericFormatContext &context ) const
69{
70 const QChar decimal = mDecimalSeparator.isNull() ? context.decimalSeparator() : mDecimalSeparator;
71 std::basic_stringstream<wchar_t> os;
72 os.imbue( std::locale( os.getloc(), new QgsBasicNumericFormat_ns::formatter( mThousandsSeparator.isNull() ? context.thousandsSeparator() : mThousandsSeparator,
73 mShowThousandsSeparator,
74 decimal ) ) );
75
76 if ( !mUseScientific )
77 {
78 switch ( mRoundingType )
79 {
80 case DecimalPlaces:
81 os << std::fixed << std::setprecision( mNumberDecimalPlaces );
82 if ( qgsDoubleNear( value, 0 ) )
83 os << 0.0;
84 else
85 os << value;
86
87 break;
88
90 {
91 if ( qgsDoubleNear( value, 0 ) )
92 {
93 os << std::fixed << std::setprecision( mNumberDecimalPlaces - 1 ) << 0.0;
94 }
95 else
96 {
97 // digits before decimal point
98 const int d = std::floor( std::log10( value < 0 ? -value : value ) ) + 1;
99 const double order = std::pow( 10.0, mNumberDecimalPlaces - d );
100 os << std::fixed << std::setprecision( std::max( mNumberDecimalPlaces - d, 0 ) ) << std::round( value * order ) / order;
101 }
102 break;
103 }
104 }
105 }
106 else
107 {
108 os << std::scientific << std::setprecision( mNumberDecimalPlaces );
109 if ( qgsDoubleNear( value, 0 ) )
110 os << 0.0;
111 else
112 os << value;
113 }
114
115 QString res = QString::fromStdWString( os.str() );
116
117 if ( mShowPlusSign && value > 0 )
118 res.prepend( context.positiveSign() );
119
120 if ( !mShowTrailingZeros && res.contains( decimal ) )
121 {
122 int trimPoint = res.length() - 1;
123 int ePoint = 0;
124 if ( mUseScientific )
125 {
126 while ( res.at( trimPoint ).toUpper() != context.exponential().toUpper() )
127 trimPoint--;
128 ePoint = trimPoint;
129 trimPoint--;
130 }
131
132 while ( res.at( trimPoint ) == context.zeroDigit() )
133 trimPoint--;
134
135 if ( res.at( trimPoint ) == decimal )
136 trimPoint--;
137
138 const QString original = res;
139 res.truncate( trimPoint + 1 );
140 if ( mUseScientific )
141 res += original.mid( ePoint );
142 }
143
144 return res;
145}
146
148{
149 return new QgsBasicNumericFormat( *this );
150}
151
153{
154 auto res = std::make_unique< QgsBasicNumericFormat >();
155 res->setConfiguration( configuration, context );
156 return res.release();
157}
158
160{
161 QVariantMap res;
162 res.insert( u"decimals"_s, mNumberDecimalPlaces );
163 res.insert( u"show_thousand_separator"_s, mShowThousandsSeparator );
164 res.insert( u"show_plus"_s, mShowPlusSign );
165 res.insert( u"show_trailing_zeros"_s, mShowTrailingZeros );
166 res.insert( u"rounding_type"_s, static_cast< int >( mRoundingType ) );
167 res.insert( u"thousand_separator"_s, mThousandsSeparator.isNull() ? QVariant() : QVariant::fromValue( mThousandsSeparator ) );
168 res.insert( u"decimal_separator"_s, mDecimalSeparator.isNull() ? QVariant() : QVariant::fromValue( mDecimalSeparator ) );
169 return res;
170}
171
173{
174 mNumberDecimalPlaces = configuration.value( u"decimals"_s, 6 ).toInt();
175 mShowThousandsSeparator = configuration.value( u"show_thousand_separator"_s, true ).toBool();
176 mShowPlusSign = configuration.value( u"show_plus"_s, false ).toBool();
177 mShowTrailingZeros = configuration.value( u"show_trailing_zeros"_s, false ).toBool();
178 mRoundingType = static_cast< RoundingType >( configuration.value( u"rounding_type"_s, static_cast< int >( DecimalPlaces ) ).toInt() );
179 mThousandsSeparator = configuration.value( u"thousand_separator"_s, QChar() ).toChar();
180 mDecimalSeparator = configuration.value( u"decimal_separator"_s, QChar() ).toChar();
181}
182
184{
185 return mNumberDecimalPlaces;
186}
187
192
194{
195 return mShowThousandsSeparator;
196}
197
202
204{
205 return mShowPlusSign;
206}
207
209{
210 mShowPlusSign = showPlusSign;
211}
212
214{
215 return mShowTrailingZeros;
216}
217
222
227
232
234{
235 return mThousandsSeparator;
236}
237
239{
240 mThousandsSeparator = character;
241}
242
244{
245 return mDecimalSeparator;
246}
247
249{
250 mDecimalSeparator = character;
251}
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:6900
std::string do_grouping() const override
formatter(QChar thousands, bool showThousands, QChar decimal)