File indexing completed on 2024-04-28 16:30:15

0001 /***************************************************************************
0002  * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr
0003  * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  ***************************************************************************/
0006 /** @file
0007 * This file defines classes SKGUnitObject.
0008 *
0009 * @author Stephane MANKOWSKI / Guillaume DE BURE
0010 */
0011 #include "skgunitobject.h"
0012 
0013 #include <qdesktopservices.h>
0014 #include <qdir.h>
0015 #include <qdiriterator.h>
0016 #include <qfile.h>
0017 #include <qfileinfo.h>
0018 #include <qglobal.h>
0019 #include <qmath.h>
0020 #include <qprocess.h>
0021 #include <qregularexpression.h>
0022 #include <qsavefile.h>
0023 #include <qstandardpaths.h>
0024 
0025 #include <kconfig.h>
0026 #include <kconfiggroup.h>
0027 #include <klocalizedstring.h>
0028 #include <kservice.h>
0029 #include <kservicetypetrader.h>
0030 #include <qvariant.h>
0031 
0032 #include "skgdocumentbank.h"
0033 #include "skgoperationobject.h"
0034 #include "skgtraces.h"
0035 #include "skgtransactionmng.h"
0036 #include "skgunitvalueobject.h"
0037 
0038 SKGUnitObject::SKGUnitObject() : SKGUnitObject(nullptr)
0039 {}
0040 
0041 SKGUnitObject::SKGUnitObject(SKGDocument* iDocument, int iID) : SKGNamedObject(iDocument, QStringLiteral("v_unit"), iID)
0042 {}
0043 
0044 SKGUnitObject::~SKGUnitObject()
0045     = default;
0046 
0047 SKGUnitObject::SKGUnitObject(const SKGUnitObject& iObject) = default;
0048 
0049 SKGUnitObject::SKGUnitObject(const SKGNamedObject& iObject)
0050 {
0051     if (iObject.getRealTable() == QStringLiteral("unit")) {
0052         copyFrom(iObject);
0053     } else {
0054         *this = SKGNamedObject(iObject.getDocument(), QStringLiteral("v_unit"), iObject.getID());
0055     }
0056 }
0057 
0058 SKGUnitObject::SKGUnitObject(const SKGObjectBase& iObject)
0059 {
0060     if (iObject.getRealTable() == QStringLiteral("unit")) {
0061         copyFrom(iObject);
0062     } else {
0063         *this = SKGNamedObject(iObject.getDocument(), QStringLiteral("v_unit"), iObject.getID());
0064     }
0065 }
0066 
0067 SKGUnitObject& SKGUnitObject::operator= (const SKGObjectBase& iObject)
0068 {
0069     copyFrom(iObject);
0070     return *this;
0071 }
0072 
0073 SKGUnitObject& SKGUnitObject::operator= (const SKGUnitObject& iObject)
0074 {
0075     copyFrom(iObject);
0076     return *this;
0077 }
0078 
0079 
0080 QString SKGUnitObject::getWhereclauseId() const
0081 {
0082     QString output = SKGObjectBase::getWhereclauseId();  // clazy:exclude=skipped-base-method
0083     if (output.isEmpty()) {
0084         QString name = getName();
0085         if (!name.isEmpty()) {
0086             output = "t_name='" % SKGServices::stringToSqlString(name) % '\'';
0087         }
0088 
0089         QString symbol = getSymbol();
0090         if (!symbol.isEmpty()) {
0091             if (!output.isEmpty()) {
0092                 output += QStringLiteral(" OR ");
0093             }
0094             output += "t_symbol='" % SKGServices::stringToSqlString(symbol) % '\'';
0095         }
0096         if (!output.isEmpty()) {
0097             output = '(' % output % ')';
0098         }
0099     }
0100 
0101     return output;
0102 }
0103 
0104 QList<SKGServices::SKGUnitInfo> SKGUnitObject::currencies;
0105 
0106 QStringList SKGUnitObject::getListofKnownCurrencies(bool iIncludingObsolete)
0107 {
0108     SKGTRACEINFUNC(10)
0109     if (currencies.isEmpty()) {
0110         // Search currencies
0111         const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("skrooge/currency/"), QStandardPaths::LocateDirectory);
0112         for (const auto& dir : dirs) {
0113             auto listDesktopFiles = QDir(dir).entryList(QStringList() << QStringLiteral("*.desktop"));
0114             for (const auto& path : qAsConst(listDesktopFiles)) {
0115                 // Read the file
0116                 QFileInfo file(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("skrooge/currency/") + path));
0117                 KConfig cgFile(file.absoluteFilePath());
0118                 KConfigGroup cg(&cgFile, QStringLiteral("Currency Code"));
0119 
0120                 SKGServices::SKGUnitInfo unit;
0121                 unit.Name = cg.readEntry(QStringLiteral("Name"), QString()) + QStringLiteral(" (") + cg.readEntry(QStringLiteral("CurrencyCodeIsoAlpha3"), QString()) + QStringLiteral(")");
0122                 unit.Symbol = cg.readEntry(QStringLiteral("CurrencyUnitSymbolDefault"), QString());
0123                 if (unit.Symbol.isEmpty()) {
0124                     unit.Symbol = cg.readEntry(QStringLiteral("CurrencyCodeIsoAlpha3"), file.baseName());
0125                 }
0126                 unit.Value = 1;
0127                 unit.NbDecimal = cg.readEntry(QStringLiteral("CurrencyDecimalPlacesDisplay"), 2);
0128                 unit.Source = QStringLiteral("GrandTrunk");
0129                 unit.Date = cg.readEntry(QStringLiteral("CurrencyIntroducedDate"), QDate::currentDate());
0130                 unit.Obsolete = (cg.readEntry(QStringLiteral("CurrencySuspendedDate"), cg.readEntry(QStringLiteral("CurrencyWithdrawnDate"), QDate())) != QDate());
0131                 currencies.push_back(unit);
0132             }
0133         }
0134 
0135         // Add other units
0136         {
0137             // CAC40
0138             SKGServices::SKGUnitInfo info;
0139             info.Name = i18nc("Noun, a currency", "CAC 40");
0140             info.Symbol = info.Name;
0141             info.Country = i18nc("Noun, a country", "France");
0142             info.Date = QDate(1987, 1, 1);
0143             info.Internet = QStringLiteral("^FCHI");
0144             info.Source = QStringLiteral("Yahoo");
0145             info.NbDecimal = 2;
0146             info.Value = -1;
0147             currencies.push_back(info);
0148         }
0149         {
0150             // NASDAQ
0151             SKGServices::SKGUnitInfo info;
0152             info.Name = i18nc("Noun, a currency", "NASDAQ");
0153             info.Symbol = info.Name;
0154             info.Country = i18nc("Noun, a country", "United States");
0155             info.Date = QDate(1971, 2, 5);
0156             info.Internet = QStringLiteral("^IXIC");
0157             info.Source = QStringLiteral("Yahoo");
0158             info.NbDecimal = 2;
0159             info.Value = -1;
0160             currencies.push_back(info);
0161         }
0162         {
0163             // Dow Jones
0164             SKGServices::SKGUnitInfo info;
0165             info.Name = i18nc("Noun, a currency", "Dow Jones (DJIA)");
0166             info.Symbol = QStringLiteral("DJIA");
0167             info.Country = i18nc("Noun, a country", "United States");
0168             info.Date = QDate(1884, 1, 1);
0169             info.Internet = QStringLiteral("^DJI");
0170             info.Source = QStringLiteral("Yahoo");
0171             info.NbDecimal = 2;
0172             info.Value = -1;
0173             currencies.push_back(info);
0174         }
0175         {
0176             // SBF 120
0177             SKGServices::SKGUnitInfo info;
0178             info.Name = i18nc("Noun, a currency", "SBF 120");
0179             info.Symbol = info.Name;
0180             info.Country = i18nc("Noun, a country", "France");
0181             info.Date = QDate(1990, 12, 31);
0182             info.Internet = QStringLiteral("^SBF120");
0183             info.Source = QStringLiteral("Yahoo");
0184             info.NbDecimal = 2;
0185             info.Value = -1;
0186             currencies.push_back(info);
0187         }
0188         {
0189             // S&P 500
0190             SKGServices::SKGUnitInfo info;
0191             info.Name = i18nc("Noun, a currency", "S&P 500");
0192             info.Symbol = info.Name;
0193             info.Country = i18nc("Noun, a country", "United States");
0194             info.Date = QDate(1920, 1, 1);
0195             info.Internet = QStringLiteral("^GSPC");
0196             info.Source = QStringLiteral("Yahoo");
0197             info.NbDecimal = 2;
0198             info.Value = -1;
0199             currencies.push_back(info);
0200         }
0201         {
0202             // FTSE 100
0203             SKGServices::SKGUnitInfo info;
0204             info.Name = i18nc("Noun, a currency", "FTSE 100");
0205             info.Symbol = info.Name;
0206             info.Country = i18nc("Noun, a country", "England");
0207             info.Date = QDate(1984, 1, 3);
0208             info.Internet = QStringLiteral("^FTSE");
0209             info.Source = QStringLiteral("Yahoo");
0210             info.NbDecimal = 2;
0211             info.Value = -1;
0212             currencies.push_back(info);
0213         }
0214         {
0215             // DAX
0216             SKGServices::SKGUnitInfo info;
0217             info.Name = i18nc("Noun, a currency", "DAX");
0218             info.Symbol = info.Name;
0219             info.Country = i18nc("Noun, a country", "Germany");
0220             info.Date = QDate(1920, 1, 1);
0221             info.Internet = QStringLiteral("^GDAXI");
0222             info.Source = QStringLiteral("Yahoo");
0223             info.NbDecimal = 2;
0224             info.Value = -1;
0225             currencies.push_back(info);
0226         }
0227         {
0228             // NIKKEI 225
0229             SKGServices::SKGUnitInfo info;
0230             info.Name = i18nc("Noun, a currency", "NIKKEI 225");
0231             info.Symbol = info.Name;
0232             info.Country = i18nc("Noun, a country", "Japan");
0233             info.Date = QDate(1920, 1, 1);
0234             info.Internet = QStringLiteral("^N225");
0235             info.Source = QStringLiteral("Yahoo");
0236             info.NbDecimal = 2;
0237             info.Value = -1;
0238             currencies.push_back(info);
0239         }
0240         {
0241             // HANG SENG
0242             SKGServices::SKGUnitInfo info;
0243             info.Name = i18nc("Noun, a currency", "HANG SENG");
0244             info.Symbol = info.Name;
0245             info.Country = i18nc("Noun, a country", "China");
0246             info.Date = QDate(1920, 1, 1);
0247             info.Internet = QStringLiteral("^HSI");
0248             info.Source = QStringLiteral("Yahoo");
0249             info.NbDecimal = 2;
0250             info.Value = -1;
0251             currencies.push_back(info);
0252         }
0253         {
0254             // STRAITS TIMES
0255             SKGServices::SKGUnitInfo info;
0256             info.Name = i18nc("Noun, a currency", "STRAITS TIMES");
0257             info.Symbol = info.Name;
0258             info.Date = QDate(1920, 1, 1);
0259             info.Country = i18nc("Noun, a country", "Singapore");
0260             info.Internet = QStringLiteral("^STI");
0261             info.Source = QStringLiteral("Yahoo");
0262             info.NbDecimal = 2;
0263             info.Value = -1;
0264             currencies.push_back(info);
0265         }
0266         {
0267             // BITCOIN
0268             SKGServices::SKGUnitInfo info;
0269             info.Name = i18nc("Noun, a currency", "Bitcoin");
0270             info.Symbol = QStringLiteral("BTC");
0271             info.Date = QDate(2009, 2, 4);
0272             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0273             info.Internet = QStringLiteral("BTC");
0274             info.Source = QStringLiteral("CoinMarketCap");
0275             info.Parent = QStringLiteral("USD");
0276             info.NbDecimal = 4;
0277             info.Value = -1;
0278             currencies.push_back(info);
0279         }
0280         {
0281             // ETHEREUM
0282             SKGServices::SKGUnitInfo info;
0283             info.Name = i18nc("Noun, a cryptocurrency", "Ethereum");
0284             info.Symbol = QStringLiteral("ETH");
0285             info.Date = QDate(2009, 2, 4);
0286             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0287             info.Internet = QStringLiteral("ETH");
0288             info.Source = QStringLiteral("CoinMarketCap");
0289             info.Parent = QStringLiteral("USD");
0290             info.NbDecimal = 4;
0291             info.Value = -1;
0292             currencies.push_back(info);
0293         }
0294         {
0295             // RIPPLE
0296             SKGServices::SKGUnitInfo info;
0297             info.Name = i18nc("Noun, a cryptocurrency", "Ripple");
0298             info.Symbol = QStringLiteral("XRP");
0299             info.Date = QDate(2009, 2, 4);
0300             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0301             info.Internet = QStringLiteral("XRP");
0302             info.Source = QStringLiteral("CoinMarketCap");
0303             info.Parent = QStringLiteral("USD");
0304             info.NbDecimal = 4;
0305             info.Value = -1;
0306             currencies.push_back(info);
0307         }
0308         {
0309             // BITCOIN-CASH
0310             SKGServices::SKGUnitInfo info;
0311             info.Name = i18nc("Noun, a cryptocurrency", "Bitcoin Cash");
0312             info.Symbol = QStringLiteral("BCH");
0313             info.Date = QDate(2009, 2, 4);
0314             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0315             info.Internet = QStringLiteral("BCH");
0316             info.Source = QStringLiteral("CoinMarketCap");
0317             info.Parent = QStringLiteral("USD");
0318             info.NbDecimal = 4;
0319             info.Value = -1;
0320             currencies.push_back(info);
0321         }
0322         {
0323             // CARDANO
0324             SKGServices::SKGUnitInfo info;
0325             info.Name = i18nc("Noun, a cryptocurrency", "Cardano");
0326             info.Symbol = QStringLiteral("ADA");
0327             info.Date = QDate(2009, 2, 4);
0328             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0329             info.Internet = QStringLiteral("ADA");
0330             info.Source = QStringLiteral("CoinMarketCap");
0331             info.Parent = QStringLiteral("USD");
0332             info.NbDecimal = 4;
0333             info.Value = -1;
0334             currencies.push_back(info);
0335         }
0336         {
0337             // NEM
0338             SKGServices::SKGUnitInfo info;
0339             info.Name = i18nc("Noun, a cryptocurrency", "NEM");
0340             info.Symbol = QStringLiteral("XEM");
0341             info.Date = QDate(2009, 2, 4);
0342             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0343             info.Internet = QStringLiteral("XEM");
0344             info.Source = QStringLiteral("CoinMarketCap");
0345             info.Parent = QStringLiteral("USD");
0346             info.NbDecimal = 4;
0347             info.Value = -1;
0348             currencies.push_back(info);
0349         }
0350         {
0351             // LITECOIN
0352             SKGServices::SKGUnitInfo info;
0353             info.Name = i18nc("Noun, a cryptocurrency", "Litecoin");
0354             info.Symbol = QStringLiteral("LTC");
0355             info.Date = QDate(2009, 2, 4);
0356             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0357             info.Internet = QStringLiteral("LTC");
0358             info.Source = QStringLiteral("CoinMarketCap");
0359             info.Parent = QStringLiteral("USD");
0360             info.NbDecimal = 4;
0361             info.Value = -1;
0362             currencies.push_back(info);
0363         }
0364         {
0365             // STELLAR
0366             SKGServices::SKGUnitInfo info;
0367             info.Name = i18nc("Noun, a cryptocurrency", "Stellar");
0368             info.Symbol = QStringLiteral("XLM");
0369             info.Date = QDate(2009, 2, 4);
0370             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0371             info.Internet = QStringLiteral("XLM");
0372             info.Source = QStringLiteral("CoinMarketCap");
0373             info.Parent = QStringLiteral("USD");
0374             info.NbDecimal = 4;
0375             info.Value = -1;
0376             currencies.push_back(info);
0377         }
0378         {
0379             // IOTA
0380             SKGServices::SKGUnitInfo info;
0381             info.Name = i18nc("Noun, a cryptocurrency", "IOTA");
0382             info.Symbol = QStringLiteral("MIOTA");
0383             info.Date = QDate(2009, 2, 4);
0384             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0385             info.Internet = QStringLiteral("MIOTA");
0386             info.Source = QStringLiteral("CoinMarketCap");
0387             info.Parent = QStringLiteral("USD");
0388             info.NbDecimal = 4;
0389             info.Value = -1;
0390             currencies.push_back(info);
0391         }
0392         {
0393             // TRON
0394             SKGServices::SKGUnitInfo info;
0395             info.Name = i18nc("Noun, a cryptocurrency", "TRON");
0396             info.Symbol = QStringLiteral("TRX");
0397             info.Date = QDate(2009, 2, 4);
0398             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0399             info.Internet = QStringLiteral("TRX");
0400             info.Source = QStringLiteral("CoinMarketCap");
0401             info.Parent = QStringLiteral("USD");
0402             info.NbDecimal = 4;
0403             info.Value = -1;
0404             currencies.push_back(info);
0405         }
0406         {
0407             // DASH
0408             SKGServices::SKGUnitInfo info;
0409             info.Name = i18nc("Noun, a cryptocurrency", "Dash");
0410             info.Symbol = QStringLiteral("DASH");
0411             info.Date = QDate(2009, 2, 4);
0412             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0413             info.Internet = QStringLiteral("DASH");
0414             info.Source = QStringLiteral("CoinMarketCap");
0415             info.Parent = QStringLiteral("USD");
0416             info.NbDecimal = 4;
0417             info.Value = -1;
0418             currencies.push_back(info);
0419         }
0420         {
0421             // NEO
0422             SKGServices::SKGUnitInfo info;
0423             info.Name = i18nc("Noun, a cryptocurrency", "NEO");
0424             info.Symbol = QStringLiteral("NEO");
0425             info.Date = QDate(2009, 2, 4);
0426             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0427             info.Internet = QStringLiteral("NEO");
0428             info.Source = QStringLiteral("CoinMarketCap");
0429             info.Parent = QStringLiteral("USD");
0430             info.NbDecimal = 4;
0431             info.Value = -1;
0432             currencies.push_back(info);
0433         }
0434         {
0435             // MONERO
0436             SKGServices::SKGUnitInfo info;
0437             info.Name = i18nc("Noun, a cryptocurrency", "Monero");
0438             info.Symbol = QStringLiteral("XMR");
0439             info.Date = QDate(2009, 2, 4);
0440             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0441             info.Internet = QStringLiteral("XMR");
0442             info.Source = QStringLiteral("CoinMarketCap");
0443             info.Parent = QStringLiteral("USD");
0444             info.NbDecimal = 4;
0445             info.Value = -1;
0446             currencies.push_back(info);
0447         }
0448         {
0449             // EOS
0450             SKGServices::SKGUnitInfo info;
0451             info.Name = i18nc("Noun, a cryptocurrency", "EOS");
0452             info.Symbol = QStringLiteral("EOS");
0453             info.Date = QDate(2009, 2, 4);
0454             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0455             info.Internet = QStringLiteral("EOS");
0456             info.Source = QStringLiteral("CoinMarketCap");
0457             info.Parent = QStringLiteral("USD");
0458             info.NbDecimal = 4;
0459             info.Value = -1;
0460             currencies.push_back(info);
0461         }
0462         {
0463             // QTUM
0464             SKGServices::SKGUnitInfo info;
0465             info.Name = i18nc("Noun, a cryptocurrency", "Qtum");
0466             info.Symbol = QStringLiteral("QTUM");
0467             info.Date = QDate(2009, 2, 4);
0468             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0469             info.Internet = QStringLiteral("QTUM");
0470             info.Source = QStringLiteral("CoinMarketCap");
0471             info.Parent = QStringLiteral("USD");
0472             info.NbDecimal = 4;
0473             info.Value = -1;
0474             currencies.push_back(info);
0475         }
0476         {
0477             // ICON
0478             SKGServices::SKGUnitInfo info;
0479             info.Name = i18nc("Noun, a cryptocurrency", "ICON");
0480             info.Symbol = QStringLiteral("ICX");
0481             info.Date = QDate(2009, 2, 4);
0482             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0483             info.Internet = QStringLiteral("ICX");
0484             info.Source = QStringLiteral("CoinMarketCap");
0485             info.Parent = QStringLiteral("USD");
0486             info.NbDecimal = 4;
0487             info.Value = -1;
0488             currencies.push_back(info);
0489         }
0490         {
0491             // BITCOIN-GOLD
0492             SKGServices::SKGUnitInfo info;
0493             info.Name = i18nc("Noun, a cryptocurrency", "Bitcoin Gold");
0494             info.Symbol = QStringLiteral("BTG");
0495             info.Date = QDate(2009, 2, 4);
0496             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0497             info.Internet = QStringLiteral("BTG");
0498             info.Source = QStringLiteral("CoinMarketCap");
0499             info.Parent = QStringLiteral("USD");
0500             info.NbDecimal = 4;
0501             info.Value = -1;
0502             currencies.push_back(info);
0503         }
0504         {
0505             // LISK
0506             SKGServices::SKGUnitInfo info;
0507             info.Name = i18nc("Noun, a cryptocurrency", "Lisk");
0508             info.Symbol = QStringLiteral("LSK");
0509             info.Date = QDate(2009, 2, 4);
0510             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0511             info.Internet = QStringLiteral("LSK");
0512             info.Source = QStringLiteral("CoinMarketCap");
0513             info.Parent = QStringLiteral("USD");
0514             info.NbDecimal = 4;
0515             info.Value = -1;
0516             currencies.push_back(info);
0517         }
0518         {
0519             // RAIBLOCKS
0520             SKGServices::SKGUnitInfo info;
0521             info.Name = i18nc("Noun, a cryptocurrency", "RaiBlocks");
0522             info.Symbol = QStringLiteral("XRB");
0523             info.Date = QDate(2009, 2, 4);
0524             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0525             info.Internet = QStringLiteral("XRB");
0526             info.Source = QStringLiteral("CoinMarketCap");
0527             info.Parent = QStringLiteral("USD");
0528             info.NbDecimal = 4;
0529             info.Value = -1;
0530             currencies.push_back(info);
0531         }
0532         {
0533             // ETHEREUM-CLASSIC
0534             SKGServices::SKGUnitInfo info;
0535             info.Name = i18nc("Noun, a cryptocurrency", "Ethereum Classic");
0536             info.Symbol = QStringLiteral("ETC");
0537             info.Date = QDate(2009, 2, 4);
0538             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0539             info.Internet = QStringLiteral("ETC");
0540             info.Source = QStringLiteral("CoinMarketCap");
0541             info.Parent = QStringLiteral("USD");
0542             info.NbDecimal = 4;
0543             info.Value = -1;
0544             currencies.push_back(info);
0545         }
0546         {
0547             // VERGE
0548             SKGServices::SKGUnitInfo info;
0549             info.Name = i18nc("Noun, a cryptocurrency", "Verge");
0550             info.Symbol = QStringLiteral("XVG");
0551             info.Date = QDate(2009, 2, 4);
0552             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0553             info.Internet = QStringLiteral("XVG");
0554             info.Source = QStringLiteral("CoinMarketCap");
0555             info.Parent = QStringLiteral("USD");
0556             info.NbDecimal = 4;
0557             info.Value = -1;
0558             currencies.push_back(info);
0559         }
0560         {
0561             // SIACOIN
0562             SKGServices::SKGUnitInfo info;
0563             info.Name = i18nc("Noun, a cryptocurrency", "Siacoin");
0564             info.Symbol = QStringLiteral("SC");
0565             info.Date = QDate(2009, 2, 4);
0566             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0567             info.Internet = QStringLiteral("SC");
0568             info.Source = QStringLiteral("CoinMarketCap");
0569             info.Parent = QStringLiteral("USD");
0570             info.NbDecimal = 4;
0571             info.Value = -1;
0572             currencies.push_back(info);
0573         }
0574         {
0575             // OMISEGO
0576             SKGServices::SKGUnitInfo info;
0577             info.Name = i18nc("Noun, a cryptocurrency", "OmiseGO");
0578             info.Symbol = QStringLiteral("OMG");
0579             info.Date = QDate(2009, 2, 4);
0580             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0581             info.Internet = QStringLiteral("OMG");
0582             info.Source = QStringLiteral("CoinMarketCap");
0583             info.Parent = QStringLiteral("USD");
0584             info.NbDecimal = 4;
0585             info.Value = -1;
0586             currencies.push_back(info);
0587         }
0588         {
0589             // BYTECOIN-BCN
0590             SKGServices::SKGUnitInfo info;
0591             info.Name = i18nc("Noun, a cryptocurrency", "Bytecoin");
0592             info.Symbol = QStringLiteral("BCN");
0593             info.Date = QDate(2009, 2, 4);
0594             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0595             info.Internet = QStringLiteral("BCN");
0596             info.Source = QStringLiteral("CoinMarketCap");
0597             info.Parent = QStringLiteral("USD");
0598             info.NbDecimal = 4;
0599             info.Value = -1;
0600             currencies.push_back(info);
0601         }
0602         {
0603             // BITCONNECT
0604             SKGServices::SKGUnitInfo info;
0605             info.Name = i18nc("Noun, a cryptocurrency", "BitConnect");
0606             info.Symbol = QStringLiteral("BCC");
0607             info.Date = QDate(2009, 2, 4);
0608             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0609             info.Internet = QStringLiteral("BCC");
0610             info.Source = QStringLiteral("CoinMarketCap");
0611             info.Parent = QStringLiteral("USD");
0612             info.NbDecimal = 4;
0613             info.Value = -1;
0614             currencies.push_back(info);
0615         }
0616         {
0617             // POPULOUS
0618             SKGServices::SKGUnitInfo info;
0619             info.Name = i18nc("Noun, a cryptocurrency", "Populous");
0620             info.Symbol = QStringLiteral("PPT");
0621             info.Date = QDate(2009, 2, 4);
0622             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0623             info.Internet = QStringLiteral("PPT");
0624             info.Source = QStringLiteral("CoinMarketCap");
0625             info.Parent = QStringLiteral("USD");
0626             info.NbDecimal = 4;
0627             info.Value = -1;
0628             currencies.push_back(info);
0629         }
0630         {
0631             // STRATIS
0632             SKGServices::SKGUnitInfo info;
0633             info.Name = i18nc("Noun, a cryptocurrency", "Stratis");
0634             info.Symbol = QStringLiteral("STRAT");
0635             info.Date = QDate(2009, 2, 4);
0636             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0637             info.Internet = QStringLiteral("STRAT");
0638             info.Source = QStringLiteral("CoinMarketCap");
0639             info.Parent = QStringLiteral("USD");
0640             info.NbDecimal = 4;
0641             info.Value = -1;
0642             currencies.push_back(info);
0643         }
0644         {
0645             // ZCASH
0646             SKGServices::SKGUnitInfo info;
0647             info.Name = i18nc("Noun, a cryptocurrency", "Zcash");
0648             info.Symbol = QStringLiteral("ZEC");
0649             info.Date = QDate(2009, 2, 4);
0650             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0651             info.Internet = QStringLiteral("ZEC");
0652             info.Source = QStringLiteral("CoinMarketCap");
0653             info.Parent = QStringLiteral("USD");
0654             info.NbDecimal = 4;
0655             info.Value = -1;
0656             currencies.push_back(info);
0657         }
0658         {
0659             // DENTACOIN
0660             SKGServices::SKGUnitInfo info;
0661             info.Name = i18nc("Noun, a cryptocurrency", "Dentacoin");
0662             info.Symbol = QStringLiteral("DCN");
0663             info.Date = QDate(2009, 2, 4);
0664             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0665             info.Internet = QStringLiteral("DCN");
0666             info.Source = QStringLiteral("CoinMarketCap");
0667             info.Parent = QStringLiteral("USD");
0668             info.NbDecimal = 4;
0669             info.Value = -1;
0670             currencies.push_back(info);
0671         }
0672         {
0673             // BITSHARES
0674             SKGServices::SKGUnitInfo info;
0675             info.Name = i18nc("Noun, a cryptocurrency", "BitShares");
0676             info.Symbol = QStringLiteral("BTS");
0677             info.Date = QDate(2009, 2, 4);
0678             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0679             info.Internet = QStringLiteral("BTS");
0680             info.Source = QStringLiteral("CoinMarketCap");
0681             info.Parent = QStringLiteral("USD");
0682             info.NbDecimal = 4;
0683             info.Value = -1;
0684             currencies.push_back(info);
0685         }
0686         {
0687             // BINANCE-COIN
0688             SKGServices::SKGUnitInfo info;
0689             info.Name = i18nc("Noun, a cryptocurrency", "Binance Coin");
0690             info.Symbol = QStringLiteral("BNB");
0691             info.Date = QDate(2009, 2, 4);
0692             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0693             info.Internet = QStringLiteral("BNB");
0694             info.Source = QStringLiteral("CoinMarketCap");
0695             info.Parent = QStringLiteral("USD");
0696             info.NbDecimal = 4;
0697             info.Value = -1;
0698             currencies.push_back(info);
0699         }
0700         {
0701             // DOGECOIN
0702             SKGServices::SKGUnitInfo info;
0703             info.Name = i18nc("Noun, a cryptocurrency", "Dogecoin");
0704             info.Symbol = QStringLiteral("DOGE");
0705             info.Date = QDate(2009, 2, 4);
0706             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0707             info.Internet = QStringLiteral("DOGE");
0708             info.Source = QStringLiteral("CoinMarketCap");
0709             info.Parent = QStringLiteral("USD");
0710             info.NbDecimal = 4;
0711             info.Value = -1;
0712             currencies.push_back(info);
0713         }
0714         {
0715             // STATUS
0716             SKGServices::SKGUnitInfo info;
0717             info.Name = i18nc("Noun, a cryptocurrency", "Status");
0718             info.Symbol = QStringLiteral("SNT");
0719             info.Date = QDate(2009, 2, 4);
0720             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0721             info.Internet = QStringLiteral("SNT");
0722             info.Source = QStringLiteral("CoinMarketCap");
0723             info.Parent = QStringLiteral("USD");
0724             info.NbDecimal = 4;
0725             info.Value = -1;
0726             currencies.push_back(info);
0727         }
0728         {
0729             // ARDOR
0730             SKGServices::SKGUnitInfo info;
0731             info.Name = i18nc("Noun, a cryptocurrency", "Ardor");
0732             info.Symbol = QStringLiteral("ARDR");
0733             info.Date = QDate(2009, 2, 4);
0734             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0735             info.Internet = QStringLiteral("ARDR");
0736             info.Source = QStringLiteral("CoinMarketCap");
0737             info.Parent = QStringLiteral("USD");
0738             info.NbDecimal = 4;
0739             info.Value = -1;
0740             currencies.push_back(info);
0741         }
0742         {
0743             // KUCOIN-SHARES
0744             SKGServices::SKGUnitInfo info;
0745             info.Name = i18nc("Noun, a cryptocurrency", "KuCoin Shares");
0746             info.Symbol = QStringLiteral("KCS");
0747             info.Date = QDate(2009, 2, 4);
0748             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0749             info.Internet = QStringLiteral("KCS");
0750             info.Source = QStringLiteral("CoinMarketCap");
0751             info.Parent = QStringLiteral("USD");
0752             info.NbDecimal = 4;
0753             info.Value = -1;
0754             currencies.push_back(info);
0755         }
0756         {
0757             // TETHER
0758             SKGServices::SKGUnitInfo info;
0759             info.Name = i18nc("Noun, a cryptocurrency", "Tether");
0760             info.Symbol = QStringLiteral("USDT");
0761             info.Date = QDate(2009, 2, 4);
0762             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0763             info.Internet = QStringLiteral("USDT");
0764             info.Source = QStringLiteral("CoinMarketCap");
0765             info.Parent = QStringLiteral("USD");
0766             info.NbDecimal = 4;
0767             info.Value = -1;
0768             currencies.push_back(info);
0769         }
0770         {
0771             // STEEM
0772             SKGServices::SKGUnitInfo info;
0773             info.Name = i18nc("Noun, a cryptocurrency", "Steem");
0774             info.Symbol = QStringLiteral("STEEM");
0775             info.Date = QDate(2009, 2, 4);
0776             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0777             info.Internet = QStringLiteral("STEEM");
0778             info.Source = QStringLiteral("CoinMarketCap");
0779             info.Parent = QStringLiteral("USD");
0780             info.NbDecimal = 4;
0781             info.Value = -1;
0782             currencies.push_back(info);
0783         }
0784         {
0785             // WAVES
0786             SKGServices::SKGUnitInfo info;
0787             info.Name = i18nc("Noun, a cryptocurrency", "Waves");
0788             info.Symbol = QStringLiteral("WAVES");
0789             info.Date = QDate(2009, 2, 4);
0790             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0791             info.Internet = QStringLiteral("WAVES");
0792             info.Source = QStringLiteral("CoinMarketCap");
0793             info.Parent = QStringLiteral("USD");
0794             info.NbDecimal = 4;
0795             info.Value = -1;
0796             currencies.push_back(info);
0797         }
0798         {
0799             // VECHAIN
0800             SKGServices::SKGUnitInfo info;
0801             info.Name = i18nc("Noun, a cryptocurrency", "VeChain");
0802             info.Symbol = QStringLiteral("VEN");
0803             info.Date = QDate(2009, 2, 4);
0804             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0805             info.Internet = QStringLiteral("VEN");
0806             info.Source = QStringLiteral("CoinMarketCap");
0807             info.Parent = QStringLiteral("USD");
0808             info.NbDecimal = 4;
0809             info.Value = -1;
0810             currencies.push_back(info);
0811         }
0812         {
0813             // DIGIBYTE
0814             SKGServices::SKGUnitInfo info;
0815             info.Name = i18nc("Noun, a cryptocurrency", "DigiByte");
0816             info.Symbol = QStringLiteral("DGB");
0817             info.Date = QDate(2009, 2, 4);
0818             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0819             info.Internet = QStringLiteral("DGB");
0820             info.Source = QStringLiteral("CoinMarketCap");
0821             info.Parent = QStringLiteral("USD");
0822             info.NbDecimal = 4;
0823             info.Value = -1;
0824             currencies.push_back(info);
0825         }
0826         {
0827             // KOMODO
0828             SKGServices::SKGUnitInfo info;
0829             info.Name = i18nc("Noun, a cryptocurrency", "Komodo");
0830             info.Symbol = QStringLiteral("KMD");
0831             info.Date = QDate(2009, 2, 4);
0832             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0833             info.Internet = QStringLiteral("KMD");
0834             info.Source = QStringLiteral("CoinMarketCap");
0835             info.Parent = QStringLiteral("USD");
0836             info.NbDecimal = 4;
0837             info.Value = -1;
0838             currencies.push_back(info);
0839         }
0840         {
0841             // DRAGONCHAIN
0842             SKGServices::SKGUnitInfo info;
0843             info.Name = i18nc("Noun, a cryptocurrency", "Dragonchain");
0844             info.Symbol = QStringLiteral("DRGN");
0845             info.Date = QDate(2009, 2, 4);
0846             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0847             info.Internet = QStringLiteral("DRGN");
0848             info.Source = QStringLiteral("CoinMarketCap");
0849             info.Parent = QStringLiteral("USD");
0850             info.NbDecimal = 4;
0851             info.Value = -1;
0852             currencies.push_back(info);
0853         }
0854         {
0855             // AUGUR
0856             SKGServices::SKGUnitInfo info;
0857             info.Name = i18nc("Noun, a cryptocurrency", "Augur");
0858             info.Symbol = QStringLiteral("REP");
0859             info.Date = QDate(2009, 2, 4);
0860             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0861             info.Internet = QStringLiteral("REP");
0862             info.Source = QStringLiteral("CoinMarketCap");
0863             info.Parent = QStringLiteral("USD");
0864             info.NbDecimal = 4;
0865             info.Value = -1;
0866             currencies.push_back(info);
0867         }
0868         {
0869             // GOLEM-NETWORK-TOKENS
0870             SKGServices::SKGUnitInfo info;
0871             info.Name = i18nc("Noun, a cryptocurrency", "Golem");
0872             info.Symbol = QStringLiteral("GNT");
0873             info.Date = QDate(2009, 2, 4);
0874             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0875             info.Internet = QStringLiteral("GNT");
0876             info.Source = QStringLiteral("CoinMarketCap");
0877             info.Parent = QStringLiteral("USD");
0878             info.NbDecimal = 4;
0879             info.Value = -1;
0880             currencies.push_back(info);
0881         }
0882         {
0883             // VERITASEUM
0884             SKGServices::SKGUnitInfo info;
0885             info.Name = i18nc("Noun, a cryptocurrency", "Veritaseum");
0886             info.Symbol = QStringLiteral("VERI");
0887             info.Date = QDate(2009, 2, 4);
0888             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0889             info.Internet = QStringLiteral("VERI");
0890             info.Source = QStringLiteral("CoinMarketCap");
0891             info.Parent = QStringLiteral("USD");
0892             info.NbDecimal = 4;
0893             info.Value = -1;
0894             currencies.push_back(info);
0895         }
0896         {
0897             // HSHARE
0898             SKGServices::SKGUnitInfo info;
0899             info.Name = i18nc("Noun, a cryptocurrency", "Hshare");
0900             info.Symbol = QStringLiteral("HSR");
0901             info.Date = QDate(2009, 2, 4);
0902             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0903             info.Internet = QStringLiteral("HSR");
0904             info.Source = QStringLiteral("CoinMarketCap");
0905             info.Parent = QStringLiteral("USD");
0906             info.NbDecimal = 4;
0907             info.Value = -1;
0908             currencies.push_back(info);
0909         }
0910         {
0911             // KIN
0912             SKGServices::SKGUnitInfo info;
0913             info.Name = i18nc("Noun, a cryptocurrency", "Kin");
0914             info.Symbol = QStringLiteral("KIN");
0915             info.Date = QDate(2009, 2, 4);
0916             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0917             info.Internet = QStringLiteral("KIN");
0918             info.Source = QStringLiteral("CoinMarketCap");
0919             info.Parent = QStringLiteral("USD");
0920             info.NbDecimal = 4;
0921             info.Value = -1;
0922             currencies.push_back(info);
0923         }
0924         {
0925             // SALT
0926             SKGServices::SKGUnitInfo info;
0927             info.Name = i18nc("Noun, a cryptocurrency", "SALT");
0928             info.Symbol = QStringLiteral("SALT");
0929             info.Date = QDate(2009, 2, 4);
0930             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0931             info.Internet = QStringLiteral("SALT");
0932             info.Source = QStringLiteral("CoinMarketCap");
0933             info.Parent = QStringLiteral("USD");
0934             info.NbDecimal = 4;
0935             info.Value = -1;
0936             currencies.push_back(info);
0937         }
0938         {
0939             // ELECTRONEUM
0940             SKGServices::SKGUnitInfo info;
0941             info.Name = i18nc("Noun, a cryptocurrency", "Electroneum");
0942             info.Symbol = QStringLiteral("ETN");
0943             info.Date = QDate(2009, 2, 4);
0944             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0945             info.Internet = QStringLiteral("ETN");
0946             info.Source = QStringLiteral("CoinMarketCap");
0947             info.Parent = QStringLiteral("USD");
0948             info.NbDecimal = 4;
0949             info.Value = -1;
0950             currencies.push_back(info);
0951         }
0952         {
0953             // ARK
0954             SKGServices::SKGUnitInfo info;
0955             info.Name = i18nc("Noun, a cryptocurrency", "Ark");
0956             info.Symbol = QStringLiteral("ARK");
0957             info.Date = QDate(2009, 2, 4);
0958             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0959             info.Internet = QStringLiteral("ARK");
0960             info.Source = QStringLiteral("CoinMarketCap");
0961             info.Parent = QStringLiteral("USD");
0962             info.NbDecimal = 4;
0963             info.Value = -1;
0964             currencies.push_back(info);
0965         }
0966         {
0967             // DENT
0968             SKGServices::SKGUnitInfo info;
0969             info.Name = i18nc("Noun, a cryptocurrency", "Dent");
0970             info.Symbol = QStringLiteral("DENT");
0971             info.Date = QDate(2009, 2, 4);
0972             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0973             info.Internet = QStringLiteral("DENT");
0974             info.Source = QStringLiteral("CoinMarketCap");
0975             info.Parent = QStringLiteral("USD");
0976             info.NbDecimal = 4;
0977             info.Value = -1;
0978             currencies.push_back(info);
0979         }
0980         {
0981             // ETHOS
0982             SKGServices::SKGUnitInfo info;
0983             info.Name = i18nc("Noun, a cryptocurrency", "Ethos");
0984             info.Symbol = QStringLiteral("ETHOS");
0985             info.Date = QDate(2009, 2, 4);
0986             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
0987             info.Internet = QStringLiteral("ETHOS");
0988             info.Source = QStringLiteral("CoinMarketCap");
0989             info.Parent = QStringLiteral("USD");
0990             info.NbDecimal = 4;
0991             info.Value = -1;
0992             currencies.push_back(info);
0993         }
0994         {
0995             // BASIC-ATTENTION-TOKEN
0996             SKGServices::SKGUnitInfo info;
0997             info.Name = i18nc("Noun, a cryptocurrency", "Basic Attention Token");
0998             info.Symbol = QStringLiteral("BAT");
0999             info.Date = QDate(2009, 2, 4);
1000             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1001             info.Internet = QStringLiteral("BAT");
1002             info.Source = QStringLiteral("CoinMarketCap");
1003             info.Parent = QStringLiteral("USD");
1004             info.NbDecimal = 4;
1005             info.Value = -1;
1006             currencies.push_back(info);
1007         }
1008         {
1009             // REDDCOIN
1010             SKGServices::SKGUnitInfo info;
1011             info.Name = i18nc("Noun, a cryptocurrency", "ReddCoin");
1012             info.Symbol = QStringLiteral("RDD");
1013             info.Date = QDate(2009, 2, 4);
1014             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1015             info.Internet = QStringLiteral("RDD");
1016             info.Source = QStringLiteral("CoinMarketCap");
1017             info.Parent = QStringLiteral("USD");
1018             info.NbDecimal = 4;
1019             info.Value = -1;
1020             currencies.push_back(info);
1021         }
1022         {
1023             // 0X
1024             SKGServices::SKGUnitInfo info;
1025             info.Name = i18nc("Noun, a cryptocurrency", "0x");
1026             info.Symbol = QStringLiteral("ZRX");
1027             info.Date = QDate(2009, 2, 4);
1028             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1029             info.Internet = QStringLiteral("ZRX");
1030             info.Source = QStringLiteral("CoinMarketCap");
1031             info.Parent = QStringLiteral("USD");
1032             info.NbDecimal = 4;
1033             info.Value = -1;
1034             currencies.push_back(info);
1035         }
1036         {
1037             // DECRED
1038             SKGServices::SKGUnitInfo info;
1039             info.Name = i18nc("Noun, a cryptocurrency", "Decred");
1040             info.Symbol = QStringLiteral("DCR");
1041             info.Date = QDate(2009, 2, 4);
1042             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1043             info.Internet = QStringLiteral("DCR");
1044             info.Source = QStringLiteral("CoinMarketCap");
1045             info.Parent = QStringLiteral("USD");
1046             info.NbDecimal = 4;
1047             info.Value = -1;
1048             currencies.push_back(info);
1049         }
1050         {
1051             // NEXUS
1052             SKGServices::SKGUnitInfo info;
1053             info.Name = i18nc("Noun, a cryptocurrency", "Nexus");
1054             info.Symbol = QStringLiteral("NXS");
1055             info.Date = QDate(2009, 2, 4);
1056             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1057             info.Internet = QStringLiteral("NXS");
1058             info.Source = QStringLiteral("CoinMarketCap");
1059             info.Parent = QStringLiteral("USD");
1060             info.NbDecimal = 4;
1061             info.Value = -1;
1062             currencies.push_back(info);
1063         }
1064         {
1065             // EXPERIENCE-POINTS
1066             SKGServices::SKGUnitInfo info;
1067             info.Name = i18nc("Noun, a cryptocurrency", "Experience Points");
1068             info.Symbol = QStringLiteral("XP");
1069             info.Date = QDate(2009, 2, 4);
1070             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1071             info.Internet = QStringLiteral("XP");
1072             info.Source = QStringLiteral("CoinMarketCap");
1073             info.Parent = QStringLiteral("USD");
1074             info.NbDecimal = 4;
1075             info.Value = -1;
1076             currencies.push_back(info);
1077         }
1078         {
1079             // QASH
1080             SKGServices::SKGUnitInfo info;
1081             info.Name = i18nc("Noun, a cryptocurrency", "QASH");
1082             info.Symbol = QStringLiteral("QASH");
1083             info.Date = QDate(2009, 2, 4);
1084             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1085             info.Internet = QStringLiteral("QASH");
1086             info.Source = QStringLiteral("CoinMarketCap");
1087             info.Parent = QStringLiteral("USD");
1088             info.NbDecimal = 4;
1089             info.Value = -1;
1090             currencies.push_back(info);
1091         }
1092         {
1093             // KYBER-NETWORK
1094             SKGServices::SKGUnitInfo info;
1095             info.Name = i18nc("Noun, a cryptocurrency", "Kyber Network");
1096             info.Symbol = QStringLiteral("KNC");
1097             info.Date = QDate(2009, 2, 4);
1098             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1099             info.Internet = QStringLiteral("KNC");
1100             info.Source = QStringLiteral("CoinMarketCap");
1101             info.Parent = QStringLiteral("USD");
1102             info.NbDecimal = 4;
1103             info.Value = -1;
1104             currencies.push_back(info);
1105         }
1106         {
1107             // PIVX
1108             SKGServices::SKGUnitInfo info;
1109             info.Name = i18nc("Noun, a cryptocurrency", "PIVX");
1110             info.Symbol = QStringLiteral("PIVX");
1111             info.Date = QDate(2009, 2, 4);
1112             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1113             info.Internet = QStringLiteral("PIVX");
1114             info.Source = QStringLiteral("CoinMarketCap");
1115             info.Parent = QStringLiteral("USD");
1116             info.NbDecimal = 4;
1117             info.Value = -1;
1118             currencies.push_back(info);
1119         }
1120         {
1121             // FUNFAIR
1122             SKGServices::SKGUnitInfo info;
1123             info.Name = i18nc("Noun, a cryptocurrency", "FunFair");
1124             info.Symbol = QStringLiteral("FUN");
1125             info.Date = QDate(2009, 2, 4);
1126             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1127             info.Internet = QStringLiteral("FUN");
1128             info.Source = QStringLiteral("CoinMarketCap");
1129             info.Parent = QStringLiteral("USD");
1130             info.NbDecimal = 4;
1131             info.Value = -1;
1132             currencies.push_back(info);
1133         }
1134         {
1135             // FACTOM
1136             SKGServices::SKGUnitInfo info;
1137             info.Name = i18nc("Noun, a cryptocurrency", "Factom");
1138             info.Symbol = QStringLiteral("FCT");
1139             info.Date = QDate(2009, 2, 4);
1140             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1141             info.Internet = QStringLiteral("FCT");
1142             info.Source = QStringLiteral("CoinMarketCap");
1143             info.Parent = QStringLiteral("USD");
1144             info.NbDecimal = 4;
1145             info.Value = -1;
1146             currencies.push_back(info);
1147         }
1148         {
1149             // NEBLIO
1150             SKGServices::SKGUnitInfo info;
1151             info.Name = i18nc("Noun, a cryptocurrency", "Neblio");
1152             info.Symbol = QStringLiteral("NEBL");
1153             info.Date = QDate(2009, 2, 4);
1154             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1155             info.Internet = QStringLiteral("NEBL");
1156             info.Source = QStringLiteral("CoinMarketCap");
1157             info.Parent = QStringLiteral("USD");
1158             info.NbDecimal = 4;
1159             info.Value = -1;
1160             currencies.push_back(info);
1161         }
1162         {
1163             // REQUEST-NETWORK
1164             SKGServices::SKGUnitInfo info;
1165             info.Name = i18nc("Noun, a cryptocurrency", "Request Network");
1166             info.Symbol = QStringLiteral("REQ");
1167             info.Date = QDate(2009, 2, 4);
1168             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1169             info.Internet = QStringLiteral("REQ");
1170             info.Source = QStringLiteral("CoinMarketCap");
1171             info.Parent = QStringLiteral("USD");
1172             info.NbDecimal = 4;
1173             info.Value = -1;
1174             currencies.push_back(info);
1175         }
1176         {
1177             // AETERNITY
1178             SKGServices::SKGUnitInfo info;
1179             info.Name = i18nc("Noun, a cryptocurrency", "Aeternity");
1180             info.Symbol = QStringLiteral("AE");
1181             info.Date = QDate(2009, 2, 4);
1182             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1183             info.Internet = QStringLiteral("AE");
1184             info.Source = QStringLiteral("CoinMarketCap");
1185             info.Parent = QStringLiteral("USD");
1186             info.NbDecimal = 4;
1187             info.Value = -1;
1188             currencies.push_back(info);
1189         }
1190         {
1191             // SUBSTRATUM
1192             SKGServices::SKGUnitInfo info;
1193             info.Name = i18nc("Noun, a cryptocurrency", "Substratum");
1194             info.Symbol = QStringLiteral("SUB");
1195             info.Date = QDate(2009, 2, 4);
1196             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1197             info.Internet = QStringLiteral("SUB");
1198             info.Source = QStringLiteral("CoinMarketCap");
1199             info.Parent = QStringLiteral("USD");
1200             info.NbDecimal = 4;
1201             info.Value = -1;
1202             currencies.push_back(info);
1203         }
1204         {
1205             // POWER-LEDGER
1206             SKGServices::SKGUnitInfo info;
1207             info.Name = i18nc("Noun, a cryptocurrency", "Power Ledger");
1208             info.Symbol = QStringLiteral("POWR");
1209             info.Date = QDate(2009, 2, 4);
1210             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1211             info.Internet = QStringLiteral("POWR");
1212             info.Source = QStringLiteral("CoinMarketCap");
1213             info.Parent = QStringLiteral("USD");
1214             info.NbDecimal = 4;
1215             info.Value = -1;
1216             currencies.push_back(info);
1217         }
1218         {
1219             // WAX
1220             SKGServices::SKGUnitInfo info;
1221             info.Name = i18nc("Noun, a cryptocurrency", "WAX");
1222             info.Symbol = QStringLiteral("WAX");
1223             info.Date = QDate(2009, 2, 4);
1224             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1225             info.Internet = QStringLiteral("WAX");
1226             info.Source = QStringLiteral("CoinMarketCap");
1227             info.Parent = QStringLiteral("USD");
1228             info.NbDecimal = 4;
1229             info.Value = -1;
1230             currencies.push_back(info);
1231         }
1232         {
1233             // AELF
1234             SKGServices::SKGUnitInfo info;
1235             info.Name = i18nc("Noun, a cryptocurrency", "aelf");
1236             info.Symbol = QStringLiteral("ELF");
1237             info.Date = QDate(2009, 2, 4);
1238             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1239             info.Internet = QStringLiteral("ELF");
1240             info.Source = QStringLiteral("CoinMarketCap");
1241             info.Parent = QStringLiteral("USD");
1242             info.NbDecimal = 4;
1243             info.Value = -1;
1244             currencies.push_back(info);
1245         }
1246         {
1247             // BYTOM
1248             SKGServices::SKGUnitInfo info;
1249             info.Name = i18nc("Noun, a cryptocurrency", "Bytom");
1250             info.Symbol = QStringLiteral("BTM");
1251             info.Date = QDate(2009, 2, 4);
1252             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1253             info.Internet = QStringLiteral("BTM");
1254             info.Source = QStringLiteral("CoinMarketCap");
1255             info.Parent = QStringLiteral("USD");
1256             info.NbDecimal = 4;
1257             info.Value = -1;
1258             currencies.push_back(info);
1259         }
1260         {
1261             // AION
1262             SKGServices::SKGUnitInfo info;
1263             info.Name = i18nc("Noun, a cryptocurrency", "Aion");
1264             info.Symbol = QStringLiteral("AION");
1265             info.Date = QDate(2009, 2, 4);
1266             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1267             info.Internet = QStringLiteral("AION");
1268             info.Source = QStringLiteral("CoinMarketCap");
1269             info.Parent = QStringLiteral("USD");
1270             info.NbDecimal = 4;
1271             info.Value = -1;
1272             currencies.push_back(info);
1273         }
1274         {
1275             // RCHAIN
1276             SKGServices::SKGUnitInfo info;
1277             info.Name = i18nc("Noun, a cryptocurrency", "RChain");
1278             info.Symbol = QStringLiteral("RHOC");
1279             info.Date = QDate(2009, 2, 4);
1280             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1281             info.Internet = QStringLiteral("RHOC");
1282             info.Source = QStringLiteral("CoinMarketCap");
1283             info.Parent = QStringLiteral("USD");
1284             info.NbDecimal = 4;
1285             info.Value = -1;
1286             currencies.push_back(info);
1287         }
1288         {
1289             // DIGITALNOTE
1290             SKGServices::SKGUnitInfo info;
1291             info.Name = i18nc("Noun, a cryptocurrency", "DigitalNote");
1292             info.Symbol = QStringLiteral("XDN");
1293             info.Date = QDate(2009, 2, 4);
1294             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1295             info.Internet = QStringLiteral("XDN");
1296             info.Source = QStringLiteral("CoinMarketCap");
1297             info.Parent = QStringLiteral("USD");
1298             info.NbDecimal = 4;
1299             info.Value = -1;
1300             currencies.push_back(info);
1301         }
1302         {
1303             // ENIGMA-PROJECT
1304             SKGServices::SKGUnitInfo info;
1305             info.Name = i18nc("Noun, a cryptocurrency", "Enigma");
1306             info.Symbol = QStringLiteral("ENG");
1307             info.Date = QDate(2009, 2, 4);
1308             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1309             info.Internet = QStringLiteral("ENG");
1310             info.Source = QStringLiteral("CoinMarketCap");
1311             info.Parent = QStringLiteral("USD");
1312             info.NbDecimal = 4;
1313             info.Value = -1;
1314             currencies.push_back(info);
1315         }
1316         {
1317             // NXT
1318             SKGServices::SKGUnitInfo info;
1319             info.Name = i18nc("Noun, a cryptocurrency", "Nxt");
1320             info.Symbol = QStringLiteral("NXT");
1321             info.Date = QDate(2009, 2, 4);
1322             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1323             info.Internet = QStringLiteral("NXT");
1324             info.Source = QStringLiteral("CoinMarketCap");
1325             info.Parent = QStringLiteral("USD");
1326             info.NbDecimal = 4;
1327             info.Value = -1;
1328             currencies.push_back(info);
1329         }
1330         {
1331             // TIME-NEW-BANK
1332             SKGServices::SKGUnitInfo info;
1333             info.Name = i18nc("Noun, a cryptocurrency", "Time New Bank");
1334             info.Symbol = QStringLiteral("TNB");
1335             info.Date = QDate(2009, 2, 4);
1336             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1337             info.Internet = QStringLiteral("TNB");
1338             info.Source = QStringLiteral("CoinMarketCap");
1339             info.Parent = QStringLiteral("USD");
1340             info.NbDecimal = 4;
1341             info.Value = -1;
1342             currencies.push_back(info);
1343         }
1344         {
1345             // BITCOINDARK
1346             SKGServices::SKGUnitInfo info;
1347             info.Name = i18nc("Noun, a cryptocurrency", "BitcoinDark");
1348             info.Symbol = QStringLiteral("BTCD");
1349             info.Date = QDate(2009, 2, 4);
1350             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1351             info.Internet = QStringLiteral("BTCD");
1352             info.Source = QStringLiteral("CoinMarketCap");
1353             info.Parent = QStringLiteral("USD");
1354             info.NbDecimal = 4;
1355             info.Value = -1;
1356             currencies.push_back(info);
1357         }
1358         {
1359             // MONACOIN
1360             SKGServices::SKGUnitInfo info;
1361             info.Name = i18nc("Noun, a cryptocurrency", "MonaCoin");
1362             info.Symbol = QStringLiteral("MONA");
1363             info.Date = QDate(2009, 2, 4);
1364             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1365             info.Internet = QStringLiteral("MONA");
1366             info.Source = QStringLiteral("CoinMarketCap");
1367             info.Parent = QStringLiteral("USD");
1368             info.NbDecimal = 4;
1369             info.Value = -1;
1370             currencies.push_back(info);
1371         }
1372         {
1373             // QUANTSTAMP
1374             SKGServices::SKGUnitInfo info;
1375             info.Name = i18nc("Noun, a cryptocurrency", "Quantstamp");
1376             info.Symbol = QStringLiteral("QSP");
1377             info.Date = QDate(2009, 2, 4);
1378             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1379             info.Internet = QStringLiteral("QSP");
1380             info.Source = QStringLiteral("CoinMarketCap");
1381             info.Parent = QStringLiteral("USD");
1382             info.NbDecimal = 4;
1383             info.Value = -1;
1384             currencies.push_back(info);
1385         }
1386         {
1387             // MAIDSAFECOIN
1388             SKGServices::SKGUnitInfo info;
1389             info.Name = i18nc("Noun, a cryptocurrency", "MaidSafeCoin");
1390             info.Symbol = QStringLiteral("MAID");
1391             info.Date = QDate(2009, 2, 4);
1392             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1393             info.Internet = QStringLiteral("MAID");
1394             info.Source = QStringLiteral("CoinMarketCap");
1395             info.Parent = QStringLiteral("USD");
1396             info.NbDecimal = 4;
1397             info.Value = -1;
1398             currencies.push_back(info);
1399         }
1400         {
1401             // BYTEBALL
1402             SKGServices::SKGUnitInfo info;
1403             info.Name = i18nc("Noun, a cryptocurrency", "Byteball Bytes");
1404             info.Symbol = QStringLiteral("GBYTE");
1405             info.Date = QDate(2009, 2, 4);
1406             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1407             info.Internet = QStringLiteral("GBYTE");
1408             info.Source = QStringLiteral("CoinMarketCap");
1409             info.Parent = QStringLiteral("USD");
1410             info.NbDecimal = 4;
1411             info.Value = -1;
1412             currencies.push_back(info);
1413         }
1414         {
1415             // GAS
1416             SKGServices::SKGUnitInfo info;
1417             info.Name = i18nc("Noun, a cryptocurrency", "Gas");
1418             info.Symbol = QStringLiteral("GAS");
1419             info.Date = QDate(2009, 2, 4);
1420             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1421             info.Internet = QStringLiteral("GAS");
1422             info.Source = QStringLiteral("CoinMarketCap");
1423             info.Parent = QStringLiteral("USD");
1424             info.NbDecimal = 4;
1425             info.Value = -1;
1426             currencies.push_back(info);
1427         }
1428         {
1429             // CHAINLINK
1430             SKGServices::SKGUnitInfo info;
1431             info.Name = i18nc("Noun, a cryptocurrency", "ChainLink");
1432             info.Symbol = QStringLiteral("LINK");
1433             info.Date = QDate(2009, 2, 4);
1434             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1435             info.Internet = QStringLiteral("LINK");
1436             info.Source = QStringLiteral("CoinMarketCap");
1437             info.Parent = QStringLiteral("USD");
1438             info.NbDecimal = 4;
1439             info.Value = -1;
1440             currencies.push_back(info);
1441         }
1442         {
1443             // SYSCOIN
1444             SKGServices::SKGUnitInfo info;
1445             info.Name = i18nc("Noun, a cryptocurrency", "Syscoin");
1446             info.Symbol = QStringLiteral("SYS");
1447             info.Date = QDate(2009, 2, 4);
1448             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1449             info.Internet = QStringLiteral("SYS");
1450             info.Source = QStringLiteral("CoinMarketCap");
1451             info.Parent = QStringLiteral("USD");
1452             info.NbDecimal = 4;
1453             info.Value = -1;
1454             currencies.push_back(info);
1455         }
1456         {
1457             // SANTIMENT
1458             SKGServices::SKGUnitInfo info;
1459             info.Name = i18nc("Noun, a cryptocurrency", "Santiment Network Token");
1460             info.Symbol = QStringLiteral("SAN");
1461             info.Date = QDate(2009, 2, 4);
1462             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1463             info.Internet = QStringLiteral("SAN");
1464             info.Source = QStringLiteral("CoinMarketCap");
1465             info.Parent = QStringLiteral("USD");
1466             info.NbDecimal = 4;
1467             info.Value = -1;
1468             currencies.push_back(info);
1469         }
1470         {
1471             // COBINHOOD
1472             SKGServices::SKGUnitInfo info;
1473             info.Name = i18nc("Noun, a cryptocurrency", "Cobinhood");
1474             info.Symbol = QStringLiteral("COB");
1475             info.Date = QDate(2009, 2, 4);
1476             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1477             info.Internet = QStringLiteral("COB");
1478             info.Source = QStringLiteral("CoinMarketCap");
1479             info.Parent = QStringLiteral("USD");
1480             info.NbDecimal = 4;
1481             info.Value = -1;
1482             currencies.push_back(info);
1483         }
1484         {
1485             // RED-PULSE
1486             SKGServices::SKGUnitInfo info;
1487             info.Name = i18nc("Noun, a cryptocurrency", "Red Pulse");
1488             info.Symbol = QStringLiteral("RPX");
1489             info.Date = QDate(2009, 2, 4);
1490             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1491             info.Internet = QStringLiteral("RPX");
1492             info.Source = QStringLiteral("CoinMarketCap");
1493             info.Parent = QStringLiteral("USD");
1494             info.NbDecimal = 4;
1495             info.Value = -1;
1496             currencies.push_back(info);
1497         }
1498         {
1499             // DIGIXDAO
1500             SKGServices::SKGUnitInfo info;
1501             info.Name = i18nc("Noun, a cryptocurrency", "DigixDAO");
1502             info.Symbol = QStringLiteral("DGD");
1503             info.Date = QDate(2009, 2, 4);
1504             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1505             info.Internet = QStringLiteral("DGD");
1506             info.Source = QStringLiteral("CoinMarketCap");
1507             info.Parent = QStringLiteral("USD");
1508             info.NbDecimal = 4;
1509             info.Value = -1;
1510             currencies.push_back(info);
1511         }
1512         {
1513             // TENX
1514             SKGServices::SKGUnitInfo info;
1515             info.Name = i18nc("Noun, a cryptocurrency", "TenX");
1516             info.Symbol = QStringLiteral("PAY");
1517             info.Date = QDate(2009, 2, 4);
1518             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1519             info.Internet = QStringLiteral("PAY");
1520             info.Source = QStringLiteral("CoinMarketCap");
1521             info.Parent = QStringLiteral("USD");
1522             info.NbDecimal = 4;
1523             info.Value = -1;
1524             currencies.push_back(info);
1525         }
1526         {
1527             // ICONOMI
1528             SKGServices::SKGUnitInfo info;
1529             info.Name = i18nc("Noun, a cryptocurrency", "Iconomi");
1530             info.Symbol = QStringLiteral("ICN");
1531             info.Date = QDate(2009, 2, 4);
1532             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1533             info.Internet = QStringLiteral("ICN");
1534             info.Source = QStringLiteral("CoinMarketCap");
1535             info.Parent = QStringLiteral("USD");
1536             info.NbDecimal = 4;
1537             info.Value = -1;
1538             currencies.push_back(info);
1539         }
1540         {
1541             // POET
1542             SKGServices::SKGUnitInfo info;
1543             info.Name = i18nc("Noun, a cryptocurrency", "Po.et");
1544             info.Symbol = QStringLiteral("POE");
1545             info.Date = QDate(2009, 2, 4);
1546             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1547             info.Internet = QStringLiteral("POE");
1548             info.Source = QStringLiteral("CoinMarketCap");
1549             info.Parent = QStringLiteral("USD");
1550             info.NbDecimal = 4;
1551             info.Value = -1;
1552             currencies.push_back(info);
1553         }
1554         {
1555             // ZCOIN
1556             SKGServices::SKGUnitInfo info;
1557             info.Name = i18nc("Noun, a cryptocurrency", "ZCoin");
1558             info.Symbol = QStringLiteral("XZC");
1559             info.Date = QDate(2009, 2, 4);
1560             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1561             info.Internet = QStringLiteral("XZC");
1562             info.Source = QStringLiteral("CoinMarketCap");
1563             info.Parent = QStringLiteral("USD");
1564             info.NbDecimal = 4;
1565             info.Value = -1;
1566             currencies.push_back(info);
1567         }
1568         {
1569             // GNOSIS-GNO
1570             SKGServices::SKGUnitInfo info;
1571             info.Name = i18nc("Noun, a cryptocurrency", "Gnosis");
1572             info.Symbol = QStringLiteral("GNO");
1573             info.Date = QDate(2009, 2, 4);
1574             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1575             info.Internet = QStringLiteral("GNO");
1576             info.Source = QStringLiteral("CoinMarketCap");
1577             info.Parent = QStringLiteral("USD");
1578             info.NbDecimal = 4;
1579             info.Value = -1;
1580             currencies.push_back(info);
1581         }
1582         {
1583             // BLOCKV
1584             SKGServices::SKGUnitInfo info;
1585             info.Name = i18nc("Noun, a cryptocurrency", "BLOCKv");
1586             info.Symbol = QStringLiteral("VEE");
1587             info.Date = QDate(2009, 2, 4);
1588             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1589             info.Internet = QStringLiteral("VEE");
1590             info.Source = QStringLiteral("CoinMarketCap");
1591             info.Parent = QStringLiteral("USD");
1592             info.NbDecimal = 4;
1593             info.Value = -1;
1594             currencies.push_back(info);
1595         }
1596         {
1597             // WALTON
1598             SKGServices::SKGUnitInfo info;
1599             info.Name = i18nc("Noun, a cryptocurrency", "Walton");
1600             info.Symbol = QStringLiteral("WTC");
1601             info.Date = QDate(2009, 2, 4);
1602             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1603             info.Internet = QStringLiteral("WTC");
1604             info.Source = QStringLiteral("CoinMarketCap");
1605             info.Parent = QStringLiteral("USD");
1606             info.NbDecimal = 4;
1607             info.Value = -1;
1608             currencies.push_back(info);
1609         }
1610         {
1611             // PACCOIN
1612             SKGServices::SKGUnitInfo info;
1613             info.Name = i18nc("Noun, a cryptocurrency", "PACcoin");
1614             info.Symbol = QStringLiteral("PAC");
1615             info.Date = QDate(2009, 2, 4);
1616             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1617             info.Internet = QStringLiteral("PAC");
1618             info.Source = QStringLiteral("CoinMarketCap");
1619             info.Parent = QStringLiteral("USD");
1620             info.NbDecimal = 4;
1621             info.Value = -1;
1622             currencies.push_back(info);
1623         }
1624         {
1625             // DEEPBRAIN-CHAIN
1626             SKGServices::SKGUnitInfo info;
1627             info.Name = i18nc("Noun, a cryptocurrency", "DeepBrain Chain");
1628             info.Symbol = QStringLiteral("DBC");
1629             info.Date = QDate(2009, 2, 4);
1630             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1631             info.Internet = QStringLiteral("DBC");
1632             info.Source = QStringLiteral("CoinMarketCap");
1633             info.Parent = QStringLiteral("USD");
1634             info.NbDecimal = 4;
1635             info.Value = -1;
1636             currencies.push_back(info);
1637         }
1638         {
1639             // ETHLEND
1640             SKGServices::SKGUnitInfo info;
1641             info.Name = i18nc("Noun, a cryptocurrency", "ETHLend");
1642             info.Symbol = QStringLiteral("LEND");
1643             info.Date = QDate(2009, 2, 4);
1644             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1645             info.Internet = QStringLiteral("LEND");
1646             info.Source = QStringLiteral("CoinMarketCap");
1647             info.Parent = QStringLiteral("USD");
1648             info.NbDecimal = 4;
1649             info.Value = -1;
1650             currencies.push_back(info);
1651         }
1652         {
1653             // CIVIC
1654             SKGServices::SKGUnitInfo info;
1655             info.Name = i18nc("Noun, a cryptocurrency", "Civic");
1656             info.Symbol = QStringLiteral("CVC");
1657             info.Date = QDate(2009, 2, 4);
1658             info.Country = i18nc("Noun, the country of bitcoin", "Internet");
1659             info.Internet = QStringLiteral("CVC");
1660             info.Source = QStringLiteral("CoinMarketCap");
1661             info.Parent = QStringLiteral("USD");
1662             info.NbDecimal = 4;
1663             info.Value = -1;
1664             currencies.push_back(info);
1665         }
1666     }
1667     QStringList output;
1668     output.reserve(currencies.count());
1669     for (const auto& unit : qAsConst(currencies)) {
1670         if (iIncludingObsolete || !unit.Obsolete) {
1671             output.push_back(unit.Name);
1672         }
1673     }
1674     output.sort();
1675     return output;
1676 }
1677 
1678 QString SKGUnitObject::getInternationalCode(const QString& iUnitName)
1679 {
1680     SKGTRACEINFUNC(10)
1681     QString output = iUnitName;
1682     auto match = QRegularExpression(QStringLiteral(".*\\(([^\\(\\)]+)\\)[^\\(\\)]*")).match(iUnitName);
1683     if (match.hasMatch()) {
1684         output = match.captured(1);
1685     }
1686 
1687     return output;
1688 }
1689 
1690 SKGServices::SKGUnitInfo SKGUnitObject::getUnitInfo()
1691 {
1692     SKGTRACEINFUNC(10)
1693     SKGServices::SKGUnitInfo info;
1694     info.Name = getName();
1695     info.Value = getAmount();
1696     info.NbDecimal = getNumberDecimal();
1697     info.Symbol = getSymbol();
1698     info.Country = getCountry();
1699     info.Internet = getInternetCode();
1700     info.Date = QDate::currentDate();
1701 
1702     return info;
1703 }
1704 
1705 SKGServices::SKGUnitInfo SKGUnitObject::getUnitInfo(const QString& iUnitName)
1706 {
1707     SKGTRACEINFUNC(10)
1708     SKGServices::SKGUnitInfo info;
1709     if (currencies.isEmpty()) {
1710         getListofKnownCurrencies(false);
1711     }
1712     QString isoCode = getInternationalCode(iUnitName);
1713     for (const auto& unit : qAsConst(currencies)) {
1714         if (getInternationalCode(unit.Name) == isoCode) {
1715             info = unit;
1716             break;
1717         }
1718     }
1719     return info;
1720 }
1721 
1722 SKGError SKGUnitObject::createCurrencyUnit(SKGDocumentBank* iDocument, const QString& iUnitName, SKGUnitObject& oUnit)
1723 {
1724     SKGError err;
1725     SKGTRACEINFUNCRC(10, err)
1726     if (iDocument != nullptr) {
1727         SKGUnitObject parentUnit;
1728         oUnit = SKGUnitObject(iDocument);
1729 
1730         SKGUnitObject::UnitType type = SKGUnitObject::CURRENCY;
1731         SKGServices::SKGUnitInfo prim = iDocument->getPrimaryUnit();
1732         SKGServices::SKGUnitInfo seco = iDocument->getSecondaryUnit();
1733 
1734         // Get information on the unit
1735         SKGServices::SKGUnitInfo info = getUnitInfo(iUnitName);
1736         if (info.Name.isEmpty()) {
1737             err = SKGError(ERR_INVALIDARG, i18nc("Error message", "Unknown unit '%1'", iUnitName));
1738         }
1739         if (!err && !info.Parent.isEmpty()) {
1740             err = createCurrencyUnit(iDocument, info.Parent, parentUnit);
1741         }
1742 
1743         // Set the type
1744         if (info.Name == info.Symbol) {
1745             // This is an index
1746             type = SKGUnitObject::INDEX;
1747         } else if (!info.Parent.isEmpty()) {
1748             // This is a secondary unit
1749             type = (seco.Symbol.isEmpty() || seco.Symbol == info.Symbol  ? SKGUnitObject::SECONDARY : SKGUnitObject::CURRENCY);
1750         } else {
1751             // As primary
1752             type = (prim.Symbol.isEmpty() || prim.Symbol == info.Symbol ? SKGUnitObject::PRIMARY : SKGUnitObject::CURRENCY);
1753         }
1754 
1755         // Point on primary unit
1756         if (info.Value == 1 && !err && (type == SKGUnitObject::CURRENCY || type == SKGUnitObject::SECONDARY)) {
1757             SKGUnitObject primunit(iDocument);
1758             err = primunit.setSymbol(prim.Symbol);
1759             IFOKDO(err, primunit.load())
1760             IFOK(err) {
1761                 QString codeprimunit = getInternationalCode(primunit.getName());
1762                 QString codeunit = getInternationalCode(info.Name);
1763                 if (!codeprimunit.isEmpty()) {
1764                     info.Internet = codeunit % '/' % codeprimunit;
1765                     info.Value = -1;
1766 
1767                     parentUnit = SKGUnitObject(iDocument);
1768                     err = parentUnit.setSymbol(prim.Symbol);
1769                     IFOKDO(err, parentUnit.load())
1770                 }
1771             }
1772         }
1773 
1774         IFOKDO(err, oUnit.setName(info.Name))
1775         if (!err && oUnit.exist()) {
1776             err = oUnit.load();
1777         }
1778         IFOKDO(err, oUnit.setType(type))
1779         IFOKDO(err, oUnit.setSymbol(info.Symbol))
1780         IFOKDO(err, oUnit.setInternetCode(info.Internet))
1781         IFOKDO(err, oUnit.setDownloadSource(info.Source))
1782         IFOKDO(err, oUnit.setCountry(info.Country))
1783         IFOKDO(err, oUnit.setNumberDecimal(info.NbDecimal))
1784         if (!err && parentUnit.exist()) {
1785             err = oUnit.setUnit(parentUnit);
1786         }
1787         IFOKDO(err, oUnit.save())
1788 
1789         // Creation of the value
1790         if (info.Value > 0) {
1791             SKGUnitValueObject unitValue;
1792             IFOKDO(err, oUnit.addUnitValue(unitValue))
1793             IFOKDO(err, unitValue.setDate(info.Date))
1794             IFOKDO(err, unitValue.setQuantity(info.Value))
1795             IFOKDO(err, unitValue.save())
1796         }
1797     }
1798     return err;
1799 }
1800 
1801 double SKGUnitObject::convert(double iValue, const SKGUnitObject& iUnitFrom, const SKGUnitObject& iUnitTo, QDate iDate)
1802 {
1803     double output = iValue;
1804     if (iUnitFrom != iUnitTo) {
1805         double valFrom = iUnitFrom.getAmount(iDate);
1806         double valTo = iUnitTo.getAmount(iDate);
1807         output = iValue * valFrom / valTo;
1808     }
1809     return output;
1810 }
1811 
1812 SKGError SKGUnitObject::setSymbol(const QString& iSymbol)
1813 {
1814     return setAttribute(QStringLiteral("t_symbol"), iSymbol);
1815 }
1816 
1817 QString SKGUnitObject::getSymbol() const
1818 {
1819     return getAttribute(QStringLiteral("t_symbol"));
1820 }
1821 
1822 QString SKGUnitObject::getDownloadSource() const
1823 {
1824     return getAttribute(QStringLiteral("t_source"));
1825 }
1826 
1827 SKGError SKGUnitObject::setDownloadSource(const QString& iSource)
1828 {
1829     return setAttribute(QStringLiteral("t_source"), iSource);
1830 }
1831 
1832 SKGError SKGUnitObject::setNumberDecimal(int iNb)
1833 {
1834     return setAttribute(QStringLiteral("i_nbdecimal"), SKGServices::intToString(iNb));
1835 }
1836 
1837 int SKGUnitObject::getNumberDecimal() const
1838 {
1839     return SKGServices::stringToInt(getAttribute(QStringLiteral("i_nbdecimal")));
1840 }
1841 
1842 SKGError SKGUnitObject::setCountry(const QString& iCountry)
1843 {
1844     return setAttribute(QStringLiteral("t_country"), iCountry);
1845 }
1846 
1847 QString SKGUnitObject::getCountry() const
1848 {
1849     return getAttribute(QStringLiteral("t_country"));
1850 }
1851 
1852 SKGError SKGUnitObject::setInternetCode(const QString& iCode)
1853 {
1854     return setAttribute(QStringLiteral("t_internet_code"), iCode);
1855 }
1856 
1857 QString SKGUnitObject::getInternetCode() const
1858 {
1859     return getAttribute(QStringLiteral("t_internet_code"));
1860 }
1861 
1862 SKGError SKGUnitObject::setType(SKGUnitObject::UnitType iType)
1863 {
1864     SKGError err;
1865     if (getAttribute(QStringLiteral("t_type")).isEmpty() || this->getType() != iType) {
1866         // Guaranty that PRIMARY and SECONDARY is unique
1867         if (iType == PRIMARY || iType == SECONDARY) {
1868             // Set old SECONDARY as CURRENCY
1869             err = getDocument()->executeSqliteOrder(QStringLiteral("UPDATE unit SET t_type='C' WHERE t_type='2'"));
1870 
1871             // Set old PRIMARY as SECONDARY
1872             if (!err && iType == PRIMARY) {
1873                 err = getDocument()->executeSqliteOrder(QStringLiteral("UPDATE unit SET t_type='2' WHERE t_type='1'"));
1874             }
1875         }
1876     }
1877     IFOKDO(err, setAttribute(QStringLiteral("t_type"), (iType == CURRENCY ? QStringLiteral("C") : (iType == PRIMARY ? QStringLiteral("1") : (iType == SECONDARY ? QStringLiteral("2") : (iType == SHARE ? QStringLiteral("S") : (iType == INDEX ? QStringLiteral("I") : QStringLiteral("O"))))))))
1878     return err;
1879 }
1880 
1881 SKGUnitObject::UnitType SKGUnitObject::getType() const
1882 {
1883     QString typeString = getAttribute(QStringLiteral("t_type"));
1884     return (typeString == QStringLiteral("C") ? CURRENCY : (typeString == QStringLiteral("S") ? SHARE : (typeString == QStringLiteral("1") ? PRIMARY : (typeString == QStringLiteral("2") ? SECONDARY : (typeString == QStringLiteral("I") ? INDEX : OBJECT)))));
1885 }
1886 
1887 SKGError SKGUnitObject::getUnit(SKGUnitObject& oUnit) const
1888 {
1889     SKGError err;
1890     if (getDocument() != nullptr) {
1891         err = getDocument()->getObject(QStringLiteral("v_unit"), "id=" % getAttribute(QStringLiteral("rd_unit_id")), oUnit);
1892     }
1893     return err;
1894 }
1895 
1896 SKGError SKGUnitObject::setUnit(const SKGUnitObject& iUnit)
1897 {
1898     SKGError err;
1899     if (*this == iUnit && iUnit.getID() != 0) {
1900         err = SKGError(ERR_INVALIDARG, i18nc("Error message", "Reference unit of a unit cannot be itself."));
1901     } else {
1902         err = setAttribute(QStringLiteral("rd_unit_id"), SKGServices::intToString(iUnit.getID()));
1903     }
1904     return err;
1905 }
1906 
1907 SKGError SKGUnitObject::removeUnit()
1908 {
1909     return setAttribute(QStringLiteral("rd_unit_id"), QStringLiteral("0"));
1910 }
1911 
1912 SKGError SKGUnitObject::addUnitValue(SKGUnitValueObject& oUnitValue)
1913 {
1914     SKGError err;
1915     if (getID() == 0) {
1916         err = SKGError(ERR_FAIL, i18nc("Error message", "%1 failed because linked object is not yet saved in the database.", QStringLiteral("SKGUnitObject::addUnitValue")));
1917     } else {
1918         oUnitValue = SKGUnitValueObject(qobject_cast<SKGDocumentBank*>(getDocument()));
1919         err = oUnitValue.setAttribute(QStringLiteral("rd_unit_id"), SKGServices::intToString(getID()));
1920     }
1921     return err;
1922 }
1923 
1924 SKGError SKGUnitObject::simplify()
1925 {
1926     SKGListSKGObjectBase values;
1927     SKGError err = getUnitValues(values);
1928     int nb = values.count();
1929     if (!err && (nb != 0)) {
1930         QHash<QString, SKGListSKGObjectBase> groups;
1931 
1932         SKGBEGINPROGRESSTRANSACTION(*getDocument(), "#INTERNAL#" % i18nc("Progression step", "Simplify unit"), err, 2)
1933         // Build groups
1934         {
1935             SKGBEGINPROGRESSTRANSACTION(*getDocument(), "#INTERNAL#" % i18nc("Progression step", "Analyze unit"), err, nb)
1936             QDate limit1 = QDate::currentDate().addMonths(-3);
1937             QDate limit2 = QDate::currentDate().addYears(-1);
1938             QDate limit3 = QDate::currentDate().addYears(-3);
1939             for (int i = nb - 1; !err && i >= 0 ; --i) {
1940                 SKGUnitValueObject v(values.at(i));
1941                 QDate date = v.getDate();
1942                 if (date >= limit1) {
1943                     // No simplification ==> nothing to do
1944                 } else if (date >= limit2) {
1945                     // Simplification by group of 30 days
1946                     QString key = limit1.addDays(30 * (limit1.daysTo(date) / 30)).toString();
1947                     SKGListSKGObjectBase group = groups[key];
1948                     group.push_back(v);
1949                     groups[key] = group;
1950 
1951                 } else if (date >= limit3) {
1952                     // Simplification by group of 2 months
1953                     QString key = limit2.addDays(60 * (limit2.daysTo(date) / 60)).toString();
1954                     SKGListSKGObjectBase group = groups[key];
1955                     group.push_back(v);
1956                     groups[key] = group;
1957                 } else {
1958                     // Simplification by group of 6 months
1959                     QString key = limit3.addDays(180 * (limit2.daysTo(date) / 180)).toString();
1960                     SKGListSKGObjectBase group = groups[key];
1961                     group.push_back(v);
1962                     groups[key] = group;
1963                 }
1964 
1965                 IFOKDO(err, getDocument()->stepForward(nb - i))
1966             }
1967         }
1968         IFOKDO(err, getDocument()->stepForward(1))
1969 
1970         // Simplify
1971         {
1972             QList<QString> keys = groups.keys();
1973             nb = keys.count();
1974             SKGBEGINPROGRESSTRANSACTION(*getDocument(), "#INTERNAL#" % i18nc("Progression step", "Remove useless values"), err, nb)
1975             for (int i = 0; !err && i < nb ; ++i) {
1976                 const QString& k = keys.at(i);
1977                 SKGListSKGObjectBase group = groups[k];
1978 
1979                 // Simplify the group
1980                 int nb2 = group.count();
1981 
1982                 // Compute min and max
1983                 double min = 10e20;
1984                 double max = 0;
1985                 for (int j = 0; j < nb2; ++j) {
1986                     SKGUnitValueObject v1(group.at(j));
1987                     double y1 = v1.getQuantity();
1988                     min = qMin(y1, min);
1989                     max = qMax(y1, max);
1990                 }
1991 
1992                 // Simplify
1993                 for (int j = 1; !err && j < nb2 - 1; ++j) {
1994                     SKGUnitValueObject v1(group.at(j));
1995                     double y1 = v1.getQuantity();
1996                     if (y1 != min && y1 != max) {
1997                         err = v1.remove();
1998                     }
1999                 }
2000 
2001                 IFOKDO(err, getDocument()->stepForward(i + 1))
2002             }
2003         }
2004         IFOKDO(err, getDocument()->stepForward(2))
2005     }
2006     return err;
2007 }
2008 
2009 SKGError SKGUnitObject::getUnitValues(SKGListSKGObjectBase& oUnitValueList) const
2010 {
2011     SKGError err = getDocument()->getObjects(QStringLiteral("v_unitvalue"),
2012                    "rd_unit_id=" % SKGServices::intToString(getID()) % " ORDER BY d_date",
2013                    oUnitValueList);
2014     return err;
2015 }
2016 
2017 SKGError SKGUnitObject::getLastUnitValue(SKGUnitValueObject& oUnitValue) const
2018 {
2019     return SKGObjectBase::getDocument()->getObject(QStringLiteral("v_unitvalue"),
2020             "rd_unit_id=" % SKGServices::intToString(getID()) % " AND d_date=(select MAX(u2.d_date) from unitvalue u2 where u2.rd_unit_id=" % SKGServices::intToString(getID()) % ')',
2021             oUnitValue);
2022 }
2023 
2024 SKGError SKGUnitObject::getUnitValue(QDate iDate, SKGUnitValueObject& oUnitValue) const
2025 {
2026     QString ids = SKGServices::intToString(getID());
2027     QString dates = SKGServices::dateToSqlString(iDate);
2028     SKGError err = SKGObjectBase::getDocument()->getObject(QStringLiteral("v_unitvalue"),
2029                    "rd_unit_id=" % ids % " AND d_date<='" % dates %
2030                    "' AND  ABS(strftime('%s','" % dates %
2031                    "')-strftime('%s',d_date))=(select MIN(ABS(strftime('%s','" % dates %
2032                    "')-strftime('%s',u2.d_date))) from unitvalue u2 where u2.rd_unit_id=" % ids %
2033                    " AND u2.d_date<='" % dates % "')",
2034                    oUnitValue);
2035 
2036     // If not found then get first
2037     IFKO(err) err = SKGObjectBase::getDocument()->getObject(QStringLiteral("v_unitvalue"),
2038                     "rd_unit_id=" % SKGServices::intToString(getID()) % " AND d_date=(select MIN(d_date) from unitvalue where rd_unit_id=" %
2039                     SKGServices::intToString(getID()) % ')',
2040                     oUnitValue);
2041     return err;
2042 }
2043 
2044 double SKGUnitObject::getAmount(QDate iDate) const
2045 {
2046     SKGTRACEINFUNC(10)
2047     double output = 0;
2048     if (getType() == SKGUnitObject::PRIMARY) {
2049         output = 1.0;
2050     } else if (getDocument() != nullptr) {
2051         // Search result in cache
2052         QString ids = SKGServices::intToString(getID());
2053         QString dates = SKGServices::dateToSqlString(iDate);
2054         QString key = "unitvalue-" % ids % '-' % dates;
2055         QString val = getDocument()->getCachedValue(key);
2056         if (val.isEmpty()) {
2057             // Get quantity
2058             double quantity = 1;
2059             SKGUnitValueObject uv;
2060             if (getUnitValue(iDate, uv).isSucceeded()) {
2061                 quantity = uv.getQuantity();
2062             }
2063 
2064             SKGUnitObject unit;
2065             double coef = 1;
2066             if (getUnit(unit).isSucceeded()) {
2067                 if (unit != *this) {
2068                     coef = unit.getAmount(iDate);
2069                 }
2070             }
2071 
2072             output = coef * quantity;
2073             getDocument()->addValueInCache(key, SKGServices::doubleToString(output));
2074 
2075             if (getAttribute(QStringLiteral("i_NBVALUES")) == QStringLiteral("1")) {
2076                 // Store value for this symbol for all date
2077                 getDocument()->addValueInCache("unitvalue-" % ids, SKGServices::doubleToString(output));
2078             }
2079         } else {
2080             output = SKGServices::stringToDouble(val);
2081         }
2082     }
2083     return output;
2084 }
2085 
2086 double SKGUnitObject::getDailyChange(QDate iDate) const
2087 {
2088     double output = 0;
2089     SKGStringListList result;
2090     SKGError err = getDocument()->executeSelectSqliteOrder(
2091                        "SELECT d_date, f_quantity from unitvalue where rd_unit_id=" %
2092                        SKGServices::intToString(getID()) %
2093                        " AND d_date<='" % SKGServices::dateToSqlString(iDate) %
2094                        "' ORDER BY d_date DESC LIMIT 2",
2095                        result);
2096     if (!err && result.count() == 3) {
2097         double v2 = SKGServices::stringToDouble(result.at(1).at(1));
2098         double v1 = SKGServices::stringToDouble(result.at(2).at(1));
2099 
2100         QDate d2 = SKGServices::stringToTime(result.at(1).at(0)).date();
2101         QDate d1 = SKGServices::stringToTime(result.at(2).at(0)).date();
2102 
2103         output = 100 * (qExp(qLn(v2 / v1) / (SKGServices::nbWorkingDays(d1, d2))) - 1);
2104     }
2105     return output;
2106 }
2107 
2108 SKGError SKGUnitObject::split(double iRatio) const
2109 {
2110     SKGError err;
2111     if (iRatio > 0) {
2112         err = getDocument()->executeSqliteOrder("UPDATE unitvalue SET f_quantity=f_quantity/" % SKGServices::doubleToString(iRatio) %
2113                                                 " WHERE rd_unit_id=" % SKGServices::intToString(getID()));
2114         IFOKDO(err, getDocument()->executeSqliteOrder("UPDATE suboperation SET f_value=f_value*" % SKGServices::doubleToString(iRatio) %
2115                 " WHERE rd_operation_id IN (SELECT id FROM operation WHERE rc_unit_id=" % SKGServices::intToString(getID()) % ')'));
2116     } else {
2117         err = SKGError(ERR_INVALIDARG, i18nc("Error message", "Invalid ratio. Ratio must be greater than 0."));
2118     }
2119     return err;
2120 }
2121 
2122 QStringList SKGUnitObject::downloadSources()
2123 {
2124     QStringList sources;
2125     // Get sources from .txt file (old mode) TODO: Remove
2126     QString a = QStringLiteral("skrooge/quotes");
2127     const auto list = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, a, QStandardPaths::LocateDirectory);
2128     for (const auto& dir : list) {
2129         QDirIterator it(dir, QStringList() << QStringLiteral("*.txt"));
2130         while (it.hasNext()) {
2131             QFileInfo f(it.next());
2132             QString file2 = f.completeBaseName();
2133             if (!sources.contains(file2)) {
2134                 sources.push_back(file2);
2135             }
2136         }
2137     }
2138 
2139     // Get sources from.desktop file
2140     const auto list2 = KServiceTypeTrader::self()->query(QStringLiteral("skrooge/source"));
2141     for (const auto& service : list2) {
2142 #ifdef SKG_KF_5102
2143         auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QMetaType::QString).toString();
2144 #else
2145         auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QVariant::String).toString();
2146 #endif
2147         if (!sources.contains(name)) {
2148             sources.push_back(name);
2149         }
2150     }
2151     sources.sort();
2152     return sources;
2153 }
2154 
2155 QString SKGUnitObject::getCommentFromSource(const QString& iSource)
2156 {
2157     QString output;
2158     const auto list2 = KServiceTypeTrader::self()->query(QStringLiteral("skrooge/source"));
2159     for (const auto& service : list2) {
2160 #ifdef SKG_KF_5102
2161         auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QMetaType::QString).toString();
2162         if (name == iSource) {
2163             output = service->property(QStringLiteral("Comment"), QMetaType::QString).toString();
2164 #else
2165         auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QVariant::String).toString();
2166         if (name == iSource) {
2167             output = service->property(QStringLiteral("Comment"), QVariant::String).toString();
2168 #endif
2169             break;
2170         }
2171     }
2172     return output;
2173 }
2174 
2175 SKGError SKGUnitObject::addSource(const QString& iNewSource, bool iOpenSource)
2176 {
2177     SKGError err;
2178 
2179     QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
2180     QDir(path).mkpath(QStringLiteral("skrooge/quotes/"));
2181 
2182     QString newfile = path + "/skrooge/quotes/" % iNewSource % ".txt";
2183 
2184     // Create the new file
2185     QSaveFile file(newfile);
2186     // Check if file already existing
2187     if (!QFile(newfile).exists()) {
2188         // Creation of the template
2189         if (!file.open(QIODevice::WriteOnly)) {
2190             err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message",  "Save file '%1' failed", newfile));
2191         } else {
2192             QTextStream out(&file);
2193 
2194             out << "#" << i18nc("Description test for a text file used to define a source of download",
2195                                 "The URL or the SCRIPT of the source. %1 will be replaced by the internet code of the unit", "%1") << SKGENDL;
2196             out << "#" << i18nc("Description test for a text file used to define a source of download",
2197                                 "%1 will be replaced by the current day in format yyyy-MM-dd", "%2") << SKGENDL;
2198             out << "#" << i18nc("Description test for a text file used to define a source of download",
2199                                 "%1 will be replaced by the previous date in format yyyy-MM-dd", "%3") << SKGENDL;
2200             out << "url=https://server/?s=%1" << SKGENDL;
2201             out << "or" << SKGENDL;
2202             out << "script=mydownloadscript %1" << SKGENDL << SKGENDL;
2203 
2204 
2205             out << "#" << i18nc("Description test for a text file used to define a source of download",
2206                                 "The mode (HTML or CSV or CSVR). In HTML mode, only one value will be extracted from downloaded page. In CSV mode, a value per line will be extracted. CSVR means CSV in reverse mode.") << SKGENDL;
2207             out << "mode=CSV, CSVR or or HTML" << SKGENDL << SKGENDL;
2208 
2209             out << "#" << i18nc("Description test for a text file used to define a source of download",
2210                                 "The regular expression for the price (see %1)", "https://doc.qt.io/qt-5/qregularexpression.html") << SKGENDL;
2211             out << "price=" << SKGENDL << SKGENDL;
2212 
2213             out << "#" << i18nc("Description test for a text file used to define a source of download",
2214                                 "The regular expression for the date (see %1)", "https://doc.qt.io/qt-5/qregularexpression.html") << SKGENDL;
2215             out << "date=" << SKGENDL << SKGENDL;
2216 
2217             out << "#" << i18nc("Description test for a text file used to define a source of download",
2218                                 "The format of the date (see %1) or \"UNIX\" for unix time", "https://doc.qt.io/qt-5/qdate.html#fromString-1") << SKGENDL;
2219             out << "dateformat=yyyy-MM-dd" << SKGENDL;
2220 
2221             // Close file
2222             file.commit();
2223         }
2224     }
2225 
2226     // Open the created or already existing file
2227     if (iOpenSource) {
2228         QDesktopServices::openUrl(QUrl::fromLocalFile(newfile));
2229     }
2230     return err;
2231 }
2232 
2233 SKGError SKGUnitObject::deleteSource(const QString& iSource)
2234 {
2235     SKGError err;
2236 
2237     QString fileName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + QStringLiteral("skrooge/quotes/") % iSource % ".txt";
2238 
2239     // Delete the file
2240     QFile file(fileName);
2241     if (!file.remove()) {
2242         err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message",  "Deletion of '%1' failed", fileName));
2243     }
2244     return err;
2245 }
2246 
2247 bool SKGUnitObject::isWritable(const QString& iSource)
2248 {
2249     QString fileName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + QStringLiteral("skrooge/quotes/") % iSource % ".txt";
2250     return QFileInfo(fileName).isWritable();
2251 }
2252 
2253 SKGError SKGUnitObject::downloadUnitValue(UnitDownloadMode iMode, int iNbMaxValues)
2254 {
2255     SKGError err;
2256     SKGTRACEINFUNCRC(10, err)
2257 
2258     QString unitname = getName();
2259     QString code = getInternetCode();
2260     bool invert = code.contains(QStringLiteral(" /"));
2261     code.remove(QStringLiteral(" /"));
2262     QString source = getDownloadSource();
2263     auto* doc = qobject_cast<SKGDocumentBank*>(getDocument());
2264     if (!code.trimmed().isEmpty() && (doc != nullptr)) {
2265         // Get last date
2266         QDate firstDate;
2267         SKGStringListList result;
2268         doc->executeSelectSqliteOrder("SELECT MAX(d_date) FROM unitvalue where rd_unit_id=" % SKGServices::intToString(getID()), result);
2269         if (result.count() == 2) {
2270             firstDate = SKGServices::stringToTime(result.at(1).at(0)).date().addDays(-1);
2271         }
2272 
2273         if (code.startsWith(QLatin1String("="))) {
2274             // MODE FORMULAR
2275             // Set 1st january if date is not found
2276             if (!firstDate.isValid()) {
2277                 firstDate.setDate(QDate::currentDate().year(), 1, 1);
2278             }
2279 
2280             // Compute yearly rate
2281             double rate = SKGServices::stringToDouble(code.right(code.length() - 1));
2282 
2283             // Compute rate for step
2284             double step = (iMode == LAST_MONTHLY || iMode == ALL_MONTHLY ? 12.0 : (iMode == LAST_WEEKLY || iMode == ALL_WEEKLY ? 365.0 / 7.0 : 365));
2285             double rate2 = 100.0 * (qExp(qLn(1 + rate / 100.0) / step) - 1.0);
2286 
2287             // Get last value
2288             SKGStringListList result2;
2289             double value = 100;
2290             doc->executeSelectSqliteOrder("SELECT f_quantity FROM unitvalue where rd_unit_id=(SELECT id from unit where t_name='" % SKGServices::stringToSqlString(unitname) % "') AND d_date='" % SKGServices::dateToSqlString(firstDate) % '\'', result2);
2291             if (result2.count() == 2) {
2292                 value = SKGServices::stringToDouble(result2.at(1).at(0));
2293             }
2294 
2295             // Compute and add values
2296             while (!err && firstDate <= QDate::currentDate()) {
2297                 // Compute next date and value
2298                 if (iMode == LAST_MONTHLY || iMode == ALL_MONTHLY) {
2299                     firstDate = firstDate.addMonths(1);
2300                 } else if (iMode == LAST_WEEKLY || iMode == ALL_WEEKLY) {
2301                     firstDate = firstDate.addDays(7);
2302                 } else {
2303                     firstDate = firstDate.addDays(1);
2304                 }
2305 
2306                 value *= (1 + rate2 / 100.0);
2307 
2308                 // Create value
2309                 SKGUnitValueObject val;
2310                 err = addUnitValue(val);
2311                 IFOKDO(err, val.setDate(firstDate))
2312                 IFOKDO(err, val.setQuantity(value))
2313                 IFOKDO(err, val.save())
2314             }
2315         } else if (!source.trimmed().isEmpty()) {
2316             // Quote download
2317 
2318             // Set 1st january 1970 if date is not found
2319             if (!firstDate.isValid()) {
2320                 firstDate.setDate(1970, 1, 1);
2321             }
2322 
2323             QString interval = QStringLiteral("1d");
2324             bool last = (iMode == LAST);
2325             if (last) {
2326                 interval = QStringLiteral("1d");
2327             } else if (iMode == LAST_MONTHLY) {
2328                 interval = QStringLiteral("1mo");
2329             } else if (iMode == LAST_WEEKLY) {
2330                 interval = QStringLiteral("1wk");
2331             } else if (iMode == LAST_DAILY) {
2332                 interval = QStringLiteral("1d");
2333             } else if (iMode == ALL_MONTHLY) {
2334                 firstDate = QDate(1970, 01, 01);
2335                 interval = QStringLiteral("1mo");
2336             } else if (iMode == ALL_WEEKLY) {
2337                 firstDate = QDate(1970, 01, 01);
2338                 interval = QStringLiteral("1wk");
2339             } else if (iMode == ALL_DAILY) {
2340                 firstDate = QDate(1970, 01, 01);
2341                 interval = QStringLiteral("1d");
2342             }
2343 
2344             bool modeScript = false;
2345             QString path;
2346             QString mode;
2347             QString price;
2348             QString date;
2349             QString dateFormat;
2350             QString apiKey;
2351             QString fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "skrooge/quotes/" % source % ".txt");
2352             if (fileName.isEmpty()) {
2353                 const auto list2 = KServiceTypeTrader::self()->query(QStringLiteral("skrooge/source"));
2354                 for (const auto& service : list2) {
2355 #ifdef SKG_KF_5102
2356                     auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QMetaType::QString).toString();
2357                     if (name == source) {
2358                         path = service->property(QStringLiteral("X-SKROOGE-url"), QMetaType::QString).toString();
2359                         if (path.isEmpty()) {
2360                             path = service->property(QStringLiteral("X-SKROOGE-script"), QMetaType::QString).toString();
2361                             modeScript = true;
2362                         }
2363 
2364                         mode = service->property(QStringLiteral("X-SKROOGE-mode"), QMetaType::QString).toString().toUpper();
2365                         price = service->property(QStringLiteral("X-SKROOGE-price"), QMetaType::QString).toString().replace(QStringLiteral("%1"), code);
2366                         date = service->property(QStringLiteral("X-SKROOGE-date"), QMetaType::QString).toString().replace(QStringLiteral("%1"), code);
2367                         dateFormat = service->property(QStringLiteral("X-SKROOGE-dateformat"), QMetaType::QString).toString();
2368                         if (service->property(QStringLiteral("X-SKROOGE-keyAPI"), QMetaType::Bool).toBool()) {
2369                             apiKey = getDocument()->getParameter("KEYAPI_" + source);
2370                         }
2371                         break;
2372                     }
2373 #else
2374                     auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QVariant::String).toString();
2375                     if (name == source) {
2376                         path = service->property(QStringLiteral("X-SKROOGE-url"), QVariant::String).toString();
2377                         if (path.isEmpty()) {
2378                             path = service->property(QStringLiteral("X-SKROOGE-script"), QVariant::String).toString();
2379                             modeScript = true;
2380                         }
2381 
2382                         mode = service->property(QStringLiteral("X-SKROOGE-mode"), QVariant::String).toString().toUpper();
2383                         price = service->property(QStringLiteral("X-SKROOGE-price"), QVariant::String).toString().replace(QStringLiteral("%1"), code);
2384                         date = service->property(QStringLiteral("X-SKROOGE-date"), QVariant::String).toString().replace(QStringLiteral("%1"), code);
2385                         dateFormat = service->property(QStringLiteral("X-SKROOGE-dateformat"), QVariant::String).toString();
2386                         if (service->property(QStringLiteral("X-SKROOGE-keyAPI"), QVariant::Bool).toBool()) {
2387                             apiKey = getDocument()->getParameter("KEYAPI_" + source);
2388                         }
2389                         break;
2390                     }
2391 #endif
2392                 }
2393                 if (path.isEmpty()) {
2394                     err = SKGError(ERR_FAIL, i18nc("Error message", "Source of download %1 is not installed.", source));
2395                 }
2396             } else {
2397                 // Read source file from .txt file
2398                 QHash< QString, QString > properties;
2399                 err = SKGServices::readPropertyFile(fileName, properties);
2400                 IFOK(err) {
2401                     path = properties[QStringLiteral("url")];
2402                     if (path.isEmpty()) {
2403                         path = properties[QStringLiteral("script")];
2404                         modeScript = true;
2405                     }
2406                     mode = properties[QStringLiteral("mode")].toUpper();
2407                     price = properties[QStringLiteral("price")].replace(QStringLiteral("%1"), code);
2408                     date = properties[QStringLiteral("date")].replace(QStringLiteral("%1"), code);
2409                     dateFormat = properties[QStringLiteral("dateformat")];
2410                 } else {
2411                     doc->sendMessage(i18nc("An information message", "Open url '%1' failed", path), SKGDocument::Warning);
2412                 }
2413             }
2414 
2415             IFOK(err) {
2416                 path = path.replace(QStringLiteral("%1"), code);
2417                 path = path.replace(QStringLiteral("%2"), QDate::currentDate().toString(QStringLiteral("yyyy-MM-dd")));
2418                 path = path.replace(QStringLiteral("%3"), firstDate.toString(QStringLiteral("yyyy-MM-dd")));
2419                 path = path.replace(QStringLiteral("%4"), interval);
2420                 path = path.replace(QStringLiteral("%5"), apiKey);
2421 
2422                 SKGTRACEL(1) << "path=[" << path << "]" << SKGENDL;
2423                 SKGTRACEL(1) << "mode=[" << mode << "]" << SKGENDL;
2424                 SKGTRACEL(1) << "price=[" << price << "]" << SKGENDL;
2425                 SKGTRACEL(1) << "date=[" << date << "]" << SKGENDL;
2426                 SKGTRACEL(1) << "dateFormat=[" << dateFormat << "]" << SKGENDL;
2427 
2428                 // Download url
2429                 QByteArray stream;
2430                 if (modeScript) {
2431                     path = SKGServices::getFullPathCommandLine(path);
2432                     SKGTRACEL(1) << "full path=[" << path << "]" << SKGENDL;
2433 
2434                     QProcess p;
2435                     p.start(QStringLiteral("/bin/bash"), QStringList() << QStringLiteral("-c") << path);
2436                     if (p.waitForFinished(1000 * 60 * 2) && p.exitCode() == 0) {
2437                         stream = p.readAllStandardOutput();
2438                     } else {
2439                         err.setReturnCode(ERR_FAIL).setMessage(i18nc("Error message",  "The following command line failed with code %2:\n'%1'", path, p.exitCode()));
2440                     }
2441                 } else {
2442                     SKGServices::downloadToStream(QUrl::fromUserInput(path), stream);
2443                 }
2444                 if (!err && !stream.isEmpty()) {
2445                     SKGTRACEL(1) << "stream=[" << stream << "]" << SKGENDL;
2446 
2447                     // Parse data
2448                     QRegularExpression priceRegExp(price, QRegularExpression::CaseInsensitiveOption);
2449                     QRegularExpression dateRegExp(date, QRegularExpression::CaseInsensitiveOption);
2450 
2451                     QStringList lines = (mode.startsWith(QLatin1String("CSV")) ? SKGServices::splitCSVLine(stream, '\n') : QStringList() << QLatin1String("") << stream);
2452                     int nb = lines.count();
2453                     int nbLoaded = 0;
2454                     for (int i = 1; i < nb && !err && (i < iNbMaxValues || iNbMaxValues == 0); ++i) {
2455                         QString data = lines.at(mode == QStringLiteral("CSVR") ? nb - i : i).trimmed();
2456                         if (!data.isEmpty()) {
2457                             SKGTRACEL(1) << "Downloaded data from [" << path << "]=[" << data << "]" << SKGENDL;
2458 
2459                             double val = 0.0;
2460                             auto match = priceRegExp.match(data);
2461                             if (match.hasMatch()) {
2462                                 val = SKGServices::stringToDouble(match.captured(1));
2463                             }
2464                             QString date2;
2465                             match = dateRegExp.match(data);
2466                             if (match.hasMatch()) {
2467                                 date2 = match.captured(1);
2468                             }
2469                             SKGTRACEL(1) << "Price found=[" << val << "]" << SKGENDL;
2470                             SKGTRACEL(1) << "Date found=[" << date2 << "]" << SKGENDL;
2471 
2472                             // Set value
2473                             if (val != 0.0) {
2474                                 QDate ds;
2475                                 if (dateFormat == QStringLiteral("UNIX")) {
2476                                     ds = QDateTime::fromTime_t(SKGServices::stringToInt(date2)).date();
2477                                 } else {
2478                                     ds = QDate::fromString(date2, dateFormat);
2479                                     // Try with an english locale
2480                                     if (!ds.isValid()) {
2481                                         QLocale en(QStringLiteral("en_EN"));
2482                                         ds = en.toDate(date2, dateFormat);
2483                                     }
2484                                 }
2485 
2486                                 if (!ds.isValid()) {
2487                                     ds = QDate::currentDate();
2488                                     SKGTRACE << "WARNING:" << date2 << " not well parsed with format " << dateFormat << SKGENDL;
2489                                 }
2490                                 if (!dateFormat.contains(QStringLiteral("yyyy")) && ds.year() < 2000) {
2491                                     ds = ds.addYears(100);
2492                                 }
2493 
2494                                 // Creation or update of the value
2495                                 SKGUnitValueObject value;
2496                                 IFOKDO(err, addUnitValue(value))
2497                                 IFOKDO(err, value.setDate(ds))
2498                                 IFOKDO(err, value.setQuantity(invert && val != 0 ? 1 / val : val))
2499                                 IFOKDO(err, value.save())
2500 
2501                                 if (last) {
2502                                     break;
2503                                 }
2504 
2505                                 nbLoaded++;
2506                             }
2507                         }
2508                         if (nbLoaded == 0 && !data.isEmpty()) {
2509                             err = doc->sendMessage(i18nc("Information message", "Price not found for '%1' with regular expression '%2' in line '%3'", getName(), SKGServices::stringToHtml(price), data), SKGDocument::Warning);    // TODO(Stephane MANKOWSKI) does not work with html
2510                         }
2511                     }
2512                 }
2513             }
2514         }
2515     }
2516 
2517     IFKO(err) {
2518         err.addError(ERR_FAIL, i18nc("Error message", "Impossible to download unit %1 with Internet code %2 on the source %3.", unitname, code, source));
2519     }
2520 
2521     return err;
2522 }
2523 
2524 SKGError SKGUnitObject::getUrl(QUrl& oUrl) const
2525 {
2526     SKGError err;
2527     SKGTRACEINFUNCRC(10, err)
2528 
2529     QString url;
2530     QString code = getInternetCode();
2531     code.remove(QStringLiteral(" /"));
2532     QString source = getDownloadSource();
2533     if (!code.isEmpty()) {
2534         if (code.startsWith(QLatin1String("="))) {
2535             // MODE FORMULAR
2536 
2537         } else {
2538             // ALTERNATIVE MODE
2539             QString fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "skrooge/quotes/" % source % ".txt");
2540             if (fileName.isEmpty()) {
2541                 const auto list2 = KServiceTypeTrader::self()->query(QStringLiteral("skrooge/source"));
2542                 for (const auto& service : list2) {
2543 #ifdef SKG_KF_5102
2544                     auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QMetaType::QString).toString();
2545                     if (name == source) {
2546                         url = service->property(QStringLiteral("X-SKROOGE-url"), QMetaType::QString).toString().replace(QStringLiteral("%1"), code);
2547 #else
2548                     auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QVariant::String).toString();
2549                     if (name == source) {
2550                         url = service->property(QStringLiteral("X-SKROOGE-url"), QVariant::String).toString().replace(QStringLiteral("%1"), code);
2551 #endif
2552                         url = url.replace(QStringLiteral("%2"), QDate::currentDate().toString(QStringLiteral("yyyy-MM-dd")));
2553                         url = url.replace(QStringLiteral("%3"), QDate::currentDate().addDays(-15).toString(QStringLiteral("yyyy-MM-dd")));
2554                         break;
2555                     }
2556                 }
2557                 if (url.isEmpty()) {
2558                     err = SKGError(ERR_FAIL, i18nc("Error message", "Source of download %1 is not installed.", source));
2559                 }
2560             } else {
2561                 // Read source file
2562                 QHash< QString, QString > properties;
2563                 err = SKGServices::readPropertyFile(fileName, properties);
2564 
2565                 IFOK(err) {
2566                     url = properties[QStringLiteral("url")].replace(QStringLiteral("%1"), code);
2567                     url = url.replace(QStringLiteral("%2"), QDate::currentDate().toString(QStringLiteral("yyyy-MM-dd")));
2568                     url = url.replace(QStringLiteral("%3"), QDate::currentDate().addDays(-15).toString(QStringLiteral("yyyy-MM-dd")));
2569                 }
2570             }
2571         }
2572     }
2573 
2574     IFOK(err) {
2575         oUrl = QUrl(url);
2576     }
2577 
2578     return err;
2579 }
2580 
2581 SKGError SKGUnitObject::openURL() const
2582 {
2583     QUrl url;
2584     SKGError err = getUrl(url);
2585 
2586     IFKO(err) {
2587         err.addError(ERR_FAIL, i18nc("Error message", "Impossible to open unit %1 with Internet code %2.", getName(), getInternetCode()));
2588     } else {
2589         QDesktopServices::openUrl(url);
2590     }
2591 
2592     return err;
2593 }
2594 
2595 SKGError SKGUnitObject::getOperations(SKGObjectBase::SKGListSKGObjectBase& oOperations) const
2596 {
2597     SKGError err = getDocument()->getObjects(QStringLiteral("v_operation"),
2598                    "rc_unit_id=" % SKGServices::intToString(getID()),
2599                    oOperations);
2600     return err;
2601 }
2602 
2603 SKGError SKGUnitObject::merge(const SKGUnitObject& iUnit)
2604 {
2605     SKGError err;
2606 
2607     SKGObjectBase::SKGListSKGObjectBase ops;
2608     IFOKDO(err, iUnit.getOperations(ops))
2609     int nb = ops.count();
2610     for (int i = 0; !err && i < nb; ++i) {
2611         SKGOperationObject op(ops.at(i));
2612         err = op.setUnit(*this);
2613         IFOKDO(err, op.save(true, false))
2614     }
2615 
2616     IFOKDO(err, iUnit.remove(false))
2617     return err;
2618 }