31 #include <QApplication>
36 #include <QTextStream>
39 #include <KConfigGroup>
41 #include <KEncodingProber>
43 #include <kio/netaccess.h>
44 #include <kio/scheduler.h>
66 if (!m_type.contains(t)) {
74 return m_type.contains(t);
99 static int s_area = KDebug::registerArea(
"Alkimia (AlkOnlineQuote)");
117 bool initLaunch(
const QString &_symbol,
const QString &_id,
const QString &_source);
119 const QString &_source);
121 bool launchNative(
const QString &_symbol,
const QString &_id,
const QString &_source);
122 bool launchFinanceQuote(
const QString &_symbol,
const QString &_id,
const QString &_source);
140 emit m_p->status(QString(
"(Debug) symbol=%1 id=%2...").arg(_symbol, _id));
143 QString source = _source;
144 if (source.isEmpty()) {
145 source =
"KMyMoney Currency";
148 if (!m_profile->quoteSources().contains(source)) {
149 emit m_p->error(i18n(
"Source <placeholder>%1</placeholder> does not exist.", source));
160 if (m_source.url().contains(
"%2")) {
163 QRegExp splitrx(
"([0-9a-z\\.]+)[^a-z0-9]+([0-9a-z\\.]+)", Qt::CaseInsensitive);
165 if (splitrx.indexIn(m_symbol) != -1) {
166 url = KUrl(m_source.url().arg(splitrx.cap(1), splitrx.cap(2)));
168 kDebug(
Private::dbgArea()) <<
"WebPriceQuote::launch() did not find 2 symbols";
172 url = KUrl(m_source.url().arg(m_symbol));
183 emit m_p->error(i18n(
"Unable to fetch url for %1").arg(m_symbol));
185 emit m_p->failed(m_id, m_symbol);
197 emit m_p->error(i18n(
"Unable to fetch url for %1").arg(m_symbol));
199 emit m_p->failed(m_id, m_symbol);
204 if (!symbol.isEmpty()) {
205 emit m_p->status(i18n(
"Symbol found: '%1'", symbol));
208 emit m_p->error(i18n(
"Unable to parse symbol for %1", m_symbol));
213 bool gotprice = parsePrice(price);
217 bool gotdate = parseDate(date);
219 if (gotprice && gotdate) {
220 emit m_p->quote(m_id, m_symbol, m_date, m_price);
222 emit m_p->failed(m_id, m_symbol);
231 emit m_p->status(i18n(
"Fetching URL %1...", m_url.prettyUrl()));
235 const QString &_source)
237 if (!initLaunch(_symbol, _id, _source)) {
241 connect(webPage, SIGNAL(loadStarted()),
this, SLOT(slotLoadStarted()));
242 connect(webPage, SIGNAL(loadFinished(
bool)),
this,
243 SLOT(slotLoadFinishedCssSelector(
bool)));
245 m_eventLoop =
new QEventLoop;
248 disconnect(webPage, SIGNAL(loadStarted()),
this, SLOT(slotLoadStarted()));
249 disconnect(webPage, SIGNAL(loadFinished(
bool)),
this,
250 SLOT(slotLoadFinishedCssSelector(
bool)));
257 const QString &_source)
259 if (!initLaunch(_symbol, _id, _source)) {
263 connect(webPage, SIGNAL(loadStarted()),
this, SLOT(slotLoadStarted()));
264 connect(webPage, SIGNAL(loadFinished(
bool)),
this, SLOT(slotLoadFinishedHtmlParser(
bool)));
265 webPage->
load(m_url, m_acceptLanguage);
266 m_eventLoop =
new QEventLoop;
269 disconnect(webPage, SIGNAL(loadStarted()),
this, SLOT(slotLoadStarted()));
270 disconnect(webPage, SIGNAL(loadFinished(
bool)),
this, SLOT(slotLoadFinishedHtmlParser(
bool)));
277 const QString &_source)
280 if (!initLaunch(_symbol, _id, _source)) {
285 if (url.isLocalFile()) {
286 emit m_p->status(i18nc(
"The process x is executing",
"Executing %1...", url.toLocalFile()));
288 m_filter.clearProgram();
289 m_filter << url.toLocalFile().split(
' ', QString::SkipEmptyParts);
290 m_filter.setSymbol(m_symbol);
292 m_filter.setOutputChannelMode(KProcess::MergedChannels);
295 if (m_filter.waitForStarted()) {
298 emit m_p->error(i18n(
"Unable to launch: %1", url.toLocalFile()));
300 result = slotParseQuote(QString());
306 if (KIO::NetAccess::download(url, tmpFile, 0)) {
310 if (f.open(QIODevice::ReadOnly)) {
312 QByteArray page = f.readAll();
313 KEncodingProber prober(KEncodingProber::Universal);
315 QTextCodec *codec = QTextCodec::codecForName(prober.encoding());
317 codec = QTextCodec::codecForLocale();
319 QString
quote = codec->toUnicode(page);
321 emit m_p->status(i18n(
"URL found: %1...", url.prettyUrl()));
324 result = slotParseQuote(
quote);
326 emit m_p->error(i18n(
"Failed to open downloaded file"));
328 result = slotParseQuote(QString());
330 KIO::NetAccess::removeTempFile(tmpFile);
332 emit m_p->error(KIO::NetAccess::lastErrorString());
334 result = slotParseQuote(QString());
341 const QString &_sourcename)
349 "[^,]*,[^,]*,\"([^\"]*)\"",
356 tmp.
crypticName(_sourcename) : _sourcename.section(
' ', 1);
359 args <<
"perl" << m_profile->scriptPath() << fQSource << m_symbol;
360 m_filter.clearProgram();
362 emit m_p->status(i18nc(
"Executing 'script' 'online source' 'investment symbol' ",
363 "Executing %1 %2 %3...", args.join(
" "), QString(), QString()));
365 m_filter.setOutputChannelMode(KProcess::MergedChannels);
369 if (m_filter.waitForFinished()) {
371 emit m_p->error(i18n(
"Unable to launch: %1", m_profile->scriptPath()));
373 result = slotParseQuote(QString());
388 QString pricestr(_pricestr);
389 if (!pricestr.isEmpty()) {
390 int pos = pricestr.lastIndexOf(QRegExp(
"\\D"));
393 pos = pricestr.lastIndexOf(QRegExp(
"\\D"), pos - 1);
396 pricestr.remove(pos, 1);
397 pos = pricestr.lastIndexOf(QRegExp(
"\\D"), pos);
400 m_price = pricestr.toDouble();
402 emit m_p->status(i18n(
"Price found: '%1' (%2)", pricestr, m_price));
405 emit m_p->error(i18n(
"Unable to parse price for '%1'", m_symbol));
413 if (!datestr.isEmpty()) {
414 emit m_p->status(i18n(
"Date found: '%1'", datestr));
420 emit m_p->status(i18n(
"Date format found: '%1' -> '%2'", datestr, m_date.toString()));
423 emit m_p->error(i18n(
"Unable to parse date '%1' using format '%2': %3").arg(datestr,
426 m_date = QDate::currentDate();
427 emit m_p->status(i18n(
"Using current date for '%1'").arg(m_symbol));
431 emit m_p->error(i18n(
"Unable to parse date for '%1'").arg(m_symbol));
432 m_date = QDate::currentDate();
433 emit m_p->status(i18n(
"Using current date for '%1'").arg(m_symbol));
447 QString quotedata = _quotedata;
448 m_quoteData = quotedata;
449 bool gotprice =
false;
450 bool gotdate =
false;
455 if (!quotedata.isEmpty()) {
456 if (!m_source.skipStripping()) {
462 quotedata.remove(QRegExp(
"<[^>]*>"));
465 quotedata.replace(QRegExp(
"&\\w+;"),
" ");
468 quotedata = quotedata.simplified();
472 QRegExp symbolRegExp(m_source.sym());
473 QRegExp dateRegExp(m_source.date());
474 QRegExp priceRegExp(m_source.price());
476 if (symbolRegExp.indexIn(quotedata) > -1) {
478 emit m_p->status(i18n(
"Symbol found: '%1'", symbolRegExp.cap(1)));
481 emit m_p->error(i18n(
"Unable to parse symbol for %1", m_symbol));
484 if (priceRegExp.indexIn(quotedata) > -1) {
486 QString pricestr = priceRegExp.cap(1);
487 parsePrice(pricestr);
489 parsePrice(QString());
492 if (dateRegExp.indexIn(quotedata) > -1) {
494 QString datestr = dateRegExp.cap(1);
497 parseDate(QString());
500 if (gotprice && gotdate) {
501 emit m_p->quote(m_id, m_symbol, m_date, m_price);
503 emit m_p->failed(m_id, m_symbol);
508 emit m_p->error(i18n(
"Unable to update price for %1 (empty quote data)", m_symbol));
509 emit m_p->failed(m_id, m_symbol);
566 }
else if (_source.endsWith(
".css")) {
568 }
else if (_source.endsWith(
".webkit")) {
580 #include "alkonlinequote.moc"
const QString & what() const
const QString crypticName(const QString &niceName) const
bool isFinanceQuote() const
bool operator&(Type t) const
Errors & operator|=(Type t)
AlkOnlineQuoteProcess m_filter
bool launchWebKitHtmlParser(const QString &_symbol, const QString &_id, const QString &_source)
AlkOnlineQuotesProfile * m_profile
bool parseDate(const QString &datestr)
bool launchNative(const QString &_symbol, const QString &_id, const QString &_source)
bool initLaunch(const QString &_symbol, const QString &_id, const QString &_source)
bool parsePrice(const QString &pricestr)
AlkOnlineQuote::Errors m_errors
bool launchWebKitCssSelector(const QString &_symbol, const QString &_id, const QString &_source)
void slotLoadFinishedCssSelector(bool ok)
Private(AlkOnlineQuote *parent)
bool launchFinanceQuote(const QString &_symbol, const QString &_id, const QString &_source)
void slotLoadFinishedHtmlParser(bool ok)
bool slotParseQuote(const QString &_quotedata)
AlkOnlineQuoteSource m_source
void quote(QString id, QString symbol, QDate date, double price)
AlkOnlineQuote(AlkOnlineQuotesProfile *profile=0, QObject *=0)
void setAcceptLanguage(const QString &language)
void setProfile(AlkOnlineQuotesProfile *profile)
AlkOnlineQuotesProfile * profile()
bool launch(const QString &_symbol, const QString &_id, const QString &_source=QString())
static AlkOnlineQuotesProfileManager & instance()
void load(const QUrl &url, const QString &acceptLanguage)
void setContent(const QString &s)
void setUrl(const QUrl &url)
QString getFirstElement(const QString &symbol)