1/*
2 * SPDX-FileCopyrightText: 2009 Petri Damstén <damu@iki.fi>
3 * SPDX-FileCopyrightText: 2014 John Layt <jlayt@kde.org>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8#include "currency_p.h"
9#include "kunitconversion_debug.h"
10#include "unit_p.h"
11#include "unitcategory.h"
12#include <KLocalizedString>
13#include <QDateTime>
14#include <QDir>
15#include <QFileInfo>
16#include <QLocale>
17#include <QNetworkAccessManager>
18#include <QNetworkInterface>
19#include <QNetworkReply>
20#include <QNetworkRequest>
21#include <QSaveFile>
22#include <QStandardPaths>
23#include <QXmlStreamReader>
24
25using namespace std::chrono_literals;
26
27namespace KUnitConversion
28{
29static const char URL[] = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml";
30
31static QString cacheLocation()
32{
33#ifndef Q_OS_ANDROID
34 return QStandardPaths::writableLocation(type: QStandardPaths::GenericDataLocation) + QStringLiteral("/libkunitconversion/currency.xml");
35#else
36 return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/libkunitconversion/currency.xml");
37#endif
38}
39
40class CurrencyCategoryPrivate : public UnitCategoryPrivate
41{
42public:
43 CurrencyCategoryPrivate(CategoryId id, const QString &name, const QString &description)
44 : UnitCategoryPrivate(id, name, description)
45 {
46 }
47
48 Value convert(const Value &value, const Unit &toUnit) override;
49 bool hasOnlineConversionTable() const override;
50 UpdateJob* syncConversionTable(std::chrono::seconds updateSkipSeconds) override;
51
52 QNetworkReply *m_currentReply = nullptr;
53 bool readConversionTable(const QString &cacheLocation);
54 bool m_initialized{false}; //!< indicates if units are prepared from currency table
55};
56
57bool CurrencyCategoryPrivate::hasOnlineConversionTable() const
58{
59 return true;
60}
61
62UnitCategory Currency::makeCategory()
63{
64 auto c = UnitCategoryPrivate::makeCategory(dd: new CurrencyCategoryPrivate(CurrencyCategory, i18n("Currency"), i18n("From ECB")));
65 auto d = UnitCategoryPrivate::get(category: c);
66 KLocalizedString symbolString = ki18nc("%1 value, %2 unit symbol (currency)", "%1 %2");
67
68 // Static rates
69 d->addDefaultUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
70 id: Eur,
71 multiplier: 1.0,
72 QStringLiteral("EUR"),
73 i18nc("currency name", "Euro"),
74 i18nc("EUR Euro - unit synonyms for matching user input", "euro;euros") + QStringLiteral(";EUR;") + QStringLiteral("€")
75 + QLatin1Char(';') + i18nc("currency name", "Euro"),
76 symbolString,
77 ki18nc("amount in units (real)", "%1 euros"),
78 ki18ncp("amount in units (integer)", "%1 euro", "%1 euros")));
79
80 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
81 id: Ats,
82 multiplier: 0.0726728,
83 QStringLiteral("ATS"),
84 i18nc("currency name", "Austrian Schilling"),
85 i18nc("ATS Austrian Schilling - unit synonyms for matching user input", "schilling;schillings") + QStringLiteral(";ATS;")
86 + QLocale::territoryToString(territory: QLocale::Austria) + QLatin1Char(';') + i18nc("currency name", "Austrian Schilling"),
87 symbolString,
88 ki18nc("amount in units (real)", "%1 schillings"),
89 ki18ncp("amount in units (integer)", "%1 schilling", "%1 schillings")));
90
91 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
92 id: Bef,
93 multiplier: 0.0247894,
94 QStringLiteral("BEF"),
95 i18nc("currency name", "Belgian Franc"),
96 i18nc("BEF Belgian Franc - unit synonyms for matching user input", "franc;francs") + QStringLiteral(";BEF;")
97 + QLocale::territoryToString(territory: QLocale::Belgium) + QLatin1Char(';') + i18nc("currency name", "Belgian Franc"),
98 symbolString,
99 ki18nc("amount in units (real)", "%1 Belgian francs"),
100 ki18ncp("amount in units (integer)", "%1 Belgian franc", "%1 Belgian francs")));
101
102 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
103 id: Nlg,
104 multiplier: 0.45378,
105 QStringLiteral("NLG"),
106 i18nc("currency name", "Netherlands Guilder"),
107 i18nc("NLG Netherlands Guilder - unit synonyms for matching user input", "guilder;guilders") + QStringLiteral(";NLG;")
108 + QLocale::territoryToString(territory: QLocale::Netherlands) + QLatin1Char(';') + i18nc("currency name", "Netherlands Guilder"),
109 symbolString,
110 ki18nc("amount in units (real)", "%1 guilders"),
111 ki18ncp("amount in units (integer)", "%1 guilder", "%1 guilders")));
112
113 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
114 id: Fim,
115 multiplier: 0.168188,
116 QStringLiteral("FIM"),
117 i18nc("currency name", "Finnish Markka"),
118 i18nc("FIM Finnish Markka - unit synonyms for matching user input", "markka;markkas;markkaa") + QStringLiteral(";FIM;")
119 + QLocale::territoryToString(territory: QLocale::Finland) + QLatin1Char(';') + i18nc("currency name", "Finnish Markka"),
120 symbolString,
121 ki18nc("amount in units (real)", "%1 markkas"),
122 ki18ncp("amount in units (integer)", "%1 markka", "%1 markkas"))); // Alternative = markkaa
123
124 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
125 id: Frf,
126 multiplier: 0.152449,
127 QStringLiteral("FRF"),
128 i18nc("currency name", "French Franc"),
129 i18nc("FRF French Franc - unit synonyms for matching user input", "franc;francs") + QStringLiteral(";FRF;")
130 + QLocale::territoryToString(territory: QLocale::France) + QLatin1Char(';') + i18nc("currency name", "French Franc"),
131 symbolString,
132 ki18nc("amount in units (real)", "%1 French francs"),
133 ki18ncp("amount in units (integer)", "%1 French franc", "%1 French francs")));
134
135 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
136 id: Dem,
137 multiplier: 0.511292,
138 QStringLiteral("DEM"),
139 i18nc("currency name", "German Mark"),
140 i18nc("DEM German Mark - unit synonyms for matching user input", "mark;marks") + QStringLiteral(";DEM;")
141 + QLocale::territoryToString(territory: QLocale::Germany) + QLatin1Char(';') + i18nc("currency name", "German Mark"),
142 symbolString,
143 ki18nc("amount in units (real)", "%1 marks"),
144 ki18ncp("amount in units (integer)", "%1 mark", "%1 marks")));
145
146 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
147 id: Iep,
148 multiplier: 1.26974,
149 QStringLiteral("IEP"),
150 i18nc("currency name", "Irish Pound"),
151 i18nc("IEP Irish Pound - unit synonyms for matching user input", "Irish pound;Irish pounds") + QStringLiteral(";IEP;")
152 + QLocale::territoryToString(territory: QLocale::Ireland) + QLatin1Char(';') + i18nc("currency name", "Irish Pound"),
153 symbolString,
154 ki18nc("amount in units (real)", "%1 Irish pounds"),
155 ki18ncp("amount in units (integer)", "%1 Irish pound", "%1 Irish pounds")));
156
157 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
158 id: Itl,
159 multiplier: 0.000516457,
160 QStringLiteral("ITL"),
161 i18nc("currency name", "Italian Lira"),
162 i18nc("ITL Italian Lira - unit synonyms for matching user input", "lira;liras") + QStringLiteral(";ITL;")
163 + QLocale::territoryToString(territory: QLocale::Italy) + QLatin1Char(';') + i18nc("currency name", "Italian Lira"),
164 symbolString,
165 ki18nc("amount in units (real)", "%1 Italian lira"),
166 ki18ncp("amount in units (integer)", "%1 Italian lira", "%1 Italian lira")));
167
168 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
169 id: Luf,
170 multiplier: 0.0247894,
171 QStringLiteral("LUF"),
172 i18nc("currency name", "Luxembourgish Franc"),
173 i18nc("LUF Luxembourgish Franc - unit synonyms for matching user input", "franc;francs") + QStringLiteral(";LUF;")
174 + QLocale::territoryToString(territory: QLocale::Luxembourg) + QLatin1Char(';') + i18nc("currency name", "Luxembourgish Franc"),
175 symbolString,
176 ki18nc("amount in units (real)", "%1 Luxembourgish francs"),
177 ki18ncp("amount in units (integer)", "%1 Luxembourgish franc", "%1 Luxembourgish francs")));
178
179 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
180 id: Pte,
181 multiplier: 0.00498798,
182 QStringLiteral("PTE"),
183 i18nc("currency name", "Portuguese Escudo"),
184 i18nc("PTE Portuguese Escudo - unit synonyms for matching user input", "escudo;escudos") + QStringLiteral(";PTE;")
185 + QLocale::territoryToString(territory: QLocale::Portugal) + QLatin1Char(';') + i18nc("currency name", "Portuguese Escudo"),
186 symbolString,
187 ki18nc("amount in units (real)", "%1 escudos"),
188 ki18ncp("amount in units (integer)", "%1 escudo", "%1 escudos")));
189
190 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
191 id: Esp,
192 multiplier: 0.00601012,
193 QStringLiteral("ESP"),
194 i18nc("currency name", "Spanish Peseta"),
195 i18nc("ESP Spanish Peseta - unit synonyms for matching user input", "peseta;pesetas") + QStringLiteral(";ESP;")
196 + QLocale::territoryToString(territory: QLocale::Spain) + QLatin1Char(';') + i18nc("currency name", "Spanish Peseta"),
197 symbolString,
198 ki18nc("amount in units (real)", "%1 pesetas"),
199 ki18ncp("amount in units (integer)", "%1 peseta", "%1 pesetas")));
200
201 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
202 id: Grd,
203 multiplier: 0.0029347,
204 QStringLiteral("GRD"),
205 i18nc("currency name", "Greek Drachma"),
206 i18nc("GRD Greek Drachma - unit synonyms for matching user input", "drachma;drachmas") + QStringLiteral(";GRD;")
207 + QLocale::territoryToString(territory: QLocale::Greece) + QLatin1Char(';') + i18nc("currency name", "Greek Drachma"),
208 symbolString,
209 ki18nc("amount in units (real)", "%1 drachmas"),
210 ki18ncp("amount in units (integer)", "%1 drachma", "%1 drachmas")));
211
212 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
213 id: Sit,
214 multiplier: 0.00417293,
215 QStringLiteral("SIT"),
216 i18nc("currency name", "Slovenian Tolar"),
217 i18nc("SIT Slovenian Tolar - unit synonyms for matching user input", "tolar;tolars;tolarjev") + QStringLiteral(";SIT;")
218 + QLocale::territoryToString(territory: QLocale::Slovenia) + QLatin1Char(';') + i18nc("currency name", "Slovenian Tolar"),
219 symbolString,
220 ki18nc("amount in units (real)", "%1 tolars"),
221 ki18ncp("amount in units (integer)", "%1 tolar", "%1 tolars"))); // Alt: tolarjev/tolarja/tolarji
222
223 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
224 id: Cyp,
225 multiplier: 1.7086,
226 QStringLiteral("CYP"),
227 i18nc("currency name", "Cypriot Pound"),
228 i18nc("CYP Cypriot Pound - unit synonyms for matching user input", "Cypriot pound;Cypriot pounds") + QStringLiteral(";CYP;")
229 + QLocale::territoryToString(territory: QLocale::Cyprus) + QLatin1Char(';') + i18nc("currency name", "Cypriot Pound"),
230 symbolString,
231 ki18nc("amount in units (real)", "%1 Cypriot pounds"),
232 ki18ncp("amount in units (integer)", "%1 Cypriot pound", "%1 Cypriot pounds")));
233
234 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
235 id: Mtl,
236 multiplier: 2.32937,
237 QStringLiteral("MTL"),
238 i18nc("currency name", "Maltese Lira"),
239 i18nc("MTL Maltese Lira - unit synonyms for matching user input", "Maltese lira") + QStringLiteral(";MTL;")
240 + QLocale::territoryToString(territory: QLocale::Malta) + QLatin1Char(';') + i18nc("currency name", "Maltese Lira"),
241 symbolString,
242 ki18nc("amount in units (real)", "%1 Maltese lira"),
243 ki18ncp("amount in units (integer)", "%1 Maltese lira", "%1 Maltese lira")));
244
245 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
246 id: Skk,
247 multiplier: 0.0331939,
248 QStringLiteral("SKK"),
249 i18nc("currency name", "Slovak Koruna"),
250 i18nc("SKK Slovak Koruna - unit synonyms for matching user input", "koruna;korunas;koruny;korun") + QStringLiteral(";SKK;")
251 + QLocale::territoryToString(territory: QLocale::Slovakia) + QLatin1Char(';') + i18nc("currency name", "Slovak Koruna"),
252 symbolString,
253 ki18nc("amount in units (real)", "%1 Slovak korunas"),
254 ki18ncp("amount in units (integer)", "%1 Slovak koruna", "%1 Slovak korunas"))); // Alt: koruny, korun
255
256 // From ECB
257 d->addCommonUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
258 id: Usd,
259 multiplier: qSNaN(),
260 QStringLiteral("USD"),
261 i18nc("currency name", "United States Dollar"),
262 i18nc("USD United States Dollar - unit synonyms for matching user input", "dollar;dollars") + QStringLiteral(";USD;$;")
263 + QLocale::territoryToString(territory: QLocale::UnitedStates) + QLatin1Char(';') + i18nc("currency name", "United States Dollar"),
264 symbolString,
265 ki18nc("amount in units (real)", "%1 United States dollars"),
266 ki18ncp("amount in units (integer)", "%1 United States dollar", "%1 United States dollars")));
267
268 d->addCommonUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
269 id: Jpy,
270 multiplier: qSNaN(),
271 QStringLiteral("JPY"),
272 i18nc("currency name", "Japanese Yen"),
273 i18nc("JPY Japanese Yen - unit synonyms for matching user input", "yen") + QStringLiteral(";JPY;") + QStringLiteral("¥")
274 + QLatin1Char(';') + QLocale::territoryToString(territory: QLocale::Japan) + QLatin1Char(';') + i18nc("currency name", "Japanese Yen"),
275 symbolString,
276 ki18nc("amount in units (real)", "%1 yen"),
277 ki18ncp("amount in units (integer)", "%1 yen", "%1 yen")));
278
279 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
280 id: Bgn,
281 multiplier: qSNaN(),
282 QStringLiteral("BGN"),
283 i18nc("currency name", "Bulgarian Lev"),
284 i18nc("BGN Bulgarian Lev - unit synonyms for matching user input", "lev;leva") + QStringLiteral(";BGN;")
285 + QLocale::territoryToString(territory: QLocale::Bulgaria) + QLatin1Char(';') + i18nc("currency name", "Bulgarian Lev"),
286 symbolString,
287 ki18nc("amount in units (real)", "%1 leva"),
288 ki18ncp("amount in units (integer)", "%1 lev", "%1 leva")));
289
290 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
291 id: Czk,
292 multiplier: qSNaN(),
293 QStringLiteral("CZK"),
294 i18nc("currency name", "Czech Koruna"),
295 i18nc("CZK Czech Koruna - unit synonyms for matching user input", "koruna;korunas") + QStringLiteral(";CZK;")
296 + QLocale::territoryToString(territory: QLocale::CzechRepublic) + QLatin1Char(';') + i18nc("currency name", "Czech Koruna"),
297 symbolString,
298 ki18nc("amount in units (real)", "%1 Czech korunas"),
299 // Alt: koruny, korun
300 ki18ncp("amount in units (integer)", "%1 Czech koruna", "%1 Czech korunas")));
301
302 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
303 id: Dkk,
304 multiplier: qSNaN(),
305 QStringLiteral("DKK"),
306 i18nc("currency name", "Danish Krone"),
307 i18nc("DKK Danish Krone - unit synonyms for matching user input", "Danish krone;Danish kroner") + QStringLiteral(";DKK;")
308 + QLocale::territoryToString(territory: QLocale::Denmark) + QLatin1Char(';') + i18nc("currency name", "Danish Krone"),
309 symbolString,
310 ki18nc("amount in units (real)", "%1 Danish kroner"),
311 ki18ncp("amount in units (integer)", "%1 Danish krone", "%1 Danish kroner")));
312
313 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
314 id: Eek,
315 multiplier: qSNaN(),
316 QStringLiteral("EEK"),
317 i18nc("currency name", "Estonian Kroon"),
318 i18nc("EEK Estonian Kroon - unit synonyms for matching user input", "kroon;kroons;krooni") + QStringLiteral(";EEK;")
319 + QLocale::territoryToString(territory: QLocale::Estonia) + QLatin1Char(';') + i18nc("currency name", "Estonian Kroon"),
320 symbolString,
321 ki18nc("amount in units (real)", "%1 kroons"),
322 ki18ncp("amount in units (integer)", "%1 kroon", "%1 kroons"))); // Alt: krooni
323
324 d->addCommonUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
325 id: Gbp,
326 multiplier: qSNaN(),
327 QStringLiteral("GBP"),
328 i18nc("currency name", "British Pound"),
329 i18nc("GBP British Pound - unit synonyms for matching user input", "pound;pounds;pound sterling;pounds sterling")
330 + QStringLiteral(";GBP;") + QStringLiteral("£") + QLatin1Char(';') + QLocale::territoryToString(territory: QLocale::UnitedKingdom)
331 + QLatin1Char(';') + i18nc("currency name", "British Pound"),
332 symbolString,
333 ki18nc("amount in units (real)", "%1 pounds sterling"),
334 ki18ncp("amount in units (integer)", "%1 pound sterling", "%1 pounds sterling")));
335
336 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
337 id: Huf,
338 multiplier: qSNaN(),
339 QStringLiteral("HUF"),
340 i18nc("currency name", "Hungarian Forint"),
341 i18nc("HUF hungarian Forint - unit synonyms for matching user input", "forint") + QStringLiteral(";HUF;")
342 + QLocale::territoryToString(territory: QLocale::Hungary) + QLatin1Char(';') + i18nc("currency name", "Hungarian Forint"),
343 symbolString,
344 ki18nc("amount in units (real)", "%1 forint"),
345 ki18ncp("amount in units (integer)", "%1 forint", "%1 forint")));
346
347 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
348 id: Ils,
349 multiplier: qSNaN(),
350 QStringLiteral("ILS"),
351 i18nc("currency name", "Israeli New Shekel"),
352 i18nc("ILS Israeli New Shekel - unit synonyms for matching user input", "shekel;shekels;sheqel;sheqels;sheqalim")
353 + QStringLiteral(";ILS;") + QLocale::territoryToString(territory: QLocale::Israel) + QLatin1Char(';')
354 + i18nc("currency name", "Israeli New Shekel"),
355 symbolString,
356 ki18nc("amount in units (real)", "%1 shekels"),
357 ki18ncp("amount in units (integer)", "%1 shekel", "%1 shekels")));
358
359 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
360 id: Ltl,
361 multiplier: qSNaN(),
362 QStringLiteral("LTL"),
363 i18nc("currency name", "Lithuanian Litas"),
364 i18nc("LTL Lithuanian Litas - unit synonyms for matching user input", "litas;litai;litu") + QStringLiteral(";LTL;")
365 + QLocale::territoryToString(territory: QLocale::Lithuania) + QLatin1Char(';') + i18nc("currency name", "Lithuanian Litas"),
366 symbolString,
367 ki18nc("amount in units (real)", "%1 litas"),
368 ki18ncp("amount in units (integer)", "%1 litas", "%1 litai"))); // Alt: litu
369
370 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
371 id: Lvl,
372 multiplier: qSNaN(),
373 QStringLiteral("LVL"),
374 i18nc("currency name", "Latvian Lats"),
375 i18nc("LVL Latvian Lats - unit synonyms for matching user input", "lats;lati") + QStringLiteral(";LVL;")
376 + QLocale::territoryToString(territory: QLocale::Latvia) + QLatin1Char(';') + i18nc("currency name", "Latvian Lats"),
377 symbolString,
378 ki18nc("amount in units (real)", "%1 lati"),
379 ki18ncp("amount in units (integer)", "%1 lats", "%1 lati")));
380
381 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
382 id: Pln,
383 multiplier: qSNaN(),
384 QStringLiteral("PLN"),
385 i18nc("currency name", "Polish Zloty"),
386 i18nc("PLN Polish Zloty - unit synonyms for matching user input", "zloty;zlotys;zloties") + QStringLiteral(";PLN;")
387 + QLocale::territoryToString(territory: QLocale::Poland) + QLatin1Char(';') + i18nc("currency name", "Polish Zloty"),
388 symbolString,
389 ki18nc("amount in units (real)", "%1 zlotys"),
390 ki18ncp("amount in units (integer)", "%1 zloty", "%1 zlotys"))); // Alt: zloty, zlote, zlotych
391
392 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
393 id: Ron,
394 multiplier: qSNaN(),
395 QStringLiteral("RON"),
396 i18nc("currency name", "Romanian Leu"),
397 i18nc("RON Romanian Leu - unit synonyms for matching user input", "leu;lei") + QStringLiteral(";RON;")
398 + QLocale::territoryToString(territory: QLocale::Romania) + QLatin1Char(';') + i18nc("currency name", "Romanian Leu"),
399 symbolString,
400 ki18nc("amount in units (real)", "%1 lei"),
401 ki18ncp("amount in units (integer)", "%1 leu", "%1 lei")));
402
403 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
404 id: Sek,
405 multiplier: qSNaN(),
406 QStringLiteral("SEK"),
407 i18nc("currency name", "Swedish Krona"),
408 i18nc("SEK Swedish Krona - unit synonyms for matching user input", "krona;kronor") + QStringLiteral(";SEK;")
409 + QLocale::territoryToString(territory: QLocale::Sweden) + QLatin1Char(';') + i18nc("currency name", "Swedish Krona"),
410 symbolString,
411 ki18nc("amount in units (real)", "%1 kronor"),
412 ki18ncp("amount in units (integer)", "%1 krona", "%1 kronor")));
413
414 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
415 id: Chf,
416 multiplier: qSNaN(),
417 QStringLiteral("CHF"),
418 i18nc("currency name", "Swiss Franc"),
419 i18nc("CHF Swiss Franc - unit synonyms for matching user input", "franc;francs") + QStringLiteral(";CHF;")
420 + QLocale::territoryToString(territory: QLocale::Switzerland) + QLatin1Char(';') + i18nc("currency name", "Swiss Franc"),
421 symbolString,
422 ki18nc("amount in units (real)", "%1 Swiss francs"),
423 ki18ncp("amount in units (integer)", "%1 Swiss franc", "%1 Swiss francs")));
424
425 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
426 id: Nok,
427 multiplier: qSNaN(),
428 QStringLiteral("NOK"),
429 i18nc("currency name", "Norwegian Krone"),
430 i18nc("Norwegian Krone - unit synonyms for matching user input", "Norwegian krone;Norwegian kroner") + QStringLiteral(";NOK;")
431 + QLocale::territoryToString(territory: QLocale::Norway) + QLatin1Char(';') + i18nc("currency name", "Norwegian Krone"),
432 symbolString,
433 ki18nc("amount in units (real)", "%1 Norwegian kroner"),
434 ki18ncp("amount in units (integer)", "%1 Norwegian krone", "%1 Norwegian kroner")));
435
436 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
437 id: Hrk,
438 multiplier: 1.0/7.53450,
439 QStringLiteral("HRK"),
440 i18nc("currency name", "Croatian Kuna"),
441 i18nc("HRK Croatian Kuna - unit synonyms for matching user input", "kuna;kune") + QStringLiteral(";HRK;")
442 + QLocale::territoryToString(territory: QLocale::Croatia) + QLatin1Char(';') + i18nc("currency name", "Croatian Kuna"),
443 symbolString,
444 ki18nc("amount in units (real)", "%1 kune"),
445 ki18ncp("amount in units (integer)", "%1 kuna", "%1 kune")));
446
447 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
448 id: Rub,
449 multiplier: qSNaN(),
450 QStringLiteral("RUB"),
451 i18nc("currency name", "Russian Ruble"),
452 i18nc("RUB Russian Ruble - unit synonyms for matching user input", "ruble;rubles;rouble;roubles") + QStringLiteral(";RUB;")
453 + QLocale::territoryToString(territory: QLocale::Russia) + QLatin1Char(';') + i18nc("currency name", "Russian Ruble"),
454 symbolString,
455 ki18nc("amount in units (real)", "%1 rubles"),
456 ki18ncp("amount in units (integer)", "%1 ruble", "%1 rubles"))); // Alt: rouble/roubles
457
458 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
459 id: Try,
460 multiplier: qSNaN(),
461 QStringLiteral("TRY"),
462 i18nc("currency name", "Turkish Lira"),
463 i18nc("TRY Turkish Lira - unit synonyms for matching user input", "lira") + QStringLiteral(";TRY;")
464 + QLocale::territoryToString(territory: QLocale::Turkey) + QLatin1Char(';') + i18nc("currency name", "Turkish Lira"),
465 symbolString,
466 ki18nc("amount in units (real)", "%1 Turkish lira"),
467 ki18ncp("amount in units (integer)", "%1 Turkish lira", "%1 Turkish lira")));
468
469 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
470 id: Aud,
471 multiplier: qSNaN(),
472 QStringLiteral("AUD"),
473 i18nc("currency name", "Australian Dollar"),
474 i18nc("AUD Australian Dollar - unit synonyms for matching user input", "Australian dollar;Australian dollars") + QStringLiteral(";AUD;")
475 + QLocale::territoryToString(territory: QLocale::Australia) + QLatin1Char(';') + i18nc("currency name", "Australian Dollar"),
476 symbolString,
477 ki18nc("amount in units (real)", "%1 Australian dollars"),
478 ki18ncp("amount in units (integer)", "%1 Australian dollar", "%1 Australian dollars")));
479
480 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
481 id: Brl,
482 multiplier: qSNaN(),
483 QStringLiteral("BRL"),
484 i18nc("currency name", "Brazilian Real"),
485 i18nc("BRL Brazilian Real - unit synonyms for matching user input", "real;reais") + QStringLiteral(";BRL;")
486 + QLocale::territoryToString(territory: QLocale::Brazil) + QLatin1Char(';') + i18nc("currency name", "Brazilian Real"),
487 symbolString,
488 ki18nc("amount in units (real)", "%1 reais"),
489 ki18ncp("amount in units (integer)", "%1 real", "%1 reais")));
490
491 d->addCommonUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
492 id: Cad,
493 multiplier: qSNaN(),
494 QStringLiteral("CAD"),
495 i18nc("currency name", "Canadian Dollar"),
496 i18nc("Canadian Dollar - unit synonyms for matching user input", "Canadian dollar;Canadian dollars") + QStringLiteral(";CAD;")
497 + QLocale::territoryToString(territory: QLocale::Canada) + QLatin1Char(';') + i18nc("currency name", "Canadian Dollar"),
498 symbolString,
499 ki18nc("amount in units (real)", "%1 Canadian dollars"),
500 ki18ncp("amount in units (integer)", "%1 Canadian dollar", "%1 Canadian dollars")));
501
502 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
503 id: Cny,
504 multiplier: qSNaN(),
505 QStringLiteral("CNY"),
506 i18nc("currency name", "Chinese Yuan"),
507 i18nc("Chinese Yuan - unit synonyms for matching user input", "yuan") + QStringLiteral(";CNY;")
508 + QLocale::territoryToString(territory: QLocale::China) + QLatin1Char(';') + i18nc("currency name", "Chinese Yuan"),
509 symbolString,
510 ki18nc("amount in units (real)", "%1 yuan"),
511 ki18ncp("amount in units (integer)", "%1 yuan", "%1 yuan")));
512
513 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
514 id: Hkd,
515 multiplier: qSNaN(),
516 QStringLiteral("HKD"),
517 i18nc("currency name", "Hong Kong Dollar"),
518 i18nc("Hong Kong Dollar - unit synonyms for matching user input", "Hong Kong dollar;Hong Kong dollars") + QStringLiteral(";HKD;")
519 + QLocale::territoryToString(territory: QLocale::HongKong) + QLatin1Char(';') + i18nc("currency name", "Hong Kong Dollar"),
520 symbolString,
521 ki18nc("amount in units (real)", "%1 Hong Kong dollars"),
522 ki18ncp("amount in units (integer)", "%1 Hong Kong dollar", "%1 Hong Kong dollars")));
523
524 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
525 id: Idr,
526 multiplier: qSNaN(),
527 QStringLiteral("IDR"),
528 i18nc("currency name", "Indonesian Rupiah"),
529 i18nc("IDR Indonesian Rupiah - unit synonyms for matching user input", "rupiah;rupiahs") + QStringLiteral(";IDR;")
530 + QLocale::territoryToString(territory: QLocale::Indonesia) + QLatin1Char(';') + i18nc("currency name", "Indonesian Rupiah"),
531 symbolString,
532 ki18nc("amount in units (real)", "%1 rupiahs"),
533 ki18ncp("amount in units (integer)", "%1 rupiah", "%1 rupiahs"))); // Alt: rupiah
534
535 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
536 id: Inr,
537 multiplier: qSNaN(),
538 QStringLiteral("INR"),
539 i18nc("currency name", "Indian Rupee"),
540 i18nc("INR Indian Rupee - unit synonyms for matching user input", "rupee;rupees") + QStringLiteral(";INR;")
541 + QLocale::territoryToString(territory: QLocale::India) + QLatin1Char(';') + i18nc("currency name", "Indian Rupee"),
542 symbolString,
543 ki18nc("amount in units (real)", "%1 rupees"),
544 ki18ncp("amount in units (integer)", "%1 rupee", "%1 rupees"))); // Alt: rupee
545
546 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
547 id: Krw,
548 multiplier: qSNaN(),
549 QStringLiteral("KRW"),
550 i18nc("currency name", "Korean Won"),
551 i18nc("KRW Korean Won - unit synonyms for matching user input", "won") + QStringLiteral(";KRW;")
552 + QLocale::territoryToString(territory: QLocale::SouthKorea) + QLatin1Char(';') + i18nc("currency name", "Korean Won"),
553 symbolString,
554 ki18nc("amount in units (real)", "%1 won"),
555 ki18ncp("amount in units (integer)", "%1 won", "%1 won")));
556
557 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
558 id: Mxn,
559 multiplier: qSNaN(),
560 QStringLiteral("MXN"),
561 i18nc("currency name", "Mexican Peso"),
562 i18nc("MXN Mexican Peso - unit synonyms for matching user input", "Mexican peso;Mexican pesos") + QStringLiteral(";MXN;")
563 + QLocale::territoryToString(territory: QLocale::Mexico) + QLatin1Char(';') + i18nc("currency name", "Mexican Peso"),
564 symbolString,
565 ki18nc("amount in units (real)", "%1 Mexican pesos"),
566 ki18ncp("amount in units (integer)", "%1 Mexican peso", "%1 Mexican pesos")));
567
568 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
569 id: Myr,
570 multiplier: qSNaN(),
571 QStringLiteral("MYR"),
572 i18nc("currency name", "Malaysian Ringgit"),
573 i18nc("MYR Malaysian Ringgit - unit synonyms for matching user input", "ringgit;ringgits") + QStringLiteral(";MYR;")
574 + QLocale::territoryToString(territory: QLocale::Malaysia) + QLatin1Char(';') + i18nc("currency name", "Malaysian Ringgit"),
575 symbolString,
576 ki18nc("amount in units (real)", "%1 ringgit"),
577 ki18ncp("amount in units (integer)", "%1 ringgit", "%1 ringgit"))); // Alt: ringgits
578
579 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
580 id: Nzd,
581 multiplier: qSNaN(),
582 QStringLiteral("NZD"),
583 i18nc("currency name", "New Zealand Dollar"),
584 i18nc("NZD New Zealand Dollar - unit synonyms for matching user input", "New Zealand dollar;New Zealand dollars")
585 + QStringLiteral(";NZD;") + QLocale::territoryToString(territory: QLocale::NewZealand) + QLatin1Char(';')
586 + i18nc("currency name", "New Zealand Dollar"),
587 symbolString,
588 ki18nc("amount in units (real)", "%1 New Zealand dollars"),
589 ki18ncp("amount in units (integer)", "%1 New Zealand dollar", "%1 New Zealand dollars")));
590
591 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
592 id: Php,
593 multiplier: qSNaN(),
594 QStringLiteral("PHP"),
595 i18nc("currency name", "Philippine Peso"),
596 i18nc("PHP Philippine Peso - unit synonyms for matching user input", "Philippine peso;Philippine pesos") + QStringLiteral(";PHP;")
597 + QLocale::territoryToString(territory: QLocale::Philippines) + QLatin1Char(';') + i18nc("currency name", "Philippine Peso"),
598 symbolString,
599 ki18nc("amount in units (real)", "%1 Philippine pesos"),
600 ki18ncp("amount in units (integer)", "%1 Philippine peso", "%1 Philippine pesos")));
601
602 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
603 id: Sgd,
604 multiplier: qSNaN(),
605 QStringLiteral("SGD"),
606 i18nc("currency name", "Singapore Dollar"),
607 i18nc("SGD Singapore Dollar - unit synonyms for matching user input", "Singapore dollar;Singapore dollars") + QStringLiteral(";SGD;")
608 + QLocale::territoryToString(territory: QLocale::Singapore) + QLatin1Char(';') + i18nc("currency name", "Singapore Dollar"),
609 symbolString,
610 ki18nc("amount in units (real)", "%1 Singapore dollars"),
611 ki18ncp("amount in units (integer)", "%1 Singapore dollar", "%1 Singapore dollars")));
612
613 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
614 id: Thb,
615 multiplier: qSNaN(),
616 QStringLiteral("THB"),
617 i18nc("currency name", "Thai Baht"),
618 i18nc("THB Thai Baht - unit synonyms for matching user input", "baht") + QStringLiteral(";THB;")
619 + QLocale::territoryToString(territory: QLocale::Thailand) + QLatin1Char(';') + i18nc("currency name", "Thai Baht"),
620 symbolString,
621 ki18nc("amount in units (real)", "%1 baht"),
622 ki18ncp("amount in units (integer)", "%1 baht", "%1 baht")));
623
624 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
625 id: Zar,
626 multiplier: qSNaN(),
627 QStringLiteral("ZAR"),
628 i18nc("currency name", "South African Rand"),
629 i18nc("South African Rand - unit synonyms for matching user input", "rand") + QStringLiteral(";ZAR;")
630 + QLocale::territoryToString(territory: QLocale::SouthAfrica) + QLatin1Char(';') + i18nc("currency name", "South African Rand"),
631 symbolString,
632 ki18nc("amount in units (real)", "%1 rand"),
633 ki18ncp("amount in units (integer)", "%1 rand", "%1 rand")));
634 d->addUnit(unit: UnitPrivate::makeUnit(categoryId: CurrencyCategory,
635 id: Isk,
636 multiplier: qSNaN(),
637 QStringLiteral("ISK"),
638 i18nc("currency name", "Icelandic Krona"),
639 i18nc("Icelandic Krona - unit synonyms for matching user input", "Icelandic krona;Icelandic crown") + QStringLiteral(";ISK;")
640 + QLocale::territoryToString(territory: QLocale::Iceland) + QLatin1Char(';') + i18nc("currency name", "Icelandic Krona"),
641 symbolString,
642 ki18nc("amount in units (real)", "%1 Icelandic kronar"),
643 ki18ncp("amount in units (integer)", "%1 Icelandic krona", "%1 Icelandic kronar")));
644
645 return c;
646}
647
648static bool isConnected()
649{
650 // don't download currencies in autotests
651 if (qEnvironmentVariableIsSet(varName: "KF5UNITCONVERT_NO_DOWNLOAD")) {
652 return false;
653 }
654 bool ret = false;
655 const auto listInterface = QNetworkInterface::allInterfaces();
656 for (const QNetworkInterface &net : listInterface) {
657 if (net.flags().testFlag(flag: QNetworkInterface::IsUp) && !net.flags().testFlag(flag: QNetworkInterface::IsLoopBack)) {
658 ret = true;
659 break;
660 }
661 }
662 return ret;
663}
664
665QDateTime Currency::lastConversionTableUpdate()
666{
667 QFileInfo info(cacheLocation());
668 if (!info.exists()) {
669 qCDebug(LOG_KUNITCONVERSION) << "No cache file available:" << cacheLocation();
670 return QDateTime();
671 } else {
672 return info.lastModified();
673 }
674}
675
676UpdateJob* CurrencyCategoryPrivate::syncConversionTable(std::chrono::seconds updateSkipPeriod)
677{
678 QFileInfo info(cacheLocation());
679 if (info.exists() && info.lastModified().secsTo(QDateTime::currentDateTime()) <= updateSkipPeriod.count()) {
680 return nullptr; // already present and up to date
681 }
682 if (!isConnected()) {
683 qCInfo(LOG_KUNITCONVERSION) << "currency conversion table update has no network connection, abort update";
684 return nullptr;
685 }
686 if (m_currentReply) {
687 return makeUpdateJob(reply: m_currentReply);
688 }
689
690 qCDebug(LOG_KUNITCONVERSION) << "currency conversion table sync started";
691 m_currentReply = nam()->get(request: QNetworkRequest(QUrl(QString::fromLatin1(ba: URL))));
692 QObject::connect(sender: m_currentReply, signal: &QNetworkReply::finished, slot: [this] {
693 auto reply = m_currentReply;
694 m_currentReply = nullptr;
695 reply->deleteLater();
696 if (reply->error()) {
697 qCWarning(LOG_KUNITCONVERSION) << "currency conversion table network error" << reply->errorString();
698 return;
699 }
700 const auto cachePath = cacheLocation();
701 QFileInfo info(cachePath);
702 const QString cacheDir = info.absolutePath();
703 if (!QFileInfo::exists(file: cacheDir)) {
704 QDir().mkpath(dirPath: cacheDir);
705 }
706
707 QSaveFile cacheFile(cachePath);
708 if (!cacheFile.open(flags: QFile::WriteOnly)) {
709 qCCritical(LOG_KUNITCONVERSION) << cacheFile.errorString();
710 return;
711 }
712 cacheFile.write(data: reply->readAll());
713 if (!cacheFile.commit()) {
714 qCCritical(LOG_KUNITCONVERSION) << cacheFile.errorString();
715 return;
716 }
717 qCInfo(LOG_KUNITCONVERSION) << "currency conversion table data obtained via network";
718 m_initialized = readConversionTable(cacheLocation: cachePath);
719 });
720
721 return makeUpdateJob(reply: m_currentReply);
722}
723
724bool CurrencyCategoryPrivate::readConversionTable(const QString &cachePath)
725{
726 QFile file(cachePath);
727 if (!file.open(flags: QIODevice::ReadOnly)) {
728 return false;
729 }
730 QXmlStreamReader xml(&file);
731 while (!xml.atEnd()) {
732 xml.readNext();
733
734 if (xml.isStartElement() && xml.name() == QLatin1String("Cube")) {
735 const auto attributes = xml.attributes();
736 if (attributes.hasAttribute(qualifiedName: QLatin1String("currency"))) {
737 Unit unit = m_unitMap.value(key: attributes.value(qualifiedName: QLatin1String("currency")).toString());
738 if (unit.isValid()) {
739 const auto multiplier = attributes.value(qualifiedName: QLatin1String("rate")).toDouble();
740 if (!qFuzzyIsNull(d: multiplier)) {
741 unit.setUnitMultiplier(1.0 / multiplier);
742 qCDebug(LOG_KUNITCONVERSION()) << "currency updated:" << unit.description() << multiplier;
743 }
744 }
745 }
746 }
747 }
748
749 if (xml.hasError()) {
750 qCCritical(LOG_KUNITCONVERSION) << "currency conversion fetch could not parse obtained XML, update aborted";
751 return false;
752 }
753 return true;
754}
755
756Value CurrencyCategoryPrivate::convert(const Value &value, const Unit &to)
757{
758 if (!m_initialized) {
759 m_initialized = readConversionTable(cachePath: cacheLocation());
760 }
761
762 Value v = UnitCategoryPrivate::convert(value, toUnit: to);
763 return v;
764}
765
766} // KUnitConversion namespace
767

source code of kunitconversion/src/currency.cpp