diff --git a/README b/README index b2f4a6808..9e71dc30a 100644 --- a/README +++ b/README @@ -1,233 +1,233 @@ # A personal finances manager, powered by KDE Skrooge allows you to manage your personal finances, powered by [KDE](http://www.kde.org). Thanks to its many [features](https://skrooge.org/features), it is one of the most powerful way to enter, follow, and analyze your expenses. Based on its KDE foundations, Skrooge can run on many platforms, including of course linux, BSD, Solaris, but also on Mac OS, and possibly on Windows. Learn more about [skrooge.org](https://skrooge.org/). ## Features ### Import your accounts from many sources Skrooge is able to import transactions from many formats (AFB120, QIF, CSV, MT940, OFX, QFX). For a more reach import, Skrooge is able to import documents from many applications ([KMYMONEY](https://kmymoney.org/), Microsoft Money, [GNUCASH](http://gnucash.org/), [GRISBI](http://fr.grisbi.org/), [HOMEBANK](http://homebank.free.fr/fr/index.php) and [MONEY MANAGER EX](https://www.moneymanagerex.org/)). And better, Skrooge is able to import directly transactions from all your banks web sites in one click. ### Reporting Build the graph you want to well undestand how your spend your money. Have a look to the periodic reports (monthly, annually, ...) to undestand the progress. Have a quick look on the dashboard. Skrooge is also able to give you advice based on your behavior. ### Like in a web browser Several tabs to help you organize your work. Bookmark your preferred reports, graphs, filters, pages, ... ### Budget Budgeting isn’t about restriction. It’s about setting and reaching your goals. Skrooge can help you to manage your budgets by putting in places simples rules. ### Classical features Infinite categories levels. Scheduled operations. Multi currencies. Manage payees. ### Advanced features Infinite undo/redo (even after the file was closed !) Mass update of operations. Automatically process operations based on search conditions. Instant filtering on operations and reports. Download of quotes. Add all properties you want on all objets (transactions, accounts, categories, ...) and including files (pdf, pictures, ...). ### Track refund of your expenses Skrooge can help you to check that you have received the expected refund (e.g. medical). ## How to install it: More information here: [https://skrooge.org/download](https://skrooge.org/download) ## How to build it: ### Install prerequisits: - xsltproc - libgrantlee5-dev (>=5.0.0) - libsqlite3-dev (>=3.7.0) - libofx-dev - libboost-dev - qtscript5-dev - qttools5-dev - libqt5webkit5-dev (If you want to build with WebKit. You must not activate the option SKG_WEBENGINE) (**Preferred**) - libqt5webengine5-dev (If you want to build with WebEngine. You must activate the option SKG_WEBENGINE) - libqt5svg5-dev - libkf5coreaddons-dev - libkf5archive-dev - libkf5xmlgui-dev - libkf5wallet-dev - libkf5parts-dev - libkf5newstuff-dev - libkf5iconthemes-dev - libkf5kdelibs4support-dev - libkf5notifyconfig-dev - libkf5runner-dev - plasma-framework-dev - kdoctools-dev - kgendesignerplugin - libqca-qt5-2-dev - libkf5activities-dev - kross-dev - qtdeclarative5-controls-plugin - libsqlcipher-dev - sqlcipher #### Examples: On ubuntu: sudo apt-get install pkg-config build-essential cmake devscripts cdbs extra-cmake-modules kross-dev sqlite3 sqlcipher libsqlcipher-dev libgrantlee5-dev libsqlite3-dev libofx-dev libboost-dev xsltproc qtscript5-dev qttools5-dev libqt5webkit5-dev libqt5webengine5-dev libqt5svg5-dev libkf5coreaddons-dev libkf5archive-dev libkf5xmlgui-dev libkf5activities-dev libkf5wallet-dev libkf5parts-dev libkf5newstuff-dev libkf5iconthemes-dev libkf5kdelibs4support-dev libkf5notifyconfig-dev libkf5runner-dev plasma-framework-dev kdoctools-dev kgendesignerplugin libqca-qt5-2-dev qtbase5-private-dev qtdeclarative5-controls-plugin ### Extract the archive, and enter the "skrooge" directory. Then run : mkdir build && cd build cmake .. -DCMAKE_INSTALL_PREFIX=[path to your KDE installation] make getpo :This command downloads all translation. This step is OPTIONAL and must be done only if you want skrooge in your language make #### Examples: On ubuntu: mkdir build && cd build cmake .. -DCMAKE_INSTALL_PREFIX=`kf5-config --prefix` -DQT_PLUGIN_INSTALL_DIR=`kf5-config --qt-plugins` -DCMAKE_BUILD_TYPE=release -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DSKG_WEBENGINE=OFF -DSKG_BUILD_TEST=OFF -DSKG_DESIGNER=OFF make getpo :This command downloads all translation. This step is OPTIONAL and must be done only if you want skrooge in your language make On ubuntu (with ninja): mkdir build && cd build release -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DSKG_WEBENGINE=OFF -DSKG_BUILD_TEST=OFF -DSKG_DESIGNER=OFF make getpo :This command downloads all translation. This step is OPTIONAL and must be done only if you want skrooge in your language make ### Prepare to run Skrooge uses plugins. By default, plugins are loaded from your system. It means that, if you have a local build of Skrooge and an other version of Skrooge installed on your system. The system version of plugins will be loaded. The easiest solution is to install your local build like this: make install (as root) #### Examples: On ubuntu: sudo make install If you don't want to install Skrooge on your system, you will have to set many Qt and Kde environment variables before running skrooge. This is not easy to do. ### Run the test ctest #### Run skrooge /usr/bin/skrooge ## Other important thinks to remember ### For Static code analysis (scan-build) CXX=clang++ CC=clang scan-build -k cmake .. -DCMAKE_INSTALL_PREFIX=`kf5-config --prefix` -DCMAKE_BUILD_TYPE=profile make clean scan-build -k -o results make ### With sanitizer (-fno-omit-frame-pointer ) cmake .. -DCMAKE_INSTALL_PREFIX=`kf5-config --prefix` -DQT_PLUGIN_INSTALL_DIR=`kf5-config --qt-plugins` -DCMAKE_BUILD_TYPE=profile -DECM_ENABLE_SANITIZERS='undefined,address,asan,ubsan' export ASAN_OPTIONS=detect_leaks=1 ### With clazy export CXX="clazy" export CLAZY_CHECKS="level0,level1,level2,level3" export CLAZY_FIXIT="fix-qlatin1string-allocations,fix-fromLatin1_fromUtf8-allocations,fix-fromCharPtrAllocations" cmake .. -DCMAKE_CXX_COMPILER=clazy -DCMAKE_INSTALL_PREFIX=`kf5-config --prefix` -DQT_PLUGIN_INSTALL_DIR=`kf5-config --qt-plugins` -DCMAKE_BUILD_TYPE=Debug make clean make -i > t.txt 2>&1 cat t.txt | grep "warning:" | grep -v "ui_" | grep -v "moc_" | grep -v "_settings" |grep -v "/usr/include" | grep -v "FixIt failed" | grep -v ".moc:" | grep -v "/build/" | sort -u > warning_all.txt cat warning_all.txt | grep -v "ctor-missing-parent-argument" | grep -v "clazy-copyable-polymorphic" | sort -u > warning.txt ### With clazy-standalone cmake .. -DCMAKE_INSTALL_PREFIX=`kf5-config --prefix` -DQT_PLUGIN_INSTALL_DIR=`kf5-config --qt-plugins` -DCMAKE_BUILD_TYPE=release -DCMAKE_EXPORT_COMPILE_COMMANDS=1 make find . -name "*cpp" | xargs clazy-standalone -checks=level2 -p compile_commands.json > t.txt 2>&1 cat t.txt | grep "warning:" | grep -v "ui_" | grep -v "moc_" | grep -v "_settings" |grep -v "/usr/include" | grep -v "FixIt failed" | sort -u > warning.txt ### clang-tidy run-clang-tidy.py -header-filter='.*' -checks=*,-fuchsia-*,-objc-*,-android-*,-abseil-*,-google-*,-misc-unused-parameters,-clang-diagnostic-error,-cppcoreguidelines-pro-type-member-init,-llvm-header-guard,-readability-inconsistent-declaration-parameter-name,-readability-redundant-member-init -fix > traces.txt cat traces.txt | grep warning | grep -v ui_ | grep -v /build/ | grep -v "clang-tidy -header" | sort -u > clangtidy.txt ### With coverity - export PATH=~/Telechargements/cov-analysis-linux64-2017.07/bin/:$PATH + export PATH=~/Telechargements/cov-analysis-linux64-2019.03/bin/:$PATH make clean cov-build --dir cov-int make -j 4 tar caf skrooge.bz2 cov-int ### iwyu iwyu_tool.py -p . ### Docker sudo docker build -t skrooge . sudo docker run -e DISPLAY=unix$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix skrooge ### Flatpak [https://community.kde.org/Guidelines_and_HOWTOs/Flatpak] #### Build mkdir app repo flatpak install flathub org.kde.Platform//5.12 flatpak install flathub org.kde.Sdk//5.12 flatpak install flathub io.qt.qtwebkit.BaseApp//5.12 flatpak-builder --ccache --repo=repo --subject="Build of skrooge `date`" skrooge org.kde.skrooge.json --force-clean #### Install flatpak uninstall org.kde.skrooge flatpak install skrooge org.kde.skrooge #### Run flatpak run org.kde.skrooge #### Debug flatpak run --command=sh --devel org.kde.skrooge ### Convert all logo in 100x100 for x in /home/s/Developpements/skrooge/images/logos/*.png do convert $x -resize 100x100 $x done diff --git a/plugins/skrooge/skrooge_unit/skgunitplugin.cpp b/plugins/skrooge/skrooge_unit/skgunitplugin.cpp index 9adeb362b..0f61951d2 100644 --- a/plugins/skrooge/skrooge_unit/skgunitplugin.cpp +++ b/plugins/skrooge/skrooge_unit/skgunitplugin.cpp @@ -1,628 +1,665 @@ /*************************************************************************** * Copyright (C) 2008 by S. MANKOWSKI / G. DE BURE support@mankowski.fr * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see * ***************************************************************************/ /** @file * This file is Skrooge plugin for unit management. * * @author Stephane MANKOWSKI / Guillaume DE BURE */ #include "skgunitplugin.h" #include #include #include +#include #include #include #include #include "skgdocumentbank.h" #include "skghtmlboardwidget.h" #include "skgmainpanel.h" #include "skgtraces.h" #include "skgtransactionmng.h" #include "skgunit_settings.h" #include "skgunitboardwidget.h" #include "skgunitpluginwidget.h" #include "skgunitvalueobject.h" /** * This plugin factory. */ K_PLUGIN_FACTORY(SKGUnitPluginFactory, registerPlugin();) SKGUnitPlugin::SKGUnitPlugin(QWidget* iWidget, QObject* iParent, const QVariantList& /*iArg*/) : SKGInterfacePlugin(iParent), m_currentBankDocument(nullptr) { Q_UNUSED(iWidget) SKGTRACEINFUNC(10) } SKGUnitPlugin::~SKGUnitPlugin() { SKGTRACEINFUNC(10) m_currentBankDocument = nullptr; } bool SKGUnitPlugin::setupActions(SKGDocument* iDocument) { SKGTRACEINFUNC(10) m_currentBankDocument = qobject_cast(iDocument); if (m_currentBankDocument == nullptr) { return false; } setComponentName(QStringLiteral("skrooge_unit"), title()); setXMLFile(QStringLiteral("skrooge_unit.rc")); // Menu auto actSplitShare = new QAction(SKGServices::fromTheme(QStringLiteral("format-text-strikethrough")), i18nc("Verb", "Split share..."), this); connect(actSplitShare, &QAction::triggered, this, &SKGUnitPlugin::onSplitShare); actionCollection()->setDefaultShortcut(actSplitShare, Qt::ALT + Qt::Key_Slash); registerGlobalAction(QStringLiteral("edit_split_stock"), actSplitShare, QStringList() << QStringLiteral("unit"), 1, 1, 310); // TODO(Stephane MANKOWSKI): must be a share // ----------- auto act = new QAction(SKGServices::fromTheme(icon()), i18nc("Verb", "Delete unused units"), this); connect(act, &QAction::triggered, this, &SKGUnitPlugin::deleteUnusedUnits); registerGlobalAction(QStringLiteral("clean_delete_unused_units"), act); return true; } int SKGUnitPlugin::getNbDashboardWidgets() { return 2; } QString SKGUnitPlugin::getDashboardWidgetTitle(int iIndex) { if (iIndex == 0) { return i18nc("Noun, the title of a section", "Quotes"); } return i18nc("Noun, the title of a section", "Stock portfolio"); } SKGBoardWidget* SKGUnitPlugin::getDashboardWidget(int iIndex) { if (iIndex == 0) { return new SKGUnitBoardWidget(SKGMainPanel::getMainPanel(), m_currentBankDocument); } // Get QML mode for dashboard KConfigSkeleton* skl = SKGMainPanel::getMainPanel()->getPluginByName(QStringLiteral("Dashboard plugin"))->getPreferenceSkeleton(); KConfigSkeletonItem* sklItem = skl->findItem(QStringLiteral("qmlmode")); bool qml = sklItem->property().toBool(); return new SKGHtmlBoardWidget(SKGMainPanel::getMainPanel(), m_currentBankDocument, getDashboardWidgetTitle(iIndex), QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("skrooge/html/default/portfolio.") % (qml ? QStringLiteral("qml") : QStringLiteral("html"))), QStringList() << QStringLiteral("v_operation_display")); } void SKGUnitPlugin::refresh() { SKGTRACEINFUNC(10) if ((SKGMainPanel::getMainPanel() != nullptr) && (m_currentBankDocument != nullptr)) { // Automatic download QString doc_id = m_currentBankDocument->getUniqueIdentifier(); if (m_docUniqueIdentifier != doc_id) { m_docUniqueIdentifier = doc_id; // Check if current unit is existing bool exist = false; SKGError err = m_currentBankDocument->existObjects(QStringLiteral("unit"), QLatin1String(""), exist); IFOK(err) { if (!exist) { SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Create default unit"), err) IFOK(err) { // Create default unit SKGUnitObject unit; QString unitS = QLocale().currencySymbol(QLocale::CurrencyIsoCode); if (!unitS.isEmpty()) { err = SKGUnitObject::createCurrencyUnit(m_currentBankDocument, unitS, unit); } // The file is considered has not modified m_currentBankDocument->setFileNotModified(); } } else if (skgunit_settings::download_on_open()) { // Check frequency QString lastAutomaticDownload = m_currentBankDocument->getParameter(QStringLiteral("SKG_LAST_UNIT_AUTOMATIC_DOWNLOAD")); if (lastAutomaticDownload.isEmpty()) { lastAutomaticDownload = QStringLiteral("1970-01-01"); } QDate lastAutomaticDownloadDate = QDate::fromString(lastAutomaticDownload, QStringLiteral("yyyy-MM-dd")); if ((lastAutomaticDownloadDate.daysTo(QDate::currentDate()) >= 1 && skgunit_settings::download_frequency() == 0) || (lastAutomaticDownloadDate.daysTo(QDate::currentDate()) >= 7 && skgunit_settings::download_frequency() == 1) || (lastAutomaticDownloadDate.daysTo(QDate::currentDate()) >= 30 && skgunit_settings::download_frequency() == 2)) { // Download all units SKGObjectBase::SKGListSKGObjectBase selection; err = m_currentBankDocument->getObjects(QStringLiteral("unit"), QLatin1String(""), selection); int nb = selection.count(); SKGBEGINPROGRESSTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Automatic download of units"), err, nb) for (int i = 0; !err && i < nb; ++i) { SKGUnitObject unit(selection.at(i)); err = SKGUnitPluginWidget::downloadUnitValue(unit, SKGUnitPluginWidget::getDownloadModeFromSettings()); // Send message IFOKDO(err, m_currentBankDocument->sendMessage(i18nc("An information to the user", "The unit '%1' has been downloaded", unit.getDisplayName()), SKGDocument::Hidden)) IFOKDO(err, m_currentBankDocument->stepForward(i + 1)) } // Memorize the last download date IFOKDO(err, m_currentBankDocument->setParameter(QStringLiteral("SKG_LAST_UNIT_AUTOMATIC_DOWNLOAD"), QDate::currentDate().toString(QStringLiteral("yyyy-MM-dd")))) } } } // Display error SKGMainPanel::displayErrorMessage(err); } } } SKGTabPage* SKGUnitPlugin::getWidget() { SKGTRACEINFUNC(10) return new SKGUnitPluginWidget(SKGMainPanel::getMainPanel(), m_currentBankDocument); } QWidget* SKGUnitPlugin::getPreferenceWidget() { SKGTRACEINFUNC(10) auto w = new QWidget(); ui.setupUi(w); + + // Get sources from.desktop file + QStringList sources; + const auto list2 = KServiceTypeTrader::self()->query(QStringLiteral("skrooge/source")); + for (const auto& service : list2) { + auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QVariant::String).toString(); + auto keyAPI = service->property(QStringLiteral("X-SKROOGE-keyAPI"), QVariant::Bool).toBool(); + if (!sources.contains(name) && keyAPI) { + sources.push_back(name); + } + } + sources.sort(); + + auto nb = sources.count(); + auto lwidgets = new QHash(); + for (auto i = 0; i < nb; ++i) { + // Get Current value + auto ln = new QLineEdit(w); + ln->setText(m_currentBankDocument->getParameter("KEYAPI_" + sources[i])); + lwidgets->insert(sources.value(i), ln); + + ui.kAPIKeyLayout->addWidget(new QLabel(sources[i] + ':', w), i, 0); + ui.kAPIKeyLayout->addWidget(ln, i, 1); + } + connect(ui.kcfg_download_on_open, &QCheckBox::toggled, ui.kcfg_download_frequency, &KComboBox::setEnabled); + connect(ui.kSave, &QPushButton::clicked, this, [ = ]() { + SKGError err; + { + SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Save API keys"), err) + foreach (auto k, lwidgets->keys()) { + m_currentBankDocument->setParameter("KEYAPI_" + k, lwidgets->value(k)->text()); + } + } + // Display error + SKGMainPanel::displayErrorMessage(err); + }); return w; } KConfigSkeleton* SKGUnitPlugin::getPreferenceSkeleton() { return skgunit_settings::self(); } QString SKGUnitPlugin::title() const { return i18nc("Noun, units for operations, usually currencies or a shares", "Units"); } QString SKGUnitPlugin::icon() const { return QStringLiteral("taxes-finances"); } QString SKGUnitPlugin::toolTip() const { return i18nc("A tool tip", "Unit management"); } QStringList SKGUnitPlugin::tips() const { QStringList output; output.push_back(i18nc("Description of a tips", "

