File indexing completed on 2024-07-14 04:55:01

0001 /*
0002  * SPDX-FileCopyrightText: 2018 Ralf Habacker ralf.habacker@freenet.de
0003  * SPDX-FileCopyrightText: 2023 Thomas Baumgart <tbaumgart@kde.org>
0004  * SPDX-License-Identifier: LGPL-2.1-or-later
0005  *
0006  * This file is part of libalkimia.
0007  */
0008 
0009 #include "alkonlinequotesource.h"
0010 
0011 #include "alkonlinequotesprofile.h"
0012 
0013 #include "alkonlinequotesource_p.h"
0014 
0015 /**
0016  * Key to identifying "Finance::Quote" sources
0017  */
0018 static const char *fqName = "Finance::Quote";
0019 
0020 AlkOnlineQuoteSource::AlkOnlineQuoteSource()
0021     : d(new Private)
0022 {
0023 }
0024 
0025 AlkOnlineQuoteSource::AlkOnlineQuoteSource(const AlkOnlineQuoteSource &other)
0026     : d(new Private(other.d))
0027 {
0028 }
0029 
0030 AlkOnlineQuoteSource &AlkOnlineQuoteSource::operator=(AlkOnlineQuoteSource other)
0031 {
0032     swap(*this, other);
0033     return *this;
0034 }
0035 
0036 AlkOnlineQuoteSource::AlkOnlineQuoteSource(const QString& name,
0037                                            const QString& url,
0038                                            const QString& idRegex,
0039                                            const IdSelector idBy,
0040                                            const QString& priceRegex,
0041                                            const QString& dateRegex,
0042                                            const QString& dateFormat,
0043                                            DataFormat dataFormat)
0044     : d(new Private)
0045 {
0046     d->m_name = name;
0047     d->m_url = url;
0048     d->m_idRegex = idRegex;
0049     d->m_idSelector = idBy;
0050     d->m_priceRegex = priceRegex;
0051     d->m_dataFormat = dataFormat;
0052     d->m_dateRegex = dateRegex;
0053     d->m_dateFormat = dateFormat;
0054     d->m_isGHNSSource = false;
0055 }
0056 
0057 AlkOnlineQuoteSource::AlkOnlineQuoteSource(const QString &name, AlkOnlineQuotesProfile *profile)
0058     : d(new Private)
0059 {
0060     if ((profile != nullptr) && (profile->type() == AlkOnlineQuotesProfile::Type::None) && (profile->defaultQuoteSources().contains(name))) {
0061         *this = profile->defaultQuoteSources()[name];
0062     } else {
0063         d->m_profile = profile;
0064         d->m_name = name;
0065         read();
0066     }
0067 }
0068 
0069 AlkOnlineQuoteSource AlkOnlineQuoteSource::defaultCurrencyQuoteSource(const QString& name)
0070 {
0071     return AlkOnlineQuoteSource(name,
0072                                 "https://fx-rate.net/%1/%2",
0073                                 QString(), // idregexp
0074                                 AlkOnlineQuoteSource::Symbol,
0075                                 "Today\\s+=\\s+([^<]+)",
0076                                 ",\\s*(\\d+\\s*[a-zA-Z]{3}\\s*\\d{4})",
0077                                 "%d %m %y",
0078                                 HTML
0079     );
0080 }
0081 
0082 AlkOnlineQuoteSource::~AlkOnlineQuoteSource()
0083 {
0084     delete d;
0085 }
0086 
0087 bool AlkOnlineQuoteSource::isEmpty()
0088 {
0089     return !isValid()  && !d->m_url.isEmpty();
0090 }
0091 
0092 bool AlkOnlineQuoteSource::isValid()
0093 {
0094     return !d->m_name.isEmpty();
0095 }
0096 
0097 QString AlkOnlineQuoteSource::name() const
0098 {
0099     return d->m_name;
0100 }
0101 
0102 QString AlkOnlineQuoteSource::url() const
0103 {
0104     return d->m_url;
0105 }
0106 
0107 QString AlkOnlineQuoteSource::idRegex() const
0108 {
0109     return d->m_idRegex;
0110 }
0111 
0112 AlkOnlineQuoteSource::IdSelector AlkOnlineQuoteSource::idSelector() const
0113 {
0114     return d->m_idSelector;
0115 }
0116 
0117 QString AlkOnlineQuoteSource::priceRegex() const
0118 {
0119     return d->m_priceRegex;
0120 }
0121 
0122 QString AlkOnlineQuoteSource::dateRegex() const
0123 {
0124     return d->m_dateRegex;
0125 }
0126 
0127 AlkOnlineQuoteSource::DataFormat AlkOnlineQuoteSource::dataFormat() const
0128 {
0129     return d->m_dataFormat;
0130 }
0131 
0132 QString AlkOnlineQuoteSource::dateFormat() const
0133 {
0134     return d->m_dateFormat;
0135 }
0136 
0137 /**
0138  * Returns the name of the "Finance::Quote" source.
0139  * This function only makes sense if the current source
0140  * is of the specified type.
0141  *
0142  * @return "Finance::Quote" source name
0143  */
0144 QString AlkOnlineQuoteSource::financeQuoteName() const
0145 {
0146     return d->m_name.section(' ', 1);
0147 }
0148 
0149 void AlkOnlineQuoteSource::setName(const QString &name)
0150 {
0151     d->m_name = name;
0152 }
0153 
0154 void AlkOnlineQuoteSource::setUrl(const QString &url)
0155 {
0156     d->m_url = url;
0157 }
0158 
0159 void AlkOnlineQuoteSource::setPriceRegex(const QString &priceRegex)
0160 {
0161     d->m_priceRegex = priceRegex;
0162 }
0163 
0164 void AlkOnlineQuoteSource::setIdRegex(const QString &idRegex)
0165 {
0166     d->m_idRegex = idRegex;
0167 }
0168 
0169 void AlkOnlineQuoteSource::setIdSelector(AlkOnlineQuoteSource::IdSelector idSelector)
0170 {
0171     d->m_idSelector = idSelector;
0172 }
0173 
0174 /**
0175  * Set regular expression for parsing dates
0176  *
0177  * An empty string as expression disables the extraction
0178  * of the date, which is sometimes necessary, for example
0179  * if the service does not provide a complete date.
0180  *
0181  * @param date regular expression
0182  */
0183 void AlkOnlineQuoteSource::setDateRegex(const QString &dateRegex)
0184 {
0185     d->m_dateRegex = dateRegex;
0186 }
0187 
0188 void AlkOnlineQuoteSource::setDataFormat(DataFormat dataFormat)
0189 {
0190     d->m_dataFormat = dataFormat;
0191 }
0192 
0193 void AlkOnlineQuoteSource::setDateFormat(const QString &dateFormat)
0194 {
0195     d->m_dateFormat = dateFormat;
0196 }
0197 
0198 void AlkOnlineQuoteSource::setGHNS(bool state)
0199 {
0200     d->m_storageChanged = d->m_isGHNSSource != state;
0201     d->m_isGHNSSource = state;
0202 }
0203 
0204 bool AlkOnlineQuoteSource::isGHNS() const
0205 {
0206     return d->m_isGHNSSource;
0207 }
0208 
0209 bool AlkOnlineQuoteSource::isReadOnly() const
0210 {
0211     return d->m_readOnly;
0212 }
0213 
0214 /**
0215  * Checks whether the current source is of type "Finance::Quote"
0216  *
0217  * @return state
0218  */
0219 bool AlkOnlineQuoteSource::isFinanceQuote() const
0220 {
0221     return d->m_name.contains(fqName);
0222 }
0223 
0224 /**
0225  * Checks whether the specified source name is of type "Finance::Quote"
0226  *
0227  * @return state
0228  */
0229 bool AlkOnlineQuoteSource::isFinanceQuote(const QString &name)
0230 {
0231     return name.contains(fqName);
0232 }
0233 
0234 QString AlkOnlineQuoteSource::ghnsWriteFileName() const
0235 {
0236     return d->ghnsWriteFilePath();
0237 }
0238 
0239 void AlkOnlineQuoteSource::setProfile(AlkOnlineQuotesProfile *profile)
0240 {
0241     d->m_profile = profile;
0242     qDebug() << "using profile" << profile->name();
0243 }
0244 
0245 AlkOnlineQuotesProfile *AlkOnlineQuoteSource::profile()
0246 {
0247     return d->m_profile;
0248 }
0249 
0250 AlkOnlineQuotesProfile *AlkOnlineQuoteSource::profile() const
0251 {
0252     return d->m_profile;
0253 }
0254 
0255 bool AlkOnlineQuoteSource::read()
0256 {
0257     if (d->m_profile->hasGHNSSupport()) {
0258         if (d->readFromGHNSFile()) {
0259             return true;
0260         }
0261     }
0262     return d->read();
0263 }
0264 
0265 bool AlkOnlineQuoteSource::write()
0266 {
0267     bool result = false;
0268     // check if type has been changedd->isGHNS
0269     if (d->m_profile->hasGHNSSupport() && d->m_isGHNSSource) {
0270         result = d->writeToGHNSFile();
0271         if (d->m_storageChanged)
0272             d->remove();
0273         return result;
0274     } else {
0275         if (d->m_storageChanged && d->m_profile->quoteSources().contains(d->m_name))
0276             d->m_name.append(".local");
0277         result = d->write();
0278         if (d->m_profile->hasGHNSSupport() && d->m_storageChanged) {
0279             d->removeGHNSFile();
0280         }
0281     }
0282     d->m_storageChanged = false;
0283     return result;
0284 }
0285 
0286 void AlkOnlineQuoteSource::rename(const QString &name)
0287 {
0288     if (d->m_profile->type() != AlkOnlineQuotesProfile::Type::None) {
0289         remove();
0290         d->m_name = name;
0291         write();
0292     } else
0293         d->m_name = name;
0294 }
0295 
0296 void AlkOnlineQuoteSource::remove()
0297 {
0298     if (d->m_profile->hasGHNSSupport() && d->m_isGHNSSource) {
0299         d->removeGHNSFile();
0300     } else if (d->m_profile->type() != AlkOnlineQuotesProfile::Type::None) {
0301         d->remove();
0302     }
0303 }
0304 
0305 const QString &AlkOnlineQuoteSource::defaultId() const
0306 {
0307     return d->m_defaultId;
0308 }
0309 
0310 void AlkOnlineQuoteSource::setDefaultId(const QString &defaultId)
0311 {
0312     d->m_defaultId = defaultId;
0313 }
0314 
0315 bool AlkOnlineQuoteSource::requiresTwoIdentifier() const
0316 {
0317     return url().contains("%2");
0318 }