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