... you can download units.

")); output.push_back(i18nc("Description of a tips", "

... units can be downloaded automatically when a document is opened.

")); output.push_back(i18nc("Description of a tips", "

... you can split a share.

")); output.push_back(i18nc("Description of a tips", "

... units can be merged by drag & drop.

")); output.push_back(i18nc("Description of a tips", "

... you can download more sources of quote.

")); output.push_back(i18nc("Description of a tips", "

... you can create and share your own source of quote.

")); return output; } int SKGUnitPlugin::getOrder() const { return 60; } bool SKGUnitPlugin::isInPagesChooser() const { return true; } void SKGUnitPlugin::onSplitShare() { SKGError err; SKGTRACEINFUNCRC(10, err) // Get Selection if (SKGMainPanel::getMainPanel() != nullptr) { SKGObjectBase::SKGListSKGObjectBase selection = SKGMainPanel::getMainPanel()->getSelectedObjects(); int nb = selection.count(); if (nb == 1) { bool ok = false; double ratio = QInputDialog::getDouble(SKGMainPanel::getMainPanel(), i18nc("Question", "Split share"), i18nc("Question", "Ratio (2 means 2-for-1, 0.5 means 1-for-2):"), 2.0, 0, std::numeric_limits::max(), 8, &ok); if (ok) { SKGUnitObject unit(selection.at(0)); SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Split stock '%1' by '%2'", unit.getName(), ratio), err) IFOKDO(err, unit.split(ratio)) } } // status IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Stock split."))) else { err.addError(ERR_FAIL, i18nc("Error message", "Splitting stock failed.")); } // Display error SKGMainPanel::displayErrorMessage(err); } } SKGAdviceList SKGUnitPlugin::advice(const QStringList& iIgnoredAdvice) { SKGTRACEINFUNC(10) SKGAdviceList output; output.reserve(20); // Get all currencies SKGStringListList result; m_currentBankDocument->executeSelectSqliteOrder(QStringLiteral("SELECT (SELECT count(1) FROM operation WHERE operation.rc_unit_id=unit.id), unit.t_name FROM unit WHERE t_type='C' GROUP BY t_name ORDER BY count(1) DESC"), result); int nb = result.count(); // Check primary unit if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_primaryunit"))) { if (m_currentBankDocument->getPrimaryUnit().Name.isEmpty() && nb > 1) { // Get unit QString unit = result.at(1).at(1); SKGAdvice ad; ad.setUUID("skgunitplugin_primaryunit|" % unit); ad.setPriority(8); ad.setShortMessage(i18nc("Advice on making the best (short)", "Define a primary currency")); ad.setLongMessage(i18nc("Advice on making the best (long)", "To avoid misunderstanding and conflicts between units at conversion time, you should define a primary currency. It is the currency against which all other will be converted")); SKGAdvice::SKGAdviceActionList autoCorrections; { SKGAdvice::SKGAdviceAction a; a.Title = i18nc("Advice on making the best (action)", "Set '%1' as primary currency", unit); a.IconName = icon(); a.IsRecommended = true; autoCorrections.push_back(a); } { SKGAdvice::SKGAdviceAction a; a.Title = i18nc("Advice on making the best (action)", "Edit units"); a.IconName = icon(); a.IsRecommended = false; autoCorrections.push_back(a); } ad.setAutoCorrections(autoCorrections); output.push_back(ad); --nb; } } // Check secondary unit if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_secondaryunit"))) { if (m_currentBankDocument->getSecondaryUnit().Name.isEmpty() && nb > 1) { // Get unit QString unit = result.at(1).at(1); SKGAdvice ad; ad.setUUID("skgunitplugin_secondaryunit|" % unit); ad.setPriority(2); ad.setShortMessage(i18nc("Advice on making the best (short)", "Define a secondary currency")); ad.setLongMessage(i18nc("Advice on making the best (long)", "When a secondary unit is defined, Skrooge will display it as an additional amount information.")); SKGAdvice::SKGAdviceActionList autoCorrections; { SKGAdvice::SKGAdviceAction a; a.Title = i18nc("Advice on making the best (action)", "Set '%1' as secondary currency", unit); a.IconName = icon(); a.IsRecommended = true; autoCorrections.push_back(a); } { SKGAdvice::SKGAdviceAction a; a.Title = i18nc("Advice on making the best (action)", "Edit units"); a.IconName = icon(); a.IsRecommended = false; autoCorrections.push_back(a); } ad.setAutoCorrections(autoCorrections); output.push_back(ad); } } // Shares not downloaded if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_notdownloaded"))) { m_currentBankDocument->executeSelectSqliteOrder(QStringLiteral("SELECT t_name, t_internet_code from unit WHERE t_internet_code<>'' AND (julianday('now')-(SELECT MAX(julianday(d_date)) FROM unitvalue WHERE rd_unit_id=unit.id ))>30 OR NOT EXISTS (SELECT 1 FROM unitvalue WHERE unitvalue.rd_unit_id=unit.id)"), result); nb = result.count(); SKGAdvice::SKGAdviceActionList autoCorrections; autoCorrections.reserve(nb); for (int i = 1; i < nb; ++i) { // Ignore header // Get parameters const QStringList& line = result.at(i); const QString& unit = line.at(0); const QString& internet_code = line.at(1); SKGAdvice ad; ad.setUUID("skgunitplugin_notdownloaded|" % unit); ad.setPriority(5); ad.setShortMessage(i18nc("Advice on making the best (short)", "Unit '%1' has not been downloaded for more than a month", unit)); ad.setLongMessage(i18nc("Advice on making the best (long)", "Do not forget download units to have a better view of your accounts")); autoCorrections.resize(0); { SKGAdvice::SKGAdviceAction a; a.Title = i18nc("Advice on making the best (action)", "Edit units"); a.IconName = icon(); a.IsRecommended = false; autoCorrections.push_back(a); } if (!internet_code.isEmpty()) { SKGAdvice::SKGAdviceAction a; a.Title = i18nc("Advice on making the best (action)", "Download '%1'", unit); a.IconName = QStringLiteral("download"); a.IsRecommended = true; autoCorrections.push_back(a); } ad.setAutoCorrections(autoCorrections); output.push_back(ad); } } // Check unused units if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_unused"))) { bool exist = false; m_currentBankDocument->existObjects(QStringLiteral("unit"), QStringLiteral("t_type NOT IN ('I', '1', '2') AND NOT EXISTS (SELECT 1 FROM operation WHERE operation.rc_unit_id=unit.id) AND NOT EXISTS (SELECT 1 FROM unit as unit2 WHERE unit2.rd_unit_id=unit.id)"), exist); if (exist) { SKGAdvice ad; ad.setUUID(QStringLiteral("skgunitplugin_unused")); ad.setPriority(5); ad.setShortMessage(i18nc("Advice on making the best (short)", "Many unused units")); ad.setLongMessage(i18nc("Advice on making the best (long)", "You can improve performances by removing units for which no operation is registered.")); QStringList autoCorrections; autoCorrections.push_back(QStringLiteral("skg://clean_delete_unused_units")); ad.setAutoCorrections(autoCorrections); output.push_back(ad); } } // Check unit too complex if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_amountnotdefined"))) { m_currentBankDocument->executeSelectSqliteOrder(QStringLiteral("SELECT t_name FROM v_unit WHERE t_type IN ('2','C') AND f_CURRENTAMOUNT=1"), result); nb = result.count(); SKGAdvice::SKGAdviceActionList autoCorrections; autoCorrections.reserve(nb); for (int i = 1; i < nb; ++i) { // Ignore header // Get parameters const QStringList& line = result.at(i); const QString& unit = line.at(0); SKGAdvice ad; ad.setUUID("skgunitplugin_amountnotdefined|" % unit); ad.setPriority(9); ad.setShortMessage(i18nc("Advice on making the best (short)", "The amount of the unit '%1' is not defined", unit)); ad.setLongMessage(i18nc("Advice on making the best (long)", "'%1' has an amount defined at 1. Most of the time this is not normal and causes wrong computation. Check if this is normal.", unit)); autoCorrections.resize(0); { SKGAdvice::SKGAdviceAction a; a.Title = i18nc("Advice on making the best (action)", "Edit units"); a.IconName = icon(); a.IsRecommended = false; autoCorrections.push_back(a); } ad.setAutoCorrections(autoCorrections); output.push_back(ad); } } // Check unit too complex if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_toocomplex"))) { m_currentBankDocument->executeSelectSqliteOrder(QStringLiteral("SELECT A.t_name FROM unit A, unit B, unit C, unit D WHERE A.rd_unit_id=B.id AND B.rd_unit_id=C.id AND C.rd_unit_id=D.id"), result); nb = result.count(); SKGAdvice::SKGAdviceActionList autoCorrections; autoCorrections.reserve(nb); for (int i = 1; i < nb; ++i) { // Ignore header // Get parameters const QStringList& line = result.at(i); const QString& unit = line.at(0); SKGAdvice ad; ad.setUUID(QStringLiteral("skgunitplugin_toocomplex")); ad.setPriority(9); ad.setShortMessage(i18nc("Advice on making the best (short)", "The definition of the unit '%1' is too complex", unit)); ad.setLongMessage(i18nc("Advice on making the best (long)", "'%1' is defined relatively to another unit defined relatively to a third one. This is too complex and not supported by Skrooge.", unit)); autoCorrections.resize(0); { SKGAdvice::SKGAdviceAction a; a.Title = i18nc("Advice on making the best (action)", "Edit units"); a.IconName = icon(); a.IsRecommended = false; autoCorrections.push_back(a); } ad.setAutoCorrections(autoCorrections); output.push_back(ad); } } // Unit with very old values if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_veryold"))) { m_currentBankDocument->executeSelectSqliteOrder(QStringLiteral("SELECT t_name from unit WHERE (SELECT COUNT(*) FROM unitvalue WHERE unitvalue.rd_unit_id=unit.id)>1 AND EXISTS (SELECT 1 FROM unitvalue WHERE unitvalue.rd_unit_id=unit.id AND unitvalue.d_date<=(SELECT date('now', '-50 year')))"), result); nb = result.count(); SKGAdvice::SKGAdviceActionList autoCorrections; autoCorrections.reserve(nb); for (int i = 1; i < nb; ++i) { // Ignore header // Get parameters const QStringList& line = result.at(i); const QString& unit = line.at(0); SKGAdvice ad; ad.setUUID("skgunitplugin_veryold|" % unit); ad.setPriority(3); ad.setShortMessage(i18nc("Advice on making the best (short)", "Unit '%1' has very old values", unit)); ad.setLongMessage(i18nc("Advice on making the best (long)", "Unit '%1' has very old values. Check if this is normal.", unit)); autoCorrections.resize(0); { SKGAdvice::SKGAdviceAction a; a.Title = i18nc("Advice on making the best (action)", "Edit units"); a.IconName = icon(); a.IsRecommended = false; autoCorrections.push_back(a); } ad.setAutoCorrections(autoCorrections); output.push_back(ad); } } // No decimal settings if (!iIgnoredAdvice.contains(QStringLiteral("skgunitplugin_decimalsymbol")) && QLocale().decimalPoint().isNull()) { SKGAdvice ad; ad.setUUID(QStringLiteral("skgunitplugin_decimalsymbol")); ad.setPriority(9); ad.setShortMessage(i18nc("Advice on making the best (short)", "No decimal symbol defined")); ad.setLongMessage(i18nc("Advice on making the best (long)", "In KDE localization settings, there is no decimal symbol defined for currencies. This could be confusing.")); SKGAdvice::SKGAdviceActionList autoCorrections; { SKGAdvice::SKGAdviceAction a; a.Title = i18nc("Advice on making the best (action)", "Edit KDE settings"); a.IconName = QStringLiteral("configure"); a.IsRecommended = false; autoCorrections.push_back(a); } ad.setAutoCorrections(autoCorrections); output.push_back(ad); } return output; } SKGError SKGUnitPlugin::executeAdviceCorrection(const QString& iAdviceIdentifier, int iSolution) { if ((m_currentBankDocument != nullptr) && iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_primaryunit|"))) { if (iSolution == 1) { SKGMainPanel::getMainPanel()->openPage(QStringLiteral("skg://skrooge_unit_plugin")); } else { // Get parameters QString unit = iAdviceIdentifier.right(iAdviceIdentifier.length() - 26); SKGError err; { SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Define primary currency"), err) SKGUnitObject unitObj(m_currentBankDocument); err = unitObj.setName(unit); IFOKDO(err, unitObj.load()) IFOKDO(err, unitObj.setType(SKGUnitObject::PRIMARY)) IFOKDO(err, unitObj.save()) // Send message IFOKDO(err, unitObj.getDocument()->sendMessage(i18nc("An information to the user", "The unit '%1' is now the primary unit", unitObj.getDisplayName()), SKGDocument::Hidden)) } // status bar IFOKDO(err, SKGError(0, i18nc("Message for successful user action", "Primary currency defined."))) else { err.addError(ERR_FAIL, i18nc("Error message", "Primary currency definition failed")); } // Display error SKGMainPanel::displayErrorMessage(err); } return SKGError(); } if ((m_currentBankDocument != nullptr) && iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_secondaryunit|"))) { if (iSolution == 1) { SKGMainPanel::getMainPanel()->openPage(QStringLiteral("skg://skrooge_unit_plugin")); } else { // Get parameters QString unit = iAdviceIdentifier.right(iAdviceIdentifier.length() - 28); SKGError err; { SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Define secondary currency"), err) SKGUnitObject unitObj(m_currentBankDocument); err = unitObj.setName(unit); IFOKDO(err, unitObj.load()) IFOKDO(err, unitObj.setType(SKGUnitObject::SECONDARY)) IFOKDO(err, unitObj.save()) // Send message IFOKDO(err, unitObj.getDocument()->sendMessage(i18nc("An information to the user", "The unit '%1' is now the secondary unit", unitObj.getDisplayName()), SKGDocument::Hidden)) } // status bar IFOKDO(err, SKGError(0, i18nc("Message for successful user action", "Secondary currency defined."))) else { err.addError(ERR_FAIL, i18nc("Error message", "Secondary currency definition failed")); } // Display error SKGMainPanel::displayErrorMessage(err); } return SKGError(); } if ((m_currentBankDocument != nullptr) && iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_notdownloaded|"))) { if (iSolution == 0) { SKGMainPanel::getMainPanel()->openPage(QStringLiteral("skg://skrooge_unit_plugin")); } else { // Get parameters QString unit = iAdviceIdentifier.right(iAdviceIdentifier.length() - 28); SKGError err; SKGUnitObject unitObj(m_currentBankDocument); err = unitObj.setName(unit); IFOKDO(err, unitObj.load()) IFOKDO(err, SKGUnitPluginWidget::downloadUnitValue(unitObj, SKGUnitPluginWidget::getDownloadModeFromSettings())) // Display error SKGMainPanel::displayErrorMessage(err); } return SKGError(); } if ((m_currentBankDocument != nullptr) && (iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_veryold|")) || iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_toocomplex")) || iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_amountnotdefined|"))) ) { SKGMainPanel::getMainPanel()->openPage(QStringLiteral("skg://skrooge_unit_plugin")); return SKGError(); } if ((m_currentBankDocument != nullptr) && iAdviceIdentifier.startsWith(QLatin1String("skgunitplugin_decimalsymbol"))) { QProcess::execute(QStringLiteral("kcmshell5"), QStringList() << QStringLiteral("formats")); return SKGError(); } return SKGInterfacePlugin::executeAdviceCorrection(iAdviceIdentifier, iSolution); } void SKGUnitPlugin::deleteUnusedUnits() const { SKGError err; _SKGTRACEINFUNCRC(10, err) if (m_currentBankDocument != nullptr) { SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Delete unused units"), err) // Modification of payee object QString sql = QStringLiteral("DELETE FROM unit WHERE t_type NOT IN ('I', '1', '2') AND NOT EXISTS (SELECT 1 FROM operation WHERE operation.rc_unit_id=unit.id) AND NOT EXISTS (SELECT 1 FROM unit as unit2 WHERE unit2.rd_unit_id=unit.id)"); err = m_currentBankDocument->executeSqliteOrder(sql); } // status bar IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Unused units deleted"))) else { err.addError(ERR_FAIL, i18nc("Error message", "Unused units deletion failed")); } // Display error SKGMainPanel::displayErrorMessage(err); } #include diff --git a/plugins/skrooge/skrooge_unit/skgunitpluginwidget_pref.ui b/plugins/skrooge/skrooge_unit/skgunitpluginwidget_pref.ui index 8ee9c3990..47ce22990 100644 --- a/plugins/skrooge/skrooge_unit/skgunitpluginwidget_pref.ui +++ b/plugins/skrooge/skrooge_unit/skgunitpluginwidget_pref.ui @@ -1,197 +1,236 @@ skgunitplugin_pref 0 0 - 328 - 334 + 596 + 542 2 Download on open false Once a day Once a week Once a month Qt::Horizontal 40 20 Download mode 2 Last &value found only &Monthly values since last download Wee&kly values since last download Dail&y values since last download Monthly values for all dates Weekly values for all dates Daily values for all dates 2 Maximum num&ber of imported values: kcfg_nb_loaded_values 50 Qt::Horizontal 40 20 + + + + API Keys + + + + + + <html><head/><body><p>Some download sources (e.g. coinmarketcap, cryptocompare) may require an API key. So you need to request one from the source site and enter it here:</p></body></html> + + + true + + + + + + + 2 + + + + + + + For security reasons, these keys are not save in setting file but in your document. + + + Save in document + + + true + + + + + + Qt::Vertical 20 44 KComboBox QComboBox
kcombobox.h
kcfg_download_on_open kcfg_download_frequency kcfg_last kcfg_last_monthly kcfg_last_weekly kcfg_last_daily kcfg_all_monthly kcfg_all_weekly kcfg_all_daily kcfg_nb_loaded_values
diff --git a/skgbankmodeler/CMakeLists.txt b/skgbankmodeler/CMakeLists.txt index 2200064f5..1adb57f01 100644 --- a/skgbankmodeler/CMakeLists.txt +++ b/skgbankmodeler/CMakeLists.txt @@ -1,62 +1,63 @@ #*************************************************************************** #* Copyright (C) 2008 by S. MANKOWSKI / G. DE BURE support@mankowski.fr * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU General Public License as published by * #* the Free Software Foundation; either version 2 of the License, or * #* (at your option) any later version. * #* * #* This program is distributed in the hope that it will be useful, * #* but WITHOUT ANY WARRANTY; without even the implied warranty of * #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * #* GNU General Public License for more details. * #* * #* You should have received a copy of the GNU General Public License * #* along with this program. If not, see * #*************************************************************************** MESSAGE( STATUS "..:: CMAKE SKGBANKMODELER ::..") PROJECT(SKGBANKMODELER) LINK_DIRECTORIES (${LIBRARY_OUTPUT_PATH}) SET(skgbankmodeler_SRCS skgbankobject.cpp skgbudgetobject.cpp skgbudgetruleobject.cpp skgaccountobject.cpp skgoperationobject.cpp skgrecurrentoperationobject.cpp skgtrackerobject.cpp skgpayeeobject.cpp skgsuboperationobject.cpp skgcategoryobject.cpp skgunitobject.cpp skgunitvalueobject.cpp skgruleobject.cpp skginterestobject.cpp skgdocumentbank.cpp skgimportexportmanager.cpp skgimportplugin.cpp skgreportbank.cpp ) #build a shared library ADD_LIBRARY(skgbankmodeler SHARED ${skgbankmodeler_SRCS}) #need to link to some other libraries ? just add them here TARGET_LINK_LIBRARIES(skgbankmodeler LINK_PUBLIC KF5::Parts Qt5::Xml skgbasemodeler) SET_TARGET_PROPERTIES( skgbankmodeler PROPERTIES VERSION ${SKG_VERSION} SOVERSION ${SOVERSION} ) GENERATE_EXPORT_HEADER(skgbankmodeler BASE_NAME skgbankmodeler) ADD_SUBDIRECTORY(currency) ########### install files ############### INSTALL(TARGETS skgbankmodeler ${INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP) INSTALL(FILES ${PROJECT_SOURCE_DIR}/org.kde.skrooge-import-plugin.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) INSTALL(FILES ${PROJECT_SOURCE_DIR}/org.kde.skrooge-source-plugin.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) INSTALL(DIRECTORY sources DESTINATION ${KDE_INSTALL_KSERVICES5DIR} FILES_MATCHING PATTERN "*.desktop") INSTALL(PROGRAMS skrooge-yahoodl.py DESTINATION ${KDE_INSTALL_DATADIR}/skrooge) INSTALL(PROGRAMS skrooge-ratesapi.py DESTINATION ${KDE_INSTALL_DATADIR}/skrooge) INSTALL(PROGRAMS skrooge-cryptocompare.py DESTINATION ${KDE_INSTALL_DATADIR}/skrooge) +INSTALL(PROGRAMS skrooge-coinmarketcap.py DESTINATION ${KDE_INSTALL_DATADIR}/skrooge) diff --git a/skgbankmodeler/skgunitobject.cpp b/skgbankmodeler/skgunitobject.cpp index 1298584a5..20d5b2444 100644 --- a/skgbankmodeler/skgunitobject.cpp +++ b/skgbankmodeler/skgunitobject.cpp @@ -1,2578 +1,2582 @@ /*************************************************************************** * Copyright (C) 2008 by S. MANKOWSKI / G. DE BURE support@mankowski.fr * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see * ***************************************************************************/ /** @file * This file defines classes SKGUnitObject. * * @author Stephane MANKOWSKI / Guillaume DE BURE */ #include "skgunitobject.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "skgdocumentbank.h" #include "skgoperationobject.h" #include "skgtraces.h" #include "skgtransactionmng.h" #include "skgunitvalueobject.h" SKGUnitObject::SKGUnitObject() : SKGUnitObject(nullptr) {} SKGUnitObject::SKGUnitObject(SKGDocument* iDocument, int iID) : SKGNamedObject(iDocument, QStringLiteral("v_unit"), iID) {} SKGUnitObject::~SKGUnitObject() = default; SKGUnitObject::SKGUnitObject(const SKGUnitObject& iObject) = default; SKGUnitObject::SKGUnitObject(const SKGNamedObject& iObject) { if (iObject.getRealTable() == QStringLiteral("unit")) { copyFrom(iObject); } else { *this = SKGNamedObject(iObject.getDocument(), QStringLiteral("v_unit"), iObject.getID()); } } SKGUnitObject::SKGUnitObject(const SKGObjectBase& iObject) { if (iObject.getRealTable() == QStringLiteral("unit")) { copyFrom(iObject); } else { *this = SKGNamedObject(iObject.getDocument(), QStringLiteral("v_unit"), iObject.getID()); } } SKGUnitObject& SKGUnitObject::operator= (const SKGObjectBase& iObject) { copyFrom(iObject); return *this; } QString SKGUnitObject::getWhereclauseId() const { QString output = SKGObjectBase::getWhereclauseId(); // clazy:exclude=skipped-base-method if (output.isEmpty()) { QString name = getName(); if (!name.isEmpty()) { output = "t_name='" % SKGServices::stringToSqlString(name) % '\''; } QString symbol = getSymbol(); if (!symbol.isEmpty()) { if (!output.isEmpty()) { output += QStringLiteral(" OR "); } output += "t_symbol='" % SKGServices::stringToSqlString(symbol) % '\''; } if (!output.isEmpty()) { output = '(' % output % ')'; } } return output; } QList SKGUnitObject::currencies; QStringList SKGUnitObject::getListofKnownCurrencies(bool iIncludingObsolete) { SKGTRACEINFUNC(10) if (currencies.isEmpty()) { // Search currencies const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("skrooge/currency/"), QStandardPaths::LocateDirectory); for (const auto& dir : dirs) { auto listDesktopFiles = QDir(dir).entryList(QStringList() << QStringLiteral("*.desktop")); for (const auto& path : qAsConst(listDesktopFiles)) { // Read the file QFileInfo file(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("skrooge/currency/") + path)); KConfig cgFile(file.absoluteFilePath()); KConfigGroup cg(&cgFile, QStringLiteral("Currency Code")); SKGServices::SKGUnitInfo unit; unit.Name = cg.readEntry(QStringLiteral("Name"), QString()) + QStringLiteral(" (") + cg.readEntry(QStringLiteral("CurrencyCodeIsoAlpha3"), QString()) + QStringLiteral(")"); unit.Symbol = cg.readEntry(QStringLiteral("CurrencyUnitSymbolDefault"), QString()); if (unit.Symbol.isEmpty()) { unit.Symbol = cg.readEntry(QStringLiteral("CurrencyCodeIsoAlpha3"), file.baseName()); } unit.Value = 1; unit.NbDecimal = cg.readEntry(QStringLiteral("CurrencyDecimalPlacesDisplay"), 2); unit.Source = QStringLiteral("GrandTrunk"); unit.Date = cg.readEntry(QStringLiteral("CurrencyIntroducedDate"), QDate::currentDate()); unit.Obsolete = (cg.readEntry(QStringLiteral("CurrencySuspendedDate"), cg.readEntry(QStringLiteral("CurrencyWithdrawnDate"), QDate())) != QDate()); currencies.push_back(unit); } } // Add other units { // CAC40 SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a currency", "CAC 40"); info.Symbol = info.Name; info.Country = i18nc("Noun, a country", "France"); info.Date = QDate(1987, 1, 1); info.Internet = QStringLiteral("^FCHI"); info.Source = QStringLiteral("Yahoo"); info.NbDecimal = 2; info.Value = -1; currencies.push_back(info); } { // NASDAQ SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a currency", "NASDAQ"); info.Symbol = info.Name; info.Country = i18nc("Noun, a country", "United States"); info.Date = QDate(1971, 2, 5); info.Internet = QStringLiteral("^IXIC"); info.Source = QStringLiteral("Yahoo"); info.NbDecimal = 2; info.Value = -1; currencies.push_back(info); } { // Dow Jones SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a currency", "Dow Jones (DJIA)"); info.Symbol = QStringLiteral("DJIA"); info.Country = i18nc("Noun, a country", "United States"); info.Date = QDate(1884, 1, 1); info.Internet = QStringLiteral("^DJI"); info.Source = QStringLiteral("Yahoo"); info.NbDecimal = 2; info.Value = -1; currencies.push_back(info); } { // SBF 120 SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a currency", "SBF 120"); info.Symbol = info.Name; info.Country = i18nc("Noun, a country", "France"); info.Date = QDate(1990, 12, 31); info.Internet = QStringLiteral("^SBF120"); info.Source = QStringLiteral("Yahoo"); info.NbDecimal = 2; info.Value = -1; currencies.push_back(info); } { // S&P 500 SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a currency", "S&P 500"); info.Symbol = info.Name; info.Country = i18nc("Noun, a country", "United States"); info.Date = QDate(1920, 1, 1); info.Internet = QStringLiteral("^GSPC"); info.Source = QStringLiteral("Yahoo"); info.NbDecimal = 2; info.Value = -1; currencies.push_back(info); } { // FTSE 100 SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a currency", "FTSE 100"); info.Symbol = info.Name; info.Country = i18nc("Noun, a country", "England"); info.Date = QDate(1984, 1, 3); info.Internet = QStringLiteral("^FTSE"); info.Source = QStringLiteral("Yahoo"); info.NbDecimal = 2; info.Value = -1; currencies.push_back(info); } { // DAX SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a currency", "DAX"); info.Symbol = info.Name; info.Country = i18nc("Noun, a country", "Germany"); info.Date = QDate(1920, 1, 1); info.Internet = QStringLiteral("^GDAXI"); info.Source = QStringLiteral("Yahoo"); info.NbDecimal = 2; info.Value = -1; currencies.push_back(info); } { // NIKKEI 225 SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a currency", "NIKKEI 225"); info.Symbol = info.Name; info.Country = i18nc("Noun, a country", "Japan"); info.Date = QDate(1920, 1, 1); info.Internet = QStringLiteral("^N225"); info.Source = QStringLiteral("Yahoo"); info.NbDecimal = 2; info.Value = -1; currencies.push_back(info); } { // HANG SENG SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a currency", "HANG SENG"); info.Symbol = info.Name; info.Country = i18nc("Noun, a country", "China"); info.Date = QDate(1920, 1, 1); info.Internet = QStringLiteral("^HSI"); info.Source = QStringLiteral("Yahoo"); info.NbDecimal = 2; info.Value = -1; currencies.push_back(info); } { // STRAITS TIMES SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a currency", "STRAITS TIMES"); info.Symbol = info.Name; info.Date = QDate(1920, 1, 1); info.Country = i18nc("Noun, a country", "Singapore"); info.Internet = QStringLiteral("^STI"); info.Source = QStringLiteral("Yahoo"); info.NbDecimal = 2; info.Value = -1; currencies.push_back(info); } { // BITCOIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a currency", "Bitcoin"); info.Symbol = QStringLiteral("BTC"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("BTC"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // ETHEREUM SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Ethereum"); info.Symbol = QStringLiteral("ETH"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("ETH"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // RIPPLE SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Ripple"); info.Symbol = QStringLiteral("XRP"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("XRP"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // BITCOIN-CASH SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Bitcoin Cash"); info.Symbol = QStringLiteral("BCH"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("BCH"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // CARDANO SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Cardano"); info.Symbol = QStringLiteral("ADA"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("ADA"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // NEM SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "NEM"); info.Symbol = QStringLiteral("XEM"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("XEM"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // LITECOIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Litecoin"); info.Symbol = QStringLiteral("LTC"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("LTC"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // STELLAR SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Stellar"); info.Symbol = QStringLiteral("XLM"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("XLM"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // IOTA SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "IOTA"); info.Symbol = QStringLiteral("MIOTA"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("MIOTA"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // TRON SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "TRON"); info.Symbol = QStringLiteral("TRX"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("TRX"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // DASH SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Dash"); info.Symbol = QStringLiteral("DASH"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("DASH"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // NEO SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "NEO"); info.Symbol = QStringLiteral("NEO"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("NEO"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // MONERO SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Monero"); info.Symbol = QStringLiteral("XMR"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("XMR"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // EOS SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "EOS"); info.Symbol = QStringLiteral("EOS"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("EOS"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // QTUM SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Qtum"); info.Symbol = QStringLiteral("QTUM"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("QTUM"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // ICON SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "ICON"); info.Symbol = QStringLiteral("ICX"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("ICX"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // BITCOIN-GOLD SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Bitcoin Gold"); info.Symbol = QStringLiteral("BTG"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("BTG"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // LISK SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Lisk"); info.Symbol = QStringLiteral("LSK"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("LSK"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // RAIBLOCKS SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "RaiBlocks"); info.Symbol = QStringLiteral("XRB"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("XRB"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // ETHEREUM-CLASSIC SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Ethereum Classic"); info.Symbol = QStringLiteral("ETC"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("ETC"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // VERGE SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Verge"); info.Symbol = QStringLiteral("XVG"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("XVG"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // SIACOIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Siacoin"); info.Symbol = QStringLiteral("SC"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("SC"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // OMISEGO SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "OmiseGO"); info.Symbol = QStringLiteral("OMG"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("OMG"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // BYTECOIN-BCN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Bytecoin"); info.Symbol = QStringLiteral("BCN"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("BCN"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // BITCONNECT SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "BitConnect"); info.Symbol = QStringLiteral("BCC"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("BCC"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // POPULOUS SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Populous"); info.Symbol = QStringLiteral("PPT"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("PPT"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // STRATIS SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Stratis"); info.Symbol = QStringLiteral("STRAT"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("STRAT"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // ZCASH SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Zcash"); info.Symbol = QStringLiteral("ZEC"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("ZEC"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // DENTACOIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Dentacoin"); info.Symbol = QStringLiteral("DCN"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("DCN"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // BITSHARES SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "BitShares"); info.Symbol = QStringLiteral("BTS"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("BTS"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // BINANCE-COIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Binance Coin"); info.Symbol = QStringLiteral("BNB"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("BNB"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // DOGECOIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Dogecoin"); info.Symbol = QStringLiteral("DOGE"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("DOGE"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // STATUS SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Status"); info.Symbol = QStringLiteral("SNT"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("SNT"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // ARDOR SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Ardor"); info.Symbol = QStringLiteral("ARDR"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("ARDR"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // KUCOIN-SHARES SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "KuCoin Shares"); info.Symbol = QStringLiteral("KCS"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("KCS"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // TETHER SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Tether"); info.Symbol = QStringLiteral("USDT"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("USDT"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // STEEM SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Steem"); info.Symbol = QStringLiteral("STEEM"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("STEEM"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // WAVES SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Waves"); info.Symbol = QStringLiteral("WAVES"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("WAVES"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // VECHAIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "VeChain"); info.Symbol = QStringLiteral("VEN"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("VEN"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // DIGIBYTE SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "DigiByte"); info.Symbol = QStringLiteral("DGB"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("DGB"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // KOMODO SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Komodo"); info.Symbol = QStringLiteral("KMD"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("KMD"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // DRAGONCHAIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Dragonchain"); info.Symbol = QStringLiteral("DRGN"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("DRGN"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // AUGUR SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Augur"); info.Symbol = QStringLiteral("REP"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("REP"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // GOLEM-NETWORK-TOKENS SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Golem"); info.Symbol = QStringLiteral("GNT"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("GNT"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // VERITASEUM SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Veritaseum"); info.Symbol = QStringLiteral("VERI"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("VERI"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // HSHARE SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Hshare"); info.Symbol = QStringLiteral("HSR"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("HSR"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // KIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Kin"); info.Symbol = QStringLiteral("KIN"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("KIN"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // SALT SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "SALT"); info.Symbol = QStringLiteral("SALT"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("SALT"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // ELECTRONEUM SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Electroneum"); info.Symbol = QStringLiteral("ETN"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("ETN"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // ARK SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Ark"); info.Symbol = QStringLiteral("ARK"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("ARK"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // DENT SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Dent"); info.Symbol = QStringLiteral("DENT"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("DENT"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // ETHOS SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Ethos"); info.Symbol = QStringLiteral("ETHOS"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("ETHOS"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // BASIC-ATTENTION-TOKEN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Basic Attention Token"); info.Symbol = QStringLiteral("BAT"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("BAT"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // REDDCOIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "ReddCoin"); info.Symbol = QStringLiteral("RDD"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("RDD"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // 0X SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "0x"); info.Symbol = QStringLiteral("ZRX"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("ZRX"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // DECRED SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Decred"); info.Symbol = QStringLiteral("DCR"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("DCR"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // NEXUS SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Nexus"); info.Symbol = QStringLiteral("NXS"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("NXS"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // EXPERIENCE-POINTS SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Experience Points"); info.Symbol = QStringLiteral("XP"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("XP"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // QASH SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "QASH"); info.Symbol = QStringLiteral("QASH"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("QASH"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // KYBER-NETWORK SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Kyber Network"); info.Symbol = QStringLiteral("KNC"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("KNC"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // PIVX SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "PIVX"); info.Symbol = QStringLiteral("PIVX"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("PIVX"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // FUNFAIR SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "FunFair"); info.Symbol = QStringLiteral("FUN"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("FUN"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // FACTOM SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Factom"); info.Symbol = QStringLiteral("FCT"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("FCT"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // NEBLIO SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Neblio"); info.Symbol = QStringLiteral("NEBL"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("NEBL"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // REQUEST-NETWORK SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Request Network"); info.Symbol = QStringLiteral("REQ"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("REQ"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // AETERNITY SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Aeternity"); info.Symbol = QStringLiteral("AE"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("AE"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // SUBSTRATUM SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Substratum"); info.Symbol = QStringLiteral("SUB"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("SUB"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // POWER-LEDGER SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Power Ledger"); info.Symbol = QStringLiteral("POWR"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("POWR"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // WAX SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "WAX"); info.Symbol = QStringLiteral("WAX"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("WAX"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // AELF SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "aelf"); info.Symbol = QStringLiteral("ELF"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("ELF"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // BYTOM SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Bytom"); info.Symbol = QStringLiteral("BTM"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("BTM"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // AION SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Aion"); info.Symbol = QStringLiteral("AION"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("AION"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // RCHAIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "RChain"); info.Symbol = QStringLiteral("RHOC"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("RHOC"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // DIGITALNOTE SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "DigitalNote"); info.Symbol = QStringLiteral("XDN"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("XDN"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // ENIGMA-PROJECT SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Enigma"); info.Symbol = QStringLiteral("ENG"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("ENG"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // NXT SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Nxt"); info.Symbol = QStringLiteral("NXT"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("NXT"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // TIME-NEW-BANK SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Time New Bank"); info.Symbol = QStringLiteral("TNB"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("TNB"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // BITCOINDARK SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "BitcoinDark"); info.Symbol = QStringLiteral("BTCD"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("BTCD"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // MONACOIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "MonaCoin"); info.Symbol = QStringLiteral("MONA"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("MONA"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // QUANTSTAMP SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Quantstamp"); info.Symbol = QStringLiteral("QSP"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("QSP"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // MAIDSAFECOIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "MaidSafeCoin"); info.Symbol = QStringLiteral("MAID"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("MAID"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // BYTEBALL SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Byteball Bytes"); info.Symbol = QStringLiteral("GBYTE"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("GBYTE"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // GAS SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Gas"); info.Symbol = QStringLiteral("GAS"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("GAS"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // CHAINLINK SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "ChainLink"); info.Symbol = QStringLiteral("LINK"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("LINK"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // SYSCOIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Syscoin"); info.Symbol = QStringLiteral("SYS"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("SYS"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // SANTIMENT SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Santiment Network Token"); info.Symbol = QStringLiteral("SAN"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("SAN"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // COBINHOOD SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Cobinhood"); info.Symbol = QStringLiteral("COB"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("COB"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // RED-PULSE SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Red Pulse"); info.Symbol = QStringLiteral("RPX"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("RPX"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // DIGIXDAO SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "DigixDAO"); info.Symbol = QStringLiteral("DGD"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("DGD"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // TENX SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "TenX"); info.Symbol = QStringLiteral("PAY"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("PAY"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // ICONOMI SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Iconomi"); info.Symbol = QStringLiteral("ICN"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("ICN"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // POET SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Po.et"); info.Symbol = QStringLiteral("POE"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("POE"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // ZCOIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "ZCoin"); info.Symbol = QStringLiteral("XZC"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("XZC"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // GNOSIS-GNO SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Gnosis"); info.Symbol = QStringLiteral("GNO"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("GNO"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // BLOCKV SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "BLOCKv"); info.Symbol = QStringLiteral("VEE"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("VEE"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // WALTON SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Walton"); info.Symbol = QStringLiteral("WTC"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("WTC"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // PACCOIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "PACcoin"); info.Symbol = QStringLiteral("PAC"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("PAC"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // DEEPBRAIN-CHAIN SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "DeepBrain Chain"); info.Symbol = QStringLiteral("DBC"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("DBC"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // ETHLEND SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "ETHLend"); info.Symbol = QStringLiteral("LEND"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("LEND"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } { // CIVIC SKGServices::SKGUnitInfo info; info.Name = i18nc("Noun, a cryptocurrency", "Civic"); info.Symbol = QStringLiteral("CVC"); info.Date = QDate(2009, 2, 4); info.Country = i18nc("Noun, the country of bitcoin", "Internet"); info.Internet = QStringLiteral("CVC"); info.Source = QStringLiteral("CoinMarketCap"); info.Parent = QStringLiteral("USD"); info.NbDecimal = 4; info.Value = -1; currencies.push_back(info); } } QStringList output; output.reserve(currencies.count()); for (const auto& unit : qAsConst(currencies)) { if (iIncludingObsolete || !unit.Obsolete) { output.push_back(unit.Name); } } output.sort(); return output; } QString SKGUnitObject::getInternationalCode(const QString& iUnitName) { SKGTRACEINFUNC(10) QString output = iUnitName; QRegExp rx(QStringLiteral(".*\\(([^\\(\\)]+)\\)[^\\(\\)]*")); if (rx.indexIn(iUnitName) != -1) { output = rx.cap(1); } return output; } SKGServices::SKGUnitInfo SKGUnitObject::getUnitInfo() { SKGTRACEINFUNC(10) SKGServices::SKGUnitInfo info; info.Name = getName(); info.Value = getAmount(); info.NbDecimal = getNumberDecimal(); info.Symbol = getSymbol(); info.Country = getCountry(); info.Internet = getInternetCode(); info.Date = QDate::currentDate(); return info; } SKGServices::SKGUnitInfo SKGUnitObject::getUnitInfo(const QString& iUnitName) { SKGTRACEINFUNC(10) SKGServices::SKGUnitInfo info; if (currencies.isEmpty()) { getListofKnownCurrencies(false); } QString isoCode = getInternationalCode(iUnitName); for (const auto& unit : qAsConst(currencies)) { if (getInternationalCode(unit.Name) == isoCode) { info = unit; break; } } return info; } SKGError SKGUnitObject::createCurrencyUnit(SKGDocumentBank* iDocument, const QString& iUnitName, SKGUnitObject& oUnit) { SKGError err; SKGTRACEINFUNCRC(10, err) if (iDocument != nullptr) { SKGUnitObject parentUnit; oUnit = SKGUnitObject(iDocument); SKGUnitObject::UnitType type = SKGUnitObject::CURRENCY; SKGServices::SKGUnitInfo prim = iDocument->getPrimaryUnit(); SKGServices::SKGUnitInfo seco = iDocument->getSecondaryUnit(); // Get information on the unit SKGServices::SKGUnitInfo info = getUnitInfo(iUnitName); if (info.Name.isEmpty()) { err = SKGError(ERR_INVALIDARG, i18nc("Error message", "Unknown unit '%1'", iUnitName)); } if (!err && !info.Parent.isEmpty()) { err = createCurrencyUnit(iDocument, info.Parent, parentUnit); } // Set the type if (info.Name == info.Symbol) { // This is an index type = SKGUnitObject::INDEX; } else if (!info.Parent.isEmpty()) { // This is a secondary unit type = (seco.Symbol.isEmpty() || seco.Symbol == info.Symbol ? SKGUnitObject::SECONDARY : SKGUnitObject::CURRENCY); } else { // As primary type = (prim.Symbol.isEmpty() || prim.Symbol == info.Symbol ? SKGUnitObject::PRIMARY : SKGUnitObject::CURRENCY); } // Point on primary unit if (info.Value == 1 && !err && (type == SKGUnitObject::CURRENCY || type == SKGUnitObject::SECONDARY)) { SKGUnitObject primunit(iDocument); err = primunit.setSymbol(prim.Symbol); IFOKDO(err, primunit.load()) IFOK(err) { QString codeprimunit = getInternationalCode(primunit.getName()); QString codeunit = getInternationalCode(info.Name); if (!codeprimunit.isEmpty()) { info.Internet = codeunit % '/' % codeprimunit; info.Value = -1; parentUnit = SKGUnitObject(iDocument); err = parentUnit.setSymbol(prim.Symbol); IFOKDO(err, parentUnit.load()) } } } IFOKDO(err, oUnit.setName(info.Name)) if (!err && oUnit.exist()) { err = oUnit.load(); } IFOKDO(err, oUnit.setType(type)) IFOKDO(err, oUnit.setSymbol(info.Symbol)) IFOKDO(err, oUnit.setInternetCode(info.Internet)) IFOKDO(err, oUnit.setDownloadSource(info.Source)) IFOKDO(err, oUnit.setCountry(info.Country)) IFOKDO(err, oUnit.setNumberDecimal(info.NbDecimal)) if (!err && parentUnit.exist()) { err = oUnit.setUnit(parentUnit); } IFOKDO(err, oUnit.save()) // Creation of the value if (info.Value > 0) { SKGUnitValueObject unitValue; IFOKDO(err, oUnit.addUnitValue(unitValue)) IFOKDO(err, unitValue.setDate(info.Date)) IFOKDO(err, unitValue.setQuantity(info.Value)) IFOKDO(err, unitValue.save()) } } return err; } double SKGUnitObject::convert(double iValue, const SKGUnitObject& iUnitFrom, const SKGUnitObject& iUnitTo, QDate iDate) { double output = iValue; if (iUnitFrom != iUnitTo) { double valFrom = iUnitFrom.getAmount(iDate); double valTo = iUnitTo.getAmount(iDate); output = iValue * valFrom / valTo; } return output; } SKGError SKGUnitObject::setSymbol(const QString& iSymbol) { return setAttribute(QStringLiteral("t_symbol"), iSymbol); } QString SKGUnitObject::getSymbol() const { return getAttribute(QStringLiteral("t_symbol")); } QString SKGUnitObject::getDownloadSource() const { return getAttribute(QStringLiteral("t_source")); } SKGError SKGUnitObject::setDownloadSource(const QString& iSource) { return setAttribute(QStringLiteral("t_source"), iSource); } SKGError SKGUnitObject::setNumberDecimal(int iNb) { return setAttribute(QStringLiteral("i_nbdecimal"), SKGServices::intToString(iNb)); } int SKGUnitObject::getNumberDecimal() const { return SKGServices::stringToInt(getAttribute(QStringLiteral("i_nbdecimal"))); } SKGError SKGUnitObject::setCountry(const QString& iCountry) { return setAttribute(QStringLiteral("t_country"), iCountry); } QString SKGUnitObject::getCountry() const { return getAttribute(QStringLiteral("t_country")); } SKGError SKGUnitObject::setInternetCode(const QString& iCode) { return setAttribute(QStringLiteral("t_internet_code"), iCode); } QString SKGUnitObject::getInternetCode() const { return getAttribute(QStringLiteral("t_internet_code")); } SKGError SKGUnitObject::setType(SKGUnitObject::UnitType iType) { SKGError err; if (getAttribute(QStringLiteral("t_type")).isEmpty() || this->getType() != iType) { // Guaranty that PRIMARY and SECONDARY is unique if (iType == PRIMARY || iType == SECONDARY) { // Set old SECONDARY as CURRENCY err = getDocument()->executeSqliteOrder(QStringLiteral("UPDATE unit SET t_type='C' WHERE t_type='2'")); // Set old PRIMARY as SECONDARY if (!err && iType == PRIMARY) { err = getDocument()->executeSqliteOrder(QStringLiteral("UPDATE unit SET t_type='2' WHERE t_type='1'")); } } } 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")))))))) return err; } SKGUnitObject::UnitType SKGUnitObject::getType() const { QString typeString = getAttribute(QStringLiteral("t_type")); return (typeString == QStringLiteral("C") ? CURRENCY : (typeString == QStringLiteral("S") ? SHARE : (typeString == QStringLiteral("1") ? PRIMARY : (typeString == QStringLiteral("2") ? SECONDARY : (typeString == QStringLiteral("I") ? INDEX : OBJECT))))); } SKGError SKGUnitObject::getUnit(SKGUnitObject& oUnit) const { SKGError err; if (getDocument() != nullptr) { err = getDocument()->getObject(QStringLiteral("v_unit"), "id=" % getAttribute(QStringLiteral("rd_unit_id")), oUnit); } return err; } SKGError SKGUnitObject::setUnit(const SKGUnitObject& iUnit) { SKGError err; if (*this == iUnit && iUnit.getID() != 0) { err = SKGError(ERR_INVALIDARG, i18nc("Error message", "Reference unit of a unit cannot be itself.")); } else { err = setAttribute(QStringLiteral("rd_unit_id"), SKGServices::intToString(iUnit.getID())); } return err; } SKGError SKGUnitObject::removeUnit() { return setAttribute(QStringLiteral("rd_unit_id"), QStringLiteral("0")); } SKGError SKGUnitObject::addUnitValue(SKGUnitValueObject& oUnitValue) { SKGError err; if (getID() == 0) { err = SKGError(ERR_FAIL, i18nc("Error message", "%1 failed because linked object is not yet saved in the database.", QStringLiteral("SKGUnitObject::addUnitValue"))); } else { oUnitValue = SKGUnitValueObject(qobject_cast(getDocument())); err = oUnitValue.setAttribute(QStringLiteral("rd_unit_id"), SKGServices::intToString(getID())); } return err; } SKGError SKGUnitObject::simplify() { SKGListSKGObjectBase values; SKGError err = getUnitValues(values); int nb = values.count(); if (!err && (nb != 0)) { QHash groups; SKGBEGINPROGRESSTRANSACTION(*getDocument(), "#INTERNAL#" % i18nc("Progression step", "Simplify unit"), err, 2) // Build groups { SKGBEGINPROGRESSTRANSACTION(*getDocument(), "#INTERNAL#" % i18nc("Progression step", "Analyze unit"), err, nb) QDate limit1 = QDate::currentDate().addMonths(-3); QDate limit2 = QDate::currentDate().addYears(-1); QDate limit3 = QDate::currentDate().addYears(-3); for (int i = nb - 1; !err && i >= 0 ; --i) { SKGUnitValueObject v(values.at(i)); QDate date = v.getDate(); if (date >= limit1) { // No simplification ==> nothing to do } else if (date >= limit2) { // Simplification by group of 30 days QString key = limit1.addDays(30 * (limit1.daysTo(date) / 30)).toString(); SKGListSKGObjectBase group = groups[key]; group.push_back(v); groups[key] = group; } else if (date >= limit3) { // Simplification by group of 2 months QString key = limit2.addDays(60 * (limit2.daysTo(date) / 60)).toString(); SKGListSKGObjectBase group = groups[key]; group.push_back(v); groups[key] = group; } else { // Simplification by group of 6 months QString key = limit3.addDays(180 * (limit2.daysTo(date) / 180)).toString(); SKGListSKGObjectBase group = groups[key]; group.push_back(v); groups[key] = group; } IFOKDO(err, getDocument()->stepForward(nb - i)) } } IFOKDO(err, getDocument()->stepForward(1)) // Simplify { QList keys = groups.keys(); nb = keys.count(); SKGBEGINPROGRESSTRANSACTION(*getDocument(), "#INTERNAL#" % i18nc("Progression step", "Remove useless values"), err, nb) for (int i = 0; !err && i < nb ; ++i) { const QString& k = keys.at(i); SKGListSKGObjectBase group = groups[k]; // Simplify the group int nb2 = group.count(); // Compute min and max double min = 10e20; double max = 0; for (int j = 0; j < nb2; ++j) { SKGUnitValueObject v1(group.at(j)); double y1 = v1.getQuantity(); min = qMin(y1, min); max = qMax(y1, max); } // Simplify for (int j = 1; !err && j < nb2 - 1; ++j) { SKGUnitValueObject v1(group.at(j)); double y1 = v1.getQuantity(); if (y1 != min && y1 != max) { err = v1.remove(); } } IFOKDO(err, getDocument()->stepForward(i + 1)) } } IFOKDO(err, getDocument()->stepForward(2)) } return err; } SKGError SKGUnitObject::getUnitValues(SKGListSKGObjectBase& oUnitValueList) const { SKGError err = getDocument()->getObjects(QStringLiteral("v_unitvalue"), "rd_unit_id=" % SKGServices::intToString(getID()) % " ORDER BY d_date", oUnitValueList); return err; } SKGError SKGUnitObject::getLastUnitValue(SKGUnitValueObject& oUnitValue) const { return SKGObjectBase::getDocument()->getObject(QStringLiteral("v_unitvalue"), "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()) % ')', oUnitValue); } SKGError SKGUnitObject::getUnitValue(QDate iDate, SKGUnitValueObject& oUnitValue) const { QString ids = SKGServices::intToString(getID()); QString dates = SKGServices::dateToSqlString(QDateTime(iDate)); SKGError err = SKGObjectBase::getDocument()->getObject(QStringLiteral("v_unitvalue"), "rd_unit_id=" % ids % " AND d_date<='" % dates % "' AND ABS(strftime('%s','" % dates % "')-strftime('%s',d_date))=(select MIN(ABS(strftime('%s','" % dates % "')-strftime('%s',u2.d_date))) from unitvalue u2 where u2.rd_unit_id=" % ids % " AND u2.d_date<='" % dates % "')", oUnitValue); // If not found then get first IFKO(err) err = SKGObjectBase::getDocument()->getObject(QStringLiteral("v_unitvalue"), "rd_unit_id=" % SKGServices::intToString(getID()) % " AND d_date=(select MIN(d_date) from unitvalue where rd_unit_id=" % SKGServices::intToString(getID()) % ')', oUnitValue); return err; } double SKGUnitObject::getAmount(QDate iDate) const { SKGTRACEINFUNC(10) double output = 0; if (getType() == SKGUnitObject::PRIMARY) { output = 1.0; } else if (getDocument() != nullptr) { // Search result in cache QString ids = SKGServices::intToString(getID()); QString dates = SKGServices::dateToSqlString(QDateTime(iDate)); QString key = "unitvalue-" % ids % '-' % dates; QString val = getDocument()->getCachedValue(key); if (val.isEmpty()) { // Get quantity double quantity = 1; SKGUnitValueObject uv; if (getUnitValue(iDate, uv).isSucceeded()) { quantity = uv.getQuantity(); } SKGUnitObject unit; double coef = 1; if (getUnit(unit).isSucceeded()) { if (unit != *this) { coef = unit.getAmount(iDate); } } output = coef * quantity; getDocument()->addValueInCache(key, SKGServices::doubleToString(output)); if (getAttribute(QStringLiteral("i_NBVALUES")) == QStringLiteral("1")) { // Store value for this symbol for all date getDocument()->addValueInCache("unitvalue-" % ids, SKGServices::doubleToString(output)); } } else { output = SKGServices::stringToDouble(val); } } return output; } double SKGUnitObject::getDailyChange(QDate iDate) const { double output = 0; SKGStringListList result; SKGError err = getDocument()->executeSelectSqliteOrder( "SELECT d_date, f_quantity from unitvalue where rd_unit_id=" % SKGServices::intToString(getID()) % " AND d_date<='" % SKGServices::dateToSqlString(QDateTime(iDate)) % "' ORDER BY d_date DESC LIMIT 2", result); if (!err && result.count() == 3) { double v2 = SKGServices::stringToDouble(result.at(1).at(1)); double v1 = SKGServices::stringToDouble(result.at(2).at(1)); QDate d2 = SKGServices::stringToTime(result.at(1).at(0)).date(); QDate d1 = SKGServices::stringToTime(result.at(2).at(0)).date(); output = 100 * (qExp(qLn(v2 / v1) / (SKGServices::nbWorkingDays(d1, d2))) - 1); } return output; } SKGError SKGUnitObject::split(double iRatio) const { SKGError err; if (iRatio > 0) { err = getDocument()->executeSqliteOrder("UPDATE unitvalue SET f_quantity=f_quantity/" % SKGServices::doubleToString(iRatio) % " WHERE rd_unit_id=" % SKGServices::intToString(getID())); IFOKDO(err, getDocument()->executeSqliteOrder("UPDATE suboperation SET f_value=f_value*" % SKGServices::doubleToString(iRatio) % " WHERE rd_operation_id IN (SELECT id FROM operation WHERE rc_unit_id=" % SKGServices::intToString(getID()) % ')')); } else { err = SKGError(ERR_INVALIDARG, i18nc("Error message", "Invalid ratio. Ratio must be greater than 0.")); } return err; } QStringList SKGUnitObject::downloadSources() { QStringList sources; // Get sources from .txt file (old mode) TODO: Remove QString a = QStringLiteral("skrooge/quotes"); const auto list = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, a, QStandardPaths::LocateDirectory); for (const auto& dir : list) { QDirIterator it(dir, QStringList() << QStringLiteral("*.txt")); while (it.hasNext()) { QFileInfo f(it.next()); QString file2 = f.completeBaseName(); if (!sources.contains(file2)) { sources.push_back(file2); } } } // Get sources from.desktop file const auto list2 = KServiceTypeTrader::self()->query(QStringLiteral("skrooge/source")); for (const auto& service : list2) { auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QVariant::String).toString(); if (!sources.contains(name)) { sources.push_back(name); } } sources.sort(); return sources; } QString SKGUnitObject::getCommentFromSource(const QString& iSource) { QString output; const auto list2 = KServiceTypeTrader::self()->query(QStringLiteral("skrooge/source")); for (const auto& service : list2) { auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QVariant::String).toString(); if (name == iSource) { output = service->property(QStringLiteral("Comment"), QVariant::String).toString(); break; } } return output; } SKGError SKGUnitObject::addSource(const QString& iNewSource, bool iOpenSource) { SKGError err; QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); QDir(path).mkpath(QStringLiteral("skrooge/quotes/")); QString newfile = path + "/skrooge/quotes/" % iNewSource % ".txt"; // Create the new file QSaveFile file(newfile); // Check if file already existing if (!QFile(newfile).exists()) { // Creation of the template if (!file.open(QIODevice::WriteOnly)) { err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message", "Save file '%1' failed", newfile)); } else { QTextStream out(&file); out << "#" << i18nc("Description test for a text file used to define a source of download", "The URL or the SCRIPT of the source. %1 will be replaced by the internet code of the unit", "%1") << endl; out << "#" << i18nc("Description test for a text file used to define a source of download", "%1 will be replaced by the current day in format yyyy-MM-dd", "%2") << endl; out << "#" << i18nc("Description test for a text file used to define a source of download", "%1 will be replaced by the previous date in format yyyy-MM-dd", "%3") << endl; out << "url=https://server/?s=%1" << endl; out << "or" << endl; out << "script=mydownloadscript %1" << endl << endl; out << "#" << i18nc("Description test for a text file used to define a source of download", "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.") << endl; out << "mode=CSV, CSVR or or HTML" << endl << endl; out << "#" << i18nc("Description test for a text file used to define a source of download", "The regular expression for the price (see %1)", "https://doc.qt.io/qt-5/qregexp.html") << endl; out << "price=" << endl << endl; out << "#" << i18nc("Description test for a text file used to define a source of download", "The regular expression for the date (see %1)", "https://doc.qt.io/qt-5/qregexp.html") << endl; out << "date=" << endl << endl; out << "#" << i18nc("Description test for a text file used to define a source of download", "The format of the date (see %1) or \"UNIX\" for unix time", "https://doc.qt.io/qt-5/qdate.html#fromString-1") << endl; out << "dateformat=yyyy-MM-dd" << endl; // Close file file.commit(); } } // Open the created or already existing file if (iOpenSource) { QDesktopServices::openUrl(QUrl::fromLocalFile(newfile)); } return err; } SKGError SKGUnitObject::deleteSource(const QString& iSource) { SKGError err; QString fileName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + QStringLiteral("skrooge/quotes/") % iSource % ".txt"; // Delete the file QFile file(fileName); if (!file.remove()) { err.setReturnCode(ERR_INVALIDARG).setMessage(i18nc("Error message", "Deletion of '%1' failed", fileName)); } return err; } bool SKGUnitObject::isWritable(const QString& iSource) { QString fileName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + QStringLiteral("skrooge/quotes/") % iSource % ".txt"; return QFileInfo(fileName).isWritable(); } SKGError SKGUnitObject::downloadUnitValue(UnitDownloadMode iMode, int iNbMaxValues) { SKGError err; SKGTRACEINFUNCRC(10, err) QString unitname = getName(); QString code = getInternetCode(); bool invert = code.contains(QStringLiteral(" /")); code.remove(QStringLiteral(" /")); QString source = getDownloadSource(); auto* doc = qobject_cast(getDocument()); if (!code.trimmed().isEmpty() && !source.trimmed().isEmpty() && (doc != nullptr)) { // Get last date QDate firstDate; SKGStringListList result; doc->executeSelectSqliteOrder("SELECT MAX(d_date) FROM unitvalue where rd_unit_id=" % SKGServices::intToString(getID()), result); if (result.count() == 2) { firstDate = SKGServices::stringToTime(result.at(1).at(0)).date().addDays(-1); } if (code.startsWith(QLatin1String("="))) { // MODE FORMULAR // Set 1st january if date is not found if (!firstDate.isValid()) { firstDate.setDate(QDate::currentDate().year(), 1, 1); } // Compute yearly rate double rate = SKGServices::stringToDouble(code.right(code.length() - 1)); // Compute rate for step double step = (iMode == LAST_MONTHLY || iMode == ALL_MONTHLY ? 12.0 : (iMode == LAST_WEEKLY || iMode == ALL_WEEKLY ? 365.0 / 7.0 : 365)); double rate2 = 100.0 * (qExp(qLn(1 + rate / 100.0) / step) - 1.0); // Get last value SKGStringListList result2; double value = 100; 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(QDateTime(firstDate)) % '\'', result2); if (result2.count() == 2) { value = SKGServices::stringToDouble(result2.at(1).at(0)); } // Compute and add values while (!err && firstDate <= QDate::currentDate()) { // Compute next date and value if (iMode == LAST_MONTHLY || iMode == ALL_MONTHLY) { firstDate = firstDate.addMonths(1); } else if (iMode == LAST_WEEKLY || iMode == ALL_WEEKLY) { firstDate = firstDate.addDays(7); } else { firstDate = firstDate.addDays(1); } value *= (1 + rate2 / 100.0); // Create value SKGUnitValueObject val; err = addUnitValue(val); IFOKDO(err, val.setDate(firstDate)) IFOKDO(err, val.setQuantity(value)) IFOKDO(err, val.save()) } } else { // Quote download // Set 1st january 1970 if date is not found if (!firstDate.isValid()) { firstDate.setDate(1970, 1, 1); } QString interval = QStringLiteral("1d"); bool last = (iMode == LAST); if (last) { interval = QStringLiteral("1d"); } else if (iMode == LAST_MONTHLY) { interval = QStringLiteral("1mo"); } else if (iMode == LAST_WEEKLY) { interval = QStringLiteral("1wk"); } else if (iMode == LAST_DAILY) { interval = QStringLiteral("1d"); } else if (iMode == ALL_MONTHLY) { firstDate = QDate(1970, 01, 01); interval = QStringLiteral("1mo"); } else if (iMode == ALL_WEEKLY) { firstDate = QDate(1970, 01, 01); interval = QStringLiteral("1wk"); } else if (iMode == ALL_DAILY) { firstDate = QDate(1970, 01, 01); interval = QStringLiteral("1d"); } bool modeScript = false; QString path; QString mode; QString price; QString date; QString dateFormat; + QString apiKey; QString fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "skrooge/quotes/" % source % ".txt"); if (fileName.isEmpty()) { const auto list2 = KServiceTypeTrader::self()->query(QStringLiteral("skrooge/source")); for (const auto& service : list2) { auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QVariant::String).toString(); if (name == source) { path = service->property(QStringLiteral("X-SKROOGE-url"), QVariant::String).toString(); if (path.isEmpty()) { path = service->property(QStringLiteral("X-SKROOGE-script"), QVariant::String).toString(); modeScript = true; } mode = service->property(QStringLiteral("X-SKROOGE-mode"), QVariant::String).toString().toUpper(); price = service->property(QStringLiteral("X-SKROOGE-price"), QVariant::String).toString().replace(QStringLiteral("%1"), code); date = service->property(QStringLiteral("X-SKROOGE-date"), QVariant::String).toString().replace(QStringLiteral("%1"), code); dateFormat = service->property(QStringLiteral("X-SKROOGE-dateformat"), QVariant::String).toString(); + if (service->property(QStringLiteral("X-SKROOGE-keyAPI"), QVariant::Bool).toBool()) { + apiKey = getDocument()->getParameter("KEYAPI_" + source); + } break; } } if (path.isEmpty()) { err = SKGError(ERR_FAIL, i18nc("Error message", "Source of download %1 is not installed.", source)); } } else { // Read source file from .txt file QHash< QString, QString > properties; err = SKGServices::readPropertyFile(fileName, properties); IFOK(err) { path = properties[QStringLiteral("url")]; if (path.isEmpty()) { path = properties[QStringLiteral("script")]; modeScript = true; } mode = properties[QStringLiteral("mode")].toUpper(); price = properties[QStringLiteral("price")].replace(QStringLiteral("%1"), code); date = properties[QStringLiteral("date")].replace(QStringLiteral("%1"), code); dateFormat = properties[QStringLiteral("dateformat")]; } else { doc->sendMessage(i18nc("An information message", "Open url '%1' failed", path), SKGDocument::Warning); } } IFOK(err) { path = path.replace(QStringLiteral("%1"), code); path = path.replace(QStringLiteral("%2"), QDate::currentDate().toString(QStringLiteral("yyyy-MM-dd"))); path = path.replace(QStringLiteral("%3"), firstDate.toString(QStringLiteral("yyyy-MM-dd"))); path = path.replace(QStringLiteral("%4"), interval); - + path = path.replace(QStringLiteral("%5"), apiKey); SKGTRACEL(1) << "path=[" << path << "]" << endl; SKGTRACEL(1) << "mode=[" << mode << "]" << endl; SKGTRACEL(1) << "price=[" << price << "]" << endl; SKGTRACEL(1) << "date=[" << date << "]" << endl; SKGTRACEL(1) << "dateFormat=[" << dateFormat << "]" << endl; // Download url QByteArray stream; if (modeScript) { path = SKGServices::getFullPathCommandLine(path); SKGTRACEL(1) << "full path=[" << path << "]" << endl; QProcess p; p.start(path); if (p.waitForFinished(1000 * 60 * 2) && p.exitCode() == 0) { stream = p.readAllStandardOutput(); } else { err.setReturnCode(ERR_FAIL).setMessage(i18nc("Error message", "The following command line failed with code %2:\n'%1'", path, p.exitCode())); } } else { SKGServices::downloadToStream(QUrl::fromUserInput(path), stream); } if (!err && !stream.isEmpty()) { SKGTRACEL(1) << "stream=[" << stream << "]" << endl; // Parse data QRegExp priceRegExp(price, Qt::CaseInsensitive); QRegExp dateRegExp(date, Qt::CaseInsensitive); QStringList lines = (mode.startsWith(QLatin1String("CSV")) ? SKGServices::splitCSVLine(stream, '\n') : QStringList() << QLatin1String("") << stream); int nb = lines.count(); int nbLoaded = 0; for (int i = 1; i < nb && !err && (i < iNbMaxValues || iNbMaxValues == 0); ++i) { QString data = lines.at(mode == QStringLiteral("CSVR") ? nb - i : i).trimmed(); if (!data.isEmpty()) { SKGTRACEL(1) << "Downloaded data from [" << path << "]=[" << data << "]" << endl; double val = 0.0; if (priceRegExp.indexIn(data) > -1) { val = SKGServices::stringToDouble(priceRegExp.cap(1)); } QString date2; if (dateRegExp.indexIn(data) > -1) { date2 = dateRegExp.cap(1); } SKGTRACEL(1) << "Price found=[" << val << "]" << endl; SKGTRACEL(1) << "Date found=[" << date2 << "]" << endl; // Set value if (val != 0.0) { QDate ds; if (dateFormat == QStringLiteral("UNIX")) { ds = QDateTime::fromTime_t(SKGServices::stringToInt(date2)).date(); } else { ds = QDate::fromString(date2, dateFormat); // Try with an english locale if (!ds.isValid()) { QLocale en(QStringLiteral("en_EN")); ds = en.toDate(date2, dateFormat); } } if (!ds.isValid()) { ds = QDate::currentDate(); SKGTRACE << "WARNING:" << date2 << " not well parsed with format " << dateFormat << endl; } if (!dateFormat.contains(QStringLiteral("yyyy")) && ds.year() < 2000) { ds = ds.addYears(100); } // Creation or update of the value SKGUnitValueObject value; IFOKDO(err, addUnitValue(value)) IFOKDO(err, value.setDate(ds)) IFOKDO(err, value.setQuantity(invert && val != 0 ? 1 / val : val)) IFOKDO(err, value.save()) if (last) { break; } nbLoaded++; } } if (nbLoaded == 0 && !data.isEmpty()) { 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 } } } } } } IFKO(err) { err.addError(ERR_FAIL, i18nc("Error message", "Impossible to download unit %1 with Internet code %2 on the source %3.", unitname, code, source)); } return err; } SKGError SKGUnitObject::getUrl(QUrl& oUrl) const { SKGError err; SKGTRACEINFUNCRC(10, err) QString url; QString code = getInternetCode(); code.remove(QStringLiteral(" /")); QString source = getDownloadSource(); if (!code.isEmpty()) { if (code.startsWith(QLatin1String("="))) { // MODE FORMULAR } else { // ALTERNATIVE MODE QString fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "skrooge/quotes/" % source % ".txt"); if (fileName.isEmpty()) { const auto list2 = KServiceTypeTrader::self()->query(QStringLiteral("skrooge/source")); for (const auto& service : list2) { auto name = service->property(QStringLiteral("X-KDE-PluginInfo-Name"), QVariant::String).toString(); if (name == source) { url = service->property(QStringLiteral("X-SKROOGE-url"), QVariant::String).toString().replace(QStringLiteral("%1"), code); url = url.replace(QStringLiteral("%2"), QDate::currentDate().toString(QStringLiteral("yyyy-MM-dd"))); url = url.replace(QStringLiteral("%3"), QDate::currentDate().addDays(-15).toString(QStringLiteral("yyyy-MM-dd"))); break; } } if (url.isEmpty()) { err = SKGError(ERR_FAIL, i18nc("Error message", "Source of download %1 is not installed.", source)); } } else { // Read source file QHash< QString, QString > properties; err = SKGServices::readPropertyFile(fileName, properties); IFOK(err) { url = properties[QStringLiteral("url")].replace(QStringLiteral("%1"), code); url = url.replace(QStringLiteral("%2"), QDate::currentDate().toString(QStringLiteral("yyyy-MM-dd"))); url = url.replace(QStringLiteral("%3"), QDate::currentDate().addDays(-15).toString(QStringLiteral("yyyy-MM-dd"))); } } } } IFOK(err) { oUrl = QUrl(url); } return err; } SKGError SKGUnitObject::openURL() const { QUrl url; SKGError err = getUrl(url); IFKO(err) { err.addError(ERR_FAIL, i18nc("Error message", "Impossible to open unit %1 with Internet code %2.", getName(), getInternetCode())); } else { QDesktopServices::openUrl(url); } return err; } SKGError SKGUnitObject::getOperations(SKGObjectBase::SKGListSKGObjectBase& oOperations) const { SKGError err = getDocument()->getObjects(QStringLiteral("v_operation"), "rc_unit_id=" % SKGServices::intToString(getID()), oOperations); return err; } SKGError SKGUnitObject::merge(const SKGUnitObject& iUnit) { SKGError err; SKGObjectBase::SKGListSKGObjectBase ops; IFOKDO(err, iUnit.getOperations(ops)) int nb = ops.count(); for (int i = 0; !err && i < nb; ++i) { SKGOperationObject op(ops.at(i)); err = op.setUnit(*this); IFOKDO(err, op.save(true, false)) } IFOKDO(err, iUnit.remove(false)) return err; } diff --git a/skgbankmodeler/skrooge-coinmarketcap.py b/skgbankmodeler/skrooge-coinmarketcap.py index 46bee3709..156a2d40d 100755 --- a/skgbankmodeler/skrooge-coinmarketcap.py +++ b/skgbankmodeler/skrooge-coinmarketcap.py @@ -1,38 +1,38 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- #************************************************************************** #* Copyright (C) 2017 by S. MANKOWSKI / G. DE BURE support@mankowski.fr #* Redistribution and use in source and binary forms, with or without #* modification, are permitted provided that the following conditions #* are met: #* #* 1. Redistributions of source code must retain the above copyright #* notice, this list of conditions and the following disclaimer. #* 2. Redistributions in binary form must reproduce the above copyright #* notice, this list of conditions and the following disclaimer in the #* documentation and/or other materials provided with the distribution. #* #* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR #* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES #* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. #* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT #* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, #* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY #* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT #* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF #* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #************************************************************************** from urllib.request import Request, urlopen import json import sys units=sys.argv[1].split('-') req = Request('https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest?symbol='+units[0]+'&convert='+units[1]) -req.add_header("X-CMC_PRO_API_KEY", '-'.join(units[2:])) +req.add_header("X-CMC_PRO_API_KEY", sys.argv[5]) f = urlopen(req) print("Date,Price") item=json.loads(f.read().decode('utf-8'))['data'][units[0]]['quote'][units[1]] print(item["last_updated"][0:10]+','+str(item["price"])) diff --git a/skgbankmodeler/skrooge-cryptocompare.py b/skgbankmodeler/skrooge-cryptocompare.py index 9f1fc998b..5c5b9ea79 100755 --- a/skgbankmodeler/skrooge-cryptocompare.py +++ b/skgbankmodeler/skrooge-cryptocompare.py @@ -1,37 +1,37 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- #************************************************************************** #* Copyright (C) 2017 by S. MANKOWSKI / G. DE BURE support@mankowski.fr #* Redistribution and use in source and binary forms, with or without #* modification, are permitted provided that the following conditions #* are met: #* #* 1. Redistributions of source code must retain the above copyright #* notice, this list of conditions and the following disclaimer. #* 2. Redistributions in binary form must reproduce the above copyright #* notice, this list of conditions and the following disclaimer in the #* documentation and/or other materials provided with the distribution. #* #* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR #* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES #* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. #* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, #* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT #* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, #* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY #* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT #* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF #* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #************************************************************************** import urllib.request import json import sys import time units=sys.argv[1].split('-') -f = urllib.request.urlopen('https://min-api.cryptocompare.com/data/v2/histoday?fsym='+units[0]+'&tsym='+units[1]+'&limit=1000&api_key='+units[2]) +f = urllib.request.urlopen('https://min-api.cryptocompare.com/data/v2/histoday?fsym='+units[0]+'&tsym='+units[1]+'&limit=1000&api_key='+sys.argv[5]) print("Date,Price") for item in json.loads(f.read().decode('utf-8'))['Data']['Data']: print(time.strftime('%Y-%m-%d', time.gmtime(int(item["time"])))+','+str(item['close'])) diff --git a/skgbankmodeler/sources/org.kde.skrooge-source-coinmarketcap.desktop b/skgbankmodeler/sources/org.kde.skrooge-source-coinmarketcap.desktop index ecb5919bb..b737bc61a 100644 --- a/skgbankmodeler/sources/org.kde.skrooge-source-coinmarketcap.desktop +++ b/skgbankmodeler/sources/org.kde.skrooge-source-coinmarketcap.desktop @@ -1,67 +1,72 @@ [Desktop Entry] Name=CoinMarketCap Name[ca]=CoinMarketCap Name[ca@valencia]=CoinMarketCap Name[en_GB]=CoinMarketCap Name[es]=CoinMarketCap Name[et]=CoinMarketCap Name[fr]=CoinMarketCap Name[gl]=CoinMarketCap Name[it]=CoinMarketCap Name[nl]=CoinMarketCap Name[pl]=CoinMarketCap Name[pt]=CoinMarketCap Name[pt_BR]=CoinMarketCap Name[sv]=CoinMarketCap Name[uk]=CoinMarketCap Name[x-test]=xxCoinMarketCapxx -Comment=You can get the list of available quotes from CoinMarketCap.

