File indexing completed on 2024-04-14 05:43:12
0001 /*************************************************************************** 0002 currencies.cpp - list of currencies 0003 ------------------- 0004 begin : sam déc 1 23:40:19 CET 2001 0005 copyright : (C) 2001-2022 by Éric Bischoff 0006 email : bischoff@kde.org 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * * 0011 * This program is free software; you can redistribute it and/or modify * 0012 * it under the terms of the GNU General Public License as published by * 0013 * the Free Software Foundation; either version 2 of the License, or * 0014 * (at your option) any later version. * 0015 * * 0016 ***************************************************************************/ 0017 0018 #include "currencies.h" 0019 0020 #include <QFile> 0021 #include <QDate> 0022 #include <QStandardPaths> 0023 #include <QDomDocument> 0024 #include <QDebug> 0025 0026 #include <KIO/TransferJob> 0027 #include <KLocalizedString> 0028 0029 static const char 0030 *urlECB = "http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml", 0031 // *urlNY_FRB = "http://www.newyorkfed.org/markets/fxrates/FXtoXML.cfm?FEXdate=%04d-%02d-%02d&FEXtime=1200", 0032 *urlTG = "http://rss.timegenie.com/forex2.xml"; 0033 0034 // Constructor 0035 Currencies::Currencies() 0036 : QObject(), 0037 variableRates() 0038 { 0039 currency = 0; 0040 } 0041 0042 // Destructor 0043 Currencies::~Currencies() 0044 { 0045 if (currency) delete [] currency; 0046 } 0047 0048 // Read currencies list 0049 bool Currencies::readCurrencies( const char *filename ) 0050 { 0051 QDomDocument document( "currencies" ); 0052 QFile file( QStandardPaths::locate(QStandardPaths::AppDataLocation, filename) ); 0053 0054 if ( !file.open( QIODevice::ReadOnly ) ) return false; 0055 if ( !document.setContent( &file ) ) { file.close(); return false; } 0056 file.close(); 0057 0058 QDomNodeList currenciesList = document.elementsByTagName( "currency" ); 0059 int num; 0060 QString name; 0061 0062 numCurrencies = currenciesList.count(); 0063 if (currency) delete [] currency; 0064 currency = new currencyStruc[numCurrencies]; 0065 for (num = 0; num < numCurrencies; ++num) 0066 { 0067 QDomElement elt = currenciesList.item(num).toElement(); 0068 0069 if ( !elt.hasAttribute( "symbol" ) ) 0070 return false; 0071 currency[num].symbol = elt.attribute( "symbol" ); 0072 0073 if ( !elt.hasAttribute( "code" ) ) 0074 return false; 0075 currency[num].code = elt.attribute( "code" ); 0076 if ( currency[num].code == "USD" ) 0077 dollarCurrency = num; 0078 else if ( currency[num].code == "EUR" ) 0079 euroCurrency = num; 0080 0081 if ( !elt.hasAttribute( "official-rules-precision" ) ) 0082 return false; 0083 currency[num].officialRulesPrecision = elt.attribute( "official-rules-precision" ).toDouble(); 0084 0085 if ( !elt.hasAttribute( "smallest-coin-precision" ) ) 0086 return false; 0087 currency[num].smallestCoinPrecision = elt.attribute( "smallest-coin-precision" ).toDouble(); 0088 0089 if ( !elt.hasAttribute( "name" ) ) 0090 return false; 0091 name = elt.attribute( "name" ); 0092 currency[num].name = i18n( name.toUtf8().data() ); 0093 0094 if ( elt.hasAttribute( "new-york-name" ) ) 0095 currency[num].newYorkName = elt.attribute( "new-york-name" ); 0096 else 0097 currency[num].newYorkName = "N/A"; 0098 0099 if ( elt.hasAttribute( "fixed-rate" ) ) 0100 currency[num].fixedRate = elt.attribute( "fixed-rate" ).toDouble(); 0101 else 0102 currency[num].fixedRate = 0.0; 0103 0104 currency[num].rate = 1.0; 0105 currency[num].position = -1; 0106 } 0107 return true; 0108 } 0109 0110 // Clear rates 0111 void Currencies::clearRates() 0112 { 0113 int num; 0114 0115 for (num = 0; num < numCurrencies; num++) 0116 { 0117 if ( !currency[num].fixedRate ) 0118 { 0119 currency[num].rate = 1.0; 0120 currency[num].position = -1; 0121 } 0122 } 0123 } 0124 0125 // Add fixed rates 0126 void Currencies::addFixedRates( int rounding, bool someMoreToCome ) 0127 { 0128 int num; 0129 double currencyPrecision; 0130 QString blank(""); 0131 0132 for (num = 0; num < numCurrencies; num++) 0133 if ( currency[num].fixedRate ) 0134 { 0135 switch (rounding) 0136 { 0137 case OFFICIAL_RULES: 0138 currencyPrecision = currency[num].officialRulesPrecision; 0139 break; 0140 case SMALLEST_COIN: 0141 currencyPrecision = currency[num].smallestCoinPrecision; 0142 break; 0143 default: 0144 currencyPrecision = 1.0; 0145 } 0146 currency[num].rate = 0147 currency[num].fixedRate / currencyPrecision; 0148 currency[num].position = -2; 0149 } 0150 endDownload( someMoreToCome? 0: euroCurrency, blank ); 0151 } 0152 0153 // Add variable rates from European Central Bank 0154 void Currencies::addECBRates( int rounding ) 0155 { 0156 KIO::TransferJob *job; 0157 0158 roundingMethod = rounding; 0159 0160 job = KIO::get( QUrl( urlECB ), KIO::Reload, KIO::HideProgressInfo ); 0161 connect( job, SIGNAL(data(KIO::Job*,QByteArray)), 0162 this, SLOT(httpDataECB(KIO::Job*,QByteArray)) 0163 ); 0164 connect( job, SIGNAL(result(KJob*)), 0165 this, SLOT(httpResultECB(KJob*)) 0166 ); 0167 } 0168 0169 // Add variable rates from New York Federal Reserve Bank 0170 //void Currencies::addNY_FRBRates( int rounding ) 0171 //{ 0172 // char url[128]; 0173 // QDate yesterday; 0174 // KIO::TransferJob *job; 0175 // 0176 // roundingMethod = rounding; 0177 // 0178 // yesterday = QDate::currentDate().addDays(-1); 0179 // // This is suboptimal: we should guess the date of latest working day at 12:00 in New York local time 0180 // // Or much better: use a URL that does not depend on that date... 0181 // sprintf(url, urlNY_FRB, yesterday.year(), yesterday.month(), yesterday.day()); 0182 // job = KIO::get( QUrl( url ), KIO::Reload, KIO::HideProgressInfo ); 0183 // connect( job, SIGNAL(data(KIO::Job*,QByteArray)), 0184 // this, SLOT(httpDataNY_FRB(KIO::Job*,QByteArray)) 0185 // ); 0186 // connect( job, SIGNAL(result(KJob*)), 0187 // this, SLOT(httpResultNY_FRB(KJob*)) 0188 // ); 0189 //} 0190 0191 // Add variable rates from Time Genie foreign exchange 0192 void Currencies::addTGRates( int rounding ) 0193 { 0194 KIO::TransferJob *job; 0195 0196 roundingMethod = rounding; 0197 0198 job = KIO::get( QUrl( urlTG ), KIO::Reload, KIO::HideProgressInfo ); 0199 connect( job, SIGNAL(data(KIO::Job*,QByteArray)), 0200 this, SLOT(httpDataTG(KIO::Job*,QByteArray)) 0201 ); 0202 connect( job, SIGNAL(result(KJob*)), 0203 this, SLOT(httpResultTG(KJob*)) 0204 ); 0205 } 0206 0207 // Exchange rates received from European Central Bank 0208 void Currencies::httpDataECB(KIO::Job *job, const QByteArray &array) 0209 { 0210 (void) job; // Unused parameter 0211 0212 if ( array.size() ) 0213 { 0214 variableRates += QString(array); 0215 } 0216 else 0217 { 0218 QDomDocument document( "rates" ); 0219 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0220 const QDomDocument::ParseResult parseResult = document.setContent(variableRates, QDomDocument::ParseOption::UseNamespaceProcessing); 0221 if (!parseResult) { 0222 qDebug() << QStringLiteral("Can't read variableRates\nError: %1 in Line %2, Column %3") 0223 .arg(parseResult.errorMessage).arg(parseResult.errorLine).arg(parseResult.errorColumn); 0224 } 0225 #else 0226 document.setContent( variableRates, true ); 0227 #endif 0228 QDomNodeList ratesList = document.elementsByTagName( "Cube" ); 0229 int num; 0230 double currencyPrecision; 0231 0232 for (int i = 0; i < ratesList.count(); i++) 0233 { 0234 QDomElement elt = ratesList.item(i).toElement(); 0235 if ( elt.hasAttribute( "time" ) ) 0236 date = elt.attribute( "time" ); 0237 else if ( elt.hasAttribute( "currency" ) && elt.hasAttribute( "rate" ) ) 0238 { 0239 QString code(elt.attribute( "currency" )); 0240 for (num = 0; num < numCurrencies; ++num) 0241 if ( code == currency[num].code ) 0242 break; 0243 if ( num < numCurrencies ) 0244 { 0245 if ( !currency[num].fixedRate ) 0246 { 0247 switch (roundingMethod) 0248 { 0249 case OFFICIAL_RULES: 0250 currencyPrecision = currency[num].officialRulesPrecision; 0251 break; 0252 case SMALLEST_COIN: 0253 currencyPrecision = currency[num].smallestCoinPrecision; 0254 break; 0255 default: 0256 currencyPrecision = 1.0; 0257 } 0258 currency[num].rate = 0259 elt.attribute( "rate" ).toDouble() / currencyPrecision; 0260 currency[num].position = -2; 0261 } 0262 } 0263 } 0264 } 0265 variableRates = ""; 0266 } 0267 } 0268 0269 // End of exchange rates from European Central Bank 0270 void Currencies::httpResultECB(KJob *job) 0271 { 0272 if ( job->error() ) 0273 { 0274 clearRates(); 0275 endDownload( euroCurrency, "ERROR" ); 0276 } 0277 else 0278 endDownload( euroCurrency, date ); 0279 } 0280 0281 // Exchange rates received from New York Federal Reserve Bank 0282 //void Currencies::httpDataNY_FRB(KIO::Job *job, const QByteArray &array) 0283 //{ 0284 // static const char *frbny = "http://www.newyorkfed.org/xml/schemas/FX/utility"; 0285 // 0286 // (void) job; // Unused parameter 0287 // 0288 // if ( array.size() ) 0289 // { 0290 // variableRates += QString(array); 0291 // } 0292 // else 0293 // { 0294 // QDomDocument document( "rates" ); 0295 // 0296 // document.setContent( variableRates, true ); 0297 // 0298 // QDomNodeList ratesList = document.elementsByTagNameNS( frbny, "Series" ); 0299 // int num; 0300 // double currencyPrecision; 0301 // 0302 // for (int i = 0; i < ratesList.count(); i++) 0303 // { 0304 // QDomElement elt = ratesList.item(i).toElement(); 0305 // QDomNodeList dateElements = elt.elementsByTagNameNS( frbny, "TIME_PERIOD" ), 0306 // currencyElements = elt.elementsByTagNameNS( frbny, "CURR" ), 0307 // valueElements = elt.elementsByTagNameNS( frbny, "OBS_VALUE" ); 0308 // if (dateElements.count() == 1 && currencyElements.count() == 1 && valueElements.count() == 1) 0309 // { 0310 // QDomElement dateElement = dateElements.item(0).toElement(), 0311 // currencyElement = currencyElements.item(0).toElement(), 0312 // valueElement = valueElements.item(0).toElement(); 0313 // QString code( 0314 // elt.attribute( "UNIT" ) == "USD" ? 0315 // currencyElement.text(): 0316 // elt.attribute( "UNIT" ) 0317 // ); 0318 // for (num = 0; num < numCurrencies; num++) 0319 // if ( code == currency[num].code ) 0320 // break; 0321 // if ( num < numCurrencies ) 0322 // { 0323 // if ( !currency[num].fixedRate ) 0324 // { 0325 // switch (roundingMethod) 0326 // { 0327 // case OFFICIAL_RULES: 0328 // currencyPrecision = currency[num].officialRulesPrecision; 0329 // break; 0330 // case SMALLEST_COIN: 0331 // currencyPrecision = currency[num].smallestCoinPrecision; 0332 // break; 0333 // default: 0334 // currencyPrecision = 1.0; 0335 // } 0336 // if ( elt.attribute( "UNIT" ) != "USD" ) 0337 // currency[num].rate = 0338 // valueElement.text().toDouble() / currencyPrecision; 0339 // else currency[num].rate = 0340 // ( 1.0 / valueElement.text().toDouble() ) / currencyPrecision; 0341 // currency[num].position = -2; 0342 // } 0343 // if ( date.isNull() ) 0344 // date = dateElement.text(); 0345 // } 0346 // } 0347 // } 0348 // variableRates = ""; 0349 // } 0350 //} 0351 0352 // End of exchange rates from New York Federal Reserve Bank 0353 //void Currencies::httpResultNY_FRB(KJob *job) 0354 //{ 0355 // if ( job->error() ) 0356 // { 0357 // clearRates(); 0358 // endDownload( dollarCurrency, "ERROR" ); 0359 // } 0360 // else 0361 // endDownload( dollarCurrency, date ); 0362 //} 0363 0364 // Exchange rates received from Time Genie foreign exchange 0365 void Currencies::httpDataTG(KIO::Job *job, const QByteArray &array) 0366 { 0367 (void) job; // Unused parameter 0368 0369 if ( array.size() ) 0370 { 0371 variableRates += QString(array); 0372 } 0373 else 0374 { 0375 QDomDocument document( "forex" ); 0376 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0377 const QDomDocument::ParseResult parseResult = document.setContent(variableRates, QDomDocument::ParseOption::UseNamespaceProcessing); 0378 if (!parseResult) { 0379 qDebug() << QStringLiteral("Can't read variableRates\nError: %1 in Line %2, Column %3") 0380 .arg(parseResult.errorMessage).arg(parseResult.errorLine).arg(parseResult.errorColumn); 0381 } 0382 #else 0383 document.setContent( variableRates, true ); 0384 #endif 0385 0386 QDomNodeList ratesList = document.elementsByTagName( "currency" ); 0387 int num; 0388 double currencyPrecision; 0389 0390 for (int i = 0; i < ratesList.count(); i++) 0391 { 0392 QDomElement elt = ratesList.item(i).toElement(); 0393 if ( elt.hasAttribute( "code" ) && elt.hasAttribute( "rate" ) ) 0394 { 0395 QString code(elt.attribute( "code" )); 0396 for (num = 0; num < numCurrencies; ++num) 0397 if ( code == currency[num].code ) 0398 break; 0399 if ( num < numCurrencies ) 0400 { 0401 if ( !currency[num].fixedRate ) 0402 { 0403 switch (roundingMethod) 0404 { 0405 case OFFICIAL_RULES: 0406 currencyPrecision = currency[num].officialRulesPrecision; 0407 break; 0408 case SMALLEST_COIN: 0409 currencyPrecision = currency[num].smallestCoinPrecision; 0410 break; 0411 default: 0412 currencyPrecision = 1.0; 0413 } 0414 currency[num].rate = 0415 elt.attribute( "rate" ).toDouble() / currencyPrecision; 0416 currency[num].position = -2; 0417 } 0418 } 0419 } 0420 } 0421 variableRates = ""; 0422 date = QDate::currentDate().toString("yyyy-MM-dd"); // TG does not provide time information, use current date 0423 } 0424 } 0425 0426 // End of exchange rates from Time Genie foreign exchange 0427 void Currencies::httpResultTG(KJob *job) 0428 { 0429 if ( job->error() ) 0430 { 0431 clearRates(); 0432 endDownload( euroCurrency, "ERROR" ); 0433 } 0434 else 0435 endDownload( euroCurrency, date ); 0436 0437 } 0438 0439 #include "moc_currencies.cpp"