QGIS API Documentation 3.99.0-Master (752b475928d)
Loading...
Searching...
No Matches
qgsfractionnumericformat.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsfractionnumericformat.cpp
3 ----------------------------
4 begin : March 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#include <sstream>
24
25#include "qgis.h"
26
27#include <QString>
28
30
31struct formatter : std::numpunct<wchar_t>
32{
33 formatter( QChar thousands, bool showThousands, QChar decimal )
34 : mThousands( thousands.unicode() )
35 , mDecimal( decimal.unicode() )
36 , mShowThousands( showThousands )
37 {}
38 wchar_t do_decimal_point() const override { return mDecimal; }
39 wchar_t do_thousands_sep() const override { return mThousands; }
40 std::string do_grouping() const override { return mShowThousands ? "\3" : "\0"; }
41
42 wchar_t mThousands;
43 wchar_t mDecimal;
44 bool mShowThousands = true;
45};
47
51
53{
54 return QStringLiteral( "fraction" );
55}
56
58{
59 return QObject::tr( "Fraction" );
60}
61
63{
64 return 100;
65}
66
67QString QgsFractionNumericFormat::formatDouble( double value, const QgsNumericFormatContext &context ) const
68{
69 std::basic_stringstream<wchar_t> os;
70 os.imbue( std::locale( os.getloc(), new formatter( mThousandsSeparator.isNull() ? context.thousandsSeparator() : mThousandsSeparator,
71 mShowThousandsSeparator,
72 context.decimalSeparator() ) ) );
73
74 unsigned long long num;
75 unsigned long long den;
76 int sign;
77
78 QString res;
79
80 const double fixed = std::floor( std::fabs( value ) );
81 const bool success = doubleToVulgarFraction( std::fabs( value ) - fixed, num, den, sign );
82 if ( success )
83 {
84 if ( mUseDedicatedUnicode && num == 1 && den == 2 )
85 res = QChar( 0xBD ); //½
86 else if ( mUseDedicatedUnicode && num == 1 && den == 3 )
87 res = QChar( 0x2153 ); //⅓
88 else if ( mUseDedicatedUnicode && num == 2 && den == 3 )
89 res = QChar( 0x2154 ); //⅔
90 else if ( mUseDedicatedUnicode && num == 1 && den == 4 )
91 res = QChar( 0xBC ); //¼
92 else if ( mUseDedicatedUnicode && num == 3 && den == 4 )
93 res = QChar( 0xBE ); //¾
94 else if ( mUseDedicatedUnicode && num == 1 && den == 5 )
95 res = QChar( 0x2155 ); //⅕
96 else if ( mUseDedicatedUnicode && num == 2 && den == 5 )
97 res = QChar( 0x2156 ); //⅖
98 else if ( mUseDedicatedUnicode && num == 3 && den == 5 )
99 res = QChar( 0x2157 ); //⅗
100 else if ( mUseDedicatedUnicode && num == 4 && den == 5 )
101 res = QChar( 0x2158 ); //⅘
102 else if ( mUseDedicatedUnicode && num == 1 && den == 6 )
103 res = QChar( 0x2159 ); //⅙
104 else if ( mUseDedicatedUnicode && num == 5 && den == 6 )
105 res = QChar( 0x215A ); //⅚
106 else if ( mUseDedicatedUnicode && num == 1 && den == 7 )
107 res = QChar( 0x2150 ); //⅐
108 else if ( mUseDedicatedUnicode && num == 1 && den == 8 )
109 res = QChar( 0x215B ); //⅛
110 else if ( mUseDedicatedUnicode && num == 3 && den == 8 )
111 res = QChar( 0x215C ); //⅜
112 else if ( mUseDedicatedUnicode && num == 5 && den == 8 )
113 res = QChar( 0x215D ); //⅝
114 else if ( mUseDedicatedUnicode && num == 7 && den == 8 )
115 res = QChar( 0x215E ); //⅞
116 else if ( mUseDedicatedUnicode && num == 1 && den == 9 )
117 res = QChar( 0x2151 ); //⅑
118 else if ( mUseDedicatedUnicode && num == 1 && den == 10 )
119 res = QChar( 0x2152 ); //⅒
120 else if ( mUseUnicodeSuperSubscript )
121 res = num == 0 ? QString() : QStringLiteral( "%1%2%3" ).arg( toUnicodeSuperscript( QString::number( num ) ),
122 QChar( 0x002F ), // "SOLIDUS" character
123 toUnicodeSubscript( QString::number( den ) ) );
124 else
125 res = num == 0 ? QString() : QStringLiteral( "%2/%3" ).arg( num ).arg( den );
126 if ( fixed )
127 {
128 os << std::fixed << std::setprecision( 0 );
129 os << fixed;
130 res.prepend( QString::fromStdWString( os.str() ) + ' ' );
131 res = res.trimmed();
132 }
133 if ( res.isEmpty() )
134 res = QString::number( 0 );
135
136 if ( value < 0 )
137 res.prepend( context.negativeSign() );
138 }
139 else
140 {
141 os << std::fixed << std::setprecision( 10 );
142 os << value;
143 res = QString::fromStdWString( os.str() );
144 }
145
146 if ( value > 0 && mShowPlusSign )
147 {
148 res.prepend( context.positiveSign() );
149 }
150
151 return res;
152}
153
158
160{
161 auto res = std::make_unique< QgsFractionNumericFormat >();
162 res->setConfiguration( configuration, context );
163 return res.release();
164}
165
167{
168 QVariantMap res;
169 res.insert( QStringLiteral( "show_thousand_separator" ), mShowThousandsSeparator );
170 res.insert( QStringLiteral( "show_plus" ), mShowPlusSign );
171 res.insert( QStringLiteral( "thousand_separator" ), mThousandsSeparator.isNull() ? QVariant() : QVariant::fromValue( mThousandsSeparator ) );
172 res.insert( QStringLiteral( "use_dedicated_unicode" ), mUseDedicatedUnicode );
173 res.insert( QStringLiteral( "use_unicode_supersubscript" ), mUseUnicodeSuperSubscript );
174 return res;
175}
176
178{
179 return 1234.75;
180}
181
183{
184 return mUseDedicatedUnicode;
185}
186
188{
189 mUseDedicatedUnicode = enabled;
190}
191
193{
194 return mUseUnicodeSuperSubscript;
195}
196
198{
199 mUseUnicodeSuperSubscript = enabled;
200}
201
203{
204 mShowThousandsSeparator = configuration.value( QStringLiteral( "show_thousand_separator" ), true ).toBool();
205 mShowPlusSign = configuration.value( QStringLiteral( "show_plus" ), false ).toBool();
206 mThousandsSeparator = configuration.value( QStringLiteral( "thousand_separator" ), QChar() ).toChar();
207 mUseDedicatedUnicode = configuration.value( QStringLiteral( "use_dedicated_unicode" ), false ).toBool();
208 mUseUnicodeSuperSubscript = configuration.value( QStringLiteral( "use_unicode_supersubscript" ), true ).toBool();
209}
210
212{
213 return mShowThousandsSeparator;
214}
215
220
222{
223 return mShowPlusSign;
224}
225
227{
228 mShowPlusSign = showPlusSign;
229}
230
232{
233 return mThousandsSeparator;
234}
235
237{
238 mThousandsSeparator = character;
239}
240
242{
243 QString res = input;
244 for ( int i = 0; i < input.size(); ++i )
245 {
246 const QChar c = input.at( i );
247 if ( c == '0' )
248 res[i] = QChar( 0x2070 ); //⁰
249 else if ( c == '1' )
250 res[i] = QChar( 0x00B9 ); //¹
251 else if ( c == '2' )
252 res[i] = QChar( 0x00B2 ); //²
253 else if ( c == '3' )
254 res[i] = QChar( 0x00B3 ); //³
255 else if ( c == '4' )
256 res[i] = QChar( 0x2074 ); //⁴
257 else if ( c == '5' )
258 res[i] = QChar( 0x2075 ); //⁵
259 else if ( c == '6' )
260 res[i] = QChar( 0x2076 ); //⁶
261 else if ( c == '7' )
262 res[i] = QChar( 0x2077 ); //⁷
263 else if ( c == '8' )
264 res[i] = QChar( 0x2078 ); //⁸
265 else if ( c == '9' )
266 res[i] = QChar( 0x2079 ); //⁹
267 }
268 return res;
269}
270
271QString QgsFractionNumericFormat::toUnicodeSubscript( const QString &input )
272{
273 QString res = input;
274 for ( int i = 0; i < input.size(); ++i )
275 {
276 const QChar c = input.at( i );
277 if ( c == '0' )
278 res[i] = QChar( 0x2080 ); //₀
279 else if ( c == '1' )
280 res[i] = QChar( 0x2081 ); //₁
281 else if ( c == '2' )
282 res[i] = QChar( 0x2082 ); //₂
283 else if ( c == '3' )
284 res[i] = QChar( 0x2083 ); //₃
285 else if ( c == '4' )
286 res[i] = QChar( 0x2084 ); //₄
287 else if ( c == '5' )
288 res[i] = QChar( 0x2085 ); //₅
289 else if ( c == '6' )
290 res[i] = QChar( 0x2086 ); //₆
291 else if ( c == '7' )
292 res[i] = QChar( 0x2087 ); //₇
293 else if ( c == '8' )
294 res[i] = QChar( 0x2088 ); //₈
295 else if ( c == '9' )
296 res[i] = QChar( 0x2089 ); //₉
297 }
298 return res;
299}
void setUseUnicodeSuperSubscript(bool enabled)
Sets whether unicode superscript and subscript characters should be used, (e.g.
QString visibleName() const override
Returns the translated, user-visible name for this format.
bool useDedicatedUnicodeCharacters() const
Returns true if dedicated unicode characters should be used, when the are available for the particula...
QgsNumericFormat * create(const QVariantMap &configuration, const QgsReadWriteContext &context) const override
Creates a new copy of the format, using the supplied configuration.
QgsNumericFormat * clone() const override
Clones the format, returning a new object.
static QString toUnicodeSubscript(const QString &input)
Converts numbers in an input string to unicode subscript equivalents.
QChar thousandsSeparator() const
Returns any override for the thousands separator character.
void setUseDedicatedUnicodeCharacters(bool enabled)
Sets whether dedicated unicode characters should be used, when the are available for the particular f...
bool showThousandsSeparator() const
Returns true if the thousands grouping separator will be shown.
bool useUnicodeSuperSubscript() const
Returns true if unicode superscript and subscript characters should be used, (e.g.
bool showPlusSign() const
Returns true if a leading plus sign will be shown for positive values.
void setShowPlusSign(bool show)
Sets whether a leading plus sign will be shown for positive values.
int sortKey() override
Returns a sorting key value, where formats with a lower sort key will be shown earlier in lists.
double suggestSampleValue() const override
Returns a suggested sample value which nicely represents the current format configuration.
void setShowThousandsSeparator(bool show)
Sets whether the thousands grouping separator will be shown.
QString id() const override
Returns a unique id for this numeric format.
QgsFractionNumericFormat()
Default constructor.
static bool doubleToVulgarFraction(const double value, unsigned long long &numerator, unsigned long long &denominator, int &sign, const double tolerance=1e-10)
Converts a double value to a vulgar fraction (e.g.
QString formatDouble(double value, const QgsNumericFormatContext &context) const override
Returns a formatted string representation of a numeric double value.
static QString toUnicodeSuperscript(const QString &input)
Converts numbers in an input string to unicode superscript equivalents.
virtual void setConfiguration(const QVariantMap &configuration, const QgsReadWriteContext &context)
Sets the format's configuration.
QVariantMap configuration(const QgsReadWriteContext &context) const override
Returns the current configuration of the formatter.
void setThousandsSeparator(QChar character)
Sets an override character for the thousands separator character.
A context for numeric formats.
QChar negativeSign() const
Returns the negative sign character.
QChar thousandsSeparator() const
Returns the thousands separator 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.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c