diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | bcb704366cb5e333a626c18c308c7e0448a8e69f (patch) | |
tree | f0d6ab7d78ecdd9207cf46536376b44b91a1ca71 /knewsticker/common | |
download | tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.tar.gz tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdenetwork@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'knewsticker/common')
-rw-r--r-- | knewsticker/common/Makefile.am | 13 | ||||
-rw-r--r-- | knewsticker/common/configaccess.cpp | 674 | ||||
-rw-r--r-- | knewsticker/common/configaccess.h | 135 | ||||
-rw-r--r-- | knewsticker/common/configiface.h | 56 | ||||
-rw-r--r-- | knewsticker/common/newsengine.cpp | 324 | ||||
-rw-r--r-- | knewsticker/common/newsengine.h | 203 | ||||
-rw-r--r-- | knewsticker/common/newsiconmgr.cpp | 159 | ||||
-rw-r--r-- | knewsticker/common/newsiconmgr.h | 60 | ||||
-rw-r--r-- | knewsticker/common/xmlnewsaccess.cpp | 132 | ||||
-rw-r--r-- | knewsticker/common/xmlnewsaccess.h | 86 |
10 files changed, 1842 insertions, 0 deletions
diff --git a/knewsticker/common/Makefile.am b/knewsticker/common/Makefile.am new file mode 100644 index 00000000..60fddef7 --- /dev/null +++ b/knewsticker/common/Makefile.am @@ -0,0 +1,13 @@ +INCLUDES = $(all_includes) + +noinst_LTLIBRARIES = libknewstickercommon.la + +noinst_HEADERS = configiface.h configaccess.h newsiconmgr.h xmlnewsaccess.h \ + newsengine.h + +METASOURCES = AUTO + +libknewstickercommon_la_SOURCES = newsiconmgr.cpp xmlnewsaccess.cpp \ + configaccess.cpp newsiconmgr.skel newsengine.cpp +libknewstickercommon_la_LIBADD = $(LIB_KIO) $(LIB_KDECORE) +libknewstickercommon_la_LDFLAGS = $(all_libraries) -no-undefined diff --git a/knewsticker/common/configaccess.cpp b/knewsticker/common/configaccess.cpp new file mode 100644 index 00000000..942b3f70 --- /dev/null +++ b/knewsticker/common/configaccess.cpp @@ -0,0 +1,674 @@ +/* + * configaccess.cpp + * + * Copyright (c) 2001 Frerich Raabe <raabe@kde.org> + * + * 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. For licensing and distribution details, check the + * accompanying file 'COPYING'. + */ +#include "configaccess.h" +#include "newsengine.h" + +#include <qregexp.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <kglobalsettings.h> + +static NewsSourceBase::Data NewsSourceDefault[DEFAULT_NEWSSOURCES] = { + // Arts --------------- + NewsSourceBase::Data( + QString::fromLatin1("Bureau 42"), + QString::fromLatin1("http://www.bureau42.com/rdf/"), + QString::fromLatin1("http://www.bureau42.com/favicon.ico"), + NewsSourceBase::Arts, 5, false, false), + NewsSourceBase::Data( + QString::fromLatin1("eFilmCritic"), + QString::fromLatin1("http://efilmcritic.com/fo.rdf"), + QString::fromLatin1("http://efilmcritic.com/favicon.ico"), + NewsSourceBase::Arts, 3, false, false), + NewsSourceBase::Data( + QString::fromLatin1("superhits.ch"), + QString::fromLatin1("http://www.superhits.ch/cgi-bin/superhits.cgi?page=rdf"), + QString::fromLatin1("http://www.superhits.ch/favicon.ico"), + NewsSourceBase::Arts, 10, false, false, QString::fromLatin1("de")), + // Business ----------- + NewsSourceBase::Data( + QString::fromLatin1("Internet.com Business"), + QString::fromLatin1("http://headlines.internet.com/internetnews/bus-news/news.rss"), + QString::null, + NewsSourceBase::Business, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("TradeSims"), + QString::fromLatin1("http://www.tradesims.com/AEX.rdf"), + QString::null, + NewsSourceBase::Business, 10, false, false), + // Computers ---------- + NewsSourceBase::Data( + QString::fromLatin1( "linuxartist.org" ), + QString::fromLatin1( "http://www.linuxartist.org/backend.php"), + QString::fromLatin1( "http://www.linuxartist.org/favicon.ico"), + NewsSourceBase::Computers, 10, false, false ), + NewsSourceBase::Data( + QString::fromLatin1("KDE Deutschland"), + QString::fromLatin1("http://www.kde.de/nachrichten/nachrichten.rdf"), + QString::fromLatin1("http://www.kde.de/favicon.ico"), + NewsSourceBase::Computers, 10, true, false, QString::fromLatin1("de")), + NewsSourceBase::Data( + QString::fromLatin1("KDE France"), + QString::fromLatin1("http://www.kde-france.org/backend-breves.php3"), + QString::null, + NewsSourceBase::Computers, 10, true, false, QString::fromLatin1("fr")), + NewsSourceBase::Data( + QString::fromLatin1("FreeBSD Project News"), + QString::fromLatin1("http://www.freebsd.org/news/news.rdf"), + QString::fromLatin1("http://www.freebsd.org/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("dot.kde.org"), + QString::fromLatin1("http://www.kde.org/dotkdeorg.rdf"), + QString::fromLatin1("http://www.kde.org/favicon.ico"), + NewsSourceBase::Computers, 10, true, false), + NewsSourceBase::Data( + QString::fromLatin1("GNOME News"), + QString::fromLatin1("http://www.gnomedesktop.org/backend.php"), + QString::null, + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("Slashdot"), + QString::fromLatin1("http://slashdot.org/slashdot.rdf"), + QString::fromLatin1("http://slashdot.org/favicon.ico"), + NewsSourceBase::Computers, 10, true, false), + NewsSourceBase::Data( + QString::fromLatin1("Ask Slashdot"), + QString::fromLatin1("http://slashdot.org/askslashdot.rdf"), + QString::fromLatin1("http://slashdot.org/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("Slashdot: Features"), + QString::fromLatin1("http://slashdot.org/features.rdf"), + QString::fromLatin1("http://slashdot.org/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("Slashdot: Apache"), + QString::fromLatin1("http://slashdot.org/apache.rdf"), + QString::fromLatin1("http://slashdot.org/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("Slashdot: Books"), + QString::fromLatin1("http://slashdot.org/books.rdf"), + QString::fromLatin1("http://slashdot.org/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("Jabber News"), + QString::fromLatin1("http://www.jabber.org/news/rss.xml"), + QString::null, + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("Freshmeat"), + QString::fromLatin1("http://freshmeat.net/backend/fm.rdf"), + QString::fromLatin1("http://freshmeat.net/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("Linux Weekly News"), + QString::fromLatin1("http://www.lwn.net/headlines/rss"), + QString::fromLatin1("http://www.lwn.net/favicon.ico"), + NewsSourceBase::Computers, 10, true, false), + NewsSourceBase::Data( + QString::fromLatin1("heise online news"), + QString::fromLatin1("http://www.heise.de/newsticker/heise.rdf"), + QString::fromLatin1("http://www.heise.de/favicon.ico"), + NewsSourceBase::Computers, 10, true, false, QString::fromLatin1("de")), + NewsSourceBase::Data( + QString::fromLatin1("RUS-CERT Ticker"), + QString::fromLatin1("http://cert.uni-stuttgart.de/ticker/rus-cert.rdf"), + QString::fromLatin1("http://cert.uni-stuttgart.de/favicon.ico"), + NewsSourceBase::Computers, 10, true, false, QString::fromLatin1("de")), + NewsSourceBase::Data( + QString::fromLatin1("RUS-CERT Elsewhere"), + QString::fromLatin1("http://cert.uni-stuttgart.de/ticker/rus-cert-elsewhere.rdf"), + QString::fromLatin1("http://cert.uni-stuttgart.de/favicon.ico"), + NewsSourceBase::Computers, 10, false, false, QString::fromLatin1("de")), + NewsSourceBase::Data( + QString::fromLatin1("Kuro5hin"), + QString::fromLatin1("http://kuro5hin.org/backend.rdf"), + QString::fromLatin1("http://kuro5hin.org/favicon.ico"), + NewsSourceBase::Computers, 10, true, false), + NewsSourceBase::Data( + QString::fromLatin1("Prolinux"), + QString::fromLatin1("http://www.pl-forum.de/backend/pro-linux.rdf"), + QString::fromLatin1("http://www.prolinux.de/favicon.ico"), + NewsSourceBase::Computers, 10, false, false, QString::fromLatin1("de")), + NewsSourceBase::Data( + QString::fromLatin1("Linuxde.org"), + QString::fromLatin1("http://www.linuxde.org/backends/news.rdf"), + QString::fromLatin1("http://www.linuxde.org/favicon.ico"), + NewsSourceBase::Computers, 10, false, false, QString::fromLatin1("de")), + NewsSourceBase::Data( + QString::fromLatin1("LinuxSecurity.com"), + QString::fromLatin1("http://www.linuxsecurity.com/linuxsecurity_hybrid.rdf"), + QString::null, + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("Linux Game Tome"), + QString::fromLatin1("http://happypenguin.org/html/news.rdf"), + QString::null, + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("Telefragged"), + QString::fromLatin1("http://www.telefragged.com/cgi-bin/rdf.pl"), + QString::null, + NewsSourceBase::Computers, 10, false, false), +/* NewsSourceBase::Data( + QString::fromLatin1("Gimp News"), + QString::fromLatin1("http://www.xach.com/gimp/news/channel.rdf"), + QString::null, + NewsSourceBase::Computers, 10, false, false),*/ + NewsSourceBase::Data( + QString::fromLatin1("Mozilla"), + QString::fromLatin1("http://www.mozilla.org/news.rdf"), + QString::fromLatin1("http://www.mozillazine.org/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("MozillaZine"), + QString::fromLatin1("http://www.mozillazine.org/contents.rdf"), + QString::fromLatin1("http://www.mozillazine.org/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("Daemon News"), + QString::fromLatin1("http://daily.daemonnews.org/ddn.rdf.php3"), + QString::null, + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("use Perl;"), + QString::fromLatin1("http://use.perl.org/useperl.rdf"), + QString::null, + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("desktopian.org"), + QString::fromLatin1("http://www.desktopian.org/includes/headlines.xml"), + QString::fromLatin1("http://www.desktopian.org/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("Root prompt"), + QString::fromLatin1("http://www.rootprompt.org/rss/"), + QString::fromLatin1("http://www.rootprompt.org/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("SecurityFocus"), + QString::fromLatin1("http://www.securityfocus.com/rss/news.xml"), + QString::fromLatin1("http://www.securityfocus.com/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("LinuxNewbie"), + QString::fromLatin1("http://www.linuxnewbie.org/news.cdf"), + QString::fromLatin1("http://www.linuxnewbie.org/favicon.ico"), + NewsSourceBase::Computers, 5, false, false), + NewsSourceBase::Data( + QString::fromLatin1("Arstechnica"), + QString::fromLatin1("http://arstechnica.com/etc/rdf/ars.rdf"), + QString::fromLatin1("http://arstechnica.com/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("amiga-news.de - deutschsprachige Amiga Nachrichten"), + QString::fromLatin1("http://www.amiga-news.de/de/backends/news/index.rss"), + QString::fromLatin1("http://www.amiga-news.de/favicon.ico"), + NewsSourceBase::Computers, 10, false, false, QString::fromLatin1("de")), + NewsSourceBase::Data( + QString::fromLatin1("amiga-news.de - english Amiga news"), + QString::fromLatin1("http://www.amiga-news.de/en/backends/news/index.rss"), + QString::fromLatin1("http://www.amiga-news.de/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("RadioTux)"), + QString::fromLatin1("http://blog.radiotux.de/feed/"), + QString::null, + NewsSourceBase::Computers, 10, false, false, QString::fromLatin1("de")), + NewsSourceBase::Data( + QString::fromLatin1("kdenews.unixcode.org"), + QString::fromLatin1("http://kdenews.unixcode.org/?node=news&action=rss"), + QString::null, + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("FreshPorts - the place for ports"), + QString::fromLatin1("http://www.freshports.org/news.php"), + QString::fromLatin1("http://www.freshports.org/favicon.ico"), + NewsSourceBase::Computers, 20, false, false), + NewsSourceBase::Data( + QString::fromLatin1("NetPhoenix"), + QString::fromLatin1("http://www.netphoenix.at/rss/netphoenix.php"), + QString::fromLatin1("http://www.netphoenix.at/favicon.ico"), + NewsSourceBase::Computers, 10, false, false, QString::fromLatin1("de")), + NewsSourceBase::Data( + QString::fromLatin1("ShortNews - by www.netphoenix.at"), + QString::fromLatin1("http://www.netphoenix.at/rss/shortnews.php"), + QString::fromLatin1("http://www.netphoenix.at/favicon.ico"), + NewsSourceBase::Computers, 10, false, false, QString::fromLatin1("de")), + NewsSourceBase::Data( + QString::fromLatin1("zez.org - about code "), + QString::fromLatin1("http://zez.org/article/rssheadlines"), + QString::null, + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("BSDatwork.com"), + QString::fromLatin1("http://BSDatwork.com/backend.php"), + QString::fromLatin1("http://BSDatwork.com/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("FreshSource - the place for source"), + QString::fromLatin1("http://www.freshsource.org/news.php"), + QString::fromLatin1("http://www.freshsource.org/favicon.ico"), + NewsSourceBase::Computers, 20, false, false), + NewsSourceBase::Data( + QString::fromLatin1("The FreeBSD Diary"), + QString::fromLatin1("http://www.freebsddiary.org/news.php"), + QString::fromLatin1("http://www.freebsddiary.org/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("MaximumBSD"), + QString::fromLatin1("http://www.maximumbsd.com/backend/mb.rdf"), + QString::fromLatin1("http://www.maximumbsd.com/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("BR-Linux.org"), + QString::fromLatin1("http://br-linux.org/noticias/index.rdf"), + QString::fromLatin1("http://br-linux.org/noticias/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("OSNews.com"), + QString::fromLatin1("http://www.osnews.com/files/recent.rdf"), + QString::fromLatin1("http://www.osnews.com/favicon.ico"), + NewsSourceBase::Computers, 10, false, false), + // Miscellaneous ------ + NewsSourceBase::Data( + QString::fromLatin1("tagesschau.de"), + QString::fromLatin1("http://www.tagesschau.de/newsticker.rdf"), + QString::fromLatin1("http://www.tagesschau.de/favicon.ico"), + NewsSourceBase::Misc, 10, true, false, QString::fromLatin1("de")), + NewsSourceBase::Data( + QString::fromLatin1("N24.de"), + QString::fromLatin1("http://www.n24.de/rss/?rubrik=home"), + QString::fromLatin1("http://www.n24.de/favicon.ico"), + NewsSourceBase::Misc, 10, true, false, QString::fromLatin1("de")), +/* + NewsSourceBase::Data( + QString::fromLatin1("CNN"), + QString::fromLatin1("http://www.cnn.com/cnn.rss"), + QString::fromLatin1("http://www.cnn.com/favicon.ico"), + NewsSourceBase::Misc, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("CNN Europe"), + QString::fromLatin1("http://europe.cnn.com/cnn.rss"), + QString::fromLatin1("http://europe.cnn.com/favicon.ico"), + NewsSourceBase::Misc, 10, false, false), +*/ + NewsSourceBase::Data( + QString::fromLatin1("HotWired"), + QString::fromLatin1("http://www.hotwired.com/webmonkey/meta/headlines.rdf"), + QString::fromLatin1("http://www.hotwired.com/favicon.ico"), + NewsSourceBase::Misc, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1("The Register"), + QString::fromLatin1("http://www.theregister.co.uk/tonys/slashdot.rdf"), + QString::fromLatin1("http://www.theregister.co.uk/favicon.ico"), + NewsSourceBase::Misc, 10, false, false), + NewsSourceBase::Data( + QString::fromLatin1( "Christian Science Monitor" ), + QString::fromLatin1( "http://www.csmonitor.com/rss/csm.rss"), + QString::fromLatin1( "http://www.csmonitor.com/favicon.ico"), + NewsSourceBase::Misc, 10, false, false ), + // Magazines ------ + NewsSourceBase::Data( + QString::fromLatin1("Revista do Linux"), + QString::fromLatin1("http://www.revistadolinux.com.br/noticias/arquivo/noticias.rdf"), + QString::fromLatin1("http://www.revistadolinux.com.br/favicon.ico"), + NewsSourceBase::Magazines, 10, false, false /*, QString::fromLatin1("br")*/ ), + NewsSourceBase::Data( + QString::fromLatin1("Spiegel.de"), + QString::fromLatin1("http://www.spiegel.de/schlagzeilen/rss/0,5291,,00.xml"), + QString::fromLatin1("http://www.spiegel.de/favicon.ico"), + NewsSourceBase::Magazines, 10, true, false, QString::fromLatin1("de")), + NewsSourceBase::Data( + QString::fromLatin1("FAZ.de"), + QString::fromLatin1("http://www.faz.net/s/Rub/Tpl~Epartner~SRss_.xml"), + QString::fromLatin1("http://www.faz.net/favicon.ico"), + NewsSourceBase::Magazines, 10, true, false, QString::fromLatin1("de")), + // Recreation + NewsSourceBase::Data( + QString::fromLatin1("Segfault"), + QString::fromLatin1("http://segfault.org/stories.xml"), + QString::fromLatin1("http://segfault.org/favicon.ico"), + NewsSourceBase::Recreation, 10, false, false), + // Society + NewsSourceBase::Data( + QString::fromLatin1("nippon.it"), + QString::fromLatin1("http://www.nippon.it/backend.it.php"), + QString::fromLatin1("http://www.nippon.it/favicon.ico"), + NewsSourceBase::Society, 10, false, false, QString::fromLatin1("it")), + NewsSourceBase::Data( + QString::fromLatin1( "gflash" ), + QString::fromLatin1( "http://www.gflash.de/backend.php"), + QString::fromLatin1( "http://www.gflash.de/favicon.ico"), + NewsSourceBase::Society, 10, false, false, QString::fromLatin1( "de" ) ), + NewsSourceBase::Data( + QString::fromLatin1( "Quintessenz" ), + QString::fromLatin1( "http://quintessenz.at/cgi-bin/rdf"), + QString::fromLatin1( "http://quintessenz.at/favicon.ico"), + NewsSourceBase::Society, 9, false, false, QString::fromLatin1( "de" ) ) +}; + +ArticleFilter::ArticleFilter(const QString &action, const QString &newsSource, + const QString &condition, const QString &expression, bool enabled) + : m_action(action), + m_newsSource(newsSource), + m_condition(condition), + m_expression(expression), + m_enabled(enabled) +{ +} + +bool ArticleFilter::matches(Article::Ptr a) const +{ + if (!enabled() || + (a->newsSource()->data().name != newsSource() && + newsSource() != i18n("all news sources"))) + return false; + + bool matches; + + if (condition() == i18n("contain")) + matches = a->headline().contains(expression()); + else if (condition() == i18n("do not contain")) + matches = !a->headline().contains(expression()); + else if (condition() == i18n("equal")) + matches = (a->headline() == expression()); + else if (condition() == i18n("do not equal")) + matches = (a->headline() != expression()); + else { // condition() == i18n("match") + QRegExp regexp = QRegExp(expression()); + matches = regexp.exactMatch(a->headline()); + } + + if (action() == i18n("Show")) + matches = !matches; + + return matches; +} + +ConfigAccess::ConfigAccess() + : m_defaultCfg(new KConfig(QString::null, true, false)) +{ + m_cfg = m_defaultCfg; +} + +ConfigAccess::ConfigAccess(KConfig *config) + : m_cfg(config), m_defaultCfg(0L) +{ + m_cfg->setGroup("KNewsTicker"); +} + +ConfigAccess::~ConfigAccess() +{ + delete m_defaultCfg; +} + +unsigned int ConfigAccess::interval() const +{ + return m_cfg->readNumEntry("Update interval", 30); +} + +void ConfigAccess::setInterval(const unsigned int interval) +{ + m_cfg->writeEntry("Update interval", interval); + m_cfg->sync(); +} + +unsigned int ConfigAccess::mouseWheelSpeed() const +{ + return m_cfg->readNumEntry("Mouse wheel speed", 5); +} + +void ConfigAccess::setMouseWheelSpeed(const unsigned int mouseWheelSpeed) +{ + m_cfg->writeEntry("Mouse wheel speed", mouseWheelSpeed); + m_cfg->sync(); +} + +QFont ConfigAccess::font() const +{ + QFont font = KGlobalSettings::fixedFont(); + return m_cfg->readFontEntry("Font", &font); +} + +void ConfigAccess::setFont(const QFont &font) +{ + m_cfg->writeEntry("Font", font); + m_cfg->sync(); +} + +bool ConfigAccess::customNames() const +{ + return m_cfg->readBoolEntry("Custom names", false); +} + +void ConfigAccess::setCustomNames(bool customNames) +{ + m_cfg->writeEntry("Custom names", customNames); + m_cfg->sync(); +} + +bool ConfigAccess::scrollMostRecentOnly() const +{ + return m_cfg->readBoolEntry("Scroll most recent headlines only", false); +} + +void ConfigAccess::setScrollMostRecentOnly(bool scrollMostRecentOnly) +{ + m_cfg->writeEntry("Scroll most recent headlines only", scrollMostRecentOnly); + m_cfg->sync(); +} + +bool ConfigAccess::offlineMode() const +{ + return m_cfg->readBoolEntry("Offline mode", false); +} + +void ConfigAccess::setOfflineMode(bool offlineMode) +{ + m_cfg->writeEntry("Offline mode", offlineMode); + m_cfg->sync(); +} + +QStringList ConfigAccess::newsSources() const +{ + QStringList tempList = m_cfg->readListEntry("News sources"); + if (tempList.isEmpty()) + for (unsigned int i = 0; i < DEFAULT_NEWSSOURCES; i++) + tempList << NewsSourceDefault[i].name; + return tempList; +} + +ArticleFilter::List ConfigAccess::filters() const +{ + return m_cfg->readIntListEntry("Filters"); +} + +void ConfigAccess::setNewsSources(const QStringList &newsSources) +{ + m_cfg->writeEntry("News sources", newsSources); + m_cfg->sync(); +} + +void ConfigAccess::setFilters(const ArticleFilter::List &filters) +{ + m_cfg->writeEntry("Filters", filters); + m_cfg->sync(); +} + +unsigned int ConfigAccess::scrollingSpeed() const +{ + return m_cfg->readNumEntry("Scrolling speed", 20); +} + +void ConfigAccess::setScrollingSpeed(const unsigned int scrollingSpeed) +{ + m_cfg->writeEntry("Scrolling speed", scrollingSpeed); + m_cfg->sync(); +} + +unsigned int ConfigAccess::scrollingDirection() const +{ + return m_cfg->readNumEntry("Scrolling direction", 0); +} + +void ConfigAccess::setScrollingDirection(const unsigned int scrollingDirection) +{ + m_cfg->writeEntry("Scrolling direction", scrollingDirection); + m_cfg->sync(); +} + +QColor ConfigAccess::foregroundColor() const +{ + return m_cfg->readColorEntry("Foreground color", &Qt::black); +} + +void ConfigAccess::setForegroundColor(const QColor &foregroundColor) +{ + m_cfg->writeEntry("Foreground color", foregroundColor); + m_cfg->sync(); +} + +QColor ConfigAccess::backgroundColor() const +{ + return m_cfg->readColorEntry("Background color", &Qt::white); +} + +void ConfigAccess::setBackgroundColor(const QColor &backgroundColor) +{ + m_cfg->writeEntry("Background color", backgroundColor); + m_cfg->sync(); +} + +QColor ConfigAccess::highlightedColor() const +{ + return m_cfg->readColorEntry("Highlighted color", &Qt::red); +} + +void ConfigAccess::setHighlightedColor(const QColor &highlightedColor) +{ + m_cfg->writeEntry("Highlighted color", highlightedColor); + m_cfg->sync(); +} + +bool ConfigAccess::underlineHighlighted() const +{ + return m_cfg->readBoolEntry("Underline highlighted headlines", true); +} + +void ConfigAccess::setUnderlineHighlighted(bool underlineHighlighted) +{ + m_cfg->writeEntry("Underline highlighted headlines", underlineHighlighted); + m_cfg->sync(); +} + +NewsSourceBase *ConfigAccess::newsSource(const QString &newsSource) +{ + NewsSourceBase::Data nsd; + + if (m_cfg->hasGroup(newsSource)) { + m_cfg->setGroup(newsSource); + nsd.name = newsSource; + nsd.sourceFile = m_cfg->readPathEntry("Source file"); + nsd.isProgram = m_cfg->readBoolEntry("Is program", false); + nsd.subject = static_cast<NewsSourceBase::Subject> + (m_cfg->readNumEntry("Subject", NewsSourceBase::Computers)); + nsd.icon = m_cfg->readEntry("Icon"); + nsd.maxArticles = m_cfg->readNumEntry("Max articles", 10); + nsd.enabled = m_cfg->readBoolEntry("Enabled", true); + nsd.language = m_cfg->readEntry("Language", QString::fromLatin1("C")); + m_cfg->setGroup("KNewsTicker"); + } else for (unsigned int i = 0; i < DEFAULT_NEWSSOURCES; i++) + if (NewsSourceDefault[i].name == newsSource) { + nsd = NewsSourceDefault[i]; + if (nsd.enabled) + nsd.enabled = (nsd.language == QString::fromLatin1("C") || + KGlobal::locale()->languageList().contains(nsd.language)); + break; + } + + if (nsd.isProgram) + return new ProgramNewsSource(nsd, this); + else + return new SourceFileNewsSource(nsd, this); + + return 0L; +} + +ArticleFilter ConfigAccess::filter(const unsigned int filterNo) const +{ + ArticleFilter f; + f.setId(filterNo); + + if (m_cfg->hasGroup(QString::fromLatin1("Filter #%1").arg(filterNo))) { + m_cfg->setGroup(QString::fromLatin1("Filter #%1").arg(filterNo)); + f.setAction(m_cfg->readEntry("Action", i18n("Show"))); + f.setNewsSource(m_cfg->readEntry("News source", i18n("all news sources"))); + f.setCondition(m_cfg->readEntry("Condition", i18n("contain"))); + f.setExpression(m_cfg->readEntry("Expression")); + f.setEnabled(m_cfg->readBoolEntry("Enabled", true)); + m_cfg->setGroup("KNewsTicker"); + } + + return f; +} + +void ConfigAccess::setNewsSource(const NewsSourceBase::Data &ns) +{ + m_cfg->setGroup(ns.name); + m_cfg->writePathEntry("Source file", ns.sourceFile); + m_cfg->writeEntry("Is program", ns.isProgram); + m_cfg->writeEntry("Max articles", ns.maxArticles); + m_cfg->writeEntry("Subject", ns.subject); + m_cfg->writeEntry("Icon", ns.icon); + m_cfg->writeEntry("Enabled", ns.enabled); + m_cfg->writeEntry("Language", ns.language); + m_cfg->setGroup("KNewsTicker"); + m_cfg->sync(); +} + +void ConfigAccess::setFilter(const ArticleFilter &f) +{ + m_cfg->setGroup(QString::fromLatin1("Filter #%1").arg(f.id())); + m_cfg->writeEntry("Action", f.action()); + m_cfg->writeEntry("News source", f.newsSource()); + m_cfg->writeEntry("Condition", f.condition()); + m_cfg->writeEntry("Expression", f.expression()); + m_cfg->writeEntry("Enabled", f.enabled()); + m_cfg->setGroup("KNewsTicker"); + m_cfg->sync(); +} + +bool ConfigAccess::showIcons() const +{ + return m_cfg->readBoolEntry("Show icons", true); +} + +void ConfigAccess::setShowIcons(bool showIcons) +{ + m_cfg->writeEntry("Show icons", showIcons); + m_cfg->sync(); +} + +bool ConfigAccess::slowedScrolling() const +{ + return m_cfg->readBoolEntry("Slowed scrolling", false); +} + +void ConfigAccess::setSlowedScrolling(bool slowedScrolling) +{ + m_cfg->writeEntry("Slowed scrolling", slowedScrolling); + m_cfg->sync(); +} + diff --git a/knewsticker/common/configaccess.h b/knewsticker/common/configaccess.h new file mode 100644 index 00000000..3cdf80e5 --- /dev/null +++ b/knewsticker/common/configaccess.h @@ -0,0 +1,135 @@ +/* + * configaccess.h + * + * Copyright (c) 2001 Frerich Raabe <raabe@kde.org> + * + * 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. For licensing and distribution details, check the + * accompanying file 'COPYING'. + */ +#ifndef CONFIGACCESS_H +#define CONFIGACCESS_H + +#include "configiface.h" +#include "newsengine.h" + +#include <kconfig.h> +#include <kio/job.h> +#include <klocale.h> + +#include <qpixmap.h> +#include <qvaluelist.h> + +#define DEFAULT_NEWSSOURCES 63 +#define DEFAULT_SUBJECTS 13 + +class QColor; +class QFont; +class KURL; + +class ArticleFilter { + public: + typedef QValueList<int> List; + + ArticleFilter(const QString & = I18N_NOOP(QString::fromLatin1("Show")), + const QString & = I18N_NOOP(QString::fromLatin1("all newssources")), + const QString & = I18N_NOOP(QString::fromLatin1("contain")), + const QString & = QString::null, + bool = true); + + QString action() const { return m_action; } + void setAction(const QString &action) { m_action = action; } + + QString newsSource() const { return m_newsSource; } + void setNewsSource(const QString &newsSource) { m_newsSource = newsSource; } + + QString condition() const { return m_condition; } + void setCondition(const QString &condition) { m_condition = condition; } + + QString expression() const { return m_expression; } + void setExpression(const QString &expression) { m_expression = expression; } + + bool enabled() const { return m_enabled; } + void setEnabled(bool enabled) { m_enabled = enabled; } + + unsigned int id() const { return m_id; } + void setId(const unsigned int id) { m_id = id; } + + bool matches(Article::Ptr) const; + + private: + QString m_action; + QString m_newsSource; + QString m_condition; + QString m_expression; + bool m_enabled; + unsigned int m_id; +}; + +class ConfigAccess : public ConfigIface +{ + public: + ConfigAccess(); + ConfigAccess(KConfig *); + virtual ~ConfigAccess(); + + virtual unsigned int interval() const; + virtual unsigned int scrollingSpeed() const; + virtual unsigned int mouseWheelSpeed() const; + virtual unsigned int scrollingDirection() const; + virtual bool customNames() const; + virtual bool scrollMostRecentOnly() const; + virtual bool offlineMode() const; + virtual bool underlineHighlighted() const; + virtual bool showIcons() const; + virtual bool slowedScrolling() const; + virtual QColor foregroundColor() const; + virtual QColor backgroundColor() const; + virtual QColor highlightedColor() const; + QFont font() const; + virtual QStringList newsSources() const; + NewsSourceBase *newsSource(const QString &); + ArticleFilter::List filters() const; + ArticleFilter filter(const unsigned int) const; + + static bool horizontal(Direction d) { return d == Left || d == Right; } + static bool vertical(Direction d) { return d == Up || d == Down; } + static bool rotated(Direction d) { return d == UpRotated || d == DownRotated; } + + inline bool horizontalScrolling() const + { + return horizontal((Direction) scrollingDirection()); + }; + + inline bool verticalScrolling() const + { + return vertical((Direction)scrollingDirection()); + }; + + virtual void setInterval(const unsigned int); + virtual void setScrollingSpeed(const unsigned int); + virtual void setMouseWheelSpeed(const unsigned int); + virtual void setScrollingDirection(const unsigned int); + virtual void setCustomNames(bool); + virtual void setScrollMostRecentOnly(bool); + virtual void setOfflineMode(bool); + virtual void setUnderlineHighlighted(bool); + virtual void setShowIcons(bool); + virtual void setSlowedScrolling(bool); + virtual void setForegroundColor(const QColor &); + virtual void setBackgroundColor(const QColor &); + virtual void setHighlightedColor(const QColor &); + void setFont(const QFont &); + virtual void setNewsSources(const QStringList &); + void setNewsSource(const NewsSourceBase::Data &); + void setFilters(const ArticleFilter::List &); + void setFilter(const ArticleFilter &); + void reparseConfiguration() { m_cfg->reparseConfiguration(); } + + private: + KConfig *m_cfg; + KConfig *m_defaultCfg; +}; + +#endif // CONFIGACCESS_H diff --git a/knewsticker/common/configiface.h b/knewsticker/common/configiface.h new file mode 100644 index 00000000..64bc312d --- /dev/null +++ b/knewsticker/common/configiface.h @@ -0,0 +1,56 @@ +/* + * configface.h + * + * Copyright (c) 2001 Frerich Raabe <raabe@kde.org> + * + * 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. For licensing and distribution details, check the + * accompanying file 'COPYING'. + */ +#ifndef CONFIGIFACE_H +#define CONFIGIFACE_H + +class QColor; +class QStringList; +class QFont; + +class KURL; + +class ConfigIface +{ + public: + enum Direction {Left = 0, Right, Up, Down, UpRotated, DownRotated}; + + virtual unsigned int interval() const = 0; + virtual unsigned int scrollingSpeed() const = 0; + virtual unsigned int mouseWheelSpeed() const = 0; + virtual unsigned int scrollingDirection() const = 0; + virtual bool customNames() const = 0; + virtual bool scrollMostRecentOnly() const = 0; + virtual bool offlineMode() const = 0; + virtual bool underlineHighlighted() const = 0; + virtual bool showIcons() const = 0; + virtual bool slowedScrolling() const = 0; + virtual QColor foregroundColor() const = 0; + virtual QColor backgroundColor() const = 0; + virtual QColor highlightedColor() const = 0; + virtual QStringList newsSources() const = 0; + + virtual void setInterval(const unsigned int) = 0; + virtual void setScrollingSpeed(const unsigned int) = 0; + virtual void setMouseWheelSpeed(const unsigned int) = 0; + virtual void setScrollingDirection(const unsigned int) = 0; + virtual void setCustomNames(bool) = 0; + virtual void setScrollMostRecentOnly(bool) = 0; + virtual void setOfflineMode(bool) = 0; + virtual void setUnderlineHighlighted(bool) = 0; + virtual void setShowIcons(bool) = 0; + virtual void setSlowedScrolling(bool) = 0; + virtual void setForegroundColor(const QColor &) = 0; + virtual void setBackgroundColor(const QColor &) = 0; + virtual void setHighlightedColor(const QColor &) = 0; + virtual void setNewsSources(const QStringList &) = 0; +}; + +#endif // CONFIGIFACE_H diff --git a/knewsticker/common/newsengine.cpp b/knewsticker/common/newsengine.cpp new file mode 100644 index 00000000..cce7895c --- /dev/null +++ b/knewsticker/common/newsengine.cpp @@ -0,0 +1,324 @@ +/* + * newsengine.cpp + * + * Copyright (c) 2000, 2001 Frerich Raabe <raabe@kde.org> + * + * 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. For licensing and distribution details, check the + * accompanying file 'COPYING'. + */ +#include "newsengine.h" +#include "configiface.h" +#include "configaccess.h" +#include "xmlnewsaccess.h" +#include "newsiconmgr.h" + +#include <kapplication.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <krun.h> +#include <kstandarddirs.h> + +#include <qbuffer.h> + +Article::Article(NewsSourceBase *parent, const QString &headline, + const KURL &address) + : XMLNewsArticle(headline, address), + m_parent(parent), + m_read(false) +{ +} + +bool Article::operator==(const Article &other) const +{ + return headline() == other.headline() && address() == other.address(); +} + +void Article::open() +{ + (void) new KRun(address()); + m_read = true; +} + +NewsSourceBase::NewsSourceBase(const Data &nsd, ConfigIface *config) + : XMLNewsSource(), + m_data(nsd), + m_icon(QPixmap()), + m_cfg(dynamic_cast<ConfigAccess *>(config)), + m_newsIconMgr(NewsIconMgr::self()) +{ + connect(this, SIGNAL(loadComplete(XMLNewsSource *, bool)), + SLOT(slotProcessArticles(XMLNewsSource *, bool))); +} + +void NewsSourceBase::getIcon() +{ + connect(m_newsIconMgr, SIGNAL(gotIcon(const KURL &, const QPixmap &)), + this, SLOT(slotGotIcon(const KURL &, const QPixmap &))); + m_newsIconMgr->getIcon( KURL( m_data.icon ) ); +} + +QString NewsSourceBase::newsSourceName() const +{ + if (m_cfg->customNames() || m_name.isEmpty()) + return m_data.name; + else + return m_name; +} + +QString NewsSourceBase::subjectText(const Subject subject) +{ + switch (subject) { + case Arts: return i18n("Arts"); + case Business: return i18n("Business"); + case Computers: return i18n("Computers"); + case Games: return i18n("Games"); + case Health: return i18n("Health"); + case Home: return i18n("Home"); + case Recreation: return i18n("Recreation"); + case Reference: return i18n("Reference"); + case Science: return i18n("Science"); + case Shopping: return i18n("Shopping"); + case Society: return i18n("Society"); + case Sports: return i18n("Sports"); + case Misc: return i18n("Miscellaneous"); + case Magazines: return i18n("Magazines"); + default: return i18n("Unknown"); + } +} + +void NewsSourceBase::slotProcessArticles(XMLNewsSource *, bool gotEm) +{ + if (!gotEm) { + emit invalidInput(this); + return; + } + + Article::List oldArticles = m_articles; + + // Truncate the list of articles if necessary. + m_articles.clear(); + XMLNewsArticle::List::ConstIterator it = XMLNewsSource::articles().begin(); + XMLNewsArticle::List::ConstIterator end = XMLNewsSource::articles().end(); + for (; it != end; ++it) + m_articles.append(new Article(this, (*it).headline(), (*it).address())); + + // Fill the list with old articles until maxArticles is reached. + if (m_articles.count() < m_data.maxArticles) { + Article::List::ConstIterator oldArtIt = oldArticles.begin(); + Article::List::ConstIterator oldArtEnd = oldArticles.end(); + bool isNewArticle; + for (; oldArtIt != oldArtEnd; ++oldArtIt) { + isNewArticle = true; + Article::List::ConstIterator newArtIt = m_articles.begin(); + Article::List::ConstIterator newArtEnd = m_articles.end(); + for (; newArtIt != newArtEnd; ++newArtIt) { + Article newArt = **newArtIt; + Article oldArt = **oldArtIt; + if (newArt == oldArt) + isNewArticle = false; + } + + if (isNewArticle) + m_articles.append(*oldArtIt); + if (m_articles.count() == m_data.maxArticles) + break; + } + } else + while (m_articles.count() > m_data.maxArticles) + m_articles.remove(m_articles.fromLast()); + + // Copy the read flag of known articles + Article::List::ConstIterator oldArtIt = oldArticles.begin(); + Article::List::ConstIterator oldArtEnd = oldArticles.end(); + for (; oldArtIt != oldArtEnd; ++oldArtIt) { + Article::List::Iterator newArtIt = m_articles.begin(); + Article::List::Iterator newArtEnd = m_articles.end(); + for (; newArtIt != newArtEnd; ++newArtIt) + if (**oldArtIt == **newArtIt) + (*newArtIt)->setRead((*oldArtIt)->read()); + } + + emit newNewsAvailable(this, oldArticles != m_articles); +} + +Article::Ptr NewsSourceBase::article(const QString &headline) +{ + Article::List::ConstIterator it = m_articles.begin(); + Article::List::ConstIterator end = m_articles.end(); + for (; it != end; ++it) + if ((*it)->headline() == headline) + return *it; + + return 0L; +} + +void NewsSourceBase::slotGotIcon(const KURL &url, const QPixmap &pixmap) +{ + if (url.url() == m_data.icon) { + m_icon = pixmap; + + disconnect(m_newsIconMgr, SIGNAL(gotIcon(const KURL &, const QPixmap &)), + this, SLOT(slotGotIcon(const KURL &, const QPixmap &))); + } +} + +SourceFileNewsSource::SourceFileNewsSource(const NewsSourceBase::Data &nsd, + ConfigIface *config) + : NewsSourceBase(nsd, config) +{ +} + +void SourceFileNewsSource::retrieveNews() +{ + loadFrom(KURL( m_data.sourceFile )); +} + +ProgramNewsSource::ProgramNewsSource(const NewsSourceBase::Data &nsd, + ConfigIface *config) : NewsSourceBase(nsd, config), + m_program(new KProcess()), + m_programOutput(0) +{ + connect(m_program, SIGNAL(processExited(KProcess *)), + SLOT(slotProgramExited(KProcess *))); + connect(m_program, SIGNAL(receivedStdout(KProcess *, char *, int)), + SLOT(slotGotProgramOutput(KProcess *, char *, int))); + + m_data.sourceFile = KURL(m_data.sourceFile).encodedPathAndQuery(); +} + +ProgramNewsSource::~ProgramNewsSource() +{ + delete m_program; + delete m_programOutput; +} + +void ProgramNewsSource::retrieveNews() +{ + m_programOutput = new QBuffer; + m_programOutput->open(IO_WriteOnly); + + *m_program << m_data.sourceFile; + m_program->start(KProcess::NotifyOnExit, KProcess::Stdout); +} + +void ProgramNewsSource::slotGotProgramOutput(KProcess *, char *data, int length) +{ + m_programOutput->writeBlock(data, length); +} + +void ProgramNewsSource::slotProgramExited(KProcess *proc) +{ + bool okSoFar = true; + + QString errorMsg; + + if (!proc->normalExit()) { + errorMsg = i18n("<p>The program '%1' was terminated abnormally.<br>This can" + " happen if it receives the SIGKILL signal.</p>"); + okSoFar = false; + } else { + ErrorCode error = static_cast<ErrorCode>(proc->exitStatus()); + if (error != NOERR) { + errorMsg = errorMessage(error).arg(m_data.sourceFile); + okSoFar = false; + } + } + + if (!okSoFar) { + QString output = QString(m_programOutput->buffer()); + if (!output.isEmpty()) { + output = QString::fromLatin1("\"") + output + QString::fromLatin1("\""); + errorMsg += i18n("<p>Program output:<br>%1<br>").arg(output); + } + KMessageBox::detailedError(0, i18n("An error occurred while updating the" + " news source '%1'.").arg(newsSourceName()), errorMsg, + i18n("KNewsTicker Error")); + } + + processData(m_programOutput->buffer(), okSoFar); + + delete m_programOutput; + m_programOutput = 0; +} + +QString ProgramNewsSource::errorMessage(const ErrorCode errorCode) +{ + switch (errorCode) { + case EPERM: return i18n("The program '%1' could not be started at all."); + case ENOENT: return i18n("The program '%1' tried to read or write a file or" + " directory which could not be found."); + case EIO: return i18n("An error occurred while the program '%1' tried to" + " read or write data."); + case E2BIG: return i18n("The program '%1' was passed too many arguments." + " Please adjust the command line in the configuration dialog."); + case ENOEXEC: return i18n("An external system program upon which the" + " program '%1' relied could not be executed."); + case EACCESS: return i18n("The program '%1' tried to read or write a file or" + " directory but lacks the permission to do so."); + case ENODEV: return i18n("The program '%1' tried to access a device which" + " was not available."); + case ENOSPC: return i18n("There is no more space left on the device used by" + " the program '%1'."); + case EROFS: return i18n("The program '%1' tried to create a temporary file" + " on a read only file system."); + case ENOSYS: return i18n("The program '%1' tried to call a function which" + " is not implemented or attempted to access an external resource which" + " does not exist."); + case ENODATA: return i18n("The program '%1' was unable to retrieve input data and" + " was therefore unable to return any XML data."); + case ENONET: return i18n("The program '%1' tried to access a host which is not" + " connected to a network."); + case EPROTO: return i18n("The program '%1' tried to access a protocol which is not" + " implemented."); + case EDESTADDRREQ: return i18n("The program '%1' requires you to configure a" + " destination address to retrieve data from. Please refer to the" + " documentation of the program for information on how to do that."); + case ESOCKTNOSUPPORT: return i18n("The program '%1' tried to use a socket" + " type which is not supported by this system."); + case ENETUNREACH: return i18n("The program '%1' tried to access an unreachable" + " network."); + case ENETRESET: return i18n("The network the program '%1' was trying to access" + " dropped the connection with a reset."); + case ECONNRESET: return i18n("The connection of the program '%1' was reset by" + " peer."); + case ETIMEDOUT: return i18n("The connection the program '%1' was trying to" + " establish timed out."); + case ECONNREFUSED: return i18n("The connection the program '%1' was trying to" + " establish was refused."); + case EHOSTDOWN: return i18n("The host the program '%1' was trying to reach is" + " down."); + case EHOSTUNREACH: return i18n("The host the program '%1' was trying to reach is" + " unreachable, no route to host."); + case ENOEXECBIT: return i18n("KNewsTicker could not execute the program '%1'" + " because its executable bit was not set. You can mark that program as" + " executable by executing the following steps:<ul>" + "<li>Open a Konqueror window and browse to the program</li>" + "<li>Click on the file with the right mouse button, and select 'Properties'</li>" + "<li>Open the 'Permissions' tab and make sure that the box in the column" + " 'Exec' and the row 'User' is checked to ensure that the current user" + " is allowed to execute that file.</li></ul>"); + case EBADREQ: return i18n("The program '%1' sent a bad request which was not" + " understood by the server."); + case ENOAUTH: return i18n("The program '%1' failed to issue an authorization for" + " an area which needs some form of authorization before it can be" + " accessed."); + case EMUSTPAY: return i18n("The program '%1' aborted because it could not access" + " the data without paying for it."); + case EFORBIDDEN: return i18n("The program '%1' tried to access a forbidden" + " source."); + case ENOTFOUND: return i18n("The program '%1' tried to access data which" + " could not be found."); + case ETIMEOUT: return i18n("The HTTP request of the program '%1' timed out."); + case ESERVERE: return i18n("A server error has been encountered. It is likely" + " that you cannot do anything about it."); + case EHTTPNOSUP: return i18n("The HTTP protocol version used by the program" + " '%1' was not understood by the HTTP server or source."); + default: return i18n("KNewsTicker was unable to detect the exact reasons for" + " the error."); + } +} + +#include "newsengine.moc" diff --git a/knewsticker/common/newsengine.h b/knewsticker/common/newsengine.h new file mode 100644 index 00000000..342dd7fe --- /dev/null +++ b/knewsticker/common/newsengine.h @@ -0,0 +1,203 @@ +/* + * newsengine.h + * + * Copyright (c) 2000, 2001 Frerich Raabe <raabe@kde.org> + * + * 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. For licensing and distribution details, check the + * accompanying file 'COPYING'. + */ +#ifndef NEWSENGINE_H +#define NEWSENGINE_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "configiface.h" +#include "xmlnewsaccess.h" + +#include <qptrlist.h> +#include <qmap.h> +#include <qpixmap.h> + +#include <kio/job.h> +#include <klocale.h> +#include <ksharedptr.h> + +class ConfigAccess; +class NewsIconMgr; +class NewsSourceBase; + +class QBuffer; +class QDomDocument; + +class KProcess; +class KURL; + +class KDE_EXPORT Article : public XMLNewsArticle, public KShared +{ + public: + typedef KSharedPtr<Article> Ptr; + typedef QValueList<Ptr> List; + + Article(NewsSourceBase *, const QString & = QString::null, + const KURL & = KURL()); + bool operator==(const Article &other) const; + + bool read() const { return m_read; } + void setRead(bool read) { m_read = read; } + + NewsSourceBase *newsSource() const { return m_parent; } + + void open(); + + private: + NewsSourceBase *m_parent; // don't use KSharedPtr to avoid circular refs! + bool m_read; +}; + +class KDE_EXPORT NewsSourceBase : public XMLNewsSource, public KShared +{ + Q_OBJECT + + public: + enum Subject { + Arts = 0, Business, Computers, Games, Health, Home, Recreation, + Reference, Science, Shopping, Society, Sports, Misc, Magazines + }; + struct Data { + Data(const QString &_name = I18N_NOOP("Unknown"), + const QString &_sourceFile = QString::null, + const QString &_icon = QString::null, + const Subject _subject = Computers, + unsigned int _maxArticles = 10, + bool _enabled = true, bool _isProgram = false, + const QString &_language = QString::fromLatin1("C")) + { + name = _name; + sourceFile = _sourceFile; + icon = _icon; + maxArticles = _maxArticles; + subject = _subject; + enabled = _enabled; + isProgram = _isProgram; + language = _language; + } + + QString name; + QString sourceFile; + QString icon; + Subject subject; + unsigned int maxArticles; + bool enabled; + bool isProgram; + QString language; + }; + typedef KSharedPtr<NewsSourceBase> Ptr; + typedef QValueList<Ptr> List; + + NewsSourceBase(const Data &, ConfigIface *); + + virtual QString newsSourceName() const; + QString sourceFile() const { return m_data.sourceFile; } + unsigned int maxArticles() const { return m_data.maxArticles; } + QPixmap icon() const { return m_icon; } + void getIcon(); + + Data data() const { return m_data; } + + Article::List articles() const { return m_articles; } + Article::Ptr article(const QString &); + + static QString subjectText(const Subject); + + signals: + void newNewsAvailable(const NewsSourceBase::Ptr &, bool); + void invalidInput(const NewsSourceBase::Ptr &); + + public slots: + virtual void retrieveNews() = 0; + + protected slots: + void slotProcessArticles(XMLNewsSource *, bool); + void slotGotIcon(const KURL &, const QPixmap &); + + protected: + Data m_data; + QPixmap m_icon; + ConfigAccess *m_cfg; + NewsIconMgr *m_newsIconMgr; + Article::List m_articles; +}; + +class KDE_EXPORT SourceFileNewsSource : public NewsSourceBase +{ + Q_OBJECT + + public: + SourceFileNewsSource(const NewsSourceBase::Data &, ConfigIface *); + + public slots: + virtual void retrieveNews(); +}; + +// Make sure compilers don't translate +// ProgramNewsSource::ErrorCode into +// enum ErrorCode { 1 = 2, ... } +#undef NOERR +#undef EPERM +#undef ENOENT +#undef EIO +#undef E2BIG +#undef ENOEXEC +#undef EACCESS +#undef ENODEV +#undef ENOSPC +#undef EROFS +#undef ENOSYS +#undef ENODATA +#undef ENONET +#undef EPROTO +#undef EDESTADDRREQ +#undef ESOCKTNOSUPPORT +#undef ENETUNREACH +#undef ENETRESET +#undef ECONNRESET +#undef ETIMEDOUT +#undef ECONNREFUSED +#undef EHOSTDOWN +#undef EHOSTUNREACH + +class KDE_EXPORT ProgramNewsSource : public NewsSourceBase +{ + Q_OBJECT + + public: + enum ErrorCode { NOERR = 0, EPERM, ENOENT, EIO = 5, E2BIG = 7, + ENOEXEC, EACCESS = 13, ENODEV = 19, ENOSPC = 28, EROFS = 30, + ENOSYS = 38, ENODATA = 61, ENONET = 64, EPROTO = 71, EDESTADDRREQ = 89, + ESOCKTNOSUPPORT = 94, ENETUNREACH = 101, ENETRESET = 102, + ECONNRESET = 104, ETIMEDOUT = 110, ECONNREFUSED, EHOSTDOWN, EHOSTUNREACH, + ENOEXECBIT = 126, EBADREQ = 400, ENOAUTH, EMUSTPAY, EFORBIDDEN, ENOTFOUND, + ETIMEOUT = 408, ESERVERE = 500, EHTTPNOSUP = 505 }; + + ProgramNewsSource(const NewsSourceBase::Data &, ConfigIface *); + virtual ~ProgramNewsSource(); + + public slots: + virtual void retrieveNews(); + + protected slots: + void slotGotProgramOutput(KProcess *, char *, int); + void slotProgramExited(KProcess *); + + private: + static QString errorMessage(const ErrorCode); + + KProcess *m_program; + QBuffer *m_programOutput; +}; + +#endif // NEWSENGINE_H diff --git a/knewsticker/common/newsiconmgr.cpp b/knewsticker/common/newsiconmgr.cpp new file mode 100644 index 00000000..69617490 --- /dev/null +++ b/knewsticker/common/newsiconmgr.cpp @@ -0,0 +1,159 @@ +/* + * newsiconmgr.cpp + * + * Copyright (c) 2001 Frerich Raabe <raabe@kde.org> + * + * 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. For licensing and distribution details, check the + * accompanying file 'COPYING'. + */ +#include "newsiconmgr.h" + +#include <dcopclient.h> + +#include <kapplication.h> +#include <kiconloader.h> +#include <kstandarddirs.h> + +#include <qbuffer.h> +#include <qfile.h> +#include <qimage.h> + +struct KIODownload +{ + KURL url; + QByteArray data; + QIODevice::Offset dataOffset; +}; + +NewsIconMgr *NewsIconMgr::m_instance = 0; + +NewsIconMgr *NewsIconMgr::self() +{ + if (!m_instance) + m_instance = new NewsIconMgr(); + + return m_instance; +} + +NewsIconMgr::NewsIconMgr(QObject *parent, const char *name) + : QObject(parent, name), DCOPObject("NewsIconMgr"), + m_stdIcon(SmallIcon(QString::fromLatin1("news"))) +{ + connectDCOPSignal("kded", + "favicons", "iconChanged(bool, QString, QString)", + "slotGotIcon(bool, QString, QString)", + false); +} + +NewsIconMgr::~NewsIconMgr() +{ + delete m_instance; +} + +void NewsIconMgr::getIcon(const KURL &url) +{ + if (url.isEmpty()) { + emit gotIcon(url, m_stdIcon); + return; + } + + if (url.isLocalFile()) { + if (QFile::exists(url.encodedPathAndQuery())) { + QPixmap icon(url.encodedPathAndQuery()); + if (!icon.isNull()) { + if (icon.size() != QSize(16, 16)) { + if (!icon.convertFromImage(icon.convertToImage().smoothScale(16, 16, QImage::ScaleMin))) { + emit gotIcon(url, m_stdIcon); + return; + } + } + emit gotIcon(url, icon); + return; + } + } + emit gotIcon(url, m_stdIcon); + return; + } + + if (url.encodedPathAndQuery() == "/favicon.ico") { + if (favicon(url).isNull()) { + QByteArray data; + QDataStream ds(data, IO_WriteOnly); + ds << url; + kapp->dcopClient()->send("kded", "favicons", "downloadHostIcon(KURL)", data); + } else { + emit gotIcon(url, QPixmap(KGlobal::dirs()->findResource("cache", + QString::fromLatin1("favicons/%1.png").arg(url.host())))); + } + } else { + KIO::Job *job = KIO::get(url, true, false); + connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), + SLOT(slotData(KIO::Job *, const QByteArray &))); + connect(job, SIGNAL(result(KIO::Job *)), SLOT(slotResult(KIO::Job *))); + + KIODownload download; + download.url = url; + download.dataOffset = 0; + m_kioDownload.insert(job, download); + } +} + +bool NewsIconMgr::isStdIcon(const QPixmap &pixmap) const +{ + if (!pixmap.isNull()) + return pixmap.convertToImage() == m_stdIcon.convertToImage(); + else + return false; +} + +void NewsIconMgr::slotData(KIO::Job *job, const QByteArray &data) +{ + QBuffer buf(m_kioDownload[job].data); + buf.open(IO_WriteOnly); + buf.at(m_kioDownload[job].dataOffset); + buf.writeBlock(data); + m_kioDownload[job].dataOffset = buf.at(); +} + +void NewsIconMgr::slotResult(KIO::Job *job) +{ + emit gotIcon(m_kioDownload[job].url, QPixmap(m_kioDownload[job].data)); + m_kioDownload.remove(job); +} + +void NewsIconMgr::slotGotIcon(bool isHost, QString hostOrURL, QString iconName) +{ + KURL url = KURL(hostOrURL); + if (!isHost) + url.setProtocol(QString::fromLatin1("http")); + + if (iconName.isNull()) + emit gotIcon(url, m_stdIcon); + else + emit gotIcon(url, QPixmap(KGlobal::dirs()->findResource("cache", + QString::fromLatin1("favicons/%1.png").arg(url.host())))); +} + +QString NewsIconMgr::favicon(const KURL &url) const +{ + QByteArray data, reply; + QCString replyType; + QDataStream ds(data, IO_WriteOnly); + + ds << url; + + kapp->dcopClient()->call("kded", "favicons", "iconForURL(KURL)", data, replyType, reply); + + if (replyType == "QString") { + QDataStream replyStream(reply, IO_ReadOnly); + QString result; + replyStream >> result; + return result; + } + + return QString::null; +} + +#include "newsiconmgr.moc" diff --git a/knewsticker/common/newsiconmgr.h b/knewsticker/common/newsiconmgr.h new file mode 100644 index 00000000..e4c6b657 --- /dev/null +++ b/knewsticker/common/newsiconmgr.h @@ -0,0 +1,60 @@ +/* + * newsiconmgr.h + * + * Copyright (c) 2001 Frerich Raabe <raabe@kde.org> + * + * 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. For licensing and distribution details, check the + * accompanying file 'COPYING'. + */ +#ifndef NEWSICONMGR_H +#define NEWSICONMGR_H + +#include <qobject.h> +#include <qpixmap.h> + +#include <dcopobject.h> +#include <kio/job.h> +#include <kurl.h> + +class DCOPClient; + +struct KIODownload; +typedef QMap<KIO::Job *, KIODownload> KIODownloadMap; + +class NewsIconMgr : public QObject, public DCOPObject +{ + Q_OBJECT + K_DCOP + + public: + static NewsIconMgr *self(); + + void getIcon(const KURL &); + bool isStdIcon(const QPixmap &) const; + + k_dcop: + void slotGotIcon(bool, QString, QString); + + signals: + void gotIcon(const KURL &, const QPixmap &); + + protected: + NewsIconMgr(QObject * = 0L, const char * = 0L); + ~NewsIconMgr(); + + private slots: + void slotData(KIO::Job *, const QByteArray &); + void slotResult(KIO::Job *); + + private: + QString favicon(const KURL &) const; + + QPixmap m_stdIcon; + KIODownloadMap m_kioDownload; + + static NewsIconMgr *m_instance; +}; + +#endif // NEWSICONMGR_H diff --git a/knewsticker/common/xmlnewsaccess.cpp b/knewsticker/common/xmlnewsaccess.cpp new file mode 100644 index 00000000..1c892e8e --- /dev/null +++ b/knewsticker/common/xmlnewsaccess.cpp @@ -0,0 +1,132 @@ +/* + * xmlnewsaccess.cpp + * + * Copyright (c) 2001 Frerich Raabe <raabe@kde.org> + * + * 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. For licensing and distribution details, check the + * accompanying file 'COPYING'. + */ +#include "xmlnewsaccess.h" + +#include <kcharsets.h> +#include <kdebug.h> +#include <kglobal.h> + +#include <qbuffer.h> +#include <qdom.h> +#include <qregexp.h> + +XMLNewsArticle::XMLNewsArticle(const QString &headline, const KURL &address) + : m_headline(headline), + m_address(address) +{ +} + +XMLNewsArticle &XMLNewsArticle::operator=(const XMLNewsArticle &other) +{ + m_headline = other.m_headline; + m_address = other.m_address; + return *this; +} + +bool XMLNewsArticle::operator==(const XMLNewsArticle &a) +{ + return m_headline == a.headline() && m_address == a.address(); +} + +XMLNewsSource::XMLNewsSource() : QObject(), + m_name(QString::null), + m_link(QString::null), + m_description(QString::null), + m_downloadData(0) +{ +} + +XMLNewsSource::~XMLNewsSource() +{ + delete m_downloadData; // Might exist if we are in the middle of a download +} + +void XMLNewsSource::loadFrom(const KURL &url) +{ + if ( m_downloadData != 0 ) { + kdDebug( 5005 ) << "XMLNewsSource::loadFrom(): Busy, ignoring load " + "request for " << url << endl; + return; + } + m_downloadData = new QBuffer; + m_downloadData->open(IO_WriteOnly); + + KIO::Job *job = KIO::get(url, false, false); + job->addMetaData(QString::fromLatin1("UserAgent"), + QString::fromLatin1("KNewsTicker v0.2")); + connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), + SLOT(slotData(KIO::Job *, const QByteArray &))); + connect(job, SIGNAL(result(KIO::Job *)), SLOT(slotResult(KIO::Job *))); +} + +void XMLNewsSource::slotData(KIO::Job *, const QByteArray &data) +{ + m_downloadData->writeBlock(data.data(), data.size()); +} + +void XMLNewsSource::slotResult(KIO::Job *job) +{ + kdDebug(5005) << "XMLNewsSource::slotResult(): Finished downloading data (" << job->error() << ")." << endl; + processData(m_downloadData->buffer(), !job->error()); + delete m_downloadData; + m_downloadData = 0; +} + +void XMLNewsSource::processData(const QByteArray &data, bool okSoFar) +{ + bool validContent = okSoFar; + kdDebug(5005) << "XMLNewsSource::processData(): validContent = " << validContent << endl; + + if (okSoFar) { + /* + * Some servers prepend whitespace before the <?xml...?> declaration. + * Since QDom doesn't like that we strip this first. + */ + QDomDocument domDoc; + + const char *charData = data.data(); + int len = data.count(); + + while (len && (*charData == ' ' || *charData == '\n' || *charData == '\t' || *charData == '\r') ) { + len--; + charData++; + } + + QByteArray tmpData; + tmpData.setRawData(charData, len); + + if (validContent = domDoc.setContent(tmpData)) { + QDomNode channelNode = domDoc.documentElement().namedItem(QString::fromLatin1("channel")); + + m_name = channelNode.namedItem(QString::fromLatin1("title")).toElement().text().simplifyWhiteSpace(); + kdDebug(5005) << "XMLNewsSource::processData(): Successfully updated " << m_name << endl; + m_link = channelNode.namedItem(QString::fromLatin1("link")).toElement().text().simplifyWhiteSpace(); + m_description = channelNode.namedItem(QString::fromLatin1("description")).toElement().text().simplifyWhiteSpace(); + + QDomNodeList items = domDoc.elementsByTagName(QString::fromLatin1("item")); + m_articles.clear(); + QDomNode itemNode; + QString headline, address; + for (unsigned int i = 0; i < items.count(); i++) { + itemNode = items.item(i); + headline = KCharsets::resolveEntities(itemNode.namedItem(QString::fromLatin1("title")).toElement().text().simplifyWhiteSpace()); + address = KCharsets::resolveEntities(itemNode.namedItem(QString::fromLatin1("link")).toElement().text().simplifyWhiteSpace()); + m_articles.append(XMLNewsArticle(headline, KURL( address ))); + } + } + kdDebug(5005) << "XMLNewsSource::processData(): validContent = " << validContent << endl; + tmpData.resetRawData(charData, len); + } + + emit loadComplete(this, validContent); +} + +#include "xmlnewsaccess.moc" diff --git a/knewsticker/common/xmlnewsaccess.h b/knewsticker/common/xmlnewsaccess.h new file mode 100644 index 00000000..91cbf77f --- /dev/null +++ b/knewsticker/common/xmlnewsaccess.h @@ -0,0 +1,86 @@ +/* + * xmlnewsaccess.h + * + * Copyright (c) 2001 Frerich Raabe <raabe@kde.org> + * + * 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. For licensing and distribution details, check the + * accompanying file 'COPYING'. + */ +#ifndef XMLNEWSACCESS_H +#define XMLNEWSACCESS_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qvaluelist.h> +#include <qobject.h> + +#include <kio/job.h> +#include <kurl.h> + +class QBuffer; +class QDomDocument; +class XMLNewsSource; + +class XMLNewsArticle +{ + public: + typedef QValueList<XMLNewsArticle> List; + + XMLNewsArticle() {} + XMLNewsArticle(const QString &headline, const KURL &addresss); + XMLNewsArticle(const XMLNewsArticle &other) { (*this) = other; } + XMLNewsArticle &operator=(const XMLNewsArticle &other); + + QString headline() const { return m_headline; } + void setHeadline(const QString &headline) { m_headline = headline; } + + KURL address() const { return m_address; } + void setAddress(const KURL &address) { m_address = address; } + + bool operator== (const XMLNewsArticle &a); + bool operator!= (const XMLNewsArticle &a) { return !operator==(a); } + + private: + QString m_headline; + KURL m_address; +}; + +class XMLNewsSource : public QObject +{ + Q_OBJECT + + public: + XMLNewsSource(); + virtual ~XMLNewsSource(); + + void loadFrom(const KURL &); + + virtual QString newsSourceName() const { return m_name; } + virtual QString link() const { return m_link; } + virtual QString description() const { return m_description; } + const XMLNewsArticle::List &articles() const { return m_articles; } + + signals: + void loadComplete(XMLNewsSource *, bool); + + protected: + void processData(const QByteArray &, bool = true); + + QString m_name; + QString m_link; + QString m_description; + + private slots: + void slotData(KIO::Job *, const QByteArray &); + void slotResult(KIO::Job *); + + private: + XMLNewsArticle::List m_articles; + QBuffer *m_downloadData; +}; + +#endif // XMLNEWSACCESS_H |