diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8c5efc3..ad05885 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,193 +1,198 @@ include(GenerateExportHeader) include(ECMGenerateHeaders) include(ECMGeneratePriFile) include(CMakePackageConfigHelpers) include(ECMSetupVersion) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) ########### target alkimia-internal ########### set(alkimia_INTERNAL_SRCS alkdateformat.cpp alkexception.cpp alkmoney.cpp alkquotereceiver.cpp alkonlinequoteprocess.cpp alkfinancequoteprocess.cpp alkonlinequotesprofile.cpp alkonlinequotesprofilemanager.cpp alkonlinequoteswidget.cpp ) set(alkimia_INTERNAL_HEADERS alkdateformat.h alkexception.h alkmoney.h alkquotereceiver.h alkonlinequoteprocess.h alkfinancequoteprocess.h alkonlinequotesprofile.h alkonlinequotesprofilemanager.h alkonlinequoteswidget.h ) set(alkimia_INTERNAL_UI alkonlinequoteswidget.ui ) ki18n_wrap_ui(alkimia_INTERNAL_SRCS ${alkimia_INTERNAL_UI} ) add_library(alkimia-internal STATIC ${alkimia_INTERNAL_SRCS} ${alkimia_INTERNAL_HEADERS}) if(NOT BUILD_QT4) set (ALKIMIA_INTERNAL_LIBS PUBLIC KF5::CoreAddons KF5::KDELibs4Support KF5::NewStuff ) endif() target_link_libraries(alkimia-internal PUBLIC ${QT_USE_LIBSPREFIX}Core ${ALKIMIA_INTERNAL_LIBS}) kde_target_enable_exceptions(alkimia-internal PUBLIC) ########### target alkimia ########### set(ALKIMIA_LIB_VERSION ${alkimia_VERSION}) set(ALKIMIA_LIB_SOVERSION "${alkimia_VERSION_MAJOR}") set(alkimia_LIB_SRCS alkcompany.cpp alkquoteitem.cpp alkvalue.cpp alkonlinequote.cpp alkonlinequotesource.cpp ) set(alkimia_LIB_HEADERS alkcompany.h alkquoteitem.h ${CMAKE_CURRENT_BINARY_DIR}/alkvalue.h alkonlinequote.h alkonlinequotesource.h ${CMAKE_CURRENT_BINARY_DIR}/alk_export.h ) set(alkimia_UI ) add_definitions(-DKNSRC_DIR="${CMAKE_CURRENT_SOURCE_DIR}") ki18n_wrap_ui(alkimia_SRCS ${alkimia_UI} ) add_library(alkimia SHARED ${alkimia_LIB_SRCS} ${alkimia_INTERNAL_SRCS} ${alkimia_LIB_HEADERS}) kde_target_enable_exceptions(alkimia PUBLIC) if(BUILD_QT4) set(ALKIMIA_LIBS PUBLIC ${KDE_LIBRARIES} ${KDE4_KDEUI_LIBS} ${KDE4_KNEWSTUFF3_LIBS}) else() set(ALKIMIA_LIBS PUBLIC ${QT_USE_LIBSPREFIX}WebKitWidgets KF5::KDELibs4Support KF5::NewStuff ) endif() target_link_libraries(alkimia PRIVATE alkimia-internal PUBLIC ${QT_USE_LIBSPREFIX}Core ${QT_USE_LIBSPREFIX}DBus ${QT_USE_LIBSPREFIX}WebKit ${MP_LIBRARIES} ${ALKIMIA_LIBS} ) generate_export_header(alkimia BASE_NAME alk) if(WIN32) set_target_properties(alkimia PROPERTIES SUFFIX "${ALKIMIA_LIB_SOVERSION}${CMAKE_SHARED_LIBRARY_SUFFIX}") else() set_target_properties(alkimia PROPERTIES VERSION ${ALKIMIA_LIB_VERSION} SOVERSION ${ALKIMIA_LIB_SOVERSION}) endif() set_target_properties(alkimia PROPERTIES OUTPUT_NAME alkimia${ALKIMIA_LIB_SUFFIX}) set(INCLUDE_INSTALL_DIR include/alkimia/${ALKIMIA_INCLUDE_SUFFIX}) install(TARGETS alkimia EXPORT alkimiaTargets ${INSTALL_TARGETS_DEFAULT_ARGS} ) install(FILES ${alkimia_LIB_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/alkimia COMPONENT Devel ) -install(FILES alkimia-skrooge.knsrc DESTINATION ${CONFIG_INSTALL_DIR}) +install(FILES + alkimia-quotes.knsrc + kmymoney-quotes.knsrc + skrooge-quotes.knsrc + DESTINATION ${CONFIG_INSTALL_DIR} +) install(FILES financequote.pl DESTINATION ${DATA_INSTALL_DIR}/alkimia${ALKIMIA_PATH_SUFFIX}/misc ) if (NOT WIN32) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libalkimia.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libalkimia${ALKIMIA_PATH_SUFFIX}.pc IMMEDIATE @ONLY) endif(NOT WIN32) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/alkvalue.h.in ${CMAKE_CURRENT_BINARY_DIR}/alkvalue.h IMMEDIATE) ########### create package configuration file ########### # create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/LibAlkimia${ALKIMIA_PATH_SUFFIX}-${alkimia_VERSION_MAJOR}.${alkimia_VERSION_MINOR}") ecm_setup_version(${alkimia_VERSION} VARIABLE_PREFIX ALKIMIA PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/LibAlkimia${ALKIMIA_PATH_SUFFIX}ConfigVersion.cmake" COMPATIBILITY SameMajorVersion ) configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/LibAlkimiaConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/LibAlkimia${ALKIMIA_PATH_SUFFIX}Config.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} PATH_VARS INCLUDE_INSTALL_DIR ) ########### install files ############### export(TARGETS alkimia FILE "${CMAKE_CURRENT_BINARY_DIR}/LibAlkimia${ALKIMIA_PATH_SUFFIX}Targets.cmake" NAMESPACE Alkimia:: ) install(EXPORT alkimiaTargets FILE LibAlkimia${ALKIMIA_PATH_SUFFIX}Targets.cmake NAMESPACE Alkimia:: DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/LibAlkimia${ALKIMIA_PATH_SUFFIX}Config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/LibAlkimia${ALKIMIA_PATH_SUFFIX}ConfigVersion.cmake" "../cmake/modules/Find${MP_CMAKE_MODULE}.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel) if (NOT WIN32) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libalkimia${ALKIMIA_PATH_SUFFIX}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) endif(NOT WIN32) ########### documentation ################### if(DOXYGEN_FOUND) set(APIDOC_DIR ${CMAKE_CURRENT_BINARY_DIR}/apidocs) make_directory(${APIDOC_DIR}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libalkimia.doxygen.in ${CMAKE_CURRENT_BINARY_DIR}/libalkimia.doxygen IMMEDIATE) add_custom_target(libalkimia_apidoc ${DOXYGEN} ${CMAKE_CURRENT_BINARY_DIR}/libalkimia.doxygen) endif(DOXYGEN_FOUND) diff --git a/src/alkimia-skrooge-local.knsrc b/src/alkimia-quotes-local.knsrc similarity index 100% rename from src/alkimia-skrooge-local.knsrc rename to src/alkimia-quotes-local.knsrc diff --git a/src/alkimia-skrooge.knsrc b/src/alkimia-quotes.knsrc similarity index 82% copy from src/alkimia-skrooge.knsrc copy to src/alkimia-quotes.knsrc index 6672d90..aec0c64 100644 --- a/src/alkimia-skrooge.knsrc +++ b/src/alkimia-quotes.knsrc @@ -1,5 +1,5 @@ [KNewStuff3] ProvidersUrl=http://download.kde.org/ocs/providers.xml Categories=Skrooge quote source -TargetDir=skrooge/quotes +TargetDir=alkimia/quotes Uncompress=archive diff --git a/src/alkonlinequotesource.cpp b/src/alkonlinequotesource.cpp index 924433c..dfc4ed9 100644 --- a/src/alkonlinequotesource.cpp +++ b/src/alkonlinequotesource.cpp @@ -1,288 +1,359 @@ /*************************************************************************** * Copyright 2018 Ralf Habacker * * * * This file is part of libalkimia. * * * * libalkimia is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * * as published by the Free Software Foundation; either version 2.1 of * * the License or (at your option) version 3 or any later version. * * * * libalkimia 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 * ***************************************************************************/ #include "alkonlinequotesource.h" #include "alkonlinequotesprofile.h" +#include #include #include #include class AlkOnlineQuoteSource::Private { public: Private() : m_skipStripping(false) , m_profile(nullptr) + , m_isGHNSSource(false) + , m_storageChanged(false) { } Private(const Private *other) : m_name(other->m_name) , m_url(other->m_url) , m_sym(other->m_sym) , m_price(other->m_price) , m_date(other->m_date) , m_dateformat(other->m_dateformat) , m_skipStripping(other->m_skipStripping) , m_profile(other->m_profile) + , m_isGHNSSource(other->m_isGHNSSource) { } - bool read(KConfig *kconfig, const QString &groupName) + bool read() { - const QString &group = QString("Online-Quote-Source-%1").arg(groupName); + KConfig *kconfig = m_profile->kConfig(); + const QString &group = QString("Online-Quote-Source-%1").arg(m_name); if (!kconfig->hasGroup(group)) { return false; } KConfigGroup grp = kconfig->group(group); - m_name = groupName; m_sym = grp.readEntry("SymbolRegex"); m_date = grp.readEntry("DateRegex"); m_dateformat = grp.readEntry("DateFormatRegex", "%m %d %y"); m_price = grp.readEntry("PriceRegex"); m_url = grp.readEntry("URL"); m_skipStripping = grp.readEntry("SkipStripping", false); + m_isGHNSSource = false; return true; } - bool write(KConfig *kconfig, const QString &groupName) + bool write() { - KConfigGroup grp = kconfig->group(QString("Online-Quote-Source-%1").arg(groupName)); + KConfig *kconfig = m_profile->kConfig(); + KConfigGroup grp = kconfig->group(QString("Online-Quote-Source-%1").arg(m_name)); grp.writeEntry("URL", m_url); grp.writeEntry("PriceRegex", m_price); grp.writeEntry("DateRegex", m_date); grp.writeEntry("DateFormatRegex", m_dateformat); grp.writeEntry("SymbolRegex", m_sym); if (m_skipStripping) { grp.writeEntry("SkipStripping", m_skipStripping); } else { grp.deleteEntry("SkipStripping"); } kconfig->sync(); return true; } + bool remove() + { + KConfig *kconfig = m_profile->kConfig(); + kconfig->deleteGroup(QString("Online-Quote-Source-%1").arg(m_name)); + kconfig->sync(); + return true; + } + + QString ghnsReadFilePath() + { + QString fileName = m_profile->hotNewStuffReadFilePath(m_name); + if (!fileName.endsWith(".txt")) + fileName.append(".txt"); + return fileName; + } + + QString ghnsWriteFilePath() + { + QString fileName = m_profile->hotNewStuffWriteFilePath(m_name); + if (!fileName.endsWith(".txt")) + fileName.append(".txt"); + return fileName; + } + // This is currently in skrooge format - bool readFromGHNSFile(const QString &configFile) + bool readFromGHNSFile() { - if (configFile.isEmpty()) { - return false; - } - KConfig config(configFile); + QFileInfo f(ghnsReadFilePath()); + if (!f.exists()) + f.setFile(ghnsWriteFilePath()); + KConfig config(f.absoluteFilePath()); KConfigGroup group(&config, ""); if (!(group.hasKey("mode") && group.readEntry("mode") == "HTML" && group.hasKey("url") && group.hasKey("date") && group.hasKey("dateformat") && group.hasKey("price"))) { return false; } m_skipStripping = true; m_url = group.readEntry("url"); m_price = group.readEntry("price"); m_date = group.readEntry("date"); m_dateformat = group.readEntry("dateformat"); + m_isGHNSSource = true; return true; } // This is currently in skrooge format - bool writeToGHNSFile(const QString &configFile) + bool writeToGHNSFile() { - if (configFile.isEmpty()) { - return false; - } - KConfig config(configFile); + KConfig config(ghnsWriteFilePath()); KConfigGroup group(&config, ""); group.writeEntry("url", m_url); group.writeEntry("price", m_price); group.writeEntry("date", m_date); group.writeEntry("dateformat", m_dateformat); group.writeEntry("mode", "HTML"); return true; } + bool removeGHNSFile() + { + qDebug() << "delete" << ghnsWriteFilePath(); + return true; + } + QString m_name; QString m_url; QString m_sym; QString m_price; QString m_date; QString m_dateformat; bool m_skipStripping; AlkOnlineQuotesProfile *m_profile; + bool m_isGHNSSource; + bool m_storageChanged; }; AlkOnlineQuoteSource::AlkOnlineQuoteSource() : d(new Private) { } AlkOnlineQuoteSource::AlkOnlineQuoteSource(const AlkOnlineQuoteSource &other) : d(new Private(other.d)) { } AlkOnlineQuoteSource &AlkOnlineQuoteSource::operator=(const AlkOnlineQuoteSource &other) { delete d; d = new Private(other.d); return *this; } AlkOnlineQuoteSource::AlkOnlineQuoteSource(const QString &name, const QString &url, const QString &sym, const QString &price, const QString &date, const QString &dateformat, bool skipStripping) : d(new Private) { d->m_name = name; d->m_url = url; d->m_sym = sym; d->m_price = price; d->m_date = date; d->m_dateformat = dateformat; d->m_skipStripping = skipStripping; + d->m_isGHNSSource = false; } AlkOnlineQuoteSource::AlkOnlineQuoteSource(const QString &name, AlkOnlineQuotesProfile *profile) : d(new Private) { d->m_profile = profile; - if (name.endsWith(".txt")) { - d->readFromGHNSFile(profile->hotNewStuffReadFilePath(name)); - d->m_name = name; - } else { - d->read(profile->kConfig(), name); - } + d->m_name = name; + read(); } AlkOnlineQuoteSource::~AlkOnlineQuoteSource() { delete d; } bool AlkOnlineQuoteSource::isValid() { return !d->m_name.isEmpty(); } QString AlkOnlineQuoteSource::name() const { return d->m_name; } QString AlkOnlineQuoteSource::url() const { return d->m_url; } QString AlkOnlineQuoteSource::sym() const { return d->m_sym; } QString AlkOnlineQuoteSource::price() const { return d->m_price; } QString AlkOnlineQuoteSource::date() const { return d->m_date; } QString AlkOnlineQuoteSource::dateformat() const { return d->m_dateformat; } bool AlkOnlineQuoteSource::skipStripping() const { return d->m_skipStripping; } void AlkOnlineQuoteSource::setName(const QString &name) { d->m_name = name; } void AlkOnlineQuoteSource::setUrl(const QString &url) { d->m_url = url; } void AlkOnlineQuoteSource::setSym(const QString &symbol) { d->m_sym = symbol; } void AlkOnlineQuoteSource::setPrice(const QString &price) { d->m_price = price; } void AlkOnlineQuoteSource::setDate(const QString &date) { d->m_date = date; } void AlkOnlineQuoteSource::setDateformat(const QString &dateformat) { d->m_dateformat = dateformat; } void AlkOnlineQuoteSource::setSkipStripping(bool state) { d->m_skipStripping = state; } +void AlkOnlineQuoteSource::setGHNS(bool state) +{ + d->m_storageChanged = d->m_isGHNSSource != state; + d->m_isGHNSSource = state; +} + +bool AlkOnlineQuoteSource::isGHNS() +{ + return d->m_isGHNSSource; +} + +QString AlkOnlineQuoteSource::ghnsWriteFileName() +{ + return d->ghnsWriteFilePath(); +} + void AlkOnlineQuoteSource::setProfile(AlkOnlineQuotesProfile *profile) { d->m_profile = profile; qDebug() << "using profile" << profile->name(); } AlkOnlineQuotesProfile *AlkOnlineQuoteSource::profile() { return d->m_profile; } +bool AlkOnlineQuoteSource::read() +{ + bool result = false; + if (d->m_profile->hasGHNSSupport()) { + result = d->readFromGHNSFile(); + if (result) + return true; + } + return d->read(); +} + bool AlkOnlineQuoteSource::write() { - // FIXME - if (d->m_name.endsWith(".txt")) { - return d->writeToGHNSFile(profile()->hotNewStuffWriteFilePath(d->m_name)); + bool result = false; + // check if type has been changedd->isGHNS + if (d->m_profile->hasGHNSSupport() && d->m_isGHNSSource) { + result = d->writeToGHNSFile(); + if (d->m_storageChanged) + d->remove(); + return result; } else { - return d->write(profile()->kConfig(), d->m_name); + result = d->write(); + if (d->m_profile->hasGHNSSupport() && d->m_storageChanged) { + d->removeGHNSFile(); + } } + d->m_storageChanged = false; + return result; } void AlkOnlineQuoteSource::rename(const QString &name) { remove(); d->m_name = name; write(); } void AlkOnlineQuoteSource::remove() { - KConfig *kconfig = profile()->kConfig(); - kconfig->deleteGroup(QString("Online-Quote-Source-%1").arg(d->m_name)); - kconfig->sync(); + if (d->m_profile->hasGHNSSupport() && d->m_isGHNSSource) { + d->removeGHNSFile(); + } else { + d->remove(); + } } diff --git a/src/alkonlinequotesource.h b/src/alkonlinequotesource.h index 72e9433..6b8f4d0 100644 --- a/src/alkonlinequotesource.h +++ b/src/alkonlinequotesource.h @@ -1,76 +1,80 @@ /*************************************************************************** * Copyright 2018 Ralf Habacker * * * * This file is part of libalkimia. * * * * libalkimia is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * * as published by the Free Software Foundation; either version 2.1 of * * the License or (at your option) version 3 or any later version. * * * * libalkimia 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 * ***************************************************************************/ #ifndef ALKONLINEQUOTESOURCE_H #define ALKONLINEQUOTESOURCE_H #include "alk_export.h" #include "alkonlinequotesprofile.h" #include /** * @author Thomas Baumgart & Ace Jones * * This is a helper class to store information about an online source * for stock prices or currency exchange rates. */ class ALK_EXPORT AlkOnlineQuoteSource { public: AlkOnlineQuoteSource(); AlkOnlineQuoteSource(const AlkOnlineQuoteSource &other); AlkOnlineQuoteSource &operator=(const AlkOnlineQuoteSource &other); AlkOnlineQuoteSource(const QString &name, AlkOnlineQuotesProfile *profile); AlkOnlineQuoteSource(const QString &name, const QString &url, const QString &sym, const QString &price, const QString &date, const QString &dateformat, bool skipStripping = false); ~AlkOnlineQuoteSource(); bool isValid(); + bool read(); bool write(); void rename(const QString &name); void remove(); QString name() const; QString url() const; QString sym() const; QString price() const; QString date() const; QString dateformat() const; bool skipStripping() const; + bool isGHNS(); void setName(const QString &name); void setUrl(const QString &url); void setSym(const QString &symbol); void setPrice(const QString &price); void setDate(const QString &date); void setDateformat(const QString &dateformat); void setSkipStripping(bool state); + void setGHNS(bool state); + QString ghnsWriteFileName(); void setProfile(AlkOnlineQuotesProfile *profile); AlkOnlineQuotesProfile *profile(); protected: class Private; Private *d; }; #endif // ALKONLINEQUOTESOURCE_H diff --git a/src/alkonlinequotesprofile.cpp b/src/alkonlinequotesprofile.cpp index b6656df..2afe1d0 100644 --- a/src/alkonlinequotesprofile.cpp +++ b/src/alkonlinequotesprofile.cpp @@ -1,302 +1,313 @@ /*************************************************************************** * Copyright 2018 Ralf Habacker * * * * This file is part of libalkimia. * * * * libalkimia is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * * as published by the Free Software Foundation; either version 2.1 of * * the License or (at your option) version 3 or any later version. * * * * libalkimia 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 * ***************************************************************************/ #include "alkonlinequotesprofile.h" #include "alkonlinequotesprofilemanager.h" #include "alkonlinequotesource.h" #include "alkfinancequoteprocess.h" #include #include #include #include #include #include #include #include #include class AlkOnlineQuotesProfile::Private : public QObject { Q_OBJECT public: AlkOnlineQuotesProfile *m_p; QString m_name; QString m_GHNSFile; QString m_GHNSFilePath; QString m_kconfigFile; AlkOnlineQuotesProfileManager *m_profileManager; KNS3::DownloadManager *m_manager; KConfig *m_config; Type m_type; static QString m_financeQuoteScriptPath; static QStringList m_financeQuoteSources; Private(AlkOnlineQuotesProfile *p) : m_p(p) , m_profileManager(0) , m_manager(0) , m_config(0) , m_type(Type::Undefined) { if (m_financeQuoteScriptPath.isEmpty()) { m_financeQuoteScriptPath = KGlobal::dirs()->findResource("appdata", QString("misc/financequote.pl")); } } ~Private() { delete m_manager; delete m_config; } void checkUpdates() { m_manager = new KNS3::DownloadManager(m_p->hotNewStuffConfigFile(), this); // to know when checking for updates is done connect(m_manager, SIGNAL(searchResult(KNS3::Entry::List)), this, SLOT(slotUpdatesFound(KNS3::Entry::List))); // to know about finished installations connect(m_manager, SIGNAL(entryStatusChanged(KNS3::Entry)), this, SLOT(entryStatusChanged(KNS3::Entry))); // start checking for updates m_manager->checkForUpdates(); } public Q_SLOTS: void slotUpdatesFound(const KNS3::Entry::List &updates) { foreach (const KNS3::Entry &entry, updates) { qDebug() << entry.name(); } } // to know about finished installations void entryStatusChanged(const KNS3::Entry &entry) { qDebug() << entry.summary(); } const QStringList quoteSourcesNative() { //KSharedConfigPtr kconfig = KGlobal::config(); KConfig config(m_kconfigFile); KConfig *kconfig = &config; QStringList groups = kconfig->groupList(); QStringList::Iterator it; QRegExp onlineQuoteSource(QString("^Online-Quote-Source-(.*)$")); // get rid of all 'non online quote source' entries for (it = groups.begin(); it != groups.end(); it = groups.erase(it)) { if (onlineQuoteSource.indexIn(*it) >= 0) { // Insert the name part it = groups.insert(it, onlineQuoteSource.cap(1)); ++it; } } // Set up each of the default sources. These are done piecemeal so that // when we add a new source, it's automatically picked up. And any changes // are also picked up. QMap defaults = defaultQuoteSources(); QMap::iterator it_source = defaults.begin(); while (it_source != defaults.end()) { if (!groups.contains((*it_source).name())) { groups += (*it_source).name(); (*it_source).write(); kconfig->sync(); } ++it_source; } return groups; } const QStringList quoteSourcesFinanceQuote() { if (m_financeQuoteSources.empty()) { // run the process one time only // since this is a static function it can be called without constructing an object // so we need to make sure that m_financeQuoteScriptPath is properly initialized if (m_financeQuoteScriptPath.isEmpty()) { m_financeQuoteScriptPath = KGlobal::dirs()->findResource("appdata", QString("financequote.pl")); } AlkFinanceQuoteProcess getList; getList.launch(m_financeQuoteScriptPath); while (!getList.isFinished()) { qApp->processEvents(); } m_financeQuoteSources = getList.getSourceList(); } return m_financeQuoteSources; } const QStringList quoteSourcesSkrooge() + { + return quoteSourcesGHNS(); + } + + const QStringList quoteSourcesGHNS() { QStringList sources; QString relPath = m_GHNSFilePath; foreach (const QString &file, KStandardDirs().findAllResources("data", relPath + QString::fromLatin1("/*.txt"))) { QFileInfo f(file); - QString file2 = f.fileName(); + QString file2 = f.completeBaseName(); if (!sources.contains(file2)) { sources.push_back(file2); } } return sources; } const AlkOnlineQuotesProfile::Map defaultQuoteSources() { QMap result; // Use fx-rate.net as the standard currency exchange rate source until // we have the capability to use more than one source. Use a neutral // name for the source. if (m_p->name() == "alkimia") { result["Alkimia Currency"] = AlkOnlineQuoteSource("Alkimia Currency", "https://fx-rate.net/%1/%2", QString(), // symbolregexp "1[ a-zA-Z]+=
*(\\d+\\.\\d+)", "updated\\s\\d+:\\d+:\\d+\\(\\w+\\)\\s+(\\d{1,2}/\\d{2}/\\d{4})", "%d/%m/%y", true // skip HTML stripping ); } return result; } }; // define static members QString AlkOnlineQuotesProfile::Private::m_financeQuoteScriptPath; QStringList AlkOnlineQuotesProfile::Private::m_financeQuoteSources; AlkOnlineQuotesProfile::AlkOnlineQuotesProfile(const QString &name, Type type, - const QString &configFile) + const QString &ghnsConfigFile) : d(new Private(this)) { d->m_name = name; - d->m_GHNSFile = configFile; + d->m_GHNSFile = ghnsConfigFile; d->m_type = type; d->m_kconfigFile = name + "rc"; d->m_config = new KConfig(d->m_kconfigFile); - if (type == Type::GHNS) { + if (!d->m_GHNSFile.isEmpty()) { KConfig ghnsFile(hotNewStuffConfigFile()); KConfigGroup group = ghnsFile.group("KNewStuff3"); d->m_GHNSFilePath = group.readEntry("TargetDir"); d->checkUpdates(); } } AlkOnlineQuotesProfile::~AlkOnlineQuotesProfile() { delete d; } QString AlkOnlineQuotesProfile::name() const { return d->m_name; } QString AlkOnlineQuotesProfile::hotNewStuffConfigFile() const { QString configFile = KStandardDirs::locate("config", d->m_GHNSFile); if (configFile.isEmpty()) { configFile = QString("%1/%2").arg(KNSRC_DIR, d->m_GHNSFile); } return configFile; } QString AlkOnlineQuotesProfile::hotNewStuffReadFilePath(const QString &fileName) const { return KStandardDirs::locate("data", d->m_GHNSFilePath + "/" + fileName); } QString AlkOnlineQuotesProfile::hotNewStuffWriteFilePath(const QString &fileName) const { return KStandardDirs::locateLocal("data", d->m_GHNSFilePath + "/" + fileName); } QString AlkOnlineQuotesProfile::hotNewStuffRelPath() const { return d->m_GHNSFilePath; } QString AlkOnlineQuotesProfile::kConfigFile() const { return d->m_kconfigFile; } KConfig *AlkOnlineQuotesProfile::kConfig() const { return d->m_config; } AlkOnlineQuotesProfile::Type AlkOnlineQuotesProfile::type() { return d->m_type; } +bool AlkOnlineQuotesProfile::hasGHNSSupport() +{ + return !d->m_GHNSFile.isEmpty(); +} + const AlkOnlineQuotesProfile::Map AlkOnlineQuotesProfile::defaultQuoteSources() { return d->defaultQuoteSources(); } const QStringList AlkOnlineQuotesProfile::quoteSources() { QStringList result; switch(d->m_type) { case AlkOnlineQuotesProfile::Type::KMyMoney: result << d->quoteSourcesNative(); break; case AlkOnlineQuotesProfile::Type::Script: result << d->quoteSourcesFinanceQuote(); break; - case AlkOnlineQuotesProfile::Type::GHNS: case AlkOnlineQuotesProfile::Type::Skrooge: result << d->quoteSourcesSkrooge(); break; default: break; } + if (hasGHNSSupport()) + result << d->quoteSourcesGHNS(); return result; } void AlkOnlineQuotesProfile::setManager(AlkOnlineQuotesProfileManager *manager) { d->m_profileManager = manager; } AlkOnlineQuotesProfileManager *AlkOnlineQuotesProfile::manager() { return d->m_profileManager; } #include "alkonlinequotesprofile.moc" diff --git a/src/alkonlinequotesprofile.h b/src/alkonlinequotesprofile.h index 656fcee..5ed8870 100644 --- a/src/alkonlinequotesprofile.h +++ b/src/alkonlinequotesprofile.h @@ -1,71 +1,71 @@ /*************************************************************************** * Copyright 2018 Ralf Habacker * * * * This file is part of libalkimia. * * * * libalkimia is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License * * as published by the Free Software Foundation; either version 2.1 of * * the License or (at your option) version 3 or any later version. * * * * libalkimia 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 * ***************************************************************************/ #ifndef ALKONLINEQUOTESPROFILE_H #define ALKONLINEQUOTESPROFILE_H #include "alk_export.h" #include #include class KConfig; class AlkOnlineQuoteSource; class AlkOnlineQuotesProfileManager; class ALK_EXPORT AlkOnlineQuotesProfile { public: typedef QMap Map; enum class Type { Undefined, GHNS, KMyMoney, Skrooge, Script }; - AlkOnlineQuotesProfile( - const QString &name = "alkimia", Type type = Type::KMyMoney, - const QString &configFile = QString()); + AlkOnlineQuotesProfile(const QString &name = "alkimia", Type type = Type::KMyMoney, + const QString &ghnsConfigFile = QString()); ~AlkOnlineQuotesProfile(); QString name() const; QString hotNewStuffConfigFile() const; QString hotNewStuffRelPath() const; QString hotNewStuffReadFilePath(const QString &fileName) const; QString hotNewStuffWriteFilePath(const QString &fileName) const; QString kConfigFile() const; void setManager(AlkOnlineQuotesProfileManager *manager); AlkOnlineQuotesProfileManager *manager(); KConfig *kConfig() const; Type type(); + bool hasGHNSSupport(); /** * return available default sources of this profile */ const Map defaultQuoteSources(); /** * return available sources of this profile */ const QStringList quoteSources(); private: class Private; Private *d; }; #endif // ALKONLINEQUOTESPROFILE_H diff --git a/src/alkonlinequoteswidget.cpp b/src/alkonlinequoteswidget.cpp index c039f79..6ac3ce9 100644 --- a/src/alkonlinequoteswidget.cpp +++ b/src/alkonlinequoteswidget.cpp @@ -1,543 +1,549 @@ /*************************************************************************** * Copyright 2004 Thomas Baumgart tbaumgart@kde.org * * * * This file is part of libalkimia. * * * * libalkimia 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.1 of * * the License or (at your option) version 3 or any later version. * * * * libalkimia 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 * ***************************************************************************/ #include "alkonlinequoteswidget.h" #include "alkonlinequote.h" #include "alkonlinequotesprofile.h" #include "alkonlinequotesprofilemanager.h" #include "alkonlinequotesource.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class AlkOnlineQuotesWidget::Private : public QWidget, public Ui::AlkOnlineQuotesWidget { Q_OBJECT public: QWebView *m_webView; QString m_acceptLanguage; QList m_resetList; AlkOnlineQuoteSource m_currentItem; bool m_quoteInEditing; AlkOnlineQuotesProfile *m_profile; Private(QWidget *parent); public slots: void slotNewProfile(); void slotDeleteProfile(); void slotSelectProfile(); void slotLoadProfile(); void slotDeleteEntry(); void slotUpdateEntry(); void slotLoadWidgets(); void slotEntryChanged(); void slotNewEntry(); void slotCheckEntry(); void slotLogStatus(const QString &s); void slotLogError(const QString &s); void slotLogFailed(const QString &id, const QString &symbol); void slotLogQuote(const QString &id, const QString &symbol, const QDate &date, double price); void slotEntryRenamed(QListWidgetItem *item); void slotStartRename(QListWidgetItem *item); void slotInstallEntries(); void slotUploadEntry(); public: void loadProfiles(); void loadQuotesList(const bool updateResetList = false); void clearIcons(); void setupIcons(const AlkOnlineQuote::Errors &errors); QString singleSymbol() const; QStringList doubleSymbol() const; QString expandedUrl() const; }; AlkOnlineQuotesWidget::Private::Private(QWidget *parent) : m_webView(nullptr) , m_quoteInEditing(false) , m_profile(nullptr) { setupUi(parent); loadProfiles(); // TODO move to ui file KGuiItem updateButtenItem(i18nc("Accepts the entered data and stores it", "&Accept"), KIcon("dialog-ok"), i18n("Accepts the entered data and stores it"), i18n("Use this to accept the modified data.")); m_updateButton->setGuiItem(updateButtenItem); KGuiItem deleteButtenItem(i18n("&Delete"), KIcon("edit-delete"), i18n("Delete the selected source entry"), i18n("Use this to delete the selected online source entry")); m_deleteButton->setGuiItem(deleteButtenItem); KGuiItem checkButtonItem(i18nc("Check the selected source entry", "&Check Source"), KIcon("document-edit-verify"), i18n("Check the selected source entry"), i18n("Use this to check the selected online source entry")); m_checkButton->setGuiItem(checkButtonItem); KGuiItem showButtonItem(i18nc("Show the selected source entry in a web browser", "&Show page"), KIcon("applications-internet"), i18n("Show the selected source entry in a web browser"), i18n("Use this to show the selected online source entry")); m_showButton->setGuiItem(showButtonItem); KGuiItem newButtenItem(i18nc("Create a new source entry for online quotes", "&New..."), KIcon("document-new"), i18n("Create a new source entry for online quotes"), i18n("Use this to create a new entry for online quotes")); m_newButton->setGuiItem(newButtenItem); connect(m_newProfile, SIGNAL(clicked()), this, SLOT(slotNewProfile())); connect(m_deleteProfile, SIGNAL(clicked()), this, SLOT(slotDeleteProfile())); connect(m_profileList, SIGNAL(itemSelectionChanged()), this, SLOT(slotLoadProfile())); connect(m_updateButton, SIGNAL(clicked()), this, SLOT(slotUpdateEntry())); connect(m_newButton, SIGNAL(clicked()), this, SLOT(slotNewEntry())); connect(m_checkButton, SIGNAL(clicked()), this, SLOT(slotCheckEntry())); connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(slotDeleteEntry())); connect(m_installButton, SIGNAL(clicked()), this, SLOT(slotInstallEntries())); connect(m_uploadButton, SIGNAL(clicked()), this, SLOT(slotUploadEntry())); connect(m_quoteSourceList, SIGNAL(itemSelectionChanged()), this, SLOT(slotLoadWidgets())); connect(m_quoteSourceList, SIGNAL(itemChanged(QListWidgetItem *)), this, SLOT(slotEntryRenamed(QListWidgetItem *))); connect(m_quoteSourceList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(slotStartRename(QListWidgetItem *))); connect(m_editURL, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged())); connect(m_editSymbol, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged())); connect(m_editDate, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged())); connect(m_editDateFormat, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged())); connect(m_editPrice, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged())); connect(m_skipStripping, SIGNAL(toggled(bool)), this, SLOT(slotEntryChanged())); + connect(m_ghnsSource, SIGNAL(toggled(bool)), this, SLOT(slotEntryChanged())); m_checkSymbol->setText("ORCL"); m_checkSymbol2->setText("BTC GBP"); m_updateButton->setEnabled(false); m_showButton->setVisible(false); slotLoadProfile(); } void AlkOnlineQuotesWidget::Private::loadProfiles() { AlkOnlineQuotesProfileList list = AlkOnlineQuotesProfileManager::instance().profiles(); foreach (AlkOnlineQuotesProfile *profile, list) { QListWidgetItem *item = new QListWidgetItem(dynamic_cast(m_profileList)); item->setText(profile->name()); item->setFlags(item->flags() | Qt::ItemIsEditable); } m_profileList->setCurrentRow(0); m_profile = AlkOnlineQuotesProfileManager::instance().profiles().first(); loadQuotesList(); } void AlkOnlineQuotesWidget::Private::loadQuotesList(const bool updateResetList) { //disconnect the slot while items are being loaded and reconnect at the end disconnect(m_quoteSourceList, SIGNAL(itemChanged(QListWidgetItem *)), this, SLOT(slotEntryRenamed(QListWidgetItem *))); m_quoteInEditing = false; QStringList groups = m_profile->quoteSources(); if (updateResetList) { m_resetList.clear(); } m_quoteSourceList->clear(); QStringList::Iterator it; for (it = groups.begin(); it != groups.end(); ++it) { AlkOnlineQuoteSource source(*it, m_profile); if (!source.isValid()) { continue; } QListWidgetItem *item = new QListWidgetItem(*it); item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled); m_quoteSourceList->addItem(item); if (updateResetList) { m_resetList += source; } } m_quoteSourceList->sortItems(); QListWidgetItem *first = m_quoteSourceList->item(0); if (first) { m_quoteSourceList->setCurrentItem(first); } slotLoadWidgets(); m_newButton->setEnabled((m_quoteSourceList->findItems(i18n("New Quote Source"), Qt::MatchExactly)).count() == 0); connect(m_quoteSourceList, SIGNAL(itemChanged(QListWidgetItem *)), this, SLOT(slotEntryRenamed(QListWidgetItem *))); } void AlkOnlineQuotesWidget::Private::slotNewProfile() { QListWidgetItem *item = new QListWidgetItem(dynamic_cast(m_profileList)); item->setText(QLatin1String("new profile")); item->setFlags(item->flags() | Qt::ItemIsEditable); } void AlkOnlineQuotesWidget::Private::slotDeleteProfile() { delete m_profileList->currentItem(); } void AlkOnlineQuotesWidget::Private::slotSelectProfile() { slotLoadProfile(); } void AlkOnlineQuotesWidget::Private::slotLoadProfile() { AlkOnlineQuotesProfileList list = AlkOnlineQuotesProfileManager::instance().profiles(); foreach (AlkOnlineQuotesProfile *profile, list) { if (m_profileList->currentItem()->text() == profile->name()) { m_profile = profile; loadQuotesList(); m_installButton->setVisible(profile->type() == AlkOnlineQuotesProfile::Type::GHNS); } } } void AlkOnlineQuotesWidget::Private::slotLoadWidgets() { m_quoteInEditing = false; QListWidgetItem *item = m_quoteSourceList->currentItem(); m_editURL->setEnabled(true); m_editSymbol->setEnabled(true); m_editPrice->setEnabled(true); m_editDate->setEnabled(true); m_editDateFormat->setEnabled(true); m_skipStripping->setEnabled(true); + m_ghnsSource->setEnabled(true); m_editURL->setText(QString()); m_editSymbol->setText(QString()); m_editPrice->setText(QString()); m_editDate->setText(QString()); m_editDateFormat->setText(QString()); if (item) { m_currentItem = AlkOnlineQuoteSource(item->text(), m_profile); m_editURL->setText(m_currentItem.url()); m_editSymbol->setText(m_currentItem.sym()); m_editPrice->setText(m_currentItem.price()); m_editDate->setText(m_currentItem.date()); m_editDateFormat->setText(m_currentItem.dateformat()); m_skipStripping->setChecked(m_currentItem.skipStripping()); + m_ghnsSource->setChecked(m_currentItem.isGHNS()); } else { m_editURL->setEnabled(false); m_editSymbol->setEnabled(false); m_editPrice->setEnabled(false); m_editDate->setEnabled(false); m_editDateFormat->setEnabled(false); m_skipStripping->setEnabled(false); + m_ghnsSource->setEnabled(false); } m_updateButton->setEnabled(false); } void AlkOnlineQuotesWidget::Private::slotEntryChanged() { clearIcons(); bool modified = m_editURL->text() != m_currentItem.url() || m_editSymbol->text() != m_currentItem.sym() || m_editDate->text() != m_currentItem.date() || m_editDateFormat->text() != m_currentItem.dateformat() || m_editPrice->text() != m_currentItem.price() - || m_skipStripping->isChecked() != m_currentItem.skipStripping(); + || m_skipStripping->isChecked() != m_currentItem.skipStripping() + || m_ghnsSource->isChecked() != m_currentItem.isGHNS(); m_updateButton->setEnabled(modified); m_checkButton->setEnabled(!modified); m_checkSymbol->setEnabled(!m_currentItem.url().contains("%2")); m_checkSymbol2->setEnabled(m_currentItem.url().contains("%2")); } void AlkOnlineQuotesWidget::Private::slotDeleteEntry() { QList items = m_quoteSourceList->findItems( m_currentItem.name(), Qt::MatchExactly); if (items.size() == 0) { return; } QListWidgetItem *item = items.at(0); if (!item) { return; } int ret = KMessageBox::warningContinueCancel(this, i18n("Are you sure to delete this online quote ?"), i18n("Delete online quote"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QString("DeletingOnlineQuote")); if (ret == KMessageBox::Cancel) { return; } // keep this order to avoid deleting the wrong current item m_currentItem.remove(); delete item; slotEntryChanged(); } void AlkOnlineQuotesWidget::Private::slotUpdateEntry() { m_currentItem.setUrl(m_editURL->text()); m_currentItem.setSym(m_editSymbol->text()); m_currentItem.setDate(m_editDate->text()); m_currentItem.setDateformat(m_editDateFormat->text()); m_currentItem.setPrice(m_editPrice->text()); m_currentItem.setSkipStripping(m_skipStripping->isChecked()); + m_currentItem.setGHNS(m_ghnsSource->isChecked()); m_currentItem.write(); m_checkButton->setEnabled(true); slotEntryChanged(); } void AlkOnlineQuotesWidget::Private::slotNewEntry() { AlkOnlineQuoteSource newSource(i18n("New Quote Source"), m_profile); newSource.write(); loadQuotesList(); QListWidgetItem *item = m_quoteSourceList->findItems(i18n("New Quote Source"), Qt::MatchExactly).at(0); if (item) { m_quoteSourceList->setCurrentItem(item); slotLoadWidgets(); } } void AlkOnlineQuotesWidget::Private::clearIcons() { QPixmap emptyIcon; m_urlCheckLabel->setPixmap(emptyIcon); m_dateCheckLabel->setPixmap(emptyIcon); m_priceCheckLabel->setPixmap(emptyIcon); m_symbolCheckLabel->setPixmap(emptyIcon); m_dateFormatCheckLabel->setPixmap(emptyIcon); } void AlkOnlineQuotesWidget::Private::setupIcons(const AlkOnlineQuote::Errors &errors) { QPixmap okIcon(BarIcon("dialog-ok-apply")); QPixmap failIcon(BarIcon("dialog-cancel")); if (errors & AlkOnlineQuote::Errors::URL) { m_urlCheckLabel->setPixmap(failIcon); } else { m_urlCheckLabel->setPixmap(okIcon); m_symbolCheckLabel->setPixmap(errors & AlkOnlineQuote::Errors::Symbol ? failIcon : okIcon); m_priceCheckLabel->setPixmap(errors & AlkOnlineQuote::Errors::Price ? failIcon : okIcon); if (errors & AlkOnlineQuote::Errors::Date) { m_dateCheckLabel->setPixmap(failIcon); } else { m_dateCheckLabel->setPixmap(okIcon); m_dateFormatCheckLabel->setPixmap( errors & AlkOnlineQuote::Errors::DateFormat ? failIcon : okIcon); } } } void AlkOnlineQuotesWidget::Private::slotCheckEntry() { AlkOnlineQuote quote(m_profile); m_logWindow->setVisible(true); m_logWindow->clear(); clearIcons(); quote.setWebView(m_webView); quote.setAcceptLanguage(m_acceptLanguage); connect("e, SIGNAL(status(QString)), this, SLOT(slotLogStatus(QString))); connect("e, SIGNAL(error(QString)), this, SLOT(slotLogError(QString))); connect("e, SIGNAL(failed(QString,QString)), this, SLOT(slotLogFailed(QString,QString))); connect("e, SIGNAL(quote(QString,QString,QDate,double)), this, SLOT(slotLogQuote(QString,QString,QDate,double))); if (m_currentItem.url().contains("%2")) { quote.launch(m_checkSymbol2->text(), m_checkSymbol2->text(), m_currentItem.name()); } else { quote.launch(m_checkSymbol->text(), m_checkSymbol->text(), m_currentItem.name()); } setupIcons(quote.errors()); } void AlkOnlineQuotesWidget::Private::slotLogStatus(const QString &s) { m_logWindow->append(s); } void AlkOnlineQuotesWidget::Private::slotLogError(const QString &s) { slotLogStatus(QString("") + s + QString("")); } void AlkOnlineQuotesWidget::Private::slotLogFailed(const QString &id, const QString &symbol) { slotLogStatus(QString("%1 %2").arg(id, symbol)); } void AlkOnlineQuotesWidget::Private::slotLogQuote(const QString &id, const QString &symbol, const QDate &date, double price) { slotLogStatus(QString("%1 %2 %3 %4").arg(id, symbol, date.toString()).arg( price)); } void AlkOnlineQuotesWidget::Private::slotStartRename(QListWidgetItem *item) { m_quoteInEditing = true; m_quoteSourceList->editItem(item); } void AlkOnlineQuotesWidget::Private::slotEntryRenamed(QListWidgetItem *item) { //if there is no current item selected, exit if (m_quoteInEditing == false || !m_quoteSourceList->currentItem() || item != m_quoteSourceList->currentItem()) { return; } m_quoteInEditing = false; QString text = item->text(); int nameCount = 0; for (int i = 0; i < m_quoteSourceList->count(); ++i) { if (m_quoteSourceList->item(i)->text() == text) { ++nameCount; } } // Make sure we get a non-empty and unique name if (text.length() > 0 && nameCount == 1) { m_currentItem.rename(text); } else { item->setText(m_currentItem.name()); } m_quoteSourceList->sortItems(); m_newButton->setEnabled(m_quoteSourceList->findItems(i18n( "New Quote Source"), Qt::MatchExactly).count() == 0); } void AlkOnlineQuotesWidget::Private::slotInstallEntries() { QString configFile = m_profile->hotNewStuffConfigFile(); QPointer dialog = new KNS3::DownloadDialog(configFile, this); dialog->exec(); delete dialog; loadQuotesList(); } void AlkOnlineQuotesWidget::Private::slotUploadEntry() { QString configFile = m_profile->hotNewStuffConfigFile(); - QUrl url = QUrl::fromLocalFile(m_profile->hotNewStuffWriteFilePath(m_currentItem.name())); + QUrl url = QUrl::fromLocalFile(m_currentItem.ghnsWriteFileName()); qDebug() << "uploading file" << url; QPointer dialog = new KNS3::UploadDialog(configFile, this); dialog->setUploadName(m_currentItem.name()); dialog->setUploadFile(url); dialog->exec(); delete dialog; } QString AlkOnlineQuotesWidget::Private::expandedUrl() const { if (m_currentItem.url().contains("%2")) { return m_currentItem.url().arg(m_checkSymbol2->text()); } else { return m_currentItem.url().arg(m_checkSymbol->text()); } } AlkOnlineQuotesWidget::AlkOnlineQuotesWidget(QWidget *parent) : QWidget(parent) , d(new Private(this)) { } AlkOnlineQuotesWidget::~AlkOnlineQuotesWidget() { delete d; } void AlkOnlineQuotesWidget::readConfig() { } void AlkOnlineQuotesWidget::writeConfig() { } void AlkOnlineQuotesWidget::resetConfig() { QStringList::ConstIterator it; QStringList groups = d->m_profile->quoteSources(); // delete all currently defined entries for (it = groups.constBegin(); it != groups.constEnd(); ++it) { AlkOnlineQuoteSource(*it, d->m_profile).remove(); } // and write back the one's from the reset list QList::iterator itr; for (itr = d->m_resetList.begin(); itr != d->m_resetList.end(); ++itr) { (*itr).write(); } d->loadQuotesList(); } void AlkOnlineQuotesWidget::setView(QWebView *view) { d->m_webView = view; } QString AlkOnlineQuotesWidget::acceptLanguage() const { return d->m_acceptLanguage; } void AlkOnlineQuotesWidget::setAcceptLanguage(const QString &text) { d->m_acceptLanguage = text; } #include "alkonlinequoteswidget.moc" diff --git a/src/alkonlinequoteswidget.ui b/src/alkonlinequoteswidget.ui index a06b886..fca6141 100644 --- a/src/alkonlinequoteswidget.ui +++ b/src/alkonlinequoteswidget.ui @@ -1,467 +1,484 @@ AlkOnlineQuotesWidget 0 0 523 815 0 0 Online Quotes <html><head/><body><p>Select, add or delete an application profile, where where to load profiles from and save into eg. kmymoney or skrooge.</p></body></html> Application Profiles Qt::AlignCenter false New false Delete Qt::Vertical 20 40 <html><head/><body><p>online price quotes</p></body></html> Online Quotes Qt::AlignCenter 0 0 16777215 120 New Delete Install Upload Qt::Vertical 20 40 <html><head/><body><p><span style=" font-style:italic;">Enter regular expressions which can be used to parse the data returned from the URL entered above. The symbol, price, and date must be found in the quote data to be usable. You may also try the KMyMoney forum at </span><a href="https://forum.kde.org/viewforum.php?f=69"><span style=" text-decoration: underline; color:#2980b9;">https://forum.kde.org/viewforum.php?f=69</span></a> or the <span style=" font-style:italic;">user's mailinglist at </span><a href="mailto:kmymoney@kde.org"><span style=" font-style:italic; text-decoration: underline; color:#2980b9;">kmymoney@kde.org</span></a><span style=" font-style:italic;"> to find what settings work for other users in your country.</span></p></body></html> Details Qt::AlignCenter - - - - Regular Expression to extract the price from the downloaded data - - - - - - - Price - - - false - - - Regular Expression to extract the date from the downloaded data Date Format false - - + + - Symbol - - - false + Regular Expression to extract the symbol from the downloaded data - - + + - + Date + + + false - + <p>For easier processing of the data returned by the online source, KMyMoney usually strips unused parts before it is parsed with the regular expressions. If matching of the fields relies on those items, then use this option to turn stripping off.</p> <p>The following items are usually removed by stripping: <ul> <li>HTML tags such as <b>&lt;tag&gt;</b></li> <li>& encoded characters such as <b>&amp;nbsp;</b></li> <li>duplicate whitespace</li> </ul> </p> Skip HTML stripping - - + + - - + + + + + + URL + + + false + + + + + + + Regular Expression to extract the price from the downloaded data + + + + + + + Options + + + + + + + + + + GHNS Source + + + - - + + - - - - URL to be used to download the quote + + + + Price - - Enter the URL from which stock quotes will be fetched. <b>%1</b> will be replaced with the symbol for the security being quoted. For currency conversions, <b>%2</b> will be replaced with the currency to be quoted and <b>%1</b> with the currency the quote is based on. + + false - - + + - URL + Symbol false Regular Expression to extract the date from the downloaded data - - - - Date + + + + URL to be used to download the quote - - false + + Enter the URL from which stock quotes will be fetched. <b>%1</b> will be replaced with the symbol for the security being quoted. For currency conversions, <b>%2</b> will be replaced with the currency to be quoted and <b>%1</b> with the currency the quote is based on. 0 Accept Qt::Vertical 20 40 Debugging Qt::AlignCenter One Symbol Two Symbols Check Source Show Page Qt::Vertical 20 40 KListWidget QListWidget
klistwidget.h
KPushButton QPushButton
kpushbutton.h
KTextEdit QTextEdit
ktextedit.h
KLineEdit QLineEdit
klineedit.h
diff --git a/src/alkimia-skrooge.knsrc b/src/kmymoney-quotes.knsrc similarity index 82% copy from src/alkimia-skrooge.knsrc copy to src/kmymoney-quotes.knsrc index 6672d90..4ae3c08 100644 --- a/src/alkimia-skrooge.knsrc +++ b/src/kmymoney-quotes.knsrc @@ -1,5 +1,5 @@ [KNewStuff3] ProvidersUrl=http://download.kde.org/ocs/providers.xml Categories=Skrooge quote source -TargetDir=skrooge/quotes +TargetDir=kmymoney/quotes Uncompress=archive diff --git a/src/alkimia-skrooge.knsrc b/src/skrooge-quotes.knsrc similarity index 100% rename from src/alkimia-skrooge.knsrc rename to src/skrooge-quotes.knsrc diff --git a/tools/onlinequoteseditor/mainwindow.cpp b/tools/onlinequoteseditor/mainwindow.cpp index e8134d6..1769042 100644 --- a/tools/onlinequoteseditor/mainwindow.cpp +++ b/tools/onlinequoteseditor/mainwindow.cpp @@ -1,140 +1,138 @@ /*************************************************************************** * Copyright 2018 Ralf Habacker * * * * This file is part of libalkimia. * * * * libalkimia 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.1 of * * the License or (at your option) version 3 or any later version. * * * * libalkimia 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 * ***************************************************************************/ #include "mainwindow.h" #include "ui_mainwindow.h" #include "alkonlinequotesprofile.h" #include "alkonlinequotesprofilemanager.h" #include "alkonlinequoteswidget.h" #include #include #include #include #include class MainWindow::Private { public: Private() : view(nullptr) , urlLine(nullptr) , quotesWidget(nullptr) { } ~Private() { delete view; delete quotesWidget; } QWebView *view; QLineEdit *urlLine; AlkOnlineQuotesWidget *quotesWidget; }; void MainWindow::slotUrlChanged(const QUrl &url) { d->urlLine->setText(url.toString()); } void MainWindow::slotEditingFinished() { QUrl url(d->urlLine->text()); QNetworkRequest request; request.setUrl(url); if (!d->quotesWidget->acceptLanguage().isEmpty()) request.setRawHeader("Accept-Language", d->quotesWidget->acceptLanguage().toLocal8Bit()); d->view->load(request); } void MainWindow::slotLanguageChanged(const QString &text) { d->quotesWidget->setAcceptLanguage(text); if (!d->urlLine->text().isEmpty()) slotEditingFinished(); } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , d(new Private) , ui(new Ui::MainWindow) { AlkOnlineQuotesProfileManager &manager = AlkOnlineQuotesProfileManager::instance(); - manager.addProfile(new AlkOnlineQuotesProfile("alkimia", - AlkOnlineQuotesProfile::Type::KMyMoney)); - //manager.addProfile(new AlkOnlineQuotesProfile("onlinequoteseditor", AlkOnlineQuotesProfile::Type::GHNS, "alkimia-skrooge.knsrc")); - //manager.addProfile(new AlkOnlineQuotesProfile("local", AlkOnlineQuotesProfile::Type::GHNS, "alkimia-skrooge-local.knsrc")); - manager.addProfile(new AlkOnlineQuotesProfile("skrooge", AlkOnlineQuotesProfile::Type::GHNS, "alkimia-skrooge.knsrc")); - manager.addProfile(new AlkOnlineQuotesProfile("kmymoney", AlkOnlineQuotesProfile::Type::KMyMoney)); + manager.addProfile(new AlkOnlineQuotesProfile("alkimia", AlkOnlineQuotesProfile::Type::KMyMoney, "alkimia-quotes.knsrc")); + //manager.addProfile(new AlkOnlineQuotesProfile("local", AlkOnlineQuotesProfile::Type::GHNS, "alkimia-quotes-local.knsrc")); + manager.addProfile(new AlkOnlineQuotesProfile("skrooge", AlkOnlineQuotesProfile::Type::GHNS, "skrooge-quotes.knsrc")); + manager.addProfile(new AlkOnlineQuotesProfile("kmymoney", AlkOnlineQuotesProfile::Type::KMyMoney, "kmymoney-quotes.knsrc")); ui->setupUi(this); QDockWidget *dockWidget = new QDockWidget(tr("Browser"), this); d->view = new QWebView; connect(d->view, SIGNAL(urlChanged(QUrl)), this, SLOT(slotUrlChanged(QUrl))); d->urlLine = new QLineEdit; connect(d->urlLine, SIGNAL(editingFinished()), this, SLOT(slotEditingFinished())); d->quotesWidget = new AlkOnlineQuotesWidget; d->quotesWidget->setView(d->view); setCentralWidget(d->quotesWidget); // setup language box QComboBox *box = new QComboBox; QList allLocales = QLocale::matchingLocales( QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry); QStringList languages; foreach(const QLocale &locale, allLocales) { languages.append(locale.uiLanguages()); } languages.sort(); box->addItems(languages); d->quotesWidget->setAcceptLanguage(box->currentText()); connect(box, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotLanguageChanged(QString))); // setup layouts QHBoxLayout *hLayout = new QHBoxLayout; hLayout->addWidget(d->urlLine); hLayout->addWidget(box); QVBoxLayout *layout = new QVBoxLayout; layout->addLayout(hLayout); layout->addWidget(d->view); QWidget *group = new QWidget; group->setLayout(layout); dockWidget->setWidget(group); addDockWidget(Qt::RightDockWidgetArea, dockWidget); // setup inspector d->view->page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); QWebInspector *inspector = new QWebInspector; inspector->setPage(d->view->page()); } MainWindow::~MainWindow() { delete d; delete ui; }