Then, you must create an account to get an API key.
Then, enter the --. Example: if you want BTC in USD, you must enter BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. +Comment=You can get the list of available quotes from CoinMarketCap.

Then, you must create an account to get an API key and set it in setting.
Then, enter the -. Example: if you want BTC in USD, you must enter BTC-USD. Comment[ca]=Podeu obtenir la llista de les cotitzacions disponibles a CoinMarketCap.

Després, cal crear un compte per aconseguir una clau d'API.
Després, introduïu la --. Exemple: si voleu BTC en USD, cal introduir BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[ca@valencia]=Podeu obtindre la llista de les cotitzacions disponibles a CoinMarketCap.

Després, cal crear un compte per aconseguir una clau d'API.
Després, introduïu la --. Exemple: si voleu BTC en USD, cal introduir BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[en_GB]=You can get the list of available quotes from CoinMarketCap.

Then, you must create an account to get an API key.
Then, enter the --. Example: if you want BTC in USD, you must enter BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[es]=Puede obtener la lista de cotizaciones disponibles en CoinMarketCap.

Tras ello, debe crear una cuenta para obtener una clave API.
Luego, introduzca la --. Por ejemplo: si quiere BTC en USD, debe introducir BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[et]=Saadaolevate kursside loendi võib hankida saidilt CoinMarketCap.

