diff options
Diffstat (limited to 'knewsticker')
40 files changed, 7327 insertions, 0 deletions
diff --git a/knewsticker/AUTHORS b/knewsticker/AUTHORS new file mode 100644 index 00000000..5c626223 --- /dev/null +++ b/knewsticker/AUTHORS @@ -0,0 +1,2 @@ +Frerich Raabe <raabe@kde.org> +Malte Starostik <malte@kde.org> diff --git a/knewsticker/COPYING b/knewsticker/COPYING new file mode 100644 index 00000000..cca2a5c9 --- /dev/null +++ b/knewsticker/COPYING @@ -0,0 +1,20 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/knewsticker/Makefile.am b/knewsticker/Makefile.am new file mode 100644 index 00000000..eea97be4 --- /dev/null +++ b/knewsticker/Makefile.am @@ -0,0 +1,34 @@ +SUBDIRS = common kntsrcfilepropsdlg knewstickerstub +INCLUDES = -I$(top_srcdir)/knewsticker/common $(all_includes) + +kde_module_LTLIBRARIES = knewsticker_panelapplet.la + +noinst_HEADERS = newsscroller.h knewsticker.h + +METASOURCES = AUTO + +knewsticker_panelapplet_la_SOURCES = newsscroller.cpp \ + knewsticker.cpp knewsticker.skel \ + knewstickerconfig.cpp knewstickerconfigwidget.ui \ + newssourcedlgimpl.cpp newssourcedlg.ui +knewsticker_panelapplet_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module +knewsticker_panelapplet_la_LIBADD = common/libknewstickercommon.la \ + $(LIB_KIO) $(LIB_KDEUI) + +appdatadir = $(kde_datadir)/knewsticker +appdata_DATA = eventsrc + +updatedir = $(kde_datadir)/kconf_update +update_DATA = knewsticker.upd +update_SCRIPTS = knt-0.1-0.2.pl + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = knewsticker.desktop + +xdg_apps_DATA = knewsticker-standalone.desktop + +KDE_ICON = AUTO + +messages: rc.cpp + $(EXTRACTRC) *.ui */*.ui >> rc.cpp + $(XGETTEXT) *.cpp *.h */*.cpp */*.h -o $(podir)/knewsticker.pot diff --git a/knewsticker/TODO b/knewsticker/TODO new file mode 100644 index 00000000..6d586831 --- /dev/null +++ b/knewsticker/TODO @@ -0,0 +1,10 @@ +TODO +---- +* Make KNewsTicker choose one of the rotated modes as soon as Kicker is moved + to one of the sides. +* Fix the highlighting of the headlines, right now the headlines stay + highlighted sometimes even if the mouse is moved away (i.e. with the context + menu) +* Make the "Suggest" function in the news source dialog work for program news + sources. +* Make it possible to pass parameters to external program newssources. 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 diff --git a/knewsticker/eventsrc b/knewsticker/eventsrc new file mode 100644 index 00000000..e3fdee2f --- /dev/null +++ b/knewsticker/eventsrc @@ -0,0 +1,335 @@ +[!Global!] +IconName=knewsticker +Comment=News Ticker +Comment[af]=Nuus Tikker +Comment[ar]=تجديد الأخبار +Comment[az]=Xəbər Gözləyici +Comment[be]=Аглядальнік навінаў +Comment[bg]=Четец на новини +Comment[bn]=সংবাদ টিকার +Comment[br]=Kliker keleier +Comment[bs]=Traka s vijestima +Comment[ca]=Teletip de notícies +Comment[cs]=Novinky +Comment[cy]=Ticer Newyddion +Comment[da]=Nyhedstelegraf +Comment[de]=Newsticker +Comment[el]=Προβολή ειδήσεων +Comment[eo]=Novaĵprezentilo +Comment[es]=Teletipo de noticias +Comment[et]=Uudiste jälgija +Comment[eu]=Berri markatzailea +Comment[fa]=تیکر اخبار +Comment[fi]=Uutisnäyttäjä +Comment[fr]=Téléscripteur +Comment[gl]=Teletipo +Comment[he]=צג חדשות +Comment[hi]=न्यूज टिकर +Comment[hr]=Ticker sa novostima +Comment[hu]=Hírmegjelenítő +Comment[id]=Ticker Berita +Comment[is]=Fréttastrimill +Comment[it]=Ticker notizie +Comment[ja]=ニュースティッカー +Comment[ka]=სიახლეების მიმღები +Comment[kk]=Жаңалық таспасы +Comment[km]=កម្មវិធីទទួលព័ត៌មាន +Comment[ko]=새소식 표시기 +Comment[lt]=Naujienų pranešėjas +Comment[lv]=Ziņu TIkkers +Comment[mk]=Лента со вести +Comment[mn]=Мэдээний Дэлгэц +Comment[ms]=Detik Berita +Comment[mt]=News ticker +Comment[nb]=Nyhetstelegraf +Comment[nds]=Narichten-Ticker +Comment[ne]=समाचार टिकर +Comment[nl]=Nieuwslezer +Comment[nn]=Nyhendetelegraf +Comment[nso]=Seswai sa Ditaba +Comment[pt]=Notícias +Comment[pt_BR]=Mini-aplicativo de notícias +Comment[ro]=Ştiri Internet +Comment[ru]=Монитор новостей +Comment[se]=Ođastelegráfa +Comment[sk]=Sledovač správ +Comment[sl]=Prikazovalnik novic +Comment[sr]=Пратилац вести +Comment[sr@Latn]=Pratilac vesti +Comment[sv]=Nyhetsövervakare +Comment[ta]=செய்தி அறிவிப்பான் +Comment[tg]=Дидабони Ахборот +Comment[th]=ตั๋วข่าว +Comment[tr]=Haber Gözlemcisi +Comment[uk]=Стрічка новин +Comment[ven]=Musengulusi wa Mafhungo +Comment[zh_CN]=新闻简报 +Comment[zh_HK]=新聞快報 +Comment[zh_TW]=新聞簡報 +Comment[zu]=Umlungiseleli Wezindaba + +[NewNews] +Name=New News Available +Name[af]=Nuwe Nuus Beskikbaar +Name[ar]=توجد أخبار جديدة +Name[az]=Mövcud Yeni Xəbərlər +Name[be]=Ёсць навіны +Name[bg]=Пристигнаха нови новини +Name[bn]=নতুন সংবাদ পাওয়া যাচ্ছে +Name[br]=Keleier nevez da gaout +Name[bs]=Nove vijesti su dostupne +Name[ca]=Noves notícies disponibles +Name[cs]=Jsou dostupné nové zprávy +Name[cy]=Newyddion Newydd ar Gael +Name[da]=Nye nyheder tilgængelige +Name[de]=Neu eingetroffene Nachrichten +Name[el]=Καινούριες ειδήσεις διαθέσιμες +Name[eo]=Novaj diskutmesaĝoj +Name[es]=Nuevas noticias disponibles +Name[et]=Uus uudis +Name[eu]=Azken berriak eskuragarri +Name[fa]=خبرهای جدید در دسترس +Name[fi]=Uutisia saatavilla +Name[fr]=Des nouvelles sont arrivées +Name[ga]=Nuacht Nua ar Fáil +Name[gl]=Novas noticias dispoñibles +Name[he]=ישנן חדשות זמינות +Name[hi]=नया समाचार उपलब्ध +Name[hr]=Novosti su raspoložive +Name[hu]=Új hír érkezett +Name[id]=Berita baru tersedia +Name[is]=Nýjar fréttir komnar +Name[it]=Nuove notizie disponibili +Name[ja]=新着ニュース +Name[ka]=ახალი სიახლეები ხელმისაწვდომია +Name[kk]=Жаңалықтар бар +Name[km]=មានព័ត៌មានថ្មី +Name[ko]=새로운 소식이 있습니다 +Name[lt]=Yra šviežių naujienų +Name[lv]=Jaunas Ziņas Pieejamas +Name[mk]=Има нови вести +Name[mn]=Шинэ Мэдээ гарлаа +Name[ms]=Ada Berita Mutakhir +Name[mt]=Aħbarijiet ġodda +Name[nb]=Nye artikler tilgjengelige +Name[nds]=Nieg Narichten verföögbor +Name[ne]=नयाँ समाचार उपलब्ध छ +Name[nl]=Nieuw nieuws beschikbaar +Name[nn]=Nyhende tilgjengeleg +Name[nso]=Ditaba tse Diswa di Gona +Name[pa]=ਨਵੀਆਂ ਖ਼ਬਰਾਂ ਉਪਲੱਬਧ ਹਨ +Name[pl]=Dostępne nowe wiadomości +Name[pt]=Estão novas notícias disponíveis +Name[pt_BR]=Novas notícias +Name[ro]=Nu există ştiri noi +Name[ru]=Есть новости +Name[se]=Ođđa ođđasat olamuttus +Name[sk]=Nové správy +Name[sl]=Na voljo so sveže novice +Name[sr]=Доступне су нове вести +Name[sr@Latn]=Dostupne su nove vesti +Name[sv]=Det har kommit nya nyheter +Name[ta]=புதிய செய்திகள் உள்ளன +Name[tg]=Ахборотҳои Нав Дастрасанд +Name[th]=ข่าวใหม่ที่มี +Name[tr]=Mevcut Yeni Haberler +Name[uk]=Останні новини +Name[ven]=Mafhungo maswa are hone +Name[xh]=Iindaba Ezintsha Ezikhoyo +Name[zh_CN]=有新的新闻 +Name[zh_HK]=有新的新聞 +Name[zh_TW]=有新的新聞 +Name[zu]=Izindaba Ezintsha Ziyatholakala manje +Comment=There is new news available +Comment[af]=Daar is nuwe nuus beskikbaar +Comment[ar]=هناك أخبار جديدة +Comment[az]=Yeni xəbərlər mövcuddur +Comment[be]=Ёсць навіны +Comment[bg]=Пристигнаха нови новини +Comment[bn]=নতুন সংবাদ পাওয়া যাচ্ছে +Comment[bs]=Sada ima novih vijesti +Comment[ca]=Hi ha noves notícies disponibles +Comment[cs]=Jsou dostupné nové zprávy +Comment[cy]=Mae newyddion newydd ar gael +Comment[da]=Der er nye nyheder tilgængelige +Comment[de]=Es sind neue Nachrichten eingetroffen +Comment[el]=Υπάρχουν καινούριες ειδήσεις διαθέσιμες +Comment[eo]=Alvenis novaj diskutmesaĝoj +Comment[es]=Hay nuevas noticias disponibles +Comment[et]=Uusi uudiseid pole +Comment[eu]=Azken berriak eskuragarri +Comment[fa]=اخبار جدید در دسترس است +Comment[fi]=Uutisia saatavilla +Comment[fr]=De nouvelles informations sont arrivées. +Comment[ga]=Tá nuacht nua ar fáil +Comment[gl]=Hai novas noticias dispoñibles +Comment[he]=ישנן חדשות זמינות +Comment[hi]=वहाँ नया समाचार उपलब्ध है +Comment[hr]=Postoje nove novosti +Comment[hu]=Új hír érkezett. +Comment[id]=Ada berita baru tersedia +Comment[is]=Nýjar fréttir hafa borist +Comment[it]=C'è una nuova notizia disponibile +Comment[ja]=新しいニュースが届きました +Comment[ka]=სიახლეები არ არის ხელმისაწვდომი +Comment[kk]=Жаңалықтар бар +Comment[km]=មានព័ត៌មានថ្មីហើយ +Comment[ko]=새로운 소식이 있습니다 +Comment[lt]=Yra šviežių naujienų +Comment[lv]=Šeit ir jaunas ziņas pieejamas +Comment[mk]=Има нови вести +Comment[mn]=Мэдээ гарлаа +Comment[ms]=Berita mutakhir hari ini +Comment[mt]=Hemm aħbarijiet ġodda +Comment[nb]=Det er nye artikler tilgjengelig +Comment[nds]=Dat gifft niege Narichten +Comment[ne]=त्यहाँ नयाँ समाचार उपलब्ध छ +Comment[nl]=Er is nieuw nieuws beschikbaar +Comment[nn]=Nyhende tilgjengeleg +Comment[nso]=Gona le ditaba tse diswa tseo di lego gona +Comment[pl]=Jest nowa wiadomość +Comment[pt]=Existem novas notícias disponíveis +Comment[pt_BR]=Há novas notícias +Comment[ro]=Nu există ştiri noi +Comment[ru]=Есть новости +Comment[se]=Leat varas ođđasat olamuttus +Comment[sk]=Žiadne nové správy +Comment[sl]=Na voljo so sveže novice +Comment[sr]=Има нових вести +Comment[sr@Latn]=Ima novih vesti +Comment[sv]=Det har kommit nya nyheter +Comment[ta]=புதிய செய்திகள் உள்ளன +Comment[tg]=Ахборотҳои нав дастрасанд +Comment[th]=นี่เป็นข่าวใหม่ที่มี +Comment[tr]=Yeni haberler var +Comment[uk]=Надійшли свіжі новини +Comment[ven]=Huna mafhungo maswa are hone +Comment[xh]=Kukho iindaba ezintsha ezikhoyo +Comment[zh_CN]=有新的新闻 +Comment[zh_HK]=有新的新聞 +Comment[zh_TW]=有新的新聞 +Comment[zu]=Kukhona izindaba ezintsha ezitholakalayo +default_sound= +default_presentation=1 + +[InvalidRDF] +Name=Invalid RDF file +Name[af]=Ongeldige Rdf lêer +Name[ar]=ملف RDF غير صالح +Name[az]=Xətalı RDF faylı +Name[be]=Няправільны файл RDF +Name[bg]=Невалиден файл RDF +Name[bn]=অবৈধ আর-ডি-এফ ফাইল +Name[br]=N'eo ket mat ar restr RDF +Name[bs]=Neispravna RDF datoteka +Name[ca]=Fitxer RDF no vàlid +Name[cs]=Neplatný RDF soubor +Name[cy]=Ffeil RDF annilys +Name[da]=Ugyldig RDF-fil +Name[de]=Ungültige RDF-Datei +Name[el]=Μη έγκυρο αρχείο RDF +Name[eo]=Nevalida RDF-dosierojn +Name[es]=Archivo RDF no válido +Name[et]=Vigane RDF-fail +Name[eu]=RDF fitxategia baliogabea da +Name[fa]=پروندۀ RDF نامعتبر +Name[fi]=Virheellinen RDF-tiedosto +Name[fr]=Fichier RDF non valable +Name[ga]=Comhad RDF Neamhbhailí +Name[gl]=Fichero RDF inválido +Name[he]=קובץ RDF לא תקף +Name[hi]=अवैध RDF फ़ाइल +Name[hr]=Nevažeća RDF datoteka +Name[hu]=Érvénytelen RDF fájl +Name[id]=Berkas RDF rusak +Name[is]=Ógild RDF skrá +Name[it]=File RDF non valido +Name[ja]=不正な RDF ファイル +Name[ka]=არასწორი RDF ფაილი +Name[kk]=Жарамсыз RDF файл +Name[km]=ឯកសារ RDF មិនត្រឹមត្រូវ +Name[ko]=잘못된 RDF 파일 +Name[lt]=Neteisinga RDF byla +Name[lv]=Nepareizs RDF fails +Name[mk]=Невалидна RDF-датотека +Name[mn]=Буруу RDF файл +Name[ms]=Fail RDF tidak sah +Name[mt]=Fajl RDF invalidu +Name[nb]=Ugyldig RDF-fil +Name[nds]=Leeg RDF-Datei +Name[ne]=अवैध आर डी एफ फाइल +Name[nl]=Ongeldig RDF-bestand +Name[nn]=Ugyldig RDF-fil +Name[nso]=Faele ya RDF yeo esa dumelelwago +Name[pl]=Nieprawidłowy plik RDF +Name[pt]=Ficheiro RDF inválido +Name[pt_BR]=Arquivo RDF inválido +Name[ro]=Fişier RDF eronat +Name[ru]=Неверный RDF файл +Name[se]=Gustomeahttun RDF-fiila +Name[sk]=Neplatný súbor RDF +Name[sl]=Neveljavna datoteka PDF +Name[sr]=Погрешан RDF фајл +Name[sr@Latn]=Pogrešan RDF fajl +Name[sv]=Ogiltig RDF-fil +Name[ta]=வலிதற்ற RDF ஆவணம் +Name[tg]=RDF файли нодуруст +Name[th]=แฟ้ม RDF ไม่ถูกต้อง +Name[tr]=Hatalı RDF dosyası +Name[uk]=Невірний файл RDF +Name[ven]=Faela ya RDF isina tshithu +Name[wa]=Fitchî RDF nén valide +Name[xh]=Ifayile ye RDF engasebenziyo +Name[zh_CN]=无效的 RDF 文件 +Name[zh_HK]=無效的 RDF 檔案 +Name[zh_TW]=無效的 RDF 檔案 +Name[zu]=Ifayela Engasebenziyo ye RDF +Comment=The downloaded RDF file could not be parsed +Comment[be]=Немагчыма апрацаваць сцягнуты файл RDF +Comment[bg]=Изтегленият файл RDF не може да бъде анализиран +Comment[bn]=ডাউনলোডকৃত আর-ডি-এফ ফাইল পার্স করতে পারল না +Comment[bs]=Ne mogu protumačiti pribavljenu RDF datoteku +Comment[ca]=El fitxer RDF descarregat no s'ha pogut analitzar +Comment[cs]=Analýza stáhnutého RDF souboru selhala +Comment[da]=Den hentede RDF-fil kunne ikke fortolkes +Comment[de]=Die heruntergeladene RDF-Datei kann nicht eingelesen werden +Comment[el]=Το αρχείο που λήφθηκε RDF ήταν αδύνατο να αναλυθεί +Comment[eo]=La elŝutita RDF-dosiero ne estis analizebla +Comment[es]=El archivo RDF descargado no se pudo analizar +Comment[et]=Allalaaditud RDF-faili pole võimalik parsida +Comment[eu]=Deskargatutako RDF fitxategia ezin izan da aztertu +Comment[fa]=پروندۀ بارگیریشدۀ RDF نتوانست تجزیه شود +Comment[fi]=Haettua RDF-tiedostoa ei saatu jäsennettyä +Comment[fr]=Le fichier RDF téléchargé n'a pas pu être analysé +Comment[ga]=Ní féidir an comhad RDF íosluchtaithe a pharsáil +Comment[gl]=O ficheiro RDF descargado non se puido interpretar +Comment[he]=אין אפשרות לנתח את קובץ ה-RDF שהורד +Comment[hu]=A letöltött RDF-fájlt nem sikerült feldolgozni +Comment[is]=Gat ekki þáttað RDF skrána sem var sótt +Comment[it]=Il file RDF scaricato non può essere interpretato +Comment[ja]=ダウンロードされた RDF ファイルは解読できません +Comment[ka]=ჩამოქაჩული RDF ფაილის გაანალიზება ვერ განხორციელდა +Comment[kk]=Түсіріп алынған RDF талдауға келмеді +Comment[km]=មិនអាចញែកឯកសារ RDF ដែលបានទាញយកបានឡើយ +Comment[lt]=Nepavyko apdoroti atsisiųstos RDF bylos +Comment[nb]=Kunne ikke tolke RDF-fila som ble lastet ned +Comment[nds]=De daallaadt RDF-Datei lett sik nich inlesen +Comment[ne]=डाउनलोड गरिएको आर डी एफ फाइल पद वर्णन गर्न सकेन +Comment[nl]=Het gedownloade RDF-bestand kon niet worden ontleed +Comment[nn]=Klarte ikkje tolka den nedlasta RDF-fila +Comment[pl]=Ściągnięty plik RDF ma złą składnię +Comment[pt]=Não foi possível processar o ficheiro RDF transferido +Comment[pt_BR]=O arquivo RDF obtido não pôde ser interpretado +Comment[ro]=Fişierul RDF transferat nu poate fi analizat +Comment[ru]=Не удалось разобрать загруженный RDF-файл +Comment[sk]=Stiahnutý RDF súbor nie je možné analyzovať +Comment[sl]=Prenesene datoteke RDF ni moč razčleniti +Comment[sr]=Преузети RDF фајл не може да се рашчлани +Comment[sr@Latn]=Preuzeti RDF fajl ne može da se raščlani +Comment[sv]=Den nerladdade RDF-filen kunde inte tolkas +Comment[tr]=İndirilen RDF dosyası ayrıştırılamadı +Comment[uk]=Не вдалось проаналізувати звантажений файл RDF +Comment[zh_CN]=下载的 RDF 无法分析 +Comment[zh_HK]=下載的 RDF 檔案無法解析 +Comment[zh_TW]=下載的 RDF 無法分析 +default_presentation=0 diff --git a/knewsticker/hi16-app-knewsticker.png b/knewsticker/hi16-app-knewsticker.png Binary files differnew file mode 100644 index 00000000..a450d096 --- /dev/null +++ b/knewsticker/hi16-app-knewsticker.png diff --git a/knewsticker/hi32-app-knewsticker.png b/knewsticker/hi32-app-knewsticker.png Binary files differnew file mode 100644 index 00000000..36b0f702 --- /dev/null +++ b/knewsticker/hi32-app-knewsticker.png diff --git a/knewsticker/hi48-app-knewsticker.png b/knewsticker/hi48-app-knewsticker.png Binary files differnew file mode 100644 index 00000000..447b6813 --- /dev/null +++ b/knewsticker/hi48-app-knewsticker.png diff --git a/knewsticker/knewsticker-standalone.desktop b/knewsticker/knewsticker-standalone.desktop new file mode 100644 index 00000000..d31a44b1 --- /dev/null +++ b/knewsticker/knewsticker-standalone.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +Name=KNewsTicker +Name[af]=K-nuustikker +Name[ar]=مجدد أخبار كيدي +Name[bn]=কে-নিউজ-টিকার +Name[cy]=KTicerNewyddion +Name[eo]=Novaĵprezentilo +Name[he]=KNewsTicker - צג חדשות +Name[hi]=के-न्यूज-टिकर +Name[lv]=KZiņuTikkers +Name[nb]=Nyhetstelegraf +Name[ne]=केडीई न्यूज टिकर +Name[nso]=Seswai sa KDitaba +Name[pt_BR]=Mostrador de Notícias +Name[sv]=Knewsticker +Name[ta]=கேசெய்தி அறிவிப்பான் +Name[tg]=KДидабони Ахборот +Name[th]=ตั๋วข่าว - K +Name[tr]=KDE Haber Gözlemcisi +Name[ven]=Musengulusi wa mafhungo a K +Name[zu]=Umlungiseleli Wezindaba ze K +Type=Application +Exec=appletproxy knewsticker.desktop +Icon=knewsticker +DocPath=knewsticker/index.html +GenericName=News Ticker +GenericName[af]=Nuus Tikker +GenericName[ar]=تجديد الأخبار +GenericName[az]=Xəbər Gözləyici +GenericName[be]=Аглядальнік навінаў +GenericName[bg]=Четец на новини +GenericName[bn]=সংবাদ টিকার +GenericName[br]=Kliker keleier +GenericName[bs]=Traka s vijestima +GenericName[ca]=Teletip de notícies +GenericName[cs]=Novinky +GenericName[cy]=Ticer Newyddion +GenericName[da]=Nyhedstelegraf +GenericName[de]=Newsticker +GenericName[el]=Προβολή ειδήσεων +GenericName[eo]=Novaĵprezentilo +GenericName[es]=Teletipo de noticias +GenericName[et]=Uudiste jälgija +GenericName[eu]=Berri markatzailea +GenericName[fa]=تیکر اخبار +GenericName[fi]=Uutisnäyttäjä +GenericName[fr]=Téléscripteur +GenericName[gl]=Teletipo de noticias +GenericName[he]=צג חדשות +GenericName[hi]=न्यूज टिकर +GenericName[hr]=Ticker sa novostima +GenericName[hu]=RSS hírbejelentő +GenericName[id]=Ticker Berita +GenericName[is]=Fréttastrimill +GenericName[it]=Ticker notizie +GenericName[ja]=ニュースティッカー +GenericName[ka]=სიახლეების მიმღები +GenericName[kk]=Жаңалық таспасы +GenericName[km]=កម្មវិធីទទួលព័ត៌មាន +GenericName[ko]=새소식 표시기 +GenericName[lt]=Naujienų pranešėjas +GenericName[lv]=Ziņu TIkkers +GenericName[mk]=Лента со вести +GenericName[mn]=Мэдээний Дэлгэц +GenericName[ms]=Detik Berita +GenericName[nb]=Nyhetstelegraf +GenericName[nds]=Narichten-Ticker +GenericName[ne]=समाचार टिकर +GenericName[nl]=Nieuws-lichtkrant +GenericName[nn]=Nyhendetelegraf +GenericName[nso]=Seswai sa Ditaba +GenericName[pt]=Notícias +GenericName[pt_BR]=Mini-aplicativo de notícias +GenericName[ro]=Ştiri Internet +GenericName[ru]=Монитор новостей +GenericName[se]=Ođastelegráfa +GenericName[sk]=Sledovač správ +GenericName[sl]=Prikazovalnik novic +GenericName[sr]=Пратилац вести +GenericName[sr@Latn]=Pratilac vesti +GenericName[sv]=Nyhetsövervakare +GenericName[ta]=செய்தி அறிவிப்பான் +GenericName[tg]=Дидабони Ахборот +GenericName[th]=ตั๋วข่าว +GenericName[tr]=Haber Gözlemcisi +GenericName[uk]=Стрічка новин +GenericName[ven]=Musengulusi wa Mafhungo +GenericName[zh_CN]=新闻播报器 +GenericName[zh_HK]=新聞快報 +GenericName[zh_TW]=新聞簡報 +GenericName[zu]=Umlungiseleli Wezindaba +Terminal=false +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Unique +Categories=Qt;KDE;Network;X-KDE-More;News; diff --git a/knewsticker/knewsticker.cpp b/knewsticker/knewsticker.cpp new file mode 100644 index 00000000..6d2f90cb --- /dev/null +++ b/knewsticker/knewsticker.cpp @@ -0,0 +1,546 @@ +/* + * knewsticker.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 "knewsticker.h" +#include "newsengine.h" +#include "newsscroller.h" +#include "configaccess.h" +#include "newsiconmgr.h" +#include "knewstickerconfig.h" + +#include <kaboutapplication.h> +#include <kapplication.h> +#include <karrowbutton.h> +#include <kbugreport.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <knotifyclient.h> +#include <kprocess.h> +#include <kprotocolmanager.h> +#include <kstandarddirs.h> +#include <kstartupinfo.h> + +#include <qcursor.h> +#include <qlayout.h> +#include <qtimer.h> +#include <qtooltip.h> + +#include <dcopclient.h> + +KNewsTicker::KNewsTicker(const QString &cfgFile, Type t, int actions, QWidget *parent, const char *name) + : ConfigIface(), DCOPObject("KNewsTicker"), + KPanelApplet(cfgFile, t, actions, parent, name), + m_instance(new KInstance("knewsticker")), + m_dcopClient(new DCOPClient()), + m_cfg(new ConfigAccess(config())), + m_newsTimer(new QTimer(this)), + m_updateTimer(new QTimer(this)), + m_newsIconMgr(NewsIconMgr::self()), + m_aboutData(new KAboutData("knewsticker", I18N_NOOP("KNewsTicker"), "v0.2", + I18N_NOOP("A news ticker applet."), KAboutData::License_BSD, + I18N_NOOP("(c) 2000, 2001 The KNewsTicker developers"))) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + + m_contextMenu = new KNewsTickerMenu(this); + connect(m_contextMenu, SIGNAL(aboutToHide()), + SLOT(slotContextMenuAboutToHide())); + setCustomMenu(m_contextMenu); + + m_arrowButton = new KArrowButton(this); + QToolTip::add(m_arrowButton, i18n("Show menu")); + connect(m_arrowButton, SIGNAL(clicked()), SLOT(slotArrowButtonPressed())); + m_arrowButton->setFocusPolicy(NoFocus); + setupArrowButton(); + layout->addWidget(m_arrowButton); + + m_scroller = new NewsScroller(this, m_cfg); + layout->addWidget(m_scroller); + + m_dcopClient->registerAs("knewsticker", false); + + QToolTip::add(m_scroller, QString::null); + connect(m_scroller, SIGNAL(contextMenu()), SLOT(slotOpenContextMenu())); + + connect(m_newsTimer, SIGNAL(timeout()), SLOT(slotUpdateNews())); + + connect(m_updateTimer, SIGNAL(timeout()), SLOT(slotNotifyOfFailures())); + + m_aboutData->addAuthor("Frerich Raabe", I18N_NOOP("Original author"), + "raabe@kde.org"); + m_aboutData->addAuthor("Malte Starostik", I18N_NOOP("Hypertext headlines" + " and much more"), "malte@kde.org"); + m_aboutData->addAuthor("Wilco Greven", I18N_NOOP("Mouse wheel support"), + "greven@kde.org"); + m_aboutData->addAuthor("Adriaan de Groot", I18N_NOOP("Rotated scrolling text" + " modes"), "adridg@sci.kun.nl"); + + reparseConfig(); + + KStartupInfo::appStarted(); +} + +KNewsTicker::~KNewsTicker() +{ + delete m_cfg; + delete m_dcopClient; +} + +int KNewsTicker::heightForWidth(int) const +{ + return m_scroller->sizeHint().height() + m_arrowButton->height(); +} + +int KNewsTicker::widthForHeight(int) const +{ + return m_scroller->sizeHint().width() + m_arrowButton->width(); +} + +void KNewsTicker::preferences() +{ + KNewsTickerConfig dlg(m_cfg, this); + if (dlg.exec() == QDialog::Accepted) { + reparseConfig(); + } +} + +void KNewsTicker::about() +{ + KAboutApplication aboutDlg(m_aboutData); + aboutDlg.exec(); +} + +void KNewsTicker::help() +{ + kapp->invokeHelp(QString::null, QString::fromLatin1("knewsticker")); +} + +void KNewsTicker::reportBug() +{ + KBugReport bugReport(this, true, m_aboutData); + bugReport.exec(); +} + +void KNewsTicker::reparseConfig() +{ + m_cfg->reparseConfiguration(); + m_newsSources.clear(); + + QStringList newsSources = m_cfg->newsSources(); + QStringList::ConstIterator it = newsSources.begin(); + QStringList::ConstIterator end = newsSources.end(); + for (; it != end; ++it) { + NewsSourceBase::Ptr ns = m_cfg->newsSource((*it)); + if (!ns->data().enabled) + continue; + + connect(ns, SIGNAL(newNewsAvailable(const NewsSourceBase::Ptr &, bool)), + SLOT(slotNewsSourceUpdated(const NewsSourceBase::Ptr &, bool))); + connect(ns, SIGNAL(invalidInput(const NewsSourceBase::Ptr &)), + SLOT(slotNewsSourceFailed(const NewsSourceBase::Ptr &))); + m_newsSources.append(ns); + } + + setOfflineMode(m_cfg->offlineMode()); + if (!m_cfg->offlineMode()) + slotUpdateNews(); +} + +void KNewsTicker::slotUpdateNews() +{ + kdDebug(5005) << "slotUpdateNews()" << endl; + m_newNews = false; + + m_updateTimer->start(KProtocolManager::responseTimeout(), true); + + m_failedNewsUpdates.clear(); + m_pendingNewsUpdates.clear(); + + m_scroller->clear(); + + NewsSourceBase::List::Iterator it = m_newsSources.begin(); + NewsSourceBase::List::Iterator end = m_newsSources.end(); + for (; it != end; ++it) { + m_pendingNewsUpdates += (*it)->data().name; + (*it)->retrieveNews(); + (*it)->getIcon(); + } + kdDebug(5005) << "m_pendingNewsUpdates = " << m_pendingNewsUpdates.join(",") + << endl; +} + +void KNewsTicker::slotNewsSourceUpdated(const NewsSourceBase::Ptr &ns, + bool newNews) +{ + kdDebug(5005) << "slotNewsSourceUpdate()" << endl; + if (newNews) + m_newNews = true; + + if (!ns->articles().isEmpty()) + if (m_cfg->scrollMostRecentOnly()) + m_scroller->addHeadline(ns->articles().first()); + else { + Article::List articles = ns->articles(); + Article::List::ConstIterator artIt = articles.begin(); + Article::List::ConstIterator artEnd = articles.end(); + for (; artIt != artEnd; ++artIt) + m_scroller->addHeadline(*artIt); + } + + m_scroller->reset(true); + + m_pendingNewsUpdates.remove(ns->data().name); + kdDebug(5005) << "Updated news source: '" << ns->data().name << "'" << "\n" + << "m_pendingNewsUpdates = " << m_pendingNewsUpdates.join(",") << "\n" + << "m_failedNewsUpdates = " << m_failedNewsUpdates.join(",") + << endl; + + if (!m_pendingNewsUpdates.isEmpty()) + return; + + m_updateTimer->stop(); + + if (!m_failedNewsUpdates.isEmpty()) + slotNotifyOfFailures(); + + if (m_newNews) { + KNotifyClient::Instance instance(m_instance); + KNotifyClient::event(winId(), QString::fromLatin1("NewNews")); + } +} + +void KNewsTicker::slotNewsSourceFailed(const NewsSourceBase::Ptr &ns) +{ + m_failedNewsUpdates += ns->newsSourceName(); + slotNewsSourceUpdated(ns); +} + +void KNewsTicker::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == QMouseEvent::RightButton) + slotOpenContextMenu(); +} + +void KNewsTicker::slotOpenContextMenu() +{ + m_contextMenu->setFullMenu(true); + m_contextMenu->exec(QCursor::pos()); +} + +void KNewsTicker::slotArrowButtonPressed() +{ + QPoint pos(m_arrowButton->mapToGlobal(QPoint(0, 0))); + QSize size(m_arrowButton->size()); + + if (position() == KPanelApplet::pTop) { + pos.setY(pos.y() + size.height() + 2); + } else if (position() == KPanelApplet::pBottom) { + const int y = pos.y() - m_contextMenu->sizeHint().height() - 2; + pos.setY(QMAX(0, y)); + } else if (position() == KPanelApplet::pLeft ) { + pos.setX(pos.x() + size.width() + 2); + } else { // position() == KPanelApplet::pRight + const int x = pos.x() - m_contextMenu->sizeHint().width() - 2; + pos.setX(QMAX(0, x)); + } + + m_contextMenu->setFullMenu(true); + m_contextMenu->exec(pos); +} + +void KNewsTicker::positionChange(Position) +{ + delete layout(); + + QBoxLayout *layout; + + if (orientation() == Horizontal) + layout = new QHBoxLayout(this); + else + layout = new QVBoxLayout(this); + + if (m_arrowButton) { + layout->addWidget(m_arrowButton); + setupArrowButton(); + } + + layout->addWidget(m_scroller); +} + +void KNewsTicker::slotContextMenuAboutToHide() +{ + if (m_arrowButton) + m_arrowButton->setDown(false); +} + +void KNewsTicker::slotNotifyOfFailures() +{ + KNotifyClient::Instance instance(m_instance); + QString notification = QString::null; + + if (m_failedNewsUpdates.count() == 1) + notification = i18n("<qt>Could not update news site '%1'.<br>" + "The supplied resource file is probably invalid or" + " broken.</qt>").arg(m_failedNewsUpdates.first()); + else if (m_failedNewsUpdates.count() > 1 && m_failedNewsUpdates.count() < 8) { + notification = i18n("<qt>The following news sites had problems. Their" + " resource files are probably invalid or broken.<ul>"); + QStringList::ConstIterator it = m_failedNewsUpdates.begin(); + QStringList::ConstIterator end = m_failedNewsUpdates.end(); + for (; it != end; ++it) + notification += QString::fromLatin1("<li>%1</li>").arg(*it); + notification += QString::fromLatin1("</ul></qt>"); + } else + notification = i18n("Failed to update several news" + " sites. The Internet connection might be cut."); + + KNotifyClient::event(winId(), QString::fromLatin1("InvalidRDF"), notification); +} + +void KNewsTicker::setInterval(const uint interval) +{ + m_cfg->setInterval(interval); + if ( interval > 4 ) + m_newsTimer->changeInterval(interval * 60 * 1000); +} + +void KNewsTicker::setScrollingSpeed(const uint scrollingSpeed) +{ + m_cfg->setScrollingSpeed(scrollingSpeed); + m_scroller->reset(true); +} + +void KNewsTicker::setMouseWheelSpeed(const uint mouseWheelSpeed) +{ + m_cfg->setMouseWheelSpeed(mouseWheelSpeed); +} + +void KNewsTicker::setScrollingDirection(const uint scrollingDirection) +{ + m_cfg->setScrollingDirection(scrollingDirection); + m_scroller->reset(true); +} + +void KNewsTicker::setCustomNames(bool customNames) +{ + m_cfg->setCustomNames(customNames); +} + +void KNewsTicker::setScrollMostRecentOnly(bool scrollMostRecentOnly) +{ + m_cfg->setScrollMostRecentOnly(scrollMostRecentOnly); + m_scroller->reset(true); +} + +void KNewsTicker::setOfflineMode(bool offlineMode) +{ + if (offlineMode) + m_newsTimer->stop(); + else + if ( m_cfg->interval() > 4 ) + m_newsTimer->start(m_cfg->interval() * 1000 * 60); + + m_cfg->setOfflineMode(offlineMode); +} + +void KNewsTicker::setUnderlineHighlighted(bool underlineHighlighted) +{ + m_cfg->setUnderlineHighlighted(underlineHighlighted); + m_scroller->reset(true); +} + +void KNewsTicker::setShowIcons(bool showIcons) +{ + m_cfg->setShowIcons(showIcons); + m_scroller->reset(true); +} + +void KNewsTicker::setSlowedScrolling(bool slowedScrolling) +{ + m_cfg->setSlowedScrolling(slowedScrolling); +} + +void KNewsTicker::setForegroundColor(const QColor &foregroundColor) +{ + m_cfg->setForegroundColor(foregroundColor); + m_scroller->reset(false); +} + +void KNewsTicker::setBackgroundColor(const QColor &backgroundColor) +{ + m_cfg->setBackgroundColor(backgroundColor); + m_scroller->reset(false); +} + +void KNewsTicker::setHighlightedColor(const QColor &highlightedColor) +{ + m_cfg->setHighlightedColor(highlightedColor); + m_scroller->reset(false); +} + +void KNewsTicker::setupArrowButton() +{ + ArrowType at; + + if (orientation() == Horizontal) { + m_arrowButton->setFixedWidth(12); + m_arrowButton->setMaximumHeight(128); + at = (position() == KPanelApplet::pTop ? DownArrow : UpArrow); + } else { + m_arrowButton->setMaximumWidth(128); + m_arrowButton->setFixedHeight(12); + at = (position() == KPanelApplet::pLeft ? RightArrow : LeftArrow); + } + m_arrowButton->setArrowType(at); +} + +KNewsTickerMenu::KNewsTickerMenu(KNewsTicker *parent, const char *name) + : KPopupMenu(parent, name), + m_parent(parent), + m_fullMenu(false) +{ + populateMenu(); +} + +void KNewsTickerMenu::populateMenu() +{ + clear(); + + /* + * Perhaps this hardcoded stuff should be replaced by some kind of + * themeing functionality? + */ + const QPixmap lookIcon = SmallIcon(QString::fromLatin1("viewmag")); + const QPixmap newArticleIcon = SmallIcon(QString::fromLatin1("info")); + const QPixmap oldArticleIcon = SmallIcon(QString::fromLatin1("mime_empty")); + const QPixmap noArticlesIcon = SmallIcon(QString::fromLatin1("remove")); + + unsigned int articleIdx = 0; + const NewsSourceBase::List sources = m_parent->m_newsSources; + NewsSourceBase::List::ConstIterator nIt = sources.begin(); + for (; nIt != sources.end(); ++nIt) { + NewsSourceBase::Ptr ns = *nIt; + + KPopupMenu *submenu = new KPopupMenu; + int checkNewsId = submenu->insertItem(lookIcon, i18n("Check News"), this, SLOT(slotCheckNews(int)), 0, sources.findIndex(ns) + 1000); + setItemParameter(checkNewsId, sources.findIndex(ns)); + + submenu->insertSeparator(); + + if (m_parent->m_pendingNewsUpdates.contains(ns->newsSourceName())) { + submenu->insertItem(noArticlesIcon, i18n("Currently Being Updated, No Articles Available")); + } else if (!ns->articles().isEmpty()) { + const Article::List articles = ns->articles(); + Article::List::ConstIterator artIt = articles.begin(); + for (; artIt != articles.end(); ++artIt) { + Article::Ptr a = *artIt; + QString headline = a->headline().replace('&', "&&"); + int id; + if ( a->read() ) + id = submenu->insertItem(oldArticleIcon, headline, this, SLOT(slotOpenArticle(int)), 0, articleIdx+2000); + else + id = submenu->insertItem(newArticleIcon, headline, this, SLOT(slotOpenArticle(int)), 0, articleIdx+2000); + kdDebug( 5005 ) << "Setting articles index for " << a->headline() << " to " << articleIdx << endl; + setItemParameter( id, articleIdx++ ); + } + } else { + submenu->insertItem(noArticlesIcon, i18n("No Articles Available")); + } + + insertItem(ns->icon(), ns->newsSourceName().replace('&', "&&"), submenu); + } + + if (!m_parent->m_cfg->newsSources().isEmpty()) + insertSeparator(); + + insertItem(lookIcon, i18n("Check News"), m_parent, SLOT(slotUpdateNews())); + int i = insertItem(i18n("Offline Mode"), this, SLOT(slotToggleOfflineMode()), 0, 4711 ); + setItemChecked(i, m_parent->m_cfg->offlineMode()); + + if (m_fullMenu) { + insertSeparator(); + + const QPixmap logoIcon = SmallIcon(QString::fromLatin1("knewsticker")); + const QPixmap helpIcon = SmallIcon(QString::fromLatin1("help")); + const QPixmap confIcon = SmallIcon(QString::fromLatin1("configure")); + + insertTitle(logoIcon, i18n("KNewsTicker"), 0, 0); + + insertItem(helpIcon, i18n("Help"), this, SLOT(slotShowHelp())); + insertItem(logoIcon, i18n("About KNewsTicker"), this, SLOT(slotShowAbout())); + insertSeparator(); + insertItem(confIcon, i18n("Configure KNewsTicker..."), this, SLOT(slotConfigure())); + } +} + +void KNewsTickerMenu::slotShowHelp() +{ + m_parent->help(); +} + +void KNewsTickerMenu::slotShowAbout() +{ + m_parent->about(); +} + +void KNewsTickerMenu::slotConfigure() +{ + m_parent->preferences(); +} + +void KNewsTickerMenu::slotToggleOfflineMode() +{ + m_parent->setOfflineMode(!m_parent->m_cfg->offlineMode()); + setItemChecked( indexOf( 4711 ), !m_parent->m_cfg->offlineMode() ); +} + +void KNewsTickerMenu::slotCheckNews(int idx) +{ + m_parent->m_newsSources[ idx - 1000 ]->retrieveNews(); +} + +void KNewsTickerMenu::slotOpenArticle(int idx) +{ + unsigned int i = idx - 2000; + const NewsSourceBase::List sources = m_parent->m_newsSources; + NewsSourceBase::List::ConstIterator it = sources.begin(); + while ( it != sources.end() ) { + if ( ( *it )->articles().isEmpty() ) { + ++it; + continue; + } + + if ( i <= ( *it )->articles().count() - 1 ) + break; + + i -= ( *it )->articles().count(); + + ++it; + } + + if ( it == sources.end() ) + return; + + ( *it )->articles()[ i ]->open(); +} + +extern "C" +{ + KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString &configFile) + { + KGlobal::locale()->insertCatalogue(QString::fromLatin1("knewsticker")); + return new KNewsTicker(configFile, KPanelApplet::Stretch, + KPanelApplet::Preferences | KPanelApplet::About | + KPanelApplet::Help | KPanelApplet::ReportBug, + parent, "knewsticker"); + } +} + +#include "knewsticker.moc" diff --git a/knewsticker/knewsticker.desktop b/knewsticker/knewsticker.desktop new file mode 100644 index 00000000..c27cee6b --- /dev/null +++ b/knewsticker/knewsticker.desktop @@ -0,0 +1,104 @@ +[Desktop Entry] +Name=News Ticker +Name[af]=Nuus Tikker +Name[be]=Аглядальнік навінаў +Name[bn]=সংবাদ টিকার +Name[br]=Kliker keleier +Name[bs]=Čitač vijesti +Name[ca]=Teletip de notícies +Name[cs]=KNewsTicker +Name[cy]=Ticer Newyddion +Name[da]=Nyhedstelegraf +Name[de]=KNewsTicker +Name[el]=Προβολή ειδήσεων +Name[eo]=Novaĵprezentilo +Name[et]=Uudiste jälgija +Name[eu]=Berri-markatzailea +Name[fa]=تیکر اخبار +Name[fr]=Téléscripteur de nouvelles +Name[gl]=Visor de Novas +Name[he]=צג חדשות +Name[hu]=KNewsTicker +Name[id]=Ticker Berita +Name[is]=Fréttastrimill +Name[it]=Gestore notizie +Name[ja]=ニュースティッカー +Name[ka]=სიახლეთა მიმღები +Name[kk]=Жаңалық таспасы +Name[km]=កម្មវិធីទទួលព័ត៌មាន +Name[ko]=새소식 표시기 +Name[lt]=Naujienų pranešėjas +Name[lv]=Ziņu Tikkers +Name[mn]=Мэдээний Дэлгэц +Name[ms]=Detik Berita +Name[nb]=Nyhetstelegraf +Name[nds]=Narichten-Ticker +Name[ne]=समाचार टिकर +Name[nl]=Nieuwsticker +Name[nn]=Telegraf +Name[nso]=Seswai sa Ditaba +Name[pt]=Extractor de Notícias +Name[pt_BR]=Mostrador de Notícias +Name[ru]=Монитор новостей +Name[sk]=Sledovač správ +Name[sl]=Prikazovalnik novic +Name[sv]=Nyhetsläsare +Name[ta]=செய்திகள் அறிவிப்பான் +Name[th]=ตั๋วข่าว +Name[tr]=Haber Gözlemcisi +Name[uk]=Стрічка новин +Name[ven]=Musengulusi wa Mafhungo +Name[zh_CN]=新闻播报器 +Name[zh_HK]=新聞快報 +Name[zh_TW]=新聞簡報 +Name[zu]=Umlungiseleli Wezindaba +X-KDE-Library=knewsticker_panelapplet +X-KDE-UniqueApplet=true +Icon=knewsticker +Comment=A scrolling RDF news ticker +Comment[be]=Бягучы радок навінаў +Comment[bg]=Четец на новини RDF +Comment[bn]=একটি অবিরাম আর-ডি-এফ সংবাদ টিকার +Comment[bs]=Traka s vijestima iz RDF datoteka +Comment[ca]=Teletip de notícies RDF amb desplaçament +Comment[cs]=Rolující RDF novinky +Comment[da]=En rullende RDF nyhedstelegraf +Comment[de]=Ein durchlaufender RDF-Newsticker +Comment[el]=Μια κυλιόμενη προβολή ειδήσεων RDF +Comment[eo]=Rulumanta RDF-novaĵprezentilo +Comment[es]=Teletipo de noticias RDF +Comment[et]=RDF uudiste jälgija +Comment[eu]=RDF berri-markatzailea +Comment[fa]=یک لغزاندن تیکر اخبار RDF +Comment[fi]=Skrollaava RDF-uutisnäyttäjä +Comment[fr]=Défilement de nouvelles RDF +Comment[gl]=Un visor de novas RDF deslizante +Comment[he]=צג חדשות +Comment[hu]=Hírbejelentő RSS hírforrásokhoz +Comment[is]=Skrunandi RDF fréttastrimill +Comment[it]=Un ticker notizie RDF a scorrimento +Comment[ja]=スクロールする RDFニュースティッカー +Comment[ka]=მოსრიალე RDF სიახლეთა მიმღები +Comment[kk]=Ақтарылатын RDF жаңалық таспасы +Comment[km]=កម្មវិធីទទួលព័ត៌មាន RDF រមូរ +Comment[lt]=Slenkantis RDF naujienų pranešiklis +Comment[nb]=En rullende RDF nyhetstelegraf +Comment[nds]=En rullen RDF-Narichtenticker +Comment[ne]=स्क्रोल गरिरहेको आर डी एफ टिकर +Comment[nl]=Een verschuivende RDF-nieuwsticker +Comment[nn]=RDF-nyhendetelegraf +Comment[pl]=Przewijający się pasek wiadomości RDF +Comment[pt]=Um extractor de notícias deslizante +Comment[pt_BR]=Um mini-aplicativo de notícias +Comment[ru]=Индикатор новостей RDF с прокруткой +Comment[sk]=Rolujúci sledovač RDF správ +Comment[sl]=Prikazovalnik novic v obliki RDF +Comment[sr]=Клизајући приказивач RDF вести +Comment[sr@Latn]=Klizajući prikazivač RDF vesti +Comment[sv]=En RDF-nyhetsövervakare med rullning +Comment[tr]=Akan bir RDF haber gözlemcisi +Comment[uk]=Стрічка новин RDF +Comment[zh_CN]=滚动的 RDF 新闻播报器 +Comment[zh_HK]=捲軸式 RDF 新聞簡報器 +Comment[zh_TW]=捲軸的 RDF 新聞簡報 + diff --git a/knewsticker/knewsticker.h b/knewsticker/knewsticker.h new file mode 100644 index 00000000..bbb228f6 --- /dev/null +++ b/knewsticker/knewsticker.h @@ -0,0 +1,146 @@ +/* + * knewsticker.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 KNEWSTICKER_H +#define KNEWSTICKER_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <dcopobject.h> + +#include <qtoolbutton.h> +#include <kpanelapplet.h> +#include <kpopupmenu.h> + +#include "configiface.h" +#include "configaccess.h" +#include "newsengine.h" + +class KInstance; +class NewsSource; +class KArrowButton; +class NewsIconMgr; +class NewsScroller; +class KNewsTickerMenu; +class KAboutData; +class QTimer; + +class KNewsTicker : public KPanelApplet, virtual public ConfigIface, + virtual public DCOPObject +{ + Q_OBJECT + K_DCOP + + friend class KNewsTickerMenu; + + public: + KNewsTicker(const QString &, Type, int, QWidget * = 0, const char * = 0); + virtual ~KNewsTicker(); + + virtual int widthForHeight(int) const; + virtual int heightForWidth(int) const; + + k_dcop: + virtual void reparseConfig(); + virtual void updateNews() { slotUpdateNews(); } + virtual uint interval() const { return m_cfg->interval(); } + virtual uint scrollingSpeed() const { return m_cfg->scrollingSpeed(); } + virtual uint mouseWheelSpeed() const { return m_cfg->mouseWheelSpeed(); } + virtual uint scrollingDirection() const { return m_cfg->scrollingDirection(); } + virtual bool customNames() const { return m_cfg->customNames(); } + virtual bool scrollMostRecentOnly() const { return m_cfg->scrollMostRecentOnly(); } + virtual bool offlineMode() const { return m_cfg->offlineMode(); } + virtual bool underlineHighlighted() const { return m_cfg->underlineHighlighted(); } + virtual bool showIcons() const { return m_cfg->showIcons(); } + virtual bool slowedScrolling() const { return m_cfg->slowedScrolling(); } + virtual QColor foregroundColor() const { return m_cfg->foregroundColor(); } + virtual QColor backgroundColor() const { return m_cfg->backgroundColor(); } + virtual QColor highlightedColor() const { return m_cfg->highlightedColor(); } + virtual QStringList newsSources() const { return m_cfg->newsSources(); } + virtual void setInterval(const uint); + virtual void setScrollingSpeed(const uint); + virtual void setMouseWheelSpeed(const uint); + virtual void setScrollingDirection(const uint); + 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 &); + virtual void setNewsSources(const QStringList &) {} + + public slots: + void slotUpdateNews(); + void slotOpenContextMenu(); + + protected: + virtual void preferences(); + virtual void about(); + virtual void help(); + virtual void reportBug(); + virtual void mousePressEvent(QMouseEvent *); + virtual void positionChange(Position); + + protected slots: + void slotArrowButtonPressed(); + void slotNewsSourceUpdated(const NewsSourceBase::Ptr &, bool = false); + void slotNewsSourceFailed(const NewsSourceBase::Ptr &); + void slotContextMenuAboutToHide(); + void slotNotifyOfFailures(); + + private: + void setupArrowButton(); + + KInstance *m_instance; + DCOPClient *m_dcopClient; + ConfigAccess *m_cfg; + KArrowButton *m_arrowButton; + QTimer *m_newsTimer; + QTimer *m_updateTimer; + NewsIconMgr *m_newsIconMgr; + NewsScroller *m_scroller; + KAboutData *m_aboutData; + KNewsTickerMenu *m_contextMenu; + bool m_newNews; + NewsSourceBase::List m_newsSources; + QStringList m_failedNewsUpdates; + QStringList m_pendingNewsUpdates; +}; + +class KNewsTickerMenu : public KPopupMenu +{ + Q_OBJECT + + public: + KNewsTickerMenu(KNewsTicker *, const char * = 0); + void setFullMenu(bool full) { m_fullMenu = full; populateMenu(); } + + protected slots: + void populateMenu(); + + private slots: + void slotShowHelp(); + void slotShowAbout(); + void slotConfigure(); + void slotToggleOfflineMode(); + void slotCheckNews(int idx); + void slotOpenArticle(int idx); + + private: + KNewsTicker *m_parent; + bool m_fullMenu; +}; + +#endif // KNEWSTICKER_H diff --git a/knewsticker/knewsticker.upd b/knewsticker/knewsticker.upd new file mode 100644 index 00000000..80720bdb --- /dev/null +++ b/knewsticker/knewsticker.upd @@ -0,0 +1,13 @@ +# Updates from version 0.1 to version 0.2 +Id=KNewsTicker-0.2 +File=knewstickerrc,knewstickerappletrc +Script=knt-0.1-0.2.pl,perl +# Update for KDE 3.0, Kicker applets use a different naming scheme +Id=KNewsTicker-0.2-Rename-KDE3 +File=knewstickerappletrc,knewsticker_appletrc +AllGroups +# Update for KDE 3.1, seems like they changed the nameing scheme *AGAIN* +Id=KNewsTicker-0.2-Rename-KDE3.1 +File=knewsticker_appletrc,knewsticker_panelappletrc +AllGroups +# End of file diff --git a/knewsticker/knewstickerconfig.cpp b/knewsticker/knewstickerconfig.cpp new file mode 100644 index 00000000..528269a0 --- /dev/null +++ b/knewsticker/knewstickerconfig.cpp @@ -0,0 +1,582 @@ +/* + * knewstickerconfig.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 "knewstickerconfig.h" +#include "configaccess.h" +#include "newsengine.h" +#include "newsiconmgr.h" +#include "newssourcedlgimpl.h" + +#include <kapplication.h> +#include <kcolorbutton.h> +#include <kcombobox.h> +#include <kdebug.h> +#include <kfontdialog.h> +#include <kiconloader.h> +#include <klineedit.h> +#include <klistview.h> +#include <kmessagebox.h> +#include <knuminput.h> +#include <kpopupmenu.h> + +#include <qcursor.h> +#include <qcheckbox.h> +#include <qdragobject.h> +#include <qlabel.h> +#include <qslider.h> +#include <qregexp.h> + +CategoryItem::CategoryItem(QListView *parent, const QString &text) + : QListViewItem(parent, text) +{ + setOpen(true); +} + +void CategoryItem::setOpen(bool open) +{ + if (open) + setPixmap(0, SmallIcon(QString::fromLatin1("folder_open"))); + else + setPixmap(0, SmallIcon(QString::fromLatin1("folder"))); + + QListViewItem::setOpen(open); +} + +NewsSourceItem::NewsSourceItem(KNewsTickerConfig *kcm, CategoryItem *parent, + const NewsSourceBase::Data &nsd) + : QCheckListItem(parent, QString::null, QCheckListItem::CheckBox), + m_parent(parent), + m_kcm(kcm) +{ + setData(nsd); +} + +NewsSourceBase::Data NewsSourceItem::data() const +{ + NewsSourceBase::Data nsd; + nsd.enabled = isOn(); + nsd.name = text(0); + nsd.sourceFile = text(1); + nsd.maxArticles = text(2).toUInt(); + nsd.icon = m_icon; + nsd.isProgram = m_isProgram; + nsd.subject = m_subject; + return nsd; +} + +void NewsSourceItem::setData(const NewsSourceBase::Data &nsd) +{ + setOn(nsd.enabled); + setText(0, nsd.name); + setText(1, nsd.sourceFile); + setText(2, QString::number(nsd.maxArticles)); + + m_icon = nsd.icon; + m_isProgram = nsd.isProgram; + m_subject = nsd.subject; + m_kcm->getNewsIcon(this, KURL( m_icon )); +} + +void NewsSourceItem::setIcon(const QPixmap &pixmap) +{ + setPixmap(0, pixmap); +} + +KNewsTickerConfig::KNewsTickerConfig(ConfigAccess *cfg, QWidget *parent, const char *name) + : KDialogBase(parent, name, true, i18n("Configuration"), Ok|Close), + m_cfg(cfg), + m_child(new KNewsTickerConfigWidget(this)), + m_newsIconMgr(NewsIconMgr::self()) +{ + setMainWidget(m_child); + + // Change various properties of the view which the Qt Designer cannot + // set at design time yet. + m_child->niInterval->setLabel(i18n("News query interval:")); + m_child->niInterval->setRange(4, 180); + + m_child->lvNewsSources->setShowSortIndicator(true); + m_child->lvNewsSources->setSelectionModeExt(KListView::Extended); + m_child->lvNewsSources->setAcceptDrops(true); + m_child->lvNewsSources->viewport()->setAcceptDrops(true); + m_child->lvNewsSources->viewport()->installEventFilter(this); + m_child->lvNewsSources->installEventFilter(this); + + connect(m_newsIconMgr, SIGNAL(gotIcon(const KURL &, const QPixmap &)), SLOT(slotGotNewsIcon(const KURL &, const QPixmap &))); + connect(m_child->bChooseFont, SIGNAL(clicked()), SLOT(slotChooseFont())); + + connect(m_child->lvNewsSources, SIGNAL(contextMenu(KListView *, QListViewItem *, const QPoint &)), + SLOT(slotNewsSourceContextMenu(KListView *, QListViewItem *, const QPoint &))); + connect(m_child->lvNewsSources, SIGNAL(selectionChanged()), + SLOT(slotNewsSourceSelectionChanged())); + connect(m_child->lvNewsSources, SIGNAL(doubleClicked(QListViewItem *, const QPoint &, int)), + SLOT(slotModifyNewsSource(QListViewItem *, const QPoint &, int))); + connect(m_child->bAddNewsSource, SIGNAL(clicked()), SLOT(slotAddNewsSource())); + connect(m_child->bRemoveNewsSource, SIGNAL(clicked()), SLOT(slotRemoveNewsSource())); + connect(m_child->bModifyNewsSource, SIGNAL(clicked()), SLOT(slotModifyNewsSource())); + + connect(m_child->lvFilters, SIGNAL(selectionChanged(QListViewItem *)), + SLOT(slotFilterSelectionChanged(QListViewItem *))); + connect(m_child->comboFilterAction, SIGNAL(activated(const QString &)), + SLOT(slotFilterActionChanged(const QString &))); + connect(m_child->comboFilterNewsSource, SIGNAL(activated(const QString &)), + SLOT(slotFilterNewsSourceChanged(const QString &))); + connect(m_child->comboFilterCondition, SIGNAL(activated(const QString &)), + SLOT(slotFilterConditionChanged(const QString &))); + connect(m_child->leFilterExpression, SIGNAL(textChanged(const QString &)), + SLOT(slotFilterExpressionChanged(const QString &))); + connect(m_child->bAddFilter, SIGNAL(clicked()), SLOT(slotAddFilter())); + connect(m_child->bRemoveFilter, SIGNAL(clicked()), SLOT(slotRemoveFilter())); + + load(); + + m_child->show(); +} + +void KNewsTickerConfig::load() +{ + m_child->comboFilterNewsSource->clear(); + m_child->comboFilterNewsSource->insertItem(i18n("All News Sources")); + + m_child->niInterval->setValue(m_cfg->interval()); + m_child->sliderMouseWheelSpeed->setValue(m_cfg->mouseWheelSpeed()); + m_child->cbCustomNames->setChecked(m_cfg->customNames()); + m_child->cbScrollMostRecentOnly->setChecked(m_cfg->scrollMostRecentOnly()); + m_child->cbSlowedScrolling->setChecked(m_cfg->slowedScrolling()); + + m_child->sliderScrollSpeed->setValue(m_cfg->scrollingSpeed()); + m_child->comboDirection->setCurrentItem(m_cfg->scrollingDirection()); + + m_font = m_cfg->font(); + m_child->colorForeground->setColor(m_cfg->foregroundColor()); + m_child->colorBackground->setColor(m_cfg->backgroundColor()); + m_child->colorHighlighted->setColor(m_cfg->highlightedColor()); + m_child->cbUnderlineHighlighted->setChecked(m_cfg->underlineHighlighted()); + m_child->cbShowIcons->setChecked(m_cfg->showIcons()); + + m_child->lvNewsSources->clear(); + QStringList nsList = m_cfg->newsSources(); + for (QStringList::Iterator it = nsList.begin(); it != nsList.end(); ++it) + addNewsSource(m_cfg->newsSource((*it))->data()); + + ArticleFilter::List filterList = m_cfg->filters(); + ArticleFilter::List::ConstIterator it = filterList.begin(); + ArticleFilter::List::ConstIterator end = filterList.end(); + for (; it != end; ++it) + addFilter(m_cfg->filter((*it))); + + slotNewsSourceSelectionChanged(); +} + +void KNewsTickerConfig::save() +{ + m_cfg->setInterval(m_child->niInterval->value()); + m_cfg->setMouseWheelSpeed(m_child->sliderMouseWheelSpeed->value()); + m_cfg->setCustomNames(m_child->cbCustomNames->isChecked()); + m_cfg->setScrollMostRecentOnly(m_child->cbScrollMostRecentOnly->isChecked()); + m_cfg->setSlowedScrolling(m_child->cbSlowedScrolling->isChecked()); + + m_cfg->setScrollingSpeed(m_child->sliderScrollSpeed->value()); + m_cfg->setScrollingDirection(static_cast<ConfigAccess::Direction>(m_child->comboDirection->currentItem())); + + m_cfg->setFont(m_font); + m_cfg->setForegroundColor(m_child->colorForeground->color()); + m_cfg->setBackgroundColor(m_child->colorBackground->color()); + m_cfg->setHighlightedColor(m_child->colorHighlighted->color()); + m_cfg->setUnderlineHighlighted(m_child->cbUnderlineHighlighted->isChecked()); + m_cfg->setShowIcons(m_child->cbShowIcons->isChecked()); + + QStringList newsSources; + for (QListViewItemIterator it(m_child->lvNewsSources); it.current(); it++) + if (NewsSourceItem *item = dynamic_cast<NewsSourceItem *>(it.current())) { + newsSources += item->data().name; + m_cfg->setNewsSource(item->data()); + } + m_cfg->setNewsSources(newsSources); + + ArticleFilter::List filters; + ArticleFilter f; + unsigned int i = 0; + for (QListViewItemIterator it(m_child->lvFilters); it.current(); it++) + if (QCheckListItem *item = dynamic_cast<QCheckListItem *>(it.current())) { + filters.append(i); + f.setAction(item->text(0)); + f.setNewsSource(item->text(2)); + f.setCondition(item->text(4)); + f.setExpression(item->text(5)); + f.setEnabled(item->isOn()); + f.setId(i++); + m_cfg->setFilter(f); + } + m_cfg->setFilters(filters); +} + +bool KNewsTickerConfig::eventFilter(QObject *o, QEvent *e) +{ + //<HACK> + // "if ( e->type() == QEvent::DragEnter ) {" shoult normaly be enough. but there must be a bug somewhere in KListView. + if ( e->type() == QEvent::DragMove ) { + //</HACK> + QDragEnterEvent *d = (QDragEnterEvent*)e; + d->accept(QTextDrag::canDecode(d)); + return true; // eat event + } + else if ( e->type() == QEvent::Drop) { + QDropEvent *d = (QDropEvent*)e; + QString newSourceUrl; + if ( QTextDrag::decode(d, newSourceUrl) ) { + // <HACK> + // This is just for http://www.webreference.com/services/news/ + newSourceUrl = newSourceUrl.replace( QRegExp("^view-source:http%3A//"), "http://" ); + // </HACK> + newSourceUrl = newSourceUrl.stripWhiteSpace(); + + //look for a new Name of Source: + QString name = i18n("Unknown"); + bool validName = false; + for (QListViewItemIterator it(m_child->lvNewsSources); it.current(); it++) { + if (it.current()->text(0) == name) { + validName = false; + break; + } else { + validName = true; + } + } + int i = 0; + while (validName == false) { + name = i18n("Unknown %1").arg(i); + for (QListViewItemIterator it(m_child->lvNewsSources); it.current(); it++) { + if (it.current()->text(0) == name) { + i++; + validName = false; + break; + } else { + validName = true; + } + } + } + + NewsSourceBase::Data nsd(name, newSourceUrl, "" , NewsSourceBase::Computers , 10, true, false); + NewsSourceDlgImpl nsDlg(this, 0L, true); + connect(&nsDlg, SIGNAL(newsSource(const NewsSourceBase::Data &)), + SLOT(slotAddNewsSource(const NewsSourceBase::Data &))); + nsDlg.setup(nsd, false); + nsDlg.exec(); + } + return true; // eat event + } + return QWidget::eventFilter( o, e ); +} + +void KNewsTickerConfig::resizeEvent(QResizeEvent *) +{ + m_child->resize(width(), height()); +} + +void KNewsTickerConfig::addNewsSource(const NewsSourceBase::Data &nsd, + bool select) +{ + CategoryItem *catItem = 0L; + + for (QListViewItemIterator it(m_child->lvNewsSources); it.current(); it++) { + if (it.current()->text(0) == NewsSourceBase::subjectText(nsd.subject)) { + catItem = static_cast<CategoryItem *>(it.current()); + break; + } + } + + if (!catItem) + catItem = new CategoryItem(m_child->lvNewsSources, + NewsSourceBase::subjectText(nsd.subject)); + + NewsSourceItem *item = new NewsSourceItem(this, catItem, nsd); + if (select) + m_child->lvNewsSources->setCurrentItem(item); + + m_child->comboFilterNewsSource->insertItem(item->data().name); +} + +void KNewsTickerConfig::addFilter(const ArticleFilter &fd) +{ + QCheckListItem *item = new QCheckListItem(m_child->lvFilters, fd.action(), QCheckListItem::CheckBox); + item->setOn(fd.enabled()); + item->setText(1, m_child->lArticles->text()); + item->setText(2, fd.newsSource()); + item->setText(3, m_child->lHeadlines->text()); + item->setText(4, fd.condition()); + item->setText(5, fd.expression()); +} + +void KNewsTickerConfig::removeNewsSource() +{ + if (KMessageBox::warningContinueCancel(this, i18n("<p>Do you really want to remove %n news" + " source?</p>", + "<p>Do you really want to remove these %n news" + " sources?</p>", + m_child->lvNewsSources->selectedItems().count()), QString::null, KStdGuiItem::del()) == KMessageBox::Continue) { + int itemCount = m_child->lvNewsSources->selectedItems().count(); + for (int j = 0; j < itemCount; j++) { + if (m_child->lvNewsSources->selectedItems().isEmpty()) { break; } + QListViewItem *item = m_child->lvNewsSources->selectedItems().take(0); + for (int i = 0; i < m_child->comboFilterNewsSource->count(); i++) + if (m_child->comboFilterNewsSource->text(i) == item->text(0)) { + m_child->comboFilterNewsSource->removeItem(i); + break; + } + if (dynamic_cast<NewsSourceItem *>(item) && item->parent()->childCount() == 1) + delete item->parent(); + else + delete item; + } + m_child->bRemoveNewsSource->setEnabled(false); + m_child->bModifyNewsSource->setEnabled(false); + } +} + +void KNewsTickerConfig::removeFilter(QListViewItem *item) +{ + if (KMessageBox::warningContinueCancel(this, i18n("<p>Do you really want to remove the selected" + " filter?</p>"), QString::null, KStdGuiItem::del()) == KMessageBox::Continue) { + delete item; + m_child->bRemoveFilter->setEnabled(false); + } +} + +void KNewsTickerConfig::slotNewsSourceContextMenu(KListView *, QListViewItem *item, const QPoint &) +{ + if (!dynamic_cast<NewsSourceItem *>(item)) + return; + + KPopupMenu *menu = new KPopupMenu(); + + QPixmap addIcon = SmallIcon(QString::fromLatin1("news_subscribe")); + QPixmap modifyIcon = SmallIcon(QString::fromLatin1("edit")); + QPixmap removeIcon = SmallIcon(QString::fromLatin1("news_unsubscribe")); + QPixmap logoIcon = SmallIcon(QString::fromLatin1("knewsticker")); + + menu->insertTitle(logoIcon, i18n("Edit News Source")); + menu->insertItem(addIcon, i18n("&Add News Source"), 0); + if (item) { + menu->insertItem(modifyIcon, i18n("&Modify '%1'").arg(item->text(0)), 1); + if (m_child->lvNewsSources->selectedItems().count() == 1) { + menu->insertItem(removeIcon, i18n("&Remove '%1'").arg(item->text(0)), 2); + } else { + menu->insertItem(removeIcon, i18n("&Remove News Sources"), 2); + } + } else { + menu->insertItem(modifyIcon, i18n("&Modify News Source"), 1); + menu->insertItem(removeIcon, i18n("&Remove News Source"), 2); + menu->setItemEnabled(1, false); + menu->setItemEnabled(2, false); + } + + switch (menu->exec(QCursor::pos())) { + case 0: slotAddNewsSource(); break; + case 1: modifyNewsSource(item); break; + case 2: removeNewsSource(); break; + } + + delete menu; +} + +void KNewsTickerConfig::slotChooseFont() +{ + KFontDialog fd(this, "Font Dialog", false, true); + + fd.setFont(m_font); + + if (fd.exec() == KFontDialog::Accepted) { + if (m_font != fd.font()) { + m_font = fd.font(); + } + } +} + +void KNewsTickerConfig::slotAddNewsSource() +{ + NewsSourceDlgImpl nsDlg(this, 0L, true); + connect(&nsDlg, SIGNAL(newsSource(const NewsSourceBase::Data &)), + SLOT(slotAddNewsSource(const NewsSourceBase::Data &))); + nsDlg.exec(); +} + +void KNewsTickerConfig::slotAddNewsSource(const NewsSourceBase::Data &nsd) +{ + addNewsSource(nsd); +} + +void KNewsTickerConfig::slotModifyNewsSource() +{ + if ((m_modifyItem = dynamic_cast<NewsSourceItem *>(m_child->lvNewsSources->selectedItems().take(0)))) + openModifyDialog(); +} + +void KNewsTickerConfig::slotModifyNewsSource(const NewsSourceBase::Data &nsd) +{ + if (m_modifyItem->data().subject != nsd.subject) { + QListViewItem *parentItem = m_modifyItem->parentItem(); + parentItem->takeItem(m_modifyItem); + if (parentItem->childCount() == 0) + delete parentItem; + + CategoryItem *catItem = 0L; + + for (QListViewItemIterator it(m_child->lvNewsSources); it.current(); it++) { + if (it.current()->text(0) == NewsSourceBase::subjectText(nsd.subject)) { + catItem = static_cast<CategoryItem *>(it.current()); + break; + } + } + + if (!catItem) + catItem = new CategoryItem(m_child->lvNewsSources, + NewsSourceBase::subjectText(nsd.subject)); + + catItem->insertItem(m_modifyItem); + } + + m_modifyItem->setData(nsd); +} + +void KNewsTickerConfig::slotModifyNewsSource(QListViewItem *item, const QPoint &, int) +{ + if (dynamic_cast<NewsSourceItem *>(item)) + modifyNewsSource(item); +} + +void KNewsTickerConfig::modifyNewsSource(QListViewItem *item) +{ + if ((m_modifyItem = dynamic_cast<NewsSourceItem *>(item))) + openModifyDialog(); +} + +void KNewsTickerConfig::openModifyDialog() +{ + NewsSourceDlgImpl nsDlg(this, 0L, true); + connect(&nsDlg, SIGNAL(newsSource(const NewsSourceBase::Data &)), + SLOT(slotModifyNewsSource(const NewsSourceBase::Data &))); + nsDlg.setup(m_modifyItem->data(), true); + nsDlg.exec(); +} + +void KNewsTickerConfig::slotAddFilter() +{ + ArticleFilter fd; + fd.setAction(m_child->comboFilterAction->currentText()); + fd.setNewsSource(m_child->comboFilterNewsSource->currentText()); + fd.setCondition(m_child->comboFilterCondition->currentText()); + fd.setExpression(m_child->leFilterExpression->text()); + fd.setEnabled(true); + addFilter(fd); +} + +void KNewsTickerConfig::slotRemoveNewsSource() +{ + removeNewsSource(); +} + +void KNewsTickerConfig::slotRemoveFilter() +{ + QListViewItem *item=m_child->lvFilters->selectedItem(); + if(!item) + return; + removeFilter(item); +} + +void KNewsTickerConfig::slotNewsSourceSelectionChanged() +{ + m_child->bRemoveNewsSource->setEnabled(! m_child->lvNewsSources->selectedItems().isEmpty()); + m_child->bModifyNewsSource->setEnabled(m_child->lvNewsSources->selectedItems().count() == 1); +} + +void KNewsTickerConfig::slotFilterSelectionChanged(QListViewItem *item) +{ + for (int i = 0; i < m_child->comboFilterAction->count(); i++) + if (m_child->comboFilterAction->text(i) == item->text(0)) { + m_child->comboFilterAction->setCurrentItem(i); + break; + } + + for (int i = 0; i < m_child->comboFilterNewsSource->count(); i++) + if (m_child->comboFilterNewsSource->text(i) == item->text(2)) { + m_child->comboFilterNewsSource->setCurrentItem(i); + break; + } + + for (int i = 0; i < m_child->comboFilterCondition->count(); i++) + if (m_child->comboFilterCondition->text(i) == item->text(4)) { + m_child->comboFilterCondition->setCurrentItem(i); + break; + } + + m_child->leFilterExpression->setText(item->text(5)); + + m_child->bRemoveFilter->setEnabled(item); +} + +void KNewsTickerConfig::slotFilterActionChanged(const QString &action) +{ + QListViewItem *item = m_child->lvFilters->selectedItem(); + + if (item) { + item->setText(0, action); + } +} + +void KNewsTickerConfig::slotFilterNewsSourceChanged(const QString &newsSource) +{ + QListViewItem *item = m_child->lvFilters->selectedItem(); + + if (item) { + item->setText(2, newsSource); + } +} + +void KNewsTickerConfig::slotFilterConditionChanged(const QString &condition) +{ + QListViewItem *item = m_child->lvFilters->selectedItem(); + + if (item) { + item->setText(4, condition); + } +} + +void KNewsTickerConfig::slotFilterExpressionChanged(const QString &expression) +{ + QListViewItem *item = m_child->lvFilters->selectedItem(); + + if (item) { + item->setText(5, expression); + } +} + +void KNewsTickerConfig::getNewsIcon(NewsSourceItem *item, const KURL &url) +{ + m_itemIconMap[url.url()] = item; + m_newsIconMgr->getIcon(url); +} + +void KNewsTickerConfig::slotGotNewsIcon(const KURL &url, const QPixmap &pixmap) +{ + if (m_itemIconMap.find(url.url()) == m_itemIconMap.end()) { + kdDebug(5005) << "Got unknown icon for URL " << url << endl; + return; + } + m_itemIconMap[url.url()]->setIcon(pixmap); + m_itemIconMap.remove(url.url()); +} + +void KNewsTickerConfig::slotOk() +{ + save(); + accept(); +} + +#include "knewstickerconfig.moc" diff --git a/knewsticker/knewstickerconfig.h b/knewsticker/knewstickerconfig.h new file mode 100644 index 00000000..ec475236 --- /dev/null +++ b/knewsticker/knewstickerconfig.h @@ -0,0 +1,110 @@ +/* + * knewstickerconfig.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 KCMNEWSTICKER_H +#define KCMNEWSTICKER_H + +#include "knewstickerconfigwidget.h" +#include "configaccess.h" +#include "newsengine.h" + +#include <kdialogbase.h> + +#include <qevent.h> +#include <qfont.h> +#include <qlistview.h> + +class KNewsTickerConfig; +class KNewsTickerConfigWidget; +class KConfig; +class NewsIconMgr; +class ConfigAccess; + +class CategoryItem : public QListViewItem +{ + public: + CategoryItem(QListView *, const QString &); + + void setOpen(bool); +}; + +class NewsSourceItem : public QCheckListItem +{ + public: + NewsSourceItem(KNewsTickerConfig *, CategoryItem *, const NewsSourceBase::Data &); + + NewsSourceBase::Data data() const; + void setData(const NewsSourceBase::Data &); + void setIcon(const QPixmap &); + + QListViewItem *parentItem() { return QCheckListItem::parent(); } + + private: + QString m_icon; + bool m_isProgram; + NewsSourceBase::Subject m_subject; + CategoryItem *m_parent; + KNewsTickerConfig *m_kcm; +}; + +class KNewsTickerConfig : public KDialogBase +{ + Q_OBJECT + friend class NewsSourceItem; + public: + KNewsTickerConfig(ConfigAccess *, QWidget * = 0, const char * = 0); + + void load(); + void save(); + void defaults(); + + protected: + void addNewsSource(const NewsSourceBase::Data &, bool = false); + void modifyNewsSource(QListViewItem *); + void removeNewsSource(); + void addFilter(const ArticleFilter &); + void removeFilter(QListViewItem *); + void resizeEvent(QResizeEvent *); + void openModifyDialog(); + bool eventFilter(QObject *o, QEvent *e); + void getNewsIcon(NewsSourceItem *, const KURL &); + + protected slots: + void slotNewsSourceContextMenu(KListView *, QListViewItem *, const QPoint &); + void slotChooseFont(); + void slotAddNewsSource(); + void slotAddFilter(); + void slotAddNewsSource(const NewsSourceBase::Data &); + void slotRemoveNewsSource(); + void slotRemoveFilter(); + void slotModifyNewsSource(); + void slotModifyNewsSource(const NewsSourceBase::Data &); + void slotModifyNewsSource(QListViewItem *, const QPoint &, int); + void slotNewsSourceSelectionChanged(); + void slotFilterSelectionChanged(QListViewItem *); + void slotFilterActionChanged(const QString &); + void slotFilterNewsSourceChanged(const QString &); + void slotFilterConditionChanged(const QString &); + void slotFilterExpressionChanged(const QString &); + virtual void slotOk(); + + private slots: + void slotGotNewsIcon(const KURL &, const QPixmap &); + + private: + ConfigAccess *m_cfg; + KNewsTickerConfigWidget *m_child; + QFont m_font; + NewsSourceItem *m_modifyItem; + NewsIconMgr *m_newsIconMgr; + QMap<QString, NewsSourceItem *> m_itemIconMap; +}; + +#endif // KCMNEWSTICKER_H diff --git a/knewsticker/knewstickerconfigwidget.ui b/knewsticker/knewstickerconfigwidget.ui new file mode 100644 index 00000000..3afa390d --- /dev/null +++ b/knewsticker/knewstickerconfigwidget.ui @@ -0,0 +1,1178 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>KNewsTickerConfigWidget</class> +<comment>The core widget of the KCMNewsTicker KControl module.</comment> +<author>Frerich Raabe <raabe@kde.org></author> +<widget class="QWidget"> + <property name="name"> + <cstring>KNewsTickerConfigWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>597</width> + <height>525</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="layoutMargin" stdset="0"> + </property> + <property name="layoutSpacing" stdset="0"> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>4</number> + </property> + <property name="spacing"> + <number>4</number> + </property> + <widget class="QTabWidget"> + <property name="name"> + <cstring>tabScrollerPreferences</cstring> + </property> + <property name="layoutMargin" stdset="0"> + </property> + <property name="layoutSpacing" stdset="0"> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>tabGeneral</cstring> + </property> + <attribute name="title"> + <string>General</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>4</number> + </property> + <property name="spacing"> + <number>4</number> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>gbGeneral</cstring> + </property> + <property name="title"> + <string>General</string> + </property> + <property name="layoutMargin" stdset="0"> + </property> + <property name="layoutSpacing" stdset="0"> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="KIntNumInput" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>niInterval</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="value"> + <number>30</number> + </property> + <property name="suffix"> + <string> min</string> + </property> + <property name="specialValueText"> + <string>Never</string> + </property> + <property name="toolTip" stdset="0"> + <string>Interval of news queries</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can define at what interval KNewsTicker queries the configured news sources for new headlines. This depends generally on how fast you would like to hear about news and how much load you want to put on the network:<ul> +<li>A lower value (lower than <b>15 minutes</b>) enables you to get notified about news very quickly if you want or need to. Please note that it increases the network traffic significantly, though. Therefore, such low values should not be used if you query popular news sites (such as <a href="http://slashdot.org">Slashdot</a> or <a href="http://freshmeat.net">Freshmeat</a>) as they have generally already enough work processing the incoming queries.</li> +<li>A higher value (higher than <b>45 minutes</b>) will make you hear about news less quickly. For non-timecritical applications, it should be suitable, though. The positive aspect of longer intervals is that only very little load is put on the network; this saves resources and nerves, for you and the system administrators of the news sites you query.</li></ul> +The default value (30 minutes) should be appropriate and reasonable in most cases.</string> + </property> + </widget> + <widget class="QLayoutWidget" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>Layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>lNonSensitive</cstring> + </property> + <property name="text"> + <string>Nonsensitive</string> + </property> + <property name="toolTip" stdset="0"> + <string>Mousewheel sensitivity</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This slider allows you to define how quickly/slowly the text should be scrolled when using the mousewheel.</string> + </property> + </widget> + <widget class="QSlider"> + <property name="name"> + <cstring>sliderMouseWheelSpeed</cstring> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="maxValue"> + <number>10</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="tickInterval"> + <number>150</number> + </property> + <property name="toolTip" stdset="0"> + <string>Mousewheel sensitivity</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This slider allows you to define how fast/slow the text should be scrolled when using the mousewheel.</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>lSensitive</cstring> + </property> + <property name="text"> + <string>Sensitive</string> + </property> + <property name="toolTip" stdset="0"> + <string>Mousewheel sensitivity</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This slider allows you to define how fast/slow the text should be scrolled when using the mousewheel.</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>lMouseWheelSensitivity</cstring> + </property> + <property name="text"> + <string>&Mousewheel sensitivity:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>sliderMouseWheelSpeed</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Mousewheel sensitivity</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This slider allows you to define how fast/slow the text should be scrolled when using the mousewheel.</string> + </property> + </widget> + <widget class="QCheckBox" row="3" column="0"> + <property name="name"> + <cstring>cbCustomNames</cstring> + </property> + <property name="text"> + <string>&Use custom names for news sites</string> + </property> + <property name="toolTip" stdset="0"> + <string>Use the names defined in the list of news sources</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this box to make the news ticker use the names you specified in the list of news sources (available on the tab labeled <i>News sources</i>) instead of the ones the news sites themselves report.<br>This can be handy for news sites which report a very long or useless name.</string> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer5_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </vbox> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tabNewsSources</cstring> + </property> + <attribute name="title"> + <string>News Sources</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>4</number> + </property> + <property name="spacing"> + <number>4</number> + </property> + <widget class="KListView" row="0" column="0" rowspan="1" colspan="4"> + <column> + <property name="text"> + <string>Name of Site</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Source File</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Max. Articles</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>lvNewsSources</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="rootIsDecorated"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>News sources to be queried</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This list lets you manage the list of news sites the news ticker will query for headlines. The news sources are arranged in a tree-like hierarchy and sorted by topic.<br>The column labeled "Max. articles" shows how many articles will be cached for the news sites (read: how many articles will be accessible through the context menu).<ul> +<li>To add a site, you can either drag the URL of the RDF or RSS file to this list from Konqueror or any other application, or use the <i>Add...</i> button in the bottom right corner.</li> +<li>To modify a site, just double-click on the particular news source you would like to edit and an input field will pop up which lets you edit the respective property.</li> +<li>To remove a site, simply select a news source in the list and click on the <i>Remove</i> button in the lower right corner.</li></ul> +Note that you can also right-click on the list to open a menu which lets you add and remove news sources. You can also enable or disable certain news sources temporarily by checking or unchecking the box next to it; those news sources whose boxes are checked are considered activated and will be processed by KNewsTicker.</string> + </property> + </widget> + <widget class="QPushButton" row="1" column="3"> + <property name="name"> + <cstring>bRemoveNewsSource</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>R&emove</string> + </property> + <property name="toolTip" stdset="0"> + <string>Remove selected site</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Click this button to remove the currently selected news site from the list.</string> + </property> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>Spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>bAddNewsSource</cstring> + </property> + <property name="text"> + <string>Add...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Add a new site</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Click this button to add a new site to the list. Note that you can also drag a RDF or RSS file to this list (i.e. from Konqueror) to add it to the list.</string> + </property> + </widget> + <widget class="QPushButton" row="1" column="2"> + <property name="name"> + <cstring>bModifyNewsSource</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>&Modify...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Modify selected news source</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Click this button to open a dialog which lets you edit the properties (such as the name, the source file, or the icon) of the currently selected news source.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tabFilters</cstring> + </property> + <attribute name="title"> + <string>Filters</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>4</number> + </property> + <property name="spacing"> + <number>4</number> + </property> + <widget class="KListView" row="0" column="0" rowspan="1" colspan="3"> + <column> + <property name="text"> + <string>Action</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string></string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Affects</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string></string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Condition</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Expression</string> + </property> + <property name="clickable"> + <bool>false</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>lvFilters</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="rootIsDecorated"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Currently configured filters</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can see the list of currently configured filters and manage them as well as add new filters. Managing them is fairly easy:<ul> +<li>To <b>add</b> a new filter, specify its properties in the box below labeled <i>Filter properties</i> and press the <i>Add</i> button in the lower right corner.</li> +<li><b>Modifying</b> an existing filter is done in a similar manner: simply select the filter you would like to edit in the list and change its properties in the box below.</li> +<li>Finally, to <b>remove</b> a filter, select it in the list and press the button labeled <i>Remove</i> in the lower right corner.</li></ul> +You can also enable or disable certain filters temporarily by checking or unchecking the box next to them; those filters whose boxes are checked are considered enabled and will be honored by KNewsTicker.<br> +Note that the filters are processed from the top to the bottom so that of two filters which might nullify each other (like "Show...does not contain KDE" and "Show...contains KDE") only the one which is lower in the list will take effect.</string> + </property> + </widget> + <spacer row="2" column="0"> + <property name="name"> + <cstring>Spacer9</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="2" column="2"> + <property name="name"> + <cstring>bRemoveFilter</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>R&emove</string> + </property> + <property name="toolTip" stdset="0"> + <string>Remove selected filter</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Press this button to remove the selected filter from the list.</string> + </property> + </widget> + <widget class="QPushButton" row="2" column="1"> + <property name="name"> + <cstring>bAddFilter</cstring> + </property> + <property name="text"> + <string>A&dd</string> + </property> + <property name="toolTip" stdset="0"> + <string>Add configured filter</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Press this button to add the configured filter to the list.</string> + </property> + </widget> + <widget class="QGroupBox" row="1" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>gbFilterProperties</cstring> + </property> + <property name="title"> + <string>Filter Properties</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="KComboBox" row="0" column="0" rowspan="1" colspan="3"> + <item> + <property name="text"> + <string>Hide</string> + </property> + </item> + <item> + <property name="text"> + <string>Show</string> + </property> + </item> + <property name="name"> + <cstring>comboFilterAction</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Action for this filter</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can define what should happen if this filter matches (e.g. whether the matching articles should be shown or hidden).</string> + </property> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>Spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="0" column="3"> + <property name="name"> + <cstring>lArticles</cstring> + </property> + <property name="text"> + <string>articles from</string> + </property> + </widget> + <widget class="KComboBox" row="0" column="4" rowspan="1" colspan="2"> + <item> + <property name="text"> + <string>all news sources</string> + </property> + </item> + <property name="name"> + <cstring>comboFilterNewsSource</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Affected news sources</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can specify which news sources (or all of them) are affected. Note that only the news sources which have been activated on the <i>News sources</i> tab are shown in this combo box.</string> + </property> + </widget> + <widget class="QLabel" row="0" column="6"> + <property name="name"> + <cstring>lwhose</cstring> + </property> + <property name="text"> + <string>whose</string> + </property> + </widget> + <widget class="KLineEdit" row="1" column="5" rowspan="1" colspan="3"> + <property name="name"> + <cstring>leFilterExpression</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Keyword/Expression</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can type a keyword or expression to be used for this filter which depends on the condition you selected in the combo box at the right:<ul> +<li><b>contain</b>, <b>does not contain</b> - you should probably enter a keyword here, like "KDE", "Baseball" or "Business". The keyword is not case-sensitive so it does not matter whether you type "kde", "KDE" or "kDe".</li> +<li><b>equals</b>, <b>does not equal</b> - enter a phrase or expression here to have the filter match only those articles whose headlines match <b>exactly</b> the text you typed. The phrase you type will be considered to be case-sensitive, so it makes a difference whether you show articles which contain "Boeing" or "BOEING".</li> +<li><b>matches</b> - a regular expression is expected. Recommended only if you are familiar with regular expressions, i.e. it should be used by advanced users only.</li></ul></string> + </property> + </widget> + <spacer row="0" column="7"> + <property name="name"> + <cstring>Spacer15</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>lHeadlines</cstring> + </property> + <property name="text"> + <string>headlines</string> + </property> + </widget> + <widget class="KComboBox" row="1" column="2" rowspan="1" colspan="3"> + <item> + <property name="text"> + <string>contain</string> + </property> + </item> + <item> + <property name="text"> + <string>do not contain</string> + </property> + </item> + <item> + <property name="text"> + <string>equal</string> + </property> + </item> + <item> + <property name="text"> + <string>do not equal</string> + </property> + </item> + <item> + <property name="text"> + <string>match</string> + </property> + </item> + <property name="name"> + <cstring>comboFilterCondition</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Condition for this filter</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This combo box lets you specify the condition under which the keyword/expression you entered in the input field at the right will match. You can select one of the following values:<ul> +<li>contain - the filter matches if the headline contains the keyword.</li> +<li>does not contain - the filter matches if the headline does not contain the keyword.</li> +<li>equals - the filter matches if the headline equals the expression.</li> +<li>does not equal - the filter matches if the headline does not equal the expression.</li> +<li>matches - the filter matches if the expression matches the headline. The expression you typed at the right will be considered a regular expression in this mode.</li></string> + </property> + </widget> + </grid> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>tabScrollerPreferences</cstring> + </property> + <attribute name="title"> + <string>Scroller</string> + </attribute> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>4</number> + </property> + <property name="spacing"> + <number>4</number> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>gbScrollerBehaviour</cstring> + </property> + <property name="title"> + <string>Behavior</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>Layout5</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>lScrollingSpeed</cstring> + </property> + <property name="text"> + <string>&Scrolling speed:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>sliderScrollSpeed</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Scrolling speed</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can define how fast the text should be scrolling. If you only have a little space on your taskbar (and therefore a rather small news ticker), you should probably set this to a slower speed so that you have a chance to read the headlines. For wider news tickers (and better eyes), faster scrolling is probably appropriate so that you do not have to wait too long for the next headline.</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout6_2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>lSlow</cstring> + </property> + <property name="text"> + <string>Slow</string> + </property> + <property name="toolTip" stdset="0"> + <string>Scrolling speed</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can define how fast the text should be scrolling. If you only have a little space on your taskbar (and therefore a rather small news ticker), you should probably set this to a slower speed so that you have a chance to read the headlines. For wider news tickers (and better eyes), faster scrolling is probably appropriate so that you do not have to wait too long for the next headline.</string> + </property> + </widget> + <widget class="QSlider"> + <property name="name"> + <cstring>sliderScrollSpeed</cstring> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="maxValue"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="tickInterval"> + <number>10</number> + </property> + <property name="toolTip" stdset="0"> + <string>Scrolling speed</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can define how fast the text should be scrolling. If you only have a little space on your taskbar (and therefore a rather small news ticker), you should probably set this to a slower speed so that you have a chance to read the headlines. For wider news tickers (and better eyes), faster scrolling is probably appropriate so that you do not have to wait too long for the next headline.</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>lFast</cstring> + </property> + <property name="text"> + <string>Fast</string> + </property> + <property name="toolTip" stdset="0"> + <string>Scrolling speed</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can define how fast the text should be scrolling. If you only have a little space on your taskbar (and therefore a rather small news ticker), you should probably set this to a slower speed so that you have a chance to read the headlines. For wider news tickers (and better eyes), faster scrolling is probably appropriate so that you do not have to wait too long for the next headline.</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>lDirectionOfScrolling_2</cstring> + </property> + <property name="text"> + <string>Di&rection of scrolling:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>comboDirection</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Direction of scrolling</string> + </property> + <property name="whatsThis" stdset="0"> + <string>These options allow you to define in what direction the text should be scrolled, e.g. to the left or to the right, upwards or downwards.</string> + </property> + </widget> + <widget class="KComboBox" row="1" column="1"> + <item> + <property name="text"> + <string>To the Left</string> + </property> + </item> + <item> + <property name="text"> + <string>To the Right</string> + </property> + </item> + <item> + <property name="text"> + <string>Upwards</string> + </property> + </item> + <item> + <property name="text"> + <string>Downwards</string> + </property> + </item> + <item> + <property name="text"> + <string>Upwards, Rotated</string> + </property> + </item> + <item> + <property name="text"> + <string>Downwards, Rotated</string> + </property> + </item> + <property name="name"> + <cstring>comboDirection</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Direction of scrolling</string> + </property> + <property name="whatsThis" stdset="0"> + <string>These options allow you to define in what direction the text should be scrolled, e.g. to the left or to the right, upwards or downwards. Rotated means the text is rotated 90 degrees.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>gbScrollerAppearance</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="title"> + <string>Appearance</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>lHighlightedColor_2</cstring> + </property> + <property name="text"> + <string>H&ighlighted color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>colorHighlighted</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Highlighted color</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Click the button at the right to open a convenient color-selection dialog which lets you choose the color of the headlines when they are highlighted (when you move the mouse over them).</string> + </property> + </widget> + <widget class="KColorButton" row="3" column="1"> + <property name="name"> + <cstring>colorHighlighted</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="toolTip" stdset="0"> + <string>Highlighted color</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Click this button to open a convenient color-selection dialog which lets you choose the color of the headlines when they are highlighted (when you move the mouse over them).</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>lBackgroundColor_2</cstring> + </property> + <property name="text"> + <string>&Background color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>colorBackground</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Background color</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Click the button at the right to open a convenient color-selection dialog which lets you choose the background color of the scrolling text.</string> + </property> + </widget> + <widget class="KColorButton" row="2" column="1"> + <property name="name"> + <cstring>colorBackground</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="toolTip" stdset="0"> + <string>Background color</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Click this button to open a convenient color-selection dialog which lets you choose the background color of the scrolling text.</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>lForegroundColor_2</cstring> + </property> + <property name="text"> + <string>&Foreground color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>colorForeground</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Foreground color</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Click the button at the right to open a convenient color-selection dialog which lets you choose the color of the scrolling text.</string> + </property> + </widget> + <widget class="KColorButton" row="1" column="1"> + <property name="name"> + <cstring>colorForeground</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="toolTip" stdset="0"> + <string>Foreground color</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Click this button to open a convenient color-selection dialog which lets you choose the color of the scrolling text.</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>lFont_2</cstring> + </property> + <property name="text"> + <string>F&ont:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>bChooseFont</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Scrolling text font</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Click on the button at the right labeled <i>Choose Font...</i> to choose the font which will be used for the scrolling text. Please note that certain fonts are harder to read than others, especially when they are used as scrolling text. You should probably choose a font which can be easily read while it is moving.</string> + </property> + </widget> + <widget class="QPushButton" row="0" column="1"> + <property name="name"> + <cstring>bChooseFont</cstring> + </property> + <property name="text"> + <string>Choose Font...</string> + </property> + <property name="toolTip" stdset="0"> + <string>Scrolling text font</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Click here to choose the font which will be used for the scrolling text. Please note that certain fonts are harder to read than others, especially when they are used as a scrolling text. You should probably choose a font which can be easily read while it is moving.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>gbMiscScrollingOptions</cstring> + </property> + <property name="title"> + <string>Miscellaneous</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>cbScrollMostRecentOnly</cstring> + </property> + <property name="text"> + <string>Scroll the most recent headlines onl&y</string> + </property> + <property name="toolTip" stdset="0"> + <string>Show only the most recent headline for each news site in the scroller</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this button to show only the most recent headline for each news site. </string> + </property> + </widget> + <widget class="QCheckBox" row="0" column="1"> + <property name="name"> + <cstring>cbShowIcons</cstring> + </property> + <property name="text"> + <string>Show icons</string> + </property> + <property name="toolTip" stdset="0"> + <string>Show icons in the scrolling text</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Click this button to make KNewsTicker show the icons of the news site to which each headline belongs. This makes associating a headline to a news site very easy but takes up some space in the text.</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>cbSlowedScrolling</cstring> + </property> + <property name="text"> + <string>&Temporarily slowed scrolling</string> + </property> + <property name="toolTip" stdset="0"> + <string>Slow the scrolling down when mouse points at the scroller</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this box to make KNewsTicker slow the scrolling down when you move the mouse cursor over the scrolling text. This makes clicking on items and dragging the icons (if enabled) away a lot easier.</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="1"> + <property name="name"> + <cstring>cbUnderlineHighlighted</cstring> + </property> + <property name="text"> + <string>&Underline highlighted headline</string> + </property> + <property name="toolTip" stdset="0"> + <string>Underline the currently highlighted headline</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this box to have the currently highlighted headline (e.g. the headline which is currently under the mouse cursor) underlined.</string> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>Spacer6</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </widget> + </vbox> +</widget> +<tabstops> + <tabstop>sliderMouseWheelSpeed</tabstop> + <tabstop>niInterval</tabstop> + <tabstop>cbCustomNames</tabstop> + <tabstop>lvNewsSources</tabstop> + <tabstop>bAddNewsSource</tabstop> + <tabstop>bModifyNewsSource</tabstop> + <tabstop>bRemoveNewsSource</tabstop> + <tabstop>lvFilters</tabstop> + <tabstop>comboFilterAction</tabstop> + <tabstop>comboFilterNewsSource</tabstop> + <tabstop>comboFilterCondition</tabstop> + <tabstop>leFilterExpression</tabstop> + <tabstop>bAddFilter</tabstop> + <tabstop>bRemoveFilter</tabstop> + <tabstop>sliderScrollSpeed</tabstop> + <tabstop>comboDirection</tabstop> + <tabstop>bChooseFont</tabstop> + <tabstop>colorForeground</tabstop> + <tabstop>colorBackground</tabstop> + <tabstop>colorHighlighted</tabstop> + <tabstop>cbScrollMostRecentOnly</tabstop> + <tabstop>cbShowIcons</tabstop> + <tabstop>cbSlowedScrolling</tabstop> + <tabstop>cbUnderlineHighlighted</tabstop> + <tabstop>tabScrollerPreferences</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">kcolorbutton.h</include> + <include location="global" impldecl="in declaration">kcombobox.h</include> + <include location="global" impldecl="in declaration">klineedit.h</include> + <include location="global" impldecl="in declaration">klistview.h</include> + <include location="global" impldecl="in declaration">knuminput.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>klistview.h</includehint> + <includehint>klistview.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> + <includehint>kcolorbutton.h</includehint> +</includehints> +</UI> diff --git a/knewsticker/knewstickerstub/Makefile.am b/knewsticker/knewstickerstub/Makefile.am new file mode 100644 index 00000000..200e2eac --- /dev/null +++ b/knewsticker/knewstickerstub/Makefile.am @@ -0,0 +1,13 @@ +INCLUDES = -I$(top_srcdir)/knewsticker/common $(all_includes) + +bin_PROGRAMS = knewstickerstub + +servicedir = $(kde_appsdir)/.hidden +service_DATA = knewstickerstub.desktop + +METASOURCES = AUTO + +knewstickerstub_SOURCES = knewstickerstub.cpp +knewstickerstub_LDADD = $(LIB_KIO) ../common/libknewstickercommon.la +knewstickerstub_LDFLAGS = $(all_libraries) $(KDE_RPATH) + diff --git a/knewsticker/knewstickerstub/knewstickerstub.cpp b/knewsticker/knewstickerstub/knewstickerstub.cpp new file mode 100644 index 00000000..7f5960a4 --- /dev/null +++ b/knewsticker/knewstickerstub/knewstickerstub.cpp @@ -0,0 +1,80 @@ +/* + * knewstickerstub.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 <kaboutdata.h> +#include <kapplication.h> +#include <kcmdlineargs.h> +#include <kdebug.h> + +#include <dcopclient.h> + + +#include "configaccess.h" + +static const char name[] = "knewstickerstub"; +static const char verbname[] = I18N_NOOP("KNewsTickerStub"); +static const char version[] = "0.3"; +static const char description[] = I18N_NOOP("A frontend to the KNewsTicker configuration"); +static const char copyright[] = I18N_NOOP("(c)2000, 2001 Frerich Raabe"); + +static const KCmdLineOptions options[] = +{ + {"a", 0, 0}, + {"addrdf <url>", I18N_NOOP("Add the RDF/RSS file referenced by <url>"), 0}, + KCmdLineLastOption +}; + +int main(int argc, char **argv) +{ + KLocale::setMainCatalogue("knewsticker"); + + KAboutData aboutData(name, verbname, version, description, + KAboutData::License_BSD, copyright); + aboutData.addAuthor("Frerich Raabe", I18N_NOOP("Author"), "raabe@kde.org"); + + KCmdLineArgs::init(argc, argv, &aboutData); + KCmdLineArgs::addCmdLineOptions(options); + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + KApplication app(false, false); + + DCOPClient *dcopClient = app.dcopClient(); + dcopClient->attach(); + + KConfig cfg(QString::fromLatin1("knewsticker_panelappletrc"), false, false); + ConfigAccess configFrontend(&cfg); + + if (args->isSet("addrdf")) { + QStringList newsSources = configFrontend.newsSources(); + + // TODO: Use the "Suggest" functionality from addnewssourcedlgimpl.cpp here. + QString name = i18n("Unknown"); + if (newsSources.contains(name)) + for (unsigned int i = 0; ; i++) + if (!newsSources.contains(i18n("Unknown %1").arg(i))) { + name = i18n("Unknown %1").arg(i); + break; + } + + newsSources += name; + + QString sourceFile = QString(args->getOption("addrdf")); + configFrontend.setNewsSource(NewsSourceBase::Data(name, sourceFile)); + configFrontend.setNewsSources(newsSources); + + QByteArray data; + dcopClient->send("knewsticker", "KNewsTicker", "reparseConfig()", data); + } + + args->clear(); + + return 0; +} diff --git a/knewsticker/knewstickerstub/knewstickerstub.desktop b/knewsticker/knewstickerstub/knewstickerstub.desktop new file mode 100644 index 00000000..1ce2238b --- /dev/null +++ b/knewsticker/knewstickerstub/knewstickerstub.desktop @@ -0,0 +1,202 @@ +[Desktop Entry] +Name=KNewsTicker Config Frontend +Name[be]=Праграма настаўлення KNewsTicker +Name[bg]=Настройване четеца на новини +Name[bn]=কে-নিউজ-টিকার কনফিগ ফ্রন্ট-এন্ড +Name[bs]=KNewsTicker konfiguracijski frontend +Name[ca]=Interfície de configuració per a KNewsTicker +Name[cs]=Nastavení KNewsTickeru +Name[da]=KNewsTicker config-grænseflade +Name[de]=Newsticker-Einrichtung +Name[el]=Πρόγραμμα ρύθμισης KNewsTicker +Name[eo]=Agordilo por Novaĵprezentilo +Name[es]=Interfaz de configuración de KNewsTicker +Name[et]=Uudistejälgija seadistamine +Name[eu]=KNewsTicker konfigurazio interfazea +Name[fa]=پایانۀ پیکربندی KNewsTicker +Name[fi]=KNewsTickerin asetusten käyttöliittymä +Name[fr]=Interface pour la configuration du téléscripteur +Name[gl]=Interface de Configuración de KNewsTicker +Name[he]=ממשק לקביעת התצורה של KNewsTicker +Name[hu]=Grafikus felületű beállítóprogram a KNewsTickerhez +Name[is]=Stillingatól KNewsTicker +Name[it]=Interfaccia per la configurazione di KNewsTicker +Name[ja]=ニュースティッカー設定フロントエンド +Name[ka]=KNewsTicker კონფიგურაცია +Name[kk]=KNewsTicker баптауы +Name[km]=ផ្នែកខាងមុខសម្រាប់កំណត់រចនាសម្ព័ន្ធ KNewsTicker +Name[lt]=KNewsTicker derinimo naudotojo sąsaja +Name[mk]=Конфигурација на интерфејсот на KNewsTicker +Name[nb]=Oppsettsmodul for KNewsTicker +Name[nds]=KNewsTicker-Inrichten +Name[ne]=केडीई न्यूज टिकर कन्फिग फ्रन्टइन्ड +Name[nl]=KNewsTicker configuratie-interface +Name[nn]=Oppsett av KNewsTicker +Name[pl]=Interfejs konfiguracji KNewsTickera +Name[pt]=Configuração das Notícias +Name[pt_BR]=Interface de configuração do KNewsTicker +Name[ro]=Interfaţă configurare Ştiri Internet +Name[ru]=Параметры монитора новостей +Name[se]=Heivet KNewsTicker-lavtta +Name[sk]=Nastavenie KNewsTicker +Name[sl]=Nastavitveni vmesnik programa KNewsTicker +Name[sr]=Интерфејс за подешавање KNewsTicker-а +Name[sr@Latn]=Interfejs za podešavanje KNewsTicker-a +Name[sv]=Gränssnitt för anpassning av nyhetsövervakaren +Name[ta]=கேசெய்தி அறிவிப்பான் கட்டமை முன்னிலை +Name[tg]=KПешохири Танзими Дидабони Ахборот +Name[tr]=KDE Haber Gözlemcisi Yapılandırma Önyüzü +Name[uk]=Інтерфейс налаштування KNewsTicker +Name[zh_CN]=KNewsTicker 配置前端 +Name[zh_HK]=KNewsTicker 設定前端 +Name[zh_TW]=KNewsTicker 設定前端 +Comment=A frontend for the KNewsTicker configuration +Comment[af]='n voorprogram vir die K-nuustikker opstelling +Comment[ar]=واجهة لضبط مجدد الأخبار +Comment[az]=KNewsTicker quraşdırması üçün bir axtar üz +Comment[be]=Праграма настаўлення KNewsTicker +Comment[bg]=Графичен интерфейс за настройки на четеца на новини +Comment[bn]=কে-নিউজ-টিকার কনফিগারেশনের জন্য একটি ফ্রন্ট-এন্ড +Comment[bs]=Frontend za podešavanje KNewsTicker-a +Comment[ca]=Una interfície per a la configuració del KNewsTicker +Comment[cs]=Rozhraní pro nastavení KNewsTickeru +Comment[cy]=Blaen-wyneb i'r ffurweddiad KTicerNewyddion +Comment[da]=En grænseflade til indstilling af KNewsTicker +Comment[de]=Eine Oberfläche zur Einrichtung von KNewsTicker +Comment[el]=Ένα πρόγραμμα για τη ρύθμιση του KNewsTicker +Comment[eo]=Agordilofasado por Novaĵprezentilo +Comment[es]=Un interfaz para la configuración de KNewsTicker +Comment[et]=Uudistejälgija seadistamise kasutajaliides +Comment[eu]=KNewsTicker konfigurazioaren interfazea +Comment[fa]=یک پایانه برای پیکربندی KNewsTicker +Comment[fi]=Käyttöliittymä KNewsTicker-asetuksiin +Comment[fr]=Interface pour la configuration de KNewsTicker +Comment[ga]=Comhéadan le haghaidh chumraíocht KNewsTicker +Comment[gl]=Unha interfaz para a configuración de KNewsTicker +Comment[he]=ממשק לקביעת התצורה של KNewsTicker +Comment[hi]=के-न्यूज टिकर कॉन्फ़िगरेशन के लिए फ्रन्टएण्ड +Comment[hr]=Sučelje za podešavanje KNewsTicker-a +Comment[hu]=Előtétprogram a KNewsTicker beállításához +Comment[is]=Stillingatól fyrir Fréttastrimilinn +Comment[it]=Un'interfaccia grafica per la configurazione di KNewsTicker +Comment[ja]=KNewsTicker (ニュースティッカー) の設定フロントエンド +Comment[ka]=KNewsTicker კონფიგურაციის +Comment[kk]=KNewsTicker баптауының интерфейсі +Comment[km]=ផ្នែកខាងមុខសម្រាប់កំណត់រចនាសម្ព័ន្ធ KNewsTicker +Comment[ko]=K새소식 표시기 설정 도구 +Comment[lt]=Naudotojo sąsaja, skirta KNewsTicker derinimui +Comment[lv]=KZiņuTikkera konfigurēšanas frontends +Comment[mk]=Интерфејс за конфигурацијата на KNewsTicker +Comment[mn]=KNewsTicker-ийн Тохируулгыг Үзүүлэх +Comment[ms]=Bahagian depan untuk penyelarasan KNewsTicker +Comment[mt]=Faċċata għall-konfigurazzjoni ta' KNewsTicker +Comment[nb]=Program for oppsett av KNewsTicker +Comment[nds]=En Böversiet för de KNewsTicker-Instellen +Comment[ne]=केडीई न्यूज टिकर कन्फिगरेसनका लागि फ्रन्टइन्ड +Comment[nl]=Een grafische schil voor de configuratie van KNewsTicker +Comment[nn]=Program for oppsett av KNewsTicker +Comment[nso]=Mafelelo a kapele a peakanyo ya Seswai sa KDitaba +Comment[pl]=Konfiguracja KNewsTickera +Comment[pt]=Configuração do extractor de notícias +Comment[pt_BR]=Uma interface para configuração do KNewsTicker +Comment[ro]=O interfaţă de configurare pentru Ştiri Internet +Comment[ru]=Графическая оболочка для клиента новостей +Comment[se]=Prográmma mainna heiveha KNewsTicker +Comment[sk]=Nastavenie KNewsTicker +Comment[sl]=Vmesnik za nastavitve programa KNewsTicker +Comment[sr]=Интерфејс за подешавање KNewsTicker-а +Comment[sr@Latn]=Interfejs za podešavanje KNewsTicker-a +Comment[sv]=Gränssnitt för anpassning av nyhetsövervakaren +Comment[ta]=செய்தி அறிவிப்பதற்கான முன் அமைப்பு +Comment[tg]=Муқоваи графикӣ барои танзими KДидабони Ахборот +Comment[th]=ฟรอนต์เอนด์สำหรับปรับแต่งตั๋วข่าว - K +Comment[tr]=KDE Haber Gözlemcisi yapılandırması için önyüz +Comment[uk]=Зовнішній інтерфейс налаштування KNewsTicker +Comment[ven]=U iswa phanda uitela Mavhekanyele a musengulusi wa mafhungo a K +Comment[xh]=Umphambili wesiphelo soqwalaselo se KNewsTicker +Comment[zh_CN]=KNewsTicker 配置的前端 +Comment[zh_HK]=設定 KNewsTicker 的前端程式 +Comment[zh_TW]=設定 KNewsTicker 的前端 +Comment[zu]=Isiqalo sesiphelo sezindaba zesiphelo senhlanganiso lomlekeleli wezindaba ze K +MimeType=text/rdf;text/rss +Exec=knewstickerstub -a %u +Icon=knode +NoDisplay=true +Type=Application +Terminal=false +InitialPreference=8 +Actions=Add; +X-KDE-StartupNotify=false + +[Desktop Action Add] +Exec=knewstickerstub -a %u +Name=Use with KNewsTicker +Name[af]=Gebruik met K-nuustikker +Name[ar]=استخدمه مع مجدد الأخبار +Name[az]=KNewsTicker ilə birgə işlədin +Name[be]=Выкарыстаць з KNewsTicker +Name[bg]=Използване с четеца на новини +Name[bn]=কে-নিউজ-টিকারের সঙ্গে ব্যবহার +Name[br]=Implijit gant KNewsTicker +Name[bs]=Koristite sa KNewsTicker-om +Name[ca]=Empra amb el KNewsTicker +Name[cs]=Použít s KNewsTickerem +Name[cy]=Defnyddio efo KTicerNewyddion +Name[da]=Brug med KNewsTicker +Name[de]=Zur Benutzung mit KNewsticker +Name[el]=Χρήση με το KNewsTicker +Name[eo]=Uzu kun Novaĵprezentilo +Name[es]=Usar con KNewsTicker +Name[et]=Kasutamine KNewsTickeriga +Name[eu]=Erabili KNewsTicker-ekin +Name[fa]=استفاده با KNewsTicker +Name[fi]=Käytä KNewsTicker-ohjelman kanssa +Name[fr]=Utiliser avec KNewsTicker +Name[gl]=Usar con KNewsTicker +Name[he]=השתמש ב- KNewsTicker +Name[hi]=के-न्यूज टिकर के साथ इस्तेमाल करें +Name[hr]=Koristi sa KNewsTicker-om +Name[hu]=A KNewsTicker egyik alkotórésze +Name[id]=Gunakan dengan KNewsTicker +Name[is]=Notist með 'Fréttastrimli' +Name[it]=Utilizza con KNewsTicker +Name[ja]=ニュースティッカーを使用 +Name[ka]=KNewsTicker გამოყენება +Name[kk]=KNewsTicker-мен бірге қолданылады +Name[km]=ប្រើជាមួយ KNewsTicker +Name[ko]=K새소식 표시기와 같이 씀 +Name[lt]=Naudojama su KNewsTicker +Name[lv]=Lieto ar KZiņuTikkeru +Name[mk]=Користи со KNewsTicker +Name[mn]=KNewsTicker тэй хэрэглэх +Name[ms]=Digunakan bersama KNewsTicker +Name[mt]=Uża ma' KNewsTicker +Name[nb]=Bruk med KNewsTicker +Name[nds]=Bruuk dat mit KNewsTicker +Name[ne]=केडीई न्यूज टिकरसँग प्रयोग गर्नुहोस् +Name[nl]=Gebruik met KNewsTicker +Name[nn]=Bruk med KNewsTicker +Name[nso]=Somisa le Seswai sa KDitaba +Name[pl]=Użyj za pomocą KNewsTickera +Name[pt]=Usar com as Notícias +Name[pt_BR]=Usar com KNewsTicker +Name[ro]=Utilizează cu Ştiri Internet +Name[ru]=Используется с KNewsTicker +Name[se]=Geavat ovttas KNewsTicker:in +Name[sk]=Použiť s KNewsTicker +Name[sl]=Uporabite s KNewsTicker +Name[sr]=Користи са KNewsTicker-ом +Name[sr@Latn]=Koristi sa KNewsTicker-om +Name[sv]=Använd med nyhetsövervakaren +Name[ta]=கேசெய்தி அறிவிப்பான் +Name[tg]=Бо KДидабони Ахборот истифода мегардад +Name[th]=ใช้กับตั๋วข่าว - K +Name[tr]=KDE Haber Gözlemcisi ile birlikte kullanın +Name[uk]=Для використання з KNewsTicker +Name[ven]=Shumisani na Musengulusi wa mafhungo +Name[xh]=Yisebenzise ne KNewsTicker +Name[zh_CN]=和 KNewsTicker 一起使用 +Name[zh_HK]=和 KNewsTicker 一起使用 +Name[zh_TW]=和 KNewsTicker 一起使用 +Name[zu]=Yisebenzise nomlungiseleli wezindaba ze K +X-KDE-StartupNotify=false diff --git a/knewsticker/knt-0.1-0.2.pl b/knewsticker/knt-0.1-0.2.pl new file mode 100755 index 00000000..2ca9e30c --- /dev/null +++ b/knewsticker/knt-0.1-0.2.pl @@ -0,0 +1,104 @@ +#!/usr/bin/perl +# convert which file to which file? +# I did nto bother to build in any checks. so that file better exists and it is readable and the data will +# be written to a writeable directory. Since this is an old config file, it is safe to assume, that is the +# case. + +#$file = $ARGV[0]; + +# Take your hands off the rest unless you darn well knwo what you are doing +################################################################################## +################################################################################## + +open(INFO, $file); + my ($section, %data); + +#read in all the data, split it up into hashes. Thanks again to malte for much input +while (<>) { + if (/\[(.*)\]/) { + $sections{$section} = {%data} if $section; + $section = $1; + undef %data; + next; + } +$data{$1} = $2 if /^([^=]*)=(.*)$/; +} + +$sections{$section} = {%data} if $section; + +# do the data writing magic +#first of all be check how many old news souerces we have + +$sources = $sections{'General'}->{'News sources'}; +#gather all news sources into a very pretty string before we write the global section +#also give some feedback to the user +for my $i (0..($sources-1)) { + $all .= "," .$sections{"News source #$i"}->{'Name'}; + $all =~s/^,//; +} + +# write the main section +print "[KNewsTicker]\n"; + +while (($key,$dat) = each(%{$sections{'General'}})) { + if ($key ne "News sources") { + if ($key eq "Interval") { + $key="Update interval"; + } + if ($key eq "Scroll most recent only") { + $key="Scroll most recent headlines only"; + } + print "$key=$dat\n"; + } else { + print "News sources=".$all."\n"; + } + +} + +# next merge the old scrolling section into the KNewticker Section +while (($key,$dat) = each(%{$sections{'Scrolling'}})) { + if ($key eq "Background") { + $key="Background color"; + + } + if ($key eq "Foreground") { + $key="Foreground color"; + } + if ($key eq "Highlighted") { + $key="Highlighted color"; + } + if ($key eq "Underline highlighted") { + $key="Underline highlighted headlines"; + } + if (($key eq "Direction") && ($dat eq "Left")) { + $key ="Scrolling direction"; + $dat = "0"; + +} +if (($key eq "Direction") && ($dat ne "Left")) { + + $key ="Scrolling direction"; + +} +if ($key eq "Speed") { + $key="Scrolling speed"; +} + + + + print "$key=$dat\n"; +} + +# next we write the news sources, making sure we have the correct headers +for my $i (0..($sources-1)) { + +print "\n[" .$sections{"News source #$i"}->{'Name'} ."]\n"; + while (($key,$dat) = each(%{$sections{"News source #$i"}})) { + if ($key ne "Address") { + print "$key=$dat\n"; + } else { + print "Source file=".$dat."\n"; + } + } +} + diff --git a/knewsticker/kntsrcfilepropsdlg/Makefile.am b/knewsticker/kntsrcfilepropsdlg/Makefile.am new file mode 100644 index 00000000..9782b90c --- /dev/null +++ b/knewsticker/kntsrcfilepropsdlg/Makefile.am @@ -0,0 +1,12 @@ +INCLUDES = -I$(top_srcdir)/knewsticker/common -I$(top_srcdir)/librss $(all_includes) + +kde_module_LTLIBRARIES = libkntsrcfilepropsdlg.la + +libkntsrcfilepropsdlg_la_SOURCES = kntsrcfilepropsdlg.cpp \ + kntsrcfilepropsdlgwidget.ui +libkntsrcfilepropsdlg_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +libkntsrcfilepropsdlg_la_LIBADD = $(LIB_KIO) ../common/libknewstickercommon.la ../../librss/librss.la +libkntsrcfilepropsdlg_la_METASOURCES = AUTO + +service_DATA = kntsrcfilepropsdlg.desktop +servicedir = $(kde_servicesdir) diff --git a/knewsticker/kntsrcfilepropsdlg/kntsrcfilepropsdlg.cpp b/knewsticker/kntsrcfilepropsdlg/kntsrcfilepropsdlg.cpp new file mode 100644 index 00000000..93bc71cc --- /dev/null +++ b/knewsticker/kntsrcfilepropsdlg/kntsrcfilepropsdlg.cpp @@ -0,0 +1,130 @@ +/* + * kntsrcfilepropsdlg.cpp + * + * Copyright (c) 2001, 2002, 2003 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 "kntsrcfilepropsdlg.h" +#include "kntsrcfilepropsdlgwidget.h" +#include "xmlnewsaccess.h" +#include "newsiconmgr.h" + +#include <article.h> +#include <document.h> +#include <loader.h> + +#include <kapplication.h> +#include <klistbox.h> +#include <klocale.h> +#include <kurl.h> +#include <kurllabel.h> +#include <kstandarddirs.h> +#include <kglobal.h> + +#include <qmultilineedit.h> +#include <qvbox.h> + +using namespace RSS; + +class ArticleListBoxItem : public QListBoxText +{ + public: + ArticleListBoxItem( QListBox *listbox, const Article &article ); + + const Article &article() const { return m_article; } + + private: + Article m_article; +}; + +ArticleListBoxItem::ArticleListBoxItem( QListBox *listbox, const Article &article ) + : QListBoxText( listbox ), + m_article( article ) +{ + setText( article.title() ); +} + +KntSrcFilePropsDlg::KntSrcFilePropsDlg(KPropertiesDialog *props) + : KPropsDlgPlugin(props) +{ + m_child = new KntSrcFilePropsDlgWidget(properties->addVBoxPage(i18n("News Resource"))); + connect(m_child->urlName, SIGNAL(leftClickedURL(const QString &)), + SLOT(slotOpenURL(const QString &))); + connect(m_child->lbArticles, SIGNAL(executed(QListBoxItem *)), + SLOT(slotClickedArticle(QListBoxItem *))); + + Loader *loader = Loader::create(); + connect(loader, SIGNAL(loadingComplete(Loader *, Document, Status)), + SLOT(slotConstructUI(Loader *, Document, Status))); + loader->loadFrom(props->item()->url(), new FileRetriever); + + connect(NewsIconMgr::self(), SIGNAL(gotIcon(const KURL &, const QPixmap &)), + SLOT(slotGotIcon(const KURL &, const QPixmap &))); + + m_child->show(); +} + +void KntSrcFilePropsDlg::slotConstructUI(Loader *, Document doc, Status status) +{ + if (status != RSS::Success) + return; + + KURL iconURL = doc.link(); + iconURL.setEncodedPathAndQuery(QString::fromLatin1("/favicon.ico")); + NewsIconMgr::self()->getIcon(iconURL); + + m_child->urlName->setText(doc.title()); + m_child->urlName->setURL(doc.link().url()); + + m_child->mleDescription->setText(doc.description()); + + Article::List::ConstIterator it = doc.articles().begin(); + Article::List::ConstIterator end = doc.articles().end(); + for (; it != end; ++it) + new ArticleListBoxItem(m_child->lbArticles, *it); +} + +void KntSrcFilePropsDlg::slotOpenURL(const QString &url) +{ + kapp->invokeBrowser(url); +} + +void KntSrcFilePropsDlg::slotGotIcon(const KURL &, const QPixmap &pixmap) +{ + m_child->pixmapIcon->setPixmap(pixmap); +} + +void KntSrcFilePropsDlg::slotClickedArticle(QListBoxItem *item) +{ + ArticleListBoxItem *articleItem = static_cast<ArticleListBoxItem *>(item); + slotOpenURL(articleItem->article().link().url()); +} + +QObject *KntSrcFilePropsFactory::createObject(QObject *parent, const char *, + const char *classname, const QStringList &) +{ + if (QString::fromLatin1(classname) == "KPropsDlgPlugin") + { + if (!parent->inherits("KPropertiesDialog")) + return 0L; + + QObject *obj = new KntSrcFilePropsDlg(static_cast<KPropertiesDialog *>(parent)); + return obj; + } + return 0L; +} + +extern "C" +{ + KDE_EXPORT void *init_libkntsrcfilepropsdlg() + { + KGlobal::locale()->insertCatalogue( "knewsticker" ); + return new KntSrcFilePropsFactory(); + } +} + +#include "kntsrcfilepropsdlg.moc" diff --git a/knewsticker/kntsrcfilepropsdlg/kntsrcfilepropsdlg.desktop b/knewsticker/kntsrcfilepropsdlg/kntsrcfilepropsdlg.desktop new file mode 100644 index 00000000..6902d9b3 --- /dev/null +++ b/knewsticker/kntsrcfilepropsdlg/kntsrcfilepropsdlg.desktop @@ -0,0 +1,69 @@ +[Desktop Entry] +Type=Service +Name=KNewsticker Source File Properties Page +Name[af]=K-nuustikker Bron Lêer Eienskappe Bladsy +Name[ar]=صفحة خصائص ملف مصدر مجدد الأخبار +Name[az]=KNewsticker Mənbə Faylı Xüsusiyyətləri Səhifəsi +Name[bg]=Настройване на файла източник на KNewsticker +Name[bn]=কে-নিউজ-টিকার উত্স ফাইল বৈশিষ্ট্যাবলী পাতা +Name[bs]=KNewsticker stranica sa osobinama izvorne datoteke +Name[ca]=Pàgina de propietats dels fitxers font del KNewsticker +Name[cs]=Popis vlastností zdrojového souboru programu KNewsticker +Name[cy]=Tudalen Priodweddau Ffeil Tarddiad KTicerNewyddion +Name[da]=KNewsTickers side med egenskaber for kildefil +Name[de]=KNewsticker: Einstellungsseite für Quelldateien +Name[el]=Σελίδα ιδιοτήτων αρχείου πηγής KNewsticker +Name[eo]=Ecopaĝo por Novaĵprezentilaj fontdosieroj +Name[es]=Página de propiedades de archivos fuente de KNewsticker +Name[et]=KNewstickeri lähtefaili omaduste dialoog +Name[eu]=KNewsticker iturburu fitxategiaren propietateen orria +Name[fa]=صفحۀ ویژگیهای پروندۀ مبدأ KNewsticker +Name[fi]=KNewsticker lähdetiedostojen asetussivu +Name[fr]=Page des propriétés du fichier source de KNewsTicker +Name[gl]=Páxina de propiedades dos arquivos fonte de KNewsTicker +Name[he]=דף מאפייני קובץ מקור של KNewsTicker +Name[hi]=के-न्यूज टिकर स्रोत फ़ाइल गुण पृष्ठ +Name[hr]=Stranica sa postavkama KNewsTicker izvorne datoteke +Name[hu]=A KNewsTicker forrásfájlok tulajdonságlapja +Name[is]=Stillisíða fyrir frumskrár Fréttastrimils +Name[it]=Pagina proprietà file sorgente di notizie per KNewsticker +Name[ja]=KNewsticker ソースファイルプロパティページ +Name[ka]=KNewsticker წყაროს ფაილის თვისებათა გვერდი +Name[kk]=KNewsticker файлының қасиеттер беті +Name[km]=ទំព័រលក្ខណៈសម្បត្តិឯកសារប្រភព KNewsticker +Name[lt]=KNewsticker pirminio teksto bylos parinkčių puslapis +Name[lv]=KZiņutikkera Avota Faila Īpašību Lapa +Name[mk]=Страница за својствата на изворната датотека на KNewsticker +Name[mn]=KNewsticker сурвалж файлын Тодорхойлолт хуудас +Name[ms]=Laman Ciri-ciri Fail Sumber KNewsticker +Name[mt]=Paġna ta' Propjetajiet Fajl ta' Sors KNewsticker +Name[nb]=Egenskaper for kildefiler til KNewsticker +Name[nds]=KNewsTicker Borndateien-Egenschappensiet +Name[ne]=केडीई न्यूज टिकर स्रोत फाइल विशेषता पृष्ठ +Name[nl]=KNewsticker Bronbestand Eigenschappenpagina +Name[nn]=Eigenskapsside for KNewsticker-kjeldefil +Name[nso]=Letlakala la Dithoto tsa Faele ya Mothopo wa seswai sa KDitaba +Name[pl]=Strona właściwości pliku źródłowego KNewsTickera +Name[pt]=Página de Propriedades do Ficheiro da Fonte do KNewsticker +Name[pt_BR]=Página de Propriedades do Arquivo Fonte do KNewsTicher +Name[ro]=Pagină de proprietăţi pentru fişier sursă KNewsticker +Name[ru]=Страница свойств сведений о файле KNewsticker +Name[se]=KNewsTicker-gáldofiilla iešvuohtasiidu +Name[sk]=Popis vlastností konfiguračného súboru pre KNewsticker +Name[sl]=Stran z lastnostmi za izvorno datoteko KNewsTicker +Name[sr]=KNewsticker страна за подешавање својстава изворних фајлова +Name[sr@Latn]=KNewsticker strana za podešavanje svojstava izvornih fajlova +Name[sv]=Nyhetsövervakarens sida för källfilsegenskaper +Name[ta]=கேசெய்தி அறிவிப்பானின் மூல கோப்பின் பண்புகளை அறியும் பக்கம். +Name[tg]=Саҳофаи Хусусиятҳои Файли Сарчашмавии KДидабони Ахборот +Name[th]=หน้าคุณสมบัติของแฟ้มต้นฉบับตั๋วข่าว - K +Name[tr]=KDE Haber Gözlemcisi Kaynak Dosyası Özellikler Sayfası +Name[uk]=Сторінка властивостей вихідного файла KNewsticker +Name[ven]=Siatari la tshishumiswa tshavhubvo ha faela la tshauthika mafhungo a K +Name[xh]=Iphepha Leempahla Lemvelaphi Yefayile ye KNewsticker +Name[zh_CN]=KNewsticker 来源文件属性页 +Name[zh_HK]=KNewsticker 來源檔案屬性頁 +Name[zh_TW]=KNewsticker 來源檔案屬性頁 +Name[zu]=Umlekeleli wezindaba ze K wephepha lefayela Yemvelaphi Yempahla +X-KDE-Library=libkntsrcfilepropsdlg +ServiceTypes=KPropsDlg/Plugin,text/rdf,text/rss diff --git a/knewsticker/kntsrcfilepropsdlg/kntsrcfilepropsdlg.h b/knewsticker/kntsrcfilepropsdlg/kntsrcfilepropsdlg.h new file mode 100644 index 00000000..8fe1be58 --- /dev/null +++ b/knewsticker/kntsrcfilepropsdlg/kntsrcfilepropsdlg.h @@ -0,0 +1,57 @@ +/* + * kntsrcfilepropsdlg.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 KNTSRCFILEPROPSDLG_H +#define KNTSRCFILEPROPSDLG_H + +#include <global.h> + +#include <klibloader.h> +#include <kpropertiesdialog.h> + +class KntSrcFilePropsDlgWidget; +class QListBoxItem; + +namespace RSS { + class Loader; + class Document; +} + +using RSS::Loader; +using RSS::Document; +using RSS::Status; + +class KntSrcFilePropsFactory : public KLibFactory +{ + Q_OBJECT + + public: + virtual QObject *createObject(QObject * = 0, const char * = 0, + const char * = "QObject", const QStringList & = QStringList()); +}; + +class KntSrcFilePropsDlg : public KPropsDlgPlugin +{ + Q_OBJECT + + public: + KntSrcFilePropsDlg(KPropertiesDialog *); + + protected slots: + void slotOpenURL(const QString &); + void slotConstructUI(Loader *loader, Document doc, Status status); + void slotGotIcon(const KURL &, const QPixmap &); + void slotClickedArticle(QListBoxItem *); + + private: + KntSrcFilePropsDlgWidget *m_child; +}; + +#endif // KNTSRCFILEPROPSDLG_H diff --git a/knewsticker/kntsrcfilepropsdlg/kntsrcfilepropsdlgwidget.ui b/knewsticker/kntsrcfilepropsdlg/kntsrcfilepropsdlgwidget.ui new file mode 100644 index 00000000..b8d1827e --- /dev/null +++ b/knewsticker/kntsrcfilepropsdlg/kntsrcfilepropsdlgwidget.ui @@ -0,0 +1,215 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KntSrcFilePropsDlgWidget</class> +<comment>The widget to be used for the RDF/RSS file properties dialog plugin.</comment> +<author>Frerich Raabe <raabe@kde.org></author> +<widget class="QWidget"> + <property name="name"> + <cstring>KntSrcFilePropsDlgWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>311</width> + <height>274</height> + </rect> + </property> + <property name="layoutMargin" stdset="0"> + </property> + <property name="layoutSpacing" stdset="0"> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>4</number> + </property> + <property name="spacing"> + <number>4</number> + </property> + <spacer row="0" column="3"> + <property name="name"> + <cstring>Spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="0" column="4"> + <property name="name"> + <cstring>pixmapIcon</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="pixmap"> + <pixmap>image0</pixmap> + </property> + <property name="toolTip" stdset="0"> + <string>Icon of this news site</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can see the icon of this news site.</string> + </property> + </widget> + <widget class="KURLLabel" row="0" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>urlName</cstring> + </property> + <property name="text"> + <string>heise online news</string> + </property> + <property name="url" stdset="0"> + <string>http://www.heise.de/newsticker/</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>lDescription</cstring> + </property> + <property name="text"> + <string>Description:</string> + </property> + <property name="toolTip" stdset="0"> + <string>Brief description of the news site</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can see a brief description about the news site and its contents.</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>lName</cstring> + </property> + <property name="text"> + <string>Name:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>leName</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Name of the news site</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This is the name of the news site.</string> + </property> + </widget> + <widget class="QMultiLineEdit" row="1" column="2" rowspan="2" colspan="3"> + <property name="name"> + <cstring>mleDescription</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="wordWrap"> + <enum>WidgetWidth</enum> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Brief description of the news site</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can see a brief description about the news site and its contents.</string> + </property> + </widget> + <spacer row="2" column="0"> + <property name="name"> + <cstring>Spacer_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Maximum</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>63</height> + </size> + </property> + </spacer> + <widget class="KSeparator" row="3" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>Line1</cstring> + </property> + <property name="orientation"> + <number>5</number> + </property> + </widget> + <widget class="QLabel" row="4" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>lArticles</cstring> + </property> + <property name="text"> + <string>Available articles:</string> + </property> + <property name="toolTip" stdset="0"> + <string>Articles contained within this source file</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This list shows the headlines and links to the corresponding complete articles which have been stored in the source file whose properties you are watching.</string> + </property> + </widget> + <widget class="KListBox" row="5" column="0" rowspan="1" colspan="5"> + <property name="name"> + <cstring>lbArticles</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip" stdset="0"> + <string>Articles contained within this source file</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This list shows the headlines and links to the corresponding complete articles which have been stored in the source file whose properties you are watching.<p>You can open the corresponding full article for each headline by, depending on the global KDE settings, clicking or double-clicking on a headline</string> + </property> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="597">89504e470d0a1a0a0000000d49484452000000100000001008060000001ff3ff610000021c49444154388d8592316813511cc67f910c1770b8408704742838248260c63ad943974041533a84d0a1440a9ad6418a83dc22a853b62693c40c25e9503c07e93908ed601b3b354be90916ae43e10e2c5c06e1fed007714873b56daadff28ef7eefbf17dfff762db9d6dfe567db9dee73faa2c5662c3eff8c5c3dcdd1ca56209518216d7a2d5d9dba5b1d2c6b86f505faef787907300f393d91f9f4a621e7c8fccee5761e3dd3afa7503fbcb26e5f97294b4b25889c52f9aad9716e96c1614783f5d8c171318af0c365e6f401c76bbbb1164e1d9423f020ccc36b93b93983326fa988e73e462ab0fb8471ddc4397542a457ba54da3d9e0d0393c3f03e79b873e9e227f2b4f3693257d338d9be9e2adb9c82f8dfd837d961697f08e5ddc1ffb746e7469af5a5c1b02aa93d5583223f8be0f0ad64f5ad83b36c435509020017148eb29b299dbdccbe500ce0000b5871f639eefd149d9585b16aee7e2343d6a73358c0713a04242d543d334e4b77f193094bd639f99e76b4ccfe46935eb84aa87bdd64224403b2d3f12303457e7aa4c3fca8302949038bddae4581a11b91ac0964e32077a62d03f941ea562191414a60aa0403bfdf5d24b04683dad22aa070cccd66a83c2e30228419420be8f9c045727308fdf527eff865069241494662b589f6d44044d0112460946cf602da0dbddc4f75d421510f65c0ac53220880451922b2b548b26cc9a8804387bcea08eea8204034828ff9ec193e74ba3b647ea0f69200af223e8435e0000000049454e44ae426082</data> + </image> +</images> +<includes> + <include location="global" impldecl="in declaration">klistbox.h</include> + <include location="global" impldecl="in declaration">kurllabel.h</include> + <include location="global" impldecl="in declaration">kseparator.h</include> +</includes> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurllabel.h</includehint> + <includehint>kseparator.h</includehint> + <includehint>klistbox.h</includehint> +</includehints> +</UI> diff --git a/knewsticker/newsscroller.cpp b/knewsticker/newsscroller.cpp new file mode 100644 index 00000000..9d11f19e --- /dev/null +++ b/knewsticker/newsscroller.cpp @@ -0,0 +1,596 @@ +/* + * newsscroller.cpp + * + * Copyright (c) 2000, 2001 Frerich Raabe <raabe@kde.org> + * Copyright (c) 2001 Malte Starostik <malte@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 <dcopclient.h> + +#include <qpainter.h> +#include <qregexp.h> +#include <qtimer.h> + +#include <kcursor.h> +#include <kstandarddirs.h> +#include <kurldrag.h> +#include <kmessagebox.h> + +#include "configaccess.h" +#include "newsscroller.h" +#include "newsengine.h" +#include <kapplication.h> + +class Headline +{ +public: + Headline(NewsScroller *scroller, const Article::Ptr &article) + : m_scroller(scroller), + m_article(article), + m_normal(0), + m_highlighted(0) + { + }; + + virtual ~Headline() + { + reset(); + } + + Article::Ptr article() const { return m_article; } + + int width() { return pixmap()->width(); } + int height() { return pixmap()->height(); } + + QPixmap *pixmap(bool highlighted = false, bool underlineHighlighted = true) + { + QPixmap *result = highlighted ? m_highlighted : m_normal; + if (!result) { + const QFontMetrics &metrics = m_scroller->fontMetrics(); + + int w, h; + if (m_scroller->m_cfg->showIcons()) { + w = m_article->newsSource()->icon().width() + 4 + metrics.width(m_article->headline()); + h = QMAX(metrics.height(), m_article->newsSource()->icon().height()); + } else { + w = metrics.width(m_article->headline()); + h = metrics.height(); + } + + if (ConfigAccess::rotated(static_cast<ConfigAccess::Direction>(m_scroller->m_cfg->scrollingDirection()))) + result = new QPixmap(h, w); + else + result = new QPixmap(w, h); + + result->fill(m_scroller->m_cfg->backgroundColor()); + QPainter p(result); + QFont f = m_scroller->font(); + + if (highlighted) + f.setUnderline(underlineHighlighted); + + p.setFont(f); + p.setPen(highlighted ? m_scroller->m_cfg->highlightedColor() : m_scroller->m_cfg->foregroundColor()); + + if (ConfigAccess::rotated(static_cast<ConfigAccess::Direction>(m_scroller->m_cfg->scrollingDirection()))) { + if (m_scroller->m_cfg->scrollingDirection() == ConfigAccess::UpRotated) { + // Note that rotation also + // changes the coordinate space + // + p.rotate(90.0); + if (m_scroller->m_cfg->showIcons()) { + p.drawPixmap(0, -m_article->newsSource()->icon().height(), m_article->newsSource()->icon()); + p.drawText(m_article->newsSource()->icon().width() + 4, -metrics.descent(), m_article->headline()); + } else + p.drawText(0, -metrics.descent(), m_article->headline()); + } else { + p.rotate(-90.0); + if (m_scroller->m_cfg->showIcons()) { + p.drawPixmap(-w, h - m_article->newsSource()->icon().height(), m_article->newsSource()->icon()); + p.drawText(-w + m_article->newsSource()->icon().width() + 4, h - metrics.descent(), m_article->headline()); + } else + p.drawText(-w, h - metrics.descent(), m_article->headline()); + } + } else { + if (m_scroller->m_cfg->showIcons()) { + p.drawPixmap(0, + (result->height() - m_article->newsSource()->icon().height()) / 2, + m_article->newsSource()->icon()); + p.drawText(m_article->newsSource()->icon().width() + 4, result->height() - metrics.descent(), m_article->headline()); + } else + p.drawText(0, result->height() - metrics.descent(), m_article->headline()); + } + + if (highlighted) + m_highlighted = result; + else + m_normal = result; + } + return result; + } + + void reset() + { + delete m_normal; + m_normal = 0; + delete m_highlighted; + m_highlighted = 0; + } + +private: + NewsScroller *m_scroller; + Article::Ptr m_article; + QPixmap *m_normal; + QPixmap *m_highlighted; +}; + +NewsScroller::NewsScroller(QWidget *parent, ConfigAccess *cfg, const char *name) + : QFrame(parent, name, WNoAutoErase), + m_cfg(cfg), + m_scrollTimer(new QTimer(this)), + m_activeHeadline(0), + m_mouseDrag(false), + m_totalStepping(0.0) +{ + if (!kapp->dcopClient()->isAttached()) + kapp->dcopClient()->attach(); + + setFrameStyle(StyledPanel | Sunken); + + m_headlines.setAutoDelete(true); + + connect(m_scrollTimer, SIGNAL(timeout()), SLOT(slotTimeout())); + + setAcceptDrops(true); + + reset(); +} + +QSize NewsScroller::sizeHint() const +{ + return QSize(fontMetrics().width(QString::fromLatin1("X")) * 20, fontMetrics().height() * 2); +} + +QSizePolicy NewsScroller::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); +} + +void NewsScroller::clear() +{ + m_headlines.clear(); + reset(); +} + +void NewsScroller::dragEnterEvent(QDragEnterEvent* event) +{ + event->accept(QTextDrag::canDecode(event)); +} + +void NewsScroller::dropEvent(QDropEvent* event) +{ + QString newSourceUrl; + if ( QTextDrag::decode(event, newSourceUrl) ) { + // <HACK> + // This is just for http://www.webreference.com/services/news/ + newSourceUrl = newSourceUrl.replace(QRegExp( + QString::fromLatin1("^view-source:http%3A//")), + QString::fromLatin1("http://")); + // </HACK> + newSourceUrl = newSourceUrl.stripWhiteSpace(); + if (!isHeadline(newSourceUrl) && KMessageBox::questionYesNo(this, i18n("<p>Do you really want to add '%1' to" + " the list of news sources?</p>") + .arg(newSourceUrl), QString::null, i18n("Add"), KStdGuiItem::cancel()) == KMessageBox::Yes) { + KConfig cfg(QString::fromLatin1("knewsticker_panelappletrc"), false, false); + ConfigAccess configFrontend(&cfg); + QStringList newsSources = configFrontend.newsSources(); + + QString name = i18n("Unknown"); + if (newsSources.contains(name)) + for (unsigned int i = 0; ; i++) + if (!newsSources.contains(i18n("Unknown %1").arg(i))) { + name = i18n("Unknown %1").arg(i); + break; + } + + newsSources += name; + configFrontend.setNewsSource(NewsSourceBase::Data(name, newSourceUrl)); + configFrontend.setNewsSources(newsSources); + + QByteArray data; + kapp->dcopClient()->send("knewsticker", "KNewsTicker", "reparseConfig()", data); + } + } +} + +bool NewsScroller::isHeadline(const QString &location) const +{ + for (Headline *h = m_headlines.first(); h; h = m_headlines.next()) + if (h->article()->address() == location) + return true; + + return false; +} + +void NewsScroller::addHeadline(Article::Ptr article) +{ + for (unsigned int i = 0; i < m_cfg->filters().count(); i++) + if (m_cfg->filter(i).matches(article)) + return; + + m_headlines.append(new Headline(this, article)); +} + +void NewsScroller::scroll(int distance, bool interpret_directions) +{ + unsigned int t_dir; + if ( interpret_directions ) t_dir = m_cfg->scrollingDirection(); + else t_dir = m_cfg->horizontalScrolling() ? ConfigAccess::Left : ConfigAccess::Up; + switch (t_dir) { + case ConfigAccess::Left: + m_offset -= distance; + if (m_offset <= - scrollWidth()) + m_offset = m_offset + scrollWidth() - m_separator.width(); + break; + case ConfigAccess::Right: + m_offset += distance; + if (m_offset >= contentsRect().width()) + m_offset = m_offset + m_separator.width() - scrollWidth(); + break; + case ConfigAccess::Up: + case ConfigAccess::UpRotated: + m_offset -= distance; + if (m_offset <= - scrollHeight()) + m_offset = m_offset + scrollHeight() - m_separator.height(); + break; + case ConfigAccess::Down: + case ConfigAccess::DownRotated: + m_offset += distance; + if (m_offset >= contentsRect().height()) + m_offset = m_offset + m_separator.height() - scrollHeight(); + } + + QPoint pt = mapFromGlobal(QCursor::pos()); + + if (contentsRect().contains(pt)) + updateActive(pt); + + update(); +} + +void NewsScroller::enterEvent(QEvent *) +{ + if (m_cfg->slowedScrolling() && m_cfg->scrollingSpeed() > 1) + m_scrollTimer->changeInterval(speedAsInterval(m_cfg->scrollingSpeed() / 2)); +} + +void NewsScroller::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == QMouseEvent::LeftButton || e->button() == QMouseEvent::MidButton) { + m_dragPos = e->pos(); + + if (m_activeHeadline) + m_tempHeadline = m_activeHeadline->article()->headline(); + } +} + +void NewsScroller::mouseReleaseEvent(QMouseEvent *e) +{ + if ((e->button() == QMouseEvent::LeftButton || e->button() == QMouseEvent::MidButton) + && m_activeHeadline && m_activeHeadline->article()->headline() == m_tempHeadline + && !m_mouseDrag) { + m_activeHeadline->article()->open(); + m_tempHeadline = QString::null; + } + + if (e->button() == QMouseEvent::RightButton) + emit(contextMenu()); + + if (m_mouseDrag) { + m_mouseDrag = false; + if (m_cfg->scrollingSpeed()) + m_scrollTimer->start(speedAsInterval(m_cfg->scrollingSpeed())); + } +} + +void NewsScroller::mouseMoveEvent(QMouseEvent *e) +{ + // Are we in a drag phase? + if (!m_mouseDrag) { + // If not, check whether we need to start a drag. + int dragDistance = 0; + if (m_cfg->horizontalScrolling()) + dragDistance = QABS(e->x() - m_dragPos.x()); + else + dragDistance = QABS(e->y() - m_dragPos.y()); + m_mouseDrag = (e->state() & QMouseEvent::LeftButton != 0) && + dragDistance >= KGlobal::config()->readNumEntry("StartDragDist", KApplication::startDragDistance()); + if (m_mouseDrag) // Stop the scroller if we just started a drag. + m_scrollTimer->stop(); + } else { + // If yes, move the scroller accordingly. + bool createDrag; + if (m_cfg->horizontalScrolling()) { + scroll(m_dragPos.x() - e->x(), false); + m_dragPos = e->pos(); + createDrag = e->y() < 0 || e->y() > height(); + } else { + scroll(m_dragPos.y() - e->y(), false); + m_dragPos = e->pos(); + createDrag = e->x() < 0 || e->x() > width(); + } + m_dragPos = e->pos(); + if (createDrag && m_activeHeadline) { + KURL::List url; + url.append(m_activeHeadline->article()->address()); + QDragObject *drag = new KURLDrag(url, this); + drag->setPixmap(m_activeHeadline->article()->newsSource()->icon()); + drag->drag(); + m_mouseDrag = false; + if (m_cfg->scrollingSpeed()) + m_scrollTimer->start(speedAsInterval(m_cfg->scrollingSpeed())); + } + } + + if (updateActive(e->pos())) + update(); +} + +void NewsScroller::wheelEvent(QWheelEvent *e) +{ + // ### This 11 - m_cfg->mouseWheelSpeed() could be eliminated by swapping + // the labels of the QSlider. :] + int distance = qRound(QABS(e->delta()) / (11 - m_cfg->mouseWheelSpeed())); + int direction = e->delta() > 0 ? -1 : 1; + + for (int i = 0; i < distance; i++) + scroll(direction); + + QFrame::wheelEvent(e); +} + +void NewsScroller::leaveEvent(QEvent *) +{ + if (m_cfg->slowedScrolling() && m_cfg->scrollingSpeed() > 1) + m_scrollTimer->changeInterval(speedAsInterval(m_cfg->scrollingSpeed())); + + if (m_activeHeadline) { + m_activeHeadline = 0; + update(); + } +} + +void NewsScroller::drawContents(QPainter *p) +{ + if (!scrollWidth() || // No news and no "No News Available": uninitialized + m_headlines.isEmpty()) // Happens when we're currently fetching new news + return; + + QPixmap buffer(contentsRect().width(), contentsRect().height()); + buffer.fill(m_cfg->backgroundColor()); + int pos = m_offset; + + // Paste in all the separator bitmaps (" +++ ") + if (horizontal()) { + while (pos > 0) + pos -= scrollWidth() - (m_headlines.isEmpty() ? m_separator.width() : 0); + do { + bitBlt(&buffer, pos, (contentsRect().height() - m_separator.height()) / 2, &m_separator); + pos += m_separator.width(); + } while (m_headlines.isEmpty() && pos < contentsRect().width()); + } else { + while (pos > 0) + pos -= scrollHeight() - (m_headlines.isEmpty() ? 0 : m_separator.height()); + do { + bitBlt(&buffer, (contentsRect().width() - m_separator.width()) / 2, pos, &m_separator); + pos += m_separator.height(); + } while (m_headlines.isEmpty() && pos < contentsRect().height()); + } + + // Now do the headlines themselves + do { + QPtrListIterator<Headline> it(m_headlines); + for(; *it; ++it) { + if (horizontal()) { + if (pos + (*it)->width() >= 0) + bitBlt(&buffer, pos, (contentsRect().height() - (*it)->height()) / 2, (*it)->pixmap(*it == m_activeHeadline, m_cfg->underlineHighlighted())); + pos += (*it)->width(); + + if (pos + m_separator.width() >= 0) + bitBlt(&buffer, pos, (contentsRect().height() - m_separator.height()) / 2, &m_separator); + pos += m_separator.width(); + + if (pos >= contentsRect().width()) + break; + } else { + if (pos + (*it)->height() >= 0) + bitBlt(&buffer, (contentsRect().width() - (*it)->width()) / 2, pos, (*it)->pixmap(*it == m_activeHeadline, m_cfg->underlineHighlighted())); + pos += (*it)->height(); + + if (pos + m_separator.height() >= 0) + bitBlt(&buffer, (contentsRect().width() - m_separator.width()) / 2, pos, &m_separator); + pos += m_separator.height(); + + if (pos > contentsRect().height()) + break; + } + } + + /* + * Break out if we reached the bottom of the window before the end of the + * list of headlines. + */ + if (*it) + break; + } + while ((m_cfg->horizontalScrolling() && pos < contentsRect().width()) || pos < contentsRect().height()); + + p->drawPixmap(0, 0, buffer); +} + +void NewsScroller::reset(bool bSeparatorOnly) +{ + setFont(m_cfg->font()); + + m_scrollTimer->stop(); + if (m_cfg->scrollingSpeed()) + m_scrollTimer->start(speedAsInterval(m_cfg->scrollingSpeed())); + + QString sep = m_headlines.isEmpty() ? i18n(" +++ No News Available +++") : QString::fromLatin1(" +++ "); + + int w = fontMetrics().width(sep); + int h = fontMetrics().height(); + + if (rotated()) + m_separator.resize(h, w); + else + m_separator.resize(w, h); + + m_separator.fill(m_cfg->backgroundColor()); + + QPainter p(&m_separator); + p.setFont(font()); + p.setPen(m_cfg->foregroundColor()); + + if(rotated()) { + if (m_cfg->scrollingDirection() == ConfigAccess::UpRotated) { + p.rotate(90.0); + p.drawText(0, -fontMetrics().descent(),sep); + } else { + p.rotate(-90.0); + p.drawText(-w, h-fontMetrics().descent(),sep); + } + } else + p.drawText(0, m_separator.height() - fontMetrics().descent(), sep); + p.end(); + + if (!bSeparatorOnly) + for (QPtrListIterator<Headline> it(m_headlines); *it; ++it) + (*it)->reset(); + + switch (m_cfg->scrollingDirection()) { + case ConfigAccess::Left: + m_offset = contentsRect().width(); + break; + case ConfigAccess::Right: + m_offset = - scrollWidth(); + break; + case ConfigAccess::Up: + case ConfigAccess::UpRotated: + m_offset = contentsRect().height(); + break; + case ConfigAccess::Down: + case ConfigAccess::DownRotated: + m_offset = - scrollHeight(); + } + + update(); +} + +int NewsScroller::scrollWidth() const +{ + int result = (m_headlines.count() + 1) * m_separator.width(); + + for (QPtrListIterator<Headline> it(m_headlines); *it; ++it) + result += (*it)->width(); + + return result; +} + +int NewsScroller::scrollHeight() const +{ + int result = (m_headlines.count() + 1) * m_separator.height(); + + for (QPtrListIterator<Headline> it(m_headlines); *it; ++it) + result += (*it)->height(); + + return result; +} + +bool NewsScroller::updateActive(const QPoint &pt) +{ + int pos = m_offset; + + Headline *headline = 0; + + if (!m_headlines.isEmpty()) { + while (pos > 0) + if (horizontal()) + pos -= scrollWidth() - m_separator.width(); + else + pos -= scrollHeight() - m_separator.height(); + + do { + QPtrListIterator<Headline> it(m_headlines); + for (; (headline = *it); ++it) { + QRect rect; + if (horizontal()) { + pos += m_separator.width(); + rect.moveTopLeft(QPoint(pos, (contentsRect().height() - (*it)->height()) / 2)); + pos += (*it)->width(); + } else { + pos += m_separator.height(); + rect.moveTopLeft(QPoint((contentsRect().width() - (*it)->width()) / 2, pos)); + pos += (*it)->height(); + } + rect.setSize(QSize((*it)->width(), (*it)->height())); + + if (m_mouseDrag) + if (horizontal()) { + rect.setTop(0); + rect.setHeight(height()); + } else { + rect.setLeft(0); + rect.setWidth(width()); + } + + if (rect.contains(pt)) + break; + } + if (*it) + break; + } + while ((m_cfg->horizontalScrolling() && pos < contentsRect().width()) || pos < contentsRect().height()); + } + + if (m_activeHeadline == headline) + return false; + + if ((m_activeHeadline = headline)) + setCursor(KCursor::handCursor()); + else + unsetCursor(); + + return true; +} + +void NewsScroller::slotTimeout() +{ + m_totalStepping += m_stepping; + if ( m_totalStepping >= 1.0 ) { + const int distance = static_cast<int>( m_totalStepping ); + m_totalStepping -= distance; + scroll( distance ); + } +} + +int NewsScroller::speedAsInterval( int speed ) +{ + Q_ASSERT( speed > 0 ); + + static const int MaxScreenUpdates = 25; + + if ( speed <= MaxScreenUpdates ) { + m_stepping = 1.0; + return 1000 / speed; + } + + m_stepping = speed / MaxScreenUpdates; + return 1000 / MaxScreenUpdates; +} + +#include "newsscroller.moc" diff --git a/knewsticker/newsscroller.h b/knewsticker/newsscroller.h new file mode 100644 index 00000000..efe0c3c2 --- /dev/null +++ b/knewsticker/newsscroller.h @@ -0,0 +1,102 @@ +/* + * newsscroller.h + * + * Copyright (c) 2000, 2001 Frerich Raabe <raabe@kde.org> + * Copyright (c) 2001 Malte Starostik <malte@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 NEWSSCROLLER_H +#define NEWSSCROLLER_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "configaccess.h" +#include "newsengine.h" + +#include <qframe.h> +#include <qptrlist.h> +#include <qpixmap.h> + +class QTimer; +class Headline; +template <class> class QPtrList; +typedef QPtrList<Headline> HeadlineList; + +class NewsScroller : public QFrame +{ + Q_OBJECT + + public: + NewsScroller(QWidget *, ConfigAccess *, const char * = 0); + + virtual QSize sizeHint() const; + virtual QSizePolicy sizePolicy() const; + + // Convenience stuff. Somehow ugly, no? + inline bool horizontal() const + { + return m_cfg->horizontal(static_cast<ConfigAccess::Direction>(m_cfg->scrollingDirection())); + } + + inline bool vertical() const + { + return m_cfg->vertical(static_cast<ConfigAccess::Direction>(m_cfg->scrollingDirection())); + } + + inline bool rotated() const + { + return m_cfg->rotated(static_cast<ConfigAccess::Direction>(m_cfg->scrollingDirection())); + } + + public slots: + void clear(); + void addHeadline(Article::Ptr); + void reset(bool bSeparatorOnly = false); + + signals: + void contextMenu(); + + protected: + virtual void enterEvent(QEvent *); + virtual void mousePressEvent(QMouseEvent *); + virtual void mouseReleaseEvent(QMouseEvent *); + virtual void mouseMoveEvent(QMouseEvent *); + virtual void wheelEvent(QWheelEvent *); + virtual void leaveEvent(QEvent *); + virtual void drawContents(QPainter *); + virtual void dragEnterEvent( QDragEnterEvent *); + virtual void dropEvent(QDropEvent *); + + protected slots: + void scroll(int = 1, bool = true); + void slotTimeout(); + + private: + int scrollWidth() const; + int scrollHeight() const; + bool updateActive(const QPoint &); + bool isHeadline(const QString &) const; + int speedAsInterval( int speed ); + + private: + friend class Headline; + ConfigAccess *m_cfg; + QTimer *m_scrollTimer; + mutable HeadlineList m_headlines; + Headline *m_activeHeadline; + QPixmap m_separator; + int m_offset; + QPoint m_dragPos; + bool m_mouseDrag; + QString m_tempHeadline; + float m_totalStepping; + float m_stepping; +}; + +#endif // NEWSSCROLLER_H diff --git a/knewsticker/newssourcedlg.ui b/knewsticker/newssourcedlg.ui new file mode 100644 index 00000000..bc2690b2 --- /dev/null +++ b/knewsticker/newssourcedlg.ui @@ -0,0 +1,408 @@ +<!DOCTYPE UI><UI version="3.0" stdsetdef="1"> +<class>NewsSourceDlg</class> +<comment>The dialog to be used to edit another news source.</comment> +<author>Frerich Raabe <raabe@kde.org></author> +<widget class="QDialog"> + <property name="name"> + <cstring>NewsSourceDlg</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>438</width> + <height>201</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="caption"> + <string>Add News Source</string> + </property> + <property name="icon"> + <pixmap>image0</pixmap> + </property> + <property name="layoutMargin" stdset="0"> + </property> + <property name="layoutSpacing" stdset="0"> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>4</number> + </property> + <property name="spacing"> + <number>4</number> + </property> + <widget class="QGroupBox" row="0" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>gbNewsSourceProperties</cstring> + </property> + <property name="title"> + <string>News Source Properties</string> + </property> + <property name="layoutMargin" stdset="0"> + </property> + <property name="layoutSpacing" stdset="0"> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>lName</cstring> + </property> + <property name="text"> + <string>&Name:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>leName</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Name of the news source</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can enter the name of the news source.<br>Note that you can also use the button at the bottom right labeled <i>Suggest</i> to let KNewsTicker fill this field automatically, after you have entered a source file below.</string> + </property> + </widget> + <widget class="KLineEdit" row="0" column="1" rowspan="1" colspan="5"> + <property name="name"> + <cstring>leName</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Name of the news source</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can enter the name of the news source.<br>Note that you can also use the button at the bottom right labeled <i>Suggest</i> to let KNewsTicker fill this field automatically, after you have entered a source file below.</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>lSourceFile</cstring> + </property> + <property name="text"> + <string>Source &file:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>urlSourceFile</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>The source file for this news source</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the path to the source file for the news source you want to add here. If you specified a source file here, you can use the button at the bottom right labeled <i>Suggest</i> to let KNewsTicker fill in the remaining values automatically.</string> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>lIcon</cstring> + </property> + <property name="text"> + <string>&Icon:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>leIcon</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Path to the icon for this news source</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can specify the path to an icon to be used for this news source. Icons make it easier to distinguish between multiple news sources as the headlines scroll by.<br>Note that you can also use the button at the bottom right labeled <i>Suggest</i> to let KNewsTicker fill this field automatically, after you have entered a source file above.</string> + </property> + </widget> + <widget class="KLineEdit" row="4" column="1" rowspan="1" colspan="4"> + <property name="name"> + <cstring>leIcon</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Path to the icon for this news source</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can specify the path to an icon to be used for this news source. Icons make it easier to distinguish between multiple news sources as the headlines scroll by.<br>Note that you can also use the button at the bottom right labeled <i>Suggest</i> to let KNewsTicker fill this field automatically, after you have entered a source file above.</string> + </property> + </widget> + <widget class="QLabel" row="4" column="5"> + <property name="name"> + <cstring>pixmapIcon</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="pixmap"> + <pixmap>image1</pixmap> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Icon to be used for this news source</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This is what the currently configured icon for this news source looks like. To change this icon, use the input field at the left.</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>lCategory</cstring> + </property> + <property name="text"> + <string>Ca&tegory:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>comboCategory</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Into which category does this news source belong?</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can specify into which category this news source belongs. Arranging the news sources into categories makes it much easier to maintain large lists of news sources.<br>Note that you can also use the button at the bottom right labeled <i>Suggest</i> to let KNewsTicker fill this field automatically, after you have entered a source file above.</string> + </property> + </widget> + <widget class="KComboBox" row="3" column="1"> + <property name="name"> + <cstring>comboCategory</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Into which category does this news source belong?</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Here you can specify into which category this news source belongs. Arranging the news sources into categories makes it much easier to maintain large lists of news sources.<br>Note that you can also use the button at the bottom right labeled <i>Suggest</i> to let KNewsTicker fill this field automatically, after you have entered a source file above.</string> + </property> + </widget> + <spacer row="3" column="2"> + <property name="name"> + <cstring>Spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + </spacer> + <widget class="QLabel" row="3" column="3"> + <property name="name"> + <cstring>lMaxArticles</cstring> + </property> + <property name="text"> + <string>&Max. articles:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>sbMaxArticles</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>Maximum number of articles</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This option lets you define how many articles KNewsTicker should cache for this news source. This value will never be exceeded.<br>Note that you can also use the button at the bottom right labeled <i>Suggest</i> to let KNewsTicker fill this field automatically, after you have entered a source file above.</string> + </property> + </widget> + <widget class="KIntSpinBox" row="3" column="4" rowspan="1" colspan="2"> + <property name="name"> + <cstring>sbMaxArticles</cstring> + </property> + <property name="maxValue"> + <number>1000</number> + </property> + <property name="value"> + <number>10</number> + </property> + <property name="toolTip" stdset="0"> + <string>Maximum number of articles</string> + </property> + <property name="whatsThis" stdset="0"> + <string>This option lets you define how many articles KNewsTicker should cache for this news source. This value will never be exceeded.<br>Note that you can also use the button at the bottom right labeled <i>Suggest</i> to let KNewsTicker fill this field automatically, after you have entered a source file above.</string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>cbProgram</cstring> + </property> + <property name="text"> + <string>The file is a &program</string> + </property> + <property name="toolTip" stdset="0"> + <string>Is the specified source file a program?</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Check this box to tell KNewsTicker that the file you specified in the above input field labeled <i>Source file</i> is a program and not a RDF or RSS file. KNewsTicker will then process the output (as received on <i>stdout</i>) of that program.</string> + </property> + </widget> + <widget class="KURLRequester" row="1" column="1" rowspan="1" colspan="5"> + <property name="name"> + <cstring>urlSourceFile</cstring> + </property> + <property name="toolTip" stdset="0"> + <string>The source file for this news source</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Enter the path to the source file for the news source you want to add here. If you specified a source file here, you can use the button at the bottom right labeled <i>Suggest</i> to let KNewsTicker fill in the remaining values automatically.</string> + </property> + </widget> + </grid> + </widget> + <widget class="QPushButton" row="1" column="3"> + <property name="name"> + <cstring>bCancel</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + <property name="toolTip" stdset="0"> + <string>Cancel this configuration</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Press this button to close this dialog, discarding all entered information.</string> + </property> + </widget> + <widget class="QPushButton" row="1" column="2"> + <property name="name"> + <cstring>bSuggest</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>&Suggest</string> + </property> + <property name="toolTip" stdset="0"> + <string>Suggest suitable values</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Press this button to make KNewsTicker guess more or less reasonable values for some of the news properties (such as the name, icon or maximum number of articles).<br>Note that you have to supply a source file in order to use this function.</string> + </property> + </widget> + <widget class="QPushButton" row="1" column="1"> + <property name="name"> + <cstring>bOk</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Acknowledge these values</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Press this button to apply the values of this dialog and return to the previous configuration dialog.</string> + </property> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacerButtons</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + </spacer> + </grid> +</widget> +<images> + <image name="image0"> + <data format="XPM.GZ" length="2045">789c55d45b53db381407f0773e4586f3c6ec9cc6777b76f6a177480b85425be8ce3ec8924c4248805cb87467bffb4ae7fc6d688433f3437f1dc992e3577ba3f3e3c3d1deab9df5c66c667664a76635da73dbc5e2e9ef7ffefa7767372947e1af6e46e9ee1f3bbb279b911d1ddd2c7d04670134964f34ddc039bc14d7c1b5e44fa2933ab1899aa2d3713a4e24cfefe13c557f1637c18dd4bb82ad9a1fa2b324b55922fd703656732e6eb23ad3bc872deca2f324b3b9e6e7ea7c0c4fe01c7e2d3639d6c307bd7323fe155da443bfacb73005f6876d74990efe24366551ca789ac38d9a8f61079be82a2b1dd67fa6ae922a13bf13b75551b5e2b770a3260f3bf4c7c3a43aab0aecffd3603d9f37b0aba53e91ba4ed42ce75d87fa38af1676b8ff525d17b5ce770137f00fd8c1e7d14d5ebb26179faa9b04fe0217f0bed8065bf111dcc01f60077f8c3679e38c8e7f549b04eec4613cce7b0d3b78a63649293f0692e7a7cddbb4d5f18dd8198ff5add46da9e743dcbb75d27f0f7b352da26dd138e4efd506e74bb3c17a9e977081f3b1b0d1fda40dece195ba2d71bf696facbf80bd2dc45bb54dd5a476a1beceb756b7a9ee2fddc1dea86f7ba3fe77b53556ef7f1aed0adbefd757b54b9dce2ff59c1ffa0fd5ae74fafe59c21e4ea27d3978d1db97e26bb54fd5a4f6d6e87ed054ed52ac5f9e87ae7406e7d3c2fdfed4ea3083ba828dce4ff27bedbade3c5677a957dfc2fdfdfcecdde97abfc106be84c3475fc67d6362c32ddbe7ffc4a61976ece5eaf892a73ce32bd8f5199ef3352f78c9377ccb77bce2356fd8f236b47b7e40c687c463684f61fc15ffe2d7d2def05b7ec7ef9171a1c6237fe08fbccf073c79717de2cf439d433e0aed4bc84cc2bc4b5cc74127439daf21b11fda6918bb08ebd676c6dff860a8f33df49ef20f3e973acf99b3703f13d4d92271f1a2ce4f1e73c229eb3b2ce722f45e70195a5f27262aaeb941c6136b82087542820cd7d492edeb90a3f8f12113eba046487474f95bc6cbaec53a7d8d8ea634d30c5dd19ce67c2cdfb14e3524ae69a19970a6192de345377c40b774472b5ad386b674ff9c79f1744c38fbbdd1c3ee7f7feefc0f291dd297</data> + </image> + <image name="image1"> + <data format="XPM.GZ" length="620">789c7dcfcd6a84301007f0bb4f11f426256bd4b886a58fd0d263a1f43093c48fdd55a1dd1e4ae9bbd749a2220b8d82f9fd33c99843ca5e5f9e587a883e6f70eb35d31d7cb0d47c0dc3f7dbfbe34f148b8ad17b64227e8862ce347b9e464b739ce749e606113c8b5a02315958e5c4c6b3cc2ab7da0796c782683d655623d1044a5512a740a534511373550b2d899740e9d9110bb1f04a2c8512da10cf4499cf2739b6c40a008c2b1e56ba0b8ec41ad1dacadd7d1e09d08334e521036d10d158c4356b5a4380ced2d767fdd9ef828b5db344bb3ade5cb73a0e6ed39c6d759c239d0e83d97af801e3847c9fc130edfe6fedb9cf96debbbd18a25d0f7e9f01dc6549fbef79bfa7e80f2829874e</data> + </image> +</images> +<connections> + <connection> + <sender>bSuggest</sender> + <signal>clicked()</signal> + <receiver>NewsSourceDlg</receiver> + <slot>slotSuggestClicked()</slot> + </connection> + <connection> + <sender>bCancel</sender> + <signal>clicked()</signal> + <receiver>NewsSourceDlg</receiver> + <slot>slotCancelClicked()</slot> + </connection> + <connection> + <sender>leName</sender> + <signal>textChanged(const QString&)</signal> + <receiver>NewsSourceDlg</receiver> + <slot>slotModified()</slot> + </connection> + <connection> + <sender>comboCategory</sender> + <signal>highlighted(const QString&)</signal> + <receiver>NewsSourceDlg</receiver> + <slot>slotModified()</slot> + </connection> + <connection> + <sender>sbMaxArticles</sender> + <signal>valueChanged(int)</signal> + <receiver>NewsSourceDlg</receiver> + <slot>slotModified()</slot> + </connection> + <connection> + <sender>leIcon</sender> + <signal>textChanged(const QString&)</signal> + <receiver>NewsSourceDlg</receiver> + <slot>slotModified()</slot> + </connection> + <connection> + <sender>bOk</sender> + <signal>clicked()</signal> + <receiver>NewsSourceDlg</receiver> + <slot>slotOkClicked()</slot> + </connection> + <connection> + <sender>urlSourceFile</sender> + <signal>textChanged(const QString &)</signal> + <receiver>NewsSourceDlg</receiver> + <slot>slotSourceFileChanged()</slot> + </connection> +</connections> +<tabstops> + <tabstop>leName</tabstop> + <tabstop>urlSourceFile</tabstop> + <tabstop>cbProgram</tabstop> + <tabstop>comboCategory</tabstop> + <tabstop>sbMaxArticles</tabstop> + <tabstop>leIcon</tabstop> + <tabstop>bOk</tabstop> + <tabstop>bSuggest</tabstop> + <tabstop>bCancel</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in declaration">kurlrequester.h</include> + <include location="global" impldecl="in declaration">kcombobox.h</include> + <include location="global" impldecl="in declaration">klineedit.h</include> + <include location="global" impldecl="in declaration">knuminput.h</include> +</includes> +<slots> + <slot access="protected">slotOkClicked()</slot> + <slot access="protected">slotCancelClicked()</slot> + <slot access="protected">slotModified()</slot> + <slot access="protected">slotSourceFileChanged()</slot> + <slot access="protected">slotSuggestClicked()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/knewsticker/newssourcedlgimpl.cpp b/knewsticker/newssourcedlgimpl.cpp new file mode 100644 index 00000000..2cf39511 --- /dev/null +++ b/knewsticker/newssourcedlgimpl.cpp @@ -0,0 +1,240 @@ +/* + * newssourcedlgimpl.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 "newssourcedlgimpl.h" +#include "xmlnewsaccess.h" +#include "configaccess.h" +#include "newsiconmgr.h" + +#include <kcombobox.h> +#include <klineedit.h> +#include <kmessagebox.h> +#include <knuminput.h> +#include <kurlrequester.h> + +#include <qcheckbox.h> +#include <qlabel.h> +#include <qprogressbar.h> +#include <qtimer.h> +#include <qvbox.h> + +SuggestProgressDlg::SuggestProgressDlg(const KURL &url, QWidget *parent, const char *name) + : KDialogBase(parent, name, true, i18n("Downloading Data"), Cancel, Cancel), + m_gotSourceFile(false), + m_gotIcon(false) +{ + QVBox *mainWidget = makeVBoxMainWidget(); + + new QLabel(i18n("<qt>Please wait while KNewsTicker is downloading some " + "data necessary to suggest reasonable values.<br/>" + "<br/>" + "This will not take longer than one minute.</qt>" ), + mainWidget); + + m_progressBar = new QProgressBar(60, mainWidget); + m_progressBar->setPercentageVisible(false); + + m_timeoutTimer = new QTimer(this); + connect(m_timeoutTimer, SIGNAL(timeout()), this, SLOT(slotTimeoutTick())); + m_timeoutTimer->start(1000); + + m_xmlSrc = new XMLNewsSource; + connect(m_xmlSrc, SIGNAL(loadComplete(XMLNewsSource *, bool)), + this, SLOT(slotLoadComplete(XMLNewsSource *, bool))); + m_xmlSrc->loadFrom(url); + + connect(NewsIconMgr::self(), SIGNAL(gotIcon(const KURL &, const QPixmap &)), + this, SLOT(slotGotIcon(const KURL &, const QPixmap &))); + KURL u = url; + if (url.isLocalFile()) + u = QString::null; + else + u.setEncodedPathAndQuery(QString::fromLatin1("/favicon.ico")); + NewsIconMgr::self()->getIcon(u); +} + +SuggestProgressDlg::~SuggestProgressDlg() +{ + delete m_xmlSrc; +} + +void SuggestProgressDlg::slotTimeoutTick() +{ + if (m_progressBar->progress() == m_progressBar->totalSteps()) { + m_timeoutTimer->stop(); + KMessageBox::error(this, i18n("Could not retrieve the specified source file.")); + reject(); + return; + } + m_progressBar->setProgress(m_progressBar->progress() + 1); +} + +void SuggestProgressDlg::slotLoadComplete(XMLNewsSource *, bool succeeded) +{ + m_gotSourceFile = true; + m_succeeded = succeeded; + + if (m_gotIcon) + done(succeeded ? QDialog::Accepted : QDialog::Rejected); +} + +void SuggestProgressDlg::slotGotIcon(const KURL &url, const QPixmap &pixmap) +{ + m_gotIcon = true; + m_icon = pixmap; + m_iconURL = url; + + if (m_gotIcon) + done(m_succeeded ? QDialog::Accepted : QDialog::Rejected); +} + +NewsSourceDlgImpl::NewsSourceDlgImpl(QWidget *parent, const char *name, bool modal, WFlags fl) + : NewsSourceDlg(parent, name, modal, fl), + m_modified(false) +{ + connect(NewsIconMgr::self(), SIGNAL(gotIcon(const KURL &, const QPixmap &)), + this, SLOT(slotGotIcon(const KURL &, const QPixmap &))); + + for (unsigned int i = 0; i < DEFAULT_SUBJECTS; i++) + comboCategory->insertItem( + NewsSourceBase::subjectText(static_cast<NewsSourceBase::Subject>(i))); + +} + +void NewsSourceDlgImpl::slotCancelClicked() +{ + close(); +} + +void NewsSourceDlgImpl::slotOkClicked() +{ + KURL url (polishedURL(KURL(urlSourceFile->url()))); + + if (!validateURL(url)) + return; + + if (leName->text().isEmpty()) { + KMessageBox::error(this, i18n("You have to specify a name for this news" + " source to be able to use it."), i18n("No Name Specified")); + return; + } + + // This finds out which subject is selected in the 'Subject' combo box. + NewsSourceBase::Subject subject = NewsSourceBase::Computers; + for (unsigned int i = 0; i < DEFAULT_SUBJECTS; i++) { + NewsSourceBase::Subject thisSubj = static_cast<NewsSourceBase::Subject>(i); + if (comboCategory->currentText() == NewsSourceBase::subjectText(thisSubj)) { + subject = thisSubj; + break; + } + } + + KURL iconURL ( leIcon->text() ); + if (iconURL.protocol().isEmpty()) + if (iconURL.host().startsWith(QString::fromLatin1("ftp."))) + iconURL.setProtocol(QString::fromLatin1("ftp")); + else if (iconURL.host().startsWith(QString::fromLatin1("www."))) + iconURL.setProtocol(QString::fromLatin1("http")); + else + iconURL.setProtocol(QString::fromLatin1("file")); + + NewsSourceBase::Data nsd(leName->text(), url.url(), iconURL.url(), subject, + sbMaxArticles->value(), true, cbProgram->isChecked()); + + emit newsSource(nsd); + + close(); +} + +void NewsSourceDlgImpl::slotSourceFileChanged() +{ + bSuggest->setEnabled(!urlSourceFile->url().isEmpty()); +} + +void NewsSourceDlgImpl::slotSuggestClicked() +{ + KURL url ( polishedURL(KURL( urlSourceFile->url() )) ); + + if (!validateURL(url)) + return; + + SuggestProgressDlg dlg(url, this); + if (dlg.exec() == QDialog::Accepted) { + pixmapIcon->setPixmap(dlg.icon()); + if (NewsIconMgr::self()->isStdIcon(dlg.icon())) + leIcon->clear(); + else + leIcon->setText(dlg.iconURL().url()); + cbProgram->setChecked(false); + leName->setText(dlg.xmlSrc()->newsSourceName()); + sbMaxArticles->setValue(dlg.xmlSrc()->articles().count()); + } +} + +void NewsSourceDlgImpl::slotModified() +{ + m_modified = true; +} + +void NewsSourceDlgImpl::setup(const NewsSourceBase::Data &nsd, bool modify) +{ + leName->setText(nsd.name); + urlSourceFile->setURL(nsd.sourceFile); + cbProgram->setChecked(nsd.isProgram); + comboCategory->setCurrentItem(nsd.subject); + sbMaxArticles->setValue(nsd.maxArticles); + KURL iconURL ( nsd.icon ); + if (iconURL.protocol() == QString::fromLatin1("file")) + iconURL.setProtocol(QString::null); + leIcon->setText(iconURL.url()); + NewsIconMgr::self()->getIcon(iconURL); + if (modify == true) { + setCaption(i18n("Edit News Source")); + } +} + +KURL NewsSourceDlgImpl::polishedURL(const KURL &url) const +{ + KURL newURL = url; + + if (url.protocol().isEmpty()) + if (url.url().startsWith(QString::fromLatin1("ftp"))) + newURL = QString::fromLatin1("ftp://") + url.url(); + else + newURL = QString::fromLatin1("http://") + url.url(); + + return newURL; +} + +bool NewsSourceDlgImpl::validateURL(const KURL &url) +{ + if (url.isEmpty()) { + KMessageBox::error(this, i18n("You have to specify the source file for this" + " news source to be able to use it."), i18n("No Source File" + " Specified")); + return false; + } + + if (!url.isValid() || !url.hasPath() || url.encodedPathAndQuery() == QString::fromLatin1("/")) { + KMessageBox::error(this, i18n("KNewsTicker needs a valid RDF or RSS file to" + " suggest sensible values. The specified source file is invalid."), + i18n("Invalid Source File")); + return false; + } + + return true; +} + +void NewsSourceDlgImpl::slotGotIcon(const KURL &, const QPixmap &pixmap) +{ + pixmapIcon->setPixmap(pixmap); +} + +#include "newssourcedlgimpl.moc" diff --git a/knewsticker/newssourcedlgimpl.h b/knewsticker/newssourcedlgimpl.h new file mode 100644 index 00000000..71bb6964 --- /dev/null +++ b/knewsticker/newssourcedlgimpl.h @@ -0,0 +1,82 @@ +/* + * newssourcedlgimpl.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 NEWSSOURCEDLGIMPL_H +#define NEWSSOURCEDLGIMPL_H +#include "newssourcedlg.h" +#include "newsengine.h" + +#include <kdialogbase.h> +#include <kurl.h> + +#include <qpixmap.h> + +class XMLNewsSource; +class NewsIconMgr; +class QProgressBar; +class QTimer; + +class SuggestProgressDlg : public KDialogBase +{ + Q_OBJECT + + public: + SuggestProgressDlg(const KURL &url, QWidget *parent, const char *name = 0); + virtual ~SuggestProgressDlg(); + + XMLNewsSource *xmlSrc() { return m_xmlSrc; } + QPixmap icon() const { return m_icon; } + const KURL &iconURL() const { return m_iconURL; } + + private slots: + void slotTimeoutTick(); + void slotLoadComplete(XMLNewsSource *, bool); + void slotGotIcon(const KURL &, const QPixmap &); + + private: + bool m_gotSourceFile; + bool m_gotIcon; + XMLNewsSource *m_xmlSrc; + bool m_succeeded; + QPixmap m_icon; + KURL m_iconURL; + QProgressBar *m_progressBar; + QTimer *m_timeoutTimer; +}; + +class NewsSourceDlgImpl : public NewsSourceDlg +{ + Q_OBJECT + + public: + NewsSourceDlgImpl(QWidget * = 0, const char * = 0, bool = FALSE, WFlags = 0); + + void setup(const NewsSourceBase::Data &, bool); + + signals: + void newsSource(const NewsSourceBase::Data &); + + protected slots: + void slotCancelClicked(); + void slotOkClicked(); + void slotSourceFileChanged(); + void slotSuggestClicked(); + void slotModified(); + KURL polishedURL(const KURL &) const; + bool validateURL(const KURL &); + + private slots: + void slotGotIcon(const KURL &, const QPixmap &); + + private: + bool m_modified; +}; + +#endif // NEWSSOURCEDLGIMPL_H |