File indexing completed on 2024-04-28 07:47:32

0001 /*
0002  *   SPDX-FileCopyrightText: 2009 Petri Damstén <damu@iki.fi>
0003  *   SPDX-FileCopyrightText: 2014 John Layt <jlayt@kde.org>
0004  *
0005  *   SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "currency_p.h"
0009 #include "kunitconversion_debug.h"
0010 #include "unit_p.h"
0011 #include "unitcategory.h"
0012 #include <KLocalizedString>
0013 #include <QDateTime>
0014 #include <QDir>
0015 #include <QFileInfo>
0016 #include <QLocale>
0017 #include <QNetworkAccessManager>
0018 #include <QNetworkInterface>
0019 #include <QNetworkReply>
0020 #include <QNetworkRequest>
0021 #include <QSaveFile>
0022 #include <QStandardPaths>
0023 #include <QXmlStreamReader>
0024 
0025 using namespace std::chrono_literals;
0026 
0027 namespace KUnitConversion
0028 {
0029 static const char URL[] = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml";
0030 
0031 static QString cacheLocation()
0032 {
0033 #ifndef Q_OS_ANDROID
0034     return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/libkunitconversion/currency.xml");
0035 #else
0036     return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/libkunitconversion/currency.xml");
0037 #endif
0038 }
0039 
0040 class CurrencyCategoryPrivate : public UnitCategoryPrivate
0041 {
0042 public:
0043     CurrencyCategoryPrivate(CategoryId id, const QString &name, const QString &description)
0044         : UnitCategoryPrivate(id, name, description)
0045     {
0046     }
0047 
0048     Value convert(const Value &value, const Unit &toUnit) override;
0049     bool hasOnlineConversionTable() const override;
0050     UpdateJob* syncConversionTable(std::chrono::seconds updateSkipSeconds) override;
0051 
0052     QNetworkReply *m_currentReply = nullptr;
0053     bool readConversionTable(const QString &cacheLocation);
0054     bool m_initialized{false}; //!< indicates if units are prepared from currency table
0055 };
0056 
0057 bool CurrencyCategoryPrivate::hasOnlineConversionTable() const
0058 {
0059     return true;
0060 }
0061 
0062 UnitCategory Currency::makeCategory()
0063 {
0064     auto c = UnitCategoryPrivate::makeCategory(new CurrencyCategoryPrivate(CurrencyCategory, i18n("Currency"), i18n("From ECB")));
0065     auto d = UnitCategoryPrivate::get(c);
0066     KLocalizedString symbolString = ki18nc("%1 value, %2 unit symbol (currency)", "%1 %2");
0067 
0068     // Static rates
0069     d->addDefaultUnit(UnitPrivate::makeUnit(CurrencyCategory,
0070                               Eur,
0071                               1.0,
0072                               QStringLiteral("EUR"),
0073                               i18nc("currency name", "Euro"),
0074                               i18nc("EUR Euro - unit synonyms for matching user input", "euro;euros") + QStringLiteral(";EUR;") + QStringLiteral("€")
0075                                   + QLatin1Char(';') + i18nc("currency name", "Euro"),
0076                               symbolString,
0077                               ki18nc("amount in units (real)", "%1 euros"),
0078                               ki18ncp("amount in units (integer)", "%1 euro", "%1 euros")));
0079 
0080     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0081                        Ats,
0082                        0.0726728,
0083                        QStringLiteral("ATS"),
0084                        i18nc("currency name", "Austrian Schilling"),
0085                        i18nc("ATS Austrian Schilling - unit synonyms for matching user input", "schilling;schillings") + QStringLiteral(";ATS;")
0086                            + QLocale::territoryToString(QLocale::Austria) + QLatin1Char(';') + i18nc("currency name", "Austrian Schilling"),
0087                        symbolString,
0088                        ki18nc("amount in units (real)", "%1 schillings"),
0089                        ki18ncp("amount in units (integer)", "%1 schilling", "%1 schillings")));
0090 
0091     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0092                        Bef,
0093                        0.0247894,
0094                        QStringLiteral("BEF"),
0095                        i18nc("currency name", "Belgian Franc"),
0096                        i18nc("BEF Belgian Franc - unit synonyms for matching user input", "franc;francs") + QStringLiteral(";BEF;")
0097                            + QLocale::territoryToString(QLocale::Belgium) + QLatin1Char(';') + i18nc("currency name", "Belgian Franc"),
0098                        symbolString,
0099                        ki18nc("amount in units (real)", "%1 Belgian francs"),
0100                        ki18ncp("amount in units (integer)", "%1 Belgian franc", "%1 Belgian francs")));
0101 
0102     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0103                        Nlg,
0104                        0.45378,
0105                        QStringLiteral("NLG"),
0106                        i18nc("currency name", "Netherlands Guilder"),
0107                        i18nc("NLG Netherlands Guilder - unit synonyms for matching user input", "guilder;guilders") + QStringLiteral(";NLG;")
0108                            + QLocale::territoryToString(QLocale::Netherlands) + QLatin1Char(';') + i18nc("currency name", "Netherlands Guilder"),
0109                        symbolString,
0110                        ki18nc("amount in units (real)", "%1 guilders"),
0111                        ki18ncp("amount in units (integer)", "%1 guilder", "%1 guilders")));
0112 
0113     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0114                        Fim,
0115                        0.168188,
0116                        QStringLiteral("FIM"),
0117                        i18nc("currency name", "Finnish Markka"),
0118                        i18nc("FIM Finnish Markka - unit synonyms for matching user input", "markka;markkas;markkaa") + QStringLiteral(";FIM;")
0119                            + QLocale::territoryToString(QLocale::Finland) + QLatin1Char(';') + i18nc("currency name", "Finnish Markka"),
0120                        symbolString,
0121                        ki18nc("amount in units (real)", "%1 markkas"),
0122                        ki18ncp("amount in units (integer)", "%1 markka", "%1 markkas"))); // Alternative = markkaa
0123 
0124     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0125                        Frf,
0126                        0.152449,
0127                        QStringLiteral("FRF"),
0128                        i18nc("currency name", "French Franc"),
0129                        i18nc("FRF French Franc - unit synonyms for matching user input", "franc;francs") + QStringLiteral(";FRF;")
0130                            + QLocale::territoryToString(QLocale::France) + QLatin1Char(';') + i18nc("currency name", "French Franc"),
0131                        symbolString,
0132                        ki18nc("amount in units (real)", "%1 French francs"),
0133                        ki18ncp("amount in units (integer)", "%1 French franc", "%1 French francs")));
0134 
0135     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0136                        Dem,
0137                        0.511292,
0138                        QStringLiteral("DEM"),
0139                        i18nc("currency name", "German Mark"),
0140                        i18nc("DEM German Mark - unit synonyms for matching user input", "mark;marks") + QStringLiteral(";DEM;")
0141                            + QLocale::territoryToString(QLocale::Germany) + QLatin1Char(';') + i18nc("currency name", "German Mark"),
0142                        symbolString,
0143                        ki18nc("amount in units (real)", "%1 marks"),
0144                        ki18ncp("amount in units (integer)", "%1 mark", "%1 marks")));
0145 
0146     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0147                        Iep,
0148                        1.26974,
0149                        QStringLiteral("IEP"),
0150                        i18nc("currency name", "Irish Pound"),
0151                        i18nc("IEP Irish Pound - unit synonyms for matching user input", "Irish pound;Irish pounds") + QStringLiteral(";IEP;")
0152                            + QLocale::territoryToString(QLocale::Ireland) + QLatin1Char(';') + i18nc("currency name", "Irish Pound"),
0153                        symbolString,
0154                        ki18nc("amount in units (real)", "%1 Irish pounds"),
0155                        ki18ncp("amount in units (integer)", "%1 Irish pound", "%1 Irish pounds")));
0156 
0157     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0158                        Itl,
0159                        0.000516457,
0160                        QStringLiteral("ITL"),
0161                        i18nc("currency name", "Italian Lira"),
0162                        i18nc("ITL Italian Lira - unit synonyms for matching user input", "lira;liras") + QStringLiteral(";ITL;")
0163                            + QLocale::territoryToString(QLocale::Italy) + QLatin1Char(';') + i18nc("currency name", "Italian Lira"),
0164                        symbolString,
0165                        ki18nc("amount in units (real)", "%1 Italian lira"),
0166                        ki18ncp("amount in units (integer)", "%1 Italian lira", "%1 Italian lira")));
0167 
0168     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0169                        Luf,
0170                        0.0247894,
0171                        QStringLiteral("LUF"),
0172                        i18nc("currency name", "Luxembourgish Franc"),
0173                        i18nc("LUF Luxembourgish Franc - unit synonyms for matching user input", "franc;francs") + QStringLiteral(";LUF;")
0174                            + QLocale::territoryToString(QLocale::Luxembourg) + QLatin1Char(';') + i18nc("currency name", "Luxembourgish Franc"),
0175                        symbolString,
0176                        ki18nc("amount in units (real)", "%1 Luxembourgish francs"),
0177                        ki18ncp("amount in units (integer)", "%1 Luxembourgish franc", "%1 Luxembourgish francs")));
0178 
0179     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0180                        Pte,
0181                        0.00498798,
0182                        QStringLiteral("PTE"),
0183                        i18nc("currency name", "Portuguese Escudo"),
0184                        i18nc("PTE Portuguese Escudo - unit synonyms for matching user input", "escudo;escudos") + QStringLiteral(";PTE;")
0185                            + QLocale::territoryToString(QLocale::Portugal) + QLatin1Char(';') + i18nc("currency name", "Portuguese Escudo"),
0186                        symbolString,
0187                        ki18nc("amount in units (real)", "%1 escudos"),
0188                        ki18ncp("amount in units (integer)", "%1 escudo", "%1 escudos")));
0189 
0190     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0191                        Esp,
0192                        0.00601012,
0193                        QStringLiteral("ESP"),
0194                        i18nc("currency name", "Spanish Peseta"),
0195                        i18nc("ESP Spanish Peseta - unit synonyms for matching user input", "peseta;pesetas") + QStringLiteral(";ESP;")
0196                            + QLocale::territoryToString(QLocale::Spain) + QLatin1Char(';') + i18nc("currency name", "Spanish Peseta"),
0197                        symbolString,
0198                        ki18nc("amount in units (real)", "%1 pesetas"),
0199                        ki18ncp("amount in units (integer)", "%1 peseta", "%1 pesetas")));
0200 
0201     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0202                        Grd,
0203                        0.0029347,
0204                        QStringLiteral("GRD"),
0205                        i18nc("currency name", "Greek Drachma"),
0206                        i18nc("GRD Greek Drachma - unit synonyms for matching user input", "drachma;drachmas") + QStringLiteral(";GRD;")
0207                            + QLocale::territoryToString(QLocale::Greece) + QLatin1Char(';') + i18nc("currency name", "Greek Drachma"),
0208                        symbolString,
0209                        ki18nc("amount in units (real)", "%1 drachmas"),
0210                        ki18ncp("amount in units (integer)", "%1 drachma", "%1 drachmas")));
0211 
0212     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0213                        Sit,
0214                        0.00417293,
0215                        QStringLiteral("SIT"),
0216                        i18nc("currency name", "Slovenian Tolar"),
0217                        i18nc("SIT Slovenian Tolar - unit synonyms for matching user input", "tolar;tolars;tolarjev") + QStringLiteral(";SIT;")
0218                            + QLocale::territoryToString(QLocale::Slovenia) + QLatin1Char(';') + i18nc("currency name", "Slovenian Tolar"),
0219                        symbolString,
0220                        ki18nc("amount in units (real)", "%1 tolars"),
0221                        ki18ncp("amount in units (integer)", "%1 tolar", "%1 tolars"))); // Alt: tolarjev/tolarja/tolarji
0222 
0223     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0224                        Cyp,
0225                        1.7086,
0226                        QStringLiteral("CYP"),
0227                        i18nc("currency name", "Cypriot Pound"),
0228                        i18nc("CYP Cypriot Pound - unit synonyms for matching user input", "Cypriot pound;Cypriot pounds") + QStringLiteral(";CYP;")
0229                            + QLocale::territoryToString(QLocale::Cyprus) + QLatin1Char(';') + i18nc("currency name", "Cypriot Pound"),
0230                        symbolString,
0231                        ki18nc("amount in units (real)", "%1 Cypriot pounds"),
0232                        ki18ncp("amount in units (integer)", "%1 Cypriot pound", "%1 Cypriot pounds")));
0233 
0234     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0235                        Mtl,
0236                        2.32937,
0237                        QStringLiteral("MTL"),
0238                        i18nc("currency name", "Maltese Lira"),
0239                        i18nc("MTL Maltese Lira - unit synonyms for matching user input", "Maltese lira") + QStringLiteral(";MTL;")
0240                            + QLocale::territoryToString(QLocale::Malta) + QLatin1Char(';') + i18nc("currency name", "Maltese Lira"),
0241                        symbolString,
0242                        ki18nc("amount in units (real)", "%1 Maltese lira"),
0243                        ki18ncp("amount in units (integer)", "%1 Maltese lira", "%1 Maltese lira")));
0244 
0245     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0246                        Skk,
0247                        0.0331939,
0248                        QStringLiteral("SKK"),
0249                        i18nc("currency name", "Slovak Koruna"),
0250                        i18nc("SKK Slovak Koruna - unit synonyms for matching user input", "koruna;korunas;koruny;korun") + QStringLiteral(";SKK;")
0251                            + QLocale::territoryToString(QLocale::Slovakia) + QLatin1Char(';') + i18nc("currency name", "Slovak Koruna"),
0252                        symbolString,
0253                        ki18nc("amount in units (real)", "%1 Slovak korunas"),
0254                        ki18ncp("amount in units (integer)", "%1 Slovak koruna", "%1 Slovak korunas"))); // Alt: koruny, korun
0255 
0256     // From ECB
0257     d->addCommonUnit(UnitPrivate::makeUnit(CurrencyCategory,
0258                              Usd,
0259                              qSNaN(),
0260                              QStringLiteral("USD"),
0261                              i18nc("currency name", "United States Dollar"),
0262                              i18nc("USD United States Dollar - unit synonyms for matching user input", "dollar;dollars") + QStringLiteral(";USD;$;")
0263                                  + QLocale::territoryToString(QLocale::UnitedStates) + QLatin1Char(';') + i18nc("currency name", "United States Dollar"),
0264                              symbolString,
0265                              ki18nc("amount in units (real)", "%1 United States dollars"),
0266                              ki18ncp("amount in units (integer)", "%1 United States dollar", "%1 United States dollars")));
0267 
0268     d->addCommonUnit(UnitPrivate::makeUnit(CurrencyCategory,
0269                              Jpy,
0270                              qSNaN(),
0271                              QStringLiteral("JPY"),
0272                              i18nc("currency name", "Japanese Yen"),
0273                              i18nc("JPY Japanese Yen - unit synonyms for matching user input", "yen") + QStringLiteral(";JPY;") + QStringLiteral("¥")
0274                                  + QLatin1Char(';') + QLocale::territoryToString(QLocale::Japan) + QLatin1Char(';') + i18nc("currency name", "Japanese Yen"),
0275                              symbolString,
0276                              ki18nc("amount in units (real)", "%1 yen"),
0277                              ki18ncp("amount in units (integer)", "%1 yen", "%1 yen")));
0278 
0279     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0280                        Bgn,
0281                        qSNaN(),
0282                        QStringLiteral("BGN"),
0283                        i18nc("currency name", "Bulgarian Lev"),
0284                        i18nc("BGN Bulgarian Lev - unit synonyms for matching user input", "lev;leva") + QStringLiteral(";BGN;")
0285                            + QLocale::territoryToString(QLocale::Bulgaria) + QLatin1Char(';') + i18nc("currency name", "Bulgarian Lev"),
0286                        symbolString,
0287                        ki18nc("amount in units (real)", "%1 leva"),
0288                        ki18ncp("amount in units (integer)", "%1 lev", "%1 leva")));
0289 
0290     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0291                        Czk,
0292                        qSNaN(),
0293                        QStringLiteral("CZK"),
0294                        i18nc("currency name", "Czech Koruna"),
0295                        i18nc("CZK Czech Koruna - unit synonyms for matching user input", "koruna;korunas") + QStringLiteral(";CZK;")
0296                            + QLocale::territoryToString(QLocale::CzechRepublic) + QLatin1Char(';') + i18nc("currency name", "Czech Koruna"),
0297                        symbolString,
0298                        ki18nc("amount in units (real)", "%1 Czech korunas"),
0299                        // Alt: koruny, korun
0300                        ki18ncp("amount in units (integer)", "%1 Czech koruna", "%1 Czech korunas")));
0301 
0302     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0303                        Dkk,
0304                        qSNaN(),
0305                        QStringLiteral("DKK"),
0306                        i18nc("currency name", "Danish Krone"),
0307                        i18nc("DKK Danish Krone - unit synonyms for matching user input", "Danish krone;Danish kroner") + QStringLiteral(";DKK;")
0308                            + QLocale::territoryToString(QLocale::Denmark) + QLatin1Char(';') + i18nc("currency name", "Danish Krone"),
0309                        symbolString,
0310                        ki18nc("amount in units (real)", "%1 Danish kroner"),
0311                        ki18ncp("amount in units (integer)", "%1 Danish krone", "%1 Danish kroner")));
0312 
0313     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0314                        Eek,
0315                        qSNaN(),
0316                        QStringLiteral("EEK"),
0317                        i18nc("currency name", "Estonian Kroon"),
0318                        i18nc("EEK Estonian Kroon - unit synonyms for matching user input", "kroon;kroons;krooni") + QStringLiteral(";EEK;")
0319                            + QLocale::territoryToString(QLocale::Estonia) + QLatin1Char(';') + i18nc("currency name", "Estonian Kroon"),
0320                        symbolString,
0321                        ki18nc("amount in units (real)", "%1 kroons"),
0322                        ki18ncp("amount in units (integer)", "%1 kroon", "%1 kroons"))); // Alt: krooni
0323 
0324     d->addCommonUnit(UnitPrivate::makeUnit(CurrencyCategory,
0325                              Gbp,
0326                              qSNaN(),
0327                              QStringLiteral("GBP"),
0328                              i18nc("currency name", "British Pound"),
0329                              i18nc("GBP British Pound - unit synonyms for matching user input", "pound;pounds;pound sterling;pounds sterling")
0330                                  + QStringLiteral(";GBP;") + QStringLiteral("£") + QLatin1Char(';') + QLocale::territoryToString(QLocale::UnitedKingdom)
0331                                  + QLatin1Char(';') + i18nc("currency name", "British Pound"),
0332                              symbolString,
0333                              ki18nc("amount in units (real)", "%1 pounds sterling"),
0334                              ki18ncp("amount in units (integer)", "%1 pound sterling", "%1 pounds sterling")));
0335 
0336     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0337                        Huf,
0338                        qSNaN(),
0339                        QStringLiteral("HUF"),
0340                        i18nc("currency name", "Hungarian Forint"),
0341                        i18nc("HUF hungarian Forint - unit synonyms for matching user input", "forint") + QStringLiteral(";HUF;")
0342                            + QLocale::territoryToString(QLocale::Hungary) + QLatin1Char(';') + i18nc("currency name", "Hungarian Forint"),
0343                        symbolString,
0344                        ki18nc("amount in units (real)", "%1 forint"),
0345                        ki18ncp("amount in units (integer)", "%1 forint", "%1 forint")));
0346 
0347     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0348                        Ils,
0349                        qSNaN(),
0350                        QStringLiteral("ILS"),
0351                        i18nc("currency name", "Israeli New Shekel"),
0352                        i18nc("ILS Israeli New Shekel - unit synonyms for matching user input", "shekel;shekels;sheqel;sheqels;sheqalim")
0353                            + QStringLiteral(";ILS;") + QLocale::territoryToString(QLocale::Israel) + QLatin1Char(';')
0354                            + i18nc("currency name", "Israeli New Shekel"),
0355                        symbolString,
0356                        ki18nc("amount in units (real)", "%1 shekels"),
0357                        ki18ncp("amount in units (integer)", "%1 shekel", "%1 shekels")));
0358 
0359     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0360                        Ltl,
0361                        qSNaN(),
0362                        QStringLiteral("LTL"),
0363                        i18nc("currency name", "Lithuanian Litas"),
0364                        i18nc("LTL Lithuanian Litas - unit synonyms for matching user input", "litas;litai;litu") + QStringLiteral(";LTL;")
0365                            + QLocale::territoryToString(QLocale::Lithuania) + QLatin1Char(';') + i18nc("currency name", "Lithuanian Litas"),
0366                        symbolString,
0367                        ki18nc("amount in units (real)", "%1 litas"),
0368                        ki18ncp("amount in units (integer)", "%1 litas", "%1 litai"))); // Alt: litu
0369 
0370     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0371                        Lvl,
0372                        qSNaN(),
0373                        QStringLiteral("LVL"),
0374                        i18nc("currency name", "Latvian Lats"),
0375                        i18nc("LVL Latvian Lats - unit synonyms for matching user input", "lats;lati") + QStringLiteral(";LVL;")
0376                            + QLocale::territoryToString(QLocale::Latvia) + QLatin1Char(';') + i18nc("currency name", "Latvian Lats"),
0377                        symbolString,
0378                        ki18nc("amount in units (real)", "%1 lati"),
0379                        ki18ncp("amount in units (integer)", "%1 lats", "%1 lati")));
0380 
0381     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0382                        Pln,
0383                        qSNaN(),
0384                        QStringLiteral("PLN"),
0385                        i18nc("currency name", "Polish Zloty"),
0386                        i18nc("PLN Polish Zloty - unit synonyms for matching user input", "zloty;zlotys;zloties") + QStringLiteral(";PLN;")
0387                            + QLocale::territoryToString(QLocale::Poland) + QLatin1Char(';') + i18nc("currency name", "Polish Zloty"),
0388                        symbolString,
0389                        ki18nc("amount in units (real)", "%1 zlotys"),
0390                        ki18ncp("amount in units (integer)", "%1 zloty", "%1 zlotys"))); // Alt: zloty, zlote, zlotych
0391 
0392     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0393                        Ron,
0394                        qSNaN(),
0395                        QStringLiteral("RON"),
0396                        i18nc("currency name", "Romanian Leu"),
0397                        i18nc("RON Romanian Leu - unit synonyms for matching user input", "leu;lei") + QStringLiteral(";RON;")
0398                            + QLocale::territoryToString(QLocale::Romania) + QLatin1Char(';') + i18nc("currency name", "Romanian Leu"),
0399                        symbolString,
0400                        ki18nc("amount in units (real)", "%1 lei"),
0401                        ki18ncp("amount in units (integer)", "%1 leu", "%1 lei")));
0402 
0403     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0404                        Sek,
0405                        qSNaN(),
0406                        QStringLiteral("SEK"),
0407                        i18nc("currency name", "Swedish Krona"),
0408                        i18nc("SEK Swedish Krona - unit synonyms for matching user input", "krona;kronor") + QStringLiteral(";SEK;")
0409                            + QLocale::territoryToString(QLocale::Sweden) + QLatin1Char(';') + i18nc("currency name", "Swedish Krona"),
0410                        symbolString,
0411                        ki18nc("amount in units (real)", "%1 kronor"),
0412                        ki18ncp("amount in units (integer)", "%1 krona", "%1 kronor")));
0413 
0414     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0415                        Chf,
0416                        qSNaN(),
0417                        QStringLiteral("CHF"),
0418                        i18nc("currency name", "Swiss Franc"),
0419                        i18nc("CHF Swiss Franc - unit synonyms for matching user input", "franc;francs") + QStringLiteral(";CHF;")
0420                            + QLocale::territoryToString(QLocale::Switzerland) + QLatin1Char(';') + i18nc("currency name", "Swiss Franc"),
0421                        symbolString,
0422                        ki18nc("amount in units (real)", "%1 Swiss francs"),
0423                        ki18ncp("amount in units (integer)", "%1 Swiss franc", "%1 Swiss francs")));
0424 
0425     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0426                        Nok,
0427                        qSNaN(),
0428                        QStringLiteral("NOK"),
0429                        i18nc("currency name", "Norwegian Krone"),
0430                        i18nc("Norwegian Krone - unit synonyms for matching user input", "Norwegian krone;Norwegian kroner") + QStringLiteral(";NOK;")
0431                            + QLocale::territoryToString(QLocale::Norway) + QLatin1Char(';') + i18nc("currency name", "Norwegian Krone"),
0432                        symbolString,
0433                        ki18nc("amount in units (real)", "%1 Norwegian kroner"),
0434                        ki18ncp("amount in units (integer)", "%1 Norwegian krone", "%1 Norwegian kroner")));
0435 
0436     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0437                        Hrk,
0438                        1.0/7.53450,
0439                        QStringLiteral("HRK"),
0440                        i18nc("currency name", "Croatian Kuna"),
0441                        i18nc("HRK Croatian Kuna - unit synonyms for matching user input", "kuna;kune") + QStringLiteral(";HRK;")
0442                            + QLocale::territoryToString(QLocale::Croatia) + QLatin1Char(';') + i18nc("currency name", "Croatian Kuna"),
0443                        symbolString,
0444                        ki18nc("amount in units (real)", "%1 kune"),
0445                        ki18ncp("amount in units (integer)", "%1 kuna", "%1 kune")));
0446 
0447     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0448                        Rub,
0449                        qSNaN(),
0450                        QStringLiteral("RUB"),
0451                        i18nc("currency name", "Russian Ruble"),
0452                        i18nc("RUB Russian Ruble - unit synonyms for matching user input", "ruble;rubles;rouble;roubles") + QStringLiteral(";RUB;")
0453                            + QLocale::territoryToString(QLocale::Russia) + QLatin1Char(';') + i18nc("currency name", "Russian Ruble"),
0454                        symbolString,
0455                        ki18nc("amount in units (real)", "%1 rubles"),
0456                        ki18ncp("amount in units (integer)", "%1 ruble", "%1 rubles"))); // Alt: rouble/roubles
0457 
0458     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0459                        Try,
0460                        qSNaN(),
0461                        QStringLiteral("TRY"),
0462                        i18nc("currency name", "Turkish Lira"),
0463                        i18nc("TRY Turkish Lira - unit synonyms for matching user input", "lira") + QStringLiteral(";TRY;")
0464                            + QLocale::territoryToString(QLocale::Turkey) + QLatin1Char(';') + i18nc("currency name", "Turkish Lira"),
0465                        symbolString,
0466                        ki18nc("amount in units (real)", "%1 Turkish lira"),
0467                        ki18ncp("amount in units (integer)", "%1 Turkish lira", "%1 Turkish lira")));
0468 
0469     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0470                        Aud,
0471                        qSNaN(),
0472                        QStringLiteral("AUD"),
0473                        i18nc("currency name", "Australian Dollar"),
0474                        i18nc("AUD Australian Dollar - unit synonyms for matching user input", "Australian dollar;Australian dollars") + QStringLiteral(";AUD;")
0475                            + QLocale::territoryToString(QLocale::Australia) + QLatin1Char(';') + i18nc("currency name", "Australian Dollar"),
0476                        symbolString,
0477                        ki18nc("amount in units (real)", "%1 Australian dollars"),
0478                        ki18ncp("amount in units (integer)", "%1 Australian dollar", "%1 Australian dollars")));
0479 
0480     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0481                        Brl,
0482                        qSNaN(),
0483                        QStringLiteral("BRL"),
0484                        i18nc("currency name", "Brazilian Real"),
0485                        i18nc("BRL Brazilian Real - unit synonyms for matching user input", "real;reais") + QStringLiteral(";BRL;")
0486                            + QLocale::territoryToString(QLocale::Brazil) + QLatin1Char(';') + i18nc("currency name", "Brazilian Real"),
0487                        symbolString,
0488                        ki18nc("amount in units (real)", "%1 reais"),
0489                        ki18ncp("amount in units (integer)", "%1 real", "%1 reais")));
0490 
0491     d->addCommonUnit(UnitPrivate::makeUnit(CurrencyCategory,
0492                              Cad,
0493                              qSNaN(),
0494                              QStringLiteral("CAD"),
0495                              i18nc("currency name", "Canadian Dollar"),
0496                              i18nc("Canadian Dollar - unit synonyms for matching user input", "Canadian dollar;Canadian dollars") + QStringLiteral(";CAD;")
0497                                  + QLocale::territoryToString(QLocale::Canada) + QLatin1Char(';') + i18nc("currency name", "Canadian Dollar"),
0498                              symbolString,
0499                              ki18nc("amount in units (real)", "%1 Canadian dollars"),
0500                              ki18ncp("amount in units (integer)", "%1 Canadian dollar", "%1 Canadian dollars")));
0501 
0502     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0503                        Cny,
0504                        qSNaN(),
0505                        QStringLiteral("CNY"),
0506                        i18nc("currency name", "Chinese Yuan"),
0507                        i18nc("Chinese Yuan - unit synonyms for matching user input", "yuan") + QStringLiteral(";CNY;")
0508                            + QLocale::territoryToString(QLocale::China) + QLatin1Char(';') + i18nc("currency name", "Chinese Yuan"),
0509                        symbolString,
0510                        ki18nc("amount in units (real)", "%1 yuan"),
0511                        ki18ncp("amount in units (integer)", "%1 yuan", "%1 yuan")));
0512 
0513     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0514                        Hkd,
0515                        qSNaN(),
0516                        QStringLiteral("HKD"),
0517                        i18nc("currency name", "Hong Kong Dollar"),
0518                        i18nc("Hong Kong Dollar - unit synonyms for matching user input", "Hong Kong dollar;Hong Kong dollars") + QStringLiteral(";HKD;")
0519                            + QLocale::territoryToString(QLocale::HongKong) + QLatin1Char(';') + i18nc("currency name", "Hong Kong Dollar"),
0520                        symbolString,
0521                        ki18nc("amount in units (real)", "%1 Hong Kong dollars"),
0522                        ki18ncp("amount in units (integer)", "%1 Hong Kong dollar", "%1 Hong Kong dollars")));
0523 
0524     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0525                        Idr,
0526                        qSNaN(),
0527                        QStringLiteral("IDR"),
0528                        i18nc("currency name", "Indonesian Rupiah"),
0529                        i18nc("IDR Indonesian Rupiah - unit synonyms for matching user input", "rupiah;rupiahs") + QStringLiteral(";IDR;")
0530                            + QLocale::territoryToString(QLocale::Indonesia) + QLatin1Char(';') + i18nc("currency name", "Indonesian Rupiah"),
0531                        symbolString,
0532                        ki18nc("amount in units (real)", "%1 rupiahs"),
0533                        ki18ncp("amount in units (integer)", "%1 rupiah", "%1 rupiahs"))); // Alt: rupiah
0534 
0535     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0536                        Inr,
0537                        qSNaN(),
0538                        QStringLiteral("INR"),
0539                        i18nc("currency name", "Indian Rupee"),
0540                        i18nc("INR Indian Rupee - unit synonyms for matching user input", "rupee;rupees") + QStringLiteral(";INR;")
0541                            + QLocale::territoryToString(QLocale::India) + QLatin1Char(';') + i18nc("currency name", "Indian Rupee"),
0542                        symbolString,
0543                        ki18nc("amount in units (real)", "%1 rupees"),
0544                        ki18ncp("amount in units (integer)", "%1 rupee", "%1 rupees"))); // Alt: rupee
0545 
0546     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0547                        Krw,
0548                        qSNaN(),
0549                        QStringLiteral("KRW"),
0550                        i18nc("currency name", "Korean Won"),
0551                        i18nc("KRW Korean Won - unit synonyms for matching user input", "won") + QStringLiteral(";KRW;")
0552                            + QLocale::territoryToString(QLocale::SouthKorea) + QLatin1Char(';') + i18nc("currency name", "Korean Won"),
0553                        symbolString,
0554                        ki18nc("amount in units (real)", "%1 won"),
0555                        ki18ncp("amount in units (integer)", "%1 won", "%1 won")));
0556 
0557     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0558                        Mxn,
0559                        qSNaN(),
0560                        QStringLiteral("MXN"),
0561                        i18nc("currency name", "Mexican Peso"),
0562                        i18nc("MXN Mexican Peso - unit synonyms for matching user input", "Mexican peso;Mexican pesos") + QStringLiteral(";MXN;")
0563                            + QLocale::territoryToString(QLocale::Mexico) + QLatin1Char(';') + i18nc("currency name", "Mexican Peso"),
0564                        symbolString,
0565                        ki18nc("amount in units (real)", "%1 Mexican pesos"),
0566                        ki18ncp("amount in units (integer)", "%1 Mexican peso", "%1 Mexican pesos")));
0567 
0568     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0569                        Myr,
0570                        qSNaN(),
0571                        QStringLiteral("MYR"),
0572                        i18nc("currency name", "Malaysian Ringgit"),
0573                        i18nc("MYR Malaysian Ringgit - unit synonyms for matching user input", "ringgit;ringgits") + QStringLiteral(";MYR;")
0574                            + QLocale::territoryToString(QLocale::Malaysia) + QLatin1Char(';') + i18nc("currency name", "Malaysian Ringgit"),
0575                        symbolString,
0576                        ki18nc("amount in units (real)", "%1 ringgit"),
0577                        ki18ncp("amount in units (integer)", "%1 ringgit", "%1 ringgit"))); // Alt: ringgits
0578 
0579     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0580                        Nzd,
0581                        qSNaN(),
0582                        QStringLiteral("NZD"),
0583                        i18nc("currency name", "New Zealand Dollar"),
0584                        i18nc("NZD New Zealand Dollar - unit synonyms for matching user input", "New Zealand dollar;New Zealand dollars")
0585                            + QStringLiteral(";NZD;") + QLocale::territoryToString(QLocale::NewZealand) + QLatin1Char(';')
0586                            + i18nc("currency name", "New Zealand Dollar"),
0587                        symbolString,
0588                        ki18nc("amount in units (real)", "%1 New Zealand dollars"),
0589                        ki18ncp("amount in units (integer)", "%1 New Zealand dollar", "%1 New Zealand dollars")));
0590 
0591     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0592                        Php,
0593                        qSNaN(),
0594                        QStringLiteral("PHP"),
0595                        i18nc("currency name", "Philippine Peso"),
0596                        i18nc("PHP Philippine Peso - unit synonyms for matching user input", "Philippine peso;Philippine pesos") + QStringLiteral(";PHP;")
0597                            + QLocale::territoryToString(QLocale::Philippines) + QLatin1Char(';') + i18nc("currency name", "Philippine Peso"),
0598                        symbolString,
0599                        ki18nc("amount in units (real)", "%1 Philippine pesos"),
0600                        ki18ncp("amount in units (integer)", "%1 Philippine peso", "%1 Philippine pesos")));
0601 
0602     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0603                        Sgd,
0604                        qSNaN(),
0605                        QStringLiteral("SGD"),
0606                        i18nc("currency name", "Singapore Dollar"),
0607                        i18nc("SGD Singapore Dollar - unit synonyms for matching user input", "Singapore dollar;Singapore dollars") + QStringLiteral(";SGD;")
0608                            + QLocale::territoryToString(QLocale::Singapore) + QLatin1Char(';') + i18nc("currency name", "Singapore Dollar"),
0609                        symbolString,
0610                        ki18nc("amount in units (real)", "%1 Singapore dollars"),
0611                        ki18ncp("amount in units (integer)", "%1 Singapore dollar", "%1 Singapore dollars")));
0612 
0613     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0614                        Thb,
0615                        qSNaN(),
0616                        QStringLiteral("THB"),
0617                        i18nc("currency name", "Thai Baht"),
0618                        i18nc("THB Thai Baht - unit synonyms for matching user input", "baht") + QStringLiteral(";THB;")
0619                            + QLocale::territoryToString(QLocale::Thailand) + QLatin1Char(';') + i18nc("currency name", "Thai Baht"),
0620                        symbolString,
0621                        ki18nc("amount in units (real)", "%1 baht"),
0622                        ki18ncp("amount in units (integer)", "%1 baht", "%1 baht")));
0623 
0624     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0625                        Zar,
0626                        qSNaN(),
0627                        QStringLiteral("ZAR"),
0628                        i18nc("currency name", "South African Rand"),
0629                        i18nc("South African Rand - unit synonyms for matching user input", "rand") + QStringLiteral(";ZAR;")
0630                            + QLocale::territoryToString(QLocale::SouthAfrica) + QLatin1Char(';') + i18nc("currency name", "South African Rand"),
0631                        symbolString,
0632                        ki18nc("amount in units (real)", "%1 rand"),
0633                        ki18ncp("amount in units (integer)", "%1 rand", "%1 rand")));
0634     d->addUnit(UnitPrivate::makeUnit(CurrencyCategory,
0635                        Isk,
0636                        qSNaN(),
0637                        QStringLiteral("ISK"),
0638                        i18nc("currency name", "Icelandic Krona"),
0639                        i18nc("Icelandic Krona - unit synonyms for matching user input", "Icelandic krona;Icelandic crown") + QStringLiteral(";ISK;")
0640                            + QLocale::territoryToString(QLocale::Iceland) + QLatin1Char(';') + i18nc("currency name", "Icelandic Krona"),
0641                        symbolString,
0642                        ki18nc("amount in units (real)", "%1 Icelandic kronar"),
0643                        ki18ncp("amount in units (integer)", "%1 Icelandic krona", "%1 Icelandic kronar")));
0644 
0645     return c;
0646 }
0647 
0648 static bool isConnected()
0649 {
0650     // don't download currencies in autotests
0651     if (qEnvironmentVariableIsSet("KF5UNITCONVERT_NO_DOWNLOAD")) {
0652         return false;
0653     }
0654     bool ret = false;
0655     const auto listInterface = QNetworkInterface::allInterfaces();
0656     for (const QNetworkInterface &net : listInterface) {
0657         if (net.flags().testFlag(QNetworkInterface::IsUp) && !net.flags().testFlag(QNetworkInterface::IsLoopBack)) {
0658             ret = true;
0659             break;
0660         }
0661     }
0662     return ret;
0663 }
0664 
0665 QDateTime Currency::lastConversionTableUpdate()
0666 {
0667     QFileInfo info(cacheLocation());
0668     if (!info.exists()) {
0669         qCDebug(LOG_KUNITCONVERSION) << "No cache file available:" << cacheLocation();
0670         return QDateTime();
0671     } else {
0672         return info.lastModified();
0673     }
0674 }
0675 
0676 UpdateJob* CurrencyCategoryPrivate::syncConversionTable(std::chrono::seconds updateSkipPeriod)
0677 {
0678     QFileInfo info(cacheLocation());
0679     if (info.exists() && info.lastModified().secsTo(QDateTime::currentDateTime()) <= updateSkipPeriod.count()) {
0680         return nullptr; // already present and up to date
0681     }
0682     if (!isConnected()) {
0683         qCInfo(LOG_KUNITCONVERSION) << "currency conversion table update has no network connection, abort update";
0684         return nullptr;
0685     }
0686     if (m_currentReply) {
0687         return makeUpdateJob(m_currentReply);
0688     }
0689 
0690     qCDebug(LOG_KUNITCONVERSION) << "currency conversion table sync started";
0691     m_currentReply = nam()->get(QNetworkRequest(QUrl(QString::fromLatin1(URL))));
0692     QObject::connect(m_currentReply, &QNetworkReply::finished, [this] {
0693         auto reply = m_currentReply;
0694         m_currentReply = nullptr;
0695         reply->deleteLater();
0696         if (reply->error()) {
0697             qCWarning(LOG_KUNITCONVERSION) << "currency conversion table network error" << reply->errorString();
0698             return;
0699         }
0700         const auto cachePath = cacheLocation();
0701         QFileInfo info(cachePath);
0702         const QString cacheDir = info.absolutePath();
0703         if (!QFileInfo::exists(cacheDir)) {
0704             QDir().mkpath(cacheDir);
0705         }
0706 
0707         QSaveFile cacheFile(cachePath);
0708         if (!cacheFile.open(QFile::WriteOnly)) {
0709             qCCritical(LOG_KUNITCONVERSION) << cacheFile.errorString();
0710             return;
0711         }
0712         cacheFile.write(reply->readAll());
0713         if (!cacheFile.commit()) {
0714             qCCritical(LOG_KUNITCONVERSION) << cacheFile.errorString();
0715             return;
0716         }
0717         qCInfo(LOG_KUNITCONVERSION) << "currency conversion table data obtained via network";
0718         m_initialized = readConversionTable(cachePath);
0719     });
0720 
0721     return makeUpdateJob(m_currentReply);
0722 }
0723 
0724 bool CurrencyCategoryPrivate::readConversionTable(const QString &cachePath)
0725 {
0726     QFile file(cachePath);
0727     if (!file.open(QIODevice::ReadOnly)) {
0728         return false;
0729     }
0730     QXmlStreamReader xml(&file);
0731     while (!xml.atEnd()) {
0732         xml.readNext();
0733 
0734         if (xml.isStartElement() && xml.name() == QLatin1String("Cube")) {
0735             const auto attributes = xml.attributes();
0736             if (attributes.hasAttribute(QLatin1String("currency"))) {
0737                 Unit unit = m_unitMap.value(attributes.value(QLatin1String("currency")).toString());
0738                 if (unit.isValid()) {
0739                     const auto multiplier = attributes.value(QLatin1String("rate")).toDouble();
0740                     if (!qFuzzyIsNull(multiplier)) {
0741                         unit.setUnitMultiplier(1.0 / multiplier);
0742                         qCDebug(LOG_KUNITCONVERSION()) << "currency updated:" << unit.description() << multiplier;
0743                     }
0744                 }
0745             }
0746         }
0747     }
0748 
0749     if (xml.hasError()) {
0750         qCCritical(LOG_KUNITCONVERSION) << "currency conversion fetch could not parse obtained XML, update aborted";
0751         return false;
0752     }
0753     return true;
0754 }
0755 
0756 Value CurrencyCategoryPrivate::convert(const Value &value, const Unit &to)
0757 {
0758     if (!m_initialized) {
0759         m_initialized = readConversionTable(cacheLocation());
0760     }
0761 
0762     Value v = UnitCategoryPrivate::convert(value, to);
0763     return v;
0764 }
0765 
0766 } // KUnitConversion namespace