Seejärel tuleb API võtme saamiseks luua konto.
Seejärel sisesta .-. Kui näiteks soovid BTC-d USA dollarites, tuleb sisestada BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[nl]=U kunt de lijst met beschikbare koersen ophalen van CoinMarketCap.

Daarna, moet u een account aanmaken om een API-sleutel te krijgen.
Voer daarna de -- in. Voorbeeld: als u BTC in USD wilt, moet u invoeren BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[pt]=Poderá obter a lista de cotações disponíveis no CoinMarketCap.

Depois será necessário criar uma conta para obter uma chave da API.
Finalmente, indique a --. Por exemplo, se quiser a BTC em USD, tem de indicar BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[sv]=Du kan hämta listan över tillgängliga kurser från CoinMarketCap.

Därefter måste du skapa ett konto för att få en programmeringsgränssnittsnyckel.
Ange därefter --. Om du exempelvis ha BTC i USD måste du skriva in BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[uk]=Ви можете отримувати список доступних курсів з CoinMarketCap.

Для цього вам слід створити обліковий запис та отримати ключ до програмного інтерфейсу.
Далі, введіть комбінацію <потрібний курс>-<бажана валюта>-<ключ до програмного інтерфейсу>. Приклад: якщо потрібен курс BTC у доларах США, вам слід вказати BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[x-test]=xxYou can get the list of available quotes from CoinMarketCap.

Then, you must create an account to get an API key.
Then, enter the --. Example: if you want BTC in USD, you must enter BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36.xx Encoding=UTF-8 Icon=skrooge Type=Service X-KDE-ServiceTypes=skrooge/source X-Krunner-ID=coinmarketcap X-KDE-PluginInfo-Author=Stephane MANKOWSKI,miraks X-KDE-PluginInfo-Email=stephane@mankowski.fr X-KDE-PluginInfo-Name=CoinMarketCap X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Website=https://skrooge.org/ X-KDE-PluginInfo-Category=Plugins X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true +#To know if this plugin needs a key API +X-SKROOGE-keyAPI=true + #The url or the command line to get the list of accounts in the standard output, something like this: #%1 will be replaced by the internet code of the unit #%2 will be replaced by the current day in format yyyy-MM-dd #%3 will be replaced by the previous date in format yyyy-MM-dd +#%4 will be replaced by the interval +#%5 will be replaced by the key API #Example: # X-SKROOGE-url=https://server/?s=%1 # or # X-SKROOGE-script=mydownloadscript %1 #This parameter is MANDATORY -X-SKROOGE-script=skrooge-coinmarketcap.py %1 +X-SKROOGE-script=skrooge-coinmarketcap.py "%1" "%2" "%3" "%4" "%5" #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 X-SKROOGE-mode=CSV #Regular expression to capture the price of the quote #This parameter is not MANDATORY. X-SKROOGE-price=[^,]*,([^,]*) #Regular expression to capture the date of the quote #This parameter is not MANDATORY. X-SKROOGE-date=([^,]*),.* #The date format X-SKROOGE-dateformat=yyyy-MM-dd diff --git a/skgbankmodeler/sources/org.kde.skrooge-source-cryptocompare.desktop b/skgbankmodeler/sources/org.kde.skrooge-source-cryptocompare.desktop index 107a90b65..a8b07b9dd 100644 --- a/skgbankmodeler/sources/org.kde.skrooge-source-cryptocompare.desktop +++ b/skgbankmodeler/sources/org.kde.skrooge-source-cryptocompare.desktop @@ -1,62 +1,67 @@ [Desktop Entry] Name=Cryptocompare Name[ca]=Cryptocompare Name[ca@valencia]=Cryptocompare Name[en_GB]=Cryptocompare Name[es]=Cryptocompare Name[et]=Cryptocompare Name[nl]=Cryptocompare Name[pt]=Cryptocompare Name[sv]=Cryptocompare Name[uk]=Cryptocompare Name[x-test]=xxCryptocomparexx -Comment=You can get the list of available quotes from CryptoCompare.
Then, you must create an account to get an API key.
Then, enter the --. Example: if you want BTC in USD, you must enter BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. +Comment=You can get the list of available quotes from CryptoCompare.
Then, you must create an account to get an API key and set it in setting.
Then, enter the -. Example: if you want BTC in USD, you must enter BTC-USD. Comment[ca]=Podeu obtenir la llista de les cotitzacions disponibles a CryptoCompare.
Després, cal crear un compte per aconseguir una clau d'API.
Després, introduïu la --. Exemple: si voleu BTC en USD, cal introduir BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[ca@valencia]=Podeu obtindre la llista de les cotitzacions disponibles a CryptoCompare.
Després, cal crear un compte per aconseguir una clau d'API.
Després, introduïu la --. Exemple: si voleu BTC en USD, cal introduir BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[en_GB]=You can get the list of available quotes from CryptoCompare.
Then, you must create an account to get an API key.
Then, enter the --. Example: if you want BTC in USD, you must enter BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[es]=Puede obtener la lista de cotizaciones disponibles en CryptoCompare
.Tras ello, debe crear una cuenta para obtener una clave API.
Luego, introduzca la --. Por ejemplo: si quiere BTC en USD, debe introducir BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[et]=Saadaolevate kursside loendi võib hankida saidilt CryptoCompare.
Seejärel tuleb API võtme saamiseks luua konto.
Seejärel sisesta .-. Kui näiteks soovid BTC-d USA dollarites, tuleb sisestada BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[nl]=U kunt de lijst met beschikbare koersen ophalen van CryptoCompare.
Daarna, moet u een account aanmaken om een API-sleutel te krijgen.
Voer daarna de -- in. Voorbeeld: als u BTC in USD wilt, moet u invoeren BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[pt]=Poderá obter a lista de cotações disponíveis no CryptoCompare.

Depois será necessário criar uma conta para obter uma chave da API.
Finalmente, indique a --. Por exemplo, se quiser a BTC em USD, tem de indicar BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[sv]=Du kan hämta listan över tillgängliga kurser från CryptoCompare.

Därefter måste du skapa ett konto för att få en programmeringsgränssnittsnyckel.
Ange därefter --. Om du exempelvis ha BTC i USD måste du skriva in BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[uk]=Ви можете отримувати список доступних курсів з CryptoCompare.
Для цього вам слід створити обліковий запис та отримати ключ до програмного інтерфейсу.
Далі, введіть комбінацію <потрібний курс>-<бажана валюта>-<ключ до програмного інтерфейсу>. Приклад: якщо потрібен курс BTC у доларах США, вам слід вказати BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36. Comment[x-test]=xxYou can get the list of available quotes from CryptoCompare.
Then, you must create an account to get an API key.
Then, enter the --. Example: if you want BTC in USD, you must enter BTC-USD-3b415edbc7d42bd9e367dc43b415edbc7d42bd9e367dc3b415edbc7d42bd9e36.xx Encoding=UTF-8 Icon=skrooge Type=Service X-KDE-ServiceTypes=skrooge/source X-Krunner-ID=cryptocompare X-KDE-PluginInfo-Author=Stephane MANKOWSKI,miraks X-KDE-PluginInfo-Email=stephane@mankowski.fr X-KDE-PluginInfo-Name=Cryptocompare X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Website=https://skrooge.org/ X-KDE-PluginInfo-Category=Plugins X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true +#To know if this plugin needs a key API +X-SKROOGE-keyAPI=true + #The url or the command line to get the list of accounts in the standard output, something like this: #%1 will be replaced by the internet code of the unit #%2 will be replaced by the current day in format yyyy-MM-dd #%3 will be replaced by the previous date in format yyyy-MM-dd +#%4 will be replaced by the interval +#%5 will be replaced by the key API #Example: # X-SKROOGE-url=https://server/?s=%1 # or # X-SKROOGE-script=mydownloadscript %1 #This parameter is MANDATORY -X-SKROOGE-script=skrooge-cryptocompare.py %1 +X-SKROOGE-script=skrooge-cryptocompare.py "%1" "%2" "%3" "%4" "%5" #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 X-SKROOGE-mode=CSVR #Regular expression to capture the price of the quote #This parameter is not MANDATORY. X-SKROOGE-price=[^,]*,([^,]*) #Regular expression to capture the date of the quote #This parameter is not MANDATORY. X-SKROOGE-date=([^,]*),.* #The date format X-SKROOGE-dateformat=yyyy-MM-dd diff --git a/skgbankmodeler/sources/org.kde.skrooge-source-grandtrunk.desktop b/skgbankmodeler/sources/org.kde.skrooge-source-grandtrunk.desktop index 63f7894f1..1b31060c7 100644 --- a/skgbankmodeler/sources/org.kde.skrooge-source-grandtrunk.desktop +++ b/skgbankmodeler/sources/org.kde.skrooge-source-grandtrunk.desktop @@ -1,70 +1,75 @@ [Desktop Entry] Name=Grand Trunk Name[ca]=Grand Trunk Name[ca@valencia]=Grand Trunk Name[en_GB]=Grand Trunk Name[es]=Grand Trunk Name[et]=Grand Trunk Name[fr]=Grand Trunk Name[gl]=Grand Trunk Name[it]=Grand Trunk Name[nl]=Grand Trunk Name[pl]=Grand Trunk Name[pt]=Grand Trunk Name[pt_BR]=Grand Trunk Name[sv]=Grand Trunk Name[uk]=Grand Trunk Name[x-test]=xxGrand Trunkxx Comment=You can get the list of supported currencies from here.
Then, enter the expected currency. Comment[ca]=Podeu obtenir la llista de les divises admeses aquí.
Després introduïu la divisa esperada. Comment[ca@valencia]=Podeu obtindre la llista de les divises admeses ací.
Després introduïu la divisa esperada. Comment[en_GB]=You can get the list of supported currencies from here.
Then, enter the expected currency. Comment[es]=Puede obtener la lista de las monedas permitidas de aquí.
A continuación, introduzca la moneda esperada. Comment[et]=Toetatud vääringute loendi võib hankida siit.
Seejärel sisesta oodatav vääring. Comment[fr]=Vous pouvez récupérer la liste des cotation disponibles depuis ici.
Ensuite, saisissez la devise souhaitée. Comment[gl]=Pode obter a lista de divisas compatíbeis de aquí.
A continuación escriba a divisa esperada. Comment[it]=Puoi ottenere un elenco delle valute supportate qui.
Digita, quindi, la valuta desiderata. Comment[nl]=U kunt de lijst met ondersteunde valuta ophalen vanaf hier.
Voer dan de naam van de gewenste valuta in. Comment[pt]=Poderá obter a lista de moedas suportadas a partir de aqui.
Depois, introduza a moeda esperada. Comment[sv]=Lista över valutor som stöds kan hämtas här. Skriv därefter in förväntad valuta. Comment[uk]=Ознайомитися зі списком підтримуваних валют можна тут.
Далі, введіть потрібну валюту. Comment[x-test]=xxYou can get the list of supported currencies from here.
Then, enter the expected currency.xx Encoding=UTF-8 Icon=skrooge Type=Service X-KDE-ServiceTypes=skrooge/source X-Krunner-ID=grandtrunk X-KDE-PluginInfo-Author=Stephane MANKOWSKI,miraks X-KDE-PluginInfo-Email=stephane@mankowski.fr X-KDE-PluginInfo-Name=GrandTrunk X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Website=https://skrooge.org/ X-KDE-PluginInfo-Category=Plugins X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true +#To know if this plugin needs a key API +X-SKROOGE-keyAPI=false + #The url or the command line to get the list of accounts in the standard output, something like this: #%1 will be replaced by the internet code of the unit #%2 will be replaced by the current day in format yyyy-MM-dd #%3 will be replaced by the previous date in format yyyy-MM-dd +#%4 will be replaced by the interval +#%5 will be replaced by the key API #Example: # X-SKROOGE-url=https://server/?s=%1 # or # X-SKROOGE-script=mydownloadscript %1 #This parameter is MANDATORY X-SKROOGE-url=https://currencies.apps.grandtrunk.net/getrange/%3/%2/%1 #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 X-SKROOGE-mode=CSVR #Regular expression to capture the price of the quote #This parameter is not MANDATORY. X-SKROOGE-price=^[^ ]* (.*)$ #Regular expression to capture the date of the quote #This parameter is not MANDATORY. X-SKROOGE-date=^(.*) [^ ]*$ #The date format X-SKROOGE-dateformat=yyyy-MM-dd diff --git a/skgbankmodeler/sources/org.kde.skrooge-source-msn.desktop b/skgbankmodeler/sources/org.kde.skrooge-source-msn.desktop index 79414a2e7..d62dc5b54 100644 --- a/skgbankmodeler/sources/org.kde.skrooge-source-msn.desktop +++ b/skgbankmodeler/sources/org.kde.skrooge-source-msn.desktop @@ -1,74 +1,79 @@ [Desktop Entry] Name=MSN Name[ca]=MSN Name[ca@valencia]=MSN Name[cs]=MSN Name[de]=MSN Name[en_GB]=MSN Name[es]=MSN Name[et]=MSN Name[fr]=MSN Name[gl]=MSN Name[it]=MSN Name[nl]=MSN Name[pl]=MSN Name[pt]=MSN Name[pt_BR]=MSN Name[sv]=MSN Name[uk]=MSN Name[x-test]=xxMSNxx Comment=You can get the list of available quotes from MSN.
Then, enter the code of the expected quote (the xxx in the url like https://www.msn.com/en-us/money/stockdetails/xxx). Comment[ca]=Podeu obtenir la llista de les cotitzacions disponibles a MSN.
Després introduïu el codi de la cotització esperada (les «xxx» a l'URL com aquest https://www.msn.com/en-us/money/stockdetails/xxx). Comment[ca@valencia]=Podeu obtindre la llista de les cotitzacions disponibles a MSN.
Després introduïu el codi de la cotització esperada (les «xxx» a l'URL com aquest https://www.msn.com/en-us/money/stockdetails/xxx). Comment[en_GB]=You can get the list of available quotes from MSN.
Then, enter the code of the expected quote (the xxx in the URL like https://www.msn.com/en-us/money/stockdetails/xxx). Comment[es]=Puede obtener la lista de las cotizaciones disponibles de MSN.
A continuación, introduzca el símbolo de la cotización esperada (el xxx del url, como en https://www.msn.com/en-us/money/stockdetails/xxx). Comment[et]=Saadaolevate kursside loendi võib hankida saidilt MSN.
Seejärel sisesta oodatava kursi kood (xxx URL-is, näiteks https://www.msn.com/en-us/money/stockdetails/xxx). Comment[fr]=Vous pouvez récupérer la liste des cotation disponibles depuis MSN.
Ensuite, saisissez la cotation souhaitée (le xxx dans l'adresse comme celle-ci https://www.msn.com/en-us/money/stockdetails/xxx). Comment[gl]=Pode obter a lista de cotizacións dispoñíbeis de MSN.
A continuación escriba a cotización esperada (o xxx dos URL coa forma https://www.msn.com/en-us/money/stockdetails/xxx). Comment[it]=Puoi ottenere un elenco delle quotazioni disponibili da MSN.
Digita, quindi, il codice della quotazione desiderata (la xxx nell'URL, tipo https://www.msn.com/en-us/money/stockdetails/xxx). Comment[nl]=U kunt de lijst met namen van beschikbare koersen ophalen uit MSN.
Voer dan de naam van de gevraagde koers in (de xxx in de url zoals deze https://www.msn.com/en-us/money/stockdetails/xxx/). Comment[pl]=Wykaz dostępnych wycen można pobrać z MSN.
Następnie podaj żądaną wycenę(trzy iksy xxx w adresie url tak jak w https://www.msn.com/en-us/money/stockdetails/xxx). Comment[pt]=Poderá obter a lista de cotações disponíveis a partir do MSN.
Depois, indique a cotação esperada (o 'xxx' num URL como o seguinte: https://msn.com/en-us/money/stockdetails/xxx/). Comment[sv]=Listan över tillgängliga kursnoteringar kan hämtas från MSN.
Skriv därefter in förväntad kurs (xxx i webbadressen https://www.msn.com/en-us/money/stockdetails/xxx). Comment[uk]=Список доступних курсів можна отримати з MSN.
Далі, введіть потрібний курс (xxx у адресі, наприклад https://www.msn.com/en-us/money/stockdetails/xxx). Comment[x-test]=xxYou can get the list of available quotes from MSN.
Then, enter the code of the expected quote (the xxx in the url like https://www.msn.com/en-us/money/stockdetails/xxx).xx Encoding=UTF-8 Icon=skrooge Type=Service X-KDE-ServiceTypes=skrooge/source X-Krunner-ID=msn X-KDE-PluginInfo-Author=Stephane MANKOWSKI,miraks X-KDE-PluginInfo-Email=stephane@mankowski.fr X-KDE-PluginInfo-Name=MSN X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Website=https://skrooge.org/ X-KDE-PluginInfo-Category=Plugins X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true +#To know if this plugin needs a key API +X-SKROOGE-keyAPI=false + #The url or the command line to get the list of accounts in the standard output, something like this: #%1 will be replaced by the internet code of the unit #%2 will be replaced by the current day in format yyyy-MM-dd #%3 will be replaced by the previous date in format yyyy-MM-dd +#%4 will be replaced by the interval +#%5 will be replaced by the key API #Example: # X-SKROOGE-url=https://server/?s=%1 # or # X-SKROOGE-script=mydownloadscript %1 #This parameter is MANDATORY X-SKROOGE-url=https://www.msn.com/en-us/money/stockdetails/%1 #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 X-SKROOGE-mode=HTML #Regular expression to capture the price of the quote #This parameter is not MANDATORY. X-SKROOGE-price="currentvalue">([^<]*)< #Regular expression to capture the date of the quote #This parameter is not MANDATORY. #X-SKROOGE-date=%1,([^,]*),.* #The date format #X-SKROOGE-dateformat=yyyy-MM-dd diff --git a/skgbankmodeler/sources/org.kde.skrooge-source-ratesapi.desktop b/skgbankmodeler/sources/org.kde.skrooge-source-ratesapi.desktop index eea5571a3..59689f787 100644 --- a/skgbankmodeler/sources/org.kde.skrooge-source-ratesapi.desktop +++ b/skgbankmodeler/sources/org.kde.skrooge-source-ratesapi.desktop @@ -1,72 +1,77 @@ [Desktop Entry] Name=RatesAPI Name[ca]=RatesAPI Name[ca@valencia]=RatesAPI Name[cs]=RatesAPI Name[en_GB]=RatesAPI Name[es]=RatesAPI Name[et]=RatesAPI Name[fr]=RatesAPI Name[gl]=RatesAPI Name[it]=RatesAPI Name[nl]=RatesAPI Name[pl]=RatesAPI Name[pt]=RatesAPI Name[pt_BR]=RatesAPI Name[sv]=RatesAPI Name[uk]=RatesAPI Name[x-test]=xxRatesAPIxx Comment=You can get the list of available quotes from RatesAPI.
Then, enter the expected quote in format CURRENCY/BASE (eg. USD/EUR). Comment[ca]=Podeu obtenir la llista de les cotitzacions disponibles a RatesAPI.
Després introduïu la cotització desitjada en format DIVISA/BASE (p. ex. USD/EUR). Comment[ca@valencia]=Podeu obtindre la llista de les cotitzacions disponibles a RatesAPI.
Després introduïu la cotització desitjada en format DIVISA/BASE (p. ex. USD/EUR). Comment[en_GB]=You can get the list of available quotes from RatesAPI.
Then, enter the expected quote in format CURRENCY/BASE (eg. USD/EUR). Comment[es]=Puede obtener la lista de las cotizaciones disponibles de RatesAPI.
A continuación, introduzca la cotización esperada con el formato DIVISA/BASE (por ejemplo, USD/EUR). Comment[et]=Saadaolevate kursside loendi võib hankida saidilt RatesAPI.
Seejärel sisesta oodatav kurss kujul VÄÄRING/BAAS (nt USD/EUR). Comment[fr]=Vous pouvez récupérer la liste des cotation disponibles depuis RatesAPI.
Ensuite, saisissez le symbole de la cotation souhaitée au format DEVISE/BASE (par ex. USD/EUR). Comment[gl]=Pode obter a lista de cotizacións dispoñíbeis de RatesAPI.
A continuación escriba a cotización esperada no formato DIVISA/BASE (p. ex. USD/EUR). Comment[it]=Puoi ottenere l'elenco delle quotazioni disponibili da RatesAPI.
Digita, quindi, la quotazione attesa nel formato VALUTA/BASE (es. USD/EUR). Comment[nl]=U kunt de lijst met namen van beschikbare koersen ophalen uit RatesAPI.
Voer dan de gewenste koers in in het formaat VALUTA/BASIS (bijv. USD/EUR). Comment[pt]=Poderá obter a lista de cotações disponíveis a partir do RatesAPI.
Depois, indique o símbolo das cotações esperadas no formato MOEDA/BASE (p.ex., USD/EUR). Comment[sv]=Listan över tillgängliga kursnoteringar kan hämtas från RatesAPI.
Skriv därefter in förväntad kursnotering på formatet VALUTA/BAS (t.ex. USD/EUR). Comment[uk]=Ви можете отримати список доступних курсів з сайта RatesAPI.
Далі, введіть потрібний вам курс у форматі ВАЛЮТА/ЕТАЛОН (наприклад USD/EUR). Comment[x-test]=xxYou can get the list of available quotes from RatesAPI.
Then, enter the expected quote in format CURRENCY/BASE (eg. USD/EUR).xx Encoding=UTF-8 Icon=skrooge Type=Service X-KDE-ServiceTypes=skrooge/source X-Krunner-ID=ratesapi X-KDE-PluginInfo-Author=Stephane MANKOWSKI,miraks X-KDE-PluginInfo-Email=stephane@mankowski.fr X-KDE-PluginInfo-Name=RatesAPI X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Website=https://skrooge.org/ X-KDE-PluginInfo-Category=Plugins X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true +#To know if this plugin needs a key API +X-SKROOGE-keyAPI=false + #The url or the command line to get the list of accounts in the standard output, something like this: #%1 will be replaced by the internet code of the unit #%2 will be replaced by the current day in format yyyy-MM-dd #%3 will be replaced by the previous date in format yyyy-MM-dd +#%4 will be replaced by the interval +#%5 will be replaced by the key API #Example: # X-SKROOGE-url=https://server/?s=%1 # or # X-SKROOGE-script=mydownloadscript %1 #This parameter is MANDATORY X-SKROOGE-script=skrooge-ratesapi.py %1 #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 X-SKROOGE-mode=CSV #Regular expression to capture the price of the quote #This parameter is not MANDATORY. X-SKROOGE-price=[^,]*,([^,]*) #Regular expression to capture the date of the quote #This parameter is not MANDATORY. X-SKROOGE-date=([^,]*),.* #The date format X-SKROOGE-dateformat=yyyy-MM-dd diff --git a/skgbankmodeler/sources/org.kde.skrooge-source-skrooge.desktop b/skgbankmodeler/sources/org.kde.skrooge-source-skrooge.desktop index 43e082ef8..15b1787f1 100644 --- a/skgbankmodeler/sources/org.kde.skrooge-source-skrooge.desktop +++ b/skgbankmodeler/sources/org.kde.skrooge-source-skrooge.desktop @@ -1,87 +1,92 @@ [Desktop Entry] Name=Skrooge Name[bs]=Skrooge Name[ca]=Skrooge Name[ca@valencia]=Skrooge Name[cs]=Skrooge Name[da]=Skrooge Name[de]=Skrooge Name[el]=Skrooge Name[en_GB]=Skrooge Name[eo]=Skrooge Name[es]=Skrooge Name[et]=Skrooge Name[fi]=Skrooge Name[fr]=Skrooge Name[gl]=Skrooge Name[hu]=Skrooge Name[it]=Skrooge Name[lt]=Skrooge Name[nb]=Skrooge Name[nl]=Skrooge Name[pl]=Skrooge Name[pt]=Skrooge Name[pt_BR]=Skrooge Name[ru]=Skrooge Name[sk]=Skrooge Name[sv]=Skrooge Name[tr]=Skrooge Name[uk]=Skrooge Name[x-test]=xxSkroogexx Name[zh_CN]=Skrooge Name[zh_TW]=Skrooge Comment=Here is the list of available quotes: fr_inflation. Comment[ca]=Aquí hi ha la llista de cotitzacions disponibles: fr_inflation. Comment[ca@valencia]=Ací hi ha la llista de cotitzacions disponibles: fr_inflation. Comment[en_GB]=Here is the list of available quotes: fr_inflation. Comment[es]=Esta es la lista de las cotizaciones disponibles: fr_inflation. Comment[et]=Saadaolevate kursside loend: fr_inflation. Comment[fr]=Voici la liste des cotations disponibles: fr_inflation. Comment[gl]=Esta é a lista de cotizacións dispoñíbeis: fr_inflation. Comment[it]=Ecco l'elenco delle quotazioni disponibili: fr_inflation. Comment[nl]=Hier is de lijst met beschikbare quotes: fr_inflation. Comment[pl]=Oto lista dostępnych wycen: fr_inflation. Comment[pt]=Aqui está a lista de cotações disponíveis: fr_inflation. Comment[sv]=Här är listan över tillgängliga kursnoteringar: fr_inflation Comment[uk]=Ось список доступних курсів: fr_inflation. Comment[x-test]=xxHere is the list of available quotes: fr_inflation.xx Encoding=UTF-8 Icon=skrooge Type=Service X-KDE-ServiceTypes=skrooge/source X-Krunner-ID=skrooge X-KDE-PluginInfo-Author=Stephane MANKOWSKI,miraks X-KDE-PluginInfo-Email=stephane@mankowski.fr X-KDE-PluginInfo-Name=Skrooge X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Website=https://skrooge.org/ X-KDE-PluginInfo-Category=Plugins X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true +#To know if this plugin needs a key API +X-SKROOGE-keyAPI=false + #The url or the command line to get the list of accounts in the standard output, something like this: #%1 will be replaced by the internet code of the unit #%2 will be replaced by the current day in format yyyy-MM-dd #%3 will be replaced by the previous date in format yyyy-MM-dd +#%4 will be replaced by the interval +#%5 will be replaced by the key API #Example: # X-SKROOGE-url=https://server/?s=%1 # or # X-SKROOGE-script=mydownloadscript %1 #This parameter is MANDATORY X-SKROOGE-url=https://filedn.com/lfh5wtnkbtUFtBhIeKEriJz/skrooge/%1.csv #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 X-SKROOGE-mode=CSV #Regular expression to capture the price of the quote #This parameter is not MANDATORY. X-SKROOGE-price=[^,]*,([^,]*) #Regular expression to capture the date of the quote #This parameter is not MANDATORY. X-SKROOGE-date=([^,]*),.* #The date format X-SKROOGE-dateformat=yyyy diff --git a/skgbankmodeler/sources/org.kde.skrooge-source-stooq.desktop b/skgbankmodeler/sources/org.kde.skrooge-source-stooq.desktop index a09adb471..40a0565b1 100644 --- a/skgbankmodeler/sources/org.kde.skrooge-source-stooq.desktop +++ b/skgbankmodeler/sources/org.kde.skrooge-source-stooq.desktop @@ -1,73 +1,78 @@ [Desktop Entry] Name=Stooq Name[ca]=Stooq Name[ca@valencia]=Stooq Name[de]=Stooq Name[en_GB]=Stooq Name[es]=Stooq Name[et]=Stooq Name[fr]=Stooq Name[gl]=Stooq Name[it]=Stooq Name[nl]=Stooq Name[pl]=Stooq Name[pt]=Stooq Name[pt_BR]=Stooq Name[sv]=Stooq Name[uk]=Stooq Name[x-test]=xxStooqxx Comment=You can get the list of available quotes from Stooq.
Then, enter the symbol of the expected quotes. Comment[ca]=Podeu obtenir la llista de les cotitzacions disponibles a Stooq.
Després introduïu el símbol de les cotitzacions esperades. Comment[ca@valencia]=Podeu obtindre la llista de les cotitzacions disponibles a Stooq.
Després introduïu el símbol de les cotitzacions esperades. Comment[en_GB]=You can get the list of available quotes from Stooq.
Then, enter the symbol of the expected quotes. Comment[es]=Puede obtener la lista de las cotizaciones disponibles de Stooq.
A continuación, introduzca el símbolo de las cotizaciones esperadas. Comment[et]=Saadaolevate kursside loendi võib hankida saidilt Stooq.Seejärel sisesta oodatava kursi sümbol. Comment[fr]=Vous pouvez récupérer la liste des cotation disponibles depuis Stooq.
Ensuite, saisissez le symbole de la cotation souhaitée. Comment[gl]=Pode obter a lista de cotizacións dispoñíbeis de Stooq.
A continuación escriba o símbolo das cotizacións esperadas. Comment[it]=Puoi ottenere l'elenco delle quotazioni disponibili da Stooq.
Digita, quindi, il simbolo delle quotazioni desiderate. Comment[nl]=U kunt de lijst met namen van beschikbare koersen ophalen uit Stooq.
Voer dan het symbool van de gewenste koers in. Comment[pl]=Możesz pobrać wykaz dostępnych wycen z Stooq.
Następnie podaj symbol żądanej wyceny. Comment[pt]=Poderá obter a lista de cotações disponíveis a partir do Stooq.
Depois, indique o símbolo das cotações esperadas. Comment[sv]=Listan över tillgängliga kursnoteringar kan hämtas från Stooq.
Skriv därefter in symbolen för de förväntade kurserna. Comment[uk]=Список доступних курсів можна отримати з Stooq
Далі, введіть позначення потрібного курсу. Comment[x-test]=xxYou can get the list of available quotes from Stooq.
Then, enter the symbol of the expected quotes.xx Encoding=UTF-8 Icon=skrooge Type=Service X-KDE-ServiceTypes=skrooge/source X-Krunner-ID=stooq X-KDE-PluginInfo-Author=Stephane MANKOWSKI,miraks X-KDE-PluginInfo-Email=stephane@mankowski.fr X-KDE-PluginInfo-Name=Stooq X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Website=https://skrooge.org/ X-KDE-PluginInfo-Category=Plugins X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true +#To know if this plugin needs a key API +X-SKROOGE-keyAPI=false + #The url or the command line to get the list of accounts in the standard output, something like this: #%1 will be replaced by the internet code of the unit #%2 will be replaced by the current day in format yyyy-MM-dd #%3 will be replaced by the previous date in format yyyy-MM-dd +#%4 will be replaced by the interval +#%5 will be replaced by the key API #Example: # X-SKROOGE-url=https://server/?s=%1 # or # X-SKROOGE-script=mydownloadscript %1 #This parameter is MANDATORY X-SKROOGE-url=https://stooq.pl/q/l/?s=%1&f=sd2t2ohlcv&h&e=csv #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 X-SKROOGE-mode=CSV #Regular expression to capture the price of the quote #This parameter is not MANDATORY. X-SKROOGE-price=%1,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,([^,]*),.* #Regular expression to capture the date of the quote #This parameter is not MANDATORY. X-SKROOGE-date=%1,([^,]*),.* #The date format X-SKROOGE-dateformat=yyyy-MM-dd diff --git a/skgbankmodeler/sources/org.kde.skrooge-source-yahoo.desktop b/skgbankmodeler/sources/org.kde.skrooge-source-yahoo.desktop index 72d0eb833..9437a586a 100644 --- a/skgbankmodeler/sources/org.kde.skrooge-source-yahoo.desktop +++ b/skgbankmodeler/sources/org.kde.skrooge-source-yahoo.desktop @@ -1,76 +1,81 @@ [Desktop Entry] Name=Yahoo Name[ca]=Yahoo Name[ca@valencia]=Yahoo Name[cs]=Yahoo Name[de]=Yahoo Name[en_GB]=Yahoo Name[es]=Yahoo Name[et]=Yahoo Name[fr]=Yahoo Name[gl]=Yahoo Name[ia]=Yahoo Name[it]=Yahoo Name[nl]=Yahoo Name[pl]=Yahoo Name[pt]=Yahoo Name[pt_BR]=Yahoo Name[sv]=Yahoo Name[uk]=Yahoo Name[x-test]=xxYahooxx Name[zh_CN]=Yahoo Comment=You can get the list of available quotes from Yahoo Finance.
Then, enter the symbol of the expected quotes. Comment[ca]=Podeu obtenir la llista de les cotitzacions disponibles a Yahoo Finance.
Després introduïu el símbol de les cotitzacions esperades. Comment[ca@valencia]=Podeu obtindre la llista de les cotitzacions disponibles a Yahoo Finance.
Després introduïu el símbol de les cotitzacions esperades. Comment[en_GB]=You can get the list of available quotes from Yahoo Finance.
Then, enter the symbol of the expected quotes. Comment[es]=Puede obtener la lista de las cotizaciones disponibles de Yahoo Finance.
A continuación, introduzca el símbolo de las cotizaciones esperadas. Comment[et]=Saadaolevate kursside loendi võib hankida saidilt Yahoo Finance.
Seejärel sisesta oodatava kursi sümbol. Comment[fr]=Vous pouvez récupérer la liste des cotation disponibles depuis Yahoo Finance.
Ensuite, saisissez le symbole de la cotation souhaitée. Comment[gl]=Pode obter a lista de cotizacións dispoñíbeis de Yahoo Finance.A continuación escriba o símbolo das cotizacións esperadas. Comment[it]=Puoi ottenere l'elenco delle quotazioni disponibili da Yahoo Finanza.
Digita, quindi, il simbolo delle quotazioni desiderate. Comment[nl]=U kunt de lijst met namen van beschikbare koersen ophalen uit Yahoo Finance.
Voer dan de naam van de gewenste koers in. Comment[pl]=Możesz pobrać wykaz dostępnych wycen z Yahoo Finance.
Następnie podaj symbol żądanej wyceny. Comment[pt]=Poderá obter a lista de cotações disponíveis a partir do Yahoo Finance. Depois, indique o símbolo das cotações esperadas. Comment[sv]=Listan över tillgängliga kursnoteringar kan hämtas från Yahoo Finance.
Skriv därefter in symbolen för de förväntade kurserna. Comment[uk]=Список доступних курсів можна отримати з Yahoo Finance.
Далі, введіть позначення потрібних курсів. Comment[x-test]=xxYou can get the list of available quotes from Yahoo Finance.
Then, enter the symbol of the expected quotes.xx Encoding=UTF-8 Icon=skrooge Type=Service X-KDE-ServiceTypes=skrooge/source X-Krunner-ID=yahoo X-KDE-PluginInfo-Author=Stephane MANKOWSKI,miraks X-KDE-PluginInfo-Email=stephane@mankowski.fr X-KDE-PluginInfo-Name=Yahoo X-KDE-PluginInfo-Version=1.0 X-KDE-PluginInfo-Website=https://skrooge.org/ X-KDE-PluginInfo-Category=Plugins X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true +#To know if this plugin needs a key API +X-SKROOGE-keyAPI=false + #The url or the command line to get the list of accounts in the standard output, something like this: #%1 will be replaced by the internet code of the unit #%2 will be replaced by the current day in format yyyy-MM-dd #%3 will be replaced by the previous date in format yyyy-MM-dd +#%4 will be replaced by the interval +#%5 will be replaced by the key API #Example: # X-SKROOGE-url=https://server/?s=%1 # or # X-SKROOGE-script=mydownloadscript %1 #This parameter is MANDATORY X-SKROOGE-script=skrooge-yahoodl.py %1 %3 %2 %4 #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 X-SKROOGE-mode=CSV #Regular expression to capture the price of the quote #This parameter is not MANDATORY. X-SKROOGE-price=[^,]*,[^,]*,[^,]*,([^,]*) #Regular expression to capture the date of the quote #This parameter is not MANDATORY. X-SKROOGE-date=([^,]*),.* #The date format X-SKROOGE-dateformat=yyyy-MM-dd